ec82764bef
RTL (GS rasterizer, EE core stub, platform bridge, LPDDR4B path), sim regression (272 TBs), docs, and tooling. Copyrighted PS2 content (BIOS, game code, GS dumps, and all dump-derived textures/traces) is excluded via .gitignore and stays local. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
130 lines
5.8 KiB
Bash
Executable File
130 lines
5.8 KiB
Bash
Executable File
#!/bin/sh
|
|
# retroDE_ps2 LPDDR framebuffer write/readback test — Ch318 operator helper.
|
|
#
|
|
# Drives the runtime LPDDR test controls in `ps2_hps_bridge` and verifies the
|
|
# tile-flush writer reached real LPDDR. ONE bitstream (GS_TILE_PSMCT16FB_DEMO +
|
|
# GS_LPDDR_FB); all control is at runtime — no rebuild between stages.
|
|
#
|
|
# Same style/contract as ps2_status.sh: PS2 HPS-bridge base + busybox devmem
|
|
# (busybox avoids the devmem2 "Bus error" quirk on 0x?4-suffixed offsets — and
|
|
# LPDDR_BURSTS sits at 0x...34). See rtl/platform/ps2_hps_bridge.sv and
|
|
# docs/ch318-lpddr-fb-bringup.md.
|
|
#
|
|
# Usage (run from HPS Linux after loading the .core.rbf):
|
|
# ./ps2_lpddr_test.sh # read-only LPDDR status (safe; no arming)
|
|
# ./ps2_lpddr_test.sh --canary # arm canary (1 line), re-render, prove via counters
|
|
# ./ps2_lpddr_test.sh --full # arm full frame, re-render, prove via counters
|
|
# ./ps2_lpddr_test.sh --disarm # write LPDDR_CTRL = 0x2 (disarmed, canary)
|
|
#
|
|
# PROOF METHOD = bridge counters, NOT /dev/mem. The Ch318 writer targets the HPS
|
|
# LPDDR (f2sdram) at 0x80000000, which is a firmware-RESERVED region: reading it
|
|
# with `dd /dev/mem` HARD-CRASHES the fabric (needs a power cycle). So this script
|
|
# NEVER touches /dev/mem. It proves the write reached LPDDR by reading LPDDR_BYTES/
|
|
# LPDDR_BURSTS/LPDDR_STATUS over the HPS bridge (safe register reads). Byte-level
|
|
# CONTENT verification needs the Ch318b bridge-register readback path (ported from
|
|
# ao486 lpddr4b_loader.sv) — until that lands, content is not checked here.
|
|
#
|
|
# ONE-SHOT FIX: the EE bootlet renders once at boot (before you can arm), then
|
|
# halts -> BYTES stays 0. So --canary/--full arm FIRST, then pulse the core reset
|
|
# (CORE_CTRL[0]) to re-run the bootlet and flush a frame WHILE ARMED.
|
|
#
|
|
# Defaults are SAFE: the bitstream boots disarmed; this script only writes when
|
|
# you pass --canary/--full, and always leaves the writer disarmed on exit.
|
|
|
|
set -u
|
|
|
|
BASE="${PS2_BRIDGE_BASE:-0x40000000}"
|
|
DEVMEM="${DEVMEM:-busybox devmem}"
|
|
MODE="${1:-status}"
|
|
|
|
# Register offsets (see ps2_hps_bridge.sv).
|
|
OFF_CORE_CTRL=0x010 # RW [0]=core reset (pulse 1->0 re-runs the EE bootlet)
|
|
OFF_LPDDR_CTRL=0x018 # RW [0]=arm [1]=canary (reset 0x2)
|
|
OFF_LPDDR_FB_BASE=0x01C # RW LPDDR byte base (reset 0x80000000)
|
|
OFF_LPDDR_STATUS=0x02C # R [0]=idle [1]=bresp_err [2]=fifo_ovf
|
|
OFF_LPDDR_BYTES=0x030 # R total bytes written
|
|
OFF_LPDDR_BURSTS=0x034 # R total 32-byte bursts
|
|
OFF_LPDDR_BRESP_ERRS=0x038 # R count of bursts with non-OKAY response (1=reset-race phantom; 256=all refused)
|
|
|
|
# Expected byte counts (canary = 1 top line = 32 B; full = 64x64 PSMCT16 = 8 KiB).
|
|
EXP_CANARY_BYTES=32
|
|
EXP_FULL_BYTES=8192
|
|
|
|
read_reg() { $DEVMEM "$(printf '0x%08x' $(( BASE + $1 )) )" w; }
|
|
write_reg() { $DEVMEM "$(printf '0x%08x' $(( BASE + $1 )) )" w "$2"; }
|
|
bit_set() { if [ $(( ($1 >> $2) & 1 )) -eq 1 ]; then echo 1; else echo 0; fi; }
|
|
|
|
show_status() {
|
|
local ctrl base st by bu
|
|
ctrl=$(read_reg $OFF_LPDDR_CTRL); base=$(read_reg $OFF_LPDDR_FB_BASE)
|
|
st=$(read_reg $OFF_LPDDR_STATUS); by=$(read_reg $OFF_LPDDR_BYTES); bu=$(read_reg $OFF_LPDDR_BURSTS)
|
|
printf "LPDDR writer status\n"
|
|
printf " LPDDR_CTRL : %s (arm=%d canary=%d)\n" "$ctrl" "$(bit_set $((ctrl)) 0)" "$(bit_set $((ctrl)) 1)"
|
|
printf " LPDDR_FB_BASE: %s\n" "$base"
|
|
printf " LPDDR_STATUS : %s (idle=%d bresp_err=%d fifo_ovf=%d)\n" \
|
|
"$st" "$(bit_set $((st)) 0)" "$(bit_set $((st)) 1)" "$(bit_set $((st)) 2)"
|
|
printf " LPDDR_BYTES : %s\n LPDDR_BURSTS : %s\n" "$by" "$bu"
|
|
printf " LPDDR_BRESP_ERRS: %s\n" "$(read_reg $OFF_LPDDR_BRESP_ERRS)"
|
|
}
|
|
|
|
err_bits_clear() { # 1 if bresp_err and fifo_ovf both 0
|
|
local st=$(( $(read_reg $OFF_LPDDR_STATUS) ))
|
|
[ "$(bit_set $st 1)" = "0" ] && [ "$(bit_set $st 2)" = "0" ]
|
|
}
|
|
|
|
# Re-run the EE bootlet so it renders a frame WHILE the writer is armed.
|
|
# (The bootlet is one-shot; it renders once at boot, before you can arm.)
|
|
rerender_pulse() {
|
|
write_reg $OFF_CORE_CTRL 0x1 # assert core reset
|
|
sleep 1
|
|
write_reg $OFF_CORE_CTRL 0x0 # release -> bootlet re-runs, flushes a frame
|
|
sleep 3 # ~2 s DMAC-drain render cadence + margin
|
|
}
|
|
|
|
# Arm, re-render, and prove the write reached LPDDR via the bridge counters.
|
|
# $1 = LPDDR_CTRL arm value (0x3 canary / 0x1 full), $2 = expected byte count, $3 = label
|
|
prove_via_counters() {
|
|
local armval=$1 expbytes=$2 label=$3 by bu
|
|
write_reg $OFF_LPDDR_CTRL "$armval" # arm
|
|
rerender_pulse # render a frame while armed
|
|
by=$(( $(read_reg $OFF_LPDDR_BYTES) ))
|
|
bu=$(( $(read_reg $OFF_LPDDR_BURSTS) ))
|
|
be=$(( $(read_reg $OFF_LPDDR_BRESP_ERRS) ))
|
|
write_reg $OFF_LPDDR_CTRL 0x2 # DISARM
|
|
printf "after re-render: LPDDR_BYTES=%d (expect %d) LPDDR_BURSTS=%d BRESP_ERRS=%d\n" "$by" "$expbytes" "$bu" "$be"
|
|
if [ "$by" -ge "$expbytes" ] && err_bits_clear; then
|
|
printf "%s: PASS (fabric delivered %d B to LPDDR; no AXI/FIFO errors)\n" "$label" "$by"
|
|
return 0
|
|
else
|
|
printf "%s: FAIL (BYTES=%d < %d, or error bits set)\n" "$label" "$by" "$expbytes"
|
|
show_status; return 1
|
|
fi
|
|
}
|
|
|
|
case "$MODE" in
|
|
status)
|
|
show_status
|
|
;;
|
|
|
|
--canary)
|
|
printf "== LPDDR CANARY (32-byte top-line write, counter proof) ==\n"
|
|
printf "defaults: LPDDR_CTRL=%s (expect 0x00000002) LPDDR_FB_BASE=%s (expect 0x80000000)\n" \
|
|
"$(read_reg $OFF_LPDDR_CTRL)" "$(read_reg $OFF_LPDDR_FB_BASE)"
|
|
prove_via_counters 0x3 "$EXP_CANARY_BYTES" CANARY; exit $?
|
|
;;
|
|
|
|
--full)
|
|
printf "== LPDDR FULL FRAME (%d B, counter proof) ==\n" "$EXP_FULL_BYTES"
|
|
prove_via_counters 0x1 "$EXP_FULL_BYTES" FULL; exit $?
|
|
;;
|
|
|
|
--disarm)
|
|
write_reg $OFF_LPDDR_CTRL 0x2
|
|
printf "disarmed (LPDDR_CTRL=0x2)\n"
|
|
;;
|
|
|
|
*)
|
|
printf "usage: %s [--canary|--full|--disarm] (no arg = status)\n" "$0"; exit 2
|
|
;;
|
|
esac
|