mc97.v 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /*
  2. * mc97.v
  3. *
  4. * vim: ts=4 sw=4
  5. *
  6. * Copyright (C) 2021 Sylvain Munaut <tnt@246tNt.com>
  7. * SPDX-License-Identifier: CERN-OHL-P-2.0
  8. */
  9. `default_nettype none
  10. module mc97 (
  11. // MC97 link
  12. output wire mc97_sdata_out,
  13. input wire mc97_sdata_in,
  14. output wire mc97_sync,
  15. input wire mc97_bitclk,
  16. // User interface - Samples
  17. input wire [15:0] pcm_out_data,
  18. output reg pcm_out_ack,
  19. output wire [15:0] pcm_in_data,
  20. output reg pcm_in_stb,
  21. // User interface - GPIO (slot 12)
  22. output reg [19:0] gpio_in,
  23. input wire [19:0] gpio_out,
  24. input wire gpio_ena,
  25. // User interface - Registers
  26. input wire [ 5:0] reg_addr,
  27. input wire [15:0] reg_wdata,
  28. output wire [15:0] reg_rdata,
  29. output reg reg_rerr,
  30. input wire reg_valid,
  31. input wire reg_we,
  32. output reg reg_ack,
  33. // User interface - Misc
  34. input wire cfg_run,
  35. output wire stat_codec_ready,
  36. output reg [12:0] stat_slot_valid,
  37. output reg [12:0] stat_slot_req,
  38. input wire stat_clr,
  39. // Clock / Reset
  40. input wire clk,
  41. input wire rst
  42. );
  43. // Signals
  44. // -------
  45. genvar i;
  46. // Sequencer
  47. reg [12:0] seq_wr_slot;
  48. wire [12:0] seq_rd_slot;
  49. // MC97 Frame control
  50. wire [15:0] fc_tag_out;
  51. reg [15:0] fc_tag_in; // Captured input slot 0
  52. reg [19:0] fc_status_addr; // Captured input slot 1
  53. wire [12:0] fc_slotvalid; // Mapped "slot valid" value
  54. wire [12:0] fc_slotreq; // Mapped "slot request" value
  55. // Command FSM
  56. localparam [1:0]
  57. CS_IDLE = 0,
  58. CS_SUBMIT = 1,
  59. CS_WAIT = 2,
  60. CS_CAPTURE = 3;
  61. reg [1:0] cmd_state;
  62. reg [1:0] cmd_state_nxt;
  63. // PCM samples
  64. reg pcm_out_frame;
  65. // GPIO
  66. reg gpio_ena_frame;
  67. // Interface to Shifter Unit
  68. reg [4:0] sui_bitcnt; // user -> amr
  69. reg sui_out_sync; // user -> amr
  70. reg [19:0] sui_out_data; // user -> amr
  71. reg [19:0] sui_in_data; // amr -> user
  72. reg [ 2:0] sui_flip; // amr -> user
  73. reg sui_ack; // user
  74. // Shift Unit
  75. reg [3:0] su_rst;
  76. reg [5:0] su_bitcnt;
  77. reg [2:0] su_trig;
  78. reg [19:0] su_data;
  79. reg [3:0] rst_amr_cnt;
  80. wire clk_amr;
  81. wire rst_amr;
  82. // IOs
  83. wire iob_sdata_in;
  84. wire iob_sdata_out;
  85. reg iob_sync;
  86. // Sequencer
  87. // ---------
  88. always @(posedge clk or posedge rst)
  89. if (rst)
  90. seq_wr_slot <= 13'h0001;
  91. else if (sui_ack)
  92. seq_wr_slot <= { seq_wr_slot[11:0], seq_wr_slot[12] };
  93. assign seq_rd_slot = { seq_wr_slot[1:0], seq_wr_slot[12:2] };
  94. // MC97 Frame control (TAG / SLOTREQ)
  95. // ------------------
  96. // Prepare output TAG value
  97. assign fc_tag_out = {
  98. cfg_run, // [15] Frame valid,
  99. (cmd_state == CS_SUBMIT), // [14] Slot 1 - Command Address
  100. (cmd_state == CS_SUBMIT) & reg_we, // [13] Slot 2 - Command Data
  101. 2'b00, // [12:11] Slot 3-4 - (n/a)
  102. pcm_out_frame, // [10] Slot 5 - Modem Line 1 PCM
  103. 6'd0, // [9:4] Slot 6-11 - (n/a)
  104. gpio_ena_frame, // [3] Slot 12 - GPIO
  105. 1'b0, // [2] Reserved
  106. 2'b00 // [1:0] Codec ID (always primary here)
  107. };
  108. // Capture input TAG value
  109. always @(posedge clk)
  110. if (sui_ack & seq_rd_slot[0])
  111. fc_tag_in <= sui_in_data[15:0];
  112. // Capture input STATUS_ADDR (Slot 1)
  113. always @(posedge clk)
  114. if (sui_ack & seq_rd_slot[1])
  115. fc_status_addr <= sui_in_data[15:0];
  116. // Map those
  117. generate
  118. for (i=1; i<13; i=i+1)
  119. assign fc_slotvalid[i] = fc_tag_in[15-i];
  120. endgenerate
  121. assign fc_slotvalid[0] = 1'b0; // Slot 0 fixed to 0 (special)
  122. generate
  123. for (i=3; i<13; i=i+1)
  124. assign fc_slotreq[i] = fc_status_addr[14-i];
  125. endgenerate
  126. assign fc_slotreq[2:0] = 3'b000; // Slot 0...2 fixed to 0 (special)
  127. // User Side status
  128. // Codec ready flag
  129. assign stat_codec_ready = fc_tag_in[15];
  130. // Slot valid flags
  131. always @(posedge clk)
  132. if (rst)
  133. stat_slot_valid[12:1] <= 1'b0;
  134. else
  135. stat_slot_valid[12:1] <= (stat_slot_valid[12:1] | fc_slotvalid[12:1]) & {12{~stat_clr}};
  136. initial
  137. stat_slot_valid[0] = 1'b0; // Slot 0 fixed to 0 (special)
  138. // Slot request flags
  139. always @(posedge clk)
  140. if (rst)
  141. stat_slot_req[12:3] <= 0;
  142. else
  143. stat_slot_req[12:3] <= (stat_slot_req[12:3] | fc_slotreq[12:3]) & {10{~stat_clr}};
  144. initial
  145. stat_slot_req[2:0] = 3'b000; // Slot 0-2 fixed to 0 (special)
  146. // Command FSM
  147. // -----------
  148. // State register
  149. always @(posedge clk)
  150. if (rst)
  151. cmd_state <= CS_IDLE;
  152. else
  153. cmd_state <= cmd_state_nxt;
  154. // Next-State
  155. always @(*)
  156. begin
  157. // Default is no-change
  158. cmd_state_nxt = cmd_state;
  159. // Transistions
  160. case (cmd_state)
  161. CS_IDLE:
  162. // Start new access for frame beginning
  163. if (sui_ack & seq_wr_slot[12] & reg_valid)
  164. cmd_state_nxt = CS_SUBMIT;
  165. CS_SUBMIT:
  166. // Command has been sent in this frame
  167. if (sui_ack & seq_wr_slot[12])
  168. // If it was a write, we're done.
  169. // For reads, we need to wait for an answer
  170. cmd_state_nxt = reg_we ? CS_IDLE : CS_WAIT;
  171. CS_WAIT:
  172. // No matter what, we move onto capture at the next slot
  173. // But here we check if the read worked or not (see reg_rerr)
  174. if (sui_ack & seq_rd_slot[1])
  175. cmd_state_nxt = CS_CAPTURE;
  176. CS_CAPTURE:
  177. if (sui_ack)
  178. cmd_state_nxt = CS_IDLE;
  179. endcase
  180. end
  181. // Ack
  182. always @(posedge clk)
  183. begin
  184. // Default
  185. reg_ack <= 1'b0;
  186. // Write ack
  187. if ((cmd_state == CS_SUBMIT) & sui_ack & seq_wr_slot[12] & reg_we)
  188. reg_ack <= 1'b1;
  189. // Read ack
  190. if ((cmd_state == CS_CAPTURE) & sui_ack)
  191. reg_ack <= 1'b1;
  192. end
  193. // Read error ?
  194. always @(posedge clk)
  195. if ((cmd_state == CS_WAIT) & sui_ack & seq_rd_slot[1])
  196. reg_rerr <= (sui_in_data[18:13] != reg_addr) | (fc_slotvalid[2:1] != 2'b11);
  197. // Read data
  198. assign reg_rdata = sui_in_data[19:4];
  199. // PCM samples
  200. // -----------
  201. // Output
  202. always @(posedge clk)
  203. if (sui_ack & seq_wr_slot[12])
  204. pcm_out_frame <= ~fc_slotreq[5];
  205. always @(posedge clk)
  206. pcm_out_ack <= sui_ack & seq_wr_slot[5] & pcm_out_frame;
  207. // Input
  208. assign pcm_in_data = sui_in_data[19:4];
  209. always @(posedge clk)
  210. pcm_in_stb <= sui_ack & seq_rd_slot[5] & fc_slotvalid[5];
  211. // GPIO (slot 12)
  212. // ----
  213. // Register enable status for the frame
  214. always @(posedge clk)
  215. if (sui_ack & seq_wr_slot[12])
  216. gpio_ena_frame <= gpio_ena;
  217. // Capture GPIO input
  218. always @(posedge clk)
  219. if (sui_ack & seq_rd_slot[12])
  220. gpio_in <= sui_in_data;
  221. // Shifter control
  222. // ---------------
  223. always @(posedge clk or posedge rst)
  224. if (rst) begin
  225. sui_bitcnt <= 5'd0;
  226. sui_out_sync <= 1'b0;
  227. sui_out_data <= 20'h00000;
  228. end else if (sui_ack) begin
  229. sui_bitcnt <= seq_wr_slot[0] ? 5'd14 : 5'd18;
  230. sui_out_sync <= seq_wr_slot[0];
  231. sui_out_data <= 20'h00000;
  232. (* parallel_case *)
  233. case (1'b1)
  234. seq_wr_slot[ 0]: sui_out_data <= { fc_tag_out, 4'h0 };
  235. seq_wr_slot[ 1]: sui_out_data <= (cmd_state == CS_SUBMIT) ? { ~reg_we, reg_addr, 13'h0000 } : 20'h00000;
  236. seq_wr_slot[ 2]: sui_out_data <= ((cmd_state == CS_SUBMIT) & reg_we) ? { reg_wdata, 4'h0 } : 20'h00000;
  237. seq_wr_slot[ 5]: sui_out_data <= pcm_out_frame ? { pcm_out_data, 4'h0 } : 20'h00000;
  238. seq_wr_slot[12]: sui_out_data <= gpio_ena_frame ? gpio_out : 20'h00000;
  239. endcase
  240. end
  241. // Shifter
  242. // -------
  243. // Clock input
  244. SB_GB_IO #(
  245. .PIN_TYPE(6'b 0000_01),
  246. .PULLUP(1'b0),
  247. .IO_STANDARD("SB_LVCMOS")
  248. ) clk_gb_I (
  249. .PACKAGE_PIN (mc97_bitclk),
  250. .GLOBAL_BUFFER_OUTPUT (clk_amr)
  251. );
  252. // Reset
  253. always @(posedge clk_amr or posedge rst)
  254. if (rst)
  255. rst_amr_cnt <= 4'hf;
  256. else
  257. rst_amr_cnt <= rst_amr_cnt + {4{rst_amr_cnt[3]}};
  258. SB_GB rst_gbuf_I (
  259. .USER_SIGNAL_TO_GLOBAL_BUFFER (rst_amr_cnt[3]),
  260. .GLOBAL_BUFFER_OUTPUT (rst_amr)
  261. );
  262. // Bit Counter
  263. always @(posedge clk_amr or posedge rst_amr)
  264. if (rst_amr)
  265. su_bitcnt <= 6'h3f;
  266. else
  267. su_bitcnt <= su_bitcnt[5] ? (su_bitcnt + {6{su_bitcnt[5]}}) : { 1'b1, sui_bitcnt };
  268. always @(*)
  269. su_trig[0] = ~su_bitcnt[5];
  270. always @(posedge clk_amr)
  271. su_trig[2:1] <= su_trig[1:0];
  272. // Sync signal
  273. always @(posedge clk_amr)
  274. iob_sync <= su_trig[0] ? sui_out_sync : iob_sync;
  275. // Data shift register
  276. always @(posedge clk_amr)
  277. su_data <= su_trig[1] ? { sui_out_data } : { su_data[18:0], iob_sdata_in };
  278. assign iob_sdata_out = su_data[19];
  279. // Data in capture register
  280. always @(posedge clk_amr)
  281. if (su_trig[1])
  282. sui_in_data[19:1] <= { su_data[17:0], iob_sdata_in };
  283. always @(posedge clk_amr)
  284. if (su_trig[2])
  285. sui_in_data[0] <= iob_sdata_in;
  286. // Flip signal
  287. always @(posedge clk_amr)
  288. if (rst_amr)
  289. sui_flip[0] <= 1'b0;
  290. else
  291. sui_flip[0] <= sui_flip[0] ^ su_trig[2];
  292. always @(posedge clk)
  293. begin
  294. if (rst) begin
  295. sui_flip[2:1] <= 2'b00;
  296. sui_ack <= 1'b0;
  297. end else begin
  298. sui_flip[2:1] <= sui_flip[1:0];
  299. sui_ack <= sui_flip[2] ^ sui_flip[1];
  300. end
  301. end
  302. // IOBs
  303. // ----
  304. SB_IO #(
  305. .PIN_TYPE (6'b0101_00),
  306. .PULLUP (1'b0),
  307. .IO_STANDARD ("SB_LVCMOS")
  308. ) iob_sdata_out_I (
  309. .PACKAGE_PIN (mc97_sdata_out),
  310. .OUTPUT_CLK (clk_amr),
  311. .D_OUT_0 (iob_sdata_out)
  312. );
  313. SB_IO #(
  314. .PIN_TYPE (6'b0000_00),
  315. .PULLUP (1'b0),
  316. .IO_STANDARD ("SB_LVCMOS")
  317. ) iob_sdata_in_I (
  318. .PACKAGE_PIN (mc97_sdata_in),
  319. .INPUT_CLK (clk_amr),
  320. .D_IN_1 (iob_sdata_in)
  321. );
  322. SB_IO #(
  323. .PIN_TYPE (6'b0101_00),
  324. .PULLUP (1'b0),
  325. .IO_STANDARD ("SB_LVCMOS")
  326. ) iob_sync_I (
  327. .PACKAGE_PIN (mc97_sync),
  328. .OUTPUT_CLK (clk_amr),
  329. .D_OUT_0 (iob_sync)
  330. );
  331. endmodule // mc97