Sunday, April 14, 2019

A 6809 Single Board Computer: Instruction Trace/Step Function

In my JMON monitor for the 6502, I implemented a trace or step function where you can execute code one instruction at a time and see the results of execution on the CPU registers. This is very useful for debugging, particularly as this implementation supports stepping through ROM code, something that can't be done with breakpoints.

For my 6809 single board computer I wondered if I could do the same for the 6809 processor. After some thought, it looked feasible, although more challenging as the 6809 has a larger and more complex instruction set than the 6502.

The basic idea is to take the instruction to be executed and store it in a buffer in RAM. The values of all CPU registers from the previous instruction trace are restored and the instruction is executed. A jump instruction is placed right after the traced instruction that goes back to the trace program. After execution, the new register values can be displayed and saved. This allows running code that is in ROM, as it gets copied to RAM when executed.

To implement this requires knowing the length of each instruction, as they can vary on the 6809 from one to five bytes depending on the instruction and addressing mode. From my previously written disassembler I already had code that could determine the instruction length and even disassemble it.

A wrinkle in this approach is handling instructions which cause a change in the flow of execution, such as a JMP (jump) instruction which would not return if simply executed in the buffer. We need to handle this instruction as a special case. We can examine the destination address and update the saved program counter accordingly. We don't need to actually execute it since it changes no other registers than the PC. We do need to check for and handle both direct (8 bit) and extended (16-bit) jump instructions. For direct, the destination address needs to be calculated by combining the instruction operand with the current value of the direct page (DP) register.

Jump to subroutine (JSR) in another special case. Here we need to push the return address on the stack (using the saved value of the stack pointer that we trace with) and then calculate the new PC value.

Similarly, we can handle BRA/LBRA and BSR/LBSR like JMP and JSR but the effective address needs to be calculated by adding the offset to the current PC value. Again we don't need to execute the instruction, just update the new PC value.

The interrupt related instructions SYNC, CWAI, SWI, SWI2, and SWI3 can all be simulated by pushing registers on the stack and setting the PC to the appropriate interrupt vector.

RTS and RTI are simulated by pulling registers (in the case of RTI) or just the PC (for RTS) off the stack. One wrinkle is that in the 6809 we need to check the E (Entire) flag in the condition code register to know of we should restore all registers from the stack.

Conditional branches are a little more tricky. They can transfer control to two different places depending on whether the condition is true or not. These are handled by writing into the execution buffer both the instruction being traced as well as different jumps depending on whether the branch is taken or not. The branch destinations can update the PC accordingly. The code in the buffer looks like below:

XXXX XX 03           Bxx $03 (Taken)         ; Instruction being traced
XXXX 7E XX XX        JMP BranchNotTaken
XXXX 7E XX XX Taken  JMP BranchTaken

We execute the instruction in the buffer and let it perform the test. We need to handle all the possible branch instructions, both short and long versions.

TFR (transfer) and EXG (exchange) instructions are okay to run except the cases where the source or destination is the PC. We need to handle those cases manually since it would otherwise change the flow of control.

Similarly, PSHS/PHSU and PULS/PULU could potentially include the PC in the list of registers pushed or pulled. Currently I just check for this case, remove the PC from the list of registers, and warn the user in this case that it is not fully handled yet.

Indexed addressing poses a challenge: we need to handle an instruction that changes flow of control like JMP 1,X with an arbitrary index addressing mode. It might also produce side effects in the case of instructions like JMP 1,X++. These are handled using a trick: instead of JMP, we run a LEAU instruction with the same indexed operand. Then we examine value of U, which should be the new PC. Currently the code can't handle addressing modes that change the U register like JMP ,U++.

A final challenge is PCR relative index addressing. If we move the instruction to the buffer to execute it, the PC relative address is now wrong. I thought about this, and it should be possible to adjust the offset based on the difference between the original instruction location and the address of the buffer where it will be run. This would get a little complicated, so I didn't implement it (yet). For now I just ignore it and display a message at run time that it is not supported.

After working out most of the logic as pseudocode, I implemented and debugged it. I started with the basic instructions and then added all of the special cases, testing them one at a time. Once done, I tested it with some smaller complete programs.

Finally, I was able to integrate it into the "combined" ROM which also contains the ASSIST09 monitor, disassembler, and Microsoft Basic. I added the trace command as a new ASSIST09 "T" command. It took some shuffling but I was able to just get them all to fit in the 8K ROM.

It hasn't been tested exhaustively, and it can't run BASIC because it uses some PC relative instructions, but it seems to work quite well. Here is some sample output:

>T D000
D000  81 30        CMPA  #$30 
PC=D002 A=FF B=FF X=FFFF Y=FFFF S=FFDF U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D002  25 04        BCS   $D008 
PC=D004 A=FF B=FF X=FFFF Y=FFFF S=FFDF U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D004  81 3C        CMPA  #$3C 
PC=D006 A=FF B=FF X=FFFF Y=FFFF S=FFDF U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D006  25 C0        BCS   $CFC8 
PC=D008 A=FF B=FF X=FFFF Y=FFFF S=FFDF U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D008  30 1F        LEAX  $1F ,X
PC=D00A A=FF B=FF X=FFFE Y=FFFF S=FFDF U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D00A  34 50        PSHS  U,X
PC=D00C A=FF B=FF X=FFFE Y=FFFF S=FFDB U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D00C  0F 41        CLR   $41 
PC=D00E A=FF B=FF X=FFFE Y=FFFF S=FFDB U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D00E  CE C0 E7     LDU   #$C0E7 
PC=D011 A=FF B=FF X=FFFE Y=FFFF S=FFDB U=C0E7 DP=FF CC=01111110 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D011  0F 42        CLR   $42 
PC=D013 A=FF B=FF X=FFFE Y=FFFF S=FFDB U=C0E7 DP=FF CC=01111110 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D013  33 4A        LEAU  $0A ,U
PC=D015 A=FF B=FF X=FFFE Y=FFFF S=FFDB U=C0F1 DP=FF CC=01011001 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT 

References

  1. https://github.com/jefftranter/6809/tree/master/sbc/trace
  2. https://github.com/jefftranter/6809/tree/master/sbc/combined
  3. https://github.com/jefftranter/6809/tree/master/sbc/disasm
  4. https://github.com/jefftranter/6502/tree/master/asm/jmon

Saturday, April 13, 2019

A 6809 Single Board Computer: The MC6839 Floating Point ROM



Implementing floating point math was a challenge with 8-bit microprocessors. The early version of BASIC for the 6502-based Apple 1 and Apple 2 series written by Steve Wozniak only supported 16-bit integer variables in order to keep the size down and achieve acceptable performance. Later, Applesoft BASIC was licensed from Microsoft which supported floating point variables. A significant amount of the code for Microsoft BASIC for 8-bit microprocessors was dedicated to floating point math. Some versions, loaded from tape, gave the user the option to leave out the sin/cos/tan trig functions to save space and free up some memory.

The 6809 supports instructions for 8-bit addition, subtraction, and division and some 16-bit math instructions. While more powerful than earlier processors like the 6502 and 6800, implementing floating point math was still a significant undertaking. Motorola saw an opportunity to offer a floating point math library as a standard product for the 6809. This was made more viable for two reasons:

  • An IEEE standard for floating point math formats appeared to be poised to become an industry standard.
  • The 6809 allowed writing position independent code, so a floating point library could be offered in binary form that would be independent of the memory map of the system it needed to run on.

Out of this came a product: the MC6839 Floating Point ROM. While essentially a software product, it was sold as hardware: an 8K ROM programmed with the floating point code. As well as the ROM, it included a programming manual almost 100 pages in length, describing how to use it.

The basic features of the library were:

  • An 8KB ROM which would run at any contiguous range of addresses.
  • All RAM used was relative to the stack pointer.
  • A well documented API that allowed operands to be passed in registers or via the stack.
  • Fully implemented the IEEE Standard for floating point math (at the time, still in draft form).
  • Support for the following operations: add, subtract, multiply, divide, remainder, square root, integer part, absolute value, negate, condition code compares, conversion between integer and floating point, and conversion between binary floating point and BCD.
  • Supported three precisions (4, 8, and 10 bytes) defined by the IEEE standard.
  • Supported the rounding modes, closure modes, and normalize modes defined by the standard.
  • Supported handling of exceptions (e.g. division by zero).

According to the source code it was written around 1980, with revisions up to at least 1982. The author names in the source code were Greg Stevens, Joel Boney, and G. Walker. In 1988 the source code was put in the public domain by Motorola, and can be found on the Internet as well as the binary for the ROM.

I came across the code and decided to try it out on my 6809 single board computer. There is a programming example in the manual that finds the roots to quadratic equations of the form ax^2 + bx +c = 0 using the classic formula -b +/- sqrt(b^2 - 4ac) / 2a

I typed in the example and adapted it to the lwasm assembler. The program uses a standard set of macro instructions to set up the parameters in the correct calling sequences for the ROM. These macros make the code much more readable and were easily ported to the lwasm assembler. I needed to make a few changes in order to make the example a complete runnable program. When run, and with the S record file for the MC6839 ROM also loaded into memory, I was able to get the example to run and produce the correct results. The code is on my github account.

Since I had the source, I took a look at whether I could assemble it. It would take some effort because the original source required a special Motorola "structured assembler" that I have not been able t find any information about. It has a number of structured programming macros for things like looping and conditionals. Given some time this could be reversed engineering by looking at the binary file.

I also found that the source does not quite match the binary (the former has a 1980 copyright date and the latter 1982). Without having a known good binary that corresponds to the source code, porting would be a challenge, so I set any further work on this aside for now.

The MC6839 Floating Point ROM was Motorola's first foray into this type of binary ROM product. The data sheet lists the product as "preliminary" and according to one source it was never actually offered as a product.

Later processors, like the 68000 series, would support floating point math in hardware using either a separate dedicated chip or on-board floating point unit (FPU). These still use (as do modern computers, including your smart phone) the IEEE standard for floating point math.

References

  1. https://github.com/jefftranter/6809/tree/master/sbc/mc6839
  2. http://github.com/brouhaha/fp09
  3. http://www.colorcomputerarchive.com/updates/2017
  4. http://www.classiccmp.org/pipermail/cctalk/2017-March/033678.html
  5. http://www.classiccmp.org/pipermail/cctech/2016-June/019519.html
  6. http://www.colorcomputerarchive.com/coco/Documents/Manuals/Hardware/MC6839%20Floating-point%20ROM%20Manual.pdf

Sunday, March 17, 2019

Hugo Winner Book Review: Lord of Light by Roger Zelazny


Arthur C. Clarke's Third Law states: Any sufficiently advanced technology is indistinguishable from magic. This book is based on a similar premise: Any being with sufficiently advanced technology is indistinguishable from a god.

The book was the winner of the Hugo Award for best novel in 1968. An interesting mixture of science fiction and Hindu and Buddhist mythology, it is never really explained where or when the events happen.

I found it an interesting concept, but I didn't fully buy into it and didn't find any characters that I really liked or felt that I understood. I found it rough going to get through, despite being extremely well written and very poetic in places.

It is an interesting and imaginative concept that defies categorization as science fiction, fantasy, or something else.

Wednesday, February 20, 2019

Hugo Winner Book Review: The Moon is a Harsh Mistress by Robert A. Heinlein


The winner of the Hugo for best novel in 1967, this was the sixth (and last) Hugo won by Heinlein.

It is pretty much classic Heinlein fare, with a good adventure story, interesting characters, and some bold predictions about the future. He also used it as a vehicle to promote some of his ideas on politics, the military, and marriage, but keeps it a little more restrained and less preachy than some of his earlier (and later) novels. It also has a little more humour than his earlier novels.


I had read it some time ago, but enjoyed it on re-reading. In some ways it seems more like his stories written prior to Stranger in a Strange Land, despite being written later. My only complain was that it used a strange plot device: the narrator speaks in a dialect of English influenced by Russian. The use of some Russian words was fine, but his speech takes on some features of Russian grammar, most notably omitting the use of the article "the". Find it makes for annoying read after while.

The novel also helped popularize the expression TANSTAAFL: There Ain't No Such Thing As A Free Lunch, although it was apparently in use before the book used it.

Reviewing Heinlein's bibliography, I would also say that this marked the last of his books that I really enjoyed. His later works (1970 and later) seemed to me to either repeat similar themes, and/or seemed to be written merely to shock the reader.

Tuesday, February 12, 2019

6809 Single Board Computer: TSC Micro Basic Plus

On the hunt for interesting software that could run on my 6809 Single Board Computer, I came across a small BASIC interpreter.

Originally written for the 6800 processor to run on systems like the Southwest Technical Products SWTPC, Micro Basic Plus was developed by Technical Systems Consultants in 1976 and cost $15.95 for the manual and listing. A cassette tape was $6.95 and paper tape was $6.00. The original version can be found here  and had this marketing blurb about it:


TSC Micro Basic Plus

This is the most complete small Basic available to micro users. Statements include: PRINT, INPUT, READ, DATA, RESTORE, IF ... THEN, GOTO, GOSUB, LET, ON ...GOTO, ON ...GOSUB, RETURN, FOR (with + and - step), NEXT, DIM (single and double dimensioned arrays up to 98 by 98), REM and END. There are also several functions available which include TAB and SPC (for output formatting), RND, ABS, SGN and exponentiation. The commands available to the user are LIST, SCRATCH, RUN, and MONITOR. But the list does not stop here. MICRO BASIC PLUS also includes a complete line editor ability to have multiple statements per line, direct execution of most statements, large arithmetic range (integer only -99999 to +99999), and a very simple load and dump procedure for saving the user's BASIC program on paper tape or cassette and then reloading it at a later time. Also included is an EXTERNAL statement which allows the user to write 6800 machine language subroutines to be called during BASIC program execution.

You are probably thinking all this sounds great, but if the less extensive versions of small BASIC require 23K of memory then this version must require 5 or 6K because the capability is doubled. Well here is the icing on the cake. MICRO BASIC PLUS resides in a fraction over 3K which means that in a 4K system you still have room for a 30 to 60 line BASIC program. For more complex programs, we recommend a system with 8K or more of memory.

One more plus... you not only receive a complete manual and hex dump of the program, but also the fully commented source listing! This is a great aid for learning programming techniques as well as enabling you to alter the program should you so desire.


I found a 6809 port here,  developed by Drexel University to run on their 6809 Single Board Computer. It looks to have been a straight port from 6800 to 6809 mnemonics with the input/output routines adapted to their hardware and monitor.

I ported it to my board, using ASSIST09 monitor routines for i/o. I had it up and running in an evening, and made a few improvements after that. It supports most common BASIC keywords including ON/GOTO and ON/GOSUB and one and two dimensional arrays.

Overall, though, the language is pretty limited as compared to other BASICs with support for integer math only and no string variables at all. This is not surprising given that it is only a little of 3 Kilobytes in size! It is not too different in capabilities from Apple 1 BASIC originally written by Steve Wozniak and later expanded into Integer BASIC for the Apple ][.

I tried a few sample programs and they ran quite well. I made an enhancement it to show full error messages rather than just numbers (which increases the size by another 1/2 K or so). The code is here.

For running real BASIC programs I think I will stick to the port of Microsoft BASIC for the Color Computer, but this is an interesting little program.

Friday, February 8, 2019

A 6809 Single Board Computer: Cross-Compilers under Linux


Assembling code by hand is possible, but for any program of non-trivial size, cross-compilation is the way to go, even for 8-bit processors like the 6809. When working with my 6809 single board computer I went looking for a suitable cross-assembler. My requirements were to support the 6809, run on Linux, and be freely available. I came across three suitable programs, which I'll briefly describe here.

AS9 Assembler

Home page: http://home.hccnet.nl/a.w.m.van.der.horst/m6809.html

Documentation: http://home.hccnet.nl/a.w.m.van.der.horst/as11v2.pdf

This code is apparently derived from the original and official Motorola cross-assembler circa 1981. Written in very old pre-ANSI standard C, it was modified by a number of people over the years, and this version was last modified Albert van der Horst in 2004 to compile under Linux. I had no trouble building it under Ubuntu Linux.

As the official Motorola assembler, it follows the Motorola documentation. It seems pretty comprehensive, and supports the 6800, 6809, 68HC11, and some other chips in the 68xx series.

I have used this as my primary cross-assembler to develop or port the 6809 code I've been working on. The S-record files it generates are happily accepted by the ASSIST09 monitor's Load command.

Here is a sample output listing:

0005 7000                            ORG     $7000           ; Start address
0006                         
0007 7000 86 12              START:  LDA     #$12
0008 7002 c6 34                      LDB     #$34
0009 7004 8e 56 78                   LDX     #$5678
0010 7007 1e 89                      EXG     A,B
0011 7009 12                         NOP
0012 700a 12                         NOP
0013 700b 39                         RTS

The only quirk I encountered is a known issue where it can produce invalid warnings about comments. I worked around this when needed by disabling warnings with a command line option.

ASM6809 Assembler

Home page: https://www.6809.org.uk/asm6809

Documentation: https://www.6809.org.uk/asm6809/doc/asm6809.shtml

This is a portable cross assembler targeting the Motorola 6809 and Hitachi 6309 written by Ciaran Anscomb. It features arbitrarily complex expressions (with most C-style operators available), forward references, macro expansion and conditional assembly. Output formats are: raw binary, DragonDOS binary, Color Computer RS-DOS or "DECB" binary, Motorola S record, and Intel HEX.

Written in C, it is licensed under the GPL and is actively being maintained with the latest version being 2.11 released on 2018-07-27.

I downloaded the source and was able to build it with no problems simply by running the configure script, make, and sudo make install.

Trying it on my 6809 disassembler program (about 2000 lines of code), the only issues I encountered were that it didn't accept labels with a colon at the end and it didn't like one symbol I used that started with a dot. After making appropriate changes, the code built fine. It even warns that some long branches fit in eight bits and could have used short branches, so I modified them and made the code a little smaller. I did notice that it generated slightly different code than the as9 assembler had, where it picked a different (more efficient) indexed addressing mode that could use a 5-bit displacement.

Here is a sample listing:
                     
7000                          ORG     $7000           ; Start address
                      
7000  8612            START   LDA     #$12
7002  C634                    LDB     #$34
7004  8E5678                  LDX     #$5678
7007  1E89                    EXG     A,B
7009  12                      NOP
700A  12                      NOP
700B  39                      RTS

It generated a Motorola S record (RUN) file, but the ASSIST09 firmware did not like to load it. Investigation showed that it was producing S record files with invalid checksums. I made a code fix to the source for this. It also doesn't produce the S9 record at the end of the file that ASSIST09 wants to see, unless you have an END directory specifying that start address.

LWTOOLS

Home page: http://lwtools.projects.l-w.ca/

Documentation: http://lwtools.projects.l-w.ca/manual/manual.html

LWTOOLS is a set of cross-development tools for the Motorola 6809 and Hitachi 6309 microprocessors. It supports a number of output formats including raw binary, Motorola S record, Color Computer binaries, and a proprietary object file format that supports linking.

It is implemented in C and is actively maintained. I used version 4.16 that was released in December 2018.

It supports a number of platforms. I was able to build it with no issues on Ubuntu Linux. It installs a number of tools including lwasm, lwlink, lwar, and lwobjdump.

Here is a sample output listing:

                      (          ex1.asm):00005                 ORG     $7000           ; Start address
                      (          ex1.asm):00006         
7000 8612             (          ex1.asm):00007         START   LDA     #$12
7002 C634             (          ex1.asm):00008                 LDB     #$34
7004 8E5678           (          ex1.asm):00009                 LDX     #$5678
7007 1E89             (          ex1.asm):00010                 EXG     A,B
7009 12               (          ex1.asm):00011                 NOP
700A 12               (          ex1.asm):00012                 NOP
700B 39               (          ex1.asm):00013                 RTS

I only tried the assembler, using my disassembler program again. It didn't like items in FCB directives to be separated by any white space, only commas. It also didn't a like symbol starting with "." Other than that it assembled it fine, and generated a S record file which I successfully loaded and ran on the single board computer.

For advanced development work where you might want to assemble multiple files and link them, this looks like a good choice for a toolset. A 6809-based C compiler I have tried, CMOC, uses it as it's cross-assembler.

Summary

All three of these cross-assemblers look adequate for basic 6809 assembly language programming hosted on a Linux desktop. With a few changes I was able to get same source code for my disassembler to build with all three assemblers.

Tuesday, February 5, 2019

A 6809 Single Board Computer: Disassembler and Thoughts on the 6809


As a project to use my 6809 SBC and learn more about 6809 assembly language programming, I wrote a disassembler that can run on the board. The design was loosely based on the one I did for the 6502.

While straightforward in principle, a disassembler for the 6809 is a little more challenging that for the 6502 for a number of reasons:
  • It supports many instructions.
  • Some instructions have unique operand formats (e.g. TFR/EXG, PSH/PULS).
  • There are many (24) different indexed addressing modes.
  • The instruction length can change based on the indexed addressing mode being used.
  • Some instructions are two bytes long, prefixed by $10 or $11 (the so-called page 2 and page 3 op codes).
Implementation was pretty straightforward. I used lookup tables for a number of things including op codes, instruction types, addressing modes, and mnemonics. I strove to make the code readable and avoided any tricks that might increase efficiency slightly at the expense of clarity.

It is mostly portable. It uses ASSIST09 monitor routines for i/o, but other than that could be used on other systems with minor changes.

I implemented over a few evenings, building it up in pieces. It took some time (but less than I expected) to handle all the index addressing modes and to correctly handle the differing instruction lengths and page 2/3 instructions.

My basic approaches for testing and debug were:
  1. Test low level functions, like PrintString, on their own with some test code.
  2. "Desk check" complex code on paper to try to verify the logic, use of registers, etc.
  3. Build it up in stages and confirm them working before adding on (e.g. initially just display hex bytes)
When I ran into bugs I used the "desk check" method as well as making use of breakpoints when running the code to see what it was doing at various steps. Having a working monitor to run, display and change memory and registers, etc. was a requirement and ASSIST09 worked well for that. Downloading new versions of code over the serial port only took a few seconds.

I initially ran it standalone, but at the end I was able to also support installing it as an external command in the ASSSIST09 monitor, so you can run it by typing U (for unassemble). ASSIST09 has calls to add new commands, so it can be done without changing the code in ROM.

Here is some sample output (disassembling the start of the ASSIST09 ROM code):

>U F800
F800  30 8D 68 BE  LEAX  $68BE ,PCR
F804  1F 10        TFR   X,D
F806  1F 8B        TFR   A,DP
F808  97 9D        STA   $9D 
F80A  33 84        LEAU  ,X
F80C  31 8C 35     LEAY  $35 ,PCR
F80F  EF 81        STU   ,X++
F811  C6 16        LDB   #$16 
F813  34 04        PSHS  B
F815  1F 20        TFR   Y,D
F817  E3 A1        ADDD  ,Y++
F819  ED 81        STD   ,X++
F81B  6A E4        DEC   ,S
F81D  26 F6        BNE   $F815 
F81F  C6 0D        LDB   #$0D 
F821  A6 A0        LDA   ,Y+
F823  A7 80        STA   ,X+
F825  5A           DECB
F826  26 F9        BNE   $F821 
F828  31 8D F7 D4  LEAY  $F7D4 ,PCR
F82C  8E 20 FE     LDX   #$20FE 
F82F  AC A1        CMPX  ,Y++
F831  26 02        BNE   $F835 
F833  AD A4        JSR   ,Y
PRESS SPACE TO CONTINUE, Q TO QUIT 

With a little more 6809 assembly language programming experience under my belt, it is interesting to compare it to the other 8-bit processor I am most familiar with, the 6502. Let me list a few thoughts here.

Having two accumulators is very handy. Often one is being used as an accumulator for some form of data, but another may be needed for indexing or as a parameter to calling another routine. Surprisingly, I also found myself using the 16-bit D register (which uses A and B) because I needed 16-bit data. Some functions, like addition and subtraction, are supported on the D register, but many only have 8-bit versions which you need to combine using several instructions to work on 16 bits of data.

Two index registers is also handy (the 6502 has two, but the 6809's predecessor the 6800 only had one). But I found in practice that I rarely needed a second one. Having 16-bit index registers, unlike the 8-bit registers of the 6502, was much more convenient as you often find you are using them to store addresses.

The 6502 typically makes the programmer heavily use addresses in the first 256 bytes of memory (page 0). Some key instructions and addressing modes can only work with page zero. For that reason, these tend to become valuable real estate and you can run out of them or run into collisions between different uses of them. In contrast, the 6809 has a more orthogonal instruction set and all relevant instructions can work with full 16-bit addresses. It does have direct mode (8-bit addresses) but with the Direct Page register you can have them work with any page of memory, not just page zero. I did not use this feature (the ASSIST09 monitor does) but I can see it being useful when you wanted to optimize the size of your code.

In general the 6809 is more orthogonal than the 6502, with few limitations on the addressing modes or operands of instructions. Unlike the 6502 you can push, pull, transfer, or exchange any registers. The push and pull (PSHS/PSHU/PULS/PULU) instructions are particularly nice in that you can push or pull a set of registers in one instruction. The order of push and pull is defined, so that you do not have to ensure that the order is correct in your code (provided you push and pull the same list of registers). There are two stack pointers, but I only used one. And of course, the 16-bit stack pointer is much more reasonable than the 8-bit stack on the 6502 that is fixed in page 1 of memory.

Transfer (TFR) and Exchange (EXG) are two other instructions which are very handy for moving registers around without any restrictions. The 6502 had some limitations on what registers you could transfer and had no equivalent to EXG.

The 6809 introduced a MULtiply instruction, which sounded at the time like a luxury for assembly language programmers. I actually used it in an early version of my disassembler program when I needed to multiply the offset to a table by 4 and get a 16-bit result. I felt it was overkill using a multiply to do this, and later did it using two shifts (you can easily implement a 16-bit shift of the D register using two instructions: ASLB, ROLA).

The 6809 has many more addressing modes than the 6502, with 24 variations of indexed addressing. I think it is unlikely that assembly language programmers would use the majority of these as just a few of them generally suffice. I suspect the original intention may have been to help support compilers of high-level languages that could use these.

One quirk with indexed addressing that could confuse programmers is that the 5, 8, and 16 b-t offset modes consider the offset to be signed. So, for example, the 5 bit offsets are not 0 to 31 but rather -16 to 15. If you have a lookup table of 256 elements, for example, and expect the 8-bit offset indexed addressing mode to access all of them starting from an offset of zero, you will be surprised when values of $80 and higher don't read the table entries you expected. I ran into this, and solved it by using 16-bit offset in this case.

One instruction that you could easily overlook is LEA (Load Effective Address). It might not seem particularly useful, essentially removing one level of indirection. In fact it is very useful, and is the key to a lot of efficient programming as it can make use of all of the indexed addressing modes and make code position independent.

The 6809 supports position independent code (PIC). The ASSIST09 monitor, for example, is fully position independent. It is not particularly hard to write PIC code, and I made some effort to try this in the disassembler. Mostly it is a matter of using branches rather than jumps and using the PCR (program counter relative) addressing mode when working with addresses. I did leave the memory locations in RAM used by the program at fixed addresses. One annoyance is that as code gets larger during development 8-bit branches often fail and need to be converted to long branches. Unlike some assemblers, the one I was using did not automatically select short or long branches as needed.

Overall, the 6809 is quite a pleasant processor to program, with more instructions, more and larger registers than the 6502. Of course, it is not really a fair comparison as it came a generation later and could make use of advanced in technology that allowed a more complex chip. The 6800 was of the same vintage as the 6502. In fact, the decision to use the 6502 over the 6800 in a number of early computers was based on cost. Compared to the $300 price tag of the 6800, the 6502 sold for $25. The Apple 1 was originally designed to use a 6800, but was converted to the 6502 when Steve Wozniak learned about it. The schematic diagram for the Apple 1 still listed the circuit changes needed on the board to use a 6800.