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

Replace ad-hoc model configuration with Sail-native configuration #758

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Alasdair
Copy link
Collaborator

This is the first in a series of PRs (and probably patches to this PR) aiming to replace the ad-hoc C stubs used for configuration with a Sail-native configuration system using a separate configuration file. This is a draft PR as it needs a new release of Sail to work.

This PR is split into two commits:

  1. The first simply updates the CMake build system to include the Sail JSON handling code, and adds a simulator option to pass a configuration file but does not change the model code whatsoever. The file config/default.json is added to store all the default configuration options (but is empty in this commit). I took the -c short option away from the sail coverage option, as it isn't even built in by default.
  2. The second replaces the existing options in the simulator. The only behaviour change is the handling of rom_base and rom_size is slightly different, in that it'll just print if the configuration values don't match what the C code that creates the reset vector and writes the DTB expect rather than setting the values.

Note that this PR isn't aiming to add all the configuration we want for MC100 or beyond, it's just a direct port of existing functionality.

With this adding a new configurable option to the model is easy, add config x.y.z : T anywhere in the model, and then add x.y.z into the JSON file, and it'll just work.

TODOs:

  1. Update the other Sail targets. This configuration system works across all Sail backends, but the CMake commands for them need to be updated to reflect this
  2. Sail can generate a JSON schema that will validate any provided config fits into the model, that hasn't been set up yet. The default config should be JSON schema validated in CI as well.
  3. We probably want some more friendly way to write the configuration rather than plain JSON, that could be specific to this repository, or by writing a script that imports values from riscv-config or UDB, or both. I haven't decided the best way to go yet.

Copy link
Collaborator

@Timmmm Timmmm left a comment

Choose a reason for hiding this comment

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

This is fantastic.

@@ -431,6 +304,12 @@ static int process_args(int argc, char **argv)
break;
}
}

if (!have_config) {
fprintf(stderr, "No configuration file provided.\n");
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it might be nice to have default.json built-in and used by default? We can probably just embed it as a string literal in a header or whatever.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Does CMake have a built in way to do that?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Could probably do this using objcopy or .incbin although that isn't too portable. I imagine a custom_command() that runs something like:

(echo 'extern "C" const char default_data[] = R"(' && ${CMAKE} -E cat ${CMAKE_SOURCE_DIR}/default.json && echo ')";')> file.cc

Copy link
Collaborator

Choose a reason for hiding this comment

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

Not in an especially nice way but something like this might work I guess? I think @arichardson has the misfortune of being more of a CMake expert than me.

file(READ "default.json" DEFAULT_JSON)
configure_file("default_json.h.in" "default_json.h" ESCAPE_QUOTES @ONLY)
# Ensure this runs again if `default.json` is changed.
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "default_json.h.in")
// default_json.h.in
#pragma once
const char* DEFAULT_JSON = "@DEFAULT_JSON@";

Copy link
Collaborator

Choose a reason for hiding this comment

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

That avoids the need for c++ but I'm not sure if changes to default.json will be noticed by an incremental build without rerunning cmake.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That's what the CMAKE_CONFIGURE_DEPENDS does (in theory).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Did not know about that! Sounds like the best solution then

Copy link
Collaborator

Choose a reason for hiding this comment

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

Though if we change the code to be C++ I would be in favour of just having it hard-coded as a string literal:

#pragma once
constexpr DEFAULT_JSON = r#"
...
"#;

Much simpler and still very easy to copy/paste if people want to use it as a base.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess the advantage of having both the file and the builtin default is that you can pass the file with --config=. But if we add something like --print-default-config you could run $(SIM) --config <($(SIM) --print-default-config) ....

I guess the main advantage of having it as a real file in the repository is that we can get syntax highlighting+json formatting in IDEs.

Copy link
Collaborator

Choose a reason for hiding this comment

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

So I think the suggestion in https://github.com/riscv/sail-riscv/pull/758/files#r1972488749 is probably best?

sail_config_key rom_size_key = {"platform", "rom", "size"};
if (rom_base != get_config_uint64(3, rom_base_key)) {
fprintf(stderr,
"Configuration value platform.rom.base does not match %" PRIu64
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would be nice to print both values. Also I haven't followed the flow but why do you have to have two matching values?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The way it used to work is it would set rv_rom_base, overriding the default value in the configuration (such as it existed previously). Now it's just checking the configuration setting is correct, not sure if it's the best thing to do.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh I see. The whole ROM/RAM thing is wrong anyway so maybe we should just not worry about it too much for now. Once this is merged we can easily add a proper PMA memory map.

@pmundkur pmundkur added the tgmm-agenda Tagged for the next Golden Model meeting agenda. label Mar 1, 2025
Because passing in a configuration file is something we need to
do every time, re-purpose the '-c' short option from the optional
SAILCOV feature.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tgmm-agenda Tagged for the next Golden Model meeting agenda.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants