Skip to content

Commit d1c2a3d

Browse files
authored
Central synthesizer naming (#652)
1 parent 2705970 commit d1c2a3d

17 files changed

Lines changed: 2175 additions & 379 deletions

lib/src/exceptions/logic/put_exception.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99

1010
import 'package:rohd/rohd.dart';
1111

12-
/// An exception that thrown when a [Logic] signal fails to `put`.
12+
/// An exception that thrown when a [Logic] signal fails to [Logic.put].
1313
class PutException extends RohdException {
14-
/// Creates an exception for when a `put` fails on a `Logic` with [context] as
15-
/// to where the
14+
/// Creates an exception for when a [Logic.put] fails on a [Logic] with
15+
/// [context] as to where the failure occurred and [message] describing the
16+
/// failure.
1617
PutException(String context, String message)
1718
: super('Failed to put value on signal ($context): $message');
1819
}

lib/src/module.dart

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2021-2025 Intel Corporation
1+
// Copyright (C) 2021-2026 Intel Corporation
22
// SPDX-License-Identifier: BSD-3-Clause
33
//
44
// module.dart
@@ -11,11 +11,11 @@ import 'dart:async';
1111
import 'dart:collection';
1212

1313
import 'package:meta/meta.dart';
14-
1514
import 'package:rohd/rohd.dart';
1615
import 'package:rohd/src/collections/traverseable_collection.dart';
1716
import 'package:rohd/src/diagnostics/inspector_service.dart';
1817
import 'package:rohd/src/utilities/config.dart';
18+
import 'package:rohd/src/utilities/namer.dart';
1919
import 'package:rohd/src/utilities/sanitizer.dart';
2020
import 'package:rohd/src/utilities/timestamper.dart';
2121
import 'package:rohd/src/utilities/uniquifier.dart';
@@ -52,6 +52,18 @@ abstract class Module {
5252
/// An internal mapping of input names to their sources to this [Module].
5353
late final Map<String, Logic> _inputSources = {};
5454

55+
// ─── Central naming (Namer) ─────────────────────────────────────
56+
57+
/// Central namer that owns both the signal and instance namespaces.
58+
/// Initialized lazily on first access (after build).
59+
@internal
60+
late final Namer namer = _createNamer();
61+
62+
Namer _createNamer() {
63+
assert(hasBuilt, 'Module must be built before canonical names are bound.');
64+
return Namer.forModule(this);
65+
}
66+
5567
/// An internal mapping of inOut names to their sources to this [Module].
5668
late final Map<String, Logic> _inOutSources = {};
5769

@@ -202,6 +214,18 @@ abstract class Module {
202214
this, 'Module must be built to access uniquified name.');
203215
String _uniqueInstanceName;
204216

217+
/// A stable identity used to memoize this module's canonical instance name
218+
/// across repeated synthesis passes (e.g. netlist then SystemVerilog).
219+
///
220+
/// Defaults to the [Module] itself, which is correct for modules that are
221+
/// part of the built hierarchy and therefore persist across passes.
222+
/// Synthesis-time throwaway modules that are *recreated* on every pass (and
223+
/// thus have a fresh [Module] identity each time) must override this to
224+
/// return a stable identity — typically the [Logic] they drive — so their
225+
/// instance name does not drift run-to-run.
226+
@internal
227+
Object get instanceNameKey => this;
228+
205229
/// If true, guarantees [uniqueInstanceName] matches [name] or else the
206230
/// [build] will fail.
207231
final bool reserveName;

lib/src/synthesizers/synth_builder.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2021-2025 Intel Corporation
1+
// Copyright (C) 2021-2026 Intel Corporation
22
// SPDX-License-Identifier: BSD-3-Clause
33
//
44
// synth_builder.dart

lib/src/synthesizers/synthesizer.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
// Copyright (C) 2021-2023 Intel Corporation
1+
// Copyright (C) 2021-2026 Intel Corporation
22
// SPDX-License-Identifier: BSD-3-Clause
33
//
44
// synthesizer.dart
55
// Generic definition for something that synthesizes output files
66
//
77
// 2021 August 26
88
// Author: Max Korbel <max.korbel@intel.com>
9-
//
109

1110
import 'package:rohd/rohd.dart';
1211

lib/src/synthesizers/systemverilog/systemverilog_synth_module_definition.dart

Lines changed: 43 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2021-2025 Intel Corporation
1+
// Copyright (C) 2021-2026 Intel Corporation
22
// SPDX-License-Identifier: BSD-3-Clause
33
//
44
// systemverilog_synth_module_definition.dart
@@ -19,7 +19,7 @@ class SystemVerilogSynthModuleDefinition extends SynthModuleDefinition {
1919
@override
2020
void process() {
2121
_replaceNetConnections();
22-
_collapseChainableModules();
22+
_collapseMarkedChainableModules();
2323
_replaceInOutConnectionInlineableModules();
2424
}
2525

@@ -30,34 +30,41 @@ class SystemVerilogSynthModuleDefinition extends SynthModuleDefinition {
3030
/// Creates a new [_NetConnect] module to synthesize assignment between two
3131
/// [LogicNet]s.
3232
SystemVerilogSynthSubModuleInstantiation _addNetConnect(
33-
SynthLogic dst, SynthLogic src) {
33+
SynthLogic dst,
34+
SynthLogic src,
35+
) {
3436
// make an (unconnected) module representing the assignment
35-
final netConnect =
36-
_NetConnect(LogicNet(width: dst.width), LogicNet(width: src.width));
37+
final netConnect = _NetConnect(
38+
LogicNet(width: dst.width),
39+
LogicNet(width: src.width),
40+
);
3741

3842
// instantiate the module within the definition
3943
final netConnectSynthSubModInst =
4044
(getSynthSubModuleInstantiation(netConnect)
4145
as SystemVerilogSynthSubModuleInstantiation)
42-
4346
// map inouts to the appropriate `_SynthLogic`s
4447
..setInOutMapping(_NetConnect.n0Name, dst)
4548
..setInOutMapping(_NetConnect.n1Name, src);
4649

4750
// notify the `SynthBuilder` that it needs declaration
4851
supportingModules.add(netConnect);
4952

53+
netConnectSynthSubModInst.pickName(module);
54+
5055
return netConnectSynthSubModInst;
5156
}
5257

53-
/// Replace all [assignments] between two [LogicNet]s with a [_NetConnect].
58+
/// Builds [_NetConnect] instances for [LogicNet] assignments.
5459
void _replaceNetConnections() {
5560
final reducedAssignments = <SynthAssignment>[];
5661

5762
for (final assignment in assignments) {
5863
if (assignment.src.isNet && assignment.dst.isNet) {
59-
assert(assignment is! PartialSynthAssignment,
60-
'Net connections should not be partial assignments.');
64+
assert(
65+
assignment is! PartialSynthAssignment,
66+
'Net connections should not be partial assignments.',
67+
);
6168

6269
_addNetConnect(assignment.dst, assignment.src);
6370
} else {
@@ -73,106 +80,19 @@ class SystemVerilogSynthModuleDefinition extends SynthModuleDefinition {
7380
}
7481
}
7582

76-
/// Collapses chainable, inlineable modules.
77-
void _collapseChainableModules() {
83+
/// Collapses chainable, inlineable modules after naming.
84+
void _collapseMarkedChainableModules() {
7885
// collapse multiple lines of in-line assignments into one where they are
7986
// unnamed one-liners
8087
// for example, be capable of creating lines like:
8188
// assign x = a & b & c & _d_and_e
8289
// assign _d_and_e = d & e
8390
// assign y = _d_and_e
8491

85-
// Also feed collapsed chained modules into other modules
86-
// Need to consider order of operations in systemverilog or else add ()
87-
// everywhere! (for now add the parentheses)
88-
89-
// Algorithm:
90-
// - find submodule instantiations that are inlineable
91-
// - filter to those who only output as input to one other module
92-
// - pass an override to the submodule instantiation that the corresponding
93-
// input should map to the output of another submodule instantiation
94-
// do not collapse if signal feeds to multiple inputs of other modules
95-
96-
final inlineableSubmoduleInstantiations = module.subModules
97-
.whereType<InlineSystemVerilog>()
98-
.map((m) => getSynthSubModuleInstantiation(m)
99-
as SystemVerilogSynthSubModuleInstantiation);
100-
101-
// number of times each signal name is used by any module
102-
final signalUsage = <SynthLogic, int>{};
103-
104-
for (final subModuleInstantiation in subModuleInstantiations) {
105-
for (final inSynthLogic in [
106-
...subModuleInstantiation.inputMapping.values,
107-
...subModuleInstantiation.inOutMapping.values
108-
]) {
109-
if (inputs.contains(inSynthLogic) || inOuts.contains(inSynthLogic)) {
110-
// dont worry about inputs to THIS module
111-
continue;
112-
}
113-
114-
subModuleInstantiation as SystemVerilogSynthSubModuleInstantiation;
115-
116-
if (subModuleInstantiation.inlineResultLogic == inSynthLogic) {
117-
// don't worry about the result signal
118-
continue;
119-
}
120-
121-
signalUsage.update(
122-
inSynthLogic,
123-
(value) => value + 1,
124-
ifAbsent: () => 1,
125-
);
126-
}
127-
}
128-
129-
final singleUseSignals = <SynthLogic>{};
130-
signalUsage.forEach((signal, signalUsageCount) {
131-
// don't collapse if:
132-
// - used more than once
133-
// - inline modules for preferred names
134-
if (signalUsageCount == 1 && signal.mergeable) {
135-
singleUseSignals.add(signal);
136-
}
137-
});
138-
139-
// partial assignments are a special case, count as a usage
140-
for (final partialAssignment
141-
in assignments.whereType<PartialSynthAssignment>()) {
142-
singleUseSignals.remove(partialAssignment.src);
143-
}
144-
145-
final singleUsageInlineableSubmoduleInstantiations =
146-
inlineableSubmoduleInstantiations.where((subModuleInstantiation) {
147-
// inlineable modules have only 1 result signal
148-
final resultSynthLogic = subModuleInstantiation.inlineResultLogic!;
149-
150-
return singleUseSignals.contains(resultSynthLogic) &&
151-
152-
// don't inline modules if they were cleared from instantiation
153-
subModuleInstantiation.needsInstantiation;
154-
});
155-
156-
// remove any inlineability for those that want no expressions
157-
for (final instantiation in subModuleInstantiations) {
158-
final subModule = instantiation.module;
159-
if (subModule is SystemVerilog) {
160-
singleUseSignals.removeAll(subModule.expressionlessInputs.map((e) =>
161-
instantiation.inputMapping[e] ?? instantiation.inOutMapping[e]));
162-
}
163-
// ignore: deprecated_member_use_from_same_package
164-
else if (subModule is CustomSystemVerilog) {
165-
singleUseSignals.removeAll(subModule.expressionlessInputs.map((e) =>
166-
instantiation.inputMapping[e] ?? instantiation.inOutMapping[e]));
167-
}
168-
}
169-
17092
final synthLogicToInlineableSynthSubmoduleMap =
17193
<SynthLogic, SystemVerilogSynthSubModuleInstantiation>{};
172-
for (final subModuleInstantiation
173-
in singleUsageInlineableSubmoduleInstantiations) {
174-
(subModuleInstantiation.module as InlineSystemVerilog).resultSignalName;
175-
94+
for (final subModuleInstantiation in chainableModulesToCollapse
95+
.cast<SystemVerilogSynthSubModuleInstantiation>()) {
17696
// inlineable modules have only 1 result signal
17797
final resultSynthLogic = subModuleInstantiation.inlineResultLogic!;
17898

@@ -189,8 +109,10 @@ class SystemVerilogSynthModuleDefinition extends SynthModuleDefinition {
189109
for (final subModuleInstantiation in subModuleInstantiations) {
190110
subModuleInstantiation as SystemVerilogSynthSubModuleInstantiation;
191111

192-
subModuleInstantiation.synthLogicToInlineableSynthSubmoduleMap =
193-
synthLogicToInlineableSynthSubmoduleMap;
112+
subModuleInstantiation.synthLogicToInlineableSynthSubmoduleMap = {
113+
...?subModuleInstantiation.synthLogicToInlineableSynthSubmoduleMap,
114+
...synthLogicToInlineableSynthSubmoduleMap,
115+
};
194116
}
195117
}
196118

@@ -199,11 +121,12 @@ class SystemVerilogSynthModuleDefinition extends SynthModuleDefinition {
199121
/// [_NetConnect] assignment instead of a normal assignment.
200122
void _replaceInOutConnectionInlineableModules() {
201123
for (final subModuleInstantiation in subModuleInstantiations.toList().where(
202-
(e) =>
203-
e.module is InlineSystemVerilog &&
204-
e.needsInstantiation &&
205-
e.outputMapping.isEmpty &&
206-
e.inOutMapping.isNotEmpty)) {
124+
(e) =>
125+
e.module is InlineSystemVerilog &&
126+
e.needsInstantiation &&
127+
e.outputMapping.isEmpty &&
128+
e.inOutMapping.isNotEmpty,
129+
)) {
207130
// algorithm:
208131
// - mark module as not needing declaration
209132
// - add a net_connect
@@ -225,8 +148,10 @@ class SystemVerilogSynthModuleDefinition extends SynthModuleDefinition {
225148
parentSynthModuleDefinition: this,
226149
);
227150

228-
final netConnectSynthSubmod = _addNetConnect(subModResult, dummy)
229-
..synthLogicToInlineableSynthSubmoduleMap ??= {};
151+
final netConnectSynthSubmod = _addNetConnect(
152+
subModResult,
153+
dummy,
154+
)..synthLogicToInlineableSynthSubmoduleMap ??= {};
230155

231156
netConnectSynthSubmod.synthLogicToInlineableSynthSubmoduleMap![dummy] =
232157
subModuleInstantiation;
@@ -260,19 +185,21 @@ class _NetConnect extends Module with SystemVerilog {
260185
_NetConnect(LogicNet n0, LogicNet n1)
261186
: assert(n0.width == n1.width, 'Widths must be equal.'),
262187
width = n0.width,
263-
super(
264-
definitionName: _definitionName,
265-
name: _definitionName,
266-
) {
188+
super(definitionName: _definitionName, name: _definitionName) {
267189
n0 = addInOut(n0Name, n0, width: width);
268190
n1 = addInOut(n1Name, n1, width: width);
269191
}
270192

271193
@override
272194
String instantiationVerilog(
273-
String instanceType, String instanceName, Map<String, String> ports) {
274-
assert(instanceType == _definitionName,
275-
'Instance type selected should match the definition name.');
195+
String instanceType,
196+
String instanceName,
197+
Map<String, String> ports,
198+
) {
199+
assert(
200+
instanceType == _definitionName,
201+
'Instance type selected should match the definition name.',
202+
);
276203
return '$instanceType'
277204
' #(.WIDTH($width))'
278205
' $instanceName'

lib/src/synthesizers/systemverilog/systemverilog_synthesizer.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2021-2025 Intel Corporation
1+
// Copyright (C) 2021-2026 Intel Corporation
22
// SPDX-License-Identifier: BSD-3-Clause
33
//
44
// systemverilog_synthesizer.dart

0 commit comments

Comments
 (0)