home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
1986
/
20
/
suggest.asm
next >
Wrap
Assembly Source File
|
1987-12-12
|
12KB
|
236 lines
CODE SEGMENT ;*************************
ASSUME CS:CODE,DS:CODE ;* *
ORG 100H ;* REMEMBER TO EXE2BIN *
;* *
START: JMP INITIALIZE ;*************************
; DATA AREA
; ---------
COPY_RIGHT DB 'Copyright 1986 Ziff-Davis Publishing Co.'
SCREEN_SEG DW 0B000H
OLD_TIMER DD ?
STATUS_REG DW ?
COUNTER DW 0
TIME_OUT DW 1
FREQUENCY DW 7387H ;Twenty seven minutes
FREQ_CONSTANT EQU 3276 ;Three minutes
DURA_CONSTANT EQU 4205 ;17/1000 sec.
; CODE AREA
; ---------
SUGGEST: STI ;Turn the interrupts back on
PUSHF ; and save the flags
PUSH AX ; and all registers we will
PUSH CX ; be using.
PUSH DX
PUSH DS
PUSH ES
PUSH SI
PUSH DI
PUSH CS ;Retrieve our data segment.
POP DS
INC WORD PTR COUNTER ;Increment the counter.
MOV DX,COUNTER
CMP DX,FREQUENCY ;Is it time to display?
JNZ EXIT ;If no, exit
MOV WORD PTR COUNTER,0 ; else, reset counter
MOV AX,40H ;Point to ROM BIOS data area.
MOV ES,AX
MOV AL,ES:[49H] ;Get current CRT_MODE
CMP AL,1 ;Is it 40 column?
JBE EXIT ;If yes, exit
CMP AL,3 ;Is it color card in text?
JBE DISPLAY ;If yes, display.
CMP AL,7 ;Is it mono card?
JNZ EXIT ;If no, exit.
DISPLAY: MOV DX,STATUS_REG ;Retrieve status register and
MOV AX,SCREEN_SEG ; retrieve screen buffer segment.
PUSH DS ;ES points to data
POP ES
MOV DS,AX ; and DS points to screen buffer.
MOV SI,160*11 ;Source is 11th row of screen
MOV DI,OFFSET SCREEN ; and destination end of code.
CLD ;Set direction forward.
CALL READ ;Go read the screen.
PUSH DS ;Switch source
PUSH ES ; and destination segments.
POP DS
POP ES
MOV SI,OFFSET MSG ;Point to message
CALL WRITE ; and go write it.
MOV CX,TIME_OUT ;Get the duration time out
DELAY: DEC CX ; and delay here while monitor
JNZ DELAY ; displays message.
MOV SI,OFFSET SCREEN ;Point to data and replace
CALL WRITE ; it on the screen.
EXIT: POP DI ;Restore registers
POP SI ; and flags.
POP ES
POP DS
POP DX
POP CX
POP AX
POPF
JMP CS:OLD_TIMER ;Goto old timer interrupt.
;--------------------------------------------------------;
; This subroutine will read three lines in the middle ;
; of the screen and store them at the end of code so the ;
; display can be restored after we display our message. ;
;--------------------------------------------------------;
READ: MOV CX,3*80 ;Set count to three lines.
HORZ_RET1: IN AL,DX ;Get status.
TEST AL,1 ;Is it low?
JNZ HORZ_RET1 ;If no, wait until it is.
CLI ;No more interrupts.
WAIT1: IN AL,DX ;Get status
TEST AL,1 ;Is it high?
JZ WAIT1 ;If no, wait until it is.
LODSB ;Retrieve a byte.
STI ;Interrupts back on.
STOSB ;Store the byte.
INC SI ;Bump the point past attribute.
LOOP HORZ_RET1 ;Get next byte.
RET ;Return.
;----------------------------------------------------------;
; This subroutine writes three lines to the screen buffer. ;
;----------------------------------------------------------;
WRITE: MOV DI,160*11 ;Point to the 11th row.
MOV CX,3*80 ;Count of three rows.
PUT_BYTE: LODSB ;Get a byte.
MOV AH,AL ;Store it in AH.
HORZ_RET2: IN AL,DX ;Get status.
TEST AL,1 ;Is it low?
JNZ HORZ_RET2 ;If no, wait until it is.
CLI ;No more interrupts.
WAIT2: IN AL,DX ;Get status.
TEST AL,1 ;Is it high?
JZ WAIT2 ;If no, wait until it is.
MOV AL,AH ;Retrieve the byte
STOSB ; and store it.
STI ;Interrupts back on.
INC DI ;Bump pointer past attribute.
LOOP PUT_BYTE ;Write next byte.
RET ;Return.
;---------------------------------------------------------------------;
; This is the start of the install. We will need the port of status ;
; register and the video card address. Then we will parse the command ;
; line and store. Check for frequency and duration switches. Take the ;
; the timer tick interrupt and terminate but stay resident. ;
;---------------------------------------------------------------------;
INITIALIZE: MOV AL,32 ;First pad the message
MOV DI,OFFSET MSG ;storage area with three
MOV CX,80*3 ;lines of spaces.
REP STOSB
PARSE: XOR CX,CX ;Zero in string counter.
MOV SI,82H ;Point to string.
CMP BYTE PTR[SI-2],1 ;Is there a string?
JA GET_MSG ;If yes, get the message length
INT 20H ; else terminate.
GET_MSG: LODSB ;Get a byte.
INC CX ;Increment counter.
CMP AL,13 ;Is it carriage return?
JZ MESSAGE ;If yes, end of message.
CMP AL,'/' ;Is it switch character?
JNZ GET_MSG ;If no, get next byte.
GET_SWITCH: LODSB ;Get a byte.
CMP AL,13 ;Is it carriage return?
JZ MESSAGE ;If yes, end of switches.
AND AL,5FH ;Capitalize.
CMP AL,'F' ;Is it frequency switch?
JNZ DURATION ;If no, check duration switch
CALL CONVERT ; else convert number to hex
MOV BX,FREQ_CONSTANT ; get frequency constant
MUL BX ; and multiply.
SUB FREQUENCY,AX ;Subtract from frequency default.
JMP SHORT GET_SWITCH ;Get next character.
DURATION: CMP AL,'D' ;Is it duration switch?
JNZ GET_SWITCH ;If no, get next character
CALL CONVERT ; else convert number to hex
MOV BX,DURA_CONSTANT ; get duration constant
MUL BX ; and multiply.
ADD TIME_OUT,AX ;Add to time out default.
JMP SHORT GET_SWITCH ;Get next character.
MESSAGE: MOV SI,82H ;Point to message.
MOV DI,OFFSET MSG+80 ;Point to storage.
DEC CX ;Adjust counter.
CMP CX,80 ;Is it more than one line?
JB CENTER ;If no, center
MOV CX,80 ; else, truncate to one line
JMP SHORT STORE ; and store.
CENTER: MOV BX,80 ;Take 80
SUB BX,CX ; and subtract message length
SHR BX,1 ; divide by two
ADD DI,BX ; and add to storage offset.
STORE: REP MOVSB ;Store.
CARD: MOV AX,40H ;Point to ROM BIOS data area
MOV ES,AX
MOV AX,ES:[63H] ;Get base address of video card.
ADD AX,6 ;Convert to status register
MOV STATUS_REG,AX ; and store.
CMP AX,3BAH ;Is it mono card?
JZ INTERRUPT ;If yes, go to interrupt
ADD WORD PTR SCREEN_SEG,800H ; else point to color card.
INTERRUPT: MOV AX,351CH ;Get timer tick vector
INT 21H
MOV WORD PTR OLD_TIMER,BX ; and store offset
MOV WORD PTR OLD_TIMER[2],ES ; and segment.
MOV DX,OFFSET SUGGEST ;Replace with our
MOV AX,251CH ; offset and segment.
INT 21H
MOV DX,OFFSET SCREEN+80*3+1 ;Terminate but
INT 27H ; stay resident.
;---------------------------------------------;
; This subroutine will convert decimal to hex ;
;---------------------------------------------;
CONVERT: XOR AH,AH ;Zero in high half.
LODSB ;Get a byte.
CMP AL,'1' ;Is it less than one
JB IGNORE ; or more than nine?
CMP AL,'9'
JA IGNORE ;If yes, ignore
SUB AL,30H ; else convert to decimal
RET ; and return.
IGNORE: MOV AL,0 ;Default is zero.
RET ;Return.
;------------------------------------------------------------;
; Message and screen storage is placed here instead of in ;
; the data area to save 480 bytes in the BASIC data listing. ;
;------------------------------------------------------------;
MSG:
ORG OFFSET MSG+80*3
SCREEN:
CODE ENDS
END START