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