-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuasm.py
executable file
·111 lines (95 loc) · 2.84 KB
/
uasm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/python2
# Microassembler for Tinystack. This doesn't do much except map mnemonics to
# nibbles and generate lit instruction sequences.
from tinystack_emu import *
parser = ArgumentParser()
parser.add_argument('infile', nargs='?',
type=FileType('r'), default=sys.stdin)
parser.add_argument('-o', '--outfile',
nargs='?', type=FileType('w+'), default=sys.stdout)
args = parser.parse_args()
nibbles = []
macros = {}
labels = {}
def align(nibbles, n=0):
if n:
while len(nibbles) % (n * 2):
nibbles.append(0)
else:
while len(nibbles) & 1:
nibbles.append(0)
def emit_lit(n):
if n in labels:
n = labels[n]
lit = lambda x: nibbles.extend([Tinystack.lit_instr.opcode, x])
lit(n & 0xF)
while n > 0xF:
n >>= 4
lit(n & 0xF)
def emit_word(n):
if n in labels:
n = labels[n]
if type(n) is str:
n = int(n, 0) & 0xffff
for _ in range(4):
nibbles.append((n >> 12) & 0xF)
n <<= 4
def proc_line(line):
global nibbles
line = line.strip().split(' ')
if line == ['']: return # ignore blank lines
first = line[0]
if first[0] == ';': return # ignore lines which start with a comment
if first[0] == '$':
align(nibbles, 2)
sign = {'-': -1, '+': 1}[first[1]]
offset = sign * int(first[1:], 0)
return emit_word(len(nibbles) / 2 + offset)
if first[0] == '&':
align(nibbles)
return emit_word(first[1:])
if first[-1] == ':':
align(nibbles)
labels[first.strip(':')] = len(nibbles) / 2
return
if first == 'align':
try:
addr = int(line[1], 0) & 0xffff
return align(nibbles, addr)
except ValueError:
return align(nibbles)
if first == 'skip':
nibbles.append(0) if len(nibbles) & 3 == 3 else 0
if first == 'call':
align(nibbles)
if first == 'lit':
if line[1] in labels:
return emit_lit(line[1])
else:
return emit_lit(int(line[1], 0) & 0xffff)
if first == 'include':
return map(proc_line, open(line[1]))
if first[-2:] == '.s':
return map(proc_line, open(first))
if first == 'defmacro':
return macros.update({line[1]: line[2:]})
try:
return emit_lit(int(first, 0) & 0xffff)
except ValueError: # not a number
pass
if first in by_name:
return nibbles.append(by_name[first].opcode)
if first in labels:
return emit_lit(labels[first])
return map(proc_line, macros[first])
map(proc_line, args.infile)
# stderr.write(str(labels) + '\n')
byte = 0
for i, nibble in enumerate(nibbles):
if i % 2:
byte |= nibble
args.outfile.write(chr(byte))
else:
byte = nibble << 4
if not i % 2:
args.outfile.write(chr(byte))