feat: add lab-rv32i-c-machine-timer card
This commit is contained in:
Executable
+49
@@ -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'
|
||||
Executable
+102
@@ -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'
|
||||
Reference in New Issue
Block a user