/* $XConsortium: vgaBank.s,v 1.3 94/10/13 13:04:50 kaleb Exp $ */
/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/vga/vgaBank.s,v 3.3 1995/01/28 17:10:02 dawes Exp $ */
/*
 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Thomas Roell not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Thomas Roell makes no representations
 * about the suitability of this software for any purpose.  It is provided
 * "as is" without express or implied warranty.
 *
 * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * Author:  Thomas Roell, roell@informatik.tu-muenchen.de
 *
 */

#include "assyntax.h"

	FILE("vgaBank.s")
	AS_BEGIN

/*
 * Because a modern VGA has more than 128kBytes (which are mappable into the
 * 386' memory some logic is required. The VGA's memory (logical VGA
 * address space) is devided into smaller parts (called logical segments). 
 * These segments are mapped to logical areas.
 *
 * There are there different logical mapping areas:
 *
 * Read:       an area which can be read from
 * Write:      an area which can be written to
 * ReadWrite:  here is both read an write possible
 *
 * It is permissable to use simultaneously a Read and a Write, but you can use
 * ReadWrite only as a single. 
 * For example the bitblitting code uses a Read area as source and a Write
 * area as destination. Most other routines use only a ReadWrite.
 *
 * A logical mapping area is described by some parameters (here I will for
 * example describe a Read area:
 *
 * ReadBottom     lowest accessable byte relative to the beginning of the
 *                VGA boards mapped memory.
 * 
 * ReadTop        highes accessable byte plus one.
 *
 * SegmentSize    size of such an mapped area (common for all three)
 *
 * SegmentShift   log2(SegmentSize) (used to compute the logical segment)
 *
 * SegmentMask    SegmentSize - 1 (used to mask the offset inter an area)
 *
 * 
 * All that the following routines are doing is computing for a given offset
 * into the logical VGA adress space the offset into such an logical area
 * and the logical segment number. By the way they call also the VGA board's
 * driver to set up the VGA's physical memory mapping according to the logical
 * that was requested by the calliie.
 *
 * For shake of simplicity Write and ReadWrite share the same Bottom & Top.
 * NOTE: Read & Write may have differnt starting addresses, or even common.
 *
 * There are multible routines present for the same effect. This was made
 * for effectivly interface lowlevel assembly language best.
 */

/*
 * BUGALERT: this should be gotten from vga.h. But since there some C lang.
 *           things, too ...
 */

#include "vgaAsm.h"


	SEG_DATA
	GLOBL GLNAME(writeseg)
GLNAME(writeseg):
	D_LONG 0
GLNAME(readseg):
	D_LONG 0
GLNAME(saveseg):
	D_LONG 0

	SEG_TEXT
/*
 *-----------------------------------------------------------------------
 * vgaSetReadWrite ---
 *     select a memory bank of the VGA board for read & write access
 * Results:
 *      The adjusted pointer into the memory.
 *
 * Side Effects:
 *      None.
 *-----------------------------------------------------------------------
 * pointer
 * vgaSetReadWrite(p)
 *     register pointer p;
 * {
 * #ifdef XF86VGA16
 *   writeseg = ((unsigned long)p - vgaBase) >> vgaSegmentShift;
 *   (vgaSetReadWriteFunc)(writeseg);
 *   return (vgaWriteBottom + (((unsigned int)p - vgaBase) & vgaSegmentMask));
 * #else
 *   writeseg = ((unsigned long)p - VGABASE) >> vgaSegmentShift;
 *   (vgaSetReadWriteFunc)(writeseg);
 *   return (vgaWriteBottom + ((unsigned int)p & vgaSegmentMask));
 * #endif
 * }
 *
 */
	ALIGNTEXT4
	GLOBL GLNAME(vgaSetReadWrite)
GLNAME(vgaSetReadWrite):
	MOV_L	(REGOFF(4,ESP),EAX)
	PUSH_L	(ECX)
	PUSH_L	(EDX)
#ifdef XF86VGA16
	SUB_L	(CONTENT(GLNAME(vgaBase)),EAX)
#else
	SUB_L	(VGABASE,EAX)
#endif
	MOV_L	(CONTENT(GLNAME(vgaSegmentShift)),ECX)
	SHR_L	(CL,EAX)
	MOV_L	(EAX,CONTENT(GLNAME(writeseg)))
	MOV_L	(CONTENT(GLNAME(vgaSetReadWriteFunc)),EDX)
	CALL	(CODEPTR(EDX))
	POP_L	(EDX)
	POP_L	(ECX)
	MOV_L	(REGOFF(4,ESP),EAX)
#ifdef XF86VGA16
	SUB_L	(CONTENT(GLNAME(vgaBase)),EAX)
#endif
	AND_L	(CONTENT(GLNAME(vgaSegmentMask)),EAX)
	ADD_L	(CONTENT(GLNAME(vgaWriteBottom)),EAX)
 	RET

/*
 *-----------------------------------------------------------------------
 * vgaReadWriteNext ---
 *     switch to next memory bank of the VGA board for read & write access
 * Results:
 *      The adjusted pointer into the memory.
 *
 * Side Effects:
 *      None.
 *-----------------------------------------------------------------------
 *
 *
 * pointer
 * vgaReadWriteNext(p)
 *      register pointer p;
 * {
 *   (vgaSetReadWriteFunc)(++writeseg);
 *   return (p - vgaSegmentSize);
 * }
 */
	ALIGNTEXT4
	GLOBL	GLNAME(vgaReadWriteNext)
GLNAME(vgaReadWriteNext):
	PUSH_L	(EDX)
	MOV_L	(CONTENT(GLNAME(writeseg)),EAX)
	INC_L	(EAX)
	MOV_L	(EAX,CONTENT(GLNAME(writeseg)))
	MOV_L 	(CONTENT(GLNAME(vgaSetReadWriteFunc)),EDX)
	CALL 	(CODEPTR(EDX))
	POP_L	(EDX)
	MOV_L	(REGOFF(4,ESP),EAX)
	SUB_L	(CONTENT(GLNAME(vgaSegmentSize)),EAX)
	RET

/*
 *-----------------------------------------------------------------------
 * vgaReadWritePrev ---
 *     switch to previous memory bank of the VGA board for read & write access
 * Results:
 *      The adjusted pointer into the memory.
 *
 * Side Effects:
 *      None.
 *-----------------------------------------------------------------------
 *
 * pointer
 * vgaReadWritePrev(p)
 *      register pointer p;
 * {
 *   (vgaSetReadWriteFunc)(--writeseg); 
 *   return (p + vgaSegmentSize);
 * }
 */
	ALIGNTEXT4
	GLOBL	GLNAME(vgaReadWritePrev)
GLNAME(vgaReadWritePrev):
	PUSH_L	(EDX)
	MOV_L	(CONTENT(GLNAME(writeseg)),EAX)
	DEC_L	(EAX)
	MOV_L	(EAX,CONTENT(GLNAME(writeseg)))
	MOV_L 	(CONTENT(GLNAME(vgaSetReadWriteFunc)),EDX)
	CALL 	(CODEPTR(EDX))
	POP_L	(EDX)
	MOV_L	(REGOFF(4,ESP),EAX)
	ADD_L	(CONTENT(GLNAME(vgaSegmentSize)),EAX)
	RET

/*
 *-----------------------------------------------------------------------
 * vgaSetRead ---
 *     select a memory bank of the VGA board for read access
 * Results:
 *      The adjusted pointer into the memory.
 *
 * Side Effects:
 *      None.
 *-----------------------------------------------------------------------
 * pointer
 * vgaSetRead(p)
 *     register pointer p;
 * {
 * #ifdef XF86VGA16
 *   readseg = ((unsigned long)p - vgaBase) >> vgaSegmentShift;
 *   (vgaSetReadFunc)(readseg);
 *   return (vgaReadBottom + (((unsigned int)p - vgaBase) & vgaSegmentMask));
 * #else
 *   readseg = ((unsigned long)p - VGABASE) >> vgaSegmentShift;
 *   (vgaSetReadFunc)(readseg);
 *   return (vgaReadBottom + ((unsigned int)p & vgaSegmentMask));
 * #endif
 * }
 *
 */
	ALIGNTEXT4
	GLOBL	GLNAME(vgaSetRead)
GLNAME(vgaSetRead):
	MOV_L	(REGOFF(4,ESP),EAX)
	PUSH_L  (ECX)
	PUSH_L	(EDX)
#ifdef XF86VGA16
	SUB_L	(CONTENT(GLNAME(vgaBase)),EAX)
#else
	SUB_L	(VGABASE,EAX)
#endif
	MOV_L	(CONTENT(GLNAME(vgaSegmentShift)),ECX)
	SHR_L	(CL,EAX)
	MOV_L	(EAX,CONTENT(GLNAME(readseg)))
	MOV_L	(CONTENT(GLNAME(vgaSetReadFunc)),EDX)
	CALL	(CODEPTR(EDX))
	POP_L	(EDX)
	POP_L	(ECX)
	MOV_L	(REGOFF(4,ESP),EAX)
#ifdef XF86VGA16
	SUB_L	(CONTENT(GLNAME(vgaBase)),EAX)
#endif
	AND_L	(CONTENT(GLNAME(vgaSegmentMask)),EAX)
	ADD_L	(CONTENT(GLNAME(vgaReadBottom)),EAX)
 	RET

/*
 *-----------------------------------------------------------------------
 * vgaReadNext ---
 *     switch to next memory bank of the VGA board for read access
 * Results:
 *      The adjusted pointer into the memory.
 *
 * Side Effects:
 *      None.
 *-----------------------------------------------------------------------
 *
 *
 * pointer
 * vgaReadNext(p)
 *      register pointer p;
 * {
 *   (vgaSetReadFunc)(++readseg);
 *   return (p - vgaSegmentSize);
 * }
 */
	ALIGNTEXT4
	GLOBL	GLNAME(vgaReadNext)
GLNAME(vgaReadNext):
	PUSH_L	(EDX)
	MOV_L	(CONTENT(GLNAME(readseg)),EAX)
	INC_L	(EAX)
	MOV_L	(EAX,CONTENT(GLNAME(readseg)))
	MOV_L 	(CONTENT(GLNAME(vgaSetReadFunc)),EDX)
	CALL 	(CODEPTR(EDX))
	POP_L	(EDX)
	MOV_L	(REGOFF(4,ESP),EAX)
	SUB_L	(CONTENT(GLNAME(vgaSegmentSize)),EAX)
	RET

/*
 *-----------------------------------------------------------------------
 * vgaReadPrev ---
 *     switch to previous memory bank of the VGA board for read access
 * Results:
 *      The adjusted pointer into the memory.
 *
 * Side Effects:
 *      None.
 *-----------------------------------------------------------------------
 *
 * pointer
 * vgaReadPrev(p)
 *      register pointer p;
 * {
 *   (vgaSetReadFunc)(--readseg); 
 *   return (p + vgaSegmentSize);
 * }
 */
	ALIGNTEXT4
	GLOBL	GLNAME(vgaReadPrev)
GLNAME(vgaReadPrev):
	PUSH_L	(EDX)
	MOV_L	(CONTENT(GLNAME(readseg)),EAX)
	DEC_L	(EAX)
	MOV_L	(EAX,CONTENT(GLNAME(readseg)))
	MOV_L 	(CONTENT(GLNAME(vgaSetReadFunc)),EDX)
	CALL 	(CODEPTR(EDX))
	POP_L	(EDX)
	MOV_L	(REGOFF(4,ESP),EAX)
	ADD_L	(CONTENT(GLNAME(vgaSegmentSize)),EAX)
	RET

/*
 *-----------------------------------------------------------------------
 * vgaSetWrite ---
 *     select a memory bank of the VGA board for write access
 * Results:
 *      The adjusted pointer into the memory.
 *
 * Side Effects:
 *      None.
 *-----------------------------------------------------------------------
 * pointer
 * vgaSetWrite(p)
 *     register pointer p;
 * {
 * #ifdef XF86VGA16
 *   writeseg = ((unsigned long)p - vgaBase) >> vgaSegmentShift;
 *   (vgaSetWriteFunc)(writeseg);
 *   return (vgaWriteBottom + (((unsigned int)p - vgaBase) & vgaSegmentMask));
 * #else
 *   writeseg = ((unsigned long)p - VGABASE) >> vgaSegmentShift;
 *   (vgaSetWriteFunc)(writeseg);
 *   return (vgaWriteBottom + ((unsigned int)p & vgaSegmentMask));
 * #endif
 * }
 *
 */
	ALIGNTEXT4
	GLOBL	GLNAME(vgaSetWrite)
GLNAME(vgaSetWrite):
	MOV_L	(REGOFF(4,ESP),EAX)
	PUSH_L  (ECX)
	PUSH_L	(EDX)
#ifdef XF86VGA16
	SUB_L	(CONTENT(GLNAME(vgaBase)),EAX)
#else
	SUB_L	(VGABASE,EAX)
#endif
	MOV_L	(CONTENT(GLNAME(vgaSegmentShift)),ECX)
	SHR_L	(CL,EAX)
	MOV_L	(EAX,CONTENT(GLNAME(writeseg)))
	MOV_L	(CONTENT(GLNAME(vgaSetWriteFunc)),EDX)
	CALL	(CODEPTR(EDX))
	POP_L	(EDX)
	POP_L	(ECX)
	MOV_L	(REGOFF(4,ESP),EAX)
#ifdef XF86VGA16
	SUB_L	(CONTENT(GLNAME(vgaBase)),EAX)
#endif
	AND_L	(CONTENT(GLNAME(vgaSegmentMask)),EAX)
	ADD_L	(CONTENT(GLNAME(vgaWriteBottom)),EAX)
 	RET

/*
 *-----------------------------------------------------------------------
 * vgaWriteNext ---
 *     switch to next memory bank of the VGA board for write access
 * Results:
 *      The adjusted pointer into the memory.
 *
 * Side Effects:
 *      None.
 *-----------------------------------------------------------------------
 *
 *
 * pointer
 * vgaWriteNext(p)
 *      register pointer p;
 * {
 *   (vgaSetWriteFunc)(++writeseg);
 *   return (p - vgaSegmentSize);
 * }
 */
	ALIGNTEXT4
	GLOBL	GLNAME(vgaWriteNext)
GLNAME(vgaWriteNext):
	PUSH_L	(EDX)
	MOV_L	(CONTENT(GLNAME(writeseg)),EAX)
	INC_L	(EAX)
	MOV_L	(EAX,CONTENT(GLNAME(writeseg)))
	MOV_L 	(CONTENT(GLNAME(vgaSetWriteFunc)),EDX)
	CALL 	(CODEPTR(EDX))
	POP_L	(EDX)
	MOV_L	(REGOFF(4,ESP),EAX)
	SUB_L	(CONTENT(GLNAME(vgaSegmentSize)),EAX)
	RET

/*
 *-----------------------------------------------------------------------
 * vgaWritePrev ---
 *     switch to previous memory bank of the VGA board for write access
 * Results:
 *      The adjusted pointer into the memory.
 *
 * Side Effects:
 *      None.
 *-----------------------------------------------------------------------
 *
 * pointer
 * vgaWritePrev(p)
 *      register pointer p;
 * {
 *   (vgaSetWriteFunc)(--writeseg); 
 *   return (p + vgaSegmentSize);
 * }
 */
	ALIGNTEXT4
	GLOBL	GLNAME(vgaWritePrev)
GLNAME(vgaWritePrev):
	PUSH_L	(EDX)
	MOV_L	(CONTENT(GLNAME(writeseg)),EAX)
	DEC_L	(EAX)
	MOV_L	(EAX,CONTENT(GLNAME(writeseg)))
	MOV_L 	(CONTENT(GLNAME(vgaSetWriteFunc)),EDX)
	CALL 	(CODEPTR(EDX))
	POP_L	(EDX)
	MOV_L	(REGOFF(4,ESP),EAX)
	ADD_L	(CONTENT(GLNAME(vgaSegmentSize)),EAX)
	RET

/*
 *-----------------------------------------------------------------------
 * vgaSaveBank --
 *     save Banking-state
 * Results:
 *      None.
 *
 * Side Effects:
 *      None.
 *-----------------------------------------------------------------------
 *
 * void
 * vgaSaveBank()
 * {
 *   saveseg = writeseg;
 * }
 */
	ALIGNTEXT4
	GLOBL	GLNAME(vgaSaveBank)
GLNAME(vgaSaveBank):
	MOV_L	(CONTENT(GLNAME(writeseg)),EAX)
	MOV_L	(EAX,CONTENT(GLNAME(saveseg)))
	RET

/*
 *-----------------------------------------------------------------------
 * vgaRestoreBank --
 *     restore the banking after vgaSaveBank was called
 *
 * Results:
 *      None.
 *
 * Side Effects:
 *      None.
 *-----------------------------------------------------------------------
 *
 * void
 * vgaRestoreBank()
 * {
 *   (vgaSetWriteFunc)(saveseg);
 *   (vgaSetReadFunc)(saveseg);
 * }
 */
	ALIGNTEXT4
	GLOBL	GLNAME(vgaRestoreBank)
GLNAME(vgaRestoreBank):
	PUSH_L	(EDX)
	MOV_L	(CONTENT(GLNAME(saveseg)),EAX)
	MOV_L	(EAX,CONTENT(GLNAME(writeseg)))
	MOV_L	(CONTENT(GLNAME(vgaSetWriteFunc)),EDX)
	CALL	(CODEPTR(EDX))
	MOV_L	(CONTENT(GLNAME(saveseg)),EAX)
	MOV_L	(EAX,CONTENT(GLNAME(readseg)))
	MOV_L	(CONTENT(GLNAME(vgaSetReadFunc)),EDX)
	CALL	(CODEPTR(EDX))
	POP_L	(EDX)
	RET


/*
 *-----------------------------------------------------------------------
 * vgaPushRead ---
 *     make the write-bank also readable. no acces to the former read bank !
 * Results:
 *      None.
 *
 * Side Effects:
 *      None.
 *-----------------------------------------------------------------------
 *
 * void
 * vgaPushRead(p)
 * {
 *   (vgaSetReadWriteFunc)(writeseg);
 * }
 */
	ALIGNTEXT4
	GLOBL	GLNAME(vgaPushRead)
GLNAME(vgaPushRead):
	PUSH_L	(EDX)
	MOV_L	(CONTENT(GLNAME(writeseg)),EAX)
	MOV_L	(CONTENT(GLNAME(vgaSetReadWriteFunc)),EDX)
	CALL	(CODEPTR(EDX))
	POP_L	(EDX)
	RET

/*
 *-----------------------------------------------------------------------
 * vgaPopRead ---
 *     restore the banking after vgaPushRead was called
 *
 * Results:
 *      None.
 *
 * Side Effects:
 *      None.
 *-----------------------------------------------------------------------
 *
 * void
 * vgaPopRead(p)
 * {
 *   (vgaSetWriteFunc)(writeseg);
 *   (vgaSetReadFunc)(readseg);
 * }
 */
	ALIGNTEXT4
	GLOBL	GLNAME(vgaPopRead)
GLNAME(vgaPopRead):
	PUSH_L	(EDX)
	MOV_L	(CONTENT(GLNAME(writeseg)),EAX)
	MOV_L	(CONTENT(GLNAME(vgaSetWriteFunc)),EDX)
	CALL	(CODEPTR(EDX))
	MOV_L	(CONTENT(GLNAME(readseg)),EAX)
	MOV_L	(CONTENT(GLNAME(vgaSetReadFunc)),EDX)
	CALL	(CODEPTR(EDX))
	POP_L	(EDX)
	RET
