diff --git a/Gameboy.sv b/Gameboy.sv index eba8281..a880273 100644 --- a/Gameboy.sv +++ b/Gameboy.sv @@ -151,7 +151,7 @@ assign AUDIO_MIX = status[8:7]; // 0 1 2 3 // 01234567890123456789012345678901 // 0123456789ABCDEFGHIJKLMNOPQRSTUV -// XXXXXXXXXXXXXXXXXXXXX XXXXX +// XXXXXXXXXXXXXXXXXXXXX XXXX `include "build_id.v" localparam CONF_STR = { @@ -180,8 +180,8 @@ localparam CONF_STR = { "OB,Boot,Normal,Fast;", "O6,Link Port,Disabled,Enabled;", "-;", - "OPQ,FastForward Sound,Normal,Hack,Off;", - "OR,Pause when OSD is open,Off,On;", + "OP,FastForward Sound,On,Off;", + "OQ,Pause when OSD is open,Off,On;", "-;", "R0,Reset;", "J1,A,B,Select,Start,FastForward;", @@ -286,6 +286,8 @@ wire [15:0] sdram_di = cart_download ? ioctl_dout : 16'd0; wire [23:0] sdram_addr = cart_download? ioctl_addr[24:1]: {2'b00, mbc_bank, cart_addr[12:1]}; wire sdram_oe = ~cart_download & cart_rd & ~cram_rd; wire sdram_we = cart_download & dn_write; +wire sdram_refresh_force; +wire sdram_autorefresh = !fastforward; assign SDRAM_CKE = 1; @@ -312,6 +314,8 @@ sdram sdram ( .ds ( sdram_ds ), .we ( sdram_we ), .oe ( sdram_oe ), + .autorefresh ( sdram_autorefresh ), + .refresh ( sdram_refresh_force ), .dout ( sdram_do ) ); @@ -583,7 +587,6 @@ gb gb ( .clk_sys ( clk_sys ), .ce ( ce_cpu ), // the whole gameboy runs on 4mhnz .ce_2x ( ce_cpu2x ), // ~8MHz in dualspeed mode (GBC) - .ce_sound ( ce_sound ), // ~8Mhz if not fastforward .fast_boot ( status[11] ), @@ -631,8 +634,8 @@ gb gb ( .gg_available(gg_available) ); -assign AUDIO_L = (joystick_0[8] && status[26]) ? 16'd0 : GB_AUDIO_L; -assign AUDIO_R = (joystick_0[8] && status[26]) ? 16'd0 : GB_AUDIO_R; +assign AUDIO_L = (joystick_0[8] && status[25]) ? 16'd0 : GB_AUDIO_L; +assign AUDIO_R = (joystick_0[8] && status[25]) ? 16'd0 : GB_AUDIO_R; // the lcd to vga converter wire [7:0] video_r, video_g, video_b; @@ -765,22 +768,28 @@ video_mixer #(.LINE_LENGTH(200), .GAMMA(1)) video_mixer //////////////////////////////// CE //////////////////////////////////// -wire ce_cpu, ce_cpu2x, ce_sound, ce_soundhack; +wire ce_cpu, ce_cpu2x; wire cart_act = cart_wr | cart_rd; +wire fastforward = joystick_0[8] && !ioctl_download && !OSD_STATUS; + +reg paused; +always_ff @(posedge clk_sys) begin + paused <= status[26] && OSD_STATUS && !ioctl_download && !reset; +end + speedcontrol speedcontrol ( .clk_sys (clk_sys), - .pause (status[27] && OSD_STATUS && !ioctl_download), - .speedup (joystick_0[8] && !ioctl_download && !OSD_STATUS), + .speed (speed), + .pause (paused), + .speedup (fastforward), .cart_act (cart_act), .ce (ce_cpu), .ce_2x (ce_cpu2x), - .ce_2xNormal (ce_soundhack) + .refresh (sdram_refresh_force) ); -assign ce_sound = status[25] ? ce_soundhack : ce_cpu2x; - ///////////////////////////// GBC BIOS ///////////////////////////////// wire [7:0] bios_do; diff --git a/rtl/gb.v b/rtl/gb.v index 688cbd0..89fbdc3 100644 --- a/rtl/gb.v +++ b/rtl/gb.v @@ -25,7 +25,6 @@ module gb ( input clk_sys, input ce, input ce_2x, - input ce_sound, input fast_boot, input [7:0] joystick, @@ -268,7 +267,7 @@ wire audio_wr = !cpu_wr_n && sel_audio; gbc_snd audio ( .clk ( clk_sys ), - .ce ( ce_sound ), + .ce ( ce_2x ), .reset ( reset_r ), .is_gbc ( isGBC ), diff --git a/rtl/sdram.sv b/rtl/sdram.sv index 9d6b32b..beab6f9 100644 --- a/rtl/sdram.sv +++ b/rtl/sdram.sv @@ -50,7 +50,9 @@ module sdram input [23:0] addr, // 24 bit word address input [1:0] ds, // upper/lower data strobe input oe, // cpu/chipset requests read - input we // cpu/chipset requests write + input we, // cpu/chipset requests write + input autorefresh,// autorefresh when no read or write required + input refresh // force refresh when core is paused or fastforward ); localparam RASCAS_DELAY = 3'd2; // tRCD=20ns -> 3 cycles@128MHz @@ -122,11 +124,15 @@ reg [2:0] stage; always @(posedge clk) begin reg [12:0] addr_r; reg old_sync; + reg old_oe; if(|stage) stage <= stage + 1'd1; old_sync <= sync; - if(~old_sync & sync) stage <= 1; + old_oe <= oe; + if(~old_sync && sync && autorefresh) stage <= 1; // normal operation with read/write and refresh + if(refresh && stage == STATE_FIRST) stage <= 1; // forced refresh when paused or fastforward + if(~old_oe && oe && ~autorefresh) stage <= 1; // react on request only with fastforward sd_cmd <= CMD_INHIBIT; // default: idle sd_data <= 16'hZZZZ; @@ -163,7 +169,7 @@ always @(posedge clk) begin din_r <= din; addr_r <= { we ? ~ds : 2'b00, 2'b10, addr[22], addr[7:0] }; // auto precharge end - else begin + else if (autorefresh || refresh) begin sd_cmd <= CMD_AUTO_REFRESH; mode <= 0; end diff --git a/rtl/speedcontrol.vhd b/rtl/speedcontrol.vhd index b51cd6a..aa62228 100644 --- a/rtl/speedcontrol.vhd +++ b/rtl/speedcontrol.vhd @@ -5,69 +5,138 @@ use IEEE.numeric_std.all; entity speedcontrol is port ( - clk_sys : in std_logic; - pause : in std_logic; - speedup : in std_logic; - cart_act : in std_logic; - ce : out std_logic := '0'; - ce_2x : out std_logic := '0'; - ceNormal : out std_logic := '0'; - ce_2xNormal : out std_logic := '0' + clk_sys : in std_logic; + speed : in std_logic; + pause : in std_logic; + speedup : in std_logic; + cart_act : in std_logic; + ce : out std_logic := '0'; + ce_2x : buffer std_logic := '0'; + refresh : out std_logic := '0' ); end entity; architecture arch of speedcontrol is - signal clkdiv : unsigned(2 downto 0) := (others => '0'); - signal nextdiv : unsigned(2 downto 0) := (others => '0'); - - signal clkdivNormal : unsigned(2 downto 0) := (others => '0'); - - signal cart_act_1 : std_logic := '0'; + signal clkdiv : unsigned(2 downto 0) := (others => '0'); + + signal cart_act_1 : std_logic := '0'; + + signal unpause_cnt : integer range 0 to 15 := 0; + signal fastforward_cnt : integer range 0 to 15 := 0; + + signal refreshcnt : integer range 0 to 127 := 0; + signal sdram_busy : integer range 0 to 1 := 0; + + type tstate is + ( + NORMAL, + PAUSED, + FASTFORWARDSTART, + FASTFORWARD, + FASTFORWARDEND, + RAMACCESS + ); + signal state : tstate := NORMAL; begin process(clk_sys) begin if falling_edge(clk_sys) then - if (pause = '1') then + + ce <= '0'; + ce_2x <= '0'; + refresh <= '0'; - ce <= '0'; - ce_2x <= '0'; - ceNormal <= '0'; - ce_2xNormal <= '0'; - - else - - clkdiv <= clkdiv + 1; - clkdivNormal <= clkdivNormal + 1; - - -- generation for speed depending on speedup - cart_act_1 <= cart_act; - - if (clkdiv = "000") then ce <= '1'; else ce <= '0'; end if; - if ((nextdiv = "111" and clkdiv(1 downto 0) = "00") or nextdiv = "001") then ce_2x <= '1'; else ce_2x <= '0'; end if; - - if (clkdiv = nextdiv and (clkdiv = "111" or cart_act = '0')) then - clkdiv <= "000"; - if (speedup = '1') then - nextdiv <= "001"; - else - nextdiv <= "111"; - end if; - end if; - - if (cart_act = '1' and cart_act_1 = '0') then - nextdiv <= "111"; - end if; - - -- generation for non speed up base, used e.g. for sound hack - if (clkdivNormal = "000") then ceNormal <= '1'; else ceNormal <= '0'; end if; - if (clkdivNormal(1 downto 0) = "00") then ce_2xNormal <= '1'; else ce_2xNormal <= '0'; end if; + cart_act_1 <= cart_act; + if (refreshcnt > 0) then + refreshcnt <= refreshcnt - 1; end if; + + case (state) is + + when NORMAL => + if (pause = '1' and clkdiv = "111") then + if (cart_act = '0') then + state <= PAUSED; + unpause_cnt <= 0; + end if; + elsif (speedup = '1' and pause = '0') then + state <= FASTFORWARDSTART; + fastforward_cnt <= 0; + else + clkdiv <= clkdiv + 1; + if (clkdiv = "000") then + ce <= '1'; + end if; + if (clkdiv(1 downto 0) = "00") then + ce_2x <= '1'; + end if; + end if; + + when PAUSED => + if (unpause_cnt = 0) then + refresh <= '1'; + end if; + + if (pause = '0') then + if (unpause_cnt = 15) then + state <= NORMAL; + else + unpause_cnt <= unpause_cnt + 1; + end if; + end if; + + when FASTFORWARDSTART => + if (fastforward_cnt = 15) then + state <= FASTFORWARD; + else + fastforward_cnt <= fastforward_cnt + 1; + end if; + + when FASTFORWARD => + if (pause = '1' or speedup = '0') then + state <= FASTFORWARDEND; + fastforward_cnt <= 0; + end if; + + if (cart_act = '1' and cart_act_1 = '0') then + state <= RAMACCESS; + sdram_busy <= 1; + elsif (cart_act = '0' and refreshcnt = 0) then + refreshcnt <= 127; + refresh <= '1'; + state <= RAMACCESS; + sdram_busy <= 1; + else + clkdiv(0) <= not clkdiv(0); + if (clkdiv(0) = '0') then + ce <= '1'; + end if; + ce_2x <= '1'; + end if; + + when FASTFORWARDEND => + if (fastforward_cnt = 15) then + state <= NORMAL; + else + fastforward_cnt <= fastforward_cnt + 1; + end if; + + when RAMACCESS => + if (sdram_busy > 0) then + sdram_busy <= sdram_busy - 1; + else + state <= FASTFORWARD; + end if; + + end case; end if; end process; + + end architecture; diff --git a/sim/src/tb/sdram_model.vhd b/sim/src/tb/sdram_model.vhd index 154ca67..ed5a444 100644 --- a/sim/src/tb/sdram_model.vhd +++ b/sim/src/tb/sdram_model.vhd @@ -65,7 +65,6 @@ begin wait until rising_edge(clk); if (cart_rd = '1') then - cart_do <= x"FF"; wait until rising_edge(clk); wait until rising_edge(clk); wait until rising_edge(clk); diff --git a/sim/src/tb/tb.vhd b/sim/src/tb/tb.vhd index b0160be..dfe8b88 100644 --- a/sim/src/tb/tb.vhd +++ b/sim/src/tb/tb.vhd @@ -24,6 +24,7 @@ architecture arch of etb is signal reset : std_logic := '1'; signal clksys : std_logic := '1'; + signal clkram : std_logic := '1'; signal clkdiv : unsigned(2 downto 0) := (others => '0'); signal nextdiv : unsigned(2 downto 0) := (others => '0'); @@ -31,6 +32,8 @@ architecture arch of etb is signal ce : std_logic := '1'; signal ce_2x : std_logic := '1'; + signal speed : std_logic; + signal command_in : std_logic; signal command_out : std_logic; signal command_out_filter : std_logic; @@ -62,6 +65,8 @@ architecture arch of etb is signal pixel_out_we : std_logic := '0'; + signal is_CGB : std_logic := '1'; + -- settings signal GB_on : std_logic_vector(Reg_GB_on.upper downto Reg_GB_on.lower) := (others => '0'); @@ -69,7 +74,8 @@ architecture arch of etb is begin reset <= not GB_on(0); - clksys <= not clksys after 15 ns; + clksys <= not clksys after 14 ns; + clkram <= not clkram after 7 ns; clk100 <= not clk100 after 5 ns; @@ -82,6 +88,7 @@ begin port map ( clk_sys => clksys, + speed => speed, pause => '0', speedup => '1', cart_act => cart_act, @@ -89,24 +96,15 @@ begin ce_2x => ce_2x ); - isdram_model : entity tb.sdram_model port map ( - clk => clksys, + clk => clkram, cart_addr => cart_addr, cart_rd => cart_rd, cart_do => cart_do ); - --itetris : entity gameboy.tetris - --port map - --( - -- clk => clksys, - -- address => cart_addr(14 downto 0), - -- data => cart_do - --); - igb : entity gameboy.gb port map ( @@ -115,12 +113,11 @@ begin clk_sys => clksys, ce => ce, ce_2x => ce_2x, - --ce_sound => ce_2x, fast_boot => '1', joystick => x"00", - isGBC => '0', - isGBC_game => '0', + isGBC => is_CGB, + isGBC_game => is_CGB, -- cartridge interface -- can adress up to 1MB ROM @@ -148,7 +145,7 @@ begin joy_p54 => open, joy_din => "0000", - speed => open, --GBC + speed => speed, --GBC gg_reset => reset, gg_en => '0', @@ -167,7 +164,7 @@ begin port map ( clk => clksys, - address => gbc_bios_addr(7 downto 0), + address => gbc_bios_addr, data => gbc_bios_do ); @@ -195,13 +192,17 @@ begin end if; end if; - case (lcd_data(1 downto 0)) is - when "00" => pixel_out_data <= "11111" & "11111" & "11111"; - when "01" => pixel_out_data <= "10000" & "10000" & "10000"; - when "10" => pixel_out_data <= "01000" & "01000" & "01000"; - when "11" => pixel_out_data <= "00000" & "00000" & "00000"; - when others => pixel_out_data <= "00000" & "00000" & "11111"; - end case; + if (is_CGB = '0') then + case (lcd_data(1 downto 0)) is + when "00" => pixel_out_data <= "11111" & "11111" & "11111"; + when "01" => pixel_out_data <= "10000" & "10000" & "10000"; + when "10" => pixel_out_data <= "01000" & "01000" & "01000"; + when "11" => pixel_out_data <= "00000" & "00000" & "00000"; + when others => pixel_out_data <= "00000" & "00000" & "11111"; + end case; + else + pixel_out_data <= lcd_data; + end if; end if; end process; diff --git a/sim/vcom_all.bat b/sim/vcom_all.bat index 6b52b8e..f21b344 100644 --- a/sim/vcom_all.bat +++ b/sim/vcom_all.bat @@ -3,6 +3,7 @@ vcom -93 -quiet -work sim/tb ^ src/tb/globals.vhd vcom -93 -quiet -work sim/mem ^ +src/mem/SyncRamDualByteEnable.vhd ^ src/mem/SyncFifo.vhd vcom -quiet -work sim/rs232 ^