| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 | //// Fast data download from 2-bit SPI flash, or zero SDRAM.//// Feed a FIFO that then writes to SDRAM.// Requires writes in aligned 8-byte chunks.//// This unit does *not* require a 2x SPI clock;// it uses a DDR buffer for clock out.//module spirom (	       input		rst_n,	       input		rom_clk,	       input		ram_clk,	       input		sys_clk,	       /* SPI ROM interface */	       output		spi_sck,	       inout [1:0]	spi_io,	       output reg	spi_cs_n,	       /* SDRAM interface */	       output [15:0]	wd, // Data to RAM	       (* syn_preserve = 1 *)	// Don't merge into FIFO	       output [24:1]	waddr, // RAM address	       output reg [1:0] wrq, // Write request (min 4/8 bytes)	       input		wacc, // Data accepted (ready for next data)	       /* CPU control interface */	       output [31:0]	cpu_rdata,	       input [31:0]	cpu_wdata,	       input		cpu_valid,	       input [3:0]	cpu_wstrb,	       input [1:0]	cpu_addr,	       output reg	irq	       );   reg [24:3] ramstart;   reg [23:3] romstart;   reg [23:3] datalen;   reg	      is_spi;   reg	      go_zero;   reg	      go_spi;   reg	      done;   reg [1:0]  done_q;   always @(negedge rst_n or posedge sys_clk)     if (~rst_n)       begin	  ramstart <= 23'bx;	  romstart <= 23'bx;	  datalen  <= 21'bx;	  is_spi   <= 1'b0;	  go_zero  <= 1'b0;	  go_spi   <= 1'b0;	  done_q   <= 2'b11;	  irq      <= 1'b1;       end     else       begin	  done_q <= { done_q[0], done };	  if (cpu_valid & cpu_wstrb[0])	    begin	       // Only full word writes supported!!	       case (cpu_addr)		 2'b00: begin		    ramstart <= cpu_wdata[24:3];		 end		 2'b01: begin		    romstart <= cpu_wdata[23:3];		    is_spi <= |cpu_wdata[23:3];		 end		 2'b10: begin		    datalen <= cpu_wdata[23:3];		    if (|cpu_wdata[23:3])		      begin			 go_zero <= ~is_spi;			 go_spi  <=  is_spi;			 irq     <=  1'b0;		      end		 end		 default: begin		    // Do nothing		 end	       endcase // case (cpu_addr)	    end // if (cpu_valid & cpu_wstrb[0])	  else if (done_q == 2'b01)	    begin	       go_zero <= 1'b0;	       go_spi  <= 1'b0;	       irq     <= 1'b1;	    end       end // else: !if(~rst_n)   always_comb     case (cpu_addr)       2'b00: cpu_rdata = { 7'b0, ramstart, 3'b0 };       2'b01: cpu_rdata = { 8'b0, romstart, 3'b0 };       2'b10: cpu_rdata = { 8'b0, datalen,  3'b0 };       2'b11: cpu_rdata = { 31'b0, irq };     endcase // case (cpu_addr)   //   // FIFO and input latches   //   reg [1:0]		  spi_in_q;   reg			  spi_in_req;   reg			  spi_in_req_q;   wire [11:0]		  wrusedw;   wire [8:0]		  rdusedw;   wire [15:0]		  fifo_out;   ddufifo spirom_fifo (			.aclr ( ~rst_n ),			.wrclk ( rom_clk ),			.data ( spi_in_q ),			.wrreq ( spi_in_req_q ),			.wrusedw ( wrusedw ),			.rdclk ( ram_clk ),			.q ( fifo_out ),			.rdreq ( wacc & go_spi ),			.rdusedw ( rdusedw )			);   //   // Interfacing between FIFO and input signals   //   // Shuffle fifo_out because SPI brings in data in bigendian bit   // order within bytes, but the FIFO IP assumes littleendian   //   assign wd[ 7: 6] = {2{go_spi}} & fifo_out[ 1: 0];   assign wd[ 5: 4] = {2{go_spi}} & fifo_out[ 3: 2];   assign wd[ 3: 2] = {2{go_spi}} & fifo_out[ 5: 4];   assign wd[ 1: 0] = {2{go_spi}} & fifo_out[ 7: 6];   assign wd[15:14] = {2{go_spi}} & fifo_out[ 9: 8];   assign wd[13:12] = {2{go_spi}} & fifo_out[11:10];   assign wd[11:10] = {2{go_spi}} & fifo_out[13:12];   assign wd[ 9: 8] = {2{go_spi}} & fifo_out[15:14];   reg [24:1] waddr_q;   reg [23:1] ram_data_ctr;   reg	      wacc_q;   reg [1:0]  go_ram_q;   assign waddr = waddr_q;   always @(negedge rst_n or posedge ram_clk)     if (~rst_n)       begin	  waddr_q      <= 24'bx;	  ram_data_ctr <= 23'bx;	  wacc_q       <= 1'b0;	  done	       <= 1'b1;	  go_ram_q     <= 2'b00;	  wrq          <= 2'b00;       end     else       begin	  wrq <= 2'b00;	  if (go_spi & ~done)	    begin	       wrq[0] <= rdusedw >=  9'd4; // 4*2 =  8 bytes min available	       wrq[1] <= rdusedw >=  9'd8; // 8*2 = 16 bytes min available	    end	  else if (go_zero & ~done)	    begin	       wrq[0] <= |ram_data_ctr[23:3];	       wrq[1] <= |ram_data_ctr[23:4];	    end	  wacc_q    <= wacc;	  go_ram_q  <= { go_ram_q[0], go_spi|go_zero };	  if (go_ram_q == 2'b01)	    begin	       waddr_q      <= {ramstart, 2'b00};	       ram_data_ctr <= { datalen, 2'b00};	       done         <= 1'b0;	    end	  else if (~done)	    begin	       waddr_q      <= waddr_q + wacc_q;	       ram_data_ctr <= ram_data_ctr - wacc_q;	       done         <= !(ram_data_ctr - wacc_q);	    end       end // else: !if(~rst_n)   reg [5:0]   spi_cmd_ctr;   reg [23:-2] spi_data_ctr;   reg	       spi_clk_en = 1'b0;   reg	       spi_mosi_en;   reg [1:0]   go_spi_q;   wire        go_spi_s;   // Explicit synchronizer for go_spi   synchronizer #(.width(1)) go_spi_synchro     (      .rst_n ( rst_n ),      .clk ( rom_clk ),      .d ( go_spi ),      .q ( go_spi_s )      );   always @(negedge rst_n or posedge rom_clk)     if (~rst_n)       begin	  spi_cmd_ctr  <= 6'b0;	  spi_clk_en   <= 1'b0;	  spi_data_ctr <= 26'b0;	  spi_cs_n     <= 1'b1;	  spi_in_req   <= 1'b0;	  spi_in_req_q <= 1'b0;	  spi_mosi_en  <= 1'b1;	  go_spi_q     <= 4'b0000;       end     else       begin	  go_spi_q     <= { go_spi_q[0], go_spi_s };	  spi_in_q     <= spi_io;	  spi_in_req   <= 1'b0;	  spi_in_req_q <= spi_in_req;	  spi_clk_en   <= 1'b0;	  spi_cs_n     <= 1'b1;	  // Note: datalen <- spi_data_ctr is a 2-cycle multipath	  if (go_spi_q == 2'b01)	    begin	       spi_data_ctr <= { datalen, 5'b0 };	       spi_cmd_ctr  <= 6'b0;	       spi_cs_n     <= 1'b0;	    end	  if ( ~|spi_data_ctr | ~go_spi_q[1] )	    begin	       spi_clk_en  <= 1'b0;	       spi_mosi_en <= 1'b1;	    end	  else	    begin	       spi_cs_n   <= 1'b0;	       if ( ~spi_cs_n )		 begin		    // 64/4 = 16 bytes min space		    spi_clk_en <= (~wrusedw) >= 12'd128;		    if ( spi_clk_en )		      begin			 if ( spi_cmd_ctr[5] & spi_cmd_ctr[2] )			   spi_mosi_en <= 1'b0;			 if ( spi_cmd_ctr[5] & spi_cmd_ctr[3] )			   begin			      spi_in_req <= 1'b1;			      spi_data_ctr <= spi_data_ctr - 1'b1;			   end			 else			   begin			      spi_cmd_ctr <= spi_cmd_ctr + 1'b1;			   end		      end // if ( spi_clk_en )		 end // if ( ~spi_cs_n )	    end // else: !if( ~|spi_data_ctr )       end // else: !if(~rst_n)   // SPI output data is shifted on the negative edge   reg [31:0] spi_cmd;   reg	      spi_clk_en_q;   assign spi_io[0] = spi_mosi_en ? spi_cmd[31] : 1'bz;   assign spi_io[1] = 1'bz;   always @(negedge rst_n or negedge rom_clk)     if (~rst_n)       begin	  spi_cmd      <= 32'bx;	// Fast Read Dual Output	  spi_clk_en_q <= 1'b0;       end     else       begin	  if (spi_cs_n)	    begin	       spi_cmd[31:24] <= 8'h3b;	// Fast Read Dual Output	       spi_cmd[23: 0] <= { romstart, 3'b000 }; // Byte address	    end	  spi_clk_en_q <= spi_clk_en;	  if ( spi_clk_en_q )	    spi_cmd <= (spi_cmd << 1) | 1'b1;       end   //   // SPI_SCK output buffer   //   ddio_out spi_clk_buf (			 .aclr ( ~rst_n ),			 .datain_h ( spi_clk_en_q ),			 .datain_l ( 1'b0 ),			 .outclock ( rom_clk ),			 .dataout ( spi_sck )			 );endmodule // spirom
 |