Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 643 lines (566 sloc) 21.29 kb
e270bb91 »
2009-09-28 Initial commit.
1 #! /usr/bin/python
2
3 # Copyright (c) 2009 Marshall Vandegrift
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 from __future__ import with_statement
19
20 import sys
21 import re
22 from cStringIO import StringIO
23 from operator import add, sub
24 import copy
25 import struct
26 from itertools import islice, izip
27 import antlr3
28 import antlr3.tree
29 from ZasLexer import ZasLexer
30 from ZasParser import ZasParser
31 from ZasWalker import ZasWalker
32 from opcodes import OPCODES, COUNT_0OP, COUNT_1OP, COUNT_2OP, COUNT_VAR, \
33 COUNT_EXT, RESULT, BRANCH, BYREF, PACK1, RELATIVE, REVERSE, INVERT
34 from zheader import ZHeader
35
36 class ZasError(Exception):
37 pass
38
39 class Atom(object):
40 def argbits(self, byref=False, offset=0):
41 try:
42 _, value = self.eval()
43 except ZasError:
44 return 0
45 value = value - offset
46 if value >= 0 and value < (1 << 8):
47 return 1
48 return 0
49
50 def arg2opbits(self):
51 bits = self.argbits()
52 if bits == 1 or bits == 2:
53 return bits - 1
54 return None
55
56 class Register(Atom):
57 def __init__(self, name, indirect=False):
58 self.name = name
59 self.indirect = indirect
60 self.value = self._eval()
61
62 def __repr__(self):
63 return "Register(%r)" % (self.name,)
64
65 def _eval(self):
66 value = None
67 if self.name == '%sp':
68 value = 0
69 elif self.name.startswith('%l'):
70 value = int(self.name[2:]) + 1
71 if value < 1 or value > 15:
72 raise ZasError("invalid local register")
73 elif self.name.startswith('%g'):
74 value = int(self.name[2:]) + 16
75 if value < 16 or value > 255:
76 raise ZasError("invalid global register")
77 return value
78
79 def eval(self):
80 return set(), self.value
81
82 def argbits(self, byref=False, offset=0):
83 if byref and not self.indirect:
84 return 1
85 return 2
86
87 class String(Atom):
88 ESCAPE_RE = re.compile(r'[\\](.)')
89 # Newline is carriage return
90 ESCAPES = {'a': '\a', 'b': '\b', 'f': '\f', 'n': '\r', 'r': '\r',
91 't': '\t', 'v': '\v'}
92
93 def _escape(self, match):
94 char = match.group(1)
95 return self.ESCAPES.get(char, char)
96
97 def __init__(self, value):
98 self.value = self.ESCAPE_RE.sub(self._escape, value[1:-1])
99
100 def eval(self):
101 return set(), ord(self.value[0])
102
103 def __str__(self):
104 return self.value
105
106 def __repr__(self):
107 return "String(%r)" % (self.value,)
108
109 class Integer(Atom):
110 def __init__(self, value):
111 if isinstance(value, (int, long)):
112 pass
113 elif value[:2] == '0b':
114 value = int(value[2:], 2)
115 elif value[:2] == '0x':
116 value = int(value[2:], 16)
117 else:
118 value = int(value)
119 self.value = value
120
121 def eval(self):
122 return set(), self.value
123
124 def argbits(self, byref=False, offset=0):
125 if offset > 0:
126 return 0
127 if self.value >= 0 and self.value < (1 << 8):
128 return 1
129 return 0
130
131 def __repr__(self):
132 return "Integer(%r)" % (self.value,)
133
134 class RetBool(Atom):
135 VALUES = {':rfalse': 0,':rtrue': 1}
136
137 def __init__(self, value):
138 self.value = value
139
140 def eval(self):
141 return set(), self.VALUES[self.value]
142
143 def argbits(self, byref=False, offset=0):
144 return 1
145
146 def __repr__(self):
147 return "RetBool(%s)" % (self.value,)
148
149 class Symbol(Atom):
150 def __init__(self, name, locdir=None):
151 self.name = name
152 self.locdir = locdir
153 self.local = bool(locdir) or name[0].isdigit()
154 self.sections = set()
155 self.value = None
156 self.expr = None
157
158 def eval(self):
159 if self.value is not None:
160 return self.sections, self.value
161 if self.expr is not None:
162 sections, value = self.expr.eval()
163 return sections, value
164 raise ZasError('Evaluated not-yet-defined symbol %r' % self.name)
165
166 def argbits(self, byref=False, offset=0):
167 if self.local and not self.value and not self.expr and offset > 0:
168 return 1
169 try:
170 value = self.eval()[1]
171 except ZasError:
172 return 0
173 if value >= 0 and value < (1 << 8):
174 return 1
175 return 0
176
177 def __repr__(self):
178 return "Symbol(%r)" % (self.name + (self.locdir or ''),)
179
180 class Expr(Atom):
181 def __init__(self, oper, *args):
182 self.oper = oper
183 self.args = args
184
185 def eval(self):
186 sections, args = set(), []
187 for arg in self.args:
188 s, a = arg.eval()
189 if self.oper == sub:
190 sections.difference_update(s)
191 else:
192 sections.update(s)
193 args.append(a)
194 value = self.oper(*args)
195 return sections, value
196
197 def __repr__(self):
198 result = []
199 for arg in self.args:
200 result.append(repr(arg))
201 return 'Expr(?, %s)' % ', '.join(result)
202
203 class Section(object):
204 def __init__(self, name):
205 self.name = name
206 self.content = StringIO()
207 # Fake-out pre-relocation symbol sizes
208 self.base = 0x10000
209
210 def offset():
211 def fget(self):
212 return self.content.tell()
213 def fset(self, value):
214 self.content.seek(value)
215 return property(fget=fget, fset=fset)
216 offset = offset()
217
218 def __len__(self):
219 offset = self.content.tell()
220 try:
221 self.content.seek(0, 2)
222 result = self.content.tell()
223 finally:
224 self.content.seek(offset, 0)
225 return result
226
227 def eval(self):
228 return set([self]), self.base
229
230 def __getattr__(self, name):
231 return getattr(self.content, name)
232
233 def __repr__(self):
234 return "Section(%r)" % (self.name,)
235
236 class ZasAssembler(object):
237 ALPHATAB = ["abcdefghijklmnopqrstuvwxyz",
238 "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
239 "\r0123456789.,!?_#'\"/\\-:()"]
240
241 def __init__(self):
242 self.symtab = {}
243 self.relocs = []
244 self.sections = {'data': Section('data'),
245 'rodata': Section('rodata'),
246 'text': Section('text')}
247 self.section = self.sections['text']
248 self.start = None
249
250 def finalize(self):
251 sections = self.sections
252 base = sections['data'].base = 0
253 datasz = len(sections['data'])
254 mod = datasz % 4
255 if mod != 0:
256 sections['data'].write('\0' * (8 - mod))
257 datasz = len(sections['data'])
258 sections['rodata'].base = base + datasz
259 rodatasz = len(sections['rodata'])
260 mod = rodatasz % 4
261 if mod != 0:
262 sections['rodata'].write('\0' * (8 - mod))
263 rodatasz = len(sections['rodata'])
264 sections['text'].base = base + datasz + rodatasz
265 mod = len(sections['text']) % 4
266 if mod != 0:
267 sections['text'].write('\0' * (8 - mod))
268 for reloc in self.relocs:
269 section, offset, expr, widths, relative, branch, invert = reloc
270 # print (section, hex(offset), widths, expr, expr.eval())
271 self._relocate(expr, widths, relative=relative, branch=branch,
272 invert=invert, fixup=True, section=section,
273 offset=offset)
274 self.start = self.start.eval()[1]
275 self.globals = self.globals.eval()[1]
276
277 def symbol(self, name):
278 if name == '.':
279 return self._current_address()
280 if name[0].isdigit() and not name[-1].isdigit():
281 locdir = name[-1]
282 name = name[:-1]
283 else:
284 locdir = None
285 if name not in self.symtab or \
286 (locdir == 'f' and self.symtab[name].expr is not None):
287 self.symtab[name] = Symbol(name, locdir)
288 return self.symtab[name]
289
290 def packaddr(self, number):
291 return number >> 2
292
293 def integer(self, *args):
294 return Integer(*args)
295
296 def expr(self, *args):
297 return Expr(*args)
298
299 def register(self, *args):
300 return Register(*args)
301
302 def string(self, *args):
303 return String(*args)
304
305 def retbool(self, *args):
306 return RetBool(*args)
307
308 def insn(self, name, args):
309 meth = '_insn_' + name.replace('.', 'dot_')
310 if hasattr(self, meth):
311 return getattr(self, meth)(*args)
312 raise ZasError('unknown instruction or directive %r' % name)
313
314 def _relocate(self, expr, widths, relative=False, branch=False,
315 invert=False, fixup=False, section=None, offset=None):
316 section = self.section if section is None else section
317 if offset is not None:
318 section.offset = offset
319 else:
320 offset = section.offset
321 if isinstance(expr, (Register, RetBool)):
322 relative = False
323 elif branch:
324 relative = True
325 sections, value = None, None
326 try:
327 sections, value = expr.eval()
328 except ZasError:
329 if fixup:
330 raise
331 if value is None or \
332 (not fixup and sections and
333 (not relative or (len(sections) > 1 or
334 section not in sections))):
335 if relative and isinstance(expr, Symbol) and expr.local:
336 width = widths[0]
337 else:
338 width = widths[-1]
339 reloc = (section, offset, expr, width, relative, branch, invert)
340 if fixup:
341 raise ZasError('could not perform relocation: %r' % (reloc,))
342 self.relocs.append(reloc)
343 self.section.write(struct.pack('>' + width, 0))
344 return struct.calcsize(width)
345 for width in widths:
346 bytes = struct.calcsize(width)
347 v = value
348 if relative:
349 v = v - (section.base + offset + bytes) + 2
350 fbits = 2 if branch else 0
351 max = 1 << ((bytes * 8) - fbits)
352 min = 0 if bytes == 1 else -(max >> 1)
353 if relative and bytes == 2:
354 max = (max >> 1)
355 if v < min or v > max:
356 continue
357 if branch:
358 if v < 0:
359 width = width.upper()
360 v = (1 << 14) - abs(v)
361 if not invert:
362 v |= 0x80 << (8 * (bytes - 1))
363 if bytes == 1:
364 v |= 0x40
365 if v > 0 and v >= (max >> 1):
366 width = width.upper()
367 #print 1, (expr, relative, width, v)
368 section.write(struct.pack('>' + width, v))
369 return struct.calcsize(width)
370 else:
9fb7a1de »
2009-09-28 Use cleaner unsigned comparison algorithm.
371 raise ZasError("number %r out of range for width options %r" %
e270bb91 »
2009-09-28 Initial commit.
372 (value, widths))
373 return
374
375 def _current_address(self):
376 return Expr(add, self.section, Integer(self.section.offset))
377
378 def _zencode(self, chars):
379 enchars = []
380 for char in chars:
381 if char == ' ':
382 enchars.append(0)
383 elif char in self.ALPHATAB[0]:
384 zchar = self.ALPHATAB[0].index(char) + 6
385 enchars.append(zchar)
386 elif char in self.ALPHATAB[1]:
387 zchar = self.ALPHATAB[1].index(char) + 6
388 enchars.extend([4, zchar])
389 elif char in self.ALPHATAB[2]:
390 zchar = self.ALPHATAB[2].index(char) + 7
391 enchars.extend([5, zchar])
392 else:
393 zchar = ord(char)
394 enchars.extend([5, 6, (zchar >> 5) & 0x1f, zchar & 0x1f])
395 mod = len(enchars) % 3
396 pad = 0 if mod == 0 else 3 - mod
397 enchars.extend([5] * pad)
398 words = []
399 slices = [islice(enchars, i, None, 3) for i in xrange(3)]
400 for hi, mi, lo in izip(*slices):
401 words.append((hi << 10) | (mi << 5) | (lo << 0))
402 words[-1] |= 0x8000
403 result = struct.pack('>' + ('H' * len(words)), *words)
404 return result
405
406 def _insn_dot_set(self, symbol, expr):
407 if symbol.value is None and symbol.expr is None:
408 symbol.expr = expr
409 return
410 symbol = copy.copy(symbol)
411 symbol.expr = expr
412 self.symtab[symbol.name] = symbol
413
414 def _insn_dot_section(self, symbol):
415 self.section = self.sections[symbol.name]
416
417 def _insn_dot_align(self, expr):
418 _, value = expr.eval()
419 self._align(value)
420
421 def _align(self, value):
422 mod = self.section.offset % value
423 if mod != 0:
424 self.section.offset += value - mod
425 return
426
427 def _insn_dot_byte(self, *args):
428 for arg in args:
429 if isinstance(arg, String):
430 self.section.write(str(arg))
431 else:
432 self._relocate(arg, 'b')
433 return
434
435 def _insn_dot_word(self, *args):
436 self._align(2)
437 for arg in args:
438 self._relocate(arg, 'h')
439 return
440
441 def _insn_dot_ascii(self, *args):
442 for arg in args:
443 self.section.write(str(arg))
444 return
445
446 def _insn_dot_asciz(self, *args):
447 for arg in args:
448 self.section.write(str(arg) + '\0')
449 return
450
451 def _insn_dot_zscii(self, *args):
452 for arg in args:
453 self.section.write(self._zencode(str(arg)))
454 return
455
456 def _insn_dot_fill(self, repeat, size=None, value=None):
457 repeat = repeat.eval()[1]
458 size = 1 if size is None else size.eval()[1]
459 value = 0 if value is None else value.eval()[1]
460 format = {1: '>b', 2: '>h', 4: '>i'}[size]
461 code = struct.pack(format, value) * repeat
462 self.section.write(code)
463
464 def _insn_dot_org(self, expr):
465 sections, value = expr.eval()
466 if len(sections) > 1:
467 raise ZasError('nonsensical .org address')
468 if len(sections) > 0:
469 self.section = sections.pop()
470 value = value - self.section.base
471 self.section.offset = value
472
473 def _insn_dot_start(self, expr):
474 self.start = expr
475
476 def _insn_dot_label(self, label):
477 return self._insn_dot_set(label, self.symbol('.'))
478
479 def _insn_dot_routine(self, label, regcount):
480 regcount = regcount.eval()[1]
481 if regcount < 0 or regcount > 15:
482 raise ZasError('invalid number of local registers %r' %
483 (regcount,))
484 self._align(4)
485 self._insn_dot_label(label)
486 self.section.write(struct.pack('>b', regcount))
487 return
488
489 def _insn_dot_globals(self, label):
490 self.globals = label
491
492 def _insn_calln(self, *args):
493 if len(args) == 1:
494 return self._insn_call_1n(*args)
495 elif len(args) == 2:
496 return self._insn_call_2n(*args)
497 elif len(args) <= 4:
498 return self._insn_call_vn(*args)
499 else:
500 return self._insn_call_vn2(*args)
501
502 def _insn_calls(self, *args):
503 if len(args) == 1:
504 raise ZasError('calls instruction without result operand')
505 if len(args) == 2:
506 return self._insn_call_1s(*args)
507 elif len(args) == 3:
508 return self._insn_call_2s(*args)
509 elif len(args) <= 5:
510 return self._insn_call_vs(*args)
511 else:
512 return self._insn_call_vs2(*args)
513
514 def _insn_print(self, string):
515 self.section.write(struct.pack('>B', 0xb2))
516 self.section.write(self._zencode(str(string)))
517
518
519 def create_insns():
520 def create_insn(name, count, opcode, flags):
521 def do_insn(self, *args):
522 args = list(args)
523 branch = None
524 result = None
525 if flags & BRANCH:
526 branch = args.pop()
527 if flags & RESULT:
528 result = args.pop()
529 if not isinstance(result, Register):
530 raise ZasError('non-register result operand')
531 if flags & REVERSE:
532 args.reverse()
533 if flags & PACK1 and not isinstance(args[0], Register):
534 args[0] = Expr(self.packaddr, args[0])
535 if flags & BYREF and not args[0].indirect:
536 args[0] = Integer(args[0].value)
537 if count == COUNT_0OP:
538 if len(args) != 0:
539 raise ZasError("bad arguments for %r" % (name,))
540 code = 0xb0 | opcode
541 self.section.write(struct.pack('>B', code))
542 elif count == COUNT_1OP:
543 if len(args) != 1:
544 raise ZasError("bad arg count for %r" % (name,))
545 arg, = args
546 if flags & RELATIVE:
547 relative = True
548 argbits = arg.argbits(offset=self.section.offset)
549 else:
550 relative = False
551 argbits = arg.argbits()
552 code = 0x80 | (argbits << 4) | opcode
553 self.section.write(struct.pack('>B', code))
554 self._relocate(arg, 'bh', relative=relative)
555 elif count == COUNT_2OP and len(args) == 2 and \
556 args[0].arg2opbits() is not None and \
557 args[1].arg2opbits() is not None:
558 code = ((args[0].arg2opbits() << 6) |
559 (args[1].arg2opbits() << 5) |
560 opcode)
561 self.section.write(struct.pack('>B', code))
562 self._relocate(args[0], 'bh')
563 self._relocate(args[1], 'bh')
564 elif count == COUNT_2OP or count == COUNT_VAR:
565 if len(args) > 4 and name not in ('call_vn2', 'call_vs2'):
566 raise ZasError("bad arg count for %r" % (name,))
567 if len(args) > 8:
568 raise ZasError("bad arg count for %r" % (name,))
569 code = 0xc0 if count == COUNT_2OP else 0xe0
570 code = code | opcode
571 self.section.write(struct.pack('>B', code))
572 argb = 0xff
573 for arg in reversed(args[:4]):
574 argb = (argb >> 2) | (arg.argbits() << 6)
575 self.section.write(struct.pack('>B', argb))
576 if len(args) > 4:
577 argb = 0xff
578 for arg in reversed(args[4:]):
579 argb = (argb >> 2) | (arg.argbits() << 6)
580 self.section.write(struct.pack('>B', argb))
581 for arg in args:
582 self._relocate(arg, 'bh')
583 elif count == COUNT_EXT:
584 if len(args) > 4:
585 raise ZasError("bad arg count for %r" % (name,))
586 argb = 0xff
587 for arg in reversed(args):
588 argb = (argb >> 2) | (arg.argbits() << 6)
589 self.section.write(struct.pack('>BBB', 0xbe, opcode, argb))
590 for arg in args:
591 self._relocate(arg, 'bh')
592 else:
593 raise ZasError('wtf? unexpected instruction type')
594 if result:
595 self._relocate(result, 'b')
596 if branch:
597 invert = flags & INVERT
598 self._relocate(branch, 'bh', branch=True, invert=invert)
599 setattr(ZasAssembler, '_insn_' + name, do_insn)
600 for name, count, opcode, flags in OPCODES:
601 create_insn(name, count, opcode, flags)
602 create_insns()
603
604 class ZasWalker(ZasWalker):
605 def __init__(self, input, assembler):
606 super(ZasWalker, self).__init__(input)
607 self.assembler = assembler
608
609 def main(argv=sys.argv):
610 inpath, outpath = argv[1:]
611 with open(inpath, 'rb') as inf:
612 char_stream = antlr3.ANTLRInputStream(inf)
613 lexer = ZasLexer(char_stream)
614 tokens = antlr3.CommonTokenStream(lexer)
615 parser = ZasParser(tokens)
616 r = parser.program()
617 t = r.tree
618 #print t.toStringTree()
619 nodes = antlr3.tree.CommonTreeNodeStream(t)
620 nodes.setTokenStream(tokens)
621 assembler = ZasAssembler()
622 walker = ZasWalker(nodes, assembler)
623 walker.program()
624 assembler.finalize()
625 zcode = []
626 for secname in ('data', 'rodata', 'text'):
627 zcode.append(assembler.sections[secname].getvalue())
628 zcode = ''.join(zcode)[0x40:]
629 header = ZHeader()
630 header.version = 5
631 header.initpc = assembler.start
632 header.globals = assembler.globals
633 header.statmem = assembler.sections['rodata'].base
634 header.himem = assembler.sections['text'].base
635 header.filesz = len(zcode) + 0x40
636 with open(outpath, 'wb') as outf:
637 outf.write(str(header))
638 outf.write(zcode)
639 return 0
640
641 if __name__ == '__main__':
642 sys.exit(main())
Something went wrong with that request. Please try again.