MalwareSourceCode/MSDOS/M-Index/Virus.MSDOS.Unknown.monograf.asm

312 lines
8.6 KiB
NASM
Raw Normal View History

2021-01-12 23:49:21 +00:00
; 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