|  | @@ -1,116 +1,201 @@
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  | -// Fast data download from 2-bit SPI flash.
 | 
	
		
			
				|  |  | +// Fast data download from 2-bit SPI flash, or zero SDRAM.
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  // Feed a FIFO that then writes to SDRAM.
 | 
	
		
			
				|  |  | -// This unit is designed to write 8-byte chunks.
 | 
	
		
			
				|  |  | +// 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		rst_n,
 | 
	
		
			
				|  |  | +	       input		rom_clk,
 | 
	
		
			
				|  |  | +	       input		ram_clk,
 | 
	
		
			
				|  |  | +	       input		sys_clk,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	       output 		 spi_sck,
 | 
	
		
			
				|  |  | -	       inout [1:0] 	 spi_io,
 | 
	
		
			
				|  |  | -	       output reg 	 spi_cs_n,
 | 
	
		
			
				|  |  | +	       /* SPI ROM interface */
 | 
	
		
			
				|  |  | +	       output		spi_sck,
 | 
	
		
			
				|  |  | +	       inout [1:0]	spi_io,
 | 
	
		
			
				|  |  | +	       output reg	spi_cs_n,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	       output [15:0] 	 wd, // Data to RAM
 | 
	
		
			
				|  |  | +	       /* 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 8/16 bytes)
 | 
	
		
			
				|  |  | -	       input 		 wacc, // Data accepted (ready for next data)
 | 
	
		
			
				|  |  | +	       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)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	       output reg 	 done
 | 
	
		
			
				|  |  | +	       /* 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
 | 
	
		
			
				|  |  |  	       );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -   //
 | 
	
		
			
				|  |  | -   // XXX: make these CPU programmable
 | 
	
		
			
				|  |  | -   //
 | 
	
		
			
				|  |  | -   parameter [24:0] ramstart = 25'h000_0000;
 | 
	
		
			
				|  |  | -   parameter [23:0] romstart = 24'h10_0000; // 1 MB
 | 
	
		
			
				|  |  | -   parameter [23:0] datalen  = 24'h08_0000; // 512K
 | 
	
		
			
				|  |  | +   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;
 | 
	
		
			
				|  |  | -   wire 		  rdempty;
 | 
	
		
			
				|  |  | -   
 | 
	
		
			
				|  |  | +   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 ),
 | 
	
		
			
				|  |  | -			.wrfull ( ),
 | 
	
		
			
				|  |  |  			.wrusedw ( wrusedw ),
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  			.rdclk ( ram_clk ),
 | 
	
		
			
				|  |  |  			.q ( fifo_out ),
 | 
	
		
			
				|  |  | -			.rdreq ( wacc ),
 | 
	
		
			
				|  |  | -			.rdempty ( rdempty ),
 | 
	
		
			
				|  |  | +			.rdreq ( wacc & go_spi ),
 | 
	
		
			
				|  |  |  			.rdusedw ( rdusedw )
 | 
	
		
			
				|  |  |  			);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     //
 | 
	
		
			
				|  |  | -   // Interfacing between FIFO and output signals
 | 
	
		
			
				|  |  | +   // 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] = fifo_out[ 1: 0];
 | 
	
		
			
				|  |  | -   assign wd[ 5: 4] = fifo_out[ 3: 2];
 | 
	
		
			
				|  |  | -   assign wd[ 3: 2] = fifo_out[ 5: 4];
 | 
	
		
			
				|  |  | -   assign wd[ 1: 0] = fifo_out[ 7: 6];
 | 
	
		
			
				|  |  | +   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] = fifo_out[ 9: 8];
 | 
	
		
			
				|  |  | -   assign wd[13:12] = fifo_out[11:10];
 | 
	
		
			
				|  |  | -   assign wd[11:10] = fifo_out[13:12];
 | 
	
		
			
				|  |  | -   assign wd[ 9: 8] = fifo_out[15:14];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -   always @(negedge rst_n or posedge ram_clk)
 | 
	
		
			
				|  |  | -     if (~rst_n)
 | 
	
		
			
				|  |  | -       begin
 | 
	
		
			
				|  |  | -	  wrq <= 2'b00;
 | 
	
		
			
				|  |  | -       end
 | 
	
		
			
				|  |  | -     else
 | 
	
		
			
				|  |  | -       begin
 | 
	
		
			
				|  |  | -	  wrq[0] <= rdusedw >= 9'd4; // 4*2 =  8 bytes min available
 | 
	
		
			
				|  |  | -	  wrq[1] <= rdusedw >= 9'd8; // 8*2 = 16 bytes min available
 | 
	
		
			
				|  |  | -       end
 | 
	
		
			
				|  |  | +   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 	      wacc_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  <= ramstart >> 1;
 | 
	
		
			
				|  |  | -	  wacc_q   <= 1'b0;
 | 
	
		
			
				|  |  | -	  done     <= 1'b0;
 | 
	
		
			
				|  |  | +	  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
 | 
	
		
			
				|  |  | -	  wacc_q   <= wacc;
 | 
	
		
			
				|  |  | -	  waddr_q  <= waddr_q + wacc_q;
 | 
	
		
			
				|  |  | -	  done  <= done |
 | 
	
		
			
				|  |  | -		   (wacc_q & (waddr_q == (((ramstart + datalen) >> 1) - 1'b1)));
 | 
	
		
			
				|  |  | +	  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 [26:0] spi_data_ctr;
 | 
	
		
			
				|  |  | -   reg 	      spi_clk_en    = 1'b0;
 | 
	
		
			
				|  |  | -   reg 	      spi_mosi_en = 1'b1;
 | 
	
		
			
				|  |  | +   reg [5:0]   spi_cmd_ctr;
 | 
	
		
			
				|  |  | +   reg [23:-2] spi_data_ctr;
 | 
	
		
			
				|  |  | +   reg	       spi_clk_en    = 1'b0;
 | 
	
		
			
				|  |  | +   reg	       spi_mosi_en = 1'b1;
 | 
	
		
			
				|  |  | +   reg [1:0]   go_spi_q;
 | 
	
		
			
				|  |  | +   reg	       load_cmd;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     ddio_out spi_clk_buf (
 | 
	
		
			
				|  |  |  			 .aclr ( ~rst_n ),
 | 
	
	
		
			
				|  | @@ -125,18 +210,26 @@ module spirom (
 | 
	
		
			
				|  |  |         begin
 | 
	
		
			
				|  |  |  	  spi_cmd_ctr  <= 6'b0;
 | 
	
		
			
				|  |  |  	  spi_clk_en   <= 1'b0;
 | 
	
		
			
				|  |  | -	  spi_data_ctr <= datalen << 2;
 | 
	
		
			
				|  |  | +	  spi_data_ctr <= 26'b0;
 | 
	
		
			
				|  |  |  	  spi_cs_n     <= 1'b1;
 | 
	
		
			
				|  |  |  	  spi_in_req   <= 1'b0;
 | 
	
		
			
				|  |  |  	  spi_in_req_q <= 1'b0;
 | 
	
		
			
				|  |  | +	  go_spi_q     <= 2'b00;
 | 
	
		
			
				|  |  |         end
 | 
	
		
			
				|  |  |       else
 | 
	
		
			
				|  |  |         begin
 | 
	
		
			
				|  |  | +	  go_spi_q     <= { go_spi_q[0], go_spi };
 | 
	
		
			
				|  |  |  	  spi_in_q     <= spi_io;
 | 
	
		
			
				|  |  |  	  spi_in_req   <= 1'b0;
 | 
	
		
			
				|  |  |  	  spi_in_req_q <= spi_in_req;
 | 
	
		
			
				|  |  |  	  spi_clk_en   <= 1'b0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	  if (go_spi_q == 2'b01)
 | 
	
		
			
				|  |  | +	    begin
 | 
	
		
			
				|  |  | +	       spi_data_ctr <= { datalen, 5'b0 };
 | 
	
		
			
				|  |  | +	       spi_cmd_ctr  <= 6'b0;
 | 
	
		
			
				|  |  | +	    end
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	  if ( ~|spi_data_ctr )
 | 
	
		
			
				|  |  |  	    begin
 | 
	
		
			
				|  |  |  	       spi_cs_n   <= 1'b1;
 | 
	
	
		
			
				|  | @@ -167,7 +260,7 @@ module spirom (
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     // SPI output data is shifted on the negative edge
 | 
	
		
			
				|  |  |     reg [31:0] spi_cmd;
 | 
	
		
			
				|  |  | -   reg 	      spi_clk_en_q;
 | 
	
		
			
				|  |  | +   reg	      spi_clk_en_q;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     assign spi_io[0] = spi_mosi_en ? spi_cmd[31] : 1'bz;
 | 
	
		
			
				|  |  |     assign spi_io[1] = 1'bz;
 | 
	
	
		
			
				|  | @@ -175,12 +268,18 @@ module spirom (
 | 
	
		
			
				|  |  |     always @(negedge rst_n or negedge rom_clk)
 | 
	
		
			
				|  |  |       if (~rst_n)
 | 
	
		
			
				|  |  |         begin
 | 
	
		
			
				|  |  | -	  spi_cmd      <= { 8'h3b, romstart }; // Fast Read Dual Output
 | 
	
		
			
				|  |  | +	  spi_cmd      <= 32'bx;	// Fast Read Dual Output
 | 
	
		
			
				|  |  |  	  spi_mosi_en  <= 1'b1;
 | 
	
		
			
				|  |  |  	  spi_clk_en_q <= 1'b0;
 | 
	
		
			
				|  |  |         end
 | 
	
		
			
				|  |  |       else
 | 
	
		
			
				|  |  |         begin
 | 
	
		
			
				|  |  | +	  if (!spi_cmd_ctr)
 | 
	
		
			
				|  |  | +	    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;
 |