BGWrenderer.v 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /*
  2. * Renders Background and Window plane
  3. */
  4. module BGWrenderer(
  5. // Video I/O
  6. input clk,
  7. input hs,
  8. input vs,
  9. input blank,
  10. input scale2x, // render vertically in 2x scaling (e.g. for HDMI to get full screen 320x240 on a 640x480 signal)
  11. // note: horizontally this scaling is always applied
  12. // Output pixels
  13. output wire [2:0] r,
  14. output wire [2:0] g,
  15. output wire [1:0] b,
  16. input [11:0] h_count, // line position in pixels including blanking
  17. input [11:0] v_count, // frame position in lines including blanking
  18. // VRAM32
  19. output [13:0] vram32_addr,
  20. input [31:0] vram32_q,
  21. // VRAM8
  22. output [13:0] vram8_addr,
  23. input [7:0] vram8_q
  24. );
  25. localparam VSTART = 86; // Line to start rendering
  26. localparam HSTART = 128; // About two tiles before blanking ends
  27. // Actions based on hTilePixelCounter value
  28. localparam
  29. fetch_bg_tile = 0,
  30. fetch_pattern_bg = 1,
  31. fetch_bg_color = 2,
  32. fetch_palette_bg = 3,
  33. fetch_wind_tile = 4,
  34. fetch_pattern_wind = 5,
  35. fetch_wind_color = 6,
  36. fetch_palette_wind = 7;
  37. // Rendering offsets
  38. reg [5:0] XtileOffset = 6'd0;
  39. reg [2:0] XfineOffset = 3'd0;
  40. // Tile and pixel counters
  41. reg [5:0] hTileCounter = 6'd0; // 40 hTiles
  42. reg [3:0] hTileDoublePixelCounter = 4'd0; // 16 pixels per tile
  43. wire [2:0] hTilePixelCounter = hTileDoublePixelCounter[3:1]; // 8 pixels per tile
  44. reg [4:0] vTileCounter = 5'd0; // 25 vTiles
  45. reg [3:0] vTileDoubleLineCounter = 4'd0; // 16 pixels per tile
  46. wire [2:0] vTileLineCounter = (scale2x) ?vTileDoubleLineCounter[3:1] : vTileDoubleLineCounter[2:0]; // 8 pixels per tile
  47. reg [10:0] bg_tile = 11'd0;
  48. reg [10:0] window_tile = 11'd0;
  49. reg [10:0] bg_tile_line = 11'd0; // does not include the horizontal position
  50. reg [10:0] window_tile_line = 11'd0; //does not include the horizontal position
  51. wire [10:0] bg_tile_next = (h_count < HSTART && vTileCounter == 5'd0) ? XtileOffset : bg_tile + XtileOffset;
  52. wire [10:0] window_tile_next = (h_count < HSTART && vTileCounter == 5'd0) ? 11'd0 : window_tile;
  53. // Updating tile and pixel counters
  54. always @(posedge clk)
  55. begin
  56. if (!vs)
  57. begin
  58. bg_tile <= 11'd0;
  59. bg_tile_line <= 11'd0;
  60. // Window tile starts at -1, since it does not have a buffer for fine scrolling
  61. window_tile <= 11'b11111111111;
  62. window_tile_line <= 11'b11111111111;
  63. end
  64. // Horizontal counters
  65. if (h_count < HSTART || v_count < VSTART-1 || v_count >= VSTART-1 + 400)
  66. begin
  67. hTileCounter <= 6'd0;
  68. hTileDoublePixelCounter <= 4'd0;
  69. bg_tile <= bg_tile_line;
  70. window_tile <= window_tile_line;
  71. end
  72. else
  73. begin
  74. hTileDoublePixelCounter <= hTileDoublePixelCounter + 1'b1;
  75. if (hTileDoublePixelCounter == 4'd15)
  76. begin
  77. hTileCounter <= hTileCounter + 1'b1;
  78. bg_tile <= bg_tile + 1'b1;
  79. window_tile <= window_tile + 1'b1;
  80. end
  81. end
  82. // Vertical counters
  83. if (h_count == 12'd0)
  84. begin
  85. if (v_count < VSTART || v_count >= VSTART + 400)
  86. begin
  87. vTileCounter <= 5'd0;
  88. vTileDoubleLineCounter <= 4'd0;
  89. bg_tile <= 11'd0;
  90. window_tile <= 11'd0;
  91. end
  92. else
  93. begin
  94. vTileDoubleLineCounter <= vTileDoubleLineCounter + 1'b1;
  95. if (scale2x)
  96. begin
  97. if (vTileDoubleLineCounter == 4'd15)
  98. begin
  99. vTileCounter <= vTileCounter + 1'b1;
  100. bg_tile_line <= bg_tile_line + 7'd64; // + number of tiles per line in bg plane
  101. window_tile_line <= window_tile_line + 6'd40; // + number of tiles per line in window plane
  102. end
  103. end
  104. else
  105. begin
  106. if (vTileDoubleLineCounter == 4'd7)
  107. begin
  108. vTileDoubleLineCounter <= 4'd0;
  109. vTileCounter <= vTileCounter + 1'b1;
  110. bg_tile_line <= bg_tile_line + 7'd64; // + number of tiles per line in bg plane
  111. window_tile_line <= window_tile_line + 6'd40; // + number of tiles per line in window plane
  112. end
  113. end
  114. end
  115. end
  116. end
  117. // Data for next tile
  118. reg [7:0] tile_index = 8'd0;
  119. reg [7:0] color_index = 8'd0;
  120. reg [15:0] pattern_bg_tile = 16'd0;
  121. reg [15:0] pattern_window_tile = 16'd0;
  122. reg [31:0] palette_bg_tile = 32'd0;
  123. //reg [31:0] palette_window_tile = 32'd0; // should not be needed
  124. // Data for current tile, should be updated at start of each tile
  125. reg [15:0] current_pattern_bg_tile = 16'd0;
  126. reg [15:0] current_pattern_window_tile = 16'd0;
  127. reg [31:0] current_palette_bg_tile = 32'd0;
  128. reg [31:0] current_palette_window_tile = 32'd0;
  129. // Reading from VRAM
  130. always @(posedge clk)
  131. begin
  132. // Parameters
  133. if (h_count == 12'd1)
  134. XtileOffset <= vram8_q;
  135. if (h_count == 12'd2)
  136. XfineOffset <= vram8_q;
  137. if (hTileDoublePixelCounter[0])
  138. begin
  139. case (hTilePixelCounter)
  140. fetch_bg_tile: tile_index <= vram8_q;
  141. fetch_pattern_bg: begin
  142. if (vTileLineCounter[0])
  143. pattern_bg_tile <= vram32_q[15:0];
  144. else
  145. pattern_bg_tile <= vram32_q[31:16];
  146. end
  147. fetch_bg_color: color_index <= vram8_q;
  148. fetch_palette_bg: palette_bg_tile <= vram32_q;
  149. fetch_wind_tile: tile_index <= vram8_q;
  150. fetch_pattern_wind: begin
  151. if (vTileLineCounter[0])
  152. pattern_window_tile <= vram32_q[15:0];
  153. else
  154. pattern_window_tile <= vram32_q[31:16];
  155. end
  156. fetch_wind_color: color_index <= vram8_q;
  157. //fetch_palette_wind: palette_window_tile <= vram32_q; // is not needed, because the data can be directly put into current_palette_window_tile
  158. endcase
  159. end
  160. if (hTileDoublePixelCounter == 4'd15)
  161. begin
  162. current_pattern_bg_tile <= pattern_bg_tile;
  163. current_pattern_window_tile <= pattern_window_tile;
  164. current_palette_bg_tile <= palette_bg_tile;
  165. current_palette_window_tile <= vram32_q;
  166. end
  167. end
  168. assign vram8_addr = (h_count == 12'd0) ? 8192: // tile scroll offset
  169. (h_count == 12'd1) ? 8193: // fine scroll offset
  170. (hTilePixelCounter == fetch_bg_tile) ? bg_tile_next:
  171. (hTilePixelCounter == fetch_bg_color) ? 2048 + bg_tile_next:
  172. (hTilePixelCounter == fetch_wind_tile) ? 4096 + window_tile_next:
  173. (hTilePixelCounter == fetch_wind_color) ? 6144 + window_tile_next:
  174. 14'd0;
  175. assign vram32_addr = (hTilePixelCounter == fetch_pattern_bg) ? (tile_index << 2) + (vTileLineCounter >> 1): //*4 because 4 addresses per tile
  176. (hTilePixelCounter == fetch_palette_bg) ? 1024 + color_index:
  177. (hTilePixelCounter == fetch_pattern_wind) ? (tile_index << 2) + (vTileLineCounter >> 1): //*4 because 4 addresses per tile
  178. (hTilePixelCounter == fetch_palette_wind) ? 1024 + color_index:
  179. 14'd0;
  180. // Pattern data for current pixel
  181. reg [1:0] current_pixel_pattern_bg;
  182. reg [1:0] current_pixel_pattern_window;
  183. always @(*)
  184. begin
  185. case (hTilePixelCounter)
  186. 3'd0: begin
  187. current_pixel_pattern_bg <= current_pattern_bg_tile[15:14];
  188. current_pixel_pattern_window <= current_pattern_window_tile[15:14];
  189. end
  190. 3'd1: begin
  191. current_pixel_pattern_bg <= current_pattern_bg_tile[13:12];
  192. current_pixel_pattern_window <= current_pattern_window_tile[13:12];
  193. end
  194. 3'd2: begin
  195. current_pixel_pattern_bg <= current_pattern_bg_tile[11:10];
  196. current_pixel_pattern_window <= current_pattern_window_tile[11:10];
  197. end
  198. 3'd3: begin
  199. current_pixel_pattern_bg <= current_pattern_bg_tile[9:8];
  200. current_pixel_pattern_window <= current_pattern_window_tile[9:8];
  201. end
  202. 3'd4: begin
  203. current_pixel_pattern_bg <= current_pattern_bg_tile[7:6];
  204. current_pixel_pattern_window <= current_pattern_window_tile[7:6];
  205. end
  206. 3'd5: begin
  207. current_pixel_pattern_bg <= current_pattern_bg_tile[5:4];
  208. current_pixel_pattern_window <= current_pattern_window_tile[5:4];
  209. end
  210. 3'd6: begin
  211. current_pixel_pattern_bg <= current_pattern_bg_tile[3:2];
  212. current_pixel_pattern_window <= current_pattern_window_tile[3:2];
  213. end
  214. 3'd7: begin
  215. current_pixel_pattern_bg <= current_pattern_bg_tile[1:0];
  216. current_pixel_pattern_window <= current_pattern_window_tile[1:0];
  217. end
  218. endcase
  219. end
  220. // Apply palette to current pixel pattern
  221. reg [2:0] bg_r;
  222. reg [2:0] bg_g;
  223. reg [1:0] bg_b;
  224. reg [2:0] window_r;
  225. reg [2:0] window_g;
  226. reg [1:0] window_b;
  227. always @(*)
  228. begin
  229. case (current_pixel_pattern_bg)
  230. 2'b00: begin
  231. bg_r <= current_palette_bg_tile[31:29];
  232. bg_g <= current_palette_bg_tile[28:26];
  233. bg_b <= current_palette_bg_tile[25:24];
  234. end
  235. 2'b01: begin
  236. bg_r <= current_palette_bg_tile[23:21];
  237. bg_g <= current_palette_bg_tile[20:18];
  238. bg_b <= current_palette_bg_tile[17:16];
  239. end
  240. 2'b10: begin
  241. bg_r <= current_palette_bg_tile[15:13];
  242. bg_g <= current_palette_bg_tile[12:10];
  243. bg_b <= current_palette_bg_tile[9:8];
  244. end
  245. 2'b11: begin
  246. bg_r <= current_palette_bg_tile[7:5];
  247. bg_g <= current_palette_bg_tile[4:2];
  248. bg_b <= current_palette_bg_tile[1:0];
  249. end
  250. endcase
  251. case (current_pixel_pattern_window)
  252. 2'b00: begin
  253. window_r <= current_palette_window_tile[31:29];
  254. window_g <= current_palette_window_tile[28:26];
  255. window_b <= current_palette_window_tile[25:24];
  256. end
  257. 2'b01: begin
  258. window_r <= current_palette_window_tile[23:21];
  259. window_g <= current_palette_window_tile[20:18];
  260. window_b <= current_palette_window_tile[17:16];
  261. end
  262. 2'b10: begin
  263. window_r <= current_palette_window_tile[15:13];
  264. window_g <= current_palette_window_tile[12:10];
  265. window_b <= current_palette_window_tile[9:8];
  266. end
  267. 2'b11: begin
  268. window_r <= current_palette_window_tile[7:5];
  269. window_g <= current_palette_window_tile[4:2];
  270. window_b <= current_palette_window_tile[1:0];
  271. end
  272. endcase
  273. end
  274. // Background pixel buffers for 8 pixels, so fine scrolling can be applied
  275. reg [23:0] buf_bg_r = 24'd0;
  276. reg [23:0] buf_bg_g = 24'd0;
  277. reg [15:0] buf_bg_b = 16'd0;
  278. always @(posedge clk)
  279. begin
  280. // Do only once per two cycles, since we are using a double horizontal resolution
  281. if (h_count[0])
  282. begin
  283. buf_bg_r <= {buf_bg_r[20:0], bg_r};
  284. buf_bg_g <= {buf_bg_g[20:0], bg_g};
  285. buf_bg_b <= {buf_bg_b[13:0], bg_b};
  286. end
  287. end
  288. reg [2:0] bg_r_sel;
  289. reg [2:0] bg_g_sel;
  290. reg [1:0] bg_b_sel;
  291. always @(*)
  292. begin
  293. case (XfineOffset)
  294. 3'd0: begin
  295. bg_r_sel <= buf_bg_r[23:21];
  296. bg_g_sel <= buf_bg_g[23:21];
  297. bg_b_sel <= buf_bg_b[15:14];
  298. end
  299. 3'd1: begin
  300. bg_r_sel <= buf_bg_r[20:18];
  301. bg_g_sel <= buf_bg_g[20:18];
  302. bg_b_sel <= buf_bg_b[13:12];
  303. end
  304. 3'd2: begin
  305. bg_r_sel <= buf_bg_r[17:15];
  306. bg_g_sel <= buf_bg_g[17:15];
  307. bg_b_sel <= buf_bg_b[11:10];
  308. end
  309. 3'd3: begin
  310. bg_r_sel <= buf_bg_r[14:12];
  311. bg_g_sel <= buf_bg_g[14:12];
  312. bg_b_sel <= buf_bg_b[9:8];
  313. end
  314. 3'd4: begin
  315. bg_r_sel <= buf_bg_r[11:9];
  316. bg_g_sel <= buf_bg_g[11:9];
  317. bg_b_sel <= buf_bg_b[7:6];
  318. end
  319. 3'd5: begin
  320. bg_r_sel <= buf_bg_r[8:6];
  321. bg_g_sel <= buf_bg_g[8:6];
  322. bg_b_sel <= buf_bg_b[5:4];
  323. end
  324. 3'd6: begin
  325. bg_r_sel <= buf_bg_r[5:3];
  326. bg_g_sel <= buf_bg_g[5:3];
  327. bg_b_sel <= buf_bg_b[3:2];
  328. end
  329. 3'd7: begin
  330. bg_r_sel <= buf_bg_r[2:0];
  331. bg_g_sel <= buf_bg_g[2:0];
  332. bg_b_sel <= buf_bg_b[1:0];
  333. end
  334. endcase
  335. end
  336. // Give priority to the window layer. Current method is by checking for a black palette for 0b00 pixels
  337. wire bgPriority = current_pixel_pattern_window == 2'b00 && current_palette_window_tile[31:24] == 8'd0;
  338. assign r = (bgPriority) ? bg_r_sel : window_r;
  339. assign g = (bgPriority) ? bg_g_sel : window_g;
  340. assign b = (bgPriority) ? bg_b_sel : window_b;
  341. endmodule