Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
82e900e
move synthesis naming to a common naming utility so all synthesizers …
desmonddak Apr 17, 2026
85f88ce
dart 3.11 parameter_assignments pickiness
desmonddak Apr 17, 2026
b1de1e5
Merge branch 'main' into central_naming
desmonddak Apr 17, 2026
b7087c4
conflict resolved and dart format . works
desmonddak Apr 17, 2026
4a55214
properly assign naming spaces for instances vs signals
desmonddak Apr 18, 2026
ed7be36
format issue
desmonddak Apr 18, 2026
ab09aed
Controllable enforcement of signal vs instance name uniqueness.
desmonddak Apr 19, 2026
520d280
Refactored to Namer class. No external API changes for ROHD
desmonddak Apr 19, 2026
61d0319
signal registry
desmonddak Apr 20, 2026
becdb36
module context name uniquification instead of signal/instance split
desmonddak May 1, 2026
a86f80c
Merge branch 'main' into central_naming
desmonddak May 3, 2026
d5904a6
cleanup of port vs signal name assumptions, constant merging and sign…
desmonddak May 3, 2026
6dfe0f9
simplified forModule, improved code doc
desmonddak May 12, 2026
3c90e5d
more coverage for Namer
desmonddak May 12, 2026
42fba62
canonical names at last, even in the comments
desmonddak Jun 12, 2026
6a41f8d
pesky override rule surfaced again on tutorials file
desmonddak Jun 12, 2026
139280f
new keyring-based installation for dart in codespaces
desmonddak Jun 12, 2026
62e4a2c
new keyring-based installation for dart in codespaces
desmonddak Jun 12, 2026
caecb02
keyring-style dart installation rather than holding keys
desmonddak Jun 14, 2026
089faf8
new dart analyzer failure with bad override
desmonddak Jun 14, 2026
e015889
Merge branch 'override-bug' into new-dart
desmonddak Jun 14, 2026
1232afb
Potential fix for pull request finding
desmonddak Jun 15, 2026
e558a4d
Orthogonalize: simplify Namer by removing instance name caching
desmonddak Jun 17, 2026
8ef6820
Fix orthogonalized Namer: remove stale instanceNameOf method
desmonddak Jun 17, 2026
1225df1
Clean DevTools extension analysis and formatting
desmonddak Jun 20, 2026
c8440c4
Keep DevTools extension changes on owning branches
desmonddak Jun 20, 2026
a87fa5c
added back pubkeys, and made a wget a fallback solution with loud war…
desmonddak Jun 21, 2026
d2760eb
Merge branch 'new-dart' into central_naming
desmonddak Jun 22, 2026
b7e46c0
Add instanceNameOf to Namer: cached instance-name lookup
desmonddak Jun 22, 2026
0f13c7b
Move instanceNameOf stability test to central_naming
desmonddak Jun 22, 2026
319706b
Wire pickName through instanceNameOf for stable instance names
desmonddak Jun 22, 2026
11bc2cd
Add instance-signal namespace collision stability tests
desmonddak Jun 22, 2026
3b8a8a8
consistency in naming
desmonddak Jun 22, 2026
249b210
Clean up Namer allocation API
desmonddak Jun 24, 2026
e35373a
Stabilize naming around collapsible synth objects
desmonddak Jun 24, 2026
ddd96f1
heuristic to mark potentially collapsed nodes for lower priority naming
desmonddak Jun 24, 2026
dd07852
bias collapsible Logics for weak naming
desmonddak Jun 24, 2026
9bf137e
update naming heuristic pickNames comment
desmonddak Jun 24, 2026
efdf60b
pana error on getter
desmonddak Jun 24, 2026
a783956
small change to reduce conflicts
desmonddak Jun 25, 2026
fa05887
small change to reduce conflicts2
desmonddak Jun 25, 2026
5edbfde
small change to reduce conflicts3
desmonddak Jun 25, 2026
afec985
small change to reduce conflicts4
desmonddak Jun 25, 2026
2e933cd
small change to reduce conflicts5
desmonddak Jun 25, 2026
1f5ef48
cleaned up redundant code
desmonddak Jun 25, 2026
ecec474
stick with Set<SynthNet> ordering
desmonddak Jun 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import '../../chapter_3/answers/helper.dart';
import '../../chapter_5/answers/full_subtractor.dart';

class FullSubtractorComb extends FullSubtractor {
@override
FullSubtractorComb(super.a, super.b, super.borrowIn) {
// Declare input and output
final a = input('a');
Expand Down
7 changes: 4 additions & 3 deletions lib/src/exceptions/logic/put_exception.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@

import 'package:rohd/rohd.dart';

/// An exception that thrown when a [Logic] signal fails to `put`.
/// An exception that thrown when a [Logic] signal fails to [Logic.put].
class PutException extends RohdException {
/// Creates an exception for when a `put` fails on a `Logic` with [context] as
/// to where the
/// Creates an exception for when a [Logic.put] fails on a [Logic] with
/// [context] as to where the failure occurred and [message] describing the
/// failure.
PutException(String context, String message)
: super('Failed to put value on signal ($context): $message');
}
28 changes: 26 additions & 2 deletions lib/src/module.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2021-2025 Intel Corporation
// Copyright (C) 2021-2026 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// module.dart
Expand All @@ -11,11 +11,11 @@ import 'dart:async';
import 'dart:collection';

import 'package:meta/meta.dart';

import 'package:rohd/rohd.dart';
import 'package:rohd/src/collections/traverseable_collection.dart';
import 'package:rohd/src/diagnostics/inspector_service.dart';
import 'package:rohd/src/utilities/config.dart';
import 'package:rohd/src/utilities/namer.dart';
import 'package:rohd/src/utilities/sanitizer.dart';
import 'package:rohd/src/utilities/timestamper.dart';
import 'package:rohd/src/utilities/uniquifier.dart';
Expand Down Expand Up @@ -52,6 +52,18 @@ abstract class Module {
/// An internal mapping of input names to their sources to this [Module].
late final Map<String, Logic> _inputSources = {};

// ─── Central naming (Namer) ─────────────────────────────────────

/// Central namer that owns both the signal and instance namespaces.
/// Initialized lazily on first access (after build).
@internal
late final Namer namer = _createNamer();

Namer _createNamer() {
assert(hasBuilt, 'Module must be built before canonical names are bound.');
return Namer.forModule(this);
}

/// An internal mapping of inOut names to their sources to this [Module].
late final Map<String, Logic> _inOutSources = {};

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

/// A stable identity used to memoize this module's canonical instance name
/// across repeated synthesis passes (e.g. netlist then SystemVerilog).
///
/// Defaults to the [Module] itself, which is correct for modules that are
/// part of the built hierarchy and therefore persist across passes.
/// Synthesis-time throwaway modules that are *recreated* on every pass (and
/// thus have a fresh [Module] identity each time) must override this to
/// return a stable identity — typically the [Logic] they drive — so their
/// instance name does not drift run-to-run.
@internal
Object get instanceNameKey => this;
Comment thread
desmonddak marked this conversation as resolved.

/// If true, guarantees [uniqueInstanceName] matches [name] or else the
/// [build] will fail.
final bool reserveName;
Expand Down
2 changes: 1 addition & 1 deletion lib/src/synthesizers/synth_builder.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2021-2025 Intel Corporation
// Copyright (C) 2021-2026 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// synth_builder.dart
Expand Down
3 changes: 1 addition & 2 deletions lib/src/synthesizers/synthesizer.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// Copyright (C) 2021-2023 Intel Corporation
// Copyright (C) 2021-2026 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// synthesizer.dart
// Generic definition for something that synthesizes output files
//
// 2021 August 26
// Author: Max Korbel <max.korbel@intel.com>
//

import 'package:rohd/rohd.dart';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class SystemVerilogSynthModuleDefinition extends SynthModuleDefinition {

@override
void process() {
_replaceNetConnections();
_collapseChainableModules();
_buildNetConnectsForNaming();
_collapseMarkedChainableModules();
_replaceInOutConnectionInlineableModules();
}

Expand All @@ -30,34 +30,41 @@ class SystemVerilogSynthModuleDefinition extends SynthModuleDefinition {
/// Creates a new [_NetConnect] module to synthesize assignment between two
/// [LogicNet]s.
SystemVerilogSynthSubModuleInstantiation _addNetConnect(
SynthLogic dst, SynthLogic src) {
SynthLogic dst,
SynthLogic src,
) {
// make an (unconnected) module representing the assignment
final netConnect =
_NetConnect(LogicNet(width: dst.width), LogicNet(width: src.width));
final netConnect = _NetConnect(
LogicNet(width: dst.width),
LogicNet(width: src.width),
);

// instantiate the module within the definition
final netConnectSynthSubModInst =
(getSynthSubModuleInstantiation(netConnect)
as SystemVerilogSynthSubModuleInstantiation)

// map inouts to the appropriate `_SynthLogic`s
..setInOutMapping(_NetConnect.n0Name, dst)
..setInOutMapping(_NetConnect.n1Name, src);

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

netConnectSynthSubModInst.pickName(module);

return netConnectSynthSubModInst;
}

/// Replace all [assignments] between two [LogicNet]s with a [_NetConnect].
void _replaceNetConnections() {
/// Builds [_NetConnect] instances for [LogicNet] assignments.
void _buildNetConnectsForNaming() {
final reducedAssignments = <SynthAssignment>[];

for (final assignment in assignments) {
if (assignment.src.isNet && assignment.dst.isNet) {
assert(assignment is! PartialSynthAssignment,
'Net connections should not be partial assignments.');
assert(
assignment is! PartialSynthAssignment,
'Net connections should not be partial assignments.',
);

_addNetConnect(assignment.dst, assignment.src);
} else {
Expand All @@ -73,106 +80,19 @@ class SystemVerilogSynthModuleDefinition extends SynthModuleDefinition {
}
}

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

// Also feed collapsed chained modules into other modules
// Need to consider order of operations in systemverilog or else add ()
// everywhere! (for now add the parentheses)

// Algorithm:
// - find submodule instantiations that are inlineable
// - filter to those who only output as input to one other module
// - pass an override to the submodule instantiation that the corresponding
// input should map to the output of another submodule instantiation
// do not collapse if signal feeds to multiple inputs of other modules

final inlineableSubmoduleInstantiations = module.subModules
.whereType<InlineSystemVerilog>()
.map((m) => getSynthSubModuleInstantiation(m)
as SystemVerilogSynthSubModuleInstantiation);

// number of times each signal name is used by any module
final signalUsage = <SynthLogic, int>{};

for (final subModuleInstantiation in subModuleInstantiations) {
for (final inSynthLogic in [
...subModuleInstantiation.inputMapping.values,
...subModuleInstantiation.inOutMapping.values
]) {
if (inputs.contains(inSynthLogic) || inOuts.contains(inSynthLogic)) {
// dont worry about inputs to THIS module
continue;
}

subModuleInstantiation as SystemVerilogSynthSubModuleInstantiation;

if (subModuleInstantiation.inlineResultLogic == inSynthLogic) {
// don't worry about the result signal
continue;
}

signalUsage.update(
inSynthLogic,
(value) => value + 1,
ifAbsent: () => 1,
);
}
}

final singleUseSignals = <SynthLogic>{};
signalUsage.forEach((signal, signalUsageCount) {
// don't collapse if:
// - used more than once
// - inline modules for preferred names
if (signalUsageCount == 1 && signal.mergeable) {
singleUseSignals.add(signal);
}
});

// partial assignments are a special case, count as a usage
for (final partialAssignment
in assignments.whereType<PartialSynthAssignment>()) {
singleUseSignals.remove(partialAssignment.src);
}

final singleUsageInlineableSubmoduleInstantiations =
inlineableSubmoduleInstantiations.where((subModuleInstantiation) {
// inlineable modules have only 1 result signal
final resultSynthLogic = subModuleInstantiation.inlineResultLogic!;

return singleUseSignals.contains(resultSynthLogic) &&

// don't inline modules if they were cleared from instantiation
subModuleInstantiation.needsInstantiation;
});

// remove any inlineability for those that want no expressions
for (final instantiation in subModuleInstantiations) {
final subModule = instantiation.module;
if (subModule is SystemVerilog) {
singleUseSignals.removeAll(subModule.expressionlessInputs.map((e) =>
instantiation.inputMapping[e] ?? instantiation.inOutMapping[e]));
}
// ignore: deprecated_member_use_from_same_package
else if (subModule is CustomSystemVerilog) {
singleUseSignals.removeAll(subModule.expressionlessInputs.map((e) =>
instantiation.inputMapping[e] ?? instantiation.inOutMapping[e]));
}
}

final synthLogicToInlineableSynthSubmoduleMap =
<SynthLogic, SystemVerilogSynthSubModuleInstantiation>{};
for (final subModuleInstantiation
in singleUsageInlineableSubmoduleInstantiations) {
(subModuleInstantiation.module as InlineSystemVerilog).resultSignalName;

for (final subModuleInstantiation in chainableModulesToCollapse
.cast<SystemVerilogSynthSubModuleInstantiation>()) {
// inlineable modules have only 1 result signal
final resultSynthLogic = subModuleInstantiation.inlineResultLogic!;

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

subModuleInstantiation.synthLogicToInlineableSynthSubmoduleMap =
synthLogicToInlineableSynthSubmoduleMap;
subModuleInstantiation.synthLogicToInlineableSynthSubmoduleMap = {
...?subModuleInstantiation.synthLogicToInlineableSynthSubmoduleMap,
...synthLogicToInlineableSynthSubmoduleMap,
};
}
}

Expand All @@ -199,11 +121,12 @@ class SystemVerilogSynthModuleDefinition extends SynthModuleDefinition {
/// [_NetConnect] assignment instead of a normal assignment.
void _replaceInOutConnectionInlineableModules() {
for (final subModuleInstantiation in subModuleInstantiations.toList().where(
(e) =>
e.module is InlineSystemVerilog &&
e.needsInstantiation &&
e.outputMapping.isEmpty &&
e.inOutMapping.isNotEmpty)) {
(e) =>
e.module is InlineSystemVerilog &&
e.needsInstantiation &&
e.outputMapping.isEmpty &&
e.inOutMapping.isNotEmpty,
)) {
// algorithm:
// - mark module as not needing declaration
// - add a net_connect
Expand All @@ -225,8 +148,10 @@ class SystemVerilogSynthModuleDefinition extends SynthModuleDefinition {
parentSynthModuleDefinition: this,
);

final netConnectSynthSubmod = _addNetConnect(subModResult, dummy)
..synthLogicToInlineableSynthSubmoduleMap ??= {};
final netConnectSynthSubmod = _addNetConnect(
subModResult,
dummy,
)..synthLogicToInlineableSynthSubmoduleMap ??= {};

netConnectSynthSubmod.synthLogicToInlineableSynthSubmoduleMap![dummy] =
subModuleInstantiation;
Expand Down Expand Up @@ -260,19 +185,21 @@ class _NetConnect extends Module with SystemVerilog {
_NetConnect(LogicNet n0, LogicNet n1)
: assert(n0.width == n1.width, 'Widths must be equal.'),
width = n0.width,
super(
definitionName: _definitionName,
name: _definitionName,
) {
super(definitionName: _definitionName, name: _definitionName) {
n0 = addInOut(n0Name, n0, width: width);
n1 = addInOut(n1Name, n1, width: width);
}

@override
String instantiationVerilog(
String instanceType, String instanceName, Map<String, String> ports) {
assert(instanceType == _definitionName,
'Instance type selected should match the definition name.');
String instanceType,
String instanceName,
Map<String, String> ports,
) {
assert(
instanceType == _definitionName,
'Instance type selected should match the definition name.',
);
return '$instanceType'
' #(.WIDTH($width))'
' $instanceName'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2021-2025 Intel Corporation
// Copyright (C) 2021-2026 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// systemverilog_synthesizer.dart
Expand Down
Loading
Loading