;	[]===========================================================[]
;
;	NOTICE: THIS PROGRAM BELONGS TO AWARD SOFTWARE INTERNATIONAL(R)
;	        INC. IT IS CONSIDERED A TRADE SECRET AND IS NOT TO BE 	
;	        DIVULGED OR USED BY PARTIES WHO HAVE NOT RECEIVED	
;	        WRITTEN AUTHORIZATION FROM THE OWNER.
;
; 	[]===========================================================[]
;

;----------------------------------------------------------------------------
;Rev  Date   Name  Description
;----------------------------------------------------------------------------
;R10  07/15/98 KVN  Added a error message for 0E000h code exceed 64K
;		    during make BIOS when not define "AVIDEO_AT_F000"
;R08A 11/14/97 TNY  Delete "NO_SUPPORT_AVIDEO" definition.
;R09  07/02/97 RCH  Fixed "PrintScreen" only print one line of screen display
;		    while using monochrome card.
;R08  03/18/97 TNY  Add "NO_SUPPORT_AVIDEO" definition.
;R04A 05/02/96 RCH  Fixed monochrome display abnormal while using "LIST.EXE"
;		    to browse a text file.
;R07  03/28/96 RCH  Fixed the whole bottom line can not be cleared after
;		    exiting autoexec.bat with menu selection for monochrome
;		    card
;R06  03/13/96 RCH  Performance improve for monochrome display (coding by jeff)	
;R05A 02/06/96 RAY  Fix coding mistake
;R05  02/05/96 RAY  Bug fixed: the screen mess up in some applications.
;R04  01/19/96 KKS  Fixed coding mistakes that cause CHECKIT and AMIDIAG 
;		    testing failed
;R03  01/16/96 KKS  Fixed two coding mistakes.
;R02  01/11/96 RCH  Replace branch instruction with short branch to reduce
;		    code size
;R01  01/11/96 RCH  Modifiy original code from USA to support current 
;		    structure	
;R99  01/16/96 RCH  Original codes mask by USA
;R00  12/21/95 KKS  Convert TSR INT10 into BIOS Avideo function
;                   TSR INT10h is written by Irving A. Tjomsland in a clear  
;                   room environment. IT IS VERY IMPORTANT NOT TO MODIFY
;                   THIS CODE ACCRODING TO THE ORIGINAL IBM CODE.                   

    PAGE  63,132
    TITLE  AVIDEO  -- ROM INT 10 VIDEO DRIVER
.386            
;             +---------------+
;             |               |
;             | CGA/MDA VIDEO |
;             |               |
;             +---------------+
;
;HARDWARE     EQU  410H      ; INSTALLED HARDWARE FLAG
;CON_MODE     EQU  449H      ; CURRENT MODE
;CON_COLS     EQU  44AH      ; # OF COLUMNS ON SCREEN
;CON_LEN      EQU  44CH      ; LENGTH OF SCREEN
;CON_STR      EQU  44EH      ; BASE ADDRESS OF SCREEN
;CUR_POS      EQU  450H      ; CURSOR POSITION FOR 8 PAGES
;CURSOR_MODE  EQU  460H      ; CURSOR MODE SETTING
;ACT_PAGE     EQU  462H      ; PAGE BEING DISPLAYED
;CARD_ADDR    EQU  463H      ; BASE ADDRESS OF DISPLAY CARD
;CON_MODE_SET EQU  465H      ; Current mode select register
;CON_PALETTE  EQU  466H      ; Current palette value
;CON_LLINE    EQU  484H      ; last row of video screen.

G_RAM    SEGMENT  USE16 AT 40H
  INCLUDE    G_RAM.INC
G_RAM    ENDS

;INT VECTORS (LOC 0)

;PTR_VIDEO_PARM  EQU  1DH * 4     ; POINTER TO VIDEO PARMS
;PTR_VIDEO_EXT   EQU  1FH * 4     ; Video Graphics Characters

SEG_0    SEGMENT  USE16 AT 01H    ; eliminate segment 0
  INCLUDE  SEG_0.INC
SEG_0    ENDS

;Equates, externals and macros

    INCLUDE  BIOS.CFG             ; BIOS building equates
    INCLUDE  COMMON.EQU           ; Common equates

    INCLUDE AVIDEO.EQU
    INCLUDE ATORGS.EXT            ; Data in atorgs.asm

		INCLUDE COMMON.MAC

    PAGE
;R08Aifndef NO_SUPPORT_AVIDEO		;R08

;R01 - start
		extrn	F000_call_proc:near	
		extrn	F000_func_end:Near	
		extrn	F000_VECT:Near		
		extrn	RET_E_SEG:near		

ifndef	PNP_BIOS
AVIDEO_AT_F000		EQU	1
endif	;PNP_BIOS

ifndef	AVIDEO_AT_F000						
;R10EGROUP		GROUP	ECODE
;R10ECODE		SEGMENT	USE16 PARA PUBLIC 'ECODE'
EGROUP		GROUP	EFCODE					;R10
EFCODE		SEGMENT	USE16 DWORD COMMON 'EFCODE'		;R10
		ASSUME	CS:EGROUP
;R10 start
		org	0
		DB	55h,0aah			;signature
		db	08H				;4kb
		retf
		DB	'(c) COPYRIGHT 1984,1995 Award Software Inc.'
		DB	'ALL RIGHTS RESERVED'
;R10 end
else	;AVIDEO_AT_F000	
DGROUP		GROUP	FCODE
FCODE		SEGMENT	USE16 PARA PUBLIC 'CODE'
		ASSUME	CS:DGROUP
endif	;AVIDEO_AT_F000	
;R01 - end

;R01 ifdef  POST_SEG
;R01     extrn  F000_call_proc:near    ; Micro for f000_call
;R01 EGROUP    GROUP  ECODE
;R01 ECODE    SEGMENT  USE16 PARA PUBLIC 'ECODE'
;R01     ASSUME  CS:EGROUP
;R01 ifndef  NO_MONO_Support           ; Reserve some area for avideo and pnp
;R01     DB  55h,0aah                  ; signature
;R01 endif  ;NO_MONO_Support        
;R01 ifdef  PNP_BIOS          
;R01     DB  10h                       ; size = 8 KB
;R01 else;  PNP_BIOS        
;R01     db  08H                       ; 4kb      
;R01 endif;  PNP_BIOS         
;R01     retf
;R01     DB  '(c) COPYRIGHT 1984,1995 Award Software Inc.'
;R01     DB  'ALL RIGHTS RESERVED'
;R01 else;  POST_SEG
;R01 DGROUP    GROUP  FCODE
;R01 FCODE    SEGMENT  USE16 DWORD PUBLIC 'CODE'
;R01     ASSUME  CS:DGROUP
;R01 endif;  POST_SEG

;DATA FOR INT10H


v_jmptab  dw    v00r, v01r, v02r, v03r, gpl, v05r, v06r, v07r, v08r, v09r
          dw    v0ar, v0br, v0cr, v0dr, v0er, v0fr, vnlr, vnlr, vnlr, v13r

v_blocs   dw    0b800h, 0b000h  ; Color and mono video buffer locations
v_colrb   db    030h, 030h, 030h, 030h, 030h, 030h, 03fh, 030h ; Data for 6845 color reg
v_pgmax   db    7, 7, 3, 3, 1, 1, 1, 1 ; Max video buffer number for each mode

mask_6    db    07fh, 000h, 07fh, 080h, 0bfh, 000h, 0bfh, 040h
          db    0dfh, 000h, 0dfh, 020h, 0efh, 000h, 0efh, 010h  ; Masks for
          db    0f7h, 000h, 0f7h, 008h, 0fbh, 000h, 0fbh, 004h
          db    0fdh, 000h, 0fdh, 002h, 0feh, 000h, 0feh, 001h  ; inserting and
mask_3    db    03fh, 000h, 03fh, 040h, 03fh, 080h, 03fh, 0c0h  ; reading
          db    0cfh, 000h, 0cfh, 010h, 0cfh, 020h, 0cfh, 030h  ; pixels
          db    0f3h, 000h, 0f3h, 004h, 0f3h, 008h, 0f3h, 00ch
          db    0fch, 000h, 0fch, 001h, 0fch, 002h, 0fch, 003h

s45_col   db    000h, 055h, 0aah, 0ffh
s45_msk   db    000h, 003h, 00ch, 00fh, 030h, 033h, 03ch, 03fh  ; Masks for 2
          db    0c0h, 0c3h, 0cch, 0cfh, 0f0h, 0f3h, 0fch, 0ffh  ; bit color

tab_get   dw    0000h, 2000h, 0050h, 2050h ; Table for accessing single
          dw    00a0h, 20a0h, 00f0h, 20f0h ; char in video buffer

    PAGE

;    +-----------------------+
;    |   CGA INT 10 ENTRY    |
;    +-----------------------+

    PUBLIC  VIDEO_ENTRY
VIDEO_ENTRY  PROC  NEAR

    STI
    CLD        ; FORWARD DIRECTION

 ifdef CALL_TABLE                 
;requires a table of dword ptrs to reside at F000:0 which may just point   
;to a far return or may point to a user maintained routine.                

   %OUT CALL_TABLE Video hook enabled                
    call  dword ptr CS:[4*15]  ; Entry 15 dec       
 endif ;CALL_TABLE                     

; Save the working registers

    pushad                          ; save all the gp registers
    push    ds                      ; and the seg registers
    push    es
    push    fs
    push    gs
    mov     bp, sp                  ; Set up bp as the frame pointer
    
    push    0F000h
    pop     es                      ; Set es to point at f000

    push    G_RAM
    pop     fs                      ; Set the fs to point at ROM BIOS data

    push    vectseg              
    pop     gs                      ; Clear gs for interrupt vector points

;R01 ifdef  POST_SEG
;R01     push    egroup
;R01 else  ;POST_SEG
;R01     push    dgroup
;R01 endif ;POST_SEG
;R01 - start
ifndef	AVIDEO_AT_F000						
	    push    egroup
else;	AVIDEO_AT_F000						
	    push    dgroup
endif;	AVIDEO_AT_F000						

;R01 - end
    pop     ds                      ; Set up base of read only data seg

; Use a jump table based on al to calculate the location of the appropriate routine.
    mov     al, ah                  ; Calculate the offset to the proper
                                    ; routine in v_jmptab
;R05    and     ax, 07fh                ; Get rid of any high bits
;R05    cmp     al, 13h                 ; If not 13 or less, exit
;R05    jg      short v_exit            ;

;R05 - starts
    cmp     al, 13h
    ja      short v_exit
;R05A    and     al, 07Fh
    and     ax, 07Fh		;R05A
;R05 - ends

    shl     ax, 1                   ; Multiply x 2
    mov     si, ax                  ; and put in index register
    jmp     v_jmptab[si]            ; Go to the selected subroutine

vnlr:                               ; Exit for non support int10 functions

v_exit:
    pop     gs
    pop     fs
    pop     es
    pop     ds
    popad

    IRET

VIDEO_ENTRY  ENDP

    SUBTTL  FUNC 0 - SET MODE

;    +-----------------------+
;    |    FUNC 0 SET MODE    |
;    +-----------------------+

;------------------------------------------------------------------------------
;Function:      Set Video Mode
;Function id:   00h
;
;Entry:         AH = 00h
;               AL = Video Mode
;
;Exit:          None
;
;Notes:         Uses the ROM BIOS Data Area and is partially controlled by
;               several different interrupt vectors.
;------------------------------------------------------------------------------

    ALIGN  4
v00r    proc    near

; First select the display adapter using only the equip bits in 40:10
        mov     dx, v_cadapt    ; ;RKKS Set to CGA mode
        mov     ax, v_equip     ; Get the equipment word
        and     al, 30h         ; Clear all but the video bits
        jz      v00_xit   	; If zero, we shouldn't be here
        jnp     short v00_4     ; ;RKKS If no parity we have CGA
        mov     dx, v_madapt    ; ;RKKS Otherwise, its a MDA
        mov     b ueax, 07h     ; ;RKKS force to mode 7

; Initialization is adequate and will be completed by the normal operation
; of int 10h, Set Video Mode .

v00_4:
        mov     ah, byte ptr ueax         ; Get the mode id
        and     ah, 07h         ; Clear all but the mode id

        mov     bx, 03h         ; Get the loc of MDA page size
        test    al, 30h         ; Test the video equip bits yet again
        jpe     short v00_6     ; Go if we're in MDA mode
        xor     bx, bx          ; Set for first CGA reg init table
v00_5:
        cmp     ah, 02h         ; If less than
        jl      short v00_6     ;  two, we have the table address
        add     bl, 1           ; Step to next table
        cmp     ah, 04h         ; If less than 5,
        jl      short v00_6     ; We have the proper table
        add     bl, 1           ; This is the proper table for 4, 5 and 6
v00_6:
        push    ds              ; save data segment 
        mov     si, offset ES:TBL_MODE_CLEN         ; Get the base for the buffer sizes ;RKKS
        shl     bx, 1           ; Mult x 2 to calculate word offset
        add     si, bx          ; Location of corresponding buffer size
        mov     si, ES:[si]     ; Get the buffer size in si 
        mov     v_pgsze, si     ; and set the RBDA current page size
        mov     w v_pgoff, 0    ; Set the offset to page 0, ( 0 offset )
        mov     b v_actpg, 0    ; Set the active page to 0

        shl     bx, 3           ; Finish shifting bx to cause mult by 16
        lds     si, gs:v_iptr   ; Get location of 6840 Reg init table
                                ; We are using the interrupt vector because DOS
                                ; MODE op likes to move the initiation values.
        add     si, bx          ; Add the location of the first CGA init bytes
                                ; DS:SI now points at the proper Reg Init table
        movzx   bx, ah          ; Save mode id in bx for later use setting RBDA

; Turn off the 6845 video screen enable bit in the 6845 to allow reprogramming
; of various 6845 registers

        add     dx, 4           ; Step to point at the mode select register
;RKKS        mov     al, v_mreg      ; Get the mode select byte
;RKKS        and     al, not 08h     ; Turn off the video enable signal
        mov     al,ah           ; get video mode 
        inc     al              ; ;RKKS for mode 7 set bit 3
        shr     al,3            ; ;RKKS shift bit 3 value to al bit 0
        out     dx, al          ; ;RKKS and set in 6845
        sub     dx, 4           ; Reset dx to point at the register select
                                ; port
; Now, set up the 6845 registers and the ROM BIOS Data Area (40:0, the RBDA)

        mov     cx, 16          ; number of registers to be progremed 
v00_7:
        dec     cl              ; cl is the register index number
        mov     al, cl          ; Set al to cause 6845 to point at index
        add     si, cx          ; point to the value to be programed  
        mov     ah, [si]        ; Get the initiation value for R0
        out     dx, ax          ; Al sets the register and ah goes to the reg
        sub     si,cx           ; restore si
        or      cl,cl           ; is index 0
        jnz     short v00_7     ; Are all of the register programed      

; Set up 40 area data

; R0 - Set the screen width in character -- total characters on a line.
; R1 - Set the number of characters displayed on a line.
        mov     al, 1[si]       ; Get the initiation for R1
        cmp     bl, 6           ; If mode 6, the required tables are wrong
        jne     short v00_7_1   ; We can't change the tables -- they're
        mov     al, 80          ; also used by DOS -- Mode 6 has 80 columns
v00_7_1:
        xor     ah, ah          ; Convert to full word
        mov     v_cols, ax      ; and set the RBDO at 40:4a
; R2 - Horiz sync.  Determines where line actually starts.  This is the field
;      changed by the DOS MODE command.  It can vary and must be set from the
;      value as set by DOS during normal operation.
; R3 - Horiz sync. width.  Determines width of horizontal line
; R4 - Vertical total scan lines
; R5 - Vertical total adjusted scan lines
; R6 - Vertical Displayed lines
; R7 - Vertical sync positioning
; R8 - Interlace Mode
; R9 - Max Scan Line Address - 1
; R10 - Starting Scan Line for the cursor
        mov     ch, 10[si]      ; Get the initiation value for R10
; R11 - Ending Scan Line for the cursor
        mov     cl, 11[si]      ; Get the initiation value for R11
        mov     v_crshp, cx     ; Set the cursor shape in the RBDA
; R12 - High six bits of the 6845 buffer offset.  This value, along with R13,
;       sets the first character to be scanned from the appropriate buffer
        mov     ch, 12[si]      ; Get the hi order 6 bits of scan offset
; R13 - The low order eight bits of the scan address.  See R12.
        mov     cl, 13[si]      ; Get the low order 8 bits of the scan offset
        mov     v_pgoff, cx     ; and set the offset address in the RBDA
; R14 - High six bits of cursor position expressed as offset from beginning of
;       the video buffer -- not the active page.
; R15 - Low order eight bits of cursor position.  See R14.


; Clear the RBDA cursor postions for every page
        xor     ecx, ecx        ; Clear 4 bytes in ecx
        mov     d fs:v_crpos + 0, ecx     ; Set page 0,1 cursor to 0
        mov     d fs:v_crpos + 4, ecx     ; Set page 2,3 cursor to 0
        mov     d fs:v_crpos + 8, ecx     ; Set page 4,5 cursor to 0
        mov     d fs:v_crpos + 12, ecx    ; Set page 6,7 cursor to 0

; Note that R16 and R17 also exist.  They are used for the light pen and are
; not supported by this code.

; Set the RBDA mode id the port address we've been using

        mov     v_mode, bl      ; Set the RBDA video mode id byte
        mov     v_port, dx      ; Set the RBDA port address

; Now set the 6845 color palette select byte

        pop     ds              ; Restore data segment ;RKKS
        mov     al, ds:v_colrb[bx]        ; Get the color reg data
        add     dx, 5           ; Step to color select port
        out     dx, al          ; Set the color register
        mov     v_cpal, al      ; Set the RDBA color byte

; Is the "don't clear" switch specified in al?

        test    b ueax, 80h     ; Hi order bit means don't clear the buffer
        jnz     short v00_11    ; Go if the bit is on

; Clear the video buffer

        push    es              ; save es as f000 segment ;RKKS
        mov     eax, 07000700h  ; Init to white chars, black bkgnd for text
        test    ES:TBL_MODE_SETS[bx], m_graphics    ; Graphic mode
        jz      short v00_10_1  ; Go, if we're not in graphics
        xor     eax, eax        ; Zero the buffer for graphics mode
v00_10_1:

        xor     cx, cx          ; Clear the destination reg

        mov     di, cx          ;
        mov     cx, 4000h / 4   ; Assume the CGA Buffer length in dwords 
        mov     es, v_blocs     ; and Buffer address
        cmp     dx, 03d0h       ; Do we have a mono buffer?
        jg      short v00_10    ; Nope, use as we set it up
        mov     cx, 800h/2      ; Else, change setup to the mono length and
        mov     es, v_blocs + 2 ; Buffer address
v00_10:
        cld                     ; use the forward direction

        rep stosd               ; and clear the buffer

        pop     es

; The 6845 reprogramming is complete.  Restart the video according to the IBM
; Color Graphics write up.

v00_11:
        mov     al, ES:TBL_MODE_SETS[bx]  ; Get the new video mode byte
        dec     dx              ; Step back from color port to video select port
        out     dx, al          ; Restart the video

        mov     v_mreg, al      ; Save the actual byte set in the 6845

	mov	fs:CON_LLINE,24	; set 25 lines for Mono & CGA	;R09

v00_xit:
        jmp     v_exit          ; Exit from the interrupt routine

v00r    endp

    SUBTTL  FUNC 01 - SET CURSOR TYPE
;    PAGE

;    +---------------------------+
;    | FUNC 01 - SET CURSOR TYPE |
;    +---------------------------+

;------------------------------------------------------------------------------
;Function:      Set Cursor Type
;Function ID:   01h
;
;Entry:         AH = 01h
;               CH = Cursor Start Line and Control Bits
;               CL = Cursor End Line
;
;Exit:          None
;
;Notes:         Sets RBDA w 40:60h, Cursor Shape and control bits
;
;------------------------------------------------------------------------------

    ALIGN  4
v01r    proc    near

; First, set the Rom Bios Data Area ( RBDA ) with the new cursor shape

        mov     v_crshp, cx     ; Save cursor shape in the Rom Bios Data Area

; Then, set the 6845 with the new information.  Note this is not page sensitive
; and will change the cursor shape no matter what page is being displayed.

        mov     ax, cx          ; Value to be programed  
        mov     cl, 10          ; Get ptr to cursor starting line register (R10)
        call    set_6845

        jmp     v_exit          ; Exit from the interrupt routine

v01r    endp


    SUBTTL  FUNC 02 - SET CURSOR POSSITION
;    PAGE

;    +---------------------------------------+
;    |    FUNC 02 - SET CURSOR POSSITION     |
;    +---------------------------------------+

;------------------------------------------------------------------------------
;Function:      Set Cursor Position
;Function ID:   02h
;
;Entry:         AH = 02h
;               DH = Row
;               DL = Column
;               BH = Page number specification
;
;Exit:          None
;
;Notes:         Sets RBDA w 40:4ah, Mi,ber pf Text Columns in Text Mode
;                         b 40:4eh, Offset to beginning of active page
;                       8 w 40:50h, Cursor postions for each of 8 pages, 0 - 7
;
;------------------------------------------------------------------------------

        ALIGN   4
v02r    proc    near

; If the current page is specifed, the 6845 must also be set.

        cmp     bh, v_actpg     ; Is user specifying the currently active page?
        jne     short v02_5     ; No, only set proper RBDA slot -- not the 6845

; Set the 6845. First calculate the offset from the beginning of the current
; video buffer.  row * max_cols + col + page_offset

        mov     cx, dx          ; Save the row and col
        movzx   ax, ch          ; Move the row number to ax for mult.
        mul     word ptr v_cols ; mult by number of chars in a row
        movzx   dx, cl          ; Zero extend column number to dx
        add     ax, dx          ; Add col number
        add     ax, v_pgoff     ; Add the offset to the current page
                                ; The 6845 cursor is now in ax

; Set up the 6845

        mov     dx, cx          ; Restore the original row and column
        mov     cl, 14          ; Get pointer to register 14
        call    set_6845        ; Go set cursor position

v02_5:
        movzx   bx, bh          ; Get the specified page number
        shl     bx, 1           ; Calculate byte offset to page in cursor table
        mov     v_crpos[bx], dx ; Set cursor table

        jmp     v_exit          ; Exit from the interrupt routine

v02r    endp

    SUBTTL  FUNC 03 - READ CURSOR POSITION

;    +---------------------------------------+
;    |     FUNC 03 - READ CURSOR POSITION    |
;    +---------------------------------------+

;------------------------------------------------------------------------------
;Function:      Get Cursor Position
;Function ID:   03h
;
;Entry:         AH = 03h
;               BH = Page number specification
;
;Exit:          CH = Beginning Line of Cursor and Control Bits
;               CH = Ending line of the Cursor
;               DH = Row
;               DL = Column
;
;Notes:         Sets RBDA w 40:4eh, Offset to active page
;                         b 40:62h, Active Page Number
;
;------------------------------------------------------------------------------

        ALIGN   4
v03r    proc    near

        movzx   bx, bh          ; Get the active page number
        shl     bx, 1           ; Calculate word offset to page in cursor table
        mov     dx, v_crpos[bx] ; Get the cursor pos from the cursor table
        mov     uedx, dx        ; Set to be sent to user
        mov     cx, v_crshp     ; Get the shape from the RBDA
        mov     uecx, cx        ; Set to be returned when regs are restored
        jmp     v_exit          ; Exit from the interrupt routine
v03r    endp


    SUBTTL  FUNC 04 - READ LIGHT PEN

;    +-------------------------------+
;    |   FUNC 04 - READ LIGHT PEN    |
;    +-------------------------------+

; This function is not supported


    SUBTTL  FUNC 05 - SET DISPLAY PAGE

;    +-------------------------------+
;    |  FUNC 05 - SET DISPLAY PAGE   |
;    +-------------------------------+

;------------------------------------------------------------------------------
;Function:      Set Active Video Page
;Function ID:   05h
;
;Entry:         AH = 05h
;               AL = Page number specification
;
;Exit:          None
;
;Notes:         Sets RBDA w 40:4eh, Offset to active page
;                         b 40:62h, Active Page Number
;
;------------------------------------------------------------------------------

        ALIGN   4
v05r    proc    near

        mov     al, b ueax      ; Get the specified page id

        movzx   bx, b v_mode      ; Get the current mode id
        and     bl, 07h         ; Make sure it's legal
        cmp     al, v_pgmax[bx] ; Is it bigger than max
        jg      short v05_exit  ; If so ignore it

        mov     v_actpg, al     ; Set the RBDA to the new active page number
;R99    movzx   bx,al           ; save active page

        mul     w v_pgsze       ; Page number x page len is offset
        mov     v_pgoff, ax     ; and set the RBDA
        shr     ax,1            ; adjust ax to byte offset ;RKKS
        mov     cl,12           ; set 6845 index to 12 ;RKKS
        call    set_6845        ; set 6845 ;RKKS

;R99        shl     bx, 1           ; Calculate word offset to page in cursor table
;R99        mov     ax, v_crpos[bx] ; Get the cursor pos from the cursor table
;R99        movzx   bx, al          ; save column
;R99        mov     al, v_cols      ; columns per row
;R99        mul     ah              ; chara/row * row
;R99        add     ax, bx          ; total chara
;R99        shl     ax, 1           ; chara + attrib
;R99        add     ax, v_pgoff     ; add page offset base
;R99        shr     ax, 1
;R99        mov     cl, 14
;R99        call    set_6845

v05_exit:
        jmp     v_exit          ; Exit from the interrupt routine
v05r    endp

    SUBTTL  FUNC 06 - SCROLL UP 
    PAGE

;    +-----------------------+
;    |  FUNC 06 SCROLL_UP    |
;    +-----------------------+
;
;------------------------------------------------------------------------------
;Function:      Scroll active page up
;Function ID:   06h
;
;Entry:         AH = 06h
;               AL = Number of lines to scroll
;               BH = Color for Attribute of scrolled lines ( Text Only )
;               CX = Row, Col of Upper Reft Corner of box to be scrolled
;               DX = Row, Col of Lower Right Corner of box to be scrolled
;
;Exit:          None
;
;Notes:
;
;------------------------------------------------------------------------------

        ALIGN   4
v06r    proc    near

; Calculate target and source offsets
        mov     al, ch          ; upper row
        mul     b v_cols        ; upper_row * v_col in ax
        movzx   bx, cl          ; left column
        test    b v_mreg, m_graphics ;
        jnz     short v06_1_3   ; If we're in text mode, go
        add     ax, bx          ; (upper_row * v_col) + left_column
        shl     ax, 1           ; convert to byte offset
        jmp     v06_1_9         ; If we're in text mode, go
v06_1_3:
        shl     ax, 2           ; [456] (ROWulc x v_col) * 4
        add     ax, bx          ; [45] (ROWulc x v_col) * 4 + COLulc
        test    b v_mreg, m_bitsize ;
        jnz     short v06_1_9   ; Go if in mode 6
        shl     ax, 1           ; [45] (ROWulc x v_col) * 4 + COLulc) * 2
v06_1_9:
        mov     di, ax          ; and set the destination pointer

; Calculate initial si setting
        mov     al, b ueax      ; Get the number of rows to blank
        mul     b v_cols        ; x nmbr of chars / line
        shl     ax, 1           ; x 2 for byte offset (all text modes)
        test    b v_mreg, m_graphics ; If in text modes, we're done
        jz      short v06_2_1   ;
        shl     ax, 1           ; x 2 again (mode 6)
        test    b v_mreg, m_bitsize  ; If we're in mode 6
        jnz     short v06_2_1   ; or
        shl     ax, 1           ; x 2 again for all other graphics modes
v06_2_1:
        add     ax, di          ; + target base = source base
        mov     si, ax

; Get the number of mov bytes each line,
        sub     dl, cl          ; Last char - first char
        inc     dl              ; + 1 is the word mov count each line
        test    b v_mreg, m_bitsize ; We're done if in mode 6
        jnz     short v06_3_1   ;
        shl     dl, 1           ; Convert to byte count
; Get the number of characters to step "between lines"
v06_3_1:
        mov     bx, v_cols      ; Get the number of chars / col
        test    b v_mreg, m_bitsize ; If in mode 6
        jnz     short v06_4_1   ;  go
        shl     bx, 1           ;
v06_4_1:
;R04    sub     bl, dl          ; bx is the count to step each pointer
                                ; to begin the next move

; This is the entry point for scroll down and all code from here to the
; end of the routine must work for scrolling either up or down.

v06_shared:
; Set the segment registers for the moves
        mov     ax, v_pgoff     ; Get the byte offset to the current page
        shr     ax, 2           ; Divide by 4 to get segments
        add     ax, c_bloc      ; Add the seg address of mono buffer
        cmp     v_port, v_cadapt ; Is this a color adapter
        je      short v06_5     ;
        sub     ax, c_bloc - m_bloc ; Step to mono buffer
v06_5:
        mov     es, ax          ; Set target
        mov     ds, ax          ; and source seg registers
; Calculate the number of lines to move
        sub     dh, ch          ; Last row - first row
        inc     dh              ; +1 is the max number of lines to move
;R04        cmp     dh, b ueax      ;;RKKS is max window lines less than lines to scroll 
;R04        ja      short v06_5_0   ;;RKKS go to blanking routine
;R04        mov     b ueax, 0       ;;RKKS setflag to blanking screen
;R04v06_5_0:
;R04        sub     dh, b ueax      ; - number of lines to blank
;R04        test    b v_mreg, m_graphics      ; If not in graphics,
;R04        jz      short v06_5_1   ;    we're done
;R04        shl     dh, 2                   ; In graphics, it's 4 lines each char
;R04v06_5_1:
        cld                     ; Clear the direction flag

; If in text mode, use a word length move during the horizontal retrace
; blanking period.  Otherwize, go use a byte length move any old time

        test    b v_mreg, m_graphics      ; Go, if graphics bit
;R04        jnz     short v06_30              ; is on

        jz      short v06_5_0   ; R04 is not graphic
        cmp     dh, b ueax      ; R04 is max window lines less than lines to scroll 
        jbe     v06_40 		; R04 go to blanking routine
        sub     dh, b ueax      ; R04 - number of lines to blank
        shl     dh, 2           ; R04 In graphics, it's 4 lines each char
        jmp     short v06_30    ; R04 go graphics
v06_5_0:			; R04

; Move the text buffer
        shr     dl, 1           ; Convert the byte count to a word count
                                ; Text can work in two byte chunks
;  If the line cnt in al = 0, just blank the space
        cmp     b ueax, 0       ;
        jz      short v6_20     ; Go directly to blanking routine
        cmp     dh, b ueax      ; R04 is max window lines less than lines to scroll 
        jbe     short v6_20     ; R04 go to blanking routine
        sub     dh, b ueax      ; R04 - number of lines to blank

; This loop moves entire area to be moved
v6_10:
        movzx   cx, dl          ; Get the number of words to move on each line
        push    di              ; R04 save di
        push    si              ; R04 save si

; This loop moves 1 line
v6_11:
;R06        cli                     ; Turn off the interrupts
;R06        call    blnk            ; Go wait for horizontal retrace
        movsw
        dec     cx              ; Are we done?
        jz      short v6_13     ; If so, get out
        movsw
        dec     cx              ; Are we done?
        jz      short v6_13     ; If so, get out
        movsw                   ; If not, move another char/attrib pair
        sti                     ; and restart the interrupts
;R06- start
        cmp     b v_mode, 7     ; If this is mono,
        je      short v6_111    ; Skip the Snow test
        cli                     ; Turn off the interrupts
        call    blnk            ; Go wait for horizontal retrace
v6_111:				;R06
;R06 - end
        loop    short v6_11
v6_13:

        pop     si              ; R04 restore si
        pop     di              ; R04 restore di

        add     si, bx          ; Step source and target to the next line
        add     di, bx
        dec     dh              ; Drop the line count
        jnz     short v6_10     ; Go if more lines to move
v6_19:
        mov     ah, b ueax      ; Get count for the number of lines to blank
        cmp     ah, 0           ; For a zero blank count, its already in dh
        jz      short v6_20
        mov     dh, ah
v6_20:                          ; For a zero blank count, its already in dh
        cmp     dh,0            ; R04 are there any line to move
        jz      short v6_29     ; R04 no exit

        mov     ah, b uebx + 1  ; Get the attribute for the blank area
v6_21:
        movzx     cx, dl        ; Get the number of chars to clear each line
        push    di              ; R04 save di
v6_22:
;R06        cli                     ; Turn off the interrupts
;R06        call    blnk            ; Go wait for horizontal retrace
        stosw                   ; Clear a char/attrib pair
        dec     cx              ; Are we done?
        je      short v6_25     ; Yes, stop clearing
        stosw                   ; Clear a char/attrib pair
        dec     cx              ; Are we done?
        je      short v6_25     ; Yes, stop clearing
        stosw                   ; Clear a char/attrib pair
        dec     cx              ; Are we done?
        je      short v6_25     ; Yes, stop clearing
        stosw                   ; Clear a char/attrib pair
        dec     cx              ; Are we done?
        je      short v6_25     ; Yes, stop clearing
        stosw                   ; If not, sneak in another clear
        sti                     ; and restart the interrupts
;R06- start
        cmp     b v_mode, 7     ; If this is mono,
        je      short v6_222    ; Skip the Snow test
        cli                     ; Turn off the interrupts
        call    blnk            ; Go wait for horizontal retrace
v6_222:				;R06
;R06 - end
        loop    v6_22           ; Continue until the line is complete
v6_25:
        pop     di		;R04
;R04        add     si, bx          ; Step source and target to the next line
        add     di, bx
        dec     dh              ; Drop the line count
        jnz     short v6_21     ; Go if more lines to clear
v6_29:
v06_exit:
        jmp     v_exit          ; Exit from the interrupt routine


        page
; This area performs the graphics moves and clears
v06_30:
        mov     al, ueax + 1      ; scroll down or up
        mov     bx, 80
        cmp     al, 06h
        je      short v06_30_1
        neg     bx
v06_30_1:
;R99        cmp     bx, 0           ; If we are working with a scroll down,
;R99        jg      v06_35          ;
;R99        add     si, 80 * 3      ; move the graphic pointers to point at the
;R99        add     di, 80 * 3      ; last row of the character in the buffer
v06_35:
        mov     ah, b ueax      ; Get the user specified move count
        cmp     ah, 0           ; If zero, the entire area is to be cleared
        je      short v06_40    ; and the move count is the clear count
                                ; so skip the move routine
; The graphics move routines
v6_15:
        push    si              ; Save the initial pointers
        push    di              ;

        call    v06_mov         ; Call a closed subroutine to do the move

        pop     di              ; Step to the second or odd block
        add     di, 2000h       ;
        pop     si              ;
        add     si, 2000h       ;

        call    v06_mov         ; Move the bits in second block

        sub     di, 2000h       ; Step output pointer back to upper block

; The graphics clear routines
        mov     dh, b ueax      ; Get the user specified # lines to clear
        shl     dh, 2           ; x 4 for graphics work
v06_40:
        push    di              ; Save the output pointer
        mov     al, b uebx+1    ; R04 get attribute

        call    v06_clr         ; Call the clear routine for upper block

        pop     di              ; Get original pointers
        add     di, 2000h       ;  and step to lower block

        call    v06_clr         ; Go clear the bytes

        jmp     v06_exit        ; We're done -- leave

v06r    endp


; The move graphics area routine
        ALIGN   4
v06_mov proc    near            ; Internal proc to move graphic bits
        mov     ah, dh          ; Save the count
v06_mov_1:
        movzx   cx, dl          ; Set a count for rep
        push    di
        push    si

        rep movsb               ; move a line

        pop     si
        pop     di

        add     si, bx          ; Step to next line
        add     di, bx          ;

        dec     ah
        jnz     short v06_mov_1 ; Loop until entire area moved

        ret
v06_mov endp

; The clear graphics area routine
        ALIGN   4
v06_clr proc    near            ; Internal proc to clear graphic area
        mov     ah, dh          ; Save the orig count
;R04        xor     al, al          ; Clear the byte to be stored
v06_clr_1:
        movzx   cx, dl          ; Set a count for rep
        push    di
        push    si

        rep stosb               ; move a line

        pop     si
        pop     di

        add     di, bx          ; Step ( = or - ) to next line

        dec     ah              ; Drop the line count
        jnz     short v06_clr_1 ; Loop until entire area cleared

        ret
v06_clr endp


    SUBTTL  FUNC 07 - SCROLL DOWN
    PAGE

;    +-----------------------+
;    |  FUNC 07 SCROLL  DOWN |
;    +-----------------------+

;------------------------------------------------------------------------------
;Function:      Scroll Active Page Down
;Function ID:   07h
;
;Entry:         AH = 07h
;               AL = Number of lines to scroll
;
;Exit:          None
;
;Notes:
;
;------------------------------------------------------------------------------

        ALIGN   4
v07r    proc    near

; Calculate target and source offsets
;R04        movzx   ax, dh          ; ROWulc
        mov     al, dh          ; R04 ROWulc
        mul     b v_cols        ; ROWulc * v_col
;R04        movzx   bx, cl          ; Get the character offset to 1st char
        movzx   bx, dl          ; R04 Get the character offset to 1st char
        sub     dl, cl          ; R04 Last char - first char
        test    b v_mreg, m_graphics ;
        jnz     short v07_1_3   ; If we're in graphics, go
        add     ax, bx          ; (ROWulc * v_col) + COLulc
        shl     ax, 1           ; convert to byte offset
        movzx   bx, dl          ; R04 save dl
        shl     bx, 1           ; R04 convert to byte offset
        sub     ax, bx          ; R04 adjust to the begining of the line          
        jmp     short v07_1_9   ; Go set di
v07_1_3:
        shl     ax, 2           ; [456] (ROWulc x v_col) * 4
        add     ax, bx          ; R04 [456] (ROWulc x v_col) * 4 + COLulc
        movzx   bx, dl          ; R04 extend to word size
        sub     ax, bx          ; R04 subtract window size
        test    b v_mreg, m_bitsize ;
        jnz     short v07_1_7   ; Go if in mode 6
;R04        add     ax, bx          ; [45] (ROWulc x v_col) * 4 + COLulc
        shl     ax, 1           ; [45] (ROWulc x v_col) * 4 + COLulc) * 2
;R04        jmp     short v07_1_9
v07_1_7:
;R04        add     ax, bx          ; [6]  (ROWulc x v_col) * 4 ) + COLulc
        add     ax, 0F0h        ; R04 adjust offset for scroll down
v07_1_9:
        mov     di, ax          ; and set the destination pointer

; Calculate initial si setting
;R04        movzx   ax, b ueax      ; Get the number of rows to blank
        movzx   ax, b ueax      ; Get the number of rows to blank;R04A
        mul     b v_cols        ; x nmbr of chars / line
        test    b v_mreg, m_bitsize  ; If we're in mode 6
        jnz     short v07_2_0        ;  or
        shl     ax, 1           ; x 2 for byte offset
        test    b v_mreg, m_graphics ; If in text modes, we're done
        jz      short v07_2_1   ;
v07_2_0:
        shl     ax, 2           ; Times 4 for graphics modes
v07_2_1:
        neg     ax              ;
        add     ax, di          ; + target base = source base
        mov     si, ax

; Get the number of mov bytes each line,
;R04        sub     dl, cl          ; Last char - first char
        inc     dl              ; + 1 is the word mov count each line
        test    b v_mreg, m_bitsize ; We're done if in mode 6
        jnz     short v07_3_1   ;
        shl     dl, 1           ; Convert to byte count

; Get the number of characters to step "between lines"
v07_3_1:
        mov     bx, -80         ; Step one line
        test    b v_mreg, 01    ; In 80 col text modes, the line is 160
        jz      short v07_3_3   ; bytes long, so for modes 2, 3 and 7
        sub     bx, 80          ; go back another 80 bytes
v07_3_3:
;R04        sub     bl, dl          ; plus the move length
        jmp     v06_shared      ; Go to code shared with scroll up
v07r    endp


    SUBTTL  FUNC 08 - READ CHARACTER/ATTRIBUTE

;    +---------------+
;    |    FUNC 08    |
;    +---------------+

;------------------------------------------------------------------------------
;Function:      Read Character and attribute
;Function ID:   08h
;
;Entry:         AH = 08h
;               bh = page number
;
;Exit:          None
;               AL = character at location specified by v_crpos in page
;                    specified by bh
;               AH = Character attribute ( Undefined for graphics modes )
;
;Notes:
;
;
;------------------------------------------------------------------------------

        ALIGN   4
v08r    proc    near            ; Read character and attribute from current crsr
                                ; position - both text and graphics modes
        test    b v_mreg, m_graphics ; If this is graphics mode
        jnz     short v08_10    ; go to the graphics routines

; The text modes are processed here

        call    gcp             ; Get the current cursor position for page in bh

;R06- start
        cmp     b v_mode, 7     ; If this is mono,
        je      short v08_51    ; Skip the Snow test
;R06 - end
v08_5:
        cli                     ; Turn off the interrupts
        call    blnk            ; Wait for blanked screen
v08_51:				;R06
        mov     ax, es:[di]     ; Gets both the character and the attribute
        sti                     ; Start the interrupts again

        mov     w ueax, ax      ; Save to be set on exit from int 10h

v08_exit:
        jmp     v_exit          ; Exit from the interrupt routine
        page
; The grapics modes are processed here
; Set gs:di to point at the graphical representation of the character in the
; buffer

v08_10:
        mov     gs, v_blocs     ; Set GS to the CGA buffer location

        movzx   ax, b v_crpos + 1 ; Get the target row number
        mov     bx, 4 * 80      ; There are 80 bytes and 4 rows in each text row
        mul     bx              ; ax beginning of target row
        movzx   bx, b v_crpos   ; Get the character offset in the row
        add     ax, bx          ; Step to char for mode 6
        test    b v_mreg, m_bitsize ; If in mode 6, ax is char position
        jnz     short v08_15
        add     ax, bx          ; For modes 4 and 5, ax is character position
v08_15:
        mov     di, ax          ; Set gs:di to point at the character

; Look for the character at gs:di in the tables pointed to by es:si

;RKKS        les     si, l_gchar     ; Pointer to the primary character table
        mov     si, offset ES:DOUBLE_DOT     ; Pointer to the primary character table

        call    cscn            ; Go scan the table for a match to gs:di

        cmp     ah, 0           ; If zero, al = char, bh is the attribute
        jne     short v08_28    ; go set up to return to the caller
                                ; Otherwise scan the alternate table
v08_25:
        mov     ah, bh          ; Put the attribute in ah
v08_27:
        mov     ueax, ax        ; and set to be returned to the caller
        jmp     v08_exit        ; and go back to the caller

; Scan the alternate table if it exists
v08_28:
        mov     ax, 0           ;
        mov     es, ax          ; Set es to point at 0
        les     si, es:v_echrs  ; es:si points to the extended character table
        mov     ax, es          ; If it doesn't exist, es:si is zero
        add     ax, si          ;
        jz      short v08_30    ; No alternate table -
                                ; treat as no character found - set a nul exit

        call    cscn            ; Go scan the alternate table

        add     al, 128         ; Step to compensate for alternate table
        cmp     ah, 0           ; If ah = 0, we found it
        je      short v08_25    ;

; Character not in tables, return a nul character and attribute 0, 0
v08_30:
        mov     ax, 0           ; Set ax to nuls
        jmp     v08_27          ;  and go set up for the user

v08r    endp
;RD_AC_CUR  ENDP


;    +---------------+
;    | FUNC 09       |
;    +---------------+

;------------------------------------------------------------------------------
;Function:      Write Character and attribute
;Function ID:   09h
;
;Entry:         AH = 09h
;               AL = character to be written
;               bh = page number
;               bl = attribute in text mode, fg color if supported in graphics
;               cx = count of characters to be written
;
;Exit:          None
;
;Notes:
;
;
;------------------------------------------------------------------------------

        ALIGN   4
v09r    proc    near

        test    b v_mreg, m_graphics ; If we're in graphics mode, v09 and v0a
        jnz     short v0a_10         ; process the command identically - use v0a

        call    gcp             ; Get the current cursor position for page in bh
                                ; Note that the 6845 and RBDA are both updated
        mov     ah, b uebx      ; Get the character attribute from input bl
        mov     al, b ueax      ;  and the character from user's al

        mov     cx, uecx        ; Get the user spec'd count
        cmp     cx, 0           ; Check to be sure the count is really set
        je      short v09_exit  ; If not, quit before disaster

;R06        cmp     b v_mode, 7     ; If this is mono,
;R06        je      short v09_5     ; Go display the character
;R06- start
        cmp     b v_mode, 7     ; If this is mono,
        je      short v09_51    ; Skip the Snow test
;R06 - end

; The following sequence can cause snow if cx is large
v09_5:
        cli                     ; Turn off the interrupts
        call    blnk            ; Wait for screen to blank
v09_51:				;R06
      rep  stosw                ; note that es:di was set by gcp

        sti                     ; Turn the interrupts on again

        jmp     v09_exit        ;

v09_10:                         ; Code for inserting graphics char goes here

v09_exit:
        jmp     v_exit          ; Exit from the interrupt routine
v09r    endp


;    +---------------+
;    | FUNC 0A       |
;    +---------------+

;------------------------------------------------------------------------------
;Function:      Write Character Only
;Function ID:   0ah
;
;Entry:         AH = 0ah
;               AL = character to be written
;               bh = page number
;               cx = count of characters to be written
;
;Exit:          None
;
;Notes:
;
;------------------------------------------------------------------------------

        ALIGN   4
v0ar    proc    near

        test    b v_mreg, m_graphics ; If we're in graphics mode, v09 and v0a
        jnz     short v0a_10         ; are identical - both use this routine

        call    gcp             ; Get the current cursor position for page in bh
                                ; Note that the 6845 and RBDA are both updated
        mov     al, b ueax      ; Get the user character

        mov     cx, uecx        ; Get the char count
        cmp     cx, 0           ; Check to be sure the count is really set
        je      short v0a_exit  ; If not, quit before disaster

        cmp     b v_mode, 7     ; Is this mono mode?
;R06        je      short v0a_3     ; If so, just display the character
        je      short v0a_5     ; If so, just display the character	;R06

; For CGA, wait for a blank screen then insert the character(s)

v0a_3:
        cli                     ; turn off the interrupts
        call    blnk            ; Wait for the screen to blank
v0a_5:
;R07        inc     si              ; Step over the attribute
        stosb                   ; note that es:di was set by gcp
        inc     di              ; Step over the attribute	;;R07

        loop    v0a_5           ; Loop until count exhausted

        sti                     ; Turn the interrupts on
        jmp     v0a_exit        ;

v0a_10:                         ; Code for inserting graphics char goes here
        mov     al, b ueax      ; Get the character to be displayed
        call    wrgc            ; Call the graphics character write routine

v0a_exit:
        jmp     v_exit          ; Exit from the interrupt routine
v0ar    endp


    SUBTTL  FUNC 0B - SET COLOR PALETTE

;    +-------------------------------+
;    |  FUNC 0B - SET COLOR PALETTE  |
;    +-------------------------------+

;------------------------------------------------------------------------------
;Function:      Set Color Palette, Background Color or Border Color
;Function ID:   0bh
;
;Entry:         AH = 0bh
;               BH = 0    ( BH is Subfunction )
;               Modes 0 - 3;    bl, 0-3 = border color ( 0 - 15 )
;                               bl, 4   = 0 Blinking Option
;                                       = 1 Intensified Background Option
;               Modes 4, 5;     bl      = Background color ( 0 - 15 )
;               Modes 6         bl      = Foreground color ( 0 - 15 )
;               BH = 1
;               Modes 4,5 Only; bl      = 0 Foreground green/red/brown
;                                       = 1 Foreground cyan/magenta/white
;
;Exit:          Colors, borders, etc, set on color board
;
;Notes:
;
;------------------------------------------------------------------------------

        ALIGN   4
v0br    proc    near            ; Set color palette, border or background

        cmp     b v_mode, 07h   ; This function does not operate
        je      short v0b_exit  ; in mono mode
        mov     dx, v_port      ; Get the color adapter basic port address
        add     dx, 5           ; Step to the color select port
        mov     al, v_cpal      ; Get the last setting of the color select port

        test    bh, 1           ; If this is subfunction one,
        jnz     short v0b_10    ; Go

        and     al, 0f0h        ; Clear the low order 4 bits
        and     bl, 0fh         ; Clear all but low order 4 bits in bl
        or      al, bl          ; Set the new color select value
        jmp     v0b_20
v0b_10:
        test    b v_mreg, m_graphics ; If we're not in graphics, ignore
        jz      short v0b_exit       ; the request
        test    b v_mreg, m_bitsize  ; If we're in 640 bit mode , ignore
        jnz     short v0b_exit       ; the request
        and     al, 0dfh        ; Clear all but the blue bit
        test    bl, 01h         ; If caller wants to clear the bit,
        jz      short v0b_20    ; Go do it
        or      al, 20h         ; Otherwise, set the cyan/magenta/white palette
v0b_20:
        out     dx, al          ; and set the register
        mov     v_cpal, al      ; Save for later use
v0b_exit:
        jmp     v_exit          ; Exit from the interrupt routine

v0br    endp


    SUBTTL  FUNC 0C - WRITE PIXEL DOT

;    +---------------------------------------+
;    |  FUNC 0C - WRITE PIXEL DOT            |
;    +---------------------------------------+

;------------------------------------------------------------------------------
;Function:      Write or Exclusive Or a Pixel to the specified location
;Function ID:   0ch
;
;Entry:         AH = 0ch
;               AL = Pixel to be inserted or XOR'd
;                  = If 7 bit is set, XOR instead of insert
;               BH = page number ( ignored )
;               CX = Column Number
;               DX = Row number
;
;Exit:          Pixel displayed or XOR action taken
;
;Notes:         The CGA only supports a single page in modes that allow
;               allow pixel updating.  Therefore, page number ( BH )is ignored.
;
;------------------------------------------------------------------------------

        ALIGN   4
v0cr    proc    near            ; Write a pixel

        call    gpl             ; Go get the address and mask for mods

        mov     bx, ueax        ; Get the user spec'd color
        and     bx, 03h         ; Clear all but the 2 bits of color

        test    b v_mreg, m_bitsize ; If we're in 320, the field is correct
        jz      short v0c_5     ; Go do the operation
        and     bx, 01h         ; If we're in 640, use only 1 bit of color
v0c_5:
        shl     bx, 1           ; Change bx to word displacement
        test    b ueax, 80h     ; Is the 7 bit on?
        jnz     short v0c_10    ; If so, go do an XOR
        mov     ax, [bx+si]     ; Get the mask and positioned color bits
        and     es:[di], al     ; Clear the bits in memory
        or      es:[di], ah     ; and set them
        jmp     v0c_30          ; We're done
v0c_10:
        mov     al, 1[bx+si]    ; Get the bits to XOR
        xor     es:[di], al     ; and do it
v0c_30:
        jmp     v_exit          ; Exit from the interrupt routine
v0cr    endp


    SUBTTL  FUNC 0D - READ PIXEL DOT

;    +---------------------------------------+
;    |  FUNC 0D - READ PIXEL DOT             |
;    +---------------------------------------+

;------------------------------------------------------------------------------
;Function:      Read Pixel
;Function ID:   0dh
;
;Entry:         AH = 0dh
;               BH = page number ( ignored )
;               CX = Column Number
;               DX = Row number
;
;Exit:          AL = pixel color at specified location
;
;Notes:         The CGA only supports a single page in modes that allow
;               allow pixel updating.  Therefore, page number ( BH )is ignored.
;
;------------------------------------------------------------------------------


        ALIGN   4
v0dr    proc    near            ; Read a pixel

        call    gpl             ; Go convert to pixel location in buffer

        mov     al, [si]        ; Get the mask for insertion
        xor     al, 0ffh        ; Change to mask for extraction
        mov     ah, al          ; Save it for later manipulation
        and     al, es:[di]     ; Get the bits
v0d_10:
        test    ah, 01h         ; Are the mask bits in the least sig. portion?
        jnz     short v0d_20    ; If so, we're done
        shr     ax, 1           ; Shift the mask and color bits right
        jmp     v0d_10          ;  and go test again
v0d_20:
        mov     ueax, al        ; And put the value in user's al for return
        jmp     v_exit          ; Exit from the interrupt routine
v0dr    endp

;    +-----------------------+
;    |  FUNC 0E - WRITE TTY  |
;    +-----------------------+

;------------------------------------------------------------------------------
;Function:      Write Character in TTY mode
;Function ID:   0eh
;
;Entry:         AH = 0eh
;               AL = character to be written
;               bl = foreground color ( in graphics modes only )
;
;Exit:          v_crpos updated, character displayed or action taken
;
;Notes:
;
;------------------------------------------------------------------------------

        ALIGN   4
v0er    proc    near

; This routine always writes to the active page.  The number provided by the
; caller is ignored.

        movzx   bx, b v_actpg   ; Get the active page number
        shl     bx, 1           ; x 2 to become word offset
        mov     dx, v_crpos[bx] ; v0e uses the crsr in dx -- v_crpos updated
                                ; by int 10h 02h on exit from v0e.
        mov     bh, bl          ; Convert bl back to page id
        shr     bh, 1           ; bh is the active page number
        mov     bl, b uebx      ; Get the graphics foreground color

        mov     al, b ueax      ; Get the input character
        mov     ah, 0           ; Set ah to indicate no attribute in text mode

        call    dsp             ; Call the display routine

        jmp     v_exit          ; and return to caller

v0er    endp


    SUBTTL  FUNC 0F - RETURN VIDEO STATE

;    +---------------------------------------+
;    |     FUNC 0F - RETURN VIDEO STATE      |
;    +---------------------------------------+

;------------------------------------------------------------------------------
;Function:      Get Video Status
;Function ID:   0Fh
;
;Entry:         AH = 0Fh
;
;Exit:          AH = Number of characters/columns
;               AL = Display Mode
;               BH = Active Page Number
;
;Notes:         AH <- 40:4b
;               AL <- 40:49
;               BH <- 40:62
;------------------------------------------------------------------------------

        ALIGN   4
v0fr    proc    near

        mov     ax, v_cols - 1  ; Get the number of cols into ah
        mov     al, v_mode      ; Get the mode into al
        mov     w ueax, ax      ; and set to have returned when reg's restored
        mov     bh, v_actpg     ; put the active page number in bh
        mov     b uebx + 1, bh  ; and set to send back

        jmp     v_exit          ; Exit from the interrupt routine
v0fr    endp


    SUBTTL  FUNC 13H - WRITE STRING

;    +-------------------------------+
;    |    FUNC 13H - WRITE STRING    |
;    +-------------------------------+

;------------------------------------------------------------------------------
;Function:      Write TTY Strings
;Function ID:   13h
;
;Entry:         AH = 13h
;               AL = Mode
;                    00 - Write characters with attribute from bl  ignore crsr
;                    01 - Write characters with attribute from bl, update crsr
;                    02 - Write characters/attributes from string, ignore crsr
;                    03 - Write characters/attributes from string, update crsr
;               BH = Page Specification
;               BL = Attribute for modes 0, 1
;               CX = Number of chars or char/attrib pairs in buffer
;               DX = Row and Column
;               es:bp = Location of input string
;
;Exit:
;
;Notes:
;------------------------------------------------------------------------------

        ALIGN   4
v13r    proc    near

; Set up input pointers
        mov     ax, ues         ; ;RKKS Get base reg for input data
        mov     gs, ax          ; gs:si will be input pointer
        mov     ax, w uebp      ; Bp had location offset when we started
        mov     si, ax          ;

        test    b ueax, 01h     ; If zero, reset the cursor when
        jnz     short v13_02    ; If nz, cursor will be ok when done
        movzx   bx, b v_actpg   ; Get the active page id
        shl     bx, 1           ; Change to word offset
        mov     bx, v_crpos[bx] ; Save the old cursor value
        push    bx
v13_02:
        mov     bl, b uebx      ; R04 Get the specified attribute
        call    ncp1            ; Go normalize the cursor in dx

        mov     cx, uecx        ; Get the message length

v13_03:
        mov     al, gs:[si]     ; Get the character
;R04        mov     bl, b uebx      ; Get the specified attribute
        inc     si              ; Step to next char or attribute

;R04        test    b ueax, 20h     ; If mode 0 or 1, we're done
        test    b ueax, 10b     ; R04 If submode 0 or 1, we're done
        jz      short v13_05
        mov     bl, gs:[si]     ; If mode 2 or 3, we need attribute from string
        inc     si              ; Step over attribute to next character

v13_05:
        push    cx              ; Save the count
        mov     ah, 1           ; Set to tell dsp to use a text attribute
        mov     bh, b uebx + 1  ; Set the page number
        call    dsp             ; Call the display tty char routine

        pop     cx              ; and restore the count

v13_10:
        loop    v13_03          ; Continue until cx is zero

        test    b ueax, 01h     ; Did user want cursor unchanged?
        jnz     short v13_20
        pop     dx              ; If user wants cursor unchanged, change it
        mov     bh, v_actpg     ; back to where we found it
        mov     ah, 02h         ;
        int     10h             ; Go reset cursor

v13_20:
        jmp     v_exit          ; and then go back

v13r    endp


    SUBTTL  CGA SUB ROUTINES

;------------------------------------------------------------------------------
;Name:          BLNK - a strange little routine to prevent snow on the screen
;Function:      Waits until a blank period caused by vertical or horizontal
;               retrace is beginning, then returns control to caller
;
;Function ID:   This is an internal routine without a function id
;
;Entry:         None
;
;Exit:          No registers modified
;
;Notes:         Interrupts should be disabled before calling BLNK
;
;------------------------------------------------------------------------------
        ALIGN   4
blnk    proc    near

        push    ax              ; Save ax and dx
        push    dx

        mov     dx, v_port      ; Get the current video port
        add     dx, 6           ; Step from 3x4 to 3xA
blnk_01:
        in      al, dx          ; Get the video port status register
        test    al, 01h         ; If the one bit is on, the screen is
        jnz     short blnk_01   ; blank, wait for the blank to quit
blnk_02:
        in      al, dx          ; Now the video is on, wait for
        test    al, 01h         ; blanking to start again.  This way we
        jz      short blnk_02   ; return control at beginning of blanked
                                ; period

                                ; Screen is now blank
        pop     dx              ; Restore dx
        pop     ax              ;    and ax

        ret                     ; Go back to user

blnk    endp

;------------------------------------------------------------------------------
;Name:          GCP - Get Cursor position
;Function:      Gets Cursor Position for inserting or reading buffer
;
;Function ID:   This is an internal routine without a function id
;
;Entry:         BH = Page number for cursor selection
;               RBDA, v_crpos, the bh entry specs the cursor
;
;Exit:          ES:DI = Attribute location for char specified in rbda v_crpos
;               6845 updated to loc specified by v_crpos if active page in bh
;
;Notes:         This routine is used by v09, v0a, and v0e to obtain es:di
;               indicating the character to be set.  Hopefully, it can be used
;               by other routines before we're done.
;
;------------------------------------------------------------------------------

        ALIGN   4
gcp     proc    near    ; Internal routine for video bios

        push    bx
; Calculate the offset from the beginning of the buffer
        movzx   bx, bh          ; get the page number
        shl     bx, 1           ; by two to get the offset in the page crsr tab
gcp03:
        mov     ax, v_crpos[bx] ; Get the proper cursor for the page number

        pop     bx              ; Restore page number to bh
        call    gcp1            ; Go convert to video buffer offset in es:di

gcp_exit:
        ret

gcp     endp

        ALIGN   4
gcp1    proc    near            ; Calculates es:di for row, col in ax

        push    dx
        push    cx
        push    bx

        mov     cx, ax          ; Save the cursor position
        movzx   ax, ch          ; Get the row number in ax
        mul     b v_cols        ; mult by chars per row
        movzx   cx, cl          ; Get col number
        add     ax, cx          ; = The word displacement within the page
        shl     ax, 1           ; R03 Convert offset in ax from word to byte

gcp1_1:
        cmp     bh, 0           ; Are we at page 0
        jz      short gcp1_2
        add     ax, v_pgsze     ; Step to next page
        dec     bh              ; Reduce page count
        jmp     gcp1_1          ; Continue until page count exhausted
gcp1_2:
        mov     cx, c_bloc      ; Get the location of the cga video buffer
        cmp     v_port, 03d4h   ; If the port is CGA,
        je      short gcp1_3    ;   we have the correct buffer address in cx
        mov     cx, m_bloc      ; Else change to the the mono video buffer
gcp1_3:
        mov     es, cx          ; Set es for the caller
;R03    shl     ax, 1           ; Convert offset in ax from word to byte
        mov     di, ax          ; and set di

gcp1_exit:
        pop     bx
        pop     cx
        pop     dx

        ret

gcp1    endp

;------------------------------------------------------------------------------
;Name:          Set_6845
;Function:      Set 6845 Registers
;
;Entry:         AX = Value to be programed
;               CL = start index
;
;Exit:          None
;
;Notes:
;
;------------------------------------------------------------------------------
            Align   4
set_6845    proc    near

        push    cx              ; Save the working regs
        push    dx

        xchg    cl, al          ; Save low byte in cl and set index in al
        mov     dx, v_port      ; Get location of display adapt reg pointer
        out     dx, ax          ; and set the 6845 from the hi bits in ah - row
        mov     ah, cl          ; Get the low bits
        inc     al              ; Step pointer to low cursor address (R15)
        out     dx, ax          ; and set the low order- col
        mov     al, cl          ; Restore al

        pop     dx              ; Restore the working regs
        pop     cx              ;

        ret

set_6845    endp

;------------------------------------------------------------------------------
;Name:          S45 - Sets Grapics characters in video buffer for modes 4 and 5
;Function:      Moves 8 bytes from gs:si to the proper areas of video
;               buffer adjusting for color etc as we go along
;
;Function ID:   This is an internal routine without a function id
;
;Entry:         gs:si = pointer to the bytes to be inserted
;               es:di = pointer to the first character position in upper block
;                       of the video buffer
;               bl    = Foreground or char color ( 80h is the XOR bit )
;               cx    = The number of times to insert the character
;
;Exit:          The specified character has been displayed the specified
;               number of times
;
;Notes:         If character pointer crosses the end of a line, junk comes out
;
;------------------------------------------------------------------------------

        Align   4
s45     proc    near   ; Writes graphic chars to video buffer for modes 4 and 5

        push    dx              ; Save the cursor
        cmp     cx, 0           ; If count is zero, forget it
        je      short s45_exit  ; quit

        mov     dl, bl          ; Save the color and XOR bit
        and     bx, 03h         ; Clear all but the lsp 2 bits of color
        mov     dh, s45_col[bx] ; Set into dh

s45_08:
        push    cx              ; Save the count
        mov     cx, 4           ; Repeat the loop 4 times for each character
        push    si
        push    di

s45_10:                         ; Basic loop to insert 2 bytes upper and 2 lower
        call    s45_exp         ; Go convert a byte to a word in ax ready to
                                ; insert to the next location
        test    dl, 80h         ; Test the original color byte for an XOR bit
        jnz     short s45_12    ; Go if its there
        mov     es:[di], ax     ; Put the word into the upper buffer
        jmp     s45_20          ; Go do lower buffer
s45_12:
        xor     es:[di], ax     ; XOR the word into the upper buffer
s45_20:
        call    s45_exp         ; Go convert a byte to a word in ax ready to
                                ; insert to the next location
        test    dl, 80h         ; Test the original color byte for an XOR bit
        jnz     short s45_22    ; Go if its there
        mov     es:[di+2000h], ax  ; Put the word into the lower buffer
        jmp     s45_25             ; Go do next byte
s45_22:
        xor     es:[di+2000h], ax  ; XOR the word into the upper buffer
s45_25:
        add     di, 80          ; Step to next graphics row

        loop    s45_10          ; Do this loop 4 times for eight chars

        pop     di              ; Get original output pointer ( row 0 )
        inc     di              ; Step to the next output character position
        pop     si              ; Reset input pointer
        pop     cx              ; Get the char count back
        loop    s45_08          ; and display the same char count times
s45_exit:
        pop     dx
        ret
s45     endp


        Align   4
s45_exp proc    near            ; A very tight routine for s45 use only
                                ; This routine expands a byte of 8 bits to
                                ; a word of 2 bit color bits
        lods    b gs:[si]       ; Get the 1st byte to be expanded
        mov     bl, al          ;
        and     bl, 0fh         ; Use the lower half
        mov     ah, s45_msk[bx] ; Get the mask for the lower half
        and     ah, dh          ; and AND in the color bits
        mov     bl, al          ; Get the upper half
        shr     bl, 4           ;
        mov     al, s45_msk[bx] ; Get the mask
        and     al, dh          ; AND in the color

        ret

s45_exp endp


;------------------------------------------------------------------------------
;Name:          S6 - Sets Grapics characters in video buffer for mode 6
;Function:      Moves 8 bytes from gs:si to the proper areas of video
;               buffer
;
;Function ID:   This is an internal routine without a function id
;
;Entry:         gs:si = pointer to the characters to be inserted
;               es:di = pointer to the first character in upper block of
;                       the video buffer
;               cx    = The number of times to insert the character
;
;Exit:          The specified character has been displayed the specified
;               number of times
;
;Notes:         If character pointer crosses the end of a line, junk comes out
;
;------------------------------------------------------------------------------

        Align   4
s6      proc    near    ; Writes graphic characters to video buffer for mode 6


        push    dx              ; Save dx

        cmp     cx, 0           ; If count zero
        je      short s6_exit   ;   forget the whole thing

s6_10:
        push    di              ; Save the output pointer
        push    si              ; Save input pointer

        mov     dx, 4
s6_12:
        lods    w gs:[si]               ; Get the 1st word
        test    bl, 80h                 ; Is the xor bit on?
        jnz     short s6_14             ; Go if on

        mov     b es:[di], al           ; Insert the even byte
        mov     b es:[di + 2000h], ah   ; Insert the odd byte
        jmp     s6_16                   ;
s6_14:
        xor     b es:[di], al           ; XOR the even byte
        xor     b es:[di + 2000h], ah   ; XOR the odd byte
s6_16:
        add     di, 80          ; Step to next graphics row

        dec     dx              ; Do this loop 4 time for eight chars
        jnz     short s6_12     ;

        pop     si              ; R03 Reset input pointer
        pop     di              ; Get original output pointer ( row 0 )
        inc     di              ; Step to the next output character position
;R03    pop     si              ; Reset input pointer

        loop    s6_10

s6_exit:
        pop     dx
        ret

s6      endp

;------------------------------------------------------------------------------
;Name:          CSCN - Scans the graphics char table for matches to input
;Function:      Finds the equivalent ASCII code for the input graphics chars
;
;Function ID:   This is an internal routine without a function id
;
;Entry:         GS:DI = Location of graphics char string
;               ES:SI = Table to scanned
;
;Exit:          AH = 0:  AL = Character
;                        BH = Attribute ( If any )
;Notes:
;
;------------------------------------------------------------------------------

soff    equ     3       ; The offset in the table to use for the initial pass

        Align   4
cscn    proc    near    ; Internal routine to look up graphics chars in table
                        ; for read characters function
        push    si      ; Save the pointer to beginning of char table
; Pick up a byte in the string to be matched
        mov     bx, soff * 2     ; Calculate the location of the soff char
        mov     bx, tab_get[bx]  ; Get the offset of soff character
        mov     ax, gs:[di + bx] ; Get the soff character in the string
                                 ; Gets both halves for mode 4 or 5
; If in Modes 4 or 5, each character is 2 bytes long and must be compressed
; into a single byte to compare with a byte in the table
        test    b v_mreg, m_bitsize     ; Go if were in mode 6
        jnz     short cscn_10

        call    sqez    ; Go squeese two bytes into al

; Scan down the table looking for a match on the soff byte of the string
; compared with the soff byte of each table entry.

cscn_10:
        mov     cx, 128 ; Set the number of entries in the table
        mov     b ueax, al          ; Save the character
; Begin table scan loop
cscn_20:
        cmp     al, es:[si + soff] ; Look at the next entry
        jne     short cscn_29      ; Not this entry, step to next entry

; The soff byte matches, check the rest of the string
; Begin loop to scan a table entry
        mov     dx, 8           ; Eight bytes in each entry string
        mov     bx, 0           ; Start with the leftmost char in the string
cscn_22:
        push    di              ; Do a little hand indexing here ---
        shl     bx, 1
        add     di, tab_get[bx] ; Gets the bytes from proper location in
                                ; the top or bottom buffer
        shr     bx, 1
        mov     ax, gs:[di]     ; Get the bx char in the input string
        pop     di              ; Restore di to beginning of input
        test    b v_mreg, m_bitsize ; If we're in mode six,
        jnz     short cscn_25       ; al is the character

        call    sqez                ; Otherwise go sqez two char into al

cscn_25:
        cmp     al, es:[si + bx] ; Does this byte match in both strings?
        jne     short cscn_28    ; If not, try the next string
        inc     bx               ; If so, try the next char in this string
        dec     dx               ; Count reduced by 1
        jnz     short cscn_22    ; Loop until entire strings compared
; End of table entry scan
; If everything matches, we've found the equivalent character

        mov     ax, si          ; Get the offset into the table
        pop     si              ; Restore the initial table pointer
        sub     ax, si          ; Get offset into table
        shr     ax, 3           ; Divided by eight to get entry number
                                ; This puts the ascii code in al
        mov     ah, 0           ; Set a zero in ah to tell of success
        ret                     ; Were done, return leaving everything in a mess

; Step to next entry in the search table

cscn_28:
        mov     al, b ueax      ; Restore the search byte
cscn_29:
        add     si, 8           ; Step to next entry. Each is 8 bytes long
        loop    cscn_20         ; Go look at next entry
; End of table scan loop
; If we fall thry the loop, the string isn't in the table, tell the caller

        pop     si              ; Reset table pointer
        mov     ax, 0100h       ; Not found flag and null character
        mov     bh, 0           ; null attribute

        ret


        Align   4
sqez    proc    near            ; Process to convert mode 4, 5 chars to mode 6

        cmp     ax, 0           ; If ax = 0, nothing to do. We're done.
        jz      short sq_exit   ; al is zero and that is the correct result

        push    cx              ; Clear a working register
        xchg    ah, al          ; Put the bytes in proper order
        mov     cx, ax          ; Create word in ax, with the even bits nonzero
        shl     cx, 1           ; if the corresponding 2 bit field was nonzero
        or      ax, cx          ;
; Compress ax into al by throwing away the odd bits
        mov     cx, 8           ; There are eight bits to obtain
sq_10:
        shl     eax, 1          ; Alternate double and word shifts to move the
        shl     ax, 1           ; nonzero bits into eal
        loop    sq_10           ; When we fall thru, eal is set to the byte
        shr     eax, 16         ; Put it into al

        pop     cx              ; Get the original cx back
sq_exit:
        ret                     ; and go back to caller

sqez    endp

cscn    endp


;------------------------------------------------------------------------------
;Name:          WRGC - Write Graphic Character
;Function:      Writes both the 40 or 80 char/line modes 4,5 or 6
;
;Function ID:   This is an internal routine without a function id
;
;Entry:         AL = the character to be displayed
;               BL  = character ( foreground ) color, 80h bit is XOR mode
;               CX  = count, the number of times to write the character
;
;Exit:          The character is inserted in the display buffer
;
;Notes:         If the cursor runs past the end of the line during the count
;               moves, the results are junk
;
;------------------------------------------------------------------------------

        Align   4
wrgc    proc    near

        push    gs              ; Save gs
        push    si              ; and si
        push    dx              ; Save dx
        push    es              ; R04 save es


;       movzx   ax, b ueax      ; Get the char to be displayed
        xor     ah, ah          ; Clear the high part of ax
; Select the appropriate graphics table
        cmp     al, 128         ; Make sure the char is in the standard table
        jb      short wrg_10    ; OK if its 127 or less	;R02
        sub     al, 128         ; Reduce al to be valid offset in ext. table
        lgs     si, gs:v_echrs  ; Otherwise, load a pointer to the extended tab.
        mov     dx, gs          ; Check to be sure the table is set
        or      dx, si          ;
        jnz     short wrg_20    ; Go if it's set to ANYTHING	;R02
        mov     al, 0           ; Otherwise, nul the char to be displayed
wrg_10:
;RKKS        lgs     si, l_gchar     ; Assume the char is lt 128
        mov     si, offset ES:DOUBLE_DOT     ; Pointer to the primary character table
        push    es              ; RKKS
        pop     gs              ; RKKS
wrg_20:
        mov     es, v_blocs     ; Set es to point at cga video buffer
        shl     ax, 3           ; Multiply char by 8
        add     si, ax          ; and add to si = gs:si now points at grapics
                                ; char string representing the input char
        movzx   ax, b v_crpos + 1 ; get the row number
        mov     dl, 80          ; Multiply by 80 for 4,5 AND 80 for 6
        mul     dl              ;
        shl     ax, 2           ; Multiply by 4 to get the graphics value
        movzx   dx, b v_crpos   ; Get the column number
        add     ax, dx          ; The pointer is now correct for 6
        mov     di, ax          ; Set so es:di is now correct for mode 6
        test    b v_mreg, m_bitsize ; If set, we're in mode 6
        jz      short wrg_30    ; Go if 4 or 5			;R02
; This is the mode 6 insertion, video pointer is ok
        call    s6              ; Call the set chars for mode 6 routine
        jmp     short wrg_exit  ; End of routine		;R02
; This is the mode 4, 5 insertion, video pointer must be adjusted
wrg_30:
        add     di, dx          ; Adjust di so that pointer is correct for 4,5
        call    s45             ; Call the set chars for mode 4,5 routine
wrg_exit:
        pop     es              ; R04 restore es
        pop     dx              ; Restore dx,
        pop     si              ; si,
        pop     gs              ; and gs

        ret                     ; Go back to calling routine

wrgc    endp

;------------------------------------------------------------------------------
;Name:          GPL - Get Pixel Location
;Function:      Sets ES:DI to the target byte and bx to the table offset of
;               masks
;
;Function ID:   This is an internal routine without a function id
;
;Entry:         BH = Page number for cursor selection
;               CX = Col number
;               DX = Line number
;
;Exit:          ES:DI = Location of byte to be changed
;               SI    = Mask Table + offset for insertion masks
;
;Notes:         Assumes we are in graphics modes 4, 5 or 6
;               Destroys all registers - if needed they should be in user regs
;               Since graphics modes have only one page, bh is ignored
;
;------------------------------------------------------------------------------

        Align   4
gpl     proc    near            ; Internal routine for video bios

; Determine the bank -- even or on depending on row number
        mov     di, 0           ; Assume bank 0 for the pixel
        shr     dx, 1           ; / row number by 2 - setting carry with bit 0
        jnc     short gpl_10    ; If carry off, bank 0 is correct	;R02
        mov     di, 2000h       ; If carry on, we should be in bank 1

; Adjust pointer for row number-- add row / 2 * 80
gpl_10:
        mov     ax, 80          ; Set for 80 bytes / row
        mul     dx              ; Byte offset to row / 2 ( also dx <= 0 )
        add     di, ax          ; Step di to beginning of row

; Adjust pointer for char location --
;    add col / 4  for 320 modes, col / 8 for 640 modes
        mov     ax, cx          ; Get the col position
        shr     ax, 2           ; Divide by 4 to get 320 mode offsets
        test    b v_mreg, m_bitsize ; Is this 320 or 640
        jz      short gpl_20    ; Go if 320				;R02
; Make 640 adjustments
        and     cx, 07h         ; Clear all but lowest 3 bits of col loc ( 640 )
        shl     cx, 2           ; Change to 4 bytes / entry
        add     cx, o mask_6    ; Add the offset of the 640 mask table
        shr     ax, 1           ; Divide offset by 2 ( 8 total )
        jmp     short gpl_30    ;                for 640 mode offsets	;R02
; Make 320 adjustments
gpl_20:
        and     cx, 03h         ; Clear all but two lowest bits
        shl     cx, 3           ; Change to 8 bytes / entry offset in 320 mode
        add     cx, o mask_3    ; + offset of the 320 mask table
gpl_30:
        add     di, ax          ; Add col offset to target pointer

        mov     dx, c_bloc      ; Set to seg location of color video buffer
        mov     es, dx          ; and set the target seg register

        mov     si, cx          ; Put mask table offsets in bx
;       jmp     v_exit          ; xxxxxxx Temporary for testing xxxxxxxxxxxxxx
        ret

gpl     endp

;------------------------------------------------------------------------------
;Name:          DSP - Display the TTY character in al at the cursor location
;Function:      Displays characters for 0er and 13r -- the TTY disp routines
;
;Function ID:   This is an internal routine without a function id
;
;Entry:         AH = 0 if not attribute is to be inserted in text mode
;                  = 1 if the attribute is in bl
;               AL = the character to be displayed or processed
;               BH = Page number
;               BL = The text attribute, if reqd, or the grapics fg color
;
;
;Exit:
;
;Notes:
;
;------------------------------------------------------------------------------

        Align   4
dsp     proc    near    ; Internal routine to display TTY char

        cmp     al, bel         ; Is this a bell?
        je      short dsp_20    ; Go process the bell		;R02

        cmp     al, bsp         ; Is this a Backspace:
        je      short dsp_30    ; Go adjust the cursor		;R02

        cmp     al, lf          ; How about a line feed?
        je      short dsp_40					;R02

        cmp     al, cr          ; A carriage ( ? ) return?
        je      short dsp_50					;R02

; Graphics processing is different

        test    b v_mreg, m_graphics ; Check to be sure we're in text mode
        jnz     short dsp_10    ; If a graphics mode, go do graphics work;R02

; Process normal character
        push    ax              ; Save the character and the control

        mov     ax, dx          ; Move the cursor to ax for gcp1
        call    gcp1            ; Get the current cursor position for page in bh
                                ; Note that the 6845 and RBDA are both updated
        pop     ax              ; Get the character and control

        cmp     b v_mode, 7     ; See if we're in mono text
        je      short dsp_5     ; If so, don't wait for the retrace signal;R02
        cli                     ; turn off the interrupts
        call    blnk            ; go wait for a blank screen
dsp_5:
        stosb                   ; note that es:di was set by gcp
        cmp     ah, 0           ; If ah ne 0, then we set the attribute
        jz      short disp_51   ; at specified in bl			;R02
        mov     es:[di], bl     ; Note that the stosb stepped di
disp_51:
        sti                     ; and startup the interrupts again

; Step the cursor to the next col
dsp_6:
        inc     dl              ; Step the cursor to next character
dsp_7:
        call    ncp1            ; and normalize it, scrolling as necessary
dsp_8:                          ; A normalized cursor should be in dx
        mov     ax, 0200h       ; Set for position crsr interrupt service
        int     10h             ; Go do it
dsp_exit:
        ret                     ; Return to caller


dsp_10:                         ; Code for inserting graphics char goes here
        mov     cx, 1           ; Tell graphics routine to write 1 character
        mov     v_crpos, dx     ; Set the cursor
;R04        mov     bl, b uebx      ; Get the original color back for graphics
        call    wrgc            ; Call the graphics write char routine
        jmp     short dsp_6     ; Go increment cursor and exit	;R02



; Process the 07h, bell command generating a 1/2 second beep
dsp_20:
        push    bx              ; RKKS save bx
        mov     bx, 2           ; RKKS
;R01 ifdef  POST_SEG
;R01         f000_call    snd_spkr   ; RKKS Go send a bell tone - crsr doesn't move
;R01 else  ;POST_SEG
;R01         call    snd_spkr        ; RKKS Go send a bell tone - crsr doesn't move
;R01 endif ;POST_SEG
;R01         f000_call    snd_spkr   ; RKKS Go send a bell tone - crsr doesn't move
;R01 - start
ifndef	AVIDEO_AT_F000						
	F000_call    snd_spkr   ; RKKS Go send a bell tone - crsr doesn't move
else;	AVIDEO_AT_F000						
        call    snd_spkr        ; RKKS Go send a bell tone - crsr doesn't move
endif;	AVIDEO_AT_F000						
;R01 - end

        pop     bx              ; RKKS restore bx
        jmp     dsp_exit

; Process the 08, backspace unless at zero.
dsp_30:
        cmp     dl, 0           ; If col already zero --
        je      short dsp_exit  ;             exit with no crsr change	;R02
        dec     dl              ; Reduce cursor col by one
        jmp     dsp_7           ; Adjust cursor position

; Process the 0a, linefeed with scrolling as necessary
dsp_40:
        inc     dh              ; Step the row number
        jmp     dsp_7

; Process the 0d, carriage return. Simply sets the col to zero.
dsp_50:
        mov     dl, 0           ; Clear the col id
        jmp     dsp_8           ; and go move the cursor

dsp     endp
 


        Align   4
ncp1    proc    near

ncp1_01:
        cmp     dl, v_cols      ; If col less than max allowed by mode,
        jl      short ncp1_02   ;    go look at rows		;R02
        sub     dl, v_cols      ; else reduce by max rows
        inc     dh              ; inc row number by one
        jmp     ncp1_01         ; and go see if we're done
ncp1_02:
        cmp     dh, 24          ; If less than 25, the max rows in all modes,
        jle     short ncp1_03   ;   we're  done			;R02
        sub     dh, 24          ; Calculate number of rows to scroll = n

        push    dx
        push    cx
        push    bx
        push    ax

        mov     ah, 06h         ; Move area
        mov     al, dh          ; Move specific number of lines
        xor	cx,cx	        ; ULC is 0,0
        mov     dx, 184fh       ; LRC is 24, 79
;R04        mov     bh, 07h         ; Set the attribute xxxxxxxxxxxxxxxxxxxxxxxx
        mov     bh, bl          ; R04 Set the attribute 
        test    b v_mreg, m_graphics ;R04 Is it graphic mode
        jz      short ncp1_02_0 ; R04 If we're in text mode, go
        xor	bh,bh           ; R04 Set the attribute for graphic
ncp1_02_0:                      ; R04
        int     10h             ; Go scroll to get cursor back on screen

        pop     ax
        pop     bx
        pop     cx
        pop     dx

        mov     dh, 24          ; Set crsr to the last row
ncp1_03:
        ret                     ; go back to caller

ncp1    endp


    PUBLIC  DATAC_END
DATAC_END  LABEL  BYTE      ; END OF CODE FOR RAM LOAD

;R01 ifdef  POST_SEG
;R01 ECODE    ENDS
;R01 else  ;POST_SEG
;R01 FCODE    ENDS
;R01 endif  ;POST_SEG
;R01 - start
ifndef	AVIDEO_AT_F000
;R10ECODE    ENDS
		org	0fffh			;R10
		public	E000_code_end		;R10
E000_code_end:					;R10
		db	?			;R10
EFCODE		ENDS				;R10
else;	AVIDEO_AT_F000
FCODE    ENDS
endif;	AVIDEO_AT_F000
;R01 - end
;R08Aendif ;NO_SUPPORT_AVIDEO		;R08

    END

