Recently, I’ve been playing around with constructing replacement ROMs for the Coco3 internal ROM. Since I have neither EPROM programming hardware nor the hardware knowledge to change out the ROM in one of my actual Coco3 machines, I have been using emulators to test things. One of the most useful emulators for testing is Mess (related to the Mame project). It turns out, however, that Mess gets one important aspect of how the ROM is handled wrong.
At startup, the 6809 fetches the first address to start executing at from FFFEh. Because this has to be present at power on, this must come from ROM somewhere. On the Coco1 and Coco2, this came from BFFEh in the Color Basic ROM. In fact, all the interrupt vectors from FFF0h through FFFFh come from BFF0h through BFFFh. This redirection is accomplished by the hardware in the Coco.
On the Coco3, this vector table actually comes from the top bytes of the internal ROM which would be at FFFxh if the top 256 bytes of the ROM were not overshadowed by the I/O page. Again, the hardware in the Coco3 automatically forces accesses in the range of FFF0h through FFFFh to the internal ROM but this time at the top of it.
One can demonstrate that the active vector area on the Coco3 does not come from BFFxh by powering on a Coco3 and doing the following:
POKE&HFFDE,0 ?PEEK(&HFFF0) ?PEEK(&HBFF0)
The first command forces the machine to ROM mode to eliminate any interference from the ROM/RAM transfer. The second one shows the value retrived from FFF0x, the bottom of the CPU vector area, and the one vector that is not used by the 6809. The third one shows the contents of BFF0h which would be the value at FFF0h if the redirection was to the BFFxh range. On the Coco3, one gets a value of 0 from the FFF0h address but 166 from BFF0h. That shows that the BFFxh range is not used for the FFFxh range. The reason it shows that is remapping only 14 bytes is not practical from a binary logic point of view. It is much easier and cheaper to remap 16 bytes. (In fact, it looks like 32 bytes is remapped in this case, including the FFE0h through FFEFh range.)
One can determine that the vectors must then come from the top of the internal ROM by examining any of a number of dumps of that ROM available from multiple sources. It is possible to examine it on the Coco3 itself but that is a complicated process due to the way ROM mapping interacts with the MMU. Anyway, one can see that the only other place in the internal ROM that the interrupt vector values appear is right at the top of it (what would be FFFxh). And, the icing on the cake is that the byte that would be at FFF0h is, in fact, zero. Further checking will show that the values obtained by peeking at FFExh also match the top part of the internal ROM.
Thus, instead of mapping FFE0h throught FFFFh to offset 3FE0h in the ROM, Mess should be mapping the addresses to offset 7FE0h in the ROM. Making the trivial change to src/mess/drivers/coco3.c in the Mess source code to change that mapping yields an emulator that still works with the stock ROM but now returns the correct value at FFF0h.
It is interesting to note that the above information is at odds with other documentation available, notably Tepolt’s Coco3 addendum. However, the above information is experimentally verified.