Untitled

 avatar
unknown
plain_text
20 days ago
11 kB
14
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,
        DATA_READY_PULSE,
        DONE
    );
    signal curState, nextState : fsm_state := IDLE;
 
    signal dataReady_int : std_logic := '0';
    signal seqDone_int : std_logic := '0';
    signal processing_done : boolean := false;
 
    ------------------------------------------------------------------------
    -- 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(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';
 
    ------------------------------------------------------------------------
    -- 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;
 
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 <= DATA_READY_PULSE;
                else
                    nextState <= REQUEST_BYTE;
                end if;
 
            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);
    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'));
 
                dataReady <= '0';
                seqDone <= '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(6) <= std_logic_vector(prev_samples(2));
                            dataResults(5) <= std_logic_vector(prev_samples(1));
                            dataResults(4) <= std_logic_vector(prev_samples(0));
                            dataResults(3) <= data;  -- the new peak
 
                            -- clear out the next 3 positions
                            dataResults(2) <= (others => '0');
                            dataResults(1) <= (others => '0');
                            dataResults(0) <= (others => '0');
                            post_count <= 3;
 
                        elsif post_count > 0 then
                            dataResults(post_count - 1) <= data;
                            post_count <= post_count - 1;
                        end if;
 
                        -- increment global sample counter
                        counter <= counter + 1;
                        byte <= std_logic_vector(peak_value);
 
                    when DATA_READY_PULSE =>
                        dataReady <= '1';
                        -- 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));
                        sedDone <= '1';
 
                    when others =>
                        null;
 
                end case;
            end if;
        end if;
    end process;
 
    process(clk)
    begin
        if rising_edge(clk) then
            if reset = '1' then
                processing_done <= false;
            else
                processing_done <= (counter >= nWords-1) and (curState = LATCH_DATA);
            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
 
end architecture Behavioral;
 
Editor is loading...
Leave a Comment