feat: add lab-rv32i-c-machine-timer card

This commit is contained in:
user
2026-07-21 19:14:20 +02:00
commit a0e116f24e
23 changed files with 4720 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
set -euo pipefail
root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
tmp_dir="$(mktemp -d /tmp/c11-card.XXXXXX)"
cleanup() {
rm -rf -- "$tmp_dir"
}
trap cleanup EXIT HUP INT TERM
"$root/scripts/render_card_layouts.sh" >/dev/null
"$root/scripts/render_new_pdf.sh" >/dev/null
pdf="$(find "$root/doc/pdf" -maxdepth 1 -type f \
-name 'mpabi-inf-c-11-machine-timer-*.pdf' -print -quit)"
test -n "$pdf"
qpdf --check "$pdf" >/dev/null
pdftotext -layout "$pdf" "$tmp_dir/card.txt"
blocks="$(rg -o 'A[1-8] (CONTEXT|STRUCTURE|DISPATCH|APPLICATION|FLOW|STATE|RUNTIME|PATTERNS)' \
"$tmp_dir/card.txt" | wc -l)"
test "$blocks" -eq 24
if awk 'BEGIN { RS="\f" } { compact=$0; gsub(/[[:space:]]/, "", compact); if (length(compact) < 100) exit 1 }' \
"$tmp_dir/card.txt"; then
:
else
echo "FAIL: empty or nearly empty PDF page" >&2
exit 1
fi
if awk 'BEGIN { RS="\f" } \
/A[1-8] (CONTEXT|STRUCTURE|DISPATCH|APPLICATION|FLOW|STATE|RUNTIME|PATTERNS)/ && !/TASK0[1-3]/ { exit 1 }' \
"$tmp_dir/card.txt"; then
:
else
echo "FAIL: A1-A8 block on a page without its TASK heading" >&2
exit 1
fi
jq -e '
.tasks_order == ["task01", "task02", "task03"] and
all(.tasks[];
[.viewpoints[].id] == ["A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8"] and
all(.viewpoints[]; .status == "enabled" or .status == "unavailable"))
' "$root/json/card_source.json" >/dev/null
node --check "$root/web/app.js"
printf 'PASS card: 3 tasks, 24 A blocks, valid PDF, no empty/anonymous page\n'
+102
View File
@@ -0,0 +1,102 @@
#!/usr/bin/env bash
set -euo pipefail
root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
env_root="${RV_ENV_ROOT:-/home/user/dev/edu/rv32i-hazard3-student-env}"
tb="${HAZARD3_TB:-$env_root/vendor/Hazard3/test/sim/tb_verilator/tb}"
objdump="${RISCV_PREFIX:-riscv64-unknown-elf-}objdump"
if [[ ! -x "$tb" ]]; then
make -C "$(dirname -- "$tb")" tb >/dev/null
fi
make -C "$root" -s tasks "RV_ENV_ROOT=$env_root"
run_task() {
local task="$1"
shift
local log="$root/build/$task/oracle.log"
"$tb" --bin "$root/build/$task/prog.bin" --cycles 500000 --cpuret --logfile "$log"
if grep -Eq 'Unhandled trap|Max cycles reached' "$log"; then
printf 'FAIL %s: trap or timeout\n' "$task" >&2
sed -n '1,160p' "$log" >&2
return 1
fi
local expected
for expected in "$@"; do
grep -Fqx "$expected" "$log" || {
printf 'FAIL %s: missing <%s>\n' "$task" "$expected" >&2
sed -n '1,160p' "$log" >&2
return 1
}
done
printf 'PASS Hazard3 oracle: %s\n' "$task"
}
run_task task01_mtime_consistent_read \
'T01 retry=00000001' \
'T01 value_high=00000001' \
'T01 monotonic=00000001' \
'T01 pass=00000001'
run_task task02_oneshot_timer_irq \
'T02 count=00000001' \
'T02 mcause=80000007' \
'T02 pending_before=00000000' \
'T02 pending_after=00000000' \
'T02 resumed=00000001' \
'T02 deadline_reached=00000001' \
'T02 pass=00000001'
run_task task03_periodic_absolute_deadline \
'T03 count=00000004' \
'T03 causes=00000004' \
'T03 period_low=00000640' \
'T03 step_ok=00000001' \
'T03 ordered=00000001' \
'T03 late_math=00000001' \
'T03 naive_shift_ok=00000001' \
'T03 pass=00000001'
# Independent relations: do not accept a program's pass flag as the only oracle.
t01_attempts_hex="$(sed -n 's/^T01 attempts=//p' \
"$root/build/task01_mtime_consistent_read/oracle.log")"
(( 16#$t01_attempts_hex > 1 )) || {
echo "FAIL task01: rollover did not force a retry" >&2
exit 1
}
mapfile -t t03_deadline < <(sed -n 's/^T03 deadline_low=//p' \
"$root/build/task03_periodic_absolute_deadline/oracle.log")
mapfile -t t03_observed < <(sed -n 's/^T03 observed_low=//p' \
"$root/build/task03_periodic_absolute_deadline/oracle.log")
mapfile -t t03_lateness < <(sed -n 's/^T03 lateness_low=//p' \
"$root/build/task03_periodic_absolute_deadline/oracle.log")
[[ ${#t03_deadline[@]} -eq 4 && ${#t03_observed[@]} -eq 4 && ${#t03_lateness[@]} -eq 4 ]]
for i in 0 1 2 3; do
d=$((16#${t03_deadline[$i]}))
o=$((16#${t03_observed[$i]}))
l=$((16#${t03_lateness[$i]}))
(( o >= d && o - d == l )) || {
echo "FAIL task03: invalid observed/deadline/lateness relation at tick $i" >&2
exit 1
}
if (( i > 0 )); then
previous=$((16#${t03_deadline[$((i - 1))]}))
(( d - previous == 1600 )) || {
echo "FAIL task03: deadline step is not 1600 at tick $i" >&2
exit 1
}
fi
done
for task in task02_oneshot_timer_irq task03_periodic_absolute_deadline; do
"$objdump" -d "$root/build/$task/prog.elf" |
sed -n '/<isr_machine_timer>:/,/^$/p' |
grep -Eq '[[:space:]]mret$' || {
echo "FAIL $task: ISR does not end in mret" >&2
exit 1
}
done
printf 'PASS independent oracle: rollover retry, periodic arithmetic, ISR mret\n'