commit 9a08be53e52cf8b49d67746c838713773b930daa
parent bdedf3e3a899eb0d3b8723e306adc199573a7581
Author: Bradley Gannon <bradley@bradleygannon.com>
Date: Fri, 17 Jul 2026 22:28:39 -0400
Add initial configuration for building riscv-arch-test
Diffstat:
9 files changed, 954 insertions(+), 3 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -13,4 +13,6 @@ project/metals.sbt
project/project/
project/target/
target/
+tests/perilus-rv32i
+tests/stamps
verilated/
diff --git a/flake.lock b/flake.lock
@@ -2,7 +2,8 @@
"nodes": {
"root": {
"inputs": {
- "stable-pkgs": "stable-pkgs"
+ "stable-pkgs": "stable-pkgs",
+ "unstable-pkgs": "unstable-pkgs"
}
},
"stable-pkgs": {
@@ -20,6 +21,22 @@
"repo": "nixpkgs",
"type": "github"
}
+ },
+ "unstable-pkgs": {
+ "locked": {
+ "lastModified": 1784007870,
+ "narHash": "sha256-djcLt/JJphyNt4eDY9XTly+/WbCK5lqWq9lSgCmJkkQ=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "18b9261cb3294b6d2a06d03f96872827b8fe2698",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
}
},
"root": "root",
diff --git a/flake.nix b/flake.nix
@@ -3,30 +3,60 @@
inputs = {
stable-pkgs.url = "github:nixos/nixpkgs?ref=nixos-26.05";
+ unstable-pkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
outputs =
- { self, stable-pkgs }:
+ {
+ self,
+ stable-pkgs,
+ unstable-pkgs,
+ }:
let
system = "x86_64-linux";
stable = import stable-pkgs {
inherit system;
};
+ unstable = import unstable-pkgs {
+ inherit system;
+ };
+ libInputs = with stable; [
+ stdenv.cc.cc.lib
+ ];
+ lib-path = with stable; lib.makeLibraryPath libInputs;
in
{
devShells.${system}.default = stable.mkShellNoCC {
packages = with stable; [
act
+ bundler
+ cargo
coursier
+ gcc
+ git
+ gnumake
gtkwave
jdk21
just
llvm
metals
+ pkgsCross.riscv64-embedded.binutils
+ pkgsCross.riscv64-embedded.gcc
+ ruby
+ rust-analyzer
+ rustc
+ rustfmt
sbt
typst
+ unstable.sail-riscv
+ uv
verilator
];
+
+ shellHook = ''
+ export BUNDLE_FROZEN=1
+ export "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${lib-path}"
+ '';
};
};
}
diff --git a/justfile b/justfile
@@ -1,8 +1,17 @@
ci: fmt clean test doc
-test:
+test: test-chisel test-official
+
+test-chisel:
sbt test
+test-official:
+ cd riscv-arch-test && \
+ CONFIG_FILES=../tests/perilus/test_config.yaml \
+ WORKDIR=../tests \
+ make --jobs $(nproc)
+ # TODO run the tests in the simulator
+
doc:
typst compile -f svg doc/perilus.typ
@@ -33,3 +42,5 @@ clean:
sbt clean
rm -rf build generated verilated
cd sim && cargo clean
+ rm -rf tests/perilus-rv32i tests/stamps
+ cd riscv-arch-test && make clean
diff --git a/tests/perilus/link.ld b/tests/perilus/link.ld
@@ -0,0 +1,15 @@
+OUTPUT_ARCH( "riscv" )
+ENTRY(rvtest_entry_point)
+
+SECTIONS
+{
+ . = 0x0;
+ .text.init : { *(.text.init) }
+ .text.rvtest : { *(.text.rvtest) *(.text.rvtest.*) }
+ . = ALIGN(0x100);
+ .data : { *(.data) }
+ . = ALIGN(0x100);
+ .text.rvmodel : { *(.text.rvmodel) *(.text.rvmodel.*) *(.text) *(.text.*) }
+ . = ALIGN(0x100);
+ _end = .;
+}
diff --git a/tests/perilus/perilus.yaml b/tests/perilus/perilus.yaml
@@ -0,0 +1,53 @@
+# yaml-language-server: $schema=https://raw.githubusercontent.com/riscv/riscv-unified-db/main/spec/schemas/config_schema.json
+---
+$schema: config_schema.json#
+kind: architecture configuration
+type: fully configured
+name: perilus-rv32i
+description: Perilus RISC-V processor
+implemented_extensions:
+ - { name: I, version: "= 2.1" }
+ - { name: M, version: "= 2.0" }
+ - { name: Sm, version: "= 1.12.0" }
+params:
+ MXLEN: 32
+ PRECISE_SYNCHRONOUS_EXCEPTIONS: true
+ TRAP_ON_ECALL_FROM_M: true
+ TRAP_ON_EBREAK: true
+ MARCHID_IMPLEMENTED: true
+ ARCH_ID_VALUE: 1
+ MIMPID_IMPLEMENTED: true
+ IMP_ID_VALUE: 0x0
+ VENDOR_ID_BANK: 0x0
+ VENDOR_ID_OFFSET: 0x0
+ MISALIGNED_LDST: false
+ MISALIGNED_LDST_EXCEPTION_PRIORITY: high
+ TRAP_ON_ILLEGAL_WLRL: false
+ TRAP_ON_UNIMPLEMENTED_INSTRUCTION: true
+ TRAP_ON_RESERVED_INSTRUCTION: true
+ TRAP_ON_UNIMPLEMENTED_CSR: true
+ REPORT_VA_IN_MTVAL_ON_BREAKPOINT: true
+ REPORT_VA_IN_MTVAL_ON_LOAD_MISALIGNED: true
+ REPORT_VA_IN_MTVAL_ON_STORE_AMO_MISALIGNED: true
+ REPORT_VA_IN_MTVAL_ON_INSTRUCTION_MISALIGNED: true
+ REPORT_VA_IN_MTVAL_ON_LOAD_ACCESS_FAULT: true
+ REPORT_VA_IN_MTVAL_ON_STORE_AMO_ACCESS_FAULT: true
+ REPORT_VA_IN_MTVAL_ON_INSTRUCTION_ACCESS_FAULT: true
+ REPORT_ENCODING_IN_MTVAL_ON_ILLEGAL_INSTRUCTION: true
+ MTVAL_WIDTH: 32
+ CONFIG_PTR_ADDRESS: 0
+ PMA_GRANULARITY: 3
+ PHYS_ADDR_WIDTH: 32
+ M_MODE_ENDIANNESS: little
+ MISA_CSR_IMPLEMENTED: true
+ MTVEC_ACCESS: rw
+ MTVEC_MODES: [0, 1]
+ MTVEC_BASE_ALIGNMENT_DIRECT: 4
+ MTVEC_BASE_ALIGNMENT_VECTORED: 4
+ MTVEC_ILLEGAL_WRITE_BEHAVIOR: retain
+ NUM_PMP_ENTRIES: 0
+ MUTABLE_MISA_M: false
+ MCOUNTINHIBIT_IMPLEMENTED: true
+ MCOUNTENABLE_EN: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
+ HPM_COUNTER_EN: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
+ COUNTINHIBIT_EN: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
diff --git a/tests/perilus/rvmodel_macros.h b/tests/perilus/rvmodel_macros.h
@@ -0,0 +1,44 @@
+#ifndef _RVMODEL_MACROS_H
+#define _RVMODEL_MACROS_H
+
+#define RVMODEL_DATA_SECTION \
+ .pushsection .tohost,"aw",@progbits; \
+ .balign 8; .global tohost; tohost: .word 0; \
+ .balign 8; .global fromhost; fromhost: .word 0; \
+ .popsection
+
+#define RVMODEL_HALT_PASS \
+ li x1, 1; \
+ la t0, tohost; \
+ write_tohost_pass: \
+ sw x1, 0(t0); \
+ sw x0, 4(t0); \
+ j write_tohost_pass; \
+
+#define RVMODEL_HALT_FAIL \
+ li x1, 3; \
+ la t0, tohost; \
+ write_tohost_fail: \
+ sw x1, 0(t0); \
+ sw x0, 4(t0); \
+ j write_tohost_fail; \
+
+#define RVMODEL_IO_WRITE_STR(_R1, _R2, _R3, _STR_PTR)
+
+#define RVMODEL_INTERRUPT_LATENCY 0
+#define RVMODEL_TIMER_INT_SOON_DELAY 0
+
+#define RVMODEL_SET_MEXT_INT(_R1, _R2)
+#define RVMODEL_CLR_MEXT_INT(_R1, _R2)
+#define RVMODEL_SET_MSW_INT(_R1, _R2)
+#define RVMODEL_CLR_MSW_INT(_R1, _R2)
+
+#define RVMODEL_SET_SEXT_INT(_R1, _R2)
+#define RVMODEL_CLR_SEXT_INT(_R1, _R2)
+#define RVMODEL_SET_SSW_INT(_R1, _R2)
+#define RVMODEL_CLR_SSW_INT(_R1, _R2)
+
+#define CLINT_BASE_ADDRESS 0x00000000
+#define RVMODEL_MSIP_ADDRESS (CLINT_BASE_ADDRESS + 0x0)
+
+#endif /* _RVMODEL_MACROS_H */
diff --git a/tests/perilus/sail.json b/tests/perilus/sail.json
@@ -0,0 +1,771 @@
+{
+ "$schema": "/opt/riscv/share/sail-riscv/sail_riscv_config_schema.json",
+ "base": {
+ "xlen": 32,
+ // Whether the base ISA is E, in which case accessing
+ // x16-31 is reserved and in this implementation will
+ // raise an illegal instruction exception.
+ "E": false,
+ "writable_misa": false,
+ "writable_fiom": true,
+ // The top 29 bits in this value control whether the corresponding
+ // HPM counters (hpmcounter31 .. hpmcounter3) are supported
+ // (i.e. are not read-only zero). A set bit specifies that the
+ // corresponding counter is supported. The lowest 3 bits
+ // (writable_hpm_counters[2 .. 0]) are ignored.
+ "writable_hpm_counters": {
+ "len": 32,
+ "value": "0x0"
+ },
+ // The bits in this value control whether the corresponding bits
+ // of the `scounteren` CSR that control access to HPM counters,
+ // and `cycle`, `time` and `instret` registers, are read-only
+ // zero. A set bit specifies that the corresponding bit of
+ // `scounteren` is writable, otherwise the bit is read-only zero.
+ // If Sscounterenw is supported the top 29 bits must be a superset of
+ // the top 29 bits of `writable_hpm_counters`.
+ "scounteren_writable_bits": {
+ "len": 32,
+ "value": "0x0"
+ },
+ // The bits in this value control whether the corresponding bits
+ // of the `mcounteren` CSR that control access to HPM counters,
+ // and `cycle`, `time` and `instret` registers at lower privilege
+ // modes, are read-only zero. A set bit specifies that the
+ // corresponding bit of `mcounteren` is writable, otherwise the
+ // bit is read-only zero.
+ "mcounteren_writable_bits": {
+ "len": 32,
+ "value": "0x0"
+ },
+ // `mtvec.{direct,vectored}.supported` indicates whether the
+ // corresponding mode is supported for `mtvec`. At least one mode
+ // should be supported. If both modes are supported, the mode on
+ // reset is unspecified.
+ // The `mtvec.{direct,vectored}.base_alignment` parameters control the alignment
+ // of the trap vector base for each mode. The alignment is
+ // specified as the power of 2 of the desired byte alignment, and
+ // can range from a minimum of 2 upto a maximum of 24. If
+ // unaligned values are written to these CSRs, the lowest bits
+ // will be zeroed to respect the specified alignment.
+ "mtvec": {
+ "direct": {
+ "supported": true,
+ "base_alignment": 2
+ },
+ "vectored": {
+ "supported": true,
+ "base_alignment": 2
+ }
+ },
+ // Similar to `mtvec` above. If `S` mode is not supported, these
+ // values need to be present and legal but are ignored.
+ "stvec": {
+ // The spec requires `base_alignment` for `stvec.direct` to be 2
+ // (i.e. 4-byte alignment), hence there is no configuration
+ // parameter for it.
+ "direct": {
+ "supported": false
+ },
+ "vectored": {
+ "supported": false,
+ "base_alignment": 2
+ }
+ },
+ // These settings control whether the specified exceptions
+ // cause information to be written into the appropriate
+ // `xtval` registers.
+ "xtval_nonzero": {
+ "illegal_instruction": true,
+ "software_breakpoint": true,
+ "hardware_breakpoint": true,
+ "load_address_misaligned": true,
+ "load_access_fault": true,
+ "load_page_fault": true,
+ "samo_address_misaligned": true,
+ "samo_access_fault": true,
+ "samo_page_fault": true,
+ "fetch_address_misaligned": true,
+ "fetch_access_fault": true,
+ "fetch_page_fault": true,
+ "software_check": true,
+ "reserved_exceptions": false
+ },
+ "reserved_behavior": {
+ // The configuration option determines how to handle the reserved behavior `amocas_odd_registers`.
+ // "AMOCAS_Fatal" – raise a Sail exception, stopping execution.
+ // "AMOCAS_Illegal" – treat it as an illegal instruction.
+ "amocas_odd_register": "AMOCAS_Fatal",
+ // The configuration option determines how to handle execution of a floating-point
+ // instruction with DYN (dynamic) rounding mode when `fcsr.FRM` contains a
+ // reserved value (0b101, 0b110, 0b111).
+ // This does not affect the execution of floating-point instructions that have a
+ // reserved rounding mode statically encoded in the instruction.
+ // "Fcsr_RM_Fatal" – raise a Sail exception, stopping execution.
+ // "Fcsr_RM_Illegal" – treat it as an illegal instruction.
+ "fcsr_rm": "Fcsr_RM_Fatal",
+ // The configuration option determines how to handle the reserved behavior `pmpcfg_with_R0W1`.
+ // "PMP_Fatal" – raise a Sail exception, stopping execution.
+ // "PMP_ClearPermissions" – convert a PMP entry with R=0, W=1 to R=0, W=0, X=0.
+ "pmpcfg_write_only": "PMP_ClearPermissions",
+ // The configuration option determines how to handle the reserved behavior `xenvcfg.CBIE` with 0b10.
+ // "Xenvcfg_Fatal" – raise a Sail exception, stopping execution.
+ // "Xenvcfg_ClearPermissions" – convert CBIE with 0b10 to 0b00.
+ "xenvcfg_cbie": "Xenvcfg_ClearPermissions",
+ // The configuration option determines how to handle the reserved behavior `xtvec[Mode] >= 2`.
+ // "Xtvec_Fatal" – raise a Sail exception, stopping execution.
+ // "Xtvec_Ignore" – use old Mode of xtvec.
+ "xtvec_mode": "Xtvec_Ignore",
+ // The configuration option determines how to handle the reserved behavior: Odd-numbered registers for RV32Zdinx.
+ // "Zdinx_Fatal" – raise a Sail exception, stopping execution.
+ // "Zdinx_Illegal" – treat it as an illegal instruction.
+ "rv32zdinx_odd_register": "Zdinx_Fatal"
+ },
+ "mstatus": {
+ // The legal values for the FS and VS fields in this CSR are
+ // specified by the two fields below. Their values can be one
+ // of:
+ // - "ExtContext_FourState" allows all values {Off, Initial, Clean, Dirty}.
+ // - "ExtContext_TwoState" allows {Off, Dirty}, and writes of Initial and Clean get written as Dirty.
+ // - "ExtContext_Off" allows only {Off}. This makes the field read-only zero.
+ "fs_legal_states": "ExtContext_FourState",
+ "vs_legal_states": "ExtContext_Off"
+ }
+ },
+ "memory": {
+ "pmp": {
+ "grain": 0,
+ // This specifies the number of PMP entries present.
+ // The value must be one of 0, 16, or 64.
+ "count": 0,
+ // This specifies the number of usable PMP entries.
+ // Entries higher than this are read-only-zero.
+ // The value must be less than or equal to `count`.
+ "usable_count": 0,
+ "tor_supported": true,
+ "na4_supported": true,
+ "napot_supported": true
+ },
+ // These settings control global support for misaligned access so they are
+ // checked before address translation. `misaligned_fault` in
+ // `regions` is checked after address translation.
+ "misaligned": {
+ // `exceptions` specifies the treatment of misaligned accesses
+ // before address translation. If a fault is specified for an access,
+ // it will have a higher priority than memory-protection faults arising from
+ // that access if it were allowed to proceed.
+ "exceptions": {
+ // A misaligned scalar or vector load/store can either proceed
+ // without a fault (use `{"None" : null}`), or raise an access fault
+ // (use `{"Some": "AccessFault"}`) or a misaligned exception
+ // (use `{"Some": "AlignmentException"}`).
+ // This option controls scalar loads/stores.
+ "load_store": {
+ "Some": "AlignmentException"
+ },
+ // A misaligned vector load/store can be configured
+ // independently of the scalar case above, but uses the same
+ // option values.
+ "vector": {
+ "Some": "AlignmentException"
+ },
+ // A misaligned LR/SC currently always faults, and this field can specify
+ // whether it generates an access fault (use `"AccessFault"`)
+ // or a misaligned exception (use `"AlignmentException"`).
+ "lrsc": "AccessFault",
+ // Similarly, a misaligned AMO currently always faults, and this field
+ // can specify either `"AccessFault"` or `"AlignmentException"`.
+ "amo": "AccessFault"
+ },
+ // If a misaligned access was specified to have no fault in `exceptions` above, the
+ // fields below specify how it is handled.
+ //
+ // Memory accesses that span multiple naturally aligned
+ // 2^allowed_within_exp sized regions will be split into multiple
+ // memory operations. 0 means all misaligned accesses will be split.
+ // The maximum value is 12 (one page).
+ "allowed_within_exp": 0,
+ // If the access gets split due to `allowed_within_exp` then the size
+ // of the operations will be one byte if `byte_by_byte` is set, otherwise
+ // they will be the maximum size possible based on the alignment. For
+ // example a 4-byte access to address 0x2 will use two 2-byte operations.
+ "byte_by_byte": false,
+ // If multiple memory operations are needed, this controls whether they
+ // are done in increasing or decreasing address order. This is architecturally
+ // observable because some store operations may succeed, and even for
+ // loads the resulting `xtval` may depend on this setting.
+ "order_decreasing": false
+ },
+ // Address to write DTB to (if provided). This must be in a suitable memory
+ // region (see `memory.regions`).
+ "dtb_address": {
+ "len": 64,
+ "value": "0x1000"
+ },
+ // The locations and sizes of memory regions and their PMAs. These regions
+ // are required to be aligned to 4K (page) boundaries. To specify
+ // the `misaligned` PMA attribute for a region, see the comments for
+ // `memory.misaligned.exceptions` above.
+ "regions": [
+ // RAM (test code + data + signature region, includes ROM area)
+ {
+ "base": {
+ "len": 64,
+ "value": "0x0"
+ },
+ "size": {
+ "len": 64,
+ "value": "0x50000"
+ },
+ "attributes": {
+ "mem_type": "MainMemory",
+ "cacheable": true,
+ "coherent": true,
+ "executable": true,
+ "readable": true,
+ "writable": true,
+ "read_idempotent": true,
+ "write_idempotent": true,
+ "misaligned_exceptions": {
+ "load_store": {
+ "None": null
+ },
+ "vector": {
+ "None": null
+ },
+ "amo": "AccessFault"
+ },
+ "atomic_support": "AMOArithmetic",
+ "reservability": "RsrvEventual",
+ "supports_cbo_zero": true,
+ "supports_pte_read": true,
+ "supports_pte_write": true
+ },
+ "include_in_device_tree": false
+ },
+ // MMIO
+ {
+ "base": {
+ "len": 64,
+ "value": "0x2000000"
+ },
+ "size": {
+ "len": 64,
+ "value": "0x10000000"
+ },
+ "attributes": {
+ "mem_type": "IOMemory",
+ "cacheable": false,
+ "coherent": true,
+ "executable": false,
+ "readable": true,
+ "writable": true,
+ "read_idempotent": false,
+ "write_idempotent": false,
+ "misaligned_exceptions": {
+ "load_store": {
+ "None": null
+ },
+ "vector": {
+ "None": null
+ },
+ "amo": "AccessFault"
+ },
+ "atomic_support": "AMONone",
+ "reservability": "RsrvNone",
+ "supports_cbo_zero": false,
+ "supports_pte_read": false,
+ "supports_pte_write": false
+ },
+ "include_in_device_tree": false
+ },
+ // RAM
+ {
+ "base": {
+ "len": 64,
+ "value": "0x80000000"
+ },
+ "size": {
+ "len": 64,
+ "value": "0x80000000"
+ },
+ "attributes": {
+ "mem_type": "MainMemory",
+ "cacheable": true,
+ "coherent": true,
+ "executable": true,
+ "readable": true,
+ "writable": true,
+ "read_idempotent": true,
+ "write_idempotent": true,
+ "misaligned_exceptions": {
+ "load_store": {
+ "None": null
+ },
+ "vector": {
+ "None": null
+ },
+ "amo": "AccessFault"
+ },
+ "atomic_support": "AMOCASQ",
+ "reservability": "RsrvEventual",
+ "supports_cbo_zero": true,
+ "supports_pte_read": true,
+ "supports_pte_write": true
+ },
+ "include_in_device_tree": true
+ }
+ ]
+ },
+ "platform": {
+ "vendorid": 0,
+ "archid": 0,
+ "impid": 0,
+ "hartid": 0,
+ // Cache block size, specified as a power of 2.
+ "cache_block_size_exp": 6,
+ "reservation": {
+ // This specifies both the size and alignment of the reservation set, specified as a power of 2.
+ // It must be at least 2 on RV32 and 3 on RV64 to support Zalrsc. It must not be more than
+ // 6 for Za64rs and 7 for Za128rs. In all cases, it must be less than or equal to 12.
+ "reservation_set_size_exp": 2,
+ // Some implementations (e.g. Spike) require the Store-Conditional to provide the same
+ // address as the matching Load-Reserve in order to succeed, regardless of the
+ // configured reservation set size. This controls whether such an exact address
+ // match is required for a Store-Conditional to succeed.
+ "require_exact_reservation_addr": true,
+ // Some implementations (e.g. SiFive U74) also invalidate the
+ // reservation on stores from the same hart. If this is set to `true`, the
+ // model invalidates the reservation if a store from the same hart lies within
+ // the reservation set.
+ "invalidate_on_same_hart_store": false
+ },
+ "clint": {
+ // Whether the platform contains a CLINT.
+ "supported": true,
+ // If supported, this must be in a suitable IO memory region (see `memory.regions`).
+ // Otherwise, these values can be left as 0.
+ "base": 33554432,
+ "size": 786432
+ },
+ // Very simple MMIO device to generate interrupts for testing
+ // purposes. See docs/SimpleInterruptGenerator.md for details.
+ "simple_interrupt_generator": {
+ // Whether the platform contains this device.
+ "supported": true,
+ // If supported, this must be in a suitable IO memory region (see `memory.regions`)
+ // and 4-byte aligned. The size is always 0x20. If not supported, this can be left
+ // as 0.
+ "base": 201326592
+ },
+ "clock_frequency": 1000000000,
+ "instructions_per_tick": 2,
+ "wfi_is_nop": false,
+ // WFI is optionally available to User mode. Note that even if
+ // `wfi_is_nop` is set to `true` above, it will still not be
+ // available to User mode unless `wfi_available_to_user_mode` is
+ // also `true`.
+ "wfi_available_to_user_mode": false,
+ // The maximum increment in the time CSR before a wait instruction
+ // (e.g. WFI, WRS.NTO, WRS.STO) that is not a NOP expires its
+ // wait. It is not possible to wait indefinitely.
+ //
+ // If WFI or WRS.STO (Short TimeOut) exceed this limit in
+ // non-machine privilege with mstatus[TW] set, an illegal
+ // instruction is raised. Otherwise they retire successfully.
+ //
+ // Note: it is also legal for these instructions to spuriously
+ // retire successfully at any point, but there is currently no
+ // configuration option for this behaviour.
+ "max_time_to_wait": 200
+ },
+ "extensions": {
+ "M": {
+ "supported": true
+ },
+ "A": {
+ "supported": true
+ },
+ "F": {
+ "supported": true
+ },
+ "D": {
+ "supported": true
+ },
+ "V": {
+ // `support_level` must be one of the below strings:
+ // . "Disabled" for no vector extension support
+ // . "Integer" for Zve*x support
+ // . "Float_single" for Zve*f support
+ // . "Float_double" for Zve*d support
+ // . "Full" for the full V extension
+ // Note that `support_level` requires compatible
+ // values for `vlen_exp` and `elen_exp` below.
+ // For e.g. Zve32x and Zve32f require `elen_exp` >= 5,
+ // Zve64x, Zve64f, and Zve64d require `elen_exp` >= 6,
+ // and V requires `elen_exp` >= 6 and `vlen_exp` >= 7.
+ "support_level": "Disabled",
+ // `vlen_exp` and `elen_exp` should be between 3 and 16,
+ // inclusive. If `support_level` is `"Disabled"`, then these
+ // should be left as 3 (or any other legal value).
+ "vlen_exp": 8,
+ "elen_exp": 6,
+ "reserved_behavior": {
+ // This determines how to handle attempts by vsetvli, vsetivli,
+ // and vsetvl to set an unsupported or reserved vtype.
+ // "IllegalVtype_SetVill" - set vtype.vill, set vl to zero, clear vstart, and write rd.
+ // "IllegalVtype_Illegal" - treat it as an illegal instruction.
+ // "IllegalVtype_Fatal" - raise a Sail exception, stopping execution.
+ "illegal_vtype": "IllegalVtype_SetVill",
+ // This determines how to handle an out-of-bounds vstart (vstart >= VLMAX), which the
+ // vector spec marks reserved and recommends, but does not require, trapping.
+ // "Vstart_Illegal" - raise an illegal instruction exception.
+ // "Vstart_Ignore" - treat as a no-op, the instruction writes nothing.
+ "vstart_out_of_bounds": "Vstart_Illegal"
+ },
+ "vl_use_ceil": false,
+ // The maximum index EEW for indexed vector addressing mode, as
+ // a power of 2. This must be at least 3 but must not exceed
+ // the supported ELEN.
+ "max_index_eew_exp": 6,
+ "vstart": {
+ // The vector specification permits implementations to raise an
+ // illegal instruction exception when `vstart` is non-zero for
+ // instructions that cannot produce such a `vstart` value through
+ // normal execution.
+ "zero_required": {
+ // Whether vector arithmetic instructions raise an illegal instruction
+ // exception when `vstart` is non-zero. This also governs instructions
+ // from the Zvbb, Zvbc, Zvabd, Zvfbfmin, and Zvfbfwma extensions.
+ "arith": true,
+ // Whether the vector scalar move instructions (vmv.x.s, vmv.s.x,
+ // vfmv.f.s and vfmv.s.f) raise an illegal instruction exception when
+ // `vstart` is non-zero.
+ "scalar_move": true
+ }
+ }
+ },
+ "B": {
+ "supported": false
+ },
+ "S": {
+ "supported": false
+ },
+ "U": {
+ "supported": false
+ },
+ "Zibi": {
+ "supported": false
+ },
+ // This extension just asserts that the cache block size is 64 bytes.
+ // If you enable this you also need to ensure `platform.cache_block_size_exp`
+ // is 6, otherwise you will get a config validation error.
+ "Zic64b": {
+ "supported": false
+ },
+ "Zicbom": {
+ "supported": false
+ },
+ "Zicbop": {
+ "supported": false
+ },
+ "Zicboz": {
+ "supported": false
+ },
+ "Ziccamoa": {
+ "supported": false
+ },
+ "Ziccamoc": {
+ "supported": false
+ },
+ "Ziccif": {
+ "supported": false
+ },
+ "Zicclsm": {
+ "supported": false
+ },
+ "Ziccrse": {
+ "supported": false
+ },
+ "Zicfilp": {
+ "supported": false
+ },
+ "Zicfiss": {
+ "supported": false
+ },
+ "Zicond": {
+ "supported": false
+ },
+ "Zicntr": {
+ "supported": true
+ },
+ "Zicsr": {
+ "supported": true
+ },
+ "Zifencei": {
+ "supported": true
+ },
+ "Zihintntl": {
+ "supported": false
+ },
+ "Zihintpause": {
+ "supported": false
+ },
+ "Zihpm": {
+ "supported": true
+ },
+ "Zimop": {
+ "supported": false
+ },
+ "Zmmul": {
+ "supported": true
+ },
+ "Zaamo": {
+ "supported": true
+ },
+ "Zabha": {
+ "supported": false
+ },
+ "Zacas": {
+ "supported": false
+ },
+ "Zalrsc": {
+ "supported": true
+ },
+ "Zawrs": {
+ "supported": false,
+ // Whether `WRS.NTO` and `WRS.STO` behave as NOPS. If they do
+ // not, see above note for `platform.max_time_to_wait`. If
+ // Zawrs is not supported, these `is_nop` fields need to be
+ // present but their boolean values are ignored.
+ "nto": {
+ "is_nop": false
+ },
+ "sto": {
+ "is_nop": false
+ }
+ },
+ "Zfa": {
+ "supported": false
+ },
+ "Zfbfmin": {
+ "supported": false
+ },
+ "Zfh": {
+ "supported": false
+ },
+ "Zfhmin": {
+ "supported": false
+ },
+ "Zfinx": {
+ "supported": false
+ },
+ "Zdinx": {
+ "supported": false
+ },
+ "Zca": {
+ "supported": true
+ },
+ "Zcf": {
+ "supported": true
+ },
+ "Zcd": {
+ "supported": true
+ },
+ "Zcb": {
+ "supported": false
+ },
+ "Zcmop": {
+ "supported": false
+ },
+ "Zba": {
+ "supported": false
+ },
+ "Zbb": {
+ "supported": false
+ },
+ "Zbs": {
+ "supported": false
+ },
+ "Zbc": {
+ "supported": false
+ },
+ "Zbkb": {
+ "supported": false
+ },
+ "Zbkc": {
+ "supported": false
+ },
+ "Zbkx": {
+ "supported": false
+ },
+ "Zknd": {
+ "supported": false
+ },
+ "Zkne": {
+ "supported": false
+ },
+ "Zknh": {
+ "supported": false
+ },
+ "Zkr": {
+ "supported": false,
+ // If Zkr is not supported, these fields need to be present but
+ // their boolean values are ignored.
+ "sseed_reset_value": false,
+ "useed_reset_value": false,
+ "sseed_read_only_zero": false,
+ "useed_read_only_zero": false
+ },
+ "Zksed": {
+ "supported": false
+ },
+ "Zksh": {
+ "supported": false
+ },
+ "Zkt": {
+ "supported": false
+ },
+ "Zhinx": {
+ "supported": false
+ },
+ "Zhinxmin": {
+ "supported": false
+ },
+ "Zvabd": {
+ "supported": false
+ },
+ "Zvfbfmin": {
+ "supported": false
+ },
+ "Zvfbfwma": {
+ "supported": false
+ },
+ "Zvfh": {
+ "supported": false
+ },
+ "Zvfhmin": {
+ "supported": false
+ },
+ "Zvbb": {
+ "supported": false
+ },
+ "Zvbc": {
+ "supported": false
+ },
+ "Zvkb": {
+ "supported": false
+ },
+ "Zvkg": {
+ "supported": false
+ },
+ "Zvkned": {
+ "supported": false
+ },
+ "Zvknha": {
+ "supported": false
+ },
+ "Zvknhb": {
+ "supported": false
+ },
+ "Zvksed": {
+ "supported": false
+ },
+ "Zvksh": {
+ "supported": false
+ },
+ "Zvkt": {
+ "supported": false
+ },
+ "Ssccptr": {
+ "supported": false
+ },
+ "Sscofpmf": {
+ "supported": false
+ },
+ "Sscounterenw": {
+ "supported": false
+ },
+ "Sstc": {
+ "supported": false
+ },
+ // Enabling Sstvala requires that the exceptions specified in the extension
+ // have their appropriate settings under `base.xtval_nonzero`.
+ "Sstvala": {
+ "supported": false
+ },
+ "Svade": {
+ "supported": false
+ },
+ "Svadu": {
+ "supported": false
+ },
+ "Svinval": {
+ "supported": false
+ },
+ "Svrsw60t59b": {
+ "supported": false
+ },
+ "Svnapot": {
+ "supported": false
+ },
+ "Ssnpm": {
+ "supported": false,
+ "supported_pmlen_7": true,
+ "supported_pmlen_16": true
+ },
+ "Smnpm": {
+ "supported": false,
+ "supported_pmlen_7": true,
+ "supported_pmlen_16": true
+ },
+ "Smmpm": {
+ "supported": false,
+ "supported_pmlen_7": true,
+ "supported_pmlen_16": true
+ },
+ "Smcntrpmf": {
+ "supported": false
+ },
+ "Svbare": {
+ "supported": false,
+ "sfence_vma_illegal_if_svbare_only": true
+ },
+ "Sv32": {
+ "supported": false
+ },
+ "Sv39": {
+ "supported": false
+ },
+ "Sv48": {
+ "supported": false
+ },
+ "Sv57": {
+ "supported": false
+ },
+ "Stateen": {
+ "Smstateen": {
+ "supported": false
+ },
+ "Ssstateen": {
+ "supported": false
+ },
+ "C_readonly_zero": true,
+ "SE0_readonly_zero": false
+ },
+ "Ssqosid": {
+ "supported": false,
+ // These lengths should be between 1 and 12, inclusive.
+ // If Ssqosid is not supported, this should be left as 1
+ // (or any other legal value).
+ "rcid_length": 12,
+ "mcid_length": 12
+ },
+ "Svpbmt": {
+ "supported": false
+ },
+ "Svvptc": {
+ "supported": false
+ }
+ }
+}
diff --git a/tests/perilus/test_config.yaml b/tests/perilus/test_config.yaml
@@ -0,0 +1,8 @@
+name: perilus-rv32i
+compiler_exe: riscv64-none-elf-gcc
+objdump_exe: riscv64-none-elf-objdump
+ref_model_exe: sail_riscv_sim
+udb_config: perilus.yaml
+linker_script: link.ld
+dut_include_dir: .
+include_priv_tests: false