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

Generic CSR Functionality #151

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open

Generic CSR Functionality #151

wants to merge 14 commits into from

Conversation

kimmeljo
Copy link
Contributor

@kimmeljo kimmeljo commented Jan 3, 2025

Description & Motivation

Adding a mechanism to generically generate a module to define, read and write control/status registers (CSRs). This functionality includes automatic construction of CSRs based on configuration objects down to the granularity of register fields.

Related Issue(s)

N/A

Testing

Added unit tests (csr_test.dart)

Backwards-compatibility

Is this a breaking change that will not be backwards-compatible? If yes, how so?

New functionality so no breaking changes.

Documentation

Does the change require any updates to documentation? If so, where? Are they included?

A new document describing all functionality will be added.

Copy link
Contributor

@mkorbel1 mkorbel1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i really like this approach, looking good!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

split into multiple files?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I like that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about even more files? :)

let's try to aim for 1 class per file (except for small, supporting classes)

lib/src/memory/csr.dart Outdated Show resolved Hide resolved
lib/src/memory/csr.dart Outdated Show resolved Hide resolved
lib/src/memory/csr.dart Outdated Show resolved Hide resolved
lib/src/memory/csr.dart Outdated Show resolved Hide resolved
lib/src/memory/csr.dart Outdated Show resolved Hide resolved
lib/src/memory/csr.dart Outdated Show resolved Hide resolved
lib/src/memory/csr.dart Outdated Show resolved Hide resolved
@@ -1,5 +1,6 @@
// Copyright (C) 2023-2024 Intel Corporation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update date year

test/csr_test.dart Outdated Show resolved Hide resolved
@ganewto
Copy link

ganewto commented Jan 13, 2025

I'm late to commenting on this PR.

I didn't see a test for the legalValues restriction. Sometimes it helps to have short burst tests for pieces of functionality to provide a 'smoke test'. It's harder to find in a longer sequence of setup, though easier to amortize that over multiple tests. A strategy could be to setup the CR you want to use at the beginning of a group test and then do a bunch of shorter 'test' functions underneath:

group('CSR big test', () {
//  setup CRs here
... bunch of code
// end setup CRs 
  test('feature access one', () {
  });
  
  test ('feature access two', () {
  });
  ...
 });

@ganewto
Copy link

ganewto commented Jan 13, 2025

Need a doc (csr.md) where you can describe the overall architecture and feature set. Could be just a few short paragraphs, maybe a code example with init and with access and a bit of inspiration on how clean this is.

lib/src/memory/csr_config.dart Outdated Show resolved Hide resolved
lib/src/memory/csr_config.dart Outdated Show resolved Hide resolved
/// Helper to derive a reset value for the register from its fields.
///
/// Only should be used if a reset value isn't explicitly provided.
int resetValueFromFields() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this API be exposed publicly? since it might not be the "real" reset value if a resetValue for the whole register is provided. you could make it private or even @internal

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually used in a encapsulating class (CsrBlock). Is there an annotation that enables the proper protections given this information?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about even more files? :)

let's try to aim for 1 class per file (except for small, supporting classes)

bool get isBackdoorWritable => config.isBackdoorWritable;

/// Getter for the field configuration of the CSR
List<CsrFieldConfig> get fields => config.fields;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this Csr Logic object is created at the point of time when it is constructed, but the fields property of the config could theoretically be changed by a user after the fact, meaning this fields property could become out of sync from the actual Logics present. This would be silly to do intentionally, but it should be possible to prevent accidentally doing something like that. This ties into that making fields unmodifiable idea from other comments. We should decide how we want these configuration objects to behave: should they be immutable? should they be copied at the time they are consumed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the point. My opinion is that they should be immutable within an encapsulating HW object (i.e., passed during construction, readable to users, but not modifiable). I'm guessing there's nice Dart syntax to do this?

for (var i = 0; i < elements.length; i++) {
// if the given field is reserved or read only
// take the current value instead of the new value
final chk1 = rsvdIndices.contains(i);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and for chk2, why not just move the checking condition into the if condition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was a vestige of code I ended up refactoring. But is that a big deal?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding a comment to track that we need some documentation added to the doc area for how to use these

/// Method to validate the configuration of a single register.
///
/// Must check that its fields are mutually valid.
void validate() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is intended to call these validate functions? should hardware validate upon construction? is the user expected to call it before using it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardware calls all of these functions appropriately and automatically upon construction/build. But I decided it's perfectly valid to also allow a user to call the validate function independently on the config object if they want.

/// register validation is called separately (i.e., in Csr HW construction).
void validate() {
// at least 1 register
if (registers.isEmpty) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this have to be illegal? is an empty block so bad?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's not terrible but it doesn't really make sense to me....

/// based on the maximum block base address. Note that we independently
/// validate the block offset width relative to the base addresses
/// so we can trust the simpler analysis here.
int minAddrBits() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should these be private helper functions rather than public API?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are currently called outside of the class (during HW construction for validation) but by an encapsulating class. If there's a better annotation, I'm open but also I kind of like having them be public (why not allow users to call them?).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants