1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-02-21 14:47:33 +00:00
Files
Gehstock.Mist_FPGA/Arcade_MiST/Phoenix Hardware/rtl/phoenix_effect2.vhd
2022-08-31 17:54:02 +02:00

388 lines
12 KiB
VHDL

---------------------------------------------------------------------------------
-- Phoenix sound effect2 by Dar (darfpga@aol.fr) (April 2016)
-- http://darfpga.blogspot.fr
---------------------------------------------------------------------------------
-- this module outputs sound of mothership's descend
-- it could be heard at beginning of level 5
-- the prrrrr...vioooouuuuu sound
-- fixme:
-- the VCO control levels are too coarse (quantized)
-- frequency transitions are heard in large steps
-- instead of continous sweep
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.ALL;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity phoenix_effect2 is
generic(
-- Oscillator 1
Osc1_Fs: real := 11.0; -- MHz
Osc1_Vb: real := 5.0; -- V
Osc1_Vce: real := 0.2; -- V
Osc1_R1: real := 47.0; -- k
Osc1_R2: real := 100.0; -- k
Osc1_C1: real := 0.01; -- uF
Osc1_C2: real := 0.47; -- uF
Osc1_C3: real := 1.0; -- uF
Osc1_Div2n: integer := 8; -- bits divisor
Osc1_bits: integer := 16; -- bits counter
-- Oscillator 2
Osc2_Fs: real := 11.0; -- MHz
Osc2_Vb: real := 5.0; -- V
Osc2_Vce: real := 0.2; -- V
Osc2_R1: real := 510.0; -- k
Osc2_R2: real := 510.0; -- k
Osc2_C: real := 1.0; -- uF
Osc2_Div2n: integer := 8; -- bits divisor
Osc2_bits: integer := 17; -- bits counter
-- Filter 2
Filt2_Fs: real := 11.0; -- MHz
Filt2_V: real := 5.0; -- V
Filt2_R1: real := 10.0; -- k
Filt2_R2: real := 5.1; -- k
Filt2_R3: real := 5.1; -- k
Filt2_R4: real := 5.0; -- k
Filt2_R5: real := 10.0; -- k
Filt2_C: real := 100.0; -- uF
Filt2_Div2n: integer := 8; -- bits divisor
Filt2_bits: integer := 16; -- bits counter
-- Oscillator 3
Osc3_Fs: real := 11.0; -- MHz
Osc3_Vb: real := 5.0; -- V
Osc3_Vce: real := 0.2; -- V
Osc3_R1: real := 20.0; -- k
Osc3_R2: real := 20.0; -- k
Osc3_C: real := 0.001; -- uF
Osc3_Div2n: integer := 6; -- bits divisor
Osc3_bits: integer := 6; -- bits counter
C_flip1_0: integer := 22020;
C_flip1_1: integer := 33063;
C_flip1_scale: integer := 84; -- ??
Vmax: real := 5.0; -- V
Vmax_bits: integer := 16 -- number of bits to represent Vmax
);
port(
clk : in std_logic;
reset : in std_logic;
trigger1 : in std_logic;
trigger2 : in std_logic;
divider : in std_logic_vector(3 downto 0);
snd : out std_logic_vector(1 downto 0)
);
end phoenix_effect2;
architecture struct of phoenix_effect2 is
function imax(x,y: integer) return integer is begin
if x > y then
return x;
else
return y;
end if;
end imax;
-- integer representation of voltage, full range
constant IVmax: integer := integer(2**Vmax_bits)-1;
-- Oscillator1 --
constant Osc1_div: integer := integer(2**Osc1_Div2n);
-- Oscillator1 charge/discharge voltages
constant Osc1_VFc: real := Osc1_Vb; -- V
constant Osc1_iVFc: integer := integer(Osc1_VFc * real(IVmax)/Vmax);
constant Osc1_VFd: real := Osc1_Vce; -- V
constant Osc1_iVFd: integer := integer(Osc1_VFd * real(IVmax)/Vmax);
-- Oscillator1 charge/discharge time constants
constant Osc1_T0_RCc: real := (Osc1_R1+Osc1_R2)*Osc1_C1/1000.0; -- s
constant Osc1_T0_ikc: integer := integer(Osc1_Fs * 1.0E6 * Osc1_T0_RCc / 2.0**Osc1_Div2n);
constant Osc1_T0_RCd: real := Osc1_R2*Osc1_C1/1000.0; -- s
constant Osc1_T0_ikd: integer := integer(Osc1_Fs * 1.0E6 * Osc1_T0_RCd / 2.0**Osc1_Div2n);
constant Osc1_T1_RCc: real := (Osc1_R1+Osc1_R2)*(Osc1_C1+Osc1_C2)/1000.0; -- s
constant Osc1_T1_ikc: integer := integer(Osc1_Fs * 1.0E6 * Osc1_T1_RCc / 2.0**Osc1_Div2n);
constant Osc1_T1_RCd: real := Osc1_R2*(Osc1_C1+Osc1_C2)/1000.0; -- s
constant Osc1_T1_ikd: integer := integer(Osc1_Fs * 1.0E6 * Osc1_T1_RCd / 2.0**Osc1_Div2n);
constant Osc1_T2_RCc: real := (Osc1_R1+Osc1_R2)*(Osc1_C1+Osc1_C3)/1000.0; -- s
constant Osc1_T2_ikc: integer := integer(Osc1_Fs * 1.0E6 * Osc1_T2_RCc / 2.0**Osc1_Div2n);
constant Osc1_T2_RCd: real := Osc1_R2*(Osc1_C1+Osc1_C3)/1000.0; -- s
constant Osc1_T2_ikd: integer := integer(Osc1_Fs * 1.0E6 * Osc1_T2_RCd / 2.0**Osc1_Div2n);
constant Osc1_T3_RCc: real := (Osc1_R1+Osc1_R2)*(Osc1_C1+Osc1_C2+Osc1_C3)/1000.0; -- s
constant Osc1_T3_ikc: integer := integer(Osc1_Fs * 1.0E6 * Osc1_T3_RCc / 2.0**Osc1_Div2n);
constant Osc1_T3_RCd: real := Osc1_R2*(Osc1_C1+Osc1_C2+Osc1_C3)/1000.0; -- s
constant Osc1_T3_ikd: integer := integer(Osc1_Fs * 1.0E6 * Osc1_T3_RCd / 2.0**Osc1_Div2n);
constant Osc1_ik_max: integer := imax( imax(Osc1_T1_ikc,Osc1_T1_ikd), imax(Osc1_T3_ikc,Osc1_T3_ikd));
-- Oscillator2 --
constant Osc2_div: integer := integer(2**Osc2_Div2n);
-- Oscillator2 charge/discharge voltages
constant Osc2_VFc: real := Osc2_Vb; -- V
constant Osc2_iVFc: integer := integer(Osc2_VFc * real(IVmax)/Vmax);
constant Osc2_VFd: real := Osc2_Vce; -- V
constant Osc2_iVFd: integer := integer(Osc2_VFd * real(IVmax)/Vmax);
-- Oscillator2 charge/discharge time constants
constant Osc2_RCc: real := (Osc2_R1+Osc2_R2)*Osc2_C/1000.0; -- s
constant Osc2_ikc: integer := integer(Osc2_Fs * 1.0E6 * Osc2_RCc / 2.0**Osc2_Div2n);
constant Osc2_RCd: real := Osc2_R2*Osc2_C/1000.0; -- s
constant Osc2_ikd: integer := integer(Osc2_Fs * 1.0E6 * Osc2_RCd / 2.0**Osc2_Div2n);
-- Filter2 --
constant Filt2_div: integer := integer(2**Filt2_Div2n);
constant Filt2_R4p: real := 1.0/(1.0/Filt2_R1+1.0/Filt2_R4); -- k
constant Filt2_R5p: real := 1.0/(1.0/Filt2_R1+1.0/Filt2_R5); -- k
constant Filt2_Rp: real := 1.0/(1.0/Filt2_R3+1.0/Filt2_R4+1.0/Filt2_R5p); -- k
constant Filt2_Rs: real := 1.0/(1.0/Filt2_R2+1.0/Filt2_R3-Filt2_Rp/(Filt2_R3**2)); -- k
constant Filt2_RC: real := Filt2_Rs*Filt2_C/1000.0; -- s
constant Filt2_ik: integer := integer(Filt2_Fs*1.0E6*Filt2_RC / 2.0**Filt2_Div2n);
-- Filter2 voltages
constant Filt2_V0: real := Filt2_V*Filt2_Rp*Filt2_Rs/(Filt2_R3*Filt2_R4); -- V
constant Filt2_iV0: integer := integer(Filt2_V0 * real(IVmax)/Vmax);
constant Filt2_V1: real := Filt2_V*Filt2_Rp*Filt2_Rs/(Filt2_R4p*Filt2_R3); -- V
constant Filt2_iV1: integer := integer(Filt2_V1 * real(IVmax)/Vmax);
constant Filt2_V2: real := Filt2_V*Filt2_Rp*Filt2_Rs/(Filt2_R3*Filt2_R4)+Filt2_V*Filt2_Rs/Filt2_R2; -- V
constant Filt2_iV2: integer := integer(Filt2_V2 * real(IVmax)/Vmax);
constant Filt2_V3: real := Filt2_V*Filt2_Rp*Filt2_Rs/(Filt2_R3*Filt2_R4p)+Filt2_V*Filt2_Rs/Filt2_R2; -- V
constant Filt2_iV3: integer := integer(Filt2_V3 * real(IVmax)/Vmax);
-- Oscillator3 --
constant Osc3_div: integer := integer(2**Osc3_Div2n);
-- Oscillator3 charge/discharge voltages
constant Osc3_VFc: real := Osc3_Vb; -- V
constant Osc3_iVFc: integer := integer(Osc3_VFc * real(IVmax)/Vmax);
constant Osc3_VFd: real := Osc3_Vce; -- V
constant Osc3_iVFd: integer := integer(Osc3_VFd * real(IVmax)/Vmax);
-- Oscillator3 charge/discharge time constants
constant Osc3_RCc: real := (Osc3_R1+Osc3_R2)*Osc3_C/1000.0; -- s
constant Osc3_ikc: integer := integer(Osc3_Fs * 1.0E6 * Osc3_RCc / 2.0**Osc3_Div2n);
constant Osc3_RCd: real := Osc3_R2*Osc3_C/1000.0; -- s
constant Osc3_ikd: integer := integer(Osc3_Fs * 1.0E6 * Osc3_RCd / 2.0**Osc3_Div2n);
signal u_c1 : unsigned(15 downto 0) := (others => '0');
signal u_c2 : unsigned(15 downto 0) := (others => '0');
signal u_c3 : unsigned(16 downto 0) := (others => '0');
signal flip1 : std_logic := '0';
signal flip2 : std_logic := '0';
signal flip3 : std_logic := '0';
signal triggers : std_logic_vector(1 downto 0) := "00";
--signal kc : unsigned(15 downto 0) := (others =>'0');
--signal kd : unsigned(15 downto 0) := (others =>'0');
signal kc : integer range 0 to Osc1_ik_max;
signal kd : integer range 0 to Osc1_ik_max;
signal u_cf : unsigned(15 downto 0) := (others => '0');
signal flips : std_logic_vector(1 downto 0) := "00";
signal vf : unsigned(15 downto 0) := (others =>'0');
signal u_cf_scaled : unsigned(23 downto 0) := (others => '0');
signal u_ctrl : unsigned(15 downto 0) := (others => '0');
signal sound: std_logic := '0';
begin
-- Oscillateur1
-- R1 = 47k, R2 = 100k, C1=0.01e-6, C2=0.047e-6, C3=1.000e-6 SR=10MHz
-- Div = 2^8
-- trigger = 00
-- Charge : VF1 = 65535, k1 = 57 (R1+R2, C1)
-- Decharge : VF2 = 2621, k2 = 39 (R2, C1)
-- trigger = 01
-- Charge : VF1 = 65535, k1 = 2756 (R1+R2, C1+C2)
-- Decharge : VF2 = 2621, k2 = 1875 (R2, C1+C2)
-- trigger = 10
-- Charge : VF1 = 65535, k1 = 5800 (R1+R2, C1+C3)
-- Decharge : VF2 = 2621, k2 = 3945 (R2, C1+C3)
-- trigger = 11
-- Charge : VF1 = 65535, k1 = 8498 (R1+R2, C1+C2+C3)
-- Decharge : VF2 = 2621, k2 = 5781 (R2, C1+C2+C3)
triggers <= trigger2 & trigger1;
with triggers select
kc <= Osc1_T0_ikc when "00",
Osc1_T1_ikc when "01",
Osc1_T2_ikc when "10",
Osc1_T3_ikc when others;
with triggers select
kd <= Osc1_T0_ikd when "00",
Osc1_T1_ikd when "01",
Osc1_T2_ikd when "10",
Osc1_T3_ikd when others;
process (clk)
variable cnt: integer range 0 to Osc1_ik_max := 0;
begin
if rising_edge(clk) then
if reset = '1' then
cnt := 0;
u_c1 <= (others => '0');
else
if u_c1 > X"AAAA" then flip1 <= '0'; end if;
if u_c1 < X"5555" then flip1 <= '1'; end if;
cnt := cnt + 1;
if flip1 = '1' then
if cnt = kc then
cnt := 0;
u_c1 <= u_c1 + (Osc1_iVFc - u_c1)/Osc1_div;
end if;
else
if cnt = kd then
cnt := 0;
u_c1 <= u_c1 - (u_c1 - Osc1_iVFd)/Osc1_div;
end if;
end if;
end if;
end if;
end process;
-- Oscillateur2
-- R1 = 510k, R2 = 510k, C=1.000e-6, SR=10MHz
-- Charge : VF1 = 65535, k1 = 39844 (R1+R2, C)
-- Decharge : VF2 = 2621, k2 = 19922 (R2, C)
-- Div = 2^8
process (clk)
variable cnt: integer range 0 to imax(Osc2_ikc,Osc2_ikd) := 0;
begin
if rising_edge(clk) then
if reset = '1' then
cnt := 0;
u_c2 <= (others => '0');
else
if u_c2 > X"AAAA" then flip2 <= '0'; end if;
if u_c2 < X"5555" then flip2 <= '1'; end if;
cnt := cnt + 1;
if flip2 = '1' then
if cnt = Osc2_ikc then
cnt := 0;
u_c2 <= u_c2 + (Osc2_iVFc - u_c2)/Osc2_div;
end if;
else
if cnt = Osc2_ikd then
cnt := 0;
u_c2 <= u_c2 - (u_c2 - Osc2_iVFd)/Osc2_div;
end if;
end if;
end if;
end if;
end process;
-- Filtre
-- V1 = 5V
-- R1 = 10k, R2 = 5.1k, R3 = 5.1k, R4 = 5k, R5 = 10k, C=100.0e-6, SR=10MHz
-- Rp = R3//R4//R4//R1 = 1.68k
-- Rs = 1/(1/R2 + 1/R3 - Rp/(R3*R3)) = 3.05k
-- k = 11922 (Rs*C)
-- Div = 2^8
-- VF00 = 13159 (V*Rp*Rs)/(R4*R3)
-- VF01 = 19738 (V*Rp*Rs)/(R4p*R3)
-- VF10 = 52377 (V*Rp*Rs)/(R4*R3) + V*Rs/R2
-- VF11 = 58957 (V*Rp*Rs)/(R4p*R3) + V*Rs/R2
flips <= flip2 & flip1;
with flips select
vf <= to_unsigned(Filt2_iV0,16) when "00",
to_unsigned(Filt2_iV1,16) when "01",
to_unsigned(Filt2_iV2,16) when "10",
to_unsigned(Filt2_iV3,16) when others;
process (clk)
variable cnt: integer range 0 to Filt2_ik := 0;
begin
if rising_edge(clk) then
if reset = '1' then
cnt := 0;
u_cf <= (others => '0');
else
cnt := cnt + 1;
if vf > u_cf then
if cnt = Filt2_ik then
cnt := 0;
u_cf <= u_cf + (vf - u_cf)/Filt2_div;
end if;
else
if cnt = Filt2_ik then
cnt := 0;
u_cf <= u_cf - (u_cf - vf)/Filt2_div;
end if;
end if;
end if;
end if;
end process;
-- U_CTRL
-- flip1 = 0 u_ctrl = 5V*Rp/R4 + u_cf*Rp/R3 # 22020 + u_cf*84/256
-- flip1 = 1 u_ctrl = 5V*Rp/R4p + u_cf*Rp/R3 # 33063 + u_cf*84/256
u_cf_scaled <= u_cf*to_unsigned(C_flip1_scale,8);
with flip1 select
u_ctrl <= to_unsigned(C_flip1_0,16)+u_cf_scaled(23 downto 8) when '0',
to_unsigned(C_flip1_1,16)+u_cf_scaled(23 downto 8) when others;
-- Oscillateur3
-- R1 = 20k, R2 = 20k, C=0.001e-6 SR=50MHz
-- Charge : VF1 = 65535, k1 = 31 (R1+R2)
-- Decharge : VF2 = 2621, k2 = 16 (R2)
-- Div = 2^6
-- Diviseur
-- LS163 : Count up, Sync load when 0xF (no toggle sound if divider = 0xF)
-- LS74 : Divide by 2
process (clk)
variable cnt: integer range 0 to imax(Osc3_ikc,Osc3_ikd) := 0;
variable cnt2: unsigned(3 downto 0) := (others => '0');
begin
if rising_edge(clk) then
if reset = '1' then
cnt := 0;
u_c3 <= (others => '0');
flip3 <= '0';
else
if u_c3 > u_ctrl then flip3 <= '0'; end if;
if u_c3 < u_ctrl/2 then
flip3 <= '1';
if flip3 = '0' then
cnt2 := cnt2 + 1;
if cnt2 = "0000" then
cnt2 := unsigned(divider);
if divider /= "1111" then sound <= not sound; end if;
end if;
end if;
end if;
cnt := cnt + 1;
if flip3 = '1' then
if cnt = Osc3_ikc then
cnt := 0;
u_c3 <= u_c3 + (Osc3_iVFc - u_c3)/Osc3_div;
end if;
else
if cnt = Osc3_ikd then
cnt := 0;
u_c3 <= u_c3 - (u_c3 - Osc3_iVFd)/Osc3_div;
end if;
end if;
end if;
end if;
end process;
with trigger2 select snd <= '0'&sound when '1', sound&'0' when others;
end struct;