mirror of
https://github.com/mnaberez/py65.git
synced 2025-04-08 19:40:03 +00:00
first steps to support 65Org16 cpu
This commit is contained in:
parent
fc3cb0be34
commit
0eb140d6c1
src/py65
@ -17,11 +17,17 @@ class MPU:
|
||||
ZERO = 2
|
||||
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
|
||||
self.debug = debug
|
||||
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
|
||||
self.excycles = 0
|
||||
self.addcycles = False
|
||||
@ -35,30 +41,32 @@ class MPU:
|
||||
# init
|
||||
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):
|
||||
flags = itoa(self.p, 2).rjust(8, '0')
|
||||
flags = itoa(self.p, 2).rjust(self.byteWidth, '0')
|
||||
indent = ' ' * (len(self.name) + 2)
|
||||
|
||||
out = "%s PC AC XR YR SP NV-BDIZC\n" + \
|
||||
"%s: %04x %02x %02x %02x %02x %s"
|
||||
|
||||
return out % (indent, self.name,
|
||||
return self.reprformat() % (indent, self.name,
|
||||
self.pc, self.a, self.x, self.y, self.sp, flags)
|
||||
|
||||
def step(self):
|
||||
instructCode = self.ImmediateByte()
|
||||
self.pc +=1
|
||||
self.pc &=0xffff
|
||||
self.pc &=self.addrMask
|
||||
self.excycles = 0
|
||||
self.addcycles = self.extracycles[instructCode]
|
||||
self.instruct[instructCode](self)
|
||||
self.processorCycles += self.cycletime[instructCode]+self.excycles
|
||||
self.pc &= 0xffff
|
||||
self.pc &= self.addrMask
|
||||
return self
|
||||
|
||||
def reset(self):
|
||||
self.pc = self.start_pc
|
||||
self.sp = 255
|
||||
self.sp = self.byteMask
|
||||
self.a = 0
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
@ -71,11 +79,11 @@ class MPU:
|
||||
return self.memory[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):
|
||||
wrap = lambda x: (x & 0xff00) + ((x + 1) & 0xff)
|
||||
return self.ByteAt(addr) + (self.ByteAt(wrap(addr)) << 8)
|
||||
wrap = lambda x: (x & self.addrHighMask) + ((x + 1) & self.byteMask)
|
||||
return self.ByteAt(addr) + (self.ByteAt(wrap(addr)) << self.byteWidth)
|
||||
|
||||
def ProgramCounter(self):
|
||||
return self.pc
|
||||
@ -89,23 +97,23 @@ class MPU:
|
||||
return self.ByteAt(self.pc)
|
||||
|
||||
def ZeroPageXAddr(self):
|
||||
return 255 & (self.x + self.ByteAt(self.pc))
|
||||
return self.byteMask & (self.x + self.ByteAt(self.pc))
|
||||
|
||||
def ZeroPageYAddr(self):
|
||||
return 255 & (self.y + self.ByteAt(self.pc))
|
||||
return self.byteMask & (self.y + self.ByteAt(self.pc))
|
||||
|
||||
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):
|
||||
if self.addcycles:
|
||||
a1 = self.WrapAt(self.ByteAt(self.pc))
|
||||
a2 = (a1+self.y) & 0xffff
|
||||
if (a1 & 0xff00) != (a2 & 0xff00):
|
||||
a2 = (a1+self.y) & self.addrMask
|
||||
if (a1 & self.addrHighMask) != (a2 & self.addrHighMask):
|
||||
self.excycles += 1
|
||||
return a2
|
||||
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):
|
||||
return self.WordAt(self.pc)
|
||||
@ -113,57 +121,57 @@ class MPU:
|
||||
def AbsoluteXAddr(self):
|
||||
if self.addcycles:
|
||||
a1 = self.WordAt(self.pc)
|
||||
a2 = (a1 + self.x) & 0xffff
|
||||
if (a1 & 0xff00) != (a2 & 0xff00):
|
||||
a2 = (a1 + self.x) & self.addrMask
|
||||
if (a1 & self.addrHighMask) != (a2 & self.addrHighMask):
|
||||
self.excycles += 1
|
||||
return a2
|
||||
else:
|
||||
return (self.WordAt(self.pc)+self.x)&0xffff
|
||||
return (self.WordAt(self.pc)+self.x)&self.addrMask
|
||||
|
||||
def AbsoluteYAddr(self):
|
||||
if self.addcycles:
|
||||
a1 = self.WordAt(self.pc)
|
||||
a2 = (a1 + self.y) & 0xffff
|
||||
if (a1 & 0xff00) != (a2 & 0xff00):
|
||||
a2 = (a1 + self.y) & self.addrMask
|
||||
if (a1 & self.addrHighMask) != (a2 & self.addrHighMask):
|
||||
self.excycles += 1
|
||||
return a2
|
||||
else:
|
||||
return (self.WordAt(self.pc)+self.y)&0xffff
|
||||
return (self.WordAt(self.pc)+self.y)&self.addrMask
|
||||
|
||||
def BranchRelAddr(self):
|
||||
self.excycles += 1
|
||||
addr = self.ImmediateByte()
|
||||
self.pc += 1
|
||||
|
||||
if addr & 128:
|
||||
addr = self.pc - (addr ^ 0xFF) - 1
|
||||
if addr & self.NEGATIVE:
|
||||
addr = self.pc - (addr ^ self.byteMask) - 1
|
||||
else:
|
||||
addr = self.pc + addr
|
||||
|
||||
if (self.pc & 0xff00) != (addr & 0xff00):
|
||||
if (self.pc & self.addrHighMask) != (addr & self.addrHighMask):
|
||||
self.excycles += 1
|
||||
|
||||
self.pc = addr & 0xffff
|
||||
self.pc = addr & self.addrMask
|
||||
|
||||
# stack
|
||||
|
||||
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 &= 255
|
||||
self.sp &= self.byteMask
|
||||
|
||||
def stPop(self):
|
||||
self.sp += 1
|
||||
self.sp &= 255
|
||||
return self.ByteAt(self.sp+256)
|
||||
self.sp &= self.byteMask
|
||||
return self.ByteAt(self.sp+self.spBase)
|
||||
|
||||
def stPushWord(self, z):
|
||||
self.stPush((z>>8)&255)
|
||||
self.stPush(z&255)
|
||||
self.stPush((z>>self.byteWidth)&self.byteMask)
|
||||
self.stPush(z&self.byteMask)
|
||||
|
||||
def stPopWord(self):
|
||||
z = self.stPop()
|
||||
z += 256*self.stPop()
|
||||
z += self.stPop()<<self.byteWidth
|
||||
return z
|
||||
|
||||
def FlagsNZ(self, value):
|
||||
@ -188,12 +196,12 @@ class MPU:
|
||||
|
||||
self.p &= ~(self.CARRY + self.NEGATIVE + self.ZERO)
|
||||
|
||||
if tbyte & 128:
|
||||
if tbyte & self.NEGATIVE:
|
||||
self.p |= self.CARRY
|
||||
tbyte = (tbyte << 1) & 0xFF
|
||||
tbyte = (tbyte << 1) & self.byteMask
|
||||
|
||||
if tbyte:
|
||||
self.p |= tbyte & 128
|
||||
self.p |= tbyte & self.NEGATIVE
|
||||
else:
|
||||
self.p |= self.ZERO
|
||||
|
||||
@ -250,7 +258,7 @@ class MPU:
|
||||
self.p &=~(self.ZERO+self.NEGATIVE+self.OVERFLOW)
|
||||
if (self.a & tbyte) == 0:
|
||||
self.p |= self.ZERO
|
||||
self.p |= tbyte&(128+64)
|
||||
self.p |= tbyte&(self.NEGATIVE+self.OVERFLOW)
|
||||
|
||||
def opROL(self, x):
|
||||
if x is None:
|
||||
@ -260,16 +268,16 @@ class MPU:
|
||||
tbyte = self.ByteAt(addr)
|
||||
|
||||
if self.p & self.CARRY:
|
||||
if tbyte & 128:
|
||||
if tbyte & self.NEGATIVE:
|
||||
pass
|
||||
else:
|
||||
self.p &= ~self.CARRY
|
||||
tbyte = (tbyte << 1) | 1
|
||||
else:
|
||||
if tbyte & 128:
|
||||
if tbyte & self.NEGATIVE:
|
||||
self.p |= self.CARRY
|
||||
tbyte = tbyte << 1
|
||||
tbyte &= 0xFF
|
||||
tbyte &= self.byteMask
|
||||
self.FlagsNZ(tbyte)
|
||||
|
||||
if x is None:
|
||||
@ -313,7 +321,7 @@ class MPU:
|
||||
self.p |= aluresult & self.NEGATIVE
|
||||
if decimalcarry == 1:
|
||||
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.a = (nibble1 << 4) + nibble0
|
||||
else:
|
||||
@ -323,12 +331,12 @@ class MPU:
|
||||
tmp = 0
|
||||
result = data + self.a + tmp
|
||||
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
|
||||
data = result
|
||||
if data > 255:
|
||||
if data > self.byteMask:
|
||||
self.p |= self.CARRY
|
||||
data &=255
|
||||
data &=self.byteMask
|
||||
if data == 0:
|
||||
self.p |= self.ZERO
|
||||
else:
|
||||
@ -347,7 +355,7 @@ class MPU:
|
||||
pass # {}
|
||||
else:
|
||||
self.p &=~ self.CARRY
|
||||
tbyte=(tbyte>>1)|128
|
||||
tbyte=(tbyte>>1)|self.NEGATIVE
|
||||
else:
|
||||
if tbyte & 1:
|
||||
self.p |= self.CARRY
|
||||
@ -395,10 +403,10 @@ class MPU:
|
||||
adjust1 = 10 << 4
|
||||
|
||||
# the ALU outputs are not decimally adjusted
|
||||
aluresult = self.a + (~data & 0xFF) + (self.p & self.CARRY)
|
||||
if aluresult > 0xff:
|
||||
aluresult = self.a + (~data & self.byteMask) + (self.p & self.CARRY)
|
||||
if aluresult > self.byteMask:
|
||||
decimalcarry = 1
|
||||
aluresult &= 0xff
|
||||
aluresult &= self.byteMask
|
||||
|
||||
# but the final result will be adjusted
|
||||
nibble0 = (aluresult + adjust0) & 0xf
|
||||
@ -411,7 +419,7 @@ class MPU:
|
||||
self.p |= aluresult & self.NEGATIVE
|
||||
if decimalcarry == 1:
|
||||
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.a = (nibble1 << 4) + nibble0
|
||||
else:
|
||||
@ -420,11 +428,11 @@ class MPU:
|
||||
else:
|
||||
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)
|
||||
if ( (self.a ^ data) & (self.a ^ result) ) & 0x80:
|
||||
if ( (self.a ^ data) & (self.a ^ result) ) & self.NEGATIVE:
|
||||
self.p |= self.OVERFLOW
|
||||
data = result & 0xFF
|
||||
data = result & self.byteMask
|
||||
if data == 0:
|
||||
self.p |= self.ZERO
|
||||
if result & 0x100:
|
||||
@ -440,7 +448,7 @@ class MPU:
|
||||
tbyte = self.ByteAt(addr)
|
||||
|
||||
self.p &= ~(self.ZERO + self.NEGATIVE)
|
||||
tbyte = (tbyte - 1) & 0xFF
|
||||
tbyte = (tbyte - 1) & self.byteMask
|
||||
if tbyte:
|
||||
self.p |= tbyte & self.NEGATIVE
|
||||
else:
|
||||
@ -459,7 +467,7 @@ class MPU:
|
||||
tbyte = self.ByteAt(addr)
|
||||
|
||||
self.p &= ~(self.ZERO + self.NEGATIVE)
|
||||
tbyte = (tbyte + 1) & 0xFF
|
||||
tbyte = (tbyte + 1) & self.byteMask
|
||||
if tbyte:
|
||||
self.p |= tbyte & self.NEGATIVE
|
||||
else:
|
||||
@ -499,7 +507,7 @@ class MPU:
|
||||
|
||||
@instruction(name="BRK", mode="imp", cycles=7)
|
||||
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.p |= self.BREAK
|
||||
@ -586,7 +594,7 @@ class MPU:
|
||||
|
||||
@instruction(name="JSR", mode="abs", cycles=6)
|
||||
def inst_0x20(self):
|
||||
self.stPushWord((self.pc+1)&0xffff)
|
||||
self.stPushWord((self.pc+1)&self.addrMask)
|
||||
self.pc=self.WordAt(self.pc)
|
||||
|
||||
@instruction(name="AND", mode="inx", cycles=6)
|
||||
@ -870,7 +878,7 @@ class MPU:
|
||||
@instruction(name="DEY", mode="imp", cycles=2)
|
||||
def inst_0x88(self):
|
||||
self.y -= 1
|
||||
self.y&=255
|
||||
self.y&=self.byteMask
|
||||
self.FlagsNZ(self.y)
|
||||
|
||||
@instruction(name="TXA", mode="imp", cycles=2)
|
||||
@ -1077,7 +1085,7 @@ class MPU:
|
||||
@instruction(name="INY", mode="imp", cycles=2)
|
||||
def inst_0xc8(self):
|
||||
self.y += 1
|
||||
self.y &= 255
|
||||
self.y &= self.byteMask
|
||||
self.FlagsNZ(self.y)
|
||||
|
||||
@instruction(name="CMP", mode="imm", cycles=2)
|
||||
@ -1088,7 +1096,7 @@ class MPU:
|
||||
@instruction(name="DEX", mode="imp", cycles=2)
|
||||
def inst_0xca(self):
|
||||
self.x -= 1
|
||||
self.x &= 255
|
||||
self.x &= self.byteMask
|
||||
self.FlagsNZ(self.x)
|
||||
|
||||
@instruction(name="CPY", mode="abs", cycles=4)
|
||||
@ -1172,7 +1180,7 @@ class MPU:
|
||||
@instruction(name="INX", mode="imp", cycles=2)
|
||||
def inst_0xe8(self):
|
||||
self.x+=1
|
||||
self.x&=255
|
||||
self.x&=self.byteMask
|
||||
self.FlagsNZ(self.x)
|
||||
|
||||
@instruction(name="SBC", mode="imm", cycles=2)
|
||||
@ -1236,4 +1244,3 @@ class MPU:
|
||||
def inst_0xfe(self):
|
||||
self.opINCR(self.AbsoluteXAddr)
|
||||
self.pc += 2
|
||||
|
||||
|
32
src/py65/devices/mpu65Org16.py
Normal file
32
src/py65/devices/mpu65Org16.py
Normal 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"
|
||||
)
|
@ -1,8 +1,21 @@
|
||||
# this sparse array module only needed for large-memory CPU models
|
||||
try:
|
||||
from blist import *
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
class ObservableMemory:
|
||||
def __init__(self, subject=None):
|
||||
def __init__(self, subject=None, addrWidth=16):
|
||||
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._read_subscribers = {}
|
||||
|
@ -8,6 +8,7 @@ import sys
|
||||
from asyncore import compact_traceback
|
||||
from py65.devices.mpu6502 import MPU as NMOS6502
|
||||
from py65.devices.mpu65c02 import MPU as CMOS65C02
|
||||
from py65.devices.mpu65Org16 import MPU as V65Org16
|
||||
from py65.disassembler import Disassembler
|
||||
from py65.assembler import Assembler
|
||||
from py65.utils.addressing import AddressParser
|
||||
@ -112,7 +113,7 @@ class Monitor(cmd.Cmd):
|
||||
byte = 0
|
||||
return byte
|
||||
|
||||
m = ObservableMemory()
|
||||
m = ObservableMemory(addrWidth=self._mpu.addrWidth)
|
||||
m.subscribe_to_write([0xF001], putc)
|
||||
m.subscribe_to_read([0xF004], getc)
|
||||
|
||||
@ -147,7 +148,7 @@ class Monitor(cmd.Cmd):
|
||||
self._reset(mpu_type=klass)
|
||||
|
||||
def do_mpu(self, args):
|
||||
mpus = {'6502': NMOS6502, '65C02': CMOS65C02}
|
||||
mpus = {'6502': NMOS6502, '65C02': CMOS65C02, '65Org16': V65Org16}
|
||||
|
||||
def available_mpus():
|
||||
mpu_list = ', '.join(mpus.keys())
|
||||
@ -157,7 +158,7 @@ class Monitor(cmd.Cmd):
|
||||
self._output("Current MPU is %s" % self._mpu.name)
|
||||
available_mpus()
|
||||
else:
|
||||
requested = args.upper()
|
||||
requested = args
|
||||
new_mpu = mpus.get(requested, None)
|
||||
if new_mpu is None:
|
||||
self._output("Unknown MPU: %s" % args)
|
||||
|
Loading…
x
Reference in New Issue
Block a user