346 lines
25 KiB
Plaintext
346 lines
25 KiB
Plaintext
# SplitBit test manifest
|
|
# Written by Anachronaut
|
|
#
|
|
# One test per line, fields separated by '|'. Blank lines and lines starting
|
|
# with '#' are ignored.
|
|
#
|
|
# 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.
|
|
#
|
|
# 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.
|
|
#
|
|
# 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.
|
|
|
|
# ---- 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 | run | - | -
|
|
16bitSegmentedSieve | primeSieve/16bitSegmentedSieve.asm | run | - | -
|
|
# The four pointer rewrite. It emits exactly the same primes as the line above, which
|
|
# is the whole point of keeping both: the pair is a direct before and after.
|
|
16bitSegmentedSieveModern | primeSieve/16bitSegmentedSieveModern.asm | run | - | -
|
|
mathTest | testPrograms/mathTest.asm | run | - | -
|
|
printTest | testPrograms/printTest.asm | run | - | -
|
|
int16print | Libraries/int16print.asm | run | - | -
|
|
|
|
# ---- The multiple Data Pointer behaviour, which nothing else exercises ----
|
|
dataPointerTest | testPrograms/dataPointerTest.asm | run | - | -
|
|
twoPointerCopy | testPrograms/twoPointerCopy.asm | run | - | -
|
|
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 | - | -
|
|
|
|
# ---- The memory controller ----
|
|
# Reading and writing Program Memory, which the instruction set deliberately cannot do,
|
|
# and the bank table that says what is reachable.
|
|
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
|
|
# Walking the directory rather than searching it, which is what listing a disk needs.
|
|
# Twelve files is more than the eight an entry block holds, so the walk has to cross into
|
|
# the second directory block to see them all.
|
|
sbfsWalkTest | testPrograms/sbfsWalkTest.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
|
|
# Deleting, renaming, and saving over something already there, which is what any tool that
|
|
# edits a document needs and what none of the tests above touch. The interesting line is
|
|
# the third: saving a longer version moves the file, because files here are contiguous and
|
|
# do not grow. The last two lines are a rename and a delete having actually happened.
|
|
sbfsEditTest | testPrograms/sbfsEditTest.asm | run | - | - | disks/edit.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.
|
|
loaderTest | testPrograms/loaderTest.asm | run | - | -
|
|
|
|
# Giving a bank number to a device's memory, which is what an OS does at boot.
|
|
registerBankTest | testPrograms/registerBankTest.asm | run | - | -
|
|
# The fence: raised, walked into, clipped by a blit, read through, and lowered again.
|
|
fenceTest | testPrograms/fenceTest.asm | run | - | -
|
|
# Meant to fault: a bank knows how big it is.
|
|
bankBoundsTest | testPrograms/bankBoundsTest.asm | run | - | -
|
|
|
|
# ---- A device saying no ----
|
|
# Refusing is not interrupting: it stops the instruction that asked, rather than asking
|
|
# for attention later. The device on port 0x11 refuses everything so this path stays
|
|
# tested before the memory controller becomes its only real user.
|
|
refusalTest | testPrograms/refusalTest.asm | run | - | -
|
|
# The same, with nothing installed to catch it. Meant to fault.
|
|
refusalFaultTest | testPrograms/refusalFaultTest.asm | run | - | -
|
|
|
|
# ---- Asking the machine what it is made of ----
|
|
registryTest | testPrograms/registryTest.asm | run | - | -
|
|
|
|
# ---- Moving the cursor along ----
|
|
paddingTest | testPrograms/paddingTest.asm | run | - | -
|
|
|
|
# ---- Finding the Stack, and moving it ----
|
|
stackPointerTest | testPrograms/stackPointerTest.asm | run | - | -
|
|
# MVDS, the dangerous one: a system taking its Stack back from a program that stopped
|
|
# without unwinding. The sequence is the one the Programming Manual prints under "The
|
|
# Stack Pointer, Set By Hand", so the manual's example cannot quietly stop working.
|
|
stackReclaimTest | testPrograms/stackReclaimTest.asm | run | - | -
|
|
|
|
# ---- The Interrupt Flag ----
|
|
# Nothing reads the flag yet. This checks that setting and clearing it leaves
|
|
# the registers and the Carry Flag it shares a byte with untouched.
|
|
interruptFlagTest | testPrograms/interruptFlagTest.asm | run | - | -
|
|
|
|
# ---- Vectors laid down by the assembler ----
|
|
# These are the interrupt path end to end. Until #Vectors existed, none of them could
|
|
# be written as a source file at all, because nothing could install a handler.
|
|
vectorTest | testPrograms/vectorTest.asm | run | - | -
|
|
# Numbers written down and numbers handed out, in one program. A vector number only matters
|
|
# where two separately assembled programs have to agree about it, so those are pinned by
|
|
# hand from a range the assembler never allocates, and everything else is drawn from above
|
|
# it. This pins both ends of that range and leaves a third to the assembler, then calls all
|
|
# three by name: a number going astray shows up as the wrong word rather than as silence.
|
|
pinnedVectorTest | testPrograms/pinnedVectorTest.asm | run | - | -
|
|
# A service handing something back, which RETI otherwise makes impossible: it restores every
|
|
# register from the frame, so a handler that worked something out has no way to say so. The
|
|
# answer is written into the frame over the saved register. All three cases are here - a
|
|
# service that says nothing and leaves Q exactly as it found it, one that answers in Q, and
|
|
# one that answers in DP3 - because the first is what makes the other two safe to rely on.
|
|
serviceReturnTest | testPrograms/serviceReturnTest.asm | run | - | -
|
|
deviceTest | testPrograms/deviceTest.asm | run | - | -
|
|
faultResumeTest | testPrograms/faultResumeTest.asm | run | - | -
|
|
# The worked example out of the Assembler Manual, so the manual cannot go stale.
|
|
interruptExample | testPrograms/interruptExample.asm | run | - | -
|
|
|
|
# ---- Holding a device off, and then letting it through ----
|
|
# Faults on purpose. The fault is the proof that the line was answered, and where it
|
|
# lands in the output is the proof of when.
|
|
maskTest | testPrograms/maskTest.asm | run | - | -
|
|
|
|
# ---- Dispatching through a vector with nothing in it ----
|
|
# Also meant to fault. Until the assembler can lay a vector table down, every entry
|
|
# reads as zero, so this is the only half of the interrupt path a source file can
|
|
# reach on its own. The round trip through a handler is covered by hand built
|
|
# binaries until #Vectors arrives.
|
|
swiFaultTest | testPrograms/swiFaultTest.asm | run | - | -
|
|
|
|
# ---- Meeting a byte that is not an instruction ----
|
|
# This one is meant to fault. It checks the CPU stops, says what it found and
|
|
# where, and exits non zero, rather than stepping over it and carrying on.
|
|
faultTest | testPrograms/faultTest.asm | run | - | -
|
|
|
|
# ---- The modern console library ----
|
|
# Every routine in console.asm, called with the cases that are easy to get wrong: a zero,
|
|
# the largest thing that fits, and a leading zero that should not print. The reading half
|
|
# is given a line longer than its buffer, so truncation and the swallowing of the rest
|
|
# are shown rather than assumed.
|
|
consoleTest | testPrograms/consoleTest.asm | run | consoleTest.in | -
|
|
# The console's status and control ports. Input here is a file rather than a terminal, so
|
|
# key mode has no terminal to change and only the mode bit moves: that is deliberate, since
|
|
# a program has to behave the same either way and a test needing a terminal could not run.
|
|
# What it pins down is that READY is clear at the end of input while ENDED is set, so a
|
|
# loop reading while READY stops on its own instead of taking imaginary bytes forever.
|
|
consoleModeTest | testPrograms/consoleModeTest.asm | run | consoleModeTest.in | -
|
|
# The console interrupting instead of being asked. The main program never touches the
|
|
# console at all, so every byte in that output was delivered by a handler. It also pins
|
|
# down the two things that make the feature usable rather than merely present: the end of
|
|
# input raises the line once, so an interrupt-driven program is told when to stop, and a
|
|
# handler that does not read the byte is not called again, so nothing storms.
|
|
consoleInterruptTest | testPrograms/consoleInterruptTest.asm | run | consoleInterruptTest.in | -
|
|
# Picking a typed line apart, which is how the shell understands anything. Includes a
|
|
# string beginning with a zero: the assembler strips the quotes before deciding what a
|
|
# token is, so such a string looked like a malformed literal and was refused.
|
|
textTest | testPrograms/textTest.asm | run | - | -
|
|
|
|
# ---- CosmOS ----
|
|
# The system and its shell, driven by a script of commands. This is the first thing that
|
|
# uses the machine as a machine rather than exercising one part of it: it boots, mounts a
|
|
# disk written by the host tool, reads lines, and walks a directory to answer 'dir'.
|
|
cosmos | CosmOS/Source/cosmos.asm | run | cosmos.in | - | disks/sbfs.img
|
|
# The same with nothing attached. A shell that only works with a disk in the drive is not
|
|
# finished, so the empty machine is a case in its own right rather than an accident.
|
|
cosmosNoDisk | CosmOS/Source/cosmos.asm | run | cosmosNoDisk.in | -
|
|
# Loading a program and running it, which is the whole machine at once: the filesystem
|
|
# finds it, the controller writes it into Program Memory, the vector table carries its
|
|
# requests back to the system, and MVDS takes the Stack back when it stops. Every way
|
|
# load can refuse is tried first, and run is asked for twice, so the Stack being reclaimed
|
|
# rather than merely abandoned is what makes the second one work.
|
|
cosmosRun | CosmOS/Source/cosmos.asm | run | cosmosRun.in | - | disks/cosmos.img
|
|
# The monitor. It reads Program Memory, which the instruction set cannot do at all, so it
|
|
# works only through the controller. The targets are chosen to be stable: a loaded
|
|
# program's code and data, and the bank table, rather than the system's own code, which
|
|
# would churn whenever any library changed.
|
|
#
|
|
# Dumping the bank table is worth having on its own. It is the machine describing itself,
|
|
# and it shows the disk buffer that sbfsMount registered as bank 3 at boot.
|
|
cosmosDump | CosmOS/Source/cosmos.asm | run | cosmosDump.in | - | disks/cosmos.img
|
|
# The original hello.asm, brought over as an application. It is not much of a program,
|
|
# but it is the one that talks to the hardware directly: it writes to port 0x00 instead
|
|
# of calling osPrintString, so it is the case where a program reaches past the system and
|
|
# the system has to get control back anyway. run is asked for twice for the same reason
|
|
# it is in cosmosRun, and here it also says the Stack comes back from a program that never
|
|
# entered a service handler at all.
|
|
cosmosHello | CosmOS/Source/cosmos.asm | run | cosmosHello.in | - | disks/cosmos.img
|
|
# Life, which is the one program that had no end state to reach. It stops when the board
|
|
# settles, and the glider does settle: it crosses the field, hits the dead border, and
|
|
# collapses into a block at generation 54. NO CYCLE LIMIT ON PURPOSE. Whether it stops on
|
|
# its own is the whole point of the port, and a limit would answer that question for it.
|
|
#
|
|
# NOTHING IS TYPED AFTER run, and that is load bearing rather than tidy. Life polls the
|
|
# console between generations, and a byte sitting in the pipe is a byte waiting on the
|
|
# console as far as the machine is concerned - exactly as typing ahead at a terminal
|
|
# would be. An "exit" on the next line stops it at generation 1 and gets eaten. The shell
|
|
# ends the run by reaching the end of input instead, the way cosmosNoDisk does.
|
|
cosmosLife | CosmOS/Source/cosmos.asm | run | cosmosLife.in | - | disks/cosmos.img
|
|
# The other half of that: a key IS waiting, so it stops at once instead of at generation
|
|
# 54. The two together are what say the poll is reading the console rather than always
|
|
# answering the same way.
|
|
cosmosLifeKey | CosmOS/Source/cosmos.asm | run | cosmosLifeKey.in | - | disks/cosmos.img
|
|
# A whole game of Snake, played by a script. Life is watched; this is steered, and it is
|
|
# the first program on this machine that reads the console without ever waiting for it.
|
|
# One key is taken per frame, so twelve bytes in the pipe are twelve moves rather than
|
|
# twelve moves at once: six turn it down the board and six take it left onto the food. So
|
|
# what is recorded is a turn, a meal, a longer snake, and then a wall.
|
|
cosmosSnake | CosmOS/Source/cosmos.asm | run | cosmosSnake.in | - | disks/cosmos.img
|
|
# A loaded program that brings a vector of its own, which nothing could do until the
|
|
# loadable format could carry one. It is run TWICE on purpose: installing has to be exactly
|
|
# undone by removing, and the way that fails is asymmetrically, so the second run is the one
|
|
# that catches it. The dump afterwards is the proof that the table was put back - the
|
|
# console's slot at FE00 is zero again, and CosmOS's own disk handler further along is
|
|
# untouched by a program having installed over the top of it.
|
|
cosmosKeys | CosmOS/Source/cosmos.asm | run | cosmosKeys.in | - | disks/cosmos.img
|
|
# The shell taking things off a disk and calling them something else, which is the last of
|
|
# CosmOS's original four verbs to be built and the first time anything has changed a disk
|
|
# from the shell. Its own image, because it changes what is on it: a fixture named with a
|
|
# directory is used as it stands, so a test that writes to a shared one changes what every
|
|
# test after it sees. The refusals are here too - deleting what is not there, renaming with
|
|
# a name missing, and renaming something to a name already taken.
|
|
cosmosFiles | CosmOS/Source/cosmos.asm | run | cosmosFiles.in | - | disks/files.img
|
|
# A program being told what it is for. Nothing loaded before this could be told anything,
|
|
# so every app did the same thing however it was started - which is fine for a demo and no
|
|
# use at all to a tool that edits a named document. Run three times: with nothing, with a
|
|
# name, and with several words, since what arrives is the rest of the line rather than a
|
|
# list and it is the program's business what to make of it.
|
|
cosmosSay | CosmOS/Source/cosmos.asm | run | cosmosSay.in | - | disks/cosmos.img
|
|
# The editor, which is the first program on this machine that makes a file a person typed:
|
|
# every byte on every other image here was put there by the host tool. It is run twice in
|
|
# one session, and that is the test rather than a flourish - the second run reads back what
|
|
# the first one wrote, so the whole path is checked at once: read a name from the argument,
|
|
# split a file into lines, edit them, build a file back out of them, and save it over
|
|
# something that was already there and is now a different size.
|
|
cosmosEdit | CosmOS/Source/cosmos.asm | run | cosmosEdit.in | - | disks/editor.img
|
|
# The programs CosmOS loads, checked on their own so that a failure here reads as "the app
|
|
# does not assemble" rather than as a broken disk image.
|
|
app-greet | CosmOS/Apps/greet.asm | assemble | - | -
|
|
app-hello | CosmOS/Apps/hello.asm | assemble | - | -
|
|
app-Life | CosmOS/Apps/Life.asm | assemble | - | -
|
|
app-Snake | CosmOS/Apps/Snake.asm | assemble | - | -
|
|
app-Keys | CosmOS/Apps/Keys.asm | assemble | - | -
|
|
app-Say | CosmOS/Apps/Say.asm | assemble | - | -
|
|
app-Edit | CosmOS/Apps/Edit.asm | assemble | - | -
|
|
|
|
# ---- Programs driven by console input ----
|
|
inputTest | inputTest.asm | run | inputTest.in | -
|
|
inputTestOld | testPrograms/inputTest.asm | 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
|
|
# The four pointer rewrite, on the same budget so the two can be compared directly.
|
|
# Note that this cannot show a speed difference: frameDelay is 255 by 255 and swamps
|
|
# the simulation, so both versions render the same fourteen generations and produce
|
|
# identical bytes. What it checks is that the rewrite still evolves the board the same
|
|
# way, which is what a regression test is for.
|
|
16x16LifeModern | gameOfLife/16x16LifeModern.asm | run | - | 3000000
|
|
|
|
# ---- Libraries: no entry point, so only check that they assemble ----
|
|
# The CosmOS libraries assemble on their own, unlike print.asm below, which cannot: it
|
|
# begins with a branch to a label only the including program defines. That difference is
|
|
# the point of the rewrite, so both halves of it are recorded here.
|
|
lib-console | CosmOS/Source/console.asm | assemble | - | -
|
|
lib-text | CosmOS/Source/text.asm | assemble | - | -
|
|
lib-sbfs | CosmOS/Source/sbfs.asm | 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 | - | -
|
|
|
|
# ---- Deliberately broken, to check the assembler still diagnoses them ----
|
|
# These are not programs anyone meant to run. Each one contains a single mistake
|
|
# that the assembler used to accept quietly, and is here so that it cannot start
|
|
# being accepted quietly again.
|
|
diagDuplicateLabel | testPrograms/diagnostics/duplicateLabel.asm | xfail | - | -
|
|
diagBareInclude | testPrograms/diagnostics/bareInclude.asm | xfail | - | -
|
|
diagUnknownVector | testPrograms/diagnostics/unknownVector.asm | xfail | - | -
|
|
diagDuplicateVector | testPrograms/diagnostics/duplicateVector.asm | xfail | - | -
|
|
# The two mistakes that pinning a number makes possible. Numbers the assembler hands out
|
|
# cannot collide; numbers a person writes down can, and can also be written outside the
|
|
# range set aside for them.
|
|
# A string in the Program Segment, which used to assemble to nothing at all and say so to
|
|
# nobody. Strings only have a case for the Data buffer, so one aimed anywhere else fell
|
|
# through and vanished.
|
|
diagStringInProgram | testPrograms/diagnostics/stringInProgram.asm | xfail | - | -
|
|
diagPinnedRange | testPrograms/diagnostics/pinnedVectorRange.asm | xfail | - | -
|
|
diagPinnedTaken | testPrograms/diagnostics/pinnedVectorTaken.asm | xfail | - | -
|
|
diagBareSWI | testPrograms/diagnostics/bareSWI.asm | xfail | - | -
|
|
diagAlignOutside | testPrograms/diagnostics/alignOutside.asm | xfail | - | -
|
|
diagBareAlign | testPrograms/diagnostics/bareAlign.asm | xfail | - | -
|
|
# One segment based and the other forgotten, which is how the ported Fib-8 put its data
|
|
# on top of the console's variables. It assembled and it ran, so nothing but the assembler
|
|
# was ever going to catch it.
|
|
diagUnbasedSegment | testPrograms/diagnostics/unbasedSegment.asm | xfail | - | -
|
|
|
|
# ---- 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. They are
|
|
# only ever pulled in by printTest.asm, so they are not standalone programs.
|
|
printDecimalTest | testPrograms/printDecimalTest.asm | xfail | - | -
|
|
printDigitTest | testPrograms/printDigitTest.asm | xfail | - | -
|
|
printHexTest | testPrograms/printHexTest.asm | xfail | - | -
|
|
# shiftTest calls printDecimal, which print.asm does not have. It looks like the
|
|
# routine was renamed and this caller was never updated.
|
|
shiftTest | testPrograms/shiftTest.asm | xfail | - | -
|