Saturday, July 7, 2012

65816 Disassembly - 8 and 16 bit modes


Today I made JMON a little smarter about 65816 disassembly. It now handles 8-bit and 16-bit instructions, looking at SEP and REP instructions to determine what mode the CPU is currently in. Of course, it cannot always get this correct as it doesn't know if code could be called when the CPU is in a specified mode. It starts in all 8-bit mode. This is similar to how the CC65 assembler works in "auto" mode unless you use assembler directives to explicitly set the mode.

While I was testing this I noticed the SEP instruction was disassembled as CPX. There is actually an error in the Western Design Center manual in Chapter 19, Instruction Lists, which I had copied when I entered the op codes. The byte $E2 is SEP but is listed as CPX.

Here is sample disassembly output from JMON showing all 4 combinations of 8 and 16-bit accumulator and index register modes (I've manually added spaces to highlight where the mode changes).

JMON MONITOR 0.97 BY JEFF TRANTER
? U 60B9
60B9   E2 30       SEP   #$30
60BB   09 12       ORA   #$12
60BD   29 12       AND   #$12
60BF   49 12       EOR   #$12
60C1   69 12       ADC   #$12
60C3   89 12       BIT   #$12
60C5   A9 12       LDA   #$12
60C7   C9 12       CMP   #$12
60C9   E9 12       SBC   #$12
60CB   A0 12       LDY   #$12
60CD   A2 12       LDX   #$12
60CF   C0 12       CPY   #$12
60D1   E0 12       CPX   #$12


60D3   C2 30       REP   #$30
60D5   09 34 12    ORA   #$1234
60D8   29 34 12    AND   #$1234
60DB   49 34 12    EOR   #$1234
60DE   69 34 12    ADC   #$1234
60E1   89 34 12    BIT   #$1234
60E4   A9 34 12    LDA   #$1234
60E7   C9 34 12    CMP   #$1234
60EA   E9 34 12    SBC   #$1234
60ED   A0 34 12    LDY   #$1234
60F0   A2 34 12    LDX   #$1234
60F3   C0 34 12    CPY   #$1234
60F6   E0 34 12    CPX   #$1234


60F9   C2 20       REP   #$20
60FB   E2 10       SEP   #$10
60FD   09 34 12    ORA   #$1234
6100   29 34 12    AND   #$1234
6103   49 34 12    EOR   #$1234
6106   69 34 12    ADC   #$1234
6109   89 34 12    BIT   #$1234
610C   A9 34 12    LDA   #$1234
610F   C9 34 12    CMP   #$1234
6112   E9 34 12    SBC   #$1234
6115   A0 12       LDY   #$12
6117   A2 12       LDX   #$12
6119   C0 12       CPY   #$12
611B   E0 12       CPX   #$12


611D   E2 20       SEP   #$20
611F   C2 10       REP   #$10
6121   09 12       ORA   #$12
6123   29 12       AND   #$12
6125   49 12       EOR   #$12
6127   69 12       ADC   #$12
6129   89 12       BIT   #$12
612B   A9 12       LDA   #$12
612D   C9 12       CMP   #$12
612F   E9 12       SBC   #$12
6131   A0 34 12    LDY   #$1234
6134   A2 34 12    LDX   #$1234
6137   C0 34 12    CPY   #$1234
613A   E0 34 12    CPX   #$1234

Friday, July 6, 2012

65816 Support added to JMON


The other day I added 65816 support to the disassembler in my JMON program. It doesn't currently handle instructions that are of different lengths in 8-bit and 16-bit modes. The code can also now be configured at build time whether to support the 6502, 65C02, additional Rockwell 65C02 instructions, and 65816. The was an extension of my existing code and not based on any part of the DEBUG16 program.

The code now also has a new Options command that allows configuring a few things and will likely support more in the future.

Tuesday, July 3, 2012

DEBUG16 - 65816 Disassembler and Trace Utility


Now that my Replica 1 is running with a 65816 processor, I wanted to try a program that was more substantial than the small demo programs I had tried.

The manual Programming the 65816 Including the 6502, 65C02 and 65802 available from The Western Design Center has a chapter describing and giving the source code for a program called DEBUG16. The program can perform disassembly and instruction tracing of 65816 machine code. It is about 1700 lines of assembler code. I thought I would try porting it to my Replica 1 using the CC65 assembler.

The first step was copying and pasting the assembler listings from the PDF file for the manual. That gave me a text file with the assembler listing of the original code.

Then I stripped out the the listing portion of the file to generate an assembler source file. It needed some changes to port it to the CC65 assembler, due to differences in it's assembler directives. After making a number of changes I had a file which would assemble and I could compare to the original listing.

It turns out there are a number of typographical as well as logic errors in the listing in the manual. A Google search shows at least one other person tried getting this code to work (about 10 years ago) and noticed the errors. After some detective work I think I was able to determine what the errors were, and obtained a file which could successfully build and generated the same code as in the original listing.

The original code was intended for running on an Apple //e with a 65816 card. The Apple specific code (e.g. for input and output) was clearly indicated in the source. I made the necessary changes to the input/output code to work on the Replica 1.

Next, I wrote a small main routine to call the LIST routine which disassembles 65816 code (I had it disassemble itself). Somewhat to my surprise, it actually produced reasonable output on the first try. I found a few errors in the code, such as an instruction or two that were disassembled incorrectly. I fixed that, although there may be some issues with a few instructions. It is at least correct enough for 6502 code that I can disassemble my entire JMON program and get the same output as from the 6502 disassembler that I wrote.

A sample of the output is shown here:

00:6013   08        PHP                                               
00:6014   18        CLC                                               
00:6015   FB        XCE                                               
00:6016   08        PHP                                               
00:6017   0B        PHD                                               
00:6018   F40000    PEA     $0000                                     
00:601B   2B        PLD                                               
00:601C   C220      REP     #$20                                      
00:601E   E210      SEP     #$10                                      
00:6020   649D      STZ     $9D                                       
00:6022   A580      LDA     $80                                       
00:6024   8584      STA     $84                                       
00:6026   A682      LDX     $82                                       
00:6028   8686      STX     $86                                       
00:602A   A780      LDA     [$80]                                     
00:602C   AA        TAX                                               
00:602D   8687      STX     $87                                       
00:602F   207762    JSR     $6277                                     
00:6032   204760    JSR     $6047                                     
00:6035   208F60    JSR     $608F                                     
00:6038   20CD61    JSR     $61CD                                     
00:603B   9005      BCC     $6042                                     
00:603D   20D462    JSR     $62D4                                     
00:6040   80DA      BRA     $601C                                     
00:6042   2B        PLD                                               
00:6043   28        PLP                                               
00:6044   FB        XCE                                               
00:6045   28        PLP                                               
00:6046   60        RTS                                               
00:6047   201D62    JSR     $621D                                     
00:604A   E230      SEP     #$30                                      
00:604C   A000      LDY     #$00                                      
00:604E   A586      LDA     $86                                       
00:6050   20F761    JSR     $61F7

The other function of DEBUG16 is a trace facility that allows stepping through 65816 code and seeing the current value of registers and disassembled instructions. This code has significantly more dependencies on Apple II functions and is harder to port. I spent some time on it, but it is tricky to debug the code as the 65816 changes in and out of native mode and 8/16 bit data and index register modes, and existing debug tools I have like Krusader's mini-monitor will not work in the 65816's native mode. I set this aside to look at later.

So the current status is that the disassembly routine is working well although it has not been tested exhaustively for all 65816 instructions. The trace function has not yet been tested or debugged. The code is available here.

While I was playing with the 65816, I took the time to make a little 65816 quick reference document. It can be printed on one double-sides page, and lists the register model, new addressing modes and instructions, and some other specifics of the 65816. It is most useful if you are familiar with the 6502 and are looking for a quick summary of what is added by the 65816. You can get it here in both OpenOffice.org and PDF formats.

Tuesday, June 26, 2012

Using the 65816 Processor


The Western Design Center 65816 is a 6502 family processor. It is backwards software compatible with the 6502 and 65C02 and was used on a number of computers including the Apple IIGS.

I've been playing with one using the CPU adaptor board I built for my Replica 1.

The 65816 comes up in "emulation mode" where it is software compatible with the 6502 and 65C02. It also implements a number of new instructions, some of which are in the 65C02 and some are new ones.

You can switch the 65816 to "native mode" at any time under software control. Native mode offers 16-bit X and Y registers and accumulator, a 24-bit address space (16 megabytes), new instructions and new addressing modes. In native mode you independently configure whether the accumulator and index registers are 8 or 16-bit. Zero page (now called direct page) and the stack can be relocated anywhere in memory.

The chip is not electrically compatible with the 6502 or 65C02. The 65802 was plug-in compatible with the 6502 but is no longer being made. The 65816 is almost compatible. The adaptor I constructed makes it compatible, or at least compatible enough for the Replica 1.

There are some limitations of the adaptor: the system still only has 16 address lines so 16MB addressing is not possible. The extra 8 high order address lines are ignored. Some hardware pins are also not supported, such as SO and SYNC, but these are not used on the Replica 1.

The only compatibility issue I have run onto is with the CFFA1 compact flash adaptor. It gives an "I/O" error. I suspect it is either due to instruction timing differences or more likely the timing of the clock signals generated by the adaptor is not quite right. I need to investigate further.

Having 16-bit registers is a nice luxury and you can still use 8-bits when you need it, by switching modes, which can save speed and code size.

There are even two new memory copy instructions which can copy a range of memory, up to the full address space, in a single instruction.

I wrote three small demo programs, available here. They compile with the CA65 assembler which fully supports the 65816 instruction set. It even has a "smart" mode where the assembler tracks whether the CPU is in 8 or 16-bit accumulator and index registers modes and generates the code accordingly.

Demo 1 uses some of the new instructions in emulation mode and then switches to native mode, first with 8-bit accumulator and index registers, and then switches to 16-bit. What can be confusing is that an instruction like PHA can push 1 or 2 bytes on the stack depending on the mode selected. An instruction like LDA #$1234 is only valid in 16-bit accumulator mode. As you can imagine, existing 8-bit 6502 machine code will soon break if run in 16-bit mode.

Demo 2 uses the MVP (MOve Positive) instruction. First it copies an overlapping range of memory, demonstrating how it can be used to fill a range of memory, in this case with zeroes. Then it does the more commonly uses copy of a range of memory from one area to another. With this single instruction you can move any amount of memory up to the full 24MB address space, taking 7 cycles per byte copied.

Demo 3 is an example taken from the Western Design Center manual which determines the CPU type: 6502, 65C02, or 65816. I extended it to be a complete program which displays the result on the Replica 1.

Links

Here are some useful links related to the 65816:

  1. http://en.wikipedia.org/wiki/WDC_65816/65802
  2. http://www.zophar.net/fileuploads/2/10538ivwiu/65816info.txt
  3. http://www.defence-force.org/computing/oric/coding/annexe_2/
  4. http://www.smwiki.net/wiki/65c816
  5. http://www.zophar.net/documents/65816.html

The definitive manual is Programming the 65816 Including the 6502, 65C02 and 65802 and is available as a free download from Western Design Center's web site, as is the data sheet.

Debugging Tips for 6502 Programing


After working on some 6502 assembler code recently I was thinking about some useful tips for debugging that I could pass on. Here are a few thoughts based on my experience. Many of these are not specific to the 6502 but valid for assembly language or any software debugging in general.

First, here are some suggestions on things to to to minimize your time spent debugging:

1. Use a cross-assembler

While some programmers can write machine code in their head and change code in memory on the fly, with assembler code you can't afford to make simple mistakes like entering the wrong hex code for an instruction. For any significant amount of code I recommend you use a cross-assembler (or at last a resident assembler, like Krusader).

2. Comment your code

It really helps to comment code, even if you are the only person who may ever look at it. A few weeks or months from now you may not understand what your code is doing if it is uncommented. As compared to high-level languages like C or C++ (or BASIC), I think it is good practice to comment almost every line of code, with additional comments describing what each routine does and tricky features and algorithms, etc. Here is an example:

; Get character from keyboard
; Returns character in A
; Clears high bit to be valid ASCII
; Registers changed: A
GetKey:
        LDA KBDCR               ; Read keyboard control register
        BPL GetKey              ; Loop until key pressed (bit 7 goes high)
        LDA KBD                 ; Get keyboard data
        AND #%01111111          ; Clear ms bit to convert to standard ASCII
        RTS

3. Use a source code management system

Even if you are the only person who may ever use your code, using a source code management system will help you keep different versions of your code during development. This is really useful for the times when you break something that was previously working and you need to figure out what changed. If you use a remote server it also protects you against losing all your work due to human error or hardware failure. There are many services now like github.com, many of which are free for free software projects, that will host your code so you don't have to set up a server.

4. Build up and test small routines

Don't write several hundred lines of code and then attempt to debug it. Write code in small routines and test them individually. It is much easier to debug and your code will likely end up being more modular as well.

5. Do a desk check

A desk check is a manual process of running through your code, as if you were the computer, verifying that it works correctly. It is often helpful to actually step through the code and keep track of values of variables and registers on paper. You will often find errors in your code this way and can more efficiently find and correct the problems.

I have to admit that I sometimes only go back and do a desk check when my code doesn't work the first time (which is usually the case).

6. Print statement debugging

Often you need to figure out where your code is going, and what the values of certain variables are. A tried and true method of debugging is to put instructions in to print information at key points in the code.

You may want to write functions that can print strings and 8 and 16-bit values that you can call for this purpose. In simple code it may be enough to just print single characters or values. If your hardware is such that you don't have a device to send characters to (screen, serial port, etc.) then even a LED or output port can be used to output debug information.

7. Use a simulator.

If you don't have a good debugger on your system you should consider using one of the available 6502 simulators to run and test your code. They may provide a better environment for debugging and testing and eliminate the possibility of hardware problems.

8. Use a debugger

On the Replica 1 the Krusader assembler provide a "mini-monitor" which lets you change registers and single step through code.

My JMON monitor  also has a breakpoint feature that works in conjunction with the mini monitor.

An assembler listing generated by your cross-assembler is also very helpful when single stepping and using breakpoints so you can relate the code to addresses.

Common Errors

Here is a list of what in my experience are some of the more common errors made, even by experienced programmers, when writing in 6502 assembler.

Off by one errors


This is the classic error where a condition test is off by one, such as a loop which runs one time too few or too often.

Branching on the wrong condition

It is easy to use a "BEQ" when you meant "BNE" and hard to notice the error when looking at the code you wrote. Good comments can help here.

Forgetting to clear/set carry before addition/subtraction

This is specific to the 6502 and most programmers soon learn not to make this mistake.

Use # when not needed or missing it when needed

It is easy to forget to use immediate addressing mode mode when that is what you intended or inadvertently use immediate addressing when you shouldn't. For example, the two code examples below are probably wrong but you can easily overlook the mistake, particularly in your own code:

  LDA '$'               ; probably should have been #'$'
  JSR PrintChar


  LDA #VAL              ; if VAL is a memory location, this is wrong
  JSR PrintByte

Registers being changed by called routines

A common error is to call a subroutine and forget that it changes some registers containing values that you subsequently use. I try to always document what registers are changed and try to preserve all registers in code unless I need to optimize them for efficiency.

Conflicts in memory locations (usually page zero)

This is a common error, especially when calling other code that might use memory locations used by your code.

Branching to the wrong part of loop

It is easy to branch to the wrong location in a loop. How many times does the code below run through the loop?

loop: LDX #10
      DEX
      BNE loop

I recently had an error like this (but a little more subtle):

loop1:
        JSR GetKey              ; Get character from keyboard
        CMP #CR                 ; key pressed?
        BEQ EnterPressed        ; If so, handle it
        CMP #ESC                ; key pressed?
        BEQ EscapePressed       ; If so, handle it
        JSR PrintChar           ; Echo the key pressed
        STA IN+1,X              ; Store character in buffer (skip first length byte)
        INX                     ; Advance index into buffer
        CPX #$7E                ; Buffer full?
        BEQ EnterPressed        ; If so, return as if was pressed
        BNE loop                ; Always taken

You can ignore most of what the code is doing. The problem is the last instruction. I meant to branch to label "loop1" but I branched to "loop", which was in a completely different routine (so it assembled okay). In part it happened because I copied and pasted the code from a similar routine and then changed it but left the wrong label. The program ran but the behaviour left me scratching my head and I had to single step through the code before I realized the problem.

Here are some additional errors which in my experience are less common but you should watch out for:

Pushing data on the stack and not correctly restoring it

A particularly bad error is pushing data on the stack and then doing an RTS, which will cause your code to return to the wrong address.

Leaving the CPU in decimal mode

If you use decimal mode, be sure it set it back to binary mode when done.

Jump indirect across page boundary

The 6502 has a bug when using jump indirect across a page boundary. The 65C02 CPU fixes this.

There are many good books on 6502 programming, some of which are freely available on the Internet on sites like http://www.6502.org.

A good reference on 6502 hardware and software advice that was recently posted on the 6502.org forum is here.

Monday, June 25, 2012

Replica 1 Now Running With 65816 CPU


I've now built the 65816 CPU adaptor board described here. The parts arrived last week, I finished wiring it up today, and I powered it up with the Replica 1 for the first time. I was amazed to see that it came up in the Woz Monitor.

I was a little concerned that the design was too simple, and if it did not work for some reason, it could not be made to work.

So far it looks good. I am able to run all the 6502 code I tried and my first quick test of some 65816 instructions, including going into and out of 65816 native mode, appears to work.

I built mine on a protoboard and used two 40-pin DIP headers and a short piece of ribbon cable to attach it to the Replica 1 CPU socket.

65815 Adaptor Board Attached to Replica 1

I'll report here as I learn more about the 65816 and get some code examples running on it.





Oh, and my copy of The New Apple II User's Guide arrived today from amazon.com. I'll post a review once I get a chance to read it (all 700+ pages!)








Monday, June 18, 2012

New JMON commands and Enhancements

JMON is my machine language monitor program for the Replica 1. While waiting for some parts to arrive for my next hardware project, I recently added a few new features to it:
  1. I added a new Register command. It allows displaying and setting the registers. The register values are used when executing a Go command.
  2. The Fill and Search commands now accept a data pattern of any length (up to 127 bytes).
  3. I added back and debugged some code in the break handler that checks for break versus interrupt and displays a message if the handler was called by an interrupt rather than a BRK instruction.
  4. The Go command now does a JSR (or the equivalent) so the called program can return to JMON.
  5. I removed the reliance on some external Woz Mon routines to make it more portable and use constants for the hardware registers like the keyboard and screen.
  6. I added a new = command that does simple hex math calculations (addition and subtraction of two 16-bit hex numbers). An example where this is useful is when using the CFFA1 flash card and you need to calculate the program length given the start and end addresses.
  7. Added a command to call the ACI (Apple Cassette Interface) firmware, if an ACI card is present.


Several Apple 1 related auctions were recently completed.

An original Apple 1 on eBay sold for US$75,600.

An original Apple 1 auctioned by Sotheby's in New York sold for US$374,500. This is a new record high for an Apple 1.

A Mimeo-1, the Apple 1 reproduction kit by Mike Willegal, sold on eBay for US$2,025. Note that this was a kit that included all parts but needed to be assembled. Mike also just posted on his blog that he will be offering more Mimeo-1 kits and assembled systems.

Just as a point of comparison, the original Apple 1 originally sold new for US$666.66.



Vince Briel of Briel Computers is considering making another run of reproduction Apple 1 Cassette Interface board kits.  He needs 20 people interested in purchasing one to justify a run of boards. E-mail him if you are interested.



While it is Apple II related rather than Apple 1, the long awaited first new book to be published on the Apple II, The New Apple II User's Guide, started shipping this week. I've already ordered a copy and plan to write a review when I finish reading it.