Initial revision
[ssr] / StraySrc / Hammer / s / diss
1 ;
2 ; diss.s
3 ;
4 ; Superior Disassembly of ARM instructions (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 ;----- Things to do ---------------------------------------------------------
28 ;
29 ; Disassemble Floating point instructions
30 ; Deal with labels
31 ; Recognise XRel's
32
33 ;----- Standard header ------------------------------------------------------
34
35 GET libs:header
36 GET libs:swis
37 GET libs:stream
38
39 ;----- External dependencies ------------------------------------------------
40
41 GET quartz:quartz
42 GET quartz:string
43
44 ;----- Main code ------------------------------------------------------------
45
46 AREA |Hammer$$Code|,CODE,READONLY
47
48 ; --- diss_setOptions ---
49 ;
50 ; On entry: R0 == new options field
51 ;
52 ; On exit: --
53 ;
54 ; Use: Sets up the new display options for the disassembly
55
56 EXPORT diss_setOptions
57 diss_setOptions ROUT
58
59 STMFD R13!,{R12} ;Stack registers
60 LDR R12,diss__wSpace ;Locate my workspace
61 STR R0,ws__options ;Save the new options
62 LDMFD R13!,{R12} ;Reclaim stack
63 MOVS PC,R14
64
65 ; --- diss_address ---
66 ;
67 ; On entry: R0 == address to start disassembly
68 ;
69 ; On exit: --
70 ;
71 ; Use: Initialises the disassembly to start at the given address
72
73 EXPORT diss_address
74 diss_address ROUT
75
76 STMFD R13!,{R12,R14} ;Save some registers
77 LDR R12,diss__wSpace ;Find my workspace address
78 LDR R14,ws__flags ;Load the flags word
79 AND R14,R14,#wFlag__inited ;Clear most of the flags
80 STR R14,ws__flags ;Save the flags back again
81 STR R0,ws__nextAddr ;Store as next address
82 LDMFD R13!,{R12,PC}^ ;Return to caller
83
84 LTORG
85
86 ; --- diss_disassemble ---
87 ;
88 ; On entry: R0 == the instruction itself
89 ;
90 ; On exit: R0 == pointer to buffer containing disassembly of
91 ; instruction
92 ;
93 ; Use: Disassembles the instruction given, and places
94 ; the resulting string in the returned buffer.
95
96 EXPORT diss_disassemble
97 diss_disassemble ROUT
98
99 STMFD R13!,{R1-R12,R14} ;Stack lots of registers
100 LDR R12,diss__wSpace ;Locate my workspace
101 LDR R9,ws__nextAddr ;Get the address to use
102 MOV R8,R0 ;And the contents in R8
103
104 ; --- We don't have any comments yet ---
105
106 MOV R2,#0 ;A nice NULL byte
107 STR R2,ws__comment ;Zero the comment
108 ADR R2,ws__comment ;Point to the comment
109 STR R2,ws__commentEnd ;Start comment from here
110
111 ; --- Sort out the flags ---
112
113 LDR R14,ws__flags ;Load the flags
114 TST R14,#wFlag__newAdr ;Was it a new ADR?
115 BICNE R14,R14,#wFlag__newAdr ;Yes -- clear the flag
116 BICEQ R14,R14,#wFlag__wasAdr ;Otherwise clear was ADR flag
117 STR R14,ws__flags ;Save the flags back again
118
119 ; --- First do the address ---
120
121 MOV R0,R9 ;Put the address in R0
122 ADR R7,ws__buffer ;Point to string buffer
123 ADR R1,ws__buffer ;Point to string buffer
124 MOV R2,#16 ;The buffer size
125 SWI OS_ConvertHex8 ;Convert the address
126
127 MOV R3,#' ' ;A nice space
128 STRB R3,[R1],#1 ;Put it in the buffer
129
130 ; --- Display the label ---
131
132 MOV R4,#20 ;Enter 20 spaces
133 00 STRB R3,[R1],#1 ;Store the space
134 SUBS R4,R4,#1 ;Decrement the counter
135 BNE %00diss_disassemble ;Keep on looping
136
137 MOV R3,#' ' ;A nice space
138 STRB R3,[R1],#1 ;Put it in the buffer
139
140 ; --- Display the word ---
141
142 MOV R0,R8 ;Load the word into R0
143 MOV R2,#16 ;The buffer size
144 SWI OS_ConvertHex8 ;Convert the address
145
146 MOV R3,#' ' ;A nice space
147 STRB R3,[R1],#1 ;Put it in the buffer
148
149 ; --- Display the ASCII field ---
150
151 MOV R0,R8 ;Get the instruction
152 BL diss__showChar ;Show a character
153 MOV R0,R0,LSR#8 ;Get nextww byte
154 BL diss__showChar ;Show a character
155 MOV R0,R0,LSR#8 ;Get next byte
156 BL diss__showChar ;Show a character
157 MOV R0,R0,LSR#8 ;Get next byte
158 BL diss__showChar ;Show a character
159
160 MOV R3,#' ' ;A nice space
161 STRB R3,[R1],#1 ;Put it in the buffer
162
163 ; --- Disassemble the instruction ---
164
165 AND R0,R8,#&0F000000 ;Get just the opcode
166 MOV R0,R0,LSR#26 ;Get top two bits of opcode
167
168 MOV R14,PC ;Set up return address
169 ADD PC,PC,R0,LSL#2 ;Branch to correct routine
170 B %90diss_disassemble ;Branch ahead
171
172 B diss__type00
173 B diss__type01
174 B diss__type10
175 B diss__type11
176
177 ; --- Return to caller ---
178
179 90 LDRB R14,ws__comment ;Is there a comment?
180 CMP R14,#0 ;Look and see
181 BEQ %95diss_disassemble ;No -- jump ahead
182
183 MOV R3,#68 ;Set up the tab
184 BL diss__tab ;And do it
185 MOV R0,R1 ;Point to the buffer end
186 ADR R1,ws__comment ;Point at the comment
187 BL str_cpy ;Copy it over
188
189 95 ADD R9,R9,#4 ;Set up the next address
190 STR R9,ws__nextAddr ;And store it away
191 ADR R0,ws__buffer ;Point to the buffer
192 MOV R2,#0 ;A nice NULL value
193 STRB R2,[R1] ;Terminate the string
194 LDMFD R13!,{R1-R12,PC}^ ;Return to caller
195
196 LTORG
197
198 ; --- diss__showChar ---
199 ;
200 ; On entry: R0 == character to display
201 ; R1 == address to insert character
202 ;
203 ; On exit: --
204 ;
205 ; Use: Inserts the character in the bottom 8 bits of R0 into
206 ; the buffer pointed to by R1
207
208 diss__showChar ROUT
209
210 STMFD R13!,{R2-R3} ;Stack some registers
211 AND R2,R0,#&FF ;Get LSB
212 CMP R2,#127 ;Is it the delete char?
213 CMPNE R2,#31 ;..or a control character
214 MOVLE R2,#'.' ;Yes -- make it a dot
215 STRB R2,[R1],#1 ;Store char in the buffer
216 LDMFD R13!,{R2-R3} ;Get registers back
217 MOVS PC,R14 ;Return to caller
218
219 ; --- diss__addComment ---
220 ;
221 ; On entry: R0 == pointer to comment to add
222 ;
223 ; On exit: R0 corrupted
224 ;
225 ; Use: Adds the given comment to the current one
226
227 diss__addComment ROUT
228
229 STMFD R13!,{R1,R14} ;Stack some registers
230 MOV R1,R0 ;Copying from here
231 LDR R0,ws__commentEnd ;Point to the comment end
232 ADR R14,ws__comment ;Get the beginning
233 CMP R14,R0 ;Are they the same?
234 MOVEQ R14,#';' ;Yes -- get a semicolon
235 STREQB R14,[R0],#1 ;And put it at beginning
236 BL str_cpy ;Copy the string over
237 STR R0,ws__commentEnd ;This is now comment end
238 LDMFD R13!,{R1,PC}^ ;Return to caller
239
240 ; --- diss__typeXX ---
241 ;
242 ; On entry: R1 == buffer position to write to
243 ; R8 == the instruction
244 ; R9 == address from which instruction came
245 ;
246 ; On exit: R0,R2-R6,R10-R12 possibly corrupted
247 ;
248 ; Use: Disassemble instructions with an opcode prefix of XX.
249
250 diss__type00 ROUT
251
252 AND R5,R8,#&0FC00000 ;Get the op code
253 AND R6,R8,#&000000F0 ;We need these bits too
254
255 ; --- See if it is a multiply instruction ---
256
257 CMP R5,#0 ;Multiply instruction?
258 CMPEQ R6,#&90 ;Double check
259 BEQ diss__multiply ;Yes -- deal with it then
260
261 ; --- Is it a SWP instruction ---
262
263 CMP R5,#&01000000 ;Is this bit set?
264 CMPNE R5,#&01400000 ;Or maybe this bit too?
265 CMPEQ R6,#&90 ;Double check
266 BEQ diss__swp ;Yes -- deal with it
267
268 ; --- Is it an undefined operation? ---
269
270 AND R0,R5,#&03000000 ;Get the correct bits
271 AND R3,R6,#&00000090 ;Are these bits set too?
272 CMP R0,#&01000000 ;Is opcode 0001?
273 CMPEQ R3,#&00000090 ;And are these bits set?
274 BEQ diss__undefined ;Yes -- deal with it then
275
276 ; --- It must be a data processing operation then ---
277
278 B diss__aluOp ;Dissassemble an ALU op
279
280 LTORG
281
282 diss__type01 ROUT
283
284 ; --- See if it's undefined ---
285
286 TST R8,#(1<<25) ;Is bit 25 set?
287 TSTNE R8,#(1<<4) ;And bit 4?
288 BNE diss__undefined ;Yes -- it's undefined then
289
290 ; --- So it must be a data transfer ---
291
292 B diss__sTransfer ;Deal with it
293
294 LTORG
295
296 diss__type10 ROUT
297
298 ; --- Test to see if it's a branch ---
299
300 TST R8,#(1<<25) ;Is this bit set?
301 BNE diss__branch ;Yes -- it's a branch
302
303 ; --- It must be a multiple load then ---
304
305 B diss__mTransfer ;Disassemble it
306
307 LTORG
308
309 diss__type11 ROUT
310
311 TST R8,#(1<<25) ;Is this bit clear?
312 BEQ diss__coDataTran ;Yes -- do co proc data trans
313
314 AND R0,R8,#&0F000000 ;Get top nibble of opcode
315 CMP R0,#&0F000000 ;Is it a SWI instruction?
316 BEQ diss__swi ;Yes -- deal with it
317
318 TST R8,#(1<<4) ;Is it a coregister transfer?
319 BNE diss__coRegTran ;Yes -- deal with it
320
321 B diss__coDataOp ;Do a co-proc data op
322
323 LTORG
324
325 diss__undefined ROUT
326
327 MOVS R3,R14 ;Remember return address
328 MOVS R0,R1 ;Copy to here
329 ADR R1,diss__undef ;Point to the message
330 BL str_cpy ;Copy the string across
331 MOVS R1,R0 ;Make R1 point to buffer end
332 MOVS PC,R3 ;Return to caller
333
334 diss__undef DCB "Undefined instruction",0
335
336 LTORG
337
338 ; --- diss__multiply ---
339 ;
340 ; On entry R1 == position in buffer to write dissassembly
341 ; R7 == address of buffer for dissassembled line
342 ; R8 == instruction to dissassemble
343 ; R9 == location in memory of instruction
344 ;
345 ; On exit: R0,R2,R3,R4 corrupted
346 ;
347 ; Use: Dissassembles a multiply instruction
348
349
350 diss__multiply ROUT
351
352 STMFD R13!,{R14} ;Stack the link register
353
354 ; --- Set up the opcode in the buffer ---
355
356 TST R8,#(1<<21) ;Is it an MLA?
357 LDRNE R14,diss__mla ;Yes -- load that name
358 LDREQ R14,diss__mul ;No -- load MUL word then
359 STR R14,[R1],#3 ;Store the opcode in buffer
360 BL diss__cond ;Put the condition code in
361
362 TST R8,#(1<<20) ;Write back condition code?
363 MOVNE R14,#'S' ;Yes -- stick an `S' on it
364 STRNEB R14,[R1],#1 ;And write it on the end
365
366 MOV R3,#52 ;Tab to here please
367 BL diss__tab ;Do a 'tab' character
368
369 ; --- Write out the registers ---
370
371 MOV R2,#',' ;A comma, for niceness
372 MOV R3,R8,LSR #16 ;Get Rd
373 AND R3,R3,#&F ;Get the register
374 CMP R3,#&F ;Is it PC?
375 ADREQ R0,diss__mulErr1 ;Yes -- point to comment
376 BLEQ diss__addComment ;And add the comment
377 BL diss__reg ;Write out the register name
378 STRB R2,[R1],#1 ;Separate Rd from the rest
379 MOV R4,R8 ;Get Rm next
380 AND R4,R4,#&F ;Get the register
381 CMP R4,R3 ;Is Rd == Rm?
382 ADREQ R0,diss__mulErr2 ;Yes -- point to comment
383 BLEQ diss__addComment ;And add the comment
384 MOV R3,R4 ;Display this register
385
386 BL diss__reg ;Write out the register name
387 STRB R2,[R1],#1 ;Separate Rm from next one
388 MOV R3,R8,LSR #8 ;Get Rs
389 BL diss__reg ;Write out the register name
390 TST R8,#(1<<21) ;Is this an MLA instruction
391 STRNEB R2,[R1],#1 ;Separate Rs from next one
392 MOVNE R3,R8,LSR #12 ;Get Rn
393 BLNE diss__reg ;And write that on the end
394
395 LDMFD R13!,{PC}^ ;Return to caller
396
397 diss__mla DCB "MLA",0
398 diss__mul DCB "MUL",0
399
400 diss__mulErr1 DCB "! Rd=PC ",0
401 diss__mulErr2 DCB "! Rd=Rm ",0
402
403 LTORG
404
405 ; --- diss__swp ---
406 ;
407 ; On entry R1 == position in buffer to write dissassembly
408 ; R7 == address of buffer for dissassembled line
409 ; R8 == instruction to dissassemble
410 ; R9 == location in memory of instruction
411 ;
412 ; On exit: R0,R2,R3,R4 corrupted
413 ;
414 ; Use: Dissassembles an SWP operation instruction
415
416
417 diss__swp ROUT
418
419 STMFD R13!,{R14} ;Stack the link register
420
421 ; --- Set up the opcode in the buffer ---
422
423 LDR R14,diss__swpName ;Get the SWP word
424 STR R14,[R1],#3 ;Store the opcode in buffer
425 BL diss__cond ;Put the condition code in
426
427 TST R8,#(1<<22) ;Single byte transfer?
428 MOVNE R14,#'B' ;Yes -- stick an `B' on it
429 STRNEB R14,[R1],#1 ;And write it on the end
430
431 MOV R3,#52 ;Tab to here please
432 BL diss__tab ;Do a 'tab' character
433
434 ; --- Write out the registers ---
435
436 MOV R2,#',' ;A comma, for niceness
437 MOV R3,R8,LSR #12 ;Get Rd
438 BL diss__reg ;Write out the register name
439 STRB R2,[R1],#1 ;Separate Rd from the rest
440 MOV R4,R8 ;Get Rm next
441 MOV R3,R4 ;Display this register
442 BL diss__reg ;Write out the register name
443 STRB R2,[R1],#1 ;Separate Rm from next one
444 MOV R2,#'[' ;Get a '['
445 STRB R2,[R1],#1 ;Put it in the string
446 MOV R3,R8,LSR #16 ;Get Rn
447 BL diss__reg ;Write out the register name
448 MOV R2,#']' ;Get a ']'
449 STRB R2,[R1],#1 ;Put it in the string
450 ADR R0,diss__swpComment ;Point to the comment
451 BL diss__addComment ;And add it nicley
452
453 LDMFD R13!,{PC}^ ;Return to caller
454
455 diss__swpName DCB "SWP",0
456 diss__swpComment DCB "Not available on ARM 2",0
457
458 ; --- diss__aluOp ---
459 ;
460 ; On entry: R1 == position in buffer to write dissassembly
461 ; R7 == address of buffer for dissassembled line
462 ; R8 == instruction to dissassemble
463 ; R9 == location in memory of instruction
464 ;
465 ; On exit: R0,R2-R6,R10 corrupted
466 ;
467 ; Use: Dissassembles an ALU operation instruction
468
469 diss__aluOp ROUT
470
471 STMFD R13!,{R14} ;Save some register(s)
472
473 ; --- Display the opcode nicely ---
474
475 MOV R2,R8,LSR #21 ;Get the opcode
476 AND R2,R2,#15 ;Mask of unwanted bits
477 ADR R3,diss__aluTable ;Point to my table
478 ADD R3,R3,R2,LSL #3 ;Point to the entry I want
479 LDMIA R3,{R3,R5} ;Load text opcode and flags
480
481 ; --- Check for ADR instructions ---
482
483 TST R5,#dFlag__adrable ;Is it at all possible?
484 TSTNE R8,#(1<<25) ;Is it also an immediate op?
485 BEQ %05diss__aluOp ;No -- skip onwards then
486 TSTNE R8,#(1<<20) ;Is he writing back flags?
487 BNE %05diss__aluOp ;Yes -- it's not an ADR then
488 MOV R14,R8,LSR #16 ;Get the middle register
489 AND R14,R14,#15 ;Mask off unwanted bits
490 CMP R14,#15 ;Is it the PC?
491 BEQ %70diss__aluOp ;Yes -- then handle it
492
493 ; --- Just do it the old fashioned way (oo-er) ---
494
495 05diss__aluOp STR R3,[R1],#3 ;Store the opcode
496 BL diss__cond ;Add on the condition code
497
498 TST R8,#(1<<20) ;Do we need to write an S?
499 TSTNE R5,#dFlag__nonCmp ;Would it be superfluous?
500 MOVNE R14,#'S' ;All OK, get an `S' char
501 STRNEB R14,[R1],#1 ;And store it away
502 BNE %10diss__aluOp ;And don't mess with CMPs
503
504 ; --- Handle the `P' suffix on CMP instructions ---
505
506 TST R5,#dFlag__nonCmp ;Is this a CMP-type instr?
507 BNE %10diss__aluOp ;No -- don't bother with P
508 MOV R3,R8,LSR #12 ;Otherwise get dest reg
509 AND R3,R3,#15 ;Mask off other bits
510 CMP R3,#15 ;Is it a `P' instruction?
511 MOVEQ R14,#'P' ;Yes -- get a `P' char
512 STREQB R14,[R1],#1 ;And store it away
513
514 10diss__aluOp MOV R3,#52 ;Get the tab position
515 BL diss__tab ;And move the position on
516
517 ; --- Output the operands ---
518
519 MOV R2,#',' ;Get our trusty comma
520 TST R5,#dFlag__nonCmp ;Is there a destination reg?
521 MOVNE R3,R8,LSR #12 ;Yes -- get the register sym
522 BLNE diss__reg ;And display it nicely
523 STRNEB R2,[R1],#1 ;And separate it off nicely
524
525 TST R5,#dFlag__noMiddle ;Is there a middle operand?
526 MOVEQ R3,R8,LSR #16 ;Yes -- get the register
527 BLEQ diss__reg ;And display it nicely
528 STREQB R2,[R1],#1 ;And separate it off nicely
529
530 ; --- Oh no -- it's the last operand ---
531
532 TST R8,#(1<<25) ;Is it an immediate op?
533 BNE %50diss__aluOp ;Yes -- AAARRRGHHHH
534
535 MOV R3,R8 ;Get the Op2 register
536 BL diss__reg ;Display it nicely
537
538 ; --- It's fun with shifts time, boys and girls ---
539
540 TST R8,#(1<<4) ;Is it a register shift
541 BLEQ diss__shift ;No -- do a constant shift
542 BEQ %90diss__aluOp ;...and return
543
544 MOV R3,#',' ;Get a comma
545 STRB R3,[R1],#1 ;Store it away then
546 MOV R3,R8,LSR #5 ;Get the shift type
547 AND R3,R3,#3 ;Kill off excess bits
548 ADRL R4,diss__shifts ;Point to the shifts table
549 LDR R4,[R4,R3,LSL #2] ;Load the shift name
550
551 STRB R4,[R1],#1 ;Store the first byte
552 MOV R4,R4,LSR #8 ;Shift it down one byte
553 STRB R4,[R1],#1 ;Store the second byte
554 MOV R4,R4,LSR #8 ;Shift it down one byte
555 STRB R4,[R1],#1 ;Store the third byte
556 MOV R4,R4,LSR #8 ;Shift it down one byte
557 STRB R4,[R1],#1 ;Store the last byte (space)
558 MOV R4,R4,LSR #8 ;Shift it down one byte
559
560 MOV R3,R8,LSR #8 ;Get the shift register
561 BL diss__reg ;Display the register name
562 B %90diss__aluOp ;And return to caller
563
564 ; --- Now deal with immediate constants ---
565
566 50diss__aluOp AND R2,R8,#&F00 ;Get the shift size
567 MOV R2,R2,LSR #7 ;Make it an even rotation
568 AND R0,R8,#&FF ;Get the actual immediate
569 MOV R0,R0,ROR R2 ;And work out the real value
570
571 ; --- Add a comment if we need to ---
572
573 SUB R14,R0,#32 ;Greater or equal to this?
574 CMP R14,#255 ;Or lower than this?
575 BHS %53diss__aluOp ;No -- jump ahead
576 CMP R0,#127 ;Is it ASCII 127?
577 BEQ %53diss__aluOp ;Yes -- jump ahead
578 MOV R2,R0 ;Put the character in R2
579 MOV R3,R1 ;Preserve buffer pointer
580 MOV R4,R0 ;Preserve the number too
581 SUB R13,R13,#12 ;Get a small block
582 MOV R1,R13 ;Point to it nicely
583 ADR R0,diss__chMess ;Point to the skeleton
584 BL str_subst ;Substitute the string
585 BL diss__addComment ;Add the comment
586 ADD R13,R13,#12 ;Get my stack back again
587 MOV R0,R4 ;Restore the constant
588 MOV R1,R3 ;And restore buffer pointer
589
590 ; --- Handle possible ADRLs ---
591
592 53diss__aluOp TST R5,#dFlag__adrable ;Is it a possible
593 LDRNE R14,ws__flags ;Load the jolly old flags
594 TSTNE R14,#wFlag__wasAdr ;Was the last one an ADR?
595 BEQ %55diss__aluOp ;No -- skip ahead then
596 MOV R2,R8,LSR #16 ;Get Rn out
597 AND R2,R2,#15 ;Clear off excess bits
598 LDRB R3,ws__lastReg ;Get the last register
599 CMP R2,R3 ;Do they match nicely?
600 LDREQB R2,ws__lastCond ;Get the previous condition
601 MOVEQ R3,R8,LSR #28 ;Get the current condition
602 CMPEQ R2,R3 ;Do they match too?
603 BNE %55diss__aluOp ;No -- skip ahead then
604
605 ; --- It's an ADRL -- it's official ---
606
607 STMFD R13!,{R1} ;Save the old buffer pointer
608 MOV R10,R0 ;Keep the offset value safe
609 BL str_buffer ;Get a buffer thingy
610 MOV R6,R1 ;Keep this buffer ptr
611 LDR R14,diss__adr ;Load the opcode text
612 STR R14,[R1],#3 ;Save it in the buffer
613 BL diss__cond ;Attach the condition code
614 MOV R14,#'L' ;Say this is a long ADR
615 STRB R14,[R1],#1 ;Tack the L on the end
616 MOV R14,#' ' ;Put a space in there too
617 STRB R14,[R1],#1 ;Put that in nicely
618 MOV R3,R8,LSR #12 ;Get Rd
619 BL diss__reg ;Insert the register name
620 STRB R3,ws__lastReg ;Save the new register val
621 MOV R14,#',' ;The magic comma again
622 STRB R14,[R1],#1 ;Put that in nicely
623 LDR R0,ws__lastAddr ;Load the previous address
624 TST R8,#(1<<23) ;Is it an ADD instruction?
625 ADDNE R0,R0,R10 ;Yes -- add offset to old
626 SUBEQ R0,R0,R10 ;Otherwise subtract it
627 STR R0,ws__lastAddr ;Store this new address
628 BL diss__address ;Insert the address
629 MOV R0,R6 ;Point to the buffer
630 LDMFD R13!,{R1} ;Restore my old buffer
631 BL diss__addComment ;Insert the comment string
632 MOV R0,R10 ;Get the immediate value back
633
634 LDR R14,ws__flags ;Load the old flags word
635 ORR R14,R14,#wFlag__newAdr ;This is another ADR thing
636 STR R14,ws__flags ;Save the flags back again
637
638 ; --- Display the mystic hash sign ---
639
640 55diss__aluOp MOV R14,#'#' ;Get a hash sign
641 STRB R14,[R1],#1 ;Add it to the string
642
643 ; --- Now work out how we want to display it ---
644
645 LDR R14,ws__options ;Load the options word
646 TST R5,#dFlag__bitwise ;Is this a bitwise operation?
647 MOVEQ R14,R14,LSR #1 ;No -- then shift options
648 TST R14,#dOpt__bitHex ;Now, do we display in hex?
649 BNE %60diss__aluOp ;Yes -- do that then
650
651 ; --- Display the constant in decimal ---
652
653 MOV R2,#50 ;Say my buffer is big
654 SWI XOS_ConvertInteger4 ;Display the number
655 B %90diss__aluOp ;Now we can go home
656
657 ; --- Display it in hexadecimal ---
658
659 60diss__aluOp BL diss__displayHex ;Print the hex value
660 B %90diss__aluOp ;Return to caller
661
662 ; --- Display an ADR pseudo instruction ---
663
664 70diss__aluOp LDR R0,diss__adr ;Load the characters `ADR'
665 STR R0,[R1],#3 ;Save them in the buffer
666 BL diss__cond ;Add on a condition code
667 MOV R3,#52 ;Get the tab position
668 BL diss__tab ;Tab up to the right pos
669
670 ; --- Set up the flags to say this was an ADR ---
671
672 LDR R14,ws__flags ;Load the flags word
673 ORR R14,R14,#wFlag__wasAdr+wFlag__newAdr
674 STR R14,ws__flags ;Save the flags back again
675 MOV R14,R8,LSR #28 ;Get the condition code
676 STRB R14,ws__lastCond ;Save that for later nicely
677
678 ; --- Display the destination register ---
679
680 MOV R3,R8,LSR #12 ;Get the register number
681 AND R3,R3,#15 ;Kill off the excess bits
682 STRB R3,ws__lastReg ;Store this register away
683 BL diss__reg ;And display it nicely
684 MOV R2,#',' ;Get our trusty comma
685 STRB R2,[R1],#1 ;And separate it off nicely
686
687 AND R2,R8,#&F00 ;Get the shift size
688 MOV R2,R2,LSR #7 ;Make it an even rotation
689 AND R0,R8,#&FF ;Get the actual immediate
690 MOV R0,R0,ROR R2 ;And work out the real value
691 ADD R14,R9,#8 ;Move PC on a little bit
692 TST R8,#(1<<23) ;Is it an ADD instruction?
693 ADDNE R0,R14,R0 ;Yes -- add offset to PC
694 SUBEQ R0,R14,R0 ;Otherwise subtract it
695 STR R0,ws__lastAddr ;Save this address away
696 BL diss__address ;Display the address
697
698 90diss__aluOp LDMFD R13!,{PC}^ ;Return to caller
699
700 dFlag__bitwise EQU (1<<0)
701 dFlag__adrable EQU (1<<1)
702 dFlag__multiply EQU (1<<2)
703 dFlag__noMiddle EQU (1<<3)
704 dFlag__nonCmp EQU (1<<4)
705
706 diss__adr DCB "ADR",0
707
708 diss__aluTable DCB "AND",0
709 DCD dFlag__bitwise+dFlag__nonCmp
710 DCB "EOR",0
711 DCD dFlag__bitwise+dFlag__nonCmp
712 DCB "SUB",0
713 DCD dFlag__adrable+dFlag__nonCmp
714 DCB "RSB",0
715 DCD dFlag__multiply+dFlag__nonCmp
716
717 DCB "ADD",0
718 DCD dFlag__multiply+dFlag__adrable+dFlag__nonCmp
719 DCB "ADC",0
720 DCD dFlag__nonCmp
721 DCB "SBC",0
722 DCD dFlag__nonCmp
723 DCB "RSC",0
724 DCD dFlag__nonCmp
725
726 DCB "TST",0
727 DCD dFlag__bitwise
728 DCB "TEQ",0
729 DCD dFlag__bitwise
730 DCB "CMP",0
731 DCD 0
732 DCB "CMN",0
733 DCD 0
734
735 DCB "ORR",0
736 DCD dFlag__bitwise+dFlag__nonCmp
737 DCB "MOV",0
738 DCD dFlag__noMiddle+dFlag__multiply+dFlag__nonCmp
739 DCB "BIC",0
740 DCD dFlag__bitwise+dFlag__nonCmp
741 DCB "MVN",0
742 DCD dFlag__noMiddle+dFlag__nonCmp
743
744 diss__chMess DCB "='%c0'",0
745 ALIGN
746
747 LTORG
748
749 diss__shifts DCB "LSL "
750 DCB "LSR "
751 DCB "ASR "
752 DCB "ROR "
753 diss__rrx DCB " RRX"
754
755 ; --- diss__shift ---
756 ;
757 ; On entry: R1 == pointer to buffer to disassemble into
758 ; R5 == Flags word of the instruction
759 ; R7 == pointer to the start of the buffer
760 ; R8 == the instruction
761 ; R9 == location in memory from which instruction came
762 ;
763 ; On exit: R3,R4 corrupted
764 ;
765 ; Use: Disassemble a constant controlled shift
766
767
768 diss__shift ROUT
769
770 STMFD R13!,{R14} ;Stack the link register
771
772 AND R3,R8,#&FF0 ;Get the shift type and size
773 CMP R3,#&000 ;Is it an LSL #0?
774 LDMEQFD R13!,{PC}^ ;Yes -- nothing to do then
775
776 CMP R3,#&060 ;Is it an RRX?
777 BNE %10diss__shift ;No -- do other things then
778
779 LDR R4,diss__rrx ;Get the RRX string
780 STRB R4,[R1],#1 ;Store the first byte (comma)
781 MOV R4,R4,LSR #8 ;Shift it down one byte
782 STRB R4,[R1],#1 ;Store the second byte
783 MOV R4,R4,LSR #8 ;Shift it down one byte
784 STRB R4,[R1],#1 ;Store the third byte
785 MOV R4,R4,LSR #8 ;Shift it down one byte
786 STRB R4,[R1],#1 ;Store the last byte
787 MOV R4,R4,LSR #8 ;Shift it down one byte
788 LDMEQFD R13!,{PC}^ ;And return to caller
789
790 ; --- Do ordinary things now ---
791
792 10diss__shift MOV R14,#' ' ;Put a comma in
793 STRB R14,[R1],#1 ;Store that in the buffer
794 MOV R14,R8,LSR #5 ;Get the shift type
795 AND R14,R14,#3 ;Kill off excess bits
796 ADR R4,diss__shifts ;Point to the shifts table
797 LDR R4,[R4,R14,LSL #2] ;Load the shift name
798
799 MOV R0,R3,LSR #7 ;Get the shift amount value
800 CMP R0,#0 ;Is it zero?
801 MOVEQ R0,#32 ;Then pretend it's 32
802
803 ; --- Add in the multipy comment ---
804
805 TST R5,#dFlag__multiply ;Does it apply to the inst?
806 BEQ %50diss__shift ;No -- jump ahead
807 CMP R14,#0 ;Is it an LSL?
808 BNE %50diss__shift ;No -- jump ahead
809
810 MOV R6,R8 ;Get Rm
811 AND R6,R6,#&F ;Clear unwanted bits
812 MOV R3,R8,LSR#16 ;Get Rn
813 AND R3,R3,#&F ;Clear unwanted bits
814 TST R5,#dFlag__noMiddle ;Does it have a middle reg?
815 BNE %12diss__shift ;No -- jump folowing test
816 CMP R3,R6 ;And is Rm <> Rn?
817 BNE %50diss__shift ;If so -- jump ahead
818 TST R5,#dFlag__noMiddle ;Does it have a middle reg?
819
820 12 MOV R5,#1 ;We start with 1
821 MOV R5,R5,LSL R0 ;Work out the multiply
822
823 BNE %15diss__shift ;No -- jump ahead a bit
824 TST R8,#(1<<23) ;Is it a RSB?
825 ADDNE R5,R5,#1 ;No -- increment multiply
826 SUBEQ R5,R5,#1 ;Yes -- decrement multiply
827
828 15 MOV R11,R0 ;Preserve R0
829 MOV R3,R8,LSR#12 ;Get Rd
830 MOV R10,R1 ;Preserve the buffer pointer
831 BL str_buffer ;Get a buffer
832 STMFD R13!,{R1} ;Remember this position
833 BL diss__reg ;Display the destination
834 MOV R3,#'=' ;Get the equal sign
835 STRB R3,[R1],#1 ;Store it in the buffer
836 MOV R3,R6 ;Get the operand register
837 BL diss__reg ;Display that
838 MOV R3,#'*' ;Get the '*' sign
839 STRB R3,[R1],#1 ;Store it in the buffer
840 MOV R0,R5 ;Put 'multiply by' in R0
841 SWI OS_ConvertInteger4 ;Convert to a string
842 LDMFD R13!,{R0} ;Get comment pointer
843 BL diss__addComment ;Add the comment
844 MOV R0,R11 ;Restore R0 value
845 MOV R1,R10 ;Get buffer pos back
846
847 ; --- Display the shift ---
848
849 50 STRB R4,[R1],#1 ;Store the first byte
850 MOV R4,R4,LSR #8 ;Shift it down one byte
851 STRB R4,[R1],#1 ;Store the second byte
852 MOV R4,R4,LSR #8 ;Shift it down one byte
853 STRB R4,[R1],#1 ;Store the third byte
854 MOV R4,R4,LSR #8 ;Shift it down one byte
855 STRB R4,[R1],#1 ;Store the last byte (space)
856 MOV R4,R4,LSR #8 ;Shift it down one byte
857
858 MOV R14,#'#' ;Put a hash sign in
859 STRB R14,[R1],#1 ;Store it away
860 MOV R2,#50 ;Say my buffer's massive
861 SWI XOS_ConvertInteger1 ;Write it out in decimal
862 LDMFD R13!,{PC}^ ;Return to caller
863
864 LTORG
865
866 ; --- diss__displayHex ---
867 ;
868 ; On entry: R0 == hex number to display
869 ; R1 == pointer to buffer to disassemble into
870 ; R7 == pointer to the start of the buffer
871 ; R8 == the instruction
872 ; R9 == location in memory from which instruction came
873 ;
874 ; On exit: R0,R2,R3 corrupted
875 ;
876 ; Use: Displays a hex number without leading NULL bytes
877
878 diss__displayHex ROUT
879
880 STMFD R13!,{R14} ;Stack the link register
881 MOV R2,#'&' ;Tell user it's in hex
882 STRB R2,[R1],#1 ;Save it in the buffer
883 MOV R2,#8 ;No nastiness done yet
884 TST R0,#&FF000000 ;Is the top byte set?
885 MOVEQ R0,R0,LSL #8 ;No -- shift it up then
886 SUBEQ R2,R2,#2 ;Two digits lost here
887 TST R0,#&FF000000 ;Is the top byte set?
888 MOVEQ R0,R0,LSL #8 ;No -- shift it up then
889 SUBEQ R2,R2,#2 ;Two digits lost here
890 TST R0,#&FF000000 ;Is the top byte set?
891 MOVEQ R0,R0,LSL #8 ;No -- shift it up then
892 SUBEQ R2,R2,#2 ;Two digits lost here
893 ADR R3,diss__hexDigits ;Point to my hex table
894
895 10 MOV R14,R0,LSR #28 ;Get the top nibble
896 LDRB R14,[R3,R14] ;Get the correct hex digit
897 STRB R14,[R1],#1 ;Store it in the buffer
898 MOV R0,R0,LSL #4 ;Shift up by a nibble
899 SUBS R2,R2,#1 ;One less digit to go
900 BGT %10diss__displayHex ;If I've done it, stop
901
902 LDMFD R13!,{PC}^ ;Return to caller
903
904 diss__hexDigits DCB "0123456789ABCDEF"
905
906 LTORG
907
908 ; --- diss__sTransfer ---
909 ;
910 ; On entry: R1 == pointer to buffer to disassemble into
911 ; R7 == pointer to the start of the buffer
912 ; R8 == the instruction
913 ; R9 == location in memory from which instruction came
914 ;
915 ; On exit: Lots corrupted
916 ;
917 ; Use: Disassemble LDR/STR instructions, putting the result into
918 ; the buffer.
919
920 diss__sTransfer ROUT
921
922 STMFD R13!,{R14} ;Stack the link register
923
924 ; --- Display the instruction ---
925
926 TST R8,#(1<<20) ;Is it an LDR?
927 LDRNE R14,diss__ldr ;Yes -- load that name
928 LDREQ R14,diss__str ;No -- load STR word then
929 STR R14,[R1],#3 ;Store the opcode in buffer
930 BL diss__cond ;Put the condition code in
931 TST R8,#(1<<22) ;Is this byte load?
932 MOVNE R3,#'B' ;Yes -- get a 'B' character
933 STRNEB R3,[R1],#1 ;...and store it in buffer
934
935 ; --- Display the 'T' suffix ---
936
937 TST R8,#(1<<21) ;Is the W bit set?
938 BEQ %00diss__sTransfer ;No -- jump ahead a bit
939 TST R8,#(1<<24) ;How about the P bit?
940 MOVEQ R3,#'T' ;No -- get a 'B' character
941 STREQB R3,[R1],#1 ;...and store it in buffer
942
943 ; --- Now the destination register ---
944
945 00 MOV R3,#52 ;Tab to this position
946 BL diss__tab ;Do the tabbing
947 MOV R3,R8,LSR#12 ;Get Rd in bottom nibble
948 BL diss__reg ;Display the register
949 MOV R3,#',' ;Get a comma
950 STRB R3,[R1],#1 ;...and store it in buffer
951 TST R8,#(1<<24) ;Are we pre-indexed?
952 BNE diss__preIndexed ;Yes -- deal with it then
953 BEQ diss__postIndexed ;No -- must be post-indexed
954
955 diss__ldr DCB "LDR",0
956 diss__str DCB "STR",0
957
958 LTORG
959
960 ; --- diss__preIndexed ---
961 ;
962 ; On entry: R1 == pointer to buffer to disassemble into
963 ; R7 == pointer to the start of the buffer
964 ; R8 == the instruction
965 ; R9 == location in memory from which instruction came
966 ; Return address is on the stack
967 ;
968 ; On exit: Lots corrupted
969 ;
970 ; Use: Disassembles the pre-indexed part of a data transfer op.
971
972 diss__preIndexed ROUT
973
974 ; --- Deal with the base register ---
975
976 MOV R3,R8,LSR#16 ;Get the base register
977 AND R3,R3,#&F ;Mask off unwanted bits
978 CMP R3,#&F ;Is it the PC?
979 TSTEQ R8,#(1<<25) ;And is data immediate?
980 TSTEQ R8,#(1<<21) ;And are we not using !
981 BEQ diss__pcRel ;Yes -- it's PC relative
982
983 MOV R2,#'[' ;Get an open bracket
984 STRB R2,[R1],#1 ;Store it nicely
985 BL diss__reg ;Display the base register
986 MOV R5,#&FF ;Prepare the bit mask
987 ORR R5,R5,#&F00 ;Finish it off
988 AND R0,R8,R5 ;Get the offset
989
990 MOV R2,#',' ;Get an comma
991 STRB R2,[R1],#1 ;Store it in the buffer
992 TST R8,#(1<<25) ;Is data immediate?
993 MOVEQ R2,#'#' ;Yes -- get an hash
994 STREQB R2,[R1],#1 ;...and store it
995 TST R8,#(1<<23) ;Is data negative?
996 MOVEQ R2,#'-' ;Yes -- get a minus sugn
997 STREQB R2,[R1],#1 ;...and store that
998
999 TST R8,#(1<<25) ;Is data immediate?
1000 MOV R5,#0 ;The flags word
1001 BEQ %10diss__preIndexed ;Yes -- deal with it
1002
1003 MOV R3,R8 ;Get the register
1004 BL diss__reg ;Display the register
1005 BL diss__shift ;Display the shift
1006 B %20diss__preIndexed ;and jump ahead
1007
1008 ; --- Now work out how we want to display constant ---
1009
1010 10 LDR R14,ws__options ;Load the options word
1011 TST R14,#dOpt__tranHex ;Now, do we display in hex?
1012 BLNE diss__displayHex ;Yes -- do it then
1013 MOVEQ R2,#50 ;No -- say my buffer is big
1014 SWIEQ XOS_ConvertInteger4 ;...display the number
1015
1016 ; --- Finish off the instruction ---
1017
1018 20 MOV R2,#']' ;Yes -- get an close bracket
1019 STRB R2,[R1],#1 ;...and store it
1020 TST R8,#(1<<21) ;Are we writing back?
1021 MOVNE R2,#'!' ;Yes -- get the pling
1022 STRNEB R2,[R1],#1 ;...and store it
1023
1024 LDMFD R13!,{PC}^ ;Return to caller
1025
1026 LTORG
1027
1028 ; --- diss__postIndexed ---
1029 ;
1030 ; On entry: R1 == pointer to buffer to disassemble into
1031 ; R7 == pointer to the start of the buffer
1032 ; R8 == the instruction
1033 ; R9 == location in memory from which instruction came
1034 ; Return address is on the stack
1035 ;
1036 ; On exit: Lots corrupted
1037 ;
1038 ; Use: Disassembles the post-indexed part of a data transfer op.
1039
1040 diss__postIndexed ROUT
1041
1042 ; --- Deal with the base register ---
1043
1044 MOV R3,R8,LSR#16 ;Get the base register
1045 MOV R2,#'[' ;Get an open bracket
1046 STRB R2,[R1],#1 ;Store it nicely
1047 BL diss__reg ;Display the base register
1048 MOV R2,#']' ;Get an close bracket
1049 STRB R2,[R1],#1 ;Store it nicely
1050
1051 ; --- Is there any post index to display ---
1052
1053 MOV R5,#&FF ;Prepare the bit mask
1054 ORR R5,R5,#&F00 ;Finish it off
1055 AND R0,R8,R5 ;Get the offset
1056
1057 MOV R2,#',' ;Get an comma
1058 STRB R2,[R1],#1 ;Store it in the buffer
1059 TST R8,#(1<<25) ;Is data immediate?
1060 MOVEQ R2,#'#' ;Yes -- get an hash
1061 STREQB R2,[R1],#1 ;...and store it
1062 TST R8,#(1<<23) ;Is data negative?
1063 MOVEQ R2,#'-' ;Yes -- get a minus sugn
1064 STREQB R2,[R1],#1 ;...and store that
1065
1066 TST R8,#(1<<25) ;Is data immediate?
1067 BEQ %10diss__postIndexed ;Yes -- deal with it
1068
1069 MOV R3,R8 ;Get the register
1070 BL diss__reg ;Display the register
1071 MOV R5,#0 ;The flags word
1072 BL diss__shift ;Display the shift
1073 LDMFD R13!,{PC}^ ;Return to caller
1074
1075 ; --- Now work out how we want to display constant ---
1076
1077 10 LDR R14,ws__options ;Load the options word
1078 TST R14,#dOpt__tranHex ;Now, do we display in hex?
1079 BLNE diss__displayHex ;Yes -- do it then
1080 MOVEQ R2,#50 ;No -- say my buffer is big
1081 SWIEQ XOS_ConvertInteger4 ;...display the number
1082
1083 LDMFD R13!,{PC}^ ;Return to caller
1084
1085 LTORG
1086
1087 ; --- diss__pcRel ---
1088 ;
1089 ; On entry: R1 == pointer to buffer to disassemble into
1090 ; R7 == pointer to the start of the buffer
1091 ; R8 == the instruction
1092 ; R9 == location in memory from which instruction came
1093 ; Return address is on the stack
1094 ;
1095 ; On exit: Lots corrupted
1096 ;
1097 ; Use: Disassembles PC relative data transfer instructions
1098
1099 diss__pcRel ROUT
1100
1101 ADD R2,R9,#8 ;Allow for the pipeline
1102 MOV R0,#&FF ;Prepare the bit mask
1103 ORR R0,R0,#&F00 ;Finish it off
1104 AND R0,R8,R0 ;Get the offset
1105 TST R8,#(1<<23) ;Is offset negative?
1106 SUBEQ R0,R2,R0 ;Yes -- do a subtraction
1107 ADDNE R0,R2,R0 ;No -- do an addition
1108 BIC R0,R0,#&FC000000 ;Clear silly bits
1109 BL diss__address ;Display the address
1110 LDMFD R13!,{PC}^ ;Return to caller
1111
1112 LTORG
1113
1114 ; --- diss__mTransfer ---
1115 ;
1116 ; On entry: R1 == pointer to buffer to disassemble into
1117 ; R7 == pointer to the start of the buffer
1118 ; R8 == the instruction
1119 ; R9 == location in memory from which instruction came
1120 ;
1121 ; On exit: Lots corrupted
1122 ;
1123 ; Use: Disassembles LDM/STM instruction
1124
1125 diss__mTransfer ROUT
1126
1127 STMFD R13!,{R14} ;Stack the link
1128
1129 TST R8,#(1<<20) ;Is it a load?
1130 LDRNE R14,diss__ldm ;Yes -- load that name
1131 LDREQ R14,diss__stm ;No -- load STM word then
1132 STR R14,[R1],#3 ;Store the opcode in buffer
1133 BL diss__cond ;Put the condition code in
1134
1135 MOV R5,R8,LSR#16 ;Get the base register
1136 AND R5,R5,#&F ;Clear unwanted bits
1137 LDR R0,ws__options ;Get the options
1138 TST R0,#dOpt__r13Stack ;Do we use alternative type
1139 BEQ %10diss__mTransfer ;No -- jump ahead
1140 CMP R5,#13 ;Are we using R13?
1141 BNE %10diss__mTransfer ;No -- jump ahead
1142 TST R8,#(1<<21) ;Is there write back?
1143 BEQ %10diss__mTransfer ;No -- jump ahead
1144
1145 ; --- Work out stack type (FD etc.) ---
1146
1147 TST R8,#(1<<20) ;Yes -- Are we storing?
1148 BNE %05diss__mTransfer ;No -- do load seperatley
1149
1150 TST R8,#(1<<24) ;Are we full?
1151 MOVNE R0,#'F' ;Yes -- use 'F'
1152 MOVEQ R0,#'E' ;No -- use 'E'
1153 STRB R0,[R1],#1 ;Store the character
1154 TST R8,#(1<<23) ;Are we incrementing?
1155 MOVNE R0,#'A' ;Yes -- use 'A'
1156 MOVEQ R0,#'D' ;No -- use 'D'
1157 STRB R0,[R1],#1 ;Store the character
1158 B %20diss__mTransfer ;Jump ahead
1159
1160 05 TST R8,#(1<<24) ;Are we full?
1161 MOVNE R0,#'E' ;Yes -- use 'E'
1162 MOVEQ R0,#'F' ;No -- use 'F'
1163 STRB R0,[R1],#1 ;Store the character
1164 TST R8,#(1<<23) ;Are we incrementing?
1165 MOVNE R0,#'D' ;Yes -- use 'D'
1166 MOVEQ R0,#'A' ;No -- use 'A'
1167 STRB R0,[R1],#1 ;Store the character
1168 B %20diss__mTransfer ;Jump ahead
1169
1170 ; --- Word out stack type normally ---
1171
1172 10 TST R8,#(1<<23) ;Are we incrementing?
1173 MOVNE R0,#'I' ;Yes -- use 'I'
1174 MOVEQ R0,#'D' ;No -- use 'D'
1175 STRB R0,[R1],#1 ;Store the character
1176 TST R8,#(1<<24) ;Are we full?
1177 MOVNE R0,#'B' ;Yes -- use 'B'
1178 MOVEQ R0,#'A' ;No -- use 'A'
1179 STRB R0,[R1],#1 ;Store the character
1180 B %20diss__mTransfer ;Jump ahead
1181
1182 ; --- Continue the disassembly ---
1183
1184 20 MOV R3,#52 ;Tab to here
1185 BL diss__tab ;Do the tab
1186 MOV R3,R5 ;Put the base regster in R3
1187 BL diss__reg ;And display it
1188 TST R8,#(1<<21) ;Do we want write back?
1189 MOVNE R0,#'!' ;Yes -- get the '!'
1190 STRNEB R0,[R1],#1 ;...store the character
1191 MOV R0,#',' ;Get a comma
1192 STRB R0,[R1],#1 ;Store it
1193 MOV R0,#'{' ;Get the '{'
1194 STRB R0,[R1],#1 ;And store that too
1195
1196 ; --- Now do the register list ---
1197
1198 MOV R6,#1 ;The flags so far
1199 MOV R4,#0 ;The current register
1200 MOV R5,#0 ;Number in a row so far
1201
1202 30 MOV R2,#1 ;A nice 1 value
1203 MOV R2,R2,LSL R4 ;Set up the bit mask
1204 ANDS R14,R8,R2 ;Is the register in the list?
1205 BNE %50diss__mTransfer ;Yes -- jump ahead
1206 35 TST R6,#4 ;Are we in a sequence?
1207 BEQ %40diss__mTransfer ;No -- jump a bit
1208 CMP R5,#2 ;Have there been >2 regs?
1209 MOVGT R14,#'-' ;Yes -- get the dash
1210 MOVLE R14,#',' ;No -- get a comma then
1211 STRB R14,[R1],#1 ;Store it in the buffer
1212 SUB R3,R4,#1 ;Put previous register in R3
1213 BL diss__reg ;And display it
1214
1215 40 BIC R6,R6,#&6 ;Clear some flags
1216 MOV R5,#0 ;None in a row now
1217 B %70diss__mTransfer ;And jump to end of loop
1218
1219 ; --- The register is in the list ---
1220
1221 50 ADD R5,R5,#1 ;Increment reg count
1222 TST R6,#2 ;Is this the second?
1223 BNE %55diss__mTransfer ;Yes -- jump ahead a bit
1224 TST R6,#4 ;Are we in a sequence?
1225 BNE %70diss__mTransfer ;Yes -- jump to loop end
1226 TST R6,#1 ;Is this the *very* first?
1227 MOVEQ R14,#',' ;No -- get a comma then
1228 STREQB R14,[R1],#1 ;...store it in the buffer
1229 MOVEQ R6,#2 ;...just set 'first' bit now
1230 BEQ %60diss__mTransfer ;...and jump ahead
1231 55 TST R6,#2 ;Was last one first one?
1232 MOVNE R6,#4 ;Yes -- now in sequence
1233 BNE %70diss__mTransfer ;...and jump to loop end
1234
1235 60 MOV R3,R4 ;Put register in R3
1236 BL diss__reg ;Display the register
1237 MOV R6,#2 ;That was the first
1238
1239 70 ADD R4,R4,#1 ;Increment current register
1240 CMP R4,#15 ;Have we finished?
1241 BLE %30diss__mTransfer ;No -- keep on looping
1242 TST R6,#4 ;Are we still in a sequence?
1243 MOVNE R4,#16 ;Yes -- say were on R16
1244 BNE %35diss__mTransfer ;And finish off nicely
1245
1246 ; --- Finish off the instruction ---
1247
1248 MOV R0,#'}' ;Get the closing bracket
1249 STRB R0,[R1],#1 ;Store it
1250 TST R8,#(1<<22) ;Is there a '^'?
1251 MOVNE R0,#'^' ;Yes -- get the character
1252 STRNEB R0,[R1],#1 ;And store that too
1253
1254 LDMFD R13!,{PC}^ ;Return to caller
1255
1256 diss__ldm DCB "LDM",0
1257 diss__stm DCB "STM",0
1258
1259 LTORG
1260
1261 ; --- diss__branch ---
1262 ;
1263 ; On entry: R1 == pointer to buffer to disassemble into
1264 ; R7 == pointer to the start of the buffer
1265 ; R8 == the instruction
1266 ; R9 == location in memory from which instruction came
1267 ;
1268 ; On exit: Lots corrupted
1269 ;
1270 ; Use: Disassembles branch instructions
1271
1272 diss__branch STMFD R13!,{R14} ;Stack the link
1273 MOV R3,#'B' ;It's a B instruction
1274 STRB R3,[R1],#1 ;So store it away
1275 TST R8,#(1<<24) ;Is it BL?
1276 MOVNE R3,#'L' ;Yes -- get the 'L'
1277 STRNEB R3,[R1],#1 ;...and store it in buffer
1278 BL diss__cond ;Put in the condition
1279 MOV R3,#52 ;Tab to here
1280 BL diss__tab ;Do the tab
1281 BIC R0,R8,#&FF000000 ;Get the offset
1282 ADD R0,R9,R0,LSL#2 ;Offset correctld
1283 ADD R0,R0,#8 ;Take pipeline into account
1284 BIC R0,R0,#&FC000000 ;Make sure its not silly
1285 BL diss__address ;Print the address
1286 LDMFD R13!,{PC}^ ;Return to caller
1287
1288 ; --- diss__coDataOp ---
1289 ;
1290 ; On entry: R1 == pointer to buffer to disassemble into
1291 ; R7 == pointer to the start of the buffer
1292 ; R8 == the instruction
1293 ; R9 == location in memory from which instruction came
1294 ;
1295 ; On exit: Lots corrupted
1296 ;
1297 ; Use: Disassembles co-processor data operations
1298
1299
1300 diss__coDataOp ROUT
1301
1302 STMFD R13!,{R14} ;Stack the link
1303 LDR R14,diss__cdp ;Load the mnemonic
1304 STR R14,[R1],#3 ;Store the opcode in buffer
1305 BL diss__cond ;Put the condition code in
1306
1307 10 MOV R3,#52 ;Set up the tab position
1308 BL diss__tab ;And do the tab
1309 MOV R3,#'C' ;Get the 'C'
1310 STRB R3,[R1],#1 ;And store it in buffer
1311 MOV R3,#'P' ;Get the 'P'
1312 STRB R3,[R1],#1 ;And store it in buffer
1313 MOV R0,R8,LSR#8 ;Get cp#
1314 AND R0,R0,#&F ;Clear unwanted bits
1315 MOV R2,#50 ;Say that buffer is big
1316 SWI OS_ConvertInteger1 ;Translate the number
1317 MOV R4,#',' ;Get the ','
1318 STRB R4,[R1],#1 ;And store it in buffer
1319 MOV R0,R8,LSR#20 ;Get cp instruction
1320 AND R0,R0,#&F ;Clear unwanted bits
1321 MOV R2,#50 ;Say that buffer is big
1322 SWI OS_ConvertInteger1 ;Translate the number
1323 STRB R4,[R1],#1 ;Store comma in buffer
1324 MOV R3,R8,LSR#12 ;Get destination register
1325 BL diss__coReg ;Display the register
1326 STRB R4,[R1],#1 ;Store comma in buffer
1327 MOV R3,R8,LSR#16 ;Get CRn
1328 BL diss__coReg ;Display it
1329 STRB R4,[R1],#1 ;Store comma in buffer
1330 MOV R3,R8 ;Get CRm
1331 BL diss__coReg ;Display it
1332 MOV R0,R8,LSR#5 ;Get optional constant
1333 ANDS R0,R0,#&7 ;Clear unwanted bits
1334 STRNEB R4,[R1],#1 ;Store comma in buffer
1335 MOVNE R2,#50 ;...say that buffer is big
1336 SWINE OS_ConvertInteger1 ;...translate the number
1337
1338 LDMFD R13!,{PC}^ ;Return to caller
1339
1340 diss__cdp DCB "CDP",0
1341
1342 LTORG
1343
1344 ; --- diss__coDataTran ---
1345 ;
1346 ; On entry: R1 == pointer to buffer to disassemble into
1347 ; R7 == pointer to the start of the buffer
1348 ; R8 == the instruction
1349 ; R9 == location in memory from which instruction came
1350 ;
1351 ; On exit: Lots corrupted
1352 ;
1353 ; Use: Disassembles co-processor data transfers
1354
1355
1356 diss__coDataTran ROUT
1357
1358 STMFD R13!,{R14} ;Stack the link
1359 TST R8,#(1<<20) ;Is it a load?
1360 LDRNE R14,diss__ldc ;Yes -- load that name
1361 LDREQ R14,diss__stc ;No -- load STC word then
1362 STR R14,[R1],#3 ;Store the opcode in buffer
1363 BL diss__cond ;Put the condition code in
1364 TST R8,#(1<<22) ;Is it long transfer?
1365 MOVNE R3,#'L' ;Yes -- get the 'L'
1366 STRNEB R3,[R1],#1 ;...and store it in buffer
1367
1368 [ 1<>1 ;T on co-processor trandfers
1369 TST R8,#(1<<21) ;Is the W bit set?
1370 BEQ %10diss__coDataTran ;No -- jump ahead a bit
1371 TST R8,#(1<<24) ;How about the P bit?
1372 MOVEQ R3,#'T' ;No -- get a 'T' character
1373 STREQB R3,[R1],#1 ;...and store it in buffer
1374 ]
1375
1376 10 MOV R3,#52 ;Set up the tab position
1377 BL diss__tab ;And do the tab
1378 MOV R3,#'C' ;Get the 'C'
1379 STRB R3,[R1],#1 ;And store it in buffer
1380 MOV R3,#'P' ;Get the 'P'
1381 STRB R3,[R1],#1 ;And store it in buffer
1382 MOV R0,R8,LSR#8 ;Get cp#
1383 AND R0,R0,#&F ;Clear unwanted bits
1384 MOV R2,#50 ;Say that buffer is big
1385 SWI OS_ConvertInteger1 ;Translate the number
1386 MOV R3,#',' ;Get the ','
1387 STRB R3,[R1],#1 ;And store it in buffer
1388 MOV R3,#'C' ;Get the 'C'
1389 STRB R3,[R1],#1 ;And store that in the buffer
1390 MOV R0,R8,LSR#12 ;Get cp#
1391 AND R0,R0,#&F ;Clear unwanted bits
1392 MOV R2,#50 ;Say that buffer is big
1393 SWI OS_ConvertInteger1 ;Translate the number
1394 MOV R3,#',' ;Get the ','
1395 STRB R3,[R1],#1 ;And store it in buffer
1396
1397 ; --- Sabotage into and LDR/STR form ---
1398
1399 BIC R0,R8,#&000000FF ;Clear bottom bits
1400 BIC R0,R0,#&00000F00 ;Those ones too
1401 AND R2,R8,#&FF ;Get the offset
1402 MOV R2,R2,LSL#2 ;Shift it up properley
1403 ORR R0,R0,R2 ;Merge the two words
1404 MOV R8,R0 ;Put new instruction in R8
1405 TST R8,#(1<<24) ;Are we pre-indexing?
1406 BNE diss__preIndexed ;Yes -- deal with it
1407 BEQ diss__postIndexed ;No -- do a post index
1408
1409 diss__ldc DCB "LDC",0
1410 diss__stc DCB "STC",0
1411
1412 LTORG
1413
1414 ; --- diss__coRegTran ---
1415 ;
1416 ; On entry: R1 == pointer to buffer to disassemble into
1417 ; R7 == pointer to the start of the buffer
1418 ; R8 == the instruction
1419 ; R9 == location in memory from which instruction came
1420 ;
1421 ; On exit: Lots corrupted
1422 ;
1423 ; Use: Disassembles co-processor register transfers
1424
1425
1426 diss__coRegTran ROUT
1427
1428 STMFD R13!,{R14} ;Stack the link
1429 TST R8,#(1<<20) ;Is it a co->arc
1430 LDRNE R14,diss__mcr ;Yes -- load that name
1431 LDREQ R14,diss__mrc ;No -- load MRC word then
1432 STR R14,[R1],#3 ;Store the opcode in buffer
1433 BL diss__cond ;Put the condition code in
1434
1435 10 MOV R3,#52 ;Set up the tab position
1436 BL diss__tab ;And do the tab
1437 MOV R3,#'C' ;Get the 'C'
1438 STRB R3,[R1],#1 ;And store it in buffer
1439 MOV R3,#'P' ;Get the 'P'
1440 STRB R3,[R1],#1 ;And store it in buffer
1441 MOV R0,R8,LSR#8 ;Get cp#
1442 AND R0,R0,#&F ;Clear unwanted bits
1443 MOV R2,#50 ;Say that buffer is big
1444 SWI OS_ConvertInteger1 ;Translate the number
1445 MOV R4,#',' ;Get the ','
1446 STRB R4,[R1],#1 ;And store it in buffer
1447 MOV R0,R8,LSR#21 ;Get cp instruction
1448 AND R0,R0,#&7 ;Clear unwanted bits
1449 MOV R2,#50 ;Say that buffer is big
1450 SWI OS_ConvertInteger1 ;Translate the number
1451 STRB R4,[R1],#1 ;Store comma in buffer
1452 MOV R3,R8,LSR#12 ;Get arc register
1453 BL diss__reg ;Display the register
1454 STRB R4,[R1],#1 ;Store comma in buffer
1455 MOV R3,R8,LSR#16 ;Get CRn
1456 BL diss__coReg ;Display it
1457 STRB R4,[R1],#1 ;Store comma in buffer
1458 MOV R3,R8 ;Get CRm
1459 BL diss__coReg ;Display it
1460 MOV R0,R8,LSR#5 ;Get optional constant
1461 ANDS R0,R0,#&7 ;Clear unwanted bits
1462 STRNEB R4,[R1],#1 ;Store comma in buffer
1463 MOVNE R2,#50 ;...say that buffer is big
1464 SWINE OS_ConvertInteger1 ;...translate the number
1465
1466 LDMFD R13!,{PC}^ ;Return to caller
1467
1468 diss__mcr DCB "MCR",0
1469 diss__mrc DCB "MRC",0
1470
1471 LTORG
1472
1473 ; --- diss__swi ---
1474 ;
1475 ; On entry: R1 == pointer to buffer to disassemble into
1476 ; R7 == pointer to the start of the buffer
1477 ; R8 == the instruction
1478 ; R9 == location in memory from which instruction came
1479 ;
1480 ; On exit: Lots corrupted
1481 ;
1482 ; Use: Disassembles swi instructions
1483
1484
1485 diss__swi ROUT
1486
1487 STMFD R13!,{R14} ;Stack the link
1488 LDR R0,diss__swiCode ;Load the opcode
1489 STR R0,[R1],#3 ;Store it in the buffer
1490 BL diss__cond ;Put in the condition
1491 MOV R3,#52 ;Set up the tab position
1492 BL diss__tab ;Do the tabbing
1493 MOV R4,R1 ;Look after the buffer pos
1494 BL str_buffer ;Get a buffer to use
1495 MOV R6,R1 ;Don't lose this either!
1496 BIC R0,R8,#&FF000000 ;Get the swi number
1497 MOV R5,R0 ;Look after this too
1498 MOV R2,#256 ;The buffer size
1499 SWI XOS_SWINumberToString ;Get the SWI name
1500
1501 ; --- Now try to convert back again ---
1502
1503 BIC R2,R5,#(1<<17) ;Clear the X bit
1504 SUB R2,R2,#&100 ;Do a range check between
1505 SUBS R2,R2,#&200 ;...if its OS_WriteI
1506 BLO %10diss__swi ;It is -- return
1507
1508 SWI XOS_SWINumberFromString ;Convert back again
1509 BVC %10diss__swi ;All OK, jump ahead
1510 MOV R1,R6 ;...point to the number
1511 MOV R2,#'&' ;Get the '&' character
1512 STRB R2,[R1],#1 ;Store it in the buffer
1513 MOV R0,R5 ;Put number in R0
1514 MOV R2,#50 ;Say buffer is big
1515 SWI XOS_ConvertHex8 ;And convert the number
1516 MOV R1,R6 ;Point to the number
1517
1518 ; --- Now put the string in the buffer ---
1519
1520 10diss__swi MOV R0,R4 ;Write to here
1521 BL str_cpy ;Copy the string over
1522 MOV R1,R0 ;Make R1 point to buffer end
1523
1524 LDMFD R13!,{PC}^ ;Return to caller
1525
1526 diss__swiCode DCB "SWI",0
1527
1528 LTORG
1529
1530 ; --- diss__cond ---
1531 ;
1532 ; On entry: R1 == position in buffer to put string
1533 ; R8 == the instruction
1534 ;
1535 ; On exit: --
1536 ;
1537 ; Use: Inserts the condition code into the buffer
1538
1539 diss__cond ROUT
1540
1541 MOV R3,R8,LSR#28 ;Get the condition code
1542 ADR R4,diss__condTable ;Point to the table
1543 ADD R4,R4,R3,LSL#2 ;Point to the string
1544 LDRB R2,[R4],#1 ;Get a byte
1545 CMP R2,#0 ;Am I there yet
1546 STRNEB R2,[R1],#1 ;Store the byte
1547 LDRNEB R2,[R4],#1 ;Get a byte
1548 CMPNE R2,#0 ;Am I there yet
1549 STRNEB R2,[R1],#1 ;Store the byte
1550 MOVS PC,R14 ;Return to caller
1551
1552 diss__condTable DCB "EQ",0,0
1553 DCB "NE",0,0
1554 DCB "CS",0,0
1555 DCB "CC",0,0
1556 DCB "MI",0,0
1557 DCB "PL",0,0
1558 DCB "VS",0,0
1559 DCB "VC",0,0
1560 DCB "HI",0,0
1561 DCB "LS",0,0
1562 DCB "GE",0,0
1563 DCB "LT",0,0
1564 DCB "GT",0,0
1565 DCB "LE",0,0
1566 DCB 0,0,0,0
1567 DCB "NV",0,0
1568
1569 ; --- diss__tab ---
1570 ;
1571 ; On entry: R1 == Current position within buffer
1572 ; R3 == tab position required
1573 ; R7 == start of the buffer
1574 ;
1575 ; On exit: R1 updated appropriately
1576 ;
1577 ; Use: Inserts as many spaces as in nessesary to get to the
1578 ; right position in the buffer.
1579
1580 diss__tab ROUT
1581
1582 ADD R4,R7,R3 ;Word out the offset
1583 MOV R2,#' ' ;Get a space character
1584 00diss__tab STRB R2,[R1],#1 ;Store the sapce character
1585 CMP R1,R4 ;Have we finished yet?
1586 BLT %00diss__tab ;No -- keep looping
1587 MOVS PC,R14 ;Return
1588
1589 LTORG
1590
1591 ; --- diss__reg ---
1592 ;
1593 ; On entry: R1 == position in buffer to write register name
1594 ; R3 == register number to write (in bottom 4 bits)
1595 ;
1596 ; On exit: R1 updated
1597 ;
1598 ; Use: Writes a register name to the output buffer
1599
1600 diss__reg ROUT
1601
1602 STMFD R13!,{R14} ;Save some registers
1603 ADR R14,ws__names ;Find the register names
1604 AND R3,R3,#15 ;Hack off unwanted bits
1605 MOV R0,R1 ;Point to the output buffer
1606 LDR R1,[R14,R3,LSL #2] ;Find the name I want
1607 BL str_cpy ;Copy the string out
1608 MOV R1,R0 ;Point to string terminator
1609 LDMFD R13!,{PC}^ ;Return to caller
1610
1611 LTORG
1612
1613 ; --- diss__coReg ---
1614 ;
1615 ; On entry: R1 == position in buffer to write register name
1616 ; R3 == register number to write (in bottom 4 bits)
1617 ;
1618 ; On exit: R1 updated
1619 ;
1620 ; Use: Writes a co-processor register name to the output buffer
1621
1622 diss__coReg ROUT
1623
1624 STMFD R13!,{R14} ;Save some registers
1625 AND R0,R3,#15 ;Hack off unwanted bits
1626 MOV R14,#'C' ;Get the prefix
1627 STRB R14,[R1],#1 ;Store it
1628 MOV R2,#50 ;Say buffer is big
1629 SWI OS_ConvertInteger1 ;Write number into buffer
1630 LDMFD R13!,{PC}^ ;Return to caller
1631
1632 LTORG
1633
1634 ; --- diss__address ---
1635 ;
1636 ; On entry: R0 == an address to display
1637 ; R1 == pointer to where to store it
1638 ;
1639 ; On exit: R1 updated
1640 ;
1641 ; Use: Displays an address, looking it up in the symbol table
1642 ; and trying to turn it into a label if possible.
1643 ;
1644 ; (26-Aug-1994 Symbol table not implemented)
1645
1646 diss__address ROUT
1647
1648 STMFD R13!,{R14} ;Stash the link away
1649 MOV R14,#'&' ;The address is in hex
1650 STRB R14,[R1],#1 ;Store it in the buffer
1651 MOV R2,#50 ;Please fondle my buffer (?)
1652 SWI XOS_ConvertHex8 ;Convert to nice address
1653 LDMFD R13!,{PC}^ ;Return to caller
1654
1655 LTORG
1656
1657 ; --- diss_regTable ---
1658 ;
1659 ; On entry: --
1660 ;
1661 ; On exit: R0 == pointer to register table
1662 ;
1663 ; Use: Returns a pointer to the register name table, so that the
1664 ; assembler can get its grubby paws on it.
1665
1666 EXPORT diss_regTable
1667 diss_regTable ROUT
1668
1669 LDR R0,diss__wSpace ;Find the workspace address
1670 ADD R0,R0,#:INDEX: ws__names
1671 MOVS PC,R14 ;Return to caller
1672
1673 LTORG
1674
1675 ; --- diss_init ---
1676 ;
1677 ; On entry: R12 == pointer to workspace
1678 ;
1679 ; On exit: --
1680 ;
1681 ; Use: Initialises the disassembler segment nicely.
1682
1683 EXPORT diss_init
1684 diss_init ROUT
1685
1686 STMFD R13!,{R0-R3,R14} ;Stack what we need
1687
1688 ; --- If we are already initialised, return ---
1689
1690 LDR R0,ws__flags ;Load my flags word
1691 TST R0,#wFlag__inited ;Are we initialised?
1692 BNE %99diss_init ;Yes -- return
1693
1694 ORR R0,R0,#wFlag__inited ;We are initialised now
1695 STR R0,ws__flags ;Store this fact
1696
1697 ; --- Set up the default options ---
1698
1699 MOV R0,#0 ;The default options
1700 STR R0,ws__options ;Store them here
1701
1702 ; --- Set up the default register names ---
1703
1704 BL quartz_base ;Find the module base
1705 ADR R1,ws__names ;Point to the name table
1706 ADR R2,diss__defNames ;Point to default name table
1707 MOV R3,#16 ;Copy over this many
1708
1709 10diss_init LDR R14,[R2],#4 ;Get a name pointer
1710 ADD R14,R14,R0 ;Relocate the name pointer
1711 STR R14,[R1],#4 ;Copy it over
1712 SUBS R3,R3,#1 ;Decrement the counter
1713 BNE %10diss_init ;More to go -- do them
1714
1715 99diss_init LDMFD R13!,{R0-R3,PC}^ ;Return to caller
1716
1717 LTORG
1718
1719 diss__wSpace DCD 0
1720
1721 diss__defNames DCD dName__R0,dName__R1,dName__R2,dName__R3
1722 DCD dName__R4,dName__R5,dName__R6,dName__R7
1723 DCD dName__R8,dName__R9,dName__R10,dName__R11
1724 DCD dName__R12,dName__R13,dName__R14,dName__R15
1725
1726 dName__R0 DCB "R0",0
1727 dName__R1 DCB "R1",0
1728 dName__R2 DCB "R2",0
1729 dName__R3 DCB "R3",0
1730 dName__R4 DCB "R4",0
1731 dName__R5 DCB "R5",0
1732 dName__R6 DCB "R6",0
1733 dName__R7 DCB "R7",0
1734 dName__R8 DCB "R8",0
1735 dName__R9 DCB "R9",0
1736 dName__R10 DCB "R10",0
1737 dName__R11 DCB "R11",0
1738 dName__R12 DCB "R12",0
1739 dName__R13 DCB "R13",0
1740 dName__R14 DCB "R14",0
1741 dName__R15 DCB "PC",0
1742
1743 ;----- Workspace ------------------------------------------------------------
1744
1745 ^ 0,R12
1746
1747 ws__start # 0
1748
1749 ws__flags # 4 ;The main flags word
1750 ws__options # 4 ;Disassembler options
1751 ws__commentEnd # 4 ;End of the current comment
1752 ws__lastReg # 1 ;Register in ADR / LDR
1753 ws__lastCond # 3 ;Last condition code thing
1754 ws__lastAddr # 4 ;Address from ADR / LDR
1755 ws__nextAddr # 4 ;Address of next instruction
1756 ws__names # 16*4 ;Table of register names
1757 ws__buffer # 256 ;Somewhere to put the string
1758 ws__comment # 80 ;Somewhere to put comments
1759
1760 ws__size EQU {VAR}-ws__start ;The workspace size
1761
1762 wFlag__inited EQU (1<<0) ;We are initialised
1763 wFlag__wasAdr EQU (1<<1) ;Last instruction was ADR
1764 wFlag__newAdr EQU (1<<2) ;This instruction is ADR
1765
1766 dOpt__bitHex EQU (1<<0) ;Display bitwise in hex
1767 dOpt__arthHex EQU (1<<1) ;Display arithmetic in hex
1768 dOpt__tranHex EQU (1<<2) ;Display data transfer in hex
1769 dOpt__r13Stack EQU (1<<3) ;Use FD etc. if R13 is base
1770
1771 AREA |Quartz$$Table|,CODE,READONLY
1772
1773 DCD ws__size
1774 DCD diss__wSpace
1775 DCD diss_init
1776 DCD 0
1777
1778 ;----- That's all, folks ----------------------------------------------------
1779
1780 END