initial commit.

This commit is contained in:
Chris Burbridge 2014-08-29 22:48:33 +01:00
commit 52a3bb9ea9
30 changed files with 36874 additions and 0 deletions

42
README.md Normal file
View File

@ -0,0 +1,42 @@
## Z80 CPU Emulator
This is a Zilog Z80 CPU emulator, written in Python.
It runs a 1978 Microsoft Basic 4.7 ROM taken from [Grant Searle's Z80 SBC project][http://searle.hostei.com/grant/z80/SimpleZ80.html]
### Why?
Just for fun. I like the Z80 CPU - it was in many devices I played with as a
kid.
### Is it useful?
No. It runs really slowly, and is a completely non-optimal software design for
an emulator, but (in my opinion) the code is readable. If you want a CPU emulator,
probably don't use Python. That said, an optimised python coded emulator could run
a lot faster than this :-)
### Running
```
cd src
python z80sbc.py
```
Unit tests:
```
cd src
PYTHONPATH=`pwd`:$PYTHONPATH python ../tests/test_z80.py
PYTHONPATH=`pwd`:$PYTHONPATH python ../tests/test_registers.py
```
Fuse tests:
```
cd src
PYTHONPATH=`pwd`:$PYTHONPATH python ../fuse_tests/tests.py
```
### Missing and todo
Most undocumented opcodes, undocumented flags for `CPI` and `CPIR`.
### Credits
[Grant Searle's Z80 SBC project][http://searle.hostei.com/grant/z80/SimpleZ80.html]
[FUSE - Free Unix Spectrum Emulator][http://fuse-emulator.sourceforge.net/] for the instruction set tests
### License
Public domain; do what the like. (Except fuse tests and BASIC rom)

73
fuse_tests/README Normal file
View File

@ -0,0 +1,73 @@
File formats
============
tests.in
--------
Each test has the format:
<arbitrary test description>
AF BC DE HL AF' BC' DE' HL' IX IY SP PC
I R IFF1 IFF2 IM <halted> <tstates>
<halted> specifies whether the Z80 is halted.
<tstates> specifies the number of tstates to run the test for, in
decimal; the number actually executed may be higher, as the final
instruction is allowed to complete.
Then followed by lines specifying the initial memory setup. Each has
the format:
<start address> <byte1> <byte2> ... -1
eg
1234 56 78 9a -1
says to put 0x56 at 0x1234, 0x78 at 0x1235 and 0x9a at 0x1236.
Finally, -1 to end the test. Blank lines may follow before the next test.
tests.expected
--------------
Each test output starts with the test description, followed by a list
of 'events': each has the format
<time> <type> <address> <data>
<time> is simply the time at which the event occurs.
<type> is one of MR (memory read), MW (memory write), MC (memory
contend), PR (port read), PW (port write) or PC (port contend).
<address> is the address (or IO port) affected.
<data> is the byte written or read. Missing for contentions.
After that, lines specifying AF, BC etc as for .in files. <tstates>
now specifies the final time.
After that, lines specifying which bits of memory have changed since
the initial setup. Same format as for .in files.
Why some specific tests are here
================================
37_{1,2,3}: check the behaviour of SCF with respect to bits 3 and 5
(bug fixed on 20040225).
cb{4,5,6,7}{7,f}_1: designed to check that bits 3 and 5 are copied to
F only for BIT 3,<arg> and BIT 5,<arg> respectively
(bug fixed on 20040225).
However, later research has revealed the bits 3
and 5 are copied on all BIT instructions, l.
tests are now essentially redundant.
d{3,b}_{1,2,3}: check for correct port contention on IO in the four
relevant states (port high byte in 0x40 to 0x7f or not,
port low bit set or reset).
dd00.in, ddfd00.in: test timings of "extended NOP" opcodes DD 00 and
DD FD 00; the extra 00 at the end is to check the
next opcode executes at the right time (bug fixed
on 20060722).

18395
fuse_tests/tests.expected Normal file

File diff suppressed because it is too large Load Diff

9011
fuse_tests/tests.in Normal file

File diff suppressed because it is too large Load Diff

267
fuse_tests/tests.py Normal file
View File

@ -0,0 +1,267 @@
from z80 import io, gui, instructions, registers, util
import copy
from time import sleep, time
import sys
from PySide.QtCore import *
from PySide.QtGui import *
import threading
import os
import inspect
#logging.basicConfig(level=logging.INFO)
class Z80Tester(io.Interruptable):
def __init__(self):
self.registers = registers.Registers()
self.instructions = instructions.InstructionSet(self.registers)
self._memory = bytearray(64*1024)
self._interrupted = False
def interrupt(self):
self._interrupted = True
def step_instruction(self):
trace = ""
ins, args = False, []
pc = self.registers.PC
if self._interrupted and self.registers.IFF:
self.registers.IFF = False
self._interrupted = False
if self.registers.IM == 1:
print "!!! Interrupt !!!"
ins, args = self.instructions << 0xCD
ins, args = self.instructions << 0x38
ins, args = self.instructions << 0x00
self.registers.IFF = False
else:
while not ins:
try:
ins, args = self.instructions << self._memory[self.registers.PC]
except:
raise Exception("Can't decode instruction.")
self.registers.PC = util.inc16(self.registers.PC)
trace += "{0:X} : {1}\n ".format(pc, ins.assembler(args))
rd = ins.get_read_list(args)
data = [0] * len(rd)
for n, i in enumerate(rd):
if i < 0x10000:
data[n] = self._memory[i]
else:
address = i & 0xFF
#data[n] = self._iomap.address[address].read(address)
data[n] = self.registers.A
print "Read IO ",
raise Exception("Skip.")
wrt = ins.execute(data, args)
for i in wrt:
if i[0] > 0x10000:
address = i[0] & 0xFF
#iomap.address[address].write.emit(address, i[1])
#self._iomap.address[address].write(address, i[1])
#print (chr(i[1]))
print "Write IO ",
raise Exception("Skip.")
else:
try:
self._memory[i[0]] = i[1]
except:
print i
print trace
raise
return ins.tstates, trace
if __name__ == '__main__':
''' Main Program '''
mach = Z80Tester()
infile = file = os.path.join(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))),
"tests.in")
expectfile = file = os.path.join(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))),
"tests.expected")
with open(infile, "r") as f:
tests_in = f.read()
with open(expectfile, "r") as f:
tests_expected = f.read()
fails = passes = 0
for t, results in zip(tests_in.split("\n\n"), tests_expected.split("\n\n")):
#print "---\n", t, "\n====\n", results,"\n---\n"
test_lines = t.split("\n")
test_key = test_lines[0]
regs = [int(s, 16) for s in test_lines[1].split()]
mach.registers.AF = regs[0]
mach.registers.BC = regs[1]
mach.registers.DE = regs[2]
mach.registers.HL = regs[3]
mach.registers.A_ = regs[4] >> 8
mach.registers.F_ = regs[4] & 0xFF
mach.registers.B_ = regs[5] >> 8
mach.registers.C_ = regs[5] & 0xFF
mach.registers.D_ = regs[6] >> 8
mach.registers.E_ = regs[6] & 0xFF
mach.registers.H_ = regs[7] >> 8
mach.registers.L_ = regs[7] & 0xFF
mach.registers.IX = regs[8]
mach.registers.IY = regs[9]
mach.registers.SP = regs[10]
mach.registers.PC = regs[11]
regs2 = [s for s in test_lines[2].split()]
mach.registers.I = int(regs2[0], 16)
mach.registers.R = int(regs2[1], 16)
mach.registers.IFF = regs2[2] == "1"
mach.registers.IFF2 = regs2[3] == "1"
mach.registers.IFF2 = regs2[3] == "1"
mach.registers.IM = regs2[4] == "1"
mach.registers.HALT = regs2[5] == "1"
tstates = int(regs2[6])
for memline in test_lines[3:]:
memsplit = memline.split()
base = int(memsplit[0], 16)
for val in memsplit[1:-1]:
if int(val, 16) == -1:
continue
mach._memory[base] = int(val, 16)
base += 1
print ": Test '%s' : "%(str(test_key)),
if test_key.startswith("27"):
print "SKIPPED"
continue
trace = ""
taken= 0
try:
while taken < tstates:
states, asm = mach.step_instruction()
taken += states
trace += "%d/%d\t%d\t" % (taken, tstates, states) + asm
except Exception, e:
if e.message == "Can't decode instruction.":
print " - NO INSTRUCTION"
mach.instructions.reset_composer()
continue
elif e.message == "Skip.":
print "Skipped."
mach.instructions.reset_composer()
continue
else:
print "FAULTY"
mach.instructions.reset_composer()
raise
expected_lines = results.split('\n')
if expected_lines[0] != test_key:
print "Test expectation mismatch"
sys.exit(1)
i = 1
while expected_lines[i].startswith(" "):
i += 1
regs = [int(s, 16) for s in expected_lines[i].split()]
try:
if mach.registers.A != regs[0] >> 8:
raise Exception("Bad A register")
if mach.registers.BC != regs[1]:
raise Exception("Bad register")
if mach.registers.DE != regs[2]:
raise Exception("Bad register")
if mach.registers.HL != regs[3]:
raise Exception("Bad register")
if mach.registers.A_ != regs[4] >> 8:
raise Exception("Bad register")
if mach.registers.F_ != regs[4] & 0xFF:
raise Exception("Bad register")
if mach.registers.B_ != regs[5] >> 8:
raise Exception("Bad register")
if mach.registers.C_ != regs[5] & 0xFF:
raise Exception("Bad register")
if mach.registers.D_ != regs[6] >> 8:
raise Exception("Bad register")
if mach.registers.E_ != regs[6] & 0xFF:
raise Exception("Bad register")
if mach.registers.H_ != regs[7] >> 8:
raise Exception("Bad register")
if mach.registers.L_ != regs[7] & 0xFF:
raise Exception("Bad register")
if mach.registers.IX != regs[8]:
raise Exception("Bad register")
if mach.registers.IY != regs[9]:
raise Exception("Bad register")
if mach.registers.SP != regs[10]:
raise Exception("Bad register")
if mach.registers.PC != regs[11]:
raise Exception("Bad register")
regs2 = [s for s in expected_lines[i+1].split()]
if mach.registers.I != int(regs2[0], 16):
raise Exception("Bad register")
#if mach.registers.R != regs2[1]:
#raise Exception("Bad register")
if mach.registers.IFF != (regs2[2] == "1"):
print "Bad interrups flag flop"
print regs2[2]
print mach.registers.IFF
raise Exception("Bad register")
if mach.registers.IFF2 != (regs2[3] == "1"):
print "Bad interrups flag flop"
print regs2[3]
print mach.registers.IFF2
raise Exception("Bad register")
#if mach.registers.IFF2 != (regs2[3] == "1"):
#raise Exception("Bad register")
if mach.registers.IM != int(regs2[4]):
raise Exception("Bad register")
if mach.registers.HALT != (regs2[5] == "1"):
raise Exception("Bad HALT register. "+str(mach.registers.HALT)+"!="+ str(regs2[5]=='1'))
if taken != int(regs2[6]):
raise Exception("Bad number of tstates taken.")
if mach.registers.F != regs[0] & 0xFF:
raise Exception("Bad F register")
for memline in expected_lines[i+3:]:
memsplit = memline.split()
base = int(memsplit[0], 16)
for val in memsplit[1:-1]:
if int(val, 16) == -1:
continue
if mach._memory[base] != int(val, 16):
raise Exception("Memory mismatch")
base += 1
except Exception, e:
print "FAILED:",e.message
fails += 1
continue
print "TRACE:"
print trace
print
flags = ["S", "Z", "F5", "H", "F3", "PV", "N", "C"]
s = ""
for i, f in enumerate(flags):
s += f+':' + str((regs[0] >> (7 - i)) & 0x01) + ' '
print "\nTarget flags: ", s
s = ""
for i, f in enumerate(flags):
s += f+':' + str((mach.registers.F >> (7 - i)) & 0x01) + ' '
print "Actual flags: ", s
print
print "--INITIAL--\n", t, "\n--TARGET--\n", results,"\n==--==\n"
regs = ['PC', 'SP', 'I',
'A', 'F', 'B', 'C',
'D', 'E', 'H', 'L',
'IFF']
regsr = ['IX', 'IY', 'R','A_', 'F_', 'B_', 'C_','D_', 'E_','H_', 'L_', 'IM']
print "Registers:"
for rl, rr in zip(regs, regsr):
print rl, ": {0:X}".format( mach.registers[rl]), "\t\t", rr, ": {0:X}".format( mach.registers[rr])
raise
print "PASSED"
passes += 1
print "Failed:", fails
print "Passed:", passes

304
roms/BASIC.HEX Normal file
View File

@ -0,0 +1,304 @@
:18015000C35601C3F401DD210000C36101070A7D11214520F9C39C1D08
:18016800112E0406632145201A77231305C27001F9CD2F06CDFD0B324C
:18018000EF20323E21214302CD9B12CD4C06CD5509B7C2AA0121A22195
:18019800237CB5CABC017E472F77BE70CA9801C3BC01CD210AB7C2FD8A
:1801B00004EB2B3ED94677BE70C285012B11A121CDC507DA850111CEFD
:1801C800FF22F42019229F20CD0A062A9F2011EFFF19113E217D936F23
:1801E0007C9A67E5210C02CD9B12E1CD3E1921FD01CD9B1231AB20CD95
:1801F8002F06C3480520427974657320667265650D0A00005A383020C8
:1802100042415349432056657220342E37620D0A436F707972696768B0
:1802280074202843292031393738206279204D6963726F736F66740DBF
:180240000A00004D656D6F727920746F7000B3177718C91748205B11A3
:18025800E01489113D1A1C1B58168B1A911B971BF81B0D1C3415781CE8
:1802700096200D142512A7141C142D149A1C2D1D3D146D147714C54ECC
:1802880044C64F52CE455854C4415441C94E505554C4494DD245414454
:1802A000CC4554C74F544FD2554EC946D24553544F5245C74F53554200
:1802B800D2455455524ED2454DD3544F50CF5554CF4ECE554C4CD7413C
:1802D0004954C44546D04F4B45C44F4B45D3435245454ECC494E45539D
:1802E800C34C53D749445448CD4F4E49544F52D34554D245534554D0B5
:1803000052494E54C34F4E54CC495354C34C454152C34C4F4144C35358
:18031800415645CE4557D4414228D44FC64ED3504328D448454ECE4F77
:1803300054D3544550ABADAAAFDEC14E44CF52BEBDBCD3474EC94E5498
:18034800C14253D55352C65245C94E50D04F53D35152D24E44CC4F475B
:18036000C55850C34F53D3494ED4414EC1544ED045454BC445454BD075
:180378004F494E54CC454ED3545224D6414CC15343C3485224C8455897
:1803900024C2494E24CC45465424D24947485424CD494424809F099C81
:1803A80008770DEC0A7E0CB30FAD0C030BA90A8C0A7B0B6509980AC702
:1803C0000AEE0A9D09EC145D0BDE09F21491113B15831CEE0A691C5CBE
:1803D8001C611C991D99209C209F0BCB091108460AEE0AEE0A090679EA
:1803F00025197959157C97167CF8167F461A500C0F460B0F4E46534E3E
:1804080052474F4446434F564F4D554C425344442F304944544D4F53F9
:180420004C535354434E55464D4F4858424EC3F401C31C0AD300C9D673
:18043800006F7CDE006778DE00473E00C9000000354ACA99391C769893
:180450002295B3980ADD479853D199990A1A9F9865BCCD98D6773E9872
:1804680052C74F80DB00C901FF1C00001400140000000000C34207C3DD
:180480000000C30000C30000A221FEFF3F21204572726F720020696E9D
:1804980020004F6B0D0A0000427265616B00210400397E23FE81C04EEA
:1804B000234623E569607AB3EBCAC004EBCDC507010D00E1C809C3AAA3
:1804C80004CDE304C5E3C1CDC5077E02C80B2BC3CF04E52A1F210600F9
:1804E00009093EE53ED0956F3EFF9CDAF2046739E1D81E0CC311052A8E
:1804F8000E2122A1201E02011E14011E00011E12011E22011E0A011EAE
:1805100018CD2F06328A20CDF00B210404573E3FCDD607197ECDD6072D
:18052800CD5509CDD607218E04CD9B122AA12011FEFFCDC507CA6101FB
:180540007CA53CC436193EC1AF328A20CDF00B219A04CD9B1221FFFF89
:1805580022A120CD4207DA5505CD55093C3DCA5505F5CD210AD5CD59AE
:180570000647D1F1D23509D5C5AF321121CD5509B7F5CDE905DA8E05A8
:18058800F1F5CAC20AB7C5D2A505EB2A1B211A020313CDC507C296056E
:1805A0006069221B21D1F1CACC052A1B21E3C109E5CDC904E1221B21EE
:1805B800EB74D123237323722311A6201A772313B7C2C405CD1506239F
:1805D000EB626B7E23B6CA5505232323AFBE23C2DD05EB732372C3D1BC
:1805E800052AA320444D7E23B62BC823237E23666FCDC50760697E236F
:18060000666F3FC83FD0C3EC05C02AA320AF77237723221B212AA32068
:180618002B2213212AF420220821AFCD65092A1B21221D21221F21C1ED
:180630002A9F20F921F82022F620AF6F67221921321021222321E5C50B
:180648002A1321C93E3FCDD6073E20CDD607C39320AF32F3200E0511B6
:18066000A6207EFE20CAE10647FE22CA0107B7CA08073AF320B77EC262
:18067800E106FE3F3E9ECAE1067EFE30DA8C06FE3CDAE106D511850239
:18069000C501DD06C5067F7EFE61DAA506FE7BD2A506E65F774EEB23EF
:1806A800B6F2A706047EE67FC8B9C2A706EBE5131AB7FAD9064F78FEBC
:1806C00088C2C806CD55092B237EFE61DAD106E65FB9CAB706E1C3A535
:1806D8000648F1EBC9EB79C1D12312130CD63ACAEF06FE49C2F20632CB
:1806F000F320D654C26206477EB7CA0807B8CAE10623120C13C3F806B8
:1807080021A5201213121312C93A8920B73E00328920C2250705CA421C
:1807200007CDD6073E052BCA39077ECDD607C34B07052BCDD607C24B74
:1807380007CDD607CDFD0BC3420721A6200601AF328920CD00084FFE7D
:180750007FCA11073A8920B7CA64073E00CDD607AF32892079FE07CAA7
:18076800A807FE03CCFD0B37C8FE0DCAF80BFE15CA3C07FE40CA3907B6
:18078000FE5FCA3107FE08CA3107FE12C2A307C5D5E53600CDAD1D2111
:18079800A620CD9B12E1D1C1C34B07FE20DA4B0778FE493E07D2BD079D
:1807B00079713211212304CDD607C34B07CDD6073E08C3B7077C92C0BE
:1807C8007D93C97EE3BE23E3CA5509C3FD04F53A8A20B7C2D012F1C545
:1807E000F5FE20DAFA073A8720473AF02004CAF60705B8CCFD0B3C32D7
:1807F800F020F1C1CD961DC9CD5A1CE67FFE0FC03A8A202F328A20AFCB
:18081000C9CD210AC0C1CDE905C5CD6708E14E23462378B1CA4805CD0A
:180828007008CD8009C5CDFD0B5E235623E5EBCD3E193E20E1CDD60779
:180840007EB723CA1D08F23D08D67F4F1186021A13B7F24F080DC24F9A
:1808580008E67FCDD6071A13B7F25908C34008E52A8D20228B20E1C9FC
:18087000E5D52A8B2011FFFFED5A228B20D1E1F0E52A8D20228B20CDC6
:180888005A1CFE03CA9308E1C370082A8D20228B20C3F7013E6432101D
:1808A00021CD030BC1E5CDEC0A220C2121020039CDAA04D1C2CC080945
:1808B800D52B562B5E2323E52A0C21CDC507E1C2B008D1F9EB0E08CD3B
:1808D000DA04E52A0C21E3E52AA120E3CDC50DCDCB07A6CDC20DE5CD2E
:1808E800F017E1C5D5010081515A7EFEAB3E01C20809CD5509CDC20D49
:18090000E5CDF017CDA417E1C5D5F533E52A1321E30681C533CD800900
:180918002213217EFE3ACA3509B7C2FD04237E23B6CAA709235E23564B
:18093000EB22A120EBCD5509111509D5C8D680DA030BFE25D2FD0407C4
:180948004F0600EB21A503094E2346C5EB237EFE3AD0FE20CA5509FE31
:18096000303F3C3DC9EB2AA320CA7A09EBCD210AE5CDE9056069D1D2BA
:18097800C20A2B222121EBC9DFC8D7FE1B2811FE03280DFE13C0D7FEAC
:1809900011C8FE03280718F63EFF329220C0F6C022132121F6FFC12A4A
:1809A800A120F57DA43CCABA092217212A1321221921AF328A20CDF03B
:1809C0000BF121A004C23105C348052A19217CB51E20CA1105EB2A1777
:1809D8002122A120EBC9CD2315C0328620C9E52A8F2006004F09228F1C
:1809F00020E1C97EFE41D8FE5B3FC9CD5509CDC20DCDA417FA1C0A3A86
:180A08002C21FE90DA4C18018090110000E5CD1F18E151C81E08C311BE
:180A2000052B110000CD5509D0E5F5219819CDC507DAFD04626B192953
:180A38001929F1D6305F160019EBE1C3250ACA1906CDFE092BCD55090E
:180A5000E52AF420CA690AE1CDCB072CD5CDFE092BCD5509C2FD04E3DD
:180A6800EB7D935F7C9A57DAF204E52A1B2101280009CDC507D2F20401
:180A8000EB229F20E122F420E1C31906CA1506CD1906011509C3A80A53
:180A98000E03CDDA04C1E5E52AA120E33E8CF533C5CD210ACDEE0AE5D8
:180AB0002AA120CDC507E123DCEC05D4E90560692BD81E0EC31105C086
:180AC80016FFCDA604F9FE8C1E04C21105E122A120237CB5C2E60A3A09
:180AE0001121B7C24705211509E33EE1013A0E0006007948477EB7C872
:180AF800B8C823FE22CAF20AC3F50ACDB80FCDCB07B4D53AF220F5CDD1
:180B1000D40DF1E32213211FCDC70DCA560BE52A2921E523235E23567C
:180B28002AA320CDC507D2450B2A9F20CDC507D1D24D0B210421CDC5B8
:180B400007D24D0B3ED1CDFC13EBCD3512CDFC13E1CDFF17E1C9E5CD86
:180B5800FC17D1E1C9CD23157E47FE8CCA6C0BCDCB07882B4B0D78CA76
:180B70003D09CD220AFE2CC0C36D0BCDD40D7EFE88CA890BCDCB07A9B1
:180B88002BCDC50DCDA417CAEE0ACD5509DAA90AC33C092BCD5509CA61
:180BA000FD0BC8FEA5CA300CFEA8CA300CE5FE2CCA190CFE3BCA530CB8
:180BB800C1CDD40DE53AF220B7C2E90BCD4919CD591236202A292134B3
:180BD0002A29213A87204704CAE50B043AF020863DB8D4FD0BCD9E1291
:180BE800AFC49E12E1C39B0B3AF020B7C8C3FD0B360021A5203E0DCDC0
:180C0000D6073E0ACDD607AF32F0203A86203DC8F5AFCDD607F1C30E27
:180C18000C3A8820473AF020B8D4FD0BD2530CD60ED2270C2FC3480C51
:180C3000F5CD2015CDCB07292BF1D6A8E5CA430C3AF0202F83D2530C28
:180C48003C473E20CDD60705C24C0CE1CD5509C3A20B3F5265646F2085
:180C600066726F6D2073746172740D0A003A1221B7C2F704C1215A0C3A
:180C7800CD9B12C34806CD06127EFE223E00328A20C2980CCD5A12CDD0
:180C9000CB073BE5CD9E123EE5CD4C06C1DAA409237EB72BC5CAEB0A4C
:180CA800362CC3B20CE52A2121F6AF321221E3C3BE0CCDCB072CCDB836
:180CC0000FE3D57EFE2CCAE60C3A1221B7C2530D3E3FCDD607CD4C0665
:180CD800D1C1DAA409237EB72BC5CAEB0AD53AF220B7CA100DCD5509FA
:180CF0005747FE22CA040D3A1221B757CA010D163A062C2BCD5D12EB2C
:180D0800211B0DE3D5C31E0BCD5509CDAB18E3CDFC17E12BCD5509CA67
:180D2000270DFE2CC26D0CE32BCD5509C2BA0CD13A1221B7EBC27B093B
:180D3800D5B621420DC49B12E1C93F45787472612069676E6F72656442
:180D50000D0A00CDEC0AB7C26C0D237E23B61E06CA1105235E2356EB5C
:180D6800220E21EBCD5509FE83C2530DC3E60C110000C4B80F221321C2
:180D8000CDA604C20305F9D57E23F5D5CDE217E3E5CD4F15E1CDFC1761
:180D9800E1CDF317E5CD1F18E1C190CDF317CAB20DEB22A1206960C3B6
:180DB0001109F92A13217EFE2CC21509CD5509CD7A0DCDD40DF6373A9E
:180DC800F2208FB7E8C30F05CDCB07282B1600D50E01CDDA04CD4B0E3F
:180DE0002215212A1521C178FE78D4C50D7E1600D6B3DA0C0EFE03D20A
:180DF8000C0EFE0117AABA57DAFD04220A21CD5509C3F00D7AB7C233BF
:180E10000F7E220A21D6ACD8FE07D05F3AF2203DB37BCA911307835F54
:180E280021EF03197856BAD023CDC50DC501E30DC5434ACDD517585102
:180E40004E234623C52A0A21C3D70DAF32F220CD55091E24CA1105DAE5
:180E5800AB18CDF309D2B20EFE262012CD5509FE48CAEF1CFE42CA5F5F
:180E70001D1E02CA1105FEACCA4B0EFE2ECAAB18FEADCAA10EFE22CAB9
:180E88005A12FEAACA930FFEA7CABE11D6B6D2C30ECDD00DCDCB0729F3
:180EA000C9167DCDD70D2A1521E5CDCD17CDC50DE1C9CDB80FE5EB2268
:180EB80029213AF220B7CCE217E1C90600074FC5CD550979FE31DAEAAE
:180ED0000ECDD00DCDCB072CCDC60DEB2A2921E3E5EBCD2315EBE3C33F
:180EE800F20ECD990EE311AD0ED5014E02094E236669E915FEADC8FEF1
:180F00002DC814FE2BC8FEACC82BC9F6AFF5CDC50DCD070AF1EBC1E3E2
:180F1800EBCDE517F5CD070AF1C179217C11C22E0FA34F78A2E9B34F6B
:180F300078B2E921450F3AF2201F7A175F166478BAD0C3340E470F7976
:180F4800B71FC1D1F5CDC70D21890FE5CA1F18AF32F220D5CDDE137EF0
:180F600023234E2346D1C5F5CDE213CDF317F157E17BB2C87AD601D811
:180F7800AFBB3CD0151D0ABE2303CA710F3FC3AF173C8FC1A0C6FF9F29
:180F9000C3B617165ACDD70DCDC50DCD070A7B2F4F7A2FCD7C11C1C39B
:180FA800E30D2BCD5509C8CDCB072C01AA0FC5F6AF32F12046CDF309E2
:180FC000DAFD04AF4F32F220CD5509DAD40FCDF309DAE10F4FCD550907
:180FD800DAD50FCDF309D2D50FD624C2F00F3C32F2200F814FCD55097F
:180FF0003A10213DCA9D10F200107ED628CA7510AF321021E550592A33
:181008002321CDC507112521CAE5162A1D21EB2A1B21CDC507CA331078
:18102000799623C22810789623CA671023232323C31A10E1E3D511B542
:181038000ECDC507D1CA6A10E3E5C50106002A1F21E509C1E5CDC904B8
:18105000E1221F216069221D212B3600CDC507C25910D173237223EB10
:18106800E1C9322C21219904222921E1C9E52AF120E357D5C5CDFB09AE
:18108000C1F1EBE3E5EB3C577EFE2CCA7B10CDCB0729221521E122F164
:18109800201E00D511E5F52A1D213E19EB2A1F21EBCDC507CAD5107E7D
:1810B000B923C2B7107EB8235E235623C2A3103AF120B7C20605F144F7
:1810C8004DCAE51696CA33111E10C31105110400F1CA1C0A7123702336
:1810E0004FCDDA042323220A2171233AF1201779010B00D2F810C10352
:1810F80071237023F5E5CD9018EBE1F13DC2F010F5424BEB19DAF20458
:18111000CDE304221F212B3600CDC507C2161103572A0A215EEB2909A4
:18112800EB2B2B73237223F1DA5711474F7E2316E15E235623E3F5CD43
:18114000C507D2D010E5CD9018D119F13D444DC238112929C109EB2ADA
:181158001521C92A1F21EB210000393AF220B7CA7711CDDE13CDDE1201
:181170002A9F20EB2A08217D934F7C9A41501E0021F220730690C3BB62
:18118800173AF02047AFC37D11CD1412CD061201EC0AC5D5CDCB072877
:1811A000CDB80FE5EB2B562B5EE1CDC50DCDCB0729CDCB07B4444DE3BA
:1811B800712370C35312CD1412D5CD990ECDC50DE35E2356237AB3CA44
:1811D00009057E23666FE52A2321E32223212A2721E52A2521E52125F5
:1811E80021D5CDFC17E1CDC20D2BCD5509C2FD04E1222521E1222721EF
:18120000E1222321E1C9E52AA120237CB5E1C01E16C31105CDCB07A7CD
:181218003E80321021B647CDBD0FC3C50DCDC50DCD4919CD5912CDDEC1
:1812300013013914C57E2323E5CDB412E14E2346CD4D12E56FCDD1137B
:18124800D1C9CDB412210421E5772323732372E1C92B062250E50EFF32
:18126000237E0CB7CA6F12BACA6F12B8C26012FE22CC5509E323EB7922
:18127800CD4D121104212AF6202229213E0132F220CDFF17CDC507222F
:18129000F620E17EC01E1EC3110523CD5912CDDE13CDF3171C1DC80A01
:1812A800CDD607FE0DCC070C03C3A512B70EF1F52A9F20EB2A08212F1C
:1812C0004F06FF0923CDC507DAD21222082123EBF1C9F11E1ACA110523
:1812D800BFF501B612C52AF420220821210000E52A9F20E521F820EB3B
:1812F0002AF620EBCDC50701EF12C243132A1B21EB2A1D21EBCDC507CB
:18130800CA16137E2323B7CD4613C30013C1EB2A1F21EBCDC507CA6C93
:1813200013CDF3177BE509B7F21513220A21E14E0600090923EB2A0ABB
:1813380021EBCDC507CA1613013513C5F6807E23235E235623F0B7C854
:18135000444D2A0821CDC5076069D8E1E3CDC507E3E56069D0C1F1F106
:18136800E5D5C5C9D1E17DB4C82B462B4EE52B2B6E26000950592B44A0
:181380004D2A0821CDCC04E171237069602BC3E112C5E52A2921E3CDBB
:181398004B0EE3CDC60D7EE52A2921E5861E1CDA1105CD4A12D1CDE24C
:1813B00013E3CDE113E52A0621EBCDC813CDC81321E00DE3E5C37B12D7
:1813C800E1E37E23234E23466F2C2DC80A120313C3D213CDC60D2A2971
:1813E00021EBCDFC13EBC0D550591B4E2A0821CDC507C2FA134709224E
:1813F8000821E1C92AF6202B462B4E2B2BCDC507C022F620C9018C1192
:18141000C5CDDB13AF5732F2207EB7C9018C11C5CD1114CA1C0A232371
:181428005E23561AC93E01CD4A12CD26152A062173C1C37B12CDD614F6
:18144000AFE34FE57EB8DA4B1478110E00C5CDB412C1E1E5232346233A
:181458006668060009444DCD4D126FCDD113D1CDE213C37B12CDD61428
:18147000D1D51A90C34114EB7ECDDB140405CA1C0AC51EFFFE29CA907B
:1814880014CDCB072CCD2315CDCB0729F1E3014314C53DBE0600D04F8F
:1814A0007E91BB47D843C9CD1114CAC4155F23237E23666FE5194672D9
:1814B800E3C57EFE24C2C514CDEF1C180DFE25C2CF14CD5F1D1803CD43
:1814D000AB18C1E170C9EBCDCB0729C1D1C543C9CD2615328420CD8322
:1814E80020C38C11CD1015C34B20CD1015F51E002BCD5509CA0615CD3F
:18150000CB072CCD2315C1CD8320ABA0CA0715C9CD2315328420324C4C
:1815180020CDCB072CC32315CD5509CDC20DCD010A7AB7C21C0A2BCD25
:1815300055097BC9CD070A1AC38C11CDC20DCD070AD5CDCB072CCD239F
:1815480015D112C921221ACDF317C35E15CDF31721C1D1CDCD1778B7F6
:18156000C83A2C21B7CAE51790D278152F3CEBCDD517EBCDE517C1D163
:18157800FE19D0F5CD0A1867F1CD2316B4212921F29E15CD0316D2E4D2
:18159000152334CA0C052E01CD3916C3E415AF90477E9B5F237E9A5765
:1815A800237E994FDC0F166863AF4779B7C2D1154A54656F78D608FE42
:1815C000E0C2B215AF322C21C905297A1757798F4FF2C915785C45B7A6
:1815D800CAE415212C218677D2C415C878212C21B7FCF61546237EE6E9
:1815F00080A94FC3E5171CC014C00CC00E8034C0C30C057E835F237ED9
:181608008A57237E894FC9212D217E2F77AF6F90477D9B5F7D9A577DBD
:18162000994FC90600D608DA3216435A510E00C32516C6096FAF2DC81F
:18163800791F4F7A1F577B1F5F781F47C335160000008103AA561980C1
:18165000F122768045AA3882CDA417B7EA1C0A212C217E01358011F3DB
:181668000490F570D5C5CD5E15C1D104CDFA16214716CD5515214B16ED
:18168000CDEC1A018080110000CD5E15F1CD1F1901318011187221C108
:18169800D1CDA417C82E00CD621779323B21EB223C210100005058216A
:1816B000AF15E521BB16E5E52129217E23B7CAE716E52E081F6779D247
:1816C800D516E52A3C2119EBE13A3B21891F4F7A1F577B1F5F781F477A
:1816E0002D7CC2C416E1C9435A514FC9CDD517012084110000CDE517C5
:1816F800C1D1CDA417CA00052EFFCD621734342B7E3257202B7E325396
:18171000202B7E324F2041EBAF4F575F325A20E5C57DCD4E20DE003F4C
:18172800D23217325A20F1F137D2C1E1793C3D1FFAE515177B175F7ACE
:18174000175779174F297817473A5A2017325A2079B2B3C21F17E521F2
:181758002C2135E1C21F17C30C0578B7CA86177D212C21AE80471FA88D
:1817700078F28517C68077CAE516CD0A18772BC9CDA4172FE1B7E1F25D
:18178800C415C30C05CDF01778B7C8C602DA0C0547CD5E15212C2134F5
:1817A000C0C30C053A2C21B7C83A2B21FE2F179FC03CC9CDA417068853
:1817B800110000212C214F70060023368017C3AC15CDA417F0212B217C
:1817D0007EEE8077C9EB2A2921E3E52A2B21E3E5EBC9CDF317EB2229AF
:1817E800216069222B21EBC92129215E2356234E234623C91129210674
:18180000041A77132305C20118C9212B217E07371F773F1F2323777909
:1818180007371F4F1FAEC978B7CAA41721AD17E5CDA41779C8212B21C2
:18183000AE79F8CD39181FA9C92378BEC02B79BEC02B7ABEC02B7B9638
:18184800C0E1E1C9474F575FB7C8E5CDF017CD0A18AE67FC70183E985B
:1818600090CD23167C17DCF6150600DC0F16E1C91B7AA33CC00BC92186
:181878002C217EFE983A2921D07ECD4C1836987BF57917CDAC15F1C9DE
:1818900021000078B1C83E1029DAD010EB29EBD2A61809DAD0103DC2AC
:1818A8009818C9FE2DF5CAB718FE2BCAB7182BCDC41547575F2F4FCD1B
:1818C0005509DA0819FE2ECAE318FE45C2E718CD5509CDFB0ECD550996
:1818D800DA2A1914C2E718AF935F0C0CCABF18E57B90F40019F2F618AF
:1818F000F5CDEC16F13CC2EA18D1F1CCCD17EBC9C8F5CD8D17F13DC9E0
:18190800D557788947C5E5D5CD8D17F1D630CD1F19E1C1D1C3BF18CD8D
:18192000D517CDB617C1D1C35E157B0707830786D6305FC3D518E521AD
:181938009504CD9B12E1EBAF0698CDBB17219A12E5212E21E5CDA4173D
:181950003620F25719362D233630CA0D1AE5FCCD17AFF5CD131A014343
:181968009111F84FCD1F18B7E28419F1CD0119F5C36619CDEC16F13C39
:18198000F5CD131ACD4C153CCD4C18CDE517010603F1813CFAA019FE93
:1819980008D2A0193C473E023D3DE1F511261A05C2B119362E233630C2
:1819B0002305362ECCFA17C5E5D5CDF017E1062F047B965F237A9E5747
:1819C80023799E4F2B2BD2C019CD031623CDE517EBE17023C10DC2B10B
:1819E0001905CAF1192B7EFE30CAE519FE2EC4FA17F1CA101A364523DA
:1819F800362BF2011A362D2F3C062F04D60AD2031AC63A237023772343
:181A100071E1C901749411F723CD1F18B7E1E27B19E900000080A086CE
:181A280001102700E803006400000A000001000021CD17E3E9CDD5178A
:181A400021221ACDE217C1D1CDA41778CA8B1AF2561AB7CA0005B7CA01
:181A5800C515D5C579F67FCDF017F2731AD5C5CD7718C1D1F5CD1F1840
:181A7000E17C1FE1222B21E1222921DC381ACCCD17D5C5CD5816C1D101
:181A8800CD9916CDD517013881113BAACD99163A2C21FE88D28017CDA2
:181AA0007718C680C602DA8017F5214716CD4F15CD9016F1C1D1F5CDC4
:181AB8005B15CDCD1721CB1ACDFB1A110000C14AC3991608402E947401
:181AD000704F2E776E02887AE6A02A7C50AAAA7EFFFF7F7F00008081DD
:181AE80000000081CDD517119716D5E5CDF017CD9916E1CDD5177E23A9
:181B0000CDE21706F1C1D13DC8D5C5F5E5CD9916E1CDF317E5CD5E15AC
:181B1800E1C3041BCDA417215E20FA7D1B217F20CDE217215E20C886C6
:181B3000E6070600772387874F09CDF317CD99163A5D203CE603060075
:181B4800FE0188325D2021811B87874F09CD4F15CDF0177B59EE4F4FC7
:181B600036802B463680215C20347ED6ABC2741B770C151CCDAF152109
:181B78007F20C3FC17772B772B77C3581B68B1466899E9926910D17555
:181B90006821DB1BCD4F15CDD51701498311DB0FCDE517C1D1CDFA16D4
:181BA800CDD517CD7718C1D1CD5B1521DF1BCD5515CDA41737F2C71B5C
:181BC000CD4C15CDA417B7F5F4CD1721DF1BCD4F15F1D4CD1721E31BBF
:181BD800C3EC1ADB0F49810000007F05BAD71E866426998758342387DF
:181BF000E05DA586DA0F4983CDD517CD971BC1E1CDD517EBCDE517CDAC
:181C0800911BC3F816CDA417FC381AFCCD173A2C21FE81DA2A1C01006A
:181C2000815159CDFA16215515E521341CCDEC1A21DB1BC9094AD73BAB
:181C380078026E847BFEC12F7C74319A7D843D5A7DC87F917EE4BB4CAE
:181C50007E6CAAAA7F00000081C9D7C93E0CC3961DCD23157B328720BC
:181C6800C9CDC20DCD070AED538B20ED538D20C9CD070AD5E146237E05
:181C8000C37D11CDC20DCD070AD5CDCB072CCDC20DCD070AE37323727C
:181C9800E1C9CDC50DCD070AC5212E217AFE00280CCDD21C78FE3028A3
:181CB00002702371237BCDD21C7AFE00200578FE30280270237123AF7A
:181CC800772377C1212E21C32B1247E60FFE0A3802C607C6304F780FAB
:181CE0000F0F0FE60FFE0A3802C607C63047C9EB210000CD081DDA28B5
:181CF8001D1805CD081D381F29292929B56F18F3131AFE20CA081DD66E
:181D100030D8FE0A3805D607FE0AD8FE103FC9EB7A4BE5CD7C11E1C902
:181D28001E26C31105CDC50DCD070AC5212E2106110578FE012808CB46
:181D400013CB1230F41804CB13CB123E30CE0077230520F3AF772377F2
:181D5800C1212E21C32B12EB210000CD7C1DDA8A1DD63029B56FCD7CB3
:181D70001D30F6EB7A4BE5CD7C11E1C9131AFE20CA7C1DFE30D8FE329B
:181D88003FC91E28C31105DD21FFFFC36101C30800C300003E0032926B
:131DA00020C36801ED45F5A0C1B83E00C9CDD607C3FD0B28
:00000001FF

15
roms/INTMINI.HEX Normal file
View File

@ -0,0 +1,15 @@
:18000000F3C3B800FFFFFFFFC39F00FFFFFFFFFFC37400FFFFFFFFFFEF
:18001800C3AA00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78
:18003000FFFFFFFFFFFFFFFF1800F5E5DB80E601282DDB81F53A432049
:18004800FE3F2003F118202A3F20237DFE3F2003210020223F20F17764
:180060003A43203C324320FE3038043ED6D380E1F1FBED4D3A4320FEA7
:180078000028F9E52A4120237DFE3F2003210020F32241203A43203D4E
:18009000324320FE0530043E96D3807EFBE1C9F5DB80CB4F28FAF1D3F2
:1800A80081C93A4320FE00C97EB7C8CF2318F9C921ED20F9210020223F
:1800C0003F20224120AF3243203E96D380ED56FB210901CDB0003A4477
:1800D80020FE592016212401CDB000CD7400E6DFFE43200FCF3E0DCF41
:1800F0003E0ACF3E59324420C35001FE5720E4CF3E0DCF3E0ACFC35331
:18010800010C5A383020534243204279204772616E7420536561726C0A
:18012000650D0A000D0A436F6C64206F72207761726D2073746172748C
:0C013800202843206F722057293F200030
:00000001FF

257
roms/ROM.HEX Normal file
View File

@ -0,0 +1,257 @@
:20000000F3C3B800FFFFFFFFC39F00FFFFFFFFFFC37400FFFFFFFFFFC3AA00FFFFFFFFFF7F
:20002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1800F5E5DB80E601A4
:20004000282DDB81F53A4320FE3F2003F118202A3F20237DFE3F2003210020223F20F17721
:200060003A43203C324320FE3038043ED6D380E1F1FBED4D3A4320FE0028F9E52A412023EB
:200080007DFE3F2003210020F32241203A43203D324320FE0530043E96D3807EFBE1C9F5E7
:2000A000DB80CB4F28FAF1D381C93A4320FE00C97EB7C8CF2318F9C921ED20F921002022E4
:2000C0003F20224120AF3243203E96D380ED56FB210901CDB0003A4420FE5920162124017C
:2000E000CDB000CD7400E6DFFE43200FCF3E0DCF3E0ACF3E59324420C35001FE5720E4CFA4
:200100003E0DCF3E0ACFC353010C5A383020534243204279204772616E7420536561726CC3
:20012000650D0A000D0A436F6C64206F72207761726D207374617274202843206F72205781
:20014000293F2000FFFFFFFFFFFFFFFFFFFFFFFFC35601C3F401DD210000C36101070A7DA0
:2001600011214520F9C39C1D112E0406632145201A77231305C27001F9CD2F06CDFD0B3240
:20018000EF20323E21214302CD9B12CD4C06CD5509B7C2AA0121A221237CB5CABC017E47ED
:2001A0002F77BE70CA9801C3BC01CD210AB7C2FD04EB2B3ED94677BE70C285012B11A121B8
:2001C000CDC507DA850111CEFF22F42019229F20CD0A062A9F2011EFFF19113E217D936F4B
:2001E0007C9A67E5210C02CD9B12E1CD3E1921FD01CD9B1231AB20CD2F06C348052042796D
:2002000074657320667265650D0A00005A38302042415349432056657220342E37620D0AF6
:20022000436F70797269676874202843292031393738206279204D6963726F736F66740D7A
:200240000A00004D656D6F727920746F7000B3177718C91748205B11E01489113D1A1C1B7F
:2002600058168B1A911B971BF81B0D1C3415781C96200D142512A7141C142D149A1C2D1DBA
:200280003D146D147714C54E44C64F52CE455854C4415441C94E505554C4494DD2454144E4
:2002A000CC4554C74F544FD2554EC946D24553544F5245C74F535542D2455455524ED24581
:2002C0004DD3544F50CF5554CF4ECE554C4CD7414954C44546D04F4B45C44F4B45D34352FD
:2002E00045454ECC494E4553C34C53D749445448CD4F4E49544F52D34554D245534554D0E2
:2003000052494E54C34F4E54CC495354C34C454152C34C4F4144C353415645CE4557D441F5
:200320004228D44FC64ED3504328D448454ECE4F54D3544550ABADAAAFDEC14E44CF52BEF1
:20034000BDBCD3474EC94E54C14253D55352C65245C94E50D04F53D35152D24E44CC4F470F
:20036000C55850C34F53D3494ED4414EC1544ED045454BC445454BD04F494E54CC454ED301
:20038000545224D6414CC15343C3485224C8455824C2494E24CC45465424D2494748542461
:2003A000CD494424809F099C08770DEC0A7E0CB30FAD0C030BA90A8C0A7B0B6509980AC7C0
:2003C0000AEE0A9D09EC145D0BDE09F21491113B15831CEE0A691C5C1C611C991D99209C12
:2003E000209F0BCB091108460AEE0AEE0A09067925197959157C97167CF8167F461A500C6B
:200400000F460B0F4E46534E52474F4446434F564F4D554C425344442F304944544D4F5355
:200420004C535354434E55464D4F4858424EC3F401C31C0AD300C9D6006F7CDE006778DEE5
:2004400000473E00C9000000354ACA99391C76982295B3980ADD479853D199990A1A9F9890
:2004600065BCCD98D6773E9852C74F80DB00C901FF1C00001400140000000000C34207C334
:200480000000C30000C30000A221FEFF3F21204572726F720020696E20004F6B0D0A0000A4
:2004A000427265616B00210400397E23FE81C04E234623E569607AB3EBCAC004EBCDC50767
:2004C000010D00E1C809C3AA04CDE304C5E3C1CDC5077E02C80B2BC3CF04E52A1F210600CC
:2004E00009093EE53ED0956F3EFF9CDAF2046739E1D81E0CC311052A0E2122A1201E020153
:200500001E14011E00011E12011E22011E0A011E18CD2F06328A20CDF00B210404573E3F15
:20052000CDD607197ECDD607CD5509CDD607218E04CD9B122AA12011FEFFCDC507CA610110
:200540007CA53CC436193EC1AF328A20CDF00B219A04CD9B1221FFFF22A120CD4207DA5559
:2005600005CD55093C3DCA5505F5CD210AD5CD590647D1F1D23509D5C5AF321121CD5509CF
:20058000B7F5CDE905DA8E05F1F5CAC20AB7C5D2A505EB2A1B211A020313CDC507C296059A
:2005A0006069221B21D1F1CACC052A1B21E3C109E5CDC904E1221B21EB74D1232373237268
:2005C0002311A6201A772313B7C2C405CD150623EB626B7E23B6CA5505232323AFBE23C21F
:2005E000DD05EB732372C3D1052AA320444D7E23B62BC823237E23666FCDC50760697E2306
:20060000666F3FC83FD0C3EC05C02AA320AF77237723221B212AA3202B2213212AF420227F
:200620000821AFCD65092A1B21221D21221F21C12A9F20F921F82022F620AF6F672219218A
:20064000321021222321E5C52A1321C93E3FCDD6073E20CDD607C39320AF32F3200E051143
:20066000A6207EFE20CAE10647FE22CA0107B7CA08073AF320B77EC2E106FE3F3E9ECAE1AF
:20068000067EFE30DA8C06FE3CDAE106D5118502C501DD06C5067F7EFE61DAA506FE7BD234
:2006A000A506E65F774EEB23B6F2A706047EE67FC8B9C2A706EBE5131AB7FAD9064F78FEF9
:2006C00088C2C806CD55092B237EFE61DAD106E65FB9CAB706E1C3A50648F1EBC9EB79C115
:2006E000D12312130CD63ACAEF06FE49C2F20632F320D654C26206477EB7CA0807B8CAE1B4
:200700000623120C13C3F80621A5201213121312C93A8920B73E00328920C2250705CA4201
:2007200007CDD6073E052BCA39077ECDD607C34B07052BCDD607C24B07CDD607CDFD0BC323
:20074000420721A6200601AF328920CD00084FFE7FCA11073A8920B7CA64073E00CDD6079E
:20076000AF32892079FE07CAA807FE03CCFD0B37C8FE0DCAF80BFE15CA3C07FE40CA3907E4
:20078000FE5FCA3107FE08CA3107FE12C2A307C5D5E53600CDAD1D21A620CD9B12E1D1C156
:2007A000C34B07FE20DA4B0778FE493E07D2BD0779713211212304CDD607C34B07CDD60762
:2007C0003E08C3B7077C92C07D93C97EE3BE23E3CA5509C3FD04F53A8A20B7C2D012F1C5B0
:2007E000F5FE20DAFA073A8720473AF02004CAF60705B8CCFD0B3C32F020F1C1CD961DC9C4
:20080000CD5A1CE67FFE0FC03A8A202F328A20AFC9CD210AC0C1CDE905C5CD6708E14E2375
:20082000462378B1CA4805CD7008CD8009C5CDFD0B5E235623E5EBCD3E193E20E1CDD60703
:200840007EB723CA1D08F23D08D67F4F1186021A13B7F24F080DC24F08E67FCDD6071A134E
:20086000B7F25908C34008E52A8D20228B20E1C9E5D52A8B2011FFFFED5A228B20D1E1F0DC
:20088000E52A8D20228B20CD5A1CFE03CA9308E1C370082A8D20228B20C3F7013E643210C7
:2008A00021CD030BC1E5CDEC0A220C2121020039CDAA04D1C2CC0809D52B562B5E2323E533
:2008C0002A0C21CDC507E1C2B008D1F9EB0E08CDDA04E52A0C21E3E52AA120E3CDC50DCD19
:2008E000CB07A6CDC20DE5CDF017E1C5D5010081515A7EFEAB3E01C20809CD5509CDC20D83
:20090000E5CDF017CDA417E1C5D5F533E52A1321E30681C533CD80092213217EFE3ACA35ED
:2009200009B7C2FD04237E23B6CAA709235E2356EB22A120EBCD5509111509D5C8D680DA66
:20094000030BFE25D2FD04074F0600EB21A503094E2346C5EB237EFE3AD0FE20CA5509FE26
:20096000303F3C3DC9EB2AA320CA7A09EBCD210AE5CDE9056069D1D2C20A2B222121EBC9A3
:20098000DFC8D7FE1B2811FE03280DFE13C0D7FE11C8FE03280718F63EFF329220C0F6C0FD
:2009A00022132121F6FFC12AA120F57DA43CCABA092217212A1321221921AF328A20CDF0E4
:2009C0000BF121A004C23105C348052A19217CB51E20CA1105EB2A172122A120EBC9CD23C7
:2009E00015C0328620C9E52A8F2006004F09228F20E1C97EFE41D8FE5B3FC9CD5509CDC23A
:200A00000DCDA417FA1C0A3A2C21FE90DA4C18018090110000E5CD1F18E151C81E08C311CF
:200A2000052B110000CD5509D0E5F5219819CDC507DAFD04626B19291929F1D6305F16009D
:200A400019EBE1C3250ACA1906CDFE092BCD5509E52AF420CA690AE1CDCB072CD5CDFE09F7
:200A60002BCD5509C2FD04E3EB7D935F7C9A57DAF204E52A1B2101280009CDC507D2F20405
:200A8000EB229F20E122F420E1C31906CA1506CD1906011509C3A80A0E03CDDA04C1E5E504
:200AA0002AA120E33E8CF533C5CD210ACDEE0AE52AA120CDC507E123DCEC05D4E90560692F
:200AC0002BD81E0EC31105C016FFCDA604F9FE8C1E04C21105E122A120237CB5C2E60A3A41
:200AE0001121B7C24705211509E33EE1013A0E0006007948477EB7C8B8C823FE22CAF20AE1
:200B0000C3F50ACDB80FCDCB07B4D53AF220F5CDD40DF1E32213211FCDC70DCA560BE52A44
:200B20002921E523235E23562AA320CDC507D2450B2A9F20CDC507D1D24D0B210421CDC56C
:200B400007D24D0B3ED1CDFC13EBCD3512CDFC13E1CDFF17E1C9E5CDFC17D1E1C9CD2315EB
:200B60007E47FE8CCA6C0BCDCB07882B4B0D78CA3D09CD220AFE2CC0C36D0BCDD40D7EFE6B
:200B800088CA890BCDCB07A92BCDC50DCDA417CAEE0ACD5509DAA90AC33C092BCD5509CA33
:200BA000FD0BC8FEA5CA300CFEA8CA300CE5FE2CCA190CFE3BCA530CC1CDD40DE53AF22010
:200BC000B7C2E90BCD4919CD591236202A2921342A29213A87204704CAE50B043AF0208615
:200BE0003DB8D4FD0BCD9E12AFC49E12E1C39B0B3AF020B7C8C3FD0B360021A5203E0DCD72
:200C0000D6073E0ACDD607AF32F0203A86203DC8F5AFCDD607F1C30E0C3A8820473AF020A0
:200C2000B8D4FD0BD2530CD60ED2270C2FC3480CF5CD2015CDCB07292BF1D6A8E5CA430C69
:200C40003AF0202F83D2530C3C473E20CDD60705C24C0CE1CD5509C3A20B3F5265646F2058
:200C600066726F6D2073746172740D0A003A1221B7C2F704C1215A0CCD9B12C34806CD06D4
:200C8000127EFE223E00328A20C2980CCD5A12CDCB073BE5CD9E123EE5CD4C06C1DAA40925
:200CA000237EB72BC5CAEB0A362CC3B20CE52A2121F6AF321221E3C3BE0CCDCB072CCDB82F
:200CC0000FE3D57EFE2CCAE60C3A1221B7C2530D3E3FCDD607CD4C06D1C1DAA409237EB7EC
:200CE0002BC5CAEB0AD53AF220B7CA100DCD55095747FE22CA040D3A1221B757CA010D1659
:200D00003A062C2BCD5D12EB211B0DE3D5C31E0BCD5509CDAB18E3CDFC17E12BCD5509CAA9
:200D2000270DFE2CC26D0CE32BCD5509C2BA0CD13A1221B7EBC27B09D5B621420DC49B12C7
:200D4000E1C93F45787472612069676E6F7265640D0A00CDEC0AB7C26C0D237E23B61E0634
:200D6000CA1105235E2356EB220E21EBCD5509FE83C2530DC3E60C110000C4B80F221321FD
:200D8000CDA604C20305F9D57E23F5D5CDE217E3E5CD4F15E1CDFC17E1CDF317E5CD1F18B8
:200DA000E1C190CDF317CAB20DEB22A1206960C31109F92A13217EFE2CC21509CD5509CD56
:200DC0007A0DCDD40DF6373AF2208FB7E8C30F05CDCB07282B1600D50E01CDDA04CD4B0EA3
:200DE0002215212A1521C178FE78D4C50D7E1600D6B3DA0C0EFE03D20C0EFE0117AABA5717
:200E0000DAFD04220A21CD5509C3F00D7AB7C2330F7E220A21D6ACD8FE07D05F3AF2203DA8
:200E2000B37BCA911307835F21EF03197856BAD023CDC50DC501E30DC5434ACDD51758517D
:200E40004E234623C52A0A21C3D70DAF32F220CD55091E24CA1105DAAB18CDF309D2B20EBF
:200E6000FE262012CD5509FE48CAEF1CFE42CA5F1D1E02CA1105FEACCA4B0EFE2ECAAB18CA
:200E8000FEADCAA10EFE22CA5A12FEAACA930FFEA7CABE11D6B6D2C30ECDD00DCDCB0729E5
:200EA000C9167DCDD70D2A1521E5CDCD17CDC50DE1C9CDB80FE5EB2229213AF220B7CCE265
:200EC00017E1C90600074FC5CD550979FE31DAEA0ECDD00DCDCB072CCDC60DEB2A2921E334
:200EE000E5EBCD2315EBE3C3F20ECD990EE311AD0ED5014E02094E236669E915FEADC8FE8B
:200F00002DC814FE2BC8FEACC82BC9F6AFF5CDC50DCD070AF1EBC1E3EBCDE517F5CD070A53
:200F2000F1C179217C11C22E0FA34F78A2E9B34F78B2E921450F3AF2201F7A175F1664780D
:200F4000BAD0C3340E470F79B71FC1D1F5CDC70D21890FE5CA1F18AF32F220D5CDDE137E92
:200F600023234E2346D1C5F5CDE213CDF317F157E17BB2C87AD601D8AFBB3CD0151D0ABE99
:200F80002303CA710F3FC3AF173C8FC1A0C6FF9FC3B617165ACDD70DCDC50DCD070A7B2FB1
:200FA0004F7A2FCD7C11C1C3E30D2BCD5509C8CDCB072C01AA0FC5F6AF32F12046CDF3090C
:200FC000DAFD04AF4F32F220CD5509DAD40FCDF309DAE10F4FCD5509DAD50FCDF309D2D5D1
:200FE0000FD624C2F00F3C32F2200F814FCD55093A10213DCA9D10F200107ED628CA7510B1
:20100000AF321021E550592A2321CDC507112521CAE5162A1D21EB2A1B21CDC507CA3310AE
:20102000799623C22810789623CA671023232323C31A10E1E3D511B50ECDC507D1CA6A107E
:20104000E3E5C50106002A1F21E509C1E5CDC904E1221F216069221D212B3600CDC507C23C
:201060005910D173237223EBE1C9322C21219904222921E1C9E52AF120E357D5C5CDFB095E
:20108000C1F1EBE3E5EB3C577EFE2CCA7B10CDCB0729221521E122F1201E00D511E5F52A34
:2010A0001D213E19EB2A1F21EBCDC507CAD5107EB923C2B7107EB8235E235623C2A3103A2E
:2010C000F120B7C20605F1444DCAE51696CA33111E10C31105110400F1CA1C0A712370236C
:2010E0004FCDDA042323220A2171233AF1201779010B00D2F810C10371237023F5E5CD90EC
:2011000018EBE1F13DC2F010F5424BEB19DAF204CDE304221F212B3600CDC507C2161103A9
:20112000572A0A215EEB2909EB2B2B73237223F1DA5711474F7E2316E15E235623E3F5CD1C
:20114000C507D2D010E5CD9018D119F13D444DC238112929C109EB2A1521C92A1F21EB215D
:201160000000393AF220B7CA7711CDDE13CDDE122A9F20EB2A08217D934F7C9A41501E001B
:2011800021F220730690C3BB173AF02047AFC37D11CD1412CD061201EC0AC5D5CDCB0728BD
:2011A000CDB80FE5EB2B562B5EE1CDC50DCDCB0729CDCB07B4444DE3712370C35312CD14A5
:2011C00012D5CD990ECDC50DE35E2356237AB3CA09057E23666FE52A2321E32223212A27D0
:2011E00021E52A2521E5212521D5CDFC17E1CDC20D2BCD5509C2FD04E1222521E12227214E
:20120000E1222321E1C9E52AA120237CB5E1C01E16C31105CDCB07A73E80321021B647CDDA
:20122000BD0FC3C50DCDC50DCD4919CD5912CDDE13013914C57E2323E5CDB412E14E2346A2
:20124000CD4D12E56FCDD113D1C9CDB412210421E5772323732372E1C92B062250E50EFF01
:20126000237E0CB7CA6F12BACA6F12B8C26012FE22CC5509E323EB79CD4D121104212AF698
:20128000202229213E0132F220CDFF17CDC50722F620E17EC01E1EC3110523CD5912CDDE51
:2012A00013CDF3171C1DC80ACDD607FE0DCC070C03C3A512B70EF1F52A9F20EB2A08212F27
:2012C0004F06FF0923CDC507DAD21222082123EBF1C9F11E1ACA1105BFF501B612C52AF4BB
:2012E00020220821210000E52A9F20E521F820EB2AF620EBCDC50701EF12C243132A1B2147
:20130000EB2A1D21EBCDC507CA16137E2323B7CD4613C30013C1EB2A1F21EBCDC507CA6CBC
:2013200013CDF3177BE509B7F21513220A21E14E0600090923EB2A0A21EBCDC507CA16131B
:20134000013513C5F6807E23235E235623F0B7C8444D2A0821CDC5076069D8E1E3CDC50761
:20136000E3E56069D0C1F1F1E5D5C5C9D1E17DB4C82B462B4EE52B2B6E26000950592B449C
:201380004D2A0821CDCC04E171237069602BC3E112C5E52A2921E3CD4B0EE3CDC60D7EE574
:2013A0002A2921E5861E1CDA1105CD4A12D1CDE213E3CDE113E52A0621EBCDC813CDC81353
:2013C00021E00DE3E5C37B12E1E37E23234E23466F2C2DC80A120313C3D213CDC60D2A294B
:2013E00021EBCDFC13EBC0D550591B4E2A0821CDC507C2FA134709220821E1C92AF6202B08
:20140000462B4E2B2BCDC507C022F620C9018C11C5CDDB13AF5732F2207EB7C9018C11C594
:20142000CD1114CA1C0A23235E23561AC93E01CD4A12CD26152A062173C1C37B12CDD614CE
:20144000AFE34FE57EB8DA4B1478110E00C5CDB412C1E1E5232346236668060009444DCDF7
:201460004D126FCDD113D1CDE213C37B12CDD614D1D51A90C34114EB7ECDDB140405CA1CD7
:201480000AC51EFFFE29CA9014CDCB072CCD2315CDCB0729F1E3014314C53DBE0600D04F22
:2014A0007E91BB47D843C9CD1114CAC4155F23237E23666FE5194672E3C57EFE24C2C514EE
:2014C000CDEF1C180DFE25C2CF14CD5F1D1803CDAB18C1E170C9EBCDCB0729C1D1C543C962
:2014E000CD2615328420CD8320C38C11CD1015C34B20CD1015F51E002BCD5509CA0615CD11
:20150000CB072CCD2315C1CD8320ABA0CA0715C9CD2315328420324C20CDCB072CC323155E
:20152000CD5509CDC20DCD010A7AB7C21C0A2BCD55097BC9CD070A1AC38C11CDC20DCD0791
:201540000AD5CDCB072CCD2315D112C921221ACDF317C35E15CDF31721C1D1CDCD1778B75C
:20156000C83A2C21B7CAE51790D278152F3CEBCDD517EBCDE517C1D1FE19D0F5CD0A186729
:20158000F1CD2316B4212921F29E15CD0316D2E4152334CA0C052E01CD3916C3E415AF9067
:2015A000477E9B5F237E9A57237E994FDC0F166863AF4779B7C2D1154A54656F78D608FEF1
:2015C000E0C2B215AF322C21C905297A1757798F4FF2C915785C45B7CAE415212C21867770
:2015E000D2C415C878212C21B7FCF61546237EE680A94FC3E5171CC014C00CC00E8034C0D2
:20160000C30C057E835F237E8A57237E894FC9212D217E2F77AF6F90477D9B5F7D9A577DE8
:20162000994FC90600D608DA3216435A510E00C32516C6096FAF2DC8791F4F7A1F577B1FA6
:201640005F781F47C335160000008103AA561980F122768045AA3882CDA417B7EA1C0A2100
:201660002C217E01358011F30490F570D5C5CD5E15C1D104CDFA16214716CD5515214B1668
:20168000CDEC1A018080110000CD5E15F1CD1F1901318011187221C1D1CDA417C82E00CDE4
:2016A000621779323B21EB223C21010000505821AF15E521BB16E5E52129217E23B7CAE79D
:2016C00016E52E081F6779D2D516E52A3C2119EBE13A3B21891F4F7A1F577B1F5F781F4778
:2016E0002D7CC2C416E1C9435A514FC9CDD517012084110000CDE517C1D1CDA417CA0005D4
:201700002EFFCD621734342B7E3257202B7E3253202B7E324F2041EBAF4F575F325A20E593
:20172000C57DCD4E20DE003FD23217325A20F1F137D2C1E1793C3D1FFAE515177B175F7A34
:20174000175779174F297817473A5A2017325A2079B2B3C21F17E5212C2135E1C21F17C3CC
:201760000C0578B7CA86177D212C21AE80471FA878F28517C68077CAE516CD0A18772BC9B9
:20178000CDA4172FE1B7E1F2C415C30C05CDF01778B7C8C602DA0C0547CD5E15212C2134D3
:2017A000C0C30C053A2C21B7C83A2B21FE2F179FC03CC9CDA4170688110000212C214F700D
:2017C000060023368017C3AC15CDA417F0212B217EEE8077C9EB2A2921E3E52A2B21E3E519
:2017E000EBC9CDF317EB2229216069222B21EBC92129215E2356234E234623C911292106B3
:20180000041A77132305C20118C9212B217E07371F773F1F2323777907371F4F1FAEC97847
:20182000B7CAA41721AD17E5CDA41779C8212B21AE79F8CD39181FA9C92378BEC02B79BE23
:20184000C02B7ABEC02B7B96C0E1E1C9474F575FB7C8E5CDF017CD0A18AE67FC70183E983C
:2018600090CD23167C17DCF6150600DC0F16E1C91B7AA33CC00BC9212C217EFE983A292199
:20188000D07ECD4C1836987BF57917CDAC15F1C921000078B1C83E1029DAD010EB29EBD29F
:2018A000A61809DAD0103DC29818C9FE2DF5CAB718FE2BCAB7182BCDC41547575F2F4FCD9B
:2018C0005509DA0819FE2ECAE318FE45C2E718CD5509CDFB0ECD5509DA2A1914C2E718AFED
:2018E000935F0C0CCABF18E57B90F40019F2F618F5CDEC16F13CC2EA18D1F1CCCD17EBC965
:20190000C8F5CD8D17F13DC9D557788947C5E5D5CD8D17F1D630CD1F19E1C1D1C3BF18CD68
:20192000D517CDB617C1D1C35E157B0707830786D6305FC3D518E5219504CD9B12E1EBAF17
:201940000698CDBB17219A12E5212E21E5CDA4173620F25719362D233630CA0D1AE5FCCD78
:2019600017AFF5CD131A01439111F84FCD1F18B7E28419F1CD0119F5C36619CDEC16F13C40
:20198000F5CD131ACD4C153CCD4C18CDE517010603F1813CFAA019FE08D2A0193C473E0235
:2019A0003D3DE1F511261A05C2B119362E2336302305362ECCFA17C5E5D5CDF017E1062F36
:2019C000047B965F237A9E5723799E4F2B2BD2C019CD031623CDE517EBE17023C10DC2B105
:2019E0001905CAF1192B7EFE30CAE519FE2EC4FA17F1CA101A364523362BF2011A362D2FD2
:201A00003C062F04D60AD2031AC63A237023772371E1C901749411F723CD1F18B7E1E27BEA
:201A200019E900000080A08601102700E803006400000A000001000021CD17E3E9CDD517E2
:201A400021221ACDE217C1D1CDA41778CA8B1AF2561AB7CA0005B7CAC515D5C579F67FCDCA
:201A6000F017F2731AD5C5CD7718C1D1F5CD1F18E17C1FE1222B21E1222921DC381ACCCD80
:201A800017D5C5CD5816C1D1CD9916CDD517013881113BAACD99163A2C21FE88D28017CD24
:201AA0007718C680C602DA8017F5214716CD4F15CD9016F1C1D1F5CD5B15CDCD1721CB1A95
:201AC000CDFB1A110000C14AC3991608402E9474704F2E776E02887AE6A02A7C50AAAA7EF4
:201AE000FFFF7F7F0000808100000081CDD517119716D5E5CDF017CD9916E1CDD5177E23AC
:201B0000CDE21706F1C1D13DC8D5C5F5E5CD9916E1CDF317E5CD5E15E1C3041BCDA4172138
:201B20005E20FA7D1B217F20CDE217215E20C886E6070600772387874F09CDF317CD9916DC
:201B40003A5D203CE6030600FE0188325D2021811B87874F09CD4F15CDF0177B59EE4F4FE5
:201B600036802B463680215C20347ED6ABC2741B770C151CCDAF15217F20C3FC17772B7773
:201B80002B77C3581B68B1466899E9926910D1756821DB1BCD4F15CDD51701498311DB0FA2
:201BA000CDE517C1D1CDFA16CDD517CD7718C1D1CD5B1521DF1BCD5515CDA41737F2C71B24
:201BC000CD4C15CDA417B7F5F4CD1721DF1BCD4F15F1D4CD1721E31BC3EC1ADB0F4981003A
:201BE00000007F05BAD71E866426998758342387E05DA586DA0F4983CDD517CD971BC1E155
:201C0000CDD517EBCDE517CD911BC3F816CDA417FC381AFCCD173A2C21FE81DA2A1C010030
:201C2000815159CDFA16215515E521341CCDEC1A21DB1BC9094AD73B78026E847BFEC12FCE
:201C40007C74319A7D843D5A7DC87F917EE4BB4C7E6CAAAA7F00000081C9D7C93E0CC39629
:201C60001DCD23157B328720C9CDC20DCD070AED538B20ED538D20C9CD070AD5E146237E8F
:201C8000C37D11CDC20DCD070AD5CDCB072CCDC20DCD070AE3732372E1C9CDC50DCD070A4D
:201CA000C5212E217AFE00280CCDD21C78FE302802702371237BCDD21C7AFE00200578FE48
:201CC00030280270237123AF772377C1212E21C32B1247E60FFE0A3802C607C6304F780F7B
:201CE0000F0F0FE60FFE0A3802C607C63047C9EB210000CD081DDA281D1805CD081D381F2A
:201D000029292929B56F18F3131AFE20CA081DD630D8FE0A3805D607FE0AD8FE103FC9EBD5
:201D20007A4BE5CD7C11E1C91E26C31105CDC50DCD070AC5212E2106110578FE012808CB98
:201D400013CB1230F41804CB13CB123E30CE0077230520F3AF772377C1212E21C32B12EBCE
:201D6000210000CD7C1DDA8A1DD63029B56FCD7C1D30F6EB7A4BE5CD7C11E1C9131AFE2098
:201D8000CA7C1DFE30D8FE323FC91E28C31105DD21FFFFC36101C30800C300003E003292D2
:201DA00020C36801ED45F5A0C1B83E00C9CDD607C3FD0BFFFFFFFFFFFFFFFFFFFFFFFFFF28
:201DC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23
:201DE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03
:201E0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2
:201E2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2
:201E4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2
:201E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82
:201E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62
:201EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42
:201EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22
:201EE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02
:201F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1
:201F2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1
:201F4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1
:201F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81
:201F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61
:201FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41
:201FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21
:201FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01
:00000001FF

4341
roms/basic.asm Normal file

File diff suppressed because it is too large Load Diff

202
roms/intmini.asm Normal file
View File

@ -0,0 +1,202 @@
;==================================================================================
; Contents of this file are copyright Grant Searle
;
; You have permission to use this for NON COMMERCIAL USE ONLY
; If you wish to use it elsewhere, please include an acknowledgement to myself.
;
; http://searle.hostei.com/grant/index.html
;
; eMail: home.micros01@btinternet.com
;
; If the above don't work, please perform an Internet search to see if I have
; updated the web page hosting service.
;
;==================================================================================
; Minimum 6850 ACIA interrupt driven serial I/O to run modified NASCOM Basic 4.7
; Full input buffering with incoming data hardware handshaking
; Handshake shows full before the buffer is totally filled to allow run-on from the sender
SER_BUFSIZE .EQU 3FH
SER_FULLSIZE .EQU 30H
SER_EMPTYSIZE .EQU 5
RTS_HIGH .EQU 0D6H
RTS_LOW .EQU 096H
serBuf .EQU $2000
serInPtr .EQU serBuf+SER_BUFSIZE
serRdPtr .EQU serInPtr+2
serBufUsed .EQU serRdPtr+2
basicStarted .EQU serBufUsed+1
TEMPSTACK .EQU $20ED ; Top of BASIC line input buffer so is "free ram" when BASIC resets
CR .EQU 0DH
LF .EQU 0AH
CS .EQU 0CH ; Clear screen
.ORG $0000
;------------------------------------------------------------------------------
; Reset
RST00 DI ;Disable interrupts
JP INIT ;Initialize Hardware and go
;------------------------------------------------------------------------------
; TX a character over RS232
.ORG 0008H
RST08 JP TXA
;------------------------------------------------------------------------------
; RX a character over RS232 Channel A [Console], hold here until char ready.
.ORG 0010H
RST10 JP RXA
;------------------------------------------------------------------------------
; Check serial status
.ORG 0018H
RST18 JP CKINCHAR
;------------------------------------------------------------------------------
; RST 38 - INTERRUPT VECTOR [ for IM 1 ]
.ORG 0038H
RST38 JR serialInt
;------------------------------------------------------------------------------
serialInt: PUSH AF
PUSH HL
IN A,($80)
AND $01 ; Check if interupt due to read buffer full
JR Z,rts0 ; if not, ignore
IN A,($81)
PUSH AF
LD A,(serBufUsed)
CP SER_BUFSIZE ; If full then ignore
JR NZ,notFull
POP AF
JR rts0
notFull: LD HL,(serInPtr)
INC HL
LD A,L ; Only need to check low byte becasuse buffer<256 bytes
CP (serBuf+SER_BUFSIZE) & $FF
JR NZ, notWrap
LD HL,serBuf
notWrap: LD (serInPtr),HL
POP AF
LD (HL),A
LD A,(serBufUsed)
INC A
LD (serBufUsed),A
CP SER_FULLSIZE
JR C,rts0
LD A,RTS_HIGH
OUT ($80),A
rts0: POP HL
POP AF
EI
RETI
;------------------------------------------------------------------------------
RXA:
waitForChar: LD A,(serBufUsed)
CP $00
JR Z, waitForChar
PUSH HL
LD HL,(serRdPtr)
INC HL
LD A,L ; Only need to check low byte becasuse buffer<256 bytes
CP (serBuf+SER_BUFSIZE) & $FF
JR NZ, notRdWrap
LD HL,serBuf
notRdWrap: DI
LD (serRdPtr),HL
LD A,(serBufUsed)
DEC A
LD (serBufUsed),A
CP SER_EMPTYSIZE
JR NC,rts1
LD A,RTS_LOW
OUT ($80),A
rts1:
LD A,(HL)
EI
POP HL
RET ; Char ready in A
;------------------------------------------------------------------------------
TXA: PUSH AF ; Store character
conout1: IN A,($80) ; Status byte
BIT 1,A ; Set Zero flag if still transmitting character
JR Z,conout1 ; Loop until flag signals ready
POP AF ; Retrieve character
OUT ($81),A ; Output the character
RET
;------------------------------------------------------------------------------
CKINCHAR LD A,(serBufUsed)
CP $0
RET
PRINT: LD A,(HL) ; Get character
OR A ; Is it $00 ?
RET Z ; Then RETurn on terminator
RST 08H ; Print it
INC HL ; Next Character
JR PRINT ; Continue until $00
RET
;------------------------------------------------------------------------------
INIT:
LD HL,TEMPSTACK ; Temp stack
LD SP,HL ; Set up a temporary stack
LD HL,serBuf
LD (serInPtr),HL
LD (serRdPtr),HL
XOR A ;0 to accumulator
LD (serBufUsed),A
LD A,RTS_LOW
OUT ($80),A ; Initialise ACIA
IM 1
EI
LD HL,SIGNON1 ; Sign-on message
CALL PRINT ; Output string
LD A,(basicStarted); Check the BASIC STARTED flag
CP 'Y' ; to see if this is power-up
JR NZ,COLDSTART ; If not BASIC started then always do cold start
LD HL,SIGNON2 ; Cold/warm message
CALL PRINT ; Output string
CORW:
CALL RXA
AND %11011111 ; lower to uppercase
CP 'C'
JR NZ, CHECKWARM
RST 08H
LD A,$0D
RST 08H
LD A,$0A
RST 08H
COLDSTART: LD A,'Y' ; Set the BASIC STARTED flag
LD (basicStarted),A
JP $0150 ; Start BASIC COLD
CHECKWARM:
CP 'W'
JR NZ, CORW
RST 08H
LD A,$0D
RST 08H
LD A,$0A
RST 08H
JP $0153 ; Start BASIC WARM
SIGNON1: .BYTE CS
.BYTE "Z80 SBC By Grant Searle",CR,LF,0
SIGNON2: .BYTE CR,LF
.BYTE "Cold or warm start (C or W)? ",0
.END

32
src/units/16bit_arith.asm Normal file
View File

@ -0,0 +1,32 @@
ADD HL, SP
ADD HL, BC
ADD HL, DE
ADD HL, HL
ADC HL, SP
ADC HL, BC
ADC HL, DE
ADC HL, HL
SBC HL, SP
SBC HL, BC
SBC HL, DE
SBC HL, HL
ADD IX, SP
ADD IX, BC
ADD IX, DE
ADD IX, IX
ADD IY, SP
ADD IY, BC
ADD IY, DE
add IY, IY
inc hl
inc bc
inc de
inc sp
inc ix
inc iy
dec hl
dec bc
dec de
dec sp
DEC ix
dec iy

34
src/units/16bit_load.asm Normal file
View File

@ -0,0 +1,34 @@
PUSH DE
PUSH BC
PUSH HL
PUSH AF
PUSH IX
PUSH IY
POP IY
POP IX
POP DE
POP BC
POP HL
POP AF
LD SP, HL
LD BC, 4567H
LD DE, 4567H
LD HL, 4567H
LD IX, 4567H
LD IY, 4567H
LD SP, 4567H
LD BC, (4567H)
LD DE, (4567H)
LD HL, (4567H)
LD IX, (4567H)
LD IY, (4567H)
LD SP, (4567H)
LD (4567H), IX
LD (4567H), IY
LD (4567H), SP
LD (4567H), BC
LD (4567H), DE
LD (4567H), HL
LD SP, HL
LD SP, IX
LD SP, IY

96
src/units/8bit_arith.asm Normal file
View File

@ -0,0 +1,96 @@
ADD A, A
ADD A, B
ADD A, C
ADD A, D
ADD A, E
ADD A, H
ADD A, L
ADD A, (HL)
ADD A, 45H
ADD A, (IX+45H)
ADC A, A
ADC A, B
ADC A, C
ADC A, D
ADC A, E
ADC A, H
ADC A, L
ADC A, (HL)
ADC A, 45H
ADC A, (IX+45H)
SUB A, A
SUB A, B
SUB A, C
SUB A, D
SUB A, E
SUB A, H
SUB A, L
SUB A, (HL)
SUB A, 45H
SUB A, (IX+45H)
AND A
AND B
AND C
AND D
AND E
AND H
AND L
AND (HL)
AND 56H
AND (IX+54H)
AND (IY+54H)
OR A
OR B
OR C
OR D
OR E
OR H
OR L
OR (HL)
OR 56H
OR (IX+54H)
OR (IY+54H)
XOR A
XOR B
XOR C
XOR D
XOR E
XOR H
XOR L
XOR (HL)
XOR 56H
XOR (IX+54H)
XOR (IY+54H)
CP A
CP B
CP C
CP D
CP E
CP H
CP L
CP (HL)
CP 56H
CP (IX+54H)
CP (IY+54H)
INC A
INC B
INC C
INC D
INC E
INC H
INC L
INC (HL)
INC (IX+76H)
INC (IY+76H)
DEC A
DEC B
DEC C
DEC D
DEC E
DEC H
DEC L
DEC (HL)
DEC (IX+76H)
DEC (IY+76H)

127
src/units/8bit_load.asm Normal file
View File

@ -0,0 +1,127 @@
LD A, A
LD A, B
LD A, C
LD A, D
LD A, E
LD A, H
LD A, L
LD A, I
LD A, R
LD B, A
LD B, B
LD B, C
LD B, D
LD B, E
LD B, H
LD B, L
LD C, A
LD C, B
LD C, C
LD C, D
LD C, E
LD C, H
LD C, L
LD D, A
LD D, B
LD D, C
LD D, D
LD D, E
LD D, H
LD D, L
LD E, A
LD E, B
LD E, C
LD E, D
LD E, E
LD E, H
LD H, A
LD H, B
LD H, C
LD H, D
LD H, E
LD H, H
LD H, L
LD L, A
LD L, B
LD L, C
LD L, D
LD L, E
LD L, H
LD L, L
LD E, A
LD I, A
LD R, A
LD (HL), A
LD (HL), B
LD (HL), C
LD (HL), D
LD (HL), E
LD (HL), H
LD (HL), L
LD A, (HL)
LD B, (HL)
LD C, (HL)
LD D, (HL)
LD E, (HL)
LD H, (HL)
LD L, (HL)
LD (BC), A
LD (DE), A
LD A, (BC)
LD A, (DE)
LD A, (IX+3DH)
LD B, (IX+3DH)
LD C, (IX+3DH)
LD D, (IX+3DH)
LD E, (IX+3DH)
LD H, (IX+3DH)
LD L, (IX+3DH)
LD A, (IY+1DH)
LD B, (IY+8DH)
LD C, (IY+2DH)
LD D, (IY+15H)
LD E, (IY+3DH)
LD H, (IY+3DH)
LD L, (IY+3DH)
LD A, (IX+3DH)
LD B, (IX+3DH)
LD C, (IX+3DH)
LD D, (IX+3DH)
LD E, (IX+3DH)
LD H, (IX+3DH)
LD L, (IX+3DH)
LD A, (IY+1DH)
LD B, (IY+8DH)
LD C, (IY+2DH)
LD D, (IY+15H)
LD E, (IY+3DH)
LD H, (IY+3DH)
LD (IX+3DH), A
LD (IX+3DH), B
LD (IX+3DH), C
LD (IX+3DH), D
LD (IX+3DH), E
LD (IX+3DH), H
LD (IX+3DH), L
LD (IY+3DH), A
LD (IY+3DH), B
LD (IY+3DH), C
LD (IY+3DH), D
LD (IY+3DH), E
LD (IY+3DH), H
LD (IY+3DH), L
LD A, 31H
LD B, 31H
LD C, 31H
LD D, 31H
LD E, 31H
LD H, 31H
LD L, 31H
LD (BC), A
LD (DE), A
LD I, A
LD R, A
LD A, (8765H)
LD (8762H), A
LD (IX+87H), 65H
LD (IY+87H), 65H

240
src/units/bit_set.asm Normal file
View File

@ -0,0 +1,240 @@
BIT 0, A
BIT 0, B
BIT 0, C
BIT 0, D
BIT 0, E
BIT 0, H
BIT 0, L
BIT 1, A
BIT 1, B
BIT 1, C
BIT 1, D
BIT 1, E
BIT 1, H
BIT 1, L
BIT 2, A
BIT 2, B
BIT 2, C
BIT 2, D
BIT 2, E
BIT 2, H
BIT 2, L
BIT 3, A
BIT 3, B
BIT 3, C
BIT 3, D
BIT 3, E
BIT 3, H
BIT 3, L
BIT 4, A
BIT 4, B
BIT 4, C
BIT 4, D
BIT 4, E
BIT 4, H
BIT 4, L
BIT 5, A
BIT 5, B
BIT 5, C
BIT 5, D
BIT 5, E
BIT 5, H
BIT 5, L
BIT 6, A
BIT 6, B
BIT 6, C
BIT 6, D
BIT 6, E
BIT 6, H
BIT 6, L
BIT 7, A
BIT 7, B
BIT 7, C
BIT 7, D
BIT 7, E
BIT 7, H
BIT 7, L
BIT 0, (HL)
BIT 1, (HL)
BIT 2, (HL)
BIT 3, (HL)
BIT 4, (HL)
BIT 5, (HL)
BIT 6, (HL)
BIT 7, (HL)
BIT 0, (IX+87H)
BIT 1, (IX+87H)
BIT 2, (IX+87H)
BIT 3, (IX+87H)
BIT 4, (IX+87H)
BIT 5, (IX+87H)
BIT 6, (IX+87H)
BIT 7, (IX+87H)
BIT 0, (IY+87H)
BIT 1, (IY+87H)
BIT 2, (IY+87H)
BIT 3, (IY+87H)
BIT 4, (IY+87H)
BIT 5, (IY+87H)
BIT 6, (IY+87H)
BIT 7, (IY+87H)
SET 0, A
SET 0, B
SET 0, C
SET 0, D
SET 0, E
SET 0, H
SET 0, L
SET 1, A
SET 1, B
SET 1, C
SET 1, D
SET 1, E
SET 1, H
SET 1, L
SET 2, A
SET 2, B
SET 2, C
SET 2, D
SET 2, E
SET 2, H
SET 2, L
SET 3, A
SET 3, B
SET 3, C
SET 3, D
SET 3, E
SET 3, H
SET 3, L
SET 4, A
SET 4, B
SET 4, C
SET 4, D
SET 4, E
SET 4, H
SET 4, L
SET 5, A
SET 5, B
SET 5, C
SET 5, D
SET 5, E
SET 5, H
SET 5, L
SET 6, A
SET 6, B
SET 6, C
SET 6, D
SET 6, E
SET 6, H
SET 6, L
SET 7, A
SET 7, B
SET 7, C
SET 7, D
SET 7, E
SET 7, H
SET 7, L
SET 0, (HL)
SET 1, (HL)
SET 2, (HL)
SET 3, (HL)
SET 4, (HL)
SET 5, (HL)
SET 6, (HL)
SET 7, (HL)
SET 0, (IX+87H)
SET 1, (IX+87H)
SET 2, (IX+87H)
SET 3, (IX+87H)
SET 4, (IX+87H)
SET 5, (IX+87H)
SET 6, (IX+87H)
SET 7, (IX+87H)
SET 0, (IY+87H)
SET 1, (IY+87H)
SET 2, (IY+87H)
SET 3, (IY+87H)
SET 4, (IY+87H)
SET 5, (IY+87H)
SET 6, (IY+87H)
SET 7, (IY+87H)
RES 0, A
RES 0, B
RES 0, C
RES 0, D
RES 0, E
RES 0, H
RES 0, L
RES 1, A
RES 1, B
RES 1, C
RES 1, D
RES 1, E
RES 1, H
RES 1, L
RES 2, A
RES 2, B
RES 2, C
RES 2, D
RES 2, E
RES 2, H
RES 2, L
RES 3, A
RES 3, B
RES 3, C
RES 3, D
RES 3, E
RES 3, H
RES 3, L
RES 4, A
RES 4, B
RES 4, C
RES 4, D
RES 4, E
RES 4, H
RES 4, L
RES 5, A
RES 5, B
RES 5, C
RES 5, D
RES 5, E
RES 5, H
RES 5, L
RES 6, A
RES 6, B
RES 6, C
RES 6, D
RES 6, E
RES 6, H
RES 6, L
RES 7, A
RES 7, B
RES 7, C
RES 7, D
RES 7, E
RES 7, H
RES 7, L
RES 0, (HL)
RES 1, (HL)
RES 2, (HL)
RES 3, (HL)
RES 4, (HL)
RES 5, (HL)
RES 6, (HL)
RES 7, (HL)
RES 0, (IX+87H)
RES 1, (IX+87H)
RES 2, (IX+87H)
RES 3, (IX+87H)
RES 4, (IX+87H)
RES 5, (IX+87H)
RES 6, (IX+87H)
RES 7, (IX+87H)
RES 0, (IY+87H)
RES 1, (IY+87H)
RES 2, (IY+87H)
RES 3, (IY+87H)
RES 4, (IY+87H)
RES 5, (IY+87H)
RES 6, (IY+87H)
RES 7, (IY+87H)

28
src/units/call_return.asm Normal file
View File

@ -0,0 +1,28 @@
CALL 7219H
CALL NZ, 7219H
CALL Z, 7219H
CALL NC, 7219H
CALL C, 7219H
CALL PO, 7219H
CALL PE, 7219H
CALL P, 7219H
CALL M, 7219H
RETI
RETN
RET
RET NZ
RET Z
RET NC
RET C
RET PO
RET PE
RET P
RET M
RST 0H
RST 8H
RST 10H
RST 18H
RST 20H
RST 28H
RST 30H
RST 38H

14
src/units/exchange.asm Normal file
View File

@ -0,0 +1,14 @@
EX DE, HL
EX AF, AF'
EXX
EX (SP), HL
EX (SP), IX
EX (SP), IY
LDI
LDIR
LDD
LDDR
CPI
CPIR
CPD
CPDR

View File

@ -0,0 +1,14 @@
CPL
DAA
NEG
CCF
SCF
HALT
DI
EI
NOP
IM 0
IM 1
IM 2

View File

@ -0,0 +1,25 @@
IN A, (32H)
IN B, (C)
IN C, (C)
IN D, (C)
IN E, (C)
IN F, (C)
IN H, (C)
IN L, (C)
INI
INIR
IND
INDR
OUT (32H), A
OUT (C), B
OUT (C), C
OUT (C), D
OUT (C), E
OUT (C), H
OUT (C), L
OUTI
OTIR
OUTD
OTDR

12
src/units/jump_group.asm Normal file
View File

@ -0,0 +1,12 @@
JP 7219H
JP NZ, 7219H
JP Z, 7219H
JP NC, 7219H
JP C, 7219H
JP PO, 7219H
JP PE, 7219H
JP P, 7219H
JP M, 7219H
JP (HL)
JP (IX)
JP (IY)

View File

@ -0,0 +1,65 @@
RLCA
RLA
RRA
RLC A
RLC B
RLC C
RLC D
RLC E
RLC H
RLC L
RLC (HL)
RLC (IX+87H)
RLC (IY+87H)
RL A
RL B
RL C
RL D
RL E
RL h
RL l
rl (hl)
rl (ix+65h)
rl (iy+43h)
rr a
rr b
rr c
rr d
rr e
rr h
rr l
rr (hl)
rr (ix+87H)
rr (iy+71H)
rrc a
rrc b
rrc c
rrc d
rrc e
rrc h
rrc l
rrc (hl)
rrc (ix+87H)
rrc (iy+71H)
sla a
sla b
sla c
sla d
sla e
sla h
sla l
sla (hl)
sla (ix+76H)
sla (iy+87h)
sra a
sra b
sra c
sra d
sra e
sra h
sra l
sra (hl)
sra (ix+76H)
sra (iy+87h)
rld
rrd

View File

@ -0,0 +1,32 @@
from z80 import registers
import unittest
class TestZ80Registers(unittest.TestCase):
def setUp(self):
self.registers = registers.Registers(power=None)
def test_double_register_access(self):
self.registers.H = 0x45
self.registers.L = 0x46
self.assertEqual(self.registers.HL, 0x4546)
def test_condition_flags(self):
self.registers.F=0x0
self.registers.condition.C=True
self.assertEqual(self.registers.F, 0x01 << 0)
self.registers.F=0x0
self.registers.condition.S=True
self.assertEqual(self.registers.F, 0x01 << 7)
self.registers.F=0x0
self.registers.condition.PV=True
self.assertEqual(self.registers.F, 0x01 << 2)
if __name__ == '__main__':
unittest.main()
raw_input()

233
src/units/test_z80.py Normal file
View File

@ -0,0 +1,233 @@
import random
import unittest
from time import sleep
import logging
logging.basicConfig(level=logging.ERROR)
import subprocess
from subprocess import PIPE, STDOUT, Popen
from z80 import util, registers, instructions
import tempfile
import string
import inspect
import os
def compile_code(code):
p = Popen(["z80asm", "-o", "-"], stdout=PIPE, stdin=PIPE)
by = p.communicate(input=code)[0]
object_code = [ord(b) for b in by]
return object_code
class TestZ80Instructions(unittest.TestCase):
def setUp(self):
self.registers = registers.Registers(power=None)
self.instructions = instructions.InstructionSet(self.registers)
self.mem = bytearray(48*1024)
def pass_bytes(self, bytes):
for i in bytes:
ins, args = self.instructions << i
if ins:
yield ins, args
def execute(self, ins):
rd = ins[0].get_read_list(ins[1])
data = [self.mem[i] for i in rd]
wrt = ins[0].execute(data, ins[1])
for i in wrt:
self.mem[i[0]] = i[1]
def test_ld(self):
by = [0x3E, 0x45]
for ins in self.pass_bytes(by):
print ins
self.execute(ins)
self.assertEqual(self.registers.A, 0x45)
def _test_assembler(self, file_name):
file = os.path.join(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))),
file_name)
with open(file, "r") as f:
asm = f.read()
by = subprocess.check_output(["z80asm", "-i", file, "-o", "-"])
byts = [ord(b) for b in by]
res = ""
for ins, a in zip(self.pass_bytes(byts), asm.split("\n")):
res = ins[0].assembler(ins[1])
self.assertEqual(res, a.strip().upper())
print res
res = res[:-1]
def test_assembler_8bit_load(self):
self._test_assembler("8bit_load.asm")
def test_assembler_16bit_load(self):
self._test_assembler("16bit_load.asm")
def test_assembler_exchange_block_transfer(self):
self._test_assembler("exchange.asm")
def test_assembler_8bit_arith(self):
self._test_assembler("8bit_arith.asm")
def test_assembler_16bit_arith(self):
self._test_assembler("16bit_arith.asm")
def test_assembler_general_arith(self):
self._test_assembler("general_purp.asm")
def test_assembler_rotate_and_shift_group(self):
self._test_assembler("rotate_shift.asm")
def test_assembler_bit_set_and_test_group(self):
self._test_assembler("bit_set.asm")
def test_assembler_jump_group(self):
self._test_assembler("jump_group.asm")
def test_assembler_call_return_group(self):
self._test_assembler("call_return.asm")
def test_assembler_input_output(self):
self._test_assembler("input_output.asm")
def compile_and_load(self,program):
obj = compile_code(program)
p=0
for i in obj:
self.mem[p]=i
p+=1
self.registers.reset()
self.assertGreater(p, 0, msg="Zero length program, bad compile")
return p
def test_program1(self):
program = ("LD A, 54H",
"NOP",
"LD BC, 6543H",
"LD HL, 1234H",
"ADD HL, BC",
"ADD A, A",
"SUB A, 37H",
# "LD B, 0H",
# "LD C, 54H",
"LD BC, 54H",
"INC BC",
"SBC HL, BC",
"ADD IX, BC",
"ADD IX, IX",
"ADD IX, SP",
"inc ix",
"inc iy",
"inc iy",
"dec iy",
"ld b, a",
"ld a, 0x01",
"rla",
"ld C, 1H",
"rlc c",
"rlc c",
"rlc c",
"ld iy, 1ffH",
"ld (iy+0H), 0x8",
"rlc (iy+0H)",
"HALT"
)
program = string.join(program, "\n")
self.compile_and_load(program)
while not self.registers.HALT:
ins, args = False, []
while not ins:
ins, args = self.instructions << self.mem[self.registers.PC]
self.registers.PC = util.inc8(self.registers.PC)
self.execute((ins, args))
print self.registers.A
self.assertEqual(self.registers.B, 0x54+0x54-0x37)
self.assertEqual(self.registers.HL, 0x6543+0x1234-0x55)
self.assertEqual(self.registers.IX, 0x55 + 0x55 + 1)
# self.assertEqual(self.registers.IY, 0x01)
self.assertEqual(self.registers.A, 2)
self.assertEqual(self.registers.C, 8)
self.assertEqual(self.mem[0x1ff], 16)
class TestAdditionSubtraction(unittest.TestCase):
def setUp(self):
self.registers = registers.Registers(power=None)
def test_addition_overflow1_flag(self):
res = util.add8(util.make_8bit_twos_comp(10), util.make_8bit_twos_comp(10),
self.registers)
self.assertEqual(util.get_8bit_twos_comp(res), 20)
self.assertFalse(self.registers.condition.PV)
def test_addition_overflow2_flag(self):
res = util.add8(util.make_8bit_twos_comp(-10), util.make_8bit_twos_comp(10),
self.registers)
print util.get_8bit_twos_comp(res)
self.assertEqual(util.get_8bit_twos_comp(res), 0)
self.assertFalse(self.registers.condition.PV)
self.assertFalse(self.registers.condition.S)
def test_addition_overflow3_flag(self):
res = util.add8(util.make_8bit_twos_comp(-10), util.make_8bit_twos_comp(-10),
self.registers)
self.assertEqual(util.get_8bit_twos_comp(res), util.get_8bit_twos_comp(-20))
print util.get_8bit_twos_comp(res)
self.assertFalse(self.registers.condition.PV)
self.assertTrue(self.registers.condition.S)
def test_addition_overflow4_flag(self):
res = util.add8(util.make_8bit_twos_comp(-100), util.make_8bit_twos_comp(-100),
self.registers)
self.assertTrue(self.registers.condition.PV)
def test_addition_overflow5_flag(self):
res = util.add8(util.make_8bit_twos_comp(100), util.make_8bit_twos_comp(100),
self.registers)
self.assertTrue(self.registers.condition.PV)
def test_subtraction_overflow_flag_1(self):
res = util.subtract8_check_overflow(util.make_8bit_twos_comp(10), util.make_8bit_twos_comp(10),
self.registers)
self.assertEqual(res, util.get_8bit_twos_comp(0))
self.assertFalse(self.registers.condition.PV)
def test_subtraction_overflow_flag_2(self):
res = util.subtract8_check_overflow(util.make_8bit_twos_comp(-10), util.make_8bit_twos_comp(10),
self.registers)
self.assertEqual(util.get_8bit_twos_comp(res), -20)
self.assertFalse(self.registers.condition.PV)
self.assertTrue(self.registers.condition.S)
def test_subtraction_overflow_flag_3(self):
res = util.subtract8_check_overflow(util.make_8bit_twos_comp(-10), util.make_8bit_twos_comp(-10),
self.registers)
self.assertEqual(util.get_8bit_twos_comp(res), 0)
self.assertFalse(self.registers.condition.PV)
def test_subtraction_overflow_flag_4(self):
res = util.subtract8_check_overflow(util.make_8bit_twos_comp(-100), util.make_8bit_twos_comp(100),
self.registers)
self.assertTrue(self.registers.condition.PV)
def test_subtraction_overflow_flag_5(self):
res = util.subtract8_check_overflow(util.make_8bit_twos_comp(100), util.make_8bit_twos_comp(-100),
self.registers)
self.assertTrue(self.registers.condition.PV)
def test_twos_comp(self):
self.assertEqual(util.get_8bit_twos_comp(0b100), 4)
self.assertEqual(util.get_8bit_twos_comp(0b11100011), -29)
self.assertEqual(util.make_8bit_twos_comp(-29),0b11100011)
self.assertEqual(util.make_8bit_twos_comp(25),0b00011001)
if __name__ == '__main__':
unittest.main()
raw_input()

0
src/z80/__init__.py Normal file
View File

275
src/z80/gui.py Normal file
View File

@ -0,0 +1,275 @@
import sys
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtWebKit import *
from cStringIO import StringIO
class RegistersGUI(QWidget):
_addresses = [0x80, 0x81]
_update_sgl = Signal()
format_data = """
<html>
<head>
<title>HTML Online Editor Sample</title>
</head>
<body>
<p>
&nbsp;</p>
<table border="0" cellpadding="0" cellspacing="0" style="width: 100px;">
<tbody>
<tr>
<td>
<span style="font-size:12px;">A</span></td>
<td>
<span style="font-size:12px;">0x{A:X}</span></td>
</tr>
<tr>
<td colspan="2">
<span style="font-size:12px;">Flags</span>
<table border="0" cellpadding="1" cellspacing="1" style="width: 100px;">
<tbody>
<tr>
<td style="text-align: center;">
<span style="font-size:12px;">S</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">Z</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">F5</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">H</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">F3</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">PV</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">N</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">C</span></td>
</tr>
<tr>
<td style="text-align: center;">
<span style="font-size:12px;">{FS}</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">{FZ}</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">{FF5}</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">{FH}</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">{FF3}</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">{FPV}</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">{FN}</span></td>
<td style="text-align: center;">
<span style="font-size:12px;">{FC}</span></td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>
<span style="font-size:12px;">BC</span></td>
<td>
<span style="font-size:12px;">0x{BC:X}</span></td>
</tr>
<tr>
<td>
<span style="font-size:12px;">DE</span></td>
<td>
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{DE:X}</span></td>
</tr>
<tr>
<td>
<span style="font-size:12px;">HL</span></td>
<td>
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{HL:X}</span></td>
</tr>
<tr>
<td>
<span style="font-size:12px;">PC</span></td>
<td>
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{PC:X}</span></td>
</tr>
<tr>
<td>
<span style="font-size:12px;">SP</span></td>
<td>
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{SP:X}</span></td>
</tr>
<tr>
<td>
<span style="font-size:12px;">IX</span></td>
<td>
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{IX:X}</span></td>
</tr>
<tr>
<td>
<span style="font-size:12px;">IY</span></td>
<td>
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{IY:X}</span></td>
</tr>
<tr>
<td>
<span style="font-size:12px;">I</span></td>
<td>
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{I:X}</span></td>
</tr>
<tr>
<td>
<span style="font-size:12px;">R</span></td>
<td>
<span style="font-size: 12px;">0x</span><span style="font-size: 12px;">{R:X}</span></td>
</tr>
</tbody>
</table></body>
</html>
"""
def __init__(self, registers):
super(RegistersGUI, self).__init__()
vbox=QVBoxLayout()
self.setLayout(vbox)
self._view = QWebView()
vbox.addWidget(self._view)
#self.setPlainText("")
#self.setFontFamily("Mono")
#self.setFontPointSize(8)
#self._modifiers = {}
#self.setCursorWidth(0)
self._registers = registers
self._update_sgl.connect(self._update)
#self.setReadOnly(True)
self.setGeometry(100, 0, 200, 480)
self.update()
@Slot()
def update(self):
#print "WRITE ", address
self._update_sgl.emit()
def _update(self):
fields = {}
for f in "A,BC,DE,HL,SP,IX,IY,I,R,PC".split(","):
fields[f] = self._registers[f]
for b in ["S", "Z", "F5", "H", "F3", "PV", "N", "C"]:
fields["F{}".format(b)] = getattr(self._registers.condition, b)
self._view.setHtml(self.format_data.format(**fields))
class MemoryView(QWidget):
_update_sgl = Signal(int)
def __init__(self, memory, registers):
super(MemoryView, self).__init__()
self._modifiers = {}
self._page_height = 16
self._memory = memory
self._registers = registers
self._update_sgl.connect(self._update)
self._web_view = QWebView()
vbox = QVBoxLayout()
self.setLayout(vbox)
hbox = QHBoxLayout()
self._offset_entry = QLineEdit()
self._offset_entry.returnPressed.connect(self.address_change)
self._offset = 0x0
self._offset_entry.setText(hex(self._offset))
self._offset_next = QPushButton(">>")
self._offset_prev = QPushButton("<<")
self._offset_next.clicked.connect(self.on_next)
self._offset_prev.clicked.connect(self.on_prev)
hbox.addWidget(self._offset_entry)
hbox.addWidget(self._offset_prev)
hbox.addWidget(self._offset_next)
hbox.addStretch(1)
vbox.addLayout(hbox)
vbox.addWidget(self._web_view)
self.setGeometry(100, 580, 840, 480)
self.update()
def on_next(self):
self._offset += self._page_height * 16
self._offset_entry.setText(hex(self._offset))
self.update()
pass
def on_prev(self):
if self._offset < 1:
return
self._offset -= self._page_height * 16
self._offset_entry.setText(hex(self._offset))
self.update()
pass
def address_change(self):
new_val=self._offset_entry.text()
val=0
ln=0
try:
val=int(new_val,16)
ln=(val-(val%16))# * 16
pg = ln - ln%(self._page_height*16)
except:
return
self._offset_entry.setText(hex(pg))
self._offset=pg
self.update(val)
@Slot()
def update(self,highlight=-1):
self._update_sgl.emit(highlight)
def _update(self,highlight):
sp = self._registers.SP
txt = StringIO()
txt.write("<table><tr><td>Offset</td>")
for i in range(16):
txt.write("<td>{:X}</td>".format(i))
txt.write("<td>ASCII</td></tr>")
for i in range(self._offset, min(len(self._memory),
self._offset+16*self._page_height), 16):
txt.write("<tr>")
offset = i
txt.write("<td>{}</td>".format(hex(offset)))
ascii = ""
for j in range(16):
v = self._memory[offset+j]
if v > 31 and v < 127:
ascii += chr(self._memory[offset+j])
else:
ascii += "."
if offset+j == sp:
txt.write("<td style=\"color:red\">{:2X}</td>".format(v))
elif highlight > 0 and offset+j==highlight:
txt.write("<td style=\"color:blue\">{:2X}</td>".format(v))
else:
txt.write("<td>{:2X}</td>".format(v))
txt.write("<td><tt>{}</tt></td>".format(ascii))
txt.write("</tr>")
txt.write( "</table>")
text = txt.getvalue()
txt.close()
self._web_view.setHtml(text)
pass

2127
src/z80/instructions.py Normal file

File diff suppressed because it is too large Load Diff

105
src/z80/io.py Normal file
View File

@ -0,0 +1,105 @@
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class IO(object):
_addresses = []
def read(self, address):
pass
def write(self, address, value):
pass
class Interruptable(object):
def interrupt(self):
print "interrupt"
pass
class Console(QTextEdit, IO):
_addresses = [0x80, 0x81]
_wrt_sgnl = Signal(int, int)
def __init__(self, interruptable):
#assert isinstance(interruptable, Interruptable )
super(Console, self).__init__()
self.setPlainText("")
self.setFontFamily("Courier")
self.setFontPointSize(12)
self._modifiers = {}
self.setCursorWidth(0)
self._interruptable = interruptable
self._wrt_sgnl.connect(self._write)
self.setReadOnly(True)
self.setGeometry(300, 0, 640, 480)
self._send_queue = None
def read(self, address):
print "READ ", address
if address == 0x80:
v = ((1 << 1) | # RTS
((self._send_queue is not None) << 0) | # interrupt?
0 )
return v
elif address == 0x81:
if self._send_queue is not None:
val = self._send_queue
self._send_queue = None
return val
return 0x13
@Slot(int, int)
def write(self, address, value):
print "------> WRITE ", address
self._wrt_sgnl.emit(address, value)
def _write(self, address, value):
if address == 0x80:
pass
elif address == 0x81:
if value < 128 and value > 10:
self.setText(self.toPlainText()+chr(value))
else:
self.setText(self.toPlainText()+".")
else:
raise Exception("Trying Console IO with wrong address")
def keyPressEvent(self, event):
# print ("Event:", event)
if isinstance(event, QKeyEvent):
if event.key() > 255:
self._modifiers[event.key()] = True
#else:
#self.setText(self.toPlainText()+chr(event.key()))
if True:
super(QTextEdit, self).keyPressEvent(event)
def keyReleaseEvent(self, event):
# print ("Event:", event)
if isinstance(event, QKeyEvent):
key = event.key()
if key == Qt.Key_Return or event.key() == Qt.Key_Enter:
key = 13
if event.key() > 255:
self._modifiers[event.key()] = False
#print (key)
if self._send_queue is None:
self._send_queue = key
self._interruptable.interrupt()
pass
class IOMap(object):
def __init__(self):
self.address = {}
pass
def addDevice(self, dev):
assert isinstance(dev, IO)
for i in dev._addresses:
self.address[i] = dev
def interupt(self):
pass

93
src/z80/registers.py Normal file
View File

@ -0,0 +1,93 @@
class BitAccesser(object):
def __init__(self, bit_names, registers, reg):
object.__setattr__(self, "bits",
dict(zip(bit_names, range(7, -1, -1))))
self.registers = registers
#self.registers = registers
self.reg = reg
def __getattr__(self, b):
return (self.registers[self.reg] >> self.bits[b]) & 1
def __setattr__(self, b, v):
if not b in self.bits:
object.__setattr__(self, b, v)
return
if v:
self.registers[self.reg] = self.registers[self.reg] | (1 << self.bits[b])
else:
self.registers[self.reg] = self.registers[self.reg] & ((1 << self.bits[b]) ^ 0xFF)
class Registers(dict):
def __init__(self, *arg, **kw):
super(Registers, self).__init__(*arg, **kw)
self.reset()
def reset(self):
self["PC"] = 0 # Program Counter (16bit)
self["SP"] = 0 # Stack Pointer (16bit)
self["IX"] = 0 # Index Register X (16bit)
self["IY"] = 0 # Index Register Y (16bit)
self["I"] = 0 # Interrupt Page Address (8bit)
self["R"] = 0 # Memory Refresh (8bit)
self["A"] = 0 # Accumulator (8bit)
self["F"] = 0 # Flags (8bit)
self["A_"] = 0 # Alt. Accumulator (8bit)
self["F_"] = 0 # Alt. Flags (8bit)
self["B"] = 0 # General (8bit)
self["C"] = 0 # General (8bit)
self["B_"] = 0 # General (8bit)
self["C_"] = 0 # General (8bit)
self["D"] = 0 # General (8bit)
self["E"] = 0 # General (8bit)
self["D_"] = 0 # General (8bit)
self["E_"] = 0 # General (8bit)
self["H"] = 0 # General (8bit)
self["L"] = 0 # General (8bit)
self["H_"] = 0 # General (8bit)
self["L_"] = 0 # General (8bit)
self["condition"] = BitAccesser(["S", "Z", "F5", "H", "F3", "PV", "N", "C"], self, "F")
self['HALT']=False #
self['IFF']=False # Interrupt flip flop
self['IFF2']=False # NM Interrupt flip flop
self['IM']=False # Iterrupt mode
def __setattr__(self, attr, val):
if attr in ["HL", "AF", "BC", "DE"]:
self[attr[0]] = val >> 8
self[attr[1]] = val & 0xFF
else:
self[attr] = val
def __getattr__(self, reg):
if self.has_key(reg):
return self[reg]
elif reg in ["HL", "AF", "BC", "DE"]:
return self[reg[0]] << 8 | self[reg[1]]
else:
raise AttributeError("%s Not a known register."%reg)
def __getitem__(self, reg):
if reg in ["BC", "HL", "DE", "AF"]:
return getattr(self, reg)
else:
return super(Registers, self).__getitem__(reg)
def __setitem__(self, reg, val):
if reg in ["BC", "HL", "DE", "AF"]:
return setattr(self, reg, val)
else:
return super(Registers, self).__setitem__(reg, val)
@classmethod
def create(cls):
return cls()

297
src/z80/util.py Normal file
View File

@ -0,0 +1,297 @@
register_bits = {'A': 7, 'B': 0, 'C': 1, 'D': 2, 'E': 3, 'H': 4, 'L': 5}
index_bytes = [(0xDD, 'IX'), (0xfd, 'IY')]
# i, name, bit, val
conditions = [(0 << 3, 'NZ', 'Z', 0),
(1 << 3, 'Z', 'Z', 1),
(2 << 3, 'NC', 'C', 0),
(3 << 3, 'C', 'C', 1),
(4 << 3, 'PO', 'PV', 0),
(5 << 3, 'PE', 'PV', 1),
(6 << 3, 'P', 'S', 0),
(7 << 3, 'M', 'S', 1),]
def get_16bit_twos_comp(val):
""" Return the value of an 8bit 2s comp number"""
sg = val >> 15
if sg == 1:
mag = - ((val ^ 0xFFFF) + 1)
return mag
else:
return val
def get_8bit_twos_comp(val):
""" Return the value of an 8bit 2s comp number"""
sg = val >> 7
if sg == 1:
mag = - ((val ^ 0xFF) + 1)
return mag
else:
return val
def make_8bit_twos_comp(val):
if val > -1:
return val
val = (0 - val) ^ 0xFF
val += 1
return val
def subtract8(a, b, registers, S=True, N=True, Z=True,
F3=True, F5=True, H=True, PV=False, C=False):
""" subtract b from a, return result and set flags """
res = a - b
if S:
registers.condition.S = (res >> 7) & 0x01
if N:
registers.condition.N = 1
if Z:
registers.condition.Z = (res == 0)
if F3:
registers.condition.F3 = res & 0x08
if F5:
registers.condition.F5 = res & 0x20
if H:
if (b & 0xF) > (a & 0xF) :
registers.condition.H = 1
else:
registers.condition.H = 0
if PV:
#if (a >> 7 != b >> 7):
#if (b >> 7):
#if a > (a | (0x1 << 7)):
#registers.condition.PV = 1 # overflow
a = get_8bit_twos_comp(a)
b = get_8bit_twos_comp(b)
if (a - b) < -127 or (a - b) > 128:
registers.condition.PV = 1 # overflow
#if get_8bit_twos_comp(res) < -127 or get_8bit_twos_comp(res) > 128:
#registers.condition.PV = 1 # overflow
else:
registers.condition.PV = 0
if C:
registers.condition.C = res > 0xFF or res < 0
return res & 0xFF
def subtract8_check_overflow(a, b, registers):
return subtract8(a, b, registers, PV=True, C=True)
def add8(a, b, registers, S=True, Z=True, H=True,
PV=True, N=True, C=True, F3=True, F5=True):
""" add a and b, return result and set flags """
res = a + b
if S:
registers.condition.S = (res >> 7) & 0x01
if Z:
registers.condition.Z = (res & 0xFF == 0)
if H:
if ((a & 0xF) + (b & 0xF)) > 0xF :
registers.condition.H = 1
else:
registers.condition.H = 0
if PV:
if ((a >> 7) == (b >> 7) and (a >> 7) != ((res & 0xFF) >> 7)):
registers.condition.PV = 1 # overflow
else:
registers.condition.PV = 0
if N:
registers.condition.N = 0
if C:
registers.condition.C = res > 0xFF or res < 0
if F3:
registers.condition.F3 = res & 0x08
if F5:
registers.condition.F5 = res & 0x20
return res & 0xFF
def add16(a, b, registers):
""" add a and b, return result and set flags """
res = a + b
print a, "+",b,"=",res
registers.condition.S = (res >> 15) & 0x01
registers.condition.Z = (res == 0)
if ((a & 0xFFF) + (b & 0xFFF)) > 0xFFF :
registers.condition.H = 1
else:
registers.condition.H = 0
if ((a >> 15) == (b >> 15) and (a >> 15) != ((res & 0xFFFF) >> 15)):
registers.condition.PV = 1 # overflow
else:
registers.condition.PV = 0
registers.condition.N = 0
registers.condition.C = res >> 0xFFFF or res < 0
registers.condition.F3 = res & 0x0800
registers.condition.F5 = res & 0x2000
return res & 0xFFFF
def subtract16(a, b, registers):
""" subtract b from a, return result and set flags """
res = a - b
print a, "-", b, "=", res, "(", hex(res), ")"
registers.condition.S = (res >> 15) & 0x01
registers.condition.N = 1
registers.condition.Z = (res == 0)
registers.condition.F3 = res & 0x0800
registers.condition.F5 = res & 0x2000
if (b & 0xFFF) > (a & 0xFFF) :
registers.condition.H = 1
else:
registers.condition.H = 0
if (a >> 15 != (res&0xFFFF) >> 15):
registers.condition.PV = 1 # overflow
else:
registers.condition.PV = 0
registers.condition.C = res > 0xFFFF or res < 0
return res & 0xFFFF
def inc16(val):
val += 1
if val > 0xFFFF:
val = 0x0
return val
def dec16(val):
val -= 1
if val < 0:
val = 0xFFFF
return val
def inc8(val):
val += 1
if val > 0xFF:
val = 0x0
return val
def dec8(val):
val -= 1
if val < 0:
val = 0xFF
return val
def parity(n):
p=0
for i in range(0,8):
p+=(n >> i) & 0x01
return not (p % 2)
def a_and_n(registers, n):
registers.A = registers.A & n
registers.condition.H = 1
registers.condition.N = 0
registers.condition.PV = parity(registers.A)
registers.condition.C = 0
registers.condition.Z = (registers.A==0)
registers.condition.S = (registers.A>>7)
set_f5_f3_from_a(registers)
def a_or_n(registers, n):
registers.A = registers.A | n
registers.condition.H = 0
registers.condition.N = 0
registers.condition.PV = parity(registers.A)
registers.condition.C = 0
registers.condition.Z = (registers.A==0)
registers.condition.S = (registers.A>>7)
set_f5_f3_from_a(registers)
def a_xor_n(registers, n):
registers.A = registers.A ^ n
registers.condition.H = 0
registers.condition.N = 0
registers.condition.PV = parity(registers.A)
registers.condition.C = 0
registers.condition.Z = (registers.A==0)
registers.condition.S = (registers.A>>7)
set_f5_f3_from_a(registers)
def rotate_left_carry(registers, n):
c = n >> 7
v = (n << 1 | c) & 0xFF
registers.condition.S = v >> 7
registers.condition.Z = (v == 0)
registers.condition.H = 0
registers.condition.N = 0
registers.condition.PV = parity(v)
registers.condition.C = c
return v
def rotate_left(registers, n):
c = n >> 7
v = (n << 1 | registers.condition.C) & 0xFF
registers.condition.S = v >> 7
registers.condition.Z = (v == 0)
registers.condition.H = 0
registers.condition.N = 0
registers.condition.PV = parity(v)
registers.condition.C = c
return v
def rotate_right_carry(registers, n):
c = n & 0x01
v = n >> 1 | (c << 7)
registers.condition.S = v >> 7
registers.condition.Z = (v == 0)
registers.condition.H = 0
registers.condition.N = 0
registers.condition.PV = parity(v)
registers.condition.C = c
return v
def rotate_right(registers, n):
c = n & 0x01
v = n >> 1 | (registers.condition.C << 7)
registers.condition.S = v >> 7
registers.condition.Z = (v == 0)
registers.condition.H = 0
registers.condition.N = 0
registers.condition.PV = parity(v)
registers.condition.C = c
return v
def shift_left(registers, n):
c = n >> 7
v = (n << 1 ) & 0xFF
registers.condition.S = v >> 7
registers.condition.Z = (v == 0)
registers.condition.H = 0
registers.condition.N = 0
registers.condition.PV = parity(v)
registers.condition.C = c
return v
def shift_right(registers, n):
c = n & 0x01
msb = n >> 7
v = n >> 1 | (msb << 7)
registers.condition.S = v >> 7
registers.condition.Z = (v == 0)
registers.condition.H = 0
registers.condition.N = 0
registers.condition.PV = parity(v)
registers.condition.C = c
return v
def offset_pc(registers, jump):
registers.PC += get_8bit_twos_comp(jump)
if registers.PC > 0xFFFF:
registers.PC -= 0xFFFF - 1
if registers.PC < 0:
registers.PC += 0xFFFF + 1
def set_f5_f3(registers, v):
registers.condition.F5 = v & 0x20
registers.condition.F3 = v & 0x08
def set_f5_f3_from_a(registers):
set_f5_f3(registers, registers.A)

118
src/z80sbc.py Normal file
View File

@ -0,0 +1,118 @@
from z80 import util, io, gui, registers, instructions
import copy
from time import sleep, time
import sys
from PySide.QtCore import *
from PySide.QtGui import *
import threading
#logging.basicConfig(level=logging.INFO)
class Z80SBC(io.Interruptable):
def __init__(self):
self.registers = registers.Registers()
self.instructions = instructions.InstructionSet(self.registers)
self._memory = bytearray(64*1024)
self._read_rom("../roms/ROM.HEX")
self._iomap = io.IOMap()
self._console = io.Console(self)
self._reg_gui = gui.RegistersGUI(self.registers)
self._mem_view = gui.MemoryView(self._memory, self.registers)
self._iomap.addDevice(self._console)
self._console.show()
self._reg_gui.show()
self._mem_view.show()
self._interrupted = False
def interrupt(self):
self._interrupted = True
def _read_rom(self, romfile):
with open(romfile, "r") as f:
while True:
line = f.readline()
if line[0] != ":":
raise Exception("Bad start code in hex file.")
count = int(line[1:3], 16)#.decode("hex")
address = int(line[3:7], 16) #.decode("hex")
if address + count > len(self._memory):
raise Exception("Trying to create M2764 ROM with too large a ROM file")
rtype = line[7:9]
pos = 9
if rtype == "01":
break
for b in range(count):
byte = int(line[pos+(2*b):pos+(2*b)+2], 16) #. decode("hex")
self._memory[address+b] = byte
def step_instruction(self):
ins, args = False, []
pc = self.registers.PC
if self._interrupted and self.registers.IFF:
self.registers.IFF = False
self._interrupted = False
if self.registers.IM == 1:
print "!!! Interrupt !!!"
ins, args = self.instructions << 0xCD
ins, args = self.instructions << 0x38
ins, args = self.instructions << 0x00
self.registers.IFF = False
else:
while not ins:
ins, args = self.instructions << self._memory[self.registers.PC]
self.registers.PC = util.inc16(self.registers.PC)
#print( "{0:X} : {1} ".format(pc, ins.assembler(args)))
rd = ins.get_read_list(args)
data = [0] * len(rd)
for n, i in enumerate(rd):
if i < 0x10000:
data[n] = self._memory[i]
else:
address = i & 0xFF
data[n] = self._iomap.address[address].read(address)
wrt = ins.execute(data, args)
for i in wrt:
if i[0] > 0x10000:
address = i[0] & 0xFF
#iomap.address[address].write.emit(address, i[1])
self._iomap.address[address].write(address, i[1])
#print (chr(i[1]))
else:
self._memory[i[0]] = i[1]
return ins, args
if __name__ == '__main__':
''' Main Program '''
qt_app = QApplication(sys.argv)
mach = Z80SBC()
def worker():
t = time()
while True:
# t = time()
ins, args = mach.step_instruction()
print ins.assembler(args)
sleep(0.00000001)
# print (time() - t) / ins.tstates
# mach._mem_view.update()
# mach._reg_gui.update()
thread = threading.Thread(target=worker)
thread.setDaemon(True)
thread.start()
qt_app.exec_()