chiark / gitweb /
Initial revision
[ssr] / StraySrc / Hammer / s / driver
1 ;
2 ; driver.s
3 ;
4 ; The text-only interface to Sledgehammer (TMA)
5 ;
6 ; © 1994-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's Sledgehammer debugger.
12 ;
13 ; Sledgehammer is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
16 ; any later version.
17 ;
18 ; Sledgehammer is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 ; GNU General Public License for more details.
22 ;
23 ; You should have received a copy of the GNU General Public License
24 ; along with Sledgehammer.  If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27 ;----- Standard header ------------------------------------------------------
28
29                 GET     libs:header
30                 GET     libs:swis
31
32                 GET     libs:stream
33
34 ;----- External dependencies ------------------------------------------------
35
36                 GET     quartz:string
37
38                 GET     sh.brkpt
39                 GET     sh.armEmul
40                 GET     sh.asm
41                 GET     sh.diss
42                 GET     sh.hammer
43
44 ;----- Main code ------------------------------------------------------------
45
46                 AREA    |Hammer$$Code|,CODE,READONLY
47
48 ; --- driver ---
49 ;
50 ; On entry:     R0 == pointer to a register block
51 ;
52 ; On exit:      Doesn't
53 ;
54 ; Use:          Text only interactive debugger interface
55
56                 EXPORT driver
57 driver          ROUT
58
59                 BL      hammer_getStack         ;Get our own pretty stack
60                 MOV     R3,R0                   ;Preserve block pointer
61                 MOV     R10,R13                 ;Remember stack base address
62                 MOV     R14,PC                  ;Get PC with flags
63                 TST     R14,#3                  ;Are we in user mode?
64                 LDRNE   R13,[R3,#13*4]          ;No -- use his stack pointer
65
66 driver__next    LDR     R0,[R3,#15*4]           ;Get the 'PC'
67                 BIC     R0,R0,#&FC000003        ;Clear flags
68                 BL      diss_address            ;Set this as the diss address
69                 BL      brkpt_translate         ;Translate the address
70                 LDR     R0,[R0,#0]              ;Load the instruction
71                 BL      diss_disassemble        ;Disassemble the instruction
72                 SWI     XOS_NewLine             ;Print a newline
73                 SWI     XOS_Write0              ;Print it out nicely
74                 SWI     XOS_NewLine             ;Print a newline
75
76 10driver        SWI     XOS_WriteS              ;Print out the following
77                 DCB     10,"Sledgehammer [stwx rad bke nzcv *oh]",0
78
79                 MOV     R0,#229                 ;Set escape action
80                 MOV     R1,#1                   ;Just generate key code
81                 MOV     R2,#0                   ;Set the state
82                 SWI     XOS_Byte                ;Do it
83
84 15driver        SWI     XOS_ReadC               ;Read a character
85                 CMP     R0,#27                  ;Was it escape?
86                 MOVEQ   R0,#'t'                 ;Yes -- make it continue
87                 CMP     R0,#32                  ;How about space
88                 MOVEQ   R0,#'s'                 ;Yeap -- make it step
89                 ORR     R0,R0,#&20              ;Make it lower case
90                 ADR     R2,driver__table        ;Point to the table
91 20driver        LDR     R4,[R2],#8              ;Load the byte
92                 CMP     R4,#0                   ;Was there one?
93                 BEQ     %15driver               ;Nope -- keep trying
94                 CMP     R4,R0                   ;Was this what he typed?
95                 BNE     %20driver               ;No -- keep on trying
96                 SWI     XOS_WriteI+32           ;Print a space
97                 SWI     XOS_WriteC              ;Print out the character
98                 SWI     XOS_NewLine             ;Let's be pretty about this
99                 SWI     XOS_NewLine
100                 SUB     PC,R2,#4                ;Do the instruction
101
102 driver__table   DCD     's'
103                 B       driver__step
104                 DCD     't'
105                 B       driver__cont
106                 DCD     'w'
107                 B       driver__soft
108                 DCD     'x'
109                 SWI     OS_BreakPt
110                 DCD     'r'
111                 B       driver__regDump
112                 DCD     'a'
113                 B       driver__next;driver__alter
114                 DCD     'd'
115                 B       driver__diss
116                 DCD     'b'
117                 B       driver__break
118                 DCD     'k'
119                 B       driver__killBrk
120                 DCD     'e'
121                 B       driver__killAll
122                 DCD     'n'
123                 B       driver__toggleN
124                 DCD     'z'
125                 B       driver__toggleZ
126                 DCD     'c'
127                 B       driver__toggleC
128                 DCD     'v'
129                 B       driver__toggleV
130                 DCD     '*'
131                 B       driver__oscli
132                 DCD     'o'
133                 B       driver__next;driver__options
134                 DCD     'h'
135                 B       driver__help
136                 DCD     0
137
138                 ; --- Single Step ---
139
140 driver__step    MOV     R0,#229                 ;Set escape action
141                 MOV     R2,#0                   ;Set the state to what it was
142                 SWI     XOS_Byte                ;Do it
143
144                 MOV     R13,R10                 ;Use our private stack
145                 MOV     R0,R3                   ;Point to register block
146                 BL      armEmul                 ;Emulate an instruction
147                 MOV     R14,PC                  ;Get PC with flags
148                 TST     R14,#3                  ;Are we in user mode?
149                 LDRNE   R13,[R3,#13*4]          ;No -- use his stack pointer
150                 B       driver__next            ;Do the next one
151
152                 ; --- Continue ---
153
154 driver__cont    MOV     R0,#229                 ;Set escape action
155                 MOV     R2,#0                   ;Set the state to what it was
156                 SWI     XOS_Byte                ;Do it
157
158                 LDR     R0,[R3,#15*4]           ;Get the current PC
159                 BIC     R0,R0,#&FC000003        ;Get rid of flags
160                 BL      brkpt_exist             ;Is there a breakpoint here?
161                 LDMCCIA R3,{R0-PC}^             ;No -- continue his execution
162
163                 MOV     R13,R10                 ;Use our private stack
164                 MOV     R0,R3                   ;Point to register block
165                 BL      armEmul                 ;Emulate an instruction
166                 LDMIA   R3,{R0-PC}^             ;Continue pleasently
167
168                 ; --- Soft emulation ---
169
170 driver__soft    ROUT
171
172                 MOV     R0,#229                 ;Set escape action
173                 MOV     R2,#0                   ;Set the state to what it was
174                 SWI     XOS_Byte                ;Do it
175
176                 MOV     R13,R10                 ;Yes -- Use our private stack
177 00driver__soft  MOV     R0,R3                   ;...point to register block
178                 BL      armEmul                 ;...emulate an instruction
179                 LDR     R0,[R3,#15*4]           ;Get the current PC
180                 BIC     R0,R0,#&FC000003        ;Get rid of flags
181                 BL      brkpt_exist             ;Is there a breakpoint here?
182                 BCC     %00driver__soft         ;No -- keep looping
183                 MOV     R14,PC                  ;Get PC with flags
184                 TST     R14,#3                  ;Are we in user mode?
185                 LDRNE   R13,[R3,#13*4]          ;No -- use his stack pointer
186                 B       driver__next            ;And tell user about it
187
188                 LTORG
189
190                 ; --- Help display ---
191
192 driver__help    ADR     R0,driver__helpText     ;Point to my help text
193                 SWI     XOS_PrettyPrint         ;Display it on the screen
194                 B       driver__next            ;Rejoin the main loop
195
196 driver__helpText
197                 DCB     "Commands available:",13
198                 DCB     13
199                 DCB     "[S]ingle step (also SPACE)",13
200                 DCB     "con[T]inue (also ESCAPE)",13
201                 DCB     "[W]hisper mode",13
202                 DCB     "e[X]it application",13
203                 DCB     "[R]egister list",13
204                 DCB     "[A]lter register value",13
205                 DCB     "[D]isassemble around current PC",13
206                 DCB     "[B]reakpoint set",13
207                 DCB     "[K]ill breakpoint",13
208                 DCB     "toggle [N,Z,C,V] flag",13
209                 DCB     "[E]xterminate all breakpoints",13
210                 DCB     "[*] commands",13
211                 DCB     "[O]ptions",13
212                 DCB     "[H]elp",13
213                 DCB     0
214
215                 ; --- Set a breakpoint ---
216
217 driver__break   BL      driver__readAddr        ;Read the address he typed
218                 BVS     driver__error           ;If he spasmed, return
219                 BLCS    brkpt_set               ;Try to set the breakpoint
220                 BVS     driver__error           ;If he spasmed, return
221                 B       driver__next            ;And rejoin the main loop
222
223                 ; --- Remove a breakpoint ---
224
225 driver__killBrk BL      driver__readAddr        ;Read the address he typed
226                 BVS     driver__error           ;If he spasmed, return
227                 BLCS    brkpt_remove            ;Try to set the breakpoint
228                 BVS     driver__error           ;If he spasmed, return
229                 B       driver__next            ;And rejoin the main loop
230
231                 ; --- Remove all breakpoints ---
232
233 driver__killAll ADR     R0,driver__kaMsg        ;Point to message string
234                 BL      hammer_confirm          ;Get confirmation on this
235                 BLCS    brkpt_remAll            ;If OK, remove all of them
236                 B       driver__next            ;And rejoin the main loop
237
238 driver__kaMsg   DCB     "Remove all breakpoints?",0
239
240 driver__error   ADD     R0,R0,#4                ;Point to the error
241                 SWI     XOS_Write0              ;Display the message
242                 SWI     XOS_NewLine             ;Move to new line
243                 B       driver__next            ;And rejoin the main loop
244
245                 ; --- * commands ---
246
247 driver__oscli   ROUT
248
249                 STMFD   R13!,{R0-R5}            ;Save some registers
250                 BL      str_buffer              ;Get me a nice buffer
251                 MOV     R5,R1                   ;Look after the buffer
252
253 00driver__oscli SWI     XOS_WriteS              ;Write a prompt string
254                 DCB     "Sledgehammer *",0
255                 MOV     R0,R5                   ;Point to it nicely
256                 MOV     R1,#256                 ;Give the buffer size
257                 MOV     R2,#32                  ;Allow all printable chars
258                 MOV     R3,#255
259                 SWI     XOS_ReadLine            ;Read a command line
260                 BVS     %10driver__oscli        ;Failed -- report error
261                 LDRB    R1,[R5,#0]              ;Load the first character
262                 CMP     R1,#13                  ;Is the string empty?
263                 BEQ     %20driver__oscli        ;Yes -- return then
264                 MOV     R0,R5                   ;Point to the buffer
265                 SWI     XOS_CLI                 ;Do the command nicely
266                 BVS     %10driver__oscli        ;Failed -- report error
267                 B       %00driver__oscli        ;Go round for some more
268
269 10driver__oscli ADD     R0,R0,#4                ;Point to error message
270                 SWI     XOS_Write0              ;Display it
271                 B       %00driver__oscli        ;Go round for some more
272
273 20driver__oscli LDMFD   R13!,{R0-R5}            ;Unstack registers
274                 B       driver__next            ;And rejoin the main loop
275
276                 ; --- Toggle flags ---
277
278 driver__toggleN MOV     R4,#N_flag              ;Get the flag bit
279                 MOV     R5,#'N'                 ;And the name
280                 B       driver__toggle          ;Do the toggle op
281
282 driver__toggleZ MOV     R4,#Z_flag              ;Get the flag bit
283                 MOV     R5,#'Z'                 ;And the name
284                 B       driver__toggle          ;Do the toggle op
285
286 driver__toggleC MOV     R4,#C_flag              ;Get the flag bit
287                 MOV     R5,#'C'                 ;And the name
288                 B       driver__toggle          ;Do the toggle op
289
290 driver__toggleV MOV     R4,#V_flag              ;Get the flag bit
291                 MOV     R5,#'V'                 ;And the name
292                 B       driver__toggle          ;Do the toggle op
293
294 driver__toggle  LDR     R14,[R3,#15*4]          ;Load current flags
295                 EOR     R14,R14,R4              ;Toggle the flag
296                 STR     R14,[R3,#15*4]          ;Save them back again
297                 TST     R14,R4                  ;Is it on or off now?
298                 MOV     R0,R5                   ;Get the flag's name
299                 SWI     XOS_WriteC              ;Display it
300                 SWI     XOS_WriteS              ;Display some text
301                 DCB     " flag now ",0
302                 ADREQ   R0,driver__flagOff      ;Point to the right string
303                 ADRNE   R0,driver__flagOn       ;Whichever one that is
304                 SWI     XOS_Write0              ;And display it
305                 SWI     XOS_NewLine             ;Follow with a newline
306                 B       driver__next            ;And rejoin main loop
307
308 driver__flagOff DCB     "off.",0
309 driver__flagOn  DCB     "on.",0
310
311                 ; --- Disassemble context ---
312
313 driver__diss    ROUT
314
315                 LDR     R4,[R3,#15*4]           ;Load current program count
316                 BIC     R4,R4,#&FC000003        ;Clear PSR flags
317
318                 BL      driver__readAddr        ;Get an address to display
319                 BVS     driver__error           ;If he goofed, report error
320                 MOVCC   R0,R4                   ;If none, use the PC
321
322                 SUB     R5,R0,#40               ;Do 10 instrs each side
323                 MOV     R6,#21                  ;That's 21 instructions total
324
325                 MOV     R0,R5                   ;Get the disassembly base
326                 BL      diss_address            ;Set disassembly up nicely
327
328 00driver__diss  MOV     R0,R5                   ;Get the disassembly address
329                 BL      brkpt_exist             ;Is there a breakpoint there?
330                 SWICS   XOS_WriteI+"*"          ;Yes -- put a splodge there
331                 SWICC   XOS_WriteI+" "          ;Otherwise leave a gap
332                 CMP     R0,R4                   ;Is this the current one?
333                 SWIEQ   XOS_WriteI+">"          ;Yes -- mark it somehow
334                 SWINE   XOS_WriteI+" "          ;Otherwise leave a space
335                 SWI     XOS_WriteI+" "          ;Gap before disassembly
336
337                 BL      brkpt_translate         ;Translate the address
338                 LDR     R0,[R0,#0]              ;Load the instruction
339                 BL      diss_disassemble        ;Disassemble it
340                 SWI     XOS_Write0              ;Display the result
341                 SWI     XOS_NewLine             ;And move down a line
342
343                 SUBS    R6,R6,#1                ;Decrement the counter
344                 ADDGE   R5,R5,#4                ;If more to go, bump address
345                 BGE     %00driver__diss         ;And go round again
346
347                 B       driver__next            ;Rejoin the main loop
348
349                 LTORG
350
351                 ; --- Register dump ---
352
353 driver__regDump ROUT
354
355                 STMFD   R13!,{R0-R12}           ;Save some registers
356                 MOV     R0,#229                 ;Set escape action
357                 MOV     R2,#0                   ;Set the state to what it was
358                 SWI     XOS_Byte                ;Do it
359
360                 ; --- Start the main display loop ---
361
362                 MOV     R12,R3                  ;Keep pointer to dump block
363                 ADR     R11,driver__regNames    ;Point to register name tbl
364                 MOV     R10,#0                  ;Which register we're on
365
366                 ; --- Display a register ---
367
368 00              ADD     R0,R11,R10,LSL #2       ;Point to the string
369                 SWI     OS_Write0               ;Display register name
370                 SWI     OS_WriteS               ;Display immediate string
371                 DCB     " == &",0               ;A separater string
372                 LDR     R0,[R12,R10,LSL #2]     ;Load the register value
373                 BL      driver__writeHex        ;Display register value
374                 SWI     OS_WriteS               ;Display more immediate
375                 DCB     "   ",0                 ;Just some spaces
376                 ADD     R10,R10,#1              ;Increment register count
377                 TST     R10,#3                  ;Now a multiple of 4?
378                 SWIEQ   OS_NewLine              ;Yes -- new line then
379                 CMP     R10,#16                 ;Finished all registers?
380                 BLT     %00driver__regDump      ;No -- do some more then
381
382                 ; --- Now display R14 and R15 with PSR bits testually ---
383
384                 SWI     OS_NewLine              ;Another newline
385                 SWI     OS_WriteS               ;Display immediate stuff
386                 DCB     "R14 == &",0
387                 LDR     R9,[R12,#14*4]          ;Load the R14 value
388                 BL      driver__psr             ;Display all the PSR bits
389                 SWI     OS_NewLine              ;Another newline
390                 SWI     OS_WriteS               ;Display immediate stuff
391                 DCB     " PC == &",0
392                 LDR     R9,[R12,#15*4]          ;Load the PC value
393                 BL      driver__psr             ;Display all the PSR bits
394                 SWI     OS_NewLine              ;Another newline
395                 SWI     OS_NewLine              ;And one more for luck
396                 LDMFD   R13!,{R0-R12}           ;Get register back
397                 B       driver__next            ;Get the next command
398
399                 LTORG
400
401 driver__regNames
402                 DCB     " R0",0
403                 DCB     " R1",0
404                 DCB     " R2",0
405                 DCB     " R3",0
406                 DCB     " R4",0
407                 DCB     " R5",0
408                 DCB     " R6",0
409                 DCB     " R7",0
410                 DCB     " R8",0
411                 DCB     " R9",0
412                 DCB     "R10",0
413                 DCB     "R11",0
414                 DCB     "R12",0
415                 DCB     "R13",0
416                 DCB     "R14",0
417                 DCB     " PC",0
418
419 ; --- driver__psr ---
420 ;
421 ; On entry:     R9 == value to display
422 ;
423 ; On exit:      R0-R12 corrupted, maybe
424 ;
425 ; Use:          Displays R9 with PSR bits stripped away, and then with
426 ;               all the PSR bits described too.
427
428 driver__psr     ROUT
429
430                 STMFD   R13!,{R14}              ;Save the link register
431                 BIC     R0,R9,#&FC000003        ;Get the PC bits only
432                 BL      driver__writeHex        ;Display them in hex
433
434                 SWI     OS_WriteS               ;Some more spaces
435                 DCB     ", flags == ",0
436                 MOV     R0,#'N'                 ;First do the `N' flag
437                 TST     R9,#N_flag              ;Is it set
438                 ORREQ   R0,R0,#&20              ;No -- force to lower case
439                 SWI     OS_WriteC               ;Display the character
440                 MOV     R0,#'Z'                 ;First do the `N' flag
441                 TST     R9,#Z_flag              ;Is it set
442                 ORREQ   R0,R0,#&20              ;No -- force to lower case
443                 SWI     OS_WriteC               ;Display the character
444                 MOV     R0,#'C'                 ;First do the `N' flag
445                 TST     R9,#C_flag              ;Is it set
446                 ORREQ   R0,R0,#&20              ;No -- force to lower case
447                 SWI     OS_WriteC               ;Display the character
448                 MOV     R0,#'V'                 ;First do the `N' flag
449                 TST     R9,#V_flag              ;Is it set
450                 ORREQ   R0,R0,#&20              ;No -- force to lower case
451                 SWI     OS_WriteC               ;Display the character
452
453                 SWI     OS_WriteS               ;Yet more stuff
454                 DCB     ", mode == ",0
455                 ADR     R0,driver__modes        ;Point to the mode strings
456                 AND     R14,R9,#3               ;Get the mode bits
457                 ADD     R0,R0,R14,LSL #2        ;Point to the correct string
458                 SWI     OS_Write0               ;Display the mode setting
459
460                 TST     R9,#IRQ_disable         ;Is the IRQ bit on or off?
461                 ADREQ   R0,driver__irqOn        ;If off, point to message
462                 SWIEQ   OS_Write0               ;And display the string
463                 TST     R9,#FIQ_disable         ;Is the FIQ bit on or off?
464                 ADREQ   R0,driver__fiqOn        ;If off, point to message
465                 SWIEQ   OS_Write0               ;And display the string
466                 LDMFD   R13!,{PC}^              ;Return to caller
467
468                 LTORG
469
470 driver__modes   DCB     "USR",0
471                 DCB     "FIQ",0
472                 DCB     "IRQ",0
473                 DCB     "SVC",0
474
475 driver__irqOn   DCB     ", IRQ",0
476 driver__fiqOn   DCB     ", FIQ",0
477
478 driver__writeHex ROUT
479
480                 STMFD   R13!,{R0-R2,R14}
481                 SUB     R13,R13,#16
482                 MOV     R1,R13
483                 MOV     R2,#16
484                 SWI     OS_ConvertHex8
485                 SWI     OS_Write0
486                 ADD     R13,R13,#16
487                 LDMFD   R13!,{R0-R2,PC}^
488
489                 LTORG
490
491 ; --- driver__readAddr ---
492 ;
493 ; On entry:     --
494 ;
495 ; On exit:      Error, or CC for no entry, or R0 == address
496 ;
497 ; Use:          Interprets an address as typed by the user.
498
499 driver__readAddr ROUT
500
501                 BIC     R14,R14,#V_flag         ;Assume all is well
502                 STMFD   R13!,{R1-R5,R8,R14}     ;Save some registers
503                 SWI     XOS_WriteS              ;Display the prompt
504                 DCB     "([<reg>] [+|- <offset>]) | <address> :",0
505                 SUB     R13,R13,#20             ;Make a small buffer
506                 MOV     R5,R3                   ;Look after register block
507                 MOV     R0,R13                  ;Point to my buffer
508                 MOV     R1,#20                  ;Give it the buffer size
509                 MOV     R2,#32                  ;Minimum value to allow
510                 MOV     R3,#255                 ;Allow all printable chars
511                 SWI     XOS_ReadLine            ;Read the line then
512                 BVS     %90driver__readAddr     ;If he messed up, report err
513                 MOV     R3,R5                   ;Restore register block ptr
514
515                 MOV     R8,R13                  ;Point to the string
516                 MOV     R5,#0                   ;Initial address offset
517                 MOV     R4,#0                   ;Clear some flags
518                 BL      asm_register            ;Try to read a register name
519                 LDRVC   R5,[R3,R0,LSL #2]       ;If OK get register value
520                 BICVC   R5,R5,#&FC000003        ;And clear possible PSR flags
521                 ORRVC   R4,R4,#3                ;We have reg/We read sthing
522
523 00              LDRB    R14,[R8],#1             ;Load a byte from the string
524                 CMP     R14,#' '                ;Is it a space
525                 BEQ     %00driver__readAddr     ;Yes -- go for another
526
527                 CMP     R14,#32                 ;Is this the string end?
528                 BLO     %10driver__readAddr     ;Yes -- weird things happened
529                 CMP     R14,#'-'                ;Is it a '-'?
530                 ORREQ   R4,R4,#4                ;Yes -- subtract offset then
531                 CMPNE   R14,#'+'                ;Or a '+'?
532                 ORREQ   R4,R4,#1                ;This is something typed
533                 BNE     %05driver__readAddr     ;No -- skip
534
535                 TST     R4,#2                   ;Do we have a base reg?
536                 LDREQ   R5,[R3,#15*4]           ;No -- use the PC then
537                 BICEQ   R5,R5,#&FC000003        ;And clear possible PSR flags
538
539                 MOV     R1,R8                   ;Point to the string
540                 MOV     R0,#10                  ;Expect a decimal number
541                 SWI     XOS_ReadUnsigned        ;Try to understand the value
542                 BVS     %90driver__readAddr     ;If failed, report error
543                 TST     R4,#4                   ;Was it a subtract?
544                 SUBNE   R5,R5,R2                ;Yes -- subtract offset
545                 ADDEQ   R5,R5,R2                ;Otherwise add it
546                 B       %10driver__readAddr     ;And branch ahead
547
548 05              TST     R4,#2                   ;Was there a register?
549                 BNE     %10driver__readAddr     ;Yes -- almost done then
550
551                 SUB     R1,R8,#1                ;Point to the string
552                 MOV     R0,#16                  ;Expect a hex number
553                 SWI     XOS_ReadUnsigned        ;Try to understand the value
554                 BVS     %90driver__readAddr     ;If failed, report error
555                 MOV     R5,R2                   ;Get the address he typed
556                 ORR     R4,R4,#1                ;He typed something
557
558 10              TST     R4,#1                   ;Was there anything at all?
559                 BEQ     %80driver__readAddr     ;No -- return C clear then
560
561                 BIC     R0,R5,#3                ;Truncate to word boundary
562                 ADD     R13,R13,#20             ;Restore the stack
563                 LDMFD   R13!,{R1-R5,R8,R14}     ;Unstack registers
564                 ORRS    PC,R14,#C_flag          ;And return with C proudly on
565
566                 ; --- Lazy user typed nothing ---
567
568 80              ADD     R13,R13,#20             ;Restore the stack
569                 LDMFD   R13!,{R1-R5,R8,R14}     ;Unstack registers
570                 BICS    PC,R14,#C_flag          ;And return with C sadly off
571
572                 ; --- Stupid user caused an error ---
573
574 90              ADD     R13,R13,#20             ;Restore the stack
575                 LDMFD   R13!,{R1-R5,R8,R14}     ;Unstack registers
576                 ORRS    PC,R14,#V_flag          ;So set V on exit
577
578                 LTORG
579
580 ;----- That's all, folks ----------------------------------------------------
581
582                 END