Mercurial > lcfOS
annotate python/ppci/target/basetarget.py @ 385:d056b552d3f4
Made better use of layout
author | Windel Bouwman |
---|---|
date | Thu, 01 May 2014 14:03:12 +0200 |
parents | 6df89163e114 |
children | 2a970e7270e2 |
rev | line source |
---|---|
362 | 1 import types |
200 | 2 from ppci import CompilerError |
385 | 3 from ..bitfun import encode_imm32 |
4 import struct | |
199 | 5 |
6 """ | |
7 Base classes for defining a target | |
8 """ | |
9 | |
234 | 10 class Instruction: |
292 | 11 """ Base instruction class """ |
234 | 12 def encode(self): |
335 | 13 return bytes() |
292 | 14 |
335 | 15 def relocations(self): |
16 return [] | |
17 | |
18 def symbols(self): | |
19 return [] | |
234 | 20 |
381 | 21 def literals(self, add_literal): |
22 pass | |
23 | |
234 | 24 |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
277
diff
changeset
|
25 class Nop(Instruction): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
277
diff
changeset
|
26 """ Instruction that does nothing and has zero size """ |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
277
diff
changeset
|
27 def encode(self): |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
277
diff
changeset
|
28 return bytes() |
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
277
diff
changeset
|
29 |
354 | 30 def __repr__(self): |
31 return 'NOP' | |
32 | |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
277
diff
changeset
|
33 |
234 | 34 class PseudoInstruction(Instruction): |
35 pass | |
36 | |
37 | |
38 class Label(PseudoInstruction): | |
206 | 39 def __init__(self, name): |
40 self.name = name | |
41 | |
235 | 42 def __repr__(self): |
43 return '{}:'.format(self.name) | |
44 | |
335 | 45 def symbols(self): |
46 return [self.name] | |
235 | 47 |
48 | |
234 | 49 class Comment(PseudoInstruction): |
50 def __init__(self, txt): | |
51 self.txt = txt | |
249 | 52 |
235 | 53 def encode(self): |
54 return bytes() | |
249 | 55 |
234 | 56 def __repr__(self): |
57 return '; {}'.format(self.txt) | |
58 | |
235 | 59 |
234 | 60 class Alignment(PseudoInstruction): |
61 def __init__(self, a): | |
62 self.align = a | |
235 | 63 |
64 def __repr__(self): | |
65 return 'ALIGN({})'.format(self.align) | |
66 | |
234 | 67 def encode(self): |
68 pad = [] | |
335 | 69 # TODO |
70 address = 0 | |
235 | 71 while (address % self.align) != 0: |
234 | 72 address += 1 |
73 pad.append(0) | |
74 return bytes(pad) | |
75 | |
292 | 76 |
346 | 77 class Register: |
199 | 78 def __init__(self, name): |
79 self.name = name | |
80 | |
366 | 81 def __gt__(self, other): |
82 return self.num > other.num | |
83 | |
199 | 84 |
364 | 85 class LabelAddress: |
86 def __init__(self, name): | |
87 self.name = name | |
88 | |
89 | |
199 | 90 class Target: |
201 | 91 def __init__(self, name, desc=''): |
92 self.name = name | |
93 self.desc = desc | |
200 | 94 self.registers = [] |
341 | 95 self.byte_sizes = {'int' : 4} # For front end! |
354 | 96 self.byte_sizes['byte'] = 1 |
341 | 97 |
346 | 98 # For lowering: |
99 self.lower_functions = {} | |
100 | |
341 | 101 # For assembler: |
102 self.assembler_rules = [] | |
103 self.asm_keywords = [] | |
104 | |
346 | 105 self.generate_base_rules() |
385 | 106 self.reloc_map = reloc_map # TODO: make this target specific. |
346 | 107 |
108 def generate_base_rules(self): | |
345 | 109 # Base rules for constants: |
110 self.add_rule('imm32', ['val32'], lambda x: x[0].val) | |
111 self.add_rule('imm32', ['imm16'], lambda x: x[0]) | |
112 | |
113 self.add_rule('imm16', ['val16'], lambda x: x[0].val) | |
114 self.add_rule('imm16', ['imm12'], lambda x: x[0]) | |
115 | |
116 self.add_rule('imm12', ['val12'], lambda x: x[0].val) | |
117 self.add_rule('imm12', ['imm8'], lambda x: x[0]) | |
118 | |
119 self.add_rule('imm8', ['val8'], lambda x: x[0].val) | |
120 self.add_rule('imm8', ['imm5'], lambda x: x[0]) | |
121 | |
122 self.add_rule('imm5', ['val5'], lambda x: x[0].val) | |
123 self.add_rule('imm5', ['imm3'], lambda x: x[0]) | |
124 | |
125 self.add_rule('imm3', ['val3'], lambda x: x[0].val) | |
126 | |
341 | 127 def add_keyword(self, kw): |
128 self.asm_keywords.append(kw) | |
129 | |
130 def add_instruction(self, rhs, f): | |
131 self.add_rule('instruction', rhs, f) | |
132 | |
133 def add_rule(self, lhs, rhs, f): | |
362 | 134 if type(f) is int: |
135 f2 = lambda x: f | |
136 else: | |
137 f2 = f | |
138 assert type(f2) is types.FunctionType | |
139 self.assembler_rules.append((lhs, rhs, f2)) | |
200 | 140 |
346 | 141 def lower_frame_to_stream(self, frame, outs): |
142 """ Lower instructions from frame to output stream """ | |
143 for im in frame.instructions: | |
144 if isinstance(im.assem, Instruction): | |
145 outs.emit(im.assem) | |
146 else: | |
381 | 147 # TODO assert isinstance(Abs |
346 | 148 ins = self.lower_functions[im.assem](im) |
149 outs.emit(ins) | |
201 | 150 |
346 | 151 def add_lowering(self, cls, f): |
152 """ Add a function to the table of lowering options for this target """ | |
153 self.lower_functions[cls] = f | |
385 | 154 |
155 def add_reloc(self, name, f): | |
156 self.reloc_map[name] = f | |
157 | |
158 | |
159 | |
160 def align(x, m): | |
161 while ((x % m) != 0): | |
162 x = x + 1 | |
163 return x | |
164 | |
165 def wrap_negative(x, bits): | |
166 b = struct.unpack('<I', struct.pack('<i', x))[0] | |
167 mask = (1 << bits) - 1 | |
168 return b & mask | |
169 | |
170 | |
171 reloc_map = {} | |
172 | |
173 def reloc(t): | |
174 def f(c): | |
175 reloc_map[t] = c | |
176 return f | |
177 | |
178 | |
179 @reloc('lit_add_8') | |
180 def apply_lit8(reloc, sym_value, section, reloc_value): | |
181 assert sym_value % 4 == 0 | |
182 offset = (sym_value - (align(reloc_value + 2, 4))) | |
183 assert offset in range(0, 1024, 4), str(offset)+str( self.dst.sections) | |
184 rel8 = offset >> 2 | |
185 section.data[reloc.offset] = rel8 | |
186 | |
187 | |
188 @reloc('wrap_new11') | |
189 def apply_wrap_new11(reloc, sym_value, section, reloc_value): | |
190 offset = sym_value - (align(reloc_value, 2) + 4) | |
191 assert offset in range(-2048, 2046, 2) | |
192 imm11 = wrap_negative(offset >> 1, 11) | |
193 section.data[reloc.offset] = (imm11 & 0xff) | |
194 section.data[reloc.offset + 1] |= (imm11 >> 8) & 0x7 | |
195 | |
196 | |
197 @reloc('rel8') | |
198 def apply_rel8(reloc, sym_value, section, reloc_value): | |
199 assert sym_value % 2 == 0 | |
200 offset = sym_value - (align(reloc_value, 2) + 4) | |
201 assert offset in range(-256, 254, 2), str(offset) + str(reloc) | |
202 imm8 = wrap_negative(offset >> 1, 8) | |
203 section.data[reloc.offset] = imm8 | |
204 | |
205 | |
206 @reloc('bl_imm11_imm10') | |
207 def apply_bl_imm11(reloc, sym_value, section, reloc_value): | |
208 assert sym_value % 2 == 0 | |
209 offset = sym_value - (align(reloc_value, 2) + 4) | |
210 assert offset in range(-16777216, 16777214, 2), str(offset) | |
211 imm32 = wrap_negative(offset >> 1, 32) | |
212 imm11 = imm32 & 0x7FF | |
213 imm10 = (imm32 >> 11) & 0x3FF | |
214 s = (imm32 >> 24) & 0x1 | |
215 section.data[reloc.offset + 2] = imm11 & 0xFF | |
216 section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7 | |
217 section.data[reloc.offset] = imm10 & 0xff | |
218 section.data[reloc.offset + 1] |= ((imm10 >> 8) & 0x3) | (s << 2) | |
219 | |
220 @reloc('b_imm11_imm6') | |
221 def apply_b_imm11_imm6(reloc, sym_value, section, reloc_value): | |
222 assert sym_value % 2 == 0 | |
223 offset = sym_value - (align(reloc_value, 2) + 4) | |
224 assert offset in range(-1048576, 1048574, 2), str(offset) | |
225 imm32 = wrap_negative(offset >> 1, 32) | |
226 imm11 = imm32 & 0x7FF | |
227 imm6 = (imm32 >> 11) & 0x3F | |
228 s = (imm32 >> 24) & 0x1 | |
229 section.data[reloc.offset + 2] = imm11 & 0xFF | |
230 section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7 | |
231 section.data[reloc.offset] |= imm6 | |
232 section.data[reloc.offset + 1] |= (s << 2) | |
233 | |
234 # ARM reloc!! | |
235 # TODO: move to target classes??? | |
236 @reloc('b_imm24') | |
237 def apply_b_imm24(reloc, sym_value, section, reloc_value): | |
238 assert sym_value % 4 == 0 | |
239 assert reloc_value % 4 == 0 | |
240 offset = (sym_value - (reloc_value + 8)) | |
241 rel24 = wrap_negative(offset >> 2, 24) | |
242 section.data[reloc.offset+2] = (rel24 >> 16) & 0xFF | |
243 section.data[reloc.offset+1] = (rel24 >> 8) & 0xFF | |
244 section.data[reloc.offset+0] = rel24 & 0xFF | |
245 | |
246 | |
247 @reloc('ldr_imm12') | |
248 def apply_ldr_imm12(reloc, sym_value, section, reloc_value): | |
249 assert sym_value % 4 == 0 | |
250 assert reloc_value % 4 == 0 | |
251 offset = (sym_value - (reloc_value + 8)) | |
252 U = 1 | |
253 if offset < 0: | |
254 offset = -offset | |
255 U = 0 | |
256 assert offset < 4096, str(sym) + str(section) + str(reloc) | |
257 section.data[reloc.offset+2] |= (U << 7) | |
258 section.data[reloc.offset+1] |= (offset >> 8) & 0xF | |
259 section.data[reloc.offset+0] = offset & 0xFF | |
260 | |
261 @reloc('adr_imm12') | |
262 def apply_adr_imm12(reloc, sym_value, section, reloc_value): | |
263 assert sym_value % 4 == 0 | |
264 assert reloc_value % 4 == 0 | |
265 offset = (sym_value - (reloc_value + 8)) | |
266 U = 2 | |
267 if offset < 0: | |
268 offset = -offset | |
269 U = 1 | |
270 assert offset < 4096 | |
271 offset = encode_imm32(offset) | |
272 section.data[reloc.offset+2] |= (U << 6) | |
273 section.data[reloc.offset+1] |= (offset >> 8) & 0xF | |
274 section.data[reloc.offset+0] = offset & 0xFF | |
275 | |
276 @reloc('absaddr32') | |
277 def apply_absaddr32(reloc, sym_value, section, reloc_value): | |
278 assert sym_value % 4 == 0 | |
279 assert reloc_value % 4 == 0 | |
280 offset = sym_value | |
281 section.data[reloc.offset+3] = (offset >> 24) & 0xFF | |
282 section.data[reloc.offset+2] = (offset >> 16) & 0xFF | |
283 section.data[reloc.offset+1] = (offset >> 8) & 0xFF | |
284 section.data[reloc.offset+0] = offset & 0xFF |