-
Notifications
You must be signed in to change notification settings - Fork 50
Raw HDL Insertion
The goal of this feature is to approximate the functionality of gcc's __asm__()
function.
__asm__()
is used to directly describe cpu architecture specific assembler instructions (as opposed to being compiled from higher level C language). Similarly __vhdl__()
allows arbitrary VHDL to be used as PipelineC functions/modules.
uint64_t main(uint64_t x, uint64_t y)
{
__vhdl__("\
-- Arch declarations go here \n\
begin \n\
-- The arch body, processes, assignments, etc go here \n\
return_output <= x + y; \n\
");
}
The above PipelineC produces exactly the below VHDL file.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.c_structs_pkg.all;
entity main_0CLK_d751 is
port(
clk : in std_logic;
x : in unsigned(63 downto 0);
y : in unsigned(63 downto 0);
return_output : out unsigned(63 downto 0));
end main_0CLK_d751;
architecture arch of main_0CLK_d751 is
-- Arch declarations go here
begin
-- The arch body, processes, assignments, etc go here
return_output <= x + y;
end arch;
Functions that use __vhdl__()
are treated as stateful functions and will not be automatically pipelined.
Alot of hacky stuff could be done this way - however, the plan to to still have as much as possible written in PipelineC and abstracted/generated for you.
One primary use for __vhdl__()
is to instantiate existing IP. The below example instantiates an AXIS width converter module generated from Xilinx's IP catalog.
typedef struct axis32_to_axis8_t
{
axis8_t axis_out;
uint1_t axis_in_ready;
}axis32_to_axis8_t;
#pragma FUNC_BLACKBOX axis32_to_axis8
axis32_to_axis8_t axis32_to_axis8(axis32_t axis_in, uint1_t axis_out_ready)
{
__vhdl__("\n\
COMPONENT axis_dwidth_converter_4_to_1 \n\
PORT ( \n\
aclk : IN STD_LOGIC; \n\
aresetn : IN STD_LOGIC; \n\
s_axis_tvalid : IN STD_LOGIC; \n\
s_axis_tready : OUT STD_LOGIC; \n\
s_axis_tdata : IN STD_LOGIC_VECTOR(31 DOWNTO 0); \n\
s_axis_tkeep : IN STD_LOGIC_VECTOR(3 DOWNTO 0); \n\
s_axis_tlast : IN STD_LOGIC; \n\
m_axis_tvalid : OUT STD_LOGIC; \n\
m_axis_tready : IN STD_LOGIC; \n\
m_axis_tdata : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); \n\
m_axis_tkeep : OUT STD_LOGIC_VECTOR(0 DOWNTO 0); \n\
m_axis_tlast : OUT STD_LOGIC \n\
); \n\
END COMPONENT; \n\
\n\
begin \n\
\n\
inst : axis_dwidth_converter_4_to_1 \n\
PORT MAP ( \n\
aclk => clk, \n\
aresetn => '1', \n\
s_axis_tvalid => axis_in.valid(0), \n\
s_axis_tready => return_output.axis_in_ready(0), \n\
s_axis_tdata => std_logic_vector(axis_in.data), \n\
s_axis_tkeep => std_logic_vector(axis_in.keep), \n\
s_axis_tlast => axis_in.last(0), \n\
m_axis_tvalid => return_output.axis_out.valid(0), \n\
m_axis_tready => axis_out_ready(0), \n\
unsigned(m_axis_tdata) => return_output.axis_out.data, \n\
--unsigned(m_axis_tkeep) => return_output.axis_out.keep, \n\
m_axis_tlast => return_output.axis_out.last(0) \n\
); \n\
");
}
The above function uses a generated axis_dwidth_converter_4_to_1
component. This IP is user/project specific and is not known by the PipelineC tool during automated synthesis runs (yet). For this reason the function is marked as a FUNC_BLACKBOX
whose implementation is ignored/not synthesized by the PipelineC tool (only synthesized during user bitstream generation).