Untitled
unknown
plain_text
7 months ago
9.8 kB
4
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