Give Programs/ one rule: a directory per kind, nothing loose
Five .asm files sat at the top of Programs/ beside six directories, with
nothing to say which a new file should join - and hello.asm, which is the
native assembler's first target and named in sixteen places, looked like a
stray.
Programs/
Examples/ what you read to learn: hello, printHello, inputTest,
replCalculator, and Fibonacci, primeSieve and gameOfLife
as sets of their own
Libraries/ included by name, no entry point of their own
Loader/ loader.asm, and the loadable program it reads
CosmOS/ the system, its applications and its assembler
testPrograms/ what 'make test' drives
Loader/ is the one worth explaining. loader.asm is not a demonstration: it
reads a program off a disk, puts the two pieces where the header asks, and
jumps to the entry. CosmOS grew out of it and does the same thing as one of
its commands. It is kept because backward compatibility with the simplest
version of the system is a standing goal, and it was sitting loose next to
the demos as though it were one.
Programs/loadable/ was a directory holding one file called hello.asm - a
third thing of that name, and the name said nothing about why it was there.
It is Loader/loadable.asm now, beside the loader that reads it.
Every reference moved with them: the makefile's program list, twelve
manifest lines, makedisks.sh, native.sh, and four paths across the README
and both manuals. Verified by deleting both build directories and running
the whole suite from nothing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
6dbb38b209
commit
ccf4b384e1
@@ -0,0 +1,33 @@
|
||||
; A program meant to be loaded off a disk rather than booted from.
|
||||
;
|
||||
; It is assembled for where it will live. Giving each segment a base says where it goes,
|
||||
; so the labels inside are already right for the place the loader will put it, and the
|
||||
; assembler writes it out as a loadable program rather than as a boot image. Nothing
|
||||
; relocates anything: this works because the addresses here and the addresses in its
|
||||
; header say the same thing.
|
||||
;
|
||||
; The loader keeps below both of these, which is the whole of the arrangement.
|
||||
|
||||
#Program
|
||||
|
||||
#Base 0x2000 ; This program's code lives from 0x2000.
|
||||
|
||||
hello:
|
||||
SETD.0 HelloText
|
||||
helloLoop:
|
||||
LDA.0
|
||||
BRA helloDone
|
||||
OUTA 0x00
|
||||
INCD.0
|
||||
BRI helloLoop
|
||||
helloDone:
|
||||
INIA 0x0A
|
||||
OUTA 0x00
|
||||
HALT
|
||||
|
||||
#Data
|
||||
|
||||
#Base 0x1000 ; And its data from 0x1000.
|
||||
|
||||
HelloText:
|
||||
"loaded off a disk, with a string and a loop of its own"
|
||||
@@ -0,0 +1,184 @@
|
||||
; Loads a program off a disk and runs it.
|
||||
;
|
||||
; Everything this needs already existed: the filesystem reads the file, the controller
|
||||
; writes Program Memory, and BRD jumps to an address worked out at run time. The only new
|
||||
; part is the sixteen bytes on the front of a loadable program that say where it goes.
|
||||
;
|
||||
; Nothing relocates anything. The program is put exactly where its header asks, and that
|
||||
; has to be where it was assembled for, or every branch inside it points somewhere wrong.
|
||||
; This loader therefore keeps out of the way: its own code and data sit above the
|
||||
; addresses the loaded program claims, which is an arrangement rather than a mechanism.
|
||||
;
|
||||
; Correct output is:
|
||||
; loader
|
||||
; loaded off a disk, with a string and a loop of its own
|
||||
|
||||
#Include print.asm
|
||||
#Include sbfs.asm
|
||||
|
||||
#Program
|
||||
|
||||
; print.asm branches here at the top of the Program Segment, so this is where the machine
|
||||
; arrives whether or not the Boot Vector is obeyed. Naming it in the Vector Segment as
|
||||
; well says plainly where the program begins.
|
||||
start:
|
||||
SETD.0 LoaderName
|
||||
CALL printString
|
||||
CALL lineFeed
|
||||
|
||||
CALL sbfsMount
|
||||
BNQ loaderNoDisk
|
||||
|
||||
SETD.0 ProgramName
|
||||
CALL sbfsFind
|
||||
BNQ loaderMissing
|
||||
|
||||
SETD.1 Staging
|
||||
CALL sbfsRead
|
||||
BNQ loaderUnreadable
|
||||
|
||||
; "SBEX", or it is not a program at all. Loading a text file would otherwise put
|
||||
; nonsense into Program Memory and jump into it.
|
||||
SETD.0 Staging
|
||||
SETD.2 ExecMagic
|
||||
INIA 0d4
|
||||
SETD.1 LoaderCount
|
||||
STA.1
|
||||
loaderMagicLoop:
|
||||
LDA.0
|
||||
LDB.2
|
||||
XOR
|
||||
BNQ loaderNotProgram
|
||||
INCD.0
|
||||
INCD.2
|
||||
LDA.1
|
||||
DECA
|
||||
STA.1
|
||||
BNA loaderMagicLoop
|
||||
|
||||
SETD.0 Staging
|
||||
DPUP.0 0d04
|
||||
LDA.0
|
||||
INIB 0d1
|
||||
XOR
|
||||
BNQ loaderWrongVersion
|
||||
|
||||
; The code first. Source is the bytes just past the header; destination is wherever the
|
||||
; header says the code lives.
|
||||
INIA 0d1
|
||||
OUTA 0xE0 ; SourceBank: Data Memory, where the file was read to.
|
||||
SETD.0 Staging
|
||||
DPUP.0 0d16
|
||||
PSHD.0
|
||||
POPA
|
||||
POPB
|
||||
OUTB 0xE1
|
||||
OUTA 0xE2
|
||||
|
||||
RSTA
|
||||
OUTA 0xE3 ; DestBank: Program Memory.
|
||||
; Where the code goes. Read and written out a byte at a time rather than through a
|
||||
; subroutine, because a subroutine could not hand the two bytes back: CALL preserves
|
||||
; A and B along with the first three Data Pointers, so anything a routine puts in them
|
||||
; is undone by its own return.
|
||||
SETD.0 Staging
|
||||
DPUP.0 0d06
|
||||
LDA.0
|
||||
OUTA 0xE4
|
||||
INCD.0
|
||||
LDA.0
|
||||
OUTA 0xE5
|
||||
|
||||
; How much of it there is.
|
||||
SETD.0 Staging
|
||||
DPUP.0 0d10
|
||||
LDA.0
|
||||
OUTA 0xE6
|
||||
INCD.0
|
||||
LDA.0
|
||||
OUTA 0xE7
|
||||
|
||||
INIA 0x01
|
||||
OUTA 0xE8 ; Blit.
|
||||
|
||||
; Then the data. A blit leaves its addresses past whatever it touched, so the source is
|
||||
; already sitting on the first byte of the data and only the destination changes.
|
||||
INIA 0d1
|
||||
OUTA 0xE3 ; DestBank: Data Memory.
|
||||
SETD.0 Staging
|
||||
DPUP.0 0d12
|
||||
LDA.0
|
||||
OUTA 0xE4
|
||||
INCD.0
|
||||
LDA.0
|
||||
OUTA 0xE5
|
||||
|
||||
SETD.0 Staging
|
||||
DPUP.0 0d14
|
||||
LDA.0
|
||||
OUTA 0xE6
|
||||
INCD.0
|
||||
LDA.0
|
||||
OUTA 0xE7
|
||||
|
||||
INIA 0x01
|
||||
OUTA 0xE8 ; Blit.
|
||||
|
||||
; And go. The entry address is a number until BRD makes it a place. DP3 is built from
|
||||
; the two bytes by hand, since it is the pointer nothing puts back.
|
||||
SETD.0 Staging
|
||||
DPUP.0 0d08
|
||||
LDA.0
|
||||
INCD.0
|
||||
LDB.0
|
||||
PSHA
|
||||
PSHB
|
||||
POPD.3
|
||||
BRD.3
|
||||
|
||||
loaderNoDisk:
|
||||
SETD.0 NoDisk
|
||||
BRI loaderComplain
|
||||
loaderMissing:
|
||||
SETD.0 NotThere
|
||||
BRI loaderComplain
|
||||
loaderUnreadable:
|
||||
SETD.0 Unreadable
|
||||
BRI loaderComplain
|
||||
loaderNotProgram:
|
||||
SETD.0 NotProgram
|
||||
BRI loaderComplain
|
||||
loaderWrongVersion:
|
||||
SETD.0 WrongVersion
|
||||
loaderComplain:
|
||||
CALL printString
|
||||
CALL lineFeed
|
||||
HALT
|
||||
|
||||
#Data
|
||||
|
||||
ExecMagic:
|
||||
"SBEX"
|
||||
LoaderName:
|
||||
"loader"
|
||||
ProgramName:
|
||||
"hello.sbx"
|
||||
NoDisk:
|
||||
"no disk"
|
||||
NotThere:
|
||||
"no such program"
|
||||
Unreadable:
|
||||
"could not read it"
|
||||
NotProgram:
|
||||
"not a program"
|
||||
WrongVersion:
|
||||
"a version I do not know"
|
||||
LoaderCount:
|
||||
0x00
|
||||
|
||||
Staging:
|
||||
#Reserve 0d512
|
||||
|
||||
#Vectors
|
||||
|
||||
Boot start
|
||||
Reference in New Issue
Block a user