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