From 460addc5bce2cf000ebab6347f7ae7bc30a92d55 Mon Sep 17 00:00:00 2001 From: paulb-nl Date: Wed, 8 Jan 2025 13:55:27 +0100 Subject: [PATCH] HDMA: transfer stops only if target address overflows at $FFFF (#261) Fixes hang in F1 Championship Season 2000 --- rtl/hdma.v | 27 ++++++++++++++------------- rtl/reg_savestates.vhd | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/rtl/hdma.v b/rtl/hdma.v index 411c4b7..1def0d6 100644 --- a/rtl/hdma.v +++ b/rtl/hdma.v @@ -28,18 +28,18 @@ module hdma( ); // savestates -wire [44:0] SS_HDMA; -wire [44:0] SS_HDMA_BACK; +wire [47:0] SS_HDMA; +wire [47:0] SS_HDMA_BACK; -eReg_SavestateV #(0, 7, 44, 0, 64'h0000000001FFFFF0) iREG_SAVESTATE_HDMA (clk, SaveStateBus_Din, SaveStateBus_Adr, SaveStateBus_wren, SaveStateBus_rst, SaveStateBus_Dout, SS_HDMA_BACK, SS_HDMA); +eReg_SavestateV #(0, 7, 47, 0, 64'h0000E00001FFFFF0) iREG_SAVESTATE_HDMA (clk, SaveStateBus_Din, SaveStateBus_Adr, SaveStateBus_wren, SaveStateBus_rst, SaveStateBus_Dout, SS_HDMA_BACK, SS_HDMA); //"The preparation time (4 clocks) is the same in single and double speed mode" localparam START_DELAY = 3'd4, END_DELAY = 3'd4; // ff51-ff55 HDMA1-5 (GBC) -reg [11:0] hdma_source; // ff51, ff52 only top 4 bits used -reg [8:0] hdma_target; // ff53 only lowest 5 bits used, ff54 only top 4 bits used +reg [15:4] hdma_source; // ff51, ff52 only top 4 bits used +reg [15:4] hdma_target; // ff53, ff54 only top 4 bits used reg hdma_mode; // ff55 bit 7 - 0 = General Purpose DMA / 1 = H-Blank DMA reg hdma_enabled; // ff55 !bit 7 when read @@ -53,8 +53,8 @@ wire [1:0] byte_cycles = speed ? 2'd3 : 2'd1; reg [1:0] hdma_cnt; //assign hdma_rd = hdma_active; -assign hdma_source_addr = { hdma_source, byte_cnt }; -assign hdma_target_addr = { 3'b100,hdma_target, byte_cnt }; +assign hdma_source_addr = { hdma_source, byte_cnt }; +assign hdma_target_addr = { hdma_target, byte_cnt }; reg [2:0] dma_delay; @@ -68,7 +68,7 @@ assign SS_HDMA_BACK[ 0] = hdma_active ; assign SS_HDMA_BACK[ 2: 1] = hdma_state ; assign SS_HDMA_BACK[ 3] = hdma_enabled; assign SS_HDMA_BACK[15: 4] = hdma_source ; -assign SS_HDMA_BACK[24:16] = hdma_target ; +assign SS_HDMA_BACK[24:16] = hdma_target[12:4]; assign SS_HDMA_BACK[27:25] = dma_delay ; assign SS_HDMA_BACK[ 28] = hdma_rd ; assign SS_HDMA_BACK[ 29] = hdma_end ; @@ -76,6 +76,7 @@ assign SS_HDMA_BACK[ 30] = hdma_mode ; assign SS_HDMA_BACK[38:31] = hdma_length ; assign SS_HDMA_BACK[42:39] = byte_cnt ; assign SS_HDMA_BACK[44:43] = hdma_cnt ; +assign SS_HDMA_BACK[47:45] = hdma_target[15:13]; always @(posedge clk) begin @@ -84,7 +85,7 @@ always @(posedge clk) begin hdma_state <= SS_HDMA[ 2: 1]; // wait_h; hdma_enabled <= SS_HDMA[ 3]; // 1'b0; hdma_source <= SS_HDMA[15: 4]; // 12'hFFF; - hdma_target <= SS_HDMA[24:16]; // 9'h1FF; + hdma_target <= { SS_HDMA[47:45], SS_HDMA[24:16] }; // 12'hFFF; dma_delay <= SS_HDMA[27:25]; // 3'd0; hdma_rd <= SS_HDMA[ 28]; // 0; hdma_end <= SS_HDMA[ 29]; // 0; @@ -97,10 +98,10 @@ always @(posedge clk) begin if(sel_reg && wr) begin case (addr) - 4'd1: hdma_source[11:4] <= din; - 4'd2: hdma_source[3:0] <= din[7:4]; - 4'd3: hdma_target[8:4] <= din[4:0]; - 4'd4: hdma_target[3:0] <= din[7:4]; + 4'd1: hdma_source[15:8] <= din; + 4'd2: hdma_source[7:4] <= din[7:4]; + 4'd3: hdma_target[15:8] <= din; + 4'd4: hdma_target[7:4] <= din[7:4]; // writing the hdma register engages the dma engine 4'h5: begin diff --git a/rtl/reg_savestates.vhd b/rtl/reg_savestates.vhd index 7f85dba..e44867f 100644 --- a/rtl/reg_savestates.vhd +++ b/rtl/reg_savestates.vhd @@ -19,7 +19,7 @@ package pReg_savestates is -- components constant REG_SAVESTATE_Timer : regmap_type := ( 6, 46, 0, 1, x"0000000000000008"); - constant REG_SAVESTATE_HDMA : regmap_type := ( 7, 44, 0, 1, x"0000000001FFFFF0"); + constant REG_SAVESTATE_HDMA : regmap_type := ( 7, 47, 0, 1, x"0000E00001FFFFF0"); constant REG_SAVESTATE_Link : regmap_type := ( 8, 16, 0, 1, x"0000000000000000");