CoCo 3 PIA 2 Mirror

The second PIA has a smaller mirror in the CoCo 3 than the CoCo 1/2. It goes from $FF20 to $FF2F. The CoCo 1/2 mirror is from $FF20 to $FF3F.

Recently I was challenged to find a citation for this information. But I could not. Tepolt has this wrong. So I decided to create a test program and accompanying video to document this first hand.

Here is the test program.
PIA Test Program
It is a menu driven program that allows you to choose a specific mirror address for PIA 2, then allows you to choose one of three tests.

Test ‘S’ produces a square wave using the CoCo’s DAC. This DAC is connect to port A of the PIA.
Test ‘B’ produces a square wave using the CoCo 1 bit sound source. This is connected to bit 1 of port B of the PIA.
Test ‘V’ toggles the A/G line of the VDG. This is connected to bit 7 of port B of the PIA.

When using this program on a CoCo 3 you will find the the second PIA only responds from $FF20 to $FF2F. And the VDG test only responds to $FF20 to $FF23, because the GIME only see writes to these specific addresses.

GIME Horizontal Retrace Register Update Table

This is a proposal to the people who make FPGA version of the CoCo 3′s GIME chip.

I was recently reading about the Amiga’s Copper chip. I thought something similar could be added to a GIME implementation. The following is my idea, for what it’s worth.

Addresses used:
FF99, Bit 7 Horizontal retrace update enable
FFEA-FFEC Address (24 bit) table start
Table format:
0 byte Scan line
1 byte GIME register number
2 byte New value
Repeating.

Function

If enabled, during the vertical retrace, the 24 bit table start address is loaded. Then the first byte of the table is deference. If the scan line value (table byte 0) is $FF, then the new value is written to the register number. The table pointer is advanced (by three bytes) and writes are repeated until the scan line is no longer $FF. This allows you to set any video registers before they are latched for the frame.

During every Horizontal retrace the scan line declared in the table is compared to the current scan line. If there is a match, the table value is written to the specified GIME register. Then the next table entry scan line is loaded.

If the scan line does not match, the process is paused until then next horizontal retrace.

If there is time, multiple GIME registers can be changed during horizontal retrace.

Register number zero refers to $FF90 (Initialization register #0). It goes up from there.

Register numbers $FE will trigger an FIRQ or IRQ. Nothing will be written to an internal register. Bit 6 will determine which interrupt is generated ($FF92 or $FF93).

Register number $FD will cause the GIME to reload the video start address from $FF9D and $FF9E. Nothing will be written to an internal register.

Example Programs

I implemented the above in a private MAME branch. I wrote some demos and made these screen captures. All this code can be found here.

COLOR64/BAS:

In BASIC, switch to HSCREEN 2 and draw a grid of 64 circles. Eight every row, for 8 rows. Use palette index 1 to 8 for every row. Load in an assembly language program to install a horizontal sync table to update the palette color to show all 64 colors on the screen at the same time.

Color64

JOY/BAS:

In BASIC, switch to HSCREEN 2, then load a binary file. This file contains:
1. Image data to be loaded in the Hi-res screen memory.
2. The first 52 lines are 128 bytes wide
3. The rest are 256 bytes wide.
4. Hsync table to switch to 256 byte wide video at line 52.
5. Code to install hsync table and turn it on.
Then the BASIC program will update the horizontal scroll register in the table to match the horizontal joystick position.

Joy

DUAL/BAS:

In BASIC switch to HSCREEN 2, Draw random circles. Load hsync table and enable it. Near the bottom of the screen the GIME is instructed to switch to text mode and change the display address to be the bottom of the 40 column text screen.
Repeat drawing circle to the graphics screen and printing text to the 40 column screen.

Dual

INT/BAS:

In BASIC load binary from disk, wait for disk to stop spinning. Switch to HSCREEN 2 and have BASIC draw random circles. Setup horizontal table to trigger IRQ interrupt on scan line 100.

Interrupt service routine quickly sets all palette registers to zero. Then immediately restore RGB palette values. Repeat on next frame.

Int

Laurel & Hardy – Commodore 64 Game

I’m not a C64 guy. But I do play their games for a little show I do with my sister. Recently we played this game. https://www.lemon64.com/game/laurel-and-hardy

We usually do a poor job of playing complicated game we don’t know. But both of us decided to really learn this game and try to play it well. The game has a sprawling world and I quickly decided I needed a map. So I made one. I like to share so here it is.

Laurel and Hardy Map.

6809 Exchange and Transfer Opcodes

It was recently brought to my attention that Darren Atkinson has a really good summary of the invalid register exchange and transfer opcodes in the 6809.

So good, that I should use the information to make MAME’s 6809 better match real hardware.

That will be a future post. In the mean time, I wrote a little program to exercise all of the invalid combinations and print results to the CoCo’s screen memory. This way I can, eventually, verify the implementation.

The software package is here: Test-Exg-TFR.zip

Here is a screen shot from a real CoCo 2B with a 6809 running my program:
REAL coco2b

And here is a screen shot form a real CoCo 3 with a 6309 running the same program:
REAL CoCo3h

By “invalid”, I mean the combinations of registers that Motorola didn’t document. Combinations like specifying different width registers when exchanging or transferring. Or the use of the register bit patterns not defined by Motorola.

VDG study (July 2022)

I was recently informed of some inaccuracies with the various VDG text screens emulated in MAME. I also recently acquired an RGB2HDMI. This device is a very configurable retro computer video to HDMI device. One nice feature it has is to write the frame buffer to a PNG file.
Using this device I can capture pixel perfect pictures of my CoCos and compare them to what MAME currently produces.

First, here is the comparison between a real and MAME emulated CoCo 2.

2 and MAME 2 Normal
The stem of the number ’3′ is too short in MAME.
The “E” stem is too short.
The “F” stem is too short.

Next is the CoCo 2B in normal mode.

2B and MAME 2B Normal
Over all the characters need to be pushed one pixel to the right and one pixel up to properly fit in their boxes.
The ‘@’ has an extra pixel.
The ‘G’ is the wrong shape.
The ‘J’ has an extra pixel.
The pound sign has extra pixels.
The dollar sign has extra pixels.
The apostrophe is missing some pixels.
The comma is missing some pixels.
The period is missing some pixels.
The three is missing a pixel on it’s stem.
The ’6′ is the wrong shape.
The ’9′ is the wrong shape.
The colon is missing some pixels.
The semi-colon is missing some pixels.

Next is the CoCo 2B in lowercase mode.

2B and MAME 2B Lowercase
Over all the characters need to be moved one pixel up and to the right. Except the lowercase J. It only needs to be moved one pixel to the right.
The lowercase letter g is the wrong shape.
The lowercase letter m has an extra pixel.
The lowercase letter p is the wrong shape.
The lowercase letter q is the wrong shape.
The lowercase letter t is the wrong shape.
The lowercase letter w is the wrong shape.
The lowercase letter y is the wrong shape.
The pound sign has extra pixels.
The dollar sign has extra pixels.
The apostrophe is missing some pixels.
The comma is missing some pixels.
The period is missing some pixels.
The ’3′ is missing a pixel on it’s stem.
The ’6′ is the wrong shape.
The ’9′ is the wrong shape.
The ‘@’ has an extra pixel.
The colon is missing some pixels.
The semi-colon is missing some pixels.
The ‘G’ is the wrong shape.
The ‘J’ has an extra pixel.

Next is the CoCo 3 in normal mode.

3 and MAME 3 Normal
Over all, the characters need to be moved a pixel up.
The comma also needs to be moved one pixel to the right.
The number 9 has an extra pixel.

Last is the CoCo 3 in lowercase mode.

3 and MAME 3 Lowercase
Over all the characters need to be moved one pixel up.
The lowercase letter g is the wrong shape.
The lowercase letter i is the wrong shape.
The lowercase letter j is the wrong shape.
The lowercase letter m has an extra pixel.
The lowercase letter p is the wrong shape.
The lowercase letter q is the wrong shape.
The comma need to be moved to the right one pixel.
The numeral 9 has an extra pixel.

Special thanks to Pedro Pena for a screen capture.

MAME 0.246 is the first version to contain the fixes for the above.

The Write Protect Problem

An interesting bug appeared on MAME Testers recently. The bug linked here is really simple. OS-9 wont boot on a copy protected disk image. The solution also was simple: properly emulate the delay between issuing a write command, and the INTRQ that happens when the write protect notch is covered.
But how long of a delay should it be? The floppy disk controller chip data sheet does not specify what is normal. I wish I had an oscilloscope to measure things like this, but I don’t. So I had to get tricky.
I wrote a Color Computer program that writes to a write protected disk on purpose. Normally after you issue the command to write to a sector, you prepare to start writing and then wait until the disk is ready. But if you know the disk write will error becuase of a write protect notch, all you really have to do is count. That is what I did, initiate write and then count forever:


    pragma 6809
    opt cd

start
    org $6000
count fcb 55
error fcb $55

begin
    orcc #$50 turn off interrupts, keep motor spinning
    clrb clear counter
    ldx #vector_return
    stx $0983 load my NMI vector routine
    lda #$ff
    sta $0982 Enable NMI flag to vector
    lda $ff48 reset status of 1793
    lda #$A0
    sta $FF48 do write sector command

; disk should be write protected.

loop
    incb
    bra loop

vector_return
    stb count
    lda $ff48
    sta error
    andcc #$AF enable interrupts
    rts
    end begin

The loop will not actually count forever. When the write fails, the Floppy Disk Controller will produce an Interrupt Request signal. On the Color Computer this is tied to the Non-Maskable Interrupt line. This will stop the loop and run my NMI handler. The records the counter and status to make available to a BASIC program for further processing.

I now have two results from different Floppy Disk Controllers: 20 and 19. With a 5 cycle loop counter, this comes to a delay of about 111 microseconds. I show my work here.

CoCo Max III Hi Res interface

Thanks to a few friends I’ve been able to upgrade my hi-res tester to support the CoCo Max III interface. It is a device similar to the Tandy Hi-res interface, but is triggered differently.
A985155D-394F-459C-B696-E844B0AECB8EScreenshotcapture24-1
Here is what MAME is doing as of today for the CoCo Max III interface:

Speed Start Value End Value Length
Slow 67 483 416
Fast 67 483 416

After going over the data here is what I am going to change MAME to do:

Speed Start Value End Value Length
Slow 29 243 214
Fast 57 486 429

You can see the new values are nearly the same as the previous values, but I think it is an improvement to use values verified on actual hardware.

Tandy Hi-Res Joystick Interface

Screen Shot 2022-03-27 at 12.20.09 AMI was recently told about a bug in MAME’s implementation of the Tandy Hi-Res Joystick interface. The author of C-III Pages (an early desktop publishing application for the Color Computer) discovered the mouse cursor would only go 7/8th across the width of the screen.
This means it is now time to really try to understand the device. Reading the code in MAME doesn’t really tell the whole story, and none of the values that are chosen are explained.
So I did what I always do, I wrote a test program to run on real hardware. https://github.com/tlindner/HiRes-Interface-Test
This program uses a slightly modified version of the sampling code found in most software. It does not do any scaling of the returned values to fit within the screen width or height. It leaves them raw.
I have in my possession four “joysticks” to test. A black beauty, a delux joystick, a C&H joystick, and a Koala Touchpad. The testing procedure was to start the program and wiggle the joystick while looking at the graphic screen (the G command). When I filled in as much as the four rectangles as I could, I returned to the text screen and took a screen shot.

Black Beauty Screen Shot 2022-03-26 at 9.48.38 PM capture17
Deluxe Joystick Screen Shot 2022-03-26 at 9.48.15 PM capture18
C&H Joystick Screen Shot 2022-03-26 at 9.49.04 PM capture19
Koala Touch pad Screen Shot 2022-03-26 at 9.49.20 PM capture20

The Kola touch pad had the weirdest response to both versions of the sampling routine. See the image below and notice how much noise is in the bitmaps:
capture21
Here is what MAME is doing as of today:

Speed Start Value End Value Length
Slow 99 805 706
Fast 99 805 706

After going over the data here is what I am going to change MAME to do:

Speed Start Value End Value Length
Slow 40 475 435
Fast 80 950 870

Hopefully this will fix the bug in MAME that affects C-III Pages and not cause any regressions.
If you want to run the program your self with your own interfaces and joystick, I would love more data. I am especially interested in what the 1 and 2 button Color Mice do.
I would also like to get values from the Color Max 3 hi-res interface. If uses the same method, but the RC values are different in the circuit.

Color Disk EDTASM Symbol Table

The Color Disk EDTASM assembler has the option of writing a symbol table to the end of binaries it produces. You enable the feature by including the /WS switch during assembly to disk. The symbol table can be used by the stand alone ZBUG debugger.

Invoking the switch will add extra data after the LOADM post-amble. Here is how that data is formatted. First is the header. This is always 5 bytes in length.

Length Example Value Description
1 Byte 01 Seems to be constant
2 Bytes 0019 The total length of the symbols and values, plus one
2 Bytes 0000 Seems to be constant

Next you will find a table entry for each symbol and value pair.

Length Example Value Description
1 Byte 84 Length of the symbol text, with the high bit set
n Bytes DONE Symbol name, ASCII encoded
2 Bytes 0004 Symbol value

And finally is the footer. a single constant byte:

Length Example Value Description
1 Byte 0 Seems to be constant

It should be noted the Assembler and ZBUG pair can only handle symbols with a maximum of six characters.

Salient Assembly Episode 1

https://www.youtube.com/watch?v=dxwmPFIUpLY
Welcome to Salient Assembly.

The show where we deep dive into a very specific 6809 assembly language topic.

Today we’re talking about calling subroutines. Subroutines are a very important aspect to programming. When ever you find yourself needing to do the same thing in two different parts of your program your best bet is to create a subroutine for that function. This process is so fundamental it has a name: refactoring.

There are many instructions to facilitate this. But the today we’ll be investiagting Branch to subroutine, and jump to subroutine. The branch version is used in position independant code, and also has a faster, shorter version for smaller branches.

JSR with no parameters

Let’s first talk about a subroutine that requires no parameters to be passed. The JSR instruction will push the address of the next instruction to the stack and then pass control to the subroutine.

The RTS instruction will pull two bytes off the top of the stack and jump to that memory location.

These two instructions are what enable calling subroutines in 6809 assemble language.

For example, let’s say we’re writing a game and we want to write a subroutine that displays the text GAME OVER in the center of the screen.

GameOverCondition

jsr GAMEOVER

jmp NextMiniGame

GAMEOVER

ldx #$50C

ldy #text

loop

lda ,y+

beq WaitGameOver

sta ,x+

bra loop

WaitGameOver

jsr [POLCAT]

beq WaitGameOver

rts

text fcn "GAME OVER"

Here we see the code for a mini game ending. Let’s dig in deep to the specifics

• We execute the jsr instruction. It will push the address of the next instruction on the stack and jump to the operand.
• Do the work of the subroutine. This will copy some text to the middle of the VDG screen.
• Then return to the main program

JSR with calculated address

Sometimes you want to branch to different subroutines based on a condition. One method to do this is with a table of of subroutines. For example:

GameOverCondition

ldb randomNumber

aslb

ldx #gameOverTable

abx

jsr [,x]

jmp nextMiniGame

gameOverTable

fdb WaitGameOver1

fdb WaitGameOver2

WaitGameOver1

...

rts

WaitGameOver2

...

rts

• I load a previously calculated random number that will be 0 or 1.
• Then multiply it by two.
• I add that value to the base address of the subroutine table.
• Then jump to that specific subroutine.
• After the subroutine finishes, it returns to the main program.

Parameter passing

Most of the time a subroutine will take parameters. These are values that change how the subroutine functions. In the example we’ve seen so far we may want to change the subroutine to make the text it displays variable. We also may want to have the text’s final position variable. Let’s go over some methods of passing these parameters to our subroutine.

JSR fixed memory locations

A simple, non-position independant method of passing parameters to a sub-routine is by using fixed memory locations.

GameOverCondition

ldx #text

stx textBufferAddress

ldx #$50C

stx textposition

jsr GAMEOVER

jmp NextMiniGame

GAMEOVER

ldx textposition

ldy textBufferAddress

loop

lda ,y+

beq WaitGameOver

sta ,x+

bra loop

WaitGameOver

jsr [POLCAT]

beq WaitGameOver

rts

textBufferAddress fdb 0
textposition fdb 0
text fcn "GAME OVER"

1. load the address of the text string and store it in the parameter area
2. load the screen position and store it into the parameter area
3. jump to the subroutine
4. load the parameters into registers and perform the function.
5. then return to the main program.

This allows the GAMEOVER subroutine to print different messages. You can pass different text string and different positions to get different results.

JSR register

A faster way to pass parameters would be to use registers

GameOverCondition

ldy #text

ldx #$50C

jsr GAMEOVER

jmp NextMiniGame

GAMEOVER
loop

lda ,y+

beq WaitGameOver

sta ,x+

bra loop

WaitGameOver

jsr [POLCAT]

beq WaitGameOver

rts

text fcn "GAME OVER"

• load the registers with the parameters
• call the subroutine
• notice how the registers are all setup ready for the function to be done.
• and return to the main program.

JSR stack

The stack is also a good way to pass parameters to a subroutine. Since the return address is already stored on the stack it makes sense to put the other parameters there.

GameOverCondition

ldx #text

pshs x

ldx #$50C

pshs x

jsr GAMEOVER

jmp NextMiniGame

GAMEOVER

puls u

puls x

puls y

loop

lda ,y+

beq WaitGameOver

sta ,x+

bra loop

WaitGameOver

jsr [POLCAT]

beq WaitGameOver

tfr u,pc

text fcn "GAME OVER"

• Push the two parameters onto the stack
• Call the subroutine
• Pop the return address off the stack
• pop the parameters off the stack
• perform the function
• transfer the return address to the pc register and return to the main program.

JSR post data

The last method we’ll discuss is when you put the data to be passed after the subroutine call. Care must be taken to return to the proper address when done with the subroutine.

GameOverCondition

jsr GAMEOVER

fdb $50C

fcn "GAME OVER"

jmp NextMiniGame

GAMEOVER

puls x

leay 2,x

ldx ,x

loop

lda ,y+

beq WaitGameOver

sta ,x+

bra loop

WaitGameOver

jsr [POLCAT]

beq WaitGameOver

tfr y,pc

• First we call the subroutine
• immediately after the call, we put two bytes of a destination address and then a string of characters with a zero terminator.
• In the subroutine we load x with the address that was pushed onto the stack. This is technically the return address, but if we used it as such, we would return to data, not code.
• Then we load register Y with the address of the text string
• Then we load register X with the address of the text destination.
• We perform the function
• Then we return from the subroutine by transferring the Y register to the PC register which will conveniently be the proper return address.

That’s it for this episode. I hope you had a good time learning about subroutines and all the various ways you can pass parameters to them.

Bye for now.