BGWrenderer.v 14 KB

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