3 | 3 |
|
4 | 4 |
|
5 | 5 |
class Outputter(object):
|
6 | |
def __init__(self, output_format):
|
7 | |
self.output_format = output_format
|
8 | |
if output_format == 'raw':
|
9 | |
self.start_addr = 0x0000
|
10 | |
self.prelude = []
|
11 | |
elif output_format == 'prg':
|
12 | |
self.start_addr = 0xc000
|
13 | |
self.prelude = []
|
14 | |
elif output_format == 'c64-basic-prg':
|
15 | |
self.start_addr = 0x0801
|
16 | |
self.prelude = [0x10, 0x08, 0xc9, 0x07, 0x9e, 0x32,
|
17 | |
0x30, 0x36, 0x31, 0x00, 0x00, 0x00]
|
18 | |
elif output_format == 'vic20-basic-prg':
|
19 | |
self.start_addr = 0x1001
|
20 | |
self.prelude = [0x0b, 0x10, 0xc9, 0x07, 0x9e, 0x34,
|
21 | |
0x31, 0x30, 0x39, 0x00, 0x00, 0x00]
|
22 | |
elif output_format == 'atari2600-cart':
|
23 | |
self.start_addr = 0xf000
|
24 | |
self.prelude = [0x78, 0xd8, 0xa2, 0xff, 0x9a, 0xa9,
|
25 | |
0x00, 0x95, 0x00, 0xca, 0xd0, 0xfb]
|
26 | |
else:
|
27 | |
raise NotImplementedError("Unknown output format: {}".format(output_format))
|
|
6 |
def __init__(self, fh, start_addr=None):
|
|
7 |
self.start_addr = self.__class__.start_addr
|
|
8 |
if start_addr is not None:
|
|
9 |
self.start_addr = start_addr
|
|
10 |
self.prelude = self.__class__.prelude
|
|
11 |
self.fh = fh
|
|
12 |
self.emitter = Emitter(self.start_addr)
|
28 | 13 |
|
29 | |
def set_start_addr(self, start_addr):
|
30 | |
self.start_addr = start_addr
|
|
14 |
def write_header(self):
|
|
15 |
pass
|
31 | 16 |
|
32 | |
def write_prelude(self, fh):
|
|
17 |
def write_prelude(self):
|
|
18 |
self.write_header()
|
|
19 |
for byte in self.prelude:
|
|
20 |
self.emitter.emit(Byte(byte))
|
33 | 21 |
|
|
22 |
def write_postlude(self):
|
|
23 |
pass
|
|
24 |
|
|
25 |
|
|
26 |
class RawOutputter(Outputter):
|
|
27 |
start_addr = 0x0000
|
|
28 |
prelude = []
|
|
29 |
|
|
30 |
|
|
31 |
class PrgOutputter(Outputter):
|
|
32 |
start_addr = 0xc000
|
|
33 |
prelude = []
|
|
34 |
|
|
35 |
def write_header(self):
|
34 | 36 |
# If we are outputting a .PRG, we output the load address first.
|
35 | 37 |
# We don't use the Emitter for this b/c not part of addr space.
|
36 | |
if self.output_format in ('prg', 'c64-basic-prg', 'vic20-basic-prg'):
|
37 | |
fh.write(bytearray(Word(self.start_addr).serialize(0)))
|
|
38 |
self.fh.write(bytearray(Word(self.start_addr).serialize(0)))
|
38 | 39 |
|
39 | |
emitter = Emitter(self.start_addr)
|
40 | |
for byte in self.prelude:
|
41 | |
emitter.emit(Byte(byte))
|
42 | 40 |
|
43 | |
return emitter
|
|
41 |
class C64BasicPrgOutputter(PrgOutputter):
|
|
42 |
start_addr = 0x0801
|
|
43 |
prelude = [0x10, 0x08, 0xc9, 0x07, 0x9e, 0x32,
|
|
44 |
0x30, 0x36, 0x31, 0x00, 0x00, 0x00]
|
44 | 45 |
|
45 | |
def write_postlude(self, emitter):
|
|
46 |
|
|
47 |
class Vic20BasicPrgOutputter(PrgOutputter):
|
|
48 |
start_addr = 0x1001
|
|
49 |
prelude = [0x0b, 0x10, 0xc9, 0x07, 0x9e, 0x34,
|
|
50 |
0x31, 0x30, 0x39, 0x00, 0x00, 0x00]
|
|
51 |
|
|
52 |
|
|
53 |
class Atari2600CartOutputter(Outputter):
|
|
54 |
start_addr = 0xf000
|
|
55 |
prelude = [0x78, 0xd8, 0xa2, 0xff, 0x9a, 0xa9,
|
|
56 |
0x00, 0x95, 0x00, 0xca, 0xd0, 0xfb]
|
|
57 |
|
|
58 |
def write_postlude(self):
|
46 | 59 |
# If we are outputting a cartridge with boot and BRK address
|
47 | 60 |
# at the end, pad to ROM size minus 4 bytes, and emit addresses.
|
48 | |
if self.output_format == 'atari2600-cart':
|
49 | |
emitter.pad_to_size(4096 - 4)
|
50 | |
emitter.emit(Word(self.start_addr))
|
51 | |
emitter.emit(Word(self.start_addr))
|
|
61 |
self.emitter.pad_to_size(4096 - 4)
|
|
62 |
self.emitter.emit(Word(self.start_addr))
|
|
63 |
self.emitter.emit(Word(self.start_addr))
|
|
64 |
|
|
65 |
|
|
66 |
def outputter_class_for(output_format):
|
|
67 |
return {
|
|
68 |
'raw': RawOutputter,
|
|
69 |
'prg': PrgOutputter,
|
|
70 |
'c64-basic-prg': C64BasicPrgOutputter,
|
|
71 |
'vic20-basic-prg': Vic20BasicPrgOutputter,
|
|
72 |
'atari2600-cart': Atari2600CartOutputter,
|
|
73 |
}[output_format]
|