Integrate Custom HDL Code Into MATLAB Design
hdl.BlackBox provides
a way to include custom HDL code, such as legacy or handwritten HDL
code, in a MATLAB® design intended for HDL code generation.
When you create a user-defined System object™ that inherits
from hdl.BlackBox, you specify a port interface and
simulation behavior that matches your custom HDL code.
HDL Coder™ simulates the design in MATLAB using the behavior you define in the System object. During code generation, instead of generating code for the simulation behavior, the code generator instantiates a module with the port interface you specify in the System object.
To use the generated HDL code in a larger system, you include the custom HDL source files with the rest of the generated code.
Define the hdl.BlackBox System object
Create a user-defined System object that inherits from
hdl.BlackBox.Configure the black box interface to match the port interface for your custom HDL code by setting
hdl.BlackBoxproperties in the System object.Define the
stepmethod such that its simulation behavior matches the custom HDL code.Alternatively, the System object you define can inherit from
hdl.BlackBoxclass, and you can defineoutputandupdatemethods to match the custom HDL code simulation behavior.
Example Code
For example, the following code defines a System object, CounterBbox, that inherits from hdl.BlackBox and represents custom HDL code for a counter that increments
until it reaches a threshold. The CounterBbox
reset and step methods model the custom HDL code
behavior.
classdef CounterBbox < hdl.BlackBox % derive from hdl.BlackBox class
%Counter: Count up to a threshold.
%
% This is an example of a discrete-time System object with state
% variables.
%
properties (Nontunable)
Threshold = fi(1, 0, 1, 0, hdlfimath)
end
properties (DiscreteState)
% Define discrete-time states.
Count
end
methods
function obj = CounterBbox(varargin)
% Support name-value pair arguments
setProperties(obj,nargin,varargin{:});
obj.NumInputs = 1; % define number of inputs
obj.NumOutputs = 1; % define number of inputs
end
end
methods (Access=protected)
% Define simulation behavior.
% For code generation, the coder uses your custom HDL code instead.
function resetImpl(obj)
% Specify initial values for DiscreteState properties
obj.Count = fi(0, 0, 8, 0, hdlfimath);
end
function myout = stepImpl(obj, myin)
% Implement algorithm. Calculate y as a function of
% input u and state.
if (myin > obj.Threshold)
obj.Count = fi(obj.Count + fi(1, 0, 1, 0, hdlfimath), 0, 8, 0, hdlfimath);
end
myout = fi(obj.Count, 0, 8, 0, hdlfimath);
end
end
endUse System object In MATLAB Design Function
After you define your System object, use it in the MATLAB design function by creating an instance and calling its step
method.
To generate code, you also need to create a test bench function that exercises the top-level design function.
Example Code
The following example code shows a top-level design function that creates an instance
of the CounterBbox and calls its step
method.
function [y1, y2] = topLevelDesign(u)
persistent mybboxObj myramObj
if isempty(mybboxObj)
mybboxObj = CounterBbox; % instantiate the black box
myramObj = hdl.RAM('RAMType', 'Dual port');
end
y1 = step(mybboxObj, u); % call the system object step method
[~, y2] = step(myramObj, uint8(10), uint8(0), true, uint8(20));The following example code shows a test bench function for the
topLevelDesign
function.
y1 = fi(zeros(1,200), 0, 8, 0, hdlfimath);
y2 = fi(zeros(1,200), 0, 8, 0, hdlfimath);
for ii=1:200
[y1(ii), y2(ii)] = topLevelDesign(fi(ii, 0, 8, 0, hdlfimath));
endGenerate HDL Code
Generate HDL code using the design function and test bench code.
hdlcfg = coder.config('hdl');
hdlcfg.TestBenchName = 'testBench';
codegen -config hdlcfg topLevelDesignWhen you use the generated HDL code, include your custom HDL code with the generated HDL files.
Example Code
In the following generated VHDL® code for the CounterBbox example, you can see that the
CounterBbox instance in the MATLAB code maps to an HDL component definition and instantiation, but HDL code is
not generated for the step method.
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
ENTITY topLevelDesign IS
PORT( clk : IN std_logic;
reset : IN std_logic;
clk_enable : IN std_logic;
u : IN std_logic_vector(7 DOWNTO 0); -- ufix8
ce_out : OUT std_logic;
y1 : OUT std_logic_vector(7 DOWNTO 0); -- ufix8
y2 : OUT std_logic_vector(7 DOWNTO 0) -- uint8
);
END topLevelDesign;
ARCHITECTURE rtl OF topLevelDesign IS
-- Component Declarations
COMPONENT CounterBbox
PORT( clk : IN std_logic;
clk_enable : IN std_logic;
reset : IN std_logic;
myin : IN std_logic_vector(7 DOWNTO 0); -- ufix8
myout : OUT std_logic_vector(7 DOWNTO 0) -- ufix8
);
END COMPONENT;
COMPONENT DualPortRAM_generic
GENERIC( AddrWidth : integer;
DataWidth : integer
);
PORT( clk : IN std_logic;
enb : IN std_logic;
wr_din : IN std_logic_vector(DataWidth - 1 DOWNTO 0); -- generic width
wr_addr : IN std_logic_vector(AddrWidth - 1 DOWNTO 0); -- generic width
wr_en : IN std_logic;
rd_addr : IN std_logic_vector(AddrWidth - 1 DOWNTO 0); -- generic width
wr_dout : OUT std_logic_vector(DataWidth - 1 DOWNTO 0); -- generic width
rd_dout : OUT std_logic_vector(DataWidth - 1 DOWNTO 0) -- generic width
);
END COMPONENT;
-- Component Configuration Statements
FOR ALL : CounterBbox
USE ENTITY work.CounterBbox(rtl);
FOR ALL : DualPortRAM_generic
USE ENTITY work.DualPortRAM_generic(rtl);
-- Signals
SIGNAL enb : std_logic;
SIGNAL varargout_1 : std_logic_vector(7 DOWNTO 0); -- ufix8
SIGNAL tmp : unsigned(7 DOWNTO 0); -- uint8
SIGNAL tmp_1 : unsigned(7 DOWNTO 0); -- uint8
SIGNAL tmp_2 : std_logic;
SIGNAL tmp_3 : unsigned(7 DOWNTO 0); -- uint8
SIGNAL varargout_1_1 : std_logic_vector(7 DOWNTO 0); -- ufix8
SIGNAL varargout_2 : std_logic_vector(7 DOWNTO 0); -- ufix8
BEGIN
-- instantiate the black box
u_CounterBbox : CounterBbox
PORT MAP( clk => clk,
clk_enable => enb,
reset => reset,
myin => u, -- ufix8
myout => varargout_1 -- ufix8
);
u_dualPortRam_generic : DualPortRAM_generic
GENERIC MAP( AddrWidth => 8,
DataWidth => 8
)
PORT MAP( clk => clk,
enb => enb,
wr_din => std_logic_vector(tmp),
wr_addr => std_logic_vector(tmp_1),
wr_en => tmp_2,
rd_addr => std_logic_vector(tmp_3),
wr_dout => varargout_1_1,
rd_dout => varargout_2
);
enb <= clk_enable;
-- call the system object step method
tmp <= to_unsigned(16#0A#, 8);
tmp_1 <= to_unsigned(16#00#, 8);
tmp_2 <= '1';
tmp_3 <= to_unsigned(16#14#, 8);
ce_out <= clk_enable;
y1 <= varargout_1;
y2 <= varargout_2;
END rtl;Limitations for hdl.BlackBox
You cannot use hdl.BlackBox to assign values to a
VHDL
generic, or Verilog® or SystemVerilog
parameter in your custom HDL code.