We simulate the operation of FPGAs beautifully

Why do you need to configure anything at all, and why waste time on it? Developing a program, or as in the case of FPGAs, developing an HDL description is not only writing code, but also its subsequent debugging. And often, it is the debugging process that spends the most time. Help make debugging convenient and modeling in the ModelSim environment comfortable, and thereby reduce the overall development time – this is the main goal of this article.

1. Where to start? Wave Tab

Let's assume that we already have the HDL code of the module under test, model files (testbench) and scripts for running the simulation. And all this started and compiled into ModelSim without errors.

The script is running...

The script is running…

The main work when modeling and debugging the HDL code of a project in the ModelSim environment usually occurs on the ” tabWave

Tab "Wave" at the beginning of work

“Wave” tab at the beginning of work

If for some reason this tab is not there, then most likely it was disabled in the settings. It turns on simply – left-click in the main menu on “View“, then in the list that opens, put a tick next to “Wave

The tab will appear in the horizontal list at the bottom of the program window. You can go to it (like any other tab) by clicking the left mouse button.

Now you can start adding signals to the “Wave” To be more precise, objects (signals, variables, constants, etc.) from the “ tab are transferred to this tab.Objects” But since in most cases the modeling work is done with signals, for convenience we will call all these objects signals.

2. Adding signals

At the very beginning of work, the tab “Wave» will most likely be empty. We need to add signals to it. First, let's add the signals described in the model file (testbench). Typically these are external signals connected to the inputs and outputs of the module under test, as well as some auxiliary signals. To add them, go to the tab “Transcript“and enter the command in the console:

add wave *

After executing the command, we return back to “Wave” Here in the left column a list of all signals from the model file will be displayed. It looks like this:

List of signals with full names

List of signals with full names

For each signal its full name is given. That is, in addition to the name of the signal itself, the hierarchy of modules within which it is declared is indicated. In this example, all signals are located at the very top of the hierarchy – in the model file, the top module of which is called “sdram_memory_ctrl_vhd_tst”. If the signal is located in a module located deep in the hierarchy, then its full name when displayed may be too long. For example, the signal for the internal FIFO address counter has the full name:

sdram_memory_ctrl_vhd_tst/i1/w_fifo_inst/br_core/addr_wr

Such signal designations are not very convenient when working. In order to display only the name, you need to click on the “Toggle leaf names“, located under the list of signals in the lower left corner.

List of signals with short names

List of signals with short names

As is not difficult to notice, short signal names are much more convenient when working.

3. Tabs “sim” and “Objects”

Of course, with full-fledged modeling and debugging, it is impossible to limit ourselves to just external signals. It is also necessary to have before your eyes the signals located inside the module under test (and its submodules). To add them, you need to go to the “sim” Here is a hierarchical list. The topmost in this list, as already mentioned, will be the module describing the model itself. Inside it there is a module under test with its submodules. Additional modules may also be present if they were included inside the model file.

Tab "sim"

“sim” tab

It should be noted that the list does not indicate the name of the module itself, but the name assigned to its copy (there can be several copies of one module at the same time). The name, as it appears in the HDL description file of the module, is given to the right – in the column “Design unit” For example, the module under test here is “i1”in the HDL description file its name is “sdram_memory_ctrl”.

Now in the hierarchical list we select the module in which the signal we are interested in is located. In this example, this is the module “br_core”. After that, switch to the “Objects” All signals that are present in the module selected on the ” tab will be shown heresim” Now we find the signal (or several signals) we need and mark it with the left mouse button. Next, right-click on it and select “Add Wave” – the signal will be automatically transferred to the ” tabWave

Tab "Objects" - signal transfer

“Objects” tab – signal transfer

In this example, the signal selected “addr_wr”. You can also transfer the desired signal using the “Transcript” by running the following console command, for example:

add wave -noupdate sim:/sdram_memory_ctrl_vhd_tst/i1/w_fifo_inst/br_core/addr_wr

In this option, you must specify the full name of the signal with a list of all submodules. If you need all the signals from the selected module at once, then in the console command you should replace the signal name with the symbol “*”, for example:

add wave -noupdate sim:/sdram_memory_ctrl_vhd_tst/i1/w_fifo_inst/br_core/*

Constantly switching between tabs “sim“, “Objects” And “Wave” can be tedious. To simultaneously display several tabs on one screen, use the “zoom/unzoom“, located in the upper right corner.

Multiple tabs in one window

Multiple tabs in one window

Now you can directly drag and drop the desired signals from the “Objects” to “Wave» without additional switching between tabs.

4. Signal layout

After going to the “Wave» all the necessary signals have been moved, in principle, modeling could already begin. This is what they do when testing small modules. But when working with a large project containing nested submodules, on the “Wave“There may be several dozen, or even hundreds of signals at the same time. It would be convenient to somehow arrange them so as not to get confused in the variety of signals. There are several basic options.

The first is grouping. It's easy to do. Several signals are selected, then at the command “Group“A single group is formed from them. By default, a group is created with the name “New Group” but you can rename it at any time. In the example above, a group has been created with the name “GRP_R”which combines signals associated with reading data.

Signal grouping

Signal grouping

The same result can be obtained using console commands, for example:

add wave -noupdate -expand -group GRP_R /sdram_memory_ctrl_vhd_tst/R_rts
add wave -noupdate -expand -group GRP_R /sdram_memory_ctrl_vhd_tst/R_data
. . .
add wave -noupdate -expand -group GRP_R /sdram_memory_ctrl_vhd_tst/R_extra_info

Meaning “-expand” indicates that the created group will immediately be displayed expanded, that is, with a list of signals of all the signals that it consists of. If this value is removed, only the group name will be displayed. Signals will be hidden. You can also create groups within existing groups. This is all done by the same team “Group

The second option for composing signals is to use separators. There are no difficulties here either. To add this element use the command “Add –> New Divider” By default, a separator is created with the name “New Divider” but you can rename it at any time. In the example above, separators with names are created “READ” And “LOGIC”.

Adding Separators

Adding Separators

Just like for a group, you can use console commands to create a separator, for example:

add wave -noupdate -divider -height 35 READ
add wave -noupdate -divider -height 35 LOGIC

The example uses the parameter “-height” with a value of 35. It sets the height of the separator. If this option is not used, a separator will be created with a height value of 17 units.

The last signal layout option that I wanted to write about is combination. This option is convenient to use when working with tires. For example, there is a signal that is a data bus of some width. Sometimes it may be convenient to break it up into separate parts of 8 bits each.

Combining individual bits

Combining individual bits

This operation is performed using the command “Combine Signals…“, or using console commands, for example:

quietly virtual signal -install /<...> { /<...>/q_a(255 downto 248)} byte31add wave -noupdate /<...>/byte31

Note: the signal “q_a” from this example is deep inside the hierarchy. To save space, its full name is not indicated in the example; it is replaced with <…>.

As a result, after all the iterations, the result of the signal layout looks like this:

List of signals after combining

List of signals after combining

All signals necessary for operation are output. They are conveniently arranged, divided into groups that can be expanded or collapsed as needed. Added separators. Everything is in its place, the likelihood of errors and confusion is minimized.

5. Summing up the interim results

In this part of the article, the preparatory iterations immediately preceding the modeling process were analyzed and illustrated. It may seem that all this preparation will take a lot of time, and you can easily do without it? In fact, after some practice, these actions will take no more than 5-10 minutes. But the convenience will save hours during further work!

Initially, I wanted to describe here the modeling process itself and the accompanying settings. But it seems that this will be too much for one article. I decided to break it into two.

Therefore, I plan to discuss the modeling process, working with timing diagrams and creating a settings file in detail in the next part of the article.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *