6502 opcodes are Emittables. Can compile simple programs now!
Chris Pressey
7 years ago
32 | 32 | optparser.add_option("--compile", |
33 | 33 | action="store_true", dest="compile", default=False, |
34 | 34 | help="") |
35 | optparser.add_option("--debug", | |
36 | action="store_true", dest="debug", default=False, | |
37 | help="") | |
35 | 38 | optparser.add_option("--traceback", |
36 | 39 | action="store_true", dest="traceback", default=False, |
37 | 40 | help="") |
60 | 63 | if options.compile: |
61 | 64 | emitter = Emitter(41952) |
62 | 65 | compile_program(program, emitter) |
63 | emitter.serialize(sys.stdout) | |
66 | if options.debug: | |
67 | print repr(emitter.accum) | |
68 | else: | |
69 | emitter.serialize(sys.stdout) | |
64 | 70 | |
65 | 71 | if options.execute: |
66 | 72 | context = eval_program(program) |
4 | 4 | ConstantRef, LocationRef, |
5 | 5 | REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C |
6 | 6 | ) |
7 | from sixtypical.gen6502 import Generator | |
7 | from sixtypical.emitter import Byte | |
8 | from sixtypical.gen6502 import ( | |
9 | Immediate, Absolute, | |
10 | LDA, LDX, LDY, STA, STX, STY, CLC, SEC, ADC, RTS | |
11 | ) | |
12 | ||
13 | ||
14 | class UnsupportedOpcodeError(KeyError): | |
15 | pass | |
8 | 16 | |
9 | 17 | |
10 | 18 | def compile_program(program, emitter): |
11 | 19 | assert isinstance(program, Program) |
12 | generator = Generator(emitter) | |
13 | 20 | routines = {r.name: r for r in program.routines} |
14 | 21 | for routine in program.routines: |
15 | compile_routine(routine, generator, routines) | |
22 | compile_routine(routine, emitter, routines) | |
16 | 23 | |
17 | 24 | |
18 | def compile_routine(routine, generator, routines): | |
25 | def compile_routine(routine, emitter, routines): | |
19 | 26 | assert isinstance(routine, Routine) |
20 | label = generator.emitter.make_label(routine.name) | |
21 | compile_block(routine.block, generator, routines) | |
27 | label = emitter.make_label(routine.name) | |
28 | compile_block(routine.block, emitter, routines) | |
29 | emitter.emit(RTS()) | |
22 | 30 | return label |
23 | 31 | |
24 | 32 | |
25 | def compile_block(block, generator, routines): | |
33 | def compile_block(block, emitter, routines): | |
26 | 34 | assert isinstance(block, Block) |
27 | label = generator.emitter.make_label() | |
35 | label = emitter.make_label() | |
28 | 36 | for instr in block.instrs: |
29 | compile_instr(instr, generator, routines) | |
37 | compile_instr(instr, emitter, routines) | |
30 | 38 | return label |
31 | 39 | |
32 | 40 | |
33 | def compile_instr(instr, generator, routines): | |
41 | def compile_instr(instr, emitter, routines): | |
34 | 42 | assert isinstance(instr, Instr) |
35 | 43 | opcode = instr.opcode |
36 | 44 | dest = instr.dest |
39 | 47 | if opcode == 'ld': |
40 | 48 | if dest == REG_A: |
41 | 49 | if isinstance(src, ConstantRef): |
42 | # LDA #... | |
43 | pass | |
50 | emitter.emit(LDA(Immediate(Byte(src.value)))) | |
44 | 51 | else: |
45 | # LDA abs | |
46 | pass | |
52 | emitter.emit(LDA(Absolute(src.label))) | |
47 | 53 | elif dest == REG_X: |
48 | 54 | pass |
49 | 55 | elif dest == REG_Y: |
50 | 56 | pass |
51 | 57 | else: |
52 | raise KeyError | |
58 | raise UnsupportedOpcodeError(instr) | |
53 | 59 | elif opcode == 'st': |
54 | if src == REG_A: | |
55 | # assert isinstance(dest, MemoryRef) | |
56 | # generate STA | |
57 | pass | |
60 | if dest == FLAG_C and src == ConstantRef(0): | |
61 | emitter.emit(CLC()) | |
62 | elif dest == FLAG_C and src == ConstantRef(1): | |
63 | emitter.emit(SEC()) | |
64 | elif src == REG_A: | |
65 | emitter.emit(STA(Absolute(dest.label))) | |
66 | elif src == REG_X: | |
67 | emitter.emit(STX(Absolute(dest.label))) | |
68 | elif src == REG_Y: | |
69 | emitter.emit(STY(Absolute(dest.label))) | |
58 | 70 | else: |
59 | raise KeyError | |
71 | raise UnsupportedOpcodeError(instr) | |
60 | 72 | elif opcode == 'add': |
61 | raise NotImplementedError | |
73 | if dest == REG_A: | |
74 | if isinstance(src, ConstantRef): | |
75 | emitter.emit(ADC(Immediate(Byte(src.value)))) | |
76 | else: | |
77 | emitter.emit(ADC(Absolute(src.label))) | |
78 | else: | |
79 | raise UnsupportedOpcodeError(instr) | |
62 | 80 | elif opcode == 'sub': |
63 | 81 | raise NotImplementedError |
64 | 82 | elif opcode == 'inc': |
0 | class Word(object): | |
0 | class Emittable(object): | |
1 | def size(self): | |
2 | """Default implementation may not be very efficient.""" | |
3 | return len(self.serialize()) | |
4 | ||
5 | def serialize(self): | |
6 | raise NotImplementedError | |
7 | ||
8 | ||
9 | class Byte(Emittable): | |
1 | 10 | def __init__(self, value): |
11 | if value < -127 or value > 255: | |
12 | raise IndexError(thing) | |
13 | if value < 0: | |
14 | value += 256 | |
15 | self.value = value | |
16 | ||
17 | def size(self): | |
18 | return 1 | |
19 | ||
20 | def serialize(self): | |
21 | return chr(self.value) | |
22 | ||
23 | def __repr__(self): | |
24 | return "%s(%r)" % (self.__class__.__name__, self.value) | |
25 | ||
26 | ||
27 | class Word(Emittable): | |
28 | def __init__(self, value): | |
29 | # TODO: range-checking | |
2 | 30 | self.value = value |
3 | 31 | |
4 | 32 | def size(self): |
10 | 38 | high = (word >> 8) & 255 |
11 | 39 | return chr(low) + chr(high) |
12 | 40 | |
41 | def __repr__(self): | |
42 | return "%s(%r)" % (self.__class__.__name__, self.value) | |
13 | 43 | |
14 | class Label(object): | |
44 | ||
45 | class Label(Emittable): | |
15 | 46 | def __init__(self, name, addr=None): |
16 | 47 | self.name = name |
17 | 48 | self.addr = addr |
23 | 54 | return 2 |
24 | 55 | |
25 | 56 | def serialize(self): |
26 | if self.addr is None: | |
27 | raise ValueError(self.addr) | |
57 | assert self.addr is not None, "unresolved label: %s" % self.name | |
28 | 58 | return Word(self.addr).serialize() |
29 | 59 | |
30 | 60 | |
34 | 64 | self.addr = addr |
35 | 65 | self.name_counter = 0 |
36 | 66 | |
37 | def gen(self, *things): | |
67 | def emit(self, *things): | |
38 | 68 | for thing in things: |
39 | 69 | if isinstance(thing, int): |
40 | if thing < -127 or thing > 255: | |
41 | raise ValueError(thing) | |
42 | if thing < 0: | |
43 | thing += 256 | |
44 | self.accum.append(thing) | |
45 | self.addr += 1 | |
46 | else: | |
47 | self.accum.append(thing) | |
48 | self.addr += thing.size() | |
70 | thing = Byte(thing) | |
71 | self.accum.append(thing) | |
72 | self.addr += thing.size() | |
49 | 73 | |
50 | 74 | def serialize(self, stream): |
51 | for thing in self.accum: | |
52 | if isintance(thing, int): | |
53 | stream.write(chr(thing)) | |
54 | else: | |
55 | stream.write(thing.serialize()) | |
75 | for emittable in self.accum: | |
76 | stream.write(emittable.serialize()) | |
56 | 77 | |
57 | 78 | def make_label(self, name=None): |
58 | 79 | if name is None: |
0 | 0 | """This is just a sketch for now.""" |
1 | 1 | |
2 | from sixtypical.emitter import Emitter, Word, Label | |
3 | ||
4 | ||
5 | class Generator(object): | |
6 | def __init__(self, emitter): | |
7 | self.emitter = emitter | |
8 | ||
9 | ### ld ### | |
10 | ||
11 | def gen_lda_imm(self, b): | |
12 | self.emitter.emit(0xa9, b) | |
13 | ||
14 | def gen_lda_abs(self, addr): | |
15 | self.emitter.emit(0xad, addr) | |
16 | ||
17 | def gen_ldx_imm(self, b): | |
18 | self.emitter.emit(0xa2, b) | |
19 | ||
20 | def gen_ldx_abs(self, addr): | |
21 | self.emitter.emit(0xae, addr) | |
22 | ||
23 | def gen_tax(self): | |
24 | self.emitter.emit(0xaa) | |
25 | ||
26 | def gen_tay(self): | |
27 | self.emitter.emit(0xa8) | |
28 | ||
29 | def gen_txa(self): | |
30 | self.emitter.emit(0x8a) | |
31 | ||
32 | def gen_tya(self): | |
33 | self.emitter.emit(0x98) | |
34 | ||
35 | ### st ### | |
36 | ||
37 | def gen_sta_abs(self, addr): | |
38 | self.emitter.emit(0x8d, addr) | |
39 | ||
40 | def gen_stx_abs(self, addr): | |
41 | self.emitter.emit(0x8e, addr) | |
42 | ||
43 | def gen_sty_abs(self, addr): | |
44 | self.emitter.emit(0x8c, addr) | |
45 | ||
46 | ### add ### | |
47 | ||
48 | def gen_adc_imm(self, b): | |
49 | self.emitter.emit(0x69, b) | |
50 | ||
51 | def gen_adc_abs(self, addr): | |
52 | self.emitter.emit(0x6d, addr) | |
53 | ||
54 | ### sub ### | |
55 | ||
56 | def gen_sbc_imm(self, b): | |
57 | self.emitter.emit(0xe9, b) | |
58 | ||
59 | def gen_sbc_abs(self, addr): | |
60 | self.emitter.emit(0xed, addr) | |
61 | ||
62 | ### inc ### | |
63 | ||
64 | def gen_inc_abs(self, addr): | |
65 | self.emitter.emit(0xee, addr) | |
66 | ||
67 | def gen_inx(self): | |
68 | self.emitter.emit(0xe8) | |
69 | ||
70 | def gen_iny(self): | |
71 | self.emitter.emit(0xc8) | |
72 | ||
73 | ### dec ### | |
74 | ||
75 | def gen_dec_abs(self, addr): | |
76 | self.emitter.emit(0xce, addr) | |
77 | ||
78 | def gen_dex(self): | |
79 | self.emitter.emit(0xca) | |
80 | ||
81 | def gen_dey(self): | |
82 | self.emitter.emit(0x88) | |
83 | ||
84 | ### and ### | |
85 | ||
86 | def gen_and_imm(self, b): | |
87 | self.emitter.emit(0x29, b) | |
88 | ||
89 | def gen_and_abs(self, addr): | |
90 | self.emitter.emit(0x2d, addr) | |
2 | from sixtypical.emitter import Emittable, Byte, Word, Label | |
3 | ||
4 | ||
5 | class AddressingMode(object): | |
6 | def size(self): | |
7 | """Size of the operand for the mode (not including the opcode)""" | |
8 | raise NotImplementedError | |
9 | ||
10 | ||
11 | class Implied(AddressingMode): | |
12 | def size(self): | |
13 | return 0 | |
14 | ||
15 | def serialize(self): | |
16 | return '' | |
17 | ||
18 | def __repr__(self): | |
19 | return "%s()" % (self.__class__.__name__) | |
20 | ||
21 | ||
22 | class Immediate(AddressingMode): | |
23 | def __init__(self, value): | |
24 | assert isinstance(value, Byte) | |
25 | self.value = value | |
26 | ||
27 | def size(self): | |
28 | return 1 | |
29 | ||
30 | def serialize(self): | |
31 | return self.value.serialize() | |
32 | ||
33 | def __repr__(self): | |
34 | return "%s(%r)" % (self.__class__.__name__, self.value) | |
35 | ||
36 | ||
37 | class Absolute(AddressingMode): | |
38 | def __init__(self, value): | |
39 | assert isinstance(value, (Word, Label)) | |
40 | self.value = value | |
41 | ||
42 | def size(self): | |
43 | return 2 | |
44 | ||
45 | def serialize(self): | |
46 | return self.value.serialize() | |
47 | ||
48 | def __repr__(self): | |
49 | return "%s(%r)" % (self.__class__.__name__, self.value) | |
50 | ||
51 | ||
52 | class Opcode(Emittable): | |
53 | def __init__(self, operand=None): | |
54 | self.operand = operand or Implied() | |
55 | ||
56 | def size(self): | |
57 | return 1 + self.operand.size() if self.operand else 0 | |
58 | ||
59 | def serialize(self): | |
60 | return ( | |
61 | chr(self.opcodes[self.operand.__class__]) + | |
62 | self.operand.serialize() | |
63 | ) | |
64 | ||
65 | def __repr__(self): | |
66 | return "%s(%r)" % (self.__class__.__name__, self.operand) | |
67 | ||
68 | ||
69 | class ADC(Opcode): | |
70 | opcodes = { | |
71 | Immediate: 0x69, | |
72 | Absolute: 0x6d, | |
73 | } | |
74 | ||
75 | ||
76 | class ADD(Opcode): | |
77 | opcodes = { | |
78 | Immediate: 0x29, | |
79 | Absolute: 0x2d, | |
80 | } | |
81 | ||
82 | ||
83 | class CLC(Opcode): | |
84 | opcodes = { | |
85 | Implied: 0x18 | |
86 | } | |
87 | ||
88 | ||
89 | class DEC(Opcode): | |
90 | opcodes = { | |
91 | Absolute: 0xce, | |
92 | } | |
93 | ||
94 | ||
95 | class DEX(Opcode): | |
96 | opcodes = { | |
97 | Implied: 0xca, | |
98 | } | |
99 | ||
100 | ||
101 | class DEY(Opcode): | |
102 | opcodes = { | |
103 | Implied: 0x88, | |
104 | } | |
105 | ||
106 | ||
107 | class INC(Opcode): | |
108 | opcodes = { | |
109 | Absolute: 0xee, | |
110 | } | |
111 | ||
112 | ||
113 | class INX(Opcode): | |
114 | opcodes = { | |
115 | Implied: 0xe8, | |
116 | } | |
117 | ||
118 | ||
119 | class INY(Opcode): | |
120 | opcodes = { | |
121 | Implied: 0xc8, | |
122 | } | |
123 | ||
124 | ||
125 | class LDA(Opcode): | |
126 | opcodes = { | |
127 | Immediate: 0xa9, | |
128 | Absolute: 0xad, | |
129 | } | |
130 | ||
131 | ||
132 | class LDX(Opcode): | |
133 | opcodes = { | |
134 | Immediate: 0xa2, | |
135 | Absolute: 0xae, | |
136 | } | |
137 | ||
138 | ||
139 | class LDY(Opcode): | |
140 | opcodes = { | |
141 | Immediate: 0xa0, | |
142 | Absolute: 0xac, | |
143 | } | |
144 | ||
145 | ||
146 | class ORA(Opcode): | |
147 | opcodes = { | |
148 | Immediate: 0x09, | |
149 | Absolute: 0x0d, | |
150 | } | |
151 | ||
152 | ||
153 | class RTS(Opcode): | |
154 | opcodes = { | |
155 | Implied: 0x60, | |
156 | } | |
157 | ||
158 | ||
159 | class SBC(Opcode): | |
160 | opcodes = { | |
161 | Immediate: 0xe9, | |
162 | Absolute: 0xed, | |
163 | } | |
164 | ||
165 | ||
166 | class SEC(Opcode): | |
167 | opcodes = { | |
168 | Implied: 0x38, | |
169 | } | |
170 | ||
171 | ||
172 | class STA(Opcode): | |
173 | opcodes = { | |
174 | Absolute: 0x8d, | |
175 | } | |
176 | ||
177 | ||
178 | class STX(Opcode): | |
179 | opcodes = { | |
180 | Absolute: 0x8e, | |
181 | } | |
182 | ||
183 | ||
184 | class STY(Opcode): | |
185 | opcodes = { | |
186 | Absolute: 0x8c, | |
187 | } | |
188 | ||
189 | ||
190 | class TAX(Opcode): | |
191 | opcodes = { | |
192 | Implied: 0xaa, | |
193 | } | |
194 | ||
195 | ||
196 | class TAY(Opcode): | |
197 | opcodes = { | |
198 | Implied: 0xa8, | |
199 | } | |
200 | ||
201 | ||
202 | class TXA(Opcode): | |
203 | opcodes = { | |
204 | Implied: 0x8a, | |
205 | } | |
206 | ||
207 | ||
208 | class TYA(Opcode): | |
209 | opcodes = { | |
210 | Implied: 0x98, | |
211 | } |