[comp.sys.zenith.z100] Interlace stuff

GUBBINS@RADC-TOPS20.ARPA (Gern) (04/14/88)

Forward Msg:
12-Apr-88 15:57:08-EST,2069;000000000001
Return-Path: <SAC.DYESGPF@E.ISI.EDU>
Received: from E.ISI.EDU by RADC-TOPS20.ARPA with TCP; Tue 12 Apr 88 15:57:02-EST
Date: 11 Apr 1988 23:22-CDT
Sender: SAC.DYESGPF@E.ISI.EDU
Subject: Interlace Mode for HZ100
From: SAC.DYESGPF@E.ISI.EDU
To: INFO-HZ100-REQUEST@RADC-TOPS20.ARPA
Message-ID: <[E.ISI.EDU]11-Apr-88 23:22:30.SAC.DYESGPF>

For the individuals who were wondering about the interlace mode on the
HZ100, I hope the following code gets you going in the right direction.
The following program is included in the ASMUTIL1.ARC file in PD1:<HZ100>
on SIMTEL20 and demonstrates how to toggle this mode on/off.

With a little modification this code could easily be used as a proceedure
within assembly, pascal and C programs. The proc would be passed a 1 (turn
on interlace) or a 0 (turn off it off).  As is, the program functions
as a transient dos command.  If activated at the dos level before loading
ZBASIC the interlace mode will be in effect during all graphics and text
outputs to the screen, however the coorinates for graphics (e.g.
circle (x,y),r) remain unchanged (0 to 639 and 0 to 224)

Al Holecek
<SAC.DYESGPF@E.ISI.EDU>

------------------------------  CUT HERE  --------------------------------

        title.  INTERLAC - turn on or off the interlace video only mode

;;;     INTERLAC - turn on or off the interlace video only mode
;
;       Usage: INTERLAC [0 | 1]
;
;       An argument of 1 will turn interlace video only mode on, 0 will turn
;       it off.
;
;       To build INTERLAC use:
;               MASM INTERLAC;
;               LINK INTERLAC;
;               EXE2BIN INTERLAC .COM
;
;       Code comes from REMark Volume 5 Issue 12 (Dec. '84)
;       Article by Frank T. Clark, Zenith Data Systems
;
code    segment
        assume  cs:code,ds:code,es:code,ss:code
        org     0100H

begin:  cli
        mov     al,8
        out     0DCH,al
        mov     al,ds:[082H]
        and     al,1
        out     0DDH,al
        sti
        ret
code    ends
        end     begin
-------

jrv@MITRE-BEDFORD.ARPA (James R. Van Zandt) (05/01/88)

The real value of the interlace mode, as far as I'm concerned, is that
it allows you to use more than the standard 225 scan lines.  64K of
video memory is required (not the 32K that most were shipped with), and
a slow phosphor monitor is recommended to control the flicker.  You
also have to reprogram the 6845 video controller chip, and restore it
afterwards.  To show the method, I've appended the relevant parts of
the device controller from my graphics package for the Z-100.

In 400*640 mode, the screen has the same format as in 225*640 mode,
but there are no "skipped" scan lines.  The first 8 pixels of the first
scan in the blue plane are at c000:0000, and the first 8 pixels of the
next scan are 640/8 = 128 bytes further, at c000:0080.  To turn on the
3rd pixel in the second scan, write 20H to c000:0080.

The standard system routines for displaying text still work after a
fashion.  They treat the screen as having 25 text lines, each with 16
scan lines.  They put the character on scans 1-9, but they also put the
ASCII code on scan 10 and the foreground/background color codes on the
scan 11.  These are now visible, which is distracting to say the least. 
For that reason, I developed a routine to access the font table and
display characters without the extra information.  In 400*640 mode, it
treats the screen as having 400/9 = 44 text lines.

For restoring the screen, I rely on the video reset function in the
system code.

                                   - Jim Van Zandt
--------------------------------------------------------------
/* */
/* Constants */
/* */

#define BLUE	1
#define P_BLUE  0xC000
#define RED		2
#define P_RED	0xD000
#define GREEN	4
#define P_GREEN 0xE000

#define VIDEO_LATCH_ADDR 0xD8

static unsigned ram_page=P_GREEN;	/* segment for brightest plane in use */
static int color_ram=1;				/* nonzero if color RAM installed */

int pixels_wide		=	640;
int pixels_high		=	225;
double best_width	=	1.;
double best_height	=	.872;
							/* text parameters */
int char_height		=	9;
static font_height	=	9;	/* no blank scans */
int char_width		=	8;
int char_rows		=	25;
int char_columns	=	80;
int x_offset		=	0;
int y_offset		=	8;

/*	init_graphics - initialize hardware for graphics */
init_graphics()
{	static int result,not_z100;
	char buf[25];

	puts("\033z");		/* reset video parameters and clear screen */
	puts("\033y?");		/* disable key expansion */
	puts("\033x1");		/* enable 25th line */
	puts("\033x5");		/* disable cursor   */
#asm
	push	es
	mov	al,78h		;d7=0		VRAM cpu access enabled
 				;d6=d5=d4=1	no simultaneous write
 				;d3=1		VRAM data displayed
 				;d2=d1=d0=0	all planes displayed
	out	0d8h,al

	mov	bx,3
	mov	ax,0c000H	;BLUE plane
	mov	es,ax
	mov	cx,es:[0]
	push cx
	mov	es:[0],bx
				;	color ram	green plane only
	add	bx,es:[0]	;	3+3 => 6	3+(-1) => 2
	mov	ax,0d000H	;RED plane
	mov	es,ax
	mov	cx,es:[0]
	push cx
	mov	es:[0],bx
	add	bx,es:[0]	;	6+6 => 12	2+(-1) => 1
	mov	ax,0e000H	;GREEN plane
	mov	es,ax
	mov	cx,es:[0]
	push cx
	mov	es:[0],bx
	add	bx,es:[0]	;	12+12 => 24	1+1 => 2
	mov	word init_graphics_result_,bx
;
;	Is this machine a Z-100?
;	(Test the video hardware)
;
	mov	al,08h		;d7=0		VRAM cpu access enabled
				;d6=d5=d4=0	simultaneous write to all planes
				;d3=1		VRAM data displayed
				;d2=d1=d0=0	all planes displayed
	out	0d8h,al
	mov	ax,0c000H	;BLUE plane
	mov	es,ax
	mov	word es:[0],0	;		clear all planes (if Z-100)
	mov	ax,0e000H	;GREEN plane
	mov	es,ax
	mov	ax,es:[0]	;get one of the cleared (?) bytes
	mov	word init_graphics_not_z100_,ax ; zero if Z-100

	mov	al,78h		;d7=0		VRAM cpu access enabled
				;d6=d5=d4=1	no simultaneous write
				;d3=1		VRAM data displayed
				;d2=d1=d0=0	all planes displayed
	out	0d8h,al
	mov	ax,0e000H	;GREEN plane
	mov	es,ax
	pop	cx
	mov	es:[0],cx
	mov	ax,0d000H	;RED plane
	mov	es,ax
	pop	cx
	mov	es:[0],cx
	mov	ax,0c000H	;BLUE plane
	mov	es,ax
	pop	cx
	mov	es:[0],cx

	mov	al,88h		;d7=1		VRAM cpu access disabled
 				;d6=d5=d4=0	simultaneous write for all planes
				;d3=1		VRAM data displayed
				;d2=d1=d0=0	all planes displayed
	out	0d8h,al
;
;	fetch address of font table in RAM
;
        push    ds
        xor     ax,ax
        mov     ds,ax
        mov     ax,[3feh]
        mov     ds,ax
        mov     ax,[6fh]
        mov     bx,[71h]
        pop     ds
        mov     word font_seg_,bx
        mov     word font_off_,ax
	pop	es
#endasm

	if(not_z100)
		{puts("This version is for the Z-100!\007\n");
		exit(1);
		}
	clear_graphics();
	color_ram=(result==24);
	if(version()>=0x200) envsearch("GRAPHICS",buf); else buf[0]=0;
	if(buf[0]==0 | strcmp(buf,"1")==0)	/* leave in 225 * 640 mode */
		{draw_char=putchar2;
		draw_text=puts2;
		}
	else if(strcmp(buf,"2")==0)
		{draw_char=putchar2;
		draw_text=puts2;
#asm
	cli			; disable interrupts, accessing CRTC

	mov	al,4		; 30 -> R4 = vertical total
	out	0dch,al
	mov	al,30
	out	0ddh,al

	mov	al,5		; 9  -> R5 = vertical adjust
	out	0dch,al
	mov	al,9
	out	0ddh,al
				; 25 -> R6 = vertical displayed (default)
				; 28 -> R7 = sync position (default)
	mov	al,8		; 3  -> R8 = interlace sync & video
	out	0dch,al
	mov	al,011B
	out	0ddh,al

	mov	al,9		; 14 -> R9 = rasters per char
	out	0dch,al
	mov	al,14
	out	0ddh,al

	sti			;enable interrupts

	push	es
	mov	al,78h		;d7=0		VRAM cpu access enabled
 				;d6=d5=d4=1	no simultaneous write
 				;d3=1		VRAM data displayed
 				;d2=d1=d0=0	all planes displayed
	out	0d8h,al

	mov	bx,3
	mov	ax,0c000H	;BLUE plane
	mov	es,ax
	mov	cx,es:[0]
	push cx
	mov	es:[0],bx
				;			color ram		green plane only
	add	bx,es:[0]	;			3+3 => 6		3+(-1) => 2
	mov	ax,0d000H	;RED plane
	mov	es,ax
	mov	cx,es:[0]
	push cx
	mov	es:[0],bx
	add	bx,es:[0]	;			6+6 => 12		2+(-1) => 1
	mov	ax,0e000H	;GREEN plane
	mov	es,ax
	mov	cx,es:[0]
	push cx
	mov	es:[0],bx
	add	bx,es:[0]	;			12+12 => 24		1+1 => 2
	mov	word init_graphics_result_,bx

	mov	al,08h		;d7=0		VRAM cpu access enabled
 				;d6=d5=d4=0	simultaneous write to all planes
 				;d3=1		VRAM data displayed
 				;d2=d1=d0=0	all planes displayed
	out	0d8h,al
	mov	ax,0c000H	;BLUE plane
	mov	es,ax
	mov	word es:[0],0	;		clear all planes (if Z-100)
	mov	ax,0e000H	;GREEN plane
	mov	es,ax
	mov	ax,es:[0]	;get one of the cleared (?) bytes
	mov	word init_graphics_not_z100_,ax

	mov	al,78h		;d7=0		VRAM cpu access enabled
 				;d6=d5=d4=1	no simultaneous write
 				;d3=1		VRAM data displayed
 				;d2=d1=d0=0	all planes displayed
	out	0d8h,al
	mov	ax,0e000H	;GREEN plane
	mov	es,ax
	pop	cx
	mov	es:[0],cx
	mov	ax,0d000H	;RED plane
	mov	es,ax
	pop	cx
	mov	es:[0],cx
	mov	ax,0c000H	;BLUE plane
	mov	es,ax
	pop	cx
	mov	es:[0],cx

	mov	al,88h		;d7=1		VRAM cpu access disabled
 				;d6=d5=d4=0	simultaneous write for all planes
				;d3=1		VRAM data displayed
				;d2=d1=d0=0	all planes displayed
	out	0d8h,al
	pop	es
#endasm
				/* height/width parameters of screen */
		pixels_wide=640;
		pixels_high=400;
		best_width=1.;
		best_height=.777;
		clear_graphics();
		color_ram=(result==24);
		draw_line=draw2;	/* pointers to line routines */
		erase_line=erase2;
		char_rows=pixels_high/char_height;	/* text parameters */
		char_columns=80;
		char_width=8;
		x_offset=0;
		y_offset=15;
		}
	else
		{puts("graphics mode "); puts(buf); puts(" not implemented");
		getchar();
		}
}

/*	finish_graphics - clean up after graphics */
finish_graphics()
{	puts("\033z");	/* reset video parameters and clear screen */
}

static puts2(s) char *s;
{	while(*s) putchar2(*s++);
}
	
/* */
/* Calculate address of pixel on Z100 color plane (9 lines/char) */
/*  address = pixel_addr(x, y);
/* */
   
pixel_addr(x, y)

int	x, y;	/* Coordinates (x:0 - 639, y:0 - 224) */

{  int	row_start;	/* Address of first byte in row */
   int	pixel_byte;	/* Location of pixel byte in row */

   row_start  = ((y/9)<<4) + (y%9);
   pixel_byte = x>>3;

   return( (row_start*128) + pixel_byte );

}

/*
	Calculate address of pixel on Z100 color plane (16 lines/char)
	address = pixel2_addr(x, y);
*/   
pixel2_addr(x, y)

int	x, y;	/* Coordinates (x:0 - 639, y:0 - 399) */

{  int	row_start;	/* Address of first byte in row */
   int	pixel_byte;	/* Location of pixel byte in row */

   row_start  = y;
   pixel_byte = x>>3;

   return( (row_start*128) + pixel_byte );

}


static putchar2(c) int c;
{	static char *f, *start;
	int i, x, y, vls;
	static scans;

	if(c=='\n')
		{cursor_x=0; cursor_y += char_height; return c;
		}
	x=cursor_x+4;
#ifdef INCLUDING
	if(cursor_y<font_height) cursor_y=font_height;
	else if(cursor_y>=pixels_high) cursor_y=pixels_high-1;
	if(x<0) x=0;
	else if(x+char_width>=pixels_wide)
		x=pixels_wide-char_width;
#endif
	y=cursor_y-font_height;
	if(x>=0 && x<=pixels_wide-char_width &&
	y>=0 && cursor_y<pixels_high)
		{f=font_off+font_height*(c-' ');
		vls = _inb(VIDEO_LATCH_ADDR);
/*		_outb(vls&0x0F, VIDEO_LATCH_ADDR ); */
		_outb( ((vls&0x7F)|0x70)^(color_code<<4),VIDEO_LATCH_ADDR );
		if(pixels_high==400) {start=pixel2_addr(x,y); scan_row=15;}
		else {start=pixel_addr(x,y); scan_row=9-y%9;}
		scans=font_height;
#asm
	PUSH	DS
	PUSH	ES
	MOV	SI,WORD putchar2_f_		; font offset
	MOV	AX,WORD ram_page_		; destination segment...
	MOV	ES,AX
	MOV	DI,WORD putchar2_start_		; ...and offset
	MOV	AH,BYTE scan_row_		; starting scan (0 to 8)
	MOV	CX,WORD putchar2_scans_		; # bytes to move
	MOV	BX,WORD font_seg_
	MOV	DS,BX				; font segment

putchar_1:
	MOVSB					; es:di++ = ds:si++
	DEC	AH
	JZ	putchar_3
	ADD	DI,127	;	Increment to next line (same text row)
	JMP	putchar_5
putchar_3:
			;	(in 400*640 mode, this instruction 
			;	never gets executed)
	ADD	DI,1023	;	Increment to next line (next text row)
putchar_5:
	LOOP	putchar_1

	POP	ES
	POP	DS
#endasm
		_outb( vls, VIDEO_LATCH_ADDR );
		}
	cursor_x += char_width;
	return c;
}