mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-05-01 22:26:35 +00:00
349 lines
14 KiB
VHDL
349 lines
14 KiB
VHDL
-------------------------------------------------------------------------------
|
|
--
|
|
-- SID 6581
|
|
--
|
|
-- A fully functional SID chip implementation in VHDL
|
|
--
|
|
-------------------------------------------------------------------------------
|
|
-- to do: - filter
|
|
-- - smaller implementation, use multiplexed channels
|
|
--
|
|
--
|
|
-- "The Filter was a classic multi-mode (state variable) VCF design. There was
|
|
-- no way to create a variable transconductance amplifier in our NMOS process,
|
|
-- so I simply used FETs as voltage-controlled resistors to control the cutoff
|
|
-- frequency. An 11-bit D/A converter generates the control voltage for the
|
|
-- FETs (it's actually a 12-bit D/A, but the LSB had no audible affect so I
|
|
-- disconnected it!)."
|
|
-- "Filter resonance was controlled by a 4-bit weighted resistor ladder. Each
|
|
-- bit would turn on one of the weighted resistors and allow a portion of the
|
|
-- output to feed back to the input. The state-variable design provided
|
|
-- simultaneous low-pass, band-pass and high-pass outputs. Analog switches
|
|
-- selected which combination of outputs were sent to the final amplifier (a
|
|
-- notch filter was created by enabling both the high and low-pass outputs
|
|
-- simultaneously)."
|
|
-- "The filter is the worst part of SID because I could not create high-gain
|
|
-- op-amps in NMOS, which were essential to a resonant filter. In addition,
|
|
-- the resistance of the FETs varied considerably with processing, so different
|
|
-- lots of SID chips had different cutoff frequency characteristics. I knew it
|
|
-- wouldn't work very well, but it was better than nothing and I didn't have
|
|
-- time to make it better."
|
|
--
|
|
-------------------------------------------------------------------------------
|
|
|
|
library IEEE;
|
|
use IEEE.std_logic_1164.all;
|
|
use IEEE.std_logic_unsigned.all;
|
|
use IEEE.numeric_std.all;
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
entity sid_6581 is
|
|
port (
|
|
clk_1MHz : in std_logic; -- main SID clock signal
|
|
clk32 : in std_logic; -- main clock signal
|
|
reset : in std_logic; -- high active signal (reset when reset = '1')
|
|
cs : in std_logic; -- "chip select", when this signal is '1' this model can be accessed
|
|
we : in std_logic; -- when '1' this model can be written to, otherwise access is considered as read
|
|
|
|
addr : in std_logic_vector(4 downto 0); -- address lines
|
|
data_i : in std_logic_vector(7 downto 0); -- data in (to chip)
|
|
data_o : out std_logic_vector(7 downto 0); -- data out (from chip)
|
|
|
|
poti_x : in std_logic; -- paddle input-X
|
|
poti_y : in std_logic; -- paddle input-Y
|
|
audio_data : out std_logic_vector(17 downto 0)
|
|
);
|
|
end sid_6581;
|
|
|
|
architecture Behavioral of sid_6581 is
|
|
|
|
component pwm_sdadc is
|
|
port (
|
|
clk : in std_logic; -- main clock signal (actually the higher the better)
|
|
reset : in std_logic; --
|
|
ADC_out : out std_logic_vector(7 downto 0); -- binary input of signal to be converted
|
|
ADC_in : in std_logic -- "analog" paddle input pin
|
|
);
|
|
end component;
|
|
|
|
-- Implementation of the SID voices (sound channels)
|
|
component sid_voice is
|
|
port (
|
|
clk_1MHz : in std_logic; -- this line drives the oscilator
|
|
reset : in std_logic; -- active high signal (i.e. registers are reset when reset=1)
|
|
Freq_lo : in std_logic_vector(7 downto 0); --
|
|
Freq_hi : in std_logic_vector(7 downto 0); --
|
|
Pw_lo : in std_logic_vector(7 downto 0); --
|
|
Pw_hi : in std_logic_vector(3 downto 0); --
|
|
Control : in std_logic_vector(7 downto 0); --
|
|
Att_dec : in std_logic_vector(7 downto 0); --
|
|
Sus_Rel : in std_logic_vector(7 downto 0); --
|
|
PA_MSB_in : in std_logic; --
|
|
PA_MSB_out : out std_logic; --
|
|
Osc : out std_logic_vector(7 downto 0); --
|
|
Env : out std_logic_vector(7 downto 0); --
|
|
voice : out std_logic_vector(11 downto 0) --
|
|
);
|
|
end component;
|
|
|
|
-------------------------------------------------------------------------------
|
|
--constant <name>: <type> := <value>;
|
|
-- DC offset required to play samples, this is actually a bug of the real 6581,
|
|
-- that was converted into an advantage to play samples
|
|
constant DC_offset : std_logic_vector(13 downto 0) := "00111111111111";
|
|
-------------------------------------------------------------------------------
|
|
|
|
signal Voice_1_Freq_lo : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_1_Freq_hi : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_1_Pw_lo : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_1_Pw_hi : std_logic_vector(3 downto 0) := (others => '0');
|
|
signal Voice_1_Control : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_1_Att_dec : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_1_Sus_Rel : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_1_Osc : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_1_Env : std_logic_vector(7 downto 0) := (others => '0');
|
|
|
|
signal Voice_2_Freq_lo : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_2_Freq_hi : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_2_Pw_lo : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_2_Pw_hi : std_logic_vector(3 downto 0) := (others => '0');
|
|
signal Voice_2_Control : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_2_Att_dec : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_2_Sus_Rel : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_2_Osc : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_2_Env : std_logic_vector(7 downto 0) := (others => '0');
|
|
|
|
signal Voice_3_Freq_lo : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_3_Freq_hi : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_3_Pw_lo : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_3_Pw_hi : std_logic_vector(3 downto 0) := (others => '0');
|
|
signal Voice_3_Control : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_3_Att_dec : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Voice_3_Sus_Rel : std_logic_vector(7 downto 0) := (others => '0');
|
|
|
|
signal Filter_Fc_lo : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Filter_Fc_hi : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Filter_Res_Filt : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Filter_Mode_Vol : std_logic_vector(7 downto 0) := (others => '0');
|
|
|
|
signal Misc_PotX : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Misc_PotY : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Misc_Osc3_Random : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal Misc_Env3 : std_logic_vector(7 downto 0) := (others => '0');
|
|
|
|
signal do_buf : std_logic_vector(7 downto 0) := (others => '0');
|
|
|
|
signal voice_1 : std_logic_vector(11 downto 0) := (others => '0');
|
|
signal voice_2 : std_logic_vector(11 downto 0) := (others => '0');
|
|
signal voice_3 : std_logic_vector(11 downto 0) := (others => '0');
|
|
signal voice_mixed : std_logic_vector(13 downto 0) := (others => '0');
|
|
|
|
signal divide_0 : std_logic_vector(31 downto 0) := (others => '0');
|
|
signal voice_1_PA_MSB : std_logic := '0';
|
|
signal voice_2_PA_MSB : std_logic := '0';
|
|
signal voice_3_PA_MSB : std_logic := '0';
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
begin
|
|
|
|
paddle_x: pwm_sdadc
|
|
port map (
|
|
clk => clk_1MHz,
|
|
reset => reset,
|
|
ADC_out => Misc_PotX,
|
|
ADC_in => poti_x
|
|
);
|
|
|
|
paddle_y: pwm_sdadc
|
|
port map (
|
|
clk => clk_1MHz,
|
|
reset => reset,
|
|
ADC_out => Misc_PotY,
|
|
ADC_in => poti_y
|
|
);
|
|
|
|
sid_voice_1: sid_voice
|
|
port map(
|
|
clk_1MHz => clk_1MHz,
|
|
reset => reset,
|
|
Freq_lo => Voice_1_Freq_lo,
|
|
Freq_hi => Voice_1_Freq_hi,
|
|
Pw_lo => Voice_1_Pw_lo,
|
|
Pw_hi => Voice_1_Pw_hi,
|
|
Control => Voice_1_Control,
|
|
Att_dec => Voice_1_Att_dec,
|
|
Sus_Rel => Voice_1_Sus_Rel,
|
|
PA_MSB_in => voice_3_PA_MSB,
|
|
PA_MSB_out => voice_1_PA_MSB,
|
|
Osc => Voice_1_Osc,
|
|
Env => Voice_1_Env,
|
|
voice => voice_1
|
|
);
|
|
|
|
sid_voice_2: sid_voice
|
|
port map(
|
|
clk_1MHz => clk_1MHz,
|
|
reset => reset,
|
|
Freq_lo => Voice_2_Freq_lo,
|
|
Freq_hi => Voice_2_Freq_hi,
|
|
Pw_lo => Voice_2_Pw_lo,
|
|
Pw_hi => Voice_2_Pw_hi,
|
|
Control => Voice_2_Control,
|
|
Att_dec => Voice_2_Att_dec,
|
|
Sus_Rel => Voice_2_Sus_Rel,
|
|
PA_MSB_in => voice_1_PA_MSB,
|
|
PA_MSB_out => voice_2_PA_MSB,
|
|
Osc => Voice_2_Osc,
|
|
Env => Voice_2_Env,
|
|
voice => voice_2
|
|
);
|
|
|
|
sid_voice_3: sid_voice
|
|
port map(
|
|
clk_1MHz => clk_1MHz,
|
|
reset => reset,
|
|
Freq_lo => Voice_3_Freq_lo,
|
|
Freq_hi => Voice_3_Freq_hi,
|
|
Pw_lo => Voice_3_Pw_lo,
|
|
Pw_hi => Voice_3_Pw_hi,
|
|
Control => Voice_3_Control,
|
|
Att_dec => Voice_3_Att_dec,
|
|
Sus_Rel => Voice_3_Sus_Rel,
|
|
PA_MSB_in => voice_2_PA_MSB,
|
|
PA_MSB_out => voice_3_PA_MSB,
|
|
Osc => Misc_Osc3_Random,
|
|
Env => Misc_Env3,
|
|
voice => voice_3
|
|
);
|
|
|
|
-------------------------------------------------------------------------------------
|
|
data_o <= do_buf;
|
|
|
|
-- add voice 1+2 and 3, we must do this in this way to create the shortest
|
|
-- timing path (keep in mind that a basic adder can only add two variables)
|
|
voice_mixed <= (("00" & voice_1) + ("00" & voice_2)) + (voice_3 + DC_offset);
|
|
-- multiply the volume register with the voices
|
|
audio_data <= (voice_mixed * Filter_Mode_Vol(3 downto 0));
|
|
|
|
-- Register decoding
|
|
register_decoder:process(clk32)
|
|
begin
|
|
if rising_edge(clk32) then
|
|
if (reset = '1') then
|
|
--------------------------------------- Voice-1
|
|
Voice_1_Freq_lo <= (others => '0');
|
|
Voice_1_Freq_hi <= (others => '0');
|
|
Voice_1_Pw_lo <= (others => '0');
|
|
Voice_1_Pw_hi <= (others => '0');
|
|
Voice_1_Control <= (others => '0');
|
|
Voice_1_Att_dec <= (others => '0');
|
|
Voice_1_Sus_Rel <= (others => '0');
|
|
--------------------------------------- Voice-2
|
|
Voice_2_Freq_lo <= (others => '0');
|
|
Voice_2_Freq_hi <= (others => '0');
|
|
Voice_2_Pw_lo <= (others => '0');
|
|
Voice_2_Pw_hi <= (others => '0');
|
|
Voice_2_Control <= (others => '0');
|
|
Voice_2_Att_dec <= (others => '0');
|
|
Voice_2_Sus_Rel <= (others => '0');
|
|
--------------------------------------- Voice-3
|
|
Voice_3_Freq_lo <= (others => '0');
|
|
Voice_3_Freq_hi <= (others => '0');
|
|
Voice_3_Pw_lo <= (others => '0');
|
|
Voice_3_Pw_hi <= (others => '0');
|
|
Voice_3_Control <= (others => '0');
|
|
Voice_3_Att_dec <= (others => '0');
|
|
Voice_3_Sus_Rel <= (others => '0');
|
|
--------------------------------------- Filter & volume
|
|
Filter_Fc_lo <= (others => '0');
|
|
Filter_Fc_hi <= (others => '0');
|
|
Filter_Res_Filt <= (others => '0');
|
|
Filter_Mode_Vol <= (others => '0');
|
|
else
|
|
Voice_1_Freq_lo <= Voice_1_Freq_lo;
|
|
Voice_1_Freq_hi <= Voice_1_Freq_hi;
|
|
Voice_1_Pw_lo <= Voice_1_Pw_lo;
|
|
Voice_1_Pw_hi <= Voice_1_Pw_hi;
|
|
Voice_1_Control <= Voice_1_Control;
|
|
Voice_1_Att_dec <= Voice_1_Att_dec;
|
|
Voice_1_Sus_Rel <= Voice_1_Sus_Rel;
|
|
Voice_2_Freq_lo <= Voice_2_Freq_lo;
|
|
Voice_2_Freq_hi <= Voice_2_Freq_hi;
|
|
Voice_2_Pw_lo <= Voice_2_Pw_lo;
|
|
Voice_2_Pw_hi <= Voice_2_Pw_hi;
|
|
Voice_2_Control <= Voice_2_Control;
|
|
Voice_2_Att_dec <= Voice_2_Att_dec;
|
|
Voice_2_Sus_Rel <= Voice_2_Sus_Rel;
|
|
Voice_3_Freq_lo <= Voice_3_Freq_lo;
|
|
Voice_3_Freq_hi <= Voice_3_Freq_hi;
|
|
Voice_3_Pw_lo <= Voice_3_Pw_lo;
|
|
Voice_3_Pw_hi <= Voice_3_Pw_hi;
|
|
Voice_3_Control <= Voice_3_Control;
|
|
Voice_3_Att_dec <= Voice_3_Att_dec;
|
|
Voice_3_Sus_Rel <= Voice_3_Sus_Rel;
|
|
Filter_Fc_lo <= Filter_Fc_lo;
|
|
Filter_Fc_hi <= Filter_Fc_hi;
|
|
Filter_Res_Filt <= Filter_Res_Filt;
|
|
Filter_Mode_Vol <= Filter_Mode_Vol;
|
|
do_buf <= (others => '0');
|
|
|
|
if (cs='1') then
|
|
if (we='1') then -- Write to SID-register
|
|
------------------------
|
|
case addr is
|
|
-------------------------------------- Voice-1
|
|
when "00000" => Voice_1_Freq_lo <= data_i;
|
|
when "00001" => Voice_1_Freq_hi <= data_i;
|
|
when "00010" => Voice_1_Pw_lo <= data_i;
|
|
when "00011" => Voice_1_Pw_hi <= data_i(3 downto 0);
|
|
when "00100" => Voice_1_Control <= data_i;
|
|
when "00101" => Voice_1_Att_dec <= data_i;
|
|
when "00110" => Voice_1_Sus_Rel <= data_i;
|
|
--------------------------------------- Voice-2
|
|
when "00111" => Voice_2_Freq_lo <= data_i;
|
|
when "01000" => Voice_2_Freq_hi <= data_i;
|
|
when "01001" => Voice_2_Pw_lo <= data_i;
|
|
when "01010" => Voice_2_Pw_hi <= data_i(3 downto 0);
|
|
when "01011" => Voice_2_Control <= data_i;
|
|
when "01100" => Voice_2_Att_dec <= data_i;
|
|
when "01101" => Voice_2_Sus_Rel <= data_i;
|
|
--------------------------------------- Voice-3
|
|
when "01110" => Voice_3_Freq_lo <= data_i;
|
|
when "01111" => Voice_3_Freq_hi <= data_i;
|
|
when "10000" => Voice_3_Pw_lo <= data_i;
|
|
when "10001" => Voice_3_Pw_hi <= data_i(3 downto 0);
|
|
when "10010" => Voice_3_Control <= data_i;
|
|
when "10011" => Voice_3_Att_dec <= data_i;
|
|
when "10100" => Voice_3_Sus_Rel <= data_i;
|
|
--------------------------------------- Filter & volume
|
|
when "10101" => Filter_Fc_lo <= data_i;
|
|
when "10110" => Filter_Fc_hi <= data_i;
|
|
when "10111" => Filter_Res_Filt <= data_i;
|
|
when "11000" => Filter_Mode_Vol <= data_i;
|
|
--------------------------------------
|
|
when others => null;
|
|
end case;
|
|
|
|
else -- Read from SID-register
|
|
-------------------------
|
|
--case CONV_INTEGER(addr) is
|
|
case addr is
|
|
-------------------------------------- Misc
|
|
when "11001" => do_buf <= Misc_PotX;
|
|
when "11010" => do_buf <= Misc_PotY;
|
|
when "11011" => do_buf <= Misc_Osc3_Random;
|
|
when "11100" => do_buf <= Misc_Env3;
|
|
--------------------------------------
|
|
-- when others => null;
|
|
when others => do_buf <= (others => '0');
|
|
end case;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
end Behavioral;
|