diff --git a/apple-one.qsf b/apple-one.qsf index 70b22e2..2e9c17f 100644 --- a/apple-one.qsf +++ b/apple-one.qsf @@ -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 diff --git a/rtl/apple1_mist.sv b/rtl/apple1_mist.sv index d46b599..45ea8cf 100644 --- a/rtl/apple1_mist.sv +++ b/rtl/apple1_mist.sv @@ -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 diff --git a/rtl/roms/rom.S2513.bin b/rtl/roms/rom.S2513.bin new file mode 100644 index 0000000..dd087a8 Binary files /dev/null and b/rtl/roms/rom.S2513.bin differ diff --git a/rtl/roms/s2513.bin b/rtl/roms/s2513.bin new file mode 100644 index 0000000..69594b7 --- /dev/null +++ b/rtl/roms/s2513.bin @@ -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 diff --git a/rtl/sid/Q_table.vhd b/rtl/sid/Q_table.vhd new file mode 100644 index 0000000..61dfd33 --- /dev/null +++ b/rtl/sid/Q_table.vhd @@ -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; diff --git a/rtl/sid/adsr_multi.vhd b/rtl/sid/adsr_multi.vhd new file mode 100644 index 0000000..0387df4 --- /dev/null +++ b/rtl/sid/adsr_multi.vhd @@ -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; diff --git a/rtl/sid/mult_acc.vhd b/rtl/sid/mult_acc.vhd new file mode 100644 index 0000000..fbabfd0 --- /dev/null +++ b/rtl/sid/mult_acc.vhd @@ -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; diff --git a/rtl/sid/my_math_pkg.vhd b/rtl/sid/my_math_pkg.vhd new file mode 100644 index 0000000..40f77fd --- /dev/null +++ b/rtl/sid/my_math_pkg.vhd @@ -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; diff --git a/rtl/sid/oscillator.vhd b/rtl/sid/oscillator.vhd new file mode 100644 index 0000000..543cfdc --- /dev/null +++ b/rtl/sid/oscillator.vhd @@ -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; diff --git a/rtl/sid/sid_ctrl.vhd b/rtl/sid/sid_ctrl.vhd new file mode 100644 index 0000000..5b2bb3c --- /dev/null +++ b/rtl/sid/sid_ctrl.vhd @@ -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; diff --git a/rtl/sid/sid_debug_pkg.vhd b/rtl/sid/sid_debug_pkg.vhd new file mode 100644 index 0000000..1345275 --- /dev/null +++ b/rtl/sid/sid_debug_pkg.vhd @@ -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; diff --git a/rtl/sid/sid_filter.vhd b/rtl/sid/sid_filter.vhd new file mode 100644 index 0000000..cfadd86 --- /dev/null +++ b/rtl/sid/sid_filter.vhd @@ -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; diff --git a/rtl/sid/sid_mixer.vhd b/rtl/sid/sid_mixer.vhd new file mode 100644 index 0000000..0b6c090 --- /dev/null +++ b/rtl/sid/sid_mixer.vhd @@ -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; diff --git a/rtl/sid/sid_regs.vhd b/rtl/sid/sid_regs.vhd new file mode 100644 index 0000000..f2e1298 --- /dev/null +++ b/rtl/sid/sid_regs.vhd @@ -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; diff --git a/rtl/sid/sid_top.vhd b/rtl/sid/sid_top.vhd new file mode 100644 index 0000000..8544ac3 --- /dev/null +++ b/rtl/sid/sid_top.vhd @@ -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; diff --git a/rtl/sid/wave_map.vhd b/rtl/sid/wave_map.vhd new file mode 100644 index 0000000..47e7985 --- /dev/null +++ b/rtl/sid/wave_map.vhd @@ -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;