Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e6cfe51
refactored synthesizers to be more modular, passing tests
mkorbel1 Nov 26, 2024
ccbd415
minor tweaks
mkorbel1 Dec 16, 2024
2262dfe
refactor to return multiple file contents
mkorbel1 Dec 27, 2024
8dc3c9c
add a reminder todo for issue
mkorbel1 Dec 30, 2024
231a4c4
initial work on LogicEnum
mkorbel1 Jun 24, 2025
f170ef1
Merge branch 'main' of github.com:intel/rohd into logic_enum
mkorbel1 Jun 24, 2025
6e4e297
Merge branch 'main' of github.com:intel/rohd into synth_modularity
mkorbel1 Jun 24, 2025
b2834f5
deprecate ane make new names, to preserve backwards compatibility
mkorbel1 Jun 24, 2025
0157952
adjust apis a bit
mkorbel1 Jun 24, 2025
97790a9
tested that multi top works in synth builder
mkorbel1 Jun 24, 2025
dda9399
test more stuff about synthfilecontents
mkorbel1 Jun 25, 2025
4e9c373
cleanup and docs
mkorbel1 Jun 25, 2025
fd6c0cb
update docs a bit
mkorbel1 Jun 25, 2025
bc93467
tweaks to docs
mkorbel1 Jun 25, 2025
748d652
Merge branch 'synth_modularity' into logic_enum
mkorbel1 Jun 25, 2025
0fa161f
wip enum sv gen
mkorbel1 Jun 25, 2025
d8c9fab
try a new runner
mkorbel1 Jun 25, 2025
64fb5e3
Merge branch 'main' of github.com:intel/rohd into logic_enum
mkorbel1 Jun 25, 2025
2d1b65e
wip implementing enum stuff
mkorbel1 Jun 27, 2025
8177d88
first basic test passing with enum sorta
mkorbel1 Jun 30, 2025
d51be81
basic sv gen testing
mkorbel1 Jun 30, 2025
09c11cf
got enum and const merging working better
mkorbel1 Jun 30, 2025
b645199
got some basic cond type passing working
mkorbel1 Jul 1, 2025
7ca82de
got basic case and condassign working with type matching
mkorbel1 Jul 1, 2025
97a8926
added actual logicenum type support for conds
mkorbel1 Jul 1, 2025
0b39f1d
got cases special case for enum
mkorbel1 Jul 2, 2025
0c451d6
wip enum stuff
mkorbel1 Jul 8, 2025
97dccee
some todos
mkorbel1 Jul 9, 2025
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 @@ -16,7 +16,7 @@ jobs:
name: Run Checks
permissions: {}
timeout-minutes: 60
runs-on: ${{ github.repository_owner == 'intel' && 'intel-ubuntu-latest' || 'ubuntu-latest' }}
runs-on: 'jf5-ubuntu-latest' #${{ github.repository_owner == 'intel' && 'intel-ubuntu-latest' || 'ubuntu-latest' }}
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down
26 changes: 14 additions & 12 deletions lib/src/finite_state_machine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import 'package:rohd/rohd.dart';

/// Deprecated: use [FiniteStateMachine] instead.
@Deprecated('Use FiniteStateMachine instead')
typedef StateMachine<T> = FiniteStateMachine<T>;
typedef StateMachine<T extends Enum> = FiniteStateMachine<T>;

/// Simple class for FSM [FiniteStateMachine].
///
/// Abstraction for representing Finite state machines (FSM).
/// Contains the logic for performing the state transitions.
class FiniteStateMachine<StateIdentifier> {
class FiniteStateMachine<StateIdentifier extends Enum> {
/// List of all the [State]s in this machine.
List<State<StateIdentifier>> get states => UnmodifiableListView(_states);
final List<State<StateIdentifier>> _states;
Expand Down Expand Up @@ -71,7 +71,8 @@ class FiniteStateMachine<StateIdentifier> {
///
/// Use [getStateIndex] to map from a [StateIdentifier] to the value on this
/// bus.
final Logic currentState;
late final LogicEnum<StateIdentifier> currentState =
stateEnum(name: 'currentState');

/// A [List] of [Conditional] actions to perform at the beginning of the
/// evaluation of actions for the [FiniteStateMachine]. This is useful for
Expand All @@ -82,7 +83,8 @@ class FiniteStateMachine<StateIdentifier> {
///
/// Use [getStateIndex] to map from a [StateIdentifier] to the value on this
/// bus.
final Logic nextState;
late final LogicEnum<StateIdentifier> nextState =
stateEnum(name: 'nextState');

/// Returns a ceiling on the log of [x] base [base].
static int _logBase(num x, num base) => (log(x) / log(base)).ceil();
Expand All @@ -93,6 +95,9 @@ class FiniteStateMachine<StateIdentifier> {
/// If `true`, the [reset] signal is asynchronous.
final bool asyncReset;

LogicEnum<StateIdentifier> stateEnum({String? name}) =>
LogicEnum<StateIdentifier>.withMapping(stateIndexLookup, name: name);

/// Creates an finite state machine for the specified list of [_states], with
/// an initial state of [resetState] (when synchronous [reset] is high) and
/// transitions on positive [clk] edges.
Expand All @@ -119,11 +124,7 @@ class FiniteStateMachine<StateIdentifier> {
this.asyncReset = false,
List<Conditional> setupActions = const [],
}) : setupActions = List.unmodifiable(setupActions),
stateWidth = _logBase(_states.length, 2),
currentState =
Logic(name: 'currentState', width: _logBase(_states.length, 2)),
nextState =
Logic(name: 'nextState', width: _logBase(_states.length, 2)) {
stateWidth = _logBase(_states.length, 2) {
_validate();

var stateCounter = 0;
Expand All @@ -138,8 +139,9 @@ class FiniteStateMachine<StateIdentifier> {
currentState,
_states
.map((state) => CaseItem(
Const(_stateValueLookup[state], width: stateWidth)
.named(state.identifier.toString()),
stateEnum()..getsEnum(state.identifier),
// Const(_stateValueLookup[state], width: stateWidth)
// .named(state.identifier.toString()),
[
...state.actions,
Case(
Expand Down Expand Up @@ -226,7 +228,7 @@ class FiniteStateMachine<StateIdentifier> {
}

/// Simple class to initialize each state of the FSM.
class State<StateIdentifier> {
class State<StateIdentifier extends Enum> {
/// Identifier or name of the state.
final StateIdentifier identifier;

Expand Down
12 changes: 12 additions & 0 deletions lib/src/module.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ abstract class Module {
/// An internal mapping of inOut names to their sources to this [Module].
late final Map<String, Logic> _inOutSources = {};

/// A mapping between [inputs], [outputs], and/or [inOuts] which must have the
/// same type as each other. The keys of the map will be updated to match the
/// type of the values.
///
/// This is used for type checking for [LogicEnum]s through [Conditional]s.
///
/// NOTE: This is for internal usage only, and the API will not be guaranteed
/// to be stable.
@internal
final Map<Logic, Logic> portTypePairs = {};

/// The parent [Module] of this [Module].
///
/// This only gets populated after its parent [Module], if it exists, has
Expand Down Expand Up @@ -307,6 +318,7 @@ abstract class Module {

// set unique module instance names for submodules
final uniquifier = Uniquifier();
//TODO: BUG! we must guarantee this unique name is the same one used for generation!?
for (final module in _subModules) {
module._uniqueInstanceName = uniquifier.getUniqueName(
initialName: Sanitizer.sanitizeSV(module.name),
Expand Down
8 changes: 8 additions & 0 deletions lib/src/modules/conditionals/always.dart
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,11 @@ abstract class Always extends Module with SystemVerilog {
// share the registration information down
conditional.updateAssignmentMaps(
assignedReceiverToOutputMap, assignedDriverToInputMap);

portTypePairs.addAll(conditional.portTypePairs.map((k, v) => MapEntry(
conditional.driverOrReceiverPort(k),
conditional.driverOrReceiverPort(v),
)));
}
}

Expand Down Expand Up @@ -177,6 +182,9 @@ abstract class Always extends Module with SystemVerilog {
final outputs = Map.fromEntries(ports.entries
.where((element) => this.outputs.containsKey(element.key)));

assert(ports.length == inputs.length + outputs.length,
'All ports of an always should be inputs or outputs');

var verilog = '';
verilog += '// $instanceName\n';
verilog += '${alwaysVerilogStatement(inputs)} begin\n';
Expand Down
19 changes: 16 additions & 3 deletions lib/src/modules/conditionals/case.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,11 @@ Logic cases(Logic expression, Map<dynamic, dynamic> conditions,
[
for (final condition in conditions.entries)
CaseItem(
condition.key is Logic
? condition.key as Logic
: Const(condition.key, width: expression.width),
(expression is LogicEnum && condition.key is Enum)
? (expression.clone()..getsEnum(condition.key as Enum))
: condition.key is Logic
? condition.key as Logic
: Const(condition.key, width: expression.width),
[result < condition.value])
],
conditionalType: conditionalType,
Expand Down Expand Up @@ -125,6 +127,15 @@ class Case extends Conditional {
/// See [ConditionalType] for more details.
final ConditionalType conditionalType;

@override
Map<Logic, Logic> get portTypePairs => {
...super.portTypePairs,
..._itemTypePortPairs,
};

//TODO doc
final Map<Logic, Logic> _itemTypePortPairs = {};

/// Whenever an item in [items] matches [expression], it will be executed.
///
/// If none of [items] match, then [defaultItem] is executed.
Expand All @@ -136,6 +147,8 @@ class Case extends Conditional {
if (item.value.width != expression.width) {
throw PortWidthMismatchException.equalWidth(expression, item.value);
}

_itemTypePortPairs[item.value] = expression;
}
}

Expand Down
17 changes: 17 additions & 0 deletions lib/src/modules/conditionals/conditional.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ abstract class Conditional {
Logic receiverOutput(Logic receiver) =>
_assignedReceiverToOutputMap[receiver]!;

//TODO: do we like this API?
@protected
Logic driverOrReceiverPort(Logic driverOrReceiver) =>
_assignedDriverToInputMap[driverOrReceiver] ??
_assignedReceiverToOutputMap[driverOrReceiver] ??
(throw Exception(//TODO: exception
'Logic $driverOrReceiver is not a driver or receiver in this Conditional.'));

/// Executes the functionality of this [Conditional] and
/// populates [drivenSignals] with all [Logic]s that were driven
/// during execution.
Expand Down Expand Up @@ -120,6 +128,15 @@ abstract class Conditional {
/// Does *not* recursively call down through sub-[Conditional]s.
List<Conditional> get conditionals;

/// A mapping between [receivers] and [drivers] to be fed up to the enclosing
/// [Combinational] or [Sequential]'s [Module.portTypePairs].
///
/// NOTE: This is for internal usage only, and the API will not be guaranteed
/// to be stable.
@internal
Map<Logic, Logic> get portTypePairs =>
{for (final cond in conditionals) ...cond.portTypePairs};

/// Returns a [String] of SystemVerilog to be used in generated output.
///
/// The [indent] is used for pretty-printing, and should generally be
Expand Down
11 changes: 7 additions & 4 deletions lib/src/modules/conditionals/conditional_assign.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,18 @@ import 'package:rohd/src/modules/conditionals/ssa.dart';

/// An assignment that only happens under certain conditions.
///
/// [Logic] has a short-hand for creating [ConditionalAssign] via the
/// `<` operator.
/// [Logic] has a short-hand for creating [ConditionalAssign] via the `<`
/// operator.
class ConditionalAssign extends Conditional {
/// The input to this assignment.
/// The receiver for this assignment.
final Logic receiver;

/// The output of this assignment.
/// The driver for this assignment.
final Logic driver;

@override
Map<Logic, Logic> get portTypePairs => {driver: receiver};

/// Conditionally assigns [receiver] to the value of [driver].
ConditionalAssign(this.receiver, this.driver) {
if (driver.width != receiver.width) {
Expand Down
9 changes: 5 additions & 4 deletions lib/src/signals/logic.dart
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,8 @@ class Logic {

/// Handles the actual connection of this [Logic] to be driven by [other].
void _connect(Logic other) {
_unassignable = true;
makeUnassignable(reason: '$this is connected to $other.');

if (other is LogicNet) {
put(other.value);
other.glitch.listen((args) {
Expand Down Expand Up @@ -670,11 +671,11 @@ class Logic {
/// [Conditional].
Conditional operator <(dynamic other) {
if (_unassignable) {
throw Exception('This signal "$this" has been marked as unassignable. '
'It may be a constant expression or otherwise'
' should not be assigned.');
throw UnassignableException(this, reason: _unassignableReason);
}

//TODO: add support for enum types

if (other is Logic) {
return ConditionalAssign(this, other);
} else {
Expand Down
20 changes: 20 additions & 0 deletions lib/src/signals/logic_def.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
part of 'signals.dart';

@internal
sealed class LogicDef extends Logic {
final bool reserveDefinitionName;

// TODO: test naming conflicts in generated RTL
String get definitionName =>
Sanitizer.sanitizeSV(_definitionName ?? runtimeType.toString());
final String? _definitionName;

LogicDef({
super.width,
super.name,
super.naming,
String? definitionName,
this.reserveDefinitionName = false,
}) : _definitionName = Naming.validatedName(definitionName,
reserveName: reserveDefinitionName);
}
Loading
Loading