diff --git a/hardware/signal_processing/add.vhd b/hardware/signal_processing/add.vhd index 3e7315a..0746746 100644 --- a/hardware/signal_processing/add.vhd +++ b/hardware/signal_processing/add.vhd @@ -26,52 +26,139 @@ entity add is end entity add; architecture rtl of add is + + type AddState is (z0_ADD_IDLE, z1_ADD_READ_FIFO, z2_ADD_CALC, z3_ADD_STORE_RESULT); + 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; + + -- Interne Signale für die Verbindung zur float_add Komponente + signal internal_start : std_logic; + signal internal_done : std_logic; + signal internal_sum : std_logic_vector(31 downto 0); + + -- Signal für den internen Additions-Status + signal current_calc_state : AddState; begin - 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 - next_task_state <= work.task.TASK_RUNNING; - end if; - when work.task.TASK_RUNNING => - if ( index = 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_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; + u_float_add : entity work.float_add + port map( + clk => clk, + reset => reset, + start => internal_start, + done => internal_done, + A => signal_a_readdata, + B => signal_b_readdata, + sum => internal_sum + ); - task_state <= current_task_state; + task_state_transition : 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 + next_task_state <= work.task.TASK_RUNNING; + end if; + when work.task.TASK_RUNNING => + 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 + next_task_state <= work.task.TASK_RUNNING; + end if; + end case; + end process task_state_transition; + + + sync : process (clk, reset) is + begin + if (reset = '1') then + current_task_state <= work.task.TASK_IDLE; + index <= 0; + + -- Reset + current_calc_state <= z1_ADD_READ_FIFO; + internal_start <= '0'; + signal_a_read <= '0'; + signal_b_read <= '0'; + signal_write <= '0'; + + elsif (rising_edge(clk)) then + current_task_state <= next_task_state; + + -- defaults für Steuersignale + signal_a_read <= '0'; + signal_b_read <= '0'; + signal_write <= '0'; + internal_start <= '0'; + + case next_task_state is + when work.task.TASK_IDLE => + index <= 0; + --signal_write <= '0'; + current_calc_state <= z1_ADD_READ_FIFO; -- Reset für nächsten Lauf + when work.task.TASK_RUNNING => + --index <= index + 1; + --signal_write <= '1'; + --signal_writedata <= (others => '0'); + + -- Sub State Machine + case current_calc_state is + + when z1_ADD_READ_FIFO => + -- Daten aus den FIFOs anfordern + if (index < work.task.STREAM_LEN) then + current_calc_state <= z2_ADD_CALC; + end if; + + when z2_ADD_CALC => + internal_start <= '1'; + + -- Warten bis float_add 'done' meldet + if (internal_done = '1') then + internal_start <= '0'; -- Trigger wegnehmen + current_calc_state <= z3_ADD_STORE_RESULT; + else + -- Bleibe hier und warte + current_calc_state <= z2_ADD_CALC; + end if; + + when z3_ADD_STORE_RESULT => + -- Ergebnis schreiben + signal_write <= '1'; + signal_writedata <= internal_sum; + + -- nicht in Schritt z1_ADD_READ_FIFO!! + signal_a_read <= '1'; + signal_b_read <= '1'; + + -- Index erhöhen + index <= index + 1; + + -- Zurück zum Lesen für das nächste Paar + current_calc_state <= z1_ADD_READ_FIFO; + + when others => + current_calc_state <= z1_ADD_READ_FIFO; + end case; + + when work.task.TASK_DONE => + index <= 0; + signal_write <= '0'; + + + end case; + end if; + end process sync; + + task_state <= current_task_state; end architecture rtl; + + + + diff --git a/hardware/signal_processing/rand.vhd b/hardware/signal_processing/rand.vhd index 3a229f3..ff69444 100644 --- a/hardware/signal_processing/rand.vhd +++ b/hardware/signal_processing/rand.vhd @@ -26,7 +26,11 @@ architecture rtl of rand is signal next_task_state : work.task.State; signal index : integer range 0 to work.task.STREAM_LEN; + -- Register für den LFSR Zustand + signal lfsr_reg : std_logic_vector(31 downto 0); + begin + task_state_transitions : process ( current_task_state, task_start, index ) is begin next_task_state <= current_task_state; @@ -36,7 +40,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 ) then next_task_state <= work.task.TASK_DONE; end if; when work.task.TASK_DONE => @@ -47,23 +51,60 @@ begin end process task_state_transitions; sync : process ( clk, reset ) is + variable v_feedback : std_logic; + variable v_lfsr_next : std_logic_vector(31 downto 0); + + variable v_send_cycle : boolean := true; -- toggle um signal_write nur einen Takt auszugeben begin if ( reset = '1' ) then current_task_state <= work.task.TASK_IDLE; index <= 0; + lfsr_reg <= (others => '0'); + signal_write <= '0'; + signal_writedata <= (others => '0'); + v_send_cycle := true; + 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; + signal_write <= '0'; + lfsr_reg <= seed; + v_send_cycle := true; -- Reset toggle für nächsten Start + when work.task.TASK_RUNNING => + if v_send_cycle = true then + index <= index + 1; + -- 1. LFSR Feedback berechnen (Polynom x^31 + x^21 + x^1 + 1) + v_feedback := lfsr_reg(31) xor lfsr_reg(21) xor lfsr_reg(1) xor lfsr_reg(0); + -- 2. Schieben und neues Bit einfügen + v_lfsr_next := lfsr_reg(30 downto 0) & v_feedback; + -- Register aktualisieren für den nächsten Takt + lfsr_reg <= v_lfsr_next; + -- 3. Daten schreiben und Bit-Manipulation + signal_write <= '1'; + -- Wir nutzen hier v_lfsr_next, damit der geschriebene Wert + -- dem aktuellen Berechnungsschritt entspricht. + if v_lfsr_next(30) = '1' then + -- Fall A: Bit 30 ist 1. Bits 29-24 löschen + -- Maske: AND mit 1100 0000 ... (0xC0...) + signal_writedata <= v_lfsr_next and x"C0FFFFFF"; + else + -- Fall B: Bit 30 ist 0. Bits 29-25 setzen + -- Maske: OR mit 0011 1110 ... (0x3E...) + signal_writedata <= v_lfsr_next or x"3E000000"; + end if; + + v_send_cycle := false; + else + signal_write <= '0'; + v_send_cycle := true; + end if; + + when work.task.TASK_DONE => + index <= 0; + signal_write <= '0'; end case; end if; end process sync; @@ -71,3 +112,4 @@ begin task_state <= current_task_state; end architecture rtl; + diff --git a/hardware/signal_processing/sine.vhd b/hardware/signal_processing/sine.vhd index 36fb916..99a0232 100644 --- a/hardware/signal_processing/sine.vhd +++ b/hardware/signal_processing/sine.vhd @@ -25,12 +25,38 @@ entity sine is end entity sine; architecture rtl of sine is + + type SineState is(S_IDLE, S_CALC_START, S_WAIT_CALC, S_WRITE); + signal current_sine_state : SineState; + + signal s_data_valid : std_logic; + signal s_angle : signed(31 downto 0); + signal s_busy : std_logic; + signal s_result_valid : std_logic; + signal s_sine_out : signed(31 downto 0); + + signal current_angle_reg : unsigned(31 downto 0); signal current_task_state : work.task.State; signal next_task_state : work.task.State; signal index : integer range 0 to work.task.STREAM_LEN; begin + + u_float_sine : entity work.float_sine + generic map ( + ITERATIONS => 8 + ) + port map ( + clk => clk, + reset => reset, + data_valid => s_data_valid, + angle => s_angle, + busy => s_busy, + result_valid => s_result_valid, + sine => s_sine_out + ); + task_state_transitions : process ( current_task_state, task_start, index ) is begin next_task_state <= current_task_state; @@ -40,7 +66,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 ) then next_task_state <= work.task.TASK_DONE; end if; when work.task.TASK_DONE => @@ -51,20 +77,79 @@ begin end process task_state_transitions; sync : process ( clk, reset ) is + + variable v_exp_sine : unsigned(7 downto 0); + variable v_exp_amp : unsigned(7 downto 0); + variable v_exp_new : unsigned(7 downto 0); begin if ( reset = '1' ) then current_task_state <= work.task.TASK_IDLE; index <= 0; + + signal_write <= '0'; + signal_writedata <= (others => '0'); + + s_data_valid <= '0'; + s_angle <= (others => '0'); + current_angle_reg <= (others => '0'); + + current_sine_state <= S_IDLE; + elsif ( rising_edge( clk ) ) then current_task_state <= next_task_state; + + signal_write <= '0'; + s_data_valid <= '0'; + 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_IDLE => + index <= 0; + + current_sine_state <= S_CALC_START; + current_angle_reg <= unsigned(phase); + + when work.task.TASK_RUNNING => + case current_sine_state is + when S_CALC_START => + + s_data_valid <= '1'; + s_angle <= signed(current_angle_reg); + + if s_busy = '1' then + s_data_valid <= '0'; -- startpulse beenden + index <= index + 1; + current_sine_state <= S_WAIT_CALC; + end if; + + when S_WAIT_CALC => + if s_result_valid = '1' and s_busy = '0' then + current_sine_state <= S_WRITE; + end if; + when S_WRITE => + v_exp_sine := unsigned(s_sine_out(30 downto 23)); -- nur Exponent (30-23) + v_exp_amp := unsigned(amplitude(30 downto 23)); + + -- (V)errechnen:E_neu = E_sin + E_amp - 127 (127 = bias/verschiebung) + v_exp_new := v_exp_sine + v_exp_amp - 127; + + -- ergebnis der mul von sinus und amplitude wieder zusammenstzen + -- da amp immer positiv ist, wird nur vorzeichen von s_sine_out verwendet + signal_writedata <= std_logic(s_sine_out(31)) & + std_logic_vector(v_exp_new) & + std_logic_vector(s_sine_out(22 downto 0)); + signal_write <= '1'; + + current_angle_reg <= current_angle_reg + unsigned(step_size); + + + current_sine_state <= S_CALC_START; + + when others => + current_sine_state <= S_CALC_START; + + end case; + + when work.task.TASK_DONE => index <= 0; signal_write <= '0'; @@ -75,3 +160,4 @@ begin task_state <= current_task_state; end architecture rtl; + diff --git a/software/signal_processing/add.c b/software/signal_processing/add.c index c0be7d1..7d5cec8 100644 --- a/software/signal_processing/add.c +++ b/software/signal_processing/add.c @@ -4,8 +4,24 @@ int task_add_run( void * task ) { - // TODO + add_config * config = ( add_config * ) task; + + for ( uint32_t i = 0; i < DATA_CHANNEL_DEPTH; ++i ) { + float sinus; + // & pointer Adresse von sinus + data_channel_read( config->sources[0], (uint32_t *) & sinus); + + float cosinus; + // & pointer Adresse von cosinus + data_channel_read( config->sources[1], (uint32_t *) & cosinus); + float_word result; + + result.value = sinus + cosinus; + + data_channel_write( config->sink, result.word); + } + return 0; } diff --git a/software/signal_processing/rand.c b/software/signal_processing/rand.c index d4fc0fd..34cdfba 100644 --- a/software/signal_processing/rand.c +++ b/software/signal_processing/rand.c @@ -1,11 +1,43 @@ -#include "system/task_rand.h" +#include "system/task_rand.h" #include "system/hardware_task.h" #include "system/data_channel.h" #include "system/float_word.h" +#include +#include int task_rand_run( void * task ) { - // TODO + rand_config * config = ( rand_config * ) task; + // seed auslesen (Startwert für Algorithmus) + float_word seed = { .value = config->seed }; + // LFSR (linear feedback shift register) + uint32_t lfsr = seed.word; + + for ( uint32_t i = 0; i < DATA_CHANNEL_DEPTH; ++i ) { + + // LFSR Algorithmus + // Polynom: x^31 + x^21 + x^1 + 1 + // Bits an Stellen 31, 21, 1 und 0 verknüpfen mit XOR + uint32_t bit = ((lfsr >> 31) ^ (lfsr >> 21) ^ (lfsr >> 1) ^ (lfsr >> 0)) & 1; + // Schiebe links und das neue Bit hinten anfügen + lfsr = (lfsr << 1) | bit; + + // IEEE 754 Bit-Manipulation für Exponenten + float_word res; + res.word = lfsr; + // Prüfe Bit 30 (das höchste Bit des Exponenten 127 bias) + if ( res.word & (1 << 30) ) { + // Fall: Hoher Exponent -> Bits 29 bis 24 auf 0 setzen + // Das erzeugt Werte im Bereich um 2^2 (z.B. 4.0 bis 8.0) + res.word &= ~(0x3F << 24); + } else { + // Fall: Niedriger Exponent -> Bits 29 bis 25 auf 1 zwingen + // Das erzeugt Werte im Bereich um 2^-3 (z.B. 0.125) + res.word |= (0x1F << 25); + } + + data_channel_write( config->base.sink, res.word ); + } return 0; } diff --git a/software/signal_processing/sine.c b/software/signal_processing/sine.c index 3eb3ce5..74a267f 100644 --- a/software/signal_processing/sine.c +++ b/software/signal_processing/sine.c @@ -1,10 +1,33 @@ #include "system/task_sine.h" #include "system/data_channel.h" #include "system/float_word.h" +#include "system/hardware_task.h" +#include "system/sine_config.h" + +#include +#include +#include +#include int task_sine_run( void * data ) { - // TODO + sine_config * task = ( sine_config * ) data; + + // Daten aus Konfig holen + uint32_t data_channel_base = task->base.sink; + double period_len = (double)task->samples_per_periode; + float amp = task->amplitude; + double phase = (double)task->phase; + + for ( uint32_t i = 0; i < DATA_CHANNEL_DEPTH; ++i ) { + float_word res; + + double angle = 2.0 * M_PI * ((double)i / period_len); + + res.value = amp * (float)sin(angle + phase); + + data_channel_write( data_channel_base, res.word); + } return 0; }