VHDL.vhd

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

HDL Verified with GHDL Q16.16 fixed point 749 of 806 blocks
DPT_Feedback_Discrete.vhd
✓ verified · 1 %
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;

What Deploy writes for the reference model below, with only the file's header banner removed. 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.

Export · Verify · Integrate

From the diagram to your VHDL build.

Deploy writes the folder, ICore checks it against the simulation, and your code calls it once per sample.

01 · ExportICore

Deploy writes

  • icore_pkg.vhd
  • <name>.vhd
  • <name>_tb.vhd
  • Makefile (GHDL)
→ code/<name>/
02 · VerifyICore

Built, run and compared

Built with GHDL, run across the simulation window and compared with the solver sample by sample, against a 1 % tolerance.

observed ≈1e-3 %
03 · IntegrateYour build

One call, one sample

Numbers are Q16.16 fixed point, and 749 of 806 library blocks export to VHDL.

one rising clk edge = one sample
With verification on, a failed comparison stops the export and says why, so a core that disagrees with the simulation never reaches your folder.
HDL target

Where VHDL fits.

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.

$ Code Engine → Code Export Verifier → Verify All
Target classToleranceObserved
Software · 7 languages0.1 %≈1e-11 %
HDL · Q16.161 %≈1e-3 %
VHDL carries every signal in Q16.16 - about ±32768 with a step of 1.5e-5 - so its residual is set by the number format, not by the generator. See verification.
The reference model

One model, ten targets.

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 and an output, with the plant's output fed back into the junction. The export-verification suite calls it DPT_Feedback_Discrete - which is where the names in the file come from.

DPT_Feedback_Discrete · 5 blocks
In1 Σ + − Error × 1.8 Ctrl_Gain 0.4z⁻¹ 1 − 0.6z⁻¹ Plant Out1 the previous sample, fed back
Get started

See it run on your own model.

Download the application from the customer portal, or read the documentation first - the manual, a page for every block, and the full command reference are public.