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;