Untitled

 avatar
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