2
0

spirom.sv 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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 reg [31:0] cpu_rdata,
  27. input [31:0] cpu_wdata,
  28. input cpu_valid,
  29. input [3:0] cpu_wstrb,
  30. input [2:0] cpu_addr,
  31. output reg irq
  32. );
  33. reg [24:2] ramstart;
  34. reg [31:0] romcmd;
  35. reg [23:2] datalen;
  36. reg [2:0] cmdlen;
  37. reg go_zero;
  38. reg go_spi;
  39. reg spi_dual;
  40. reg spi_more; // Do not raise CS# after command done
  41. reg ram_done;
  42. reg ram_done_q;
  43. reg [1:0] done_q;
  44. reg busy;
  45. reg [31:0] spi_in_shr; // Input shift register for one-bit input
  46. reg spi_active;
  47. reg spi_active_q;
  48. always @(negedge rst_n or posedge sys_clk)
  49. if (~rst_n)
  50. begin
  51. ramstart <= 23'b0;
  52. romcmd <= 32'b0;
  53. datalen <= 22'b0;
  54. cmdlen <= 3'bx;
  55. go_zero <= 1'b0;
  56. go_spi <= 1'b0;
  57. ram_done_q <= 1'b1;
  58. done_q <= 2'b11;
  59. busy <= 1'b0;
  60. spi_active_q <= 1'b0;
  61. irq <= 1'b1;
  62. spi_dual <= 1'b0;
  63. spi_more <= 1'b0;
  64. end
  65. else
  66. begin
  67. ram_done_q <= ram_done;
  68. spi_active_q <= spi_active;
  69. done_q <= { done_q[0], ram_done_q & ~spi_active_q };
  70. irq <= ~(busy | spi_active_q);
  71. if (cpu_valid & cpu_wstrb[0])
  72. begin
  73. // Only full word accesses supported via DMA!!
  74. case (cpu_addr)
  75. 2'b00: begin
  76. ramstart <= cpu_wdata[24:2];
  77. end
  78. 2'b01: begin
  79. romcmd <= cpu_wdata[31:0];
  80. end
  81. 2'b10: begin
  82. datalen <= cpu_wdata[23:2];
  83. cmdlen <= cpu_wdata[26:24];
  84. go_spi <= cpu_wdata[26:24] != 3'd0;
  85. go_zero <= cpu_wdata[26:24] == 3'd0;
  86. spi_dual <= cpu_wdata[27];
  87. spi_more <= cpu_wdata[28];
  88. busy <= 1'b1;
  89. irq <= 1'b0;
  90. end
  91. default: begin
  92. // Do nothing
  93. end
  94. endcase // case (cpu_addr)
  95. end // if (cpu_valid & cpu_wstrb[0])
  96. else if (done_q == 2'b01)
  97. begin
  98. go_zero <= 1'b0;
  99. go_spi <= 1'b0;
  100. busy <= 1'b0;
  101. end
  102. end // else: !if(~rst_n)
  103. always_comb
  104. case (cpu_addr)
  105. 3'b000: cpu_rdata = { 7'b0, ramstart, 2'b0 };
  106. 3'b001: cpu_rdata = romcmd;
  107. 3'b010: cpu_rdata = { 3'b0, spi_more, spi_dual, cmdlen, datalen, 2'b0 };
  108. 3'b011: cpu_rdata = { 31'b0, irq };
  109. 3'b100: cpu_rdata = spi_in_shr;
  110. default: cpu_rdata = 32'bx;
  111. endcase // case (cpu_addr)
  112. //
  113. // FIFO and input latches
  114. //
  115. reg [1:0] spi_in_q;
  116. reg spi_in_req;
  117. reg spi_in_req_q;
  118. wire [11:0] wrusedw;
  119. wire [8:0] rdusedw;
  120. wire [15:0] fifo_out;
  121. reg from_spi;
  122. ddufifo spirom_fifo (
  123. .aclr ( ~rst_n ),
  124. .wrclk ( rom_clk ),
  125. .data ( spi_in_q ),
  126. .wrreq ( spi_in_req_q ),
  127. .wrusedw ( wrusedw ),
  128. .rdclk ( ram_clk ),
  129. .q ( fifo_out ),
  130. .rdreq ( wacc & from_spi ),
  131. .rdusedw ( rdusedw )
  132. );
  133. //
  134. // Interfacing between FIFO and input signals
  135. //
  136. // Shuffle fifo_out because SPI brings in data in bigendian bit
  137. // order within bytes, but the FIFO IP assumes littleendian
  138. //
  139. assign wd[ 7: 6] = {2{from_spi}} & fifo_out[ 1: 0];
  140. assign wd[ 5: 4] = {2{from_spi}} & fifo_out[ 3: 2];
  141. assign wd[ 3: 2] = {2{from_spi}} & fifo_out[ 5: 4];
  142. assign wd[ 1: 0] = {2{from_spi}} & fifo_out[ 7: 6];
  143. assign wd[15:14] = {2{from_spi}} & fifo_out[ 9: 8];
  144. assign wd[13:12] = {2{from_spi}} & fifo_out[11:10];
  145. assign wd[11:10] = {2{from_spi}} & fifo_out[13:12];
  146. assign wd[ 9: 8] = {2{from_spi}} & fifo_out[15:14];
  147. reg [24:1] waddr_q;
  148. reg [23:1] ram_data_ctr;
  149. reg wacc_q;
  150. reg [1:0] go_ram_q;
  151. assign waddr = waddr_q;
  152. always @(negedge rst_n or posedge ram_clk)
  153. if (~rst_n)
  154. begin
  155. waddr_q <= 24'bx;
  156. ram_data_ctr <= 23'bx;
  157. wacc_q <= 1'b0;
  158. ram_done <= 1'b1;
  159. go_ram_q <= 2'b00;
  160. wrq <= 2'b00;
  161. end
  162. else
  163. begin
  164. wrq <= 2'b00;
  165. if (ram_done)
  166. begin
  167. wrq <= 2'b00;
  168. end
  169. else if (from_spi)
  170. begin
  171. // Reading from SPI ROM
  172. wrq[0] <= rdusedw >= 9'd4; // 4*2 = 8 bytes min available
  173. wrq[1] <= rdusedw >= 9'd8; // 8*2 = 16 bytes min available
  174. end
  175. else
  176. begin
  177. // Zeroing memory
  178. wrq[0] <= |ram_data_ctr[23:3];
  179. wrq[1] <= |ram_data_ctr[23:4];
  180. end
  181. wacc_q <= wacc;
  182. go_ram_q <= { go_ram_q[0], go_spi|go_zero };
  183. if (go_ram_q == 2'b01)
  184. begin
  185. waddr_q <= { ramstart, 1'b0 };
  186. ram_data_ctr <= { datalen, 1'b0 };
  187. ram_done <= !datalen;
  188. from_spi <= go_spi;
  189. end
  190. else if (~ram_done)
  191. begin
  192. waddr_q <= waddr_q + wacc_q;
  193. ram_data_ctr <= ram_data_ctr - wacc_q;
  194. ram_done <= !(ram_data_ctr - wacc_q);
  195. end
  196. end // else: !if(~rst_n)
  197. // Negative indicies refer to fractional bytes
  198. reg [2:-3] spi_cmd_ctr;
  199. reg [23:-2] spi_data_ctr;
  200. reg spi_clk_en = 1'b0;
  201. reg spi_mosi_en;
  202. reg [1:0] go_spi_q;
  203. wire go_spi_s;
  204. reg spi_more_q;
  205. // Explicit synchronizer for go_spi
  206. synchronizer #(.width(1)) go_spi_synchro
  207. (
  208. .rst_n ( rst_n ),
  209. .clk ( rom_clk ),
  210. .d ( go_spi ),
  211. .q ( go_spi_s )
  212. );
  213. always @(negedge rst_n or posedge rom_clk)
  214. if (~rst_n)
  215. begin
  216. spi_cmd_ctr <= 6'b0;
  217. spi_clk_en <= 1'b0;
  218. spi_data_ctr <= 26'b0;
  219. spi_cs_n <= 1'b1;
  220. spi_in_req <= 1'b0;
  221. spi_in_req_q <= 1'b0;
  222. spi_mosi_en <= 1'b1;
  223. spi_in_q <= 2'bx;
  224. spi_in_shr <= 32'b0;
  225. go_spi_q <= 2'b00;
  226. spi_active <= 1'b0;
  227. spi_more_q <= 1'b0;
  228. end
  229. else
  230. begin
  231. go_spi_q <= { go_spi_q[0], go_spi_s };
  232. spi_in_q <= spi_io;
  233. spi_in_req <= 1'b0;
  234. spi_in_req_q <= spi_in_req;
  235. spi_clk_en <= 1'b0;
  236. // Note: datalen <- spi_data_ctr is a 2-cycle multipath
  237. if (go_spi_q == 2'b01)
  238. begin
  239. spi_cmd_ctr <= { cmdlen, 3'b0 };
  240. spi_data_ctr <= { datalen, 4'b0 };
  241. spi_active <= 1'b1;
  242. spi_cs_n <= 1'b0;
  243. spi_more_q <= spi_more;
  244. end
  245. if ( ~|{spi_data_ctr, spi_cmd_ctr} )
  246. begin
  247. spi_clk_en <= 1'b0;
  248. spi_mosi_en <= 1'b1;
  249. spi_active <= 1'b0;
  250. spi_cs_n <= ~spi_more_q;
  251. end
  252. else
  253. begin
  254. spi_active <= 1'b1;
  255. spi_cs_n <= 1'b0;
  256. if ( spi_active )
  257. begin
  258. // 64/4 = 16 bytes min space
  259. spi_clk_en <= (~wrusedw) >= 12'd128;
  260. if ( spi_clk_en )
  261. begin
  262. spi_in_shr <= { spi_in_shr[30:0], spi_io[1] };
  263. if ( spi_cmd_ctr == 6'd1 )
  264. spi_mosi_en <= ~spi_dual;
  265. if ( spi_cmd_ctr == 6'd0 )
  266. begin
  267. spi_in_req <= 1'b1;
  268. spi_data_ctr <= spi_data_ctr - 1'b1;
  269. end
  270. else
  271. begin
  272. spi_cmd_ctr <= spi_cmd_ctr - 1'b1;
  273. end
  274. end // if ( spi_clk_en )
  275. end // if ( ~spi_cs_n )
  276. end // else: !if( ~|spi_data_ctr )
  277. end // else: !if(~rst_n)
  278. // SPI output data is shifted on the negative edge
  279. reg [31:0] spi_out_shr;
  280. reg spi_clk_en_q;
  281. assign spi_io[0] = spi_mosi_en ? spi_out_shr[31] : 1'bz;
  282. assign spi_io[1] = 1'bz;
  283. always @(negedge rst_n or negedge rom_clk)
  284. if (~rst_n)
  285. begin
  286. spi_out_shr <= 32'b0;
  287. spi_clk_en_q <= 1'b0;
  288. end
  289. else
  290. begin
  291. spi_clk_en_q <= spi_clk_en;
  292. if (~spi_active)
  293. spi_out_shr <= romcmd;
  294. else if ( spi_clk_en_q )
  295. spi_out_shr <= { spi_out_shr[30:0], 1'b0 };
  296. end
  297. //
  298. // SPI_SCK output buffer
  299. //
  300. ddio_out spi_clk_buf (
  301. .aclr ( ~rst_n ),
  302. .datain_h ( spi_clk_en_q ),
  303. .datain_l ( 1'b0 ),
  304. .outclock ( rom_clk ),
  305. .dataout ( spi_sck )
  306. );
  307. endmodule // spirom