From b5e28ecc9db5570050c0d25d3166b392c0e77330 Mon Sep 17 00:00:00 2001 From: pfeiffjo103624 Date: Tue, 13 Jan 2026 10:05:02 +0100 Subject: [PATCH] =?UTF-8?q?L=C3=B6sung=20Praktikum=20HW/SW?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hardware/signal_processing/add.vhd | 207 +++++++++++++++--- hardware/signal_processing/crc.vhd | 113 ++++++++-- hardware/signal_processing/sine.vhd | 202 ++++++++++++++--- software/signal_processing/add.c | 21 +- software/signal_processing/crc.c | 40 +++- software/signal_processing/sine.c | 29 ++- software/signal_processing/system/task_sine.c | 2 +- 7 files changed, 527 insertions(+), 87 deletions(-) diff --git a/hardware/signal_processing/add.vhd b/hardware/signal_processing/add.vhd index 3e7315a..34b4aeb 100644 --- a/hardware/signal_processing/add.vhd +++ b/hardware/signal_processing/add.vhd @@ -14,60 +14,216 @@ entity add is task_start : in std_logic; task_state : out work.task.State; - signal_a_read : out std_logic; - signal_a_readdata : in std_logic_vector( 31 downto 0 ); + signal_a_read : out std_logic; + signal_a_readdata : in std_logic_vector(31 downto 0); - signal_b_read : out std_logic; - signal_b_readdata : in std_logic_vector( 31 downto 0 ); + signal_b_read : out std_logic; + signal_b_readdata : in std_logic_vector(31 downto 0); - signal_write : out std_logic; - signal_writedata : out std_logic_vector( 31 downto 0 ) + signal_write : out std_logic; + signal_writedata : out std_logic_vector(31 downto 0) ); end entity add; architecture rtl of add is + + ------------------------------------------------------------------------- + -- äußere Task-FSM + ------------------------------------------------------------------------- signal current_task_state : work.task.State; - signal next_task_state : work.task.State; - signal index : integer range 0 to work.task.STREAM_LEN; + signal next_task_state : work.task.State; + signal index : integer range 0 to work.task.STREAM_LEN; + + ------------------------------------------------------------------------- + -- innere Add-FSM + ------------------------------------------------------------------------- + type AddState is ( + ADD_IDLE, -- wartet auf run_calc + ADD_REQ_SAMPLES, -- Read anfordern + ADD_WAIT_DATA, -- einen Takt warten, bis FIFO-Daten gültig sind + ADD_START, -- FIFO-Daten latches + float_add starten + ADD_WAIT_DONE, -- auf done vom float_add warten + ADD_WRITE -- Ergebnis in Senke schreiben + ); + + signal current_add_state : AddState; + signal next_add_state : AddState; + + -- float_add-Schnittstelle + signal start_calc : std_logic; + signal add_done : std_logic; + signal result_sum : std_logic_vector(31 downto 0); + + -- Operanden-Register für den Addierer + signal op_a_reg : std_logic_vector(31 downto 0); + signal op_b_reg : std_logic_vector(31 downto 0); + + -- Task läuft UND es sind noch Werte zu berechnen + signal run_calc : std_logic; begin + + ------------------------------------------------------------------------- + -- float_add mit registrierten Operanden instanzieren + ------------------------------------------------------------------------- + u_float_add : entity work.float_add + port map ( + clk => clk, + reset => reset, + start => start_calc, + A => op_a_reg, + B => op_b_reg, + done => add_done, + sum => result_sum + ); + + ------------------------------------------------------------------------- + -- äußere Task-State-Maschine + ------------------------------------------------------------------------- task_state_transitions : process ( current_task_state, task_start, index ) is begin next_task_state <= current_task_state; + case current_task_state is + when work.task.TASK_IDLE => - if ( task_start = '1' ) then + if task_start = '1' then next_task_state <= work.task.TASK_RUNNING; end if; + when work.task.TASK_RUNNING => - if ( index = work.task.STREAM_LEN - 1 ) then + -- wenn letztes Sample geschrieben wurde -> DONE + if index = work.task.STREAM_LEN then next_task_state <= work.task.TASK_DONE; end if; + when work.task.TASK_DONE => - if ( task_start = '1' ) then + if task_start = '1' then next_task_state <= work.task.TASK_RUNNING; end if; + end case; end process task_state_transitions; + -- Task läuft UND es sind noch Werte zu berechnen + run_calc <= '1' when (current_task_state = work.task.TASK_RUNNING + and index < work.task.STREAM_LEN) + else '0'; + + ------------------------------------------------------------------------- + -- innere Add-FSM: kombinatorischer Teil + ------------------------------------------------------------------------- + add_state_transitions : process ( current_add_state, run_calc, add_done, index ) is + begin + next_add_state <= current_add_state; + + case current_add_state is + + when ADD_IDLE => + if run_calc = '1' then + next_add_state <= ADD_REQ_SAMPLES; + end if; + + when ADD_REQ_SAMPLES => + -- Read-Impuls, Daten stehen im nächsten Takt an + next_add_state <= ADD_WAIT_DATA; + + when ADD_WAIT_DATA => + -- jetzt liegen die neuen FIFO-Werte stabil an, + -- im nächsten Zustand werden sie gelatcht + Addition gestartet + next_add_state <= ADD_START; + + when ADD_START => + -- Addierer starten, dann auf done warten + next_add_state <= ADD_WAIT_DONE; + + when ADD_WAIT_DONE => + if add_done = '1' then + next_add_state <= ADD_WRITE; + end if; + + when ADD_WRITE => + if index = work.task.STREAM_LEN then + next_add_state <= ADD_IDLE; + else + next_add_state <= ADD_REQ_SAMPLES; + end if; + + end case; + end process add_state_transitions; + + ------------------------------------------------------------------------- + -- synchroner Prozess: Zustände + tatsächliche Ausgänge + ------------------------------------------------------------------------- sync : process ( clk, reset ) is begin - if ( reset = '1' ) then + if reset = '1' then current_task_state <= work.task.TASK_IDLE; - index <= 0; - elsif ( rising_edge( clk ) ) then + current_add_state <= ADD_IDLE; + index <= 0; + + signal_a_read <= '0'; + signal_b_read <= '0'; + signal_write <= '0'; + signal_writedata <= (others => '0'); + start_calc <= '0'; + op_a_reg <= (others => '0'); + op_b_reg <= (others => '0'); + + elsif rising_edge(clk) then + -- Zustände übernehmen current_task_state <= next_task_state; - case next_task_state is - when work.task.TASK_IDLE => - index <= 0; - signal_write <= '0'; - when work.task.TASK_RUNNING => - index <= index + 1; - signal_write <= '1'; - signal_writedata <= ( others => '0' ); - when work.task.TASK_DONE => - index <= 0; - signal_write <= '0'; + current_add_state <= next_add_state; + + -- Default-Ausgänge pro Takt + signal_a_read <= '0'; + signal_b_read <= '0'; + signal_write <= '0'; + start_calc <= '0'; + + case current_task_state is + + when work.task.TASK_IDLE => + -- beim Warten Index zurücksetzen + index <= 0; + + when work.task.TASK_RUNNING => + case current_add_state is + + when ADD_IDLE => + null; + + when ADD_REQ_SAMPLES => + -- neuen Wert aus beiden FIFOs anfordern + signal_a_read <= '1'; + signal_b_read <= '1'; + -- FIFO-Daten latches und Addierer starten + op_a_reg <= signal_a_readdata; + op_b_reg <= signal_b_readdata; + + when ADD_WAIT_DATA => + -- nur warten, bis FIFO-Daten stabil sind + null; + + when ADD_START => + start_calc <= '1'; -- Start HIGH + + when ADD_WAIT_DONE => + -- Berechnung läuft weiter -> Start HIGH lassen, + -- bis add_done='1' ist + start_calc <= '1'; + + when ADD_WRITE => + -- Ergebnis schreiben und Index erhöhen + signal_write <= '1'; + signal_writedata <= result_sum; + index <= index + 1; + + end case; + + when work.task.TASK_DONE => + null; + end case; end if; end process sync; @@ -75,3 +231,4 @@ begin task_state <= current_task_state; end architecture rtl; + diff --git a/hardware/signal_processing/crc.vhd b/hardware/signal_processing/crc.vhd index cf51dcc..11d4119 100644 --- a/hardware/signal_processing/crc.vhd +++ b/hardware/signal_processing/crc.vhd @@ -1,7 +1,6 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; - library work; use work.reg32.all; use work.task.all; @@ -10,26 +9,35 @@ entity crc is port ( clk : in std_logic; reset : in std_logic; - task_start : in std_logic; task_state : out work.task.State; - signal_read : out std_logic; signal_readdata : in std_logic_vector( 31 downto 0 ); - signal_write : out std_logic; signal_writedata : out std_logic_vector( 31 downto 0 ) ); end entity crc; architecture rtl of crc is - + constant CRC32_POLY_REVERSED : std_logic_vector(31 downto 0) := x"EDB88320"; + constant CRC32_INIT : std_logic_vector(31 downto 0) := x"FFFFFFFF"; + signal current_task_state : work.task.State; signal next_task_state : work.task.State; signal index : integer range 0 to work.task.STREAM_LEN; - + + -- CRC Berechnung + signal crc_value : std_logic_vector(31 downto 0); + + -- Zustandsmaschine für CRC-Berechnung + signal bit_counter : integer range 0 to 32; + signal word_buffer : std_logic_vector(31 downto 0); + + type processing_state_t is (IDLE, READ_WAIT, COMPUTE); + signal proc_state : processing_state_t; + begin - task_state_transitions : process ( current_task_state, task_start, index ) is + task_state_transitions : process ( current_task_state, task_start, index, proc_state ) is begin next_task_state <= current_task_state; case current_task_state is @@ -38,7 +46,7 @@ begin next_task_state <= work.task.TASK_RUNNING; end if; when work.task.TASK_RUNNING => - if ( index = work.task.STREAM_LEN - 1 ) then + if ( index = work.task.STREAM_LEN and proc_state = IDLE ) then next_task_state <= work.task.TASK_DONE; end if; when work.task.TASK_DONE => @@ -47,30 +55,91 @@ begin end if; end case; end process task_state_transitions; - + sync : process ( clk, reset ) is + variable crc_temp : std_logic_vector(31 downto 0); + variable bit_in : std_logic; begin if ( reset = '1' ) then current_task_state <= work.task.TASK_IDLE; index <= 0; + crc_value <= CRC32_INIT; + bit_counter <= 0; + proc_state <= IDLE; + signal_read <= '0'; + signal_write <= '0'; + signal_writedata <= (others => '0'); + word_buffer <= (others => '0'); + elsif ( rising_edge( clk ) ) then current_task_state <= next_task_state; + case next_task_state is - when work.task.TASK_IDLE => - index <= 0; - signal_write <= '0'; - when work.task.TASK_RUNNING => - index <= index + 1; - signal_write <= '1'; - signal_writedata <= ( others => '0' ); - when work.task.TASK_DONE => - index <= 0; - signal_write <= '0'; + when work.task.TASK_IDLE => + index <= 0; + crc_value <= CRC32_INIT; + bit_counter <= 0; + proc_state <= IDLE; + signal_read <= '0'; + signal_write <= '0'; + + when work.task.TASK_RUNNING => + signal_write <= '0'; + + case proc_state is + when IDLE => + if index < work.task.STREAM_LEN then + -- Leseanfrage starten + signal_read <= '1'; + proc_state <= READ_WAIT; + end if; + + when READ_WAIT => + -- Daten sind jetzt verfügbar (nach 1 Takt) + signal_read <= '0'; + word_buffer <= signal_readdata; + bit_counter <= 0; + proc_state <= COMPUTE; + + when COMPUTE => + -- Bitweise CRC berechnen (32 Bits pro Wort, LSB first) + if bit_counter < 32 then + crc_temp := crc_value; + + -- Bit aus word_buffer extrahieren (LSB first) + bit_in := word_buffer(bit_counter); + + -- CRC Update für ein Bit + if (crc_temp(0) xor bit_in) = '1' then + crc_temp := ('0' & crc_temp(31 downto 1)) xor CRC32_POLY_REVERSED; + else + crc_temp := '0' & crc_temp(31 downto 1); + end if; + + crc_value <= crc_temp; + bit_counter <= bit_counter + 1; + else + -- Wort fertig verarbeitet, nächstes Wort + index <= index + 1; + proc_state <= IDLE; + end if; + end case; + + when work.task.TASK_DONE => + -- Finales CRC schreiben (invertiert) + if proc_state = IDLE then + signal_write <= '1'; + signal_writedata <= not crc_value; + signal_read <= '0'; + else + signal_write <= '0'; + proc_state <= IDLE; + end if; + end case; end if; end process sync; - + task_state <= current_task_state; - + end architecture rtl; - diff --git a/hardware/signal_processing/sine.vhd b/hardware/signal_processing/sine.vhd index 36fb916..23b532b 100644 --- a/hardware/signal_processing/sine.vhd +++ b/hardware/signal_processing/sine.vhd @@ -9,69 +9,205 @@ library work; entity sine is port ( - clk : in std_logic; + 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; + phase : in work.reg32.word; amplitude : in work.reg32.word; - signal_write : out std_logic; - signal_writedata : out std_logic_vector( 31 downto 0 ) + 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; - signal index : integer range 0 to work.task.STREAM_LEN; + 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 : process ( current_task_state, task_start, index ) is + + ------------------------------------------------------------------------- + -- 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 + if task_start = '1' then next_task_state <= work.task.TASK_RUNNING; end if; + when work.task.TASK_RUNNING => - if ( index = work.task.STREAM_LEN - 1 ) then + 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 + if task_start = '1' then next_task_state <= work.task.TASK_RUNNING; end if; end case; - end process task_state_transitions; - - sync : process ( clk, reset ) is - begin - if ( reset = '1' ) then - current_task_state <= work.task.TASK_IDLE; - index <= 0; - elsif ( rising_edge( clk ) ) then - current_task_state <= next_task_state; - case next_task_state is - when work.task.TASK_IDLE => - index <= 0; - signal_write <= '0'; - when work.task.TASK_RUNNING => - index <= index + 1; - signal_write <= '1'; - signal_writedata <= ( others => '0' ); - when work.task.TASK_DONE => - index <= 0; - signal_write <= '0'; - end case; - end if; - end process sync; + 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; diff --git a/software/signal_processing/add.c b/software/signal_processing/add.c index c0be7d1..4ae409c 100644 --- a/software/signal_processing/add.c +++ b/software/signal_processing/add.c @@ -2,9 +2,26 @@ #include "system/data_channel.h" #include "system/float_word.h" -int task_add_run( void * task ) { +int task_add_run( void * task ) +{ + // Die Task-Einstellungen liegen als task_base_config vor + task_base_config *config = (task_base_config *) task; - // TODO + for (uint32_t i = 0; i < DATA_CHANNEL_DEPTH; i++) { + + float_word a, b, c; + + // aus Quelle 0 lesen + data_channel_read(config->sources[0], &a.word); + // aus Quelle 1 lesen + data_channel_read(config->sources[1], &b.word); + + // Addition der beiden Float-Werte + c.value = a.value + b.value; + + // Ergebnis in den Ziel-Data-Channel schreiben + data_channel_write(config->sink, c.word); + } return 0; } diff --git a/software/signal_processing/crc.c b/software/signal_processing/crc.c index e214b9e..fc4cc06 100644 --- a/software/signal_processing/crc.c +++ b/software/signal_processing/crc.c @@ -2,10 +2,46 @@ #include "system/data_channel.h" #include "system/float_word.h" -int task_crc_run( void * task ) { +#define CRC32_POLY_REVERSED 0xEDB88320u - // TODO +// CRC32-Update über ein komplettes 32-bit Wort (LSB-first) +static inline uint32_t crc32_update_word(uint32_t crc, uint32_t word) +{ + for (int i = 0; i < 4; i++) + { + uint8_t b = (word >> (8 * i)) & 0xFF; // LSB first! + crc ^= b; + for (int j = 0; j < 8; j++) + { + if (crc & 1) + crc = (crc >> 1) ^ CRC32_POLY_REVERSED; + else + crc >>= 1; + } + } + return crc; +} +int task_crc_run(void *task) +{ + crc_config *config = (crc_config*)task; + + // WICHTIG: Startwert invertieren (wie im PDF Seite 14 beschrieben) + uint32_t crc = ~config->start; // = ~0xFFFFFFFF = 0x00000000 + + for (uint32_t i = 0; i < DATA_CHANNEL_DEPTH; i++) + { + uint32_t word; + data_channel_read(config->base.sources[0], &word); + crc = crc32_update_word(crc, word); + } + + // Endwert invertieren (zlib-Standard) + crc = ~crc; + + // Ergebnis schreiben + data_channel_write(config->base.sink, crc); + return 0; } diff --git a/software/signal_processing/sine.c b/software/signal_processing/sine.c index 3eb3ce5..6d46928 100644 --- a/software/signal_processing/sine.c +++ b/software/signal_processing/sine.c @@ -1,10 +1,35 @@ #include "system/task_sine.h" #include "system/data_channel.h" #include "system/float_word.h" +#include -int task_sine_run( void * data ) { +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif - // TODO +int task_sine_run(void *data) +{ + sine_config *task = (sine_config *) data; + + uint32_t data_channel_base = task->base.sink; + data_channel_clear(data_channel_base); + + float amplitude = task->amplitude; + float phase_rad = task->phase * (float)M_PI / 180.0f; + float step = 2.0f * (float)M_PI / (float)task->samples_per_periode; + + for (uint32_t i = 0; i < DATA_CHANNEL_DEPTH; i++) + { + float angle = phase_rad + i * step; + float y = amplitude * sinf(angle); + + float_word res; + res.value = y; + + data_channel_write(data_channel_base, res.word); + } return 0; } + + diff --git a/software/signal_processing/system/task_sine.c b/software/signal_processing/system/task_sine.c index bd3f30e..9450adc 100644 --- a/software/signal_processing/system/task_sine.c +++ b/software/signal_processing/system/task_sine.c @@ -37,7 +37,7 @@ sine_config COSINE_CONFIG = { .sink = DATA_CHANNEL_1_BASE, .cycle_count = 0 }, .samples_per_periode = 200, - .phase = M_PI / 2.0, + .phase = 90.0, .amplitude = 2.0 }; uint32_t to_hardware_step_size( uint32_t steps ) {