Untitled
unknown
plain_text
a month ago
12 kB
4
Indexable
library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.NUMERIC_STD.all; use work.common_pack.all; entity dataConsume is port ( clk : in std_logic; reset : in std_logic; start : in std_logic; numWords_bcd: in BCD_ARRAY_TYPE(2 downto 0); -- BCD-coded #words ctrlIn : in std_logic; -- handshake from prior stage ctrlOut : out std_logic; -- handshake toggled to request next byte data : in std_logic_vector(7 downto 0); dataReady : out std_logic; -- single-cycle "data is done" pulse byte : out std_logic_vector(7 downto 0); seqDone : out std_logic; -- single-cycle "all done" pulse maxIndex : out BCD_ARRAY_TYPE(2 downto 0); dataResults : out CHAR_ARRAY_TYPE(0 to RESULT_BYTE_NUM - 1) ); end dataConsume; architecture Behavioral of dataConsume is ------------------------------------------------------------------------ -- 1) State definitions ------------------------------------------------------------------------ type fsm_state is ( IDLE, SETUP, REQUEST_BYTE, WAIT_CTRL, LATCH_DATA, PEAK_1, PEAK_2, PEAK_3, DATA_READY_PULSE, DONE ); signal curState, nextState : fsm_state := IDLE; ------------------------------------------------------------------------ -- 2) Internal registers and handshake detection ------------------------------------------------------------------------ signal nWords : integer range 0 to 999 := 0; signal counter : integer range 0 to 999 := 0; signal ctrlOut_reg : std_logic := '0'; signal ctrlIn_prev : std_logic := '0'; -- For single rising-edge detection signal edgeDetect : std_logic := '0'; ------------------------------------------------------------------------ -- Peak-detection signals ------------------------------------------------------------------------ signal peak_value : signed(7 downto 0) := (others => '0'); signal peak_index : integer range 0 to 999 := 0; -- Rolling buffer (3 previous samples) type rolling_array is array(0 to 2) of signed(7 downto 0); signal prev_samples : rolling_array := (others => (others => '0')); -- Once we detect a new peak, we want the next 3 samples stored in dataResults_internal(2..0). signal post_count : integer range 0 to 3 := 0; -- Single-cycle pulses signal dataReady_reg : std_logic := '0'; signal seqDone_reg : std_logic := '0'; signal dataResults_internal : CHAR_ARRAY_TYPE(0 to RESULT_BYTE_NUM - 1); ------------------------------------------------------------------------ -- 3) Convert 3-digit BCD to integer ------------------------------------------------------------------------ function bcd_to_int(bcd3 : BCD_ARRAY_TYPE(2 downto 0)) return integer is variable tmp : integer := 0; begin tmp := to_integer(unsigned(bcd3(2))) * 100 + to_integer(unsigned(bcd3(1))) * 10 + to_integer(unsigned(bcd3(0))); return tmp; end function; function decimal_to_bcd(input_decimal : integer) return BCD_ARRAY_TYPE is variable bcd : BCD_ARRAY_TYPE(2 downto 0); begin bcd := (others => (others => '0')); bcd(2) := std_logic_vector(to_unsigned(input_decimal / 100, 4)); bcd(1) := std_logic_vector(to_unsigned((input_decimal mod 100) / 10, 4)); bcd(0) := std_logic_vector(to_unsigned(input_decimal mod 100, 4)); return bcd; end function; begin ---------------------------------------------------------------------------- -- A) State register: synchronous ---------------------------------------------------------------------------- process(clk, reset) begin if rising_edge(clk) then if reset = '1' then curState <= IDLE; else curState <= nextState; end if; end if; end process; ---------------------------------------------------------------------------- -- B) Synchronous detection of a single rising edge on ctrlIn ---------------------------------------------------------------------------- process(clk) begin if rising_edge(clk) then ctrlIn_prev <= ctrlIn; if ctrlIn = '1' and ctrlIn_prev = '0' then edgeDetect <= '1'; else edgeDetect <= '0'; end if; end if; end process; ---------------------------------------------------------------------------- -- C) Combinational next-state logic, plus single-cycle pulses ---------------------------------------------------------------------------- process(curState, start, counter, nWords, edgeDetect) begin ------------------------------------------------------------------------ -- By default, dataReady_reg and seqDone_reg are '0' each cycle ------------------------------------------------------------------------ dataReady_reg <= '0'; seqDone_reg <= '0'; nextState <= curState; case curState is when IDLE => if start = '1' then nextState <= SETUP; end if; when SETUP => nextState <= REQUEST_BYTE; when REQUEST_BYTE => -- We'll toggle ctrlOut in the sequential block nextState <= WAIT_CTRL; when WAIT_CTRL => -- Wait for single rising edge on ctrlIn if edgeDetect = '1' then nextState <= LATCH_DATA; end if; when LATCH_DATA => -- If not finished, request another. If done, do a dataReady pulse. if counter >= nWords-1 then nextState <= PEAK_1; else nextState <= REQUEST_BYTE; end if; when PEAK_1 => nextState <= PEAK_2; when PEAK_2 => nextState <= PEAK_3; when PEAK_3 => nextState <= DATA_READY_PULSE; when DATA_READY_PULSE => -- single-cycle dataReady='1' dataReady_reg <= '1'; nextState <= DONE; when DONE => -- single-cycle seqDone='1'; once start=0 => IDLE seqDone_reg <= '1'; if start = '0' then nextState <= IDLE; end if; when others => nextState <= IDLE; end case; end process; ---------------------------------------------------------------------------- -- D) Synchronous data-path: counters, handshake toggling, storing peak window ---------------------------------------------------------------------------- process(clk) variable new_sample : signed(7 downto 0); variable reg_peak : integer := -128; begin if rising_edge(clk) then if reset = '1' then -- Reset everything nWords <= 0; counter <= 0; ctrlOut_reg <= '0'; peak_value <= (others => '0'); peak_index <= 0; prev_samples <= (others => (others => '0')); post_count <= 0; dataResults <= (others => (others => '0')); maxIndex <= (others => (others => '0')); else case curState is when IDLE => null; -- do nothing when SETUP => nWords <= bcd_to_int(numWords_bcd); counter <= 0; peak_value <= (others => '0'); peak_index <= 0; prev_samples <= (others => (others => '0')); post_count <= 0; dataResults <= (others => (others => '0')); when REQUEST_BYTE => -- Toggle ctrlOut to request next byte ctrlOut_reg <= not ctrlOut_reg; when WAIT_CTRL => null; -- just waiting for the rising edge when LATCH_DATA => -- read the new data new_sample := signed(data); -- shift the rolling buffer prev_samples(2) <= prev_samples(1); prev_samples(1) <= prev_samples(0); prev_samples(0) <= new_sample; -- Peak detection & storing if (counter = 0) or (new_sample > peak_value) then peak_value <= new_sample; peak_index <= counter; -- store the 3 samples before the new peak dataResults_internal(6) <= std_logic_vector(prev_samples(2)); dataResults_internal(5) <= std_logic_vector(prev_samples(1)); dataResults_internal(4) <= std_logic_vector(prev_samples(0)); dataResults_internal(3) <= data; -- the new peak -- clear out the next 3 positions dataResults_internal(2) <= (others => '0'); dataResults_internal(1) <= (others => '0'); dataResults_internal(0) <= (others => '0'); post_count <= 3; elsif post_count > 0 then dataResults_internal(post_count - 1) <= data; post_count <= post_count - 1; if counter >= nWords-1 then reg_peak := to_integer(peak_value); end if; end if; -- increment global sample counter counter <= counter + 1; if counter >= nWords-1 then reg_peak := to_integer(peak_value); end if; when PEAK_1 => if signed(dataResults_internal(2)) > reg_peak then dataResults_internal(1 to 6) <= dataResults_internal(0 to 5); maxIndex <= decimal_to_bcd(counter - 3); end if; when PEAK_2 => if signed(dataResults_internal(1)) > reg_peak then dataResults_internal(2 to 6) <= dataResults_internal(0 to 4); maxIndex <= decimal_to_bcd(counter - 2); end if; when PEAK_3 => if signed(dataResults_internal(0)) > reg_peak then dataResults_internal(3 to 6) <= dataResults_internal(0 to 3); maxIndex <= decimal_to_bcd(counter - 1); end if; when DATA_READY_PULSE => -- no extra data updates. The comb process sets dataReady=1 for this cycle when DONE => -- convert peak_index to BCD maxIndex(0) <= std_logic_vector(to_unsigned(peak_index mod 10, 4)); maxIndex(1) <= std_logic_vector(to_unsigned((peak_index / 10) mod 10, 4)); maxIndex(2) <= std_logic_vector(to_unsigned((peak_index / 100) mod 10, 4)); when others => null; end case; end if; end if; end process; ---------------------------------------------------------------------------- -- E) Drive final outputs from internal registers ---------------------------------------------------------------------------- ctrlOut <= ctrlOut_reg; dataReady <= dataReady_reg; -- pulses high for one clock in DATA_READY_PULSE seqDone <= seqDone_reg; -- pulses high for one clock in DONE dataResults <= dataResults_internal; byte <= data; end architecture Behavioral;
Editor is loading...
Leave a Comment