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 coder 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.
hdl.BlackBox
System objectCreate 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.BlackBox
properties
in the System object.
Define the step
method such that
its simulation behavior matches the custom HDL code.
Alternatively, the System object you define can inherit
from both hdl.BlackBox
and the matlab.system.mixin.Nondirect
class,
and you can define output
and update
methods
to match the custom HDL code simulation behavior.
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 = 1 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 = 0; end function myout = stepImpl(obj, myin) % Implement algorithm. Calculate y as a function of % input u and state. if (myin > obj.Threshold) obj.Count = obj.Count + 1; end myout = obj.Count; end end end
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.
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.
clear topLevelDesign y1 = zeros(1,200); y2 = zeros(1,200); for ii=1:200 [y1(ii), y2(ii)] = topLevelDesign(ii); end plot([1:200], y2)
Generate HDL code using the design function and test bench code.
When you use the generated HDL code, include your custom HDL code with the generated HDL files.
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 foo IS PORT( clk : IN std_logic; reset : IN std_logic; clk_enable : IN std_logic; u : IN std_logic_vector(7 DOWNTO 0); -- uint8 ce_out : OUT std_logic; y1 : OUT real; -- double y2 : OUT std_logic_vector(7 DOWNTO 0) -- uint8 ); END foo; ARCHITECTURE rtl OF foo 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); -- uint8 myout : OUT real -- double ); END COMPONENT; COMPONENT DualPortRAM_Inst0 PORT( clk : IN std_logic; enb : IN std_logic; wr_din : IN std_logic_vector(7 DOWNTO 0); -- uint8 wr_addr : IN std_logic_vector(7 DOWNTO 0); -- uint8 wr_en : IN std_logic; rd_addr : IN std_logic_vector(7 DOWNTO 0); -- uint8 wr_dout : OUT std_logic_vector(7 DOWNTO 0); -- uint8 rd_dout : OUT std_logic_vector(7 DOWNTO 0) -- uint8 ); END COMPONENT; -- Component Configuration Statements FOR ALL : CounterBbox USE ENTITY work.CounterBbox(rtl); FOR ALL : DualPortRAM_Inst0 USE ENTITY work.DualPortRAM_Inst0(rtl); -- Signals SIGNAL enb : std_logic; SIGNAL varargout_1 : real := 0.0; -- double 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 u_CounterBbox : CounterBbox PORT MAP( clk => clk, clk_enable => enb, reset => reset, myin => u, -- uint8 myout => varargout_1 -- double ); u_DualPortRAM_Inst0 : DualPortRAM_Inst0 PORT MAP( clk => clk, enb => enb, wr_din => std_logic_vector(tmp), -- uint8 wr_addr => std_logic_vector(tmp_1), -- uint8 wr_en => tmp_2, rd_addr => std_logic_vector(tmp_3), -- uint8 wr_dout => varargout_1_1, -- uint8 rd_dout => varargout_2 -- uint8 ); enb <= clk_enable; y1 <= varargout_1; --y2 = u; tmp <= to_unsigned(2#00001010#, 8); tmp_1 <= to_unsigned(2#00000000#, 8); tmp_2 <= '1'; tmp_3 <= to_unsigned(2#00010100#, 8); ce_out <= clk_enable; y2 <= varargout_2; END rtl;
hdl.BlackBox
You cannot use hdl.BlackBox
to assign values
to a VHDL® generic
or Verilog® parameter
in
your custom HDL code.