hdmi_out.v 7.1 KB

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