Lösung Praktikum HW/SW

This commit is contained in:
pfeiffjo103624 2026-01-13 10:05:02 +01:00
parent c90753aa23
commit b5e28ecc9d
7 changed files with 527 additions and 87 deletions

View File

@ -15,59 +15,215 @@ entity add is
task_state : out work.task.State;
signal_a_read : out std_logic;
signal_a_readdata : in std_logic_vector( 31 downto 0 );
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_readdata : in std_logic_vector(31 downto 0);
signal_write : out std_logic;
signal_writedata : out std_logic_vector( 31 downto 0 )
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;
-------------------------------------------------------------------------
-- 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;
current_add_state <= ADD_IDLE;
index <= 0;
elsif ( rising_edge( clk ) ) then
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
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;
signal_write <= '0';
when work.task.TASK_RUNNING =>
index <= index + 1;
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 <= ( others => '0' );
signal_writedata <= result_sum;
index <= index + 1;
end case;
when work.task.TASK_DONE =>
index <= 0;
signal_write <= '0';
null;
end case;
end if;
end process sync;
@ -75,3 +231,4 @@ begin
task_state <= current_task_state;
end architecture rtl;

View File

@ -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 =>
@ -49,23 +57,85 @@ begin
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;
crc_value <= CRC32_INIT;
bit_counter <= 0;
proc_state <= IDLE;
signal_read <= '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';
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;
@ -73,4 +143,3 @@ begin
task_state <= current_task_state;
end architecture rtl;

View File

@ -20,58 +20,194 @@ entity sine is
amplitude : in work.reg32.word;
signal_write : out std_logic;
signal_writedata : out std_logic_vector( 31 downto 0 )
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;
-- 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;

View File

@ -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;
}

View File

@ -2,9 +2,45 @@
#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;
}

View File

@ -1,10 +1,35 @@
#include "system/task_sine.h"
#include "system/data_channel.h"
#include "system/float_word.h"
#include <math.h>
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;
}

View File

@ -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 ) {