|
---------------------------------------------------------------------------
|
|
-- (c) 2018 mark watson
|
|
-- I am happy for anyone to use this for non-commercial use.
|
|
-- If my vhdl files are used commercially or otherwise sold,
|
|
-- please contact me for explicit permission at scrameta (gmail).
|
|
-- This applies for source and binary form and derived works.
|
|
---------------------------------------------------------------------------
|
|
|
|
LIBRARY ieee;
|
|
USE ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
|
|
|
|
LIBRARY work;
|
|
|
|
ENTITY pokeymax IS
|
|
GENERIC
|
|
(
|
|
stereo : integer := 1 -- 0=MONO,1=STEREO
|
|
);
|
|
PORT
|
|
(
|
|
PHI2 : IN STD_LOGIC;
|
|
|
|
CLK_OUT : OUT STD_LOGIC; -- Use PHI2 and internal oscillator to create a clock, feed out here
|
|
CLK_SLOW : IN STD_LOGIC; -- ... and back in here, then to pll!
|
|
|
|
D : INOUT STD_LOGIC_VECTOR(7 DOWNTO 0);
|
|
A : IN STD_LOGIC_VECTOR(4 DOWNTO 0);
|
|
W_N : IN STD_LOGIC;
|
|
IRQ : INOUT STD_LOGIC;
|
|
SOD : OUT STD_LOGIC;
|
|
ACLK : OUT STD_LOGIC;
|
|
BCLK : INOUT STD_LOGIC;
|
|
SID : IN STD_LOGIC;
|
|
CS_COMB : IN STD_LOGIC;
|
|
|
|
AUD : OUT STD_LOGIC_VECTOR(4 DOWNTO 1);
|
|
|
|
PADDLE : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
|
|
--set_location_assignment PIN_M1 -to PADDLE[0] (pin3/potch7/pot7/p0)
|
|
--set_location_assignment PIN_M2 -to PADDLE[1] (pin2/potch6/pot6/p1)
|
|
--set_location_assignment PIN_N2 -to PADDLE[3] (pin0/potch5/pot5/p3)
|
|
--set_location_assignment PIN_M3 -to PADDLE[2] (pin1/potch4/pot4/p2)
|
|
--set_location_assignment PIN_N3 -to PADDLE[5] (pin7/potch3/pot3/p5)
|
|
--set_location_assignment PIN_M4 -to PADDLE[7] (pin4/potch1/pot0/p7)
|
|
--set_location_assignment PIN_N4 -to PADDLE[4] (pin6/potch2/pot2/p4)
|
|
--set_location_assignment PIN_N5 -to PADDLE[6] (pin5/potch0/pot1/p6)
|
|
|
|
|
|
IOX_RST : OUT STD_LOGIC;
|
|
IOX_INT : IN STD_LOGIC;
|
|
IOX_SDA : INOUT STD_LOGIC;
|
|
IOX_SCL : INOUT STD_LOGIC
|
|
);
|
|
END pokeymax;
|
|
|
|
ARCHITECTURE vhdl OF pokeymax IS
|
|
component int_osc is
|
|
port (
|
|
clkout : out std_logic; -- clkout.clk
|
|
oscena : in std_logic := '0' -- oscena.oscena
|
|
);
|
|
end component;
|
|
|
|
component hq_dac
|
|
port (
|
|
reset :in std_logic;
|
|
clk :in std_logic;
|
|
clk_ena : in std_logic;
|
|
pcm_in : in std_logic_vector(19 downto 0);
|
|
dac_out : out std_logic
|
|
);
|
|
end component;
|
|
|
|
component pll
|
|
port (
|
|
inclk0 : in std_logic := '0';
|
|
c0 : out std_logic;
|
|
locked : out std_logic
|
|
);
|
|
end component;
|
|
|
|
signal OSC_CLK : std_logic;
|
|
signal PHI2_6X : std_logic;
|
|
|
|
signal CLK : std_logic;
|
|
signal RESET_N : std_logic;
|
|
|
|
signal ENABLE_CYCLE : std_logic;
|
|
|
|
-- POKEY
|
|
SIGNAL POKEY_DO : STD_LOGIC_VECTOR(7 DOWNTO 0);
|
|
SIGNAL POKEY_WRITE_ENABLE : STD_LOGIC;
|
|
signal POKEY1_CHANNEL0 : std_logic_vector(3 downto 0);
|
|
signal POKEY1_CHANNEL1 : std_logic_vector(3 downto 0);
|
|
signal POKEY1_CHANNEL2 : std_logic_vector(3 downto 0);
|
|
signal POKEY1_CHANNEL3 : std_logic_vector(3 downto 0);
|
|
|
|
SIGNAL POKEY2_DO : STD_LOGIC_VECTOR(7 DOWNTO 0);
|
|
SIGNAL POKEY2_WRITE_ENABLE : STD_LOGIC;
|
|
signal POKEY2_CHANNEL0 : std_logic_vector(3 downto 0);
|
|
signal POKEY2_CHANNEL1 : std_logic_vector(3 downto 0);
|
|
signal POKEY2_CHANNEL2 : std_logic_vector(3 downto 0);
|
|
signal POKEY2_CHANNEL3 : std_logic_vector(3 downto 0);
|
|
|
|
signal SIO_CLOCKIN_IN : std_logic;
|
|
signal SIO_CLOCKIN_OUT : std_logic;
|
|
signal SIO_CLOCKIN_OE : std_logic;
|
|
signal SIO_CLOCKOUT : std_logic;
|
|
|
|
signal SIO_TXD : std_logic;
|
|
signal SIO_RXD : std_logic;
|
|
|
|
signal POKEY_IRQ : std_logic;
|
|
|
|
signal POT_RESET : std_logic;
|
|
|
|
signal ADDR_IN : std_logic_vector(4 downto 0);
|
|
signal WRITE_DATA : std_logic_vector(7 downto 0);
|
|
|
|
signal AUDIO_L : std_logic_vector(15 downto 0);
|
|
signal AUDIO_R : std_logic_vector(15 downto 0);
|
|
signal AUDIO_M : std_logic_vector(15 downto 0);
|
|
|
|
signal AUDIO_LEFT : std_logic;
|
|
signal AUDIO_RIGHT : std_logic;
|
|
signal AUDIO_MIXED : std_logic;
|
|
|
|
signal KEYBOARD_SCAN : std_logic_vector(5 downto 0);
|
|
signal KEYBOARD_RESPONSE : std_logic_vector(1 downto 0);
|
|
signal KEYBOARD_SCAN_ENABLE : std_logic;
|
|
|
|
signal BUS_DATA : std_logic_vector(7 downto 0);
|
|
signal BUS_OE : std_logic;
|
|
|
|
signal REQUEST : std_logic;
|
|
signal WRITE_N : std_logic;
|
|
|
|
signal DO_MUX : std_logic_vector(7 downto 0);
|
|
|
|
signal i2c0_ena : std_logic;
|
|
signal i2c0_addr : std_logic_vector(7 downto 1);
|
|
signal i2c0_rw : std_logic;
|
|
signal i2c0_write_data : std_logic_vector(7 downto 0);
|
|
signal i2c0_busy : std_logic;
|
|
signal i2c0_read_data : std_logic_vector(7 downto 0);
|
|
signal i2c0_error : std_logic;
|
|
|
|
signal sel_pokey2 : std_logic;
|
|
BEGIN
|
|
IOX_RST <= 'Z'; -- TODO weak pull up in pins (see TODO file)
|
|
|
|
oscillator : int_osc
|
|
port map
|
|
(
|
|
clkout => OSC_CLK,
|
|
oscena => '1'
|
|
);
|
|
|
|
|
|
--phi_multiplier : entity work.phi_mult
|
|
--port map
|
|
--(
|
|
-- clkin => OSC_CLK,
|
|
-- phi2 => PHI2,
|
|
-- clkout => PHI2_6X -- 6x phi2, aligned!
|
|
--);
|
|
|
|
PHI2_6X <= OSC_CLK;
|
|
|
|
pll_inst : pll
|
|
PORT MAP(inclk0 => CLK_SLOW,
|
|
c0 => CLK, -- 27MHz
|
|
locked => RESET_N);
|
|
|
|
bus_adapt : entity work.slave_timing_6502
|
|
PORT MAP
|
|
(
|
|
CLK => CLK,
|
|
RESET_N => RESET_N,
|
|
|
|
-- input from the cart port
|
|
PHI2 => PHI2,
|
|
bus_addr => A,
|
|
bus_data => D,
|
|
|
|
-- output to the cart port
|
|
bus_data_out => BUS_DATA,
|
|
bus_drive => BUS_OE,
|
|
bus_cs => CS_COMB,
|
|
bus_rw_n => W_N,
|
|
|
|
-- request for a memory bus cycle (read or write)
|
|
BUS_REQUEST => REQUEST,
|
|
ADDR_IN => ADDR_IN,
|
|
DATA_IN => WRITE_DATA,
|
|
RW_N => WRITE_N,
|
|
|
|
-- end of cycle
|
|
ENABLE_CYCLE => ENABLE_CYCLE,
|
|
|
|
DATA_OUT => DO_MUX
|
|
);
|
|
pokey_mixer_both : entity work.pokey_mixer_mux
|
|
PORT MAP(CLK => CLK,
|
|
ENABLE_179 => ENABLE_CYCLE,
|
|
CHANNEL_L_0 => POKEY1_CHANNEL0,
|
|
CHANNEL_L_1 => POKEY1_CHANNEL1,
|
|
CHANNEL_L_2 => POKEY1_CHANNEL2,
|
|
CHANNEL_L_3 => POKEY1_CHANNEL3,
|
|
CHANNEL_R_0 => POKEY2_CHANNEL0,
|
|
CHANNEL_R_1 => POKEY2_CHANNEL1,
|
|
CHANNEL_R_2 => POKEY2_CHANNEL2,
|
|
CHANNEL_R_3 => POKEY2_CHANNEL3,
|
|
VOLUME_OUT_M => AUDIO_M,
|
|
VOLUME_OUT_L => AUDIO_L,
|
|
VOLUME_OUT_R => AUDIO_R);
|
|
|
|
pokey1 : entity work.pokey
|
|
GENERIC MAP
|
|
(
|
|
custom_keyboard_scan => 1
|
|
)
|
|
PORT MAP(CLK => CLK,
|
|
ENABLE_179 => ENABLE_CYCLE,
|
|
WR_EN => POKEY_WRITE_ENABLE,
|
|
RESET_N => RESET_N,
|
|
SIO_IN1 => SIO_RXD,
|
|
SIO_IN2 => '1',
|
|
SIO_IN3 => '1',
|
|
SIO_CLOCKIN_IN => SIO_CLOCKIN_IN,
|
|
SIO_CLOCKIN_OUT => SIO_CLOCKIN_OUT,
|
|
SIO_CLOCKIN_OE => SIO_CLOCKIN_OE,
|
|
ADDR => ADDR_IN(3 DOWNTO 0),
|
|
DATA_IN => WRITE_DATA(7 DOWNTO 0),
|
|
keyboard_response => KEYBOARD_RESPONSE,
|
|
POT_IN => PADDLE,
|
|
IRQ_N_OUT => POKEY_IRQ,
|
|
SIO_OUT1 => SIO_TXD,
|
|
SIO_OUT2 => open,
|
|
SIO_OUT3 => open,
|
|
SIO_CLOCKOUT => SIO_CLOCKOUT,
|
|
POT_RESET => POT_RESET,
|
|
CHANNEL_0_OUT => POKEY1_CHANNEL0,
|
|
CHANNEL_1_OUT => POKEY1_CHANNEL1,
|
|
CHANNEL_2_OUT => POKEY1_CHANNEL2,
|
|
CHANNEL_3_OUT => POKEY1_CHANNEL3,
|
|
DATA_OUT => POKEY_DO,
|
|
keyboard_scan => KEYBOARD_SCAN,
|
|
keyboard_scan_enable => KEYBOARD_SCAN_ENABLE
|
|
);
|
|
|
|
gen_stereo : if stereo=1 generate
|
|
process(SEL_POKEY2,POKEY_DO,POKEY2_DO)
|
|
begin
|
|
DO_MUX <= (others =>'0');
|
|
if (SEL_POKEY2='1') then
|
|
DO_MUX <= POKEY2_DO;
|
|
else
|
|
DO_MUX <= POKEY_DO;
|
|
end if;
|
|
end process;
|
|
|
|
isstereo : ENTITY work.stereo_detect
|
|
PORT MAP
|
|
(
|
|
CLK => clk,
|
|
RESET_N => reset_n,
|
|
|
|
A => A, -- raw...
|
|
ADDR_IN => ADDR_IN, -- on request
|
|
|
|
SEL_POKEY2 => sel_pokey2
|
|
);
|
|
|
|
POKEY_WRITE_ENABLE <= NOT(WRITE_N) and REQUEST and NOT(SEL_POKEY2);
|
|
POKEY2_WRITE_ENABLE <= NOT(WRITE_N) and REQUEST and SEL_POKEY2;
|
|
|
|
pokey2 : entity work.pokey
|
|
PORT MAP(CLK => CLK,
|
|
ENABLE_179 => ENABLE_CYCLE,
|
|
WR_EN => POKEY2_WRITE_ENABLE,
|
|
RESET_N => RESET_N,
|
|
ADDR => ADDR_IN(3 DOWNTO 0),
|
|
DATA_IN => WRITE_DATA(7 DOWNTO 0),
|
|
CHANNEL_0_OUT => POKEY2_CHANNEL0,
|
|
CHANNEL_1_OUT => POKEY2_CHANNEL1,
|
|
CHANNEL_2_OUT => POKEY2_CHANNEL2,
|
|
CHANNEL_3_OUT => POKEY2_CHANNEL3,
|
|
DATA_OUT => POKEY2_DO,
|
|
SIO_IN1 => '1',
|
|
SIO_IN2 => '1',
|
|
SIO_IN3 => '1',
|
|
keyboard_response => "00",
|
|
pot_in=>"00000000");
|
|
end generate;
|
|
|
|
gen_mono : if stereo=0 generate
|
|
POKEY2_CHANNEL0 <= "0000";
|
|
POKEY2_CHANNEL1 <= "0000";
|
|
POKEY2_CHANNEL2 <= "0000";
|
|
POKEY2_CHANNEL3 <= "0000";
|
|
|
|
DO_MUX <= POKEY_DO;
|
|
|
|
POKEY_WRITE_ENABLE <= NOT(WRITE_N) and REQUEST;
|
|
|
|
end generate;
|
|
|
|
dac_left : hq_dac
|
|
port map
|
|
(
|
|
reset => not(reset_n),
|
|
clk => clk,
|
|
clk_ena => '1',
|
|
pcm_in => AUDIO_L&"0000",
|
|
dac_out => AUDIO_LEFT
|
|
);
|
|
|
|
dac_right : hq_dac
|
|
port map
|
|
(
|
|
reset => not(reset_n),
|
|
clk => clk,
|
|
clk_ena => '1',
|
|
pcm_in => AUDIO_R&"0000",
|
|
dac_out => AUDIO_RIGHT
|
|
);
|
|
|
|
dac_mixed : hq_dac
|
|
port map
|
|
(
|
|
reset => not(reset_n),
|
|
clk => clk,
|
|
clk_ena => '1',
|
|
pcm_in => AUDIO_M&"0000",
|
|
dac_out => AUDIO_MIXED
|
|
);
|
|
|
|
-- io extension
|
|
-- drive to 0 for pot reset (otherwise high imp)
|
|
-- drive keyboard lines
|
|
i2c_master0 : entity work.i2c_master
|
|
generic map(input_clk=>58_000_000, bus_clk=>400_000)
|
|
port map(
|
|
clk=>clk,
|
|
reset_n=>reset_n,
|
|
|
|
ena=>i2c0_ena,
|
|
addr=>i2c0_addr,
|
|
rw=>i2c0_rw,
|
|
data_wr=>i2c0_write_data,
|
|
busy=>i2c0_busy,
|
|
data_rd=>i2c0_read_data,
|
|
ack_error=>i2c0_error,
|
|
|
|
sda=>IOX_SDA,
|
|
scl=>IOX_SCL
|
|
);
|
|
|
|
iox_glue : entity work.iox_glue
|
|
port map(
|
|
clk=>clk,
|
|
reset_n=>reset_n,
|
|
|
|
ena=>i2c0_ena,
|
|
addr=>i2c0_addr,
|
|
rw=>i2c0_rw,
|
|
write_data=>i2c0_write_data,
|
|
busy=>i2c0_busy,
|
|
read_data=>i2c0_read_data,
|
|
error=>i2c0_error,
|
|
|
|
int=>iox_int,
|
|
|
|
pot_reset=>pot_reset,
|
|
keyboard_scan=>keyboard_scan,
|
|
keyboard_scan_enable=>keyboard_scan_enable,
|
|
keyboard_response=>keyboard_response
|
|
);
|
|
|
|
-- Wire up pins
|
|
CLK_OUT <= PHI2_6X;
|
|
|
|
ACLK <= SIO_CLOCKOUT;
|
|
BCLK <= '0' when (SIO_CLOCKIN_OE='1' and SIO_CLOCKIN_OUT='0') else 'Z';
|
|
SIO_CLOCKIN_IN <= BCLK;
|
|
|
|
SOD <= '0' when SIO_TXD='0' else 'Z';
|
|
SIO_RXD <= SID;
|
|
|
|
--3
|
|
AUD(3) <= AUDIO_LEFT;
|
|
--4
|
|
AUD(4) <= AUDIO_RIGHT;
|
|
--2
|
|
AUD(2) <= AUDIO_MIXED;
|
|
--gnd
|
|
--
|
|
--1->pin37
|
|
AUD(1) <= AUDIO_MIXED;
|
|
|
|
IRQ <= '0' when POKEY_IRQ='0' else 'Z';
|
|
|
|
D <= BUS_DATA when BUS_OE='1' else (others=>'Z');
|
|
|
|
END vhdl;
|