mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 20:35:25 +00:00
312 lines
8.6 KiB
NASM
312 lines
8.6 KiB
NASM
; MONOGRAF.DRV -- Lotus Driver for Graphics on Monochrome Display
|
||
; ============
|
||
;
|
||
; (For use with Lotus 1-2-3 Version 1A)
|
||
;
|
||
; (C) Copyright Charles Petzold, 1985
|
||
|
||
CSEG Segment
|
||
Assume CS:CSEG
|
||
|
||
Org 0
|
||
Beginning dw Offset EndDriver,1,1,Offset Initialize
|
||
|
||
Org 18h
|
||
db "Monochrome Graphics (C) Charles Petzold, 1985",0
|
||
|
||
Org 40h
|
||
dw 40 * 8 - 1 ; Maximum Dot Column
|
||
dw 25 * 8 - 1 ; Maximum Dot Row
|
||
dw 10, 7, 6, 10, 7, 6, 256
|
||
db -1 ; For one monitor
|
||
|
||
Org 53h
|
||
Jmp Near Ptr ClearScreen ; Call 0 -- Clear Screen
|
||
Jmp Near Ptr ColorSet ; Call 1 -- Set Color
|
||
Jmp Near Ptr SetAddress ; Call 2 -- Set Row/Col Addr
|
||
Jmp Near Ptr DrawLine ; Call 3 -- Draw a Line
|
||
Jmp Near Ptr Initialize ; Call 4 -- Write Dot (nothing)
|
||
Jmp Near Ptr WriteChar ; Call 5 -- Write a Character
|
||
Jmp Near Ptr DrawBlock ; Call 6 -- Draw a Block
|
||
Jmp Near Ptr Initialize ; Call 7 -- Read Dot (nothing)
|
||
Jmp Near Ptr Initialize ; Call 8 -- Video Reset
|
||
|
||
; Initialization Routine
|
||
; ----------------------
|
||
|
||
Initialize Proc Far
|
||
Mov AX,0 ; This is standard
|
||
Or AX,AX ; for all drivers
|
||
Ret
|
||
Initialize EndP
|
||
|
||
; Common Data Used in Routines
|
||
; -----------------------------------
|
||
|
||
CharacterRow dw ? ; from 0 to 24
|
||
CharacterCol dw ? ; from 0 to 79
|
||
ScreenAddress dw ?,0B000h ; Offset & Segment
|
||
CurrentColor db ?,7 ; For Screen Output
|
||
Colors db 219,219,178,177,176,219,178 ; Actually blocks
|
||
|
||
; Row and Column Conversion of AX from graphics to character
|
||
; ----------------------------------------------------------
|
||
|
||
Rounder dw 0 ; Value to add before division
|
||
Divisor db ? ; Value to divide by
|
||
MaxDots dw ? ; Number of dots
|
||
|
||
RowConvertRnd: Mov [Rounder],4 ; Row rounding -- add 4
|
||
RowConvert: Mov [Divisor],8 ; Row normal -- divide by 8
|
||
Mov [MaxDots],200 ; 25 lines times 8 dots
|
||
Jmp Short Convert ; And do generalized conversion
|
||
|
||
ColConvertRnd: Mov [Rounder],2 ; Column rounding -- add 2
|
||
ColConvert: Mov [Divisor],4 ; Will divide by 4
|
||
Mov [MaxDots],320 ; 40 columns times 4 dots
|
||
|
||
Convert: Cmp AX,[MaxDots] ; See if graphics value OK
|
||
Jb OKToConvert ; It is if under maximum
|
||
Jl Negative ; But could be negative
|
||
Sub AX,[MaxDots] ; Otherwise wrap down
|
||
Jmp Convert ; And check again
|
||
Negative: Add AX,[MaxDots] ; Negatives wrap up
|
||
Jmp Convert ; And check again
|
||
|
||
OkToConvert: Add AX,[Rounder] ; Add rounding value
|
||
Div [Divisor] ; Divide
|
||
Cbw ; And convert to word
|
||
Mov [Rounder],0 ; For next time through
|
||
Ret
|
||
|
||
; Calc Offset -- DX, CX character positions in
|
||
; -----------
|
||
|
||
CalcOffset: Push AX
|
||
Push DX
|
||
|
||
Mov AX,80 ; Columns Per Line
|
||
Mul DX ; AX now at beginning of row
|
||
Add AX,CX ; Add column value
|
||
Add AX,AX ; Double for attributes
|
||
Mov [ScreenAddress],AX ; Save as the current address
|
||
|
||
Pop DX
|
||
Pop AX
|
||
|
||
Ret
|
||
|
||
; Address Convert -- DX, CX row and column converted to character
|
||
; ---------------
|
||
|
||
AddrConvert: Push AX
|
||
|
||
Mov AX,DX ; This is graphics row
|
||
Call RowConvert ; Convert to character row
|
||
Mov DX,AX ; Save back in DX
|
||
Mov [CharacterRow],AX ; And save value in memory
|
||
|
||
Mov AX,CX ; This is graphics column
|
||
Call ColConvert ; Convert to character column
|
||
Mov CX,AX ; Back in CX
|
||
Mov [CharacterCol],AX ; And value also saved
|
||
|
||
Call CalcOffset ; Find the screen destination
|
||
|
||
Pop AX
|
||
|
||
Ret
|
||
|
||
; Call 0 -- Clear Screen -- AL = 0 for B&W
|
||
; ====================== -1 for Color
|
||
|
||
ClearScreen Proc Far
|
||
Mov AX,0B000h ; Monochrome Segment
|
||
Mov ES,AX ; Set EX to it
|
||
Sub DI,DI ; Start at zero
|
||
Mov CX,25 * 80 ; Number of characters
|
||
Mov AX,0720h ; Blanks only
|
||
Cld ; Forward direction
|
||
Rep Stosw ; Do it
|
||
Ret
|
||
ClearScreen EndP
|
||
|
||
; Call 1 -- Color Set -- AL = Color (0, 1-6)
|
||
; -------------------
|
||
|
||
ColorSet Proc Far
|
||
Mov BX,Offset Colors ; Blocks for 7 colors
|
||
Xlat Colors ; Translate the bytes
|
||
Mov [CurrentColor],AL ; And save it
|
||
Ret
|
||
ColorSet EndP
|
||
|
||
; Call 2 -- Set Address -- DX = Graphics Row
|
||
; --------------------- CX = Graphics Columns
|
||
|
||
SetAddress Proc Far
|
||
Call AddrConvert ; One routine does it all
|
||
Ret
|
||
SetAddress EndP
|
||
|
||
; Call 3 -- Draw Line -- DX = End Row
|
||
; ------------------- CX = End Column
|
||
|
||
DrawLine Proc Far
|
||
Les DI,DWord Ptr [ScreenAddress] ; Beginning address
|
||
Mov AX,[CharacterCol] ; AX now beginning column
|
||
Mov BX,[CharacterRow] ; BX now beginning row
|
||
|
||
Call AddrConvert ; CX,DX now ending col, row
|
||
|
||
Cmp AX,CX ; See if cols are the same
|
||
Je VertLine ; If so, it's vertical line
|
||
|
||
Cmp BX,DX ; See if rows are the same
|
||
Jne DrawLineEnd ; If not, don't draw anything
|
||
|
||
HorizLine: Sub CX,AX ; Find the number of bytes
|
||
Mov BX,2 ; Increment for next byte
|
||
Mov AL,196 ; The horizontal line
|
||
Mov AH,179 ; The vertical line
|
||
Jae DrawTheLine ; If CX > AX, left to right
|
||
Jmp Short ReverseLine ; Otherwise right to left
|
||
|
||
VertLine: Mov CX,DX ; This is the ending column
|
||
Sub CX,BX ; Subtract beginning from it
|
||
Mov BX,80 * 2 ; Increment for next line
|
||
Mov AL,179 ; The vertical line
|
||
Mov AH,196 ; The horizontal line
|
||
Jae DrawTheLine ; If CX > BX, up to down
|
||
|
||
ReverseLine: Neg BX ; Reverse Increment
|
||
Neg CX ; Make a positive value
|
||
|
||
DrawTheLine: Inc CX ; One more byte than calced
|
||
|
||
DrawLineLoop: Cmp Byte Ptr ES:[DI],197 ; See if criss-cross there
|
||
Je DrawLineCont ; If so, branch around
|
||
|
||
Cmp ES:[DI],AH ; See if opposite line
|
||
Jne NoOverLap ; If not, skip next code
|
||
|
||
Mov Byte Ptr ES:[DI],197 ; Write out criss-cross
|
||
Jmp Short DrawLineCont ; And continue
|
||
|
||
NoOverLap: Mov ES:[DI],AL ; Display line chararacter
|
||
|
||
DrawLineCont: Add DI,BX ; Next destination
|
||
Loop DrawLineLoop ; For CX repetitions
|
||
|
||
DrawLineEnd: Ret
|
||
DrawLine EndP
|
||
|
||
; Call 5 -- Write Character -- DX, CX = row, col; BX = count,
|
||
; ------------------------- AH = direction, AL = type
|
||
|
||
Direction db ?
|
||
|
||
WriteChar Proc Far
|
||
|
||
Push BX ; Save count
|
||
Add BX,BX ; Initialize adjustment
|
||
Mov [Direction],AH ; Save direction
|
||
|
||
Or AL,AL ; Branch according to type
|
||
Jz WriteType0
|
||
Dec AL
|
||
Jz WriteType1
|
||
Dec AL
|
||
Jz WriteType2
|
||
Dec AL
|
||
Jz WriteType3
|
||
|
||
WriteType4: Mov AX,4 ; Adjustment to row
|
||
Jmp Short WriteCharCont
|
||
|
||
WriteType3: Add BX,BX ; Center on column
|
||
WriteType2: Sub AX,AX ; No adjustment to row
|
||
Jmp Short WriteCharCont
|
||
|
||
WriteType1: Sub BX,BX ; No adjustment on column
|
||
WriteType0: Mov AX,2 ; Adjustment to row
|
||
|
||
WriteCharCont: Cmp [Direction],0 ; Check the direction
|
||
Jz HorizChars
|
||
|
||
Sub DX,BX ; Vertical -- adjust row
|
||
Sub DX,BX
|
||
Sub CX,AX ; Adjust column
|
||
Mov AX,80 * 2 - 1 ; Increment for writes
|
||
Jmp Short DoWriteChar
|
||
|
||
HorizChars: Sub DX,AX ; Horizontal -- adjust row
|
||
Sub DX,AX
|
||
Sub CX,BX ; Adjust column
|
||
Mov AX,1 ; Increment for writes
|
||
|
||
DoWriteChar: Call AddrConvert ; Convert the address
|
||
Les DI,DWord Ptr [ScreenAddress] ; Get video address
|
||
Cld
|
||
Pop CX ; Get back character count
|
||
Jcxz WriteCharEnd ; Do nothing if no characters
|
||
|
||
CharacterLoop: Movsb ; Write character to display
|
||
Add DI,AX ; Increment address
|
||
Loop CharacterLoop ; Do it CX times
|
||
|
||
WriteCharEnd: Ret
|
||
WriteChar EndP
|
||
|
||
; Call 6 -- Draw Block -- BX,DX = Rows; AX,CX = Columns
|
||
; --------------------
|
||
|
||
DrawBlock Proc Far
|
||
Call ColConvertRnd ; AX now first char col
|
||
Xchg AX,CX ; Switch with 2nd graph col
|
||
Call ColConvertRnd ; AX now 2nd char col
|
||
Cmp AX,CX ; Compare two char cols
|
||
Je DrawBlockEnd ; End routine if the same
|
||
Ja NowDoRow ; If CX lowest, just continue
|
||
|
||
Xchg AX,CX ; Otherwise switch them
|
||
|
||
NowDoRow: Xchg AX,BX ; AX now 1st graph row
|
||
Call RowConvertRnd ; AX now 1st char row
|
||
Xchg AX,DX ; AX now 2nd graph row
|
||
Call RowConvertRnd ; AX now 2nd char row
|
||
Cmp AX,DX ; Compare two character columns
|
||
Je DrawBlockEnd ; End routine if the same
|
||
Ja BlockRowLoop ; If DX lowest, just continue
|
||
|
||
Xchg AX,DX ; Otherwise switch them
|
||
|
||
BlockRowLoop: Push CX ; Beginning Column
|
||
Push BX ; Ending Column
|
||
|
||
BlockColLoop: Call CalcOffset ; Calculate screen address
|
||
Les DI,DWord Ptr [ScreenAddress] ; And set ES:DI
|
||
|
||
Push Word Ptr [CurrentColor] ; Push the current color
|
||
Pop ES:[DI] ; And Pop it on the screen
|
||
|
||
Inc CX ; Next Column
|
||
Cmp CX,BX ; Are we an end?
|
||
Jb BlockColLoop ; Nope -- loop again
|
||
|
||
Pop BX ; Get back beginning col
|
||
Pop CX ; And the end
|
||
|
||
Inc DX ; Prepare for next row
|
||
Cmp DX,AX ; Are we at the end?
|
||
Jb BlockRowLoop ; If not, loop
|
||
|
||
DrawBlockEnd: Ret
|
||
DrawBlock EndP
|
||
|
||
Org $ + 16 - (($ - Beginning) Mod 16)
|
||
EndDriver Label Byte
|
||
|
||
CSEG EndS
|
||
End
|
||
|