chiark / gitweb /
Initial revision
[ssr] / StraySrc / Hammer / s / asm
1 ;
2 ; asm.s
3 ;
4 ; Assembly of 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 ;----- Standard header ------------------------------------------------------
28
29                 GET     libs:header
30                 GET     libs:swis
31                 GET     libs:stream
32
33 ;----- External dependencies ------------------------------------------------
34
35                 GET     quartz:string
36
37                 GET     sh.diss
38
39 ;----- Main code ------------------------------------------------------------
40
41                 AREA    |Hammer$$Code|,CODE,READONLY
42
43 ; --- asm_assemble ---
44 ;
45 ; On entry:     R0 == pointer to the instruction to assemble
46 ;               R1 == address at which to assemble instruction
47 ;
48 ; On exit:      VC and R0 == the assembled instruction
49 ;               VS and R0 == pointer to an error
50 ;
51 ; Use:          Assembles the given insruction, returning the result in
52 ;               R0. The instruction is NOT placed into the memory location
53 ;               passed in R1.
54
55                 EXPORT  asm_assemble
56 asm_assemble    ROUT
57
58
59                 STMFD   R13!,{R1-R9,R14}        ;Stack some registers
60
61                 ; --- Set up 'global' registers ---
62
63                 MOV     R9,#0                   ;Instruction so far
64                 MOV     R8,R0                   ;Put string pointer in R8
65                 MOV     R7,R1                   ;And address in R7
66
67                 ; --- Read the opcode ---
68
69                 BL      asm__readOpcode         ;Read opcode
70
71                 MOVVC   R0,R9                   ;Place instruction in R0
72                 LDMFD   R13!,{R1-R9,R14}        ;Load registers
73                 ORRVSS  PC,R14,#V_flag          ;Return with error
74                 BICVCS  PC,R14,#V_flag          ;Or hopefully without
75
76                 LTORG
77
78 ; --- asm__readOpcode ---
79 ;
80 ; On entry:     R8 == pointer into the instruction
81 ;               R9 == instruction so far
82 ;
83 ; On exit:      VS and R0 == pointer to error or
84 ;               VC and R8,R9 updated appropriately
85 ;
86 ; Use:          Reads in the current opcode, and deals with it
87
88 asm__readOpcode ROUT
89
90                 ; --- First, try to find the opcode number ---
91
92                 STMFD   R13!,{R14}              ;Save link for a bit
93                 LDRB    R0,[R8,#0]              ;Get a byte from input
94                 CMP     R0,#'B'                 ;Is it a 'B'?
95                 CMPNE   R0,#'b'
96                 BNE     %00asm__readOpcode      ;No -- skip ahead
97                 LDRB    R0,[R8,#1]              ;Get the next byte
98                 CMP     R0,#'I'                 ;Is it an 'I'
99                 CMPNE   R0,#'i'
100                 LDMNEFD R13!,{R14}              ;No -- get the link back
101                 BNE     asm__branch             ;...it must be a branch
102
103 00              ADR     R6,asm__opTable         ;Point to opcode table
104                 BL      asm__lookup             ;Try to find it in there
105                 LDMFD   R13!,{R14}              ;Restore link again
106                 ADDCC   R8,R8,#3                ;Skip past the opcode
107                 ADDCC   PC,PC,R5,LSL#2          ;Jump to handling routine
108                 B       %80asm__readOpcode      ;If not there, moan
109
110                 B       asm__aluOp3             ;AND
111                 B       asm__aluOp3             ;EOR
112                 B       asm__aluOp3             ;SUB
113                 B       asm__aluOp3             ;RSB
114                 B       asm__aluOp3             ;ADD
115                 B       asm__aluOp3             ;ADC
116                 B       asm__aluOp3             ;SBC
117                 B       asm__aluOp3             ;RSC
118                 B       asm__aluOp3             ;ORR
119                 B       asm__aluOp3             ;BIC
120                 B       asm__aluOp2             ;MOV
121                 B       asm__aluOp2             ;MVN
122                 B       asm__aluOpTest          ;TST
123                 B       asm__aluOpTest          ;TEQ
124                 B       asm__aluOpTest          ;CMP
125                 B       asm__aluOpTest          ;CMN
126                 B       asm__multiply           ;MUL
127                 B       asm__multiply           ;MLA
128                 B       asm__sDataTrans         ;LDR
129                 B       asm__sDataTrans         ;STR
130                 B       asm__mDataTrans         ;LDM
131                 B       asm__mDataTrans         ;STM
132                 B       asm__swi                ;SWI
133                 B       asm__adr                ;ADR
134                 B       asm__swp                ;SWP
135                 B       asm__cdp                ;CDP
136                 B       asm__coDataTrans        ;STC
137                 B       asm__coDataTrans        ;LDC
138                 B       asm__coRegTrans         ;MRC
139                 B       asm__coRegTrans         ;MCR
140
141 80              ADR     R0,asm__noOpcode        ;Point to the error message
142                 ORRS    PC,R14,#V_flag          ;Return to caller
143
144 asm__opTable    DCB     "AND",0,"EOR",0,"SUB",0,"RSB",0,"ADD",0,"ADC",0
145                 DCB     "SBC",0,"RSC",0,"ORR",0,"BIC",0,"MOV",0,"MVN",0
146                 DCB     "TST",0,"TEQ",0,"CMP",0,"CMN",0,"MUL",0,"MLA",0
147                 DCB     "LDR",0,"STR",0,"LDM",0,"STM",0,"SWI",0,"ADR",0
148                 DCB     "SWP",0,"CDP",0,"STC",0,"LDC",0,"MRC",0,"MCR",0
149                 DCD     0
150
151 asm__noOpcode   DCD     1
152                 DCB     "Unknown opcode",0
153
154                 LTORG
155
156 ; --- asm__lookup ---
157 ;
158 ; On entry:     R6 == pointer to lookup table, with values in words
159 ;               R8 == pointer to three character thing to read
160 ;
161 ; On exit:      CC if found, and R5 == index into table of match
162 ;               CS if not found
163 ;               R0-R2, R6 corrupted horridly
164
165 asm__lookup     ROUT
166
167                 MOV     R5,#0                   ;Zero the initial index
168
169                 BIC     R0,R8,#3                ;Get base of thingy
170                 AND     R2,R8,#3                ;Get non-wordalignedness
171                 LDMIA   R0,{R0,R1}              ;Load the possible bytes
172                 MOVS    R2,R2,LSL #3            ;Shift offset up to bytes
173                 MOVNE   R0,R0,LSR R2            ;Shift that bit down
174                 RSBNE   R2,R2,#32               ;Work out the other shift
175                 ORRNE   R0,R0,R1,LSL R2         ;Mix in the top bits
176                 BIC     R0,R0,#&FF000000        ;Clear the top byte
177                 BIC     R0,R0,#&00200000        ;Force to upper case
178                 BIC     R0,R0,#&00002000        ;Force to upper case
179                 BIC     R0,R0,#&00000020        ;Force to upper case
180
181 00asm__lookup   LDR     R1,[R6],#4              ;Get an entry from table
182                 CMP     R1,#0                   ;Are we at end of the table
183                 ORREQS  PC,R14,#C_flag          ;Yes -- return failure
184                 CMP     R1,R0                   ;Are the strings the same?
185                 ADDNE   R5,R5,#1                ;No -- inc instruction no.
186                 BNE     %00asm__lookup          ;And keep looking
187
188                 BICS    PC,R14,#C_flag          ;Found it -- return C clear
189
190                 LTORG
191
192 ; --- asm__condition ---
193 ;
194 ; On entry:     R8 == pointer into the instruction
195 ;               R9 == instruction so far
196 ;
197 ; On exit:      VS and R0 == pointer to error or
198 ;               VC and R8,R9 updated appropriately
199 ;                      R0,R1,R5,R6 corrupted
200 ;
201 ; Use:          Reads in the current opcode, and deals with it
202
203 asm__condition  ROUT
204
205                 ADR     R6,asm__condTable       ;Point to the table
206                 LDRB    R0,[R8,#0]              ;Get a character
207                 CMP     R0,#32                  ;Is it a control character?
208                 ORRLE   R9,R9,#&E0000000        ;Yes -- make it 'AL'
209                 MOVLES  PC,R14                  ;Return to caller
210                 MOV     R5,#0                   ;Set up the count again
211 00              LDRB    R0,[R8,#0]              ;Get a character
212                 BIC     R0,R0,#&00000020        ;Force to upper case
213                 LDRB    R1,[R6],#2              ;Get a byte from the table
214                 BIC     R1,R1,#&00000020        ;Force to upper case
215                 CMP     R0,R1                   ;Are they the same
216                 LDREQB  R0,[R8,#1]              ;Yes -- get another character
217                 BICEQ   R0,R0,#&00000020        ;...force to upper case
218                 LDREQB  R1,[R6,#-1]             ;...and one from the table
219                 BICEQ   R1,R1,#&00000020        ;...force to upper case
220                 CMPEQ   R0,R1                   ;...and compare them
221                 ORREQ   R9,R9,R5,LSL #28        ;If we've found it, yippee
222                 ADDEQ   R8,R8,#2                ;...skip past condition code
223                 MOVEQS  PC,R14                  ;...and return to caller
224                 ADD     R5,R5,#1                ;Increment the counter
225                 CMP     R5,#21                  ;Have we tried them all?
226                 BLE     %00asm__condition       ;And keep trying if not
227                 ORR     R9,R9,#&E0000000        ;Make it 'AL'
228                 MOVS    PC,R14                  ;Return to caller
229
230 asm__condTable  DCB     "EQ","NE","CS","CC","MI","PL","VS","VC"
231                 DCB     "HI","LS","GE","LT","GT","LE","AL","NV"
232                 DCB     "ZS","ZC","HS","LO","NS","NC"
233
234                 LTORG
235
236 ; --- asm__doSBit ---
237 ;
238 ; On entry:     R8 == pointer into the instruction
239 ;               R9 == instruction so far
240 ;
241 ; On exit:      VS and R0 == pointer to error or
242 ;               VC and R8,R9 updated appropriately
243 ;
244 ; Use:          Reads in an optional 'S', setting the bit, and then skips
245 ;               the following spaces (ensuring that there is at least one).
246
247 asm__doSBit     ROUT
248                 STMFD   R13!,{R14}              ;Stack the link register
249
250                 LDRB    R14,[R8,#0]             ;Read another byte
251                 CMP     R14,#'S'                ;Is it an 'S'?
252                 CMPNE   R14,#'s'
253                 ORREQ   R9,R9,#(1<<20)          ;Yes -- set the bit
254                 ADDEQ   R8,R8,#1                ;...skip past the 'S'
255                 LDREQB  R14,[R8,#0]             ;...and read another byte
256                 CMP     R14,#' '                ;Is it a space?
257                 CMPNE   R14,#9                  ;Allow a tab here too
258                 ADRNE   R0,asm__opcJunk         ;No -- something odd's there
259                 BNE     %95asm__doSBit          ;So moan about it then
260
261 10asm__doSBit   LDRB    R14,[R8],#1             ;Load the next byte
262                 CMP     R14,#' '                ;Is it a space?
263                 CMPNE   R14,#9                  ;Allow a tab here too
264                 BEQ     %10asm__doSBit          ;Yes -- ignore it then
265                 SUB     R8,R8,#1                ;We overstepped the mark
266
267                 LDMFD   R13!,{R14}              ;Get the link back
268                 BICS    PC,R14,#V_flag          ;Return without error
269
270 95asm__doSBit   LDMFD   R13!,{R14}              ;Get the link back
271                 ORRS    PC,R14,#V_flag          ;Return without error
272
273                 LTORG
274
275 asm__opcJunk    DCD     1
276                 DCB     "Rubbish on end of opcode",0
277
278 ; --- asm__doSpaces ---
279 ;
280 ; On entry:     R8 == pointer into the instruction
281 ;               R9 == instruction so far
282 ;
283 ; On exit:      VS and R0 == pointer to error or
284 ;               VC and R8,R9 updated appropriately
285 ;
286 ; Use:          Skips the following spaces, ensureing that there is
287 ;               at least one.
288
289 asm__doSpaces   ROUT
290                 STMFD   R13!,{R14}              ;Stack the link register
291
292                 LDRB    R14,[R8,#0]             ;...and read another byte
293                 CMP     R14,#' '                ;Is it a space?
294                 CMPNE   R14,#9                  ;Allow a tab here too
295                 ADRNE   R0,asm__opcJunk         ;No -- something odd's there
296                 BNE     %95asm__doSpaces        ;So moan about it then
297
298 10asm__doSpaces LDRB    R14,[R8],#1             ;Load the next byte
299                 CMP     R14,#' '                ;Is it a space?
300                 CMPNE   R14,#9                  ;Allow a tab here too
301                 BEQ     %10asm__doSpaces        ;Yes -- ignore it then
302                 SUB     R8,R8,#1                ;We overstepped the mark
303
304                 LDMFD   R13!,{R14}              ;Get the link back
305                 BICS    PC,R14,#V_flag          ;Return without error
306
307 95asm__doSpaces LDMFD   R13!,{R14}              ;Get the link back
308                 ORRS    PC,R14,#V_flag          ;Return without error
309
310                 LTORG
311
312 ; --- asm__aluOp3 ---
313 ;
314 ; On entry:     R8 == pointer into the instruction
315 ;               R9 == instruction so far
316 ;
317 ; On exit:      VS and R0 == pointer to error or
318 ;               VC and R8,R9 updated appropriately
319 ;
320 ; Use:          Deals with 3 operand ALU operations
321
322 asm__aluOp3     ROUT
323
324                 STMFD   R13!,{R14}              ;Stack the link register
325                 CMP     R5,#7                   ;Does R5 hold correct code?
326                 MOVLE   R9,R5,LSL #21           ;Yes -- put it in the inst.
327                 CMP     R5,#8                   ;Is it ORR?
328                 MOVEQ   R9,#&01800000           ;Yes -- make it so
329                 CMP     R5,#9                   ;Is it a BIC?
330                 MOVEQ   R9,#&01C00000           ;Yes -- make it so
331                 MOV     R4,R5                   ;Remember the opcode
332                 BL      asm__condition          ;Read the condition
333                 BL      asm__doSBit             ;Skip onto next register
334
335                 ; --- First off is a register name ---
336
337                 BL      asm_register            ;Read a register name
338                 ORRVC   R9,R9,R0,LSL #12        ;Insert Rd in nicely
339                 BLVC    asm__comma              ;Read and ignore a comma
340
341                 ; --- So's the next one ---
342
343                 BLVC    asm_register            ;Read a register name
344                 ORRVC   R9,R9,R0,LSL #16        ;Insert Rn in nicely
345                 BLVC    asm__comma              ;Read a comma
346
347                 BVS     %95asm__aluOp3          ;Barf if there's an error
348
349                 ; --- Now for the last op (easy one, this) ---
350
351                 LDRB    R14,[R8]                ;Read a character
352                 CMP     R14,#'#'                ;Is is a hash?
353                 BNE     %50asm__aluOp3          ;No -- Next is a register
354
355                 ; --- Operand 2 is an immediate constant ---
356
357                 ADD     R8,R8,#1                ;Skip past the '#'
358                 BL      asm__constant           ;Read the constant
359                 MOV     R1,R0                   ;Remember the number
360                 BVS     %95asm__aluOp3          ;If error -- barf
361                 ORR     R9,R9,#(1<<25)          ;Operand 2 is immediate
362                 BL      asm__doConstShift       ;Make it into a valid shift
363                 BVC     %90asm__aluOp3          ;All OK -- return
364
365                 ; --- Try an alternative opcode ---
366
367                 CMP     R4,#0                   ;Was it an AND
368                 CMPNE   R4,#9                   ;Or a BIC
369                 CMPNE   R4,#4                   ;Or an ADD
370                 CMPNE   R4,#5                   ;Or a ADC
371                 CMPNE   R4,#2                   ;Perhaps a SUB
372                 CMPNE   R4,#6                   ;Or an SBC
373                 ADRNE   R0,asm__invConst        ;No, point to the error
374                 BNE     %95asm__aluOp3          ;And return with error
375
376                 MOV     R0,R1                   ;Put the number back in R0
377                 CMP     R4,#0                   ;Was it an AND
378                 MVNEQ   R0,R0                   ;Yes -- invert the number
379                 MOVEQ   R4,#9                   ;And make it a BIC
380                 BEQ     %20asm__aluOp3          ;Try the new opcode then
381
382                 CMP     R4,#9                   ;Was it a BIC
383                 MVNEQ   R0,R0                   ;Yes -- invert the number
384                 MOVEQ   R4,#0                   ;And make it an AND
385                 BEQ     %20asm__aluOp3          ;Try the new opcode then
386
387                 CMP     R4,#4                   ;Was it an ADD
388                 RSBEQ   R0,R0,#0                ;Yes -- negate the number
389                 MOVEQ   R4,#2                   ;And make it a SUB
390                 BEQ     %20asm__aluOp3          ;Try the new opcode then
391
392                 CMP     R4,#2                   ;Was it a SUB
393                 RSBEQ   R0,R0,#0                ;Yes -- negate the number
394                 MOVEQ   R4,#4                   ;And make it an ADD
395                 BEQ     %20asm__aluOp3          ;Try the new opcode then
396
397                 CMP     R4,#5                   ;Was it an ADC
398                 MVNEQ   R0,R0                   ;Yes -- negate the number
399                 MOVEQ   R4,#6                   ;And make it a SBC
400                 BEQ     %20asm__aluOp3          ;Try the new opcode then
401
402                 CMP     R4,#6                   ;Was it an SBC
403                 MVNEQ   R0,R0                   ;Yes -- negate the number
404                 MOVEQ   R4,#5                   ;And make it a ADC
405                 BEQ     %20asm__aluOp3          ;Try the new opcode then
406
407 20asm__aluOp3   BIC     R9,R9,#&01E00000        ;Clear the current opcode
408                 CMP     R4,#9                   ;Is it a BIC?
409                 MOVEQ   R4,#14                  ;Yes -- make it so
410                 ORR     R9,R9,R4,LSL#21         ;And put in the new one
411                 BL      asm__doConstShift       ;Make it into a valid shift
412                 BVC     %90asm__aluOp3          ;Return without error
413                 BVS     %95asm__aluOp3          ;Return with error
414
415                 ; --- Operand 2 is a register ---
416
417 50asm__aluOp3   MOV     R0,#0                   ;No -- set up some flags
418                 BL      asm__op2reg             ;..read in operand 2
419
420 90asm__aluOp3   BLVC    asm__endOfLine          ;Make sure it ends here
421                 LDMVCFD R13!,{R14}              ;Load the link back
422                 BICVCS  PC,R14,#V_flag          ;Return without error
423
424 95asm__aluOp3   LDMFD   R13!,{R14}              ;Load the link back
425                 ORRS    PC,R14,#V_flag          ;Return with error
426
427                 LTORG
428
429 ; --- asm__aluOp2 ---
430 ;
431 ; On entry:     R8 == pointer into the instruction
432 ;               R9 == instruction so far
433 ;
434 ; On exit:      VS and R0 == pointer to error or
435 ;               VC and R8,R9 updated appropriately
436 ;
437 ; Use:          Deals with 2 operand ALU operations
438
439 asm__aluOp2     ROUT
440
441                 STMFD   R13!,{R14}              ;Stack the link register
442                 MOV     R9,#&01A00000           ;Make it a MOV
443                 CMP     R5,#11                  ;Was it a MVN?
444                 ORREQ   R9,R9,#&00400000        ;Yes -- make it so
445                 MOV     R4,R5                   ;Remember the opcode
446                 BL      asm__condition          ;Read the condition
447                 BL      asm__doSBit             ;Skip to first register
448
449                 ; --- First off is a register name ---
450
451                 BL      asm_register            ;Read a register name
452                 BVS     %95asm__aluOp2          ;On error -- report it
453                 ORR     R9,R9,R0,LSL #12        ;Insert Rd in nicely
454                 BL      asm__comma              ;Read a comma
455                 BVS     %95asm__aluOp2          ;On error -- report it
456
457                 ; --- Now for the last op (easy one, this) ---
458
459                 LDRB    R14,[R8]                ;Read a character
460                 CMP     R14,#'#'                ;Is is a hash?
461                 BNE     %50asm__aluOp2          ;No -- Next is a register
462
463                 ; --- Operand 2 is an immediate constant ---
464
465                 ADD     R8,R8,#1                ;Skip past the '#'
466                 BL      asm__constant           ;Read the constant
467                 MOV     R1,R0                   ;Remember the number
468                 BVS     %95asm__aluOp2          ;If error -- barf
469                 ORR     R9,R9,#(1<<25)          ;Operand 2 is immediate
470                 BL      asm__doConstShift       ;Make it into a valid shift
471                 BVC     %90asm__aluOp2          ;All OK -- return
472
473                 ; --- Try an alternative opcode ---
474
475                 MVN     R0,R1                   ;Put the number back in R0
476                 CMP     R4,#10                  ;Was it a MOV
477                 MOVEQ   R4,#11                  ;Yes -- make it an MVN
478                 MOVNE   R4,#10                  ;No -- it's a MOV then
479
480 20asm__aluOp2   BIC     R9,R9,#&01E00000        ;Clear the current opcode
481                 ORR     R9,R9,#&01A00000        ;Make it a MOV
482                 CMP     R4,#11                  ;Was it a MVN?
483                 ORREQ   R9,R9,#&00400000        ;Yes -- make it so
484                 BL      asm__doConstShift       ;Make it into a valid shift
485                 BVC     %90asm__aluOp2          ;Return without error
486                 BVS     %95asm__aluOp2          ;Return with error
487
488                 ; --- Operand 2 is a register ---
489
490 50asm__aluOp2   MOV     R0,#0                   ;No -- set up some flags
491                 BL      asm__op2reg             ;..read in operand 2
492
493 90asm__aluOp2   BLVC    asm__endOfLine          ;Make sure it ends here
494                 LDMVCFD R13!,{R14}              ;Load the link back
495                 BICVCS  PC,R14,#V_flag          ;Return without error
496
497 95asm__aluOp2   LDMFD   R13!,{R14}              ;Load the link back
498                 ORRS    PC,R14,#V_flag          ;Return with error
499
500                 LTORG
501
502 ; --- asm__aluOpTest ---
503 ;
504 ; On entry:     R8 == pointer into the instruction
505 ;               R9 == instruction so far
506 ;
507 ; On exit:      VS and R0 == pointer to error or
508 ;               VC and R8,R9 updated appropriately
509 ;
510 ; Use:          Deals with comparison ALU operations
511
512 asm__aluOpTest  ROUT
513
514                 STMFD   R13!,{R14}              ;Stack the link register
515                 MOV     R9,#&01100000           ;Set top opcode bit, and 'S'
516                 MOV     R4,R5                   ;Remember the opcode
517                 SUB     R5,R5,#12               ;Index opcode from 0
518                 ADD     R9,R9,R5,LSL#21         ;Correct the instruction
519                 BL      asm__condition          ;Read the condition
520                 BL      asm__doSBit             ;Skip to next register
521
522                 ; --- First off is a register name ---
523
524                 BL      asm_register            ;Read a register name
525                 BVS     %95asm__aluOpTest       ;On an error -- moan
526                 ORR     R9,R9,R0,LSL #12        ;Insert Rd in nicely
527                 BL      asm__comma              ;Read a comma
528                 BVS     %95asm__aluOpTest       ;On an error -- moan
529
530                 ; --- Now for the last op (easy one, this) ---
531
532                 LDRB    R14,[R8]                ;Read a character
533                 CMP     R14,#'#'                ;Is is a hash?
534                 BNE     %50asm__aluOpTest       ;No -- Next is a register
535
536                 ; --- Operand 2 is an immediate constant ---
537
538                 ADD     R8,R8,#1                ;Skip past the hash sign
539                 BL      asm__constant           ;Read the constant
540                 MOV     R1,R0                   ;Remember the number
541                 BVS     %95asm__aluOpTest       ;If error -- barf
542                 ORR     R9,R9,#(1<<25)          ;Operand 2 is immediate
543                 BL      asm__doConstShift       ;Make it into a valid shift
544                 BVC     %90asm__aluOpTest       ;All OK -- return
545
546                 ; --- Try an alternative opcode ---
547
548                 CMP     R4,#14                  ;Was it a CMP
549                 CMPNE   R4,#15                  ;Or a CMN
550                 ADRNE   R0,asm__invConst        ;No, point to the error
551                 BNE     %95asm__aluOpTest       ;And return with error
552
553                 RSB     R0,R1,#0                ;Negate the number
554                 CMP     R4,#14                  ;Was it a CMP
555                 MOVEQ   R4,#15                  ;Yes -- make it a CMN
556                 MOVNE   R4,#14                  ;No -- make it a CMP then
557                 BIC     R9,R9,#&00E00000        ;Clear the current opcode
558                 SUB     R4,R4,#12               ;Index opcode from 0
559                 ADD     R9,R9,R4,LSL#21         ;Correct the instruction
560                 BL      asm__doConstShift       ;Make it into a valid shift
561                 BVC     %90asm__aluOpTest       ;Return without error
562                 BVS     %95asm__aluOpTest       ;Return with error
563
564                 ; --- Operand 2 is a register ---
565
566 50              MOV     R0,#0                   ;No -- set up some flags
567                 BL      asm__op2reg             ;..read in operand 2
568
569 90              BLVC    asm__endOfLine          ;Make sure it ends here
570                 LDMVCFD R13!,{R14}              ;Load the link back
571                 BICVCS  PC,R14,#V_flag          ;Return without error
572
573 95              LDMFD   R13!,{R14}              ;Load the link back
574                 ORRS    PC,R14,#V_flag          ;Return with error
575
576                 LTORG
577
578 ; --- asm__doConstShift ---
579 ;
580 ; On entry:     R0 == The immediate
581 ;               R9 == instruction so far
582 ;
583 ; On exit:      VS and R0 == pointer to error or
584 ;               VC and R8,R9 updated appropriately
585 ;
586 ; Use:          Tries to find a way of fitting the given constant into
587 ;               8 bits, with an even rotation.
588
589 asm__doConstShift ROUT
590
591                 STMFD   R13!,{R0-R3,R14}        ;Stack some registers
592                 MOV     R1,#0                   ;The current shift count
593 10              MOV     R2,R0,ROR R1            ;Perform the shift
594                 AND     R3,R2,#&FF              ;Just get the bottom byte
595                 CMP     R2,R3                   ;Were any other bits set?
596                 BEQ     %50asm__doConstShift    ;No -- we've found one
597                 ADD     R1,R1,#2                ;Increment the shift count
598                 CMP     R1,#30                  ;Have we finished
599                 BLE     %10asm__doConstShift    ;No -- keep trying
600
601                 ; --- The constant is invalid ---
602
603                 ADR     R0,asm__invConst        ;Point to the error message
604                 LDMFD   R13!,{R0-R3,R14}        ;Load the link back
605                 ADR     R0,asm__invConst        ;Point to the error
606                 ORRS    PC,R14,#V_flag          ;Return with error
607
608                 ; --- We have found an valid rotation ---
609
610 50              CMP     R1,#0                   ;Is rotation greater than 0?
611                 RSBGT   R1,R1,#32               ;Yes -- get 'reverse' value
612                 ORR     R9,R9,R1,LSL #7         ;Put the rotation in inst
613                 ORR     R9,R9,R2                ;And put the constant in too
614                 LDMFD   R13!,{R0-R3,R14}        ;Load the link back
615                 BICS    PC,R14,#V_flag          ;Return without error
616
617 asm__invConst   DCD     1
618                 DCB     "Invalid immediate constant",0
619
620                 LTORG
621
622 ; --- asm__op2reg ---
623 ;
624 ; On entry:     R0 == A nice flags word
625 ;               R8 == pointer into the instruction
626 ;               R9 == instruction so far
627 ;
628 ; On exit:      VS and R0 == pointer to error or
629 ;               VC and R8,R9 updated appropriately
630 ;
631 ; Use:          Deals with the dreaded operand 2
632 ;               (Rx [[,]<shift type> [(#<num> | Ry)]]
633
634 asm__op2reg     ROUT
635
636                 STMFD   R13!,{R14}              ;Stack the link register
637
638                 ; --- Read a (shifed) register ---
639
640                 MOV     R4,R0                   ;Remember the flags word
641                 BL      asm_register            ;Read a register name
642                 BVS     %95asm__op2reg          ;Barf if there's an error
643                 ORR     R9,R9,R0                ;ORR in register
644                 BL      asm__comma              ;Skip the optional comma
645                 ORRVS   R4,R4,#(1<<31)          ;If error -- remember this
646
647                 ; --- Read in the shift ---
648
649                 MOV     R0,R4                   ;Put flags in R0
650                 BL      asm__readShift          ;Read in the shift type
651                 BVC     %90asm__op2reg          ;All OK -- return
652
653                 TST     R4,#(1<<31)             ;Was there an error before?
654                 ADREQ   R0,asm__badShift        ;No -- we expected a shift
655                 BEQ     %95asm__op2reg          ;Right -- report the error
656
657 90asm__op2reg   LDMFD   R13!,{R14}              ;Load the link back
658                 BICS    PC,R14,#V_flag          ;Return without error
659
660 95asm__op2reg   LDMFD   R13!,{R14}              ;Load the link back
661                 ORRS    PC,R14,#V_flag          ;Return with error
662
663                 LTORG
664
665 asm__badShift   DCD     1
666                 DCB     "Bad or missing shift",0
667
668 ; --- asm__comma ---
669 ;
670 ; On entry:     R8 == pointer into the instruction
671 ;
672 ; On exit:      VS and R0 == pointer to error or
673 ;               VC and R8 updated appropriately
674 ;
675 ; Use:          Reads in a comma, skipping spaces
676
677 asm__comma      ROUT
678
679                 STMFD   R13!,{R14}              ;Stack the link register
680
681                 ; --- First we skip spaces ---
682
683 00              LDRB    R14,[R8],#1             ;Load a new byte
684                 CMP     R14,#' '                ;Skip over spaces
685                 CMPNE   R14,#9                  ;And tabs too
686                 BEQ     %00asm__comma           ;And stop when it isn't one
687
688                 ; --- No we read a comma ---
689
690                 CMP     R14,#','                ;Is it a comma
691                 BNE     %95asm__comma           ;No -- complain
692
693                 ; --- Skip more spaces ---
694
695 10              LDRB    R14,[R8],#1             ;Load a new byte
696                 CMP     R14,#' '                ;Skip over spaces
697                 CMPNE   R14,#9                  ;And tabs too
698                 BEQ     %00asm__comma           ;And stop when it isn't one
699
700                 SUB     R8,R8,#1                ;We overstepped the mark
701                 LDMFD   R13!,{R14}              ;Load the link back
702                 BICS    PC,R14,#V_flag          ;Return without error
703
704                 ; --- Return an error ---
705
706 95asm__comma    SUB     R8,R8,#1                ;We overstepped the mark
707                 LDMFD   R13!,{R14}              ;Load the link back
708                 ADR     R0,asm__commaExp        ;Point to the message
709                 ORRS    PC,R14,#V_flag          ;Return with error
710
711 asm__commaExp   DCD     1
712                 DCB     "Comma expected",0
713
714                 LTORG
715
716 ; --- asm__endOfLine ---
717 ;
718 ; On entry:     R8 == pointer into the instruction
719 ;               R9 == instruction so far
720 ;
721 ; On exit:      VS and R0 == pointer to error or
722 ;               VC and R8 updated appropriately
723 ;
724 ; Use:          Ensures that the end of the line has been reached
725
726 asm__endOfLine  ROUT
727
728                 STMFD   R13!,{R14}              ;Stack the link register
729
730                 ; --- First we skip spaces ---
731
732 00              LDRB    R14,[R8],#1             ;Load a new byte
733                 CMP     R14,#' '                ;Skip over spaces
734                 CMPNE   R14,#9                  ;And tabs too
735                 BEQ     %00asm__endOfLine       ;And stop when it isn't one
736
737                 CMP     R14,#';'                ;Is it a semicolon
738                 CMPNE   R14,#31                 ;Or a control character
739
740                 LDMFD   R13!,{R14}              ;Get the link back
741                 BICLES  PC,R14,#V_flag          ;All OK -- return nicely
742                 ADR     R0,asm__eofError        ;Point to error message
743                 ORRS    PC,R14,#V_flag          ;And return an error
744
745 asm__eofError   DCD     1
746                 DCB     "Rubbish at end of instruction",0
747
748                 LTORG
749
750 ; --- asm__constant ---
751 ;
752 ; On entry:     R8 == pointer into the instruction
753 ;               R9 == instruction so far
754 ;
755 ; On exit:      VS and R0 == pointer to error or
756 ;               VC and R0 == number, R8 updated appropriately
757 ;
758 ; Use:          Reads in a constant from the expression
759
760 asm__constant   ROUT
761
762                 STMFD   R13!,{R1-R3,R14}        ;Stack some registers
763
764                 LDRB    R3,[R8]                 ;Read in a character
765                 CMP     R3,#'-'                 ;Is it a minus character
766                 ADDEQ   R8,R8,#1                ;Yes -- jump over it
767                 MOV     R0,#10                  ;Read decimal by default
768                 MOV     R1,R8                   ;Point to the string
769                 SWI     XOS_ReadUnsigned        ;Read in the number
770                 BVS     %95asm__constant        ;If error -- report it
771                 MOV     R8,R1                   ;Make R8 correct again
772                 MOV     R0,R2                   ;Put the number in R0
773                 CMP     R3,#'-'                 ;Should we negate number?
774                 RSBEQ   R0,R0,#0                ;Yes -- make it negative
775
776 90asm__constant LDMFD   R13!,{R1-R3,R14}        ;Load the link back
777                 BICS    PC,R14,#V_flag          ;Return without error
778
779 95asm__constant LDMFD   R13!,{R1-R3,R14}        ;Load the link back
780                 ORRS    PC,R14,#V_flag          ;Return with error
781
782                 LTORG
783
784 ; --- asm_register ---
785 ;
786 ; On entry:     R8 == pointer into the instruction
787 ;
788 ; On exit:      VS and R0 == pointer to error or
789 ;               VC and R0 == number, R8 updated appropriately
790 ;
791 ; Use:          Reads in a register name
792
793                 EXPORT  asm_register
794 asm_register    ROUT
795
796                 STMFD   R13!,{R1-R5,R14}        ;Save some registers
797
798 00asm_register  LDRB    R14,[R8],#1             ;Read a character
799                 CMP     R14,#32                 ;Is it a space?
800                 CMPNE   R14,#9                  ;Or a tab
801                 BEQ     %00asm_register         ;Yes -- skip spaces
802                 SUB     R8,R8,#1                ;We overshot the mark
803
804                 BL      diss_regTable           ;Find the register name table
805                 MOV     R3,R0                   ;Look after this pointer
806
807                 ; --- Start the main loop thing ---
808
809                 MOV     R0,#15                  ;Start testing R15
810 05asm_register  MOV     R1,R8                   ;Point to the name start
811                 LDR     R2,[R3,R0,LSL #2]       ;Load the correct name ptr
812
813 10asm_register  LDRB    R4,[R2],#1              ;Get a byte from reg name
814                 LDRB    R5,[R1],#1              ;Get a byte from the string
815
816                 ; --- Mangle R5 to be upper case, digit, or 0 ---
817
818                 CMP     R5,#'Z'                 ;Is it bigger than a 'Z'?
819                 BICHI   R5,R5,#&20              ;Yes -- make it upper case
820                 SUB     R14,R5,#'A'             ;Subtract upper case 'A'
821                 CMP     R14,#26                 ;Is it a letter of some kind?
822                 SUBHS   R14,R5,#'0'             ;No -- try a digit then
823                 CMPHS   R14,#10                 ;Is it one of them instead
824                 MOVHS   R5,#0                   ;No -- it's not alnum then
825
826                 ; --- Now make R4 upper case if it isn't already ---
827
828                 SUB     R14,R4,#'a'             ;Subtract lower case 'a'
829                 CMP     R14,#26                 ;Is it a lower case letter?
830                 BICLO   R4,R4,#&20              ;Yes -- make it upper case
831
832                 ; --- Do the actual comparison then ---
833
834                 CMP     R4,R5                   ;Do they match nicely?
835                 BNE     %20asm_register         ;No -- try the next register
836                 CMP     R4,#0                   ;Is it the end of the string?
837                 BNE     %10asm_register         ;No -- then try more bytes
838
839                 ; --- We found a match -- yippee ---
840
841                 SUB     R8,R1,#1                ;Update the string pointer
842                 LDMFD   R13!,{R1-R5,R14}        ;Unstack some registers
843                 BICS    PC,R14,#V_flag          ;And there wuz no error
844
845                 ; --- Try the next register ---
846
847 20asm_register  SUBS    R0,R0,#1                ;Move down a register
848                 BGE     %05asm_register         ;If more to try, do 'em
849
850                 ADR     R0,asm__badReg          ;Point to the error message
851                 LDMFD   R13!,{R1-R5,R14}        ;Unstack some registers
852                 ORRS    PC,R14,#V_flag          ;And return with my error
853
854 asm__badReg     DCD     1
855                 DCB     "Bad register name",0
856
857                 LTORG
858
859 ; --- asm__readShift ---
860 ;
861 ; On entry:     R0 == A nice flags word
862 ;               R8 == pointer into the instruction
863 ;               R9 == instruction so far
864 ;
865 ; On exit:      VS and R0 == pointer to error or
866 ;               VC and R8,R9 updated appropriately
867 ;
868 ; Use:          Deals with the dreaded operand 2
869 ;               (#<num> or Rx [[,]<shift type> [(#<num> | Ry)]]
870
871 asm__readShift  ROUT
872
873                 STMFD   R13!,{R14}              ;Stack the link register
874                 MOV     R4,R0                   ;Look after the flags
875
876                 ADR     R6,asm__shifts          ;Point to the possibilities
877                 BL      asm__lookup             ;Find the one that matches
878                 BCS     %94asm__readShift       ;And return the error
879
880                 ADD     R8,R8,#3                ;Skip past shift op
881                 CMP     R5,#4                   ;Is it an RRX?
882                 MOVEQ   R0,#0                   ;Yes -- shift size is 0 then
883                 MOVEQ   R5,#3                   ;And it's realy an ROR
884                 BEQ     %20asm__readShift       ;And skip onwards
885                 CMP     R5,#5                   ;Is it ASL?
886                 MOVEQ   R5,#0                   ;Yes -- ASL doesn't exist!
887
888 00              LDRB    R14,[R8],#1             ;Load a new byte
889                 CMP     R14,#' '                ;Skip over spaces
890                 CMPNE   R14,#9                  ;And tabs too
891                 BEQ     %00asm__readShift       ;And stop when it isn't one
892
893                 ; --- We now reach the Shift Operand ---
894
895                 CMP     R14,#'#'                ;Is it immediate?
896                 BEQ     %10asm__readShift       ;Yes -- read the operand
897
898                 TST     R4,#1                   ;Is this a single reg trans?
899                 BNE     %94asm__readShift       ;And return the error
900
901                 SUB     R8,R8,#1                ;We overstepped as usual
902                 BL      asm_register            ;Get the register value
903                 BVS     %95asm__readShift       ;Failed -- report the error
904                 ORR     R9,R9,R5,LSL #5         ;Bang in the shift type
905                 ORR     R9,R9,R0,LSL #8         ;Put that in there too
906                 ORR     R9,R9,#(1<<4)           ;And set reg-shifty bit
907                 B       %90asm__readShift       ;Finished... 'RAY!!!
908
909                 ; --- Immediate shifts ---
910
911 10              BL      asm__constant           ;Read a constant value
912                 BVS     %95asm__readShift       ;Failed -- report the error
913                 CMP     R0,#0                   ;Is this vaguely sensible?
914                 BLT     %94asm__readShift       ;-ve shifts are daft
915
916                 CMPEQ   R5,#0                   ;Check for LSL by 0
917                 BEQ     %20asm__readShift       ;This is OK
918                 CMP     R0,#0                   ;Otherwise, is it 0?
919                 BEQ     %94asm__readShift       ;0 has special meanings
920
921                 CMP     R0,#32                  ;Is it too big?
922                 BGT     %94asm__readShift       ;Yes -- that's really bad
923                 BLT     %20asm__readShift       ;Less is OK though
924                 CMP     R5,#1                   ;32 is allowed for LSR
925                 CMPNE   R5,#2                   ;And for ASR
926                 BNE     %94asm__readShift       ;But not for anything else
927                 MOV     R0,#0                   ;Fix it to be 0 cunningly
928
929 20              ORR     R9,R9,R5,LSL #5         ;Bang in the shift type
930                 ORR     R9,R9,R0,LSL #7         ;Put the constant in too
931
932 90              LDMFD   R13!,{R14}              ;Load the link back
933                 BICS    PC,R14,#V_flag          ;Return without error
934
935 94              ADR     R0,asm__badShift        ;Point to bad shift message
936 95              LDMFD   R13!,{R14}              ;Load the link back
937                 ORRS    PC,R14,#V_flag          ;Return with error
938
939 asm__shifts     DCB     "LSL",0,"LSR",0,"ASR",0,"ROR",0,"RRX",0,"ASL",0
940                 DCD     0
941
942                 LTORG
943
944 ; --- asm__branch ---
945 ;
946 ; On entry:     R0 == The second character
947 ;               R8 == pointer into the instruction
948 ;               R9 == instruction so far
949 ;
950 ; On exit:      VS and R0 == pointer to error or
951 ;               VC and R8,R9 updated appropriately
952 ;
953 ; Use:          Deals with branch instructions
954
955 asm__branch     ROUT
956
957                 STMFD   R13!,{R14}              ;Stack what we need
958                 ADD     R8,R8,#1                ;Skip past the 'B'
959                 CMP     R0,#'L'                 ;Is it a 'BL'?
960                 CMPNE   R0,#'l'
961                 MOVNE   R9,#&0A000000           ;No -- make instr a branch
962                 BNE     %00asm__branch          ;And skip ahead
963                 LDRB    R0,[R8,#2]              ;Is there a 3rd letter here?
964                 CMP     R0,#32                  ;What is it?
965                 MOVLE   R9,#&0A000000           ;Nothing -- must be a branch
966                 MOVGT   R9,#&0B000000           ;A character -- BL then
967                 ADDGT   R8,R8,#1                ;...skip past the 'L'
968
969 00asm__branch   BL      asm__condition          ;Read in the condition
970                 BL      asm__doSpaces           ;Skip following spaces
971
972                 ; --- Read in the value ---
973
974                 BLVC    asm__readAddress        ;Read in the address
975                 BVS     %95asm__branch          ;If there's an error, barf
976                 BIC     R0,R0,#3                ;Clear the lower 2 bits
977                 SUB     R0,R0,R7                ;Branch is PC relative
978                 MOV     R0,R0,LSR#2             ;Shift it down a bit
979                 SUB     R0,R0,#2                ;Allow for pipelining
980                 BIC     R0,R0,#&FF000000        ;Clear the top bits
981                 ORR     R9,R9,R0                ;Put value into instruction
982
983 90asm__branch   BL      asm__endOfLine          ;Make sure it ends here
984                 LDMVCFD R13!,{R14}              ;Load the link back
985                 BICVCS  PC,R14,#V_flag          ;Return without error
986
987 95asm__branch   LDMFD   R13!,{R14}              ;Load the link back
988                 ORRS    PC,R14,#V_flag          ;Return with error
989
990                 LTORG
991
992 ; --- asm__readAddress ---
993 ;
994 ; On entry:     R8 == pointer into the instruction
995 ;
996 ; On exit:      VS and R0 == pointer to error or
997 ;               VC and R8 updated appropriately
998 ;
999 ; Use:          Reads in an address
1000
1001 asm__readAddress ROUT
1002                 STMFD   R13!,{R1-R3,R14}        ;Stack some registers
1003
1004                 MOV     R0,#10                  ;Read decimal by default
1005                 MOV     R1,R8                   ;Point to the string
1006                 SWI     XOS_ReadUnsigned        ;Read in the number
1007                 BVS     %95asm__readAddress     ;If error -- report it
1008                 MOV     R8,R1                   ;Make R8 correct again
1009                 MOV     R0,R2                   ;Put the number in R0
1010
1011 90              LDMFD   R13!,{R1-R3,R14}        ;Load the link back
1012                 BICS    PC,R14,#V_flag          ;Return without error
1013
1014 95              LDMFD   R13!,{R1-R3,R14}        ;Load the link back
1015                 ORRS    PC,R14,#V_flag          ;Return with error
1016
1017                 LTORG
1018
1019 ; --- asm__multiply ---
1020 ;
1021 ; On entry:     R8 == pointer into the instruction
1022 ;               R9 == instruction so far
1023 ;
1024 ; On exit:      VS and R0 == pointer to error or
1025 ;               VC and R8,R9 updated appropriately
1026 ;
1027 ; Use:          Deals with multiply operation
1028
1029 asm__multiply   ROUT
1030
1031                 STMFD   R13!,{R14}              ;Stack the link register
1032                 MOV     R9,#&90                 ;Make it identifiable
1033                 CMP     R5,#17                  ;Is it an MLA?
1034                 ORREQ   R9,R9,#&00200000        ;Yes -- make it so
1035                 MOV     R4,R5                   ;Remember the opcode
1036                 BL      asm__condition          ;Read in the condition code
1037                 BL      asm__doSBit             ;Skip to first register
1038
1039                 ; --- First off is a register name ---
1040
1041                 BL      asm_register            ;Read a register name
1042                 ORRVC   R9,R9,R0,LSL #16        ;Insert Rd in nicely
1043                 BLVC    asm__comma              ;Read and ignore a comma
1044
1045                 ; --- So's the next one ---
1046
1047                 BLVC    asm_register            ;Read a register name
1048                 ORRVC   R9,R9,R0                ;Insert Rm in nicely
1049                 BLVC    asm__comma              ;Read and ignore a comma
1050
1051                 ; --- So's the next one ---
1052
1053                 BLVC    asm_register            ;Read a register name
1054                 ORRVC   R9,R9,R0,LSL#8          ;Insert Rs in nicely
1055                 BVS     %95asm__multiply        ;Barf if there's an error
1056
1057                 CMP     R4,#17                  ;Is this an MLA
1058                 BNE     %90asm__multiply        ;No -- we're finished then
1059
1060                 BL      asm__comma              ;Read and ignore a comma
1061                 BLVC    asm_register            ;Read a register name
1062                 ORRVC   R9,R9,R0,LSL#12         ;Insert Rn in nicely
1063                 BVS     %95asm__multiply        ;Barf if there's an error
1064
1065 90asm__multiply BL      asm__endOfLine          ;Make sure it ends here
1066                 LDMVCFD R13!,{R14}              ;Load the link back
1067                 BICVCS  PC,R14,#V_flag          ;Return without error
1068
1069 95asm__multiply LDMFD   R13!,{R14}              ;Load the link back
1070                 ORRS    PC,R14,#V_flag          ;Return with error
1071
1072                 LTORG
1073
1074 ; --- asm__sDataTrans ---
1075 ;
1076 ; On entry:     R8 == pointer into the instruction
1077 ;               R9 == instruction so far
1078 ;
1079 ; On exit:      VS and R0 == pointer to error or
1080 ;               VC and R8,R9 updated appropriately
1081 ;
1082 ; Use:          Deals with LDR/STR type instructions
1083
1084 asm__sDataTrans ROUT
1085
1086                 STMFD   R13!,{R14}              ;Stack the link register
1087                 MOV     R9,#&04000000           ;Make it identifiable
1088                 CMP     R5,#18                  ;Is it an LDR?
1089                 ORREQ   R9,R9,#(1<<20)          ;Yes -- make it so
1090                 BL      asm__condition          ;Read in the condition
1091                 LDRB    R14,[R8,#0]             ;Read the next character
1092                 CMP     R14,#'B'                ;Is it a 'B'?
1093                 CMPNE   R14,#'b'
1094                 ORREQ   R9,R9,#(1<<22)          ;Yes -- make it byte transfer
1095                 ADDEQ   R8,R8,#1                ;...skip over it
1096                 LDREQB  R14,[R8,#0]             ;...and read another char
1097                 CMP     R14,#'T'                ;Is it a 'T'?
1098                 CMPNE   R14,#'t'
1099                 ORREQ   R9,R9,#(1<<21)          ;Yes -- set 'W' bit
1100                 ADDEQ   R8,R8,#1                ;...skip over it
1101                 BL      asm__doSpaces           ;Skip over spaces
1102
1103                 ; --- First off is a register name ---
1104
1105                 BL      asm_register            ;Read a register name
1106                 ORRVC   R9,R9,R0,LSL #12        ;Insert Rd in nicely
1107                 BLVC    asm__comma              ;Read and ignore a comma
1108                 BVS     %95asm__sDataTrans      ;Report a possible error
1109
1110                 LDRB    R14,[R8,#0]             ;Read a character
1111                 CMP     R14,#'['                ;Is it an open bracket?
1112                 BNE     %70asm__sDataTrans      ;No -- jump ahead
1113                 ADD     R8,R8,#1                ;Skip over the bracket
1114
1115                 BL      asm_register            ;Read a register name
1116                 BVS     %95asm__sDataTrans      ;Report a possible error
1117                 ORR     R9,R9,R0,LSL #16        ;Insert Rd in nicely
1118                 LDRB    R14,[R8,#0]             ;Read a character
1119                 CMP     R14,#']'                ;Is it an close bracket?
1120                 ORRNE   R9,R9,#(1<<24)          ;No -- set 'P' bit
1121                 ADDEQ   R8,R8,#1                ;Yes -- skip over it
1122                 BEQ     %10asm__sDataTrans      ;...and jump ahead a little
1123                 TST     R9,#(1<<21)             ;Is the 'W' bit set?
1124                 ADRNE   R0,asm__preAndT         ;Yes -- point to an error
1125                 BNE     %95asm__sDataTrans      ;And report the error
1126
1127 10              BL      asm__comma              ;Read in the comma
1128                 BVS     %60asm__sDataTrans      ;No comma -- tidy up
1129
1130                 ; --- Now for the last op (easy one, this) ---
1131
1132                 LDRB    R14,[R8]                ;Read a character
1133                 CMP     R14,#'#'                ;Is is a hash?
1134                 BNE     %50asm__sDataTrans      ;No -- Next is a register
1135
1136                 ; --- Operand 2 is an immediate constant ---
1137
1138                 ADD     R8,R8,#1                ;Skip past the '#'
1139                 BL      asm__constant           ;Read the constant
1140                 BVS     %95asm__sDataTrans      ;If error -- barf
1141                 CMP     R0,#0                   ;Is it negative
1142                 RSBLT   R0,R0,#0                ;Yes -- make it positive
1143                 ORRGE   R9,R9,#(1<<23)          ;No -- offset is +ve
1144                 TST     R0,#&FF000000           ;Are any of these bits set?
1145                 TSTEQ   R0,#&00FF0000           ;Or these bits?
1146                 TSTEQ   R0,#&0000F000           ;Or even these?
1147                 ADRNE   R0,asm__invOffset       ;Yes -- point to error
1148                 BNE     %95asm__sDataTrans      ;And report error
1149                 ORR     R9,R9,R0                ;ORR in the value
1150                 B       %60asm__sDataTrans      ;And finsh off nicely
1151
1152                 ; --- Operand 2 is a register ---
1153
1154 50              LDRB    R14,[R8,#0]             ;Read in the next character
1155                 CMP     R14,#'-'                ;Is it a minus sign?
1156                 ADDEQ   R8,R8,#1                ;Yes -- skip past it then
1157                 ORRNE   R9,R9,#(1<<23)          ;No -- offset is +ve
1158                 ORR     R9,R9,#(1<<25)          ;Offset is register based
1159                 MOV     R0,#1                   ;Set up some flags
1160                 BL      asm__op2reg             ;..read in operand 2
1161                 BVS     %95asm__sDataTrans      ;If error -- barf
1162
1163                 ; --- Finish off now ---
1164
1165 60              TST     R9,#(1<<24)             ;Is this pre-indexed?
1166                 BEQ     %90asm__sDataTrans      ;No -- return OK
1167                 LDRB    R14,[R8],#1             ;Read a character
1168                 CMP     R14,#']'                ;Is it the close character
1169                 ADRNE   R0,asm__noClose         ;No -- point to an error
1170                 BNE     %95asm__sDataTrans      ;And report an error
1171                 LDRB    R14,[R8,#0]             ;Read a character
1172                 CMP     R14,#'!'                ;Is it a '!'?
1173                 ORREQ   R9,R9,#(1<<21)          ;Yes -- set write back bit
1174                 ADDEQ   R8,R8,#1                ;And skip past the pling
1175                 B       %90asm__sDataTrans      ;All OK then
1176
1177                 ; --- The instruction is PC relative ---
1178
1179 70              BL      asm__readAddress        ;Read the address
1180                 BVS     %95asm__sDataTrans      ;Report the error
1181                 ORR     R9,R9,#(1<<24)          ;Make instruction pre-indexed
1182                 ORR     R9,R9,#(15<<16)         ;Rn = PC
1183                 BIC     R0,R0,#3                ;Clear the lower 2 bits
1184                 SUB     R0,R0,R7                ;Branch is PC relative
1185                 SUBS    R0,R0,#8                ;Allow for pipelining
1186                 RSBLT   R0,R0,#0                ;If -ve -- make it positive
1187                 ORRGE   R9,R9,#(1<<23)          ;Otherwise say offset is +ve
1188                 BIC     R0,R0,#&FF000000        ;Clear the top bits
1189                 TST     R0,#&FF000000           ;Are any of these bits set?
1190                 TSTEQ   R0,#&00FF0000           ;Or these bits?
1191                 TSTEQ   R0,#&0000F000           ;Or even these?
1192                 ADRNE   R0,asm__invOffset       ;Yes -- point to error
1193                 BNE     %95asm__sDataTrans      ;And report error
1194                 ORR     R9,R9,R0                ;Put value into instruction
1195
1196 90              BL      asm__endOfLine          ;Make sure it ends here
1197                 LDMVCFD R13!,{R14}              ;Load the link back
1198                 BICVCS  PC,R14,#V_flag          ;Return without error
1199
1200 95              LDMFD   R13!,{R14}              ;Load the link back
1201                 ORRS    PC,R14,#V_flag          ;Return with error
1202
1203 asm__invOffset  DCD     1
1204                 DCB     "Invalid offset",0
1205
1206 asm__noClose    DCD     1
1207                 DCB     "] Expected",0
1208
1209 asm__preAndT    DCD     1
1210                 DCB     "Can't set Trans pin with pre-indexed "
1211                 DCB     "data transfer",0
1212
1213                 LTORG
1214
1215 ; --- asm__mDataTrans ---
1216 ;
1217 ; On entry:     R8 == pointer into the instruction
1218 ;               R9 == instruction so far
1219 ;
1220 ; On exit:      VS and R0 == pointer to error or
1221 ;               VC and R8,R9 updated appropriately
1222 ;
1223 ; Use:          Deals with LDM/STM type instructions
1224
1225 asm__mDataTrans ROUT
1226
1227                 STMFD   R13!,{R14}              ;Stack the link register
1228                 MOV     R9,#&08000000           ;Make it identifiable
1229                 CMP     R5,#20                  ;Is it a load instruction
1230                 ORREQ   R9,R9,#(1<<20)          ;Yes -- make it so
1231                 MOV     R4,R5                   ;Remember the opcode
1232                 BL      asm__condition          ;Read the condition
1233                 LDRB    R14,[R8],#1             ;Read a character
1234                 CMP     R14,#'D'                ;Is it a 'D'?
1235                 CMPNE   R14,#'d'
1236                 BEQ     %10asm__mDataTrans      ;Yes -- jump ahead a bit
1237                 CMP     R14,#'I'                ;Is it an 'I'?
1238                 CMPNE   R14,#'i'
1239                 ORREQ   R9,R9,#(1<<23)          ;Yes -- make increase +ve
1240                 BEQ     %10asm__mDataTrans      ;...and jump ahead a bit
1241                 CMP     R14,#'F'                ;Is it an 'F'?
1242                 CMPNE   R14,#'f'
1243                 BEQ     %20asm__mDataTrans      ;Yes -- deal with it
1244                 CMP     R14,#'E'                ;Is it an 'E'?
1245                 CMPNE   R14,#'e'
1246                 BEQ     %30asm__mDataTrans      ;Yes -- deal with it
1247                 ADR     R0,asm__invStk          ;Point to the error message
1248                 B       %95asm__mDataTrans      ;And report it
1249
1250                 ; --- It's an I/D stack ---
1251
1252 10              LDRB    R14,[R8],#1             ;Load another character
1253                 CMP     R14,#'B'                ;Is it a 'B'?
1254                 CMPNE   R14,#'b'
1255                 ORREQ   R9,R9,#(1<<24)          ;Yes -- make it pre-indexed
1256                 CMPNE   R14,#'A'                ;Is it a 'A'?
1257                 CMPNE   R14,#'a'
1258                 ADRNE   R0,asm__invStk          ;Neither -- Point to error
1259                 BNE     %95asm__mDataTrans      ;And report it
1260                 B       %40asm__mDataTrans      ;Deal with the rest of it
1261
1262                 ; --- It's a F stack ---
1263
1264 20              LDRB    R14,[R8],#1             ;Load another character
1265                 CMP     R14,#'D'                ;Is it a 'D'?
1266                 CMPNE   R14,#'d'
1267                 CMPEQ   R4,#21                  ;...and is it a store?
1268                 ORREQ   R9,R9,#(1<<24)          ;Yes -- make it pre-indexed
1269                 BEQ     %40asm__mDataTrans      ;Deal with the rest of it
1270                 CMP     R14,#'D'                ;Is it a 'D'?
1271                 CMPNE   R14,#'d'
1272                 CMPEQ   R4,#20                  ;...and is it a load?
1273                 ORREQ   R9,R9,#(1<<23)          ;Yes -- make it increasing
1274                 BEQ     %40asm__mDataTrans      ;Deal with the rest of it
1275                 CMP     R14,#'A'                ;Is it a 'A'?
1276                 CMPNE   R14,#'a'
1277                 CMPEQ   R4,#21                  ;...and is it a store?
1278                 ORREQ   R9,R9,#&01800000        ;Yes -- make it pre & +ve
1279                 BEQ     %40asm__mDataTrans      ;Deal with the rest of it
1280                 CMP     R14,#'A'                ;Is it a 'A'?
1281                 CMPNE   R14,#'a'
1282                 CMPEQ   R4,#20                  ;...and is it a load?
1283                 BEQ     %40asm__mDataTrans      ;Yes -- deal with rest of it
1284                 ADR     R0,asm__invStk          ;Point to error
1285                 B       %95asm__mDataTrans      ;And report it
1286
1287                 ; --- It's a E stack ---
1288
1289 30              LDRB    R14,[R8],#1             ;Load another character
1290                 CMP     R14,#'D'                ;Is it a 'D'?
1291                 CMPNE   R14,#'d'
1292                 CMPEQ   R4,#21                  ;...and is it a store?
1293                 BEQ     %40asm__mDataTrans      ;Yes -- deal with rest of it
1294                 CMP     R14,#'D'                ;Is it a 'D'?
1295                 CMPNE   R14,#'d'
1296                 CMPEQ   R4,#20                  ;...and is it a load?
1297                 ORREQ   R9,R9,#&01800000        ;Yes -- make it increasing
1298                 BEQ     %40asm__mDataTrans      ;Deal with the rest of it
1299                 CMP     R14,#'A'                ;Is it a 'A'?
1300                 CMPNE   R14,#'a'
1301                 CMPEQ   R4,#21                  ;...and is it a store?
1302                 ORREQ   R9,R9,#(1<<23)          ;Yes -- make it +ve
1303                 BEQ     %40asm__mDataTrans      ;Deal with the rest of it
1304                 CMP     R14,#'A'                ;Is it a 'A'?
1305                 CMPNE   R14,#'a'
1306                 CMPEQ   R4,#20                  ;...and is it a load?
1307                 ORREQ   R9,R9,#(1<<24)          ;Yes -- make it pre-indexed
1308                 BEQ     %40asm__mDataTrans      ;Yes -- deal with rest of it
1309                 ADR     R0,asm__invStk          ;Point to error
1310                 B       %95asm__mDataTrans      ;And report it
1311
1312                 ; --- Now parse the rest of the instruction ---
1313
1314 40              BL      asm__doSpaces           ;Skip the following spaces
1315                 BVS     %95asm__mDataTrans      ;Report the error
1316                 BL      asm_register            ;Read in the next register
1317                 BVS     %95asm__mDataTrans      ;Report the error
1318                 ORR     R9,R9,R0,LSL #16        ;Store it in the instruction
1319                 LDRB    R14,[R8,#0]             ;Read the next character
1320                 CMP     R14,#'!'                ;Is it a pling?
1321                 ORREQ   R9,R9,#(1<<21)          ;Yes -- we want write back
1322                 ADDEQ   R8,R8,#1                ;...skip past the pling
1323                 BL      asm__comma              ;Skip the comma
1324                 BVS     %95asm__mDataTrans      ;Report the error
1325                 LDRB    R14,[R8],#1             ;Read the next character
1326                 CMP     R14,#'{'                ;Is it the '{'
1327                 ADRNE   R0,asm__expLOpen        ;No -- Point to error
1328                 BNE     %95asm__mDataTrans      ;...and report it
1329
1330                 ; --- Now we read in the register list ---
1331
1332 50              BL      asm_register            ;Read in the register
1333                 BVS     %95asm__mDataTrans      ;Report the error
1334                 MOV     R3,R0                   ;Remember this register
1335                 LDRB    R14,[R8,#0]             ;Load the next character
1336                 CMP     R14,#'-'                ;Is it a register range?
1337                 MOVNE   R4,R3                   ;No -- this is the final one
1338                 BNE     %60asm__mDataTrans      ;...and jump ahead a little
1339                 ADD     R8,R8,#1                ;Skip over the minus sign
1340                 BL      asm_register            ;Read in the register
1341                 BVS     %95asm__mDataTrans      ;Report the error
1342                 MOV     R4,R0                   ;Remember this register too
1343                 CMP     R3,R4                   ;Is first higher than second?
1344                 ADRGT   R0,asm__invListSyn      ;No -- Point to error
1345                 BGT     %95asm__mDataTrans      ;...and report it
1346 60              MOV     R5,#1                   ;Get a nice 1 value
1347                 ORR     R9,R9,R5,LSL R3         ;Set a register bit
1348                 ADD     R3,R3,#1                ;Increment the count
1349                 CMP     R3,R4                   ;Have we finished?
1350                 BLE     %60asm__mDataTrans      ;No -- keep on going
1351                 LDRB    R14,[R8,#0]             ;Get the next character
1352                 CMP     R14,#'}'                ;Is it a close bracket?
1353                 BEQ     %70asm__mDataTrans      ;Yes -- we're nearly finished
1354                 BL      asm__comma              ;Read in a comma
1355                 BVS     %95asm__mDataTrans      ;Report the error
1356                 B       %50asm__mDataTrans      ;Keep looping round
1357
1358 70              ADD     R8,R8,#1                ;Skip the bracket
1359                 LDRB    R14,[R8,#0]             ;Read in the next character
1360                 CMP     R14,#'^'                ;Is it the caret?
1361                 ORREQ   R9,R9,#(1<<22)          ;Yes -- set the 'S' bit
1362                 ADDEQ   R8,R8,#1                ;And skip over it
1363
1364 90              BL      asm__endOfLine          ;Make sure it ends here
1365                 LDMVCFD R13!,{R14}              ;Load the link back
1366                 BICVCS  PC,R14,#V_flag          ;Return without error
1367
1368 95              LDMFD   R13!,{R14}              ;Load the link back
1369                 ORRS    PC,R14,#V_flag          ;Return with error
1370
1371 asm__invStk     DCD     1
1372                 DCB     "Unrecognised stack type",0
1373
1374 asm__expLOpen   DCD     1
1375                 DCB     "Missing {",0
1376
1377 asm__invListSyn DCD     1
1378                 DCB     "Invalid list syntax",0
1379
1380                 LTORG
1381
1382 ; --- asm__swi ---
1383 ;
1384 ; On entry:     R8 == pointer into the instruction
1385 ;               R9 == instruction so far
1386 ;
1387 ; On exit:      VS and R0 == pointer to error or
1388 ;               VC and R8,R9 updated appropriately
1389 ;
1390 ; Use:          Deals with SWI instructions
1391
1392 asm__swi        ROUT
1393
1394                 STMFD   R13!,{R14}              ;Stack the link register
1395                 MOV     R9,#&0F000000           ;Make it a SWI then
1396                 BL      asm__condition          ;Read the condition code
1397                 BL      asm__doSpaces           ;Skip over spaces
1398                 BVS     %95asm__swi             ;Report possible error
1399
1400                 ; --- Try to read a number ---
1401
1402                 MOV     R0,#10                  ;Default base
1403                 MOV     R1,R8                   ;Point to the number
1404                 SWI     XOS_ReadUnsigned        ;Read it in
1405                 MOVVC   R8,R1                   ;All OK -- point to end
1406                 MOVVC   R0,R2                   ;Put number in R0
1407                 BVC     %80asm__swi             ;...and return
1408
1409                 ; --- It must be a string then ---
1410
1411                 MOV     R1,R8                   ;Point to it again
1412                 SWI     XOS_SWINumberFromString ;Translate to a number
1413                 BVS     %04asm__swi             ;On error -- look ahead
1414
1415 00asm__swi      LDRB    R14,[R8],#1             ;Read a character
1416                 CMP     R14,#32                 ;Is it a terminator?
1417                 BGT     %00asm__swi             ;No -- keep looking
1418                 SUB     R8,R8,#1                ;We overshot
1419                 B       %80asm__swi             ;...and return
1420
1421                 ; --- As a last resort, see if it's an OS_WriteI ---
1422
1423 04asm__swi      MOV     R4,R8                   ;Point to the first character
1424                 BL      str_buffer              ;Get a buffer use
1425                 MOV     R0,R1                   ;Remember this buffer
1426 05asm__swi      LDRB    R14,[R4],#1             ;Read a character
1427                 CMP     R14,#'+'                ;Is it a plus?
1428                 BEQ     %10asm__swi             ;Yes -- jump ahead
1429                 CMP     R14,#31                 ;Or a terminatore?
1430                 BLE     %95asm__swi             ;Yes -- return
1431                 STRB    R14,[R0],#1             ;Store the character
1432                 B       %05asm__swi             ;Keep on searching
1433
1434                 ; --- We have found a plus sign ---
1435
1436 10asm__swi      MOV     R14,#0                  ;Get a NULL byte
1437                 STRB    R14,[R0,#0]             ;Store at end of sting
1438                 SWI     XOS_SWINumberFromString ;Translate to a number
1439                 BVS     %95asm__swi             ;Return possible error
1440                 CMP     R0,#&100                ;Is it OS_WriteC?
1441                 ADRNE   R0,asm__unknownSWI      ;No -- point to error message
1442                 BNE     %95asm__swi             ;..and return error
1443                 MOV     R0,#10                  ;Default base to read
1444                 MOV     R1,R4                   ;Point to after '+'
1445                 SWI     XOS_ReadUnsigned        ;Read in a number
1446                 BVC     %70asm__swi             ;All OK -- jump ahead
1447                 LDRB    R14,[R4,#0]             ;Read the next character
1448                 CMP     R14,#'"'                ;Is it a quote?
1449                 CMPNE   R14,#'''                ;Allow single ones too
1450                 ADRNE   R0,asm__unknownSWI      ;No -- point to error
1451                 BNE     %95asm__swi             ;And return error
1452                 LDRB    R1,[R4,#2]              ;Read the next character
1453                 CMP     R1,R14                  ;Is it a quote?
1454                 ADRNE   R0,asm__unknownSWI      ;No -- point to error
1455                 BNE     %95asm__swi             ;And return error
1456                 LDRB    R2,[R4,#1]              ;Read the character
1457                 ADD     R1,R4,#3                ;Skip over string
1458
1459 70asm__swi      MOV     R0,R2                   ;Put number in R0
1460                 ADD     R0,R0,#&100             ;Form correct number
1461                 MOV     R8,R1                   ;Point to end of string
1462
1463 80asm__swi      TST     R0,#&FF000000           ;Are these bits set?
1464                 ADRNE   R0,asm__invSWINum       ;Yes -- point to error
1465                 BNE     %95asm__swi             ;...and return
1466                 ORR     R9,R9,R0                ;ORR in the number
1467
1468 90asm__swi      BL      asm__endOfLine          ;Make sure it ends here
1469                 LDMVCFD R13!,{R14}              ;Load the link back
1470                 BICVCS  PC,R14,#V_flag          ;Return without error
1471
1472 95asm__swi      LDMFD   R13!,{R14}              ;Load the link back
1473                 ORRS    PC,R14,#V_flag          ;Return with error
1474
1475 asm__unknownSWI DCD     1
1476                 DCB     "SWI name not known",0
1477
1478 asm__invSWINum  DCD     1
1479                 DCB     "SWI number too high",0
1480
1481                 LTORG
1482
1483 ; --- asm__adr ---
1484 ;
1485 ; On entry:     R8 == pointer into the instruction
1486 ;               R9 == instruction so far
1487 ;
1488 ; On exit:      VS and R0 == pointer to error or
1489 ;               VC and R8,R9 updated appropriately
1490 ;
1491 ; Use:          Copes with the ADR directive
1492
1493 asm__adr        ROUT
1494
1495                 STMFD   R13!,{R14}              ;Stack the link register
1496                 MOV     R9,#&02000000           ;ALU with immediate operand 2
1497                 ORR     R9,R9,#(15<<16)         ;Make Rn = PC
1498                 BL      asm__condition          ;Read a condition
1499                 BL      asm__doSpaces           ;Skips past spaces
1500                 BVS     %95asm__adr             ;Complain bitterley
1501                 BL      asm_register            ;Read in a register
1502                 BVS     %95asm__adr             ;Complain if we need to
1503                 ORR     R9,R9,R0,LSL#12         ;Set up Rd
1504                 BL      asm__comma              ;Skip over the comma
1505                 BVS     %95asm__adr             ;Complain if we need to
1506                 BL      asm__readAddress        ;Read the following address
1507                 BVS     %95asm__adr             ;Complain if we need to
1508                 SUB     R0,R0,#8                ;Allow for pipelining
1509                 CMP     R0,R7                   ;What sort of offset is it?
1510                 SUBLT   R0,R7,R0                ;Maybe its positive
1511                 SUBGE   R0,R0,R7                ;Or even positive
1512                 ORRLT   R9,R9,#&00400000        ;Make it a SUB
1513                 ORRGE   R9,R9,#&00800000        ;Or an ADD as appropriate
1514                 BL      asm__doConstShift       ;Make it into a valid shift
1515                 BVS     %95asm__adr             ;Complain n an error
1516
1517 90asm__adr      BL      asm__endOfLine          ;Make sure it ends here
1518                 LDMVCFD R13!,{R14}              ;Load the link back
1519                 BICVCS  PC,R14,#V_flag          ;Return without error
1520
1521 95asm__adr      LDMFD   R13!,{R14}              ;Load the link back
1522                 ORRS    PC,R14,#V_flag          ;Return with error
1523
1524                 LTORG
1525
1526 ; --- asm__swp ---
1527 ;
1528 ; On entry:     R8 == pointer into the instruction
1529 ;               R9 == instruction so far
1530 ;
1531 ; On exit:      VS and R0 == pointer to error or
1532 ;               VC and R8,R9 updated appropriately
1533 ;
1534 ; Use:          Deals with SWP instructions
1535
1536 asm__swp        ROUT
1537
1538                 STMFD   R13!,{R14}              ;Save the link
1539                 MOV     R9,#&01000000           ;Make it identifiable
1540                 ORR     R9,R9,#&90              ;Set these bits right too
1541                 BL      asm__condition          ;Read the condition
1542                 LDRB    R14,[R8,#0]             ;Load the next character
1543                 CMP     R14,#'B'                ;Is it a 'B'
1544                 CMPNE   R14,#'b'
1545                 ADDEQ   R8,R8,#1                ;Yes -- skip over it
1546                 ORREQ   R9,R9,#(1<<22)          ;...and make it a byte trans.
1547                 BL      asm__doSpaces           ;Skip spaces
1548                 BVS     %95asm__swp             ;And complain if we can
1549                 BL      asm_register            ;Read a register
1550                 ORRVC   R9,R9,R0,LSL #12        ;Put Rd in instruction
1551                 BLVC    asm__comma              ;And read a comma
1552                 BLVC    asm_register            ;Read a register
1553                 ORRVC   R9,R9,R0                ;Put Rm in instruction
1554                 BLVC    asm__comma              ;And read a comma
1555                 BVS     %95asm__swp             ;And complain if we can
1556                 LDRB    R14,[R8],#1             ;Load the next character
1557                 CMP     R14,#'['                ;Is it a '['
1558                 ADRNE   R0,asm__invSWPSyn       ;No -- point to the error
1559                 BNE     %95asm__swp             ;...and report it
1560                 BL      asm_register            ;Read a register
1561                 BVS     %95asm__swp             ;And complain if we can
1562                 ORR     R9,R9,R0,LSL #16        ;Put Rn in instruction
1563                 LDRB    R14,[R8],#1             ;Load the next character
1564                 CMP     R14,#']'                ;Is it a ']'
1565                 ADRNE   R0,asm__invSWPSyn       ;No -- point to the error
1566                 BNE     %95asm__swp             ;...and report it
1567
1568 90asm__swp      BL      asm__endOfLine          ;Make sure it ends here
1569                 LDMVCFD R13!,{R14}              ;Load the link back
1570                 BICVCS  PC,R14,#V_flag          ;Return without error
1571
1572 95asm__swp      LDMFD   R13!,{R14}              ;Load the link back
1573                 ORRS    PC,R14,#V_flag          ;Return with error
1574
1575 asm__invSWPSyn  DCD     1
1576                 DCB     "Invalid synatax for SWP",0
1577
1578                 LTORG
1579
1580 ; --- asm__coproc ---
1581 ;
1582 ; On entry:     R8 == pointer into the instruction
1583 ;
1584 ; On exit:      VS and R0 == pointer to error or
1585 ;               VC and R8 updated appropriately
1586 ;                      R0 == co-processor number
1587 ;
1588 ; Use:          Reads a co-processor number of the form CPxx
1589
1590 asm__coproc     ROUT
1591
1592                 STMFD   R13!,{R14}              ;Stack the link register
1593                 LDRB    R14,[R8],#1             ;Read a character
1594                 CMP     R14,#'C'                ;Is it a 'C'?
1595                 CMPNE   R14,#'c'
1596                 ADRNE   R0,asm__invCoproc       ;No -- point to error
1597                 BNE     %95asm__coproc          ;...and return
1598                 LDRB    R14,[R8],#1             ;Read a character
1599                 CMP     R14,#'P'                ;Is it a 'P'?
1600                 CMPNE   R14,#'p'
1601                 ADRNE   R0,asm__invCoproc       ;No -- point to error
1602                 BNE     %95asm__coproc          ;...and return
1603                 BL      asm__constant           ;Read in a constant
1604                 CMP     R0,#16                  ;Is it in range?
1605                 ADRHS   R0,asm__invCoproc       ;No -- point to error
1606                 BHS     %95asm__coproc          ;...and return
1607
1608 90asm__coproc   LDMFD   R13!,{R14}              ;Load the link back
1609                 BICS    PC,R14,#V_flag          ;Return without error
1610
1611 95asm__coproc   LDMFD   R13!,{R14}              ;Load the link back
1612                 ORRS    PC,R14,#V_flag          ;Return with error
1613
1614 asm__invCoproc  DCD     1
1615                 DCB     "Invalid co-processor number",0
1616
1617                 LTORG
1618
1619 ; --- asm__coprocReg ---
1620 ;
1621 ; On entry:     R8 == pointer into the instruction
1622 ;
1623 ; On exit:      VS and R0 == pointer to error or
1624 ;               VC and R8 updated appropriately
1625 ;                      R0 == co-processor number
1626 ;
1627 ; Use:          Reads a co-processor register number of the form Cxx
1628
1629 asm__coprocReg  ROUT
1630
1631                 STMFD   R13!,{R14}              ;Stack the link register
1632                 LDRB    R14,[R8],#1             ;Read a character
1633                 CMP     R14,#'C'                ;Is it a 'C'?
1634                 CMPNE   R14,#'c'
1635                 ADRNE   R0,asm__invCoReg        ;No -- point to error
1636                 BNE     %95asm__coprocReg       ;...and return
1637                 BL      asm__constant           ;Read in a constant
1638                 CMP     R0,#16                  ;Is it in range?
1639                 ADRHS   R0,asm__invCoReg        ;No -- point to error
1640                 BHS     %95asm__coprocReg       ;...and return
1641
1642 90              LDMFD   R13!,{R14}              ;Load the link back
1643                 BICS    PC,R14,#V_flag          ;Return without error
1644
1645 95              LDMFD   R13!,{R14}              ;Load the link back
1646                 ORRS    PC,R14,#V_flag          ;Return with error
1647
1648 asm__invCoReg   DCD     1
1649                 DCB     "Invalid co-processor register",0
1650
1651                 LTORG
1652
1653 ; --- asm__cpOpc ---
1654 ;
1655 ; On entry:     R0 == maximum number allowed
1656 ;               R8 == pointer into the instruction
1657 ;
1658 ; On exit:      VS and R0 == pointer to error or
1659 ;               VC and R8 updated appropriately
1660 ;                      R0 == co-processor number
1661 ;
1662 ; Use:          Reads a co-processor register number of the form xx.
1663 ;               It ensures that the number is between 0 and R0
1664
1665 asm__cpOpc      ROUT
1666
1667                 STMFD   R13!,{R14}              ;Stack the link register
1668                 MOV     R1,R0                   ;Remember this value
1669                 BL      asm__constant           ;Read in a constant
1670                 CMP     R0,R1                   ;Is it in range?
1671                 ADRHI   R0,asm__invCoOp         ;No -- point to error
1672                 BHI     %95asm__cpOpc           ;...and return
1673
1674 90asm__cpOpc    LDMFD   R13!,{R14}              ;Load the link back
1675                 BICS    PC,R14,#V_flag          ;Return without error
1676
1677 95asm__cpOpc    LDMFD   R13!,{R14}              ;Lad the link back
1678                 ORRS    PC,R14,#V_flag          ;Return with error
1679
1680 asm__invCoOp    DCD     1
1681                 DCB     "Operation code is out of range",0
1682
1683                 LTORG
1684
1685 ; --- asm__cdp ---
1686 ;
1687 ; On entry:     R8 == pointer into the instruction
1688 ;               R9 == instruction so far
1689 ;
1690 ; On exit:      VS and R0 == pointer to error or
1691 ;               VC and R8,R9 updated appropriately
1692 ;
1693 ; Use:          Deals with CDP instructions
1694
1695 asm__cdp        ROUT
1696                 STMFD   R13!,{R14}
1697
1698                 MOV     R9,#&0E000000           ;Set up the instruction
1699                 BL      asm__condition          ;Read the condition type
1700                 BL      asm__doSpaces           ;Skip spaces
1701                 BLVC    asm__coproc             ;Read the co-processor number
1702                 ORRVC   R9,R9,R0,LSL #8         ;Put it in the instruction
1703                 BLVC    asm__comma              ;Read a comma
1704                 MOVVC   R0,#15                  ;Maximum allowed operation
1705                 BLVC    asm__cpOpc              ;Read the operation type
1706                 ORRVC   R9,R9,R0,LSL#20         ;Put it in the instruction
1707                 BLVC    asm__comma              ;Read a comma
1708                 BLVC    asm__coprocReg          ;Read CRd
1709                 ORRVC   R9,R9,R0,LSL#12         ;Put it in the instruction
1710                 BLVC    asm__comma              ;Read a comma
1711                 BLVC    asm__coprocReg          ;Read CRn
1712                 ORRVC   R9,R9,R0,LSL#16         ;Put it in the instruction
1713                 BLVC    asm__comma              ;Read a comma
1714                 BLVC    asm__coprocReg          ;Read CRm
1715                 ORRVC   R9,R9,R0                ;Put it in the instruction
1716                 BVS     %95asm__cdp             ;Return possible error
1717                 BL      asm__comma              ;Read a comma
1718                 BVS     %90asm__cdp             ;If no comma, return OK
1719                 BL      asm__constant           ;Read a constant
1720                 BVS     %95asm__cdp             ;Return possible error
1721                 CMP     R0,#8                   ;Is number out of range?
1722                 ADRHS   R0,asm__invAux          ;Yes -- point to error
1723                 BHS     %95asm__cdp             ;Return possible error
1724                 ORR     R9,R9,R0,LSL #5         ;Store the number
1725
1726 90asm__cdp      BL      asm__endOfLine          ;Make sure it ends here
1727                 LDMVCFD R13!,{R14}              ;Load the link back
1728                 BICVCS  PC,R14,#V_flag          ;Return without error
1729
1730 95asm__cdp      LDMFD   R13!,{R14}              ;Load the link back
1731                 ORRS    PC,R14,#V_flag          ;Return with error
1732
1733                 LTORG
1734
1735 asm__invAux     DCD     1
1736                 DCB     "Auxilary expression must be 0-7",0
1737
1738 ; --- asm__coRegTrans ---
1739 ;
1740 ; On entry:     R8 == pointer into the instruction
1741 ;               R9 == instruction so far
1742 ;
1743 ; On exit:      VS and R0 == pointer to error or
1744 ;               VC and R8,R9 updated appropriately
1745 ;
1746 ; Use:          Deals with MCR/MRC instructions
1747
1748 asm__coRegTrans ROUT
1749                 STMFD   R13!,{R14}
1750
1751                 MOV     R9,#&0E000000           ;Set up the instruction
1752                 ORR     R9,R9,#(1<<4)           ;This bit should be set
1753                 CMP     R5,#29                  ;Is it MCR?
1754                 ORREQ   R9,R9,#(1<<20)          ;Yes -- make it so
1755                 BL      asm__condition          ;Read the condition type
1756                 BL      asm__doSpaces           ;Skip spaces
1757                 BLVC    asm__coproc             ;Read the co-processor number
1758                 ORRVC   R9,R9,R0,LSL #8         ;Put it in the instruction
1759                 BLVC    asm__comma              ;Read a comma
1760                 MOVVC   R0,#7                   ;Maximum allowed operation
1761                 BLVC    asm__cpOpc              ;Read the operation type
1762                 ORRVC   R9,R9,R0,LSL#21         ;Put it in the instruction
1763                 BLVC    asm__comma              ;Read a comma
1764                 BLVC    asm_register            ;Read Rd
1765                 ORRVC   R9,R9,R0,LSL#12         ;Put it in the instruction
1766                 BLVC    asm__comma              ;Read a comma
1767                 BLVC    asm__coprocReg          ;Read CRn
1768                 ORRVC   R9,R9,R0,LSL#16         ;Put it in the instruction
1769                 BLVC    asm__comma              ;Read a comma
1770                 BLVC    asm__coprocReg          ;Read CRm
1771                 ORRVC   R9,R9,R0                ;Put it in the instruction
1772                 BVS     %95asm__coRegTrans      ;Return possible error
1773                 BL      asm__comma              ;Read a comma
1774                 BVS     %90asm__coRegTrans      ;If no comma, return OK
1775                 BL      asm__constant           ;Read a constant
1776                 BVS     %95asm__coRegTrans      ;Return possible error
1777                 CMP     R0,#8                   ;Is number out of range?
1778                 ADRHS   R0,asm__invAux          ;Yes -- point to error
1779                 BHS     %95asm__coRegTrans      ;Return possible error
1780                 ORR     R9,R9,R0,LSL #5         ;Store the number
1781
1782 90              BL      asm__endOfLine          ;Make sure it ends here
1783                 LDMVCFD R13!,{R14}              ;Load the link back
1784                 BICVCS  PC,R14,#V_flag          ;Return without error
1785
1786 95              LDMFD   R13!,{R14}              ;Load the link back
1787                 ORRS    PC,R14,#V_flag          ;Return with error
1788
1789                 LTORG
1790
1791 ; --- asm__coDataTrans ---
1792 ;
1793 ; On entry:     R8 == pointer into the instruction
1794 ;               R9 == instruction so far
1795 ;
1796 ; On exit:      VS and R0 == pointer to error or
1797 ;               VC and R8,R9 updated appropriately
1798 ;
1799 ; Use:          Deals with LDC/STC instructions
1800
1801 asm__coDataTrans ROUT
1802
1803                 STMFD   R13!,{R14}
1804
1805                 MOV     R9,#&0C000000           ;Set up the instruction
1806                 CMP     R5,#26                  ;Is it STC?
1807                 ORRNE   R9,R9,#(1<<20)          ;No -- make it load then
1808                 BL      asm__condition          ;Read the condition type
1809                 LDRB    R14,[R8,#0]             ;Read the next character
1810                 CMP     R14,#'L'                ;Is it an 'L'?
1811                 CMPNE   R14,#'l'
1812                 ORREQ   R9,R9,#(1<<22)          ;Yes -- make it long transfer
1813                 ADDEQ   R8,R8,#1                ;...skip over it
1814                 LDREQB  R14,[R8,#0]             ;...and read another char
1815                 CMP     R14,#'T'                ;Is it a 'T'?
1816                 CMPNE   R14,#'t'
1817                 ORREQ   R9,R9,#(1<<21)          ;Yes -- set 'W' bit
1818                 ADDEQ   R8,R8,#1                ;...skip over it
1819                 BL      asm__doSpaces           ;Skip spaces
1820
1821                 BLVC    asm__coproc             ;Read the co-processor number
1822                 ORRVC   R9,R9,R0,LSL #8         ;Put it in the instruction
1823                 BLVC    asm__comma              ;Read a comma
1824                 BLVC    asm__coprocReg          ;Read CRd
1825                 ORRVC   R9,R9,R0,LSL#12         ;Put it in the instruction
1826                 BLVC    asm__comma              ;Read a comma
1827                 BVS     %95asm__coDataTrans     ;Return possible error
1828
1829                 LDRB    R14,[R8,#0]             ;Read a character
1830                 CMP     R14,#'['                ;Is it an open bracket?
1831                 BNE     %70asm__coDataTrans     ;No -- jump ahead
1832                 ADD     R8,R8,#1                ;Skip over the bracket
1833
1834                 BL      asm_register            ;Read a register name
1835                 BVS     %95asm__coDataTrans     ;Report a possible error
1836                 ORR     R9,R9,R0,LSL #16        ;Insert Rn in nicely
1837                 LDRB    R14,[R8,#0]             ;Read a character
1838                 CMP     R14,#']'                ;Is it an close bracket?
1839                 ORRNE   R9,R9,#(1<<24)          ;No -- set 'P' bit
1840                 ADDEQ   R8,R8,#1                ;Yes -- skip over it
1841                 BEQ     %10asm__coDataTrans     ;...and jump ahead a little
1842                 TST     R9,#(1<<21)             ;Is the 'W' bit set?
1843                 ADRNEL  R0,asm__preAndT         ;Yes -- point to an error
1844                 BNE     %95asm__coDataTrans     ;And report the error
1845
1846 10              BL      asm__comma              ;Read in the comma
1847                 ORRVS   R9,R9,#(1<<23)          ;No comma -- offset is +ve
1848                 BVS     %60asm__coDataTrans     ;...tidy up
1849
1850                 ; --- Now for the last op (easy one, this) ---
1851
1852                 LDRB    R14,[R8]                ;Read a character
1853                 CMP     R14,#'#'                ;Is is a hash?
1854                 ADRNE   R0,asm__invCoOffset     ;No -- point to error
1855                 BNE     %95asm__coDataTrans     ;And return an error
1856
1857                 ; --- Operand 2 is an immediate constant ---
1858
1859                 ADD     R8,R8,#1                ;Skip past the '#'
1860                 BL      asm__constant           ;Read the constant
1861                 BVS     %95asm__coDataTrans     ;If error -- barf
1862                 CMP     R0,#0                   ;Is it negative
1863                 RSBLT   R0,R0,#0                ;Yes -- make it positive
1864                 ORRGE   R9,R9,#(1<<23)          ;No -- offset is +ve
1865                 MOV     R0,R0,LSR#2             ;Scale it a little
1866                 AND     R1,R0,#&FF              ;Just get lower bits
1867                 CMP     R1,R0                   ;Were just these set?
1868                 ADRNEL  R0,asm__invOffset       ;No -- point to error
1869                 BNE     %95asm__coDataTrans     ;And report error
1870                 ORR     R9,R9,R0                ;ORR in the value
1871
1872                 ; --- Finish off now ---
1873
1874 60              TST     R9,#(1<<24)             ;Is this pre-indexed?
1875                 BEQ     %90asm__coDataTrans     ;No -- return OK
1876                 LDRB    R14,[R8],#1             ;Read a character
1877                 CMP     R14,#']'                ;Is it the close character
1878                 ADRNEL  R0,asm__noClose         ;No -- point to an error
1879                 BNE     %95asm__coDataTrans     ;And report an error
1880                 LDRB    R14,[R8,#0]             ;Read a character
1881                 CMP     R14,#'!'                ;Is it a '!'?
1882                 ORREQ   R9,R9,#(1<<21)          ;Yes -- set write back bit
1883                 ADDEQ   R8,R8,#1                ;And skip past the pling
1884                 B       %90asm__coDataTrans     ;All OK then
1885
1886                 ; --- The instruction is PC relative ---
1887
1888 70              BL      asm__readAddress        ;Read the address
1889                 BVS     %95asm__coDataTrans     ;Report the error
1890                 TST     R0,#3                   ;Is the address word-aligned
1891                 ADRNE   R0,asm__ldcWord         ;No -- point to error
1892                 BNE     %95asm__coDataTrans     ;Report the error
1893                 ORR     R9,R9,#(1<<24)          ;Make instruction pre-indexed
1894                 ORR     R9,R9,#(15<<16)         ;Rn = PC
1895                 SUB     R0,R0,R7                ;Branch is PC relative
1896                 SUBS    R0,R0,#8                ;Allow for pipelining
1897                 RSBLT   R0,R0,#0                ;If -ve -- make it positive
1898                 ORRGE   R9,R9,#(1<<23)          ;Otherwise say offset is +ve
1899                 MOV     R0,R0,LSR #2            ;Shift the offset down
1900                 AND     R1,R0,#&FF              ;Just get lower bits
1901                 CMP     R1,R0                   ;Were just these set?
1902                 ADRNEL  R0,asm__invOffset       ;No -- point to error
1903                 BNE     %95asm__coDataTrans     ;And report error
1904                 ORR     R9,R9,R0                ;Put value into instruction
1905
1906 90              BL      asm__endOfLine          ;Make sure it ends here
1907                 LDMVCFD R13!,{R14}              ;Load the link back
1908                 BICVCS  PC,R14,#V_flag          ;Return without error
1909
1910 95              LDMFD   R13!,{R14}              ;Load the link back
1911                 ORRS    PC,R14,#V_flag          ;Return with error
1912
1913 asm__ldcWord    DCD     1
1914                 DCB     "Target is not word aligned",0
1915
1916 asm__invCoOffset DCD    1
1917                 DCB     "Offset must be immediate constant",0
1918
1919                 LTORG
1920
1921 ;----- That's all, folks ----------------------------------------------------
1922
1923                 END