6502.py

#!/usr/bin/python3
# ===================================================================
# my 6502 simulator
# a start at a first cut
# -------------------------------------------------------------------
#
# My memory layout is not a real one. A real memory layout is
# more complicated (Google 6502 memory layout).
#
# This is just to test my CPU implementation and a few selected
# instructions. 
#
# ---- my test memory layout
#
#  0      255  256    511  512                            4095  
#  +--------+  +--------+  +---------------------------------+
#  |  zero  |  | stack  |  | program and data                |
#  |  page  |  |        |  |                                 |
#  +--------+  +--------+  +---------------------------------+
#
#  Decimal      Hex
#        0     0x00
#      255     0xFF
#      256   0x0100
#      511   0x01FF
#      512   0x0200
#     4095   0x0FFF
#     4096   0x1000
#
# ---- registers and status register bits
#
#  PC   programm counter      word (2 bytes) 
#  SP   stack pointer         byte
#  A    accmulator register   byte
#  X    X rergister           byte
#  Y    Y register            byte
#  P    status register       byte
#       N                     bit  (negative flag)
#       V                     bit  (overflow flag)
#       B                     bit  (break command flag)
#       D                     bit  (decimal mode flag)
#       I                     bit  (IRQ disable flag)
#       Z                     bit  (zero flag)
#       C                     bit  (carry flag)
#
# ===================================================================

import sys

MAX_MEM = 1024 * 4

mem = bytearray(MAX_MEM)       # memory (4096 bytes)


# -------------------------------------------------------------------
# ---- CPU
# -------------------------------------------------------------------

class CPU:

    def __init__(self):
        self.reset()

    def reset(self):
        self.PC = 0x0200        # my program counter
        self.SP = 0xFF          # my stack pointer
        self.A  = 0x00          # accmulator register
        self.X  = 0x00          # X register
        self.Y  = 0x00          # Y register
        self.N  = 0             # negative flag
        self.V  = 0             # overflow flag
        self.B  = 0             # break command flag
        self.D  = 0             # decimal mode flag
        self.I  = 0             # IRQ disable flag
        self.Z  = 0             # zero flag
        self.C  = 0             # carry flag

    def getN(self):
        return self.N
    def setN(self,x):
        if not verify_bit_value(x):
            sys.exit()
        self.N = x
    def statusN(self):
        if self.N:
            return True
        return False

    def getV(self):
        return self.V
    def setV(self,x):
        if not verify_bit_value(x):
            sys.exit()
        self.V = x
    def statusV(self):
        if self.V:
            return True
        return False

    def getB(self):
        return self.B
    def setB(self,x):
        if not verify_bit_value(x):
            sys.exit()
        self.B = x
    def statusB(self):
        if self.B:
            return True
        return False

    def getD(self):
        return self.D
    def setD(self,x):
        if not verify_bit_value(x):
            sys.exit()
        self.D = x
    def statusD(self):
        if self.B:
            return True
        return False

    def getI(self):
        return self.PI
    def setI(self,x):
        if not verify_bit_value(x):
            sys.exit()
        self.I = x
    def statusI(self):
        if self.B:
            return True
        return False

    def getZ(self):
        return self.Z
    def setZ(self,x):
        if not verify_bit_value(x):
            sys.exit()
        self.Z = x
    def statusZ(self):
        if self.B:
            return True
        return False

    def getC(self):
        return self.C
    def setC(self,x):
        if not verify_bit_value(x):
            sys.exit()
        self.C = x
    def statusC(self):
        if self.B:
            return True
        return False

    def resetP(self):
        self.N  = 0             # negative flag
        self.V  = 0             # overflow flag
        self.B  = 0             # break command flag
        self.D  = 0             # decimal mode flag
        self.I  = 0             # IRQ disable flag
        self.Z  = 0             # zero flag
        self.C  = 0             # carry flag

    def getA(self):
        return self.A
    def setC(self,x):
        if not verify_byte_value(x):
            sys.exit()
        self.A = x

    def getX(self):
        return self.X
    def setC(self,x):
        if not verify_byte_value(x):
            sys.exit()
        self.X = x

    def getY(self):
        return self.Y
    def setC(self,x):
        if not verify_byte_value(x):
            sys.exit()
        self.Y = x

    def getPC(self):
        return self.PC
    def setPC(self,x):
        if not verify_word_value(x):
            sys.exit()
        self.PC = x

    def getSP(self):
        return self.SP
    def setSP(self,x):
        if not verify_word_value(x):
            sys.exit()
        self.SP = x

    def displayRegisters(self,title=None):
        print('-- CPU Registers ---------------------')
        if title:
            print(f'-- {title}')
        print(f'PC  = {hex(self.PC):7}  ({self.PC})')
        print(f'SP  = {hex(self.SP):7}  ({self.SP})')
        print(f'A   = {hex(self.A):7}  ({self.A})')
        print(f'X   = {hex(self.X):7}  ({self.X})')
        print(f'Y   = {hex(self.Y):7}  ({self.Y})')
        ##print(f'P.N = {self.N}')
        print(f'P.N = {self.statusN()}')
        ##print(f'P.V = {self.V}')
        print(f'P.V = {self.statusV()}')
        ##print(f'P.B = {self.B}')
        print(f'P.B = {self.statusB()}')
        ##print(f'P.D = {self.D}')
        print(f'P.D = {self.statusD()}')
        ##print(f'P.I = {self.I}')
        print(f'P.I = {self.statusI()}')
        ##print(f'P.Z = {self.Z}')
        print(f'P.Z = {self.statusZ()}')
        ##print(f'P.C = {self.C}')
        print(f'P.C = {self.statusC()}')
        print('--------------------------------------')

    def execute(mem):
        pass


# -------------------------------------------------------------------
# ---- support functions
# -------------------------------------------------------------------

def verify_bit_value(v):
    if v != 0 and v != 1:
        print(f'Illegal bit value ({v})')
        return False
    return True

def verify_byte_value(v):
    if v < 0 or v > 255:
        print(f'Illegal byte value ({v})')
        return False
    return True

def verify_word_value(v):
    if v < 0 and v > 65535:
        print(f'Illegal word value ({v})')
        return False
    return True

def is_float(s):
    try:
        n = float(s)
        return (True,n)
    except:
        return (False,0.0)

def is_int(s):
    try:
        n = int(s)
        return (True,n)
    except:
        return (False,0)

def is_a_number(s):
    x,n = is_int(s)
    if x:
        return True
    x,n = is_float(s)
    if x:
        return True
    return False

def init_memory():
    mem = bytearray(MAX_MEM)


# -------------------------------------------------------------------
# main
# -------------------------------------------------------------------

if __name__ == '__main__':

    print()
    print('my 6502 CPU simulator')
    print()

    cpu = CPU()

    cpu.displayRegisters()