chiark / gitweb /
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