# 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/.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 | - | - # Strings that spell instructions. The quotes are gone by the time a token is classified, so # "ADD" in a Data Segment was assembled as the ADD instruction and refused with a message # about a mistake nobody had made. Mnemonics match without regard to case, so "or" and "and" # were caught too - ordinary words to want in a message. stringMnemonic | testPrograms/stringMnemonic.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, which is part of the shell rather than a program: a mode you go into and stay # in. 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. # # Looking at 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. # # The last part is what the mode is FOR: a program typed in as bytes, run with g, and the # prompt that comes back is the monitor's own. A program giving the machine back lands where # it was started from, so looking at something and running it do not interrupt each other. # # It also asks to write into bank 2, the controller's own table, which is published read # only. That used to stop the machine, and the recorded output of this test contained the # crash without anybody noticing, which is what blessing a result without reading it buys. cosmosMonitor | CosmOS/Source/cosmos.asm | run | cosmosMonitor.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 # A program stopping itself to be looked at. Two breakpoints, so what is checked is not only # that one fires but that the SECOND one does - which is the whole difference between this # design and one that overwrites an instruction, since an overwritten instruction has to be # put back to continue and putting it back is the same act as disarming the breakpoint. # Every value shown comes out of the interrupt frame rather than the registers, because by # the time the handler runs the registers are the handler's. cosmosBreak | CosmOS/Source/cosmos.asm | run | cosmosBreak.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 file services, exercised by a program that includes NOTHING but the service names: no # filesystem library, no console library. It writes a file, reads it back, says how long it # was, renames it and deletes it, in 645 bytes - against the editor's 4941, which does less # with files and carries the filesystem inside it. That difference is the whole case for the # service layer, and this is where it is checked rather than argued. cosmosServices | CosmOS/Source/cosmos.asm | run | cosmosFiles2.in | - | disks/services.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-Break | CosmOS/Apps/Break.asm | assemble | - | - app-Edit | CosmOS/Apps/Edit.asm | assemble | - | - app-Files | CosmOS/Apps/Files.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 | - | -