# 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 | keys # # 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, and the assembler's diagnostic is recorded # and compared like any other output. Catches a known breakage that stops # being detected, an accidental new one, and a message that changes # without anybody meaning it to # # 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. # # keys names a file in Tests/input to be fed to the console as a KEYBOARD rather than as # standard input, and the difference is the point. Standard input reaches a console that # believes a terminal is handling the line editing, which is true when one is. A keyboard # reaches a console that knows it has to do the editing itself - gathering a line, rubbing # out a backspace, handing it over only at Return - which is what happens behind a window, # where there is no terminal to do any of it. # # 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 | Examples/hello.asm | run | - | - printHello | Examples/printHello.asm | run | - | - 8bitFibonacci | Examples/Fibonacci/8bitFibonacci.asm | run | - | - 16bitFibonacci | Examples/Fibonacci/16bitFibonacci.asm | run | - | - 32bitFibonacci | Examples/Fibonacci/32bitFibonacci.asm | run | - | - colours | Examples/colours.asm | run | - | - # frames waits for the screen sixty times, which is one second at the emulated rate. It is # here because the count is exact: a frame is counted in the machine's own cycles, so the # same program sees the same sixty however fast the host really went. frames | Examples/frames.asm | run | - | - # picture draws a whole 320 by 200 bitmap and prints nothing, so what is recorded is only # that it ran and what it cost. Tests/video.sh is where the pixels are checked. picture | Examples/picture.asm | run | - | - # tune plays the Anachronaut Labs theme and prints nothing, so what is recorded is that it # ran, that it finished on its own, and how much of its time it spent asleep - which is # 99.8% of it, because the tempo is the screen's frame and a program waiting on a frame is # not using the bus. Tests/sound.sh is where the samples are checked. # # THE BUDGET IS A DURATION, and that is the thing to know if this ever fails. 567 frames of # music at 16,667 cycles a frame is 9.45 million, so twelve leaves room to lengthen the tune # without coming back here - and a failure saying "cycle limit reached" means somebody added # bars, not that anything broke. tune | Examples/tune.asm | run | - | 12000000 8bitSieve | Examples/primeSieve/8bitSieve.asm | run | - | - 16bitSegmentedSieve | Examples/primeSieve/16bitSieve.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 | Examples/primeSieve/16bitSieveModern.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/controllerWrite.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/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/consoleInterrupt.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. # # It ends with a whole program typed in: a string poked into Data Memory, instructions # assembled into Program Memory, and the result run - which prints something no assembler # ever saw. The mnemonics deliberately include a lower case one, both selector forms, an # instruction that does not exist and one missing its value, so that the refusals are # recorded next to the successes and a failed line is shown writing nothing. 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 keys that are not characters, both halves of the rule in one run: a line read in line # mode with an arrow key in the middle of it, which arrives with the arrow dropped because # line mode delivers characters, and then the same keys in key mode where they are what the # program asked for. Fed as STANDARD INPUT, so the console is reading bytes that are exactly # what is in the file - no terminal is involved and no escape sequence is translated, which # is what makes an arrow key testable at all. cosmosPress | CosmOS/Source/cosmos.asm | run | cosmosPress.in | - | disks/cosmos.img # The same program and the same keys, fed as a KEYBOARD instead. That is the other front # end - the window's path through the gatherer - and it has its own copy of the line mode # rule, so it needs its own test. The two recordings should agree, which is the point. cosmosPressKeys | CosmOS/Source/cosmos.asm | run | - | - | disks/cosmos.img | cosmosPress.in # The shell editing the line it is being given, which is the whole reason the keys were # made to arrive. Every line here is typed wrong and then corrected with a different key, and # every one of them comes out as the same command - so the recording says both what the # machine printed on the way and that the line the shell finally acted on was right. # # The escape sequences in it are the point rather than noise: moving the cursor by hand is # what a terminal is TOLD about, and they are the only evidence of where the shell thinks it # is. The last line is eighty five characters at a prompt in column two, so the cursor has to # be found on the row below - the one case the arithmetic exists for. cosmosEditKeys | CosmOS/Source/cosmos.asm | run | cosmosEditKeys.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. Break sets all three of the # pointers it owns and rotates them between the two stops, so every value recorded here is # one something chose - it used to leave two of them holding whatever the shell had left, # which tied this record to where CosmOS's code sits and made it churn on changes that had # nothing to do with breakpoints. DP3 is left as the system set it, being where the program # was entered. 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 # Streaming, which is what a file bigger than memory needs. The disk here holds 84000 # bytes in one file and the machine has 64K of Data Memory, so there is no arrangement of # osFileRead that could get at it: the program reads it through a buffer of one block. # # THE CHECK THAT MATTERS IS THE SECOND ONE. A small file is read both ways - whole with # osFileRead, and streamed - and the two checksums have to agree, so streaming is measured # against the path that already worked rather than against a number somebody wrote down. # The checksum is Fletcher's rather than a sum, because a sum is the same whatever order # the bytes arrived in and the order is exactly what streaming has to get right. # # The rest of it is the lookup the system keeps so that reading four hundred blocks of one # file does not search the directory four hundred times. Two files read alternately catch a # memory that does not notice the name changed, and a rename catches one that does not # notice the file moved - and that one would otherwise pass, since the blocks are still # there and still hold the same bytes. cosmosStream | CosmOS/Source/cosmos.asm | run | cosmosStream.in | - | disks/stream.img # A useful application made out of the streaming primitive: print a named text file without # requiring it to fit in Data Memory. The fixture crosses block boundaries, includes a full # 256-byte block, and also checks empty, missing, and absent filename cases. cosmosType | CosmOS/Source/cosmos.asm | run | cosmosType.in | - | disks/type.img # The same stream with interaction layered on it. Three runs exercise q, a whole screen # with Space, and one line with Return. The input is intentionally packed so that the one # byte the pager consumes leaves the next shell command immediately behind it. cosmosMore | CosmOS/Source/cosmos.asm | run | cosmosMore.in | - | disks/type.img # Copy and Compare exercise both halves of block streaming together. Empty, exact-block, # part-block and 84,000-byte files are copied through one buffer; Compare checks the copies # and a same-sized file whose only difference is deep into the input. cosmosCopyCompare | CosmOS/Source/cosmos.asm | run | cosmosCopyCompare.in | - | disks/copycompare.img # A working directory deeper than the prompt can print. The prompt is built BACKWARDS into # 127 bytes, and nothing bounds how deep the directories go - a path is capped at what one # operation can name, but "cd" a level at a time is well inside that and can be repeated. # So the walk wrote down past the front of its own buffer and into what the assembler put # below it, which was the shell's command names: at six directories of twenty two # characters the word "exit" was gone and the shell no longer knew how to stop. # # WHAT IS RECORDED IS THAT THE COMMANDS STILL WORK, and that is the whole point of running # help and cd and exit from down there rather than just looking at the prompt. A prompt # that is merely wrong is a cosmetic fault; this one was writing into other variables. cosmosDeep | CosmOS/Source/cosmos.asm | run | cosmosDeep.in | - | disks/deep.img # A disk claiming a directory of 8192 blocks, which is 65536 entries. The last of those is # entry 65535, and the parent field is an index PLUS ONE in two bytes - so it wraps to # zero, which means the root. Anything created in such a directory goes into the root # while the caller is told it went where it asked, and looking there afterwards finds # nothing, so the same create works again and again and fills the root with entries of one # name. Refused at mount, which is the only place it can be refused once and for all. cosmosBigDir | CosmOS/Source/cosmos.asm | run | cosmosBigDir.in | - | disks/bigdir.img # ---- Starting the machine off a disk ---- # # Stage one is what will one day be in ROM. It knows the disk's ports, that a SplitBit disk # begins with its own name, and where two numbers sit in that first block - and nothing # else. It reads the live boot slot into Program Memory and jumps to the first byte. # # Two disks, differing only in which slot the superblock names, and the payloads say # different things. That is what makes this a test of CHOOSING a slot rather than a test # that some bytes were read: one prints "booted" and the other does not. bootChain | Boot/stage1.asm | run | - | - | disks/chain.img bootChainAlt | Boot/stage1.asm | run | - | - | disks/chainAlt.img # A disk with no boot area cannot be started, and says so in the one character a ROM has # room to say anything in. bootNoArea | Boot/stage1.asm | run | - | - | disks/sbfs.img # A payload that arranges its own Data Segment, by copying it down from just past its own # code. Stage one places Program Memory and nothing else - knowing where a payload's data # ended would mean knowing a format - so this is how the real second stage will get the # variables and the string that sbfs.asm needs. bootData | Boot/slotData.asm | assemble | - | - bootDataRuns | Boot/stage1.asm | run | - | - | disks/chainData.img # ---- The machine starting itself ---- # # The whole chain: the emulator hands over stage one, stage one reads the live boot slot # into Program Memory and jumps, stage two mounts the filesystem, finds /System/cosmos.bin, # takes the image apart and places its code, its data and its vector table, and jumps to # the entry point the vectors named. # # WHAT IS RECORDED IS THAT THE SYSTEM WORKS AFTERWARDS, not that it started. A loaded # program running is what says the vector table arrived, because a program reaches the # system through SWI and nothing else; the file written and the directory entered say the # filesystem and the console came up with it. selfBoot | Boot/stage1.asm | run | selfBoot.in | 90000000 | disks/selfboot.img # And a disk with a boot slot but nothing to start, which says so rather than jumping. selfBootNoSystem | Boot/stage1.asm | run | - | 90000000 | disks/nosystem.img # ---- And with no image named at all ---- # # The mode is "rom": the emulator is handed a disk and nothing else, so it shadows its own # built-in stage one into Program Memory and starts there, which is what a machine with no # debugger attached does. Naming an image is the debugger, and every other test here is # using it. # # The source column still names stage1.asm even though the binary is thrown away, because # that is what is IN the ROM: the makefile builds rom.c from that file, so assembling it # here says the thing the emulator carries is a thing that still assembles. romBoot | Boot/stage1.asm | rom | selfBoot.in | 90000000 | disks/selfboot.img # ---- What starts is a setting, not a name compiled into the loader ---- # # Three disks differing only in /System/Boot/boot.cfg, so each is a test of the file rather # than of the machinery under it. # # cfgBare starts an image with NO OPERATING SYSTEM IN IT, which is what loading an ordinary # boot image buys: a program wanting the whole machine is a file like any other, and is # chosen the same way the system is. cfgBare | Boot/stage1.asm | rom | - | 90000000 | disks/cfgbare.img # cfgBroken has every kind of mistake in it and a good setting underneath them. The machine # STILL STARTS - configuration is advice - and says what it could not use on the way, so a # setting somebody meant which did not happen is not silent. cfgBroken | Boot/stage1.asm | rom | - | 90000000 | disks/cfgbroken.img # cfgFallback names a system that is not there. What was tried, and what was tried next. cfgFallback | Boot/stage1.asm | rom | selfBoot.in | 90000000 | disks/cfgfallback.img # And the bare image on its own, which has to keep assembling. bareMetal | Boot/bare.asm | assemble | - | - # ---- A system that never reaches a prompt ---- # # Three disks that differ only in the boot state on them, so the three tests read as three # consecutive starts of one machine while none of them depends on another having run. # # wedgeFirst tries it and marks the disk. wedgeSecond finds the mark still set - nothing # came back to say the last start arrived - and uses the fallback. wedgeThird finds that # already happened and does the same again WITHOUT retrying, which is the part worth # pinning down: a system known not to start should not be tried every other boot for ever. wedgeFirst | Boot/stage1.asm | rom | - | 90000000 | disks/wedgefirst.img wedgeSecond | Boot/stage1.asm | rom | - | 90000000 | disks/wedgesecond.img wedgeThird | Boot/stage1.asm | rom | - | 90000000 | disks/wedgethird.img wedgedImage | Boot/wedged.asm | assemble | - | - # ---- Closing the loop from inside the machine ---- # # A machine that says "settle it to try again" and gives you no way to do so has told you # about a problem it will not let you fix. Settle is a program rather than a shell word: # one job, reached through SWI, replaceable, and callable by anything that comes to call # programs in sequence. # ---- The console doing a terminal's job ---- # # Behind a window nothing is handling the line editing, so the console does it. Typing "halp", # backing over it, and arriving at "help" has to reach the shell as "help" - it used to arrive # with the backspaces still in it, which made a corrected line unrecognisable while looking # perfectly right on the screen. cosmosTyped | CosmOS/Source/cosmos.asm | run | - | - | disks/cosmos.img | cosmosTyped.keys cosmosSettle | CosmOS/Source/cosmos.asm | run | settle.in | 90000000 | disks/settle.img # Saying so when there is nothing to settle is as much a part of it as doing it. cosmosSettled | CosmOS/Source/cosmos.asm | run | settle.in | 90000000 | disks/settled.img settleApp | CosmOS/Apps/Settle.asm | assemble | - | - # ---- What a program made of it ---- # # Three programs in a row, each asked after. A status that did not survive the program that # set it would be no use to the thing this exists for - whatever comes to run programs in # sequence and has to decide whether to run the next one. # # 0 it did what it was asked, 1 it did not, 2 it was asked wrongly. cosmosStatus | CosmOS/Source/cosmos.asm | run | status.in | 90000000 | disks/status.img statusApp | CosmOS/Apps/Status.asm | assemble | - | - # ---- Reading a file with long lines into the editor ---- # # Opened twice, because once was not enough to see it: the first open corrupted the head of # the document and the allocator's pointer, and the second walked a list that led back into # itself and never came back. The emulator kept running and the machine never answered. # # Then a file with a line past what the editor can hold, which is REFUSED rather than # shortened - a line cut here would be written back cut, and the file damaged by having # been looked at. cosmosEditLong | CosmOS/Source/cosmos.asm | run | editLong.in | 200000000 | disks/editlong.img # ---- Starting something else just this once ---- # # A bare metal program has nowhere to run: starting it from the shell means there is no # shell, and pointing boot.cfg at it means a machine that keeps starting it. Once writes a # request the loader reads before boot.cfg and DELETES BEFORE IT JUMPS, so the image runs on # the next start and on no other, whatever becomes of it. # # Three disks, each a start further on, so none of them depends on another having run. onceAsked | CosmOS/Source/cosmos.asm | run | once.in | 200000000 | disks/onceasked.img # The start the request was for. It starts an image with no operating system in it at all, # and THE BOOT STATE IS NOT TOUCHED: a one shot is already self limiting, and marking it # would report every successful bare metal boot as a start that never arrived. onceDue | Boot/stage1.asm | rom | - | 200000000 | disks/oncedue.img # And the start after, which is an ordinary one again. onceAfter | Boot/stage1.asm | rom | - | 200000000 | disks/onceafter.img onceApp | CosmOS/Apps/Once.asm | assemble | - | - # ---- Starting again ---- # # The loop end to end and inside one session: ask for a one shot, restart, and watch an # image with no operating system in it take the machine. Before this the only way to # restart was to stop the emulator, which meant the one thing the machine could not do was # the thing Once exists for. # # A reset repeats HOW THIS MACHINE STARTED. Here no image is named, so the ROM is shadowed # again and reads the disk. rebootOnce | Boot/stage1.asm | rom | reboot.in | 300000000 | disks/reboot.img # And here one IS named, so the reset places it again rather than reading the disk - a # reset that changed what the machine is would be the one thing a reset must not do. rebootDirect | CosmOS/Source/cosmos.asm | run | rebootDirect.in | 200000000 | disks/reboot.img rebootApp | CosmOS/Apps/Reboot.asm | assemble | - | - # A failed start with NOTHING to fall back to. The mark must not become a reason to refuse # to start at all - a failure that was passing recovers here, and one that is not leaves # the machine exactly where it would have been without any of this. noFallback | Boot/stage1.asm | rom | - | 90000000 | disks/nofallback.img # Reading a disk that has directories on it. The machine can walk a path at this point but # cannot make a directory, so the disk is built by the host tool and read here - which is # the two implementations checking each other rather than either checking itself. # # The two Say.sbx are DIFFERENT PROGRAMS under one name - Say echoes its argument, hello # prints one fixed line - so which one a path reached is written in the output. Two copies # of the same program would have passed this test with the parent comparison removed # altogether, which is the one thing it exists to check. # Then the ways a path does not resolve: through a file, into a directory that is not # there, onto a directory rather than a program, a component too long to be a name, and # the root itself. Last, that delete refuses a directory - the refusal that keeps a freed # entry index from being handed out with children still pointing at it. cosmosTree | CosmOS/Source/cosmos.asm | run | cosmosTree.in | - | disks/tree.img # Writing a file onto a disk that has directories on it. The document goes in the root, # because nothing on the machine can put one anywhere else yet, and the point is that it # gets there at all: making a file walks the allocator over two directory entries, which # hold no blocks and must therefore be in nobody's way when a run of free ones is wanted. # The listing afterwards says where it landed and how big it is. cosmosTreeWrite | CosmOS/Source/cosmos.asm | run | cosmosTreeWrite.in | - | disks/treewrite.img # Committing a streamed file bigger than the room reserved for it, which must be refused. # # osFileStart sets an extent aside and osFileWrite already refuses a block index outside it, # so writing off the end is barred. This is the same neighbour reached the other way: claim # the extra block at commit rather than write into it. A directory entry is the only record # of what a file owns, so an entry claiming a block it was never given simply owns it, and # so does whatever owned it before - both files then look perfectly well formed. # # The size is compared and not the room it takes up, because those differ: one block and a # tail occupies what two whole blocks occupy, so bounding the blocks alone would allow a # file to report two hundred and forty six bytes that were never written to it. The # reservation here is one block and a tail of ten, and the claim is two whole blocks - the # same two blocks, and a bigger lie. # # The listing at the end is the point: 266 bytes, which is what was reserved and what was # written, after the refusal and the honest commit that follows it. cosmosClaim | CosmOS/Source/cosmos.asm | run | cosmosClaim.in | - | disks/claim.img # The filesystem waiting for a disk that takes time. Every other test here runs with the # disk finishing before the next instruction starts, which is what it has always done and # what hides whether anything honours the busy bit. This one gives it a latency. # # It is the same directory listing as any other; the point is that it is the SAME. A # filesystem that did not wait would read the block before the one it asked for, which is # not an error anywhere - just quietly the wrong bytes - and this listing would be nonsense # rather than a failure with a message. cosmosSlowDisk | CosmOS/Source/cosmos.asm | run | cosmosSlowDisk.in | - | disks/cosmos.img@2000 # The machine building its own tree. It starts with a blank version one disk and makes # every directory on it, which is the half of the filesystem the machine could only read # until now. # # The refusals are most of the test. rmdir will not take a file and delete will not take a # directory, so neither can be the one that removed more than was asked for; a directory # with anything in it is refused outright, because a parent is an entry INDEX and a freed # index goes to the next thing created - the children would turn up inside whatever took # its place, with nothing pointing downward to find them by. A name already taken in that # directory is refused, and the same name in a different directory is not, which is the # whole point of the exercise. # # The last dir is there to show the disk still adds up: every entry made and unmade, and # nothing left over. cosmosBuild | CosmOS/Source/cosmos.asm | run | cosmosBuild.in | - | disks/build.img # The working directory. cd moves the machine, the prompt says where it is once that is # not the root, and dir lists one directory rather than the whole disk. # # The two notes.txt say different things ON PURPOSE, and that is the whole test: reading # "notes.txt" from /A and then from /B has to give two different files. If the remembered # file were not dropped when the machine moves, the second read would hand back the first # one - same key, same entry, nothing about it looking wrong. # # Then that a program is looked for where you are BEFORE /Apps: /A holds a Say.sbx that is # really hello, so "Say" from /A prints the wrong thing on purpose, and "Say" from /B has # to reach the real one in /Apps. # # And the two things only a program moving the machine itself can check. Wander calls # osChangeDir, so after "Wander /A" from /B the prompt has to say /B again - the shell puts # the working directory back the way it puts the Stack and the vector table back. Reading # notes.txt straight afterwards has to give B's copy, which is the remembered file being # dropped when the machine moved. Without Wander neither of those could be made to fail, # because nothing else on the machine can move it. cosmosCwd | CosmOS/Source/cosmos.asm | run | cosmosCwd.in | - | disks/cwd.img # Typing a program's name starts it. The disk is built so that each line of the input asks # a different question of the one rule: "Say hello there" is a bare name with an argument, # "Say.sbx" is the same file spelled out in full, and "run once more" says the program that # was invoked really did land in the loaded slot and can be started again from it. # # Then the four ways a word does not become a running program. "dir" is a real program on # this disk and must still list the disk, because the built-ins are tried first. "notes" # finds notes.sbx and says it is not a program, which is the answer that has to differ from # "I do not know" - the file is there. "notes.txt" looks for notes.txt.sbx and finds # nothing, which is how a text file stays unreachable by name. And the last two are the # length boundary: eighteen characters is the longest bare name that leaves room for the # extension, and nineteen cannot be a file name at all, so both are unknown words. cosmosInvoke | CosmOS/Source/cosmos.asm | run | cosmosInvoke.in | - | disks/invoke.img # The assembler's front end, checked in two pieces before anything is built on it. # # cosmosSource reads a source file and prints it back. The file crosses a block boundary, # so the seam is exercised rather than assumed, and the line count at the end says the # reader knows where it is as well as what it holds. # # cosmosTokens says what each token IS. That is the part worth checking here rather than at # the far end: a wrong classification does not produce a wrong byte somewhere obvious, it # produces a right looking program of the wrong length with everything after it shifted, # and by then the only symptom is a label pointing into the middle of an instruction. cosmosSource | CosmOS/Source/cosmos.asm | run | cosmosSource.in | - | disks/asm.img cosmosTokens | CosmOS/Source/cosmos.asm | run | cosmosTokens.in | - | disks/asm.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 | - | - app-Stream | CosmOS/Apps/Stream.asm | assemble | - | - app-Type | CosmOS/Apps/Type.asm | assemble | - | - app-Wander | CosmOS/Apps/Wander.asm | assemble | - | - app-Pour | CosmOS/Apps/Pour.asm | assemble | - | - app-Claim | CosmOS/Apps/Claim.asm | assemble | - | - app-More | CosmOS/Apps/More.asm | assemble | - | - app-Copy | CosmOS/Apps/Copy.asm | assemble | - | - app-Compare | CosmOS/Apps/Compare.asm | assemble | - | - # The assembler that runs on the machine, and its parts. Checked on their own so that a # failure reads as "it does not assemble" rather than as a broken disk image. asm-Asm | CosmOS/Assembler/Asm.asm | assemble | - | - asm-readTest | CosmOS/Assembler/readTest.asm | assemble | - | - asm-tokenTest | CosmOS/Assembler/tokenTest.asm | assemble | - | - asm-scratch | CosmOS/Assembler/scratch.asm | assemble | - | - # ---- Programs driven by console input ---- inputTest | Examples/inputTest.asm | run | inputTest.in | - inputTestOld | testPrograms/inputTest.asm | run | inputTest.in | - replCalculator | Examples/replCalculator.asm | run | replCalculator.in | - # ---- Programs that run forever by design, bounded by a cycle count ---- # 11,200,000 cycles is about fourteen generations of the glider, which puts evolveBoard and # its pointer juggling through its paces many times over. # # It was 3,000,000, and the number changed rather than the amount of work: a cycle used to # be an instruction and is now a memory access, and the average SplitBit instruction makes # 3.72 of those. Nothing about these two programs changed at all. 16x16Life | Examples/gameOfLife/16x16Life.asm | run | - | 11200000 # 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 | Examples/gameOfLife/16x16LifeModern.asm | run | - | 11200000 # ---- 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. # A string that spells a directive is a string. The quotes are gone by the time a token is # looked at, so "#Program" in a program's data was read as the directive: the segment # changed in the middle of the Data Segment and every label after it came out nine bytes # wrong, in a file that still had a valid header and a plausible length. stringKeyword | testPrograms/stringKeyword.asm | run | - | - # The six instructions added after the first sixty four. Four of them move a Data Pointer # by a register rather than by a byte written into the program, and two are a call that # puts nothing back. # # What is recorded is the DIFFERENCE between the two kinds of call, twice over: the same # callee sets A, and after the raw one that is what A holds while after the safe one it is # not; and each reports how far the Stack came down, which is two bytes against ten. A # version of RCAL that quietly did what CALL does would pass a test that only checked it # returned to the right place. rawCallAndOffsets | testPrograms/rawCallAndOffsets.asm | run | - | - # Falling off the end of a program into Program Memory nobody wrote. It faults on the byte # after the last instruction rather than executing a run of additions and going wrong # somewhere else, which is what 0x00 through 0x0F being empty buys. runOffTest | testPrograms/runOffTest.asm | run | - | - # WAIT, the seventy first instruction, on a disk given ten thousand cycles of latency. Two # reads with interrupts masked and no handler anywhere: the machine sleeps through both and # reads the status port when it wakes. What is recorded here is that it FINISHES - a WAIT # that never woke would hang, and a hang is what this catches. Whether it slept or spun is # a question about cycle counts, which settle() strips, so Tests/terminal.sh asks that one. waitTest | testPrograms/waitTest.asm | run | - | 5000000 | disks/sbfs.img@10000 # The other half of what WAIT is for, and the half that was missing. waitTest checks that a # masked program which SLEEPS on a device is woken and does not leave the line up; this checks # the program that never sleeps at all, because the disk finished before the first look. The # WAIT is unreachable, so nothing but the status read can take the line down. It then sets the # Interrupt Flag with no handler installed anywhere: a standing line faults there, which is # how a program loaded by CosmOS used to die on the instruction after its SIF. diskLineTest | testPrograms/diskLineTest.asm | run | - | 1000000 | disks/sbfs.img # ---- Scripts ---- # # The shell reading its lines out of a file instead of off the console. cosmosScript is the # ordinary case and also checks that comments and blank lines never reach the dispatch, and # that a script running out hands back to the console rather than ending the shell. cosmosScript | CosmOS/Source/cosmos.asm | run | cosmosScript.in | 200000000 | disks/cosmos.img # The three refusals and the stop. A line that fails stops the script - "after" must not be # in the recording - and a file with no #! is not a script however it is named. cosmosScriptBad | CosmOS/Source/cosmos.asm | run | cosmosScriptBad.in | 200000000 | disks/cosmos.img # The two that are about byte positions rather than about behaviour: a command lying across # the boundary between two blocks, and a last line with no newline after it. Both of these # were faults before they were checks. cosmosScriptEdges | CosmOS/Source/cosmos.asm | run | cosmosScriptEdges.in | 200000000 | disks/cosmos.img # One script inside another, and the limit on how far that goes. The outer script resumes in # its second block, which is the case the design turns on - the inner one reads its own block # into the single buffer, so coming back means reading the outer one's again and landing on # the byte it left. Then a script that runs itself, which stops at four deep and takes every # level with it, because a build whose helper failed should not carry on in its caller. cosmosScriptNest | CosmOS/Source/cosmos.asm | run | cosmosScriptNest.in | 200000000 | disks/cosmos.img # ---- Starting itself ---- # # /System/Boot/startup.sh runs before anybody can type. This one is also the check on #quiet # and #loud: the welcome has no prompts interleaved with it, the line after #loud does, and # the console gets its prompt back when the script ends. And on clear, whose mark on a # terminal is the escape the console has always sent. cosmosStartup | CosmOS/Source/cosmos.asm | run | cosmosStartup.in | 200000000 | disks/startup.img # Present, and not a script. A missing one is ordinary and says nothing; one somebody meant # to run and got wrong is worth a word. cosmosStartupBad | CosmOS/Source/cosmos.asm | run | cosmosStartup.in | 200000000 | disks/startupbad.img # ---- A program that takes the screen, and gives the disk back ---- # # Grid registers video memory as a bank, and bank numbers are one namespace for the whole # machine with nothing handing them out. It asked for 3, which is the one CosmOS gives the # disk's buffer at mount - and that does not fail, it SUCCEEDS: every read the filesystem # made afterwards came out of video memory. The shell found an empty disk and could not # start anything by name, and nothing said a word. # # So this runs a program by name, then Grid, then the same program again. The second one is # the check. dir at the end says the disk is still there to be read. cosmosGrid | CosmOS/Source/cosmos.asm | run | cosmosGrid.in | 60000000 | disks/cosmos.img # Which disk the registers mean. Several disks are one controller with a drive register # rather than several devices, because a port is an immediate byte inside the instruction # that names it and a program cannot compute one. Run with a single disk, so drive 1 is a # drive that exists with nothing in it - selectable, and failing to read, like an empty # floppy drive. driveSelectTest | testPrograms/driveSelectTest.asm | run | - | 200000 | disks/sbfs.img # ---- Two disks ---- # # The first thing on this machine to have more than one. drive says which, and going to the # other shows a disk with nothing in common with the first - so a listing that looked right # could not have come from the wrong one. # # THE WORKING DIRECTORY GOES WITH THE DRIVE, which is the whole point of the mount record. # Drive 1 is left standing in /notes and drive 0 at the root, and the prompt says which on # every trip between them - three times each way, because a record that is copied one way # and not the other would still look right once. A drive this machine has not got is # refused. cosmosDrives | CosmOS/Source/cosmos.asm | run | cosmosDrives.in | 60000000 | disks/cosmos.img+disks/other.img # And a drive named in the path rather than by a command. Handled where every path in the # system arrives, so it works for anything that takes one. A name beginning with a digit is # still a name: the colon is the whole of what tells the two apart. cosmosDrivePath | CosmOS/Source/cosmos.asm | run | cosmosDrivePath.in | 60000000 | disks/cosmos.img+disks/other.img # ---- Working across two disks ---- # # The two things anybody expects of a second disk: copying to it, and running a program that # lives on one disk over files that live on the other. # # THE FILE IS MORE THAN ONE BLOCK ON PURPOSE. A copy of a single block looks its source up # once and never meets the cache that skips the walk - and skipping the walk skipped the # drive, so block one of every cross-drive copy came off the destination. One block worked # and two did not. # # Say lives in /Apps on drive 0 and is run while standing on drive 1, which is the third # place the shell looks. The drive it says afterwards is the check that fetching a program # did not move the person who ran it. cosmosCrossDisk | CosmOS/Source/cosmos.asm | run | cosmosCrossDisk.in | 90000000 | disks/cosmos.img+disks/other.img # ---- A beat a program sets for itself ---- # # That reading the status is what takes the tick down, and that without the repeat bit it # runs its period out and stops. NOT that the period is the length it says: settle() strips # cycle counts from these recordings, so how long anything took cannot be checked here. # Tests/terminal.sh measures that, which is where anything about cycles belongs. timerTest | testPrograms/timerTest.asm | run | - | 5000000 | - # And interrupting, which is what a music routine wants. 125,000 cycles is a sixteenth note # at 120 beats a minute - seven and a half frames, so the screen cannot express it at all. # Eight of them is a second, and nearly all of that second is spent asleep. timerBeatTest | testPrograms/timerBeatTest.asm | run | - | 5000000 | - # ---- A disk made of memory ---- # # The machine supplies blocks and says the drive is volatile; the SYSTEM decides what that # means. CosmOS formats a volatile drive it cannot read, because a drive whose contents do # not survive the machine never had anything to lose - and leaves any other one alone, which # is why an unformatted floppy is safe from it. # # So this boots with a drive of nothing, and the first dir on it is a listing rather than an # error: the system brought it up. Then a copy onto it, to show it is a disk like any other. cosmosRamDisk | CosmOS/Source/cosmos.asm | run | cosmosRamDisk.in | 90000000 | disks/cosmos.img+ram:2048 # ---- And the other half of that rule, which is the dangerous half ---- # # The same blank disk, on a drive the machine has NOT called volatile. It must be refused # rather than formatted: an unformatted floppy is not an invitation, it is a blank floppy, # and a system that formatted one on sight is a system you could not safely put a disk into. # # blank.img has no directory in its name, so run.sh removes it before every run and the # emulator makes a fresh one of zeroes - which is exactly the disk this is about. cosmosBlankDisk | CosmOS/Source/cosmos.asm | run | cosmosBlankDisk.in | 90000000 | disks/cosmos.img+blank.img 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 | - | -