spirom.sv 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. //
  2. // Fast data download from 2-bit SPI flash.
  3. //
  4. // Feed a FIFO that then writes to SDRAM.
  5. // This unit is designed to write 8-byte chunks.
  6. //
  7. // This unit does *not* require a 2x SPI clock;
  8. // it uses a DDR buffer for clock out.
  9. //
  10. module spirom (
  11. input rst_n,
  12. input rom_clk,
  13. input ram_clk,
  14. output spi_sck,
  15. inout [1:0] spi_io,
  16. output reg spi_cs_n,
  17. output [15:0] wd, // Data to RAM
  18. (* syn_preserve = 1 *) // Don't merge into FIFO
  19. output [24:1] waddr, // RAM address
  20. output reg [1:0] wrq, // Write request (min 8/16 bytes)
  21. input wacc, // Data accepted (ready for next data)
  22. output reg done
  23. );
  24. //
  25. // XXX: make these CPU programmable
  26. //
  27. parameter [24:0] ramstart = 25'h000_0000;
  28. parameter [23:0] romstart = 24'h10_0000; // 1 MB
  29. parameter [23:0] datalen = 24'h08_0000; // 512K
  30. //
  31. // FIFO and input latches
  32. //
  33. reg [1:0] spi_in_q;
  34. reg spi_in_req;
  35. reg spi_in_req_q;
  36. wire [11:0] wrusedw;
  37. wire [8:0] rdusedw;
  38. wire [15:0] fifo_out;
  39. wire rdempty;
  40. ddufifo spirom_fifo (
  41. .aclr ( ~rst_n ),
  42. .wrclk ( rom_clk ),
  43. .data ( spi_in_q ),
  44. .wrreq ( spi_in_req_q ),
  45. .wrfull ( ),
  46. .wrusedw ( wrusedw ),
  47. .rdclk ( ram_clk ),
  48. .q ( fifo_out ),
  49. .rdreq ( wacc ),
  50. .rdempty ( rdempty ),
  51. .rdusedw ( rdusedw )
  52. );
  53. //
  54. // Interfacing between FIFO and output signals
  55. //
  56. // Shuffle fifo_out because SPI brings in data in bigendian bit
  57. // order within bytes, but the FIFO IP assumes littleendian
  58. //
  59. assign wd[ 7: 6] = fifo_out[ 1: 0];
  60. assign wd[ 5: 4] = fifo_out[ 3: 2];
  61. assign wd[ 3: 2] = fifo_out[ 5: 4];
  62. assign wd[ 1: 0] = fifo_out[ 7: 6];
  63. assign wd[15:14] = fifo_out[ 9: 8];
  64. assign wd[13:12] = fifo_out[11:10];
  65. assign wd[11:10] = fifo_out[13:12];
  66. assign wd[ 9: 8] = fifo_out[15:14];
  67. always @(negedge rst_n or posedge ram_clk)
  68. if (~rst_n)
  69. begin
  70. wrq <= 2'b00;
  71. end
  72. else
  73. begin
  74. wrq[0] <= rdusedw >= 9'd4; // 4*2 = 8 bytes min available
  75. wrq[1] <= rdusedw >= 9'd8; // 8*2 = 16 bytes min available
  76. end
  77. reg [24:1] waddr_q;
  78. reg wacc_q;
  79. assign waddr = waddr_q;
  80. always @(negedge rst_n or posedge ram_clk)
  81. if (~rst_n)
  82. begin
  83. waddr_q <= ramstart >> 1;
  84. wacc_q <= 1'b0;
  85. done <= 1'b0;
  86. end
  87. else
  88. begin
  89. wacc_q <= wacc;
  90. waddr_q <= waddr_q + wacc_q;
  91. done <= done |
  92. (wacc_q & (waddr_q == (((ramstart + datalen) >> 1) - 1'b1)));
  93. end // else: !if(~rst_n)
  94. reg [5:0] spi_cmd_ctr;
  95. reg [26:0] spi_data_ctr;
  96. reg spi_clk_en = 1'b0;
  97. reg spi_mosi_en = 1'b1;
  98. ddio_out spi_clk_buf (
  99. .aclr ( ~rst_n ),
  100. .datain_h ( spi_clk_en ),
  101. .datain_l ( 1'b0 ),
  102. .outclock ( rom_clk ),
  103. .dataout ( spi_sck )
  104. );
  105. always @(negedge rst_n or posedge rom_clk)
  106. if (~rst_n)
  107. begin
  108. spi_cmd_ctr <= 6'b0;
  109. spi_clk_en <= 1'b0;
  110. spi_data_ctr <= datalen << 2;
  111. spi_cs_n <= 1'b1;
  112. spi_in_req <= 1'b0;
  113. spi_in_req_q <= 1'b0;
  114. end
  115. else
  116. begin
  117. spi_in_q <= spi_io;
  118. spi_in_req <= 1'b0;
  119. spi_in_req_q <= spi_in_req;
  120. spi_clk_en <= 1'b0;
  121. if ( ~|spi_data_ctr )
  122. begin
  123. spi_cs_n <= 1'b1;
  124. spi_clk_en <= 1'b0;
  125. end
  126. else
  127. begin
  128. spi_cs_n <= 1'b0;
  129. if ( ~spi_cs_n )
  130. begin
  131. // 64/4 = 16 bytes min space
  132. spi_clk_en <= (~wrusedw) >= 12'd128;
  133. if ( spi_clk_en )
  134. begin
  135. if ( spi_cmd_ctr[5] & spi_cmd_ctr[3] )
  136. begin
  137. spi_in_req <= 1'b1;
  138. spi_data_ctr <= spi_data_ctr - 1'b1;
  139. end
  140. else
  141. begin
  142. spi_cmd_ctr <= spi_cmd_ctr + 1'b1;
  143. end
  144. end // if ( spi_clk_en )
  145. end // if ( ~spi_cs_n )
  146. end // else: !if( ~|spi_data_ctr )
  147. end // else: !if(~rst_n)
  148. // SPI output data is shifted on the negative edge
  149. reg [31:0] spi_cmd;
  150. reg spi_clk_en_q;
  151. assign spi_io[0] = spi_mosi_en ? spi_cmd[31] : 1'bz;
  152. assign spi_io[1] = 1'bz;
  153. always @(negedge rst_n or negedge rom_clk)
  154. if (~rst_n)
  155. begin
  156. spi_cmd <= { 8'h3b, romstart }; // Fast Read Dual Output
  157. spi_mosi_en <= 1'b1;
  158. spi_clk_en_q <= 1'b0;
  159. end
  160. else
  161. begin
  162. spi_clk_en_q <= spi_clk_en;
  163. if ( spi_clk_en_q )
  164. spi_cmd <= (spi_cmd << 1) | 1'b1;
  165. spi_mosi_en <= spi_cs_n | (spi_cmd_ctr < 6'd36);
  166. end
  167. endmodule // spirom