1
0
mirror of https://github.com/mnaberez/py65.git synced 2025-08-08 13:25:01 +00:00

first steps to support 65Org16 cpu

This commit is contained in:
BigEd
2011-08-19 17:40:07 +01:00
parent fc3cb0be34
commit 0eb140d6c1
4 changed files with 122 additions and 69 deletions

View File

@@ -17,11 +17,17 @@ class MPU:
ZERO = 2 ZERO = 2
CARRY = 1 CARRY = 1
def __init__(self, memory=None, pc=0x0000, debug=False): def __init__(self, memory=None, pc=0x0000, debug=False, byteWidth=8, addrWidth=16):
# config # config
self.debug = debug self.debug = debug
self.name = '6502' self.name = '6502'
self.byteWidth = byteWidth
self.byteMask = ((1<<byteWidth)-1)
self.addrWidth = addrWidth
self.addrMask = ((1<<addrWidth)-1)
self.addrHighMask = (self.byteMask<<byteWidth)
self.spBase = 1<<byteWidth
# vm status # vm status
self.excycles = 0 self.excycles = 0
self.addcycles = False self.addcycles = False
@@ -35,30 +41,32 @@ class MPU:
# init # init
self.reset() self.reset()
def reprformat(self):
return ("%s PC AC XR YR SP NV-BDIZC\n" + \
"%s: %04x %02x %02x %02x %02x %s"
)
def __repr__(self): def __repr__(self):
flags = itoa(self.p, 2).rjust(8, '0') flags = itoa(self.p, 2).rjust(self.byteWidth, '0')
indent = ' ' * (len(self.name) + 2) indent = ' ' * (len(self.name) + 2)
out = "%s PC AC XR YR SP NV-BDIZC\n" + \ return self.reprformat() % (indent, self.name,
"%s: %04x %02x %02x %02x %02x %s"
return out % (indent, self.name,
self.pc, self.a, self.x, self.y, self.sp, flags) self.pc, self.a, self.x, self.y, self.sp, flags)
def step(self): def step(self):
instructCode = self.ImmediateByte() instructCode = self.ImmediateByte()
self.pc +=1 self.pc +=1
self.pc &=0xffff self.pc &=self.addrMask
self.excycles = 0 self.excycles = 0
self.addcycles = self.extracycles[instructCode] self.addcycles = self.extracycles[instructCode]
self.instruct[instructCode](self) self.instruct[instructCode](self)
self.processorCycles += self.cycletime[instructCode]+self.excycles self.processorCycles += self.cycletime[instructCode]+self.excycles
self.pc &= 0xffff self.pc &= self.addrMask
return self return self
def reset(self): def reset(self):
self.pc = self.start_pc self.pc = self.start_pc
self.sp = 255 self.sp = self.byteMask
self.a = 0 self.a = 0
self.x = 0 self.x = 0
self.y = 0 self.y = 0
@@ -71,11 +79,11 @@ class MPU:
return self.memory[addr] return self.memory[addr]
def WordAt(self, addr): def WordAt(self, addr):
return self.ByteAt(addr) + (self.ByteAt(addr + 1) << 8) return self.ByteAt(addr) + (self.ByteAt(addr + 1) << self.byteWidth)
def WrapAt(self, addr): def WrapAt(self, addr):
wrap = lambda x: (x & 0xff00) + ((x + 1) & 0xff) wrap = lambda x: (x & self.addrHighMask) + ((x + 1) & self.byteMask)
return self.ByteAt(addr) + (self.ByteAt(wrap(addr)) << 8) return self.ByteAt(addr) + (self.ByteAt(wrap(addr)) << self.byteWidth)
def ProgramCounter(self): def ProgramCounter(self):
return self.pc return self.pc
@@ -89,23 +97,23 @@ class MPU:
return self.ByteAt(self.pc) return self.ByteAt(self.pc)
def ZeroPageXAddr(self): def ZeroPageXAddr(self):
return 255 & (self.x + self.ByteAt(self.pc)) return self.byteMask & (self.x + self.ByteAt(self.pc))
def ZeroPageYAddr(self): def ZeroPageYAddr(self):
return 255 & (self.y + self.ByteAt(self.pc)) return self.byteMask & (self.y + self.ByteAt(self.pc))
def IndirectXAddr(self): def IndirectXAddr(self):
return self.WrapAt( 255 & (self.ByteAt(self.pc) + self.x)) return self.WrapAt( self.byteMask & (self.ByteAt(self.pc) + self.x))
def IndirectYAddr(self): def IndirectYAddr(self):
if self.addcycles: if self.addcycles:
a1 = self.WrapAt(self.ByteAt(self.pc)) a1 = self.WrapAt(self.ByteAt(self.pc))
a2 = (a1+self.y) & 0xffff a2 = (a1+self.y) & self.addrMask
if (a1 & 0xff00) != (a2 & 0xff00): if (a1 & self.addrHighMask) != (a2 & self.addrHighMask):
self.excycles += 1 self.excycles += 1
return a2 return a2
else: else:
return (self.WrapAt(self.ByteAt(self.pc))+self.y)&0xffff return (self.WrapAt(self.ByteAt(self.pc))+self.y)&self.addrMask
def AbsoluteAddr(self): def AbsoluteAddr(self):
return self.WordAt(self.pc) return self.WordAt(self.pc)
@@ -113,57 +121,57 @@ class MPU:
def AbsoluteXAddr(self): def AbsoluteXAddr(self):
if self.addcycles: if self.addcycles:
a1 = self.WordAt(self.pc) a1 = self.WordAt(self.pc)
a2 = (a1 + self.x) & 0xffff a2 = (a1 + self.x) & self.addrMask
if (a1 & 0xff00) != (a2 & 0xff00): if (a1 & self.addrHighMask) != (a2 & self.addrHighMask):
self.excycles += 1 self.excycles += 1
return a2 return a2
else: else:
return (self.WordAt(self.pc)+self.x)&0xffff return (self.WordAt(self.pc)+self.x)&self.addrMask
def AbsoluteYAddr(self): def AbsoluteYAddr(self):
if self.addcycles: if self.addcycles:
a1 = self.WordAt(self.pc) a1 = self.WordAt(self.pc)
a2 = (a1 + self.y) & 0xffff a2 = (a1 + self.y) & self.addrMask
if (a1 & 0xff00) != (a2 & 0xff00): if (a1 & self.addrHighMask) != (a2 & self.addrHighMask):
self.excycles += 1 self.excycles += 1
return a2 return a2
else: else:
return (self.WordAt(self.pc)+self.y)&0xffff return (self.WordAt(self.pc)+self.y)&self.addrMask
def BranchRelAddr(self): def BranchRelAddr(self):
self.excycles += 1 self.excycles += 1
addr = self.ImmediateByte() addr = self.ImmediateByte()
self.pc += 1 self.pc += 1
if addr & 128: if addr & self.NEGATIVE:
addr = self.pc - (addr ^ 0xFF) - 1 addr = self.pc - (addr ^ self.byteMask) - 1
else: else:
addr = self.pc + addr addr = self.pc + addr
if (self.pc & 0xff00) != (addr & 0xff00): if (self.pc & self.addrHighMask) != (addr & self.addrHighMask):
self.excycles += 1 self.excycles += 1
self.pc = addr & 0xffff self.pc = addr & self.addrMask
# stack # stack
def stPush(self,z): def stPush(self,z):
self.memory[self.sp+256] = z&255 self.memory[self.sp+self.spBase] = z&self.byteMask
self.sp -= 1 self.sp -= 1
self.sp &= 255 self.sp &= self.byteMask
def stPop(self): def stPop(self):
self.sp += 1 self.sp += 1
self.sp &= 255 self.sp &= self.byteMask
return self.ByteAt(self.sp+256) return self.ByteAt(self.sp+self.spBase)
def stPushWord(self, z): def stPushWord(self, z):
self.stPush((z>>8)&255) self.stPush((z>>self.byteWidth)&self.byteMask)
self.stPush(z&255) self.stPush(z&self.byteMask)
def stPopWord(self): def stPopWord(self):
z = self.stPop() z = self.stPop()
z += 256*self.stPop() z += self.stPop()<<self.byteWidth
return z return z
def FlagsNZ(self, value): def FlagsNZ(self, value):
@@ -188,12 +196,12 @@ class MPU:
self.p &= ~(self.CARRY + self.NEGATIVE + self.ZERO) self.p &= ~(self.CARRY + self.NEGATIVE + self.ZERO)
if tbyte & 128: if tbyte & self.NEGATIVE:
self.p |= self.CARRY self.p |= self.CARRY
tbyte = (tbyte << 1) & 0xFF tbyte = (tbyte << 1) & self.byteMask
if tbyte: if tbyte:
self.p |= tbyte & 128 self.p |= tbyte & self.NEGATIVE
else: else:
self.p |= self.ZERO self.p |= self.ZERO
@@ -250,7 +258,7 @@ class MPU:
self.p &=~(self.ZERO+self.NEGATIVE+self.OVERFLOW) self.p &=~(self.ZERO+self.NEGATIVE+self.OVERFLOW)
if (self.a & tbyte) == 0: if (self.a & tbyte) == 0:
self.p |= self.ZERO self.p |= self.ZERO
self.p |= tbyte&(128+64) self.p |= tbyte&(self.NEGATIVE+self.OVERFLOW)
def opROL(self, x): def opROL(self, x):
if x is None: if x is None:
@@ -260,16 +268,16 @@ class MPU:
tbyte = self.ByteAt(addr) tbyte = self.ByteAt(addr)
if self.p & self.CARRY: if self.p & self.CARRY:
if tbyte & 128: if tbyte & self.NEGATIVE:
pass pass
else: else:
self.p &= ~self.CARRY self.p &= ~self.CARRY
tbyte = (tbyte << 1) | 1 tbyte = (tbyte << 1) | 1
else: else:
if tbyte & 128: if tbyte & self.NEGATIVE:
self.p |= self.CARRY self.p |= self.CARRY
tbyte = tbyte << 1 tbyte = tbyte << 1
tbyte &= 0xFF tbyte &= self.byteMask
self.FlagsNZ(tbyte) self.FlagsNZ(tbyte)
if x is None: if x is None:
@@ -313,7 +321,7 @@ class MPU:
self.p |= aluresult & self.NEGATIVE self.p |= aluresult & self.NEGATIVE
if decimalcarry == 1: if decimalcarry == 1:
self.p |= self.CARRY self.p |= self.CARRY
if ( ~(self.a ^ data) & (self.a ^ aluresult) ) & 0x80: if ( ~(self.a ^ data) & (self.a ^ aluresult) ) & self.NEGATIVE:
self.p |= self.OVERFLOW self.p |= self.OVERFLOW
self.a = (nibble1 << 4) + nibble0 self.a = (nibble1 << 4) + nibble0
else: else:
@@ -323,12 +331,12 @@ class MPU:
tmp = 0 tmp = 0
result = data + self.a + tmp result = data + self.a + tmp
self.p &= ~(self.CARRY+self.OVERFLOW+self.NEGATIVE+self.ZERO) self.p &= ~(self.CARRY+self.OVERFLOW+self.NEGATIVE+self.ZERO)
if ( ~(self.a ^ data) & (self.a ^ result) ) & 0x80: if ( ~(self.a ^ data) & (self.a ^ result) ) & self.NEGATIVE:
self.p |= self.OVERFLOW self.p |= self.OVERFLOW
data = result data = result
if data > 255: if data > self.byteMask:
self.p |= self.CARRY self.p |= self.CARRY
data &=255 data &=self.byteMask
if data == 0: if data == 0:
self.p |= self.ZERO self.p |= self.ZERO
else: else:
@@ -347,7 +355,7 @@ class MPU:
pass # {} pass # {}
else: else:
self.p &=~ self.CARRY self.p &=~ self.CARRY
tbyte=(tbyte>>1)|128 tbyte=(tbyte>>1)|self.NEGATIVE
else: else:
if tbyte & 1: if tbyte & 1:
self.p |= self.CARRY self.p |= self.CARRY
@@ -395,10 +403,10 @@ class MPU:
adjust1 = 10 << 4 adjust1 = 10 << 4
# the ALU outputs are not decimally adjusted # the ALU outputs are not decimally adjusted
aluresult = self.a + (~data & 0xFF) + (self.p & self.CARRY) aluresult = self.a + (~data & self.byteMask) + (self.p & self.CARRY)
if aluresult > 0xff: if aluresult > self.byteMask:
decimalcarry = 1 decimalcarry = 1
aluresult &= 0xff aluresult &= self.byteMask
# but the final result will be adjusted # but the final result will be adjusted
nibble0 = (aluresult + adjust0) & 0xf nibble0 = (aluresult + adjust0) & 0xf
@@ -411,7 +419,7 @@ class MPU:
self.p |= aluresult & self.NEGATIVE self.p |= aluresult & self.NEGATIVE
if decimalcarry == 1: if decimalcarry == 1:
self.p |= self.CARRY self.p |= self.CARRY
if ( (self.a ^ data) & (self.a ^ aluresult) ) & 0x80: if ( (self.a ^ data) & (self.a ^ aluresult) ) & self.NEGATIVE:
self.p |= self.OVERFLOW self.p |= self.OVERFLOW
self.a = (nibble1 << 4) + nibble0 self.a = (nibble1 << 4) + nibble0
else: else:
@@ -420,11 +428,11 @@ class MPU:
else: else:
borrow = 1 borrow = 1
result = self.a + (~data & 0xFF) + (self.p & self.CARRY) result = self.a + (~data & self.byteMask) + (self.p & self.CARRY)
self.p &= ~(self.CARRY + self.ZERO + self.OVERFLOW + self.NEGATIVE) self.p &= ~(self.CARRY + self.ZERO + self.OVERFLOW + self.NEGATIVE)
if ( (self.a ^ data) & (self.a ^ result) ) & 0x80: if ( (self.a ^ data) & (self.a ^ result) ) & self.NEGATIVE:
self.p |= self.OVERFLOW self.p |= self.OVERFLOW
data = result & 0xFF data = result & self.byteMask
if data == 0: if data == 0:
self.p |= self.ZERO self.p |= self.ZERO
if result & 0x100: if result & 0x100:
@@ -440,7 +448,7 @@ class MPU:
tbyte = self.ByteAt(addr) tbyte = self.ByteAt(addr)
self.p &= ~(self.ZERO + self.NEGATIVE) self.p &= ~(self.ZERO + self.NEGATIVE)
tbyte = (tbyte - 1) & 0xFF tbyte = (tbyte - 1) & self.byteMask
if tbyte: if tbyte:
self.p |= tbyte & self.NEGATIVE self.p |= tbyte & self.NEGATIVE
else: else:
@@ -459,7 +467,7 @@ class MPU:
tbyte = self.ByteAt(addr) tbyte = self.ByteAt(addr)
self.p &= ~(self.ZERO + self.NEGATIVE) self.p &= ~(self.ZERO + self.NEGATIVE)
tbyte = (tbyte + 1) & 0xFF tbyte = (tbyte + 1) & self.byteMask
if tbyte: if tbyte:
self.p |= tbyte & self.NEGATIVE self.p |= tbyte & self.NEGATIVE
else: else:
@@ -499,7 +507,7 @@ class MPU:
@instruction(name="BRK", mode="imp", cycles=7) @instruction(name="BRK", mode="imp", cycles=7)
def inst_0x00(self): def inst_0x00(self):
pc = (self.pc + 1) & 0xFFFF # The pc has already been increased one pc = (self.pc + 1) & self.addrMask # The pc has already been increased one
self.stPushWord(pc) self.stPushWord(pc)
self.p |= self.BREAK self.p |= self.BREAK
@@ -586,7 +594,7 @@ class MPU:
@instruction(name="JSR", mode="abs", cycles=6) @instruction(name="JSR", mode="abs", cycles=6)
def inst_0x20(self): def inst_0x20(self):
self.stPushWord((self.pc+1)&0xffff) self.stPushWord((self.pc+1)&self.addrMask)
self.pc=self.WordAt(self.pc) self.pc=self.WordAt(self.pc)
@instruction(name="AND", mode="inx", cycles=6) @instruction(name="AND", mode="inx", cycles=6)
@@ -870,7 +878,7 @@ class MPU:
@instruction(name="DEY", mode="imp", cycles=2) @instruction(name="DEY", mode="imp", cycles=2)
def inst_0x88(self): def inst_0x88(self):
self.y -= 1 self.y -= 1
self.y&=255 self.y&=self.byteMask
self.FlagsNZ(self.y) self.FlagsNZ(self.y)
@instruction(name="TXA", mode="imp", cycles=2) @instruction(name="TXA", mode="imp", cycles=2)
@@ -1077,7 +1085,7 @@ class MPU:
@instruction(name="INY", mode="imp", cycles=2) @instruction(name="INY", mode="imp", cycles=2)
def inst_0xc8(self): def inst_0xc8(self):
self.y += 1 self.y += 1
self.y &= 255 self.y &= self.byteMask
self.FlagsNZ(self.y) self.FlagsNZ(self.y)
@instruction(name="CMP", mode="imm", cycles=2) @instruction(name="CMP", mode="imm", cycles=2)
@@ -1088,7 +1096,7 @@ class MPU:
@instruction(name="DEX", mode="imp", cycles=2) @instruction(name="DEX", mode="imp", cycles=2)
def inst_0xca(self): def inst_0xca(self):
self.x -= 1 self.x -= 1
self.x &= 255 self.x &= self.byteMask
self.FlagsNZ(self.x) self.FlagsNZ(self.x)
@instruction(name="CPY", mode="abs", cycles=4) @instruction(name="CPY", mode="abs", cycles=4)
@@ -1172,7 +1180,7 @@ class MPU:
@instruction(name="INX", mode="imp", cycles=2) @instruction(name="INX", mode="imp", cycles=2)
def inst_0xe8(self): def inst_0xe8(self):
self.x+=1 self.x+=1
self.x&=255 self.x&=self.byteMask
self.FlagsNZ(self.x) self.FlagsNZ(self.x)
@instruction(name="SBC", mode="imm", cycles=2) @instruction(name="SBC", mode="imm", cycles=2)
@@ -1236,4 +1244,3 @@ class MPU:
def inst_0xfe(self): def inst_0xfe(self):
self.opINCR(self.AbsoluteXAddr) self.opINCR(self.AbsoluteXAddr)
self.pc += 2 self.pc += 2

View File

@@ -0,0 +1,32 @@
from py65.devices import mpu6502
from py65.utils.devices import make_instruction_decorator
class MPU(mpu6502.MPU):
def __init__(self, byteWidth=16, addrWidth=32, *args, **kwargs):
mpu6502.MPU.__init__(self, byteWidth=byteWidth, addrWidth=addrWidth, *args, **kwargs)
self.name = '65Org16'
self.waiting = False
self.IrqTo = (1<<self.addrWidth)-2
self.ResetTo = (1<<self.addrWidth)-4
self.NMITo = (1<<self.addrWidth)-6
self.NEGATIVE = 1 << 15
self.OVERFLOW = 1 << 14
def step(self):
if self.waiting:
self.processorCycles += 1
else:
mpu6502.MPU.step(self)
return self
# Make copies of the lists
instruct = mpu6502.MPU.instruct[:]
cycletime = mpu6502.MPU.cycletime[:]
extracycles = mpu6502.MPU.extracycles[:]
disassemble = mpu6502.MPU.disassemble[:]
def reprformat(self):
return ("%s PC AC XR YR SP NV---------BDIZC\n" + \
"%s: %08x %04x %04x %04x %04x %s"
)

View File

@@ -1,8 +1,21 @@
# this sparse array module only needed for large-memory CPU models
try:
from blist import *
except ImportError:
pass
class ObservableMemory: class ObservableMemory:
def __init__(self, subject=None): def __init__(self, subject=None, addrWidth=16):
if subject is None: if subject is None:
subject = 0x10000 * [0x00] if addrWidth <= 16:
subject = 0x10000 * [0x00]
else:
try:
subject = blist([0]) * (1 << addrWidth)
except:
print "Fatal: failed to initialise large memory for this CPU"
exit (1)
self._subject = subject self._subject = subject
self._read_subscribers = {} self._read_subscribers = {}

View File

@@ -8,6 +8,7 @@ import sys
from asyncore import compact_traceback from asyncore import compact_traceback
from py65.devices.mpu6502 import MPU as NMOS6502 from py65.devices.mpu6502 import MPU as NMOS6502
from py65.devices.mpu65c02 import MPU as CMOS65C02 from py65.devices.mpu65c02 import MPU as CMOS65C02
from py65.devices.mpu65Org16 import MPU as V65Org16
from py65.disassembler import Disassembler from py65.disassembler import Disassembler
from py65.assembler import Assembler from py65.assembler import Assembler
from py65.utils.addressing import AddressParser from py65.utils.addressing import AddressParser
@@ -112,7 +113,7 @@ class Monitor(cmd.Cmd):
byte = 0 byte = 0
return byte return byte
m = ObservableMemory() m = ObservableMemory(addrWidth=self._mpu.addrWidth)
m.subscribe_to_write([0xF001], putc) m.subscribe_to_write([0xF001], putc)
m.subscribe_to_read([0xF004], getc) m.subscribe_to_read([0xF004], getc)
@@ -147,7 +148,7 @@ class Monitor(cmd.Cmd):
self._reset(mpu_type=klass) self._reset(mpu_type=klass)
def do_mpu(self, args): def do_mpu(self, args):
mpus = {'6502': NMOS6502, '65C02': CMOS65C02} mpus = {'6502': NMOS6502, '65C02': CMOS65C02, '65Org16': V65Org16}
def available_mpus(): def available_mpus():
mpu_list = ', '.join(mpus.keys()) mpu_list = ', '.join(mpus.keys())
@@ -157,7 +158,7 @@ class Monitor(cmd.Cmd):
self._output("Current MPU is %s" % self._mpu.name) self._output("Current MPU is %s" % self._mpu.name)
available_mpus() available_mpus()
else: else:
requested = args.upper() requested = args
new_mpu = mpus.get(requested, None) new_mpu = mpus.get(requested, None)
if new_mpu is None: if new_mpu is None:
self._output("Unknown MPU: %s" % args) self._output("Unknown MPU: %s" % args)