Skip to content

Commit c4265e9

Browse files
committed
Improve Verilog output by using sanitized MemBlock and RomBlock names instead
of `mem_{memid}` names. Also add more comments to the generated Verilog: - Indicate if a memory is a MemBlock or a RomBlock - Show the un-sanitized name when it differs from the sanitized name
1 parent 07ec4c3 commit c4265e9

File tree

2 files changed

+190
-123
lines changed

2 files changed

+190
-123
lines changed

pyrtl/importexport.py

Lines changed: 85 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,7 @@ def gate_key(gate: Gate) -> str:
798798
return gate.name
799799
return gate.args[2].name
800800

801+
# Sanitize all Gate names.
801802
for gate in sorted(self.gate_graph.gates, key=gate_key):
802803
if gate.name:
803804
self.internal_names.make_valid_string(gate.name)
@@ -807,8 +808,8 @@ def gate_key(gate: Gate) -> str:
807808

808809
self.io_list = [
809810
"clk",
810-
*[self._verilog_name(input) for input in self.inputs],
811-
*[self._verilog_name(output) for output in self.outputs],
811+
*[self._verilog_name(input.name) for input in self.inputs],
812+
*[self._verilog_name(output.name) for output in self.outputs],
812813
]
813814
if self.add_reset:
814815
self.io_list.insert(1, "rst")
@@ -828,6 +829,10 @@ def gate_key(gate: Gate) -> str:
828829
key=lambda memblock: memblock.id,
829830
)
830831

832+
# Sanitize all MemBlock names.
833+
for memblock in self.all_memblocks:
834+
self.internal_names.make_valid_string(memblock.name)
835+
831836
# List of unique MemBlocks (not RomBlocks!), sorted by memid.
832837
self.memblocks = [
833838
memblock for memblock in self.all_memblocks if type(memblock) is MemBlock
@@ -840,9 +845,9 @@ def gate_key(gate: Gate) -> str:
840845
if isinstance(romblock, RomBlock)
841846
]
842847

843-
def _verilog_name(self, gate: Gate) -> str:
844-
"""Return a ``Gate``'s Verilog name."""
845-
return self.internal_names[gate.name]
848+
def _verilog_name(self, name: str) -> str:
849+
"""Return the sanitized Verilog identifier name for ``name``."""
850+
return self.internal_names[name]
846851

847852
def _name_sorted(self, gates: set[Gate]) -> list[Gate]:
848853
def name_mapper(gate: Gate) -> str:
@@ -851,7 +856,7 @@ def name_mapper(gate: Gate) -> str:
851856
# ``wr_en``, since this particular net is used within 'always begin ...
852857
# end' blocks for memory update logic.
853858
return gate.args[2].name
854-
return self._verilog_name(gate)
859+
return self._verilog_name(gate.name)
855860

856861
return _name_sorted(gates, name_mapper=name_mapper)
857862

@@ -923,6 +928,25 @@ def _should_declare_wire(self, gate: Gate) -> bool:
923928

924929
return not excluded and (is_named or multiple_users or is_read or is_sliced)
925930

931+
def _name_and_comment(self, name: str, kind="") -> tuple[str, str]:
932+
"""Return the sanitized version of ``name`` and a Verilog comment with the
933+
un-sanitized name. If ``kind`` is provided, it will always be included in the
934+
comment.
935+
"""
936+
sanitized_name = self._verilog_name(name)
937+
if kind:
938+
if sanitized_name != name:
939+
comment = f" // {kind} {name}"
940+
else:
941+
comment = f" // {kind}"
942+
else:
943+
if sanitized_name != name:
944+
comment = f" // {name}"
945+
else:
946+
comment = ""
947+
948+
return sanitized_name, comment
949+
926950
def _to_verilog_header(self, file: IO, initialize_registers: bool):
927951
"""Print the header of the verilog implementation."""
928952
print("// Generated automatically via PyRTL", file=file)
@@ -940,16 +964,19 @@ def _to_verilog_header(self, file: IO, initialize_registers: bool):
940964
print(" input clk;", file=file)
941965
if self.add_reset:
942966
print(" input rst;", file=file)
967+
943968
for input_gate in self.inputs:
969+
sanitized_name, comment = self._name_and_comment(input_gate.name)
944970
print(
945-
f" input{self._verilog_size(input_gate.bitwidth)} "
946-
f"{self._verilog_name(input_gate)};",
971+
f" input{self._verilog_size(input_gate.bitwidth)} {sanitized_name};"
972+
f"{comment}",
947973
file=file,
948974
)
949975
for output_gate in self.outputs:
976+
sanitized_name, comment = self._name_and_comment(output_gate.name)
950977
print(
951978
f" output{self._verilog_size(output_gate.bitwidth)} "
952-
f"{self._verilog_name(output_gate)};",
979+
f"{sanitized_name};{comment}",
953980
file=file,
954981
)
955982
print(file=file)
@@ -958,10 +985,14 @@ def _to_verilog_header(self, file: IO, initialize_registers: bool):
958985
if self.all_memblocks:
959986
print(" // Memories", file=file)
960987
for memblock in self.all_memblocks:
988+
kind = "MemBlock"
989+
if isinstance(memblock, RomBlock):
990+
kind = "RomBlock"
991+
sanitized_name, comment = self._name_and_comment(memblock.name, kind)
961992
print(
962993
f" reg{self._verilog_size(memblock.bitwidth)} "
963-
f"mem_{memblock.id}{self._verilog_size(1 << memblock.addrwidth)};"
964-
f" // {memblock.name}",
994+
f"{sanitized_name}{self._verilog_size(1 << memblock.addrwidth)};"
995+
f"{comment}",
965996
file=file,
966997
)
967998
if self.all_memblocks:
@@ -978,16 +1009,16 @@ def _to_verilog_header(self, file: IO, initialize_registers: bool):
9781009
if reg_gate.op_param[0] is not None:
9791010
reset_value = reg_gate.op_param[0]
9801011
register_initialization = f" = {reg_gate.bitwidth}'d{reset_value}"
1012+
sanitized_name, comment = self._name_and_comment(reg_gate.name)
9811013
print(
9821014
f" reg{self._verilog_size(reg_gate.bitwidth)} "
983-
f"{self._verilog_name(reg_gate)}"
984-
f"{register_initialization};",
1015+
f"{sanitized_name}{register_initialization};{comment}",
9851016
file=file,
9861017
)
9871018
if self.registers:
9881019
print(file=file)
9891020

990-
# Declare constants with user-specified names.
1021+
# Declare constants.
9911022
const_gates = []
9921023
for const_gate in self._name_sorted(self.gate_graph.consts):
9931024
if self._should_declare_const(const_gate):
@@ -997,10 +1028,11 @@ def _to_verilog_header(self, file: IO, initialize_registers: bool):
9971028
if const_gates:
9981029
print(" // Constants", file=file)
9991030
for const_gate in const_gates:
1031+
sanitized_name, comment = self._name_and_comment(const_gate.name)
10001032
print(
10011033
f" wire{self._verilog_size(const_gate.bitwidth)} "
1002-
f"{self._verilog_name(const_gate)} = "
1003-
f"{const_gate.bitwidth}'d{const_gate.op_param[0]};",
1034+
f"{sanitized_name} = {const_gate.bitwidth}'d{const_gate.op_param[0]};"
1035+
f"{comment}",
10041036
file=file,
10051037
)
10061038
if const_gates:
@@ -1017,9 +1049,10 @@ def _to_verilog_header(self, file: IO, initialize_registers: bool):
10171049
if temp_gates:
10181050
print(" // Temporaries", file=file)
10191051
for temp_gate in temp_gates:
1052+
sanitized_name, comment = self._name_and_comment(temp_gate.name)
10201053
print(
1021-
f" wire{self._verilog_size(temp_gate.bitwidth)} "
1022-
f"{self._verilog_name(temp_gate)};",
1054+
f" wire{self._verilog_size(temp_gate.bitwidth)} {sanitized_name};"
1055+
f"{comment}",
10231056
file=file,
10241057
)
10251058
if temp_gates:
@@ -1034,7 +1067,7 @@ def _to_verilog_header(self, file: IO, initialize_registers: bool):
10341067
print(" initial begin", file=file)
10351068
for addr in range(1 << romblock.addrwidth):
10361069
print(
1037-
f" mem_{romblock.id}[{addr}] = "
1070+
f" {self._verilog_name(romblock.name)}[{addr}] = "
10381071
f"{romblock.bitwidth}'h{romblock._get_read_data(addr):x};",
10391072
file=file,
10401073
)
@@ -1073,7 +1106,7 @@ def _verilog_expr(self, gate: Gate, lhs: Gate | None = None) -> str:
10731106
if gate in self.declared_gates and lhs is not gate:
10741107
# If a Verilog wire/reg has been declared for the gate, and we are not
10751108
# currently defining the Gate's value, just return the wire's Verilog name.
1076-
return self._verilog_name(gate)
1109+
return self._verilog_name(gate.name)
10771110
if gate.op == "C":
10781111
# Return the constant's Verilog value.
10791112
return f"{gate.bitwidth}'d{gate.op_param[0]}"
@@ -1138,7 +1171,7 @@ def _to_verilog_combinational(self, file: IO):
11381171
print(" // Combinational logic", file=file)
11391172
for assignment_gate in self._name_sorted(self.combinational_gates):
11401173
print(
1141-
f" assign {self._verilog_name(assignment_gate)} = "
1174+
f" assign {self._verilog_name(assignment_gate.name)} = "
11421175
f"{self._verilog_expr(assignment_gate, lhs=assignment_gate)};",
11431176
file=file,
11441177
)
@@ -1160,7 +1193,7 @@ def _to_verilog_sequential(self, file: IO):
11601193
for register in self._name_sorted(self.gate_graph.registers):
11611194
reset_value = register.op_param[0]
11621195
print(
1163-
f" {self._verilog_name(register)} <= "
1196+
f" {self._verilog_name(register.name)} <= "
11641197
f"{register.bitwidth}'d{reset_value};",
11651198
file=file,
11661199
)
@@ -1171,7 +1204,7 @@ def _to_verilog_sequential(self, file: IO):
11711204

11721205
for register in self._name_sorted(self.gate_graph.registers):
11731206
print(
1174-
f" {self._verilog_name(register)} <= "
1207+
f" {self._verilog_name(register.name)} <= "
11751208
f"{self._verilog_expr(register.args[0])};",
11761209
file=file,
11771210
)
@@ -1182,7 +1215,10 @@ def _to_verilog_sequential(self, file: IO):
11821215
def _to_verilog_memories(self, file: IO):
11831216
"""Generate Verilog logic for MemBlock and RomBlock reads and writes."""
11841217
for memblock in self.all_memblocks:
1185-
print(f" // Memory mem_{memblock.id}: {memblock.name}", file=file)
1218+
kind = "MemBlock"
1219+
if isinstance(memblock, RomBlock):
1220+
kind = "RomBlock"
1221+
print(f" // {kind} {memblock.name}", file=file)
11861222

11871223
# Find writes to ``memblock``.
11881224
write_gates = []
@@ -1200,15 +1236,15 @@ def _to_verilog_memories(self, file: IO):
12001236
# Simplify the assignment if the enable bit is a constant ``1``.
12011237
if enable.op == "C" and enable.op_param[0] == 1:
12021238
print(
1203-
f" mem_{write_gate.op_param[0]}[{verilog_addr}] <= "
1204-
f"{verilog_rhs};",
1239+
f" {self._verilog_name(memblock.name)}"
1240+
f"[{verilog_addr}] <= {verilog_rhs};",
12051241
file=file,
12061242
)
12071243
else:
12081244
print(
12091245
f" if ({verilog_enable}) begin\n"
1210-
f" mem_{write_gate.op_param[0]}[{verilog_addr}] "
1211-
f"<= {verilog_rhs};\n"
1246+
f" {self._verilog_name(memblock.name)}"
1247+
f"[{verilog_addr}] <= {verilog_rhs};\n"
12121248
" end",
12131249
file=file,
12141250
)
@@ -1222,8 +1258,8 @@ def _to_verilog_memories(self, file: IO):
12221258
read_gates.append(read_gate)
12231259
for read_gate in self._name_sorted(read_gates):
12241260
print(
1225-
f" assign {self._verilog_name(read_gate)} = "
1226-
f"mem_{read_gate.op_param[0]}"
1261+
f" assign {self._verilog_name(read_gate.name)} = "
1262+
f"{self._verilog_name(memblock.name)}"
12271263
f"[{self._verilog_expr(read_gate.args[0])}];",
12281264
file=file,
12291265
)
@@ -1259,18 +1295,24 @@ def output_verilog_testbench(
12591295
print(" reg clk;", file=dest_file)
12601296
if self.add_reset:
12611297
print(" reg rst;", file=dest_file)
1298+
if self.inputs:
1299+
print("\n // block Inputs", file=dest_file)
12621300
for input_gate in self.inputs:
1301+
sanitized_name, comment = self._name_and_comment(input_gate.name)
12631302
print(
1264-
f" reg{self._verilog_size(input_gate.bitwidth)} "
1265-
f"{self._verilog_name(input_gate)};",
1303+
f" reg{self._verilog_size(input_gate.bitwidth)} {sanitized_name};"
1304+
f"{comment}",
12661305
file=dest_file,
12671306
)
12681307

12691308
# Declare all block outputs as wires.
1309+
if self.outputs:
1310+
print("\n // block Outputs", file=dest_file)
12701311
for output_gate in self.outputs:
1312+
sanitized_name, comment = self._name_and_comment(output_gate.name)
12711313
print(
1272-
f" wire{self._verilog_size(output_gate.bitwidth)} "
1273-
f"{self._verilog_name(output_gate)};",
1314+
f" wire{self._verilog_size(output_gate.bitwidth)} {sanitized_name};"
1315+
f"{comment}",
12741316
file=dest_file,
12751317
)
12761318
print(file=dest_file)
@@ -1313,6 +1355,9 @@ def default_value() -> int:
13131355
register.name: value
13141356
for register, value in simulation_trace.register_value_map.items()
13151357
}
1358+
1359+
if self.registers:
1360+
print("\n // Initialize Registers", file=dest_file)
13161361
for reg_gate in self.registers:
13171362
# Try using register_value_map first.
13181363
initial_value = register_value_map.get(reg_gate.name)
@@ -1323,17 +1368,19 @@ def default_value() -> int:
13231368
if not initial_value:
13241369
initial_value = default_value()
13251370
print(
1326-
f" block.{self._verilog_name(reg_gate)} = "
1371+
f" block.{self._verilog_name(reg_gate.name)} = "
13271372
f"{reg_gate.bitwidth}'d{initial_value};",
13281373
file=dest_file,
13291374
)
13301375

13311376
# Initialize MemBlocks.
1377+
if self.memblocks:
1378+
print("\n // Initialize MemBlocks", file=dest_file)
13321379
for memblock in self.memblocks:
13331380
max_addr = 1 << memblock.addrwidth
13341381
print(
13351382
f" for (tb_addr = 0; tb_addr < {max_addr}; tb_addr++) "
1336-
f"begin block.mem_{memblock.id}[tb_addr] = "
1383+
f"begin block.{self._verilog_name(memblock.name)}[tb_addr] = "
13371384
f"{memblock.bitwidth}'d{default_value()}; end",
13381385
file=dest_file,
13391386
)
@@ -1349,7 +1396,7 @@ def default_value() -> int:
13491396
if initial_data == default_value():
13501397
continue
13511398
print(
1352-
f" block.mem_{memblock.id}[{addr}] = "
1399+
f" block.{self._verilog_name(memblock.name)}[{addr}] = "
13531400
f"{memblock.bitwidth}'d{initial_data};",
13541401
file=dest_file,
13551402
)
@@ -1361,7 +1408,7 @@ def default_value() -> int:
13611408
for input_gate in self.inputs:
13621409
input_value = simulation_trace.trace[input_gate.name][i]
13631410
print(
1364-
f" {self._verilog_name(input_gate)} = "
1411+
f" {self._verilog_name(input_gate.name)} = "
13651412
f"{input_gate.bitwidth}'d{input_value};",
13661413
file=dest_file,
13671414
)

0 commit comments

Comments
 (0)