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

AXI4 Interface and Functional Modeling #159

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 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
647 changes: 647 additions & 0 deletions lib/src/interfaces/axi4.dart

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion lib/src/interfaces/interfaces.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (C) 2023-2024 Intel Corporation
// Copyright (C) 2024-2025 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause

export 'apb.dart';
export 'axi4.dart';
10 changes: 10 additions & 0 deletions lib/src/models/axi4_bfm/axi4_bfm.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (C) 2024-2025 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause

export 'axi4_compliance_checker.dart';
export 'axi4_main.dart';
export 'axi4_main_driver.dart';
export 'axi4_monitor.dart';
export 'axi4_packet.dart';
export 'axi4_subordinate.dart';
export 'axi4_tracker.dart';
270 changes: 270 additions & 0 deletions lib/src/models/axi4_bfm/axi4_compliance_checker.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
// Copyright (C) 2024-2025 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// axi4_compliance_checker.dart
// Compliance checking for AXI4.
//
// 2025 January
// Author: Josh Kimmel <[email protected]>

import 'dart:async';

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

// /// A checker for some of the rules defined in the AXI4 interface specification.
// ///
// /// This does not necessarily cover all rules defined in the spec.
// class Axi4ComplianceChecker extends Component {
// /// AXI4 System Interface.
// final Axi4SystemInterface sIntf;

// /// AXI4 Read Interface.
// final Axi4ReadInterface rIntf;

// /// AXI4 Write Interface.
// final Axi4WriteInterface wIntf;

// /// Creates a new compliance checker for AXI4.
// Axi4ComplianceChecker(
// this.sIntf,
// this.rIntf,
// this.wIntf, {
// required Component parent,
// String name = 'axi4ComplianceChecker',
// }) : super(name, parent);

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

// // wait for reset to complete
// await sIntf.resetN.nextPosedge;

// // checks to run
// // READ REQUESTS
// // number of flits returned matches ARLEN if no error
// // if RLAST is present, asserted on the final flit only
// // if RID is present, every read response should match
// // a pending request ARID
// // WRITE REQUESTS
// // number of flits sent matches AWLEN
// // WLAST is asserted on the final flit only
// // if BID is present, every write response should match
// // a pending request AWID

// final rLastPresent = rIntf.rLast != null;

// final readReqMap = <int, List<int>>{};
// final writeReqMap = <int, List<int>>{};
// var lastWriteReqId = -1;

// sIntf.clk.posedge.listen((event) {
// // capture read requests for counting
// if (rIntf.arValid.previousValue!.isValid &&
// rIntf.arValid.previousValue!.toBool()) {
// final id = rIntf.arId?.previousValue?.toInt() ?? 0;
// final len = (rIntf.arLen?.previousValue?.toInt() ?? 0) + 1;
// readReqMap[id] = [len, 0];
// }

// // track read response flits
// if (rIntf.rValid.previousValue!.isValid &&
// rIntf.rValid.previousValue!.toBool()) {
// final id = rIntf.rId?.previousValue?.toInt() ?? 0;
// if (!readReqMap.containsKey(id)) {
// logger.severe(
// 'Cannot match a read response to any pending read request. '
// 'ID captured by the response was $id.');
// }

// readReqMap[id]![1] = readReqMap[id]![1] + 1;
// final len = readReqMap[id]![0];
// final currCount = readReqMap[id]![1];
// if (currCount > len) {
// logger.severe(
// 'Received more read response data flits than indicated by the '
// 'request with ID $id ARLEN. Expected $len but got $currCount');
// } else if (currCount == len &&
// rLastPresent &&
// !rIntf.rLast!.previousValue!.toBool()) {
// logger.severe('Received the final flit in the read response data per '
// 'the request with ID $id ARLEN but RLAST is not asserted.');
// }
// }

// // track write requests
// if (wIntf.awValid.previousValue!.isValid &&
// wIntf.awValid.previousValue!.toBool()) {
// final id = wIntf.awId?.previousValue?.toInt() ?? 0;
// final len = (wIntf.awLen?.previousValue?.toInt() ?? 0) + 1;
// writeReqMap[id] = [len, 0];
// lastWriteReqId = id;
// }

// // track write data flits
// if (wIntf.wValid.previousValue!.isValid &&
// wIntf.wValid.previousValue!.toBool()) {
// final id = lastWriteReqId;
// if (!writeReqMap.containsKey(id)) {
// logger.severe('There is no pending write request '
// 'to associate with valid write data.');
// }

// writeReqMap[id]![1] = writeReqMap[id]![1] + 1;
// final len = writeReqMap[id]![0];
// final currCount = writeReqMap[id]![1];
// if (currCount > len) {
// logger.severe(
// 'Sent more write data flits than indicated by the request '
// 'with ID $id AWLEN. Expected $len but sent $currCount');
// } else if (currCount == len && !wIntf.wLast.previousValue!.toBool()) {
// logger.severe('Sent the final flit in the write data per the request '
// 'with ID $id AWLEN but WLAST is not asserted.');
// }
// }
// });
// }
// }

/// A checker for some of the rules defined in the AXI4 interface specification.
///
/// This does not necessarily cover all rules defined in the spec.
class Axi4ReadComplianceChecker extends Component {
/// AXI4 System Interface.
final Axi4SystemInterface sIntf;

/// AXI4 Read Interface.
final Axi4ReadInterface rIntf;

/// Creates a new compliance checker for AXI4.
Axi4ReadComplianceChecker(
this.sIntf,
this.rIntf, {
required Component parent,
String name = 'axi4ReadComplianceChecker',
}) : super(name, parent);

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

// wait for reset to complete
await sIntf.resetN.nextPosedge;

// checks to run
// READ REQUESTS
// number of flits returned matches ARLEN if no error
// if RLAST is present, asserted on the final flit only
// if RID is present, every read response should match
// a pending request ARID

final rLastPresent = rIntf.rLast != null;
final readReqMap = <int, List<int>>{};

sIntf.clk.posedge.listen((event) {
// capture read requests for counting
if (rIntf.arValid.previousValue!.isValid &&
rIntf.arValid.previousValue!.toBool()) {
final id = rIntf.arId?.previousValue?.toInt() ?? 0;
final len = (rIntf.arLen?.previousValue?.toInt() ?? 0) + 1;
readReqMap[id] = [len, 0];
}

// track read response flits
if (rIntf.rValid.previousValue!.isValid &&
rIntf.rValid.previousValue!.toBool()) {
final id = rIntf.rId?.previousValue?.toInt() ?? 0;
if (!readReqMap.containsKey(id)) {
logger.severe(
'Cannot match a read response to any pending read request. '
'ID captured by the response was $id.');
}

readReqMap[id]![1] = readReqMap[id]![1] + 1;
final len = readReqMap[id]![0];
final currCount = readReqMap[id]![1];
if (currCount > len) {
logger.severe(
'Received more read response data flits than indicated by the '
'request with ID $id ARLEN. Expected $len but got $currCount');
} else if (currCount == len &&
rLastPresent &&
!rIntf.rLast!.previousValue!.toBool()) {
logger.severe('Received the final flit in the read response data per '
'the request with ID $id ARLEN but RLAST is not asserted.');
}
}
});
}
}

/// A checker for some of the rules defined in the AXI4 interface specification.
///
/// This does not necessarily cover all rules defined in the spec.
class Axi4WriteComplianceChecker extends Component {
/// AXI4 System Interface.
final Axi4SystemInterface sIntf;

/// AXI4 Write Interface.
final Axi4WriteInterface wIntf;

/// Creates a new compliance checker for AXI4.
Axi4WriteComplianceChecker(
this.sIntf,
this.wIntf, {
required Component parent,
String name = 'axi4WriteComplianceChecker',
}) : super(name, parent);

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

// wait for reset to complete
await sIntf.resetN.nextPosedge;

// checks to run
// WRITE REQUESTS
// number of flits sent matches AWLEN
// WLAST is asserted on the final flit only
// if BID is present, every write response should match
// a pending request AWID

final writeReqMap = <int, List<int>>{};
var lastWriteReqId = -1;

sIntf.clk.posedge.listen((event) {
// track write requests
if (wIntf.awValid.previousValue!.isValid &&
wIntf.awValid.previousValue!.toBool()) {
final id = wIntf.awId?.previousValue?.toInt() ?? 0;
final len = (wIntf.awLen?.previousValue?.toInt() ?? 0) + 1;
writeReqMap[id] = [len, 0];
lastWriteReqId = id;
}

// track write data flits
if (wIntf.wValid.previousValue!.isValid &&
wIntf.wValid.previousValue!.toBool()) {
final id = lastWriteReqId;
if (!writeReqMap.containsKey(id)) {
logger.severe('There is no pending write request '
'to associate with valid write data.');
}

writeReqMap[id]![1] = writeReqMap[id]![1] + 1;
final len = writeReqMap[id]![0];
final currCount = writeReqMap[id]![1];
if (currCount > len) {
logger.severe(
'Sent more write data flits than indicated by the request '
'with ID $id AWLEN. Expected $len but sent $currCount');
} else if (currCount == len && !wIntf.wLast.previousValue!.toBool()) {
logger.severe('Sent the final flit in the write data per the request '
'with ID $id AWLEN but WLAST is not asserted.');
}
}
});
}
}
Loading
Loading