-- ----------------------------------------------------------------------- -- -- Turbo Chameleon -- -- Multi purpose FPGA expansion for the Commodore 64 computer -- -- ----------------------------------------------------------------------- -- Copyright 2005-2019 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 . -- -- ----------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; -- ----------------------------------------------------------------------- architecture rtl of chameleon2_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; -- I/O entity internal C64 bus signal c64_cs_loc : std_logic; signal c64_cs_roms_loc : std_logic; signal c64_cs_vicii_loc : std_logic; signal c64_cs_clockport_loc : std_logic; signal c64_we_loc : std_logic; signal c64_a_loc : unsigned(15 downto 0); signal c64_d_loc : unsigned(7 downto 0); signal c64_q_loc : unsigned(7 downto 0); -- C64 joystick/keyboard signal c64_joystick1 : unsigned(5 downto 0); signal c64_joystick2 : unsigned(5 downto 0); signal c64_joystick3 : unsigned(5 downto 0); signal c64_joystick4 : unsigned(5 downto 0); signal c64_keys : unsigned(63 downto 0); -- CDTV remote signal ir_up : std_logic := '0'; signal ir_down : std_logic := '0'; signal ir_left : std_logic := '0'; signal ir_right : std_logic := '0'; signal ir_f1 : std_logic := '0'; signal ir_f2 : std_logic := '0'; signal ir_f3 : std_logic := '0'; signal ir_f4 : std_logic := '0'; signal ir_f5 : std_logic := '0'; signal ir_f6 : std_logic := '0'; signal ir_f7 : std_logic := '0'; signal ir_f8 : std_logic := '0'; signal ir_space : std_logic := '0'; signal ir_enter : std_logic := '0'; signal ir_left_button : std_logic := '0'; signal ir_middle_button : std_logic := '0'; signal ir_right_button : std_logic := '0'; signal ir_arrowleft : std_logic := '0'; signal ir_y : std_logic := '0'; signal ir_n : std_logic := '0'; signal ir_runstop : std_logic := '0'; signal ir_keys : unsigned(63 downto 0); signal ir_joystick1 : unsigned(5 downto 0) := (others => '1'); signal ir_joystick2 : unsigned(5 downto 0) := (others => '1'); -- 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); begin 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_q <= c64_q_loc; -- joystick1 <= docking_joystick1 and ir_joystick1 and c64_joystick1; joystick2 <= docking_joystick2 and ir_joystick2 and c64_joystick2; joystick3 <= docking_joystick3 and c64_joystick3; joystick4 <= docking_joystick4 and c64_joystick4; keys <= docking_keys and c64_keys and ir_keys; -- ----------------------------------------------------------------------- -- PHI2 clock sync -- ----------------------------------------------------------------------- phiInstance : entity work.chameleon_phi_clock generic map ( phase_shift => 8 ) 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 => ioef, rom_lh_n => romlh, 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 => '0', -- led_green, amiga_drive_led => '0', -- 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; -- ----------------------------------------------------------------------- -- CDTV remote support -- To enable set enable_cdtv_remote to true. -- ----------------------------------------------------------------------- genCdtvRemote : if enable_cdtv_remote generate myCdtvRemote : entity work.chameleon_cdtv_remote port map ( clk => clk, ena_1mhz => ena_1mhz, ir => ir_data, key_1 => ir_f1, key_2 => ir_f2, key_3 => ir_f3, key_4 => ir_f4, key_5 => ir_f5, key_6 => ir_f6, key_7 => ir_f7, key_8 => ir_f8, key_9 => ir_runstop, key_0 => ir_space, key_escape => ir_arrowleft, key_enter => ir_enter, key_genlock => ir_left_button, key_cdtv => ir_middle_button, key_power => ir_right_button, key_rew => ir_left, key_play => ir_up, key_ff => ir_right, key_stop => ir_down, key_vol_up => ir_y, key_vol_dn => ir_n, joystick_a => ir_joystick1, joystick_b => ir_joystick2 ); ir_keys <= (not ir_runstop) & "11" & (not ir_n) & "111" & (not (ir_up or ir_down)) & "1111111" & (not (ir_f5 or ir_f6)) & "1111111" & (not (ir_f3 or ir_f4)) & (not ir_space) & (not (ir_left or ir_up or ir_f2 or ir_f4 or ir_f6 or ir_f8)) & "11111" & (not (ir_f1 or ir_f2)) & "1111111" & (not (ir_f7 or ir_f8)) & "1111111" & (not (ir_left or ir_right)) & (not ir_arrowleft) & "111" & (not ir_y) & "11" & (not ir_enter) & "11111111"; end generate; noCdtvRemote : if not enable_cdtv_remote generate ir_keys <= (others => '1'); ir_joystick1 <= (others => '1'); ir_joystick2 <= (others => '1'); end generate; -- ----------------------------------------------------------------------- -- C64 keyboard and joystick support -- To enable set enable_c64_joykeyb to true. -- ----------------------------------------------------------------------- c64_joykeyb_gen : if enable_c64_joykeyb generate c64_joykeyb_blk : block signal c64_kb_cs_reg : std_logic := '0'; signal c64_kb_req : std_logic := '0'; signal c64_kb_ack : std_logic := '0'; signal c64_kb_we : std_logic := '0'; signal c64_kb_a : unsigned(15 downto 0); signal c64_kb_d : unsigned(7 downto 0); signal c64_kb_q : unsigned(7 downto 0); begin c64_joykeyb_inst : 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 => ba_in, req => c64_kb_req, ack => c64_kb_ack, we => c64_kb_we, a => c64_kb_a, d => c64_kb_d, q => c64_kb_q, joystick1 => c64_joystick1, joystick2 => c64_joystick2, joystick3 => c64_joystick3, joystick4 => c64_joystick4, keys => c64_keys ); process(clk) begin if rising_edge(clk) then if end_of_phi_1 = '1' then c64_kb_cs_reg <= '0'; if c64_kb_req /= c64_kb_ack then if c64_kb_cs_reg = '1' then -- C64 bus transaction finished c64_kb_ack <= c64_kb_req; else -- Start new C64 bus transaction c64_kb_cs_reg <= '1'; end if; end if; end if; end if; end process; c64_cs_loc <= c64_kb_cs_reg; c64_cs_roms_loc <= '0'; c64_cs_vicii_loc <= '0'; c64_cs_clockport_loc <= '0'; c64_we_loc <= c64_kb_we; c64_a_loc <= c64_kb_a; c64_d_loc <= c64_kb_q; c64_kb_d <= c64_q_loc; end block; end generate; no_c64_joykeyb_gen : 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_cs_loc <= c64_cs; c64_cs_roms_loc <= c64_cs_roms; c64_cs_vicii_loc <= c64_cs_vicii; c64_cs_clockport_loc <= c64_cs_clockport; c64_we_loc <= c64_we; c64_a_loc <= c64_a; c64_d_loc <= c64_d; end generate; -- ----------------------------------------------------------------------- -- Cartridge port and C64 bus control -- ----------------------------------------------------------------------- c64_bus_blk : block constant dir_fr_c64 : std_logic := '0'; constant dir_to_c64 : std_logic := '1'; type state_t is ( BUS_RESET, BUS_WAIT_PHI0, BUS0_00, BUS0_01, BUS0_02, BUS0_03, BUS0_04, BUS0_05, BUS0_06, BUS0_07, BUS0_08, BUS0_09, BUS0_0A, --BUS0_0B, BUS0_0C, BUS0_0D, BUS0_0E, BUS0_0F, BUS_WAIT_PHI1, BUS1_00, BUS1_01, BUS1_02, BUS1_03, BUS1_04, BUS1_05); signal state_reg : state_t := BUS_RESET; --signal exrom_out_reg : std_logic := '0'; signal clock_ior_reg : std_logic := '1'; signal clock_iow_reg : std_logic := '1'; signal game_out_reg : std_logic := '1'; signal rw_out_reg : std_logic := '0'; signal sa_dir_reg : std_logic := '1'; signal sa_oe_reg : std_logic := '1'; signal sa15_out_reg : std_logic := '0'; signal low_a_oe_reg : std_logic := '0'; signal low_a_reg : unsigned(15 downto 0) := (others => '0'); signal sd_dir_reg : std_logic := '1'; signal sd_oe_reg : std_logic := '1'; signal low_d_inp_reg : unsigned(7 downto 0) := (others => '0'); signal low_d_oe_reg : std_logic := '0'; signal low_d_out_reg : unsigned(7 downto 0) := (others => '0'); signal c64_q_reg : unsigned(c64_q'range) := (others => '1'); begin process(clk) begin if rising_edge(clk) then low_d_inp_reg <= low_d; case state_reg is when BUS_RESET => clock_ior_reg <= '1'; clock_iow_reg <= '1'; game_out_reg <= '1'; rw_out_reg <= '0'; sa_oe_reg <= '1'; sa15_out_reg <= '0'; sd_oe_reg <= '1'; low_a_oe_reg <= '0'; low_d_oe_reg <= '0'; if reset = '0' then state_reg <= BUS_WAIT_PHI0; end if; when BUS_WAIT_PHI0 => c64_q_reg <= low_d_inp_reg; if phi = '0' then state_reg <= BUS0_00; else if c64_cs_vicii_loc = '1' then low_d_out_reg <= c64_d_loc; end if; end if; when BUS0_00 => state_reg <= BUS0_01; when BUS0_01 => game_out_reg <= '1'; low_a_reg(15) <= '0'; clock_ior_reg <= '1'; clock_iow_reg <= '1'; state_reg <= BUS0_02; when BUS0_02 => state_reg <= BUS0_03; when BUS0_03 => low_a_oe_reg <= '0'; rw_out_reg <= '0'; sa_oe_reg <= '1'; state_reg <= BUS0_04; when BUS0_04 => sa15_out_reg <= '1'; state_reg <= BUS0_05; when BUS0_05 => state_reg <= BUS0_06; when BUS0_06 => state_reg <= BUS0_07; when BUS0_07 => state_reg <= BUS0_08; when BUS0_08 => state_reg <= BUS0_09; when BUS0_09 => sd_dir_reg <= dir_to_c64; state_reg <= BUS0_0A; when BUS0_0A => low_d_oe_reg <= '1'; sd_oe_reg <= '0'; state_reg <= BUS_WAIT_PHI1; -- state_reg <= -- when BUS0_04 => state_reg <= BUS0_05; -- when BUS0_05 => state_reg <= BUS0_06; -- when BUS0_06 => state_reg <= BUS0_07; -- when BUS0_07 => state_reg <= BUS0_08; -- when BUS0_08 => state_reg <= BUS0_09; -- when BUS0_09 => state_reg <= BUS0_0A; -- when BUS0_0A => state_reg <= BUS0_0B; -- when BUS0_0B => state_reg <= BUS0_0C; -- when BUS0_0C => state_reg <= BUS0_0D; -- when BUS0_0D => state_reg <= BUS0_0E; -- when BUS0_0E => state_reg <= BUS0_0F; -- when BUS0_0F => -- state_reg <= BUS_WAIT_PHI1; when BUS_WAIT_PHI1 => low_d_out_reg <= c64_vicii_data; if phi = '1' then state_reg <= BUS1_00; end if; when BUS1_00 => state_reg <= BUS1_01; when BUS1_01 => state_reg <= BUS1_02; when BUS1_02 => sa_dir_reg <= dir_to_c64; rw_out_reg <= c64_we_loc and c64_cs_loc; if (c64_cs_loc = '1') and (c64_cs_vicii_loc = '0') then sa15_out_reg <= '0'; low_a_oe_reg <= '1'; end if; if ((c64_cs_loc and c64_we_loc) = '0') and (c64_cs_vicii_loc = '0') then low_d_oe_reg <= '0'; sd_oe_reg <= '1'; end if; -- For reading ROMs the GAME line need to be high (game_out_reg low as driver inverts). game_out_reg <= '1'; if c64_cs_roms_loc = '1' then game_out_reg <= '0'; end if; low_a_reg <= "0" & c64_a_loc(14 downto 0); low_d_out_reg <= c64_d_loc; state_reg <= BUS1_03; when BUS1_03 => if (c64_cs_loc = '1') and (c64_cs_vicii_loc = '0') then sa_oe_reg <= '0'; end if; if c64_cs_vicii_loc = '1' then sa15_out_reg <= '1'; end if; low_a_reg <= "0" & c64_a_loc(14 downto 0); low_d_out_reg <= c64_d_loc; state_reg <= BUS1_04; when BUS1_04 => sd_dir_reg <= dir_fr_c64; if ((c64_cs_loc and c64_we_loc) or c64_cs_vicii_loc) = '1' then sd_dir_reg <= dir_to_c64; low_d_oe_reg <= '1'; end if; low_a_reg <= "0" & c64_a_loc(14 downto 0); low_d_out_reg <= c64_d_loc; state_reg <= BUS1_05; when BUS1_05 => sd_oe_reg <= '0'; if c64_cs_clockport_loc = '1' then clock_ior_reg <= c64_we_loc; clock_iow_reg <= not c64_we_loc; end if; low_a_reg <= c64_a_loc(15 downto 0); low_d_out_reg <= c64_d_loc; state_reg <= BUS_WAIT_PHI0; end case; end if; end process; clock_ior <= clock_ior_reg; clock_iow <= clock_iow_reg; dma_out <= '1'; exrom_out <= '0'; game_out <= game_out_reg; rw_out <= rw_out_reg; sa_dir <= sa_dir_reg; sa_oe <= sa_oe_reg; sa15_out <= sa15_out_reg; low_a <= low_a_reg when low_a_oe_reg = '1' else (others => 'Z'); sd_dir <= sd_dir_reg; sd_oe <= sd_oe_reg; low_d <= low_d_out_reg when low_d_oe_reg = '1' else (others => 'Z'); c64_q_loc <= c64_q_reg; end block; end architecture;