spirom.sv 4.0 KB

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