VHDL

A synthesizable entity where one rising clock edge is one sample — plus a testbench and a GHDL makefile.

Deploy writes
  • icore_pkg.vhd
  • <name>.vhd
  • <name>_tb.vhd
  • Makefile (GHDL)
One call, one sample

one rising clk edge = one sample

Verified with

GHDL

Numbers

Q16.16 fixed point

Library blocks

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

Get started

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.