VOGONS


First post, by bradr

User metadata
Rank Newbie
Rank
Newbie

Hey All,

First post here! I've been working on a simple DOS emulator - mainly as a learning exercise with the goal to build just enough to run the DOS version of "Oh No, more Lemmings". It's written in C# with an OpenGL shader to render the VGA frame buffer and seems to be working quite well so far.

But, I've hit on something a little intriguing... when the Lemmings start up options "VGA" and "High Performance PC" are chosen it appears to be doing some kind of "in frame" palette animation - by which I mean on every frame 8 palette registers seem to be re-programmed twice, presumably so the bottom part of the screen can use different colors to the main game area. ie: 24 colors in a 16 color video mode (mode 0x0d)

I noticed this because my emulator is rendering some colors in the bottom panel incorrectly and I can see continuous reprogramming of the palette registers. DOSBox gets it wrong too - unless the machine type is set to "vgaonly" in which case it works correctly.

I've not heard of this technique before and wondering if someone can explain how it works? How does it get the timing accurate enough to know when to flip the palette?

(Or, perhaps it's doing something else and I'm misinterpreting, but that's sure what it looks like)

Any clues appreciated.

Brad

Last edited by bradr on 2017-12-03, 05:10. Edited 1 time in total.

Reply 1 of 14, by bradr

User metadata
Rank Newbie
Rank
Newbie

I think I figured this out. Looks like after detecting the vertical retrace it's setting up the programmable interval timer to raise an interrupt at the required scan line - at which point it reprograms the palette.

Anyone know if this was a common technique?

Reply 2 of 14, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie

I'd say pretty common to lock on to vertical rate and update palette while drawing. Bart vs Space Mutants might do the same.

IIRC, when VGA is selected, it's in EGA graphics mode but and switching the EGA palette entries, but in EGA mode it does not switch palette entries.

Reply 3 of 14, by bradr

User metadata
Rank Newbie
Rank
Newbie
Jepael wrote:

I'd say pretty common to lock on to vertical rate and update palette while drawing. Bart vs Space Mutants might do the same.

ok cool. I've never seen this described anywhere before. Thanks.

IIRC, when VGA is selected, it's in EGA graphics mode but and switching the EGA palette entries, but in EGA mode it does not switch palette entries.

Pretty much, except it's the "high-perf-pc" option that changes the behaviour.

Reply 4 of 14, by xjas

User metadata
Rank l33t
Rank
l33t

Interesting! I know of a few titles that do that - 1991 Donut by Scali (a member here) switches palettes twice in EGA mode - there are three palettes on-screen at once, and he used some really tight timing to pull it off. Hopefully he'll see this thread & chime in with some more details.
00062165.gif

California Games does it in CGA and manages to get six colours onto the screen in 320x200x"4" mode. Note halfway down where it changes from cyan/red/white/black (already a 'tweak' palette IIRC) to red/yellow/green/black. Shame more games didn't use this back then.
7722-california-games-dos-screenshot-footbag-cga-more-color-mode.gif

twitch.tv/oldskooljay - playing the obscure, forgotten & weird - most Tuesdays & Thursdays @ 6:30 PM PDT. Bonus streams elsewhen!

Reply 6 of 14, by bradr

User metadata
Rank Newbie
Rank
Newbie

For anyone who's interested in the details on how this is done, I did some reverse engineering. There are two places where this is used in Lemmings - first on the level intro screen and second in the game itself. Each uses a slightly different approach.

Level Intro Screen

LemmingsLevelInto.png?dl=1

The level intro screen runs in mode 10h (16 color, 640x350) uses one palette for the top 60 rows and another for the rest of the screen.

To determine when to switch palettes it just spins a busy loop waiting first for the horizontal retrace and then counts through 60 "display disabled" cycles. Display disabled is true once for everything after vertical retrace pulse until start of display and then once again at the end for each scan line during the horizontal blanking.

Row 60 in the above screen shot is immediately below last visible pixel the level preview screen - so there are quite a few blank lines before the second palette needs to be loaded.

; Wait for vertical retrace
1060:7772 mov dx,word ptr [0x1FD6]
1060:7776 add dl,0x06 ; DX = 0x3DA (Video input status)
1060:7779 in al,dx
1060:777A test al,0x08 ; Bit 3 (0x08) = in vertical retrace
1060:777C jz 0x7779
1060:777E in al,dx
1060:777F test al,0x08
1060:7781 jnz 0x777E
1060:7783 cli

; Load pallete A
1060:7784 push dx
1060:7785 mov al,0x00
1060:7787 call 0x7EC5
1060:778A pop dx
1060:778B cli

; Wait for 60 scan lines
1060:778C mov cx,0x003C ; 0x3C = 60
1060:778F in al,dx
1060:7790 test al,0x01 ; Bit 0 (0x01) = display disabled (horiztonal blank)
1060:7792 jnz 0x778F
1060:7794 in al,dx
1060:7795 test al,0x01
1060:7797 jz 0x7794
1060:7799 loop 0x778F

; Load pallete B
1060:779B mov al,0x07
1060:779D call 0x7EC5

In Game Screen

The in game screen runs in mode 0x0D (16 color 320x200) and uses one palette for the first 160 lines and another for the remaining 40 lines (the control panel at the bottom of the screen). Note that mode 0x0D is scan line doubled so the CRTC timing is based on 400 display rows.

LemmingsInGame.png?dl=1

Pixel row 160 (aka scan line 320) in the above screen shot is immediately below the play area and there are a couple of blank lines following which presumably provide enough time to reprogram the palette. Note too that the screen shot is from my emulator where this palette switching isn't implemented so the palette is wrong in the bottom 40 rows - most noticeably in the red pixels in the "OUT: IN: TIME:" display area.

This screen uses the Programmable Interval Timer (PIT) and some startup calibration. The calibration works like this:

1. Wait for vertical retrace
2. Setup PIT to count down from 65535
3. Wait for 320 display disabled cycles.
4. Stop the PIT timer
5. Read back the PIT counter
6. Subtract the read value from 65535 to get the PIT timer reload value to use while the game is running.

; Measure how long it takes to get from end of vertical retrace pulse
; to line 320 (ie: pixel row 160)

1060:7C63 mov cx,0xFFFF

; wait for retrace
1060:7C66 mov dx,word ptr [0x1FD6]
1060:7C6A add dl,0x06
1060:7C6D in al,dx
1060:7C6E test al,0x08
1060:7C70 jz 0x7C6D
1060:7C72 in al,dx
1060:7C73 test al,0x08
1060:7C75 jnz 0x7C72

; Start pit timer
1060:7C77 mov al,0x30
1060:7C79 out 0x43,al
1060:7C7B mov al,cl
1060:7C7D out 0x40,al
1060:7C7F mov al,ch
1060:7C81 out 0x40,al

; Wait for 320 horizontal blanks
1060:7C83 mov cx,bx
1060:7C85 in al,dx
1060:7C86 test al,0x01
1060:7C88 jnz 0x7C85
1060:7C8A in al,dx
1060:7C8B test al,0x01
1060:7C8D jz 0x7C8A
1060:7C8F loop 0x7C85

; Stop PIT timer
1060:7C91 mov al,0x06
1060:7C93 out 0x43,al
1060:7C95 mov al,0x36
1060:7C97 out 0x43,al
1060:7C99 nop
1060:7C9A nop
1060:7C9B nop

; Read value
1060:7C9C in al,0x40
1060:7C9E mov cl,al
1060:7CA0 in al,0x40
1060:7CA2 mov ch,al
1060:7CA4 ret

The in game PIT interrupt handler then fires whenever scan line 320 is hit and does the following:

1. Load palette B
2. Set screen start address (for page flipping)
3. Wait for vertical retrace
4. Restart the PIT timer using the value calculated during calibration.
5. Load palette A
6. Other undetermined logic (screen update, sound perhaps, not sure...)

; Load palette B
1060:7CAC call 0x7F3C

; Setup CRTC start address
1060:7CAF cli
1060:7CB0 mov dx,word ptr [0x1FD6]
1060:7CB4 mov bx,word ptr [0x1F75]
1060:7CB8 add bx,word ptr [0x1F77]
1060:7CBC add bx,0x02
1060:7CBF mov ah,bh
1060:7CC1 mov al,0x0C
1060:7CC3 out dx,ax
1060:7CC4 mov ah,bl
1060:7CC6 inc al
1060:7CC8 out dx,ax
1060:7CC9 add dl,0x06
1060:7CCC sti

; Wait for start vertical retrace
1060:7CCD in al,dx
1060:7CCE jmp 0x7CD0
1060:7CD0 jmp 0x7CD2
1060:7CD2 jmp 0x7CD4
1060:7CD4 test al,0x08
1060:7CD6 jz 0x7CCD

; Wait for end vertical retrace
1060:7CD8 in al,dx
1060:7CD9 jmp 0x7CDB
1060:7CDB jmp 0x7CDD
1060:7CDD jmp 0x7CDF
1060:7CDF test al,0x08
1060:7CE1 jnz 0x7CD8

; Setup PIT timer
1060:7CE3 cli
1060:7CE4 mov cx,word ptr [0x1FC5]
1060:7CE8 mov al,0x36
1060:7CEA out 0x43,al
1060:7CEC jmp 0x7CEE
1060:7CEE jmp 0x7CF0
1060:7CF0 jmp 0x7CF2
1060:7CF2 mov al,cl
1060:7CF4 out 0x40,al
1060:7CF6 jmp 0x7CF8
1060:7CF8 jmp 0x7CFA
1060:7CFA jmp 0x7CFC
1060:7CFC mov al,ch
1060:7CFE out 0x40,al
1060:7D00 jmp 0x7D02
1060:7D02 jmp 0x7D04
1060:7D04 jmp 0x7D06
1060:7D06 sti

; Load palette A
1060:7D07 call 0x8005

; Redraw screen?
1060:7D0A call 0x4C5C
1060:7D0D cmp byte ptr [0x1FFE],0x00
Show last 7 lines
1060:7D12 jnz 0x7D17

; Restore graphics registers
1060:7D14 call 0x4CB4
1060:7D17 ret

There you go!

Now I just need to figure out if I could be bothered updating my emulator to support this or just run in non-high-perf-pc mode.

Reply 9 of 14, by Scali

User metadata
Rank l33t
Rank
l33t
derSammler wrote:

That's because for CGA, it only works at 4.77 MHz and even then is very complicated.

CGA is actually simpler than EGA/VGA, because CGA is synchronized to the PIT.
You won't have to re-set the PIT every frame, because you know that a CGA frame is exactly 19912 PIT ticks at all time.
8088 MPH exploits this characteristic in some areas, such as the title screen rolldown and the DeLorean sprite part.

For EGA/VGA (like with 1991 Donut), the video card has its own clock generator, and as such it runs asynchronously. This is why I had to re-set my timer at every vertical blank in 1991 Donut, because otherwise the timing of the PIT and the CRTC would drift apart after a few frames, and you'd actually see the palette changes shift up or down the screen.

I don't think it was too common on PC, especially on CGA, because it's a very limited technique. California Games is the only game I know of that uses it, and even there it is only used in one screen. It just happened to work there.

Also, I find it interesting that Lemmings actually rewrites the palette itself.
In 1991 Donut I exploit a feature of VGA which allows you to create multiple palette banks. Especially on slow PCs, it is impossible to switch all 16 colours of the palette in the horizontal blank interval, or even within the time of an entire scanline. So you got visual aliasing.
By setting up the palette banks in advance, I needed far fewer writes to the VGA registers to switch to 16 new colours, which even an 8088 at 4.77 MHz could do without aliasing.

For more info, see my blogpost on 1991 Donut here: https://scalibq.wordpress.com/2013/11/24/just … -like-its-1991/

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 10 of 14, by derSammler

User metadata
Rank l33t
Rank
l33t
Scali wrote:

California Games is the only game I know of that uses it, and even there it is only used in one screen.

No, it's used in the entire game. See http://www.mobygames.com/game/dos/california- … mes/screenshots (screenshots marked with CGA "MORE-color" mode).

Reply 11 of 14, by Scali

User metadata
Rank l33t
Rank
l33t
derSammler wrote:

No, it's used in the entire game. See http://www.mobygames.com/game/dos/california- … mes/screenshots (screenshots marked with CGA "MORE-color" mode).

Ah yes, seems you're right! For some reason I only ever saw the footbag part in extra colours.

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 12 of 14, by bradr

User metadata
Rank Newbie
Rank
Newbie
Scali wrote:

Also, I find it interesting that Lemmings actually rewrites the palette itself.

I wondered about that too. Even just rewriting the palette map in the attribute controller I would have thought would be simpler.

For more info, see my blogpost on 1991 Donut here: https://scalibq.wordpress.com/2013/11/24/just … -like-its-1991/

Nice!

Reply 13 of 14, by Dr.Yak

User metadata
Rank Newbie
Rank
Newbie
bradr wrote:

I wondered about that too. Even just rewriting the palette map in the attribute controller I would have thought would be simpler.

Random guessing: Because the game is a port of an Amiga game, were the coper chip is routinely used to re-program the palette on the flight ?
So it seemed the most simple to replicate the behaviour ?
(As opposed to hardware where palette switching per scan-line is the practice - as in Apple IIGs, I've read ?)

Reply 14 of 14, by NJRoadfan

User metadata
Rank Oldbie
Rank
Oldbie

Incidentally, the Apple IIgs port of Lemmings uses the Atari ST graphics (Brutal Deluxe had the luxury of picking the best features of each port ex: the music is from the DOS version). That system's graphics are more in line with the IIgs. The IIgs VGC can switch between 16 user programmed palettes on a scanline basis. Further tricks with swapping palettes on the fly (racing the beam) can further increase the total color output to 3200 colors (one unique 16 color palette per scanline).