Skip to content

Commit

Permalink
Add multi-trigger support to abstractions for async reset, fix #406
Browse files Browse the repository at this point in the history
  • Loading branch information
mkorbel1 committed Sep 19, 2023
1 parent 129ece1 commit 33f249c
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 12 deletions.
28 changes: 22 additions & 6 deletions lib/src/finite_state_machine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,15 @@ class FiniteStateMachine<StateIdentifier> {
return _stateValueLookup[_stateLookup[id]];
}

/// The clock signal to the FSM.
final Logic clk;
/// The clock signal to the FSM (when only single-triggered). Otherwise, the
/// first clock.
///
/// Deprecated: do not reference the clock from [FiniteStateMachine].
@Deprecated('Do not reference the clock from the `FiniteStateMachine`.')
Logic get clk => _clks.first;

/// The clock signals to the FSM.
final List<Logic> _clks;

/// The reset signal to the FSM.
final Logic reset;
Expand All @@ -79,12 +86,21 @@ class FiniteStateMachine<StateIdentifier> {
/// Width of the state.
final int _stateWidth;

//TODO: async reset (#406)

/// 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.
FiniteStateMachine(this.clk, this.reset, this.resetState, this._states)
FiniteStateMachine(
Logic clk,
Logic reset,
StateIdentifier resetState,
List<State<StateIdentifier>> states,
) : this.multi([clk], reset, resetState, states);

/// 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 edges of any of [_clks].
FiniteStateMachine.multi(
this._clks, this.reset, this.resetState, this._states)
: _stateWidth = _logBase(_states.length, 2),
currentState =
Logic(name: 'currentState', width: _logBase(_states.length, 2)),
Expand Down Expand Up @@ -137,7 +153,7 @@ class FiniteStateMachine<StateIdentifier> {
])
]);

Sequential(clk, reset: reset, resetValues: {
Sequential.multi(_clks, reset: reset, resetValues: {
currentState: _stateValueLookup[_stateLookup[resetState]]
}, [
currentState < nextState,
Expand Down
4 changes: 4 additions & 0 deletions lib/src/modules/conditional.dart
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,10 @@ class Sequential extends _Always {
/// specified reset value.
Sequential.multi(List<Logic> clks, super._conditionals,
{super.reset, super.resetValues, super.name = 'sequential'}) {
if (clks.isEmpty) {
throw IllegalConfigurationException('Must provide at least one clock.');
}

for (var i = 0; i < clks.length; i++) {
final clk = clks[i];
if (clk.width > 1) {
Expand Down
50 changes: 44 additions & 6 deletions lib/src/modules/pipeline.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,13 @@ class _PipeStage {

/// A simple pipeline, separating arbitrary combinational logic by flop stages.
class Pipeline {
/// The clock whose positive edge triggers the flops in this pipeline.
final Logic clk;
/// The clock whose positive edge triggers the flops in this pipeline when
/// single-triggered. Otherwise, the first clock.
@Deprecated('Do not reference the clock from the `Pipeline`.')
Logic get clk => _clks.first;

/// The clocks whose positive edges trigger the flops in this pipeline.
final List<Logic> _clks;

/// An optional reset signal for all pipelined signals.
final Logic? reset;
Expand Down Expand Up @@ -112,7 +117,21 @@ class Pipeline {
/// Each stage can be stalled independently using [stalls], where every index
/// of [stalls] corresponds to the index of the stage to be stalled. When
/// a stage's stall is asserted, the output of that stage will not change.
Pipeline(this.clk,
Pipeline(Logic clk,
{List<List<Conditional> Function(PipelineStageInfo p)> stages = const [],
List<Logic?>? stalls,
List<Logic> signals = const [],
Map<Logic, Const> resetValues = const {},
Logic? reset})
: this.multi([clk],
stages: stages,
stalls: stalls,
signals: signals,
resetValues: resetValues,
reset: reset);

/// Constructs a [Pipeline] with multiple triggers on any of [_clks].
Pipeline.multi(this._clks,
{List<List<Conditional> Function(PipelineStageInfo p)> stages = const [],
List<Logic?>? stalls,
List<Logic> signals = const [],
Expand Down Expand Up @@ -225,7 +244,7 @@ class Pipeline {
])
];
}
Sequential(clk, ffAssignsWithStall, name: 'ff_${newLogic.name}');
Sequential.multi(_clks, ffAssignsWithStall, name: 'ff_${newLogic.name}');
}

/// The stage input for a signal associated with [logic] to [stageIndex].
Expand Down Expand Up @@ -304,14 +323,33 @@ class ReadyValidPipeline extends Pipeline {
/// If contents are pushed in when the pipeline is not ready, they
/// will be dropped.
ReadyValidPipeline(
super.clk,
Logic clk,
Logic validPipeIn,
Logic readyPipeOut, {
List<List<Conditional> Function(PipelineStageInfo p)> stages = const [],
Map<Logic, Const> resetValues = const {},
List<Logic> signals = const [],
Logic? reset,
}) : this.multi(
[clk],
validPipeIn,
readyPipeOut,
stages: stages,
resetValues: resetValues,
signals: signals,
reset: reset,
);

/// Creates a [ReadyValidPipeline] with multiple triggers.
ReadyValidPipeline.multi(
super._clks,
this.validPipeIn,
this.readyPipeOut, {
List<List<Conditional> Function(PipelineStageInfo p)> stages = const [],
super.resetValues,
List<Logic> signals = const [],
super.reset,
}) : super(
}) : super.multi(
stages: stages,
signals: [validPipeIn, ...signals],
stalls: List.generate(
Expand Down

0 comments on commit 33f249c

Please sign in to comment.