A breakpoint that shows every register as the program had them, waits for a key, and carries on. NOTHING IS OVERWRITTEN, and that is the design rather than a shortcut. A breakpoint poked into a running program has to replace an instruction, and putting that instruction back in order to continue is the same act as disarming the breakpoint; firing a second time would mean stepping over the restored instruction and putting the breakpoint back behind it, and this machine cannot step a single instruction. SWI is two bytes, dispatches through a vector, and its frame already holds the address after it, so RETI resumes at the next instruction with nothing to restore and nothing to re-arm. It fires every time it is reached. The price is that a breakpoint is part of the program: a build with them in has different addresses from a build without. That is the bargain every machine with a break instruction makes. Every value shown comes out of the frame rather than the registers, because by the time the handler runs the registers are the handler's. Apps/Break.asm stops twice so that the second stop is checked as well as the first. Also here, found by the test that came with it: the monitor's s wrote into whichever bank was selected, and bank 2 is the controller's own table, published read only. Writing to it was refused, and a refusal nobody catches stops the machine - so selecting the bank table to look at it and then typing s killed the session. bankPresent now keeps the whole flags byte and s declines. The recorded output of cosmosMonitor had contained that crash, having been blessed without being read. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
57 lines
1.4 KiB
NASM
57 lines
1.4 KiB
NASM
; Stopping a program to look at it.
|
|
;
|
|
; SWI osBreak shows every register as this program had them, waits for a key, and carries
|
|
; on. It is two bytes and it fires every time it is reached.
|
|
;
|
|
; WHY IT IS AN INSTRUCTION RATHER THAN SOMETHING SET FROM OUTSIDE. A breakpoint that was
|
|
; poked into a running program would have to overwrite an instruction, and then putting that
|
|
; instruction back in order to continue is the same act as disarming the breakpoint. Firing
|
|
; a second time would mean stepping over the restored instruction and putting the breakpoint
|
|
; back behind it, and this machine cannot step one instruction. Nothing is overwritten here,
|
|
; so there is nothing to restore and nothing to re-arm.
|
|
;
|
|
; The price is that it is part of the program. A build with breakpoints in it has different
|
|
; addresses from a build without, which is the same bargain every machine makes that has a
|
|
; break instruction.
|
|
;
|
|
; Correct output is two stops, showing A and B changing between them, and the addresses of
|
|
; the two SWIs.
|
|
|
|
#Include services.asm
|
|
|
|
#Program
|
|
|
|
#Base 0x2000
|
|
|
|
start:
|
|
SETD.0 Banner
|
|
SWI osPrintString
|
|
|
|
INIA 0d17
|
|
INIB 0d34
|
|
SETD.0 Marker
|
|
SWI osBreak
|
|
|
|
; Something for the second stop to show as different.
|
|
INIA 0d68
|
|
INIB 0d85
|
|
SETD.0 Banner
|
|
SWI osBreak
|
|
|
|
SETD.0 DoneText
|
|
SWI osPrintString
|
|
SWI osExit
|
|
|
|
#Data
|
|
|
|
#Base 0x1000
|
|
|
|
Banner:
|
|
"two stops, and what the registers were at each
|
|
"
|
|
Marker:
|
|
"marker"
|
|
DoneText:
|
|
"carried on to the end
|
|
"
|