mirror of
https://github.com/hoglet67/AtomBusMon.git
synced 2025-01-03 15:30:19 +00:00
c045ebd10c
Change-Id: I97ca73690c7e1258a5b359260d695af25c21ca54
402 lines
13 KiB
VHDL
402 lines
13 KiB
VHDL
-------------------------------------------------------------------------------
|
|
-- Copyright (c) 2019 David Banks
|
|
--
|
|
--------------------------------------------------------------------------------
|
|
-- ____ ____
|
|
-- / /\/ /
|
|
-- /___/ \ /
|
|
-- \ \ \/
|
|
-- \ \
|
|
-- / / Filename : MC6808CpuMonCore.vhd
|
|
-- /___/ /\ Timestamp : 24/010/2019
|
|
-- \ \ / \
|
|
-- \___\/\___\
|
|
--
|
|
--Design Name: MC6808CpuMonCore
|
|
--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 MC6809CpuMonCore is
|
|
generic (
|
|
UseCPU09Core : boolean := true;
|
|
ClkMult : integer := 10; -- default value correct for GODIL
|
|
ClkDiv : integer := 31; -- default value correct for GODIL
|
|
ClkPer : real := 20.345; -- default value correct for GODIL
|
|
num_comparators : integer := 8; -- default value correct for GODIL
|
|
avr_prog_mem_size : integer := 1024 * 9 -- default value correct for GODIL
|
|
);
|
|
port (
|
|
-- Fast clock
|
|
clock : in std_logic;
|
|
|
|
-- Quadrature clocks
|
|
E : in std_logic;
|
|
Q : in std_logic;
|
|
|
|
--6809 Signals
|
|
DMA_n_BREQ_n : in std_logic;
|
|
|
|
-- 6809E Sig
|
|
TSC : in std_logic;
|
|
LIC : out std_logic;
|
|
AVMA : out std_logic;
|
|
BUSY : out std_logic;
|
|
|
|
-- Signals common to both 6809 and 6809E
|
|
RES_n : in std_logic;
|
|
NMI_n : in std_logic;
|
|
IRQ_n : in std_logic;
|
|
FIRQ_n : in std_logic;
|
|
HALT_n : in std_logic;
|
|
BS : out std_logic;
|
|
BA : out std_logic;
|
|
R_W_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;
|
|
|
|
-- Switches
|
|
sw_interrupt : in std_logic;
|
|
sw_reset : in std_logic;
|
|
|
|
-- LEDs
|
|
led_bkpt : out std_logic;
|
|
led_trig0 : out std_logic;
|
|
led_trig1 : 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
|
|
|
|
);
|
|
end MC6809CpuMonCore;
|
|
|
|
architecture behavioral of MC6809CpuMonCore is
|
|
|
|
signal clock_avr : std_logic;
|
|
|
|
signal cpu_clk : std_logic;
|
|
signal busmon_clk : std_logic;
|
|
signal R_W_n_int : std_logic;
|
|
signal NMI_sync : std_logic;
|
|
signal IRQ_sync : std_logic;
|
|
signal FIRQ_sync : std_logic;
|
|
signal nRST_sync : std_logic;
|
|
signal HALT_sync : std_logic;
|
|
signal Addr_int : std_logic_vector(15 downto 0);
|
|
signal Din : std_logic_vector(7 downto 0);
|
|
signal Dout : std_logic_vector(7 downto 0);
|
|
signal Sync_int : std_logic;
|
|
signal Rdy_int : std_logic;
|
|
signal hold : std_logic;
|
|
|
|
signal memory_rd : std_logic;
|
|
signal memory_wr : std_logic;
|
|
signal memory_rd1 : std_logic;
|
|
signal memory_wr1 : std_logic;
|
|
signal memory_addr : std_logic_vector(15 downto 0);
|
|
signal memory_addr1 : 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 Regs : std_logic_vector(111 downto 0);
|
|
signal Regs1 : std_logic_vector(255 downto 0);
|
|
signal last_PC : std_logic_vector(15 downto 0);
|
|
|
|
signal ifetch : std_logic;
|
|
signal ifetch1 : std_logic;
|
|
signal SS_Single : std_logic;
|
|
signal SS_Step : std_logic;
|
|
signal CountCycle : std_logic;
|
|
signal special : std_logic_vector(1 downto 0);
|
|
|
|
signal LIC_int : std_logic;
|
|
|
|
signal E_a : std_logic; -- E delayed by 0..20ns
|
|
signal E_b : std_logic; -- E delayed by 20..40ns
|
|
signal E_c : std_logic; -- E delayed by 40..60ns
|
|
signal E_d : std_logic; -- E delayed by 60..80ns
|
|
signal E_e : std_logic; -- E delayed by 80..100ns
|
|
signal E_f : std_logic; -- E delayed by 100..120ns
|
|
signal E_g : std_logic; -- E delayed by 120..140ns
|
|
signal E_h : std_logic; -- E delayed by 120..140ns
|
|
signal E_i : std_logic; -- E delayed by 120..140ns
|
|
signal data_wr : std_logic;
|
|
signal nRSTout : std_logic;
|
|
|
|
signal NMI_n_masked : std_logic;
|
|
signal IRQ_n_masked : std_logic;
|
|
signal FIRQ_n_masked : std_logic;
|
|
|
|
signal led_trig0_n : std_logic;
|
|
signal led_trig1_n : std_logic;
|
|
signal led_bkpt_n : std_logic;
|
|
|
|
begin
|
|
|
|
LIC <= LIC_int;
|
|
-- The following outputs are not implemented
|
|
-- BUSY (6809E mode)
|
|
BUSY <= '0';
|
|
|
|
-- The following inputs are not implemented
|
|
-- DMA_n_BREQ_n (6809 mode)
|
|
|
|
led_trig0 <= not led_trig0_n;
|
|
led_trig1 <= not led_trig1_n;
|
|
led_bkpt <= not led_bkpt_n;
|
|
|
|
inst_dcm0 : entity work.DCM0
|
|
generic map (
|
|
ClkMult => ClkMult,
|
|
ClkDiv => ClkDiv,
|
|
ClkPer => ClkPer
|
|
)
|
|
port map(
|
|
CLKIN_IN => clock,
|
|
CLKFX_OUT => clock_avr
|
|
);
|
|
|
|
mon : entity work.BusMonCore
|
|
generic map (
|
|
num_comparators => num_comparators,
|
|
avr_prog_mem_size => avr_prog_mem_size
|
|
)
|
|
port map (
|
|
clock_avr => clock_avr,
|
|
busmon_clk => busmon_clk,
|
|
busmon_clken => '1',
|
|
cpu_clk => cpu_clk,
|
|
cpu_clken => '1',
|
|
Addr => Addr_int,
|
|
Data => Data,
|
|
Rd_n => not R_W_n_int,
|
|
Wr_n => R_W_n_int,
|
|
RdIO_n => '1',
|
|
WrIO_n => '1',
|
|
Sync => Sync_int,
|
|
Rdy => Rdy_int,
|
|
nRSTin => nRST_sync,
|
|
nRSTout => nRSTout,
|
|
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 => sw_interrupt,
|
|
nsw2 => not sw_reset,
|
|
led3 => led_trig0_n,
|
|
led6 => led_trig1_n,
|
|
led8 => led_bkpt_n,
|
|
tmosi => tmosi,
|
|
tdin => tdin,
|
|
tcclk => tcclk,
|
|
Regs => Regs1,
|
|
RdMemOut => memory_rd,
|
|
WrMemOut => memory_wr,
|
|
RdIOOut => open,
|
|
WrIOOut => open,
|
|
AddrOut => memory_addr,
|
|
DataOut => memory_dout,
|
|
DataIn => memory_din,
|
|
Done => memory_done,
|
|
Special => special,
|
|
SS_Step => SS_Step,
|
|
SS_Single => SS_Single
|
|
);
|
|
|
|
NMI_n_masked <= NMI_n or special(1);
|
|
FIRQ_n_masked <= FIRQ_n or special(1);
|
|
IRQ_n_masked <= IRQ_n or special(0);
|
|
|
|
-- The CPU is slightly pipelined and the register update of the last
|
|
-- instruction overlaps with the opcode fetch of the next instruction.
|
|
--
|
|
-- If the single stepping stopped on the opcode fetch cycle, then the registers
|
|
-- valued would not accurately reflect the previous instruction.
|
|
--
|
|
-- To work around this, when single stepping, we stop on the cycle after
|
|
-- the opcode fetch, which means the program counter has advanced.
|
|
--
|
|
-- To hide this from the user single stepping, all we need to do is to
|
|
-- also pipeline the value of the program counter by one stage to compensate.
|
|
|
|
last_pc_gen : process(cpu_clk)
|
|
begin
|
|
if rising_edge(cpu_clk) then
|
|
if (hold = '0') then
|
|
last_PC <= Regs(95 downto 80);
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
Regs1( 79 downto 0) <= Regs( 79 downto 0);
|
|
Regs1( 95 downto 80) <= last_PC;
|
|
Regs1(111 downto 96) <= Regs(111 downto 96);
|
|
Regs1(255 downto 112) <= (others => '0');
|
|
|
|
GenCPU09Core: if UseCPU09Core generate
|
|
inst_cpu09: entity work.cpu09 port map (
|
|
clk => cpu_clk,
|
|
rst => not nRST_sync,
|
|
vma => AVMA,
|
|
lic_out => LIC_int,
|
|
ifetch => ifetch,
|
|
opfetch => open,
|
|
ba => BA,
|
|
bs => BS,
|
|
addr => Addr_int,
|
|
rw => R_W_n_int,
|
|
data_out => Dout,
|
|
data_in => Din,
|
|
irq => IRQ_sync,
|
|
firq => FIRQ_sync,
|
|
nmi => NMI_sync,
|
|
halt => HALT_sync,
|
|
hold => hold,
|
|
Regs => Regs
|
|
);
|
|
end generate;
|
|
|
|
|
|
-- Synchronize all external inputs, to avoid subtle bugs like missed interrupts
|
|
irq_gen : process(cpu_clk)
|
|
begin
|
|
if falling_edge(cpu_clk) then
|
|
NMI_sync <= not NMI_n_masked;
|
|
IRQ_sync <= not IRQ_n_masked;
|
|
FIRQ_sync <= not FIRQ_n_masked;
|
|
nRST_sync <= RES_n and nRSTout;
|
|
HALT_sync <= not HALT_n;
|
|
end if;
|
|
end process;
|
|
|
|
-- This block generates a sync signal that has the same characteristic as
|
|
-- a 6502 sync, i.e. asserted during the fetching the first byte of each instruction.
|
|
-- The below logic copes ifetch being active for all bytes of the instruction.
|
|
sync_gen : process(cpu_clk)
|
|
begin
|
|
if rising_edge(cpu_clk) then
|
|
if (hold = '0') then
|
|
ifetch1 <= ifetch and not LIC_int;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
Sync_int <= ifetch and not ifetch1;
|
|
|
|
-- This block generates a hold signal that acts as the inverse of a clock enable
|
|
-- for the 6809. See comments above for why this is a cycle later than the way
|
|
-- we would do if for the 6502.
|
|
hold_gen : process(cpu_clk)
|
|
begin
|
|
if rising_edge(cpu_clk) then
|
|
if (Sync_int = '1') then
|
|
-- stop after the opcode has been fetched
|
|
hold <= SS_Single;
|
|
elsif (SS_Step = '1') then
|
|
-- start again when the single step command is issues
|
|
hold <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- Only count cycles when the 6809 is actually running
|
|
CountCycle <= not hold;
|
|
|
|
-- this block delays memory_rd, memory_wr, memory_addr until the start of the next cpu clk cycle
|
|
-- necessary because the cpu mon block is clocked of the opposite edge of the clock
|
|
-- this allows a full cpu clk cycle for cpu mon reads and writes
|
|
mem_gen : process(cpu_clk)
|
|
begin
|
|
if rising_edge(cpu_clk) then
|
|
memory_rd1 <= memory_rd;
|
|
memory_wr1 <= memory_wr;
|
|
memory_addr1 <= memory_addr;
|
|
end if;
|
|
end process;
|
|
|
|
R_W_n <= 'Z' when TSC = '1' else
|
|
'1' when memory_rd1 = '1' else
|
|
'0' when memory_wr1 = '1' else
|
|
R_W_n_int;
|
|
|
|
Addr <= (others => 'Z') when TSC = '1' else
|
|
memory_addr1 when (memory_rd1 = '1' or memory_wr1 = '1') else
|
|
Addr_int;
|
|
|
|
data_latch : process(E)
|
|
begin
|
|
if falling_edge(E) then
|
|
Din <= Data;
|
|
memory_din <= Data;
|
|
end if;
|
|
end process;
|
|
|
|
Data <= memory_dout when TSC = '0' and data_wr = '1' and memory_wr1 = '1' else
|
|
Dout when TSC = '0' and data_wr = '1' and R_W_n_int = '0' and memory_rd1 = '0' else
|
|
(others => 'Z');
|
|
|
|
memory_done <= memory_rd1 or memory_wr1;
|
|
|
|
-- Delayed/Deglitched version of the E clock
|
|
e_gen : process(clock)
|
|
begin
|
|
if rising_edge(clock) then
|
|
E_a <= E;
|
|
E_b <= E_a;
|
|
if E_b /= E_i then
|
|
E_c <= E_b;
|
|
end if;
|
|
E_d <= E_c;
|
|
E_e <= E_d;
|
|
E_f <= E_e;
|
|
E_g <= E_f;
|
|
E_h <= E_g;
|
|
E_i <= E_h;
|
|
end if;
|
|
end process;
|
|
|
|
-- Main clock timing control
|
|
-- E_c is delayed by 40-60ns
|
|
-- On a real 6809 the output delay (to ADDR, RNW, BA, BS) is 65ns (measured)
|
|
cpu_clk <= not E_c;
|
|
busmon_clk <= E_c;
|
|
|
|
-- Data bus write timing control
|
|
--
|
|
-- When data_wr is 0 the bus is high impedence
|
|
--
|
|
-- This avoids bus conflicts when the direction of the data bus
|
|
-- changes from read to write (or visa versa).
|
|
--
|
|
-- Note: on the dragon this is not critical; setting to '1' seemed to work
|
|
data_wr <= Q or E;
|
|
|
|
-- Spare pins used for testing
|
|
test1 <= E_a;
|
|
test2 <= E_c;
|
|
|
|
|
|
end behavioral;
|