123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- //
- // Fast data download from 2-bit SPI flash.
- //
- // Feed a FIFO that then writes to SDRAM.
- // This unit is designed to write 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,
- output spi_sck,
- inout [1:0] spi_io,
- output reg spi_cs_n,
- 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 reg done
- );
- //
- // 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
- //
- // 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;
-
- 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 ),
- .rdusedw ( rdusedw )
- );
- //
- // Interfacing between FIFO and output 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[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
- reg [24:1] waddr_q;
- reg wacc_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;
- end
- else
- begin
- wacc_q <= wacc;
- waddr_q <= waddr_q + wacc_q;
- done <= done |
- (wacc_q & (waddr_q == (((ramstart + datalen) >> 1) - 1'b1)));
- 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;
- ddio_out spi_clk_buf (
- .aclr ( ~rst_n ),
- .datain_h ( spi_clk_en ),
- .datain_l ( 1'b0 ),
- .outclock ( rom_clk ),
- .dataout ( spi_sck )
- );
- 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 <= datalen << 2;
- spi_cs_n <= 1'b1;
- spi_in_req <= 1'b0;
- spi_in_req_q <= 1'b0;
- end
- else
- begin
- spi_in_q <= spi_io;
- spi_in_req <= 1'b0;
- spi_in_req_q <= spi_in_req;
- spi_clk_en <= 1'b0;
- if ( ~|spi_data_ctr )
- begin
- spi_cs_n <= 1'b1;
- spi_clk_en <= 1'b0;
- 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[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 <= { 8'h3b, romstart }; // Fast Read Dual Output
- spi_mosi_en <= 1'b1;
- spi_clk_en_q <= 1'b0;
- end
- else
- begin
- spi_clk_en_q <= spi_clk_en;
- if ( spi_clk_en_q )
- spi_cmd <= (spi_cmd << 1) | 1'b1;
- spi_mosi_en <= spi_cs_n | (spi_cmd_ctr < 6'd36);
- end
- endmodule // spirom
|