mirror of
https://github.com/stevenhowes/wbios.git
synced 2026-05-27 00:03:32 +01:00
d410ad0acb
Original source https://www.pcengines.ch/file/wbios111s.zip
509 lines
10 KiB
Plaintext
509 lines
10 KiB
Plaintext
;
|
|
; Hercules monochrome video BIOS
|
|
;
|
|
; (C)1997-2001 Pascal Dornier / PC Engines; All rights reserved.
|
|
; This file is licensed pursuant to the COMMON PUBLIC LICENSE 0.5.
|
|
;
|
|
; Limitations:
|
|
;
|
|
; - No CGA / graphics support - CGA cards / monitors are no longer
|
|
; available. VGA is handled by separate BIOS anyway, Hercules
|
|
; support is mainly for debug purposes.
|
|
; - No light pen support
|
|
; - No print screen function (risky for embedded systems)
|
|
; - Video mode ignored (monochrome only supports 80x25)
|
|
; - INT 1D (pointer to video parameters) not supported.
|
|
; - Font not supported.
|
|
; - Historic entry points not supported.
|
|
; - INT 1F extended font not supported.
|
|
; - AH=13 Write string not supported (AT only)
|
|
;
|
|
|
|
;
|
|
; Initialize text mode
|
|
;
|
|
vid_init: mov al,21h ;disable video, high res bit
|
|
mov dx,crtc+4
|
|
out dx,al
|
|
|
|
mov si,offset v_parm ;set text mode
|
|
mov bl,0
|
|
mov dl,low(crtc)
|
|
hercloop: mov al,bl
|
|
out dx,al
|
|
inc dx
|
|
cs: lodsb
|
|
out dx,al
|
|
dec dx
|
|
inc bx
|
|
cmp bl,16
|
|
jb hercloop
|
|
|
|
mov ax,vidseg ;clear screen
|
|
mov es,ax
|
|
mov ax,vid_fill ;fill value
|
|
mov cx,2048
|
|
mov di,0
|
|
rep stosw
|
|
|
|
mov al,29h ;enable video
|
|
mov dl,low(crtc+4)
|
|
out dx,al
|
|
ret
|
|
;
|
|
; initialize video variables
|
|
;
|
|
vid_vars: mov word [m_vcrt],crtc ;video I/O port
|
|
mov si,offset v_parm ;video parameters
|
|
mov byte [m_vpgno],0 ;page number = 0
|
|
mov byte [m_vmsel],29h ;mode register shadow
|
|
mov byte [m_vpal],30h ;palette shadow
|
|
mov word [m_vmode],7 ;force mode 7
|
|
mov word [m_vcol],80 ;80 columns per line
|
|
mov word [m_vrow],24 ;25-1 rows
|
|
mov word [m_vpgsz],2048 ;video page size
|
|
push ds ;clear video positions per page
|
|
pop es
|
|
mov di,offset m_vpage ;& m_vcolrow
|
|
xor ax,ax
|
|
mov cx,9 ;also set page offset
|
|
rep stosw
|
|
mov ax,0b0ch ;m_vcursor cursor end line, start line
|
|
stosw
|
|
mov al,0
|
|
stosb ;m_vpgno
|
|
ret
|
|
;
|
|
; INT 10 entry
|
|
;
|
|
int10: cmp ah,10h ;max command code
|
|
jae int10_ret
|
|
sti
|
|
cld ;forward mode
|
|
push ds
|
|
push es
|
|
pusha
|
|
xor si,si ;DS = BIOS segment
|
|
mov ds,si
|
|
mov si,vidseg
|
|
#if def VID_CGA
|
|
cmp byte [m_vcrt],0d4h ;CGA ?
|
|
jnz vid_cga1
|
|
mov si,0b800h ;CGA segment
|
|
vid_cga1:
|
|
#endif
|
|
mov es,si
|
|
mov si,ax ;calculate jump table vector
|
|
shr si,8
|
|
shl si,1
|
|
jmp [cs:si+int10_tab] ;jump to individual routine
|
|
|
|
int10_ret: iret
|
|
;
|
|
; video dispatch table
|
|
;
|
|
even
|
|
|
|
int10_tab: dw v_mode ;00 = set video mode
|
|
dw v_cursor ;01 = set cursor characteristics
|
|
dw v_setcur ;02 = set cursor position
|
|
dw v_getcur ;03 = get cursor position
|
|
dw v_getpen ;04 = get light pen position
|
|
dw v_setpage ;05 = set display page
|
|
dw v_scrlup ;06 = scroll up
|
|
dw v_scrldn ;07 = scroll down
|
|
dw v_rdattr ;08 = read character attribute
|
|
dw v_wrattr ;09 = write character attribute
|
|
dw v_wrchar ;0A = write character
|
|
dw v_exit ;0B = set palette
|
|
dw v_exit ;0C = write pixel
|
|
dw v_exit ;0D = read pixel
|
|
dw v_tty ;0E = write TTY
|
|
dw v_stat ;0F = read video status
|
|
;
|
|
; AH=00: set video mode
|
|
;
|
|
v_mode:
|
|
#if def VID_CGA
|
|
cmp byte [m_vcrt],0d4h ;CGA mode ?
|
|
jz v_mode9 ;:bail
|
|
#endif
|
|
call vid_init ;initialize video
|
|
call vid_vars ;set video variables
|
|
v_mode9: jmp v_exit ;return
|
|
;
|
|
; video mode settings
|
|
;
|
|
v_parm: db 61h,50h,52h,0Fh,19h,06h,19h,19h,02h,0Dh,0Bh,0Ch,0,0,0,0
|
|
;
|
|
; AH=01: set cursor characteristics
|
|
;
|
|
v_cursor: mov [m_vcursor],cx ;save cursor value
|
|
mov al,10
|
|
jmp v_set
|
|
;
|
|
; AH=02: set cursor position
|
|
;
|
|
v_setcur: mov bl,0 ;page number -> index
|
|
mov si,bx
|
|
shr si,7
|
|
mov [si+m_vcolrow],dx ;save position
|
|
cmp [m_vpgno],bh ;same page ?
|
|
jnz v_setc2 ;:no
|
|
jmp v_tty3 ;set cursor
|
|
v_setc2: jmp v_exit
|
|
;
|
|
; AH=03: get cursor position
|
|
;
|
|
v_getcur: mov bp,sp ;access stack frame
|
|
mov bl,0 ;page number -> index
|
|
shr bx,7
|
|
mov ax,[bx+m_vcolrow] ;get cursor pos from table
|
|
mov [bp._dx],ax ;-> DX
|
|
mov ax,[m_vcursor] ;cursor shape
|
|
mov [bp._cx],ax ;-> CX
|
|
jmp v_exit
|
|
;
|
|
; AH=04: get light pen position
|
|
;
|
|
; anyone remember what a light pen looks like ? ;-)
|
|
;
|
|
v_getpen: mov bp,sp ;access stack frame
|
|
mov byte [bp._ah],0 ;not activated -> AH
|
|
jmp v_exit
|
|
;
|
|
; AH = 05: set video page
|
|
;
|
|
v_setpage: mov [m_vpgno],al ;page number
|
|
shl ax,1
|
|
mov bx,ax ;table index
|
|
shl ax,11
|
|
mov [m_vpage],ax ;page offset
|
|
shr ax,1
|
|
mov cx,ax
|
|
#if def VID_CGA
|
|
mov dx,[m_vcrt]
|
|
#else
|
|
mov dx,crtc
|
|
#endif
|
|
mov al,12 ;set display offset
|
|
mov ah,ch
|
|
out dx,ax
|
|
inc ax
|
|
mov ah,cl
|
|
out dx,ax
|
|
mov dx,[bx+m_vcolrow] ;page cursor position
|
|
jmp v_tty3 ;set cursor position
|
|
;
|
|
; AH=06: scroll window up
|
|
;
|
|
v_scrlup: mov bl,dh ;row difference
|
|
sub bl,ch
|
|
sub bl,al ;- scroll count
|
|
inc bl ;+1 -> number of lines to scroll
|
|
sub dl,cl ;character count
|
|
inc dl
|
|
mov dh,al ;number of lines to clear
|
|
mul byte [m_vcol] ;scroll count
|
|
add ax,ax
|
|
mov si,ax ;-> start offset
|
|
mov al,ch ;start row
|
|
mul byte [m_vcol] ;* columns
|
|
add al,cl ;add start column
|
|
adc ah,0
|
|
add ax,ax
|
|
add ax,[m_vpage] ;+ page offset
|
|
mov di,ax ;DI = destination offset
|
|
add si,ax ;add to SI -> source offset
|
|
mov ax,[m_vcol] ;calculate line skip
|
|
sub al,dl
|
|
add ax,ax
|
|
mov bp,ax
|
|
;
|
|
; AX = fill character
|
|
; BL = lines to scroll
|
|
; DL = character count
|
|
; DH = lines to clear
|
|
; SI = source offset
|
|
; DI = destination offset
|
|
; BP = columns per line - character count
|
|
;
|
|
v_scroll: mov al," " ;fill pattern
|
|
mov ah,bh
|
|
xor cx,cx
|
|
and dh,dh ;0 lines to clear ?
|
|
jz v_scroll2
|
|
push es
|
|
pop ds
|
|
v_scroll1: mov cl,dl ;character count
|
|
rep movsw ;scroll a line
|
|
add si,bp ;go to next line
|
|
add di,bp
|
|
dec bl
|
|
jnz v_scroll1 ;:another line
|
|
mov bl,dh
|
|
v_scroll2: mov cl,dl ;character count
|
|
rep stosw ;clear a line
|
|
add di,bp
|
|
dec bl
|
|
jnz v_scroll2
|
|
jmp v_exit
|
|
;
|
|
; AH=07: scroll window down
|
|
;
|
|
v_scrldn: sub dl,cl ;number of characters
|
|
inc dl
|
|
mov bl,dh ;row difference
|
|
sub bl,ch
|
|
sub bl,al ;- scroll count
|
|
inc bl ;+1 -> number of lines to scroll
|
|
mov ch,al ;number of lines to clear
|
|
mul byte [m_vcol] ;scroll count
|
|
add ax,ax
|
|
neg ax
|
|
mov si,ax ;-> start offset
|
|
mov al,dh ;end row
|
|
mul byte [m_vcol] ;* columns
|
|
add al,cl ;add start column
|
|
adc ah,0
|
|
add ax,ax
|
|
add ax,[m_vpage] ;+ page offset
|
|
mov di,ax ;DI = destination offset
|
|
add si,ax ;add to SI -> source offset
|
|
mov ah,0 ;calculate line skip
|
|
mov al,dl ;- characters per line - window width
|
|
add ax,[m_vcol] ;(move is forward)
|
|
add ax,ax
|
|
neg ax
|
|
mov bp,ax
|
|
mov dh,ch ;number of lines to clear
|
|
jmp v_scroll ;do the actual scroll
|
|
;
|
|
; AH=08: read character + attribute
|
|
;
|
|
v_rdattr: call v_pos ;calculate position
|
|
mov bp,sp
|
|
mov ax,[es:di] ;read character
|
|
mov [bp._ax],ax ;-> AX
|
|
jmp v_exit
|
|
;
|
|
; calculate video offset
|
|
;
|
|
; -> DI offset
|
|
; -> AX character, attribute
|
|
; -> SI page number * 2
|
|
;
|
|
v_pos: mov dh,bl ;attribute
|
|
mov dl,al ;character
|
|
mov di,bx ;save BX &pd 980406 fixed
|
|
mov bl,0 ;page -> index
|
|
mov si,bx
|
|
shr si,7
|
|
mov ax,[si+m_vcolrow] ;get cursor position for page
|
|
shl bx,4 ;-> page offset
|
|
add bl,al ;column offset
|
|
adc bl,0
|
|
mov al,ah ;row offset
|
|
mul byte [m_vcol]
|
|
add bx,ax
|
|
add bx,bx
|
|
xchg di,bx ;-> page offset, restore BX
|
|
mov ax,dx ;restore character, attribute
|
|
ret
|
|
;
|
|
; AH=09: write character + attribute
|
|
;
|
|
v_wrattr: call v_pos ;calculate position
|
|
rep stosw ;write characters
|
|
jmp short v_exit
|
|
;
|
|
; AH=0A: write character only, no attribute
|
|
;
|
|
v_wrchar: call v_pos ;calculate position
|
|
v_wrc1: stosb
|
|
inc di
|
|
loop v_wrc1
|
|
jmp short v_exit
|
|
;
|
|
; AH=0E: write character TTY
|
|
;
|
|
v_tty:
|
|
|
|
#if def CONSOLE
|
|
|
|
; serial port console
|
|
;
|
|
; if m_vpal bit 0 is set, we copy characters to the console.
|
|
|
|
test byte [m_console],1 ;serial port redirect ?
|
|
jz v_ttys9 ;:no
|
|
push dx
|
|
push ax
|
|
mov dx,CONSOLE+5
|
|
v_ttys1: in al,dx ;wait for transmit ready
|
|
out iowait,ax
|
|
test al,40h
|
|
jz v_ttys1
|
|
mov dl,low(CONSOLE)
|
|
pop ax
|
|
out dx,al
|
|
pop dx
|
|
v_ttys9:
|
|
|
|
#endif
|
|
call v_pos
|
|
mov dx,[si+m_vcolrow] ;get cursor position
|
|
cmp al,cr
|
|
jbe v_ctrl
|
|
v_tty1: stosb
|
|
inc dl ;inc column
|
|
cmp dl,[m_vcol] ;max ?
|
|
jz v_lf0 ;yes: line feed
|
|
;
|
|
; set cursor position
|
|
;
|
|
v_tty2: mov [si+m_vcolrow],dx ;save position
|
|
cmp [m_vpgno],bh ;same page ?
|
|
jnz v_exit ;:no
|
|
v_tty3: mov cx,[m_vpage] ;page offset / 2
|
|
shr cx,1
|
|
mov cl,dl ;column
|
|
mov al,dh ;row * column width
|
|
mul byte [m_vcol]
|
|
add cx,ax ;get address
|
|
mov al,14 ;set cursor offset
|
|
v_set:
|
|
#if def VID_CGA
|
|
mov dx,[m_vcrt]
|
|
#else
|
|
mov dx,crtc
|
|
#endif
|
|
mov ah,ch
|
|
out dx,ax
|
|
inc ax
|
|
mov ah,cl
|
|
out dx,ax
|
|
v_exit: popa
|
|
pop es
|
|
pop ds
|
|
iret
|
|
;
|
|
; display control characters
|
|
;
|
|
v_ctrl: jnz v_ctrl2 ;:not carriage return
|
|
;
|
|
; carriage return
|
|
;
|
|
v_cr: mov dl,0 ;beginning of line
|
|
jmp v_tty2 ;set cursor position
|
|
|
|
v_ctrl2: cmp al,lf
|
|
jz v_lf
|
|
cmp al,bs
|
|
jz v_bs
|
|
cmp al,bell
|
|
jz v_bell
|
|
#if def MEDIAGX
|
|
cmp al,0bh ;clear to beginning of line
|
|
jz v_cr
|
|
#endif
|
|
jmp v_tty1
|
|
;
|
|
; line feed
|
|
;
|
|
v_lf0: mov dl,0 ;beginning of line
|
|
v_lf: inc dh ;increment line
|
|
#if def VID_CGA
|
|
cmp dh,[m_vrow] ;last line ?
|
|
jbe v_tty2 ;:no scroll, set cursor
|
|
#else
|
|
cmp dh,25 ;last line ?
|
|
jb v_tty2 ;:no scroll, set cursor
|
|
#endif
|
|
dec dh ;restore
|
|
push si ;pd 980422: fix LF bug
|
|
and di,0f000h ;keep page offset
|
|
#if def VID_CGA
|
|
mov al,[m_vcol] ;columns
|
|
mov ah,0
|
|
push ax ;save columns
|
|
mov si,di ;SI = point to next line
|
|
add si,ax
|
|
add si,ax
|
|
mov bx,ax ;save...
|
|
mul byte [m_vrow] ;* rows -> characters to scroll
|
|
mov cx,ax
|
|
#else
|
|
lea si,[di+160]
|
|
mov cx,24*80 ;scroll full screen
|
|
#endif
|
|
mov ax,es ;DS = video segment
|
|
mov ds,ax
|
|
rep movsw
|
|
mov al," " ;fill with same attribute
|
|
mov ah,[di+1]
|
|
#if def VID_CGA
|
|
pop cx ;number of columns
|
|
#else
|
|
mov cx,80 ;fill bottom line
|
|
#endif
|
|
rep stosw
|
|
xor ax,ax ;restore DS
|
|
mov ds,ax
|
|
pop si ;pd 980422: fix LF bug
|
|
jmp v_tty2
|
|
;
|
|
; backspace
|
|
;
|
|
v_bs: sub dl,1
|
|
adc dl,0 ;limit to 0
|
|
jmp v_tty2 ;set cursor position
|
|
;
|
|
; bell
|
|
;
|
|
v_bell: call beep
|
|
jmp v_exit
|
|
;
|
|
; AH=0F: get video status
|
|
;
|
|
v_stat: mov bp,sp
|
|
mov ax,[m_vmode] ;& m_vcol
|
|
mov [bp._ax],ax
|
|
mov al,[m_vpgno] ;page number
|
|
mov [bp._bh],al
|
|
jmp v_exit
|
|
;
|
|
; display string [SI] -> TTY
|
|
;
|
|
v_msg: cs: lodsb ;get character
|
|
and al,al ;0 = end
|
|
jz v_msg9
|
|
mov ah,0eh ;TTY output
|
|
mov bh,0 ;page 0
|
|
int 10h
|
|
jmp v_msg
|
|
v_msg9: ret
|
|
;
|
|
; ring bell
|
|
;
|
|
beep: push ax
|
|
push cx
|
|
mov al,0b6h ;set beep timer
|
|
out timer+3,al
|
|
mov al,33h ;beep frequency
|
|
out timer+2,al
|
|
mov al,05h
|
|
out timer+2,al
|
|
in al,port61 ;enable beep
|
|
mov ah,al
|
|
or al,3
|
|
out port61,al
|
|
xor cx,cx ;delay
|
|
bell1: out iowait,ax
|
|
loop bell1
|
|
mov al,ah
|
|
out port61,al
|
|
pop cx
|
|
pop ax
|
|
ret
|