Infrastructure for system services through software interrupts.
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
; A software interrupt handing something back.
|
||||
;
|
||||
; RETI restores every register from the frame, which is what makes an interrupt safe to
|
||||
; arrive at an arbitrary moment: the interrupted code cannot tell it happened. A SERVICE is
|
||||
; not arbitrary - it was asked for - and the same rule means it has no way to answer.
|
||||
;
|
||||
; So a service that has something to say writes it INTO ITS OWN FRAME, over the saved
|
||||
; register, and lets RETI put it back. MVSD is what makes the frame reachable: it copies
|
||||
; the Stack Pointer into a Data Pointer, and the frame sits just above it.
|
||||
;
|
||||
; +1 Status +5 DP3 high +9 DP1 high +13 resume high
|
||||
; +2 Q +6 DP3 low +10 DP1 low +14 resume low
|
||||
; +3 A +7 DP2 high +11 DP0 high
|
||||
; +4 B +8 DP2 low +12 DP0 low
|
||||
;
|
||||
; WHICH REGISTERS A SERVICE MAY ANSWER IN is a convention rather than a rule, and it is the
|
||||
; same one CALL already has: Q and DP3. A subroutine cannot hand back A, B or DP0 to DP2
|
||||
; because RET puts them back; a service could write over any of them, and should not, for
|
||||
; exactly the reason the first list exists. A caller expects what it kept to still be there.
|
||||
;
|
||||
; ONLY THE HANDLER ITSELF CAN DO THIS. The offsets are from where the Stack Pointer is, and
|
||||
; a CALL moves it by ten. A routine called by a handler that tried this would be writing
|
||||
; into its own return address.
|
||||
;
|
||||
; Correct output is:
|
||||
; quiet: 7 a service that says nothing leaves Q as it found it
|
||||
; answer: 42 one that does, does not
|
||||
; pointer: ABC and DP3 comes back the same way
|
||||
|
||||
#Include console.asm
|
||||
|
||||
#Program
|
||||
|
||||
start:
|
||||
; Something recognisable in Q, so that a service leaving it alone is visible.
|
||||
INIA 0d7
|
||||
RSTB
|
||||
CCF
|
||||
ADD
|
||||
|
||||
SETD.0 QuietText
|
||||
CALL printString
|
||||
SWI quiet
|
||||
MVQA
|
||||
CALL printByteDecimal
|
||||
CALL newLine
|
||||
|
||||
SETD.0 AnswerText
|
||||
CALL printString
|
||||
SWI answer
|
||||
MVQA
|
||||
CALL printByteDecimal
|
||||
CALL newLine
|
||||
|
||||
SETD.0 PointerText
|
||||
CALL printString
|
||||
SWI pointer
|
||||
PSHD.3
|
||||
POPD.0
|
||||
CALL printString
|
||||
CALL newLine
|
||||
HALT
|
||||
|
||||
; Says nothing, so whatever the caller had in Q is still there afterwards.
|
||||
quiet:
|
||||
INIA 0d99
|
||||
RSTB
|
||||
CCF
|
||||
ADD ; Q is 99 in here, and nobody outside will ever know.
|
||||
RETI
|
||||
|
||||
answer:
|
||||
INIA 0d42
|
||||
MVSD.1
|
||||
DPUP.1 0d02 ; The saved Q.
|
||||
STA.1
|
||||
RETI
|
||||
|
||||
pointer:
|
||||
SETD.0 Letters
|
||||
MVSD.1
|
||||
DPUP.1 0d05 ; The saved DP3, high byte first the way everything is stored.
|
||||
PSHD.0
|
||||
POPA ; The low half comes off the Stack first.
|
||||
POPB
|
||||
STB.1
|
||||
INCD.1
|
||||
STA.1
|
||||
RETI
|
||||
|
||||
#Data
|
||||
|
||||
QuietText:
|
||||
"quiet: "
|
||||
AnswerText:
|
||||
"answer: "
|
||||
PointerText:
|
||||
"pointer: "
|
||||
Letters:
|
||||
"ABC"
|
||||
|
||||
#Vectors
|
||||
|
||||
Boot start
|
||||
quiet quiet
|
||||
answer answer
|
||||
pointer pointer
|
||||
Reference in New Issue
Block a user