Mercurial > lcfOS
annotate python/target/arminstructions.py @ 336:d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
author | Windel Bouwman |
---|---|
date | Wed, 19 Feb 2014 22:32:15 +0100 |
parents | 582a1aaa3983 |
children | c7cc54c0dfdf |
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 | |
6 | |
7 def u16(h): | |
8 return struct.pack('<H', h) | |
9 | |
10 def u32(x): | |
11 return struct.pack('<I', x) | |
12 | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
13 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
14 def val2bit(v, bits): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
15 b = [] |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
16 for i in range(bits): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
17 b.append(bool((1<<i) & v)) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
18 #b.reverse() |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
19 return b |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
20 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
21 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
22 def bit_range(b, e): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
23 getter = lambda s: s[b:e] |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
24 def setter(s, v): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
25 s[b:e] = v |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
26 return property(getter, setter) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
27 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
28 class ArmToken: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
29 def __init__(self): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
30 self.bit_value = 0 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
31 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
32 def set_bit(self, i, value): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
33 value = bool(value) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
34 assert i in range(0, 16) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
35 mask = 1 << i |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
36 if value: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
37 self.bit_value |= mask |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
38 else: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
39 self.bit_value &= (~mask) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
40 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
41 def __getitem__(self, key): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
42 return False |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
43 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
44 def __setitem__(self, key, value): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
45 if type(key) is int: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
46 self.set_bit(key, value) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
47 elif type(key) is slice: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
48 assert key.step is None |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
49 bits = key.stop - key.start |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
50 value_bits = val2bit(value, bits) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
51 for i in range(key.start, key.stop): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
52 self.set_bit(i, value_bits[i - key.start]) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
53 else: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
54 raise KeyError() |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
55 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
56 rd = bit_range(0, 3) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
57 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
58 def encode(self): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
59 return u16(self.bit_value) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
60 |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
61 |
292 | 62 # Operands: |
63 | |
64 class ArmRegister(Register): | |
65 def __init__(self, num, name): | |
66 super().__init__(name) | |
67 self.num = num | |
68 | |
69 def __repr__(self): | |
70 return self.name | |
71 | |
72 @classmethod | |
73 def Create(cls, vop): | |
74 if type(vop) is ASymbol: | |
75 name = vop.name | |
76 regs = {} | |
77 for r in registers: | |
78 regs[r.name] = r | |
79 if name in regs: | |
80 r = regs[name] | |
81 if isinstance(r, cls): | |
82 return r | |
83 | |
84 | |
85 class Reg8Op(ArmRegister): | |
86 pass | |
87 | |
88 | |
89 class Reg16Op(ArmRegister): | |
90 pass | |
91 | |
92 | |
93 R0 = Reg8Op(0, 'r0') | |
94 R1 = Reg8Op(1, 'r1') | |
95 R2 = Reg8Op(2, 'r2') | |
96 R3 = Reg8Op(3, 'r3') | |
97 R4 = Reg8Op(4, 'r4') | |
98 R5 = Reg8Op(5, 'r5') | |
99 R6 = Reg8Op(6, 'r6') | |
100 R7 = Reg8Op(7, 'r7') | |
101 # Other registers: | |
102 # TODO | |
103 SP = ArmRegister(13, 'sp') | |
104 LR = ArmRegister(14, 'lr') | |
105 PC = ArmRegister(15, 'pc') | |
106 | |
107 registers = [R0, R1, R2, R3, R4, R5, R6, R7, SP, LR, PC] | |
108 | |
109 | |
110 class RegSpOp: | |
111 @classmethod | |
112 def Create(cls, vop): | |
113 if type(vop) is ASymbol: | |
114 if vop.name.lower() == 'sp': | |
115 return cls() | |
116 | |
117 | |
118 def getRegNum(n): | |
119 for r in registers: | |
120 if r.num == n: | |
121 return r | |
122 | |
123 | |
124 def getRegisterRange(n1, n2): | |
125 regs = [] | |
126 if n1.num < n2.num: | |
127 for n in range(n1.num, n2.num + 1): | |
128 r = getRegNum(n) | |
129 assert r | |
130 regs.append(r) | |
131 return regs | |
132 | |
133 | |
134 def isRegOffset(regname, x, y): | |
135 if type(x) is ASymbol and type(y) is ANumber and x.name.upper() == regname: | |
136 return y.number | |
137 elif type(y) is ASymbol and type(x) is ANumber and y.name.upper() == regname: | |
138 return x.number | |
139 | |
140 | |
141 class MemRegXRel: | |
142 def __init__(self, offset): | |
143 assert offset % 4 == 0 | |
144 self.offset = offset | |
145 | |
146 def __repr__(self): | |
147 return '[{}, #{}]'.format(self.regname, self.offset) | |
148 | |
149 @classmethod | |
150 def Create(cls, vop): | |
151 if type(vop) is AUnop and vop.operation == '[]' and type(vop.arg) is ABinop and vop.arg.op == '+': | |
152 vop = vop.arg # descent | |
153 offset = isRegOffset(cls.regname, vop.arg1, vop.arg2) | |
154 if type(offset) is int: | |
155 if offset % 4 == 0: | |
156 offset = vop.arg2.number | |
157 return cls(offset) | |
158 elif type(vop) is ASymbol and vop.name.upper() == self.regname: | |
159 return cls(0) | |
160 | |
161 | |
162 class MemSpRel(MemRegXRel): | |
163 regname = 'SP' | |
164 | |
165 | |
166 class MemR8Rel: | |
167 def __init__(self, basereg, offset): | |
168 assert type(basereg) is Reg8Op | |
169 assert type(offset) is int | |
170 self.basereg = basereg | |
171 self.offset = offset | |
172 | |
173 def __repr__(self): | |
174 return '[{}, #{}]'.format(self.basereg, self.offset) | |
175 | |
176 @classmethod | |
177 def Create(cls, vop): | |
178 if type(vop) is AUnop and vop.operation == '[]': | |
179 vop = vop.arg # descent | |
180 if type(vop) is ABinop: | |
181 if vop.op == '+' and type(vop.arg1) is ASymbol and type(vop.arg2) is ANumber: | |
182 offset = vop.arg2.number | |
183 if offset > 120: | |
184 return | |
185 basereg = Reg8Op.Create(vop.arg1) | |
186 if not basereg: | |
187 return | |
188 else: | |
189 return | |
190 elif type(vop) is ASymbol: | |
191 offset = 0 | |
192 basereg = Reg8Op.Create(vop) | |
193 if not basereg: | |
194 return | |
195 else: | |
196 return | |
197 return cls(getRegNum(basereg.num), offset) | |
198 | |
199 | |
200 class RegisterSet: | |
201 def __init__(self, regs): | |
202 assert type(regs) is set | |
203 self.regs = regs | |
204 | |
205 def __repr__(self): | |
206 return ','.join([str(r) for r in self.regs]) | |
207 | |
208 @classmethod | |
209 def Create(cls, vop): | |
210 assert type(vop) is AUnop and vop.operation == '{}' | |
211 assert type(vop.arg) is list | |
212 regs = set() | |
213 for arg in vop.arg: | |
214 if type(arg) is ASymbol: | |
215 reg = ArmRegister.Create(arg) | |
216 if not reg: | |
217 return | |
218 regs.add(reg) | |
219 elif type(arg) is ABinop and arg.op == '-': | |
220 reg1 = ArmRegister.Create(arg.arg1) | |
221 reg2 = ArmRegister.Create(arg.arg2) | |
222 if not reg1: | |
223 return | |
224 if not reg2: | |
225 return | |
226 for r in getRegisterRange(reg1, reg2): | |
227 regs.add(r) | |
228 else: | |
229 raise Exception('Cannot be') | |
230 return cls(regs) | |
231 | |
232 def registerNumbers(self): | |
233 return [r.num for r in self.regs] | |
234 | |
235 | |
236 | |
237 # Instructions: | |
238 | |
239 class ArmInstruction(Instruction): | |
240 pass | |
241 | |
242 | |
243 allins = [] | |
244 | |
245 | |
246 def instruction(i): | |
247 allins.append(i) | |
248 return i | |
249 | |
250 | |
251 @instruction | |
252 class Dcd(ArmInstruction): | |
253 mnemonic = 'dcd' | |
254 operands = (Imm32,) | |
255 def __init__(self, expr): | |
256 if isinstance(expr, Imm32): | |
257 self.expr = expr.imm | |
258 self.label = None | |
259 elif isinstance(expr, LabelRef): | |
260 self.expr = 0 | |
261 self.label = expr | |
262 elif isinstance(expr, int): | |
263 self.expr = expr | |
264 self.label = None | |
265 else: | |
266 raise NotImplementedError() | |
267 | |
268 def encode(self): | |
269 return u32(self.expr) | |
270 | |
335 | 271 def relocations(self): |
272 assert not isinstance(self.expr, LabelRef) | |
273 return [] | |
274 | |
292 | 275 def __repr__(self): |
276 return 'DCD 0x{0:X}'.format(self.expr) | |
277 | |
278 | |
279 @instruction | |
280 class nop_ins(ArmInstruction): | |
281 mnemonic = 'nop' | |
282 operands = tuple() | |
283 | |
284 def encode(self): | |
285 return bytes() | |
286 | |
287 def __repr__(self): | |
288 return 'NOP' | |
289 | |
290 | |
291 # Memory related | |
292 | |
293 class LS_imm5_base(ArmInstruction): | |
294 """ ??? Rt, [Rn, imm5] """ | |
295 operands = (Reg8Op, MemR8Rel) | |
296 def __init__(self, rt, memop): | |
297 assert memop.offset % 4 == 0 | |
298 self.imm5 = memop.offset >> 2 | |
299 self.rn = memop.basereg.num | |
300 self.rt = rt | |
301 self.memloc = memop | |
302 assert self.rn < 8 | |
303 assert self.rt.num < 8 | |
304 | |
305 def encode(self): | |
306 Rn = self.rn | |
307 Rt = self.rt.num | |
308 imm5 = self.imm5 | |
309 | |
310 h = (self.opcode << 11) | (imm5 << 6) | (Rn << 3) | Rt | |
311 return u16(h) | |
312 | |
313 | |
314 def __repr__(self): | |
315 return '{} {}, {}'.format(self.mnemonic, self.rt, self.memloc) | |
316 | |
317 | |
318 @instruction | |
319 class Str2(LS_imm5_base): | |
320 mnemonic = 'STR' | |
321 opcode = 0xC | |
322 | |
323 @classmethod | |
324 def fromim(cls, im): | |
325 mem = MemR8Rel(im.src[0], im.others[0]) | |
326 return cls(im.src[1], mem) | |
327 | |
328 | |
329 @instruction | |
330 class Ldr2(LS_imm5_base): | |
331 mnemonic = 'LDR' | |
332 opcode = 0xD | |
333 | |
334 @classmethod | |
335 def fromim(cls, im): | |
336 mem = MemR8Rel(im.src[0], im.others[0]) | |
337 return cls(im.dst[0], mem) | |
338 | |
339 class ls_sp_base_imm8(ArmInstruction): | |
340 operands = (Reg8Op, MemSpRel) | |
341 def __init__(self, rt, memop): | |
342 self.rt = rt | |
343 self.offset = memop.offset | |
344 | |
345 def encode(self): | |
346 rt = self.rt.num | |
347 assert rt < 8 | |
348 imm8 = self.offset >> 2 | |
349 assert imm8 < 256 | |
350 h = (self.opcode << 8) | (rt << 8) | imm8 | |
351 return u16(h) | |
352 | |
353 def __repr__(self): | |
354 return '{} {}, [sp,#{}]'.format(self.mnemonic, self.rt, self.offset) | |
355 | |
356 def align(x, m): | |
357 while ((x % m) != 0): | |
358 x = x + 1 | |
359 return x | |
360 | |
361 | |
362 @instruction | |
363 class Ldr3(ArmInstruction): | |
364 """ ldr Rt, LABEL, load value from pc relative position """ | |
365 mnemonic = 'ldr' | |
366 operands = (Reg8Op, LabelRef) | |
367 def __init__(self, rt, label): | |
368 assert isinstance(label, LabelRef) | |
369 self.rt = rt | |
370 self.label = label | |
371 self.offset = 0 | |
372 | |
373 @classmethod | |
374 def fromim(cls, im): | |
375 return cls(im.dst[0], im.others[0]) | |
376 | |
335 | 377 def relocations(self): |
378 return [(self.label.name, 'lit_add_8')] | |
292 | 379 |
380 def encode(self): | |
381 rt = self.rt.num | |
382 assert rt < 8 | |
383 assert self.offset % 4 == 0 | |
384 imm8 = self.offset >> 2 | |
385 assert imm8 < 256 | |
386 assert imm8 >= 0 | |
387 h = (0x9 << 11) | (rt << 8) | imm8 | |
388 return u16(h) | |
389 | |
390 def __repr__(self): | |
391 return 'LDR {}, {}'.format(self.rt, self.label.name) | |
392 | |
393 | |
394 @instruction | |
395 class Ldr1(ls_sp_base_imm8): | |
396 """ ldr Rt, [SP, imm8] """ | |
397 mnemonic = 'LDR' | |
398 opcode = 0x98 | |
399 | |
400 | |
401 @instruction | |
402 class Str1(ls_sp_base_imm8): | |
403 """ str Rt, [SP, imm8] """ | |
404 mnemonic = 'STR' | |
405 opcode = 0x90 | |
406 | |
407 | |
408 @instruction | |
409 class Mov3(ArmInstruction): | |
410 """ mov Rd, imm8, move immediate value into register """ | |
411 mnemonic = 'mov' | |
412 opcode = 4 # 00100 Rd(3) imm8 | |
413 operands = (Reg8Op, Imm8) | |
414 def __init__(self, rd, imm): | |
415 if type(imm) is int: | |
416 imm = Imm8(imm) | |
417 assert type(imm) is Imm8 | |
418 self.imm = imm.imm | |
419 assert type(rd) is Reg8Op, str(type(rd)) | |
420 self.rd = rd | |
421 | |
422 @classmethod | |
423 def fromim(cls, im): | |
424 return cls(im.dst[0], im.others[0]) | |
425 | |
426 def encode(self): | |
427 rd = self.rd.num | |
428 opcode = self.opcode | |
429 imm8 = self.imm | |
430 h = (opcode << 11) | (rd << 8) | imm8 | |
431 return u16(h) | |
432 | |
433 def __repr__(self): | |
434 return 'MOV {}, {}'.format(self.rd, self.imm) | |
435 | |
436 | |
437 | |
438 # Arithmatics: | |
439 | |
440 | |
441 | |
442 class regregimm3_base(ArmInstruction): | |
443 operands = (Reg8Op, Reg8Op, Imm3) | |
444 def __init__(self, rd, rn, imm3): | |
445 self.rd = rd | |
446 self.rn = rn | |
447 assert type(imm3) is Imm3 | |
448 self.imm3 = imm3 | |
449 | |
450 @classmethod | |
451 def fromim(cls, im): | |
452 return cls(im.dst[0], im.src[0], im.others[0]) | |
453 | |
454 def encode(self): | |
455 rd = self.rd.num | |
456 rn = self.rn.num | |
457 imm3 = self.imm3.imm | |
458 opcode = self.opcode | |
459 h = (self.opcode << 9) | (imm3 << 6) | (rn << 3) | rd | |
460 return u16(h) | |
461 | |
462 def __repr__(self): | |
463 return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.imm3.imm) | |
464 | |
465 @instruction | |
300 | 466 class Add2(regregimm3_base): |
292 | 467 """ add Rd, Rn, imm3 """ |
468 mnemonic = 'add' | |
469 opcode = 0b0001110 | |
470 | |
471 | |
472 @instruction | |
300 | 473 class Sub2(regregimm3_base): |
292 | 474 """ sub Rd, Rn, imm3 """ |
475 mnemonic = 'sub' | |
476 opcode = 0b0001111 | |
477 | |
478 | |
479 class regregreg_base(ArmInstruction): | |
480 """ ??? Rd, Rn, Rm """ | |
481 operands = (Reg8Op, Reg8Op, Reg8Op) | |
482 def __init__(self, rd, rn, rm): | |
483 self.rd = rd | |
484 self.rn = rn | |
485 self.rm = rm | |
486 | |
487 @classmethod | |
488 def fromim(cls, im): | |
489 return cls(im.dst[0], im.src[0], im.src[1]) | |
490 | |
491 def encode(self): | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
492 at = ArmToken() |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
493 at.rd = self.rd.num |
292 | 494 rn = self.rn.num |
495 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
|
496 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
|
497 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
|
498 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
|
499 #h = (self.opcode << 9) | (rm << 6) | (rn << 3) | rd |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
500 #return u16(h) |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
501 return at.encode() |
292 | 502 |
503 def __repr__(self): | |
504 return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm) | |
505 | |
506 | |
507 @instruction | |
508 class Add(regregreg_base): | |
509 mnemonic = 'ADD' | |
510 opcode = 0b0001100 | |
511 | |
512 | |
513 @instruction | |
514 class Sub(regregreg_base): | |
515 mnemonic = 'SUB' | |
516 opcode = 0b0001101 | |
517 | |
518 | |
519 @instruction | |
520 class Mov2(ArmInstruction): | |
521 """ mov rd, rm """ | |
522 operands = (ArmRegister, ArmRegister) | |
523 mnemonic = 'MOV' | |
524 def __init__(self, rd, rm): | |
525 self.rd = rd | |
526 self.rm = rm | |
527 | |
528 @classmethod | |
529 def fromim(cls, im): | |
530 return cls(im.dst[0], im.src[0]) | |
531 | |
532 def encode(self): | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
533 at = ArmToken() |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
534 at.rd = self.rd.num & 0x7 |
292 | 535 D = (self.rd.num >> 3) & 0x1 |
536 Rm = self.rm.num | |
537 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
|
538 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
|
539 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
|
540 at[7] = D |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
541 return at.encode() # u16((opcode << 8) | (D << 7) |(Rm << 3) | Rd) |
292 | 542 |
543 def __repr__(self): | |
544 return '{} {}, {}'.format(self.mnemonic, self.rd, self.rm) | |
335 | 545 |
292 | 546 |
547 @instruction | |
300 | 548 class Mul(ArmInstruction): |
292 | 549 """ mul Rn, Rdm """ |
550 operands = (Reg8Op, Reg8Op) | |
551 mnemonic = 'MUL' | |
552 def __init__(self, rn, rdm): | |
553 self.rn = rn | |
554 self.rdm = rdm | |
555 | |
556 @classmethod | |
557 def fromim(cls, im): | |
558 assert im.src[1] is im.dst[0] | |
559 return cls(im.src[0], im.dst[0]) | |
560 | |
561 def encode(self): | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
562 at = ArmToken() |
292 | 563 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
|
564 at.rd = self.rdm.num |
292 | 565 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
|
566 #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
|
567 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
|
568 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
|
569 return at.encode() |
292 | 570 |
571 def __repr__(self): | |
572 return '{} {}, {}'.format(self.mnemonic, self.rn, self.rdm) | |
573 | |
574 | |
575 class regreg_base(ArmInstruction): | |
576 """ ??? Rdn, Rm """ | |
577 operands = (Reg8Op, Reg8Op) | |
578 # TODO: integrate with the code gen interface: | |
579 src = (0, 1) | |
580 dst = (0,) | |
581 def __init__(self, rdn, rm): | |
582 self.rdn = rdn | |
583 self.rm = rm | |
584 | |
585 @classmethod | |
586 def fromim(cls, im): | |
587 return cls(im.src[0], im.src[1]) | |
588 | |
589 def encode(self): | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
590 at = ArmToken() |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
591 at.rd = self.rdn.num |
292 | 592 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
|
593 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
|
594 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
|
595 return at.encode() |
292 | 596 |
597 def __repr__(self): | |
598 return '{} {}, {}'.format(self.mnemonic, self.rdn, self.rm) | |
599 | |
600 | |
601 @instruction | |
602 class movregreg_ins(regreg_base): | |
603 """ mov Rd, Rm (reg8 operands) """ | |
604 mnemonic = 'mov' | |
605 opcode = 0 | |
606 | |
607 | |
608 @instruction | |
609 class And(regreg_base): | |
610 mnemonic = 'AND' | |
611 opcode = 0b0100000000 | |
612 | |
613 | |
614 @instruction | |
615 class Orr(regreg_base): | |
616 mnemonic = 'ORR' | |
617 opcode = 0b0100001100 | |
618 | |
619 | |
620 @instruction | |
621 class Cmp(regreg_base): | |
622 mnemonic = 'CMP' | |
623 opcode = 0b0100001010 | |
624 | |
625 | |
626 @instruction | |
627 class Lsl(regreg_base): | |
628 mnemonic = 'LSL' | |
629 opcode = 0b0100000010 | |
630 | |
631 | |
632 @instruction | |
633 class cmpregimm8_ins(ArmInstruction): | |
634 """ cmp Rn, imm8 """ | |
635 mnemonic = 'cmp' | |
636 opcode = 5 # 00101 | |
637 operands = (Reg8Op, Imm8) | |
638 def __init__(self, rn, imm): | |
639 self.rn = rn | |
640 self.imm = imm | |
641 | |
642 def encode(self): | |
643 rn = self.rn.num | |
644 imm = self.imm.imm | |
645 opcode = self.opcode | |
646 h = (opcode << 11) | (rn << 8) | imm | |
647 return u16(h) | |
648 | |
649 | |
650 # Jumping: | |
651 | |
652 def wrap_negative(x, bits): | |
653 b = struct.unpack('<I', struct.pack('<i', x))[0] | |
654 mask = (1 << bits) - 1 | |
655 return b & mask | |
656 | |
657 class jumpBase_ins(ArmInstruction): | |
658 operands = (LabelRef,) | |
659 def __init__(self, target_label): | |
660 assert type(target_label) is LabelRef | |
661 self.target = target_label | |
662 self.offset = 0 | |
663 | |
664 def __repr__(self): | |
665 return '{} {}'.format(self.mnemonic, self.target.name) | |
666 | |
667 | |
335 | 668 class Imm11Reloc: |
669 def apply(self, P, S): | |
670 pass | |
671 | |
672 | |
292 | 673 @instruction |
674 class B(jumpBase_ins): | |
675 mnemonic = 'B' | |
676 def encode(self): | |
677 imm11 = wrap_negative(self.offset >> 1, 11) | |
678 h = (0b11100 << 11) | imm11 # | 1 # 1 to enable thumb mode | |
679 return u16(h) | |
680 | |
335 | 681 def relocations(self): |
682 return [(self.target.name, 'wrap_new11')] | |
292 | 683 |
684 @instruction | |
685 class Bl(jumpBase_ins): | |
686 mnemonic = 'BL' | |
687 def encode(self): | |
688 imm32 = wrap_negative(self.offset >> 1, 32) | |
689 imm11 = imm32 & 0x7FF | |
690 imm10 = (imm32 >> 11) & 0x3FF | |
691 j1 = 1 # TODO: what do these mean? | |
692 j2 = 1 | |
693 s = (imm32 >> 24) & 0x1 | |
694 h1 = (0b11110 << 11) | (s << 10) | imm10 | |
695 h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) | imm11 | |
696 return u16(h1) + u16(h2) | |
697 | |
335 | 698 def relocations(self): |
699 return [(self.target.name, 'bl_imm11_imm10')] | |
292 | 700 |
335 | 701 |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
702 class cond_base_ins(jumpBase_ins): |
292 | 703 def encode(self): |
704 imm8 = wrap_negative(self.offset >> 1, 8) | |
705 h = (0b1101 << 12) | (self.cond << 8) | imm8 | |
706 return u16(h) | |
707 | |
335 | 708 def relocations(self): |
709 return [(self.target.name, 'rel8')] | |
710 | |
711 | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
712 class cond_base_ins_long(jumpBase_ins): |
335 | 713 """ Encoding T3 """ |
714 def encode(self): | |
715 j1 = 1 # TODO: what do these mean? | |
716 j2 = 1 | |
717 h1 = (0b11110 << 11) | (self.cond << 6) | |
718 h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) | |
719 return u16(h1) + u16(h2) | |
720 | |
721 def relocations(self): | |
722 return [(self.target.name, 'b_imm11_imm6')] | |
723 | |
292 | 724 |
725 @instruction | |
726 class Beq(cond_base_ins): | |
727 mnemonic = 'beq' | |
728 cond = 0 | |
729 | |
730 | |
731 @instruction | |
732 class Bne(cond_base_ins): | |
733 mnemonic = 'bne' | |
734 cond = 1 | |
735 | |
736 | |
737 @instruction | |
738 class Blt(cond_base_ins): | |
739 mnemonic = 'blt' | |
740 cond = 0b1011 | |
741 | |
742 | |
743 @instruction | |
744 class Bgt(cond_base_ins): | |
745 mnemonic = 'bgt' | |
746 cond = 0b1100 | |
747 | |
748 | |
749 @instruction | |
750 class Push(ArmInstruction): | |
751 operands = (RegisterSet,) | |
752 mnemonic = 'push' | |
753 | |
754 def __init__(self, regs): | |
755 if type(regs) is set: | |
756 regs = RegisterSet(regs) | |
757 assert (type(regs),) == self.operands, (type(regs),) | |
758 self.regs = regs | |
759 | |
760 def __repr__(self): | |
761 return '{0} {{{1}}}'.format(self.mnemonic, self.regs) | |
762 | |
763 def encode(self): | |
764 reg_list = 0 | |
765 M = 0 | |
766 for n in self.regs.registerNumbers(): | |
767 if n < 8: | |
768 reg_list |= (1 << n) | |
769 elif n == 14: | |
770 M = 1 | |
771 else: | |
772 raise NotImplementedError('not implemented for this register') | |
773 h = (0x5a << 9) | (M << 8) | reg_list | |
774 return u16(h) | |
775 | |
776 | |
777 @instruction | |
778 class Pop(ArmInstruction): | |
779 operands = (RegisterSet,) | |
780 mnemonic = 'pop' | |
781 | |
782 def __init__(self, regs): | |
783 if type(regs) is set: | |
784 regs = RegisterSet(regs) | |
785 assert (type(regs),) == self.operands, (type(regs),) | |
786 self.regs = regs | |
787 | |
788 def __repr__(self): | |
789 return '{0} {{{1}}}'.format(self.mnemonic, self.regs) | |
790 | |
791 def encode(self): | |
792 reg_list = 0 | |
793 P = 0 | |
794 for n in self.regs.registerNumbers(): | |
795 if n < 8: | |
796 reg_list |= (1 << n) | |
797 elif n == 15: | |
798 P = 1 | |
799 else: | |
800 raise NotImplementedError('not implemented for this register') | |
801 h = (0x5E << 9) | (P << 8) | reg_list | |
802 return u16(h) | |
803 | |
804 | |
805 @instruction | |
806 class Yield(ArmInstruction): | |
807 operands = () | |
808 mnemonic = 'yield' | |
809 | |
810 def encode(self): | |
811 return u16(0xbf10) | |
812 | |
813 # misc: | |
814 | |
815 # add/sub SP: | |
816 class addspsp_base(ArmInstruction): | |
817 operands = (RegSpOp, RegSpOp, Imm7) | |
818 def __init__(self, _sp, _sp2, imm7): | |
819 self.imm7 = imm7.imm | |
820 assert self.imm7 % 4 == 0 | |
821 self.imm7 >>= 2 | |
822 | |
823 def encode(self): | |
824 return u16((self.opcode << 7) |self.imm7) | |
825 | |
826 def __repr__(self): | |
827 return '{} sp, sp, {}'.format(self.mnemonic, self.imm7 << 2) | |
828 | |
305 | 829 |
292 | 830 @instruction |
831 class AddSp(addspsp_base): | |
832 mnemonic = 'add' | |
833 opcode = 0b101100000 | |
834 | |
835 | |
836 @instruction | |
837 class SubSp(addspsp_base): | |
838 mnemonic = 'sub' | |
839 opcode = 0b101100001 |