-- -- A simulation model of Pacman hardware -- Copyright (c) MikeJ - September 2002 -- -- 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. -- -- You are responsible for any legal issues arising from your use of this code. -- -- The latest version of this file can be found at: www.fpgaarcade.com -- -- Email pacman@fpgaarcade.com -- -- Revision list -- -- version 002 added volume multiplier -- version 001 initial release -- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.pkg_pacman_xilinx_prims.all; use work.pkg_pacman.all; entity PACMAN_AUDIO is port ( HCNT : in std_logic_vector(8 downto 0); AB : in std_logic_vector(11 downto 0); DB : in std_logic_vector( 7 downto 0); WR1_L : in std_logic; WR0_L : in std_logic; SOUND_ON : in std_logic; AUDIO_OUT : out std_logic_vector(7 downto 0); CLK_6 : in std_logic ); end; architecture RTL of PACMAN_AUDIO is signal addr : std_logic_vector(3 downto 0); signal data : std_logic_vector(3 downto 0); signal vol_ram_wen : std_logic; signal frq_ram_wen : std_logic; signal vol_ram_dout : std_logic_vector(3 downto 0); signal frq_ram_dout : std_logic_vector(3 downto 0); signal sum : std_logic_vector(5 downto 0); signal accum_reg : std_logic_vector(5 downto 0); signal rom3m_n : std_logic_vector(15 downto 0); signal rom3m_w : std_logic_vector(3 downto 0); signal rom3m : std_logic_vector(3 downto 0); signal rom1m_addr : std_logic_vector(8 downto 0); signal rom1m_data : std_logic_vector(7 downto 0); signal audio_vol_out : std_logic_vector(3 downto 0); signal audio_wav_out : std_logic_vector(3 downto 0); signal audio_mul_out : std_logic_vector(7 downto 0); begin p_sel_com : process(HCNT, AB, DB, accum_reg) begin if (HCNT(1) = '0') then -- 2h, addr <= AB(3 downto 0); data <= DB(3 downto 0); -- removed invert else addr <= HCNT(5 downto 2); data <= accum_reg(4 downto 1); end if; end process; p_ram_comb : process(WR1_L, rom3m) begin vol_ram_wen <= '0'; if (WR1_L = '0') then vol_ram_wen <= '1'; end if; frq_ram_wen <= '0'; if (rom3m(1) = '1') then frq_ram_wen <= '1'; end if; end process; vol_ram : for i in 0 to 3 generate -- should be a latch, but we are using a clock begin inst: RAM16X1D port map ( a0 => addr(0), a1 => addr(1), a2 => addr(2), a3 => addr(3), dpra0 => addr(0), dpra1 => addr(1), dpra2 => addr(2), dpra3 => addr(3), wclk => CLK_6, we => vol_ram_wen, d => data(i), dpo => vol_ram_dout(i) ); end generate; frq_ram : for i in 0 to 3 generate -- should be a latch, but we are using a clock begin inst: RAM16X1D port map ( a0 => addr(0), a1 => addr(1), a2 => addr(2), a3 => addr(3), dpra0 => addr(0), dpra1 => addr(1), dpra2 => addr(2), dpra3 => addr(3), wclk => CLK_6, we => frq_ram_wen, d => data(i), dpo => frq_ram_dout(i) ); end generate; p_control_rom_comb : process(HCNT) begin rom3m_n <= x"0000"; rom3m_w <= x"0"; -- default assign case HCNT(3 downto 0) is when x"0" => rom3m_n <= x"0008"; rom3m_w <= x"0"; when x"1" => rom3m_n <= x"0000"; rom3m_w <= x"2"; when x"2" => rom3m_n <= x"1111"; rom3m_w <= x"0"; when x"3" => rom3m_n <= x"2222"; rom3m_w <= x"0"; when x"4" => rom3m_n <= x"0000"; rom3m_w <= x"0"; when x"5" => rom3m_n <= x"0000"; rom3m_w <= x"2"; when x"6" => rom3m_n <= x"1101"; rom3m_w <= x"0"; when x"7" => rom3m_n <= x"2242"; rom3m_w <= x"0"; when x"8" => rom3m_n <= x"0080"; rom3m_w <= x"0"; when x"9" => rom3m_n <= x"0000"; rom3m_w <= x"2"; when x"A" => rom3m_n <= x"1011"; rom3m_w <= x"0"; when x"B" => rom3m_n <= x"2422"; rom3m_w <= x"0"; when x"C" => rom3m_n <= x"0800"; rom3m_w <= x"0"; when x"D" => rom3m_n <= x"0000"; rom3m_w <= x"2"; when x"E" => rom3m_n <= x"0111"; rom3m_w <= x"0"; when x"F" => rom3m_n <= x"4222"; rom3m_w <= x"0"; when others => null; end case; end process; p_control_rom_op_comb : process(HCNT, WR0_L, rom3m_n, rom3m_w) begin rom3m <= rom3m_w; if (WR0_L = '1') then case HCNT(5 downto 4) is when "00" => rom3m <= rom3m_n( 3 downto 0); when "01" => rom3m <= rom3m_n( 7 downto 4); when "10" => rom3m <= rom3m_n(11 downto 8); when "11" => rom3m <= rom3m_n(15 downto 12); when others => null; end case; end if; end process; p_adder : process(vol_ram_dout, frq_ram_dout, accum_reg) begin -- 1K 4 bit adder sum <= ('0' & vol_ram_dout & '1') + ('0' & frq_ram_dout & accum_reg(5)); end process; p_accum_reg : process begin -- 1L wait until rising_edge(CLK_6); if (rom3m(3) = '1') then -- clear accum_reg <= "000000"; elsif (rom3m(0) = '1') then -- rising edge clk accum_reg <= sum(5 downto 1) & accum_reg(4); end if; end process; p_rom_1m_addr_comb : process(accum_reg, frq_ram_dout) begin rom1m_addr(8) <= '0'; rom1m_addr(7 downto 5) <= frq_ram_dout(2 downto 0); rom1m_addr(4 downto 0) <= accum_reg(4 downto 0); end process; audio_rom_1m : PACROM_1M port map( CLK => CLK_6, ADDR => rom1m_addr, DATA => rom1m_data ); p_original_output_reg : process begin -- 2m used to use async clear wait until rising_edge(CLK_6); if (SOUND_ON = '0') then audio_vol_out <= "0000"; audio_wav_out <= "0000"; elsif (rom3m(2) = '1') then audio_vol_out <= vol_ram_dout(3 downto 0); audio_wav_out <= rom1m_data(3 downto 0); end if; end process; u_volume_mul : PACMAN_MUL4 -- replaces external fet switch used for volume port map( A => audio_vol_out, B => audio_wav_out, R => audio_mul_out ); p_output_reg : process begin wait until rising_edge(CLK_6); AUDIO_OUT(7 downto 0) <= audio_mul_out; end process; end architecture RTL;