home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
asm
/
a86
/
bios
/
bios.8
next >
Wrap
Text File
|
1989-04-30
|
22KB
|
462 lines
;---------------
; BIOS module for the D86 debugger
;---------------
; Copyright 1987,88 Eric Isaacson. All rights reserved. Permission to
; copy and use this module is granted ONLY for machines registered for both
; the A86 assembler and the D86 debugger.
; Current support: IBM-PC, Wang PC, TI-PC, Sanyo 555, Tandy 2000,
; and Sirius/Victor 9000, DEC RAINBOW, and Zenith Z-100.
; This module defines the BIOS interface for my D86 debugger. I am publishing
; it to assist those who wish to assist me in implementing D86 on machines not
; BIOS-compatible with the IBM-PC. To support a non-standard BIOS, we must
; provide new keyboard codes, new action routines, and several other data
; quantities. This module provides a routine BIOS_INIT that sets everything
; up according to the machine being used. BIOS_INIT must do four things:
;
; 1. The routine must figure out what machine we are running on. The best
; way to do this is to find a machine-specific identifier in a fixed
; area of memory (ROM or the BIOS). If you can locate such an identifier,
; you can simply create an entry in the BIOS_SIGS structure below.
;
; 2. The routine must point SI to a special data structure (which I'll
; describe shortly), then call the routine NEW_KEYS, to propagate the
; items in the structure to the necessary places throughout the debugger.
;
; 3. The routine must perform any initializations necessary for this BIOS.
; For example, WANG_CONFIG locates and stores the port number for hardware
; that enables video access on the Wang.
;
; 4. The routine must decide if the debugger is running on the same screen as
; the user program. If it is, it must move the user's cursor to the lower
; left corner of the screen.
;
; The structure fed to NEW_KEYS contains all the data necessary for ongoing
; debugger execution under the new BIOS. See the structure WANG_KEYS for a
; prototype. The structure consists of the following:
;
; * a byte giving the keyboard code for the debugger's HELP key.
;
; * a byte declaring the difference between your BIOS's key codes for
; function keys, and the IBM BIOS's key codes. Your BIOS_KEY must return
; consecutive values for the function keys F1 through F10. You should
; declare this byte to be X - FUNC, where X is one less than the code
; returned by the F1 key. For example, since the Wang F1 key returns hex
; 080, the byte is declared 07F - FUNC.
; * a number of bytes giving code values for all the other control keys
; used by the debugger. This list will be expanding with new versions;
; see WANG_KEYS for the current version's list. You should precede the list
; with the L1 label, and follow it with the declaration N_CONTROL_KEYS EQU
; $-L1, exactly as shown. Don't change the name N_CONTROL_KEYS; the
; redeclaration of the same name insures that you've gotten the right number
; of codes into the table.
;
; * a word pointing to a message string with the name of the help-key. If your
; keyboard has a key labelled HELP, use the name HELP_HELP as in WANG_KEYS.
; If there is another key nonexistent on the IBM-PC (e.g. F11), then put
; a new name (e.g. F11_HELP) following DW; I'll supply the definition for
; the new name. If there is no extra key and no HELP key, use Alt-F10 as
; on the IBM-PC, and declare DW ALTF10_HELP here.
;
; * the label L2: to be used to verify the number of following bytes.
;
; * pointers to your BIOS's versions of the procedures VID_COPY, VID_ATTR,
; VID_FIX, BIOS_BELL, and BIOS_KEY, described shortly. Substitute the name
; of your machine for VID and BIOS in the generic names; e.g. the WANG_KEYS
; structure has WANG_COPY, WANG_ATTR, WANG_BELL, and WANG_KEY.
;
; * a word giving the segment register value for video memory on your machine.
; The debugger will supply this value in the ES register when it calls
; VID_COPY and VID_ATTR. That is all the debugger does with it; so this
; value can really be anything that the BIOS's versions of VID_COPY and
; VID_ATTR want.
;
; * a byte giving the attribute value for normal video. This attribute will
; be in effect for the entire debugger screen, except for the location of
; the debugger's cursor.
;
; * a byte giving the attribute value for reverse video. This attribute will
; be used to mark the debugger cursor.
;
; * the declaration N_BIOS_CALLS EQU ($-L2)/2 Again, don't change the name;
; the redeclaration of the name insures you didn't leave anything out.
;
; This completes the description of the structure fed to NEW_KEYS. After
; BIOS_INIT is called, the debugger will keep calling 7 action routines to
; perform its interactive I/O. The routines must perform actions as
; follows:
; VID_COPY copies CL bytes of characters from DS:SI to the video memory whose
; location is given by ES:DI. The characters should have the attribute
; NORM_ATTR, which the caller will place into AH for VID_COPY's convenience.
; VID_COPY must place the character byte and the attribute byte into each
; output video word. VID_COPY must return with BL preserved, the high byte
; of SI preserved (it will be if you leave SI pointing beyond the bytes
; copied), and DI advanced beyond the video memory just output. The caller
; assumes that video memory can be found at the value of VIDEO_SEG set by
; BIOS_INIT, starting at offset 0, and proceeding consecutively, one 16-bit
; memory word for every character. The caller will set CH=0 for its first
; call, so that VID_COPY can use CX as the count; but if it does, it must
; return CH=0 for subsequent calls.
; VID_ATTR places the attribute byte AL into the video word whose location is
; given by ES:DI. The character byte of the video word must not be disturbed.
; VID_FIX restores a video screen that might have been clobbered by programs
; external to the debugger. If VID_COPY copies all characters to video memory
; every time, then VID_FIX should RET without doing anything. If, however,
; VID_COPY tries to keep track of which characters are already on the screen,
; and suppress video output for those that are, then VID_FIX should disable
; the suppression feature, call the debugger's routine REFRESH to update the
; whole screen, then re-enable the suppression feature.
; BIOS_BELL rings the bell. NOTE that it is not acceptible for BIOS_BELL to
; use the MS-DOS write routine to send a bell control-code to standard output;
; if it did, then the debugger couldn't debug programs that have redirected
; their standard output-- the bell code would go to the user program's output
; file, and not be translated into a beep.
; BIOS_KEY returns in AL a code for a single keystroke. The code should be
; compatible with the values placed into the debugger's function tables by
; BIOS_INIT. If there is no keystroke available, BIOS_KEY should wait until
; there is one. BIOS_KEY should return on each individual key, and not wait
; for any line-editing to take place.
; BIOS_SAVE saves whatever there is about the user program's BIOS state that
; might be clobbered by the debugger. Currently, the only such thing is
; the user's cursor position on the Sanyo. So on all machines but the Sanyo,
; this is a "do-nothing" routine.
; BIOS_RESTORE restores the BIOS state saved by BIOS_SAVE. Again, this routine
; does nothing except on the Sanyo, on which it restores the user cursor
; position, clobbered because D86 must use BIOS calls to write to the Sanyo
; screen.
BIOS_SIGNATURE MACRO
DB #1 ; case number for the machine being sought
DB #NL-2 ; number of far pointers to look at
DB >M2 ; length byte for the following string
M1:
DB #2 ; BIOS signature string we are looking for
M2 EQU $-M1 ; we calculate the forward-reference length byte here
#RX3L ; loop for remaining macro operands
DD #X ; far pointers to each place where the string might be found
#ER
#EM
BIOS_SIGS:
BIOS_SIGNATURE 6,'Texas I',0F400:0A022
BIOS_SIGNATURE 7,'Tandy' ,0FC00:002F ,0FC00:0032
BIOS_SIGNATURE 10,'Rainbow',0FE00:0166 ,0FC00:03F2, 0FE00:0163
BIOS_SIGNATURE 12, 0E9 ,040:0
DB 0FF ; terminator byte
L0: ; jump table for each type of machine
DW IBM_MONO_CONFIG ; 1
DW IBM_CGA_CONFIG ; 2
DW IBM_EGA_CONFIG ; 3
DW IBM_CONFIG ; 4
DW WANG_CONFIG ; 5
DW TIPC_CONFIG ; 6
DW TANDY_CONFIG ; 7
DW SANYO_CONFIG ; 8
DW SIRIUS_CONFIG ; 9
DW DEC_CONFIG ; 10
dw ibm_mono_config
; DW HP_CONFIG ; 11
DW Z100_CONFIG ; 12
L6 EQU ($-L0)/2
L2: ; machine type AL is not 1
CMP AL,0FF ; is it 0FF?
JNZ >L7 ; jump if not -- we are on an IBM-PC
MOV ES,AX,0FFFF ; it was-- address the end of ROM
ES CMP AX,[6] ; are there FFFF's beyond the boot-JMP?
MOV AL,8 ; load Sanyo index, in case there were
JE >L1 ; jump if there were-- it is a Sanyo
L7: ; all non-IBM tests fail: let's assume IBM compatibility
MOV ES,CS ; point ES to CS, where IBM_CONFIG wants it
MOV DH,0 ; the case number is zero-- no EGA vs. CGA decided yet
JMP IBM_CONFIG ; jump to IBM-compatible configuration code
BIOS_INIT:
MOV DS,CS ; insure that DS points to our code segment
MOV AL,SWITCH'B' ; fetch the BIOS switch setting if there was one
DEC AX ; eliminate 0 setting from consideration
CMP AL,L6 ; was there an explicit BIOS switch setting?
JB >L5 ; jump if there was, to the matching case
MOV SI,BIOS_SIGS ; point to the BIOS-signatures data structure
LODSW ; fetch the first case number and far-pointer-count
L3: ; loop here for each subsequent machine's record
XCHG DX,AX ; swap the case number to DL, pointers count to DH
LODSB ; fetch the length byte
CBW ; extend the length AL to AX
XCHG CX,AX ; swap the length into CX
MOV BX,SI ; save the string pointer in BX
ADD SI,CX ; advance SI beyond the string, to the far pointers
L8: ; loop here for each far pointer
LODSW ; fetch the offset of the pointer
XCHG DI,AX ; swap the offset into DI
LODSW ; fetch the segment of the pointer
MOV ES,AX ; move the segment into ES
XCHG BX,SI ; swap the string pointer into SI
PUSH CX,SI ; save the count
REPE CMPSB ; see if the string is at this far pointer
POP SI,CX ; restore the count
XCHG SI,BX ; swap string pointer to BX, template pointer to SI
MOV AL,DL ; fetch the case number in case the string matched
JE >L1 ; jump if the string matched to act upon the case
DEC DH ; count down far pointers
JNZ L8 ; loop if there is another far pointer
LODSW ; fetch the next record's case number and pointers count
CMP AL,0FF ; did we load the terminator byte instead?
JNE L3 ; loop if not, to process the next machine record
MOV AL,0 ; no string match: load the machine type, already plugged in
MACHINE_TYPE EQU B[$-1]
CMP AL,1 ; is it a Wang?
JNE L2 ; jump if not
MOV AL,5 ; load index for Wang
L1: ; we will jump to case number AL
DEC AX ; decrement so the first case is 0 not 1
L5:
CBW ; extend the case number from AL into AX
MOV DH,AL ; save the case number in DH
ADD AX,AX ; double the case number, to address a word pointer
XCHG BX,AX ; swap the index into BX, for addressing
MOV ES,CS ; restore ES=CS, for the benefit of the case code
JMP L0[BX] ; jump to the appropriate case for this machine
; IBM_CONFIG is the BIOS_INIT routine for the IBM-PC. Since its NEW_KEY
; values are the defaults, we do not need to call NEW_KEY.
IBM_MONO_CONFIG:
IBM_CGA_CONFIG:
IBM_EGA_CONFIG:
IBM_CONFIG:
MOV AH,15 ; function number for GET_VIDEO_MODE
INT 16 ; call the BIOS to get the mode
CMP AL,7 ; are we in monochrome mode?
MOV AX,0B000 ; load monochrome map location in case yes
IF B MOV AH,0B8 ; if not then load color map location
MOV BL,0 ; initial BL set for non-screen-swapping
TEST B SWITCH'V',1 ; is the V flag set?
IF NZ MOV BL,8 ; if it is then we will swap screens
XOR AH,BL ; switch interfaces if we saw a +V in invocation
MOV VIDEO_SEG,AX ; store the location of physical video
TEST AH,8 ; are we on a CGA or EGA video board?
JZ >L1 ; skip if not
CMP DH,1 ; have we already selected which, via the B case?
JAE >L5 ; skip if we have
PUSH BX ; we haven't selected CGA vs. EGA: save BX
MOV AH,012 ; BIOS function code for GET_EGA_STATUS
MOV BL,010 ; load an impossible status
INT 16 ; set BL to the EGA status
CMP BL,010 ; was there an EGA status?
POP BX ; restore clobbered register
L5: ; NE is set if we have an EGA
MOV AX,EGA_ATTRS ; load EGA attributes in case we do have an EGA
JNE >L2 ; jump if we do have an EGA
MOV AX,CGA_ATTRS ; not an EGA: load CGA attributes
TEST B SWITCH'F',1 ; is the FAST switch set?
JNZ >L2 ; skip if it is
MOV VID_COPY,COLOR_COPY ; CGA and no FAST switch: change copy routine
MOV BIOS_RESTORE,COLOR_RESTORE ; activate the screen-restore function
L2:
MOV ATTR_BYTES,AX ; set the attribute bytes to AL and AH
L1:
TEST BL ; are we the same screen as the user program?
JNZ RET ; return if we are not-- no need to move cursor
SET_IBM_LOW_LEFT:
MOV BH,0 ; page number is zero
MOV DX,24 BY 0 ; we will move the cursor to row 24, column 0
SET_IBM_CURSOR:
MOV AH,2 ; video BIOS function number for SET CURSOR POSITION
INT 16 ; call the BIOS to put user cursor in lower left corner
RET
; IBM_FIX performs a fixup of a trashed screen on an IBM machine.
; COLOR_RESTORE checks to see if the debugger screen has been trashed. If it
; has, we restore the screen.
COLOR_RESTORE:
PUSH DS ; save register across call
MOV DS,AX,0B800 ; point DS to the video screen
MOV DX,03DA ; load the port number for reading the video status
L2: ; loop here to wait for vertical retrace
IN AL,DX ; input the status
TEST AL,1 ; mask the retrace bit
JZ L2 ; loop if we are not in vertical retrace
CMP B[2400],'A' ; check the "A" of the fixed "AX" display
POP DS ; restore clobbered register
JE RET ; return if the "A" has not rolled away or been trashed
IBM_FIX:
CS PUSH VID_COPY ; save the old VID_COPY value
CS MOV VID_COPY,MONO_COPY ; coerce it to MONO_COPY, to blindly copy all
CALL REFRESH ; refresh the screen; let the snow scatter!
CS POP VID_COPY ; restore the old VID_COPY value
IBM_SAVE:
IBM_RESTORE:
RET
; MONO_COPY is the VID_COPY routine for an IBM monochrome video board. The
; characters occupy the lower byte of the DI-pointed words. We can afford
; to rewrite the entire screen on each refresh; so no special action needs to
; be taken. We do complicated looping to make the routine as fast as
; possible.
MONO_COPY:
SHR CX,1 ; is the character count odd?
JC >L5 ; jump if yes, to special code
L1:
SHR CX,1 ; is the character count a multiple of 4?
JC >L6 ; jump if not, to special code
L2: ; loop here to copy every 4 bytes
LODSB ; load the character from the source
STOSW ; output the character, with the standard attribute byte
LODSB ; char # 2
STOSW
LODSB ; char # 3
STOSW
LODSB ; char # 4
STOSW
LOOP L2 ; loop for the next 4 characters
RET
L5: ; the character count was odd
MOVSB ; copy the odd character to the video buffer
INC DI ; advance beyond the attribute byte
JCXZ RET ; return if count is depleted
JMP L1 ; join even code
L6: ; the character count is 2 mod 4
LODSB ; load one character
STOSW ; output it and the attribute-- count now 1 mod 4
LODSB ; load second character
STOSW ; output it-- count now 0 mod 4
JCXZ RET ; return if count is depleted
JMP L2 ; join multiple-of-4 code
; COLOR_COPY is the VID_COPY routine for an IBM Color Graphics Adapter board.
; The characters occupy the lower byte of the DI-pointed words. We must wait
; for vertical retrace to output our data, to avoid annying "snow" on the
; screen. So we can't afford to output the entire buffer every time. So we
; maintain at [SI+81] a copy of what's already on the screen for [SI], and we
; output only if the buffer is new.
COLOR_COPY:
PUSH BX ; preserve BX across the call
MOV DX,03DA ; load the port number for reading the video status
SKIP2 ; skip to the LODSB instruction
L0: ; loop here for every character that is already out there
INC DI ; advance the output pointer beyond the character
L1: ; loop here after a non-matching character was stored
INC DI ; advance beyond the following attribute byte
LODSB ; fetch the next character
MOV BL,AL ; save the character in BL
XCHG AL,[SI+79] ; swap it with the already-out-there value
CMP AL,BL ; is the character already out there?
LOOPE L0 ; loop if it is
JE >L4 ; jump if the characters are exhausted
L2: ; loop here to wait for vertical retrace
IN AL,DX ; input the status
TEST AL,1 ; mask the retrace bit
JZ L2 ; loop if we are not in vertical retrace
MOV AL,BL ; re-fetch the character to be output
STOSB ; output the character
INC CX ; undo the previous LOOPE's decrement of CX
LOOP L1 ; loop to check for another output character
INC DI ; advance beyond the attribute byte of the last character
POP BX ; restore clobbered register
RET
L4: ; matching character was the last in the buffer
INC DI,2 ; advance beyond the output video word
POP BX ; restore clobbered register
RET
; IBM_ATTR is the VID_ATTR routine for IBM-PC compatible computers. The
; attribute byte is the high byte of the DI-pointed video word.
IBM_ATTR:
INC DI ; advance to the high, attribute byte
STOSB ; output the attribute code AL to the byte
RET
; IBM_KEY is the BIOS_KEY routine for IBM_PC compatible computers. We must
; transform the two-byte code returned by the IBM BIOS into the single
; code AL expected by the rest of the debugger.
IBM_KEY:
MOV AH,0 ; function code for GET KEY
INT 016 ; get the keystroke from the IBM BIOS
TEST AL ; is the return AL nonzero?
JNZ RET ; if yes then AL is our return code
MOV AL,AH ; AL is zero, so AH determines the return code
ADD AL,080-16 ; shift the values into a range not seen directly in AL
RET
; IBM_BELL is the BIOS_BELL routine for IBM-PC compatible computers. We
; output the code 07 to the BIOS's console output routine.
IBM_BELL:
MOV AX,0E07 ; AH= console out function number; AL="BELL" control code
INT 010 ; output BELL to the console
RET
; NEW_KEYS reassigns the keyboard codes and the action routines for a non-
; IBM-compatible BIOS. We are called with CS:SI pointing to a table of
; various new values, whose format is identical to the one given by
; WANG_KEYS below. The new values are plugged into the various tables
; in the debugger, so that correct actions are taken for the non-compatible
; machine.
NEW_KEYS:
LODSB ; load the first byte of the table
MOV HELP_KEY,AL ; first byte is the code for HELP_KEY
LODSB ; load the second byte
ADD SWITCH_KEY,AL ; byte 2 is (new-IBM) function-key-codes-difference
MOV DI,CTRL_JUMPS+2 ; point to the control-jumps table
MOV CX,N_FUNCS ; load the number of function-keys in that table
L1: ; loop here to adjust each function-key code
ADD [DI],AL ; add the code into the table entry
ADD DI,3 ; advance to the next table entry
LOOP L1 ; loop to adjust the next table entry
MOV CL,N_CONTROL_KEYS ; load the number of subsequent keys in the table
L2: ; loop here to plug in the new value for each key
MOVSB ; copy the new key code to the function table
INC DI,2 ; advance output pointer to the next key code
LOOP L2 ; loop to plug in the next key code
LODSW ; fetch the message-pointer to the name of HELP key
MOV HELP_MSG,AX ; plug the pointer into the messages-string
MOV DI,BIOS_CALLS ; point to the table of action routines
MOV CX,N_BIOS_CALLS ; load the count of words in action-routine-table
REP MOVSW ; copy the new pointers to the table
RET
; GET_MACHINE_TYPE sets the variables MACHINE_TYPE and SUBDIR_CHAR.
GET_MACHINE_TYPE:
MOV AH,030 ; MS-DOS function number for GET_DOS_VERSION
INT 33 ; we call this to get the machine number in BH
MOV MACHINE_TYPE,BH
DEC BH ; are we on a Wang PC?
IF Z MOV SUBDIR_CHAR,'/'; if yes then switch the subdirectory character
RET