2026-01-13 09:57:40 +01:00

262 lines
9.6 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; --Startsignal
task_state : out work.task.State; --Ausgang
step_size : in work.reg32.word; --Winkelinkrement pro Sample
phase : in work.reg32.word; --Startwinkel
amplitude : in work.reg32.word; --Amplitude
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 := 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 := 0;
--Flanken-Erkennung
signal task_start_d : std_logic := '0';
signal task_start_re : std_logic := '0';
--float_sine-IP-core
signal fs_data_valid : std_logic := '0'; --eingabe
signal fs_busy : std_logic; -- Steuerung
signal fs_result_valid : std_logic;
signal fs_angle : signed(31 downto 0) := (others => '0');
signal fs_sine : signed(31 downto 0); --Ausgabe
--Datenpfad
signal angle_reg : signed(31 downto 0) := (others => '0'); --aktueller Winkel
signal sine_raw_fp : std_logic_vector(31 downto 0) := (others => '0'); --Ergebnis des IP-Cores
signal sine_scaled_fp : std_logic_vector(31 downto 0) := (others => '0'); --skaliertes Ergebnis
--Calc-FSM
type calc_state_t is (
C_IDLE,
C_START,
C_WAIT,
C_SCALE,
C_WRITE
);
signal calc_state : calc_state_t := C_IDLE;
begin
task_state <= current_task_state;
--------------------------------------------------------------------------
-- Task-FSM transitions
--------------------------------------------------------------------------
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 ) 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, --Eingabe starten
busy => fs_busy, --Core arbeitet
result_valid => fs_result_valid, --Ergebnis fertig
angle => fs_angle, --Eingabewinkel
sine => fs_sine --Ergebnis
);
--------------------------------------------------------------------------
-- Sync / Datenpfad
--------------------------------------------------------------------------
--Multiplikation über: neuer_exponent = sin_exp + (amp_exp -127)
sync : process(clk, reset)
variable sin_exp : unsigned(7 downto 0); --Speichern Sinuszahl
variable amp_exp : unsigned(7 downto 0); --Speichern Amplitude
variable new_exp : unsigned(7 downto 0); --Speichern neuen Exponenten
--Exponenten als Integerwerte für Berechnung
variable sin_e_i : integer range -255 to 511;
variable amp_e_i : integer range -255 to 511;
variable new_e_i : integer range -255 to 511;
begin
if reset = '1' then
current_task_state <= work.task.TASK_IDLE;
index <= 0;
task_start_d <= '0';
task_start_re <= '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');
elsif rising_edge(clk) then
------------------------------------------------------------------
-- rising edge detect
------------------------------------------------------------------
task_start_re <= task_start and not task_start_d;
task_start_d <= task_start;
------------------------------------------------------------------
-- Defaults
------------------------------------------------------------------
signal_write <= '0';
fs_data_valid <= '0';
------------------------------------------------------------------
-- Task-FSM update
------------------------------------------------------------------
current_task_state <= next_task_state;
------------------------------------------------------------------
-- Berechnungs-FSM
------------------------------------------------------------------
case calc_state is
------------------------------------------------------------------
-- Start: Sofort mit erstem Winkel beginnen
------------------------------------------------------------------
when C_IDLE =>
if (current_task_state = work.task.TASK_RUNNING) then
angle_reg <= signed(phase);
calc_state <= C_START;
end if;
------------------------------------------------------------------
-- Wert in den Core laden, sobald busy='0'
------------------------------------------------------------------
when C_START =>
if fs_busy = '0' then --Wenn Core ist frei
fs_data_valid <= '1'; --Input-Latch im Core
calc_state <= C_WAIT;
end if;
------------------------------------------------------------------
-- Warten auf Ergebnis
------------------------------------------------------------------
when C_WAIT => --Warten auf Ergebnis
if fs_result_valid = '1' then
sine_raw_fp <= std_logic_vector(fs_sine);
calc_state <= C_SCALE;
end if;
------------------------------------------------------------------
-- Skalierung
------------------------------------------------------------------
when C_SCALE =>
sin_exp := unsigned(sine_raw_fp(30 downto 23)); --Liest die 8 Exponentenbits des Sinuswerts
amp_exp := unsigned(amplitude(30 downto 23)); --Liese die 8 der Amplitude
sin_e_i := to_integer(sin_exp); --Umwandlung in Integer
amp_e_i := to_integer(amp_exp);
new_e_i := sin_e_i + (amp_e_i - 127); --Eigentliche Multiplikation
if new_e_i < 0 then -- Falls Wert negativ
new_exp := (others => '0'); --Setze Wert auf 0
else
new_exp := to_unsigned(new_e_i, 8); --Zurückwandeln in 8-Bit-Exponent
end if;
--Berechnten Exponenten wieder zusammensetzen
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;
------------------------------------------------------------------
-- Schreiben + nächsten Winkel
------------------------------------------------------------------
when C_WRITE =>
signal_write <= '1';
signal_writedata <= sine_scaled_fp;
if index = work.task.STREAM_LEN then
calc_state <= C_IDLE;
else
angle_reg <= angle_reg + signed(step_size);
calc_state <= C_START;
end if;
end case;
------------------------------------------------------------------
-- Index update
------------------------------------------------------------------
case next_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 then
index <= index + 1;
end if;
end if;
when work.task.TASK_DONE =>
index <= 0;
end case;
end if;
end process;
end architecture rtl;