Block device peripheral and SBFS file system implemented.
This commit is contained in:
Executable
+106
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env bash
|
||||
# Checks SplitDisk against the SBFS format.
|
||||
#
|
||||
# The tool and the SplitBit side are two implementations of one written specification,
|
||||
# and nothing but that document keeps them the same. This checks the host half on its
|
||||
# own: that a file put onto a disk comes back off it byte for byte, that the sizes which
|
||||
# exercise the block and tail arithmetic all survive, and that the things the format
|
||||
# says cannot happen are refused rather than half done.
|
||||
#
|
||||
# Written by Anachronaut
|
||||
|
||||
set -u
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
TOOL="$ROOT/SplitDisk"
|
||||
WORK="$ROOT/Tests/build/disk"
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
FAILED_NAMES=()
|
||||
|
||||
GREEN=$'\033[32m'; RED=$'\033[31m'; RESET=$'\033[0m'
|
||||
[ -t 1 ] || { GREEN=""; RED=""; RESET=""; }
|
||||
|
||||
check() {
|
||||
local name="$1"; shift
|
||||
if "$@" >/dev/null 2>&1; then
|
||||
PASS=$((PASS + 1)); printf " [%sok %s] %s\n" "$GREEN" "$RESET" "$name"
|
||||
else
|
||||
FAIL=$((FAIL + 1)); FAILED_NAMES+=("$name")
|
||||
printf " [%sFAIL%s] %s\n" "$RED" "$RESET" "$name"
|
||||
fi
|
||||
}
|
||||
|
||||
# The opposite: the command is supposed to fail, and passing would be the bug.
|
||||
refuses() {
|
||||
local name="$1"; shift
|
||||
if "$@" >/dev/null 2>&1; then
|
||||
FAIL=$((FAIL + 1)); FAILED_NAMES+=("$name")
|
||||
printf " [%sFAIL%s] %s (it was allowed)\n" "$RED" "$RESET" "$name"
|
||||
else
|
||||
PASS=$((PASS + 1)); printf " [%sok %s] %s\n" "$GREEN" "$RESET" "$name"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ ! -x "$TOOL" ]; then
|
||||
echo "SplitDisk is not built."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf "$WORK"; mkdir -p "$WORK"
|
||||
cd "$WORK" || exit 1
|
||||
|
||||
echo "Checking SplitDisk against the SBFS format."
|
||||
|
||||
check "format a disk" "$TOOL" format work.img 64 2
|
||||
refuses "refuse a disk with no room" "$TOOL" format tiny.img 2 4
|
||||
refuses "refuse an unformatted disk" "$TOOL" list /dev/null
|
||||
|
||||
# The sizes that exercise every corner of blocks-plus-tail: nothing at all, less than a
|
||||
# block, exactly a block, a part block, and an exact multiple.
|
||||
: > empty.bin
|
||||
printf 'x' > one.bin
|
||||
head -c 256 /dev/urandom > exact.bin
|
||||
head -c 700 /dev/urandom > part.bin
|
||||
head -c 768 /dev/urandom > whole.bin
|
||||
|
||||
for f in empty.bin one.bin exact.bin part.bin whole.bin; do
|
||||
check "put $f" "$TOOL" put work.img "$f"
|
||||
done
|
||||
|
||||
roundTrip() {
|
||||
"$TOOL" get work.img "$1" "got_$1" >/dev/null 2>&1 || return 1
|
||||
cmp -s "$1" "got_$1"
|
||||
}
|
||||
for f in empty.bin one.bin exact.bin part.bin whole.bin; do
|
||||
check "$f comes back byte for byte" roundTrip "$f"
|
||||
done
|
||||
|
||||
refuses "refuse a name of 29 characters" "$TOOL" put work.img part.bin 16bitSegmentedSieveModern.asm
|
||||
refuses "refuse a duplicate name" "$TOOL" put work.img one.bin
|
||||
refuses "refuse a file that is not there" "$TOOL" get work.img nosuch.bin out.bin
|
||||
check "delete" "$TOOL" delete work.img one.bin
|
||||
refuses "the deleted file is gone" "$TOOL" get work.img one.bin out.bin
|
||||
check "the name can be used again" "$TOOL" put work.img one.bin
|
||||
|
||||
# Contiguous files mean a disk can have room without having room in one piece. That is a
|
||||
# consequence of the format rather than a bug, so it is checked rather than worked around.
|
||||
"$TOOL" format frag.img 16 1 >/dev/null 2>&1
|
||||
head -c 1024 /dev/urandom > a.bin; cp a.bin b.bin; cp a.bin c.bin
|
||||
"$TOOL" put frag.img a.bin >/dev/null 2>&1
|
||||
"$TOOL" put frag.img b.bin >/dev/null 2>&1
|
||||
"$TOOL" put frag.img c.bin >/dev/null 2>&1
|
||||
"$TOOL" delete frag.img a.bin >/dev/null 2>&1
|
||||
"$TOOL" delete frag.img c.bin >/dev/null 2>&1
|
||||
head -c 2048 /dev/urandom > big.bin
|
||||
refuses "refuse a file with no run long enough" "$TOOL" put frag.img big.bin
|
||||
head -c 512 /dev/urandom > fits.bin
|
||||
check "but one that fits the gap goes on" "$TOOL" put frag.img fits.bin
|
||||
|
||||
echo
|
||||
if [ "$FAIL" -eq 0 ]; then
|
||||
echo "All $PASS disk tool checks passed."
|
||||
exit 0
|
||||
fi
|
||||
echo "$PASS passed, $FAIL failed: ${FAILED_NAMES[*]}"
|
||||
exit 1
|
||||
Executable
+127
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env bash
|
||||
# Checks the manuals against the code.
|
||||
#
|
||||
# Documentation goes stale quietly. An instruction added without a table row, or a count
|
||||
# in a heading that nobody updated, is wrong in a way nothing notices until somebody
|
||||
# trusts it. Everything here is a claim the manuals make that can be settled by looking
|
||||
# at the source, so it is settled every time the tests run.
|
||||
#
|
||||
# Written by Anachronaut
|
||||
|
||||
set -u
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
cd "$ROOT" || exit 1
|
||||
|
||||
python3 - <<'PY'
|
||||
import re
|
||||
import sys
|
||||
|
||||
problems = []
|
||||
|
||||
|
||||
def read(path):
|
||||
return open(path).read()
|
||||
|
||||
|
||||
pm = read("SplitBit Programming Manual.md")
|
||||
am = read("SplitBit Assembler Manual.md")
|
||||
asmc = read("Source/Assembler/assembly.c")
|
||||
util = read("Source/Assembler/Assm-util.c")
|
||||
|
||||
# ---- Every instruction has a row, and every row is an instruction ----
|
||||
#
|
||||
# A mnemonic begins with a letter, which is what keeps the offset and size columns of the
|
||||
# other tables in these manuals out of it.
|
||||
documented = {(int(m.group(1), 16), m.group(2))
|
||||
for m in re.finditer(r'^\|\s*([0-9A-F]{2})\s*\|\s*([A-Z][A-Z0-9]*)\s*\|', pm, re.M)}
|
||||
implemented = {(int(m.group(1), 16), m.group(2))
|
||||
for m in re.finditer(r'\{0x([0-9A-Fa-f]{2}),\s*"([A-Z0-9]+)"\}', asmc)}
|
||||
for opcode, name in sorted(implemented - documented):
|
||||
problems.append("%s (0x%02X) is implemented and not in the manual" % (name, opcode))
|
||||
for opcode, name in sorted(documented - implemented):
|
||||
problems.append("%s (0x%02X) is in the manual and not implemented" % (name, opcode))
|
||||
|
||||
# ---- The counts in the group headings ----
|
||||
body = asmc[asmc.index("Instruction instruction_set[]"):asmc.index("int num_instructions")]
|
||||
actual = {}
|
||||
group = None
|
||||
for line in body.split("\n"):
|
||||
heading = re.match(r'\s*// (.+?) Operations:', line)
|
||||
if heading:
|
||||
group = heading.group(1)
|
||||
actual.setdefault(group, 0)
|
||||
if re.search(r'\{0x[0-9A-Fa-f]{2},', line) and group:
|
||||
actual[group] += 1
|
||||
|
||||
for m in re.finditer(r'^### (.+?) Operations: (\d+) Instructions?$', pm, re.M):
|
||||
name, claimed = m.group(1), int(m.group(2))
|
||||
# The manual's headings are wordier than the source's comments, so match on the start.
|
||||
match = [v for k, v in actual.items() if name.startswith(k)]
|
||||
if not match:
|
||||
problems.append("the manual has a group called \"%s\" that the source does not" % name)
|
||||
elif match[0] != claimed:
|
||||
problems.append("the manual says %s has %d instructions, and it has %d"
|
||||
% (name, claimed, match[0]))
|
||||
|
||||
# ---- Every directive the assembler knows is written down ----
|
||||
for directive in sorted(set(re.findall(r'"(#[A-Za-z]+)"', util))):
|
||||
if directive not in am:
|
||||
problems.append("%s is a directive and is not in the Assembler Manual" % directive)
|
||||
|
||||
# ---- Every routine the manual promises exists ----
|
||||
for library, names in [("Programs/Libraries/sbfs.asm", re.findall(r'\| (sbfs[A-Za-z]+) \|', pm))]:
|
||||
defined = set(re.findall(r'^([a-zA-Z][A-Za-z0-9]*):', read(library), re.M))
|
||||
for name in names:
|
||||
if name not in defined:
|
||||
problems.append("the manual lists %s, which %s does not define" % (name, library))
|
||||
|
||||
# ---- The worked example still assembles to the bytes the manual prints ----
|
||||
#
|
||||
# The hello world program and the hex dump beside it are two claims about the same thing,
|
||||
# and nothing but this keeps them agreeing.
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
source = pm.split("### Example Program: Hello World")[1].split("```")[1]
|
||||
claimed = pm.split("assembled and dumped as hex:")[1].split("```")[1].split()
|
||||
with tempfile.TemporaryDirectory() as work:
|
||||
asm = os.path.join(work, "hello.asm")
|
||||
binary = os.path.join(work, "hello.bin")
|
||||
open(asm, "w").write(source)
|
||||
built = subprocess.run(["./Assembler", asm, "-o", binary],
|
||||
capture_output=True)
|
||||
if built.returncode != 0:
|
||||
problems.append("the hello world program in the manual no longer assembles")
|
||||
else:
|
||||
actual = ["%02x" % b for b in open(binary, "rb").read()]
|
||||
if [c.lower() for c in claimed] != actual:
|
||||
problems.append("the hex dump in the manual is not what that program assembles to"
|
||||
" now: it prints %d bytes and the assembler makes %d"
|
||||
% (len(claimed), len(actual)))
|
||||
|
||||
# ---- The Assembler Manual's worked programs still assemble ----
|
||||
for heading in ["## An Example SplitBit Assembly Program:",
|
||||
"## An Example Using More Than One Data Pointer:",
|
||||
"## An Example Using Interrupts:"]:
|
||||
if heading not in am:
|
||||
problems.append("the Assembler Manual has lost its \"%s\" section" % heading.strip("# :"))
|
||||
continue
|
||||
example = am.split(heading)[1].split("```")[1]
|
||||
with tempfile.TemporaryDirectory() as work:
|
||||
asm = os.path.join(work, "example.asm")
|
||||
open(asm, "w").write(example)
|
||||
built = subprocess.run(["./Assembler", "-I", "Programs/Libraries", asm,
|
||||
"-o", os.path.join(work, "example.bin")],
|
||||
capture_output=True)
|
||||
if built.returncode != 0:
|
||||
problems.append("the example under \"%s\" no longer assembles"
|
||||
% heading.strip("# :"))
|
||||
|
||||
if problems:
|
||||
print("The manuals and the code disagree:")
|
||||
for p in problems:
|
||||
print(" " + p)
|
||||
sys.exit(1)
|
||||
print("The manuals agree with the code.")
|
||||
PY
|
||||
@@ -0,0 +1,4 @@
|
||||
QAB C qab c
|
||||
9876543210
|
||||
Execution halted after 176 cycles.
|
||||
[exit 0]
|
||||
@@ -0,0 +1,5 @@
|
||||
04
|
||||
04
|
||||
06
|
||||
Execution halted after 114 cycles.
|
||||
[exit 0]
|
||||
@@ -0,0 +1,5 @@
|
||||
00
|
||||
from the disk
|
||||
02
|
||||
Execution halted after 245 cycles.
|
||||
[exit 0]
|
||||
@@ -0,0 +1,4 @@
|
||||
loader
|
||||
loaded off a disk, with a string and a loop of its own
|
||||
Execution halted after 1098 cycles.
|
||||
[exit 0]
|
||||
@@ -0,0 +1,7 @@
|
||||
greeting.txt 0000 11 hello from a file
|
||||
across.txt 0002 BC ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX
|
||||
aName22CharactersLong! 0000 16 exactly twenty two!!!!
|
||||
empty.txt 0000 00
|
||||
absent.txt missing
|
||||
Execution halted after 19230 cycles.
|
||||
[exit 0]
|
||||
@@ -0,0 +1,5 @@
|
||||
here.txt 0002 already here
|
||||
first.txt 0003 written by SplitBit itself
|
||||
second.txt 0004 and a second one after it
|
||||
Execution halted after 5888 cycles.
|
||||
[exit 0]
|
||||
Executable
+56
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
# Builds the disk images the tests read from.
|
||||
#
|
||||
# These are made with SplitDisk, which is the other implementation of the same format.
|
||||
# That is the point of them: a SplitBit program reading one of these is being checked
|
||||
# against something written by different code from a written specification, rather than
|
||||
# against itself.
|
||||
#
|
||||
# Written by Anachronaut
|
||||
|
||||
set -eu
|
||||
BUILD="$1"
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
TOOL="$ROOT/SplitDisk"
|
||||
DISKS="$BUILD/disks"
|
||||
WORK="$BUILD/.diskwork"
|
||||
|
||||
[ -x "$TOOL" ] || { echo "SplitDisk is not built."; exit 1; }
|
||||
mkdir -p "$DISKS" "$WORK"
|
||||
|
||||
# Two directory blocks, so that a file can be put beyond the first one and the walk from
|
||||
# block to block gets exercised rather than assumed.
|
||||
"$TOOL" format "$DISKS/sbfs.img" 64 2 >/dev/null
|
||||
|
||||
cd "$WORK"
|
||||
printf 'hello from a file' > greeting.txt
|
||||
|
||||
# Eight files fill the first directory block exactly, so everything after this lands in
|
||||
# the second one.
|
||||
for i in 1 2 3 4 5 6 7 8; do printf 'filler %d' "$i" > "filler$i.txt"; done
|
||||
|
||||
# Longer than a block, so reading it has to cross from one to the next. The pattern
|
||||
# repeats every twenty six bytes, which makes a misplaced block obvious to read.
|
||||
awk 'BEGIN { for (i = 0; i < 700; i++) printf "%c", 65 + (i % 26) }' > across.txt
|
||||
|
||||
: > empty.txt
|
||||
printf 'exactly twenty two!!!!' > longname.txt
|
||||
|
||||
"$TOOL" put "$DISKS/sbfs.img" greeting.txt >/dev/null
|
||||
for i in 1 2 3 4 5 6 7 8; do "$TOOL" put "$DISKS/sbfs.img" "filler$i.txt" >/dev/null; done
|
||||
"$TOOL" put "$DISKS/sbfs.img" across.txt >/dev/null
|
||||
"$TOOL" put "$DISKS/sbfs.img" empty.txt >/dev/null
|
||||
"$TOOL" put "$DISKS/sbfs.img" longname.txt aName22CharactersLong! >/dev/null
|
||||
|
||||
# A disk with a loadable program on it. The program is assembled here rather than kept as
|
||||
# bytes, so that what gets loaded is always built from the source beside it.
|
||||
"$TOOL" format "$DISKS/load.img" 64 2 >/dev/null
|
||||
"$ROOT/Assembler" "$ROOT/Programs/loadable/hello.asm" -o "$WORK/hello.bin" >/dev/null
|
||||
python3 "$ROOT/Source/DiskTool/wrap.py" "$WORK/hello.bin" "$WORK/hello.sbx" 0x2000 0x1000 0x2000 >/dev/null
|
||||
"$TOOL" put "$DISKS/load.img" "$WORK/hello.sbx" >/dev/null
|
||||
|
||||
# A disk of its own for the writing test, with one file already on it so that what it
|
||||
# writes has to be placed somewhere that does not tread on what is there.
|
||||
"$TOOL" format "$DISKS/write.img" 32 1 >/dev/null
|
||||
printf 'already here' > here.txt
|
||||
"$TOOL" put "$DISKS/write.img" here.txt >/dev/null
|
||||
+32
-1
@@ -4,7 +4,7 @@
|
||||
# One test per line, fields separated by '|'. Blank lines and lines starting
|
||||
# with '#' are ignored.
|
||||
#
|
||||
# name | source | mode | stdin | limit
|
||||
# name | source | mode | stdin | limit | disk
|
||||
#
|
||||
# source is relative to Programs/. Everything assembles from there with
|
||||
# Libraries/ on the include path, and the binary is written into Tests/build.
|
||||
@@ -18,6 +18,14 @@
|
||||
# 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.
|
||||
#
|
||||
# disk names a disk image to attach, made fresh inside Tests/build for every run so that
|
||||
# nothing a test writes can be seen by the next one. Leave it off for a machine with no
|
||||
# disk, which is most of them. A trailing :ro attaches it write protected.
|
||||
#
|
||||
# A disk name with a directory in it, such as disks/sbfs.img, is one of the images that
|
||||
# Tests/makedisks.sh builds with SplitDisk before the run. Those are used as they stand,
|
||||
# so a test can read a filesystem written by the other implementation of the format.
|
||||
# Every program is run with --fast, since the emulated cycle rate has no bearing
|
||||
# on what a program prints.
|
||||
|
||||
@@ -43,6 +51,11 @@ pointerTableTest | testPrograms/pointerTableTest.asm | run | -
|
||||
staticTableTest | testPrograms/staticTableTest.asm | run | - | -
|
||||
dispatchTest | testPrograms/dispatchTest.asm | run | - | -
|
||||
|
||||
# ---- Branching both ways round ----
|
||||
# Each of the four conditions is checked taken and not taken, so a branch that always
|
||||
# went the same way would be caught rather than looking right half the time.
|
||||
branchTest | testPrograms/branchTest.asm | run | - | -
|
||||
|
||||
# ---- Moving an ALU result back into an operand register ----
|
||||
moveQTest | testPrograms/moveQTest.asm | run | - | -
|
||||
|
||||
@@ -53,6 +66,24 @@ controllerReadTest | testPrograms/controllerReadTest.asm | run | -
|
||||
controllerWriteTest | testPrograms/controllerWriteTest.asm | run | - | -
|
||||
# Block transfers: between banks, within one, overlapping, and one that is refused.
|
||||
blitTest | testPrograms/blitTest.asm | run | - | -
|
||||
# Reading a filesystem that the host tool wrote. The two are separate implementations of
|
||||
# one written format, so this is where any drift between them would show.
|
||||
sbfsReadTest | testPrograms/sbfsReadTest.asm | run | - | - | disks/sbfs.img
|
||||
|
||||
# Writing a filesystem, then reading back what was written. The disk starts with a file
|
||||
# on it, so allocation has to find room rather than start at the beginning.
|
||||
sbfsWriteTest | testPrograms/sbfsWriteTest.asm | run | - | - | disks/write.img
|
||||
|
||||
# Loading a program off a disk and running it. Everything below this line existed before
|
||||
# the loader did; the only new part is the sixteen bytes on the front of a loadable
|
||||
# program saying where it goes.
|
||||
loader | loader.asm | run | - | - | disks/load.img
|
||||
|
||||
# Storage. The image is made fresh for each run, so block 3 starts as zeroes.
|
||||
diskTest | testPrograms/diskTest.asm | run | - | - | disk.img
|
||||
# The same disk attached write protected, so the device bars writes rather than software.
|
||||
diskProtectTest | testPrograms/diskProtectTest.asm | run | - | - | protected.img:ro
|
||||
|
||||
# A program that loads a program: blits code into Program Memory, installs a vector at
|
||||
# run time, and calls it. If the vector install ever silently failed, the SWI would fault
|
||||
# with "no handler" rather than printing, so this test cannot pass by accident.
|
||||
|
||||
+27
-2
@@ -54,6 +54,12 @@ PROGRAMS="$ROOT/Programs"
|
||||
rm -rf "$BUILD"
|
||||
mkdir -p "$BUILD" "$EXPECTED"
|
||||
|
||||
# Disk images the tests read from are built here, with the host tool, before anything
|
||||
# runs. The build directory is thrown away above, so they are always freshly made.
|
||||
if [ -x "$TESTS/makedisks.sh" ]; then
|
||||
"$TESTS/makedisks.sh" "$BUILD" || { echo "Couldn't build the test disks."; exit 1; }
|
||||
fi
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
BLESSED=0
|
||||
@@ -116,13 +122,14 @@ assemble() {
|
||||
return 1
|
||||
}
|
||||
|
||||
while IFS='|' read -r name src mode stdin limit; do
|
||||
while IFS='|' read -r name src mode stdin limit disk; do
|
||||
name="$(trim "$name")"
|
||||
[ -z "$name" ] && continue
|
||||
case "$name" in \#*) continue ;; esac
|
||||
src="$(trim "$src")"
|
||||
mode="$(trim "$mode")"; stdin="$(trim "$stdin")"
|
||||
limit="$(trim "$limit")"
|
||||
limit="$(trim "$limit")"; disk="$(trim "$disk")"
|
||||
[ -z "$disk" ] && disk="-"
|
||||
|
||||
wanted "$name" || continue
|
||||
|
||||
@@ -166,6 +173,24 @@ while IFS='|' read -r name src mode stdin limit; do
|
||||
# bounds them by cycle count rather than by wall clock.
|
||||
EMUARGS=(--fast)
|
||||
[ "$limit" != "-" ] && EMUARGS+=(--cycles "$limit")
|
||||
# A disk starts fresh for every run, so a test cannot pass because of what a
|
||||
# previous one left lying on it. The emulator makes the image if it is
|
||||
# missing, which is what removing it first arranges for.
|
||||
if [ "$disk" != "-" ]; then
|
||||
# A trailing :ro attaches the image write protected, so that a test can
|
||||
# check the device bars writes rather than the filesystem asking nicely.
|
||||
DISKFILE="${disk%:ro}"
|
||||
# A name with a directory in it is one of the images makedisks.sh built,
|
||||
# and is used as it stands. A bare name is scratch: it is removed first so
|
||||
# that nothing a test writes can be seen by the next one, and the emulator
|
||||
# makes a blank image in its place.
|
||||
case "$DISKFILE" in
|
||||
*/*) ;;
|
||||
*) rm -f "$BUILD/$DISKFILE" ;;
|
||||
esac
|
||||
EMUARGS+=(--disk "$BUILD/$DISKFILE")
|
||||
[ "$disk" != "$DISKFILE" ] && EMUARGS+=(--write-protect)
|
||||
fi
|
||||
timeout "$RUN_TIMEOUT" "$EMULATOR" "${EMUARGS[@]}" "$BIN" <"$IN" >"$OUT" 2>&1
|
||||
STATUS=$?
|
||||
if [ "$STATUS" -eq 124 ]; then
|
||||
|
||||
Reference in New Issue
Block a user