summaryrefslogtreecommitdiffstats
path: root/fpga/hw-v2/src
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/hw-v2/src')
-rw-r--r--fpga/hw-v2/src/mt_filter/mt_fil_mac_slow.vhd146
-rw-r--r--fpga/hw-v2/src/mt_filter/mt_fil_storage_slow.vhd403
-rw-r--r--fpga/hw-v2/src/mt_filter/mt_filter.vhd46
-rw-r--r--fpga/hw-v2/src/mt_filter/mt_fir_symmetric_slow.vhd219
-rw-r--r--fpga/hw-v2/src/mt_toolbox/mt_clktools.vhd151
-rw-r--r--fpga/hw-v2/src/mt_toolbox/mt_toolbox.vhd182
-rw-r--r--fpga/hw-v2/src/testbench/tb_filter.vhd131
-rw-r--r--fpga/hw-v2/src/testbench/tb_usbrx.vhd356
-rw-r--r--fpga/hw-v2/src/usbrx/datapath/usbrx_ad7357.vhd299
-rw-r--r--fpga/hw-v2/src/usbrx/datapath/usbrx_decimate.vhd218
-rw-r--r--fpga/hw-v2/src/usbrx/datapath/usbrx_offset.vhd105
-rw-r--r--fpga/hw-v2/src/usbrx/datapath/usbrx_ssc.vhd191
-rw-r--r--fpga/hw-v2/src/usbrx/filter/usbrx_halfband.vhd505
-rw-r--r--fpga/hw-v2/src/usbrx/toplevel/usbrx_clkgen.vhd165
-rw-r--r--fpga/hw-v2/src/usbrx/toplevel/usbrx_pwm.vhd100
-rw-r--r--fpga/hw-v2/src/usbrx/toplevel/usbrx_regbank.vhd194
-rw-r--r--fpga/hw-v2/src/usbrx/toplevel/usbrx_spi.vhd215
-rw-r--r--fpga/hw-v2/src/usbrx/toplevel/usbrx_toplevel.vhd331
-rw-r--r--fpga/hw-v2/src/usbrx/usbrx.vhd66
19 files changed, 4023 insertions, 0 deletions
diff --git a/fpga/hw-v2/src/mt_filter/mt_fil_mac_slow.vhd b/fpga/hw-v2/src/mt_filter/mt_fil_mac_slow.vhd
new file mode 100644
index 0000000..603b72a
--- /dev/null
+++ b/fpga/hw-v2/src/mt_filter/mt_fil_mac_slow.vhd
@@ -0,0 +1,146 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : mt_fil_mac_slow.vhd
+-- Project : maintech filter toolbox
+-- Purpose : MAC cell for FIR-like filters
+-- - version for 'slow' filter versions
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+-- mt_fil_mac_slow ------------------------------------------------------------
+-------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.mt_filter.all;
+
+entity mt_fil_mac_slow is
+ port (
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- control-path
+ start : in std_logic;
+ active : in std_logic;
+ presub : in std_logic;
+
+ -- data input
+ smp1 : in fir_dataword18;
+ smp2 : in fir_dataword18;
+ coeff : in fir_dataword18;
+
+ -- data output
+ dnew : out std_logic;
+ dout : out fir_dataword18
+ );
+end mt_fil_mac_slow;
+
+architecture rtl of mt_fil_mac_slow is
+
+ -- rounding constant (16 bits will get truncated)
+ constant RNDVAL : natural := (2**16/2);
+
+ -- control signals
+ signal done : std_logic;
+ signal active_del : std_logic_vector(2 downto 0);
+ signal start_del : std_logic_vector(2 downto 0);
+ signal done_del : std_logic_vector(2 downto 0);
+
+ -- data registers
+ signal psreg : std_logic;
+ signal dreg : signed(17 downto 0);
+ signal b0reg : signed(17 downto 0);
+ signal b1reg : signed(18 downto 0);
+ signal a0reg : signed(17 downto 0);
+ signal a1reg : signed(17 downto 0);
+ signal mreg : signed(35 downto 0);
+ signal preg : signed(35 downto 0);
+
+begin
+
+ -- create done-flag after 'active' goes low or 'start' is set while still active
+ done <= (start or (not active)) and active_del(0);
+
+ -- create delayed control-signals
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ active_del <= active_del(active_del'left-1 downto 0) & active;
+ start_del <= start_del(start_del'left-1 downto 0) & start;
+ done_del <= done_del(done_del'left-1 downto 0) & done;
+ end if;
+ end process;
+
+ -- do math
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ -- simple storage registers
+ psreg <= presub;
+ dreg <= smp1;
+ b0reg <= smp2;
+ a0reg <= coeff;
+ a1reg <= a0reg;
+
+ -- pre-adder
+ if psreg='1'
+ then b1reg <= resize(b0reg,19) - resize(dreg,19);
+ else b1reg <= resize(b0reg,19) + resize(dreg,19);
+ end if;
+
+ -- multiplier
+ mreg <= a1reg * b1reg(18 downto 1);
+
+ -- post-adder / accumulator
+ if active_del(2)='1' then
+ if start_del(2)='1'
+ then preg <= mreg + to_signed(RNDVAL,36);
+ else preg <= mreg + preg;
+ end if;
+ end if;
+ end if;
+ end process;
+
+ -- update output
+ process(reset, clk)
+ begin
+ if reset='1' then
+ dnew <= '0';
+ dout <= (others=>'0');
+ elsif rising_edge(clk) then
+ if done_del(2)='1' then
+ dnew <= '1';
+ if preg(35)='0' and preg(34 downto 33)/="00" then
+ dout <= to_signed(2**17-1,18);
+ elsif preg(35)='1' and preg(34 downto 33)/="11" then
+ dout <= to_signed(-(2**17),18);
+ else
+ dout <= preg(33 downto 16);
+ end if;
+ else
+ dnew <= '0';
+ end if;
+ end if;
+ end process;
+end rtl;
diff --git a/fpga/hw-v2/src/mt_filter/mt_fil_storage_slow.vhd b/fpga/hw-v2/src/mt_filter/mt_fil_storage_slow.vhd
new file mode 100644
index 0000000..05f4eae
--- /dev/null
+++ b/fpga/hw-v2/src/mt_filter/mt_fil_storage_slow.vhd
@@ -0,0 +1,403 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : mt_fil_storage_slow.vhd
+-- Project : maintech filter toolbox
+-- Purpose : basic data storage for FIR-like filters
+-- - version for 'slow' filter versions
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+-- mt_fil_dstorage_slow ------------------------------------------------------
+-------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.mt_filter.all;
+
+entity mt_fil_dstorage_slow is
+ generic (
+ CHANNELS : natural;
+ DEPTH : natural;
+ RAMSTYLE : string
+ );
+ port (
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- control
+ chan : in unsigned(log2(CHANNELS)-1 downto 0);
+ load : in std_logic;
+ start : in std_logic;
+ stop : in std_logic;
+ active : in std_logic;
+
+ -- datapath
+ din : in fir_dataword18;
+ dout1 : out fir_dataword18;
+ dout2 : out fir_dataword18
+ );
+end mt_fil_dstorage_slow;
+
+architecture rtl of mt_fil_dstorage_slow is
+
+ --
+ -- types & rams
+ --
+
+ -- derived constants
+ constant MEMSIZE : natural := CHANNELS * DEPTH;
+
+ -- internal types
+ subtype offset_t is unsigned(log2(DEPTH)-1 downto 0);
+ subtype addr_t is unsigned(log2(MEMSIZE)-1 downto 0);
+ subtype data_t is fir_dataword18;
+ type atab_t is array(CHANNELS-1 downto 0) of addr_t;
+ type pram_t is array(CHANNELS-1 downto 0) of offset_t;
+ type sram_t is array(MEMSIZE-1 downto 0) of data_t;
+
+ -- create address tables
+ function get_addr_tab return atab_t is
+ variable res : atab_t;
+ begin
+ for i in res'range loop
+ res(i) := to_unsigned(i*DEPTH, addr_t'length);
+ end loop;
+ return res;
+ end get_addr_tab;
+ constant addr_tab : atab_t := get_addr_tab;
+
+ -- ram ports
+ signal sram1_we : std_logic;
+ signal sram1_waddr : addr_t;
+ signal sram1_wdata : data_t;
+ signal sram1_re : std_logic;
+ signal sram1_raddr : addr_t;
+ signal sram1_rdata : data_t := (others=>'0');
+ signal sram2_we : std_logic;
+ signal sram2_waddr : addr_t;
+ signal sram2_wdata : data_t;
+ signal sram2_re : std_logic;
+ signal sram2_raddr : addr_t;
+ signal sram2_rdata : data_t := (others=>'0');
+
+ -- actual rams
+ signal pram : pram_t := (others=>(others=>'0'));
+ signal sram1 : sram_t := (others=>(others=>'0'));
+ signal sram2 : sram_t := (others=>(others=>'0'));
+
+ -- configure rams
+ attribute syn_ramstyle of pram : signal is "logic";
+ attribute syn_ramstyle of sram1 : signal is RAMSTYLE;
+ attribute syn_ramstyle of sram2 : signal is RAMSTYLE&",no_rw_check";
+
+
+ --
+ -- status
+ --
+
+ -- delayed control signals
+ signal start_del : std_logic_vector(1 downto 0);
+ signal load_del : std_logic_vector(2 downto 0);
+ signal active_del : std_logic_vector(1 downto 0);
+ signal stop_del : std_logic_vector(2 downto 0);
+
+ -- status
+ signal selchan : unsigned(log2(CHANNELS)-1 downto 0);
+ signal baseaddr : addr_t;
+ signal woffset : offset_t;
+ signal roffset1 : offset_t;
+ signal roffset2 : offset_t;
+
+begin
+
+ -- validate generics
+ assert DEPTH>1
+ report "mt_fil_dstorage_slow: DEPTH must be larger than 1"
+ severity FAILURE;
+
+ -- control logic
+ process(clk, reset)
+ variable offset : offset_t;
+ begin
+ if reset='1' then
+ start_del <= (others=>'0');
+ load_del <= (others=>'0');
+ active_del <= (others=>'0');
+ stop_del <= (others=>'0');
+ selchan <= (others=>'0');
+ baseaddr <= (others=>'0');
+ woffset <= (others=>'0');
+ roffset1 <= (others=>'0');
+ roffset2 <= (others=>'0');
+ sram1_re <= '0';
+ sram1_we <= '0';
+ sram1_raddr <= (others=>'0');
+ sram1_waddr <= (others=>'0');
+ sram1_wdata <= (others=>'0');
+ sram2_re <= '0';
+ sram2_we <= '0';
+ sram2_raddr <= (others=>'0');
+ sram2_waddr <= (others=>'0');
+ sram2_wdata <= (others=>'0');
+ elsif rising_edge(clk) then
+ -- set default values
+ sram1_re <= '0';
+ sram1_we <= '0';
+ sram2_re <= '0';
+ sram2_we <= '0';
+
+ -- create delayed flags
+ start_del <= start_del(start_del'left-1 downto 0) & start;
+ load_del <= load_del(load_del'left-1 downto 0) & load;
+ active_del <= active_del(active_del'left-1 downto 0) & active;
+ stop_del <= stop_del(stop_del'left-1 downto 0) & stop;
+
+ -- init status on start of burst
+ if start='1' then
+ -- remember channel
+ selchan <= chan;
+
+ -- get base-address for selected channels
+ baseaddr <= addr_tab(to_integer(chan));
+
+ -- init pointers
+ offset := pram(to_integer(chan));
+ woffset <= offset;
+ roffset1 <= offset;
+ if offset=(DEPTH-1)
+ then roffset2 <= to_unsigned(0,roffset2'length);
+ else roffset2 <= offset + 1;
+ end if;
+ end if;
+
+ -- store sample into ram and increment write-pointer if 'load'-flag is set
+ if load_del(0)='1' then
+ -- write sample into ram
+ sram1_we <= '1';
+ sram1_waddr <= baseaddr + woffset;
+ sram1_wdata <= din;
+
+ -- update write-pointer
+ woffset <= roffset2; -- 'roffset2' is actually "((woffset+1) mod DEPTH)" here
+ end if;
+ if load_del(1)='1' then
+ -- write-back updated write-pointer
+ pram(to_integer(selchan)) <= woffset;
+ end if;
+
+ -- carry sample from sram1 into sram2 if 'stop'-flag is set
+ if load_del(1)='1' then
+ sram2_waddr <= baseaddr + woffset;
+ end if;
+ if stop_del(2)='1' then
+ sram2_we <= '1';
+ sram2_wdata <= sram1_rdata;
+ end if;
+
+ -- issue read-requests when active
+ if active_del(0)='1' then
+ -- read samples from ram
+ sram1_re <= '1';
+ sram2_re <= '1';
+ sram1_raddr <= baseaddr + roffset1;
+ sram2_raddr <= baseaddr + roffset2;
+
+ -- update read-pointers
+ if roffset1=0
+ then roffset1 <= to_unsigned(DEPTH-1,roffset1'length);
+ else roffset1 <= roffset1 - 1;
+ end if;
+ if roffset2=(DEPTH-1)
+ then roffset2 <= to_unsigned(0,roffset2'length);
+ else roffset2 <= roffset2 + 1;
+ end if;
+ end if;
+
+ end if;
+ end process;
+
+ -- set output
+ dout1 <= sram1_rdata when load_del(2)='0' else din;
+ dout2 <= sram2_rdata;
+
+ -- infer rams
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if sram1_we='1' then
+ sram1(to_integer(sram1_waddr)) <= sram1_wdata;
+ end if;
+ if sram1_re='1' then
+ sram1_rdata <= sram1(to_integer(sram1_raddr));
+ end if;
+ if sram2_we='1' then
+ sram2(to_integer(sram2_waddr)) <= sram2_wdata;
+ end if;
+ if sram2_re='1' then
+ sram2_rdata <= sram2(to_integer(sram2_raddr));
+ end if;
+ end if;
+ end process;
+
+end rtl;
+
+
+
+-------------------------------------------------------------------------------
+-- mt_fil_storage_slow --------------------------------------------------------
+-------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.mt_filter.all;
+
+entity mt_fil_storage_slow is
+ generic (
+ COEFFS : fir_coefficients; -- coefficients
+ DCHAN : natural; -- number of data channels
+ TAPS : natural; -- number of samples in each segment
+ RAMSTYLE : string; -- ram style for inferred memories
+ ROMSTYLE : string -- ram style for coefficent rom
+ );
+ port (
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- config
+ chan : in unsigned(log2(DCHAN)-1 downto 0);
+
+ -- input
+ in_load : in std_logic;
+ in_start : in std_logic;
+ in_stop : in std_logic;
+ in_active : in std_logic;
+ in_data : in fir_dataword18;
+
+ -- output
+ out_load : out std_logic;
+ out_start : out std_logic;
+ out_stop : out std_logic;
+ out_active : out std_logic;
+ out_data1 : out fir_dataword18;
+ out_data2 : out fir_dataword18;
+ out_coeff : out fir_dataword18
+ );
+end mt_fil_storage_slow;
+
+architecture rtl of mt_fil_storage_slow is
+
+ -- status
+ signal del_load : std_logic_vector(1 downto 0);
+ signal del_start : std_logic_vector(1 downto 0);
+ signal del_stop : std_logic_vector(1 downto 0);
+ signal del_active : std_logic_vector(1 downto 0);
+ signal cind : unsigned(log2(TAPS)-1 downto 0);
+
+ -- coeff rom
+ constant rom_size : natural := 1 * (2**log2(TAPS));
+ type rom_t is array (0 to rom_size-1) of fir_dataword18;
+ function generate_rom return rom_t is
+ variable rom : rom_t;
+ variable ssize : natural;
+ begin
+ ssize := 2**log2(TAPS);
+ rom := (others=>(others=>'0'));
+ for t in 0 to TAPS-1 loop
+ rom(t) := to_signed(COEFFS(t), 18);
+ end loop;
+ return rom;
+ end generate_rom;
+ signal rom : rom_t := generate_rom;
+
+ -- don't waste blockram
+ attribute syn_romstyle of rom : signal is ROMSTYLE;
+ attribute syn_ramstyle of rom : signal is ROMSTYLE;
+
+begin
+
+ -- data-buffer
+ dbuf: entity mt_fil_dstorage_slow
+ generic map (
+ CHANNELS => DCHAN,
+ DEPTH => TAPS,
+ RAMSTYLE => RAMSTYLE
+ )
+ port map (
+ clk => clk,
+ reset => reset,
+ chan => chan,
+ load => in_load,
+ start => in_start,
+ stop => in_stop,
+ active => in_active,
+ din => in_data,
+ dout1 => out_data1,
+ dout2 => out_data2
+ );
+
+ -- control logic
+ process(clk, reset)
+ begin
+ if reset='1' then
+ del_load <= (others=>'0');
+ del_start <= (others=>'0');
+ del_stop <= (others=>'0');
+ del_active <= (others=>'0');
+ out_load <= '0';
+ out_start <= '0';
+ out_stop <= '0';
+ out_active <= '0';
+ out_coeff <= (others=>'0');
+ cind <= (others=>'0');
+ elsif rising_edge(clk) then
+ -- create delayed control flags
+ del_load <= del_load(del_load'left-1 downto 0) & in_load;
+ del_start <= del_start(del_start'left-1 downto 0) & in_start;
+ del_stop <= del_stop(del_stop'left-1 downto 0) & in_stop;
+ del_active <= del_active(del_active'left-1 downto 0) & in_active;
+
+ -- output delayed control flags
+ out_load <= del_load(1);
+ out_start <= del_start(1);
+ out_stop <= del_stop(1);
+ out_active <= del_active(1);
+
+ -- update coeff-indices
+ if del_start(0)='1' then
+ cind <= to_unsigned(0, cind'length);
+ elsif del_active(0)='1' then
+ cind <= cind + 1;
+ end if;
+
+ -- output coefficent
+ out_coeff <= rom(to_integer(cind));
+ end if;
+ end process;
+
+end rtl;
diff --git a/fpga/hw-v2/src/mt_filter/mt_filter.vhd b/fpga/hw-v2/src/mt_filter/mt_filter.vhd
new file mode 100644
index 0000000..bfdbdb4
--- /dev/null
+++ b/fpga/hw-v2/src/mt_filter/mt_filter.vhd
@@ -0,0 +1,46 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : mt_filter.vhd
+-- Project : maintech filter toolbox
+-- Purpose : maintech filter toolbox package
+--
+-- Description : declaration of common types, functions and attributes
+-- used throughout the filter toolbox
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+package mt_filter is
+
+ --
+ -- FIR filter types
+ --
+ subtype fir_dataword18 is signed(17 downto 0);
+ type fir_databus18 is array (natural range <>) of fir_dataword18;
+ subtype fir_coefficient is integer range -2**17 to 2**17-1;
+ type fir_coefficients is array (natural range <>) of fir_coefficient;
+
+end mt_filter;
+
+package body mt_filter is
+ -- nothing so far
+end mt_filter;
+
diff --git a/fpga/hw-v2/src/mt_filter/mt_fir_symmetric_slow.vhd b/fpga/hw-v2/src/mt_filter/mt_fir_symmetric_slow.vhd
new file mode 100644
index 0000000..fcb6ff6
--- /dev/null
+++ b/fpga/hw-v2/src/mt_filter/mt_fir_symmetric_slow.vhd
@@ -0,0 +1,219 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : mt_fir_symmetric_slow.vhd
+-- Project : maintech filter toolbox
+-- Purpose : Symmetric FIR filter
+-- - multiplexed input/output for all data-channels
+-- - single MAC-cell for all calculations
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.mt_filter.all;
+
+entity mt_fir_symmetric_slow is
+ generic (
+ CHANNELS : natural; -- number of data channels
+ TAPS : natural; -- number of filter taps (AFTER folding)
+ COEFFS : fir_coefficients; -- coefficent sets
+ RAMSTYLE : string; -- ram style for inferred memories
+ ROMSTYLE : string -- ram style for coefficent rom
+ );
+ port(
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- input port
+ in_clk : in std_logic;
+ in_ack : out std_logic;
+ in_chan : in unsigned(log2(CHANNELS)-1 downto 0);
+ in_data : in fir_dataword18;
+
+ -- output port
+ out_clk : out std_logic;
+ out_chan : out unsigned(log2(CHANNELS)-1 downto 0);
+ out_data : out fir_dataword18
+ );
+end mt_fir_symmetric_slow;
+
+architecture rtl of mt_fir_symmetric_slow is
+
+ -- internal types
+ subtype chan_t is unsigned(log2(CHANNELS)-1 downto 0);
+ type chan_array_t is array(natural range<>) of chan_t;
+
+ -- control signals
+ signal active : std_logic;
+ signal shiftcnt : unsigned(log2(TAPS)-1 downto 0);
+ signal ochan : chan_array_t(3 downto 0);
+
+ -- storage ports
+ signal st_chan : chan_t;
+ signal st_start : std_logic;
+ signal st_stop : std_logic;
+ signal st_active : std_logic;
+ signal st_din : fir_dataword18;
+
+ -- storage <-> MAC
+ signal st_mac_start : std_logic;
+ signal st_mac_stop : std_logic;
+ signal st_mac_active : std_logic;
+ signal st_mac_dout1 : fir_dataword18;
+ signal st_mac_dout2 : fir_dataword18;
+ signal st_mac_coeff : fir_dataword18;
+
+ -- MAC output
+ signal mac_dnew : std_logic;
+ signal mac_dout : fir_dataword18;
+
+begin
+
+ -- control logic
+ process(clk, reset)
+ begin
+ if reset='1' then
+ active <= '0';
+ shiftcnt <= (others=>'0');
+ ochan <= (others=>(others=>'0'));
+ st_start <= '0';
+ st_stop <= '0';
+ st_active <= '0';
+ in_ack <= '0';
+ out_clk <= '0';
+ out_data <= (others=>'0');
+ out_chan <= (others=>'0');
+ elsif rising_edge(clk) then
+ -- set default values
+ in_ack <= '0';
+ out_clk <= '0';
+ st_start <= '0';
+ st_stop <= '0';
+ st_active <= '0';
+
+ -- get current status
+ if active='0' then
+ --> idle
+
+ -- check for new request
+ if in_clk='1' then
+ --> input new sample and start burst from storage to MAC cell
+ shiftcnt <= to_unsigned(TAPS-1, shiftcnt'length);
+ st_start <= '1';
+ st_active <= '1';
+ active <= '1';
+ end if;
+ else
+ --> active
+
+ -- control storage
+ if shiftcnt/=0 then
+ --> continue with burst
+ shiftcnt <= shiftcnt-1;
+ st_active <= '1';
+ if shiftcnt=1 then
+ -- last cycle of burst
+ st_stop <= '1';
+ in_ack <= '1';
+ active <= '0';
+ end if;
+ end if;
+ end if;
+
+ -- check if new result is ready
+ if mac_dnew='1' then
+ --> MAC done, update output
+ out_clk <= '1';
+ out_chan <= ochan(ochan'left);
+ out_data <= mac_dout;
+ end if;
+
+ -- delay channel-number to compensate for MAC delay
+ ochan <= ochan(ochan'left-1 downto 0) & ochan(0);
+ if st_mac_start='1' then
+ ochan(0) <= in_chan;
+ end if;
+ end if;
+ end process;
+
+ -- connect storage input
+ st_chan <= in_chan;
+ st_din <= in_data;
+
+ -- data storage
+ st: entity mt_fil_storage_slow
+ generic map (
+ COEFFS => COEFFS,
+ DCHAN => CHANNELS,
+ TAPS => TAPS,
+ RAMSTYLE => RAMSTYLE,
+ ROMSTYLE => ROMSTYLE
+ )
+ port map (
+ -- common
+ clk => clk,
+ reset => reset,
+
+ -- config
+ chan => st_chan,
+
+ -- input
+ in_load => st_start,
+ in_start => st_start,
+ in_stop => st_stop,
+ in_active => st_active,
+ in_data => st_din,
+
+ -- output
+ out_load => open,
+ out_start => st_mac_start,
+ out_stop => st_mac_stop,
+ out_active => st_mac_active,
+ out_data1 => st_mac_dout1,
+ out_data2 => st_mac_dout2,
+ out_coeff => st_mac_coeff
+ );
+
+ -- do create MAC cell
+ mac: entity mt_fil_mac_slow
+ port map (
+ -- common
+ clk => clk,
+ reset => reset,
+
+ -- control-path
+ start => st_mac_start,
+ active => st_mac_active,
+ presub => '0',
+
+ -- data input
+ smp1 => st_mac_dout1,
+ smp2 => st_mac_dout2,
+ coeff => st_mac_coeff,
+
+ -- data output
+ dnew => mac_dnew,
+ dout => mac_dout
+ );
+
+end rtl;
diff --git a/fpga/hw-v2/src/mt_toolbox/mt_clktools.vhd b/fpga/hw-v2/src/mt_toolbox/mt_clktools.vhd
new file mode 100644
index 0000000..b0f3e73
--- /dev/null
+++ b/fpga/hw-v2/src/mt_toolbox/mt_clktools.vhd
@@ -0,0 +1,151 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : mt_clktools.vhd
+-- Project : maintech IP-Core toolbox
+-- Purpose : Basic tools for clock/reset-generation
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+-- mt_reset_gen ---------------------------------------------------------------
+-------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+entity mt_reset_gen is
+ port (
+ clk : in std_logic; -- some direct clock-input
+ ext_rst : in std_logic; -- external reset
+ pll_locked : in std_logic; -- PLLs locked?
+ reset_pll : out std_logic; -- reset signal for PLLs
+ reset_sys : out std_logic; -- global reset signal
+
+ -- debug
+ dbg_ext : out std_logic;
+ dbg_rst : out std_logic;
+ dbg_lock : out std_logic
+ );
+end mt_reset_gen;
+
+architecture rtl of mt_reset_gen is
+
+ -- reset generation
+ signal rst_roc2pll : std_logic_vector(15 downto 0) := (others=>'1'); -- delay between rst_roc <-> rst_pll
+ signal rst_pll2go : std_logic_vector( 5 downto 0) := (others=>'1'); -- delay between reset_pll <-> reset_I
+ signal reset_pll_i : std_logic := '1'; -- inner version of 'reset_pll'
+ signal reset_sys_i : std_logic; -- inner version of 'reset_sys'
+
+ -- TODO
+ signal lockcnt : unsigned(15 downto 0) := (others=>'0');
+ signal relock : std_logic := '0';
+
+begin
+
+ -- generate PLL-reset
+ process(clk)
+ begin
+ if rising_edge(clk) then
+-- if ext_rst='0' or relock='1' then
+ if relock='1' then
+ rst_roc2pll <= (others=>'1');
+ reset_pll_i <= '1';
+ else
+ rst_roc2pll <= '0' & rst_roc2pll(rst_roc2pll'high downto 1);
+ reset_pll_i <= rst_roc2pll(0);
+ end if;
+ end if;
+ end process;
+
+ -- TODO
+ process(clk)
+ begin
+ if rising_edge(clk) then
+-- if ext_rst='0' or pll_locked='1' or relock='1' then
+ if pll_locked='1' or relock='1' then
+ lockcnt <= to_unsigned(0,16);
+ relock <= '0';
+ else
+ lockcnt <= lockcnt+1;
+ if lockcnt=30000-1 then
+ relock <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+ -- generate system-reset
+ process(clk, reset_pll_i)
+ begin
+ if reset_pll_i = '1' then
+ reset_sys_i <= '1';
+ rst_pll2go <= (others=>'1');
+ elsif rising_edge(clk) then
+ if pll_locked='0' then
+ rst_pll2go <= (others=>'1');
+ reset_sys_i <= '1';
+ else
+ rst_pll2go <= '0' & rst_pll2go(rst_pll2go'high downto 1);
+ reset_sys_i <= rst_pll2go(0);
+ end if;
+ end if;
+ end process;
+
+ -- output reset-signal
+ reset_sys <= reset_sys_i;
+
+ -- output PLL-reset
+ reset_pll <= reset_pll_i;
+
+ -- debug
+ dbg_ext <= ext_rst;
+ dbg_rst <= reset_pll_i;
+ dbg_lock <= pll_locked;
+end;
+
+
+-------------------------------------------------------------------------------
+-- mt_reset_sync --------------------------------------------------------------
+-------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+
+entity mt_reset_sync is
+ port (
+ clk : in std_logic;
+ rst_in : in std_logic;
+ rst_out : out std_logic
+ );
+end mt_reset_sync;
+
+architecture rtl of mt_reset_sync is
+ signal taps : std_logic_vector(3 downto 0);
+begin
+ process(clk, rst_in)
+ begin
+ if rst_in='1' then
+ taps <= (others=>'1');
+ rst_out <= '1';
+ elsif rising_edge(clk) then
+ taps <= "0" & taps(taps'high downto 1);
+ rst_out <= taps(0);
+ end if;
+ end process;
+end;
diff --git a/fpga/hw-v2/src/mt_toolbox/mt_toolbox.vhd b/fpga/hw-v2/src/mt_toolbox/mt_toolbox.vhd
new file mode 100644
index 0000000..77768a5
--- /dev/null
+++ b/fpga/hw-v2/src/mt_toolbox/mt_toolbox.vhd
@@ -0,0 +1,182 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : mt_toolbox.vhd
+-- Project : maintech IP-Core toolbox
+-- Purpose : maintech toolbox package
+--
+-- Description : declaration of common types, functions and attributes
+-- used throughout the toolbox
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+package mt_toolbox is
+
+ --
+ -- basic types
+ --
+ subtype slv8_t is std_logic_vector(7 downto 0);
+ subtype slv16_t is std_logic_vector(15 downto 0);
+ subtype slv32_t is std_logic_vector(31 downto 0);
+ subtype byte_t is unsigned(7 downto 0);
+ subtype word_t is unsigned(15 downto 0);
+ subtype dword_t is unsigned(31 downto 0);
+ type slv8_array_t is array (natural range<>) of slv8_t;
+ type slv16_array_t is array (natural range<>) of slv16_t;
+ type slv32_array_t is array (natural range<>) of slv32_t;
+ type byte_array_t is array (natural range<>) of byte_t;
+ type word_array_t is array (natural range<>) of word_t;
+ type dword_array_t is array (natural range<>) of dword_t;
+
+ --
+ -- simple helper functions
+ --
+ function log2(x: natural) return positive;
+
+ --
+ -- type conversion helper
+ --
+ function to_slv8(x: std_logic) return std_logic_vector;
+ function to_slv8(x: std_logic_vector) return std_logic_vector;
+ function to_slv8(x: unsigned) return std_logic_vector;
+ function to_slv8(x: signed) return std_logic_vector;
+ function to_slv8(x: natural) return std_logic_vector;
+ function to_slv16(x: std_logic) return std_logic_vector;
+ function to_slv16(x: std_logic_vector) return std_logic_vector;
+ function to_slv16(x: unsigned) return std_logic_vector;
+ function to_slv16(x: signed) return std_logic_vector;
+ function to_slv16(x: natural) return std_logic_vector;
+ function to_slv32(x: std_logic) return std_logic_vector;
+ function to_slv32(x: std_logic_vector) return std_logic_vector;
+ function to_slv32(x: unsigned) return std_logic_vector;
+ function to_slv32(x: signed) return std_logic_vector;
+ function to_slv32(x: natural) return std_logic_vector;
+
+ --
+ -- common attributes
+ --
+ attribute syn_keep : boolean;
+ attribute syn_ramstyle : string;
+ attribute syn_romstyle : string;
+
+end mt_toolbox;
+
+package body mt_toolbox is
+
+ --
+ -- simple helper functions
+ --
+
+ -- calculate ceiling base 2 logarithm (returns always >=1)
+ function log2(x: natural) return positive is
+ variable x_tmp: natural;
+ variable y: positive;
+ begin
+ x_tmp := x-1;
+ y := 1;
+ while x_tmp > 1 loop
+ y := y+1;
+ x_tmp := x_tmp/2;
+ end loop;
+ return y;
+ end;
+
+ -- to_slv8 (pack basic types into "std_logic_vector(7 downto 0)")
+ function to_slv8(x: std_logic) return std_logic_vector is
+ variable res : std_logic_vector(7 downto 0);
+ begin
+ res := (0=>x,others=>'0');
+ return res;
+ end to_slv8;
+ function to_slv8(x: std_logic_vector) return std_logic_vector is
+ variable res : std_logic_vector(7 downto 0);
+ begin
+ res := (others=>'0');
+ res(x'length-1 downto 0) := x;
+ return res;
+ end to_slv8;
+ function to_slv8(x: unsigned) return std_logic_vector is
+ begin
+ return to_slv8(std_logic_vector(x));
+ end to_slv8;
+ function to_slv8(x: signed) return std_logic_vector is
+ begin
+ return to_slv8(std_logic_vector(x));
+ end to_slv8;
+ function to_slv8(x: natural) return std_logic_vector is
+ begin
+ return to_slv8(to_unsigned(x,8));
+ end to_slv8;
+
+ -- to_slv16 (pack basic types into "std_logic_vector(15 downto 0)")
+ function to_slv16(x: std_logic) return std_logic_vector is
+ variable res : std_logic_vector(15 downto 0);
+ begin
+ res := (0=>x,others=>'0');
+ return res;
+ end to_slv16;
+ function to_slv16(x: std_logic_vector) return std_logic_vector is
+ variable res : std_logic_vector(15 downto 0);
+ begin
+ res := (others=>'0');
+ res(x'length-1 downto 0) := x;
+ return res;
+ end to_slv16;
+ function to_slv16(x: unsigned) return std_logic_vector is
+ begin
+ return to_slv16(std_logic_vector(x));
+ end to_slv16;
+ function to_slv16(x: signed) return std_logic_vector is
+ begin
+ return to_slv16(std_logic_vector(x));
+ end to_slv16;
+ function to_slv16(x: natural) return std_logic_vector is
+ begin
+ return to_slv16(to_unsigned(x,16));
+ end to_slv16;
+
+ -- to_slv32 (pack basic types into "std_logic_vector(31 downto 0)")
+ function to_slv32(x: std_logic) return std_logic_vector is
+ variable res : std_logic_vector(31 downto 0);
+ begin
+ res := (0=>x,others=>'0');
+ return res;
+ end to_slv32;
+ function to_slv32(x: std_logic_vector) return std_logic_vector is
+ variable res : std_logic_vector(31 downto 0);
+ begin
+ res := (others=>'0');
+ res(x'length-1 downto 0) := x;
+ return res;
+ end to_slv32;
+ function to_slv32(x: unsigned) return std_logic_vector is
+ begin
+ return to_slv32(std_logic_vector(x));
+ end to_slv32;
+ function to_slv32(x: signed) return std_logic_vector is
+ begin
+ return to_slv32(std_logic_vector(x));
+ end to_slv32;
+ function to_slv32(x: natural) return std_logic_vector is
+ begin
+ return to_slv32(to_unsigned(x,32));
+ end to_slv32;
+end mt_toolbox;
+
diff --git a/fpga/hw-v2/src/testbench/tb_filter.vhd b/fpga/hw-v2/src/testbench/tb_filter.vhd
new file mode 100644
index 0000000..275c429
--- /dev/null
+++ b/fpga/hw-v2/src/testbench/tb_filter.vhd
@@ -0,0 +1,131 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : usbrx_toplevel.vhd
+-- Project : OsmoSDR FPGA Firmware Testbench
+-- Purpose : Decimation Filter Stimulus
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.std_logic_misc.all;
+ use ieee.numeric_std.all;
+ use ieee.math_real.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.mt_filter.all;
+ use work.usbrx.all;
+
+entity tb_filter is
+end tb_filter;
+
+architecture rtl of tb_filter is
+
+ -- common
+ signal clk : std_logic := '1';
+ signal reset : std_logic := '1';
+
+ -- config
+ signal config : usbrx_fil_config_t;
+
+ -- input
+ signal in_clk : std_logic;
+ signal in_i : signed(15 downto 0);
+ signal in_q : signed(15 downto 0);
+
+ -- output
+ signal out_clk : std_logic;
+ signal out_i : signed(15 downto 0);
+ signal out_q : signed(15 downto 0);
+
+begin
+
+ -- generate clock
+ clk <= not clk after 500ns / 100.0;
+ reset <= '1', '0' after 123ns;
+
+ -- set config
+ config.decim <= "110";
+
+ -- input control
+ process
+ variable t : real := 0.0;
+ variable f : real := 1.0;
+ begin
+ in_clk <= '0';
+ in_i <= to_signed(0,16);
+ in_q <= to_signed(0,16);
+ wait until rising_edge(clk) and reset='0';
+
+ loop
+ -- wait some time
+ for i in 0 to 38 loop
+ wait until rising_edge(clk);
+ end loop;
+
+ -- get sample data
+ in_i <= to_signed(integer(cos(t)*10000.0),16);
+ in_q <= to_signed(0,16);
+
+ -- input sample
+ in_clk <= '1';
+ wait until rising_edge(clk);
+ in_clk <= '0';
+
+ -- update time
+ t := t + f/2000000.0*2.0*MATH_PI;
+ if t >= 2.0*MATH_PI then
+ t := t - 2.0*MATH_PI;
+ end if;
+
+ -- update frequency
+ f := f + 1.0;
+ if f>1000000.0 then
+ f := 1.0;
+ end if;
+ end loop;
+
+ wait;
+ end process;
+
+ -- create filter core
+ uut: entity usbrx_decimate
+ port map (
+ -- common
+ clk => clk,
+ reset => reset,
+
+ -- config
+ config => config,
+
+ -- input
+ in_clk => in_clk,
+ in_i => in_i,
+ in_q => in_q,
+
+ -- output
+ out_clk => out_clk,
+ out_i => out_i,
+ out_q => out_q
+ );
+
+end rtl;
+
+
diff --git a/fpga/hw-v2/src/testbench/tb_usbrx.vhd b/fpga/hw-v2/src/testbench/tb_usbrx.vhd
new file mode 100644
index 0000000..4884ee7
--- /dev/null
+++ b/fpga/hw-v2/src/testbench/tb_usbrx.vhd
@@ -0,0 +1,356 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : usbrx_toplevel.vhd
+-- Project : OsmoSDR FPGA Firmware Testbench
+-- Purpose : Toplevel Stimulus
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.std_logic_misc.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+
+entity tb_usbrx is
+end tb_usbrx;
+
+architecture rtl of tb_usbrx is
+
+ -- common
+ signal clk_in_pclk : std_logic := '1';
+
+ -- special control
+ signal dings : std_logic;
+ signal dingsrst : std_logic;
+
+ -- ADC interface
+ signal adc_cs : std_logic;
+ signal adc_sck : std_logic;
+ signal adc_sd1 : std_logic;
+ signal adc_sd2 : std_logic;
+
+ -- control SPI
+ signal ctl_int : std_logic;
+ signal ctl_cs : std_logic;
+ signal ctl_sck : std_logic;
+ signal ctl_mosi : std_logic;
+ signal ctl_miso : std_logic;
+
+ -- data SPIs
+ signal rx_clk : std_logic;
+ signal rx_syn : std_logic;
+ signal rx_dat : std_logic;
+
+ -- data SPIs
+ signal tx_clk : std_logic := '1';
+ signal tx_syn : std_logic;
+ signal tx_dat : std_logic;
+
+ -- gain PWMs
+ signal gain0 : std_logic;
+ signal gain1 : std_logic;
+
+ -- GPS
+ signal gps_1pps : std_logic;
+ signal gps_10k : std_logic;
+
+ -- gpios
+ signal gpio : std_logic_vector(9 downto 0);
+
+ -- virtual GNDs/VCCs
+ signal vgnd : std_logic_vector(11 downto 0);
+ signal vcc33 : std_logic_vector(11 downto 0);
+ signal vcc12 : std_logic_vector(4 downto 0);
+
+begin
+
+ -- generate clocks
+ clk_in_pclk <= not clk_in_pclk after 500 ns / 30.0;
+ tx_clk <= '0'; --not tx_clk after 500 ns / 24.0;
+
+ -- special control
+ dings <= '0';
+ dingsrst <= '1'; --, '0' after 100 us, '1' after 200 us;
+
+ -- data SPIs
+ tx_syn <= '0';
+ tx_dat <= '0';
+
+ -- GPS
+ gps_1pps <= '0';
+ gps_10k <= '0';
+
+ -- gpios
+ gpio <= (others=>'H');
+
+ -- dummy ADC model
+ process
+-- constant word1 : unsigned(15 downto 0) := "0010000000000001";
+-- constant word2 : unsigned(15 downto 0) := "0001111111111110";
+-- constant word1 : unsigned(15 downto 0) := "0001111111111111";
+-- constant word2 : unsigned(15 downto 0) := "0001111111111111";
+ variable word1 : unsigned(15 downto 0) := "0011010111001101";
+ variable word2 : unsigned(15 downto 0) := "0001001111000101";
+ variable sreg1 : unsigned(15 downto 0);
+ variable sreg2 : unsigned(15 downto 0);
+
+ variable cnt : natural;
+
+ begin
+ adc_sd1 <= 'Z';
+ adc_sd2 <= 'Z';
+
+ cnt := 0;
+ loop
+ wait until falling_edge(adc_cs);
+
+ word1 := to_unsigned(8192 + cnt, 16);
+ word2 := to_unsigned(8192 - cnt, 16);
+ cnt := (cnt + 1) mod 8192;
+
+ sreg1 := word1;
+ sreg2 := word2;
+
+ adc_sd1 <= transport 'X', sreg1(15) after 5ns;
+ adc_sd2 <= transport 'X', sreg2(15) after 5ns;
+ sreg1 := shift_left(sreg1,1);
+ sreg2 := shift_left(sreg2,1);
+
+ il: loop
+ wait until rising_edge(adc_cs) or falling_edge(adc_sck);
+ exit when rising_edge(adc_cs);
+
+ adc_sd1 <= transport 'X', sreg1(15) after 11.0ns;
+ adc_sd2 <= transport 'X', sreg2(15) after 11.0ns;
+ sreg1 := shift_left(sreg1,1);
+ sreg2 := shift_left(sreg2,1);
+ end loop;
+
+ adc_sd1 <= transport 'X', 'Z' after 9.5ns;
+ adc_sd2 <= transport 'X', 'Z' after 9.5ns;
+
+ end loop;
+
+ end process;
+
+ -- SPI interface
+ process
+
+ -- write cycle
+ procedure spi_write(addr: in integer; data: in slv32_t) is
+ variable sreg : std_logic_vector(39 downto 0);
+ begin
+ -- assemble message
+ sreg(39) := '0';
+ sreg(38 downto 32) := std_logic_vector(to_unsigned(addr,7));
+ sreg(31 downto 0) := data;
+
+ -- assert CS
+ ctl_sck <= '1';
+ ctl_mosi <= '1';
+ ctl_cs <= '0';
+ wait for 250ns;
+
+ -- clock out data
+ for i in 39 downto 0 loop
+ ctl_sck <= '0';
+ ctl_mosi <= sreg(i);
+ wait for 250ns;
+ ctl_sck <= '1';
+ wait for 250ns;
+ end loop;
+
+ -- deassert CS
+ wait for 250ns;
+ ctl_cs <= '1';
+ wait for 250ns;
+ end procedure spi_write;
+
+ -- write cycle
+ procedure spi_writem(addr,count: in integer; data: in slv32_array_t) is
+ variable sreg : std_logic_vector(31 downto 0);
+ begin
+
+ -- assert CS
+ ctl_sck <= '1';
+ ctl_mosi <= '1';
+ ctl_cs <= '0';
+ wait for 250ns;
+
+ -- write command
+ sreg(7) := '0';
+ sreg(6 downto 0) := std_logic_vector(to_unsigned(addr,7));
+ for i in 7 downto 0 loop
+ ctl_sck <= '0';
+ ctl_mosi <= sreg(i);
+ wait for 250ns;
+ ctl_sck <= '1';
+ wait for 250ns;
+ end loop;
+
+ --write data
+ for j in 0 to count-1 loop
+ sreg := data(j);
+ for i in 31 downto 0 loop
+ ctl_sck <= '0';
+ ctl_mosi <= sreg(i);
+ wait for 250ns;
+ ctl_sck <= '1';
+ wait for 250ns;
+ end loop;
+ end loop;
+
+ -- deassert CS
+ wait for 250ns;
+ ctl_cs <= '1';
+ wait for 250ns;
+ end procedure spi_writem;
+
+ -- read cycle
+ procedure spi_read(addr,count: in integer; data: out slv32_array_t) is
+ variable sreg : std_logic_vector(7 downto 0);
+ begin
+
+ -- assemble message
+ sreg(7) := '1';
+ sreg(6 downto 0) := std_logic_vector(to_unsigned(addr,7));
+
+ -- assert CS
+ ctl_sck <= '1';
+ ctl_mosi <= '1';
+ ctl_cs <= '0';
+ wait for 250ns;
+
+ -- clock out command
+ for i in 7 downto 0 loop
+ ctl_sck <= '0';
+ ctl_mosi <= sreg(i);
+ wait for 250ns;
+ ctl_sck <= '1';
+ wait for 250ns;
+ end loop;
+
+ wait for 50us;
+
+ -- read data
+ for j in 0 to count-1 loop
+ for i in 31 downto 0 loop
+ ctl_sck <= '0';
+ wait for 250ns;
+ data(j)(i) := ctl_miso;
+ ctl_sck <= '1';
+ wait for 250ns;
+
+ if i=24 or i=16 or i=8 then
+ wait for 50us;
+ end if;
+
+ end loop;
+ end loop;
+
+ -- deassert CS
+ wait for 250ns;
+ ctl_cs <= '1';
+ wait for 250ns;
+ end procedure spi_read;
+
+ variable temp : slv32_array_t(0 to 5);
+
+ begin
+ ctl_cs <= '1';
+ ctl_sck <= '1';
+ ctl_mosi <= '1';
+
+ wait for 30us;
+
+-- spi_write(4,x"00000001");
+
+-- spi_read(0,1,temp);
+-- spi_read(0,1,temp);
+-- wait;
+--
+-- temp(0) := x"00000000";
+-- temp(1) := x"12345678";
+-- temp(2) := x"9ABCDEF0";
+-- temp(3) := x"11233435";
+-- temp(4) := x"23652662";
+-- temp(5) := x"98735773";
+-- spi_writem(0,6,temp);
+--
+-- temp := (others=>x"00000000");
+-- spi_read(0,6,temp);
+
+ wait;
+ end process;
+
+ -- unit under test
+ uut: entity usbrx_toplevel
+ port map (
+ -- common
+ clk_in_pclk => clk_in_pclk,
+
+ -- special control
+ dings => dings,
+ dingsrst => dingsrst,
+
+ -- ADC interface
+ adc_cs => adc_cs,
+ adc_sck => adc_sck,
+ adc_sd1 => adc_sd1,
+ adc_sd2 => adc_sd2,
+
+ -- control SPI
+ ctl_int => ctl_int,
+ ctl_cs => ctl_cs,
+ ctl_sck => ctl_sck,
+ ctl_mosi => ctl_mosi,
+ ctl_miso => ctl_miso,
+
+ -- data SPIs
+ rx_clk => rx_clk,
+ rx_syn => rx_syn,
+ rx_dat => rx_dat,
+
+ -- data SPIs
+ tx_clk => tx_clk,
+ tx_syn => tx_syn,
+ tx_dat => tx_dat,
+
+ -- gain PWMs
+ gain0 => gain0,
+ gain1 => gain1,
+
+ -- GPS
+ gps_1pps => gps_1pps,
+ gps_10k => gps_10k,
+
+ -- gpios
+ gpio => gpio,
+
+ -- virtual GNDs/VCCs
+ vgnd => vgnd,
+ vcc33 => vcc33,
+ vcc12 => vcc12
+ );
+
+end rtl;
+
+
diff --git a/fpga/hw-v2/src/usbrx/datapath/usbrx_ad7357.vhd b/fpga/hw-v2/src/usbrx/datapath/usbrx_ad7357.vhd
new file mode 100644
index 0000000..f37d0fb
--- /dev/null
+++ b/fpga/hw-v2/src/usbrx/datapath/usbrx_ad7357.vhd
@@ -0,0 +1,299 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : usbrx_ad7357.vhd
+-- Project : OsmoSDR FPGA Firmware
+-- Purpose : AD7357 Interface
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library xp2;
+ use xp2.all;
+ use xp2.components.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.usbrx.all;
+
+entity usbrx_ad7357 is
+ port(
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- config
+ config : in usbrx_adc_config_t;
+
+ -- ADC interface
+ adc_cs : out std_logic;
+ adc_sck : out std_logic;
+ adc_sd1 : in std_logic;
+ adc_sd2 : in std_logic;
+
+ -- output
+ out_clk : out std_logic;
+ out_i : out unsigned(13 downto 0);
+ out_q : out unsigned(13 downto 0)
+ );
+end usbrx_ad7357;
+
+architecture rtl of usbrx_ad7357 is
+
+ -- internal types
+ type state_t is (S_ACQUISITION, S_CONVERT);
+
+ -- main status
+ signal state : state_t;
+ signal counter : unsigned(7 downto 0);
+
+ -- SCK generator
+ signal cg_div : unsigned(7 downto 0);
+ signal cg_count : unsigned(7 downto 0);
+ signal cg_phase : std_logic;
+ signal cg_ddr_a : std_logic;
+ signal cg_ddr_b : std_logic;
+ signal cg_renxt : std_logic;
+ signal cg_redge : std_logic;
+
+ -- chip select (+ delayed versions)
+ signal css : std_logic_vector(3 downto 0);
+
+ -- latch input on rising/falling edge of current cycle
+ -- (+ delayed versions)
+ signal latch_r : std_logic_vector(3 downto 0);
+ signal latch_f : std_logic_vector(3 downto 0);
+
+ -- input register stage #1
+ signal sd1_s1r : std_logic; -- SD1 - rising edge
+ signal sd1_s1f : std_logic; -- SD1 - falling edge
+ signal sd2_s1r : std_logic; -- SD2 - rising edge
+ signal sd2_s1f : std_logic; -- SD2 - falling edge
+
+ -- input register stage #2
+ signal sd1_s2r : std_logic; -- SD1 - rising edge
+ signal sd1_s2f : std_logic; -- SD1 - falling edge
+ signal sd2_s2r : std_logic; -- SD2 - rising edge
+ signal sd2_s2f : std_logic; -- SD2 - falling edge
+
+ -- input shift registers
+ signal sreg1 : std_logic_vector(13 downto 0);
+ signal sreg2 : std_logic_vector(13 downto 0);
+
+ -- output latches
+ signal onew : std_logic;
+ signal oreg1 : std_logic_vector(13 downto 0);
+ signal oreg2 : std_logic_vector(13 downto 0);
+
+begin
+
+ -- SCL clock generator logic
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ -- set default values
+ cg_renxt <= '0';
+ cg_redge <= cg_renxt;
+ latch_r <= latch_r(latch_r'left-1 downto 0) & '0';
+ latch_f <= latch_f(latch_f'left-1 downto 0) & '0';
+
+ -- get config
+ cg_div <= config.clkdiv;
+
+ -- get operation mode
+ if cg_div=0 or cg_div=1 then
+ --> full speed, just pass through clock
+ cg_ddr_a <= '0';
+ cg_ddr_b <= '1';
+ cg_renxt <= '1';
+ latch_f(0) <= '1';
+ else
+ --> divided clock, update divider-logic
+ if cg_count=0 then
+ -- toggle clock on FE in middle of cycle
+ cg_count <= cg_div - 2;
+ cg_phase <= not cg_phase;
+ cg_ddr_a <= cg_phase;
+ cg_ddr_b <= not cg_phase;
+ cg_renxt <= not cg_phase;
+ latch_r(0) <= cg_phase;
+ elsif cg_count=1 then
+ -- toggle clock on RE after this cycle
+ cg_count <= cg_div - 1;
+ cg_phase <= '0'; --not cg_phase;
+ cg_ddr_a <= '1'; --cg_phase;
+ cg_ddr_b <= '1'; --cg_phase;
+ latch_f(0) <= '1';
+ else
+ -- leave clock unchanged
+ cg_count <= cg_count - 2;
+ cg_ddr_a <= cg_phase;
+ cg_ddr_b <= cg_phase;
+ end if;
+
+ -- failsafe
+ if cg_count=1 and cg_div(0)='0' then
+ cg_count <= cg_div - 2;
+ end if;
+
+ end if;
+
+ -- handle reset
+ if reset='1' then
+ cg_div <= (others=>'1');
+ cg_count <= (others=>'0');
+ cg_phase <= '0';
+ cg_renxt <= '0';
+ cg_redge <= '0';
+ cg_ddr_a <= '1';
+ cg_ddr_b <= '1';
+ latch_r <= (others=>'0');
+ latch_f <= (others=>'0');
+ end if;
+ end if;
+ end process;
+
+ -- output register for SCLK
+ oddr: ODDRXC
+ port map (
+ clk => clk,
+ rst => reset,
+ da => cg_ddr_a,
+ db => cg_ddr_b,
+ q => adc_sck
+ );
+
+ -- main control logig
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ -- set default values
+ css <= css(css'left-1 downto 0) & css(0);
+
+ -- update status
+ case state is
+ when S_ACQUISITION =>
+ -- doing ACQUISITION, wait until ready to start conversion
+ if cg_redge='1' then
+ -- new SCLK cycle, check if wait-counter has ellapsed
+ counter <= counter - 1;
+ if counter<=1 then
+ --> counter ellapsed, start conversion
+ state <= S_CONVERT;
+ counter <= to_unsigned(15,counter'length);
+ css(0) <= '0';
+ end if;
+ end if;
+
+ when S_CONVERT =>
+ -- doing conversion, wait until all bits are clocked out
+ if cg_redge='1' then
+ -- new SCLK cycle, check if bit-counter has ellapsed
+ counter <= counter - 1;
+ if counter=0 then
+ -- all bits received, return to ACQUISITION state
+ state <= S_ACQUISITION;
+ counter <= config.acqlen;
+ css(0) <= '1';
+ end if;
+ end if;
+ end case;
+
+ -- handle reset
+ if reset='1' then
+ state <= S_ACQUISITION; -- TODO
+ counter <= (others=>'0');
+ css <= (others=>'1');
+ end if;
+ end if;
+ end process;
+
+ -- output chip-select
+ adc_cs <= css(0);
+
+ -- input capture registers
+ iddr1: IDDRXC
+ port map (
+ clk => clk,
+ rst => '0',
+ ce => '1',
+ d => adc_sd1,
+ qa => sd1_s1r,
+ qb => sd1_s1f
+ );
+ iddr2: IDDRXC
+ port map (
+ clk => clk,
+ rst => '0',
+ ce => '1',
+ d => adc_sd2,
+ qa => sd2_s1r,
+ qb => sd2_s1f
+ );
+
+ -- input data handling
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ -- set default valies
+ onew <= '0';
+
+ -- register input-bits once more
+ sd1_s2r <= sd1_s1r;
+ sd1_s2f <= sd1_s1f;
+ sd2_s2r <= sd2_s1r;
+ sd2_s2f <= sd2_s1f;
+
+ -- update shift-registers
+ if latch_r(3)='1' then
+ sreg1 <= sreg1(12 downto 0) & sd1_s2r;
+ sreg2 <= sreg2(12 downto 0) & sd2_s2r;
+ elsif latch_f(3)='1' then
+ sreg1 <= sreg1(12 downto 0) & sd1_s2f;
+ sreg2 <= sreg2(12 downto 0) & sd2_s2f;
+ end if;
+
+ -- latch away shift-register when requested
+ if css(2)='1' and css(3)='0' then
+ onew <= '1';
+ oreg1 <= sreg1;
+ oreg2 <= sreg2;
+ end if;
+
+ -- handle reset
+ if reset='1' then
+ sd1_s2r <= '0';
+ sd1_s2f <= '0';
+ sd2_s2r <= '0';
+ sd2_s2f <= '0';
+ sreg1 <= (others=>'0');
+ sreg2 <= (others=>'0');
+ oreg1 <= (others=>'0');
+ oreg2 <= (others=>'0');
+ onew <= '0';
+ end if;
+ end if;
+ end process;
+
+ -- set output
+ out_clk <= onew;
+ out_i <= unsigned(oreg1);
+ out_q <= unsigned(oreg2);
+
+end rtl;
diff --git a/fpga/hw-v2/src/usbrx/datapath/usbrx_decimate.vhd b/fpga/hw-v2/src/usbrx/datapath/usbrx_decimate.vhd
new file mode 100644
index 0000000..e3be853
--- /dev/null
+++ b/fpga/hw-v2/src/usbrx/datapath/usbrx_decimate.vhd
@@ -0,0 +1,218 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : usbrx_decimate.vhd
+-- Project : OsmoSDR FPGA Firmware
+-- Purpose : Variable decimation filter
+-- (possible factors: 1,2,4,8,16,32,64)
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+-- decimation filter ----------------------------------------------------------
+-------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.mt_filter.all;
+ use work.usbrx.all;
+
+entity usbrx_decimate is
+ port (
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- config
+ config : in usbrx_fil_config_t;
+
+ -- input
+ in_clk : in std_logic;
+ in_i : in signed(15 downto 0);
+ in_q : in signed(15 downto 0);
+
+ -- output
+ out_clk : out std_logic;
+ out_i : out signed(15 downto 0);
+ out_q : out signed(15 downto 0)
+ );
+end usbrx_decimate;
+
+architecture rtl of usbrx_decimate is
+
+ -- config
+ signal active : std_logic_vector(5 downto 0);
+
+ -- adapted input
+ signal in_si : fir_dataword18;
+ signal in_sq : fir_dataword18;
+
+ -- filter input
+ signal fil_in_clk : std_logic_vector(5 downto 0);
+ signal fil_in_i : fir_databus18(5 downto 0);
+ signal fil_in_q : fir_databus18(5 downto 0);
+
+ -- filter output
+ signal fil_out_clk : std_logic_vector(5 downto 0);
+ signal fil_out_i : fir_databus18(5 downto 0);
+ signal fil_out_q : fir_databus18(5 downto 0);
+
+ -- unclipped output
+ signal nxt_clk : std_logic;
+ signal nxt_i : fir_dataword18;
+ signal nxt_q : fir_dataword18;
+
+begin
+
+ -- convert input into 18bit signed
+ in_si <= signed(in_i) & "00";
+ in_sq <= signed(in_q) & "00";
+
+ -- control logic
+ process(clk)
+ variable tmp_i,tmp_q : fir_dataword18;
+ begin
+ if rising_edge(clk) then
+
+ -- get active stages
+ case to_integer(config.decim) is
+ when 0 => active <= "000000";
+ when 1 => active <= "000001";
+ when 2 => active <= "000011";
+ when 3 => active <= "000111";
+ when 4 => active <= "001111";
+ when 5 => active <= "011111";
+ when others => active <= "111111";
+ end case;
+
+ -- select output
+ case to_integer(config.decim) is
+ when 0 =>
+ nxt_clk <= in_clk;
+ nxt_i <= in_si;
+ nxt_q <= in_sq;
+ when 1 =>
+ nxt_clk <= fil_out_clk(0);
+ nxt_i <= fil_out_i(0);
+ nxt_q <= fil_out_q(0);
+ when 2 =>
+ nxt_clk <= fil_out_clk(1);
+ nxt_i <= fil_out_i(1);
+ nxt_q <= fil_out_q(1);
+ when 3 =>
+ nxt_clk <= fil_out_clk(2);
+ nxt_i <= fil_out_i(2);
+ nxt_q <= fil_out_q(2);
+ when 4 =>
+ nxt_clk <= fil_out_clk(3);
+ nxt_i <= fil_out_i(3);
+ nxt_q <= fil_out_q(3);
+ when 5 =>
+ nxt_clk <= fil_out_clk(4);
+ nxt_i <= fil_out_i(4);
+ nxt_q <= fil_out_q(4);
+ when others =>
+ nxt_clk <= fil_out_clk(5);
+ nxt_i <= fil_out_i(5);
+ nxt_q <= fil_out_q(5);
+ end case;
+
+ -- set output
+ out_clk <= nxt_clk;
+ if nxt_clk='1' then
+ tmp_i := nxt_i + 2;
+ tmp_q := nxt_q + 2;
+ out_i <= tmp_i(17 downto 2);
+ out_q <= tmp_q(17 downto 2);
+ end if;
+
+ -- handle reset
+ if reset='1' then
+ active <= (others=>'0');
+ nxt_clk <= '0';
+ nxt_i <= (others=>'0');
+ nxt_q <= (others=>'0');
+ out_clk <= '0';
+ out_i <= (others=>'0');
+ out_q <= (others=>'0');
+ end if;
+ end if;
+ end process;
+
+
+ process(in_clk,in_si,in_sq,fil_out_clk,fil_out_i,fil_out_q,active)
+ begin
+ -- feed first filter stage
+ fil_in_clk(0) <= in_clk and active(0);
+ fil_in_i(0) <= in_si;
+ fil_in_q(0) <= in_sq;
+
+ -- chain remaining filter stages
+ for i in 1 to 5 loop
+ fil_in_clk(i) <= fil_out_clk(i-1) and active(i-1);
+ fil_in_i(i) <= fil_out_i(i-1);
+ fil_in_q(i) <= fil_out_q(i-1);
+ end loop;
+ end process;
+
+ -- filter instance #1 (stage 0)
+ hbf1: entity usbrx_halfband
+ generic map (
+ N => 1
+ )
+ port map (
+ -- common
+ clk => clk,
+ reset => reset,
+
+ -- input
+ in_clk => fil_in_clk(0 downto 0),
+ in_i => fil_in_i(0 downto 0),
+ in_q => fil_in_q(0 downto 0),
+
+ -- output
+ out_clk => fil_out_clk(0 downto 0),
+ out_i => fil_out_i(0 downto 0),
+ out_q => fil_out_q(0 downto 0)
+ );
+
+ -- filter instance #2 (stage 1-5)
+ hbf2: entity usbrx_halfband
+ generic map (
+ N => 5
+ )
+ port map (
+ -- common
+ clk => clk,
+ reset => reset,
+
+ -- input
+ in_clk => fil_in_clk(5 downto 1),
+ in_i => fil_in_i(5 downto 1),
+ in_q => fil_in_q(5 downto 1),
+
+ -- output
+ out_clk => fil_out_clk(5 downto 1),
+ out_i => fil_out_i(5 downto 1),
+ out_q => fil_out_q(5 downto 1)
+ );
+
+end rtl;
diff --git a/fpga/hw-v2/src/usbrx/datapath/usbrx_offset.vhd b/fpga/hw-v2/src/usbrx/datapath/usbrx_offset.vhd
new file mode 100644
index 0000000..8337256
--- /dev/null
+++ b/fpga/hw-v2/src/usbrx/datapath/usbrx_offset.vhd
@@ -0,0 +1,105 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : usbrx_halfband.vhd
+-- Project : OsmoSDR FPGA Firmware
+-- Purpose : Programmable sample value offset
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.usbrx.all;
+
+entity usbrx_offset is
+ port (
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- config
+ config : in usbrx_off_config_t;
+
+ -- input
+ in_clk : in std_logic;
+ in_i : in unsigned(13 downto 0);
+ in_q : in unsigned(13 downto 0);
+
+ -- output
+ out_clk : out std_logic;
+ out_i : out signed(15 downto 0);
+ out_q : out signed(15 downto 0)
+ );
+end usbrx_offset;
+
+architecture rtl of usbrx_offset is
+
+ -- clip & saturate sample
+ function doClipValue(x : signed) return signed is
+ begin
+ if x >= 32768 then
+ -- overflow
+ return to_signed(+32767,16);
+ elsif x < -32768 then
+ -- underflow
+ return to_signed(-32768,16);
+ else
+ -- in range
+ return x(15 downto 0);
+ end if;
+ end doClipValue;
+
+begin
+
+ -- control logic
+ process(clk)
+ variable s16i, s16q : signed(15 downto 0);
+ variable s17i, s17q : signed(16 downto 0);
+ begin
+ if rising_edge(clk) then
+ -- passthough clock
+ out_clk <= in_clk;
+
+ -- handle data
+ if in_clk='1' then
+ -- convert input into 16bit signed
+ s16i := signed(in_i xor "10000000000000") & "00";
+ s16q := signed(in_q xor "10000000000000") & "00";
+
+ -- add offset
+ s17i := resize(s16i,17) + resize(config.ioff,17);
+ s17q := resize(s16q,17) + resize(config.qoff,17);
+
+ -- clip output
+ out_i <= doClipValue(s17i);
+ out_q <= doClipValue(s17q);
+ end if;
+
+ -- handle reset
+ if reset='1' then
+ out_clk <= '0';
+ out_i <= (others=>'0');
+ out_q <= (others=>'0');
+ end if;
+ end if;
+ end process;
+
+end rtl;
diff --git a/fpga/hw-v2/src/usbrx/datapath/usbrx_ssc.vhd b/fpga/hw-v2/src/usbrx/datapath/usbrx_ssc.vhd
new file mode 100644
index 0000000..84c0c6c
--- /dev/null
+++ b/fpga/hw-v2/src/usbrx/datapath/usbrx_ssc.vhd
@@ -0,0 +1,191 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : usbrx_ssc.vhd
+-- Project : OsmoSDR FPGA Firmware
+-- Purpose : ATSAM3U SSC Interface
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.usbrx.all;
+
+entity usbrx_ssc is
+ port(
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- config
+ config : in usbrx_ssc_config_t;
+
+ -- output
+ in_clk : in std_logic;
+ in_i : in signed(15 downto 0);
+ in_q : in signed(15 downto 0);
+
+ -- SSC interface
+ ssc_clk : out std_logic;
+ ssc_syn : out std_logic;
+ ssc_dat : out std_logic
+ );
+end usbrx_ssc;
+
+architecture rtl of usbrx_ssc is
+
+ -- CLK generator
+ signal cg_div : unsigned(7 downto 0);
+ signal cg_phase : std_logic;
+ signal cg_tick : std_logic;
+
+ -- shift register
+ signal sreg : std_logic_vector(31 downto 0);
+ signal remain : unsigned(5 downto 0);
+ signal nxtsyn : std_logic;
+
+ -- input latch
+ signal lreg : std_logic_vector(31 downto 0);
+ signal filled : std_logic;
+
+ -- helper function
+ function to_signed(x : unsigned) return signed is
+ begin
+ return signed((not x(x'left)) & x(x'left-1 downto 0));
+ end to_signed;
+ function pack(i,q : unsigned) return slv32_t is
+ variable res : slv32_t := (others=>'0');
+ begin
+ res(31 downto 32-i'length) := std_logic_vector(to_signed(i));
+ res(15 downto 16-q'length) := std_logic_vector(to_signed(q));
+ return res;
+ end pack;
+ function pack(i,q : signed) return slv32_t is
+ variable res : slv32_t := (others=>'0');
+ begin
+ res(31 downto 32-i'length) := std_logic_vector(i);
+ res(15 downto 16-q'length) := std_logic_vector(q);
+ return res;
+ end pack;
+
+ -- debug
+ signal counter1 : unsigned(15 downto 0);
+ signal counter2 : unsigned(15 downto 0);
+
+begin
+
+ -- clock generator
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ -- set default values
+ cg_tick <= '0';
+
+ -- update clock-divider
+ if cg_div=0 then
+ -- toggle phase
+ cg_phase <= not cg_phase;
+ cg_div <= config.clkdiv;
+
+ -- set 'tick'-flag when generating falling edge
+ if cg_phase='1' then
+ cg_tick <= '1';
+ end if;
+ else
+ -- stay in current phase
+ cg_div <= cg_div-1;
+ end if;
+
+ -- update output
+ ssc_clk <= cg_phase;
+
+ -- handle reset
+ if reset='1' then
+ cg_div <= (others=>'0');
+ cg_phase <= '0';
+ cg_tick <= '0';
+ ssc_clk <= '0';
+ end if;
+ end if;
+ end process;
+
+ -- output shift register
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ -- wait for output-clock
+ if cg_tick='1' then
+ -- update output
+ ssc_dat <= sreg(sreg'left);
+ ssc_syn <= nxtsyn;
+ sreg <= sreg(sreg'left-1 downto 0) & '0';
+ nxtsyn <= '0';
+
+ -- consume bit
+ if remain > 0 then
+ remain <= remain - 1;
+ end if;
+
+ -- reload shift-register when possible
+ if filled='1' and remain<=1 then
+ filled <= '0';
+ remain <= to_unsigned(32, remain'length);
+ nxtsyn <= '1';
+ sreg <= lreg;
+ end if;
+ end if;
+
+ -- handle incoming samples
+ if in_clk='1' then
+ if filled='0' then
+ -- latch sample
+ lreg <= pack(in_i,in_q);
+ filled <= '1';
+
+ -- apply test-mode
+ if config.tmode='1' then
+ lreg <= pack(counter1,counter2);
+ counter1 <= counter1 + 1;
+ counter2 <= counter2 - 1;
+ end if;
+ else
+ --> overflow
+ report "usbrx_ssc: input too fast"
+ severity warning;
+ end if;
+ end if;
+
+ -- handle reset
+ if reset='1' then
+ sreg <= (others=>'0');
+ remain <= (others=>'0');
+ nxtsyn <= '0';
+ lreg <= (others=>'0');
+ filled <= '0';
+ ssc_syn <= '0';
+ ssc_dat <= '0';
+ counter1 <= (others=>'0');
+ counter2 <= (others=>'1');
+ end if;
+ end if;
+ end process;
+
+end rtl;
diff --git a/fpga/hw-v2/src/usbrx/filter/usbrx_halfband.vhd b/fpga/hw-v2/src/usbrx/filter/usbrx_halfband.vhd
new file mode 100644
index 0000000..ffc6eda
--- /dev/null
+++ b/fpga/hw-v2/src/usbrx/filter/usbrx_halfband.vhd
@@ -0,0 +1,505 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : usbrx_halfband.vhd
+-- Project : OsmoSDR FPGA Firmware
+-- Purpose : Multichannel Halfband Decimation Filter
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+-- halfband decimation filter - input cache/control ---------------------------
+-------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.mt_filter.all;
+
+entity usbrx_halfband_ictrl is
+ generic (
+ N : natural := 3
+ );
+ port (
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- input
+ in_clk : in std_logic_vector(N-1 downto 0);
+ in_i : in fir_databus18(N-1 downto 0);
+ in_q : in fir_databus18(N-1 downto 0);
+
+ -- output
+ out_ready : in std_logic;
+ out_clk : out std_logic;
+ out_chan : out unsigned(log2(N)-1 downto 0);
+ out_i0 : out fir_dataword18;
+ out_i1 : out fir_dataword18;
+ out_q0 : out fir_dataword18;
+ out_q1 : out fir_dataword18
+ );
+end usbrx_halfband_ictrl;
+
+architecture rtl of usbrx_halfband_ictrl is
+
+ -- control
+ signal phase : std_logic_vector(N-1 downto 0);
+ signal tmp_i : fir_databus18(N-1 downto 0);
+ signal tmp_q : fir_databus18(N-1 downto 0);
+ signal oclk : std_logic;
+
+ -- output
+ signal pending : std_logic_vector(N-1 downto 0);
+ signal cache_i0 : fir_databus18(N-1 downto 0);
+ signal cache_i1 : fir_databus18(N-1 downto 0);
+ signal cache_q0 : fir_databus18(N-1 downto 0);
+ signal cache_q1 : fir_databus18(N-1 downto 0);
+
+begin
+
+ -- control logic
+ process(clk)
+ variable found : std_logic;
+ begin
+ if rising_edge(clk) then
+ -- set default values
+ oclk <= '0';
+
+ -- check if we are allowed to output the next entry
+ if out_ready='1' and oclk='0' then
+ -- search for pending cache-entry
+ found := '0';
+ for i in 0 to N-1 loop
+ if found='0' and pending(i)='1' then
+ --> output entry
+ oclk <= '1';
+ out_chan <= to_unsigned(i,out_chan'length);
+ out_i0 <= cache_i0(i);
+ out_i1 <= cache_i1(i);
+ out_q0 <= cache_q0(i);
+ out_q1 <= cache_q1(i);
+
+ -- update status
+ pending(i) <= '0';
+ found := '1';
+ end if;
+ end loop;
+ end if;
+
+ -- handle incoming samples
+ for i in in_clk'range loop
+ if in_clk(i)='1' then
+ -- write sample into cache
+ if phase(i)='0' then
+ tmp_i(i) <= in_i(i);
+ tmp_q(i) <= in_q(i);
+ else
+ pending(i) <= '1';
+ cache_i0(i) <= tmp_i(i);
+ cache_q0(i) <= tmp_q(i);
+ cache_i1(i) <= in_i(i);
+ cache_q1(i) <= in_q(i);
+ end if;
+ phase(i) <= not phase(i);
+
+ -- debug check
+ assert phase(i)='0' or pending(i)='0'
+ report "usbrx_halfband_ictrl: input too fast"
+ severity error;
+ end if;
+ end loop;
+
+ -- handle reset
+ if reset='1' then
+ phase <= (others=>'0');
+ tmp_i <= (others=>(others=>'0'));
+ tmp_q <= (others=>(others=>'0'));
+ pending <= (others=>'0');
+ cache_i0 <= (others=>(others=>'0'));
+ cache_i1 <= (others=>(others=>'0'));
+ cache_q0 <= (others=>(others=>'0'));
+ cache_q1 <= (others=>(others=>'0'));
+ oclk <= '0';
+ out_chan <= (others=>'0');
+ out_i0 <= (others=>'0');
+ out_i1 <= (others=>'0');
+ out_q0 <= (others=>'0');
+ out_q1 <= (others=>'0');
+ end if;
+ end if;
+ end process;
+
+ -- connect output-clock
+ out_clk <= oclk;
+
+end rtl;
+
+
+-------------------------------------------------------------------------------
+-- halfband decimation filter - output control --------------------------------
+-------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.mt_filter.all;
+
+entity usbrx_halfband_octrl is
+ generic (
+ N : natural := 3
+ );
+ port (
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- input
+ in_clk : in std_logic;
+ in_chan : in unsigned(log2(2*N)-1 downto 0);
+ in_data : in fir_dataword18;
+
+ -- output
+ out_clk : out std_logic_vector(N-1 downto 0);
+ out_i : out fir_databus18(N-1 downto 0);
+ out_q : out fir_databus18(N-1 downto 0)
+ );
+end usbrx_halfband_octrl;
+
+architecture rtl of usbrx_halfband_octrl is
+
+ -- cache
+ signal tmp_i : fir_databus18(N-1 downto 0);
+
+begin
+
+ -- control logic
+ process(clk)
+ variable sel : natural range 0 to N-1;
+ begin
+ if rising_edge(clk) then
+ -- set default values
+ out_clk <= (others=>'0');
+
+ -- handle input
+ if in_clk='1' then
+ sel := to_integer(in_chan)/2;
+ for i in out_clk'range loop
+ if sel=i then
+ if in_chan(0)='0' then
+ -- cache result
+ tmp_i(i) <= in_data;
+ else
+ -- output result
+ out_clk(i) <= '1';
+ out_i(i) <= tmp_i(i);
+ out_q(i) <= in_data;
+ end if;
+ end if;
+ end loop;
+ end if;
+
+ -- handle reset
+ if reset='1' then
+ tmp_i <= (others=>(others=>'0'));
+ out_clk <= (others=>'0');
+ out_i <= (others=>(others=>'0'));
+ out_q <= (others=>(others=>'0'));
+ end if;
+ end if;
+ end process;
+end rtl;
+
+
+-------------------------------------------------------------------------------
+-- halfband decimation filter -------------------------------------------------
+-------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.mt_filter.all;
+
+entity usbrx_halfband is
+ generic (
+ N : natural := 3
+ );
+ port (
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- input
+ in_clk : in std_logic_vector(N-1 downto 0);
+ in_i : in fir_databus18(N-1 downto 0);
+ in_q : in fir_databus18(N-1 downto 0);
+
+ -- output
+ out_clk : out std_logic_vector(N-1 downto 0);
+ out_i : out fir_databus18(N-1 downto 0);
+ out_q : out fir_databus18(N-1 downto 0)
+ );
+end usbrx_halfband;
+
+architecture rtl of usbrx_halfband is
+
+ -- internal types
+ type state_t is (S_IDLE, S_FILTER_I, S_FILTER_Q, S_COOLDOWN);
+
+ -- status
+ signal state : state_t;
+
+ -- input control
+ signal ic_ready : std_logic;
+ signal ic_clk : std_logic;
+ signal ic_chan : unsigned(log2(N)-1 downto 0);
+ signal ic_i0 : fir_dataword18;
+ signal ic_i1 : fir_dataword18;
+ signal ic_q0 : fir_dataword18;
+ signal ic_q1 : fir_dataword18;
+
+ -- next output
+ signal on_clk : std_logic;
+ signal on_chan : unsigned(log2(2*N)-1 downto 0);
+ signal on_dat1 : fir_dataword18;
+ signal on_dat2 : fir_dataword18;
+
+ -- output control
+ signal oc_iclk : std_logic;
+ signal oc_ichan : unsigned(log2(2*N)-1 downto 0);
+ signal oc_idata : fir_dataword18;
+
+ -- FIR input
+ signal fir_iclk : std_logic;
+ signal fir_iack : std_logic;
+ signal fir_idata : fir_dataword18;
+ signal fir_ichan : unsigned(log2(2*N)-1 downto 0);
+
+ -- FIR output
+ signal fir_oclk : std_logic;
+ signal fir_ochan : unsigned(log2(2*N)-1 downto 0);
+ signal fir_odata : fir_dataword18;
+
+ -- center samples
+ signal cent_i : fir_databus18(N-1 downto 0);
+ signal cent_q : fir_databus18(N-1 downto 0);
+
+ -- coefficients for 2x-FIR-interpolator
+ -- (halfband, order 48, wpass 0.40)
+ constant coeffs : fir_coefficients(0 to 11) := (
+ -52, 151, -354, 715,
+ -1307, 2227, -3614, 5691,
+ -8907, 14403, -26386, 82957
+ );
+
+begin
+
+ -- control logic
+ process(clk)
+ variable sel : natural range 0 to N-1;
+ begin
+ if rising_edge(clk) then
+ -- set default values
+ fir_iclk <= '0';
+ oc_iclk <= '0';
+ on_clk <= '0';
+
+ -- filter control
+ case state is
+ when S_IDLE =>
+ -- wait for new sample-pair
+ if ic_clk='1' then
+ -- start filter (I)
+ fir_iclk <= '1';
+ fir_idata <= ic_i1;
+ fir_ichan <= resize(ic_chan & "0", fir_ichan'length);
+
+ -- update status
+ state <= S_FILTER_I;
+ end if;
+
+ when S_FILTER_I =>
+ -- wait until filtering is done
+ if fir_iack='1' then
+ -- start filter (Q)
+ fir_iclk <= '1';
+ fir_idata <= ic_q1;
+ fir_ichan <= resize(ic_chan & "1", fir_ichan'length);
+
+ -- update status
+ state <= S_FILTER_Q;
+ end if;
+
+ when S_FILTER_Q =>
+ -- wait until filtering is done
+ if fir_iack='1' then
+ -- update status
+ state <= S_COOLDOWN;
+ end if;
+
+ when S_COOLDOWN =>
+ -- TODO: get rid of state
+ if fir_oclk='1' then
+ state <= S_IDLE;
+ end if;
+ end case;
+
+ -- fetch FIR result and corresonding center-sample
+ if fir_oclk='1' then
+ on_clk <= '1';
+ on_chan <= fir_ochan;
+ on_dat1 <= fir_odata;
+ sel := to_integer(fir_ochan)/2;
+ if fir_ochan(0)='0'
+ then on_dat2 <= cent_i(sel);
+ else on_dat2 <= cent_q(sel);
+ end if;
+ end if;
+
+ -- create final result
+ if on_clk='1' then
+ oc_iclk <= '1';
+ oc_ichan <= on_chan;
+ oc_idata <= resize((resize(on_dat1,19) + resize(on_dat2,19)) / 2,18);
+ end if;
+
+ -- handle reset
+ if reset='1' then
+ state <= S_IDLE;
+ fir_iclk <= '0';
+ fir_idata <= (others=>'0');
+ fir_ichan <= (others=>'0');
+ oc_iclk <= '0';
+ oc_ichan <= (others=>'0');
+ oc_idata <= (others=>'0');
+ on_clk <= '0';
+ on_chan <= (others=>'0');
+ on_dat1 <= (others=>'0');
+ on_dat2 <= (others=>'0');
+ end if;
+ end if;
+ end process;
+
+ -- create ready-flag
+ ic_ready <= '1' when state=S_IDLE else '0';
+
+ -- shift register for center-sample
+ sreg: for i in 0 to N-1 generate
+ subtype entry_t is signed(35 downto 0);
+ type sreg_t is array(natural range<>) of entry_t;
+ signal sreg : sreg_t(11 downto 0) := (others=>(others=>'0'));
+ begin
+
+ -- infer shift-register
+ process(clk)
+ variable temp : entry_t;
+ begin
+ if rising_edge(clk) then
+ if ic_clk='1' and to_integer(ic_chan)=i then
+ temp := ic_q0 & ic_i0;
+ sreg <= sreg(sreg'left-1 downto 0) & temp;
+ end if;
+ end if;
+ end process;
+
+ -- output center-sample
+ cent_i(i) <= sreg(sreg'left)(17 downto 0);
+ cent_q(i) <= sreg(sreg'left)(35 downto 18);
+ end generate;
+
+ -- input control
+ ic: entity usbrx_halfband_ictrl
+ generic map (
+ N => N
+ )
+ port map (
+ -- common
+ clk => clk,
+ reset => reset,
+
+ -- input
+ in_clk => in_clk,
+ in_i => in_i,
+ in_q => in_q,
+
+ -- output
+ out_ready => ic_ready,
+ out_clk => ic_clk,
+ out_chan => ic_chan,
+ out_i0 => ic_i0,
+ out_i1 => ic_i1,
+ out_q0 => ic_q0,
+ out_q1 => ic_q1
+ );
+
+ -- FIR filter core
+ fir: entity mt_fir_symmetric_slow
+ generic map (
+ CHANNELS => 2*N,
+ TAPS => 12,
+ COEFFS => coeffs,
+ RAMSTYLE => "block_ram",
+ ROMSTYLE => "logic"
+ )
+ port map (
+ -- common
+ clk => clk,
+ reset => reset,
+
+ -- input port
+ in_clk => fir_iclk,
+ in_ack => fir_iack,
+ in_data => fir_idata,
+ in_chan => fir_ichan,
+
+ -- output port
+ out_clk => fir_oclk,
+ out_chan => fir_ochan,
+ out_data => fir_odata
+ );
+
+ -- output control
+ oc: entity usbrx_halfband_octrl
+ generic map (
+ N => N
+ )
+ port map (
+ -- common
+ clk => clk,
+ reset => reset,
+
+ -- input
+ in_clk => oc_iclk,
+ in_chan => oc_ichan,
+ in_data => oc_idata,
+
+ -- output
+ out_clk => out_clk,
+ out_i => out_i,
+ out_q => out_q
+ );
+
+end rtl;
diff --git a/fpga/hw-v2/src/usbrx/toplevel/usbrx_clkgen.vhd b/fpga/hw-v2/src/usbrx/toplevel/usbrx_clkgen.vhd
new file mode 100644
index 0000000..382cd78
--- /dev/null
+++ b/fpga/hw-v2/src/usbrx/toplevel/usbrx_clkgen.vhd
@@ -0,0 +1,165 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : usbrx_clkgen.vhd
+-- Project : OsmoSDR FPGA Firmware
+-- Purpose : Clock Management
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.std_logic_misc.all;
+ use ieee.numeric_std.all;
+library xp2;
+ use xp2.all;
+ use xp2.components.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+
+entity usbrx_clkgen is
+ port(
+ -- clock input
+ clk_30_pclk : in std_logic; -- 30MHz
+ ext_rst : in std_logic; -- external reset
+
+ -- system clock
+ clk_30 : out std_logic; -- 30MHz clock
+ clk_80 : out std_logic; -- 80MHz clock
+ rst_30 : out std_logic; -- 30MHz reset
+ rst_80 : out std_logic; -- 80MHz reset
+
+ -- debug
+ dbg_ext : out std_logic;
+ dbg_rst : out std_logic;
+ dbg_lock : out std_logic
+ );
+end usbrx_clkgen;
+
+architecture rtl of usbrx_clkgen is
+
+ -- reset generation
+ signal rst_pll : std_logic; -- reset signal for PLLs
+ signal pll_locked : std_logic; -- PLLs locked
+ signal reset_i : std_logic; -- reset-signal
+
+ -- system clock management
+ signal clk_80_pll : std_logic;
+
+ -- enusure that signal-names are kept (important for timing contraints)
+ attribute syn_keep of clk_80_pll : signal is true;
+
+ -- component declaration
+ component EPLLD1
+ generic (CLKOK_BYPASS : in String; CLKOS_BYPASS : in String;
+ CLKOP_BYPASS : in String; DUTY : in Integer;
+ PHASEADJ : in String; PHASE_CNTL : in String;
+ CLKOK_DIV : in Integer; CLKFB_DIV : in Integer;
+ CLKOP_DIV : in Integer; CLKI_DIV : in Integer;
+ FIN : in String);
+ port (CLKI: in std_logic; CLKFB: in std_logic; RST: in std_logic;
+ RSTK: in std_logic; DPAMODE: in std_logic; DRPAI3: in std_logic;
+ DRPAI2: in std_logic; DRPAI1: in std_logic; DRPAI0: in std_logic;
+ DFPAI3: in std_logic; DFPAI2: in std_logic; DFPAI1: in std_logic;
+ DFPAI0: in std_logic; PWD: in std_logic; CLKOP: out std_logic;
+ CLKOS: out std_logic; CLKOK: out std_logic; LOCK: out std_logic;
+ CLKINTFB: out std_logic);
+ end component;
+
+begin
+
+ --
+ -- reset generation
+ --
+
+ -- generate asynchronous reset-signal
+ rg: entity mt_reset_gen
+ port map (
+ clk => clk_30_pclk,
+ ext_rst => ext_rst,
+ pll_locked => pll_locked,
+ reset_pll => rst_pll,
+ reset_sys => reset_i,
+
+
+ -- debug
+ dbg_ext => dbg_ext,
+ dbg_rst => dbg_rst,
+ dbg_lock => dbg_lock
+ );
+
+ -- sync reset to clock-domains
+ rs30: entity mt_reset_sync
+ port map (
+ clk => clk_30_pclk,
+ rst_in => reset_i,
+ rst_out => rst_30
+ );
+ rs80: entity mt_reset_sync
+ port map (
+ clk => clk_80_pll,
+ rst_in => reset_i,
+ rst_out => rst_80
+ );
+
+ --
+ -- system clock
+ --
+
+ -- PLL for system-clock
+ pll : EPLLD1
+ generic map (
+ FIN => "30.0",
+ CLKOK_BYPASS => "DISABLED",
+ CLKOS_BYPASS => "DISABLED",
+ CLKOP_BYPASS => "DISABLED",
+ PHASE_CNTL => "STATIC",
+ DUTY => 8,
+ PHASEADJ => "0.0",
+ CLKOK_DIV => 2,
+ CLKOP_DIV => 8,
+ CLKFB_DIV => 8,
+ CLKI_DIV => 3
+ )
+ port map (
+ CLKI => clk_30_pclk,
+ CLKFB => clk_80_pll,
+ RST => rst_pll,
+ RSTK => '0',
+ DPAMODE => '0',
+ DRPAI3 => '0',
+ DRPAI2 => '0',
+ DRPAI1 => '0',
+ DRPAI0 => '0',
+ DFPAI3 => '0',
+ DFPAI2 => '0',
+ DFPAI1 => '0',
+ DFPAI0 => '0',
+ PWD => '0',
+ CLKOP => clk_80_pll,
+ CLKOS => open,
+ CLKOK => open,
+ LOCK => pll_locked,
+ CLKINTFB=> open
+ );
+
+ -- output clocks
+ clk_30 <= clk_30_pclk;
+ clk_80 <= clk_80_pll;
+
+end rtl;
diff --git a/fpga/hw-v2/src/usbrx/toplevel/usbrx_pwm.vhd b/fpga/hw-v2/src/usbrx/toplevel/usbrx_pwm.vhd
new file mode 100644
index 0000000..c71e3a2
--- /dev/null
+++ b/fpga/hw-v2/src/usbrx/toplevel/usbrx_pwm.vhd
@@ -0,0 +1,100 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : usbrx_pwm.vhd
+-- Project : OsmoSDR FPGA Firmware
+-- Purpose : PWM Generator
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.usbrx.all;
+
+entity usbrx_pwm is
+ port(
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- config
+ config : in usbrx_pwm_config_t;
+
+ -- PWM output
+ pwm0 : out std_logic;
+ pwm1 : out std_logic
+ );
+end usbrx_pwm;
+
+architecture rtl of usbrx_pwm is
+
+ -- status
+ signal counter0 : unsigned(15 downto 0);
+ signal counter1 : unsigned(15 downto 0);
+ signal out0 : std_logic;
+ signal out1 : std_logic;
+
+begin
+
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ -- update counter #0
+ counter0 <= counter0 - 1;
+ if counter0 = 0 then
+ counter0 <= config.freq0;
+ end if;
+
+ -- update counter #1
+ counter1 <= counter1 - 1;
+ if counter1 = 0 then
+ counter1 <= config.freq1;
+ end if;
+
+ -- update output #0
+ if counter0 < config.duty0
+ then out0 <= '1';
+ else out0 <= '0';
+ end if;
+
+ -- update output #1
+ if counter1 < config.duty1
+ then out1 <= '1';
+ else out1 <= '0';
+ end if;
+
+ -- output register
+ pwm0 <= out0;
+ pwm1 <= out1;
+
+ -- handle reset
+ if reset='1' then
+ counter0 <= (others=>'0');
+ counter1 <= (others=>'0');
+ out0 <= '0';
+ out1 <= '0';
+ pwm0 <= '0';
+ pwm1 <= '0';
+ end if;
+ end if;
+ end process;
+
+end rtl;
diff --git a/fpga/hw-v2/src/usbrx/toplevel/usbrx_regbank.vhd b/fpga/hw-v2/src/usbrx/toplevel/usbrx_regbank.vhd
new file mode 100644
index 0000000..feb4bd8
--- /dev/null
+++ b/fpga/hw-v2/src/usbrx/toplevel/usbrx_regbank.vhd
@@ -0,0 +1,194 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : usbrx_regbank.vhd
+-- Project : OsmoSDR FPGA Firmware
+-- Purpose : Registerbank
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.usbrx.all;
+
+entity usbrx_regbank is
+ port(
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- config
+ cfg_pwm : out usbrx_pwm_config_t;
+ cfg_adc : out usbrx_adc_config_t;
+ cfg_ssc : out usbrx_ssc_config_t;
+ cfg_fil : out usbrx_fil_config_t;
+ cfg_off : out usbrx_off_config_t;
+
+ -- status (TODO HACK)
+ adc_i : in unsigned(13 downto 0);
+ adc_q : in unsigned(13 downto 0);
+
+ -- SPI interface
+ spi_ncs : in std_logic;
+ spi_sclk : in std_logic;
+ spi_mosi : in std_logic;
+ spi_miso : out std_logic
+ );
+end usbrx_regbank;
+
+architecture rtl of usbrx_regbank is
+
+ -- bus interface
+ signal bus_rena : std_logic;
+ signal bus_wena : std_logic;
+ signal bus_addr : unsigned(6 downto 0);
+ signal bus_rdata : std_logic_vector(31 downto 0);
+ signal bus_wdata : std_logic_vector(31 downto 0);
+
+ -- registers
+ signal reg_pwm1 : std_logic_vector(31 downto 0);
+ signal reg_pwm2 : std_logic_vector(31 downto 0);
+ signal reg_adc : std_logic_vector(15 downto 0);
+ signal reg_ssc1 : std_logic_vector(0 downto 0);
+ signal reg_ssc2 : std_logic_vector(7 downto 0);
+ signal reg_fil : std_logic_vector(2 downto 0);
+ signal reg_off : std_logic_vector(31 downto 0);
+
+ -- avoid block-ram inference
+ attribute syn_romstyle : string;
+ attribute syn_romstyle of rtl : architecture is "logic";
+
+begin
+
+ -- SPI slave
+ spi: entity usbrx_spi
+ port map (
+ -- common
+ clk => clk,
+ reset => reset,
+
+ -- SPI interface
+ spi_ncs => spi_ncs,
+ spi_sclk => spi_sclk,
+ spi_mosi => spi_mosi,
+ spi_miso => spi_miso,
+
+ -- bus interface
+ bus_rena => bus_rena,
+ bus_wena => bus_wena,
+ bus_addr => bus_addr,
+ bus_rdata => bus_rdata,
+ bus_wdata => bus_wdata
+ );
+
+ -- handle requests
+ process(reset, clk)
+ begin
+ if reset = '1' then
+ bus_rdata <= (others=>'0');
+ reg_pwm1 <= x"17701F3F";
+ reg_pwm2 <= x"07D01F3F";
+ reg_adc <= x"0401";
+ reg_ssc1 <= "0";
+ reg_ssc2 <= x"01";
+ reg_fil <= "011";
+ reg_off <= x"00000000";
+ elsif rising_edge(clk) then
+ -- output zeros by default
+ bus_rdata <= (others=>'0');
+
+ -- handle requests
+ case to_integer(bus_addr) is
+ when 0 =>
+ -- identification
+ bus_rdata <= x"DEADBEEF";
+
+ when 1 =>
+ -- PWM #1
+ bus_rdata <= reg_pwm1;
+ if bus_wena='1' then
+ reg_pwm1 <= bus_wdata(31 downto 0);
+ end if;
+
+ when 2 =>
+ -- PWM #2
+ bus_rdata <= reg_pwm2;
+ if bus_wena='1' then
+ reg_pwm2 <= bus_wdata(31 downto 0);
+ end if;
+
+ when 3 =>
+ -- ADC interface
+ bus_rdata <= to_slv32(reg_adc);
+ if bus_wena='1' then
+ reg_adc <= bus_wdata(15 downto 0);
+ end if;
+
+ when 4 =>
+ -- SSC interface
+ bus_rdata( 0 downto 0) <= reg_ssc1;
+ bus_rdata(15 downto 8) <= reg_ssc2;
+ if bus_wena='1' then
+ reg_ssc1 <= bus_wdata( 0 downto 0);
+ reg_ssc2 <= bus_wdata(15 downto 8);
+ end if;
+
+ when 5 =>
+ -- ADC Quickhack
+ bus_rdata(15 downto 0) <= to_slv16(adc_i);
+ bus_rdata(31 downto 16) <= to_slv16(adc_q);
+
+ when 6 =>
+ -- decimation filter
+ bus_rdata <= to_slv32(reg_fil);
+ if bus_wena='1' then
+ reg_fil <= bus_wdata(2 downto 0);
+ end if;
+
+ when 7 =>
+ -- offset stage
+ bus_rdata <= reg_off;
+ if bus_wena='1' then
+ reg_off <= bus_wdata(31 downto 0);
+ end if;
+
+ when others =>
+ -- invalid address
+ null;
+ end case;
+ end if;
+ end process;
+
+ -- map registers to config
+ cfg_pwm.freq0 <= unsigned(reg_pwm1(15 downto 0));
+ cfg_pwm.freq1 <= unsigned(reg_pwm2(15 downto 0));
+ cfg_pwm.duty0 <= unsigned(reg_pwm1(31 downto 16));
+ cfg_pwm.duty1 <= unsigned(reg_pwm2(31 downto 16));
+ cfg_adc.clkdiv <= unsigned(reg_adc( 7 downto 0));
+ cfg_adc.acqlen <= unsigned(reg_adc(15 downto 8));
+ cfg_ssc.tmode <= reg_ssc1(0);
+ cfg_ssc.clkdiv <= unsigned(reg_ssc2);
+ cfg_fil.decim <= unsigned(reg_fil);
+ cfg_fil.decim <= unsigned(reg_fil);
+ cfg_off.ioff <= signed(reg_off(15 downto 0));
+ cfg_off.qoff <= signed(reg_off(31 downto 16));
+
+end rtl;
diff --git a/fpga/hw-v2/src/usbrx/toplevel/usbrx_spi.vhd b/fpga/hw-v2/src/usbrx/toplevel/usbrx_spi.vhd
new file mode 100644
index 0000000..1c3b541
--- /dev/null
+++ b/fpga/hw-v2/src/usbrx/toplevel/usbrx_spi.vhd
@@ -0,0 +1,215 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : usbrx_spi.vhd
+-- Project : OsmoSDR FPGA Firmware
+-- Purpose : SPI Slave Implementation
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+
+entity usbrx_spi is
+ port(
+ -- common
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- SPI interface
+ spi_ncs : in std_logic;
+ spi_sclk : in std_logic;
+ spi_mosi : in std_logic;
+ spi_miso : out std_logic;
+
+ -- bus interface
+ bus_rena : out std_logic;
+ bus_wena : out std_logic;
+ bus_addr : out unsigned(6 downto 0);
+ bus_rdata : in std_logic_vector(31 downto 0);
+ bus_wdata : out std_logic_vector(31 downto 0)
+ );
+end usbrx_spi;
+
+architecture rtl of usbrx_spi is
+
+ -- internal types
+ type state_t is (S_COMMAND, S_WRITE, S_READ2, S_READ3, S_READ4);
+
+ -- IO-registers
+ signal iob_ncs : std_logic;
+ signal iob_sclk : std_logic;
+ signal iob_mosi : std_logic;
+
+ -- synchronized inputs
+ signal sync_ncs : std_logic;
+ signal sync_sclk : std_logic;
+ signal sync_mosi : std_logic;
+
+ -- edge detection
+ signal last_sclk : std_logic;
+ signal last_re : std_logic;
+ signal last_fe : std_logic;
+
+ -- SPI slave
+ signal state : state_t;
+ signal remain : unsigned(5 downto 0);
+ signal sireg : std_logic_vector(31 downto 0);
+ signal soreg : std_logic_vector(32 downto 0);
+ signal addr : unsigned(6 downto 0);
+
+begin
+
+ -- IOBs
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ iob_ncs <= spi_ncs;
+ iob_sclk <= spi_sclk;
+ iob_mosi <= spi_mosi;
+ if iob_ncs='0'
+ then spi_miso <= soreg(32);
+ else spi_miso <= '1';
+ end if;
+ end if;
+ end process;
+
+ -- input synchronizer
+ process(clk,reset)
+ begin
+ if reset = '1' then
+ sync_ncs <= '1';
+ sync_sclk <= '0';
+ sync_mosi <= '0';
+ elsif rising_edge(clk) then
+ sync_ncs <= iob_ncs;
+ sync_sclk <= iob_sclk;
+ sync_mosi <= iob_mosi;
+ end if;
+ end process;
+
+ -- SPI slave
+ process(clk,reset)
+ variable re,fe : std_logic;
+ begin
+ if reset = '1' then
+ last_sclk <= '0';
+ last_re <= '0';
+ last_fe <= '0';
+ state <= S_COMMAND;
+ remain <= (others=>'0');
+ sireg <= (others=>'1');
+ soreg <= (others=>'1');
+ addr <= (others=>'0');
+ bus_rena <= '0';
+ bus_wena <= '0';
+ bus_addr <= (others=>'0');
+ bus_wdata <= (others=>'0');
+ elsif rising_edge(clk) then
+ -- set default values
+ bus_rena <= '0';
+ bus_wena <= '0';
+
+ -- detect edges on clock line
+ last_sclk <= sync_sclk;
+ re := sync_sclk and (not last_sclk);
+ fe := (not sync_sclk) and last_sclk;
+ last_re <= re;
+ last_fe <= fe;
+
+ -- update shift-registers
+ if re='1' then
+ sireg <= sireg(30 downto 0) & sync_mosi;
+ end if;
+ if fe='1' then
+ soreg <= soreg(31 downto 0) & '1';
+ end if;
+
+ -- check state of chip-select
+ if sync_ncs='1' then
+ --> CS deasserted, reset slave
+ state <= S_COMMAND;
+ remain <= to_unsigned(7,6);
+ else
+ --> CS asserted, tick state-machine
+ case state is
+ when S_COMMAND =>
+ -- wait until 8 bits were received
+ if last_re='1' then
+ remain <= remain - 1;
+ if remain=0 then
+ --> got 8 bits, decode address & direction
+ addr <= unsigned(sireg(6 downto 0));
+ remain <= to_unsigned(31,6);
+ if sireg(7)='1' then
+ state <= S_READ2;
+ bus_rena <= '1';
+ bus_addr <= unsigned(sireg(6 downto 0));
+ else
+ state <= S_WRITE;
+ end if;
+ end if;
+ end if;
+
+ when S_WRITE =>
+ -- wait until 32 bits were received
+ if last_re='1' then
+ remain <= remain - 1;
+ if remain=0 then
+ -- issue write-request
+ bus_wena <= '1';
+ bus_addr <= addr;
+ bus_wdata <= sireg;
+
+ -- continue with next word
+ addr <= addr + 1;
+ remain <= to_unsigned(31,6);
+ end if;
+ end if;
+
+ when S_READ2 =>
+ -- wait-state
+ state <= S_READ3;
+
+ when S_READ3 =>
+ -- load shift-register
+ soreg <= soreg(32) & bus_rdata;
+ state <= S_READ4;
+ remain <= to_unsigned(31,6);
+
+ when S_READ4 =>
+ -- wait until 32 bits were transmitted
+ if fe='1' then
+ remain <= remain - 1;
+ if remain=0 then
+ -- continue with next word
+ bus_rena <= '1';
+ bus_addr <= addr + 1;
+ addr <= addr + 1;
+ state <= S_READ2;
+ end if;
+ end if;
+ end case;
+ end if;
+ end if;
+ end process;
+
+end rtl;
diff --git a/fpga/hw-v2/src/usbrx/toplevel/usbrx_toplevel.vhd b/fpga/hw-v2/src/usbrx/toplevel/usbrx_toplevel.vhd
new file mode 100644
index 0000000..b0b9010
--- /dev/null
+++ b/fpga/hw-v2/src/usbrx/toplevel/usbrx_toplevel.vhd
@@ -0,0 +1,331 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : usbrx_toplevel.vhd
+-- Project : OsmoSDR FPGA Firmware
+-- Purpose : Toplevel component
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.std_logic_misc.all;
+ use ieee.numeric_std.all;
+library work;
+ use work.all;
+ use work.mt_toolbox.all;
+ use work.usbrx.all;
+
+entity usbrx_toplevel is
+ port (
+ -- common
+ clk_in_pclk : in std_logic;
+
+ -- special control
+ dings : in std_logic;
+ dingsrst : in std_logic;
+
+ -- ADC interface
+ adc_cs : out std_logic;
+ adc_sck : out std_logic;
+ adc_sd1 : in std_logic;
+ adc_sd2 : in std_logic;
+
+ -- control SPI
+ ctl_int : out std_logic;
+ ctl_cs : in std_logic;
+ ctl_sck : in std_logic;
+ ctl_mosi : in std_logic;
+ ctl_miso : out std_logic;
+
+ -- data SPIs
+ rx_clk : out std_logic;
+ rx_syn : out std_logic;
+ rx_dat : out std_logic;
+
+ -- data SPIs
+ tx_clk : in std_logic;
+ tx_syn : in std_logic;
+ tx_dat : in std_logic;
+
+ -- gain PWMs
+ gain0 : out std_logic;
+ gain1 : out std_logic;
+
+ -- GPS
+ gps_1pps : in std_logic;
+ gps_10k : in std_logic;
+
+ -- gpios
+ gpio : inout std_logic_vector(9 downto 0);
+
+ -- virtual GNDs/VCCs
+ vgnd : out std_logic_vector(11 downto 0);
+ vcc33 : inout std_logic_vector(11 downto 0);
+ vcc12 : inout std_logic_vector(4 downto 0)
+ );
+end usbrx_toplevel;
+
+architecture rtl of usbrx_toplevel is
+
+ -- clocks
+ signal clk_30 : std_logic;
+ signal clk_80 : std_logic;
+ signal rst_30 : std_logic;
+ signal rst_80 : std_logic;
+
+ -- config
+ signal cfg_pwm : usbrx_pwm_config_t;
+ signal cfg_adc : usbrx_adc_config_t;
+ signal cfg_ssc : usbrx_ssc_config_t;
+ signal cfg_fil : usbrx_fil_config_t;
+ signal cfg_off : usbrx_off_config_t;
+
+ -- ADC <-> offset
+ signal adc_off_clk : std_logic;
+ signal adc_off_i : unsigned(13 downto 0);
+ signal adc_off_q : unsigned(13 downto 0);
+
+ -- offset <-> filter
+ signal off_fil_clk : std_logic;
+ signal off_fil_i : signed(15 downto 0);
+ signal off_fil_q : signed(15 downto 0);
+
+ -- filter <-> output
+ signal fil_out_clk : std_logic;
+ signal fil_out_i : signed(15 downto 0);
+ signal fil_out_q : signed(15 downto 0);
+
+ -- blinken lights
+ signal blcnt1 : unsigned(31 downto 0) := x"00000000";
+ signal blcnt2 : unsigned(31 downto 0) := x"00000000";
+ signal blcnt3 : unsigned(31 downto 0) := x"00000000";
+ signal blink1 : std_logic := '0';
+ signal blink2 : std_logic := '0';
+ signal blink3 : std_logic := '0';
+
+ -- enusure that signal-names are kept (important for timing contraints)
+ attribute syn_keep of clk_in_pclk : signal is true;
+
+ -- debug
+ signal dbg_ext : std_logic;
+ signal dbg_rst : std_logic;
+ signal dbg_lock : std_logic;
+
+begin
+
+ -- house-keeping
+ cg: entity usbrx_clkgen
+ port map (
+ -- clock input
+ clk_30_pclk => clk_in_pclk,
+ ext_rst => dingsrst,
+
+ -- system clock
+ clk_30 => clk_30,
+ clk_80 => clk_80,
+ rst_30 => rst_30,
+ rst_80 => rst_80,
+
+ -- debug
+ dbg_ext => dbg_ext,
+ dbg_rst => dbg_rst,
+ dbg_lock => dbg_lock
+ );
+
+ -- register bank
+ rb: entity usbrx_regbank
+ port map (
+ -- common
+ clk => clk_80,
+ reset => rst_80,
+
+ -- config
+ cfg_pwm => cfg_pwm,
+ cfg_adc => cfg_adc,
+ cfg_ssc => cfg_ssc,
+ cfg_fil => cfg_fil,
+ cfg_off => cfg_off,
+
+ -- status (TODO HACK)
+ adc_i => adc_off_i,
+ adc_q => adc_off_q,
+
+ -- SPI interface
+ spi_ncs => ctl_cs,
+ spi_sclk => ctl_sck,
+ spi_mosi => ctl_mosi,
+ spi_miso => ctl_miso
+ );
+
+ -- gain PWMs
+ pwm: entity usbrx_pwm
+ port map (
+ -- common
+ clk => clk_80,
+ reset => rst_80,
+
+ -- config
+ config => cfg_pwm,
+
+ -- PWM output
+ pwm0 => gain0,
+ pwm1 => gain1
+ );
+
+ -- A/D interface
+ adc: entity usbrx_ad7357
+ port map (
+ -- common
+ clk => clk_80,
+ reset => rst_80,
+
+ -- config
+ config => cfg_adc,
+
+ -- ADC interface
+ adc_cs => adc_cs,
+ adc_sck => adc_sck,
+ adc_sd1 => adc_sd1,
+ adc_sd2 => adc_sd2,
+
+ -- output
+ out_clk => adc_off_clk,
+ out_i => adc_off_i,
+ out_q => adc_off_q
+ );
+
+ -- offset stage
+ off: entity usbrx_offset
+ port map (
+ -- common
+ clk => clk_80,
+ reset => rst_80,
+
+ -- config
+ config => cfg_off,
+
+ -- input
+ in_clk => adc_off_clk,
+ in_i => adc_off_i,
+ in_q => adc_off_q,
+
+ -- output
+ out_clk => off_fil_clk,
+ out_i => off_fil_i,
+ out_q => off_fil_q
+ );
+
+
+ -- decimation filter
+ fil: entity usbrx_decimate
+ port map (
+ -- common
+ clk => clk_80,
+ reset => rst_80,
+
+ -- config
+ config => cfg_fil,
+
+ -- input
+ in_clk => off_fil_clk,
+ in_i => off_fil_i,
+ in_q => off_fil_q,
+
+ -- output
+ out_clk => fil_out_clk,
+ out_i => fil_out_i,
+ out_q => fil_out_q
+ );
+
+ -- SSC output
+ ssc: entity usbrx_ssc
+ port map (
+ -- common
+ clk => clk_80,
+ reset => rst_80,
+
+ -- config
+ config => cfg_ssc,
+
+ -- output
+ in_clk => fil_out_clk,
+ in_i => fil_out_i,
+ in_q => fil_out_q,
+
+ -- SSC interface
+ ssc_clk => rx_clk,
+ ssc_syn => rx_syn,
+ ssc_dat => rx_dat
+ );
+
+ -- TODO
+ ctl_int <= '1';
+-- tx_clk <= '0';
+
+ -- blinken lights
+ process(clk_in_pclk)
+ begin
+ if rising_edge(clk_in_pclk) then
+ if blcnt1=0 then
+ blcnt1 <= to_unsigned(30000000/2-1, 32);
+ blink1 <= not blink1;
+ else
+ blcnt1 <= blcnt1-1;
+ end if;
+ end if;
+ end process;
+ process(clk_30)
+ begin
+ if rising_edge(clk_30) then
+ if rst_30='1' then
+ blcnt2 <= (others=>'0');
+ blink2 <= '0';
+ elsif blcnt2=0 then
+ blcnt2 <= to_unsigned(30000000/2-1, 32);
+ blink2 <= not blink2;
+ else
+ blcnt2 <= blcnt2-1;
+ end if;
+ end if;
+ end process;
+ process(clk_80)
+ begin
+ if rising_edge(clk_80) then
+ if rst_80='1' then
+ blcnt3 <= (others=>'0');
+ blink3 <= '0';
+ elsif blcnt3=0 then
+ blcnt3 <= to_unsigned(80000000/2-1, 32);
+ blink3 <= not blink3;
+ else
+ blcnt3 <= blcnt3-1;
+ end if;
+ end if;
+ end process;
+
+ -- 8 7 6 5 4 3 2 1
+ gpio <= "00" & clk_80 & clk_30 & dbg_ext & dbg_rst & dbg_lock & blink3 & blink2 & blink1;
+
+ -- virtual GNDs/VCCs
+ vgnd <= (others=>'0');
+ vcc12 <= (others=>'Z');
+ vcc33 <= (others=>'1');
+
+end rtl;
+
+
diff --git a/fpga/hw-v2/src/usbrx/usbrx.vhd b/fpga/hw-v2/src/usbrx/usbrx.vhd
new file mode 100644
index 0000000..59d4f11
--- /dev/null
+++ b/fpga/hw-v2/src/usbrx/usbrx.vhd
@@ -0,0 +1,66 @@
+---------------------------------------------------------------------------------------------------
+-- Filename : usbrx.vhd
+-- Project : OsmoSDR FPGA Firmware
+-- Purpose : OsmoSDR package
+---------------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------
+-- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany --
+-- written by Matthias Kleffel --
+-- --
+-- This program is free software; you can redistribute it and/or modify --
+-- it under the terms of the GNU General Public License as published by --
+-- the Free Software Foundation as version 3 of the License, or --
+-- --
+-- This program is distributed in the hope that it will be useful, --
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
+-- GNU General Public License V3 for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+package usbrx is
+
+ -- PWM config
+ type usbrx_pwm_config_t is record
+ freq0 : unsigned(15 downto 0);
+ freq1 : unsigned(15 downto 0);
+ duty0 : unsigned(15 downto 0);
+ duty1 : unsigned(15 downto 0);
+ end record;
+
+ -- ADC interface config
+ type usbrx_adc_config_t is record
+ clkdiv : unsigned(7 downto 0);
+ acqlen : unsigned(7 downto 0);
+ end record;
+
+ -- SSC interface config
+ type usbrx_ssc_config_t is record
+ clkdiv : unsigned(7 downto 0);
+ tmode : std_logic;
+ end record;
+
+ -- offset stage
+ type usbrx_off_config_t is record
+ ioff : signed(15 downto 0);
+ qoff : signed(15 downto 0);
+ end record;
+
+ -- decimation filter config
+ type usbrx_fil_config_t is record
+ decim : unsigned(2 downto 0);
+ end record;
+
+end usbrx;
+
+package body usbrx is
+ -- nothing so far
+end usbrx;
+