|
---------------------------------------------------------------------------
|
|
-- (c) 2013 mark watson
|
|
-- I am happy for anyone to use this for non-commercial use.
|
|
-- If my vhdl files are used commercially or otherwise sold,
|
|
-- please contact me for explicit permission at scrameta (gmail).
|
|
-- This applies for source and binary form and derived works.
|
|
---------------------------------------------------------------------------
|
|
LIBRARY ieee;
|
|
USE ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
USE ieee.math_real.ceil;
|
|
USE ieee.math_real.log2;
|
|
|
|
-- TODO - review this whole scheme
|
|
-- Massively overcomplex and turbo doesn't even work with it right now!
|
|
ENTITY shared_enable IS
|
|
GENERIC
|
|
(
|
|
cycle_length : integer := 16 -- or 32...
|
|
);
|
|
PORT
|
|
(
|
|
CLK : IN STD_LOGIC;
|
|
RESET_N : IN STD_LOGIC;
|
|
ANTIC_REFRESH : IN STD_LOGIC;
|
|
MEMORY_READY_CPU : IN STD_LOGIC; -- during memory wait states keep CPU awake
|
|
MEMORY_READY_ANTIC : IN STD_LOGIC; -- during memory wait states keep CPU awake
|
|
PAUSE_6502 : in std_logic;
|
|
THROTTLE_COUNT_6502 : in std_logic_vector(5 downto 0);
|
|
|
|
ANTIC_ENABLE_179 : OUT STD_LOGIC; -- always about 1.79MHz to keep sound the same - 1 cycle early
|
|
oldcpu_enable : OUT STD_LOGIC; -- always about 1.79MHz to keep sound the same - 1 cycle only, when memory is ready...
|
|
CPU_ENABLE_OUT : OUT STD_LOGIC -- for compatibility run at 1.79MHz, for speed run as fast as we can
|
|
|
|
-- antic DMA runs 1 cycle after 'enable', so ANTIC_ENABLE is delayed by cycle_length-1 cycles vs CPU_ENABLE (when in 1.79MHz mode)
|
|
);
|
|
END shared_enable;
|
|
|
|
ARCHITECTURE vhdl OF shared_enable IS
|
|
component enable_divider IS
|
|
generic(COUNT : natural := 1);
|
|
PORT
|
|
(
|
|
CLK : IN STD_LOGIC;
|
|
RESET_N : IN STD_LOGIC;
|
|
ENABLE_IN : IN STD_LOGIC;
|
|
|
|
ENABLE_OUT : OUT STD_LOGIC
|
|
);
|
|
END component;
|
|
|
|
component delay_line IS
|
|
generic(COUNT : natural := 1);
|
|
PORT
|
|
(
|
|
CLK : IN STD_LOGIC;
|
|
SYNC_RESET : IN STD_LOGIC;
|
|
DATA_IN : IN STD_LOGIC;
|
|
ENABLE : IN STD_LOGIC;
|
|
RESET_N : IN STD_LOGIC;
|
|
|
|
DATA_OUT : OUT STD_LOGIC
|
|
);
|
|
END component;
|
|
|
|
signal enable_179 : std_logic;
|
|
signal enable_179_early : std_logic;
|
|
signal cpu_enable : std_logic;
|
|
|
|
signal cpu_extra_enable_next : std_logic;
|
|
signal cpu_extra_enable_reg : std_logic;
|
|
|
|
signal speed_shift_next : std_logic_vector(cycle_length-1 downto 0);
|
|
signal speed_shift_reg : std_logic_vector(cycle_length-1 downto 0);
|
|
|
|
signal oldcycle_go : std_logic;
|
|
signal oldcycle_state_next : std_logic_vector(2 downto 0);
|
|
signal oldcycle_state_reg : std_logic_vector(2 downto 0);
|
|
constant oldcycle_state_idle : std_logic_vector(2 downto 0) := "000";
|
|
constant oldcycle_state_first_cycle_in_progress : std_logic_vector(2 downto 0) := "001";
|
|
constant oldcycle_state_cycle_in_progress : std_logic_vector(2 downto 0) := "010";
|
|
constant oldcycle_state_will_start_when_memory_free : std_logic_vector(2 downto 0) := "011";
|
|
constant oldcycle_state_delayed : std_logic_vector(2 downto 0) := "100";
|
|
|
|
signal memory_ready : std_logic;
|
|
signal skip_cycle : std_logic;
|
|
|
|
constant cycle_length_bits: integer := integer(ceil(log2(real(cycle_length))));
|
|
begin
|
|
-- instantiate some clock calcs
|
|
enable_179_clock_div : enable_divider
|
|
generic map (COUNT=>cycle_length)
|
|
port map(clk=>clk,reset_n=>reset_n,enable_in=>'1',enable_out=>enable_179);
|
|
|
|
process(THROTTLE_COUNT_6502, speed_shift_reg, enable_179)
|
|
variable speed_shift : std_logic;
|
|
variable speed_shift_temp : std_logic_vector(cycle_length-1 downto 0);
|
|
begin
|
|
|
|
if (enable_179 = '1') then -- synchronize
|
|
speed_shift_temp(cycle_length-1 downto 1) := (others=>'0');
|
|
speed_shift_temp(0) := '1';
|
|
else
|
|
speed_shift_temp := speed_shift_reg;
|
|
end if;
|
|
|
|
speed_shift_next(cycle_length-1 downto 1) <= speed_shift_temp(cycle_length-2 downto 0);
|
|
|
|
speed_shift := '0';
|
|
|
|
for i in 0 to cycle_length_bits loop
|
|
speed_shift := speed_shift or (speed_shift_temp(cycle_length/(2**i)-1) and throttle_count_6502(i));
|
|
end loop;
|
|
|
|
speed_shift_next(0) <= speed_shift;
|
|
end process;
|
|
|
|
delay_line_phase : delay_line
|
|
generic map (COUNT=>cycle_length-1)
|
|
port map(clk=>clk,sync_reset=>'0',reset_n=>reset_n,data_in=>enable_179, enable=>'1', data_out=>enable_179_early);
|
|
|
|
-- registers
|
|
process(clk,reset_n)
|
|
begin
|
|
if (reset_n = '0') then
|
|
cpu_extra_enable_reg <= '0';
|
|
oldcycle_state_reg <= oldcycle_state_idle;
|
|
speed_shift_reg <= (others=>'0');
|
|
elsif (clk'event and clk='1') then
|
|
cpu_extra_enable_reg <= cpu_extra_enable_next;
|
|
oldcycle_state_reg <= oldcycle_state_next;
|
|
speed_shift_reg <= speed_shift_next;
|
|
end if;
|
|
end process;
|
|
|
|
-- next state
|
|
memory_ready <= memory_ready_cpu or memory_ready_antic;
|
|
skip_cycle <= pause_6502 or antic_refresh;
|
|
|
|
cpu_enable <= (speed_shift_reg(0) or cpu_extra_enable_reg or enable_179) and not(skip_cycle);
|
|
cpu_extra_enable_next <= cpu_enable and not(memory_ready);
|
|
|
|
process(oldcycle_state_reg,enable_179,memory_ready,skip_cycle,cpu_enable)
|
|
begin
|
|
oldcycle_go <= '0';
|
|
oldcycle_state_next <= oldcycle_state_reg;
|
|
|
|
case (oldcycle_state_reg) is
|
|
when oldcycle_state_idle =>
|
|
if (enable_179 = '1') then
|
|
if (skip_cycle = '1') then
|
|
oldcycle_go <= '1';
|
|
else
|
|
if (memory_ready = '1') then
|
|
oldcycle_go <= '1';
|
|
else
|
|
oldcycle_state_next <= oldcycle_state_first_cycle_in_progress;
|
|
end if;
|
|
end if;
|
|
else
|
|
if (cpu_enable = '1' and memory_ready='0') then
|
|
oldcycle_state_next <= oldcycle_state_cycle_in_progress;
|
|
end if;
|
|
end if;
|
|
when oldcycle_state_first_cycle_in_progress =>
|
|
if (memory_ready = '1') then
|
|
oldcycle_go <= '1';
|
|
oldcycle_state_next <= oldcycle_state_idle;
|
|
end if;
|
|
when oldcycle_state_cycle_in_progress =>
|
|
if (enable_179 = '1') then
|
|
if (memory_ready = '1') then
|
|
oldcycle_state_next <= oldcycle_state_delayed;
|
|
else
|
|
oldcycle_state_next <= oldcycle_state_will_start_when_memory_free;
|
|
end if;
|
|
else
|
|
if (memory_ready = '1') then
|
|
oldcycle_state_next <= oldcycle_state_idle;
|
|
end if;
|
|
end if;
|
|
when oldcycle_state_will_start_when_memory_free =>
|
|
if (memory_ready = '1') then
|
|
oldcycle_state_next <= oldcycle_state_delayed;
|
|
end if;
|
|
when oldcycle_state_delayed =>
|
|
oldcycle_state_next <= oldcycle_state_idle;
|
|
if (skip_cycle = '1') then
|
|
oldcycle_go <= '1';
|
|
else
|
|
if (memory_ready = '1') then
|
|
oldcycle_go <= '1';
|
|
else
|
|
oldcycle_state_next <= oldcycle_state_first_cycle_in_progress;
|
|
end if;
|
|
end if;
|
|
when others=>
|
|
oldcycle_state_next <= oldcycle_state_idle;
|
|
end case;
|
|
|
|
end process;
|
|
|
|
-- output
|
|
oldcpu_enable <= oldcycle_go;
|
|
ANTIC_ENABLE_179 <= enable_179_early;
|
|
|
|
CPU_ENABLE_OUT <= cpu_enable; -- run at 25MHz
|
|
|
|
end vhdl;
|