Project

General

Profile

-- -----------------------------------------------------------------------
--
-- Turbo Chameleon
--
-- Multi purpose FPGA expansion for the Commodore 64 computer
--
-- -----------------------------------------------------------------------
-- Copyright 2005-2013 by Peter Wendrich (pwsoft@syntiac.com)
-- http://www.syntiac.com
--
-- This source file is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Lesser General Public License as published
-- by the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This source file is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- -----------------------------------------------------------------------
--
-- For better understanding what this entity does in detail, please refer
-- to the Chameleon core-developers manual. It has documentation about
-- the CPLD MUX, signal timing, docking-station protocol and the cartridge port access.
--
-- Chameleon timing and I/O driver. Handles all the timing and multiplexing
-- details of the cartridge port and the CPLD mux.
-- - Detects the type of mode the chameleon is running in.
-- - Multiplexes the PS/2 keyboard and mouse signals.
-- - Gives access to joysticks and keyboard on a C64 in cartridge mode.
-- - Gives access to joysticks and keyboard on a docking-station
-- - Gives access to MMC card and serial-flash through the CPLD MUX.
-- - Drives the two LEDs on the Chameleon (or an optional Amiga keyboard).
-- - Can optionally give access to the IEC bus
-- - Can optionally give access to other C64 resources like the SID.
--
-- -----------------------------------------------------------------------
-- enable_docking_station - Enable support for the docking-station.
-- enable_c64_joykeyb - Automatically read joystick and keyboard on the C64 bus.
-- Take note this disables the C64 bus access feature on this entity.
-- enable_c64_4player - Enable 4player support on the user-port of the C64.
-- The flag enable_c64_joykeyb must be true for this to work.
-- enable_raw_spi - SPI controller inside this entity is switched off.
-- And the actual SPI lines are exposed. The maximum speed is limited
-- as the signals are time multiplexed. The maximum spi speed usable
-- is around 1/12 of clk. (One line transition each 6 clk cycles)
-- enable_iec_access - Enables support for the IEC bus on the break-out cable.
-- Set this to 'false' when the IEC bus is not used to save some logic.
-- -----------------------------------------------------------------------
-- clk - system clock
-- ena_1mhz - Enable must be '1' one clk cycle each 1 Mhz.
-- reset - Perform a reset of the subsystems
-- reset_ext - Hardware reset from the cartridge-port (eg. a C64 reset button)
--
-- no_clock - '0' when connected to C64 cartridge port.
-- '1' when in standalone mode or docking-station connected.
-- docking_station - '0' standalone/cartrdige mode
-- '1' when docking-station is connected.
--
-- to_usb_rx
--
-- The following timing signals are only useful when writing C64 related designs.
-- They can be left unconnected in all other FPGA designs.
-- phi_mode - Selects timing in standalone mode ('0' is PAL, '1' is NTSC).
-- phi_out - Regenerated or synthesized phi2 clock.
-- phi_cnt - Counting the system-clock cycles within one phi2 cycle.
-- phi_end_0 - The half of the cycle where phi_out is low ends.
-- phi_end_1 - The half of the cycle where phi_out is high ends.
-- phi_post_1 - Triggers when phi changes
-- phi_post_2 - Triggers one cycle after phi changed
-- phi_post_3 - Triggers two cycles phi changed
-- phi_post_4 - Triggers three cycles phi changed
--
-- c64_irq_n - Status of the C64 IRQ line (cartridge mode only)
-- c64_nmi_n - Status of the C64 NMI line
-- c64_ba - status of the C64 BA line
--
-- The following signals should be synchronised to the phi_out signal
-- c64_vic - When set data on c64_d is send to the VIC-II chip.
-- c64_cs - When set it accesses the C64 databus (uses Ultimax mode, no memory is mapped)
-- c64_cs_roms - Enables access to the C64 Kernal and Basic ROMs (disables Ultimax mode)
-- c64_clockport - When set it accesses the clockport.
-- c64_we - Access is a write when set (note polarity is the inverse of R/W on cartridge port)
-- c64_a - C64 address bus
-- c64_d - Data to the C64
-- c64_q - Data from the C64 (only valid when phi_end_1 is set)
--
-- spi_speed - 0 SPI bus runs at slow speed (250 Kbit), SPI bus runs at fast speed (8 Mbit)
-- spi_req - Toggle to request SPI transfer.
-- spi_ack - Is made equal to spi_req after transfer is complete.
-- spi_d - Data input into SPI controller.
-- spi_q - Data output from SPI controller.
--
-- led_green - Control the green LED (0 off, 1 on). Also power LED on Amiga keyboard.
-- led_red - Control the red LED (0 off, 1 on). Also drive LED on Amiga keyboard.
-- ir - ir signal. Input for the chameleon_cdtv_remote entity.
--
-- ps2_* - PS2 signals for both keyboard and mouse.
-- button_reset_n - Status of blue reset button (right button) on the Chameleon. Low active.
-- joystick* - Joystick ports of both docking-station and C64. Bits: fire2, fire1, right, left, down, up
-- The C64 only supports one button fire1. The signals are low active
-- keys - C64 keyboard. One bit for each key on the keyboard. Low active.
-- restore_key_n - Trigger for restore key on docking-station.
-- On a C64 the restore key is wired to the NMI line instead.
-- iec_* - IEC signals. Only valid when enable_iec_access is set to true.
-- -----------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;

-- -----------------------------------------------------------------------

entity chameleon_io is
generic (
enable_docking_station : boolean := true;
enable_c64_joykeyb : boolean := false;
enable_c64_4player : boolean := false;
enable_raw_spi : boolean := false;
enable_iec_access : boolean := false
);
port (
-- Clocks
clk : in std_logic;
clk_mux : in std_logic;
ena_1mhz : in std_logic;
reset : in std_logic;
reset_ext : out std_logic;

-- Config
no_clock : out std_logic;
docking_station : out std_logic;

-- Chameleon FPGA pins
-- C64 Clocks
phi2_n : in std_logic;
dotclock_n : in std_logic;
-- C64 cartridge control lines
io_ef_n : in std_logic;
rom_lh_n : in std_logic;
-- SPI bus
spi_miso : in std_logic;
-- CPLD multiplexer
mux_clk : out std_logic;
mux : out unsigned(3 downto 0);
mux_d : out unsigned(3 downto 0);
mux_q : in unsigned(3 downto 0);

-- USB microcontroller (To RX of micro)
to_usb_rx : in std_logic := '1';

-- C64 timing (only for C64 related cores)
phi_mode : in std_logic := '0';
phi_out : out std_logic;
phi_cnt : out unsigned(7 downto 0);
phi_end_0 : out std_logic;
phi_end_1 : out std_logic;
phi_post_1 : out std_logic;
phi_post_2 : out std_logic;
phi_post_3 : out std_logic;
phi_post_4 : out std_logic;

-- C64 bus
c64_irq_n : out std_logic;
c64_nmi_n : out std_logic;
c64_ba : out std_logic;

c64_vic : in std_logic := '0';
c64_cs : in std_logic := '0';
c64_cs_roms : in std_logic := '0';
c64_clockport : in std_logic := '0';
c64_we : in std_logic := '0';
c64_a : in unsigned(15 downto 0) := (others => '0');
c64_d : in unsigned(7 downto 0) := (others => '1');
c64_q : out unsigned(7 downto 0);

-- SPI chip-selects
mmc_cs_n : in std_logic := '1';
flash_cs_n : in std_logic := '1';
rtc_cs : in std_logic := '0';

-- SPI controller (enable_raw_spi must be set to false)
spi_speed : in std_logic := '1';
spi_req : in std_logic := '0';
spi_ack : out std_logic;
spi_d : in unsigned(7 downto 0) := (others => '-');
spi_q : out unsigned(7 downto 0);

-- SPI raw signals (enable_raw_spi must be set to true)
spi_raw_clk : in std_logic := '1';
spi_raw_mosi : in std_logic := '1';
spi_raw_ack : out std_logic; -- Added by AMR
-- LEDs
led_green : in std_logic := '0';
led_red : in std_logic := '0';
ir : out std_logic;

-- PS/2 Keyboard
ps2_keyboard_clk_out: in std_logic := '1';
ps2_keyboard_dat_out: in std_logic := '1';
ps2_keyboard_clk_in: out std_logic;
ps2_keyboard_dat_in: out std_logic;

-- PS/2 Mouse
ps2_mouse_clk_out: in std_logic := '1';
ps2_mouse_dat_out: in std_logic := '1';
ps2_mouse_clk_in: out std_logic;
ps2_mouse_dat_in: out std_logic;

-- Buttons
button_reset_n : out std_logic;
-- Joysticks
joystick1 : out unsigned(5 downto 0);
joystick2 : out unsigned(5 downto 0);
joystick3 : out unsigned(5 downto 0);
joystick4 : out unsigned(5 downto 0);

-- Keyboards
-- 0 = col0, row0
-- 1 = col1, row0
-- 8 = col0, row1
-- 63 = col7, row7
keys : out unsigned(63 downto 0);
restore_key_n : out std_logic;
amiga_reset_n : out std_logic;
amiga_trigger : out std_logic;
amiga_scancode : out unsigned(7 downto 0);

-- IEC bus
iec_clk_out : in std_logic := '1';
iec_dat_out : in std_logic := '1';
iec_atn_out : in std_logic := '1';
iec_srq_out : in std_logic := '1';
iec_clk_in : out std_logic;
iec_dat_in : out std_logic;
iec_atn_in : out std_logic;
iec_srq_in : out std_logic
);
end entity;
-- -----------------------------------------------------------------------

architecture rtl of chameleon_io is
-- Clocks
signal no_clock_loc : std_logic;
signal phi : std_logic;
signal end_of_phi_0 : std_logic;
signal end_of_phi_1 : std_logic;
-- State
signal reset_pending : std_logic := '0';
signal reset_in : std_logic := '0';

-- MUX
type muxstate_t is (
-- Reset phase
MUX_RESET,
-- MMC
MUX_MMC0L, MUX_MMC0H, MUX_MMC1L, MUX_MMC1H, MUX_MMC2L, MUX_MMC2H, MUX_MMC3L, MUX_MMC3H,
MUX_MMC4L, MUX_MMC4H, MUX_MMC5L, MUX_MMC5H, MUX_MMC6L, MUX_MMC6H, MUX_MMC7L, MUX_MMC7H,
-- IEC
MUX_IEC1, MUX_IEC2, MUX_IEC3, MUX_IEC4,
-- PS2
MUX_PS2,
-- LED
MUX_LED,
-- PHI=0
MUX_WAIT0,
MUX_A3_C, MUX_BUSVIC,
MUX_D0VIC, MUX_D1VIC,
MUX_NMIIRQ1, MUX_NMIIRQ2,
MUX_ULTIMAX,
MUX_END0,
-- PHI=1
MUX_WAIT1,
MUX_BUS, MUX_CLKPORT,
MUX_A0, MUX_A1, MUX_A2, MUX_A3,
MUX_D0WR, MUX_D1WR, MUX_D0WR_1, MUX_D1WR_1, MUX_D0WR_2, MUX_D1WR_2,
MUX_D0RD_1, MUX_D1RD_1, MUX_D0RD_2, MUX_D1RD_2
);
signal mux_state : muxstate_t;
signal mux_toggle : std_logic := '0';

signal mux_c128_timeout : unsigned(7 downto 0) := (others => '1');
signal mux_clk_reg : std_logic := '0';
signal mux_d_reg : unsigned(mux_d'range) := X"F";
signal mux_reg : unsigned(mux'range) := X"F";
signal mux_d_mmc : unsigned(1 downto 0) := "11";

-- C64 bus
signal c64_reset_reg : std_logic := '0';
signal c64_ba_reg : std_logic := '1';
signal c64_data_reg : unsigned(7 downto 0) := (others => '1');
signal c64_addr : unsigned(15 downto 0) := (others => '0');
signal c64_to_io : unsigned(7 downto 0) := (others => '0');
signal c64_we_loc : std_logic := '0';
signal c64_vic_loc : std_logic := '0';
signal c64_cs_loc : std_logic := '0';
signal c64_roms_loc : std_logic := '0';
signal c64_clockport_loc : std_logic := '0';
-- C64 joystick/keyboard
signal c64_kb_req : std_logic := '0';
signal c64_kb_ack : std_logic := '0';
signal c64_kb_we : std_logic := '1';
signal c64_kb_a : unsigned(15 downto 0) := (others => '0');
signal c64_kb_q : unsigned(7 downto 0) := (others => '1');
signal c64_joystick1 : unsigned(4 downto 0);
signal c64_joystick2 : unsigned(4 downto 0);
signal c64_joystick3 : unsigned(4 downto 0);
signal c64_joystick4 : unsigned(4 downto 0);
signal c64_keys : unsigned(63 downto 0);

-- Docking-station
signal docking_station_loc : std_logic;
signal docking_irq : std_logic;
signal docking_joystick1 : unsigned(5 downto 0);
signal docking_joystick2 : unsigned(5 downto 0);
signal docking_joystick3 : unsigned(5 downto 0);
signal docking_joystick4 : unsigned(5 downto 0);
signal docking_keys : unsigned(63 downto 0);
signal docking_amiga_reset_n : std_logic;
signal docking_amiga_scancode : unsigned(7 downto 0);

-- MMC
signal mmc_state : unsigned(5 downto 0) := (others => '0');
signal spi_q_reg : unsigned(7 downto 0) := (others => '1');
signal spi_run : std_logic := '0';
signal spi_sample : std_logic := '0';
signal mmc_shift_req : std_logic;
signal mmc_shift_ack : std_logic := '0';

-- IEC
signal iec_clk_reg : std_logic := '1';
signal iec_dat_reg : std_logic := '1';
signal iec_atn_reg : std_logic := '1';
signal iec_srq_reg : std_logic := '1';
begin
reset_ext <= reset_in;
no_clock <= no_clock_loc;
docking_station <= docking_station_loc;
--
phi_out <= phi;
phi_end_0 <= end_of_phi_0;
phi_end_1 <= end_of_phi_1;
--
c64_ba <= c64_ba_reg;
c64_q <= c64_data_reg;
--
spi_q <= spi_q_reg;
--
joystick1 <= docking_joystick1 and ("1" & c64_joystick1);
joystick2 <= docking_joystick2 and ("1" & c64_joystick2);
joystick3 <= docking_joystick3 and ("1" & c64_joystick3);
joystick4 <= docking_joystick4 and ("1" & c64_joystick4);
keys <= docking_keys and c64_keys;

-- -----------------------------------------------------------------------
-- PHI2 clock sync
-- -----------------------------------------------------------------------
phiInstance : entity work.chameleon_phi_clock
port map (
clk => clk,
phi2_n => phi2_n,
mode => phi_mode,

no_clock => no_clock_loc,
docking_station => docking_station_loc,

phiLocal => phi,
phiCnt => phi_cnt,
phiPreHalf => end_of_phi_0,
phiPreEnd => end_of_phi_1,
phiPost1 => phi_post_1,
phiPost2 => phi_post_2,
phiPost3 => phi_post_3,
phiPost4 => phi_post_4
);

-- -----------------------------------------------------------------------
-- Docking-station
-- To enable set enable_docking_station to true.
-- -----------------------------------------------------------------------
genDockingStation : if enable_docking_station generate
myDockingStation : entity work.chameleon_docking_station
port map (
clk => clk,
docking_station => docking_station_loc,
dotclock_n => dotclock_n,
io_ef_n => io_ef_n,
rom_lh_n => rom_lh_n,
irq_q => docking_irq,
joystick1 => docking_joystick1,
joystick2 => docking_joystick2,
joystick3 => docking_joystick3,
joystick4 => docking_joystick4,
keys => docking_keys,
restore_key_n => restore_key_n,
amiga_power_led => led_green,
amiga_drive_led => led_red,
amiga_reset_n => amiga_reset_n,
amiga_trigger => amiga_trigger,
amiga_scancode => amiga_scancode
);
end generate;

noDockingStation : if not enable_docking_station generate
docking_joystick1 <= (others => '1');
docking_joystick2 <= (others => '1');
docking_joystick3 <= (others => '1');
docking_joystick4 <= (others => '1');
docking_keys <= (others => '1');
end generate;

-- -----------------------------------------------------------------------
-- C64 keyboard and joystick support
-- To enable set enable_c64_joykeyb to true.
-- -----------------------------------------------------------------------
genC64JoyKeyb : if enable_c64_joykeyb generate
myC64JoyKeyb : entity work.chameleon_c64_joykeyb
generic map (
enable_4player => enable_c64_4player
)
port map (
clk => clk,
ena_1mhz => ena_1mhz,
no_clock => no_clock_loc,
reset => reset,
ba => c64_ba_reg,
req => c64_kb_req,
ack => c64_kb_ack,
we => c64_kb_we,
a => c64_kb_a,
d => c64_data_reg,
q => c64_kb_q,
joystick1 => c64_joystick1,
joystick2 => c64_joystick2,
joystick3 => c64_joystick3,
joystick4 => c64_joystick4,
keys => c64_keys
);

c64_addr <= c64_kb_a;
c64_to_io <= c64_kb_q;
c64_vic_loc <= '0';
c64_roms_loc <= '0';
c64_clockport_loc <= '0';
c64_we_loc <= c64_kb_we;

process(clk)
begin
if rising_edge(clk) then
if end_of_phi_1 = '1' then
c64_cs_loc <= '0';
if c64_kb_req /= c64_kb_ack then
if c64_cs_loc = '1' then
c64_kb_ack <= c64_kb_req;
else
c64_cs_loc <= '1';
end if;
end if;
end if;
end if;
end process;
end generate;
noC64JoyKeyb : if not enable_c64_joykeyb generate
c64_joystick1 <= (others => '1');
c64_joystick2 <= (others => '1');
c64_joystick3 <= (others => '1');
c64_joystick4 <= (others => '1');
c64_keys <= (others => '1');
c64_addr <= c64_a;
c64_to_io <= c64_d;

c64_vic_loc <= c64_vic;
c64_cs_loc <= c64_cs;
c64_roms_loc <= c64_cs_roms;
c64_clockport_loc <= c64_clockport;
c64_we_loc <= c64_we;
end generate;

-- -----------------------------------------------------------------------
-- MUX CPLD
-- -----------------------------------------------------------------------
-- MUX clock
process(clk_mux)
begin
if rising_edge(clk_mux) then
mux_clk_reg <= not mux_clk_reg;
end if;
end process;

-- MUX sequence
process(clk_mux)
begin
if rising_edge(clk_mux) then
if mux_clk_reg = '1' then
mux_toggle <= not mux_toggle;
case mux_state is
when MUX_RESET =>
if phi = '1' then
mux_state <= MUX_WAIT0;
end if;
-- PHI2 0
when MUX_WAIT0 =>
if phi = '0' then
mux_state <= MUX_MMC0L;
if mux_c128_timeout /= 0 then
mux_c128_timeout <= mux_c128_timeout - 1;
end if;
end if;
when MUX_MMC0L => mux_state <= MUX_A3_C;
when MUX_A3_C => mux_state <= MUX_ULTIMAX;
when MUX_ULTIMAX => mux_state <= MUX_MMC0H;
when MUX_MMC0H => mux_state <= MUX_BUSVIC;
when MUX_BUSVIC => mux_state <= MUX_IEC1;
when MUX_IEC1 => mux_state <= MUX_MMC1L;
when MUX_MMC1L => mux_state <= MUX_PS2;
when MUX_PS2 => mux_state <= MUX_A2;
when MUX_A2 => mux_state <= MUX_MMC1H;
when MUX_MMC1H => mux_state <= MUX_NMIIRQ1;
when MUX_NMIIRQ1 => mux_state <= MUX_LED;
when MUX_LED => mux_state <= MUX_MMC2L;
when MUX_MMC2L => mux_state <= MUX_A0;
when MUX_A0 => mux_state <= MUX_IEC4;
when MUX_IEC4 => mux_state <= MUX_MMC2H;
when MUX_MMC2H => mux_state <= MUX_A1;
when MUX_A1 => mux_state <= MUX_D0VIC;
when MUX_D0VIC => mux_state <= MUX_D1VIC;
when MUX_D1VIC => mux_state <= MUX_MMC3L;
when MUX_MMC3L => mux_state <= MUX_IEC3;
when MUX_IEC3 => mux_state <= MUX_MMC3H;
when MUX_MMC3H => mux_state <= MUX_END0;
when MUX_END0 => mux_state <= MUX_WAIT1;
-- PHI2 1
when MUX_WAIT1 =>
if phi = '1' then
mux_state <= MUX_MMC4L;
end if;
when MUX_MMC4L => mux_state <= MUX_BUS;
when MUX_BUS => mux_state <= MUX_D0WR;
when MUX_D0WR => mux_state <= MUX_D1WR;
when MUX_D1WR => mux_state <= MUX_MMC4H;
when MUX_MMC4H => mux_state <= MUX_A3;
when MUX_A3 => mux_state <= MUX_CLKPORT;
when MUX_CLKPORT => mux_state <= MUX_MMC5L;
when MUX_MMC5L => mux_state <= MUX_NMIIRQ2;
when MUX_NMIIRQ2 => mux_state <= MUX_MMC5H;
when MUX_MMC5H => mux_state <= MUX_D0WR_1;
when MUX_D0WR_1 => mux_state <= MUX_D1WR_1;
when MUX_D1WR_1 => mux_state <= MUX_MMC6L;
when MUX_MMC6L => mux_state <= MUX_IEC2;
when MUX_IEC2 => mux_state <= MUX_MMC6H;
--when MUX_LED => mux_state <= MUX_MMC6H;
when MUX_MMC6H => mux_state <= MUX_D0WR_2;
when MUX_D0WR_2 => mux_state <= MUX_D1WR_2;
when MUX_D1WR_2 => mux_state <= MUX_MMC7L;
when MUX_MMC7L => mux_state <= MUX_D0RD_1;
when MUX_D0RD_1 => mux_state <= MUX_D1RD_1;
when MUX_D1RD_1 => mux_state <= MUX_MMC7H;
when MUX_MMC7H => mux_state <= MUX_D0RD_2;
when MUX_D0RD_2 => mux_state <= MUX_D1RD_2;
when MUX_D1RD_2 => mux_state <= MUX_WAIT0;
end case;
end if;
if reset = '1' then
mux_c128_timeout <= (others => '1');
-- system_wait <= '1';
end if;
end if;
end process;

-- MUX read
process(clk_mux)
begin
if rising_edge(clk_mux) then
if mux_clk_reg = '1' then
case mux_reg is
when X"0" =>
c64_data_reg(3 downto 0) <= mux_q;
when X"1" =>
c64_data_reg(7 downto 4) <= mux_q;
when X"6" =>
c64_reset_reg <= not mux_q(0);
c64_irq_n <= mux_q(2);
c64_nmi_n <= mux_q(3);
reset_pending <= reset or c64_reset_reg;
if reset_pending = '0' then
reset_in <= c64_reset_reg;
else
reset_in <= '0';
end if;
if no_clock_loc = '1' then
c64_irq_n <= '1';
end if;
when X"7" =>
c64_ba_reg <= mux_q(1);
if no_clock_loc = '1' then
c64_ba_reg <= '1';
end if;
when X"B" =>
button_reset_n <= mux_q(1);
ir <= mux_q(3);
when X"D" =>
iec_dat_reg <= mux_q(0);
iec_clk_reg <= mux_q(1);
iec_srq_reg <= mux_q(2);
iec_atn_reg <= mux_q(3);
when X"E" =>
ps2_keyboard_dat_in <= mux_q(0);
ps2_keyboard_clk_in <= mux_q(1);
ps2_mouse_dat_in <= mux_q(2);
ps2_mouse_clk_in <= mux_q(3);
when others =>
null;
end case;
if spi_sample = '1' then
spi_q_reg <= spi_q_reg(6 downto 0) & spi_miso;
end if;
end if;
iec_dat_in <= iec_dat_reg;
iec_clk_in <= iec_clk_reg;
iec_srq_in <= iec_srq_reg;
iec_atn_in <= iec_atn_reg;
end if;
end process;

-- MUX write
process(clk_mux)
begin
if rising_edge(clk_mux) then
spi_raw_ack <= '0';
if mux_clk_reg = '1' then
spi_sample <= '0';
case mux_state is
--
-- RESET
when MUX_RESET =>
mux_d_reg <= (others => '-');
mux_reg <= X"F";
--
-- MMC
when MUX_MMC0L =>
-- Remember current state for lowspeed transfer.
-- Register is accessed another 15 times in
-- system cycle, but should not be updated when running on 250khz speed.
mux_d_mmc(0) <= mmc_state(1) or (not mmc_state(5));
mux_d_mmc(1) <= spi_d(7 - to_integer(mmc_state(4 downto 2)));
-- Update register
mux_d_reg(0) <= mmc_state(1) or (not mmc_state(5));
mux_d_reg(1) <= spi_d(7 - to_integer(mmc_state(4 downto 2)));
mux_d_reg(2) <= mmc_cs_n;
mux_d_reg(3) <= to_usb_rx;
mux_reg <= X"C";
if mmc_state(5) = '1' then
if spi_speed = '0' then
-- Slow speed. Only toggle once in two cycles
mmc_state <= mmc_state + "000001";
if mmc_state(1 downto 0) = "11" then
spi_sample <= '1';
end if;
else
-- Fast speed. Toggle 16 times in a cycle
mmc_state <= mmc_state + "000010";
if mmc_state(1) = '1' then
spi_sample <= '1';
end if;
end if;
end if;
if enable_raw_spi then
mux_d_reg(0) <= spi_raw_clk;
mux_d_reg(1) <= spi_raw_mosi;
mux_d_reg(2) <= mmc_cs_n;
mux_d_reg(3) <= to_usb_rx;
mux_reg <= X"C";
spi_raw_ack <= '1';
end if;
when MUX_MMC1L | MUX_MMC2L | MUX_MMC3L
| MUX_MMC4L | MUX_MMC5L | MUX_MMC6L | MUX_MMC7L =>
mux_d_reg(0) <= mux_d_mmc(0);
mux_d_reg(1) <= mux_d_mmc(1);
mux_d_reg(2) <= mmc_cs_n;
mux_d_reg(3) <= to_usb_rx;
mux_reg <= X"C";
-- Only update register on when running at fast speed (8Mhz).
if (mmc_state(5) = '1') and (spi_speed = '1') then
mux_d_reg(0) <= mmc_state(1);
mux_d_reg(1) <= spi_d(7 - to_integer(mmc_state(4 downto 2)));
-- Fast speed. Toggle 16 times in a cycle
mmc_state <= mmc_state + "000010";
if mmc_state(1) = '1' then
spi_sample <= '1';
end if;
end if;
if enable_raw_spi then
mux_d_reg(0) <= spi_raw_clk;
mux_d_reg(1) <= spi_raw_mosi;
mux_d_reg(2) <= mmc_cs_n;
mux_d_reg(3) <= to_usb_rx;
mux_reg <= X"C";
spi_raw_ack <= '1';
end if;

when MUX_MMC0H | MUX_MMC1H | MUX_MMC2H | MUX_MMC3H
| MUX_MMC4H | MUX_MMC5H | MUX_MMC6H | MUX_MMC7H =>
mux_d_reg(0) <= mux_d_mmc(0);
mux_d_reg(1) <= mux_d_mmc(1);
mux_d_reg(2) <= mmc_cs_n;
mux_d_reg(3) <= to_usb_rx;
mux_reg <= X"C";
if (mmc_state(5) = '1') and (spi_speed = '1') then
-- Only update register on when running at fast speed (8Mhz).
mux_d_reg(0) <= mmc_state(1);
mux_d_reg(1) <= spi_d(7 - to_integer(mmc_state(4 downto 2)));
-- Fast speed. Toggle 16 times in a cycle
mmc_state <= mmc_state + "000010";
if mmc_state(1) = '1' then
spi_sample <= '1';
end if;
elsif enable_iec_access then
-- When MMC transfer is not pending use some of the MMC cycles for IEC transfers.
mux_d_reg(0) <= iec_dat_out;
mux_d_reg(1) <= iec_clk_out;
mux_d_reg(2) <= iec_srq_out;
mux_d_reg(3) <= iec_atn_out;
mux_reg <= X"D";
end if;
if enable_raw_spi then
mux_d_reg(0) <= spi_raw_clk;
mux_d_reg(1) <= spi_raw_mosi;
mux_d_reg(2) <= mmc_cs_n;
mux_d_reg(3) <= to_usb_rx;
mux_reg <= X"C";
spi_raw_ack <= '1';
end if;
when MUX_NMIIRQ1 | MUX_NMIIRQ2=>
mux_d_reg <= "110" & (not reset);
mux_reg <= X"6";
if docking_station_loc = '1' then
mux_d_reg(2) <= docking_irq;
end if;
--
-- IEC
when MUX_IEC1 | MUX_IEC2 | MUX_IEC3 | MUX_IEC4 =>
mux_d_reg(0) <= iec_dat_out;
mux_d_reg(1) <= iec_clk_out;
mux_d_reg(2) <= iec_srq_out;
mux_d_reg(3) <= iec_atn_out;
mux_reg <= X"D";
--
-- USART, LEDs and IR
when MUX_LED =>
mux_d_reg <= flash_cs_n & rtc_cs & led_green & led_red;
mux_reg <= X"B";
--
-- PS2
when MUX_PS2 =>
mux_d_reg(0) <= ps2_keyboard_dat_out;
mux_d_reg(1) <= ps2_keyboard_clk_out;
mux_d_reg(2) <= ps2_mouse_dat_out;
mux_d_reg(3) <= ps2_mouse_clk_out;
mux_reg <= X"E";
--
-- WAITS
when MUX_WAIT0 =>
if spi_req /= spi_run then
spi_run <= spi_req;
mmc_state <= "100000";
end if;
-- Use dead time to do IEC reads/writes
mux_d_reg(0) <= iec_dat_out;
mux_d_reg(1) <= iec_clk_out;
mux_d_reg(2) <= iec_srq_out;
mux_d_reg(3) <= iec_atn_out;
mux_reg <= X"D";
if enable_raw_spi then
mux_d_reg(0) <= spi_raw_clk;
mux_d_reg(1) <= spi_raw_mosi;
mux_d_reg(2) <= mmc_cs_n;
mux_d_reg(3) <= to_usb_rx;
mux_reg <= X"C";
spi_raw_ack <= '1';
end if;
when MUX_WAIT1 =>
-- Continue BUSVIC output at end of phi2=0, so we sample BA a few times.
mux_d_reg <= "0101";
if docking_station_loc = '1' then
mux_d_reg <= "1111";
end if;
mux_reg <= X"7";
-- Toggle between SPI/IEC and updating BUSVIC.
if mux_toggle = '1' then
if enable_iec_access then
mux_d_reg(0) <= iec_dat_out;
mux_d_reg(1) <= iec_clk_out;
mux_d_reg(2) <= iec_srq_out;
mux_d_reg(3) <= iec_atn_out;
mux_reg <= X"D";
end if;
if enable_raw_spi then
mux_d_reg(0) <= spi_raw_clk;
mux_d_reg(1) <= spi_raw_mosi;
mux_d_reg(2) <= mmc_cs_n;
mux_d_reg(3) <= to_usb_rx;
mux_reg <= X"C";
spi_raw_ack <= '1';
end if;
end if;
--
-- PHI2 0
when MUX_A3_C =>
mux_d_reg <= X"C";
mux_reg <= X"5";
when MUX_BUSVIC =>
mux_d_reg <= "0101";
if docking_station_loc = '1' then
mux_d_reg <= "1111";
end if;
mux_reg <= X"7";
when MUX_ULTIMAX =>
mux_d_reg <= "1011";
mux_reg <= X"8";
when MUX_D0VIC =>
mux_d_reg <= c64_to_io(3 downto 0);
mux_reg <= X"0";
when MUX_D1VIC =>
mux_d_reg <= c64_to_io(7 downto 4);
mux_reg <= X"1";
when MUX_END0 =>
mux_d_reg <= "0111";
if docking_station_loc = '1' then
mux_d_reg <= "1111";
end if;
mux_reg <= X"7";
--
-- PHI2 1
when MUX_A0 =>
mux_d_reg <= c64_addr(3 downto 0);
mux_reg <= X"2";
when MUX_A1 =>
mux_d_reg <= c64_addr(7 downto 4);
mux_reg <= X"3";
when MUX_A2 =>
mux_d_reg <= c64_addr(11 downto 8);
mux_reg <= X"4";
when MUX_BUS =>
if c64_vic_loc = '0' then
if c64_cs_loc = '1' then
mux_d_reg <= "00" & (not c64_we_loc) & (not c64_we_loc);
mux_reg <= X"7";
end if;
else
-- A15..12 driven, A11..0 not driven, Data driven, no write.
mux_d_reg <= "0101";
mux_reg <= X"7";
end if;
when MUX_CLKPORT =>
-- GAME = low unless accessing roms
mux_d_reg <= "1" & c64_roms_loc & "11";
if c64_clockport_loc = '1' then
if c64_we_loc = '0' then
-- Clockport read
mux_d_reg <= "1010";
else
-- Clockport write
mux_d_reg <= "1001";
end if;
end if;
mux_reg <= X"8";
when MUX_A3 =>
if c64_vic_loc = '0' then
if c64_cs_loc = '1' then
mux_d_reg <= c64_addr(15 downto 12);
mux_reg <= X"5";
end if;
end if;
-- when MUX_D0WR | MUX_D0WR_1 | MUX_D0WR_2 =>
when MUX_D0WR | MUX_D0WR_1 | MUX_D0WR_2 | MUX_D0RD_1 | MUX_D0RD_2 =>
mux_d_reg <= c64_to_io(3 downto 0);
mux_reg <= X"0";
-- when MUX_D1WR | MUX_D1WR_1 | MUX_D1WR_2 =>
when MUX_D1WR | MUX_D1WR_1 | MUX_D1WR_2 | MUX_D1RD_1 | MUX_D1RD_2 =>
mux_d_reg <= c64_to_io(7 downto 4);
mux_reg <= X"1";
when others =>
null;
end case;
end if;
end if;
end process;

process(clk_mux)
begin
if rising_edge(clk_mux) then
if mmc_state(5) = '0' then
spi_ack <= spi_run;
end if;
end if;
end process;

mux_clk <= mux_clk_reg;
mux_d <= mux_d_reg;
mux <= mux_reg;
end architecture;
(12-12/40)