4 ; Superior Disassembly of ARM instructions (TMA)
6 ; © 1994-1998 Straylight
9 ;----- Licensing note -------------------------------------------------------
11 ; This file is part of Straylight's Sledgehammer debugger.
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)
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.
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.
27 ;----- Things to do ---------------------------------------------------------
29 ; Disassemble Floating point instructions
33 ;----- Standard header ------------------------------------------------------
39 ;----- External dependencies ------------------------------------------------
44 ;----- Main code ------------------------------------------------------------
46 AREA |Hammer$$Code|,CODE,READONLY
48 ; --- diss_setOptions ---
50 ; On entry: R0 == new options field
54 ; Use: Sets up the new display options for the disassembly
56 EXPORT diss_setOptions
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
65 ; --- diss_address ---
67 ; On entry: R0 == address to start disassembly
71 ; Use: Initialises the disassembly to start at the given address
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
86 ; --- diss_disassemble ---
88 ; On entry: R0 == the instruction itself
90 ; On exit: R0 == pointer to buffer containing disassembly of
93 ; Use: Disassembles the instruction given, and places
94 ; the resulting string in the returned buffer.
96 EXPORT diss_disassemble
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
104 ; --- We don't have any comments yet ---
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
111 ; --- Sort out the flags ---
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
119 ; --- First do the address ---
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
127 MOV R3,#' ' ;A nice space
128 STRB R3,[R1],#1 ;Put it in the buffer
130 ; --- Display the label ---
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
137 MOV R3,#' ' ;A nice space
138 STRB R3,[R1],#1 ;Put it in the buffer
140 ; --- Display the word ---
142 MOV R0,R8 ;Load the word into R0
143 MOV R2,#16 ;The buffer size
144 SWI OS_ConvertHex8 ;Convert the address
146 MOV R3,#' ' ;A nice space
147 STRB R3,[R1],#1 ;Put it in the buffer
149 ; --- Display the ASCII field ---
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
160 MOV R3,#' ' ;A nice space
161 STRB R3,[R1],#1 ;Put it in the buffer
163 ; --- Disassemble the instruction ---
165 AND R0,R8,#&0F000000 ;Get just the opcode
166 MOV R0,R0,LSR#26 ;Get top two bits of opcode
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
177 ; --- Return to caller ---
179 90 LDRB R14,ws__comment ;Is there a comment?
180 CMP R14,#0 ;Look and see
181 BEQ %95diss_disassemble ;No -- jump ahead
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
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
198 ; --- diss__showChar ---
200 ; On entry: R0 == character to display
201 ; R1 == address to insert character
205 ; Use: Inserts the character in the bottom 8 bits of R0 into
206 ; the buffer pointed to by R1
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
219 ; --- diss__addComment ---
221 ; On entry: R0 == pointer to comment to add
223 ; On exit: R0 corrupted
225 ; Use: Adds the given comment to the current one
227 diss__addComment ROUT
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
240 ; --- diss__typeXX ---
242 ; On entry: R1 == buffer position to write to
243 ; R8 == the instruction
244 ; R9 == address from which instruction came
246 ; On exit: R0,R2-R6,R10-R12 possibly corrupted
248 ; Use: Disassemble instructions with an opcode prefix of XX.
252 AND R5,R8,#&0FC00000 ;Get the op code
253 AND R6,R8,#&000000F0 ;We need these bits too
255 ; --- See if it is a multiply instruction ---
257 CMP R5,#0 ;Multiply instruction?
258 CMPEQ R6,#&90 ;Double check
259 BEQ diss__multiply ;Yes -- deal with it then
261 ; --- Is it a SWP instruction ---
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
268 ; --- Is it an undefined operation? ---
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
276 ; --- It must be a data processing operation then ---
278 B diss__aluOp ;Dissassemble an ALU op
284 ; --- See if it's undefined ---
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
290 ; --- So it must be a data transfer ---
292 B diss__sTransfer ;Deal with it
298 ; --- Test to see if it's a branch ---
300 TST R8,#(1<<25) ;Is this bit set?
301 BNE diss__branch ;Yes -- it's a branch
303 ; --- It must be a multiple load then ---
305 B diss__mTransfer ;Disassemble it
311 TST R8,#(1<<25) ;Is this bit clear?
312 BEQ diss__coDataTran ;Yes -- do co proc data trans
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
318 TST R8,#(1<<4) ;Is it a coregister transfer?
319 BNE diss__coRegTran ;Yes -- deal with it
321 B diss__coDataOp ;Do a co-proc data op
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
334 diss__undef DCB "Undefined instruction",0
338 ; --- diss__multiply ---
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
345 ; On exit: R0,R2,R3,R4 corrupted
347 ; Use: Dissassembles a multiply instruction
352 STMFD R13!,{R14} ;Stack the link register
354 ; --- Set up the opcode in the buffer ---
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
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
366 MOV R3,#52 ;Tab to here please
367 BL diss__tab ;Do a 'tab' character
369 ; --- Write out the registers ---
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
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
395 LDMFD R13!,{PC}^ ;Return to caller
397 diss__mla DCB "MLA",0
398 diss__mul DCB "MUL",0
400 diss__mulErr1 DCB "! Rd=PC ",0
401 diss__mulErr2 DCB "! Rd=Rm ",0
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
412 ; On exit: R0,R2,R3,R4 corrupted
414 ; Use: Dissassembles an SWP operation instruction
419 STMFD R13!,{R14} ;Stack the link register
421 ; --- Set up the opcode in the buffer ---
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
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
431 MOV R3,#52 ;Tab to here please
432 BL diss__tab ;Do a 'tab' character
434 ; --- Write out the registers ---
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
453 LDMFD R13!,{PC}^ ;Return to caller
455 diss__swpName DCB "SWP",0
456 diss__swpComment DCB "Not available on ARM 2",0
458 ; --- diss__aluOp ---
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
465 ; On exit: R0,R2-R6,R10 corrupted
467 ; Use: Dissassembles an ALU operation instruction
471 STMFD R13!,{R14} ;Save some register(s)
473 ; --- Display the opcode nicely ---
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
481 ; --- Check for ADR instructions ---
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
493 ; --- Just do it the old fashioned way (oo-er) ---
495 05diss__aluOp STR R3,[R1],#3 ;Store the opcode
496 BL diss__cond ;Add on the condition code
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
504 ; --- Handle the `P' suffix on CMP instructions ---
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
514 10diss__aluOp MOV R3,#52 ;Get the tab position
515 BL diss__tab ;And move the position on
517 ; --- Output the operands ---
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
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
530 ; --- Oh no -- it's the last operand ---
532 TST R8,#(1<<25) ;Is it an immediate op?
533 BNE %50diss__aluOp ;Yes -- AAARRRGHHHH
535 MOV R3,R8 ;Get the Op2 register
536 BL diss__reg ;Display it nicely
538 ; --- It's fun with shifts time, boys and girls ---
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
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
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
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
564 ; --- Now deal with immediate constants ---
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
571 ; --- Add a comment if we need to ---
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
590 ; --- Handle possible ADRLs ---
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
605 ; --- It's an ADRL -- it's official ---
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
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
638 ; --- Display the mystic hash sign ---
640 55diss__aluOp MOV R14,#'#' ;Get a hash sign
641 STRB R14,[R1],#1 ;Add it to the string
643 ; --- Now work out how we want to display it ---
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
651 ; --- Display the constant in decimal ---
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
657 ; --- Display it in hexadecimal ---
659 60diss__aluOp BL diss__displayHex ;Print the hex value
660 B %90diss__aluOp ;Return to caller
662 ; --- Display an ADR pseudo instruction ---
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
670 ; --- Set up the flags to say this was an ADR ---
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
678 ; --- Display the destination register ---
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
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
698 90diss__aluOp LDMFD R13!,{PC}^ ;Return to caller
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)
706 diss__adr DCB "ADR",0
708 diss__aluTable DCB "AND",0
709 DCD dFlag__bitwise+dFlag__nonCmp
711 DCD dFlag__bitwise+dFlag__nonCmp
713 DCD dFlag__adrable+dFlag__nonCmp
715 DCD dFlag__multiply+dFlag__nonCmp
718 DCD dFlag__multiply+dFlag__adrable+dFlag__nonCmp
736 DCD dFlag__bitwise+dFlag__nonCmp
738 DCD dFlag__noMiddle+dFlag__multiply+dFlag__nonCmp
740 DCD dFlag__bitwise+dFlag__nonCmp
742 DCD dFlag__noMiddle+dFlag__nonCmp
744 diss__chMess DCB "='%c0'",0
749 diss__shifts DCB "LSL "
755 ; --- diss__shift ---
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
763 ; On exit: R3,R4 corrupted
765 ; Use: Disassemble a constant controlled shift
770 STMFD R13!,{R14} ;Stack the link register
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
776 CMP R3,#&060 ;Is it an RRX?
777 BNE %10diss__shift ;No -- do other things then
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
790 ; --- Do ordinary things now ---
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
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
803 ; --- Add in the multipy comment ---
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
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?
820 12 MOV R5,#1 ;We start with 1
821 MOV R5,R5,LSL R0 ;Work out the multiply
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
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
847 ; --- Display the shift ---
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
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
866 ; --- diss__displayHex ---
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
874 ; On exit: R0,R2,R3 corrupted
876 ; Use: Displays a hex number without leading NULL bytes
878 diss__displayHex ROUT
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
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
902 LDMFD R13!,{PC}^ ;Return to caller
904 diss__hexDigits DCB "0123456789ABCDEF"
908 ; --- diss__sTransfer ---
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
915 ; On exit: Lots corrupted
917 ; Use: Disassemble LDR/STR instructions, putting the result into
922 STMFD R13!,{R14} ;Stack the link register
924 ; --- Display the instruction ---
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
935 ; --- Display the 'T' suffix ---
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
943 ; --- Now the destination register ---
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
955 diss__ldr DCB "LDR",0
956 diss__str DCB "STR",0
960 ; --- diss__preIndexed ---
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
968 ; On exit: Lots corrupted
970 ; Use: Disassembles the pre-indexed part of a data transfer op.
972 diss__preIndexed ROUT
974 ; --- Deal with the base register ---
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
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
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
999 TST R8,#(1<<25) ;Is data immediate?
1000 MOV R5,#0 ;The flags word
1001 BEQ %10diss__preIndexed ;Yes -- deal with it
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
1008 ; --- Now work out how we want to display constant ---
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
1016 ; --- Finish off the instruction ---
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
1024 LDMFD R13!,{PC}^ ;Return to caller
1028 ; --- diss__postIndexed ---
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
1036 ; On exit: Lots corrupted
1038 ; Use: Disassembles the post-indexed part of a data transfer op.
1040 diss__postIndexed ROUT
1042 ; --- Deal with the base register ---
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
1051 ; --- Is there any post index to display ---
1053 MOV R5,#&FF ;Prepare the bit mask
1054 ORR R5,R5,#&F00 ;Finish it off
1055 AND R0,R8,R5 ;Get the offset
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
1066 TST R8,#(1<<25) ;Is data immediate?
1067 BEQ %10diss__postIndexed ;Yes -- deal with it
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
1075 ; --- Now work out how we want to display constant ---
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
1083 LDMFD R13!,{PC}^ ;Return to caller
1087 ; --- diss__pcRel ---
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
1095 ; On exit: Lots corrupted
1097 ; Use: Disassembles PC relative data transfer instructions
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
1114 ; --- diss__mTransfer ---
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
1121 ; On exit: Lots corrupted
1123 ; Use: Disassembles LDM/STM instruction
1125 diss__mTransfer ROUT
1127 STMFD R13!,{R14} ;Stack the link
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
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
1145 ; --- Work out stack type (FD etc.) ---
1147 TST R8,#(1<<20) ;Yes -- Are we storing?
1148 BNE %05diss__mTransfer ;No -- do load seperatley
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
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
1170 ; --- Word out stack type normally ---
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
1182 ; --- Continue the disassembly ---
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
1196 ; --- Now do the register list ---
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
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
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
1219 ; --- The register is in the list ---
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
1235 60 MOV R3,R4 ;Put register in R3
1236 BL diss__reg ;Display the register
1237 MOV R6,#2 ;That was the first
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
1246 ; --- Finish off the instruction ---
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
1254 LDMFD R13!,{PC}^ ;Return to caller
1256 diss__ldm DCB "LDM",0
1257 diss__stm DCB "STM",0
1261 ; --- diss__branch ---
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
1268 ; On exit: Lots corrupted
1270 ; Use: Disassembles branch instructions
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
1288 ; --- diss__coDataOp ---
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
1295 ; On exit: Lots corrupted
1297 ; Use: Disassembles co-processor data operations
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
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
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
1338 LDMFD R13!,{PC}^ ;Return to caller
1340 diss__cdp DCB "CDP",0
1344 ; --- diss__coDataTran ---
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
1351 ; On exit: Lots corrupted
1353 ; Use: Disassembles co-processor data transfers
1356 diss__coDataTran ROUT
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
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
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
1397 ; --- Sabotage into and LDR/STR form ---
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
1409 diss__ldc DCB "LDC",0
1410 diss__stc DCB "STC",0
1414 ; --- diss__coRegTran ---
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
1421 ; On exit: Lots corrupted
1423 ; Use: Disassembles co-processor register transfers
1426 diss__coRegTran ROUT
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
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
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
1466 LDMFD R13!,{PC}^ ;Return to caller
1468 diss__mcr DCB "MCR",0
1469 diss__mrc DCB "MRC",0
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
1480 ; On exit: Lots corrupted
1482 ; Use: Disassembles swi instructions
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
1501 ; --- Now try to convert back again ---
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
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
1518 ; --- Now put the string in the buffer ---
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
1524 LDMFD R13!,{PC}^ ;Return to caller
1526 diss__swiCode DCB "SWI",0
1530 ; --- diss__cond ---
1532 ; On entry: R1 == position in buffer to put string
1533 ; R8 == the instruction
1537 ; Use: Inserts the condition code into the buffer
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
1552 diss__condTable DCB "EQ",0,0
1571 ; On entry: R1 == Current position within buffer
1572 ; R3 == tab position required
1573 ; R7 == start of the buffer
1575 ; On exit: R1 updated appropriately
1577 ; Use: Inserts as many spaces as in nessesary to get to the
1578 ; right position in the buffer.
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
1593 ; On entry: R1 == position in buffer to write register name
1594 ; R3 == register number to write (in bottom 4 bits)
1596 ; On exit: R1 updated
1598 ; Use: Writes a register name to the output buffer
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
1613 ; --- diss__coReg ---
1615 ; On entry: R1 == position in buffer to write register name
1616 ; R3 == register number to write (in bottom 4 bits)
1618 ; On exit: R1 updated
1620 ; Use: Writes a co-processor register name to the output buffer
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
1634 ; --- diss__address ---
1636 ; On entry: R0 == an address to display
1637 ; R1 == pointer to where to store it
1639 ; On exit: R1 updated
1641 ; Use: Displays an address, looking it up in the symbol table
1642 ; and trying to turn it into a label if possible.
1644 ; (26-Aug-1994 Symbol table not implemented)
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
1657 ; --- diss_regTable ---
1661 ; On exit: R0 == pointer to register table
1663 ; Use: Returns a pointer to the register name table, so that the
1664 ; assembler can get its grubby paws on it.
1666 EXPORT diss_regTable
1669 LDR R0,diss__wSpace ;Find the workspace address
1670 ADD R0,R0,#:INDEX: ws__names
1671 MOVS PC,R14 ;Return to caller
1677 ; On entry: R12 == pointer to workspace
1681 ; Use: Initialises the disassembler segment nicely.
1686 STMFD R13!,{R0-R3,R14} ;Stack what we need
1688 ; --- If we are already initialised, return ---
1690 LDR R0,ws__flags ;Load my flags word
1691 TST R0,#wFlag__inited ;Are we initialised?
1692 BNE %99diss_init ;Yes -- return
1694 ORR R0,R0,#wFlag__inited ;We are initialised now
1695 STR R0,ws__flags ;Store this fact
1697 ; --- Set up the default options ---
1699 MOV R0,#0 ;The default options
1700 STR R0,ws__options ;Store them here
1702 ; --- Set up the default register names ---
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
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
1715 99diss_init LDMFD R13!,{R0-R3,PC}^ ;Return to caller
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
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
1743 ;----- Workspace ------------------------------------------------------------
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
1760 ws__size EQU {VAR}-ws__start ;The workspace size
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
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
1771 AREA |Quartz$$Table|,CODE,READONLY
1778 ;----- That's all, folks ----------------------------------------------------