Verilog
A clocked module, a testbench and an Icarus makefile — the same model your software target runs, in gates.
icore_defs.vh<name>.v<name>_tb.vMakefile (Icarus)
one clk edge = one sample
Icarus Verilog (iverilog, vvp)
Q16.16 fixed point
306 of 308
The diagram becomes a module driven by clk: one edge, one sample. The
generated icore_defs.vh carries the shared widths and fixed-point definitions.
Signals are Q16.16 fixed point, so the residual against the simulation is bounded by
the 1.5e-5 quantum rather than by the generator. The verifier builds the testbench with
Icarus Verilog and runs it with vvp.
Because the same diagram also exports to C or Rust, the usual FPGA workflow — prove the algorithm in software, then move it to fabric — stays one model rather than two implementations to keep in step.
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.v
`include "icore_defs.vh"
module DPT_Feedback_Discrete (
input clk,
input rst,
input [1*`ICORE_WIDTH-1:0] blk2_gain,
input [1*`ICORE_WIDTH-1:0] in_sig0,
output [1*`ICORE_WIDTH-1:0] sig0,
output [1*`ICORE_WIDTH-1:0] sig1,
output [1*`ICORE_WIDTH-1:0] sig2,
output [1*`ICORE_WIDTH-1:0] sig3,
output [1*`ICORE_WIDTH-1:0] sig4
);
function real to_real;
input signed [`ICORE_WIDTH-1:0] v;
begin to_real = $itor(v) / (2.0 ** `ICORE_FRAC_BITS); end
endfunction
function signed [`ICORE_WIDTH-1:0] to_fx;
input real v;
begin to_fx = $rtoi(v * (2.0 ** `ICORE_FRAC_BITS) + (v >= 0.0 ? 0.5 : -0.5)); end
endfunction
function integer fx_to_int;
input signed [`ICORE_WIDTH-1:0] v;
begin fx_to_int = v >>> `ICORE_FRAC_BITS; end
endfunction
reg [1*`ICORE_WIDTH-1:0] r_sig0 = 0;
reg [1*`ICORE_WIDTH-1:0] r_sig1 = 0;
reg [1*`ICORE_WIDTH-1:0] r_sig2 = 0;
reg [1*`ICORE_WIDTH-1:0] r_sig3 = 0;
reg [1*`ICORE_WIDTH-1:0] r_sig4 = 0;
assign sig0 = r_sig0;
assign sig1 = r_sig1;
assign sig2 = r_sig2;
assign sig3 = r_sig3;
assign sig4 = r_sig4;
reg signed [`ICORE_WIDTH-1:0] uh_blk3 [0:0][0:0];
reg signed [`ICORE_WIDTH-1:0] yh_blk3 [0:0][0:0];
always @(posedge clk) begin : exec
reg [1*`ICORE_WIDTH-1:0] w_sig0;
reg [1*`ICORE_WIDTH-1:0] w_sig1;
reg [1*`ICORE_WIDTH-1:0] w_sig2;
reg [1*`ICORE_WIDTH-1:0] w_sig3;
reg [1*`ICORE_WIDTH-1:0] w_sig4;
reg signed [2*`ICORE_WIDTH-1:0] acc;
if (rst) begin
r_sig0 <= 0;
r_sig1 <= 0;
r_sig2 <= 0;
r_sig3 <= 0;
r_sig4 <= 0;
uh_blk3[0][0] <= 0;
yh_blk3[0][0] <= 0;
end else begin
w_sig0 = r_sig0;
w_sig1 = r_sig1;
w_sig2 = r_sig2;
w_sig3 = r_sig3;
w_sig4 = r_sig4;
acc = 0;
// blk0: ICore Blocks/Home/DPT_Feedback_Discrete/In1
w_sig0 = in_sig0;
// blk1: ICore Blocks/Home/DPT_Feedback_Discrete/Error
w_sig1[0*`ICORE_WIDTH +: `ICORE_WIDTH] = $signed(w_sig0[0*`ICORE_WIDTH +: `ICORE_WIDTH]) - $signed(w_sig3[0*`ICORE_WIDTH +: `ICORE_WIDTH]);
// blk2: ICore Blocks/Home/DPT_Feedback_Discrete/Ctrl_Gain
acc = $signed(w_sig1[0*`ICORE_WIDTH +: `ICORE_WIDTH]) * $signed(blk2_gain[0*`ICORE_WIDTH +: `ICORE_WIDTH]);
w_sig2[0*`ICORE_WIDTH +: `ICORE_WIDTH] = acc >>> `ICORE_FRAC_BITS;
// blk3: ICore Blocks/Home/DPT_Feedback_Discrete/Plant
acc = 0;
acc = acc + $signed(to_fx(0)) * $signed(w_sig2[0*`ICORE_WIDTH +: `ICORE_WIDTH]);
acc = acc + $signed(to_fx(0.40000000000000002)) * $signed(uh_blk3[0][0]);
acc = acc - $signed(to_fx(-0.59999999999999998)) * $signed(yh_blk3[0][0]);
w_sig3[0*`ICORE_WIDTH +: `ICORE_WIDTH] = acc >>> `ICORE_FRAC_BITS;
uh_blk3[0][0] <= w_sig2[0*`ICORE_WIDTH +: `ICORE_WIDTH];
yh_blk3[0][0] <= acc >>> `ICORE_FRAC_BITS;
// blk4: ICore Blocks/Home/DPT_Feedback_Discrete/Out1
w_sig4 = w_sig3;
r_sig0 <= w_sig0;
r_sig1 <= w_sig1;
r_sig2 <= w_sig2;
r_sig3 <= w_sig3;
r_sig4 <= w_sig4;
end
end
endmodule
The same clocked pass in Verilog: each signal is a packed bus, the blocking working copies
(w_sig*) run the ordered pass, and the non-blocking commits at the end make one
edge one sample. The plant multiplies into a double-width acc and shifts by
ICORE_FRAC_BITS — that shift is where Q16.16 rounding actually happens, and where
an HDL residual against the simulation comes from.
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.