# Moku Library
The Moku library is available to provide some useful types, functions and components to use in your designs. These design elements are defined in the Support package, and can be used in your design like this:
library Moku;
use Moku.Support.clip;
architecture Behavioural of CustomWrapper is
signal X : signed(31 downto 0);
begin
-- Multiply results in bit growth to 32 bits
X <= InputA * InputB;
-- Use library function to "clip" the value to 16 bits
OutputA <= clip(X, 15, 0);
end architecture;
# Moku.Support Functions
# sum_no_overflow
sum A and B and clip the result to the range of A instead of wrapping
function sum_no_overflow(A : signed; B : signed) return signed;
function sum_no_overflow(A : signed; B : integer) return signed;
function sum_no_overflow(A : unsigned; B : signed) return unsigned;
function sum_no_overflow(A : unsigned; B : integer) return unsigned;
# clip
Clip A from NewLeft to NewRight and saturate the result if original value exceeds the resulting range
function clip(A : signed; NewLeft, NewRight : integer) return signed;
# clip_val
Clip A between MinVal and MaxVal (inclusive) without resizing the vector.
function clip_val(A : signed; MinVal, MaxVal : integer) return signed;
# or_reduce
Return the result of or'ing all bits in X
function or_reduce(X: std_logic_vector) return std_logic;
# Moku.Support Components
# ScaleOffset
ScaleOffset
and ScaleOffset2
are wrappers for a DSP block to compute Z = X * Scale + Offset
and Z = (X + Y) * Scale + Offset
respectively.
Scale
can be up to 18 bits long and covers the range -2^NORMAL_SHIFT -> 2^NORMAL_SHIFT
; i.e., ±1
with the default value of NORMAL_SHIFT=0
. This means that if you need this block to scale up, then NORMAL_SHIFT
must be set greater than 0; for example, if you need to scale up by a factor of 10x then NORMAL_SHIFT=4
gives a range of ±16
then Scale=0.625
, or 0x4FFF
in signed 16-bits, gives the required scale overall.
OFFSET_SHIFT
gives the relative shift between the Offset
field and the X
argument. This is useful to get the Offset
field to the same order as the X * Scale
value.
ROUNDING
is on by default. Set to 0
to floor the result.
The calculation can be registered at different locations to meet timing constraints. By default, the calculation is registered in the middle only, for a one clock cycle latency. This can be disabled by setting MID_REG=0
. On the other hand, long timing paths to and from the block can be registered right at the input and/or output (IN_REG=1
and/or OUT_REG=1
) if required. Note that IN_REG
and MID_REG
are mutually exclusive and trying to set both at once will fail synthesis.
-- Z = X * Scale + Offset
component ScaleOffset
generic (
NORMAL_SHIFT : integer := 0;
OFFSET_SHIFT : integer := 0;
ROUNDING : boolean := true;
IN_REG : integer range 0 to 1 := 0;
OUT_REG : integer range 0 to 1 := 0;
MID_REG : integer range 0 to 1 := 1
);
port (
Clk : in std_logic;
Reset : in std_logic;
X : in signed;
Scale : in signed;
Offset : in signed;
Z : out signed;
Valid : in std_logic;
OutValid : out std_logic
);
end component;
-- Z = (X + Y) * Scale + Offset
component ScaleOffset2
generic (
NORMAL_SHIFT : integer := 0;
OFFSET_SHIFT : integer := 0;
ROUNDING : boolean := true;
IN_REG : integer range 0 to 1 := 0;
OUT_REG : integer range 0 to 1 := 0;
MID_REG : integer range 0 to 1 := 1
);
port (
Clk : in std_logic;
Reset : in std_logic;
X : in signed;
Y : in signed;
Scale : in signed;
Offset : in signed;
Z : out signed;
Valid : in std_logic;
OutValid : out std_logic
);
end component;
# Interpolator
Linearly interpolate between A and B a distance of N N is normalized between 0 and 1
component Interpolator
generic (
OUT_REG : integer range 0 to 1 := 0 -- optional output register
);
port (
Clk : in std_logic;
Reset : in std_logic;
A : in signed; --Point A
B : in signed; --Point B
N : in unsigned; --Distance from A to B to resolve Z
Z : out signed --Result
);
end component;
# Example
library Moku;
use Moku.Support.Interpolator;
architecture Behavioural of CustomWrapper is
signal A, B : signed(15 downto 0);
signal N : unsigned(7 downto 0);
signal Z : signed(15 downto 0);
begin
-- These can be any dynamic signals
A <= to_signed(0, 16);
B <= to_signed(1000, 16);
-- N is normalized to N'range, so 128 ~= 128 / 2^8 = 0.5
N <= to_unsigned(128, 8);
INTERP0: Interpolator
port map (
Clk => Clk,
Reset => Reset,
A => A,
B => B,
N => N,
Z => Z
);
-- Z = (B - A) * 0.5 + A = 500
end architecture;