spirom.sv 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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. reg [1:0] spi_in_q;
  31. reg spi_in_req;
  32. wire [11:0] wrusedw;
  33. (* syn_preserve = 1 *) wire [8:0] rdusedw;
  34. //
  35. // FIFO
  36. //
  37. wire [15:0] fifo_out;
  38. (* syn_preserve = 1 *) wire rdempty;
  39. ddufifo spirom_fifo (
  40. .aclr ( ~rst_n ),
  41. .wrclk ( rom_clk ),
  42. .data ( spi_in_q ),
  43. .wrreq ( spi_in_req ),
  44. .wrfull ( ),
  45. .wrusedw ( wrusedw ),
  46. .rdclk ( ram_clk ),
  47. .q ( fifo_out ),
  48. .rdreq ( wacc ),
  49. .rdempty ( rdempty ),
  50. .rdusedw ( rdusedw )
  51. );
  52. //
  53. // Interfacing between FIFO and output signals
  54. //
  55. // Shuffle fifo_out because SPI brings in data in bigendian bit
  56. // order within bytes, but the FIFO IP assumes littleendian
  57. //
  58. assign wd[ 7: 6] = fifo_out[ 1: 0];
  59. assign wd[ 5: 4] = fifo_out[ 3: 2];
  60. assign wd[ 3: 2] = fifo_out[ 5: 4];
  61. assign wd[ 1: 0] = fifo_out[ 7: 6];
  62. assign wd[15:14] = fifo_out[ 9: 8];
  63. assign wd[13:12] = fifo_out[11:10];
  64. assign wd[11:10] = fifo_out[13:12];
  65. assign wd[ 9: 8] = fifo_out[15:14];
  66. always @(negedge rst_n or posedge ram_clk)
  67. if (~rst_n)
  68. begin
  69. wrq <= 2'b00;
  70. end
  71. else
  72. begin
  73. wrq[0] <= rdusedw >= 9'd4; // 4*2 = 8 bytes min available
  74. wrq[1] <= rdusedw >= 9'd8; // 8*2 = 16 bytes min available
  75. end
  76. reg [24:1] waddr_q;
  77. reg wacc_q;
  78. assign waddr = waddr_q;
  79. always @(negedge rst_n or posedge ram_clk)
  80. if (~rst_n)
  81. begin
  82. waddr_q <= ramstart >> 1;
  83. wacc_q <= 1'b0;
  84. done <= 1'b0;
  85. end
  86. else
  87. begin
  88. wacc_q <= wacc;
  89. waddr_q <= waddr_q + wacc_q;
  90. done <= done |
  91. (wacc_q & (waddr_q == (((ramstart + datalen) >> 1) - 1'b1)));
  92. end // else: !if(~rst_n)
  93. reg [5:0] spi_cmd_ctr;
  94. reg [26:0] spi_data_ctr;
  95. reg spi_clk_en = 1'b0;
  96. reg spi_mosi_en = 1'b1;
  97. ddio_out spi_clk_buf (
  98. .aclr ( ~rst_n ),
  99. .datain_h ( spi_clk_en ),
  100. .datain_l ( 1'b0 ),
  101. .outclock ( rom_clk ),
  102. .dataout ( spi_sck )
  103. );
  104. always @(negedge rst_n or posedge rom_clk)
  105. if (~rst_n)
  106. begin
  107. spi_cmd_ctr <= 6'b0;
  108. spi_clk_en <= 1'b0;
  109. spi_data_ctr <= datalen << 2;
  110. spi_cs_n <= 1'b1;
  111. end
  112. else
  113. begin
  114. spi_in_q <= spi_io;
  115. spi_in_req <= 1'b0;
  116. spi_clk_en <= 1'b0;
  117. if ( ~|spi_data_ctr )
  118. begin
  119. spi_cs_n <= 1'b1;
  120. spi_clk_en <= 1'b0;
  121. end
  122. else
  123. begin
  124. spi_cs_n <= 1'b0;
  125. if ( ~spi_cs_n )
  126. begin
  127. // 64/4 = 16 bytes min space
  128. spi_clk_en <= (~wrusedw) >= 12'd128;
  129. if ( spi_clk_en )
  130. begin
  131. if ( spi_cmd_ctr[5] & spi_cmd_ctr[3] & spi_cmd_ctr[0] )
  132. begin
  133. spi_in_req <= 1'b1;
  134. spi_data_ctr <= spi_data_ctr - 1'b1;
  135. end
  136. else
  137. begin
  138. spi_cmd_ctr <= spi_cmd_ctr + 1'b1;
  139. end
  140. end // if ( spi_clk_en )
  141. end // if ( ~spi_cs_n )
  142. end // else: !if( ~|spi_data_ctr )
  143. end // else: !if(~rst_n)
  144. // SPI output data is shifted on the negative edge
  145. reg [31:0] spi_cmd;
  146. reg spi_clk_en_q;
  147. assign spi_io[0] = spi_mosi_en ? spi_cmd[31] : 1'bz;
  148. assign spi_io[1] = 1'bz;
  149. always @(negedge rst_n or negedge rom_clk)
  150. if (~rst_n)
  151. begin
  152. spi_cmd <= { 8'h3b, romstart }; // Fast Read Dual Output
  153. spi_mosi_en <= 1'b1;
  154. spi_clk_en_q <= 1'b0;
  155. end
  156. else
  157. begin
  158. spi_clk_en_q <= spi_clk_en;
  159. if ( spi_clk_en_q )
  160. spi_cmd <= (spi_cmd << 1) | 1'b1;
  161. spi_mosi_en <= spi_cs_n | (spi_cmd_ctr < 6'd36);
  162. end
  163. endmodule // spirom