hram_top.v 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /*
  2. * hram_top.v
  3. *
  4. * vim: ts=4 sw=4
  5. *
  6. * Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
  7. * All rights reserved.
  8. *
  9. * BSD 3-clause, see LICENSE.bsd
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions are met:
  13. * * Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. * * Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in the
  17. * documentation and/or other materials provided with the distribution.
  18. * * Neither the name of the <organization> nor the
  19. * names of its contributors may be used to endorse or promote products
  20. * derived from this software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  23. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  24. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  25. * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  26. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  27. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  28. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  29. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. */
  33. `default_nettype none
  34. module hram_top (
  35. // PHY interface
  36. output reg [ 1:0] phy_ck_en,
  37. input wire [ 3:0] phy_rwds_in,
  38. output reg [ 3:0] phy_rwds_out,
  39. output reg [ 1:0] phy_rwds_oe,
  40. input wire [31:0] phy_dq_in,
  41. output reg [31:0] phy_dq_out,
  42. output reg [ 1:0] phy_dq_oe,
  43. output reg [ 3:0] phy_cs_n,
  44. output wire phy_rst_n,
  45. // PHY configuration
  46. output wire [ 7:0] phy_cfg_wdata,
  47. input wire [ 7:0] phy_cfg_rdata,
  48. output wire phy_cfg_stb,
  49. // Memory interface
  50. input wire [ 1:0] mi_addr_cs,
  51. input wire [31:0] mi_addr,
  52. input wire [ 6:0] mi_len,
  53. input wire mi_rw, /* 0=Write, 1=Read */
  54. input wire mi_linear, /* 0=Wrapped burst, 1=Linear */
  55. input wire mi_valid,
  56. output wire mi_ready,
  57. input wire [31:0] mi_wdata,
  58. input wire [ 3:0] mi_wmsk,
  59. output wire mi_wack,
  60. output wire mi_wlast,
  61. output wire [31:0] mi_rdata,
  62. output wire mi_rstb,
  63. output wire mi_rlast,
  64. // Wishbone interface
  65. input wire [31:0] wb_wdata,
  66. output reg [31:0] wb_rdata,
  67. input wire [ 3:0] wb_addr,
  68. input wire wb_we,
  69. input wire wb_cyc,
  70. output wire wb_ack,
  71. // Clock / Reset
  72. input wire clk,
  73. input wire rst
  74. );
  75. // FSM
  76. // ---
  77. localparam
  78. ST_IDLE_CFG = 0,
  79. ST_IDLE_RUN = 1,
  80. ST_CMD_ADDR_MSB = 2,
  81. ST_CMD_ADDR_LSB = 3,
  82. ST_LATENCY = 4,
  83. ST_DATA_WRITE = 5,
  84. ST_DATA_READ = 6,
  85. ST_DONE = 7;
  86. reg [3:0] state;
  87. reg [3:0] state_nxt;
  88. // Signals
  89. // -------
  90. // Control
  91. wire running;
  92. reg [ 3:0] lat_cnt;
  93. wire lat_last;
  94. reg [ 7:0] xfer_cnt;
  95. wire xfer_last;
  96. reg [95:0] sr_data;
  97. reg [11:0] sr_mask;
  98. reg [ 5:0] sr_oe;
  99. reg [ 1:0] sr_src;
  100. reg [ 1:0] sr_ce;
  101. wire [ 1:0] cap_in;
  102. wire [ 1:0] cap_out;
  103. // Current transaction
  104. reg cmd_is_read;
  105. reg cmd_is_reg;
  106. reg cmd_is_wb;
  107. reg [ 3:0] cmd_cs;
  108. // Wishbone interface
  109. reg wb_ack_i;
  110. reg wbi_we_csr;
  111. reg wbi_we_exec;
  112. reg wbi_we_wq_data;
  113. reg wbi_ae_wq_data;
  114. reg wbi_we_wq_attr;
  115. wire wbi_cmd_now;
  116. wire [3:0] wbi_cmd_len;
  117. wire [3:0] wbi_cmd_lat;
  118. wire [1:0] wbi_cmd_cs;
  119. wire wbi_cmd_is_reg;
  120. wire wbi_cmd_is_read;
  121. reg [15:0] wbi_csr;
  122. wire [31:0] wbi_csr_rd;
  123. reg [ 5:0] wbi_attr;
  124. // FSM
  125. // ---
  126. // State register
  127. always @(posedge clk)
  128. if (rst)
  129. state <= ST_IDLE_CFG;
  130. else
  131. state <= state_nxt;
  132. // Next-State logic
  133. always @(*)
  134. begin
  135. // Default is to stay put
  136. state_nxt = state;
  137. // Transisions
  138. case (state)
  139. ST_IDLE_CFG:
  140. if (wbi_cmd_now)
  141. state_nxt = ST_CMD_ADDR_MSB;
  142. else if (running)
  143. state_nxt = ST_IDLE_RUN;
  144. ST_IDLE_RUN:
  145. if (mi_valid)
  146. state_nxt = ST_CMD_ADDR_MSB;
  147. else if (!running)
  148. state_nxt = ST_IDLE_CFG;
  149. ST_CMD_ADDR_MSB:
  150. state_nxt = ST_CMD_ADDR_LSB;
  151. ST_CMD_ADDR_LSB:
  152. state_nxt = (cmd_is_reg & ~cmd_is_read) ? ST_DONE : ST_LATENCY;
  153. ST_LATENCY:
  154. if (lat_last)
  155. state_nxt = cmd_is_read ? ST_DATA_READ : ST_DATA_WRITE;
  156. ST_DATA_WRITE:
  157. if (xfer_last)
  158. state_nxt = ST_DONE;
  159. ST_DATA_READ:
  160. if (xfer_last)
  161. state_nxt = ST_DONE;
  162. ST_DONE:
  163. state_nxt = running ? ST_IDLE_RUN : ST_IDLE_CFG;
  164. endcase
  165. end
  166. // Control
  167. // -------
  168. // State
  169. assign running = wbi_csr[0];
  170. // Command latch
  171. always @(posedge clk)
  172. begin
  173. if ((state == ST_IDLE_RUN) & mi_valid)
  174. begin
  175. cmd_is_read <= mi_rw;
  176. cmd_is_reg <= 1'b0;
  177. cmd_is_wb <= 1'b0;
  178. cmd_cs <= 4'hf ^ (1 << mi_addr_cs);
  179. end
  180. else if ((state == ST_IDLE_CFG) & wbi_cmd_now)
  181. begin
  182. cmd_is_read <= wbi_cmd_is_read;
  183. cmd_is_reg <= wbi_cmd_is_reg;
  184. cmd_is_wb <= 1'b1;
  185. cmd_cs <= 4'hf ^ (1 << wbi_cmd_cs);
  186. end
  187. end
  188. // Shift register control
  189. always @(*)
  190. begin
  191. // Defaults
  192. sr_ce[1] = 1'b0;
  193. sr_ce[0] = 1'b0;
  194. sr_src[1] = 1'b0;
  195. sr_src[0] = 1'b0;
  196. // Memory interface Command accept
  197. if ((state == ST_IDLE_RUN) & mi_valid)
  198. begin
  199. sr_ce[1] = 1'b1;
  200. sr_src[1] = 1'b1;
  201. end
  202. // Wishbone accesses
  203. if (wbi_ae_wq_data)
  204. begin
  205. sr_ce[1] = 1'b1;
  206. sr_ce[0] = 1'b1;
  207. sr_src[1] = 1'b0;
  208. sr_src[0] = 1'b1;
  209. end
  210. // Config mode capture
  211. if (cap_out == 2'b01)
  212. begin
  213. sr_ce[1] = 1'b1;
  214. sr_ce[0] = 1'b1;
  215. sr_src[1] = 1'b0;
  216. sr_src[0] = 1'b0;
  217. end
  218. // Normal "shift"
  219. if ((state == ST_CMD_ADDR_MSB) || (state == ST_CMD_ADDR_LSB))
  220. begin
  221. sr_ce[1] = 1'b1;
  222. sr_ce[0] = 1'b1;
  223. sr_src[1] = 1'b0;
  224. sr_src[0] = 1'b0;
  225. end
  226. end
  227. // Shift register
  228. always @(posedge clk)
  229. begin
  230. // MSBs [95:32]
  231. if (sr_ce[1])
  232. begin
  233. sr_oe [ 5: 2] <= sr_src[1] ? 4'b1110 : sr_oe [3:0];
  234. sr_mask[11: 4] <= sr_src[1] ? 8'h00 : sr_mask[7:0];
  235. sr_data[95:32] <= sr_src[1] ?
  236. { mi_rw, 1'b0, mi_linear, mi_addr[31:3], 13'h0000, mi_addr[2:0], 16'h0000 } :
  237. sr_data[63:0];
  238. end
  239. // LSBs [31: 0]
  240. if (sr_ce[0])
  241. begin
  242. sr_oe [ 1:0] <= sr_src[0] ? wbi_attr[5:4] : 2'b11;
  243. sr_mask[ 3:0] <= sr_src[0] ? wbi_attr[3:0] : phy_rwds_in;
  244. sr_data[31:0] <= sr_src[0] ? wb_wdata : phy_dq_in;
  245. end
  246. end
  247. // Latency counter
  248. always @(posedge clk)
  249. begin
  250. if (state == ST_IDLE_RUN)
  251. lat_cnt <= wbi_csr[11:8] - 1;
  252. else if (state == ST_IDLE_CFG)
  253. lat_cnt <= wbi_cmd_lat - 1;
  254. else if (state == ST_LATENCY)
  255. lat_cnt <= lat_cnt - 1;
  256. end
  257. assign lat_last = lat_cnt[3];
  258. // Transfer counter
  259. always @(posedge clk)
  260. begin
  261. if (state == ST_IDLE_RUN)
  262. xfer_cnt <= { 1'b0, mi_len } - 1;
  263. else if (state == ST_IDLE_CFG)
  264. xfer_cnt <= { 4'h0, wbi_cmd_len } - 1;
  265. else if ((state == ST_DATA_WRITE) || (state == ST_DATA_READ))
  266. xfer_cnt <= xfer_cnt - 1;
  267. end
  268. assign xfer_last = xfer_cnt[7];
  269. // Input capture
  270. // 00 - Nothing
  271. // 01 - Capture WB
  272. // 10 - Capture MemIF
  273. // 11 - Capture MemIF last
  274. assign cap_in[1] = (state == ST_DATA_READ) & ~cmd_is_wb;
  275. assign cap_in[0] = (state == ST_DATA_READ) & (cmd_is_wb | xfer_last);
  276. hram_dline #(
  277. .N(3)
  278. ) cap_I[1:0] (
  279. .di(cap_in),
  280. .do(cap_out),
  281. .delay(wbi_csr[14:12]),
  282. .clk(clk)
  283. );
  284. // PHY drive
  285. // ---------
  286. // Main signals
  287. always @(*)
  288. begin
  289. // Defaults
  290. phy_ck_en = 2'b00;
  291. phy_rwds_out = 4'h0;
  292. phy_rwds_oe = 2'b00;
  293. phy_dq_out = sr_data[95:64];
  294. phy_dq_oe = 2'b00;
  295. phy_cs_n = 4'hf;
  296. // Special per-state overrides
  297. case (state)
  298. ST_CMD_ADDR_MSB: begin
  299. phy_ck_en = 2'b11;
  300. phy_dq_oe = sr_oe[5:4];
  301. phy_cs_n = cmd_cs;
  302. end
  303. ST_CMD_ADDR_LSB: begin
  304. phy_ck_en = 2'b11;
  305. phy_dq_oe = sr_oe[5:4];
  306. phy_cs_n = cmd_cs;
  307. end
  308. ST_LATENCY: begin
  309. phy_ck_en = 2'b11;
  310. phy_cs_n = cmd_cs;
  311. end
  312. ST_DATA_WRITE: begin
  313. phy_ck_en = 2'b11;
  314. phy_dq_oe = 2'b11;
  315. phy_rwds_oe = 2'b11;
  316. phy_dq_out = cmd_is_wb ? sr_data[95:64] : mi_wdata;
  317. phy_rwds_out = cmd_is_wb ? sr_mask[11: 8] : mi_wmsk;
  318. phy_cs_n = cmd_cs;
  319. end
  320. ST_DATA_READ: begin
  321. phy_ck_en = 2'b11;
  322. phy_cs_n = cmd_cs;
  323. end
  324. ST_DONE: begin
  325. phy_cs_n = cmd_cs;
  326. end
  327. endcase
  328. end
  329. // OOB
  330. assign phy_rst_n = ~wbi_csr[1];
  331. // Memory interface
  332. // ----------------
  333. assign mi_ready = (state == ST_IDLE_RUN);
  334. assign mi_wack = (state == ST_DATA_WRITE) & ~cmd_is_wb;
  335. assign mi_wlast = xfer_last;
  336. assign mi_rdata = phy_dq_in;
  337. assign mi_rstb = cap_out[1];
  338. assign mi_rlast = cap_out[0];
  339. // Wishbone interface
  340. // ------------------
  341. // Ack
  342. always @(posedge clk)
  343. wb_ack_i <= wb_cyc & ~wb_ack_i;
  344. assign wb_ack = wb_ack_i;
  345. // Read Mux
  346. always @(posedge clk)
  347. if (~wb_cyc | wb_ack)
  348. wb_rdata <= 32'h00000000;
  349. else
  350. case (wb_addr[1:0])
  351. 2'b00: wb_rdata <= wbi_csr_rd;
  352. 2'b10: wb_rdata <= sr_data[95:64];
  353. 2'b11: wb_rdata <= { 26'h0000000, sr_oe[5:4], sr_mask[11:8] };
  354. default: wb_rdata <= 32'hxxxxxxxx;
  355. endcase
  356. assign wbi_csr_rd[31:16] = { 8'h00, phy_cfg_rdata };
  357. assign wbi_csr_rd[15: 0] = (wbi_csr & 16'hff03) | {
  358. 12'h000,
  359. (state == ST_IDLE_RUN),
  360. (state == ST_IDLE_CFG),
  361. 2'b00
  362. };
  363. // Read/Write/Access Enables
  364. always @(posedge clk)
  365. begin
  366. if (wb_ack) begin
  367. wbi_we_csr <= 1'b0;
  368. wbi_we_exec <= 1'b0;
  369. wbi_we_wq_data <= 1'b0;
  370. wbi_ae_wq_data <= 1'b0;
  371. wbi_we_wq_attr <= 1'b0;
  372. end else begin
  373. wbi_we_csr <= wb_cyc & wb_we & (wb_addr[1:0] == 2'b00);
  374. wbi_we_exec <= wb_cyc & wb_we & (wb_addr[1:0] == 2'b01);
  375. wbi_we_wq_data <= wb_cyc & wb_we & (wb_addr[1:0] == 2'b10);
  376. wbi_ae_wq_data <= wb_cyc & (wb_addr[1:0] == 2'b10);
  377. wbi_we_wq_attr <= wb_cyc & wb_we & (wb_addr[1:0] == 2'b11);
  378. end
  379. end
  380. // CSR
  381. always @(posedge clk)
  382. if (rst)
  383. wbi_csr <= 16'h0000;
  384. else if (wbi_we_csr)
  385. wbi_csr <= wb_wdata[15:0];
  386. // PHY config
  387. assign phy_cfg_wdata = wb_wdata[23:16];
  388. assign phy_cfg_stb = wbi_we_csr;
  389. // Attrs
  390. always @(posedge clk)
  391. if (wbi_we_wq_attr)
  392. wbi_attr <= wb_wdata[5:0];
  393. // Command execute
  394. assign wbi_cmd_now = wbi_we_exec;
  395. assign wbi_cmd_len = wb_wdata[11:8];
  396. assign wbi_cmd_lat = wb_wdata[ 7:4];
  397. assign wbi_cmd_cs = wb_wdata[ 3:2];
  398. assign wbi_cmd_is_reg = wb_wdata[1];
  399. assign wbi_cmd_is_read = wb_wdata[0];
  400. endmodule