library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; library work; use work.reg32.all; use work.task.all; entity add is port ( clk : in std_logic; reset : in std_logic; task_start : in std_logic; task_state : out work.task.State; signal_a_read : out std_logic; signal_a_readdata : in std_logic_vector(31 downto 0); signal_b_read : out std_logic; signal_b_readdata : in std_logic_vector(31 downto 0); signal_write : out std_logic; signal_writedata : out std_logic_vector(31 downto 0) ); end entity add; architecture rtl of add is -- Task FSM signal current_task_state : work.task.State := work.task.TASK_IDLE; signal next_task_state : work.task.State := work.task.TASK_IDLE; signal index : integer range 0 to work.task.STREAM_LEN-1 := 0; -- task_start rising edge detect (combinational pulse) signal task_start_d : std_logic := '0'; signal task_start_re : std_logic; -- float_add IP core signal fa_start : std_logic := '0'; signal fa_done : std_logic := '0'; signal fa_sum : std_logic_vector(31 downto 0); signal a_value : std_logic_vector(31 downto 0) := (others => '0'); signal b_value : std_logic_vector(31 downto 0) := (others => '0'); -- Calc FSM type calc_state_t is ( C_IDLE, C_READ_A, C_READ_B, C_START_ADD, C_WAIT_ADD, C_WRITE_RESULT ); signal calc_state : calc_state_t := C_IDLE; begin -- combinational rising edge detect task_start_re <= task_start and not task_start_d; task_state <= current_task_state; -- float_add instance u_float_add : entity work.float_add port map ( A => a_value, B => b_value, clk => clk, reset => reset, start => fa_start, done => fa_done, sum => fa_sum ); -- Task FSM transitions (ONLY driver of next_task_state) task_state_transitions : process(current_task_state, task_start_re, index, calc_state) begin next_task_state <= current_task_state; case current_task_state is when work.task.TASK_IDLE => if task_start_re = '1' then next_task_state <= work.task.TASK_RUNNING; end if; when work.task.TASK_RUNNING => if (index = work.task.STREAM_LEN - 1) and (calc_state = C_WRITE_RESULT) then next_task_state <= work.task.TASK_DONE; end if; when work.task.TASK_DONE => if task_start_re = '1' then next_task_state <= work.task.TASK_RUNNING; end if; end case; end process; -- Synchronous process sync : process(clk, reset) begin if reset = '1' then current_task_state <= work.task.TASK_IDLE; index <= 0; task_start_d <= '0'; calc_state <= C_IDLE; fa_start <= '0'; signal_a_read <= '0'; signal_b_read <= '0'; signal_write <= '0'; signal_writedata <= (others => '0'); a_value <= (others => '0'); b_value <= (others => '0'); elsif rising_edge(clk) then -- register delayed start for edge detect task_start_d <= task_start; -- defaults signal_a_read <= '0'; signal_b_read <= '0'; signal_write <= '0'; fa_start <= '0'; -- update task state current_task_state <= next_task_state; -- index update case current_task_state is when work.task.TASK_IDLE => index <= 0; when work.task.TASK_RUNNING => if calc_state = C_WRITE_RESULT then if index < work.task.STREAM_LEN - 1 then index <= index + 1; end if; end if; when work.task.TASK_DONE => index <= 0; end case; -- calc FSM case calc_state is when C_IDLE => if current_task_state = work.task.TASK_RUNNING then calc_state <= C_READ_A; end if; when C_READ_A => signal_a_read <= '1'; a_value <= signal_a_readdata; calc_state <= C_READ_B; when C_READ_B => signal_b_read <= '1'; b_value <= signal_b_readdata; calc_state <= C_START_ADD; when C_START_ADD => fa_start <= '1'; calc_state <= C_WAIT_ADD; when C_WAIT_ADD => fa_start <= '1'; if fa_done = '1' then calc_state <= C_WRITE_RESULT; end if; when C_WRITE_RESULT => signal_write <= '1'; signal_writedata <= fa_sum; if index = work.task.STREAM_LEN - 1 then calc_state <= C_IDLE; else calc_state <= C_READ_A; end if; end case; end if; end process; end architecture rtl;