AtomBusMon/src/Z80CpuMon.vhd

357 lines
11 KiB
VHDL
Raw Normal View History

--------------------------------------------------------------------------------
-- Copyright (c) 2015 David Banks
--
--------------------------------------------------------------------------------
-- ____ ____
-- / /\/ /
-- /___/ \ /
-- \ \ \/
-- \ \
-- / / Filename : Z80CpuMon.vhd
-- /___/ /\ Timestamp : 22/06/2015
-- \ \ / \
-- \___\/\___\
--
--Design Name: Z80CpuMon
--Device: XC3S250E
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
use work.OhoPack.all ;
entity Z80CpuMon is
generic (
UseT80Core : boolean := true
);
port (
clock49 : in std_logic;
-- Z80 Signals
RESET_n : in std_logic;
CLK_n : in std_logic;
WAIT_n : in std_logic;
INT_n : in std_logic;
NMI_n : in std_logic;
BUSRQ_n : in std_logic;
M1_n : out std_logic;
MREQ_n : out std_logic;
IORQ_n : out std_logic;
RD_n : out std_logic;
WR_n : out std_logic;
RFSH_n : out std_logic;
HALT_n : out std_logic;
BUSAK_n : out std_logic;
Addr : out std_logic_vector(15 downto 0);
Data : inout std_logic_vector(7 downto 0);
-- External trigger inputs
trig : in std_logic_vector(1 downto 0);
-- Serial Console
avr_RxD : in std_logic;
avr_TxD : out std_logic;
-- GODIL Switches
sw1 : in std_logic;
nsw2 : in std_logic;
-- GODIL LEDs
led3 : out std_logic;
led6 : out std_logic;
led8 : out std_logic;
-- OHO_DY1 connected to test connector
tmosi : out std_logic;
tdin : out std_logic;
tcclk : out std_logic;
-- Debugging signals
test1 : out std_logic;
test2 : out std_logic;
test3 : out std_logic;
test4 : out std_logic
);
end Z80CpuMon;
architecture behavioral of Z80CpuMon is
type state_type is (idle, rd_init, rd_setup, rd, rd_hold, wr_init, wr_setup, wr, wr_hold, release);
signal state : state_type;
signal RESET_n_int : std_logic;
signal cpu_clk : std_logic;
signal busmon_clk : std_logic;
signal Addr_int : std_logic_vector(15 downto 0);
signal RD_n_int : std_logic;
signal WR_n_int : std_logic;
signal MREQ_n_int : std_logic;
signal IORQ_n_int : std_logic;
signal M1_n_int : std_logic;
signal WAIT_n_int : std_logic;
signal TState : std_logic_vector(2 downto 0);
signal SS_Single : std_logic;
signal SS_Step : std_logic;
signal SS_Step_held : std_logic;
signal CountCycle : std_logic;
signal Regs : std_logic_vector(255 downto 0);
signal io_not_mem : std_logic;
signal io_rd : std_logic;
signal io_wr : std_logic;
signal memory_rd : std_logic;
signal memory_wr : std_logic;
signal memory_addr : std_logic_vector(15 downto 0);
signal memory_dout : std_logic_vector(7 downto 0);
signal memory_din : std_logic_vector(7 downto 0);
signal memory_done : std_logic;
signal INT_n_sync : std_logic;
signal NMI_n_sync : std_logic;
signal Rdy : std_logic;
signal Read_n : std_logic;
signal Read_n0 : std_logic;
signal Read_n1 : std_logic;
signal Write_n : std_logic;
signal Write_n0 : std_logic;
signal Sync : std_logic;
signal Sync0 : std_logic;
signal nRST : std_logic;
signal MemState : std_logic_vector(2 downto 0);
signal Din : std_logic_vector(7 downto 0);
signal Dout : std_logic_vector(7 downto 0);
signal Den : std_logic;
signal ex_data : std_logic_vector(7 downto 0);
signal rd_data : std_logic_vector(7 downto 0);
signal mon_data : std_logic_vector(7 downto 0);
begin
mon : entity work.BusMonCore
generic map (
num_comparators => 4
)
port map (
clock49 => clock49,
Addr => Addr_int,
Data => mon_data,
Phi2 => busmon_clk,
Rd_n => Read_n,
Wr_n => Write_n,
Sync => Sync,
Rdy => Rdy,
nRSTin => RESET_n_int,
nRSTout => nRST,
CountCycle => CountCycle,
trig => trig,
lcd_rs => open,
lcd_rw => open,
lcd_e => open,
lcd_db => open,
avr_RxD => avr_RxD,
avr_TxD => avr_TxD,
sw1 => '0',
nsw2 => nsw2,
led3 => led3,
led6 => led6,
led8 => led8,
tmosi => tmosi,
tdin => tdin,
tcclk => tcclk,
Regs => Regs,
RdMemOut => memory_rd,
WrMemOut => memory_wr,
RdIOOut => io_rd,
WrIOOut => io_wr,
AddrOut => memory_addr,
DataOut => memory_dout,
DataIn => memory_din,
Done => memory_done,
SS_Single => SS_Single,
SS_Step => SS_Step
);
GenT80Core: if UseT80Core generate
inst_t80: entity work.T80a port map (
TS => TState,
Regs => Regs,
RESET_n => RESET_n_int,
CLK_n => cpu_clk,
WAIT_n => WAIT_n_int,
INT_n => INT_n_sync,
NMI_n => NMI_n_sync,
BUSRQ_n => BUSRQ_n,
M1_n => M1_n_int,
MREQ_n => MREQ_n_int,
IORQ_n => IORQ_n_int,
RD_n => RD_n_int,
WR_n => WR_n_int,
RFSH_n => RFSH_n,
HALT_n => HALT_n,
BUSAK_n => BUSAK_n,
A => Addr_int,
Din => Din,
Dout => Dout,
DEn => Den
);
end generate;
WAIT_n_int <= WAIT_n when SS_Single = '0' else
WAIT_n and SS_Step_held;
CountCycle <= '1' when SS_Single = '0' or SS_Step_held = '1' else '0';
sync_gen : process(CLK_n, RESET_n_int)
begin
if RESET_n_int = '0' then
NMI_n_sync <= '1';
INT_n_sync <= '1';
SS_Step_held <= '1';
elsif rising_edge(CLK_n) then
NMI_n_sync <= NMI_n;
INT_n_sync <= INT_n;
if (M1_n_int = '0' and TState = "001") then
-- stop at the end of T1 instruction fetch
SS_Step_held <= '0';
elsif (SS_Step = '1') then
-- start again when the single step command is issues
SS_Step_held <= '1';
end if;
end if;
end process;
-- Make the monitoring decision in the middle of T2, but only if WAIT_n is '1'
Sync0 <= (WAIT_n_int and (not RD_n_int) and (not MREQ_n_int) and (not M1_n_int)) when TState = "010" else '0';
Read_n0 <= not (WAIT_n_int and (not RD_n_int) and (not MREQ_n_int) and (M1_n_int)) when TState = "010" else '1';
Write_n0 <= not (WAIT_n_int and (not WR_n_int) and (not MREQ_n_int) and (M1_n_int)) when TState = "010" else '1';
-- These are useful for debugging IO Requests:
-- Read_n0 <= not (WAIT_n_int and (not RD_n_int) and (not IORQ_n_int) and (M1_n_int)) when TState = "010" else '1';
-- Write_n0 <= not ( ( RD_n_int) and (not IORQ_n_int) and (M1_n_int)) when TState = "011" else '1';
-- Hold the monitoring decision so it is valid on the rising edge of the clock
-- For instruction fetches and writes, the monitor sees these at the start of T3
-- For reads, the data can arrive in the middle of T3 so delay until end of T3
watch_gen : process(CLK_n)
begin
if falling_edge(CLK_n) then
Sync <= Sync0;
Read_n1 <= Read_n0;
Read_n <= Read_n1;
Write_n <= Write_n0;
end if;
end process;
-- Register the exec/write data on the rising at the end of T2
ex_data_latch : process(CLK_n)
begin
if rising_edge(CLK_n) then
if (Sync = '1' or Write_n = '0') then
ex_data <= Data;
end if;
end if;
end process;
-- Register the read data on the falling edge of clock in the middle of T3
rd_data_latch : process(CLK_n)
begin
if falling_edge(CLK_n) then
if (Read_n1 = '0') then
rd_data <= Data;
end if;
memory_din <= Data;
end if;
end process;
-- Mux the data seen by the bus monitor appropriately
mon_data <= rd_data when Read_n <= '0' else ex_data;
-- Memory access
Addr <= memory_addr when (state /= idle) else Addr_int;
MREQ_n <= '1' when (state = rd_init or state = wr_init or state = release) else
'0' when (state /= idle and io_not_mem = '0') else MREQ_n_int;
IORQ_n <= '1' when (state = rd_init or state = wr_init or state = release) else
'0' when (state /= idle and io_not_mem = '1') else IORQ_n_int;
WR_n <= '0' when (state = wr) else
'1' when (state /= idle) else WR_n_int;
RD_n <= '0' when (state = rd_setup or state = rd or state = rd_hold) else
'1' when (state /= idle) else RD_n_int;
M1_n <= '1' when (state /= idle) else M1_n_int;
memory_done <= '1' when (state = rd_hold or state = wr_hold) else '0';
-- TODO: Also need to take account of BUSRQ_n/BUSAK_n
Data <= memory_dout when state = wr_setup or state = wr or state = wr_hold else
Dout when state = idle and Den = '1' else
(others => 'Z');
Din <= Data;
-- TODO: Add refresh generation into idle loop
men_access_machine : process(CLK_n)
begin
if (RESET_n = '0') then
state <= idle;
elsif falling_edge(CLK_n) then
case state IS
when idle =>
if (memory_wr = '1' or io_wr = '1') then
state <= wr_init;
io_not_mem <= io_wr;
elsif (memory_rd = '1' or io_rd = '1') then
state <= rd_init;
io_not_mem <= io_rd;
end if;
when rd_init =>
state <= rd_setup;
when rd_setup =>
if (WAIT_n = '1') then
state <= rd;
end if;
when rd =>
state <= rd_hold;
when rd_hold =>
state <= idle;
when wr_init =>
state <= wr_setup;
when wr_setup =>
if (WAIT_n = '1') then
state <= wr;
end if;
when wr =>
state <= wr_hold;
when wr_hold =>
state <= release;
when release =>
state <= idle;
end case;
end if;
end process;
RESET_n_int <= RESET_n and (not sw1) and nRST;
test1 <= TState(0);
test2 <= TState(1);
test3 <= TState(2);
test4 <= CLK_n;
cpu_clk <= CLK_n;
busmon_clk <= CLK_n;
end behavioral;