#!/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" test -x "$tb" 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 1000000 \ --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,180p' "$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,180p' "$log" >&2 return 1 } done printf 'PASS Hazard3 oracle: %s\n' "$task" } run_task task01_gpio_polling \ 'T01 dir=00000001' \ 'T01 external_high=00000002' \ 'T01 out_after_set=00000001' \ 'T01 both_high=00000003' \ 'T01 final_in=00000000' \ 'T01 pass=00000001' run_task task02_gpio_rising_irq \ 'T02 count=00000001' \ 'T02 irq=00000012' \ 'T02 source_before=00000001' \ 'T02 controller_before=00000001' \ 'T02 pending_in_handler=00000004' \ 'T02 source_after=00000000' \ 'T02 controller_after=00000000' \ 'T02 same_level_pending=00000000' \ 'T02 resumed=00000001' \ 'T02 pass=00000001' run_task task03_gpio_quiet_window \ 'T03 count=00000003' \ 'T03 level0=00000001' \ 'T03 level1=00000000' \ 'T03 level2=00000001' \ 'T03 quiet=000007d0' \ 'T03 early=00000000' \ 'T03 accepted=00000001' \ 'T03 pass=00000001' run_task task04_raw_c_superloop \ 'T04 timer_irq=00000001' \ 'T04 timer_mcause=80000007' \ 'T04 uart_irq=00000001' \ 'T04 uart_number=00000010' \ 'T04 uart_byte=00000055' \ 'T04 gpio_irq=00000001' \ 'T04 gpio_number=00000012' \ 'T04 gpio_level=00000001' \ 'T04 main_timer=00000001' \ 'T04 main_uart=00000001' \ 'T04 main_gpio=00000001' \ 'T04 final_out=00000007' \ 'T04 final_in=00000017' \ 'T04 pass=00000001' # Independent arithmetic oracle for debounce; do not trust only program pass. t03_log="$root/build/task03_gpio_quiet_window/oracle.log" mapfile -t times < <(sed -n 's/^T03 time[0-2]_low=//p' "$t03_log") mapfile -t gaps < <(sed -n 's/^T03 gap[01][12]=//p' "$t03_log") quiet_hex="$(sed -n 's/^T03 quiet=//p' "$t03_log")" accepted_hex="$(sed -n 's/^T03 accepted_after=//p' "$t03_log")" [[ ${#times[@]} -eq 3 && ${#gaps[@]} -eq 2 ]] quiet=$((16#$quiet_hex)) accepted_after=$((16#$accepted_hex)) for i in 0 1; do first=$((16#${times[$i]})) second=$((16#${times[$((i + 1))]})) gap=$((16#${gaps[$i]})) (( second > first && second - first == gap && gap < quiet )) || { echo "FAIL task03: invalid bounce interval $i" >&2 exit 1 } done (( accepted_after >= quiet )) || { echo "FAIL task03: accepted before the quiet window" >&2 exit 1 } # The machine-timer handler must return from a trap, not as a normal function. "$objdump" -d "$root/build/task04_raw_c_superloop/prog.elf" | sed -n '/:/,/^$/p' | grep -Eq '[[:space:]]mret$' printf 'PASS independent oracle: edge/W1C relations, debounce timing, ISR mret\n'