|
-- -----------------------------------------------------------------------
|
|
--
|
|
-- 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/>.
|
|
--
|
|
-- -----------------------------------------------------------------------
|
|
--
|
|
-- Keyboard/joystick readout in cartridge mode
|
|
--
|
|
-- -----------------------------------------------------------------------
|
|
-- clk - system clock
|
|
-- ena_1mhz - Enable must be '1' one clk cycle each 1 Mhz.
|
|
--
|
|
-- joystick* - Joystick outputs (fire1, right, left, down, up) low active
|
|
-- keys - State of the keyboard (low is pressed)
|
|
-- -----------------------------------------------------------------------
|
|
|
|
library IEEE;
|
|
use IEEE.STD_LOGIC_1164.ALL;
|
|
use IEEE.numeric_std.all;
|
|
|
|
-- -----------------------------------------------------------------------
|
|
|
|
entity chameleon_c64_joykeyb is
|
|
generic (
|
|
enable_4player : boolean
|
|
);
|
|
port (
|
|
clk : in std_logic;
|
|
ena_1mhz : in std_logic;
|
|
no_clock : in std_logic;
|
|
reset : in std_logic;
|
|
|
|
-- To C64 cartridge logic
|
|
ba : in std_logic;
|
|
req : out std_logic;
|
|
ack : in std_logic;
|
|
we : out std_logic;
|
|
a : out unsigned(15 downto 0);
|
|
d : in unsigned(7 downto 0);
|
|
q : out unsigned(7 downto 0);
|
|
|
|
joystick1 : out unsigned(4 downto 0);
|
|
joystick2 : out unsigned(4 downto 0);
|
|
joystick3 : out unsigned(4 downto 0);
|
|
joystick4 : out unsigned(4 downto 0);
|
|
-- 0 = col0, row0
|
|
-- 1 = col1, row0
|
|
-- 8 = col0, row1
|
|
-- 63 = col7, row7
|
|
keys : out unsigned(63 downto 0)
|
|
);
|
|
end entity;
|
|
|
|
-- -----------------------------------------------------------------------
|
|
|
|
architecture rtl of chameleon_c64_joykeyb is
|
|
type state_t is (
|
|
INIT_RESET, INIT_DISABLE_VIC, INIT_DISABLE_MOB,
|
|
INIT_CIA1_A, INIT_CIA1_B, INIT_CIA2_B, --INIT_CIA2_A, ,
|
|
SET_COL, READ_ROW, STORE_ROW, SET_NOCOL,
|
|
READ_JOY1, STORE_JOY1, STORE_JOY2,
|
|
READ_JOY34, STORE_JOY34);
|
|
signal state : state_t := INIT_RESET;
|
|
signal req_reg : std_logic := '0';
|
|
signal joy34_flag : std_logic := '0';
|
|
signal cnt : unsigned(3 downto 0) := (others => '0');
|
|
signal col : integer range 0 to 7 := 0;
|
|
signal keys_reg : unsigned(63 downto 0) := (others => '1');
|
|
signal last_keys_reg : unsigned(63 downto 0) := (others => '1');
|
|
signal approved_keys_reg : unsigned(63 downto 0) := (others => '1');
|
|
signal joystick1_reg : unsigned(4 downto 0);
|
|
signal joystick1_prev_reg : unsigned(4 downto 0);
|
|
signal joystick2_prev_reg : unsigned(4 downto 0);
|
|
begin
|
|
keys <= approved_keys_reg;
|
|
req <= req_reg;
|
|
|
|
process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
if ena_1mhz = '1' then
|
|
cnt <= cnt - 1;
|
|
if cnt = 0 then
|
|
cnt <= (others => '0');
|
|
end if;
|
|
end if;
|
|
if (req_reg = ack) and (ba = '1') and (cnt = 0) then
|
|
we <= '-';
|
|
a <= (others => '-');
|
|
q <= (others => '-');
|
|
case state is
|
|
when INIT_RESET =>
|
|
if (reset = '0') and (ba = '1') then
|
|
state <= INIT_DISABLE_VIC;
|
|
end if;
|
|
when INIT_DISABLE_VIC =>
|
|
-- Turn off VIC-II raster DMA, so we don't have to deal with BA.
|
|
we <= '1';
|
|
a <= X"D011";
|
|
q <= X"00";
|
|
req_reg <= not req_reg;
|
|
state <= INIT_DISABLE_MOB;
|
|
when INIT_DISABLE_MOB =>
|
|
-- Turn off VIC-II sprite DMA, so we don't have to deal with BA.
|
|
we <= '1';
|
|
a <= X"D015";
|
|
q <= X"00";
|
|
req_reg <= not req_reg;
|
|
state <= INIT_CIA1_A;
|
|
when INIT_CIA1_A =>
|
|
-- Set keyboard columns port (joy2) to output
|
|
we <= '1';
|
|
a <= X"DC02";
|
|
q <= X"FF";
|
|
req_reg <= not req_reg;
|
|
state <= INIT_CIA1_B;
|
|
when INIT_CIA1_B =>
|
|
-- Set keyboard rows port (joy1) to input
|
|
we <= '1';
|
|
a <= X"DC03";
|
|
q <= X"00";
|
|
req_reg <= not req_reg;
|
|
state <= SET_COL;
|
|
if enable_4player then
|
|
state <= INIT_CIA2_B;
|
|
end if;
|
|
when INIT_CIA2_B =>
|
|
-- Set CIA2 port B for 4 player adapter
|
|
-- Bit7 output and others input.
|
|
we <= '1';
|
|
a <= X"DD03";
|
|
q <= X"80";
|
|
req_reg <= not req_reg;
|
|
state <= SET_COL;
|
|
when SET_COL =>
|
|
we <= '1';
|
|
a <= X"DC00";
|
|
q <= to_unsigned(255 - 2**col, 8);
|
|
req_reg <= not req_reg;
|
|
cnt <= (others => '1');
|
|
state <= READ_ROW;
|
|
when READ_ROW =>
|
|
we <= '0';
|
|
a <= X"DC01";
|
|
req_reg <= not req_reg;
|
|
state <= STORE_ROW;
|
|
when STORE_ROW =>
|
|
keys_reg(0 + col) <= d(0);
|
|
keys_reg(8 + col) <= d(1);
|
|
keys_reg(16 + col) <= d(2);
|
|
keys_reg(24 + col) <= d(3);
|
|
keys_reg(32 + col) <= d(4);
|
|
keys_reg(40 + col) <= d(5);
|
|
keys_reg(48 + col) <= d(6);
|
|
keys_reg(56 + col) <= d(7);
|
|
if col /= 7 then
|
|
col <= col + 1;
|
|
state <= SET_COL;
|
|
else
|
|
col <= 0;
|
|
state <= SET_NOCOL;
|
|
end if;
|
|
when SET_NOCOL =>
|
|
we <= '1';
|
|
a <= X"DC00";
|
|
q <= X"FF";
|
|
req_reg <= not req_reg;
|
|
cnt <= (others => '1');
|
|
state <= READ_JOY1;
|
|
when READ_JOY1 =>
|
|
-- read joystick port 1
|
|
we <= '0';
|
|
a <= X"DC01";
|
|
req_reg <= not req_reg;
|
|
state <= STORE_JOY1;
|
|
when STORE_JOY1 =>
|
|
-- read joystick port 2
|
|
we <= '0';
|
|
a <= X"DC00";
|
|
req_reg <= not req_reg;
|
|
joystick1 <= d(4 downto 0);
|
|
joystick1_prev_reg <= joystick1_reg;
|
|
joystick1_reg <= d(4 downto 0);
|
|
state <= STORE_JOY2;
|
|
when STORE_JOY2 =>
|
|
joystick2 <= d(4 downto 0);
|
|
state <= SET_COL;
|
|
if enable_4player then
|
|
state <= READ_JOY34;
|
|
end if;
|
|
last_keys_reg <= keys_reg;
|
|
if ((joystick1_reg and d(4 downto 0) and joystick1_prev_reg and joystick2_prev_reg) = "11111" and last_keys_reg = keys_reg) then
|
|
approved_keys_reg <= keys_reg;
|
|
end if;
|
|
joystick2_prev_reg <= d(4 downto 0);
|
|
|
|
when READ_JOY34 =>
|
|
-- read user port for joystick 3 or 4
|
|
we <= '0';
|
|
a <= X"DD01";
|
|
req_reg <= not req_reg;
|
|
state <= STORE_JOY34;
|
|
when STORE_JOY34 =>
|
|
joystick3(4) <= d(5);
|
|
joystick4(4) <= d(4);
|
|
if joy34_flag = '0' then
|
|
joystick4(3 downto 0) <= d(3 downto 0);
|
|
else
|
|
joystick3(3 downto 0) <= d(3 downto 0);
|
|
end if;
|
|
-- select the other joystick (3 or 4) on the userport
|
|
we <= '1';
|
|
a <= X"DD01";
|
|
q <= joy34_flag & "0000000";
|
|
joy34_flag <= not joy34_flag;
|
|
req_reg <= not req_reg;
|
|
state <= SET_COL;
|
|
end case;
|
|
end if;
|
|
if reset = '1' then
|
|
state <= INIT_RESET;
|
|
end if;
|
|
if no_clock = '1' then
|
|
joystick1 <= (others => '1');
|
|
joystick2 <= (others => '1');
|
|
joystick3 <= (others => '1');
|
|
joystick4 <= (others => '1');
|
|
keys_reg <= (others => '1');
|
|
end if;
|
|
if not enable_4player then
|
|
joystick3 <= (others => '1');
|
|
joystick4 <= (others => '1');
|
|
end if;
|
|
end if;
|
|
end process;
|
|
end architecture;
|
|
|
|
|