6802/6808 Assembly Code Development

Code Development

One area that I have not previously explored is the development of my own ROMs for the 6802.  To get started in this area, I looked into several cross-assemblers, and settled on the A68.  One appealing aspect is that it is a small, portable (143 kbytes) DOS command line application.  My first goal was to write a small assembly program that demonstrates the basic interactions I would need and then decide later how far to take it.  This initial program would 1)read ROM, 2)write and read RAM, and 3)do some PIA output toggling.  It would also 4)demonstrate the Reset and Interrupt vectors.

The first thing to figure out is how to set up the code to run.  From reading the datasheet on the 6802, the CPU core uses the word at the top of memory as the vector to jump to after a Reset (this is known as the Reset Vector).  One important thing to note is that on System 11 (my first target system), the U27 ROM is located starting at address 0x8000.  It is a 27256 (a 32kbyte) device.  So it spans from CPU address 0x8000 to CPU 0xFFFF.  This needs to be taken into account in the constants in the ROM.  An example with a super minimal program illustrates this:

; Top of program
LOOP    ORG    $3FFF
        JMP    $BFFF
; Set up Reset Vector
        ORG $7FFE
        FCB $BF,$FF

In the code snippet above, note that the code placed in ROM 0x7FFE is equivalent to CPU 0xFFFE.  That is where the word 0xBFFF is placed (composing out of bytes 0xBF and 0xFF).  When the CPU jumps to 0xBFFF, it is really reading ROM location 0x3FFF, and that is why the "Top of program" is placed at 0x3FFF with the ORG statement.  Examination of the generated .hex file confirms the placement of the bytes 0xBFFF in the top word of the ROM.

Development Environment

I have been using a Dataman S4 for several years to program ROMs, and I know it has an emulator mode.  I had initially assumed that I needed to  connect the CPU board (the target location) to the ZIF socket where the ROM normally goes, but after emailing the manufacturer, I learned that a special emulator cable plugs into the back of the programmer.

ROM emulation cable for an S4.  Left end plugs into the S4,
right end into the target board at the ROM location.

This cable effectively turns the S4 into a ROM chip that can be easily changed and updated via its serial cable.  I therefore didn't need to constantly burn and erase ROMs to try code revisions.

development setup

S4 (right) plugged into the System 11 board.

The above images shows the development environment.  The S4 is plugged into the System 11 board at the U27 ROM location, and the CPU chip is plugged into a breakout board that allows me to connect in my Logic Analyzer.  This latter tool allows me to observe what the CPU chip is doing and do general code debugging.

The power of this setup is shown by the fact that I can edit the assembly file and then have that code running on the board in mere seconds.  I can repeat this cycle quickly without having to burn and UV erase any PROMS.  As a note, the hex file that A68 generates can be transferred directly into the S4 without any processing (set S4 to hex mode).

Running the Code

The sample program (see link below),  was assembled and then loaded into the  S4  ROM emulator.  The Logic Analyzer result is shown on the right side of the image below.  This simple program demonstrates  most of the goals set above.  


Assembly listing on the left and the Logic Analyzer samples of the Address and Data Bus on the right.

The 'Full' revision below adds understanding of the rest of the interrupt vectors so that the code can be diverted when the test switch on the CPU board is pressed.  Future work will be to develop a diagnostic test program like Leon's (RIP), but with some enhancements.  It will be available for download in the section below.

Disassembler - Going the other way
One other aspect of assembly development is to be able to possible change or add enhancements to existing code.  The first step in this is to decode or reverse the process above and obtain some kind of human readable form from the original binary image.  In essense, to dis-assemble the ROM file.  After some looking it appears that DASMx is a good choice to check out as it features "code threading".  Similar to A86, it runs as a simple, small command line .exe file.

Since I was familiar with it and there were no copyright issues, I ran my 'full' version of the assembly code through it.  The first step of that is to obtain a ROM image.  The output of the A68 assembler is hex (and can directly be sent into the S4), but DASMx takes a complete binary image.  The easiest way for me to obtain that is to read back out the S4 memory.  I had previously 'erased' the S4 buffer by filling it with 0xFF, just like an erased ROM would appear.  I then created a symbol file so that the Dissassembler could annotate the results accordingly and help me interpret its output.  I then ran the program and could see that DASMx correctly interpreted all the bytes as being either instruction or operand.  An example is the "Main" loop that loops continuously.  A portion of the output is analyzed below.

This is the output from the A68 cross-compiler (assembly to opcode):

 ; Top of main to demo read/writes
 3000     MAIN    ORG    $3000     ;@B000 to CPU
 3000   b6 80 00    LDA A $8000    ; Read bottom of ROM and write to RAM
 3003   97 01       STA A $0001    ;   0001 <- 8000 (memory location)
 3005   96 01       LDA A $0001    ;   0001?
 3007   86 55       LDA A #$55     ; Write constant to RAM
 3009   97 01       STA A $0001    ;   0001 <- 0x55 (literal)
 300b   96 01       LDA A $0001    ;   0001?
 300d   8e 07 ff    LDS #$07FF     ; Set location of Stack
 3010   7e b0 00    JMP $B000

and this is the listing from the DASMx disassembler (opcode back to assembly):

B000                swi_handler:
B000                rst_handler:
B000 : B6 80 00     ldaa    X8000
B003 : 97 01        staa    X0001
B005 : 96 01        ldaa    X0001
B007 : 86 55        ldaa    #$55
B009 : 97 01        staa    X0001
B00B : 96 01        ldaa    X0001
B00D : 8E 07 FF     lds    #$07FF
B010 : 7E B0 00     jmp    swi_handler

Note the similarity in the opcodes and the assembly code in both listings.  The full listing files are included below.

CPU Board Test ROM - XFlash
Each of the PIAs on the Williams CPU boards have an 8-bit Port A, an 8-bit Port B, and a 4-bit Port C.  Unfortunately, Leon's PROM does not test the Port C pins, and I have always wanted to change that.  I decided to write my own test PROM as a result.  Outputs CA2 and CB2 are not difficult to test, and the new code does that by toggling them.  However CA1 and CB1 are input only.  They are tested on the board by applying a toggle to these inputs.  Once this is done, the code halts toggling of that PIA's outputs to indicate successful reading of the pulse.

On a System 11 board, there are three PIAs that have their CA1 and CB1 pins connected as inputs.  The first is U51, the second is U41, and the third is U42.  The first one inputs the coin door switches on its CA1 and CB1 pins, so toggling either of those switches will cause the LED2 on the board to stop flashing (that is demonstrated in the video below).  The other PIAs have their CA1 and CB1 ports connected to 1J21, so you can test those functions by jumpering to the appropriate pins.

Video of System 11 board running the XFlash ROM.

The above mentioned functions of the test ROM work without using any of the RAM (since this may be faulty in the target CPU board).  As a result, I cannot make the use of subroutines as any call would require pushing return information onto the stack.  So I had to figure out how to use the CPU's own meager registers to perform tasks such as loops for delays.  One such register is the X (index) register.  This can be loaded, incremented and tested for a particular value so it makes for a good delay counter.  Another register to use possibly is the Stack Pointer register.  As for flags, it may be possible to use the Interrupt Enable flag (I) in the Status Register, although if you set it, the IRQ will fire every ~928 instructions (CPU pin 4).

Finally, just like Leon's ROM, pushing the 'test' button on the CPU board will run a RAM test.  If that fails, the program will halt and light the LED2 on the CPU board.  XFlash is available for download both in assembly and compiled hex code.  You just need to burn the code into a 27256 PROM.

Afterwards, I developed the ROM for the System 9 board and got better at assembly.  I was able to remove all the absolute jumps and made the code easier to read and more portable.  I was then able to combine the System 9 and 11 versions into one file and have a simple IF switch control the assembly process.  The source assembly file is available below.  To use the hex files, simply download the appropriate one and burn a 27128 ROM for System 9 or a 27256 ROM for System 11.

After further study, I realized that the ROM image for the System 9 would also work for a System 11 if I burned the image in both (top and bottom) halves of the 27256.  A test showed this is correct.  A single 27256 (with the 2x System 9 image) works in both System 9 and 11 boards.  Subsequently I made adjustments to allow the same ROM to run both the main as well as the sound section on both types of boards.  So this single ROM can do the work (with improvements) of the four previous versions of Leon's ROMs.



Main Pinball Page

Back Home

(c) 2021 Edward Cheung, all rights reserved.