mirror of
https://github.com/MiSTer-devel/Gameboy_MiSTer.git
synced 2026-05-24 03:03:25 +00:00
Merge pull request #113 from paulb-nl/frame_blend
Frame blend, PPU fixes, Serial Link fix
This commit is contained in:
14
Gameboy.sv
14
Gameboy.sv
@@ -151,7 +151,7 @@ assign AUDIO_MIX = status[8:7];
|
||||
// 0 1 2 3
|
||||
// 01234567890123456789012345678901
|
||||
// 0123456789ABCDEFGHIJKLMNOPQRSTUV
|
||||
// XXXXXXXXXXXXXXXX XXXX XX
|
||||
// XXXXXXXXXXXXXXXXXXXXX XX
|
||||
|
||||
`include "build_id.v"
|
||||
localparam CONF_STR = {
|
||||
@@ -174,6 +174,7 @@ localparam CONF_STR = {
|
||||
"O34,Aspect ratio,Original,Full Screen,[ARC1],[ARC2];",
|
||||
"OIK,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%,CRT 75%;",
|
||||
"O5,Stabilize video(buffer),Off,On;",
|
||||
"OG,Frame blend,Off,On;",
|
||||
"O78,Stereo mix,none,25%,50%,100%;",
|
||||
"-;",
|
||||
"OB,Boot,Normal,Fast;",
|
||||
@@ -599,7 +600,6 @@ gb gb (
|
||||
.serial_data_in(ser_data_in),
|
||||
.serial_clk_out(ser_clk_out),
|
||||
.serial_data_out(ser_data_out),
|
||||
.serial_ena(status[6]),
|
||||
|
||||
// Palette download will disable cheats option (HPS doesn't distinguish downloads),
|
||||
// so clear the cheats and disable second option (chheats enable/disable)
|
||||
@@ -634,6 +634,7 @@ lcd lcd
|
||||
.tint ( |tint ),
|
||||
.inv ( status[12] ),
|
||||
.double_buffer( status[5]),
|
||||
.frame_blend( status[16] ),
|
||||
|
||||
// Palettes
|
||||
.pal1 (palette[127:104]),
|
||||
@@ -808,12 +809,13 @@ wire ser_data_in;
|
||||
wire ser_data_out;
|
||||
wire ser_clk_in;
|
||||
wire ser_clk_out;
|
||||
wire serial_ena = status[6];
|
||||
|
||||
assign ser_data_in = USER_IN[2];
|
||||
assign USER_OUT[1] = ser_data_out;
|
||||
assign ser_data_in = serial_ena ? USER_IN[2] : 1'b1;
|
||||
assign USER_OUT[1] = serial_ena ? ser_data_out : 1'b1;
|
||||
|
||||
assign ser_clk_in = USER_IN[0];
|
||||
assign USER_OUT[0] = sc_int_clock_out?ser_clk_out:1'b1;
|
||||
assign ser_clk_in = serial_ena ? USER_IN[0] : 1'b1;
|
||||
assign USER_OUT[0] = (serial_ena & sc_int_clock_out) ? ser_clk_out : 1'b1;
|
||||
|
||||
|
||||
|
||||
|
||||
61
rtl/gb.v
61
rtl/gb.v
@@ -65,7 +65,6 @@ module gb (
|
||||
output gg_available,
|
||||
|
||||
//serial port
|
||||
input serial_ena,
|
||||
output sc_int_clock2,
|
||||
input serial_clk_in,
|
||||
output serial_clk_out,
|
||||
@@ -130,7 +129,7 @@ wire [7:0] cpu_di =
|
||||
isGBC&&sel_hdma?{hdma_do}: //hdma GBC
|
||||
isGBC&&sel_key1?{cpu_speed,6'h3f,prepare_switch}: //key1 cpu speed register(GBC)
|
||||
sel_joy?joy_do: // joystick register
|
||||
sel_sb?sb: // serial transfer data register
|
||||
sel_sb?sb_o: // serial transfer data register
|
||||
sel_sc?sc_r: // serial transfer control register
|
||||
sel_timer?timer_do: // timer registers
|
||||
sel_video_reg?video_do: // video registers
|
||||
@@ -260,16 +259,11 @@ gbc_snd audio (
|
||||
// -----------------------serial port()--------------------------------
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
wire serial_irq = serial_ena ? serial_irq_s : serial_irq_f;
|
||||
wire [7:0] sb = serial_ena ? sb_s : 8'hFF;
|
||||
wire sc_start = serial_ena ? sc_start_s : sc_start_f;
|
||||
wire sc_shiftclock = serial_ena ? sc_shiftclock_s : sc_shiftclock_f;
|
||||
|
||||
// SNAC
|
||||
wire serial_irq_s;
|
||||
wire [7:0] sb_s;
|
||||
wire sc_start_s;
|
||||
wire sc_shiftclock_s;
|
||||
wire serial_irq;
|
||||
wire [7:0] sb_o;
|
||||
wire sc_start;
|
||||
wire sc_shiftclock;
|
||||
|
||||
assign sc_int_clock2 = sc_shiftclock;
|
||||
|
||||
@@ -290,50 +284,13 @@ link link (
|
||||
|
||||
.serial_clk_out(serial_clk_out),
|
||||
.serial_data_out(serial_data_out),
|
||||
.sb(sb_s),
|
||||
.serial_irq(serial_irq_s),
|
||||
.sc_start(sc_start_s),
|
||||
.sc_int_clock(sc_shiftclock_s)
|
||||
.sb(sb_o),
|
||||
.serial_irq(serial_irq),
|
||||
.sc_start(sc_start),
|
||||
.sc_int_clock(sc_shiftclock)
|
||||
|
||||
);
|
||||
|
||||
// Fake
|
||||
reg sc_start_f,sc_shiftclock_f;
|
||||
reg serial_irq_f;
|
||||
|
||||
always @(posedge clk_cpu) begin
|
||||
reg [3:0] serial_counter;
|
||||
reg [8:0] serial_clk_div; //8192Hz
|
||||
|
||||
serial_irq_f <= 1'b0;
|
||||
if(reset_r) begin
|
||||
sc_start_f <= 1'b0;
|
||||
sc_shiftclock_f <= 1'b0;
|
||||
end else if (sel_sc && !cpu_wr_n) begin //cpu write
|
||||
sc_start_f <= cpu_do[7];
|
||||
sc_shiftclock_f <= cpu_do[0];
|
||||
if (cpu_do[7]) begin //enable transfer
|
||||
serial_clk_div <= 9'h1FF;
|
||||
serial_counter <= 4'd8;
|
||||
end
|
||||
end else if (sc_start_f && sc_shiftclock_f) begin // serial transfer and serial clock enabled
|
||||
|
||||
serial_clk_div <= serial_clk_div - 9'd1;
|
||||
|
||||
if (serial_clk_div == 9'd0 && serial_counter)
|
||||
serial_counter <= serial_counter - 4'd1;
|
||||
|
||||
if (!serial_counter) begin
|
||||
serial_irq_f <= 1'b1; //trigger interrupt
|
||||
sc_start_f <= 1'b0; //reset transfer state
|
||||
serial_clk_div <= 9'h1FF;
|
||||
serial_counter <= 4'd8;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------------------ inputs ------------------------------
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
110
rtl/lcd.v
110
rtl/lcd.v
@@ -28,6 +28,7 @@ module lcd
|
||||
|
||||
input tint,
|
||||
input inv,
|
||||
input frame_blend,
|
||||
|
||||
input on,
|
||||
|
||||
@@ -123,12 +124,14 @@ parameter VTOTAL = 264;
|
||||
// We need 4256 cycles per line so 1 pixel clock cycle needs to be 6 cycles longer.
|
||||
// 424x10 + 1x16 cycles
|
||||
reg [3:0] pix_div_cnt;
|
||||
reg ce_pix_n;
|
||||
always @(posedge clk_vid) begin
|
||||
pix_div_cnt <= pix_div_cnt + 1'd1;
|
||||
if (h_cnt != HTOTAL-1 && pix_div_cnt == 4'd9) // Longer cycle at the last pixel
|
||||
pix_div_cnt <= 0;
|
||||
|
||||
ce_pix <= !pix_div_cnt;
|
||||
ce_pix_n <= (pix_div_cnt == 4'd5);
|
||||
end
|
||||
|
||||
reg [14:0] vbuffer_outptr;
|
||||
@@ -144,7 +147,7 @@ always @(posedge clk_vid) begin
|
||||
inptr1 <= inptr2;
|
||||
if(inptr1 == inptr2) inptr <= inptr1;
|
||||
|
||||
if (!pix_div_cnt) begin
|
||||
if (ce_pix_n) begin
|
||||
// generate positive hsync signal
|
||||
if(h_cnt == H_START+H+HFP+HS) hs <= 0;
|
||||
if(h_cnt == H_START+H+HFP) begin
|
||||
@@ -213,11 +216,26 @@ end
|
||||
reg [14:0] pixel_reg;
|
||||
always @(posedge clk_vid) pixel_reg <= vbuffer[{vbuffer_out_bank, vbuffer_outptr}];
|
||||
|
||||
wire [1:0] pixel = (pixel_reg[1:0] ^ {inv,inv}); //invert gb only
|
||||
// Previous frame data for frame blend
|
||||
reg [14:0] prev_vbuffer[160*144];
|
||||
reg [14:0] prev_pixel_reg;
|
||||
always @(posedge clk_vid) begin
|
||||
if(ce_pix & ~gb_hb & ~gb_vb) prev_vbuffer[vbuffer_outptr] <= pixel_reg;
|
||||
prev_pixel_reg <= prev_vbuffer[vbuffer_outptr];
|
||||
end
|
||||
|
||||
wire [4:0] r5 = pixel_reg[4:0];
|
||||
wire [4:0] g5 = pixel_reg[9:5];
|
||||
wire [4:0] b5 = pixel_reg[14:10];
|
||||
// Current pixel_reg latched at ce_pix_n so it is ready at ce_pix
|
||||
reg [14:0] pixel_out;
|
||||
always@(posedge clk_vid) begin
|
||||
if (ce_pix_n) pixel_out <= pixel_reg;
|
||||
else if (ce_pix) pixel_out <= prev_pixel_reg;
|
||||
end
|
||||
|
||||
wire [1:0] pixel = (pixel_out[1:0] ^ {inv,inv}); //invert gb only
|
||||
|
||||
wire [4:0] r5 = pixel_out[4:0];
|
||||
wire [4:0] g5 = pixel_out[9:5];
|
||||
wire [4:0] b5 = pixel_out[14:10];
|
||||
|
||||
wire [31:0] r10 = (r5 * 13) + (g5 * 2) +b5;
|
||||
wire [31:0] g10 = (g5 * 3) + b5;
|
||||
@@ -229,35 +247,69 @@ wire [7:0] grey = (pixel==0) ? 8'd252 : (pixel==1) ? 8'd168 : (pixel==2) ? 8'd96
|
||||
// sgb_border_pix contains backdrop color when sgb_border_pix[15] is low.
|
||||
wire sgb_border = sgb_border_pix[15] & sgb_en;
|
||||
|
||||
always@(posedge clk_vid) begin
|
||||
if(ce_pix) begin
|
||||
// visible area?
|
||||
hbl <= sgb_en ? hb : gb_hb;
|
||||
vbl <= sgb_en ? vb : gb_vb;
|
||||
|
||||
// Allow backdrop color in border area and the border to overlap game area.
|
||||
if (((gb_hb|gb_vb) & sgb_en) | sgb_border) begin
|
||||
r <= {sgb_border_pix[4:0],sgb_border_pix[4:2]};
|
||||
g <= {sgb_border_pix[9:5],sgb_border_pix[9:7]};
|
||||
b <= {sgb_border_pix[14:10],sgb_border_pix[14:12]};
|
||||
end else if (isGBC) begin
|
||||
r <= r10[8:1];
|
||||
g <= {g10[6:0],1'b0};
|
||||
b <= b10[8:1];
|
||||
end else if (sgb_pal_en) begin
|
||||
r <= {r5,r5[4:2]};
|
||||
g <= {g5,g5[4:2]};
|
||||
b <= {b5,b5[4:2]};
|
||||
end else if (tint) begin
|
||||
{r,g,b} <= (pixel==0) ? pal1 : (pixel==1) ? pal2 : (pixel==2) ? pal3 : pal4;
|
||||
end else begin
|
||||
{r,g,b} <= {3{grey}};
|
||||
end
|
||||
function [7:0] blend;
|
||||
input [7:0] a,b;
|
||||
reg [8:0] sum;
|
||||
begin
|
||||
sum = a + b;
|
||||
blend = sum[8:1];
|
||||
end
|
||||
endfunction
|
||||
|
||||
reg [7:0] r_tmp, g_tmp, b_tmp;
|
||||
always@(*) begin
|
||||
if (isGBC) begin
|
||||
r_tmp = r10[8:1];
|
||||
g_tmp = {g10[6:0],1'b0};
|
||||
b_tmp = b10[8:1];
|
||||
end else if (sgb_pal_en) begin
|
||||
r_tmp = {r5,r5[4:2]};
|
||||
g_tmp = {g5,g5[4:2]};
|
||||
b_tmp = {b5,b5[4:2]};
|
||||
end else if (tint) begin
|
||||
{r_tmp,g_tmp,b_tmp} = (pixel==0) ? pal1 : (pixel==1) ? pal2 : (pixel==2) ? pal3 : pal4;
|
||||
end else begin
|
||||
{r_tmp,g_tmp,b_tmp} = {3{grey}};
|
||||
end
|
||||
end
|
||||
|
||||
reg [7:0] r_prev, g_prev, b_prev;
|
||||
reg [7:0] r_cur, g_cur, b_cur;
|
||||
reg [14:0] sgb_border_d;
|
||||
reg hbl_l, vbl_l;
|
||||
reg border_en;
|
||||
always@(posedge clk_vid) begin
|
||||
|
||||
if (ce_pix)
|
||||
{r_cur, g_cur, b_cur} <= {r_tmp, g_tmp, b_tmp};
|
||||
|
||||
if (ce_pix_n)
|
||||
{r_prev, g_prev, b_prev} <= {r_tmp, g_tmp, b_tmp};
|
||||
|
||||
if (ce_pix) begin
|
||||
// visible area?
|
||||
hbl_l <= sgb_en ? hb : gb_hb;
|
||||
vbl_l <= sgb_en ? vb : gb_vb;
|
||||
hbl <= hbl_l;
|
||||
vbl <= vbl_l;
|
||||
|
||||
// Allow backdrop color in border area and the border to overlap game area.
|
||||
border_en <= ((gb_hb|gb_vb) & sgb_en) | sgb_border;
|
||||
sgb_border_d <= sgb_border_pix[14:0];
|
||||
|
||||
if (border_en) begin
|
||||
r <= {sgb_border_d[4:0],sgb_border_d[4:2]};
|
||||
g <= {sgb_border_d[9:5],sgb_border_d[9:7]};
|
||||
b <= {sgb_border_d[14:10],sgb_border_d[14:12]};
|
||||
end else if (frame_blend) begin
|
||||
r <= blend(r_cur, r_prev);
|
||||
g <= blend(g_cur, g_prev);
|
||||
b <= blend(b_cur, b_prev);
|
||||
end else begin
|
||||
{r,g,b} <= {r_cur, g_cur, b_cur};
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -69,7 +69,7 @@ always @(posedge clk) begin
|
||||
serial_clk_div <= serial_clk_div - 9'd1;
|
||||
|
||||
if (serial_counter != 0) begin
|
||||
if (serial_clk_div == {1'b0,CLK_DIV[8:1]+1'd1}) begin
|
||||
if (serial_clk_div == CLK_DIV/2+1) begin
|
||||
serial_clk_out_r <= ~serial_clk_out_r;
|
||||
serial_out_r <= sb[7];
|
||||
end else if (!serial_clk_div) begin
|
||||
|
||||
@@ -197,11 +197,12 @@ end
|
||||
wire h455 = (h_cnt == 9'd455);
|
||||
wire vblank = (v_cnt >= 144);
|
||||
|
||||
reg vblank_l, end_of_line, lyc_match_l;
|
||||
reg vblank_l, end_of_line, end_of_line_l, lyc_match_l;
|
||||
always @(posedge clk) begin
|
||||
if (!lcd_on) begin
|
||||
vblank_l <= 1'b0;
|
||||
end_of_line <= 1'b0;
|
||||
end_of_line_l <= 1'b0;
|
||||
end else if (ce) begin
|
||||
if (h455) end_of_line <= 1'b1;
|
||||
else if (end_of_line) begin
|
||||
@@ -216,6 +217,8 @@ always @(posedge clk) begin
|
||||
end_of_line <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
end_of_line_l <= end_of_line;
|
||||
end
|
||||
end
|
||||
|
||||
@@ -223,7 +226,7 @@ always @(posedge clk) begin
|
||||
if (reset) begin
|
||||
lyc_match_l <= 1'b0; // lyc_match does not reset when lcd is off
|
||||
end else if (ce) begin
|
||||
if (h_cnt[1:0] == 2'b10) begin
|
||||
if (h_cnt[1:0] == 2'b11) begin
|
||||
lyc_match_l <= lyc_match;
|
||||
end
|
||||
end
|
||||
@@ -244,7 +247,7 @@ always @(posedge clk) begin
|
||||
end
|
||||
|
||||
wire int_lyc = (stat[6] & lyc_match_l);
|
||||
wire int_oam = (stat[5] & end_of_line & ~vblank_l);
|
||||
wire int_oam = (stat[5] & end_of_line_l & ~vblank_l);
|
||||
wire int_vbl = (stat[4] & vblank_l);
|
||||
wire int_hbl = (stat[3] & mode3_end & ~vblank_l);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user