beckal87649 4d0bb79521 4.Test
2026-01-13 10:53:22 +01:00

257 lines
7.2 KiB
VHDL

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;