Various bug fixes to assembler, added more data pointers.

This commit is contained in:
Anachronaut
2026-08-13 23:41:22 -04:00
parent b50210d127
commit c2440ae5fa
38 changed files with 1028 additions and 236 deletions
+2
View File
@@ -0,0 +1,2 @@
0000 0001 0001 0002 0003 0005 0008 000D 0015 0022 0037 0059 0090 00E9 0179 0262 03DB 063D 0A18 1055 1A6D 2AC2 452F 6FF1
Execution halted after 2534 cycles.
File diff suppressed because one or more lines are too long
+225
View File
@@ -0,0 +1,225 @@
 #
#
###

# #
##
#

#
# #
##

#
##
##

#
#
###

# #
##
#

#
# #
##

#
##
##

#
#
###

# #
##
#

#
# #
##

#
##
##

#
#
###

# #
##
#
Execution stopped after 3000000 cycles. (cycle limit reached)
+2
View File
@@ -0,0 +1,2 @@
00000000 00000001 00000001 00000002 00000003 00000005 00000008 0000000D 00000015 00000022 00000037 00000059 00000090 000000E9 00000179 00000262 000003DB 0000063D 00000A18 00001055 00001A6D 00002AC2 0000452F 00006FF1 0000B520 00012511 0001DA31 0002FF42 0004D973 0007D8B5 000CB228 00148ADD 00213D05 0035C7E2 005704E7 008CCCC9 00E3D1B0 01709E79 02547029 03C50EA2 06197ECB 09DE8D6D 0FF80C38 19D699A5 29CEA5DD 43A53F82 6D73E55F
Execution halted after 10610 cycles.
+2
View File
@@ -0,0 +1,2 @@
0 1 1 2 3 5 8 13 21 34 55 89 144 233
Execution halted after 1506 cycles.
+2
View File
@@ -0,0 +1,2 @@
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251
Execution halted after 54061 cycles.
+2
View File
@@ -0,0 +1,2 @@
ABCZ
Execution halted after 21 cycles.
+2
View File
@@ -0,0 +1,2 @@
Hello, World!
Execution halted after 70 cycles.
+3
View File
@@ -0,0 +1,3 @@
Input Test: Will echo anything you put in.
Hello SplitBit
Execution halted after 406 cycles.
+3
View File
@@ -0,0 +1,3 @@
Input Test: Will echo anything you put in.
Hello SplitBit
Execution halted after 406 cycles.
+3
View File
@@ -0,0 +1,3 @@
00 00 00 00 01
1
Execution halted after 4707 cycles.
+2
View File
@@ -0,0 +1,2 @@
0000 0032
Execution halted after 1134 cycles.
+3
View File
@@ -0,0 +1,3 @@
Hello, World!
42 is the great answer.
Execution halted after 295 cycles.
+12
View File
@@ -0,0 +1,12 @@
Test suite for SplitBit's print.asm library.
Testing printDigit...
0 1 2 3 4 5 6 7 8 9
Testing printByteDecimal...
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
Testing printByteHex...
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
Testing complete!
Execution halted after 71185 cycles.
+16
View File
@@ -0,0 +1,16 @@
SplitBit calculator (+ - * & | ^), Q quits.
> 0F
> 00
> 30
> 00
> FF
> 55
> 18
> Goodbye!Execution halted after 2960 cycles.
+2
View File
@@ -0,0 +1,2 @@
Two pointers, no stack shenanigans.
Execution halted after 395 cycles.
+1
View File
@@ -0,0 +1 @@
Hello SplitBit
+8
View File
@@ -0,0 +1,8 @@
0A+05
FF+01
10*03
F0&0F
0F|F0
AA^FF
20-08
Q
+65
View File
@@ -0,0 +1,65 @@
# SplitBit test manifest
# Written by Anachronaut
#
# One test per line, fields separated by '|'. Blank lines and lines starting
# with '#' are ignored.
#
# name | source | assemble-from | mode | stdin | limit
#
# source and assemble-from are both relative to Programs/. assemble-from exists
# because #Include paths resolve against the current directory rather than
# against the including file, so each program has one directory it builds in.
#
# Modes:
# run Assemble, execute, compare all output against Tests/expected/<name>.out
# assemble Assemble only. For library files that have no entry point to run
# xfail Assembly is expected to fail. Records a known breakage so that
# fixing one is noticed, and so an accidental new one is too
#
# limit is a cycle count, for programs that never halt on their own. It is passed
# to the emulator as --cycles, which bounds the run by cycles rather than by wall
# clock time and so keeps the recorded output identical from one run to the next.
# Every program is run with --fast, since the emulated cycle rate has no bearing
# on what a program prints.
# ---- Programs that halt on their own ----
hello | hello.asm | . | run | - | -
printHello | printHello.asm | . | run | - | -
8bitFibonacci | Fibonacci/8bitFibonacci.asm | . | run | - | -
16bitFibonacci | Fibonacci/16bitFibonacci.asm | . | run | - | -
32bitFibonacci | Fibonacci/32bitFibonacci.asm | . | run | - | -
8bitSieve | primeSieve/8bitSieve.asm | primeSieve | run | - | -
16bitSegmentedSieve | primeSieve/16bitSegmentedSieve.asm | . | run | - | -
mathTest | testPrograms/mathTest.asm | testPrograms | run | - | -
printTest | testPrograms/printTest.asm | testPrograms | run | - | -
int16print | Libraries/int16print.asm | Libraries | run | - | -
# ---- The multiple Data Pointer behaviour, which nothing else exercises ----
dataPointerTest | testPrograms/dataPointerTest.asm | testPrograms | run | - | -
twoPointerCopy | testPrograms/twoPointerCopy.asm | testPrograms | run | - | -
# ---- Programs driven by console input ----
inputTest | inputTest.asm | . | run | inputTest.in | -
inputTestOld | testPrograms/inputTest.asm | testPrograms | run | inputTest.in | -
replCalculator | replCalculator.asm | . | run | replCalculator.in | -
# ---- Programs that run forever by design, bounded by a cycle count ----
# 3,000,000 cycles is about fourteen generations of the glider, which puts
# evolveBoard and its pointer juggling through its paces many times over.
16x16Life | gameOfLife/16x16Life.asm | . | run | - | 3000000
# ---- Libraries: no entry point, so only check that they assemble ----
lib-int8 | Libraries/int8.asm | . | assemble | - | -
lib-int16 | Libraries/int16.asm | . | assemble | - | -
lib-int32 | Libraries/int32.asm | . | assemble | - | -
lib-math | Libraries/math.asm | . | assemble | - | -
# ---- Known breakages, recorded rather than ignored ----
# print.asm branches to 'start', which only the including program defines.
lib-print | Libraries/print.asm | . | xfail | - | -
# These three call print.asm routines but have no #Include line at all.
printDecimalTest | testPrograms/printDecimalTest.asm | testPrograms | xfail | - | -
printDigitTest | testPrograms/printDigitTest.asm | testPrograms | xfail | - | -
printHexTest | testPrograms/printHexTest.asm | testPrograms | xfail | - | -
# shiftTest includes "print.asm", which is not beside it.
shiftTest | testPrograms/shiftTest.asm | testPrograms | xfail | - | -
Executable
+193
View File
@@ -0,0 +1,193 @@
#!/usr/bin/env bash
# run.sh
# Test runner for the SplitBit Emulator and Assembler.
# Written by Anachronaut
#
# Assembles and runs every program listed in Tests/manifest and compares the
# output against the recorded results in Tests/expected.
#
# ./Tests/run.sh Run the suite.
# ./Tests/run.sh --bless Record current output as the expected results.
# ./Tests/run.sh <name>... Run only the named tests.
#
# Programs are built inside Tests/build so that running the suite never touches
# the binaries in Programs/.
set -u
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TESTS="$ROOT/Tests"
BUILD="$TESTS/build"
EXPECTED="$TESTS/expected"
INPUT="$TESTS/input"
MANIFEST="$TESTS/manifest"
ASSEMBLER="$ROOT/Assembler"
EMULATOR="$ROOT/SplitBit"
RUN_TIMEOUT=10
BLESS=0
ONLY=()
for arg in "$@"; do
case "$arg" in
--bless) BLESS=1 ;;
-h|--help)
sed -n '3,14p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
exit 0
;;
-*) echo "run.sh: unknown option $arg" >&2; exit 2 ;;
*) ONLY+=("$arg") ;;
esac
done
for tool in "$ASSEMBLER" "$EMULATOR"; do
if [ ! -x "$tool" ]; then
echo "run.sh: $tool is missing. Run 'make' first." >&2
exit 2
fi
done
rm -rf "$BUILD"
mkdir -p "$BUILD" "$EXPECTED"
cp -r "$ROOT/Programs/." "$BUILD/"
find "$BUILD" -name '*.bin' -delete
PASS=0
FAIL=0
BLESSED=0
FAILED_NAMES=()
wanted() {
[ ${#ONLY[@]} -eq 0 ] && return 0
local n
for n in "${ONLY[@]}"; do [ "$n" = "$1" ] && return 0; done
return 1
}
report() {
# report <status> <name> <detail>
printf ' [%-4s] %-20s %s\n' "$1" "$2" "$3"
}
trim() {
local v="$1"
v="${v#"${v%%[![:space:]]*}"}"
v="${v%"${v##*[![:space:]]}"}"
printf '%s' "$v"
}
check() {
# check <name> <actual-file>
local name="$1" actual="$2" golden="$EXPECTED/$1.out"
if [ "$BLESS" -eq 1 ]; then
cp "$actual" "$golden"
BLESSED=$((BLESSED + 1))
report "rec" "$name" "$(wc -c < "$golden" | tr -d ' ') bytes recorded"
return 0
fi
if [ ! -f "$golden" ]; then
FAIL=$((FAIL + 1)); FAILED_NAMES+=("$name")
report "FAIL" "$name" "no recorded output; run with --bless"
return 1
fi
if cmp -s "$actual" "$golden"; then
PASS=$((PASS + 1))
report "ok" "$name" ""
return 0
fi
FAIL=$((FAIL + 1)); FAILED_NAMES+=("$name")
report "FAIL" "$name" "output differs"
diff -u "$golden" "$actual" 2>/dev/null | head -20 | sed 's/^/ /'
return 1
}
assemble() {
# assemble <source> <assemble-from>; echoes the built binary path on success
local src="$1" dir="$2"
local wd="$BUILD/$dir" rel bin
rel="$(realpath --relative-to="$wd" "$BUILD/$src")"
bin="$wd/$(basename "${src%.asm}").bin"
if ( cd "$wd" && "$ASSEMBLER" "$rel" ) >"$BUILD/.assemble.log" 2>&1; then
echo "$bin"
return 0
fi
return 1
}
while IFS='|' read -r name src dir mode stdin limit; do
name="$(trim "$name")"
[ -z "$name" ] && continue
case "$name" in \#*) continue ;; esac
src="$(trim "$src")"; dir="$(trim "$dir")"
mode="$(trim "$mode")"; stdin="$(trim "$stdin")"
limit="$(trim "$limit")"
wanted "$name" || continue
if [ "$mode" = "xfail" ]; then
if assemble "$src" "$dir" >/dev/null; then
FAIL=$((FAIL + 1)); FAILED_NAMES+=("$name")
report "FAIL" "$name" "expected assembly to fail, but it succeeded"
else
PASS=$((PASS + 1))
report "ok" "$name" "fails as recorded: $(head -1 "$BUILD/.assemble.log" | tr -d '\033' | sed 's/\[[0-9;]*m//g')"
fi
continue
fi
if ! BIN="$(assemble "$src" "$dir")"; then
FAIL=$((FAIL + 1)); FAILED_NAMES+=("$name")
report "FAIL" "$name" "assembly failed"
head -3 "$BUILD/.assemble.log" | tr -d '\033' | sed 's/\[[0-9;]*m//g' | sed 's/^/ /'
continue
fi
if [ "$mode" = "assemble" ]; then
PASS=$((PASS + 1))
report "ok" "$name" "assembles"
continue
fi
if [ "$stdin" != "-" ] && [ ! -f "$INPUT/$stdin" ]; then
FAIL=$((FAIL + 1)); FAILED_NAMES+=("$name")
report "FAIL" "$name" "missing input fixture $stdin"
continue
fi
IN=/dev/null
[ "$stdin" != "-" ] && IN="$INPUT/$stdin"
OUT="$BUILD/.out"
case "$mode" in
run)
# --fast because there is nothing to learn from waiting out the emulated
# clock, and --cycles for programs that never halt on their own, which
# bounds them by cycle count rather than by wall clock.
EMUARGS=(--fast)
[ "$limit" != "-" ] && EMUARGS+=(--cycles "$limit")
if ! timeout "$RUN_TIMEOUT" "$EMULATOR" "${EMUARGS[@]}" "$BIN" <"$IN" >"$OUT" 2>&1; then
FAIL=$((FAIL + 1)); FAILED_NAMES+=("$name")
report "FAIL" "$name" "did not finish within ${RUN_TIMEOUT}s"
continue
fi
check "$name" "$OUT"
;;
*)
FAIL=$((FAIL + 1)); FAILED_NAMES+=("$name")
report "FAIL" "$name" "unknown mode '$mode' in manifest"
;;
esac
done < "$MANIFEST"
echo
if [ "$BLESS" -eq 1 ]; then
echo "Recorded $BLESSED expected results into Tests/expected."
exit 0
fi
if [ "$FAIL" -eq 0 ]; then
echo "All $PASS tests passed."
exit 0
fi
echo "$PASS passed, $FAIL failed: ${FAILED_NAMES[*]}"
exit 1