A project log for Commodore CHESSmate Reproduction

The plan is to make a reproduction of the dedicated chess computer CHESSmate released by Commodore in 1978.

michael-gardiMichael Gardi 02/14/2024 at 01:192 Comments

After I convinced myself that the emulator was probably OK, I turned back to the ROM.  But after I found yet another ROM image online, and it turned out to be identical to the other three, I have to rule out bad ROM as well. Just as well as I was reluctant to put my original CHESSmate at risk.

So that means that my emulation of the CHESSmate hardware must be wrong. However, as  far as I could tell, I was handling all of the reads and writes from the firmware. I knew this because I had code in place to detect unhandled I/O.  And that would have been a valid assumption if I had put the unhandled code in the right place!

Whoops. Embarrassing.  When I relocated the code to the correct spot I discovered that I had missed a few interactions.

R/W            Program
Address                                      Value                    Notes
   1           R           F3908B0EIs Timer Interrupt?    Occurs when a move is
  2         WF0B28B0FF5 Set Interrupt     Occurs when move is made
  3RFEF08009Doesn't matterOccurs constantly. Part of the main keyboard / display loop.
  4RF3058xxxFFOccurs when move made.
  5RF3098xxxFFOccurs when move made.

So what does this mean?

1, 2 - 8B0E and 8B0F are part of the RRIOT Control Registers. I was surprised that I was not picking these up.  When I looked at the code I found my second error.

#define RRIOT_REG_SIZE 12

There are 16 registers not 12. The 8B0E and 8B0F registers control the RRIOT's Timer. Because of my error, I had not seen these before so I thought that CHESSmate did not use the timer.  I was wrong. I did notice that the chess clock feature was not working though. So I fixed the define and am now processing these interactions but will have to spend some time figuring out how they should work. TODO.

3 - I'm not sure exactly what this is doing. It's related to this piece of code:

FEEB 29 7F                AND #$7F
FEED 2C                 .byte $2C       ; BIT skip next instruction 
FEEE 09 80       LFEEE    ORA #$80
FEF0 A0 00                LDY #$00      ; lookup conversion
FEF2 8C 00 8B             STY SAD       ; turn off segments
FEF5 8E 02 8B             STX SBD       ; output digit enable
FEF8 8D 00 8B             STA SAD       ; output segments
FEFB E8                   INX
FEFC A0 7F                LDY #$7F      ; delay 500 cycles
FEFE 88         CONVD1    DEY
FEFF D0 FD                BNE CONVD1
FF01 60                   RTS

The 2C 09 80 sequence is treated as a BIT operation on the absolute address 8009. This sets the Negative flag in status to bit-7 of the byte read, and the Overflow flag in status to bit-6 of the byte read. Since there are no subsequent branch instructions I'm pretty sure this sequence has no effect on the code. This looks like a patch of some sort. Ignored.

4, 5 - These occur when a move is being made. The address is in the 8xxx range but varies quite a bit. They are associated with this piece of code. 

F303 B1 76       LF303     LDA ($76),Y
F305 48                    PHA
F306 C8                    INY
F307 B1 76                 LDA ($76),Y
F309 85 2A                 STA $2A
F30B 68                    PLA
F30C A2 11                 LDX #$11

So I do the sequence H - ENTER (switch CHESSmate to WHITE), G - ENTER (CHESSmate MOVES). If I return a 0 to these two reads CHESSmate fails returning the move H1 - H1. If I return FF to the reads, CHESSmate plays E2 - E4, the same as the original game.  I think that this has something to do with the opening book. I'll have to dig in a bit to figure it out.  TODO

The bottom line here is that with these changes the game plays pretty well now. I played a couple of full games today with no issues, from the opening move to the annoying musical sequence CHESSmate plays when it wins (both games sigh).  

I still have some work to do but I'm much more confident now of a great result.


barrym95838 wrote 02/22/2024 at 06:18 point

The .byte $2C is just a little hack to allow two distinct entry points into the following LDY etc. code.  A BPL $FEF0 would have done essentially the same thing but would have consumed an additional precious byte with its $10 $02.  When literally every byte counts, pulling a little trick like that can sometimes mean the difference between squeezing in a feature and having to abandon it.

  Are you sure? yes | no

Ken Yap wrote 02/14/2024 at 05:55 point

Re 3: Since the 2C takes in a couple of instructions following my theory is it was used to null an erroneous opcode there but NOP couldn't be used because they could only flip 1-bits to 0 to avoid having to erase EPROMs, not possible with OTP ones anyway.

  Are you sure? yes | no