342
|
1
|
364
|
2 from ..basetarget import Instruction, LabelAddress
|
365
|
3 from ...bitfun import encode_imm32
|
342
|
4
|
|
5 from .token import ArmToken
|
345
|
6 from .registers import R0, SP, ArmRegister
|
|
7
|
|
8
|
342
|
9
|
|
10 # Instructions:
|
|
11
|
|
12 class ArmInstruction(Instruction):
|
|
13 def __init__(self):
|
|
14 self.token = ArmToken()
|
|
15
|
|
16
|
353
|
17 class ConstantData(ArmInstruction):
|
346
|
18 def __init__(self, v):
|
|
19 super().__init__()
|
353
|
20 assert isinstance(v, int)
|
346
|
21 self.v = v
|
|
22
|
353
|
23
|
364
|
24 class Dcd(ArmInstruction):
|
|
25 def __init__(self, v):
|
|
26 super().__init__()
|
|
27 assert isinstance(v, int) or isinstance(v, LabelAddress)
|
|
28 self.v = v
|
|
29
|
346
|
30 def encode(self):
|
364
|
31 if type(self.v) is int:
|
|
32 self.token[0:32] = self.v
|
|
33 else:
|
|
34 self.token[0:32] = 0
|
346
|
35 return self.token.encode()
|
|
36
|
364
|
37 def relocations(self):
|
|
38 if type(self.v) is LabelAddress:
|
|
39 return [(self.v.name, 'absaddr32')]
|
|
40 return []
|
|
41
|
350
|
42 def __repr__(self):
|
364
|
43 if type(self.v) is int:
|
|
44 return 'DCD {}'.format(hex(self.v))
|
|
45 else:
|
|
46 return 'DCD ={}'.format(self.v.name)
|
350
|
47
|
346
|
48
|
353
|
49 class Db(ConstantData):
|
|
50 def encode(self):
|
|
51 assert self.v < 256
|
|
52 return bytes([self.v])
|
|
53
|
|
54 def __repr__(self):
|
|
55 return 'DB {}'.format(hex(self.v))
|
|
56
|
|
57
|
346
|
58 def Mov(*args):
|
|
59 if len(args) == 2:
|
|
60 if isinstance(args[1], int):
|
|
61 return Mov1(*args)
|
|
62 elif isinstance(args[1], ArmRegister):
|
|
63 return Mov2(*args)
|
|
64 raise Exception()
|
|
65
|
|
66
|
|
67 class Mov1(ArmInstruction):
|
342
|
68 """ Mov Rd, imm16 """
|
|
69 def __init__(self, reg, imm):
|
|
70 super().__init__()
|
346
|
71 assert type(imm) is int
|
342
|
72 self.reg = reg
|
|
73 self.imm = imm
|
|
74
|
|
75 def encode(self):
|
346
|
76 self.token[0:12] = encode_imm32(self.imm)
|
345
|
77 self.token.Rd = self.reg.num
|
342
|
78 self.token[16:20] = 0
|
346
|
79 self.token[20] = 0 # Set flags
|
342
|
80 self.token[21:28] = 0b0011101
|
346
|
81 self.token.cond = AL
|
342
|
82 return self.token.encode()
|
|
83
|
|
84 def __repr__(self):
|
345
|
85 return 'Mov {}, {}'.format(self.reg, self.imm)
|
|
86
|
|
87
|
346
|
88 class Mov2(ArmInstruction):
|
|
89 def __init__(self, rd, rm):
|
|
90 super().__init__()
|
|
91 self.rd = rd
|
|
92 self.rm = rm
|
|
93
|
|
94 def encode(self):
|
|
95 self.token[0:4] = self.rm.num
|
|
96 self.token[4:12] = 0
|
|
97 self.token[12:16] = self.rd.num
|
|
98 self.token[16:20] = 0
|
|
99 self.token.S = 0
|
|
100 self.token[21:28] = 0xD
|
|
101 self.token.cond = AL
|
|
102 return self.token.encode()
|
|
103
|
350
|
104 def __repr__(self):
|
|
105 return 'MOV {}, {}'.format(self.rd, self.rm)
|
|
106
|
346
|
107
|
352
|
108 def Cmp(*args):
|
|
109 if len(args) == 2:
|
|
110 if isinstance(args[1], int):
|
|
111 return Cmp1(*args)
|
|
112 elif isinstance(args[1], ArmRegister):
|
|
113 return Cmp2(*args)
|
|
114 raise Exception()
|
|
115
|
|
116
|
|
117 class Cmp1(ArmInstruction):
|
|
118 """ CMP Rn, imm """
|
|
119 def __init__(self, reg, imm):
|
|
120 super().__init__()
|
|
121 assert type(imm) is int
|
|
122 self.reg = reg
|
|
123 self.imm = imm
|
|
124
|
|
125 def encode(self):
|
|
126 self.token[0:12] = encode_imm32(self.imm)
|
|
127 self.token.Rn = self.reg.num
|
|
128 self.token[20:28] = 0b00110101
|
|
129 self.token.cond = AL
|
|
130 return self.token.encode()
|
|
131
|
|
132 def __repr__(self):
|
|
133 return 'CMP {}, {}'.format(self.reg, self.imm)
|
|
134
|
|
135
|
|
136 class Cmp2(ArmInstruction):
|
|
137 """ CMP Rn, Rm """
|
|
138 def __init__(self, rn, rm):
|
|
139 super().__init__()
|
|
140 self.rn = rn
|
|
141 self.rm = rm
|
|
142
|
|
143 def encode(self):
|
|
144 self.token.Rn = self.rn.num
|
|
145 self.token.Rm = self.rm.num
|
|
146 self.token[7:16] = 0
|
|
147 self.token[20:28] = 0b10101
|
|
148 self.token.cond = AL
|
|
149 return self.token.encode()
|
|
150
|
|
151 def __repr__(self):
|
|
152 return 'CMP {}, {}'.format(self.rn, self.rm)
|
|
153
|
|
154
|
345
|
155 def Add(*args):
|
|
156 if len(args) == 3 and isinstance(args[0], ArmRegister) and \
|
|
157 isinstance(args[1], ArmRegister):
|
|
158 if isinstance(args[2], ArmRegister):
|
|
159 return Add1(args[0], args[1], args[2])
|
|
160 elif isinstance(args[2], int):
|
|
161 return Add2(args[0], args[1], args[2])
|
|
162 raise Exception()
|
|
163
|
|
164 def Sub(*args):
|
|
165 if len(args) == 3 and isinstance(args[0], ArmRegister) and \
|
|
166 isinstance(args[1], ArmRegister):
|
|
167 if isinstance(args[2], ArmRegister):
|
|
168 return Sub1(args[0], args[1], args[2])
|
|
169 elif isinstance(args[2], int):
|
|
170 return Sub2(args[0], args[1], args[2])
|
|
171 raise Exception()
|
|
172
|
352
|
173
|
346
|
174 def Mul(*args):
|
|
175 return Mul1(args[0], args[1], args[2])
|
|
176
|
|
177
|
354
|
178 class Mul1(ArmInstruction):
|
346
|
179 def __init__(self, rd, rn, rm):
|
|
180 super().__init__()
|
|
181 self.rd = rd
|
|
182 self.rn = rn
|
|
183 self.rm = rm
|
|
184
|
|
185 def encode(self):
|
|
186 self.token[0:4] = self.rn.num
|
|
187 self.token[4:8] = 0b1001
|
|
188 self.token[8:12] = self.rm.num
|
|
189 self.token[16:20] = self.rd.num
|
|
190 self.token.S = 0
|
|
191 self.token.cond = AL
|
|
192 return self.token.encode()
|
|
193
|
|
194
|
345
|
195 class OpRegRegReg(ArmInstruction):
|
|
196 """ add rd, rn, rm """
|
|
197 def __init__(self, rd, rn, rm, shift=0):
|
|
198 super().__init__()
|
|
199 self.rd = rd
|
|
200 self.rn = rn
|
|
201 self.rm = rm
|
|
202
|
|
203 def encode(self):
|
|
204 self.token[0:4] = self.rm.num
|
|
205 self.token[4] = 0
|
|
206 self.token[5:7] = 0
|
|
207 self.token[7:12] = 0 # Shift
|
|
208 self.token.Rd = self.rd.num
|
|
209 self.token.Rn = self.rn.num
|
|
210 self.token.S = 0 # Set flags
|
|
211 self.token[21:28] = self.opcode
|
|
212 self.token.cond = 0xE # Always!
|
|
213 return self.token.encode()
|
|
214
|
|
215 def __repr__(self):
|
354
|
216 return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm)
|
345
|
217
|
|
218
|
|
219 class Add1(OpRegRegReg):
|
354
|
220 mnemonic = 'ADD'
|
345
|
221 opcode = 0b0000100
|
|
222
|
|
223
|
|
224 class Sub1(OpRegRegReg):
|
354
|
225 mnemonic = 'SUB'
|
345
|
226 opcode = 0b0000010
|
|
227
|
|
228
|
|
229 class Orr1(OpRegRegReg):
|
354
|
230 mnemonic = 'ORR'
|
345
|
231 opcode = 0b0001100
|
|
232
|
342
|
233
|
356
|
234 class And1(OpRegRegReg):
|
|
235 mnemonic = 'AND'
|
|
236 opcode = 0b0000000
|
|
237
|
|
238
|
|
239 class ShiftBase(ArmInstruction):
|
|
240 """ ? rd, rn, rm """
|
|
241 def __init__(self, rd, rn, rm):
|
|
242 super().__init__()
|
|
243 self.rd = rd
|
|
244 self.rn = rn
|
|
245 self.rm = rm
|
|
246
|
|
247 def encode(self):
|
|
248 self.token[0:4] = self.rn.num
|
|
249 self.token[4:8] = self.opcode
|
|
250 self.token[8:12] = self.rm.num
|
|
251 self.token[12:16] = self.rd.num
|
|
252 self.token.S = 0 # Set flags
|
|
253 self.token[21:28] = 0b1101
|
|
254 self.token.cond = 0xE # Always!
|
|
255 return self.token.encode()
|
|
256
|
|
257 def __repr__(self):
|
|
258 return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm)
|
|
259
|
|
260
|
|
261 class Lsr1(ShiftBase):
|
|
262 mnemonic = 'LSR'
|
|
263 opcode = 0b0011
|
|
264
|
|
265
|
|
266 class Lsl1(ShiftBase):
|
|
267 mnemonic = 'LSL'
|
|
268 opcode = 0b0001
|
|
269
|
|
270
|
345
|
271 class OpRegRegImm(ArmInstruction):
|
|
272 """ add rd, rn, imm12 """
|
|
273 def __init__(self, rd, rn, imm):
|
|
274 super().__init__()
|
|
275 self.rd = rd
|
|
276 self.rn = rn
|
|
277 self.imm2 = encode_imm32(imm)
|
|
278 self.imm = imm
|
|
279
|
|
280 def encode(self):
|
|
281 self.token[0:12] = self.imm2
|
|
282 self.token.Rd = self.rd.num
|
|
283 self.token.Rn = self.rn.num
|
|
284 self.token.S = 0 # Set flags
|
|
285 self.token[21:28] = self.opcode
|
|
286 self.token.cond = 0xE # Always!
|
|
287 return self.token.encode()
|
|
288
|
|
289 def __repr__(self):
|
354
|
290 return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.imm)
|
345
|
291
|
|
292
|
|
293 class Add2(OpRegRegImm):
|
354
|
294 mnemonic = 'ADD'
|
345
|
295 opcode = 0b0010100
|
|
296
|
|
297
|
|
298 class Sub2(OpRegRegImm):
|
354
|
299 mnemonic = 'SUB'
|
345
|
300 opcode = 0b0010010
|
|
301
|
|
302
|
|
303
|
|
304 # Branches:
|
|
305
|
|
306 class BranchBaseRoot(ArmInstruction):
|
|
307 def __init__(self, target):
|
|
308 super().__init__()
|
|
309 self.target = target
|
|
310
|
|
311 def encode(self):
|
|
312 self.token.cond = self.cond
|
|
313 self.token[24:28] = self.opcode
|
|
314 return self.token.encode()
|
|
315
|
|
316 def relocations(self):
|
|
317 return [(self.target, 'b_imm24')]
|
|
318
|
350
|
319 def __repr__(self):
|
|
320 mnemonic = self.__class__.__name__
|
|
321 return '{} {}'.format(mnemonic, self.target)
|
|
322
|
345
|
323
|
346
|
324 EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL = range(15)
|
|
325
|
345
|
326 class BranchBase(BranchBaseRoot):
|
|
327 opcode = 0b1010
|
|
328
|
|
329 class BranchLinkBase(BranchBaseRoot):
|
|
330 opcode = 0b1011
|
|
331
|
|
332 class Bl(BranchLinkBase):
|
346
|
333 cond = AL
|
345
|
334
|
|
335 class B(BranchBase):
|
346
|
336 cond = AL
|
345
|
337
|
|
338 class Beq(BranchBase):
|
346
|
339 cond = EQ
|
345
|
340
|
|
341 class Bgt(BranchBase):
|
346
|
342 cond = GT
|
345
|
343
|
360
|
344 class Bge(BranchBase):
|
|
345 cond = GE
|
|
346
|
345
|
347 class Ble(BranchBase):
|
346
|
348 cond = LE
|
|
349
|
|
350 class Blt(BranchBase):
|
|
351 cond = LT
|
|
352
|
352
|
353 class Bne(BranchBase):
|
|
354 cond = NE
|
346
|
355
|
|
356 # Memory:
|
|
357
|
|
358 def reg_list_to_mask(reg_list):
|
|
359 mask = 0
|
|
360 for reg in reg_list:
|
|
361 mask |= (1 << reg.num)
|
|
362 return mask
|
|
363
|
|
364
|
|
365 class Push(ArmInstruction):
|
|
366 def __init__(self, register_set):
|
|
367 super().__init__()
|
|
368 self.reg_list = register_set
|
|
369
|
|
370 def encode(self):
|
|
371 self.token.cond = AL
|
|
372 self.token[16:28] = 0b100100101101
|
|
373 reg_list = 0
|
|
374 self.token[0:16] = reg_list_to_mask(self.reg_list)
|
|
375 return self.token.encode()
|
|
376
|
350
|
377 def __repr__(self):
|
|
378 return 'PUSH {}'.format(self.reg_list)
|
|
379
|
|
380
|
346
|
381 class Pop(ArmInstruction):
|
|
382 def __init__(self, register_set):
|
|
383 super().__init__()
|
|
384 self.reg_list = register_set
|
|
385
|
|
386 def encode(self):
|
|
387 self.token.cond = AL
|
|
388 self.token[16:28] = 0b100010111101
|
|
389 self.token[0:16] = reg_list_to_mask(self.reg_list)
|
|
390 return self.token.encode()
|
345
|
391
|
350
|
392 def __repr__(self):
|
|
393 return 'POP {}'.format(self.reg_list)
|
|
394
|
345
|
395
|
346
|
396 def Ldr(*args):
|
350
|
397 """ Convenience function that creates the correct instruction """
|
|
398 if len(args) == 3:
|
|
399 if isinstance(args[1], ArmRegister):
|
|
400 return Ldr1(*args)
|
|
401 elif len(args) == 2:
|
|
402 if isinstance(args[1], ArmRegister):
|
|
403 return Ldr1(args[0], args[1], 0)
|
|
404 elif isinstance(args[1], str):
|
|
405 return Ldr3(*args)
|
346
|
406 raise Exception()
|
|
407
|
350
|
408
|
346
|
409 def Str(*args):
|
|
410 if len(args) == 3 and isinstance(args[1], ArmRegister):
|
|
411 return Str1(*args)
|
|
412 elif len(args) == 2 and isinstance(args[1], ArmRegister):
|
|
413 return Str1(args[0], args[1], 0)
|
|
414 raise Exception()
|
|
415
|
|
416
|
|
417 class LdrStrBase(ArmInstruction):
|
|
418 def __init__(self, rt, rn, offset):
|
|
419 super().__init__()
|
|
420 self.rt = rt
|
|
421 self.rn = rn
|
|
422 self.offset = offset
|
|
423
|
|
424 def encode(self):
|
|
425 self.token.cond = AL
|
|
426 self.token.Rn = self.rn.num
|
|
427 self.token[25:28] = self.opcode
|
|
428 self.token[20] = self.bit20
|
|
429 self.token[12:16] = self.rt.num
|
|
430 self.token[24] = 1 # Index
|
|
431 if self.offset >= 0:
|
|
432 self.token[23] = 1 # U == 1 'add'
|
|
433 self.token[0:12] = self.offset
|
|
434 else:
|
|
435 self.token[23] = 0
|
|
436 self.token[0:12] = -self.offset
|
|
437 return self.token.encode()
|
|
438
|
350
|
439 def __repr__(self):
|
|
440 return '{} {}, [{}, {}]'.format(self.mnemonic, self.rt, self.rn,
|
|
441 hex(self.offset))
|
346
|
442
|
354
|
443
|
346
|
444 class Str1(LdrStrBase):
|
|
445 opcode = 0b010
|
|
446 bit20 = 0
|
350
|
447 mnemonic = 'STR'
|
346
|
448
|
|
449
|
|
450 class Ldr1(LdrStrBase):
|
|
451 opcode = 0b010
|
|
452 bit20 = 1
|
350
|
453 mnemonic = 'LDR'
|
346
|
454
|
|
455
|
354
|
456 class Adr(ArmInstruction):
|
|
457 def __init__(self, rd, label):
|
|
458 super().__init__()
|
|
459 self.rd = rd
|
|
460 self.label = label
|
|
461
|
|
462 def __repr__(self):
|
|
463 return 'ADR {}, {}'.format(self.rd, self.label)
|
|
464
|
|
465 def relocations(self):
|
|
466 return [(self.label, 'adr_imm12')]
|
|
467
|
|
468 def encode(self):
|
|
469 self.token.cond = AL
|
|
470 self.token[0:12] = 0 # Filled by linker
|
|
471 self.token[12:16] = self.rd.num
|
|
472 self.token[16:20] = 0b1111
|
|
473 self.token[25] = 1
|
|
474 return self.token.encode()
|
|
475
|
|
476
|
346
|
477 class Ldr3(ArmInstruction):
|
350
|
478 """ Load PC relative constant value
|
|
479 LDR rt, label
|
|
480 encoding A1
|
|
481 """
|
346
|
482 def __init__(self, rt, label):
|
350
|
483 super().__init__()
|
346
|
484 self.rt = rt
|
|
485 self.label = label
|
|
486
|
350
|
487 def __repr__(self):
|
|
488 return 'LDR {}, {}'.format(self.rt, self.label)
|
|
489
|
|
490 def relocations(self):
|
|
491 return [(self.label, 'ldr_imm12')]
|
|
492
|
|
493 def encode(self):
|
|
494 self.token.cond = AL
|
|
495 self.token[0:12] = 0 # Filled by linker
|
|
496 self.token[12:16] = self.rt.num
|
|
497 self.token[16:23] = 0b0011111
|
|
498 self.token[24:28] = 0b0101
|
|
499 return self.token.encode()
|
362
|
500
|
|
501
|
|
502 class McrBase(ArmInstruction):
|
|
503 """ Mov arm register to coprocessor register """
|
|
504 def __init__(self, coproc, opc1, rt, crn, crm, opc2):
|
|
505 super().__init__()
|
|
506 self.coproc = coproc
|
|
507 self.opc1 = opc1
|
|
508 self.rt = rt
|
|
509 self.crn = crn
|
|
510 self.crm = crm
|
|
511 self.opc2 = opc2
|
|
512
|
|
513 def encode(self):
|
|
514 self.token[0:4] = self.crm
|
|
515 self.token[4] = 1
|
|
516 self.token[5:8] = self.opc2
|
|
517 self.token[8:12] = self.coproc
|
|
518 self.token[12:16] = self.rt.num
|
|
519 self.token[16:20] = self.crn
|
|
520 self.token[20] = self.b20
|
|
521 self.token[21:24] = self.opc1
|
|
522 self.token[24:28] = 0b1110
|
|
523 self.token.cond = AL
|
|
524 return self.token.encode()
|
|
525
|
|
526
|
|
527 class Mcr(McrBase):
|
|
528 b20 = 0
|
|
529
|
|
530
|
|
531 class Mrc(McrBase):
|
|
532 b20 = 1
|