2014-05-16 18:28:35 +00:00
-- Copyright: Matthias Heinrichs 2014
-- Free for non-comercial use
-- No warranty just for fun
-- I you want to earn money with this code, ask me first!
2014-05-15 19:16:29 +00:00
library ieee ;
use ieee.std_logic_1164. all ;
use ieee.std_logic_arith. all ;
use ieee.std_logic_unsigned. all ;
entity BUS68030 is
port (
AS_030 : inout std_logic ;
AS_000 : inout std_logic ;
DS_030 : inout std_logic ;
UDS_000 : inout std_logic ;
LDS_000 : inout std_logic ;
SIZE : inout std_logic_vector ( 1 downto 0 ) ;
A : inout std_logic_vector ( 31 downto 0 ) ;
2014-05-16 18:18:55 +00:00
nEXP_SPACE : in std_logic ;
2014-05-15 21:05:08 +00:00
BERR : inout std_logic ;
2014-05-15 19:16:29 +00:00
BG_030 : in std_logic ;
BG_000 : out std_logic ;
BGACK_030 : out std_logic ;
BGACK_000 : in std_logic ;
CLK_030 : in std_logic ;
CLK_000 : in std_logic ;
CLK_OSZI : in std_logic ;
CLK_DIV_OUT : out std_logic ;
CLK_EXP : out std_logic ;
FPU_CS : out std_logic ;
IPL_030 : out std_logic_vector ( 2 downto 0 ) ;
IPL : in std_logic_vector ( 2 downto 0 ) ;
DSACK : inout std_logic_vector ( 1 downto 0 ) ;
DTACK : inout std_logic ;
AVEC : out std_logic ;
AVEC_EXP : inout std_logic ; --this is a "free pin"
E : out std_logic ;
VPA : in std_logic ;
VMA : out std_logic ;
RST : in std_logic ;
RESET : out std_logic ;
RW : in std_logic ;
-- D: inout std_logic_vector ( 31 downto 28 );
FC : in std_logic_vector ( 1 downto 0 ) ;
AMIGA_BUS_ENABLE : out std_logic ;
AMIGA_BUS_DATA_DIR : out std_logic ;
AMIGA_BUS_ENABLE_LOW : out std_logic ;
CIIN : out std_logic
) ;
end BUS68030 ;
architecture Behavioral of BUS68030 is
subtype ESTATE is std_logic_vector ( 3 downto 0 ) ;
constant E1 : ESTATE : = "0110" ;
constant E2 : ESTATE : = "0111" ;
constant E3 : ESTATE : = "0100" ;
constant E4 : ESTATE : = "0101" ;
constant E5 : ESTATE : = "0010" ;
constant E6 : ESTATE : = "0011" ;
constant E7 : ESTATE : = "1010" ;
constant E8 : ESTATE : = "1011" ;
constant E9 : ESTATE : = "1100" ;
constant E10 : ESTATE : = "1111" ;
-- Illegal states
constant E20 : ESTATE : = "0000" ;
constant E4a : ESTATE : = "0001" ;
constant E21 : ESTATE : = "1000" ;
constant E22 : ESTATE : = "1001" ;
constant E23 : ESTATE : = "1101" ;
constant E24 : ESTATE : = "1110" ;
signal cpu_est : ESTATE : = E20 ;
signal cpu_est_d : ESTATE : = E20 ;
subtype AMIGA_STATE is std_logic_vector ( 2 downto 0 ) ;
constant IDLE_P : AMIGA_STATE : = "000" ;
constant IDLE_N : AMIGA_STATE : = "001" ;
constant AS_SET_P : AMIGA_STATE : = "010" ;
constant AS_SET_N : AMIGA_STATE : = "011" ;
constant SAMPLE_DTACK_P : AMIGA_STATE : = "100" ;
constant DATA_FETCH_N : AMIGA_STATE : = "101" ;
constant DATA_FETCH_P : AMIGA_STATE : = "110" ;
constant END_CYCLE_N : AMIGA_STATE : = "111" ;
signal SM_AMIGA : AMIGA_STATE : = IDLE_P ;
--signal Dout:STD_LOGIC_VECTOR(3 downto 0) := "0000";
signal AS_000_INT : STD_LOGIC : = '1' ;
signal AS_030_000_SYNC : STD_LOGIC : = '1' ;
signal BGACK_030_INT : STD_LOGIC : = '1' ;
signal DTACK_SYNC : STD_LOGIC : = '1' ;
signal DTACK_DMA : STD_LOGIC : = '1' ;
signal FPU_CS_INT : STD_LOGIC : = '1' ;
signal VPA_D : STD_LOGIC : = '1' ;
signal VPA_SYNC : STD_LOGIC : = '1' ;
signal VMA_INT : STD_LOGIC : = '1' ;
signal UDS_000_INT : STD_LOGIC : = '1' ;
signal LDS_000_INT : STD_LOGIC : = '1' ;
signal DSACK_INT : STD_LOGIC_VECTOR ( 1 downto 0 ) : = "11" ;
2014-05-24 14:03:26 +00:00
signal CLK_CNT_P : STD_LOGIC_VECTOR ( 1 downto 0 ) : = "00" ;
signal CLK_CNT_N : STD_LOGIC_VECTOR ( 1 downto 0 ) : = "00" ;
2014-05-15 19:16:29 +00:00
signal CLK_REF : STD_LOGIC_VECTOR ( 1 downto 0 ) : = "10" ;
signal CLK_OUT_PRE : STD_LOGIC : = '1' ;
signal CLK_OUT_INT : STD_LOGIC : = '1' ;
signal CLK_030_D : STD_LOGIC : = '1' ;
2014-05-16 18:18:55 +00:00
signal CLK_000_D0 : STD_LOGIC : = '1' ;
signal CLK_000_D1 : STD_LOGIC : = '1' ;
signal CLK_000_D2 : STD_LOGIC : = '1' ;
signal CLK_000_D3 : STD_LOGIC : = '1' ;
signal CLK_000_D4 : STD_LOGIC : = '1' ;
signal CLK_000_D5 : STD_LOGIC : = '1' ;
2014-05-24 13:17:08 +00:00
signal CLK_000_D6 : STD_LOGIC : = '1' ;
2014-05-15 19:16:29 +00:00
begin
--the clocks
2014-05-24 14:03:26 +00:00
neg_clk : process ( RST , CLK_OSZI )
begin
if ( RST = '0' ) then
CLK_CNT_N < = "00" ;
elsif ( falling_edge ( CLK_OSZI ) ) then
--clk generation : up to now just half the clock
if ( CLK_CNT_N = "10" ) then
--CLK_OUT_PRE <= not CLK_OUT_PRE;
CLK_CNT_N < = "00" ;
else
CLK_CNT_N < = CLK_CNT_N + 1 ;
end if ;
end if ;
end process neg_clk ;
--the clocks
clk : process ( RST , CLK_OSZI )
2014-05-15 19:16:29 +00:00
begin
2014-05-24 14:03:26 +00:00
if ( RST = '0' ) then
CLK_CNT_P < = "00" ;
RESET < = '0' ;
CLK_OUT_PRE < = '0' ;
CLK_OUT_INT < = '0' ;
cpu_est < = E20 ;
cpu_est_d < = E20 ;
VPA_D < = '1' ;
CLK_000_D0 < = '1' ;
CLK_000_D1 < = '1' ;
CLK_000_D2 < = '1' ;
CLK_000_D3 < = '1' ;
CLK_000_D4 < = '1' ;
CLK_000_D5 < = '1' ;
CLK_000_D6 < = '1' ;
elsif ( rising_edge ( CLK_OSZI ) ) then
2014-05-15 19:16:29 +00:00
--reset buffer
2014-05-24 14:03:26 +00:00
RESET < = '1' ;
2014-05-15 19:16:29 +00:00
--clk generation : up to now just half the clock
2014-05-24 14:03:26 +00:00
if ( CLK_CNT_P = "10" ) then
--CLK_OUT_PRE <= not CLK_OUT_PRE;
CLK_CNT_P < = "00" ;
2014-05-15 19:16:29 +00:00
else
2014-05-24 14:03:26 +00:00
CLK_CNT_P < = CLK_CNT_P + 1 ;
end if ;
if ( CLK_CNT_P = "00" or CLK_CNT_N = "00" ) then --33MHz Clock
CLK_OUT_PRE < = '0' ;
else
CLK_OUT_PRE < = '1' ;
2014-05-15 19:16:29 +00:00
end if ;
-- the external clock to the processor is generated here
CLK_OUT_INT < = CLK_OUT_PRE ; --this way we know the clock of the next state: Its like looking in the future, cool!
--delayed Clocks for edge detection
2014-05-16 18:18:55 +00:00
CLK_000_D0 < = CLK_000 ;
CLK_000_D1 < = CLK_000_D0 ;
CLK_000_D2 < = CLK_000_D1 ;
CLK_000_D3 < = CLK_000_D2 ;
CLK_000_D4 < = CLK_000_D3 ;
CLK_000_D5 < = CLK_000_D4 ;
2014-05-24 13:17:08 +00:00
CLK_000_D6 < = CLK_000_D5 ;
2014-05-15 19:16:29 +00:00
-- e-clock
2014-05-16 18:18:55 +00:00
if ( CLK_000_D1 = '0' and CLK_000_D0 = '1' ) then
2014-05-15 19:16:29 +00:00
case ( cpu_est ) is
when E1 = > cpu_est < = E2 ;
when E2 = > cpu_est < = E3 ;
when E3 = > cpu_est < = E4 ;
when E4 = > cpu_est < = E5 ;
when E5 = > cpu_est < = E6 ;
when E6 = > cpu_est < = E7 ;
when E7 = > cpu_est < = E8 ;
when E8 = > cpu_est < = E9 ;
when E9 = > cpu_est < = E10 ;
when E10 = > cpu_est < = E1 ;
-- Illegal states
when E4a = > cpu_est < = E5 ;
when E20 = > cpu_est < = E10 ;
when E21 = > cpu_est < = E10 ;
when E22 = > cpu_est < = E9 ;
when E23 = > cpu_est < = E9 ;
when E24 = > cpu_est < = E10 ;
when others = >
null ;
end case ;
end if ;
cpu_est_d < = cpu_est ;
VPA_D < = VPA ;
end if ;
end process clk ;
--the state process
state_machine : process ( RST , CLK_OSZI )
begin
if ( RST = '0' ) then
2014-05-19 05:35:45 +00:00
SM_AMIGA < = IDLE_P ;
AS_000_INT < = '1' ;
AS_030_000_SYNC < = '1' ;
UDS_000_INT < = '1' ;
LDS_000_INT < = '1' ;
2014-05-24 13:17:08 +00:00
CLK_REF < = "00" ;
2014-05-19 05:35:45 +00:00
VMA_INT < = '1' ;
FPU_CS_INT < = '1' ;
BG_000 < = '1' ;
2014-05-15 19:16:29 +00:00
BGACK_030_INT < = '1' ;
2014-05-19 05:35:45 +00:00
DSACK_INT < = "11" ;
DTACK_DMA < = '1' ;
DTACK_SYNC < = '1' ;
VPA_SYNC < = '1' ;
IPL_030 < = "111" ;
2014-05-15 19:16:29 +00:00
elsif ( rising_edge ( CLK_OSZI ) ) then
--bgack is simple: assert as soon as Amiga asserts but hold bg_ack for one amiga-clock
if ( BGACK_000 = '0' ) then
BGACK_030_INT < = '0' ;
2014-05-16 18:18:55 +00:00
elsif ( BGACK_000 = '1' AND CLK_000_D1 = '0' and CLK_000_D0 = '1' ) then -- BGACK_000 is high here!
2014-05-15 19:16:29 +00:00
BGACK_030_INT < = '1' ; --hold this signal high until 7m clock goes high
end if ;
--bus grant only in idle state
if ( BG_030 = '1' ) then
BG_000 < = '1' ;
2014-05-24 14:03:26 +00:00
elsif ( BG_030 = '0' AND ( SM_AMIGA = IDLE_P )
and nEXP_SPACE = '0' and AS_030 = '1'
and CLK_000_D0 = '1' AND CLK_000_D1 = '0' ) then --bus granted no local access and no AS_030 running!
2014-05-15 19:16:29 +00:00
BG_000 < = '0' ;
2014-05-24 14:03:26 +00:00
else
BG_000 < = '1' ;
2014-05-15 19:16:29 +00:00
end if ;
2014-05-15 21:05:08 +00:00
2014-05-15 19:16:29 +00:00
--interrupt buffering to avoid ghost interrupts
2014-05-16 18:18:55 +00:00
if ( CLK_000_D1 = '0' and CLK_000_D0 = '1' ) then
2014-05-15 19:16:29 +00:00
IPL_030 < = IPL ;
end if ;
-- as030-sampling and FPU-Select
2014-05-15 21:05:08 +00:00
if ( AS_030 = '1' ) then -- "async" reset of various signals
2014-05-15 19:16:29 +00:00
AS_030_000_SYNC < = '1' ;
FPU_CS_INT < = '1' ;
2014-05-19 05:35:45 +00:00
DSACK_INT < = "11" ;
AS_000_INT < = '1' ;
UDS_000_INT < = '1' ;
LDS_000_INT < = '1' ;
DTACK_SYNC < = '1' ;
VPA_SYNC < = '1' ;
AMIGA_BUS_ENABLE < = '1' ;
2014-05-15 19:16:29 +00:00
elsif ( CLK_030 = '1' AND --68030 has a valid AS on high clocks
AS_030 = '0' ) then
if ( FC ( 1 ) = '1' and FC ( 0 ) = '1' and A ( 19 ) = '0' and A ( 18 ) = '0' and A ( 17 ) = '1' and A ( 16 ) = '0' AND BGACK_000 = '1' ) then
FPU_CS_INT < = '0' ;
else
2014-05-24 13:17:08 +00:00
if ( nEXP_SPACE = '1' and SM_AMIGA = IDLE_P ) then
2014-05-16 18:18:55 +00:00
AS_030_000_SYNC < = '0' ;
end if ;
2014-05-15 19:16:29 +00:00
end if ;
end if ;
-- VMA generation
2014-05-16 18:18:55 +00:00
if ( CLK_000_D0 = '0' AND VPA_D = '0' AND cpu_est = E4 ) then --assert
2014-05-15 19:16:29 +00:00
VMA_INT < = '0' ;
2014-05-16 18:18:55 +00:00
elsif ( CLK_000_D0 = '1' AND AS_000_INT = '1' AND cpu_est = E1 ) then --deassert
2014-05-15 19:16:29 +00:00
VMA_INT < = '1' ;
end if ;
--Amiga statemachine
case ( SM_AMIGA ) is
when IDLE_P = > --68000:S0 wait for a falling edge
2014-05-24 13:17:08 +00:00
if ( CLK_000_D2 = '0' and CLK_000_D3 = '1' and AS_030_000_SYNC = '0' ) then
SM_AMIGA < = IDLE_N ; --go to s1
2014-05-15 19:16:29 +00:00
end if ;
2014-05-24 13:17:08 +00:00
when IDLE_N = > --68000:S1 place Adress on bus and wait for rising edge, on a rising CLK_000 look for a amiga adressrobe
if ( nEXP_SPACE = '1' ) then
2014-05-19 05:35:45 +00:00
AMIGA_BUS_ENABLE < = '0' ; --for now: allways on for amiga
2014-05-24 13:17:08 +00:00
else -- if this a delayed expansion space detection, aboard this cycle!
2014-05-19 05:35:45 +00:00
AMIGA_BUS_ENABLE < = '1' ;
2014-05-24 13:17:08 +00:00
AS_030_000_SYNC < = '1' ;
SM_AMIGA < = IDLE_P ; --aboard
2014-05-19 05:35:45 +00:00
end if ;
2014-05-24 13:17:08 +00:00
if ( CLK_000_D0 = '1' ) then --go to s2
SM_AMIGA < = AS_SET_P ; --as for amiga set!
2014-05-15 19:16:29 +00:00
end if ;
when AS_SET_P = > --68000:S2 Amiga cycle starts here: since AS is asserted during transition to this state we simply wait here
2014-05-24 13:17:08 +00:00
AS_000_INT < = '0' ;
if ( RW = '1' and DS_030 = '0' ) then --read: set udl/lds
if ( A ( 0 ) = '0' ) then
UDS_000_INT < = '0' ;
else
UDS_000_INT < = '1' ;
end if ;
if ( ( A ( 0 ) = '1' OR SIZE ( 0 ) = '0' OR SIZE ( 1 ) = '1' ) ) then
LDS_000_INT < = '0' ;
else
LDS_000_INT < = '1' ;
end if ;
end if ;
if ( CLK_000_D0 = '0' ) then --go to s3
SM_AMIGA < = AS_SET_N ;
2014-05-15 19:16:29 +00:00
end if ;
when AS_SET_N = > --68000:S3: nothing happens here; on a transition to s4: assert uds/lds on write
2014-05-19 05:35:45 +00:00
if ( RW = '0' and DS_030 = '0' ) then --write: set udl/lds earlier than in the specs. this does not seem to harm anything and is saver, than sampling uds/lds too late
if ( A ( 0 ) = '0' ) then
UDS_000_INT < = '0' ;
else
UDS_000_INT < = '1' ;
end if ;
if ( ( A ( 0 ) = '1' OR SIZE ( 0 ) = '0' OR SIZE ( 1 ) = '1' ) ) then
LDS_000_INT < = '0' ;
else
LDS_000_INT < = '1' ;
2014-05-15 19:16:29 +00:00
end if ;
2014-05-19 05:35:45 +00:00
end if ;
2014-05-24 13:17:08 +00:00
if ( CLK_000_D0 = '1' ) then --go to s4
SM_AMIGA < = SAMPLE_DTACK_P ;
2014-05-15 19:16:29 +00:00
end if ;
when SAMPLE_DTACK_P = > --68000:S4 wait for dtack or VMA
2014-05-24 13:17:08 +00:00
if ( CLK_000_D0 = '0' ) then --go to s5
2014-05-15 19:16:29 +00:00
if ( DTACK_SYNC = '0' OR VPA_SYNC = '0' ) then
SM_AMIGA < = DATA_FETCH_N ;
end if ;
2014-05-24 13:17:08 +00:00
elsif ( CLK_000_D0 = '1' ) then -- high clock: sample DTACK
2014-05-15 19:16:29 +00:00
if ( VPA_D = '1' AND DTACK = '0' ) then
DTACK_SYNC < = '0' ;
2014-05-15 20:19:03 +00:00
elsif ( VPA_D = '0' AND cpu_est = E9 AND VMA_INT = '0' ) then --vpa/vma cycle: sync VPA on E9: one 7M-clock to latch!
2014-05-15 21:05:08 +00:00
VPA_SYNC < = '0' ;
2014-05-15 19:16:29 +00:00
end if ;
end if ;
when DATA_FETCH_N = > --68000:S5 nothing happens here just wait for positive clock
2014-05-24 13:17:08 +00:00
if ( CLK_000_D0 = '1' ) then --go to s6
2014-05-15 19:16:29 +00:00
SM_AMIGA < = DATA_FETCH_P ;
end if ;
when DATA_FETCH_P = > --68000:S6: READ: here comes the data on the bus!
2014-05-24 13:17:08 +00:00
if ( CLK_000_D4 = '1' AND CLK_000_D5 = '0' ) then --go to s7 next 030-clock is high: dsack is sampled at the falling edge
2014-05-15 20:19:03 +00:00
DSACK_INT < = "01" ;
2014-05-24 13:17:08 +00:00
AS_030_000_SYNC < = '1' ; --cycle end
elsif ( CLK_000_D0 = '0' ) then --go to s7 next 030-clock is high: dsack is sampled at the falling edge
--DSACK_INT<="01";
2014-05-15 20:19:03 +00:00
SM_AMIGA < = END_CYCLE_N ;
2014-05-24 13:17:08 +00:00
--AS_030_000_SYNC <= '1'; --cycle end
2014-05-15 19:16:29 +00:00
end if ;
2014-05-24 13:17:08 +00:00
when END_CYCLE_N = > --68000:S7: Latch/Store data. Wait here for new cycle and go to IDLE on high clock
if ( CLK_000_D0 = '1' and AS_000_INT = '1' ) then --go to s0
2014-05-15 19:16:29 +00:00
SM_AMIGA < = IDLE_P ;
end if ;
end case ;
2014-05-15 21:05:08 +00:00
2014-05-15 19:16:29 +00:00
--dma stuff
--DTACK for DMA cycles
if ( AS_000_INT = '0' AND DSACK ( 1 ) = '0' ) then
DTACK_DMA < = '0' ;
else
DTACK_DMA < = '1' ;
end if ;
end if ;
end process state_machine ;
--output clock assignment
CLK_DIV_OUT < = CLK_OUT_INT ;
2014-05-15 20:51:43 +00:00
CLK_EXP < = CLK_OUT_INT ;
2014-05-15 19:16:29 +00:00
AVEC_EXP < = 'Z' when FPU_CS_INT = '1' else '0' ;
--dtack for dma
DTACK < = 'Z' when BGACK_030_INT = '1' else
DTACK_DMA ;
--fpu
FPU_CS < = FPU_CS_INT ;
--if no copro is installed:
BERR < = 'Z' when FPU_CS_INT = '1' else '0' ;
--cache inhibit: For now: disable
CIIN < = '1' WHEN A ( 31 downto 20 ) = x"00F" ELSE
--'1' WHEN A(31 downto 16) = x"00E0" ELSE
'Z' WHEN not ( A ( 31 downto 24 ) = x"00" ) ELSE
'0' ;
--bus buffers
AMIGA_BUS_DATA_DIR < = '1' WHEN RW = '0' ELSE '0' ;
AMIGA_BUS_ENABLE_LOW < = '1' ; --for now: allways off
--e and VMA
E < = cpu_est ( 3 ) ;
VMA < = VMA_INT ;
--AVEC
AVEC < = '1' ;
--as and uds/lds
2014-05-24 14:03:26 +00:00
AS_000 < = 'Z' when BGACK_030_INT = '0' else
2014-05-15 19:16:29 +00:00
AS_000_INT ;
UDS_000 < = 'Z' when BGACK_030_INT = '0' else -- output on cpu cycle
UDS_000_INT ;
LDS_000 < = 'Z' when BGACK_030_INT = '0' else -- output on cpu cycle
LDS_000_INT ;
--dsack
2014-05-16 18:18:55 +00:00
DSACK < = "ZZ" when nEXP_SPACE = '0' else -- output on amiga cycle
2014-05-15 19:16:29 +00:00
DSACK_INT ;
BGACK_030 < = BGACK_030_INT ;
-- signal assignment
--DS_030 <= "ZZ";
--DS_030 <= "ZZ" when BGACK_030_INT ='1' else -- output on dma cycle
-- DS_030_INT;
--A(1) <= 'Z';
--A(0) <= 'Z';
--A[1 downto 0] <= "ZZ" when BGACK_030_INT ='1' else -- output on dma cycle
-- A_INT;
--SIZE <= "ZZ";
--SIZE <= "ZZ" when BGACK_030_INT ='1' else -- output on dma cycle
-- SIZE_INT;
end Behavioral ;