2026-01-13 10:05:02 +01:00

214 lines
7.7 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 sine;
architecture rtl of sine is
-- Task-FSM
signal current_task_state : work.task.State;
signal next_task_state : work.task.State;
-- Zähler
signal samples_requested : integer range 0 to work.task.STREAM_LEN + 1;
signal samples_written : integer range 0 to work.task.STREAM_LEN + 1;
-- Winkel-Register
signal angle_current : signed(31 downto 0);
signal step_value : signed(31 downto 0);
-- float_sine IP-Core Signale
signal core_data_valid : std_logic;
signal core_busy : std_logic;
signal core_result_valid : std_logic;
--signal core_angle : signed(31 downto 0);
signal core_sine_out : signed(31 downto 0);
-- Zustandsmaschine für Ablaufsteuerung
type calc_state_type is (IDLE, REQUEST, WAIT_RESULT, WRITE);
signal calc_state : calc_state_type;
begin
-------------------------------------------------------------------------
-- Task-State-Transitions (NICHT ÄNDERN laut Aufgabe)
-------------------------------------------------------------------------
task_state_transitions : process (current_task_state, task_start, samples_written) is
begin
next_task_state <= current_task_state;
case current_task_state is
when work.task.TASK_IDLE =>
if task_start = '1' then
next_task_state <= work.task.TASK_RUNNING;
end if;
when work.task.TASK_RUNNING =>
if samples_written >= work.task.STREAM_LEN+1 then
next_task_state <= work.task.TASK_DONE;
end if;
when work.task.TASK_DONE =>
if task_start = '1' then
next_task_state <= work.task.TASK_RUNNING;
end if;
end case;
end process;
task_state <= current_task_state;
-------------------------------------------------------------------------
-- float_sine IP-Core instanzieren
-------------------------------------------------------------------------
float_sine_inst : entity work.float_sine
generic map (
ITERATIONS => 16
)
port map (
clk => clk,
reset => reset,
data_valid => core_data_valid,
angle => angle_current,
busy => core_busy,
result_valid => core_result_valid,
sine => core_sine_out
);
-------------------------------------------------------------------------
-- Kombinatorischer Prozess: Skalierung
-------------------------------------------------------------------------
scale_output : process (core_sine_out, amplitude) is
variable sine_word : std_logic_vector(31 downto 0);
variable amp_word : std_logic_vector(31 downto 0);
variable expo_sine : unsigned(7 downto 0);
variable expo_amp : unsigned(7 downto 0);
variable expo_result : unsigned(7 downto 0);
variable scaled_word : std_logic_vector(31 downto 0);
begin
-- Float-Werte als std_logic_vector
sine_word := std_logic_vector(core_sine_out);
amp_word := amplitude;
-- Exponenten extrahieren
expo_sine := unsigned(sine_word(30 downto 23));
expo_amp := unsigned(amp_word(30 downto 23));
-- Neuer Exponent = Expo(Sine) + (Expo(Amplitude) - 127)
expo_result := expo_sine + (expo_amp - to_unsigned(127, 8));
-- Skaliertes Ergebnis: Sign + Mantisse unverändert, nur Exponent ersetzen
scaled_word := sine_word;
scaled_word(30 downto 23) := std_logic_vector(expo_result);
signal_writedata <= scaled_word;
end process;
-------------------------------------------------------------------------
-- Synchroner Prozess: Ablaufsteuerung
-------------------------------------------------------------------------
sync : process (clk, reset) is
begin
if reset = '1' then
current_task_state <= work.task.TASK_IDLE;
samples_requested <= 0;
samples_written <= 0;
angle_current <= (others => '0');
step_value <= (others => '0');
core_data_valid <= '0';
signal_write <= '0';
calc_state <= IDLE;
elsif rising_edge(clk) then
-- Task-State übernehmen
current_task_state <= next_task_state;
-- Defaults
signal_write <= '0';
core_data_valid <= '0';
case current_task_state is
when work.task.TASK_IDLE =>
samples_requested <= 0;
samples_written <= 0;
angle_current <= signed(phase);
step_value <= signed(step_size);
calc_state <= IDLE;
when work.task.TASK_RUNNING =>
-- Zustandsmaschine für die Berechnung
case calc_state is
when IDLE =>
-- Starte erste Berechnung
if samples_requested < work.task.STREAM_LEN+1 then
core_data_valid <= '1';
samples_requested <= samples_requested + 1;
calc_state <= WAIT_RESULT;
end if;
when WAIT_RESULT =>
-- Warte auf Ergebnis
if core_result_valid = '1' and core_busy = '0' then
-- Inkrementiere Winkel NACH dem Schreiben für nächste Berechnung
angle_current <= angle_current + step_value;
calc_state <= WRITE;
end if;
when WRITE =>
if samples_written = 0 then
calc_state <= REQUEST;
samples_written <= samples_written + 1;
else
signal_write <= '1';
samples_written <= samples_written + 1;
calc_state <= REQUEST;
end if;
when REQUEST =>
-- Starte nächste Berechnung nur wenn Core nicht busy ist
if samples_requested < work.task.STREAM_LEN +1 and core_busy = '0' then
core_data_valid <= '1';
samples_requested <= samples_requested + 1;
calc_state <= WAIT_RESULT;
elsif samples_requested >= work.task.STREAM_LEN then
calc_state <= IDLE;
end if;
end case;
when work.task.TASK_DONE =>
calc_state <= IDLE;
end case;
end if;
end process;
end architecture rtl;