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;
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_cordic_pkg
--
-- 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;
use ieee.math_real.all;
package gc_cordic_pkg is
subtype t_CORDIC_MODE is std_logic_vector(0 downto 0);
subtype t_CORDIC_SUBMODE is std_logic_vector(1 downto 0);
constant c_ANGLE_FORMAT_S8_7 : integer := 0;
constant c_ANGLE_FORMAT_FULL_SCALE_180 : integer := 1;
constant c_MODE_VECTOR : t_CORDIC_MODE := "0";
constant c_MODE_ROTATE : t_CORDIC_MODE := "1";
constant c_SUBMODE_CIRCULAR : t_CORDIC_SUBMODE := "00";
constant c_SUBMODE_LINEAR : t_CORDIC_SUBMODE := "01";
constant c_SUBMODE_HYPERBOLIC : t_CORDIC_SUBMODE := "11";
-- Used by CORDIC algo and init
-- Constant GHHfFReg : Std_logic_vector(19 downto 1) := X"0000"&"000";
constant c_DegPlus90 : signed(15 downto 0) := X"2D00";
constant c_DegMinus90 : signed(15 downto 0) := X"D300";
constant c_DegPlus180c : signed(15 downto 0) := X"5A00";
constant c_DegMinus180c : signed(15 downto 0) := X"A600";
-- Modulo 360 d constants
constant c_DegPlus90_X : signed(16 downto 0) := '0'&X"2D00"; -- +90 d
constant c_DegMinus90_X : signed(16 downto 0) := '1'&X"D300"; -- -90 d
constant c_DegPlus180 : signed(16 downto 0) := '0'&X"5A00"; -- +180 d
constant c_DegMinus180 : signed(16 downto 0) := '1'&X"A600"; -- -180 d
constant c_DegPlus360 : signed(16 downto 0) := '0'&X"B400"; -- +360 d
constant c_DegMinus360 : signed(16 downto 0) := '1'&X"4C00"; -- -360 d
constant c_DegZero : signed(16 downto 0) := '0'&X"0000"; -- +000 d
-- Angle Constants for FS Angle format
constant c_FSDegPlus90 : signed(15 downto 0) := X"4000";
constant c_FSDegMinus90 : signed(15 downto 0) := X"C000";
constant c_FSDegPlus180c : signed(15 downto 0) := X"7FFF";
constant c_FSDegMinus180c : signed(15 downto 0) := X"8000";
-- Modulo 360 d constants FS Angle format
constant c_FSDegPlus90_X : signed(16 downto 0) := '0'&X"4000"; -- +90 d
constant c_FSDegMinus90_X : signed(16 downto 0) := '1'&X"C000"; -- -90 d
constant c_FSDegPlus180 : signed(16 downto 0) := '0'&X"8000"; -- +180 d
constant c_FSDegMinus180 : signed(16 downto 0) := '1'&X"8000"; -- -180 d
constant c_FSDegPlus360 : signed(16 downto 0) := '0'&X"FFFF"; -- +360 d
constant c_FSDegMinus360 : signed(16 downto 0) := '1'&X"0000"; -- -360 d
constant c_FSDegZero : signed(16 downto 0) := '0'&X"0000"; -- +000 d
--Constants for the generic HD module 360
constant c_DegPlus90HD_X : signed(32 downto 0) := '0'&X"2D000000"; -- +90 d
constant c_DegMinus90HD_X : signed(32 downto 0) := '1'&X"D3000000"; -- -90 d
constant c_DegPlus180HD_X : signed(32 downto 0) := '0'&X"5A000000"; -- +180 d
constant c_DegMinus180HD_X : signed(32 downto 0) := '1'&X"A6000000"; -- -180 d
constant c_DegPlus360HD_X : signed(32 downto 0) := '0'&X"B4000000"; -- +360 d
constant c_DegMinus360HD_X : signed(32 downto 0) := '1'&X"4C000000"; -- -360 d
constant c_DegZeroHD_X : signed(32 downto 0) := '0'&X"00000000"; -- +000 d
--Constants for the HD CorDic implementation
constant c_DegPlus90HD : signed(31 downto 0) := X"2D000000";
constant c_DegMinus90HD : signed(31 downto 0) := X"D3000000";
constant c_DegPlus180HD : signed(31 downto 0) := X"5A000000";
constant c_DegMinus180HD : signed(31 downto 0) := X"A6000000";
constant c_DegZeroHD : signed(31 downto 0) := X"00000000";
--Constants for the generic HD module 360 FS Angle Format
constant c_FSDegPlus90HD_X : signed(32 downto 0) := '0'&X"40000000"; -- +90 d
constant c_FSDegMinus90HD_X : signed(32 downto 0) := '1'&X"C0000000"; -- -90 d
constant c_FSDegPlus180HD_X : signed(32 downto 0) := '0'&X"80000000"; -- +180 d
constant c_FSDegMinus180HD_X : signed(32 downto 0) := '1'&X"80000000"; -- -180 d
constant c_FSDegPlus360HD_X : signed(32 downto 0) := '0'&X"ffffffff"; -- +360 d
constant c_FSDegMinus360HD_X : signed(32 downto 0) := '1'&X"00000000"; -- -360 d
constant c_FSDegZeroHD_X : signed(32 downto 0) := '0'&X"00000000"; -- +000 d
--Constants for the HD CorDic implementation FS Angle Format
constant c_FSDegPlus90HD : signed(31 downto 0) := X"40000000";
constant c_FSDegMinus90HD : signed(31 downto 0) := X"C0000000";
constant c_FSDegPlus180HD : signed(31 downto 0) := X"7fffffff";
constant c_FSDegMinus180HD : signed(31 downto 0) := X"80000000";
constant c_FSDegZeroHD : signed(31 downto 0) := X"00000000";
function f_compute_an(nbits : integer) return std_logic_vector;
-- Cordic Sequencer Iteration Constants
constant c_CirIter : std_logic_vector(4 downto 0) := '0'&X"D";
constant c_LinIter : std_logic_vector(4 downto 0) := '0'&X"F";
-- Cordic Sequencer Iteration Constants for FS Angle format
constant c_FSCirIter : std_logic_vector(4 downto 0) := '0'&X"F";
-- Unity Vector Length (0x7FFF) divided by An (=1.647)
-- This constant can be used to initialize X0 prior to a rotation by Z0
-- By initializing Y0 to 0x0000 we obtain Xn = cos(Z0) and Yn = sin(Z0)
-- (Xn,Yn) being a unit vector with angle Z0.
constant c_UnByAn : std_logic_vector(15 downto 0) := X"4DB7"; --!! We may change this to 4DBA after verifications.
--AnHD = 1.6467602581210656483661780066297
--CorDicHD
constant c_UnByAnHD : std_logic_vector(31 downto 0) := X"4DBA76D4";
procedure f_limit_subtract
(use_limiter : boolean;
a, b : in signed;
o : out signed;
lim : out std_logic);
procedure f_limit_add
(use_limiter : boolean;
a, b : in signed;
o : out signed;
lim : out std_logic);
function f_limit_negate(
use_limiter : boolean;
x : in signed;
neg : in std_logic) return signed;
function f_phi_lookup (
stage : integer;
submode : t_CORDIC_SUBMODE;
angle_format : integer
)
return signed;
function f_pick (cond : boolean;
if_true : signed;
if_false : signed) return signed;
end package;
package body gc_cordic_pkg is
function f_compute_an(nbits : integer) return std_logic_vector is
variable v_an : real := 1.0;
variable v_ret : std_logic_vector(nbits-1 downto 0);
begin
for i in 0 to nbits-1 loop
v_an := v_an * sqrt(1.0+2.0**(-2*i));
end loop;
v_ret := std_logic_vector(to_signed(integer((1.0/v_an)*(2.0**(nbits-1))), nbits));
return v_ret;
end function f_compute_an;
procedure f_limit_subtract
(use_limiter : boolean;
a, b : in signed;
o : out signed;
lim : out std_logic) is
constant c_max_val : signed(o'range) := ('0', others => '1');
constant c_min_val : signed(o'range) := ('1', others => '0');
variable l_sum : signed(O'length downto 0) := (others => '0');
begin
l_sum := a(a'left)&a - b;
if not use_limiter then
o := l_sum(o'range);
lim := '0';
-- value above maximum
elsif l_sum(o'length) = '0' and l_sum(o'length-1) = '1' then
o := c_max_val;
lim := '1';
-- value below minimum
elsif l_sum(o'length) = '1' and l_sum(o'length-1) = '0' then
o := c_min_val;
lim := '1';
else
o := l_sum(o'range);
lim := '0';
end if;
end procedure;
procedure f_limit_add
(
use_limiter : boolean;
a, b : in signed;
o : out signed;
lim : out std_logic) is
constant c_max_val : signed(o'range) := ('0', others => '1');
constant c_min_val : signed(o'range) := ('1', others => '0');
variable l_sum : signed(o'length downto 0) := (others => '0');
begin
l_sum := a(a'left)&a + b;
if not use_limiter then
o := l_sum(o'range);
lim := '0';
-- value above maximum
elsif l_sum(o'length) = '0' and l_sum(o'length-1) = '1' then
o := c_max_val;
lim := '1';
-- value below minimum
elsif l_sum(o'length) = '1' and l_sum(o'length-1) = '0' then
o := c_min_val;
lim := '1';
else
o := l_sum(o'range);
lim := '0';
end if;
end procedure;
function f_limit_negate(
use_limiter : boolean;
x : in signed;
neg : in std_logic) return signed is
constant c_max_val : signed(x'range) := ('0', others => '1');
constant c_min_val : signed(x'range) := ('1', others => '0');
begin
if neg = '1' then
if x = c_min_val and use_limiter then
return c_max_val;
else
return not x(x'length-1 downto 0)+1;
end if;
else
return x;
end if;
end f_limit_negate;
function f_phi_lookup (
stage : integer;
submode : t_CORDIC_SUBMODE;
angle_format : integer
) return signed is
type t_LUT is array(integer range<>) of signed(31 downto 0);
constant c_LUT_LIN : t_LUT(0 to 31) := (
X"7fffffff",
X"40000000",
X"20000000",
X"10000000",
X"08000000",
X"04000000",
X"02000000",
X"01000000",
X"00800000",
X"00400000",
X"00200000",
X"00100000",
X"00080000",
X"00040000",
X"00020000",
X"00010000",
X"00008000",
X"00004000",
X"00002000",
X"00001000",
X"00000800",
X"00000400",
X"00000200",
X"00000100",
X"00000080",
X"00000040",
X"00000020",
X"00000010",
X"00000008",
X"00000004",
X"00000002",
X"00000001"
);
constant c_LUT_CIRC_A0 : t_LUT(0 to 31) := (
X"16800000",
X"0D485398",
X"0704A3A0",
X"03900089",
X"01C9C553",
X"00E51BCA",
X"0072950D",
X"00394B6B",
X"001CA5D2",
X"000E52EC",
X"00072976",
X"000394BB",
X"0001CA5D",
X"0000E52E",
X"00007297",
X"0000394B",
X"00001CA5",
X"00000E52",
X"00000729",
X"00000394",
X"000001CA",
X"000000E5",
X"00000072",
X"00000039",
X"0000001C",
X"0000000E",
X"00000007",
X"00000003",
X"00000001",
X"00000000",
X"00000000",
X"00000000"
);
constant c_LUT_CIRC_A1 : t_LUT(0 to 31) := (
X"20000000",
X"12E4051E",
X"09FB385B",
X"051111D4",
X"028B0D43",
X"0145D7E1",
X"00A2F61E",
X"00517C55",
X"0028BE53",
X"00145F2F",
X"000A2F98",
X"000517CC",
X"00028BE6",
X"000145F3",
X"0000A2FA",
X"0000517D",
X"000028BE",
X"0000145F",
X"00000A30",
X"00000518",
X"0000028C",
X"00000146",
X"000000A3",
X"00000051",
X"00000029",
X"00000014",
X"0000000A",
X"00000005",
X"00000003",
X"00000001",
X"00000001",
X"00000000"
);
begin
if submode = c_SUBMODE_CIRCULAR then
if angle_format = c_ANGLE_FORMAT_S8_7 then
return c_LUT_CIRC_A0(stage);
else
return c_LUT_CIRC_A1(stage);
end if;
else
return c_LUT_LIN(stage);
end if;
end f_phi_lookup;
function f_pick (cond : boolean;
if_true : signed;
if_false : signed)return signed is
begin
if cond then
return if_true;
else
return if_false;
end if;
end f_pick;
end package body;
--------------------------------------------------------------------------------
-- CERN SY-RF-FB
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_cordic_top
--
-- authors: Nathan Pittet (nathan.pittet@solidwatts.ch) based on the work of
-- Gregoire Hagmann <gregoire.hagmann@cern.ch> and
-- John Molendijk (CERN)
--
-- description: Pipelined cordic. This implementation aims at removing the few
-- small quirks from the previous one:
-- - 32 bits limitation being one,
-- - non-propagation of the cor_submode and cor_mode signals
-- - only half of the full scale being available
-- - Removing the absolutely useless g_ANGLE_FORMAT = s8.7
-- - Proper behaviour upon reset
--
-- Data is available after g_ITERATIONS+1 clk periods at the output.
--
--
-- functionnality and limitations
-- in the following assume K ~= 1.6467
-- in the following assume FS = 2**(g_WIDTH-1)-1
--
-- rotate / circular
-- inputs limitations :
-- - sqrt(x*x + y*y) < FS/K
-- - -FS < z < +FS
-- outputs :
-- - x_o = K*FS*(x*cos(z)-y*sin(z)) (-FS <= x_o <= +FS)
-- - y_o = K*FS*(y*cos(z)+y*sin(z)) (-FS <= x_o <= +FS)
-- - z_o = 0
--
-- vector / circular
-- inputs limitations
-- - avoid small x and y values because the error grows quite large
-- - sqrt(x*x + y*y) < FS/K
-- - -FS < z < +FS
-- outputs
-- - x_o = K*sqrt(x*x+y*y) (0 <= x_o <= +FS)
-- - y_o = 0
-- - z_o = z + atan(y/x) (-FS <= z_o <= +FS)
--
-- rotate / linear
-- inputs limitations
-- - don't use this mode. not reliable. overflows happen in the
-- computation using python, no way around it.
-- outputs:
-- - x_o = x
-- - y_o = y + x*z/FS (-FS <= y_o <= +FS)
-- - z_o = 0
--
-- vector / linear
-- input limitations
-- - avoid small x and y (< 10% FS) because the error will grow large
-- - avoid x close to 0 obviously
-- - abs(z) < (1 - y/x)*FS so that the block does not overflows
-- x_o = x
-- y_o = 0
-- z_o = z + y/x*FS (-FS <= z_o <= +FS)
--
-- rotate / hyperbolic
-- untested
-- vector / hyperbolic
-- untested
--
--
--------------------------------------------------------------------------------
-- 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 ieee.math_real.all;
use work.gc_cordic_pkg.all;
entity gc_cordic_top is
generic
(
-- Word-width
g_WIDTH : integer := 16;
-- Number of pipeline stages
g_ITERATIONS : integer := 16
);
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.
mode_i : in t_CORDIC_MODE;
submode_i : in t_CORDIC_SUBMODE;
x_i : in std_logic_vector(g_WIDTH-1 downto 0);
y_i : in std_logic_vector(g_WIDTH-1 downto 0);
z_i : in std_logic_vector(g_WIDTH-1 downto 0);
valid_i : in std_logic;
lim_x_o : out std_logic; -- '1' when saturation happened. You may not want to
lim_y_o : out std_logic; -- trust the result in this case.
x_o : out std_logic_vector(g_WIDTH-1 downto 0);
y_o : out std_logic_vector(g_WIDTH-1 downto 0);
z_o : out std_logic_vector(g_WIDTH-1 downto 0);
valid_o : out std_logic;
mode_o : out t_CORDIC_MODE;
submode_o : out t_CORDIC_SUBMODE
);
end entity gc_cordic_top;
architecture rtl of gc_cordic_top is
type t_CORDIC_STV is record
x : signed(g_WIDTH-1 downto 0);
y : signed(g_WIDTH-1 downto 0);
z : signed(g_WIDTH-1 downto 0);
valid : std_logic;
lim_x : std_logic;
lim_y : std_logic;
mode : t_CORDIC_MODE;
submode : t_CORDIC_SUBMODE;
end record;
constant c_CORDIC_DEFAULT : t_CORDIC_STV := (x => (others => '0'),
y => (others => '0'),
z => (others => '0'),
valid => '0',
lim_x => '0',
lim_y => '0',
mode => c_MODE_ROTATE,
submode => c_SUBMODE_CIRCULAR);
type t_CORDIC_ARRAY is array(natural range <>) of t_CORDIC_STV;
signal s_cordic_init : t_CORDIC_STV;
signal s_stg : t_CORDIC_ARRAY(0 to g_ITERATIONS) := (others => c_CORDIC_DEFAULT);
signal s_di : std_logic_vector(g_ITERATIONS-1 downto 0) := (others => '0');
constant c_FS : real := 2.0**(g_WIDTH-1)-1.0;
function f_shift(inp : signed; i : integer) return signed is
variable v_ret : signed(inp'range);
begin
if i >= inp'left then
v_ret := (others => '0');
else
v_ret := resize(inp(inp'length-1 downto i), inp'length);
end if;
return v_ret;
end function f_shift;
begin
s_cordic_init <= (x => signed(x_i), y => signed(y_i), z => signed(z_i),
valid => valid_i, lim_x =>'0', lim_y => '0',
mode => mode_i, submode => submode_i);
-- Unfortunately necessary init process:
-- the cordic algorithm solves an arctangeant, therefore it is required
-- to
p_cordic_init : process(clk_i)
constant c_FS_P90D : signed(g_WIDTH-1 downto 0) := to_signed(2**(g_WIDTH-2)-1, g_WIDTH);
begin
if rising_edge(clk_i) then
if rst_i = '1' then
s_stg(0) <= c_CORDIC_DEFAULT;
else
if s_cordic_init.mode = c_MODE_ROTATE and s_cordic_init.submode = c_SUBMODE_CIRCULAR then
-- z < fs/2 and z > -fs/2 (equivalent to ]-90; 90[ )
if s_cordic_init.z(g_WIDTH-1 downto g_WIDTH-2) = "00" or s_cordic_init.z(g_WIDTH-1 downto g_WIDTH-2) = "11"then
s_stg(0) <= s_cordic_init;
-- z > fs/2
elsif s_cordic_init.z(g_WIDTH-1 downto g_WIDTH-2) = "01" then
s_stg(0) <= s_cordic_init;
s_stg(0).x <= -s_cordic_init.y;
s_stg(0).y <= s_cordic_init.x;
s_stg(0).z <= s_cordic_init.z - c_FS_P90D;
-- z < fs/2
elsif s_cordic_init.z(g_WIDTH-1 downto g_WIDTH-2) = "10" then
s_stg(0) <= s_cordic_init;
s_stg(0).x <= s_cordic_init.y;
s_stg(0).y <= -s_cordic_init.x;
s_stg(0).z <= s_cordic_init.z + c_FS_P90D;
end if;
elsif s_cordic_init.mode = c_MODE_VECTOR and s_cordic_init.submode = c_SUBMODE_CIRCULAR then
-- x > 0
if s_cordic_init.x(g_WIDTH-1) = '0' then
s_stg(0) <= s_cordic_init;
else
-- x < 0 and y > 0
if s_cordic_init.y(g_WIDTH-1) = '0' then
s_stg(0) <= s_cordic_init;
s_stg(0).x <= s_cordic_init.y;
s_stg(0).y <= -s_cordic_init.x;
s_stg(0).z <= s_cordic_init.z + c_FS_P90D;
-- x < 0 and y < 0
else
s_stg(0) <= s_cordic_init;
s_stg(0).x <= -s_cordic_init.y;
s_stg(0).y <= s_cordic_init.x;
s_stg(0).z <= s_cordic_init.z - c_FS_P90D;
end if;
end if;
else
s_stg(0) <= s_cordic_init;
end if;
end if;
end if;
end process p_cordic_init;
gen_iterations : for i in 0 to g_ITERATIONS-2 generate
p_iter : process(clk_i)
constant c_ALPHA_CIRCULAR : signed(g_WIDTH-1 downto 0) := to_signed(integer(arctan(1.0/(2.0**(i)))*c_FS/MATH_PI), g_WIDTH);
constant c_ALPHA_LINEAR : signed(g_WIDTH-1 downto 0) := to_signed(integer((1.0/(2.0**i)*c_FS)), g_WIDTH);
constant c_ALPHA_HYPERBOLIC : signed(g_WIDTH-1 downto 0) := to_signed(integer(arctanh(1.0/(2.0**i))*c_FS), g_WIDTH);
variable v_alpha : signed(g_WIDTH-1 downto 0);
variable v_negate : std_logic; --inverts when '1', equivalent to di=-1
variable v_x_shifted : signed(g_WIDTH-1 downto 0);
variable v_y_shifted : signed(g_WIDTH-1 downto 0);
variable v_x, v_y : signed(g_WIDTH-1 downto 0);
variable v_z : signed(g_WIDTH-1 downto 0);
variable v_lim_x, v_lim_y, v_lim_z : std_logic;
begin
if rising_edge(clk_i) then
if rst_i = '1' then
s_stg(i+1) <= c_CORDIC_DEFAULT;
s_di(i) <= '0';
else
case s_stg(i).mode is
when c_MODE_ROTATE =>
-- di = sign(z) = not z'left. add when z is >= 0, else substract
v_negate := s_stg(i).z(s_stg(i).z'left);
when c_MODE_VECTOR =>
-- di = -sign(x*y) => + when (+.+) and (-.-), - when (+.-) and (-.+) -> xor
v_negate := not (s_stg(i).x(g_WIDTH-1) xor s_stg(i).y(g_WIDTH-1));
when others =>
report "Wrong mode" severity error;
v_negate := '0';
end case;
case s_stg(i).submode is
when c_SUBMODE_CIRCULAR =>
-- Using f_limit_negate to invert the number depending on v_negate (di)
v_alpha := f_limit_negate(true, c_ALPHA_CIRCULAR, v_negate);
v_y_shifted := f_limit_negate(true, f_shift(s_stg(i).y, i), v_negate);
when c_SUBMODE_LINEAR =>
v_alpha := f_limit_negate(true, c_ALPHA_LINEAR, v_negate);
v_y_shifted := (others => '0');
when c_SUBMODE_HYPERBOLIC =>
v_alpha := f_limit_negate(true, c_ALPHA_HYPERBOLIC, v_negate);
v_y_shifted := f_limit_negate(true, f_shift(s_stg(i).y, i), v_negate);
when others =>
report "Wrong submode" severity error;
end case;
v_x_shifted := f_limit_negate(true, f_shift(s_stg(i).x, i), v_negate);
s_di(i) <= v_negate;
-- we always want to limit substract on x and y
f_limit_subtract(true, s_stg(i).x, v_y_shifted, v_x, v_lim_x);
f_limit_add (true, s_stg(i).y, v_x_shifted, v_y, v_lim_y);
-- On vector/circular, the output z is an angle. We want it to freely overflow, because [-FS:+FS] -> [-180°:+180°]
f_limit_subtract(s_stg(i).mode /= c_MODE_VECTOR and s_stg(i).submode /= c_SUBMODE_CIRCULAR, s_stg(i).z, v_alpha, v_z, v_lim_z);
s_stg(i+1).valid <= s_stg(i).valid;
s_stg(i+1).x <= v_x;
s_stg(i+1).y <= v_y;
s_stg(i+1).z <= v_z;
s_stg(i+1).lim_x <= v_lim_x;
s_stg(i+1).lim_y <= v_lim_y;
s_stg(i+1).mode <= s_stg(i).mode;
s_stg(i+1).submode <= s_stg(i).submode;
end if;
end if;
end process p_iter;
end generate gen_iterations;
x_o <= std_logic_vector(s_stg(g_ITERATIONS-1).x);
y_o <= std_logic_vector(s_stg(g_ITERATIONS-1).y);
z_o <= std_logic_vector(s_stg(g_ITERATIONS-1).z);
lim_x_o <= s_stg(g_ITERATIONS-1).lim_x;
lim_y_o <= s_stg(g_ITERATIONS-1).lim_y;
mode_o <= s_stg(g_ITERATIONS-1).mode;
submode_o <= s_stg(g_ITERATIONS-1).submode;
valid_o <= s_stg(g_ITERATIONS-1).valid;
end architecture rtl;
\ No newline at end of file
--------------------------------------------------------------------------------
-- 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,
......
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: generic_async_fifo
--
-- description: Parametrizable asynchronous FIFO (Generic version).
-- Dual-clock asynchronous FIFO.
-- - configurable ports width and size
--
-- In case of different width, the fifo will unpack in little-endian mode
-- (so if the read port is smaller than the write port, the first output
-- will be the least significant bits of the first input).
-- The fifo will pack in little-endian mode (so if the read port is larger
-- than the write port, the first input will appear on the least significant
-- bits of the first output).
--
-- TODO: synchronous reset: add new ports (unused reset will be optimized)
-- TODO: same clock: add a generic to simplify the design.
--------------------------------------------------------------------------------
-- Copyright CERN 2011-2023
--------------------------------------------------------------------------------
-- 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;
entity generic_async_fifo_mixedw is
generic (
-- Width of the write port. The ratio between the rd and wr port
-- width must be a power of two.
g_wr_width : natural;
-- Width of the read port.
g_rd_width : natural;
-- Number of entries (whose width is the max between rd and wr ports)
g_size : natural;
-- If true, the rd port outputs the current valid data (if the fifo is
-- not empty), and rd_i acts as acknowledge.
-- If false, rd_i acts as a request.
g_show_ahead : boolean := false;
g_memory_implementation_hint : string := "auto"
);
port (
-- Asynchronous reset
rst_n_a_i : in std_logic := '1';
-- write port
clk_wr_i : in std_logic;
d_i : in std_logic_vector(g_wr_width-1 downto 0);
we_i : in std_logic;
wr_full_o : out std_logic;
wr_count_o : out std_logic_vector(f_log2_size(g_size * ((g_rd_width + g_wr_width - 1) / g_wr_width)) downto 0);
-- read port
clk_rd_i : in std_logic;
q_o : out std_logic_vector(g_rd_width-1 downto 0);
rd_i : in std_logic;
rd_empty_o : out std_logic;
rd_count_o : out std_logic_vector(f_log2_size(g_size * ((g_rd_width + g_wr_width - 1) / g_rd_width)) downto 0)
);
end generic_async_fifo_mixedw;
architecture syn of generic_async_fifo_mixedw is
-- Extra number of bits in counters due to the width difference.
-- The largest port has 0 extra bits.
constant c_extra_rd_width_bits : natural := f_log2((g_rd_width + g_wr_width - 1) / g_rd_width);
constant c_extra_wr_width_bits : natural := f_log2((g_rd_width + g_wr_width - 1) / g_wr_width);
-- We use one more bit to be able to differentiate between an empty FIFO
-- (where rcb = wcb) and a full FIFO (where rcb = wcb except from the most
-- significant extra bit).
-- This extra bit is not used of course for actual addressing of the memory.
constant c_rd_counter_bits : integer := f_log2_size(g_size) + c_extra_rd_width_bits + 1;
constant c_wr_counter_bits : integer := f_log2_size(g_size) + c_extra_wr_width_bits + 1;
subtype t_rd_counter is std_logic_vector(c_rd_counter_bits-1 downto 0);
subtype t_wr_counter is std_logic_vector(c_wr_counter_bits-1 downto 0);
-- bin: binary counter
-- bin_inc: bin + 1
-- n_bin: combinatorial next value of bin (either bin or bin_inc)
-- bin_x: cross-clock domain version of bin
-- gray: gray code of bin
-- gray_inc: gray code of bin_inc
-- n_gray: combinatorial next value of gray (either gray or gray_inc)
-- gray_x: gray code of bin_x
--
-- We use gray codes for safe cross-clock domain crossing of counters. Thus,
-- a binary counter is converted to gray before crossing, and then it is
-- converted back to binary after crossing.
type t_rd_counter_block is record
bin, bin_inc, n_bin : t_rd_counter;
gray, gray_inc, n_gray : t_rd_counter;
bin_x, gray_x : t_rd_counter;
end record;
type t_wr_counter_block is record
bin, bin_inc, n_bin : t_wr_counter;
gray, gray_inc, n_gray : t_wr_counter;
bin_x, gray_x : t_wr_counter;
end record;
constant c_max_width : natural := f_max(g_rd_width, g_wr_width);
-- The internal memory
type t_mem_type is array (0 to g_size-1) of std_logic_vector(c_max_width-1 downto 0);
signal mem : t_mem_type := (others => (others => '0'));
attribute ram_type : string;
attribute ram_type of mem : signal is g_memory_implementation_hint;
signal rcb : t_rd_counter_block;
signal wcb : t_wr_counter_block;
signal full_int, empty_int : std_logic;
signal rd_count : std_logic_vector(c_rd_counter_bits + c_extra_wr_width_bits - 1 downto 0);
signal wr_count : std_logic_vector(c_wr_counter_bits + c_extra_rd_width_bits - 1 downto 0);
signal rd_int, we_int : std_logic;
signal q_int : std_logic_vector(c_max_width-1 downto 0);
signal buf_in : std_logic_vector(c_max_width - 1 downto 0);
signal rd_addr : unsigned(rcb.bin_inc'LEFT-1 downto 0);
begin
-- Protect against overflow and underflow.
rd_int <= rd_i and not empty_int;
we_int <= we_i and not full_int;
buf_in (c_max_width - 1 downto c_max_width - g_wr_width) <= d_i;
p_mem_write : process(clk_wr_i)
begin
if rising_edge(clk_wr_i) then
if we_int = '1' then
mem(to_integer(unsigned(wcb.bin(wcb.bin'LEFT-1 downto c_extra_wr_width_bits)))) <= buf_in;
end if;
end if;
end process p_mem_write;
g_write_buf_in: if c_extra_wr_width_bits > 0 generate
process (clk_wr_i)
begin
if rising_edge(clk_wr_i) and we_int = '1' then
buf_in(c_max_width - g_wr_width - 1 downto 0) <= buf_in(c_max_width - 1 downto g_wr_width);
end if;
end process;
end generate;
p_read_addr: process (rd_int, rcb)
begin
-- 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.
rd_addr <= unsigned(rcb.bin_inc(rcb.bin_inc'LEFT-1 downto 0));
elsif(rd_int = '1' or g_show_ahead) then
-- Read the current entry.
rd_addr <= unsigned(rcb.bin(rcb.bin'LEFT-1 downto 0));
end if;
end process;
p_mem_read : process(clk_rd_i)
begin
if rising_edge(clk_rd_i) then
q_int <= mem(to_integer(rd_addr(rd_addr'left downto c_extra_rd_width_bits)));
end if;
end process p_mem_read;
g_rd_sel: if c_extra_rd_width_bits > 0 generate
signal rd_sel_in, rd_sel : natural range 0 to 2**c_extra_rd_width_bits-1;
begin
rd_sel_in <= to_integer(unsigned(rcb.bin (c_extra_rd_width_bits - 1 downto 0)));
process(clk_rd_i, rd_sel_in)
begin
if g_show_ahead or rising_edge(clk_rd_i) then
rd_sel <= rd_sel_in;
end if;
end process;
q_o <= q_int(rd_sel * g_rd_width + g_rd_width - 1 downto rd_sel * g_rd_width);
end generate;
g_no_rd_sel: if c_extra_rd_width_bits = 0 generate
q_o <= q_int;
end generate;
wcb.bin_inc <= std_logic_vector(unsigned(wcb.bin) + 1);
wcb.gray_inc <= f_gray_encode(wcb.bin_inc);
wcb.n_bin <= wcb.bin_inc when we_int = '1' else wcb.bin;
wcb.n_gray <= wcb.gray_inc when we_int = '1' else wcb.gray;
p_write_ptr : process(clk_wr_i, rst_n_a_i)
begin
if rst_n_a_i = '0' then
wcb.bin <= (others => '0');
wcb.gray <= (others => '0');
elsif rising_edge(clk_wr_i) then
wcb.bin <= wcb.n_bin;
wcb.gray <= wcb.n_gray;
end if;
end process p_write_ptr;
rcb.bin_inc <= std_logic_vector(unsigned(rcb.bin) + 1);
rcb.gray_inc <= f_gray_encode(rcb.bin_inc);
rcb.n_bin <= rcb.bin_inc when rd_int = '1' else rcb.bin;
rcb.n_gray <= rcb.gray_inc when rd_int = '1' else rcb.gray;
p_read_ptr : process(clk_rd_i, rst_n_a_i)
begin
if rst_n_a_i = '0' then
rcb.bin <= (others => '0');
rcb.gray <= (others => '0');
elsif rising_edge(clk_rd_i) then
rcb.bin <= rcb.n_bin;
rcb.gray <= rcb.n_gray;
end if;
end process p_read_ptr;
U_Sync1 : gc_sync_register
generic map (
g_width => c_rd_counter_bits)
port map (
clk_i => clk_wr_i,
rst_n_a_i => rst_n_a_i,
d_i => rcb.gray,
q_o => rcb.gray_x);
U_Sync2 : gc_sync_register
generic map (
g_width => c_wr_counter_bits)
port map (
clk_i => clk_rd_i,
rst_n_a_i => rst_n_a_i,
d_i => wcb.gray,
q_o => wcb.gray_x);
wcb.bin_x <= f_gray_decode(wcb.gray_x, 1);
rcb.bin_x <= f_gray_decode(rcb.gray_x, 1);
p_gen_empty : process(clk_rd_i, rst_n_a_i)
begin
if rst_n_a_i = '0' then
empty_int <= '1';
elsif rising_edge (clk_rd_i) then
if wcb.gray_x(wcb.gray_x'left downto c_extra_wr_width_bits) = rcb.n_gray(rcb.n_gray'left downto c_extra_rd_width_bits) then
empty_int <= '1';
else
empty_int <= '0';
end if;
end if;
end process p_gen_empty;
rd_empty_o <= empty_int;
p_register_full : process(clk_wr_i, rst_n_a_i)
begin
if rst_n_a_i = '0' then
full_int <= '0';
elsif rising_edge (clk_wr_i) then
if wcb.n_bin (wcb.bin'LEFT-1 downto c_extra_wr_width_bits) = rcb.bin_x(rcb.bin_x'LEFT-1 downto c_extra_rd_width_bits)
and wcb.n_bin(wcb.bin'LEFT) /= rcb.bin_x(rcb.bin_x'LEFT)
then
full_int <= '1';
else
full_int <= '0';
end if;
end if;
end process p_register_full;
wr_full_o <= full_int;
p_wr_count : process(clk_wr_i, rst_n_a_i)
begin
if rst_n_a_i = '0' then
wr_count <= (others => '0');
elsif rising_edge(clk_wr_i) then
wr_count <= std_logic_vector((unsigned(wcb.n_bin) & (c_extra_rd_width_bits - 1 downto 0 => '0'))
- (unsigned(rcb.bin_x) & (c_extra_wr_width_bits - 1 downto 0 => '0')));
end if;
end process;
p_rd_count : process(clk_rd_i, rst_n_a_i)
begin
if rst_n_a_i = '0' then
rd_count <= (others => '0');
elsif rising_edge(clk_rd_i) then
rd_count <= std_logic_vector((unsigned(wcb.bin_x) & (c_extra_rd_width_bits - 1 downto 0 => '0'))
- (unsigned(rcb.bin) & (c_extra_wr_width_bits - 1 downto 0 => '0')));
end if;
end process;
wr_count_o <= wr_count(wr_count'left downto c_extra_rd_width_bits);
rd_count_o <= rd_count(rd_count'left downto c_extra_wr_width_bits);
end syn;
......@@ -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")
......@@ -20,15 +20,16 @@ entity fine_pulse_gen_kintex7 is
clk_serdes_i : in std_logic;
rst_serdes_i : in std_logic;
rst_sys_n_i : in std_logic;
cont_i : in std_logic;
rst_par_n_i : in std_logic;
cont_i : in std_logic;
pol_i : in std_logic;
coarse_i : in std_logic_vector(7 downto 0);
coarse_i : in std_logic_vector(3 downto 0);
trig_p_i : in std_logic;
length_i : in std_logic_vector(23 downto 0);
pulse_o : out std_logic;
pulse_o : out std_logic;
ready_o : out std_logic;
dly_load_i : in std_logic;
dly_fine_i : in std_logic_vector(4 downto 0)
......@@ -43,7 +44,6 @@ architecture rtl of fine_pulse_gen_kintex7 is
signal dout_predelay, dout_prebuf, dout_nodelay : std_logic;
signal odelay_load : std_logic;
signal rst : std_logic;
signal odelay_ntaps : std_logic_vector(4 downto 0);
......@@ -55,75 +55,156 @@ architecture rtl of fine_pulse_gen_kintex7 is
-- end f_gen_bitmask;
signal mask : std_logic_vector(15 downto 0);
signal flip : std_logic;
signal dly_load_d : std_logic;
begin
signal mask_start : std_logic_vector(15 downto 0);
signal mask_end : std_logic_vector(15 downto 0);
signal dly_load_d : std_logic;
signal length_d : unsigned(23 downto 0);
signal pulse_pending : std_logic;
rst <= not rst_sys_n_i;
attribute mark_debug : string;
attribute mark_debug of pol_i : signal is "TRUE";
attribute mark_debug of coarse_i : signal is "TRUE";
attribute mark_debug of trig_p_i : signal is "TRUE";
attribute mark_debug of dly_load_i : signal is "TRUE";
attribute mark_debug of dly_fine_i : signal is "TRUE";
attribute mark_debug of odelay_ntaps : signal is "TRUE";
type t_state is (IDLE, CONT_H, CONT_L, START_PULSE_H, START_PULSE_L, MID_PULSE_H, MID_PULSE_L, END_PULSE_H, END_PULSE_L);
signal state : t_state;
begin
process(clk_par_i)
variable rv : std_logic_vector(15 downto 0);
process(clk_par_i, rst_par_n_i)
variable rv, rv2 : std_logic_vector(15 downto 0);
begin
if rising_edge(clk_par_i) then
if rst_par_n_i = '0' then
pulse_pending <= '0';
--dly_load_d <= '0';
ready_o <= '0';
elsif rising_edge(clk_par_i) then
dly_load_d <= dly_load_i;
if dly_load_i = '1' then
odelay_ntaps <= dly_fine_i;
length_d <= unsigned(length_i);
if cont_i = '1' then
case coarse_i is
when x"00" =>
when x"0" =>
rv := "1111000011110000";
when x"01" =>
when x"1" =>
rv := "0111100001111000";
when x"02" =>
when x"2" =>
rv := "0011110000111100";
when x"03" =>
when x"3" =>
rv := "0001111000011110";
when x"04" =>
when x"4" =>
rv := "0000111100001111";
when x"05" =>
when x"5" =>
rv := "1000011110000111";
when x"06" =>
when x"6" =>
rv := "1100001111000011";
when x"07" =>
when x"7" =>
rv := "1110000111100001";
when others =>
rv := (others => '0');
end case;
if pol_i = '1' then
mask_start <= not rv;
mask_end <= not rv;
else
mask_start <= rv;
mask_end <= rv;
end if;
else
case coarse_i is
when x"00" =>
rv := "1111000000000000";
when x"01" =>
rv := "0111100000000000";
when x"02" =>
rv := "0011110000000000";
when x"03" =>
rv := "0001111000000000";
when x"04" =>
rv := "0000111100000000";
when x"05" =>
rv := "0000011110000000";
when x"06" =>
rv := "0000001111000000";
when x"07" =>
rv := "0000000111100000";
when others =>
rv := (others => '0');
end case;
end if;
if pol_i = '0' then
mask <= rv;
else
mask <= not rv;
if unsigned(length_i) = 0 then
case coarse_i is
when x"0" =>
rv := "1111000000000000";
when x"1" =>
rv := "0111100000000000";
when x"2" =>
rv := "0011110000000000";
when x"3" =>
rv := "0001111000000000";
when x"4" =>
rv := "0000111100000000";
when x"5" =>
rv := "0000011110000000";
when x"6" =>
rv := "0000001111000000";
when x"7" =>
rv := "0000000111100000";
when others =>
rv := (others => '0');
end case;
if pol_i = '1' then
mask_start <= not rv;
mask_end <= not rv;
else
mask_start <= rv;
mask_end <= rv;
end if;
else
case coarse_i is
when x"0" =>
rv := "1111111111111111";
when x"1" =>
rv := "0111111111111111";
when x"2" =>
rv := "0011111111111111";
when x"3" =>
rv := "0001111111111111";
when x"4" =>
rv := "0000111111111111";
when x"5" =>
rv := "0000011111111111";
when x"6" =>
rv := "0000001111111111";
when x"7" =>
rv := "0000000111111111";
when x"8" =>
rv := "0000000011111111";
when x"9" =>
rv := "0000000001111111";
when x"a" =>
rv := "0000000000111111";
when x"b" =>
rv := "0000000000011111";
when x"c" =>
rv := "0000000000001111";
when x"d" =>
rv := "0000000000000111";
when x"e" =>
rv := "0000000000000011";
when x"f" =>
rv := "0000000000000001";
when others =>
rv := (others => '0');
end case;
if pol_i = '1' then
mask_start <= not rv;
mask_end <= rv;
else
mask_start <= rv;
mask_end <= not rv;
end if;
end if;
end if;
end if;
......@@ -131,29 +212,88 @@ begin
odelay_load <= dly_load_i or dly_load_d;
trig_d <= trig_p_i;
case state is
when IDLE =>
if pol_i = '1' then
par_data <= (others => '1');
else
par_data <= (others => '0');
end if;
ready_o <= '1';
if trig_p_i = '1' then
if cont_i = '1' then
state <= CONT_H;
ready_o <= '1';
elsif length_d = 0 then
state <= END_PULSE_H;
ready_o <= '0';
else
state <= START_PULSE_H;
ready_o <= '0';
end if;
end if;
if trig_p_i = '1' then
par_data <= mask(15 downto 8);
flip <= '0';
elsif trig_d = '1' then
par_data <= mask(7 downto 0);
else
when CONT_H =>
if cont_i = '0' then
state <= IDLE;
else
state <= CONT_L;
end if;
if cont_i = '1' then
if flip = '1' then
par_data <= mask(7 downto 0);
par_data <= mask_start(15 downto 8);
when CONT_L =>
par_data <= mask_start(7 downto 0);
state <= CONT_H;
when START_PULSE_H =>
par_data <= mask_start(15 downto 8);
state <= START_PULSE_L;
when START_PULSE_L =>
par_data <= mask_start(7 downto 0);
if length_d = 0 then
state <= IDLE;
else
par_data <= mask(15 downto 8);
state <= MID_PULSE_H;
end if;
else
when MID_PULSE_H =>
state <= MID_PULSE_L;
if pol_i = '1' then
par_data <= (others => '0');
else
par_data <= (others => '1');
end if;
when MID_PULSE_L =>
if length_d = 0 then
state <= END_PULSE_H;
else
state <= MID_PULSE_L;
end if;
length_d <= length_d - 1;
if pol_i = '1' then
par_data <= (others => '0');
else
par_data <= (others => '1');
end if;
end if;
end if;
when END_PULSE_H =>
par_data <= mask_end(15 downto 8);
state <= END_PULSE_L;
when END_PULSE_L =>
par_data <= mask_end(7 downto 0);
state <= IDLE;
end case;
end if;
end process;
......@@ -225,7 +365,7 @@ begin
end generate gen_without_odelay;
pulse_o <= dout_prebuf;
-- gen_output_diff : if g_use_diff_output generate
-- U_OBuf : OBUFDS
-- generic map(
......
......@@ -15,6 +15,9 @@ entity fine_pulse_gen_kintex7_shared is
-- PLL async reset
pll_rst_i : in std_logic;
idelayctrl_rst_i : in std_logic;
idelayctrl_rdy_o : out std_logic;
clk_ser_ext_i : in std_logic;
-- 62.5 MHz reference
......@@ -95,9 +98,9 @@ begin
IDELAYCTRL_inst : IDELAYCTRL
port map (
RDY => open, -- 1-bit output: Ready output
RDY => idelayctrl_rdy_o, -- 1-bit output: Ready output
REFCLK => clk_iodelay_bufg, -- 1-bit input: Reference clock input
RST => '0' -- 1-bit input: Active high reset input
RST => idelayctrl_rst_i -- 1-bit input: Active high reset input
);
clk_odelay_o <= clk_iodelay_bufg;
......
......@@ -28,6 +28,7 @@ entity fine_pulse_gen_kintexultrascale is
pol_i : in std_logic;
coarse_i : in std_logic_vector(7 downto 0);
trig_p_i : in std_logic;
ready_o : out std_logic;
pulse_o : out std_logic;
......@@ -154,6 +155,8 @@ begin
begin
if rising_edge(clk_ref_i) then
ready_o <= '1';
dly_load_d <= dly_load_i;
if dly_load_i = '1' then
......
......@@ -37,6 +37,19 @@ end fine_pulse_gen_kintexultrascale_shared;
architecture rtl of fine_pulse_gen_kintexultrascale_shared is
component IDELAYCTRL is
generic (
SIM_DEVICE : string := "7SERIES"
);
port(
RDY : out std_ulogic;
REFCLK : in std_ulogic;
RST : in std_ulogic
);
end component;
component MMCME3_ADV
generic (
BANDWIDTH : string := "OPTIMIZED";
......
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for Generic Fine Pulse Generator Unit
---------------------------------------------------------------------------------------
-- File : fine_pulse_gen_wb.vhd
-- Author : auto-generated by wbgen2 from fine_pulse_gen_wb.wb
-- Created : Tue Jul 7 14:29:21 2020
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE fine_pulse_gen_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.fpg_wbgen2_pkg.all;
entity fine_pulse_gen_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_fpg_in_registers;
regs_o : out t_fpg_out_registers
);
end fine_pulse_gen_wb;
architecture syn of fine_pulse_gen_wb is
signal fpg_csr_trig0_dly0 : std_logic ;
signal fpg_csr_trig0_int : std_logic ;
signal fpg_csr_trig1_dly0 : std_logic ;
signal fpg_csr_trig1_int : std_logic ;
signal fpg_csr_trig2_dly0 : std_logic ;
signal fpg_csr_trig2_int : std_logic ;
signal fpg_csr_trig3_dly0 : std_logic ;
signal fpg_csr_trig3_int : std_logic ;
signal fpg_csr_trig4_dly0 : std_logic ;
signal fpg_csr_trig4_int : std_logic ;
signal fpg_csr_trig5_dly0 : std_logic ;
signal fpg_csr_trig5_int : std_logic ;
signal fpg_csr_trig6_dly0 : std_logic ;
signal fpg_csr_trig6_int : std_logic ;
signal fpg_csr_trig7_dly0 : std_logic ;
signal fpg_csr_trig7_int : std_logic ;
signal fpg_csr_force0_dly0 : std_logic ;
signal fpg_csr_force0_int : std_logic ;
signal fpg_csr_force1_dly0 : std_logic ;
signal fpg_csr_force1_int : std_logic ;
signal fpg_csr_force2_dly0 : std_logic ;
signal fpg_csr_force2_int : std_logic ;
signal fpg_csr_force3_dly0 : std_logic ;
signal fpg_csr_force3_int : std_logic ;
signal fpg_csr_force4_dly0 : std_logic ;
signal fpg_csr_force4_int : std_logic ;
signal fpg_csr_force5_dly0 : std_logic ;
signal fpg_csr_force5_int : std_logic ;
signal fpg_csr_pll_rst_int : std_logic ;
signal fpg_csr_serdes_rst_int : std_logic ;
signal fpg_ocr0_pps_offs_int : std_logic_vector(3 downto 0);
signal fpg_ocr0_fine_int : std_logic_vector(8 downto 0);
signal fpg_ocr0_pol_int : std_logic ;
signal fpg_ocr0_mask_int : std_logic_vector(7 downto 0);
signal fpg_ocr0_cont_int : std_logic ;
signal fpg_ocr0_trig_sel_int : std_logic ;
signal fpg_ocr1_pps_offs_int : std_logic_vector(3 downto 0);
signal fpg_ocr1_fine_int : std_logic_vector(8 downto 0);
signal fpg_ocr1_pol_int : std_logic ;
signal fpg_ocr1_mask_int : std_logic_vector(7 downto 0);
signal fpg_ocr1_cont_int : std_logic ;
signal fpg_ocr1_trig_sel_int : std_logic ;
signal fpg_ocr2_pps_offs_int : std_logic_vector(3 downto 0);
signal fpg_ocr2_fine_int : std_logic_vector(8 downto 0);
signal fpg_ocr2_pol_int : std_logic ;
signal fpg_ocr2_mask_int : std_logic_vector(7 downto 0);
signal fpg_ocr2_cont_int : std_logic ;
signal fpg_ocr2_trig_sel_int : std_logic ;
signal fpg_ocr3_pps_offs_int : std_logic_vector(3 downto 0);
signal fpg_ocr3_fine_int : std_logic_vector(8 downto 0);
signal fpg_ocr3_pol_int : std_logic ;
signal fpg_ocr3_mask_int : std_logic_vector(7 downto 0);
signal fpg_ocr3_cont_int : std_logic ;
signal fpg_ocr3_trig_sel_int : std_logic ;
signal fpg_ocr4_pps_offs_int : std_logic_vector(3 downto 0);
signal fpg_ocr4_fine_int : std_logic_vector(8 downto 0);
signal fpg_ocr4_pol_int : std_logic ;
signal fpg_ocr4_mask_int : std_logic_vector(7 downto 0);
signal fpg_ocr4_cont_int : std_logic ;
signal fpg_ocr4_trig_sel_int : std_logic ;
signal fpg_ocr5_pps_offs_int : std_logic_vector(3 downto 0);
signal fpg_ocr5_fine_int : std_logic_vector(8 downto 0);
signal fpg_ocr5_pol_int : std_logic ;
signal fpg_ocr5_mask_int : std_logic_vector(7 downto 0);
signal fpg_ocr5_cont_int : std_logic ;
signal fpg_ocr5_trig_sel_int : std_logic ;
signal fpg_ocr6_pps_offs_int : std_logic_vector(3 downto 0);
signal fpg_ocr6_fine_int : std_logic_vector(8 downto 0);
signal fpg_ocr6_pol_int : std_logic ;
signal fpg_ocr6_mask_int : std_logic_vector(7 downto 0);
signal fpg_ocr6_cont_int : std_logic ;
signal fpg_ocr6_trig_sel_int : std_logic ;
signal fpg_ocr7_pps_offs_int : std_logic_vector(3 downto 0);
signal fpg_ocr7_fine_int : std_logic_vector(8 downto 0);
signal fpg_ocr7_pol_int : std_logic ;
signal fpg_ocr7_mask_int : std_logic_vector(7 downto 0);
signal fpg_ocr7_cont_int : std_logic ;
signal fpg_ocr7_trig_sel_int : std_logic ;
signal fpg_odelay_calib_rst_idelayctrl_int : std_logic ;
signal fpg_odelay_calib_rst_odelay_int : std_logic ;
signal fpg_odelay_calib_rst_oserdes_int : std_logic ;
signal fpg_odelay_calib_value_int : std_logic_vector(8 downto 0);
signal fpg_odelay_calib_value_update_dly0 : std_logic ;
signal fpg_odelay_calib_value_update_int : std_logic ;
signal fpg_odelay_calib_en_vtc_int : std_logic ;
signal fpg_odelay_calib_cal_latch_dly0 : std_logic ;
signal fpg_odelay_calib_cal_latch_int : std_logic ;
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(3 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";
fpg_csr_trig0_int <= '0';
fpg_csr_trig1_int <= '0';
fpg_csr_trig2_int <= '0';
fpg_csr_trig3_int <= '0';
fpg_csr_trig4_int <= '0';
fpg_csr_trig5_int <= '0';
fpg_csr_trig6_int <= '0';
fpg_csr_trig7_int <= '0';
fpg_csr_force0_int <= '0';
fpg_csr_force1_int <= '0';
fpg_csr_force2_int <= '0';
fpg_csr_force3_int <= '0';
fpg_csr_force4_int <= '0';
fpg_csr_force5_int <= '0';
fpg_csr_pll_rst_int <= '0';
fpg_csr_serdes_rst_int <= '0';
fpg_ocr0_pps_offs_int <= "0000";
fpg_ocr0_fine_int <= "000000000";
fpg_ocr0_pol_int <= '0';
fpg_ocr0_mask_int <= "00000000";
fpg_ocr0_cont_int <= '0';
fpg_ocr0_trig_sel_int <= '0';
fpg_ocr1_pps_offs_int <= "0000";
fpg_ocr1_fine_int <= "000000000";
fpg_ocr1_pol_int <= '0';
fpg_ocr1_mask_int <= "00000000";
fpg_ocr1_cont_int <= '0';
fpg_ocr1_trig_sel_int <= '0';
fpg_ocr2_pps_offs_int <= "0000";
fpg_ocr2_fine_int <= "000000000";
fpg_ocr2_pol_int <= '0';
fpg_ocr2_mask_int <= "00000000";
fpg_ocr2_cont_int <= '0';
fpg_ocr2_trig_sel_int <= '0';
fpg_ocr3_pps_offs_int <= "0000";
fpg_ocr3_fine_int <= "000000000";
fpg_ocr3_pol_int <= '0';
fpg_ocr3_mask_int <= "00000000";
fpg_ocr3_cont_int <= '0';
fpg_ocr3_trig_sel_int <= '0';
fpg_ocr4_pps_offs_int <= "0000";
fpg_ocr4_fine_int <= "000000000";
fpg_ocr4_pol_int <= '0';
fpg_ocr4_mask_int <= "00000000";
fpg_ocr4_cont_int <= '0';
fpg_ocr4_trig_sel_int <= '0';
fpg_ocr5_pps_offs_int <= "0000";
fpg_ocr5_fine_int <= "000000000";
fpg_ocr5_pol_int <= '0';
fpg_ocr5_mask_int <= "00000000";
fpg_ocr5_cont_int <= '0';
fpg_ocr5_trig_sel_int <= '0';
fpg_ocr6_pps_offs_int <= "0000";
fpg_ocr6_fine_int <= "000000000";
fpg_ocr6_pol_int <= '0';
fpg_ocr6_mask_int <= "00000000";
fpg_ocr6_cont_int <= '0';
fpg_ocr6_trig_sel_int <= '0';
fpg_ocr7_pps_offs_int <= "0000";
fpg_ocr7_fine_int <= "000000000";
fpg_ocr7_pol_int <= '0';
fpg_ocr7_mask_int <= "00000000";
fpg_ocr7_cont_int <= '0';
fpg_ocr7_trig_sel_int <= '0';
fpg_odelay_calib_rst_idelayctrl_int <= '0';
fpg_odelay_calib_rst_odelay_int <= '0';
fpg_odelay_calib_rst_oserdes_int <= '0';
fpg_odelay_calib_value_int <= "000000000";
fpg_odelay_calib_value_update_int <= '0';
fpg_odelay_calib_en_vtc_int <= '0';
fpg_odelay_calib_cal_latch_int <= '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
fpg_csr_trig0_int <= '0';
fpg_csr_trig1_int <= '0';
fpg_csr_trig2_int <= '0';
fpg_csr_trig3_int <= '0';
fpg_csr_trig4_int <= '0';
fpg_csr_trig5_int <= '0';
fpg_csr_trig6_int <= '0';
fpg_csr_trig7_int <= '0';
fpg_csr_force0_int <= '0';
fpg_csr_force1_int <= '0';
fpg_csr_force2_int <= '0';
fpg_csr_force3_int <= '0';
fpg_csr_force4_int <= '0';
fpg_csr_force5_int <= '0';
fpg_odelay_calib_value_update_int <= '0';
fpg_odelay_calib_cal_latch_int <= '0';
ack_in_progress <= '0';
else
end if;
else
if ((slave_i.cyc = '1') and (slave_i.stb = '1')) then
case rwaddr_reg(3 downto 0) is
when "0000" =>
if (slave_i.we = '1') then
fpg_csr_trig0_int <= wrdata_reg(0);
fpg_csr_trig1_int <= wrdata_reg(1);
fpg_csr_trig2_int <= wrdata_reg(2);
fpg_csr_trig3_int <= wrdata_reg(3);
fpg_csr_trig4_int <= wrdata_reg(4);
fpg_csr_trig5_int <= wrdata_reg(5);
fpg_csr_trig6_int <= wrdata_reg(6);
fpg_csr_trig7_int <= wrdata_reg(7);
fpg_csr_force0_int <= wrdata_reg(8);
fpg_csr_force1_int <= wrdata_reg(9);
fpg_csr_force2_int <= wrdata_reg(10);
fpg_csr_force3_int <= wrdata_reg(11);
fpg_csr_force4_int <= wrdata_reg(12);
fpg_csr_force5_int <= wrdata_reg(13);
fpg_csr_pll_rst_int <= wrdata_reg(20);
fpg_csr_serdes_rst_int <= wrdata_reg(21);
end if;
rddata_reg(0) <= '0';
rddata_reg(1) <= '0';
rddata_reg(2) <= '0';
rddata_reg(3) <= '0';
rddata_reg(4) <= '0';
rddata_reg(5) <= '0';
rddata_reg(6) <= '0';
rddata_reg(7) <= '0';
rddata_reg(8) <= '0';
rddata_reg(9) <= '0';
rddata_reg(10) <= '0';
rddata_reg(11) <= '0';
rddata_reg(12) <= '0';
rddata_reg(13) <= '0';
rddata_reg(19 downto 14) <= regs_i.csr_ready_i;
rddata_reg(20) <= fpg_csr_pll_rst_int;
rddata_reg(21) <= fpg_csr_serdes_rst_int;
rddata_reg(22) <= regs_i.csr_pll_locked_i;
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 "0001" =>
if (slave_i.we = '1') then
fpg_ocr0_pps_offs_int <= wrdata_reg(3 downto 0);
fpg_ocr0_fine_int <= wrdata_reg(12 downto 4);
fpg_ocr0_pol_int <= wrdata_reg(13);
fpg_ocr0_mask_int <= wrdata_reg(21 downto 14);
fpg_ocr0_cont_int <= wrdata_reg(22);
fpg_ocr0_trig_sel_int <= wrdata_reg(23);
end if;
rddata_reg(3 downto 0) <= fpg_ocr0_pps_offs_int;
rddata_reg(12 downto 4) <= fpg_ocr0_fine_int;
rddata_reg(13) <= fpg_ocr0_pol_int;
rddata_reg(21 downto 14) <= fpg_ocr0_mask_int;
rddata_reg(22) <= fpg_ocr0_cont_int;
rddata_reg(23) <= fpg_ocr0_trig_sel_int;
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 "0010" =>
if (slave_i.we = '1') then
fpg_ocr1_pps_offs_int <= wrdata_reg(3 downto 0);
fpg_ocr1_fine_int <= wrdata_reg(12 downto 4);
fpg_ocr1_pol_int <= wrdata_reg(13);
fpg_ocr1_mask_int <= wrdata_reg(21 downto 14);
fpg_ocr1_cont_int <= wrdata_reg(22);
fpg_ocr1_trig_sel_int <= wrdata_reg(23);
end if;
rddata_reg(3 downto 0) <= fpg_ocr1_pps_offs_int;
rddata_reg(12 downto 4) <= fpg_ocr1_fine_int;
rddata_reg(13) <= fpg_ocr1_pol_int;
rddata_reg(21 downto 14) <= fpg_ocr1_mask_int;
rddata_reg(22) <= fpg_ocr1_cont_int;
rddata_reg(23) <= fpg_ocr1_trig_sel_int;
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 "0011" =>
if (slave_i.we = '1') then
fpg_ocr2_pps_offs_int <= wrdata_reg(3 downto 0);
fpg_ocr2_fine_int <= wrdata_reg(12 downto 4);
fpg_ocr2_pol_int <= wrdata_reg(13);
fpg_ocr2_mask_int <= wrdata_reg(21 downto 14);
fpg_ocr2_cont_int <= wrdata_reg(22);
fpg_ocr2_trig_sel_int <= wrdata_reg(23);
end if;
rddata_reg(3 downto 0) <= fpg_ocr2_pps_offs_int;
rddata_reg(12 downto 4) <= fpg_ocr2_fine_int;
rddata_reg(13) <= fpg_ocr2_pol_int;
rddata_reg(21 downto 14) <= fpg_ocr2_mask_int;
rddata_reg(22) <= fpg_ocr2_cont_int;
rddata_reg(23) <= fpg_ocr2_trig_sel_int;
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 "0100" =>
if (slave_i.we = '1') then
fpg_ocr3_pps_offs_int <= wrdata_reg(3 downto 0);
fpg_ocr3_fine_int <= wrdata_reg(12 downto 4);
fpg_ocr3_pol_int <= wrdata_reg(13);
fpg_ocr3_mask_int <= wrdata_reg(21 downto 14);
fpg_ocr3_cont_int <= wrdata_reg(22);
fpg_ocr3_trig_sel_int <= wrdata_reg(23);
end if;
rddata_reg(3 downto 0) <= fpg_ocr3_pps_offs_int;
rddata_reg(12 downto 4) <= fpg_ocr3_fine_int;
rddata_reg(13) <= fpg_ocr3_pol_int;
rddata_reg(21 downto 14) <= fpg_ocr3_mask_int;
rddata_reg(22) <= fpg_ocr3_cont_int;
rddata_reg(23) <= fpg_ocr3_trig_sel_int;
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 "0101" =>
if (slave_i.we = '1') then
fpg_ocr4_pps_offs_int <= wrdata_reg(3 downto 0);
fpg_ocr4_fine_int <= wrdata_reg(12 downto 4);
fpg_ocr4_pol_int <= wrdata_reg(13);
fpg_ocr4_mask_int <= wrdata_reg(21 downto 14);
fpg_ocr4_cont_int <= wrdata_reg(22);
fpg_ocr4_trig_sel_int <= wrdata_reg(23);
end if;
rddata_reg(3 downto 0) <= fpg_ocr4_pps_offs_int;
rddata_reg(12 downto 4) <= fpg_ocr4_fine_int;
rddata_reg(13) <= fpg_ocr4_pol_int;
rddata_reg(21 downto 14) <= fpg_ocr4_mask_int;
rddata_reg(22) <= fpg_ocr4_cont_int;
rddata_reg(23) <= fpg_ocr4_trig_sel_int;
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 "0110" =>
if (slave_i.we = '1') then
fpg_ocr5_pps_offs_int <= wrdata_reg(3 downto 0);
fpg_ocr5_fine_int <= wrdata_reg(12 downto 4);
fpg_ocr5_pol_int <= wrdata_reg(13);
fpg_ocr5_mask_int <= wrdata_reg(21 downto 14);
fpg_ocr5_cont_int <= wrdata_reg(22);
fpg_ocr5_trig_sel_int <= wrdata_reg(23);
end if;
rddata_reg(3 downto 0) <= fpg_ocr5_pps_offs_int;
rddata_reg(12 downto 4) <= fpg_ocr5_fine_int;
rddata_reg(13) <= fpg_ocr5_pol_int;
rddata_reg(21 downto 14) <= fpg_ocr5_mask_int;
rddata_reg(22) <= fpg_ocr5_cont_int;
rddata_reg(23) <= fpg_ocr5_trig_sel_int;
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 "0111" =>
if (slave_i.we = '1') then
fpg_ocr6_pps_offs_int <= wrdata_reg(3 downto 0);
fpg_ocr6_fine_int <= wrdata_reg(12 downto 4);
fpg_ocr6_pol_int <= wrdata_reg(13);
fpg_ocr6_mask_int <= wrdata_reg(21 downto 14);
fpg_ocr6_cont_int <= wrdata_reg(22);
fpg_ocr6_trig_sel_int <= wrdata_reg(23);
end if;
rddata_reg(3 downto 0) <= fpg_ocr6_pps_offs_int;
rddata_reg(12 downto 4) <= fpg_ocr6_fine_int;
rddata_reg(13) <= fpg_ocr6_pol_int;
rddata_reg(21 downto 14) <= fpg_ocr6_mask_int;
rddata_reg(22) <= fpg_ocr6_cont_int;
rddata_reg(23) <= fpg_ocr6_trig_sel_int;
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 "1000" =>
if (slave_i.we = '1') then
fpg_ocr7_pps_offs_int <= wrdata_reg(3 downto 0);
fpg_ocr7_fine_int <= wrdata_reg(12 downto 4);
fpg_ocr7_pol_int <= wrdata_reg(13);
fpg_ocr7_mask_int <= wrdata_reg(21 downto 14);
fpg_ocr7_cont_int <= wrdata_reg(22);
fpg_ocr7_trig_sel_int <= wrdata_reg(23);
end if;
rddata_reg(3 downto 0) <= fpg_ocr7_pps_offs_int;
rddata_reg(12 downto 4) <= fpg_ocr7_fine_int;
rddata_reg(13) <= fpg_ocr7_pol_int;
rddata_reg(21 downto 14) <= fpg_ocr7_mask_int;
rddata_reg(22) <= fpg_ocr7_cont_int;
rddata_reg(23) <= fpg_ocr7_trig_sel_int;
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 "1001" =>
if (slave_i.we = '1') then
fpg_odelay_calib_rst_idelayctrl_int <= wrdata_reg(0);
fpg_odelay_calib_rst_odelay_int <= wrdata_reg(1);
fpg_odelay_calib_rst_oserdes_int <= wrdata_reg(2);
fpg_odelay_calib_value_int <= wrdata_reg(12 downto 4);
fpg_odelay_calib_value_update_int <= wrdata_reg(13);
fpg_odelay_calib_en_vtc_int <= wrdata_reg(14);
fpg_odelay_calib_cal_latch_int <= wrdata_reg(15);
end if;
rddata_reg(0) <= fpg_odelay_calib_rst_idelayctrl_int;
rddata_reg(1) <= fpg_odelay_calib_rst_odelay_int;
rddata_reg(2) <= fpg_odelay_calib_rst_oserdes_int;
rddata_reg(3) <= regs_i.odelay_calib_rdy_i;
rddata_reg(12 downto 4) <= fpg_odelay_calib_value_int;
rddata_reg(13) <= '0';
rddata_reg(14) <= fpg_odelay_calib_en_vtc_int;
rddata_reg(15) <= '0';
rddata_reg(24 downto 16) <= regs_i.odelay_calib_taps_i;
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 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;
-- Trigger Sync Pulse 0
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_trig0_dly0 <= '0';
regs_o.csr_trig0_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_trig0_dly0 <= fpg_csr_trig0_int;
regs_o.csr_trig0_o <= fpg_csr_trig0_int and (not fpg_csr_trig0_dly0);
end if;
end process;
-- Trigger Sync Pulse 1
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_trig1_dly0 <= '0';
regs_o.csr_trig1_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_trig1_dly0 <= fpg_csr_trig1_int;
regs_o.csr_trig1_o <= fpg_csr_trig1_int and (not fpg_csr_trig1_dly0);
end if;
end process;
-- Trigger Sync Pulse 2
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_trig2_dly0 <= '0';
regs_o.csr_trig2_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_trig2_dly0 <= fpg_csr_trig2_int;
regs_o.csr_trig2_o <= fpg_csr_trig2_int and (not fpg_csr_trig2_dly0);
end if;
end process;
-- Trigger Sync Pulse 3
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_trig3_dly0 <= '0';
regs_o.csr_trig3_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_trig3_dly0 <= fpg_csr_trig3_int;
regs_o.csr_trig3_o <= fpg_csr_trig3_int and (not fpg_csr_trig3_dly0);
end if;
end process;
-- Trigger Sync Pulse 4
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_trig4_dly0 <= '0';
regs_o.csr_trig4_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_trig4_dly0 <= fpg_csr_trig4_int;
regs_o.csr_trig4_o <= fpg_csr_trig4_int and (not fpg_csr_trig4_dly0);
end if;
end process;
-- Trigger Sync Pulse 5
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_trig5_dly0 <= '0';
regs_o.csr_trig5_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_trig5_dly0 <= fpg_csr_trig5_int;
regs_o.csr_trig5_o <= fpg_csr_trig5_int and (not fpg_csr_trig5_dly0);
end if;
end process;
-- Trigger Sync Pulse 6
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_trig6_dly0 <= '0';
regs_o.csr_trig6_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_trig6_dly0 <= fpg_csr_trig6_int;
regs_o.csr_trig6_o <= fpg_csr_trig6_int and (not fpg_csr_trig6_dly0);
end if;
end process;
-- Trigger Sync Pulse 7
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_trig7_dly0 <= '0';
regs_o.csr_trig7_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_trig7_dly0 <= fpg_csr_trig7_int;
regs_o.csr_trig7_o <= fpg_csr_trig7_int and (not fpg_csr_trig7_dly0);
end if;
end process;
-- Immediately Force Sync Pulse 0
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_force0_dly0 <= '0';
regs_o.csr_force0_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_force0_dly0 <= fpg_csr_force0_int;
regs_o.csr_force0_o <= fpg_csr_force0_int and (not fpg_csr_force0_dly0);
end if;
end process;
-- Immediately Force Sync Pulse 1
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_force1_dly0 <= '0';
regs_o.csr_force1_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_force1_dly0 <= fpg_csr_force1_int;
regs_o.csr_force1_o <= fpg_csr_force1_int and (not fpg_csr_force1_dly0);
end if;
end process;
-- Immediately Force Sync Pulse 2
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_force2_dly0 <= '0';
regs_o.csr_force2_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_force2_dly0 <= fpg_csr_force2_int;
regs_o.csr_force2_o <= fpg_csr_force2_int and (not fpg_csr_force2_dly0);
end if;
end process;
-- Immediately Force Sync Pulse 3
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_force3_dly0 <= '0';
regs_o.csr_force3_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_force3_dly0 <= fpg_csr_force3_int;
regs_o.csr_force3_o <= fpg_csr_force3_int and (not fpg_csr_force3_dly0);
end if;
end process;
-- Immediately Force Sync Pulse 4
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_force4_dly0 <= '0';
regs_o.csr_force4_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_force4_dly0 <= fpg_csr_force4_int;
regs_o.csr_force4_o <= fpg_csr_force4_int and (not fpg_csr_force4_dly0);
end if;
end process;
-- Immediately Force Sync Pulse 5
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_csr_force5_dly0 <= '0';
regs_o.csr_force5_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_csr_force5_dly0 <= fpg_csr_force5_int;
regs_o.csr_force5_o <= fpg_csr_force5_int and (not fpg_csr_force5_dly0);
end if;
end process;
-- Sync Pulse Ready
-- PLL Reset
regs_o.csr_pll_rst_o <= fpg_csr_pll_rst_int;
-- Serdes Reset
regs_o.csr_serdes_rst_o <= fpg_csr_serdes_rst_int;
-- PLL Locked
-- WR PPS offset
regs_o.ocr0_pps_offs_o <= fpg_ocr0_pps_offs_int;
-- Fine delay adjust
regs_o.ocr0_fine_o <= fpg_ocr0_fine_int;
-- Polarity
regs_o.ocr0_pol_o <= fpg_ocr0_pol_int;
-- Serdes Bitmask
regs_o.ocr0_mask_o <= fpg_ocr0_mask_int;
-- Continuous mode select
regs_o.ocr0_cont_o <= fpg_ocr0_cont_int;
-- Trigger select
regs_o.ocr0_trig_sel_o <= fpg_ocr0_trig_sel_int;
-- WR PPS offset
regs_o.ocr1_pps_offs_o <= fpg_ocr1_pps_offs_int;
-- Fine delay adjust
regs_o.ocr1_fine_o <= fpg_ocr1_fine_int;
-- Polarity
regs_o.ocr1_pol_o <= fpg_ocr1_pol_int;
-- Serdes Bitmask
regs_o.ocr1_mask_o <= fpg_ocr1_mask_int;
-- Continuous mode select
regs_o.ocr1_cont_o <= fpg_ocr1_cont_int;
-- Trigger select
regs_o.ocr1_trig_sel_o <= fpg_ocr1_trig_sel_int;
-- WR PPS offset
regs_o.ocr2_pps_offs_o <= fpg_ocr2_pps_offs_int;
-- Fine delay adjust
regs_o.ocr2_fine_o <= fpg_ocr2_fine_int;
-- Polarity
regs_o.ocr2_pol_o <= fpg_ocr2_pol_int;
-- Serdes Bitmask
regs_o.ocr2_mask_o <= fpg_ocr2_mask_int;
-- Continuous mode select
regs_o.ocr2_cont_o <= fpg_ocr2_cont_int;
-- Trigger select
regs_o.ocr2_trig_sel_o <= fpg_ocr2_trig_sel_int;
-- WR PPS offset
regs_o.ocr3_pps_offs_o <= fpg_ocr3_pps_offs_int;
-- Fine delay adjust
regs_o.ocr3_fine_o <= fpg_ocr3_fine_int;
-- Polarity
regs_o.ocr3_pol_o <= fpg_ocr3_pol_int;
-- Serdes Bitmask
regs_o.ocr3_mask_o <= fpg_ocr3_mask_int;
-- Continuous mode select
regs_o.ocr3_cont_o <= fpg_ocr3_cont_int;
-- Trigger select
regs_o.ocr3_trig_sel_o <= fpg_ocr3_trig_sel_int;
-- WR PPS offset
regs_o.ocr4_pps_offs_o <= fpg_ocr4_pps_offs_int;
-- Fine delay adjust
regs_o.ocr4_fine_o <= fpg_ocr4_fine_int;
-- Polarity
regs_o.ocr4_pol_o <= fpg_ocr4_pol_int;
-- Serdes Bitmask
regs_o.ocr4_mask_o <= fpg_ocr4_mask_int;
-- Continuous mode select
regs_o.ocr4_cont_o <= fpg_ocr4_cont_int;
-- Trigger select
regs_o.ocr4_trig_sel_o <= fpg_ocr4_trig_sel_int;
-- WR PPS offset
regs_o.ocr5_pps_offs_o <= fpg_ocr5_pps_offs_int;
-- Fine delay adjust
regs_o.ocr5_fine_o <= fpg_ocr5_fine_int;
-- Polarity
regs_o.ocr5_pol_o <= fpg_ocr5_pol_int;
-- Serdes Bitmask
regs_o.ocr5_mask_o <= fpg_ocr5_mask_int;
-- Continuous mode select
regs_o.ocr5_cont_o <= fpg_ocr5_cont_int;
-- Trigger select
regs_o.ocr5_trig_sel_o <= fpg_ocr5_trig_sel_int;
-- WR PPS offset
regs_o.ocr6_pps_offs_o <= fpg_ocr6_pps_offs_int;
-- Fine delay adjust
regs_o.ocr6_fine_o <= fpg_ocr6_fine_int;
-- Polarity
regs_o.ocr6_pol_o <= fpg_ocr6_pol_int;
-- Serdes Bitmask
regs_o.ocr6_mask_o <= fpg_ocr6_mask_int;
-- Continuous mode select
regs_o.ocr6_cont_o <= fpg_ocr6_cont_int;
-- Trigger select
regs_o.ocr6_trig_sel_o <= fpg_ocr6_trig_sel_int;
-- WR PPS offset
regs_o.ocr7_pps_offs_o <= fpg_ocr7_pps_offs_int;
-- Fine delay adjust
regs_o.ocr7_fine_o <= fpg_ocr7_fine_int;
-- Polarity
regs_o.ocr7_pol_o <= fpg_ocr7_pol_int;
-- Serdes Bitmask
regs_o.ocr7_mask_o <= fpg_ocr7_mask_int;
-- Continuous mode select
regs_o.ocr7_cont_o <= fpg_ocr7_cont_int;
-- Trigger select
regs_o.ocr7_trig_sel_o <= fpg_ocr7_trig_sel_int;
-- Reset Output IDELAYCTRL
regs_o.odelay_calib_rst_idelayctrl_o <= fpg_odelay_calib_rst_idelayctrl_int;
-- Reset Output ODELAY
regs_o.odelay_calib_rst_odelay_o <= fpg_odelay_calib_rst_odelay_int;
-- Reset Output OSERDES
regs_o.odelay_calib_rst_oserdes_o <= fpg_odelay_calib_rst_oserdes_int;
-- Output Delay Ready
-- Output Delay Value
regs_o.odelay_calib_value_o <= fpg_odelay_calib_value_int;
-- Delay value update
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_odelay_calib_value_update_dly0 <= '0';
regs_o.odelay_calib_value_update_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_odelay_calib_value_update_dly0 <= fpg_odelay_calib_value_update_int;
regs_o.odelay_calib_value_update_o <= fpg_odelay_calib_value_update_int and (not fpg_odelay_calib_value_update_dly0);
end if;
end process;
-- Enable VT compensation
regs_o.odelay_calib_en_vtc_o <= fpg_odelay_calib_en_vtc_int;
-- Latch calibration taps
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
fpg_odelay_calib_cal_latch_dly0 <= '0';
regs_o.odelay_calib_cal_latch_o <= '0';
elsif rising_edge(clk_sys_i) then
fpg_odelay_calib_cal_latch_dly0 <= fpg_odelay_calib_cal_latch_int;
regs_o.odelay_calib_cal_latch_o <= fpg_odelay_calib_cal_latch_int and (not fpg_odelay_calib_cal_latch_dly0);
end if;
end process;
-- n Taps
rwaddr_reg <= slave_i.adr(5 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 = "Generic Fine Pulse Generator Unit";
hdl_entity = "fine_pulse_gen_wb";
prefix = "fpg";
reg {
name = "Control/Status Register";
prefix = "CSR";
field {
name = "Trigger Sync Pulse 0";
prefix = "TRIG0";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Trigger Sync Pulse 1";
prefix = "TRIG1";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Trigger Sync Pulse 2";
prefix = "TRIG2";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Trigger Sync Pulse 3";
prefix = "TRIG3";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Trigger Sync Pulse 4";
prefix = "TRIG4";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Trigger Sync Pulse 5";
prefix = "TRIG5";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Trigger Sync Pulse 6";
prefix = "TRIG6";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Trigger Sync Pulse 7";
prefix = "TRIG7";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Immediately Force Sync Pulse 0";
prefix = "FORCE0";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Immediately Force Sync Pulse 1";
prefix = "FORCE1";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Immediately Force Sync Pulse 2";
prefix = "FORCE2";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Immediately Force Sync Pulse 3";
prefix = "FORCE3";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Immediately Force Sync Pulse 4";
prefix = "FORCE4";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Immediately Force Sync Pulse 5";
prefix = "FORCE5";
-- clock = "clk_ref_i";
type = MONOSTABLE;
};
field {
name = "Sync Pulse Ready";
size = 6;
type = SLV;
prefix = "READY";
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "PLL Reset";
prefix = "PLL_RST";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Serdes Reset";
prefix = "SERDES_RST";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "PLL Locked";
prefix = "PLL_LOCKED";
type = BIT;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
reg {
name = "Output 0 Control";
prefix = "OCR0";
field {
name = "WR PPS offset";
prefix = "PPS_OFFS";
size = 4;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Fine delay adjust";
prefix = "FINE";
size = 9;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Polarity";
prefix = "POL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Serdes Bitmask";
prefix = "MASK";
size = 8;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Continuous mode select";
prefix = "CONT";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Trigger select";
prefix = "TRIG_SEL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
description = "1: external trigger; 0: PPS";
};
};
reg {
name = "Output 1 Control";
prefix = "OCR1";
field {
name = "WR PPS offset";
prefix = "PPS_OFFS";
size = 4;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Fine delay adjust";
prefix = "FINE";
size = 9;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Polarity";
prefix = "POL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Serdes Bitmask";
prefix = "MASK";
size = 8;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Continuous mode select";
prefix = "CONT";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Trigger select";
prefix = "TRIG_SEL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
description = "1: external trigger; 0: PPS";
};
};
reg {
name = "Output 2 Control";
prefix = "OCR2";
field {
name = "WR PPS offset";
prefix = "PPS_OFFS";
size = 4;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Fine delay adjust";
prefix = "FINE";
size = 9;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Polarity";
prefix = "POL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Serdes Bitmask";
prefix = "MASK";
size = 8;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Continuous mode select";
prefix = "CONT";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Trigger select";
prefix = "TRIG_SEL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
description = "1: external trigger; 0: PPS";
};
};
reg {
name = "Output 3 Control";
prefix = "OCR3";
field {
name = "WR PPS offset";
prefix = "PPS_OFFS";
size = 4;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Fine delay adjust";
prefix = "FINE";
size = 9;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Polarity";
prefix = "POL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Serdes Bitmask";
prefix = "MASK";
size = 8;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Continuous mode select";
prefix = "CONT";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Trigger select";
prefix = "TRIG_SEL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
description = "1: external trigger; 0: PPS";
};
};
reg {
name = "Output 4 Control";
prefix = "OCR4";
field {
name = "WR PPS offset";
prefix = "PPS_OFFS";
size = 4;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Fine delay adjust";
prefix = "FINE";
size = 9;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Polarity";
prefix = "POL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Serdes Bitmask";
prefix = "MASK";
size = 8;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Continuous mode select";
prefix = "CONT";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Trigger select";
prefix = "TRIG_SEL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
description = "1: external trigger; 0: PPS";
};
};
reg {
name = "Output 5 Control";
prefix = "OCR5";
field {
name = "WR PPS offset";
prefix = "PPS_OFFS";
size = 4;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Fine delay adjust";
prefix = "FINE";
size = 9;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Polarity";
prefix = "POL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Serdes Bitmask";
prefix = "MASK";
size = 8;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Continuous mode select";
prefix = "CONT";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Trigger select";
prefix = "TRIG_SEL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
description = "1: external trigger; 0: PPS";
};
};
reg {
name = "Output 6 Control";
prefix = "OCR6";
field {
name = "WR PPS offset";
prefix = "PPS_OFFS";
size = 4;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Fine delay adjust";
prefix = "FINE";
size = 9;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Polarity";
prefix = "POL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Serdes Bitmask";
prefix = "MASK";
size = 8;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Continuous mode select";
prefix = "CONT";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Trigger select";
prefix = "TRIG_SEL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
description = "1: external trigger; 0: PPS";
};
};
reg {
name = "Output 7 Control";
prefix = "OCR7";
field {
name = "WR PPS offset";
prefix = "PPS_OFFS";
size = 4;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Fine delay adjust";
prefix = "FINE";
size = 9;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Polarity";
prefix = "POL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Serdes Bitmask";
prefix = "MASK";
size = 8;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Continuous mode select";
prefix = "CONT";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Trigger select";
prefix = "TRIG_SEL";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
description = "1: external trigger; 0: PPS";
};
};
reg {
name = "Output Delay Calibration (Ultrascale-specific)";
prefix = "odelay_calib";
field {
name = "Reset Output IDELAYCTRL";
type = BIT;
prefix = "rst_idelayctrl";
};
field {
name = "Reset Output ODELAY";
type = BIT;
prefix = "rst_odelay";
};
field {
name = "Reset Output OSERDES";
type = BIT;
prefix = "rst_oserdes";
};
field {
name = "Output Delay Ready";
type = BIT;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
prefix = "rdy";
};
field {
name = "Output Delay Value";
description = "Delay value in taps";
type = SLV;
size = 9;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
prefix = "value";
};
field {
name = "Delay value update";
prefix = "value_update";
type = MONOSTABLE;
};
field {
name = "Enable VT compensation";
description = "Enable VT compensation";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
prefix = "en_vtc";
};
field {
name = "Latch calibration taps";
type = MONOSTABLE;
prefix = "cal_latch";
};
field {
name = "n Taps";
description = "Value in number of taps";
type = SLV;
size = 9;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
prefix = "taps";
};
};
};
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for Generic Fine Pulse Generator Unit
---------------------------------------------------------------------------------------
-- File : fine_pulse_gen_wbgen2_pkg.vhd
-- Author : auto-generated by wbgen2 from fine_pulse_gen_wb.wb
-- Created : Tue Jul 7 14:29:21 2020
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE fine_pulse_gen_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 fpg_wbgen2_pkg is
-- Input registers (user design -> WB slave)
type t_fpg_in_registers is record
csr_ready_i : std_logic_vector(5 downto 0);
csr_pll_locked_i : std_logic;
odelay_calib_rdy_i : std_logic;
odelay_calib_taps_i : std_logic_vector(8 downto 0);
end record;
constant c_fpg_in_registers_init_value: t_fpg_in_registers := (
csr_ready_i => (others => '0'),
csr_pll_locked_i => '0',
odelay_calib_rdy_i => '0',
odelay_calib_taps_i => (others => '0')
);
-- Output registers (WB slave -> user design)
type t_fpg_out_registers is record
csr_trig0_o : std_logic;
csr_trig1_o : std_logic;
csr_trig2_o : std_logic;
csr_trig3_o : std_logic;
csr_trig4_o : std_logic;
csr_trig5_o : std_logic;
csr_trig6_o : std_logic;
csr_trig7_o : std_logic;
csr_force0_o : std_logic;
csr_force1_o : std_logic;
csr_force2_o : std_logic;
csr_force3_o : std_logic;
csr_force4_o : std_logic;
csr_force5_o : std_logic;
csr_pll_rst_o : std_logic;
csr_serdes_rst_o : std_logic;
ocr0_pps_offs_o : std_logic_vector(3 downto 0);
ocr0_fine_o : std_logic_vector(8 downto 0);
ocr0_pol_o : std_logic;
ocr0_mask_o : std_logic_vector(7 downto 0);
ocr0_cont_o : std_logic;
ocr0_trig_sel_o : std_logic;
ocr1_pps_offs_o : std_logic_vector(3 downto 0);
ocr1_fine_o : std_logic_vector(8 downto 0);
ocr1_pol_o : std_logic;
ocr1_mask_o : std_logic_vector(7 downto 0);
ocr1_cont_o : std_logic;
ocr1_trig_sel_o : std_logic;
ocr2_pps_offs_o : std_logic_vector(3 downto 0);
ocr2_fine_o : std_logic_vector(8 downto 0);
ocr2_pol_o : std_logic;
ocr2_mask_o : std_logic_vector(7 downto 0);
ocr2_cont_o : std_logic;
ocr2_trig_sel_o : std_logic;
ocr3_pps_offs_o : std_logic_vector(3 downto 0);
ocr3_fine_o : std_logic_vector(8 downto 0);
ocr3_pol_o : std_logic;
ocr3_mask_o : std_logic_vector(7 downto 0);
ocr3_cont_o : std_logic;
ocr3_trig_sel_o : std_logic;
ocr4_pps_offs_o : std_logic_vector(3 downto 0);
ocr4_fine_o : std_logic_vector(8 downto 0);
ocr4_pol_o : std_logic;
ocr4_mask_o : std_logic_vector(7 downto 0);
ocr4_cont_o : std_logic;
ocr4_trig_sel_o : std_logic;
ocr5_pps_offs_o : std_logic_vector(3 downto 0);
ocr5_fine_o : std_logic_vector(8 downto 0);
ocr5_pol_o : std_logic;
ocr5_mask_o : std_logic_vector(7 downto 0);
ocr5_cont_o : std_logic;
ocr5_trig_sel_o : std_logic;
ocr6_pps_offs_o : std_logic_vector(3 downto 0);
ocr6_fine_o : std_logic_vector(8 downto 0);
ocr6_pol_o : std_logic;
ocr6_mask_o : std_logic_vector(7 downto 0);
ocr6_cont_o : std_logic;
ocr6_trig_sel_o : std_logic;
ocr7_pps_offs_o : std_logic_vector(3 downto 0);
ocr7_fine_o : std_logic_vector(8 downto 0);
ocr7_pol_o : std_logic;
ocr7_mask_o : std_logic_vector(7 downto 0);
ocr7_cont_o : std_logic;
ocr7_trig_sel_o : std_logic;
odelay_calib_rst_idelayctrl_o : std_logic;
odelay_calib_rst_odelay_o : std_logic;
odelay_calib_rst_oserdes_o : std_logic;
odelay_calib_value_o : std_logic_vector(8 downto 0);
odelay_calib_value_update_o : std_logic;
odelay_calib_en_vtc_o : std_logic;
odelay_calib_cal_latch_o : std_logic;
end record;
constant c_fpg_out_registers_init_value: t_fpg_out_registers := (
csr_trig0_o => '0',
csr_trig1_o => '0',
csr_trig2_o => '0',
csr_trig3_o => '0',
csr_trig4_o => '0',
csr_trig5_o => '0',
csr_trig6_o => '0',
csr_trig7_o => '0',
csr_force0_o => '0',
csr_force1_o => '0',
csr_force2_o => '0',
csr_force3_o => '0',
csr_force4_o => '0',
csr_force5_o => '0',
csr_pll_rst_o => '0',
csr_serdes_rst_o => '0',
ocr0_pps_offs_o => (others => '0'),
ocr0_fine_o => (others => '0'),
ocr0_pol_o => '0',
ocr0_mask_o => (others => '0'),
ocr0_cont_o => '0',
ocr0_trig_sel_o => '0',
ocr1_pps_offs_o => (others => '0'),
ocr1_fine_o => (others => '0'),
ocr1_pol_o => '0',
ocr1_mask_o => (others => '0'),
ocr1_cont_o => '0',
ocr1_trig_sel_o => '0',
ocr2_pps_offs_o => (others => '0'),
ocr2_fine_o => (others => '0'),
ocr2_pol_o => '0',
ocr2_mask_o => (others => '0'),
ocr2_cont_o => '0',
ocr2_trig_sel_o => '0',
ocr3_pps_offs_o => (others => '0'),
ocr3_fine_o => (others => '0'),
ocr3_pol_o => '0',
ocr3_mask_o => (others => '0'),
ocr3_cont_o => '0',
ocr3_trig_sel_o => '0',
ocr4_pps_offs_o => (others => '0'),
ocr4_fine_o => (others => '0'),
ocr4_pol_o => '0',
ocr4_mask_o => (others => '0'),
ocr4_cont_o => '0',
ocr4_trig_sel_o => '0',
ocr5_pps_offs_o => (others => '0'),
ocr5_fine_o => (others => '0'),
ocr5_pol_o => '0',
ocr5_mask_o => (others => '0'),
ocr5_cont_o => '0',
ocr5_trig_sel_o => '0',
ocr6_pps_offs_o => (others => '0'),
ocr6_fine_o => (others => '0'),
ocr6_pol_o => '0',
ocr6_mask_o => (others => '0'),
ocr6_cont_o => '0',
ocr6_trig_sel_o => '0',
ocr7_pps_offs_o => (others => '0'),
ocr7_fine_o => (others => '0'),
ocr7_pol_o => '0',
ocr7_mask_o => (others => '0'),
ocr7_cont_o => '0',
ocr7_trig_sel_o => '0',
odelay_calib_rst_idelayctrl_o => '0',
odelay_calib_rst_odelay_o => '0',
odelay_calib_rst_oserdes_o => '0',
odelay_calib_value_o => (others => '0'),
odelay_calib_value_update_o => '0',
odelay_calib_en_vtc_o => '0',
odelay_calib_cal_latch_o => '0'
);
function "or" (left, right: t_fpg_in_registers) return t_fpg_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 fine_pulse_gen_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_fpg_in_registers;
regs_o : out t_fpg_out_registers
);
end component;
end package;
package body fpg_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_fpg_in_registers) return t_fpg_in_registers is
variable tmp: t_fpg_in_registers;
begin
tmp.csr_ready_i := f_x_to_zero(left.csr_ready_i) or f_x_to_zero(right.csr_ready_i);
tmp.csr_pll_locked_i := f_x_to_zero(left.csr_pll_locked_i) or f_x_to_zero(right.csr_pll_locked_i);
tmp.odelay_calib_rdy_i := f_x_to_zero(left.odelay_calib_rdy_i) or f_x_to_zero(right.odelay_calib_rdy_i);
tmp.odelay_calib_taps_i := f_x_to_zero(left.odelay_calib_taps_i) or f_x_to_zero(right.odelay_calib_taps_i);
return tmp;
end function;
end package body;
#!/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
memory-map:
description: Generic Fine Pulse Generator Unit
bus: wb-32-be
name: wb_fpgen
x-hdl:
busgroup: True
iogroup: fpgen_regs
name-suffix: _regs
schema-version:
core: 2.0.0
x-gena: 1.0.0
x-hdl: 1.0.0
x-driver-edge: 1.0.0
x-conversions: 1.0.0
x-map-info: 1.0.0
x-map-info:
memmap-version: 0.0.1
children:
- reg:
name: csr
description: Control/Status Register
width: 32
access: rw
address: next
children:
- field:
name: TRIG0
description: Trigger Pulse @ Output 0 at next PPS
range: 0
x-hdl:
type: autoclear
- field:
name: TRIG1
description: Trigger Pulse @ Output 1 at next PPS
range: 1
x-hdl:
type: autoclear
- field:
name: TRIG2
description: Trigger Pulse @ Output 2 at next PPS
range: 2
x-hdl:
type: autoclear
- field:
name: TRIG3
description: Trigger Pulse @ Output 3 at next PPS
range: 3
x-hdl:
type: autoclear
- field:
name: TRIG4
description: Trigger Pulse @ Output 4 at next PPS
range: 4
x-hdl:
type: autoclear
- field:
name: TRIG5
description: Trigger Pulse @ Output 5 at next PPS
range: 5
x-hdl:
type: autoclear
- field:
name: TRIG6
description: Trigger Pulse @ Output 6 at next PPS
range: 6
x-hdl:
type: autoclear
- field:
name: TRIG7
description: Trigger Pulse @ Output 7 at next PPS
range: 7
x-hdl:
type: autoclear
- field:
name: FORCE0
description: Trigger Pulse @ Output 0 immediately
range: 8
x-hdl:
type: autoclear
- field:
name: FORCE1
description: Trigger Pulse @ Output 1 immediately
range: 9
x-hdl:
type: autoclear
- field:
name: FORCE2
description: Trigger Pulse @ Output 2 immediately
range: 10
x-hdl:
type: autoclear
- field:
name: FORCE3
description: Trigger Pulse @ Output 3 immediately
range: 11
x-hdl:
type: autoclear
- field:
name: FORCE4
description: Trigger Pulse @ Output 4 immediately
range: 12
x-hdl:
type: autoclear
- field:
name: FORCE5
description: Trigger Pulse @ Output 5 immediately
range: 13
x-hdl:
type: autoclear
- field:
name: READY
description: Pulse Generator Ready
range: 19-14
x-hdl:
type: wire
- field:
name: PLL_RST
description: PLL Reset
range: 20
- field:
name: SERDES_RST
description: Serdes Reset
range: 21
- field:
name: PLL_LOCKED
description: PLL Locked
range: 22
x-hdl:
type: wire
- reg:
name: OCR0A
description: Output 0 Control Register A
width: 32
access: rw
address: next
children:
- field:
name: FINE
description: Fine delay adjust
range: 11-0
- field:
name: POL
description: Polarity
range: 12
- field:
name: COARSE
description: Serdes Bitmask
range: 17-13
- field:
name: CONT
description: Continuous mode select
range: 18
- field:
name: TRIG_SEL
description: Trigger select
comment: '1: external trigger; 0: PPS'
range: 19
- reg:
name: OCR0B
description: Output 0 Control Register B
width: 32
access: rw
address: next
children:
- field:
name: PPS_OFFS
description: WR PPS offset in reference clock cycles
range: 15-0
- field:
name: LENGTH
description: Pulse Length (target platform specific, 0 = minimum possible pulse width)
range: 31-16
x-wbgen:
access_bus: READ_WRITE
access_dev: READ_ONLY
type: SLV
- reg:
name: OCR1A
description: Output 0 Control Register A
width: 32
access: rw
address: next
children:
- field:
name: FINE
description: Fine delay adjust
range: 11-0
- field:
name: POL
description: Polarity
range: 12
- field:
name: COARSE
description: Serdes Bitmask
range: 17-13
- field:
name: CONT
description: Continuous mode select
range: 18
- field:
name: TRIG_SEL
description: Trigger select
comment: '1: external trigger; 0: PPS'
range: 19
- reg:
name: OCR1B
description: Output 1 Control Register B
width: 32
access: rw
address: next
children:
- field:
name: PPS_OFFS
description: WR PPS offset in reference clock cycles
range: 15-0
- field:
name: LENGTH
description: Pulse Length (target platform specific, 0 = minimum possible pulse width)
range: 31-16
x-wbgen:
access_bus: READ_WRITE
access_dev: READ_ONLY
type: SLV
- reg:
name: OCR2A
description: Output 2 Control Register A
width: 32
access: rw
address: next
children:
- field:
name: FINE
description: Fine delay adjust
range: 11-0
- field:
name: POL
description: Polarity
range: 12
- field:
name: COARSE
description: Serdes Bitmask
range: 17-13
- field:
name: CONT
description: Continuous mode select
range: 18
- field:
name: TRIG_SEL
description: Trigger select
comment: '1: external trigger; 0: PPS'
range: 19
- reg:
name: OCR2B
description: Output 2 Control Register B
width: 32
access: rw
address: next
children:
- field:
name: PPS_OFFS
description: WR PPS offset in reference clock cycles
range: 15-0
- field:
name: LENGTH
description: Pulse Length (target platform specific, 0 = minimum possible pulse width)
range: 31-16
x-wbgen:
access_bus: READ_WRITE
access_dev: READ_ONLY
type: SLV
- reg:
name: OCR3A
description: Output 3 Control Register A
width: 32
access: rw
address: next
children:
- field:
name: FINE
description: Fine delay adjust
range: 11-0
- field:
name: POL
description: Polarity
range: 12
- field:
name: COARSE
description: Serdes Bitmask
range: 17-13
- field:
name: CONT
description: Continuous mode select
range: 18
- field:
name: TRIG_SEL
description: Trigger select
comment: '1: external trigger; 0: PPS'
range: 19
- reg:
name: OCR3B
description: Output 3 Control Register B
width: 32
access: rw
address: next
children:
- field:
name: PPS_OFFS
description: WR PPS offset in reference clock cycles
range: 15-0
- field:
name: LENGTH
description: Pulse Length (target platform specific, 0 = minimum possible pulse width)
range: 31-16
x-wbgen:
access_bus: READ_WRITE
access_dev: READ_ONLY
type: SLV
- reg:
name: OCR4A
description: Output 4 Control Register A
width: 32
access: rw
address: next
children:
- field:
name: FINE
description: Fine delay adjust
range: 11-0
- field:
name: POL
description: Polarity
range: 12
- field:
name: COARSE
description: Serdes Bitmask
range: 17-13
- field:
name: CONT
description: Continuous mode select
range: 18
- field:
name: TRIG_SEL
description: Trigger select
comment: '1: external trigger; 0: PPS'
range: 19
- reg:
name: OCR4B
description: Output 4 Control Register B
width: 32
access: rw
address: next
children:
- field:
name: PPS_OFFS
description: WR PPS offset in reference clock cycles
range: 15-0
- field:
name: LENGTH
description: Pulse Length (target platform specific, 0 = minimum possible pulse width)
range: 31-16
x-wbgen:
access_bus: READ_WRITE
access_dev: READ_ONLY
type: SLV
- reg:
name: OCR5A
description: Output 5 Control Register A
width: 32
access: rw
address: next
children:
- field:
name: FINE
description: Fine delay adjust
range: 11-0
- field:
name: POL
description: Polarity
range: 12
- field:
name: COARSE
description: Serdes Bitmask
range: 17-13
- field:
name: CONT
description: Continuous mode select
range: 18
- field:
name: TRIG_SEL
description: Trigger select
comment: '1: external trigger; 0: PPS'
range: 19
- reg:
name: OCR5B
description: Output 5 Control Register B
width: 32
access: rw
address: next
children:
- field:
name: PPS_OFFS
description: WR PPS offset in reference clock cycles
range: 15-0
- field:
name: LENGTH
description: Pulse Length (target platform specific, 0 = minimum possible pulse width)
range: 31-16
x-wbgen:
access_bus: READ_WRITE
access_dev: READ_ONLY
type: SLV
- reg:
name: odelay_calib
description: Output Delay Calibration (Ultrascale-specific)
width: 32
access: rw
address: next
children:
- field:
name: rst_idelayctrl
description: Reset Output IDELAYCTRL
range: 0
- field:
name: rst_odelay
description: Reset Output ODELAY
range: 1
- field:
name: rst_oserdes
description: Reset Output OSERDES
range: 2
- field:
name: rdy
description: Output Delay Ready
range: 3
x-hdl:
type: wire
- field:
name: value
description: Output Delay Value
comment: Delay value in taps
range: 12-4
x-hdl:
type: wire
- field:
name: value_update
description: Delay value update
range: 13
x-hdl:
type: autoclear
- field:
name: en_vtc
description: Enable VT compensation
comment: Enable VT compensation
range: 14
- field:
name: cal_latch
description: Latch calibration taps
range: 15
x-hdl:
type: autoclear
- field:
name: taps
description: n Taps
comment: Value in number of taps
range: 24-16
x-hdl:
type: wire
-- Do not edit. Generated by cheby 1.5.dev0 using these options:
-- -i wb_fpgen_regs.cheby --gen-hdl wb_fpgen_regs.vhd
-- Generated on Fri Mar 17 20:57:47 2023 by twl
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
package wb_fpgen_regs_pkg is
type t_fpgen_regs_master_out is record
csr_TRIG0 : std_logic;
csr_TRIG1 : std_logic;
csr_TRIG2 : std_logic;
csr_TRIG3 : std_logic;
csr_TRIG4 : std_logic;
csr_TRIG5 : std_logic;
csr_TRIG6 : std_logic;
csr_TRIG7 : std_logic;
csr_FORCE0 : std_logic;
csr_FORCE1 : std_logic;
csr_FORCE2 : std_logic;
csr_FORCE3 : std_logic;
csr_FORCE4 : std_logic;
csr_FORCE5 : std_logic;
csr_READY : std_logic_vector(5 downto 0);
csr_PLL_RST : std_logic;
csr_SERDES_RST : std_logic;
csr_PLL_LOCKED : std_logic;
OCR0A_FINE : std_logic_vector(11 downto 0);
OCR0A_POL : std_logic;
OCR0A_COARSE : std_logic_vector(4 downto 0);
OCR0A_CONT : std_logic;
OCR0A_TRIG_SEL : std_logic;
OCR0B_PPS_OFFS : std_logic_vector(15 downto 0);
OCR0B_LENGTH : std_logic_vector(15 downto 0);
OCR1A_FINE : std_logic_vector(11 downto 0);
OCR1A_POL : std_logic;
OCR1A_COARSE : std_logic_vector(4 downto 0);
OCR1A_CONT : std_logic;
OCR1A_TRIG_SEL : std_logic;
OCR1B_PPS_OFFS : std_logic_vector(15 downto 0);
OCR1B_LENGTH : std_logic_vector(15 downto 0);
OCR2A_FINE : std_logic_vector(11 downto 0);
OCR2A_POL : std_logic;
OCR2A_COARSE : std_logic_vector(4 downto 0);
OCR2A_CONT : std_logic;
OCR2A_TRIG_SEL : std_logic;
OCR2B_PPS_OFFS : std_logic_vector(15 downto 0);
OCR2B_LENGTH : std_logic_vector(15 downto 0);
OCR3A_FINE : std_logic_vector(11 downto 0);
OCR3A_POL : std_logic;
OCR3A_COARSE : std_logic_vector(4 downto 0);
OCR3A_CONT : std_logic;
OCR3A_TRIG_SEL : std_logic;
OCR3B_PPS_OFFS : std_logic_vector(15 downto 0);
OCR3B_LENGTH : std_logic_vector(15 downto 0);
OCR4A_FINE : std_logic_vector(11 downto 0);
OCR4A_POL : std_logic;
OCR4A_COARSE : std_logic_vector(4 downto 0);
OCR4A_CONT : std_logic;
OCR4A_TRIG_SEL : std_logic;
OCR4B_PPS_OFFS : std_logic_vector(15 downto 0);
OCR4B_LENGTH : std_logic_vector(15 downto 0);
OCR5A_FINE : std_logic_vector(11 downto 0);
OCR5A_POL : std_logic;
OCR5A_COARSE : std_logic_vector(4 downto 0);
OCR5A_CONT : std_logic;
OCR5A_TRIG_SEL : std_logic;
OCR5B_PPS_OFFS : std_logic_vector(15 downto 0);
OCR5B_LENGTH : std_logic_vector(15 downto 0);
odelay_calib_rst_idelayctrl : std_logic;
odelay_calib_rst_odelay : std_logic;
odelay_calib_rst_oserdes : std_logic;
odelay_calib_rdy : std_logic;
odelay_calib_value : std_logic_vector(8 downto 0);
odelay_calib_value_update : std_logic;
odelay_calib_en_vtc : std_logic;
odelay_calib_cal_latch : std_logic;
odelay_calib_taps : std_logic_vector(8 downto 0);
end record t_fpgen_regs_master_out;
subtype t_fpgen_regs_slave_in is t_fpgen_regs_master_out;
type t_fpgen_regs_slave_out is record
csr_READY : std_logic_vector(5 downto 0);
csr_PLL_LOCKED : std_logic;
odelay_calib_rdy : std_logic;
odelay_calib_value : std_logic_vector(8 downto 0);
odelay_calib_taps : std_logic_vector(8 downto 0);
end record t_fpgen_regs_slave_out;
subtype t_fpgen_regs_master_in is t_fpgen_regs_slave_out;
end wb_fpgen_regs_pkg;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.wb_fpgen_regs_pkg.all;
entity wb_fpgen_regs is
port (
rst_n_i : in std_logic;
clk_i : in std_logic;
wb_i : in t_wishbone_slave_in;
wb_o : out t_wishbone_slave_out;
-- Wires and registers
fpgen_regs_i : in t_fpgen_regs_master_in;
fpgen_regs_o : out t_fpgen_regs_master_out
);
end wb_fpgen_regs;
architecture syn of wb_fpgen_regs is
signal adr_int : std_logic_vector(5 downto 2);
signal rd_req_int : std_logic;
signal wr_req_int : std_logic;
signal rd_ack_int : std_logic;
signal wr_ack_int : std_logic;
signal wb_en : std_logic;
signal ack_int : std_logic;
signal wb_rip : std_logic;
signal wb_wip : std_logic;
signal csr_TRIG0_reg : std_logic;
signal csr_TRIG1_reg : std_logic;
signal csr_TRIG2_reg : std_logic;
signal csr_TRIG3_reg : std_logic;
signal csr_TRIG4_reg : std_logic;
signal csr_TRIG5_reg : std_logic;
signal csr_TRIG6_reg : std_logic;
signal csr_TRIG7_reg : std_logic;
signal csr_FORCE0_reg : std_logic;
signal csr_FORCE1_reg : std_logic;
signal csr_FORCE2_reg : std_logic;
signal csr_FORCE3_reg : std_logic;
signal csr_FORCE4_reg : std_logic;
signal csr_FORCE5_reg : std_logic;
signal csr_PLL_RST_reg : std_logic;
signal csr_SERDES_RST_reg : std_logic;
signal csr_wreq : std_logic;
signal csr_wack : std_logic;
signal OCR0A_FINE_reg : std_logic_vector(11 downto 0);
signal OCR0A_POL_reg : std_logic;
signal OCR0A_COARSE_reg : std_logic_vector(4 downto 0);
signal OCR0A_CONT_reg : std_logic;
signal OCR0A_TRIG_SEL_reg : std_logic;
signal OCR0A_wreq : std_logic;
signal OCR0A_wack : std_logic;
signal OCR0B_PPS_OFFS_reg : std_logic_vector(15 downto 0);
signal OCR0B_LENGTH_reg : std_logic_vector(15 downto 0);
signal OCR0B_wreq : std_logic;
signal OCR0B_wack : std_logic;
signal OCR1A_FINE_reg : std_logic_vector(11 downto 0);
signal OCR1A_POL_reg : std_logic;
signal OCR1A_COARSE_reg : std_logic_vector(4 downto 0);
signal OCR1A_CONT_reg : std_logic;
signal OCR1A_TRIG_SEL_reg : std_logic;
signal OCR1A_wreq : std_logic;
signal OCR1A_wack : std_logic;
signal OCR1B_PPS_OFFS_reg : std_logic_vector(15 downto 0);
signal OCR1B_LENGTH_reg : std_logic_vector(15 downto 0);
signal OCR1B_wreq : std_logic;
signal OCR1B_wack : std_logic;
signal OCR2A_FINE_reg : std_logic_vector(11 downto 0);
signal OCR2A_POL_reg : std_logic;
signal OCR2A_COARSE_reg : std_logic_vector(4 downto 0);
signal OCR2A_CONT_reg : std_logic;
signal OCR2A_TRIG_SEL_reg : std_logic;
signal OCR2A_wreq : std_logic;
signal OCR2A_wack : std_logic;
signal OCR2B_PPS_OFFS_reg : std_logic_vector(15 downto 0);
signal OCR2B_LENGTH_reg : std_logic_vector(15 downto 0);
signal OCR2B_wreq : std_logic;
signal OCR2B_wack : std_logic;
signal OCR3A_FINE_reg : std_logic_vector(11 downto 0);
signal OCR3A_POL_reg : std_logic;
signal OCR3A_COARSE_reg : std_logic_vector(4 downto 0);
signal OCR3A_CONT_reg : std_logic;
signal OCR3A_TRIG_SEL_reg : std_logic;
signal OCR3A_wreq : std_logic;
signal OCR3A_wack : std_logic;
signal OCR3B_PPS_OFFS_reg : std_logic_vector(15 downto 0);
signal OCR3B_LENGTH_reg : std_logic_vector(15 downto 0);
signal OCR3B_wreq : std_logic;
signal OCR3B_wack : std_logic;
signal OCR4A_FINE_reg : std_logic_vector(11 downto 0);
signal OCR4A_POL_reg : std_logic;
signal OCR4A_COARSE_reg : std_logic_vector(4 downto 0);
signal OCR4A_CONT_reg : std_logic;
signal OCR4A_TRIG_SEL_reg : std_logic;
signal OCR4A_wreq : std_logic;
signal OCR4A_wack : std_logic;
signal OCR4B_PPS_OFFS_reg : std_logic_vector(15 downto 0);
signal OCR4B_LENGTH_reg : std_logic_vector(15 downto 0);
signal OCR4B_wreq : std_logic;
signal OCR4B_wack : std_logic;
signal OCR5A_FINE_reg : std_logic_vector(11 downto 0);
signal OCR5A_POL_reg : std_logic;
signal OCR5A_COARSE_reg : std_logic_vector(4 downto 0);
signal OCR5A_CONT_reg : std_logic;
signal OCR5A_TRIG_SEL_reg : std_logic;
signal OCR5A_wreq : std_logic;
signal OCR5A_wack : std_logic;
signal OCR5B_PPS_OFFS_reg : std_logic_vector(15 downto 0);
signal OCR5B_LENGTH_reg : std_logic_vector(15 downto 0);
signal OCR5B_wreq : std_logic;
signal OCR5B_wack : std_logic;
signal odelay_calib_rst_idelayctrl_reg : std_logic;
signal odelay_calib_rst_odelay_reg : std_logic;
signal odelay_calib_rst_oserdes_reg : std_logic;
signal odelay_calib_value_update_reg : std_logic;
signal odelay_calib_en_vtc_reg : std_logic;
signal odelay_calib_cal_latch_reg : std_logic;
signal odelay_calib_wreq : std_logic;
signal odelay_calib_wack : std_logic;
signal rd_ack_d0 : std_logic;
signal rd_dat_d0 : std_logic_vector(31 downto 0);
signal wr_req_d0 : std_logic;
signal wr_adr_d0 : std_logic_vector(5 downto 2);
signal wr_dat_d0 : std_logic_vector(31 downto 0);
begin
-- WB decode signals
adr_int <= wb_i.adr(5 downto 2);
wb_en <= wb_i.cyc and wb_i.stb;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
wb_rip <= '0';
else
wb_rip <= (wb_rip or (wb_en and not wb_i.we)) and not rd_ack_int;
end if;
end if;
end process;
rd_req_int <= (wb_en and not wb_i.we) and not wb_rip;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
wb_wip <= '0';
else
wb_wip <= (wb_wip or (wb_en and wb_i.we)) and not wr_ack_int;
end if;
end if;
end process;
wr_req_int <= (wb_en and wb_i.we) and not wb_wip;
ack_int <= rd_ack_int or wr_ack_int;
wb_o.ack <= ack_int;
wb_o.stall <= not ack_int and wb_en;
wb_o.rty <= '0';
wb_o.err <= '0';
-- pipelining for wr-in+rd-out
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
rd_ack_int <= '0';
wr_req_d0 <= '0';
else
rd_ack_int <= rd_ack_d0;
wb_o.dat <= rd_dat_d0;
wr_req_d0 <= wr_req_int;
wr_adr_d0 <= adr_int;
wr_dat_d0 <= wb_i.dat;
end if;
end if;
end process;
-- Register csr
fpgen_regs_o.csr_TRIG0 <= csr_TRIG0_reg;
fpgen_regs_o.csr_TRIG1 <= csr_TRIG1_reg;
fpgen_regs_o.csr_TRIG2 <= csr_TRIG2_reg;
fpgen_regs_o.csr_TRIG3 <= csr_TRIG3_reg;
fpgen_regs_o.csr_TRIG4 <= csr_TRIG4_reg;
fpgen_regs_o.csr_TRIG5 <= csr_TRIG5_reg;
fpgen_regs_o.csr_TRIG6 <= csr_TRIG6_reg;
fpgen_regs_o.csr_TRIG7 <= csr_TRIG7_reg;
fpgen_regs_o.csr_FORCE0 <= csr_FORCE0_reg;
fpgen_regs_o.csr_FORCE1 <= csr_FORCE1_reg;
fpgen_regs_o.csr_FORCE2 <= csr_FORCE2_reg;
fpgen_regs_o.csr_FORCE3 <= csr_FORCE3_reg;
fpgen_regs_o.csr_FORCE4 <= csr_FORCE4_reg;
fpgen_regs_o.csr_FORCE5 <= csr_FORCE5_reg;
fpgen_regs_o.csr_READY <= wr_dat_d0(19 downto 14);
fpgen_regs_o.csr_PLL_RST <= csr_PLL_RST_reg;
fpgen_regs_o.csr_SERDES_RST <= csr_SERDES_RST_reg;
fpgen_regs_o.csr_PLL_LOCKED <= wr_dat_d0(22);
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
csr_TRIG0_reg <= '0';
csr_TRIG1_reg <= '0';
csr_TRIG2_reg <= '0';
csr_TRIG3_reg <= '0';
csr_TRIG4_reg <= '0';
csr_TRIG5_reg <= '0';
csr_TRIG6_reg <= '0';
csr_TRIG7_reg <= '0';
csr_FORCE0_reg <= '0';
csr_FORCE1_reg <= '0';
csr_FORCE2_reg <= '0';
csr_FORCE3_reg <= '0';
csr_FORCE4_reg <= '0';
csr_FORCE5_reg <= '0';
csr_PLL_RST_reg <= '0';
csr_SERDES_RST_reg <= '0';
csr_wack <= '0';
else
if csr_wreq = '1' then
csr_TRIG0_reg <= wr_dat_d0(0);
csr_TRIG1_reg <= wr_dat_d0(1);
csr_TRIG2_reg <= wr_dat_d0(2);
csr_TRIG3_reg <= wr_dat_d0(3);
csr_TRIG4_reg <= wr_dat_d0(4);
csr_TRIG5_reg <= wr_dat_d0(5);
csr_TRIG6_reg <= wr_dat_d0(6);
csr_TRIG7_reg <= wr_dat_d0(7);
csr_FORCE0_reg <= wr_dat_d0(8);
csr_FORCE1_reg <= wr_dat_d0(9);
csr_FORCE2_reg <= wr_dat_d0(10);
csr_FORCE3_reg <= wr_dat_d0(11);
csr_FORCE4_reg <= wr_dat_d0(12);
csr_FORCE5_reg <= wr_dat_d0(13);
csr_PLL_RST_reg <= wr_dat_d0(20);
csr_SERDES_RST_reg <= wr_dat_d0(21);
else
csr_TRIG0_reg <= '0';
csr_TRIG1_reg <= '0';
csr_TRIG2_reg <= '0';
csr_TRIG3_reg <= '0';
csr_TRIG4_reg <= '0';
csr_TRIG5_reg <= '0';
csr_TRIG6_reg <= '0';
csr_TRIG7_reg <= '0';
csr_FORCE0_reg <= '0';
csr_FORCE1_reg <= '0';
csr_FORCE2_reg <= '0';
csr_FORCE3_reg <= '0';
csr_FORCE4_reg <= '0';
csr_FORCE5_reg <= '0';
end if;
csr_wack <= csr_wreq;
end if;
end if;
end process;
-- Register OCR0A
fpgen_regs_o.OCR0A_FINE <= OCR0A_FINE_reg;
fpgen_regs_o.OCR0A_POL <= OCR0A_POL_reg;
fpgen_regs_o.OCR0A_COARSE <= OCR0A_COARSE_reg;
fpgen_regs_o.OCR0A_CONT <= OCR0A_CONT_reg;
fpgen_regs_o.OCR0A_TRIG_SEL <= OCR0A_TRIG_SEL_reg;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
OCR0A_FINE_reg <= "000000000000";
OCR0A_POL_reg <= '0';
OCR0A_COARSE_reg <= "00000";
OCR0A_CONT_reg <= '0';
OCR0A_TRIG_SEL_reg <= '0';
OCR0A_wack <= '0';
else
if OCR0A_wreq = '1' then
OCR0A_FINE_reg <= wr_dat_d0(11 downto 0);
OCR0A_POL_reg <= wr_dat_d0(12);
OCR0A_COARSE_reg <= wr_dat_d0(17 downto 13);
OCR0A_CONT_reg <= wr_dat_d0(18);
OCR0A_TRIG_SEL_reg <= wr_dat_d0(19);
end if;
OCR0A_wack <= OCR0A_wreq;
end if;
end if;
end process;
-- Register OCR0B
fpgen_regs_o.OCR0B_PPS_OFFS <= OCR0B_PPS_OFFS_reg;
fpgen_regs_o.OCR0B_LENGTH <= OCR0B_LENGTH_reg;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
OCR0B_PPS_OFFS_reg <= "0000000000000000";
OCR0B_LENGTH_reg <= "0000000000000000";
OCR0B_wack <= '0';
else
if OCR0B_wreq = '1' then
OCR0B_PPS_OFFS_reg <= wr_dat_d0(15 downto 0);
OCR0B_LENGTH_reg <= wr_dat_d0(31 downto 16);
end if;
OCR0B_wack <= OCR0B_wreq;
end if;
end if;
end process;
-- Register OCR1A
fpgen_regs_o.OCR1A_FINE <= OCR1A_FINE_reg;
fpgen_regs_o.OCR1A_POL <= OCR1A_POL_reg;
fpgen_regs_o.OCR1A_COARSE <= OCR1A_COARSE_reg;
fpgen_regs_o.OCR1A_CONT <= OCR1A_CONT_reg;
fpgen_regs_o.OCR1A_TRIG_SEL <= OCR1A_TRIG_SEL_reg;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
OCR1A_FINE_reg <= "000000000000";
OCR1A_POL_reg <= '0';
OCR1A_COARSE_reg <= "00000";
OCR1A_CONT_reg <= '0';
OCR1A_TRIG_SEL_reg <= '0';
OCR1A_wack <= '0';
else
if OCR1A_wreq = '1' then
OCR1A_FINE_reg <= wr_dat_d0(11 downto 0);
OCR1A_POL_reg <= wr_dat_d0(12);
OCR1A_COARSE_reg <= wr_dat_d0(17 downto 13);
OCR1A_CONT_reg <= wr_dat_d0(18);
OCR1A_TRIG_SEL_reg <= wr_dat_d0(19);
end if;
OCR1A_wack <= OCR1A_wreq;
end if;
end if;
end process;
-- Register OCR1B
fpgen_regs_o.OCR1B_PPS_OFFS <= OCR1B_PPS_OFFS_reg;
fpgen_regs_o.OCR1B_LENGTH <= OCR1B_LENGTH_reg;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
OCR1B_PPS_OFFS_reg <= "0000000000000000";
OCR1B_LENGTH_reg <= "0000000000000000";
OCR1B_wack <= '0';
else
if OCR1B_wreq = '1' then
OCR1B_PPS_OFFS_reg <= wr_dat_d0(15 downto 0);
OCR1B_LENGTH_reg <= wr_dat_d0(31 downto 16);
end if;
OCR1B_wack <= OCR1B_wreq;
end if;
end if;
end process;
-- Register OCR2A
fpgen_regs_o.OCR2A_FINE <= OCR2A_FINE_reg;
fpgen_regs_o.OCR2A_POL <= OCR2A_POL_reg;
fpgen_regs_o.OCR2A_COARSE <= OCR2A_COARSE_reg;
fpgen_regs_o.OCR2A_CONT <= OCR2A_CONT_reg;
fpgen_regs_o.OCR2A_TRIG_SEL <= OCR2A_TRIG_SEL_reg;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
OCR2A_FINE_reg <= "000000000000";
OCR2A_POL_reg <= '0';
OCR2A_COARSE_reg <= "00000";
OCR2A_CONT_reg <= '0';
OCR2A_TRIG_SEL_reg <= '0';
OCR2A_wack <= '0';
else
if OCR2A_wreq = '1' then
OCR2A_FINE_reg <= wr_dat_d0(11 downto 0);
OCR2A_POL_reg <= wr_dat_d0(12);
OCR2A_COARSE_reg <= wr_dat_d0(17 downto 13);
OCR2A_CONT_reg <= wr_dat_d0(18);
OCR2A_TRIG_SEL_reg <= wr_dat_d0(19);
end if;
OCR2A_wack <= OCR2A_wreq;
end if;
end if;
end process;
-- Register OCR2B
fpgen_regs_o.OCR2B_PPS_OFFS <= OCR2B_PPS_OFFS_reg;
fpgen_regs_o.OCR2B_LENGTH <= OCR2B_LENGTH_reg;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
OCR2B_PPS_OFFS_reg <= "0000000000000000";
OCR2B_LENGTH_reg <= "0000000000000000";
OCR2B_wack <= '0';
else
if OCR2B_wreq = '1' then
OCR2B_PPS_OFFS_reg <= wr_dat_d0(15 downto 0);
OCR2B_LENGTH_reg <= wr_dat_d0(31 downto 16);
end if;
OCR2B_wack <= OCR2B_wreq;
end if;
end if;
end process;
-- Register OCR3A
fpgen_regs_o.OCR3A_FINE <= OCR3A_FINE_reg;
fpgen_regs_o.OCR3A_POL <= OCR3A_POL_reg;
fpgen_regs_o.OCR3A_COARSE <= OCR3A_COARSE_reg;
fpgen_regs_o.OCR3A_CONT <= OCR3A_CONT_reg;
fpgen_regs_o.OCR3A_TRIG_SEL <= OCR3A_TRIG_SEL_reg;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
OCR3A_FINE_reg <= "000000000000";
OCR3A_POL_reg <= '0';
OCR3A_COARSE_reg <= "00000";
OCR3A_CONT_reg <= '0';
OCR3A_TRIG_SEL_reg <= '0';
OCR3A_wack <= '0';
else
if OCR3A_wreq = '1' then
OCR3A_FINE_reg <= wr_dat_d0(11 downto 0);
OCR3A_POL_reg <= wr_dat_d0(12);
OCR3A_COARSE_reg <= wr_dat_d0(17 downto 13);
OCR3A_CONT_reg <= wr_dat_d0(18);
OCR3A_TRIG_SEL_reg <= wr_dat_d0(19);
end if;
OCR3A_wack <= OCR3A_wreq;
end if;
end if;
end process;
-- Register OCR3B
fpgen_regs_o.OCR3B_PPS_OFFS <= OCR3B_PPS_OFFS_reg;
fpgen_regs_o.OCR3B_LENGTH <= OCR3B_LENGTH_reg;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
OCR3B_PPS_OFFS_reg <= "0000000000000000";
OCR3B_LENGTH_reg <= "0000000000000000";
OCR3B_wack <= '0';
else
if OCR3B_wreq = '1' then
OCR3B_PPS_OFFS_reg <= wr_dat_d0(15 downto 0);
OCR3B_LENGTH_reg <= wr_dat_d0(31 downto 16);
end if;
OCR3B_wack <= OCR3B_wreq;
end if;
end if;
end process;
-- Register OCR4A
fpgen_regs_o.OCR4A_FINE <= OCR4A_FINE_reg;
fpgen_regs_o.OCR4A_POL <= OCR4A_POL_reg;
fpgen_regs_o.OCR4A_COARSE <= OCR4A_COARSE_reg;
fpgen_regs_o.OCR4A_CONT <= OCR4A_CONT_reg;
fpgen_regs_o.OCR4A_TRIG_SEL <= OCR4A_TRIG_SEL_reg;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
OCR4A_FINE_reg <= "000000000000";
OCR4A_POL_reg <= '0';
OCR4A_COARSE_reg <= "00000";
OCR4A_CONT_reg <= '0';
OCR4A_TRIG_SEL_reg <= '0';
OCR4A_wack <= '0';
else
if OCR4A_wreq = '1' then
OCR4A_FINE_reg <= wr_dat_d0(11 downto 0);
OCR4A_POL_reg <= wr_dat_d0(12);
OCR4A_COARSE_reg <= wr_dat_d0(17 downto 13);
OCR4A_CONT_reg <= wr_dat_d0(18);
OCR4A_TRIG_SEL_reg <= wr_dat_d0(19);
end if;
OCR4A_wack <= OCR4A_wreq;
end if;
end if;
end process;
-- Register OCR4B
fpgen_regs_o.OCR4B_PPS_OFFS <= OCR4B_PPS_OFFS_reg;
fpgen_regs_o.OCR4B_LENGTH <= OCR4B_LENGTH_reg;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
OCR4B_PPS_OFFS_reg <= "0000000000000000";
OCR4B_LENGTH_reg <= "0000000000000000";
OCR4B_wack <= '0';
else
if OCR4B_wreq = '1' then
OCR4B_PPS_OFFS_reg <= wr_dat_d0(15 downto 0);
OCR4B_LENGTH_reg <= wr_dat_d0(31 downto 16);
end if;
OCR4B_wack <= OCR4B_wreq;
end if;
end if;
end process;
-- Register OCR5A
fpgen_regs_o.OCR5A_FINE <= OCR5A_FINE_reg;
fpgen_regs_o.OCR5A_POL <= OCR5A_POL_reg;
fpgen_regs_o.OCR5A_COARSE <= OCR5A_COARSE_reg;
fpgen_regs_o.OCR5A_CONT <= OCR5A_CONT_reg;
fpgen_regs_o.OCR5A_TRIG_SEL <= OCR5A_TRIG_SEL_reg;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
OCR5A_FINE_reg <= "000000000000";
OCR5A_POL_reg <= '0';
OCR5A_COARSE_reg <= "00000";
OCR5A_CONT_reg <= '0';
OCR5A_TRIG_SEL_reg <= '0';
OCR5A_wack <= '0';
else
if OCR5A_wreq = '1' then
OCR5A_FINE_reg <= wr_dat_d0(11 downto 0);
OCR5A_POL_reg <= wr_dat_d0(12);
OCR5A_COARSE_reg <= wr_dat_d0(17 downto 13);
OCR5A_CONT_reg <= wr_dat_d0(18);
OCR5A_TRIG_SEL_reg <= wr_dat_d0(19);
end if;
OCR5A_wack <= OCR5A_wreq;
end if;
end if;
end process;
-- Register OCR5B
fpgen_regs_o.OCR5B_PPS_OFFS <= OCR5B_PPS_OFFS_reg;
fpgen_regs_o.OCR5B_LENGTH <= OCR5B_LENGTH_reg;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
OCR5B_PPS_OFFS_reg <= "0000000000000000";
OCR5B_LENGTH_reg <= "0000000000000000";
OCR5B_wack <= '0';
else
if OCR5B_wreq = '1' then
OCR5B_PPS_OFFS_reg <= wr_dat_d0(15 downto 0);
OCR5B_LENGTH_reg <= wr_dat_d0(31 downto 16);
end if;
OCR5B_wack <= OCR5B_wreq;
end if;
end if;
end process;
-- Register odelay_calib
fpgen_regs_o.odelay_calib_rst_idelayctrl <= odelay_calib_rst_idelayctrl_reg;
fpgen_regs_o.odelay_calib_rst_odelay <= odelay_calib_rst_odelay_reg;
fpgen_regs_o.odelay_calib_rst_oserdes <= odelay_calib_rst_oserdes_reg;
fpgen_regs_o.odelay_calib_rdy <= wr_dat_d0(3);
fpgen_regs_o.odelay_calib_value <= wr_dat_d0(12 downto 4);
fpgen_regs_o.odelay_calib_value_update <= odelay_calib_value_update_reg;
fpgen_regs_o.odelay_calib_en_vtc <= odelay_calib_en_vtc_reg;
fpgen_regs_o.odelay_calib_cal_latch <= odelay_calib_cal_latch_reg;
fpgen_regs_o.odelay_calib_taps <= wr_dat_d0(24 downto 16);
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
odelay_calib_rst_idelayctrl_reg <= '0';
odelay_calib_rst_odelay_reg <= '0';
odelay_calib_rst_oserdes_reg <= '0';
odelay_calib_value_update_reg <= '0';
odelay_calib_en_vtc_reg <= '0';
odelay_calib_cal_latch_reg <= '0';
odelay_calib_wack <= '0';
else
if odelay_calib_wreq = '1' then
odelay_calib_rst_idelayctrl_reg <= wr_dat_d0(0);
odelay_calib_rst_odelay_reg <= wr_dat_d0(1);
odelay_calib_rst_oserdes_reg <= wr_dat_d0(2);
odelay_calib_value_update_reg <= wr_dat_d0(13);
odelay_calib_en_vtc_reg <= wr_dat_d0(14);
odelay_calib_cal_latch_reg <= wr_dat_d0(15);
else
odelay_calib_value_update_reg <= '0';
odelay_calib_cal_latch_reg <= '0';
end if;
odelay_calib_wack <= odelay_calib_wreq;
end if;
end if;
end process;
-- Process for write requests.
process (wr_adr_d0, wr_req_d0, csr_wack, OCR0A_wack, OCR0B_wack, OCR1A_wack,
OCR1B_wack, OCR2A_wack, OCR2B_wack, OCR3A_wack, OCR3B_wack, OCR4A_wack,
OCR4B_wack, OCR5A_wack, OCR5B_wack, odelay_calib_wack) begin
csr_wreq <= '0';
OCR0A_wreq <= '0';
OCR0B_wreq <= '0';
OCR1A_wreq <= '0';
OCR1B_wreq <= '0';
OCR2A_wreq <= '0';
OCR2B_wreq <= '0';
OCR3A_wreq <= '0';
OCR3B_wreq <= '0';
OCR4A_wreq <= '0';
OCR4B_wreq <= '0';
OCR5A_wreq <= '0';
OCR5B_wreq <= '0';
odelay_calib_wreq <= '0';
case wr_adr_d0(5 downto 2) is
when "0000" =>
-- Reg csr
csr_wreq <= wr_req_d0;
wr_ack_int <= csr_wack;
when "0001" =>
-- Reg OCR0A
OCR0A_wreq <= wr_req_d0;
wr_ack_int <= OCR0A_wack;
when "0010" =>
-- Reg OCR0B
OCR0B_wreq <= wr_req_d0;
wr_ack_int <= OCR0B_wack;
when "0011" =>
-- Reg OCR1A
OCR1A_wreq <= wr_req_d0;
wr_ack_int <= OCR1A_wack;
when "0100" =>
-- Reg OCR1B
OCR1B_wreq <= wr_req_d0;
wr_ack_int <= OCR1B_wack;
when "0101" =>
-- Reg OCR2A
OCR2A_wreq <= wr_req_d0;
wr_ack_int <= OCR2A_wack;
when "0110" =>
-- Reg OCR2B
OCR2B_wreq <= wr_req_d0;
wr_ack_int <= OCR2B_wack;
when "0111" =>
-- Reg OCR3A
OCR3A_wreq <= wr_req_d0;
wr_ack_int <= OCR3A_wack;
when "1000" =>
-- Reg OCR3B
OCR3B_wreq <= wr_req_d0;
wr_ack_int <= OCR3B_wack;
when "1001" =>
-- Reg OCR4A
OCR4A_wreq <= wr_req_d0;
wr_ack_int <= OCR4A_wack;
when "1010" =>
-- Reg OCR4B
OCR4B_wreq <= wr_req_d0;
wr_ack_int <= OCR4B_wack;
when "1011" =>
-- Reg OCR5A
OCR5A_wreq <= wr_req_d0;
wr_ack_int <= OCR5A_wack;
when "1100" =>
-- Reg OCR5B
OCR5B_wreq <= wr_req_d0;
wr_ack_int <= OCR5B_wack;
when "1101" =>
-- Reg odelay_calib
odelay_calib_wreq <= wr_req_d0;
wr_ack_int <= odelay_calib_wack;
when others =>
wr_ack_int <= wr_req_d0;
end case;
end process;
-- Process for read requests.
process (adr_int, rd_req_int, fpgen_regs_i.csr_READY, csr_PLL_RST_reg,
csr_SERDES_RST_reg, fpgen_regs_i.csr_PLL_LOCKED, OCR0A_FINE_reg,
OCR0A_POL_reg, OCR0A_COARSE_reg, OCR0A_CONT_reg, OCR0A_TRIG_SEL_reg,
OCR0B_PPS_OFFS_reg, OCR0B_LENGTH_reg, OCR1A_FINE_reg, OCR1A_POL_reg,
OCR1A_COARSE_reg, OCR1A_CONT_reg, OCR1A_TRIG_SEL_reg,
OCR1B_PPS_OFFS_reg, OCR1B_LENGTH_reg, OCR2A_FINE_reg, OCR2A_POL_reg,
OCR2A_COARSE_reg, OCR2A_CONT_reg, OCR2A_TRIG_SEL_reg,
OCR2B_PPS_OFFS_reg, OCR2B_LENGTH_reg, OCR3A_FINE_reg, OCR3A_POL_reg,
OCR3A_COARSE_reg, OCR3A_CONT_reg, OCR3A_TRIG_SEL_reg,
OCR3B_PPS_OFFS_reg, OCR3B_LENGTH_reg, OCR4A_FINE_reg, OCR4A_POL_reg,
OCR4A_COARSE_reg, OCR4A_CONT_reg, OCR4A_TRIG_SEL_reg,
OCR4B_PPS_OFFS_reg, OCR4B_LENGTH_reg, OCR5A_FINE_reg, OCR5A_POL_reg,
OCR5A_COARSE_reg, OCR5A_CONT_reg, OCR5A_TRIG_SEL_reg,
OCR5B_PPS_OFFS_reg, OCR5B_LENGTH_reg,
odelay_calib_rst_idelayctrl_reg, odelay_calib_rst_odelay_reg,
odelay_calib_rst_oserdes_reg, fpgen_regs_i.odelay_calib_rdy,
fpgen_regs_i.odelay_calib_value, odelay_calib_en_vtc_reg,
fpgen_regs_i.odelay_calib_taps) begin
-- By default ack read requests
rd_dat_d0 <= (others => 'X');
case adr_int(5 downto 2) is
when "0000" =>
-- Reg csr
rd_ack_d0 <= rd_req_int;
rd_dat_d0(0) <= '0';
rd_dat_d0(1) <= '0';
rd_dat_d0(2) <= '0';
rd_dat_d0(3) <= '0';
rd_dat_d0(4) <= '0';
rd_dat_d0(5) <= '0';
rd_dat_d0(6) <= '0';
rd_dat_d0(7) <= '0';
rd_dat_d0(8) <= '0';
rd_dat_d0(9) <= '0';
rd_dat_d0(10) <= '0';
rd_dat_d0(11) <= '0';
rd_dat_d0(12) <= '0';
rd_dat_d0(13) <= '0';
rd_dat_d0(19 downto 14) <= fpgen_regs_i.csr_READY;
rd_dat_d0(20) <= csr_PLL_RST_reg;
rd_dat_d0(21) <= csr_SERDES_RST_reg;
rd_dat_d0(22) <= fpgen_regs_i.csr_PLL_LOCKED;
rd_dat_d0(31 downto 23) <= (others => '0');
when "0001" =>
-- Reg OCR0A
rd_ack_d0 <= rd_req_int;
rd_dat_d0(11 downto 0) <= OCR0A_FINE_reg;
rd_dat_d0(12) <= OCR0A_POL_reg;
rd_dat_d0(17 downto 13) <= OCR0A_COARSE_reg;
rd_dat_d0(18) <= OCR0A_CONT_reg;
rd_dat_d0(19) <= OCR0A_TRIG_SEL_reg;
rd_dat_d0(31 downto 20) <= (others => '0');
when "0010" =>
-- Reg OCR0B
rd_ack_d0 <= rd_req_int;
rd_dat_d0(15 downto 0) <= OCR0B_PPS_OFFS_reg;
rd_dat_d0(31 downto 16) <= OCR0B_LENGTH_reg;
when "0011" =>
-- Reg OCR1A
rd_ack_d0 <= rd_req_int;
rd_dat_d0(11 downto 0) <= OCR1A_FINE_reg;
rd_dat_d0(12) <= OCR1A_POL_reg;
rd_dat_d0(17 downto 13) <= OCR1A_COARSE_reg;
rd_dat_d0(18) <= OCR1A_CONT_reg;
rd_dat_d0(19) <= OCR1A_TRIG_SEL_reg;
rd_dat_d0(31 downto 20) <= (others => '0');
when "0100" =>
-- Reg OCR1B
rd_ack_d0 <= rd_req_int;
rd_dat_d0(15 downto 0) <= OCR1B_PPS_OFFS_reg;
rd_dat_d0(31 downto 16) <= OCR1B_LENGTH_reg;
when "0101" =>
-- Reg OCR2A
rd_ack_d0 <= rd_req_int;
rd_dat_d0(11 downto 0) <= OCR2A_FINE_reg;
rd_dat_d0(12) <= OCR2A_POL_reg;
rd_dat_d0(17 downto 13) <= OCR2A_COARSE_reg;
rd_dat_d0(18) <= OCR2A_CONT_reg;
rd_dat_d0(19) <= OCR2A_TRIG_SEL_reg;
rd_dat_d0(31 downto 20) <= (others => '0');
when "0110" =>
-- Reg OCR2B
rd_ack_d0 <= rd_req_int;
rd_dat_d0(15 downto 0) <= OCR2B_PPS_OFFS_reg;
rd_dat_d0(31 downto 16) <= OCR2B_LENGTH_reg;
when "0111" =>
-- Reg OCR3A
rd_ack_d0 <= rd_req_int;
rd_dat_d0(11 downto 0) <= OCR3A_FINE_reg;
rd_dat_d0(12) <= OCR3A_POL_reg;
rd_dat_d0(17 downto 13) <= OCR3A_COARSE_reg;
rd_dat_d0(18) <= OCR3A_CONT_reg;
rd_dat_d0(19) <= OCR3A_TRIG_SEL_reg;
rd_dat_d0(31 downto 20) <= (others => '0');
when "1000" =>
-- Reg OCR3B
rd_ack_d0 <= rd_req_int;
rd_dat_d0(15 downto 0) <= OCR3B_PPS_OFFS_reg;
rd_dat_d0(31 downto 16) <= OCR3B_LENGTH_reg;
when "1001" =>
-- Reg OCR4A
rd_ack_d0 <= rd_req_int;
rd_dat_d0(11 downto 0) <= OCR4A_FINE_reg;
rd_dat_d0(12) <= OCR4A_POL_reg;
rd_dat_d0(17 downto 13) <= OCR4A_COARSE_reg;
rd_dat_d0(18) <= OCR4A_CONT_reg;
rd_dat_d0(19) <= OCR4A_TRIG_SEL_reg;
rd_dat_d0(31 downto 20) <= (others => '0');
when "1010" =>
-- Reg OCR4B
rd_ack_d0 <= rd_req_int;
rd_dat_d0(15 downto 0) <= OCR4B_PPS_OFFS_reg;
rd_dat_d0(31 downto 16) <= OCR4B_LENGTH_reg;
when "1011" =>
-- Reg OCR5A
rd_ack_d0 <= rd_req_int;
rd_dat_d0(11 downto 0) <= OCR5A_FINE_reg;
rd_dat_d0(12) <= OCR5A_POL_reg;
rd_dat_d0(17 downto 13) <= OCR5A_COARSE_reg;
rd_dat_d0(18) <= OCR5A_CONT_reg;
rd_dat_d0(19) <= OCR5A_TRIG_SEL_reg;
rd_dat_d0(31 downto 20) <= (others => '0');
when "1100" =>
-- Reg OCR5B
rd_ack_d0 <= rd_req_int;
rd_dat_d0(15 downto 0) <= OCR5B_PPS_OFFS_reg;
rd_dat_d0(31 downto 16) <= OCR5B_LENGTH_reg;
when "1101" =>
-- Reg odelay_calib
rd_ack_d0 <= rd_req_int;
rd_dat_d0(0) <= odelay_calib_rst_idelayctrl_reg;
rd_dat_d0(1) <= odelay_calib_rst_odelay_reg;
rd_dat_d0(2) <= odelay_calib_rst_oserdes_reg;
rd_dat_d0(3) <= fpgen_regs_i.odelay_calib_rdy;
rd_dat_d0(12 downto 4) <= fpgen_regs_i.odelay_calib_value;
rd_dat_d0(13) <= '0';
rd_dat_d0(14) <= odelay_calib_en_vtc_reg;
rd_dat_d0(15) <= '0';
rd_dat_d0(24 downto 16) <= fpgen_regs_i.odelay_calib_taps;
rd_dat_d0(31 downto 25) <= (others => '0');
when others =>
rd_ack_d0 <= rd_req_int;
end case;
end process;
end syn;
......@@ -5,7 +5,7 @@ use ieee.numeric_std.all;
use work.gencores_pkg.all;
use work.wishbone_pkg.all;
use work.fpg_wbgen2_pkg.all;
use work.wb_fpgen_regs_pkg.all;
--library unisim;
--use unisim.VCOMPONENTS.all;
......@@ -52,34 +52,6 @@ architecture rtl of xwb_fine_pulse_gen is
component fine_pulse_gen_kintex7_shared is
generic (
g_global_use_odelay : boolean;
g_use_external_serdes_clock : boolean);
port (
pll_rst_i : in std_logic;
clk_ser_ext_i : in std_logic;
clk_ref_i : in std_logic;
clk_par_o : out std_logic;
clk_ser_o : out std_logic;
clk_odelay_o : out std_logic;
pll_locked_o : out std_logic);
end component fine_pulse_gen_kintex7_shared;
component fine_pulse_gen_kintexultrascale_shared is
generic (
g_global_use_odelay : boolean;
g_use_external_serdes_clock : boolean
);
port (
pll_rst_i : in std_logic;
clk_ser_ext_i : in std_logic;
clk_ref_i : in std_logic;
clk_par_o : out std_logic;
clk_ser_o : out std_logic;
clk_odelay_o : out std_logic;
pll_locked_o : out std_logic);
end component fine_pulse_gen_kintexultrascale_shared;
type t_channel_state is (IDLE, WAIT_PPS, WAIT_PPS_FORCED, WAIT_TRIGGER);
......@@ -93,17 +65,17 @@ architecture rtl of xwb_fine_pulse_gen is
ready : std_logic;
pol : std_logic;
cnt : unsigned(3 downto 0);
pps_offs : unsigned(3 downto 0);
mask : std_logic_vector(7 downto 0);
pps_offs : unsigned(15 downto 0);
coarse : std_logic_vector(3 downto 0);
delay_load : std_logic;
delay_fine : std_logic_vector(8 downto 0);
delay_fine : std_logic_vector(11 downto 0);
length: std_logic_vector(23 downto 0);
cont : std_logic;
force_tr : std_logic;
phy_ready : std_logic;
trig_ready : std_logic;
odelay_load : std_logic;
odelay_value_out : std_logic_vector(8 downto 0);
end record;
type t_channel_array is array(integer range <>) of t_channel;
......@@ -116,8 +88,8 @@ architecture rtl of xwb_fine_pulse_gen is
signal clk_ser : std_logic;
signal clk_odelay : std_logic;
signal regs_out : t_fpg_out_registers;
signal regs_in : t_fpg_in_registers;
signal regs_out : t_fpgen_regs_master_out;
signal regs_in : t_fpgen_regs_master_in;
signal rst_n_wr : std_logic;
signal pps_p_d : std_logic;
......@@ -171,14 +143,14 @@ begin
end if;
end process;
U_Regs : entity work.fine_pulse_gen_wb
U_Regs : entity work.wb_fpgen_regs
port map (
rst_n_i => rst_sys_n_i,
clk_sys_i => clk_sys_i,
slave_i => slave_i,
slave_o => slave_o,
regs_i => regs_in,
regs_o => regs_out);
clk_i => clk_sys_i,
wb_i => slave_i,
wb_o => slave_o,
fpgen_regs_i => regs_in,
fpgen_regs_o => regs_out);
U_Sync_Reset : gc_sync_ffs
port map (
......@@ -189,90 +161,102 @@ begin
);
U_Sync1: entity work.gc_pulse_synchronizer
U_Sync1: entity work.gc_pulse_synchronizer2
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_ref_i,
rst_n_i => rst_sys_n_i,
d_p_i => regs_out.csr_trig0_o,
rst_in_n_i => rst_sys_n_i,
rst_out_n_i => rst_n_wr,
d_p_i => regs_out.csr_trig0,
q_p_o => ch(0).arm);
U_Sync2: entity work.gc_pulse_synchronizer
U_Sync2: entity work.gc_pulse_synchronizer2
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_ref_i,
rst_n_i => rst_sys_n_i,
d_p_i => regs_out.csr_trig1_o,
rst_in_n_i => rst_sys_n_i,
rst_out_n_i => rst_n_wr,
d_p_i => regs_out.csr_trig1,
q_p_o => ch(1).arm);
U_Sync3: entity work.gc_pulse_synchronizer
U_Sync3: entity work.gc_pulse_synchronizer2
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_ref_i,
rst_n_i => rst_sys_n_i,
d_p_i => regs_out.csr_trig2_o,
rst_in_n_i => rst_sys_n_i,
rst_out_n_i => rst_n_wr,
d_p_i => regs_out.csr_trig2,
q_p_o => ch(2).arm);
U_Sync4: entity work.gc_pulse_synchronizer
U_Sync4: entity work.gc_pulse_synchronizer2
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_ref_i,
rst_n_i => rst_sys_n_i,
d_p_i => regs_out.csr_trig3_o,
rst_in_n_i => rst_sys_n_i,
rst_out_n_i => rst_n_wr,
d_p_i => regs_out.csr_trig3,
q_p_o => ch(3).arm);
U_Sync5: entity work.gc_pulse_synchronizer
U_Sync5: entity work.gc_pulse_synchronizer2
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_ref_i,
rst_n_i => rst_sys_n_i,
d_p_i => regs_out.csr_trig4_o,
rst_in_n_i => rst_sys_n_i,
rst_out_n_i => rst_n_wr,
d_p_i => regs_out.csr_trig4,
q_p_o => ch(4).arm);
U_Sync6: entity work.gc_pulse_synchronizer
U_Sync6: entity work.gc_pulse_synchronizer2
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_ref_i,
rst_n_i => rst_sys_n_i,
d_p_i => regs_out.csr_trig5_o,
rst_in_n_i => rst_sys_n_i,
rst_out_n_i => rst_n_wr,
d_p_i => regs_out.csr_trig5,
q_p_o => ch(5).arm);
U_Sync71: entity work.gc_pulse_synchronizer
U_Sync71: entity work.gc_pulse_synchronizer2
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_ref_i,
rst_n_i => rst_sys_n_i,
d_p_i => regs_out.csr_force0_o,
rst_in_n_i => rst_sys_n_i,
rst_out_n_i => rst_n_wr,
d_p_i => regs_out.csr_force0,
q_p_o => ch(0).force_tr);
U_Sync72: entity work.gc_pulse_synchronizer
U_Sync72: entity work.gc_pulse_synchronizer2
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_ref_i,
rst_n_i => rst_sys_n_i,
d_p_i => regs_out.csr_force1_o,
rst_in_n_i => rst_sys_n_i,
rst_out_n_i => rst_n_wr,
d_p_i => regs_out.csr_force1,
q_p_o => ch(1).force_tr);
U_Sync73: entity work.gc_pulse_synchronizer
U_Sync73: entity work.gc_pulse_synchronizer2
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_ref_i,
rst_n_i => rst_sys_n_i,
d_p_i => regs_out.csr_force2_o,
rst_in_n_i => rst_sys_n_i,
rst_out_n_i => rst_n_wr,
d_p_i => regs_out.csr_force2,
q_p_o => ch(2).force_tr);
U_Sync74: entity work.gc_pulse_synchronizer
U_Sync74: entity work.gc_pulse_synchronizer2
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_ref_i,
rst_n_i => rst_sys_n_i,
d_p_i => regs_out.csr_force3_o,
rst_in_n_i => rst_sys_n_i,
rst_out_n_i => rst_n_wr,
d_p_i => regs_out.csr_force3,
q_p_o => ch(3).force_tr);
U_Sync75: entity work.gc_pulse_synchronizer
U_Sync75: entity work.gc_pulse_synchronizer2
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_ref_i,
rst_n_i => rst_sys_n_i,
d_p_i => regs_out.csr_force4_o,
rst_in_n_i => rst_sys_n_i,
rst_out_n_i => rst_n_wr,
d_p_i => regs_out.csr_force4,
q_p_o => ch(4).force_tr);
U_Sync76: entity work.gc_pulse_synchronizer
U_Sync76: entity work.gc_pulse_synchronizer2
port map (
clk_in_i => clk_sys_i,
clk_out_i => clk_ref_i,
rst_n_i => rst_sys_n_i,
d_p_i => regs_out.csr_force5_o,
rst_in_n_i => rst_sys_n_i,
rst_out_n_i => rst_n_wr,
d_p_i => regs_out.csr_force5,
q_p_o => ch(5).force_tr);
......@@ -283,11 +267,11 @@ begin
clk_i => clk_sys_i,
rst_n_i => rst_sys_n_i,
data_i => ch(i).ready,
synced_o => regs_in.csr_ready_i(i)
synced_o => regs_in.csr_ready(i)
);
end generate gen_ready_flags;
rst_serdes_in <= regs_out.odelay_calib_rst_oserdes_o or regs_out.csr_serdes_rst_o;
rst_serdes_in <= regs_out.odelay_calib_rst_oserdes or regs_out.csr_serdes_rst;
U_Sync_Serdes_Reset : gc_sync_ffs
port map (
......@@ -297,54 +281,65 @@ begin
synced_o => rst_serdes
);
ch(0).pol <= regs_out.ocr0_pol_o;
ch(1).pol <= regs_out.ocr1_pol_o;
ch(2).pol <= regs_out.ocr2_pol_o;
ch(3).pol <= regs_out.ocr3_pol_o;
ch(4).pol <= regs_out.ocr4_pol_o;
ch(5).pol <= regs_out.ocr5_pol_o;
ch(0).delay_fine <= regs_out.ocr0_fine_o;
ch(1).delay_fine <= regs_out.ocr1_fine_o;
ch(2).delay_fine <= regs_out.ocr2_fine_o;
ch(3).delay_fine <= regs_out.ocr3_fine_o;
ch(4).delay_fine <= regs_out.ocr4_fine_o;
ch(5).delay_fine <= regs_out.ocr5_fine_o;
ch(0).mask <= regs_out.ocr0_mask_o;
ch(1).mask <= regs_out.ocr1_mask_o;
ch(2).mask <= regs_out.ocr2_mask_o;
ch(3).mask <= regs_out.ocr3_mask_o;
ch(4).mask <= regs_out.ocr4_mask_o;
ch(5).mask <= regs_out.ocr5_mask_o;
ch(0).cont <= regs_out.ocr0_cont_o;
ch(1).cont <= regs_out.ocr1_cont_o;
ch(2).cont <= regs_out.ocr2_cont_o;
ch(3).cont <= regs_out.ocr3_cont_o;
ch(4).cont <= regs_out.ocr4_cont_o;
ch(5).cont <= regs_out.ocr5_cont_o;
ch(0).trig_sel <= regs_out.ocr0_trig_sel_o;
ch(1).trig_sel <= regs_out.ocr1_trig_sel_o;
ch(2).trig_sel <= regs_out.ocr2_trig_sel_o;
ch(3).trig_sel <= regs_out.ocr3_trig_sel_o;
ch(4).trig_sel <= regs_out.ocr4_trig_sel_o;
ch(5).trig_sel <= regs_out.ocr5_trig_sel_o;
ch(0).pps_offs <= unsigned(regs_out.ocr0_pps_offs_o);
ch(1).pps_offs <= unsigned(regs_out.ocr1_pps_offs_o);
ch(2).pps_offs <= unsigned(regs_out.ocr2_pps_offs_o);
ch(3).pps_offs <= unsigned(regs_out.ocr3_pps_offs_o);
ch(4).pps_offs <= unsigned(regs_out.ocr4_pps_offs_o);
ch(5).pps_offs <= unsigned(regs_out.ocr5_pps_offs_o);
ch(0).odelay_load <= '0';
ch(1).odelay_load <= '0';
ch(2).odelay_load <= '0';
ch(3).odelay_load <= '0';
ch(4).odelay_load <= '0';
ch(5).odelay_load <= '0';
ch(0).pol <= regs_out.ocr0a_pol;
ch(1).pol <= regs_out.ocr1a_pol;
ch(2).pol <= regs_out.ocr2a_pol;
ch(3).pol <= regs_out.ocr3a_pol;
ch(4).pol <= regs_out.ocr4a_pol;
ch(5).pol <= regs_out.ocr5a_pol;
ch(0).delay_fine <= regs_out.ocr0a_fine;
ch(1).delay_fine <= regs_out.ocr1a_fine;
ch(2).delay_fine <= regs_out.ocr2a_fine;
ch(3).delay_fine <= regs_out.ocr3a_fine;
ch(4).delay_fine <= regs_out.ocr4a_fine;
ch(5).delay_fine <= regs_out.ocr5a_fine;
ch(0).coarse <= regs_out.ocr0a_coarse(3 downto 0);
ch(1).coarse <= regs_out.ocr1a_coarse(3 downto 0);
ch(2).coarse <= regs_out.ocr2a_coarse(3 downto 0);
ch(3).coarse <= regs_out.ocr3a_coarse(3 downto 0);
ch(4).coarse <= regs_out.ocr4a_coarse(3 downto 0);
ch(5).coarse <= regs_out.ocr5a_coarse(3 downto 0);
ch(0).length <= "0000" & regs_out.ocr0b_length & "0000";
ch(1).length <= "0000" & regs_out.ocr1b_length & "0000";
ch(2).length <= "0000" & regs_out.ocr2b_length & "0000";
ch(3).length <= "0000" & regs_out.ocr3b_length & "0000";
ch(4).length <= "0000" & regs_out.ocr4b_length & "0000";
ch(5).length <= "0000" & regs_out.ocr5b_length & "0000";
ch(0).cont <= regs_out.ocr0a_cont;
ch(1).cont <= regs_out.ocr1a_cont;
ch(2).cont <= regs_out.ocr2a_cont;
ch(3).cont <= regs_out.ocr3a_cont;
ch(4).cont <= regs_out.ocr4a_cont;
ch(5).cont <= regs_out.ocr5a_cont;
ch(0).trig_sel <= regs_out.ocr0a_trig_sel;
ch(1).trig_sel <= regs_out.ocr1a_trig_sel;
ch(2).trig_sel <= regs_out.ocr2a_trig_sel;
ch(3).trig_sel <= regs_out.ocr3a_trig_sel;
ch(4).trig_sel <= regs_out.ocr4a_trig_sel;
ch(5).trig_sel <= regs_out.ocr5a_trig_sel;
ch(0).pps_offs <= unsigned(regs_out.ocr0b_pps_offs);
ch(1).pps_offs <= unsigned(regs_out.ocr1b_pps_offs);
ch(2).pps_offs <= unsigned(regs_out.ocr2b_pps_offs);
ch(3).pps_offs <= unsigned(regs_out.ocr3b_pps_offs);
ch(4).pps_offs <= unsigned(regs_out.ocr4b_pps_offs);
ch(5).pps_offs <= unsigned(regs_out.ocr5b_pps_offs);
gen_channels : for i in 0 to g_NUM_CHANNELS-1 generate
ch(i).ready <= ch(i).trig_ready and ch(i).phy_ready;
p_fsm : process(clk_ref_i)
begin
......@@ -353,6 +348,7 @@ begin
ch(i).state <= IDLE;
ch(i).trig_p <= '0';
ch(i).delay_load <= '0';
ch(i).trig_ready <= '0';
else
if ch(i).trig_sel = '1' then
......@@ -370,20 +366,18 @@ begin
if ch(i).force_tr = '1' then
ch(i).ready <= '0';
ch(i).trig_ready <= '0';
ch(i).cnt <= (others => '0');
ch(i).state <= WAIT_PPS_FORCED;
ch(i).delay_load <= '1';
elsif ch(i).arm = '1' then
ch(i).ready <= '0';
ch(i).trig_ready <= '0';
ch(i).cnt <= (others => '0');
ch(i).state <= WAIT_PPS;
ch(i).delay_load <= '1';
else
ch(i).delay_load <= '0';
ch(i).ready <= '1';
ch(i).trig_ready <= '1';
end if;
when WAIT_PPS_FORCED =>
......@@ -428,12 +422,14 @@ begin
clk_par_i => clk_par,
clk_serdes_i => clk_ser,
rst_serdes_i => rst_serdes,
rst_sys_n_i => rst_sys_n_i,
rst_par_n_i => rst_n_wr,
trig_p_i => ch(I).trig_p,
cont_i => ch(i).cont,
coarse_i => ch(I).mask,
coarse_i => ch(I).coarse,
length_i => ch(i).length,
pol_i => ch(I).pol,
pulse_o => pulse_o(i),
ready_o => ch(I).phy_ready,
dly_load_i => ch(i).delay_load,
dly_fine_i => ch(i).delay_fine(4 downto 0));
......@@ -455,18 +451,20 @@ begin
rst_sys_n_i => rst_sys_n_i,
trig_p_i => ch(I).trig_p,
cont_i => ch(i).cont,
coarse_i => ch(I).mask,
coarse_i => ("0000" & ch(I).coarse),
-- length_i => ch(i).length, -- fixme: ultrascale PG doesn't support length
pol_i => ch(I).pol,
pulse_o => pulse_o(i),
dly_load_i => ch(i).delay_load,
dly_fine_i => ch(i).delay_fine,
dly_fine_i => ch(i).delay_fine(8 downto 0),
ready_o => ch(I).phy_ready,
odelay_load_i => ch(i).odelay_load,
odelay_en_vtc_i => regs_out.odelay_calib_en_vtc_o,
odelay_rst_i => regs_out.odelay_calib_rst_odelay_o,
odelay_value_in_i => regs_out.odelay_calib_value_o,
odelay_en_vtc_i => regs_out.odelay_calib_en_vtc,
odelay_rst_i => regs_out.odelay_calib_rst_odelay,
odelay_value_in_i => regs_out.odelay_calib_value,
odelay_value_out_o => ch(i).odelay_value_out,
odelay_cal_latch_i => regs_out.odelay_calib_cal_latch_o
odelay_cal_latch_i => regs_out.odelay_calib_cal_latch
);
......@@ -475,23 +473,34 @@ begin
end generate;
regs_in.odelay_calib_taps_i <= ch(0).odelay_value_out;
regs_in.odelay_calib_taps <= ch(0).odelay_value_out;
gen_is_kintex7: if g_target_platform = "Kintex7" generate
U_K7_Shared: fine_pulse_gen_kintex7_shared
U_K7_Shared: entity work.fine_pulse_gen_kintex7_shared
generic map (
g_global_use_odelay => f_global_use_odelay,
g_use_external_serdes_clock => g_use_external_serdes_clock)
port map (
pll_rst_i => regs_out.csr_pll_rst_o,
pll_rst_i => regs_out.csr_pll_rst,
clk_ref_i => clk_ref_i,
clk_par_o => clk_par,
clk_ser_o => clk_ser,
clk_ser_ext_i => clk_ser_ext_i,
-- clk_odelay_o => clk_odelay,
pll_locked_o => pll_locked);
pll_locked_o => pll_locked,
idelayctrl_rdy_o => odelay_calib_rdy,
idelayctrl_rst_i => regs_out.odelay_calib_rst_idelayctrl
);
U_Sync_Reset : gc_sync_ffs
port map (
clk_i => clk_sys_i,
rst_n_i => rst_sys_n_i,
data_i => odelay_calib_rdy,
synced_o => regs_in.odelay_calib_rdy
);
end generate gen_is_kintex7;
......@@ -503,7 +512,7 @@ begin
g_use_external_serdes_clock => g_use_external_serdes_clock
)
port map (
pll_rst_i => regs_out.csr_pll_rst_o,
pll_rst_i => regs_out.csr_pll_rst,
clk_ref_i => clk_ref_i,
clk_par_o => clk_par,
clk_ser_o => clk_ser,
......@@ -512,7 +521,7 @@ begin
pll_locked_o => pll_locked,
odelayctrl_rdy_o => odelay_calib_rdy,
odelayctrl_rst_i => regs_out.odelay_calib_rst_idelayctrl_o
odelayctrl_rst_i => regs_out.odelay_calib_rst_idelayctrl
);
U_Sync_Reset : gc_sync_ffs
......@@ -520,12 +529,12 @@ begin
clk_i => clk_sys_i,
rst_n_i => rst_sys_n_i,
data_i => odelay_calib_rdy,
synced_o => regs_in.odelay_calib_rdy_i
synced_o => regs_in.odelay_calib_rdy
);
end generate gen_is_kintex_ultrascale;
clk_par_o <= clk_par;
regs_in.csr_pll_locked_i <= pll_locked;
regs_in.csr_pll_locked <= pll_locked;
end rtl;
files = [ "xwb_lm32_mcs.vhd" ];
--------------------------------------------------------------------------------
-- CERN BE-CEM-EDL
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: xwb_lm32_mcs
--
-- description: A minimal embedded microcontroller with some amount of RAM,
-- UART and a Wishbone bus for user peripherals. The code can
-- be preloaded or loaded on-the-fly through the Wishbone system bus.
--
--------------------------------------------------------------------------------
-- 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.genram_pkg.all;
use work.wishbone_pkg.all;
entity xwb_lm32_mcs is
generic(
-- size of the code/data memory in bytes
g_iram_size : integer;
-- timeout (in clock cycles) for the Wishbone master.
-- exceeding the timeout (e.g. due to an incorrect address/
-- unresponsive slave) causes a WB error after g_bus_timeout cycles.
g_bus_timeout : integer := 30;
-- file (.bram format) with the firmware to pre-load during synthesis.
g_preload_firmware : string := "";
-- Enable host interface (allows loading code from a system bus)
g_with_host_if : boolean := true;
-- Enable Virtual UART (serial console accessible from the system bus)
g_with_vuart : boolean := true
);
port(
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
irq_i : in std_logic_vector(31 downto 0) := x"00000000";
host_wb_i : in t_wishbone_slave_in := cc_dummy_slave_in;
host_wb_o : out t_wishbone_slave_out;
dbg_txd_o : out std_logic;
dbg_rxd_i : in std_logic := '0';
dwb_o : out t_wishbone_master_out;
dwb_i : in t_wishbone_master_in
);
end xwb_lm32_mcs;
architecture wrapper of xwb_lm32_mcs is
signal CONTROL0 : std_logic_vector(35 downto 0);
signal TRIG0 : std_logic_vector(31 downto 0);
signal TRIG1 : std_logic_vector(31 downto 0);
signal TRIG2 : std_logic_vector(31 downto 0);
signal TRIG3 : std_logic_vector(31 downto 0);
component chipscope_icon is
port (
CONTROL0 : inout std_logic_vector(35 downto 0));
end component chipscope_icon;
component chipscope_ila is
port (
CONTROL : inout std_logic_vector(35 downto 0);
CLK : in std_logic;
TRIG0 : in std_logic_vector(31 downto 0);
TRIG1 : in std_logic_vector(31 downto 0);
TRIG2 : in std_logic_vector(31 downto 0);
TRIG3 : in std_logic_vector(31 downto 0));
end component chipscope_ila;
constant c_iram_addr_width : integer := f_log2_size(g_iram_size)-2;
component lm32_cpu_wr_node is
generic (
eba_reset : std_logic_vector(31 downto 0) := x"00000000"
);
port (
clk_i : in std_logic;
enable_i : in std_logic := '1';
rst_i : in std_logic;
interrupt : in std_logic_vector(31 downto 0) := x"00000000";
-- dbg_csr_write_enable_i : in std_logic := '0';
-- dbg_csr_write_data_i : in std_logic_vector(31 downto 0) := x"00000000";
-- dbg_csr_addr_i : in std_logic_vector(4 downto 0) := "00000";
-- dbg_exception_o : out std_logic;
-- dbg_reset_i : in std_logic := '0';
-- dbg_break_i : in std_logic := '0';
iram_i_adr_o : out std_logic_vector(31 downto 0);
iram_i_dat_i : in std_logic_vector(31 downto 0);
iram_i_en_o : out std_logic;
iram_d_adr_o : out std_logic_vector(31 downto 0);
iram_d_dat_o : out std_logic_vector(31 downto 0);
iram_d_dat_i : in std_logic_vector(31 downto 0);
iram_d_sel_o : out std_logic_vector(3 downto 0);
iram_d_we_o : out std_logic;
iram_d_en_o : out std_logic;
D_DAT_O : out std_logic_vector(31 downto 0);
D_ADR_O : out std_logic_vector(31 downto 0);
D_CTI_O : out std_logic_vector(2 downto 0);
D_BTE_O : out std_logic_vector(1 downto 0);
D_lock_o: out std_logic;
D_CYC_O : out std_logic;
D_SEL_O : out std_logic_vector(3 downto 0);
D_STB_O : out std_logic;
D_WE_O : out std_logic;
D_DAT_I : in std_logic_vector(31 downto 0);
D_ACK_I : in std_logic;
D_ERR_I : in std_logic := '0';
D_RTY_I : in std_logic := '0'
);
end component;
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
-- synthesis translate_off
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;
-- synthesis translate_on
return x;
end function;
constant c_cnx_slave_ports : integer := 1;
constant c_cnx_master_ports : integer := 2;
constant c_master_host : integer := 0;
constant c_slave_csr : integer := 0;
constant c_slave_vuart : integer := 1;
signal cnx_slave_in : t_wishbone_slave_in_array(c_cnx_slave_ports-1 downto 0);
signal cnx_slave_out : t_wishbone_slave_out_array(c_cnx_slave_ports-1 downto 0);
signal cnx_master_in : t_wishbone_master_in_array(c_cnx_master_ports-1 downto 0);
signal cnx_master_out : t_wishbone_master_out_array(c_cnx_master_ports-1 downto 0);
constant c_cfg_base_addr : t_wishbone_address_array(c_cnx_master_ports-1 downto 0) :=
(c_slave_csr => x"00000000",
c_slave_vuart => x"00000040"
);
constant c_cfg_base_mask : t_wishbone_address_array(c_cnx_master_ports-1 downto 0) :=
(c_slave_csr => x"00000040",
c_slave_vuart => x"00000040"
);
signal cpu_reset, cpu_enable, cpu_enable_init, cpu_reset_n : std_logic;
signal d_adr : std_logic_vector(31 downto 0);
signal core_sel_match : std_logic;
signal iram_i_wr, iram_d_wr : std_logic;
signal iram_i_en, iram_i_en_cpu, iram_d_en : std_logic;
signal iram_i_adr_cpu, iram_d_adr : std_logic_vector(31 downto 0);
signal udata_addr, iram_i_adr, iram_i_adr_host : std_logic_vector(f_log2_size(g_iram_size)-3 downto 0);
signal iram_i_dat_q, iram_i_dat_d, iram_d_dat_d, iram_d_dat_q : std_logic_vector(31 downto 0);
signal iram_d_sel : std_logic_vector(3 downto 0);
signal cpu_dwb_out, cpu_dwb_out_sys : t_wishbone_master_out;
signal cpu_dwb_in, cpu_dwb_in_sys : t_wishbone_master_in;
signal dwb_out : t_wishbone_master_out;
signal bus_timeout : unsigned(7 downto 0);
signal bus_timeout_hit : std_logic;
signal host_slave_in : t_wishbone_slave_in;
signal host_slave_out : t_wishbone_slave_out;
signal cpu_csr_udata_out, cpu_csr_uaddr_addr, cpu_csr_udata_in : std_logic_vector(31 downto 0);
signal cpu_csr_udata_load : std_logic;
attribute keep : string;
attribute keep of dwb_i : signal is "true";
attribute keep of cpu_dwb_in_sys : signal is "true";
begin
U_CPU : lm32_cpu_wr_node
generic map (
eba_reset => x"00000000")
port map (
clk_i => clk_sys_i,
rst_i => cpu_reset,
interrupt => irq_i,
-- instruction bus
iram_i_adr_o => iram_i_adr_cpu,
iram_i_dat_i => iram_i_dat_q,
iram_i_en_o => iram_i_en_cpu,
-- data bus (IRAM)
iram_d_adr_o => iram_d_adr,
iram_d_dat_o => iram_d_dat_d,
iram_d_dat_i => iram_d_dat_q,
iram_d_sel_o => iram_d_sel,
iram_d_we_o => iram_d_wr,
iram_d_en_o => iram_d_en,
D_DAT_O => cpu_dwb_out.dat,
D_ADR_O => cpu_dwb_out.adr,
D_CYC_O => cpu_dwb_out.cyc,
D_SEL_O => cpu_dwb_out.sel,
D_STB_O => cpu_dwb_out.stb,
D_WE_O => cpu_dwb_out.we,
D_DAT_I => cpu_dwb_in.dat,
D_ACK_I => cpu_dwb_in.ack,
D_ERR_I => cpu_dwb_in.err,
D_RTY_I => cpu_dwb_in.rty);
cpu_dwb_in.dat <= f_x_to_zero(cpu_dwb_in_sys.dat);
cpu_dwb_in.ack <= cpu_dwb_in_sys.ack;
cpu_dwb_in.stall <= cpu_dwb_in_sys.stall;
cpu_dwb_in.rty <= '0';
cpu_dwb_in.err <= bus_timeout_hit or cpu_dwb_in_sys.err;
cpu_dwb_out_sys <= cpu_dwb_out;
p_timeout_counter : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if cpu_reset = '1' or cpu_dwb_out.cyc = '0' or (cpu_dwb_in.ack = '1' and cpu_dwb_out.cyc = '1') then
bus_timeout <= (others => '0');
bus_timeout_hit <= '0';
elsif (bus_timeout /= g_bus_timeout) then
bus_timeout <= bus_timeout + 1;
bus_timeout_hit <= '0';
else
bus_timeout_hit <= '1';
end if;
end if;
end process;
inst_iram : generic_dpram_split
generic map (
g_size => g_iram_size/4,
g_addr_conflict_resolution => "dont_care",
g_init_file => g_preload_firmware,
g_fail_if_file_not_found => true )
port map (
rst_n_i => rst_n_i,
clk_i => clk_sys_i,
bwea_i => "1111",
wea_i => iram_i_wr,
aa_i => iram_i_adr,
da_i => iram_i_dat_d,
qa_o => iram_i_dat_q,
bweb_i => iram_d_sel,
web_i => iram_d_wr,
ab_i => iram_d_adr(f_log2_size(g_iram_size)-1 downto 2),
db_i => iram_d_dat_d,
qb_o => iram_d_dat_q);
iram_i_dat_d <= cpu_csr_udata_out;
iram_i_wr <= cpu_csr_udata_load;
iram_i_adr <= cpu_csr_uaddr_addr(f_log2_size(g_iram_size)-3 downto 0) when cpu_enable = '0' else
iram_i_adr_cpu(f_log2_size(g_iram_size)-1 downto 2);
iram_i_en <= '1' when cpu_enable = '0' else iram_i_en_cpu;
cpu_csr_udata_in <= iram_i_dat_q;
U_Classic2Pipe : wb_slave_adapter
generic map (
g_master_use_struct => true,
g_master_mode => PIPELINED,
g_master_granularity => BYTE,
g_slave_use_struct => true,
g_slave_mode => CLASSIC,
g_slave_granularity => BYTE)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
slave_i => cpu_dwb_out_sys,
slave_o => cpu_dwb_in_sys,
master_i => dwb_i,
master_o => dwb_out);
dwb_o <= dwb_out;
cpu_reset <= not rst_n_i or (not cpu_enable);
cpu_reset_n <= not cpu_reset;
cnx_slave_in(c_master_host) <= host_wb_i;
host_wb_o <= cnx_slave_out(c_master_host);
U_Intercon : xwb_crossbar
generic map (
g_num_masters => c_cnx_slave_ports,
g_num_slaves => c_cnx_master_ports,
g_registered => true,
g_address => c_cfg_base_addr,
g_mask => c_cfg_base_mask)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
slave_i => cnx_slave_in,
slave_o => cnx_slave_out,
master_i => cnx_master_in,
master_o => cnx_master_out);
U_UART : xwb_simple_uart
generic map (
g_with_virtual_uart => true,
g_with_physical_uart => true,
g_interface_mode => PIPELINED,
g_address_granularity => BYTE,
g_vuart_fifo_size => 1024)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
slave_i => cnx_master_out(c_slave_vuart),
slave_o => cnx_master_in(c_slave_vuart),
uart_rxd_i => dbg_rxd_i,
uart_txd_o => dbg_txd_o);
iram_i_dat_d <= cpu_csr_udata_out;
iram_i_wr <= cpu_csr_udata_load;
iram_i_adr <= cpu_csr_uaddr_addr(f_log2_size(g_iram_size)-3 downto 0) when cpu_enable = '0' else
iram_i_adr_cpu(f_log2_size(g_iram_size)-1 downto 2);
iram_i_en <= '1' when cpu_enable = '0' else iram_i_en_cpu;
cpu_csr_udata_in <= iram_i_dat_q;
host_slave_in <= cnx_master_out(c_slave_csr);
cnx_master_in(c_slave_csr) <= host_slave_out;
p_local_regs : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
cpu_csr_udata_load <= '0';
cpu_enable <= '0';
cpu_csr_uaddr_addr <= (others => '0');
host_slave_out.ack <= '0';
host_slave_out.err <= '0';
host_slave_out.rty <= '0';
host_slave_out.stall <= '0';
cpu_enable_init <= '0';
else
cpu_csr_udata_load <= '0';
host_slave_out.ack <= '0';
if g_preload_firmware /= "" and cpu_enable_init = '0' then
cpu_enable <= '1';
cpu_enable_init <= '1';
end if;
if host_slave_in.cyc = '1' and host_slave_in.stb = '1' then
host_slave_out.ack <= '1';
if host_slave_in.we = '1' then
case host_slave_in.adr(3 downto 0) is
when "0000" => -- csr
cpu_enable <= host_slave_in.dat(0);
when "0100" => -- data
cpu_csr_udata_out <= host_slave_in.dat;
cpu_csr_udata_load <= '1';
when "1000" => -- addr
cpu_csr_uaddr_addr <= host_slave_in.dat;
when others => null;
end case;
else
case host_slave_in.adr(3 downto 0) is
when "0000" =>
host_slave_out.dat(0) <= cpu_enable;
host_slave_out.dat(31 downto 1) <= std_logic_vector(to_unsigned(g_iram_size, 31));
when "0100" =>
host_slave_out.dat <= cpu_csr_udata_in;
when others => null;
end case;
end if;
end if;
end if;
end if;
end process;
-- chipscope_icon_1 : chipscope_icon
-- port map (
-- CONTROL0 => CONTROL0);
-- chipscope_ila_1 : chipscope_ila
-- port map (
-- CONTROL => CONTROL0,
-- CLK => clk_sys_i,
-- TRIG0 => TRIG0,
-- TRIG1 => TRIG1,
-- TRIG2 => TRIG2,
-- TRIG3 => TRIG3);
trig0(31 downto 0) <= cnx_master_in(c_slave_vuart).dat;
trig1(31 downto 0) <= cnx_master_out(c_slave_vuart).dat;
trig2(16) <= cnx_master_out(c_slave_vuart).cyc;
trig2(17) <= cnx_master_out(c_slave_vuart).stb;
trig2(18) <= cnx_master_out(c_slave_vuart).we;
trig2(19) <= cnx_master_in(c_slave_vuart).stall;
trig2(20) <= cnx_master_in(c_slave_vuart).ack;
trig3 <= cnx_master_out(c_slave_vuart).adr;
end wrapper;
......@@ -279,7 +279,7 @@ module spi_top
else if(spi_ctrl_sel && wb_we_i && !tip)
begin
if (wb_sel_i[0])
ctrl[7:0] <= #Tp wb_dat_i[7:0] | {7'b0, ctrl[0]};
ctrl[7:0] <= #Tp wb_dat_i[7:0];
if (wb_sel_i[1])
ctrl[`SPI_CTRL_BIT_NB-1:8] <= #Tp wb_dat_i[`SPI_CTRL_BIT_NB-1:8];
end
......
......@@ -3,7 +3,7 @@
---------------------------------------------------------------------------------------
-- File : simple_uart_pkg.vhd
-- Author : auto-generated by wbgen2 from simple_uart_wb.wb
-- Created : Tue Aug 25 17:17:50 2020
-- Created : Fri Jan 26 16:35:06 2024
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE simple_uart_wb.wb
......@@ -28,7 +28,9 @@ package uart_wbgen2_pkg is
sr_tx_fifo_empty_i : std_logic;
sr_tx_fifo_full_i : std_logic;
sr_rx_fifo_overflow_i : std_logic;
sr_rx_fifo_bytes_i : std_logic_vector(7 downto 0);
sr_rx_fifo_bytes_i : std_logic_vector(15 downto 0);
sr_physical_uart_i : std_logic;
sr_virtual_uart_i : std_logic;
rdr_rx_data_i : std_logic_vector(7 downto 0);
host_tdr_rdy_i : std_logic;
host_rdr_data_i : std_logic_vector(7 downto 0);
......@@ -46,6 +48,8 @@ package uart_wbgen2_pkg is
sr_tx_fifo_full_i => '0',
sr_rx_fifo_overflow_i => '0',
sr_rx_fifo_bytes_i => (others => '0'),
sr_physical_uart_i => '0',
sr_virtual_uart_i => '0',
rdr_rx_data_i => (others => '0'),
host_tdr_rdy_i => '0',
host_rdr_data_i => (others => '0'),
......@@ -66,6 +70,8 @@ package uart_wbgen2_pkg is
host_tdr_data_wr_o : std_logic;
cr_rx_fifo_purge_o : std_logic;
cr_tx_fifo_purge_o : std_logic;
cr_rx_interrupt_enable_o : std_logic;
cr_tx_interrupt_enable_o : std_logic;
end record;
constant c_uart_out_registers_init_value: t_uart_out_registers := (
......@@ -78,78 +84,82 @@ package uart_wbgen2_pkg is
host_tdr_data_o => (others => '0'),
host_tdr_data_wr_o => '0',
cr_rx_fifo_purge_o => '0',
cr_tx_fifo_purge_o => '0'
cr_tx_fifo_purge_o => '0',
cr_rx_interrupt_enable_o => '0',
cr_tx_interrupt_enable_o => '0'
);
function "or" (left, right: t_uart_in_registers) return t_uart_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 simple_uart_wb is
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
wb_adr_i : in std_logic_vector(2 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_dat_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic_vector(3 downto 0);
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
wb_err_o : out std_logic;
wb_rty_o : out std_logic;
wb_stall_o : out std_logic;
rdr_rack_o : out std_logic;
host_rack_o : out std_logic;
regs_i : in t_uart_in_registers;
regs_o : out t_uart_out_registers
);
end component;
function "or" (left, right: t_uart_in_registers) return t_uart_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 simple_uart_wb is
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
wb_adr_i : in std_logic_vector(2 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_dat_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic_vector(3 downto 0);
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
wb_err_o : out std_logic;
wb_rty_o : out std_logic;
wb_stall_o : out std_logic;
rdr_rack_o : out std_logic;
host_rack_o : out std_logic;
regs_i : in t_uart_in_registers;
regs_o : out t_uart_out_registers
);
end component;
end package;
package body uart_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';
function f_x_to_zero (x:std_logic) return std_logic is
begin
if x = '1' then
return '1';
else
tmp(i):=x(i);
end if;
end loop;
return tmp;
end function;
function "or" (left, right: t_uart_in_registers) return t_uart_in_registers is
variable tmp: t_uart_in_registers;
begin
tmp.sr_tx_busy_i := f_x_to_zero(left.sr_tx_busy_i) or f_x_to_zero(right.sr_tx_busy_i);
tmp.sr_rx_rdy_i := f_x_to_zero(left.sr_rx_rdy_i) or f_x_to_zero(right.sr_rx_rdy_i);
tmp.sr_rx_fifo_supported_i := f_x_to_zero(left.sr_rx_fifo_supported_i) or f_x_to_zero(right.sr_rx_fifo_supported_i);
tmp.sr_tx_fifo_supported_i := f_x_to_zero(left.sr_tx_fifo_supported_i) or f_x_to_zero(right.sr_tx_fifo_supported_i);
tmp.sr_rx_fifo_valid_i := f_x_to_zero(left.sr_rx_fifo_valid_i) or f_x_to_zero(right.sr_rx_fifo_valid_i);
tmp.sr_tx_fifo_empty_i := f_x_to_zero(left.sr_tx_fifo_empty_i) or f_x_to_zero(right.sr_tx_fifo_empty_i);
tmp.sr_tx_fifo_full_i := f_x_to_zero(left.sr_tx_fifo_full_i) or f_x_to_zero(right.sr_tx_fifo_full_i);
tmp.sr_rx_fifo_overflow_i := f_x_to_zero(left.sr_rx_fifo_overflow_i) or f_x_to_zero(right.sr_rx_fifo_overflow_i);
tmp.sr_rx_fifo_bytes_i := f_x_to_zero(left.sr_rx_fifo_bytes_i) or f_x_to_zero(right.sr_rx_fifo_bytes_i);
tmp.rdr_rx_data_i := f_x_to_zero(left.rdr_rx_data_i) or f_x_to_zero(right.rdr_rx_data_i);
tmp.host_tdr_rdy_i := f_x_to_zero(left.host_tdr_rdy_i) or f_x_to_zero(right.host_tdr_rdy_i);
tmp.host_rdr_data_i := f_x_to_zero(left.host_rdr_data_i) or f_x_to_zero(right.host_rdr_data_i);
tmp.host_rdr_rdy_i := f_x_to_zero(left.host_rdr_rdy_i) or f_x_to_zero(right.host_rdr_rdy_i);
tmp.host_rdr_count_i := f_x_to_zero(left.host_rdr_count_i) or f_x_to_zero(right.host_rdr_count_i);
return tmp;
end function;
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) = '1') then
tmp(i):= '1';
else
tmp(i):= '0';
end if;
end loop;
return tmp;
end function;
function "or" (left, right: t_uart_in_registers) return t_uart_in_registers is
variable tmp: t_uart_in_registers;
begin
tmp.sr_tx_busy_i := f_x_to_zero(left.sr_tx_busy_i) or f_x_to_zero(right.sr_tx_busy_i);
tmp.sr_rx_rdy_i := f_x_to_zero(left.sr_rx_rdy_i) or f_x_to_zero(right.sr_rx_rdy_i);
tmp.sr_rx_fifo_supported_i := f_x_to_zero(left.sr_rx_fifo_supported_i) or f_x_to_zero(right.sr_rx_fifo_supported_i);
tmp.sr_tx_fifo_supported_i := f_x_to_zero(left.sr_tx_fifo_supported_i) or f_x_to_zero(right.sr_tx_fifo_supported_i);
tmp.sr_rx_fifo_valid_i := f_x_to_zero(left.sr_rx_fifo_valid_i) or f_x_to_zero(right.sr_rx_fifo_valid_i);
tmp.sr_tx_fifo_empty_i := f_x_to_zero(left.sr_tx_fifo_empty_i) or f_x_to_zero(right.sr_tx_fifo_empty_i);
tmp.sr_tx_fifo_full_i := f_x_to_zero(left.sr_tx_fifo_full_i) or f_x_to_zero(right.sr_tx_fifo_full_i);
tmp.sr_rx_fifo_overflow_i := f_x_to_zero(left.sr_rx_fifo_overflow_i) or f_x_to_zero(right.sr_rx_fifo_overflow_i);
tmp.sr_rx_fifo_bytes_i := f_x_to_zero(left.sr_rx_fifo_bytes_i) or f_x_to_zero(right.sr_rx_fifo_bytes_i);
tmp.sr_physical_uart_i := f_x_to_zero(left.sr_physical_uart_i) or f_x_to_zero(right.sr_physical_uart_i);
tmp.sr_virtual_uart_i := f_x_to_zero(left.sr_virtual_uart_i) or f_x_to_zero(right.sr_virtual_uart_i);
tmp.rdr_rx_data_i := f_x_to_zero(left.rdr_rx_data_i) or f_x_to_zero(right.rdr_rx_data_i);
tmp.host_tdr_rdy_i := f_x_to_zero(left.host_tdr_rdy_i) or f_x_to_zero(right.host_tdr_rdy_i);
tmp.host_rdr_data_i := f_x_to_zero(left.host_rdr_data_i) or f_x_to_zero(right.host_rdr_data_i);
tmp.host_rdr_rdy_i := f_x_to_zero(left.host_rdr_rdy_i) or f_x_to_zero(right.host_rdr_rdy_i);
tmp.host_rdr_count_i := f_x_to_zero(left.host_rdr_count_i) or f_x_to_zero(right.host_rdr_count_i);
return tmp;
end function;
end package body;
......@@ -3,7 +3,7 @@
---------------------------------------------------------------------------------------
-- File : simple_uart_wb.vhd
-- Author : auto-generated by wbgen2 from simple_uart_wb.wb
-- Created : Tue Aug 25 17:17:50 2020
-- Created : Fri Jan 26 16:35:06 2024
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE simple_uart_wb.wb
......@@ -18,25 +18,25 @@ use work.uart_wbgen2_pkg.all;
entity simple_uart_wb is
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
wb_adr_i : in std_logic_vector(2 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_dat_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic_vector(3 downto 0);
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
wb_err_o : out std_logic;
wb_rty_o : out std_logic;
wb_stall_o : out std_logic;
rdr_rack_o : out std_logic;
host_rack_o : out std_logic;
regs_i : in t_uart_in_registers;
regs_o : out t_uart_out_registers
);
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
wb_adr_i : in std_logic_vector(2 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_dat_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic_vector(3 downto 0);
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
wb_err_o : out std_logic;
wb_rty_o : out std_logic;
wb_stall_o : out std_logic;
rdr_rack_o : out std_logic;
host_rack_o : out std_logic;
regs_i : in t_uart_in_registers;
regs_o : out t_uart_out_registers
);
end simple_uart_wb;
architecture syn of simple_uart_wb is
......@@ -45,6 +45,8 @@ signal uart_cr_rx_fifo_purge_dly0 : std_logic ;
signal uart_cr_rx_fifo_purge_int : std_logic ;
signal uart_cr_tx_fifo_purge_dly0 : std_logic ;
signal uart_cr_tx_fifo_purge_int : std_logic ;
signal uart_cr_rx_interrupt_enable_int : std_logic ;
signal uart_cr_tx_interrupt_enable_int : std_logic ;
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);
......@@ -77,19 +79,25 @@ begin
uart_cr_tx_fifo_purge_int <= '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
regs_o.sr_rx_fifo_overflow_load_o <= '0';
regs_o.bcr_wr_o <= '0';
regs_o.tdr_tx_data_wr_o <= '0';
rdr_rack_o <= '0';
regs_o.host_tdr_data_wr_o <= '0';
host_rack_o <= '0';
uart_cr_rx_fifo_purge_int <= '0';
uart_cr_tx_fifo_purge_int <= '0';
ack_in_progress <= '0';
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
regs_o.sr_rx_fifo_overflow_load_o <= '0';
regs_o.bcr_wr_o <= '0';
regs_o.tdr_tx_data_wr_o <= '0';
rdr_rack_o <= '0';
regs_o.host_tdr_data_wr_o <= '0';
host_rack_o <= '0';
uart_cr_rx_fifo_purge_int <= '0';
uart_cr_tx_fifo_purge_int <= '0';
ack_in_progress <= '0';
else
regs_o.sr_rx_fifo_overflow_load_o <= '0';
regs_o.bcr_wr_o <= '0';
regs_o.tdr_tx_data_wr_o <= '0';
regs_o.host_tdr_data_wr_o <= '0';
end if;
else
regs_o.sr_rx_fifo_overflow_load_o <= '0';
regs_o.bcr_wr_o <= '0';
......@@ -334,17 +342,17 @@ begin
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;
ack_in_progress <= '1';
ack_sreg(0) <= '1';
end case;
end if;
end if;
end if;
end if;
end process;
end process;
-- Drive the data output bus
wb_dat_o <= rddata_reg;
wb_dat_o <= rddata_reg;
-- TX busy
-- RX ready
-- RX FIFO supported
......@@ -353,18 +361,20 @@ wb_dat_o <= rddata_reg;
-- TX FIFO empty
-- TX FIFO full
-- RX FIFO overflow
regs_o.sr_rx_fifo_overflow_o <= wrdata_reg(7);
regs_o.sr_rx_fifo_overflow_o <= wrdata_reg(7);
-- RX FIFO data count
-- Physical UART
-- Virtual UART
-- Baudrate divider setting
-- pass-through field: Baudrate divider setting in register: Baudrate control register
regs_o.bcr_o <= wrdata_reg(31 downto 0);
regs_o.bcr_o <= wrdata_reg(31 downto 0);
-- Transmit data
-- pass-through field: Transmit data in register: Transmit data regsiter
regs_o.tdr_tx_data_o <= wrdata_reg(7 downto 0);
regs_o.tdr_tx_data_o <= wrdata_reg(7 downto 0);
-- Received data
-- TX Data
-- pass-through field: TX Data in register: Host VUART Tx register
regs_o.host_tdr_data_o <= wrdata_reg(7 downto 0);
regs_o.host_tdr_data_o <= wrdata_reg(7 downto 0);
-- TX Ready
-- RX Data
-- RX Ready
......@@ -400,5 +410,5 @@ wb_stall_o <= (not ack_sreg(0)) and (wb_stb_i and wb_cyc_i);
wb_err_o <= '0';
wb_rty_o <= '0';
-- ACK signal generation. Just pass the LSB of ACK counter.
wb_ack_o <= ack_sreg(0);
wb_ack_o <= ack_sreg(0);
end syn;
......@@ -98,10 +98,32 @@ peripheral {
prefix = "RX_FIFO_BYTES";
type = SLV;
size = 8;
size = 16;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Physical UART";
description = "Set if the Physical UART is present";
prefix = "PHYSICAL_UART";
type = BIT;
size = 1;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Virtual UART";
description = "Set if the Virtual UART is present";
prefix = "VIRTUAL_UART";
type = BIT;
size = 1;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
......@@ -218,7 +240,25 @@ peripheral {
prefix = "TX_FIFO_PURGE";
type = MONOSTABLE;
};
field {
name = "RX Interrupt enable";
description = "RX Interrupt Enable";
prefix = "RX_INTERRUPT_ENABLE";
type = BIT;
align = 8;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "TX Interrupt enable";
description = "TX Interrupt Enable";
prefix = "TX_INTERRUPT_ENABLE";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
};
......@@ -33,6 +33,7 @@ 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.wishbone_pkg.all;
use work.UART_wbgen2_pkg.all;
......@@ -119,9 +120,16 @@ architecture arch of wb_simple_uart is
signal phys_rx_data, phys_tx_data : std_logic_vector(7 downto 0);
type t_tx_fifo_state is (IDLE, TRANSMIT_PENDING);
type t_rx_fifo_state is (IDLE, RX_READ, RX_WAIT_ACK );
signal tx_fifo_state : t_tx_fifo_state;
signal rx_fifo_state : t_rx_fifo_state;
signal s_rx_interrupt: std_logic;
signal s_tx_interrupt: std_logic;
signal rx_fifo_rdata : std_logic_vector(7 downto 0);
signal rx_fifo_wdata : std_logic_vector(7 downto 0);
begin -- arch
gen_check_generics : if (not g_WITH_PHYSICAL_UART and not g_WITH_VIRTUAL_UART) generate
......@@ -218,34 +226,38 @@ begin -- arch
baud8_tick_i => baud_tick8,
rxd_i => uart_rxd_i,
rx_ready_o => phys_rx_ready,
rx_error_o => open,
rx_error_o => open, -- fixme: support RX error detection
rx_data_o => phys_rx_data);
end generate gen_phys_uart;
gen_phys_fifos : if g_WITH_PHYSICAL_UART_FIFO generate
rx_fifo_wr <= not rx_fifo_full and phys_rx_ready;
rx_fifo_wr <= not rx_fifo_full and (phys_rx_ready or ( f_to_std_logic(g_WITH_VIRTUAL_UART) and regs_out.host_tdr_data_wr_o ) );
tx_fifo_wr <= not tx_fifo_full and regs_out.tdr_tx_data_wr_o;
tx_fifo_reset_n <= rst_n_i and not regs_out.cr_tx_fifo_purge_o;
rx_fifo_reset_n <= rst_n_i and not regs_out.cr_rx_fifo_purge_o;
rx_fifo_rd <= not rx_fifo_empty and rdr_rack;
-- RX FIFO write data: Physical UART takes the priority over VUART. Note these
-- are not meant to be used simultaneously.
rx_fifo_wdata <= phys_rx_data when phys_rx_ready = '1' else regs_out.host_tdr_data_o;
U_UART_RX_FIFO : generic_sync_fifo
generic map (
g_DATA_WIDTH => 8,
g_SIZE => g_RX_FIFO_SIZE,
g_WITH_COUNT => true,
g_SHOW_AHEAD => true
g_SHOW_AHEAD => false
)
port map (
rst_n_i => rx_fifo_reset_n,
clk_i => clk_sys_i,
d_i => phys_rx_data,
d_i => rx_fifo_wdata,
we_i => rx_fifo_wr,
q_o => regs_in.rdr_rx_data_i,
rd_i => rdr_rack,
q_o => rx_fifo_rdata,
rd_i => rx_fifo_rd,
empty_o => rx_fifo_empty,
full_o => rx_fifo_full,
count_o => rx_fifo_count);
......@@ -270,12 +282,14 @@ begin -- arch
regs_in.sr_rx_fifo_supported_i <= '1';
regs_in.sr_tx_fifo_supported_i <= '1';
regs_in.sr_rx_fifo_valid_i <= not rx_fifo_empty;
regs_in.sr_rx_rdy_i <= not rx_fifo_empty;
regs_in.sr_rx_fifo_overflow_i <= rx_fifo_overflow;
regs_in.sr_tx_fifo_full_i <= tx_fifo_full;
regs_in.sr_tx_fifo_empty_i <= tx_fifo_empty;
regs_in.sr_rx_fifo_bytes_i (rx_fifo_count'length-1 downto 0) <= rx_fifo_count;
regs_in.sr_rx_fifo_bytes_i ( 15 downto rx_fifo_count'length ) <= (others => '0');
phys_tx_start <= '1' when tx_fifo_state = IDLE and tx_fifo_empty = '0' else '0';
p_rx_fifo_overflow : process(clk_sys_i)
......@@ -284,7 +298,11 @@ begin -- arch
if rx_fifo_reset_n = '0' then
rx_fifo_overflow <= '0';
else
if regs_out.cr_rx_fifo_purge_o = '1' then
rx_fifo_overflow <= '0';
elsif rx_fifo_full = '1' then
rx_fifo_overflow <= '1';
end if;
end if;
end if;
end process;
......@@ -315,7 +333,54 @@ begin -- arch
end if;
end process;
p_rx_fifo_fsm : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rx_fifo_reset_n = '0' then
rx_fifo_state <= IDLE;
regs_in.sr_rx_fifo_valid_i <= '0';
regs_in.sr_rx_rdy_i <= '0';
else
case rx_fifo_state is
when IDLE =>
regs_in.sr_rx_fifo_valid_i <= '0';
regs_in.sr_rx_rdy_i <= '0';
if rx_fifo_rd = '1' then
rx_fifo_state <= RX_READ;
end if;
when RX_READ =>
regs_in.rdr_rx_data_i <= rx_fifo_rdata;
regs_in.sr_rx_fifo_valid_i <= '1';
regs_in.sr_rx_rdy_i <= '1';
rx_fifo_state <= RX_WAIT_ACK;
when RX_WAIT_ACK =>
if( rdr_rack = '1' ) then
regs_in.sr_rx_fifo_valid_i <= '0';
regs_in.sr_rx_rdy_i <= '0';
rx_fifo_state <= IDLE;
end if;
end case;
end if;
end if;
end process;
rx_fifo_rd <= '1' when rx_fifo_state = IDLE and rx_fifo_empty = '0' else '0';
-- Handling the interrupt for UART
s_rx_interrupt <= '1' when (regs_in.sr_rx_rdy_i = '1' and regs_out.cr_rx_interrupt_enable_o = '1') else '0';
s_tx_interrupt <= '1' when (tx_fifo_full = '0' and regs_out.cr_tx_interrupt_enable_o = '1') else '0';
int_o <= s_rx_interrupt or s_tx_interrupt;
regs_in.sr_tx_busy_i <= tx_fifo_full;
end generate gen_phys_fifos;
gen_phys_nofifos : if not g_WITH_PHYSICAL_UART_FIFO generate
......@@ -402,4 +467,8 @@ begin -- arch
regs_in.host_tdr_rdy_i <= not regs_in.sr_rx_rdy_i;
-- Registers to set if the Physical or Virtual UART is present
regs_in.sr_physical_uart_i <= '1' when g_WITH_PHYSICAL_UART else '0';
regs_in.sr_virtual_uart_i <= '1' when g_WITH_VIRTUAL_UART else '0';
end arch;
//------------------------------------------------------------------------------
// CERN BE-CEM-EDL
// General Cores Library
// https://www.ohwr.org/projects/general-cores
//------------------------------------------------------------------------------
//
// units: Logger/LoggerClient/UnitTest/UnitTestMessage
//
// description: Simple classes for testbench status logging/reporting.
//
//------------------------------------------------------------------------------
// Copyright CERN 2010-2019
//------------------------------------------------------------------------------
// 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.
//------------------------------------------------------------------------------
`ifndef __LOGGER_SVH
`define __LOGGER_SVH
`include "simdrv_defs.svh"
// converts an array of bytes to a string with given format
function automatic string array2str(string fmt, uint8_t data[$]);
string rv ="";
for(int i =0 ;i<data.size();i++)
rv = {rv, $sformatf(fmt, data[i]) };
return rv;
endfunction // str
// represents a single test log:
class UnitTestMessage;
string m_msg;
int m_slot;
function new ( int slot, string msg );
m_msg = msg;
m_slot = slot;
endfunction // new
endclass // UnitTestMessage
typedef enum
{
TR_UNKNOWN,
TR_FAIL,
TR_PASS
} TestResult;
// represents a single test log:
class UnitTest;
// test ID
int m_id;
// final result (failure, pass, unknown)
TestResult m_result;
// name of the test
string m_name;
// detailed reason for the failure
string m_failureReason;
// message buffer
UnitTestMessage m_messages[$];
function automatic void msg( int slot, string str );
UnitTestMessage m = new( slot, str );
m_messages.push_back(m);
endfunction // msg
function new ( int id, string name );
m_id = id;
m_name = name;
m_result = TR_UNKNOWN;
endfunction // new
endclass // UnitTest
// class Logger
//
// A singleton class that handles all test result logging activities.
class Logger;
int m_id;
protected static Logger m_self;
protected int m_loggerId;
protected UnitTest m_currentTest;
protected UnitTest m_tests[$];
protected int m_passedTests;
protected int m_failedTests;
function new ( string log_file, int id = -1 );
m_id = 1;
m_loggerId = id;
m_currentTest = null;
m_passedTests = 0;
m_failedTests = 0;
endfunction
// returns the singleton instance
static function Logger get();
if (m_self == null) begin
m_self = new( "sim_log.txt" );
end
return m_self;
endfunction // get
// begins a test
function automatic void startTest( string name );
m_currentTest = new( m_id, name );
m_tests.push_back(m_currentTest);
$display("[*] Running test %d: %s", m_id, name);
m_id++;
endfunction // startTest
// marks the current test as passed
function automatic void pass();
if( m_currentTest.m_result == TR_UNKNOWN)
begin
$display("[*] Test %d PASSED", m_id);
m_currentTest.m_result = TR_PASS;
end
endfunction // pass
// marks the current test as failed
function automatic void fail ( string reason );
$display("[*] Test %d FAILED: %s", m_id, reason);
m_currentTest.m_result = TR_FAIL;
m_currentTest.m_failureReason = reason;
endfunction
// logs a message within the scope of the current test
function automatic void msg ( int slot, string m );
if(m_currentTest)
m_currentTest.msg(slot, m);
$display(" %s", m);
endfunction // msg
function automatic int getPassedTestCount();
automatic int cnt = 0;
foreach(m_tests[i])
if (m_tests[i].m_result == TR_PASS)
cnt++;
return cnt;
endfunction // getPassedTestCount
function automatic int getFailedTestCount();
automatic int cnt = 0;
foreach(m_tests[i])
if (m_tests[i].m_result == TR_FAIL)
cnt++;
return cnt;
endfunction // getPassedTestCount
function automatic void fprint(int fd, string str);
if( fd >= 0 )
$fdisplay(fd, str);
$display(str);
endfunction // fprint
function automatic string getSystemDate();
automatic int fd;
string t;
void'($system("date +%X--%x > sys_time.tmp"));
fd = $fopen("sys_time.tmp","r");
void'($fscanf(fd,"%s",t));
$fclose(fd);
void'($system("rm sys_time.tmp"));
return t;
endfunction // getSystemDate
function automatic void writeTestReport( int summaryOnly, int useStdout = 1, string filename = "");
automatic int fd;
if( !useStdout )
fd = $fopen(filename,"wb");
else
fd = -1;
fprint(fd, "Unit Test Report");
fprint(fd, $sformatf("Test date: %s\n\n", getSystemDate() ));
fprint(fd, "Test Summary ");
fprint(fd, "-------------");
fprint(fd, $sformatf("%-02d tests PASSED", getPassedTestCount() ) );
fprint(fd, $sformatf("%-02d tests FAILED", getFailedTestCount() ) );
fprint(fd, "\nIndividual Test Results:" );
fprint(fd, "ID | Test Name | Status | Failure Reason" );
fprint(fd, "----------------------------------------------------------------------------------------------------------" );
foreach(m_tests[i])
begin
fprint(fd, $sformatf("%-3d | %-74s | %-6s | %s" , m_tests[i].m_id, m_tests[i].m_name, m_tests[i].m_result == TR_PASS ? "PASS" : "FAIL", m_tests[i].m_failureReason ) );
end
fprint(fd,"\n\n");
if( summaryOnly )
begin
$fclose(fd);
return;
end
foreach(m_tests[i])
begin
automatic UnitTest test = m_tests[i];
$fdisplay(fd, "Test messages for test %d", test.m_id );
$fdisplay(fd, "---------------------------\n" );
foreach(test.m_messages[j])
begin
$fdisplay(fd, test.m_messages[j].m_msg);
end
$fdisplay(fd, "\n---------------------------\n" );
end
$fclose(fd);
endfunction
endclass // Logger
class LoggerClient;
function automatic void startTest( string name );
automatic Logger l = Logger::get();
l.startTest( name );
endfunction // startTest
function automatic void pass();
automatic Logger l = Logger::get();
l.pass();
endfunction // pass
function automatic void fail ( string reason );
automatic Logger l = Logger::get();
l.fail(reason);
endfunction
function automatic void msg ( int slot, string m );
automatic Logger l = Logger::get();
l.msg(slot, m);
endfunction // msg
endclass // LoggerClient
`endif // `ifndef __LOGGER_SVH
`ifndef SIMDRV_DEFS_SV
`define SIMDRV_DEFS_SV 1
typedef byte unsigned uint8_t;
typedef longint unsigned uint64_t;
typedef int unsigned uint32_t;
typedef shortint unsigned uint16_t;
......
......@@ -6,6 +6,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
......@@ -404,8 +405,13 @@ static int spi_ocores_hw_xfer_wait_complete(struct spi_ocores *sp,
*/
static int spi_ocores_sw_xfer_finish(struct spi_ocores *sp)
{
#if KERNEL_VERSION(5,13,0) <= LINUX_VERSION_CODE
if (sp->cur_xfer->delay.value)
udelay(sp->cur_xfer->delay.value);
#else
if (sp->cur_xfer->delay_usecs)
udelay(sp->cur_xfer->delay_usecs);
#endif
if (sp->cur_xfer->cs_change) {
unsigned int cs;
......
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
# This Makefile can be called by the Continuous Integration (CI) tool to execute all
# testbenches added for CI
# AXI4 cores
TB_DIRS+=axi/axi4lite_wb_bridge
TB_DIRS+=axi/z7_axi_gpio_expander
TB_DIRS+=axi/axi4lite32_axi4full64_bridge
TB_DIRS+=axi/axi4lite_axi4full_bridge
.PHONY: $(TB_DIRS)
all: $(TB_DIRS) summary
$(TB_DIRS):
@echo "Run HDLMAKE"
@cd "$@"; \
hdlmake 2>&1
@echo "Run make"
@$(MAKE) -C $@ $(TARGET)
@echo "Run ghdl"
@cd "$@" ;\
./run.sh
@echo "ghdl returned $$?"
summary: $(TB_DIRS)
@echo "-------------------------------------------------------------------"
@echo "Summary:"
@for d in $(TB_DIRS); do \
if [ -f $$d/transcript ]; then \
echo "Warnings for $$d:"; \
cat $$d/transcript | grep Warning; \
if [ $$? -eq 1 ]; then echo "None"; fi ;\
echo "Errors for $$d:"; \
cat $$d/transcript | grep Error; \
if [ $$? -eq 1 ]; then echo "None"; fi ;\
else \
echo "No transcript file for $$d"; \
fi \
done
clean:
@for d in $(TB_DIRS); do \
if [ -f $$d/Makefile ]; then \
$(MAKE) -C $$d $@; \
rm -f $$d/Makefile; \
fi \
done
# Description
The majority of the general cores have their own testbench written in VHDL and as a verification methodology, OSVVM is used. There are also some testbenches which are written in SystemVerilog.
The common features of each test are:
- Randomization of the input signals
- FSM coverage (when there are FSM in the RTL design), results are shown at the end of the simulation
- Assertions are used to verify aspects of the core's functionality, cumply with the specifications
There are two options for the users, in order to run these tests. First is to run them all by using the Makefile in the current directory. This Makefile contains all the VHDL tests. Second option, is to run each test individually.
## Requirements
- [hdlmake](https://hdlmake.readthedocs.io/en/master/#install-hdlmake-package)
- [ghdl](https://ghdl.github.io/ghdl/development/building/index.html#build)
## Set up environment
- OSVVM is a dependency for most of these testbenches. It is already included as a git submodule. Therefore, it is necessary to run at least once `git submodule update --init` before running these testbenches.
## How to test
```console
hdlmake makefile
make
./run.sh
```
Waveform option:
```console
./run.sh --wave=waveform.ghw
```
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
*
!.gitignore
!Manifest.py
!*.vhd
!*.cheby
!run.sh
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
action="simulation"
sim_tool="ghdl"
target="generic"
ghdl_opt="--std=08 -frelaxed-rules -Wno-hide"
sim_top="tb_axi4lite32_axi4full64_bridge"
files="tb_axi4lite32_axi4full64_bridge.vhd"
modules={"local" : ["../../../",
"../../osvvm/",
"../../../modules/wishbone",
"../../../modules/axi"]}
## Description
Testbench for [axi4lite32_axi4full64_bridge](../../modules/axi/axi4lite32_axi4full64_bridge/axi4lite32_axi4full64_bridge.vhd) which is a bridge from AXI4Lite32 to AXI4Full64. Master is the axi4lite and the slave is axi4full.
NOTE: By default, the simulation time is 4ms. For any change in this, run the test and pass the simulation time as an argument to this script:
```console
./run.sh <simulation time>
```
#!/bin/bash -e
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
#This is a simple script to run simulations in GHDL
TB=tb_axi4lite32_axi4full64_bridge
if [ -z "$1" ]; then
TIME="4"
else
TIME="$1"
fi;
echo "Running simulation for $TB"
ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_sim_time=$TIME
-------------------------------------------------------------------------------
-- SPDX-FileCopyrightText: 2023 CERN (home.cern)
--
-- SPDX-License-Identifier: CERN-OHL-W-2.0+
-------------------------------------------------------------------------------
-- Title : Testbench for AXI4Full64 to AXI4Lite32 bridge
-- Project : General Cores
-------------------------------------------------------------------------------
-- File : tb_axi4lite32_axi4full64_bridge.vhd
-- Author : Konstantinos Blantos
-- Company : CERN (BE-CEM-EDL)
-- Platform : FPGA-generics
-- Standard : VHDL '08
-------------------------------------------------------------------------------
--=============================================================================
-- Libraries & Packages --
--=============================================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- OSVVM library
library osvvm;
use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all;
--=============================================================================
-- Entity declaration for tb_axi4lite32_axi4full64_bridge --
--=============================================================================
entity tb_axi4lite32_axi4full64_bridge is
generic (
g_seed : natural;
g_sim_time : natural);
end entity;
--==============================================================================
-- Architecture declaration --
--==============================================================================
architecture tb of tb_axi4lite32_axi4full64_bridge is
--==========================================================
-- constants
--==========================================================
constant C_CLK_PERIOD : time := 10 ns;
constant C_SIM_TIME : time := (g_sim_time*1.0 ms);
constant RSP_OKAY : std_logic_vector(1 downto 0) := b"00";
constant RSP_EXOKAY : std_logic_vector(1 downto 0) := b"01";
constant RSP_SLVERR : std_logic_vector(1 downto 0) := b"10";
constant RSP_DECERR : std_logic_vector(1 downto 0) := b"11";
--==========================================================
-- Signals
--==========================================================
signal tb_clk_i : std_logic;
signal tb_rst_n_i : std_logic;
-- AXI4-Full slave
signal tb_s_awaddr : std_logic_vector (31 downto 0);
signal tb_s_awlen : std_logic_vector (7 downto 0);
signal tb_s_awsize : std_logic_vector (2 downto 0);
signal tb_s_awburst : std_logic_vector (1 downto 0);
signal tb_s_awvalid : std_logic;
signal tb_s_awready : std_logic;
signal tb_s_wdata : std_logic_vector (63 downto 0);
signal tb_s_wstrb : std_logic_vector (7 downto 0);
signal tb_s_wlast : std_logic;
signal tb_s_wvalid : std_logic;
signal tb_s_wready : std_logic;
signal tb_s_bresp : std_logic_vector (1 downto 0);
signal tb_s_bvalid : std_logic;
signal tb_s_bready : std_logic;
signal tb_s_araddr : std_logic_vector (31 downto 0);
signal tb_s_arlen : std_logic_vector (7 downto 0);
signal tb_s_arsize : std_logic_vector (2 downto 0);
signal tb_s_arburst : std_logic_vector (1 downto 0);
signal tb_s_arvalid : std_logic;
signal tb_s_arready : std_logic;
signal tb_s_rdata : std_logic_vector (63 downto 0);
signal tb_s_rresp : std_logic_vector (1 downto 0);
signal tb_s_rlast : std_logic;
signal tb_s_rvalid : std_logic;
signal tb_s_rready : std_logic;
-- AXI4-Lite master
signal tb_m_awaddr : std_logic_vector (31 downto 0);
signal tb_m_awvalid : std_logic;
signal tb_m_awready : std_logic;
signal tb_m_wdata : std_logic_vector (31 downto 0);
signal tb_m_wstrb : std_logic_vector (3 downto 0);
signal tb_m_wvalid : std_logic;
signal tb_m_wready : std_logic;
signal tb_m_bresp : std_logic_vector (1 downto 0);
signal tb_m_bvalid : std_logic;
signal tb_m_bready : std_logic;
signal tb_m_araddr : std_logic_vector (31 downto 0);
signal tb_m_arvalid : std_logic;
signal tb_m_arready : std_logic;
signal tb_m_rdata : std_logic_vector (31 downto 0);
signal tb_m_rresp : std_logic_vector (1 downto 0);
signal tb_m_rvalid : std_logic;
signal tb_m_rready : std_logic;
-- other TB signals
signal stop : boolean;
signal s_waddr : std_logic_vector(31 downto 0);
signal s_wlen : std_logic_vector(7 downto 0);
signal s_wsize : std_logic_vector(2 downto 0);
signal s_raddr : std_logic_vector(31 downto 0);
signal s_rlen : std_logic_vector(7 downto 0);
signal s_rsize : std_logic_vector(2 downto 0);
signal s_rdata : std_logic_vector(63 downto 0);
signal s_awvalid : std_logic;
signal s_wvalid : std_logic;
signal s_arvalid : std_logic;
signal s_rready : std_logic;
signal s_m_awready : std_logic;
signal s_m_wready : std_logic;
signal s_bready : std_logic;
signal s_m_bvalid : std_logic;
signal rdata : std_logic_vector(63 downto 0);
signal s_rd_cnt : natural;
signal s_wr_cnt : natural;
signal wdata : std_logic_vector(31 downto 0);
signal s_tmp_wdata : std_logic_vector(63 downto 0);
type t_wr_state is (WR_IDLE,
WR_MASTER, WR_SLAVE, WR_SLAVE2, WR_WAIT, WR_DONE);
type t_rd_state is (RD_IDLE, RD_READ, RD_SLAVE);
signal s_wstate : t_wr_state;
signal s_rstate : t_rd_state;
shared variable sv_cover_wr : covPType;
shared variable sv_cover_rd : covPType;
--=============================================================================
-- Procedures used for fsm coverage
--=============================================================================
-- legal states for Write FSM
procedure fsm_covadd_states_wr (
name : in string;
prev : in t_wr_state;
curr : in t_wr_state;
covdb : inout covPType) is
begin
covdb.AddCross ( name,
GenBin(t_wr_state'pos(prev)),
GenBin(t_wr_state'pos(curr)));
end procedure;
-- legal states for Read FSM
procedure fsm_covadd_states_rd (
name : in string;
prev : in t_rd_state;
curr : in t_rd_state;
covdb : inout covPType) is
begin
covdb.AddCross ( name,
GenBin(t_rd_state'pos(prev)),
GenBin(t_rd_state'pos(curr)));
end procedure;
-- illegal states
procedure fsm_covadd_illegal (
name : in string;
covdb : inout covPType ) is
begin
covdb.AddCross(ALL_ILLEGAL,ALL_ILLEGAL);
end procedure;
-- bin collection for Write FSM
procedure fsm_covcollect_wr (
signal reset : in std_logic;
signal clk : in std_logic;
signal state : in t_wr_state;
covdb : inout covPType) is
variable v_state : t_wr_state := t_wr_state'left;
begin
wait until reset='1';
loop
v_state := state;
wait until rising_edge(clk);
covdb.ICover((t_wr_state'pos(v_state), t_wr_state'pos(state)));
end loop;
end procedure;
-- bin collection for Read FSM
procedure fsm_covcollect_rd (
signal reset : in std_logic;
signal clk : in std_logic;
signal state : in t_rd_state;
covdb : inout covPType) is
variable v_state : t_rd_state := t_rd_state'left;
begin
wait until reset='1';
loop
v_state := state;
wait until rising_edge(clk);
covdb.ICover((t_rd_state'pos(v_state), t_rd_state'pos(state)));
end loop;
end procedure;
begin
-- Unit Under Test
UUT : entity work.axi4lite32_axi4full64_bridge
port map (
clk_i => tb_clk_i,
rst_n_i => tb_rst_n_i,
s_awaddr => tb_s_awaddr,
s_awlen => tb_s_awlen,
s_awsize => tb_s_awsize,
s_awburst => tb_s_awburst,
s_awvalid => tb_s_awvalid,
s_awready => tb_s_awready,
s_wdata => tb_s_wdata,
s_wstrb => tb_s_wstrb,
s_wlast => tb_s_wlast,
s_wvalid => tb_s_wvalid,
s_wready => tb_s_wready,
s_bresp => tb_s_bresp,
s_bvalid => tb_s_bvalid,
s_bready => tb_s_bready,
s_araddr => tb_s_araddr,
s_arlen => tb_s_arlen,
s_arsize => tb_s_arsize,
s_arburst => tb_s_arburst,
s_arvalid => tb_s_arvalid,
s_arready => tb_s_arready,
s_rdata => tb_s_rdata,
s_rresp => tb_s_rresp,
s_rlast => tb_s_rlast,
s_rvalid => tb_s_rvalid,
s_rready => tb_s_rready,
m_awaddr => tb_m_awaddr,
m_awvalid => tb_m_awvalid,
m_awready => tb_m_awready,
m_wdata => tb_m_wdata,
m_wstrb => tb_m_wstrb,
m_wvalid => tb_m_wvalid,
m_wready => tb_m_wready,
m_bresp => tb_m_bresp,
m_bvalid => tb_m_bvalid,
m_bready => tb_m_bready,
m_araddr => tb_m_araddr,
m_arvalid => tb_m_arvalid,
m_arready => tb_m_arready,
m_rdata => tb_m_rdata,
m_rresp => tb_m_rresp,
m_rvalid => tb_m_rvalid,
m_rready => tb_m_rready);
-- Clock generation
clk_proc : process
begin
while (not stop) loop
tb_clk_i <= '1';
wait for C_CLK_PERIOD/2;
tb_clk_i <= '0';
wait for C_CLK_PERIOD/2;
end loop;
wait;
end process clk_proc;
-- reset generation
tb_rst_n_i <= '0', '1' after 2*C_CLK_PERIOD;
-- Stimulus
stim : process
variable data : RandomPType;
variable ncycles : natural;
begin
data.InitSeed(g_seed);
report "[STARTING] with seed = " & to_string(g_seed);
wait until tb_rst_n_i = '1';
while (NOW < C_SIM_TIME) loop
wait until rising_edge(tb_clk_i);
-- AXI-4 Full inputs
tb_s_awaddr <= data.randSlv(32);
tb_s_awlen <= data.randSlv(0,4,8) when s_wstate=WR_IDLE else (others=>'0');
s_awvalid <= data.randSlv(1)(1);
tb_s_wdata <= data.randSlv(64);
s_wvalid <= data.randSlv(1)(1);
s_bready <= data.randSlv(1)(1);
tb_s_araddr <= data.randSlv(32);
tb_s_arlen <= data.randSlv(0,4,8) when s_rstate=RD_IDLE;
s_arvalid <= data.randSlv(1)(1);
s_rready <= data.randSlv(1)(1);
-- AXI-4 Lite inputs
s_m_awready <= data.randSlv(1)(1);
s_m_wready <= data.randSlv(1)(1);
tb_m_bresp <= data.randSlv(2);
s_m_bvalid <= data.randSlv(1)(1);
tb_m_rdata <= data.randSlv(32);
ncycles := ncycles + 1;
end loop;
report "Number of simulation cycles = " & to_string(ncycles);
stop <= TRUE;
report "Test PASS!";
wait;
end process stim;
-- Based on AMBA AXI4 specification (A3.4)
-- since the size is 64-bit, aXsize="110"
tb_s_awsize <= "110";
tb_s_arsize <= "110";
-- Assign to strobe the default value which
-- means that all byte lanes hold valid data
tb_s_wstrb <= (others=>'1');
-- AXBurst logic not included in RTL core
-- The default value chosen for INCR
tb_s_awburst <= "01";
tb_s_arburst <= "01";
-- Valid/Ready signals generation
-- both for slave and master
tb_s_awvalid <= s_awvalid when s_wstate=WR_IDLE else '0';
tb_s_wvalid <= s_wvalid when s_wstate=WR_MASTER else '0';
tb_s_arvalid <= s_arvalid when s_rstate=RD_IDLE else '0';
tb_s_rready <= s_rready when s_rstate=RD_SLAVE else '0';
tb_s_bready <= s_bready when s_wstate=WR_DONE else '0';
tb_m_bvalid <= s_m_bvalid when s_wstate=WR_WAIT else '0';
-- wlast generation
tb_s_wlast <= '1' when (unsigned(s_wlen)=0 and tb_s_wvalid='1') else '0';
-- AWREADY generation
-- awready is asserted for one clock cycle when both
-- awvalid and wvalid are asserted. awready is
-- de-asserted when reset is low.
process (tb_clk_i)
begin
if rising_edge(tb_clk_i) then
if tb_rst_n_i = '0' then
tb_m_awready <= '0';
else
if tb_m_awready = '0' and tb_m_awvalid = '1' and tb_m_wvalid = '1' then
-- slave is ready to accept write address when
-- there is a valid write address and write data
-- on the write address and data bus.
tb_m_awready <= '1';
else
tb_m_awready <= '0';
end if;
end if;
end if;
end process;
-- WREADY generation
-- wready is asserted for one clock cycle when both
-- awvalid and wvalid are asserted. wready is
-- de-asserted when reset is low.
process (tb_clk_i)
begin
if rising_edge(tb_clk_i) then
if tb_rst_n_i = '0' then
tb_m_wready <= '0';
else
if tb_m_wready = '0' and tb_m_wvalid = '1' and tb_m_awvalid = '1' then
-- slave is ready to accept write data when
-- there is a valid write address and write data
-- on the write address and data bus.
tb_m_wready <= '1';
else
tb_m_wready <= '0';
end if;
end if;
end if;
end process;
-- RVALID generation
process (tb_clk_i)
begin
if rising_edge(tb_clk_i) then
if tb_rst_n_i = '0' then
tb_m_rvalid <= '0';
tb_m_rresp <= "00";
else
if tb_m_arready = '1' and tb_m_arvalid = '1' and tb_m_rvalid = '0' then
-- Valid read data is available at the read data bus
tb_m_rvalid <= '1';
tb_m_rresp <= "00"; -- 'OKAY' response
elsif tb_m_rvalid = '1' and tb_m_rready = '1' then
tb_m_rvalid <= '0';
tb_m_rresp <= (others=>'X');
end if;
end if;
end if;
end process;
-- ARREADY generation
process (tb_clk_i)
begin
if rising_edge(tb_clk_i) then
if tb_rst_n_i = '0' then
tb_m_arready <= '0';
else
if tb_m_arready = '0' and tb_m_arvalid = '1' then
-- indicates that the slave has acceped the valid read address
tb_m_arready <= '1';
else
tb_m_arready <= '0';
end if;
end if;
end if;
end process;
--==============================================================================
-- Coverage --
--==============================================================================
-- **********************
-- **FSM for Write Part**
-- **********************
p_wr_fsm : process (tb_clk_i)
begin
if rising_edge (tb_clk_i) then
if tb_rst_n_i = '0' then
s_wstate <= WR_IDLE;
else
case s_wstate is
when WR_IDLE =>
if tb_s_awvalid = '1' then
s_waddr <= tb_s_awaddr;
s_wlen <= tb_s_awlen;
s_wsize <= tb_s_awsize;
s_wstate <= WR_MASTER;
end if;
when WR_MASTER =>
if tb_s_wvalid = '1' then
s_wstate <= WR_SLAVE;
end if;
when WR_SLAVE =>
s_wstate <= WR_SLAVE2;
when WR_SLAVE2 =>
if tb_m_wready = '1' then
s_wstate <= WR_WAIT;
end if;
when WR_WAIT =>
-- End of transfer ?
if tb_m_bvalid = '1' then
if s_waddr (2) = '1'
or (s_wsize (1 downto 0) = "10" and s_waddr (1) /= '1') -- 4 bytes
or (s_wsize (1 downto 0) = "01" and s_waddr (1 downto 0) /= "11")
or s_wsize (1 downto 0) = "00" -- 1 byte
then
if s_wlen = x"00" then
s_wstate <= WR_DONE;
else
s_wlen <= std_logic_vector(unsigned(s_wlen) - 1);
s_wstate <= WR_MASTER;
end if;
else
s_waddr (2) <= '1';
s_wstate <= WR_SLAVE;
end if;
end if;
when WR_DONE =>
if tb_s_bready = '1' then
s_wstate <= WR_IDLE;
end if;
end case;
end if;
end if;
end process;
-- Legal, illegal states and coverage
-- report for write side FSM
process
begin
-- all possible legal state changes
fsm_covadd_states_wr("WR_IDLE -> WR_MASTER",WR_IDLE ,WR_MASTER,sv_cover_wr);
fsm_covadd_states_wr("WR_MASTER -> WR_SLAVE ",WR_MASTER,WR_SLAVE ,sv_cover_wr);
fsm_covadd_states_wr("WR_SLAVE -> WR_SLAVE2",WR_SLAVE ,WR_SLAVE2,sv_cover_wr);
fsm_covadd_states_wr("WR_SLAVE2 -> WR_WAIT ",WR_SLAVE2,WR_WAIT ,sv_cover_wr);
fsm_covadd_states_wr("WR_WAIT -> WR_DONE ",WR_WAIT ,WR_DONE ,sv_cover_wr);
fsm_covadd_states_wr("WR_WAIT -> WR_MASTER",WR_WAIT ,WR_MASTER,sv_cover_wr);
fsm_covadd_states_wr("WR_WAIT -> WR_SLAVE ",WR_WAIT ,WR_SLAVE ,sv_cover_wr);
fsm_covadd_states_wr("WR_DONE -> WR_IDLE ",WR_DONE ,WR_IDLE ,sv_cover_wr);
-- when current and next state is the same
fsm_covadd_states_wr("WR_IDLE -> WR_IDLE ",WR_IDLE ,WR_IDLE ,sv_cover_wr);
fsm_covadd_states_wr("WR_MASTER -> WR_MASTER",WR_MASTER,WR_MASTER,sv_cover_wr);
fsm_covadd_states_wr("WR_WAIT -> WR_WAIT ",WR_WAIT ,WR_WAIT ,sv_cover_wr);
fsm_covadd_states_wr("WR_SLAVE2 -> WR_SLAVE2",WR_SLAVE2,WR_SLAVE2,sv_cover_wr);
fsm_covadd_states_wr("WR_DONE -> WR_DONE ",WR_DONE ,WR_DONE ,sv_cover_wr);
-- illegal states
fsm_covadd_illegal("ILLEGAL",sv_cover_wr);
wait;
end process;
-- collect the cov bins
fsm_covcollect_wr(tb_rst_n_i, tb_clk_i, s_wstate, sv_cover_wr);
-- coverage report
cov_report_wr : process
begin
wait until stop;
sv_cover_wr.writebin;
report "Test PASS!";
end process;
-- **********************
-- **FSM for Read part**
-- **********************
p_rd_fsm : process (tb_clk_i)
begin
if rising_edge (tb_clk_i) then
if tb_rst_n_i = '0' then
s_rstate <= RD_IDLE;
s_raddr <= (others => 'X');
s_rdata <= (others => '0');
else
case s_rstate is
when RD_IDLE =>
if tb_s_arvalid = '1' then
s_raddr <= tb_s_araddr;
s_rlen <= tb_s_arlen;
s_rsize <= tb_s_arsize;
-- Provide a clean result.
s_rdata <= (others => '0');
s_rstate <= RD_READ;
end if;
when RD_READ =>
if tb_m_rvalid = '1' then
if s_raddr (2) = '1' then
s_rdata (63 downto 32) <= tb_m_rdata;
else
s_rdata (31 downto 0) <= tb_m_rdata;
end if;
-- End of transfer on the master ?
if s_raddr (2) = '1'
or (s_rsize (1 downto 0) = "10" and s_raddr (1) /= '1') -- 4 bytes
or (s_rsize (1 downto 0) = "01" and s_raddr (1 downto 0) /= "11")
or s_rsize (1 downto 0) = "00" -- 1 byte
then
-- To master.
s_rstate <= RD_SLAVE;
else
-- Next transfer.
s_raddr (2) <= '1';
end if;
end if;
when RD_SLAVE =>
if tb_s_rready = '1' then
if s_rlen = x"00" then
s_rstate <= RD_IDLE;
else
s_rlen <= std_logic_vector(unsigned(s_rlen) - 1);
s_rstate <= RD_READ;
end if;
end if;
end case;
end if;
end if;
end process p_rd_fsm;
-- Legal, illegal states and coverage
-- report for read side FSM
process
begin
-- all possible legal state changes
fsm_covadd_states_rd("RD_IDLE -> RD_READ ",RD_IDLE ,RD_READ ,sv_cover_rd);
fsm_covadd_states_rd("RD_READ -> RD_SLAVE ",RD_READ ,RD_SLAVE ,sv_cover_rd);
fsm_covadd_states_rd("RD_SLAVE -> RD_READ ",RD_SLAVE ,RD_READ ,sv_cover_rd);
fsm_covadd_states_rd("RD_SLAVE -> RD_IDLE ",RD_SLAVE ,RD_IDLE ,sv_cover_rd);
-- when current and next state is the same
fsm_covadd_states_rd("RD_IDLE -> RD_IDLE ",RD_IDLE ,RD_IDLE ,sv_cover_rd);
fsm_covadd_states_rd("RD_READ -> RD_READ ",RD_READ ,RD_READ ,sv_cover_rd);
fsm_covadd_states_rd("RD_SLAVE -> RD_SLAVE ",RD_SLAVE ,RD_SLAVE ,sv_cover_rd);
-- illegal states
fsm_covadd_illegal("ILLEGAL",sv_cover_rd);
wait;
end process;
-- collect the cov bins
fsm_covcollect_rd(tb_rst_n_i, tb_clk_i, s_rstate, sv_cover_rd);
-- coverage report
cov_report_rd : process
begin
wait until stop;
sv_cover_rd.writebin;
report "Test PASS!";
end process;
--==============================================================================
-- Assertions --
--==============================================================================
-- Check AXI-4 FULL Slave signals
p_s_check : process(tb_s_awvalid, tb_s_wvalid,tb_s_bready,tb_s_arvalid,tb_s_rready)
begin
if falling_edge(tb_s_awvalid) then
assert (tb_s_awready = '0')
report "SLAVE: Wrong AWREADY for AWVALID LOW" severity error;
end if;
if falling_edge(tb_s_wvalid) then
assert (tb_s_wready = '0')
report "SLAVE: Wrong WREADY for WVALID LOW" severity error;
end if;
if falling_edge(tb_s_bready) then
assert (tb_s_bvalid = '0')
report "SLAVE: Wrong BVALID for BREADY LOW" severity error;
end if;
if falling_edge(tb_s_arvalid) then
assert (tb_s_arready = '0')
report "SLAVE: Wrong ARREADY for ARVALID LOW" severity error;
end if;
if falling_edge(tb_s_rready) then
assert (tb_s_rvalid = '0')
report "SLAVE: Wrong RVALID for RREADY LOW" severity error;
end if;
end process;
-- Check AXI-4 LITE Master signals
p_m_check : process(tb_m_awready,tb_m_wready,tb_m_bvalid,tb_m_arready,tb_m_rready)
begin
if falling_edge(tb_m_awready) then
assert (tb_m_awvalid = '0')
report "MASTER: Wrong AWVALID for AWREADY LOW" severity error;
end if;
if falling_edge(tb_m_wready) then
assert (tb_m_wvalid = '0')
report "MASTER: Wrong WVALID for WREADY LOW" severity error;
end if;
if falling_edge(tb_m_bvalid) then
assert (tb_m_bready = '0')
report "MASTER: Wrong BREADY for BVALID LOW" severity error;
end if;
if falling_edge(tb_m_arready) then
assert (tb_m_arvalid = '0')
report "MASTER: Wrong ARVALID for ARREADY LOW" severity error;
end if;
if falling_edge(tb_m_rready) then
assert (tb_m_rvalid = '0')
report "MASTER: Wrong RREADY for RVALID LOW" severity error;
end if;
end process;
--Slave RDATA (64-bit) include master's rdata (2x32-bits)
process(tb_clk_i)
begin
if rising_edge(tb_clk_i) then
if tb_rst_n_i = '0' then
rdata <= (others=>'0');
s_rd_cnt <= 0;
else
if tb_m_rready = '1' and tb_m_rvalid = '1' then
if s_rd_cnt = 0 then
if tb_m_araddr(2) = '1' then
rdata(63 downto 32) <= tb_m_rdata;
else
rdata(31 downto 0) <= tb_m_rdata;
end if;
s_rd_cnt <= s_rd_cnt + 1;
elsif s_rd_cnt = 1 then
if tb_m_araddr(2) = '1' then
rdata(63 downto 32) <= tb_m_rdata;
else
rdata(31 downto 0) <= tb_m_rdata;
end if;
s_rd_cnt <= 0;
end if;
elsif s_rstate=RD_IDLE and tb_s_arvalid = '1' then
rdata <= (others=>'0');
end if;
end if;
end if;
end process;
check_s_rdata : process(tb_clk_i)
begin
if rising_edge(tb_clk_i) then
if tb_s_rvalid = '1' AND tb_s_rready = '1' then
assert (rdata = tb_s_rdata)
report "RDATA mismatch" severity error;
end if;
end if;
end process;
-- Slave WDATA (32-bit) has a part of Master's WDATA (64-bits)
s_tmp_wdata <= tb_s_wdata when (tb_s_wready = '1');
process(tb_clk_i)
begin
if rising_edge(tb_clk_i) then
if s_wstate=WR_SLAVE OR (tb_s_wready = '1' and tb_s_wvalid = '1') then
if s_waddr(2) = '1' then
wdata <= s_tmp_wdata(63 downto 32);
else
wdata <= s_tmp_wdata(31 downto 0);
end if;
end if;
end if;
end process;
check_m_wdata : process(tb_clk_i)
begin
if rising_edge(tb_clk_i) then
if tb_m_wvalid = '1' AND tb_m_wready = '1' then
assert (wdata = tb_m_wdata)
report "WDATA mismatch" severity error;
end if;
end if;
end process;
end tb;
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
*
!.gitignore
!Manifest.py
!*.vhd
!*.cheby
!run.sh
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
action ="simulation"
sim_tool="ghdl"
target ="generic"
ghdl_opt="--std=08 -frelaxed-rules -Wno-hide"
sim_top ="tb_axi4lite_axi4full_bridge"
files ="tb_axi4lite_axi4full_bridge.vhd"
modules = {"local" : ["../../../",
"../../osvvm/",
]}
## Description
Testbench for [axi4lite_axi4full_bridge](../../modules/axi/axi4lite_axi4full_bridge/axi4lite_axi4full_bridge.vhd) which is a bridge from AXI4Lite to AXI4Full. Master is the axi4lite and the slave is axi4full.
NOTE: By default, the simulation time is 4ms. For any change in this, run the test and pass the simulation time as an argument (integer) to this script:
```console
./run.sh <simulation time>
```
#!/bin/bash -e
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
#This is a simple script to run simulations in GHDL
TB=tb_axi4lite_axi4full_bridge
if [ -z "$1" ]; then
TIME="4"
else
TIME="$1"
fi;
echo "Running simulation for $TB"
ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_sim_time=$TIME
-------------------------------------------------------------------------------
-- SPDX-FileCopyrightText: 2023 CERN (home.cern)
--
-- SPDX-License-Identifier: CERN-OHL-W-2.0+
-------------------------------------------------------------------------------
-- Title : Testbench for AXI4Lite to AXI4Full bridge
-- Project : General Cores
-------------------------------------------------------------------------------
-- File : tb_axi4lite_axi4full_bridge.vhd
-- Company : CERN (BE-CEM-EDL)
-- Author : Konstantinos Blantos <konstantinos.blantos@cern.ch>
-- Platform : FPGA-generics
-- Standard : VHDL '08
-------------------------------------------------------------------------------
--=============================================================================
-- Libraries & Packages --
--=============================================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- OSVVM library
library osvvm;
use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all;
--=============================================================================
-- Entity declaration for tb_axi4lite_axi4full_bridge --
--=============================================================================
entity tb_axi4lite_axi4full_bridge is
generic (
g_seed : natural;
g_sim_time : natural;
g_ADDR_WIDTH : natural := 32;
g_DATA_WIDTH : natural := 32;
g_ID_WIDTH : natural := 4;
g_LEN_WIDTH : natural := 8
);
end entity tb_axi4lite_axi4full_bridge;
--==============================================================================
-- Architecture declaration --
--==============================================================================
architecture tb of tb_axi4lite_axi4full_bridge is
--==========================================================
-- Constants
--==========================================================
constant C_CLK_PERIOD : time := 10 ns;
constant C_SIM_TIME : time := (g_sim_time*1.0 ms);
-- Used for FSM coverage
constant RSP_OKAY : std_logic_vector(1 downto 0) := b"00";
constant RSP_EXOKAY : std_logic_vector(1 downto 0) := b"01";
constant RSP_SLVERR : std_logic_vector(1 downto 0) := b"10";
constant RSP_DECERR : std_logic_vector(1 downto 0) := b"11";
--==========================================================
-- Signals
--==========================================================
signal tb_clk_i : std_logic;
signal tb_rst_n_i : std_logic;
-- AXI4-Full slave
signal tb_s_awaddr : std_logic_vector (g_ADDR_WIDTH-1 downto 0);
signal tb_s_awlen : std_logic_vector (g_LEN_WIDTH-1 downto 0);
signal tb_s_awsize : std_logic_vector (2 downto 0);
signal tb_s_awburst : std_logic_vector (1 downto 0);
signal tb_s_awid : std_logic_vector (g_ID_WIDTH-1 downto 0);
signal tb_s_awvalid : std_logic;
signal tb_s_awready : std_logic;
signal tb_s_wdata : std_logic_vector (g_DATA_WIDTH-1 downto 0);
signal tb_s_wstrb : std_logic_vector ((g_DATA_WIDTH/8)-1 downto 0);
signal tb_s_wid : std_logic_vector (g_ID_WIDTH-1 downto 0);
signal tb_s_wlast : std_logic;
signal tb_s_wvalid : std_logic;
signal tb_s_wready : std_logic;
signal tb_s_bid : std_logic_vector (g_ID_WIDTH-1 downto 0);
signal tb_s_bresp : std_logic_vector (1 downto 0);
signal tb_s_bvalid : std_logic;
signal tb_s_bready : std_logic;
signal tb_s_araddr : std_logic_vector (g_ADDR_WIDTH-1 downto 0);
signal tb_s_arlen : std_logic_vector (g_LEN_WIDTH-1 downto 0);
signal tb_s_arsize : std_logic_vector (2 downto 0);
signal tb_s_arburst : std_logic_vector (1 downto 0);
signal tb_s_arid : std_logic_vector (g_ID_WIDTH-1 downto 0);
signal tb_s_arvalid : std_logic;
signal tb_s_arready : std_logic;
signal tb_s_rdata : std_logic_vector (g_DATA_WIDTH-1 downto 0);
signal tb_s_rid : std_logic_vector (g_ID_WIDTH-1 downto 0);
signal tb_s_rresp : std_logic_vector (1 downto 0);
signal tb_s_rlast : std_logic;
signal tb_s_rvalid : std_logic;
signal tb_s_rready : std_logic;
-- AXI4-Lite master
signal tb_m_awaddr : std_logic_vector (g_ADDR_WIDTH-1 downto 0);
signal tb_m_awvalid : std_logic;
signal tb_m_awready : std_logic;
signal tb_m_wdata : std_logic_vector (g_DATA_WIDTH-1 downto 0);
signal tb_m_wstrb : std_logic_vector ((g_DATA_WIDTH/8)-1 downto 0);
signal tb_m_wvalid : std_logic;
signal tb_m_wready : std_logic;
signal tb_m_bresp : std_logic_vector (1 downto 0);
signal tb_m_bvalid : std_logic;
signal tb_m_bready : std_logic;
signal tb_m_araddr : std_logic_vector (g_ADDR_WIDTH-1 downto 0);
signal tb_m_arvalid : std_logic;
signal tb_m_arready : std_logic;
signal tb_m_rdata : std_logic_vector (g_DATA_WIDTH-1 downto 0);
signal tb_m_rresp : std_logic_vector (1 downto 0);
signal tb_m_rvalid : std_logic;
signal tb_m_rready : std_logic;
signal stop : boolean;
signal waddr : std_logic_vector(g_ADDR_WIDTH-1 downto 0) := (others=>'0');
signal s_wlen : std_logic_vector(g_LEN_WIDTH-1 downto 0) := (others=>'0');
signal s_wsize : std_logic_vector(2 downto 0) ;
signal s_raddr : std_logic_vector(g_ADDR_WIDTH-1 downto 0) := (others=>'0');
signal s_rlen : std_logic_vector(g_LEN_WIDTH-1 downto 0) := (others=>'0');
signal s_rsize : std_logic_vector(2 downto 0);
signal s_rdata : std_logic_vector(g_DATA_WIDTH-1 downto 0) := (others=>'0');
signal s_awvalid : std_logic;
signal s_wvalid : std_logic;
signal s_wstrb : std_logic_vector((g_DATA_WIDTH/8)-1 downto 0);
signal s_arvalid : std_logic;
signal s_rready : std_logic;
signal s_bready : std_logic;
signal m_bvalid : std_logic;
signal s_wid : std_logic_vector(g_ID_WIDTH-1 downto 0);
signal wdata : std_logic_vector(g_ADDR_WIDTH-1 downto 0);
signal tmp_awaddr : std_logic_vector(g_ADDR_WIDTH-1 downto 0) := (others=>'0');
signal tmp_araddr : std_logic_vector(g_ADDR_WIDTH-1 downto 0) := (others=>'0');
signal tmp_wdata : std_logic_vector(g_DATA_WIDTH-1 downto 0) := (others=>'0');
signal tmp_rdata : std_logic_vector(g_DATA_WIDTH-1 downto 0) := (others=>'0');
type t_wr_state is (WR_IDLE,
WR_MASTER, WR_SLAVE, WR_SLAVE2, WR_WAIT, WR_DONE);
type t_rd_state is (RD_IDLE, RD_READ, RD_SLAVE);
signal s_wstate : t_wr_state;
signal s_rstate : t_rd_state;
shared variable sv_cover_wr : covPType;
shared variable sv_cover_rd : covPType;
--==========================================================
-- Procedures used for FSM coverage
--==========================================================
-- legal states for Write FSM
procedure fsm_covadd_states_wr (
name : in string;
prev : in t_wr_state;
curr : in t_wr_state;
covdb : inout covPType) is
begin
covdb.AddCross ( name,
GenBin(t_wr_state'pos(prev)),
GenBin(t_wr_state'pos(curr)));
end procedure;
-- legal states for Read FSM
procedure fsm_covadd_states_rd (
name : in string;
prev : in t_rd_state;
curr : in t_rd_state;
covdb : inout covPType) is
begin
covdb.AddCross ( name,
GenBin(t_rd_state'pos(prev)),
GenBin(t_rd_state'pos(curr)));
end procedure;
-- illegal states
procedure fsm_covadd_illegal (
name : in string;
covdb : inout covPType ) is
begin
covdb.AddCross(ALL_ILLEGAL,ALL_ILLEGAL);
end procedure;
-- bin collection for Write FSM
procedure fsm_covcollect_wr (
signal reset : in std_logic;
signal clk : in std_logic;
signal state : in t_wr_state;
covdb : inout covPType) is
variable v_state : t_wr_state := t_wr_state'left;
begin
wait until reset='1';
loop
v_state := state;
wait until rising_edge(clk);
covdb.ICover((t_wr_state'pos(v_state), t_wr_state'pos(state)));
end loop;
end procedure;
-- bin collection for Read FSM
procedure fsm_covcollect_rd (
signal reset : in std_logic;
signal clk : in std_logic;
signal state : in t_rd_state;
covdb : inout covPType) is
variable v_state : t_rd_state := t_rd_state'left;
begin
wait until reset='1';
loop
v_state := state;
wait until rising_edge(clk);
covdb.ICover((t_rd_state'pos(v_state), t_rd_state'pos(state)));
end loop;
end procedure;
begin
-- Unit Under Test
UUT : entity work.axi4lite_axi4full_bridge
port map (
clk_i => tb_clk_i,
rst_n_i => tb_rst_n_i,
s_awaddr => tb_s_awaddr,
s_awlen => tb_s_awlen,
s_awsize => tb_s_awsize,
s_awburst => tb_s_awburst,
s_awid => tb_s_awid,
s_awvalid => tb_s_awvalid,
s_awready => tb_s_awready,
s_wdata => tb_s_wdata,
s_wstrb => tb_s_wstrb,
s_wid => tb_s_wid,
s_wlast => tb_s_wlast,
s_wvalid => tb_s_wvalid,
s_wready => tb_s_wready,
s_bid => tb_s_bid,
s_bresp => tb_s_bresp,
s_bvalid => tb_s_bvalid,
s_bready => tb_s_bready,
s_araddr => tb_s_araddr,
s_arlen => tb_s_arlen,
s_arsize => tb_s_arsize,
s_arburst => tb_s_arburst,
s_arid => tb_s_arid,
s_arvalid => tb_s_arvalid,
s_arready => tb_s_arready,
s_rdata => tb_s_rdata,
s_rid => tb_s_rid,
s_rresp => tb_s_rresp,
s_rlast => tb_s_rlast,
s_rvalid => tb_s_rvalid,
s_rready => tb_s_rready,
m_awaddr => tb_m_awaddr,
m_awvalid => tb_m_awvalid,
m_awready => tb_m_awready,
m_wdata => tb_m_wdata,
m_wstrb => tb_m_wstrb,
m_wvalid => tb_m_wvalid,
m_wready => tb_m_wready,
m_bresp => tb_m_bresp,
m_bvalid => tb_m_bvalid,
m_bready => tb_m_bready,
m_araddr => tb_m_araddr,
m_arvalid => tb_m_arvalid,
m_arready => tb_m_arready,
m_rdata => tb_m_rdata,
m_rresp => tb_m_rresp,
m_rvalid => tb_m_rvalid,
m_rready => tb_m_rready);
-- Clock generation
p_clk_gen : process
begin
while not stop loop
tb_clk_i <= '1';
wait for C_CLK_PERIOD/2;
tb_clk_i <= '0';
wait for C_CLK_PERIOD/2;
end loop;
wait;
end process p_clk_gen;
-- Reset generation
tb_rst_n_i <= '0', '1' after 2*C_CLK_PERIOD;
-- Stimulus
stim : process
variable data : RandomPType;
variable ncycles : natural;
begin
data.InitSeed(g_seed);
report "[STARTING] with seed = " & to_string(g_seed);
wait until tb_rst_n_i = '1';
while (NOW < C_SIM_TIME) loop
wait until rising_edge(tb_clk_i);
-- AXI-4 Full inputs
tb_s_awaddr <= data.randSlv(g_ADDR_WIDTH);
tb_s_awlen <= data.randSlv(0,4,8) when s_wstate=WR_IDLE else (others=>'0');
s_awvalid <= data.randSlv(1)(1);
tb_s_wdata <= data.randSlv(g_DATA_WIDTH);
s_wvalid <= data.randSlv(1)(1);
s_bready <= data.randSlv(1)(1);
tb_s_araddr <= data.randSlv(g_ADDR_WIDTH);
tb_s_arlen <= data.randSlv(0,4,8) when s_rstate=RD_IDLE;
s_arvalid <= data.randSlv(1)(1);
s_rready <= data.randSlv(1)(1);
-- AXI-4 Lite inputs
m_bvalid <= data.randSlv(1)(1);
tb_m_rdata <= data.randSlv(g_ADDR_WIDTH);
ncycles := ncycles + 1;
end loop;
report "Number of simulation cycles = " & to_string(ncycles);
stop <= TRUE;
report "Test PASS!";
wait;
end process stim;
-- Based on AMBA AXI4 specification (A3.4)
-- depending on the data width, axSize can differ
g_axSize_gen : if g_DATA_WIDTH > 0 generate
process
begin
case g_DATA_WIDTH is
when 1 =>
tb_s_awsize <= "000";
tb_s_arsize <= "000";
when 2 =>
tb_s_awsize <= "001";
tb_s_arsize <= "001";
when 4 =>
tb_s_awsize <= "010";
tb_s_arsize <= "010";
when 8 =>
tb_s_awsize <= "011";
tb_s_arsize <= "011";
when 16 =>
tb_s_awsize <= "100";
tb_s_arsize <= "100";
when 32 =>
tb_s_awsize <= "101";
tb_s_arsize <= "101";
when 64 =>
tb_s_awsize <= "110";
tb_s_arsize <= "110";
when 128 =>
tb_s_awsize <= "111";
tb_s_arsize <= "111";
when others =>
tb_s_awsize <= "000";
tb_s_arsize <= "000";
end case;
wait;
end process;
end generate g_axSize_gen;
-- Assign to strobe the default value which
-- means that all byte lanes hold valid data
tb_s_wstrb <= (others=>'1');
-- AXBurst logic not included in RTL
-- The default value chosen for INCR
tb_s_awburst <= "01";
tb_s_arburst <= "01";
-- Transactions ID. Set all to 0
-- for convenience
tb_s_awid <= (others=>'0');
tb_s_wid <= (others=>'0');
tb_s_arid <= (others=>'0');
-- BRESP for Master is always OKAY
-- just for convenience in testing
tb_m_bresp <= RSP_OKAY;
-- Valid/Ready signals generation
-- both for slave and master
tb_s_awvalid <= s_awvalid when s_wstate = WR_IDLE else '0';
tb_s_wvalid <= s_wvalid when s_wstate = WR_MASTER else '0';
tb_s_arvalid <= s_arvalid when s_rstate = RD_IDLE else '0';
tb_s_rready <= s_rready when s_rstate = RD_SLAVE else '0';
tb_s_bready <= s_bready when s_wstate = WR_DONE else '0';
tb_m_bvalid <= m_bvalid when s_wstate = WR_WAIT else '0';
-- Write side, signal assignments
tb_m_awaddr <= waddr;
tb_m_wdata <= wdata;
tb_m_wstrb <= s_wstrb;
tb_s_bid <= s_wid;
-- Read side, signal assignments
tb_m_araddr <= s_raddr;
tb_s_rdata <= s_rdata;
-- Wlast generation
tb_s_wlast <= '1' when (unsigned(s_wlen)=0 and tb_s_wvalid = '1') else '0';
-- AWREADY generation
-- awready is asserted for one clock cycle when both
-- awvalid and wvalid are asserted. awready is
-- de-asserted when reset is low.
process (tb_clk_i)
begin
if rising_edge(tb_clk_i) then
if tb_rst_n_i = '0' then
tb_m_awready <= '0';
else
if tb_m_awready = '0' and tb_m_awvalid = '1' and tb_m_wvalid = '1' then
-- slave is ready to accept write address when
-- there is a valid write address and write data
-- on the write address and data bus.
tb_m_awready <= '1';
else
tb_m_awready <= '0';
end if;
end if;
end if;
end process;
-- WREADY generation
-- wready is asserted for one clock cycle when both
-- awvalid and wvalid are asserted. wready is
-- de-asserted when reset is low.
process (tb_clk_i)
begin
if rising_edge(tb_clk_i) then
if tb_rst_n_i = '0' then
tb_m_wready <= '0';
else
if tb_m_wready = '0' and tb_m_wvalid = '1' and tb_m_awvalid = '1' then
-- slave is ready to accept write data when
-- there is a valid write address and write data
-- on the write address and data bus.
tb_m_wready <= '1';
else
tb_m_wready <= '0';
end if;
end if;
end if;
end process;
-- RVALID generation
process (tb_clk_i)
begin
if rising_edge(tb_clk_i) then
if tb_rst_n_i = '0' then
tb_m_rvalid <= '0';
tb_m_rresp <= "00";
else
if tb_m_arready = '1' and tb_m_arvalid = '1' and tb_m_rvalid = '0' then
-- Valid read data is available at the read data bus
tb_m_rvalid <= '1';
tb_m_rresp <= "00"; -- 'OKAY' response
elsif tb_m_rvalid = '1' and tb_m_rready = '1' then
tb_m_rvalid <= '0';
tb_m_rresp <= (others=>'X');
end if;
end if;
end if;
end process;
-- ARREADY generation
process (tb_clk_i)
begin
if rising_edge(tb_clk_i) then
if tb_rst_n_i = '0' then
tb_m_arready <= '0';
else
if tb_m_arready = '0' and tb_m_arvalid = '1' then
-- indicates that the slave has acceped the valid read address
tb_m_arready <= '1';
else
tb_m_arready <= '0';
end if;
end if;
end if;
end process;
--==============================================================================
-- Coverage --
--==============================================================================
-- **********************
-- **FSM for Write Part**
-- **********************
p_wr_fsm : process (tb_clk_i)
begin
if rising_edge (tb_clk_i) then
if tb_rst_n_i = '0' then
s_wstate <= WR_IDLE;
tb_s_awready <= '1';
tb_s_bvalid <= '0';
tb_m_awvalid <= '0';
tb_m_wvalid <= '0';
tb_m_bready <= '0';
else
case s_wstate is
when WR_IDLE =>
-- Wait until awvalid is ready.
if tb_s_awvalid = '1' then
-- Save transaction parameters
waddr <= tb_s_awaddr;
s_wlen <= tb_s_awlen;
s_wsize <= tb_s_awsize;
s_wid <= tb_s_awid;
-- Not anymore ready for addresses.
tb_s_awready <= '0';
-- But ready for data.
s_wstate <= WR_MASTER;
end if;
when WR_MASTER =>
-- Clear wvalid when coming from WR_SLAVE.
tb_m_wvalid <= '0';
if tb_s_wvalid = '1' then
-- Got data from master.
wdata <= tb_s_wdata;
s_wstrb <= tb_s_wstrb;
-- Address cycle.
tb_m_awvalid <= '1';
s_wstate <= WR_SLAVE;
end if;
when WR_SLAVE =>
if tb_m_awready = '1' then
-- Wait for address ack.
tb_m_awvalid <= '0';
end if;
-- Prepare data write cycle.
tb_m_wvalid <= '1';
s_wstate <= WR_SLAVE2;
when WR_SLAVE2 =>
if tb_m_awready = '1' then
-- Wait for address ack.
tb_m_awvalid <= '0';
end if;
if tb_m_wready = '1' then
-- Data ack.
tb_m_wvalid <= '0';
tb_m_bready <= '1';
s_wstate <= WR_WAIT;
end if;
when WR_WAIT =>
-- End of transfer ?
if tb_m_bvalid = '1' then
tb_m_bready <= '0';
if s_wlen = (g_LEN_WIDTH - 1 downto 0 => '0') then
-- End of the burst.
tb_s_bresp <= RSP_OKAY;
tb_s_bvalid <= '1';
s_wstate <= WR_DONE;
else
s_wlen <= std_logic_vector(unsigned(s_wlen) - 1);
s_wstate <= WR_MASTER;
end if;
end if;
when WR_DONE =>
if tb_s_bready = '1' then
tb_s_bvalid <= '0';
tb_s_awready <= '1';
s_wstate <= WR_IDLE;
end if;
end case;
end if;
end if;
end process p_wr_fsm;
-- Legal, illegal states and coverage
-- report for write side FSM
process
begin
-- all possible legal state changes
fsm_covadd_states_wr("WR_IDLE -> WR_MASTER",WR_IDLE ,WR_MASTER,sv_cover_wr);
fsm_covadd_states_wr("WR_MASTER -> WR_SLAVE ",WR_MASTER,WR_SLAVE ,sv_cover_wr);
fsm_covadd_states_wr("WR_SLAVE -> WR_SLAVE2",WR_SLAVE ,WR_SLAVE2,sv_cover_wr);
fsm_covadd_states_wr("WR_SLAVE2 -> WR_WAIT ",WR_SLAVE2,WR_WAIT ,sv_cover_wr);
fsm_covadd_states_wr("WR_WAIT -> WR_DONE ",WR_WAIT ,WR_DONE ,sv_cover_wr);
fsm_covadd_states_wr("WR_WAIT -> WR_MASTER",WR_WAIT ,WR_MASTER,sv_cover_wr);
fsm_covadd_states_wr("WR_DONE -> WR_IDLE ",WR_DONE ,WR_IDLE ,sv_cover_wr);
-- when current and next state is the same
fsm_covadd_states_wr("WR_IDLE -> WR_IDLE ",WR_IDLE ,WR_IDLE ,sv_cover_wr);
fsm_covadd_states_wr("WR_MASTER -> WR_MASTER",WR_MASTER,WR_MASTER,sv_cover_wr);
fsm_covadd_states_wr("WR_WAIT -> WR_WAIT ",WR_WAIT ,WR_WAIT ,sv_cover_wr);
fsm_covadd_states_wr("WR_SLAVE2 -> WR_SLAVE2",WR_SLAVE2,WR_SLAVE2,sv_cover_wr);
fsm_covadd_states_wr("WR_DONE -> WR_DONE ",WR_DONE ,WR_DONE ,sv_cover_wr);
-- illegal states
fsm_covadd_illegal("ILLEGAL",sv_cover_wr);
wait;
end process;
-- collect the cov bins
fsm_covcollect_wr(tb_rst_n_i, tb_clk_i, s_wstate, sv_cover_wr);
-- coverage report
cov_report_wr : process
begin
wait until stop;
sv_cover_wr.writebin;
report "Test PASS!";
end process;
-- **********************
-- **FSM for Read part**
-- **********************
p_read_fsm : process (tb_clk_i)
begin
if rising_edge (tb_clk_i) then
if tb_rst_n_i = '0' then
s_rstate <= RD_IDLE;
tb_s_arready <= '1';
tb_s_rvalid <= '0';
tb_m_arvalid <= '0';
s_raddr <= (others => 'X');
s_rdata <= (others => '0');
else
case s_rstate is
when RD_IDLE =>
-- Wait until awvalid is ready.
if tb_s_arvalid = '1' then
-- Save transaction parameters
s_raddr <= tb_s_araddr;
s_rlen <= tb_s_arlen;
s_rsize <= tb_s_arsize;
tb_s_rid <= tb_s_arid;
-- Provide a clean result.
s_rdata <= (others => '0');
-- Not anymore ready for addresses.
tb_s_arready <= '0';
-- Start transfer on the slave part.
tb_m_arvalid <= '1';
s_rstate <= RD_READ;
end if;
when RD_READ =>
if tb_m_arready = '1' then
-- Address has been accepted.
tb_m_arvalid <= '0';
end if;
if tb_m_rvalid = '1' then
-- Read data. Address must have been acked.
-- According to A3.4.3 of AXI4 spec, the AXI4 bus is little
-- endian.
s_rdata <= tb_m_rdata;
s_rstate <= RD_SLAVE;
tb_s_rresp <= RSP_OKAY;
tb_s_rvalid <= '1';
end if;
when RD_SLAVE =>
if tb_s_rready = '1' then
tb_s_rvalid <= '0';
if s_rlen = (g_LEN_WIDTH - 1 downto 0 => '0') then
-- End of the burst.
tb_s_arready <= '1';
s_rstate <= RD_IDLE;
else
s_rlen <= std_logic_vector(unsigned(s_rlen) - 1);
-- New beat.
tb_m_arvalid <= '1';
s_rstate <= RD_READ;
end if;
end if;
end case;
end if;
end if;
end process;
-- Legal, illegal states and coverage
-- report for read side FSM
process
begin
-- all possible legal state changes
fsm_covadd_states_rd("RD_IDLE -> RD_READ ",RD_IDLE ,RD_READ ,sv_cover_rd);
fsm_covadd_states_rd("RD_READ -> RD_SLAVE ",RD_READ ,RD_SLAVE ,sv_cover_rd);
fsm_covadd_states_rd("RD_SLAVE -> RD_READ ",RD_SLAVE ,RD_READ ,sv_cover_rd);
fsm_covadd_states_rd("RD_SLAVE -> RD_IDLE ",RD_SLAVE ,RD_IDLE ,sv_cover_rd);
-- when current and next state is the same
fsm_covadd_states_rd("RD_IDLE -> RD_IDLE ",RD_IDLE ,RD_IDLE ,sv_cover_rd);
fsm_covadd_states_rd("RD_READ -> RD_READ ",RD_READ ,RD_READ ,sv_cover_rd);
fsm_covadd_states_rd("RD_SLAVE -> RD_SLAVE ",RD_SLAVE ,RD_SLAVE ,sv_cover_rd);
-- illegal states
fsm_covadd_illegal("ILLEGAL",sv_cover_rd);
wait;
end process;
-- collect the cov bins
fsm_covcollect_rd(tb_rst_n_i, tb_clk_i, s_rstate, sv_cover_rd);
-- coverage report
cov_report_rd : process
begin
wait until stop;
sv_cover_rd.writebin;
report "Test PASS!";
end process;
--==============================================================================
-- Assertions --
--==============================================================================
-- Check AXI-4 FULL Slave signals
p_s_check : process(tb_s_awvalid, tb_s_wvalid,tb_s_bready,tb_s_arvalid,tb_s_rready)
begin
if falling_edge(tb_s_awvalid) then
assert (tb_s_awready = '0')
report "SLAVE: Wrong AWREADY for AWVALID LOW" severity failure;
end if;
if falling_edge(tb_s_wvalid) then
assert (tb_s_wready = '0')
report "SLAVE: Wrong WREADY for WVALID LOW" severity failure;
end if;
if falling_edge(tb_s_bready) then
assert (tb_s_bvalid = '0')
report "SLAVE: Wrong BVALID for BREADY LOW" severity failure;
end if;
if falling_edge(tb_s_arvalid) then
assert (tb_s_arready = '0')
report "SLAVE: Wrong ARREADY for ARVALID LOW" severity failure;
end if;
if falling_edge(tb_s_rready) then
assert (tb_s_rvalid = '0')
report "SLAVE: Wrong RVALID for RREADY LOW" severity failure;
end if;
end process;
-- Check AXI-4 LITE Master signals
p_m_check : process(tb_m_awready,tb_m_wready,tb_m_bvalid,tb_m_arready,tb_m_rvalid)
begin
if falling_edge(tb_m_awready) then
assert (tb_m_awvalid = '0')
report "MASTER: Wrong AWVALID for AWREADY LOW" severity failure;
end if;
if falling_edge(tb_m_wready) then
assert (tb_m_wvalid = '0')
report "MASTER: Wrong WVALID for WREADY LOW" severity failure;
end if;
if falling_edge(tb_m_bvalid) then
assert (tb_m_bready = '0')
report "MASTER: Wrong BREADY for BVALID LOW" severity failure;
end if;
if falling_edge(tb_m_arready) then
assert (tb_m_arvalid = '0')
report "MASTER: Wrong ARVALID for ARREADY LOW" severity failure;
end if;
if falling_edge(tb_m_rvalid) then
assert (tb_m_rready = '0')
report "MASTER: Wrong RREADY for RVALID LOW" severity failure;
end if;
end process;
-- Check that master and slave awaddr is the same
p_awaddr_check : process
begin
while not stop loop
wait until (tb_s_awready = '1' and tb_s_awvalid = '1');
tmp_awaddr <= tb_s_awaddr;
wait until (tb_m_awready = '1' and tb_m_awvalid = '1');
assert (tb_m_awaddr = tmp_awaddr);
end loop;
wait;
end process;
-- Check that master and slave araddr is the same
p_araddr_check : process
begin
while not stop loop
wait until (tb_s_arready = '1' and tb_s_arvalid = '1');
tmp_araddr <= tb_s_araddr;
wait until (tb_m_arready = '1' and tb_m_arvalid = '1');
assert (tb_m_araddr = tmp_araddr);
end loop;
wait;
end process;
-- Check that master and slave wdata is the same
p_wdata_check : process
begin
while not stop loop
wait until (tb_s_wready = '1' and tb_s_wvalid = '1');
tmp_wdata <= tb_s_wdata;
wait until (tb_m_wready = '1' and tb_m_wvalid = '1');
assert (tb_m_wdata = tmp_wdata);
end loop;
wait;
end process;
-- Check that master and slave rdata is the same
p_rdata_check : process
begin
while not stop loop
wait until (tb_m_rready = '1' and tb_m_rvalid = '1');
tmp_rdata <= tb_m_rdata;
wait until (tb_s_rready = '1' and tb_s_rvalid = '1');
assert (tb_s_rdata = tmp_rdata);
end loop;
wait;
end process;
end tb;
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
*
!.gitignore
!Manifest.py
!*.vhd
!*.cheby
!run.sh
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
action="simulation"
sim_tool="ghdl"
target="generic"
ghdl_opt="--std=08 -frelaxed-rules -Wno-hide"
sim_top="tb_xaxi4lite_wb_bridge"
files="tb_xaxi4lite_wb_bridge.vhd"
modules={"local" : ["../../../",
"../../osvvm/",
"../../../modules/wishbone",
"../../../modules/axi"]}
## Description
Testbench for [axi4lite_wb_bridge](../../modules/axi/axi4lite_wb_bridge/xaxi4lite_wb_bridge.vhd) which is a bridge from AXI4 Lite to Wishbone. In this core, the Master is AXI4 Lite and Slave is Wishbone.
NOTE: By default, the simulation time is 4ms. To change this, run the test and pass the simulation time as an argument (integer) to this script:
```console
./run.sh <simulation time>
```
#!/bin/bash -e
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
#This is a simple script to run simulations in GHDL
TB=tb_xaxi4lite_wb_bridge
if [ -z "$1" ]; then
TIME="4"
else
TIME="$1"
fi;
echo "Running simulation for $TB"
ghdl -r --std=08 -frelaxed-rules $TB -gg_seed=$RANDOM -gg_sim_time=$TIME
-------------------------------------------------------------------------------
-- SPDX-FileCopyrightText: 2023 CERN (home.cern)
--
-- SPDX-License-Identifier: CERN-OHL-W-2.0+
-------------------------------------------------------------------------------
-- Title : Testbench for WB-to-AXI4Lite bridge
-- Project : General Cores
-------------------------------------------------------------------------------
-- File : tb_xaxi4lite_wb_bridge.vhd
-- Author : Konstantinos Blantos <Konstantinos.blantos@cern.ch>
-- Company : CERN (BE-CEM-EDL)
-- Platform : FPGA-generics
-- Standard : VHDL '08
-------------------------------------------------------------------------------
-- Description:
--
-- Testbench for a WB Slave Classic to AXI4-Lite Master bridge.
-------------------------------------------------------------------------------
--=============================================================================
-- Libraries & Packages --
--=============================================================================
library ieee;
use ieee.std_logic_1164.all;
use work.axi4_pkg.all;
use work.wishbone_pkg.all;
-- OSVVM library
library osvvm;
use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all;
--=============================================================================
-- Entity declaration for tb_axi4lite_wb_bridge --
--=============================================================================
entity tb_xaxi4lite_wb_bridge is
generic (
g_seed : natural;
g_sim_time : natural);
end entity;
--==============================================================================
-- Architecture declaration --
--==============================================================================
architecture tb of tb_xaxi4lite_wb_bridge is
-- Constants
constant C_CLK_PERIOD : time := 10 ns;
constant C_SIM_TIME : time := (g_sim_time*1.0 ms);
-- Signals
signal tb_clk_i : std_logic;
signal tb_rst_n_i : std_logic;
signal tb_wb_slave_i : t_wishbone_slave_in;
signal tb_wb_slave_o : t_wishbone_slave_out;
signal tb_axi4_master_o : t_axi4_lite_master_out_32;
signal tb_axi4_master_i : t_axi4_lite_master_in_32;
signal stop : boolean;
signal s_araddr : std_logic_vector(31 downto 0);
signal s_wb_data : std_logic_vector(31 downto 0);
type t_state is (IDLE, READ, WRITE, WB_END);
signal s_state : t_state;
shared variable sv_cover : covPType;
--------------------------------------------------------------------------------
-- Procedures used for fsm coverage
--------------------------------------------------------------------------------
-- legal states
procedure fsm_covadd_states (
name : in string;
prev : in t_state;
curr : in t_state;
covdb : inout covPType) is
begin
covdb.AddCross ( name,
GenBin(t_state'pos(prev)),
GenBin(t_state'pos(curr)));
end procedure;
-- illegal states
procedure fsm_covadd_illegal (
name : in string;
covdb : inout covPType ) is
begin
covdb.AddCross(ALL_ILLEGAL,ALL_ILLEGAL);
end procedure;
-- bin collection
procedure fsm_covcollect (
signal reset : in std_logic;
signal clk : in std_logic;
signal state : in t_state;
covdb : inout covPType) is
variable v_state : t_state := t_state'left;
begin
wait until reset='1';
loop
v_state := state;
wait until rising_edge(clk);
covdb.ICover((t_state'pos(v_state), t_state'pos(state)));
end loop;
end procedure;
begin
-- Unit Under Test
UUT : entity work.xaxi4lite_wb_bridge
port map (
rst_n_i => tb_rst_n_i,
clk_i => tb_clk_i,
wb_slave_i => tb_wb_slave_i,
wb_slave_o => tb_wb_slave_o,
axi4_master_i => tb_axi4_master_i,
axi4_master_o => tb_axi4_master_o);
-- Clock generation
clk_proc : process
begin
while (not stop) loop
tb_clk_i <= '1';
wait for C_CLK_PERIOD/2;
tb_clk_i <= '0';
wait for C_CLK_PERIOD/2;
end loop;
wait;
end process clk_proc;
-- reset generation
tb_rst_n_i <= '0', '1' after 2*C_CLK_PERIOD;
-- Stimulus
stim : process
variable data : RandomPType;
variable ncycles : natural;
begin
data.InitSeed(g_seed);
report "[STARTING] with seed = " & to_string(g_seed);
wait until tb_rst_n_i = '1';
while (NOW < C_SIM_TIME) loop
wait until rising_edge(tb_clk_i);
-- Slave inputs
tb_wb_slave_i.cyc <= data.randSlv(1)(1);
tb_wb_slave_i.stb <= data.randSlv(1)(1);
tb_wb_slave_i.we <= data.randSlv(1)(1);
tb_wb_slave_i.adr <= data.randSlv(32);
tb_wb_slave_i.sel <= data.randSlv(4);
tb_wb_slave_i.dat <= data.randSlv(32);
-- Master inputs
tb_axi4_master_i.ARREADY <= data.randSlv(1)(1);
tb_axi4_master_i.RVALID <= data.randSlv(1)(1);
tb_axi4_master_i.RRESP <= data.randSlv(2);
tb_axi4_master_i.RDATA <= data.randSlv(32);
tb_axi4_master_i.AWREADY <= data.randSlv(1)(1);
tb_axi4_master_i.WREADY <= data.randSlv(1)(1);
tb_axi4_master_i.BVALID <= data.randSlv(1)(1);
tb_axi4_master_i.BRESP <= data.randSlv(2);
ncycles := ncycles + 1;
end loop;
report "Number of simulation cycles = " & to_string(ncycles);
stop <= TRUE;
report "Test PASS!";
wait;
end process stim;
--==============================================================================
-- Coverage --
--==============================================================================
-- FSM
fsm_proc : process(tb_clk_i)
begin
if rising_edge(tb_clk_i) then
if tb_rst_n_i = '0' then
s_state <= IDLE;
else
case s_state is
-------------------------------------------
-- IDLE STATE --
------------------------------------------
when IDLE =>
if tb_wb_slave_i.stb = '1' and tb_wb_slave_i.we = '0' then
s_state <= READ;
elsif tb_wb_slave_i.stb = '1' and tb_wb_slave_i.we = '1' then
s_state <= WRITE;
else
s_state <= IDLE;
end if;
-------------------------------------------
-- READ CYCLE --
-------------------------------------------
when READ =>
if (tb_axi4_master_i.RVALID = '1') then
s_state <= WB_END;
else
s_state <= READ;
end if;
-------------------------------------------
-- WRITE CYCLE --
-------------------------------------------
when WRITE =>
if (tb_axi4_master_i.BVALID = '1') then
s_state <= WB_END;
else
s_state <= WRITE;
end if;
------------------------------------------
-- WB_END --
------------------------------------------
when WB_END =>
if (tb_wb_slave_i.stb = '0') then
s_state <= IDLE;
else
s_state <= WB_END;
end if;
end case;
end if;
end if;
end process;
process
begin
-- all possible legal state changes
fsm_covadd_states("IDLE -> READ ",IDLE, READ, sv_cover);
fsm_covadd_states("IDLE -> WRITE ",IDLE, WRITE, sv_cover);
fsm_covadd_states("READ -> WB_END",READ, WB_END,sv_cover);
fsm_covadd_states("WRITE -> WB_END",WRITE, WB_END,sv_cover);
fsm_covadd_states("WB_END -> IDLE ",WB_END,IDLE, sv_cover);
-- when current and next state is the same
fsm_covadd_states("IDLE -> IDLE ",IDLE, IDLE, sv_cover);
fsm_covadd_states("READ -> READ ",READ, READ, sv_cover);
fsm_covadd_states("WRITE -> READ ",WRITE, WRITE, sv_cover);
fsm_covadd_states("WB_END -> WB_END",WB_END,WB_END,sv_cover);
-- illegal states
fsm_covadd_illegal("ILLEGAL",sv_cover);
wait;
end process;
-- collect the cov bins
fsm_covcollect(tb_rst_n_i, tb_clk_i, s_state, sv_cover);
-- coverage report
cov_report : process
begin
wait until stop;
sv_cover.writebin;
report "Test PASS!";
end process;
--==============================================================================
-- Assertions --
--==============================================================================
-- Check wb and axi4lite signals when IDLE
process
begin
while (not stop) loop
wait until rising_edge(tb_clk_i) and tb_rst_n_i /= '0';
if s_state = IDLE then
if tb_wb_slave_i.stb = '1' and tb_wb_slave_i.we = '0' then
s_araddr <= tb_wb_slave_i.adr;
wait for C_CLK_PERIOD;
assert (tb_axi4_master_o.ARADDR = s_araddr)
report "Read Address mismatch" severity failure;
assert (tb_axi4_master_o.ARVALID = '1')
report "ARVALID mismatch" severity failure;
assert (tb_axi4_master_o.RREADY = '1')
report "RREADY mismatch" severity failure;
else
s_araddr <= (others=>'0');
end if;
end if;
end loop;
wait;
end process;
-- Check wb and axi4lite signals when READ
process
begin
while (not stop) loop
wait until rising_edge(tb_clk_i) and tb_rst_n_i /= '0';
if s_state = READ then
assert (tb_wb_slave_o.ack = '0' and tb_wb_slave_o.err = '0')
report "ACK and ERR not zero when READ" severity failure;
assert (tb_axi4_master_o.RREADY = '1')
report "RREADY not HIGH when READ" severity failure;
if falling_edge(tb_axi4_master_i.ARREADY) then
assert (tb_axi4_master_o.ARVALID = '0')
report "WRONG ARVALID" severity failure;
end if;
if tb_axi4_master_i.RVALID = '1' AND tb_axi4_master_i.RRESP = c_AXI4_RESP_OKAY then
s_wb_data <= tb_axi4_master_i.RDATA;
wait for 1 ns;
assert (tb_wb_slave_o.dat = s_wb_data)
report "WB slave output data mismatch" severity failure;
assert (tb_wb_slave_o.ack = '1' AND tb_wb_slave_o.err = '0')
report "Wrong ACK and ERR for specific RRESP" severity failure;
elsif tb_axi4_master_i.RVALID = '1' then
wait for 1 ns;
assert (tb_wb_slave_o.ack = '0' AND tb_Wb_slave_o.err = '1')
report "Wrong ACK and ERR" severity failure;
else
s_wb_data <= (others=>'0');
assert (tb_wb_slave_o.ack = '0' AND tb_Wb_slave_o.err = '0')
report "ACK and ERR are not zero" severity failure;
end if;
end if;
end loop;
wait;
end process;
-- Check wb and axi4lite signals when WRITE
process
begin
while (not stop) loop
wait until rising_edge(tb_clk_i) and tb_rst_n_i = '1';
if s_state = WRITE then
assert (tb_wb_slave_o.ack = '0' AND tb_wb_slave_o.err = '0')
report "ACK and ERR not zero when WRITE" severity failure;
if falling_edge(tb_axi4_master_i.AWREADY) then
assert (tb_axi4_master_o.AWVALID = '0')
report "Wrong AWVALID for AWREADY HIGH" severity failure;
end if;
if falling_edge(tb_axi4_master_i.WREADY) then
assert (tb_axi4_master_o.WVALID = '0')
report "Wrong WVALID for WREADY HIGH" severity failure;
end if;
if rising_edge(tb_axi4_master_i.BVALID) then
assert (tb_axi4_master_o.BREADY = '0')
report "Wrong BREADY for BVALID HIGH" severity failure;
elsif falling_edge(tb_axi4_master_i.BVALID) then
assert (tb_axi4_master_o.BREADY = '1')
report "Wrong BREADY for BVALID LOW" severity failure;
end if;
end if;
end loop;
wait;
end process;
-- Check wb signals when WB_END state
process
begin
while (not stop) loop
wait until rising_edge(tb_clk_i) and tb_rst_n_i = '1';
if s_state = WB_END then
wait for C_CLK_PERIOD;
assert (tb_wb_slave_o.ack = '0' AND tb_wb_slave_o.err = '0')
report "ACK and ERR are not zero when WB_END" severity failure;
end if;
end loop;
wait;
end process;
end tb;
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
*
!.gitignore
!Manifest.py
!*.vhd
!*.cheby
!run.sh
target = "xilinx"
action = "simulation"
sim_tool = "modelsim"
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
target = "xilinx"
action = "simulation"
sim_tool = "ghdl"
top_module = "sim_top_ps_gpio"
syn_device = "XC7Z010"
ghdl_opt = "--std=08 -frelaxed-rules -Wno-hide"
files = [ "gpio_axi.vhd", "sim_top_ps_gpio.vhd" ]
modules = { "local" : ["../../../"] }
modules = { "local" : ["../../../",
"../../osvvm/"] }
-- SPDX-FileCopyrightText: 2023 CERN (home.cern)
--
-- SPDX-License-Identifier: CERN-OHL-W-2.0+
memory-map:
bus: axi4-lite-32
name: axi_gpio
......
-- SPDX-FileCopyrightText: 2023 CERN (home.cern)
--
-- SPDX-License-Identifier: CERN-OHL-W-2.0+
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
......@@ -78,7 +82,7 @@ begin
wready <= axi_wip and wr_ack_int;
bvalid <= axi_wdone;
process (aclk, areset_n) begin
if areset_n = '0' then
if areset_n = '0' then
axi_wip <= '0';
axi_wdone <= '0';
elsif rising_edge(aclk) then
......@@ -93,7 +97,7 @@ begin
arready <= axi_rip and rd_ack_int;
rvalid <= axi_rdone;
process (aclk, areset_n) begin
if areset_n = '0' then
if areset_n = '0' then
axi_rip <= '0';
axi_rdone <= '0';
rdata <= (others => '0');
......@@ -117,7 +121,7 @@ begin
-- Process for write requests.
process (aclk, areset_n) begin
if areset_n = '0' then
if areset_n = '0' then
wr_ack_int <= '0';
out_b0_reg <= "00000000000000000000000000000000";
out_b1_reg <= "00000000000000000000000000000000";
......@@ -128,41 +132,41 @@ begin
elsif rising_edge(aclk) then
wr_ack_int <= '0';
case awaddr(15 downto 2) is
when "10100000010000" =>
when "10100000010000" =>
-- Register out_b0
if wr_int = '1' then
out_b0_reg <= wdata;
end if;
wr_ack_int <= wr_int;
when "10100000010001" =>
when "10100000010001" =>
-- Register out_b1
if wr_int = '1' then
out_b1_reg <= wdata;
end if;
wr_ack_int <= wr_int;
when "10100000011000" =>
when "10100000011000" =>
-- Register in_b0
when "10100000011001" =>
when "10100000011001" =>
-- Register in_b1
when "10100010000001" =>
when "10100010000001" =>
-- Register dir_b0
if wr_int = '1' then
dir_b0_reg <= wdata;
end if;
wr_ack_int <= wr_int;
when "10100010000010" =>
when "10100010000010" =>
-- Register oen_b0
if wr_int = '1' then
oen_b0_reg <= wdata;
end if;
wr_ack_int <= wr_int;
when "10100010010001" =>
when "10100010010001" =>
-- Register dir_b1
if wr_int = '1' then
dir_b1_reg <= wdata;
end if;
wr_ack_int <= wr_int;
when "10100010010010" =>
when "10100010010010" =>
-- Register oen_b1
if wr_int = '1' then
oen_b1_reg <= wdata;
......@@ -176,36 +180,36 @@ begin
-- Process for registers read.
process (aclk, areset_n) begin
if areset_n = '0' then
if areset_n = '0' then
rd_ack1_int <= '0';
reg_rdat_int <= (others => 'X');
elsif rising_edge(aclk) then
reg_rdat_int <= (others => '0');
case araddr(15 downto 2) is
when "10100000010000" =>
when "10100000010000" =>
-- out_b0
rd_ack1_int <= rd_int;
when "10100000010001" =>
when "10100000010001" =>
-- out_b1
rd_ack1_int <= rd_int;
when "10100000011000" =>
when "10100000011000" =>
-- in_b0
reg_rdat_int <= in_b0_i;
rd_ack1_int <= rd_int;
when "10100000011001" =>
when "10100000011001" =>
-- in_b1
reg_rdat_int <= in_b1_i;
rd_ack1_int <= rd_int;
when "10100010000001" =>
when "10100010000001" =>
-- dir_b0
rd_ack1_int <= rd_int;
when "10100010000010" =>
when "10100010000010" =>
-- oen_b0
rd_ack1_int <= rd_int;
when "10100010010001" =>
when "10100010010001" =>
-- dir_b1
rd_ack1_int <= rd_int;
when "10100010010010" =>
when "10100010010010" =>
-- oen_b1
rd_ack1_int <= rd_int;
when others =>
......@@ -219,35 +223,35 @@ begin
-- By default ack read requests
dato <= (others => '0');
case araddr(15 downto 2) is
when "10100000010000" =>
when "10100000010000" =>
-- out_b0
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100000010001" =>
when "10100000010001" =>
-- out_b1
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100000011000" =>
when "10100000011000" =>
-- in_b0
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100000011001" =>
when "10100000011001" =>
-- in_b1
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100010000001" =>
when "10100010000001" =>
-- dir_b0
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100010000010" =>
when "10100010000010" =>
-- oen_b0
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100010010001" =>
when "10100010010001" =>
-- dir_b1
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100010010010" =>
when "10100010010010" =>
-- oen_b1
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
......
vsim -t 10fs work.sim_top_ps_gpio -voptargs="+acc"
set StdArithNoWarnings 1
set NumericStdNoWarnings 1
do wave.do
radix -hexadecimal
run 200ms
wave zoomfull
radix -hexadecimal
#!/bin/bash -e
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
#This is a simple script to run simulations in GHDL
TB=sim_top_ps_gpio
echo "Running simulation for $TB"
ghdl -r --std=08 -frelaxed-rules $TB --stop-time=2ms
echo "********************************************"
-------------------------------------------------------------------------------
-- SPDX-FileCopyrightText: 2023 CERN (home.cern)
--
-- SPDX-License-Identifier: CERN-OHL-W-2.0+
-------------------------------------------------------------------------------
-- Title : AXI PS_GPIO Expander for Zynq-7 Testbench
-- Project : General Cores
-------------------------------------------------------------------------------
......@@ -16,33 +20,35 @@
-- using xsim or GHDL.
--
-------------------------------------------------------------------------------
-- Copyright (c) 2019 CERN
--------------------------------------------------------------------------------
-- 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.
--------------------------------------------------------------------------------
--=============================================================================
-- Libraries & Packages --
--=============================================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
--=============================================================================
-- Entity declaration for sim_top_ps_gpio --
--=============================================================================
entity sim_top_ps_gpio is
end sim_top_ps_gpio;
--==============================================================================
-- Architecture declaration --
--==============================================================================
architecture behav of sim_top_ps_gpio is
-- Constants
constant c_PERIOD : time := 10 ns;
constant c_NUM : integer := 54;
-- Signals
signal clk, rst_n : std_logic;
signal ARVALID : std_logic;
signal AWVALID : std_logic;
signal BREADY : std_logic;
......@@ -105,7 +111,7 @@ begin
ARADDR => ARADDR,
AWADDR => AWADDR,
WDATA => WDATA,
WSTRB => WSTRB,
WSTRB => WSTRB,
ARREADY => ARREADY,
AWREADY => AWREADY,
BVALID => BVALID,
......@@ -128,7 +134,7 @@ begin
araddr => ARADDR(15 downto 2),
awaddr => AWADDR(15 downto 2),
wdata => WDATA,
wstrb => WSTRB,
wstrb => WSTRB,
arready => ARREADY,
awready => AWREADY,
bvalid => BVALID,
......@@ -194,4 +200,34 @@ begin
wait;
end process;
--==============================================================================
-- Assertions --
--==============================================================================
-- Check AXI-4 LITE signals
p_axi_check : process(AWREADY,WREADY,BVALID,ARREADY,RVALID)
begin
if falling_edge(AWREADY) then
assert (AWVALID = '0')
report "Wrong AWVALID for AWREADY LOW" severity failure;
end if;
if falling_edge(WREADY) then
assert (WVALID = '0')
report "Wrong WVALID for WREADY LOW" severity failure;
end if;
if falling_edge(BVALID) then
assert (BREADY = '0')
report "Wrong BREADY for BVALID LOW" severity failure;
end if;
if falling_edge(ARREADY) then
assert (ARVALID = '0')
report "Wrong ARVALID for ARREADY LOW" severity failure;
end if;
if falling_edge(RVALID) then
assert (RREADY = '0')
report "Wrong RREADY for RVALID LOW" severity failure;
end if;
end process;
end behav;
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /sim_top_ps_gpio/clk
add wave -noupdate /sim_top_ps_gpio/rst_n
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/ARVALID
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/AWVALID
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/BREADY
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/RREADY
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/WVALID
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/ARADDR
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/AWADDR
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/WDATA
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/WSTRB
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/ARREADY
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/AWREADY
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/BVALID
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/RVALID
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/WREADY
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/BRESP
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/RRESP
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/RDATA
add wave -noupdate /sim_top_ps_gpio/error_b1
add wave -noupdate /sim_top_ps_gpio/out_b0
add wave -noupdate /sim_top_ps_gpio/out_b1
add wave -noupdate /sim_top_ps_gpio/dir_b0
add wave -noupdate /sim_top_ps_gpio/dir_b1
add wave -noupdate /sim_top_ps_gpio/oen_b0
add wave -noupdate /sim_top_ps_gpio/oen_b1
add wave -noupdate /sim_top_ps_gpio/gpio_out
add wave -noupdate /sim_top_ps_gpio/gpio_oe
add wave -noupdate /sim_top_ps_gpio/gpio_dir
add wave -noupdate /sim_top_ps_gpio/gpio_in
add wave -noupdate /sim_top_ps_gpio/U_EXP/state
add wave -noupdate /sim_top_ps_gpio/U_EXP/gpio_oe_prev
add wave -noupdate /sim_top_ps_gpio/U_EXP/gpio_dir_prev
add wave -noupdate /sim_top_ps_gpio/U_EXP/gpio_out_prev
add wave -noupdate /sim_top_ps_gpio/U_EXP/gpio_oe_changed
add wave -noupdate /sim_top_ps_gpio/U_EXP/gpio_dir_changed
add wave -noupdate /sim_top_ps_gpio/U_EXP/gpio_out_changed
add wave -noupdate /sim_top_ps_gpio/U_EXP/refresh_all
add wave -noupdate /sim_top_ps_gpio/U_EXP/current_bank
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {0 fs} 0}
quietly wave cursor active 0
configure wave -namecolwidth 150
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits fs
update
WaveRestoreZoom {0 fs} {5780 fs}
action = "simulation"
sim_tool = "modelsim"
vcom_opt = "-mixedsvvh l"
target = "xilinx"
syn_device = "xc6slx45t"
top_module = "main" # for hdlmake2
sim_top = "main" # for hdlmake3
include_dirs = [
"../../../sim/"
]
modules = {
"local" : [
"../../../",
],
}
files = [
"main.sv",
"gc_cordic_tb.vhd"
]
import matplotlib.pyplot as plt
import pandas as pd
def main():
filename = "res.txt"
data = pd.read_csv(filename, header=None, names=["ix", "iy", "iz","ox", "oy", "oz", "ex", "ey", "ez", "mode", "submode"])
data["mode"][data["mode"] == 0] = "vector"
data["mode"][data["mode"] == 1] = "rotate"
data["submode"][data["submode"] == 0] = "circular"
data["submode"][data["submode"] == 1] = "linear"
data.insert(len(data.columns), "err_x",abs(data["ox"]-data["ex"]))
data.insert(len(data.columns), "err_y",abs(data["oy"]-data["ey"]))
data.insert(len(data.columns), "err_z",abs(data["oz"]-data["ez"]))
print(data)
rotcirc = data[data["mode"] == "rotate"]
rotcirc = rotcirc[rotcirc["submode"] == "circular"]
rotlinear = data[data["mode"] == "rotate"]
rotlinear = rotlinear[rotlinear["submode"] == "linear"]
vectcirc = data[data["mode"] == "vector"]
vectcirc = vectcirc[vectcirc["submode"] == "circular"]
vectlinear = data[data["mode"] == "vector"]
vectlinear = vectlinear[vectlinear["submode"] == "linear"]
print(rotcirc )
print(rotlinear )
print(vectcirc )
print(vectlinear )
# How is error defined ?
# rotate/Circular -> 2 errors, xo and yo
# rotate/linear -> 2 errors, x and y
# vector/circular -> 2 errors, x and z
# vector/linear -> 2 errors, x and z
import numpy as np
fig = plt.figure()
# syntax for 3-D projection
ax = plt.axes(projection ='3d')
# defining axes
x = vectcirc["ix"]
y = vectcirc["iy"]
z = vectcirc["iz"]
err_x = vectcirc["err_x"]
err_y = vectcirc["err_y"]
err_z = vectcirc["err_z"]
plt.subplot(4,3,1)
plt.plot(x, err_x, 'x')
plt.plot(y, err_x, 'x')
plt.plot(z, err_x, 'x')
#plt.legend(["errx = f(x)", "errx = f(y)", "errx = f(z)"])
plt.title("vect/circle : magnitude error")
plt.subplot(4,3,2)
plt.plot(x, err_y, 'x')
plt.plot(y, err_y, 'x')
plt.plot(z, err_y, 'x')
#plt.legend(["erry = f(x)", "erry = f(y)", "erry = f(z)"])
plt.title("vector/circle")
plt.subplot(4,3,3)
plt.plot(x, err_z, 'x')
plt.plot(y, err_z, 'x')
plt.plot(z, err_z, 'x')
#plt.legend(["errz = f(x)", "errz = f(y)", "errz = f(z)"])
plt.title("vector/circle : angle error")
x = rotcirc["ix"]
y = rotcirc["iy"]
z = rotcirc["iz"]
err_x = rotcirc["err_x"]
err_y = rotcirc["err_y"]
err_z = rotcirc["err_z"]
plt.subplot(4,3,4)
plt.plot(x, err_x, 'x')
plt.plot(y, err_x, 'x')
plt.plot(z, err_x, 'x')
#plt.legend(["errx = f(x)", "errx = f(y)", "errx = f(z)"])
plt.title("rotate/circle")
plt.subplot(4,3,5)
plt.plot(x, err_y, 'x')
plt.plot(y, err_y, 'x')
plt.plot(z, err_y, 'x')
#plt.legend(["erry = f(x)", "erry = f(y)", "erry = f(z)"])
plt.title("rotate/circle")
plt.subplot(4,3,6)
plt.plot(x, err_z, 'x')
plt.plot(y, err_z, 'x')
plt.plot(z, err_z, 'x')
#plt.legend(["errz = f(x)", "errz = f(y)", "errz = f(z)"])
plt.title("rotate/circle")
x = rotlinear["ix"]
y = rotlinear["iy"]
z = rotlinear["iz"]
err_x = rotlinear["err_x"]
err_y = rotlinear["err_y"]
err_z = rotlinear["err_z"]
plt.subplot(4,3,7)
plt.plot(x, err_x, 'x')
plt.plot(y, err_x, 'x')
plt.plot(z, err_x, 'x')
#plt.legend(["errx = f(x)", "errx = f(y)", "errx = f(z)"])
plt.title("rotate/linear")
plt.subplot(4,3,8)
plt.plot(x, err_y, 'x')
plt.plot(y, err_y, 'x')
plt.plot(z, err_y, 'x')
#plt.legend(["erry = f(x)", "erry = f(y)", "erry = f(z)"])
plt.title("rotate/linear")
plt.subplot(4,3,9)
plt.plot(x, err_z, 'x')
plt.plot(y, err_z, 'x')
plt.plot(z, err_z, 'x')
#plt.legend(["errz = f(x)", "errz = f(y)", "errz = f(z)"])
plt.title("rotate/linear")
x = vectlinear["ix"]
y = vectlinear["iy"]
z = vectlinear["iz"]
xy = vectlinear["iy"]/vectlinear["ix"]
err_x = vectlinear["err_x"]
err_y = vectlinear["err_y"]
err_z = vectlinear["err_z"]
plt.subplot(4,3,10)
plt.plot(xy, err_x, 'x')
plt.plot(xy, err_y, 'x')
plt.plot(xy, err_z, 'x')
#plt.legend(["errx = f(y/x)", "erry = f(y/x)", "errz = f(y/x)"])
plt.title("vector/linear: ratio error = f(ratio)")
plt.subplot(4,3,11)
plt.plot(x, err_y, 'x')
plt.plot(y, err_y, 'x')
plt.plot(z, err_y, 'x')
#plt.legend(["erry = f(x)", "erry = f(y)", "erry = f(z)"])
plt.title("vector/linear")
plt.subplot(4,3,12)
plt.plot(x, err_z, 'x')
plt.plot(y, err_z, 'x')
plt.plot(z, err_z, 'x')
#plt.legend(["errz = f(x)", "errz = f(y)", "errz = f(z)"])
plt.title("vector/linear: ratio error")
plt.show()
if __name__ == "__main__":
main()
\ No newline at end of file
-----------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------
--
-- Description : Simple VHDL cordic testbench to hunt for edge cases and fix these.
--
------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.textio.all;
use work.gc_cordic_pkg.all;
entity gc_cordic_tb is
end gc_cordic_tb;
architecture tb of gc_cordic_tb is
constant c_CLK_PERIOD : time := 8 ns;
constant c_T_MAX : time := 10 ms;
signal s_clk,s_rst,s_sim_end : std_logic := '0';
constant c_ACCEPTED_ERROR : integer := 450;
constant c_WIDTH : integer := 14;
constant c_ITERATIONS : integer := 14;
signal s_done, s_done_shifted : std_logic := '0';
signal s_cor_mode : t_CORDIC_MODE;
signal s_cor_submode : t_CORDIC_SUBMODE;
type t_CORDIC_INT is record
x : integer;
y : integer;
z : integer;
mode : t_CORDIC_MODE;
submode : t_CORDIC_SUBMODE;
valid : std_logic;
end record;
type t_CORDIC_STV is record
x : std_logic_vector;
y : std_logic_vector;
z : std_logic_vector;
mode : t_CORDIC_MODE;
submode : t_CORDIC_SUBMODE;
valid : std_logic;
end record;
function f_stv2int(inp : t_CORDIC_STV) return t_CORDIC_INT is
variable v_ret : t_CORDIC_INT;
begin
v_ret.x := to_integer(signed(inp.x));
v_ret.y := to_integer(signed(inp.y));
v_ret.z := to_integer(signed(inp.z));
v_ret.mode := inp.mode;
v_ret.submode := inp.submode;
v_ret.valid := inp.valid;
return v_ret;
end function f_stv2int;
function f_int2stv(inp : t_CORDIC_INT; nbits : integer) return t_CORDIC_STV is
variable v_ret : t_CORDIC_STV(x(nbits-1 downto 0), y(nbits-1 downto 0), z(nbits-1 downto 0));
begin
if inp.x > 2**(nbits-1)-1 or inp.y > 2**(nbits-1)-1 or inp.z > 2**(nbits-1)-1 then
report "ovf " & integer'image(inp.x) & " " & integer'image(inp.y)& " " & integer'image(inp.z);
elsif inp.x < -2**(nbits-1) or inp.y < -2**(nbits-1) or inp.z < -2**(nbits-1) then
report "ovf " & integer'image(inp.x) & " " & integer'image(inp.y)& " " & integer'image(inp.z);
end if;
v_ret.x := std_logic_vector(to_signed(inp.x, nbits));
v_ret.y := std_logic_vector(to_signed(inp.y, nbits));
v_ret.z := std_logic_vector(to_signed(inp.z, nbits));
v_ret.mode := inp.mode;
v_ret.submode := inp.submode;
v_ret.valid := inp.valid;
return v_ret;
end function f_int2stv;
function f_check_error(res, target, err: integer; overflow_ok : boolean; nbits : integer) return boolean is
constant c_MAX : integer := 2**(nbits-1)-1;
constant c_MIN : integer := -2**(nbits-1);
variable v_int : integer;
begin
if overflow_ok then
v_int := res-target;
if v_int > c_MAX then
v_int := v_int + 2*c_MIN;
elsif v_int < c_MIN then
v_int := v_int + 2*c_MAX;
end if;
if v_int < err then
return true;
else
return false;
end if;
else
if res > target - err and res < target + err then
return true;
else
return false;
end if;
end if;
end function f_check_error;
procedure f_check_result(i, o : t_CORDIC_INT;
max_error: integer;
nbits : integer;
exp_o : out t_CORDIC_INT;
matched : out boolean) is
variable v_expected_x, v_expected_y, v_expected_z : integer;
constant c_SCALING : real := 2.0**(nbits-1)-1.0;
constant c_K : real := real(to_integer(signed(f_compute_an(nbits))))/c_SCALING;
constant c_K_p : integer := integer(c_SCALING * 0.8281593609602);
variable v_res : boolean;
begin
v_res := true;
if i.mode = c_MODE_ROTATE then
if i.submode = c_SUBMODE_CIRCULAR then
v_expected_x := integer(1.0/c_K*(real(i.x)*cos(real(i.z)/c_SCALING*MATH_PI) - real(i.y)*sin(real(i.z)/c_SCALING*MATH_PI)));
v_expected_y := integer(1.0/c_K*(real(i.y)*cos(real(i.z)/c_SCALING*MATH_PI) + real(i.x)*sin(real(i.z)/c_SCALING*MATH_PI)));
v_expected_z := 0;
if not (f_check_error(o.z, v_expected_z, max_error, false, nbits)
and f_check_error(o.y, v_expected_y, max_error, false, nbits)
and f_check_error(o.x, v_expected_x, max_error, false, nbits)) then
report "Rotate/Circular : o.x = K*(x*cos(z) - y*sin(z)), o.y = K*(y*cos(z)+x*sin(z)) | " &
"in["&integer'image(i.x)&" "&integer'image(i.y)&" "&integer'image(i.z)&"] -> " &
"out["&integer'image(o.x)&" "&integer'image(o.y)&" "&integer'image(o.z)&"] /= " &
"exp["&integer'image(v_expected_x) &", "&integer'image(v_expected_y)&", "&integer'image(v_expected_z)&"]"
severity error;
v_res := false;
end if;
elsif i.submode = c_SUBMODE_LINEAR then
v_expected_x := i.x;
v_expected_y := integer(real(real(i.y)/c_SCALING + real(i.x * i.z)/(c_SCALING*c_SCALING))*c_SCALING);
v_expected_z := 0;
if not (f_check_error(o.z, v_expected_z, max_error, false, nbits)
and f_check_error(o.y, v_expected_y, max_error, false, nbits)
and f_check_error(o.x, v_expected_x, max_error, false, nbits)) then
report "Rotate/Linear : o.x = x, o.y = y + x*z, o.z = 0 | " &
"in["&integer'image(i.x)&" "&integer'image(i.y)&" "&integer'image(i.z)&"] -> " &
"out["&integer'image(o.x)&" "&integer'image(o.y)&" "&integer'image(o.z)&"] /= " &
"exp["&integer'image(v_expected_x) &", "&integer'image(v_expected_y)&", "&integer'image(v_expected_z)&"]"
severity error;
v_res := false;
end if;
elsif i.submode = c_SUBMODE_HYPERBOLIC then
v_expected_x := c_K_p * (i.x * integer(c_SCALING*cosh(real(i.z))) - i.y * integer(c_SCALING*sinh(real(i.z))));
assert f_check_error(o.x, v_expected_x, max_error, false, nbits)
report "Error for o.x on rotate/hyperbolic : expected " & integer'image(v_expected_x) & ", got "& integer'image(o.x)&"."
severity error;
v_expected_y := c_K_p * (i.y * integer(c_SCALING*cosh(real(i.z))) + i.x * integer(c_SCALING*sinh(real(i.z))));
assert f_check_error(o.y, v_expected_y, max_error, false, nbits)
report "Error for o.y on rotate/hyperbolic : expected " & integer'image(v_expected_y) & ", got "& integer'image(o.y)&"."
severity error;
v_expected_z := 0;
assert f_check_error(o.z, v_expected_z, max_error, false, nbits)
report "Error for o.z on rotate/hyperbolic : expected " & integer'image(v_expected_z) & ", got "& integer'image(o.z)&"."
severity error;
else
report "Non defined submode" severity error;
end if;
elsif i.mode = c_MODE_VECTOR then
if i.submode = c_SUBMODE_CIRCULAR then
v_expected_x := integer(1.0/c_K*sqrt(real(i.x)*real(i.x) + real(i.y)*real(i.y)));
v_expected_y := 0;
if i.x = 0 then
if i.x*i.y >= 0 then
v_expected_z := i.z - integer(0.5*c_SCALING); -- 0.5 * c_SCALING = 90°
else
v_expected_z := i.z + integer(0.5*c_SCALING);
end if;
else
-- atan [-pi/2, pi/2] -> [-0.5, 0.5]*c_SCALING
v_expected_z := i.z + integer(arctan(real(i.y)/real(i.x))*c_SCALING/MATH_PI);
end if;
if i.x < 0 then
v_expected_z := v_expected_z - integer(c_SCALING);
end if;
if v_expected_z > integer(c_SCALING) then
v_expected_z := v_expected_z - integer(2.0* c_SCALING);
end if;
if v_expected_z < -integer(c_SCALING) then
v_expected_z := v_expected_z + integer(2.0* c_SCALING);
end if;
if v_expected_z > integer(c_SCALING) then
v_expected_z := v_expected_z - integer(2.0* c_SCALING);
end if;
if v_expected_z < -integer(c_SCALING) then
v_expected_z := v_expected_z + integer(2.0* c_SCALING);
end if;
if not (f_check_error(o.z, v_expected_z, max_error, true, nbits)
and f_check_error(o.y, v_expected_y, max_error, false, nbits)
and f_check_error(o.x, v_expected_x, max_error, false, nbits)) then
report "Vector/Circular : o.x = K*sqrt(x^2+y^2), o.y = 0, o.z = z + atan(y/x) | " &
"in["&integer'image(i.x)&" "&integer'image(i.y)&" "&integer'image(i.z)&"] -> " &
"out["&integer'image(o.x)&" "&integer'image(o.y)&" "&integer'image(o.z)&"] /= " &
"exp["&integer'image(v_expected_x) &", "&integer'image(v_expected_y)&", "&integer'image(v_expected_z)&"]"
severity error;
v_res := false;
end if;
elsif i.submode = c_SUBMODE_LINEAR then
v_expected_x := i.x;
v_expected_y := 0;
v_expected_z := integer((real(i.z) +real(i.y) / real(i.x)*c_SCALING));
if not (f_check_error(o.z, v_expected_z, max_error, false, nbits)
and f_check_error(o.y, v_expected_y, max_error, true, nbits)
and f_check_error(o.x, v_expected_x, max_error, false, nbits)) then
report "Vector/Linear : o.x = x, o.y = 0, o.z = z + y/x | " &
"in["&integer'image(i.x)&" "&integer'image(i.y)&" "&integer'image(i.z)&"] -> " &
"out["&integer'image(o.x)&" "&integer'image(o.y)&" "&integer'image(o.z)&"] /= " &
"exp["&integer'image(v_expected_x) &", "&integer'image(v_expected_y)&", "&integer'image(v_expected_z)&"]"
severity error;
v_res := false;
end if;
elsif i.submode = c_SUBMODE_HYPERBOLIC then
v_expected_x := integer(1.0/c_K * sqrt(real(i.x)*real(i.x) - real(i.y)*real(i.y))*c_SCALING);
assert f_check_error(o.x, v_expected_x, max_error, false, nbits)
report "Error for o.x on vector/hyperbolic : expected " & integer'image(v_expected_x) & ", got "& integer'image(o.x)&"."
severity error;
v_expected_y := 0;
assert f_check_error(o.y, v_expected_y, max_error, false, nbits)
report "Error for o.y on vector/hyperbolic : expected " & integer'image(v_expected_y) & ", got "& integer'image(o.y)&"."
severity error;
v_expected_z := i.z + integer(c_SCALING * arctanh(real(i.y) / real(i.x)));
assert f_check_error(o.z, v_expected_z, max_error, false, nbits)
report "Error for o.z on vector/hyperbolic : expected " & integer'image(v_expected_z) & ", got "& integer'image(o.z)&"."
severity error;
else
report "Non defined submode" severity error;
end if;
end if;
exp_o := o;
exp_o.x := v_expected_x;
exp_o.y := v_expected_y;
exp_o.z := v_expected_z;
matched := v_res;
end procedure f_check_result;
constant c_AN : integer := to_integer(signed(f_compute_an(c_WIDTH)));
constant c_CORDIC_INT_DEF : t_CORDIC_INT := (x=>0, y=>0, z=>0, mode=>c_MODE_ROTATE, submode=>c_SUBMODE_CIRCULAR, valid => '0');
signal s_stim, s_res : t_CORDIC_STV(x(c_WIDTH-1 downto 0), y(c_WIDTH-1 downto 0), z(c_WIDTH-1 downto 0));
signal s_in, s_in_shifted, s_out : t_CORDIC_INT;
type t_TEST_STIM is array(natural range <>) of t_CORDIC_INT;
signal s_stim_array, s_res_array : t_TEST_STIM(0 to 15) := (
-- rot / circ = mag/angle -> cos/sin
(x=>-c_AN, y=>0, z=>0, mode=>c_MODE_ROTATE, submode=>c_SUBMODE_CIRCULAR, valid => '0'),
(x=>c_AN, y=>0, z=>4095, mode=>c_MODE_ROTATE, submode=>c_SUBMODE_CIRCULAR, valid => '0'),
(x=>c_AN, y=>0, z=>8191, mode=>c_MODE_ROTATE, submode=>c_SUBMODE_CIRCULAR, valid => '0'),
(x=>c_AN, y=>0, z=>-4095, mode=>c_MODE_ROTATE, submode=>c_SUBMODE_CIRCULAR, valid => '0'),
-- vect / circ = cos/sin -> mag/angle
(x=>c_AN, y=>0, z=>0, mode=>c_MODE_VECTOR, submode=>c_SUBMODE_CIRCULAR, valid => '0'),
(x=>0, y=>c_AN, z=>0, mode=>c_MODE_VECTOR, submode=>c_SUBMODE_CIRCULAR, valid => '0'),
(x=>-c_AN, y=>0, z=>0, mode=>c_MODE_VECTOR, submode=>c_SUBMODE_CIRCULAR, valid => '0'),
(x=>0, y=>-c_AN, z=>0, mode=>c_MODE_VECTOR, submode=>c_SUBMODE_CIRCULAR, valid => '0'),
---- rot / lin = x=x, y=y+x*z
(x=>10, y=>0, z=>-100, mode=>c_MODE_ROTATE, submode=>c_SUBMODE_LINEAR, valid => '0'),
(x=>100, y=>0, z=>-10, mode=>c_MODE_ROTATE, submode=>c_SUBMODE_LINEAR, valid => '0'),
(x=>1000, y=>0, z=>5, mode=>c_MODE_ROTATE, submode=>c_SUBMODE_LINEAR, valid => '0'),
(x=>-100, y=>0, z=>-5, mode=>c_MODE_ROTATE, submode=>c_SUBMODE_LINEAR, valid => '0'),
---- vect / lin = x=x, z=z+y/x
(x=>-8192, y=>8191, z=>0, mode=>c_MODE_VECTOR, submode=>c_SUBMODE_LINEAR, valid => '0'),
(x=>8191, y=>-8190, z=>0, mode=>c_MODE_VECTOR, submode=>c_SUBMODE_LINEAR, valid => '0'),
(x=>8191, y=>0, z=>0, mode=>c_MODE_VECTOR, submode=>c_SUBMODE_LINEAR, valid => '0'),
(x=>8191, y=>4000, z=>4095, mode=>c_MODE_VECTOR, submode=>c_SUBMODE_LINEAR, valid => '0')
);
begin
s_stim <= f_int2stv(s_in, c_WIDTH);
s_out <= f_stv2int(s_res);
s_clk_proc : process is
begin
loop
s_clk <= '0';
wait for c_CLK_PERIOD/2;
s_clk <= '1';
wait for c_CLK_PERIOD/2;
if s_sim_end = '1' then
wait;
end if;
if now > c_T_MAX then
report "Max simulation time overlapped" severity error;
wait;
end if;
end loop;
end process s_clk_proc;
p_main_stim : process is
variable v_res : boolean;
begin
s_rst <= '1';
wait for 5*c_CLK_PERIOD;
wait until rising_edge(s_clk);
s_rst <= '0';
wait until rising_edge(s_clk);
wait until s_done = '1';
wait for (c_ITERATIONS+10)* c_CLK_PERIOD;
s_sim_end <= '1';
report "Simulation got to the end of main_stim process" severity note;
wait;
end process p_main_stim;
p_stim_srg : process
variable seed1, seed2 : integer := 999;
variable v_rand : real;
variable v_mag, v_angle, v_rotate_angle : real;
variable v_x, v_y, v_z : real;
constant c_K : real := 1.646760258121;
constant c_N_TESTS : integer := 10000;
constant c_RUN_SINGLE : boolean := false;
begin
s_in <= c_CORDIC_INT_DEF;
s_done <= '0';
wait until falling_edge(s_rst);
wait until rising_edge(s_clk);
wait until rising_edge(s_clk);
if c_RUN_SINGLE then
wait until rising_edge(s_clk);
s_in.x <= -3150;
s_in.y <= -3148;
s_in.z <= 35;
s_in.mode <= c_MODE_VECTOR;
s_in.submode <= c_SUBMODE_LINEAR;
s_in.valid <= '1';
wait until rising_edge(s_clk);
s_in.valid <= '0';
wait until rising_edge(s_clk);
else
report "Testing some edgecases";
for i in 0 to s_stim_array'length-1 loop
wait until rising_edge(s_clk);
s_in <= s_stim_array(i);
end loop;
report "Testing rotate/circular";
for i in 0 to c_N_TESTS-1 loop
uniform(seed1, seed2, v_rand);
v_mag := v_rand/c_K;
uniform(seed1, seed2, v_rand);
v_angle := (v_rand*2.0-1.0)*MATH_PI;
uniform(seed1, seed2, v_rand);
v_rotate_angle := (v_rand*2.0-1.0);
-- x,y,z computed as real numbers
v_x := v_mag*cos(v_angle);
v_y := v_mag*sin(v_angle);
v_z := v_rotate_angle;
wait until rising_edge(s_clk);
s_in.mode <= c_MODE_ROTATE;
s_in.submode <= c_SUBMODE_CIRCULAR;
s_in.x <= integer(v_x*2.0**(c_WIDTH-1)-1.0);
s_in.y <= integer(v_y*2.0**(c_WIDTH-1)-1.0);
s_in.z <= integer(v_z*2.0**(c_WIDTH-1)-1.0);
end loop;
report "Testing rotate/linear";
for i in 0 to c_N_TESTS-1 loop
-- x,y,z computed as real numbers
uniform(seed1, seed2, v_rand);
v_x := (v_rand*2.0-1.0);
uniform(seed1, seed2, v_rand);
v_z := (v_rand*2.0-1.0);
uniform(seed1, seed2, v_rand);
--v_y := (v_rand*2.0-1.0)*(1.0-abs(v_x*v_z));
v_y := 0.0;
wait until rising_edge(s_clk);
s_in.mode <= c_MODE_ROTATE;
s_in.submode <= c_SUBMODE_LINEAR;
s_in.x <= integer(v_x*2.0**(c_WIDTH-1)-1.0);
s_in.y <= integer(v_y*2.0**(c_WIDTH-1)-1.0);
s_in.z <= integer(v_z*2.0**(c_WIDTH-1)-1.0);
end loop;
report "Testing vector/circular";
for i in 0 to c_N_TESTS-1 loop
uniform(seed1, seed2, v_rand);
v_mag := v_rand/c_K;
uniform(seed1, seed2, v_rand);
v_angle := (v_rand*2.0-1.0)*MATH_PI;
uniform(seed1, seed2, v_rand);
v_rotate_angle := (v_rand*2.0-1.0);
-- x,y,z computed as real numbers
v_x := v_mag*cos(v_angle);
v_y := v_mag*sin(v_angle);
v_z := v_rotate_angle;
wait until rising_edge(s_clk);
s_in.mode <= c_MODE_VECTOR;
s_in.submode <= c_SUBMODE_CIRCULAR;
s_in.x <= integer(v_x*2.0**(c_WIDTH-1)-1.0);
s_in.y <= integer(v_y*2.0**(c_WIDTH-1)-1.0);
s_in.z <= integer(v_z*2.0**(c_WIDTH-1)-1.0);
end loop;
report "Testing vector/linear";
for i in 0 to c_N_TESTS-1 loop
-- x,y,z computed as real numbers
uniform(seed1, seed2, v_rand);
v_x := (v_rand*2.0-1.0);
uniform(seed1, seed2, v_rand);
v_y := (v_rand*2.0-1.0)*v_x;
uniform(seed1, seed2, v_rand);
v_z := (v_rand*2.0-1.0)*(1.0-abs(v_y/v_x));
wait until rising_edge(s_clk);
s_in.mode <= c_MODE_VECTOR;
s_in.submode <= c_SUBMODE_LINEAR;
s_in.x <= integer(v_x*2.0**(c_WIDTH-1)-1.0);
s_in.y <= integer(v_y*2.0**(c_WIDTH-1)-1.0);
s_in.z <= integer(v_z*2.0**(c_WIDTH-1)-1.0);
end loop;
end if;
s_done <= '1';
wait;
end process p_stim_srg;
s_in_shifted <= transport s_in after (c_ITERATIONS+1) * c_CLK_PERIOD;
s_done_shifted <= transport s_done after (c_ITERATIONS+1) * c_CLK_PERIOD;
p_res_readback : process
variable v_res : boolean;
variable v_n_err : integer := 0;
variable v_rotate_circular : integer := 0;
variable v_rotate_linear : integer := 0;
variable v_vector_circular : integer := 0;
variable v_vector_linear : integer := 0;
variable v_exp_out : t_CORDIC_INT;
file test_vector : text open write_mode is "res.txt";
variable row : line;
begin
wait until falling_edge(s_rst);
wait for (c_ITERATIONS+4)*c_CLK_PERIOD;
while s_done_shifted = '0' loop
wait until rising_edge(s_clk);
f_check_result(s_in_shifted, s_out, c_ACCEPTED_ERROR, c_WIDTH, v_exp_out,v_res );
if not v_res then
v_n_err := v_n_err + 1;
if s_out.mode = c_MODE_ROTATE then
if s_out.submode = c_SUBMODE_CIRCULAR then
v_rotate_circular := v_rotate_circular+1;
elsif s_out.submode = c_SUBMODE_LINEAR then
v_rotate_linear := v_rotate_linear+1;
end if;
elsif s_out.mode = c_MODE_VECTOR then
if s_out.submode = c_SUBMODE_CIRCULAR then
v_vector_circular := v_vector_circular+1;
elsif s_out.submode = c_SUBMODE_LINEAR then
v_vector_linear := v_vector_linear+1;
end if;
end if;
end if;
write(row, integer'image(s_in_shifted.x) & "," & integer'image(s_in_shifted.y) & "," & integer'image(s_in_shifted.z) & "," &
integer'image(s_out.x) & "," & integer'image(s_out.y) & "," & integer'image(s_out.z) & "," &
integer'image(v_exp_out.x) & "," & integer'image(v_exp_out.y) & "," & integer'image(v_exp_out.z)
& "," & to_hstring(s_in_shifted.mode) & "," & to_hstring(s_in_shifted.submode));
writeline(test_vector, row);
end loop;
report "Total errors : " & integer'image(v_n_err);
report "Total rotate/circular errors : " & integer'image(v_rotate_circular);
report "Total rotate/linear errors : " & integer'image(v_rotate_linear);
report "Total vector/circular errors : " & integer'image(v_vector_circular);
report "Total vector/linear errors : " & integer'image(v_vector_linear);
wait;
end process p_res_readback;
cmp_dut : entity work.gc_cordic_top
generic map
(
g_ITERATIONS => c_ITERATIONS,
g_WIDTH => c_WIDTH
)
port map
(
clk_i => s_clk,
rst_i => s_rst,
mode_i => s_stim.mode,
submode_i => s_stim.submode,
x_i => s_stim.x,
y_i => s_stim.y,
z_i => s_stim.z,
valid_i => s_stim.valid,
x_o => s_res.x,
y_o => s_res.y,
z_o => s_res.z,
lim_x_o => open,
lim_y_o => open,
mode_o => s_res.mode,
submode_o => s_res.submode
);
--cmp_dut : entity work.gc_cordic
--generic map
--(
-- g_N => c_ITERATIONS,
-- g_M => c_WIDTH
--)
--port map
--(
-- clk_i => s_clk,
-- rst_i => s_rst,
-- lim_x_i => '0',
-- lim_y_i => '0',
-- cor_mode_i => s_stim.mode,
-- cor_submode_i => s_stim.submode,
-- x0_i => s_stim.x,
-- y0_i => s_stim.y,
-- z0_i => s_stim.z,
-- xn_o => s_res.x,
-- yn_o => s_res.y,
-- zn_o => s_res.z,
-- lim_x_o => open,
-- lim_y_o => open
--);
end tb;
\ No newline at end of file
`include "sim_logger.svh"
`timescale 1ns/1ps
import gc_cordic_pkg::*;
const bit[0:0] MODE_VECTOR =1'b0;
const bit[0:0] MODE_ROTATE =1'b1;
const bit[1:0] SUBMODE_CIRCULAR = 2'b00;
const bit[1:0] SUBMODE_LINEAR = 2'b01;
const bit[1:0] SUBMODE_HYPERBOLIC = 2'b11;
const real M_PI = 3.14159265358;
const real AN = 1.6467602581210656483661780066297;
module main;
reg rst_n = 0;
reg clk= 0;
parameter time g_clk_period = 10.0ns;
always #(g_clk_period/2) clk <= ~clk;
initial #200ns rst_n <= 1;
logic signed [15:0] x0=0, y0=0, z0=0;
wire signed [15:0] xn, yn, zn;
// ROTATE/CIRCULAR -> mag/phase -> sin/cos
// VECTOR/CIRCULAR -> sin/soc -> mag/phase
logic [0:0] cor_mode = MODE_ROTATE;
logic [1:0] cor_submode = SUBMODE_CIRCULAR;
const int c_PHASE_BITS = 16;
const int c_PIPELINE_DELAY = 17;
typedef struct {
real phase;
real mag;
logic signed [15:0] x, y, z;
} cordic_data_t;
cordic_data_t cor_in, cor_out;
gc_cordic #(
.g_N(16),
.g_M(16),
.g_ANGLE_FORMAT(1)
)
DUT
(
.clk_i(clk),
.rst_i(~rst_n),
.cor_mode_i ( cor_mode ),
.cor_submode_i ( cor_submode ),
.lim_x_i(1'b0),
.lim_y_i(1'b0),
.x0_i(cor_in.x),
.y0_i(cor_in.y),
.z0_i(cor_in.z),
.xn_o(cor_out.x),
.yn_o(cor_out.y),
.zn_o(cor_out.z),
.lim_x_o(),
.lim_y_o(),
.rst_o()
);
`ifdef disabled
CoRDICPipeHD
#(
.N(16),
.M(16)
// .AngleMode(1'b1)
)
DUT2
(
.Clk(clk),
.RstO(),
.Rst(~rst_n),
.LimXin(1'b0),
.LimX(),
.LimY(),
.X0(cor_in.x),
.Y0(cor_in.y),
.Z0(cor_in.z),
// .Xn(cor_out.x),
// .Yn(cor_out.y),
// .Zn(cor_out.z),
// .CorMode : in CoRDiCMode;
.LimYin(1'b0)
);
`endif // `ifdef disabled
function int abs(int x);
if(x<0)
x=-x;
return x;
endfunction // abs
task automatic run_cordic_testcase( cordic_data_t in [$], cordic_data_t exp_out[$], int latency, int max_error, bit check_x, bit check_y, bit check_z, output int err_count );
automatic Logger l = Logger::get();
automatic int j;
cordic_data_t out[$];
fork
begin : din
foreach( in[i] )
begin
cor_in <= in[i];
@(posedge clk);
end
end
begin : dout
repeat(latency) @(posedge clk);
for(j=0; j < in.size(); j++)
begin
@(posedge clk);
out.push_back(cor_out);
end
end
join
for(j=0;j<in.size();j++)
begin
cordic_data_t e = exp_out[j];
cordic_data_t o = out[j];
cordic_data_t err = e;
err.x = abs(e.x-o.x);
err.y = abs(e.y-o.y);
err.z = abs(e.z-o.z);
if(check_x && err.x > max_error)
begin
l.msg(1, $sformatf( "Sample %d: X expected = %d, actual = %d", j, e.x, o.x) );
err_count++;
end
if(check_y && err.y > max_error)
begin
l.msg(1, $sformatf( "Sample %f: Y expected = %d, actual = %d", j, e.y, o.y) );
err_count++;
end
if(check_z && err.z > max_error)
begin
l.msg(1, $sformatf( "Sample %d: Z expected = %d, actual = %d", j, e.z, o.z) );
err_count++;
end
end
endtask // run_cordic_testcase
function int phase2fix( real phase );
int rv;
while( phase > M_PI )
phase -= 2.0*M_PI;
while (phase < -M_PI )
phase += 2.0*M_PI;
rv= int' ( real'((1 << (c_PHASE_BITS-1) ) - 1) * phase / M_PI );
// $display("ph %f %d\n", phase, rv);
return rv;
endfunction // phase2fix
function real rand_real(real a, real b);
return a + (b-a)*(real'($urandom())/32'hffffffff);
endfunction // rand_real
task automatic run_testcase_sincos( int nsamples );
automatic Logger l = Logger::get();
cordic_data_t in[$], expected[$], tmp, result;
int i, err_cnt=0;
l.startTest("Cordic Angle/Mag -> Sin/Cos");
cor_mode = MODE_ROTATE;
cor_submode = SUBMODE_CIRCULAR;
for(i=0; i < nsamples; i++)
begin
tmp.mag = $random()%15000;
tmp.phase = rand_real(-M_PI, M_PI); // -M_PI + (2*M_PI*real'(i)/real'(nsamples) );//rand_real(-M_PI, M_PI);
in.push_back(tmp);
end
foreach (in[i])
begin
real mag = in[i].mag * AN;
in[i].x = int'(in[i].mag);
in[i].y = 0;
in[i].z = phase2fix( in[i].phase );
result.x = int'( mag * $cos( in[i].phase ) );
result.y = int'( mag * $sin( in[i].phase ) );
result.z = 0;
expected.push_back(result);
end
run_cordic_testcase( in, expected, c_PIPELINE_DELAY, 20, 1, 1, 0, err_cnt );
l.msg(0, $sformatf( "Mag/Phase->Sin/Cos: %d errors", err_cnt) );
if( err_cnt )
l.fail("Cordic/s sin/cos value mismatch with model values");
else
l.pass();
endtask // run_testcase_sincos
task automatic run_testcase_angle_mag( int nsamples );
automatic Logger l = Logger::get();
cordic_data_t in[$], expected[$], tmp, result;
int i, err_cnt=0;
l.startTest("Cordic Sin/Cos -> Angle/Mag");
cor_mode = MODE_VECTOR;
cor_submode = SUBMODE_CIRCULAR;
for(i=0; i < nsamples; i++)
begin
tmp.mag = 10000+ ( $urandom()%5000 );
tmp.phase = rand_real(-M_PI, M_PI);
tmp.x = int'( tmp.mag * $cos( tmp.phase ) );
tmp.y = int'( tmp.mag * $sin( tmp.phase ) );
tmp.z = 0;
in.push_back(tmp);
result.x = int'( real'(tmp.mag) * AN );
result.z = phase2fix(tmp.phase);
expected.push_back(result);
end
run_cordic_testcase( in, expected, c_PIPELINE_DELAY, 20, 1, 0, 1, err_cnt );
l.msg(0, $sformatf( "Sin/Cos->Mag/Phase: %d errors", err_cnt) );
if( err_cnt )
l.fail("Cordic/s mag/phase value mismatch with model values");
else
l.pass();
endtask
task setup();
while(!rst_n) @(posedge clk);
@(posedge clk);
endtask
initial begin
automatic Logger l = Logger::get();
setup();
run_testcase_sincos( 10000 );
run_testcase_angle_mag( 10000 );
l.writeTestReport(1);
$stop;
end
endmodule
vsim work.main -voptargs="+acc"
do wave.do
run 30ms
wave zoomfull
radix -hex
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
action = "simulation"
sim_tool = "modelsim"
vcom_opt = "-mixedsvvh l"
target = "xilinx"
syn_device = "xc6slx45t"
top_module = "main" # for hdlmake2
sim_top = "main" # for hdlmake3
include_dirs = [
"../../../sim/"
]
modules = {
"local" : [
"../../../",
],
}
files = [
"main.sv",
]
`timescale 1ns/1ps
import gc_dsp_pkg::*;
const real M_PI = 3.14159265358;
const real AN = 1.6467602581210656483661780066297;
typedef struct {
int value;
bit valid;
} opt_int_t;
class FIRFilterModel;
protected int m_coefs[$];
protected int m_delay[];
protected int m_shift;
protected int m_order;
protected int m_samples;
function new( int order, int coefs[$], int shift );
m_coefs = coefs;
m_delay = new[order];
m_shift = shift;
m_samples = 0;
m_order = order;
endfunction // new
function automatic opt_int_t filter(int x);
int i;
bit signed [63:0] acc = 0;
opt_int_t rv;
// $display("Filter %d", x);
for(i=m_order-2;i>=0;i--)
m_delay[i+1] = m_delay[i];
m_delay[0] = x;
for(i=0;i<m_order;i++)
begin
acc+=m_delay[i]*m_coefs[i];
// $display("d %d c %d a %d", m_delay[i], m_coefs[i], acc);
end
acc += (1 << ( m_shift-1 ));
acc >>= m_shift;
// $display("a %x", acc);
m_samples++;
rv.value = acc;
rv.valid = 0;
if( m_samples >= m_order )
rv.valid = 1;
return rv;
endfunction // filter
endclass // FirFilterModel
module main;
reg rst_n = 0;
reg clk= 0;
parameter time g_clk_period = 10.0ns;
always #(g_clk_period/2) clk <= ~clk;
initial #200ns rst_n <= 1;
localparam c_SYMMETRIC = 1'b1;
localparam c_ORDER = 16;
localparam c_COEF_BITS = 16;
localparam c_OUTPUT_BITS = 16;
localparam c_OUTPUT_SHIFT = 16;
localparam c_DATA_BITS = 16;
localparam c_SUM_PIPE_STAGES = 3;
typedef logic signed [31:0] coefs_t[127:0];
coefs_t coefs;
function automatic coefs_t gen_some_coefs(int order, int bits, int symmetric);
coefs_t r;
int i, n = order;
if(symmetric)
n = (order + 1) / 2;
for(i=0;i<n;i++)
begin
int c = $random() % ( 1<<(bits-1) );
r[i] = c;
if( symmetric )
r[order-1-i] = c;
end
return r;
endfunction // gen_some_coefs
const int c_PIPELINE_DELAY = 17;
typedef struct {
logic valid;
logic signed [c_DATA_BITS-1:0] data;
} fir_data_t;
fir_data_t fir_in;
wire fir_data_t fir_out;
gc_pipelined_fir_filter
#(
.g_COEF_BITS (c_COEF_BITS),
.g_DATA_BITS (c_DATA_BITS),
.g_OUTPUT_BITS (c_OUTPUT_BITS),
.g_OUTPUT_SHIFT (c_OUTPUT_SHIFT),
.g_SUM_PIPE_STAGES (c_SUM_PIPE_STAGES),
.g_SYMMETRIC (c_SYMMETRIC),
.g_ORDER (c_ORDER)
)
DUT
(
.clk_i(clk),
.rst_i(~rst_n),
.coefs_i(coefs),
.d_i(fir_in.data),
.d_valid_i(fir_in.valid),
.d_o(fir_out.data),
.d_valid_o(fir_out.valid)
);
function int abs(int x);
if(x<0)
x=-x;
return x;
endfunction // abs
task automatic run_filter_test( fir_data_t in [$], fir_data_t exp_out[$], int latency, int max_error, output int err_count );
automatic int j;
fir_data_t out[$];
fork
begin : din
foreach( in[i] )
begin
fir_in <= in[i];
@(posedge clk);
end
end
begin : dout
for(j=0; j < in.size(); j++)
begin
@(posedge clk);
if( fir_out.valid )
begin
out.push_back(fir_out);
end
end
end
join
for(j=0;j<in.size();j++)
begin
fir_data_t e = exp_out[j];
fir_data_t o = out[j];
if( e !=o )
begin
$error("Sample %d expected %d out %d", j, e.data, o.data);
err_count++;
end
end
endtask // run_filter_test
task automatic run_test( int nsamples );
fir_data_t in[$], expected[$], tmp, result;
int i, err_cnt=0;
int my_coefs[$];
FIRFilterModel model;
for(i = 0; i < c_ORDER; i++)
my_coefs.push_back(coefs[i]);
model = new ( c_ORDER, my_coefs, c_OUTPUT_SHIFT );
for(i=0; i < nsamples; i++)
begin
tmp.data = $random()%32000;
tmp.valid = 1;
in.push_back(tmp);
end
foreach (in[i])
begin
opt_int_t m = model.filter( in[i].data );
if( m.valid )
begin
fir_data_t d;
d.data = m.value;
// $display("d %d", m.value);
expected.push_back(d);
end
end
run_filter_test( in, expected, 20, 0, err_cnt );
$display("Test (order = %d, samples = %d): %d errors", c_ORDER, nsamples, err_cnt);
endtask // run_testcase_sincos
initial begin
coefs = gen_some_coefs(c_ORDER, c_DATA_BITS, c_SYMMETRIC);
fir_in.valid = 0;
while(!rst_n) @(posedge clk);
@(posedge clk);
run_test( 50000 );
$stop;
end
endmodule
vsim work.main -voptargs="+acc"
do wave.do
run 30ms
wave zoomfull
radix -hex
\ No newline at end of file
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -radix hexadecimal /main/DUT/clk_i
add wave -noupdate -radix hexadecimal /main/DUT/rst_i
add wave -noupdate -radix hexadecimal /main/DUT/coefs_i
add wave -noupdate -radix hexadecimal /main/DUT/d_i
add wave -noupdate -radix hexadecimal /main/DUT/d_valid_i
add wave -noupdate -radix hexadecimal /main/DUT/d_o
add wave -noupdate -radix hexadecimal /main/DUT/d_valid_o
add wave -noupdate -radix hexadecimal /main/DUT/dly_valid
add wave -noupdate -radix hexadecimal /main/DUT/dly
add wave -noupdate -radix hexadecimal /main/DUT/d_reg
add wave -noupdate -radix hexadecimal -childformat {{/main/DUT/premul(19) -radix hexadecimal} {/main/DUT/premul(18) -radix hexadecimal} {/main/DUT/premul(17) -radix hexadecimal} {/main/DUT/premul(16) -radix hexadecimal} {/main/DUT/premul(15) -radix hexadecimal} {/main/DUT/premul(14) -radix hexadecimal} {/main/DUT/premul(13) -radix hexadecimal} {/main/DUT/premul(12) -radix hexadecimal} {/main/DUT/premul(11) -radix hexadecimal} {/main/DUT/premul(10) -radix hexadecimal} {/main/DUT/premul(9) -radix hexadecimal} {/main/DUT/premul(8) -radix hexadecimal} {/main/DUT/premul(7) -radix hexadecimal} {/main/DUT/premul(6) -radix hexadecimal} {/main/DUT/premul(5) -radix hexadecimal} {/main/DUT/premul(4) -radix hexadecimal} {/main/DUT/premul(3) -radix hexadecimal} {/main/DUT/premul(2) -radix hexadecimal} {/main/DUT/premul(1) -radix hexadecimal} {/main/DUT/premul(0) -radix hexadecimal}} -subitemconfig {/main/DUT/premul(19) {-radix hexadecimal} /main/DUT/premul(18) {-radix hexadecimal} /main/DUT/premul(17) {-radix hexadecimal} /main/DUT/premul(16) {-radix hexadecimal} /main/DUT/premul(15) {-radix hexadecimal} /main/DUT/premul(14) {-radix hexadecimal} /main/DUT/premul(13) {-radix hexadecimal} /main/DUT/premul(12) {-radix hexadecimal} /main/DUT/premul(11) {-radix hexadecimal} /main/DUT/premul(10) {-radix hexadecimal} /main/DUT/premul(9) {-radix hexadecimal} /main/DUT/premul(8) {-radix hexadecimal} /main/DUT/premul(7) {-radix hexadecimal} /main/DUT/premul(6) {-radix hexadecimal} /main/DUT/premul(5) {-radix hexadecimal} /main/DUT/premul(4) {-radix hexadecimal} /main/DUT/premul(3) {-radix hexadecimal} /main/DUT/premul(2) {-radix hexadecimal} /main/DUT/premul(1) {-radix hexadecimal} /main/DUT/premul(0) {-radix hexadecimal}} /main/DUT/premul
add wave -noupdate -radix hexadecimal /main/DUT/premul_valid
add wave -noupdate -radix hexadecimal /main/DUT/premul_reg
add wave -noupdate -radix hexadecimal /main/DUT/postmul
add wave -noupdate -radix hexadecimal /main/DUT/postmul_reg
add wave -noupdate -radix hexadecimal /main/DUT/postmul_reg2
add wave -noupdate -radix hexadecimal /main/DUT/postmul_valid
add wave -noupdate -radix hexadecimal /main/DUT/acc_out_rounded
add wave -noupdate -radix hexadecimal /main/DUT/acc_out_valid
add wave -noupdate -radix hexadecimal /main/DUT/chain_sum
add wave -noupdate -radix hexadecimal /main/DUT/chain_sum_valid
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {219 ps} 0}
configure wave -namecolwidth 150
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {0 ps} {1 ns}
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: CERN-OHL-W-2.0+
action = "simulation"
sim_tool = "ghdl"
target = "xilinx"
syn_device = "xc6slx45t"
top_module = "tb_fifo"
files = [
top_module + ".vhd",
"tb_32_64.vhd", "tb_64_32.vhd", "tb_8_32.vhd", "tb_32_8_ahead.vhd",
]
modules = {
"local" : [
"../../../",
],
}
-- SPDX-FileCopyrightText: 2023 CERN (home.cern)
--
-- SPDX-License-Identifier: CERN-OHL-W-2.0+
-- Simple testbench for generic_async_fifo_mixedw
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb_32_64 is
generic (g_show_ahead : boolean);
port (start : std_logic := '1';
done : out std_logic);
end;
architecture arch of tb_32_64 is
constant g_wr_width : natural := 32;
constant g_rd_width : natural := 64;
constant g_size : natural := 4;
signal rst_n, clk_wr, clk_rd, we, rd, full, empty : std_logic;
signal d : std_logic_vector(g_wr_width -1 downto 0);
signal q : std_logic_vector(g_rd_width-1 downto 0);
signal wr_count : std_logic_vector(3 downto 0);
signal rd_count : std_logic_vector(2 downto 0);
begin
dut: entity work.generic_async_fifo_mixedw
generic map (
g_wr_width => g_wr_width,
g_rd_width => g_rd_width,
g_size => g_size,
g_show_ahead => g_show_ahead,
g_memory_implementation_hint => open
)
port map (
rst_n_a_i => rst_n,
clk_wr_i => clk_wr,
d_i => d,
we_i => we,
wr_full_o => full,
wr_count_o => wr_count,
clk_rd_i => clk_rd,
q_o => q,
rd_i => rd,
rd_empty_o => empty,
rd_count_o => rd_count
);
process
procedure pulse_w is
begin
clk_wr <= '0';
wait for 5 ns;
clk_wr <= '1';
wait for 5 ns;
end pulse_w;
procedure pulse_r is
begin
clk_rd <= '0';
wait for 1 ns;
clk_rd <= '1';
wait for 1 ns;
end pulse_r;
begin
done <= '0';
if start /= '1' then
wait until start = '1';
end if;
rst_n <= '0';
we <= '0';
rd <= '0';
pulse_w;
pulse_r;
rst_n <= '1';
for i in 1 to 2 loop
pulse_w;
pulse_r;
end loop;
assert empty = '1' report "fifo must be empty after reset";
assert full = '0' report "fifo must not be full after reset";
assert unsigned(rd_count) = 0 report "rd_count must be 0 after reset";
assert unsigned(wr_count) = 0 report "wr_count must be 0 after reset";
d <= x"01_02_03_04";
we <= '1';
pulse_w;
d <= x"05_06_07_08";
pulse_w;
assert full = '0';
we <= '0';
while empty = '1' loop
pulse_w;
pulse_r;
end loop;
rd <= '1';
if not g_show_ahead then
pulse_r;
end if;
assert q = x"05_06_07_08_01_02_03_04";
if g_show_ahead then
pulse_r;
end if;
rd <= '0';
assert empty = '1';
report "End of 32_64 testbench";
done <= '1';
wait;
end process;
end arch;
-- SPDX-FileCopyrightText: 2023 CERN (home.cern)
--
-- SPDX-License-Identifier: CERN-OHL-W-2.0+
-- Simple testbench for generic_async_fifo_mixedw
-- Using 32b wr port, 8b rd port and show-ahead.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb_32_8_ahead is
port (start : std_logic := '1';
done : out std_logic);
end;
architecture arch of tb_32_8_ahead is
constant g_wr_width : natural := 32;
constant g_rd_width : natural := 8;
constant g_size : natural := 4;
signal rst_n, clk_wr, clk_rd, we, rd, full, empty : std_logic;
signal d : std_logic_vector(g_wr_width -1 downto 0);
signal q : std_logic_vector(g_rd_width-1 downto 0);
signal wr_count : std_logic_vector(2 downto 0);
signal rd_count : std_logic_vector(4 downto 0);
begin
dut: entity work.generic_async_fifo_mixedw
generic map (
g_wr_width => g_wr_width,
g_rd_width => g_rd_width,
g_size => g_size,
g_show_ahead => True,
g_memory_implementation_hint => open
)
port map (
rst_n_a_i => rst_n,
clk_wr_i => clk_wr,
d_i => d,
we_i => we,
wr_full_o => full,
wr_count_o => wr_count,
clk_rd_i => clk_rd,
q_o => q,
rd_i => rd,
rd_empty_o => empty,
rd_count_o => rd_count
);
process
procedure pulse_w is
begin
clk_wr <= '0';
wait for 5 ns;
clk_wr <= '1';
wait for 5 ns;
end pulse_w;
procedure pulse_r is
begin
clk_rd <= '0';
wait for 1 ns;
clk_rd <= '1';
wait for 1 ns;
end pulse_r;
begin
done <= '0';
if start /= '1' then
wait until start = '1';
end if;
rst_n <= '0';
we <= '0';
rd <= '0';
pulse_w;
pulse_r;
rst_n <= '1';
for i in 1 to 2 loop
pulse_w;
pulse_r;
end loop;
assert empty = '1' report "fifo must be empty after reset";
assert full = '0' report "fifo must not be full after reset";
assert unsigned(rd_count) = 0 report "rd_count must be 0 after reset";
assert unsigned(wr_count) = 0 report "wr_count must be 0 after reset";
d <= x"04_03_02_01";
we <= '1';
pulse_w;
we <= '0';
for i in 1 to 4 loop
pulse_r;
pulse_w;
end loop;
assert empty = '0' report "fifo must not be empty after a write";
assert full = '0';
assert unsigned(rd_count) = 4 report "expect 4 bytes to be read";
assert unsigned(wr_count) = 1 report "expect 1 word written";
assert q = x"01" report "bad output";
rd <= '1';
pulse_r;
rd <= '0';
assert empty = '0';
assert unsigned(rd_count) >= 3 report "expect at least 3 bytes to be read";
assert q = x"02" report "bad output";
d <= x"08_07_06_05";
we <= '1';
pulse_w;
we <= '0';
rd <= '1';
pulse_r;
assert empty = '0';
assert unsigned(rd_count) >= 2 report "expect at least 2 bytes to be read";
assert q = x"03" report "bad output";
pulse_r;
assert empty = '0';
assert q = x"04" report "bad output";
pulse_r;
if empty = '1' then
-- Depends on propagation delays.
pulse_r;
end if;
assert empty = '0';
assert q = x"05" report "bad output";
-- Flush the fifo.
pulse_r;
assert empty = '0' and q = x"06";
pulse_r;
assert empty = '0' and q = x"07";
pulse_r;
assert empty = '0' and q = x"08";
pulse_r;
assert empty = '1' report "fifo should now be empty";
pulse_r;
assert unsigned(rd_count) = 0;
-- Propagation delay...
pulse_w;
pulse_w;
pulse_w;
assert unsigned(wr_count) = 0;
-- Fifo is empty, try to saturate it.
d <= x"84_83_82_81";
we <= '1';
pulse_w;
assert full = '0';
assert unsigned(wr_count) = 1;
d <= x"88_87_86_85";
pulse_w;
assert full = '0';
assert unsigned(wr_count) = 2;
d <= x"8c_8b_8a_89";
pulse_w;
assert full = '0';
assert unsigned(wr_count) = 3;
d <= x"90_8f_8e_8d";
pulse_w;
assert full = '1';
assert unsigned(wr_count) = 4;
report "End of 32_8_ahead testbench";
done <= '1';
wait;
end process;
end arch;
-- SPDX-FileCopyrightText: 2023 CERN (home.cern)
--
-- SPDX-License-Identifier: CERN-OHL-W-2.0+
-- Simple testbench for generic_async_fifo_mixedw
-- Using 32b wr port, 8b rd port and show-ahead.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb_64_32 is
generic (g_show_ahead : boolean);
port (start : std_logic := '1';
done : out std_logic);
end;
architecture arch of tb_64_32 is
constant g_wr_width : natural := 64;
constant g_rd_width : natural := 32;
constant g_size : natural := 4;
signal rst_n, clk_wr, clk_rd, we, rd, full, empty : std_logic;
signal d : std_logic_vector(g_wr_width -1 downto 0);
signal q : std_logic_vector(g_rd_width-1 downto 0);
signal wr_count : std_logic_vector(2 downto 0);
signal rd_count : std_logic_vector(3 downto 0);
begin
dut: entity work.generic_async_fifo_mixedw
generic map (
g_wr_width => g_wr_width,
g_rd_width => g_rd_width,
g_size => g_size,
g_show_ahead => g_show_ahead,
g_memory_implementation_hint => open
)
port map (
rst_n_a_i => rst_n,
clk_wr_i => clk_wr,
d_i => d,
we_i => we,
wr_full_o => full,
wr_count_o => wr_count,
clk_rd_i => clk_rd,
q_o => q,
rd_i => rd,
rd_empty_o => empty,
rd_count_o => rd_count
);
process
procedure pulse_w is
begin
clk_wr <= '0';
wait for 5 ns;
clk_wr <= '1';
wait for 5 ns;
end pulse_w;
procedure pulse_r is
begin
clk_rd <= '0';
wait for 1 ns;
clk_rd <= '1';
wait for 1 ns;
end pulse_r;
begin
done <= '0';
if start /= '1' then
wait until start = '1';
end if;
rst_n <= '0';
we <= '0';
rd <= '0';
pulse_w;
pulse_r;
rst_n <= '1';
for i in 1 to 2 loop
pulse_w;
pulse_r;
end loop;
assert empty = '1' report "fifo must be empty after reset";
assert full = '0' report "fifo must not be full after reset";
assert unsigned(rd_count) = 0 report "rd_count must be 0 after reset";
assert unsigned(wr_count) = 0 report "wr_count must be 0 after reset";
d <= x"28_27_26_25_24_23_22_21";
we <= '1';
pulse_w;
we <= '0';
for i in 1 to 4 loop
pulse_r;
pulse_w;
end loop;
assert empty = '0' report "fifo must not be empty after a write";
assert full = '0';
assert unsigned(rd_count) = 2 report "expect 2 words to be read";
assert unsigned(wr_count) = 1 report "expect 1 8B word written";
rd <= '1';
if not g_show_ahead then
pulse_r;
end if;
assert empty = '0';
assert unsigned(rd_count) >= 1 report "expect at least 1 word to be read";
assert q = x"24_23_22_21" report "bad output";
pulse_r;
assert q = x"28_27_26_25" report "bad output";
if g_show_ahead then
pulse_r;
end if;
assert empty = '1' report "fifo should now be empty";
rd <= '0';
report "End of 64_32 testbench";
done <= '1';
wait;
end process;
end arch;
-- SPDX-FileCopyrightText: 2023 CERN (home.cern)
--
-- SPDX-License-Identifier: CERN-OHL-W-2.0+
-- Simple testbench for generic_async_fifo_mixedw
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb_8_32 is
port (start : std_logic := '1';
done : out std_logic);
end;
architecture arch of tb_8_32 is
constant g_wr_width : natural := 8;
constant g_rd_width : natural := 32;
constant g_size : natural := 4;
signal rst_n, clk_wr, clk_rd, we, rd, full, empty : std_logic;
signal d : std_logic_vector(g_wr_width -1 downto 0);
signal q : std_logic_vector(g_rd_width-1 downto 0);
signal wr_count : std_logic_vector(4 downto 0);
signal rd_count : std_logic_vector(2 downto 0);
begin
dut: entity work.generic_async_fifo_mixedw
generic map (
g_wr_width => g_wr_width,
g_rd_width => g_rd_width,
g_size => g_size,
g_show_ahead => False,
g_memory_implementation_hint => open
)
port map (
rst_n_a_i => rst_n,
clk_wr_i => clk_wr,
d_i => d,
we_i => we,
wr_full_o => full,
wr_count_o => wr_count,
clk_rd_i => clk_rd,
q_o => q,
rd_i => rd,
rd_empty_o => empty,
rd_count_o => rd_count
);
process
procedure pulse_w is
begin
clk_wr <= '0';
wait for 5 ns;
clk_wr <= '1';
wait for 5 ns;
end pulse_w;
procedure pulse_r is
begin
clk_rd <= '0';
wait for 1 ns;
clk_rd <= '1';
wait for 1 ns;
end pulse_r;
begin
done <= '0';
if start /= '1' then
wait until start = '1';
end if;
rst_n <= '0';
we <= '0';
rd <= '0';
pulse_w;
pulse_r;
rst_n <= '1';
for i in 1 to 2 loop
pulse_w;
pulse_r;
end loop;
assert empty = '1' report "fifo must be empty after reset";
assert full = '0' report "fifo must not be full after reset";
assert unsigned(rd_count) = 0 report "rd_count must be 0 after reset";
assert unsigned(wr_count) = 0 report "wr_count must be 0 after reset";
d <= x"01";
we <= '1';
pulse_w;
d <= x"02";
pulse_w;
d <= x"03";
pulse_w;
assert full = '0';
d <= x"04";
pulse_w;
we <= '0';
while empty = '1' loop
pulse_w;
pulse_r;
end loop;
rd <= '1';
pulse_r;
rd <= '0';
assert empty = '1';
assert q = x"04_03_02_01";
report "End of 8_32 testbench";
done <= '1';
wait;
end process;
end arch;
-- SPDX-FileCopyrightText: 2023 CERN (home.cern)
--
-- SPDX-License-Identifier: CERN-OHL-W-2.0+
-- Simple testbench for generic_async_fifo_mixedw
library ieee;
use ieee.std_logic_1164.all;
entity tb_fifo is
end;
architecture arch of tb_fifo is
signal start_32_64 : std_logic := '0';
signal done_32_64 : std_logic;
signal start_8_32 : std_logic := '0';
signal done_8_32 : std_logic;
signal start_32_8_a : std_logic := '0';
signal done_32_8_a : std_logic;
signal start_32_64_a : std_logic := '0';
signal done_32_64_a : std_logic;
signal start_64_32 : std_logic := '0';
signal done_64_32 : std_logic;
signal start_64_32_a : std_logic := '0';
signal done_64_32_a : std_logic;
begin
dut_8_32: entity work.tb_8_32
port map (start_8_32, done_8_32);
dut_32_8_a: entity work.tb_32_8_ahead
port map (start_32_8_a, done_32_8_a);
dut_32_64: entity work.tb_32_64
generic map (g_show_ahead => False)
port map (start_32_64, done_32_64);
dut_32_64_a: entity work.tb_32_64
generic map (g_show_ahead => False)
port map (start_32_64_a, done_32_64_a);
dut_64_32: entity work.tb_64_32
generic map (g_show_ahead => false)
port map (start_64_32, done_64_32);
dut_64_32_a: entity work.tb_64_32
generic map (g_show_ahead => True)
port map (start_64_32_a, done_64_32_a);
process
begin
wait for 1 ns;
start_8_32 <= '1';
wait until done_8_32 = '1';
wait for 10 ns;
start_32_8_a <= '1';
wait until done_32_8_a = '1';
wait for 10 ns;
start_32_64 <= '1';
wait until done_32_64 = '1';
wait for 10 ns;
start_32_64_a <= '1';
wait until done_32_64_a = '1';
wait for 10 ns;
start_64_32 <= '1';
wait until done_64_32 = '1';
wait for 10 ns;
start_64_32_a <= '1';
wait until done_64_32_a = '1';
wait for 8 ns;
wait;
end process;
end arch;
library="osvvm"
files = [
"upstream/AlertLogPkg.vhd",
"upstream/CoveragePkg.vhd",
"upstream/MemoryGenericPkg.vhd",
"upstream/MemoryPkg.vhd",
"upstream/MemorySupportPkg.vhd",
"upstream/MessageListPkg.vhd",
"upstream/MessagePkg.vhd",
"upstream/NamePkg.vhd",
"upstream/NameStorePkg.vhd",
"upstream/OsvvmContext.vhd",
"upstream/OsvvmGlobalPkg.vhd",
"upstream/OsvvmTypesPkg.vhd",
"upstream/RandomBasePkg.vhd",
"upstream/RandomPkg.vhd",
"upstream/RandomProcedurePkg.vhd",
"upstream/ReportPkg.vhd",
"upstream/ResizePkg.vhd",
"upstream/ResolutionPkg.vhd",
"upstream/ScoreboardGenericPkg.vhd",
"upstream/ScoreboardPkg_int.vhd",
"upstream/ScoreboardPkg_slv.vhd",
"upstream/SortListPkg_int.vhd",
"upstream/TbUtilPkg.vhd",
"upstream/TextUtilPkg.vhd",
"upstream/TranscriptPkg.vhd",
"upstream/VendorCovApiPkg.vhd",
]
Subproject commit 0bced0107438a612b8656d5ae80a6d1a32f22b81
......@@ -39,106 +39,122 @@
`define FPG_OCR0_PPS_OFFS_OFFSET 0
`define FPG_OCR0_PPS_OFFS 32'h0000000f
`define FPG_OCR0_FINE_OFFSET 4
`define FPG_OCR0_FINE 32'h00001ff0
`define FPG_OCR0_POL_OFFSET 13
`define FPG_OCR0_POL 32'h00002000
`define FPG_OCR0_MASK_OFFSET 14
`define FPG_OCR0_MASK 32'h003fc000
`define FPG_OCR0_CONT_OFFSET 22
`define FPG_OCR0_CONT 32'h00400000
`define FPG_OCR0_TRIG_SEL_OFFSET 23
`define FPG_OCR0_TRIG_SEL 32'h00800000
`define FPG_OCR0_FINE 32'h000001f0
`define FPG_OCR0_POL_OFFSET 9
`define FPG_OCR0_POL 32'h00000200
`define FPG_OCR0_COARSE_OFFSET 10
`define FPG_OCR0_COARSE 32'h00003c00
`define FPG_OCR0_CONT_OFFSET 14
`define FPG_OCR0_CONT 32'h00004000
`define FPG_OCR0_TRIG_SEL_OFFSET 15
`define FPG_OCR0_TRIG_SEL 32'h00008000
`define FPG_OCR0_LENGTH_OFFSET 16
`define FPG_OCR0_LENGTH 32'hffff0000
`define ADDR_FPG_OCR1 6'h8
`define FPG_OCR1_PPS_OFFS_OFFSET 0
`define FPG_OCR1_PPS_OFFS 32'h0000000f
`define FPG_OCR1_FINE_OFFSET 4
`define FPG_OCR1_FINE 32'h00001ff0
`define FPG_OCR1_POL_OFFSET 13
`define FPG_OCR1_POL 32'h00002000
`define FPG_OCR1_MASK_OFFSET 14
`define FPG_OCR1_MASK 32'h003fc000
`define FPG_OCR1_CONT_OFFSET 22
`define FPG_OCR1_CONT 32'h00400000
`define FPG_OCR1_TRIG_SEL_OFFSET 23
`define FPG_OCR1_TRIG_SEL 32'h00800000
`define FPG_OCR1_FINE 32'h000001f0
`define FPG_OCR1_POL_OFFSET 9
`define FPG_OCR1_POL 32'h00000200
`define FPG_OCR1_COARSE_OFFSET 10
`define FPG_OCR1_COARSE 32'h00003c00
`define FPG_OCR1_CONT_OFFSET 14
`define FPG_OCR1_CONT 32'h00004000
`define FPG_OCR1_TRIG_SEL_OFFSET 15
`define FPG_OCR1_TRIG_SEL 32'h00008000
`define FPG_OCR1_LENGTH_OFFSET 16
`define FPG_OCR1_LENGTH 32'hffff0000
`define ADDR_FPG_OCR2 6'hc
`define FPG_OCR2_PPS_OFFS_OFFSET 0
`define FPG_OCR2_PPS_OFFS 32'h0000000f
`define FPG_OCR2_FINE_OFFSET 4
`define FPG_OCR2_FINE 32'h00001ff0
`define FPG_OCR2_POL_OFFSET 13
`define FPG_OCR2_POL 32'h00002000
`define FPG_OCR2_MASK_OFFSET 14
`define FPG_OCR2_MASK 32'h003fc000
`define FPG_OCR2_CONT_OFFSET 22
`define FPG_OCR2_CONT 32'h00400000
`define FPG_OCR2_TRIG_SEL_OFFSET 23
`define FPG_OCR2_TRIG_SEL 32'h00800000
`define FPG_OCR2_FINE 32'h000001f0
`define FPG_OCR2_POL_OFFSET 9
`define FPG_OCR2_POL 32'h00000200
`define FPG_OCR2_COARSE_OFFSET 10
`define FPG_OCR2_COARSE 32'h00003c00
`define FPG_OCR2_CONT_OFFSET 14
`define FPG_OCR2_CONT 32'h00004000
`define FPG_OCR2_TRIG_SEL_OFFSET 15
`define FPG_OCR2_TRIG_SEL 32'h00008000
`define FPG_OCR2_LENGTH_OFFSET 16
`define FPG_OCR2_LENGTH 32'hffff0000
`define ADDR_FPG_OCR3 6'h10
`define FPG_OCR3_PPS_OFFS_OFFSET 0
`define FPG_OCR3_PPS_OFFS 32'h0000000f
`define FPG_OCR3_FINE_OFFSET 4
`define FPG_OCR3_FINE 32'h00001ff0
`define FPG_OCR3_POL_OFFSET 13
`define FPG_OCR3_POL 32'h00002000
`define FPG_OCR3_MASK_OFFSET 14
`define FPG_OCR3_MASK 32'h003fc000
`define FPG_OCR3_CONT_OFFSET 22
`define FPG_OCR3_CONT 32'h00400000
`define FPG_OCR3_TRIG_SEL_OFFSET 23
`define FPG_OCR3_TRIG_SEL 32'h00800000
`define FPG_OCR3_FINE 32'h000001f0
`define FPG_OCR3_POL_OFFSET 9
`define FPG_OCR3_POL 32'h00000200
`define FPG_OCR3_COARSE_OFFSET 10
`define FPG_OCR3_COARSE 32'h00003c00
`define FPG_OCR3_CONT_OFFSET 14
`define FPG_OCR3_CONT 32'h00004000
`define FPG_OCR3_TRIG_SEL_OFFSET 15
`define FPG_OCR3_TRIG_SEL 32'h00008000
`define FPG_OCR3_LENGTH_OFFSET 16
`define FPG_OCR3_LENGTH 32'hffff0000
`define ADDR_FPG_OCR4 6'h14
`define FPG_OCR4_PPS_OFFS_OFFSET 0
`define FPG_OCR4_PPS_OFFS 32'h0000000f
`define FPG_OCR4_FINE_OFFSET 4
`define FPG_OCR4_FINE 32'h00001ff0
`define FPG_OCR4_POL_OFFSET 13
`define FPG_OCR4_POL 32'h00002000
`define FPG_OCR4_MASK_OFFSET 14
`define FPG_OCR4_MASK 32'h003fc000
`define FPG_OCR4_CONT_OFFSET 22
`define FPG_OCR4_CONT 32'h00400000
`define FPG_OCR4_TRIG_SEL_OFFSET 23
`define FPG_OCR4_TRIG_SEL 32'h00800000
`define FPG_OCR4_FINE 32'h000001f0
`define FPG_OCR4_POL_OFFSET 9
`define FPG_OCR4_POL 32'h00000200
`define FPG_OCR4_COARSE_OFFSET 10
`define FPG_OCR4_COARSE 32'h00003c00
`define FPG_OCR4_CONT_OFFSET 14
`define FPG_OCR4_CONT 32'h00004000
`define FPG_OCR4_TRIG_SEL_OFFSET 15
`define FPG_OCR4_TRIG_SEL 32'h00008000
`define FPG_OCR4_LENGTH_OFFSET 16
`define FPG_OCR4_LENGTH 32'hffff0000
`define ADDR_FPG_OCR5 6'h18
`define FPG_OCR5_PPS_OFFS_OFFSET 0
`define FPG_OCR5_PPS_OFFS 32'h0000000f
`define FPG_OCR5_FINE_OFFSET 4
`define FPG_OCR5_FINE 32'h00001ff0
`define FPG_OCR5_POL_OFFSET 13
`define FPG_OCR5_POL 32'h00002000
`define FPG_OCR5_MASK_OFFSET 14
`define FPG_OCR5_MASK 32'h003fc000
`define FPG_OCR5_CONT_OFFSET 22
`define FPG_OCR5_CONT 32'h00400000
`define FPG_OCR5_TRIG_SEL_OFFSET 23
`define FPG_OCR5_TRIG_SEL 32'h00800000
`define FPG_OCR5_FINE 32'h000001f0
`define FPG_OCR5_POL_OFFSET 9
`define FPG_OCR5_POL 32'h00000200
`define FPG_OCR5_COARSE_OFFSET 10
`define FPG_OCR5_COARSE 32'h00003c00
`define FPG_OCR5_CONT_OFFSET 14
`define FPG_OCR5_CONT 32'h00004000
`define FPG_OCR5_TRIG_SEL_OFFSET 15
`define FPG_OCR5_TRIG_SEL 32'h00008000
`define FPG_OCR5_LENGTH_OFFSET 16
`define FPG_OCR5_LENGTH 32'hffff0000
`define ADDR_FPG_OCR6 6'h1c
`define FPG_OCR6_PPS_OFFS_OFFSET 0
`define FPG_OCR6_PPS_OFFS 32'h0000000f
`define FPG_OCR6_FINE_OFFSET 4
`define FPG_OCR6_FINE 32'h00001ff0
`define FPG_OCR6_POL_OFFSET 13
`define FPG_OCR6_POL 32'h00002000
`define FPG_OCR6_MASK_OFFSET 14
`define FPG_OCR6_MASK 32'h003fc000
`define FPG_OCR6_CONT_OFFSET 22
`define FPG_OCR6_CONT 32'h00400000
`define FPG_OCR6_TRIG_SEL_OFFSET 23
`define FPG_OCR6_TRIG_SEL 32'h00800000
`define FPG_OCR6_FINE 32'h000001f0
`define FPG_OCR6_POL_OFFSET 9
`define FPG_OCR6_POL 32'h00000200
`define FPG_OCR6_COARSE_OFFSET 10
`define FPG_OCR6_COARSE 32'h00003c00
`define FPG_OCR6_CONT_OFFSET 14
`define FPG_OCR6_CONT 32'h00004000
`define FPG_OCR6_TRIG_SEL_OFFSET 15
`define FPG_OCR6_TRIG_SEL 32'h00008000
`define FPG_OCR6_LENGTH_OFFSET 16
`define FPG_OCR6_LENGTH 32'hffff0000
`define ADDR_FPG_OCR7 6'h20
`define FPG_OCR7_PPS_OFFS_OFFSET 0
`define FPG_OCR7_PPS_OFFS 32'h0000000f
`define FPG_OCR7_FINE_OFFSET 4
`define FPG_OCR7_FINE 32'h00001ff0
`define FPG_OCR7_POL_OFFSET 13
`define FPG_OCR7_POL 32'h00002000
`define FPG_OCR7_MASK_OFFSET 14
`define FPG_OCR7_MASK 32'h003fc000
`define FPG_OCR7_CONT_OFFSET 22
`define FPG_OCR7_CONT 32'h00400000
`define FPG_OCR7_TRIG_SEL_OFFSET 23
`define FPG_OCR7_TRIG_SEL 32'h00800000
`define FPG_OCR7_FINE 32'h000001f0
`define FPG_OCR7_POL_OFFSET 9
`define FPG_OCR7_POL 32'h00000200
`define FPG_OCR7_COARSE_OFFSET 10
`define FPG_OCR7_COARSE 32'h00003c00
`define FPG_OCR7_CONT_OFFSET 14
`define FPG_OCR7_CONT 32'h00004000
`define FPG_OCR7_TRIG_SEL_OFFSET 15
`define FPG_OCR7_TRIG_SEL 32'h00008000
`define FPG_OCR7_LENGTH_OFFSET 16
`define FPG_OCR7_LENGTH 32'hffff0000
`define ADDR_FPG_ODELAY_CALIB 6'h24
`define FPG_ODELAY_CALIB_RST_IDELAYCTRL_OFFSET 0
`define FPG_ODELAY_CALIB_RST_IDELAYCTRL 32'h00000001
......
`define ADDR_UART_SR 5'h0
`define UART_SR_TX_BUSY_OFFSET 0
`define UART_SR_TX_BUSY 32'h00000001
`define UART_SR_RX_RDY_OFFSET 1
`define UART_SR_RX_RDY 32'h00000002
`define UART_SR_RX_FIFO_SUPPORTED_OFFSET 2
`define UART_SR_RX_FIFO_SUPPORTED 32'h00000004
`define UART_SR_TX_FIFO_SUPPORTED_OFFSET 3
`define UART_SR_TX_FIFO_SUPPORTED 32'h00000008
`define UART_SR_RX_FIFO_VALID_OFFSET 4
`define UART_SR_RX_FIFO_VALID 32'h00000010
`define UART_SR_TX_FIFO_EMPTY_OFFSET 5
`define UART_SR_TX_FIFO_EMPTY 32'h00000020
`define UART_SR_TX_FIFO_FULL_OFFSET 6
`define UART_SR_TX_FIFO_FULL 32'h00000040
`define UART_SR_RX_FIFO_OVERFLOW_OFFSET 7
`define UART_SR_RX_FIFO_OVERFLOW 32'h00000080
`define UART_SR_RX_FIFO_BYTES_OFFSET 8
`define UART_SR_RX_FIFO_BYTES 32'h00ffff00
`define UART_SR_PHYSICAL_UART_OFFSET 24
`define UART_SR_PHYSICAL_UART 32'h01000000
`define UART_SR_VIRTUAL_UART_OFFSET 25
`define UART_SR_VIRTUAL_UART 32'h02000000
`define ADDR_UART_BCR 5'h4
`define ADDR_UART_TDR 5'h8
`define UART_TDR_TX_DATA_OFFSET 0
`define UART_TDR_TX_DATA 32'h000000ff
`define ADDR_UART_RDR 5'hc
`define UART_RDR_RX_DATA_OFFSET 0
`define UART_RDR_RX_DATA 32'h000000ff
`define ADDR_UART_HOST_TDR 5'h10
`define UART_HOST_TDR_DATA_OFFSET 0
`define UART_HOST_TDR_DATA 32'h000000ff
`define UART_HOST_TDR_RDY_OFFSET 8
`define UART_HOST_TDR_RDY 32'h00000100
`define ADDR_UART_HOST_RDR 5'h14
`define UART_HOST_RDR_DATA_OFFSET 0
`define UART_HOST_RDR_DATA 32'h000000ff
`define UART_HOST_RDR_RDY_OFFSET 8
`define UART_HOST_RDR_RDY 32'h00000100
`define UART_HOST_RDR_COUNT_OFFSET 9
`define UART_HOST_RDR_COUNT 32'h01fffe00
`define ADDR_UART_CR 5'h18
`define UART_CR_RX_FIFO_PURGE_OFFSET 0
`define UART_CR_RX_FIFO_PURGE 32'h00000001
`define UART_CR_TX_FIFO_PURGE_OFFSET 1
`define UART_CR_TX_FIFO_PURGE 32'h00000002
......@@ -62,7 +62,7 @@ class FinePulseGenDriver extends IBusDevice;
super.new(acc,base);
endfunction // new
task automatic calibrate();
task automatic calibrate_k7u();
int rv;
real calib_time;
int calib_taps;
......@@ -97,30 +97,60 @@ class FinePulseGenDriver extends IBusDevice;
calib_time = real'(1.0);
calib_taps = (rv & `FPG_ODELAY_CALIB_TAPS) >> `FPG_ODELAY_CALIB_TAPS_OFFSET;
$display("FPG ODELAY calibration done, %.1f ns = %d taps\n", calib_time, calib_taps );
// $display("FPG ODELAY calibration done, %.1f ns = %d taps\n", calib_time, calib_taps );
m_delay_tap_size = calib_time / real'(calib_taps);
endtask // calibrate
task automatic calibrate_k7();
int rv;
real calib_time;
int calib_taps;
$error("Calibrate start");
write32( `ADDR_FPG_ODELAY_CALIB, `FPG_ODELAY_CALIB_RST_IDELAYCTRL );
write32( `ADDR_FPG_ODELAY_CALIB, 0 );
write32( `ADDR_FPG_ODELAY_CALIB, `FPG_ODELAY_CALIB_RST_OSERDES );
write32( `ADDR_FPG_ODELAY_CALIB, 0 );
#100ns;
while(1)
begin
read32( `ADDR_FPG_ODELAY_CALIB, rv );
$display("odelay = %x", rv);
if ( rv & `FPG_ODELAY_CALIB_RDY )
break;
end
m_delay_tap_size = 0.078 /*ns*/;
endtask // calibrate
task automatic pulse( int out, int polarity, int cont, real delta, int tr_force = 0 );
task automatic pulse( int out, int polarity, int cont, real delta, int length = 0, int tr_force = 0 );
uint64_t rv;
int coarse_par = int'($floor (delta / 16.0));
int coarse_ser = int'($floor (delta / 1.0) - coarse_par * 16);
int fine = int'((delta / 1.0 - $floor(delta / 1.0)) * 1.0 / m_delay_tap_size);
int mask = coarse_ser;
uint32_t ocr;
$display("Tapsize %.5f Fine %d", m_delay_tap_size, fine);
// $display("Tapsize %.5f Fine %d", m_delay_tap_size, fine);
ocr = (coarse_par << `FPG_OCR0_PPS_OFFS_OFFSET)
| (mask << `FPG_OCR0_MASK_OFFSET)
| (coarse_ser << `FPG_OCR0_COARSE_OFFSET)
| (fine << `FPG_OCR0_FINE_OFFSET)
| (cont ? `FPG_OCR0_CONT : 0)
| (polarity ? `FPG_OCR0_POL : 0 );
| (polarity ? `FPG_OCR0_POL : 0 )
| (length << `FPG_OCR0_LENGTH_OFFSET);
m_acc.write( m_base + `ADDR_FPG_OCR0 + 4 * out, ocr );
......@@ -201,7 +231,7 @@ module main;
if( dlys.size() && t_pps_valid )
begin
automatic real t_req = dlys.pop_front();
automatic real t_req = dlys.pop_front();
automatic time dly = t_pulse - t_pps;
t_pps_valid = 0;
......@@ -233,10 +263,10 @@ module main;
// the Device Under Test
xwb_fine_pulse_gen
#(
.g_target_platform("KintexUltrascale"),
.g_target_platform("Kintex7"),
.g_use_external_serdes_clock(0),
.g_num_channels(1),
.g_use_odelay(6'b1)
.g_use_odelay(6'b111111)
)
DUT
(
......@@ -279,7 +309,7 @@ module main;
drv = new( acc, 0 );
drv.calibrate();
drv.calibrate_k7();
......@@ -292,10 +322,10 @@ module main;
for (t = 1.0; t <= 200.9; t+=0.1)
begin
$display("Pulse @ %f", t );
// $display("Pulse @ %f", t );
dlys.push_back(t);
drv.pulse(0, 1, 0, t);
drv.pulse(0, 0, 0, t, 4);
end
......
library ieee;
use ieee.std_logic_1164.all;
use work.wishbone_pkg.all;
use work.sim_wishbone.all;
entity wb_spi_tb is
end wb_spi_tb;
architecture behav of wb_spi_tb is
procedure spi_test_case (signal clk_sys : std_logic;
signal wb_in: out t_wishbone_slave_in;
signal wb_out: in t_wishbone_slave_out;
control_val_lsb : in std_logic_vector (7 downto 0);
test_case_name : in String ) is
variable v : std_logic_vector(31 downto 0);
begin
-- Set divider to 2
write32(clk_sys, wb_in, wb_out, x"0000_0014", x"0000_0002");
-- Set control
write32(clk_sys, wb_in, wb_out, x"0000_0010", x"0000_24" & control_val_lsb);
-- Set data
write32(clk_sys, wb_in, wb_out, x"0000_0000", x"0000_008d");
-- Set CS
write32(clk_sys, wb_in, wb_out, x"0000_0018", x"0000_0001");
-- Verify control
read32(clk_sys, wb_in, wb_out, x"0000_0010", v);
assert v(7 downto 0) = control_val_lsb
report "(Test case: " & test_case_name & ") Control LSB returned unexpected value 0x" &
to_hstring(v(7 downto 0)) & ", expecting 0x" & to_hstring(control_val_lsb);
-- Go
write32(clk_sys, wb_in, wb_out, x"0000_0010", x"0000_25" & control_val_lsb);
loop
read32(clk_sys, wb_in, wb_out, x"0000_0010", v);
exit when v (8) = '0';
end loop;
end spi_test_case;
signal clk_sys : std_logic := '0';
signal rst_n : std_logic;
signal wb_in : t_wishbone_slave_in;
signal wb_out : t_wishbone_slave_out;
signal int : std_logic;
signal pad_cs : std_logic_vector(8-1 downto 0);
signal pad_sclk : std_logic;
signal pad_mosi : std_logic;
signal pad_miso : std_logic;
signal stop : boolean := False;
begin
xwb_spi_1: entity work.xwb_spi
generic map (
g_interface_mode => CLASSIC,
g_address_granularity => BYTE,
g_divider_len => 8,
g_max_char_len => 128,
g_num_slaves => 8)
port map (
clk_sys_i => clk_sys,
rst_n_i => rst_n,
slave_i => wb_in,
slave_o => wb_out,
desc_o => open,
int_o => int,
pad_cs_o => pad_cs,
pad_sclk_o => pad_sclk,
pad_mosi_o => pad_mosi,
pad_miso_i => pad_miso);
clk_sys <= not clk_sys after 5 ns when not stop else '0';
rst_n <= '0', '1' after 20 ns;
pad_miso <= pad_mosi;
process
variable v : std_logic_vector(31 downto 0);
begin
init(wb_in);
wait until rst_n = '1';
wait until rising_edge(clk_sys);
spi_test_case(clk_sys, wb_in, wb_out, x"28", "Case 1"); -- len = 40 chars, ok
spi_test_case(clk_sys, wb_in, wb_out, x"23", "Case 2"); -- len = 35 chars, ok
spi_test_case(clk_sys, wb_in, wb_out, x"28", "Case 3"); -- len = 40 chars, **BUG** 0x29 gets written instead?, 41 chars transmitted
report "done - success";
stop <= true;
wait;
end process;
end behav;
......@@ -67,6 +67,9 @@ class WBUartDriver extends IBusDevice;
uint32_t rv;
read32( `ADDR_UART_SR, rv );
$display("uart_init SR %b", rv);
write32(`ADDR_UART_BCR, calc_baudrate( baudrate, clock_freq) );
......@@ -203,8 +206,8 @@ module main;
.slave_i (Host1.out),
.slave_o (Host1.in),
.uart_txd_o(txd),
.uart_rxd_i(rxd)
.uart_txd_o(loop),
.uart_rxd_i(loop)
);
......@@ -241,7 +244,7 @@ module main;
.rst_n_i (rst_n));
const int n_tx_bytes = 1024;
initial begin
......@@ -249,12 +252,13 @@ module main;
automatic CWishboneAccessor acc1 = Host1.get_accessor();
automatic WBUartDriver drv_fifo = new( acc1, 0 );
automatic CWishboneAccessor acc2 = Host2.get_accessor();
automatic WBUartDriver drv_no_fifo = new( acc2, 0 );
// automatic CWishboneAccessor acc2 = Host2.get_accessor();
// automatic WBUartDriver drv_no_fifo = new( acc2, 0 );
automatic int i;
acc1.set_mode(PIPELINED);
acc2.set_mode(PIPELINED);
//acc2.set_mode(PIPELINED);
#100ns;
......@@ -265,16 +269,16 @@ module main;
@(posedge clk_62m5);
drv_fifo.init(9216000, 62500000, 0);
drv_no_fifo.init(9216000, 62500000, 0);
drv_fifo.init(9216000, 62500000, 1);
// drv_no_fifo.init(9216000, 62500000, 0);
#1us;
for(i=0;i<100;i++)
for(i=0;i<n_tx_bytes;i++)
begin
drv_no_fifo.send(i);
// drv_no_fifo.send(i);
drv_fifo.send(i);
drv_no_fifo.update();
// drv_no_fifo.update();
drv_fifo.update();
end
......@@ -283,8 +287,8 @@ module main;
// $display("%d %d", drv_fifo.tx_idle(), drv_no_fifo.tx_idle() );
drv_fifo.update();
drv_no_fifo.update();
if( drv_fifo.tx_idle() && drv_no_fifo.tx_idle() )
// drv_no_fifo.update();
if( drv_fifo.tx_idle() /* && drv_no_fifo.tx_idle() */ )
break;
end
......@@ -293,7 +297,9 @@ module main;
for(i=0;i<500;i++)
begin
drv_fifo.update();
drv_no_fifo.update();
#1us;
// drv_no_fifo.update();
end
......@@ -301,12 +307,14 @@ module main;
for(i=0;i<100;i++)
begin
automatic int rx = drv_no_fifo.recv();
if( rx != i )
$error("NoFifo err %x vs %x", i, rx );
rx = drv_fifo.recv();
if( rx != i )
$error("Fifo err %x vs %x", i, rx );
// automatic int rx = drv_no_fifo.recv();
// if( rx != i )
// $error("NoFifo err %x vs %x", i, rx );
automatic int rx = drv_fifo.recv();
$display("Fifo %02x vs %02x %s", i, rx, (i == rx) ? "OK" : "ERROR" );
if( i != rx )
$error("");
end
......
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/clk_sys_i
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/rst_n_i
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/wb_adr_i
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/wb_dat_i
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/wb_dat_o
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/wb_cyc_i
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/wb_sel_i
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/wb_stb_i
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/wb_we_i
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/wb_ack_o
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/wb_stall_o
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/int_o
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/uart_rxd_i
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/uart_txd_o
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/rx_ready_reg
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/rx_ready
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/uart_bcr
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/rdr_rack
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/host_rack
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/baud_tick
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/baud_tick8
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/resized_addr
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/wb_in
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/wb_out
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/regs_in
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/regs_out
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/vuart_fifo_empty
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/vuart_fifo_full
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/vuart_fifo_rd
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/vuart_fifo_wr
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/vuart_fifo_count
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_empty
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_full
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_rd
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_wr
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_count
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_reset_n
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_empty
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_full
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_overflow
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_rd
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_wr
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_count
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_reset_n
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/phys_rx_ready
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/phys_tx_busy
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/phys_tx_start
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/phys_rx_data
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/phys_tx_data
add wave -noupdate -group UartFifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_state
add wave -noupdate -group TXFIFO /main/DUT_FIFO/U_Wrapped_UART/gen_phys_fifos/U_UART_TX_FIFO/rst_n_i
add wave -noupdate -group TXFIFO /main/DUT_FIFO/U_Wrapped_UART/gen_phys_fifos/U_UART_TX_FIFO/clk_i
add wave -noupdate -group TXFIFO /main/DUT_FIFO/U_Wrapped_UART/gen_phys_fifos/U_UART_TX_FIFO/d_i
add wave -noupdate -group TXFIFO /main/DUT_FIFO/U_Wrapped_UART/gen_phys_fifos/U_UART_TX_FIFO/we_i
add wave -noupdate -group TXFIFO /main/DUT_FIFO/U_Wrapped_UART/gen_phys_fifos/U_UART_TX_FIFO/q_o
add wave -noupdate -group TXFIFO /main/DUT_FIFO/U_Wrapped_UART/gen_phys_fifos/U_UART_TX_FIFO/rd_i
add wave -noupdate -group TXFIFO /main/DUT_FIFO/U_Wrapped_UART/gen_phys_fifos/U_UART_TX_FIFO/empty_o
add wave -noupdate -group TXFIFO /main/DUT_FIFO/U_Wrapped_UART/gen_phys_fifos/U_UART_TX_FIFO/full_o
add wave -noupdate -group TXFIFO /main/DUT_FIFO/U_Wrapped_UART/gen_phys_fifos/U_UART_TX_FIFO/almost_empty_o
add wave -noupdate -group TXFIFO /main/DUT_FIFO/U_Wrapped_UART/gen_phys_fifos/U_UART_TX_FIFO/almost_full_o
add wave -noupdate -group TXFIFO /main/DUT_FIFO/U_Wrapped_UART/gen_phys_fifos/U_UART_TX_FIFO/count_o
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/clk_sys_i
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/rst_n_i
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/wb_adr_i
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/wb_dat_i
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/wb_dat_o
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/wb_cyc_i
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/wb_sel_i
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/wb_stb_i
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/wb_we_i
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/wb_ack_o
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/wb_stall_o
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/int_o
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/uart_rxd_i
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/uart_txd_o
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/rx_ready_reg
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/rx_ready
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/uart_bcr
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/rdr_rack
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/host_rack
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/baud_tick
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/baud_tick8
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/resized_addr
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/wb_in
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/wb_out
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/regs_in
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/regs_out
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/vuart_fifo_empty
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/vuart_fifo_full
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/vuart_fifo_rd
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/vuart_fifo_wr
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/vuart_fifo_count
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/tx_fifo_empty
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/tx_fifo_full
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/tx_fifo_rd
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/tx_fifo_wr
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/tx_fifo_count
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/tx_fifo_reset_n
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/rx_fifo_empty
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/rx_fifo_full
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/rx_fifo_overflow
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/rx_fifo_rd
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/rx_fifo_wr
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/rx_fifo_count
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/rx_fifo_reset_n
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/phys_rx_ready
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/phys_tx_busy
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/phys_tx_start
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/phys_rx_data
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/phys_tx_data
add wave -noupdate -expand -group UartNoFifo /main/DUT_NO_FIFO/U_Wrapped_UART/tx_fifo_state
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/clk_sys_i
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/rst_n_i
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/baud8_tick_i
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/rxd_i
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/rx_ready_o
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/rx_error_o
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/rx_data_o
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/Baud8Tick
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/RxD_sync_inv
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/RxD_cnt_inv
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/RxD_bit_inv
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/state
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/bit_spacing
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/next_bit
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/RxD_data
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/RxD_data_ready
add wave -noupdate -group RX /main/DUT_FIFO/U_Wrapped_UART/gen_phys_uart/U_RX/RxD_data_error
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/clk_sys_i
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rst_n_i
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/wb_adr_i
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/wb_dat_i
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/wb_dat_o
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/wb_cyc_i
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/wb_sel_i
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/wb_stb_i
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/wb_we_i
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/wb_ack_o
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/wb_stall_o
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/int_o
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/uart_rxd_i
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/uart_txd_o
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rx_ready_reg
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rx_ready
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/uart_bcr
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rdr_rack
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/host_rack
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/baud_tick
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/baud_tick8
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/resized_addr
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/wb_in
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/wb_out
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/regs_in
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/regs_out
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/vuart_fifo_empty
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/vuart_fifo_full
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/vuart_fifo_rd
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/vuart_fifo_wr
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/vuart_fifo_count
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_empty
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_full
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_rd
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_wr
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_count
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_reset_n
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_empty
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_full
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_overflow
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_rd
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_wr
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_count
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_reset_n
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/phys_rx_ready
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/phys_tx_busy
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/phys_tx_start
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/phys_rx_data
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/phys_tx_data
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/tx_fifo_state
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_state
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_data
add wave -noupdate -expand -group uart-fifo /main/DUT_FIFO/U_Wrapped_UART/rx_fifo_read
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {12968000000 fs} 0}
WaveRestoreCursors {{Cursor 1} {99593444800 fs} 0}
configure wave -namecolwidth 298
configure wave -valuecolwidth 100
configure wave -justifyvalue left
......@@ -127,4 +86,4 @@ configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {0 fs} {109552789280 fs}
WaveRestoreZoom {98737563630 fs} {100449325970 fs}
......@@ -3,6 +3,7 @@
with open("buildinfo_pkg.vhd", "w") as f:
import subprocess
import time
import unicodedata
# Extract current commit id.
try:
......@@ -27,6 +28,8 @@ with open("buildinfo_pkg.vhd", "w") as f:
try:
userid = subprocess.check_output(
["git", "config", "--get", "user.name"]).decode().strip()
# VHDL only handles ASCII strings
userid = unicodedata.normalize('NFKD', userid).encode('ascii', 'replace')
except:
userid = "unknown"
if action == "simulation":
......
# Script to generate the buildinfo_pkg.vhd file
# Script to generate the HDL sourceid information for a given project
# Local parameter: project
with open("sourceid_{}_pkg.vhd".format(project), "w") as f:
# Note: this script differs from the (similar) gen_buildinfo.py in that it produces std_logic
# vectors with versioning info to be embedded in the metadata, while buildinfo produces a string
# that focuses more on when/how/who built the bitstream.
import argparse
import sys
parser = argparse.ArgumentParser(
description='Generate source ID for given project')
parser.add_argument('-p', '--project',
help = "Project name to use. If not provided, will look for a 'project' local variable.")
parser.add_argument('-l', '--language', choices = ['VHDL','Verilog'], default = 'VHDL',
help = "HDL language for output file. If not provided, defaults to VHDL.")
args = parser.parse_args()
if(args.project):
project = args.project
try:
project
except NameError:
print("""No project defined, make sure you either define your variable
(e.g. like HdlMake does when you source this script),
or that you provide the '-p' argument at run-time.""")
sys.exit(1)
if (args.language) == 'VHDL':
outfile = "sourceid_{}_pkg.vhd".format(project)
comment = "--"
else:
outfile = "sourceid_{}.vh".format(project)
comment = "//"
with open(outfile, "w") as f:
import subprocess
import time
import re
# Extract current commit id.
try:
......@@ -22,20 +56,38 @@ with open("sourceid_{}_pkg.vhd".format(project), "w") as f:
except:
dirty = True
try:
version = re.search("\d+\.\d+\.\d+", tag)
major,minor,patch = [int(x) for x in version.group().split('.')]
except:
major = minor = patch = 0
if dirty:
# There is no room for a dirty flag, just erase half of the bytes, so
# that's obvious it's not a real sha1, and still leaves enough to
# find the sha1 in the project.
sourceid = sourceid[:16] + (16 * '0')
f.write("-- Sourceid for project {}\n".format(project))
f.write("--\n")
f.write("-- This file was automatically generated; do not edit\n")
f.write(f"{comment} Sourceid for project {project}\n")
f.write(f"{comment}\n")
f.write(f"{comment} This file was automatically generated; do not edit\n")
f.write("\n")
f.write("library ieee;")
f.write("use ieee.std_logic_1164.all;")
f.write("\n")
f.write("package sourceid_{}_pkg is\n".format(project))
f.write(" constant sourceid : std_logic_vector(127 downto 0) :=\n")
f.write(' x"{}";\n'.format(sourceid))
f.write('end sourceid_{}_pkg;\n'.format(project))
if args.language == 'VHDL':
f.write("library ieee;\n")
f.write("use ieee.std_logic_1164.all;\n")
f.write("\n")
f.write("package sourceid_{}_pkg is\n".format(project))
f.write(" constant sourceid : std_logic_vector(127 downto 0) :=\n")
f.write(' x"{}";\n'.format(sourceid))
f.write(" constant version : std_logic_vector(31 downto 0) := ")
f.write('x"{:02x}{:02x}{:04x}";\n'.format(major & 0xff, minor & 0xff, patch & 0xffff))
f.write('end sourceid_{}_pkg;\n'.format(project))
else:
f.write(f"`ifndef SOURCEID_{project.upper()}_H\n")
f.write(f"`define SOURCEID_{project.upper()}_H\n")
f.write("\n")
f.write(f"`define SOURCEID_{project.upper()}_SOURCEID 128'h{sourceid}\n")
f.write(f"`define SOURCEID_{project.upper()}_VERSION 32'h{major:02x}{minor:02x}{patch:04x}\n")
f.write("\n")
f.write(f"`endif // ifndef SOURCEID_{project.upper()}_H\n")
##-------------------------------------------------------------------------------
## CERN BE-CEM-EDL
## General Cores
## https://www.ohwr.org/projects/general-cores
##-------------------------------------------------------------------------------
##
## Tcl script to produce CDC (Clock Domain Crossing) constraints for the CDC primitives
## used in your Vivado design:
## - gc_sync
## - gc_sync_register
## - gc_reset_multi_aasd
##
## Instructions for use:
## - synthesize your design
## - open the synthesized design in Vivado
## - run this script (source generate_cdc_constraints.tcl)
## - the result of operation is a file called "gencores_constraints.xdc". Add it
## to the project's sources.
## - note: you must rerun this script every time you change (add/remove/modify)
## gencores's CDC primtives in your design.
## - enjoy and profit!
##
##-------------------------------------------------------------------------------
## Copyright CERN 2023
##-------------------------------------------------------------------------------
## This Source Code Form is subject to the terms of the Mozilla Public License,
## version 2.0. If a copy of the MPL was not distributed with this file, You can
## obtain one at https://mozilla.org/MPL/2.0/.
##-------------------------------------------------------------------------------
# Note: you can make sure all warnings for unmatched pins are displayed using:
# set_msg_config -id "Vivado 12-508" -limit 999999
proc generate_gc_sync_constraints { f_out } {
set the_cells [ get_cells -hier -filter { REF_NAME==gc_sync || ORIG_REF_NAME==gc_sync } ]
set count 0
puts $f_out "# gc_sync"
puts $f_out "###########"
foreach cell $the_cells {
puts $f_out ""
puts $f_out "### Cell $cell"
set dst_ff_clr [get_pins "$cell/sync_*.sync*_*/CLR" ]
set dst_ff [get_cells "$cell/sync_*.sync0_reg*" ]
if { "$dst_ff" == "" } {
puts $f_out "#NOTE: no sync0_reg"
set dst_ff [get_cells -hier -filter "name=~$cell/sync_*.sync0_reg*" ]
}
if { "$dst_ff_clr" == "" } {
puts $f_out "#NOTE: no CLR pin"
set dst_ff_clr [get_pins -hier -filter "name=~$cell/sync_*.sync*_*/CLR" ]
}
if { "$dst_ff" == "" } {
puts $f_out "#WARNING: can't find destination FF for sync cell '$cell'"
continue
}
set clk [ get_clocks -of_objects [ get_pins -filter {REF_PIN_NAME=~clk_i*} -of [get_cells $cell] ] ]
if { [ llength $clk] == 0 } {
puts $f_out "#WARNING: cell '$cell' has no clock, skipping"
continue
}
puts $f_out "#DST_FF $dst_ff"
set dst_fan_in [ all_fanin -startpoints_only -flat [ get_pins "$dst_ff/D"] ]
# puts $f_out "#FAN-IN: $dst_fan_in"
# puts $f_out "# fan-in: "
# foreach s $dst_fan_in {
# puts $f_out "# $s"
# #report_property $src_cell
# }
# Note: do we need to filter fanin ? Not sure why.
set src_clk_pins [ get_pins -filter {IS_CLOCK==1} $dst_fan_in ]
set src_cell_pins [ get_pins -filter {DIRECTION==OUT} $dst_fan_in ]
# Note: can you have ports ? Usually a port (top-level pin) is
# first connected to an IOB.
set src_ports [ get_ports $dst_fan_in ]
set clk_period [get_property PERIOD [ lindex $clk 0 ] ]
foreach s $src_clk_pins {
puts $f_out "#SRC-CLK: $s"
#report_property $src_cell
}
foreach s $src_ports {
puts $f_out "#SRC-PORT: $s"
#report_property $src_cell
}
foreach s $src_cell_pins {
puts $f_out "#SRC-PIN: $s"
#report_property $src_cell
}
puts $f_out "#CLK: $clk (period: $clk_period)"
set srcs [ concat $src_clk_pins $src_ports $src_cell_pins ]
if { [ llength $srcs] == 0 } {
# Maybe connected to 0 or 1.
# Vivado also emits a warning.
puts $f_out "#WARNING: no fan-in found for $cell"
continue
}
if { [ llength $srcs] > 1 } {
# Can this happen ?
puts $f_out "#WARNING: several inputs for cell"
}
# Emit constraints.
puts $f_out "set_max_delay $clk_period -datapath_only -from { $srcs } -to { $dst_ff }"
foreach clr_pin $dst_ff_clr {
puts $f_out "set_false_path -to { $clr_pin }"
}
incr count
}
return $count
}
proc generate_gc_sync_register_constraints { f_out } {
set the_cells [ get_cells -hier -filter { REF_NAME==gc_sync_register || ORIG_REF_NAME==gc_sync_register} ]
set count 0
puts $f_out "# gc_sync_register"
puts $f_out "##################"
foreach cell $the_cells {
puts $f_out ""
puts $f_out "#Cell: $cell"
set dst_ff_clr [get_pins "$cell/sync*_*[*]/CLR" ]
set dst_ff_d [get_pins "$cell/sync0_*[*]/D" ]
if { "$dst_ff_d" == "" } {
puts $f_out "#NOTE: no sync0_reg"
set dst_ff_d [get_pins -hier -filter "name=~$cell/sync0_*[*]/D" ]
}
if { "$dst_ff_clr" == "" } {
puts $f_out "#NOTE: no CLR pin"
set dst_ff_clr [get_pins -hier -filter "name=~$cell/sync*_*[*]/CLR" ]
}
if { "$dst_ff_d" == "" } {
puts $f_out "#WARNING: can't find destination FF for sync reg cell '$cell'"
continue
}
set clk [ get_clocks -of_objects [ get_pins -filter {REF_PIN_NAME=~clk_i*} -of $cell ] ]
if { [ llength $clk] == 0 } {
puts $f_out "#WARNING: cell '$cell' has no clock, skipping"
continue
}
set all_src_ffs []
foreach dst_pin $dst_ff_d {
puts $f_out "#DST_PINS: $dst_pin"
#set src_cell [get_cells -of_objects [get_pins -filter {IS_LEAF && DIRECTION == OUT} -of_objects [get_nets -segments -of_objects [get_pins "$dst_cell/D"]]]]
set src_cell [ all_fanin -startpoints_only -flat $dst_pin ]
if { [ llength $src_cell ] == 0 } {
# Connected to 0/1.
puts $f_out "#WARNING: no fan-in found for $dst_pin"
continue
}
puts $f_out "#SRC_CELL $src_cell"
lappend all_src_ffs [ lindex $src_cell 0 ]
}
if { [ llength $all_src_ffs ] == 0 } {
continue
}
set clk_period [get_property PERIOD [ lindex $clk 0 ] ]
#foreach src_cell $src_cells {
#puts "SRC: $src_cell"
#}
puts $f_out "#Cell: $cell, src $all_src_ffs, dst $dst_ff_d, clock $clk, period $clk_period"
puts $f_out "set_max_delay $clk_period -quiet -datapath_only -from { $all_src_ffs } -to { $dst_ff_d }"
puts $f_out "set_bus_skew $clk_period -quiet -from { $all_src_ffs } -to { $dst_ff_d }"
foreach clr_pin $dst_ff_clr {
puts $f_out "set_false_path -to { $clr_pin }"
}
incr count
}
return $count
}
proc generate_gc_sync_word_constraints { f_out } {
set the_cells [ get_cells -hier -filter { REF_NAME==gc_sync_word_rd || ORIG_REF_NAME==gc_sync_word_rd || REF_NAME==gc_sync_word_wr || ORIG_REF_NAME==gc_sync_word_wr } ]
set count 0
puts $f_out "# gc_sync_word"
puts $f_out "##############"
foreach cell $the_cells {
set src_ffs [get_pins "$cell/gc_sync_word_data_reg[*]/Q" ]
if { "$src_ffs" == "" } {
puts $f_out "#WARNING: can't find source FF for cell '$cell'"
continue
}
puts $f_out "#Cell: $cell"
foreach src_ff $src_ffs {
set src_nets [get_nets -segments -of_objects $src_ff]
set dst_pins [get_pins -filter {DIRECTION==IN} -of_objects $src_nets]
if { "$dst_pins" == "" } {
puts "#WARNING: can't find destination pin for cell '$cell', it might have been optimized away"
continue
}
set dst_ff [get_cells -of_objects $dst_pins]
set clk [ get_clocks -of_objects [ get_pins -filter {REF_PIN_NAME=~C} -of $dst_ff ] ]
set clk_period [get_property PERIOD [ lindex $clk 0 ] ]
puts $f_out "set_max_delay $clk_period -datapath_only -from { $src_ff } -to { $dst_ff }"
}
incr count
}
return $count
}
proc generate_gc_reset_multi_aasd_constraints { f_out } {
set the_cells [ get_cells -hier -filter { REF_NAME==gc_reset_multi_aasd || ORIG_REF_NAME==gc_reset_multi_aasd } ]
set count 0
puts $f_out "# gc_reset_multi_aasd"
puts $f_out "#####################"
foreach cell $the_cells {
set dst_ff_clr [get_pins "$cell/*rst_chains_reg[*]/CLR" ]
if { "$dst_ff_clr" == "" } {
set dst_ff_clr [get_pins -hier -filter "name=~$cell/*rst_chains_reg[*]/CLR" ]
}
if { "$dst_ff_clr" == "" } {
puts $f_out "#WARNING: can't find destination FF CLR pin for cell '$cell'"
continue
}
foreach clr_pin $dst_ff_clr {
puts $f_out "set_false_path -to { $clr_pin }"
}
incr count
}
return $count
}
proc generate_gc_falsepath_waiver_constraints { f_out } {
set the_cells [ get_cells -hier -filter { REF_NAME=~gc_falsepath_waiver* } ]
set count 0
foreach cell $the_cells {
set src_ff [get_pins "$cell/in_i[*]" ]
if { "$src_ff" == "" } {
set src_ff [get_pins -hier -filter "name=~$cell/in_i[*]" ]
}
if { "$src_ff" == "" } {
puts $f_out "#WARNING: can't find source pin for '$cell'"
continue
}
foreach pin $src_ff {
puts $f_out "set_false_path -from { $pin }"
}
incr count
}
return $count
}
set f_out [open "gencores_constraints.xdc" w]
set n_gc_sync_cells [ generate_gc_sync_constraints $f_out ]
puts $f_out ""
set n_gc_sync_register_cells [ generate_gc_sync_register_constraints $f_out ]
puts $f_out ""
set n_gc_reset_multi_aasd_cells [ generate_gc_reset_multi_aasd_constraints $f_out ]
puts $f_out ""
set n_gc_sync_word_cells [ generate_gc_sync_word_constraints $f_out ]
#set n_gc_falsepath_waiver_cells [ generate_gc_falsepath_waiver_constraints $f_out ]
puts "gencores CDC statistics: "
puts " - gc_sync: $n_gc_sync_cells instances"
puts " - gc_sync_register: $n_gc_sync_register_cells instances"
puts " - gc_sync_word: $n_gc_sync_word_cells instances"
puts " - gc_reset_multi_aasd: $n_gc_reset_multi_aasd_cells instances"
#puts " - gc_falsepath_waiver: $n_gc_falsepath_waiver_cells instances"
close $f_out
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