From 6288f407643225de6758d9378a86b6c8128f6973 Mon Sep 17 00:00:00 2001 From: sorgelig Date: Mon, 20 Aug 2018 02:01:31 +0800 Subject: [PATCH] Replace Turbosound with Turbosound FM. --- TSConf-lite.qsf | 6 +- src/sound/ay8910.vhd | 314 ------------- src/sound/jt12/jt12.qip | 21 + src/sound/jt12/jt12.v | 116 +++++ src/sound/jt12/jt12_acc.v | 178 +++++++ src/sound/jt12/jt12_clksync.v | 106 +++++ src/sound/jt12/jt12_eg.v | 621 ++++++++++++++++++++++++ src/sound/jt12/jt12_exprom.v | 76 +++ src/sound/jt12/jt12_kon.v | 68 +++ src/sound/jt12/jt12_lfo.v | 68 +++ src/sound/jt12/jt12_limitamp.v | 42 ++ src/sound/jt12/jt12_mmr.v | 370 +++++++++++++++ src/sound/jt12/jt12_mmr_sim.vh | 836 +++++++++++++++++++++++++++++++++ src/sound/jt12/jt12_mod.v | 122 +++++ src/sound/jt12/jt12_op.v | 536 +++++++++++++++++++++ src/sound/jt12/jt12_opram.v | 79 ++++ src/sound/jt12/jt12_pg.v | 412 ++++++++++++++++ src/sound/jt12/jt12_phrom.v | 77 +++ src/sound/jt12/jt12_reg.v | 363 ++++++++++++++ src/sound/jt12/jt12_sh.v | 45 ++ src/sound/jt12/jt12_sh24.v | 80 ++++ src/sound/jt12/jt12_sh_rst.v | 54 +++ src/sound/jt12/jt12_sumch.v | 37 ++ src/sound/jt12/jt12_syn.v | 338 +++++++++++++ src/sound/jt12/jt12_timers.v | 112 +++++ src/sound/jt12/lut.vh | 92 ++++ src/sound/turbosound.sv | 137 ++++++ src/sound/turbosound.vhd | 78 --- src/sound/ym2149.sv | 354 ++++++++++++++ src/sound/ym2203.sv | 130 +++++ src/tsconf.v | 73 ++- 31 files changed, 5509 insertions(+), 432 deletions(-) delete mode 100644 src/sound/ay8910.vhd create mode 100644 src/sound/jt12/jt12.qip create mode 100644 src/sound/jt12/jt12.v create mode 100644 src/sound/jt12/jt12_acc.v create mode 100644 src/sound/jt12/jt12_clksync.v create mode 100644 src/sound/jt12/jt12_eg.v create mode 100644 src/sound/jt12/jt12_exprom.v create mode 100644 src/sound/jt12/jt12_kon.v create mode 100644 src/sound/jt12/jt12_lfo.v create mode 100644 src/sound/jt12/jt12_limitamp.v create mode 100644 src/sound/jt12/jt12_mmr.v create mode 100644 src/sound/jt12/jt12_mmr_sim.vh create mode 100644 src/sound/jt12/jt12_mod.v create mode 100644 src/sound/jt12/jt12_op.v create mode 100644 src/sound/jt12/jt12_opram.v create mode 100644 src/sound/jt12/jt12_pg.v create mode 100644 src/sound/jt12/jt12_phrom.v create mode 100644 src/sound/jt12/jt12_reg.v create mode 100644 src/sound/jt12/jt12_sh.v create mode 100644 src/sound/jt12/jt12_sh24.v create mode 100644 src/sound/jt12/jt12_sh_rst.v create mode 100644 src/sound/jt12/jt12_sumch.v create mode 100644 src/sound/jt12/jt12_syn.v create mode 100644 src/sound/jt12/jt12_timers.v create mode 100644 src/sound/jt12/lut.vh create mode 100644 src/sound/turbosound.sv delete mode 100644 src/sound/turbosound.vhd create mode 100644 src/sound/ym2149.sv create mode 100644 src/sound/ym2203.sv diff --git a/TSConf-lite.qsf b/TSConf-lite.qsf index 7eb59b5..9e655fe 100644 --- a/TSConf-lite.qsf +++ b/TSConf-lite.qsf @@ -372,8 +372,10 @@ set_global_assignment -name VERILOG_FILE src/cpu/cache_addr.v set_global_assignment -name VHDL_FILE src/rtc/CMOS.vhd set_global_assignment -name VHDL_FILE src/rtc/mc146818a.vhd set_global_assignment -name VHDL_FILE src/sound/soundrive.vhd -set_global_assignment -name VHDL_FILE src/sound/turbosound.vhd -set_global_assignment -name VHDL_FILE src/sound/ay8910.vhd +set_global_assignment -name QIP_FILE src/sound/jt12/jt12.qip +set_global_assignment -name SYSTEMVERILOG_FILE src/sound/ym2149.sv +set_global_assignment -name SYSTEMVERILOG_FILE src/sound/ym2203.sv +set_global_assignment -name SYSTEMVERILOG_FILE src/sound/turbosound.sv set_global_assignment -name VERILOG_FILE src/sound/gs.v set_global_assignment -name SYSTEMVERILOG_FILE src/sound/saa1099.sv set_global_assignment -name VERILOG_FILE src/memory/dma.v diff --git a/src/sound/ay8910.vhd b/src/sound/ay8910.vhd deleted file mode 100644 index 1b925cd..0000000 --- a/src/sound/ay8910.vhd +++ /dev/null @@ -1,314 +0,0 @@ --------------------------------------------------------------------[07.09.2013] --- AY3-8910 -------------------------------------------------------------------------------- --- V0.1 15.10.2011 первая версия - -library IEEE; -use IEEE.std_logic_1164.all; -use IEEE.numeric_std.all; - -entity ay8910 is - port( - CLK : in std_logic; -- System Clock - ENA : in std_logic; -- PSG Clock - RESET : in std_logic; -- Chip Reset (set all Registers to '0', active hi) - BDIR : in std_logic; -- Bus Direction (0 - read , 1 - write) - CS : in std_logic; -- Chip Select (active hi) - BC : in std_logic; -- Bus control - DI : in std_logic_vector(7 downto 0); -- Data In - DO : out std_logic_vector(7 downto 0); -- Data Out - OUT_A : out std_logic_vector(7 downto 0); -- PSG Output channel A - OUT_B : out std_logic_vector(7 downto 0); -- PSG Output channel B - OUT_C : out std_logic_vector(7 downto 0) -- PSG Output channel C - ); -end ay8910; - -architecture rtl of ay8910 is - - signal ClockDiv : unsigned (3 downto 0); -- Divide ENA - --- AY Registers - signal Period_A : std_logic_vector (11 downto 0); -- Channel A Tone Period (R1:R0) - signal Period_B : std_logic_vector (11 downto 0); -- Channel B Tone Period (R3:R2) - signal Period_C : std_logic_vector (11 downto 0); -- Channel C Tone Period (R5:R4) - signal Period_N : std_logic_vector (4 downto 0); -- Noise Period (R6) - signal Enable : std_logic_vector (7 downto 0); -- Enable (R7) - signal Volume_A : std_logic_vector (4 downto 0); -- Channel A Amplitude (R10) - signal Volume_B : std_logic_vector (4 downto 0); -- Channel B Amplitude (R11) - signal Volume_C : std_logic_vector (4 downto 0); -- Channel C Amplitude (R12) - signal Period_E : std_logic_vector (15 downto 0); -- Envelope Period (R14:R13) - signal Shape : std_logic_vector (3 downto 0); -- Envelope Shape/Cycle (R15) --- signal Port_A : std_logic_vector (7 downto 0); -- I/O Port A Data Store (R16) --- signal Port_B : std_logic_vector (7 downto 0); -- I/O Port B Data Store (R17) --- - signal Address : std_logic_vector (3 downto 0); -- Selected Register - - alias Continue : std_logic is Shape(3); -- Envelope Control - alias Attack : std_logic is Shape(2); - alias Alternate : std_logic is Shape(1); - alias Hold : std_logic is Shape(0); - - signal Reset_Req : std_logic; -- Envelope Reset Required - signal Reset_Ack : std_logic; -- Envelope Reset Acknoledge - signal Volume_E : std_logic_vector (3 downto 0); -- Envelope Volume - - signal Freq_A : std_logic; -- Tone Generator A Output - signal Freq_B : std_logic; -- Tone Generator B Output - signal Freq_C : std_logic; -- Tone Generator C Output - signal Freq_N : std_logic; -- Noise Generator Output - - function VolumeTable (value : std_logic_vector(3 downto 0)) return std_logic_vector is - variable result : std_logic_vector (7 downto 0); - begin - case value is -- Volume Table - when "1111" => result := "11111111"; - when "1110" => result := "10110100"; - when "1101" => result := "01111111"; - when "1100" => result := "01011010"; - when "1011" => result := "00111111"; - when "1010" => result := "00101101"; - when "1001" => result := "00011111"; - when "1000" => result := "00010110"; - when "0111" => result := "00001111"; - when "0110" => result := "00001011"; - when "0101" => result := "00000111"; - when "0100" => result := "00000101"; - when "0011" => result := "00000011"; - when "0010" => result := "00000010"; - when "0001" => result := "00000001"; - when "0000" => result := "00000000"; - when others => null; - end case; - return result; - end VolumeTable; - -begin - --- Write to AY -process (RESET , CLK) -begin - if RESET = '1' then - Address <= "0000"; - Period_A <= "000000000000"; - Period_B <= "000000000000"; - Period_C <= "000000000000"; - Period_N <= "00000"; - Enable <= "00000000"; - Volume_A <= "00000"; - Volume_B <= "00000"; - Volume_C <= "00000"; - Period_E <= "0000000000000000"; - Shape <= "0000"; --- Port_A <= "00000000"; --- Port_B <= "00000000"; - Reset_Req <= '0'; - elsif rising_edge(CLK) then - if CS = '1' and BDIR = '1' then - if BC = '1' then - Address <= DI (3 downto 0); -- Latch Address - else - case Address is -- Latch Registers - when "0000" => Period_A (7 downto 0) <= DI; - when "0001" => Period_A (11 downto 8) <= DI (3 downto 0); - when "0010" => Period_B (7 downto 0) <= DI; - when "0011" => Period_B (11 downto 8) <= DI (3 downto 0); - when "0100" => Period_C (7 downto 0) <= DI; - when "0101" => Period_C (11 downto 8) <= DI (3 downto 0); - when "0110" => Period_N <= DI (4 downto 0); - when "0111" => Enable <= DI; - when "1000" => Volume_A <= DI (4 downto 0); - when "1001" => Volume_B <= DI (4 downto 0); - when "1010" => Volume_C <= DI (4 downto 0); - when "1011" => Period_E (7 downto 0) <= DI; - when "1100" => Period_E (15 downto 8) <= DI; - when "1101" => Shape <= DI (3 downto 0); - Reset_Req <= not Reset_Ack; -- Reset Envelope Generator --- when "1110" => Port_A <= DI; --- when "1111" => Port_B <= DI; - when others => null; - end case; - end if; - end if; - end if; -end process; - --- Read from AY -DO <= Period_A (7 downto 0) when Address = "0000" and CS = '1' else - "0000" & Period_A (11 downto 8) when Address = "0001" and CS = '1' else - Period_B (7 downto 0) when Address = "0010" and CS = '1' else - "0000" & Period_B (11 downto 8) when Address = "0011" and CS = '1' else - Period_C (7 downto 0) when Address = "0100" and CS = '1' else - "0000" & Period_C (11 downto 8) when Address = "0101" and CS = '1' else - "000" & Period_N when Address = "0110" and CS = '1' else - Enable when Address = "0111" and CS = '1' else - "000" & Volume_A when Address = "1000" and CS = '1' else - "000" & Volume_B when Address = "1001" and CS = '1' else - "000" & Volume_C when Address = "1010" and CS = '1' else - Period_E (7 downto 0) when Address = "1011" and CS = '1' else - Period_E (15 downto 8) when Address = "1100" and CS = '1' else - "0000" & Shape when Address = "1101" and CS = '1' else - "11111111"; - --- Divide ENA -process (RESET, CLK) -begin - if RESET = '1' then - ClockDiv <= "0000"; - elsif rising_edge(CLK) then - if ENA = '1' then - ClockDiv <= ClockDiv - 1; - end if; - end if; -end process; - --- Tone Generator -process (RESET, CLK) - variable Counter_A : unsigned (11 downto 0); - variable Counter_B : unsigned (11 downto 0); - variable Counter_C : unsigned (11 downto 0); -begin - if RESET = '1' then - Counter_A := "000000000000"; - Counter_B := "000000000000"; - Counter_C := "000000000000"; - Freq_A <= '0'; - Freq_B <= '0'; - Freq_C <= '0'; - elsif rising_edge(CLK) then - if ClockDiv(2 downto 0) = "000" and ENA = '1' then - - -- Channel A Counter - if (Counter_A /= X"000") then - Counter_A := Counter_A - 1; - elsif (Period_A /= X"000") then - Counter_A := unsigned(Period_A) - 1; - end if; - if (Counter_A = X"000") then - Freq_A <= not Freq_A; - end if; - - -- Channel B Counter - if (Counter_B /= X"000") then - Counter_B := Counter_B - 1; - elsif (Period_B /= X"000") then - Counter_B := unsigned(Period_B) - 1; - end if; - if (Counter_B = X"000") then - Freq_B <= not Freq_B; - end if; - - -- Channel C Counter - if (Counter_C /= X"000") then - Counter_C := Counter_C - 1; - elsif (Period_C /= X"000") then - Counter_C := unsigned(Period_C) - 1; - end if; - if (Counter_C = X"000") then - Freq_C <= not Freq_C; - end if; - - end if; - end if; -end process; - --- Noise Generator -process (RESET, CLK) - variable NoiseShift : unsigned (16 downto 0); - variable Counter_N : unsigned (4 downto 0); -begin - if RESET = '1' then - Counter_N := "00000"; - NoiseShift := "00000000000000001"; - elsif rising_edge(CLK) then - if ClockDiv(2 downto 0) = "000" and ENA = '1' then - if (Counter_N /= "00000") then - Counter_N := Counter_N - 1; - elsif (Period_N /= "00000") then - Counter_N := unsigned(Period_N) - 1; - end if; - if Counter_N = "00000" then - NoiseShift := (NoiseShift(0) xor NoiseShift(2)) & NoiseShift(16 downto 1); - end if; - Freq_N <= NoiseShift(0); - end if; - end if; -end process; - --- Envelope Generator -process (RESET , CLK) - variable EnvCounter : unsigned(15 downto 0); - variable EnvWave : unsigned(4 downto 0); -begin - if RESET = '1' then - EnvCounter := "0000000000000000"; - EnvWave := "11111"; - Volume_E <= "0000"; - Reset_Ack <= '0'; - elsif rising_edge(CLK) then - if ClockDiv = "0000" and ENA = '1' then - -- Envelope Period Counter - if (EnvCounter /= X"0000" and Reset_Req = Reset_Ack) then - EnvCounter := EnvCounter - 1; - elsif (Period_E /= X"0000") then - EnvCounter := unsigned(Period_E) - 1; - end if; - - -- Envelope Phase Counter - if (Reset_Req /= Reset_Ack) then - EnvWave := (others => '1'); - elsif (EnvCounter = X"0000" and (EnvWave(4) = '1' or (Hold = '0' and Continue = '1'))) then - EnvWave := EnvWave - 1; - end if; - - -- Envelope Amplitude Counter - for I in 3 downto 0 loop - if (EnvWave(4) = '0' and Continue = '0') then - Volume_E(I) <= '0'; - elsif (EnvWave(4) = '1' or (Alternate xor Hold) = '0') then - Volume_E(I) <= EnvWave(I) xor Attack; - else - Volume_E(I) <= EnvWave(I) xor Attack xor '1'; - end if; - end loop; - Reset_Ack <= Reset_Req; - end if; - end if; -end process; - --- Mixer -process (RESET , CLK) -begin - if RESET = '1' then - OUT_A <= "00000000"; - OUT_B <= "00000000"; - OUT_C <= "00000000"; - elsif rising_edge(CLK) then - if ENA = '1' then - if (((Enable(0) or Freq_A) and (Enable(3) or Freq_N)) = '0') then - OUT_A <= "00000000"; - elsif (Volume_A(4) = '0') then - OUT_A <= VolumeTable(Volume_A(3 downto 0)); - else - OUT_A <= VolumeTable(Volume_E); - end if; - - if (((Enable(1) or Freq_B) and (Enable(4) or Freq_N)) = '0') then - OUT_B <= "00000000"; - elsif (Volume_B(4) = '0') then - OUT_B <= VolumeTable(Volume_B(3 downto 0)); - else - OUT_B <= VolumeTable(Volume_E); - end if; - - if (((Enable(2) or Freq_C) and (Enable(5) or Freq_N)) = '0') then - OUT_C <= "00000000"; - elsif (Volume_C(4) = '0') then - OUT_C <= VolumeTable(Volume_C(3 downto 0)); - else - OUT_C <= VolumeTable(Volume_E); - end if; - end if; - end if; -end process; - -end rtl; \ No newline at end of file diff --git a/src/sound/jt12/jt12.qip b/src/sound/jt12/jt12.qip new file mode 100644 index 0000000..6225f7d --- /dev/null +++ b/src/sound/jt12/jt12.qip @@ -0,0 +1,21 @@ +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_acc.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_clksync.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_eg.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_exprom.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_kon.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_lfo.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_limitamp.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_mmr.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_mod.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_op.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_opram.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_pg.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_phrom.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_reg.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_sh.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_sh_rst.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_sh24.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_sumch.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_syn.v +set_global_assignment -name VERILOG_FILE src/sound/jt12/jt12_timers.v diff --git a/src/sound/jt12/jt12.v b/src/sound/jt12/jt12.v new file mode 100644 index 0000000..caa242b --- /dev/null +++ b/src/sound/jt12/jt12.v @@ -0,0 +1,116 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Based on information provided by + Sauraen VHDL version of OPN/OPN2, which is based on die shots. + Nemesis reports, based on measurements + Comparisons with real hardware lent by Mikes (Va de retro) + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 1-4-2017 + + Use tab = 4 spaces + +*/ + +// syn_clk "1.285714" + +module jt12( + input rst, + // CPU interface + input cpu_clk, + input [7:0] cpu_din, + input [1:0] cpu_addr, + input cpu_cs_n, + input cpu_wr_n, + input cpu_limiter_en, + + output [7:0] cpu_dout, + output cpu_irq_n, + // Synthesizer clock domain + input syn_clk, + // combined output + output signed [11:0] syn_snd_right, + output signed [11:0] syn_snd_left, + output syn_snd_sample, + // multiplexed output + output signed [8:0] syn_mux_right, + output signed [8:0] syn_mux_left, + output syn_mux_sample +); + +// Timers +wire syn_flag_A, syn_flag_B; + + +wire [7:0] syn_din; +wire [1:0] syn_addr; +wire syn_write, syn_limiter_en, syn_busy; +wire syn_rst, syn_irq_n; + +jt12_clksync u_clksync( + .rst ( rst ), + .cpu_clk ( cpu_clk ), + .syn_clk ( syn_clk ), + + // CPU interface + .cpu_din ( cpu_din ), + .cpu_addr ( cpu_addr ), + .cpu_dout ( cpu_dout ), + .cpu_cs_n ( cpu_cs_n ), + .cpu_wr_n ( cpu_wr_n ), + .cpu_irq_n ( cpu_irq_n ), + .cpu_limiter_en( cpu_limiter_en ), + + // Synthesizer interface + .syn_rst ( syn_rst ), + .syn_write ( syn_write ), + .syn_din ( syn_din ), + .syn_addr ( syn_addr ), + .syn_limiter_en( syn_limiter_en ), + + .syn_busy ( syn_busy ), + .syn_flag_A ( syn_flag_A), + .syn_flag_B ( syn_flag_B), + .syn_irq_n ( syn_irq_n ) +); + +jt12_syn u_syn( + .rst ( syn_rst ), + .clk ( syn_clk ), + .din ( syn_din ), + .addr ( syn_addr ), + .busy ( syn_busy ), + .flag_A ( syn_flag_A), + .flag_B ( syn_flag_B), + .write ( syn_write ), + .limiter_en ( syn_limiter_en), + .irq_n ( syn_irq_n ), + // Mixed sound + .snd_right ( syn_snd_right ), + .snd_left ( syn_snd_left ), + .snd_sample ( syn_snd_sample), + // Multiplexed sound + .mux_right ( syn_mux_right ), + .mux_left ( syn_mux_left ), + .mux_sample ( syn_mux_sample) +); + +endmodule diff --git a/src/sound/jt12/jt12_acc.v b/src/sound/jt12/jt12_acc.v new file mode 100644 index 0000000..e2e7047 --- /dev/null +++ b/src/sound/jt12/jt12_acc.v @@ -0,0 +1,178 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + + Each channel can use the full range of the DAC as they do not + get summed in the real chip. + +*/ + + + +`timescale 1ns / 1ps + +module jt12_acc +( + input rst, + input clk, + input signed [8:0] op_result, + input [ 1:0] rl, + input limiter_en, // enables the limiter on + // the accumulator to prevent overfow. + // I reckon that: + // YM2612 had a limiter + // YM3438 did not + // note that the order changes to deal + // with the operator pipeline delay + input s1_enters, + input s2_enters, + input s3_enters, + input s4_enters, + input ch6op, + input [2:0] alg, + input pcm_en, // only enabled for channel 6 + input [8:0] pcm, + // combined output + output reg signed [11:0] left, + output reg signed [11:0] right, + output sample, + // multiplexed output + output reg signed [8:0] mux_left, + output reg signed [8:0] mux_right, + output reg mux_sample +); + +reg signed [11:0] pre_left, pre_right; +wire signed [8:0] total; +reg sum_en; + +always @(*) begin + case ( alg ) + default: sum_en <= s4_enters; + 3'd4: sum_en <= s2_enters | s4_enters; + 3'd5,3'd6: sum_en <= ~s1_enters; + 3'd7: sum_en <= 1'b1; + endcase +end + +reg sum_all; +assign sample = ~sum_all; + +wire [8:0] buffer; +reg [8:0] buffer2; +reg [8:0] buf_mux; +reg [1:0] rl2,rl3; +reg last_s1; +reg [1:0] mux_cnt; + +wire signed [11:0] total_signext = { {3{total[8]}}, total }; + +always @(posedge clk) begin : mux_dac_input + buffer2 <= buffer; + rl2 <= rl; + last_s1 <= s1_enters; + mux_cnt <= last_s1 && s3_enters ? 2'd01 : mux_cnt + 1'b1; + if( mux_cnt==2'b11 ) begin + if( s1_enters || s3_enters ) begin + buf_mux <= buffer2; + rl3 <= rl2; + end + else begin + buf_mux <= buffer; + rl3 <= rl; + end + end + if( mux_cnt==2'd0 ) begin + mux_left <= rl3[1] ? buf_mux : 9'd0; + mux_right<= rl3[0] ? buf_mux : 9'd0; + mux_sample <= 1'b1; + end + else + mux_sample <= 1'b0; +end + +always @(posedge clk) begin + if( rst ) begin + sum_all <= 1'b0; + end + else begin + if( s3_enters ) begin + sum_all <= 1'b1; + if( !sum_all ) begin + pre_right <= rl[0] ? total_signext : 12'd0; + pre_left <= rl[1] ? total_signext : 12'd0; + end + else begin + pre_right <= pre_right + (rl[0] ? total_signext : 12'd0); + pre_left <= pre_left + (rl[1] ? total_signext : 12'd0); + end + end + if( s2_enters ) begin + sum_all <= 1'b0; + left <= pre_left; + right <= pre_right; + `ifdef DUMPSOUND + $strobe("%d\t%d", left, right); + `endif + end + end +end + +reg signed [8:0] next, opsum, prev; +wire signed [9:0] opsum10 = next+total; + +always @(*) begin + next <= sum_en ? op_result : 9'd0; + if( s3_enters ) + opsum <= (ch6op && pcm_en) ? { ~pcm[8], pcm[7:0] } : next; + else begin + if( sum_en && !(ch6op && pcm_en) ) + if( limiter_en ) begin + if( opsum10[9]==opsum10[8] ) + opsum <= opsum10[8:0]; + else begin + opsum <= opsum10[9] ? 9'h100 : 9'h0ff; + end + end + else begin + // MSB is discarded according to + // YM3438 application notes + opsum <= opsum10[8:0]; + end + else + opsum <= total; + end +end + +jt12_sh #(.width(9),.stages(6)) u_acc( + .clk ( clk ), + .din ( opsum ), + .drop ( total ) +); + +jt12_sh #(.width(9),.stages(6)) u_buffer( + .clk ( clk ), + .din ( s3_enters ? total : buffer ), + .drop ( buffer ) +); + +endmodule diff --git a/src/sound/jt12/jt12_clksync.v b/src/sound/jt12/jt12_clksync.v new file mode 100644 index 0000000..3ad3a7c --- /dev/null +++ b/src/sound/jt12/jt12_clksync.v @@ -0,0 +1,106 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2017 + +*/ + +module jt12_clksync( + input rst, + input cpu_clk, + input syn_clk, + + // CPU interface + input [7:0] cpu_din, + input [1:0] cpu_addr, + output[7:0] cpu_dout, + input cpu_cs_n, + input cpu_wr_n, + output cpu_irq_n, + input cpu_limiter_en, + + // Synthesizer interface + output reg [7:0] syn_din, + output reg [1:0] syn_addr, + output reg syn_rst, + output reg syn_write, + output syn_limiter_en, + + input syn_busy, + input syn_flag_A, + input syn_flag_B, + input syn_irq_n +); + +// reset generation +reg rst_aux; + +assign syn_limiter_en = cpu_limiter_en; + +always @(negedge syn_clk or posedge rst) + if( rst ) begin + syn_rst <= 1'b1; + rst_aux <= 1'b1; + end + else begin + syn_rst <= rst_aux; + rst_aux <= 1'b0; + end + +reg cpu_busy; +wire cpu_flag_B, cpu_flag_A; + +assign cpu_dout = cpu_cs_n ? 8'hFF : { cpu_busy, 5'h0, cpu_flag_B, cpu_flag_A }; + +wire write_raw = !cpu_cs_n && !cpu_wr_n; + +reg [1:0]busy_sh; +always @(posedge cpu_clk) begin + busy_sh <= { busy_sh[0], syn_busy }; +end + +jt12_sh #(.width(3),.stages(2) ) u_syn2cpu( + .clk ( cpu_clk ), + .din ( { syn_flag_B, syn_flag_A, syn_irq_n } ), + .drop ( { cpu_flag_B, cpu_flag_A, cpu_irq_n } ) +); + +always @(posedge cpu_clk) begin + reg old_write; + + old_write <= write_raw; + + if( rst ) begin + cpu_busy <= 1'b0; + end + else begin + if( ~old_write & write_raw ) begin + cpu_busy <= 1; + syn_write <= ~syn_write; + syn_addr <= cpu_addr; + syn_din <= cpu_din; + end + + if(cpu_busy && busy_sh==2'b10) cpu_busy <= 0; + end +end + +endmodule diff --git a/src/sound/jt12/jt12_eg.v b/src/sound/jt12/jt12_eg.v new file mode 100644 index 0000000..bccf571 --- /dev/null +++ b/src/sound/jt12/jt12_eg.v @@ -0,0 +1,621 @@ +/* This file is part of JT12. + + JT12 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2017 + + The non SSG-EG section is basically that of JT51's jt51_envelope.v + adapted to 6 channels, instead of the eight. + + The SSG-EG is based on the works of Nemesis, published on + http://gendev.spritesmind.net/forum/search.php?st=0&sk=t&sd=d&sr=posts&keywords=SSG-EG&t=386&sf=msgonly&ch=-1&start=15 + + This module tries to replicate exactly the original YM2612 waveforms. + Nonetheless, the verilog code is not a replica of the original circuit + as there is no reverse engineering description of it. + + Questions: + -I latch the SSG enable bit on keyon. I have to do this in order to ignore the inversion bit before the keyon + -If SSG enable is set to 0 by software before issueing a keyoff it will be ignored + -However, the other SSG bits will have an effect if changed in the meantime between keyon and keyoff + -Was YM2612 like that? + + */ + +`timescale 1ns / 1ps + +/* + + tab size 4 + +*/ + +module jt12_eg ( + `ifdef TEST_SUPPORT + input test_eg, + `endif + input rst, + input clk, + input zero, + input eg_stop, + // envelope configuration + input [4:0] keycode_III, + input [4:0] arate_II, // attack rate + input [4:0] rate1_II, // decay rate + input [4:0] rate2_II, // sustain rate + input [3:0] rrate_II, // release rate + input [3:0] d1l, // sustain level + input [1:0] ks_III, // key scale + // SSG operation + input ssg_en_II, + input [2:0] ssg_eg_II, + // envelope operation + input keyon_II, + // envelope number + input [6:0] am, + input [6:0] tl_VII, + input [1:0] ams_VII, + input amsen_VII, + + output reg [9:0] eg_IX, + output reg pg_rst_III +); + + // eg[9:6] -> direct attenuation (divide by 2) + // eg[5:0] -> mantisa attenuation (uses LUT) + // 1 LSB of eg is -0.09257 dB + +wire ssg_inv_II = ssg_eg_II[2] & ssg_en_II; +wire ssg_alt_II = ssg_eg_II[1] & ssg_en_II; +wire ssg_hold_II = ssg_eg_II[0] & ssg_en_II; + +parameter ATTACK=3'd0, DECAY1=3'd1, DECAY2=3'd2, RELEASE=3'd7, HOLD=3'd3; + +reg [4:0] d1level_II; +reg [9:0] eg_III, eg_IV, eg_V; +wire [9:0] eg_II; + +reg step_V; +reg sum_up; +reg [5:0] rate_V; + +// remember: { log_msb, pow_addr } <= log_val[11:0] + { tl, 5'd0 } + { eg, 2'd0 }; + +reg [1:0] eg_cnt_base; +reg [14:0] eg_cnt; + +always @(posedge clk) begin : envelope_counter + if( rst ) begin + eg_cnt_base <= 2'd0; + eg_cnt <=15'd0; + end + else begin + if( zero ) begin + // envelope counter increases every 3 output samples, + // there is one sample every 32 clock ticks + if( eg_cnt_base == 2'd2 ) begin + eg_cnt <= eg_cnt + 1'b1; + eg_cnt_base <= 2'd0; + end + else eg_cnt_base <= eg_cnt_base + 1'b1; + end + end +end + +wire cnt_out; // = all_cnt_last[3*31-1:3*30]; + + +reg [7:0] step_idx; +reg [2:0] state_III, state_IV, state_V, state_VI, state_VII, state_VIII; +wire [2:0] state_II; + + +wire ar_off_VI; +reg ar_off_III; + +// Register Cycle I + +always @(posedge clk) begin + if( d1l == 4'd15 ) + d1level_II <= 5'h1f; // 93dB + else + d1level_II <= d1l; +end + +// Register Cycle II +wire ssg_invertion_II, ssg_invertion_VIII; +reg ssg_invertion_III; +reg [4:0] cfg_III; +wire ssg_pg_rst = eg_II>=10'h200 && ssg_en_II && + !( ssg_alt_II || ssg_hold_II ); +wire ssg_en_out; +wire keyon_last_II; +reg ssg_en_in_II; + +always @(*) begin + if( state_II==RELEASE ) + ssg_en_in_II <= 1'b0; + else + ssg_en_in_II <= keyon_II ? ssg_en_II : ssg_en_out; +end + +wire ar_off_II = arate_II == 5'h1f; + +wire keyon_now_II = !keyon_last_II && keyon_II; +wire keyoff_now_II = keyon_last_II && !keyon_II; + +always @(posedge clk) begin + // ar_off_III <= arate_II == 5'h1f; + // trigger release + if( keyoff_now_II ) begin + cfg_III <= { rrate_II, 1'b1 }; + state_III <= RELEASE; + pg_rst_III <= 1'b0; + ar_off_III <= 1'b0; + end + else begin + // trigger 1st decay + if( keyon_now_II ) begin + cfg_III <= arate_II; + state_III <= ATTACK; + pg_rst_III <= 1'b1; + ar_off_III <= ar_off_II; + end + else begin : sel_rate + pg_rst_III <= (eg_II==10'h3FF) ||ssg_pg_rst; + if( (state_II==DECAY1 ||state_II==DECAY2) && ssg_en_II && eg_II >= 10'h200 ) begin + ssg_invertion_III <= ssg_alt_II ^ ssg_invertion_II; + if( ssg_hold_II ) begin + cfg_III <= 5'd0; + state_III <= HOLD; // repeats! + ar_off_III <= 1'b0; + end + else begin + cfg_III <= rate2_II; + state_III <= ATTACK; // repeats! + ar_off_III <= 1'b1; + end + end + else begin + ssg_invertion_III <= state_II==RELEASE ? 1'b0 : ssg_invertion_II; + case ( state_II ) + ATTACK: begin + if( eg_II==10'd0 ) begin + state_III <= DECAY1; + cfg_III <= rate1_II; + end + else begin + state_III <= state_II; // attack + cfg_III <= arate_II; + end + ar_off_III <= 1'b0; + end + DECAY1: begin + if( eg_II[9:5] >= d1level_II ) begin + cfg_III <= rate2_II; + state_III <= DECAY2; + end + else begin + cfg_III <= rate1_II; + state_III <= state_II; // decay1 + end + ar_off_III <= 1'b0; + end + DECAY2: + begin + cfg_III <= rate2_II; + state_III <= state_II; // decay2 + ar_off_III <= 1'b0; + end + RELEASE: begin + cfg_III <= { rrate_II, 1'b1 }; + state_III <= state_II; // release + ar_off_III <= 1'b0; + end + HOLD: begin + cfg_III <= 5'd0; + state_III <= HOLD; // repeats! + ar_off_III <= 1'b0; + end + endcase + end + end + end + + eg_III <= eg_II; +end + +/////////////////////////////////////////////////////////////////// +// Register Cycle III +reg [6:0] pre_rate_III; +reg [5:0] rate_IV; + +always @(*) begin : pre_rate_calc + if( cfg_III == 5'd0 ) + pre_rate_III <= 6'd0; + else + case( ks_III ) + 2'd3: pre_rate_III <= { cfg_III, 1'b0 } + keycode_III; + 2'd2: pre_rate_III <= { cfg_III, 1'b0 } + { 1'b0, keycode_III[4:1] }; + 2'd1: pre_rate_III <= { cfg_III, 1'b0 } + { 2'b0, keycode_III[4:2] }; + 2'd0: pre_rate_III <= { cfg_III, 1'b0 } + { 3'b0, keycode_III[4:3] }; + endcase +end + +always @(posedge clk) begin + if( rst ) begin + state_IV <= RELEASE; + eg_IV <= 10'h3ff; + rate_IV <= 5'h1F; + end + else begin + state_IV <= state_III; + eg_IV <= eg_III; + rate_IV <= pre_rate_III[6] ? 6'd63 : pre_rate_III[5:0]; + end +end +/////////////////////////////////////////////////////////////////// +// Register Cycle IV +reg [2:0] cnt_V; + +always @(posedge clk) begin + if( rst ) begin + state_V <= RELEASE; + rate_V <= 5'h1f; + eg_V <= 10'h3ff; + //cnt_V<= 3'd0; + end + else begin + state_V <= state_IV; + rate_V <= rate_IV; + eg_V <= eg_IV; + if( state_IV == ATTACK ) + case( rate_IV[5:2] ) + 4'h0: cnt_V <= eg_cnt[13:11]; + 4'h1: cnt_V <= eg_cnt[12:10]; + 4'h2: cnt_V <= eg_cnt[11: 9]; + 4'h3: cnt_V <= eg_cnt[10: 8]; + 4'h4: cnt_V <= eg_cnt[ 9: 7]; + 4'h5: cnt_V <= eg_cnt[ 8: 6]; + 4'h6: cnt_V <= eg_cnt[ 7: 5]; + 4'h7: cnt_V <= eg_cnt[ 6: 4]; + 4'h8: cnt_V <= eg_cnt[ 5: 3]; + 4'h9: cnt_V <= eg_cnt[ 4: 2]; + 4'ha: cnt_V <= eg_cnt[ 3: 1]; + default: cnt_V <= eg_cnt[ 2: 0]; + endcase + else + case( rate_IV[5:2] ) + 4'h0: cnt_V <= eg_cnt[14:12]; + 4'h1: cnt_V <= eg_cnt[13:11]; + 4'h2: cnt_V <= eg_cnt[12:10]; + 4'h3: cnt_V <= eg_cnt[11: 9]; + 4'h4: cnt_V <= eg_cnt[10: 8]; + 4'h5: cnt_V <= eg_cnt[ 9: 7]; + 4'h6: cnt_V <= eg_cnt[ 8: 6]; + 4'h7: cnt_V <= eg_cnt[ 7: 5]; + 4'h8: cnt_V <= eg_cnt[ 6: 4]; + 4'h9: cnt_V <= eg_cnt[ 5: 3]; + 4'ha: cnt_V <= eg_cnt[ 4: 2]; + 4'hb: cnt_V <= eg_cnt[ 3: 1]; + default: cnt_V <= eg_cnt[ 2: 0]; + endcase + end +end +////////////////////////////////////////////////////////////// +// Register Cycle V +always @(*) begin : rate_step + if( rate_V[5:4]==2'b11 ) begin // 0 means 1x, 1 means 2x + if( rate_V[5:2]==4'hf && state_V == ATTACK) + step_idx <= 8'b11111111; // Maximum attack speed, rates 60&61 + else + case( rate_V[1:0] ) + 2'd0: step_idx <= 8'b00000000; + 2'd1: step_idx <= 8'b10001000; // 2 + 2'd2: step_idx <= 8'b10101010; // 4 + 2'd3: step_idx <= 8'b11101110; // 6 + endcase + end + else begin + if( rate_V[5:2]==4'd0 && state_V != ATTACK) + step_idx <= 8'b11111110; // limit slowest decay rate_IV + else + case( rate_V[1:0] ) + 2'd0: step_idx <= 8'b10101010; // 4 + 2'd1: step_idx <= 8'b11101010; // 5 + 2'd2: step_idx <= 8'b11101110; // 6 + 2'd3: step_idx <= 8'b11111110; // 7 + endcase + end + // a rate_IV of zero keeps the level still + step_V <= rate_V[5:1]==5'd0 ? 1'b0 : step_idx[ cnt_V ]; +end + +reg [5:1] rate_VI; +reg [9:0] eg_VI; +reg step_VI; + +always @(posedge clk) begin + if( rst ) begin + state_VI <= RELEASE; + rate_VI <= 5'd1; + eg_VI <= 10'h3ff; + sum_up <= 1'b0; + step_VI <= 1'b0; + end + else begin + state_VI <= state_V; + rate_VI <= rate_V[5:1]; + eg_VI <= eg_V; + sum_up <= cnt_V[0] != cnt_out; + step_VI <= step_V; + end +end +////////////////////////////////////////////////////////////// +// Register cycle VI +reg [3:0] preatt_VI; +reg [5:0] att_VI; +wire ssg_en_VI; +reg [9:0] eg_VII, eg_stopped_VII; +reg [10:0] egatt_VI; + +always @(*) begin + case( rate_VI[5:2] ) + 4'b1100: preatt_VI <= { step_VI, ~step_VI }; // 12 + 4'b1101: preatt_VI <= { step_VI, ~step_VI, 1'b0 }; // 13 + 4'b1110: preatt_VI <= { step_VI, ~step_VI, 2'b0 }; // 14 + 4'b1111: preatt_VI <= 4'd8;// 15 + default: preatt_VI <= { step_VI, 1'b0 }; + endcase + att_VI <= ssg_en_VI ? { preatt_VI, 2'd0 } : { 2'd0, preatt_VI }; + egatt_VI <= att_VI + eg_VI; + eg_stopped_VII <= eg_VI; +end + +reg [8:0] ar_sum0; +reg [9:0] ar_result, ar_sum; + +always @(*) begin : ar_calculation + casex( rate_VI[5:2] ) + default: ar_sum0 <= eg_VI[9:4] + 1'd1; + 4'b1100: ar_sum0 <= eg_VI[9:4] + 1'd1; + 4'b1101: ar_sum0 <= eg_VI[9:3] + 1'd1; + 4'b111x: ar_sum0 <= eg_VI[9:2] + 1'd1; + endcase + if( rate_VI[5:4] == 2'b11 ) + ar_sum <= step_VI ? { ar_sum0, 1'b0 } : { 1'b0, ar_sum0 }; + else + ar_sum <= step_VI ? { 1'b0, ar_sum0 } : 10'd0; + ar_result <= ar_sum 2'b0 ? {10{1'b1}} : sum_eg_tl[9:0]; + state_VIII <= state_VII; + end +end + +////////////////////////////////////////////////////////////// +// Register cycle VIII +wire ssg_inv_VIII, ssg_en_VIII; +//reg [9:0] eg_IX; +always @(posedge clk) begin + if( rst ) + eg_IX <= 10'h3ff; + else begin + if( ssg_en_VIII && (ssg_invertion_VIII ^^ ssg_inv_VIII) ) + eg_IX <= eg_internal_VIII>=10'h200 ? 10'h0 : (10'h200 - eg_internal_VIII); + else + eg_IX <= eg_internal_VIII; + end +end + +////////////////////////////////////////////////////////////// +// Register cycle IX-XII +/* +jt12_sh #(.width(10), .stages(12-8)) u_padding( + .clk ( clk ), + .din ( eg_IX ), + .drop ( eg_XII ) +); +*/ +////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////// +// Shift registers + +jt12_sh24 #( .width(1) ) u_ssgen( + .clk ( clk ), + .din ( ssg_en_in_II ), + .st4 ( ssg_en_VI ), + .st6 ( ssg_en_VIII ), // note that din is *_II + .st24 ( ssg_en_out ) +); + +jt12_sh #( .width(1), .stages(6) ) u_ssgattsh( + .clk ( clk ), + .din ( ssg_inv_II ), + .drop ( ssg_inv_VIII ) +); + +jt12_sh #( .width(1), .stages(3) ) u_aroffsh( + .clk ( clk ), + .din ( ar_off_III), + .drop ( ar_off_VI ) +); + +jt12_sh #( .width(1), .stages(5) ) u_ssg1sh( + .clk ( clk ), + .din ( ssg_invertion_III ), + .drop ( ssg_invertion_VIII ) +); + + +jt12_sh #( .width(1), .stages(18) ) u_ssg2sh( + .clk ( clk ), + .din ( ssg_invertion_VIII ), + .drop ( ssg_invertion_II ) +); + + +/* Had 27 stages in JT51, for 32 operators + Has 19 stages here, for 24 operators + plus 1 extra stage. 20 stages does not work well. + Maybe JT51 should be 26!! */ +jt12_sh/*_rst*/ #( .width(10), .stages(19)/*, .rstval(1'b1)*/ ) u_egsh( + .clk ( clk ), +// .rst ( rst ), + .din ( eg_stop ? eg_stopped_VII : eg_VII ), + .drop ( eg_II ) +); + +/* Had 32 stages in JT51, for 32 operators + Has 24 stages here, for 24 operators */ +jt12_sh/*_rst*/ #( .width(1), .stages(24) ) u_cntsh( + .clk ( clk ), +// .rst ( rst ), + .din ( cnt_V[0] ), + .drop ( cnt_out ) +); + +jt12_sh_rst #( .width(1), .stages(24) ) u_konsh( + .clk ( clk ), +// .rst ( rst ), + .din ( keyon_II ), + .drop ( keyon_last_II ) +); + +/* Had 31 stages in JT51, for 32 operators + Has 23 stages here, for 24 operators */ +jt12_sh/*_rst*/ #( .width(3), .stages(18)/*, .rstval(1'b1)*/ ) u_statesh( + .clk ( clk ), +// .rst ( rst ), + .din ( state_VIII), + .drop ( state_II ) +); + +`ifdef SIMULATION +reg [4:0] sep24_cnt; + +wire [2:0] state_ch0s1, state_ch1s1, state_ch2s1, state_ch3s1, + state_ch4s1, state_ch5s1, state_ch0s2, state_ch1s2, + state_ch2s2, state_ch3s2, state_ch4s2, state_ch5s2, + state_ch0s3, state_ch1s3, state_ch2s3, state_ch3s3, + state_ch4s3, state_ch5s3, state_ch0s4, state_ch1s4, + state_ch2s4, state_ch3s4, state_ch4s4, state_ch5s4; + + +always @(posedge clk) + sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; + +sep24 #( .width(3), .pos0(0) ) stsep +( + .clk ( clk ), + .mixed ( state_II ), + .mask ( 0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (state_ch0s1), + .ch1s1 (state_ch1s1), + .ch2s1 (state_ch2s1), + .ch3s1 (state_ch3s1), + .ch4s1 (state_ch4s1), + .ch5s1 (state_ch5s1), + + .ch0s2 (state_ch0s2), + .ch1s2 (state_ch1s2), + .ch2s2 (state_ch2s2), + .ch3s2 (state_ch3s2), + .ch4s2 (state_ch4s2), + .ch5s2 (state_ch5s2), + + .ch0s3 (state_ch0s3), + .ch1s3 (state_ch1s3), + .ch2s3 (state_ch2s3), + .ch3s3 (state_ch3s3), + .ch4s3 (state_ch4s3), + .ch5s3 (state_ch5s3), + + .ch0s4 (state_ch0s4), + .ch1s4 (state_ch1s4), + .ch2s4 (state_ch2s4), + .ch3s4 (state_ch3s4), + .ch4s4 (state_ch4s4), + .ch5s4 (state_ch5s4) +); + +`endif + +endmodule + diff --git a/src/sound/jt12/jt12_exprom.v b/src/sound/jt12/jt12_exprom.v new file mode 100644 index 0000000..a564725 --- /dev/null +++ b/src/sound/jt12/jt12_exprom.v @@ -0,0 +1,76 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ +// altera message_off 10030 + +module jt12_exprom +( + input [4:0] addr, + input clk, + output reg [44:0] exp +); + + reg [44:0] explut_jt51[31:0]; + initial + begin + explut_jt51[0] <= 45'b111110101011010110001011010000010010111011011; + explut_jt51[1] <= 45'b111101010011010101000011001100101110110101011; + explut_jt51[2] <= 45'b111011111011010011110111001000110010101110011; + explut_jt51[3] <= 45'b111010100101010010101111000100110010101000011; + explut_jt51[4] <= 45'b111001001101010001100111000000110010100001011; + explut_jt51[5] <= 45'b110111111011010000011110111101010010011011011; + explut_jt51[6] <= 45'b110110100011001111010110111001010010010100100; + explut_jt51[7] <= 45'b110101001011001110001110110101110010001110011; + explut_jt51[8] <= 45'b110011111011001101000110110001110010001000011; + explut_jt51[9] <= 45'b110010100011001011111110101110010010000010011; + explut_jt51[10] <= 45'b110001010011001010111010101010010001111011011; + explut_jt51[11] <= 45'b101111111011001001110010100110110001110101011; + explut_jt51[12] <= 45'b101110101011001000101010100011001101101111011; + explut_jt51[13] <= 45'b101101010101000111100110011111010001101001011; + explut_jt51[14] <= 45'b101100000011000110100010011011110001100011011; + explut_jt51[15] <= 45'b101010110011000101011110011000010001011101011; + explut_jt51[16] <= 45'b101001100011000100011010010100101101010111011; + explut_jt51[17] <= 45'b101000010011000011010010010001001101010001011; + explut_jt51[18] <= 45'b100111000011000010010010001101101101001011011; + explut_jt51[19] <= 45'b100101110011000001001110001010001101000101011; + explut_jt51[20] <= 45'b100100100011000000001010000110010000111111011; + explut_jt51[21] <= 45'b100011010010111111001010000011001100111001011; + explut_jt51[22] <= 45'b100010000010111110000101111111101100110011011; + explut_jt51[23] <= 45'b100000110010111101000001111100001100101101011; + explut_jt51[24] <= 45'b011111101010111100000001111000101100101000010; + explut_jt51[25] <= 45'b011110011010111011000001110101001100100010011; + explut_jt51[26] <= 45'b011101001010111010000001110001110000011100011; + explut_jt51[27] <= 45'b011100000010111001000001101110010000010110011; + explut_jt51[28] <= 45'b011010110010111000000001101011001100010001011; + explut_jt51[29] <= 45'b011001101010110111000001100111101100001011011; + explut_jt51[30] <= 45'b011000100000110110000001100100010000000110010; + explut_jt51[31] <= 45'b010111010010110101000001100001001100000000011; + end + + always @ (posedge clk) + exp <= explut_jt51[addr]; + +endmodule diff --git a/src/sound/jt12/jt12_kon.v b/src/sound/jt12/jt12_kon.v new file mode 100644 index 0000000..78d41d2 --- /dev/null +++ b/src/sound/jt12/jt12_kon.v @@ -0,0 +1,68 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + +module jt12_kon( + input rst, + input clk, + input [3:0] keyon_op, + input [2:0] keyon_ch, + input [1:0] cur_op, + input [2:0] cur_ch, + input up_keyon, + input csm, + input flag_A, + input overflow_A, + + output reg keyon_II +); + +//reg csm_copy; + +reg din; +wire drop; + +reg [3:0] cur_op_hot; + +always @(posedge clk) + keyon_II <= (csm&&cur_ch==2'd2&&overflow_A) || drop; + +always @(*) begin + case( cur_op ) + 2'd0: cur_op_hot <= 4'b0001; // S1 + 2'd1: cur_op_hot <= 4'b0100; // S3 + 2'd2: cur_op_hot <= 4'b0010; // S2 + 2'd3: cur_op_hot <= 4'b1000; // S4 + endcase + din <= keyon_ch==cur_ch && up_keyon ? |(keyon_op&cur_op_hot) : drop; +end + +jt12_sh_rst #(.width(1),.stages(24)) u_konch( + .clk ( clk ), +// .rst ( rst ), + .din ( din ), + .drop ( drop ) +); + +endmodule diff --git a/src/sound/jt12/jt12_lfo.v b/src/sound/jt12/jt12_lfo.v new file mode 100644 index 0000000..26c3e24 --- /dev/null +++ b/src/sound/jt12/jt12_lfo.v @@ -0,0 +1,68 @@ +/* This file is part of jt12. + + jt12 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + jt12 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with jt12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 25-2-2017 + */ + +`timescale 1ns / 1ps + +/* + + tab size 4 + +*/ + +module jt12_lfo( + input rst, + input clk, + input zero, + input lfo_rst, + input lfo_en, + input [2:0] lfo_freq, + output reg [6:0] lfo_mod +); + +reg [6:0] cnt, limit; + +always @(*) + case( lfo_freq ) + 3'd0: limit <= 7'd108; + 3'd1: limit <= 7'd78; + 3'd2: limit <= 7'd71; + 3'd3: limit <= 7'd67; + 3'd4: limit <= 7'd62; + 3'd5: limit <= 7'd44; + 3'd6: limit <= 7'd8; + 3'd7: limit <= 7'd5; + endcase + +always @(posedge clk) begin + if( rst || !lfo_en ) + { lfo_mod, cnt } <= 14'd0; + else begin + if(zero) begin + if( cnt == limit ) begin + cnt <= 7'd0; + lfo_mod <= lfo_mod + 1'b1; + end + else + cnt <= cnt + 1'b1; + end + end +end + +endmodule diff --git a/src/sound/jt12/jt12_limitamp.v b/src/sound/jt12/jt12_limitamp.v new file mode 100644 index 0000000..d6ff147 --- /dev/null +++ b/src/sound/jt12/jt12_limitamp.v @@ -0,0 +1,42 @@ +/* This file is part of JT12. + + JT12 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: March, 10th 2017 + */ + +/* Limiting amplifier by 3dB * shift */ + +`timescale 1ns / 1ps + +module jt12_limitamp #( parameter width=20, shift=5 ) ( + input signed [width-1:0] left_in, + input signed [width-1:0] right_in, + output reg signed [width-1:0] left_out, + output reg signed [width-1:0] right_out +); + +always @(*) begin + left_out <= ^left_in[width-1:width-1-shift] ? + { left_in[width-1], {(width-1){~left_in[width-1]}}} : + left_in <<< shift; + + right_out <= ^right_in[width-1:width-1-shift] ? + { right_in[width-1], {(width-1){~right_in[width-1]}}} : + right_in <<< shift; +end + +endmodule diff --git a/src/sound/jt12/jt12_mmr.v b/src/sound/jt12/jt12_mmr.v new file mode 100644 index 0000000..aea9c4a --- /dev/null +++ b/src/sound/jt12/jt12_mmr.v @@ -0,0 +1,370 @@ +/* This file is part of JT12. + + JT12 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2017 + */ + +`timescale 1ns / 1ps + +module jt12_mmr( + input rst, + input clk, + input [7:0] din, + input write, + input [1:0] addr, + output reg busy, + output ch6op, + // LFO + output reg [2:0] lfo_freq, + output reg lfo_en, + // Timers + output reg [9:0] value_A, + output reg [7:0] value_B, + output reg load_A, + output reg load_B, + output reg enable_irq_A, + output reg enable_irq_B, + output reg clr_flag_A, + output reg clr_flag_B, + output reg fast_timers, + input flag_A, + input overflow_A, + // PCM + output reg [8:0] pcm, + output reg pcm_en, + + `ifdef TEST_SUPPORT + // Test + output reg test_eg, + output reg test_op0, + `endif + // Operator + output use_prevprev1, + output use_internal_x, + output use_internal_y, + output use_prev2, + output use_prev1, + // PG + output [10:0] fnum_I, + output [ 2:0] block_I, + output reg pg_stop, + // REG + output [ 1:0] rl, + output [ 2:0] fb_II, + output [ 2:0] alg, + output [ 2:0] pms, + output [ 1:0] ams_VII, + output amsen_VII, + output [ 2:0] dt1_II, + output [ 3:0] mul_V, + output [ 6:0] tl_VII, + output reg eg_stop, + + output [ 4:0] ar_II, + output [ 4:0] d1r_II, + output [ 4:0] d2r_II, + output [ 3:0] rr_II, + output [ 3:0] d1l, + output [ 1:0] ks_III, + // SSG operation + output ssg_en_II, + output [2:0] ssg_eg_II, + + output keyon_II, + +// output [ 1:0] cur_op, + // Operator + output zero, + output s1_enters, + output s2_enters, + output s3_enters, + output s4_enters +); + +reg [7:0] selected_register; + +//reg sch; // 0 => CH1~CH3 only available. 1=>CH4~CH6 +/* +reg irq_zero_en, irq_brdy_en, irq_eos_en, + irq_tb_en, irq_ta_en; + */ +reg up_clr; +reg up_alg; + +reg up_block; +reg up_fnumlo; +reg up_pms; +reg up_dt1; +reg up_tl; +reg up_ks_ar; +reg up_amen_d1r; +reg up_d2r; +reg up_d1l; +reg up_ssgeg; +reg up_keyon; + +wire busy_reg; + +parameter REG_TEST = 8'h01, + REG_TEST2 = 8'h02, + REG_TESTYM = 8'h21, + REG_LFO = 8'h22, + REG_CLKA1 = 8'h24, + REG_CLKA2 = 8'h25, + REG_CLKB = 8'h26, + REG_TIMER = 8'h27, + REG_KON = 8'h28, + REG_IRQMASK = 8'h29, + REG_PCM = 8'h2A, + REG_PCM_EN = 8'h2B, + REG_DACTEST = 8'h2C, + REG_CLK_N6 = 8'h2D, + REG_CLK_N3 = 8'h2E, + REG_CLK_N2 = 8'h2F; + + +reg csm, effect; + +reg [ 2:0] block_ch3op2, block_ch3op3, block_ch3op1; +reg [10:0] fnum_ch3op2, fnum_ch3op3, fnum_ch3op1; +reg [ 5:0] latch_ch3op2, latch_ch3op3, latch_ch3op1; + + +reg [2:0] up_ch; +reg [1:0] up_op; + +`include "jt12_mmr_sim.vh" + +always @(posedge clk) begin : memory_mapped_registers + reg old_write; + old_write <= write; + + if( rst ) begin + selected_register <= 8'h0; + busy <= 1'b0; + up_ch <= 3'd0; + up_op <= 2'd0; + { up_keyon, up_alg, up_block, up_fnumlo, + up_pms, up_dt1, up_tl, up_ks_ar, + up_amen_d1r,up_d2r, up_d1l, up_ssgeg } <= 12'd0; + `ifdef TEST_SUPPORT + { test_eg, test_op0 } <= 2'd0; + `endif + // IRQ Mask + /*{ irq_zero_en, irq_brdy_en, irq_eos_en, + irq_tb_en, irq_ta_en } = 5'h1f; */ + // timers + { value_A, value_B } <= 18'd0; + { clr_flag_B, clr_flag_A, + enable_irq_B, enable_irq_A, load_B, load_A } <= 6'd0; + up_clr <= 1'b0; + fast_timers <= 1'b0; + // LFO + lfo_freq <= 3'd0; + lfo_en <= 1'b0; + csm <= 1'b0; + effect <= 1'b0; + // PCM + pcm <= 9'h0; + pcm_en <= 1'b0; + // sch <= 1'b0; + // Original test features + eg_stop <= 1'b0; + pg_stop <= 1'b0; + `ifdef SIMULATION + mmr_dump <= 1'b0; + `endif + end else begin + // WRITE IN REGISTERS + if( old_write ^ write ) begin + busy <= 1'b1; + if( !addr[0] ) begin + selected_register <= din; + up_ch <= {addr[1], din[1:0]}; + up_op <= din[3:2]; // 0=S1,1=S3,2=S2,3=S4 + end else begin + // Global registers + if( selected_register < 8'h30 ) begin + case( selected_register) + // registros especiales + //REG_TEST: lfo_rst <= 1'b1; // regardless of din + `ifdef TEST_SUPPORT + REG_TEST2: { mmr_dump, test_op0, test_eg } <= din[2:0]; + `endif + REG_TESTYM: begin + eg_stop <= din[5]; + pg_stop <= din[3]; + fast_timers <= din[2]; + end + REG_KON: up_keyon <= 1'b1; + REG_CLKA1: value_A[9:2]<= din; + REG_CLKA2: value_A[1:0]<= din[1:0]; + REG_CLKB: value_B <= din; + REG_TIMER: begin + effect <= |din[7:6]; + csm <= din[7:6] == 2'b10; + { clr_flag_B, clr_flag_A, + enable_irq_B, enable_irq_A, + load_B, load_A } <= din[5:0]; + end + REG_LFO: { lfo_en, lfo_freq } <= din[3:0]; + REG_DACTEST:pcm[0] <= din[3]; + REG_PCM: pcm[8:1]<= din; + REG_PCM_EN: pcm_en <= din[7]; + endcase + end + else if( selected_register[1:0]!=2'b11 ) begin + // channel registers + if( selected_register >= 8'hA0 ) begin + case( selected_register ) + 8'hA0, 8'hA1, 8'hA2: up_fnumlo <= 1'b1; + 8'hA4, 8'hA5, 8'hA6: up_block <= 1'b1; + // CH3 special registers + 8'hA9: { block_ch3op1, fnum_ch3op1 } <= { latch_ch3op1, din }; + 8'hA8: { block_ch3op3, fnum_ch3op3 } <= { latch_ch3op3, din }; + 8'hAA: { block_ch3op2, fnum_ch3op2 } <= { latch_ch3op2, din }; + 8'hAD: latch_ch3op1 <= din[5:0]; + 8'hAC: latch_ch3op3 <= din[5:0]; + 8'hAE: latch_ch3op2 <= din[5:0]; + // FB + Algorithm + 8'hB0, 8'hB1, 8'hB2: up_alg <= 1'b1; + 8'hB4, 8'hB5, 8'hB6: up_pms <= 1'b1; + endcase + end + else + // operator registers + begin + case( selected_register[7:4] ) + 4'h3: up_dt1 <= 1'b1; + 4'h4: up_tl <= 1'b1; + 4'h5: up_ks_ar <= 1'b1; + 4'h6: up_amen_d1r <= 1'b1; + 4'h7: up_d2r <= 1'b1; + 4'h8: up_d1l <= 1'b1; + 4'h9: up_ssgeg <= 1'b1; + endcase + end + end + end + end + else begin /* clear once-only bits */ + // csm <= 1'b0; + // lfo_rst <= 1'b0; + { clr_flag_B, clr_flag_A, load_B, load_A } <= 4'd0; + `ifdef SIMULATION + mmr_dump <= 1'b0; + `endif + up_keyon <= 1'b0; + if( |{ up_keyon, up_alg, up_block, up_fnumlo, + up_pms, up_dt1, up_tl, up_ks_ar, + up_amen_d1r,up_d2r, up_d1l, up_ssgeg } == 1'b0 ) + busy <= 0; + else + busy <= 1'b1; + + if( busy_reg ) begin + up_clr <= 1'b1; + end + else begin + up_clr <= 1'b0; + if( up_clr ) + { up_alg, up_block, up_fnumlo, + up_pms, up_dt1, up_tl, up_ks_ar, + up_amen_d1r,up_d2r, up_d1l, up_ssgeg } <= 11'd0; + end + end + end +end + +jt12_reg u_reg( + .rst ( rst ), + .clk ( clk ), // P1 + .din ( din ), + + .up_keyon ( up_keyon ), + .up_alg ( up_alg ), + .up_block ( up_block ), + .up_fnumlo ( up_fnumlo ), + .up_pms ( up_pms ), + .up_dt1 ( up_dt1 ), + .up_tl ( up_tl ), + .up_ks_ar ( up_ks_ar ), + .up_amen_d1r(up_amen_d1r), + .up_d2r ( up_d2r ), + + .up_d1l ( up_d1l ), + .up_ssgeg ( up_ssgeg ), + + .op ( up_op ), // operator to update + .ch ( up_ch ), // channel to update + + .csm ( csm ), + .flag_A ( flag_A ), + .overflow_A ( overflow_A), + + .busy ( busy_reg ), + .ch6op ( ch6op ), + // CH3 Effect-mode operation + .effect ( effect ), // allows independent freq. for CH 3 + .fnum_ch3op2( fnum_ch3op2 ), + .fnum_ch3op3( fnum_ch3op3 ), + .fnum_ch3op1( fnum_ch3op1 ), + .block_ch3op2( block_ch3op2 ), + .block_ch3op3( block_ch3op3 ), + .block_ch3op1( block_ch3op1 ), + // Operator + .use_prevprev1(use_prevprev1), + .use_internal_x(use_internal_x), + .use_internal_y(use_internal_y), + .use_prev2 ( use_prev2 ), + .use_prev1 ( use_prev1 ), + // PG + .fnum_I ( fnum_I ), + .block_I ( block_I ), + .mul_V ( mul_V ), + .dt1_II ( dt1_II ), + + // EG + .ar_II (ar_II ), // attack rate + .d1r_II (d1r_II ), // decay rate + .d2r_II (d2r_II ), // sustain rate + .rr_II (rr_II ), // release rate + .d1l (d1l ), // sustain level + .ks_III (ks_III ), // key scale + // SSG operation + .ssg_en_II ( ssg_en_II ), + .ssg_eg_II ( ssg_eg_II ), + // envelope number + .tl_VII (tl_VII ), + .pms (pms ), + .ams_VII (ams_VII ), + .amsen_VII (amsen_VII ), + // channel configuration + .rl ( rl ), + .fb_II ( fb_II ), + .alg ( alg ), + .keyon_II ( keyon_II ), + + //.cur_op ( cur_op ), + .zero ( zero ), + .s1_enters ( s1_enters ), + .s2_enters ( s2_enters ), + .s3_enters ( s3_enters ), + .s4_enters ( s4_enters ) +); + +endmodule diff --git a/src/sound/jt12/jt12_mmr_sim.vh b/src/sound/jt12/jt12_mmr_sim.vh new file mode 100644 index 0000000..5bddb08 --- /dev/null +++ b/src/sound/jt12/jt12_mmr_sim.vh @@ -0,0 +1,836 @@ +`ifdef SIMULATION + +reg [4:0] sep24_cnt; +reg mmr_dump; + +always @(posedge clk ) + sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; + +wire [10:0] fnum_ch0s1, fnum_ch1s1, fnum_ch2s1, fnum_ch3s1, + fnum_ch4s1, fnum_ch5s1, fnum_ch0s2, fnum_ch1s2, + fnum_ch2s2, fnum_ch3s2, fnum_ch4s2, fnum_ch5s2, + fnum_ch0s3, fnum_ch1s3, fnum_ch2s3, fnum_ch3s3, + fnum_ch4s3, fnum_ch5s3, fnum_ch0s4, fnum_ch1s4, + fnum_ch2s4, fnum_ch3s4, fnum_ch4s4, fnum_ch5s4; + +sep24 #( .width(11), .pos0(1) ) fnum_sep +( + .clk ( clk ), + .mixed ( fnum_I ), + .mask ( 11'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (fnum_ch0s1), + .ch1s1 (fnum_ch1s1), + .ch2s1 (fnum_ch2s1), + .ch3s1 (fnum_ch3s1), + .ch4s1 (fnum_ch4s1), + .ch5s1 (fnum_ch5s1), + + .ch0s2 (fnum_ch0s2), + .ch1s2 (fnum_ch1s2), + .ch2s2 (fnum_ch2s2), + .ch3s2 (fnum_ch3s2), + .ch4s2 (fnum_ch4s2), + .ch5s2 (fnum_ch5s2), + + .ch0s3 (fnum_ch0s3), + .ch1s3 (fnum_ch1s3), + .ch2s3 (fnum_ch2s3), + .ch3s3 (fnum_ch3s3), + .ch4s3 (fnum_ch4s3), + .ch5s3 (fnum_ch5s3), + + .ch0s4 (fnum_ch0s4), + .ch1s4 (fnum_ch1s4), + .ch2s4 (fnum_ch2s4), + .ch3s4 (fnum_ch3s4), + .ch4s4 (fnum_ch4s4), + .ch5s4 (fnum_ch5s4) +); + +wire [2:0] block_ch0s1, block_ch1s1, block_ch2s1, block_ch3s1, + block_ch4s1, block_ch5s1, block_ch0s2, block_ch1s2, + block_ch2s2, block_ch3s2, block_ch4s2, block_ch5s2, + block_ch0s3, block_ch1s3, block_ch2s3, block_ch3s3, + block_ch4s3, block_ch5s3, block_ch0s4, block_ch1s4, + block_ch2s4, block_ch3s4, block_ch4s4, block_ch5s4; + +sep24 #( .width(3), .pos0(1) ) block_sep +( + .clk ( clk ), + .mixed ( block_I ), + .mask ( 3'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (block_ch0s1), + .ch1s1 (block_ch1s1), + .ch2s1 (block_ch2s1), + .ch3s1 (block_ch3s1), + .ch4s1 (block_ch4s1), + .ch5s1 (block_ch5s1), + + .ch0s2 (block_ch0s2), + .ch1s2 (block_ch1s2), + .ch2s2 (block_ch2s2), + .ch3s2 (block_ch3s2), + .ch4s2 (block_ch4s2), + .ch5s2 (block_ch5s2), + + .ch0s3 (block_ch0s3), + .ch1s3 (block_ch1s3), + .ch2s3 (block_ch2s3), + .ch3s3 (block_ch3s3), + .ch4s3 (block_ch4s3), + .ch5s3 (block_ch5s3), + + .ch0s4 (block_ch0s4), + .ch1s4 (block_ch1s4), + .ch2s4 (block_ch2s4), + .ch3s4 (block_ch3s4), + .ch4s4 (block_ch4s4), + .ch5s4 (block_ch5s4) +); + +wire [1:0] rl_ch0s1, rl_ch1s1, rl_ch2s1, rl_ch3s1, + rl_ch4s1, rl_ch5s1, rl_ch0s2, rl_ch1s2, + rl_ch2s2, rl_ch3s2, rl_ch4s2, rl_ch5s2, + rl_ch0s3, rl_ch1s3, rl_ch2s3, rl_ch3s3, + rl_ch4s3, rl_ch5s3, rl_ch0s4, rl_ch1s4, + rl_ch2s4, rl_ch3s4, rl_ch4s4, rl_ch5s4; + +sep24 #( .width(2), .pos0(1) ) rl_sep +( + .clk ( clk ), + .mixed ( rl ), + .mask ( 2'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (rl_ch0s1), + .ch1s1 (rl_ch1s1), + .ch2s1 (rl_ch2s1), + .ch3s1 (rl_ch3s1), + .ch4s1 (rl_ch4s1), + .ch5s1 (rl_ch5s1), + + .ch0s2 (rl_ch0s2), + .ch1s2 (rl_ch1s2), + .ch2s2 (rl_ch2s2), + .ch3s2 (rl_ch3s2), + .ch4s2 (rl_ch4s2), + .ch5s2 (rl_ch5s2), + + .ch0s3 (rl_ch0s3), + .ch1s3 (rl_ch1s3), + .ch2s3 (rl_ch2s3), + .ch3s3 (rl_ch3s3), + .ch4s3 (rl_ch4s3), + .ch5s3 (rl_ch5s3), + + .ch0s4 (rl_ch0s4), + .ch1s4 (rl_ch1s4), + .ch2s4 (rl_ch2s4), + .ch3s4 (rl_ch3s4), + .ch4s4 (rl_ch4s4), + .ch5s4 (rl_ch5s4) +); + +wire [2:0] fb_ch0s1, fb_ch1s1, fb_ch2s1, fb_ch3s1, + fb_ch4s1, fb_ch5s1, fb_ch0s2, fb_ch1s2, + fb_ch2s2, fb_ch3s2, fb_ch4s2, fb_ch5s2, + fb_ch0s3, fb_ch1s3, fb_ch2s3, fb_ch3s3, + fb_ch4s3, fb_ch5s3, fb_ch0s4, fb_ch1s4, + fb_ch2s4, fb_ch3s4, fb_ch4s4, fb_ch5s4; + +sep24 #( .width(3), .pos0(0) ) fb_sep +( + .clk ( clk ), + .mixed ( fb_II ), + .mask ( 3'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (fb_ch0s1), + .ch1s1 (fb_ch1s1), + .ch2s1 (fb_ch2s1), + .ch3s1 (fb_ch3s1), + .ch4s1 (fb_ch4s1), + .ch5s1 (fb_ch5s1), + + .ch0s2 (fb_ch0s2), + .ch1s2 (fb_ch1s2), + .ch2s2 (fb_ch2s2), + .ch3s2 (fb_ch3s2), + .ch4s2 (fb_ch4s2), + .ch5s2 (fb_ch5s2), + + .ch0s3 (fb_ch0s3), + .ch1s3 (fb_ch1s3), + .ch2s3 (fb_ch2s3), + .ch3s3 (fb_ch3s3), + .ch4s3 (fb_ch4s3), + .ch5s3 (fb_ch5s3), + + .ch0s4 (fb_ch0s4), + .ch1s4 (fb_ch1s4), + .ch2s4 (fb_ch2s4), + .ch3s4 (fb_ch3s4), + .ch4s4 (fb_ch4s4), + .ch5s4 (fb_ch5s4) +); + +wire [2:0] alg_ch0s1, alg_ch1s1, alg_ch2s1, alg_ch3s1, + alg_ch4s1, alg_ch5s1, alg_ch0s2, alg_ch1s2, + alg_ch2s2, alg_ch3s2, alg_ch4s2, alg_ch5s2, + alg_ch0s3, alg_ch1s3, alg_ch2s3, alg_ch3s3, + alg_ch4s3, alg_ch5s3, alg_ch0s4, alg_ch1s4, + alg_ch2s4, alg_ch3s4, alg_ch4s4, alg_ch5s4; + +sep24 #( .width(3), .pos0(1) ) alg_sep +( + .clk ( clk ), + .mixed ( alg ), + .mask ( 3'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (alg_ch0s1), + .ch1s1 (alg_ch1s1), + .ch2s1 (alg_ch2s1), + .ch3s1 (alg_ch3s1), + .ch4s1 (alg_ch4s1), + .ch5s1 (alg_ch5s1), + + .ch0s2 (alg_ch0s2), + .ch1s2 (alg_ch1s2), + .ch2s2 (alg_ch2s2), + .ch3s2 (alg_ch3s2), + .ch4s2 (alg_ch4s2), + .ch5s2 (alg_ch5s2), + + .ch0s3 (alg_ch0s3), + .ch1s3 (alg_ch1s3), + .ch2s3 (alg_ch2s3), + .ch3s3 (alg_ch3s3), + .ch4s3 (alg_ch4s3), + .ch5s3 (alg_ch5s3), + + .ch0s4 (alg_ch0s4), + .ch1s4 (alg_ch1s4), + .ch2s4 (alg_ch2s4), + .ch3s4 (alg_ch3s4), + .ch4s4 (alg_ch4s4), + .ch5s4 (alg_ch5s4) +); + +wire [2:0] dt1_ch0s1, dt1_ch1s1, dt1_ch2s1, dt1_ch3s1, + dt1_ch4s1, dt1_ch5s1, dt1_ch0s2, dt1_ch1s2, + dt1_ch2s2, dt1_ch3s2, dt1_ch4s2, dt1_ch5s2, + dt1_ch0s3, dt1_ch1s3, dt1_ch2s3, dt1_ch3s3, + dt1_ch4s3, dt1_ch5s3, dt1_ch0s4, dt1_ch1s4, + dt1_ch2s4, dt1_ch3s4, dt1_ch4s4, dt1_ch5s4; + +sep24 #( .width(3), .pos0(0) ) dt1_sep +( + .clk ( clk ), + .mixed ( dt1_II ), + .mask ( 3'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (dt1_ch0s1), + .ch1s1 (dt1_ch1s1), + .ch2s1 (dt1_ch2s1), + .ch3s1 (dt1_ch3s1), + .ch4s1 (dt1_ch4s1), + .ch5s1 (dt1_ch5s1), + + .ch0s2 (dt1_ch0s2), + .ch1s2 (dt1_ch1s2), + .ch2s2 (dt1_ch2s2), + .ch3s2 (dt1_ch3s2), + .ch4s2 (dt1_ch4s2), + .ch5s2 (dt1_ch5s2), + + .ch0s3 (dt1_ch0s3), + .ch1s3 (dt1_ch1s3), + .ch2s3 (dt1_ch2s3), + .ch3s3 (dt1_ch3s3), + .ch4s3 (dt1_ch4s3), + .ch5s3 (dt1_ch5s3), + + .ch0s4 (dt1_ch0s4), + .ch1s4 (dt1_ch1s4), + .ch2s4 (dt1_ch2s4), + .ch3s4 (dt1_ch3s4), + .ch4s4 (dt1_ch4s4), + .ch5s4 (dt1_ch5s4) +); + +wire [3:0] mul_ch0s1, mul_ch1s1, mul_ch2s1, mul_ch3s1, + mul_ch4s1, mul_ch5s1, mul_ch0s2, mul_ch1s2, + mul_ch2s2, mul_ch3s2, mul_ch4s2, mul_ch5s2, + mul_ch0s3, mul_ch1s3, mul_ch2s3, mul_ch3s3, + mul_ch4s3, mul_ch5s3, mul_ch0s4, mul_ch1s4, + mul_ch2s4, mul_ch3s4, mul_ch4s4, mul_ch5s4; + +sep24 #( .width(4), .pos0(21) ) mul_sep +( + .clk ( clk ), + .mixed ( mul_V ), + .mask ( 4'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (mul_ch0s1), + .ch1s1 (mul_ch1s1), + .ch2s1 (mul_ch2s1), + .ch3s1 (mul_ch3s1), + .ch4s1 (mul_ch4s1), + .ch5s1 (mul_ch5s1), + + .ch0s2 (mul_ch0s2), + .ch1s2 (mul_ch1s2), + .ch2s2 (mul_ch2s2), + .ch3s2 (mul_ch3s2), + .ch4s2 (mul_ch4s2), + .ch5s2 (mul_ch5s2), + + .ch0s3 (mul_ch0s3), + .ch1s3 (mul_ch1s3), + .ch2s3 (mul_ch2s3), + .ch3s3 (mul_ch3s3), + .ch4s3 (mul_ch4s3), + .ch5s3 (mul_ch5s3), + + .ch0s4 (mul_ch0s4), + .ch1s4 (mul_ch1s4), + .ch2s4 (mul_ch2s4), + .ch3s4 (mul_ch3s4), + .ch4s4 (mul_ch4s4), + .ch5s4 (mul_ch5s4) +); + +wire [6:0] tl_ch0s1, tl_ch1s1, tl_ch2s1, tl_ch3s1, + tl_ch4s1, tl_ch5s1, tl_ch0s2, tl_ch1s2, + tl_ch2s2, tl_ch3s2, tl_ch4s2, tl_ch5s2, + tl_ch0s3, tl_ch1s3, tl_ch2s3, tl_ch3s3, + tl_ch4s3, tl_ch5s3, tl_ch0s4, tl_ch1s4, + tl_ch2s4, tl_ch3s4, tl_ch4s4, tl_ch5s4; + +sep24 #( .width(7), .pos0(19) ) tl_step +( + .clk ( clk ), + .mixed ( tl_VII ), + .mask ( 7'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (tl_ch0s1), + .ch1s1 (tl_ch1s1), + .ch2s1 (tl_ch2s1), + .ch3s1 (tl_ch3s1), + .ch4s1 (tl_ch4s1), + .ch5s1 (tl_ch5s1), + + .ch0s2 (tl_ch0s2), + .ch1s2 (tl_ch1s2), + .ch2s2 (tl_ch2s2), + .ch3s2 (tl_ch3s2), + .ch4s2 (tl_ch4s2), + .ch5s2 (tl_ch5s2), + + .ch0s3 (tl_ch0s3), + .ch1s3 (tl_ch1s3), + .ch2s3 (tl_ch2s3), + .ch3s3 (tl_ch3s3), + .ch4s3 (tl_ch4s3), + .ch5s3 (tl_ch5s3), + + .ch0s4 (tl_ch0s4), + .ch1s4 (tl_ch1s4), + .ch2s4 (tl_ch2s4), + .ch3s4 (tl_ch3s4), + .ch4s4 (tl_ch4s4), + .ch5s4 (tl_ch5s4) +); + +wire [4:0] ar_ch0s1, ar_ch1s1, ar_ch2s1, ar_ch3s1, + ar_ch4s1, ar_ch5s1, ar_ch0s2, ar_ch1s2, + ar_ch2s2, ar_ch3s2, ar_ch4s2, ar_ch5s2, + ar_ch0s3, ar_ch1s3, ar_ch2s3, ar_ch3s3, + ar_ch4s3, ar_ch5s3, ar_ch0s4, ar_ch1s4, + ar_ch2s4, ar_ch3s4, ar_ch4s4, ar_ch5s4; + +sep24 #( .width(5), .pos0(0) ) ar_step +( + .clk ( clk ), + .mixed ( ar_II ), + .mask ( 5'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (ar_ch0s1), + .ch1s1 (ar_ch1s1), + .ch2s1 (ar_ch2s1), + .ch3s1 (ar_ch3s1), + .ch4s1 (ar_ch4s1), + .ch5s1 (ar_ch5s1), + + .ch0s2 (ar_ch0s2), + .ch1s2 (ar_ch1s2), + .ch2s2 (ar_ch2s2), + .ch3s2 (ar_ch3s2), + .ch4s2 (ar_ch4s2), + .ch5s2 (ar_ch5s2), + + .ch0s3 (ar_ch0s3), + .ch1s3 (ar_ch1s3), + .ch2s3 (ar_ch2s3), + .ch3s3 (ar_ch3s3), + .ch4s3 (ar_ch4s3), + .ch5s3 (ar_ch5s3), + + .ch0s4 (ar_ch0s4), + .ch1s4 (ar_ch1s4), + .ch2s4 (ar_ch2s4), + .ch3s4 (ar_ch3s4), + .ch4s4 (ar_ch4s4), + .ch5s4 (ar_ch5s4) +); + +wire [4:0] d1r_ch0s1, d1r_ch1s1, d1r_ch2s1, d1r_ch3s1, + d1r_ch4s1, d1r_ch5s1, d1r_ch0s2, d1r_ch1s2, + d1r_ch2s2, d1r_ch3s2, d1r_ch4s2, d1r_ch5s2, + d1r_ch0s3, d1r_ch1s3, d1r_ch2s3, d1r_ch3s3, + d1r_ch4s3, d1r_ch5s3, d1r_ch0s4, d1r_ch1s4, + d1r_ch2s4, d1r_ch3s4, d1r_ch4s4, d1r_ch5s4; + +sep24 #( .width(5), .pos0(0) ) d1r_step +( + .clk ( clk ), + .mixed ( d1r_II ), + .mask ( 0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (d1r_ch0s1), + .ch1s1 (d1r_ch1s1), + .ch2s1 (d1r_ch2s1), + .ch3s1 (d1r_ch3s1), + .ch4s1 (d1r_ch4s1), + .ch5s1 (d1r_ch5s1), + + .ch0s2 (d1r_ch0s2), + .ch1s2 (d1r_ch1s2), + .ch2s2 (d1r_ch2s2), + .ch3s2 (d1r_ch3s2), + .ch4s2 (d1r_ch4s2), + .ch5s2 (d1r_ch5s2), + + .ch0s3 (d1r_ch0s3), + .ch1s3 (d1r_ch1s3), + .ch2s3 (d1r_ch2s3), + .ch3s3 (d1r_ch3s3), + .ch4s3 (d1r_ch4s3), + .ch5s3 (d1r_ch5s3), + + .ch0s4 (d1r_ch0s4), + .ch1s4 (d1r_ch1s4), + .ch2s4 (d1r_ch2s4), + .ch3s4 (d1r_ch3s4), + .ch4s4 (d1r_ch4s4), + .ch5s4 (d1r_ch5s4) +); + +wire [4:0] d2r_ch0s1, d2r_ch1s1, d2r_ch2s1, d2r_ch3s1, + d2r_ch4s1, d2r_ch5s1, d2r_ch0s2, d2r_ch1s2, + d2r_ch2s2, d2r_ch3s2, d2r_ch4s2, d2r_ch5s2, + d2r_ch0s3, d2r_ch1s3, d2r_ch2s3, d2r_ch3s3, + d2r_ch4s3, d2r_ch5s3, d2r_ch0s4, d2r_ch1s4, + d2r_ch2s4, d2r_ch3s4, d2r_ch4s4, d2r_ch5s4; + +sep24 #( .width(5), .pos0(0) ) d2r_step +( + .clk ( clk ), + .mixed ( d2r_II ), + .mask ( 5'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (d2r_ch0s1), + .ch1s1 (d2r_ch1s1), + .ch2s1 (d2r_ch2s1), + .ch3s1 (d2r_ch3s1), + .ch4s1 (d2r_ch4s1), + .ch5s1 (d2r_ch5s1), + + .ch0s2 (d2r_ch0s2), + .ch1s2 (d2r_ch1s2), + .ch2s2 (d2r_ch2s2), + .ch3s2 (d2r_ch3s2), + .ch4s2 (d2r_ch4s2), + .ch5s2 (d2r_ch5s2), + + .ch0s3 (d2r_ch0s3), + .ch1s3 (d2r_ch1s3), + .ch2s3 (d2r_ch2s3), + .ch3s3 (d2r_ch3s3), + .ch4s3 (d2r_ch4s3), + .ch5s3 (d2r_ch5s3), + + .ch0s4 (d2r_ch0s4), + .ch1s4 (d2r_ch1s4), + .ch2s4 (d2r_ch2s4), + .ch3s4 (d2r_ch3s4), + .ch4s4 (d2r_ch4s4), + .ch5s4 (d2r_ch5s4) +); + +wire [3:0] rr_ch0s1, rr_ch1s1, rr_ch2s1, rr_ch3s1, + rr_ch4s1, rr_ch5s1, rr_ch0s2, rr_ch1s2, + rr_ch2s2, rr_ch3s2, rr_ch4s2, rr_ch5s2, + rr_ch0s3, rr_ch1s3, rr_ch2s3, rr_ch3s3, + rr_ch4s3, rr_ch5s3, rr_ch0s4, rr_ch1s4, + rr_ch2s4, rr_ch3s4, rr_ch4s4, rr_ch5s4; + +sep24 #( .width(4), .pos0(0) ) rr_step +( + .clk ( clk ), + .mixed ( rr_II ), + .mask ( 0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (rr_ch0s1), + .ch1s1 (rr_ch1s1), + .ch2s1 (rr_ch2s1), + .ch3s1 (rr_ch3s1), + .ch4s1 (rr_ch4s1), + .ch5s1 (rr_ch5s1), + + .ch0s2 (rr_ch0s2), + .ch1s2 (rr_ch1s2), + .ch2s2 (rr_ch2s2), + .ch3s2 (rr_ch3s2), + .ch4s2 (rr_ch4s2), + .ch5s2 (rr_ch5s2), + + .ch0s3 (rr_ch0s3), + .ch1s3 (rr_ch1s3), + .ch2s3 (rr_ch2s3), + .ch3s3 (rr_ch3s3), + .ch4s3 (rr_ch4s3), + .ch5s3 (rr_ch5s3), + + .ch0s4 (rr_ch0s4), + .ch1s4 (rr_ch1s4), + .ch2s4 (rr_ch2s4), + .ch3s4 (rr_ch3s4), + .ch4s4 (rr_ch4s4), + .ch5s4 (rr_ch5s4) +); + +wire [3:0] d1l_ch0s1, d1l_ch1s1, d1l_ch2s1, d1l_ch3s1, + d1l_ch4s1, d1l_ch5s1, d1l_ch0s2, d1l_ch1s2, + d1l_ch2s2, d1l_ch3s2, d1l_ch4s2, d1l_ch5s2, + d1l_ch0s3, d1l_ch1s3, d1l_ch2s3, d1l_ch3s3, + d1l_ch4s3, d1l_ch5s3, d1l_ch0s4, d1l_ch1s4, + d1l_ch2s4, d1l_ch3s4, d1l_ch4s4, d1l_ch5s4; + +sep24 #( .width(4), .pos0(1) ) d1l_step +( + .clk ( clk ), + .mixed ( d1l ), + .mask ( 4'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (d1l_ch0s1), + .ch1s1 (d1l_ch1s1), + .ch2s1 (d1l_ch2s1), + .ch3s1 (d1l_ch3s1), + .ch4s1 (d1l_ch4s1), + .ch5s1 (d1l_ch5s1), + + .ch0s2 (d1l_ch0s2), + .ch1s2 (d1l_ch1s2), + .ch2s2 (d1l_ch2s2), + .ch3s2 (d1l_ch3s2), + .ch4s2 (d1l_ch4s2), + .ch5s2 (d1l_ch5s2), + + .ch0s3 (d1l_ch0s3), + .ch1s3 (d1l_ch1s3), + .ch2s3 (d1l_ch2s3), + .ch3s3 (d1l_ch3s3), + .ch4s3 (d1l_ch4s3), + .ch5s3 (d1l_ch5s3), + + .ch0s4 (d1l_ch0s4), + .ch1s4 (d1l_ch1s4), + .ch2s4 (d1l_ch2s4), + .ch3s4 (d1l_ch3s4), + .ch4s4 (d1l_ch4s4), + .ch5s4 (d1l_ch5s4) +); + +wire [1:0] ks_ch0s1, ks_ch1s1, ks_ch2s1, ks_ch3s1, + ks_ch4s1, ks_ch5s1, ks_ch0s2, ks_ch1s2, + ks_ch2s2, ks_ch3s2, ks_ch4s2, ks_ch5s2, + ks_ch0s3, ks_ch1s3, ks_ch2s3, ks_ch3s3, + ks_ch4s3, ks_ch5s3, ks_ch0s4, ks_ch1s4, + ks_ch2s4, ks_ch3s4, ks_ch4s4, ks_ch5s4; + +sep24 #( .width(2), .pos0(23) ) ks_step +( + .clk ( clk ), + .mixed ( ks_III ), + .mask ( 0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (ks_ch0s1), + .ch1s1 (ks_ch1s1), + .ch2s1 (ks_ch2s1), + .ch3s1 (ks_ch3s1), + .ch4s1 (ks_ch4s1), + .ch5s1 (ks_ch5s1), + + .ch0s2 (ks_ch0s2), + .ch1s2 (ks_ch1s2), + .ch2s2 (ks_ch2s2), + .ch3s2 (ks_ch3s2), + .ch4s2 (ks_ch4s2), + .ch5s2 (ks_ch5s2), + + .ch0s3 (ks_ch0s3), + .ch1s3 (ks_ch1s3), + .ch2s3 (ks_ch2s3), + .ch3s3 (ks_ch3s3), + .ch4s3 (ks_ch4s3), + .ch5s3 (ks_ch5s3), + + .ch0s4 (ks_ch0s4), + .ch1s4 (ks_ch1s4), + .ch2s4 (ks_ch2s4), + .ch3s4 (ks_ch3s4), + .ch4s4 (ks_ch4s4), + .ch5s4 (ks_ch5s4) +); + +wire [3:0] ssg_II = {ssg_en_II, ssg_eg_II}; + +wire [3:0] ssg_ch0s1, ssg_ch1s1, ssg_ch2s1, ssg_ch3s1, + ssg_ch4s1, ssg_ch5s1, ssg_ch0s2, ssg_ch1s2, + ssg_ch2s2, ssg_ch3s2, ssg_ch4s2, ssg_ch5s2, + ssg_ch0s3, ssg_ch1s3, ssg_ch2s3, ssg_ch3s3, + ssg_ch4s3, ssg_ch5s3, ssg_ch0s4, ssg_ch1s4, + ssg_ch2s4, ssg_ch3s4, ssg_ch4s4, ssg_ch5s4; + +sep24 #( .width(4), .pos0(0) ) ssg_step +( + .clk ( clk ), + .mixed ( ssg_II ), + .mask ( 4'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (ssg_ch0s1), + .ch1s1 (ssg_ch1s1), + .ch2s1 (ssg_ch2s1), + .ch3s1 (ssg_ch3s1), + .ch4s1 (ssg_ch4s1), + .ch5s1 (ssg_ch5s1), + + .ch0s2 (ssg_ch0s2), + .ch1s2 (ssg_ch1s2), + .ch2s2 (ssg_ch2s2), + .ch3s2 (ssg_ch3s2), + .ch4s2 (ssg_ch4s2), + .ch5s2 (ssg_ch5s2), + + .ch0s3 (ssg_ch0s3), + .ch1s3 (ssg_ch1s3), + .ch2s3 (ssg_ch2s3), + .ch3s3 (ssg_ch3s3), + .ch4s3 (ssg_ch4s3), + .ch5s3 (ssg_ch5s3), + + .ch0s4 (ssg_ch0s4), + .ch1s4 (ssg_ch1s4), + .ch2s4 (ssg_ch2s4), + .ch3s4 (ssg_ch3s4), + .ch4s4 (ssg_ch4s4), + .ch5s4 (ssg_ch5s4) +); + +wire kon_ch0s1, kon_ch1s1, kon_ch2s1, kon_ch3s1, + kon_ch4s1, kon_ch5s1, kon_ch0s2, kon_ch1s2, + kon_ch2s2, kon_ch3s2, kon_ch4s2, kon_ch5s2, + kon_ch0s3, kon_ch1s3, kon_ch2s3, kon_ch3s3, + kon_ch4s3, kon_ch5s3, kon_ch0s4, kon_ch1s4, + kon_ch2s4, kon_ch3s4, kon_ch4s4, kon_ch5s4; + +sep24 #( .width(1), .pos0(0) ) konstep +( + .clk ( clk ), + .mixed ( keyon_II ), + .mask ( 1'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (kon_ch0s1), + .ch1s1 (kon_ch1s1), + .ch2s1 (kon_ch2s1), + .ch3s1 (kon_ch3s1), + .ch4s1 (kon_ch4s1), + .ch5s1 (kon_ch5s1), + + .ch0s2 (kon_ch0s2), + .ch1s2 (kon_ch1s2), + .ch2s2 (kon_ch2s2), + .ch3s2 (kon_ch3s2), + .ch4s2 (kon_ch4s2), + .ch5s2 (kon_ch5s2), + + .ch0s3 (kon_ch0s3), + .ch1s3 (kon_ch1s3), + .ch2s3 (kon_ch2s3), + .ch3s3 (kon_ch3s3), + .ch4s3 (kon_ch4s3), + .ch5s3 (kon_ch5s3), + + .ch0s4 (kon_ch0s4), + .ch1s4 (kon_ch1s4), + .ch2s4 (kon_ch2s4), + .ch3s4 (kon_ch3s4), + .ch4s4 (kon_ch4s4), + .ch5s4 (kon_ch5s4) +); + +/* Dump all registers on request */ +integer fmmr; +initial begin + fmmr=$fopen("mmr_dump.log"); +end + +always @(posedge clk ) +if (mmr_dump ) begin + $fdisplay( fmmr, "-------------------------------"); + // Channel 0 + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch0s1, fnum_ch0s1, rl_ch0s1, fb_ch0s1, alg_ch0s1, + dt1_ch0s1, mul_ch0s1, tl_ch0s1, ar_ch0s1, d1r_ch0s1, + d2r_ch0s1, rr_ch0s1, d1l_ch0s1, ks_ch0s1, ssg_ch0s1, + kon_ch0s1 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch0s2, fnum_ch0s2, rl_ch0s2, fb_ch0s2, alg_ch0s2, + dt1_ch0s2, mul_ch0s2, tl_ch0s2, ar_ch0s2, d1r_ch0s2, + d2r_ch0s2, rr_ch0s2, d1l_ch0s2, ks_ch0s2, ssg_ch0s2, + kon_ch0s2 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch0s1, fnum_ch0s3, rl_ch0s3, fb_ch0s3, alg_ch0s3, + dt1_ch0s3, mul_ch0s3, tl_ch0s3, ar_ch0s3, d1r_ch0s3, + d2r_ch0s3, rr_ch0s3, d1l_ch0s3, ks_ch0s3, ssg_ch0s3, + kon_ch0s3 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch0s4, fnum_ch0s4, rl_ch0s4, fb_ch0s4, alg_ch0s4, + dt1_ch0s4, mul_ch0s4, tl_ch0s4, ar_ch0s4, d1r_ch0s4, + d2r_ch0s4, rr_ch0s4, d1l_ch0s4, ks_ch0s4, ssg_ch0s4, + kon_ch0s4 ); + // Channel 1 + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch1s1, fnum_ch1s1, rl_ch1s1, fb_ch1s1, alg_ch1s1, + dt1_ch1s1, mul_ch1s1, tl_ch1s1, ar_ch1s1, d1r_ch1s1, + d2r_ch1s1, rr_ch1s1, d1l_ch1s1, ks_ch1s1, ssg_ch1s1, + kon_ch1s1 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch1s2, fnum_ch1s2, rl_ch1s2, fb_ch1s2, alg_ch1s2, + dt1_ch1s2, mul_ch1s2, tl_ch1s2, ar_ch1s2, d1r_ch1s2, + d2r_ch1s2, rr_ch1s2, d1l_ch1s2, ks_ch1s2, ssg_ch1s2, + kon_ch1s2 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch1s3, fnum_ch1s3, rl_ch1s3, fb_ch1s3, alg_ch1s3, + dt1_ch1s3, mul_ch1s3, tl_ch1s3, ar_ch1s3, d1r_ch1s3, + d2r_ch1s3, rr_ch1s3, d1l_ch1s3, ks_ch1s3, ssg_ch1s3, + kon_ch1s3 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch1s4, fnum_ch1s4, rl_ch1s4, fb_ch1s4, alg_ch1s4, + dt1_ch1s4, mul_ch1s4, tl_ch1s4, ar_ch1s4, d1r_ch1s4, + d2r_ch1s4, rr_ch1s4, d1l_ch1s4, ks_ch1s4, ssg_ch1s4, + kon_ch1s4 ); + // Channel 2 + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch2s1, fnum_ch2s1, rl_ch2s1, fb_ch2s1, alg_ch2s1, + dt1_ch2s1, mul_ch2s1, tl_ch2s1, ar_ch2s1, d1r_ch2s1, + d2r_ch2s1, rr_ch2s1, d1l_ch2s1, ks_ch2s1, ssg_ch2s1, + kon_ch2s1 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch2s2, fnum_ch2s2, rl_ch2s2, fb_ch2s2, alg_ch2s2, + dt1_ch2s2, mul_ch2s2, tl_ch2s2, ar_ch2s2, d1r_ch2s2, + d2r_ch2s2, rr_ch2s2, d1l_ch2s2, ks_ch2s2, ssg_ch2s2, + kon_ch2s2 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch2s3, fnum_ch2s3, rl_ch2s3, fb_ch2s3, alg_ch2s3, + dt1_ch2s3, mul_ch2s3, tl_ch2s3, ar_ch2s3, d1r_ch2s3, + d2r_ch2s3, rr_ch2s3, d1l_ch2s3, ks_ch2s3, ssg_ch2s3, + kon_ch2s3 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch2s4, fnum_ch2s4, rl_ch2s4, fb_ch2s4, alg_ch2s4, + dt1_ch2s4, mul_ch2s4, tl_ch2s4, ar_ch2s4, d1r_ch2s4, + d2r_ch2s4, rr_ch2s4, d1l_ch2s4, ks_ch2s4, ssg_ch2s4, + kon_ch2s4 ); + // Channel 3 + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch3s1, fnum_ch3s1, rl_ch3s1, fb_ch3s1, alg_ch3s1, + dt1_ch3s1, mul_ch3s1, tl_ch3s1, ar_ch3s1, d1r_ch3s1, + d2r_ch3s1, rr_ch3s1, d1l_ch3s1, ks_ch3s1, ssg_ch3s1, + kon_ch3s1 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch3s2, fnum_ch3s2, rl_ch3s2, fb_ch3s2, alg_ch3s2, + dt1_ch3s2, mul_ch3s2, tl_ch3s2, ar_ch3s2, d1r_ch3s2, + d2r_ch3s2, rr_ch3s2, d1l_ch3s2, ks_ch3s2, ssg_ch3s2, + kon_ch3s2 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch3s3, fnum_ch3s3, rl_ch3s3, fb_ch3s3, alg_ch3s3, + dt1_ch3s3, mul_ch3s3, tl_ch3s3, ar_ch3s3, d1r_ch3s3, + d2r_ch3s3, rr_ch3s3, d1l_ch3s3, ks_ch3s3, ssg_ch3s3, + kon_ch3s3 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch3s4, fnum_ch3s4, rl_ch3s4, fb_ch3s4, alg_ch3s4, + dt1_ch3s4, mul_ch3s4, tl_ch3s4, ar_ch3s4, d1r_ch3s4, + d2r_ch3s4, rr_ch3s4, d1l_ch3s4, ks_ch3s4, ssg_ch3s4, + kon_ch3s4 ); + // Channel 4 + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch4s1, fnum_ch4s1, rl_ch4s1, fb_ch4s1, alg_ch4s1, + dt1_ch4s1, mul_ch4s1, tl_ch4s1, ar_ch4s1, d1r_ch4s1, + d2r_ch4s1, rr_ch4s1, d1l_ch4s1, ks_ch4s1, ssg_ch4s1, + kon_ch4s1 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch4s2, fnum_ch4s2, rl_ch4s2, fb_ch4s2, alg_ch4s2, + dt1_ch4s2, mul_ch4s2, tl_ch4s2, ar_ch4s2, d1r_ch4s2, + d2r_ch4s2, rr_ch4s2, d1l_ch4s2, ks_ch4s2, ssg_ch4s2, + kon_ch4s2 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch4s3, fnum_ch4s3, rl_ch4s3, fb_ch4s3, alg_ch4s3, + dt1_ch4s3, mul_ch4s3, tl_ch4s3, ar_ch4s3, d1r_ch4s3, + d2r_ch4s3, rr_ch4s3, d1l_ch4s3, ks_ch4s3, ssg_ch4s3, + kon_ch4s3 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch4s4, fnum_ch4s4, rl_ch4s4, fb_ch4s4, alg_ch4s4, + dt1_ch4s4, mul_ch4s4, tl_ch4s4, ar_ch4s4, d1r_ch4s4, + d2r_ch4s4, rr_ch4s4, d1l_ch4s4, ks_ch4s4, ssg_ch4s4, + kon_ch4s4 ); + // Channel 5 + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch5s1, fnum_ch5s1, rl_ch5s1, fb_ch5s1, alg_ch5s1, + dt1_ch5s1, mul_ch5s1, tl_ch5s1, ar_ch5s1, d1r_ch5s1, + d2r_ch5s1, rr_ch5s1, d1l_ch5s1, ks_ch5s1, ssg_ch5s1, + kon_ch5s1 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch5s2, fnum_ch5s2, rl_ch5s2, fb_ch5s2, alg_ch5s2, + dt1_ch5s2, mul_ch5s2, tl_ch5s2, ar_ch5s2, d1r_ch5s2, + d2r_ch5s2, rr_ch5s2, d1l_ch5s2, ks_ch5s2, ssg_ch5s2, + kon_ch5s2 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch5s3, fnum_ch5s3, rl_ch5s3, fb_ch5s3, alg_ch5s3, + dt1_ch5s3, mul_ch5s3, tl_ch5s3, ar_ch5s3, d1r_ch5s3, + d2r_ch5s3, rr_ch5s3, d1l_ch5s3, ks_ch5s3, ssg_ch5s3, + kon_ch5s3 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch5s4, fnum_ch5s4, rl_ch5s4, fb_ch5s4, alg_ch5s4, + dt1_ch5s4, mul_ch5s4, tl_ch5s4, ar_ch5s4, d1r_ch5s4, + d2r_ch5s4, rr_ch5s4, d1l_ch5s4, ks_ch5s4, ssg_ch5s4, + kon_ch5s4 ); +end +`endif + diff --git a/src/sound/jt12/jt12_mod.v b/src/sound/jt12/jt12_mod.v new file mode 100644 index 0000000..9e41603 --- /dev/null +++ b/src/sound/jt12/jt12_mod.v @@ -0,0 +1,122 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + +module jt12_mod( + input s1_enters, + input s2_enters, + input s3_enters, + input s4_enters, + + input [2:0] alg_I, + + output reg use_prevprev1, + output reg use_internal_x, + output reg use_internal_y, + output reg use_prev2, + output reg use_prev1 +); + +reg [7:0] alg_hot; + +always @(*) begin + case( alg_I ) + 3'd0: alg_hot <= 8'h1; // D0 + 3'd1: alg_hot <= 8'h2; // D1 + 3'd2: alg_hot <= 8'h4; // D2 + 3'd3: alg_hot <= 8'h8; // D3 + 3'd4: alg_hot <= 8'h10; // D4 + 3'd5: alg_hot <= 8'h20; // D5 + 3'd6: alg_hot <= 8'h40; // D6 + 3'd7: alg_hot <= 8'h80; // D7 + endcase +end + +always @(*) begin + use_prevprev1 <= s1_enters | (s3_enters&alg_hot[5]); + use_prev2 <= (s3_enters&(|alg_hot[2:0])) | (s4_enters&alg_hot[3]); + use_internal_x <= s4_enters & alg_hot[2]; + use_internal_y <= s4_enters & (|{alg_hot[4:3],alg_hot[1:0]}); + use_prev1 <= s1_enters | (s3_enters&alg_hot[1]) | + (s2_enters&(|{alg_hot[6:3],alg_hot[0]}) )| + (s4_enters&(|{alg_hot[5],alg_hot[2]})); +end + +/* +always @(*) begin + use_prevprev1 <= s1_enters || (s3_enters&&(alg_I==3'd5)); + use_prev2 <= (s3_enters&&(alg_I<=3'd2)) || (s4_enters&&(alg_I==3'd3)); + use_internal_x <= s4_enters && (alg_I==3'd2); + use_internal_y <= s4_enters && (alg_I<=3'd4 && alg_I!=3'd2); + use_prev1 <= s1_enters || (s3_enters&&(alg_I==3'd1)) || + (s2_enters&&(alg_I==3'd0 || + alg_I==3'd3 || alg_I==3'd4 || + alg_I==3'd5 || alg_I==3'd6)) || + (s4_enters&&(alg_I==3'd2 || alg_I==3'd5)); +end + +always @(*) begin +case( {s1_enters, s3_enters, s2_enters, s4_enters} ) // synthesis parallel_case + 4'b1000: begin // S1 + use_prevprev1 <= 1'b1; + use_prev2 <= 1'b0; + use_internal_x<= 1'b0; + use_internal_y<= 1'b0; + use_prev1 <= 1'b1; + end + 4'b0100: begin // S3 + use_prevprev1 <= alg_I==3'd5; + use_prev2 <= (alg_I<=3'd2); + use_internal_x<= 1'b0; + use_internal_y<= 1'b0; + use_prev1 <= alg_I==3'd1; + end + 4'b0010: begin // S2 + use_prevprev1 <= 1'b0; + use_prev2 <= 1'b0; + use_internal_x<= 1'b0; + use_prev1 <= (alg_I==3'd0 || + alg_I==3'd3 || alg_I==3'd4 || + alg_I==3'd5 || alg_I==3'd6 ); + use_internal_y<= 1'b0; + end + 4'b0001: begin // S4 + use_prevprev1 <= 1'b0; + use_prev2 <= ( alg_I==3'd3 ); + use_internal_x <= alg_I==3'd2; + use_prev1 <= (alg_I==3'd2 || alg_I==3'd5); + use_internal_y <= ( alg_I<=3'd4 && alg_I!=3'd2); + end + default:begin + use_prevprev1 <= 1'bx; + use_prev2 <= 1'bx; + use_internal_x<= 1'bx; + use_prev1 <= 1'bx; + use_internal_y<= 1'bx; + end + endcase +end +*/ + +endmodule diff --git a/src/sound/jt12/jt12_op.v b/src/sound/jt12/jt12_op.v new file mode 100644 index 0000000..9dfd931 --- /dev/null +++ b/src/sound/jt12/jt12_op.v @@ -0,0 +1,536 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + + +module jt12_op( + input rst, + input clk, + input [9:0] pg_phase_VIII, + input [9:0] eg_atten_IX, // output from envelope generator + input [2:0] fb_II, // voice feedback + input use_prevprev1, + input use_internal_x, + input use_internal_y, + input use_prev2, + input use_prev1, + input test_214, + + input s1_enters, + input s2_enters, + input s3_enters, + input s4_enters, + input zero, + + output signed [8:0] op_result +); + +/* enters exits + S1 S2 + S3 S4 + S2 S1 + S4 S3 +*/ + +reg [13:0] op_result_internal, op_XII; +reg [11:0] atten_internal_IX; + +assign op_result = op_result_internal[13:5]; + +parameter NUM_VOICES = 6; + +reg signbit_IX, signbit_X, signbit_XI; +reg [11:0] totalatten_X; + +wire [13:0] prev1, prevprev1, prev2; + +jt12_sh/*_rst*/ #( .width(14), .stages(NUM_VOICES)) prev1_buffer( +// .rst ( rst ), + .clk ( clk ), + .din ( s2_enters ? op_result_internal : prev1 ), + .drop ( prev1 ) +); + +jt12_sh/*_rst*/ #( .width(14), .stages(NUM_VOICES)) prevprev1_buffer( +// .rst ( rst ), + .clk ( clk ), + .din ( s2_enters ? prev1 : prevprev1 ), + .drop ( prevprev1 ) +); + +jt12_sh/*_rst*/ #( .width(14), .stages(NUM_VOICES)) prev2_buffer( +// .rst ( rst ), + .clk ( clk ), + .din ( s1_enters ? op_result_internal : prev2 ), + .drop ( prev2 ) +); + + +reg [18:0] stb; +reg [10:0] stf, stg; +reg [11:0] logsin; +reg [10:0] subtresult; + +reg [12:0] etb; +reg [ 9:0] etf, etg, mantissa_XI; +reg [ 3:0] exponent_XI; + +reg [12:0] shifter, shifter_2, shifter_3; + +// REGISTER/CYCLE 1 +// Creation of phase modulation (FM) feedback signal, before shifting +reg [13:0] x, y; +reg [14:0] xs, ys, pm_preshift_II; +reg s1_II; + +always @(*) begin + + x <= ( {14{use_prevprev1}} & prevprev1 ) | + ( {14{use_internal_x}} & op_result_internal ) | + ( {14{use_prev2}} & prev2 ); + y <= ( {14{use_prev1}} & prev1 ) | + ( {14{use_internal_y}} & op_result_internal ); + xs <= { x[13], x }; // sign-extend + ys <= { y[13], y }; // sign-extend +end + +always @(posedge clk) begin + pm_preshift_II <= xs + ys; // carry is discarded + s1_II <= s1_enters; +end + +/* REGISTER/CYCLE 2-7 (also YM2612 extra cycles 1-6) + Shifting of FM feedback signal, adding phase from PG to FM phase + In YM2203, phasemod_II is not registered at all, it is latched on the first edge + in add_pg_phase and the second edge is the output of add_pg_phase. In the YM2612, there + are 6 cycles worth of registers between the generated (non-registered) phasemod_II signal + and the input to add_pg_phase. */ + +reg [9:0] phasemod_II; +wire [9:0] phasemod_VIII; + +always @(*) begin + // Shift FM feedback signal + if (!s1_II ) // Not S1 + phasemod_II <= pm_preshift_II[10:1]; // Bit 0 of pm_preshift_II is never used + else // S1 + case( fb_II ) + 3'd0: phasemod_II <= 10'd0; + 3'd1: phasemod_II <= { {4{pm_preshift_II[14]}}, pm_preshift_II[14:9] }; + 3'd2: phasemod_II <= { {3{pm_preshift_II[14]}}, pm_preshift_II[14:8] }; + 3'd3: phasemod_II <= { {2{pm_preshift_II[14]}}, pm_preshift_II[14:7] }; + 3'd4: phasemod_II <= { pm_preshift_II[14], pm_preshift_II[14:6] }; + 3'd5: phasemod_II <= pm_preshift_II[14:5]; + 3'd6: phasemod_II <= pm_preshift_II[13:4]; + 3'd7: phasemod_II <= pm_preshift_II[12:3]; + endcase +end + +// REGISTER/CYCLE 2-7 +jt12_sh #( .width(10), .stages(NUM_VOICES)) phasemod_sh( + .clk ( clk ), + .din ( phasemod_II ), + .drop ( phasemod_VIII ) +); + +// REGISTER/CYCLE 8 +reg [ 9:0] phase; +// Sets the maximum number of fanouts for a register or combinational +// cell. The Quartus II software will replicate the cell and split +// the fanouts among the duplicates until the fanout of each cell +// is below the maximum. + +reg [ 7:0] phaselo_IX, aux_VIII; + +always @(*) begin + phase <= phasemod_VIII + pg_phase_VIII; + aux_VIII<= phase[7:0] ^ {8{~phase[8]}}; +end + +always @(posedge clk) begin + phaselo_IX <= aux_VIII; + signbit_IX <= phase[9]; + +end + +wire [45:0] sta_IX; + +jt12_phrom u_phrom( + .clk ( clk ), + .addr ( aux_VIII[5:1] ), + .ph ( sta_IX ) +); + +// REGISTER/CYCLE 9 +// Sine table +// Main sine table body + + +always @(*) begin + //sta_IX <= sinetable[ phaselo_IX[5:1] ]; + // 2-bit row chooser + case( phaselo_IX[7:6] ) + 2'b00: stb <= { 10'b0, sta_IX[29], sta_IX[25], 2'b0, sta_IX[18], + sta_IX[14], 1'b0, sta_IX[7] , sta_IX[3] }; + 2'b01: stb <= { 6'b0 , sta_IX[37], sta_IX[34], 2'b0, sta_IX[28], + sta_IX[24], 2'b0, sta_IX[17], sta_IX[13], sta_IX[10], sta_IX[6], sta_IX[2] }; + 2'b10: stb <= { 2'b0, sta_IX[43], sta_IX[41], 2'b0, sta_IX[36], + sta_IX[33], 2'b0, sta_IX[27], sta_IX[23], 1'b0, sta_IX[20], + sta_IX[16], sta_IX[12], sta_IX[9], sta_IX[5], sta_IX[1] }; + default: stb <= { + sta_IX[45], sta_IX[44], sta_IX[42], sta_IX[40] + , sta_IX[39], sta_IX[38], sta_IX[35], sta_IX[32] + , sta_IX[31], sta_IX[30], sta_IX[26], sta_IX[22] + , sta_IX[21], sta_IX[19], sta_IX[15], sta_IX[11] + , sta_IX[8], sta_IX[4], sta_IX[0] }; + endcase + // Fixed value to sum + stf <= { stb[18:15], stb[12:11], stb[8:7], stb[4:3], stb[0] }; + // Gated value to sum; bit 14 is indeed used twice + if( phaselo_IX[0] ) + stg <= { 2'b0, stb[14], stb[14:13], stb[10:9], stb[6:5], stb[2:1] }; + else + stg <= 11'd0; + // Sum to produce final logsin value + logsin <= stf + stg; // Carry-out of 11-bit addition becomes 12th bit + // Invert-subtract logsin value from EG attenuation value, with inverted carry + // In the actual chip, the output of the above logsin sum is already inverted. + // The two LSBs go through inverters (so they're non-inverted); the eg_atten_IX signal goes through inverters. + // The adder is normal except the carry-in is 1. It's a 10-bit adder. + // The outputs are inverted outputs, including the carry bit. + //subtresult <= not (('0' & not eg_atten_IX) - ('1' & logsin([11:2]))); + // After a little pencil-and-paper, turns out this is equivalent to a regular adder! + subtresult <= eg_atten_IX + logsin[11:2]; + // Place all but carry bit into result; also two LSBs of logsin + // If addition overflowed, make it the largest value (saturate) + atten_internal_IX <= { subtresult[9:0], logsin[1:0] } | {12{subtresult[10]}}; +end + +wire [44:0] exp_X; + +jt12_exprom u_exprom( + .clk ( clk ), + .addr ( atten_internal_IX[5:1] ), + .exp ( exp_X ) +); + +always @(posedge clk) begin + totalatten_X <= atten_internal_IX; + signbit_X <= signbit_IX; +end + +//wire [1:0] et_sel = totalatten_X[7:6]; +//wire [4:0] et_fine = totalatten_X[5:1]; + +// REGISTER/CYCLE 10 +// Exponential table +// Main sine table body +always @(*) begin + //eta <= explut_jt51[ totalatten_X[5:1] ]; + // 2-bit row chooser + case( totalatten_X[7:6] ) + 2'b00: begin + etf <= { 1'b1, exp_X[44:36] }; + etg <= { 1'b1, exp_X[35:34] }; + end + 2'b01: begin + etf <= exp_X[33:24]; + etg <= { 2'b10, exp_X[23] }; + end + 2'b10: begin + etf <= { 1'b0, exp_X[22:14] }; + etg <= exp_X[13:11]; + end + 2'b11: begin + etf <= { 2'b00, exp_X[10:3] }; + etg <= exp_X[2:0]; + end + + endcase +end + +always @(posedge clk) begin + //RESULT + mantissa_XI <= etf + ( totalatten_X[0] ? 3'd0 : etg ); //carry-out discarded + exponent_XI <= totalatten_X[11:8]; + signbit_XI <= signbit_X; +end + +// REGISTER/CYCLE 11 +// Introduce test bit as MSB, 2's complement & Carry-out discarded + +always @(*) begin + // Floating-point to integer, and incorporating sign bit + // Two-stage shifting of mantissa_XI by exponent_XI + shifter <= { 3'b001, mantissa_XI }; + case( ~exponent_XI[1:0] ) + 2'b00: shifter_2 <= { 1'b0, shifter[12:1] }; // LSB discarded + 2'b01: shifter_2 <= shifter; + 2'b10: shifter_2 <= { shifter[11:0], 1'b0 }; + 2'b11: shifter_2 <= { shifter[10:0], 2'b0 }; + endcase + case( ~exponent_XI[3:2] ) + 2'b00: shifter_3 <= {12'b0, shifter_2[12] }; + 2'b01: shifter_3 <= { 8'b0, shifter_2[12:8] }; + 2'b10: shifter_3 <= { 4'b0, shifter_2[12:4] }; + 2'b11: shifter_3 <= shifter_2; + endcase +end + +always @(posedge clk) begin + // REGISTER CYCLE 11 + op_XII <= ({ test_214, shifter_3 } ^ {14{signbit_XI}}) + signbit_XI; + // REGISTER CYCLE 12 + // Extra register, take output after here + op_result_internal <= op_XII; +end + +`ifdef SIMULATION +reg [4:0] sep24_cnt; + +wire signed [13:0] op_ch0s1, op_ch1s1, op_ch2s1, op_ch3s1, + op_ch4s1, op_ch5s1, op_ch0s2, op_ch1s2, + op_ch2s2, op_ch3s2, op_ch4s2, op_ch5s2, + op_ch0s3, op_ch1s3, op_ch2s3, op_ch3s3, + op_ch4s3, op_ch5s3, op_ch0s4, op_ch1s4, + op_ch2s4, op_ch3s4, op_ch4s4, op_ch5s4; + +always @(posedge clk ) + sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; + +sep24 #( .width(14), .pos0(13)) opsep +( + .clk ( clk ), + .mixed ( op_result_internal ), + .mask ( 0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (op_ch0s1), + .ch1s1 (op_ch1s1), + .ch2s1 (op_ch2s1), + .ch3s1 (op_ch3s1), + .ch4s1 (op_ch4s1), + .ch5s1 (op_ch5s1), + + .ch0s2 (op_ch0s2), + .ch1s2 (op_ch1s2), + .ch2s2 (op_ch2s2), + .ch3s2 (op_ch3s2), + .ch4s2 (op_ch4s2), + .ch5s2 (op_ch5s2), + + .ch0s3 (op_ch0s3), + .ch1s3 (op_ch1s3), + .ch2s3 (op_ch2s3), + .ch3s3 (op_ch3s3), + .ch4s3 (op_ch4s3), + .ch5s3 (op_ch5s3), + + .ch0s4 (op_ch0s4), + .ch1s4 (op_ch1s4), + .ch2s4 (op_ch2s4), + .ch3s4 (op_ch3s4), + .ch4s4 (op_ch4s4), + .ch5s4 (op_ch5s4) +); + +wire signed [8:0] acc_ch0s1, acc_ch1s1, acc_ch2s1, acc_ch3s1, + acc_ch4s1, acc_ch5s1, acc_ch0s2, acc_ch1s2, + acc_ch2s2, acc_ch3s2, acc_ch4s2, acc_ch5s2, + acc_ch0s3, acc_ch1s3, acc_ch2s3, acc_ch3s3, + acc_ch4s3, acc_ch5s3, acc_ch0s4, acc_ch1s4, + acc_ch2s4, acc_ch3s4, acc_ch4s4, acc_ch5s4; + +sep24 #( .width(9), .pos0(13)) accsep +( + .clk ( clk ), + .mixed ( op_result_internal[13:5] ), + .mask ( 0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (acc_ch0s1), + .ch1s1 (acc_ch1s1), + .ch2s1 (acc_ch2s1), + .ch3s1 (acc_ch3s1), + .ch4s1 (acc_ch4s1), + .ch5s1 (acc_ch5s1), + + .ch0s2 (acc_ch0s2), + .ch1s2 (acc_ch1s2), + .ch2s2 (acc_ch2s2), + .ch3s2 (acc_ch3s2), + .ch4s2 (acc_ch4s2), + .ch5s2 (acc_ch5s2), + + .ch0s3 (acc_ch0s3), + .ch1s3 (acc_ch1s3), + .ch2s3 (acc_ch2s3), + .ch3s3 (acc_ch3s3), + .ch4s3 (acc_ch4s3), + .ch5s3 (acc_ch5s3), + + .ch0s4 (acc_ch0s4), + .ch1s4 (acc_ch1s4), + .ch2s4 (acc_ch2s4), + .ch3s4 (acc_ch3s4), + .ch4s4 (acc_ch4s4), + .ch5s4 (acc_ch5s4) +); + +wire signed [9:0] pm_ch0s1, pm_ch1s1, pm_ch2s1, pm_ch3s1, + pm_ch4s1, pm_ch5s1, pm_ch0s2, pm_ch1s2, + pm_ch2s2, pm_ch3s2, pm_ch4s2, pm_ch5s2, + pm_ch0s3, pm_ch1s3, pm_ch2s3, pm_ch3s3, + pm_ch4s3, pm_ch5s3, pm_ch0s4, pm_ch1s4, + pm_ch2s4, pm_ch3s4, pm_ch4s4, pm_ch5s4; + + +sep24 #( .width(10), .pos0( 18 ) ) pmsep +( + .clk ( clk ), + .mixed ( phasemod_VIII ), + .mask ( 0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (pm_ch0s1), + .ch1s1 (pm_ch1s1), + .ch2s1 (pm_ch2s1), + .ch3s1 (pm_ch3s1), + .ch4s1 (pm_ch4s1), + .ch5s1 (pm_ch5s1), + + .ch0s2 (pm_ch0s2), + .ch1s2 (pm_ch1s2), + .ch2s2 (pm_ch2s2), + .ch3s2 (pm_ch3s2), + .ch4s2 (pm_ch4s2), + .ch5s2 (pm_ch5s2), + + .ch0s3 (pm_ch0s3), + .ch1s3 (pm_ch1s3), + .ch2s3 (pm_ch2s3), + .ch3s3 (pm_ch3s3), + .ch4s3 (pm_ch4s3), + .ch5s3 (pm_ch5s3), + + .ch0s4 (pm_ch0s4), + .ch1s4 (pm_ch1s4), + .ch2s4 (pm_ch2s4), + .ch3s4 (pm_ch3s4), + .ch4s4 (pm_ch4s4), + .ch5s4 (pm_ch5s4) +); + +wire [9:0] phase_ch0s1, phase_ch1s1, phase_ch2s1, phase_ch3s1, + phase_ch4s1, phase_ch5s1, phase_ch0s2, phase_ch1s2, + phase_ch2s2, phase_ch3s2, phase_ch4s2, phase_ch5s2, + phase_ch0s3, phase_ch1s3, phase_ch2s3, phase_ch3s3, + phase_ch4s3, phase_ch5s3, phase_ch0s4, phase_ch1s4, + phase_ch2s4, phase_ch3s4, phase_ch4s4, phase_ch5s4; + + +sep24 #( .width(10), .pos0( 18 ) ) phsep +( + .clk ( clk ), + .mixed ( phase ), + .mask ( 0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (phase_ch0s1), + .ch1s1 (phase_ch1s1), + .ch2s1 (phase_ch2s1), + .ch3s1 (phase_ch3s1), + .ch4s1 (phase_ch4s1), + .ch5s1 (phase_ch5s1), + + .ch0s2 (phase_ch0s2), + .ch1s2 (phase_ch1s2), + .ch2s2 (phase_ch2s2), + .ch3s2 (phase_ch3s2), + .ch4s2 (phase_ch4s2), + .ch5s2 (phase_ch5s2), + + .ch0s3 (phase_ch0s3), + .ch1s3 (phase_ch1s3), + .ch2s3 (phase_ch2s3), + .ch3s3 (phase_ch3s3), + .ch4s3 (phase_ch4s3), + .ch5s3 (phase_ch5s3), + + .ch0s4 (phase_ch0s4), + .ch1s4 (phase_ch1s4), + .ch2s4 (phase_ch2s4), + .ch3s4 (phase_ch3s4), + .ch4s4 (phase_ch4s4), + .ch5s4 (phase_ch5s4) +); + +wire [9:0] eg_ch0s1, eg_ch1s1, eg_ch2s1, eg_ch3s1, eg_ch4s1, eg_ch5s1, + eg_ch0s2, eg_ch1s2, eg_ch2s2, eg_ch3s2, eg_ch4s2, eg_ch5s2, + eg_ch0s3, eg_ch1s3, eg_ch2s3, eg_ch3s3, eg_ch4s3, eg_ch5s3, + eg_ch0s4, eg_ch1s4, eg_ch2s4, eg_ch3s4, eg_ch4s4, eg_ch5s4; + + +sep24 #( .width(10), .pos0(17) ) egsep +( + .clk ( clk ), + .mixed ( eg_atten_IX ), + .mask ( 0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (eg_ch0s1), + .ch1s1 (eg_ch1s1), + .ch2s1 (eg_ch2s1), + .ch3s1 (eg_ch3s1), + .ch4s1 (eg_ch4s1), + .ch5s1 (eg_ch5s1), + + .ch0s2 (eg_ch0s2), + .ch1s2 (eg_ch1s2), + .ch2s2 (eg_ch2s2), + .ch3s2 (eg_ch3s2), + .ch4s2 (eg_ch4s2), + .ch5s2 (eg_ch5s2), + + .ch0s3 (eg_ch0s3), + .ch1s3 (eg_ch1s3), + .ch2s3 (eg_ch2s3), + .ch3s3 (eg_ch3s3), + .ch4s3 (eg_ch4s3), + .ch5s3 (eg_ch5s3), + + .ch0s4 (eg_ch0s4), + .ch1s4 (eg_ch1s4), + .ch2s4 (eg_ch2s4), + .ch3s4 (eg_ch3s4), + .ch4s4 (eg_ch4s4), + .ch5s4 (eg_ch5s4) +); + +`endif + + +endmodule diff --git a/src/sound/jt12/jt12_opram.v b/src/sound/jt12/jt12_opram.v new file mode 100644 index 0000000..e2e3c63 --- /dev/null +++ b/src/sound/jt12/jt12_opram.v @@ -0,0 +1,79 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + +module jt12_opram +( + input [4:0] wr_addr, + input [4:0] rd_addr, + input clk, + input [43:0] data, + output reg [43:0] q +); + + reg [43:0] ram[31:0]; + initial + begin + ram[0] = { ~7'd0, 37'd0 }; + ram[1] = { ~7'd0, 37'd0 }; + ram[2] = { ~7'd0, 37'd0 }; + ram[3] = { ~7'd0, 37'd0 }; + ram[4] = { ~7'd0, 37'd0 }; + ram[5] = { ~7'd0, 37'd0 }; + ram[6] = { ~7'd0, 37'd0 }; + ram[7] = { ~7'd0, 37'd0 }; + ram[8] = { ~7'd0, 37'd0 }; + ram[9] = { ~7'd0, 37'd0 }; + ram[10] = { ~7'd0, 37'd0 }; + ram[11] = { ~7'd0, 37'd0 }; + ram[12] = { ~7'd0, 37'd0 }; + ram[13] = { ~7'd0, 37'd0 }; + ram[14] = { ~7'd0, 37'd0 }; + ram[15] = { ~7'd0, 37'd0 }; + ram[16] = { ~7'd0, 37'd0 }; + ram[17] = { ~7'd0, 37'd0 }; + ram[18] = { ~7'd0, 37'd0 }; + ram[19] = { ~7'd0, 37'd0 }; + ram[20] = { ~7'd0, 37'd0 }; + ram[21] = { ~7'd0, 37'd0 }; + ram[22] = { ~7'd0, 37'd0 }; + ram[23] = { ~7'd0, 37'd0 }; + ram[24] = { ~7'd0, 37'd0 }; + ram[25] = { ~7'd0, 37'd0 }; + ram[26] = { ~7'd0, 37'd0 }; + ram[27] = { ~7'd0, 37'd0 }; + ram[28] = { ~7'd0, 37'd0 }; + ram[29] = { ~7'd0, 37'd0 }; + ram[30] = { ~7'd0, 37'd0 }; + ram[31] = { ~7'd0, 37'd0 }; + end + + always @ (posedge clk) begin + q <= ram[rd_addr]; + ram[wr_addr] <= data; + end + +endmodule diff --git a/src/sound/jt12/jt12_pg.v b/src/sound/jt12/jt12_pg.v new file mode 100644 index 0000000..cb73d0c --- /dev/null +++ b/src/sound/jt12/jt12_pg.v @@ -0,0 +1,412 @@ +/* This file is part of JT12. + + JT12 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2016 + + Based on information posted by Nemesis on: +http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167 + + Based on jt51_phasegen.v, from JT51 + + */ + +`timescale 1ns / 1ps + +/* + + tab size 4 + +*/ + +module jt12_pg( + input clk, + input rst, + // Channel frequency + input [10:0] fnum_I, + input [ 2:0] block_I, + // Operator multiplying + input [ 3:0] mul_V, + // Operator detuning + input [ 2:0] dt1_II, // same as JT51's DT1 + // phase modulation from LFO + //input [ 7:0] pm, + //input [ 2:0] pms, + // phase operation + input pg_rst_III, + input zero, + input pg_stop, + + output reg [ 4:0] keycode_III, + output reg [ 9:0] phase_VIII +); + +/* +reg signed [8:0] mod; + +always @(*) begin + case( pms ) // comprobar en silicio + 3'd0: mod <= 9'd0; + 3'd1: mod <= { 7'd0, pm[6:5] }; + 3'd2: mod <= { 6'd0, pm[6:4] }; + 3'd3: mod <= { 5'd0, pm[6:3] }; + 3'd4: mod <= { 4'd0, pm[6:2] }; + 3'd5: mod <= { 3'd0, pm[6:1] }; + 3'd6: mod <= { 1'd0, pm[6:0], 1'b0 }; + 3'd7: mod <= { pm[6:0], 2'b0 }; + endcase +end + +jt12_pm u_pm( + // Channel frequency + .kc(kc), + .kf(kf), + .add(~pm[7]), + .mod(mod), + .kcex(keycode_I) +); +*/ + +wire pg_rst_VI; + +////////////////////////////////////////////////// +// I +reg [4:0] keycode_II; +reg [16:0] phinc_II; + +always @(posedge clk) begin : phase_calculation_I + case ( block_I ) + 3'd0: phinc_II <= { 7'd0, fnum_I[10:1] }; + 3'd1: phinc_II <= { 6'd0, fnum_I }; + 3'd2: phinc_II <= { 5'd0, fnum_I, 1'd0 }; + 3'd3: phinc_II <= { 4'd0, fnum_I, 2'd0 }; + 3'd4: phinc_II <= { 3'd0, fnum_I, 3'd0 }; + 3'd5: phinc_II <= { 2'd0, fnum_I, 4'd0 }; + 3'd6: phinc_II <= { 1'd0, fnum_I, 5'd0 }; + 3'd7: phinc_II <= { fnum_I, 6'd0 }; + endcase + keycode_II <= { block_I, fnum_I[10], fnum_I[10] ? (|fnum_I[9:7]) : (&fnum_I[9:7])}; +end + +////////////////////////////////////////////////// +// II +reg [ 5:0] dt1_kf_III; +reg [16:0] phinc_III; +reg [ 2:0] dt1_III; + +always @(posedge clk) begin : phase_calculation_II + case( dt1_II[1:0] ) + 2'd1: dt1_kf_III <= { 1'b0, keycode_II } - 6'd4; + 2'd2: dt1_kf_III <= { 1'b0, keycode_II } + 6'd4; + 2'd3: dt1_kf_III <= { 1'b0, keycode_II } + 6'd8; + default:dt1_kf_III <= { 1'b0, keycode_II }; + endcase + dt1_III <= dt1_II; + phinc_III <= phinc_II; + keycode_III <= keycode_II; +end + +////////////////////////////////////////////////// +// III +reg [16:0] phinc_IV; +reg [ 4:0] pow2; +reg [ 2:0] dt1_IV; + +always @(*) begin : calcpow2 + case( dt1_kf_III[2:0] ) + 3'd0: pow2 <= 5'd16; + 3'd1: pow2 <= 5'd17; + 3'd2: pow2 <= 5'd19; + 3'd3: pow2 <= 5'd20; + 3'd4: pow2 <= 5'd22; + 3'd5: pow2 <= 5'd24; + 3'd6: pow2 <= 5'd26; + 3'd7: pow2 <= 5'd29; + endcase +end + +reg [5:0] dt1_unlimited; +reg [4:0] dt1_limit, dt1_offset_IV; + +always @(*) begin : dt1_limit_mux + case( dt1_III[1:0] ) + default: dt1_limit <= 5'd8; + 2'd1: dt1_limit <= 5'd8; + 2'd2: dt1_limit <= 5'd16; + 2'd3: dt1_limit <= 5'd22; + endcase + case( dt1_kf_III[5:3] ) + 3'd0: dt1_unlimited <= { 5'd0, pow2[4] }; // <2 + 3'd1: dt1_unlimited <= { 4'd0, pow2[4:3] }; // <4 + 3'd2: dt1_unlimited <= { 3'd0, pow2[4:2] }; // <8 + 3'd3: dt1_unlimited <= { 2'd0, pow2[4:1] }; + 3'd4: dt1_unlimited <= { 1'd0, pow2[4:0] }; + 3'd5: dt1_unlimited <= { pow2[4:0], 1'd0 }; + default:dt1_unlimited <= 6'd0; + endcase +end + +always @(posedge clk) begin : phase_calculation_III + dt1_offset_IV <= dt1_unlimited > dt1_limit ? + dt1_limit : dt1_unlimited[4:0]; + dt1_IV <= dt1_III; + phinc_IV <= phinc_III; +end + +////////////////////////////////////////////////// +// IV +reg [16:0] phinc_V; + +always @(posedge clk) begin : phase_calculation_IV + if( dt1_IV[1:0]==2'd0 ) + phinc_V <= phinc_IV; + else begin + if( !dt1_IV[2] ) + phinc_V <= phinc_IV + dt1_offset_IV; + else + phinc_V <= phinc_IV - dt1_offset_IV; + end +end + +////////////////////////////////////////////////// +// V APPLY_MUL +reg [16:0] phinc_VI; +always @(posedge clk) begin : phase_calculation_V + if( mul_V==4'd0 ) + phinc_VI <= { 1'b0, phinc_V[16:1] }; + else + phinc_VI <= phinc_V * mul_V; +end + +////////////////////////////////////////////////// +// VI add phinc to the phase +wire keyon_VI; +wire [19:0] phase_drop; +reg [19:0] phase_in; +reg [ 9:0] phase_VII; + +always @(*) + phase_in <= pg_rst_VI ? 20'd0 : + ( pg_stop ? phase_drop : phase_drop + phinc_VI); + +always @(posedge clk) begin : phase_calculation_VI + phase_VII <= phase_in[19:10]; +end + +////////////////////////////////////////////////// +// VIII padding + +always @(posedge clk) + phase_VIII <= phase_VII; + +jt12_sh #( .width(20), .stages(24) ) u_phsh( + .clk ( clk ), +// .rst ( rst ), + .din ( phase_in ), + .drop ( phase_drop) +); + +jt12_sh #( .width(1), .stages(3) ) u_rstsh( + .clk ( clk ), + .din ( pg_rst_III), + .drop ( pg_rst_VI ) +); + + + +`ifdef SIMULATION +reg [4:0] sep24_cnt; + +wire [9:0] pg_ch0s1, pg_ch1s1, pg_ch2s1, pg_ch3s1, + pg_ch4s1, pg_ch5s1, pg_ch0s2, pg_ch1s2, + pg_ch2s2, pg_ch3s2, pg_ch4s2, pg_ch5s2, + pg_ch0s3, pg_ch1s3, pg_ch2s3, pg_ch3s3, + pg_ch4s3, pg_ch5s3, pg_ch0s4, pg_ch1s4, + pg_ch2s4, pg_ch3s4, pg_ch4s4, pg_ch5s4; + +always @(posedge clk) + sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; + +sep24 #( .width(10), .pos0(18)) stsep +( + .clk ( clk ), + .mixed ( phase_VIII), + .mask ( 0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (pg_ch0s1), + .ch1s1 (pg_ch1s1), + .ch2s1 (pg_ch2s1), + .ch3s1 (pg_ch3s1), + .ch4s1 (pg_ch4s1), + .ch5s1 (pg_ch5s1), + + .ch0s2 (pg_ch0s2), + .ch1s2 (pg_ch1s2), + .ch2s2 (pg_ch2s2), + .ch3s2 (pg_ch3s2), + .ch4s2 (pg_ch4s2), + .ch5s2 (pg_ch5s2), + + .ch0s3 (pg_ch0s3), + .ch1s3 (pg_ch1s3), + .ch2s3 (pg_ch2s3), + .ch3s3 (pg_ch3s3), + .ch4s3 (pg_ch4s3), + .ch5s3 (pg_ch5s3), + + .ch0s4 (pg_ch0s4), + .ch1s4 (pg_ch1s4), + .ch2s4 (pg_ch2s4), + .ch3s4 (pg_ch3s4), + .ch4s4 (pg_ch4s4), + .ch5s4 (pg_ch5s4) +); + +wire [16:0] phinc_ch0s1, phinc_ch1s1, phinc_ch2s1, phinc_ch3s1, + phinc_ch4s1, phinc_ch5s1, phinc_ch0s2, phinc_ch1s2, + phinc_ch2s2, phinc_ch3s2, phinc_ch4s2, phinc_ch5s2, + phinc_ch0s3, phinc_ch1s3, phinc_ch2s3, phinc_ch3s3, + phinc_ch4s3, phinc_ch5s3, phinc_ch0s4, phinc_ch1s4, + phinc_ch2s4, phinc_ch3s4, phinc_ch4s4, phinc_ch5s4; + +sep24 #( .width(17), .pos0(3+6)) pisep +( + .clk ( clk ), + .mixed ( phinc_VI), + .mask ( 0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (phinc_ch0s1), + .ch1s1 (phinc_ch1s1), + .ch2s1 (phinc_ch2s1), + .ch3s1 (phinc_ch3s1), + .ch4s1 (phinc_ch4s1), + .ch5s1 (phinc_ch5s1), + + .ch0s2 (phinc_ch0s2), + .ch1s2 (phinc_ch1s2), + .ch2s2 (phinc_ch2s2), + .ch3s2 (phinc_ch3s2), + .ch4s2 (phinc_ch4s2), + .ch5s2 (phinc_ch5s2), + + .ch0s3 (phinc_ch0s3), + .ch1s3 (phinc_ch1s3), + .ch2s3 (phinc_ch2s3), + .ch3s3 (phinc_ch3s3), + .ch4s3 (phinc_ch4s3), + .ch5s3 (phinc_ch5s3), + + .ch0s4 (phinc_ch0s4), + .ch1s4 (phinc_ch1s4), + .ch2s4 (phinc_ch2s4), + .ch3s4 (phinc_ch3s4), + .ch4s4 (phinc_ch4s4), + .ch5s4 (phinc_ch5s4) +); + +wire [10:0] fnum_ch0s1, fnum_ch1s1, fnum_ch2s1, fnum_ch3s1, + fnum_ch4s1, fnum_ch5s1, fnum_ch0s2, fnum_ch1s2, + fnum_ch2s2, fnum_ch3s2, fnum_ch4s2, fnum_ch5s2, + fnum_ch0s3, fnum_ch1s3, fnum_ch2s3, fnum_ch3s3, + fnum_ch4s3, fnum_ch5s3, fnum_ch0s4, fnum_ch1s4, + fnum_ch2s4, fnum_ch3s4, fnum_ch4s4, fnum_ch5s4; + +sep24 #( .width(11), .pos0(3+1)) fnsep +( + .clk ( clk ), + .mixed ( fnum_I), + .mask ( 0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (fnum_ch0s1), + .ch1s1 (fnum_ch1s1), + .ch2s1 (fnum_ch2s1), + .ch3s1 (fnum_ch3s1), + .ch4s1 (fnum_ch4s1), + .ch5s1 (fnum_ch5s1), + + .ch0s2 (fnum_ch0s2), + .ch1s2 (fnum_ch1s2), + .ch2s2 (fnum_ch2s2), + .ch3s2 (fnum_ch3s2), + .ch4s2 (fnum_ch4s2), + .ch5s2 (fnum_ch5s2), + + .ch0s3 (fnum_ch0s3), + .ch1s3 (fnum_ch1s3), + .ch2s3 (fnum_ch2s3), + .ch3s3 (fnum_ch3s3), + .ch4s3 (fnum_ch4s3), + .ch5s3 (fnum_ch5s3), + + .ch0s4 (fnum_ch0s4), + .ch1s4 (fnum_ch1s4), + .ch2s4 (fnum_ch2s4), + .ch3s4 (fnum_ch3s4), + .ch4s4 (fnum_ch4s4), + .ch5s4 (fnum_ch5s4) +); + +wire pgrst_III_ch0s1, pgrst_III_ch1s1, pgrst_III_ch2s1, pgrst_III_ch3s1, + pgrst_III_ch4s1, pgrst_III_ch5s1, pgrst_III_ch0s2, pgrst_III_ch1s2, + pgrst_III_ch2s2, pgrst_III_ch3s2, pgrst_III_ch4s2, pgrst_III_ch5s2, + pgrst_III_ch0s3, pgrst_III_ch1s3, pgrst_III_ch2s3, pgrst_III_ch3s3, + pgrst_III_ch4s3, pgrst_III_ch5s3, pgrst_III_ch0s4, pgrst_III_ch1s4, + pgrst_III_ch2s4, pgrst_III_ch3s4, pgrst_III_ch4s4, pgrst_III_ch5s4; + +sep24 #( .width(1), .pos0(23)) pgrstsep +( + .clk ( clk ), + .mixed ( pg_rst_III), + .mask ( 0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (pgrst_III_ch0s1), + .ch1s1 (pgrst_III_ch1s1), + .ch2s1 (pgrst_III_ch2s1), + .ch3s1 (pgrst_III_ch3s1), + .ch4s1 (pgrst_III_ch4s1), + .ch5s1 (pgrst_III_ch5s1), + + .ch0s2 (pgrst_III_ch0s2), + .ch1s2 (pgrst_III_ch1s2), + .ch2s2 (pgrst_III_ch2s2), + .ch3s2 (pgrst_III_ch3s2), + .ch4s2 (pgrst_III_ch4s2), + .ch5s2 (pgrst_III_ch5s2), + + .ch0s3 (pgrst_III_ch0s3), + .ch1s3 (pgrst_III_ch1s3), + .ch2s3 (pgrst_III_ch2s3), + .ch3s3 (pgrst_III_ch3s3), + .ch4s3 (pgrst_III_ch4s3), + .ch5s3 (pgrst_III_ch5s3), + + .ch0s4 (pgrst_III_ch0s4), + .ch1s4 (pgrst_III_ch1s4), + .ch2s4 (pgrst_III_ch2s4), + .ch3s4 (pgrst_III_ch3s4), + .ch4s4 (pgrst_III_ch4s4), + .ch5s4 (pgrst_III_ch5s4) +); + + +`endif + +endmodule + diff --git a/src/sound/jt12/jt12_phrom.v b/src/sound/jt12/jt12_phrom.v new file mode 100644 index 0000000..2ca926c --- /dev/null +++ b/src/sound/jt12/jt12_phrom.v @@ -0,0 +1,77 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ +// altera message_off 10030 + +module jt12_phrom +( + input [4:0] addr, + input clk, + output reg [45:0] ph +); + + reg [45:0] sinetable[31:0]; + initial + begin + sinetable[5'd0 ] <= 46'b0001100000100100010001000010101010101001010010; + sinetable[5'd1 ] <= 46'b0001100000110100000100000010010001001101000001; + sinetable[5'd2 ] <= 46'b0001100000110100000100110010001011001101100000; + sinetable[5'd3 ] <= 46'b0001110000010000000000110010110001001101110010; + sinetable[5'd4 ] <= 46'b0001110000010000001100000010111010001101101001; + sinetable[5'd5 ] <= 46'b0001110000010100001001100010000000101101111010; + sinetable[5'd6 ] <= 46'b0001110000010100001101100010010011001101011010; + sinetable[5'd7 ] <= 46'b0001110000011100000101010010111000101111111100; + sinetable[5'd8 ] <= 46'b0001110000111000000001110010101110001101110111; + sinetable[5'd9 ] <= 46'b0001110000111000010100111000011101011010100110; + sinetable[5'd10] <= 46'b0001110000111100011000011000111100001001111010; + sinetable[5'd11] <= 46'b0001110000111100011100111001101011001001110111; + sinetable[5'd12] <= 46'b0100100001010000010001011001001000111010110111; + sinetable[5'd13] <= 46'b0100100001010100010001001001110001111100101010; + sinetable[5'd14] <= 46'b0100100001010100010101101101111110100101000110; + sinetable[5'd15] <= 46'b0100100011100000001000011001010110101101111001; + sinetable[5'd16] <= 46'b0100100011100100001000101011100101001011101111; + sinetable[5'd17] <= 46'b0100100011101100000111011010000001011010110001; + sinetable[5'd18] <= 46'b0100110011001000000111101010000010111010111111; + sinetable[5'd19] <= 46'b0100110011001100001011011110101110110110000001; + sinetable[5'd20] <= 46'b0100110011101000011010111011001010001101110001; + sinetable[5'd21] <= 46'b0100110011101101011010110101111001010100001111; + sinetable[5'd22] <= 46'b0111000010000001010111000101010101010110010111; + sinetable[5'd23] <= 46'b0111000010000101010111110111110101010010111011; + sinetable[5'd24] <= 46'b0111000010110101101000101100001000010000011001; + sinetable[5'd25] <= 46'b0111010010011001100100011110100100010010010010; + sinetable[5'd26] <= 46'b0111010010111010100101100101000000110100100011; + sinetable[5'd27] <= 46'b1010000010011010101101011101100001110010011010; + sinetable[5'd28] <= 46'b1010000010111111111100100111010100010000111001; + sinetable[5'd29] <= 46'b1010010111110100110010001100111001010110100000; + sinetable[5'd30] <= 46'b1011010111010011111011011110000100110010100001; + sinetable[5'd31] <= 46'b1110011011110001111011100111100001110110100111; + + end + + always @ (posedge clk) + ph <= sinetable[addr]; + +endmodule diff --git a/src/sound/jt12/jt12_reg.v b/src/sound/jt12/jt12_reg.v new file mode 100644 index 0000000..7295871 --- /dev/null +++ b/src/sound/jt12/jt12_reg.v @@ -0,0 +1,363 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2017 + +*/ + + +module jt12_reg( + input rst, + input clk, + input [7:0] din, + + input [2:0] ch, + input [1:0] op, + + input csm, + input flag_A, + input overflow_A, + + input up_keyon, + input up_alg, + input up_block, + input up_fnumlo, + input up_pms, + input up_dt1, + input up_tl, + input up_ks_ar, + input up_amen_d1r, + input up_d2r, + + input up_d1l, + input up_ssgeg, + + output busy, + output reg ch6op, // 1 when the operator belongs to CH6 + + // CH3 Effect-mode operation + input effect, + input [10:0] fnum_ch3op2, + input [10:0] fnum_ch3op3, + input [10:0] fnum_ch3op1, + input [ 2:0] block_ch3op2, + input [ 2:0] block_ch3op3, + input [ 2:0] block_ch3op1, + // Pipeline order + output reg zero, + output s1_enters, + output s2_enters, + output s3_enters, + output s4_enters, + + // Operator + output use_prevprev1, + output use_internal_x, + output use_internal_y, + output use_prev2, + output use_prev1, + + // PG + output [10:0] fnum_I, + output [ 2:0] block_I, + // channel configuration + output [1:0] rl, + output reg [2:0] fb_II, + output [2:0] alg, + // Operator multiplying + output [ 3:0] mul_V, + // Operator detuning + output [ 2:0] dt1_II, + + // EG + output [4:0] ar_II, // attack rate + output [4:0] d1r_II, // decay rate + output [4:0] d2r_II, // sustain rate + output [3:0] rr_II, // release rate + output [3:0] d1l, // sustain level + output [1:0] ks_III, // key scale + output ssg_en_II, + output [2:0] ssg_eg_II, + output [6:0] tl_VII, + output [2:0] pms, + output [1:0] ams_VII, + output amsen_VII, + + // envelope operation + output keyon_II +); + + +reg [4:0] cnt; +reg [1:0] next_op, cur_op; +reg [2:0] next_ch, cur_ch; + +assign s1_enters = cur_op == 2'b00; +assign s3_enters = cur_op == 2'b01; +assign s2_enters = cur_op == 2'b10; +assign s4_enters = cur_op == 2'b11; + +wire [4:0] next = { next_op, next_ch }; +wire [4:0] cur = { cur_op, cur_ch }; + +wire [2:0] fb_I; + +always @(posedge clk) begin + fb_II <= fb_I; + ch6op <= next_ch==3'd6; +end + +// FNUM and BLOCK +wire [10:0] fnum_I_raw; +wire [ 2:0] block_I_raw; +wire effect_on = effect && (cur_ch==3'd2); +wire effect_on_s1 = effect_on && (cur_op == 2'd0 ); +wire effect_on_s3 = effect_on && (cur_op == 2'd1 ); +wire effect_on_s2 = effect_on && (cur_op == 2'd2 ); +wire noeffect = ~|{effect_on_s1, effect_on_s3, effect_on_s2}; +assign fnum_I = ( {11{effect_on_s1}} & fnum_ch3op1 ) | + ( {11{effect_on_s2}} & fnum_ch3op2 ) | + ( {11{effect_on_s3}} & fnum_ch3op3 ) | + ( {11{noeffect}} & fnum_I_raw ); + +assign block_I =( {3{effect_on_s1}} & block_ch3op1 ) | + ( {3{effect_on_s2}} & block_ch3op2 ) | + ( {3{effect_on_s3}} & block_ch3op3 ) | + ( {3{noeffect}} & block_I_raw ); + +wire [2:0] ch_II, ch_III, ch_IV, ch_V, ch_VI; + +wire [4:0] req_opch_I = { op, ch }; +wire [4:0] req_opch_II, req_opch_III, + req_opch_IV, req_opch_V, req_opch_VI; + +jt12_sumch u_opch_II ( .chin(req_opch_I ), .chout(req_opch_II) ); +jt12_sumch u_opch_III( .chin(req_opch_II ), .chout(req_opch_III) ); +jt12_sumch u_opch_IV ( .chin(req_opch_III), .chout(req_opch_IV) ); +jt12_sumch u_opch_V ( .chin(req_opch_IV ), .chout(req_opch_V) ); +jt12_sumch u_opch_VI ( .chin(req_opch_V ), .chout(req_opch_VI) ); + +wire update_op_I = cur == req_opch_I; +wire update_op_II = cur == req_opch_II; +wire update_op_III= cur == req_opch_III; +// wire update_op_IV = cur == opch_IV; +wire update_op_V = cur == req_opch_V; +// wire update_op_VI = cur == opch_VI; +wire [2:0] op_plus1 = op+2'd1; +wire update_op_VII= cur == { op_plus1[1:0], ch }; + +// key on/off +wire [3:0] keyon_op = din[7:4]; +wire [2:0] keyon_ch = din[2:0]; +// channel data +wire [1:0] rl_in = din[7:6]; +wire [2:0] fb_in = din[5:3]; +wire [2:0] alg_in = din[2:0]; +wire [2:0] pms_in = din[2:0]; +wire [1:0] ams_in = din[5:4]; +wire [2:0] block_in= din[5:3]; +wire [2:0] fnhi_in = din[2:0]; +wire [7:0] fnlo_in = din; +// operator data +wire [2:0] dt1_in = din[6:4]; +wire [3:0] mul_in = din[3:0]; +wire [6:0] tl_in = din[6:0]; +wire [1:0] ks_in = din[7:6]; +wire [4:0] ar_in = din[4:0]; +wire amen_in = din[7]; +wire [4:0] d1r_in = din[4:0]; +wire [4:0] d2r_in = din[4:0]; +wire [3:0] d1l_in = din[7:4]; +wire [3:0] rr_in = din[3:0]; +wire [3:0] ssg_in = din[3:0]; + +wire [3:0] ssg; + +reg last; + +wire update_ch_I = cur_ch == ch; + +wire up_alg_ch = up_alg & update_ch_I; +wire up_block_ch= up_block & update_ch_I; +wire up_fnumlo_ch=up_fnumlo & update_ch_I; +wire up_pms_ch = up_pms & update_ch_I; + +// DT1 & MUL +wire up_dt1_op = up_dt1 & update_op_II; +wire up_mul_op = up_dt1 & update_op_V; +// TL +wire up_tl_op = up_tl & update_op_VII; +// KS & AR +wire up_ks_op = up_ks_ar & update_op_III; +wire up_ar_op = up_ks_ar & update_op_II; +// AM ON, D1R +wire up_amen_op = up_amen_d1r & update_op_VII; +wire up_d1r_op = up_amen_d1r & update_op_II; +// Sustain Rate (D2R) +wire up_d2r_op = up_d2r & update_op_II; +// D1L & RR +wire up_d1l_op = up_d1l & update_op_I; +wire up_rr_op = up_d1l & update_op_II; +// SSG +//wire up_ssgen_op = up_ssgeg & update_op_I; +wire up_ssg_op = up_ssgeg & update_op_II; + +wire up = up_alg | up_block | up_fnumlo | up_pms | + up_dt1 | up_tl | up_ks_ar | up_amen_d1r | + up_d2r | up_d1l | up_ssgeg | up_keyon; + +always @(*) begin + // next <= cur==5'd23 ? 5'd0 : cur +1'b1; + next_op <= cur_ch==3'd6 ? cur_op+1'b1 : cur_op; + next_ch <= cur_ch[1:0]==2'b10 ? cur_ch+2'd2 : cur_ch+1'd1; +end + +reg busy_op; +reg up_keyon_long; + +assign busy = busy_op; + + +always @(posedge clk) begin : up_counter + if( rst ) begin + cnt <= 5'h0; + last <= 1'b0; + zero <= 1'b1; + busy_op <= 1'b0; + up_keyon_long <= 1'b0; + cur_op <= 2'd0; + cur_ch <= 3'd0; + end + else begin + { cur_op, cur_ch } <= { next_op, next_ch }; + zero <= next == 5'd0; + last <= up; + if( up && !last ) begin + cnt <= cur; + busy_op <= 1'b1; + up_keyon_long <= up_keyon; + end + else if( cnt == cur ) begin + busy_op <= 1'b0; + up_keyon_long <= 1'b0; + end + end +end + +jt12_kon u_kon( + .rst ( rst ), + .clk ( clk ), + .keyon_op ( keyon_op ), + .keyon_ch ( keyon_ch ), + .cur_op ( cur_op ), + .cur_ch ( cur_ch ), + .up_keyon ( up_keyon_long ), + .csm ( csm ), + .flag_A ( flag_A ), + .overflow_A ( overflow_A), + + .keyon_II ( keyon_II ) +); + +jt12_mod u_mod( + .alg_I ( alg ), + .s1_enters ( s1_enters ), + .s3_enters ( s3_enters ), + .s2_enters ( s2_enters ), + .s4_enters ( s4_enters ), + + .use_prevprev1 ( use_prevprev1 ), + .use_internal_x( use_internal_x ), + .use_internal_y( use_internal_y ), + .use_prev2 ( use_prev2 ), + .use_prev1 ( use_prev1 ) +); + +// memory for OP registers +parameter regop_width=44; + +wire [regop_width-1:0] regop_in, regop_out; + +jt12_opram u_opram( + .clk ( clk ), + .wr_addr ( cur ), + .rd_addr ( next ), + .data ( regop_in ), + .q ( regop_out ) +); + +assign regop_in = { + up_tl_op ? tl_in : tl_VII, // 7 + up_dt1_op ? dt1_in : dt1_II, // 3 + up_mul_op ? mul_in : mul_V, // 4 - 7 + up_ks_op ? ks_in : ks_III, // 2 - 16 + up_ar_op ? ar_in : ar_II, // 5 - 21 + up_amen_op ? amen_in: amsen_VII,// 1 - 22 + up_d1r_op ? d1r_in : d1r_II, // 5 - 25 + up_d2r_op ? d2r_in : d2r_II, // 5 - 30 + up_d1l_op ? d1l_in : d1l, // 4 - 34 + up_rr_op ? rr_in : rr_II, // 4 - 38 + up_ssg_op ? ssg_in[3] : ssg_en_II, // 1 - 39 + up_ssg_op ? ssg_in[2:0] : ssg_eg_II // 3 - 42 +}; + +assign { tl_VII, dt1_II, mul_V, ks_III, + ar_II, amsen_VII, d1r_II, d2r_II, d1l, rr_II, + ssg_en_II, ssg_eg_II } = regop_out; + + +wire [2:0] block_latch, fnum_latch; + +// memory for CH registers +// Block/fnum data is latched until fnum low byte is written to +// Trying to synthesize this memory as M-9K RAM in Altera devices +// turns out worse in terms of resource utilization. Probably because +// this memory is already very small. It is better to leave it as it is. +parameter regch_width=31; +wire [regch_width-1:0] regch_out; +wire [regch_width-1:0] regch_in = { + up_block_ch ? { block_in, fnhi_in } : { block_latch, fnum_latch }, // 3+3 + up_fnumlo_ch? { block_latch, fnum_latch, fnlo_in } : { block_I_raw, fnum_I_raw }, // 14 + up_alg_ch ? { fb_in, alg_in } : { fb_I, alg },//3+3 + up_pms_ch ? { ams_in, pms_in } : { ams_VII, pms }//2+2+3 +}; + +assign { block_latch, fnum_latch, + block_I_raw, fnum_I_raw, + fb_I, alg, ams_VII, pms } = regch_out; + +jt12_sh #(.width(regch_width),.stages(6)) u_regch( + .clk ( clk ), + //.rst ( rst ), + .din ( regch_in ), + .drop ( regch_out ) +); + +// RL is on a different register to +// have the reset to 1 +jt12_sh_rst #(.width(2),.stages(6),.rstval(1'b1)) u_regch_rl( + .clk ( clk ), +// .rst ( rst ), + .din ( up_pms_ch ? rl_in : rl ), + .drop ( rl ) +); + +endmodule diff --git a/src/sound/jt12/jt12_sh.v b/src/sound/jt12/jt12_sh.v new file mode 100644 index 0000000..ac2aeb9 --- /dev/null +++ b/src/sound/jt12/jt12_sh.v @@ -0,0 +1,45 @@ +/* This file is part of JT12. + + JT12 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 1-31-2017 + */ + +`timescale 1ns / 1ps + +module jt12_sh #(parameter width=5, stages=24 ) +( + input clk, + input [width-1:0] din, + output [width-1:0] drop +); + +reg [stages-1:0] bits[width-1:0]; + +genvar i; +generate + for (i=0; i < width; i=i+1) begin: bit_shifter + always @(posedge clk) begin + if( stages> 1 ) + bits[i] <= {bits[i][stages-2:0], din[i]}; + else + bits[i] <= din[i]; + end + assign drop[i] = bits[i][stages-1]; + end +endgenerate + +endmodule diff --git a/src/sound/jt12/jt12_sh24.v b/src/sound/jt12/jt12_sh24.v new file mode 100644 index 0000000..dfb1596 --- /dev/null +++ b/src/sound/jt12/jt12_sh24.v @@ -0,0 +1,80 @@ +/* This file is part of JT12. + + JT12 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 1-31-2017 + */ + +`timescale 1ns / 1ps + +module jt12_sh24 #(parameter width=5 ) +( + input clk, + input [width-1:0] din, + output reg [width-1:0] st1, + output reg [width-1:0] st2, + output reg [width-1:0] st3, + output reg [width-1:0] st4, + output reg [width-1:0] st5, + output reg [width-1:0] st6, + output reg [width-1:0] st7, + output reg [width-1:0] st8, + output reg [width-1:0] st9, + output reg [width-1:0] st10, + output reg [width-1:0] st11, + output reg [width-1:0] st12, + output reg [width-1:0] st13, + output reg [width-1:0] st14, + output reg [width-1:0] st15, + output reg [width-1:0] st16, + output reg [width-1:0] st17, + output reg [width-1:0] st18, + output reg [width-1:0] st19, + output reg [width-1:0] st20, + output reg [width-1:0] st21, + output reg [width-1:0] st22, + output reg [width-1:0] st23, + output reg [width-1:0] st24 +); + +always @(posedge clk) begin + st24<= st23; + st23<= st22; + st22<= st21; + st21<= st20; + st20<= st19; + st19<= st18; + st18<= st17; + st17<= st16; + st16<= st15; + st15<= st14; + st14<= st13; + st13<= st12; + st12<= st11; + st11<= st10; + st10<= st9; + st9 <= st8; + st8 <= st7; + st7 <= st6; + st6 <= st5; + st5 <= st4; + st4 <= st3; + st3 <= st2; + st2 <= st1; + st1 <= din; +end + +endmodule diff --git a/src/sound/jt12/jt12_sh_rst.v b/src/sound/jt12/jt12_sh_rst.v new file mode 100644 index 0000000..3e2cc13 --- /dev/null +++ b/src/sound/jt12/jt12_sh_rst.v @@ -0,0 +1,54 @@ +/* This file is part of JT12. + + JT12 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 1-31-2017 + */ + +`timescale 1ns / 1ps + +module jt12_sh_rst #(parameter width=5, stages=32, rstval=1'b0 ) +( +// input rst, + input clk, + input [width-1:0] din, + output [width-1:0] drop +); + +reg [stages-1:0] bits[width-1:0]; + +genvar i; +integer k; +generate +initial + for (k=0; k < width; k=k+1) begin + bits[k] <= { stages{rstval}}; + end +endgenerate + +generate + for (i=0; i < width; i=i+1) begin: bit_shifter + always @(posedge clk) begin + if( stages> 1 ) + bits[i] <= {bits[i][stages-2:0], din[i]}; + else + bits[i] <= din[i]; + end + assign drop[i] = bits[i][stages-1]; + end +endgenerate + +endmodule diff --git a/src/sound/jt12/jt12_sumch.v b/src/sound/jt12/jt12_sumch.v new file mode 100644 index 0000000..d3713ed --- /dev/null +++ b/src/sound/jt12/jt12_sumch.v @@ -0,0 +1,37 @@ +/* This file is part of JT12. + + JT12 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 1-31-2017 + */ + +`timescale 1ns / 1ps + +module jt12_sumch +( + input [4:0] chin, + output reg [4:0] chout +); + +reg [2:0] aux; + +always @(*) begin + aux <= chin[2:0] + 3'd1; + chout[2:0] <= aux[1:0]==2'b11 ? aux+3'd1 : aux; + chout[4:3] <= chin[2:0]==3'd6 ? chin[4:3]+2'd1 : chin[4:3]; +end + +endmodule diff --git a/src/sound/jt12/jt12_syn.v b/src/sound/jt12/jt12_syn.v new file mode 100644 index 0000000..5ee5a0c --- /dev/null +++ b/src/sound/jt12/jt12_syn.v @@ -0,0 +1,338 @@ +module jt12_syn( + input rst, + input clk, // cpu_clk/6 ~ 1.3MHz + input [7:0] din, + input [1:0] addr, + input write, + input limiter_en, + + output busy, + output flag_A, + output flag_B, + output irq_n, + // combined output + output signed [11:0] snd_right, + output signed [11:0] snd_left, + output snd_sample, + // multiplexed output + output signed [8:0] mux_right, + output signed [8:0] mux_left, + output mux_sample +); +// Timers +wire [9:0] value_A; +wire [7:0] value_B; +wire load_A, load_B; +wire enable_irq_A, enable_irq_B; +wire clr_flag_A, clr_flag_B; +wire overflow_A; +wire fast_timers; + +wire zero; // Single-clock pulse at the begginig of s1_enters +// LFO +wire [2:0] lfo_freq; +wire lfo_en; +// Operators +wire amsen_VII; +wire [ 2:0] dt1_II; +wire [ 3:0] mul_V; +wire [ 6:0] tl_VII; + +wire [4:0] keycode_III; +wire [ 4:0] ar_II; +wire [ 4:0] d1r_II; +wire [ 4:0] d2r_II; +wire [ 3:0] rr_II; +wire [ 3:0] d1l; +wire [ 1:0] ks_III; +// SSG operation +wire ssg_en_II; +wire [2:0] ssg_eg_II; +// envelope operation +wire keyon_II; +wire [9:0] eg_IX; +wire pg_rst_III; +// Channel +wire [10:0] fnum_I; +wire [ 2:0] block_I; +wire [ 1:0] rl; +wire [ 2:0] fb_II; +wire [ 2:0] alg; +wire [ 2:0] pms; +wire [ 1:0] ams_VII; +// PCM +wire pcm_en; +wire [ 8:0] pcm; +// Test +wire pg_stop, eg_stop; + +wire ch6op; + +// Operator +wire use_internal_x, use_internal_y; +wire use_prevprev1, use_prev2, use_prev1; +wire [ 9:0] phase_VIII; +wire s1_enters, s2_enters, s3_enters, s4_enters; +wire rst_int; +// LFO +wire [6:0] lfo_mod; +wire lfo_rst; + +`ifdef TEST_SUPPORT +// Test bits +wire test_eg, test_op0; +`endif + +jt12_mmr u_mmr( + .rst ( rst ), + .clk ( clk ), + .din ( din ), + .write ( write ), + .addr ( addr ), + .busy ( busy ), + .ch6op ( ch6op ), + // LFO + .lfo_freq ( lfo_freq ), + .lfo_en ( lfo_en ), + // Timers + .value_A ( value_A ), + .value_B ( value_B ), + .load_A ( load_A ), + .load_B ( load_B ), + .enable_irq_A ( enable_irq_A ), + .enable_irq_B ( enable_irq_B ), + .clr_flag_A ( clr_flag_A ), + .clr_flag_B ( clr_flag_B ), + .flag_A ( flag_A ), + .overflow_A ( overflow_A ), + .fast_timers( fast_timers ), + // PCM + .pcm ( pcm ), + .pcm_en ( pcm_en ), + + `ifdef TEST_SUPPORT + // Test + .test_eg ( test_eg ), + .test_op0 ( test_op0 ), + `endif + // Operator + .use_prevprev1 ( use_prevprev1 ), + .use_internal_x ( use_internal_x ), + .use_internal_y ( use_internal_y ), + .use_prev2 ( use_prev2 ), + .use_prev1 ( use_prev1 ), + // PG + .fnum_I ( fnum_I ), + .block_I ( block_I ), + .pg_stop ( pg_stop ), + // EG + .rl ( rl ), + .fb_II ( fb_II ), + .alg ( alg ), + .pms ( pms ), + .ams_VII ( ams_VII ), + .amsen_VII ( amsen_VII ), + .dt1_II ( dt1_II ), + .mul_V ( mul_V ), + .tl_VII ( tl_VII ), + + .ar_II ( ar_II ), + .d1r_II ( d1r_II ), + .d2r_II ( d2r_II ), + .rr_II ( rr_II ), + .d1l ( d1l ), + .ks_III ( ks_III ), + + .eg_stop ( eg_stop ), + // SSG operation + .ssg_en_II ( ssg_en_II ), + .ssg_eg_II ( ssg_eg_II ), + + .keyon_II ( keyon_II ), + // Operator + .zero ( zero ), + .s1_enters ( s1_enters ), + .s2_enters ( s2_enters ), + .s3_enters ( s3_enters ), + .s4_enters ( s4_enters ) +); + +jt12_timers u_timers( + .clk ( clk ), + .rst ( rst ), + .clk_en ( zero ), + .fast_timers( fast_timers ), // fix this to work well with clock enable signals + .value_A ( value_A ), + .value_B ( value_B ), + .load_A ( load_A ), + .load_B ( load_B ), + .enable_irq_A( enable_irq_B ), + .enable_irq_B( enable_irq_A ), + .clr_flag_A ( clr_flag_A ), + .clr_flag_B ( clr_flag_B ), + .flag_A ( flag_A ), + .flag_B ( flag_B ), + .overflow_A ( overflow_A ), + .irq_n ( irq_n ) +); + +jt12_lfo u_lfo( + .rst ( rst ), + .clk ( clk ), + .zero ( zero ), + .lfo_rst ( 1'b0 ), + .lfo_en ( lfo_en ), + .lfo_freq ( lfo_freq ), + .lfo_mod ( lfo_mod ) +); + +`ifndef TIMERONLY + +jt12_pg u_pg( + .clk ( clk ), + .rst ( rst ), + // Channel frequency + .fnum_I ( fnum_I ), + .block_I ( block_I ), + // Operator multiplying + .mul_V ( mul_V ), + // Operator detuning + .dt1_II ( dt1_II ), // same as JT51's DT1 + // phase operation + .pg_rst_III ( pg_rst_III ), + .zero ( zero ), + .pg_stop ( pg_stop ), + .keycode_III( keycode_III ), + .phase_VIII ( phase_VIII ) +); + +jt12_eg u_eg( + `ifdef TEST_SUPPORT + .test_eg ( test_eg ), + `endif + .rst ( rst ), + .clk ( clk ), + .zero ( zero ), + .eg_stop ( eg_stop ), + // envelope configuration + .keycode_III ( keycode_III ), + .arate_II ( ar_II ), // attack rate + .rate1_II ( d1r_II ), // decay rate + .rate2_II ( d2r_II ), // sustain rate + .rrate_II ( rr_II ), // release rate + .d1l ( d1l ), // sustain level + .ks_III ( ks_III ), // key scale + // SSG operation + .ssg_en_II ( ssg_en_II ), + .ssg_eg_II ( ssg_eg_II ), + // envelope operation + .keyon_II ( keyon_II ), + // envelope number + .am ( lfo_mod ), + .tl_VII ( tl_VII ), + .ams_VII ( ams_VII ), + .amsen_VII ( amsen_VII ), + + .eg_IX ( eg_IX ), + .pg_rst_III ( pg_rst_III ) +); + +wire [8:0] op_result; + +jt12_op u_op( + .rst ( rst ), + .clk ( clk ), + .pg_phase_VIII ( phase_VIII ), + .eg_atten_IX ( eg_IX ), + .fb_II ( fb_II ), + + .test_214 ( 1'b0 ), + .s1_enters ( s1_enters ), + .s2_enters ( s2_enters ), + .s3_enters ( s3_enters ), + .s4_enters ( s4_enters ), + .use_prevprev1 ( use_prevprev1 ), + .use_internal_x ( use_internal_x), + .use_internal_y ( use_internal_y), + .use_prev2 ( use_prev2 ), + .use_prev1 ( use_prev1 ), + .zero ( zero ), + .op_result ( op_result ) +); + +jt12_acc u_acc( + .rst ( rst ), + .clk ( clk ), + .op_result ( op_result ), + .rl ( rl ), + .limiter_en ( limiter_en), + // note that the order changes to deal + // with the operator pipeline delay + .s1_enters ( s2_enters ), + .s2_enters ( s1_enters ), + .s3_enters ( s4_enters ), + .s4_enters ( s3_enters ), + .ch6op ( ch6op ), + .pcm_en ( pcm_en ), // only enabled for channel 6 + .pcm ( pcm ), + .alg ( alg ), + // combined output + .left ( snd_left ), + .right ( snd_right ), + .sample ( snd_sample), + // muxed output + .mux_left ( mux_left ), + .mux_right ( mux_right ), + .mux_sample ( mux_sample) +); + +`ifdef SIMULATION +reg [4:0] sep24_cnt; + +wire [9:0] eg_ch0s1, eg_ch1s1, eg_ch2s1, eg_ch3s1, eg_ch4s1, eg_ch5s1, + eg_ch0s2, eg_ch1s2, eg_ch2s2, eg_ch3s2, eg_ch4s2, eg_ch5s2, + eg_ch0s3, eg_ch1s3, eg_ch2s3, eg_ch3s3, eg_ch4s3, eg_ch5s3, + eg_ch0s4, eg_ch1s4, eg_ch2s4, eg_ch3s4, eg_ch4s4, eg_ch5s4; + +always @(posedge clk) + sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; + +sep24 #( .width(10), .pos0(5'd0)) egsep +( + .clk ( clk ), + .mixed ( eg_IX ), + .mask ( 10'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (eg_ch0s1), + .ch1s1 (eg_ch1s1), + .ch2s1 (eg_ch2s1), + .ch3s1 (eg_ch3s1), + .ch4s1 (eg_ch4s1), + .ch5s1 (eg_ch5s1), + + .ch0s2 (eg_ch0s2), + .ch1s2 (eg_ch1s2), + .ch2s2 (eg_ch2s2), + .ch3s2 (eg_ch3s2), + .ch4s2 (eg_ch4s2), + .ch5s2 (eg_ch5s2), + + .ch0s3 (eg_ch0s3), + .ch1s3 (eg_ch1s3), + .ch2s3 (eg_ch2s3), + .ch3s3 (eg_ch3s3), + .ch4s3 (eg_ch4s3), + .ch5s3 (eg_ch5s3), + + .ch0s4 (eg_ch0s4), + .ch1s4 (eg_ch1s4), + .ch2s4 (eg_ch2s4), + .ch3s4 (eg_ch3s4), + .ch4s4 (eg_ch4s4), + .ch5s4 (eg_ch5s4) +); +`endif + +`endif +endmodule diff --git a/src/sound/jt12/jt12_timers.v b/src/sound/jt12/jt12_timers.v new file mode 100644 index 0000000..4fb2bd8 --- /dev/null +++ b/src/sound/jt12/jt12_timers.v @@ -0,0 +1,112 @@ +/* This file is part of JT12. + + JT12 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2017 + + YM3438_APL.pdf + Timer A = 144*(1024-NA)/Phi M + Timer B = 2304*(256-NB)/Phi M + */ + +`timescale 1ns / 1ps + +module jt12_timers( + input clk, + input rst, + input clk_en, // clock enable + input fast_timers, + input [9:0] value_A, + input [7:0] value_B, + input load_A, + input load_B, + input clr_flag_A, + input clr_flag_B, + input enable_irq_A, + input enable_irq_B, + output flag_A, + output flag_B, + output overflow_A, + output irq_n +); + +assign irq_n = ~( (flag_A&enable_irq_A) | (flag_B&enable_irq_B) ); + +jt12_timer #(.mult_width(1), .mult_max(0), .counter_width(10)) +timer_A( + .clk ( clk ), + .rst ( rst ), + .clk_en ( clk_en | fast_timers ), + .start_value( value_A ), + .load ( load_A ), + .clr_flag ( clr_flag_A), + .flag ( flag_A ), + .overflow ( overflow_A) +); + +jt12_timer #(.mult_width(4), .mult_max(15), .counter_width(8)) +timer_B( + .clk ( clk ), + .rst ( rst ), + .clk_en ( clk_en | fast_timers ), + .start_value( value_B ), + .load ( load_B ), + .clr_flag ( clr_flag_B), + .flag ( flag_B ), + .overflow ( ) +); + +endmodule + +module jt12_timer #(parameter counter_width = 10, mult_width=5, mult_max=4 ) +( + input clk, + input rst, +(* direct_enable *) input clk_en, + input [counter_width-1:0] start_value, + input load, + input clr_flag, + output reg flag, + output reg overflow +); + +reg [ mult_width-1:0] mult; +reg [counter_width-1:0] cnt; + +always@(posedge clk) + if( clr_flag || rst) + flag <= 1'b0; + else if(overflow) flag<=1'b1; + +reg [mult_width+counter_width-1:0] next, init; + +always @(*) begin + if( mult. + + Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + + +initial begin + sinetable[5'd0 ] <= 46'b0001100000100100010001000010101010101001010010; + sinetable[5'd1 ] <= 46'b0001100000110100000100000010010001001101000001; + sinetable[5'd2 ] <= 46'b0001100000110100000100110010001011001101100000; + sinetable[5'd3 ] <= 46'b0001110000010000000000110010110001001101110010; + sinetable[5'd4 ] <= 46'b0001110000010000001100000010111010001101101001; + sinetable[5'd5 ] <= 46'b0001110000010100001001100010000000101101111010; + sinetable[5'd6 ] <= 46'b0001110000010100001101100010010011001101011010; + sinetable[5'd7 ] <= 46'b0001110000011100000101010010111000101111111100; + sinetable[5'd8 ] <= 46'b0001110000111000000001110010101110001101110111; + sinetable[5'd9 ] <= 46'b0001110000111000010100111000011101011010100110; + sinetable[5'd10] <= 46'b0001110000111100011000011000111100001001111010; + sinetable[5'd11] <= 46'b0001110000111100011100111001101011001001110111; + sinetable[5'd12] <= 46'b0100100001010000010001011001001000111010110111; + sinetable[5'd13] <= 46'b0100100001010100010001001001110001111100101010; + sinetable[5'd14] <= 46'b0100100001010100010101101101111110100101000110; + sinetable[5'd15] <= 46'b0100100011100000001000011001010110101101111001; + sinetable[5'd16] <= 46'b0100100011100100001000101011100101001011101111; + sinetable[5'd17] <= 46'b0100100011101100000111011010000001011010110001; + sinetable[5'd18] <= 46'b0100110011001000000111101010000010111010111111; + sinetable[5'd19] <= 46'b0100110011001100001011011110101110110110000001; + sinetable[5'd20] <= 46'b0100110011101000011010111011001010001101110001; + sinetable[5'd21] <= 46'b0100110011101101011010110101111001010100001111; + sinetable[5'd22] <= 46'b0111000010000001010111000101010101010110010111; + sinetable[5'd23] <= 46'b0111000010000101010111110111110101010010111011; + sinetable[5'd24] <= 46'b0111000010110101101000101100001000010000011001; + sinetable[5'd25] <= 46'b0111010010011001100100011110100100010010010010; + sinetable[5'd26] <= 46'b0111010010111010100101100101000000110100100011; + sinetable[5'd27] <= 46'b1010000010011010101101011101100001110010011010; + sinetable[5'd28] <= 46'b1010000010111111111100100111010100010000111001; + sinetable[5'd29] <= 46'b1010010111110100110010001100111001010110100000; + sinetable[5'd30] <= 46'b1011010111010011111011011110000100110010100001; + sinetable[5'd31] <= 46'b1110011011110001111011100111100001110110100111; + + explut_jt51[0] <= 45'b111110101011010110001011010000010010111011011; + explut_jt51[1] <= 45'b111101010011010101000011001100101110110101011; + explut_jt51[2] <= 45'b111011111011010011110111001000110010101110011; + explut_jt51[3] <= 45'b111010100101010010101111000100110010101000011; + explut_jt51[4] <= 45'b111001001101010001100111000000110010100001011; + explut_jt51[5] <= 45'b110111111011010000011110111101010010011011011; + explut_jt51[6] <= 45'b110110100011001111010110111001010010010100100; + explut_jt51[7] <= 45'b110101001011001110001110110101110010001110011; + explut_jt51[8] <= 45'b110011111011001101000110110001110010001000011; + explut_jt51[9] <= 45'b110010100011001011111110101110010010000010011; + explut_jt51[10] <= 45'b110001010011001010111010101010010001111011011; + explut_jt51[11] <= 45'b101111111011001001110010100110110001110101011; + explut_jt51[12] <= 45'b101110101011001000101010100011001101101111011; + explut_jt51[13] <= 45'b101101010101000111100110011111010001101001011; + explut_jt51[14] <= 45'b101100000011000110100010011011110001100011011; + explut_jt51[15] <= 45'b101010110011000101011110011000010001011101011; + explut_jt51[16] <= 45'b101001100011000100011010010100101101010111011; + explut_jt51[17] <= 45'b101000010011000011010010010001001101010001011; + explut_jt51[18] <= 45'b100111000011000010010010001101101101001011011; + explut_jt51[19] <= 45'b100101110011000001001110001010001101000101011; + explut_jt51[20] <= 45'b100100100011000000001010000110010000111111011; + explut_jt51[21] <= 45'b100011010010111111001010000011001100111001011; + explut_jt51[22] <= 45'b100010000010111110000101111111101100110011011; + explut_jt51[23] <= 45'b100000110010111101000001111100001100101101011; + explut_jt51[24] <= 45'b011111101010111100000001111000101100101000010; + explut_jt51[25] <= 45'b011110011010111011000001110101001100100010011; + explut_jt51[26] <= 45'b011101001010111010000001110001110000011100011; + explut_jt51[27] <= 45'b011100000010111001000001101110010000010110011; + explut_jt51[28] <= 45'b011010110010111000000001101011001100010001011; + explut_jt51[29] <= 45'b011001101010110111000001100111101100001011011; + explut_jt51[30] <= 45'b011000100000110110000001100100010000000110010; + explut_jt51[31] <= 45'b010111010010110101000001100001001100000000011; +end diff --git a/src/sound/turbosound.sv b/src/sound/turbosound.sv new file mode 100644 index 0000000..876eb99 --- /dev/null +++ b/src/sound/turbosound.sv @@ -0,0 +1,137 @@ +//============================================================================ +// Turbosound-FM +// +// Copyright (C) 2018 Ilia Sharin +// Copyright (C) 2018 Sorgelig +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +//============================================================================ + + +module turbosound +( + input RESET, // Chip RESET (set all Registers to '0', active high) + + input CLK, // Global clock + input CE_CPU, // CPU Clock enable + input CE_YM, // YM2203 Master Clock enable x2 (due to YM2612 model!) + input BDIR, // Bus Direction (0 - read , 1 - write) + input BC, // Bus control + input [7:0] DI, // Data In + output [7:0] DO, // Data Out + output [11:0] CHANNEL_L, // Output channel L + output [11:0] CHANNEL_R, // Output channel R + output ACTIVE +); + +// AY1 selected by default +reg ay_select = 1; +reg stat_sel = 1; +reg fm_ena = 0; + +always_ff @(posedge CLK or posedge RESET) begin + if (RESET) begin + ay_select <= 1; + stat_sel <= 1; + fm_ena <= 0; + end + else if (BDIR & BC & &DI[7:3]) begin + ay_select <= DI[0]; + stat_sel <= DI[1]; + fm_ena <= ~DI[2]; + end +end + +wire [7:0] psg_ch_a_0; +wire [7:0] psg_ch_b_0; +wire [7:0] psg_ch_c_0; +wire [10:0] opn_0; +wire [7:0] DO_0; + +wire WE_0 = ~ay_select & BDIR; +wire ay0_playing; + +ym2203 ym2203_0 +( + .RESET(RESET), + .CLK(CLK), + .CE_CPU(CE_CPU), + .CE_YM(CE_YM), + + .A0(WE_0 ? ~BC : stat_sel), + .WE(WE_0), + .DI(DI), + .DO(DO_0), + + .CHANNEL_A(psg_ch_a_0), + .CHANNEL_B(psg_ch_b_0), + .CHANNEL_C(psg_ch_c_0), + .CHANNEL_FM(opn_0), + + .PSG_ACTIVE(ay0_playing), + .FM_ENA(fm_ena) +); + +wire [7:0] psg_ch_a_1; +wire [7:0] psg_ch_b_1; +wire [7:0] psg_ch_c_1; +wire [10:0] opn_1; +wire [7:0] DO_1; + +wire WE_1 = ay_select & BDIR; +wire ay1_playing; + +ym2203 ym2203_1 +( + .RESET(RESET), + .CLK(CLK), + .CE_CPU(CE_CPU), + .CE_YM(CE_YM), + + .A0(WE_1 ? ~BC : stat_sel), + .WE(WE_1), + .DI(DI), + .DO(DO_1), + + .CHANNEL_A(psg_ch_a_1), + .CHANNEL_B(psg_ch_b_1), + .CHANNEL_C(psg_ch_c_1), + .CHANNEL_FM(opn_1), + + .PSG_ACTIVE(ay1_playing), + .FM_ENA(fm_ena) +); + +assign DO = ay_select ? DO_1 : DO_0; +assign ACTIVE = ay0_playing | ay1_playing | fm_ena; + +// Mix channel signals from both AY/YM chips (extending to 9 bits width to prevent clipping) +wire [8:0] sum_ch_a = { 1'b0, psg_ch_a_1 } + { 1'b0, psg_ch_a_0 }; +wire [8:0] sum_ch_b = { 1'b0, psg_ch_b_1 } + { 1'b0, psg_ch_b_0 }; +wire [8:0] sum_ch_c = { 1'b0, psg_ch_c_1 } + { 1'b0, psg_ch_c_0 }; + +// Control output channels (Only AY_1 plays if not in TurboSound mode) +wire [7:0] psg_a = ~ay0_playing ? psg_ch_a_1 : sum_ch_a[8:1]; +wire [7:0] psg_b = ~ay0_playing ? psg_ch_b_1 : sum_ch_b[8:1]; +wire [7:0] psg_c = ~ay0_playing ? psg_ch_c_1 : sum_ch_c[8:1]; + +wire signed [11:0] psg_l = {3'b000, psg_a, 1'd0} + {4'b0000, psg_b}; +wire signed [11:0] psg_r = {3'b000, psg_c, 1'd0} + {4'b0000, psg_b}; +wire signed [11:0] opn_s = {{2{opn_0[10]}}, opn_0[10:1]} + {{2{opn_1[10]}}, opn_1[10:1]}; + +assign CHANNEL_L = fm_ena ? opn_s + psg_l : psg_l; +assign CHANNEL_R = fm_ena ? opn_s + psg_r : psg_r; + +endmodule diff --git a/src/sound/turbosound.vhd b/src/sound/turbosound.vhd deleted file mode 100644 index bb500f0..0000000 --- a/src/sound/turbosound.vhd +++ /dev/null @@ -1,78 +0,0 @@ --------------------------------------------------------------------[07.09.2013] --- TurboSound -------------------------------------------------------------------------------- --- V0.1 15.10.2011 Initial version - -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; - -entity turbosound is -port( - RESET : in std_logic; - CLK : in std_logic; - ENA : in std_logic; - A : in std_logic_vector(15 downto 0); - DI : in std_logic_vector(7 downto 0); - WR_n : in std_logic; - IORQ_n : in std_logic; - M1_n : in std_logic; - SEL : out std_logic; - CN0_DO : out std_logic_vector(7 downto 0); - CN0_A : out std_logic_vector(7 downto 0); - CN0_B : out std_logic_vector(7 downto 0); - CN0_C : out std_logic_vector(7 downto 0); - CN1_DO : out std_logic_vector(7 downto 0); - CN1_A : out std_logic_vector(7 downto 0); - CN1_B : out std_logic_vector(7 downto 0); - CN1_C : out std_logic_vector(7 downto 0)); -end turbosound; - -architecture turbosound_arch of turbosound is - signal bc1 : std_logic; - signal bdir : std_logic; - signal ssg : std_logic; -begin - bc1 <= '1' when (IORQ_n = '0' and A(15) = '1' and A(1) = '0' and M1_n = '1' and A(14) = '1') else '0'; - bdir <= '1' when (IORQ_n = '0' and A(15) = '1' and A(1) = '0' and M1_n = '1' and WR_n = '0') else '0'; - SEL <= ssg; - - process(CLK, RESET) - begin - if (RESET = '1') then - ssg <= '0'; - elsif (CLK'event and CLK = '1') then - if (DI(7 downto 1) = "1111111" and bdir = '1' and bc1 = '1') then - ssg <= DI(0); - end if; - end if; - end process; - -ssg0_unit: entity work.ay8910(rtl) - port map( - RESET => RESET, - CLK => CLK, - DI => DI, - DO => CN0_DO, - ENA => ENA, - CS => not ssg, - BDIR => bdir, - BC => bc1, - OUT_A => CN0_A, - OUT_B => CN0_B, - OUT_C => CN0_C); - -ssg1_unit: entity work.ay8910(rtl) - port map( - RESET => RESET, - CLK => CLK, - DI => DI, - DO => CN1_DO, - ENA => ENA, - CS => ssg, - BDIR => bdir, - BC => bc1, - OUT_A => CN1_A, - OUT_B => CN1_B, - OUT_C => CN1_C); -end turbosound_arch; \ No newline at end of file diff --git a/src/sound/ym2149.sv b/src/sound/ym2149.sv new file mode 100644 index 0000000..4281952 --- /dev/null +++ b/src/sound/ym2149.sv @@ -0,0 +1,354 @@ +// +// Copyright (c) MikeJ - Jan 2005 +// Copyright (c) 2016-2018 Sorgelig +// +// All rights reserved +// +// Redistribution and use in source and synthezised forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// Redistributions in synthesized form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// + + +// BDIR BC MODE +// 0 0 inactive +// 0 1 read value +// 1 0 write value +// 1 1 set address +// +// Registers description +// R0, R1, R2, R4, R4, R5 - Tone Generator Control +// R6 - Noise Generator Control +// R7 - Mixer Control-I/O Enable +// R10, R11, R12 - Amplitude Control +// R13, R14, R15 - Envelope Generator Control +// R13, R14 - Envelope Period Control +// R15 - Envelope Shape/Cycle Control + +module ym2149 +( + input CLK, // Global clock + input CE, // PSG Clock enable + input RESET, // Chip RESET (set all Registers to '0', active hi) + input BDIR, // Bus Direction (0 - read , 1 - write) + input BC, // Bus control + input [7:0] DI, // Data In + output [7:0] DO, // Data Out + output [7:0] CHANNEL_A, // PSG Output channel A + output [7:0] CHANNEL_B, // PSG Output channel B + output [7:0] CHANNEL_C, // PSG Output channel C + + input SEL, + input MODE, + + output [5:0] ACTIVE, + + input [7:0] IOA_in, + output [7:0] IOA_out, + + input [7:0] IOB_in, + output [7:0] IOB_out +); + +assign ACTIVE = ~ymreg[7][5:0]; + +assign IOA_out = ymreg[14]; +assign IOB_out = ymreg[15]; + +reg ena_div; +reg ena_div_noise; +reg [7:0] addr; +reg [7:0] ymreg[16]; +reg env_ena; +reg [4:0] env_vol; + +wire [7:0] volTableAy[16] = + '{8'h00, 8'h03, 8'h04, 8'h06, + 8'h0a, 8'h0f, 8'h15, 8'h22, + 8'h28, 8'h41, 8'h5b, 8'h72, + 8'h90, 8'hb5, 8'hd7, 8'hff + }; + +wire [7:0] volTableYm[32] = + '{8'h00, 8'h01, 8'h01, 8'h02, + 8'h02, 8'h03, 8'h03, 8'h04, + 8'h06, 8'h07, 8'h09, 8'h0a, + 8'h0c, 8'h0e, 8'h11, 8'h13, + 8'h17, 8'h1b, 8'h20, 8'h25, + 8'h2c, 8'h35, 8'h3e, 8'h47, + 8'h54, 8'h66, 8'h77, 8'h88, + 8'ha1, 8'hc0, 8'he0, 8'hff + }; + +// Read from AY +assign DO = dout; +reg [7:0] dout; +always_comb begin + if(addr[7:4]) dout <= 8'hFF; + else begin + case(addr[3:0]) + 0: dout = ymreg[0]; + 1: dout = ymreg[1][3:0]; + 2: dout = ymreg[2]; + 3: dout = ymreg[3][3:0]; + 4: dout = ymreg[4]; + 5: dout = ymreg[5][3:0]; + 6: dout = ymreg[6][4:0]; + 7: dout = ymreg[7]; + 8: dout = ymreg[8][4:0]; + 9: dout = ymreg[9][4:0]; + 10: dout = ymreg[10][4:0]; + 11: dout = ymreg[11]; + 12: dout = ymreg[12]; + 13: dout = ymreg[13][3:0]; + 14: dout = (ymreg[7][6] ? ymreg[14] : IOA_in); + 15: dout = (ymreg[7][7] ? ymreg[15] : IOB_in); + endcase + end +end + +// p_divider +always @(posedge CLK) begin + reg [3:0] cnt_div; + reg noise_div; + + if(CE) begin + ena_div <= 0; + ena_div_noise <= 0; + if(!cnt_div) begin + cnt_div <= {SEL, 3'b111}; + ena_div <= 1; + + noise_div <= (~noise_div); + if (noise_div) ena_div_noise <= 1; + end else begin + cnt_div <= cnt_div - 1'b1; + end + end +end + + +reg noise_gen_op; + +// p_noise_gen +always @(posedge CLK) begin + reg [16:0] poly17; + reg [4:0] noise_gen_cnt; + + if(CE) begin + if (ena_div_noise) begin + if(ymreg[6][4:0]) begin + if (noise_gen_cnt >= ymreg[6][4:0] - 1'd1) begin + noise_gen_cnt <= 0; + poly17 <= {(poly17[0] ^ poly17[2] ^ !poly17), poly17[16:1]}; + end else begin + noise_gen_cnt <= noise_gen_cnt + 1'd1; + end + noise_gen_op <= poly17[0]; + end else begin + noise_gen_op <= 0; + noise_gen_cnt <= 0; + end + end + end +end + +wire [11:0] tone_gen_freq[1:3]; +assign tone_gen_freq[1] = {ymreg[1][3:0], ymreg[0]}; +assign tone_gen_freq[2] = {ymreg[3][3:0], ymreg[2]}; +assign tone_gen_freq[3] = {ymreg[5][3:0], ymreg[4]}; + +reg [3:1] tone_gen_op; + +//p_tone_gens +always @(posedge CLK) begin + integer i; + reg [11:0] tone_gen_cnt[1:3]; + + if(CE) begin + // looks like real chips count up - we need to get the Exact behaviour .. + + for (i = 1; i <= 3; i = i + 1) begin + if(ena_div) begin + if (tone_gen_freq[i]) begin + if (tone_gen_cnt[i] >= (tone_gen_freq[i] - 1'd1)) begin + tone_gen_cnt[i] <= 0; + tone_gen_op[i] <= ~tone_gen_op[i]; + end else begin + tone_gen_cnt[i] <= tone_gen_cnt[i] + 1'd1; + end + end else begin + tone_gen_op[i] <= 0; + tone_gen_cnt[i] <= 0; + end + end + end + end +end + +wire [15:0] env_gen_comp = {ymreg[12], ymreg[11]} ? {ymreg[12], ymreg[11]} - 1'd1 : 16'd0; + +//p_envelope_freq +always @(posedge CLK) begin + reg [15:0] env_gen_cnt; + + if(CE) begin + env_ena <= 0; + if(ena_div) begin + if (env_gen_cnt >= env_gen_comp) begin + env_gen_cnt <= 0; + env_ena <= 1; + end else begin + env_gen_cnt <= (env_gen_cnt + 1'd1); + end + end + end +end + +wire is_bot = (env_vol == 5'b00000); +wire is_bot_p1 = (env_vol == 5'b00001); +wire is_top_m1 = (env_vol == 5'b11110); +wire is_top = (env_vol == 5'b11111); + +always @(posedge CLK) begin + reg old_BDIR; + reg env_reset; + reg env_hold; + reg env_inc; + + // envelope shapes + // C AtAlH + // 0 0 x x \___ + // + // 0 1 x x /___ + // + // 1 0 0 0 \\\\ + // + // 1 0 0 1 \___ + // + // 1 0 1 0 \/\/ + // ___ + // 1 0 1 1 \ + // + // 1 1 0 0 //// + // ___ + // 1 1 0 1 / + // + // 1 1 1 0 /\/\ + // + // 1 1 1 1 /___ + + if(RESET) begin + ymreg[0] <= '0; + ymreg[1] <= '0; + ymreg[2] <= '0; + ymreg[3] <= '0; + ymreg[4] <= '0; + ymreg[5] <= '0; + ymreg[6] <= '0; + ymreg[7] <= '1; + ymreg[8] <= '0; + ymreg[9] <= '0; + ymreg[10] <= '0; + ymreg[11] <= '0; + ymreg[12] <= '0; + ymreg[13] <= '0; + ymreg[14] <= '0; + ymreg[15] <= '0; + addr <= '0; + env_vol <= '0; + end else begin + old_BDIR <= BDIR; + if(~old_BDIR & BDIR) begin + if(BC) addr <= DI; + else if(!addr[7:4])begin + ymreg[addr[3:0]] <= DI; + env_reset <= (addr == 13); + end + end + end + + if(CE) begin + if(env_reset) begin + env_reset <= 0; + // load initial state + if(!ymreg[13][2]) begin // attack + env_vol <= 5'b11111; + env_inc <= 0; // -1 + end else begin + env_vol <= 5'b00000; + env_inc <= 1; // +1 + end + env_hold <= 0; + end else begin + + if (env_ena) begin + if (!env_hold) begin + if (env_inc) env_vol <= (env_vol + 5'b00001); + else env_vol <= (env_vol + 5'b11111); + end + + // envelope shape control. + if(!ymreg[13][3]) begin + if(!env_inc) begin // down + if(is_bot_p1) env_hold <= 1; + end else if (is_top) env_hold <= 1; + end else if(ymreg[13][0]) begin // hold = 1 + if(!env_inc) begin // down + if(ymreg[13][1]) begin // alt + if(is_bot) env_hold <= 1; + end else if(is_bot_p1) env_hold <= 1; + end else if(ymreg[13][1]) begin // alt + if(is_top) env_hold <= 1; + end else if(is_top_m1) env_hold <= 1; + end else if(ymreg[13][1]) begin // alternate + if(env_inc == 1'b0) begin // down + if(is_bot_p1) env_hold <= 1; + if(is_bot) begin + env_hold <= 0; + env_inc <= 1; + end + end else begin + if(is_top_m1) env_hold <= 1; + if(is_top) begin + env_hold <= 0; + env_inc <= 0; + end + end + end + end + end + end +end + +wire [4:0] A = ~((ymreg[7][0] | tone_gen_op[1]) & (ymreg[7][3] | noise_gen_op)) ? 5'd0 : ymreg[8][4] ? env_vol[4:0] : { ymreg[8][3:0], ymreg[8][3]}; +wire [4:0] B = ~((ymreg[7][1] | tone_gen_op[2]) & (ymreg[7][4] | noise_gen_op)) ? 5'd0 : ymreg[9][4] ? env_vol[4:0] : { ymreg[9][3:0], ymreg[9][3]}; +wire [4:0] C = ~((ymreg[7][2] | tone_gen_op[3]) & (ymreg[7][5] | noise_gen_op)) ? 5'd0 : ymreg[10][4] ? env_vol[4:0] : {ymreg[10][3:0], ymreg[10][3]}; + +assign CHANNEL_A = MODE ? volTableAy[A[4:1]] : volTableYm[A]; +assign CHANNEL_B = MODE ? volTableAy[B[4:1]] : volTableYm[B]; +assign CHANNEL_C = MODE ? volTableAy[C[4:1]] : volTableYm[C]; + +endmodule diff --git a/src/sound/ym2203.sv b/src/sound/ym2203.sv new file mode 100644 index 0000000..e9ca0a4 --- /dev/null +++ b/src/sound/ym2203.sv @@ -0,0 +1,130 @@ +//============================================================================ +// YM2203 wrapper +// Copyright (C) 2018 Sorgelig +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +//============================================================================ + + +module ym2203 +( + input RESET, + input CLK, // Global clock + input CE_CPU, // CPU Clock enable + input CE_YM, // YM2203 Master Clock enable x2 (due to YM2612 model!) + + input A0, // 0 - register number/read FM, 1 - data/read PSG + input WE, // 0 - read , 1 - write + input [7:0] DI, // Data In + output [7:0] DO, // Data Out + + output [7:0] CHANNEL_A, // PSG Output channel A + output [7:0] CHANNEL_B, // PSG Output channel B + output [7:0] CHANNEL_C, // PSG Output channel C + output [10:0] CHANNEL_FM,// FM Output channel + + output PSG_ACTIVE, + input FM_ENA +); + +reg [7:0] ymreg; +reg [1:0] pres; + +always @(posedge CLK) begin + + if(RESET) pres <= 2; + else if(CE_CPU & WE) begin + if(FM_ENA) begin + if(~A0) ymreg <= DI; + else begin + case(ymreg) + 'h2d: pres[1] <= 1; + 'h2e: pres[0] <= 1; + 'h2f: pres <= 0; + endcase + end + end + end +end + +wire [2:0] opn_tbl[4] = '{1,1,5,2}; +wire [2:0] opn_pres = opn_tbl[pres]; + +wire [2:0] psg_tbl[4] = '{0,0,3,1}; +wire [2:0] psg_pres = psg_tbl[pres]; + +reg ce_psg_pre, ce_opn_pre; +always @(posedge CLK) begin + reg [2:0] div_psg, div_opn; + + {ce_opn_pre, ce_psg_pre} <= 0; + + if(RESET) {div_opn, div_psg} <= 0; + else if (CE_YM) begin + div_opn <= div_opn + 1'd1; + if(div_opn >= opn_pres) div_opn <= 0; + ce_opn_pre <= !div_opn; + + div_psg <= div_psg + 1'd1; + if(div_psg >= psg_pres) div_psg <= 0; + ce_psg_pre <= !div_psg; + end +end + +reg ce_opn, ce_psg; +always @(negedge CLK) {ce_opn, ce_psg} <= {ce_opn_pre, ce_psg_pre}; + +wire [5:0] psg_active; +wire [7:0] psg_dout; +ym2149 ym2149 +( + .CLK(CLK), + .CE(ce_psg), + .RESET(RESET), + .BDIR(WE), + .BC(~A0), + .DI(DI), + .DO(psg_dout), + .CHANNEL_A(CHANNEL_A), + .CHANNEL_B(CHANNEL_B), + .CHANNEL_C(CHANNEL_C), + .ACTIVE(psg_active), + .SEL(1'b0), + .MODE(1'b0) +); + +wire [7:0] opn_dout; +wire [11:0] opn_audio; +jt12 jt12 +( + .rst(RESET), + + .cpu_clk(CLK & CE_CPU), + .cpu_din(DI), + .cpu_dout(opn_dout), + .cpu_addr({1'b0,A0}), + .cpu_cs_n(~FM_ENA), + .cpu_wr_n(~WE), + + .syn_clk(CLK & ce_opn), + .cpu_limiter_en(1'b1), + .syn_snd_right(opn_audio) +); + +assign DO = A0 ? psg_dout : opn_dout; +assign PSG_ACTIVE = |psg_active; +assign CHANNEL_FM = opn_audio[10:0]; + +endmodule diff --git a/src/tsconf.v b/src/tsconf.v index 4484150..7c6d676 100644 --- a/src/tsconf.v +++ b/src/tsconf.v @@ -158,7 +158,6 @@ wire dram_rnw; // Port reg [7:0] port_xxfe_reg; reg [7:0] port_xx01_reg; -reg ena_1_75mhz; reg [5:0] ena_cnt; // System wire reset; @@ -184,16 +183,6 @@ wire [7:0] covox_a; wire [7:0] covox_b; wire [7:0] covox_c; wire [7:0] covox_d; -// TurboSound -wire ssg_sel; -wire [7:0] ssg_cn0_bus; -wire [7:0] ssg_cn0_a; -wire [7:0] ssg_cn0_b; -wire [7:0] ssg_cn0_c; -wire [7:0] ssg_cn1_bus; -wire [7:0] ssg_cn1_a; -wire [7:0] ssg_cn1_b; -wire [7:0] ssg_cn1_c; // clock wire f0; wire f1; @@ -865,28 +854,38 @@ soundrive SE10 .outd(covox_d) ); -// TurboSound +reg ce_ym, ce_cpu; +always @(posedge clk_28mhz) begin + reg [1:0] div; + + div <= div + 1'd1; + ce_ym <= !div; + + ce_cpu <= zclk; + if(ce_cpu) ce_cpu <= 0; +end + +wire ts_enable = cpu_a_bus[0] & cpu_a_bus[15] & ~cpu_a_bus[1]; +wire ts_we = ts_enable & ~cpu_iorq_n & ~cpu_wr_n; + +wire [11:0] ts_l, ts_r; +wire [7:0] ts_do; + turbosound SE12 -( - .reset(reset), - .clk(clk_28mhz), - .ena(ena_1_75mhz), - .a(cpu_a_bus), - .di(cpu_do_bus), - .wr_n(cpu_wr_n), - .iorq_n(cpu_iorq_n), - .m1_n(cpu_m1_n), - .sel(ssg_sel), - .cn0_do(ssg_cn0_bus), - .cn0_a(ssg_cn0_a), - .cn0_b(ssg_cn0_b), - .cn0_c(ssg_cn0_c), - .cn1_do(ssg_cn1_bus), - .cn1_a(ssg_cn1_a), - .cn1_b(ssg_cn1_b), - .cn1_c(ssg_cn1_c) -); - +( + .RESET(reset), + + .CLK(clk_28mhz), + .CE_CPU(ce_cpu), + .CE_YM(ce_ym), + .BDIR(ts_we), + .BC(cpu_a_bus[14]), + .DI(cpu_do_bus), + .DO(ts_do), + .CHANNEL_L(ts_l), + .CHANNEL_R(ts_r) +); + always @(posedge clk_84mhz) begin ce_gs <= clk_28mhz; if(ce_gs) ce_gs <= 0; @@ -937,7 +936,6 @@ assign RESET_OUT = reset; always @(negedge clk_28mhz) begin ena_cnt <= ena_cnt + 1'd1; - ena_1_75mhz <= ~ena_cnt[3] & ena_cnt[2] & ena_cnt[1] & ena_cnt[0]; ena_0_4375mhz <= ~ena_cnt[5] & ena_cnt[4] & ena_cnt[3] & ena_cnt[2] & ena_cnt[1] & ena_cnt[0]; end @@ -953,8 +951,7 @@ assign cpu_di_bus = (loader && ~cpu_mreq_n && ~cpu_rd_n && !cpu_a_bus[15:13]) ? (intack) ? im2vect : (~cpu_iorq_n && ~cpu_rd_n && port_bff7 && port_eff7_reg[7]) ? mc146818a_do_bus : // MC146818A (gs_sel && ~cpu_rd_n) ? gs_do_bus : // General Sound - (~cpu_iorq_n && ~cpu_rd_n && cpu_a_bus == 16'hFFFD && ~ssg_sel) ? ssg_cn0_bus : // TurboSound - (~cpu_iorq_n && ~cpu_rd_n && cpu_a_bus == 16'hFFFD && ssg_sel) ? ssg_cn1_bus : + (~cpu_iorq_n && ~cpu_rd_n && ts_enable) ? ts_do : // TurboSound (~cpu_iorq_n && ~cpu_rd_n && cpu_a_bus == 16'h0001) ? key_scancode : (ena_ports) ? dout_ports : 8'b11111111; @@ -993,7 +990,7 @@ assign port_bff7 = ~cpu_iorq_n && cpu_a_bus == 16'hBFF7 && cpu_m1_n && port_eff7 // SAA1099 assign saa_wr_n = ~cpu_iorq_n && ~cpu_wr_n && cpu_a_bus[7:0] == 8'hFF && ~dos; -assign SOUND_L = ({3'b000, port_xxfe_reg[4], 12'b000000000000}) + ({3'b000, ssg_cn0_a, 5'b00000}) + ({4'b0000, ssg_cn0_b, 4'b0000}) + ({3'b000, ssg_cn1_a, 5'b00000}) + ({4'b0000, ssg_cn1_b, 4'b0000}) + ({2'b00, covox_a, 6'b000000}) + ({2'b00, covox_b, 6'b000000}) + ({gs_l[14], gs_l}) + ({1'b0, saa_out_l, 7'b0000000}); -assign SOUND_R = ({3'b000, port_xxfe_reg[4], 12'b000000000000}) + ({3'b000, ssg_cn0_c, 5'b00000}) + ({4'b0000, ssg_cn0_b, 4'b0000}) + ({3'b000, ssg_cn1_c, 5'b00000}) + ({4'b0000, ssg_cn1_b, 4'b0000}) + ({2'b00, covox_c, 6'b000000}) + ({2'b00, covox_d, 6'b000000}) + ({gs_r[14], gs_r}) + ({1'b0, saa_out_r, 7'b0000000}); - +assign SOUND_L = {ts_l, 4'b0000} + {gs_l[14], gs_l} + {2'b00, covox_a, 6'b000000} + {2'b00, covox_b, 6'b000000} + {1'b0, saa_out_l, 7'b0000000} + {3'b000, port_xxfe_reg[4], 12'b000000000000}; +assign SOUND_R = {ts_r, 4'b0000} + {gs_r[14], gs_r} + {2'b00, covox_c, 6'b000000} + {2'b00, covox_d, 6'b000000} + {1'b0, saa_out_r, 7'b0000000} + {3'b000, port_xxfe_reg[4], 12'b000000000000}; + endmodule