# Getting Started

These code snippets are fully self-contained examples, each of which can be built in Moku Cloud Compile and achieves some basic task.

# More Examples

Many more examples are available on Gitlab (opens new window).

# On This Page

# The Basic Component Structure

All Moku Cloud Compile top-level blocks are architectures of CustomWrapper.

library IEEE;
use IEEE.Std_Logic_1164.all;
use IEEE.Numeric_Std.all;

architecture Behavioural of CustomWrapper is
begin
    
end architecture;

# Control Registers

The Custom Wrapper has Inputs, Outputs and Control Registers. The input and output routing is determined in the Multi-instrument Mode (MiM) configuration screen. They can be connected to ADCs and DACs respectively, but can also be attached to other slots in order to pre- or post-process instrument data.

The control registers have 32-bit values that can be changed through the MCC instrument screen on the Moku: application. Here we interpret 16 bits of each of the first two control registers as a (signed) DC voltage to output from the MCC instrument. For example, if the MiM configuration routes the MCC slot outputs to the DACs, this is a simple programmable DC supply.

library IEEE;
use IEEE.Numeric_Std.all;

architecture Behavioural of CustomWrapper is
begin
    OutputA <= signed(Control1(15 downto 0));
    OutputB <= signed(Control2(15 downto 0));
end architecture;

Control register bits can also be used to enable and disable features.

architecture Behavioural of CustomWrapper is
begin
    OutputA <= InputA when Control1(0) = '1' else (others => '0');
    OutputB <= InputB when Control1(1) = '1' else (others => '0');
end architecture;

# Some arithmetic

Basic arithmetic is available in the VHDL language, but note that this is purely combinatorial so can run in to timing errors.

-- A very simple example, simply add two inputs and route to an output.
-- This is purely combinatorial
architecture Behavioural of CustomWrapper is
begin
    OutputA <= InputA + InputB;
    OutputB <= InputA - InputB;
end architecture;

# Instantiate a DSP

For more complex arithmetic, it's common to explicitly instantiate a DSP block in the FPGA. The Moku.Support.ScaleOffset entity conveniently packages a DSP block with all the settings configured to compute the common Z = X * Scale + Offset operation, with the output properly clipped to prevent under/overflow.

library IEEE;
use IEEE.Numeric_Std.all;

library Moku;
use Moku.Support.ScaleOffset;

-- Instatiate a DSP block using the ScaleOffset wrapper
architecture Behavioural of CustomWrapper is
begin
    -- Z = X * Scale + Offset
    -- Offset is units of bits, scale by default runs from -1 to 1 across whatever signal width is given
    -- Clips Z to min/max (prevents over/underflow)
    -- Includes rounding
    -- One Clock Cycle Delay
    DSP: ScaleOffset
        port map (
            Clk => Clk,
            Reset => Reset,
            X => InputA,
            Scale => signed(Control0(15 downto 0)),
            Offset => signed(Control1(15 downto 0)),
            Z => OutputA,
            Valid => '1',
            OutValid => open
        );

    -- If you want to change the range of the scale (e.g. multiply by more than 1), then set the
    -- NORMAL_SHIFT generic. This increases the range of Scale by 2^N, so NORMAL_SHIFT=4 means that
    -- the 16 bit scale here now covers the range -16 to 16.
    DSP: ScaleOffset
        generic map (
            NORMAL_SHIFT => 4
        )
        port map (
            Clk => Clk,
            Reset => Reset,
            X => InputB,
            Scale => signed(Control2(15 downto 0)),
            Offset => signed(Control3(15 downto 0)),
            Z => OutputB,
            Valid => '1',
            OutValid => open
        );
end architecture;

# Moku Library

The Moku Library contains many useful helper functions and components, like the ScaleOffset block used above. For example, the clip function clips a signal to a defined bit range, gracefully handling saturation.

library IEEE;
use IEEE.Numeric_Std.all;

library Moku;
use Moku.Support.clip;

architecture Behavioural of CustomWrapper is 
begin
    OutputA <= resize(clip(InputA, 8, 0), 16); 
end architecture;