home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
graphics
/
int_70h.arc
/
INT70H.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-12-07
|
27KB
|
758 lines
PAGE 63, 132
Title Interupt support for the Hercules Graphics Card
CSEG SEGMENT
ORG 100H
ASSUME CS:CSEG, DS:CSEG, SS:CSEG
START: JMP SET_UP
;------------------------ routine ----------------------
ROUTINE PROC FAR
PUSHF
PUSH ES
PUSH DS
PUSH SI
PUSH DI
PUSH AX
PUSH BX
PUSH CX
PUSH DX
JMP SKIP_DATA
; data section
Pos_X DW ?
Pos_Y DW ?
Pos_Err DW ?
Neg_X DW ?
Neg_Y DW ?
Neg_Err DW ?
Line_Err DW ?
LENGTH DW ?
Point_Type DB ?
X1 DW ?
Y1 DW ?
X2 DW ?
Y2 DW ?
DeltaX DW ?
DeltaY DW ?
Ten DB 0Ah
Function_Table DW 8 DUP(0)
Active_page DB 0
Segment_value DW ?
Offset_Value DW ?
;
;++======================================================================++
;|| ||
;|| Draws the line given the present data ||
;|| ||
;++======================================================================++
;
DrawIt PROC Near
MOV AX, 0B000h
MOV BH, Active_page
CMP BH, 0
JE Pg_0d
MOV AX, 0B800h
Pg_0d: MOV ES, AX
MOV AX, Y2 ; see which is larger. if Y1 is larger,
CMP AX, Y1 ; you have to swap the end points
JNL No_Swap ; ( you always want to go up )
MOV AX, Y1 ; put the first Y value into the AX register
MOV BX, Y2 ; put the second Y value into the BX register
MOV Y2, AX ; put the first Y value into the second Y
MOV Y1, BX ; put the second Y value into the first Y
MOV AX, X1 ; same as above for the X values
MOV BX, X2
MOV X2, AX
MOV X1, BX
No_Swap: MOV AX, X2 ; come up with the difference in X's
SUB AX, X1
MOV DeltaX, AX
MOV AX, Y2 ; come up with the difference in Y's
SUB AX, Y1
MOV DeltaY, AX
JNZ Not_Horiz ; if DeltaY is zero, the line is horizontal
JMP Horiz
Not_Horiz:
CMP AX, DeltaX ; compare DeltaY to DeltaX
JNE Not_Diag1 ; if they are equal, the slope is 1
JMP Diag1
Not_Diag1:
XOR AX, 0FFFFh ; get negative DeltaY in AX
INC AX
CMP AX, DeltaX ; compare negative DeltaY to DeltaX
JNE Not_Diag2 ; if they are equal, the slope is -1
JMP Diag2
Not_Diag2:
CMP DeltaX, 0 ; compare DeltaX to zero
JNE Not_Vert ; if there is no difference in X's, it's vert
JMP Vert
Not_Vert:
JL Case_3_or_4 ; this line has a negative slope
Case_1_or_2:
XOR AX, 0FFFFh ; AX should still have -DeltaY
INC AX ; so, make it positive
CMP AX, DeltaX ; compare this to DeltaX
JA Case2 ; if DeltaY > DeltaX the goto Case 2
Case1: MOV DX, AX ; store the negative error correction
MOV SI, DeltaX ; the length of the line
SUB AX, SI ; Positive error = DeltaY - DeltaX
MOV CX, AX ; store it
MOV BX, X1 ; get the starting point
MOV AX, Y1
XOR DI, DI ; initialize the error register
Plot_1: CALL Plot_pt
CMP DI, 0 ; compare the error to zero
JL Neg_err_1 ; if a negative error, jump pos err code
ADD DI, CX ; add pos error correction
INC AX ; next point is "up" and to the right
INC BX
JMP Chk_1 ; jump neg err code
Neg_err_1:
ADD DI, DX ; add neg error correction
INC BX ; next point is to the right
Chk_1: DEC SI ; decrement counter
JNZ Plot_1 ; check to see if you are done
JMP Plot_end_pts ; go to where you will plot the end points
Case2: MOV SI, AX ; AX has DeltaX in it and that is the length
MOV CX, DeltaX ; get DeltaX for Pos err correction
SUB AX, CX ; DeltaY - DeltaX
MOV DX, AX ; store the Neg err correction
XOR CX, 0FFFFh ; Pos err cor is -DeltaX
INC CX
MOV BX, X1
MOV AX, Y1
XOR DI, DI
Plot_2: CALL Plot_pt
CMP DI, 0 ; compare the error to zero
JL Neg_err_2 ; if a negative error, jump pos err code
ADD DI, CX ; add pos error correction
INC AX ; next point is "up" one point
JMP Chk_2 ; jump neg err code
Neg_err_2:
ADD DI, DX ; add neg error correction
INC AX ; next point is "up" and to the right
INC BX ;
Chk_2: DEC SI ; decrement counter
JNZ Plot_2 ; check to see if you are done
JMP Plot_end_pts ; go to where you will plot the end points
Case_3_or_4:
MOV AX, DeltaX ; DeltaX is negative. Invert it and add 1 for
XOR AX, 0FFFFh ; 2's compliment (leave DeltaX alone use AX)
INC AX
CMP AX, DeltaY ; If DeltaY > DeltaX . . .
JB Case4 ; this means that the slope is < -1
Case3: MOV SI, AX ; AX has DeltaX in it and that is the length
MOV CX, DeltaY ; get DeltaY for neg err correction
MOV DX, CX ; store it
SUB CX, AX ; calculate the pos err correction: Dy - Dx
MOV BX, X1 ; set initial values
MOV AX, Y1
XOR DI, DI
Plot_3: CALL Plot_pt
CMP DI, 0 ; compare the error to zero
JL Neg_err_3 ; if a negative error, jump pos err code
ADD DI, CX ; add pos error correction
INC AX ; next point is "up" and to the left
DEC BX
JMP Chk_3 ; jump neg err code
Neg_err_3:
ADD DI, DX ; add neg error correction
DEC BX ; next point is "up" and to the left
Chk_3: DEC SI ; decrement counter
JNZ Plot_3 ; check to see if you are done
JMP Plot_end_pts ; go to where you will plot the end points
Case4: MOV SI, DeltaY ; the length of the line
XOR AX, 0FFFFh ; AX had -DeltaX in it
INC AX ; change it to DeltaX
MOV CX, AX ; set the pos err correction register ( +Dx )
ADD AX, SI ; calculate the neg err correction ( Dy + Dx )
MOV DX, AX ; store it
MOV BX, X1 ; set initial values
MOV AX, Y1
XOR DI, DI
Plot_4: CALL Plot_pt
CMP DI, 0 ; compare the error to zero
JL Neg_err_4 ; if a negative error, jump pos err code
ADD DI, CX ; add pos error correction
INC AX ; next point is "up" one point
JMP Chk_4 ; jump neg err code
Neg_err_4:
ADD DI, DX ; add neg error correction
INC AX ; next point is "up" and to the right
DEC BX ;
Chk_4: DEC SI ; decrement counter
JNZ Plot_4 ; check to see if you are done
JMP Plot_end_pts ; go to where you will plot the end points
Horiz: MOV SI, DeltaX ; set the length variable
MOV BX, X1 ; set initial values
MOV AX, Y1
CMP SI, 0 ; check to see if the length var is neg
JG Plot_H ; if not, skip making it neg
XOR SI, 0FFFFh ; make SI ( = -DeltaX ) positive
INC SI
Plot_H: CALL Plot_pt ; plot the point
INC BX ; move one pixel right
DEC SI ; decrement the counter
JNZ Plot_H ; if not done, go again
JMP Plot_end_pts ; plot the end points of the line
Vert: XOR AX, 0FFFFh ; AX already had -DeltaY,
INC AX ; make it DeltaY and
MOV SI, AX ; stick it into the length var
MOV BX, X1 ; set initial values
MOV AX, Y1
Plot_V: CALL Plot_pt ; plot the point
INC AX ; move one pixel right
DEC SI ; decrement the counter
JNZ Plot_V ; if not done, go again
JMP Plot_end_pts ; plot the end points of the line
Diag1: MOV SI, AX ; AX still has DeltaY in it
MOV BX, X1 ; the starting point
MOV AX, Y1
Plot_D1: CALL Plot_pt
INC AX ; next point is "up" and to the right
INC BX
DEC SI ; decrement the counter
JNZ Plot_D1 ; if not done, go again
JMP Plot_end_pts
Diag2: XOR AX, 0FFFFh ; AX has -DeltaY in it, change its sign
INC AX
MOV SI, AX ; store it
MOV BX, X1 ; initial point
MOV AX, Y1
Plot_D2: CALL Plot_pt
INC AX ; next point is "up" and to the left
DEC BX
DEC SI ; decrement counter
JNZ Plot_D2 ; if not done, go again
Plot_end_pts:
MOV AX, Y1 ; set up for plotting the 1st end pt
MOV BX, X1
CALL Plot_Pt ; plot 1st end pt
MOV AX, Y2 ; set up for plotting the 2nd end pt
MOV BX, X2
CALL Plot_Pt
RET
DrawIt ENDP ; done here
;
;++======================================================================++
;|| ||
;|| Plots a point at (BX,AX) if possible using Line_Type ||
;|| ||
;++======================================================================++
;
Plot_Pt PROC Near
PUSH AX ; save the values of X & Y
PUSH BX
PUSH CX
CALL AddrHGC ; get the offset in the buffer
CMP AX, 1000h ; check for an error being returned from
JNE No_Plot ; if an error was detected, get out
MOV CH, 1 ; bit to or into the byte
SHL CH, CL ; move the bit into position
CMP Point_Type, 2 ;
JB Or_Point ; if plotting a line...
JA Del_Point ; if erasing a line...
XOR ES:[BX], CH ; xor the line
JMP No_Plot
Or_Point:
OR ES:[BX], CH ; set the bit in the video buffer
JMP No_Plot
Del_Point:
XOR CH, 0FFFFh ; reverse the bits
AND ES:[BX], CH ; erase the bit
No_Plot: POP CX ; CX was altered, restore it
POP BX ; get the X value back
POP AX ; get the Y value back
RET
Plot_Pt ENDP
;
; in: AX = y
; BX = x <--------------------+
; |
; out: AX = 1000 if value is OK or x if bad
; BX = byte offset in buffer
; CL = nuber of bits to shift left
;
AddrHGC PROC Near
CMP AX, 0 ; is the y value too small?
JL DONE ; if so, get out of the procedure
CMP AX, 347 ; is the y value too large?
JG DONE ; if so, get out of the procedure
CMP BX, 0 ; is the x value too small?
JL DONE ; if so, get out of the procedure
CMP BX, 719 ; is the x value too large?
JG DONE ; if not, get out
MOV CL, BL ; CL = low order byte of x
SHR AX, 1 ; AX = y / 2
RCR BX, 1 ; BX = 8000h * (y&1) + x/2
SHR AX, 1 ; AX = y / 4
RCR BX, 1 ; BX = 4000h * (y&3) + x/4
SHR BX, 1 ; BX = 2000h * (y&3) + x/8
MOV AH, 90 ; bytes per line (decimal)
MUL AH ; AX = bytes per line * (y/4)
ADD BX, AX ; BX = 2000h * (y&3) + x/8 +
; bytes per line * (y/4)
AND CL, 7 ; CL = x & 7
XOR CL, 7 ; CL = number of bits to shift left
MOV AX, 1000h ; AH = unshifted bit mask
DONE: RET
AddrHGC ENDP
;
;++======================================================================++
;|| ||
;|| Turns on the HERCULES graphics mode ||
;|| ||
;++======================================================================++
;
Graphics_on PROC Near
MOV AL, 02Ah ; graphics mode (Page 0)
AND DH, 01 ; get visible page from the instruction byte
JZ Pg_0g ; if it is page 0, don't change now
MOV AL, 0AAh ; graphics mode (Page 1)
Pg_0g: MOV DX, 03B8h ; HGC mode control reister
OUT DX, AL ; set to graphics mode
MOV AL, 03h ; code to enable graphics
MOV DX, 03BFh ; HGC config switch register
OUT DX, AL ; enable graphics
RET
Graphics_on ENDP
;
;++======================================================================++
;|| ||
;|| Turns off the HERCULES graphics mode ||
;|| ||
;++======================================================================++
;
Text_on PROC Near
MOV AL, 028h ; text mode (page 0)
AND DH, 01 ; get visible page from instruction byte
JZ Pg_0 ; don't make it page 1 if page 0
MOV AL, 0A8h ; text mode (page 1)
Pg_0: MOV DX, 03B8h ; HGC mode control reister
OUT DX, AL ; set to graphics mode
MOV AL, 03h ; code to enable HGC
MOV DX, 03BFh ; HGC config switch register
OUT DX, AL ; enable graphics
RET
Text_on ENDP
;
;++======================================================================++
;|| ||
;|| plot a point on the graphics page ||
;|| ||
;++======================================================================++
;
Point PROC near
AND DH, 03 ; mask off the type of point
MOV Point_type, DH ; set the variable
MOV CX, ES:[BX] ; get the X value of the point
ADD BX, 2 ; move past the data word
MOV DX, ES:[BX] ; get the Y value of the point
ADD BX, 2 ; move pointer past the data word
MOV Offset_value, BX ; save current value
MOV AX, 0B000h ; default graphics page ( page 0 )
MOV BH, Active_page ; get the number of the active page
CMP BH, 0 ; check to see if page 0 IS the active page
JE Pg_0p ; if so, don't change it now
MOV AX, 0B800h ; if not, do change it to page 1
Pg_0p: MOV ES, AX ; plot_pt needs this
MOV BX, CX ; BX is where the procedure expects the
; X value of the point
MOV AX, DX ; AX is where the procedure expects the
; Y value of the point
CALL Plot_Pt ; call the procedure to plot the point
RET ; you're done here
Point ENDP
;
;++======================================================================++
;|| ||
;|| plot a line on the graphics page ||
;|| ||
;++======================================================================++
;
Line PROC near
MOV CX, ES:[BX] ; get the first end point's X value
MOV X1, CX ; store the value
ADD BX, 2 ; mov the pointer past the word
MOV CX, ES:[BX] ; get the 1st pt's Y value
MOV Y1, CX ; store it
ADD BX, 2
MOV CX, ES:[BX] ; 2nd pt's X value
MOV X2, CX
ADD BX, 2
MOV CX, ES:[BX] ; 2nd pt's Y value
MOV Y2, CX
ADD BX, 2
MOV Offset_value, BX ; store current value of my IR
AND DH, 03 ; get the line type
MOV Point_type, DH ;
CALL Drawit ; call the procedure to draw the line
RET ; you're done
Line ENDP
;
;++======================================================================++
;|| ||
;|| set the active page variable ||
;|| (needed by the plot_pt proc) ||
;|| ||
;++======================================================================++
;
act_page PROC near
AND DH, 01 ; the only pages are 0 and 1 & the LSB
MOV Active_page, DH ; gives the page
RET
act_page ENDP
;
;++======================================================================++
;|| ||
;|| clears the given page (graphics) ||
;|| ||
;++======================================================================++
;
Clear_page PROC near
MOV AX, 0B000h ; start of video buffer
AND DH, 01 ; get the active page number
JE Clr_pg_1 ; if it is zero, you don't need to change AX
MOV AX, 0B800h ; second page
Clr_pg_1:MOV ES, AX ; set base value
XOR DI, DI ; reset offset
XOR AX, AX ; value to put in buffer ( AX = 0 )
MOV CX, 8000H ; number of bytes to fill
REP STOSW ; repeat storing value in memory
RET
Clear_page ENDP
;
;++======================================================================++
;|| ||
;|| fills the given page (graphics) ||
;|| ||
;++======================================================================++
;
Fill_page PROC near
MOV CX, ES:[BX] ; get the value to fill the buffer
ADD BX, 2 ; increment the instruction pointer
MOV Offset_value, BX ; store the pointer
MOV AX, 0B000h ; start of video buffer
AND DH, 01 ; get the active page number
JE Fil_pg_1 ; if it is zero, you don't need to change AX
MOV AX, 0B800h ; second page
Fil_pg_1:MOV ES, AX ; set base value
XOR DI, DI ; reset offset
MOV AX, CX ; value to put in buffer ( AX = 0 )
MOV CX, 8000H ; number of bytes to fill
REP STOSW ; repeat storing value in memory
RET
Fill_page ENDP
;
;++======================================================================++
;|| ||
;|| This is the error return function ||
;|| ||
;++======================================================================++
;
Err_in_fn: POP AX ; the calling value of the AX register is
; on top of the stack. get it off.
MOV AH, 0FFh ; signify an error return
MOV AL, DH ; return erroneous function
JMP Err_exit ; get out while you still can
;
;++======================================================================++
;|| ||
;|| This is the main loop of the code ||
;|| ||
;++======================================================================++
;
SKIP_DATA: MOV CX, CS ; set DS to the same as CS
MOV DS, CX
MOV Segment_value, AX ; save these important values
MOV Offset_value, BX
MOV ES, AX ; move data segment value into ES
Go_again: MOV DH, ES:[BX] ; load the function byte
INC BX ; increment my program counter
MOV Offset_value, BX ; save program counter
CMP DH, 0 ; compare it to 0 to see if you are done
JE Quit_int ; if equal, get out
CMP DH, 80h ; see if the function # is too high
JAE Err_in_fn ; if so, go tell the user
CMP DH, 10h ; see if the function # is too low
JB Err_in_fn ; if so, go tell the user
MOV CL, 3 ; bits to shift left (to find fn in table)
MOV DL, DH ;
XOR DH, DH
MOV SI, DX ; copy function byte for manipulation
SHR SI, CL ; shift byte (divide it by 8)
AND SI, 0Eh ; mask off value (offset into the table)
MOV DH, DL ; some of the fns require DH to have the
; instruction byte
CALL Function_table[SI] ; jump to funcion offset in the table
MOV BX, Segment_value ; get the segment value
MOV ES, BX ; set the ES register to the proper segment
MOV BX, Offset_value ; get pointer to next instruction
JMP Go_again ; start over
Quit_int: POP AX
Err_exit: POP BX
POP CX
POP DX
POP DI
POP SI
POP DS
POP ES
POPF
IRET
FINISH EQU $
ROUTINE ENDP
;----------------------- set up -----------------------
SET_UP: LEA BX, Function_Table ; set up fuction offset table
LEA CX, Graphics_on
MOV [BX+2], CX
LEA CX, Text_on
MOV [BX+4], CX
LEA CX, Point
MOV [BX+6], CX
LEA CX, Line
MOV [BX+8], CX
LEA CX, Act_page
MOV [BX+10], CX
LEA CX, Clear_page
MOV [BX+12], CX
LEA CX, Fill_page
MOV [BX+14], CX
LEA DX, Strt_msg
MOV AH, 9
INT 21H
MOV DX, OFFSET ROUTINE ; start of routine
MOV AL, 70H ; what interupt I plan to use
MOV AH, 25H ; DOS function to set the int vector
INT 21H ; set the vector
LEA DX, FINISH ; end of resident routine
INT 27H ; quit and routine stays resident
strt_msg DB 13, 10, '╒══════════════════════════════════════════╕'
DB 13, 10, '│ │'
DB 13, 10, '│ Hercules video support now resident. │'
DB 13, 10, '│ │'
DB 13, 10, '│ INT 70h │'
DB 13, 10, '│ by │'
DB 13, 10, '│ │'
DB 13, 10, '│ Ted O''Connor │'
DB 13, 10, '│ │'
DB 13, 10, '╘══════════════════════════════════════════╛'
DB 13, 10, 10, '$'
CSEG ENDS
END START
END