Mercurial > lcfOS
annotate python/ppci/target/thumb/instructions.py @ 342:86b02c98a717 devel
Moved target directory
author | Windel Bouwman |
---|---|
date | Sat, 01 Mar 2014 15:40:31 +0100 |
parents | python/target/arminstructions.py@4d204f6f7d4e |
children | 3bb7dcfe5529 |
rev | line source |
---|---|
342 | 1 from ..basetarget import Register, Instruction, Target, Label |
2 from ..basetarget import Imm32, Imm8, Imm7, Imm3 | |
3 from ..token import u16, u32 | |
4 from .armtoken import ThumbToken | |
5 from ..arm.registers import R0, ArmRegister, SP | |
292 | 6 |
7 | |
341 | 8 # Instructions: |
292 | 9 |
341 | 10 class ThumbInstruction(Instruction): |
11 pass | |
292 | 12 |
13 | |
341 | 14 class Dcd(ThumbInstruction): |
292 | 15 def __init__(self, expr): |
16 if isinstance(expr, Imm32): | |
17 self.expr = expr.imm | |
18 self.label = None | |
19 elif isinstance(expr, int): | |
20 self.expr = expr | |
21 self.label = None | |
22 else: | |
23 raise NotImplementedError() | |
24 | |
25 def encode(self): | |
26 return u32(self.expr) | |
27 | |
335 | 28 def relocations(self): |
29 return [] | |
30 | |
292 | 31 def __repr__(self): |
32 return 'DCD 0x{0:X}'.format(self.expr) | |
33 | |
34 | |
341 | 35 class nop_ins(ThumbInstruction): |
292 | 36 def encode(self): |
37 return bytes() | |
38 | |
39 def __repr__(self): | |
40 return 'NOP' | |
41 | |
42 | |
43 # Memory related | |
44 | |
341 | 45 class LS_imm5_base(ThumbInstruction): |
292 | 46 """ ??? Rt, [Rn, imm5] """ |
341 | 47 def __init__(self, rt, rn, imm5): |
48 assert imm5 % 4 == 0 | |
49 self.imm5 = imm5 >> 2 | |
50 self.rn = rn | |
292 | 51 self.rt = rt |
341 | 52 assert self.rn.num < 8 |
292 | 53 assert self.rt.num < 8 |
341 | 54 self.token = ThumbToken() |
292 | 55 |
56 def encode(self): | |
341 | 57 Rn = self.rn.num |
292 | 58 Rt = self.rt.num |
59 imm5 = self.imm5 | |
341 | 60 self.token[0:3] = Rt |
61 self.token[3:6] = Rn | |
62 self.token[6:11] = imm5 | |
63 self.token[11:16] = self.opcode | |
64 return self.token.encode() | |
292 | 65 |
341 | 66 def __repr__(self): |
67 mnemonic = "???" | |
68 return '{} {}, [{}, {}]'.format(mnemonic, self.rt, self.rn, self.imm5) | |
292 | 69 |
70 | |
71 class Str2(LS_imm5_base): | |
72 opcode = 0xC | |
73 | |
74 @classmethod | |
75 def fromim(cls, im): | |
341 | 76 return cls(im.src[1], im.src[0], im.others[0]) |
292 | 77 |
78 | |
79 class Ldr2(LS_imm5_base): | |
80 opcode = 0xD | |
81 | |
82 @classmethod | |
83 def fromim(cls, im): | |
341 | 84 return cls(im.dst[0], im.src[0], im.others[0]) |
292 | 85 |
341 | 86 class ls_sp_base_imm8(ThumbInstruction): |
87 def __init__(self, rt, offset): | |
292 | 88 self.rt = rt |
341 | 89 self.offset = offset |
292 | 90 |
91 def encode(self): | |
92 rt = self.rt.num | |
93 assert rt < 8 | |
94 imm8 = self.offset >> 2 | |
95 assert imm8 < 256 | |
96 h = (self.opcode << 8) | (rt << 8) | imm8 | |
97 return u16(h) | |
98 | |
99 def __repr__(self): | |
341 | 100 mnemonic = self.__class__.__name__ |
101 return '{} {}, [sp,#{}]'.format(mnemonic, self.rt, self.offset) | |
292 | 102 |
103 def align(x, m): | |
104 while ((x % m) != 0): | |
105 x = x + 1 | |
106 return x | |
107 | |
341 | 108 def Ldr(*args): |
109 if len(args) == 2 and isinstance(args[0], ArmRegister) \ | |
110 and isinstance(args[1], str): | |
111 return Ldr3(*args) | |
112 else: | |
113 raise Exception() | |
292 | 114 |
341 | 115 |
116 class Ldr3(ThumbInstruction): | |
292 | 117 """ ldr Rt, LABEL, load value from pc relative position """ |
118 mnemonic = 'ldr' | |
119 def __init__(self, rt, label): | |
120 self.rt = rt | |
121 self.label = label | |
122 | |
123 @classmethod | |
124 def fromim(cls, im): | |
125 return cls(im.dst[0], im.others[0]) | |
126 | |
335 | 127 def relocations(self): |
341 | 128 return [(self.label, 'lit_add_8')] |
292 | 129 |
130 def encode(self): | |
131 rt = self.rt.num | |
132 assert rt < 8 | |
341 | 133 imm8 = 0 |
292 | 134 h = (0x9 << 11) | (rt << 8) | imm8 |
135 return u16(h) | |
136 | |
137 def __repr__(self): | |
341 | 138 return 'LDR {}, {}'.format(self.rt, self.label) |
292 | 139 |
140 | |
141 class Ldr1(ls_sp_base_imm8): | |
142 """ ldr Rt, [SP, imm8] """ | |
143 opcode = 0x98 | |
144 | |
145 | |
146 class Str1(ls_sp_base_imm8): | |
147 """ str Rt, [SP, imm8] """ | |
148 opcode = 0x90 | |
149 | |
150 | |
341 | 151 class Mov3(ThumbInstruction): |
292 | 152 """ mov Rd, imm8, move immediate value into register """ |
153 opcode = 4 # 00100 Rd(3) imm8 | |
154 def __init__(self, rd, imm): | |
341 | 155 assert imm < 256 |
156 self.imm = imm | |
292 | 157 self.rd = rd |
341 | 158 self.token = ThumbToken() |
292 | 159 |
160 @classmethod | |
161 def fromim(cls, im): | |
162 return cls(im.dst[0], im.others[0]) | |
163 | |
164 def encode(self): | |
165 rd = self.rd.num | |
341 | 166 self.token[8:11] = rd |
167 self.token[0:8] = self.imm | |
168 self.token[11:16] = self.opcode | |
169 return self.token.encode() | |
292 | 170 |
171 def __repr__(self): | |
172 return 'MOV {}, {}'.format(self.rd, self.imm) | |
173 | |
174 | |
175 | |
176 # Arithmatics: | |
177 | |
178 | |
179 | |
341 | 180 class regregimm3_base(ThumbInstruction): |
292 | 181 def __init__(self, rd, rn, imm3): |
182 self.rd = rd | |
183 self.rn = rn | |
341 | 184 assert imm3 < 8 |
292 | 185 self.imm3 = imm3 |
341 | 186 self.token = ThumbToken() |
292 | 187 |
188 @classmethod | |
189 def fromim(cls, im): | |
190 return cls(im.dst[0], im.src[0], im.others[0]) | |
191 | |
192 def encode(self): | |
193 rd = self.rd.num | |
341 | 194 self.token[0:3] = rd |
195 self.token[3:6] = self.rn.num | |
196 self.token[6:9] = self.imm3 | |
197 self.token[9:16] = self.opcode | |
198 return self.token.encode() | |
292 | 199 |
200 def __repr__(self): | |
341 | 201 mnemonic = self.__class__.__name__ |
202 return '{} {}, {}, {}'.format(mnemonic, self.rd, self.rn, self.imm3) | |
292 | 203 |
340 | 204 |
205 | |
300 | 206 class Add2(regregimm3_base): |
292 | 207 """ add Rd, Rn, imm3 """ |
208 opcode = 0b0001110 | |
209 | |
210 | |
300 | 211 class Sub2(regregimm3_base): |
292 | 212 """ sub Rd, Rn, imm3 """ |
213 opcode = 0b0001111 | |
214 | |
215 | |
341 | 216 def Sub(*args): |
217 if len(args) == 3 and args[0] is SP and args[1] is SP and \ | |
218 isinstance(args[2], int) and args[2] < 256: | |
219 return SubSp(args[2]) | |
220 elif len(args) == 3 and isinstance(args[0], ArmRegister) and \ | |
221 isinstance(args[1], ArmRegister) and isinstance(args[2], int) and \ | |
222 args[2] < 8: | |
223 return Sub2(args[0], args[1], args[2]) | |
224 else: | |
225 raise Exception() | |
226 | |
342 | 227 |
228 def Add(*args): | |
229 if len(args) == 3 and args[0] is SP and args[1] is SP and \ | |
230 isinstance(args[2], int) and args[2] < 256: | |
231 return AddSp(args[2]) | |
232 elif len(args) == 3 and isinstance(args[0], ArmRegister) and \ | |
233 isinstance(args[1], ArmRegister) and isinstance(args[2], int) and \ | |
234 args[2] < 8: | |
235 return Add2(args[0], args[1], args[2]) | |
236 else: | |
237 raise Exception() | |
238 | |
239 | |
341 | 240 class regregreg_base(ThumbInstruction): |
292 | 241 """ ??? Rd, Rn, Rm """ |
242 def __init__(self, rd, rn, rm): | |
243 self.rd = rd | |
244 self.rn = rn | |
245 self.rm = rm | |
246 | |
247 @classmethod | |
248 def fromim(cls, im): | |
249 return cls(im.dst[0], im.src[0], im.src[1]) | |
250 | |
251 def encode(self): | |
340 | 252 at = ThumbToken() |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
253 at.rd = self.rd.num |
292 | 254 rn = self.rn.num |
255 rm = self.rm.num | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
256 at[3:6] = rn |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
257 at[6:9] = rm |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
258 at[9:16] = self.opcode |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
259 return at.encode() |
292 | 260 |
261 def __repr__(self): | |
262 return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm) | |
263 | |
264 | |
341 | 265 class Add3(regregreg_base): |
292 | 266 mnemonic = 'ADD' |
267 opcode = 0b0001100 | |
268 | |
269 | |
341 | 270 class Sub3(regregreg_base): |
292 | 271 mnemonic = 'SUB' |
272 opcode = 0b0001101 | |
273 | |
274 | |
341 | 275 class Mov2(ThumbInstruction): |
292 | 276 """ mov rd, rm """ |
277 mnemonic = 'MOV' | |
278 def __init__(self, rd, rm): | |
279 self.rd = rd | |
280 self.rm = rm | |
281 | |
282 @classmethod | |
283 def fromim(cls, im): | |
284 return cls(im.dst[0], im.src[0]) | |
285 | |
286 def encode(self): | |
340 | 287 at = ThumbToken() |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
288 at.rd = self.rd.num & 0x7 |
292 | 289 D = (self.rd.num >> 3) & 0x1 |
290 Rm = self.rm.num | |
291 opcode = 0b01000110 | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
292 at[8:16] = opcode |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
293 at[3:7] = Rm |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
294 at[7] = D |
341 | 295 return at.encode() |
292 | 296 |
297 def __repr__(self): | |
298 return '{} {}, {}'.format(self.mnemonic, self.rd, self.rm) | |
335 | 299 |
292 | 300 |
341 | 301 class Mul(ThumbInstruction): |
292 | 302 """ mul Rn, Rdm """ |
303 mnemonic = 'MUL' | |
304 def __init__(self, rn, rdm): | |
305 self.rn = rn | |
306 self.rdm = rdm | |
307 | |
308 @classmethod | |
309 def fromim(cls, im): | |
310 assert im.src[1] is im.dst[0] | |
311 return cls(im.src[0], im.dst[0]) | |
312 | |
313 def encode(self): | |
340 | 314 at = ThumbToken() |
292 | 315 rn = self.rn.num |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
316 at.rd = self.rdm.num |
292 | 317 opcode = 0b0100001101 |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
318 #h = (opcode << 6) | (rn << 3) | rdm |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
319 at[6:16] = opcode |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
320 at[3:6] = rn |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
321 return at.encode() |
292 | 322 |
323 def __repr__(self): | |
324 return '{} {}, {}'.format(self.mnemonic, self.rn, self.rdm) | |
325 | |
326 | |
341 | 327 class regreg_base(ThumbInstruction): |
292 | 328 """ ??? Rdn, Rm """ |
329 def __init__(self, rdn, rm): | |
330 self.rdn = rdn | |
331 self.rm = rm | |
332 | |
333 @classmethod | |
334 def fromim(cls, im): | |
335 return cls(im.src[0], im.src[1]) | |
336 | |
337 def encode(self): | |
340 | 338 at = ThumbToken() |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
339 at.rd = self.rdn.num |
292 | 340 rm = self.rm.num |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
341 at[3:6] = rm |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
342 at[6:16] = self.opcode |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
343 return at.encode() |
292 | 344 |
345 def __repr__(self): | |
341 | 346 mnemonic = self.__class__.__name__ |
347 return '{} {}, {}'.format(mnemonic, self.rdn, self.rm) | |
292 | 348 |
349 | |
350 class movregreg_ins(regreg_base): | |
351 """ mov Rd, Rm (reg8 operands) """ | |
352 opcode = 0 | |
353 | |
354 | |
355 class And(regreg_base): | |
356 opcode = 0b0100000000 | |
357 | |
358 | |
359 class Orr(regreg_base): | |
360 opcode = 0b0100001100 | |
361 | |
362 | |
363 class Cmp(regreg_base): | |
364 opcode = 0b0100001010 | |
365 | |
366 | |
367 class Lsl(regreg_base): | |
368 opcode = 0b0100000010 | |
369 | |
370 | |
342 | 371 class Cmp2(ThumbInstruction): |
292 | 372 """ cmp Rn, imm8 """ |
373 opcode = 5 # 00101 | |
374 def __init__(self, rn, imm): | |
375 self.rn = rn | |
376 self.imm = imm | |
377 | |
378 def encode(self): | |
341 | 379 at = ThumbToken() |
342 | 380 at[0:8] = self.imm |
341 | 381 at[8:11] = self.rn.num |
382 at[11:16] = self.opcode | |
383 return at.encode() | |
292 | 384 |
385 | |
386 # Jumping: | |
387 | |
341 | 388 class jumpBase_ins(ThumbInstruction): |
292 | 389 def __init__(self, target_label): |
342 | 390 assert type(target_label) is str |
292 | 391 self.target = target_label |
392 self.offset = 0 | |
393 | |
394 def __repr__(self): | |
341 | 395 mnemonic = self.__class__.__name__ |
396 return '{} {}'.format(mnemonic, self.target) | |
292 | 397 |
398 | |
399 class B(jumpBase_ins): | |
400 def encode(self): | |
341 | 401 h = (0b11100 << 11) | 0 |
402 # | 1 # 1 to enable thumb mode | |
292 | 403 return u16(h) |
404 | |
335 | 405 def relocations(self): |
341 | 406 return [(self.target, 'wrap_new11')] |
292 | 407 |
408 class Bl(jumpBase_ins): | |
409 def encode(self): | |
341 | 410 imm11 = 0 |
411 imm10 = 0 | |
292 | 412 j1 = 1 # TODO: what do these mean? |
413 j2 = 1 | |
341 | 414 s = 0 |
292 | 415 h1 = (0b11110 << 11) | (s << 10) | imm10 |
416 h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) | imm11 | |
417 return u16(h1) + u16(h2) | |
418 | |
335 | 419 def relocations(self): |
341 | 420 return [(self.target, 'bl_imm11_imm10')] |
292 | 421 |
335 | 422 |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
423 class cond_base_ins(jumpBase_ins): |
292 | 424 def encode(self): |
341 | 425 imm8 = 0 |
292 | 426 h = (0b1101 << 12) | (self.cond << 8) | imm8 |
427 return u16(h) | |
428 | |
335 | 429 def relocations(self): |
341 | 430 return [(self.target, 'rel8')] |
335 | 431 |
432 | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
433 class cond_base_ins_long(jumpBase_ins): |
335 | 434 """ Encoding T3 """ |
435 def encode(self): | |
436 j1 = 1 # TODO: what do these mean? | |
437 j2 = 1 | |
438 h1 = (0b11110 << 11) | (self.cond << 6) | |
439 h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) | |
440 return u16(h1) + u16(h2) | |
441 | |
442 def relocations(self): | |
341 | 443 return [(self.target, 'b_imm11_imm6')] |
335 | 444 |
292 | 445 |
446 class Beq(cond_base_ins): | |
447 cond = 0 | |
448 | |
449 | |
450 class Bne(cond_base_ins): | |
451 cond = 1 | |
452 | |
453 | |
454 class Blt(cond_base_ins): | |
455 cond = 0b1011 | |
456 | |
457 | |
458 class Bgt(cond_base_ins): | |
459 cond = 0b1100 | |
460 | |
461 | |
341 | 462 class Push(ThumbInstruction): |
292 | 463 def __init__(self, regs): |
341 | 464 assert type(regs) is set |
292 | 465 self.regs = regs |
466 | |
467 def __repr__(self): | |
341 | 468 return 'Push {{{}}}'.format(self.regs) |
292 | 469 |
470 def encode(self): | |
341 | 471 at = ThumbToken() |
472 for n in register_numbers(self.regs): | |
292 | 473 if n < 8: |
341 | 474 at[n] = 1 |
292 | 475 elif n == 14: |
341 | 476 at[8] = 1 |
292 | 477 else: |
341 | 478 raise NotImplementedError('not implemented for {}'.format(n)) |
479 at[9:16] = 0x5a | |
480 return at.encode() | |
481 | |
292 | 482 |
483 | |
341 | 484 def register_numbers(regs): |
485 for r in regs: | |
486 yield r.num | |
340 | 487 |
341 | 488 class Pop(ThumbInstruction): |
292 | 489 def __init__(self, regs): |
341 | 490 assert type(regs) is set |
292 | 491 self.regs = regs |
341 | 492 self.token = ThumbToken() |
292 | 493 |
494 def __repr__(self): | |
341 | 495 return 'Pop {{{}}}'.format(self.regs) |
292 | 496 |
497 def encode(self): | |
341 | 498 for n in register_numbers(self.regs): |
292 | 499 if n < 8: |
341 | 500 self.token[n] = 1 |
292 | 501 elif n == 15: |
341 | 502 self.token[8] = 1 |
292 | 503 else: |
504 raise NotImplementedError('not implemented for this register') | |
341 | 505 self.token[9:16] = 0x5E |
506 return self.token.encode() | |
292 | 507 |
508 | |
509 | |
341 | 510 class Yield(ThumbInstruction): |
292 | 511 def encode(self): |
512 return u16(0xbf10) | |
513 | |
514 # misc: | |
515 | |
516 # add/sub SP: | |
341 | 517 class addspsp_base(ThumbInstruction): |
518 def __init__(self, imm7): | |
519 self.imm7 = imm7 | |
292 | 520 assert self.imm7 % 4 == 0 |
521 self.imm7 >>= 2 | |
522 | |
523 def encode(self): | |
341 | 524 return u16((self.opcode << 7) | self.imm7) |
292 | 525 |
526 def __repr__(self): | |
341 | 527 mnemonic = self.__class__.__name__ |
528 return '{} sp, sp, {}'.format(mnemonic, self.imm7 << 2) | |
292 | 529 |
305 | 530 |
292 | 531 class AddSp(addspsp_base): |
532 opcode = 0b101100000 | |
533 | |
534 | |
535 class SubSp(addspsp_base): | |
536 opcode = 0b101100001 |