Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ready/Valid BFM #69

Merged
merged 4 commits into from
Jan 8, 2024
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ tmp*
*.vcd
.vscode/*
confapp/.vscode/*
*tracker.json
*tracker.log

# Exceptions
!.vscode/extensions.json
Expand Down
1 change: 1 addition & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ Some in-development items will have opened issues, as well. Feel free to create
- HBM
- Models
- [APB](./components/apb_bfm.md)
- [Ready/Valid](./components/ready_valid_bfm.md)

----------------

Expand Down
4 changes: 2 additions & 2 deletions doc/components/apb_bfm.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ The APB BFM is a collection of [ROHD-VF](https://github.com/intel/rohd-vf) compo

The main two components are the `ApbRequesterAgent` and the `ApbCompleterAgent`, which behave like a "requester" and "completer" as described in the APB spec, respectively. The `ApbRequesterAgent` has a standard `Sequencer` that accepts `ApbPacket`s to be driven out to the completer. The `ApbCompleterAgent` has default behavior and accepts a `MemoryStorage` instance as a memory model. See the API docs for more details on how to use each of these components, which both have substantial configurability to control behavior.

A `ApbMonitor` is also included, which implements the standard `Monitor` and provides a stream of `ApbPacket`s monitored on positive edges of the clock. The `ApbTracker` can be used to log all items detected by the monitor by implementing the standard `Tracker` API (log file or JSON both supported).
An `ApbMonitor` is also included, which implements the standard `Monitor` and provides a stream of `ApbPacket`s monitored on positive edges of the clock. The `ApbTracker` can be used to log all items detected by the monitor by implementing the standard `Tracker` API (log file or JSON both supported).

Finally, a `ApbComplianceChecker` monitors an `ApbInterface` for a subset of the rules described in the APB specification. Errors are flagged using the `severe` log messages, as is standard for errors in ROHD-VF.

The unit tests in `apb_test.dart`, which have a completer and requester communicating with each other, are a good example for setting up the APB BFM.
The unit tests in `apb_bfm_test.dart`, which have a completer and requester communicating with each other, are a good example for setting up the APB BFM.

## Unsupported features

Expand Down
13 changes: 13 additions & 0 deletions doc/components/ready_valid_bfm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Ready/Valid BFM

The Ready/Valid BFM is a collection of [ROHD-VF](https://github.com/intel/rohd-vf) components and objects that are helpful for validating hardware that contains interfaces that use a ready/valid protocol. To summarize:

- When a transmitter has something to send, it raises `valid`.
- When a receiver is able to accept something, it raises `ready`.
- When both `valid` and `ready` are high, the transaction is accepted by both sides.

The main two components are the `ReadyValidTransmitterAgent` and `ReadyValidReceiverAgent`, which transmit and receive `data`, respectively. Any bundle of information can be mapped onto the `data` bus. Both agents provide a `blockRate` argument which controls a random weighted chance of preventing a transaction from occuring (either delaying a `valid` or dropping a `ready`).

Additionally, the `ReadyValidMonitor` can be placed on any ready/valid protocol to observe transactions that are accepted. The resulting `ReadyValidPacket`s can also be logged via the `ReadyValidTracker`.

The unit tests in `ready_valid_bfm_test.dart`, which have a transmitter and receiver agent talking to each other, can serve as a good example of how to use these components.
3 changes: 2 additions & 1 deletion lib/src/models/models.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (C) 2023 Intel Corporation
// Copyright (C) 2023-2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause

export 'apb_bfm/apb_bfm.dart';
export 'memory_model.dart';
export 'ready_valid_bfm/ready_valid_bfm.dart';
export 'sparse_memory_storage.dart';
40 changes: 40 additions & 0 deletions lib/src/models/ready_valid_bfm/ready_valid_agent.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// ready_valid_agent.dart
// A generic agent for ready/valid protocol.
//
// 2024 January 5
// Author: Max Korbel <[email protected]>

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

/// A generic agent for ready/valid protocol.
abstract class ReadyValidAgent extends Agent {
/// The clock.
final Logic clk;

/// Active-high reset.
final Logic reset;

/// Ready signal.
final Logic ready;

/// Valid signal.
final Logic valid;

/// Data being transmitted.
final Logic data;

/// Creates a new agent.
ReadyValidAgent({
required this.clk,
required this.reset,
required this.ready,
required this.valid,
required this.data,
required Component? parent,
String name = 'readyValidComponent',
}) : super(name, parent);
}
10 changes: 10 additions & 0 deletions lib/src/models/ready_valid_bfm/ready_valid_bfm.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause

export 'ready_valid_agent.dart';
export 'ready_valid_monitor.dart';
export 'ready_valid_packet.dart';
export 'ready_valid_receiver_agent.dart';
export 'ready_valid_tracker.dart';
export 'ready_valid_transmitter_agent.dart';
export 'ready_valid_transmitter_driver.dart';
60 changes: 60 additions & 0 deletions lib/src/models/ready_valid_bfm/ready_valid_monitor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// ready_valid_monitor.dart
// A monitor for ready/valid protocol.
//
// 2024 January 5
// Author: Max Korbel <[email protected]>

import 'dart:async';

import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';
import 'package:rohd_vf/rohd_vf.dart';

/// A [Monitor] for ready/valid protocol.
class ReadyValidMonitor extends Monitor<ReadyValidPacket> {
/// The clock.
final Logic clk;

/// Active-high reset.
final Logic reset;

/// Ready signal.
final Logic ready;

/// Valid signal.
final Logic valid;

/// Data being transmitted.
final Logic data;

/// Creates a new [ReadyValidMonitor].
ReadyValidMonitor({
required this.clk,
required this.reset,
required this.ready,
required this.valid,
required this.data,
required Component? parent,
String name = 'readyValidMonitor',
}) : super(name, parent);

@override
Future<void> run(Phase phase) async {
unawaited(super.run(phase));

await reset.nextNegedge;

clk.posedge.listen((event) {
if (!ready.previousValue!.isValid || !valid.previousValue!.isValid) {
logger.severe('Both ready and valid must be valid for protocol,'
' but found ready=${ready.value} and valid=${valid.value}');
} else if (ready.previousValue!.toBool() &&
valid.previousValue!.toBool()) {
add(ReadyValidPacket(data.previousValue!));
}
});
}
}
33 changes: 33 additions & 0 deletions lib/src/models/ready_valid_bfm/ready_valid_packet.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// ready_valid_packet.dart
// A monitor for ready/valid protocol.
//
// 2024 January 5
// Author: Max Korbel <[email protected]>

import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';
import 'package:rohd_vf/rohd_vf.dart';

/// A packet to be transmitted over a ready/valid interface.
class ReadyValidPacket extends SequenceItem implements Trackable {
/// The data associated with this packet.
final LogicValue data;

/// Constructs a new packet with associated [data].
ReadyValidPacket(this.data);

@override
String? trackerString(TrackerField field) {
switch (field.title) {
case ReadyValidTracker.timeField:
return Simulator.time.toString();
case ReadyValidTracker.dataField:
return data.toString();
}

return null;
}
}
57 changes: 57 additions & 0 deletions lib/src/models/ready_valid_bfm/ready_valid_receiver_agent.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// ready_valid_receiver_agent.dart
// An agent for receiving over a ready/valid protocol.
//
// 2024 January 5
// Author: Max Korbel <[email protected]>

import 'dart:async';
import 'dart:math';

import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';
import 'package:rohd_vf/rohd_vf.dart';

/// An [Agent] for receiving over a ready/valid protocol.
class ReadyValidReceiverAgent extends ReadyValidAgent {
/// Probability (from 0 to 1) of blocking a ready from being driven.
///
/// 0 -> never block, accept transactions as soon as possible.
final double blockRate;

/// Creates an [Agent] for receiving over a ready/valid protocol.
ReadyValidReceiverAgent({
required super.clk,
required super.reset,
required super.ready,
required super.valid,
required super.data,
required super.parent,
this.blockRate = 0,
super.name = 'readyValidReceiverAgent',
});

@override
Future<void> run(Phase phase) async {
unawaited(super.run(phase));

final random = Test.random ?? Random();

await _drive(LogicValue.zero);

await reset.nextNegedge;

while (!Simulator.simulationHasEnded) {
final doBlock = random.nextDouble() < blockRate;

await _drive(doBlock ? LogicValue.zero : LogicValue.one);
}
}

Future<void> _drive(LogicValue newReady) async {
ready.inject(newReady);
await clk.nextPosedge;
}
}
24 changes: 24 additions & 0 deletions lib/src/models/ready_valid_bfm/ready_valid_tracker.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:rohd_hcl/src/models/models.dart';
import 'package:rohd_vf/rohd_vf.dart';

/// A tracker for a ready/valid protocol.
class ReadyValidTracker extends Tracker<ReadyValidPacket> {
/// Tracker field for simulation time.
static const timeField = 'time';

/// Tracker field for data.
static const dataField = 'data';

/// Creates a new tracker for a ready/valid protocol.
ReadyValidTracker({
String name = 'readyValidTracker',
super.dumpJson,
super.dumpTable,
super.outputFolder,
int timeColumnWidth = 12,
int dataColumnWidth = 14,
}) : super(name, [
TrackerField(timeField, columnWidth: timeColumnWidth),
TrackerField(dataField, columnWidth: dataColumnWidth),
]);
}
45 changes: 45 additions & 0 deletions lib/src/models/ready_valid_bfm/ready_valid_transmitter_agent.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// ready_valid_transmitter_agent.dart
// An agent for transmitting over a ready/valid protocol.
//
// 2024 January 5
// Author: Max Korbel <[email protected]>

import 'package:rohd_hcl/rohd_hcl.dart';
import 'package:rohd_vf/rohd_vf.dart';

/// An [Agent] for transmitting over a ready/valid protocol.
class ReadyValidTransmitterAgent extends ReadyValidAgent {
/// The [Sequencer] to send [ReadyValidPacket]s into.
late final Sequencer<ReadyValidPacket> sequencer;

/// Creates an [Agent] for transmitting over a ready/valid protocol.
///
/// The [blockRate] is the probability (from 0 to 1) of blocking a valid from
/// being driven.
ReadyValidTransmitterAgent({
required super.clk,
required super.reset,
required super.ready,
required super.valid,
required super.data,
required super.parent,
double blockRate = 0,
super.name = 'readyValidTransmitterAgent',
}) {
sequencer = Sequencer<ReadyValidPacket>('sequencer', this);

ReadyValidTransmitterDriver(
clk: clk,
reset: reset,
ready: ready,
valid: valid,
data: data,
sequencer: sequencer,
blockRate: blockRate,
parent: this,
);
}
}
Loading