-- ----------------------------------------------------------------------- -- -- 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 . -- -- ----------------------------------------------------------------------- -- -- 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;