vid_text.v 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /*
  2. * vid_text.v
  3. *
  4. * vim: ts=4 sw=4
  5. *
  6. * Video Text Mode generator
  7. *
  8. * Copyright (C) 2019 Sylvain Munaut <tnt@246tNt.com>
  9. * All rights reserved.
  10. *
  11. * BSD 3-clause, see LICENSE.bsd
  12. *
  13. * Redistribution and use in source and binary forms, with or without
  14. * modification, are permitted provided that the following conditions are met:
  15. * * Redistributions of source code must retain the above copyright
  16. * notice, this list of conditions and the following disclaimer.
  17. * * Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in the
  19. * documentation and/or other materials provided with the distribution.
  20. * * Neither the name of the <organization> nor the
  21. * names of its contributors may be used to endorse or promote products
  22. * derived from this software without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  25. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  26. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  27. * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  28. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  29. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  30. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  31. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  32. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  33. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34. */
  35. `default_nettype none
  36. module vid_text (
  37. // Timing input
  38. input wire vid_active_0,
  39. input wire vid_h_first_0,
  40. input wire vid_h_last_0,
  41. input wire vid_v_first_0,
  42. input wire vid_v_last_0,
  43. // Pixel output
  44. output wire [15:0] vid_pix0_11,
  45. output wire [15:0] vid_pix1_11,
  46. // Bus interface
  47. input wire [15:0] bus_addr,
  48. input wire [15:0] bus_din,
  49. output wire [15:0] bus_dout,
  50. input wire bus_cyc,
  51. input wire bus_we,
  52. output wire bus_ack,
  53. // Clock / Reset
  54. input wire clk,
  55. input wire rst
  56. );
  57. // Signals
  58. // -------
  59. // Char look-up
  60. reg [10:0] cl_y_cnt_0;
  61. reg [ 9:0] cl_y_cnt_1;
  62. reg [ 9:0] cl_x_cnt_1;
  63. reg cl_fetch_1;
  64. reg cl_valid_1;
  65. wire cl_stb_3;
  66. wire cl_valid_3;
  67. wire [15:0] cl_char_4;
  68. // Glyph look-up
  69. reg [ 1:0] gl_x_4;
  70. wire [ 3:0] gl_y_4;
  71. reg gl_fetch_4;
  72. wire gl_flip_x_4;
  73. wire gl_flip_y_4;
  74. wire gl_flip_x_7;
  75. wire [ 3:0] gl_pixa_7;
  76. wire [ 3:0] gl_pixb_7;
  77. reg [ 3:0] gl_pix0_8;
  78. reg [ 3:0] gl_pix1_8;
  79. wire [ 7:0] gl_attrs_8;
  80. wire gl_valid_8;
  81. // RAM fetch interfaces
  82. wire [13:0] sm_addr_1;
  83. wire [15:0] sm_data_4;
  84. wire sm_read_1;
  85. wire [13:0] gm_addr_4;
  86. wire [15:0] gm_data_7;
  87. wire gm_read_4;
  88. wire [ 7:0] cm_addr0_8;
  89. wire [ 7:0] cm_addr1_8;
  90. wire [15:0] cm_data0_11;
  91. wire [15:0] cm_data1_11;
  92. wire cm_read_8;
  93. wire cm_zero_8;
  94. // RAM bus interfaces
  95. wire smb_ready;
  96. reg smb_read;
  97. reg smb_zero;
  98. reg smb_write;
  99. wire gmb_ready;
  100. reg gmb_read;
  101. reg gmb_zero;
  102. reg gmb_write;
  103. wire cmb_ready;
  104. reg cmb_read;
  105. reg cmb_zero;
  106. reg cmb_write;
  107. wire [15:0] smb_dout;
  108. wire [15:0] gmb_dout;
  109. wire [15:0] cmb_dout;
  110. // Bus interface
  111. reg smb_req;
  112. wire smb_clear;
  113. reg gmb_req;
  114. wire gmb_clear;
  115. reg cmb_req;
  116. wire cmb_clear;
  117. reg bus_ack_wait;
  118. wire bus_req_ok;
  119. reg [2:0] bus_req_ok_dly;
  120. // Char lookup
  121. // -----------
  122. // Y counter
  123. always @(posedge clk)
  124. if (vid_v_first_0)
  125. // Start at -27 to center the 1024 in the 1080 of full HD
  126. cl_y_cnt_0 <= 11'h7e5;
  127. else
  128. cl_y_cnt_0 <= cl_y_cnt_0 + vid_h_last_0;
  129. always @(posedge clk)
  130. cl_y_cnt_1 <= cl_y_cnt_0[9:0];
  131. // X counter
  132. always @(posedge clk)
  133. if (vid_h_first_0)
  134. cl_x_cnt_1 <= 0;
  135. else
  136. cl_x_cnt_1 <= cl_x_cnt_1 + 1;
  137. // Valid flag
  138. always @(posedge clk)
  139. cl_valid_1 <= ~cl_y_cnt_0[10] & vid_active_0;
  140. // Fetch
  141. always @(posedge clk)
  142. cl_fetch_1 <= ~cl_y_cnt_0[10] & vid_active_0 & (vid_h_first_0 | (cl_x_cnt_1[1:0] == 3'b11));
  143. // RAM interface
  144. assign sm_addr_1 = { cl_y_cnt_1[9:4], cl_x_cnt_1[9:2] };
  145. assign sm_read_1 = cl_fetch_1;
  146. assign cl_char_4 = sm_data_4;
  147. // Provide some sync signals to the next stage
  148. delay_bit #(2) dly_stb13 ( .d(cl_fetch_1), .q(cl_stb_3), .clk(clk) );
  149. delay_bit #(2) dly_valid13 ( .d(cl_valid_1), .q(cl_valid_3), .clk(clk) );
  150. // Glyph lookup
  151. // ------------
  152. // X Counter
  153. always @(posedge clk)
  154. if (cl_stb_3)
  155. gl_x_4 <= 2'b00;
  156. else
  157. gl_x_4 <= gl_x_4 + 1;
  158. // Y counter
  159. delay_bus #(3, 4) dly_y_cnt ( .d(cl_y_cnt_1[3:0]), .q(gl_y_4), .clk(clk) );
  160. // Fetch
  161. always @(posedge clk)
  162. gl_fetch_4 <= cl_stb_3 | gl_x_4[0];
  163. // X/Y flips attributes
  164. assign gl_flip_y_4 = cl_char_4[10] & ~cl_char_4[9];
  165. assign gl_flip_x_4 = cl_char_4[11] & ~cl_char_4[9];
  166. // RAM interface
  167. assign gm_addr_4 = {
  168. cl_char_4[8:0],
  169. gl_y_4 ^ { 4{gl_flip_y_4} }, // Handle Y-flip
  170. gl_x_4[1] ^ gl_flip_x_4 // Handle X-flip
  171. };
  172. assign gm_read_4 = gl_fetch_4;
  173. // Delay control signal for the mux
  174. delay_bit #(3) dly_flip_h ( .d(gl_flip_x_4), .q(gl_flip_x_7), .clk(clk) );
  175. // Mux
  176. assign gl_pixa_7 = (gl_x_4[0] ^ gl_flip_x_7) ? gm_data_7[11: 8] : gm_data_7[3:0];
  177. assign gl_pixb_7 = (gl_x_4[0] ^ gl_flip_x_7) ? gm_data_7[15:12] : gm_data_7[7:4];
  178. always @(posedge clk)
  179. begin
  180. gl_pix0_8 <= gl_flip_x_7 ? gl_pixa_7 : gl_pixb_7;
  181. gl_pix1_8 <= gl_flip_x_7 ? gl_pixb_7 : gl_pixa_7;
  182. end
  183. // Forward the attributes & validity to the next stage
  184. delay_bit #(5) dly_valid38 ( .d(cl_valid_3), .q(gl_valid_8), .clk(clk) );
  185. delay_bus #(4, 8) dly_attrs ( .d(cl_char_4[15:8]), .q(gl_attrs_8), .clk(clk) );
  186. // Color lookup
  187. // ------------
  188. // RAM interface
  189. vid_color_map cmap0_I (
  190. .attrs(gl_attrs_8),
  191. .glyph(gl_pix0_8),
  192. .color(cm_addr0_8)
  193. );
  194. vid_color_map cmap1_I (
  195. .attrs(gl_attrs_8),
  196. .glyph(gl_pix1_8),
  197. .color(cm_addr1_8)
  198. );
  199. assign cm_read_8 = gl_valid_8;
  200. assign cm_zero_8 = ~gl_valid_8;
  201. assign vid_pix0_11 = cm_data0_11;
  202. assign vid_pix1_11 = cm_data1_11;
  203. // Memories
  204. // --------
  205. // Screen memory (contains chars and attributes)
  206. vid_shared_ram #(
  207. .TYPE("SPRAM")
  208. ) screen_mem_I (
  209. .p_addr_0(sm_addr_1),
  210. .p_read_0(sm_read_1),
  211. .p_zero_0(1'b0),
  212. .p_dout_3(sm_data_4),
  213. .s_addr_0(bus_addr[13:0]),
  214. .s_din_0(bus_din),
  215. .s_read_0(smb_read),
  216. .s_zero_0(smb_zero),
  217. .s_write_0(smb_write),
  218. .s_dout_3(smb_dout),
  219. .s_ready_0(smb_ready),
  220. .clk(clk),
  221. .rst(rst)
  222. );
  223. // Glyph memory (contains bitmap for each character)
  224. vid_shared_ram #(
  225. .TYPE("SPRAM")
  226. ) glyph_mem_I (
  227. .p_addr_0(gm_addr_4),
  228. .p_read_0(gm_read_4),
  229. .p_zero_0(1'b0),
  230. .p_dout_3(gm_data_7),
  231. .s_addr_0(bus_addr[13:0]),
  232. .s_din_0(bus_din),
  233. .s_read_0(gmb_read),
  234. .s_zero_0(gmb_zero),
  235. .s_write_0(gmb_write),
  236. .s_dout_3(gmb_dout),
  237. .s_ready_0(gmb_ready),
  238. .clk(clk),
  239. .rst(rst)
  240. );
  241. // Palette memory (contain mapping to real color)
  242. // (duplicated to allow 2 looks ups in //)
  243. vid_shared_ram #(
  244. .TYPE("EBR")
  245. ) color_mem_a_I (
  246. .p_addr_0(cm_addr0_8),
  247. .p_read_0(cm_read_8),
  248. .p_zero_0(cm_zero_8),
  249. .p_dout_3(cm_data0_11),
  250. .s_addr_0(bus_addr[7:0]),
  251. .s_din_0(bus_din),
  252. .s_read_0(cmb_read),
  253. .s_zero_0(cmb_zero),
  254. .s_write_0(cmb_write),
  255. .s_dout_3(cmb_dout),
  256. .s_ready_0(cmb_ready),
  257. .clk(clk),
  258. .rst(rst)
  259. );
  260. vid_shared_ram #(
  261. .TYPE("EBR")
  262. ) color_mem_b_I (
  263. .p_addr_0(cm_addr1_8),
  264. .p_read_0(cm_read_8),
  265. .p_zero_0(cm_zero_8),
  266. .p_dout_3(cm_data1_11),
  267. .s_addr_0(bus_addr[7:0]),
  268. .s_din_0(bus_din),
  269. .s_read_0(1'b0),
  270. .s_zero_0(1'b0),
  271. .s_write_0(cmb_write),
  272. .s_dout_3(),
  273. .s_ready_0(),
  274. .clk(clk),
  275. .rst(rst)
  276. );
  277. // External bus interface
  278. // ----------------------
  279. // Request lines from the various memories
  280. always @(posedge clk)
  281. if (smb_clear) begin
  282. smb_read <= 1'b0;
  283. smb_zero <= 1'b0;
  284. smb_write <= 1'b0;
  285. smb_req <= 1'b0;
  286. end else begin
  287. smb_read <= (bus_addr[15:14] == 2'b10) & ~bus_we;
  288. smb_zero <= (bus_addr[15:14] != 2'b10);
  289. smb_write <= (bus_addr[15:14] == 2'b10) & bus_we;
  290. smb_req <= (bus_addr[15:14] == 2'b10);
  291. end
  292. always @(posedge clk)
  293. if (gmb_clear) begin
  294. gmb_read <= 1'b0;
  295. gmb_zero <= 1'b0;
  296. gmb_write <= 1'b0;
  297. gmb_req <= 1'b0;
  298. end else begin
  299. gmb_read <= (bus_addr[15:14] == 2'b11) & ~bus_we;
  300. gmb_zero <= (bus_addr[15:14] != 2'b11);
  301. gmb_write <= (bus_addr[15:14] == 2'b11) & bus_we;
  302. gmb_req <= (bus_addr[15:14] == 2'b11);
  303. end
  304. always @(posedge clk)
  305. if (cmb_clear) begin
  306. cmb_read <= 1'b0;
  307. cmb_zero <= 1'b0;
  308. cmb_write <= 1'b0;
  309. cmb_req <= 1'b0;
  310. end else begin
  311. cmb_read <= (bus_addr[15:13] == 3'b011) & ~bus_we;
  312. cmb_zero <= (bus_addr[15:13] != 3'b011);
  313. cmb_write <= (bus_addr[15:13] == 3'b011) & bus_we;
  314. cmb_req <= (bus_addr[15:13] == 3'b011);
  315. end
  316. // Condition to force the requests to zero :
  317. // no access needed, ack pending or this cycle went through
  318. assign smb_clear = ~bus_cyc | bus_ack_wait | (smb_req & smb_ready);
  319. assign gmb_clear = ~bus_cyc | bus_ack_wait | (gmb_req & gmb_ready);
  320. assign cmb_clear = ~bus_cyc | bus_ack_wait | (cmb_req & cmb_ready);
  321. // Track when request are accepted by the RAM
  322. assign bus_req_ok = (smb_req & smb_ready) | (gmb_req & gmb_ready) | (cmb_req & cmb_ready);
  323. always @(posedge clk)
  324. bus_req_ok_dly <= { bus_req_ok_dly[1:0], bus_req_ok & ~bus_we };
  325. // ACK wait state tracking
  326. always @(posedge clk)
  327. if (rst)
  328. bus_ack_wait <= 1'b0;
  329. else
  330. bus_ack_wait <= ((bus_ack_wait & ~bus_we) | bus_req_ok) & ~bus_req_ok_dly[2];
  331. // Bus Ack
  332. assign bus_ack = bus_ack_wait & (bus_we | bus_req_ok_dly[2]);
  333. // Output is simply the OR of all memory since we force them to zero if
  334. // they're not accessed
  335. assign bus_dout = smb_dout | gmb_dout | cmb_dout;
  336. endmodule // vid_text
  337. module vid_color_map (
  338. input wire [7:0] attrs,
  339. input wire [3:0] glyph,
  340. output reg [7:0] color
  341. );
  342. always @(*)
  343. begin
  344. if (attrs[1]) begin
  345. if (glyph[3:2] == 2'b00)
  346. color <= { 4'b0000, glyph[1], glyph[0] ? attrs[7:5] : attrs[4:2] };
  347. else
  348. color <= { 4'b0001, glyph };
  349. end else begin
  350. color <= { attrs[7:4], glyph };
  351. end
  352. end
  353. endmodule