spirom.sv 8.2 KB

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