diff --git a/libraries/dsp/si/hdllib.cfg b/libraries/dsp/si/hdllib.cfg
new file mode 100755
index 0000000000000000000000000000000000000000..218fb87f7a66bf69a85dd6ab648f882d3ccb7dbc
--- /dev/null
+++ b/libraries/dsp/si/hdllib.cfg
@@ -0,0 +1,21 @@
+hdl_lib_name = si
+hdl_library_clause_name = si_lib
+hdl_lib_uses_synth = common dp
+hdl_lib_uses_sim = 
+hdl_lib_technology = 
+
+synth_files = 
+    src/vhdl/si.vhd 
+ 
+test_bench_files = 
+    tb/vhdl/tb_si.vhd 
+
+regression_test_vhdl = 
+    #tb/vhdl/tb_si.vhd   -- tb is not self checking yet
+
+
+[modelsim_project_file]
+
+
+[quartus_project_file]
+
diff --git a/libraries/dsp/si/src/vhdl/si.vhd b/libraries/dsp/si/src/vhdl/si.vhd
new file mode 100755
index 0000000000000000000000000000000000000000..e0350848a3909f2077298b5de9ed479041481a6e
--- /dev/null
+++ b/libraries/dsp/si/src/vhdl/si.vhd
@@ -0,0 +1,127 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2020
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--
+-- Author: E. Kooistra
+-- Purpose: Spectral inversion.
+-- Description:
+--   In the even Nyquist zones the sampled spectrum gets flipped in frequency.
+--   This flip can be compensated for by a spectral inversion (SI). When
+--   enabled the SI multiplies the input samples by (-1)**n = +1, -1, ...,
+--   where n = 0 is the first sample in the FFT block. For more information
+--   see section 4.19 in LOFAR_ASTRON_SDD_018_RSP_Firmware_DD.pdf.
+-- Remark:
+-- . Ported from LOFAR1 rsp
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+ENTITY si IS
+  GENERIC (
+    g_dat_w     : NATURAL := 18;
+    g_si_dat_w  : NATURAL := 12
+  );
+  PORT (
+    in_dat_x    : IN  STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
+    in_dat_y    : IN  STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
+    in_val      : IN  STD_LOGIC;
+    in_sync     : IN  STD_LOGIC;
+    out_dat_x   : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
+    out_dat_y   : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
+    out_val     : OUT STD_LOGIC;
+    out_sync    : OUT STD_LOGIC;
+    si_en_x     : IN  STD_LOGIC;
+    si_en_y     : IN  STD_LOGIC;
+    clk         : IN  STD_LOGIC;
+    rst         : IN  STD_LOGIC
+  );
+END si;
+
+ARCHITECTURE rtl OF si IS
+
+  CONSTANT c_dat_max   : INTEGER :=  2**(g_si_dat_w-1)-1;
+  CONSTANT c_dat_min   : INTEGER := -2**(g_si_dat_w-1);
+  
+  SIGNAL nxt_out_dat_x : STD_LOGIC_VECTOR(out_dat_x'RANGE);
+  SIGNAL nxt_out_dat_y : STD_LOGIC_VECTOR(out_dat_y'RANGE);
+  SIGNAL plus      : STD_LOGIC;
+  SIGNAL nxt_plus  : STD_LOGIC;
+  SIGNAL plus_x    : STD_LOGIC;
+  SIGNAL plus_y    : STD_LOGIC;
+
+BEGIN
+
+  reg_si : PROCESS(rst,clk)
+  BEGIN
+    IF rst='1' THEN
+      out_dat_x <= (OTHERS => '0');
+      out_dat_y <= (OTHERS => '0');
+      out_val   <= '0';
+      out_sync  <= '0';
+      plus      <= '1';
+    ELSIF rising_edge(clk) THEN
+      out_dat_x <= nxt_out_dat_x;
+      out_dat_y <= nxt_out_dat_y;
+      out_val   <= in_val;
+      out_sync  <= in_sync;
+      plus      <= nxt_plus;
+    END IF;
+  END PROCESS;
+    
+  si_control : PROCESS (plus, in_sync, in_val)
+  BEGIN
+    nxt_plus <= plus;
+    IF in_sync = '1' THEN
+      nxt_plus <= '1';
+    ELSIF in_val = '1' THEN
+      nxt_plus <= NOT plus;
+    END IF;
+  END PROCESS;
+  
+  plus_x <= plus WHEN si_en_x = '1' ELSE '1';
+  plus_y <= plus WHEN si_en_y = '1' ELSE '1';
+
+  si_data_x : PROCESS (plus_x, in_dat_x)
+  BEGIN
+    nxt_out_dat_x <= in_dat_x;
+    IF plus_x = '0' THEN
+      nxt_out_dat_x <= STD_LOGIC_VECTOR(-SIGNED(in_dat_x));
+      -- Clip -c_dat_min to c_dat_max instead of wrapping to c_dat_min
+      IF SIGNED(in_dat_x) = c_dat_min THEN
+        nxt_out_dat_x <= STD_LOGIC_VECTOR(TO_SIGNED(c_dat_max, g_dat_w));
+      END IF;
+    END IF;
+  END PROCESS;
+  
+  si_data_y : PROCESS (plus_y, in_dat_y)
+  BEGIN
+    nxt_out_dat_y <= in_dat_y;
+    IF plus_y = '0' THEN
+      nxt_out_dat_y <= STD_LOGIC_VECTOR(-SIGNED(in_dat_y));
+      -- Clip -c_dat_min to c_dat_max instead of wrapping to c_dat_min
+      IF SIGNED(in_dat_y) = c_dat_min THEN
+        nxt_out_dat_y <= STD_LOGIC_VECTOR(TO_SIGNED(c_dat_max, g_dat_w));
+      END IF;
+    END IF;
+  END PROCESS;
+END rtl;
diff --git a/libraries/dsp/si/tb/vhdl/tb_si.vhd b/libraries/dsp/si/tb/vhdl/tb_si.vhd
new file mode 100755
index 0000000000000000000000000000000000000000..273e124c70e63b4e27ba9a1bf5e28e9296af65ce
--- /dev/null
+++ b/libraries/dsp/si/tb/vhdl/tb_si.vhd
@@ -0,0 +1,160 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2020
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--
+-- Author: E. Kooistra
+-- Purpose: Spectral inversion.
+-- Description:
+--   Test bench for si.vhd.
+-- Remark:
+-- . Ported from LOFAR1 rsp
+-- . The tb is self-stopping, but not self checking.
+
+LIBRARY IEEE, si_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+ENTITY tb_si IS
+END tb_si;
+
+ARCHITECTURE tb OF tb_si IS
+
+  CONSTANT c_clk_period   : TIME := 10 ns;
+
+  CONSTANT c_dat_w        : NATURAL := 5;
+  CONSTANT c_si_dat_w     : NATURAL := 5;
+
+  SIGNAL in_dat_x       : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
+  SIGNAL in_dat_y       : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
+  SIGNAL nxt_in_dat_x   : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
+  SIGNAL nxt_in_dat_y   : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
+  SIGNAL in_val         : STD_LOGIC;
+  SIGNAL in_sync        : STD_LOGIC;
+  SIGNAL out_dat_x      : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
+  SIGNAL out_dat_y      : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
+  SIGNAL out_val        : STD_LOGIC;
+  SIGNAL out_sync       : STD_LOGIC;
+  SIGNAL si_en_x        : STD_LOGIC;
+  SIGNAL si_en_y        : STD_LOGIC;
+  SIGNAL clk            : STD_LOGIC := '1';
+  SIGNAL rst            : STD_LOGIC;
+  SIGNAL tb_end         : STD_LOGIC := '0';
+
+  SIGNAL toggle         : STD_LOGIC;
+  SIGNAL nxt_toggle     : STD_LOGIC;
+
+BEGIN
+
+  rst <= '1', '0' AFTER c_clk_period;
+  clk <= NOT(clk) OR tb_end AFTER c_clk_period/2;          -- test bench clock
+  
+  u_si : ENTITY si_lib.si
+  GENERIC MAP(
+    g_dat_w     => c_dat_w,
+    g_si_dat_w  => c_si_dat_w
+  )
+  PORT MAP(
+    in_dat_x    => in_dat_x,
+    in_dat_y    => in_dat_y,
+    in_val      => in_val,
+    in_sync     => in_sync,
+    out_dat_x   => out_dat_x,
+    out_dat_y   => out_dat_y,
+    out_val     => out_val,
+    out_sync    => out_sync,
+    si_en_x     => si_en_x,
+    si_en_y     => si_en_y,
+    clk         => clk,
+    rst         => rst
+  );
+  
+  reg_stimuli : PROCESS(rst, clk)
+  BEGIN
+    IF rst='1' THEN
+      in_dat_x <= (OTHERS => '0');
+      in_dat_y <= (OTHERS => '0');
+      toggle   <= '0';
+    ELSIF rising_edge(clk) THEN
+      in_dat_x <= nxt_in_dat_x;
+      in_dat_y <= nxt_in_dat_y;
+      toggle   <= nxt_toggle;
+    END IF;
+  END PROCESS;
+
+  nxt_toggle <= NOT toggle;
+  
+  data_counter : PROCESS (toggle, in_dat_x, in_dat_y)
+  BEGIN
+    nxt_in_dat_x <= in_dat_x;
+    nxt_in_dat_y <= in_dat_y;
+    IF toggle = '1' THEN
+      nxt_in_dat_x <= STD_LOGIC_VECTOR(SIGNED(in_dat_x)+3);
+      nxt_in_dat_y <= STD_LOGIC_VECTOR(SIGNED(in_dat_y)+3);
+    END IF;
+  END PROCESS;
+  
+  PROCESS
+  BEGIN
+    si_en_x <= '1';
+    si_en_y <= '1';
+    in_sync <= '0';
+    in_val  <= '0';
+    WAIT FOR 10*c_clk_period;
+    
+    -- sync followed by valid data
+    in_sync <= '1';
+    in_val  <= '0';
+    WAIT FOR c_clk_period;
+    in_sync <= '0';
+    in_val  <= '1';
+    WAIT FOR 99*c_clk_period;
+    
+    -- insert a single valid low cycle
+    in_sync <= '0';
+    in_val  <= '0';
+    WAIT FOR c_clk_period;
+    in_sync <= '0';
+    in_val  <= '1';
+    WAIT FOR 99*c_clk_period;
+        
+    -- insert an out of phase resync cycle
+    in_sync <= '1';
+    in_val  <= '1';
+    WAIT FOR c_clk_period;
+    in_sync <= '0';
+    in_val  <= '1';
+    WAIT FOR 99*c_clk_period;
+    
+    -- insert an in phase resync cycle
+    in_sync <= '1';
+    in_val  <= '1';
+    WAIT FOR c_clk_period;
+    in_sync <= '0';
+    in_val  <= '1';
+    WAIT FOR 99*c_clk_period;
+    
+    tb_end <= '1';
+    WAIT;
+    
+  END PROCESS;
+  
+END tb;
+