Some days, you have a great idea, it is easy to implement and works straight away.
This was not one of those days.
Background
The standard Mini PET 40/80 comes with a 27C040 ROM with 8 ROM images. These include various versions of BASIC and test programs, all for use with the normal layout keyboard that is built into the Mini PET.
The Mini PET 40/80D does not have it's own keyboard, so needs to support both the Normal / Graphics / Chiclet keyboard, and the Business keyboard.
It's a long story that I am sure I have covered many times before, but these two are not at all compatible. The
Aside: for example, I was trying to add support for the business keyboard to Tut-Tut. That currently supports both directional control using QA and OP as well as the numeric keyboard keyboard 8+2 and 4+6. (although I notice as I write that that I only mentioned QA OP on the info screen, so maybe I can get away with dropping 82 46 ?)
The scancode for 4 on the normal keyboard is 46, so when I see a scancode of 46, I move the player left. But, the scancode for P on the business keyboard is also 46, so I should move right?
There is no easy way to tell programatically what keyboard is being used so you just have to select keys that don't overlap like that do.
Back to the main feature.
The PET sets it's keyboard mapping in the editor ROM, and so needs more ROM sets to support the business keyboard as well. The next ROM is the 27C080, which gives 16 options. However, BASIC 1.0 did not support the business keyboard, and the test ROMs are not keyboard dependent, so do not need to be duplicated. That left a few spaces in the ROM.
Seems a shame to leave unused space. What can I use the space for? I know, I can fit a game into ROM. Cheese and Chive seemed a good choice as it is a great game and also shows off 80 column mode. The prg file is 23K, so that will fit into the 32K ROM space, this is going to be easy.
Spoiler: It wasn't easy.
I had expected it would be similar to the way I load some of the games in the Penultimate Cartridge for the VIC20. Most of the ROM images on there are from cartridges, so are designed to run from ROM, and just need to be mapped into the address space at the appropriate locations. Others were not written as ROM games, so to make things easier, I have a stub program that copies the game into RAM, and then runs it from there.
I can do the same thing on the PET then?
Well, no, there is a slight, but very important difference. Other than 8K from 9000-AFFF which is for options ROMs, the ROM space on the PET is already taken up by BASIC, editor and kernal ROMs, and space for IO and video RAM.
Well, I can just replace those with a dummy kernal ROM that loads the game, it doesn't need BASIC right?
I wrote the kernal loader and assembled the ROM image and tried it out. I got a blank screen. Occasionally a few characters in the middle somewhere, but essentially nothing.
I checked with Misfit (the author of this and other wondrous titles - misfit.itch.io) and was assured that no library routines were used.
Tracing it through, I found the code was actually calling a kernal routine, BS_OUT, write a character to the screen. Misft checked and it was only called from the crt0.asm file added by the compiler, and only called once to change the screen mode when the program starts.
I added a dummy routine in the correct location in my dummy kernal ROM and tried again.
Now I got just a blank screen, no more random characters.
(imagine there was a picture of a blank screen here)
Further trimming of the crt0.asm to remove unnecessary calls to routines that didn't exist followed and then I got a screen.
But that is all it did. It is meant to start writing out the text of the title screen.
I guess this is related to the timer interrupt. I did account for that an set up a basic interrupt handler which should work like the original one did.
What normally happens when an interrupt is triggered is that code execution stops and jumps to address stored at FFFE. This is usually E442, which is in the editor ROM. This stores the registers, then jumps to the address stored in the zero page CINV handler (0090). This can be set to jump to a user routine, or will normally jump back into the editor ROM at E455. Here it does the usual interrupt handler stuff such as scanning the keyboard and updating the jiffy counter. Finally it restores the registers and returns to the code it was running before this started.
I knew that Misfit's code had a user level interrupt handler (set using the 0090 redirector), so I implemented a version of that, but at an address in the fake kernal ROM.
I had bypassed the keyboard scanning and jiffy counter, but forgot that the act of scanning the keyboard included writing the the PIA port B which was necessary to clear the interrupt. Without that, my code was locked in a perpetual interrupt.
.....
Skip a load of testing and dummy programs where I got the interrupt working and incrementing counters on the screen as well as running code.
.....
In order to try and work out what was going on, I wanted to extend my test program to not just write 1,2,3 etc. to the screen, but to run bits of more useful code. I decided the easiest way to do that was to try to make a ROM version of a one of my games to test out the mechanism and see if I could get a game running from ROM.
I chose Tut-Tut and modified the source so it would run directly from ROM. That was small enough so that I was able to leave the entire original editor ROM in place. I left out most of the disk and tape routines in the kernal ROM, but implemented the full jump table at the top of the ROM, most of which were set to simply return.
With a bit of tweaking for a few more entry points, I got that running,
Aside: This worked well enough that I did add it to one of the spare slots in the ROM, however, I'll probably leave it as an easter egg as it doesn't currently support the business keyboard. For two reasons:
- The issue previously identified of clashing scan codes.
- The built in editor ROM is for the normal keyboard Mini PET BASIC 4.1
The first could be fixed by modifying the inbuilt scanning routine to use QA OP only, with scan codes for both keyboard types. The second is a problem because bits of the Tut-Tut code (mainly the menus) use the kernal scanning routines, and so would need to be rewritten to use the alternate scanner to work with either keyboard type.
OK, back to Cheese and Chive again.
Misfit was kind enough to send through the source of Cheese and Chive, so I could rebuild it to run directly from ROM with the new editor and kernal, rather than being copied to RAM as I had previously done.
Great, that's almost working. But all the characters are inverted?
Anyone that has used cc65 will know that string handling can be a little confused. It seems that you spend a lot of time trying to work out what to write in the code so that when it gets mangled by the compiler the right thing will appear on the screen. It's a combination of ASCII being different to C64 character sets, and those being different from PET BASIC 1 and also from PET BASIC 2 and 4. Also the differences between uppercase characters in graphics and text mode. Also the difference between characters you send to the PutCh function vs the numbers you poke to screen RAM. And finally, I think it sometimes randomly sets the higher bits in the character to mess with you.
Misift's code has some workarounds to deal with that, and offsetting the characters by 40 before writing. I found that changing that to C0 made most of it work.
A few more tweaks and the titles were fixed.
But there were still problems in the game part.
Misfit was helping and trying these changes as well. On his system, the same code had problems in different places, he had bad characters on the title screen, but the game was OK.
Further analysis of what was different, came down to lots of weird stuff. I was using V2.18 on Linux, Misfit was using V2.19 on Mac. However, that's not entirely correct as it turns out that a bug listed against 2.19 said
"NOTE: The programs in release V2.19 report their version as V2.18"
I had to build direct from the current master instead of release version.
Right, getting there. The versions now matched, but there were still problems.
Misfit made some changes, and reported the menu was now wrong, but the game worked.
When I built it, both worked. Success, but why?
Misfit was using a makefile with ca65 and cc65. I tried with a makefile, and also got the menu is wrong, but game is right.
I normally build from a batch file, using cl65, with the same options
cl65 -t pet -v -C rom.cfg -O -Oi -Os -Cl *.c *.s
Using a batch file (calling cl65 only), and version 2.19 and the latest tweaks, the menu was right and game was right.
Retesting with the same code, but built from a batch file using ca65 and cc65, the menu was wrong again, just like the makefile.
At this point, I had code that compiled and worked, so I stopped beating my head against the wall.
So all sorts of things that shouldn't have made a difference, did. I bet all my other programs won't work now.
All of the pictures above with green characters above are screenshots from the Vice emulator. But will it work on real hardware? I had been testing various versions throughout, and they had been behaving the same as the emulator, but I had to be sure after all of the silliness we had seen with characters.
Yes, everything working as expected, direct from ROM on real hardware.
Here is Rod Hull from TFW8b testing out the Mini PET 40/80D, including Cheese and Onion below. I can only apologise that it starts with "Yo". I don't know what he was thinking.
This post is an updated version of a post from my Patreon. If you want advance previews of posts like this and behind the scenes progress on new projects, you can follow along and support me on Patreon:
https://www.patreon.com/tynemouthsoftware