tests: link M1 char helpers and check MOVB
This commit is contained in:
1 parent
b638ab0fad
commit
755b3cb7b2
7 files changed
+98
-26
No files matched your search
@@ -0,0 +1,22 @@
|
||||
; char-test.asm -- run the compiled char helpers and publish their results.
|
||||
;
|
||||
; Appended after char.s so _loadb/_storeb (and every earlier function) keep
|
||||
; their linked addresses. _start calls this instead of calling _second
|
||||
; directly, which is the same one-word-size calla; _char_test calls _second
|
||||
; and returns its result in A0 so the existing second() marker still works.
|
||||
;
|
||||
; storeb(018A8080, 0x81) writes the byte 0x81
|
||||
; loadb(018A8080) returns the sign-extended 0xFFFFFF81
|
||||
.text
|
||||
.globl _char_test
|
||||
_char_test:
|
||||
calla _second ; A0 = &arr[1]
|
||||
move a0, a3 ; save it for the second() marker
|
||||
movi 018A8080h, a0 ; p = storeb/loadb marker byte
|
||||
movi 81h, a1 ; v = 0x81 (low byte stored by MOVB)
|
||||
calla _storeb
|
||||
calla _loadb ; A0 is still 018A8080
|
||||
movi 018A8060h, a2
|
||||
move a0, *a2, 1 ; 32-bit loadb marker
|
||||
move a3, a0 ; restore &arr[1]
|
||||
rets
|
||||
@@ -0,0 +1,2 @@
|
||||
int loadb(char *p) { return *p; }
|
||||
void storeb(char *p, int v) { *p = v; }
|
||||
+35
-13
@@ -12,6 +12,8 @@
|
||||
# _load MOVE *A0, A0, 1 ; RETS 0
|
||||
# _late ADDI 24, A0 ; RETS 0
|
||||
# _second MOVI _arr+32, A0 ; RETS 0
|
||||
# _loadb MOVB *A0, A0 ; RETS 0
|
||||
# _storeb MOVB A1, *A0 ; RETS 0
|
||||
#
|
||||
# This verifies the 1987 GSPA assembler's encoding, not a dormant LLVM Inst
|
||||
# encoding. Overridable: M1_COFF DIS34
|
||||
@@ -121,31 +123,49 @@ ADD=$(get_sym _add)
|
||||
LOAD=$(get_sym _load)
|
||||
LATE=$(get_sym _late)
|
||||
SECOND=$(get_sym _second)
|
||||
LOADB=$(get_sym _loadb)
|
||||
STOREB=$(get_sym _storeb)
|
||||
ADD_HEX=$(printf '%08X' "$ADD")
|
||||
LOAD_HEX=$(printf '%08X' "$LOAD")
|
||||
LATE_HEX=$(printf '%08X' "$LATE")
|
||||
SECOND_HEX=$(printf '%08X' "$SECOND")
|
||||
LOADB_HEX=$(printf '%08X' "$LOADB")
|
||||
STOREB_HEX=$(printf '%08X' "$STOREB")
|
||||
|
||||
[ "$ADD_HEX" = "018A0240" ] || fail "_add linked at $ADD_HEX, want 018A0240"
|
||||
[ "$LOAD_HEX" = "018A0270" ] || fail "_load linked at $LOAD_HEX, want 018A0270"
|
||||
[ "$LATE_HEX" = "018A0290" ] || fail "_late linked at $LATE_HEX, want 018A0290"
|
||||
[ "$SECOND_HEX" = "018A02C0" ] || fail "_second linked at $SECOND_HEX, want 018A02C0"
|
||||
[ "$LOADB_HEX" = "018A0300" ] || fail "_loadb linked at $LOADB_HEX, want 018A0300"
|
||||
[ "$STOREB_HEX" = "018A0320" ] || fail "_storeb linked at $STOREB_HEX, want 018A0320"
|
||||
echo " _add=$ADD_HEX _load=$LOAD_HEX _late=$LATE_HEX _second=$SECOND_HEX"
|
||||
echo " _loadb=$LOADB_HEX _storeb=$STOREB_HEX (appended after _second)"
|
||||
|
||||
echo "== disassemble the emitted .text with dis34"
|
||||
"$DIS34" -b "$TEXT_HEX" -l -o "$TMP/text.bin" > "$TMP/dis34.txt" 2> "$TMP/dis34.err" \
|
||||
|| { cat "$TMP/dis34.err" >&2; fail "dis34 failed"; }
|
||||
[ -s "$TMP/dis34.txt" ] || fail "dis34 produced no output"
|
||||
|
||||
# match_at FILE DECIMAL_ADDR ERE
|
||||
# dis34 -l prints "018a0240:\tadd a0, a1\t; 4001". The operand must be
|
||||
# followed by optional whitespace and then the comment/end-of-line marker, so
|
||||
# "rets 1" cannot satisfy a "rets" pattern.
|
||||
match_at() {
|
||||
_file=$1
|
||||
_addr=$2
|
||||
_pat=$3
|
||||
_laddr=$(printf '%08x' "$_addr")
|
||||
grep -Eiq "^${_laddr}:[[:space:]]+${_pat}([[:space:]]*(;|$))" "$_file"
|
||||
}
|
||||
|
||||
# expect_at LABEL DECIMAL_ADDR EXPECTED_TEXT ERE
|
||||
# dis34 -l prints "018a0240:\tadd a0, a1\t; 4001".
|
||||
expect_at() {
|
||||
_label=$1
|
||||
_addr=$2
|
||||
_want=$3
|
||||
_pat=$4
|
||||
_laddr=$(printf '%08x' "$_addr")
|
||||
if grep -Eiq "^${_laddr}:[[:space:]]+${_pat}([[:space:]]|;|$)" "$TMP/dis34.txt"; then
|
||||
if match_at "$TMP/dis34.txt" "$_addr" "$_pat"; then
|
||||
echo " ok $_label @ 0x$_laddr: $_want"
|
||||
return 0
|
||||
fi
|
||||
@@ -191,16 +211,18 @@ expect_label "$SECOND"
|
||||
expect_at "_second" "$SECOND" "MOVI _arr+32, A0" 'movi[[:space:]]+(0x)?18a9020,[[:space:]]*a0'
|
||||
expect_at "_second+48" $((SECOND + 48)) "RETS 0" 'rets([[:space:]]+0)?'
|
||||
|
||||
# The char helpers are lit-only in M1, so the harness does not link them.
|
||||
# If a later harness does, do not silently skip their encoding.
|
||||
MOVB_SEEN=0
|
||||
for name in _loadb _storeb; do
|
||||
if addr=$(sym_addr "$name"); then
|
||||
MOVB_SEEN=1
|
||||
expect_at "$name" "$addr" "MOVB" 'movb[[:space:]]+'
|
||||
fi
|
||||
done
|
||||
[ "$MOVB_SEEN" -eq 1 ] \
|
||||
|| echo " movb: no _loadb/_storeb linked (char helpers are lit-only)"
|
||||
# Negative control for the RETS operand boundary: "rets 1" must not match.
|
||||
printf '018a0260:\trets\t1\t; 0960\n' > "$TMP/rets-neg.txt"
|
||||
if match_at "$TMP/rets-neg.txt" $((ADD + 32)) 'rets([[:space:]]+0)?'; then
|
||||
fail "negative control: the RETS pattern accepted 'rets 1'"
|
||||
fi
|
||||
echo " ok negative control @ 0x$(printf '%08x' $((ADD + 32))): 'rets 1' rejected"
|
||||
|
||||
expect_label "$LOADB"
|
||||
expect_at "_loadb" "$LOADB" "MOVB *A0, A0" 'movb[[:space:]]+\*a0,[[:space:]]*a0'
|
||||
expect_at "_loadb+16" $((LOADB + 16)) "RETS 0" 'rets([[:space:]]+0)?'
|
||||
|
||||
expect_at "_storeb" "$STOREB" "MOVB A1, *A0" 'movb[[:space:]]+a1,[[:space:]]*\*a0'
|
||||
expect_at "_storeb+16" $((STOREB + 16)) "RETS 0" 'rets([[:space:]]+0)?'
|
||||
|
||||
echo "M1 dis34 round-trip: PASS"
|
||||
@@ -7,9 +7,16 @@
|
||||
; 018A8000 add(20, 22)
|
||||
; 018A8020 load(018A8100)
|
||||
; 018A8040 second() == &arr[1]
|
||||
; 018A8060 loadb(018A8080) == 0xFFFFFF81 (sign-extended 0x81)
|
||||
; 018A8080 storeb(018A8080, 0x81) leaves the byte 0x81
|
||||
;
|
||||
; _late is linked but not called: it is a compile-time check that a surviving
|
||||
; GEP offset is 24 bits, not 192.
|
||||
;
|
||||
; The char helpers are exercised by _char_test (char-test.asm, appended after
|
||||
; the compiled functions). Calling it here instead of calling _second keeps
|
||||
; this entry's size -- and therefore every function's linked address -- the
|
||||
; same; _char_test calls _second and returns its result in A0.
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
@@ -29,7 +36,8 @@ _start:
|
||||
movi 018A8020h, a2
|
||||
move a0, *a2, 1
|
||||
|
||||
calla _second
|
||||
calla _char_test
|
||||
|
||||
movi 018A8040h, a2
|
||||
move a0, *a2, 1
|
||||
|
||||
|
||||
+13
-5
@@ -4,6 +4,8 @@
|
||||
-- M1_LOADER_LUA path to vendor/vt1200/dwt/loader/loader.lua
|
||||
-- M1_EXPECT_LOAD expected load() result (default 0x12345678)
|
||||
-- M1_EXPECT_SECOND expected &arr[1] in bits
|
||||
-- M1_EXPECT_LOADB expected sign-extended byte load (default 0xFFFFFF81)
|
||||
-- M1_EXPECT_STOREB expected byte store (default 0x81)
|
||||
--
|
||||
-- The marker read runs one frame before loader.lua's inspection/exit frame.
|
||||
|
||||
@@ -12,6 +14,8 @@ dofile(os.getenv("M1_LOADER_LUA"))
|
||||
local ENDF = tonumber(os.getenv("LOADER_END") or "2700")
|
||||
local EXPECT_LOAD = tonumber(os.getenv("M1_EXPECT_LOAD") or "0x12345678")
|
||||
local EXPECT_SECOND = tonumber(os.getenv("M1_EXPECT_SECOND") or "0x018A9020")
|
||||
local EXPECT_LOADB = tonumber(os.getenv("M1_EXPECT_LOADB") or "0xFFFFFF81")
|
||||
local EXPECT_STOREB = tonumber(os.getenv("M1_EXPECT_STOREB") or "0x81")
|
||||
local frames = 0
|
||||
local checked = false
|
||||
|
||||
@@ -23,14 +27,18 @@ emu.register_frame_done(function()
|
||||
local add = prog:read_u32(0x018A8000)
|
||||
local load = prog:read_u32(0x018A8020)
|
||||
local second = prog:read_u32(0x018A8040)
|
||||
print(string.format("M1: add=%d load=0x%08X second=0x%08X",
|
||||
add, load, second))
|
||||
if add == 42 and load == EXPECT_LOAD and second == EXPECT_SECOND then
|
||||
local loadb = prog:read_u32(0x018A8060)
|
||||
local storeb = prog:read_u8(0x018A8080)
|
||||
print(string.format(
|
||||
"M1: add=%d load=0x%08X second=0x%08X loadb=0x%08X storeb=0x%02X",
|
||||
add, load, second, loadb, storeb))
|
||||
if add == 42 and load == EXPECT_LOAD and second == EXPECT_SECOND
|
||||
and loadb == EXPECT_LOADB and storeb == EXPECT_STOREB then
|
||||
print("M1 MAME: PASS")
|
||||
else
|
||||
print(string.format(
|
||||
"M1 MAME: FAIL (want add=42 load=0x%08X second=0x%08X)",
|
||||
EXPECT_LOAD, EXPECT_SECOND))
|
||||
"M1 MAME: FAIL (want add=42 load=0x%08X second=0x%08X loadb=0x%08X storeb=0x%02X)",
|
||||
EXPECT_LOAD, EXPECT_SECOND, EXPECT_LOADB, EXPECT_STOREB))
|
||||
end
|
||||
end
|
||||
end, "m1-check")
|
||||
+10
-6
@@ -3,16 +3,18 @@
|
||||
#
|
||||
# scripts/m1/run.sh
|
||||
#
|
||||
# Compiles four C functions with scripts/tms-clang + llc -O0, assembles and
|
||||
# Compiles six C functions with scripts/tms-clang + llc -O0, assembles and
|
||||
# links them with the 1987 GSPA/GSPLNK 2.00 under DOSBox, then loads the COFF
|
||||
# into MAME through dwt/loader/loader.lua and checks the marker words:
|
||||
#
|
||||
# add(20, 22) == 42
|
||||
# load(&word) == 0x12345678
|
||||
# second() == &arr[1] (arr + 32 bits)
|
||||
# loadb(&byte) == 0xFFFFFF81 (sign-extended 0x81)
|
||||
# storeb(&byte, 0x81) leaves the byte 0x81
|
||||
#
|
||||
# Overridable: TMS_CLANG TMS_OPT TMS_BITADDR TMS_LLC MAME DOSBOX DOSBOX_CONF
|
||||
# SDK_IMG M1_WORK M1_SDK LOADER_AT LOADER_END
|
||||
# SDK_IMG M1_WORK M1_COFF M1_SDK LOADER_AT LOADER_END
|
||||
set -eu
|
||||
|
||||
ROOT=$(cd "$(dirname "$0")/../.." && pwd)
|
||||
@@ -30,6 +32,7 @@ DOSBOX_CONF=${DOSBOX_CONF:-$ROOT/vendor/vt1200/harness/sdk-scratch/dosbox-bench.
|
||||
SDK_IMG=${SDK_IMG:-$ROOT/vendor/vt1200/tools/tms34010-sdk/1987-05 TMS34010 SDK/1987-11-06 TMS34010 Simulator-C Tools-ASM Tools.img}
|
||||
|
||||
WORK=${M1_WORK:-$ROOT/build/m1}
|
||||
COFF=${M1_COFF:-$WORK/m1.coff}
|
||||
SDK=${M1_SDK:-$ROOT/build/m1-sdk}
|
||||
ASM=$WORK/asm
|
||||
LOADER_LUA=$ROOT/vendor/vt1200/dwt/loader/loader.lua
|
||||
@@ -47,10 +50,11 @@ for tool in "$TMS_CLANG" "$TMS_OPT" "$TMS_BITADDR" "$TMS_LLC"; do
|
||||
done
|
||||
|
||||
mkdir -p "$ASM" "$WORK/evidence" "$WORK/run/nvram" "$WORK/run/cfg"
|
||||
mkdir -p "$(dirname "$COFF")"
|
||||
|
||||
echo "== compile and select"
|
||||
export TMS_CLANG TMS_OPT TMS_BITADDR
|
||||
for name in add load late const_gep; do
|
||||
for name in add load late const_gep char; do
|
||||
"$ROOT/scripts/tms-clang" -O2 -o "$ASM/$name.ll" "$DIR/$name.c"
|
||||
"$TMS_LLC" -march=tms34010 -O0 -filetype=asm \
|
||||
"$ASM/$name.ll" -o "$ASM/$name.s" \
|
||||
@@ -82,7 +86,7 @@ fi
|
||||
|
||||
echo "== assemble and link with GSPA/GSPLNK under DOSBox"
|
||||
cat "$DIR/entry.asm" "$ASM/add.s" "$ASM/load.s" "$ASM/late.s" \
|
||||
"$ASM/const_gep.s" > "$SDK/M1.ASM"
|
||||
"$ASM/const_gep.s" "$ASM/char.s" "$DIR/char-test.asm" > "$SDK/M1.ASM"
|
||||
# The linker command file must keep CRLF line endings.
|
||||
sed 's/\r$//' "$DIR/link.cmd" | sed 's/$/\r/' > "$SDK/M1.CMD"
|
||||
rm -f "$SDK/M1.OBJ" "$SDK/M1.OUT" "$SDK/M1.MAP" "$SDK/M1.LST"
|
||||
@@ -102,7 +106,7 @@ grep -q 'No Errors' "$WORK/m1.lst" \
|
||||
|| { grep -i -B2 -A2 'error' "$WORK/m1.lst" >&2 || true; fail "GSPA reported errors"; }
|
||||
[ -f "$SDK/M1.OUT" ] || fail "GSPLNK produced no M1.OUT"
|
||||
sed 's/\r$//' "$SDK/M1.MAP" > "$WORK/m1.map"
|
||||
cp "$SDK/M1.OUT" "$WORK/m1.coff"
|
||||
cp "$SDK/M1.OUT" "$COFF"
|
||||
cp "$SDK/M1.ASM" "$WORK/m1.asm"
|
||||
|
||||
ENTRY=$(awk '$2 == "_start" { print $1; exit }' "$WORK/m1.map")
|
||||
@@ -133,7 +137,7 @@ echo "== run the COFF in MAME"
|
||||
|
||||
VT1200_SKIP_LEVEL1=1 \
|
||||
LOADER_AT="$LOADER_AT" LOADER_END="$LOADER_END" \
|
||||
LOADER_BIN="$LOADER_BIN" LOADER_COFF="$WORK/m1.coff" \
|
||||
LOADER_BIN="$LOADER_BIN" LOADER_COFF="$COFF" \
|
||||
LOADER_OUT="$WORK/evidence" \
|
||||
M1_LOADER_LUA="$LOADER_LUA" \
|
||||
M1_EXPECT_LOAD=0x12345678 M1_EXPECT_SECOND="$EXPECT_SECOND" \
|
||||
|
||||
@@ -5,6 +5,12 @@ set -eu
|
||||
ROOT=$(cd "$(dirname "$0")/../../.." && pwd)
|
||||
|
||||
# Always rebuild: a stale build/m1/m1.coff would let an asm-encoding
|
||||
# regression pass without ever touching the compiler or assembler.
|
||||
# regression pass without ever touching the compiler or assembler. Keep
|
||||
# dis-roundtrip.sh pointed at the file this run produces, including when
|
||||
# M1_WORK/M1_COFF are overridden.
|
||||
WORK=${M1_WORK:-$ROOT/build/m1}
|
||||
M1_COFF=${M1_COFF:-$WORK/m1.coff}
|
||||
export M1_COFF
|
||||
|
||||
"$ROOT/scripts/m1/run.sh" "$@"
|
||||
exec "$ROOT/scripts/m1/dis-roundtrip.sh" "$@"
|
||||
Reference in new issue
Block a user