Upgrading minimig with AGA capabilities, Part 2

So, to continue from Part 1, the rest of additions in Denise.

Denise bitplane updates

First, of  course, the bitplane count needs to be upgraded from ECS’ 6 bitplanes to AGA’s 8 bitplanes, together with everything dependent on it, like collision detection for 8 bitplanes, two additional bitplane output buffer registers, playfield support, etc. Quite a lot of code changes in this step, but not hard to do – basically, I just followed the existing code and used common sense and the AGA.guide document.

The tricky part is the 64bit bitplane shifter and accompanying logic. This requires upgrading the existing 16bit output shifter to 64bits, together with new scroller implementation. I spent quite some time on this, and I know it doesn’t work correctly yet, as some games scroll very strangely – moving a few pixels in one direction and then ‘jumping’ back a lot of pixels and so on. The scroller will definitely need to be fixed sometime in the future. The scroller / shifter implementation seems to be dependent on selected resolution *and* the fetch mode, I just don’t see how it fits together. There’s also some undocumented ‘extra_delay’ involved here, I just don’t understand it yet nor see where it comes from.

Denise sprite updates

Sprites are somewhat easier, once you realize how the 64bit fetches fit in. The sprite output data gets extended from four bits to eight bits by adding four new OSPRM/ESPRM bits to MSB of the output. The trick is that the 64bit fetches are only for the sprite data, not for the sprite control word – I figured that out after reading some demo coder description of how the sprite control & data need to be laid out in memory for wide sprites to work. Still missing is the part of sprite scandoubling that can ‘double’ the sprite horizontally, I haven’t figured that out yet.

Agnus bitplane DMA updates

This is the part I spent the most time on. Agnus contains a bitplane DMA sequencer, that does different DMA sequences according to resolution and selected number of bitplanes. To support AGA’s eight bitplanes and two additional fetch modes, the sequencer had to be extended with the new sequences. I studied this a lot, used many pieces of paper drawing diagrams and sequences which could work. In the end, I decided for the simplest approach with the least changes required – as I did for every other AGA change, and it seemed to work. It works very simply now: the sequencer has five ‘programs’, which includes all resolutions (lores, hires & shres) and all three fetch modes. All odd planes come first, followed by even planes, with plane 0 being always the last, since fetching plane 0 starts the parallel-to-serial converters in Denise (and enables sprites!). Another trick is that two of the sequences have free cycles following bitplane DMA cycles. The sequence length is also increased from ECS’ eight cycles to AGA’s 32 cycle sequences.

I made a program visualizing the five different encodings of the sequencer:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
unsigned int ddfseq;

printf("old sequencer:\n");
printf("ddfseq shres hires lores\n");
for (ddfseq=0; ddfseq<8; ddfseq++) {
unsigned int ddfseq_neg = (~ddfseq);
unsigned int shres = (((ddfseq_neg&1)?1:0)<<0);
unsigned int hires = (((ddfseq_neg&1)?1:0)<<1) | (((ddfseq_neg&2)?1:0)<<0);
unsigned int lores = (((ddfseq_neg&1)?1:0)<<2) | (((ddfseq_neg&2)?1:0)<<1) | (((ddfseq_neg&4)?1:0)<<0);
printf("%01d %01d %01d %01d\n", ddfseq, shres, hires, lores);
}
printf("\n");

printf("new sequencer:\n");
printf(" mode 1 = 2-fetch sequence (SHRES FMode = 0)\n");
printf(" mode 2 = 4-fetch sequence (HRES FMode = 0, SHRES FMode = 1)\n");
printf(" mode 3 = 8-fetch sequence (LRES FMode = 0, HRES FMode = 1, SHRES, FMode = 3)\n");
printf(" mode 4 = 8-fetch sequence followed by 8 free cycles (LRES FMode = 1, HRES FMode = 3)\n");
printf(" mode 5 = 8-fetch sequence followed by 24 free cycles (LRES FMode = 3)\n");
printf("ddfseq 01 02 03 04 05\n");
for (ddfseq=0; ddfseq<32; ddfseq++) {
unsigned int ddfseq_neg = (~ddfseq);
unsigned int m1 = (((ddfseq_neg&1)?1:0)<<0);
unsigned int m2 = (((ddfseq_neg&1)?1:0)<<1) | (((ddfseq_neg&2)?1:0)<<0);
unsigned int m3 = (((ddfseq_neg&1)?1:0)<<2) | (((ddfseq_neg&2)?1:0)<<1) | (((ddfseq_neg&4)?1:0)<<0);
unsigned int m4 = (((ddfseq &8)?1:0)<<3) | (((ddfseq_neg&1)?1:0)<<2) | (((ddfseq_neg&2)?1:0)<<1) | (((ddfseq_neg&4)?1:0)<<0);
unsigned int m5 = (((ddfseq &16)?1:0)<<4) | (((ddfseq &8)?1:0)<<3) | (((ddfseq_neg&1)?1:0)<<2) | (((ddfseq_neg&2)?1:0)<<1) | (((ddfseq_neg&4)?1:0)<<0);
printf("%02d %02d %02d %02d %02d %02d\n", ddfseq, m1, m2, m3, m4, m5);
}

exit(EXIT_SUCCESS);
}

I made one mistake in the bitplane DMAs implementation that took me a while to fix – I forgot to change how much the bitplane pointers advanced according to fetch mode. I made numerous tests in AsmOne trying the 64bit bitplane fetches, and they simply didn’t work, but after many reviews of the code I saw my mistake – the code needs to advance the bitplane pointers by 1 for 16bit fetches, 2 for 32bit fetches and 4 four 64bit fetches. Duh 😉 After fixing the bitplane modulos, the bitplane DMAs were ready.

Agnus sprite updates

After figuring out the bitplane DMA updates, the sprite DMA was pretty easy – just advance the sprite data pointers by an appropriate amount, at that is it!

Aaand …. done (almost)!

One of the last thing I changed was the Denise ID register, updating it with the proper AGA ID value. Once you do that and start Workbench, SetPatch will detect an AGA Amiga and try to enable 64bit bitplane fetch mode. Let’s just say the result wasn’t very good at first, but after lots of small bits fixed here and there, I got a perfect-looking desktop with 4x fetch mode enabled! Even some games worked, although most of them were a little slow, since the CPU bandwidth to the chipRAM and kickstart is still as slow as on ECS Amigas (the CPU on AGA Amigas can access chipRAM through a 32bit bus, also kickstart uses two ROM ICs, making kickstart accessible through a 32bit bus also).

That concludes the current minimig AGA implementation. There are still some missing features, like bitplane & sprite scandoubling, plus extending the CPU speed when accessing chipRAM & kickstart, like mentioned above. All in all, I spent around two weeks working on this, a week of afternoon work for upgrading the minimig design to a single 28MHz clock and a week when I was on sick leave for most of the AGA stuff. The bitplane DMAs and the bitplane output shifters were definitely the most tricky parts to get right.

And for any reader that managed to read through this very long two-post rambling – congratulations for your persistence! I’ll invite you to a beer if we ever happen to meet!

If you want to take a look at the minimig code, my repository is here: https://github.com/rkrajnc/minimig-mist

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.