Commit e8e3a4fc authored by A. Hahn's avatar A. Hahn

merge master into gsi_master_get_back_on_trask_2024

parents a637d457 3c636a53
[submodule "testbench/osvvm/upstream"]
path = testbench/osvvm/upstream
url = https://github.com/OSVVM/OSVVM.git
......@@ -9,9 +9,18 @@ Change Log
- Format inspired by: `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_
- Versioning scheme follows: `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_
1.1.4 - 2023-10-18
==================
https://www.ohwr.org/project/general-cores/tags/v1.1.4
Fixed
-----
- sw: kernel compatibilty with modern version
1.1.3 - 2021-08-23
==================
https://www.ohwr.org/project/general-cores/tags/v1.1.2
https://www.ohwr.org/project/general-cores/tags/v1.1.3
Fixed
-----
......
......@@ -4,6 +4,7 @@ modules = {
"modules/common",
"modules/genrams",
"modules/wishbone",
"modules/dsp",
"modules/radtol",
"platform"
]
......
......@@ -205,6 +205,11 @@ Directory [modules/wishbone](modules/wishbone) contains modules for wishbone.
interface to the digital thermometer.
- [wb_xc7_fw_update](modules/wishbone/wb_xc7_fw_update) is an SPI interface
to drive the xc7 bitstream spi flash (using the ht-flash tool).
- [wb_clock_monitor](modules/wishbone/wb_clock_monitor) is clock frequency
measurement/monitoring core with a programmable number of channels.
- [wb_lm32_mcs](modules/wishbone/wb_lm32_mcs) is a single-entity microcontroller
based on the LM32 softcore, featuring internal code/data RAM, UART, timer and
a pipelined Wishbone peripheral interface.
* There are utilities to handle a wishbone bus:
- [wb_clock_crossing](modules/wishbone/wb_clock_crossing) handle clock domain
......@@ -228,6 +233,9 @@ Directory [modules/wishbone](modules/wishbone) contains modules for wishbone.
a bridge from axi4full64 to axi4lite32. It was defined to interface with
the Vivado PCI-e bridge and doesn't support all the axi4full features
(in particular the burst accesses).
- [mpsoc_int_gen](modules/axi/mpsoc_int_gen) is a module that generates a
PCIe interrupt when a signal goes high (by writting a specific register
in the PS).
* There a modules to build a bus hierarchy:
- [wb_bus_fanout](modules/wishbone/wb_bus_fanout) is a simple master to
......@@ -243,3 +251,16 @@ Directory [modules/wishbone](modules/wishbone) contains modules for wishbone.
create metadata for the convention.
- [wb_indirect](modules/wishbone/wb_indirect) provides a wishbone
master driven by an address and a data registers.
In [modules/dsp](modules/dsp) there are digital signal processing-related cores:
- [gc_cordic](modules/dsp/gc_cordic) is a pipelined CORDIC core, capable of calculating
sine/cosine/magnitude/argument of fixed-point complex numbers.
- [gc_iq_modulator](modules/dsp/gc_iq_modulator) is a Fs/4 IQ modulator (upconverter)
- [gc_iq_demodulator](modules/dsp/gc_iq_demodulator) is a Fs/4 IQ demodulator (downconverter)
- [gc_pipelined_fir_filter](modules/dsp/gc_pipelined_fir_filter) is a generic FIR filter IP inferring FPGA's DSP macros
- [gc_integer_divide](modules/dsp/gc_integer_divide) is a generic sequential integer/fixed-point divider IP.
Can work with signed/unsigned numbers, also supports remainder calculation.
- [gc_soft_ramp_switch](modules/dsp/gc_soft_ramp_switch) is a "soft switch" to enable/disable a DAC output gently.
......@@ -3,6 +3,7 @@ modules = { "local" : [
"axi4lite_wb_bridge",
"axi4lite32_axi4full64_bridge",
"axi4lite_axi4full_bridge",
"mpsoc_int_gen",
]}
files = [
......
-------------------------------------------------------------------------------
-- Title : AXI4Full64 to AXI4Lite32 bridge
-- Title : AXI4Lite to AXI4Full bridge
-- Project : General Cores
-------------------------------------------------------------------------------
-- File : axi4lite32_axi4full64_bridge.vhd
-- File : axi4lite_axi4full_bridge.vhd
-- Company : CERN
-- Platform : FPGA-generics
-- Standard : VHDL '93
......@@ -230,8 +230,11 @@ begin
-- Read part.
m_araddr <= raddr;
s_rdata <= rdata;
s_rid <= rid;
s_rdata <= rdata;
s_rid <= rid;
s_rlast <= '1' when (unsigned(rlen)=0 and s_rready = '1' and s_rvalid = '1')
else '0';
process (clk_i)
begin
......@@ -240,7 +243,6 @@ begin
rstate <= RD_IDLE;
s_arready <= '1';
s_rvalid <= '0';
s_rlast <= '0';
m_arvalid <= '0';
m_rready <= '0';
raddr <= (others => 'X');
......@@ -275,6 +277,7 @@ begin
m_arvalid <= '0';
end if;
if m_rvalid = '1' then
m_rready <= '0';
-- Read data. Address must have been acked.
-- According to A3.4.3 of AXI4 spec, the AXI4 bus is little
-- endian.
......@@ -283,11 +286,6 @@ begin
-- To master.
rstate <= RD_SLAVE;
s_rresp <= RSP_OKAY;
if rlen = (g_LEN_WIDTH - 1 downto 0 => '0') then
s_rlast <= '1';
else
s_rlast <= '0';
end if;
s_rvalid <= '1';
end if;
......
files = [
"mpsoc_int_gen.vhd",
];
-------------------------------------------------------------------------------
-- Title : Interrupt generator for ZynqUS mpsoc
-- Project : General Cores
-------------------------------------------------------------------------------
-- File : mpsoc_int_gen.vhd
-- Company : CERN
-- Platform : FPGA-generics
-- Standard : VHDL '93
-------------------------------------------------------------------------------
-- Copyright (c) 2023 CERN
--
-- Generate an interrupt by writting a value in a specific address (in the pcie
-- bridge) when a line goes high.
--
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 0.51 (the "License") (which enables you, at your option,
-- to treat this file as licensed under the Apache License 2.0); you may not
-- use this file except in compliance with the License. You may obtain a copy
-- of the License at http://solderpad.org/licenses/SHL-0.51.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity mpsoc_int_gen is
generic (
-- default values for AXIPCIE_DMA0, DMA_CHANNEL_PCIE_INTERRUPT_ASSERT
g_addr : std_logic_vector(31 downto 0) := x"FD0F_0070";
g_data : std_logic_vector(31 downto 0) := x"0000_0008"
);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
-- A word is written each time this inputs goes high.
irq_i : in std_logic;
-- AXI4-Full master
S_AXI_awaddr : out std_logic_vector (48 downto 0);
S_AXI_awburst : out std_logic_vector (1 downto 0);
S_AXI_awcache : out std_logic_vector (3 downto 0);
S_AXI_awid : out std_logic_vector (5 downto 0);
S_AXI_awlen : out std_logic_vector (7 downto 0);
S_AXI_awlock : out std_logic;
S_AXI_awprot : out std_logic_vector (2 downto 0);
S_AXI_awready : in std_logic;
S_AXI_awsize : out std_logic_vector (2 downto 0);
S_AXI_awuser : out std_logic;
S_AXI_awvalid : out std_logic;
S_AXI_wdata : out std_logic_vector (31 downto 0);
S_AXI_wlast : out std_logic;
S_AXI_wready : in std_logic;
S_AXI_wstrb : out std_logic_vector (3 downto 0);
S_AXI_wvalid : out std_logic;
S_AXI_bid : in std_logic_vector (5 downto 0);
S_AXI_bready : out std_logic;
S_AXI_bresp : in std_logic_vector (1 downto 0);
S_AXI_bvalid : in std_logic
);
end mpsoc_int_gen;
architecture arch of mpsoc_int_gen is
type t_state is (S_IDLE, S_WAIT, S_DONE);
signal state : t_state;
begin
-- AW
S_AXI_awaddr (31 downto 0) <= g_addr;
S_AXI_awaddr (48 downto 32) <= (others => '0');
-- No burst.
S_AXI_awburst <= "01";
S_AXI_awlen <= x"00";
-- Word write
S_AXI_awsize <= "010";
-- Normal Non-cacheable Non-bufferable
S_AXI_awcache <= "0010";
-- Reuse the same id.
S_AXI_awid <= "000000";
S_AXI_awlock <= '0';
-- Data, unsecure, privileged.
S_AXI_awprot <= "001";
S_AXI_awuser <= '0';
-- S_AXI_awready : in std_logic;
-- S_AXI_awvalid : out std_logic;
-- W
S_AXI_wdata (31 downto 0) <= g_data;
S_AXI_wdata (S_AXI_wdata'left downto 32) <= (others => '0');
S_AXI_wlast <= '1';
S_AXI_wstrb(3 downto 0) <= "1111";
S_AXI_wstrb(s_AXI_wstrb'left downto 4) <= (others => '0');
process (clk_i)
begin
if rising_edge(clk_i) then
S_AXI_bready <= '1';
if rst_n_i = '0' then
S_AXI_awvalid <= '0';
S_AXI_wvalid <= '0';
state <= S_IDLE;
else
case state is
when S_IDLE =>
if irq_i = '1' then
-- Send the write.
S_AXI_awvalid <= '1';
S_AXI_wvalid <= '1';
state <= S_WAIT;
end if;
when S_WAIT =>
if S_AXI_awready = '1' then
S_AXI_awvalid <= '0';
end if;
if S_AXI_wready = '1' then
S_AXI_wvalid <= '0';
end if;
if S_AXI_bvalid = '1' then
-- Got the anwser.
state <= S_DONE;
end if;
when S_DONE =>
if irq_i = '0' then
-- Wait for irq release.
state <= S_IDLE;
end if;
end case;
end if;
end if;
end process;
end arch;
......@@ -134,17 +134,17 @@ architecture behav of axi_gpio_expander is
return tmp;
end function;
-------------------------------------------
function f_update_gpio_in (orig : std_logic_vector; rdata : std_logic_vector; bank : integer)
function f_update_gpio_in (orig : std_logic_vector; rd_data : std_logic_vector; bank : integer)
return std_logic_vector is
variable tmp : std_logic_vector(g_num-1 downto 0);
begin
tmp := orig;
if (bank = 0 and g_num >= c_GPIOPS_BANK0) then
tmp(c_GPIOPS_BANK0-1 downto 0) := rdata;
tmp(c_GPIOPS_BANK0-1 downto 0) := rd_data;
elsif (bank = 0 and g_num < c_GPIOPS_BANK0) then
tmp := rdata(g_num-1 downto 0);
tmp := rd_data(g_num-1 downto 0);
else
tmp(g_num-1 downto c_GPIOPS_BANK0) := rdata(g_num-c_GPIOPS_BANK0-1 downto 0);
tmp(g_num-1 downto c_GPIOPS_BANK0) := rd_data(g_num-c_GPIOPS_BANK0-1 downto 0);
end if;
return tmp;
end function;
......@@ -295,7 +295,7 @@ begin
-- write accepted, let's proceed
BREADY <= '0';
state <= INIT_WRITE_OUT;
elsif (BVALID = '1' and BRESP = c_AXI4_RESP_OKAY) then
elsif (BVALID = '1' and BRESP = c_AXI4_RESP_OKAY) then
-- nothing to update in GPIO_OUT, skip to GPIO reading
BREADY <= '0';
state <= INIT_READ;
......@@ -409,7 +409,7 @@ begin
else -- current_bank = 0 and g_num =< c_GPIOPS_BANK0
-- Only Bank0 is used, reset refresh_all flag, Bank0 registers are
-- all set here.
refresh_all <= '0';
refresh_all <= '0';
end if;
state <= IDLE;
......
......@@ -73,6 +73,9 @@ begin -- rtl
cmp_pulse_out : gc_edge_detect
generic map (
g_ASYNC_RST => true
)
port map (
clk_i => clk_out_i,
rst_n_i => rst_out_n_i,
......
......@@ -54,7 +54,8 @@ architecture arch of gc_reset_multi_aasd is
attribute keep : string;
attribute keep of gc_reset_async_in : signal is "TRUE";
attribute keep of rst_chains : signal is "TRUE";
begin
gc_reset_async_in <= arst_i;
......
......@@ -6,7 +6,7 @@
-- Author : Pablo Alvarez Sanchez
-- Company : CERN BE-Co-HT
-- Created : 2010-02-25
-- Last update: 2019-09-09
-- Last update: 2023-05-17
-- Platform : FPGA-generic
-- Standard : VHDL '87
-------------------------------------------------------------------------------
......@@ -135,7 +135,7 @@ begin
process(clk_i)
begin
if rising_edge(clk_i) then
if iValidValue = '1' then
if iValidValue = '1' and sendingData = '0' then
divider <= (others => '0');
elsif sendingData = '1' then
if(divider_muxed = '1') then
......@@ -156,7 +156,7 @@ begin
if rst_n_i = '0' then
iDacClk <= '1'; -- 0
else
if iValidValue = '1' then
if iValidValue = '1' and sendingData = '0' then
iDacClk <= '1'; -- 0
elsif divider_muxed = '1' then
iDacClk <= not(iDacClk);
......
......@@ -57,6 +57,7 @@ architecture arch of gc_sync is
attribute shreg_extract of sync1 : signal is "no";
attribute keep : string;
attribute keep of clk_i : signal is "true";
attribute keep of gc_sync_ffs_in : signal is "true";
attribute keep of sync0 : signal is "true";
attribute keep of sync1 : signal is "true";
......
......@@ -50,6 +50,7 @@ architecture rtl of gc_sync_register is
attribute shreg_extract of sync1 : signal is "no";
attribute keep : string;
attribute keep of clk_i : signal is "true";
attribute keep of gc_sync_register_in : signal is "true";
attribute keep of sync0 : signal is "true";
attribute keep of sync1 : signal is "true";
......
......@@ -45,6 +45,11 @@ package gencores_pkg is
function f_gray_encode(x : std_logic_vector) return std_logic_vector;
function f_gray_decode(x : std_logic_vector; step : natural) return std_logic_vector;
-- Returns the log2 of N such that 2**f_log2(N) >= N.
-- The result is the minimum value. Can return 0.
function f_log2(N : positive) return natural;
-- Slightly incorrect version of log2: the result is at least 1.
function f_log2_ceil(N : natural) return positive;
-- kept for backwards compatibility, same as f_log2_ceil()
function log2_ceil(N : natural) return positive;
......@@ -72,6 +77,9 @@ package gencores_pkg is
function f_pick (cond : std_logic; if_1 : std_logic_vector; if_0 : std_logic_vector)
return std_logic_vector;
-- Return the maximum of L and R.
function f_max (l, r : natural) return natural;
-- Functions to convert characters and strings to upper/lower case
function to_upper(c : character) return character;
function to_lower(c : character) return character;
......@@ -885,6 +893,16 @@ package body gencores_pkg is
end if;
end f_gray_decode;
function f_log2(N : positive) return natural is
begin
for i in 0 to 30 loop
if N <= 2**i then
return i;
end if;
end loop;
report "N is too large" severity error;
end f_log2;
------------------------------------------------------------------------------
-- Returns log of 2 of a natural number
------------------------------------------------------------------------------
......@@ -1020,6 +1038,15 @@ package body gencores_pkg is
return f_pick (f_to_std_logic(cond), if_1, if_0);
end function f_pick;
function f_max (l, r : natural) return natural is
begin
if l >= r then
return l;
else
return r;
end if;
end f_max;
------------------------------------------------------------------------------
-- Functions to convert characters and strings to upper/lower case
------------------------------------------------------------------------------
......
# the "-quiet" option is added for the use case where this module is added to
# the project, but not instatiated (e.g. because of generic settings)
# in that case Vivado would throw critical warnings during P&$
set_false_path -quiet -to [get_pins -hierarchical *rst_chains_reg[*]/CLR]
# Timing constrains for basic 1 bit synchroniser.
# In many cases this could be solved with simple set_false_path, but in some
# cases this module is used in more time-critical applications, eg. inferred FIFO.
# In that case it makes sense to apply some max_delay constraint.
#
# You can always override any of these max_delay constraints in your global XDC
# with set_false_path because it has the highest priority.
set clk [get_clocks -of_objects [get_ports clk_i]]
set clk_period [get_property PERIOD $clk]
# ATTENTION: we can't use "all_fanin" to find the source register because
# apparently this command doesn't traverse outside of scoped reference (even with -flat switch)
# This method won't work properly if there's a combinational path between a source and target FF;
# but in a proper CDC circuit it's forbidded to have logic between FFs anyway!
set dst_ff [get_pins sync_*.sync0_*/D]
set src_ff [get_cells -of_objects [get_pins -filter {IS_LEAF && DIRECTION == OUT} -of_objects [get_nets -segments -of_objects $dst_ff]]]
# We use -quiet switch, because otherwise Vivado will throw critical warning
# if module is not used in the project (e.g. due to generics)
set_max_delay $clk_period -quiet -datapath_only -from $src_ff -to $dst_ff
# Timing constrains for basic bit vector synchroniser.
#
# This is similar to gc_sync, but vector synchronisation is usually more tricky.
# Usually you really want to limit bus skew and delay to one clock cycle.
#
# You can always override any of these max_delay constraints in your global XDC
# with set_false_path because it has the highest priority.
set clk [get_clocks -of_objects [get_ports clk_i]]
set clk_period [get_property PERIOD $clk]
# ATTENTION: we can't use "all_fanin" to find the source register because
# apparently this command doesn't traverse outside of scoped reference (even with -flat switch)
# This method won't work properly if there's a combinational path between a source and target FF;
# but in a proper CDC circuit it's forbidded to have logic between FFs anyway!
set dst_ff [get_pins sync0_*[*]/D]
set src_ff [get_cells -of_objects [get_pins -filter {IS_LEAF && DIRECTION == OUT} -of_objects [get_nets -segments -of_objects $dst_ff]]]
# We use -quiet switch, because otherwise Vivado will throw critical warning
# if module is not used in the project (e.g. due to generics)
set_max_delay $clk_period -quiet -datapath_only -from $src_ff -to $dst_ff
set_bus_skew $clk_period -quiet -from $src_ff -to $dst_ff
files = ["cordic_init.vhd",
"cordic_modulo_360.vhd",
"cordic_xy_logic_hd.vhd",
"cordic_xy_logic_nhd.vhd",
"cordic_xy_logic_nmhd.vhd",
"gc_pipelined_fir_filter.vhd",
"gc_cordic_pkg.vhd",
"gc_cordic.vhd",
"gc_cordic_top.vhd",
"gc_dsp_pkg.vhd",
"gc_iq_demodulator.vhd",
"gc_iq_modulator.vhd",
"gc_pi_regulator.vhd",
"gc_soft_ramp_switch.vhd",
"gc_integer_divide.vhd"];
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: cordic_modulo_360.vhd
--
-- authors: Gregoire Hagmann <gregoire.hagmann@cern.ch>
-- John Molendijk (CERN)
--
-- description: Cordic first pipe stage, setting initial values depending on the
-- function to be calculated.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.numeric_std.all;
library work;
use work.gc_cordic_pkg.all;
entity cordic_init is
generic
(
g_M : positive := 16;
-- Default angle format S8.7 otherwise FS = 180 deg.
g_ANGLE_FORMAT : integer
);
port (
clk_i : in std_logic;
rst_i : in std_logic;
cor_mode_i : in t_CORDIC_MODE;
cor_submode_i : in t_CORDIC_SUBMODE;
x0_i : in std_logic_vector(g_M - 1 downto 0);
y0_i : in std_logic_vector(g_M - 1 downto 0);
z0_i : in std_logic_vector(g_M downto 0);
x1_o : out std_logic_vector(g_M - 1 downto 0);
y1_o : out std_logic_vector(g_M - 1 downto 0);
z1_o : out std_logic_vector(g_M downto 0);
d1_o : out std_logic
);
end cordic_init;
architecture rtl of cordic_init is
signal x0_int, y0_int, x1_int, y1_int : signed (g_M-1 downto 0);
signal z0_int, z1_int : signed (g_M downto 0);
signal d1_int : std_logic;
begin
x0_int <= signed(x0_i);
y0_int <= signed(y0_i);
z0_int <= signed(z0_i);
process (clk_i)
begin
if rising_edge(clk_i) then
x1_o <= std_logic_vector(x1_int);
y1_o <= std_logic_vector(y1_int);
z1_o <= std_logic_vector(z1_int);
d1_o <= d1_int;
if cor_mode_i = c_MODE_VECTOR and cor_submode_i = c_SUBMODE_CIRCULAR then
if x0_int >= c_DegZeroHD(31 downto 31 - (g_M - 1)) and
y0_int >= c_DegZeroHD(31 downto 31 - (g_M - 1)) then
x1_int <= x0_int;
y1_int <= y0_int;
z1_int <= z0_int;
d1_int <= '0';
elsif x0_int >= c_DegZeroHD(31 downto 31 - (g_M - 1)) and
y0_int < c_DegZeroHD(31 downto 31 - (g_M - 1)) then
x1_int <= x0_int;
y1_int <= y0_int;
z1_int <= z0_int;
d1_int <= '1';
elsif g_ANGLE_FORMAT = c_ANGLE_FORMAT_S8_7 and
x0_int < c_DegZeroHD(31 downto 31 - (g_M - 1)) and
y0_int >= c_DegZeroHD(31 downto 31 - (g_M - 1)) then
x1_int <= y0_int;
y1_int <= -x0_int; -- not (X0) + 1;
z1_int <= c_DegPlus90HD_X(32 downto 32 - g_M) + z0_int;
d1_int <= '0';
elsif g_ANGLE_FORMAT = c_ANGLE_FORMAT_S8_7 and
x0_int < c_DegZeroHD(31 downto 31 - (g_M - 1)) and
y0_int < c_DegZeroHD(31 downto 31 - (g_M - 1)) then
x1_int <= -y0_int; -- not (Y0) + 1;
y1_int <= x0_int;
z1_int <= c_DegMinus90HD_X(32 downto 32 - g_M) + z0_int;
d1_int <= '1';
elsif g_ANGLE_FORMAT = C_ANGLE_FORMAT_FULL_SCALE_180 and
x0_int < c_FSDegZeroHD(31 downto 31 - (g_M - 1)) and
y0_int >= c_FSDegZeroHD(31 downto 31 - (g_M - 1)) then
x1_int <= y0_int;
y1_int <= -x0_int; -- not (X0) + 1;
z1_int <= c_FSDegPlus90HD_X(32 downto 32 - g_M) + z0_int;
d1_int <= '0';
elsif g_ANGLE_FORMAT = C_ANGLE_FORMAT_FULL_SCALE_180 and
x0_int < c_FSDegZeroHD(31 downto 31 - (g_M - 1)) and
y0_int < c_FSDegZeroHD(31 downto 31 - (g_M - 1)) then
x1_int <= -y0_int; -- not (Y0) + 1;
y1_int <= x0_int;
z1_int <= c_FSDegMinus90HD_X(32 downto 32 - g_M) + z0_int;
d1_int <= '1';
end if;
elsif cor_mode_i = c_MODE_ROTATE and cor_submode_i = c_SUBMODE_CIRCULAR then
if g_ANGLE_FORMAT = c_ANGLE_FORMAT_S8_7 and
z0_int <= c_DegPlus90HD_X(32 downto 32 - g_M) and
z0_int >= c_DegZeroHD_X(32 downto 32 - g_M) then
x1_int <= x0_int;
y1_int <= y0_int;
z1_int <= z0_int;
d1_int <= '1';
elsif g_ANGLE_FORMAT = c_ANGLE_FORMAT_S8_7 and
z0_int < c_DegZeroHD_X(32 downto 32 - g_M) and
z0_int >= c_DegMinus90HD_X(32 downto 32 - g_M) then
x1_int <= x0_int;
y1_int <= y0_int;
z1_int <= z0_int;
d1_int <= '0';
elsif g_ANGLE_FORMAT = c_ANGLE_FORMAT_S8_7 and
z0_int < c_DegMinus90HD_X(32 downto 32 - g_M) and
z0_int >= c_DegMinus180HD_X(32 downto 32 - g_M) then
x1_int <= y0_int;
y1_int <= -x0_int; -- not (X0) + 1;
z1_int <= c_DegPlus90HD_X(32 downto 32 - g_M) + z0_int;
d1_int <= '0';
elsif g_ANGLE_FORMAT = c_ANGLE_FORMAT_S8_7 and
z0_int <= c_DegPlus180HD_X(32 downto 32 - g_M) and
z0_int > c_DegPlus90HD_X(32 downto 32 - g_M) then
x1_int <= -y0_int; --not (Y0) + 1;
y1_int <= x0_int;
z1_int <= c_DegMinus90HD_X(32 downto 32 - g_M) + z0_int;
d1_int <= '1';
elsif g_ANGLE_FORMAT = c_ANGLE_FORMAT_S8_7 and
z0_int < c_DegMinus180HD_X(32 downto 32 - g_M) then
x1_int <= -x0_int; --not (X0) + 1;
y1_int <= -y0_int; --not (Y0) + 1;
z1_int <= c_DegPlus180HD_X(32 downto 32 - g_M) + z0_int;
d1_int <= '0';
elsif g_ANGLE_FORMAT = c_ANGLE_FORMAT_S8_7 and
z0_int > c_DegPlus180HD_X(32 downto 32 - g_M) then
x1_int <= -x0_int; -- not (X0) + 1;
y1_int <= -y0_int; --not (Y0) + 1;
z1_int <= c_DegMinus180HD_X(32 downto 32 - g_M) + z0_int;
d1_int <= '1';
elsif g_ANGLE_FORMAT = C_ANGLE_FORMAT_FULL_SCALE_180 and
z0_int <= c_FSDegPlus90HD_X(32 downto 32 - g_M) and
z0_int >= c_FSDegZeroHD_X(32 downto 32 - g_M) then
x1_int <= x0_int;
y1_int <= y0_int;
z1_int <= z0_int;
d1_int <= '1';
elsif g_ANGLE_FORMAT = C_ANGLE_FORMAT_FULL_SCALE_180 and
z0_int < c_FSDegZeroHD_X(32 downto 32 - g_M) and
z0_int >= c_FSDegMinus90HD_X(32 downto 32 - g_M) then
x1_int <= x0_int;
y1_int <= y0_int;
z1_int <= z0_int;
d1_int <= '0';
elsif g_ANGLE_FORMAT = C_ANGLE_FORMAT_FULL_SCALE_180 and
z0_int < c_FSDegMinus90HD_X(32 downto 32 - g_M) and
z0_int >= c_FSDegMinus180HD_X(32 downto 32 - g_M) then
x1_int <= y0_int;
y1_int <= -x0_int; --not (X0) + 1;
z1_int <= c_FSDegPlus90HD_X(32 downto 32 - g_M) + z0_int;
d1_int <= '0';
elsif g_ANGLE_FORMAT = C_ANGLE_FORMAT_FULL_SCALE_180 and
z0_int <= c_FSDegPlus180HD_X(32 downto 32 - g_M) and
z0_int > c_FSDegPlus90HD_X(32 downto 32 - g_M) then
x1_int <= -y0_int; --not (Y0) + 1;
y1_int <= x0_int;
z1_int <= c_FSDegMinus90HD_X(32 downto 32 - g_M) + z0_int;
d1_int <= '1';
elsif g_ANGLE_FORMAT = C_ANGLE_FORMAT_FULL_SCALE_180 and
z0_int < c_FSDegMinus180HD_X(32 downto 32 - g_M) then
x1_int <= -x0_int; --not (X0) + 1;
y1_int <= -y0_int; --not (Y0) + 1;
z1_int <= c_FSDegPlus180HD_X(32 downto 32 - g_M) + z0_int;
d1_int <= '0';
elsif g_ANGLE_FORMAT = C_ANGLE_FORMAT_FULL_SCALE_180 and
z0_int > c_FSDegPlus180HD_X(32 downto 32 - g_M) then
x1_int <= -x0_int; --not (X0) + 1;
y1_int <= -y0_int; --not (Y0) + 1;
z1_int <= c_FSDegMinus180HD_X(32 downto 32 - g_M) + z0_int;
d1_int <= '1';
end if;
elsif cor_mode_i = c_MODE_VECTOR and cor_submode_i = c_SUBMODE_LINEAR then
if y0_int >= c_DegZeroHD(31 downto 31 - (g_M - 1)) then
x1_int <= x0_int;
y1_int <= y0_int;
z1_int <= z0_int;
d1_int <= '0';
elsif
y0_int < c_DegZeroHD(31 downto 31 - (g_M - 1)) then
x1_int <= x0_int;
y1_int <= y0_int;
z1_int <= z0_int;
d1_int <= '1';
end if;
elsif cor_mode_i = c_MODE_ROTATE and cor_submode_i = c_SUBMODE_LINEAR then
if z0_int >= c_DegZeroHD_X(32 downto 32 - g_M) then
x1_int <= x0_int;
y1_int <= y0_int;
z1_int <= z0_int;
d1_int <= '1';
elsif z0_int < c_DegZeroHD_X(32 downto 32 - g_M) then
x1_int <= x0_int;
y1_int <= y0_int;
z1_int <= z0_int;
d1_int <= '0';
end if;
end if;
end if;
end process;
end rtl;
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: cordic_modulo_360.vhd
--
-- authors: Gregoire Hagmann <gregoire.hagmann@cern.ch>
-- John Molendijk (CERN)
--
-- description: Cordic angle normalization
--
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
-- Angle normalization (Mod-360 degree)
-- If the angle_i argument is greater or smaller than +/-180deg.
-- the system subtracts or adds 360 degrees such that the result
-- lies again within the +/-180 degree range.
-- The number of g_M is by default 16 and can be max. 32 bit number.
-- Within the 32-bit range the number will correctly fit within a sign,
-- 8b Mantissa & 23b Fractional part. Changing the value g_M will only affect
-- to the fractional bits. This option can be selected with the g_ANGLE_MODE to
-- S8_7.
-- On the other hand, when the generic value g_ANGLE_MODE is set to FULL_SCALE the
-- modulo360 block can be used with an angle format maximum of Q1.31 with a sign
-- extension. This format gives a normalized signed representation with fixed
-- fractional bits according to the value of g_M. Changing the value of g_M will
-- affect to the amount of fractional bits. Full-scale format 180 degrees is
-- acquired in this way.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.gc_cordic_pkg.all;
entity cordic_modulo_360 is
generic(
g_M : positive;
g_ANGLE_FORMAT : integer;
g_USE_SATURATED_MATH : boolean
);
port (
cor_submode_i : in t_CORDIC_SUBMODE;
angle_i : in std_logic_vector(g_M downto 0);
angle_o : out std_logic_vector(g_M-1 downto 0);
lim_o : out std_logic
);
end entity;
architecture rtl of cordic_modulo_360 is
signal gt, lt : std_logic;
constant c_M180D : signed(g_M downto 0) :=
f_pick(g_ANGLE_FORMAT = c_ANGLE_FORMAT_S8_7, c_DegMinus180HD_X(32 downto 32 - g_M), c_FSDegMinus180HD_X(32 downto 32-g_M));
constant c_P180D : signed(g_M downto 0) :=
f_pick(g_ANGLE_FORMAT = c_ANGLE_FORMAT_S8_7, c_DegPlus180HD_X(32 downto 32 - g_M), c_FSDegPlus180HD_X(32 downto 32-g_M));
constant c_OFFS_ZERO : signed(g_M downto 0) :=
f_pick(g_ANGLE_FORMAT = c_ANGLE_FORMAT_S8_7, c_DegZeroHD_X(32 downto 32 - g_M), c_FSDegZeroHD_X(32 downto 32 - g_M));
constant c_OFFS_P360D : signed(g_M downto 0) :=
f_pick(g_ANGLE_FORMAT = c_ANGLE_FORMAT_S8_7, c_DegPlus360HD_X(32 downto 32 - g_M), c_FSDegPlus360HD_X(32 downto 32 - g_M));
constant c_OFFS_N360D : signed(g_M downto 0) :=
f_pick(g_ANGLE_FORMAT = c_ANGLE_FORMAT_S8_7, c_DegMinus360HD_X(32 downto 32 - g_M), c_FSDegMinus360HD_X(32 downto 32 - g_M));
begin
process(angle_i)
begin
if signed(angle_i) < c_M180D then
lt <= '1';
else
lt <= '0';
end if;
if signed(angle_i) > c_P180D then
gt <= '1';
else
gt <= '0';
end if;
end process;
process(lt, gt, angle_i, cor_submode_i)
variable angle_out : signed(g_M downto 0);
variable lim_out : std_logic;
begin
if cor_submode_i = c_SUBMODE_CIRCULAR then
if(lt = '1' and gt = '0') then
f_limit_add(g_USE_SATURATED_MATH, signed(angle_i), c_OFFS_P360D, angle_out, lim_out);
elsif (lt = '0' and gt = '1') then
f_limit_add(g_USE_SATURATED_MATH, signed(angle_i), c_OFFS_N360D, angle_out, lim_out);
else
f_limit_add(g_USE_SATURATED_MATH, signed(angle_i), c_OFFS_ZERO, angle_out, lim_out);
end if;
else
f_limit_add(g_USE_SATURATED_MATH, signed(angle_i), to_signed(0, g_M), angle_out, lim_out);
end if;
angle_o <= std_logic_vector(angle_out(g_M-1 downto 0));
lim_o <= lim_out;
end process;
end rtl;
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: cordic_xy_logic_hd
--
-- authors: Gregoire Hagmann <gregoire.hagmann@cern.ch>
-- John Molendijk (CERN)
--
-- description: Cordic pipeline stage
--
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.gc_cordic_pkg.all;
entity cordic_xy_logic_hd is
generic(
g_M : positive;
g_J : integer;
g_USE_SATURATED_MATH : boolean
);
port (
clk_i : in std_logic;
rst_i : in std_logic;
cor_submode_i : in t_CORDIC_SUBMODE;
d_i : in std_logic;
fi_i : in std_logic_vector(g_m-1 downto 0);
lim_x_i : in std_logic;
lim_y_i : in std_logic;
xi_i : in std_logic_vector(g_M-1 downto 0);
yi_i : in std_logic_vector(g_M-1 downto 0);
zi_i : in std_logic_vector(g_M downto 0);
xj_o : out std_logic_vector(g_M-1 downto 0);
yj_o : out std_logic_vector(g_M-1 downto 0);
zj_o : out std_logic_vector(g_M downto 0);
lim_x_o : out std_logic;
lim_y_o : out std_logic;
rst_o : out std_logic
);
end entity;
architecture rtl of cordic_xy_logic_hd is
function f_shift(
vin : signed;
m : integer;
j : integer) return signed is
begin
if j < m - 2 then
return resize(vin(m-1 downto j), m);
else
return to_signed(0, m);
end if;
end f_shift;
signal xi_shifted : signed(g_M -1 downto 0);
signal yi_shifted : signed(g_M -1 downto 0);
signal rst_l, rst_d : std_logic;
begin
xi_shifted <= f_shift(signed(xi_i), g_M, g_J);
yi_shifted <= f_shift(signed(yi_i), g_M, g_J);
p_reset : process(clk_i)
begin
if rising_edge(clk_i) then
rst_d <= rst_i;
end if;
end process;
rst_l <= rst_d or rst_i;
rst_o <= rst_l;
process(clk_i)
variable xi_muxed : signed(g_M-1 downto 0);
variable yi_muxed : signed(g_M-1 downto 0);
variable fi_inv : signed(g_M-1 downto 0);
variable xj_comb : signed(g_M-1 downto 0);
variable yj_comb : signed(g_M-1 downto 0);
variable zj_comb : signed(g_M downto 0);
variable xj_limit : std_logic;
variable yj_limit : std_logic;
begin
if rising_edge(clk_i) then
if rst_l = '1' then
xj_o <= (others => '0');
yj_o <= (others => '0');
zj_o <= (others => '0');
lim_x_o <= '0';
lim_y_o <= '0';
else
case cor_submode_i is
when c_SUBMODE_LINEAR =>
-- scntrl = 1, updmode = 0
yi_muxed := (others => '0');
-- scntrl = 1, updmode = 1
when c_SUBMODE_CIRCULAR =>
yi_muxed := f_limit_negate(g_USE_SATURATED_MATH, yi_shifted, not d_i);
-- scntrl = 0, updmode = 1
when c_SUBMODE_HYPERBOLIC =>
yi_muxed := f_limit_negate(g_USE_SATURATED_MATH, yi_shifted, d_i);
when others =>
yi_muxed := (others => '0');
end case;
xi_muxed := f_limit_negate(g_USE_SATURATED_MATH, xi_shifted, not d_i);
f_limit_subtract(g_USE_SATURATED_MATH, signed(xi_i), yi_muxed, xj_comb, xj_limit);
f_limit_add(g_USE_SATURATED_MATH, signed(yi_i), xi_muxed, yj_comb, yj_limit);
fi_inv := f_limit_negate(g_USE_SATURATED_MATH, signed(fi_i), not d_i );
zj_comb := signed(zi_i) - fi_inv;
xj_o <= std_logic_vector(xj_comb);
yj_o <= std_logic_vector(yj_comb);
zj_o <= std_logic_vector(zj_comb);
lim_x_o <= lim_x_i or xj_limit;
lim_y_o <= lim_y_i or yj_limit;
end if;
end if;
end process;
end rtl;
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: cordic_xy_logic_nhd
--
-- authors: Gregoire Hagmann <gregoire.hagmann@cern.ch>
-- John Molendijk (CERN)
--
-- description: Cordic pipeline stage
--
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.gc_cordic_pkg.all;
entity cordic_xy_logic_nhd is
generic(
g_M : positive;
g_J : integer;
g_I : integer;
g_ANGLE_FORMAT : integer;
g_USE_SATURATED_MATH : boolean
);
port (
clk_i : in std_logic;
rst_i : in std_logic;
cor_submode_i : in t_CORDIC_SUBMODE;
cor_mode_i : in t_CORDIC_MODE;
lim_x_i : in std_logic;
lim_y_i : in std_logic;
xi_i : in std_logic_vector(g_M-1 downto 0);
yi_i : in std_logic_vector(g_M-1 downto 0);
zi_i : in std_logic_vector(g_M downto 0);
xj_o : out std_logic_vector(g_M-1 downto 0);
yj_o : out std_logic_vector(g_M-1 downto 0);
zj_o : out std_logic_vector(g_M downto 0);
lim_x_o : out std_logic;
lim_y_o : out std_logic;
rst_o : out std_logic
);
end entity;
architecture rtl of cordic_xy_logic_nhd is
function f_shift(
vin : signed;
m : integer;
j : integer) return signed is
begin
if j <= m - 2 then
return resize(vin(m-1 downto j), m);
else
return to_signed(0, m);
end if;
end f_shift;
signal xi_shifted : signed(g_M -1 downto 0);
signal yi_shifted : signed(g_M -1 downto 0);
signal fi : signed(g_M-1 downto 0);
signal di_int : std_logic;
signal rst_l, rst_d : std_logic;
signal xi_muxed_s : signed(g_M-1 downto 0);
signal yi_muxed_s : signed(g_M-1 downto 0);
begin
fi <= f_phi_lookup( g_I, cor_submode_i, g_ANGLE_FORMAT )(31 downto 31-(g_M-1) );
xi_shifted <= f_shift(signed(xi_i), g_M, g_J);
yi_shifted <= f_shift(signed(yi_i), g_M, g_J);
p_gen_di: process(cor_mode_i, yi_i, zi_i)
begin
if cor_mode_i = c_MODE_VECTOR then
di_int <= yi_i(g_M-1);
else
di_int <= not zi_i(g_M);
end if;
end process;
p_reset : process(clk_i)
begin
if rising_edge(clk_i) then
rst_d <= rst_i;
end if;
end process;
rst_l <= rst_d or rst_i;
rst_o <= rst_l;
p_pipe: process(clk_i)
variable xi_muxed : signed(g_M-1 downto 0);
variable yi_muxed : signed(g_M-1 downto 0);
variable fi_inv : signed(g_M-1 downto 0);
variable xj_comb : signed(g_M-1 downto 0);
variable yj_comb : signed(g_M-1 downto 0);
variable zj_comb : signed(g_M downto 0);
variable xj_limit : std_logic;
variable yj_limit : std_logic;
begin
if rising_edge(clk_i) then
if rst_l = '1' then
xj_o <= (others => '0');
yj_o <= (others => '0');
zj_o <= (others => '0');
lim_x_o <= '0';
lim_y_o <= '0';
else
case cor_submode_i is
when c_SUBMODE_LINEAR =>
-- scntrl = 1, updmode = 0
yi_muxed := (others => '0');
when c_SUBMODE_CIRCULAR =>
-- scntrl = 1, updmode = 1
yi_muxed := f_limit_negate(g_USE_SATURATED_MATH, yi_shifted, not di_int);
when c_SUBMODE_HYPERBOLIC =>
-- scntrl = 0, updmode = 1
yi_muxed := f_limit_negate(g_USE_SATURATED_MATH, yi_shifted, di_int);
when others =>
yi_muxed := (others => '0');
end case;
xi_muxed := f_limit_negate(g_USE_SATURATED_MATH, xi_shifted, not di_int);
xi_muxed_s <= xi_muxed;
yi_muxed_s <= yi_muxed;
f_limit_subtract(g_USE_SATURATED_MATH, signed(xi_i), yi_muxed, xj_comb, xj_limit);
f_limit_add(g_USE_SATURATED_MATH, signed(yi_i), xi_muxed, yj_comb, yj_limit);
fi_inv := f_limit_negate(g_USE_SATURATED_MATH, signed(fi), not di_int );
zj_comb := signed(zi_i) - fi_inv;
xj_o <= std_logic_vector(xj_comb);
yj_o <= std_logic_vector(yj_comb);
zj_o <= std_logic_vector(zj_comb);
lim_x_o <= lim_x_i or xj_limit;
lim_y_o <= lim_y_i or yj_limit;
end if;
end if;
end process;
end rtl;
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: cordic_xy_logic_nmhd
--
-- authors: Gregoire Hagmann <gregoire.hagmann@cern.ch>
-- John Molendijk (CERN)
--
-- description: Cordic pipeline stage
--
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.gc_cordic_pkg.all;
entity cordic_xy_logic_nmhd is
generic(
-- Number of XYlogicNHD cells instantiated
g_N : positive;
--M = Word-width (maximum = 32)
g_M : positive;
--AngleMode = Default angle format S8.7 otherwise FS = 180 deg.
g_ANGLE_FORMAT : integer;
g_USE_SATURATED_MATH : boolean
);
port (
clk_i : in std_logic;
rst_i : in std_logic;
cor_mode_i : in t_CORDIC_MODE;
cor_submode_i : in t_CORDIC_SUBMODE;
d_i : in std_logic;
fi1_i : in std_logic_vector(g_m-1 downto 0);
lim_x_i : in std_logic;
lim_y_i : in std_logic;
xi_i : in std_logic_vector(g_M-1 downto 0);
yi_i : in std_logic_vector(g_M-1 downto 0);
zi_i : in std_logic_vector(g_M downto 0);
xj_o : out std_logic_vector(g_M-1 downto 0);
yj_o : out std_logic_vector(g_M-1 downto 0);
zj_o : out std_logic_vector(g_M downto 0);
lim_x_o : out std_logic;
lim_y_o : out std_logic;
rst_o : out std_logic
);
end entity;
architecture rtl of cordic_xy_logic_nmhd is
type t_xy_bus is array (0 to g_N-2) of std_logic_vector(g_M-1 downto 0);
type t_z_bus is array (0 to g_N-2) of std_logic_vector(g_M downto 0);
signal loc_Rst : std_logic_vector(g_N-2 downto 0);
signal loc_LimX : std_logic_vector(g_N-2 downto 0);
signal loc_LimY : std_logic_vector(g_N-2 downto 0);
signal loc_X : t_xy_bus;
signal loc_Y : t_xy_bus;
signal loc_Z : t_z_bus;
begin
B_Cell0 : entity work.cordic_xy_logic_hd
generic map(
g_M => g_M,
g_J => 0,
g_USE_SATURATED_MATH => g_USE_SATURATED_MATH)
port map(
clk_i => clk_i,
rst_i => rst_i,
cor_submode_i => cor_submode_i,
lim_x_i => lim_x_i,
lim_y_i => lim_y_i,
d_i => d_i,
xi_i => xi_i,
yi_i => yi_i,
Zi_i => zi_i,
fi_i => fi1_i,
rst_o => loc_Rst(0),
lim_x_o => loc_LimX(0),
lim_y_o => loc_LimY(0),
xj_o => loc_X(0),
yj_o => loc_Y(0),
zj_o => loc_Z(0));
B_CellN_1 : entity work.cordic_xy_logic_nhd
generic map(
g_M => g_M,
g_J => g_N - 1,
g_I => g_N - 1,
g_ANGLE_FORMAT => g_ANGLE_FORMAT,
g_USE_SATURATED_MATH => g_USE_SATURATED_MATH)
port map(
clk_i => clk_i,
rst_i => loc_Rst(g_N-2),
cor_submode_i => cor_submode_i,
cor_mode_i => cor_mode_i,
lim_x_i => loc_LimX(g_N-2),
lim_y_i => loc_LimY(g_N-2),
xi_i => loc_X(g_N-2),
yi_i => loc_Y(g_N-2),
zi_i => loc_Z(g_N-2),
Rst_o => Rst_o,
lim_x_o => lim_x_o,
lim_y_o => lim_y_o,
xj_o => xj_o,
yj_o => yj_o,
zj_o => zj_o);
GXYlogic : for K in 1 to g_N-2 generate
B_CellN : entity work.cordic_xy_logic_nhd
generic map(
g_M => g_M,
g_J => K,
g_ANGLE_FORMAT => g_ANGLE_FORMAT,
g_I => K,
g_USE_SATURATED_MATH => g_USE_SATURATED_MATH)
port map(
clk_i => clk_i,
rst_i => loc_Rst(K-1),
lim_x_i => loc_LimX(K-1),
lim_y_i => loc_LimY(K-1),
xi_i => loc_X(K-1),
yi_i => loc_Y(K-1),
zi_i => loc_Z(K-1),
cor_submode_i => cor_submode_i,
cor_mode_i => cor_mode_i,
Rst_o => loc_Rst(K),
lim_x_o => loc_LimX(K),
lim_y_o => loc_LimY(K),
xj_o => loc_X(K),
yj_o => loc_Y(K),
zj_o => loc_Z(K));
end generate GXYlogic;
end rtl;
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_cordic
--
-- authors: Gregoire Hagmann <gregoire.hagmann@cern.ch>
-- John Molendijk (CERN)
--
-- description: Fully pipelined multifunction CORDIC code.
--
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.gc_cordic_pkg.all;
entity gc_cordic is
generic(
-- Number of pipeline stages
g_N : positive := 12;
--M = Word-width (maximum = 32)
g_M : positive := 16;
--AngleMode = Default angle format S8.7 otherwise FS = 180 deg.
g_ANGLE_FORMAT : integer := c_ANGLE_FORMAT_FULL_SCALE_180;
-- when true, all addition/subtraction operations are performed with saturation.
-- Limit inputs/outputs are only supported if the parameter is TRUE.
g_USE_SATURATED_MATH : boolean := false
);
port (
clk_i : in std_logic;
rst_i : in std_logic;
-- Mode of operation. Two have been tested/are supported:
-- MODE = ROTATE, SUBMODE = CIRCULAR: mag/phase -> sin/cos
-- MODE = VECTOR, SUBMODE = CIRCULAR: sin/cos -> mag/phase
-- The other mode combinations may work, but have not been tested.
cor_mode_i : in t_CORDIC_MODE;
cor_submode_i : in t_CORDIC_SUBMODE;
lim_x_i : in std_logic;
lim_y_i : in std_logic;
-- cos input
x0_i : in std_logic_vector(g_M-1 downto 0);
-- sin input
y0_i : in std_logic_vector(g_M-1 downto 0);
-- phase input
z0_i : in std_logic_vector(g_M-1 downto 0);
-- cos output
xn_o : out std_logic_vector(g_M-1 downto 0);
-- sin output
yn_o : out std_logic_vector(g_M-1 downto 0);
-- phase output
zn_o : out std_logic_vector(g_M-1 downto 0);
lim_x_o : out std_logic;
lim_y_o : out std_logic;
rst_o : out std_logic
);
end entity;
architecture rtl of gc_cordic is
signal r_lim_x, r_lim_y : std_logic;
signal z0_int : std_logic_vector(g_M downto 0);
signal x1, y1 : std_logic_vector(g_M-1 downto 0);
signal z1 : std_logic_vector(g_M downto 0);
signal d1 : std_logic;
signal fi1 : std_logic_vector(31 downto 0);
signal zj_int : std_logic_vector(g_M downto 0);
signal rst_o_int, rst_o_int_d : std_logic;
begin
fi1 <= std_logic_vector(f_phi_lookup(0, cor_submode_i, g_ANGLE_FORMAT));
z0_int <= std_logic_vector(resize (signed(z0_i), g_M + 1));
p_latch_lims : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_i = '1' then
r_lim_x <= '0';
r_lim_y <= '0';
else
r_lim_x <= lim_x_i;
r_lim_y <= lim_y_i;
end if;
end if;
end process;
U_Cordic_Init : entity work.cordic_init
generic map (
g_M => g_M,
g_ANGLE_FORMAT => g_ANGLE_FORMAT)
port map (
clk_i => clk_i,
rst_i => rst_i,
cor_mode_i => cor_mode_i,
cor_submode_i => cor_submode_i,
x0_i => x0_i,
y0_i => y0_i,
z0_i => z0_int,
x1_o => x1,
y1_o => y1,
z1_o => z1,
d1_o => d1);
U_Cordic_Core : entity work.cordic_xy_logic_nmhd
generic map (
g_N => g_N-1,
g_M => g_M,
g_ANGLE_FORMAT => g_ANGLE_FORMAT,
g_USE_SATURATED_MATH => g_USE_SATURATED_MATH)
port map (
clk_i => clk_i,
rst_i => rst_i,
cor_mode_i => cor_mode_i,
cor_submode_i => cor_submode_i,
d_i => d1,
fi1_i => fi1(31 downto 31 - (g_M - 1)),
lim_x_i => r_lim_x,
lim_y_i => r_lim_y,
xi_i => x1,
yi_i => y1,
zi_i => z1,
xj_o => xn_o,
yj_o => yn_o,
zj_o => zj_int,
lim_x_o => lim_x_o,
lim_y_o => lim_y_o,
rst_o => rst_o_int);
U_Fixup_Angle : entity work.cordic_modulo_360
generic map (
g_M => g_M,
g_ANGLE_FORMAT => g_ANGLE_FORMAT,
g_USE_SATURATED_MATH => g_USE_SATURATED_MATH)
port map (
cor_submode_i => cor_submode_i,
angle_i => zj_int,
angle_o => zn_o,
lim_o => open);
p_delay_reset : process(clk_i)
begin
if rising_edge(clk_i) then
rst_o_int_d <= rst_o_int;
end if;
end process;
rst_o <= rst_o_int_d or rst_o_int;
end rtl;
This diff is collapsed.
This diff is collapsed.
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_dsp_pkg
--
-- author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
--
-- description: Shared definitions & types for the DSP core collection.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.All;
use ieee.numeric_std.All;
package gc_dsp_pkg is
constant c_MAX_COEF_BITS : integer := 32;
constant c_FIR_MAX_COEFS : integer := 128;
type t_FIR_COEF_ARRAY is array(c_FIR_MAX_COEFS-1 downto 0) of signed(c_MAX_COEF_BITS-1 downto 0);
end package;
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_integer_divide
--
-- author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
--
-- description: Sequential integer division/remainder unit. Support signed
-- and unsigned integers.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity gc_integer_divide is
generic (
g_BITS : integer := 32);
port (
clk_i : in std_logic;
rst_i : in std_logic;
is_rem_i : in std_logic;
is_signed_i : in std_logic;
a_i : in std_logic_vector(g_BITS-1 downto 0);
b_i : in std_logic_vector(g_BITS-1 downto 0);
q_o : out std_logic_vector(g_BITS-1 downto 0);
start_i : in std_logic;
ready_o : out std_logic;
done_o : out std_logic
);
end gc_integer_divide;
architecture rtl of gc_integer_divide is
signal state : integer range 0 to 63; --unsigned(5 downto 0);
signal q, r, n, d : unsigned(g_BITS-1 downto 0);
signal n_sign, d_sign : std_logic;
signal alu_result : unsigned(g_BITS downto 0);
signal alu_op1, alu_op2, r_next : unsigned(g_BITS-1 downto 0);
signal alu_sub : std_logic;
signal is_rem, is_div_by_zero : std_logic;
signal done, busy, alu_ge, alu_eq, start_divide : std_logic;
function f_trunc_int(x : integer; tv : integer) return integer is
begin
if x < 0 then
return 0;
elsif x > tv then
return tv;
else
return x;
end if;
end f_trunc_int;
begin
r_next <= r(g_BITS-2 downto 0) & n(f_trunc_int(g_BITS - 1 - (state-3), g_BITS-1));
p_alu_ops : process(state, n, d, q, r, r_next)
begin
case state is
when 0 =>
alu_op1 <= (others => 'X');
alu_op2 <= (others => 'X');
when 1 =>
alu_op1 <= (others => '0');
alu_op2 <= n;
when 2 =>
alu_op1 <= (others => '0');
alu_op2 <= d;
when others =>
if state = g_BITS + 3 then
alu_op1 <= (others => '0');
alu_op2 <= q;
elsif state = g_BITS + 4 then
alu_op1 <= (others => '0');
alu_op2 <= r;
else
alu_op1 <= r_next;
alu_op2 <= d;
end if;
end case;
end process;
p_alu : process(alu_sub, alu_op1, alu_op2)
begin
if alu_sub = '1' then
alu_result <= ('0'&alu_op1) - ('0'& alu_op2);
else
alu_result <= ('0'&alu_op1) + ('0'& alu_op2);
end if;
end process;
p_flags : process(alu_result, state, done, is_rem, busy, start_i)
begin
alu_ge <= not alu_result(g_BITS);
if alu_result = 0 then
alu_eq <= '1';
else
alu_eq <= '0';
end if;
if state = g_BITS + 5 and is_rem = '1' then
done <= '1';
elsif state = g_BITS + 4 and is_rem = '0' then
done <= '1';
else
done <= '0';
end if;
if state /= 0 and done = '0' then
busy <= '1';
else
busy <= '0';
end if;
start_divide <= start_i and not busy;
end process;
done_o <= done;
ready_o <= not busy;
-- busy_o <= busy;
p_alu_select_op : process(state, n_sign, d_sign)
begin
case state is
when 1 =>
alu_sub <= n_sign;
when 2 =>
alu_sub <= d_sign;
when others =>
if state = g_BITS + 3 then
alu_sub <= n_sign xor d_sign;
elsif state = g_BITS + 4 then
alu_sub <= n_sign;
else
alu_sub <= '1';
end if;
end case;
end process;
p_state_counter : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_i = '1' or done = '1' then
state <= 0;
elsif state /= 0 or start_divide = '1' then
state <= state + 1;
end if;
end if;
end process;
p_main : process(clk_i)
begin
if rising_edge(clk_i) then
case state is
when 0 =>
if start_divide = '1' then
is_div_by_zero <= '0';
q <= (others => '0');
r <= (others => '0');
is_rem <= is_rem_i;
n <= unsigned(a_i);
d <= unsigned(b_i);
if is_signed_i = '0' then
n_sign <= '0';
d_sign <= '0';
else
n_sign <= a_i(g_BITS-1);
d_sign <= b_i(g_BITS-1);
end if;
end if;
when 1 =>
n <= alu_result(g_BITS-1 downto 0);
when 2 =>
d <= alu_result(g_BITS-1 downto 0);
is_div_by_zero <= alu_eq and not (is_rem_i or is_signed_i);
when others =>
if state = g_BITS + 3 then
q_o <= std_logic_vector(alu_result(g_BITS-1 downto 0));
elsif state = g_BITS + 4 then
q_o <= std_logic_vector(alu_result(g_BITS-1 downto 0));
else
q <= q(g_BITS-2 downto 0) & alu_ge;
if alu_ge = '1' then
r <= resize(alu_result, r'length);
else
r <= r_next;
end if;
end if;
end case;
end if;
end process;
end rtl;
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_iq_demodulator
--
-- author: Gregoire Hagmann <gregoire.hagmann@cern.ch>
--
-- description: Fs/4 IQ demodulator.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
entity gc_iq_demodulator is
generic (
-- number of data bits
g_N : positive := 16
);
port (
clk_i : in std_logic;
rst_i : in std_logic;
sync_p1_i : in std_logic;
-- ADC data input, 2's complement
adc_data_i : in std_logic_vector(g_N-1 downto 0);
-- I/Q Fs/4 Output
i_o : out std_logic_vector(g_N downto 0);
q_o : out std_logic_vector(g_N downto 0)
);
end gc_iq_demodulator;
architecture rtl of gc_iq_demodulator is
type t_IQ_STATE is (S_0, S_PI2, S_PI, S_3PI2);
signal iacc, qacc : signed(g_N downto 0);
signal state : t_IQ_STATE;
begin
process(clk_i)
begin
if rising_edge(clk_i) then
if rst_i = '1' then
state <= S_0;
iacc <= (others => '0');
qacc <= (others => '0');
elsif sync_p1_i = '1' then
state <= S_PI2;
iacc <= resize(signed(adc_data_i), g_N + 1);
qacc <= (others => '0');
else
case state is
when S_0 =>
state <= S_PI2;
iacc <= resize(signed(adc_data_i), g_N + 1);
qacc <= (others => '0');
when S_PI2 =>
state <= S_PI;
iacc <= (others => '0');
qacc <= resize(-signed(adc_data_i), g_N + 1);
when S_PI =>
state <= S_3PI2;
iacc <= resize(-signed(adc_data_i), g_N + 1);
qacc <= (others => '0');
when S_3PI2 =>
state <= S_0;
iacc <= (others => '0');
qacc <= resize(signed(adc_data_i), g_N + 1);
end case;
end if;
end if;
end process;
i_o <= std_logic_vector(iacc);
q_o <= std_logic_vector(qacc);
end rtl;
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_iq_modulator
--
-- author: Gregoire Hagmann <gregoire.hagmann@cern.ch>
--
-- description: Fs/4 IQ modulator.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
entity gc_iq_modulator is
generic (
-- number of data bits
g_N : positive := 16
);
port (
clk_i : in std_logic;
en_i : in std_logic;
sync_p1_i : in std_logic;
rst_i : in std_logic;
i_i : in std_logic_vector(g_N-1 downto 0);
q_i : in std_logic_vector(g_N-1 downto 0);
i_o : out std_logic_vector(g_N-1 downto 0);
q_o : out std_logic_vector(g_N-1 downto 0)
);
end gc_iq_modulator;
architecture rtl of gc_iq_modulator is
type t_IQ_STATE is (S_0, S_PI2, S_PI, S_3PI2);
signal state : t_IQ_STATE;
signal sync : std_logic;
signal iin, qin : signed(i_i'range);
signal iout, qout : signed(i_o'range);
begin
--Input signal Synchronization
p_latch_input : process(clk_i)
begin
if rising_edge(clk_i) then
iin <= signed(i_i);
qin <= signed(q_i);
sync <= sync_p1_i;
end if;
end process;
p_modulator : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_i = '1' then
state <= S_0;
iout <= (others => '0');
qout <= (others => '0');
elsif en_i = '0' then
state <= S_0;
iout <= iin;
qout <= qin;
elsif sync = '1' or state = S_3PI2 then
state <= S_0;
iout <= iin;
qout <= qin;
elsif state = S_0 then
state <= S_PI2;
iout <= -qin;
qout <= iin;
elsif state = S_PI2 then
state <= S_PI;
iout <= -iin;
qout <= -qin;
elsif state = S_PI then
state <= S_3PI2;
iout <= qin;
qout <= -iin;
end if;
end if;
end process;
--output IQ data in std_logic format
i_o <= std_logic_vector(iout);
q_o <= std_logic_vector(qout);
end rtl;
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_pi_regulator.vhd
--
-- author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
--
-- description: Simple PI regulator core with correct limit/overflow handling.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity gc_pi_regulator is
generic (
g_DATA_BITS : positive := 24;
g_GAIN_BITS : integer := 16;
g_GAIN_FRAC_BITS : integer := 10;
g_INTEGRATOR_BITS : integer := 32;
g_OUTPUT_BITS : positive := 16
);
port (
clk_i : in std_logic;
rst_i : in std_logic;
en_i : in std_logic;
setpoint_i : in std_logic_vector(g_DATA_BITS-1 downto 0);
x_valid_i : in std_logic;
x_i : in std_logic_vector(g_DATA_BITS-1 downto 0);
y_valid_o : out std_logic;
y_o : out std_logic_vector(g_OUTPUT_BITS-1 downto 0);
kp_i : in std_logic_vector(g_GAIN_BITS-1 downto 0);
ki_i : in std_logic_vector(g_GAIN_BITS-1 downto 0);
lim_o : out std_logic
);
end gc_pi_regulator;
architecture rtl of gc_pi_regulator is
constant c_MUL_BITS : integer := g_DATA_BITS + g_GAIN_BITS + 1;
signal xerror : signed(g_DATA_BITS downto 0);
signal setpoint : signed(g_DATA_BITS downto 0);
signal pmul, imul : signed(c_MUL_BITS-1 downto 0);
signal pmul_d : signed(c_MUL_BITS-1 downto 0);
signal integ : signed(g_INTEGRATOR_BITS-1 downto 0);
signal mults_valid : std_logic;
signal integ_valid : std_logic;
procedure f_clamp_add (
x : signed;
y : signed;
o : out signed;
lim : out std_logic) is
variable sum : signed(o'length downto 0);
variable v_min, v_max : signed(o'length downto 0) := to_signed(0, o'length+1);
begin
v_min(v_min'left downto v_min'left-1) := "11";
v_max(v_max'left-2 downto 0) := (others => '1');
sum := resize(x+y, sum'length);
if sum > v_max then
o := resize(v_max, o'length);
lim := '1';
elsif sum < v_min then
o := resize(v_min, o'length);
lim := '1';
else
o := sum(o'length-1 downto 0);
lim := '0';
end if;
end f_clamp_add;
signal limit_sum1, limit_sum2 : std_logic;
begin
setpoint <= resize (signed(setpoint_i), setpoint'length);
xerror <= setpoint - resize(signed(x_i), setpoint'length);
p_the_pi : process(clk_i)
variable v_integ_next : signed(g_INTEGRATOR_BITS-1 downto 0);
variable v_integ_limit_hit : std_logic;
variable v_sum_next : signed(g_INTEGRATOR_BITS downto 0);
variable v_sum_limit_hit : std_logic;
begin
if rising_edge(clk_i) then
if rst_i = '1' then
y_o <= (others => '0');
y_valid_o <= '0';
mults_valid <= '0';
integ_valid <= '0';
integ <= (others => '0');
imul <= (others => '0');
pmul <= (others => '0');
pmul_d <= (others => '0');
limit_sum1 <= '0';
limit_sum2 <= '0';
else
mults_valid <= '0';
integ_valid <= '0';
y_valid_o <= '0';
if en_i = '1' then
if x_valid_i = '1' then
mults_valid <= '1';
pmul <= resize(xerror * signed(kp_i), pmul'length);
imul <= resize(xerror * signed(ki_i), imul'length);
end if;
if mults_valid = '1' then
pmul_d <= pmul;
integ_valid <= '1';
if signed(ki_i) = 0 then
integ <= (others => '0');
else
f_clamp_add(integ, imul, v_integ_next, v_integ_limit_hit);
integ <= v_integ_next;
limit_sum1 <= v_integ_limit_hit;
end if;
end if;
if integ_valid = '1' then
y_valid_o <= '1';
f_clamp_add(integ, pmul_d, v_sum_next, v_sum_limit_hit);
y_o <= std_logic_vector(v_sum_next(g_OUTPUT_BITS + g_GAIN_FRAC_BITS - 1 downto g_GAIN_FRAC_BITS));
limit_sum2 <= v_sum_limit_hit;
end if;
else
y_o <= (others => '0');
integ <= (others => '0');
pmul <= (others => '0');
imul <= (others => '0');
pmul_d <= (others => '0');
limit_sum1 <= '0';
limit_sum2 <= '0';
end if;
end if;
end if;
end process;
lim_o <= limit_sum1 or limit_sum2;
end rtl;
\ No newline at end of file
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_pipelined_fir_filter
--
-- author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
--
-- description: Fully pipelined FIR filter (transposed) structure. Infers
-- FPGA multiplier/MAC blocks. Programmable coefficients. Supports
-- symmetric impulse response optimization.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.gencores_pkg.all;
use work.genram_pkg.all;
use work.gc_dsp_pkg.all;
entity gc_pipelined_fir_filter is
generic(
-- number of coefficient bits
g_COEF_BITS : integer := 16;
-- number of data bits
g_DATA_BITS : integer := 16;
-- number of output bits
g_OUTPUT_BITS : integer := 16;
-- MAC post-sum shift
g_OUTPUT_SHIFT : integer := 16;
-- when true, takes the 1st half of the coefficients and assumes
-- the other half is symmetric to it. Saves 50% of multiplier resources.
g_SYMMETRIC : boolean := false;
-- Order of the filter
g_ORDER : integer
);
port (
clk_i : in std_logic;
rst_i : in std_logic;
coefs_i : in t_FIR_COEF_ARRAY;
d_i : in std_logic_vector(g_DATA_BITS-1 downto 0);
d_valid_i : in std_logic;
d_o : out std_logic_vector(g_OUTPUT_BITS-1 downto 0);
d_valid_o : out std_logic
);
end gc_pipelined_fir_filter;
architecture rtl of gc_pipelined_fir_filter is
constant c_ACC_BITS : integer := g_DATA_BITS + g_COEF_BITS + f_log2_size(g_ORDER) + 1;
type t_postmul_array is array(g_ORDER-1 downto 0) of signed(g_DATA_BITS+g_COEF_BITS downto 0);
function f_eval_num_taps(ncoefs : integer; is_symmetric : boolean) return integer is
begin
if is_symmetric then
if ncoefs mod 2 = 0 then
return ncoefs/2;
else
return ncoefs/2+1;
end if;
else
return ncoefs;
end if;
end f_eval_num_taps;
impure function f_convert_coef(n : integer) return signed is
begin
return coefs_i(n)(g_COEF_BITS-1 downto 0);
end f_convert_coef;
constant c_NUM_TAPS : integer := f_eval_num_taps(g_ORDER, g_SYMMETRIC);
type t_chainsum_array is array(g_ORDER-1 downto 0) of signed(c_ACC_BITS-1 downto 0);
signal d_reg : signed(g_DATA_BITS downto 0);
signal premul_valid : std_logic;
signal postmul : t_postmul_array;
signal postmul_valid : std_logic;
signal acc_out_rounded : signed(g_OUTPUT_BITS downto 0);
signal acc_out_valid : std_logic;
signal chain_sum : t_chainsum_array;
signal chain_sum_valid : std_logic_vector(g_ORDER-1 downto 0);
begin
p_multipliers : process(clk_i)
begin
if rising_edge(clk_i) then
d_reg <= resize(signed(d_i), g_DATA_BITS+1);
premul_valid <= d_valid_i;
postmul_valid <= premul_valid;
for i in 0 to c_NUM_TAPS-1 loop
postmul(i) <= d_reg * f_convert_coef(i);
end loop;
end if;
end process;
p_sum_pipe : process(clk_i)
begin
if rising_edge(clk_i) then
chain_sum_valid <= chain_sum_valid(g_ORDER-2 downto 0) & postmul_valid;
chain_sum(0) <= resize(postmul(0), c_ACC_BITS);
if not g_SYMMETRIC then
for i in 1 to g_ORDER-1 loop
chain_sum(i) <= chain_sum(i-1) + postmul(i);
end loop;
else
if g_ORDER mod 2 = 0 then
for i in 1 to c_NUM_TAPS-1 loop
chain_sum(i) <= chain_sum(i-1) + postmul(i);
end loop;
for i in 0 to c_NUM_TAPS-1 loop
chain_sum(i + c_NUM_TAPS) <= chain_sum(i + c_NUM_TAPS - 1) + postmul(c_NUM_TAPS - 1 - i);
end loop;
else
for i in 1 to c_NUM_TAPS-1 loop
chain_sum(i) <= chain_sum(i-1) + postmul(i);
end loop;
for i in 1 to c_NUM_TAPS-1 loop
chain_sum(i + c_NUM_TAPS - 1) <= chain_sum(i + c_NUM_TAPS - 2) + postmul(c_NUM_TAPS - 1 - i);
end loop;
end if;
end if;
end if;
end process;
p_round_output : process(clk_i)
begin
if rising_edge(clk_i) then
if d_valid_i = '1' then
if chain_sum(g_ORDER-1)(g_OUTPUT_SHIFT-1) = '1' then
acc_out_rounded <= chain_sum(g_ORDER-1)(g_OUTPUT_BITS + g_OUTPUT_SHIFT - 1 downto g_OUTPUT_SHIFT-1) + 1;
else
acc_out_rounded <= chain_sum(g_ORDER-1)(g_OUTPUT_BITS + g_OUTPUT_SHIFT - 1 downto g_OUTPUT_SHIFT-1);
end if;
acc_out_valid <= chain_sum_valid(g_ORDER-1);
else
acc_out_valid <= '0';
end if;
end if;
end process;
d_o <= std_logic_vector(acc_out_rounded(g_OUTPUT_BITS downto 1));
d_valid_o <= acc_out_valid;
end rtl;
--------------------------------------------------------------------------------
-- CERN BE-CEM-EDL
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_soft_ramp_switch
--
-- author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
--
-- description: "soft switch", allowing to raise/squelch a signal slowly
-- with a programmable rise time and delay. Typical use case is
-- an on-off switch for LLRF system outputs
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.gencores_pkg.all;
entity gc_soft_ramp_switch is
generic (
g_DATA_BITS : positive := 16;
g_NUM_CHANNELS : integer range 1 to 2 := 2
);
port (
clk_i : in std_logic;
rst_i : in std_logic;
rate_i : in std_logic_vector(15 downto 0);
on_i : in std_logic;
kill_i : in std_logic;
is_on_o : out std_logic;
is_off_o : out std_logic;
busy_o : out std_logic;
x_valid_i : in std_logic;
x0_i : in std_logic_vector(g_DATA_BITS-1 downto 0);
x1_i : in std_logic_vector(g_DATA_BITS-1 downto 0) := (others => '0');
x2_i : in std_logic_vector(g_DATA_BITS-1 downto 0) := (others => '0');
x3_i : in std_logic_vector(g_DATA_BITS-1 downto 0) := (others => '0');
y_valid_o : out std_logic;
y0_o : out std_logic_vector(g_DATA_BITS-1 downto 0);
y1_o : out std_logic_vector(g_DATA_BITS-1 downto 0);
y2_o : out std_logic_vector(g_DATA_BITS-1 downto 0);
y3_o : out std_logic_vector(g_DATA_BITS-1 downto 0)
);
end gc_soft_ramp_switch;
architecture rtl of gc_soft_ramp_switch is
type t_SIG_ARRAY is array(0 to 3) of signed(g_DATA_BITS-1 downto 0);
constant c_MUL_BITS : integer := g_DATA_BITS + 18;
constant c_RAMP_INTEG_BITS : integer := 24;
type t_STATE is (SW_OFF, SW_RAMP_UP, SW_ON, SW_RAMP_DOWN);
signal ramp_integ : unsigned(c_RAMP_INTEG_BITS-1 downto 0);
signal state : t_STATE;
signal mulf : unsigned(17 downto 0);
signal xi, yo : t_SIG_ARRAY;
function f_mul_sar(x : signed; y : unsigned; outbits : integer) return signed is
variable tmp : signed(x'length + y'length downto 0);
begin
tmp := x * signed('0'&y);
return tmp(tmp'length-3 downto tmp'length - outbits-2);
end f_mul_sar;
begin
p_switch : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_i = '1' or kill_i = '1' then
state <= SW_OFF;
ramp_integ <= (others => '0');
is_off_o <= '1';
is_on_o <= '0';
busy_o <= '0';
else
case state is
when SW_OFF =>
is_off_o <= '1';
busy_o <= '0';
if on_i = '1' then
ramp_integ <= (others => '0');
state <= SW_RAMP_UP;
end if;
when SW_RAMP_UP =>
busy_o <= '1';
is_off_o <= '0';
if ramp_integ(ramp_integ'length-1) = '1' then
state <= SW_ON;
end if;
ramp_integ <= ramp_integ + unsigned(rate_i);
when SW_ON =>
ramp_integ <= to_unsigned(2**(c_RAMP_INTEG_BITS-1), c_RAMP_INTEG_BITS);
busy_o <= '0';
is_on_o <= '1';
if on_i = '0' then
state <= SW_RAMP_DOWN;
end if;
when SW_RAMP_DOWN =>
is_on_o <= '0';
busy_o <= '1';
if(ramp_integ < unsigned(rate_i)) then
ramp_integ <= (others => '0');
state <= SW_OFF;
else
ramp_integ <= ramp_integ - unsigned(rate_i);
end if;
end case;
end if;
end if;
end process;
xi(0) <= signed(x0_i);
xi(1) <= signed(x1_i);
xi(2) <= signed(x2_i);
xi(3) <= signed(x3_i);
y0_o <= std_logic_vector(yo(0));
y1_o <= std_logic_vector(yo(1));
y2_o <= std_logic_vector(yo(2));
y3_o <= std_logic_vector(yo(3));
p_mulf : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_i = '1' then
y_valid_o <= '0';
mulf <= (others => '0');
else
mulf <= ramp_integ(ramp_integ'length-1 downto ramp_integ'length - 18);
y_valid_o <= x_valid_i;
for i in 0 to g_NUM_CHANNELS loop
if kill_i = '0' then
yo(i) <= f_mul_sar(xi(i), mulf, g_DATA_BITS);
else
yo(i) <= (others => '0');
end if;
end loop;
end if;
end if;
end process;
end rtl;
......@@ -6,7 +6,7 @@
-- Author : Wesley W. Terpstra
-- Company : GSI
-- Created : 2011-01-25
-- Last update: 2013-03-04
-- Last update: 2022-07-25
-- Platform :
-- Standard : VHDL'93
-------------------------------------------------------------------------------
......@@ -44,7 +44,9 @@ entity generic_dpram is
g_addr_conflict_resolution : string := "dont_care";
g_init_file : string := "none";
g_fail_if_file_not_found : boolean := true; -- dummy (exists in Xilinx/generic)
g_dual_clock : boolean := true);
g_dual_clock : boolean := true;
g_implementation_hint : string := "auto"
);
port(
rst_n_i : in std_logic := '1'; -- synchronous reset, active LO
......
......@@ -6,7 +6,7 @@
-- Author : C. Prados
-- Company : GSI
-- Created : 2014-08-25
-- Last update:
-- Last update: 2022-07-25
-- Platform :
-- Standard : VHDL'93
-------------------------------------------------------------------------------
......@@ -38,7 +38,9 @@ entity generic_dpram_mixed is
g_size : natural;
g_addr_conflict_resolution : string := "dont_care";
g_init_file : string := "none";
g_dual_clock : boolean := true);
g_dual_clock : boolean := true;
g_implementation_hint : string := "auto"
);
port(
rst_n_i : in std_logic := '1'; -- synchronous reset, active LO
......
......@@ -6,7 +6,7 @@
-- Author : Wesley W. Terpstra
-- Company : GSI
-- Created : 2013-03-04
-- Last update: 2013-03-04
-- Last update: 2022-07-25
-- Platform :
-- Standard : VHDL'93
-------------------------------------------------------------------------------
......@@ -38,7 +38,8 @@ entity generic_simple_dpram is
g_with_byte_enable : boolean := false;
g_addr_conflict_resolution : string := "dont_care";
g_init_file : string := "none";
g_dual_clock : boolean := true);
g_dual_clock : boolean := true;
g_implementation_hint : string := "auto");
port(
rst_n_i : in std_logic := '1'; -- synchronous reset, active LO
......
......@@ -6,7 +6,7 @@
-- Author : Wesley W. Terpstra
-- Company : GSI
-- Created : 2011-01-25
-- Last update: 2013-03-04
-- Last update: 2022-07-25
-- Platform :
-- Standard : VHDL'93
-------------------------------------------------------------------------------
......@@ -39,7 +39,8 @@ entity generic_spram is
g_size : natural := 1024;
g_with_byte_enable : boolean := false;
g_addr_conflict_resolution : string := "dont_care";
g_init_file : string := "");
g_init_file : string := "";
g_implementation_hint : string := "auto");
port(
rst_n_i : in std_logic := '1';
clk_i : in std_logic;
......
......@@ -53,8 +53,9 @@ entity inferred_async_fifo is
g_with_wr_count : boolean := FALSE;
g_almost_empty_threshold : integer; -- threshold for almost empty flag
g_almost_full_threshold : integer -- threshold for almost full flag
);
g_almost_full_threshold : integer; -- threshold for almost full flag
g_memory_implementation_hint : string := "auto");
port (
rst_n_i : in std_logic := '1';
......@@ -116,11 +117,24 @@ architecture syn of inferred_async_fifo is
bin_x, gray_x : t_counter;
end record;
constant c_counters_reset_value : t_counter_block :=
( bin => (others => '0'),
bin_next => (others => '0'),
gray => (others => '0'),
gray_next => (others => '0'),
bin_x => (others => '0'),
gray_x => (others => '0') );
type t_mem_type is array (0 to g_size-1) of std_logic_vector(g_data_width-1 downto 0);
signal mem : t_mem_type := (others => (others => '0'));
signal rcb, wcb : t_counter_block := (others =>(others => '0'));
attribute ram_type : string;
attribute ram_type of mem : signal is g_memory_implementation_hint;
signal rcb, wcb : t_counter_block := c_counters_reset_value;
signal full_int, empty_int : std_logic;
signal almost_full_int, almost_empty_int : std_logic;
signal going_full : std_logic;
......@@ -138,6 +152,7 @@ architecture syn of inferred_async_fifo is
begin -- syn
-- Protect against overflow and underflow.
rd_int <= rd_i and not empty_int;
we_int <= we_i and not full_int;
......@@ -153,9 +168,15 @@ begin -- syn
p_mem_read : process(clk_rd_i)
begin
if rising_edge(clk_rd_i) then
-- In show ahead mode, the output is valid (unless the fifo is empty), and 'rd'
-- ack the current value.
-- In no show ahead mode, the output is not valid, and 'rd' will output the value
-- on the next cycle.
if(rd_int = '1' and g_show_ahead) then
-- Read the next value.
q_int <= mem(to_integer(unsigned(rcb.bin_next(rcb.bin_next'LEFT-1 downto 0))));
elsif(rd_int = '1' or g_show_ahead) then
-- Read the current entry.
q_int <= mem(to_integer(unsigned(rcb.bin(rcb.bin'LEFT-1 downto 0))));
end if;
end if;
......@@ -229,6 +250,8 @@ begin -- syn
end if;
end process p_gen_empty;
-- Note: because of the synchronizer, wr_empty may not be fully accurate,
-- but this is usually ok (the writer shouldn't care).
gen_with_wr_empty : if g_with_wr_empty = TRUE generate
U_Sync_Empty : gc_sync_ffs
generic map (
......@@ -240,6 +263,8 @@ begin -- syn
synced_o => wr_empty_x);
end generate gen_with_wr_empty;
-- Likewise, because of the synchronizer the rd_full may not be fully
-- accurate.
gen_with_rd_full : if g_with_rd_full = TRUE generate
U_Sync_Full : gc_sync_ffs
generic map (
......@@ -258,10 +283,12 @@ begin -- syn
begin
if ((wcb.bin (wcb.bin'LEFT-1 downto 0) = rcb.bin_x(rcb.bin_x'LEFT-1 downto 0))
and (wcb.bin(wcb.bin'LEFT) /= rcb.bin_x(rcb.bin_x'LEFT))) then
-- It's already full!
going_full <= '1';
elsif (we_int = '1'
and (wcb.bin_next(wcb.bin'LEFT-1 downto 0) = rcb.bin_x(rcb.bin_x'LEFT-1 downto 0))
and (wcb.bin_next(wcb.bin'LEFT) /= rcb.bin_x(rcb.bin_x'LEFT))) then
-- Will probably be full (useless there is a read, but we are conservative)
going_full <= '1';
else
going_full <= '0';
......
......@@ -50,7 +50,8 @@ entity inferred_async_fifo_dual_rst is
g_with_wr_almost_full : boolean := FALSE;
g_with_wr_count : boolean := FALSE;
g_almost_empty_threshold : integer;
g_almost_full_threshold : integer);
g_almost_full_threshold : integer;
g_memory_implementation_hint : string := "auto");
port (
-- write port
rst_wr_n_i : in std_logic := '1';
......@@ -111,6 +112,9 @@ architecture arch of inferred_async_fifo_dual_rst is
signal rcb, wcb : t_counter_block := (others =>(others => '0'));
attribute ram_type : string;
attribute ram_type of mem : signal is g_memory_implementation_hint;
signal full_int, empty_int : std_logic;
signal almost_full_int, almost_empty_int : std_logic;
signal going_full : std_logic;
......
......@@ -54,7 +54,9 @@ entity inferred_sync_fifo is
g_almost_empty_threshold : integer := 0; -- threshold for almost empty flag
g_almost_full_threshold : integer := 0; -- threshold for almost full flag
g_register_flag_outputs : boolean := true
g_register_flag_outputs : boolean := true;
g_memory_implementation_hint : string := "auto"
);
port (
......@@ -105,7 +107,8 @@ begin -- syn
g_size => g_size,
g_with_byte_enable => false,
g_addr_conflict_resolution => "dont_care",
g_dual_clock => false)
g_dual_clock => false,
g_implementation_hint => g_memory_implementation_hint)
port map (
rst_n_i => rst_n_i,
clka_i => clk_i,
......
......@@ -2,4 +2,5 @@ files = [
"generic_async_fifo_dual_rst.vhd",
"generic_async_fifo.vhd",
"generic_sync_fifo.vhd",
"generic_async_fifo_mixedw.vhd",
]
......@@ -52,8 +52,10 @@ entity generic_async_fifo is
g_with_wr_almost_full : boolean := false;
g_with_wr_count : boolean := false;
g_almost_empty_threshold : integer; -- threshold for almost empty flag
g_almost_full_threshold : integer -- threshold for almost full flag
g_almost_empty_threshold : integer := 0; -- threshold for almost empty flag
g_almost_full_threshold : integer := 0; -- threshold for almost full flag
g_memory_implementation_hint : string := "auto"
);
port (
......@@ -87,48 +89,9 @@ end generic_async_fifo;
architecture syn of generic_async_fifo is
component inferred_async_fifo
generic (
g_data_width : natural;
g_size : natural;
g_show_ahead : boolean;
g_with_rd_empty : boolean;
g_with_rd_full : boolean;
g_with_rd_almost_empty : boolean;
g_with_rd_almost_full : boolean;
g_with_rd_count : boolean;
g_with_wr_empty : boolean;
g_with_wr_full : boolean;
g_with_wr_almost_empty : boolean;
g_with_wr_almost_full : boolean;
g_with_wr_count : boolean;
g_almost_empty_threshold : integer;
g_almost_full_threshold : integer);
port (
rst_n_i : in std_logic := '1';
clk_wr_i : in std_logic;
d_i : in std_logic_vector(g_data_width-1 downto 0);
we_i : in std_logic;
wr_empty_o : out std_logic;
wr_full_o : out std_logic;
wr_almost_empty_o : out std_logic;
wr_almost_full_o : out std_logic;
wr_count_o : out std_logic_vector(f_log2_size(g_size)-1 downto 0);
clk_rd_i : in std_logic;
q_o : out std_logic_vector(g_data_width-1 downto 0);
rd_i : in std_logic;
rd_empty_o : out std_logic;
rd_full_o : out std_logic;
rd_almost_empty_o : out std_logic;
rd_almost_full_o : out std_logic;
rd_count_o : out std_logic_vector(f_log2_size(g_size)-1 downto 0));
end component;
begin -- syn
U_Inferred_FIFO : inferred_async_fifo
U_Inferred_FIFO : entity work.inferred_async_fifo
generic map (
g_data_width => g_data_width,
g_size => g_size,
......@@ -144,7 +107,8 @@ begin -- syn
g_with_wr_almost_full => g_with_wr_almost_full,
g_with_wr_count => g_with_wr_count,
g_almost_empty_threshold => g_almost_empty_threshold,
g_almost_full_threshold => g_almost_full_threshold)
g_almost_full_threshold => g_almost_full_threshold,
g_memory_implementation_hint => g_memory_implementation_hint )
port map (
rst_n_i => rst_n_i,
clk_wr_i => clk_wr_i,
......
......@@ -50,7 +50,8 @@ entity generic_async_fifo_dual_rst is
g_with_wr_almost_full : boolean := FALSE;
g_with_wr_count : boolean := FALSE;
g_almost_empty_threshold : integer := 0;
g_almost_full_threshold : integer := 0);
g_almost_full_threshold : integer := 0;
g_memory_implementation_hint : string := "auto" );
port (
-- write port
rst_wr_n_i : in std_logic := '1';
......@@ -96,7 +97,8 @@ begin -- arch
g_with_wr_almost_full => g_with_wr_almost_full,
g_with_wr_count => g_with_wr_count,
g_almost_empty_threshold => g_almost_empty_threshold,
g_almost_full_threshold => g_almost_full_threshold)
g_almost_full_threshold => g_almost_full_threshold,
g_memory_implementation_hint => g_memory_implementation_hint )
port map (
rst_wr_n_i => rst_wr_n_i,
clk_wr_i => clk_wr_i,
......
This diff is collapsed.
......@@ -53,7 +53,8 @@ entity generic_sync_fifo is
g_almost_empty_threshold : integer := 0; -- threshold for almost empty flag
g_almost_full_threshold : integer := 0; -- threshold for almost full flag
g_register_flag_outputs : boolean := true
g_register_flag_outputs : boolean := true;
g_memory_implementation_hint : string := "auto"
);
port (
......@@ -76,38 +77,8 @@ entity generic_sync_fifo is
end generic_sync_fifo;
architecture syn of generic_sync_fifo is
component inferred_sync_fifo
generic (
g_data_width : natural;
g_size : natural;
g_show_ahead : boolean;
g_show_ahead_legacy_mode : boolean;
g_with_empty : boolean;
g_with_full : boolean;
g_with_almost_empty : boolean;
g_with_almost_full : boolean;
g_with_count : boolean;
g_almost_empty_threshold : integer;
g_almost_full_threshold : integer;
g_register_flag_outputs : boolean);
port (
rst_n_i : in std_logic := '1';
clk_i : in std_logic;
d_i : in std_logic_vector(g_data_width-1 downto 0);
we_i : in std_logic;
q_o : out std_logic_vector(g_data_width-1 downto 0);
rd_i : in std_logic;
empty_o : out std_logic;
full_o : out std_logic;
almost_empty_o : out std_logic;
almost_full_o : out std_logic;
count_o : out std_logic_vector(f_log2_size(g_size)-1 downto 0));
end component;
begin -- syn
U_Inferred_FIFO : inferred_sync_fifo
U_Inferred_FIFO : entity work.inferred_sync_fifo
generic map (
g_data_width => g_data_width,
g_size => g_size,
......@@ -120,8 +91,8 @@ begin -- syn
g_with_count => g_with_count,
g_almost_empty_threshold => g_almost_empty_threshold,
g_almost_full_threshold => g_almost_full_threshold,
g_register_flag_outputs => g_register_flag_outputs)
g_register_flag_outputs => g_register_flag_outputs,
g_memory_implementation_hint => g_memory_implementation_hint )
port map (
rst_n_i => rst_n_i,
clk_i => clk_i,
......@@ -134,7 +105,4 @@ begin -- syn
almost_empty_o => almost_empty_o,
almost_full_o => almost_full_o,
count_o => count_o);
end syn;
......@@ -48,7 +48,8 @@ package genram_pkg is
g_size : natural;
g_with_byte_enable : boolean := false;
g_init_file : string := "none";
g_addr_conflict_resolution : string := "dont_care") ;
g_addr_conflict_resolution : string := "dont_care";
g_implementation_hint : string := "auto") ;
port (
rst_n_i : in std_logic;
clk_i : in std_logic;
......@@ -66,7 +67,9 @@ package genram_pkg is
g_with_byte_enable : boolean := false;
g_addr_conflict_resolution : string := "dont_care";
g_init_file : string := "none";
g_dual_clock : boolean := true);
g_dual_clock : boolean := true;
g_implementation_hint : string := "auto"
);
port (
rst_n_i : in std_logic := '1';
clka_i : in std_logic;
......@@ -87,7 +90,9 @@ package genram_pkg is
g_addr_conflict_resolution : string := "dont_care";
g_init_file : string := "none";
g_fail_if_file_not_found : boolean := true;
g_dual_clock : boolean := true);
g_dual_clock : boolean := true;
g_implementation_hint : string := "auto"
);
port (
rst_n_i : in std_logic := '1';
clka_i : in std_logic;
......@@ -111,7 +116,9 @@ package genram_pkg is
g_size : natural;
g_addr_conflict_resolution : string := "dont_care";
g_init_file : string := "none";
g_dual_clock : boolean := true);
g_dual_clock : boolean := true;
g_implementation_hint : string := "auto"
);
port (
rst_n_i : in std_logic := '1';
clka_i : in std_logic;
......@@ -144,7 +151,8 @@ package genram_pkg is
g_with_wr_almost_full : boolean := false;
g_with_wr_count : boolean := false;
g_almost_empty_threshold : integer := 0;
g_almost_full_threshold : integer := 0);
g_almost_full_threshold : integer := 0;
g_memory_implementation_hint : string := "auto");
port (
rst_wr_n_i : in std_logic := '1';
clk_wr_i : in std_logic;
......@@ -223,7 +231,9 @@ package genram_pkg is
g_with_wr_almost_full : boolean := false;
g_with_wr_count : boolean := false;
g_almost_empty_threshold : integer := 0;
g_almost_full_threshold : integer := 0);
g_almost_full_threshold : integer := 0;
g_memory_implementation_hint : string := "auto"
);
port (
rst_n_i : in std_logic := '1';
clk_wr_i : in std_logic;
......@@ -258,7 +268,9 @@ package genram_pkg is
g_with_count : boolean := false;
g_almost_empty_threshold : integer := 0;
g_almost_full_threshold : integer := 0;
g_register_flag_outputs : boolean := true);
g_register_flag_outputs : boolean := true;
g_memory_implementation_hint : string := "auto"
);
port (
rst_n_i : in std_logic := '1';
clk_i : in std_logic;
......@@ -290,6 +302,29 @@ package genram_pkg is
);
end component;
component generic_dpram_split is
generic (
g_size : natural;
g_init_file : string := "none";
g_addr_conflict_resolution : string := "dont_care";
g_fail_if_file_not_found : boolean := true;
g_implementation_hint : string := "auto"
);
port (
rst_n_i : in std_logic := '1';
clk_i : in std_logic;
bwea_i : in std_logic_vector(3 downto 0);
wea_i : in std_logic;
aa_i : in std_logic_vector(f_log2_size(g_size)-1 downto 0);
da_i : in std_logic_vector(31 downto 0);
qa_o : out std_logic_vector(31 downto 0);
bweb_i : in std_logic_vector(3 downto 0);
web_i : in std_logic;
ab_i : in std_logic_vector(f_log2_size(g_size)-1 downto 0);
db_i : in std_logic_vector(31 downto 0);
qb_o : out std_logic_vector(31 downto 0));
end component generic_dpram_split;
end genram_pkg;
package body genram_pkg is
......@@ -317,6 +352,7 @@ package body genram_pkg is
function f_check_bounds(x : integer; minx : integer; maxx : integer) return integer is
begin
-- synthesis translate_off
if(x < minx) then
return minx;
elsif(x > maxx) then
......@@ -324,6 +360,8 @@ package body genram_pkg is
else
return x;
end if;
-- synthesis translate_on
return x;
end f_check_bounds;
end genram_pkg;
......@@ -49,7 +49,8 @@ entity generic_dpram is
g_addr_conflict_resolution : string := "read_first";
g_init_file : string := "";
g_dual_clock : boolean := true;
g_fail_if_file_not_found : boolean := true
g_fail_if_file_not_found : boolean := true;
g_implementation_hint : string := "auto"
);
port (
......@@ -89,7 +90,9 @@ architecture syn of generic_dpram is
g_size : natural;
g_addr_conflict_resolution : string := "dont_care";
g_init_file : string := "none";
g_fail_if_file_not_found : boolean := true);
g_fail_if_file_not_found : boolean := true;
g_implementation_hint : string := "auto"
);
port (
rst_n_i : in std_logic := '1';
clk_i : in std_logic;
......@@ -112,7 +115,9 @@ architecture syn of generic_dpram is
g_with_byte_enable : boolean;
g_addr_conflict_resolution : string;
g_init_file : string;
g_fail_if_file_not_found : boolean);
g_fail_if_file_not_found : boolean;
g_implementation_hint : string
);
port (
rst_n_i : in std_logic := '1';
clk_i : in std_logic;
......@@ -135,7 +140,9 @@ architecture syn of generic_dpram is
g_with_byte_enable : boolean;
g_addr_conflict_resolution : string;
g_init_file : string;
g_fail_if_file_not_found : boolean);
g_fail_if_file_not_found : boolean;
g_implementation_hint : string
);
port (
rst_n_i : in std_logic := '1';
clka_i : in std_logic;
......@@ -167,7 +174,8 @@ begin
g_size => g_size,
g_addr_conflict_resolution => g_addr_conflict_resolution,
g_init_file => g_init_file,
g_fail_if_file_not_found => g_fail_if_file_not_found)
g_fail_if_file_not_found => g_fail_if_file_not_found,
g_implementation_hint => g_implementation_hint)
port map(
rst_n_i => rst_n_i,
clk_i => clka_i,
......@@ -191,7 +199,8 @@ begin
g_with_byte_enable => g_with_byte_enable,
g_addr_conflict_resolution => g_addr_conflict_resolution,
g_init_file => g_init_file,
g_fail_if_file_not_found => g_fail_if_file_not_found)
g_fail_if_file_not_found => g_fail_if_file_not_found,
g_implementation_hint => g_implementation_hint)
port map (
rst_n_i => rst_n_i,
clk_i => clka_i,
......@@ -217,7 +226,8 @@ begin
g_with_byte_enable => g_with_byte_enable,
g_addr_conflict_resolution => g_addr_conflict_resolution,
g_init_file => g_init_file,
g_fail_if_file_not_found => g_fail_if_file_not_found)
g_fail_if_file_not_found => g_fail_if_file_not_found,
g_implementation_hint => g_implementation_hint)
port map (
rst_n_i => rst_n_i,
clka_i => clka_i,
......
......@@ -48,7 +48,8 @@ entity generic_dpram_dualclock is
g_with_byte_enable : boolean := false;
g_addr_conflict_resolution : string := "read_first";
g_init_file : string := "";
g_fail_if_file_not_found : boolean := true
g_fail_if_file_not_found : boolean := true;
g_implementation_hint : string := "auto"
);
port (
......@@ -122,6 +123,9 @@ architecture syn of generic_dpram_dualclock is
shared variable ram : t_ram_type := f_file_to_ramtype;
attribute ram_type : string;
attribute ram_type of ram : variable is g_implementation_hint;
signal s_we_a : std_logic_vector(c_num_bytes-1 downto 0);
signal s_we_b : std_logic_vector(c_num_bytes-1 downto 0);
......
......@@ -47,7 +47,8 @@ entity generic_dpram_sameclock is
g_with_byte_enable : boolean := false;
g_addr_conflict_resolution : string := "read_first";
g_init_file : string := "";
g_fail_if_file_not_found : boolean := true
g_fail_if_file_not_found : boolean := true;
g_implementation_hint : string := "auto"
);
port (
......@@ -122,6 +123,9 @@ architecture syn of generic_dpram_sameclock is
shared variable ram : t_ram_type := f_file_to_ramtype;
attribute ram_type : string;
attribute ram_type of ram : variable is g_implementation_hint;
signal s_we_a : std_logic_vector(c_num_bytes-1 downto 0);
signal s_we_b : std_logic_vector(c_num_bytes-1 downto 0);
......
......@@ -61,7 +61,8 @@ entity generic_dpram_split is
g_size : natural := 16384;
g_addr_conflict_resolution : string := "read_first";
g_init_file : string := "";
g_fail_if_file_not_found : boolean := true);
g_fail_if_file_not_found : boolean := true;
g_implementation_hint : string := "auto");
port (
rst_n_i : in std_logic := '1';
clk_i : in std_logic;
......@@ -112,6 +113,12 @@ architecture syn of generic_dpram_split is
shared variable ram2 : t_split_ram := f_file_to_ramtype(2);
shared variable ram3 : t_split_ram := f_file_to_ramtype(3);
attribute ram_type : string;
attribute ram_type of ram0 : variable is g_implementation_hint;
attribute ram_type of ram1 : variable is g_implementation_hint;
attribute ram_type of ram2 : variable is g_implementation_hint;
attribute ram_type of ram3 : variable is g_implementation_hint;
signal s_we_a : std_logic_vector(c_num_bytes-1 downto 0);
signal s_we_b : std_logic_vector(c_num_bytes-1 downto 0);
signal wea_rep : std_logic_vector(c_num_bytes-1 downto 0);
......
......@@ -6,7 +6,7 @@
-- Author : Wesley W. Terpstra
-- Company : GSI
-- Created : 2013-03-04
-- Last update: 2013-10-30
-- Last update: 2022-07-25
-- Platform :
-- Standard : VHDL'93
-------------------------------------------------------------------------------
......@@ -58,7 +58,8 @@ entity generic_simple_dpram is
g_addr_conflict_resolution : string := "read_first";
g_init_file : string := "";
g_dual_clock : boolean := true;
g_fail_if_file_not_found : boolean := true
g_fail_if_file_not_found : boolean := true;
g_implementation_hint : string := "auto"
);
port (
......@@ -93,7 +94,8 @@ begin
g_with_byte_enable => g_with_byte_enable,
g_addr_conflict_resolution => g_addr_conflict_resolution,
g_init_file => g_init_file,
g_dual_clock => g_dual_clock)
g_dual_clock => g_dual_clock,
g_implementation_hint => g_implementation_hint )
port map(
rst_n_i => rst_n_i,
clka_i => clka_i,
......
......@@ -19,7 +19,9 @@ entity generic_spram is
-- RAM read-on-write conflict resolution. Can be "read_first" (read-then-write)
-- or "write_first" (write-then-read)
g_addr_conflict_resolution : string := "write_first";
g_init_file : string := ""
g_init_file : string := "";
g_implementation_hint : string := "auto"
);
port (
......@@ -59,7 +61,10 @@ architecture syn of generic_spram is
signal s_ram_in : std_logic_vector(g_data_width-1 downto 0);
signal s_ram_out : std_logic_vector(g_data_width-1 downto 0);
attribute ram_type : string;
attribute ram_type of ram : signal is g_implementation_hint;
begin
assert (g_init_file = "" or g_init_file = "none")
......
......@@ -31,6 +31,8 @@ modules = { "local" : [
"wbgen2",
"wbgenplus",
"wb_xc7_fw_update",
"wb_lm32_mcs",
"wb_clock_monitor"
]}
files = [
......
......@@ -68,8 +68,8 @@ begin
case state is
when IDLE =>
wb_master_o.cyc <= '0';
axi4_slave_o.ARREADY <= '1';
axi4_slave_o.AWREADY <= '1';
axi4_slave_o.ARREADY <= '0';
axi4_slave_o.AWREADY <= '0';
axi4_slave_o.WREADY <= '0';
axi4_slave_o.BVALID <= '0';
axi4_slave_o.BRESP <= (others => 'X');
......@@ -81,14 +81,17 @@ begin
if (axi4_slave_i.AWVALID = '1') then
state <= ISSUE_WRITE;
wb_master_o.adr <= axi4_slave_i.AWADDR;
axi4_slave_o.AWREADY <= '1';
elsif (axi4_slave_i.ARVALID = '1') then
state <= ISSUE_READ;
wb_master_o.adr <= axi4_slave_i.ARADDR;
axi4_slave_o.ARREADY <= '1';
end if;
when ISSUE_WRITE =>
wb_master_o.cyc <= '1';
wb_master_o.we <= '1';
axi4_slave_o.AWREADY <= '0';
axi4_slave_o.WREADY <= '1';
if (axi4_slave_i.WVALID = '1') then
wb_master_o.stb <= '1';
......@@ -101,9 +104,10 @@ begin
wb_master_o.cyc <= '1';
wb_master_o.stb <= '1';
wb_master_o.we <= '0';
axi4_slave_o.RVALID <= '0';
axi4_slave_o.RLAST <= '0';
state <= COMPLETE_READ;
axi4_slave_o.ARREADY <= '0';
if(axi4_slave_i.RREADY = '1') then
state <= COMPLETE_READ;
end if;
when COMPLETE_READ =>
if (wb_master_i.stall = '0') then
......@@ -122,6 +126,7 @@ begin
end if;
when COMPLETE_WRITE =>
axi4_slave_o.WREADY <= '0';
if (wb_master_i.stall = '0') then
wb_master_o.stb <= '0';
if (wb_master_i.ack = '1') then
......
files = [
"clock_monitor_wbgen2_pkg.vhd",
"clock_monitor_wb.vhd",
"xwb_clock_monitor.vhd"];
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for Clock Frequency Monitor
---------------------------------------------------------------------------------------
-- File : clock_monitor_wb.vhd
-- Author : auto-generated by wbgen2 from clock_monitor_wb.wb
-- Created : Mon Jun 17 18:28:42 2019
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE clock_monitor_wb.wb
-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
---------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.cm_wbgen2_pkg.all;
entity clock_monitor_wb is
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
slave_i : in t_wishbone_slave_in;
slave_o : out t_wishbone_slave_out;
int_o : out std_logic;
regs_i : in t_cm_in_registers;
regs_o : out t_cm_out_registers
);
end clock_monitor_wb;
architecture syn of clock_monitor_wb is
signal cm_cr_cnt_rst_dly0 : std_logic ;
signal cm_cr_cnt_rst_int : std_logic ;
signal cm_cr_presc_int : std_logic_vector(7 downto 0);
signal cm_cr_refsel_int : std_logic_vector(3 downto 0);
signal cm_refdr_refdr_int : std_logic_vector(31 downto 0);
signal cm_cnt_sel_sel_int : std_logic_vector(3 downto 0);
signal ack_sreg : std_logic_vector(9 downto 0);
signal rddata_reg : std_logic_vector(31 downto 0);
signal wrdata_reg : std_logic_vector(31 downto 0);
signal bwsel_reg : std_logic_vector(3 downto 0);
signal rwaddr_reg : std_logic_vector(1 downto 0);
signal ack_in_progress : std_logic ;
signal wr_int : std_logic ;
signal rd_int : std_logic ;
signal allones : std_logic_vector(31 downto 0);
signal allzeros : std_logic_vector(31 downto 0);
begin
-- Some internal signals assignments
wrdata_reg <= slave_i.dat;
--
-- Main register bank access process.
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
ack_sreg <= "0000000000";
ack_in_progress <= '0';
rddata_reg <= "00000000000000000000000000000000";
cm_cr_cnt_rst_int <= '0';
cm_cr_presc_int <= "00000000";
cm_cr_refsel_int <= "0000";
cm_refdr_refdr_int <= "00000000000000000000000000000000";
cm_cnt_sel_sel_int <= "0000";
regs_o.cnt_val_valid_load_o <= '0';
elsif rising_edge(clk_sys_i) then
-- advance the ACK generator shift register
ack_sreg(8 downto 0) <= ack_sreg(9 downto 1);
ack_sreg(9) <= '0';
if (ack_in_progress = '1') then
if (ack_sreg(0) = '1') then
cm_cr_cnt_rst_int <= '0';
regs_o.cnt_val_valid_load_o <= '0';
ack_in_progress <= '0';
else
regs_o.cnt_val_valid_load_o <= '0';
end if;
else
if ((slave_i.cyc = '1') and (slave_i.stb = '1')) then
case rwaddr_reg(1 downto 0) is
when "00" =>
if (slave_i.we = '1') then
cm_cr_cnt_rst_int <= wrdata_reg(0);
cm_cr_presc_int <= wrdata_reg(8 downto 1);
cm_cr_refsel_int <= wrdata_reg(12 downto 9);
end if;
rddata_reg(0) <= '0';
rddata_reg(8 downto 1) <= cm_cr_presc_int;
rddata_reg(12 downto 9) <= cm_cr_refsel_int;
rddata_reg(13) <= 'X';
rddata_reg(14) <= 'X';
rddata_reg(15) <= 'X';
rddata_reg(16) <= 'X';
rddata_reg(17) <= 'X';
rddata_reg(18) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X';
rddata_reg(23) <= 'X';
rddata_reg(24) <= 'X';
rddata_reg(25) <= 'X';
rddata_reg(26) <= 'X';
rddata_reg(27) <= 'X';
rddata_reg(28) <= 'X';
rddata_reg(29) <= 'X';
rddata_reg(30) <= 'X';
rddata_reg(31) <= 'X';
ack_sreg(2) <= '1';
ack_in_progress <= '1';
when "01" =>
if (slave_i.we = '1') then
cm_refdr_refdr_int <= wrdata_reg(31 downto 0);
end if;
rddata_reg(31 downto 0) <= cm_refdr_refdr_int;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "10" =>
if (slave_i.we = '1') then
cm_cnt_sel_sel_int <= wrdata_reg(3 downto 0);
end if;
rddata_reg(3 downto 0) <= cm_cnt_sel_sel_int;
rddata_reg(4) <= 'X';
rddata_reg(5) <= 'X';
rddata_reg(6) <= 'X';
rddata_reg(7) <= 'X';
rddata_reg(8) <= 'X';
rddata_reg(9) <= 'X';
rddata_reg(10) <= 'X';
rddata_reg(11) <= 'X';
rddata_reg(12) <= 'X';
rddata_reg(13) <= 'X';
rddata_reg(14) <= 'X';
rddata_reg(15) <= 'X';
rddata_reg(16) <= 'X';
rddata_reg(17) <= 'X';
rddata_reg(18) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X';
rddata_reg(23) <= 'X';
rddata_reg(24) <= 'X';
rddata_reg(25) <= 'X';
rddata_reg(26) <= 'X';
rddata_reg(27) <= 'X';
rddata_reg(28) <= 'X';
rddata_reg(29) <= 'X';
rddata_reg(30) <= 'X';
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "11" =>
if (slave_i.we = '1') then
regs_o.cnt_val_valid_load_o <= '1';
end if;
rddata_reg(30 downto 0) <= regs_i.cnt_val_value_i;
rddata_reg(31) <= regs_i.cnt_val_valid_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when others =>
-- prevent the slave from hanging the bus on invalid address
ack_in_progress <= '1';
ack_sreg(0) <= '1';
end case;
end if;
end if;
end if;
end process;
-- Drive the data output bus
slave_o.dat <= rddata_reg;
-- Reset counters
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
cm_cr_cnt_rst_dly0 <= '0';
regs_o.cr_cnt_rst_o <= '0';
elsif rising_edge(clk_sys_i) then
cm_cr_cnt_rst_dly0 <= cm_cr_cnt_rst_int;
regs_o.cr_cnt_rst_o <= cm_cr_cnt_rst_int and (not cm_cr_cnt_rst_dly0);
end if;
end process;
-- Prescaler
regs_o.cr_presc_o <= cm_cr_presc_int;
-- Reference Select
regs_o.cr_refsel_o <= cm_cr_refsel_int;
-- Reference Division Ratio
regs_o.refdr_refdr_o <= cm_refdr_refdr_int;
-- Counter Select
regs_o.cnt_sel_sel_o <= cm_cnt_sel_sel_int;
-- Counter Value
-- Counter Value Valid/Clear
regs_o.cnt_val_valid_o <= wrdata_reg(31);
rwaddr_reg <= slave_i.adr(3 downto 2);
slave_o.stall <= (not ack_sreg(0)) and (slave_i.stb and slave_i.cyc);
slave_o.err <= '0';
slave_o.rty <= '0';
-- ACK signal generation. Just pass the LSB of ACK counter.
slave_o.ack <= ack_sreg(0);
end syn;
-- -*- Mode: LUA; tab-width: 2 -*-
peripheral {
name = "Clock Frequency Monitor";
hdl_entity = "clock_monitor_wb";
prefix = "cm";
reg {
name = "Control Register";
prefix = "CR";
field {
name = "Reset counters";
description = "write 1: resets the counters\
write 0: no effect";
prefix = "CNT_RST";
type = MONOSTABLE;
};
field {
name = "Prescaler";
prefix = "PRESC";
type = SLV;
size = 8;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Reference Select";
prefix = "REFSEL"; -- 0..n-1: channel n, 14:ext PPS, 15:system clock
type = SLV;
size = 4;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "Reference Divider Register";
prefix = "REFDR";
field {
name = "Reference Division Ratio";
prefix = "REFDR";
type = SLV;
size = 32;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "Counter Select Register";
prefix = "CNT_SEL";
field {
name = "Counter Select";
prefix = "SEL";
type = SLV;
size = 4;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "Counter Value Register";
prefix = "CNT_VAL";
field {
name = "Counter Value";
prefix = "VALUE";
type = SLV;
size = 31;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Counter Value Valid/Clear";
prefix = "VALID";
type = BIT;
size = 1;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
};
};
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for Clock Frequency Monitor
---------------------------------------------------------------------------------------
-- File : clock_monitor_wbgen2_pkg.vhd
-- Author : auto-generated by wbgen2 from clock_monitor_wb.wb
-- Created : Mon Jun 17 18:28:42 2019
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE clock_monitor_wb.wb
-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
---------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
package cm_wbgen2_pkg is
-- Input registers (user design -> WB slave)
type t_cm_in_registers is record
cnt_val_value_i : std_logic_vector(30 downto 0);
cnt_val_valid_i : std_logic;
end record;
constant c_cm_in_registers_init_value: t_cm_in_registers := (
cnt_val_value_i => (others => '0'),
cnt_val_valid_i => '0'
);
-- Output registers (WB slave -> user design)
type t_cm_out_registers is record
cr_cnt_rst_o : std_logic;
cr_presc_o : std_logic_vector(7 downto 0);
cr_refsel_o : std_logic_vector(3 downto 0);
refdr_refdr_o : std_logic_vector(31 downto 0);
cnt_sel_sel_o : std_logic_vector(3 downto 0);
cnt_val_valid_o : std_logic;
cnt_val_valid_load_o : std_logic;
end record;
constant c_cm_out_registers_init_value: t_cm_out_registers := (
cr_cnt_rst_o => '0',
cr_presc_o => (others => '0'),
cr_refsel_o => (others => '0'),
refdr_refdr_o => (others => '0'),
cnt_sel_sel_o => (others => '0'),
cnt_val_valid_o => '0',
cnt_val_valid_load_o => '0'
);
function "or" (left, right: t_cm_in_registers) return t_cm_in_registers;
function f_x_to_zero (x:std_logic) return std_logic;
function f_x_to_zero (x:std_logic_vector) return std_logic_vector;
component clock_monitor_wb is
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
slave_i : in t_wishbone_slave_in;
slave_o : out t_wishbone_slave_out;
int_o : out std_logic;
regs_i : in t_cm_in_registers;
regs_o : out t_cm_out_registers
);
end component;
end package;
package body cm_wbgen2_pkg is
function f_x_to_zero (x:std_logic) return std_logic is
begin
if x = '1' then
return '1';
else
return '0';
end if;
end function;
function f_x_to_zero (x:std_logic_vector) return std_logic_vector is
variable tmp: std_logic_vector(x'length-1 downto 0);
begin
for i in 0 to x'length-1 loop
if(x(i) = 'X' or x(i) = 'U') then
tmp(i):= '0';
else
tmp(i):=x(i);
end if;
end loop;
return tmp;
end function;
function "or" (left, right: t_cm_in_registers) return t_cm_in_registers is
variable tmp: t_cm_in_registers;
begin
tmp.cnt_val_value_i := f_x_to_zero(left.cnt_val_value_i) or f_x_to_zero(right.cnt_val_value_i);
tmp.cnt_val_valid_i := f_x_to_zero(left.cnt_val_valid_i) or f_x_to_zero(right.cnt_val_valid_i);
return tmp;
end function;
end package body;
--------------------------------------------------------------------------------
-- CERN BE-CEM-EDL
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: xwb_clock_monitor
--
-- description: Multichannel clock frequency monitor with Wishbone interface.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020-2021
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.gencores_pkg.all;
use work.wishbone_pkg.all;
use work.cm_wbgen2_pkg.all;
entity xwb_clock_monitor is
generic (
g_NUM_CLOCKS : integer := 1;
g_CLK_SYS_FREQ : integer := 62500000;
g_WITH_INTERNAL_TIMEBASE : boolean := TRUE
);
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
clk_in_i : in std_logic_vector(g_num_clocks-1 downto 0);
pps_p1_i : in std_logic := '0';
slave_i : in t_wishbone_slave_in;
slave_o : out t_wishbone_slave_out
);
end xwb_clock_monitor;
architecture rtl of xwb_clock_monitor is
signal regs_in : t_cm_in_registers;
signal regs_out : t_cm_out_registers;
type t_clock_state is record
presc_cnt : unsigned(4 downto 0);
clk_in : std_logic;
clk_presc : std_logic;
pulse : std_logic;
counter : unsigned(30 downto 0);
valid_sreg : std_logic_vector(1 downto 0);
freq : unsigned(30 downto 0);
ack : std_logic;
end record;
type t_clock_state_array is array (integer range <>) of t_clock_state;
signal clks : t_clock_state_array(0 to g_num_clocks);
signal rst_n_a : std_logic;
signal ref_pulse_p : std_logic;
signal gate_p : std_logic;
signal gate_cnt : unsigned(31 downto 0);
signal pps_p_sysclk : std_logic;
signal cntr_gate : unsigned(30 downto 0) := (others => '0');
signal gate_pulse, gate_pulse_synced : std_logic := '0';
begin
gen_ext_pps : if g_WITH_INTERNAL_TIMEBASE = false generate
U_PPS_Pulse_Detect : gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
data_i => pps_p1_i,
ppulse_o => pps_p_sysclk);
end generate gen_ext_pps;
gen_int_pps : if g_WITH_INTERNAL_TIMEBASE = true generate
p_gate_counter : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
cntr_gate <= (others => '0');
pps_p_sysclk <= '0';
else
if cntr_gate = g_CLK_SYS_FREQ-1 then
cntr_gate <= (others => '0');
pps_p_sysclk <= '1';
else
cntr_gate <= cntr_gate + 1;
pps_p_sysclk <= '0';
end if;
end if;
end if;
end process;
end generate gen_int_pps;
process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' or regs_out.cr_cnt_rst_o = '1' then
gate_cnt <= (others => '0');
gate_p <= '0';
else
ref_pulse_p <= clks(to_integer(unsigned(regs_out.cr_refsel_o))).pulse;
if unsigned(regs_out.cr_refsel_o) /= 15 then
if ref_pulse_p = '1' then
if gate_cnt = unsigned(regs_out.refdr_refdr_o) then
gate_cnt <= (others => '0');
gate_p <= '1';
else
gate_cnt <= gate_cnt + 1;
gate_p <= '0';
end if;
else
gate_p <= '0';
end if;
else
gate_p <= pps_p_sysclk;
end if;
end if;
end if;
end process;
rst_n_a <= rst_n_i;
U_WB_Slave : entity work.clock_monitor_wb
port map (
rst_n_i => rst_n_i,
clk_sys_i => clk_sys_i,
slave_i => slave_i,
slave_o => slave_o,
regs_i => regs_in,
regs_o => regs_out);
clks(g_num_clocks).clk_in <= clk_sys_i;
gen1 : for i in 0 to g_num_clocks-1 generate
clks(i).clk_in <= clk_in_i(i);
end generate gen1;
gen2 : for i in 0 to g_num_clocks generate
p_clk_prescaler : process(clks(i).clk_in, rst_n_a)
begin
if rst_n_a = '0' then
clks(i).presc_cnt <= (others => '0');
clks(i).clk_presc <= '0';
elsif rising_edge(clks(i).clk_in) then
if(clks(i).presc_cnt = unsigned(regs_out.cr_presc_o)) then
clks(i).presc_cnt <= (others => '0');
clks(i).clk_presc <= not clks(i).clk_presc;
else
clks(i).presc_cnt <= clks(i).presc_cnt + 1;
end if;
end if;
end process;
U_Edge_Detect : gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
data_i => clks(i).clk_presc,
ppulse_o => clks(i).pulse);
end generate gen2;
gen3 : for i in 0 to g_num_clocks generate
p_counter : process(clk_sys_i)
variable cnt_idx : integer range 0 to g_num_clocks;
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' or regs_out.cr_cnt_rst_o = '1' then
clks(i).counter <= (others => '0');
clks(i).valid_sreg <= (others => '0');
else
if(gate_p = '1') then
clks(i).valid_sreg <= clks(i).valid_sreg(0) & '1';
clks(i).freq <= clks(i).counter;
clks(i).counter <= (others => '0');
elsif clks(i).pulse = '1' then
clks(i).counter <= clks(i).counter + 1;
end if;
if clks(i).ack = '1' then
clks(i).valid_sreg(1) <= '0';
end if;
cnt_idx := to_integer(unsigned(regs_out.cnt_sel_sel_o));
if (i = cnt_idx) then
clks(i).ack <= regs_out.cnt_val_valid_o and regs_out.cnt_val_valid_load_o;
else
clks(i).ack <= '0';
end if;
end if;
end if;
end process;
end generate gen3;
p_regs : process(clk_sys_i)
variable cnt_idx : integer range 0 to g_num_clocks;
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
regs_in.cnt_val_valid_i <= '0';
else
cnt_idx := to_integer(unsigned(regs_out.cnt_sel_sel_o));
regs_in.cnt_val_value_i <= std_logic_vector(clks(cnt_idx).freq);
regs_in.cnt_val_valid_i <= clks(cnt_idx).valid_sreg(1);
end if;
end if;
end process;
end rtl;
......@@ -6,8 +6,7 @@ if target == "xilinx":
"fine_pulse_gen_kintexultrascale_shared.vhd",
"fine_pulse_gen_kintex7.vhd",
"fine_pulse_gen_kintexultrascale.vhd",
"fine_pulse_gen_wbgen2_pkg.vhd",
"fine_pulse_gen_wb.vhd",
"wb_fpgen_regs.vhd",
"xwb_fine_pulse_gen.vhd"]
else:
logging.info("Library component wb_fine_pulse_gen targets only xilinx devices")
#!/bin/bash
cheby -i wb_fpgen_regs.cheby --gen-hdl wb_fpgen_regs.vhd
cheby -i wb_fpgen_regs.cheby --consts-style sv --gen-consts ../../../sim/regs/wb_fpgen_regs.sv
cheby -i wb_fpgen_regs.cheby --gen-c wb_fpgen_regs.h
cheby -i wb_fpgen_regs.cheby --consts-style h --gen-consts wb_fpgen_regs2.h
This diff is collapsed.
This diff is collapsed.
files = [ "xwb_lm32_mcs.vhd" ];
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment