hector-cli 0.2.1__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {hector_cli-0.2.1/hector_cli.egg-info → hector_cli-0.4.0}/PKG-INFO +275 -13
  2. {hector_cli-0.2.1 → hector_cli-0.4.0}/README.md +274 -12
  3. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/commands/__init__.py +1 -1
  4. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/commands/base.py +12 -0
  5. hector_cli-0.4.0/hector/commands/clean.py +34 -0
  6. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/commands/run.py +2 -2
  7. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/core.py +24 -6
  8. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/docker.py +16 -3
  9. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/generator.py +40 -4
  10. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/modules.py +37 -10
  11. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/pipeline.py +161 -26
  12. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/scaffold.py +1 -1
  13. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/validator.py +29 -82
  14. {hector_cli-0.2.1 → hector_cli-0.4.0/hector_cli.egg-info}/PKG-INFO +275 -13
  15. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector_cli.egg-info/SOURCES.txt +22 -1
  16. hector_cli-0.4.0/tests/test_arguments.py +32 -0
  17. hector_cli-0.4.0/tests/test_clean.py +103 -0
  18. hector_cli-0.4.0/tests/test_cli_smoke.py +74 -0
  19. hector_cli-0.4.0/tests/test_connections.py +124 -0
  20. hector_cli-0.4.0/tests/test_core_paths.py +98 -0
  21. hector_cli-0.4.0/tests/test_core_registry.py +75 -0
  22. hector_cli-0.4.0/tests/test_core_text.py +78 -0
  23. hector_cli-0.4.0/tests/test_docker_argv.py +101 -0
  24. hector_cli-0.4.0/tests/test_generator.py +196 -0
  25. hector_cli-0.4.0/tests/test_hubs.py +53 -0
  26. hector_cli-0.4.0/tests/test_mappings.py +102 -0
  27. hector_cli-0.4.0/tests/test_matrix.py +30 -0
  28. hector_cli-0.4.0/tests/test_needs_renode_source.py +38 -0
  29. hector_cli-0.4.0/tests/test_peripherals.py +81 -0
  30. hector_cli-0.4.0/tests/test_pipeline_helpers.py +149 -0
  31. hector_cli-0.4.0/tests/test_reporters.py +70 -0
  32. hector_cli-0.4.0/tests/test_runners.py +83 -0
  33. hector_cli-0.4.0/tests/test_scaffold.py +53 -0
  34. hector_cli-0.4.0/tests/test_validator.py +141 -0
  35. hector_cli-0.4.0/tests/test_version.py +39 -0
  36. {hector_cli-0.2.1 → hector_cli-0.4.0}/LICENSE +0 -0
  37. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/__init__.py +0 -0
  38. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/__main__.py +0 -0
  39. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/commands/export.py +0 -0
  40. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/commands/init.py +0 -0
  41. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/commands/test.py +0 -0
  42. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/commands/validate.py +0 -0
  43. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/connections.py +0 -0
  44. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/dependencies.py +0 -0
  45. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/hubs.py +0 -0
  46. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/mappings.py +0 -0
  47. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/peripherals.py +0 -0
  48. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/reporters.py +0 -0
  49. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector/runners.py +0 -0
  50. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector_cli.egg-info/dependency_links.txt +0 -0
  51. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector_cli.egg-info/entry_points.txt +0 -0
  52. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector_cli.egg-info/requires.txt +0 -0
  53. {hector_cli-0.2.1 → hector_cli-0.4.0}/hector_cli.egg-info/top_level.txt +0 -0
  54. {hector_cli-0.2.1 → hector_cli-0.4.0}/setup.cfg +0 -0
  55. {hector_cli-0.2.1 → hector_cli-0.4.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hector-cli
3
- Version: 0.2.1
3
+ Version: 0.4.0
4
4
  Summary: YAML-driven Renode + Verilator simulation orchestrator for embedded hardware CI
5
5
  Home-page: https://hector-ci.com
6
6
  Author: Nemesis
@@ -50,15 +50,19 @@ Licensed under **AGPL-3.0-or-later** — see [LICENSE](LICENSE) and
50
50
  ## Contents
51
51
 
52
52
  - [Requirements](#requirements)
53
+ - [Installation](#installation)
53
54
  - [Quick start](#quick-start)
55
+ - [Run via Docker (no install)](#run-via-docker-no-install)
54
56
  - [Invocation modes](#invocation-modes)
55
57
  - [Configuration reference](#configuration-reference)
56
58
  - [Top-level fields](#top-level-fields)
57
59
  - [arguments](#arguments)
58
60
  - [matrix](#matrix)
59
61
  - [modules](#modules)
62
+ - [developing your own peripherals](#developing-your-own-peripherals)
60
63
  - [hubs](#hubs)
61
64
  - [machines](#machines)
65
+ - [inline repl and resc](#inline-repl-and-resc)
62
66
  - [peripherals](#peripherals)
63
67
  - [connections (per-machine)](#connections-per-machine)
64
68
  - [mappings](#mappings)
@@ -84,6 +88,34 @@ Licensed under **AGPL-3.0-or-later** — see [LICENSE](LICENSE) and
84
88
 
85
89
  ---
86
90
 
91
+ ## Installation
92
+
93
+ Install the package to get the `hector` command on your `PATH`:
94
+
95
+ ```bash
96
+ cd cli
97
+ pip install . # or: pip install -e . (editable — picks up local edits)
98
+ hector --version
99
+ ```
100
+
101
+ `pip install` creates a `hector` launcher in your environment's scripts directory
102
+ (the venv's `bin/`, or `~/.local/bin` for `pip install --user`). If `hector` isn't
103
+ found afterwards, that scripts directory isn't on your `PATH` — add it, e.g.
104
+ `export PATH="$HOME/.local/bin:$PATH"`.
105
+
106
+ **No install?** Run the module directly from the `cli/` directory — it's equivalent:
107
+
108
+ ```bash
109
+ python -m hector --version
110
+ ```
111
+
112
+ > **Do not add the `cli/` source directory to your `PATH`.** The Python package is
113
+ > named `hector/`, so a bare `hector` would resolve to that **directory** instead of
114
+ > the command, and your shell fails with `permission denied: hector` (or
115
+ > `command not found`). Install with `pip` (above) or use `python -m hector`.
116
+
117
+ ---
118
+
87
119
  ## Quick start
88
120
 
89
121
  ```
@@ -112,6 +144,51 @@ Generated files go in `.hector/` — add it to your `.gitignore`. The Renode **b
112
144
 
113
145
  ---
114
146
 
147
+ ## Run via Docker (no install)
148
+
149
+ If you'd rather not install hector (or even Python) on the host, build the bundled
150
+ image — it sits on top of the official Renode image, so `renode`, `renode-test`
151
+ and `hector` are all inside one container:
152
+
153
+ ```bash
154
+ cd cli
155
+ docker build -t hector-renode .
156
+ # match your project's renode_version:
157
+ docker build --build-arg RENODE_VERSION=1.16.1 -t hector-renode:1.16.1 .
158
+ ```
159
+
160
+ Because Renode is already in the image, hector runs **in-process**
161
+ (`HECTOR_NO_DOCKER=1` is baked in) — no Docker socket, no sibling containers, no
162
+ host-path matching. Use the bundled `hector-docker` wrapper, which mounts your
163
+ project and runs as your UID so output stays yours:
164
+
165
+ ```bash
166
+ ./hector-docker test # run from your project directory
167
+ ./hector-docker validate -f ci.hector.yaml
168
+ ./hector-docker run --renode-args '--console' # headless monitor (no GUI window)
169
+
170
+ # use it like the real thing by symlinking onto your PATH:
171
+ ln -s "$(pwd)/cli/hector-docker" ~/.local/bin/hector
172
+ ```
173
+
174
+ Or the raw form (what the wrapper runs):
175
+
176
+ ```bash
177
+ docker run --rm -it -u "$(id -u):$(id -g)" -e HOME=/tmp \
178
+ -v "$PWD":"$PWD" -w "$PWD" hector-renode test
179
+ ```
180
+
181
+ Override the image tag with `HECTOR_IMAGE` (default `hector-renode:latest`).
182
+
183
+ **Caveats of the in-image mode:** a `build:`/`shell` step's `image:` is ignored —
184
+ the script runs in *this* image instead (a warning is printed), and module builds
185
+ rely on this image's toolchain rather than a per-module one. Interactive `hector
186
+ run` opens Renode's GUI, which needs X forwarding; pass `--renode-args '--console'`
187
+ for a headless monitor. For full per-step image isolation (matching CI), install
188
+ the CLI natively with `pip` and let hector launch real per-step containers.
189
+
190
+ ---
191
+
115
192
  ## Invocation modes
116
193
 
117
194
  | Command | Behaviour |
@@ -122,11 +199,13 @@ Generated files go in `.hector/` — add it to your `.gitignore`. The Renode **b
122
199
  | `hector run --set BIN=fw.elf --set BOARD=nucleo` | Override multiple arguments |
123
200
  | `hector run --debug boardA:3333` | Halt a CPU and open a GDB server |
124
201
  | `hector run --debug boardA:3333 --debug boardB:3334` | Halt multiple CPUs on different ports |
202
+ | `hector run --no-start` | Load the platform and drop into the monitor **paused** — type `start` yourself |
125
203
  | `hector run --renode-args '--console'` | Pass extra flags verbatim to Renode |
126
204
  | `hector run --gather-execution-metrics` | Enable Renode's CPU execution profiler for all machines |
127
205
  | `hector run --gather-execution-metrics boardA` | Enable profiler for one specific machine |
128
206
  | `hector run --gather-execution-metrics boardA --gather-execution-metrics boardB` | Enable profiler for selected machines |
129
207
  | `hector run --renode-version 1.16.1` | Override the Renode version from `.hector.yaml` |
208
+ | `hector run --renode-image my-renode:dev` | Use a specific (e.g. self-built) Renode Docker image |
130
209
  | `hector run --renode-dir /cache/renode` | Use/cache the Renode source checkout at this path (only fetched when needed) |
131
210
  | `hector run --renode-integration-dir /cache/integration` | Likewise for the verilator-integration checkout |
132
211
  | `hector run --no-docker` | Use locally installed `renode` / `renode-test` instead of Docker |
@@ -151,11 +230,15 @@ Generated files go in `.hector/` — add it to your `.gitignore`. The Renode **b
151
230
  | `hector validate -f board.yaml` | Validate a config file by another name |
152
231
  | `hector init` | Scaffold a starter `.hector.yaml` |
153
232
  | `hector init -f board.yaml` | Scaffold the starter config under a custom name |
233
+ | `hector clean` | Remove generated build artifacts (`.hector/resc,repl,tests`) and `results/`; keeps the Renode cache |
234
+ | `hector clean --all` | Also remove the cached Renode source checkouts under `.hector/` (forces a re-clone next build) |
235
+ | `hector clean --output my-results` | Clean a custom results directory instead of `results/` |
236
+ | `hector clean --dry-run` | Show what would be removed without deleting anything |
154
237
  | `hector --version` | Print the tool version |
155
238
 
156
239
  `hector` is structured as subcommands: `run` (simulate), `test` (run the `tests:`
157
- section), `export` (emit the command without running it), plus `init` and
158
- `validate`. Run `hector <command> --help` for the flags each one accepts.
240
+ section), `export` (emit the command without running it), plus `init`, `validate`,
241
+ and `clean`. Run `hector <command> --help` for the flags each one accepts.
159
242
 
160
243
  Every command reads (or, for `init`, writes) `.hector.yaml` by default. Point it
161
244
  at a different file with **`-f` / `--file`** — useful when one project keeps
@@ -166,6 +249,11 @@ hector test -f ci.hector.yaml
166
249
  hector run --file boards/nucleo.yaml
167
250
  ```
168
251
 
252
+ **`.yaml` and `.yml` are interchangeable.** If the requested file isn't there but its
253
+ counterpart is, hector uses that instead — so a project may keep `.hector.yml` and
254
+ every command still finds it with no flag, and `-f board.yaml` will pick up
255
+ `board.yml`.
256
+
169
257
  ### Debug mode (`--debug NODE:PORT`)
170
258
 
171
259
  Repeat the flag for each machine you want to debug. ([Renode docs: GDB debugging](https://renode.readthedocs.io/en/latest/debugging/gdb.html))
@@ -181,6 +269,22 @@ server(s) and halts the debugged CPU(s) before resuming, so you can attach to a
181
269
  restored state. (A GDB server is a live connection, never part of saved snapshot
182
270
  state, so it is always (re)started on load.)
183
271
 
272
+ ### Manual start (`--no-start`)
273
+
274
+ Every generated resc ends with a `start`, so `hector run` boots the platform
275
+ immediately. Pass `--no-start` to omit it: hector builds/loads the platform, wires
276
+ everything up, and drops you at the Renode monitor **paused**, so you can inspect
277
+ state, set watchpoints, or step the setup by hand and issue `start` yourself.
278
+
279
+ ```bash
280
+ hector run --no-start # land in the monitor; type `start` when ready
281
+ ```
282
+
283
+ - Applies to a fresh boot and to `--snapshot` (the restored state loads paused).
284
+ - Composes with `--debug`: the GDB server(s) open at load, but nothing runs until
285
+ you `start`, so you can attach a debugger *before* the very first instruction.
286
+ - `hector test` ignores this (tests must run); it only affects `run`/`export`.
287
+
184
288
  Connect with:
185
289
  ```bash
186
290
  arm-none-eabi-gdb firmware.elf
@@ -239,7 +343,7 @@ hector run --snapshot results/step_1_Linux_boots/snapshot.save
239
343
  hector test --snapshot results/step_1_Linux_boots/snapshot.save
240
344
  ```
241
345
 
242
- When used with `--renode-version`, no `.hector.yaml` is needed at all — useful for inspecting a snapshot outside of any project:
346
+ When used with `--renode-version` (or `--renode-image`), no `.hector.yaml` is needed at all — useful for inspecting a snapshot outside of any project:
243
347
 
244
348
  ```bash
245
349
  hector run --snapshot /path/to/snapshot.save --renode-version 1.16.1
@@ -404,6 +508,20 @@ When combined with `--snapshot` in simulation mode, `.hector.yaml` is not requir
404
508
  hector run --snapshot path/to/snapshot.save --renode-version 1.16.1
405
509
  ```
406
510
 
511
+ #### Using a custom Renode image (`--renode-image`)
512
+
513
+ By default the image is `antmicro/renode:<renode_version>`. To use any other image — a nightly, a mirror in your registry, or one you built yourself — set `renode_image:` in `.hector.yaml` or pass `--renode-image`:
514
+
515
+ ```yaml
516
+ renode_image: my-renode:dev
517
+ ```
518
+
519
+ ```bash
520
+ hector test --renode-image ghcr.io/acme/renode:1.16.1-patched
521
+ ```
522
+
523
+ Precedence: CLI flags beat the config, and either flag replaces *both* config fields (so `--renode-version 1.15.0` wins over a `renode_image:` in the file). If both fields are set in the config, `renode_image` is the image that runs and `renode_version` only picks the Renode source tag to clone. That tag is otherwise inferred from the image tag when it looks like a version (`…:1.16.1` / `…:v1.16.1`); if the config needs the source (see below) and it can't be inferred, also set `renode_version`.
524
+
407
525
  #### Renode source checkout
408
526
 
409
527
  Running a simulation does **not** need the Renode source — the binary and its bundled platforms come from the `antmicro/renode` Docker image. Hector clones the Renode source (and the verilator-integration repo) into `.hector/` **only when a config actually needs it**:
@@ -501,7 +619,8 @@ The configuration lives in `.hector.yaml`.
501
619
  | Field | Required | Description |
502
620
  |---|---|---|
503
621
  | `version` | No | Schema version (currently `"0.1"`). Warns if unrecognised. |
504
- | `renode_version` | Yes | Renode version, no leading `v` (e.g. `1.16.1`). Selects both the git tag for cloning and the Docker image tag. |
622
+ | `renode_version` | Yes¹ | Renode version, no leading `v` (e.g. `1.16.1`). Selects both the git tag for cloning and the Docker image tag. |
623
+ | `renode_image` | Yes¹ | Full Renode Docker image to use instead of `antmicro/renode:<renode_version>` (e.g. a self-built `my-renode:dev`). See [custom Renode image](#using-a-custom-renode-image---renode-image). |
505
624
  | `arguments` | No | Scalar defaults, overridable by env var or `--set`. |
506
625
  | `build` | No | Pre-sim shell steps run once per job in containers (compile firmware, fetch/generate files, …). Interpolated with the job's arguments/matrix variables. |
507
626
  | `matrix` | No | Cross-product job expansion. |
@@ -514,6 +633,8 @@ The configuration lives in `.hector.yaml`.
514
633
  | `quantum` | No | Override the global time quantum (seconds). |
515
634
  | `ci` | No | CI pipeline definitions: when and how a CI server runs this config. |
516
635
 
636
+ ¹ At least one of `renode_version` / `renode_image` is required (or the matching CLI flag).
637
+
517
638
  ---
518
639
 
519
640
  ### arguments
@@ -606,11 +727,21 @@ modules:
606
727
 
607
728
  #### kind: csharp
608
729
 
609
- Builds (or locates) a C# Renode peripheral plugin. The resulting `.dll` is loaded at emulation scope via `i @<path>` before any machine block, making the type available to all machines in the job. ([Renode docs: writing peripherals](https://renode.readthedocs.io/en/latest/advanced/writing-peripherals.html))
730
+ A native C# Renode peripheral, loaded at emulation scope via `i @<path>` before any machine block so the type is available to every machine in the job. ([Renode docs: writing peripherals](https://renode.readthedocs.io/en/latest/advanced/writing-peripherals.html))
610
731
 
611
- Two usage modes:
732
+ `source` can take three forms:
612
733
 
613
- **Pre-built DLL** — point `source` directly at the `.dll`:
734
+ **Single `.cs` file (recommended)** — Renode compiles it **at load time** using its bundled C# compiler. No .NET SDK, no build step, nothing to install; the source is compiled against the running Renode's own assemblies, so it always matches the version in use. See the runnable [`csharp-peripheral`](examples/csharp-peripheral) example.
735
+
736
+ ```yaml
737
+ modules:
738
+ my_periph:
739
+ kind: csharp
740
+ type: Antmicro.Renode.Peripherals.Miscellaneous.MyPeripheral
741
+ source: MyPeripheral.cs
742
+ ```
743
+
744
+ **Pre-built DLL** — point `source` directly at a `.dll` (used as-is):
614
745
 
615
746
  ```yaml
616
747
  modules:
@@ -620,7 +751,7 @@ modules:
620
751
  source: prebuilt/my_periph.dll
621
752
  ```
622
753
 
623
- **Build from source** — point `source` at a directory containing a `.csproj`. `dotnet build` runs inside the Renode container (which ships with Mono/dotnet):
754
+ **Build from a `.csproj`** — point `source` at a directory containing a `.csproj`; `dotnet build` (or `msbuild`) runs in the container. This needs an image that ships the **.NET SDK** *and* Renode's reference assemblies — the stock Renode image has only the runtime, so a `.cs` source is simpler unless you specifically need a pre-built binary:
624
755
 
625
756
  ```yaml
626
757
  modules:
@@ -633,10 +764,63 @@ modules:
633
764
  | Field | Required | Description |
634
765
  |---|---|---|
635
766
  | `kind` | Yes | Must be `csharp`. |
636
- | `type` | Yes | Fully qualified C# class name as it will appear in the generated `.repl`. |
637
- | `source` | Yes | Path to a `.csproj` directory **or** a pre-built `.dll` file. |
767
+ | `type` | Yes | Fully qualified C# class name as it appears in the generated `.repl`. |
768
+ | `source` | Yes | A `.cs` file (compiled at load), a `.csproj` directory (built in the container), **or** a pre-built `.dll`. |
769
+
770
+ The `type` must match the class your source exposes. Multiple peripherals in the same job can share one source (different `type` values, same `source`); Hector emits a single `i @<path>` import even when multiple instances reference it.
771
+
772
+ #### Developing your own peripherals
638
773
 
639
- The `type` field is what you would write in a `.repl` entry — it must match the class exposed by the compiled DLL. Multiple peripherals in the same job can share one DLL (different `type` values, same `source`); Hector emits a single `i @<path>` import even when multiple instances reference the same DLL.
774
+ The `modules:` block above only *wires in* a peripheral you've built — the actual
775
+ modelling (the Verilog/C++ of a Verilated block, or the C# of a native peripheral)
776
+ is Renode's domain, not Hector's. Hector compiles your `source:` and loads the
777
+ result; **how** you write that source is documented by Renode and Verilator. The
778
+ references below are where to go to design your own hardware in depth.
779
+
780
+ ##### Verilated (HDL) peripherals
781
+
782
+ A Verilated peripheral is your RTL (Verilog / SystemVerilog) compiled by Verilator
783
+ and bridged to Renode over a bus interface (APB / AXI-Lite / Wishbone). Hector
784
+ builds it from the CMake project you point `source:` at, linking against the
785
+ **renode-verilator-integration** library (`${INTEGRATION_DIR}`).
786
+
787
+ - **How Renode co-simulates HDL** (the model, the bus connectors, the lifecycle) — [Renode docs: Co-simulating with an HDL simulator](https://renode.readthedocs.io/en/latest/advanced/co-simulating-with-an-hdl-simulator.html)
788
+ - **The integration library + copy-ready CMake samples** (start from `samples/uartlite`, which the `docker-runner`/module examples mirror) — [antmicro/renode-verilator-integration](https://github.com/antmicro/renode-verilator-integration)
789
+ - **Verilating your RTL** (the Verilator C++ API, `--cc`, the `V<top>` model) — [Verilator manual](https://verilator.org/guide/latest/)
790
+ - **Declaring the peripheral in a platform** (the `CoSimulated*` type, its bus window) — [Renode docs: platform description format](https://renode.readthedocs.io/en/latest/advanced/platform_description_format.html)
791
+
792
+ Workflow: verilate your RTL → wrap it with the integration library's bus connector
793
+ in a CMake project → point a `renode-verilator` module's `source:` at that project
794
+ → reference the module from a machine's `peripherals:`.
795
+
796
+ ##### C# peripherals
797
+
798
+ A C# peripheral is a native Renode model — full speed, with direct access to
799
+ Renode's register / IRQ / GPIO infrastructure. Use this when you don't have (or
800
+ don't need) RTL, e.g. a register-level model of a sensor or controller.
801
+
802
+ - **Writing a peripheral from scratch** (interfaces, read/write, reset — the canonical guide) — [Renode docs: Writing your own peripheral](https://renode.readthedocs.io/en/latest/advanced/writing-peripherals.html)
803
+ - **Register modelling helpers** (`DoubleWordRegisterCollection`, fields, value/read/write callbacks) — [Renode docs: Registers](https://renode.readthedocs.io/en/latest/advanced/registers.html)
804
+ - **Hundreds of real models to read and adapt** — the Renode source tree under [`src/.../Emulator/Peripherals`](https://github.com/renode/renode/tree/master/src/Infrastructure/src/Emulator/Peripherals/Peripherals)
805
+ - **Wiring the finished class into a machine** (the `.repl` entry, IRQ/GPIO connections) — [Renode docs: platform description format](https://renode.readthedocs.io/en/latest/advanced/platform_description_format.html)
806
+
807
+ Workflow: implement the class (e.g. an `IDoubleWordPeripheral` with a register
808
+ collection, plus `GPIO`/`IKnownSize`/`IGPIOReceiver` as needed) in a **single
809
+ `.cs` file** → point a `csharp` module's `source:` at it → reference its
810
+ fully-qualified `type` from `peripherals:`. Renode compiles the `.cs` at load
811
+ (bundled C# compiler — no .NET SDK), so this is the simplest, version-matched
812
+ path; the [`csharp-peripheral`](examples/csharp-peripheral) example is a complete,
813
+ runnable starting point. Reach for a `.csproj`/`.dll` only to pre-compile a larger
814
+ project — and note that needs a build image carrying both the .NET SDK and
815
+ Renode's reference assemblies.
816
+
817
+ Either kind, once built, is a first-class Renode peripheral: connect it with
818
+ [connections](#connection-syntax), bind it to host resources with [mappings](#mappings-global),
819
+ and drive it from your [tests](#tests).
820
+
821
+ > **Version note:** Renode's online docs track its latest release. If you pin an
822
+ > older `renode_version:`, cross-check against that release's docs/tag — the
823
+ > co-simulation bus interface and some C# APIs evolve between versions.
640
824
 
641
825
  ---
642
826
 
@@ -725,12 +909,16 @@ machines:
725
909
  backend: renode # optional; 'renode' is the only supported backend
726
910
  platform:
727
911
  - platforms/boards/${BOARD}.repl
912
+ repl: |
913
+ ...
728
914
  firmware: ${FW}
729
915
  peripherals: { ... }
730
916
  connections: |
731
917
  ...
732
918
  mappings: |
733
919
  ...
920
+ resc: |
921
+ ...
734
922
  commands: |
735
923
  ...
736
924
  ```
@@ -738,15 +926,89 @@ machines:
738
926
  | Field | Description |
739
927
  |---|---|
740
928
  | `backend` | Must be `renode` (default). |
741
- | `platform` | List of [`.repl` platform description](https://renode.readthedocs.io/en/latest/advanced/platform_description_format.html) files loaded in order. |
929
+ | `platform` | List of [`.repl` platform description](https://renode.readthedocs.io/en/latest/advanced/platform_description_format.html) **file paths**, loaded in order. |
930
+ | `repl` | Inline `.repl` platform description **text** (see [below](#inline-repl-and-resc)). |
742
931
  | `firmware` | ELF file loaded with [`sysbus LoadELF`](https://renode.readthedocs.io/en/latest/basic/machines.html). Omit or set to `none` to skip. |
743
932
  | `peripherals` | Peripheral instances composed onto this machine. See below. |
744
933
  | `connections` | Signal wiring scoped to this machine. Covers GPIO, IRQ, and bracket-range connections. Bare peripheral names are accepted. |
745
934
  | `mappings` | Per-machine host resource bindings. Same syntax as global `mappings:`. |
935
+ | `resc` | Inline `.resc` monitor-script **text** (see [below](#inline-repl-and-resc)). |
746
936
  | `commands` | Raw [Renode monitor](https://renode.readthedocs.io/en/latest/basic/monitor-syntax.html) commands inserted into the resc after hardware loads. |
747
937
 
748
938
  > **Note:** `artifacts` is now a **top-level** key, not a per-machine one. See [artifacts](#artifacts).
749
939
 
940
+ #### Inline `repl` and `resc`
941
+
942
+ `platform:` takes *paths*, which only works for boards the released Renode image
943
+ already ships. When the board you need exists only on Renode's **master** branch (or
944
+ in your own fork), there is no path to point at — so `repl:` and `resc:` take the
945
+ file **contents** verbatim instead:
946
+
947
+ ```yaml
948
+ machines:
949
+ mcu:
950
+ repl: | # a .repl pasted straight in
951
+ sram: Memory.MappedMemory @ sysbus 0x20000000
952
+ size: 0x10000000
953
+ cpu: CPU.CortexM @ sysbus
954
+ cpuType: "cortex-m3"
955
+ nvic: nvic
956
+ resc: | # a .resc's setup lines
957
+ sysbus ApplySVD @https://.../STM32F103.svd.gz
958
+ sysbus Tag <0x40021000, 0x40021003> "RCC_CR" 0x0A020083
959
+ ```
960
+
961
+ - **`repl:`** is written to `.hector/repl/job_<n>_<node>.inline.repl` and loaded with
962
+ `machine LoadPlatformDescription` (Renode only reads platform descriptions from
963
+ disk). It is loaded **after** any `platform:` files.
964
+
965
+ > **Patching a bundled platform: use `using`, not `platform:`.** Every
966
+ > `LoadPlatformDescription` is its **own description scope**, so an entry that another
967
+ > file created is only partly reachable from `repl:` — setting a *constructor*
968
+ > attribute on it fails with
969
+ > `E35: Constructor attribute within entry for variable that is not created`.
970
+ > To override one, pull the base platform into the *same* scope from inside `repl:`:
971
+ >
972
+ > ```yaml
973
+ > repl: |
974
+ > using "platforms/boards/nucleo_h753zi.repl"
975
+ >
976
+ > nvic:
977
+ > priorityMask: 0xFF # works: same scope that creates `nvic`
978
+ > ```
979
+ >
980
+ > This is what Renode's own scripts do with `LoadPlatformDescriptionFromString`.
981
+ > Use `platform:` alone when you're loading a board as-is, and `using` inside `repl:`
982
+ > when you need to patch it. See [`examples/nucleo-h753zi`](examples/nucleo-h753zi).
983
+ - **`resc:`** is emitted verbatim into that machine's block, **after** the platform
984
+ and firmware load and **before** `commands:`.
985
+
986
+ Resulting order inside one machine:
987
+
988
+ ```
989
+ mach create "<node>"
990
+ machine LoadPlatformDescription @<platform: files>
991
+ machine LoadPlatformDescription @<inline repl:>
992
+ sysbus LoadELF @<firmware:>
993
+ <resc:>
994
+ <commands:>
995
+ ```
996
+
997
+ > **Do not put `mach create` in `resc:`** — hector already creates the machine. Use
998
+ > `resc:` for the lines that follow it (`sysbus ApplySVD`, `sysbus Tag`, macros,
999
+ > additional `LoadPlatformDescription`, …).
1000
+
1001
+ Both accept a block scalar or a list of lines, and both are interpolated like every
1002
+ other field. Worked examples:
1003
+
1004
+ - [`examples/inline-repl-resc`](examples/inline-repl-resc) — the mechanics, on an
1005
+ STM32F103 that boots real firmware.
1006
+ - [`examples/nucleo-f767zi`](examples/nucleo-f767zi) — the real motivation: a
1007
+ **NUCLEO-F767ZI**, which Renode 1.16.1 ships no `.repl` for at all, defined inline
1008
+ and running against the pinned release image.
1009
+ - [`examples/nucleo-h753zi`](examples/nucleo-h753zi) — the other side: a board that
1010
+ **is** shipped, loaded via `using` and *patched* inline, booting Hubris.
1011
+
750
1012
  #### peripherals
751
1013
 
752
1014
  Each entry declares one peripheral instance on this machine. The `type` field is either a built-in Renode class name, a `renode-verilator` module name, or a `csharp` module name. Properties are written directly as flat keys alongside `type` and `at`.