Tutorial_HDL_Black_Box - david-macmahon/wiki_convert_test GitHub Wiki
Tutorial 6: Introduction to Black Boxing HDL in your Simulink designs.
Author: Jack Hickish
Expected completion time: 1 hr
The graphical interface provided by Simulink can be a great way to visualize and program designs at a high level. However, there may be times when you would rather describe a particular processing block using a more traditional textual HDL, such as Verilog or VHDL. This may be because you have code that already exists in these languages, or simply because you are more comfortable developing in a text-based environment. Whatever the reason, embedding Verilog of VHDL modules in a Simulink design is extremely simple.
In this tutorial, we go through a simple example of embedding a Verilog-defined module in a Simulink design using the Xilinx "Black Box" block.
This tutorial is based on the information in Chapter 4 of the Xilinx System Generator DSP User Guide. You are encouraged to refer to this guide for more information and further examples and tutorials.
Though not addressed in this tutorial, you are also encouraged to read the Black Boxing CASPER Memo, which describes how Black Boxes can be used to embed pre-compiled netlists into Simulink models. This can substantially speed up compiles containing large processing modules.
This tutorial requires a number of files, all available on Github.
tut6_blackbox.mdl This is the complete Simulink model required for the tutorial
traffic_lights.v This is the Verilog module to be embedded in Simulink
traffic_lights_config.m This is a complete Matlab wrapper, required to embed the verilog module in Simulink
tut6.py A simple python script to test your design is working
traffic_lights_tb.v Though not used in this tutorial, traffic_lights_tb.v is a quick and dirty Verilog test bench.
This tutorial uses a simple Verilog state machine as an example of a module that you might wish to embed in Simulink. In our case, the state machine is a toy module to control a set of traffic lights.
Explicitly, the module code is:
module traffic_lights
#(parameter AMBER_TIME = 32'd10)
(input clk,
input ce,
input reset,
input toggle,
output reg green_led,
output reg amber_led,
output reg red_led
);
// State encoding
localparam STATE_RED = 2'd0;
localparam STATE_GREEN = 2'd1;
localparam STATE_GOING_RED = 2'd2;
localparam STATE_GOING_GREEN = 2'd3;
// State register
reg [1:0] state = 2'b0;
// Register for amber timer counter
reg [31:0] amber_timer = 32'b0;
always @(posedge clk) begin
if (reset == 1'b1) begin
state <= STATE_RED;
end else begin
green_led <= 1'b0;
red_led <= 1'b0;
amber_led <= 1'b0;
case(state)
STATE_RED: begin
red_led <= 1'b1;
if (toggle) begin
state <= STATE_GOING_GREEN;
end else begin
state <= STATE_RED;
end
end
STATE_GREEN: begin
green_led <= 1'b1;
if (toggle) begin
state <= STATE_GOING_RED;
end else begin
state <= STATE_GREEN;
end
end
STATE_GOING_RED: begin
amber_led <= 1;
amber_timer <= amber_timer + 1;
if (amber_timer == AMBER_TIME) begin
amber_timer <= 32'b0;
state <= STATE_RED;
end else begin
state <= STATE_GOING_RED;
end
end
STATE_GOING_GREEN: begin
amber_led <= 1;
red_led <= 1;
amber_timer <= amber_timer + 1;
if (amber_timer == AMBER_TIME) begin
amber_timer <= 32'b0;
state <= STATE_GREEN;
end else begin
state <= STATE_GOING_GREEN;
end
end
default: begin
state <= STATE_RED;
end
endcase
end
end
endmodule
This module has three outputs, to control the three light colours. Four inputs are used, with clk and ce providing clock and clock enable signals (note that even though the latter is not used it is required in the input ports. More on this shortly) and rst and toggle providing reset and "change lights" strobes. The module has a single parameter, "AMBER_TIME", which sets the amount of time the amber light remains on between a transition from green to red, or red to green.
The module represents a state machine with four states. RED (only red light is on), GOING_GREEN (amber and red lights are on [this is a set of British traffic lights!]), GREEN (only green light is on) and GOING_RED (only amber light is on). The module initializes to state RED, and transitions are triggered by pulsing the "toggle" input.
You can code your Verilog (or VHDL) module however you please. However, you must meet a set of requirements. Pulled from the System Generator User Guide these are:
● Bi-directional ports are supported in HDL black boxes and will appear in compiled output. However they cannot be used in Simulink.
● For Verilog black boxes, the module and port names must be lower case and must follow standard VHDL naming conventions.
● Any port that is a clock or clock enable must be of type std_logic. (For Verilog black boxes, ports must be of non-vector inputs, e.g., input clk.)
● Black boxed HDL modules can only have clocks and clock enables which appear in pairs. Though a black box may have more than one clock port, a single clock source is used to drive each clock port. Only the clock enable rates differ. Clocks and their associated enables must be named with the convention clk, ce. For example, a valid pair is my_clk_1, and my_ce_1.
● The entity name must not collide with any other entity name in the design.
● Falling-edge triggered output data cannot be used.
By now it is assumed you are comfortable with the Simulink environment and CASPER toolflow. If this is not the case, you should probably go through Introduction to Simulink before proceeding.
A premade model is available for you as part of this tutorial, but it is worth building your own to go through the HDL embedding process.
Fire up a new model, and insert the usual XSG and MSSGE configuration blocks. Now pull in a Black Box block from the Xilinx library (it's under "Basic Elements"). As soon as you drop the block in your design, you will be prompted to specify the HDL file which your black box is wrapping. In our case, this is traffic_lights.v.
After selecting this module MATLAB should tell you that it has generated a wrapper config file, but there are sections that require user input. This wrapper is called traffic_lights_config.m
NOTE: If you try to add a traffic_lights.v black box when the tutorial version of traffic_lights_config.m is already in your MATLAB path, you may have problems. If in doubt, start with a fresh MATLAB session and a new model, saved in a clean directory.
Your black box in Simulink should now have ports corresponding to those in your underlying HDL. However, the clock and clock enable signals should not be present, as these are handled behind the scenes by Simulink. If you can see these signals, you have probably made a mistake in your port names, and have not met the criteria demanded by the black box block. If all has gone well, your black box should look like this:
You can now edit the MATLAB configuration file (MATLAB has probably opened it for editing automatically for you). The Xilinx System Generator DSP User Guide explains everything, but here are the highlights:
First we set the HDL type and top level module name:
this_block.setTopLevelLanguage('Verilog');
this_block.setEntityName('traffic_lights');
Add the ports and the port types:
this_block.addSimulinkInport('reset');
this_block.addSimulinkInport('toggle');
this_block.addSimulinkOutport('green_led');
this_block.addSimulinkOutport('amber_led');
this_block.addSimulinkOutport('red_led');
green_led_port = this_block.port('green_led');
green_led_port.setType('UFix_1_0');
green_led_port.useHDLVector(false);
amber_led_port = this_block.port('amber_led');
amber_led_port.setType('UFix_1_0');
amber_led_port.useHDLVector(false);
red_led_port = this_block.port('red_led');
red_led_port.setType('UFix_1_0');
red_led_port.useHDLVector(false);
Do a wee bit of error checking, to make sure the simulink inputs are what the block expects:
if (this_block.port('reset').width ~= 1);
this_block.setError('Input data type for port "reset" must have width=1.');
end
Set values for Verilog/VHDL parameters/generics. You should manually change these to the values you want. Or parameterise them so that the values can be entered in a Simulink block mask. We'll do this later:
this_block.addGeneric('AMBER_TIME','integer','10');
List the files that System Generator needs to find to simulate or compile the block. If your module is composed of many submodules, you would add an entry for each file here, beginning with the deepest nested module:
this_block.addFile('traffic_lights.v');
All the entries above are configured automatically for you at the first import.
You can add parameters to your black box by editing the block mask as normal. However, these parameters are not displayed when you double click the block, only when you select "mask parameters" by right-clicking. To make things neat and easy, the suggested method of parameterizing your block (according to the SysGen guide), is to place it as a subsystem in a separate, masked block.
To do this, right click the block and click "Subsystem & Model Reference --> Create Subsystem from Selection". You can then mask the parent subsystem as you would with any parameterized block. In this tutorial, the parent has been masked and the parameter "amber_time" has been defined.
To propagate this parameter to your black boxed HDL, add the following to your matlab configuration wrapper, traffic_lights_config.v:
% Grab HDL parameters from simulink mask
myname = this_block.blockName; %This is the name of the black box block
bb_mask = get_param(myname,'Parent'); %This is the name of the black box subsystem
amber_time = str2num(get_param(bb_mask,'amber_time')); %Grab the 'amber time' parameter from the parent's mask
and then use this value to set your HDL parameters:
this_block.addGeneric('AMBER_TIME','integer',num2str(amber_time)); %At 100 MHz, 100,000,000 is 1 second
Your parameterised black box is now complete!
You can simulate your model using ISE of ModelSim by setting the "simulation mode" parameter of the black box. By default, this is set to "Inactive", in which case your block will not be simulated.
The complete model tut6_blackbox.mdl allows you to simulate a simple design, where the inputs to the black box are driven by software registers, and the outputs are tied to GPIO pins and a software register. On simulation you should see a trigger input on the 11th clock cycle, which will cause the lights to transition from their initial red state, to green. The "amber_light" transition time has been set to 10 clock cycles.
If you wish, you can compile the design (but set the amber_light time to something longer first! (100,000,000 clock cycles = 1 second)), and run it on a ROACH using the (frankly, rather silly) python script provided.