library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; library work; use work.reg32.all; use work.float.all; use work.task.all; entity sine is port ( clk : in std_logic; reset : in std_logic; task_start : in std_logic; task_state : out work.task.State; step_size : in work.reg32.word; phase : in work.reg32.word; amplitude : in work.reg32.word; signal_write : out std_logic; signal_writedata : out std_logic_vector(31 downto 0) ); end entity; architecture rtl of sine is -- Task FSM states 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; -- Rising-edge detector (only task_start_d is registered) signal task_start_d : std_logic := '0'; signal task_start_re : std_logic; -- float_sine IP core signal fs_data_valid : std_logic := '0'; signal fs_busy : std_logic; signal fs_result_valid : std_logic; signal fs_angle : signed(31 downto 0) := (others => '0'); signal fs_sine : signed(31 downto 0); -- Data pipeline signal angle_reg : signed(31 downto 0) := (others => '0'); signal sine_raw_fp : std_logic_vector(31 downto 0) := (others => '0'); signal sine_scaled_fp : std_logic_vector(31 downto 0) := (others => '0'); -- Calculation FSM type calc_state_t is ( C_IDLE, C_PREPARE, C_START, C_WAIT, C_SCALE, C_WRITE ); signal calc_state : calc_state_t := C_IDLE; -- Pipeline warm-up fix (CORDIC output invalid on first result_valid) signal first_result_seen : std_logic := '0'; begin -- combinational rising-edge detect (1-cycle faster than registered pulse) task_start_re <= task_start and not task_start_d; -- Output current task state task_state <= current_task_state; -- Task FSM (combinational) task_fsm : 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) 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; -- float_sine instantiation fs_angle <= angle_reg; u_float_sine : entity work.float_sine generic map ( ITERATIONS => 8 ) port map ( clk => clk, reset => reset, data_valid => fs_data_valid, busy => fs_busy, result_valid => fs_result_valid, angle => fs_angle, sine => fs_sine ); sync : process(clk, reset) variable sin_exp : unsigned(7 downto 0); variable amp_exp : unsigned(7 downto 0); variable new_exp : unsigned(7 downto 0); variable sin_e_i : integer; variable amp_e_i : integer; variable new_e_i : integer; begin if reset = '1' then current_task_state <= work.task.TASK_IDLE; index <= 0; task_start_d <= '0'; calc_state <= C_IDLE; angle_reg <= (others => '0'); sine_raw_fp <= (others => '0'); sine_scaled_fp <= (others => '0'); fs_data_valid <= '0'; signal_write <= '0'; signal_writedata <= (others => '0'); first_result_seen <= '0'; elsif rising_edge(clk) then task_start_d <= task_start; -- Default outputs signal_write <= '0'; fs_data_valid <= '0'; -- Update Task FSM 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 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; -- Calculation FSM case calc_state is when C_IDLE => if current_task_state = work.task.TASK_RUNNING then angle_reg <= signed(phase); first_result_seen <= '0'; calc_state <= C_PREPARE; end if; when C_PREPARE => calc_state <= C_START; when C_START => if fs_busy = '0' then fs_data_valid <= '1'; calc_state <= C_WAIT; end if; when C_WAIT => if fs_result_valid = '1' then if first_result_seen = '0' then first_result_seen <= '1'; angle_reg <= angle_reg + signed(step_size); calc_state <= C_START; else sine_raw_fp <= std_logic_vector(fs_sine); calc_state <= C_SCALE; end if; end if; when C_SCALE => sin_exp := unsigned(sine_raw_fp(30 downto 23)); amp_exp := unsigned(amplitude(30 downto 23)); sin_e_i := to_integer(sin_exp); amp_e_i := to_integer(amp_exp); new_e_i := sin_e_i + (amp_e_i - 127); if new_e_i < 0 then new_exp := (others => '0'); else new_exp := to_unsigned(new_e_i, 8); end if; sine_scaled_fp(31) <= sine_raw_fp(31); sine_scaled_fp(30 downto 23) <= std_logic_vector(new_exp); sine_scaled_fp(22 downto 0) <= sine_raw_fp(22 downto 0); calc_state <= C_WRITE; when C_WRITE => signal_write <= '1'; signal_writedata <= sine_scaled_fp; if index = work.task.STREAM_LEN - 1 then calc_state <= C_IDLE; else angle_reg <= angle_reg + signed(step_size); calc_state <= C_START; end if; end case; end if; end process; end architecture;