2023-11-16 18:19:54 -05:00

479 lines
9.9 KiB
Plaintext

SUBTTL SYSIO - IBMPC SYSTEM ROUTINES
PAGE +
PUBLIC MCHRI,MTTYO,MCRLF,MSPRT,MINIT,MPRNT,MTIME,FINISH
;READ A CHARACTER INTO AX, WAITING UNTIL ONE IS AVAILABLE, NO ECHO
MCHRI PROC
PUSH CX
PUSH DX
CMP CHRFLG,0
JNZ MCHR1
MOV CHRFLG,1
MCHR1: MOV AH,CNOECHO ; (7u) USE NO ECHO
INT 21H
SUB AH,AH
POP DX
POP CX
RET
MCHRI ENDP
PUBLIC FEEP
FEEP PROC
MOV AX,7
CALL MTTYO ;BELL
RET
FEEP ENDP
;PRINT THE CHARACTER IN AL, FOREGROUND IN AH
MTTYO PROC
PUSH AX
PUSH BX ;SAVES
PUSH CX
PUSH DX
PUSH BP
PUSH SI ; (A0) TRASHED ANOTHER
PUSH AX
TEST VIDFLG,1 ; (A10) IS THE SCREEN DEVICE ENABLED?
JZ MTY00 ; (A10) ....NO
DEC AL ; (A0) SEE IF IT IS IMBEDDED HILITE
XOR AH,AH
CMP AX,0 ; (A0) ITS VALUE WOULD BE BETWEEN 0-MAX
JB MTY0
CMP AX,MAXHI
JA MTY0
MOV SI,OFFSET COLORS ; ++ OF HILIGHTS
CMP COLFLG,1 ; (A5) SHOULD WE USE COLOR TABLE?
JZ MTY0A ; (A9) ....YES
MOV SI,OFFSET HILITES ; (A9) ^ IBM TABLE
CMP IBMPC,1 ; (A9) SHOULD WE USE THE IBM TABLE?
JZ MTY0A ; (A9) ....YES
MOV SI,OFFSET NONIBM ; (A9) USE THE NONIBM MONO TABLE
MTY0A: SHL AL,1 ; (A0) IT IS, MULTIPLY BY TWO
MOV BX,AX ; (A0) GET AN INDEX INTO TABLE
MOV BX,[BX][SI] ; (A0) BX HAS OFFSET TO STRING
CALL MSPRT ; (A0) PRINT THE STRING
POP AX
JMP MTYO1 ; (A0) RESTORE ON EXIT
MTY0: INC AL
MOV AH,CCONIO
MOV DL,AL
INT 21H
MTY00: POP AX ; (A10) NEW ENTRYPOINT
TEST SCRFLG,1 ; (7x) IS SCRIPTING REQUESTED?
JZ MTYO1 ; (7n) IF NOT THEN DON'T BOTHER
CMP SCRHLD,1 ; (7n) IS SCRIPTING SUSPENDED?
JZ MTYO1
CALL PRTOUT
MTYO1: POP SI
POP BP
POP DX
POP CX
POP BX
POP AX
RET
MTTYO ENDP
;PRINT A CARRIAGE RETURN/LINE FEED WITH MORE MODE
MCRLF PROC
PUSH AX ;SAVES
PUSH BX
PUSH CX
PUSH DX
PUSH BP
TEST VIDFLG,1 ; (A14) SCREEN DEVICE ON?
JZ MCR1 ; (A14) SKIP SCREEN SCROLL
TEST SCROLL,1 ;(7) WHAT KIND OF SCROLLING
JNZ MCR$
TEST SCRNFLG,1 ; (7) ARE WE IN SCREEN #1
JNZ MCR$ ; (7) YES, USE OLD SCROLL
MOV AH,SCROLLUP ;(7) USE A VIDEO BIOS SCROLL
MOV AL,1 ;(7) ONLY 1 LINE
MOV CX,TOPLIN ;(7) ALWAYS FREEZE TOP LINE
MOV DX,184FH ; (A0) USE CONSTANT
MOV BH,SCRATR ;(7) GET THE SCREEN ATTRIBUTE
INT 10H ;(7) CALL THE VIDEO
MCR$: MOV AH,CCONIO
MOV DL,13
INT 21H
TEST SCRNFLG,1 ; (7) ARE WE WRITING TO WINDOW 1
JNZ MCRA$
TEST SCROLL,1 ;(7) NO LINE FEED ON WINDOWED SCROLL
JZ NOLF
MCRA$: MOV AH,CCONIO
MOV DL,10
INT 21H
NOLF: TEST SCRNFLG,1 ;(7) NO MORE FOR WINDOW 1
JNZ MCR1 ;(7) SKIP THIS GARBAGE
INC MORLIN ;INCREMENT NUMBER OF LINES OUTPUT
MOV AL,SLPP
SUB AH,AH
DEC AX ;(7n) SO THAT STATUS LINE DOESN'T OVERWRITE
MCRB$: MOV DX,TOPLIN ;(7) GET SCROLLING WINDOW TOPLINE
XCHG DH,DL ;(7) SCROLL LINE IN DL
SUB AL,DL ;(7) THIS MANY LINES NOW
CMP MORLIN,AX
JL MCR1
MOV MORLIN,0
MOV SCRHLD,1 ; (7o) SUSPEND SCRIPT
PRINT MORE
CALL MCHRI
PRINT EMORE
MOV SCRHLD,0 ; (7o) RESUME SCRIPT
MCR1: TEST SCRFLG,1 ; (7x) CHANGED TO TEST
JZ MCR2
CALL PRTCRL
;(E0) REMOVE THIS
; OR WORD PTR ES:[PFLAGS],REFRESH ;(A17)REFRESH THE STATUS LINE
MCR2: POP BP
POP DX
POP CX
POP BX
POP AX
RET
MCRLF ENDP
MSPRT PROC
MOV CL,BYTE PTR [BX]
SUB CH,CH
CMP CL,0
JE MSPRT1
MSPLP: INC BX
MOV DL,BYTE PTR [BX]
MOV AH,06H
PUSH BX
INT 21H
POP BX
LOOP MSPLP
MSPRT1: RET
MSPRT ENDP
MINIT PROC
MINIT1: MOV BX,OFFSET STINIT
TEST COLFLG,1 ;(7) ARE WE IN COLOR MODE
JZ MINIT2 ;(7)
MOV BX,OFFSET CTINIT ;(7)
MINIT2: CALL MSPRT
RET
MINIT ENDP
;PRINT A STRING, POINTER (TO DATA SEGMENT) IN AX, WHITE FOREGROUND
MPRNT PROC
; (A10) SECTION COMMENTED OUT
; CMP GAMEIN,1 ; (7q)DO NOT CHECK THIS UNLESS THE GAME IS IN
; JNZ MPR0
; PUSH AX
; MOV AX,ES:[PFLAGS] ; (7n) SCRIPTING?
; XCHG AH,AL ; (7n) SWAP BYTES
; MOV SCRFLG,AL ; (7n) TURN IT ON, TURN IT ON AGAIN!
; POP AX
MPR0: PUSH BX ;SAVE BX
MOV BX,AX ;STRING POINTER
MPR1: MOV AL,[BX] ;GET NEXT CHARACTER
CMP AL,0 ;END OF LINE, WITH CRLF?
JE MPR2 ;YES
CMP AL,80H ;END OF LINE, NO CRLF?
JE MPR3 ;YES
CALL MTTYO ;PRINT CHARACTER
INC BX ;POINT TO NEXT CHARACTER
JMP MPR1 ;REPEAT
MPR2: CALL MCRLF ;PRINT A CRLF
MPR3: POP BX ;RESTORE BX
RET
MPRNT ENDP
;
; GET TIME AND USE IT TO SEED THE RANDOM NUMBER GENERATOR
;
MTIME PROC
PUSH CX ; SAVE REGISTERS
PUSH DX
MOV AH,CTIME ; GET TIME OF DAY
INT 21H
CMP CX,0 ; (LD1) IF NO CLOCK TIME
JNE MTIME0 ; (LD1) IS, SO OK
MOV RSEED1,08D0EH ; (LD1) USE A NUMBER
MOV RSEED2,09F81H ; (LD1) I JUST MADE UP SO NOT 0
JMP MTIME1 ; (LD1) DOES'NT MATTER, ONLY COMES HERE ONCE
MTIME0: MOV RSEED1,CX ; HOURS & MINUTES
MOV RSEED2,DX ; SECONDS & 100THS
MTIME1: POP DX ; RESTORE REGISTERS
POP CX
RET
MTIME ENDP
; ------------------------
; INITIALIZE SPEAKER TIMER
; ------------------------
;
; PURPOSE: THIS ROUTINE INITIALIZES THE PORTION OF THE 8253 TIMER
; CHIP USED BY THE SPEAKER SYSTEM. IN PARTICULAR, IT SETS
; UP CHANNEL 2 OF THE TIMER AS A SQUARE-WAVE GENERATOR.
;
; *** NOTE *** THIS ROUTINE IS TO BE CALLED DURING COLD START
;
; INPUTS: NONE
;
; OUTPUTS: TIMER 2
;
; REGISTERS DESTROYED: NONE
;
; EXTERNAL REFERENCES: NONE
;
PUBLIC INITSND
INITSND PROC
PUSH AX ;(A0) SAVE REGISTERS
MOV AL,TMRCWD ;(A0) GET TIMER CONTROL WORD
OUT TMRCPT,AL ;(A0) SEND IT TO THE CONTROL PORT
POP AX ;(A0) RESTORE REGISTERS
RET
INITSND ENDP
; ----------------------
; SET THE TONE FREQUENCY
; ----------------------
;
; PURPOSE: THIS ROUTINE SELECTS THE FREQUENCY OF THE SQUARE-WAVE
; TONE TO THE SPEAKER.
;
; INPUTS: CX=FREQUENCY
;
; OUTPUTS: TIMER 2
;
; REGISTERS DESTROYED: NONE
;
; EXTERNAL REFERENCES: NONE
;
PUBLIC TONESET
TONESET PROC
PUSH AX ;(A0) SAVE REGISTERS
PUSH CX
MOV AL,CL ;(A0) GET LOWER BYTE
OUT TMRDPT,AL ;(A0) SEND OUT VALUE TO TIMER
MOV AL,CH ;(A0) GET UPPER BYTE
OUT TMRDPT,AL ;(A0) SEND OUT VALUE TO TIMER
POP CX ;(A0) RESTORE REGISTERS
POP AX
RET
TONESET ENDP
; ------------
; TURN ON TONE
; ------------
;
; PURPOSE: THIS ROUTINE TURNS ON THE TIMER AND SPEAKER TO PRODUCE
; A TONE. THE FREQUENCY OF THE TONE MUST HAVE ALREADY
; BEEN SENT TO THE TIMER.
;
; INPUTS: NONE
;
; OUTPUTS: TIMER 2, AND SPEAKER
;
; REGISTERS DESTROYED: NONE
;
; EXTERNAL REFERENCES: NONE
;
PUBLIC TONEON
TONEON PROC
PUSH AX ;(A0) SAVE REGISTERS
IN AL,PTBCPT ;(A0) GET SYSTEM PORT B CONTROL DATA
OR AL,SPKRON ;(A0) TURN SPEAKER AND TIMER ON
OUT PTBCPT,AL ;(A0) SEND OUT NEW VALUE
POP AX ;(A0) RESTORE REGISTERS
RET
TONEON ENDP
; ------------
; TURN OFF TONE
; ------------
;
; PURPOSE: THIS ROUTINE TURNS OFF THE TIMER AND SPEAKER
;
; INPUTS: NONE
;
; OUTPUTS: TIMER 2, AND SPEAKER
;
; REGISTERS DESTROYED: NONE
;
; EXTERNAL REFERENCES: NONE
;
PUBLIC TONEOFF
TONEOFF PROC
PUSH AX ;(A0) SAVE REGISTERS
IN AL,PTBCPT ;(A0) GET SYSTEM PORT B CONTROL DATA
AND AL,SPKROFF ;(A0) TURN SPEAKER AND TIMER OFF
OUT PTBCPT,AL ;(A0) SEND OUT NEW VALUE
POP AX ;(A0) RESTORE REGISTERS
RET
TONEOFF ENDP
; -----
; DELAY
; -----
;
; PURPOSE: THIS ROUTINE DELAYS FOR A SPECIFIED NUMBER OF .05 SEC
; INTERVALS.
;
; INPUTS: [CX] = NUMBER OF .05 SEC TO DELAY
;
; OUTPUTS: NONE
;
; REGISTERS DESTROYED: NONE
;
; EXTERNAL REFERENCES: NONE
;
PUBLIC DELAY,DELAY1,DELAY2
DELAY PROC
PUSH AX ;(A0) SAVE REGISTERS
PUSH BX
PUSH CX
PUSH DX
CALL SYNCH ;(A0) SYNCHRONIZE TIMER
MOV TIMER,DL ;(A0) SAVE 1/100 SEC COUNT
; TIMING LOOP
DELAY1: PUSH CX ;(A0) SAVE LOOP COUNTER
DELAY2: MOV AH,CTIME ;(A0) GET THE TIME UNTIL IT CHANGES
INT 21H ;(A0) MSDOS FUNCTION CALL
CMP DL,TIMER ;(A0) HAS THE CLOCK TICKED?
JNZ DELAY3 ; YES, GO DO COUNTDOWN
CMP DL,0 ; NO, BUT IF NOT STUCK AT 0
JNZ DELAY2 ; WAIT FOR IT TO TICK
POP CX ; CLEAN UP STACK
JMP DELAY4 ; AND LEAVE
DELAY3: MOV TIMER,DL ;(A0) SAVE NEW COUNT
POP CX ; GET LOOP COUNTER BACK
LOOP DELAY1 ;(A0) AND LOOP
DELAY4: POP DX ;(A0) RESTORE REGISTERS
POP CX
POP BX
POP AX
RET
DELAY ENDP
; -----
; SYNCH
; -----
;
; PURPOSE: THIS ROUTINE WAITS FOR A CHANGE IN THE 1/100 SEC TIMER, TO
; INSURE THAT WE'RE AT THE START OF A NEW TIME PERIOD.
;
; INPUTS: NONE
;
; OUTPUTS: [DL] = 1/100 SEC COUNT AT SYNCH TIME
;
; REGISTERS DESTROYED: DL
;
; EXTERNAL REFERENCES: NONE
;
PUBLIC SYNCH,SYNCH1
SYNCH PROC
PUSH AX ;(A0) SAVE REGISTERS
PUSH BX
PUSH CX
MOV AH,CTIME ;(A0) GET THE TIME FROM THE REAL TIME CLOCK
INT 21H ;(A0) MSDOS FUNCTION CALL
MOV TIMER,DL ;(A0) SAVE 1/100 SEC COUNT
; SYNCHRONIZE
SYNCH1: MOV AH,CTIME ;(A0) GET THE TIME AGAIN, SO WE CAN INSURE
INT 21H ;(A0) THAT WE ARE SYNCHRONIZED WITH THE
CMP DL,TIMER ;(A0) START OF A NEW TIMING PERIOD
JNZ SYNCH2 ; CLOCK TICKED, SO WIN
CMP DL,0 ; CLOCK DIDN'T TICK, AND IS 0, SO QUIT
JNZ SYNCH1 ; HACK TO PREVENT LOOPS WHEN 1/100'S
; CLOCK ISN'T WORKING
SYNCH2: POP CX ;(A0) RESTORE REGISTERS
POP BX
POP AX
RET
SYNCH ENDP
; ----
; FREQ
; ----
;
; PURPOSE: THIS ROUTINE CONVERTS A FREQUENCY TO THE NUMBER REQUIRED
; BY TONESET.
;
; INPUTS: [CX] = FREQUENCY IN HZ
;
; OUTPUTS: [CX] = CONVERTED VALUE
;
; REGISTERS DESTROYED: CX
;
; EXTERNAL REFERENCES: NONE
;
PUBLIC FREQ
FREQ PROC
PUSH AX ;(A0) SAVE REGISTERS
PUSH BX
PUSH DX
; DIVIDE FREQUENCY BY 1193182
MOV DX,12H ;(A0) UPPER PART OF NUMERATOR
MOV AX,34DEH ;(A0) LOWER PART OF NUMERATOR
DIV CX ;(A0) DIVIDE BY FREQUENCY
MOV CX,AX ;(A0) QUOTIENT IS THE OUTPUT
POP DX ;(A0) RESTORE REGISTERS
POP BX
POP AX
RET
FREQ ENDP
; -----------
; MAKE A TONE
; -----------
;
; PURPOSE: THIS ROUTINE MAKES A TONE OF A GIVEN FREQUENCY AND LENGTH
;
; INPUTS: [CX] = FREQUENCY IN HZ
; [DX] = DURATION IN .05 SEC
;
; OUTPUTS: TO THE SPEAKER AND TIMER 2
;
; REGISTERS DESTROYED: NONE
;
; EXTERNAL REFERENCES: {TONESET}, {TONEON}, {TONEOFF}, {DELAY}
;
PUBLIC TONE
TONE PROC
PUSH AX ;(A0) SAVE REGISTERS
PUSH BX
PUSH CX
PUSH DX
; COMPUTE THE FREQUENCY AND SETUP THE TONE GENERATOR (TIMER 2)
CALL FREQ ;(A0) CONVERT THE FREQUENCY
CALL TONESET ;(A0) SET UP TIMER 2
; TURN ON THE TONE
CALL TONEON
; WAIT FOR THE DELAY TIME
MOV CX,DX
CALL DELAY
; TURN OFF THE TONE
CALL TONEOFF
POP DX ;(A0) RESTORE THE REGISTERS
POP CX
POP BX
POP AX
RET
TONE ENDP