Project

General

Profile

-- -----------------------------------------------------------------------
--
-- 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 <http://www.gnu.org/licenses/>.
--
-- -----------------------------------------------------------------------

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;
(10-10/48)