Py65 0.1: Introducing Py65Mon

  • Posted by Mike Naberezny in Hardware,Python

    Py65 0.1, a 6502 microprocessor simulator written in Python, has been released and is available on the Python Package Index (PyPI). You can now easy_install it:

    $ easy_install py65
    

    Py65Mon

    Since my initial announcement of Py65, there have been many bug fixes and unit tests added. The most noticeable addition is a new machine language monitor. It will be installed automatically and is started with the py65mon command:

    $ py65mon
    
    Py65 Monitor
    
    <6502: A=00, X=00, Y=00, Flags=20, SP=ff, PC=0000>
    .
    

    At the prompt, type help for a list of commands or help command for help on a specific command. The monitor commands are very similar to the excellent VICE Monitor, so VICE users should feel right at home.

    The biggest difference from VICE is that the load command requires a load address as the second argument and starts reading the binary data from byte 0. It does not expect byte 0 and 1 of the file to contain a Commodore-style load address. Also, assembling and disassembling from the monitor are not yet implemented but are planned.

    Hello World

    Just like Michal Kowalski’s 6502 Macroassembler & Simulator for Windows, Py65Mon will trap writes to $E001 and echo the bytes to STDOUT.

    This is enough to get us to our first “Hello World” program running under Py65. First, we’ll write a short assembly language program to print the message. Save it as hello.asm.

    *=$C000
    CHAROUT=$F001      ;Originally $E001, now $F001 since Py65 0.2
    
    HELLO:
      LDX #$00
    LOOP:
      LDA MESSAGE,X
      BEQ DONE
      STA CHAROUT
      INX
      JMP LOOP
    DONE:
      RTS
    
    MESSAGE = *
      !text "Hello, World!"
      !byte 0
    

    We then assemble the program into a binary, using Marco Baye’s Acme Cross-Assembler:

    src$ acme --format plain --outfile hello.bin hello.asm
    

    The --format plain switch instructs Acme not to prepend the Commodore-style load address in the binary. If you’d like to get going quickly, you can also download hello.bin.

    With the binary ready, we can start the monitor and load it in:

    src$ py65mon
    
    Py65 Monitor
    
    <6502: A=00, X=00, Y=00, Flags=20, SP=ff, PC=0000>
    .add_label c000 hello
    
    <6502: A=00, X=00, Y=00, Flags=20, SP=ff, PC=0000>
    .load "hello.bin" hello
    Wrote +29 bytes from $c000 to $c01c
    

    Py65Mon supports symbolic addressing in most commands. The first command, add_label, defines hello as a label for address $C000. The second command loads the binary into that address.

    We can now set the program counter with the registers command, and execute the code up to RTS with the return command.

    <6502: A=00, X=00, Y=00, Flags=20, SP=ff, PC=0000>
    .registers pc=hello
    
    <6502: A=00, X=0d, Y=00, Flags=20, SP=ff, PC=c000>
    .return
    Hello, World!
    <6502: A=00, X=0d, Y=00, Flags=20, SP=ff, PC=c00e>
    .
    

    Now we have run the program, printed “Hello, World!”, and returned to the prompt. We can see the program counter is left at $C00E.

    You can also use the step command to step through the program. Just set the program counter to the start address again ($C000 or hello) and repeatedly enter step. As you are stepping repeatedly, you can simply hit ENTER to repeat the last command.

    From here you can also explore other commands, e.g. mem c000:c003 to display the memory in that address range. The default radix is hexadecimal. You can also prefix with $ for hexadecimal or + for decimal, like mem +49152:+49155.

    Next Steps

    Py65 and its monitor are now complete enough to run most simple 6502 programs, including many from the 6502.org Source Code Repository. The next versions will include more I/O devices and monitor commands, with the goal of running a sophisticated 6502 program like Lee’s Davisons’ Enhanced 6502 BASIC.