SWI osExit takes a status in A, and the shell keeps it. Fifty eight exits across twenty three programs now say deliberately whether they worked: 25 did what they were asked, 24 did not, 9 were asked wrongly. Compare is the exception and says so - one there means the files differ, which is a result rather than a failure, the way diff has always had it. IN A RATHER THAN Q, which is not a departure from the rule that a service answers in Q. This one takes an ARGUMENT, the way osPrintNumber takes A and B, and it never returns to answer anything. A is free precisely because a return would have put it back - and Q is the ALU's output, so a small number costs four instructions there against one in A. The shell does not print it. A program that failed has already said so in words and a number beside that is noise, so osLastStatus hands it back and Status is the program that shows it. That indirection is the point: the number exists for the thing that cannot read words. MARKING THE EXITS FOUND A DEFECT ON THE FIRST RUN. Type and More printed why they had failed and then fell through into the success exit, reporting that all was well. Nobody had noticed, because while the only reader was a person, the person could see both the complaint and the claim. Two smaller things. Snake sets the console to line mode and then exits with zero, and the linter flagged the second RSTA as redundant - an exit status and a console mode, equal by accident, which is the class that must never be collapsed. And the README still taught answering by writing into the frame, three months of habit that SRET replaced yesterday; that section is gone and the one describing SRET stands in its place.
246 lines
3.9 KiB
NASM
246 lines
3.9 KiB
NASM
; Writes a file one block at a time, without ever holding the whole of it.
|
|
;
|
|
; This is the write side of what Stream demonstrates for reading: a file bigger than the
|
|
; memory building it. It writes as many blocks as it is asked for, each one filled with a
|
|
; pattern that says which block it is, so that what comes off the disk afterwards can be
|
|
; checked against what should have gone on rather than merely being the right length.
|
|
;
|
|
; The argument is how many blocks, in decimal. The last one is deliberately a part block,
|
|
; because a tail is the case every off-by-one in a filesystem hides in.
|
|
;
|
|
; Written by Anachronaut
|
|
|
|
#Include services.asm
|
|
#Program
|
|
#Base 0x4000
|
|
|
|
start:
|
|
SETD.0 Argument
|
|
INIB 0d8
|
|
SWI osArgument
|
|
SETD.0 Argument
|
|
LDA.0
|
|
BRA useDefault
|
|
CALL readCount
|
|
BRI counted
|
|
useDefault:
|
|
INIA 0d4
|
|
SETD.0 Blocks
|
|
STA.0
|
|
counted:
|
|
|
|
; Nothing may be zero blocks: the tail below would then be the whole file.
|
|
SETD.0 Blocks
|
|
LDA.0
|
|
BNA haveCount
|
|
INIA 0d1
|
|
STA.0
|
|
haveCount:
|
|
|
|
; Whole blocks, and a tail of forty bytes on the end of them.
|
|
SETD.0 Name
|
|
SETD.3 0x00 0x00
|
|
SETD.0 Blocks
|
|
LDA.0
|
|
PSHA
|
|
POPB
|
|
RSTA
|
|
PSHA
|
|
PSHB
|
|
POPD.3
|
|
SETD.0 Name
|
|
INIA 0d40
|
|
SWI osFileStart
|
|
BNQ startFailed
|
|
|
|
; Each whole block, filled with its own number.
|
|
RSTA
|
|
SETD.0 Which
|
|
STA.0
|
|
nextBlock:
|
|
SETD.0 Which
|
|
LDA.0
|
|
SETD.2 Blocks
|
|
LDB.2
|
|
CCF
|
|
SUB
|
|
BRQ theTail
|
|
|
|
CALL fillBlock
|
|
SETD.1 Block
|
|
SETD.0 Which
|
|
LDA.0
|
|
RSTB
|
|
PSHA
|
|
POPB
|
|
RSTA
|
|
SWI osFileWrite
|
|
BNQ writeFailed
|
|
|
|
SETD.0 Which
|
|
LDA.0
|
|
INCA
|
|
STA.0
|
|
BRI nextBlock
|
|
|
|
theTail:
|
|
; And the part block at the end, which is the same fill cut short by the size given at
|
|
; the start. Only the first forty bytes of it will belong to the file.
|
|
CALL fillBlock
|
|
SETD.1 Block
|
|
SETD.0 Which
|
|
LDA.0
|
|
RSTB
|
|
PSHA
|
|
POPB
|
|
RSTA
|
|
SWI osFileWrite
|
|
BNQ writeFailed
|
|
|
|
; And how big it turned out to be, which here is what was asked for: this one knows its
|
|
; size from the start. Something that did not - an assembler, say - would ask for more
|
|
; than it needed and say the truth here.
|
|
RSTA
|
|
PSHA
|
|
SETD.0 Blocks
|
|
LDA.0
|
|
PSHA
|
|
POPD.3
|
|
INIA 0d40
|
|
SWI osFileDone
|
|
BNQ doneFailed
|
|
|
|
SETD.0 Wrote
|
|
SWI osPrintString
|
|
SETD.0 Blocks
|
|
LDB.0
|
|
RSTA ; A and B together are the number, so the count is the low half.
|
|
SWI osPrintNumber
|
|
SETD.0 AndTail
|
|
SWI osPrintString
|
|
RSTA
|
|
SWI osExit
|
|
|
|
; The block becomes 256 copies of the block number plus a fixed byte, so that a block
|
|
; written into the wrong place is visible rather than merely being bytes.
|
|
fillBlock:
|
|
SETD.0 Block
|
|
SETD.1 Which
|
|
LDA.1
|
|
INIB 0x41
|
|
CCF
|
|
ADD
|
|
MVQA
|
|
RSTB
|
|
fillLoop:
|
|
STA.0
|
|
INCD.0
|
|
DECB
|
|
BNB fillLoop
|
|
RET
|
|
|
|
; The argument, in decimal, into Blocks. Anything that is not a digit ends it.
|
|
readCount:
|
|
RSTA
|
|
SETD.1 Blocks
|
|
STA.1
|
|
SETD.0 Argument
|
|
countLoop:
|
|
LDA.0
|
|
BRA countDone
|
|
INIB 0x30
|
|
CCF
|
|
SUB
|
|
MVQA
|
|
INIB 0d10
|
|
CCF
|
|
SUB
|
|
BNC countDone ; Not a digit, so the number ended.
|
|
SETD.1 Blocks
|
|
LDB.1
|
|
PSHA
|
|
INIA 0d10
|
|
CALL timesTen
|
|
POPA
|
|
SETD.1 Scratch
|
|
LDB.1
|
|
CCF
|
|
ADD
|
|
MVQA
|
|
SETD.1 Blocks
|
|
STA.1
|
|
INCD.0
|
|
BRI countLoop
|
|
countDone:
|
|
RET
|
|
|
|
; B times ten into Scratch, by adding it up. Nothing here is bigger than a byte.
|
|
timesTen:
|
|
RSTA
|
|
SETD.0 Scratch
|
|
STA.0
|
|
INIA 0d10
|
|
tenLoop:
|
|
PSHA
|
|
SETD.0 Scratch
|
|
LDA.0
|
|
SETD.2 TenHold
|
|
STB.2
|
|
LDB.2
|
|
CCF
|
|
ADD
|
|
MVQA
|
|
STA.0
|
|
POPA
|
|
DECA
|
|
BNA tenLoop
|
|
RET
|
|
|
|
startFailed:
|
|
SETD.0 NoStart
|
|
SWI osPrintString
|
|
INIA 0d1
|
|
SWI osExit
|
|
writeFailed:
|
|
SETD.0 NoWrite
|
|
SWI osPrintString
|
|
INIA 0d1
|
|
SWI osExit
|
|
doneFailed:
|
|
SETD.0 NoDone
|
|
SWI osPrintString
|
|
INIA 0d1
|
|
SWI osExit
|
|
|
|
#Data
|
|
#Base 0x2000
|
|
|
|
Name:
|
|
"poured.dat"
|
|
Argument:
|
|
#Reserve 0d9
|
|
Blocks:
|
|
0x00
|
|
Which:
|
|
0x00
|
|
Scratch:
|
|
0x00
|
|
TenHold:
|
|
0x00
|
|
Block:
|
|
#Reserve 0d256
|
|
Wrote:
|
|
"poured "
|
|
AndTail:
|
|
" blocks and a tail of 40
|
|
"
|
|
NoStart:
|
|
"could not start it
|
|
"
|
|
NoWrite:
|
|
"could not write a block
|
|
"
|
|
NoDone:
|
|
"could not finish it
|
|
"
|