|
---------------------------------------------------------------------------
|
|
-- (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.STD_LOGIC_MISC.all;
|
|
|
|
ENTITY timing6502 IS
|
|
PORT
|
|
(
|
|
CLK : IN STD_LOGIC;
|
|
RESET_N : IN STD_LOGIC;
|
|
|
|
PHI0 : IN STD_LOGIC;
|
|
HALT_N : IN STD_LOGIC;
|
|
IRQ_N : IN STD_LOGIC;
|
|
NMI_N : IN STD_LOGIC;
|
|
|
|
-- FPGA side
|
|
ADDR_IN : IN STD_LOGIC_VECTOR(15 downto 0);
|
|
DATA_IN : IN STD_LOGIC_VECTOR(7 downto 0);
|
|
WRITE_IN : IN STD_LOGIC;
|
|
|
|
DATA_OUT : OUT STD_LOGIC_VECTOR(7 downto 0);
|
|
|
|
CPU_REQUEST : OUT STD_LOGIC;
|
|
CPU_REQUEST_COMPLETE : OUT STD_LOGIC;
|
|
|
|
CPU_IRQ_N : OUT STD_LOGIC;
|
|
CPU_NMI_N : OUT STD_LOGIC;
|
|
CPU_RDY : OUT STD_LOGIC;
|
|
|
|
-- 6502 side
|
|
BUS_DATA_IN : IN STD_LOGIC_VECTOR(7 downto 0);
|
|
BUS_RDY : IN STD_LOGIC;
|
|
|
|
BUS_PHI1 : OUT STD_LOGIC;
|
|
BUS_PHI2 : OUT STD_LOGIC;
|
|
BUS_SUBCYCLE : OUT STD_LOGIC_VECTOR(4 downto 0);
|
|
BUS_ADDR_OUT : OUT STD_LOGIC_VECTOR(15 downto 0);
|
|
BUS_ADDR_OE : OUT STD_LOGIC;
|
|
BUS_DATA_OUT : OUT STD_LOGIC_VECTOR(7 downto 0);
|
|
BUS_DATA_OE : OUT STD_LOGIC;
|
|
BUS_WRITE_N : OUT STD_LOGIC;
|
|
BUS_WRITE_OE : OUT STD_LOGIC
|
|
);
|
|
END timing6502;
|
|
|
|
ARCHITECTURE vhdl OF timing6502 IS
|
|
signal state_next : std_logic_vector(4 downto 0);
|
|
signal state_reg : STD_LOGIC_VECTOR(4 DOWNTO 0);
|
|
|
|
signal addr_next : std_logic_vector(15 downto 0);
|
|
signal addr_reg : std_logic_vector(15 downto 0);
|
|
|
|
signal addr_oe_next : std_logic;
|
|
signal addr_oe_reg : std_logic;
|
|
|
|
signal data_next : std_logic_vector(7 downto 0);
|
|
signal data_reg : std_logic_vector(7 downto 0);
|
|
|
|
signal data_oe_next : std_logic;
|
|
signal data_oe_reg : std_logic;
|
|
|
|
signal data_read_next : std_logic_vector(7 downto 0);
|
|
signal data_read_reg : std_logic_vector(7 downto 0);
|
|
|
|
signal phi1_next : std_logic;
|
|
signal phi1_reg : std_logic;
|
|
|
|
signal phi2_next : std_logic;
|
|
signal phi2_reg : std_logic;
|
|
|
|
signal write_n_next : std_logic;
|
|
signal write_n_reg : std_logic;
|
|
|
|
signal write_oe_next : std_logic;
|
|
signal write_oe_reg : std_logic;
|
|
|
|
signal request_handling_next : std_logic;
|
|
signal request_handling_reg : std_logic;
|
|
|
|
signal PHI0_NEXT : std_logic;
|
|
signal PHI0_REG : std_logic;
|
|
signal NMI_N_NEXT : std_logic;
|
|
signal NMI_N_REG : std_logic;
|
|
signal IRQ_N_NEXT : std_logic;
|
|
signal IRQ_N_REG : std_logic;
|
|
signal RDY_NEXT : std_logic;
|
|
signal RDY_REG : std_logic;
|
|
signal HALT_N_NEXT : std_logic;
|
|
signal HALT_N_REG : std_logic;
|
|
|
|
signal init_next : std_logic_vector(5 downto 0);
|
|
signal init_reg : std_logic_vector(5 downto 0);
|
|
|
|
signal syncphi2 : std_logic;
|
|
signal initmode : std_logic;
|
|
BEGIN
|
|
-- regs
|
|
|
|
process(clk, reset_n)
|
|
begin
|
|
if (reset_n='0') then
|
|
state_reg <= "01100";
|
|
addr_reg <= (others=>'0');
|
|
addr_oe_reg <= '0';
|
|
data_reg <= (others=>'0');
|
|
data_read_reg <= (others=>'0');
|
|
data_oe_reg <= '0';
|
|
phi1_reg <= '0';
|
|
phi2_reg <= '0';
|
|
write_n_reg <= '1';
|
|
write_oe_reg <= '0';
|
|
request_handling_reg <= '0';
|
|
|
|
PHI0_REG <= '1';
|
|
IRQ_N_REG <= '1';
|
|
NMI_N_REG <= '1';
|
|
HALT_N_REG <= '1';
|
|
RDY_REG <= '1';
|
|
init_reg <= (others=>'0');
|
|
elsif (clk'event and clk='1') then
|
|
state_reg <= state_next;
|
|
addr_reg <= addr_next;
|
|
addr_oe_reg <= addr_oe_next;
|
|
data_reg <= data_next;
|
|
data_read_reg <= data_read_next;
|
|
data_oe_reg <= data_oe_next;
|
|
phi1_reg <= phi1_next;
|
|
phi2_reg <= phi2_next;
|
|
write_n_reg <= write_n_next;
|
|
write_oe_reg <= write_oe_next;
|
|
request_handling_reg <= request_handling_next;
|
|
|
|
PHI0_REG <= PHI0_NEXT;
|
|
IRQ_N_REG <= IRQ_N_NEXT;
|
|
NMI_N_REG <= NMI_N_NEXT;
|
|
HALT_N_REG <= HALT_N_NEXT;
|
|
RDY_REG <= RDY_NEXT;
|
|
|
|
init_reg <= init_next;
|
|
end if;
|
|
end process;
|
|
|
|
PHI0_sync : entity work.synchronizer
|
|
port map (clk=>clk, raw=>PHI0, sync=>PHI0_NEXT);
|
|
|
|
process(init_reg,phi0_reg,phi0_next)
|
|
begin
|
|
init_next <= init_reg;
|
|
initmode <= '0';
|
|
syncphi2 <= '0';
|
|
|
|
if (phi0_reg = '0' and phi0_next='1') then
|
|
init_next(5 downto 0) <= init_reg(4 downto 0)&'1';
|
|
syncphi2 <= '1';
|
|
end if;
|
|
|
|
if (and_reduce(init_reg)='0') then
|
|
initmode <= '1';
|
|
end if;
|
|
end process;
|
|
|
|
-- next state
|
|
process(initmode, syncphi2, state_reg, phi1_reg, phi2_reg, addr_in, data_in, addr_reg, addr_oe_reg, data_reg, data_oe_reg, data_read_reg, bus_data_in, write_n_reg, write_in, request_handling_reg, write_oe_reg, irq_n_reg, nmi_n_reg, halt_n_reg, bus_rdy, rdy_reg, nmi_n, irq_n, halt_n)
|
|
begin
|
|
CPU_REQUEST_COMPLETE <= '0';
|
|
|
|
state_next <= state_reg;
|
|
phi1_next <= phi1_reg;
|
|
phi2_next <= phi2_reg;
|
|
addr_next <= addr_reg;
|
|
addr_oe_next <= addr_oe_reg;
|
|
data_next <= data_reg;
|
|
data_oe_next <= data_oe_reg;
|
|
data_read_next <= data_read_reg;
|
|
write_n_next <= write_n_reg;
|
|
request_handling_next <= request_handling_reg;
|
|
write_oe_next <= write_oe_reg;
|
|
irq_n_next <= irq_n_reg;
|
|
nmi_n_next <= nmi_n_reg;
|
|
halt_n_next <= halt_n_reg;
|
|
rdy_next <= rdy_reg;
|
|
|
|
if (initmode = '0') then
|
|
state_next <= std_logic_vector(unsigned(state_reg)+1);
|
|
end if;
|
|
|
|
if (syncphi2 = '1') then
|
|
phi1_next <= '1';
|
|
state_next <= "01111";
|
|
end if;
|
|
|
|
rdy_next <= bus_rdy;
|
|
|
|
case state_reg is
|
|
when "00000" =>
|
|
addr_next <= addr_in;
|
|
data_next <= data_in;
|
|
write_n_next <= not(write_in);
|
|
request_handling_next <= halt_n_reg;
|
|
when "00010"=>
|
|
addr_oe_next <= request_handling_reg;
|
|
write_oe_next <= request_handling_reg;
|
|
when "01100" =>
|
|
phi1_next <= '0';
|
|
when "01110" =>
|
|
phi2_next <= '1';
|
|
when "10010" =>
|
|
if (write_in = '1') then
|
|
data_oe_next <= request_handling_reg;
|
|
end if;
|
|
when "11011" =>
|
|
phi2_next <= '0';
|
|
when "11100" =>
|
|
data_read_next <= bus_data_in;
|
|
|
|
nmi_n_next <= nmi_n;
|
|
irq_n_next <= irq_n;
|
|
halt_n_next <= halt_n;
|
|
when "11101" =>
|
|
request_handling_next <= '0';
|
|
CPU_REQUEST_COMPLETE <= request_handling_reg;
|
|
when "11110" =>
|
|
addr_next <= (others=>'0');
|
|
addr_oe_next <= '0';
|
|
write_oe_next <= '0';
|
|
data_oe_next <= '0';
|
|
write_n_next <= '1';
|
|
phi1_next <= '1';
|
|
when others=>
|
|
end case;
|
|
|
|
end process;
|
|
|
|
-- outputs
|
|
BUS_SUBCYCLE <= state_reg;
|
|
BUS_PHI1 <= phi1_reg;
|
|
BUS_PHI2 <= phi2_reg;
|
|
BUS_ADDR_OUT <= addr_reg;
|
|
BUS_ADDR_OE <= addr_oe_reg;
|
|
BUS_DATA_OUT <= data_reg;
|
|
BUS_DATA_OE <= data_oe_reg;
|
|
BUS_WRITE_N <= write_n_reg;
|
|
BUS_WRITE_OE <= write_oe_reg;
|
|
|
|
DATA_OUT <= data_read_reg;
|
|
|
|
CPU_REQUEST <= request_handling_reg;
|
|
CPU_NMI_N <= NMI_N_REG;
|
|
CPU_IRQ_N <= IRQ_N_REG;
|
|
CPU_RDY <= RDY_REG;
|
|
|
|
END vhdl;
|