108 lines
2.7 KiB
NASM
108 lines
2.7 KiB
NASM
; 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
|