Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ doc/api/

# Other stuff
tmp_test/
*.sv
*.vcd
.vscode/

Expand Down
25 changes: 14 additions & 11 deletions example/example.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/// Copyright (C) 2021 Intel Corporation
/// Copyright (C) 2021-2023 Intel Corporation
/// SPDX-License-Identifier: BSD-3-Clause
///
/// example.dart
Expand All @@ -8,19 +8,22 @@
/// Author: Max Korbel <max.korbel@intel.com>
///

// Though we usually avoid them, for this example,
// allow `print` messages (disable lint):
// ignore_for_file: avoid_print

// Import the ROHD package
// Import the ROHD package.
import 'package:rohd/rohd.dart';

// Define a class Counter that extends ROHD's abstract Module class
// Define a class Counter that extends ROHD's abstract Module class.
class Counter extends Module {
// For convenience, map interesting outputs to short variable names for
// consumers of this module
// consumers of this module.
Logic get val => output('val');

// This counter supports any width, determined at run-time
// This counter supports any width, determined at run-time.
final int width;

Counter(Logic en, Logic reset, Logic clk,
{this.width = 8, super.name = 'counter'}) {
// Register inputs and outputs of the module in the constructor.
Expand All @@ -32,20 +35,20 @@ class Counter extends Module {

final val = addOutput('val', width: width);

// A local signal named 'nextVal'
// A local signal named 'nextVal'.
final nextVal = Logic(name: 'nextVal', width: width);

// Assignment statement of nextVal to be val+1
// (<= is the assignment operator)
// ('<=' is the assignment operator).
nextVal <= val + 1;

// `Sequential` is like SystemVerilog's always_ff, in this case trigger on
// the positive edge of clk
// the positive edge of clk.
Sequential(clk, [
// `If` is a conditional if statement, like `if` in SystemVerilog
// always blocks
// always blocks.
If(reset, then: [
// the '<' operator is a conditional assignment
// The '<' operator is a conditional assignment.
val < 0
], orElse: [
If(en, then: [val < nextVal])
Expand All @@ -61,7 +64,7 @@ Future<void> main({bool noPrint = false}) async {
final en = Logic(name: 'en');
final reset = Logic(name: 'reset');

// Generate a simple clock. This will run along by itself as
// Generate a simple clock. This will run along by itself as
// the Simulator goes.
final clk = SimpleClockGenerator(10).clk;

Expand Down
81 changes: 47 additions & 34 deletions example/fir_filter.dart
Original file line number Diff line number Diff line change
@@ -1,115 +1,128 @@
/// SPDX-License-Identifier: BSD-3-Clause
///
/// fir_filter.dart
/// A basic example of a FIR filter
/// A basic example of a FIR filter.
///
/// 2022 February 02
/// Author: wswongat
///

// Though we usually avoid them, for this example,
// allow `print` messages (disable lint):
// ignore_for_file: avoid_print

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

class FirFilter extends Module {
// For convenience, map interesting outputs to short variable names for
// consumers of this module
// consumers of this module.
Logic get out => output('out');

// This Fir Filter supports any width and depth, defined at runtime
// This Fir Filter supports any width and depth, defined at runtime.
final int bitWidth;
final int depth;

FirFilter(Logic en, Logic resetB, Logic clk, Logic inputVal, List<int> coef,
{this.bitWidth = 16, super.name = 'FirFilter'})
: depth = coef.length {
// Register inputs and outputs of the module in the constructor
// Module logic must consume registered inputs and output to
// registered outputs
// Depth check.
if (depth < 1) {
// Depth Check
throw Exception('Depth parameter should more than 1');
}
// Add input/output port

// Register inputs and outputs of the module in the constructor.
// Module logic must consume registered inputs and output to
// registered outputs.

// Register inputs.
en = addInput('en', en);
inputVal = addInput('inputVal', inputVal, width: bitWidth);
resetB = addInput('resetB', resetB);
clk = addInput('clk', clk);
// Generate input train
final z = List<Logic>.generate(
depth, (index) => Logic(width: bitWidth, name: 'z$index'));

// Generate output
// Register output.
final out = addOutput('out', width: bitWidth);

// Initialize conditionalAssign list
// Generate input train.
final z = List<Logic>.generate(
depth, (index) => Logic(width: bitWidth, name: 'z$index'));

// The ConditionalAssign list below is represent the FIR filter:
// sum[n] = z[n]*coef[n] + z[n-1]*coef[n-1] + ... + z[n-depth]*coef[n-depth]
final inputTrain = [z[0] < inputVal];
var sum = z[0] * coef[0];
for (var i = 0; i < z.length - 1; i++) {
inputTrain.add(z[i + 1] < z[i]);
sum = sum + z[i + 1] * coef[i + 1];
}
// The List above is represent the FIR filter
// sum[n] =
// _z[n]*coef[n] + _z[n-1]*coef[n-1] + .... + _z[n-depth]*coef[n-depth]

// `Sequential` is like SystemVerilog's always_ff,
// in this case trigger on the positive edge of clk
// in this case trigger on the positive edge of clk.
Sequential(clk, [
// `If` is a conditional if statement, like `if` in SystemVerilog
// always blocks
// always blocks.
If(resetB,
then: [
// `If` is a conditional if statement, like `if` in SystemVerilog
// always blocks
If(en, then: inputTrain + [out < sum], orElse: [
// the '<' operator is a conditional assignment
// The '<' operator is a conditional assignment.
out < 0
])
],
orElse: [
// the '<' operator is a conditional assignment
out < 0
// Set all _z to zero
] +
orElse: [out < 0] +
// Set all 'z' to zero.
List<ConditionalAssign>.generate(depth, (index) => z[index] < 0))
]);
}
}

Future<void> main({bool noPrint = false}) async {
const sumWidth = 8;

// Define some local signals.
final en = Logic(name: 'en');
final resetB = Logic(name: 'resetB');
final inputVal = Logic(name: 'inputVal', width: sumWidth);

// Generate a simple clock. This will run along by itself as
// the Simulator goes.
final clk = SimpleClockGenerator(5).clk;
// 4-cycle delay coefficients

// 4-cycle delay coefficients.
final firFilter =
FirFilter(en, resetB, clk, inputVal, [0, 0, 0, 1], bitWidth: sumWidth);

// Build a FIR filter.
await firFilter.build();

// Generate systemverilog code to file
// Generate SystemVerilog code.
final systemVerilogCode = firFilter.generateSynth();
if (!noPrint) {
// Print systemverilog code to console
// Print SystemVerilog code to console.
print(systemVerilogCode);
// Save systemverilog code to file
// Save SystemVerilog code to file.
File('rtl.sv').writeAsStringSync(systemVerilogCode);
}

// Now let's try simulating!

// Let's set the initial setting.
en.put(0);
resetB.put(0);
inputVal.put(1);

// Attach a waveform dumper
// Attach a waveform dumper.
if (!noPrint) {
WaveDumper(firFilter);
}

// Raise enable at time 5.
Simulator.registerAction(5, () => en.put(1));

// Raise resetB at time 10.
Simulator.registerAction(10, () => resetB.put(1));

// Plan the input sequence.
for (var i = 1; i < 10; i++) {
Simulator.registerAction(5 + i * 4, () => inputVal.put(i));
}
Expand All @@ -121,13 +134,13 @@ Future<void> main({bool noPrint = false}) async {
}
});

// Set a maximum time for the simulation so it doesn't keep running forever
// Set a maximum time for the simulation so it doesn't keep running forever.
Simulator.setMaxSimTime(100);

// Kick off the simulation
// Kick off the simulation.
await Simulator.run();

// We can take a look at the waves now
// We can take a look at the waves now.
if (!noPrint) {
print('To view waves, check out waves.vcd with a'
' waveform viewer (e.g. `gtkwave waves.vcd`).');
Expand Down
17 changes: 10 additions & 7 deletions example/tree.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/// Copyright (C) 2021 Intel Corporation
/// Copyright (C) 2021-2023 Intel Corporation
/// SPDX-License-Identifier: BSD-3-Clause
///
/// tree.dart
Expand All @@ -8,13 +8,15 @@
/// Author: Max Korbel <max.korbel@intel.com>
///

// Though we usually avoid them, for this example,
// allow `print` messages (disable lint):
// ignore_for_file: avoid_print

import 'package:rohd/rohd.dart';

/// The below example demonstrates some aspects of the power of ROHD where
/// writing equivalent design code in SystemVerilog can be challenging or
/// impossible. The example is a port from an example used by Chisel.
/// impossible. The example is a port from an example used by Chisel.
///
/// The ROHD module `TreeOfTwoInputModules` is a succinct representation a
/// logarithmic-height tree of arbitrary two-input/one-output modules.
Expand All @@ -30,7 +32,7 @@ import 'package:rohd/rohd.dart';
/// can be stored in variables). It expects a function which takes two
/// `Logic` inputs and provides one `Logic` output.
/// - This module recursively instantiates itself, but with different numbers of
/// inputs each time. The same module implementation can have a variable
/// inputs each time. The same module implementation can have a variable
/// number of inputs and different logic without any explicit
/// parameterization.

Expand Down Expand Up @@ -71,11 +73,12 @@ Future<void> main({bool noPrint = false}) async {
(a, b) => mux(a > b, a, b));

/// This instantiation code generates a list of sixteen 8-bit logic signals.
/// The operation to be performed (`_op`) is to create a `Mux` which returns
/// `a` if `a` is greater than `b`, otherwise `b`. Therefore, this
/// The operation to be performed (`_op`) is to create a `Mux` (in this case,
/// the `mux` helper function is used to create) which returns
/// `a` if `a` is greater than `b`, otherwise `b`. Therefore, this
/// instantiation creates a logarithmic-height tree of modules which outputs
/// the largest 8-bit value. Note that `Mux` also needs no parameters, as it
/// can automatically determine the appropriate size of `y` based on the
/// the largest 8-bit value. Note that `Mux` also needs no parameters, as it
/// can automatically determine the appropriate size of `out` based on the
/// inputs.
///
/// A SystemVerilog implementation of this requires numerous module
Expand Down