Untitled
unknown
plain_text
16 days ago
9.8 kB
1
Indexable
library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.NUMERIC_STD.all; use work.common_pack.all; -- Must define BCD_ARRAY_TYPE, CHAR_ARRAY_TYPE, etc. 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); -- 3-digit BCD: (2)=hundreds, (1)=tens, (0)=ones ctrlIn : in std_logic; -- External handshake in ctrlOut : out std_logic; -- Our handshake out data : in std_logic_vector(7 downto 0); dataReady : out std_logic; -- Pulses high for 1 clock when entire sequence done byte : out std_logic_vector(7 downto 0); seqDone : out std_logic; -- Likewise, 1-clock pulse marking done maxIndex : out BCD_ARRAY_TYPE(2 downto 0); -- BCD array for the max (peak) index dataResults : out CHAR_ARRAY_TYPE(0 to RESULT_BYTE_NUM-1) ); end entity dataConsume; architecture Behavioral of dataConsume is -- 1) State machine type fsm_state is (IDLE, SETUP, REQUEST_BYTE, WAIT_CTRL, LATCH_DATA, DONE); signal curState, nextState : fsm_state := IDLE; -- 2) Internal signals signal nWords : integer range 0 to 999 := 0; signal counter : integer range 0 to 999 := 0; -- Handshake toggle signal ctrlOut_reg : std_logic := '0'; signal ctrlIn_edge : std_logic := '0'; -- Peak detection signal peak_value : signed(7 downto 0) := (others => '0'); signal peak_index : integer range 0 to 999 := 0; -- Rolling buffer of the last 3 samples type rolling_array is array (0 to 2) of signed(7 downto 0); signal last3 : rolling_array := (others => (others => '0')); -- After-peak sample capture signal next3count : integer range 0 to 3 := 0; -- 3) Convert BCD input 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; begin ---------------------------------------------------------------------------- -- Synchronous FSM: state register ---------------------------------------------------------------------------- process(clk, reset) begin if rising_edge(clk) then if reset = '1' then curState <= IDLE; else curState <= nextState; end if; end if; end process; ---------------------------------------------------------------------------- -- Combinational FSM: next-state logic & default outputs ---------------------------------------------------------------------------- process(curState, start, counter, nWords, ctrlIn_edge) begin -- Default outputs each cycle dataReady <= '0'; seqDone <= '0'; nextState <= curState; case curState is when IDLE => if start = '1' then nextState <= SETUP; end if; when SETUP => nextState <= REQUEST_BYTE; when REQUEST_BYTE => nextState <= WAIT_CTRL; when WAIT_CTRL => if ctrlIn_edge = '1' then nextState <= LATCH_DATA; end if; when LATCH_DATA => if (counter + 1) < nWords then nextState <= REQUEST_BYTE; else nextState <= DONE; end if; when DONE => -- One-cycle pulse: dataReady='1', seqDone='1' dataReady <= '1'; seqDone <= '1'; nextState <= IDLE; -- We now return to IDLE unconditionally next cycle. when others => nextState <= IDLE; end case; end process; ---------------------------------------------------------------------------- -- Synchronous data-path updates: counters, toggles, etc. ---------------------------------------------------------------------------- process(clk, reset) variable i: integer; begin if rising_edge(clk) then if reset = '1' then nWords <= 0; counter <= 0; ctrlOut_reg <= '0'; peak_value <= (others => '0'); peak_index <= 0; last3 <= (others => (others => '0')); next3count <= 0; for i in 0 to RESULT_BYTE_NUM-1 loop dataResults(i) <= (others => '0'); end loop; else case curState is when IDLE => -- do nothing when SETUP => nWords <= bcd_to_int(numWords_bcd); counter <= 0; peak_value <= (others => '0'); peak_index <= 0; last3 <= (others => (others => '0')); next3count <= 0; for i in 0 to RESULT_BYTE_NUM-1 loop dataResults(i) <= (others => '0'); end loop; when REQUEST_BYTE => ctrlOut_reg <= not ctrlOut_reg; -- Toggle handshake when WAIT_CTRL => null; -- no internal updates when LATCH_DATA => variable new_sample : signed(7 downto 0); begin new_sample := signed(data); -- Check if this is a new peak if (counter = 0) or (new_sample > peak_value) then peak_value <= new_sample; peak_index <= counter; -- Store the old 3 samples dataResults(6) <= std_logic_vector(last3(2)); dataResults(5) <= std_logic_vector(last3(1)); dataResults(4) <= std_logic_vector(last3(0)); -- Store the peak dataResults(3) <= data; -- Clear out next 3 spots dataResults(2) <= (others => '0'); dataResults(1) <= (others => '0'); dataResults(0) <= (others => '0'); next3count <= 3; -- **Always** shift last3 after using it last3(2) <= last3(1); last3(1) <= last3(0); last3(0) <= new_sample; else -- No new peak: shift last3 last3(2) <= last3(1); last3(1) <= last3(0); last3(0) <= new_sample; -- If we are capturing 'after-peak' bytes if (next3count > 0) then dataResults(next3count - 1) <= data; next3count <= next3count - 1; end if; end if; -- increment global sample counter counter <= counter + 1; when DONE => -- dataReady & seqDone are driven combinationally -- no stateful updates needed here null; when others => null; end case; end if; end if; end process; ---------------------------------------------------------------------------- -- ctrlOut assignment ---------------------------------------------------------------------------- ctrlOut <= ctrlOut_reg; ---------------------------------------------------------------------------- -- Output the current peak on 'byte' ---------------------------------------------------------------------------- byte <= std_logic_vector(peak_value); ---------------------------------------------------------------------------- -- Convert peak_index to BCD on final -- (Can do it all the time or only after done. Here we do it every clock.) ---------------------------------------------------------------------------- process(clk) begin if rising_edge(clk) then -- Optionally only do this if (curState = DONE) or after we've latched a peak 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)); end if; end process; ---------------------------------------------------------------------------- -- Edge detection for ctrlIn ---------------------------------------------------------------------------- process(clk, reset) variable prev_ctrl : std_logic := '0'; begin if reset = '1' then ctrlIn_edge <= '0'; prev_ctrl := '0'; elsif rising_edge(clk) then ctrlIn_edge <= ctrlIn xor prev_ctrl; -- toggling handshake prev_ctrl := ctrlIn; end if; end process; end architecture Behavioral;
Editor is loading...
Leave a Comment