| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 | //// vjtag_max80.sv//// Access the SDRAM and allow the CPU to take interrupts and receive// a command opcode via virtual JTAG.//// The module supports the following command codes over virtual JTAG://// These chains use a common 1-bit boolean register://// 00000 - bypass// 00010 - trigger IRQ on update_IR// 00100 - trigger system (soft) reset on update_IR// 0011x - assert halt while bit set// 0100x - memory underrun status flag, clear on capture//// These chains use a common 32-bit shift register://// 1001x - address register (only bits [24:2] settable)// 1010x - read data from memory//         returns address before streaming 32-bit data words// 1011x - write data to memory//         send VJTAG_WRITE_PREFIX before streaming 32-bit data words// 1100x - command register to CPU// 1101x - command register to CPU, trigger IRQ on update_DR// 1110x - info register from CPU// 1111x - status register from CPU, clear on capture//// Setting bit 0 suppresses all register updates (but not other// side effects), allowing for nondestructive reads.//// The CPU registers are:////    0 - CPU command register (readonly)//    1 - CPU information register (rw)//    2 - CPU status register (rw)//    3 - CPU status register set bits (rw1)//module vjtag_max80#(  parameter        sram_bits,  parameter [31:0] sdram_base_addr,  parameter        sdram_bits,  parameter [31:0] VJTAG_WRITE_PREFIX = 32'hABC80FED) (   input		  rst_n,   input		  sys_clk,   output		  reset_cmd,   input		  cpu_valid,   input [6:2]		  cpu_addr,   input [31:0]		  cpu_wdata,   input [ 3:0]		  cpu_wstrb,   output [31:0]	  cpu_rdata,   output		  cpu_irq,   output		  cpu_halt,   dram_bus.dstr          sdram,   // SRAM interface   output [sram_bits-1:2] sram_addr,   input [31:0]		  sram_rdata,   output [31:0]	  sram_wdata,   output		  sram_read,   output		  sram_write   );   wire		  v_tdi;   reg		  v_tdo;   wire [4:0]	  v_ir;   wire		  v_tck;   wire		  v_st_cdr;   wire		  v_st_sdr;   wire		  v_st_e1dr;   wire		  v_st_pdr;   wire		  v_st_e2dr;   wire		  v_st_udr;   wire		  v_st_cir;   wire		  v_st_uir;   vjtag vjtag (		.tdi    ( v_tdi ),		.tdo    ( v_tdo ),		.tck    ( v_tck ),	// Really nothing virtual...		.ir_in  ( v_ir ),		.ir_out ( ),		.virtual_state_cdr  ( v_st_cdr ),		.virtual_state_e1dr ( v_st_e1dr ),		.virtual_state_e2dr ( v_st_e2dr ),		.virtual_state_pdr  ( v_st_pdr ),		.virtual_state_sdr  ( v_st_sdr ),		.virtual_state_udr  ( v_st_udr ),		.virtual_state_uir  ( v_st_uir ),		.virtual_state_cir  ( v_st_cir )		);   localparam cmd_bypass     = 4'b0000;   localparam cmd_irq        = 4'b0001;   localparam cmd_reset      = 4'b0010;   localparam cmd_halt       = 4'b0011;   localparam cmd_memerr     = 4'b0100;   localparam cmd_mem0       = 4'b1000;   localparam cmd_memaddr    = 4'b1001;   localparam cmd_memread    = 4'b1010;   localparam cmd_memwrite   = 4'b1011;   localparam cmd_memwr      = 3'b101; // Common bits of read and write   localparam cmd_cpucmd     = 4'b1100;   localparam cmd_cpucmd_irq = 4'b1101; // cpucmd but trigger IRQ   localparam cmd_cpuinfo    = 4'b1110;   localparam cmd_cpustatus  = 4'b1111;   reg	       jtag_bypass;   wire        jtag_out;   reg	       tdi_s;   wire	       tdo_s;   // Latched information for use in the synchronous state machine   reg [3:0]   ir_cmd;		// Command part of IR   reg	       ir_ro;		// Readonly (update suppress)   always @(posedge v_tck)     begin	jtag_bypass <= v_ir == cmd_bypass;	tdi_s       <= v_tdi;	ir_cmd      <= v_ir[4:1];	ir_ro       <= v_ir[0];     end   assign v_tdo = jtag_bypass ? tdi_s : tdo_s;   // Sync incoming JTAG signals. Only tck needs an actual   // synchronizer; the rest just need holding registers (see above)   // as the delay of tck will guarantee the others are stable.   wire       tck_s;   synchronizer #(.width(1), .stages(3)) tck_sync     (      .rst_n ( rst_n ),      .clk   ( sys_clk ),      .d     ( v_tck ),      .q     ( tck_s )      );   // Mask of memaddr bits that are not settable: the top bits   // and the bottom two bits (byte within dword), and the   // sram/dram select bit   localparam [31:0] memaddr_mask = ((1'b1 << sdram_bits) - 3'b100)     | sdram_base_addr;   function logic [31:0] maskaddr (input [31:0] addr);      maskaddr = addr & memaddr_mask;   endfunction   wire is_dram = |(mem_addr & sdram_base_addr); // Really just one bit   reg	      jtag_cpu_irq   = 1'b0;   reg	      jtag_cpu_halt  = 1'b0;   reg	      jtag_reset_cmd = 1'b0;   assign cpu_irq   = jtag_cpu_irq;   assign cpu_halt  = jtag_cpu_halt;   assign reset_cmd = jtag_reset_cmd;   reg [31:0]  jtag_memaddr = maskaddr(32'b0);   reg [31:0]  jtag_cpucmd;   reg [31:0]  jtag_cpuinfo;   reg [ 7:0]  jtag_cpustatus;   reg	       mem_valid;   reg	       mem_write;   reg  [31:0] mem_addr;   wire [31:0] mem_addr_next = maskaddr(mem_addr + 3'h4);   wire [31:0] sdram_rdata;   reg  [31:0] mem_wdata;   wire        sdram_ready;   reg	       sram_ready;   reg	       mem_done;   reg	       mem_error;	// Memory underrun   reg	       advance_mem_addr;   reg	       mem_header_done;   reg	       mem_do_write;   reg	       tck_q;   reg	       tck_stb;   always @(posedge sys_clk)     begin	tck_q   <= tck_s;	tck_stb <= tck_s & ~tck_q;     end   // Keep a counter to keep track of SDRAM data bit count; this is to   // allow streaming of data to/from SDRAM without leaving the   // SDR state.   reg [4:0] sdr_ctr;   // Main data shift register.   reg	       v_st_sdr_q;   reg  [31:0] jtag_shr;   wire [31:0] jtag_shr_in = ir_cmd[3]	       ? { tdi_s, jtag_shr[31:1] } :	       { 30'bx, tdi_s, jtag_shr[1] };   assign tdo_s = jtag_shr[0];   always @(posedge sys_clk)     begin	if ( ~rst_n )	  jtag_reset_cmd <= 1'b0;	jtag_cpu_irq <= 1'b0;	if ( tck_stb )	  begin	     v_st_sdr_q <= v_st_sdr;	     if ( v_st_sdr_q )	       jtag_shr <= jtag_shr_in;	     if ( v_st_cdr )	       case ( ir_cmd )		 cmd_halt: begin		    jtag_shr[0] <= jtag_cpu_halt;		 end		 cmd_memerr: begin		    jtag_shr[0] <= mem_error;		    if ( ~ir_ro ) mem_error <= 1'b0;		 end		 cmd_mem0, cmd_memaddr, cmd_memread, cmd_memwrite: begin		    jtag_shr <= jtag_memaddr;		 end		 cmd_cpucmd, cmd_cpucmd_irq: begin		    jtag_shr  <= jtag_cpucmd;		 end		 cmd_cpuinfo: begin		    jtag_shr <= jtag_cpuinfo;		 end		 cmd_cpustatus: begin		    jtag_shr <= jtag_cpustatus;		 end		 default:       ;	       endcase // case ( ir_cmd )	     // For performance, the SDRAM data can be streamed	     // without exiting the shift_DR state, so this is	     // based on a counter rather than going to the DR_update	     // state.	     //	     // Note: for cmd_memread, this will trigger an	     // unnecessary memory load at the end, but that is	     // completely harmless, and we cannot know until the clock	     // comes in if we need it or not, so we have to	     // suppress the update until we know that the user will	     // be reading the fetched data.	     mem_do_write <= 1'b0;	     if ( ir_cmd[3:1] == cmd_memwr )	       begin		  if ( v_st_cdr )		    begin		       mem_done           <= 1'b0;		       mem_valid          <= 1'b0;		       mem_write          <= ir_cmd[0];		       advance_mem_addr   <= 1'b0;		       mem_header_done    <= 1'b0;		       mem_addr           <= jtag_memaddr;		       sdr_ctr            <= 5'b0;		       mem_do_write       <= 1'b0;		    end		  if ( v_st_sdr )		    begin		       sdr_ctr <= sdr_ctr + 1'b1;		       if ( ~mem_header_done )			 begin			    if ( ~mem_write )			      begin				 // Read				 mem_header_done <= &sdr_ctr;			      end			    else			      begin				 // Write				 if ( jtag_shr_in == VJTAG_WRITE_PREFIX )				   mem_header_done <= 1'b1;				 else				   sdr_ctr <= 5'b0;			      end			 end		       // Memory access underrun?		       if ( sdr_ctr == 5'd31 )			 mem_error <= mem_error | mem_valid;		       if ( ~mem_write )			 begin			    // Read			    case ( sdr_ctr )			      5'd2: begin				 // For a read, make sure we are committed				 // to reading the new word				 if ( ~ir_ro )				   jtag_memaddr     <= mem_addr;				 advance_mem_addr   <= mem_header_done;			      end			      5'd3:				begin				   // After mem_addr advanced				   mem_valid          <= 1'b1;				   mem_done           <= 1'b0;				end			      5'd31: begin				 jtag_shr <= is_dram ? sdram_rdata : sram_rdata;			      end			      default: ;			    endcase // case ( sdr_ctr )			 end // if ( ~mem_write )		       else			 begin			    // Write			    mem_do_write <= &sdr_ctr;			 end // else: !if( ~mem_write )		    end // if ( st_sdr_s )	       end // if ( ir_cmd[3:1] == cmd_memwr )	     if ( mem_do_write )	       begin		  mem_wdata          <= jtag_shr_in;		  mem_valid          <= 1'b1;		  mem_done           <= 1'b0;		  advance_mem_addr   <= 1'b1;		  if ( ~ir_ro )		    jtag_memaddr     <= mem_addr_next;	       end	     if ( v_st_uir )	       jtag_cpu_irq <= ir_cmd == cmd_irq;	     else if ( v_st_udr )	       jtag_cpu_irq <= ir_cmd == cmd_cpucmd_irq;	     if ( v_st_uir )	       jtag_reset_cmd <= jtag_reset_cmd | (ir_cmd == cmd_reset);	     if ( v_st_udr & ~ir_ro )	       case ( ir_cmd )		 cmd_halt: begin		    jtag_cpu_halt  <= jtag_shr[0];		 end		 cmd_memaddr: begin		    jtag_memaddr   <= maskaddr(jtag_shr);		 end		 cmd_cpucmd, cmd_cpucmd_irq: begin		    jtag_cpucmd    <= jtag_shr;		 end		 default:     /* nothing */ ;	       endcase // case ( ir_cmd )	  end // if ( tck_stb )	// Increment the temporary address register if applicable,	// but only after the previous transaction is done...	if ( mem_valid )	  begin	     if (is_dram ? sdram_ready : sram_ready)	       begin		  mem_valid <= 1'b0;		  mem_done  <= 1'b1;	       end	     else	       sram_ready <= ~is_dram;	  end	if ( advance_mem_addr & ~mem_valid )	  begin	     mem_addr <= mem_addr_next;	     advance_mem_addr <= 1'b0;	  end     end   dram_port #(32) mem     (      .bus   ( sdram ),      .prio  ( 2'd2 ),      .addr  ( mem_addr ),      .valid ( mem_valid & is_dram ),      .wd    ( mem_wdata ),      .wstrb ( {4{mem_write}} ),      .ready ( sdram_ready ),      .rd    ( sdram_rdata )      );   assign sram_addr  = mem_addr[sram_bits-1:2];   assign sram_wdata = mem_wdata;   assign sram_read  = mem_valid & ~is_dram & ~mem_write;   assign sram_write = mem_valid & ~is_dram &  mem_write;   wire [7:0] cpustatus_new =	      ( tck_stb & v_st_cdr & ~ir_ro & (ir_cmd == cmd_cpustatus) )	      ? 'b0 : jtag_cpustatus;   always @(negedge rst_n or posedge sys_clk)     if (~rst_n)       begin	  jtag_cpuinfo   <= 'b0;	  jtag_cpustatus <= 'b0;       end     else       begin	  jtag_cpustatus <= cpustatus_new;	  if ( cpu_valid )	    begin	       case ( cpu_addr )		 5'b00001: begin		    if ( cpu_wstrb[0] )   jtag_cpuinfo[7:0] <=   cpu_wdata[7:0];		    if ( cpu_wstrb[1] )  jtag_cpuinfo[15:8] <=  cpu_wdata[15:8];		    if ( cpu_wstrb[2] ) jtag_cpuinfo[23:16] <= cpu_wdata[23:16];		    if ( cpu_wstrb[3] ) jtag_cpuinfo[31:24] <= cpu_wdata[31:24];		 end		 5'b00010: begin		    if ( cpu_wstrb[0] ) jtag_cpustatus <= cpu_wdata[7:0];		    // Add more if the width of jtag_cpustatus is increased		 end		 5'b00011: begin		    if ( cpu_wstrb[0] )		      jtag_cpustatus <= cpustatus_new | cpu_wdata[7:0];		 end		 default: /* nothing */;	       endcase // case ( cpu_addr[1:0] )	    end // if ( cpu_valid )       end   always @(*)     casez ( cpu_addr )       5'b00000: cpu_rdata = jtag_cpucmd;       5'b00001: cpu_rdata = jtag_cpuinfo;       5'b0001?: cpu_rdata = jtag_cpustatus;       default:  cpu_rdata = 32'bx;     endcase // casez ( cpu_addr )endmodule // vjtag_max80
 |