VHDL
A synthesizable entity where one rising clock edge is one sample — plus a testbench and a GHDL makefile.
icore_pkg.vhd<name>.vhd<name>_tb.vhdMakefile (GHDL)
one rising clk edge = one sample
GHDL
Q16.16 fixed point
306 of 308
The model becomes an entity clocked at your sample rate: raise clk, and
the whole diagram has advanced one step. The generated icore_pkg.vhd holds the
shared types and the fixed-point helpers the entity uses.
Fixed point, and what it costs
Every signal is carried in Q16.16 — sixteen integer bits including sign, sixteen fractional. That is a range of about ±32768 and a step of 1.5e-5. Unlike the software targets, whose residual against the simulation sits around 1e-11 %, an HDL residual is set by that quantum: the arithmetic is not wrong, it is coarser. Coefficients matter more than you might expect — rounding a transfer function's coefficients can move its DC gain by more than the quantum alone suggests, which is worth checking before you blame the generator.
The verifier builds and runs the testbench under GHDL and compares it against the simulation exactly as it does for the software targets.
What the export looks like
Every target page shows the same model, so the ten are directly comparable:
an input, an error junction, a gain of 1.8, a discrete plant
0.4z⁻¹ / (1 − 0.6z⁻¹), an output — and the plant's
output fed back into the junction. Five blocks, in a diagram the
export-verification suite calls DPT_Feedback_Discrete — which is where the names
in the file come from. Below is what Deploy writes for this target, with only the
file's header banner removed.
DPT_Feedback_Discrete.vhd
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.fixed_pkg.all; use ieee.fixed_float_types.all; use ieee.math_real.all; -- sin/cos for simulation-only source blocks library work; use work.icore_pkg.all; entity DPT_Feedback_Discrete is port ( clk : in std_logic; -- one tick == one sample period rst : in std_logic; blk2_gain : in Fx_matrix(0 to 0, 0 to 0); in_sig0 : in Fx_matrix(0 to 0, 0 to 0); sig0 : out Fx_matrix(0 to 0, 0 to 0); sig1 : out Fx_matrix(0 to 0, 0 to 0); sig2 : out Fx_matrix(0 to 0, 0 to 0); sig3 : out Fx_matrix(0 to 0, 0 to 0); sig4 : out Fx_matrix(0 to 0, 0 to 0) ); end entity DPT_Feedback_Discrete; architecture rtl of DPT_Feedback_Discrete is type Signals_t is record sig0 : Fx_matrix(0 to 0, 0 to 0); sig1 : Fx_matrix(0 to 0, 0 to 0); sig2 : Fx_matrix(0 to 0, 0 to 0); sig3 : Fx_matrix(0 to 0, 0 to 0); sig4 : Fx_matrix(0 to 0, 0 to 0); end record; constant SIGNALS_ZERO : Signals_t := ( sig0 => (others => (others => to_fx(0.0))), sig1 => (others => (others => to_fx(0.0))), sig2 => (others => (others => to_fx(0.0))), sig3 => (others => (others => to_fx(0.0))), sig4 => (others => (others => to_fx(0.0))) ); signal sig : Signals_t := SIGNALS_ZERO; signal uh_blk3 : Fx_matrix(0 to 0, 0 to 0) := (others => (others => to_fx(0.0))); signal yh_blk3 : Fx_matrix(0 to 0, 0 to 0) := (others => (others => to_fx(0.0))); begin -- Observable signal outputs sig0 <= sig.sig0; sig1 <= sig.sig1; sig2 <= sig.sig2; sig3 <= sig.sig3; sig4 <= sig.sig4; exec : process(clk) variable s : Signals_t; variable acc : Fx; variable acc2 : Fx; variable iacc : integer; begin if rising_edge(clk) then if rst = '1' then s := SIGNALS_ZERO; uh_blk3 <= (others => (others => to_fx(0.0))); yh_blk3 <= (others => (others => to_fx(0.0))); else s := sig; -- seed from last committed state acc := to_fx(0.0); acc2 := to_fx(0.0); iacc := 0; -- blk0: ICore Blocks/Home/DPT_Feedback_Discrete/In1 s.sig0 := in_sig0; -- blk1: ICore Blocks/Home/DPT_Feedback_Discrete/Error for i in 0 to 0 loop for j in 0 to 0 loop s.sig1(i, j) := resize(s.sig0(i, j) - s.sig3(i, j), s.sig1(i, j)); end loop; end loop; -- blk2: ICore Blocks/Home/DPT_Feedback_Discrete/Ctrl_Gain for i in 0 to 0 loop for j in 0 to 0 loop s.sig2(i, j) := resize(s.sig1(i, j) * blk2_gain(0, 0), s.sig2(i, j)); end loop; end loop; -- blk3: ICore Blocks/Home/DPT_Feedback_Discrete/Plant acc := to_fx(0.0); acc := resize(acc + to_fx(0.0) * s.sig2(0, 0), acc); acc := resize(acc + to_fx(0.40000000000000002) * uh_blk3(0, 0), acc); acc := resize(acc - to_fx(-0.59999999999999998) * yh_blk3(0, 0), acc); s.sig3(0, 0) := acc; uh_blk3(0, 0) <= s.sig2(0, 0); yh_blk3(0, 0) <= acc; -- blk4: ICore Blocks/Home/DPT_Feedback_Discrete/Out1 s.sig4 := s.sig3; end if; sig <= s; -- commit end if; end process; end architecture rtl;
The tunable parameters and the external input are input ports, the signals are output
ports, and the entire ordered pass sits in one clocked process: it seeds a variable from the
last committed state, runs the five blocks, and commits once at the end — so one rising edge is
exactly one sample, and the feedback path reads the previous commit. Values are Fx,
the Q16.16 subtype from the generated icore_pkg.vhd, and every arithmetic result
is resized back into its signal.
How it is checked
Every one of the ten targets is verifiable, and this one is no exception: the export is compiled with the toolchain above, run across the simulation window, and compared against the solver sample by sample. Software targets pass at around 1e-11 % against a 0.1 % tolerance; the HDL targets are bounded by their fixed-point quantum instead. See verification.
See also: Code export · Multi-target, multi-rate deploy
See it run on your own model.
Download the application from the customer portal, or read the documentation first — the manual, every block with its measured response, and the full command reference are public.