示例#1
0
def codebreaker():
    import programs.wozmon
    wozmon_program = programs.wozmon.program
    wozmon_address = programs.wozmon.starting_address

    import programs.codebreaker as game

    cpu = None
    cpu = CPU6502(cycle_limit=100_000_000_000,
                  printActivity=False,
                  enableBRK=False,
                  logging=False)
    cpu.load_program(instructions=wozmon_program,
                     memoryAddress=wozmon_address,
                     mainProgram=False)
    # cpu.loadProgram(instructions=basic_program, memoryAddress=basic_address, mainProgram=False)

    for tape in game.tapes:
        cpu.load_program(instructions=tape['data'],
                         memoryAddress=tape['starting_address'],
                         mainProgram=False)

    cpu.program_counter = wozmon_address
    print(game.instructions)
    cpu.execute()
示例#2
0
def functional_test_program():

    try:

        print('Loading in binary file...')
        with open('binary/6502_functional_test.bin', 'rb') as f:
            data = f.read()
        print('Converting to text...')
        program = [d for d in data]
        # print(program[0x03F6: 0x040F])
        # print(len(program))

        cpu = None
        cpu = CPU6502(cycle_limit=200_000_000,
                      printActivity=False,
                      enableBRK=True,
                      logging=True,
                      logFile='log.txt')
        # cpu = CPU6502(cycle_limit=10_000_000, printActivity=False, enableBRK=True, logging=False)
        cpu.reset(program_counter=0x0400)
        cpu.load_program(instructions=program,
                         memoryAddress=0x000A,
                         mainProgram=False)
        cpu.program_counter = 0x0400
        # print(cpu.memory[0x400:0x40F])
        print('Running program...')
        cpu.execute()

    except Exception as e:
        print(str(e))

    finally:
        # print(f'{cpu.cycles:,} cycles. Elapesd time {cpu.execution_time}.')
        cpu.print_benchmark_info()
示例#3
0
def hammurabi():
    import programs.wozmon
    wozmon_program = programs.wozmon.program
    wozmon_address = programs.wozmon.starting_address

    import programs.apple_1_basic
    basic_program = programs.apple_1_basic.program
    basic_address = programs.apple_1_basic.starting_address

    import programs.hammurabi

    cpu = None
    cpu = CPU6502(cycle_limit=100_000_000_000,
                  printActivity=False,
                  enableBRK=True,
                  logging=False)
    cpu.reset(program_counter=basic_address)
    cpu.load_program(instructions=wozmon_program,
                     memoryAddress=wozmon_address,
                     mainProgram=False)
    cpu.load_program(instructions=basic_program,
                     memoryAddress=basic_address,
                     mainProgram=False)

    for tape in programs.hammurabi.tapes:
        cpu.load_program(instructions=tape['data'],
                         memoryAddress=tape['starting_address'],
                         mainProgram=False)

    cpu.program_counter = wozmon_address
    print(programs.hammurabi.instructions)
    cpu.execute()
示例#4
0
def TEST_0x50_BVC_DOES_NOT_BRANCH():
    TEST_NAME = 'TEST_0x50_BVC_DOES_NOT_BRANCH'
    EXPECTED_CYCLES = 2
    INITIAL_REGISTERS = {'A': 0x7F, 'X': 0xDD, 'Y': 0xCC}
    EXPECTED_REGISTERS = {'A': 0x7F, 'X': 0xDD, 'Y': 0xCC}
    INITIAL_FLAGS = {'C': 0, 'Z': 0, 'I': 0, 'D': 0, 'B': 0, 'V': 1, 'N': 0}
    EXPECTED_FLAGS = {'C': 0, 'Z': 0, 'I': 0, 'D': 0, 'B': 0, 'V': 1, 'N': 0}

    print(f'{bcolors.UNDERLINE}Running {TEST_NAME}{bcolors.ENDC}')
    label = 'REL'
    print(f'\tTesting {label}... ', end='')
    cpu = CPU6502(cycle_limit=EXPECTED_CYCLES)
    cpu.reset(program_counter=0xFF00)
    program = [0x50, 0x02, 0x00, 0x00, 0xA9, 0x05]
    cpu.load_program(instructions=program, memoryAddress=0xFF00)
    cpu.registers = INITIAL_REGISTERS
    cpu.flags = INITIAL_FLAGS
    cpu.execute()

    try:
        assert (cpu.registers == EXPECTED_REGISTERS)
        assert (cpu.flags == EXPECTED_FLAGS)
        assert (cpu.cycles - 1 == EXPECTED_CYCLES)
    except AssertionError:
        print(f'{bcolors.FAIL}FAILED{bcolors.ENDC}', end='\n')
        cpu.print_log()
        cpu.memory_dump(startingAddress=0xFF00, endingAddress=0xFF02)
        print(f'Cycles: {cpu.cycles-1}')
        print(f'Expected Registers: {EXPECTED_REGISTERS}')
        raise
        return False
    print(f'{bcolors.OKGREEN}PASSED{bcolors.ENDC}', end='\n')
    return True
示例#5
0
def startrek():
    import programs.wozmon
    wozmon_program = programs.wozmon.program
    wozmon_address = programs.wozmon.starting_address

    import programs.apple_1_basic
    basic_program = programs.apple_1_basic.program
    basic_address = programs.apple_1_basic.starting_address

    import programs.startrek as game

    cpu = None
    cpu = CPU6502(cycle_limit=100_000_000_000,
                  printActivity=False,
                  enableBRK=True,
                  logging=False)
    cpu.load_program(instructions=wozmon_program,
                     memoryAddress=wozmon_address,
                     mainProgram=False)
    cpu.load_program(instructions=basic_program,
                     memoryAddress=basic_address,
                     mainProgram=False)

    for tape in game.tapes:
        cpu.load_program(instructions=tape['data'],
                         memoryAddress=tape['starting_address'],
                         mainProgram=False)

    cpu.program_counter = wozmon_address
    print(f'Running {game.name}...')
    print(game.description)
    print(game.instructions)
    cpu.execute()
示例#6
0
def fast_multiply_10():
    cpu = CPU6502(cycle_limit=100, printActivity=True)
    cpu.reset(program_counter=0x2000)

    program = [
        0xA9,
        0x19,  # LDA_IM 25 ; Load initial value
        0x0A,  # ASL ACC ; Double accumulator value
        0x8D,
        0x00,
        0x30,  # STA [0x3000] ; Store doubled value in memory
        0x0A,  # ASL ACC ; Double accumulator again (x4 total)
        0x0A,  # ASL ACC ; Double accumulator again (x8 total)
        0x18,  # CLC ; Clear carry flag for some reason
        0x6D,
        0x00,
        0x30,  # ADC [0x3000] ; Add memory to accumulator (effectively value x 8 + value x 2 = value x 10)
        0x8D,
        0x01,
        0x30,  # STA [0x3000] ; Store accumulator value in memory
    ]
    cpu.load_program(instructions=program,
                     memoryAddress=0x2000,
                     mainProgram=True)
    cpu.execute()
    cpu.memory_dump(startingAddress=0x2000, endingAddress=0x2017)
    cpu.memory_dump(startingAddress=0x3000,
                    endingAddress=0x3001,
                    display_format='Dec')
示例#7
0
def TEST_0xBA_TSX_NEGATIVE_FLAG_SET():
    TEST_NAME = 'TEST_0xBA_TSX_NEGATIVE_FLAG_SET'
    EXPECTED_CYCLES = 2
    INITIAL_REGISTERS = {
        'A': 0x08,
        'X': 0x12,
        'Y': 0x01
    }
    EXPECTED_REGISTERS = {
        'A': 0x08,
        'X': 0xFA,
        'Y': 0x01
    }
    INITIAL_FLAGS = {
        'C': 1,
        'Z': 0,
        'I': 1,
        'D': 1,
        'B': 1,
        'V': 1,
        'N': 0
    }
    EXPECTED_FLAGS = {
        'C': 1,
        'Z': 0,
        'I': 1,
        'D': 1,
        'B': 1,
        'V': 1,
        'N': 1
    }
    print(f'{bcolors.UNDERLINE}Running {TEST_NAME}{bcolors.ENDC}')
    label = 'REL'
    print(f'\tTesting {label}... ', end='')
    cpu = CPU6502(cycle_limit=EXPECTED_CYCLES)
    cpu.reset(program_counter=0xFF00)
    program = [0xBA]
    cpu.load_program(instructions=program, memoryAddress=0xFF00)
    cpu.registers = INITIAL_REGISTERS
    cpu.flags = INITIAL_FLAGS
    cpu.stack_pointer = 0xFA
    cpu.execute()

    try:
        assert(cpu.stack_pointer == EXPECTED_REGISTERS['X'])
        assert(cpu.registers == EXPECTED_REGISTERS)
        assert(cpu.flags == EXPECTED_FLAGS)
        assert(cpu.cycles - 1 == EXPECTED_CYCLES)
        print(f'{bcolors.OKGREEN}PASSED{bcolors.ENDC}', end='\n')
        return True
    except AssertionError:
        print(f'{bcolors.FAIL}FAILED{bcolors.ENDC}', end='\n')
        cpu.print_log()
        cpu.memory_dump(startingAddress=0xFF00, endingAddress=0xFF02)
        print(f'Cycles: {cpu.cycles-1}')
        print(f'Expected Registers: {EXPECTED_REGISTERS}')
        raise
    return False
示例#8
0
def TEST_0x68_PLA_IMP():
    EXPECTED_VALUE = 0x35
    EXPECTED_CYCLES = 4
    INITIAL_REGISTERS = {
        'A': 0x25,
        'X': 0x18,
        'Y': 0x20
    }
    EXPECTED_REGISTERS = {
        'A': EXPECTED_VALUE,
        'X': 0x18,
        'Y': 0x20
    }
    INITIAL_FLAGS = {
        'C': 0,
        'Z': 0,
        'I': 0,
        'D': 0,
        'B': 0,
        'V': 0,
        'N': 0
    }
    EXPECTED_FLAGS = {
        'C': 0,
        'Z': 0,
        'I': 0,
        'D': 0,
        'B': 0,
        'V': 0,
        'N': 0
    }
    cpu = CPU6502(cycle_limit=EXPECTED_CYCLES)
    cpu.reset(program_counter=0xFF00)
    program = [0x68, 0x00]
    cpu.load_program(instructions=program, memoryAddress=0xFF00)
    cpu.registers = INITIAL_REGISTERS
    cpu.flags = INITIAL_FLAGS
    cpu.memory[0x01FF] = EXPECTED_VALUE
    cpu.stack_pointer = 0xFE
    cpu.execute()

    try:
        assert(cpu.stack_pointer == 0xFF)
        assert(cpu.registers == EXPECTED_REGISTERS)
        assert(cpu.flags == EXPECTED_FLAGS)
        assert(cpu.cycles - 1 == EXPECTED_CYCLES)
        return True
    except AssertionError:
        cpu.print_log()
        cpu.memory_dump(startingAddress=0xFF00, endingAddress=0xFF02)
        cpu.memory_dump(startingAddress=0x01F8, endingAddress=0x01FF)
        print(f'Cycles: {cpu.cycles-1}')
        print(f'Expected Flags: {EXPECTED_FLAGS}')
        raise
    return False
示例#9
0
def wozmon():
    import programs.wozmon
    wozmon_program = programs.wozmon.program
    wozmon_address = programs.wozmon.starting_address

    cpu = None
    cpu = CPU6502(cycle_limit=100_000_000,
                  printActivity=False,
                  enableBRK=False)
    cpu.reset(program_counter=0xFF00)
    cpu.load_program(instructions=wozmon_program,
                     memoryAddress=wozmon_address,
                     mainProgram=False)
    cpu.program_counter = wozmon_address
    cpu.execute()
示例#10
0
def fibonacci_test():
    cpu = CPU6502(cycle_limit=1000, printActivity=False)
    cpu.reset(program_counter=0x0000)

    program = [
        0xA9,
        0x01,  # LDA_IM 1
        0xA2,
        0x00,  # LDX_IM 0
        0x85,
        0x21,  # STA_ZP [0x21]
        0xA9,
        0x00,  # LDA_IM 0
        0x65,
        0x21,  # ADC [0x21]  -- This is the main loop; the jump ins below should point to the address of this line
        0xB0,
        0x11,  # BCS 0x11  ; Jump to end of program if value exceeds 0xFF
        0x95,
        0x30,  # STA_ZP_X [0x30]
        0xE8,  # INX
        0x85,
        0x22,  # STA_ZP [0x22]
        0xA5,
        0x21,  # LDA_ZP [0x21]
        0x85,
        0x20,  # STA_ZP [0x20]
        0xA5,
        0x22,  # LDA_ZP [0x22]
        0x85,
        0x21,  # STA_ZP [0x21]
        0xA5,
        0x20,  # LDA_ZP [0x20]
        0x4C,
        0x08,
        0x00  # JMP 0x0008
    ]
    cpu.load_program(instructions=program, memoryAddress=0x0000)
    cpu.execute()
    cpu.print_log()
    cpu.memory_dump(startingAddress=0x0000, endingAddress=0x001F)
    cpu.memory_dump(startingAddress=0x0020,
                    endingAddress=0x0022,
                    display_format='Dec')
    cpu.memory_dump(startingAddress=0x0030,
                    endingAddress=0x003F,
                    display_format='Dec')
示例#11
0
def TEST_0x6C_JMP_IND():
    TEST_NAME = 'TEST_0x6C_JMP_IND'
    EXPECTED_CYCLES = 5 + 2
    EXPECTED_VALUE = 0xFE
    EXPECTED_REGISTERS = {
        'A': EXPECTED_VALUE,
        'X': 0,
        'Y': 0
    }
    EXPECTED_FLAGS = {
        'C': 0,
        'Z': 0,
        'I': 0,
        'D': 0,
        'B': 0,
        'U': 1,
        'V': 0,
        'N': 1
    }
    print(f'{bcolors.UNDERLINE}Running {TEST_NAME}{bcolors.ENDC}')
    label = 'IND'
    print(f'\tTesting {label}... ', end='')
    cpu = CPU6502(cycle_limit=EXPECTED_CYCLES)
    cpu.reset(program_counter=0xFF00)
    program = [0x6C, 0x10, 0xFF]
    cpu.load_program(instructions=program, memoryAddress=0xFF00)
    program = [0x20, 0xFF]
    cpu.load_program(instructions=program, memoryAddress=0xFF10, mainProgram=False)
    program = [0xA9, 0xFE]
    cpu.load_program(instructions=program, memoryAddress=0xFF20, mainProgram=False)
    cpu.execute()

    try:
        assert(cpu.cycles - 1 == EXPECTED_CYCLES)
        assert(cpu.registers == EXPECTED_REGISTERS)
        assert(cpu.flags == EXPECTED_FLAGS)
        print(f'{bcolors.OKGREEN}PASSED{bcolors.ENDC}', end='\n')
        return True
    except AssertionError:
        print(f'{bcolors.FAIL}FAILED{bcolors.ENDC}', end='\n')
        cpu.print_log()
        cpu.memory_dump(startingAddress=0xFF00, endingAddress=0xFF02)
        cpu.memory_dump(startingAddress=0xFF10, endingAddress=0xFF12)
        cpu.memory_dump(startingAddress=0xFF20, endingAddress=0xFF22)
        raise
    return False
示例#12
0
def flags_test():
    cpu = CPU6502(cycle_limit=10)
    cpu.set_flags_manually(['C', 'Z', 'I', 'D', 'B', 'U', 'V', 'N'], 0)
    cpu.get_processor_status()
    cpu.set_flags_manually(['C', 'Z', 'I', 'D', 'B', 'U', 'V', 'N'], 1)
    cpu.get_processor_status()
    cpu.set_flags_manually(['C', 'Z', 'I', 'D', 'B', 'U', 'V', 'N'], 0)
    flags = ['N', 'V', 'U', 'B', 'D', 'I', 'Z', 'C']
    for flag in flags:
        print(f'Flag: {flag}')
        cpu.set_flags_manually([flag], 1)
        cpu.print_state()
        value = cpu.get_processor_status()
        cpu.set_flags_manually([flag], 0)
        cpu.print_state()
        cpu.set_processor_status(value)
        cpu.print_state()
        print('*' * 50)
示例#13
0
def run():
    cpu = CPU6502()
    cpu.reset()
    cpu.memory[0x00CC] = 0x02  # Used for LDA_ZP

    cpu.memory[0x0080] = 0x03  # Used for LDA_ZP_X

    cpu.memory[0x00AA] = 0x03  # Used for LDA_IND_X
    cpu.memory[0x00AB] = 0xFF  # Used for LDA_IND_X

    cpu.memory[0x00AC] = 0x01  # Used for LDA_IND_Y
    cpu.memory[0x00AD] = 0xFF  # Used for LDA_IND_Y

    cpu.memory[0xFF00] = 0x04
    cpu.memory[0xFF01] = 0x05
    cpu.memory[0xFF02] = 0x06
    cpu.memory[0xFF03] = 0x07
    cpu.memory[0xFF04] = 0x08

    cpu.load_program(instructions=[0xA9, 0x09, 0x6C, 0x30, 0xFF],
                     memoryAddress=0xFF28)
    cpu.load_program(instructions=[0x38, 0xFF], memoryAddress=0xFF30)
    cpu.load_program(instructions=[
        0xA9, 0x0A, 0x85, 0xB0, 0xA2, 0x01, 0xA9, 0x0B, 0x95, 0xB0
    ],
                     memoryAddress=0xFF38)

    cpu.load_program(instructions=[
        0xA9, 0x01, 0xA5, 0xCC, 0xB5, 0x80, 0xAD, 0x00, 0xFF, 0xBD, 0x01, 0xFF,
        0xB9, 0xFF, 0xFE, 0xA1, 0xAA, 0xB1, 0xAC, 0x4C, 0x28, 0xFF
    ],
                     memoryAddress=0xFF10)

    cpu.registers['Y'] = 0x03

    cpu.execute()
    cpu.print_log()
    cpu.memory_dump(startingAddress=0xFF00, endingAddress=0xFF3F)
    cpu.memory_dump(startingAddress=0x0000, endingAddress=0x00FF)
    cpu.memory_dump(startingAddress=0x00, endingAddress=0x0F)
示例#14
0
def TEST_0x20_JSR_ABS():
    TEST_NAME = 'TEST_0x20_JSR_ABS'
    EXPECTED_VALUE = 0x35
    EXPECTED_CYCLES = 6 + 2
    INITIAL_REGISTERS = {'A': 0, 'X': 0, 'Y': 0}
    EXPECTED_REGISTERS = {'A': EXPECTED_VALUE, 'X': 0, 'Y': 0}
    INITIAL_FLAGS = {'C': 0, 'Z': 0, 'I': 0, 'D': 0, 'B': 0, 'V': 0, 'N': 0}
    EXPECTED_FLAGS = {'C': 0, 'Z': 0, 'I': 0, 'D': 0, 'B': 0, 'V': 0, 'N': 0}
    print(f'{bcolors.UNDERLINE}Running {TEST_NAME}{bcolors.ENDC}')
    label = 'ABS'
    print(f'\tTesting {label}... ', end='')
    cpu = CPU6502(cycle_limit=EXPECTED_CYCLES)
    cpu.reset(program_counter=0xFF00)
    program = [0x20, 0x05, 0xE3]
    cpu.load_program(instructions=program, memoryAddress=0xFF00)
    program = [0xA9, 0x35]
    cpu.load_program(instructions=program,
                     memoryAddress=0xE305,
                     mainProgram=False)
    cpu.registers = INITIAL_REGISTERS
    cpu.flags = INITIAL_FLAGS
    cpu.execute()

    try:
        assert (cpu.stack_pointer == 0xFD)
        assert (cpu.memory[0x01FE] == 0x02)
        assert (cpu.memory[0x01FF] == 0xFF)
        assert (cpu.registers == EXPECTED_REGISTERS)
        assert (cpu.flags == EXPECTED_FLAGS)
        assert (cpu.cycles - 1 == EXPECTED_CYCLES)
        print(f'{bcolors.OKGREEN}PASSED{bcolors.ENDC}', end='\n')
        return True
    except AssertionError:
        print(f'{bcolors.FAIL}FAILED{bcolors.ENDC}', end='\n')
        cpu.print_log()
        cpu.memory_dump(startingAddress=0x01F0, endingAddress=0x01FF)
        cpu.memory_dump(startingAddress=0xFF00, endingAddress=0xFF02)
        print(f'Cycles: {cpu.cycles-1}')
        raise
    return False
示例#15
0
def sieve_of_erastosthenes():
    import programs.sieve_of_eratosthenes
    program = programs.sieve_of_eratosthenes.program
    starting_address = programs.sieve_of_eratosthenes.starting_address
    cpu = None
    cpu = CPU6502(cycle_limit=100_000, printActivity=False, enableBRK=False)
    cpu.reset(program_counter=starting_address)
    cpu.load_program(instructions=program,
                     memoryAddress=starting_address,
                     mainProgram=True)
    # cpu.memory[0x0601] = 0x64
    cpu.execute()

    for test in programs.sieve_of_eratosthenes.tests:
        cpu.memory_dump(startingAddress=test['memory_range'][0],
                        endingAddress=test['memory_range'][1],
                        display_format='Dec')
        if test['expected_values'] is not None:
            print(cpu.memory[test['memory_range'][0]:test['memory_range'][1] +
                             1] == test['expected_values'])

    print(cpu.benchmark_info())
示例#16
0
def runBenchmark():
    cpu = None
    cpu = CPU6502(cycle_limit=750_000,
                  printActivity=False,
                  enableBRK=False,
                  logFile=None)
    cpu.reset(program_counter=0x8000)
    cpu.memory[0x0090] = 0
    program = [
        0xA2,
        0x00,  # LDX 0
        0xA0,
        0x00,  # LDY 0
        0xE8,  # INX ; 0x8004
        0xE0,
        0xFF,  # CPX 255
        0xF0,
        0x03,  # BEQ +4
        0x4C,
        0x04,
        0x80,  # JMP to 0x8004
        0xC8,  # INY
        0xC0,
        0xFF,  # CPY 255
        0xF0,
        0x03,  # BEQ +4
        0x4C,
        0x04,
        0x80,  # JMP to 0x8004
        0x00,  # BRK
    ]
    cpu.load_program(instructions=program,
                     memoryAddress=0x8000,
                     mainProgram=True)
    cpu.execute()
    print(
        f'Cycles: {cpu.cycles - 1:,} :: Elapsed time: {cpu.execution_time} :: Cycles/sec: {(cpu.cycles - 1) / cpu.execution_time.total_seconds():0,.2f}'
    )
示例#17
0
def apple_i_basic():
    import programs.wozmon
    wozmon_program = programs.wozmon.program
    wozmon_address = programs.wozmon.starting_address

    import programs.apple_1_basic
    basic_program = programs.apple_1_basic.program
    basic_address = programs.apple_1_basic.starting_address

    cpu = None
    cpu = CPU6502(cycle_limit=100_000_000_000,
                  printActivity=False,
                  enableBRK=False)
    cpu.reset(program_counter=basic_address)
    cpu.load_program(instructions=wozmon_program,
                     memoryAddress=wozmon_address,
                     mainProgram=False)
    cpu.load_program(instructions=basic_program,
                     memoryAddress=basic_address,
                     mainProgram=False)
    cpu.program_counter = wozmon_address
    print(f'{basic_address:04X}')
    cpu.execute()
示例#18
0
def decimal_mode_test():
    cpu = None
    cpu = CPU6502(cycle_limit=40,
                  printActivity=False,
                  enableBRK=False,
                  logging=True)

    program = [
        0xA9,
        0x09,  # LDA
        0x8D,
        0x00,
        0x88,  # STA ABS
        0x69,
        0x01,  # ADC IM
        0x8D,
        0x01,
        0x88,  # STA ABS
        0xF8,  # SED
        0xA9,
        0x09,  # LDA
        0x8D,
        0x02,
        0x88,  # STA ABS
        0x69,
        0x01,  # ADC IM
        0x8D,
        0x03,
        0x88,  # STA ABS
    ]
    cpu.load_program(instructions=program,
                     memoryAddress=0x8000,
                     mainProgram=True)
    cpu.program_counter = 0x8000
    cpu.execute()
    cpu.print_log()
    cpu.memory_dump(startingAddress=0x8800, endingAddress=0x8807)
示例#19
0
def apple_i_print_chars():
    import programs.wozmon
    wozmon_program = programs.wozmon.program
    wozmon_address = programs.wozmon.starting_address

    import programs.apple_1_print_characters
    char_program = programs.apple_1_print_characters.program
    char_address = programs.apple_1_print_characters.starting_address

    cpu = None
    cpu = CPU6502(cycle_limit=10_000,
                  printActivity=False,
                  enableBRK=False,
                  logging=True,
                  logFile='log.txt')
    cpu.reset(program_counter=char_address)
    cpu.load_program(instructions=wozmon_program,
                     memoryAddress=wozmon_address,
                     mainProgram=False)
    cpu.load_program(instructions=char_program,
                     memoryAddress=char_address,
                     mainProgram=False)
    cpu.program_counter = char_address
    cpu.execute()
示例#20
0
def STA_ADDRESS_MODE_TESTS() -> bool:
    TEST_NAME = f'STA_ADDRESS_MODE_TESTS'
    INSTRUCTION = 'STA'
    IMMEDIATE_VALUE = None
    # VALUE_TO_TEST = 0xA5
    ZP_ADDRESS = 0x0059
    IND_ZP_ADDRESS = 0x0069
    FULL_ADDRESS = 0xAA48
    EXPECTED_VALUE = 0x05
    CYCLE_COUNTS = {
        'ZP': 3,
        'ZP_X': 4,
        'ABS': 4,
        'ABS_X': 5,
        'ABS_Y': 5,
        'IND_X': 6,
        'IND_Y': 6
    }
    INITIAL_REGISTERS = {
        'A': EXPECTED_VALUE,
        'X': 0x01,
        'Y': 0x05
    }
    EXPECTED_REGISTERS = {
        'A': EXPECTED_VALUE,
        'X': 0x01,
        'Y': 0x05
    }
    INITIAL_FLAGS = {
        'C': 0,
        'Z': 0,
        'I': 0,
        'D': 0,
        'B': 0,
        'V': 0,
        'N': 0
    }
    EXPECTED_FLAGS = {
        'C': 0,
        'Z': 0,
        'I': 0,
        'D': 0,
        'B': 0,
        'V': 0,
        'N': 0
    }

    programs = generateProgram(instruction=INSTRUCTION,
                               registers=INITIAL_REGISTERS,
                               immediate_value=IMMEDIATE_VALUE,
                               zp_address=ZP_ADDRESS,
                               ind_zp_address=IND_ZP_ADDRESS,
                               sixteen_bit_address=FULL_ADDRESS,
                               CYCLE_COUNTS=CYCLE_COUNTS)

    print(f'{bcolors.UNDERLINE}Running {TEST_NAME}{bcolors.ENDC}')
    errors = False
    for label, program in programs.items():
        print(f'\tTesting {label}... ', end='')
        PROGRAM = program[0]
        EXPECTED_CYCLES = program[1]
        cpu = CPU6502(cycle_limit=100)
        cpu.reset(program_counter=0xFF00)
        cpu.load_program(instructions=PROGRAM, memoryAddress=0xFF00)
        cpu.registers = INITIAL_REGISTERS.copy()
        cpu.flags = INITIAL_FLAGS.copy()
        # cpu.memory[ZP_ADDRESS] = VALUE_TO_TEST  # ZP, ZP_X, and ZP_Y Location
        cpu.memory[IND_ZP_ADDRESS] = FULL_ADDRESS & 0b0000000011111111
        cpu.memory[IND_ZP_ADDRESS + 1] = (FULL_ADDRESS & 0b1111111100000000) >> 8
        # cpu.memory[FULL_ADDRESS] = VALUE_TO_TEST  # ABS, ABS_X, ABS_Y, and IND_X Location
        # cpu.memory[FULL_ADDRESS + INITIAL_REGISTERS['Y']] = VALUE_TO_TEST  # IND_Y Location
        # EXPECTED_MEMORY = cpu.memory.copy()
        cpu.execute()

        if (cpu.registers != EXPECTED_REGISTERS) \
            or (cpu.flags != EXPECTED_FLAGS) \
            or (cpu.cycles - 1 != EXPECTED_CYCLES) \
            or (EXPECTED_VALUE is not None and label in ['ZP', 'ZP_X', 'ZP_Y'] and cpu.memory[ZP_ADDRESS] != EXPECTED_VALUE) \
            or (EXPECTED_VALUE is not None and label in ['ABS', 'ABS_X', 'ABS_Y', 'IND_X'] and cpu.memory[FULL_ADDRESS] != EXPECTED_VALUE) \
            or (EXPECTED_VALUE is not None and label in ['IND_Y'] and cpu.memory[FULL_ADDRESS + INITIAL_REGISTERS['Y']] != EXPECTED_VALUE):

            print(f'{bcolors.FAIL}FAILED{bcolors.ENDC}', end='\n')
            if cpu.registers != EXPECTED_REGISTERS:
                print(f'\t{bcolors.FAIL}REGISTERS DO NOT MATCH{bcolors.ENDC}', end='\n')
            if cpu.flags != EXPECTED_FLAGS:
                print(f'\t{bcolors.FAIL}FLAGS DO NOT MATCH{bcolors.ENDC}', end='\n')
            if cpu.cycles - 1 != EXPECTED_CYCLES:
                print(f'\t{bcolors.FAIL}CYCLE COUNT DOES NOT MATCH{bcolors.ENDC}', end='\n')

            # Memory tests
            # Test that memory was unchanged
            # if EXPECTED_VALUE is not None and label in ['ZP', 'ZP_X', 'ZP_Y', 'ABS', 'ABS_X', 'ABS_Y', 'IND_X', 'IND_Y'] and cpu.memory != EXPECTED_MEMORY:
                # print(f'\t{bcolors.FAIL}MEMORY CONTENTS DO NOT MATCH{bcolors.ENDC}', end='\n')

            # Test that value was written to correct memory location
            if (EXPECTED_VALUE is not None and label in ['ZP', 'ZP_X', 'ZP_Y'] and cpu.memory[ZP_ADDRESS] != EXPECTED_VALUE) \
                or (EXPECTED_VALUE is not None and label in ['ABS', 'ABS_X', 'ABS_Y', 'IND_X'] and cpu.memory[FULL_ADDRESS] != EXPECTED_VALUE) \
                or (EXPECTED_VALUE is not None and label in ['IND_Y'] and cpu.memory[FULL_ADDRESS + INITIAL_REGISTERS['Y']] != EXPECTED_VALUE):
                print(f'\t{bcolors.FAIL}MEMORY CONTENTS DO NOT MATCH{bcolors.ENDC}', end='\n')

            cpu.print_log()
            cpu.memory_dump(startingAddress=0xFF00, endingAddress=(0xFF00 + len(program)))
            cpu.memory_dump(startingAddress=ZP_ADDRESS, endingAddress=ZP_ADDRESS + 1)
            cpu.memory_dump(startingAddress=IND_ZP_ADDRESS, endingAddress=IND_ZP_ADDRESS + 1)
            cpu.memory_dump(startingAddress=FULL_ADDRESS, endingAddress=FULL_ADDRESS + 1)

            print(f'Program: ' + ', '.join('0x{0:0{1}X}'.format(x, 2) for x in program[0]))
            print(f'Cycles: {cpu.cycles-1} Expected Cycles: {EXPECTED_CYCLES}')
            print(f'Expected Registers: {EXPECTED_REGISTERS}')
            print(f'Expected Flags: {EXPECTED_FLAGS}')
            errors = True
        else:
            print(f'{bcolors.OKGREEN}PASSED{bcolors.ENDC}', end='\n')

    if errors:
        return False
    return True
示例#21
0
def TEST_0xEA_LSR_ACC_MODE_TESTS():
    TEST_NAME = f'TEST_0xEA_LSR_ACC_MODE_TESTS'
    INSTRUCTION = 'LSR'
    VALUE_IN_MEMORY = 0x02  # Set this for loading an initial value into memory
    IMMEDIATE_VALUE = None  # Set this for loading an initial value into memory
    ZP_ADDRESS = 0x62  # Set this for loading an initial value into memory
    IND_ZP_ADDRESS = 0x72  # Set this for loading an initial value into memory
    FULL_ADDRESS = 0xABDC  # Set this for loading an initial value into memory
    EXPECTED_VALUE = 0x01  # Set this when a value should be written to memory
    CYCLE_COUNTS = {'ACC': 2}
    INITIAL_REGISTERS = {'A': 0x02, 'X': 0x01, 'Y': 0x05}
    EXPECTED_REGISTERS = {'A': EXPECTED_VALUE, 'X': 0x01, 'Y': 0x05}
    INITIAL_FLAGS = {'C': 0, 'Z': 0, 'I': 0, 'D': 0, 'B': 0, 'V': 0, 'N': 0}
    EXPECTED_FLAGS = {'C': 0, 'Z': 0, 'I': 0, 'D': 0, 'B': 0, 'V': 0, 'N': 0}

    programs = generateProgram(instruction=INSTRUCTION,
                               registers=INITIAL_REGISTERS,
                               immediate_value=IMMEDIATE_VALUE,
                               zp_address=ZP_ADDRESS,
                               ind_zp_address=IND_ZP_ADDRESS,
                               sixteen_bit_address=FULL_ADDRESS,
                               CYCLE_COUNTS=CYCLE_COUNTS)

    print(f'{bcolors.UNDERLINE}Running {TEST_NAME}{bcolors.ENDC}')
    errors = False
    for label, program in programs.items():
        print(f'\tTesting {label}... ', end='')
        PROGRAM = program[0]
        EXPECTED_CYCLES = program[1]
        cpu = CPU6502(cycle_limit=100)
        cpu.reset(program_counter=0xFF00)
        cpu.load_program(instructions=PROGRAM, memoryAddress=0xFF00)
        cpu.registers = INITIAL_REGISTERS.copy()
        cpu.flags = INITIAL_FLAGS.copy()
        if ZP_ADDRESS is not None and VALUE_IN_MEMORY is not None:
            cpu.memory[
                ZP_ADDRESS] = VALUE_IN_MEMORY  # ZP, ZP_X, and ZP_Y Location
        if IND_ZP_ADDRESS is not None and VALUE_IN_MEMORY is not None:
            cpu.memory[IND_ZP_ADDRESS] = FULL_ADDRESS & 0b0000000011111111
            cpu.memory[IND_ZP_ADDRESS +
                       1] = (FULL_ADDRESS & 0b1111111100000000) >> 8
        if FULL_ADDRESS is not None and VALUE_IN_MEMORY is not None:
            cpu.memory[
                FULL_ADDRESS] = VALUE_IN_MEMORY  # ABS, ABS_X, ABS_Y, and IND_X Location
            cpu.memory[
                FULL_ADDRESS +
                INITIAL_REGISTERS['Y']] = VALUE_IN_MEMORY  # IND_Y Location

        INITIAL_MEMORY = None  # cpu.memory.copy()  # Change to None if testing a memory write
        cpu.execute()

        if (cpu.registers != EXPECTED_REGISTERS) \
            or (cpu.flags != EXPECTED_FLAGS) \
            or (cpu.cycles - 1 != EXPECTED_CYCLES) \
            or (INITIAL_MEMORY is not None and INITIAL_MEMORY != cpu.memory) \
            or (INITIAL_MEMORY is None and EXPECTED_VALUE is not None and label in ['ZP', 'ZP_X', 'ZP_Y'] and cpu.memory[ZP_ADDRESS] != EXPECTED_VALUE) \
            or (INITIAL_MEMORY is None and EXPECTED_VALUE is not None and label in ['ABS', 'ABS_X', 'ABS_Y', 'IND_X'] and cpu.memory[FULL_ADDRESS] != EXPECTED_VALUE) \
            or (INITIAL_MEMORY is None and EXPECTED_VALUE is not None and label in ['IND_Y'] and cpu.memory[FULL_ADDRESS + INITIAL_REGISTERS['Y']] != EXPECTED_VALUE):

            print(f'{bcolors.FAIL}FAILED{bcolors.ENDC}', end='\n')
            if cpu.registers != EXPECTED_REGISTERS:
                print(f'\t{bcolors.FAIL}REGISTERS DO NOT MATCH{bcolors.ENDC}',
                      end='\n')
            if cpu.flags != EXPECTED_FLAGS:
                print(f'\t{bcolors.FAIL}FLAGS DO NOT MATCH{bcolors.ENDC}',
                      end='\n')
            if cpu.cycles - 1 != EXPECTED_CYCLES:
                print(
                    f'\t{bcolors.FAIL}CYCLE COUNT DOES NOT MATCH{bcolors.ENDC}',
                    end='\n')

            # Memory tests
            # Test that value was written to correct memory location
            if (INITIAL_MEMORY is None and EXPECTED_VALUE is not None and label in ['ZP', 'ZP_X', 'ZP_Y'] and cpu.memory[ZP_ADDRESS] != EXPECTED_VALUE) \
                or (INITIAL_MEMORY is None and EXPECTED_VALUE is not None and label in ['ABS', 'ABS_X', 'ABS_Y', 'IND_X'] and cpu.memory[FULL_ADDRESS] != EXPECTED_VALUE) \
                or (INITIAL_MEMORY is None and EXPECTED_VALUE is not None and label in ['IND_Y'] and cpu.memory[FULL_ADDRESS + INITIAL_REGISTERS['Y']] != EXPECTED_VALUE) \
                or (INITIAL_MEMORY is not None and INITIAL_MEMORY != cpu.memory):
                print(
                    f'\t{bcolors.FAIL}MEMORY CONTENTS DO NOT MATCH{bcolors.ENDC}',
                    end='\n')

            cpu.print_log()
            cpu.memory_dump(startingAddress=0xFF00,
                            endingAddress=(0xFF00 + len(program)))
            cpu.memory_dump(startingAddress=ZP_ADDRESS,
                            endingAddress=ZP_ADDRESS + 1)
            cpu.memory_dump(startingAddress=IND_ZP_ADDRESS,
                            endingAddress=IND_ZP_ADDRESS + 1)
            cpu.memory_dump(startingAddress=FULL_ADDRESS,
                            endingAddress=FULL_ADDRESS + 1)

            print(f'Program: ' + ', '.join('0x{0:0{1}X}'.format(x, 2)
                                           for x in program[0]))
            print(f'Cycles: {cpu.cycles-1} Expected Cycles: {EXPECTED_CYCLES}')
            print(f'Expected Registers: {EXPECTED_REGISTERS}')
            print(f'Expected Flags: {EXPECTED_FLAGS}')
            errors = True
        else:
            print(f'{bcolors.OKGREEN}PASSED{bcolors.ENDC}', end='\n')

    if errors:
        return False
    return True
示例#22
0
def TEST_0x08_PHP_PLA_COMBINED_TEST():
    TEST_NAME = 'TEST_0x08_PHP_PLA_COMBINED_TEST'
    INITIAL_REGISTERS = {
        'A': 0x20,
        'X': 0x60,
        'Y': 0xA5
    }
    EXPECTED_REGISTERS = {
        'A': 0x20,
        'X': 0x60,
        'Y': 0xA5
    }
    INITIAL_FLAGS = {
        'C': 0,
        'Z': 0,
        'I': 0,
        'D': 0,
        'B': 0,
        'V': 0,
        'N': 0
    }
    EXPECTED_CYCLES = 3 + 1 + 4

    print(f'{bcolors.UNDERLINE}Running {TEST_NAME}{bcolors.ENDC}')
    errors = False
    for flag in INITIAL_FLAGS:
        print(f'\tTesting {flag}... ', end='')
        cpu = CPU6502(cycle_limit=100)
        cpu.reset(program_counter=0xFF00)
        push_program = [0x08, 0x00]
        cpu.load_program(instructions=push_program, memoryAddress=0xFF00)
        cpu.registers = INITIAL_REGISTERS.copy()
        cpu.flags = INITIAL_FLAGS.copy()
        cpu.flags[flag] = 1
        cpu.execute()

        pull_program = [0x28, 0x00]
        cpu.load_program(instructions=pull_program, memoryAddress=0xFF02)
        cpu.program_counter = 0xFF02
        cpu.registers = INITIAL_REGISTERS.copy()
        cpu.flags = INITIAL_FLAGS.copy()
        cpu.execute()

        EXPECTED_FLAGS = INITIAL_FLAGS.copy()
        EXPECTED_FLAGS[flag] = 1

        if cpu.registers != EXPECTED_REGISTERS or cpu.flags != EXPECTED_FLAGS or cpu.cycles - 1 != EXPECTED_CYCLES:
            print(f'{bcolors.FAIL}FAILED{bcolors.ENDC}', end='\n')
            if cpu.registers != EXPECTED_REGISTERS:
                print(f'\t{bcolors.FAIL}REGISTERS DO NOT MATCH{bcolors.ENDC}', end='\n')
                print(f'Expected Registers: {EXPECTED_REGISTERS}\tActual Registers: {cpu.registers}')
            if cpu.flags != EXPECTED_FLAGS:
                print(f'\t{bcolors.FAIL}FLAGS DO NOT MATCH{bcolors.ENDC}', end='\n')
                print(f'Expected Flags: {EXPECTED_FLAGS}\tActual Flags: {cpu.flags}')
            if cpu.cycles - 1 != EXPECTED_CYCLES:
                print(f'\t{bcolors.FAIL}CYCLE COUNT DOES NOT MATCH{bcolors.ENDC}', end='\n')
                print(f'Cycles: {cpu.cycles-1} Expected Cycles: {EXPECTED_CYCLES}')

            cpu.print_log()
            cpu.memory_dump(startingAddress=0xFF00, endingAddress=0xFF03)
            errors = True
        else:
            print(f'{bcolors.OKGREEN}PASSED{bcolors.ENDC}', end='\n')

    return not errors
示例#23
0
                print(chr(self.value), end='', flush=True)
                self.chars += 1

            if self.value == 0x0D or self.chars >= 40:
                print('', flush=True)
                self.chars = 0

        # Handling keyboard input
        if msvcrt.kbhit():
            key = msvcrt.getch().upper()
            key_ascii = ord(key)
            self.memory[self.hooks['KBD']] = key_ascii | 0b10000000
            self.memory[self.hooks['KBDCR']] = self.memory[self.hooks['KBDCR']] | 0b10000000


cpu = CPU6502(cycle_limit=100_000_000, printActivity=False, enableBRK=False, logging=False, continuous=False)
mem = cpu.get_memory()
pia = PIA(memory=mem)


import programs.wozmon
wozmon_program = programs.wozmon.program
wozmon_address = programs.wozmon.starting_address

import programs.apple_1_basic
basic_program = programs.apple_1_basic.program
basic_address = programs.apple_1_basic.starting_address

import programs.codebreaker

""" SAMPLE PROGRAM
示例#24
0
def sort_test_16_bits() -> bool:
    TEST_NAME = 'SORT TEST 16 BITS'
    """
    The sort subroutine discussed in the preceding example (see 8-bit Bubble Sort)
    was relatively simple because the elements were 8-bit values, and could be
    compared with a CMP instruction and exchanged without too much difficulty.
    Unfortunately, the 6502 microprocessor has no 16-bit compare instruction,
    so a comparison must be made by actually subtracting the elements and testing the
    status of the result; if a borrow occurs, the elements must be exchanged, otherwise
    the elements can remain in their present order. The SORT16 subroutine sorts 16-bit
    elements using the bubble-sort algorithm and a 16-bit "compare" sequence.

    ;THIS SUBROUTINE ARRANGES THE 16-BIT ELEMENTS OF A LIST IN
    ;ASCENDING ORDER.  THE STARTING ADDRESS OF THE LIST IS IN LOCATIONS
    ;$30 AND $31.  THE LENGTH OF THE LIST IS IN THE FIRST BYTE OF THE LIST.
    ;LOCATION $32 IS USED TO HOLD AN EXCHANGE FLAG.

    SORT16   LDY #$00     ;TURN EXCHANGE FLAG OFF (= 0)
            STY $32
            LDA ($30),Y  ;FETCH ELEMENT COUNT
            TAY          ;  AND USE IT TO INDEX LAST ELEMENT
    NXTEL    LDA ($30),Y  ;FETCH MSBY
            PHA          ;  AND PUSH IT ONTO STACK
            DEY
            LDA ($30),Y  ;FETCH LSBY
            SEC
            DEY
            DEY
            SBC ($30),Y  ; AND SUBTRACT LSBY OF PRECEDING ELEMENT
            PLA
            INY
            SBC ($30),Y  ; AND SUBTRACT MSBY OF PRECEDING ELEMENT
            BCC SWAP     ;ARE THESE ELEMENTS OUT OF ORDER?
            CPY #$02     ;NO. LOOP UNTIL ALL ELEMENTS COMPARED
            BNE NXTEL
            BIT $32      ;EXCHANGE FLAG STILL OFF?
            BMI SORT16   ;NO. GO THROUGH LIST AGAIN
            RTS

    ;THIS ROUTINE BELOW EXCHANGES TWO 16-BIT ELEMENTS IN MEMORY

    SWAP     LDA ($30),Y  ;SAVE MSBY1 ON STACK
            PHA
            DEY
            LDA ($30),Y  ;SAVE LSBY1 ON STACK
            PHA
            INY
            INY
            INY
            LDA ($30),Y  ;SAVE MSBY2 ON STACK
            PHA
            DEY
            LDA ($30),Y  ;LOAD LSBY2 INTO ACCUMULATOR
            DEY
            DEY
            STA ($30),Y  ; AND STORE IT AT LSBY1 POSITION
            LDX #$03
    SLOOP    INY          ;STORE THE OTHER THREE BYTES
            PLA
            STA ($30),Y
            DEX
            BNE SLOOP    ;LOOP UNTIL THREE BYTE STORED
            LDA #$FF     ;TURN EXCHANGE FLAG ON (= -1)
            STA $32
            CPY #04      ;WAS EXCHANGE DONE AT START OF LIST?
            BEQ SORT16   ;YES. GO THROUGH LIST AGAIN.
            DEY          ;NO. COMPARE NEXT ELEMENT PAIR
            DEY
            JMP NXTEL

    The SORT16 subroutine is designed with the same algorithm as SORT8, so the two
    subroutines have several characteristics in common. For example, both SORT8 and
    SORT16 have an exchange flag (in the same location, $32) that indicates whether
    or not an exchange occurred during the last pass through the list. Like SORT8,
    the SORT16 subroutine also compares adjacent elements (albeit with a 16-bit
    subtraction, as opposed to the simple 8-bit comparison of the SORT8) and has
    an exchange routine that interchanges misordered elements in memory.

    Aside from the fact that SORT8 and SORT16 operate on different size elements,
    the only other real difference between them is that SORT16 processes the list
    from the end and works upward, whereas, SORT8 process the list from the beginning
    and works downward. Why the difference in procedure? There is no good reason,
    other than to demonstrate that a bubble sort can operate in either direction.

    SORT16 starts by initializing the exchange flag to zero, and fetching the element
    count from the first byte of the list. Using that value to point Y at the last
    element, the 6502 microprocessor executes "compare" (subtraction) instructions.
    These instructions, which start with the NXTEL instruction, perform a double-precision
    subtraction. In this subtraction, the lest-significant bytes (LSBYs) are subtracted
    first, and any borrow from that operation is passed, via the Carry, to the subtraction
    of the most-significant bytes (MSBYs).

    Operations on multiple-precision elements typically require a lot of pointer
    manipulation, as you can see by the instructions that follow the NXTEL label.
    To get the higher-addressed LSBY, the Y register must be decremented from its
    MSBY position. Before decrementing the Y register, however, the higher-addressed
    MSBY is pushed onto the stack for later use. With several more Y register decrements,
    the two LSBYs are addressed and subtracted. The result of the subtraction is not saved,
    since we are only interested in the final status of the operation, not the numerical
    result.

            |           |                     |           |
            +-----------+                     +-----------+
    ADDR     |   LSBY1   |            ADDR     |   LSBY2   |
            +-----------+                     +-----------+
    ADDR + 1 |   MSBY1   |            ADDR + 1 |   MSBY2   |
            +-----------+                     +-----------+
    ADDR + 2 |   LSBY2   |            ADDR + 2 |   LSBY1   |
            +-----------+                     +-----------+
    ADDR + 3 |   MSBY2   |            ADDR + 3 |   MSBY1   |
            +-----------+                     +-----------+
            |           |                     |           |

        (A) Before Swap.                  (B) After Swap.

    Figure 1: Swapping two 16-bit values in memory.

    The most-significant bytes (MSBYs) are subtracted next, by retrieving the higher-addressed
    MSBY from the stack and subtracting the lower-addressed MSBY from it. With this subtraction,
    we can make the exchange/no-exchange decision based ont he state of the Carry flag. If Carry
    is set (no borrow occurred), the elements are in the correct order; if Carry is reset
    (a borrow occurred), the elements must be exchanged.

    Figure 1 shows what the SWAP routine actually does, by presenting the "before" and "after"
    diagrams of the exchanged 16-bit elements. The higher-valued elements initially resides in
    symbolic addresses ADDR + 2 and ADDR + 3, and its bytes are designated as LSBY2 and MSBY2.
    The lower-valued elements initially resides in symbolic addressed ADDR and ADDR + 1, and its
    bytes are designated LSBY1 and MSBY1. The sequence of the SWAP routine will be more easily
    understood if you refer to Figure 1 while studying the instructions of the routine.

    Due to the previous subtraction routine, the Y register index is pointing at MSBY1 when the
    SWAP routine is initiated. Taking advantage of this pointer, SWAP saves MSBY1 and the adjacent
    byte, LSBY1, on the stack. Recalling that information is retrieved from a stack in the opposite
    order from which it was entered on the stack, the MSBY1-then-LSBY1 push sequence implies which
    byte will be the next to be pushed onto the stack- it will be MSBY2. With these three bytes
    on the stack, the final byte LSBY2 is moved from ADDR + 2 (again, refer to Figure 1) to ADDR.
    A short loop (SLOOP) pulls bytes MSBY2, LSBY1, and MSBY1 off the stack and stores them in the
    locations following LSBY2. The SWAP routine ends by turning on the exchange flag in location $32.
    If Elements 1 and 2 were exchanged, a BEQ SORT16 instrucion branches to the top of the subroutine;
    otherwise, control jumps to NXTEL, for the next comparison.

    Address  Hexdump   Dissassembly
    -------------------------------
    $0600    a0 00     LDY #$00
    $0602    84 32     STY $32
    $0604    b1 30     LDA ($30),Y
    $0606    a8        TAY
    $0607    b1 30     LDA ($30),Y
    $0609    48        PHA
    $060a    88        DEY
    $060b    b1 30     LDA ($30),Y
    $060d    38        SEC
    $060e    88        DEY
    $060f    88        DEY
    $0610    f1 30     SBC ($30),Y
    $0612    68        PLA
    $0613    c8        INY
    $0614    f1 30     SBC ($30),Y
    $0616    90 09     BCC $0621
    $0618    c0 02     CPY #$02
    $061a    d0 eb     BNE $0607
    $061c    24 32     BIT $32
    $061e    30 e0     BMI $0600
    $0620    60        RTS
    $0621    b1 30     LDA ($30),Y
    $0623    48        PHA
    $0624    88        DEY
    $0625    b1 30     LDA ($30),Y
    $0627    48        PHA
    $0628    c8        INY
    $0629    c8        INY
    $062a    c8        INY
    $062b    b1 30     LDA ($30),Y
    $062d    48        PHA
    $062e    88        DEY
    $062f    b1 30     LDA ($30),Y
    $0631    88        DEY
    $0632    88        DEY
    $0633    91 30     STA ($30),Y
    $0635    a2 03     LDX #$03
    $0637    c8        INY
    $0638    68        PLA
    $0639    91 30     STA ($30),Y
    $063b    ca        DEX
    $063c    d0 f9     BNE $0637
    $063e    a9 ff     LDA #$ff
    $0640    85 32     STA $32
    $0642    c0 04     CPY #$04
    $0644    f0 ba     BEQ $0600
    $0646    88        DEY
    $0647    88        DEY
    $0648    4c 07 06  JMP $0607

    """
    SEQUENCES_TO_TEST = [2, 10, 25, 50, 100, 127]
    print(f'{bcolors.UNDERLINE}Running {TEST_NAME}{bcolors.ENDC}')
    for NUMBER_SEQUENCE_LENGTH in SEQUENCES_TO_TEST:
        data = [NUMBER_SEQUENCE_LENGTH * 2]
        EXPECTED_DATA = [NUMBER_SEQUENCE_LENGTH * 2]
        for x in range(1, NUMBER_SEQUENCE_LENGTH + 1, 1):
            data.append(0x00)
            data.append(NUMBER_SEQUENCE_LENGTH + 1 - x)
            EXPECTED_DATA.append(0x00)
            EXPECTED_DATA.append(x)
        # EXPECTED_DATA.extend(sorted(data[1:]))

        cpu = None
        cpu = CPU6502(cycle_limit=2_000_000)
        cpu.reset(program_counter=0x0600)
        # Location of list to sort is in 0x0030 and 0x0031
        # List can be up to 255 elements
        program = [
            0xa0, 0x00, 0x84, 0x32, 0xb1, 0x30, 0xa8, 0xb1, 0x30, 0x48, 0x88,
            0xb1, 0x30, 0x38, 0x88, 0x88, 0xf1, 0x30, 0x68, 0xc8, 0xf1, 0x30,
            0x90, 0x09, 0xc0, 0x02, 0xd0, 0xeb, 0x24, 0x32, 0x30, 0xe0, 0x60,
            0xb1, 0x30, 0x48, 0x88, 0xb1, 0x30, 0x48, 0xc8, 0xc8, 0xc8, 0xb1,
            0x30, 0x48, 0x88, 0xb1, 0x30, 0x88, 0x88, 0x91, 0x30, 0xa2, 0x03,
            0xc8, 0x68, 0x91, 0x30, 0xca, 0xd0, 0xf9, 0xa9, 0xff, 0x85, 0x32,
            0xc0, 0x04, 0xf0, 0xba, 0x88, 0x88, 0x4c, 0x07, 0x06
        ]

        cpu.load_program(instructions=program,
                         memoryAddress=0x0600,
                         mainProgram=True)
        cpu.load_program(instructions=data,
                         memoryAddress=0x4400,
                         mainProgram=False)
        cpu.memory[0x0030] = 0x00
        cpu.memory[0x0031] = 0x44
        # cpu.memoryDump(startingAddress=0x4400, endingAddress=0x4400 + len(data) - 1, display_format='Dec')
        cpu.execute()
        # cpu.printLog()
        # cpu.memoryDump(startingAddress=0x0600, endingAddress=0x0627)

        errors = False
        # print(f'\tTesting sort of {NUMBER_SEQUENCE_LENGTH} elements: Expected {EXPECTED_DATA[1:]} / got {cpu.memory[0x4401:0x4401 + NUMBER_SEQUENCE_LENGTH]} -- ', end='')
        print(f'\tTesting sort of {NUMBER_SEQUENCE_LENGTH} elements: ', end='')
        if cpu.memory[0x4401:0x4401 +
                      NUMBER_SEQUENCE_LENGTH * 2] == EXPECTED_DATA[1:]:
            print(
                f'{bcolors.OKGREEN}PASS{bcolors.ENDC} -- {cpu.cycles - 1:,} cycles. {cpu.execution_time} -- {(cpu.cycles - 1) / (cpu.execution_time.total_seconds() + 0.00001):0,.2f} cycles / sec',
                end='\n')
        else:
            print(
                f'{bcolors.FAIL}FAIL{bcolors.ENDC} -- {cpu.cycles - 1:,} cycles.',
                end='\n')
            cpu.memory_dump(startingAddress=0x4400,
                            endingAddress=0x4400 + len(data) - 1,
                            display_format='Dec')
            errors = True

    if errors:
        return False
    return True
示例#25
0
def sort_test_8_bits() -> bool:
    TEST_NAME = 'SORT TEST 8 BITS'
    """
    The subroutine (SORT8) sorts unordered lists that are comprised of 8-bit elements.
    As in the previous examples in this chapter, the starting addres is contained
    in locations $30 (low-address byte) and $31 (high-address byte).
    The length of the list is contained in the first byte of the list.
    Since a byte is 8 bits wide, the list can contain up to 255 elements.

    ;THIS SUBROUTINE ARRANGES THE 8-BIT ELEMENTS OF A LIST IN ASCENDING
    ;ORDER.  THE STARTING ADDRESS OF THE LIST IS IN LOCATIONS $30 AND
    ;$31.  THE LENGTH OF THE LIST IS IN THE FIRST BYTE OF THE LIST.  LOCATION
    ;$32 IS USED TO HOLD AN EXCHANGE FLAG.

    SORT8    LDY #$00      ;TURN EXCHANGE FLAG OFF (= 0)
            STY $32
            LDA ($30),Y   ;FETCH ELEMENT COUNT
            TAX           ; AND PUT IT INTO X
            INY           ;POINT TO FIRST ELEMENT IN LIST
            DEX           ;DECREMENT ELEMENT COUNT
    NXTEL    LDA ($30),Y   ;FETCH ELEMENT
            INY
            CMP ($30),Y   ;IS IT LARGER THAN THE NEXT ELEMENT?
            BCC CHKEND
            BEQ CHKEND
                        ;YES. EXCHANGE ELEMENTS IN MEMORY
            PHA           ; BY SAVING LOW BYTE ON STACK.
            LDA ($30),Y   ; THEN GET HIGH BYTE AND
            DEY           ; STORE IT AT LOW ADDRESS
            STA ($30),Y
            PLA           ;PULL LOW BYTE FROM STACK
            INY           ; AND STORE IT AT HIGH ADDRESS
            STA ($30),Y
            LDA #$FF      ;TURN EXCHANGE FLAG ON (= -1)
            STA $32
    CHKEND   DEX           ;END OF LIST?
            BNE NXTEL     ;NO. FETCH NEXT ELEMENT
            BIT $32       ;YES. EXCHANGE FLAG STILL OFF?
            BMI SORT8     ;NO. GO THROUGH LIST AGAIN
            RTS           ;YES. LIST IS NOW ORDERED

    Subroutine SORT8 begins by initializing an exchange flag.
    The exchange flag is an indicator in memory location $32 that can be interrogated
    upon completion of a sorting pass to find out whether any elements were exchanged
    during that pass (flag=-1) or if the pass was exected with no exchanges (flag=0).
    The latter case indicates that the list is completely ordered and needs no further sorting.

    After loading the element count into the X register, the 6502 microprocessor
    enters an element compare loop at NXTEL. As each element is fetched, it is compared
    to the next element in the list, with CMP ($30),Y. If this pair of elements are of
    equal value, or are in ascending (sorted) order, the subroutine then branches to
    CHKEND, to see if the element count in the X register has been decremented to zero
    (the end-of-list condition). Otherwise, the elements are exchanged (if the element
    pair is in the wrong order). The stack is used to save the lower-addressed element
    while the higher-addressed element is being relocated in memory. A zero page memory
    location could have been used to save the element, but it was observed that PHA and
    PLA both execute in one less cycle than their LDA and STA counterparts. Upon completion
    of an exchange operation, the exchange flag is turned on, by loading it with -1.

    Following the exchange, the element count is decremented with a DEX instruction
    (label CHKEND) and the subsequent BNE BXTEL instruction branches to NXTEL if the
    pass has not yet been completed. When the pass is completed, BIT $32 checkes whether
    the exhange is still off (Bit 7=0), or has been turned on (Bit 7=1) by an exchange
    operation during the pass. If an exchange occurred, the subroutine is reinitiated at
    ORDER8, otherwise RTS causes a return, with a now ordered list.
    """
    SEQUENCES_TO_TEST = [2, 10, 25, 50, 100, 200, 255]
    print(f'{bcolors.UNDERLINE}Running {TEST_NAME}{bcolors.ENDC}')
    for NUMBER_SEQUENCE_LENGTH in SEQUENCES_TO_TEST:
        # NUMBER_SEQUENCE_LENGTH = 10
        data = [NUMBER_SEQUENCE_LENGTH]
        data.extend(
            list(reversed([x for x in range(1, NUMBER_SEQUENCE_LENGTH + 1)])))
        EXPECTED_DATA = [NUMBER_SEQUENCE_LENGTH]
        EXPECTED_DATA.extend(sorted(data[1:]))

        cpu = None
        cpu = CPU6502(cycle_limit=3_000_000)
        cpu.reset(program_counter=0x0600)
        # Location of list to sort is in 0x0030 and 0x0031
        # List can be up to 255 elements
        program = [
            0xa0, 0x00, 0x84, 0x32, 0xb1, 0x30, 0xaa, 0xc8, 0xca, 0xb1, 0x30,
            0xc8, 0xd1, 0x30, 0x90, 0x10, 0xf0, 0x0e, 0x48, 0xb1, 0x30, 0x88,
            0x91, 0x30, 0x68, 0xc8, 0x91, 0x30, 0xa9, 0xff, 0x85, 0x32, 0xca,
            0xd0, 0xe6, 0x24, 0x32, 0x30, 0xd9, 0x60
        ]

        cpu.load_program(instructions=program,
                         memoryAddress=0x0600,
                         mainProgram=True)
        cpu.load_program(instructions=data,
                         memoryAddress=0x4400,
                         mainProgram=False)
        cpu.memory[0x0030] = 0x00
        cpu.memory[0x0031] = 0x44
        # cpu.memoryDump(startingAddress=0x4400, endingAddress=0x4400 + len(data) - 1, display_format='Dec')
        cpu.execute()
        # cpu.printLog()
        # cpu.memoryDump(startingAddress=0x0600, endingAddress=0x0627)

        errors = False
        # print(f'\tTesting sort of {NUMBER_SEQUENCE_LENGTH} elements: Expected {EXPECTED_DATA[1:]} / got {cpu.memory[0x4401:0x4401 + NUMBER_SEQUENCE_LENGTH]} -- ', end='')
        print(f'\tTesting sort of {NUMBER_SEQUENCE_LENGTH} elements: ', end='')
        if cpu.memory[0x4401:0x4401 +
                      NUMBER_SEQUENCE_LENGTH] == EXPECTED_DATA[1:]:
            print(
                f'{bcolors.OKGREEN}PASS{bcolors.ENDC} -- {cpu.cycles - 1:,} cycles. {cpu.execution_time} -- {(cpu.cycles - 1) / (cpu.execution_time.total_seconds() + 0.00001):0,.2f} cycles / sec',
                end='\n')
        else:
            print(
                f'{bcolors.FAIL}FAIL{bcolors.ENDC} -- {cpu.cycles - 1:,} cycles.',
                end='\n')
            cpu.memory_dump(startingAddress=0x4400,
                            endingAddress=0x4400 + len(data) - 1,
                            display_format='Dec')
            errors = True

    if errors:
        return False
    return True
示例#26
0
def fibonacci_test():
    TEST_NAME = 'FIBONACCI TEST'
    print(f'{bcolors.UNDERLINE}Running {TEST_NAME}{bcolors.ENDC}')
    errors = False
    cpu = CPU6502(cycle_limit=500)
    cpu.reset(program_counter=0x0000)

    program = [
        0xA9,
        0x01,  # LDA_IM 1
        0xA2,
        0x00,  # LDX_IM 0
        0x85,
        0x21,  # STA_ZP [0x21]
        0xA9,
        0x00,  # LDA_IM 0
        0x65,
        0x21,  # ADC [0x21]        ; This is the main loop; the jump ins below should point to the address of this line
        0xB0,
        0x11,  # BCS 0x11          ; Jump to end of program if value exceeds 0xFF
        0x95,
        0x30,  # STA_ZP_X [0x30]
        0xE8,  # INX
        0x85,
        0x22,  # STA_ZP [0x22]
        0xA5,
        0x21,  # LDA_ZP [0x21]
        0x85,
        0x20,  # STA_ZP [0x20]
        0xA5,
        0x22,  # LDA_ZP [0x22]
        0x85,
        0x21,  # STA_ZP [0x21]
        0xA5,
        0x20,  # LDA_ZP [0x20]
        0x4C,
        0x08,
        0x00  # JMP 0x0008
    ]
    cpu.load_program(instructions=program, memoryAddress=0x0000)
    cpu.execute()

    EXPECTED_VALUES = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]
    errors = False
    for pos, expected in enumerate(EXPECTED_VALUES):
        print(
            f'\tTesting Fibonacci sequence: Expected {expected} / got {cpu.memory[0x0030 + pos]} -- ',
            end='')
        if cpu.memory[0x0030 + pos] == expected:
            print(f'{bcolors.OKGREEN}PASS{bcolors.ENDC}', end='\n')
        else:
            print(f'{bcolors.FAIL}FAIL{bcolors.ENDC}', end='\n')
            errors = True
    # cpu.printLog()
    # cpu.memoryDump(startingAddress=0x0000, endingAddress=0x001F)
    # cpu.memoryDump(startingAddress=0x0020, endingAddress=0x0022, display_format='Dec')
    # cpu.memoryDump(startingAddress=0x0030, endingAddress=0x003F, display_format='Dec')

    if errors:
        return False
    return True
示例#27
0
def square_root_test() -> bool:
    TEST_NAME = 'SQUARE ROOT TEST'
    """
    http://www.6502.org/source/integers/root.htm
    """

    # cpu.memoryDump(startingAddress=0x1000, endingAddress=0x1000 + len(sqroot))
    # cpu.memoryDump(startingAddress=0x1100, endingAddress=0x1100 + len(loop))
    # cpu.memoryDump(startingAddress=0x1200, endingAddress=0x1200 + len(subtr))
    # cpu.memoryDump(startingAddress=0x1300, endingAddress=0x1300 + len(next))

    # cpu.memoryDump(startingAddress=0x00F0, endingAddress=0x00F7)
    """
    Address  Hexdump   Dissassembly
    -------------------------------
    $0600    a9 90     LDA #$90
    $0602    85 f0     STA $f0
    $0604    a9 00     LDA #$00
    $0606    85 f2     STA $f2
    $0608    85 f3     STA $f3
    $060a    85 f6     STA $f6
    $060c    a2 08     LDX #$08
    $060e    06 f6     ASL $f6
    $0610    06 f0     ASL $f0
    $0612    26 f1     ROL $f1
    $0614    26 f2     ROL $f2
    $0616    26 f3     ROL $f3
    $0618    06 f0     ASL $f0
    $061a    26 f1     ROL $f1
    $061c    26 f2     ROL $f2
    $061e    26 f3     ROL $f3
    $0620    a5 f6     LDA $f6
    $0622    85 f4     STA $f4
    $0624    a9 00     LDA #$00
    $0626    85 f5     STA $f5
    $0628    38        SEC
    $0629    26 f4     ROL $f4
    $062b    26 f5     ROL $f5
    $062d    a5 f3     LDA $f3
    $062f    c5 f5     CMP $f5
    $0631    90 16     BCC $0649
    $0633    d0 06     BNE $063b
    $0635    a5 f2     LDA $f2
    $0637    c5 f4     CMP $f4
    $0639    90 0e     BCC $0649
    $063b    a5 f2     LDA $f2
    $063d    e5 f4     SBC $f4
    $063f    85 f2     STA $f2
    $0641    a5 f3     LDA $f3
    $0643    e5 f5     SBC $f5
    $0645    85 f3     STA $f3
    $0647    e6 f6     INC $f6
    $0649    ca        DEX
    $064a    d0 c2     BNE $060e
    $064c    60        RTS

    """
    """

        *= $0600            ; can be anywhere, ROM or RAM

    SqRoot:
        LDA  #$90    ; clear A
        STA  $F0    ; clear remainder low byte
        LDA  #$00    ; clear A
        STA  $F2    ; clear remainder low byte
        STA  $F3    ; clear remainder high byte
        STA  $F6    ; clear $F6
        LDX  #$08    ; 8 pairs of bits to do
    Loop:
        ASL  $F6    ; $F6 = $F6 * 2

        ASL  $F0    ; shift highest bit of numb
        ROL  $F1    ;
        ROL  $F2    ; .. into remainder
        ROL  $F3    ;

        ASL  $F0    ; shift highest bit of number ..
        ROL  $F1    ;
        ROL  $F2    ; .. into remainder
        ROL  $F3    ;

        LDA  $F6    ; copy $F6 ..
        STA  $F4    ; .. to $F4
        LDA  #$00    ; clear byte
        STA  $F5    ; clear temp high byte

        SEC          ; +1
        ROL  $F4    ; temp = temp * 2 + 1
        ROL  $F5    ;

        LDA  $F3    ; get remainder high byte
        CMP  $F5    ; comapre with partial high byte
        BCC  Next    ; skip sub if remainder high byte smaller

        BNE  Subtr    ; do sub if <> (must be remainder>partial !)

        LDA  $F2    ; get remainder low byte
        CMP  $F4    ; comapre with partial low byte
        BCC  Next    ; skip sub if remainder low byte smaller

                        ; else remainder>=partial so subtract then
                        ; and add 1 to $F6. carry is always set here
    Subtr:
        LDA  $F2    ; get remainder low byte
        SBC  $F4    ; subtract partial low byte
        STA  $F2    ; save remainder low byte
        LDA  $F3    ; get remainder high byte
        SBC  $F5    ; subtract partial high byte
        STA  $F3    ; save remainder high byte

        INC  $F6    ; increment $F6
    Next:
        DEX          ; decrement bit pair count
        BNE  Loop    ; loop if not all done

        RTS

    """
    """
    ; Calculates the 8 bit root and 9 bit remainder of a 16 bit unsigned integer in
    ; Numberl/Numberh. The result is always in the range 0 to 255 and is held in
    ; Root, the remainder is in the range 0 to 511 and is held in Reml/Remh
    ;
    ; partial results are held in templ/temph
    ;
    ; This routine is the complement to the integer square program.
    ;
    ; Destroys A, X registers.

    ; variables - must be in RAM

    Numberl		= $F0		; number to find square root of low byte
    Numberh		= Numberl+1	; number to find square root of high byte
    Reml		= $F2		; remainder low byte
    Remh		= Reml+1	; remainder high byte
    templ		= $F4		; temp partial low byte
    temph		= templ+1	; temp partial high byte
    Root		= $F6		; square root

    *= $8000        		; can be anywhere, ROM or RAM

    SqRoot
        LDA	#$00		; clear A
        STA	Reml		; clear remainder low byte
        STA	Remh		; clear remainder high byte
        STA	Root		; clear Root
        LDX	#$08		; 8 pairs of bits to do
    Loop
        ASL	Root		; Root = Root * 2

        ASL	Numberl		; shift highest bit of number ..
        ROL	Numberh		;
        ROL	Reml		; .. into remainder
        ROL	Remh		;

        ASL	Numberl		; shift highest bit of number ..
        ROL	Numberh		;
        ROL	Reml		; .. into remainder
        ROL	Remh		;

        LDA	Root		; copy Root ..
        STA	templ		; .. to templ
        LDA	#$00		; clear byte
        STA	temph		; clear temp high byte

        SEC			    ; +1
        ROL	templ		; temp = temp * 2 + 1
        ROL	temph		;

        LDA	Remh		; get remainder high byte
        CMP	temph		; comapre with partial high byte
        BCC	Next		; skip sub if remainder high byte smaller

        BNE	Subtr		; do sub if <> (must be remainder>partial !)

        LDA	Reml		; get remainder low byte
        CMP	templ		; comapre with partial low byte
        BCC	Next		; skip sub if remainder low byte smaller

                        ; else remainder>=partial so subtract then
                        ; and add 1 to root. carry is always set here
    Subtr
        LDA	Reml		; get remainder low byte
        SBC	templ		; subtract partial low byte
        STA	Reml		; save remainder low byte
        LDA	Remh		; get remainder high byte
        SBC	temph		; subtract partial high byte
        STA	Remh		; save remainder high byte

        INC	Root		; increment Root
    Next
        DEX			    ; decrement bit pair count
        BNE	Loop		; loop if not all done

        RTS
    """

    sqroot = [
        0xA9,
        0x00,  # LDA_IM 0
        0x85,
        0xF2,  # STA_ZP [0xF2] Reml
        0x85,
        0xF3,  # STA_ZP [0xF3] Remh
        0x85,
        0xF6,  # STA_ZP [0xF6] Root
        0xA2,
        0x08,  # LDX_IM 8
        0x4C,
        0x00,
        0x11,  # JMP TO LOOP [0x1100]
    ]
    loop = [
        0x06,
        0xF6,  # ASL_ZP [0xF6] Root
        0x06,
        0xF0,  # ASL_ZP [0xF0] Numberl
        0x26,
        0xF1,  # ROL_ZP [0xF1] Numberh
        0x26,
        0xF2,  # ROL_ZP [0xF2] Reml
        0x26,
        0xF3,  # ROL_ZP [0xF3] Remh
        0x06,
        0xF0,  # ASL_ZP [0xF0] Numberl
        0x26,
        0xF1,  # ROL_ZP [0xF1] Numberh
        0x26,
        0xF2,  # ROL_ZP [0xF2] Reml
        0x26,
        0xF3,  # ROL_ZP [0xF3] Remh
        0xA5,
        0xF6,  # LDA_ZP [0xF6] Root
        0x85,
        0xF4,  # STA_ZP [0xF4] Templ
        0xA9,
        0x00,  # LDA_IM 0
        0x85,
        0xF5,  # STA_ZP [0xF5] Temph
        0x38,
        0x00,  # SEC
        0x26,
        0xF4,  # ROL_ZP [0xF4] Templ
        0x26,
        0xF5,  # ROL_ZP [0xF5] Temph
        0xA5,
        0xF3,  # LDA_ZP [0xF3] Remh
        0xC5,
        0xF5,  # CMP_ZP [0xF5] Temph
        0xB0,
        0x03,  # BCC [Next Subroutine] -- CHANGED TO BCS
        0x4C,
        0x00,
        0x13,  # JMP TO NEXT [0x1300]
        0xF0,
        0xA3,  # BNE [Subtr Subroutine] -- CHANGED TO BEQ
        0x4C,
        0x00,
        0x12,  # JMP TO SUBTR [0x1200]
        0xA5,
        0xF2,  # LDA_ZP [0xF2] Reml
        0xC5,
        0xF4,  # CMP_ZP [0xF4] Templ
        0xB0,
        0xA3,  # BCC [Next Subroutine] -- CHANGED TO BCS
        0x4C,
        0x00,
        0x13,  # JMP TO NEXT [0x1300]
        0x4C,
        0x00,
        0x12,  # JMP TO SUBTR [0x1200]
    ]
    subtr = [
        0xA5,
        0xF2,  # LDA_ZP [0xF2] Reml
        0xE5,
        0xF4,  # SBC_ZP [0xF4] Templ
        0x85,
        0xF2,  # STA_ZP [0xF2] Reml
        0xA5,
        0xF3,  # LDA_ZP [0xF3] Remh
        0xE5,
        0xF5,  # SBC_ZP [0xF4] Temph
        0x85,
        0xF3,  # STA_ZP [0xF3] Remh
        0xE6,
        0xF6,  # INC_ZP [0xF6] Root
        0x4C,
        0x00,
        0x13  # JMP TO NEXT [0x1300]
    ]
    next = [
        0xCA,
        0x00,  # DEX
        0xF0,
        0x03,  # BNE [Loop Subroutine] -- CHANGED TO BEQ
        0x4C,
        0x00,
        0x11,  # JMP TO LOOP [0x1100]
        0x60,
        0x00,  # RTS
    ]

    all_in_one = [
        0xa9, 0x51, 0x85, 0xf0, 0xa9, 0x00, 0x85, 0xf2, 0x85, 0xf3, 0x85, 0xf6,
        0xa2, 0x08, 0x06, 0xf6, 0x06, 0xf0, 0x26, 0xf1, 0x26, 0xf2, 0x26, 0xf3,
        0x06, 0xf0, 0x26, 0xf1, 0x26, 0xf2, 0x26, 0xf3, 0xa5, 0xf6, 0x85, 0xf4,
        0xa9, 0x00, 0x85, 0xf5, 0x38, 0x26, 0xf4, 0x26, 0xf5, 0xa5, 0xf3, 0xc5,
        0xf5, 0x90, 0x16, 0xd0, 0x06, 0xa5, 0xf2, 0xc5, 0xf4, 0x90, 0x0e, 0xa5,
        0xf2, 0xe5, 0xf4, 0x85, 0xf2, 0xa5, 0xf3, 0xe5, 0xf5, 0x85, 0xf3, 0xe6,
        0xf6, 0xca, 0xd0, 0xc2, 0x60
    ]

    all_in_one = [
        # 0xa9, 0x51, 0x85, 0xf0,  # Load low byte of number to find square root of
        # 0xa9, 0x00, 0x85, 0xf1,  # Load high byte of number to find square root of
        0xa9,
        0x00,
        0x85,
        0xf2,
        0x85,
        0xf3,
        0x85,
        0xf6,
        0xa2,
        0x08,
        0x06,
        0xf6,
        0x06,
        0xf0,
        0x26,
        0xf1,
        0x26,
        0xf2,
        0x26,
        0xf3,
        0x06,
        0xf0,
        0x26,
        0xf1,
        0x26,
        0xf2,
        0x26,
        0xf3,
        0xa5,
        0xf6,
        0x85,
        0xf4,
        0xa9,
        0x00,
        0x85,
        0xf5,
        0x38,
        0x26,
        0xf4,
        0x26,
        0xf5,
        0xa5,
        0xf3,
        0xc5,
        0xf5,
        0x90,
        0x16,
        0xd0,
        0x06,
        0xa5,
        0xf2,
        0xc5,
        0xf4,
        0x90,
        0x0e,
        0xa5,
        0xf2,
        0xe5,
        0xf4,
        0x85,
        0xf2,
        0xa5,
        0xf3,
        0xe5,
        0xf5,
        0x85,
        0xf3,
        0xe6,
        0xf6,
        0xca,
        0xd0,
        0xc2,
        0x60
    ]

    # cpu.memory[0x00F0] = 0x09  # Number to find square root of low byte
    # cpu.memory[0x00F1] = 0x00  # Number to find square root of high byte

    # cpu.loadProgram(instructions=sqroot, memoryAddress=0x1000, mainProgram=True)
    # cpu.loadProgram(instructions=loop, memoryAddress=0x1100, mainProgram=False)
    # cpu.loadProgram(instructions=subtr, memoryAddress=0x1200, mainProgram=False)
    # cpu.loadProgram(instructions=next, memoryAddress=0x1300, mainProgram=False)
    numbers_to_test = [x**2 for x in range(2, 16)]
    expected_values = [x for x in range(2, 16)]

    print(f'{bcolors.UNDERLINE}Running {TEST_NAME}{bcolors.ENDC}')
    errors = False

    for test_value, expected_value in zip(numbers_to_test, expected_values):
        cpu = CPU6502(cycle_limit=1200, printActivity=False)
        cpu.reset(program_counter=0x0600)
        cpu.load_program(instructions=all_in_one,
                         memoryAddress=0x0600,
                         mainProgram=True)
        cpu.memory[0x00F0] = test_value
        cpu.memory[0x00F1] = 0x00  # Number to find square root of high byte
        cpu.execute()
        print(
            f'\tTesting square root of {test_value}: Expected {expected_value} / got {cpu.memory[0x00F6]} -- ',
            end='')
        if cpu.memory[0x00F6] == expected_value:
            print(f'{bcolors.OKGREEN}PASS{bcolors.ENDC}', end='\n')
        else:
            print(f'{bcolors.FAIL}FAIL{bcolors.ENDC}', end='\n')
            errors = True
    return not errors
示例#28
0
def count_set_bits_test():
    pyjion.enable()
    """
    int countSetBits(int a) {
        int count = 0;
        while (a) {
            count++;
            a &= (a - 1);
        }
        return count
    }
    """
    cpu = None
    cpu = CPU6502(cycle_limit=100_000,
                  printActivity=False,
                  enableBRK=False,
                  logging=False,
                  logFile='log.txt')
    # BEQ F0
    # INC EE
    # DEC CE
    # AND 2D
    # JMP 4C

    # 0x4000 stores the number of bits
    # 0x0000 stores the numbers
    """
        # Write out values in ZP table
        0xA2, 0x00,  # LDX 0
        0xA0, 0x00,  # LDY 0
        0x96, 0x00,  # STX,Y ZP 0x00
        0xE8,  # INX
        0xC8,  # INY
        0xD0, 0xFA,  # BNE -6

        0xA9, 0x00,  # LDA 0
        0xA2, 0x00,  # LDX 0
        0xA0, 0x00,  # LDY 0
        0x8D, 0x00, 0x40,  # STA ABS 0x4000
        0xA9, 0xFF,  # LDA 255
        0x8D, 0x00, 0x50,  # STA ABS 0x5000
        # START
        0xF0, 0x0F,  # BEQ to re-write table code
        0xEE, 0x00, 0x40,  # INC ABS 0x4000
        0xCE, 0x00, 0x50,  # DEC ABS 0x5000
        0x2D, 0x00, 0x50,  # AND ABS 0x5000
        0x8D, 0x00, 0x50,  # STA ABS 0x5000
        0x4C, 0x18, 0x80,  # JMP ABS 0x8014

        # Re-write out values in ZP table
        0xA2, 0x00,  # LDX 0
        0xA0, 0x00,  # LDY 0
        0x96, 0x00,  # STX,Y ZP 0x00
        0xE8,  # INX
        0xC8,  # INY
        0xD0, 0xFA,  # BNE -6
    """
    program = [
        # Write out values in ZP table
        0xA2,
        0x00,  # LDX 0
        0xA0,
        0x00,  # LDY 0
        0x96,
        0x00,  # STX,Y ZP 0x00
        0xE8,  # INX
        0xC8,  # INY
        0xD0,
        0xFA,  # BNE -6
        0xA9,
        0x00,  # LDA 0
        0xA2,
        0x01,  # LDX 1
        0xA0,
        0x01,  # LDY 1
        0x8D,
        0x00,
        0x40,  # STA ABS 0x4000
        # LOAD NUMBER TO PROCESS
        0xB5,
        0x00,  # LDA ZP,X -- 0x8013
        0x8D,
        0x00,
        0x50,  # STA ABS 0x5000
        # START
        0xF0,
        0x0F,  # BEQ to re-write table code
        0xFE,
        0x00,
        0x40,  # INC ABS,X 0x4000
        0xDE,
        0x00,
        0x00,  # DEC ABS,X 0x0000
        0x3D,
        0x00,
        0x00,  # AND ABS,X 0x0000
        0x9D,
        0x00,
        0x00,  # STA ABS,X 0x0000
        0x4C,
        0x13,
        0x80,  # JMP ABS 0x8013

        # Re-write out values in ZP table
        0xE8,  # INX - Check to see if we've done all 255 slots
        0xD0,
        0xE7,  # BNE BACK TO LOAD NUMBER TO PROCESS
        0xA2,
        0x00,  # LDX 0
        0xA0,
        0x00,  # LDY 0
        0x96,
        0x00,  # STX,Y ZP 0x00
        0xE8,  # INX
        0xC8,  # INY
        0xD0,
        0xFA,  # BNE -6
    ]
    cpu.load_program(instructions=program,
                     memoryAddress=0x8000,
                     mainProgram=True)
    cpu.program_counter = 0x8000
    cpu.execute()
    # cpu.print_log()
    cpu.memory_dump(startingAddress=0x0000,
                    endingAddress=0x00FF,
                    display_format='Dec',
                    items_per_row=16)
    cpu.memory_dump(startingAddress=0x4000,
                    endingAddress=0x40FF,
                    display_format='Dec',
                    items_per_row=16)
    cpu.print_benchmark_info()