August 12, 2022
Editor’s Note: This content is republished from the MicroZed Chronicles, with permission from the author.
A couple of weeks ago, I mentioned I had invested in MATLAB and HDL Coder to enable generations of RTL code directly from Simulink models. I have never used this flow before but I am a big believer in using higher level of abstractions to implement designs or elements of the design faster.
Recently I sat down to try and create my first application that I could target to hardware. I wanted to create a simple state machine for this application and start learning the process and tool chain. This state machine will set LEDs depending upon the state of the four inputs and the first input will enable the state of the remaining three switches to set the LED. I will be able to target this design to an Arty S7-50 board for testing.
To get started with this project, I first needed to create a new Simulink diagram that contains a Stateflow Chart. Just click anywhere in the canvas and start typing Stateflow and the option will become available.
You should see the Stateflow icon on the canvas. Double clicking on the chart will open it for editing.
Once in the chart editor, we can add in the states and the transitions between the states. Initially, I created two states and named them Idle and LED. The transitions between them don’t have any conditions yet.
To add state transition conditions, we can double click on the transition and enter the condition desired.
Of course, state machines can have Mealey and Moore outputs which occur as a function of the present state (Moore) or present state and input (Mealey). In this case, I declared the LED outputs as Moore outputs which are declared in each of the states.
The final diagram looks like the one below, however, now we need to declare the inputs and outputs since we can have internal variables also.
Using the Model Explorer, we can define the input and outputs to the state machine. We leave them the same type as Simulink for the inputs but need to define them for the outputs. Since we need three bits for the LEDs, we use the type fixdt(0,3,0). This means the vector is three bits wide, unsigned, and has no fractional elements to the number.
Also, within the Model Explorer check mark the Execute (enter) chart at initialization option.
Navigate to the canvas above the chart. Here we need to add in the IO for the block and we will also add in a delay. In the canvas, start typing in input or output to get the desired ports.
You can also name the ports by double clicking on the input and outputs to set them to the correct types. SW_ENB is a set to binary.
Set the sw_in to the fixdt(0,3,0) the same as the output type previously declared. We use a delay to add in a register. To add in an additional delay, just type in the canvas.
To change the length of the delay, double click on the delay and change it have a delay of one.
The image below shows the complete diagram.
Now we could generate this as RTL but first we will create a test bench for it. Select all the elements on the canvas, right click on it, and select Create SubSystem from Selection.
Add in a step function and constant, set the block types as used in the subsystem block, and make sure to set the sample time to -1 for discrete sampling.
Right click on signals of interest and select Start Logging Selected Signals.
Open the Model Explorer and set the model to be a discrete time simulation with a fixed step for the timer.
Run the simulation and open the data inspector. You should be able to see the SW_ENB being asserted and the LED output going high the next clock after.
Now we can create the HDL and export it to be used in Vivado. We can do this by right clicking on the subsystem and selecting Generate HDL for Subsystem.
If you want to change any of the generated HDL code formatting (i.e., to remove the clock enable), select the Global Settings option from the HDL Code Generation tab.
When the code is generated, you will see a message in the MATLAB window where the code is generated.
This HDL can then be imported into a Vivado project targeting the board we are looking for. The generated code itself is actually human readable and depending upon how well we comment the Simulink diagram. For example, I could have named the state chart and this would have been reflected in the case statement name.
Three VHDL files are generated: a package containing declarations, the actual source code which implements the state machine, and a top-level file.
Implementing this in Vivado, the final design takes three flip flops and two LUTs.
Of course, this is a simple example but it enabled me to learn the flow so that I can begin using it for more complex applications.
I am looking forward to working with this more on one or two of our current projects and seeing how it impacts productivity.