2
0

spirom.sv 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. //
  2. // Fast data download from 2-bit SPI flash, or zero SDRAM.
  3. //
  4. // Feed a FIFO that then writes to SDRAM.
  5. // Requires writes in aligned 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. input sys_clk,
  15. /* SPI ROM interface */
  16. output spi_sck,
  17. inout [1:0] spi_io,
  18. output reg spi_cs_n,
  19. /* SDRAM interface */
  20. output [15:0] wd, // Data to RAM
  21. (* syn_preserve = 1 *) // Don't merge into FIFO
  22. output [24:1] waddr, // RAM address
  23. output reg [1:0] wrq, // Write request (min 4/8 bytes)
  24. input wacc, // Data accepted (ready for next data)
  25. /* CPU control interface */
  26. output [31:0] cpu_rdata,
  27. input [31:0] cpu_wdata,
  28. input cpu_valid,
  29. input [3:0] cpu_wstrb,
  30. input [1:0] cpu_addr,
  31. output reg irq
  32. );
  33. reg [24:3] ramstart;
  34. reg [23:3] romstart;
  35. reg [23:3] datalen;
  36. reg is_spi;
  37. reg go_zero;
  38. reg go_spi;
  39. reg done;
  40. reg [1:0] done_q;
  41. always @(negedge rst_n or posedge sys_clk)
  42. if (~rst_n)
  43. begin
  44. ramstart <= 23'bx;
  45. romstart <= 23'bx;
  46. datalen <= 21'bx;
  47. is_spi <= 1'b0;
  48. go_zero <= 1'b0;
  49. go_spi <= 1'b0;
  50. done_q <= 2'b11;
  51. irq <= 1'b1;
  52. end
  53. else
  54. begin
  55. done_q <= { done_q[0], done };
  56. if (cpu_valid & cpu_wstrb[0])
  57. begin
  58. // Only full word writes supported!!
  59. case (cpu_addr)
  60. 2'b00: begin
  61. ramstart <= cpu_wdata[24:3];
  62. end
  63. 2'b01: begin
  64. romstart <= cpu_wdata[23:3];
  65. is_spi <= |cpu_wdata[23:3];
  66. end
  67. 2'b10: begin
  68. datalen <= cpu_wdata[23:3];
  69. if (|cpu_wdata[23:3])
  70. begin
  71. go_zero <= ~is_spi;
  72. go_spi <= is_spi;
  73. irq <= 1'b0;
  74. end
  75. end
  76. default: begin
  77. // Do nothing
  78. end
  79. endcase // case (cpu_addr)
  80. end // if (cpu_valid & cpu_wstrb[0])
  81. else if (done_q == 2'b01)
  82. begin
  83. go_zero <= 1'b0;
  84. go_spi <= 1'b0;
  85. irq <= 1'b1;
  86. end
  87. end // else: !if(~rst_n)
  88. always_comb
  89. case (cpu_addr)
  90. 2'b00: cpu_rdata = { 7'b0, ramstart, 3'b0 };
  91. 2'b01: cpu_rdata = { 8'b0, romstart, 3'b0 };
  92. 2'b10: cpu_rdata = { 8'b0, datalen, 3'b0 };
  93. 2'b11: cpu_rdata = { 31'b0, irq };
  94. endcase // case (cpu_addr)
  95. //
  96. // FIFO and input latches
  97. //
  98. reg [1:0] spi_in_q;
  99. reg spi_in_req;
  100. reg spi_in_req_q;
  101. wire [11:0] wrusedw;
  102. wire [8:0] rdusedw;
  103. wire [15:0] fifo_out;
  104. ddufifo spirom_fifo (
  105. .aclr ( ~rst_n ),
  106. .wrclk ( rom_clk ),
  107. .data ( spi_in_q ),
  108. .wrreq ( spi_in_req_q ),
  109. .wrusedw ( wrusedw ),
  110. .rdclk ( ram_clk ),
  111. .q ( fifo_out ),
  112. .rdreq ( wacc & go_spi ),
  113. .rdusedw ( rdusedw )
  114. );
  115. //
  116. // Interfacing between FIFO and input signals
  117. //
  118. // Shuffle fifo_out because SPI brings in data in bigendian bit
  119. // order within bytes, but the FIFO IP assumes littleendian
  120. //
  121. assign wd[ 7: 6] = {2{go_spi}} & fifo_out[ 1: 0];
  122. assign wd[ 5: 4] = {2{go_spi}} & fifo_out[ 3: 2];
  123. assign wd[ 3: 2] = {2{go_spi}} & fifo_out[ 5: 4];
  124. assign wd[ 1: 0] = {2{go_spi}} & fifo_out[ 7: 6];
  125. assign wd[15:14] = {2{go_spi}} & fifo_out[ 9: 8];
  126. assign wd[13:12] = {2{go_spi}} & fifo_out[11:10];
  127. assign wd[11:10] = {2{go_spi}} & fifo_out[13:12];
  128. assign wd[ 9: 8] = {2{go_spi}} & fifo_out[15:14];
  129. reg [24:1] waddr_q;
  130. reg [23:1] ram_data_ctr;
  131. reg wacc_q;
  132. reg [1:0] go_ram_q;
  133. assign waddr = waddr_q;
  134. always @(negedge rst_n or posedge ram_clk)
  135. if (~rst_n)
  136. begin
  137. waddr_q <= 24'bx;
  138. ram_data_ctr <= 23'bx;
  139. wacc_q <= 1'b0;
  140. done <= 1'b1;
  141. go_ram_q <= 2'b00;
  142. wrq <= 2'b00;
  143. end
  144. else
  145. begin
  146. wrq <= 2'b00;
  147. if (go_spi & ~done)
  148. begin
  149. wrq[0] <= rdusedw >= 9'd4; // 4*2 = 8 bytes min available
  150. wrq[1] <= rdusedw >= 9'd8; // 8*2 = 16 bytes min available
  151. end
  152. else if (go_zero & ~done)
  153. begin
  154. wrq[0] <= |ram_data_ctr[23:3];
  155. wrq[1] <= |ram_data_ctr[23:4];
  156. end
  157. wacc_q <= wacc;
  158. go_ram_q <= { go_ram_q[0], go_spi|go_zero };
  159. if (go_ram_q == 2'b01)
  160. begin
  161. waddr_q <= {ramstart, 2'b00};
  162. ram_data_ctr <= { datalen, 2'b00};
  163. done <= 1'b0;
  164. end
  165. else if (~done)
  166. begin
  167. waddr_q <= waddr_q + wacc_q;
  168. ram_data_ctr <= ram_data_ctr - wacc_q;
  169. done <= !(ram_data_ctr - wacc_q);
  170. end
  171. end // else: !if(~rst_n)
  172. reg [5:0] spi_cmd_ctr;
  173. reg [23:-2] spi_data_ctr;
  174. reg spi_clk_en = 1'b0;
  175. reg spi_mosi_en;
  176. reg [1:0] go_spi_q;
  177. wire go_spi_s;
  178. // Explicit synchronizer for go_spi
  179. synchronizer #(.width(1)) go_spi_synchro
  180. (
  181. .rst_n ( rst_n ),
  182. .clk ( rom_clk ),
  183. .d ( go_spi ),
  184. .q ( go_spi_s )
  185. );
  186. always @(negedge rst_n or posedge rom_clk)
  187. if (~rst_n)
  188. begin
  189. spi_cmd_ctr <= 6'b0;
  190. spi_clk_en <= 1'b0;
  191. spi_data_ctr <= 26'b0;
  192. spi_cs_n <= 1'b1;
  193. spi_in_req <= 1'b0;
  194. spi_in_req_q <= 1'b0;
  195. spi_mosi_en <= 1'b1;
  196. go_spi_q <= 4'b0000;
  197. end
  198. else
  199. begin
  200. go_spi_q <= { go_spi_q[0], go_spi_s };
  201. spi_in_q <= spi_io;
  202. spi_in_req <= 1'b0;
  203. spi_in_req_q <= spi_in_req;
  204. spi_clk_en <= 1'b0;
  205. spi_cs_n <= 1'b1;
  206. // Note: datalen <- spi_data_ctr is a 2-cycle multipath
  207. if (go_spi_q == 2'b01)
  208. begin
  209. spi_data_ctr <= { datalen, 5'b0 };
  210. spi_cmd_ctr <= 6'b0;
  211. spi_cs_n <= 1'b0;
  212. end
  213. if ( ~|spi_data_ctr | ~go_spi_q[1] )
  214. begin
  215. spi_clk_en <= 1'b0;
  216. spi_mosi_en <= 1'b1;
  217. end
  218. else
  219. begin
  220. spi_cs_n <= 1'b0;
  221. if ( ~spi_cs_n )
  222. begin
  223. // 64/4 = 16 bytes min space
  224. spi_clk_en <= (~wrusedw) >= 12'd128;
  225. if ( spi_clk_en )
  226. begin
  227. if ( spi_cmd_ctr[5] & spi_cmd_ctr[2] )
  228. spi_mosi_en <= 1'b0;
  229. if ( spi_cmd_ctr[5] & spi_cmd_ctr[3] )
  230. begin
  231. spi_in_req <= 1'b1;
  232. spi_data_ctr <= spi_data_ctr - 1'b1;
  233. end
  234. else
  235. begin
  236. spi_cmd_ctr <= spi_cmd_ctr + 1'b1;
  237. end
  238. end // if ( spi_clk_en )
  239. end // if ( ~spi_cs_n )
  240. end // else: !if( ~|spi_data_ctr )
  241. end // else: !if(~rst_n)
  242. // SPI output data is shifted on the negative edge
  243. reg [31:0] spi_cmd;
  244. reg spi_clk_en_q;
  245. assign spi_io[0] = spi_mosi_en ? spi_cmd[31] : 1'bz;
  246. assign spi_io[1] = 1'bz;
  247. always @(negedge rst_n or negedge rom_clk)
  248. if (~rst_n)
  249. begin
  250. spi_cmd <= 32'bx; // Fast Read Dual Output
  251. spi_clk_en_q <= 1'b0;
  252. end
  253. else
  254. begin
  255. if (spi_cs_n)
  256. begin
  257. spi_cmd[31:24] <= 8'h3b; // Fast Read Dual Output
  258. spi_cmd[23: 0] <= { romstart, 3'b000 }; // Byte address
  259. end
  260. spi_clk_en_q <= spi_clk_en;
  261. if ( spi_clk_en_q )
  262. spi_cmd <= (spi_cmd << 1) | 1'b1;
  263. end
  264. //
  265. // SPI_SCK output buffer
  266. //
  267. ddio_out spi_clk_buf (
  268. .aclr ( ~rst_n ),
  269. .datain_h ( spi_clk_en_q ),
  270. .datain_l ( 1'b0 ),
  271. .outclock ( rom_clk ),
  272. .dataout ( spi_sck )
  273. );
  274. endmodule // spirom