I’ve spent most of the last week porting Tomaz Kac’s Galaksija emulator from Spectrum to SAM, with version 1.0 now available on my site.
Basic SAM support was trivial, requiring just an
LMPR to page in the ROMs, and another
VMPR to set video mode 1. The Spectrum key matrix is compatible so the keyboard worked, and SAM’s break button could even be used for hard break in Galaksija BASIC too. Proper SAM support required a number of changes…
The first was to use mode 2 instead of mode 1, mainly to avoid the mode 1 contention slowdown. This only gave roughtly a 10% speedup, which was rather disappointing. A chunk of the extra time was eaten away by needing
ADD HL,DE to move between screen lines in the linear layout instead of
INC H (for most) on the Spectrum. In the worst case of drawing all 512 characters it requires an extra 512*11*(12-8) = 45056 tstates! It is still faster overall, and worth the change from mode 1.
The Galaksija display is a text mode of 32x16 characters, with each character 8x13 pixels in size. Tomaz had already changed the font to be 8x12 to fit the Spectrum height, which was perfect for SAM use too. Having 2 characters span 3 vertical blocks made it easier to draw on the Spectrum version, but made no difference to mode 2 on the SAM — each character could be treated completely separately.
The biggest difference from the Spectrum version was to draw only changed characters between frames. This gave a huge speed boost in most cases, and even with the extra comparisons it was faster than the old version as long as no more than 80% of the screen was being updated. Further speedups were made by using a table for character address lookups, rather than tracking the address in a register (which required some arithmetic). A stack method to access the table allows a simple
POP to fetch the next address, or discard it for skipped characters.
The speed gained meant that many games now ran too fast, or they ran with variable speed depending on how much of the display had changed. That required adding a throttling mechanism to limit the maximum speed, which was implemented by limiting number of unchanged characters that could be skipped during drawing. This technique worked well for the SAM version, but not so well for the Spectrum. In some cases adding small delays to the Spectrum drawing code increased the running speed! This is related to the long interrupt processing and the games own frame synchronisation, but I still don’t fully understand the details.
In a last minute change I replaced the SAM throttling code to use
HPEN to track the number of frames that had elapsed during drawing. Rather than looping over all 512 characters as 2 blocks of 256, I split it into 4 blocks of 128. At the end of each block I read
HPEN and compare with the previous value, and if it’s less than the current value I know it’s spilled over to a new frame. At the end, if 2+ frames have passed then I’m running too slow, otherwise there’s time to spare. In the latter case I poll
HPEN to wait for the raster to reach a specific point, before leaving the interrupt handler and allowing the game to continue. The actual screen position was determined by trial and error, to ensure that most games ran at the correct speed.
Galaksija software was loaded from tape, and the Spectrum version used the ROM routines at
0x0556 to load blocks. The same technique could have been used for the SAM version, but since nobody uses tapes anymore it wouldn’t have been much use. Instead I chose to exit to SAM BASIC to handle the loading, which was easier than paging DOS and using hook codes to do it directly. Adding a simple menu and .GTP tape image parsing was just a few dozen lines of code too.
Full source code and build instructions are included with the disk image download, if you’re interested in knowing more.