|
---------------------------------------------------------------------------
|
|
-- (c) 2020 mark watson
|
|
-- I am happy for anyone to use this for non-commercial use.
|
|
-- If my vhdl files are used commercially or otherwise sold,
|
|
-- please contact me for explicit permission at scrameta (gmail).
|
|
-- This applies for source and binary form and derived works.
|
|
---------------------------------------------------------------------------
|
|
|
|
LIBRARY ieee;
|
|
USE ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
|
|
use IEEE.STD_LOGIC_MISC.all;
|
|
|
|
LIBRARY work;
|
|
|
|
ENTITY sample_top IS
|
|
PORT
|
|
(
|
|
CLK : in std_logic;
|
|
RESET_N : in std_logic;
|
|
|
|
ENABLE : in std_logic; -- end of cycle
|
|
REQUEST : in std_logic; -- read request, provide data next cycle
|
|
|
|
WRITE_ENABLE : in std_logic;
|
|
ADDR : in std_logic_vector(4 downto 0);
|
|
DI : in std_logic_vector(7 downto 0);
|
|
|
|
DO : out std_logic_vector(7 downto 0);
|
|
AUDIO0 : out std_logic_vector(15 downto 0);
|
|
AUDIO1 : out std_logic_vector(15 downto 0);
|
|
IRQ : out std_logic;
|
|
|
|
RAM_ADDR : out std_logic_vector(15 downto 0);
|
|
RAM_WRITE_ENABLE : out std_logic;
|
|
RAM_DATA : in std_logic_vector(7 downto 0); -- next cycle: TODO, what if we use rom?
|
|
|
|
ADPCM_STEP_ADDR : out std_logic_vector(6 downto 0);
|
|
ADPCM_STEP_REQUEST : out std_logic;
|
|
ADPCM_STEP_READY : in std_logic;
|
|
ADPCM_STEP_VALUE : in std_logic_vector(14 downto 0)
|
|
);
|
|
END sample_top;
|
|
|
|
ARCHITECTURE vhdl OF sample_top IS
|
|
signal CH1_REG : std_logic_vector(12 downto 0);
|
|
signal CH0_REG : std_logic_vector(12 downto 0);
|
|
signal CH1_NEXT : std_logic_vector(12 downto 0);
|
|
signal CH0_NEXT : std_logic_vector(12 downto 0);
|
|
signal CH3_REG : std_logic_vector(12 downto 0);
|
|
signal CH2_REG : std_logic_vector(12 downto 0);
|
|
signal CH3_NEXT : std_logic_vector(12 downto 0);
|
|
signal CH2_NEXT : std_logic_vector(12 downto 0);
|
|
|
|
signal ram_cpu_addr_next : std_logic_vector(15 downto 0);
|
|
signal ram_cpu_addr_reg : std_logic_vector(15 downto 0);
|
|
signal ram_cpu_write_enable : std_logic;
|
|
|
|
signal ch0_start_addr_reg : std_logic_vector(15 downto 0);
|
|
signal ch0_start_addr_next : std_logic_vector(15 downto 0);
|
|
signal ch0_len_reg : std_logic_vector(15 downto 0);
|
|
signal ch0_len_next : std_logic_vector(15 downto 0);
|
|
signal ch0_period_reg : std_logic_vector(11 downto 0);
|
|
signal ch0_period_next : std_logic_vector(11 downto 0);
|
|
signal ch0_volume_reg : std_logic_vector(5 downto 0);
|
|
signal ch0_volume_next : std_logic_vector(5 downto 0);
|
|
|
|
signal ch1_start_addr_reg : std_logic_vector(15 downto 0);
|
|
signal ch1_start_addr_next : std_logic_vector(15 downto 0);
|
|
signal ch1_len_reg : std_logic_vector(15 downto 0);
|
|
signal ch1_len_next : std_logic_vector(15 downto 0);
|
|
signal ch1_period_reg : std_logic_vector(11 downto 0);
|
|
signal ch1_period_next : std_logic_vector(11 downto 0);
|
|
signal ch1_volume_reg : std_logic_vector(5 downto 0);
|
|
signal ch1_volume_next : std_logic_vector(5 downto 0);
|
|
|
|
signal ch2_start_addr_reg : std_logic_vector(15 downto 0);
|
|
signal ch2_start_addr_next : std_logic_vector(15 downto 0);
|
|
signal ch2_len_reg : std_logic_vector(15 downto 0);
|
|
signal ch2_len_next : std_logic_vector(15 downto 0);
|
|
signal ch2_period_reg : std_logic_vector(11 downto 0);
|
|
signal ch2_period_next : std_logic_vector(11 downto 0);
|
|
signal ch2_volume_reg : std_logic_vector(5 downto 0);
|
|
signal ch2_volume_next : std_logic_vector(5 downto 0);
|
|
|
|
signal ch3_start_addr_reg : std_logic_vector(15 downto 0);
|
|
signal ch3_start_addr_next : std_logic_vector(15 downto 0);
|
|
signal ch3_len_reg : std_logic_vector(15 downto 0);
|
|
signal ch3_len_next : std_logic_vector(15 downto 0);
|
|
signal ch3_period_reg : std_logic_vector(11 downto 0);
|
|
signal ch3_period_next : std_logic_vector(11 downto 0);
|
|
signal ch3_volume_reg : std_logic_vector(5 downto 0);
|
|
signal ch3_volume_next : std_logic_vector(5 downto 0);
|
|
|
|
signal dma_on_reg : std_logic_vector(3 downto 0);
|
|
signal dma_on_next : std_logic_vector(3 downto 0);
|
|
signal dma_on : std_logic;
|
|
signal channel_reg : std_logic_vector(2 downto 0);
|
|
signal channel_next : std_logic_vector(2 downto 0);
|
|
signal ch0_addr : std_logic_vector(16 downto 0);
|
|
signal ch1_addr : std_logic_vector(16 downto 0);
|
|
signal ch2_addr : std_logic_vector(16 downto 0);
|
|
signal ch3_addr : std_logic_vector(16 downto 0);
|
|
|
|
signal irq_en_reg : std_logic_vector(3 downto 0);
|
|
signal irq_en_next : std_logic_vector(3 downto 0);
|
|
signal irq_trigger : std_logic_vector(3 downto 0);
|
|
signal data_request : std_logic_vector(3 downto 0);
|
|
signal irq_clear_n : std_logic_vector(3 downto 0);
|
|
signal irq_active_reg : std_logic_vector(3 downto 0);
|
|
signal irq_active_next : std_logic_vector(3 downto 0);
|
|
|
|
signal adpcm_decoded : std_logic_vector(15 downto 0);
|
|
signal adpcm_reg : std_logic_vector(3 downto 0);
|
|
signal adpcm_next : std_logic_vector(3 downto 0);
|
|
signal adpcm_data_request : std_logic;
|
|
signal adpcm_data_ready_next : std_logic;
|
|
signal adpcm_data_ready_reg : std_logic;
|
|
signal adpcm_data_in : std_logic_vector(3 downto 0);
|
|
signal adpcm_on : std_logic;
|
|
signal adpcm_channel : std_logic_vector(1 downto 0);
|
|
signal adpcm_store : std_logic;
|
|
signal adpcm_step_request_raw : std_logic;
|
|
signal adpcm_step_ready_adj : std_logic;
|
|
|
|
signal bits8_reg : std_logic_vector(3 downto 0);
|
|
signal bits8_next : std_logic_vector(3 downto 0);
|
|
signal bits8 : std_logic;
|
|
|
|
signal addr_decoded5 : std_logic_vector(31 downto 0);
|
|
|
|
signal data_nibble : std_logic;
|
|
|
|
signal store_data : std_logic_vector(12 downto 0);
|
|
signal store_source : std_logic_vector(3 downto 0);
|
|
signal store_channel : std_logic_vector(1 downto 0);
|
|
signal store : std_logic;
|
|
|
|
BEGIN
|
|
|
|
decode_addr2 : entity work.complete_address_decoder
|
|
generic map(width=>5)
|
|
port map (addr_in=>ADDR(4 downto 0), addr_decoded=>addr_decoded5);
|
|
|
|
process(addr_decoded5,CH0_REG,CH1_REG,CH2_REG,CH3_REG,
|
|
ram_cpu_addr_reg, ram_data,
|
|
irq_en_reg,irq_active_reg
|
|
)
|
|
begin
|
|
DO <= (others=>'0');
|
|
|
|
if (addr_decoded5(0)='1') then
|
|
DO <= CH0_REG(12 downto 5);
|
|
end if;
|
|
|
|
if (addr_decoded5(1)='1') then
|
|
DO <= CH1_REG(12 downto 5);
|
|
end if;
|
|
|
|
if (addr_decoded5(2)='1') then
|
|
DO <= CH2_REG(12 downto 5);
|
|
end if;
|
|
|
|
if (addr_decoded5(3)='1') then
|
|
DO <= CH3_REG(12 downto 5);
|
|
end if;
|
|
|
|
if (addr_decoded5(4)='1') then
|
|
DO <= ram_cpu_addr_reg(7 downto 0);
|
|
end if;
|
|
if (addr_decoded5(5)='1') then
|
|
DO <= ram_cpu_addr_reg(15 downto 8);
|
|
end if;
|
|
if (addr_decoded5(6)='1') then --manual addr inc
|
|
DO <= ram_data;
|
|
end if;
|
|
if (addr_decoded5(17)='1') then
|
|
DO(3 downto 0) <= irq_en_reg;
|
|
end if;
|
|
if (addr_decoded5(18)='1') then
|
|
DO(3 downto 0) <= irq_active_reg;
|
|
end if;
|
|
end process;
|
|
|
|
process(adpcm_channel,adpcm_store,addr,bits8,dma_on,adpcm_on,write_enable)
|
|
begin
|
|
store <= '0';
|
|
store_channel <= (others=>'0');
|
|
store_source <= (others=>'0');
|
|
|
|
if (write_enable='0' and dma_on='1') then
|
|
store_channel <= adpcm_channel;
|
|
store <= adpcm_store;
|
|
elsif (write_enable='1') then
|
|
store_channel <= ADDR(1 downto 0);
|
|
store <= not(or_reduce(ADDR(4 downto 2)));
|
|
end if;
|
|
store_source(3) <= bits8;
|
|
store_source(2) <= dma_on;
|
|
store_source(1) <= adpcm_on;
|
|
store_source(0) <= write_enable;
|
|
end process;
|
|
|
|
process(store_source,data_nibble,
|
|
di,adpcm_decoded,ram_data)
|
|
begin
|
|
store_data <= (others=>'0');
|
|
case store_source is
|
|
when "0001"|"0011"|"0101"|"0111"|"1001"|"1011"|"1101"|"1111" =>
|
|
store_data(12 downto 5) <= di;
|
|
when "0110"|"1110" =>
|
|
store_data <= adpcm_decoded(15 downto 3);
|
|
when "1100" =>
|
|
store_data(12) <= not(ram_data(7));
|
|
store_data(11 downto 5) <= ram_data(6 downto 0);
|
|
when "0100" =>
|
|
if (data_nibble='0') then
|
|
store_data(12) <= not(ram_data(7));
|
|
store_data(11 downto 9) <= ram_data(6 downto 4);
|
|
else
|
|
store_data(12) <= not(ram_data(3));
|
|
store_data(11 downto 9) <= ram_data(2 downto 0);
|
|
end if;
|
|
|
|
when others=>
|
|
end case;
|
|
end process;
|
|
|
|
process( CH0_REG,CH1_REG,CH2_REG,CH3_REG,DI,
|
|
store,store_data,store_channel
|
|
)
|
|
begin
|
|
CH0_NEXT <= CH0_REG;
|
|
CH1_NEXT <= CH1_REG;
|
|
CH2_NEXT <= CH2_REG;
|
|
CH3_NEXT <= CH3_REG;
|
|
|
|
if (store='1') then
|
|
case store_channel is
|
|
when "00"=>
|
|
CH0_NEXT <= store_data;
|
|
when "01" =>
|
|
CH1_NEXT <= store_data;
|
|
when "10" =>
|
|
CH2_NEXT <= store_data;
|
|
when "11" =>
|
|
CH3_NEXT <= store_data;
|
|
when others =>
|
|
end case;
|
|
end if;
|
|
end process;
|
|
|
|
adpcm_decoder : entity work.sample_adpcm
|
|
port map
|
|
(
|
|
clk=>clk,
|
|
reset_n=>reset_n,
|
|
syncreset=>irq_trigger,
|
|
|
|
select_channel=>adpcm_channel,
|
|
|
|
store=>adpcm_store,
|
|
|
|
data_out=>adpcm_decoded,
|
|
|
|
dirty=>data_request,
|
|
|
|
data_request => adpcm_data_request,
|
|
data_ready => adpcm_data_ready_reg,
|
|
data_in => adpcm_data_in,
|
|
|
|
step_addr => adpcm_step_addr,
|
|
step_request => adpcm_step_request_raw,
|
|
step_ready => adpcm_step_ready_adj,
|
|
step_value => adpcm_step_value
|
|
);
|
|
--data_in=>ram_data,
|
|
--update=>data_request,
|
|
--fetch=>dma,
|
|
--data_nibble=>ch3_addr(0)&ch2_addr(0)&ch1_addr(0)&ch0_addr(0),
|
|
-- TODO -> feed in data slower and each nibble
|
|
adpcm_data_in <= ram_data(7 downto 4) when data_nibble='0' else ram_data(3 downto 0);
|
|
|
|
adpcm_step_request <= adpcm_on and dma_on and adpcm_step_request_raw;
|
|
adpcm_step_ready_adj <= (not(adpcm_on and dma_on) and adpcm_step_request_raw) or adpcm_step_ready;
|
|
|
|
process(ADDR, addr_decoded5, WRITE_ENABLE, DI,
|
|
ram_cpu_addr_reg,
|
|
ch0_start_addr_reg, ch0_len_reg, ch0_period_reg, ch0_volume_reg,
|
|
ch1_start_addr_reg, ch1_len_reg, ch1_period_reg, ch1_volume_reg,
|
|
ch2_start_addr_reg, ch2_len_reg, ch2_period_reg, ch2_volume_reg,
|
|
ch3_start_addr_reg, ch3_len_reg, ch3_period_reg, ch3_volume_reg,
|
|
dma_on_reg,dma_on,ram_data,
|
|
channel_reg,
|
|
irq_en_reg,irq_active_reg,irq_trigger,irq_clear_n,
|
|
adpcm_reg, bits8_reg
|
|
)
|
|
begin
|
|
ram_cpu_write_enable <= '0';
|
|
ram_cpu_addr_next <= ram_cpu_addr_reg;
|
|
|
|
ch0_start_addr_next <= ch0_start_addr_reg;
|
|
ch0_len_next <= ch0_len_reg;
|
|
ch0_period_next <= ch0_period_reg;
|
|
ch0_volume_next <= ch0_volume_reg;
|
|
|
|
ch1_start_addr_next <= ch1_start_addr_reg;
|
|
ch1_len_next <= ch1_len_reg;
|
|
ch1_period_next <= ch1_period_reg;
|
|
ch1_volume_next <= ch1_volume_reg;
|
|
|
|
ch2_start_addr_next <= ch2_start_addr_reg;
|
|
ch2_len_next <= ch2_len_reg;
|
|
ch2_period_next <= ch2_period_reg;
|
|
ch2_volume_next <= ch2_volume_reg;
|
|
|
|
ch3_start_addr_next <= ch3_start_addr_reg;
|
|
ch3_len_next <= ch3_len_reg;
|
|
ch3_period_next <= ch3_period_reg;
|
|
ch3_volume_next <= ch3_volume_reg;
|
|
|
|
dma_on_next <= dma_on_reg;
|
|
bits8_next <= bits8_reg;
|
|
|
|
channel_next <= channel_reg;
|
|
|
|
irq_clear_n <= (others=>'1');
|
|
irq_en_next <= irq_en_reg;
|
|
irq_active_next <= (irq_active_reg or irq_trigger) and irq_en_reg and irq_clear_n;
|
|
|
|
adpcm_next <= adpcm_reg;
|
|
|
|
if (write_enable='1') then
|
|
if (addr_decoded5(4)='1') then
|
|
ram_cpu_addr_next(7 downto 0) <= DI;
|
|
end if;
|
|
if (addr_decoded5(5)='1') then
|
|
ram_cpu_addr_next(15 downto 8) <= DI;
|
|
end if;
|
|
if (addr_decoded5(6)='1') then --manual addr inc
|
|
ram_cpu_write_enable <= '1';
|
|
end if;
|
|
if (addr_decoded5(7)='1') then --auto addr inc
|
|
ram_cpu_write_enable <= '1';
|
|
ram_cpu_addr_next <= ram_cpu_addr_reg + 1;
|
|
end if;
|
|
|
|
if (addr_decoded5(8)='1') then
|
|
channel_next(2 downto 0) <= DI(2 downto 0);
|
|
end if;
|
|
|
|
case channel_reg is
|
|
when "001" =>
|
|
if (addr_decoded5(9)='1') then
|
|
ch0_start_addr_next(7 downto 0) <= DI;
|
|
end if;
|
|
if (addr_decoded5(10)='1') then
|
|
ch0_start_addr_next(15 downto 8) <= DI;
|
|
end if;
|
|
if (addr_decoded5(11)='1') then
|
|
ch0_len_next(7 downto 0) <= DI;
|
|
end if;
|
|
if (addr_decoded5(12)='1') then
|
|
ch0_len_next(15 downto 8) <= DI;
|
|
end if;
|
|
if (addr_decoded5(13)='1') then
|
|
ch0_period_next(7 downto 0) <= DI;
|
|
end if;
|
|
if (addr_decoded5(14)='1') then
|
|
ch0_period_next(11 downto 8) <= DI(3 downto 0);
|
|
end if;
|
|
if (addr_decoded5(15)='1') then
|
|
ch0_volume_next(5 downto 0) <= DI(5 downto 0);
|
|
end if;
|
|
when "010" =>
|
|
if (addr_decoded5(9)='1') then
|
|
ch1_start_addr_next(7 downto 0) <= DI;
|
|
end if;
|
|
if (addr_decoded5(10)='1') then
|
|
ch1_start_addr_next(15 downto 8) <= DI;
|
|
end if;
|
|
if (addr_decoded5(11)='1') then
|
|
ch1_len_next(7 downto 0) <= DI;
|
|
end if;
|
|
if (addr_decoded5(12)='1') then
|
|
ch1_len_next(15 downto 8) <= DI;
|
|
end if;
|
|
if (addr_decoded5(13)='1') then
|
|
ch1_period_next(7 downto 0) <= DI;
|
|
end if;
|
|
if (addr_decoded5(14)='1') then
|
|
ch1_period_next(11 downto 8) <= DI(3 downto 0);
|
|
end if;
|
|
if (addr_decoded5(15)='1') then
|
|
ch1_volume_next(5 downto 0) <= DI(5 downto 0);
|
|
end if;
|
|
when "011" =>
|
|
if (addr_decoded5(9)='1') then
|
|
ch2_start_addr_next(7 downto 0) <= DI;
|
|
end if;
|
|
if (addr_decoded5(10)='1') then
|
|
ch2_start_addr_next(15 downto 8) <= DI;
|
|
end if;
|
|
if (addr_decoded5(11)='1') then
|
|
ch2_len_next(7 downto 0) <= DI;
|
|
end if;
|
|
if (addr_decoded5(12)='1') then
|
|
ch2_len_next(15 downto 8) <= DI;
|
|
end if;
|
|
if (addr_decoded5(13)='1') then
|
|
ch2_period_next(7 downto 0) <= DI;
|
|
end if;
|
|
if (addr_decoded5(14)='1') then
|
|
ch2_period_next(11 downto 8) <= DI(3 downto 0);
|
|
end if;
|
|
if (addr_decoded5(15)='1') then
|
|
ch2_volume_next(5 downto 0) <= DI(5 downto 0);
|
|
end if;
|
|
when "100" =>
|
|
if (addr_decoded5(9)='1') then
|
|
ch3_start_addr_next(7 downto 0) <= DI;
|
|
end if;
|
|
if (addr_decoded5(10)='1') then
|
|
ch3_start_addr_next(15 downto 8) <= DI;
|
|
end if;
|
|
if (addr_decoded5(11)='1') then
|
|
ch3_len_next(7 downto 0) <= DI;
|
|
end if;
|
|
if (addr_decoded5(12)='1') then
|
|
ch3_len_next(15 downto 8) <= DI;
|
|
end if;
|
|
if (addr_decoded5(13)='1') then
|
|
ch3_period_next(7 downto 0) <= DI;
|
|
end if;
|
|
if (addr_decoded5(14)='1') then
|
|
ch3_period_next(11 downto 8) <= DI(3 downto 0);
|
|
end if;
|
|
if (addr_decoded5(15)='1') then
|
|
ch3_volume_next(5 downto 0) <= DI(5 downto 0);
|
|
end if;
|
|
when others =>
|
|
end case;
|
|
if (addr_decoded5(16)='1') then
|
|
dma_on_next <= DI(3 downto 0);
|
|
end if;
|
|
if (addr_decoded5(17)='1') then
|
|
irq_en_next <= DI(3 downto 0);
|
|
end if;
|
|
if (addr_decoded5(18)='1') then
|
|
irq_clear_n <= DI(3 downto 0); --write 0 to disable
|
|
end if;
|
|
if (addr_decoded5(19)='1') then
|
|
adpcm_next <= DI(3 downto 0);
|
|
bits8_next <= DI(7 downto 4);
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
ch0_inst: entity work.sample_channel
|
|
PORT MAP
|
|
(
|
|
CLK => CLK,
|
|
RESET_N => RESET_N,
|
|
ENABLE => ENABLE,
|
|
|
|
syncreset => (dma_on_next(0) xor dma_on_reg(0)),
|
|
start_addr => ch0_start_addr_reg,
|
|
len => ch0_len_reg,
|
|
period => ch0_period_reg,
|
|
|
|
twocycles => adpcm_reg(0) or not(bits8_reg(0)),
|
|
|
|
addr => ch0_addr,
|
|
irq => irq_trigger(0),
|
|
req => data_request(0)
|
|
);
|
|
|
|
ch1_inst: entity work.sample_channel
|
|
PORT MAP
|
|
(
|
|
CLK => CLK,
|
|
RESET_N => RESET_N,
|
|
ENABLE => ENABLE,
|
|
|
|
syncreset => (dma_on_next(1) xor dma_on_reg(1)),
|
|
start_addr => ch1_start_addr_reg,
|
|
len => ch1_len_reg,
|
|
period => ch1_period_reg,
|
|
|
|
twocycles => adpcm_reg(1) or not(bits8_reg(1)),
|
|
|
|
addr => ch1_addr,
|
|
irq => irq_trigger(1),
|
|
req => data_request(1)
|
|
);
|
|
|
|
ch2_inst: entity work.sample_channel
|
|
PORT MAP
|
|
(
|
|
CLK => CLK,
|
|
RESET_N => RESET_N,
|
|
ENABLE => ENABLE,
|
|
|
|
syncreset => (dma_on_next(2) xor dma_on_reg(2)),
|
|
start_addr => ch2_start_addr_reg,
|
|
len => ch2_len_reg,
|
|
period => ch2_period_reg,
|
|
|
|
twocycles => adpcm_reg(2) or not(bits8_reg(2)),
|
|
|
|
addr => ch2_addr,
|
|
irq => irq_trigger(2),
|
|
req => data_request(2)
|
|
);
|
|
|
|
ch3_inst: entity work.sample_channel
|
|
PORT MAP
|
|
(
|
|
CLK => CLK,
|
|
RESET_N => RESET_N,
|
|
ENABLE => ENABLE,
|
|
|
|
syncreset => (dma_on_next(3) xor dma_on_reg(3)),
|
|
start_addr => ch3_start_addr_reg,
|
|
len => ch3_len_reg,
|
|
period => ch3_period_reg,
|
|
|
|
twocycles => adpcm_reg(3) or not(bits8_reg(3)),
|
|
|
|
addr => ch3_addr,
|
|
irq => irq_trigger(3),
|
|
req => data_request(3)
|
|
);
|
|
|
|
process (ch0_reg,ch1_reg,ch2_reg,ch3_reg,
|
|
ch0_volume_reg,ch1_volume_reg,ch2_volume_reg,ch3_volume_reg)
|
|
variable l : unsigned(26 downto 0);
|
|
variable r : unsigned(26 downto 0);
|
|
begin
|
|
l := resize(unsigned(CH0_REG),18)*resize(unsigned(ch0_volume_reg),9);
|
|
l := l + resize(unsigned(CH3_REG),18)*resize(unsigned(ch3_volume_reg),9);
|
|
r := resize(unsigned(CH1_REG),18)*resize(unsigned(ch1_volume_reg),9);
|
|
r := r + resize(unsigned(CH2_REG),18)*resize(unsigned(ch2_volume_reg),9);
|
|
-- TODO: probably need to register here?
|
|
AUDIO0 <= std_logic_vector(l(19 downto 4));
|
|
AUDIO1 <= std_logic_vector(r(19 downto 4));
|
|
|
|
-- TODO: modulation?
|
|
-- TODO: samples from rom and put in voice samples after core?
|
|
-- TODO: 4 bit mode?
|
|
|
|
-- options to set: per channel: modulate volume(4),modulate period(4),sample bits(4)
|
|
end process;
|
|
|
|
process(ch0_addr,ch1_addr,ch2_addr,ch3_addr,
|
|
ram_cpu_addr_reg,
|
|
adpcm_channel,
|
|
request,
|
|
dma_on_reg,
|
|
adpcm_reg,
|
|
bits8_reg,
|
|
adpcm_data_request)
|
|
begin
|
|
ram_addr <= (others=>'0');
|
|
data_nibble <= '0';
|
|
adpcm_on <= '0';
|
|
dma_on <= '0';
|
|
bits8 <= '0';
|
|
|
|
adpcm_data_ready_next <= adpcm_data_request;
|
|
|
|
case adpcm_channel is
|
|
when "00" =>
|
|
ram_addr <= ch0_addr(16 downto 1);
|
|
data_nibble <= ch0_addr(0);
|
|
adpcm_on <= adpcm_reg(0);
|
|
dma_on <= dma_on_reg(0);
|
|
bits8 <= bits8_reg(0);
|
|
when "01" =>
|
|
ram_addr <= ch1_addr(16 downto 1);
|
|
data_nibble <= ch1_addr(0);
|
|
adpcm_on <= adpcm_reg(1);
|
|
dma_on <= dma_on_reg(1);
|
|
bits8 <= bits8_reg(1);
|
|
when "10" =>
|
|
ram_addr <= ch2_addr(16 downto 1);
|
|
data_nibble <= ch2_addr(0);
|
|
adpcm_on <= adpcm_reg(2);
|
|
dma_on <= dma_on_reg(2);
|
|
bits8 <= bits8_reg(2);
|
|
when "11" =>
|
|
ram_addr <= ch3_addr(16 downto 1);
|
|
data_nibble <= ch3_addr(0);
|
|
adpcm_on <= adpcm_reg(3);
|
|
dma_on <= dma_on_reg(3);
|
|
bits8 <= bits8_reg(3);
|
|
when others =>
|
|
end case;
|
|
|
|
if (request='1') then
|
|
ram_addr <= ram_cpu_addr_reg;
|
|
adpcm_data_ready_next <= '0';
|
|
end if;
|
|
end process;
|
|
|
|
process(clk,reset_n)
|
|
begin
|
|
if (reset_n='0') then
|
|
CH0_REG <= (others=>'0');
|
|
CH1_REG <= (others=>'0');
|
|
CH2_REG <= (others=>'0');
|
|
CH3_REG <= (others=>'0');
|
|
ram_cpu_addr_reg <= (others=>'0');
|
|
|
|
ch0_start_addr_reg <= (others=>'0');
|
|
ch0_len_reg <= (others=>'0');
|
|
ch0_period_reg <= (others=>'0');
|
|
ch0_volume_reg <= (others=>'1');
|
|
|
|
ch1_start_addr_reg <= (others=>'0');
|
|
ch1_len_reg <= (others=>'0');
|
|
ch1_period_reg <= (others=>'0');
|
|
ch1_volume_reg <= (others=>'1');
|
|
|
|
ch2_start_addr_reg <= (others=>'0');
|
|
ch2_len_reg <= (others=>'0');
|
|
ch2_period_reg <= (others=>'0');
|
|
ch2_volume_reg <= (others=>'1');
|
|
|
|
ch3_start_addr_reg <= (others=>'0');
|
|
ch3_len_reg <= (others=>'0');
|
|
ch3_period_reg <= (others=>'0');
|
|
ch3_volume_reg <= (others=>'1');
|
|
|
|
dma_on_reg <= (others=>'0');
|
|
irq_en_reg <= (others=>'0');
|
|
irq_active_reg <= (others=>'0');
|
|
channel_reg <= (others=>'0');
|
|
|
|
adpcm_reg <= (others=>'0');
|
|
adpcm_data_ready_reg <= '0';
|
|
|
|
bits8_reg <= (others=>'1');
|
|
|
|
elsif (clk'event and clk='1') then
|
|
CH0_REG <= CH0_NEXT;
|
|
CH1_REG <= CH1_NEXT;
|
|
CH2_REG <= CH2_NEXT;
|
|
CH3_REG <= CH3_NEXT;
|
|
ram_cpu_addr_reg <= ram_cpu_addr_next;
|
|
|
|
ch0_start_addr_reg <= ch0_start_addr_next;
|
|
ch0_len_reg <= ch0_len_next;
|
|
ch0_period_reg <= ch0_period_next;
|
|
ch0_volume_reg <= ch0_volume_next;
|
|
|
|
ch1_start_addr_reg <= ch1_start_addr_next;
|
|
ch1_len_reg <= ch1_len_next;
|
|
ch1_period_reg <= ch1_period_next;
|
|
ch1_volume_reg <= ch1_volume_next;
|
|
|
|
ch2_start_addr_reg <= ch2_start_addr_next;
|
|
ch2_len_reg <= ch2_len_next;
|
|
ch2_period_reg <= ch2_period_next;
|
|
ch2_volume_reg <= ch2_volume_next;
|
|
|
|
ch3_start_addr_reg <= ch3_start_addr_next;
|
|
ch3_len_reg <= ch3_len_next;
|
|
ch3_period_reg <= ch3_period_next;
|
|
ch3_volume_reg <= ch3_volume_next;
|
|
|
|
dma_on_reg <= dma_on_next;
|
|
irq_en_reg <= irq_en_next;
|
|
irq_active_reg <= irq_active_next;
|
|
channel_reg <= channel_next;
|
|
|
|
adpcm_reg <= adpcm_next;
|
|
adpcm_data_ready_reg <= adpcm_data_ready_next;
|
|
|
|
bits8_reg <= bits8_next;
|
|
|
|
end if;
|
|
end process;
|
|
|
|
IRQ <= or_reduce(irq_active_reg);
|
|
|
|
RAM_WRITE_ENABLE <= RAM_CPU_WRITE_ENABLE;
|
|
END vhdl;
|