-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add some support for automatically displaying enums in gtkwave.
The flow is basically like this: 1. An enum is written by the developer in a .sv file. The developer must use verilator directives to generate its equivalent in C++. 2. The generated enum is parsed in Python. The names of the states and corresponding values are extracted. 3. The names and values are written to a .gtkw save file. This save file can be used by the developer to display an enum's strings instead of values. Add a README.md which explains how to use this in a step-by-step guide.
- Loading branch information
Showing
9 changed files
with
198 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import pycparser | ||
import os | ||
import argparse | ||
import math | ||
|
||
argparser = argparse.ArgumentParser() | ||
argparser.add_argument('projectname', help='The name of the project') | ||
argparser.add_argument('-f', '--project-folder', help='Project folder location', default='.') | ||
args = argparser.parse_args() | ||
|
||
INPUTFILE = args.project_folder + '/obj_dir/V' + args.projectname + '.h' | ||
OUTPUTFOLDER = args.project_folder + '/enums' | ||
try: | ||
with open(INPUTFILE, 'r') as f: | ||
lines = f.readlines() | ||
except FileNotFoundError: | ||
print('Not found:', INPUTFILE) | ||
print('Verilator not run?') | ||
exit(1) | ||
|
||
|
||
|
||
in_enum = False | ||
enumfile = "" | ||
|
||
for line in lines: | ||
if not in_enum and "enum" in line: | ||
in_enum = True | ||
if in_enum: | ||
enumfile += line | ||
if in_enum and "};" in line: | ||
in_enum = False | ||
|
||
parser = pycparser.c_parser.CParser() | ||
ast = parser.parse(enumfile, filename='<none>') | ||
|
||
def get_enums(): | ||
return ast.ext | ||
|
||
def get_enum_statename_only(name): | ||
# Verilator names the states like so: | ||
# Top__DOT__State | ||
# We only want the 'State' part | ||
return name.split('__DOT__')[-1] | ||
|
||
def get_enum_highest_value(enum): | ||
return int( | ||
enum.type.values.enumerators[-1].value.value[:-1] | ||
) | ||
|
||
def get_enum_value_binary_encoded(value, bits): | ||
value = int(value[:-1]) | ||
return "{0:b}".format(value).zfill(bits) | ||
|
||
def enum2txt(enum, bits): | ||
txt = "" | ||
name = get_enum_statename_only(enum.type.name) | ||
for e in enum.type.values.enumerators: | ||
txt += get_enum_value_binary_encoded(e.value.value, bits) + ' ' + e.name + '\n' | ||
return txt, name | ||
|
||
enums = get_enums() | ||
|
||
if not os.path.exists(OUTPUTFOLDER): | ||
os.mkdir(OUTPUTFOLDER) | ||
|
||
for enum in enums: | ||
highest = get_enum_highest_value(enum) | ||
bits = int(math.log2(highest)) + 1 | ||
(enumcfgfile, name) = enum2txt(enum, bits) | ||
with open (OUTPUTFOLDER + '/' + name + '.gtkw', 'w') as f: | ||
f.write(enumcfgfile) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
enums/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# How to add states to waveform | ||
|
||
1. In your design (.sv file), create an enum in the same way as in the `States.sv` file. Remember the `/* verilator public */` comment, as `Verilator` will pick up on this and generate a C++ equivalent enum for you. | ||
2. Run the `enumparse.py` Python script. This parses the C++ enum and generates a file that adheres to gtkwave's configuration files. The script will output one file per enum in your code under the `enums` folder. (In this project, the python script is automatically run with `make`.) | ||
3. Select the signal you want to correlate with your enums. Make sure it is *blue*! `Data format` -> `Translate Filter File` -> `Enable and Select`. See Figure 1. | ||
4. `Add filter to list` -> Add correct `.gtkw` file -> Make sure it is *blue* -> `Ok`. See Figure 2. | ||
5. Once this is done, you can save the configuration (CTRL + S) and reuse it later (`gtkwave <tracefile> -a <config file>`). It is fine to track the config file on git if the signals included are somewhat stable. | ||
|
||
Figure 1: | ||
![Figure1](./docs/gtkwave-1.png) | ||
|
||
Figure 2: | ||
![Figure2](./docs/gtkwave-2.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
module States ( | ||
input[31:0] in, | ||
output[1:0] state_out | ||
); | ||
typedef enum logic [1:0] { ZERO, LOW, HIGH, MAX } HighLow /* verilator public */; | ||
typedef enum logic [2:0] { INIT, DATA_RX, DATA_TX, STOPBIT, RESET } UART /* verilator public */; | ||
HighLow state = ZERO; | ||
|
||
always @(in) begin | ||
if (in == 0) | ||
state = ZERO; | ||
else if (in <= 'h80000000) | ||
state = LOW; | ||
else if (in == 'hFFFFFFFF) | ||
state = MAX; | ||
else | ||
state = HIGH; | ||
end | ||
|
||
assign state_out = state; | ||
|
||
endmodule |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
#include "VStates.h" | ||
#include "verilated.h" | ||
|
||
// Needed for waveform generation | ||
#include <verilated_vcd_c.h> | ||
|
||
#include <cassert> | ||
#include <vector> | ||
#include <iostream> | ||
|
||
int main(int argc, char** argv) { | ||
VStates* top = new VStates; | ||
Verilated::commandArgs(argc, argv); | ||
|
||
// For waveform generation | ||
unsigned long tickcount = 0; | ||
Verilated::traceEverOn(true); | ||
|
||
// Initialization of trace | ||
VerilatedVcdC *trace = new VerilatedVcdC; | ||
top->trace(trace, 99); | ||
trace->open("trace.vcd"); | ||
|
||
struct inout { | ||
const uint32_t in; | ||
VStates::States__DOT__HighLow out; | ||
} inout[] = { | ||
/** | ||
* The enum is generated by Verilator from using | ||
* | ||
* /* verilator public *\/ | ||
* | ||
* behind the typedef enum declaration. See the States.sv code. | ||
* | ||
*/ | ||
{ .in = 0x00000000, .out = VStates::States__DOT__HighLow::ZERO, }, | ||
{ .in = 0x00000001, .out = VStates::States__DOT__HighLow::LOW, }, | ||
{ .in = 0x00000010, .out = VStates::States__DOT__HighLow::LOW, }, | ||
{ .in = 0x7FFFFFFF, .out = VStates::States__DOT__HighLow::LOW, }, | ||
{ .in = 0x80000000, .out = VStates::States__DOT__HighLow::LOW, }, | ||
{ .in = 0x80000001, .out = VStates::States__DOT__HighLow::HIGH, }, | ||
{ .in = 0x80000002, .out = VStates::States__DOT__HighLow::HIGH, }, | ||
{ .in = 0x87236211, .out = VStates::States__DOT__HighLow::HIGH, }, | ||
{ .in = 0xFFFFFFFE, .out = VStates::States__DOT__HighLow::HIGH, }, | ||
{ .in = 0xFFFFFFFF, .out = VStates::States__DOT__HighLow::MAX, }, | ||
}; | ||
|
||
for (int i = 0; i < sizeof(inout) / sizeof(inout[0]); i++) { | ||
if (Verilated::gotFinish()) break; | ||
|
||
top->in = inout[i].in; | ||
|
||
top->eval(); | ||
assert(top->state_out == inout[i].out); | ||
|
||
trace->dump(10*tickcount++); | ||
} | ||
|
||
trace->dump(10*tickcount++); | ||
|
||
trace->close(); | ||
delete trace; | ||
|
||
delete top; | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
VERILATOR_ROOT := ../.. | ||
PROJECT_NAME := States | ||
SOURCES := *.sv | ||
SIMFILES := *.cpp | ||
ENUMPARSE := ../../enumparse.py | ||
|
||
include $(VERILATOR_ROOT)/verilator.mk | ||
|
||
all:: enums | ||
|
||
clean:: | ||
rm -rf enums | ||
|
||
enums: | ||
python3 $(ENUMPARSE) $(PROJECT_NAME) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters