-- Interactive Audio Manipulation Processor -- -- file: ram_interface.vhd -- status: not compiled -- -- author: Stephen Tang -- -- This entity interfaces with the RAM driver (ram_port), the ADC driver -- (adc_port), and the audio manipulation path (audio_manipulator). The -- RAM interface accepts samples from the ADC and saves the samples in -- RAM, and outputs those samples to the audio manipulator upon request. library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; library work; use work.Constants_Pkg.all; entity ram_interface is port ( clock: in std_logic; -- should be 25.175MHz reset: in std_logic; -- active low, from reset pushbutton -- RAM interface ram_ack_in: in std_logic; -- RAM driver has serviced the request ram_request: out std_logic; -- request services of RAM driver ram_rw: out std_logic; -- indicate request type: R (1) or W (0) ram_address: buffer std_logic_vector(RAM_ADDRESS_WIDTH-1 downto 0); ram_data: inout std_logic_vector(RAM_DATA_WIDTH-1 downto 0); -- ADC interface adc_ready: in std_logic; -- ADC has a sample ready adc_ack: out std_logic; -- tell ADC that the sample was received adc_sample_in: in std_logic_vector(EFFECTIVE_SAMPLE_WIDTH-1 downto 0); -- incoming sample from ADC; note that only the most-significant -- 8 bits out of the 24 total are input to the RAM interface! -- audio path interface a_delay: in std_logic_vector(DELAY_WIDTH-1 downto 0); -- delay of the sample to retrieve a_request: in std_logic; -- audio path wants a sample a_ack: out std_logic; -- sample has been sent a_sample: out std_logic_vector(EFFECTIVE_SAMPLE_WIDTH-1 downto 0) -- the sample requested by the audio path -- the following signal was only used while testing this entity -- using ram_bench2.vhd ;CurrentAddress: out std_logic_vector(RAM_ADDRESS_WIDTH-1 downto 0) ); end ram_interface; architecture RAMinterface of ram_interface is component bidir port( bidir : INOUT STD_LOGIC_VECTOR (RAM_DATA_WIDTH-1 DOWNTO 0); oe, clk : IN STD_LOGIC; inp : IN STD_LOGIC_VECTOR (RAM_DATA_WIDTH-1 DOWNTO 0); outp : OUT STD_LOGIC_VECTOR (RAM_DATA_WIDTH-1 DOWNTO 0)); end component; type RamInterfaceStates is (RIS_INIT, RIS_WAIT, RIS_GETNEWSAMPLE, RIS_SAMPLE2AUDIO); signal CurState: RamInterfaceStates; signal invRW: std_logic; signal RamDataIn, RamDataOut: std_logic_vector(RAM_DATA_WIDTH-1 downto 0); begin ram_rw <= not invRW; -- for RW, '0' means write, '1' means read FSM: process(clock) variable CurAddress: std_logic_vector(RAM_ADDRESS_WIDTH-1 downto 0); variable DelayedAddress: std_logic_vector(RAM_ADDRESS_WIDTH-1 downto 0); variable WaitToAvoidGlitches: std_logic; begin if rising_edge(clock) then if reset = '0' then --CurState = RIS_INIT; CurAddress := (others => '0'); DelayedAddress := (others => '0'); ram_address <= CurAddress; a_ack <= '0'; adc_ack <= '0'; ram_request <= '0'; WaitToAvoidGlitches := '0'; CurState <= RIS_WAIT; else case CurState is -- waiting for something to happen when RIS_WAIT => a_ack <= '0'; adc_ack <= '0'; ram_request <= '0'; -- when adc_ready goes high, it means that a sample is -- available to capture. But before we change state, -- wait for another clock cycle to make sure that -- adc_ready remains high. if adc_ready = '1' then if WaitToAvoidGlitches = '1' then invRW <= '1'; -- if invRW=1, then ram_rw=0, then means write CurState <= RIS_GETNEWSAMPLE; else WaitToAvoidGlitches := '1'; end if; elsif a_request = '1' then if WaitToAvoidGlitches = '1' then invRW <= '0'; -- if invRW=0, then ram_rw=1, then means read CurState <= RIS_SAMPLE2AUDIO; else WaitToAvoidGlitches := '1'; end if; end if; -- ADC has a new sample available so grab it when RIS_GETNEWSAMPLE => ram_address <= CurAddress; ram_request <= '1'; -- Note also that we only keep the 8 MSBs of the sample. -- This code assumes incoming sample data is big-endian (MSB -- is the leftmost bit of the vector). The two data bytes are -- stored with the less significant one at a lower address. RamDataOut <= adc_sample_in; if ram_ack_in = '1' then -- data has been written to RAM -- increment address pointers CurAddress := CurAddress + '1'; if CurAddress = RAM_MAX_ADDRESS then CurAddress := (others => '0'); end if; DelayedAddress := DelayedAddress + '1'; if DelayedAddress = RAM_MAX_ADDRESS then DelayedAddress := (others => '0'); end if; -- the highest 2 bytes of the sample have been written adc_ack <= '1'; -- tell ADC that the sample was received ram_request <= '0'; -- no longer need the services of ram driver WaitToAvoidGlitches := '0'; CurState <= RIS_WAIT; end if; -- audio path wants a sample, so send one when RIS_SAMPLE2AUDIO => ram_request <= '1'; -- determine what address to grab the sample from if a_delay = NO_DELAY then if (CurAddress - '1') /= RAM_ADDRESS_UNDERFLOW then ram_address <= CurAddress - '1'; else ram_address <= RAM_MAX_ADDRESS-'1'; end if; elsif CurAddress >= a_delay then DelayedAddress := CurAddress - a_delay - '1'; if DelayedAddress /= RAM_ADDRESS_UNDERFLOW then ram_address <= DelayedAddress; else ram_address <= RAM_MAX_ADDRESS-'1'; end if; else DelayedAddress := RAM_MAX_ADDRESS-(a_delay-CurAddress(DELAY_WIDTH-1 downto 0))-'1'; ram_address <= DelayedAddress; end if; if ram_ack_in = '1' then -- data has been read from RAM into RamDataIn -- now we can toss that info into a_sample -- The audio sample must be in big-endian form -- because that's the way the data is stored in RAM a_sample <= RamDataIn; a_ack <= '1'; -- tell audio path that sample is ready ram_request <= '0'; -- no longer need the services of ram driver WaitToAvoidGlitches := '0'; CurState <= RIS_WAIT; end if; -- undefined state; go to waiting state when others => CurState <= RIS_WAIT; end case; end if; end if; -- the next line is used only in the RAM test bench CurrentAddress <= CurAddress; end process FSM; RAMdataBus: bidir port map( bidir => ram_data, oe => invRW, -- OE='0' puts line to 'Z', OE='1' lets me drive the bus clk => clock, inp => RamDataOut, -- data to be dumped on the bus outp => RamDataIn -- data to be received from bus when OE='0' ); end;