Hercules graphics BIOS
D.TUTELMAN
dmt at mtuxt.UUCP
Thu Aug 28 12:47:07 AEST 1986
Well, here's the promised Hercules driverfor the PC. It's in SHAR format,
and the instructions for assembly and use are in "hercbios.doc".
Enjoy!
---------------------------------------------------------------
---=== Dave Tutelman
-------===== Physical - AT&T Information Systems
----------====== Room 1H120
==--------======== Juniper Plaza, Route 9
====---========= Freehold, NJ 07728
============ Logical - ...ihnp4!mtuxo!mtuxt!dmt
====== Audible - (201)-577-4232
---------------------------------------------------------------
------------------cut here------------------------------------
: This is a shar archive. Extract with sh, not csh.
: The rest of this file will extract:
: hercbios.doc hercbios.h hercbios.asm gchar.asm graph.asm makefile hcharset.asm hercpixl.c testpix.c
echo extracting - hercbios.doc
sed 's/^X//' > hercbios.doc << '!EOR!'
X
X
X
X
X
X ***** _H_E_R_C_B_I_O_S *****
X _B_I_O_S _P_A_T_C_H _F_O_R _T_H_E _H_E_R_C_U_L_E_S _B_O_A_R_D
X
X Dave Tutelman 1986
X
X
X
X The accompanying program is a front end to the INT 10 (VIDEO)
X functions of the DOS BIOS, so that the important functions work
X on a Hercules graphics board or its clones. (It was developed on
X a SuperComputer clone of a Hercules) It is a
X terminate-and-stay-resident program, that is installed by being
X called; it is NOT a DOS driver. If you want it installed at boot,
X include it in AUTOEXEC.BAT, not CONFIG.SYS.
X
X _W_H_A_T _I_T'_S _G_O_O_D _F_O_R
X
X The major strength of this program is that it will allow you to
X write programs for the Hercules board that run in graphics mode,
X and still write text easily on the graphics screen. With it, you
X can program in those higher-level language processors that use
X the DOS or BIOS calls for display, using their standard I/O calls
X to write text to the graphics screen. (For a list of known
X compatible and incompatible languages, see the section later in
X this manual.)
X
X A second use of this program is to allow the running of existing
X graphics programs that use the BIOS calls for ALL screen display.
X It will NOT allow most commercial graphics programs written for
X the the Color Graphics Adapter (CGA) to run on the Hercules
X board. That is because most graphics programs write directly to
X the video memory instead of using the BIOS calls. The only
X existing graphics program that this has been tested against is
X PC-LISP; that is the only graphics program I've encountered that
X uses the BIOS exclusively.
X
X
X _H_O_W _I_T _W_O_R_K_S
X
X HERCBIOS is a terminate-and-stay-resident program that intercepts
X all calls to Interrupt 10H, the BIOS video services. It will
X either process the interrupt or pass the call on to the real
X BIOS, depending on whether something specific to the Hercules
X board needs to be done. Specifically, HERCBIOS handles the
X interrupt itself if (1) the board is in graphics mode, or (2) the
X BIOS call is a request to enter graphics mode.
X
X Two graphics modes are recognized and processed by HERCBIOS:
X
X _M_o_d_e _6 - _I_B_M _H_i-_r_e_s _m_o_d_e: This uses part of the 720x348
X Hercules raster as a 640x200 IBM-compatible graphics screen.
X It will work with programs for the IBM CGA and its clones,
X provided they use the BIOS services for their graphics
X display. (Note - such programs are rare.)
X
X _M_o_d_e _8 - _H_e_r_c_u_l_e_s-_s_p_e_c_i_f_i_c _m_o_d_e: This uses the full
X
X - 1 -
X
X
X
X
X
X
X
X
X Hercules raster.
X
X Actually, both modes are quite capable of putting a pixel
X anywhere on the Hercules raster. The major difference is that
X Mode 6 draws characters in an 8x8 pixel box (like the CGA), while
X Mode 8 uses the finer resolution of the Hercules board to improve
X legibility by using a 12x8 pixel box for characters. In either
X mode, more characters than 25x80 will fit on the screen. Mode 6
X supports 43x90 characters on the screen (but 25x80 inside the
X 640x200-pixel sub-screen); Mode 8 supports 29x90 characters.
X
X The functions implemented by HERCBIOS are:
X
X Fn 0 - Set mode (6, 7, or 8)
X Fn 2 - Set cursor position
X Fn 3 - Read cursor position
X Fn 5 - New display page
X Fn 9 - Write character with attribute
X Fn 10 - Write character
X Fn 12 - Write pixel
X Fn 13 - Read pixel
X Fn 14 - Teletypewriter-style character write
X Fn 15 - Get video status
X
X Check your System Programmers' Guide for the use of these BIOS
X functions.
X
X A number of properties of the alphanumeric display are not
X supported by the hardware when you enter graphics mode. For
X instance, the cursor is not shown in graphics mode, nor are all
X of the character attributes. HERCBIOS does its best to emulate
X the alphanumeric mode, but it cannot implement a cursor or the
X blinking or bold attributes. The table below shows the "best
X shot" that HERCBIOS takes at character attributes:
X
X CODE USUALLY MEANS IBM MODE HERC MODE
X 00 invisible invisible invisible
X 01 underline [normal] underline
X 07 normal normal normal
X 0F hi-intens [rev video] [rev video]
X 70 rev video rev video rev video
X
X
X Anything else displays as normal
X
X The teletypewriter-style output protects the bottom line on the
X screen as an unscrolled line, for status messages, function key
X labels, etc. This is non-standard, but I like it. (And we do have
X more rows than the CGA display. It's the 43rd line that isn't
X scrolled.)
X
X
X
X
X
X
X
X - 2 -
X
X
X
X
X
X
X
X
X _M_A_K_I_N_G _A_N_D _I_N_S_T_A_L_L_I_N_G _T_H_E _P_R_O_G_R_A_M
X _M_a_k_i_n_g _t_h_e ._C_O_M _F_i_l_e _f_r_o_m _A_s_s_e_m_b_l_e_r _S_o_u_r_c_e
X
X HERCBIOS was originally developed on ASM 1.0. The version
X included with this uses MASM 4.0. I don't know for sure whether
X it will assemble with other versions of assembler.
X
X The commands for making HERCBIOS.COM from the source are in the
X MAKEFILE included with the distribution. I run it with NDMAKE, an
X excellent MS-DOS shareware MAKE from Don Knellers, but it should
X be easy to adapt to your own favorite MAKE. If you make it by
X hand, the commands are:
X
X masm hercbios;
X masm gchar;
X masm graph;
X link hercbios gchar graph, hercbios.exe;
X exe2bin hercbios.exe hercbios.com
X del hercbios.exe
X
X If you have a machine whose processor is an iAPX 286, 186, or
X 188, you may be able to get some increased performance and a
X smaller .COM file by editing one character in the header file
X _h_e_r_c_b_i_o_s._h. Simply remove the ";" that comments out the
X definition of _i_A_P_X_2_8_6. That will allow some non-8088 instructions
X to assemble, as well as changing some code that was optimized for
X speed (at the expense of storage and beauty) on the 8088. (This
X option is known to assemble and link, but has not been tested; I
X have no access to a 286 machine with Hercules graphics.)
X
X
X _I_n_s_t_a_l_l_i_n_g _H_E_R_C_B_I_O_S._C_O_M
X
X Once you have HERCBIOS.COM, store it where your PATH will find it
X and add the line
X
X HERCBIOS
X
X to your AUTOEXEC.BAT file somewhere after the PATH command. This
X will cause it to be installed during boot, so it will be there
X whenever you run your graphics programs. (Its presence won't
X affect operation of your computer in alphanumeric mode, since it
X passes on to the normal BIOS anything that's not in graphics
X mode.)
X
X I am including a couple of demonstration/test programs in this
X distribution, so that you can:
X - See how to write programs for HERCBIOS.
X - Test to assure that it runs with your computer and monitor.
X The programs can be run in their executable form and their source
X can be examined.
X
X
X
X
X
X
X - 3 -
X
X
X
X
X
X
X
X
X _C_O_M_P_A_T_I_B_I_L_I_T_Y _A_N_D _I_N_C_O_M_P_A_T_I_B_I_L_I_T_Y
X
X HERCBIOS has been tested on a Hercules board in an IBM PC-XT, a
X Hercules-compatible board I built from a SuperComputer bare
X board, and a Leading Edge XT clone. The current version works
X with all of these, but I have a homebrew monitor that has trouble
X syncing to the higher sweep rate of the monochrome display. If
X you have trouble with the stability of your image, try fiddling
X with the parameters for the 6845 display chip. They are in the
X file _H_E_R_C_B_I_O_S._A_S_M, in the "db" statement defining _v_i_d__p_a_r_m__t_a_b_l_e
X at the end of Function 0 (Set Video Mode). I have left in (but
X commented out) the set of parameters that works on my homebrew
X monitor.
X
X I have written programs using HERCBIOS in a number of languages.
X Here are some of the caveats I'd like to pass on:
X
X - Things are fine using INT 10h calls in assembler. (No big
X surprise.)
X
X - Turbo Pascal works with HERCBIOS, with one caveat (at least
X for releases 1 and 2). The Pascal cursor function GoTOXY will
X home the cursor if presented with x>80 or y>25. To make full
X use of the 29x90 or 43x90 screen, you will have to write your
X own version of GoTOXY, using Turbo's machine language escape
X to issue the INT 10h.
X
X - I've written a little in Microsoft C 3.0. No problems so far.
X
X - The TESTPIX program was written in deSmet C 2.4. It worked
X fine, with one caveat. The console I/O routine _g_e_t_c_h_a_r()
X seems to write to display memory (perhaps as part of keyboard
X echo). This can interfere with what is displayed on the
X Hercules board display page 1. (I had no problems on page
X 0.)
X
X - Forget about using it with BASICA or GWBASIC. Microsoft BASIC
X graphics routines write directly to display memory,
X completely bypassing the BIOS.
X
X
X USE AND ENJOY!
X
X Bug reports to:
X Dave Tutelman
X 16 Tilton Drive
X Wayside, NJ 07712
X
X
X Currently receive EMail at ...!mtuxo!mtuxt!dmt
X
X
X Flames to:
X /dev/null
X
X
X
X - 4 -
X
X
X
!EOR!
echo extracting - hercbios.h
sed 's/^X//' > hercbios.h << '!EOR!'
X.XLIST
X page 66,132
X;************************************************************
X;
X; Header file for inclusion in HERCBIOS assemblies
X;
X; Dave Tutelman - 8/86
X;
X;*************************************************************
X
X;iAPX286 equ 1 ; UN-COMMENT FOR A 186 or 286 MACHINE!
X ; Some of the "ugly" constructs are for speed
X ; on the 808X, while the "obvious" constructs
X ; run faster on the 186 & 286.
XVIDI equ 10H ; video interrupt, 10H for real, 50H for debug
Xpixbase equ 0B000H ; beginning segment of graphics board
Xmpx_bios equ 0F000H ; MPX-16 BIOS segment address
Xvid_offset equ 0F065H ; MPX-16 video offset in BIOS
Xcharbase equ 0FA6EH ; MPX-16 BIOS character table offset
Xherc_mode equ 8 ; Hercules graphics mode
Xibm_mode equ 6 ; IBM Hi-Res color graphics mode.
X ; we'll try to handle it.
Xvid_port equ 03B4H ; 6845 index register (data reg = 3B5H )
X ; (control port = 3B8H )
X;------------------------------------------
Xbios segment at mpx_bios ; setup call to vid_bios
X org vid_offset
Xvid_bios proc far
Xvid_bios endp
Xbios ends
X;------------------------------------------------
Xbios_data segment at 040h
X org 049h
Xvideo_mode db ? ; current video mode
Xn_cols dw ? ; number of columns in video display
X org 050h
Xcurs_pos dw 8 dup(?) ; cursor for each of 8 pages
Xcurs_mode dw ? ; cursor mode
Xactive_page db ? ; current active display page
Xvideo_base dw ? ; video port base
Xchip_ctrl db ? ; current setting of 3X8 register
Xbios_data ends
X;------------------------------------
Xintvec segment at 0 ; interrupt vector
X org 4*1Fh ; interrupt 1FH
Xuser_table dd ?
Xintvec ends
X;------------------------------------
X
XIFDEF iAPX286
X .286c ; allow 286/186-only instructions
XENDIF
X
X.LIST
!EOR!
echo extracting - hercbios.asm
sed 's/^X//' > hercbios.asm << '!EOR!'
X;*******************************************************
X;*
X;* Main program file for HERCBIOS
X;*
X;* Dave Tutelman - 8/86
X;*
X;*------------------------------------------------------
X;*
X;* INT10 -- acts as pre-handler for video interrupts
X;* (BIOS calls) for Hercules & SuperComputer
X;* monochrome graphics board. Calls real BIOS
X;* if not a Hercules special. Handled here are:
X;*
X;* Fn 0 Set mode (only 6 & 8)
X;* and all functions, when in mode 6 or 8.
X;* Actually, we've only implemented:
X;* Fn 2 Set cursor position
X;* Fn 3 Read cursor position
X;* Fn 5 New display page
X;* Fn 9 Write character with attribute
X;* Fn 10 Write character
X;* Fn 12 Write pixel
X;* Fn 13 Read pixel
X;* Fn 14 Teletypewriter-style character write
X;* Fn 15 Get video status
X;*
X;* The only allowable modes for these boards are:
X;* 6 IBM graphics (we handle it, but poor aspect ratio).
X;* 7 Monochrome (with 2 pages)
X;* 8 Hercules graphics mode.
X;*
X;**********************************************************
X;
XINCLUDE hercbios.h
X
Xextrn writechar:near,tty:near,scroll_up:near,scroll_down:near
Xextrn scr_start:word,scr_length:word,num_rows:byte
Xextrn wr_pixel:near
Xextrn end_herc:near
Xpublic exit_herc_bios,int10,vid_vector
Xpublic set_mode,set_curs,read_curs,new_page,status
X;-----------------------------------------
Xpage
X;************************************************************
X;*
X;* Install the Hercules video handler
X;*
X;************************************************************
Xcseg segment public
X assume cs:cseg,ds:cseg
X
X ORG 100h
X;
XSTART:
X;
X push ax
X push es
X push ds
X;
X xor ax,ax ; zero the acc
X mov es,ax ; ES points to zero (interrupt vector)
X ; Get ROM BIOS video entry point, and save in "rom_bios"
X mov ax,es:[4*VIDI]
X mov word ptr cs:rom_bios,ax
X mov ax,es:[4*VIDI+2]
X mov word ptr cs:rom_bios+2,ax
X ; Now plant the HERCBIOS entry point in interrupt vector
X mov ax,offset int10 ; address of video handler to AX
X mov es:[4*VIDI],ax ; and store it in interrupt vector 10H
X mov ax,cs ; same for the segment of video handler
X mov es:[4*VIDI+2],ax ; ...
X;
X; Leave the message that we're installed
X mov ax,cs ; DS:DX pointing to message
X mov ds,ax
X mov dx,offset install_msg
X mov ah,9 ; display-string function
X int 21h
X
X pop ds
X pop es
X pop ax
X;
X mov dx,offset end_herc ; set dx to end of this program
X int 27H ; terminate, but stay resident
X;
Xinstall_msg db "BIOS for Hercules-compatible Graphics - "
X db "(DMT Aug 1986)",10,13,'$'
Xpage
X;************************************************************
X;*
X;* Beginning of video interrupt handler
X;*
X;************************************************************
X;
X;
Xint10 proc far
X;
X sti ; allow further interrupts
X push ds ; save DS
X push ax ; save AX
X mov ax,bios_data ; bios data segment --> AX
X mov ds,ax ; now put bios data segment in DS
X assume ds:bios_data ; and tell assembler about it
X; ; check current mode
X mov ah,video_mode ; get current mode
X cmp ah,herc_mode ; test for a graphics mode
X je herc_bios
X cmp ah,ibm_mode
X je herc_bios
X; ; setmode to a graphics mode?
X pop ax ; restore AX
X push ax ; ...but leave it on stack
X cmp ax,0006 ; Fn = set to IBM hi-res mode?
X je herc_bios
X cmp ax,0008 ; Fn = set to Herc graphics mode?
X je herc_bios
X;
Xnorm_bios: ; if we get here, just go to real BIOS
X pop ax ; restore stack to pre-interrupt state
X pop ds
X db 0EAh ; opcode for FAR JUMP to rom_bios
Xrom_bios dd ? ; normal video bios address (in ROM)
X;
Xherc_bios: ; jump table for special Hercules BIOS
X;
X pop ax ; restore ax
X push bx ; save regs
X push cx
X push dx
X push si
X push di
X push es
X;
X push ax
X mov al,ah ; function # to AX
X xor ah,ah
X shl ax,1 ; *2 for word vector
X mov si,ax ; put in SI to index into vector
X pop ax ; restore old AX
X cmp si,offset vid_vec_end-offset vid_vector
X ; function number within range?
X jge exit_herc_bios ; function number out of range
X add si,offset vid_vector
X jmp word ptr cs:[si]
X ; jump to routine via vector
X;
X
Xvid_vector: ; jump vector for hercules video routines
X dw offset set_mode ; 0 = set mode
X dw offset exit_herc_bios ; 1 = cursor type (NA)
X dw offset set_curs ; 2 = set cursor position
X dw offset read_curs ; 3 = read cursor position
X dw offset exit_herc_bios ; 4 = light pen (NA)
X dw offset new_page ; 5 = choose active page
X dw offset scroll_up ; 6 = scroll up
X dw offset scroll_down ; 7 = scroll down
X dw offset exit_herc_bios ; 8 = read character (NA)
X dw offset writechar ; 9 = write char & attribute
X dw offset writechar ;10 = write character
X dw offset exit_herc_bios ;11 = set color palette (NA)
X dw offset wr_pixel ;12 = write pixel
X dw offset wr_pixel ;13 = read pixel
X dw offset tty ;14 = teletype write
X dw offset status ;15 = return video state
Xvid_vec_end:
X;
Xexit_herc_bios:
X pop es ; restore regs
X pop di
X pop si
X pop dx
X pop cx
X pop bx
X pop ds
X iret ; and return
Xpage
X;********************************************************************
X;*
X;* FUNCTION 0 - SET VIDEO MODE
X;*
X;* Only gets here to set a hi-res graphics mode
X;* 6=IBM
X;* 8=Hercules
X;* [ AX destroyed ]
X;*
X;*******************************************************************
X;
Xset_mode:
X; ; is it a graphics mode?
X cmp al,herc_mode ; set to hercules mode?
X je g_mode
X cmp al,ibm_mode ; set to IBM mode?
X je g_mode
X ; Neither. Leave it to normal BIOS
X pop es ; restore regs
X pop di
X pop si
X pop dx
X pop cx
X pop bx
X pop ds
X jmp vid_bios ; and go to MPX-16 BIOS
X;
Xg_mode: mov video_mode,al ; save video mode in BIOS data area
X mov active_page,ah ; zero the active page in BIOS data
X mov n_cols,90 ; 90 character columns in graphics mode
X;
X;* clear display area
X mov ax,pixbase ; get starting address
X mov es,ax ; page base to ES
X mov cx,8000H ; word counter
X mov di,0 ; start at beginning of display
X cld ; direction "up"
X xor ax,ax ; zero AX
X rep stosw ; write zero to both pages
X;
X;* load the 6845 internal registers
X;
X; ; first set up the loop
X push ds ; save DS
X mov ax,cs ; get cseg into DS
X mov ds,ax
X assume ds:cseg
X mov dx,vid_port ; 6845 index port address to DX
X mov si,offset vid_parm_table
X ; table pointer to SI
X mov cx,16 ; 16 parameters in table
X xor ax,ax ; zero AX (AH will be index counter)
X; ; now execute the loop
Xinit_6845_loop:
X mov al,ah ; index counter to AL
X out dx,al ; output index to 6845
X inc dx ; point DX to data reg
X mov al,[si] ; get table entry
X out dx,al ; output to 6845 data reg
X dec dx ; point DX back to index reg
X inc ah ; bump index counter
X inc si ; bump table pointer
X loop init_6845_loop
X pop ds ; restore DS
X assume ds:bios_data ; restore DS assumed
X;
X;* now set the 6845 control register
X mov dx,vid_port+4 ; control port address
X mov al,0AH ; graphics control byte
X cmp active_page,0 ; get current page
X je pg0_F0 ; skip if zero
X or al,80H ; page 1 to control byte
Xpg0_F0: out dx,al ; and ship to 6845
X mov chip_ctrl,al ; also save in bios data area
X;
X;* save cursor position (0,0) in bios data area
X xor ax,ax ; zero AX
X mov curs_pos,ax ; write zero to pg.0 cursor postion
X mov curs_pos+2,ax ; write zero to pg.1 cursor postion
X;
X;* initialize scrolling parameters
X;
X cmp video_mode,herc_mode
X je h_parm
X mov cs:scr_start,180 ; IBM parameters
X mov cs:scr_length,3690 ;
X mov cs:num_rows,42 ;
X jmp parm_done
Xh_parm: mov cs:scr_start,270 ; Herc parameters
X mov cs:scr_length,3645 ;
X mov cs:num_rows,28 ;
Xparm_done:
X;
X jmp exit_herc_bios
X;
X;* table of 6845 chip parameters
X;
Xvid_parm_table db 53,45,46,7,91,2,87,87,2,3,62H,3,0,0,0,0
X;vid_parm_table db 54,45,46,8,91,2,87,87,2,3,62H,3,0,0,0,0
X ;DMT's monitor
Xpage
X;********************************************************************
X;*
X;* FUNCTION 2 - SET CURSOR POSITION
X;*
X;* DX = new row (DH) and column (DL)
X;* BH = display page number
X;*
X;********************************************************************
X;
Xset_curs:
X;
X; * save in BIOS data area
X mov bl,bh ; page # to bl
X xor bh,bh ; zero bh (page # = BX)
X shl bx,1 ; times 2 for word
X mov curs_pos[bx],dx ; store in data area
X;
X; * if page # = active page, then we should actually move cursor
X; * However, cursor doesn't show in graphics mode, so we won't.
X;
X jmp exit_herc_bios
X;
Xpage
X;********************************************************************
X;*
X;* FUNCTION 3 - READ CURSOR POSITION
X;*
X;* on entry
X;* BH = display page number
X;*
X;* on exit
X;* CX = cursor type/size
X;* DX = current row (DH) and column (DL)
X;*
X;********************************************************************
X;
Xread_curs:
X; ; uncover the return portion of the stack
X pop es
X pop di
X pop si
X pop dx
X pop cx
X; ; now get the data and push onto stack
X push curs_mode ; cursor type to CX position in stack
X mov bl,bh ; page # to BX
X xor bh,bh
X shl bx,1 ; *2 for word offset
X push curs_pos[bx] ; cursor position for specified page
X ; to DX position in stack
X; ; refill the stack for return
X push si
X push di
X push es
X;
X jmp exit_herc_bios
Xpage
X;********************************************************************
X;*
X;* FUNCTION 5 - SELECT NEW DISPLAY PAGE
X;*
X;* AL = new display page number
X;*
X;********************************************************************
X;
Xnew_page:
X cmp al,2 ; page < 2?
X jl f5_1 ; yup
X jmp exit_herc_bios ; nope. can't do it.
X;
Xf5_1: mov active_page,al ; put away active page in bios data
X; * put starting address in 6845 register 12
X mov ah,al ; save page number in AH
X mov dx,vid_port ; index pointer address
X mov al,12 ; save in register 12
X out dx,al ; and set index pointer to 12
X mov al,ah ; restore page to AL
X ror al,1 ; page to high-order bit
X shr al,1 ; two bytes per word
X inc dx
X out dx,al ; ...and output it to register
X; * put control byte in 6845 port
X mov al,ah ; get back page number
X ror al,1 ; page to high-order bit
X or al,0AH ; create chip control byte
X mov chip_ctrl,al ; save it in data area
X mov dx,vid_port+4 ; control port address
X out dx,al ; send control byte to chip
X;
X jmp exit_herc_bios
Xpage
X;***********************************************************************
X;*
X;* FUNCTION 15 - RETURN VIDEO STATUS
X;*
X;* On exit:
X;* AL = current video mode
X;* AH = number of active display columns
X;* BH = current active page number
X;*
X;***********************************************************************
X;
Xstatus:
X; ; first uncover the stack
X pop es
X pop di
X pop si
X pop dx
X pop cx
X pop bx
X; ; now get the parameters needed
X mov al,video_mode
X mov ah,90 ; all our graphics modes have 90 cols
X mov bh,active_page
X; ; and push back onto the stack for return
X push bx
X push cx
X push dx
X push si
X push di
X push es
X;
X jmp exit_herc_bios
X;
Xint10 endp
X;
Xcseg ends
X end START
!EOR!
echo extracting - gchar.asm
sed 's/^X//' > gchar.asm << '!EOR!'
X;********************************************************************
X;*
X;* GRAPHIC CHARACTER HANDLING
X;*
X;* Dave Tutelman - 8/86
X;*
X;*-------------------------------------------------------------------
X;*
X;* Fn 6 Scroll up - not yet implemented
X;* Fn 7 Scroll down - not yet implemented
X;* Fn 9 Write character with attribute
X;* Fn 10 Write character normal
X;* Fn 14 Write character Teletypewriter style
X;*
X;* Also includes subroutines to:
X;* get_address convert page/row/col to display address
X;* do_char write a character to an address on display
X;* do_attrib change a display address to some attribute
X;* full_screen_scroll used by Fn 14, when it needs to scroll
X;* flash momentarily flash to reverse video and back
X;*
X;********************************************************************
X;
XINCLUDE hercbios.h
X
X;-----------------------------------------------
Xextrn exit_herc_bios:near
Xpublic writechar,scroll_up,scroll_down,tty
Xpublic scr_start,scr_length,num_rows
X;------------------------------------
Xcseg segment public
X assume cs:cseg,ds:bios_data
X;
X
X;**************************************************************
X;*
X;* FUNCTION 6 & 7 - SCROLL UP & DOWN
X;* (Placeholder only - not yet implemented)
X;*
X;* AL = Number of rows to scroll (if 0, blank scroll area)
X;* BH = Fill attribute (we ignore, since writechar destroys old attrib)
X;* CX = Upper left corner (CH=row, CL=col)
X;* DX = Lower right corner (DH=row, DL=col)
X;*
X;****************************************************************
X;
Xscroll_up:
Xscroll_down:
X;
X jmp exit_herc_bios
Xpage
X;********************************************************************
X;*
X;* FUNCTION 9 & 10 - WRITE A CHARACTER AT CURRENT CURSOR
X;*
X;* AL = character code to be written
X;* AH = 9 (write char with attribute) or 10 (write char normal)
X;* BL = new attribute (limited selection in graphics mode)
X;* BH = display page number
X;* CX = count of how many characters to write
X;*
X;********************************************************************
X;
Xwritechar:
X; ; Get the address corresponding to cursor[page]
X push bx
X mov bl,bh ; page to BX
X xor bh,bh
X shl bx,1 ; *2 for word pointer
X mov dx,curs_pos[bx] ; appropriate cursor position to DX
X pop bx
X call get_address ; get display address in DI
X;
Xwrchar_loop:
X; ; Write a character to that address
X call do_char ; arguments set up already
X;
X; ; If function 9, modify the character's attributes
X cmp ah,9 ; Function 9?
X jne no_attrib ; no, don't do attributes
X call do_attrib ; yes, and arguments already set up
Xno_attrib:
X;
X inc di ; move to next position, without moving
X ; the official cursor
X loop wrchar_loop ; continue until CX count exhausted
X jmp exit_herc_bios
Xpage
X;*****************************************************************
X;*
X;* FUNCTION 14 - TELETYPEWRITER-STYLE CHARACTER WRITE
X;*
X;* AL = Character to be written
X;*
X;******************************************************************
X;
Xtty:
X assume ds:bios_data
X mov bl,active_page ; active page to BX
X xor bh,bh
X mov dx,curs_pos[bx] ; get cursor for active page
X push bx
X mov bh,bl ; move page to BH
X call get_address ; address of character to DI
X pop bx
X;
X; ; process the character
X; ; check if CR
X cmp al,13 ; carriage return?
X jne not_cr
X mov dl,0 ; go to first column
X jmp fix_curs
X; ; check if LF
Xnot_cr: cmp al,10 ; line feed?
X jne not_lf
X inc dh ; next line
X jmp fix_curs
X; ; check if BS
Xnot_lf: cmp al,8 ; backspace?
X jne not_bs
X cmp dl,0 ; already first column?
X je fix_curs ; yup. do nothing
X dec dl ; nope. move cursor left one
X dec di ; also move address pointer left one
X mov al,32 ; set character to space
X call do_char ; and write the space, but don't move
X jmp fix_curs
X; ; check if BEL
Xnot_bs: cmp al,7 ; bell character?
X jne not_bl
X pop es ; restore registers
X pop di
X pop si
X pop dx
X pop cx
X pop bx
X pop ds
X jmp vid_bios ; ... and use the normal BIOS to ring the bell
X; call flash ; can't do BEL standard. Blink display instead
X; jmp fix_curs
X; ; ordinary printing character, so display it
Xnot_bl: call do_char ; write it to screen
X inc dl ; cursor one to the right
X;
X; ; now look at the cursor, do what's necessary to
X; ; fix it up, and save it away.
Xfix_curs:
X cmp dl,89 ; beyond last column?
X jle chk_scroll ; not yet
X xor dl,dl ; yes. do a CR
X inc dh ; ... and a LF
Xchk_scroll:
X cmp dh,cs:num_rows ; now see if we're beyond last row?
X jl exit_tty ; not yet
X call full_screen_scroll
X ; yes. Scroll the screen up one
X dec dh ; ... and scroll cursor, too.
X jmp chk_scroll
X;
Xexit_tty:
X mov curs_pos[bx],dx ; save cursor position
X jmp exit_herc_bios
Xpage
X;--------------------------------------------------------------------
X;
X; GET_ADDRESS SUBROUTINE
X;
X; BH = display page
X; DX = cursor position (DH=row, DL=col)
X;
X; returns:
X; DI = displacement of top row of pixels
X;
X;--------------------------------------------------------------------
X;
Xget_address:
X push cx ; save it
X
X; ; compute display address from cursor_pos
X mov cl,dh ; get row # in cx
X xor ch,ch
X shl cx,1 ; begin fast multiply by 90 (1011010 B)
X mov di,cx
X shl cx,1
X shl cx,1
X add di,cx
X shl cx,1
X add di,cx
X shl cx,1
X shl cx,1
X add di,cx ; end fast multiply by 90
X mov cx,di ; copy answer back to cx
X shl di,1 ; *2 for ibm graphics mode
X cmp video_mode,herc_mode
X jne ibm_ad ; not herc mode
X add di,cx ; *3 for herc mode
Xibm_ad: xor ch,ch ; columns in CX
X mov cl,dl
X add di,cx ; add in col. address in DI
X cmp bh,0 ; if page 1, set high-order bit of address
X je pg0
X or di,8000H
Xpg0:
X; ; address now in DI
X;
X pop cx ; restore it
X ret
Xpage
X;--------------------------------------------------------------------
X;
X; DO_CHAR SUBROUTINE
X;
X; AL = character to write
X; DI = diplacement (address) of top row of pixels
X;
X; Note: SI and ES are destroyed
X;
X;--------------------------------------------------------------------
X;
Xdo_char:
X push ax
X push bx
X push cx
X push di
X push ds
X;
X; ; get scan pattern table pointer into BX
X cmp video_mode,herc_mode
X je herc_1
X mov bx,offset ibm_pattern
X ; IBM graphics mode - use appropriate table
X jmp c_1
Xherc_1: mov bx,offset herc_pattern
X ; herc graphics mode - use appropriate table
Xc_1:
X;
X; ; set up source address registers
X xor ah,ah ; character to SI
X mov si,ax
XIFDEF iAPX286
X shl si,3 ; *8 for 8-byte table entry
XELSE
X shl si,1 ; *8 for 8-byte table entry
X shl si,1
X shl si,1
XENDIF
X ; next, find beginning of table
X cmp al,7Fh ; ROM or user table?
X jg u_tbl
X ; ROM table
X add si,charbase ; character table base added to offset
X mov ax,mpx_bios ; BIOS code segment to DS
X mov ds,ax
X jmp c_2
Xu_tbl: ; user table
X xor ax,ax ; zero (interrupt vector) to DS
X mov ds,ax
X mov ax,si ; save table offset in AX
X assume ds:intvec
X lds si,user_table ; load DS:SI from interrupt vector
X add si,ax ; add offset into table base
Xc_2:
X;
X; ; set up destination address registers
X mov ax,pixbase ; get display segment in ES
X mov es,ax
X ; displacement already in DI
X;
X;
X; ; transfer the character
X mov ax,di ; save top-row displacement in AX
X mov cx,8 ; transfer 8 rows
X cld ; direction = up
Xc_loop: mov di,ax ; top-row displacement
X add di,cs:[bx] ; add entry from scan-pattern table
X movsb ; actually transfer a byte and bump SI & DI
X add bx,2 ; next entry in scan-pattern table
X loop c_loop
X;
X; ; if hercules mode, blank the extra rows
X pop ds ; restore DS to Bios data
X assume ds:bios_data
X cmp video_mode,herc_mode
X jne c_3
X ; Hercules mode
X mov si,ax ; don't need SI. Save top-row displacement
X xor ax,ax ; zero AX
X mov cx,4 ; four rows to blank
X cld
Xc_blnk: mov di,si ; top-row displacement
X add di,cs:[bx] ; add entry from scan-pattern table
X stosb ; transfer a zero byte
X add bx,2 ; next entry in scan-pattern table
X loop c_blnk
Xc_3:
X;
X; ; clean up and return
X pop di
X pop cx
X pop bx
X pop ax
X ret
Xpage
X;---------------------------------------------------------------------
X;
X; DO_ATTRIB SUBROUTINE
X;
X; BL = attribute byte
X; DI = displacement (address) of top row of pixels
X; ES is destroyed
X;
X; Because attributes don't "just happen" in graphics mode, here's
X; what we have to transform them to.
X;
X; CODE USUALLY MEANS IBM MODE HERC MODE
X; 00 invisible invisible invisible
X; 01 underline [normal] underline
X; 07 normal normal normal
X; 0F hi-intens [rev video] [rev video]
X; 70 rev video rev video rev video
X;
X; Anything else displays as normal
X; Note that there's no way to make blinking happen.
X;
X;-----------------------------------------------------------------------
X;
Xdo_attrib:
X assume ds:bios_data
X push ax
X mov ax,pixbase ; Display base to ES
X mov es,ax
X pop ax
X;
X; ; which attribute, if any?
X and bl,7Fh ; mask off blink bit
X cmp bl,0 ; invisible?
X je invisible
X cmp bl,0Fh ; reverse video? (instead of bright)
X je reverse
X cmp bl,70H ; reverse video?
X je reverse
X cmp bl,01 ; underline?
X je underline
X ret ; none of the above. Display normal.
X;
X; ; underline the character
Xunderline:
X cmp video_mode,herc_mode
X je ul_1
X ret ; don't do it for IBM mode
Xul_1: mov byte ptr es:[di+40B4h],0FFh
X ; move ones to 11th line of pixel array
X ; 40B4h is the 11th entry in herc_pattern
X ret
X;
X; ; make it invisible
Xinvisible:
X push ax
X push bx
X push cx
X push dx
X xor ax,ax ; zero the AX
X cmp video_mode,herc_mode
X je herc_3
X mov bx,offset ibm_pattern
X ; point to scan pattern
X jmp inv_1
Xherc_3: mov bx,offset herc_pattern
X ; point to scan pattern
Xinv_1: mov dx,di ; save addr of top row of pixels in DX
X mov cx,8 ; 8 bytes to be moved
X cld ; direction = up
Xinvis_loop:
X mov di,dx ; top row address
X add di,cs:[bx] ; add scan-table offset
X stosb ; move a zero byte
X add bx,2 ; bump the scan-table pointer
X loop invis_loop
X pop dx
X pop cx
X pop bx
X pop ax
X ret
X;
X; ; reverse video
Xreverse:
X push bx
X push cx
X push dx
X cmp video_mode,herc_mode
X je herc_4
X mov bx,offset ibm_pattern
X ; point to scan pattern
X mov cx,8 ; 8 scan lines for IBM mode
X jmp rev_1
Xherc_4: mov bx,offset herc_pattern
X ; point to scan pattern
X mov cx,12 ; 12 scan lines for Hercules mode
Xrev_1: mov dx,di ; save addr of top row of pixels in DX
X cld ; direction = up
Xrev_loop:
X mov di,dx ; top row address
X add di,cs:[bx] ; add scan-table offset
X not es:byte ptr[di] ; invert one scan line
X add bx,2 ; bump the scan-table pointer
X loop rev_loop
X pop dx
X pop cx
X pop bx
X ret
Xpage
X;--------------------------------------------------------------
X;
X; SUBROUTINE FULL_SCREEN_SCROLL
X;
X; This scrolls the entire screen up one print line (8 or 12 pixels).
X; Actually, we'll protect one line on the bottom (e.g.-function keys).
X;
X;-----------------------------------------------------------------
X;
X; ; A few constants, initialized by set_mode
Xnum_rows db ? ; number of rows in display
X ; = 42 (IBM) or 28 (Herc)
Xscr_start dw ? ; 2*90 or 3*90 depending on mode
Xscr_length dw ? ; number of words to transfer in a sweep
X ; = 41*start /2 = 3690 (IBM)
X ; = 27*start /2 = 3645 (Herc)
X;
Xfull_screen_scroll:
X assume ds:bios_data
X push ds
X push ax
X push cx
X mov ax,pixbase ; start getting display segment
X cmp active_page,0 ; page 0?
X je scr_pg0
X add ax,800H ; page 1. bump by half of 64K
Xscr_pg0:
X mov ds,ax ; save display segment in DS
X mov es,ax ; ... and in ES
X;
X xor ax,ax ; zero AX
X call scr_shift
X mov ax,2000H ; bump interlace counter
X call scr_shift
X mov ax,4000H
X call scr_shift
X mov ax,6000H
X call scr_shift
X;
X pop cx
X pop ax
X pop ds
X ret
X;
X;
X; scr_shift does the actual work of scrolling, one set of interlace
X; lines at a time.
X;
Xscr_shift:
X cld ; block moves will be UP
X mov di,ax ; interlace scan ID to DI
X mov si,ax ; ... and to SI
X add si,cs:scr_start
X ; but bump by "start"
X mov cx,cs:scr_length
X ; set counter for transfer
X rep movsw ; and scroll a set of lines
X xor ax,ax ; set up a zero word
X mov cx,cs:scr_start ; set counter for one more line
X shr cx,1 ; /2 for word transfers
X rep stosw ; and blank the line
X ret
Xpage
X;-----------------------------------------------------------
X;
X; SUBROUTINE FLASH
X;
X; Flashes the screen inverse video and back to normal.
X; Used in place of an audible bell.
X;
X;-------------------------------------------------------------
X;
Xflash:
X push cx
X push di
X push es
X;
X mov di,pixbase ; get display area base
X cmp active_page,0 ; page 0?
X je pg0_f
X add di,800H ; no, page 1
Xpg0_f: mov es,di ; put resulting pointer to display in ES
X;
X; ; loop to invert screen
X xor di,di ; point to beginning of display area
X mov cx,4000H ; number of words to invert
Xflash_loop_1:
X not word ptr es:[di]
X ; invert one location
X add di,2 ; bump location pointer a word
X loop flash_loop_1
X;
X; ; and invert it back to normal
X xor di,di ; point to beginning of display area
X mov cx,4000H ; number of words to invert
Xflash_loop_2:
X not word ptr es:[di]
X ; invert one location
X add di,2 ; bump location pointer a word
X loop flash_loop_2
X;
X pop es
X pop di
X pop cx
X ret
Xpage
X;*****************************************************
X;* Data areas for character handling
X;*****************************************************
X;
Xpixels db 12 dup(?) ; 12 bytes for pixel pattern
Xibm_pattern dw 0000h,2000h,4000h,6000h,005Ah,205Ah,405Ah,605Ah
Xherc_pattern dw 4000h,6000h,005Ah,205Ah,405Ah,605Ah,00B4h,20B4h
Xblank_pattern dw 0000h,2000h,40B4h,60B4h
X;
X;
Xcseg ends
X end
!EOR!
echo extracting - graph.asm
sed 's/^X//' > graph.asm << '!EOR!'
X;*******************************************************
X;*
X;* SET OF GRAPHICS ROUTINES FOR HERCULES BIOS
X;*
X;* Dave Tutelman - 8/86
X;*
X;*-------------------------------------------------------
X;*
X;* do_pixel: draws, erases, or reads a pixel, given an
X;* offset and mask.
X;*
X;**********************************************************
X;
XINCLUDE hercbios.h
X
X;------------------------------------------
Xpublic wr_pixel,end_herc
Xextrn exit_herc_bios:near
X;-----------------------------------------
X;
Xcseg segment public
X assume cs:cseg,ds:bios_data
X;
X;
X;**********************************************
X;*
X;* read or write a pixel:
X;* DX = row # ( y )
X;* CX = col # ( x )
X;* AH = 12 for write, 13 for read
X;* AL = value (0,1, if bit 7=1 EXOR the value)
X;*
X;**********************************************
X;
Xwr_pixel:
X mov bh,video_mode ; check for valid mode
X cmp bh,herc_mode
X je do_pixel
X cmp bh,ibm_mode
X je do_pixel
X jmp exit_herc_bios ; invalid mode. don't do it.
X;
Xdo_pixel:
X push ax ; save function and pixel value
X;
X; ; first compute the address of byte to be modified
X; ; = 90*[row/4] + [col/8] + 2^D*[row/4] + 2^F*page
X mov bh,cl ; col (low order) in BH
X mov bl,dl ; row (low order) in BL
X and bx,0703H ; mask the col & row remainders
XIFDEF iAPX286
X shr cx,3 ; col / 8
X shr dx,2 ; row / 4
X mov al,90
X mul dx ; AX = 90*[ row/4 ]
X add ax,cx ; ... + col/8
X shl bl,5 ; align row remainder
XELSE ; same as above, obscure but fast for 8086
X shr cx,1 ; divide col by 8
X shr cx,1
X shr cx,1
X shr dx,1 ; divide row by 4
X shr dx,1
X shl dx,1 ; begin fast multiply by 90 (1011010 B)
X mov ax,dx
X shl dx,1
X shl dx,1
X add ax,dx
X shl dx,1
X add ax,dx
X shl dx,1
X shl dx,1
X add ax,dx ; end fast multiply by 90
X add ax,cx ; add on the col/8
X shl bl,1 ; align row remainder
X shl bl,1
X shl bl,1
X shl bl,1
X shl bl,1
XENDIF
X add ah,bl ; use aligned row remainder
X cmp active_page,0 ; page 0 active?
X je end_adr_calc ; yup
X or ah,80H ; page 1 active. Set MSB of address
Xend_adr_calc: ; address of byte is now in AX
X;
X mov dx,pixbase ; base of pixel display to DX
X mov es,dx ; ...and thence to segment reg
X mov si,ax ; address of byte w/ pixel to index reg
X mov cl,bh ; bit addr in byte
X mov al,80H ; '1000 0000' in AL
X shr al,cl ; shift mask to line up with bit to read/write
X mov bl,al
X;
X pop bx ; now retrieve original AX into BX
X ; function=BH, pixel value=BL
X cmp bh,13 ; what to do with the pixel?
X je read_pix ; read the pixel.
X cmp bl,0 ; write the pixel. But how?
X je clr_pix ; clear the pixel
X jl exor_pix ; exclusive-or the pixel
X;
Xset_pix: ; set the pixel
X or es:[si],al ; or the mask with the right byte
X jmp exit_herc_bios
X;
Xclr_pix: ;clear the pixel
X not al ; invert the mask, so zero on bit to be cleared
X and es:[si],al ; and the mask with the right byte
X jmp exit_herc_bios
X;
Xexor_pix: ; exclusive-or the pixel
X mov ah,07fH ; mask to rid 7th bit
X and ah,bl ; pixval w/o XOR flag
X jnz do_exor ; ExOr with a 1?
X jmp exit_herc_bios ; no! XOR (0,x) = x. just return.
Xdo_exor:
X xor es:[si],al ; EXOR the pixel with the mask.
X jmp exit_herc_bios
X;
Xread_pix: ; read the pixel
X and al,es:[si] ; read the bit into AL
X jz rd_zro
X mov al,1 ; if it ain't zero, it's one
Xrd_zro: jmp exit_herc_bios
X;
X;
Xend_herc: ; label for end of package. Used by hercbios
X ; to install it.
X;
Xcseg ends
X end
!EOR!
echo extracting - makefile
sed 's/^X//' > makefile << '!EOR!'
X# Makefile for HERCBIOS.COM
XSRC=hercbios gchar graph
XDEST=a:
X
Xhercbios.com : hercbios.obj gchar.obj graph.obj
X link hercbios gchar graph,,/MAP;
X exe2bin hercbios.exe hercbios.com
X del hercbios.exe
X
Xhercbios.obj : hercbios.asm hercbios.h
Xgchar.obj : gchar.asm hercbios.h
Xgraph.obj : graph.asm hercbios.h
X
X
X# Makes for the demo & test program, using deSmet C
X
Xtestpix.exe : testpix.o hercpixl.o
X bind testpix hercpixl
X
Xtestpix.o : testpix.c
X c88 testpix
X
Xhercpixl.o : hercpixl.c
X c88 hercpixl
X
X# Make a backup or distribution disk
Xbackup :
X for %f in ($(SRC)) do copy %f.asm $(DEST)
X copy hercbios.h $(DEST)
X copy hercbios.com $(DEST)
X copy hercbios.doc $(DEST)
X copy makefile $(DEST)
X
Xdistrib :
X make backup
X copy hercpixl.c $(DEST)
X copy testpix.* $(DEST)
X copy hcharset.* $(DEST)
!EOR!
echo extracting - hcharset.asm
sed 's/^X//' > hcharset.asm << '!EOR!'
X;**************************************************************
X;*
X;* Tests Hercules BIOS, specifically the functions 9 & 10
X;* to put characters on the screen in graphics mode.
X;*
X;***************************************************************
XVIDI equ 10H ; video interrupt, 10H (50H for debug)
Xcseg segment common
X assume cs:cseg,ds:cseg
XSTART proc
X; ; prompt for IBM or Hercules graphics mode
X mov ah,9 ; DOS 9 = display string
X mov dx,offset mode_prmt+100H
X ; display mode prompt
X int 21H ; DOS function
X mov ah,1 ; DOS 1 = kbd input
X int 21H
X mov bl,al ; input char --> BL
X mov ax,6 ; ibm graphics mode
X cmp bl,"h" ; input "h" for Hercules
X jne i_mode
X add ax,2 ; hercules mode
Xi_mode: int VIDI
X;
X xor bh,bh ; page 0
X mov bl,7 ; normal attribute
X mov dh,1 ; cursor at <1,1> to start
X mov dl,1
X;
X mov cx,24 ; do 24 rows
Xrow: push cx ; save row counter
X inc dh ; next row
X mov dl,0 ; back to first column
X mov ah,2 ; cursor move function
X int VIDI
X; ; compute video mode
X mov bl,dh ; row # to BL
X xor bh,bh
X shr bl,1 ; 4 rows per mode
X shr bl,1
X mov bl,mode_seq[bx+100H] ; index into mode sequence for mode
X;
X; ; for debug, first print [row+64]
X mov al,dh
X add al,64
X mov ah,10 ; fn 10 prints w/o attributes
X mov cx,1
X int VIDI
X;
X xor bh,bh ; page 0
X mov cx,64 ; each row 64 characters
Xachar: push cx ; save char counter
X mov ah,9 ; write_char function
X mov al,dh ; character = col + (row mod 2)*64
X and al,1 ; row mod 2
X ror al,1 ; *128
X shr al,1
X add al,dl ; + col
X mov cx,1 ; write one of them
X int VIDI
X inc dl ; increment row counter
X mov ah,2 ; cursor move function
X int VIDI
X pop cx ; restore character counter
X loop achar
X pop cx ; restore row counter
X loop row
X;
X; ; draw a line where it should start
X mov dx,5 ; row 5
X mov cx,0 ; col 0
Xline: push cx
X push dx
X mov ax,0C01H ; function 12=pixel
X int VIDI
X pop dx
X pop cx
X inc cx ; step col
X cmp cx,700 ; ...until 700
X jle line
X;
X; ; wait for a keystroke
X mov ah,1
X int 21H
X;
X mov ax,7 ; back to alpha mode
X int VIDI
X;
X; ; Now return to system
X xor ax,ax ; zero --> AX
X int 21H ; DOS function call 0 - terminate normally
X;
Xmode_prmt db "hercules or ibm mode? [ibm] $"
Xmode_seq db 7,0Fh,1,70h,0,9 ; sequence norm,hi,ul,rev,invis,norm
XSTART endp
Xcseg ends
!EOR!
echo extracting - hercpixl.c
sed 's/^X//' > hercpixl.c << '!EOR!'
X/*
X * HERCPIXL.C
X * Dave Tutelman - last modified 8/86
X *
X * This is a set of basic graphic routines for the Hercules
X * Board (or at least the SuperComputer version of it; I assume
X * that they work with the real thing).
X * alfa () puts us in alphanumeric mode.
X * grafix (page) puts us in graphics mode in page 0 or 1
X * pixel (x,y,val) puts a pixel at <x,y>. Bright dot if
X * val=1, dark dot if val=0.
X * dchar (x,y,c) puts character "c" at <x,y>. Note that
X * character raster is 90 x 29.
X * swpage (page) switches to a different page.
X * waitkey () just waits till a key is pressed.
X *
X * Actually, the routines should work with any board, since the
X * BIOS calls are used throughout. It's Hercules-specific only
X * because I've defined the graphics and alpha modes for my
X * Hercules BIOS.
X *
X * Compile with deSmet C.
X */
X
X#define VIDI 0x10 /* video interrupt, normally 10H */
X#define KBD 0x16 /* keyboard interrupt */
X#define ALFA_MODE 7 /* monochrome alpha mode */
X#define GRAF_MODE 8 /* Hercules graphics mode */
X
Xint page = 0;
Xextern unsigned _rax,_rbx,_rcx,_rdx;
X
X/*
X * This puts us back in alphanumeric mode
X */
X
Xalfa (dummy)
X unsigned int dummy;
X{
X _rax = ALFA_MODE; /* mono 80-col mode */
X _doint ( VIDI ); /* set mode */
X}
X
X/*
X * This one switches us to hercules graphics mode
X * in page 0 or 1
X */
X
Xgrafix (newpage)
X int newpage;
X{
X
X _rax = GRAF_MODE; /* herc grafix mode */
X _doint ( VIDI ); /* set mode */
X
X /* now set the page */
X swpage (newpage);
X}
X
X/*
X * This writes a pixel at (x,y), where (0,0) is the upper-left
X * corner of the screen. If val = 0 then the pixel is erased.
X */
X
Xpixel (x, y, val)
X int x, y, val;
X{
X
X _rax = 0x0C00 + val; /* function 12 */
X _rcx = x;
X _rdx = y;
X _doint ( VIDI ); /* set mode */
X
X}
X
X
X/*
X * dchar (x,y,c) puts character "c" at <x,y>. Note that
X * character raster is 90 x 25.
X */
X
Xdchar (x,y,c)
X int x,y;
X char c;
X{
X
X _rax = 2*256; /* AH=Fn#2 */
X _rdx = 256*y + x; /* DH=row, DX=col */
X _rbx = page * 256; /* BH=page */
X _doint (VIDI); /* set cursor */
X
X _rax = 10*256 + (int) c; /* AH=Fn#10, AL=char */
X _rbx = page * 256; /* BH=page */
X _rcx = 1; /* CX=count */
X _doint (VIDI); /* write character */
X}
X
X
X/*
X * This one switches us to a different page, without changing
X * the contents of that page.
X */
X
Xswpage (newpage)
X int newpage;
X{
X page = newpage;
X _rax = 0x500 + page; /* new page function */
X _doint ( VIDI ); /* interrupt call */
X}
X
X
Xwaitkey ()
X{
X _rax = 0; /* keyboard blocking read function */
X _doint (KBD);
X}
!EOR!
echo extracting - testpix.c
sed 's/^X//' > testpix.c << '!EOR!'
X
X/* MAIN tests PIXEL by drawing lines on the screen */
X
X#include "stdio.h"
X
Xmain ()
X{
X int i,j;
X char line [90];
X
X /* first clear screen */
X grafix (0);
X
X /* now draw a couple of lines */
X for (i=0; i<696; i++)
X {
X pixel (i, i/2, 1);
X pixel (i, 348 - i/2, 1);
X }
X
X waitkey(); /* wait for CR */
X
X /* a different pattern on page 1 */
X swpage (1);
X for (i=0; i<720; i++)
X for (j=0; j<348; j=j+50)
X pixel (i,j,1);
X for (i=0; i<720; i=i+90)
X for (j=0; j<348; j++)
X pixel (i,j,1);
X
X /* switch back and forth a couple of times */
X waitkey();
X swpage (0);
X waitkey();
X swpage (1);
X waitkey();
X swpage (0);
X waitkey();
X swpage (1);
X waitkey();
X
X#ifndef NOTONE
X /* add some writing */
X dline (10, 4, "Hello, there!");
X dline (10, 5, "Second LINE of text.");
X dline (10, 6, "all on display page 1.");
X
X waitkey();
X for (i=0; i<8; i++)
X for (j=0; j<32; j++)
X dchar (j+5, i+13, (char) (32*i+j));
X
X waitkey();
X#endif
X /* repeat for page 0 */
X swpage (0);
X
X#ifndef NOTZERO
X /* add some writing */
X dline (10, 4, "Hello, there!");
X dline (10, 5, "Second LINE of text.");
X dline (10, 6, "this time on display page 0.");
X
X waitkey();
X for (i=0; i<8; i++)
X for (j=0; j<32; j++)
X dchar (j+5, i+13, (char) (32*i+j));
X#endif
X
X waitkey();
X
X /* back to alpha mode */
X waitkey();
X alfa();
X}
X
Xdline (x, y, chstr) /* write character-string at x,y */
X int x,y;
X char chstr [90];
X{
X int i;
X char *p;
X
X i=0;
X for ( p=chstr; *p != '\0'; p++ )
X {
X dchar ( x+i, y, *p );
X i++;
X }
X}
!EOR!
More information about the Comp.sources.unix
mailing list