CosmOS had 1,161 bytes of Program Memory left before the address applications load at, and Tab completion is not going to fit in that with anything to spare. So the wall moves up one page: the system keeps below 0x4FFF and 0x2FFF, and an application is based at 0x5000 and 0x3000. A PAGE IS A CHEAP THING TO GIVE IT AND AN EXPENSIVE THING TO RUN OUT OF. An application still has 44K of Program Memory before the vector table and the largest one here uses 7.5K, so what was taken from applications is space nothing has ever asked for - while what the system gained is the difference between building the next thing and counting bytes while building it. Not doubling, which was the version that would have cost application space worth minding. One page, and the same again when it is needed. Nothing in the machine knows where the wall is, so this is 34 #Base lines, one threshold in the fault handler, and the table in the CosmOS README that Tests/docs.sh reads its limits out of. The native assembler's scratch map had to move with it, and docs.sh said so before anything ran: its data reached 0x40D6 and its buffers began at 0x4000, so they were sitting on its variables. That file already carries a paragraph about the floor coming up and the map staying where it was. It has happened twice now, and been caught by a check the first time wrote. Twenty three recordings are the same runs a page higher. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
105 lines
2.9 KiB
NASM
105 lines
2.9 KiB
NASM
; A loaded program that is interrupted by the console rather than asking it for anything.
|
|
;
|
|
; Until the loadable program format could carry vectors, this could not be written. A
|
|
; handler has to be an address in the vector table, and a program that is not the one the
|
|
; machine booted from had no way to say what its vectors were, so interrupts belonged to
|
|
; boot images and every loaded program had to poll. Snake polls for exactly that reason.
|
|
;
|
|
; What this shows is the whole path: the assembler writes the vectors into the file, the
|
|
; system installs them when the program is run, the console raises its line, the handler
|
|
; runs, and the system takes the vectors back out again when the program gives the machine
|
|
; back. Nothing in the waiting loop below looks at the console at all.
|
|
;
|
|
; The vector is named by port, because a device interrupts on the port it is plugged into
|
|
; and the console is on port 0x00.
|
|
|
|
#Include services.asm
|
|
|
|
#Program
|
|
|
|
#Base 0x5000
|
|
|
|
start:
|
|
CIF ; Nothing arrives until there is something to catch it.
|
|
|
|
; Set rather than trusted to be zero. Running a program a second time does not load it
|
|
; again, so its Data Segment is exactly as the last run left it - and the last thing the
|
|
; last run did was set this.
|
|
RSTA
|
|
SETD.0 Stopping
|
|
STA.0
|
|
|
|
SETD.0 Banner
|
|
CALL printString
|
|
CALL newLine
|
|
|
|
; Key mode and interrupt on input, in one write, since the two control bits are
|
|
; independent of each other.
|
|
INIA 0x03
|
|
OUTA 0x02
|
|
SIF
|
|
|
|
; Called spin rather than wait because WAIT is an instruction now, and a label may not
|
|
; be one. Which is the joke of it: this loop is exactly what WAIT exists to replace.
|
|
spin:
|
|
; This loop is the point. It never touches the console, so every character that appears
|
|
; below was put there by something that interrupted it.
|
|
SETD.3 Stopping
|
|
LDA.3
|
|
RSTB
|
|
OR
|
|
BRQ spin
|
|
|
|
CALL newLine
|
|
RSTA
|
|
OUTA 0x02 ; Line mode and no interrupts, the way it was found.
|
|
SETD.0 DoneText
|
|
CALL printString
|
|
CALL newLine
|
|
RSTA
|
|
SWI osExit
|
|
|
|
; Entered because the console had something to say. Never called.
|
|
keyHandler:
|
|
INA 0x01
|
|
INIB 0x01 ; READY: is there a byte, as opposed to the end of input?
|
|
AND
|
|
BRQ keyNoByte
|
|
INA 0x00
|
|
|
|
INIB 0x71 ; q, which is how this program is stopped.
|
|
XOR
|
|
BRQ keyStop
|
|
|
|
OUTA 0x00 ; Nothing echoes in key mode, so the handler does it.
|
|
RETI
|
|
|
|
keyNoByte:
|
|
; The end of input raises the line once as well, so a program driven entirely by
|
|
; interrupts is told when nothing more is coming instead of waiting for ever.
|
|
keyStop:
|
|
SETD.3 Stopping
|
|
INIA 0x01
|
|
STA.3
|
|
RETI
|
|
|
|
#Data
|
|
|
|
#Base 0x3000
|
|
|
|
Banner:
|
|
"keys, by interrupt. q stops."
|
|
DoneText:
|
|
"the console has been handed back"
|
|
|
|
; The only thing the handler and the loop it interrupts have to say to each other.
|
|
Stopping:
|
|
0x00
|
|
|
|
#Vectors
|
|
|
|
Boot start
|
|
Device 0x00 keyHandler
|
|
|
|
#Include console.asm
|