mirror of
https://github.com/MiSTer-devel/Gameboy_MiSTer.git
synced 2026-04-19 03:04:09 +00:00
GBC: start hdma and clock switching implementation
This commit is contained in:
139
gb.v
139
gb.v
@@ -21,8 +21,9 @@
|
||||
|
||||
module gb (
|
||||
input reset,
|
||||
input clk,
|
||||
|
||||
input clk,
|
||||
input clk2x,
|
||||
|
||||
input fast_boot,
|
||||
input [7:0] joystick,
|
||||
|
||||
@@ -50,7 +51,7 @@ wire [15:0] cpu_addr;
|
||||
wire [7:0] cpu_do;
|
||||
|
||||
wire sel_timer = (cpu_addr[15:4] == 12'hff0) && (cpu_addr[3:2] == 2'b01);
|
||||
wire sel_video_reg = cpu_addr[15:4] == 12'hff4;
|
||||
wire sel_video_reg = (cpu_addr[15:4] == 12'hff4); //video and oam dma
|
||||
wire sel_video_oam = cpu_addr[15:8] == 8'hfe;
|
||||
wire sel_joy = cpu_addr == 16'hff00; // joystick controller
|
||||
wire sel_sb = cpu_addr == 16'hff01; // serial SB - Serial transfer data
|
||||
@@ -66,12 +67,21 @@ wire sel_zpram = (cpu_addr[15:7] == 9'b111111111) && // 127 bytes zero pageram a
|
||||
wire sel_audio = (cpu_addr[15:8] == 8'hff) && // audio reg ff10 - ff3f
|
||||
((cpu_addr[7:5] == 3'b001) || (cpu_addr[7:4] == 4'b0001));
|
||||
|
||||
wire sel_hdma = (cpu_addr[15:4]==12'hff5) &&
|
||||
((cpu_addr[3:0]!=4'd0)&&(cpu_addr[3:0]< 4'd6)); //HDMA FF51-FF55
|
||||
wire sel_key1 = cpu_addr == 16'hff4d; // KEY1 - CGB Mode Only - Prepare Speed Switch
|
||||
|
||||
//DMA can select from $0000 to $F100
|
||||
wire dma_sel_rom = !dma_addr[15]; // lower 32k are rom
|
||||
wire dma_sel_cram = dma_addr[15:13] == 3'b101; // 8k cart ram at $a000
|
||||
wire dma_sel_vram = dma_addr[15:13] == 3'b100; // 8k video ram at $8000
|
||||
wire dma_sel_iram = (dma_addr[15:14] == 2'b11) && (dma_addr[15:8] != 8'hff); // 8k internal ram at $c000
|
||||
|
||||
//HDMA can select from $0000 to $7ff0 or A000-DFF0
|
||||
wire hdma_sel_rom = !hdma_addr[15]; // lower 32k are rom
|
||||
wire hdma_sel_cram = hdma_addr[15:13] == 3'b101; // 8k cart ram at $a000
|
||||
wire hdma_sel_iram = hdma_addr[15:13] == 3'b110; // 8k internal ram at $c000-$dff0
|
||||
|
||||
|
||||
// the boot roms sees a special $42 flag in $ff50 if it's supposed to to a fast boot
|
||||
wire sel_fast = fast_boot && cpu_addr == 16'hff50 && boot_rom_enabled;
|
||||
@@ -96,6 +106,8 @@ wire [7:0] cpu_di =
|
||||
sel_iram?iram_do: // internal ram
|
||||
sel_ie?{3'b000, ie_r}: // interrupt enable register
|
||||
sel_if?{3'b111, if_r}: // interrupt flag register
|
||||
sel_hdma&&isGBC?{hdma_do}: //hdma GBC
|
||||
sel_key1&&isGBC?{cpu_speed,6'd0,prepare_switch}: //key1 cpu speed register(GBC)
|
||||
8'hff;
|
||||
|
||||
wire cpu_wr_n;
|
||||
@@ -103,11 +115,13 @@ wire cpu_rd_n;
|
||||
wire cpu_iorq_n;
|
||||
wire cpu_m1_n;
|
||||
wire cpu_mreq_n;
|
||||
|
||||
wire cpu_clken = isGBC ? !hdma_rd:1'b1; //when hdma is enabled stop CPU (GBC)
|
||||
|
||||
GBse cpu (
|
||||
.RESET_n ( !reset ),
|
||||
.CLK_n ( clk ),
|
||||
.CLKEN ( 1'b1 ),
|
||||
.CLK_n ( clk_cpu ),
|
||||
.CLKEN ( cpu_clken ),
|
||||
.WAIT_n ( 1'b1 ),
|
||||
.INT_n ( irq_n ),
|
||||
.NMI_n ( 1'b1 ),
|
||||
@@ -125,6 +139,22 @@ GBse cpu (
|
||||
.DO ( cpu_do )
|
||||
);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// --------------------- Speed Toggle KEY1 (GBC)-----------------------
|
||||
// --------------------------------------------------------------------
|
||||
wire clk_cpu = cpu_speed?clk2x:clk;
|
||||
reg cpu_speed; // - 0 Normal mode (4MHz) - 1 Double Speed Mode (8MHz)
|
||||
reg prepare_switch; // set to 1 to toggle speed
|
||||
|
||||
always @(posedge clk2x) begin
|
||||
if(reset) begin
|
||||
cpu_speed <= 1'b0;
|
||||
end else if (sel_key1 && !cpu_wr_n && isGBC)begin
|
||||
prepare_switch <= cpu_do[0];
|
||||
//TODO: wait for stop to toggle speed
|
||||
end
|
||||
end
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------------------ audio -------------------------------
|
||||
// --------------------------------------------------------------------
|
||||
@@ -308,12 +338,15 @@ wire video_irq;
|
||||
wire [7:0] video_do;
|
||||
wire [12:0] video_addr;
|
||||
wire [15:0] dma_addr;
|
||||
wire video_rd, dma_rd;
|
||||
wire [15:0] hdma_addr;
|
||||
wire video_rd, dma_rd, hdma_rd;
|
||||
wire [7:0] dma_data = dma_sel_iram?iram_do:dma_sel_vram?vram_do:cart_do;
|
||||
wire [7:0] hdma_data = hdma_sel_iram?iram_do:cart_do;
|
||||
|
||||
video video (
|
||||
.reset ( reset ),
|
||||
.clk ( clk ),
|
||||
.clk_dma ( clk_cpu ), //can be 2x in cgb double speed mode
|
||||
|
||||
.irq ( video_irq ),
|
||||
|
||||
@@ -336,6 +369,7 @@ video video (
|
||||
.dma_rd ( dma_rd ),
|
||||
.dma_addr ( dma_addr ),
|
||||
.dma_data ( dma_data )
|
||||
|
||||
);
|
||||
|
||||
// total 8k/16k (CGB) vram from $8000 to $9fff
|
||||
@@ -362,6 +396,99 @@ always @(posedge clk) begin
|
||||
vram_bank <= cpu_do[0];
|
||||
end
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// -------------------------- HDMA engine(GBC) ------------------------
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
//ff51-ff55 HDMA1-5 (GBC)
|
||||
reg [7:0] hdma_source_h; // ff51
|
||||
reg [3:0] hdma_source_l; // ff52 only top 4 bits used
|
||||
reg [4:0] hdma_target_h; // ff53 only lowest 5 bits used
|
||||
reg [3:0] hdma_target_l; // ff54 only top 4 bits used
|
||||
reg hdma_mode; // ff55 bit 7 - 1=General Purpose DMA 0=H-Blank DMA
|
||||
reg hdma_enabled; // ff55 !bit 7 when read
|
||||
reg [6:0] hdma_length; // ff55 bit 6:0 - dma transfer length (hdma_length+1)*16 bytes
|
||||
|
||||
assign hdma_rd = hdma_active;
|
||||
assign hdma_addr = { hdma_source_h,hdma_source_l,4'd0} + hdma_cnt[12:1];
|
||||
|
||||
reg hdma_active;
|
||||
|
||||
// it takes about 8us to transfer a block of 16 bytes. -> 500ns per byte -> 2Mhz
|
||||
// 32 cycles in Normal Speed Mode, and 64 'fast' cycles in Double Speed Mode
|
||||
reg [12:0] hdma_cnt;
|
||||
reg [4:0] hdma_16byte_cnt; //16bytes*2
|
||||
|
||||
|
||||
always @(posedge clk) begin
|
||||
if(reset)
|
||||
hdma_active <= 1'b0;
|
||||
else begin
|
||||
// writing the hdma register engages the dma engine
|
||||
if(isGBC && !cpu_wr_n && (cpu_addr == 16'hff55)) begin
|
||||
hdma_enabled <= 1'b1;
|
||||
hdma_mode <= cpu_do[7];
|
||||
hdma_length <= cpu_do[6:0];
|
||||
hdma_cnt <= 12'd0;
|
||||
hdma_16byte_cnt <= 5'h1f;
|
||||
//TODO: disable HDMA in mode 1
|
||||
|
||||
end else if(hdma_mode==0) begin //mode 0 GDMA do the transfer in one go
|
||||
|
||||
if(hdma_cnt != (((hdma_length+1)*16)-1)*2) begin
|
||||
hdma_active <= 1'b1;
|
||||
hdma_cnt <= hdma_cnt + 1'd1;
|
||||
hdma_16byte_cnt <= hdma_16byte_cnt - 1'd1;
|
||||
if (!hdma_16byte_cnt)
|
||||
hdma_length <= hdma_length - 1'd1;
|
||||
|
||||
end else begin
|
||||
hdma_active <= 1'b0;
|
||||
hdma_enabled <= 1'b0;
|
||||
end
|
||||
|
||||
end else begin //mode 1 HDMA transfer 1 block (16bytes) in each H-Blank only
|
||||
|
||||
if(hdma_cnt != (((hdma_length+1)*16)-1)*2 && (lcd_mode==0) && hdma_enabled) begin //also check if hdma is enabled and in h-blank
|
||||
//TODO: have to rethink this, maybe state machine
|
||||
hdma_active <= 1'b0;
|
||||
hdma_enabled <= 1'b0;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk) begin
|
||||
if(reset) begin
|
||||
hdma_source_h <= 8'hFF;
|
||||
hdma_source_l <= 4'hF;
|
||||
hdma_target_h <= 5'h1F;
|
||||
hdma_target_l <= 4'hF;
|
||||
end else if(sel_hdma && !cpu_wr_n && isGBC) begin
|
||||
|
||||
case (cpu_addr[3:0])
|
||||
4'd1: hdma_source_h <= cpu_do;
|
||||
4'd2: hdma_source_l <= cpu_do[7:4];
|
||||
4'd3: hdma_target_h <= cpu_do[4:0];
|
||||
4'd4: hdma_target_l <= cpu_do[7:4];
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
wire [7:0] hdma_do = isGBC&&sel_hdma?
|
||||
(cpu_addr[3:0]==4'd1)?hdma_source_h:
|
||||
(cpu_addr[3:0]==4'd2)?{hdma_source_l,4'd0}:
|
||||
(cpu_addr[3:0]==4'd3)?{3'd0,hdma_target_h}:
|
||||
(cpu_addr[3:0]==4'd4)?{hdma_target_l,,4'd0}:
|
||||
(cpu_addr[3:0]==4'd5 && hdma_enabled)?{1'b0,hdma_length}:
|
||||
8'hFF:
|
||||
8'hFF;
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// -------------------------- zero page ram ---------------------------
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
3
video.v
3
video.v
@@ -22,6 +22,7 @@
|
||||
module video (
|
||||
input reset,
|
||||
input clk, // 4 Mhz cpu clock
|
||||
input clk_dma,
|
||||
|
||||
// cpu register adn oam interface
|
||||
input cpu_sel_oam,
|
||||
@@ -145,7 +146,7 @@ assign dma_rd = dma_active;
|
||||
reg dma_active;
|
||||
reg [7:0] dma;
|
||||
reg [9:0] dma_cnt; // dma runs 4*160 clock cycles = 160us @ 4MHz
|
||||
always @(posedge clk) begin
|
||||
always @(posedge clk_dma) begin
|
||||
if(reset)
|
||||
dma_active <= 1'b0;
|
||||
else begin
|
||||
|
||||
Reference in New Issue
Block a user