Update for before meeting http://jeff.tk/wiki/Trinary/Meeting_Notes_20080706#Tasks_in...
[trinary.git] / asm / asm.py
blobd3c4811c521b303fbbc1e9cda0fd07eda87e0c1c
1 #!env python
2 # Created:20080312
3 # By Jeff Connelly
5 # 3-trit computer assembler
7 import sys, os
9 def main():
10 if len(sys.argv) < 2:
11 print """usage: %s program.t
12 input file: program.t - assembly code
13 outputs:
14 \tprogram.3 - assembled tritstream
15 \tprogram.sp - SPICE file suitable for use with swrom-fast
16 """ % (sys.argv[0])
18 raise SystemExit
20 if not sys.argv[1].endswith(".t"):
21 print "Input assembly filename must end in .t"
22 raise SystemExit
24 asmfile = file(sys.argv[1], "rt")
25 tritstream_filename = sys.argv[1].replace(".t", ".3")
26 tritstream_file = file(tritstream_filename, "wt")
27 spice_filename = sys.argv[1].replace(".t", ".sp")
28 spice_file = file(spice_filename, "wt")
30 tritstream = assemble(asmfile)
31 tritstream_file.write(tritstream)
32 spice_file.write(tospice(tritstream))
34 def tospice(tritstream):
35 """Convert tritstream to SPICE source for 3x3 swrom-fast."""
37 # Read down, then across (one instruction per _column_, not row)
38 code = [
39 [None,None,None],
40 [None,None,None],
41 [None,None,None]
44 all_instr = []
45 for i in range(0,3):
46 all_instr.append(tritstream[i*3:i*3+3])
47 code[0][i] = tritstream[i*3 + 0]
48 code[1][i] = tritstream[i*3 + 1]
49 code[2][i] = tritstream[i*3 + 2]
51 s = "; swrom-fast include file, generated to by asm/asm.py, for tritstream:\n"
52 for instr in all_instr:
53 s += "; " + instr + "\n"
54 s += "\n"
56 s += """; Select a voltage value based on the logic input at A
57 .func choose(A,for_n,for_z,for_p) {if(A<={V_N_max},for_n,if(A>={V_P_min},for_p,for_z))}
59 ; Threshold voltages
60 .param V_N_max=-2
61 .param V_P_min=2
63 """
65 i = 0
66 for row in code:
67 s += ".func program_%s(A) {choose(A," % ({0:"i", 1:0, 2:1}[i],)
68 i += 1
69 voltages = []
70 for col in row:
71 v = "V("
72 if col == "i":
73 v += "_1"
74 elif col == "1":
75 v += "1"
76 else:
77 v += "0"
78 v += ")"
79 voltages.append(v)
80 s += ",".join(voltages)
81 s += ")}\n"
82 return s
84 def assemble(asmfile):
85 """Return a serialized tritstream of asmfile assembled."""
86 pc = 0 # PC goes 0, 1, -1 _NOT_ -1, 0, 1 (0 on power-up)
87 labels = {}
88 opcode_map = { "lwi": [0], "cmp": [-1], "be": [1] }
89 register_map = { "in": [-1], "out": [0], "a": [1] }
90 # TODO: balanced trinary conversion routines
91 literal_map = {
92 "4": [1, 1],
93 "3": [1, 0],
94 "2": [1, -1],
95 "1": [0, 1],
96 "0": [0, 0],
97 "-1": [0, -1],
98 "-2": [-1, 1],
99 "-3": [-1, 0],
100 "-4": [-1, -1]
103 tritstream = []
104 while True:
105 line = asmfile.readline()
106 # End on EOF
107 if len(line) == 0:
108 break
110 # Skip blank lines
111 line = line.strip()
112 if len(line) == 0:
113 continue
115 label, opcode, operands = parse_line(line)
116 if opcode == None:
117 continue
119 #print [label, opcode, operands]
120 machine_code = []
122 if label is not None:
123 labels[label] = [pc]
125 machine_code.extend(opcode_map[opcode])
126 for op in operands:
127 x = register_map.get(op,
128 labels.get(op,
129 literal_map.get(op)))
130 if x is None:
131 print "Bad register, label, or literal: %s" % (op, )
132 print "Labels: %s" % (labels,)
133 raise SystemExit
134 else:
135 machine_code.extend(x)
137 assert len(machine_code) == 3, \
138 "Incorrect operand count, instruction trits:: %s" % (machine_code,)
139 tritstream.extend(machine_code)
140 pc += 1
141 if pc > 3:
142 print "Too many instructions, need exactly 3 but pc=%d" % (pc,)
143 raise SystemExit
145 if pc != 3:
146 print "Too few instructions, need exactly 3 but pc=%d" % (pc,)
147 raise SystemExit
149 #print labels
151 # Execution goes 0, 1, i
152 # but we ordered i, 0, 1.
153 # Arrange the instructions so that the first
154 # instruction written is placed at 0, next at
155 # 1, then the last instruction at i--since
156 # execution begins at 0, this will perserve the order.
157 tritstream_ordered = (
158 tritstream[3*2:3*2+3] + # last instruction executed
159 tritstream[3*0:3*0+3] + # <-- PC starts here (0)
160 tritstream[3*1:3*1+3] # second instruction executed
163 # Serialize tritstream
164 s = ""
165 for t in tritstream_ordered:
166 if t == -1:
167 s += "i"
168 else:
169 s += str(t)
171 return s
173 def parse_line(line):
174 # Strip comments
175 without_comment = line.split(";", 1)[0]
176 if len(without_comment) == 0:
177 return (None, None, None)
179 # Separate label from instruction
180 label_and_instruction = without_comment.split(":", 1)
181 if len(label_and_instruction) > 1:
182 label, instruction = label_and_instruction
183 label = label.strip()
184 else:
185 instruction, = label_and_instruction
186 label = None
188 instruction = instruction.strip()
190 # Separate opcode from operands
191 tokens = instruction.split()
192 opcode = tokens[0]
193 operands = []
194 for token in tokens[1:]:
195 token = token.replace(",", "")
196 operands.append(token)
198 return (label, opcode, operands)
200 if __name__ == "__main__":
201 main()