From 034ca1ca96ee24fb600ce423e054ea5c87b086f0 Mon Sep 17 00:00:00 2001 From: Bruno Duarte Gouveia Date: Sun, 23 Dec 2018 20:58:59 +0000 Subject: [PATCH] GBC: added colour management to BG, full flags support for sprites (not used yet) --- Gameboy.sv | 4 ++-- gb.v | 7 +++++- sprite.v | 14 ++++++------ video.v | 64 ++++++++++++++++++++++++++++++++++++++++++------------ 4 files changed, 65 insertions(+), 24 deletions(-) diff --git a/Gameboy.sv b/Gameboy.sv index a079cac..dda6b65 100644 --- a/Gameboy.sv +++ b/Gameboy.sv @@ -488,7 +488,7 @@ wire cart_rd; wire cart_wr; wire lcd_clkena; -wire [1:0] lcd_data; +wire [14:0] lcd_data; wire [1:0] lcd_mode; wire lcd_on; @@ -534,7 +534,7 @@ lcd lcd ( .pclk ( clk_sys ), .pce ( ce_pix ), .clk ( clk_cpu ), - .isGBC ( /*status[11]*/ ), + .isGBC ( status[11] ), .tint ( status[1] ), .inv ( status[12] ), diff --git a/gb.v b/gb.v index 60aafd3..74e916d 100644 --- a/gb.v +++ b/gb.v @@ -152,6 +152,7 @@ GBse cpu ( wire clk_cpu = clk; reg cpu_speed; // - 0 Normal mode (4MHz) - 1 Double Speed Mode (8MHz) reg prepare_switch; // set to 1 to toggle speed +assign speed = cpu_speed; always @(posedge clk2x) begin if(reset) begin @@ -359,6 +360,8 @@ video video ( .reset ( reset ), .clk ( clk ), .clk_dma ( clk_cpu ), //can be 2x in cgb double speed mode + .isGBC ( isGBC ), + .irq ( video_irq ), @@ -378,6 +381,9 @@ video video ( .vram_addr ( video_addr ), .vram_data ( vram_do ), + // vram connection bank1 (GBC) + .vram1_data ( vram1_do ), + .dma_rd ( dma_rd ), .dma_addr ( dma_addr ), .dma_data ( dma_data ) @@ -399,7 +405,6 @@ wire vram1_wren = video_rd?1'b0:vram_bank&&((hdma_rd&&isGBC)||cpu_wr_vram); wire [12:0] vram_addr = video_rd?video_addr:(dma_rd&&dma_sel_vram)?dma_addr[12:0]:(hdma_rd&&isGBC)?hdma_target_addr[12:0]:cpu_addr[12:0]; - spram #(13) vram0 ( .clock ( clk ), .address ( vram_addr ), diff --git a/sprite.v b/sprite.v index 9cb7940..a0cdbaf 100644 --- a/sprite.v +++ b/sprite.v @@ -64,14 +64,14 @@ wire visible = v_visible && (h_cnt + 8'd8 >= x_pos) && (h_cnt < x_pos); // x position within sprite, mirror horizontally if required wire [7:0] col_n = h_cnt - x_pos; -wire [2:0] col = flags[1]?col_n[2:0]:~col_n[2:0]; +wire [2:0] col = flags[5]?col_n[2:0]:~col_n[2:0]; assign pixel_data = { data1[col], data0[col] }; assign pixel_active = (pixel_data != 0) && visible; // y position within sprite, mirror vertically if required wire [7:0] row_n = v_cnt - y_pos; -wire [3:0] row = flags[2]?~row_n[3:0]:row_n[3:0]; +wire [3:0] row = flags[6]?~row_n[3:0]:row_n[3:0]; // 16 pixel tall sprites use one more rwo counter bit and the lsb // of the tile index is ignored @@ -79,13 +79,13 @@ wire [10:0] addr8 = { tile , row[2:0]}; wire [10:0] addr16 = { tile[7:1] , row}; assign addr = size16?addr16:addr8; -assign pixel_cmap = flags[0]; -assign pixel_prio = flags[3]; +assign pixel_cmap = flags[4]; +assign pixel_prio = flags[7]; reg [7:0] y_pos; reg [7:0] x_pos; reg [7:0] tile; -reg [3:0] flags; +reg [7:0] flags; always @(posedge clk) begin if(oam_wr) begin @@ -93,7 +93,7 @@ always @(posedge clk) begin 0: y_pos <= oam_di; 1: x_pos <= oam_di; 2: tile <= oam_di; - 3: flags <= oam_di[7:4]; + 3: flags <= oam_di; endcase end end @@ -102,6 +102,6 @@ assign oam_do = (oam_addr == 0)?y_pos: (oam_addr == 1)?x_pos: (oam_addr == 2)?tile: - { flags, 4'h0 }; + flags; endmodule diff --git a/video.v b/video.v index 7ae2bb1..dd4e1d3 100644 --- a/video.v +++ b/video.v @@ -36,7 +36,7 @@ module video ( // output to lcd output lcd_on, output lcd_clkena, - output [1:0] lcd_data, + output [14:0] lcd_data, output reg irq, // vram connection @@ -44,6 +44,9 @@ module video ( output vram_rd, output [12:0] vram_addr, input [7:0] vram_data, + + // vram connection bank1 (GBC) + input [7:0] vram1_data, // dma connection output dma_rd, @@ -299,27 +302,36 @@ assign cpu_do = assign lcd_data = stage2_data; assign lcd_clkena = stage2_clkena; -reg [1:0] stage2_data; +reg [14:0] stage2_data; reg stage2_clkena; reg [1:0] stage2_buffer [159:0]; +reg [2:0] stage2_bgp_buffer [19:0]; //GBC only keep record of palette used for tile reg [7:0] stage2_wptr; reg [7:0] stage2_rptr; +reg [4:0] bg_palette_rptr; //GBC +reg [2:0] bg_palette_rcnt; + + +wire [5:0] palette_index = (stage2_bgp_buffer[bg_palette_rptr] << 3) + (stage2_buffer[stage2_rptr]<<1); //gbc + + // apply bg palette -wire [1:0] stage2_bg_pix = (!lcdc_bg_ena && !window_ena)?2'b11: // background off? - (stage2_buffer[stage2_rptr] == 2'b00)?bgp[1:0]: - (stage2_buffer[stage2_rptr] == 2'b01)?bgp[3:2]: - (stage2_buffer[stage2_rptr] == 2'b10)?bgp[5:4]: - bgp[7:6]; +wire [14:0] stage2_bg_pix = (!lcdc_bg_ena && !window_ena)?15'h7FFF: // background off? + isGBC?{bgpd[palette_index+1][6:0],bgpd[palette_index]}: //gbc + (stage2_buffer[stage2_rptr] == 2'b00)?{13'd0,bgp[1:0]}: + (stage2_buffer[stage2_rptr] == 2'b01)?{13'd0,bgp[3:2]}: + (stage2_buffer[stage2_rptr] == 2'b10)?{13'd0,bgp[5:4]}: + {13'd0,bgp[7:6]}; // apply sprite palette wire [7:0] obp = sprite_pixel_cmap?obp1:obp0; -wire [1:0] sprite_pix = - (sprite_pixel_data == 2'b00)?obp[1:0]: - (sprite_pixel_data == 2'b01)?obp[3:2]: - (sprite_pixel_data == 2'b10)?obp[5:4]: - obp[7:6]; +wire [14:0] sprite_pix = + (sprite_pixel_data == 2'b00)?{13'd0,obp[1:0]}: + (sprite_pixel_data == 2'b01)?{13'd0,obp[3:2]}: + (sprite_pixel_data == 2'b10)?{13'd0,obp[5:4]}: + {13'd0,obp[7:6]}; // a sprite pixel is visible if // - sprites are enabled @@ -335,6 +347,8 @@ always @(posedge clk) begin if(h_cnt == 455) begin stage2_wptr <= 8'h00; stage2_rptr <= 8'h00; + bg_palette_rptr <= 5'd0; //GBC + bg_palette_rcnt <= 3'b111; end if(stage1_clkena) begin @@ -349,6 +363,10 @@ always @(posedge clk) begin else stage2_data <= stage2_bg_pix; stage2_rptr <= stage2_rptr + 8'd1; + + bg_palette_rcnt <= bg_palette_rcnt - 3'd1; + if (bg_palette_rcnt==0) + bg_palette_rptr <= bg_palette_rptr + 5'd1; end end @@ -363,20 +381,38 @@ reg [7:0] tile_shift_0; reg [7:0] tile_shift_1; reg [7:0] bg_tile; +reg [7:0] bg_tile_attr; //GBC reg [7:0] bg_tile_data0; reg [7:0] bg_tile_data1; +reg [4:0] bg_palette_wptr; //GBC + wire stage1_clkena = !vblank && hdvalid; wire [1:0] stage1_data = { tile_shift_1[7], tile_shift_0[7] }; // read data half a clock cycle after ram has been selected always @(posedge clk) begin + if (reset || (h_cnt == 455)) + bg_palette_wptr <= 5'd0; + // every memory access is two pixel cycles if(h_cnt[0]) begin if(bg_tile_map_rd) bg_tile <= vram_data; - if(bg_tile_data0_rd) bg_tile_data0 <= vram_data; - if(bg_tile_data1_rd) bg_tile_data1 <= vram_data; + + if (isGBC) begin + if(bg_tile_map_rd) begin + bg_tile_attr <= vram1_data; //get tile attr from vram bank1 + stage2_bgp_buffer[bg_palette_wptr] <= vram1_data[2:0]; //keep a copy of the palette used + bg_palette_wptr <= bg_palette_wptr + 5'd1; + end + if(bg_tile_data0_rd) bg_tile_data0 <= bg_tile_attr[3]?vram1_data:vram_data; + if(bg_tile_data1_rd) bg_tile_data1 <= bg_tile_attr[3]?vram1_data:vram_data; + end else begin + if(bg_tile_data0_rd) bg_tile_data0 <= vram_data; + if(bg_tile_data1_rd) bg_tile_data1 <= vram_data; + end + // sprite data is evaluated inside the sprite engine end