Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • project/general-cores
  • kblantos/general-cores
2 results
Show changes
Showing
with 1672 additions and 14 deletions
# SPDX-FileCopyrightText: 2024 CERN (home.cern)
#
# SPDX-License-Identifier: GPL-2.0-or-later
-include Makefile.specific
# include parent_common.mk for buildsystem's defines
#use absolute path for REPO_PARENT
TOPDIR ?= $(shell /bin/pwd)/../../..
REPO_PARENT ?= $(TOPDIR)/..
-include $(REPO_PARENT)/parent_common.mk
CPPCHECK ?= cppcheck
FLAWFINDER ?= flawfinder
CURDIR := $(shell /bin/pwd)
KVERSION ?= $(shell uname -r)
KERNELSRC ?= /lib/modules/$(KVERSION)/build
WBGEN2 ?= wbgen2
GIT_VERSION := $(shell git describe --always --dirty --long --tags)
all: modules
install: modules_install
modules modules_install: hw_headers
hw_headers: wb_uart.h
wb_uart.h: $(TOPDIR)/modules/wishbone/wb_uart/simple_uart_wb.wb
$(WBGEN2) -s defines -C $@ $<
clean help modules:
$(MAKE) -C $(KERNELSRC) M=$(shell pwd) GIT_VERSION=$(GIT_VERSION) $@
modules_install: modules
$(MAKE) -C $(KERNELSRC) M=$(shell /bin/pwd) $@
cppcheck:
$(CPPCHECK) -q -I. --enable=all *.c *.h
flawfinder:
$(FLAWFINDER) -SQDC .
.PHONY: all modules clean help install modules_install cppcheck flawfinder hw_headers
\ No newline at end of file
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2024 CERN (home.cern)
#include "wb_uart.h"
#include <linux/version.h>
#include <linux/types.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/platform_device.h>
#include <linux/platform_data/wb_uart_pdata.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/mod_devicetable.h>
#include <linux/io.h>
#define MAX_NBR_OF_BYTES_PER_IRQ 32
#define wbu_MEM_BASE 0
struct wbu_memory_ops {
#if KERNEL_VERSION(5, 8, 0) <= LINUX_VERSION_CODE
u32 (*read)(const void *addr);
#else
u32 (*read)(void *addr);
#endif
void (*write)(u32 value, void *addr);
};
struct wbu_channel {
spinlock_t lock;
struct tty_port tty_port;
unsigned int open_count;
unsigned int nb_bytes;
unsigned int ptr_read;
unsigned int ptr_write;
};
struct wbu_desc {
struct tty_driver *tty_driver;
void *base_addr;
struct wbu_memory_ops memops;
struct wbu_channel channel;
};
enum wbu_irq_resource {
wbu_IRQ = 0,
};
static inline void wbu_write_reg(struct wbu_desc *wbuart, u32 val, u32 offset)
{
wbuart->memops.write(val, wbuart->base_addr + offset);
}
static inline u32 wbu_read_reg(struct wbu_desc *wbuart, u32 offset)
{
return wbuart->memops.read(wbuart->base_addr + offset);
}
static inline int wbu_is_bigendian(struct platform_device *pdev)
{
struct wb_uart_platform_data *wbu_pd =
(struct wb_uart_platform_data *) pdev->dev.platform_data;
return !!(wbu_pd->flags & WB_UART_BIG_ENDIAN);
}
static inline int wbu_check_type(struct wbu_desc *wbuart)
{
if (wbu_read_reg(wbuart, UART_REG_SR) & UART_SR_PHYSICAL_UART)
return 0;
return -EINVAL;
}
static inline void wbu_enable_rx_interrupts(struct wbu_desc *wbuart)
{
u32 cr = wbu_read_reg(wbuart, UART_REG_CR);
cr |= UART_CR_RX_INTERRUPT_ENABLE;
wbu_write_reg(wbuart, cr, UART_REG_CR);
}
static inline void wbu_disable_rx_interrupts(struct wbu_desc *wbuart)
{
u32 cr = wbu_read_reg(wbuart, UART_REG_CR);
cr &= ~UART_CR_RX_INTERRUPT_ENABLE;
wbu_write_reg(wbuart, cr, UART_REG_CR);
}
static inline void wbu_enable_tx_interrupts(struct wbu_desc *wbuart)
{
u32 cr = wbu_read_reg(wbuart, UART_REG_CR);
cr |= UART_CR_TX_INTERRUPT_ENABLE;
wbu_write_reg(wbuart, cr, UART_REG_CR);
}
static inline void wbu_disable_tx_interrupts(struct wbu_desc *wbuart)
{
u32 cr = wbu_read_reg(wbuart, UART_REG_CR);
cr &= ~UART_CR_TX_INTERRUPT_ENABLE;
wbu_write_reg(wbuart, cr, UART_REG_CR);
}
static void wbu_port_shutdown(struct tty_port *port)
{
struct wbu_desc *wbuart = dev_get_drvdata(port->tty->dev->parent);
wbu_disable_rx_interrupts(wbuart);
wbu_disable_tx_interrupts(wbuart);
}
static int wbu_port_activate(struct tty_port *port, struct tty_struct *tty)
{
struct wbu_desc *wbuart = dev_get_drvdata(tty->dev->parent);
wbu_enable_rx_interrupts(wbuart);
return 0;
}
static const struct tty_port_operations wbu_port_ops = {
.shutdown = wbu_port_shutdown,
.activate = wbu_port_activate
};
static void wbu_memops_detect(struct platform_device *pdev)
{
struct wbu_desc *wbuart = platform_get_drvdata(pdev);
if (wbu_is_bigendian(pdev)) {
wbuart->memops.read = ioread32be;
wbuart->memops.write = iowrite32be;
} else {
wbuart->memops.read = ioread32;
wbuart->memops.write = iowrite32;
}
}
static int wbu_tty_tx_send(struct wbu_desc *wbuart, const char c)
{
uint32_t reg = wbu_read_reg(wbuart, UART_REG_SR);
if (reg & UART_SR_TX_BUSY)
return -EBUSY;
wbu_write_reg(wbuart, c, UART_REG_TDR);
return 0;
}
static void wbu_tty_handler_tx(struct wbu_desc *wbuart)
{
struct wbu_channel *channel = &wbuart->channel;
int max_count = MAX_NBR_OF_BYTES_PER_IRQ;
if (channel->nb_bytes == 0)
return;
spin_lock(&channel->lock);
do {
u8 c = channel->tty_port.xmit_buf[channel->ptr_read];
int ret = wbu_tty_tx_send(wbuart, c);
if (ret < 0)
break;
channel->ptr_read = (channel->ptr_read + 1) % PAGE_SIZE;
channel->nb_bytes--;
max_count--;
} while (channel->nb_bytes && max_count);
if (channel->nb_bytes == 0) {
wbu_disable_tx_interrupts(wbuart);
tty_port_tty_wakeup(&channel->tty_port);
}
spin_unlock(&channel->lock);
}
static void wbu_tty_handler_rx(struct wbu_desc *wbuart)
{
struct wbu_channel *channel = &wbuart->channel;
int max_count = MAX_NBR_OF_BYTES_PER_IRQ;
if (!(wbu_read_reg(wbuart, UART_REG_SR) & UART_SR_RX_RDY))
return;
do {
u8 c = (wbu_read_reg(wbuart, UART_REG_RDR) & 0xFF);
tty_insert_flip_char(&channel->tty_port, c, TTY_NORMAL);
} while ((wbu_read_reg(wbuart, UART_REG_SR) & UART_SR_RX_RDY) &&
(--max_count > 0));
tty_flip_buffer_push(&channel->tty_port);
}
static irqreturn_t wbu_tty_handler(int irq, void *arg)
{
struct wbu_desc *wbuart = arg;
if (!(wbu_read_reg(wbuart, UART_REG_SR) & UART_SR_RX_RDY) &&
wbuart->channel.nb_bytes == 0)
return IRQ_NONE;
wbu_tty_handler_rx(wbuart);
wbu_tty_handler_tx(wbuart);
return IRQ_HANDLED;
}
static void wbu_channel_init(struct wbu_channel *channel)
{
spin_lock_init(&channel->lock);
channel->open_count = 0U;
channel->nb_bytes = 0U;
channel->ptr_read = 0U;
channel->ptr_write = 0U;
}
static int wbu_tty_port_init(struct platform_device *pdev)
{
struct wbu_desc *wbuart = platform_get_drvdata(pdev);
struct wbu_channel *channel = &wbuart->channel;
struct device *tty_dev;
wbu_channel_init(channel);
tty_port_init(&(channel->tty_port));
tty_port_alloc_xmit_buf(&channel->tty_port);
channel->tty_port.ops = &wbu_port_ops;
tty_dev = tty_port_register_device(&(channel->tty_port),
wbuart->tty_driver,
0,
&(pdev->dev));
if (IS_ERR_OR_NULL(tty_dev)) {
tty_port_put(&channel->tty_port);
return PTR_ERR(tty_dev);
}
return 0;
}
static void wbu_tty_port_exit(struct platform_device *pdev)
{
struct wbu_desc *wbuart = platform_get_drvdata(pdev);
struct wbu_channel *channel = &wbuart->channel;
tty_unregister_device(wbuart->tty_driver, 0);
tty_port_free_xmit_buf(&channel->tty_port);
tty_port_destroy(&channel->tty_port);
}
static int wbu_tty_open(struct tty_struct *tty, struct file *file)
{
struct wbu_desc *wbuart = dev_get_drvdata(tty->dev->parent);
struct wbu_channel *channel = &wbuart->channel;
channel->open_count++;
if (channel->open_count > 1)
return -EBUSY;
return tty_port_open(&channel->tty_port, tty, file);
}
static void wbu_tty_close(struct tty_struct *tty, struct file *file)
{
struct wbu_desc *wbuart = dev_get_drvdata(tty->dev->parent);
struct wbu_channel *channel = &wbuart->channel;
channel->open_count--;
if (channel->open_count == 0)
tty_port_close(&channel->tty_port, tty, file);
}
static int wbu_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
int buf_pos = 0;
struct wbu_desc *wbuart = dev_get_drvdata(tty->dev->parent);
struct wbu_channel *channel = &wbuart->channel;
unsigned long flags;
spin_lock_irqsave(&channel->lock, flags);
while (count > 0 && channel->nb_bytes < PAGE_SIZE) {
channel->tty_port.xmit_buf[channel->ptr_write] = buf[buf_pos++];
channel->ptr_write = (channel->ptr_write + 1) % PAGE_SIZE;
channel->nb_bytes++;
count--;
}
spin_unlock_irqrestore(&channel->lock, flags);
if (channel->nb_bytes > 0)
wbu_enable_tx_interrupts(wbuart);
return buf_pos;
}
#if KERNEL_VERSION(5, 14, 0) <= LINUX_VERSION_CODE
static unsigned int wbu_tty_write_room(struct tty_struct *tty)
#else
static int wbu_tty_write_room(struct tty_struct *tty)
#endif
{
struct wbu_desc *wbuart = dev_get_drvdata(tty->dev->parent);
struct wbu_channel *channel = &wbuart->channel;
return (PAGE_SIZE - channel->nb_bytes);
}
#if KERNEL_VERSION(5, 14, 0) <= LINUX_VERSION_CODE
static unsigned int wbu_tty_chars_in_buffer(struct tty_struct *tty)
#else
static int wbu_tty_chars_in_buffer(struct tty_struct *tty)
#endif
{
struct wbu_desc *wbuart = dev_get_drvdata(tty->dev->parent);
struct wbu_channel *channel = &wbuart->channel;
return channel->nb_bytes;
}
const struct tty_operations wbu_tty_ops = {
.open = wbu_tty_open,
.close = wbu_tty_close,
.write = wbu_tty_write,
.write_room = wbu_tty_write_room,
.chars_in_buffer = wbu_tty_chars_in_buffer
};
static int wbu_tty_driver_init(struct tty_driver *tty_driver,
struct wb_uart_platform_data *wbu_pd)
{
tty_driver->owner = THIS_MODULE;
tty_driver->driver_name = kasprintf(GFP_KERNEL, "wbu-%s-tty",
wbu_pd->wb_uart_name);
tty_driver->name = kasprintf(GFP_KERNEL, "ttywbu-%s-",
wbu_pd->wb_uart_name);
if (!tty_driver->driver_name || !tty_driver->name)
return -ENOMEM;
tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
tty_driver->subtype = SERIAL_TYPE_NORMAL;
tty_driver->flags = TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV |
TTY_DRIVER_RESET_TERMIOS;
tty_driver->init_termios = tty_std_termios;
tty_driver->init_termios.c_iflag = IGNBRK | IGNPAR | IXANY;
tty_driver->init_termios.c_oflag = 0;
tty_driver->init_termios.c_cflag = CS8 | CREAD | CLOCAL;
tty_driver->init_termios.c_lflag = 0;
tty_set_operations(tty_driver, &wbu_tty_ops);
return 0;
}
static int wbu_probe(struct platform_device *pdev)
{
int err = 0;
struct wbu_desc *wbuart;
struct tty_driver *tty_driver;
struct resource *r;
struct wb_uart_platform_data *wbu_pd;
if (pdev->dev.platform_data != NULL)
wbu_pd = (struct wb_uart_platform_data *) pdev->dev.platform_data;
else
return -ENXIO;
wbuart = devm_kzalloc(&pdev->dev, sizeof(struct wbu_desc), GFP_KERNEL);
if (!wbuart)
return -ENOMEM;
platform_set_drvdata(pdev, wbuart);
r = platform_get_resource(pdev, IORESOURCE_MEM, wbu_MEM_BASE);
if (!r) {
dev_err(&pdev->dev,
"wb uart need base address\n");
return -ENXIO;
}
wbuart->base_addr = devm_ioremap_resource(&pdev->dev, r);
wbu_memops_detect(pdev);
err = wbu_check_type(wbuart);
if (err < 0) {
dev_err(&(pdev->dev),
"wb uart driver supports only physical uart\n");
return err;
}
tty_driver = tty_alloc_driver(1, 0);
if (IS_ERR(tty_driver))
return PTR_ERR(tty_driver);
err = wbu_tty_driver_init(tty_driver, wbu_pd);
if (err < 0)
goto err_tty;
err = tty_register_driver(tty_driver);
if (err < 0)
goto err_tty;
wbuart->tty_driver = tty_driver;
err = wbu_tty_port_init(pdev);
if (err < 0)
goto err_port;
r = platform_get_resource(pdev, IORESOURCE_IRQ, wbu_IRQ);
if (!r) {
dev_err(&(pdev->dev),
"disable console: invalid interrupt source\n");
err = -ENXIO;
goto err_irq;
}
err = request_any_context_irq(r->start, wbu_tty_handler, 0,
r->name, wbuart);
if (err < 0) {
dev_err(&(pdev->dev),
"Cannot request IRQ %lld\n",
r->start);
goto err_irq;
}
dev_info(&pdev->dev, "%s: tty name: %s\n",
__func__, tty_driver->name);
return 0;
err_irq:
err_port:
wbu_tty_port_exit(pdev);
tty_unregister_driver(tty_driver);
err_tty:
kfree(tty_driver->driver_name);
kfree(tty_driver->name);
tty_driver_kref_put(tty_driver);
return err;
}
static int wbu_remove(struct platform_device *pdev)
{
struct wbu_desc *wbuart = platform_get_drvdata(pdev);
if (!wbuart->tty_driver)
return 0;
free_irq(platform_get_irq(pdev, wbu_IRQ), wbuart);
wbu_tty_port_exit(pdev);
tty_unregister_driver(wbuart->tty_driver);
kfree(wbuart->tty_driver->driver_name);
kfree(wbuart->tty_driver->name);
tty_driver_kref_put(wbuart->tty_driver);
return 0;
}
static const struct platform_device_id wbu_id_table[] = {
{
.name = "wb-uart",
},
{ .name = "" }, /* last */
};
static struct platform_driver wbu_driver = {
.driver = {
.name = "wb-uart",
.owner = THIS_MODULE,
},
.id_table = wbu_id_table,
.probe = wbu_probe,
.remove = wbu_remove,
};
module_platform_driver(wbu_driver);
MODULE_AUTHOR("Piotr Klasa <piotr.klasa@cern.ch>");
MODULE_DESCRIPTION("Wishbone Simple UART CERN Linux Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(GIT_VERSION);
MODULE_DEVICE_TABLE(platform, wbu_id_table);
/* SPDX-License-Identifier: GPL-2.0-or-later
* SPDX-FileCopyrightText: 2024 CERN (home.cern)
*/
#ifndef __WB_UART_PDATA_H__
#define __WB_UART_PDATA_H__
#include <linux/bitops.h>
#define WB_UART_NAME_MAX_LEN 32
#define WB_UART_BIG_ENDIAN BIT(0)
struct wb_uart_platform_data {
unsigned long flags;
char wb_uart_name[WB_UART_NAME_MAX_LEN];
};
#endif
action = "simulation"
sim_tool = "ghdl"
target = "xilinx"
syn_device = "xc6slx45t"
sim_top = "gc_argb_led_drv_tb"
files = [
"gc_argb_led_drv_tb.vhd",
]
modules = {
"local" : [
"../../../",
],
}
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- Project : General Cores Collection library
--------------------------------------------------------------------------------
--
-- unit name: gc_argb_led_drv
--
-- description: Driver for argb (or intelligent) led like ws2812b
--
--------------------------------------------------------------------------------
-- Copyright CERN 2024
--------------------------------------------------------------------------------
-- 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_argb_led_drv_tb is
end;
architecture arch of gc_argb_led_drv_tb is
constant C_CLK_FREQ : natural := 62_500_000;
signal clk : std_logic := '0';
signal rst_n : std_logic := '0';
signal b_g : std_logic_vector(7 downto 0);
signal b_r : std_logic_vector(7 downto 0);
signal b_b : std_logic_vector(7 downto 0);
signal valid : std_logic;
signal dout : std_logic;
signal ready : std_logic;
signal res : std_logic;
begin
DUT: entity work.gc_argb_led_drv
generic map (
g_clk_freq => C_clk_freq
)
port map (
clk_i => clk,
rst_n_i => rst_n,
g_i => b_g,
r_i => b_r,
b_i => b_b,
valid_i => valid,
dout_o => dout,
ready_o => ready,
res_o => res
);
process
begin
clk <= not clk;
wait for (1_000_000_000 / C_CLK_FREQ / 2) * 1 ns;
end process;
process
begin
wait until rising_edge(clk);
rst_n <= '1';
wait;
end process;
process
begin
valid <= '0';
loop
wait until rising_edge(clk);
exit when ready = '1';
end loop;
b_g <= x"80";
b_r <= x"7f";
b_b <= x"c8";
valid <= '1';
wait until rising_edge(clk);
valid <= '0';
wait;
end process;
end arch;
\ No newline at end of file
# 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;
......@@ -17,6 +17,10 @@
`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
......
# Script to generate the sourceid_<project>_pkg.vhd file
# Script to generate the HDL sourceid information for a given project
# Local parameter: project
# 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.
with open("sourceid_{}_pkg.vhd".format(project), "w") as f:
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
......@@ -39,16 +68,26 @@ with open("sourceid_{}_pkg.vhd".format(project), "w") as f:
# 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("\n")
f.write("library ieee;\n")
f.write("use ieee.std_logic_1164.all;\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("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))
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 || ORIG_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