diff --git a/hardware/signal_processing/add.vhd b/hardware/signal_processing/add.vhd index 3e7315a..9b2d671 100644 --- a/hardware/signal_processing/add.vhd +++ b/hardware/signal_processing/add.vhd @@ -1,77 +1,195 @@ library ieee; - use ieee.std_logic_1164.all; - use ieee.numeric_std.all; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; library work; - use work.reg32.all; - use work.task.all; +use work.reg32.all; +use work.task.all; entity add is port ( - clk : in std_logic; - reset : in std_logic; + clk : in std_logic; + reset : in std_logic; - task_start : in std_logic; - task_state : out work.task.State; + 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 - signal current_task_state : work.task.State; - signal next_task_state : work.task.State; - signal index : integer range 0 to work.task.STREAM_LEN; + + -- 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-1 := 0; + + -- task_start rising edge detect (combinational pulse) + signal task_start_d : std_logic := '0'; + signal task_start_re : std_logic; + + -- float_add IP core + signal fa_start : std_logic := '0'; + signal fa_done : std_logic := '0'; + signal fa_sum : std_logic_vector(31 downto 0); + + signal a_value : std_logic_vector(31 downto 0) := (others => '0'); + signal b_value : std_logic_vector(31 downto 0) := (others => '0'); + + -- Calc FSM + type calc_state_t is ( + C_IDLE, + C_READ_A, + C_READ_B, + C_START_ADD, + C_WAIT_ADD, + C_WRITE_RESULT + ); + signal calc_state : calc_state_t := C_IDLE; 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; + -- combinational rising edge detect + task_start_re <= task_start and not task_start_d; task_state <= current_task_state; + -- float_add instance + u_float_add : entity work.float_add + port map ( + A => a_value, + B => b_value, + clk => clk, + reset => reset, + start => fa_start, + done => fa_done, + sum => fa_sum + ); + + -- Task FSM transitions (ONLY driver of next_task_state) + 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 - 1) and (calc_state = C_WRITE_RESULT) 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; + -- Synchronous process + sync : process(clk, reset) + begin + if reset = '1' then + + current_task_state <= work.task.TASK_IDLE; + index <= 0; + + task_start_d <= '0'; + + calc_state <= C_IDLE; + + fa_start <= '0'; + signal_a_read <= '0'; + signal_b_read <= '0'; + signal_write <= '0'; + + signal_writedata <= (others => '0'); + a_value <= (others => '0'); + b_value <= (others => '0'); + + elsif rising_edge(clk) then + + -- register delayed start for edge detect + task_start_d <= task_start; + + -- defaults + signal_a_read <= '0'; + signal_b_read <= '0'; + signal_write <= '0'; + fa_start <= '0'; + + -- update task state + current_task_state <= next_task_state; + + -- index update + case current_task_state is + when work.task.TASK_IDLE => + index <= 0; + + when work.task.TASK_RUNNING => + if calc_state = C_WRITE_RESULT then + if index < work.task.STREAM_LEN - 1 then + index <= index + 1; + end if; + end if; + + when work.task.TASK_DONE => + index <= 0; + end case; + + -- calc FSM + case calc_state is + + when C_IDLE => + if current_task_state = work.task.TASK_RUNNING then + calc_state <= C_READ_A; + end if; + + when C_READ_A => + signal_a_read <= '1'; + a_value <= signal_a_readdata; + calc_state <= C_READ_B; + + when C_READ_B => + signal_b_read <= '1'; + b_value <= signal_b_readdata; + calc_state <= C_START_ADD; + + when C_START_ADD => + fa_start <= '1'; + calc_state <= C_WAIT_ADD; + + when C_WAIT_ADD => + fa_start <= '1'; + if fa_done = '1' then + calc_state <= C_WRITE_RESULT; + end if; + + when C_WRITE_RESULT => + signal_write <= '1'; + signal_writedata <= fa_sum; + + if index = work.task.STREAM_LEN - 1 then + calc_state <= C_IDLE; + else + calc_state <= C_READ_A; + end if; + + end case; + + end if; + end process; + end architecture rtl; + diff --git a/hardware/signal_processing/rand.vhd b/hardware/signal_processing/rand.vhd index 3a229f3..5dc5b1a 100644 --- a/hardware/signal_processing/rand.vhd +++ b/hardware/signal_processing/rand.vhd @@ -1,10 +1,10 @@ library ieee; - use ieee.std_logic_1164.all; - use ieee.numeric_std.all; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; library work; - use work.reg32.all; - use work.task.all; +use work.reg32.all; +use work.task.all; entity rand is port ( @@ -16,17 +16,21 @@ entity rand is seed : 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 rand; architecture rtl of rand is - 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 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-1 := 0; + + signal lfsr : std_logic_vector(31 downto 0) := (others => '0'); begin + -- task_state_transitions task_state_transitions : process ( current_task_state, task_start, index ) is begin next_task_state <= current_task_state; @@ -45,29 +49,94 @@ begin end if; end case; end process task_state_transitions; - + sync : process ( clk, reset ) is + variable fb : std_logic; + variable lfsr_work : std_logic_vector(31 downto 0); + variable lfsr_next : std_logic_vector(31 downto 0); + + variable exp_rand : std_logic_vector(7 downto 0); + variable exp_new : std_logic_vector(7 downto 0); + variable out_word : std_logic_vector(31 downto 0); + + variable do_run : boolean; + variable entering : boolean; begin if ( reset = '1' ) then current_task_state <= work.task.TASK_IDLE; - index <= 0; - elsif ( rising_edge( clk ) ) then + index <= 0; + lfsr <= (others => '0'); + signal_write <= '0'; + signal_writedata <= (others => '0'); + + elsif rising_edge( clk ) then + -- State-Register 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; + + -- Defaults (wichtig für assert_level) + signal_write <= '0'; + signal_writedata <= (others => '0'); + + -- Datapath-Steuerung: + -- RUNNING-Aktionen ausführen, wenn + -- a) gerade RUNNING sind (auch wenn next schon DONE ist -> letztes Sample!) + -- b) in RUNNING eintreten (IDLE/DONE -> RUNNING) + entering := (current_task_state /= work.task.TASK_RUNNING) and (next_task_state = work.task.TASK_RUNNING); + do_run := (current_task_state = work.task.TASK_RUNNING) or entering; + + if do_run then + -- LFSR-Quelle: beim Eintritt seed, sonst aktueller lfsr + if entering then + lfsr_work := seed; + index <= 0; -- erstes Sample hat Index 0 + else + lfsr_work := lfsr; + end if; + + -- Output aus aktuellem Zustand bauen + exp_rand := lfsr_work(30 downto 23); + + if exp_rand(7) = '1' then + exp_new(7) := '1'; + exp_new(6 downto 1) := (others => '0'); + exp_new(0) := exp_rand(0); + else + exp_new(7) := '0'; + exp_new(6 downto 2) := (others => '1'); + exp_new(1 downto 0) := exp_rand(1 downto 0); + end if; + + out_word(31) := lfsr_work(31); + out_word(30 downto 23) := exp_new; + out_word(22 downto 0) := lfsr_work(22 downto 0); + + signal_write <= '1'; + signal_writedata <= out_word; + + -- LFSR Schritt nach Ausgabe + fb := lfsr_work(31) xor lfsr_work(21) xor lfsr_work(1) xor lfsr_work(0); + lfsr_next := lfsr_work(30 downto 0) & fb; + lfsr <= lfsr_next; + + -- Index nach Write erhöhen + if index < work.task.STREAM_LEN - 1 then + index <= index + 1; + end if; + + else + case current_task_state is + when work.task.TASK_IDLE => + index <= 0; + when work.task.TASK_DONE => + index <= 0; + when others => + null; + end case; + end if; 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..208df00 100644 --- a/hardware/signal_processing/sine.vhd +++ b/hardware/signal_processing/sine.vhd @@ -1,77 +1,256 @@ library ieee; - use ieee.std_logic_1164.all; - use ieee.numeric_std.all; +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; +use work.reg32.all; +use work.float.all; +use work.task.all; 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; +end entity; architecture rtl of sine is - signal current_task_state : work.task.State; - signal next_task_state : work.task.State; - signal index : integer range 0 to work.task.STREAM_LEN; + -- Task FSM states + + 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-1 := 0; + + -- Rising-edge detector (only task_start_d is registered) + signal task_start_d : std_logic := '0'; + signal task_start_re : std_logic; + + -- float_sine IP core + signal fs_data_valid : std_logic := '0'; + signal fs_busy : std_logic; + signal fs_result_valid : std_logic; + + signal fs_angle : signed(31 downto 0) := (others => '0'); + signal fs_sine : signed(31 downto 0); + + -- Data pipeline + + signal angle_reg : signed(31 downto 0) := (others => '0'); + signal sine_raw_fp : std_logic_vector(31 downto 0) := (others => '0'); + signal sine_scaled_fp : std_logic_vector(31 downto 0) := (others => '0'); + + -- Calculation FSM + + type calc_state_t is ( + C_IDLE, + C_PREPARE, + C_START, + C_WAIT, + C_SCALE, + C_WRITE + ); + signal calc_state : calc_state_t := C_IDLE; + + -- Pipeline warm-up fix (CORDIC output invalid on first result_valid) + signal first_result_seen : std_logic := '0'; 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; + -- combinational rising-edge detect (1-cycle faster than registered pulse) + task_start_re <= task_start and not task_start_d; + + -- Output current task state + task_state <= current_task_state; -end architecture rtl; + -- Task FSM (combinational) + + task_fsm : 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 - 1) 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, + busy => fs_busy, + result_valid => fs_result_valid, + angle => fs_angle, + sine => fs_sine + ); + + sync : process(clk, reset) + variable sin_exp : unsigned(7 downto 0); + variable amp_exp : unsigned(7 downto 0); + variable new_exp : unsigned(7 downto 0); + + variable sin_e_i : integer; + variable amp_e_i : integer; + variable new_e_i : integer; + begin + if reset = '1' then + + current_task_state <= work.task.TASK_IDLE; + index <= 0; + + task_start_d <= '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'); + + first_result_seen <= '0'; + + elsif rising_edge(clk) then + + task_start_d <= task_start; + + -- Default outputs + + signal_write <= '0'; + fs_data_valid <= '0'; + + -- Update Task FSM + current_task_state <= next_task_state; + + -- Index update + + case current_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 - 1 then + index <= index + 1; + end if; + end if; + + when work.task.TASK_DONE => + index <= 0; + + end case; + + -- Calculation FSM + + case calc_state is + + when C_IDLE => + if current_task_state = work.task.TASK_RUNNING then + angle_reg <= signed(phase); + first_result_seen <= '0'; + calc_state <= C_PREPARE; + end if; + + when C_PREPARE => + calc_state <= C_START; + + when C_START => + if fs_busy = '0' then + fs_data_valid <= '1'; + calc_state <= C_WAIT; + end if; + + when C_WAIT => + if fs_result_valid = '1' then + + + if first_result_seen = '0' then + first_result_seen <= '1'; + angle_reg <= angle_reg + signed(step_size); + calc_state <= C_START; + else + sine_raw_fp <= std_logic_vector(fs_sine); + calc_state <= C_SCALE; + end if; + + end if; + + when C_SCALE => + + sin_exp := unsigned(sine_raw_fp(30 downto 23)); + amp_exp := unsigned(amplitude(30 downto 23)); + + sin_e_i := to_integer(sin_exp); + amp_e_i := to_integer(amp_exp); + + new_e_i := sin_e_i + (amp_e_i - 127); + + if new_e_i < 0 then + new_exp := (others => '0'); + else + new_exp := to_unsigned(new_e_i, 8); + end if; + + 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; + + when C_WRITE => + + signal_write <= '1'; + signal_writedata <= sine_scaled_fp; + + if index = work.task.STREAM_LEN - 1 then + calc_state <= C_IDLE; + else + angle_reg <= angle_reg + signed(step_size); + calc_state <= C_START; + end if; + + end case; + end if; + end process; + +end architecture; + diff --git a/software/signal_processing/rand.c b/software/signal_processing/rand.c index d4fc0fd..ab26c3d 100644 --- a/software/signal_processing/rand.c +++ b/software/signal_processing/rand.c @@ -3,10 +3,37 @@ #include "system/data_channel.h" #include "system/float_word.h" -int task_rand_run( void * task ) { +int task_rand_run(void *task) +{ + rand_config *config = (rand_config *)task; - // TODO + uint32_t data_channel_base = config->base.sink; + data_channel_clear(data_channel_base); + + float_word seed_fw = { .value = config->seed }; + uint32_t lfsr = seed_fw.word; + + for (uint32_t i = 0; i < DATA_CHANNEL_DEPTH; ++i) { + + uint32_t sign = (lfsr >> 31) & 0x1u; + uint32_t mant = lfsr & 0x007FFFFFu; // 23 Bit Mantisse + uint32_t exp_rand = (lfsr >> 23) & 0xFFu; // 8 Bit Exponent + + uint32_t exp_new; + if (exp_rand & 0x80u) { + exp_new = 0x80u | (exp_rand & 0x01u); + } else { + exp_new = 0x7Cu | (exp_rand & 0x03u); + } + + float_word out; + out.word = (sign << 31) | (exp_new << 23) | mant; + + data_channel_write(data_channel_base, out.word); + + uint32_t fb = ((lfsr >> 31) ^ (lfsr >> 21) ^ (lfsr >> 1) ^ (lfsr >> 0)) & 0x1u; + lfsr = (lfsr << 1) | fb; + } return 0; } -