static char rcsid[] = "$Header: ds.c,v 800.0 85/08/06 14:10:36 root Exp $";
static char sccsid[] = "%W% %Y% %Q% %G%";

/*
 * I/O(ds.c)
 *	display screen output device
 *	with vt100 emulation
 */


/* chars don't start on word boundaries
 *
 * logical location: x,y (in terms of bits)
 * physical location: addr (in words), bitoffset (0-15)
 * wrbitofs field:
 *    horizontal - bit # (from right to left)
 *    vertical - bit offset (how far over from left)
 *
 * cursor right: x + char width, y stays same, recalculate addr
 *
 * sbs 840917
 *	added dsgcursor().
 *	added 'ged mode' wherein the bottom line of the screen
 *	don't scroll, and it ends at column 72 rather than 79
 *	(experimentally determined that ged menu is 7 cols wide).
 * sbs 841024
 *	ged menu rescaled, so no need for 73-column bottom line
 * 841220
 *	VT100 mode by Preston Gardner
 */
#include "../h/param.h"			/* system definitions and constants */
#include "../white/config.h"		/* I/O base address */
#include "../white/via.h"		/* VIA clock XXX */
#include "../white/mouse.h"		/* mouse defs for graphics cursor */
#include "../white/dispmgr.h"		/* display manager (vt100 emulation) */
#include "../white/vt100cook.h"		/* vt100 XXX */
#include "../white/vt100pager.h"	/* vt100 XXX */
#include "../white/ds.h"		/* display-specific stuff */


#define SCCSID(s) /* s */

SCCSID(%W% %E% %U% %Y%)

int dsbase = DSBASE;		/* global value for machdep to size memory */
int dssize = DSSIZE;		/* global value for machdep to size memory */

struct dswnd hdswnd = {
	{ 16, 9, ' ', '~', 0xFFFFFE00, },
	(int *)(DSBASE+0xD55E), (int *)(DSBASE+0xD55E), 0, 719, 559,
	0, 35, 80, 0, 0
};

struct dswnd vdswnd = {
	{ 9, 16, ' ', '~', 0x0000FFFF, },
	(int *)(DSBASE+0xD506), (int *)(DSBASE+0xD506), 0, 559, 719,
	0, 45, 62, 0, 0
};

int vert = 0;			/* default: horizontal */
struct dswnd *dswnd = &hdswnd;	/* default: horizontal */
int	dsoneline = 0;
static dsdocursor = 1;
int	ds_debug;		/* enable cursor debugging gimmicks */

display vt100display;	pdisp	vt100d = &vt100display;
window  vt100window;	windowp	vt100w = &vt100window;

dsopen()
{
	static int dsfirst = 0;

	if (dsfirst == 0) {
		dsfirst = 1;
		viainit();
		if (VIAADDR->v_rb&B_VSW) {
			dswnd = &vdswnd;	/* vertical display */
			vert = 1;
		}
		VIAADDR->v_rb &= ~B_VOFF;
		wvt100init(vt100d,vt100w,
			dswnd->nlines - 1, dswnd->ncols - 1,
			dswnd->maxx,dswnd->maxy);
		clearscr();
		dscursor();
	}
}


viainit()
{
	register struct via_device *vp = VIAADDR;

	vp->v_rax = I_CLR;
	vp->v_rb = I_CLR;
	vp->v_acr = ACR_SR0|ACR_T1OS;
	vp->v_ier = I_CLR|I_CA2|I_CA1|I_SR|I_CB2|I_CB1|I_T2;
	vp->v_ier = I_SET|I_T1;
	vp->v_ddra = A_XOR;
	vp->v_ddrb = B_CH1|B_CH0|B_VADDR1|B_VADDR0|B_VOFF;
	vp->v_rb = B_VOFF;
}


clearscr()
{
	clear(DSBASE, 0x10000);
	dshome();
}


/* display a character */
dsputch(c)
	register c;
{
	c &= 0x7f;
	screen_vt100(vt100d, vt100w, c, dsdocursor /* 1 */ /*drawcursor*/);
}


/*
 * Set or clear one-line mode as appropriate, doing all necessary kludges
 * If we need a narrower bottom line (73 instead of 80), the expressions are
 *
 *	dswnd->maxx = (vert)? 510: 656;	(narrower line)
 *	dswnd->maxx = (vert)? 559: 719; (restore line width)
 */
dssetone(newmode) {
	if (dsoneline = newmode) {
		vt100w->curcol = 0;
		dswnd->xpixdelta = 0;
		vt100w->curline = 34;
		dswnd->ypixdelta = 0;
	}
}


/*
 * Take us in/out of one-line mode, returning the previous mode.
 * C'est un hack.
#ifdef SIEMENS
 * Das ist eine Hack.
#endif
 */
dsonemode(newmode) {
	int	omode = dsoneline;
	register char *p;

	if (newmode) {
		/* vomit. */
		for (p = "\033S"; *p;)
			dsputch(*p++);
	} else {
		for (p = "\033s"; *p;)
			dsputch(*p++);
	}
	return omode;
}


/*
 * Performance hack: enable/disable cursor drawing
 */
dsupdcursor(new) {
	int oldcursor = dsdocursor;
	extern oncursor(), offcursor();

	if (ds_debug == 0)
		return 1;
	dsdocursor = (new != 0);
	if (dsdocursor != oldcursor)
		(*(dsdocursor? oncursor: offcursor))(vt100d, vt100w);
	return oldcursor;
}


/* display (and undisplay) cursor */
dscursor() {
	register int d7, d6;
	register int *a5;

	a5 = dswnd->home2;
	d7 = dswnd->wrbitofs;
	d6 = dswnd->dscset.csmask;
	if (vert) {
		asm("	rorl	d7,d6");
	} else {
		asm("	roll	d7,d6");
		a5 = (int *)((char *)a5 - 2);
	}
	asm("	notl	d6");
	d7 = dswnd->dscset.cslpch;
	while (--d7 != -1) {
		*a5 ^= d6;
		a5 = (int *) ((char *)a5 - SCNOFS);
	}
}

/*
 * display (and undisplay) graphics cursor
 *	called by interrupt service [mouse.c:mstate()] to update the cursor
 *	position on the screen.  x and y are point-coordinates (0<=x<720,
 *	0<=y<560) starting at the top-left corner of the screen.
 *	Method due to Fred Ford.
 */
#define NLR		24		/* number of long words per raster */
#define NWR		48
#define NSL		5		/* shifts for long word boundary */
#define NSW		4
#define NBW		16		/* number of bits per word */
#define shortwordix(x,y)	((u_short *)scrnbase+(y)*NWR-((x)>>NSW))
static	u_char *scrnbase = (u_char *)0x88035C;
dsgcursor(x, y)
	register x, y;
{
	static u_short curs[] = {
		0x0020,0x0020,0x0020,0x0020,0x0020,
		0x07FF,0x0020,0x0020,0x0020,0x0020,
		0x0020
	};
	register u_short *frmptr;
	register u_long	*scradr, mask;
	register frmht, shift;

	shift = 0;
	x -= 5; y -= 5;			/* change to lower left corner */
	mask = (u_long)0xFFFFFFFF;
	frmht = 11;			/* XXX height of xhair cursor */
	frmptr = curs;

	/*
	 * clip the sucker to window boundaries ...
	 */
	if (x + 10 > XMAX)
		mask = ~(mask << ((XMAX + 1) - x));
	else if (x < XMIN) {
		shift = XMIN - x;
		x = XMIN;
	}
	if (y + 10 > YMAX)
		frmht = (YMAX + 1) - y;
	else if (y < YMIN) {
		frmptr += (YMIN - y);
		frmht -= (YMIN - y);
		y = YMIN;
	}

	/*
	 * ... and draw it
	 */
	scradr = (u_long *)shortwordix(x, y);
	x &= (NBW - 1);

	while (--frmht >= 0) {
		*scradr ^= ((u_long)(*frmptr++) & mask) >> shift << x;
		scradr += NLR;
	}
}


/* clear to eol (vertical) given x, y and maximum pixel addr on right */
dsclrvtomax(x, y, max)
	register x, y;
	int max;
{
	int bitoff, z, i;
	int *addr;

	dsaddr(x, y, &bitoff, &addr);	/* compute cursor addr */
	z = ror(bitoff, dswnd->dscset.csmask);
	for (i = (max - x); i >= 0; i--) {
		*addr = *addr & z;
		addr -= SCNOFSI;
	}
}

/* clear to eol (vertical) given x, y */
dsclrv(x, y)
	register x, y;
{
	dsclrvtomax(x, y, dswnd->maxx);
}

/* clear to eol (horizontal) given x, y and max pixel address on right */
dsclrhtomax(x, y, lcnt, max)
register int x, y, lcnt;
int max;
{
	register i;
	register unsigned short m1, m2;
	register short b1, b2;
	register short *a1, *a2, *a;
	short *addr;
	int bitoff;

	m1 = m2 = -1;

	dsaddr(x, y, &bitoff, &addr);
	m1 = ~(-1 << bitoff);
	a1 = addr;
	dsaddr(max, y, &bitoff, &addr);
	m2 = -1 << bitoff;
	a2 = addr;
	if (a1 == a2) {
		for (i = 0; i < lcnt; i++) {
			*a1 &= m1 | m2;
			a1 = (short *)((char *)a1 - SCNOFS);
		}
	} else for (i = 0; i < lcnt; i++) {
		a = a2;
		*a++ &= m2;
		while (a < a1)
			*a++ = 0;
		*a &= m1;
		a1 = (short *)((char *)a1 - SCNOFS);
		a2 = (short *)((char *)a2 - SCNOFS);
	}

#ifdef notdef		/* commented out in code gotten from corvus (??) */
	register int d1, d2, bitoff, z, i, z2, bitof2;
	register short *caddr, *caddr2;

	dsaddr(x, y, &bitoff2, &addr);
	caddr2 = addr;
	d1 = dswnd->dscset.csmask << bitof2;
	z = dswnd->maxx + 1;
	dsaddr(z - 1, y, &bitoff, &addr);
	z -= x;
	z -= bitoff;
	if (bitoff == 0)
		addr++;
	z2 = z & 0x0F;
	z = (z >> 4) - 1;
	d2 = -1;
	d2 = (unsigned)d2 >> z2;
	for (i = 0; i < lcnt; i++) {
		caddr = (short *)addr;
		if (bitof2 != 0) {
			*caddr2 &= d1;
			caddr2 = (short *) ((char *)caddr2 - SCNOFS);
		}
		if ((y = z + 1) > 0)
			while (--y != -1) {
				*caddr++ = 0;
			}
		addr = (int *) ((char *)addr - SCNOFS);
	}
#endif notdef
}


/* clear to eol (horizontal) given x, y */
dsclrh(x, y, lcnt)
register int x, y, lcnt;
{
	dsclrhtomax(x, y, lcnt, dswnd->maxx);
}



/* Display char at current address (where cursor is), then compute
 * x, y and new address.  Note that the cursor is implicitly overlaid
 * so no need to undisplay cursor.
 */
dsshwch(d7)
	register d7;
{
	register int d6, d5, d4;
	register int *a5;		/* current vertical address */
	register unsigned short *a4;

	if ((dswnd->dscset.frstch > d7) || (dswnd->dscset.lastch < d7))
		return;		/* if ch not in char set, don't print */
	d7 -= dswnd->dscset.frstch;	/* get relative char position */
	d4 = dswnd->dscset.cslpch;
	if (vert) {
		d6 = dswnd->dscset.csmask;
		d5 = dswnd->wrbitofs;
		asm("	rorl	d5,d6");
		d5 = 32 - DSCELLH - d5;
		a5 = dswnd->home2;
		a4 = vchset[d7];
		if (vt100w->charatts & RVBIT) {	/* reverse video */
			while (--d4 != -1) {
				*a5 = *a5 & d6 | (~(*a4++) << d5);
				a5 = (int *) ((char *)a5 - SCNOFS);
			}
		} else {
			while (--d4 != -1) {
				*a5 = *a5 & d6 | (*a4++ << d5);
				a5 = (int *) ((char *)a5 - SCNOFS);
			}
		}
	}
	else {		/* horizontal */
		d6 = dswnd->dscset.csmask;
		d5 = dswnd->wrbitofs;
		asm("	roll	d5,d6");
		a5 = (int *)((char *) dswnd->home2 - 2);
		a4 = hchset[d7];
		if (vt100w->charatts & RVBIT) {	/* reverse video */
			while (--d4 != -1) {
				/* 1ff is kludge; should use csmask (d6) */
				*a5 = *a5 & d6 | ((~(*a4++)&0x1ff) << d5);
				a5 = (int *) ((char *)a5 - SCNOFS);
			}
		} else {
			while (--d4 != -1) {
				*a5 = *a5 & d6 | (*a4++ << d5);
				a5 = (int *) ((char *)a5 - SCNOFS);
			}
		}
	}
}


/* clear to end of line */
dsclel()
{
	int x, y;

	x = dstox(vt100w->curcol,dswnd);
	y = dstoy(vt100w->curline,dswnd);
	if (vert)
		dsclrv(x, y);
	else
		dsclrh(x, y, DSCELLH);
}


/* clear to end of screen */
dscles()
{
	register cursy, maxy;

	dsclel();		/* clear to end of line */
	cursy = dstoy(vt100w->curline,dswnd);
	maxy = dswnd->maxy;
	if (vert)
		while ((cursy = cursy + DSCELLH) <= maxy)
			dsclrv(0, cursy);
	else {
		cursy += DSCELLH;
		if (cursy <= maxy)
			dsclrh(0, cursy, maxy - cursy + 1);
	}
}


/* dsaddr - compute cursor address */
dsaddr(x, y, bitoff, addr)
	register short x, y;
	int *bitoff;
	short **addr;
{
	if (vert) {
		y += dswnd->homeof;
		*bitoff = y & 0x0F;
		y >>= 4;
		*addr = (short *)dswnd->home1 + y - x * SCNOFSS;
	} else {			/* horizontal */
		x += dswnd->homeof;
		*bitoff = x & 0x0F;
		x >>= 4;
		*addr = (short *)dswnd->home1 - x - y * SCNOFSS;
	}
}


/* calculate current address and put into structure */
dscrsad()
{
	dsaddr(dstox(vt100w->curcol,dswnd), dstoy(vt100w->curline,dswnd),
		&dswnd->wrbitofs, &dswnd->home2);
}


/* handle tab (size = 8) */
dstab()
{
	register i;

	i = vt100w->curcol / 8;
	i = ++i * 8;
	if (i < dswnd->ncols)
		vt100w->curcol = i;
	else {
		vt100w->curcol = 0;
		dsincy();
	}
}


/* move cursor right one */
dsincx()
{
	register unsigned newx;

	newx = vt100w->curcol + 1;
	if (newx < dswnd->ncols) {
		vt100w->curcol = newx;
	} else {
		vt100w->curcol = 0;
		dsincy();
	}
}


/* carriage return: x = 0 */
dsreturn()
{
	vt100w->curcol = 0;
}


/* move cursor home */
dshome()
{
	vt100w->curcol = 0;
	vt100w->curline = 0;
}


/* cursor left */
dsdecx()
{
	if (vt100w->curcol == 0) {
		dswrapx();
	} else {
		vt100w->curcol--;
	}
}

/* cursor up */
dsdecy()
{
	if ((--vt100w->curline) < 0)
		vt100w->curline = 0;
}

dsincy()
{
	register int cursy;

	cursy = vt100w->curline + 1;
	if (cursy < dswnd->nlines) {
		vt100w->curline = cursy;
	} else {
		dscroll(dstoy(vt100w->topsc,dswnd), (vt100w->botsc-vt100w->topsc+1)*DSCELLH, 1);
	}
}

/* reverse carriage return, up to end of line above */
dswrapx()
{
	register unsigned d0;

	if (dsoneline || vt100w->curline == 0)
		return;
	d0 = (unsigned) dswnd->maxx / (unsigned) DSCELLW;
	d0 *= (unsigned) DSCELLW;
	vt100w->curcol = xtods(d0);
	dsdecy();
}

ror(a, b)
{
	asm("	movl	a6@(12),d0");
	asm("	movl	a6@(8),d1");
	asm("	rorl	d1,d0");
}

/* Scroll screen one line starting at pixel address y and below, ignoring
   what is above; scroll len screen lines.  This works OK for VT100 scrolling
   regions.  If dir == -1 do a reverse scroll.  */
dscroll(y, len, dir)
{
	int *addr, bitoff;
	register char *desthom, *srchom;
	short lines = DSCELLH;

	if (dsoneline) {
		dsreturn();
		dsclel();
		return;
	}
	if (!vert) {
		dsaddr(0, y, &bitoff, &addr);
		desthom = (char *)((int *)((int)addr & ~3) + 1);
		dsaddr(0, y + DSCELLH, &bitoff, &addr);
		srchom = (char *)((int *)((int)addr & ~3) + 1);
		if (dir != -1) {	/* forward scroll */
			scrolh(srchom, desthom, lines, dswnd->maxx+1, len);
		} else {		/* reverse scroll */
			scrolh(desthom, srchom, lines, dswnd->maxx+1, len);
		}
	} else {
		desthom = (char *)dswnd->home1;
		srchom = desthom + lines / 8;	/* bits to bytes per line */
		if (dir != -1) {	/* forward scroll */
			scrolv(srchom, desthom, lines, dswnd->maxx+1, len);
		} else {		/* reverse scroll */
			scrolv(desthom, srchom, lines, dswnd->maxx+1, len);
		}
	}
}


/* scroll vertical */
/* This code cannot be used for VT100 scrolling regions with a vertical
   screen because it always erases the line at the bottom and scrolls across
   the entire length of the screen.   VT100 scrolling regions for vertical
   screen do not work.  */
scrolv(srchom, dsthom, lines, wid, len)
	char *srchom, *dsthom;
	short lines, wid, len;
{
	register short i;
	register int d6 = 0, d5 = 0, d4 = 0, d3 = 0, d2 = 0;
	register char *a5 = 0, *a4 = 0, *a3 = 0, *a2 = 0;

	i = wid -1;
	if (srchom > dsthom) {	/* forward scroll */
		a5 = (char *)dsthom -(SCNOFS * wid);  /* start at other end */
		a4 = (char *)srchom -(SCNOFS * wid);
		asm("	movl a6,a7@-");
		do {
			/* copy 12 longs */
			asm("	moveml	a4@+,#0x4F7F");
			asm("	moveml	#0x4F7F,a5@");

			/* advance pointer, 12 longs to regs, zero one out, copy back */
			asm("	lea	a5@(48),a5");
			asm("	moveml	a4@+,#0x4F7F");
			asm("	lea	0,a6");  /* blank wraparound in retrace */
						/* This bashes the line that is
						    supposed to be erased.  It
						    will only work for a
						    16-pixel vertical scroll. */
			asm("	moveml	#0x4F7F,a5@");

			/* advance pointer */
			asm("	lea	a5@(48),a5");
		} while (--i != -1);
		asm("	movl a7@+,a6");
	} else if (srchom < dsthom) {	/* reverse scroll */
		a5 = (char *)dsthom;  /* start at this end, pointers decrease */
		a4 = (char *)srchom;
		asm("	movl a6,a7@-");
		do {
			/* copy 12 longs */
			asm("	lea	a4@(-48),a4");
			asm("	moveml	a4@,#0x4F7F");
			asm("	clrl	d0");	/* blank wraparound in retrace */
						/* This bashes the line that is
						    supposed to be erased.  It
						    will only work for a
						    16-pixel vertical scroll. */
			asm("	moveml	#0xFEF2,a5@-");

			/* advance pointer, 12 longs to regs, copy back */
			asm("	lea	a4@(-48),a4");
			asm("	moveml	a4@,#0x4F7F");
			asm("	moveml	#0xFEF2,a5@-");
		} while (--i != -1);
		asm("	movl a7@+,a6");
	} else { 	/* srchom == dsthom, should never happen */
		/* do nothing */
	}
}


/* scroll horizontal */
/* Works OK for VT100 partial scrolling regions */
scrolh(srchom, dsthom, lines, wid, len)
	char *srchom, *dsthom;
	short lines, wid, len;
{
	register short i;
	register int d6, d5, d4, d3, d2;
	register char *a5, *a4, *a3, *a2;

	/* This code will have to get changed when we go to higher
	   resolution screen.  The loops below do 96-byte copies for
	   a line across length of screen -- this will not be enough.  */

	if (srchom < dsthom) {	/* scroll down, text moves up */

		a4 = srchom;  a5 = dsthom;
		i =  len - lines - 1;
		asm("	movl	a6,a7@-");	/* save a6 on stack */
		do {	/* Copy one line running across length of screen */
			/* The addresses decrease because we are copying lower
			   addresses to higher addresses; if we did it the other
			   way we'd wipe out data we want to copy. */
			asm("	lea	a4@(-48),a4");
			asm("	moveml	a4@,#0x4F7F");
			asm("	moveml	#0xFEF2,a5@-"); /* FEF2 is 4F7F backwards */

			/* Advance pointer 12 longs, load the next 12 longs
			   of screen memory into registers, and copy those
			   12 into destination locations of screen memory.
			   We do the exact same thing twice to get 24*4=96
			   bytes. */
			asm("	lea	a4@(-48),a4");
			asm("	moveml	a4@,#0x4F7F");
			asm("	moveml	#0xFEF2,a5@-"); /* FEF2 is 4F7F backwards */
		} while (--i != -1);
		asm("	movl a7@+,a6");		/* restore a6 from stack */


		/* clear the lines scrolled away */
		i = lines - 1;
		asm("	movl	a6,a7@-");	/* save a6 on stack */
		asm("	moveq #0,d6");
		asm("	movl d6,d0");	/* movl is faster than clrl */
		asm("	movl d6,d1");	/* put 0's in all the registers */
		asm("	movl d6,d2");
		asm("	movl d6,a6");
		asm("	movl a6,a0");
		asm("	movl a0,a1");
		asm("	movl a1,a2");
		d2 = d3 = d4 = d5 = d6;
		a3 = a2;
		do {
			/* these registers are all 0 -- zeroes out 48
			   bytes in one instruction */
			asm("	moveml	#0xFEF2,a5@-");
			asm("	moveml	#0xFEF2,a5@-");
		} while (--i != -1);
		asm("	movl a7@+,a6");		/* restore a6 from stack */

	} else if (dsthom < srchom) {
		/* scroll up -- text moves down.  Same as above but
		   pointers move in increasing direction */
		int otherend = (SCNOFS * (len - lines));

		/* start at bottom (low end) of copy region */
		a4 = srchom - otherend;  a5 = dsthom - otherend;

		i =  len - lines - 1;
		asm("	movl	a6,a7@-");	/* save a6 on stack */
		do {	/* Copy one line running across length of screen */
			/* The addresses increase because we are copying higher
			   addresses to lower addresses; if we did it the other
			   way we'd wipe out data we want to copy. */
			asm("	moveml	a4@+,#0x4F7F");
			asm("	moveml	#0x4F7F,a5@");
			asm("	lea	a5@(+48),a5");

			/* Advance pointer 12 longs, load the next 12 longs
			   of screen memory into registers, and copy those
			   12 into destination locations of screen memory.
			   We do the exact same thing twice to get 24*4=96
			   bytes. */
			asm("	moveml	a4@+,#0x4F7F");
			asm("	moveml	#0x4F7F,a5@");
			asm("	lea	a5@(+48),a5");
		} while (--i != -1);
		asm("	movl a7@+,a6");		/* restore a6 from stack */

		a5 = srchom;  /* set pointer so we start zeroing out at high
				 end of src area.  For zero part we go in
				 decreasing order so we can use predecrement
				 moveml.  WARNING: this assignment has to be
				 done while a6 is restored to the link pointer;
				 if you do it below when a6 == 0 then you get
				 garbage for srchom because it indexes off of
				 a6 to get it.  */

		/* clear the lines scrolled away */
		i = lines - 1;
		asm("	movl	a6,a7@-");	/* save a6 on stack */
		asm("	moveq #0,d6");
		asm("	movl d6,d0");	/* movl is faster than clrl */
		asm("	movl d6,d1");	/* put 0's in all the registers */
		asm("	movl d6,d2");
		asm("	movl d6,a6");
		asm("	movl a6,a0");
		asm("	movl a0,a1");
		asm("	movl a1,a2");
		d2 = d3 = d4 = d5 = d6;
		a3 = a2;
		do {
			/* these registers are all 0 -- zeroes out 48
			   bytes in one instruction */
			asm("	moveml	#0xFEF2,a5@-");
			asm("	moveml	#0xFEF2,a5@-");
		} while (--i != -1);
		asm("	movl a7@+,a6");		/* restore a6 from stack */

	} else {	/* srchom == dsthom  -- should never happen */

		/* do nothing */
	}
}

#include "../h/errno.h"
extern struct hsimchars {
	char sc_char;
	char sc_vert; /* 0 is horizontal, 1 vertical */
	unsigned short sc_norm[16];
	unsigned short sc_sim[16];
} hschars[];
extern short hsim_height, vsim_height;
extern nhschars;

/*
 * Go into/out of "simulator" mode depending on "which" (1=into)
 *
 * If we are really going to use this mode, [hv]chset should
 * be glyph pointers, not glyphs, for faster font switching!
 */
dssimchars(which) {
	register struct hsimchars *hs;
	register i;
	register orientation = (dswnd != &hdswnd);
				/* 0 is horizontal, 1 is vertical */
	register short glyph_height = (orientation)? vsim_height: hsim_height;

	for (hs = hschars, i = nhschars; --i >= 0; hs++) {
		if (hs->sc_vert == orientation) {
			blt(hchset[hs->sc_char-' '],
				(which? hs->sc_sim: hs->sc_norm),
				glyph_height*sizeof(hs->sc_sim[0]));
		}
	}
	return 0;
}
