• Please review our updated Terms and Rules here

How to set 640x200x16 on later Tandys?

commodorejohn

Veteran Member
Joined
Jul 6, 2010
Messages
3,311
Location
California, USA
I've been thinking that this is actually a pretty decent possible graphics mode; if you treat it as each pixel pair constituting one logical pixel, you get (logically) byte-aligned chunky pixels and a total of 136 colors, which isn't bad at all for sub-VGA systems. Problem is, I can't figure out how to set it. Ralf Brown's Interrupt List nominally gives this a mode number of 0x0B for the BIOS mode-set function, but says that the Tandy BIOS doesn't actually support it (why did they include it, then?) Various other sources confirm this, and say that you have to twiddle registers, but fail to mention what needs to be twiddled. I checked the technical reference for the 1000SL (the model on which this mode was introduced,) and it doesn't say anything about it. Video Array control register 3 has separate bits for "4-color High Resolution," "16-Color Mode," and "Extra Video Mode" - do you have to set one or more of these?
 
Thanks - I've been looking through a couple other packages off TVDog, and I'm sort of getting the idea. Sounds like this mode is actually even a simple linear framebuffer, without the interleaved-lines frol-de-rol of ordinary TGA...
 
I'm not so sure it's linear, because I saw a 200-item scanline table all throughout the code. Actually... it's possible he has generic draw routines that use the scanline table no matter the mode. So, ignore me :)

You mentioned it would be cool to mix colors in 640x200 to make a pseudo-136-color mode -- if you want to see what some games look like when they do this, run Crime Wave in VGA mode, check out the title screen, then set it to EGA 640x200 and run it again. The results aren't great, but they're not horrible either. The success of doing that trick relies on how bad your monitor is -- the fuzzier the dot pitch, the better. It also helps if you design your graphics from the very beginning to do this (run Zeliard, Silpheed, Thexder, Firehawk, Vette!, Falcon AT, or Spectrum Holobyte's Tank in EGA 640x200 mode for examples.)

The real fun for any mode that has multiple video pages is mixing colors across pages -- meaning, if you want to display a particular color combo, have two 16-color pages and flip between them on every retrace, and put one color pixel in page 0 and the other in page 1. Some combinations flicker badly enough that they are unusable (like, red+green or black+white), but others are very subtle and the flickering is barely noticable. There are about 40 quite usable "colors" this way, and you get the full 640x200 resolution. I keep meaning to use this trick in a demo or graphics viewer, but I will probably never find the time.
 
Yeah, I've seen interlaced color blending. It's nifty, but I'm afraid that even subtle interlacing gives me headaches :/ Getting more colors with the full 640x200 would be nice, but on the other hand, a logical 320x200 with a vaguely logical 8-bit color depth means that, if you arrange your palette correctly, you can reuse the same graphic elements across Tandy, EGA, MCGA, and VGA and only need to change the drawing code, and on the latter two, you even get nice solid pixels and can further tweak the duplicate entries in the palette to give even greater color depth.
 
Okay, borrowing from the TANDOTS demo in tanvid.zip, I've got this put together. I haven't gotten a chance to test it on my RL yet, but it works in DOSBOX (better than the original demo does, actually - that program has a blank 20 pixels on the right edge for some reason; I think it sets one of the 6845 registers wrong, whereas mine just lets the BIOS take care of that.)

Code:
setVideo:
	; This is based on the TANDOTS 640x200x16 demo, but tries to leave as much
	; of the actual register-twiddling up to the BIOS as possible.
	
	mov	ax, 0x000a	; Set 640x200x4 mode and try to tweak registers from there.
	int	0x10
	
	mov	si, videoRegisterTable
.lp:
	lodsw			; Get port #
	test	ax, ax	; If port = 0, it's the end of the list.
	jz	.done
	mov	dx, ax
	lodsb			; Get register value
	out	dx, al
	jmp	.lp
.done:
	ret
	
videoRegisterTable:
	dw	0x03d8	; Disable video display while loading control registers.	
	db	0x13
	; CRTC registers
	;dw	0x03d4	; I've commented out all the ones that seem to be taken care of
	;db	0x10	; by the BIOS, but I'm leaving 'em in just in case.
	;dw	0x03d5
	;db	0x18
	;dw	0x03d4
	;db	0x00
	;dw	0x03d5
	;db	0x71
	;dw	0x03d4
	;db	0x01
	;dw	0x03d5
	;db	0x50
	;dw	0x03d4
	;db	0x02
	;dw	0x03d5
	;db	0x5a
	;dw	0x03d4
	;db	0x03
	;dw	0x03d5
	;db	0x0e
	;dw	0x03d4
	;db	0x04
	;dw	0x03d5
	;db	0xff
	;dw	0x03d4
	;db	0x05
	;dw	0x03d5
	;db	0x06
	dw	0x03d4
	db	0x06
	dw	0x03d5
	db	0xc8
	;dw	0x03d4
	;db	0x07
	;dw	0x03d5
	;db	0xe2
	dw	0x03d4
	db	0x09
	dw	0x03d5
	db	0x00
	;dw	0x03d4
	;db	0x0c
	;dw	0x03d5
	;db	0x00
	;dw	0x03d4
	;db	0x0d
	;dw	0x03d5
	;db	0x00
	;dw	0x03d4
	;db	0x11
	;dw	0x03d5
	;db	0x00
	;dw	0x03d4
	;db	0x12
	;dw	0x03d5
	;db	0x46
	dw	0x03da	; Palette mask
	db	0x01
	dw	0x03de
	db	0x0f	
	dw	0x03da	; Border color
	db	0x02
	dw	0x03de
	db	0x00
	dw	0x03da	; Control register (enable 16 colors)
	db	0x03
	dw	0x03de
	db	0x10
	dw	0x03da	; What are video array registers 5 and 8? They're undocumented.
	db	0x05
	dw	0x03de
	db	0x01
	dw	0x03da
	db	0x08
	dw	0x03de
	db	0x02
	dw	0x03d9	; Set border color (?).  (See docs.)
	db	0x00
	dw	0x03dd	; Set extended RAM paging off.
	db	0x00	; (This may need to be tweaked depending on where we want VRAM.)
	dw	0x03df	; Set the addressing mode, select page 2.
	db	0x24
	; Reset palette entries 1-3 to colors 1-3, rather than the CGA defaults.
	dw	0x03da
	db	0x11
	dw	0x03de
	db	0x01
	dw	0x03da
	db	0x12
	dw	0x03de
	db	0x02
	dw	0x03da
	db	0x13
	dw	0x03de
	db	0x03
	dw	0x03d8	; Reenable video.
	db	0x1b
	dw	0x0000

And a quick test program:
Code:
	cpu	8086
	org	0x100
	
	call	setVideo
	
	mov	ax, 0xa000
	mov	es, ax
	xor	di, di
	xor	ax, ax
	mov	cx, 0x7D00
	
lp:	stosw
	xchg	al, ah
	inc	ax
	xchg	al, ah
	loop	lp
	
done:
	mov	ah,	0x00
	int	0x16
	
	mov	ax, 0x0002
	int	0x10
	mov	ah, 0x4c
	int	0x21
	
	%include	"vidtandy.asm"

As can be seen from the screenshot, the pixels count linearly in 16-bit (4-pixel) sets from 0x0000 to 0x7CFF - it is a linear framebuffer.
tandytest.png
 

Attachments

  • tandytest.jpg
    tandytest.jpg
    26.8 KB · Views: 2
Last edited:
Alright, here's a simple RAW image viewer (easy enough, I just hacked up an old Hercules image viewer of mine to do the job.) I don't have any image libraries for DOS, so none o' yer fancy-pants file formats like BMP or nothin'.

(Well, okay, actually if you strip the first 0x76 bytes off a 640x200 16-color BMP...it'll come out vertically flipped, but otherwise fine. So flip-before-strip, and it's an easy way to make a test image.)
 

Attachments

  • tandypic.zip
    3.1 KB · Views: 1
What I was originally going for was a program that used your 136-color idea to take a 256-color (or 24-bit color!) .bmp or .tga or something and then convert it down to 136 colors for display. THAT'S the fun project :)
 
Ah, yes. That would probably be doable as well...though I'd have to draw the line at displaying only 320x200 images, not resizing (good scaling algorithms are pretty well outside my area of expertise...)
 
Came back to this after the discussion on extended-Tandy stuff in the PCjr thread. Still gotta work up a proper converter (I've done Atkinson dither before, just not in assembler,) but I did write this little utility that takes a 640x200x16 RAW and tweaks the bytes so that the brightest pixel is always on the left; I find this helps make the image a little clearer with less visible "dither" artifacting.
 

Attachments

  • tandyfix.zip
    687 bytes · Views: 2
Back
Top