Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions .github/workflows/regress.yml
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ jobs:
DOCKER=1 \
FAST=True \
EXTENSIONS="" \
EXCLUDE_EXTENSIONS=Sm,ExceptionsZc,S \
EXCLUDE_EXTENSIONS=Sm,ExceptionsZc,S,ExceptionsZalrsc \
CONFIG_FILES=${{ matrix.config_file }} \
make elfs --jobs $(nproc)

Expand Down Expand Up @@ -265,7 +265,7 @@ jobs:
DOCKER=1 \
FAST=True \
EXTENSIONS= \
EXCLUDE_EXTENSIONS=Sm,ExceptionsZc,S,Zalrsc,Zacas,ZacasZabha \
EXCLUDE_EXTENSIONS=Sm,ExceptionsZc,S,Zalrsc,Zacas,ZacasZabha,ExceptionsZalrsc \
CONFIG_FILES=${{ matrix.config_file }} \
make elfs --jobs $(nproc)

Expand Down
2 changes: 2 additions & 0 deletions coverpoints/priv/ExceptionsZalrsc_coverage.svh
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ covergroup ExceptionsZalrsc_cg with function sample(ins_t ins);
cp_load_access_misaligned_priority: cross lr, illegal_address_misaligned;
cp_store_address_misaligned_legal_w: cross sc_w, adr_LSBs_legal_w,rd_gt_one_prev, rd_zero_cur, non_illegal_address;
cp_store_address_misaligned_illegal_w: cross sc_w, adr_LSBs_illegal_w, rd_gt_one_prev, rd_gt_one_cur, non_illegal_address;
// illegal sc.w and sc.d does not get coverage as SAIL stores content in by bytes instead of giving exceptions
// Sail issue: https://github.com/riscv/sail-riscv/issues/1574
`ifdef XLEN64
cp_store_address_misaligned_legal_d: cross sc_d, adr_LSBs_legal_d,rd_gt_one_prev, rd_zero_cur, non_illegal_address;
cp_store_address_misaligned_illegal_d: cross sc_d, adr_LSBs_illegal_d, rd_gt_one_prev, rd_gt_one_cur, non_illegal_address;
Expand Down
273 changes: 273 additions & 0 deletions generators/testgen/src/testgen/priv/extensions/ExceptionsZalrsc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
##################################
# ExceptionsZalrsc.py
#
# ExceptionsZalrsc privileged extension test generator.
# ellyu@g.hmc.edu March 2026
# SPDX-License-Identifier: Apache-2.0
##################################

"""Zalrsc extension exception test generator."""

from testgen.asm.helpers import comment_banner, write_sigupd
from testgen.data.state import TestData
from testgen.priv.registry import add_priv_test_generator


def _generate_load_address_misaligned_tests(test_data: TestData) -> list[str]:
"""Generate load address misaligned exception tests."""
covergroup, coverpoint = "ExceptionsZalrsc_cg", "cp_load_address_misaligned"

addr_reg, check_reg = test_data.int_regs.get_registers(2, exclude_regs=[0])

lines = [comment_banner(coverpoint)]

for offset in range(8):
lines.extend(
[
f"\n# Offset {offset} (LSBs: {offset:03b})",
f" LA(x{addr_reg}, scratch)",
f" addi x{addr_reg}, x{addr_reg}, {offset}",
f" LI(x{check_reg}, 0xBAD)",
test_data.add_testcase(f"lr.w_off{offset}", coverpoint, covergroup),
f" lr.w x{check_reg}, (x{addr_reg})",
" nop",
write_sigupd(check_reg, test_data),
"#if __riscv_xlen == 64",
f" LI(x{check_reg}, 0xBAD)",
test_data.add_testcase(f"lr.d_off{offset}", coverpoint, covergroup),
f" lr.d x{check_reg}, (x{addr_reg})",
" nop",
write_sigupd(check_reg, test_data),
"#endif",
"",
]
)

test_data.int_regs.return_registers([addr_reg, check_reg])
return lines


def _generate_store_address_misaligned_tests(test_data: TestData) -> list[str]:
"""Generate store address misaligned exception tests."""
covergroup, coverpoint = "ExceptionsZalrsc_cg", "cp_store_address_misaligned"
addr_reg, data_reg, rd_reg, temp_reg, base_reg, check_reg = test_data.int_regs.get_registers(6, exclude_regs=[0])

lines = [comment_banner(coverpoint)]
# illegal sc.w does not get coverage as SAIL stores content in by bytes instead of giving exceptions
# Sail issue: https://github.com/riscv/sail-riscv/issues/1574

for offset in range(8):
lines.extend(
[
f"\n# Offset {offset} (LSBs: {offset:03b})",
f" LA(x{base_reg}, scratch)",
f" addi x{addr_reg}, x{base_reg}, {offset}", # addr = aligned base + offset
f" LI(x{data_reg}, 0xDECAFCAB)",
f" LI(x{temp_reg}, 0xBAD)",
test_data.add_testcase(f"lr.w_off{offset}", coverpoint, covergroup),
f" lr.w x{temp_reg}, (x{addr_reg})", # establish reservation
" nop",
write_sigupd(temp_reg, test_data),
f" LI(x{rd_reg}, 0xBAD)", # previous rd greater than 1
test_data.add_testcase(f"sc.w_off{offset}", coverpoint, covergroup),
f" sc.w x{rd_reg}, x{data_reg}, (x{addr_reg})",
Comment on lines +65 to +73
Copy link
Collaborator

Choose a reason for hiding this comment

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

There are limits on how many instruction can be between lr.w and sc.w. To avoid conflating this test with that limit, let's move the LI(x{rd_reg}, 0xBAD) before the lr.w. So initialize all of the registers, then do the lr.w and then do the sc.w (with a nop in between). Let's also move the write_sigupd for the temp_reg after the sc.w since it should not change in between helps avoid running extra instructions between them. This applies to all sc.w/sc.d tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

One of the reason that I put the LI(x{rd_reg}, 0xBAD) before the sc.w is because one of the coverpoint is rd_gt_one_prev. If I move it, it would just be nop before the sc.w, should I still move it?

" nop",
write_sigupd(rd_reg, test_data),
f" lw x{check_reg}, 0(x{base_reg})",
write_sigupd(check_reg, test_data),
f" lw x{check_reg}, 4(x{base_reg})",
write_sigupd(check_reg, test_data),
f" lw x{check_reg}, 8(x{base_reg})",
write_sigupd(check_reg, test_data),
f" lw x{check_reg}, 12(x{base_reg})",
write_sigupd(check_reg, test_data),
"#if __riscv_xlen == 64",
f" LI(x{temp_reg}, 0xBAD)",
test_data.add_testcase(f"lr.d_off{offset}", coverpoint, covergroup),
f" lr.d x{temp_reg}, (x{addr_reg})", # establish reservation
" nop",
write_sigupd(temp_reg, test_data),
f" LI(x{rd_reg}, 0xBAD)", # previous rd greater than 1
test_data.add_testcase(f"sc.d_off{offset}", coverpoint, covergroup),
f" sc.d x{rd_reg}, x{data_reg}, (x{addr_reg})",
" nop",
write_sigupd(rd_reg, test_data),
f" lw x{check_reg}, 0(x{base_reg})",
write_sigupd(check_reg, test_data),
f" lw x{check_reg}, 4(x{base_reg})",
write_sigupd(check_reg, test_data),
f" lw x{check_reg}, 8(x{base_reg})",
write_sigupd(check_reg, test_data),
f" lw x{check_reg}, 12(x{base_reg})",
write_sigupd(check_reg, test_data),
"#endif",
"",
]
)
test_data.int_regs.return_registers([addr_reg, data_reg, rd_reg, base_reg, temp_reg, check_reg])
return lines


def _generate_load_access_fault_tests(test_data: TestData) -> list[str]:
"""Generate load access fault exception tests."""
covergroup, coverpoint = "ExceptionsZalrsc_cg", "cp_load_access_fault"
addr_reg, check_reg = test_data.int_regs.get_registers(2, exclude_regs=[0])

lines = [
comment_banner(coverpoint),
f" LI(x{addr_reg}, RVMODEL_ACCESS_FAULT_ADDRESS)",
f" LI(x{check_reg}, 0xBAD)",
test_data.add_testcase("lr.w_load_access_fault", coverpoint, covergroup),
f" lr.w x{check_reg}, (x{addr_reg})",
" nop",
write_sigupd(check_reg, test_data),
"#if __riscv_xlen == 64",
f" LI(x{check_reg}, 0xBAD)",
test_data.add_testcase("lr.d_load_access_fault", coverpoint, covergroup),
f" lr.d x{check_reg}, (x{addr_reg})",
" nop",
write_sigupd(check_reg, test_data),
"#endif",
"",
]

test_data.int_regs.return_registers([addr_reg, check_reg])
return lines


def _generate_load_misaligned_priority_tests(test_data: TestData) -> list[str]:
"""Generate instruction address misaligned and access fault exception tests."""
covergroup, coverpoint = "ExceptionsZalrsc_cg", "cp_load_misaligned_priority"
addr_reg, check_reg = test_data.int_regs.get_registers(2, exclude_regs=[0])

lines = [
comment_banner(coverpoint),
f" LI(x{addr_reg}, RVMODEL_ACCESS_FAULT_ADDRESS)",
f" addi x{addr_reg}, x{addr_reg}, 1",
f" LI(x{check_reg}, 0xBAD)",
test_data.add_testcase("lr.w_off1_priority", coverpoint, covergroup),
f" lr.w x{check_reg}, (x{addr_reg})",
" nop",
write_sigupd(check_reg, test_data),
"#if __riscv_xlen == 64",
f" LI(x{check_reg}, 0xBAD)",
test_data.add_testcase("lr.d_off1_priority", coverpoint, covergroup),
f" lr.d x{check_reg}, (x{addr_reg})",
" nop",
write_sigupd(check_reg, test_data),
"#endif",
"",
]

test_data.int_regs.return_registers([addr_reg, check_reg])
return lines


def _generate_store_access_fault_tests(test_data: TestData) -> list[str]:
"""Generate store access fault exception tests."""
covergroup, coverpoint = "ExceptionsZalrsc_cg", "cp_store_access_fault"
addr_reg, data_reg, rd_reg = test_data.int_regs.get_registers(3, exclude_regs=[0])
# sc.w at illegal address does not trigger exception in QEMU
# QEMU issue: https://gitlab.com/qemu-project/qemu/-/issues/3323
lines = [
comment_banner(coverpoint),
f" LI(x{addr_reg}, RVMODEL_ACCESS_FAULT_ADDRESS)",
f" LI(x{data_reg}, 0xADDEDCAB)",
f" LI(x{rd_reg}, 0xBAD)",
test_data.add_testcase("lr.w_store_fault", coverpoint, covergroup),
f" lr.w x{rd_reg}, (x{addr_reg})",
" nop",
write_sigupd(rd_reg, test_data),
f" LI(x{rd_reg}, 0xBAD)", # previous rd greater than 1
test_data.add_testcase("sc.w_fault", coverpoint, covergroup),
f" sc.w x{rd_reg}, x{data_reg}, (x{addr_reg})",
" nop",
write_sigupd(rd_reg, test_data),
"#if __riscv_xlen == 64",
f" LI(x{data_reg}, 0xDEADBEEFDECAFCAB)",
f" LI(x{rd_reg}, 0xBAD)",
test_data.add_testcase("lr.d_store_fault", coverpoint, covergroup),
f" lr.d x{rd_reg}, (x{addr_reg})",
" nop",
write_sigupd(rd_reg, test_data),
f" LI(x{rd_reg}, 0xBAD)", # previous rd greater than 1
test_data.add_testcase("sc.d_fault", coverpoint, covergroup),
f" sc.d x{rd_reg}, x{data_reg}, (x{addr_reg})",
" nop",
write_sigupd(rd_reg, test_data),
"#endif",
"",
]

test_data.int_regs.return_registers([addr_reg, data_reg, rd_reg])
return lines


def _generate_store_misaligned_priority_tests(test_data: TestData) -> list[str]:
"""Generate instruction address misaligned and access fault exception tests."""
covergroup, coverpoint = "ExceptionsZalrsc_cg", "cp_store_misaligned_priority"
addr_reg, data_reg, rd_reg = test_data.int_regs.get_registers(3, exclude_regs=[0])

lines = [comment_banner(coverpoint)]

lines.extend(
[
f" LA(x{addr_reg}, RVMODEL_ACCESS_FAULT_ADDRESS)",
f" addi x{addr_reg}, x{addr_reg}, 1",
f" LI(x{data_reg}, 0xDECAFCAB)", # Match original value
f" LI(x{rd_reg}, 0xDECAFCAB)",
test_data.add_testcase("lr.w_off1_priority", coverpoint, covergroup),
f" lr.w x{rd_reg}, (x{addr_reg})",
" nop",
write_sigupd(rd_reg, test_data),
f" LI(x{rd_reg}, 0xBAD)", # previous rd greater than 1
test_data.add_testcase("sc.w_off1_priority", coverpoint, covergroup),
f" sc.w x{rd_reg}, x{data_reg}, (x{addr_reg})",
" nop",
write_sigupd(rd_reg, test_data),
"#if __riscv_xlen == 64",
f" LI(x{data_reg}, 0xDEADBEEFDECAFCAB)", # Match original value
f" LI(x{rd_reg}, 0xDECAFCAB)",
test_data.add_testcase("lr.d_off1_priority", coverpoint, covergroup),
f" lr.d x{rd_reg}, (x{addr_reg})",
" nop",
write_sigupd(rd_reg, test_data),
f" LI(x{rd_reg}, 0xBAD)", # previous rd greater than 1
test_data.add_testcase("sc.d_off1_priority", coverpoint, covergroup),
f" sc.d x{rd_reg}, x{data_reg}, (x{addr_reg})",
" nop",
write_sigupd(rd_reg, test_data),
"#endif",
"",
]
)
test_data.int_regs.return_registers([addr_reg, data_reg, rd_reg])
return lines


@add_priv_test_generator("ExceptionsZalrsc", required_extensions=["Zicsr", "Zalrsc", "Sm"])
def make_exceptionszalrsc(test_data: TestData) -> list[str]:
"""Generate tests for ExceptionsZalrsc coverpoints"""
lines = []

lines.extend(
[
"# Initialize scratch memory with test data",
" LA(x10, scratch)",
" LI(x11, 0xDEADBEEF)",
" sw x11, 0(x10)",
" sw x11, 4(x10)",
" sw x11, 8(x10)",
" sw x11, 12(x10)",
"",
]
)

lines.extend(_generate_load_address_misaligned_tests(test_data))
lines.extend(_generate_load_access_fault_tests(test_data))
lines.extend(_generate_load_misaligned_priority_tests(test_data))
lines.extend(_generate_store_address_misaligned_tests(test_data))
lines.extend(_generate_store_access_fault_tests(test_data))
lines.extend(_generate_store_misaligned_priority_tests(test_data))

return lines