Ankha Intro

The Ankha intro has been released at Sillyventure! It’s my first VGA demo on Atari ST (and as far as I know, the very first VGA demo on ST ever).

Required configuration:
Mega STE with 4MB RAM, 20MB HDD and ET4000 VGA card

Download here
Source code on GitHub (see below for technical discourse)

I tested it with a NOVA card plugged to an ET4000 + ICS 5301-2 DAC.

In any case, you *need* to run it in 320x240x256c mode. It doesn’t setup the video mode itself!

It does NOT work on ATI Mach32 or Mach64. The cards are programmed quite differently. Actually I haven’t succeeded in doing the same things on my Mach32 (even setting colors fail). If you have some actual 68000 ST code snippets to help me program those cards, I’d welcome them gladly.

The intro also features a 50kHz PCM original soundtrack by dDamage, which is streamed fro the HDD. You might hear some audio cracks when the demo is running. There is no software workaround for this, see Shifter DMA audio bug below.

No emulator can run this demo because no Atari ST emulator handles low-level VGA cards.

Create the 320x240x256 mode

This is not a guide on how to install an ET4000 card into a Mega STE or its drivers.

NOVA drivers by Idek (most recent and amazing drivers) come with a tool called VMG.PRG used to manage or create video modes. This is required since libraries like svgalib.c aren’t available on ST and the card’s BIOS can’t be called to initialize standard video modes.

Here are direction to create a 320x240x256c mode with NOVA ET4000 cards:

  • run VMG.PRG
  • Click on « Auflösung laden » (« Load Resolution »)
  • Click on « Bibliotheksname » (« Library name »)
  • Select the file STA_VDI.BIB located in C:\AUTO
  • Select the 640x480x256 mode and click on « Laden » (« Load »)
  • Enter the following data:
  • Aufl̈̈sungsname (name of resolution): 320x240x256, 60Hz
  • Signale: Total 400/525, Länge (length) 320/480, Sync-Länge (sync-length): 32/12
  • Polarität: enable both « negativ »
  • Enable « Low Res. »
  • virtuelle Auflösung (virtual resolution): horizontal 320, vertikal 240
  • Farben (colors) : 256
  • Pixelfrequenz: <= 25 =>
  • IMPORTANT : Once all done, click on the « Init » button of the « Signale » area

Then you can test the mode by clicking on « Werte setzen ». You should see a blue on white crossboard:

Press ESC and click on « Auflösung sichern » to save the new mode.

You can go back to the library by clicking on « Auflösung laden » to check if the new mode is present. Then you can sort the resolution list by clicking on « sortieren… » then choose « Auflösung »

You can then close VMG.PRG and run MENU.PRG or XMENU.PRG immediatly or on reboot to choose the 320x240x256c mode.

Technical aspects

Low-level programming of a VGA card on ST/STE/TT isn’t really challenging from the 68000 point of view. All the video RAM and registers are directly mapped to ST-RAM starting at the following addresses:

$A00000 (ST/STE), $FEA00000 (TT) => monochrome video RAM base address
$C00000 (ST/STE), $FEC00000 (TT) => color video RAM base address
$DC0000 (ST/STE), $FEDC0000 (TT) => memory-mapped registers base address

Basically you can take the ET4000 documentation and access all registers by adding their base address. The same goes for the video RAM, which can be freely read from and written to by the 68000 or the blitter.

Detecting and setting up video modes

The complexity of programming VGA cards come from the number of variations available. For instance, speaking of ET4000 cards, the video conversion is not done by the ET4000 but by an external DAC which has its own properties (for instance some cards can do 24 bits modes, some can’t). That’s where the complexity lies.

Also, clocks can vary so the same mode would be achieved by setting up different values from one card to another.

On PC this issue is handled by the onboard BIOS that do all the nasty setup stuff by calling it to require a specific VGA mode. Without a x86 emulator on ST this is not possible (it’s been done but it’s slow). So that leaves us to use only the working VDI mode setup by the ST driver, or to use a complete detection & setup library. Unfortunately the only occurrences I know of such code are the NOVA drivers (unfortunately closed source), the VGA code in EmuTOS (not available as a lib and with a very limited detection code) and svgalib.c on PC. It would be interesting to port svgalib on ST but since the number of VGA cards installed on ST is very low, I didn’t bother doing anything. Even Idek, who makes an amazing job maintaining NOVA drivers for a lot of card models, stopped his own project of universal driver due to lack of feedback.
So that’s up to the user to boot in the required mode.

Note that I don’t even check for the current mode. I think it’s possible since the NOVA drivers put system cookies with information about the working mode.

Due to lack of time, I don’t restore the previous system palette either.

Which mode to use

The ET4000 cards support various modes, from monochrome to 24-bits true color modes.

  • Monochrome mode is strictly equivalent to the ST high res and as such, is not really interesting unless you want higher resolutions. That’s why it’s used by EmuTOS, the framebuffer has the same layout than ST’s high res, so it’s just a matter of changing the physical base address to $A00000 for this mode to be 100% compatible with all applications.
  • 16 colors mode is bitplane-based and should be interesting in theory because we could use the same tricks as with ST low res but with higher resolutions, and the memory footprint is limited. Except that this mode is tricky to use on ET4000, because all bitplanes aren’t mapped at the same time in video memory: you need to flip switches to map a chosen bitplane in memory. There is also a mode where each transferred pixel is written automatically on 4 bitplanes (useful to write individual dots). A bit complex, and the dynamic mapping of bitplanes is incompatible with the Mega STE’s CPU cache (unless you do only memory writes). That’s why the CPU cache must be disabled when working in this mode with GEM.
  • 256 colors mode is a chunky mode (1 byte = 1 pixel), is completely straightforward and supported by all cards. That’s why I chose it.
  • 15 and 16-bits true color modes may also be interesting except the memory footprint is twice the size of the 256c mode, which renders any graphic refresh twice as slow.
  • 24-bits mode is not available on every card.

The easiest and fastest modes to work with are monochrome and 256 colors, so I chose 256 colors.

Speed considerations

Something I haven’t spoken about yet is the awfully slow memory access of the VGA video RAM. It seems this comes from both the ISA and VME port. Maybe this is not the case for a native card (like CrazyDots) or on Mega ST, I don’t know. But on NOVA accessing the memory is ~3x slower than accessing ST-RAM.

Since the ET4000/AX does not have an internal blitter, every refresh must be done by the 68000 or the ST blitter through the video bus, and suffers from this performance hit.

The scrolltext in Ankha intro is 320×25 pixels and is written the fastest way possible, with pure ST blitter transfers. And it takes 40% of CPU time (based on a 60fps refresh). It means that you really can’t move large objects on screen at 60fps with complex blitter operations. And of course, read/modification/write cycles are to be avoided like plague. Stick to write operations only.

Note that the ET4000/W32 and ET4000/W32i do have an internal blitter, but they’re even rarer than an ATI Mach32 ISA.


The ET4000 cards allow to change the display base address for vertical scroll and can even do horizontal scroll (used by the virtual screen feature of NOVA drivers).

It can be also used to achieve double, triple,… buffering.

In Ankha intro I preload the three backgrounds in video RAM, then I change the base address to switch backgrounds (see set_videoaddress). There is no double buffering, so the next thing after the base address is switched, the scrolltext refresh will be done on the newly displayed buffer.

Note that the base video address sent to the ET4000 registers must be divided by 4 (for example $C01000 instead of $C04000). I don’t really know why.

There’s also a split-screen feature, that allows to send back the video counter to $C00000 at a given line, that I could use but didn’t.

You can’t read or write the video counter, and the base address must be changed before vsync to be taken into account.


Changing colors is very easy (see set_palette). You send the first color index you want to change, then send all three R, G, B bytes. If you go on, it will change the next color indices.
The only drawback is that for 256 colors, you must send 768 bytes in a loop, which is not really demo-friendly.

Note that the DACs on these cards use 6-bits colors, so white is actually $3F3F3F and not $FFFFFF.

On the init phase of the demo, I take the four color palettes from BMP files (BGRA 8-bits) and convert them in RGB 6-bits so they can be sent to the DAC the fastest way possible during the demo.

240 colors are used for background and 16 colors for the scrolltext.


On VGA ST, Vsync can be achieved only by polling a VGA status register (called Input Status 1 on ET4000, INSTATUS1).

Bit 3 is on during Vsync, and off everytime else.

It’s up to you to find how to poll this bit the best possible way. Of course the ST’s VBL interrupt is useless here.

One way is to poll this bit during init and find the vertical frequency, then setup a Timer in sync.

What I did is that without looking for the vertical frequency, I wait for vsync at init, then setup Timer B to trigger an interrupt a bit before vsync, then wait for vsync, and setup the timer B again to trigger the next interrupt a bit before vsync. I took 60Hz as a reference vertical sync.

Of course this may be problematic if a blitter transfer or Timer A is running : miss vsync and you miss one frame.

Another way would be to poll the vsync bit during the main loop, but this was not possible for Ankha intro because of the streaming audio.

Streaming audio, blitter, TOS

This is a lighter version of the streaming video engine I used for my previous Bad Apple! conversion.

Except that the file now contains audio only, and that Timer A is used to handle audio buffer switch.

The blitter can be used in 256c chunky mode and is actually a lot easier to setup. Every transfer is 2-pixels aligned (16-bits), so to make pixel-perfect aligned transfers you need to use the skew register (with value 0 or 8). In Ankha intro the text scrolls by steps of 2-pixels minimum so I didn’t have to shift bits.

There’s some issues related to the TOS, for instance the NOVA screensaver fires up after a few minutes. That’s because the system Timer C isn’t disabled – it’s used by some HDD drivers. The system keyboard handler is not disabled for the very same reason. I didn’t bother finding a workaround so far.

Shifter DMA audio bug

[updated 13/08/2022]

Audio cracks appeared in the initial release of the demo and I wasn’t sure where the came from. However I quickly found out that they can be heard only when blitter transfers are in progress while a DMA sound is playing (even a basic blank audio loop with no DMA register change whatsoever). So, it was probably a hardware issue.

It turned out the culprit is the STE DMA shifter. The shifter indeed takes charge of the audio DMA transfers on STE. It exists in at least three revisions:

  • C300588 chip [early STE chipset] : no bug
  • C301712 chip [later STE + MSTE chipset] : DMA bug
  • C301712 chip, later version (v2? v3?) that may fix the bug

We couldn’t find a revised C301712, we only know it existed because it seems Atari was aware of this DMA bug with the C301712 and swapped it with a fixed version on request. But of course back in the 1990s not enough people made STE audio specific software & used the blitter enough to hit this bug, so a lot of STEs still have the original C301712 because no one asked Atari to change it.

I swapped the C301712 for a C300588 on my Mega STE and I could indeed check that it fixed the audio cracks for the Ankha intro. So unfortunately there’s no software workaround for this. Exxos tried some ways of fixing this issue, you might try them if you can’t get your hands on a C300588 shifter.

That’s all!

2 réflexions sur “Ankha Intro”

Les commentaires sont fermés.