Video: Window fixes for WX=A6, no sprite fetching if sprites are disabled on DMG

* Video: Window fixes for WX=A6

* Video: no sprite fetching if sprites are disabled on DMG
This commit is contained in:
paulb-nl
2020-11-26 17:59:29 +01:00
committed by GitHub
parent 5c2db7714e
commit 5fd81a5ae0
2 changed files with 50 additions and 36 deletions

View File

@@ -24,7 +24,8 @@ module sprites (
input ce,
input ce_cpu,
input size16,
input isGBC_game,
input isGBC,
input sprite_en,
input lcd_on,
@@ -163,7 +164,7 @@ wire [0:9] sprite_x_matches = {
sprite_x[9] == h_cnt
};
assign sprite_fetch = |sprite_x_matches & oam_fetch;
assign sprite_fetch = |sprite_x_matches & oam_fetch & (isGBC | sprite_en);
wire [3:0] active_sprite =
sprite_x_matches[0] ? 4'd0 :

View File

@@ -71,8 +71,8 @@ sprites sprites (
.ce ( ce ),
.ce_cpu ( ce_cpu ),
.size16 ( lcdc_spr_siz ),
.isGBC_game ( isGBC&&isGBC_game ),
.isGBC ( isGBC ),
.sprite_en( lcdc_spr_ena ),
.lcd_on ( lcd_on ),
.v_cnt ( v_cnt ),
@@ -228,7 +228,8 @@ always @(posedge clk) begin
end
end
wire mode3_end = ~sprite_found & (pcnt == 8'd167);
wire mode3_end = isGBC ? pcnt_end : (~sprite_found & pcnt_end);
reg mode3_end_l;
always @(posedge clk) begin
if (!lcd_on) begin
@@ -254,7 +255,7 @@ assign vblank_irq = vblank_l;
// Except on the first line when the LCD is enabled after being disabled
// where it starts at cycle 0.
wire oam = lcd_on & ~end_of_line & ~oam_eval_end;
wire mode3 = lcd_on & ~mode3_end_l & oam_eval_end;
wire mode3 = lcd_on & (isGBC ? ~mode3_end : ~mode3_end_l) & oam_eval_end;
assign mode =
vblank_l ? 2'b01 :
@@ -361,6 +362,8 @@ reg skip_en;
reg [7:0] skip;
reg [7:0] pcnt;
wire pcnt_end = ( pcnt == (isGBC ? 8'd168 : 8'd167) );
wire pcnt_reset = end_of_line & ~vblank;
always @(posedge clk) begin
if (!lcd_on) begin
skip_en <= 1'b0;
@@ -382,12 +385,12 @@ always @(posedge clk) begin
// Pixels 0-7 are for fetching partially offscreen sprites and window.
// Pixels 8-167 are output to the display.
if(~skip_en && pcnt != 8'd167)
if(~skip_en & ~pcnt_end)
pcnt <= pcnt + 1'd1;
end
if (end_of_line & ~vblank) begin
if (pcnt_reset) begin
pcnt <= 8'd0;
end
end
@@ -395,11 +398,6 @@ end
reg [8:0] h_cnt; // max 455
reg [7:0] v_cnt; // max 153
reg [7:0] win_line;
// TODO: Fix window_x = A6. Hblank starts when it should be waiting for the window fetching to end
wire win_start = lcdc_win_ena && ~sprite_fetch_hold && ~skip_en && ~bg_shift_empty && (v_cnt >= wy) && (pcnt == wx) && (wx < 8'hA6);
reg window_ena;
// vcnt_reset goes high a few cycles after v_cnt is incremented to 153.
// It resets v_cnt back to 0 and keeps it in reset until the following line.
@@ -409,19 +407,16 @@ reg vcnt_reset;
always @(posedge clk) begin
if (!lcdc_on) begin
v_cnt <= 8'd0;
win_line <= 8'd0;
vcnt_reset <= 1'b0;
end else if (ce) begin
if (~vcnt_reset && h_cnt == 9'd455) begin
v_cnt <= v_cnt + 1'b1;
if (window_ena) win_line <= win_line + 1'b1;
end
if (end_of_line && &h_cnt[1:0]) begin
vcnt_reset <= line153;
if (line153) begin
v_cnt <= 8'd0;
win_line <= 8'd0;
end
end
end
@@ -436,35 +431,51 @@ reg [4:0] win_col;
wire [9:0] win_map_addr = {win_line[7:3], win_col[4:0]};
wire [9:0] bg_tile_map_addr = window_ena ? win_map_addr : bg_map_addr;
reg [7:0] win_line;
wire [2:0] tile_line = window_ena ? win_line[2:0] : bg_line[2:0];
reg window_match, window_ena_d;
wire win_start = mode3 && lcdc_win_ena && ~sprite_fetch_hold && ~skip_en && ~bg_shift_empty && (v_cnt >= wy) && (pcnt == wx) && (wx < 8'hA7);
wire window_ena = window_match & ~pcnt_reset & lcdc_win_ena;
always @(posedge clk) begin
if (!lcdc_on) begin
//reset counters
h_cnt <= 9'd0;
window_ena <= 1'b0;
window_match <= 1'b0;
window_ena_d <= 1'b0;
win_col <= 5'd0;
win_line <= 8'd0;
end else if (ce) begin
h_cnt <= h455 ? 9'd0 : h_cnt + 9'd1;
if(h_cnt != 455) begin
h_cnt <= h_cnt + 9'd1;
if(win_start) begin
win_col <= 5'd0; // window always start with its very left
window_ena <= 1'b1;
end
// Increment when fetching is done and not waiting for sprites.
if(window_ena && ~sprite_fetch_hold && bg_fetch_done && bg_reload_shift)
win_col <= win_col + 1'b1;
end else begin
window_ena <= 1'b0; // next line starts with background
// end of line reached
h_cnt <= 9'd0;
if(win_start) begin
window_match <= 1'b1;
end
window_ena_d <= window_ena;
if (vblank_l)
win_line <= 8'd0;
else if (window_ena_d & ~window_ena)
win_line <= win_line + 1'b1;
if (window_match & ~mode3_end_l & mode3_end) begin
// DMG glitch: If WX = A6 then window_match stays high through VBlank
// until WY > v_cnt which means the window always appears on line 0.
if (isGBC || wx != 8'hA6 || wy > v_cnt) begin
window_match <= 1'b0; // next line starts with background
end
end
// Increment when fetching is done and not waiting for sprites.
if(window_ena && ~sprite_fetch_hold && bg_fetch_done && bg_reload_shift)
win_col <= win_col + 1'b1;
if (~lcdc_win_ena | pcnt_reset) win_col <= 5'd0;
end
end
@@ -622,7 +633,9 @@ always @(posedge clk) begin
if (~sprite_fetch_hold || sprite_fetch_done) sprite_fetch_cycle <= 0;
// Window start, reset fetching
if (win_start || !mode3) begin
// DMG glitch: fetching is not reset if WX = A6. The following lines all show
// the window from the start of the line.
if ( (win_start && (isGBC || wx != 8'hA6)) || !mode3) begin
bg_fetch_cycle <= 0;
bg_shift_cnt <= 0;
end