mirror of
https://github.com/MiSTer-devel/Arcade-Astrocade_MiSTer.git
synced 2026-05-24 03:01:33 +00:00
292 lines
9.1 KiB
VHDL
292 lines
9.1 KiB
VHDL
--
|
|
-- A simulation model of Bally Astrocade hardware
|
|
--
|
|
-- Pattern board for Arcade - Mike@the-coates.com
|
|
--
|
|
-- Revision list
|
|
--
|
|
-- version 001 initial release
|
|
--
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.std_logic_unsigned.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
|
|
entity BALLY_PATTERN is
|
|
port (
|
|
I_MXA : in std_logic_vector(15 downto 0);
|
|
I_MXD : in std_logic_vector( 7 downto 0);
|
|
|
|
O_MXA : out std_logic_vector(15 downto 0);
|
|
O_MXD : out std_logic_vector( 7 downto 0);
|
|
|
|
-- CPU control signals out
|
|
O_RD_L : out std_logic;
|
|
O_WR_L : out std_logic;
|
|
O_MR_L : out std_logic;
|
|
O_BUSRQ_L : out std_logic;
|
|
|
|
-- cpu control signals in
|
|
I_M1_L : in std_logic;
|
|
I_RD_L : in std_logic;
|
|
I_MREQ_L : in std_logic;
|
|
I_IORQ_L : in std_logic;
|
|
I_RESET_L : in std_logic;
|
|
I_WAIT_L : in std_logic;
|
|
I_BUSACK_L : in std_logic;
|
|
|
|
-- clks
|
|
I_CPU_ENA : in std_logic; -- cpu clock ena
|
|
ENA : in std_logic;
|
|
CLK : in std_logic
|
|
);
|
|
end;
|
|
|
|
architecture RTL of BALLY_PATTERN is
|
|
|
|
-- Signals
|
|
|
|
TYPE P_State_type IS (Suspended, Start, Source, Source_wait, Source_read, Destination, Destination_wait, Increment, Increment_Wait, Repeat, Complete); -- Define the states
|
|
SIGNAL P_State : P_State_type := Suspended;
|
|
signal next_state : P_State_type := Suspended;
|
|
|
|
-- Pattern Registers
|
|
signal p_source : std_logic_vector(15 downto 0);
|
|
signal p_dest : std_logic_vector(15 downto 0);
|
|
signal p_mode : std_logic_vector(5 downto 0);
|
|
signal p_skip : std_logic_vector(7 downto 0);
|
|
signal p_width : std_logic_vector(7 downto 0);
|
|
signal p_height : std_logic_vector(7 downto 0);
|
|
-- Pattern work
|
|
signal p_addr : std_logic_vector(15 downto 0);
|
|
signal p_data : std_logic_vector(7 downto 0);
|
|
signal u13ff : std_logic;
|
|
signal curwidth : std_logic_vector(7 downto 0);
|
|
signal p_temp : std_logic_vector(8 downto 0);
|
|
signal d_count : std_logic_vector(2 downto 0);
|
|
-- Pattern CPU equivalent
|
|
signal p_RD : std_logic := '1';
|
|
signal p_WR : std_logic := '1';
|
|
signal p_MR : std_logic := '1';
|
|
|
|
signal cs_w : std_logic;
|
|
|
|
begin
|
|
|
|
p_chip_sel : process(I_CPU_ENA, I_MXA)
|
|
begin
|
|
cs_w <= '0';
|
|
if (I_CPU_ENA = '1') then -- cpu access
|
|
if (I_MXA(7 downto 3) = "01111") then
|
|
cs_w <= '1';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
--
|
|
-- registers
|
|
--
|
|
pattern_board : process (CLK)
|
|
begin
|
|
if rising_edge(CLK) then
|
|
|
|
-- Register Write
|
|
if (I_RD_L = '1') and (I_IORQ_L = '0') and (I_M1_L = '1') and (cs_w = '1') and (P_State = Suspended) then
|
|
case I_MXA(7 downto 0) is
|
|
-- Pattern board (0x78 - 0x7E)
|
|
when "01111000" => p_source(7 downto 0) <= I_MXD(7 downto 0);
|
|
when "01111001" => p_source(15 downto 8) <= I_MXD(7 downto 0);
|
|
when "01111010" => p_mode(5 downto 0) <= I_MXD(5 downto 0);
|
|
p_dest(7 downto 0) <= "00000000";
|
|
when "01111011" => p_skip(7 downto 0) <= I_MXD(7 downto 0);
|
|
when "01111100" => -- It apparently adds p-skip to p_dest low, but since this write occurs multiple times it causes big problems!
|
|
-- since p_dest seems to always be 0 (set by write to p_mode) then we just take p_skip!
|
|
--p_dest(8 downto 0) <= ('0' & p_dest(7 downto 0)) + ('0' & p_skip(7 downto 0));
|
|
p_dest(7 downto 0) <= p_skip(7 downto 0);
|
|
p_dest(15 downto 8) <= I_MXD(7 downto 0);
|
|
when "01111101" => p_width(7 downto 0) <= I_MXD(7 downto 0);
|
|
when "01111110" => p_height(7 downto 0) <= I_MXD(7 downto 0);
|
|
-- Initialise everything for copy
|
|
if (p_mode(1) = '0') then
|
|
u13ff <= '1';
|
|
else
|
|
u13ff <= '0';
|
|
end if;
|
|
curwidth <= p_width;
|
|
-- And get ready to start copy loop
|
|
next_state <= Start;
|
|
when others => null;
|
|
end case;
|
|
end if;
|
|
|
|
-- Main loop where the copy happens
|
|
|
|
if (I_CPU_ENA = '1') then
|
|
|
|
case p_State is
|
|
|
|
when Start =>
|
|
-- Wait until CPU responds
|
|
if I_BUSACK_L = '0' then
|
|
next_state <= Source;
|
|
end if;
|
|
|
|
when Source =>
|
|
-- address is selected between source/dest based on mode.d0
|
|
if (p_mode(0) = '0') then
|
|
p_addr <= p_source;
|
|
else
|
|
p_addr <= p_dest;
|
|
end if;
|
|
p_WR <= '1';
|
|
p_MR <= '0';
|
|
p_RD <= '0'; -- Read
|
|
next_state <= Source_read; --Source_wait;
|
|
|
|
when Source_read =>
|
|
if (I_WAIT_L='1') then
|
|
-- if mode.d3 is set, then the last byte fetched per row is forced to 0 (address = gorf hack for the moment)
|
|
if ((curwidth = "00000000") and (p_mode(3) = '1')) then -- or (p_addr = x"D12B")) then
|
|
p_data <= "00000000";
|
|
else
|
|
p_data <= I_MXD(7 downto 0);
|
|
end if;
|
|
|
|
p_RD <= '1';
|
|
p_MR <= '1';
|
|
p_WR <= '1';
|
|
|
|
next_state <= Destination;
|
|
end if;
|
|
|
|
when Destination =>
|
|
-- Set destination address
|
|
if (I_WAIT_L='1') then
|
|
if (p_mode(0) = '1') then
|
|
p_addr <= p_source;
|
|
else
|
|
p_addr <= p_dest;
|
|
end if;
|
|
p_WR <= '0';
|
|
next_state <= Destination_wait;
|
|
end if;
|
|
|
|
when Destination_wait =>
|
|
-- Debug - single step!
|
|
--if ((p_source /= x"0776") or (I_FIRE = '1')) then
|
|
p_MR <= '0'; -- set it low
|
|
-- Calculate this now in case needed in increment routine
|
|
p_temp(8 downto 0) <= std_logic_vector(unsigned('0' & p_dest(7 downto 0)) + unsigned('0' & p_skip(7 downto 0)));
|
|
next_state <= Increment;
|
|
--end if;
|
|
|
|
when Increment =>
|
|
-- if the flip-flop at U13 is high and mode.d2 is 1 we can increment source
|
|
-- however, if mode.d3 is set and we're on the last byte of a row, the increment is suppressed
|
|
if ((u13ff='1') and (p_mode(2)='1')) then
|
|
if ((curwidth /= "00000000") or (p_mode(3)='0')) then
|
|
p_source <= p_source + 1;
|
|
end if;
|
|
end if;
|
|
|
|
-- if mode.d1 is 1, toggle the flip-flop; otherwise leave it preset
|
|
if (p_mode(1)='1') then
|
|
u13ff <= not u13ff;
|
|
end if;
|
|
|
|
-- destination increment is suppressed for the last byte in a row
|
|
if (curwidth = "00000000") then
|
|
-- at the end of each row, the skip value is added to the dest value
|
|
-- p_temp(8 downto 0) <= std_logic_vector(unsigned('0' & p_dest(7 downto 0)) + unsigned('0' & p_skip(7 downto 0)));
|
|
p_dest(7 downto 0) <= p_temp(7 downto 0);
|
|
-- carry behavior into the top byte is controlled by mode.d4
|
|
if p_mode(4)='0' then
|
|
if (p_temp(8)='1') then
|
|
p_dest(15 downto 8) <= p_dest(15 downto 8) + 1;
|
|
end if;
|
|
else
|
|
if (p_temp(8)='0') then
|
|
p_dest(15 downto 8) <= p_dest(15 downto 8) - 1;
|
|
end if;
|
|
end if;
|
|
else
|
|
-- if mode.d5 is 1, we increment
|
|
if p_mode(5)='1' then
|
|
p_dest <= p_dest + 1;
|
|
else
|
|
p_dest <= p_dest - 1;
|
|
end if;
|
|
end if;
|
|
|
|
next_state <= Increment_Wait;
|
|
|
|
-- Delay between write address and next byte copy
|
|
when Increment_Wait =>
|
|
if (I_WAIT_L='1') then
|
|
next_state <= Repeat;
|
|
end if;
|
|
|
|
when Repeat =>
|
|
-- Debug - single step!
|
|
--if ((p_source /= x"0776") or (I_FIRE = '0')) then
|
|
if ((p_height="00000000") and (curwidth="00000000")) then
|
|
-- Finished!
|
|
p_RD <= '1';
|
|
p_WR <= '1';
|
|
p_MR <= '1';
|
|
-- Clear pattern address and data
|
|
p_data <= "00000000";
|
|
p_addr <= "0000000000000000";
|
|
next_state <= Complete;
|
|
else
|
|
if (curwidth /= "00000000") then
|
|
curwidth <= curwidth - 1;
|
|
else
|
|
if (p_height /= "00000000") then
|
|
curwidth <= p_width;
|
|
p_height <= p_height - 1;
|
|
end if;
|
|
end if;
|
|
|
|
next_state <= Source;
|
|
end if;
|
|
|
|
--end if;
|
|
|
|
when Complete =>
|
|
-- Wait until CPU restarts
|
|
if I_BUSACK_L = '1' then
|
|
next_state <= Suspended;
|
|
end if;
|
|
|
|
when others => null;
|
|
|
|
end case;
|
|
|
|
end if;
|
|
|
|
if (I_RESET_L = '0') then
|
|
p_State <= Suspended;
|
|
next_state <= Suspended;
|
|
else
|
|
p_State <= next_state;
|
|
end if;
|
|
|
|
end if; -- rising edge CLK
|
|
|
|
end process;
|
|
|
|
-- Our interface with the outside world
|
|
O_MXA <= p_addr;
|
|
O_MXD <= p_data;
|
|
O_RD_L <= p_RD;
|
|
O_WR_L <= p_WR;
|
|
O_MR_L <= p_MR;
|
|
|
|
-- Run Z80 normally until Pattern board is active
|
|
O_BUSRQ_L <= '1' when (P_State = Suspended or P_State = Complete) else '0';
|
|
|
|
end architecture RTL;
|
|
|