hdmi_out.v 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /*
  2. * hdmi_out.v
  3. *
  4. * vim: ts=4 sw=4
  5. *
  6. * Copyright (C) 2020-2021 Sylvain Munaut <tnt@246tNt.com>
  7. * SPDX-License-Identifier: CERN-OHL-P-2.0
  8. */
  9. `default_nettype none
  10. module hdmi_out #(
  11. parameter integer DW = 4,
  12. )(
  13. // HDMI pads
  14. output wire [DW-1:0] hdmi_data,
  15. output wire hdmi_hsync,
  16. output wire hdmi_vsync,
  17. output wire hdmi_de,
  18. output wire hdmi_clk,
  19. // Memory interface
  20. output wire [31:0] mi_addr,
  21. output wire [ 6:0] mi_len,
  22. output wire mi_rw,
  23. output wire mi_valid,
  24. input wire mi_ready,
  25. output wire [31:0] mi_wdata, // Not used
  26. input wire mi_wack, // Not used
  27. input wire mi_wlast, // Not used
  28. input wire [31:0] mi_rdata,
  29. input wire mi_rstb,
  30. input wire mi_rlast,
  31. // Wishbone interface
  32. input wire [31:0] wb_wdata,
  33. output wire [31:0] wb_rdata,
  34. input wire [ 6:0] wb_addr,
  35. input wire wb_we,
  36. input wire wb_cyc,
  37. output reg wb_ack,
  38. // Clocks / Sync / Reset
  39. input wire clk_1x,
  40. input wire clk_4x,
  41. input wire sync_4x,
  42. input wire rst
  43. );
  44. genvar i;
  45. // Signals
  46. // -------
  47. // Timing Generator
  48. wire vt_hsync;
  49. wire vt_vsync;
  50. wire vt_de;
  51. wire vt_hfirst;
  52. wire vt_vfirst;
  53. wire vt_vlast;
  54. wire vt_trig;
  55. // DMA config
  56. reg [31:0] dma_cfg_base;
  57. reg [ 6:0] dma_cfg_bn_cnt;
  58. reg [ 6:0] dma_cfg_bn_len;
  59. reg [ 6:0] dma_cfg_bl_len;
  60. reg [ 7:0] dma_cfg_bl_inc;
  61. reg dma_run;
  62. // DMA runtime
  63. reg [31:0] dma_addr;
  64. reg [ 7:0] dma_cnt;
  65. reg dma_last;
  66. wire dma_valid;
  67. // Video Buffer
  68. reg vb_pingpong;
  69. reg [ 7:0] vb_waddr;
  70. wire [31:0] vb_wdata;
  71. wire vb_wren;
  72. reg [ 8:0] vb_raddr;
  73. wire [15:0] vb_rdata;
  74. // Palette
  75. wire [DW-1:0] pal_wdata;
  76. wire [ 5:0] pal_waddr;
  77. reg pal_wren;
  78. // Video Out
  79. reg [ 1:0] frame_cnt;
  80. wire [DW-1:0] vo_data[0:3];
  81. wire vo_hsync;
  82. wire vo_vsync;
  83. wire vo_de;
  84. // Wishbone interface
  85. // ------------------
  86. // Ack
  87. always @(posedge clk_1x)
  88. wb_ack <= wb_cyc & ~wb_ack;
  89. // Register Write
  90. always @(posedge clk_1x or posedge rst)
  91. if (rst) begin
  92. dma_run <= 1'b0;
  93. dma_cfg_base <= 0;
  94. dma_cfg_bn_cnt <= 0;
  95. dma_cfg_bn_len <= 0;
  96. dma_cfg_bl_len <= 0;
  97. dma_cfg_bl_inc <= 0;
  98. end else if (wb_cyc & ~wb_ack & ~wb_addr[6]) begin
  99. if (wb_addr[0])
  100. dma_cfg_base <= wb_wdata;
  101. else begin
  102. dma_run <= wb_wdata[31];
  103. dma_cfg_bn_cnt <= wb_wdata[30:24];
  104. dma_cfg_bn_len <= wb_wdata[22:16];
  105. dma_cfg_bl_len <= wb_wdata[14: 8];
  106. dma_cfg_bl_inc <= wb_wdata[ 7: 0];
  107. end
  108. end
  109. // Palette write
  110. assign pal_wdata = wb_wdata[DW-1:0];
  111. assign pal_waddr = wb_addr[5:0];
  112. always @(posedge clk_1x)
  113. pal_wren <= wb_cyc & ~wb_ack & wb_addr[6];
  114. // No read support
  115. assign wb_rdata = 32'h00000000;
  116. // Timing generator
  117. // ----------------
  118. // Standard 1080p60
  119. vid_tgen #(
  120. .H_WIDTH (12),
  121. .V_WIDTH (12),
  122. .H_FP ( 88 / 4),
  123. .H_SYNC ( 44 / 4),
  124. .H_BP ( 148 / 4),
  125. .H_ACTIVE (1920 / 4),
  126. .V_FP ( 4),
  127. .V_SYNC ( 5),
  128. .V_BP ( 36),
  129. .V_ACTIVE (1080)
  130. ) hdmi_tgen_I (
  131. .vid_hsync (vt_hsync),
  132. .vid_vsync (vt_vsync),
  133. .vid_active (vt_de),
  134. .vid_h_first (vt_hfirst),
  135. .vid_h_last (),
  136. .vid_v_first (vt_vfirst),
  137. .vid_v_last (vt_vlast),
  138. .clk (clk_1x),
  139. .rst (rst)
  140. );
  141. assign vt_trig = vt_de & vt_hfirst;
  142. // DMA
  143. // ---
  144. // DMA requests
  145. always @(posedge clk_1x)
  146. begin
  147. if (~dma_run)
  148. dma_cnt <= 8'h00;
  149. else if (vt_trig)
  150. dma_cnt <= { 1'b1, dma_cfg_bn_cnt };
  151. else if (mi_ready & mi_valid)
  152. dma_cnt <= dma_cnt - 1;
  153. end
  154. always @(posedge clk_1x)
  155. if (vt_trig)
  156. dma_last <= (dma_cfg_bn_cnt[6:0] == 6'h00);
  157. else if (mi_ready & mi_valid)
  158. dma_last <= (dma_cnt[6:0] == 6'h01);
  159. assign dma_valid = dma_cnt[7];
  160. always @(posedge clk_1x)
  161. if (vt_trig & vt_vlast)
  162. dma_addr <= dma_cfg_base;
  163. else if (mi_ready & mi_valid)
  164. dma_addr <= dma_addr + (dma_last ? dma_cfg_bl_inc : dma_cfg_bn_len) + 1;
  165. // DMA Memory interface
  166. assign mi_addr = dma_addr;
  167. assign mi_len = dma_last ? dma_cfg_bl_len : dma_cfg_bn_len;
  168. assign mi_rw = 1'b1;
  169. assign mi_valid = dma_valid;
  170. assign mi_wdata = 32'hxxxxxxxx;
  171. // Buffer write path
  172. always @(posedge clk_1x)
  173. if (vt_trig)
  174. vb_waddr <= 8'h00;
  175. else
  176. vb_waddr <= vb_waddr + mi_rstb;
  177. assign vb_wdata = mi_rdata;
  178. assign vb_wren = mi_rstb;
  179. // Video Buffer
  180. // ------------
  181. // Ping-Pong
  182. always @(posedge clk_1x)
  183. if (rst)
  184. vb_pingpong <= 1'b0;
  185. else
  186. vb_pingpong <= vb_pingpong ^ vt_trig;
  187. // Memory
  188. hdmi_buf line_I (
  189. .waddr ({vb_pingpong, vb_waddr}),
  190. .wdata (vb_wdata),
  191. .wren (vb_wren),
  192. .raddr ({~vb_pingpong, vb_raddr}),
  193. .rdata (vb_rdata),
  194. .clk (clk_1x)
  195. );
  196. // Output
  197. // ------
  198. // Frame counter (for temporal dither)
  199. always @(posedge clk_1x)
  200. if (vt_trig & vt_vfirst)
  201. frame_cnt <= frame_cnt + 1;
  202. // Buffer read
  203. always @(posedge clk_1x)
  204. if (vt_trig)
  205. vb_raddr <= 9'h000;
  206. else
  207. vb_raddr <= vb_raddr + vt_de;
  208. // Palette lookup
  209. generate
  210. for (i=0; i<4; i=i+1)
  211. ram_sdp #(
  212. .AWIDTH(6),
  213. .DWIDTH(DW)
  214. ) pal_I (
  215. .wr_addr (pal_waddr),
  216. .wr_data (pal_wdata),
  217. .wr_ena (pal_wren),
  218. .rd_addr ({frame_cnt, vb_rdata[(3-i)*4+:4]}),
  219. .rd_data (vo_data[i]),
  220. .rd_ena (1'b1),
  221. .clk (clk_1x)
  222. );
  223. endgenerate
  224. // Control delay
  225. delay_bus #(3, 3) dly_vs_I (
  226. .d ({vt_hsync, vt_vsync, vt_de}),
  227. .q ({vo_hsync, vo_vsync, vo_de}),
  228. .clk (clk_1x)
  229. );
  230. // PHY
  231. hdmi_phy_4x #(
  232. .DW(DW)
  233. ) phy_I (
  234. .hdmi_data (hdmi_data),
  235. .hdmi_hsync (hdmi_hsync),
  236. .hdmi_vsync (hdmi_vsync),
  237. .hdmi_de (hdmi_de),
  238. .hdmi_clk (hdmi_clk),
  239. .in_data0 (vo_data[0]),
  240. .in_data1 (vo_data[1]),
  241. .in_data2 (vo_data[2]),
  242. .in_data3 (vo_data[3]),
  243. .in_hsync (vo_hsync),
  244. .in_vsync (vo_vsync),
  245. .in_de (vo_de),
  246. .clk_1x (clk_1x),
  247. .clk_4x (clk_4x),
  248. .clk_sync (sync_4x)
  249. );
  250. endmodule