add experimental SID 6581

This commit is contained in:
nino-porcino 2022-01-15 10:12:46 +01:00
parent 071afcf1b1
commit cb7aeba5a9
16 changed files with 2627 additions and 10 deletions

View File

@ -202,6 +202,18 @@ set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:rtl/build_id.tcl"
# end ENTITY(apple1_mist)
# -----------------------
set_global_assignment -name VHDL_FILE rtl/sid/wave_map.vhd
set_global_assignment -name VHDL_FILE rtl/sid/sid_top.vhd
set_global_assignment -name VHDL_FILE rtl/sid/sid_regs.vhd
set_global_assignment -name VHDL_FILE rtl/sid/sid_mixer.vhd
set_global_assignment -name VHDL_FILE rtl/sid/sid_filter.vhd
set_global_assignment -name VHDL_FILE rtl/sid/sid_debug_pkg.vhd
set_global_assignment -name VHDL_FILE rtl/sid/sid_ctrl.vhd
set_global_assignment -name VHDL_FILE rtl/sid/Q_table.vhd
set_global_assignment -name VHDL_FILE rtl/sid/oscillator.vhd
set_global_assignment -name VHDL_FILE rtl/sid/my_math_pkg.vhd
set_global_assignment -name VHDL_FILE rtl/sid/mult_acc.vhd
set_global_assignment -name VHDL_FILE rtl/sid/adsr_multi.vhd
set_global_assignment -name VERILOG_FILE rtl/aci.v
set_global_assignment -name VERILOG_FILE rtl/display_ram.v
set_global_assignment -name VERILOG_FILE rtl/tms9918/vram.v

View File

@ -25,8 +25,7 @@
// TODO display: emulate PIA registers
// TODO tms9918: fix video sync on composite and mist_video
// TODO tms9918: make it selectable / use include in code
// TODO sid: implement 6581
// *TODO make it work with SDRAM
// TODO sid: unsigned vs signed dac ?
module apple1_mist(
input CLOCK_27,
@ -229,20 +228,33 @@ always @(posedge sys_clock) begin
CASIN <= ~UART_RX; // on the Mistica UART_RX is the audio input
end
wire audio;
wire audio_monitor = st_audio_mon_tape_in ? CASIN : CASOUT ;
wire audio_tape_monitor = st_audio_mon_tape_in ? CASIN : CASOUT ;
dac #(.C_bits(16)) dac_AUDIO
wire audio_tape_monitor_1bit;
dac #(.C_bits(16)) dac_tape_monitor
(
.clk_i(sys_clock),
.res_n_i(pll_locked),
.dac_i({ audio_monitor, 15'b0000000 }),
.dac_o(audio)
.dac_i({ audio_tape_monitor, 15'b0000000 }),
.dac_o(audio_tape_monitor_1bit)
);
wire sid_audio_out_1bit;
wire signed [18:0] sid_audio_out_combined = sid_audio_out_l + sid_audio_out_r;
wire signed [15:0] sid_audio_out_combined1 = sid_audio_out_combined[18:3];
wire [15:0] sid_audio_out_combined2 = sid_audio_out_combined1 + 32767;
dac #(.C_bits(16)) dac_SID
(
.clk_i(sys_clock),
.res_n_i(pll_locked),
.dac_i(sid_audio_out_combined2),
.dac_o(sid_audio_out_1bit)
);
always @(posedge sys_clock) begin
AUDIO_L <= audio;
AUDIO_R <= audio;
AUDIO_L <= audio_tape_monitor_1bit;
AUDIO_R <= sid_audio_out_1bit;
end
/******************************************************************************************/
@ -288,12 +300,14 @@ wire ram_cs = sdram_addr < 'h4000; // 0x0000 -> 0x3FF
wire sdram_cs = sdram_addr >= 'h4000 && sdram_addr <= 'hBFFF; // 0x4000 -> 0xBFFF
wire aci_cs = sdram_addr >= 'hC000 && sdram_addr <= 'hC1FF; // 0xC000 -> 0xC1FF
wire tms_cs = sdram_addr >= 'hCC00 && sdram_addr <= 'hCC01; // 0xCC00 -> 0xCC01
wire sid_cs = sdram_addr >= 'hC200 && sdram_addr <= 'hCCFF; // 0xCC00 -> 0xCCFF
wire basic_cs = sdram_addr >= 'hE000 && sdram_addr <= 'hEFFF; // 0xE000 -> 0xEFFF
wire rom_cs = sdram_addr >= 'hFF00; // 0xFF00 -> 0xFFFF
wire [7:0] bus_dout = rom_cs ? rom_dout :
basic_cs ? basic_dout :
tms_cs ? vdp_dout :
//tms_cs ? vdp_dout :
sid_cs ? vdp_dout :
aci_cs ? aci_dout :
sdram_cs ? sdram_dout :
ram_cs ? ram_dout :
@ -655,5 +669,37 @@ tms9918
.B (tms_B)
);
/******************************************************************************************/
/******************************************************************************************/
/***************************************** @sid *******************************************/
/******************************************************************************************/
/******************************************************************************************/
// TODO generic g_filter_div
wire [7:0] sid_dout;
wire signed [17:0] sid_audio_out_l;
wire signed [17:0] sid_audio_out_r;
sid_top sid_top
(
.clock(sys_clock),
.reset(reset_button),
.addr(sdram_addr[7:0]),
.wren(cpu_wr & sid_cs),
.wdata(sdram_din),
.rdata(sid_dout),
.potx(0),
.poty(0),
.comb_wave_l(0),
.comb_wave_r(0),
.start_iter(cpu_clken),
.sample_left(sid_audio_out_l),
.sample_right(sid_audio_out_r),
.extfilter_en(0)
);
endmodule

BIN
rtl/roms/rom.S2513.bin Normal file

Binary file not shown.

512
rtl/roms/s2513.bin Normal file
View File

@ -0,0 +1,512 @@
00000000
00011100
00100010
00101100
00101010
00101010
00101010
00011100
00000000
00001000
00010100
00100010
00100010
00111110
00100010
00100010
00000000
00011110
00100010
00100010
00011110
00100010
00100010
00011110
00000000
00011100
00100010
00000010
00000010
00000010
00100010
00011100
00000000
00011110
00100010
00100010
00100010
00100010
00100010
00011110
00000000
00111110
00000010
00000010
00011110
00000010
00000010
00111110
00000000
00111110
00000010
00000010
00011110
00000010
00000010
00000010
00000000
00011100
00100010
00000010
00111010
00100010
00100010
00011100
00000000
00100010
00100010
00100010
00111110
00100010
00100010
00100010
00000000
00011100
00001000
00001000
00001000
00001000
00001000
00011100
00000000
00111000
00010000
00010000
00010000
00010000
00010010
00001100
00000000
00100010
00010010
00001010
00000110
00001010
00010010
00100010
00000000
00000010
00000010
00000010
00000010
00000010
00000010
00111110
00000000
00100010
00110110
00101010
00101010
00100010
00100010
00100010
00000000
00100010
00100010
00100110
00101010
00110010
00100010
00100010
00000000
00011100
00100010
00100010
00100010
00100010
00100010
00011100
00000000
00011110
00100010
00100010
00011110
00000010
00000010
00000010
00000000
00011100
00100010
00100010
00100010
00101010
00010010
00101100
00000000
00011110
00100010
00100010
00011110
00100010
00100010
00100010
00000000
00011100
00100010
00000010
00011100
00100000
00100010
00011100
00000000
00111110
00001000
00001000
00001000
00001000
00001000
00001000
00000000
00100010
00100010
00100010
00100010
00100010
00100010
00011100
00000000
00100010
00100010
00100010
00100010
00100010
00010100
00001000
00000000
00100010
00100010
00100010
00101010
00101010
00101010
00010100
00000000
00100010
00100010
00010100
00001000
00010100
00100010
00100010
00000000
00100010
00100010
00100010
00010100
00001000
00001000
00001000
00000000
00111110
00100000
00010000
00001000
00000100
00000010
00111110
00000000
00111110
00000110
00000110
00000110
00000110
00000110
00111110
00000000
00000000
00000010
00000100
00001000
00010000
00100000
00000000
00000000
00111110
00110000
00110000
00110000
00110000
00110000
00111110
00000000
00000000
00000000
00001000
00010100
00100010
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
01111110
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00001000
00001000
00001000
00001000
00001000
00000000
00001000
00000000
00010100
00010100
00010100
00000000
00000000
00000000
00000000
00000000
00010100
00010100
00111110
00010100
00111110
00010100
00010100
00000000
00001000
00111100
00001010
00011100
00101000
00011110
00001000
00000000
00000110
00100110
00010000
00001000
00000100
00110010
00110000
00000000
00000100
00001010
00001010
00000100
00101010
00010010
00101100
00000000
00001000
00001000
00001000
00000000
00000000
00000000
00000000
00000000
00001000
00000100
00000010
00000010
00000010
00000100
00001000
00000000
00001000
00010000
00100000
00100000
00100000
00010000
00001000
00000000
00001000
00101010
00011100
00001000
00011100
00101010
00001000
00000000
00000000
00001000
00001000
00111110
00001000
00001000
00000000
00000000
00000000
00000000
00000000
00000000
00001000
00001000
00000100
00000000
00000000
00000000
00000000
00111110
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00001000
00000000
00000000
00100000
00010000
00001000
00000100
00000010
00000000
00000000
00011100
00100010
00110010
00101010
00100110
00100010
00011100
00000000
00001000
00001100
00001000
00001000
00001000
00001000
00011100
00000000
00011100
00100010
00100000
00011000
00000100
00000010
00111110
00000000
00111110
00100000
00010000
00011000
00100000
00100010
00011100
00000000
00010000
00011000
00010100
00010010
00111110
00010000
00010000
00000000
00111110
00000010
00011110
00100000
00100000
00100010
00011100
00000000
00111000
00000100
00000010
00011110
00100010
00100010
00011100
00000000
00111110
00100000
00010000
00001000
00000100
00000100
00000100
00000000
00011100
00100010
00100010
00011100
00100010
00100010
00011100
00000000
00011100
00100010
00100010
00111100
00100000
00010000
00001110
00000000
00000000
00001000
00001000
00000000
00000000
00001000
00001000
00000000
00000000
00000000
00001000
00000000
00001000
00001000
00000100
00000000
00010000
00001000
00000100
00000010
00000100
00001000
00010000
00000000
00000000
00000000
00111110
00000000
00111110
00000000
00000000
00000000
00000100
00001000
00010000
00100000
00010000
00001000
00000100
00000000
00011100
00100010
00010000
00001000
00001000
00000000
00001000

45
rtl/sid/Q_table.vhd Normal file
View File

@ -0,0 +1,45 @@
-------------------------------------------------------------------------------
--
-- (C) COPYRIGHT 2010 Gideon's Logic Architectures'
--
-------------------------------------------------------------------------------
--
-- Author: Gideon Zweijtzer (gideon.zweijtzer (at) gmail.com)
--
-- Note that this file is copyrighted, and is not supposed to be used in other
-- projects without written permission from the author.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Q_table is
port (
Q_reg : in unsigned(3 downto 0);
filter_q : out signed(17 downto 0) );
end Q_table;
architecture Gideon of Q_table is
type t_18_bit_array is array(natural range <>) of signed(17 downto 0);
function create_factors(max_Q: real) return t_18_bit_array is
constant critical : real := 0.70710678; -- no resonance at 0.5*sqrt(2)
variable q_step : real;
variable q : real;
variable scaled : real;
variable ret : t_18_bit_array(0 to 15);
begin
q_step := (max_Q - critical) / 15.0; -- linear
for i in 0 to 15 loop
q := critical + (real(i) * q_step);
scaled := 65536.0 / q;
ret(i) := to_signed(integer(scaled), 18);
end loop;
return ret;
end function;
constant c_table : t_18_bit_array(0 to 15) := create_factors(1.8);
begin
filter_q <= c_table(to_integer(Q_reg));
end Gideon;

220
rtl/sid/adsr_multi.vhd Normal file
View File

@ -0,0 +1,220 @@
-------------------------------------------------------------------------------
--
-- (C) COPYRIGHT 2010 Gideon's Logic Architectures'
--
-------------------------------------------------------------------------------
--
-- Author: Gideon Zweijtzer (gideon.zweijtzer (at) gmail.com)
--
-- Note that this file is copyrighted, and is not supposed to be used in other
-- projects without written permission from the author.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.sid_debug_pkg.all;
-- LUT: 195, FF:68
entity adsr_multi is
generic (
g_num_voices : integer := 8 );
port (
clock : in std_logic;
reset : in std_logic;
voice_i : in unsigned(3 downto 0);
enable_i : in std_logic;
voice_o : out unsigned(3 downto 0);
enable_o : out std_logic;
gate : in std_logic;
attack : in std_logic_vector(3 downto 0);
decay : in std_logic_vector(3 downto 0);
sustain : in std_logic_vector(3 downto 0);
release : in std_logic_vector(3 downto 0);
env_state: out std_logic_vector(1 downto 0); -- for testing only
env_out : out unsigned(7 downto 0) );
end adsr_multi;
-- 158 1 62 .. FF
-- 45 2 35 .. 61
-- 26 4 1C .. 34
-- 13 8 0D .. 1B
-- 6 16 07 .. 0C
-- 7 30 00 .. 06
architecture gideon of adsr_multi is
type presc_array_t is array(natural range <>) of unsigned(15 downto 0);
constant prescalers : presc_array_t(0 to 15) := (
X"0008", X"001F", X"003E", X"005E",
X"0094", X"00DB", X"010A", X"0138",
X"0187", X"03D0", X"07A1", X"0C35",
X"0F42", X"2DC7", X"4C4B", X"7A12" );
signal enveloppe : unsigned(7 downto 0) := (others => '0');
signal state : unsigned(1 downto 0) := (others => '0');
constant st_release : unsigned(1 downto 0) := "00";
constant st_attack : unsigned(1 downto 0) := "01";
constant st_decay : unsigned(1 downto 0) := "11";
type state_array_t is array(natural range <>) of unsigned(29 downto 0);
signal state_array : state_array_t(0 to g_num_voices-1) := (others => (others => '0'));
begin
env_out <= enveloppe;
env_state <= std_logic_vector(state);
-- FF-5E 01
-- 5D-37 02
-- 36-1B 04
-- 1A-0F 08
-- 0E-07 10
-- 06-01 1E
process(clock)
function logarithmic(lev: unsigned(7 downto 0)) return unsigned is
variable res : unsigned(4 downto 0);
begin
if lev = X"00" then
res := "00000"; -- prescaler off
elsif lev < X"07" then
res := "11101"; -- 1E-1
elsif lev < X"0F" then
res := "01111"; -- 10-1
elsif lev < X"1B" then
res := "00111"; -- 08-1
elsif lev < X"37" then
res := "00011"; -- 04-1
elsif lev < X"5E" then
res := "00001"; -- 02-1
else
res := "00000"; -- 01-1
end if;
return res;
end function logarithmic;
variable presc_select : integer range 0 to 15;
variable cur_state : unsigned(1 downto 0);
variable cur_env : unsigned(7 downto 0);
variable cur_pre15 : unsigned(14 downto 0);
variable cur_pre5 : unsigned(4 downto 0);
variable next_state : unsigned(1 downto 0);
variable next_env : unsigned(7 downto 0);
variable next_pre15 : unsigned(14 downto 0);
variable next_pre5 : unsigned(4 downto 0);
variable presc_val : unsigned(14 downto 0);
variable log_div : unsigned(4 downto 0);
variable do_count_15 : std_logic;
variable do_count_5 : std_logic;
begin
if rising_edge(clock) then
cur_state := state_array(0)(1 downto 0);
cur_env := state_array(0)(9 downto 2);
cur_pre15 := state_array(0)(24 downto 10);
cur_pre5 := state_array(0)(29 downto 25);
voice_o <= voice_i;
enable_o <= enable_i;
next_state := cur_state;
next_env := cur_env;
next_pre15 := cur_pre15;
next_pre5 := cur_pre5;
-- PRESCALER LOGIC, output: do_count --
-- 15 bit prescaler select --
case cur_state is
when st_attack =>
presc_select := to_integer(unsigned(attack));
when st_decay =>
presc_select := to_integer(unsigned(decay));
when others => -- includes release and idle
presc_select := to_integer(unsigned(release));
end case;
presc_val := prescalers(presc_select)(14 downto 0);
-- 15 bit prescaler counter --
do_count_15 := '0';
if cur_pre15 = presc_val then
next_pre15 := (others => '0');
do_count_15 := '1';
else
next_pre15 := cur_pre15 + 1;
end if;
-- 5 bit prescaler --
log_div := logarithmic(cur_env);
do_count_5 := '0';
if do_count_15='1' then
if (cur_state = st_attack) or cur_pre5 = log_div then
next_pre5 := "00000";
do_count_5 := '1';
else
next_pre5 := cur_pre5 + 1;
end if;
end if;
-- END PRESCALER LOGIC --
case cur_state is
when st_attack =>
if gate = '0' then
next_state := st_release;
elsif cur_env = X"FF" then
next_state := st_decay;
end if;
if do_count_15='1' then
next_env := cur_env + 1;
-- if cur_env = X"FE" or cur_env = X"FF" then -- result could be FF, but also 00!!
-- next_state := st_decay;
-- end if;
end if;
when st_decay =>
if gate = '0' then
next_state := st_release;
end if;
if do_count_15='1' and do_count_5='1' and
std_logic_vector(cur_env) /= (sustain & sustain) and
cur_env /= X"00" then
next_env := cur_env - 1;
end if;
when st_release =>
if gate = '1' then
next_state := st_attack;
end if;
if do_count_15='1' and do_count_5='1' and
cur_env /= X"00" then
next_env := cur_env - 1;
end if;
when others =>
next_state := st_release;
end case;
if enable_i='1' then
state_array(0 to g_num_voices-2) <= state_array(1 to g_num_voices-1);
state_array(g_num_voices-1) <= next_pre5 & next_pre15 & next_env & next_state;
enveloppe <= next_env;
state <= next_state;
end if;
if reset='1' then
state <= "00";
enveloppe <= (others => '0');
enable_o <= '0';
end if;
end if;
end process;
end gideon;

209
rtl/sid/mult_acc.vhd Normal file
View File

@ -0,0 +1,209 @@
-------------------------------------------------------------------------------
--
-- (C) COPYRIGHT 2010 Gideon's Logic Architectures'
--
-------------------------------------------------------------------------------
--
-- Author: Gideon Zweijtzer (gideon.zweijtzer (at) gmail.com)
--
-- Note that this file is copyrighted, and is not supposed to be used in other
-- projects without written permission from the author.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.my_math_pkg.all;
entity mult_acc is
port (
clock : in std_logic;
reset : in std_logic;
voice_i : in unsigned(3 downto 0);
enable_i : in std_logic;
voice3_off_l : in std_logic;
voice3_off_r : in std_logic;
filter_en : in std_logic := '0';
enveloppe : in unsigned(7 downto 0);
waveform : in unsigned(11 downto 0);
--
osc3 : out std_logic_vector(7 downto 0);
env3 : out std_logic_vector(7 downto 0);
--
valid_out : out std_logic;
direct_out_L : out signed(17 downto 0);
direct_out_R : out signed(17 downto 0);
filter_out_L : out signed(17 downto 0);
filter_out_R : out signed(17 downto 0) );
end mult_acc;
-- architecture unsigned_wave of mult_acc is
-- signal filter_m : std_logic;
-- signal voice_m : unsigned(3 downto 0);
-- signal mult_m : unsigned(19 downto 0);
-- signal accu_f : unsigned(17 downto 0);
-- signal accu_u : unsigned(17 downto 0);
-- signal enable_d : std_logic;
-- signal direct_i : unsigned(17 downto 0);
-- signal filter_i : unsigned(17 downto 0);
-- begin
-- process(clock)
-- variable mult_ext : unsigned(21 downto 0);
-- variable mult_trunc : unsigned(21 downto 4);
-- begin
-- if rising_edge(clock) then
-- -- latch outputs
-- if reset='1' then
-- osc3 <= (others => '0');
-- env3 <= (others => '0');
-- elsif voice_i = X"2" then
-- osc3 <= std_logic_vector(waveform(11 downto 4));
-- env3 <= std_logic_vector(enveloppe);
-- end if;
--
-- mult_ext := extend(mult_m, mult_ext'length);
-- mult_trunc := mult_ext(mult_trunc'range);
-- filter_m <= filter_en;
-- voice_m <= voice_i;
-- mult_m <= enveloppe * waveform;
-- valid_out <= '0';
-- enable_d <= enable_i;
--
-- if enable_d='1' then
-- if voice_m = 0 then
-- valid_out <= '1';
-- direct_i <= accu_u;
-- filter_i <= accu_f;
-- if filter_m='1' then
-- accu_f <= mult_trunc;
-- accu_u <= (others => '0');
-- else
-- accu_f <= (others => '0');
-- accu_u <= mult_trunc;
-- end if;
-- else
-- valid_out <= '0';
-- if filter_m='1' then
-- accu_f <= sum_limit(accu_f, mult_trunc);
-- else
-- if (voice_m /= 2) or (voice3_off = '0') then
-- accu_u <= sum_limit(accu_u, mult_trunc);
-- end if;
-- end if;
-- end if;
-- end if;
--
-- if reset = '1' then
-- valid_out <= '0';
-- accu_u <= (others => '0');
-- accu_f <= (others => '0');
-- direct_i <= (others => '0');
-- filter_i <= (others => '0');
-- end if;
-- end if;
-- end process;
--
-- direct_out <= '0' & signed(direct_i(17 downto 1));
-- filter_out <= '0' & signed(filter_i(17 downto 1));
-- end unsigned_wave;
--
architecture signed_wave of mult_acc is
signal filter_m : std_logic;
signal voice_m : unsigned(3 downto 0);
signal mult_m : signed(20 downto 0);
signal accu_fl : signed(17 downto 0);
signal accu_fr : signed(17 downto 0);
signal accu_ul : signed(17 downto 0);
signal accu_ur : signed(17 downto 0);
signal enable_d : std_logic;
begin
process(clock)
variable mult_ext : signed(21 downto 0);
variable mult_trunc : signed(21 downto 4);
variable env_signed : signed(8 downto 0);
variable wave_signed: signed(11 downto 0);
begin
if rising_edge(clock) then
-- latch outputs
if reset='1' then
osc3 <= (others => '0');
env3 <= (others => '0');
elsif voice_i = X"2" then
osc3 <= std_logic_vector(waveform(11 downto 4));
env3 <= std_logic_vector(enveloppe);
end if;
env_signed := '0' & signed(enveloppe);
wave_signed := not waveform(11) & signed(waveform(10 downto 0));
mult_ext := extend(mult_m, mult_ext'length);
mult_trunc := mult_ext(mult_trunc'range);
filter_m <= filter_en;
voice_m <= voice_i;
mult_m <= env_signed * wave_signed;
valid_out <= '0';
enable_d <= enable_i;
if enable_d='1' then
if voice_m = 0 then
valid_out <= '1';
direct_out_l <= accu_ul;
direct_out_r <= accu_ur;
filter_out_l <= accu_fl;
filter_out_r <= accu_fr;
accu_fr <= (others => '0');
accu_ur <= (others => '0');
if filter_m='1' then
accu_fl <= mult_trunc;
accu_ul <= (others => '0');
else
accu_fl <= (others => '0');
accu_ul <= mult_trunc;
end if;
elsif voice_m(3)='0' then
valid_out <= '0';
if filter_m='1' then
accu_fl <= sum_limit(accu_fl, mult_trunc);
else
if (voice_m /= 2) or (voice3_off_l = '0') then
accu_ul <= sum_limit(accu_ul, mult_trunc);
end if;
end if;
else -- upper 8 voices go to right
valid_out <= '0';
if filter_m='1' then
accu_fr <= sum_limit(accu_fr, mult_trunc);
else
if (voice_m /= 10) or (voice3_off_r = '0') then
accu_ur <= sum_limit(accu_ur, mult_trunc);
end if;
end if;
end if;
end if;
if reset = '1' then
valid_out <= '0';
accu_ul <= (others => '0');
accu_fl <= (others => '0');
accu_ur <= (others => '0');
accu_fr <= (others => '0');
direct_out_l <= (others => '0');
direct_out_r <= (others => '0');
filter_out_l <= (others => '0');
filter_out_r <= (others => '0');
end if;
end if;
end process;
end signed_wave;

120
rtl/sid/my_math_pkg.vhd Normal file
View File

@ -0,0 +1,120 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package my_math_pkg is
function sum_limit(i1, i2 : signed) return signed;
function sub_limit(i1, i2 : signed) return signed;
function sum_limit(i1, i2 : unsigned) return unsigned;
function extend(x : signed; len : natural) return signed;
function extend(x : unsigned; len : natural) return unsigned;
function left_align(x : signed; len : natural) return signed;
function left_scale(x : signed; sh : natural) return signed;
-- function shift_right(x : signed; positions: natural) return signed;
end;
package body my_math_pkg is
function sum_limit(i1, i2 : signed) return signed is
variable o : signed(i1'range);
begin
assert i1'length = i2'length
report "i1 and i2 should have the same length!"
severity failure;
o := i1 + i2;
if (i1(i1'left) = i2(i2'left)) and (o(o'left) /= i1(i1'left)) then
if i1(i1'left)='1' then
o := to_signed(-(2**(o'length-1)), o'length);
else
o := to_signed(2**(o'length-1) - 1, o'length);
end if;
end if;
return o;
end function;
function sub_limit(i1, i2 : signed) return signed is
variable o : signed(i1'range);
begin
assert i1'length = i2'length
report "i1 and i2 should have the same length!"
severity failure;
o := i1 - i2;
if (i1(i1'left) /= i2(i2'left)) and (o(o'left) /= i1(i1'left)) then
if i1(i1'left)='1' then
o := to_signed(-(2**(o'length-1)), o'length);
else
o := to_signed(2**(o'length-1) - 1, o'length);
end if;
end if;
return o;
end function;
function sum_limit(i1, i2 : unsigned) return unsigned is
variable o : unsigned(i1'length downto 0);
begin
o := ('0' & i1) + i2;
if o(o'left)='1' then
o := (others => '1');
end if;
return o(i1'length-1 downto 0);
end function;
function extend(x : signed; len : natural) return signed is
variable ret : signed(len-1 downto 0);
alias a : signed(x'length-1 downto 0) is x;
begin
ret := (others => x(x'left));
ret(a'range) := a;
return ret;
end function extend;
function extend(x : unsigned; len : natural) return unsigned is
variable ret : unsigned(len-1 downto 0);
alias a : unsigned(x'length-1 downto 0) is x;
begin
ret := (others => '0');
ret(a'range) := a;
return ret;
end function extend;
function left_align(x : signed; len : natural) return signed is
variable ret : signed(len-1 downto 0);
begin
ret := (others => '0');
ret(len-1 downto len-x'length) := x;
return ret;
end function left_align;
function left_scale(x : signed; sh : natural) return signed is
alias a : signed(x'length-1 downto 0) is x;
variable ret : signed(x'length-(1+sh) downto 0);
variable top : signed(sh downto 0);
begin
if sh=0 then
return x;
end if;
top := a(a'high downto a'high-sh);
if (top = -1) or (top = 0) then -- can shift without getting punished!
ret := a(ret'range);
elsif a(a'high)='1' then -- negative and can't shift, so max neg:
ret := (others => '0');
ret(ret'high) := '1';
else -- positive and can't shift, so max pos
ret := (others => '1');
ret(ret'high) := '0';
end if;
return ret;
end function left_scale;
-- function shift_right(x : signed; positions: natural) return signed is
-- alias a : signed(x'length-1 downto 0) is x;
-- variable ret : signed(x'length-1 downto 0);
-- begin
-- ret := (others => x(x'left));
-- ret(a'left-positions downto 0) := a(a'left downto positions);
-- return ret;
-- end function shift_right;
end;

92
rtl/sid/oscillator.vhd Normal file
View File

@ -0,0 +1,92 @@
-------------------------------------------------------------------------------
--
-- (C) COPYRIGHT 2010 Gideon's Logic Architectures'
--
-------------------------------------------------------------------------------
--
-- Author: Gideon Zweijtzer (gideon.zweijtzer (at) gmail.com)
--
-- Note that this file is copyrighted, and is not supposed to be used in other
-- projects without written permission from the author.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity oscillator is
generic (
g_num_voices : integer := 8);
port (
clock : in std_logic;
reset : in std_logic;
enable_i : in std_logic;
voice_i : in unsigned(3 downto 0);
freq : in unsigned(15 downto 0);
test : in std_logic := '0';
sync : in std_logic := '0';
voice_o : out unsigned(3 downto 0);
enable_o : out std_logic;
test_o : out std_logic;
osc_val : out unsigned(23 downto 0);
carry_20 : out std_logic;
msb_other: out std_logic );
end oscillator;
architecture Gideon of oscillator is
type accu_array_t is array (natural range <>) of unsigned(23 downto 0);
signal accu_reg : accu_array_t(0 to g_num_voices-1) := (others => (others => '0'));
type int4_array is array (natural range <>) of integer range 0 to 15;
constant voice_linkage : int4_array(0 to 15) := ( 2, 0, 1, 7, 3, 4, 5, 6,
10, 8, 9, 15, 11, 12, 13, 14 );
signal ring_index : integer range 0 to 15;
signal sync_index : integer range 0 to 15;
signal msb_register : std_logic_vector(0 to 15) := (others => '0');
signal car_register : std_logic_vector(0 to 15) := (others => '0');
signal do_sync : std_logic;
begin
sync_index <= voice_linkage(to_integer(voice_i));
do_sync <= sync and car_register(sync_index);
ring_index <= voice_linkage(to_integer(voice_i));
process(clock)
variable cur_accu : unsigned(23 downto 0);
variable new_accu : unsigned(24 downto 0);
variable cur_20 : std_logic;
begin
if rising_edge(clock) then
cur_accu := accu_reg(0);
cur_20 := cur_accu(20);
if reset='1' or test='1' or do_sync='1' then
new_accu := (others => '0');
else
new_accu := ('0' & cur_accu) + freq;
end if;
osc_val <= new_accu(23 downto 0);
-- carry <= new_accu(24);
carry_20 <= new_accu(20) xor cur_20;
msb_other <= msb_register(ring_index);
voice_o <= voice_i;
enable_o <= enable_i;
test_o <= test;
if enable_i='1' then
accu_reg(0 to g_num_voices-2) <= accu_reg(1 to g_num_voices-1);
accu_reg(g_num_voices-1) <= new_accu(23 downto 0);
car_register(to_integer(voice_i)) <= new_accu(24);
msb_register(to_integer(voice_i)) <= cur_accu(23);
end if;
end if;
end process;
end Gideon;

58
rtl/sid/sid_ctrl.vhd Normal file
View File

@ -0,0 +1,58 @@
-------------------------------------------------------------------------------
--
-- (C) COPYRIGHT 2010 Gideon's Logic Architectures'
--
-------------------------------------------------------------------------------
--
-- Author: Gideon Zweijtzer (gideon.zweijtzer (at) gmail.com)
--
-- Note that this file is copyrighted, and is not supposed to be used in other
-- projects without written permission from the author.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sid_ctrl is
generic (
g_num_voices : natural := 8 );
port (
clock : in std_logic;
reset : in std_logic;
start_iter : in std_logic;
voice_osc : out unsigned(3 downto 0);
enable_osc : out std_logic );
end sid_ctrl;
architecture gideon of sid_ctrl is
signal voice_cnt : unsigned(3 downto 0);
signal enable : std_logic;
begin
process(clock)
begin
if rising_edge(clock) then
if reset='1' then
voice_cnt <= X"0";
enable <= '0';
elsif start_iter='1' then
voice_cnt <= X"0";
enable <= '1';
elsif voice_cnt = g_num_voices-1 then
voice_cnt <= X"0";
enable <= '0';
elsif enable='1' then
voice_cnt <= voice_cnt + 1;
enable <= '1';
end if;
end if;
end process;
voice_osc <= voice_cnt;
enable_osc <= enable;
end gideon;

35
rtl/sid/sid_debug_pkg.vhd Normal file
View File

@ -0,0 +1,35 @@
-------------------------------------------------------------------------------
--
-- (C) COPYRIGHT 2010 Gideon's Logic Architectures'
--
-------------------------------------------------------------------------------
--
-- Author: Gideon Zweijtzer (gideon.zweijtzer (at) gmail.com)
--
-- Note that this file is copyrighted, and is not supposed to be used in other
-- projects without written permission from the author.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package sid_debug_pkg is
type t_voice_debug is record
state : unsigned(1 downto 0);
enveloppe : unsigned(7 downto 0);
pre15 : unsigned(14 downto 0);
pre5 : unsigned(4 downto 0);
presc : unsigned(14 downto 0);
gate : std_logic;
attack : std_logic_vector(3 downto 0);
decay : std_logic_vector(3 downto 0);
sustain : std_logic_vector(3 downto 0);
release : std_logic_vector(3 downto 0);
end record;
type t_voice_debug_array is array(natural range <>) of t_voice_debug;
end;

309
rtl/sid/sid_filter.vhd Normal file
View File

@ -0,0 +1,309 @@
-------------------------------------------------------------------------------
--
-- (C) COPYRIGHT 2010 Gideon's Logic Architectures'
--
-------------------------------------------------------------------------------
--
-- Author: Gideon Zweijtzer (gideon.zweijtzer (at) gmail.com)
--
-- Note that this file is copyrighted, and is not supposed to be used in other
-- projects without written permission from the author.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.my_math_pkg.all;
entity sid_filter is
generic (
g_divider : natural := 221 );
port (
clock : in std_logic;
reset : in std_logic;
enable : in std_logic;
filt_co : in unsigned(10 downto 0);
filt_res : in unsigned(3 downto 0);
valid_in : in std_logic := '0';
error_out : out std_logic;
input : in signed(17 downto 0);
high_pass : out signed(17 downto 0);
band_pass : out signed(17 downto 0);
low_pass : out signed(17 downto 0);
valid_out : out std_logic );
end sid_filter;
architecture dsvf of sid_filter is
signal filter_q : signed(17 downto 0);
signal filter_f : signed(17 downto 0);
signal input_sc : signed(17 downto 0);
signal filt_ram : std_logic_vector(15 downto 0);
signal xa : signed(17 downto 0);
signal xb : signed(17 downto 0);
signal sum_b : signed(17 downto 0);
signal sub_a : signed(17 downto 0);
signal sub_b : signed(17 downto 0);
signal x_reg : signed(17 downto 0) := (others => '0');
signal bp_reg : signed(17 downto 0);
signal hp_reg : signed(17 downto 0);
signal lp_reg : signed(17 downto 0);
signal temp_reg : signed(17 downto 0);
signal error : std_logic := '0';
signal divider : integer range 0 to g_divider-1;
signal instruction : std_logic_vector(7 downto 0);
type t_byte_array is array(natural range <>) of std_logic_vector(7 downto 0);
constant c_program : t_byte_array := (X"80", X"12", X"81", X"4C", X"82", X"20");
type t_word_array is array(1023 downto 0) of signed(15 downto 0);
constant coef : t_word_array :=
(
X"fff6", X"ffe5", X"ffd4", X"ffc3", X"ffb2", X"ffa0", X"ff8f", X"ff7e",
X"ff6d", X"ff5c", X"ff4a", X"ff39", X"ff28", X"ff17", X"ff06", X"fef4",
X"fee3", X"fed2", X"fec1", X"feb0", X"fe9e", X"fe8d", X"fe7c", X"fe6b",
X"fe5a", X"fe48", X"fe37", X"fe26", X"fe15", X"fe04", X"fdf2", X"fde1",
X"fdd0", X"fdbf", X"fdae", X"fd9c", X"fd8b", X"fd7a", X"fd69", X"fd58",
X"fd46", X"fd35", X"fd24", X"fd13", X"fd02", X"fcf0", X"fcdf", X"fcce",
X"fcbd", X"fcac", X"fc9a", X"fc89", X"fc78", X"fc67", X"fc56", X"fc44",
X"fc33", X"fc22", X"fc11", X"fc00", X"fbee", X"fbdd", X"fbcc", X"fbbb",
X"fb99", X"fb76", X"fb54", X"fb32", X"fb10", X"faee", X"facc", X"faaa",
X"fa88", X"fa65", X"fa43", X"fa21", X"f9ff", X"f9dd", X"f9bb", X"f999",
X"f976", X"f954", X"f932", X"f910", X"f8ee", X"f8cc", X"f8aa", X"f888",
X"f865", X"f843", X"f821", X"f7ff", X"f7dd", X"f7bb", X"f799", X"f776",
X"f754", X"f732", X"f710", X"f6ee", X"f6cc", X"f6aa", X"f688", X"f665",
X"f643", X"f621", X"f5ff", X"f5dd", X"f5bb", X"f599", X"f576", X"f554",
X"f532", X"f510", X"f4ee", X"f4cc", X"f4aa", X"f488", X"f465", X"f443",
X"f421", X"f3ff", X"f3dd", X"f3bb", X"f399", X"f376", X"f354", X"f332",
X"f2f4", X"f2b5", X"f276", X"f238", X"f1f9", X"f1bb", X"f17c", X"f13e",
X"f0ff", X"f0c0", X"f082", X"f043", X"f005", X"efc6", X"ef88", X"ef49",
X"ef0a", X"eecc", X"ee8d", X"ee4f", X"ee10", X"edd2", X"ed93", X"ed54",
X"ed16", X"ecd7", X"ec99", X"ec5a", X"ec1b", X"ebdd", X"eb9e", X"eb60",
X"eb21", X"eae3", X"eaa4", X"ea65", X"ea27", X"e9e8", X"e9aa", X"e96b",
X"e92d", X"e8ee", X"e8af", X"e871", X"e832", X"e7f4", X"e7b5", X"e777",
X"e738", X"e6f9", X"e6bb", X"e67c", X"e63e", X"e5ff", X"e5c0", X"e582",
X"e543", X"e505", X"e4c6", X"e488", X"e449", X"e40a", X"e3cc", X"e38d",
X"e338", X"e2e3", X"e28d", X"e238", X"e1e3", X"e18d", X"e138", X"e0e3",
X"e08d", X"e038", X"dfe3", X"df8d", X"df38", X"dee3", X"de8d", X"de38",
X"dde3", X"dd8d", X"dd38", X"dce3", X"dc8d", X"dc38", X"dbe3", X"db8d",
X"db38", X"dae3", X"da8d", X"da38", X"d9e3", X"d98d", X"d938", X"d8e3",
X"d88d", X"d838", X"d7e3", X"d78d", X"d738", X"d6e3", X"d68d", X"d638",
X"d5e3", X"d58d", X"d538", X"d4e3", X"d48d", X"d438", X"d3e3", X"d38d",
X"d338", X"d2e3", X"d28d", X"d238", X"d1e3", X"d18d", X"d138", X"d0e3",
X"d08d", X"d038", X"cfe3", X"cf8d", X"cf38", X"cee3", X"ce8d", X"ce38",
X"cdaa", X"cd1c", X"cc8d", X"cbff", X"cb71", X"cae3", X"ca54", X"c9c6",
X"c938", X"c8aa", X"c81c", X"c78d", X"c6ff", X"c671", X"c5e3", X"c554",
X"c4c6", X"c438", X"c3aa", X"c31c", X"c28d", X"c1ff", X"c171", X"c0e3",
X"c054", X"bfc6", X"bf38", X"beaa", X"be1c", X"bd8d", X"bcff", X"bc71",
X"bbe3", X"bb54", X"bac6", X"ba38", X"b9aa", X"b91c", X"b88d", X"b7ff",
X"b771", X"b6e3", X"b654", X"b5c6", X"b538", X"b4aa", X"b41c", X"b38d",
X"b2ff", X"b271", X"b1e3", X"b154", X"b0c6", X"b038", X"afaa", X"af1c",
X"ae8d", X"adff", X"ad71", X"ace3", X"ac54", X"abc6", X"ab38", X"aaaa",
X"aa1c", X"a98d", X"a8ff", X"a871", X"a7e3", X"a755", X"a6c6", X"a638",
X"a5aa", X"a51c", X"a48d", X"a3ff", X"a371", X"a2e3", X"a255", X"a1c6",
X"a138", X"a0aa", X"a01c", X"9f8d", X"9eff", X"9e71", X"9de3", X"9d55",
X"9cc6", X"9c38", X"9baa", X"9b1c", X"9a8d", X"99ff", X"9971", X"98e3",
X"9855", X"97c6", X"9738", X"96aa", X"961c", X"958d", X"94ff", X"9471",
X"93e3", X"9355", X"92c6", X"9238", X"91aa", X"911c", X"908d", X"8fff",
X"8f71", X"8ee3", X"8e55", X"8dc6", X"8d38", X"8caa", X"8c1c", X"8b8d",
X"8aff", X"8a71", X"89e3", X"8955", X"88c6", X"8838", X"87aa", X"871c",
X"8699", X"8616", X"8593", X"8510", X"848d", X"840b", X"8388", X"8305",
X"8282", X"81ff", X"817c", X"80fa", X"8077", X"7ff4", X"7f71", X"7eee",
X"7e6b", X"7de8", X"7d66", X"7ce3", X"7c60", X"7bdd", X"7b5a", X"7ad7",
X"7a55", X"79d2", X"794f", X"78cc", X"7849", X"77c6", X"7744", X"76c1",
X"763e", X"75bb", X"7538", X"74b5", X"7432", X"73b0", X"732d", X"72aa",
X"7227", X"71a4", X"7121", X"709f", X"701c", X"6f99", X"6f16", X"6e93",
X"6e10", X"6d8e", X"6d0b", X"6c88", X"6c05", X"6b82", X"6aff", X"6a7c",
X"69fa", X"6977", X"68f4", X"6871", X"67ee", X"676b", X"66e9", X"6666",
X"65dd", X"6555", X"64cc", X"6444", X"63bb", X"6333", X"62aa", X"6221",
X"6199", X"6110", X"6088", X"5fff", X"5f77", X"5eee", X"5e66", X"5ddd",
X"5d55", X"5ccc", X"5c44", X"5bbb", X"5b33", X"5aaa", X"5a21", X"5999",
X"5910", X"5888", X"57ff", X"5777", X"56ee", X"5666", X"55dd", X"5555",
X"54b5", X"5416", X"5377", X"52d8", X"5238", X"5199", X"50fa", X"505a",
X"4fbb", X"4f1c", X"4e7d", X"4ddd", X"4d3e", X"4c9f", X"4bff", X"4b60",
X"4ac8", X"4a31", X"4999", X"4901", X"486a", X"47d2", X"473a", X"46a2",
X"460b", X"4573", X"44db", X"4444", X"438e", X"42d8", X"4222", X"416b",
X"54b9", X"5381", X"5248", X"5110", X"4fff", X"4eee", X"4ddd", X"4ccc",
X"4c16", X"4b60", X"4aaa", X"49f4", X"493e", X"4888", X"47d2", X"471c",
X"467d", X"45dd", X"453e", X"449f", X"43ff", X"4360", X"42c1", X"4222",
X"4182", X"40e3", X"4044", X"3fa4", X"3f05", X"3e66", X"3dc6", X"3d27",
X"3caa", X"3c2d", X"3bb0", X"3b33", X"3ab5", X"3a38", X"39bb", X"393e",
X"38c1", X"3844", X"37c7", X"3749", X"36cc", X"364f", X"35d2", X"3555",
X"34d8", X"345a", X"33dd", X"3360", X"32e3", X"3266", X"31e9", X"316b",
X"30ee", X"3071", X"2ff4", X"2f77", X"2efa", X"2e7d", X"2dff", X"2d82",
X"2d1c", X"2cb5", X"2c4f", X"2be9", X"2b82", X"2b1c", X"2ab5", X"2a4f",
X"29e9", X"2982", X"291c", X"28b5", X"284f", X"27e9", X"2782", X"271c",
X"26b5", X"264f", X"25e9", X"2582", X"251c", X"24b5", X"244f", X"23e9",
X"2382", X"231c", X"22b5", X"224f", X"21e9", X"2182", X"211c", X"20b5",
X"2066", X"2016", X"1fc7", X"1f77", X"1f27", X"1ed8", X"1e88", X"1e38",
X"1de9", X"1d99", X"1d49", X"1cfa", X"1caa", X"1c5a", X"1c0b", X"1bbb",
X"1b6c", X"1b1c", X"1acc", X"1a7d", X"1a2d", X"19dd", X"198e", X"193e",
X"18ee", X"189f", X"184f", X"17ff", X"17b0", X"1760", X"1711", X"16c1",
X"1692", X"1664", X"1635", X"1606", X"15d8", X"15a9", X"157a", X"154c",
X"151d", X"14ee", X"14c0", X"1491", X"1462", X"1434", X"1405", X"13d7",
X"13a8", X"1379", X"134b", X"131c", X"12ed", X"12bf", X"1290", X"1261",
X"1233", X"1204", X"11d5", X"11a7", X"1178", X"1149", X"111b", X"10ec",
X"10bd", X"108f", X"1060", X"1032", X"1003", X"0fd4", X"0fa6", X"0f77",
X"0f48", X"0f1a", X"0eeb", X"0ebc", X"0e8e", X"0e5f", X"0e30", X"0e02",
X"0dd3", X"0da4", X"0d76", X"0d47", X"0d19", X"0cea", X"0cbb", X"0c8d",
X"0c5e", X"0c2f", X"0c01", X"0bd2", X"0ba3", X"0b75", X"0b46", X"0b17",
X"0b03", X"0aee", X"0ada", X"0ac5", X"0ab1", X"0a9c", X"0a88", X"0a74",
X"0a5f", X"0a4b", X"0a36", X"0a22", X"0a0d", X"09f9", X"09e4", X"09d0",
X"09bb", X"09a7", X"0992", X"097e", X"0969", X"0955", X"0940", X"092c",
X"0917", X"0903", X"08ee", X"08da", X"08c5", X"08b1", X"089c", X"0888",
X"0874", X"085f", X"084b", X"0836", X"0822", X"080d", X"07f9", X"07e4",
X"07d0", X"07bb", X"07a7", X"0792", X"077e", X"0769", X"0755", X"0740",
X"072c", X"0717", X"0703", X"06ee", X"06da", X"06c5", X"06b1", X"069d",
X"0688", X"0674", X"065f", X"064b", X"0636", X"0622", X"060d", X"05f9",
X"05f2", X"05eb", X"05e4", X"05dd", X"05d7", X"05d0", X"05c9", X"05c2",
X"05bb", X"05b4", X"05ae", X"05a7", X"05a0", X"0599", X"0592", X"058b",
X"0585", X"057e", X"0577", X"0570", X"0569", X"0562", X"055c", X"0555",
X"054e", X"0547", X"0540", X"053a", X"0533", X"052c", X"0525", X"051e",
X"0517", X"0511", X"050a", X"0503", X"04fc", X"04f5", X"04ee", X"04e8",
X"04e1", X"04da", X"04d3", X"04cc", X"04c5", X"04bf", X"04b8", X"04b1",
X"04aa", X"04a3", X"049d", X"0496", X"048f", X"0488", X"0481", X"047a",
X"0474", X"046d", X"0466", X"045f", X"0458", X"0451", X"044b", X"0444",
X"0441", X"043e", X"043b", X"0438", X"0436", X"0433", X"0430", X"042d",
X"042a", X"0427", X"0424", X"0422", X"041f", X"041c", X"0419", X"0416",
X"0413", X"0411", X"040e", X"040b", X"0408", X"0405", X"0402", X"03ff",
X"03fd", X"03fa", X"03f7", X"03f4", X"03f1", X"03ee", X"03ec", X"03e9",
X"03e6", X"03e3", X"03e0", X"03dd", X"03db", X"03d8", X"03d5", X"03d2",
X"03cf", X"03cc", X"03c9", X"03c7", X"03c4", X"03c1", X"03be", X"03bb",
X"03b8", X"03b6", X"03b3", X"03b0", X"03ad", X"03aa", X"03a7", X"03a4",
X"03a2", X"039f", X"039c", X"0399", X"0396", X"0393", X"0391", X"038e",
X"038d", X"038b", X"038a", X"0389", X"0388", X"0387", X"0386", X"0385",
X"0383", X"0382", X"0381", X"0380", X"037f", X"037e", X"037d", X"037c",
X"037a", X"0379", X"0378", X"0377", X"0376", X"0375", X"0374", X"0372",
X"0371", X"0370", X"036f", X"036e", X"036d", X"036c", X"036a", X"0369",
X"0368", X"0367", X"0366", X"0365", X"0364", X"0362", X"0361", X"0360",
X"035f", X"035e", X"035d", X"035c", X"035b", X"0359", X"0358", X"0357",
X"0356", X"0355", X"0354", X"0353", X"0351", X"0350", X"034f", X"034e",
X"034d", X"034c", X"034b", X"0349", X"0348", X"0347", X"0346", X"0345",
X"0344", X"0344", X"0343", X"0343", X"0342", X"0341", X"0341", X"0340",
X"0340", X"033f", X"033f", X"033e", X"033e", X"033d", X"033c", X"033c",
X"033b", X"033b", X"033a", X"033a", X"0339", X"0338", X"0338", X"0337",
X"0337", X"0336", X"0336", X"0335", X"0334", X"0334", X"0333", X"0333",
X"0332", X"0332", X"0331", X"0330", X"0330", X"032f", X"032f", X"032e",
X"032e", X"032d", X"032c", X"032c", X"032b", X"032b", X"032a", X"032a",
X"0329", X"0328", X"0328", X"0327", X"0327", X"0326", X"0326", X"0325",
X"0324", X"0324", X"0323", X"0323", X"0322", X"0322", X"0321", X"0320"
);
alias xa_select : std_logic is instruction(0);
alias xb_select : std_logic is instruction(1);
alias sub_a_sel : std_logic is instruction(2);
alias sub_b_sel : std_logic is instruction(3);
alias sum_to_lp : std_logic is instruction(4);
alias sum_to_bp : std_logic is instruction(5);
alias sub_to_hp : std_logic is instruction(6);
alias mult_enable : std_logic is instruction(7);
begin
-- Derive the actual 'f' and 'q' parameters
i_q_table: entity work.Q_table
port map (
Q_reg => filt_res,
filter_q => filter_q ); -- 2.16 format
process(clock)
begin
if rising_edge(clock) then
if(enable = '1') then
filter_f <= "00" & coef(to_integer(filt_co(10 downto 1)));
else
filter_f <= "001111111111111111";
end if;
end if;
end process;
--input_sc <= input;
input_sc <= shift_right(input, 1);
-- operations to execute the filter:
-- bp_f = f * bp_reg
-- q_contrib = q * bp_reg
-- lp = bp_f + lp_reg
-- temp = input - lp
-- hp = temp - q_contrib
-- hp_f = f * hp
-- bp = hp_f + bp_reg
-- bp_reg = bp
-- lp_reg = lp
-- x_reg = f * bp_reg -- 10000000 -- 80
-- lp_reg = x_reg + lp_reg -- 00010010 -- 12
-- q_contrib = q * bp_reg -- 10000001 -- 81
-- temp = input - lp -- 00000000 -- 00 (can be merged with previous!)
-- hp_reg = temp - q_contrib -- 01001100 -- 4C
-- x_reg = f * hp_reg -- 10000010 -- 82
-- bp_reg = x_reg + bp_reg -- 00100000 -- 20
-- now perform the arithmetic
xa <= filter_f when xa_select='0' else filter_q;
xb <= bp_reg when xb_select='0' else hp_reg;
sum_b <= bp_reg when xb_select='0' else lp_reg;
sub_a <= input_sc when sub_a_sel='0' else temp_reg;
sub_b <= lp_reg when sub_b_sel='0' else x_reg;
process(clock)
variable x_result : signed(35 downto 0);
variable sum_result : signed(17 downto 0);
variable sub_result : signed(17 downto 0);
begin
if rising_edge(clock) then
x_result := xa * xb;
if mult_enable='1' then
x_reg <= x_result(33 downto 16);
if (x_result(35 downto 33) /= "000") and (x_result(35 downto 33) /= "111") then
error <= not error;
end if;
end if;
sum_result := sum_limit(x_reg, sum_b);
temp_reg <= sum_result;
if sum_to_lp='1' then
lp_reg <= sum_result;
end if;
if sum_to_bp='1' then
bp_reg <= sum_result;
end if;
sub_result := sub_limit(sub_a, sub_b);
temp_reg <= sub_result;
if sub_to_hp='1' then
hp_reg <= sub_result;
end if;
-- control part
instruction <= (others => '0');
if reset='1' then
hp_reg <= (others => '0');
lp_reg <= (others => '0');
bp_reg <= (others => '0');
divider <= 0;
elsif divider = g_divider-1 then
divider <= 0;
else
divider <= divider + 1;
if divider < c_program'length then
instruction <= c_program(divider);
end if;
end if;
if divider = c_program'length then
valid_out <= '1';
else
valid_out <= '0';
end if;
end if;
end process;
high_pass <= hp_reg;
band_pass <= bp_reg;
low_pass <= lp_reg;
error_out <= error;
end dsvf;

115
rtl/sid/sid_mixer.vhd Normal file
View File

@ -0,0 +1,115 @@
-------------------------------------------------------------------------------
--
-- (C) COPYRIGHT 2010 Gideon's Logic Architectures'
--
-------------------------------------------------------------------------------
--
-- Author: Gideon Zweijtzer (gideon.zweijtzer (at) gmail.com)
--
-- Note that this file is copyrighted, and is not supposed to be used in other
-- projects without written permission from the author.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.my_math_pkg.all;
entity sid_mixer is
port (
clock : in std_logic;
reset : in std_logic;
valid_in : in std_logic := '0';
direct_out : in signed(17 downto 0);
high_pass : in signed(17 downto 0);
band_pass : in signed(17 downto 0);
low_pass : in signed(17 downto 0);
filter_hp : in std_logic;
filter_bp : in std_logic;
filter_lp : in std_logic;
volume : in unsigned(3 downto 0);
mixed_out : out signed(17 downto 0);
valid_out : out std_logic );
end sid_mixer;
architecture arith of sid_mixer is
signal mix_i : signed(17 downto 0);
signal mix_uns : unsigned(16 downto 0);
signal vol_uns : unsigned(16 downto 0);
signal vol_s : signed(16 downto 0);
signal state : integer range 0 to 7;
signal p_mul : unsigned(33 downto 0);
signal p_mul_s : signed(34 downto 0);
type t_volume_lut is array(natural range <>) of unsigned(15 downto 0);
constant c_volume_lut : t_volume_lut(0 to 15) := (
X"0000", X"0EEF", X"1DDE", X"2CCD", X"3BBC", X"4AAA", X"5999", X"6888",
X"7777", X"8666", X"9555", X"A444", X"B333", X"C221", X"D110", X"DFFF" );
begin
process(clock)
variable mix_total : signed(17 downto 0);
begin
if rising_edge(clock) then
valid_out <= '0';
state <= state + 1;
case state is
when 0 =>
if valid_in = '1' then
mix_i <= sum_limit(direct_out, to_signed(16384, 18));
else
state <= 0;
end if;
when 1 =>
if filter_hp='1' then
mix_i <= sum_limit(mix_i, high_pass);
end if;
when 2 =>
if filter_bp='1' then
mix_i <= sum_limit(mix_i, band_pass);
end if;
when 3 =>
if filter_lp='1' then
mix_i <= sum_limit(mix_i, low_pass);
end if;
when 4 =>
-- p_mul <= mix_uns * vol_uns;
p_mul_s <= mix_i * vol_s;
valid_out <= '1';
state <= 0;
when others =>
state <= 0;
end case;
-- mix_total := not(p_mul(32)) & signed(p_mul(31 downto 15));
-- mixed_out <= mix_total; -- + to_signed(16384, 18);
mixed_out <= p_mul_s(33 downto 16);
if reset='1' then
mix_i <= (others => '0');
state <= 0;
end if;
end if;
end process;
-- vol_uns <= "0" & volume & volume & volume & volume;
-- vol_uns <= '0' & c_volume_lut(to_integer(volume));
-- mix_uns <= not mix_i(17) & unsigned(mix_i(16 downto 1));
vol_s <= '0' & signed(c_volume_lut(to_integer(volume)));
end arith;

255
rtl/sid/sid_regs.vhd Normal file
View File

@ -0,0 +1,255 @@
-------------------------------------------------------------------------------
--
-- (C) COPYRIGHT 2010 Gideon's Logic Architectures'
--
-------------------------------------------------------------------------------
--
-- Author: Gideon Zweijtzer (gideon.zweijtzer (at) gmail.com)
--
-- Note that this file is copyrighted, and is not supposed to be used in other
-- projects without written permission from the author.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sid_regs is
port (
clock : in std_logic;
reset : in std_logic;
addr : in unsigned(7 downto 0);
wren : in std_logic;
wdata : in std_logic_vector(7 downto 0);
rdata : out std_logic_vector(7 downto 0);
potx : in std_logic_vector(7 downto 0);
poty : in std_logic_vector(7 downto 0);
---
comb_wave_l : in std_logic;
comb_wave_r : in std_logic;
---
voice_osc : in unsigned(3 downto 0);
voice_wave : in unsigned(3 downto 0);
voice_adsr : in unsigned(3 downto 0);
voice_mul : in unsigned(3 downto 0);
-- Oscillator parameters
freq : out unsigned(15 downto 0);
test : out std_logic;
sync : out std_logic;
-- Wave map parameters
comb_mode : out std_logic;
ring_mod : out std_logic;
wave_sel : out std_logic_vector(3 downto 0);
sq_width : out unsigned(11 downto 0);
-- ADSR parameters
gate : out std_logic;
attack : out std_logic_vector(3 downto 0);
decay : out std_logic_vector(3 downto 0);
sustain : out std_logic_vector(3 downto 0);
release : out std_logic_vector(3 downto 0);
-- mixer 1 parameters
filter_en : out std_logic;
-- globals
volume_l : out unsigned(3 downto 0) := (others => '0');
filter_co_l : out unsigned(10 downto 0) := (others => '0');
filter_res_l : out unsigned(3 downto 0) := (others => '0');
filter_ex_l : out std_logic := '0';
filter_hp_l : out std_logic := '0';
filter_bp_l : out std_logic := '0';
filter_lp_l : out std_logic := '0';
voice3_off_l : out std_logic := '0';
volume_r : out unsigned(3 downto 0) := (others => '0');
filter_co_r : out unsigned(10 downto 0) := (others => '0');
filter_res_r : out unsigned(3 downto 0) := (others => '0');
filter_ex_r : out std_logic := '0';
filter_hp_r : out std_logic := '0';
filter_bp_r : out std_logic := '0';
filter_lp_r : out std_logic := '0';
voice3_off_r : out std_logic := '0';
-- readback
osc3 : in std_logic_vector(7 downto 0);
env3 : in std_logic_vector(7 downto 0) );
attribute ramstyle : string;
end sid_regs;
architecture gideon of sid_regs is
attribute ramstyle of gideon : architecture is "logic";
type byte_array_t is array(natural range <>) of std_logic_vector(7 downto 0);
type nibble_array_t is array(natural range <>) of std_logic_vector(3 downto 0);
signal freq_lo : byte_array_t(0 to 15) := (others => (others => '0'));
signal freq_hi : byte_array_t(0 to 15) := (others => (others => '0'));
signal phase_lo : byte_array_t(0 to 15) := (others => (others => '0'));
signal phase_hi : nibble_array_t(0 to 15):= (others => (others => '0'));
signal control : byte_array_t(0 to 15) := (others => (others => '0'));
signal att_dec : byte_array_t(0 to 15) := (others => (others => '0'));
signal sust_rel : byte_array_t(0 to 15) := (others => (others => '0'));
signal do_write : std_logic;
signal wdata_d : std_logic_vector(7 downto 0);
signal bus_value: std_logic_vector(7 downto 0);
signal filt_en_i: std_logic_vector(15 downto 0) := (others => '0');
constant address_remap : byte_array_t(0 to 255) := (
X"00", X"01", X"02", X"03", X"04", X"05", X"06", -- 00 Voice 1
X"10", X"11", X"12", X"13", X"14", X"15", X"16", -- 07 Voice 2
X"20", X"21", X"22", X"23", X"24", X"25", X"26", -- 0E Voice 3
X"08", X"09", X"0A", X"0B", -- 15
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- 19
X"30", X"31", X"32", X"33", X"34", X"35", X"36", -- 20 Voice 4
X"40", X"41", X"42", X"43", X"44", X"45", X"46", -- 27 Voice 5
X"50", X"51", X"52", X"53", X"54", X"55", X"56", -- 2E Voice 6
X"60", X"61", X"62", X"63", X"64", X"65", X"66", -- 35 Voice 7
X"70", X"71", X"72", X"73", X"74", X"75", X"76", -- 3C Voice 8
X"0C", X"0D", X"0E", -- 43
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- 46
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- 4D
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- 54
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- 5B
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- 62
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- 69
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- 70
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- 77
X"FF", X"FF", -- 7E
X"80", X"81", X"82", X"83", X"84", X"85", X"86", -- 80 Voice 9
X"90", X"91", X"92", X"93", X"94", X"95", X"96", -- 87 Voice 10
X"A0", X"A1", X"A2", X"A3", X"A4", X"A5", X"A6", -- 8E Voice 11
X"88", X"89", X"8A", X"8B", -- 95
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- 99
X"B0", X"B1", X"B2", X"B3", X"B4", X"B5", X"B6", -- A0 Voice 12
X"C0", X"C1", X"C2", X"C3", X"C4", X"C5", X"C6", -- A7 Voice 13
X"D0", X"D1", X"D2", X"D3", X"D4", X"D5", X"D6", -- AE Voice 14
X"E0", X"E1", X"E2", X"E3", X"E4", X"E5", X"E6", -- B5 Voice 15
X"F0", X"F1", X"F2", X"F3", X"F4", X"F5", X"F6", -- BC Voice 16
X"8C", X"8D", X"8E", -- C3
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- C6
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- CD
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- D4
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- DB
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- E2
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- E9
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- F0
X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", X"FF", -- F7
X"FF", X"FF" ); -- FE
begin
process(clock)
variable address: unsigned(7 downto 0);
begin
if rising_edge(clock) then
address := unsigned(address_remap(to_integer(addr)));
do_write <= wren;
wdata_d <= wdata;
if do_write='0' and wren='1' then
bus_value <= wdata_d;
if address(3)='0' then -- Voice register
case address(2 downto 0) is
when "000" => freq_lo(to_integer(address(7 downto 4))) <= wdata_d;
when "001" => freq_hi(to_integer(address(7 downto 4))) <= wdata_d;
when "010" => phase_lo(to_integer(address(7 downto 4))) <= wdata_d;
when "011" => phase_hi(to_integer(address(7 downto 4))) <= wdata_d(3 downto 0);
when "100" => control(to_integer(address(7 downto 4))) <= wdata_d;
when "101" => att_dec(to_integer(address(7 downto 4))) <= wdata_d;
when "110" => sust_rel(to_integer(address(7 downto 4))) <= wdata_d;
when others => null;
end case;
elsif address(7)='0' then -- Global register for left
case address(2 downto 0) is
when "000" => filter_co_l(2 downto 0) <= unsigned(wdata_d(2 downto 0));
when "001" => filter_co_l(10 downto 3) <= unsigned(wdata_d);
when "010" => filter_res_l <= unsigned(wdata_d(7 downto 4));
filter_ex_l <= wdata_d(3);
filt_en_i(2 downto 0) <= wdata_d(2 downto 0);
when "011" => voice3_off_l <= wdata_d(7);
filter_hp_l <= wdata_d(6);
filter_bp_l <= wdata_d(5);
filter_lp_l <= wdata_d(4);
volume_l <= unsigned(wdata_d(3 downto 0));
when "100" => filt_en_i(7 downto 0) <= wdata_d;
when others => null;
end case;
else -- Global register for right
case address(2 downto 0) is
when "000" => filter_co_r(2 downto 0) <= unsigned(wdata_d(2 downto 0));
when "001" => filter_co_r(10 downto 3) <= unsigned(wdata_d);
when "010" => filter_res_r <= unsigned(wdata_d(7 downto 4));
filter_ex_r <= wdata_d(3);
filt_en_i(10 downto 8) <= wdata_d(2 downto 0);
when "011" => voice3_off_r <= wdata_d(7);
filter_hp_r <= wdata_d(6);
filter_bp_r <= wdata_d(5);
filter_lp_r <= wdata_d(4);
volume_r <= unsigned(wdata_d(3 downto 0));
when "100" => filt_en_i(15 downto 8) <= wdata_d;
when others => null;
end case;
end if;
end if;
-- Readback (unmapped address)
case addr is
when "00011001" => rdata <= potx; bus_value <= potx;
when "00011010" => rdata <= poty; bus_value <= poty;
when "00011011" => rdata <= osc3; bus_value <= osc3;
when "00011100" => rdata <= env3; bus_value <= env3;
when others => rdata <= bus_value;
end case;
if reset='1' then
freq_lo <= (others => (others => '0'));
freq_hi <= (others => (others => '0'));
phase_lo <= (others => (others => '0'));
phase_hi <= (others => (others => '0'));
control <= (others => (others => '0'));
att_dec <= (others => (others => '0'));
sust_rel <= (others => (others => '0'));
filt_en_i <= (others => '0');
voice3_off_l <= '0';
voice3_off_r <= '0';
volume_l <= X"0";
volume_r <= X"0";
end if;
end if;
end process;
freq <= unsigned(freq_hi(to_integer(voice_osc))) & unsigned(freq_lo(to_integer(voice_osc)));
test <= control(to_integer(voice_osc))(3);
sync <= control(to_integer(voice_osc))(1);
-- Wave map parameters
ring_mod <= control(to_integer(voice_wave))(2);
wave_sel <= control(to_integer(voice_wave))(7 downto 4);
sq_width <= unsigned(phase_hi(to_integer(voice_wave))) & unsigned(phase_lo(to_integer(voice_wave)));
comb_mode <= (voice_wave(3) and comb_wave_r) or (not voice_wave(3) and comb_wave_l);
-- ADSR parameters
gate <= control(to_integer(voice_adsr))(0);
attack <= att_dec(to_integer(voice_adsr))(7 downto 4);
decay <= att_dec(to_integer(voice_adsr))(3 downto 0);
sustain <= sust_rel(to_integer(voice_adsr))(7 downto 4);
release <= sust_rel(to_integer(voice_adsr))(3 downto 0);
-- Mixer 1 parameters
filter_en <= filt_en_i(to_integer(voice_mul));
end gideon;

411
rtl/sid/sid_top.vhd Normal file
View File

@ -0,0 +1,411 @@
-------------------------------------------------------------------------------
--
-- (C) COPYRIGHT 2010 Gideon's Logic Architectures'
--
-------------------------------------------------------------------------------
--
-- Author: Gideon Zweijtzer (gideon.zweijtzer (at) gmail.com)
--
-- Note that this file is copyrighted, and is not supposed to be used in other
-- projects without written permission from the author.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
entity sid_top is
generic (
g_filter_div : natural := 141; --for 32 MHz (221; -- for 50 MHz)
g_num_voices : natural := 3 );
port (
clock : in std_logic;
reset : in std_logic;
addr : in unsigned(7 downto 0);
wren : in std_logic;
wdata : in std_logic_vector(7 downto 0);
rdata : out std_logic_vector(7 downto 0);
potx : in std_logic_vector(7 downto 0);
poty : in std_logic_vector(7 downto 0);
comb_wave_l : in std_logic := '0';
comb_wave_r : in std_logic := '0';
start_iter : in std_logic;
sample_left : out signed(17 downto 0);
sample_right : out signed(17 downto 0);
extfilter_en : in std_logic
);
end sid_top;
architecture structural of sid_top is
-- Voice index in pipe
signal voice_osc : unsigned(3 downto 0);
signal voice_wave : unsigned(3 downto 0);
signal voice_mul : unsigned(3 downto 0);
signal enable_osc : std_logic;
signal enable_wave : std_logic;
signal enable_mul : std_logic;
-- Oscillator parameters
signal freq : unsigned(15 downto 0);
signal test : std_logic;
signal sync : std_logic;
-- Wave map parameters
signal msb_other : std_logic;
signal comb_mode : std_logic;
signal ring_mod : std_logic;
signal wave_sel : std_logic_vector(3 downto 0);
signal sq_width : unsigned(11 downto 0);
-- ADSR parameters
signal gate : std_logic;
signal attack : std_logic_vector(3 downto 0);
signal decay : std_logic_vector(3 downto 0);
signal sustain : std_logic_vector(3 downto 0);
signal release : std_logic_vector(3 downto 0);
-- Filter enable
signal filter_en : std_logic;
-- globals
signal volume_l : unsigned(3 downto 0);
signal filter_co_l : unsigned(10 downto 0);
signal filter_res_l : unsigned(3 downto 0);
signal filter_hp_l : std_logic;
signal filter_bp_l : std_logic;
signal filter_lp_l : std_logic;
signal voice3_off_l : std_logic;
signal volume_r : unsigned(3 downto 0);
signal filter_co_r : unsigned(10 downto 0);
signal filter_res_r : unsigned(3 downto 0);
signal filter_hp_r : std_logic;
signal filter_bp_r : std_logic;
signal filter_lp_r : std_logic;
signal voice3_off_r : std_logic;
-- readback
signal osc3 : std_logic_vector(7 downto 0);
signal env3 : std_logic_vector(7 downto 0);
-- intermediate flags and signals
signal test_wave : std_logic;
signal osc_val : unsigned(23 downto 0);
signal carry_20 : std_logic;
signal enveloppe : unsigned(7 downto 0);
signal waveform : unsigned(11 downto 0);
signal valid_sum : std_logic;
signal valid_filt : std_logic;
signal valid_mix : std_logic;
signal filter_out_l: signed(17 downto 0) := (others => '0');
signal direct_out_l: signed(17 downto 0) := (others => '0');
signal high_pass_l : signed(17 downto 0) := (others => '0');
signal band_pass_l : signed(17 downto 0) := (others => '0');
signal low_pass_l : signed(17 downto 0) := (others => '0');
signal mixed_out_l : signed(17 downto 0) := (others => '0');
signal filter_out_r: signed(17 downto 0) := (others => '0');
signal direct_out_r: signed(17 downto 0) := (others => '0');
signal high_pass_r : signed(17 downto 0) := (others => '0');
signal band_pass_r : signed(17 downto 0) := (others => '0');
signal low_pass_r : signed(17 downto 0) := (others => '0');
signal mixed_out_r : signed(17 downto 0) := (others => '0');
begin
i_regs: entity work.sid_regs
port map
(
clock => clock,
reset => reset,
addr => addr,
wren => wren,
wdata => wdata,
rdata => rdata,
potx => potx,
poty => poty,
comb_wave_l => comb_wave_l,
comb_wave_r => comb_wave_r,
voice_osc => voice_osc,
voice_wave => voice_wave,
voice_adsr => voice_wave,
voice_mul => voice_mul,
-- Oscillator parameters
freq => freq,
test => test,
sync => sync,
-- Wave map parameters
comb_mode => comb_mode,
ring_mod => ring_mod,
wave_sel => wave_sel,
sq_width => sq_width,
-- ADSR parameters
gate => gate,
attack => attack,
decay => decay,
sustain => sustain,
release => release,
-- mixer parameters
filter_en => filter_en,
-- globals
volume_l => volume_l,
filter_co_l => filter_co_l,
filter_res_l=> filter_res_l,
filter_ex_l => open,
filter_hp_l => filter_hp_l,
filter_bp_l => filter_bp_l,
filter_lp_l => filter_lp_l,
voice3_off_l=> voice3_off_l,
volume_r => volume_r,
filter_co_r => filter_co_r,
filter_res_r=> filter_res_r,
filter_ex_r => open,
filter_hp_r => filter_hp_r,
filter_bp_r => filter_bp_r,
filter_lp_r => filter_lp_r,
voice3_off_r=> voice3_off_r,
-- readback
osc3 => osc3,
env3 => env3
);
i_ctrl: entity work.sid_ctrl
generic map
(
g_num_voices => g_num_voices
)
port map
(
clock => clock,
reset => reset,
start_iter => start_iter,
voice_osc => voice_osc,
enable_osc => enable_osc
);
osc: entity work.oscillator
generic map
(
g_num_voices
)
port map
(
clock => clock,
reset => reset,
voice_i => voice_osc,
voice_o => voice_wave,
enable_i => enable_osc,
enable_o => enable_wave,
freq => freq,
test => test,
sync => sync,
osc_val => osc_val,
test_o => test_wave,
carry_20 => carry_20,
msb_other => msb_other
);
wmap: entity work.wave_map
generic map
(
g_num_voices => g_num_voices,
g_sample_bits => 12
)
port map
(
clock => clock,
reset => reset,
test => test_wave,
osc_val => osc_val,
carry_20 => carry_20,
msb_other => msb_other,
voice_i => voice_wave,
enable_i => enable_wave,
comb_mode => comb_mode,
wave_sel => wave_sel,
ring_mod => ring_mod,
sq_width => sq_width,
voice_o => voice_mul,
enable_o => enable_mul,
wave_out => waveform
);
adsr: entity work.adsr_multi
generic map
(
g_num_voices => g_num_voices
)
port map
(
clock => clock,
reset => reset,
voice_i => voice_wave,
enable_i => enable_wave,
voice_o => open,
enable_o => open,
gate => gate,
attack => attack,
decay => decay,
sustain => sustain,
release => release,
env_state=> open, -- for testing only
env_out => enveloppe
);
sum: entity work.mult_acc(signed_wave)
port map
(
clock => clock,
reset => reset,
voice_i => voice_mul,
enable_i => enable_mul,
voice3_off_l=> voice3_off_l,
voice3_off_r=> voice3_off_r,
enveloppe => enveloppe,
waveform => waveform,
filter_en => filter_en,
osc3 => osc3,
env3 => env3,
valid_out => valid_sum,
filter_out_L => filter_out_L,
filter_out_R => filter_out_R,
direct_out_L => direct_out_L,
direct_out_R => direct_out_R
);
i_filt_left: entity work.sid_filter
generic map
(
g_divider => g_filter_div
)
port map
(
clock => clock,
reset => reset,
enable => extfilter_en,
filt_co => filter_co_l,
filt_res => filter_res_l,
valid_in => valid_sum,
input => filter_out_L,
high_pass => high_pass_L,
band_pass => band_pass_L,
low_pass => low_pass_L,
error_out => open,
valid_out => valid_filt
);
mix: entity work.sid_mixer
port map
(
clock => clock,
reset => reset,
valid_in => valid_filt,
direct_out => direct_out_L,
high_pass => high_pass_L,
band_pass => band_pass_L,
low_pass => low_pass_L,
filter_hp => filter_hp_l,
filter_bp => filter_bp_l,
filter_lp => filter_lp_l,
volume => volume_l,
mixed_out => mixed_out_L,
valid_out => open
);
i_filt_right: entity work.sid_filter
generic map
(
g_divider => g_filter_div
)
port map
(
clock => clock,
reset => reset,
enable => extfilter_en,
filt_co => filter_co_r,
filt_res => filter_res_r,
valid_in => valid_sum,
input => filter_out_R,
high_pass => high_pass_R,
band_pass => band_pass_R,
low_pass => low_pass_R,
error_out => open,
valid_out => open
);
mix_right: entity work.sid_mixer
port map
(
clock => clock,
reset => reset,
valid_in => valid_filt,
direct_out => direct_out_R,
high_pass => high_pass_R,
band_pass => band_pass_R,
low_pass => low_pass_R,
filter_hp => filter_hp_r,
filter_bp => filter_bp_r,
filter_lp => filter_lp_r,
volume => volume_r,
mixed_out => mixed_out_R,
valid_out => open
);
sample_left <= mixed_out_L;
sample_right <= mixed_out_R;
end structural;

178
rtl/sid/wave_map.vhd Normal file
View File

@ -0,0 +1,178 @@
-------------------------------------------------------------------------------
--
-- (C) COPYRIGHT 2010 Gideon's Logic Architectures'
--
-------------------------------------------------------------------------------
--
-- Author: Gideon Zweijtzer (gideon.zweijtzer (at) gmail.com)
--
-- Note that this file is copyrighted, and is not supposed to be used in other
-- projects without written permission from the author.
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity wave_map is
generic (
g_num_voices : integer := 8; -- 8 or 16, clock should then be 8 or 16 MHz, too!
g_sample_bits : integer := 8 );
port (
clock : in std_logic;
reset : in std_logic;
osc_val : in unsigned(23 downto 0);
carry_20 : in std_logic;
msb_other: in std_logic := '0';
ring_mod : in std_logic := '0';
test : in std_logic := '0';
voice_i : in unsigned(3 downto 0);
comb_mode: in std_logic;
enable_i : in std_logic;
wave_sel : in std_logic_vector(3 downto 0);
sq_width : in unsigned(11 downto 0);
voice_o : out unsigned(3 downto 0);
enable_o : out std_logic;
wave_out : out unsigned(g_sample_bits-1 downto 0) );
end wave_map;
architecture Gideon of wave_map is
type noise_array_t is array (natural range <>) of unsigned(22 downto 0);
signal noise_reg : noise_array_t(0 to g_num_voices-1) := (others => (0 => '1', others => '0'));
type voice_array_t is array (natural range <>) of unsigned(g_sample_bits-1 downto 0);
signal voice_reg : voice_array_t(0 to g_num_voices-1) := (others => (others => '0'));
type t_byte_array is array(natural range <>) of unsigned(7 downto 0);
constant c_wave_TP : t_byte_array(0 to 255) := (
16#FF# => X"FF", 16#F7# => X"F7", 16#EF# => X"EF", 16#E7# => X"E0",
16#FE# => X"FE", 16#F6# => X"F0", 16#EE# => X"E0", 16#E6# => X"00",
16#FD# => X"FD", 16#F5# => X"FD", 16#ED# => X"E0", 16#E5# => X"00",
16#FC# => X"F8", 16#F4# => X"80", 16#EC# => X"00", 16#E4# => X"00",
16#FB# => X"FB", 16#F3# => X"F0", 16#EB# => X"E0", 16#E3# => X"00",
16#FA# => X"F8", 16#F2# => X"08", 16#EA# => X"00", 16#E2# => X"00",
16#F9# => X"F0", 16#F1# => X"00", 16#E9# => X"00", 16#E1# => X"00",
16#F8# => X"80", 16#F0# => X"00", 16#E8# => X"00", 16#E0# => X"00",
16#DF# => X"DF", 16#DE# => X"D0", 16#DD# => X"C0", 16#DB# => X"C0",
16#D7# => X"C0", 16#CF# => X"C0", 16#BF# => X"BF", 16#BE# => X"B0",
16#BD# => X"A0", 16#B9# => X"80", 16#B7# => X"80", 16#AF# => X"80",
16#7F# => X"7F", 16#7E# => X"70", 16#7D# => X"70", 16#7B# => X"60",
16#77# => X"40", others => X"00" );
constant c_wave_TS : t_byte_array(0 to 255) := (
16#7F# => X"1E", 16#FE# => X"18", 16#FF# => X"3E", others => X"00" );
begin
process(clock)
variable noise_tmp : unsigned(22 downto 0);
variable voice_tmp : unsigned(g_sample_bits-1 downto 0);
variable triangle : unsigned(g_sample_bits-1 downto 0);
variable square : unsigned(g_sample_bits-1 downto 0);
variable sawtooth : unsigned(g_sample_bits-1 downto 0);
variable out_tmp : unsigned(g_sample_bits-1 downto 0);
variable new_bit : std_logic;
begin
if rising_edge(clock) then
-- take top of list
voice_tmp := voice_reg(0);
noise_tmp := noise_reg(0);
if reset='1' or test='1' then
noise_tmp := (others => '1'); -- seed not equal to zero
elsif carry_20='1' then
new_bit := noise_tmp(22) xor noise_tmp(21) xor noise_tmp(20) xor noise_tmp(15);
noise_tmp := noise_tmp(21 downto 0) & new_bit;
end if;
if osc_val(23)='1' then
triangle := not osc_val(22 downto 23-g_sample_bits);
else
triangle := osc_val(22 downto 23-g_sample_bits);
end if;
if ring_mod='1' and msb_other='0' then
triangle := not triangle;
end if;
sawtooth := osc_val(23 downto 24-g_sample_bits);
if osc_val(23 downto 12) < sq_width then
square := (others => '0');
else
square := (others => '1');
end if;
out_tmp := (others => '0');
case wave_sel is
when X"0" =>
out_tmp := voice_tmp;
when X"1" =>
out_tmp := triangle;
when X"2" =>
out_tmp := sawtooth;
when X"3" =>
if comb_mode='0' then
out_tmp(g_sample_bits-1 downto g_sample_bits-8) :=
c_wave_TS(to_integer(osc_val(23 downto 23-g_sample_bits)));
else -- 8580
out_tmp := triangle and sawtooth;
end if;
when X"4" =>
out_tmp := square;
when X"5" => -- combined triangle and square
if comb_mode='0' then
if square(0)='1' then
out_tmp(g_sample_bits-1 downto g_sample_bits-8) :=
c_wave_TP(to_integer(triangle(g_sample_bits-1 downto g_sample_bits-8)));
end if;
else -- 8580
out_tmp := triangle and square;
end if;
when X"6" => -- combined saw and pulse
if comb_mode='1' then
out_tmp := sawtooth and square;
end if;
when X"7" => -- combined triangle, saw and pulse
if comb_mode='1' then
out_tmp := triangle and sawtooth and square;
end if;
when X"8" =>
out_tmp(g_sample_bits-1) := noise_tmp(22); -- unsure.. 21?
out_tmp(g_sample_bits-2) := noise_tmp(20);
out_tmp(g_sample_bits-3) := noise_tmp(16);
out_tmp(g_sample_bits-4) := noise_tmp(13);
out_tmp(g_sample_bits-5) := noise_tmp(11);
out_tmp(g_sample_bits-6) := noise_tmp(7);
out_tmp(g_sample_bits-7) := noise_tmp(4);
out_tmp(g_sample_bits-8) := noise_tmp(2);
-- when X"9"|X"A"|X"B"|X"C"|X"D"|X"E"|X"F" =>
-- out_tmp := noise_tmp(20 downto 21-g_sample_bits);
-- noise_tmp := (others => '0');
when others =>
null;
end case;
if enable_i='1' then
noise_reg(g_num_voices-1) <= noise_tmp;
noise_reg(0 to g_num_voices-2) <= noise_reg(1 to g_num_voices-1);
voice_reg(g_num_voices-1) <= out_tmp;
voice_reg(0 to g_num_voices-2) <= voice_reg(1 to g_num_voices-1);
end if;
--out_tmp(out_tmp'high) := not out_tmp(out_tmp'high);
wave_out <= unsigned(out_tmp);
voice_o <= voice_i;
enable_o <= enable_i;
end if;
end process;
end Gideon;