mirror of
https://github.com/MiSTer-devel/Gameboy_MiSTer.git
synced 2026-04-26 03:04:36 +00:00
Output blank image when LCD is off
The screen stays blank until 1 frame after the LCD is turned on. Fixes glitches during transitions in some games.
This commit is contained in:
13
Gameboy.sv
13
Gameboy.sv
@@ -542,6 +542,7 @@ wire lcd_clkena;
|
||||
wire [14:0] lcd_data;
|
||||
wire [1:0] lcd_mode;
|
||||
wire lcd_on;
|
||||
wire lcd_vsync;
|
||||
|
||||
assign AUDIO_S = 0;
|
||||
|
||||
@@ -590,6 +591,7 @@ gb gb (
|
||||
.lcd_data ( lcd_data ),
|
||||
.lcd_mode ( lcd_mode ),
|
||||
.lcd_on ( lcd_on ),
|
||||
.lcd_vsync ( lcd_vsync ),
|
||||
.speed ( speed ),
|
||||
|
||||
// serial port
|
||||
@@ -620,10 +622,13 @@ lcd lcd
|
||||
(
|
||||
// serial interface
|
||||
.clk_sys( clk_sys ),
|
||||
.pix_wr ( sgb_lcd_clkena & ce_cpu ),
|
||||
.ce ( ce_cpu ),
|
||||
|
||||
.lcd_clkena ( sgb_lcd_clkena ),
|
||||
.data ( sgb_lcd_data ),
|
||||
.mode ( sgb_lcd_mode ), // used to detect begin of new lines and frames
|
||||
.on ( sgb_lcd_on ),
|
||||
.lcd_vs ( sgb_lcd_vsync ),
|
||||
|
||||
.isGBC ( isGBC ),
|
||||
|
||||
@@ -658,7 +663,7 @@ wire [1:0] joy_p54;
|
||||
wire [3:0] joy_do_sgb;
|
||||
wire [14:0] sgb_lcd_data;
|
||||
wire [15:0] sgb_border_pix;
|
||||
wire sgb_lcd_clkena, sgb_lcd_on;
|
||||
wire sgb_lcd_clkena, sgb_lcd_on, sgb_lcd_vsync;
|
||||
wire [1:0] sgb_lcd_mode;
|
||||
wire sgb_pal_en;
|
||||
wire [1:0] sgb_en = {~status[24] ^ status[23], status[23]};
|
||||
@@ -685,6 +690,7 @@ sgb sgb (
|
||||
.lcd_clkena ( lcd_clkena ),
|
||||
.lcd_data ( lcd_data ),
|
||||
.lcd_mode ( lcd_mode ),
|
||||
.lcd_vsync ( lcd_vsync ),
|
||||
|
||||
.h_cnt ( h_cnt ),
|
||||
.v_cnt ( v_cnt ),
|
||||
@@ -694,7 +700,8 @@ sgb sgb (
|
||||
.sgb_lcd_data ( sgb_lcd_data ),
|
||||
.sgb_lcd_on ( sgb_lcd_on ),
|
||||
.sgb_lcd_clkena ( sgb_lcd_clkena ),
|
||||
.sgb_lcd_mode ( sgb_lcd_mode )
|
||||
.sgb_lcd_mode ( sgb_lcd_mode ),
|
||||
.sgb_lcd_vsync ( sgb_lcd_vsync )
|
||||
);
|
||||
|
||||
reg hs_o, vs_o;
|
||||
|
||||
4
rtl/gb.v
4
rtl/gb.v
@@ -52,6 +52,7 @@ module gb (
|
||||
output [14:0] lcd_data,
|
||||
output [1:0] lcd_mode,
|
||||
output lcd_on,
|
||||
output lcd_vsync,
|
||||
|
||||
output [1:0] joy_p54,
|
||||
input [3:0] joy_din,
|
||||
@@ -484,7 +485,8 @@ video video (
|
||||
.lcd_clkena ( lcd_clkena ),
|
||||
.lcd_data ( lcd_data ),
|
||||
.mode ( lcd_mode ),
|
||||
|
||||
.lcd_vsync ( lcd_vsync ),
|
||||
|
||||
.vram_rd ( video_rd ),
|
||||
.vram_addr ( video_addr ),
|
||||
.vram_data ( vram_do ),
|
||||
|
||||
47
rtl/lcd.v
47
rtl/lcd.v
@@ -6,7 +6,10 @@
|
||||
module lcd
|
||||
(
|
||||
input clk_sys,
|
||||
input pix_wr,
|
||||
input ce,
|
||||
input lcd_clkena,
|
||||
input lcd_vs,
|
||||
|
||||
input [14:0] data,
|
||||
|
||||
input [1:0] mode,
|
||||
@@ -45,22 +48,54 @@ module lcd
|
||||
reg [14:0] vbuffer_inptr;
|
||||
reg vbuffer_in_bank;
|
||||
reg lcd_off;
|
||||
reg blank_de, blank_output;
|
||||
reg [14:0] blank_data;
|
||||
|
||||
wire pix_wr = ce & (lcd_clkena | blank_de);
|
||||
always @(posedge clk_sys) begin
|
||||
reg old_lcd_off;
|
||||
reg old_lcd_off, old_on, old_lcd_vs;
|
||||
reg [8:0] blank_hcnt,blank_vcnt;
|
||||
|
||||
lcd_off <= !on || (mode == 2'd01);
|
||||
blank_de <= (!on && blank_output && blank_hcnt < 160 && blank_vcnt < 144);
|
||||
|
||||
if (pix_wr & ~lcd_off) vbuffer_inptr <= vbuffer_inptr + 1'd1;
|
||||
if (pix_wr) vbuffer_inptr <= vbuffer_inptr + 1'd1;
|
||||
|
||||
old_lcd_off <= lcd_off;
|
||||
if(~old_lcd_off & lcd_off) begin //lcd disabled or vsync restart pointer
|
||||
if(old_lcd_off ^ lcd_off) begin
|
||||
vbuffer_inptr <= 0;
|
||||
vbuffer_in_bank <= ~vbuffer_in_bank;
|
||||
if (lcd_off) vbuffer_in_bank <= ~vbuffer_in_bank; //LCD disabled or VBlank
|
||||
end
|
||||
|
||||
old_on <= on;
|
||||
if (old_on & ~on & ~blank_output) begin // LCD disabled, start blank output
|
||||
blank_output <= 1'b1;
|
||||
{blank_hcnt,blank_vcnt} <= 0;
|
||||
end
|
||||
|
||||
// Regenerate LCD timings for filling with blank color when LCD is off
|
||||
if (ce & ~on & blank_output) begin
|
||||
blank_data <= data;
|
||||
blank_hcnt <= blank_hcnt + 1'b1;
|
||||
if (blank_hcnt == 9'd455) begin
|
||||
blank_hcnt <= 0;
|
||||
blank_vcnt <= blank_vcnt + 1'b1;
|
||||
if (blank_vcnt == 9'd153) begin
|
||||
blank_vcnt <= 0;
|
||||
vbuffer_inptr <= 0;
|
||||
vbuffer_in_bank <= ~vbuffer_in_bank;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Output 1 blank frame until VSync after LCD is enabled
|
||||
old_lcd_vs <= lcd_vs;
|
||||
if (~old_lcd_vs & lcd_vs & blank_output)
|
||||
blank_output <= 0;
|
||||
end
|
||||
|
||||
reg [14:0] vbuffer[65536];
|
||||
always @(posedge clk_sys) if(pix_wr) vbuffer[{vbuffer_in_bank, vbuffer_inptr}] <= data;
|
||||
always @(posedge clk_sys) if(pix_wr) vbuffer[{vbuffer_in_bank, vbuffer_inptr}] <= (on & blank_output) ? blank_data : data;
|
||||
|
||||
|
||||
// Mode 00: h-blank
|
||||
|
||||
@@ -13,6 +13,7 @@ module sgb (
|
||||
input [14:0] lcd_data,
|
||||
input [1:0] lcd_mode,
|
||||
input lcd_on,
|
||||
input lcd_vsync,
|
||||
|
||||
input [8:0] h_cnt,
|
||||
input [8:0] v_cnt,
|
||||
@@ -31,7 +32,8 @@ module sgb (
|
||||
output reg [14:0] sgb_lcd_data,
|
||||
output reg sgb_lcd_clkena,
|
||||
output reg [1:0] sgb_lcd_mode,
|
||||
output reg sgb_lcd_on
|
||||
output reg sgb_lcd_on,
|
||||
output reg sgb_lcd_vsync
|
||||
);
|
||||
|
||||
localparam CMD_PAL01 = 5'h00;
|
||||
@@ -833,7 +835,7 @@ end
|
||||
|
||||
reg [14:0] lcd_data_r;
|
||||
reg [1:0] pal_no;
|
||||
reg lcd_clkena_r, lcd_on_r;
|
||||
reg lcd_clkena_r, lcd_on_r, lcd_vsync_r;
|
||||
reg [1:0] lcd_mode_r;
|
||||
reg [1:0] mask_en_r;
|
||||
wire [1:0] lcd_data_2 = lcd_data_r[1:0];
|
||||
@@ -848,6 +850,7 @@ always @(posedge clk_sys) begin
|
||||
lcd_clkena_r <= lcd_clkena;
|
||||
lcd_mode_r <= lcd_mode;
|
||||
lcd_on_r <= lcd_on;
|
||||
lcd_vsync_r <= lcd_vsync;
|
||||
|
||||
if (~sgb_en | ((~output_sgb_pal | tint) & !mask_en_r) ) begin
|
||||
sgb_lcd_data <= lcd_data_r;
|
||||
@@ -863,6 +866,7 @@ always @(posedge clk_sys) begin
|
||||
sgb_lcd_mode <= lcd_mode_r;
|
||||
sgb_lcd_on <= lcd_on_r;
|
||||
sgb_pal_en <= sgb_en & ( (output_sgb_pal & ~tint) || |mask_en_r);
|
||||
sgb_lcd_vsync <= lcd_vsync_r;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
14
rtl/video.v
14
rtl/video.v
@@ -39,6 +39,7 @@ module video (
|
||||
output lcd_on,
|
||||
output lcd_clkena,
|
||||
output [14:0] lcd_data,
|
||||
output lcd_vsync,
|
||||
|
||||
output irq,
|
||||
output vblank_irq,
|
||||
@@ -404,12 +405,14 @@ reg [7:0] v_cnt; // max 153
|
||||
// This results in v_cnt 0 lasting for almost 2 lines.
|
||||
wire line153 = (v_cnt == 8'd153);
|
||||
reg vcnt_reset;
|
||||
reg vsync;
|
||||
always @(posedge clk) begin
|
||||
if (!lcdc_on) begin
|
||||
v_cnt <= 8'd0;
|
||||
vcnt_reset <= 1'b0;
|
||||
vsync <= 1'b0;
|
||||
end else if (ce) begin
|
||||
if (~vcnt_reset && h_cnt == 9'd455) begin
|
||||
if (~vcnt_reset && h455) begin
|
||||
v_cnt <= v_cnt + 1'b1;
|
||||
end
|
||||
|
||||
@@ -419,9 +422,15 @@ always @(posedge clk) begin
|
||||
v_cnt <= 8'd0;
|
||||
end
|
||||
end
|
||||
|
||||
// VSync goes high on line 0 but it takes a full frame after the LCD is enabled
|
||||
// because the first line where end_of_line is high after LCD is enabled is line 1.
|
||||
if (end_of_line) vsync <= !v_cnt;
|
||||
end
|
||||
end
|
||||
|
||||
assign lcd_vsync = vsync;
|
||||
|
||||
// line inside the background currently being drawn
|
||||
wire [7:0] bg_line = v_cnt + scy;
|
||||
wire [7:0] bg_col = pcnt + scx;
|
||||
@@ -750,6 +759,9 @@ always @(posedge clk) begin
|
||||
if (lcd_clk) begin
|
||||
lcd_data_out <= (sprite_pixel_visible) ? sprite_pix : pix_rgb_data;
|
||||
end
|
||||
|
||||
// Output blank pixels if lcd is off.
|
||||
if (~lcd_on) lcd_data_out <= isGBC ? 15'h7FFF : 15'd0;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user