Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 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
76a29f5
devtools improvements
desmonddak Apr 18, 2026
3042c91
downgrade vm for flutter test
desmonddak Apr 18, 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
be1b5f7
converged into a single helper widget package
desmonddak Apr 20, 2026
a59ac39
upgrade Node to v24
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
1c4ec07
Merge branch 'main' into devtool_utilities
desmonddak May 3, 2026
3e103f9
Add ModuleServices singleton and SvService
desmonddak May 6, 2026
09569a8
devtools improvements
desmonddak Apr 18, 2026
7c8db1a
downgrade vm for flutter test
desmonddak Apr 18, 2026
fd6cf80
converged into a single helper widget package
desmonddak Apr 20, 2026
528fdf5
upgrade Node to v24
desmonddak Apr 20, 2026
35c20fb
Migrate tree_service.dart to ModuleServices.instance.hierarchyJSON
desmonddak May 6, 2026
4b895a6
fix: use tearoff for tearDown (unnecessary_lambdas)
desmonddak May 12, 2026
aa8658a
Merge branch 'devtool_utilities' of https://github.com/desmonddak/roh…
desmonddak May 12, 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
2 changes: 1 addition & 1 deletion .github/workflows/general.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 24

- name: Setup Pana source analysis
run: tool/gh_actions/install_pana.sh
Expand Down
4 changes: 4 additions & 0 deletions devtools_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
- rohd: true
2 changes: 1 addition & 1 deletion extension/devtools/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ name: rohd
issueTracker: https://github.com/intel/rohd/issues
version: 0.0.1
materialIconCodePoint: '0xe1c5'
requiresConnection: true # optional field - defaults to true
requiresConnection: false
1 change: 1 addition & 0 deletions lib/rohd.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (C) 2021-2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause

export 'src/diagnostics/module_services.dart';
export 'src/exceptions/exceptions.dart';
export 'src/external.dart';
export 'src/finite_state_machine.dart';
Expand Down
78 changes: 78 additions & 0 deletions lib/src/diagnostics/module_services.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (C) 2026 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// module_services.dart
// Singleton service registry for DevTools integration.
//
// 2026 April 25
// Author: Desmond Kirkpatrick <desmond.a.kirkpatrick@intel.com>

import 'dart:convert';

import 'package:rohd/rohd.dart';
import 'package:rohd/src/diagnostics/inspector_service.dart';

/// Singleton service registry that provides a unified query surface for
/// DevTools and other inspection tools.
///
/// Services register themselves here on construction; DevTools evaluates
/// getters on [instance] via `EvalOnDartLibrary` to pull data.
///
/// **Auto-registered:**
/// - [rootModule] / [hierarchyJSON] — set by [Module.build].
///
/// **Opt-in (registered by service constructors):**
/// - [svService] — SystemVerilog synthesis results.
///
/// Additional services (netlist, trace, waveform) can be added by setting
/// the corresponding field after construction.
class ModuleServices {
ModuleServices._();

/// The singleton instance.
static final ModuleServices instance = ModuleServices._();

// ─── Hierarchy (auto-registered by Module.build) ──────────────

/// The most recently built top-level [Module].
///
/// Set automatically at the end of [Module.build].
Module? rootModule;

/// Returns the module hierarchy as a JSON string.
///
/// DevTools evaluates this via `EvalOnDartLibrary` to display
/// the module hierarchy.
String get hierarchyJSON {
ModuleTree.rootModuleInstance = rootModule;
return ModuleTree.instance.hierarchyJSON;
}

/// Returns the primary inspector JSON for DevTools.
///
/// Returns the hierarchy JSON. Downstream branches (e.g. netlist) may
/// override this to return richer data when available.
String get inspectorJSON => hierarchyJSON;

// ─── SystemVerilog service (opt-in) ───────────────────────────

/// The active [SvService], if one has been registered.
SvService? svService;

/// Returns SV synthesis metadata as JSON, or an unavailable status.
String get svJSON =>
svService != null ? jsonEncode(svService!.toJson()) : _unavailable('sv');

// ─── Helpers ──────────────────────────────────────────────────

static String _unavailable(String service) => jsonEncode(<String, String>{
'status': 'unavailable',
'reason': '$service service not registered',
});

/// Resets all services. Intended for test teardown.
void reset() {
rootModule = null;
svService = null;
}
}
23 changes: 19 additions & 4 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,10 @@ 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 +51,22 @@ 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(
inputs: _inputs,
outputs: _outputs,
inOuts: _inOuts,
);
}

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

Expand Down Expand Up @@ -317,7 +332,7 @@ abstract class Module {

_hasBuilt = true;

ModuleTree.rootModuleInstance = this;
ModuleServices.instance.rootModule = this;
}

/// Confirms that the post-[build] hierarchy is valid.
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
114 changes: 114 additions & 0 deletions lib/src/synthesizers/systemverilog/sv_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright (C) 2026 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// sv_service.dart
// Service wrapper for SystemVerilog synthesis.
//
// 2026 April 25
// Author: Desmond Kirkpatrick <desmond.a.kirkpatrick@intel.com>

import 'dart:io';

import 'package:collection/collection.dart';
import 'package:rohd/rohd.dart';

/// A service that wraps SystemVerilog synthesis of a [Module] hierarchy.
///
/// Provides access to the generated SV file contents and per-module
/// synthesis results, and optionally registers with [ModuleServices]
/// for DevTools inspection.
///
/// Example:
/// ```dart
/// final dut = MyModule(...);
/// await dut.build();
/// final sv = SvService(dut);
///
/// // Write individual .sv files:
/// sv.writeFiles('build/');
///
/// // Or get the concatenated output (like generateSynth):
/// print(sv.allContents);
/// ```
class SvService {
/// The top-level [Module] being synthesized.
final Module module;

/// The underlying [SynthBuilder] that drove synthesis.
late final SynthBuilder synthBuilder;

/// The generated file contents (one per unique module definition).
late final List<SynthFileContents> fileContents;

/// Creates an [SvService] for [module].
///
/// [module] must already be built. Set [register] to `true` (the
/// default) to register this service with [ModuleServices] for
/// DevTools access.
SvService(this.module, {bool register = true}) {
if (!module.hasBuilt) {
throw Exception('Module must be built before creating SvService. '
'Call build() first.');
}

synthBuilder = SynthBuilder(module, SystemVerilogSynthesizer());
fileContents = synthBuilder.getSynthFileContents();

if (register) {
ModuleServices.instance.svService = this;
}
}

/// All [SynthesisResult]s produced by synthesis.
Set<SynthesisResult> get synthesisResults => synthBuilder.synthesisResults;

/// Returns the concatenated SystemVerilog output as a single string,
/// matching the format of [Module.generateSynth].
String get allContents => fileContents.map((fc) => fc.contents).join('\n\n');

/// Returns a map from module definition name to its SV file contents.
///
/// Keys are [SynthesisResult.instanceTypeName] (the uniquified definition
/// name used in the generated SV).
Map<String, String> get contentsByName => {
for (final fc in fileContents) fc.name: fc.contents,
};

/// Returns a map from module definition name
/// ([Module.definitionName]) to its SV file contents.
///
/// This uses the original definition name (not uniquified), matching
/// the keys used by FLC trace data.
Map<String, String> get contentsByDefinitionName {
final result = <String, String>{};
for (final sr in synthesisResults) {
final defName = sr.module.definitionName;
final instanceName = sr.instanceTypeName;
// Find the file content matching this instance type name.
final fc = fileContents.firstWhereOrNull((f) => f.name == instanceName);
if (fc != null) {
result[defName] = fc.contents;
}
}
return result;
}

/// Writes each module's SV to a separate file in [directory].
///
/// Files are named `<definitionName>.sv`.
void writeFiles(String directory) {
final dir = Directory(directory)..createSync(recursive: true);
for (final fc in fileContents) {
File('${dir.path}/${fc.name}.sv').writeAsStringSync(fc.contents);
}
}

/// Returns a JSON-serialisable summary of the SV synthesis.
///
/// Contains the list of generated module definition names.
Map<String, Object> toJson() => <String, Object>{
'modules': [
for (final fc in fileContents) fc.name,
],
};
}
1 change: 1 addition & 0 deletions lib/src/synthesizers/systemverilog/systemverilog.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (C) 2021-2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause

export 'sv_service.dart';
export 'systemverilog_mixins.dart';
export 'systemverilog_synthesizer.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
//
// systemverilog_synthesizer.dart
Expand Down
Loading