Skip to content

Instantly share code, notes, and snippets.

@hc0d3r
Created December 28, 2016 00:01
Show Gist options
  • Save hc0d3r/68d9596e61a978d58d039f1d9b9be422 to your computer and use it in GitHub Desktop.
Save hc0d3r/68d9596e61a978d58d039f1d9b9be422 to your computer and use it in GitHub Desktop.
Old PC BIOS Assembly Language Listing
TITLE (ROM BIOS FOR IBM PERSONAL COMPUTER)
.MODEL COMPACT
OPTION M510
;-------------------
;EQUATES
;-------------------
PORT_A EQU 60H ;8255 PORT A ADDR
PORT_B EQU 61H ;8255 PORT B ADDR
PORT_C EQU 62H ;8255 PORT C ADDR
CMD_PORT EQU 63H
INTA00 EQU 20H ;8259 PORT
INTA01 EQU 21H ;8259 PORT
EOI EQU 20H
TIMER EQU 40H
TIM_CTL EQU 43H ;8253 TIMER CONTROL PORT ADDR
TIMER0 EQU 40H ;8253 TIMER/CNTER 0 PORT ADDR
TMINT EQU 01 ;TIMER 0 INTR RECVD MASK
DMA08 EQU 08 ;DMA STATUS REG PORT ADDR
DMA EQU 00 ;DMA CHANNEL 0 ADDRESS REG PORT ADDR
MAX_PERIOD EQU 540H
MIN_PERIOD EQU 410H
KBD_IN EQU 60H ;KEYBOARD DATA IN ADDR PORT
KBDINT EQU 02 ;KEYBOARD INTR MASK
KB_DATA EQU 60H ;KEYBOARD SCAN CODE PORT
KB_CTL EQU 61H ;CONTROL BITS FOR KEYBOARD SENSE DATA
;----------------------------------
;8088 INTERRUPT LOCATIONS
;----------------------------------
ABS0 SEGMENT
ORG 0
STG_LOC0 LABEL BYTE
ORG 2*4
NMI_PTR LABEL WORD
ORG 5*4
INT5_PTR LABEL WORD
ORG 8*4
INT_ADDR LABEL WORD
INT_PTR LABEL DWORD
ORG 10H*4
VIDEO_INT LABEL WORD
ORG 1DH*4
PARM_PTR LABEL DWORD ; POINTER TO VIDEO PARMS
ORG 01EH*4 ; INT 1EH
DISK_POINTER LABEL DWORD
ORG 01FH*4 ; LOCATION OF POINTER
EXT_PTR LABEL DWORD ; POINTER TO EXTENSION
ORG 7C00H
BOOT_LOCN LABEL FAR
ABS0 ENDS
;---------------------
; STACK -- USED DURING INITIALIZATION ONLY
;---------------------
TSTACK SEGMENT 'STACK' ;AT 30H
ORG 30H
DW 128 DUP(?)
TOS LABEL WORD
TSTACK ENDS
;-----------------------------------------
; ROM BIOS DATA AREAS
;-----------------------------------------
DATA SEGMENT 'DATA' ; AT 40H
ORG 40H
RS232_BASE DW 4 DUP(?) ; ADDRESSES OF RS232 ADAPTERS
PRINTER_BASE DW 4 DUP(?) ; ADDRESSES OF PRINTERS
EQUIP_FLAG DW ? ; INSTALLED HARDWARE
MFG_TST DB ? ; INITIALIZATION FLAG
MEMORY_SIZE DW ? ; MEMORY SIZE IN K BYTES
IO_RAM_SIZE DW ? ; MEMORY IN I/O CHANNEL
;-----------------------------------------
; KEYBOARD DATA AREAS
;-----------------------------------------
KB_FLAG DB ?
;----- SHIFT FLAG EQUATES WITHIN KB_FLAG
INS_STATE EQU 80H ; INSERT STATE IS ACTIVE
CAPS_STATE EQU 40H ; CAPS LOCK STATE HAS BEEN TOGGLED
NUM_STATE EQU 20H ; NUM LOCK STATE HAS BEEN TOGGLED
SCROLL_STATE EQU 10H ; SCROLL LOCK STATE HAS BEEN TOGGLED
ALT_SHIFT EQU 08H ; ALTERNATE SHIFT KEY DEPRESSED
CTL_SHIFT EQU 04H ; CONTROL SHIFT KEY DEPRESSED
LEFT_SHIFT EQU 02H ; LEFT SHIFT KEY DEPRESSED
RIGHT_SHIFT EQU 01H ; RIGHT SHIFT KEY DEPRESSED
KB_FLAG_1 DB ? ; SECOND BYTE OF KEYBOARD STATUS
INS_SHIFT EQU 80H ; INSERT KEY IS DEPRESSED
CAPS_SHIFT EQU 40H ; CAPS LOCK KEY IS DEPRESSED
NUM_SHIFT EQU 20H ; NUM LOCK KEY IS DEPRESSED
SCROLL_SHIFT EQU 10H ; SCROLL LOCK KEY IS DEPRESSED
HOLD_STATE EQU 08H ; SUSPEND KEY HAS BEEN TOGGLED
ALT_INPUT DB ? ; STORAGE FOR ALTERNATE KEYPAD ENTRY
BUFFER_HEAD DW ? ; POINTER TO HEAD OF KEYBOARD BUFFER
BUFFER_TAIL DW ? ; POINTER TO TAIL OF KEYBOARD BUFFER
KB_BUFFER DW 16 DUP(?) ; ROOM FOR 15 ENTRIES
KB_BUFFER_END LABEL WORD
;------ HEAD = TAIL INDICATES THAT THE BUFFER IS EMPTY
NUM_KEY EQU 69 ; SCAN CODE FOR NUMBER LOCK
SCROLL_KEY EQU 70 ; SCROLL LOCK KEY
ALT_KEY EQU 56 ; ALTERNATE SHIFT KEY SCAN CODE
CTL_KEY EQU 29 ; SCAN CODE FOR CONTROL KEY
CAPS_KEY EQU 58 ; SCAN CODE FOR SHIFT LOCK
LEFT_KEY EQU 42 ; SCAN CODE FOR LEFT SHIFT
RIGHT_KEY EQU 54 ; SCAN CODE FOR RIGHT SHIFT
INS_KEY EQU 82 ; SCAN CODE FOR INSERT KEY
DEL_KEY EQU 83 ; SCAN CCDE FOR DELETE KEY
;-----------------------------------------
; DISKETTE DATA AREAS
;-----------------------------------------
SEEK_STATUS DB ? ; DRIVE RECALIBRATION STATUS
; BIT 3-0 = DRIVE 3-0 NEEDS RECAL BEFORE
; NEXT SEEK IF BIT IS = 0
INT_FLAG EQU 080H ; INTERRUPT OCCURRENCE FLAG
MOTOR_STATUS DB ? ; MOTOR STATUS
; BIT 3-0 = DRIVE 3-0 IS CURRENTLY RUNNING
; BIT 7 : CURRENT OPERATICN IS A WRITE, REQUIRES DELAY
MOTOR_COUNT DB ? ;TIME OUT COUNTER FOR DRIVE TURN OFF
MOTOR_WAIT EQU 37 ;TWO SECONDS OF COUNTS FOR MOTOR TURN OFF
;
DISKETTE_STATUS DB ? ; SINGLE BYTE OF RETURN CODE INFO FOR STATUS
TIME_OUT EQU 80H ; ATTACHMENT FAILED TO RESPOND
BAD_SEEK EQU 40H ; SEEK OPERATION FAILED
BAD_NEC EQU 20H ; NEC CONTROLLER HAS FAILED
BAD_CRC EQU 10H ; BAD CRC ON DISKETTE READ
DMA_BOUNDARY EQU 09H ; ATTEMPT TO DMA ACROSS 64K BOUNDARY
BAD_DMA EQU 08H ; DMA OVERRUN ON OPERATION
RECORD_NOT_FND EQU 04H ; REQUESTED SECTOR NOT FOUND
WRITE_PROTECT EQU 03H ; WRITE ATTEMPTED ON WRITE PROT DISK
BAD_ADDR_MARK EQU 02H ; ADDRESS MARK NOT FOUND
BAD_CMD EQU 01H ; BAD COMMAND PASSED TO DISKETTE I/O
NEC_STATUS DB 7 DUP(?) ; STATUS BYTES FROM NEC
;-----------------------------------------
; VIDEO DISPLAY DATA AREA
;-----------------------------------------
CRT_MODE DB ? ; CURRENT CRT MODE
CRT_COLS DW ? ; NUMBER OF COLUMNS ON SCREEN
CRT_LEN DW ? ; LENGTH OF REGEN IN BYTES
CRT_START DW ? ; STARTING ADDRESS IN REGEN BUFFER
CURSOR_POSN DW 8 DUP(?) ; CURSOR FOR EACH OF UP TO 8 PAGES
CURSOR_MODE DW ? ; CURRENT CURSOR MODE SETTING
ACTIVE_PAGE DB ? ; CURRENT PAGE BEING DISPLAYED
ADDR_6845 DW ? ; BASE ADDRESS FOR ACTIVE DISPLAY CARD
CRT_MODE_SET DB ? ; CURRENT SETTING OF THE 3X8 REGISTER
CRT_PALLETTE DB ? ; CURRENT PALLETTE SETTING COLOR CARD
;-----------------------------------------
; CASSETTE DATA AREA
;-----------------------------------------
EDGE_CNT DW ? ;TIME COUNT AT DATA EDGE
CRC_REG DW ? ;CRC REGISTER
LAST_VAL DB ? ;LAST INPUT VALUE
;-----------------------------------------
; TIMER DATA AREA
;-----------------------------------------
TIMER_LOW DW ? ; LOW WORD OF TIMER COUNT
TIMER_HIGH DW ? ; HIGH WORD OF TIMER COUNT
TIMER_OFL DB ? ; TIMER HAS ROLLED OVER SINCE LAST READ
;COUNTS_SEC EQU 18
;COUNTS_MIN EQU 1092
;COUNTS_HOUR EQU 65543
;COUNTS_DAY EQU 1573040 = 1800B0H
;-----------------------------------------
; SYSTEM DATA AREA
;-----------------------------------------
BIOS_BREAK DB ? ; BIT 7 = 1 IF BREAK KEY HAS BEEN DEPRESSED
RESET_FLAG DW ? ; WORD = 1234H IF KEYBDARD RESET UNDERWAY
DATA ENDS
;-----------------------------------------
; EXTRA DATA AREA
;-----------------------------------------
XXDATA SEGMENT ; AT 50H
ORG 50H
STATUS_BYTE DB ?
XXDATA ENDS
;-----------------------------------------
; VIDEO DISPLAY BUFFER
;-----------------------------------------
VIDEO_RAM SEGMENT ; AT 0B800H
ORG 0B800H
REGEN LABEL BYTE
REGENW LABEL WORD
DB 16384 DUP(?)
VIDEO_RAM ENDS
;-----------------------------------------
; ROM RESIDENT CODE
;-----------------------------------------
CODE SEGMENT 'CODE' ; AT 0F000H
ORG 0E000H
; DB 57344 DUP(?) ; FILL LOWEST 56K
DB '5700051 COPR. IBM 1981'; COPYRIGHT NOTICE
;=========================================
; INITIAL RELIABILITY TESTS -- PHASE 1
;-----------------------------------------
ASSUME CS:CODE,SS:CODE,ES:ABS0,DS:DATA
;-----------------------------------------
; DATA DEFINITIONS
;-----------------------------------------
C1 DW C11 ; RETURN ADDRESS
C2 DW C24 ; RETURN ADDRESS FOR DUMMY STACK
;-----------------------------------------
; THIS SUBROUTINE PERFORMS A READ/WRITE STORAGE TEST ON A 16K BLOCK
; OF STORGAGE.
;ENTRY REQUIREMENTS:
; ES = ADDRESS OF STORAGE SEGMENT BEING TESTED
; DS = ADDRESS OF STORAGE SEGMENT BEING TESTED
; WHEN ENTERING AT STGTST_CNT, CX MUST BE LOADED WITH THE BYTE COUNT.
;EXIT PARAMETERS:
; ZERO FLAG = 0 IF STORAGE ERROR (DATA COMPARE OR PARITY CHECK. AL=0
; DENOTES A PARITY CHECK. ELSE AL=XOR'ED BIT PATTERN OF THE
; EXPECTED DATA PATTERN VS THE ACTUAL DATA READ.
; AX,BX,CX,DX,DI, AND SI ARE ALL DESTROYED.
;-----------------------------------------
STGTST PROC NEAR
MOV CX,04000H ;SETUP CNT TO TEST A 16K BLK
STGTST_CNT:
CLD ;SET DIR FLAG TO INCREMENT
MOV BX,CX ;SAVE BYTE CNT (4K FOR VIDEO OR 16K)
MOV AX,0FFFFH ;GET DATA PATTERN TO WRITE
MOV DX,0AA55H ;SETUP OTHER DATA PATTERNS TO USE
SUB DI,DI ;DI = OFFSET 0 RELATIVE TO ES REG
REP STOSB ;WRITE STORAGE LOCATIONS
C3: ; STG01
DEC DI ;POINT TO LAST BYTE JUST WRITTEN
STD ;SET DIR FLAG TO GO BACKWARDS
C4: MOV SI,DI
MOV CX,BX ;SETUP BYTE CNT
C5: LODSB ;READ CHAR FROM STORAGE
XOR AL,AH ;DATA READ AS EXPECTED?
JNE C7 ;NO - GO TO ERROR ROUTINE
IN AL,PORT_C ;DID A PARITY ERROR OCCUR?
AND AL,0C0H
MOV AL,0 ;AL=0 DATA COMPARE OK
JNZ C7
CMP AH,0 ;READING ZERO PATTERN?
JE C6 ;CONTINUE READING TILL END
MOV AL,DL ;GET NEXT DATA PATTERN TO WRITE
STOSB ;WRITE IN BYTE LOC WE JUST READ
C6: ; WRITE_NO_MORE
LOOP C5 ;CONTINUE TILL 16K/4K BLOCK TESTED
CMP AH,0 ;ZERO PATTERN WRITTEN TO STG
JE C7 ;YES - RETURN TO CALLER
MOV AH,AL ;SETUP TO NEW VALUE TO COMPARE
XCHG DH,DL ;MOVE ZERO DATA PATTERN TO DL
CLD ;SET DIR FLAG TO GO FORWARD
INC DI ;SET POINTER TO BEG LOCATION
JZ C4 ;READ/WRITE FORWARD IN STG
DEC DI
MOV DX,1 ;SETUP 01 AND 00 PATTERNS
JMP SHORT C3 ;READ/WRITE BACKWARD IN STG
C7:
RET
STGTST ENDP
;--------------------------------------------
;TEST.01
; 8088 PROCESSOR TEST
;DESCRIPTION
; VERIFY 8088 FLAGS, REGISTERS AND CONDITIONAL JUMPS
;--------------------------------------------
RESET LABEL NEAR
START: CLI ;DISABLE INTERRUPTS
MOV AH,0D5H ;SET SF, CF, ZF, AND AF FLAGS ON
SAHF
JNC ERR01 ;GO TO ERR ROUTINE IF CF NOT SET
JNZ ERR01 ;GO TO ERR ROUTINE IF ZF NOT SET
JNP ERR01 ;GO TO ERR ROUTINE IF PF NOT SET
JNS ERR01 ;GO TO ERR ROUTINE IF SF NOT SET
LAHF ;LOAD FLAG IMAGE TO AH
MOV CL,5 ;LOAD CNT REG WITH SHIFT CNT
SHR AH,CL ;SHIFT AF INTO CARRY BIT POS
JNC ERR01 ;SO TO ERR ROUTINE IF AF NOT SET
MOV AL,40H ;SET THE OF FLAG ON
SHL AL,1 ;SETUP FOR TESTING
JNO ERR01 ;GO TO ERR ROUTINE IF OF NOT SET
XOR AH,AH ;SET AH = 0
SAHF ;CLEAR SF, CF, ZF, AND PF
JC ERR01 ;GO TO ERR ROUTINE IF CF ON
JZ ERR01 ;GO TO ERR ROUTINE IF ZF ON
JS ERR01 ;GO TO ERR ROUTINE IF SF ON
JP ERR01 ;GO TO ERR ROUTINE IF PF ON
LAHF ;LOAD FLAG IMAGE TO AH
MOV CL,5 ;LOAD CNT REG WITH SHIFT CNT
SHR AH,CL ;SHIFT AH INTO CARRY BIT POS
JC ERR01 ;GO TO ERR ROUTINE IF ON
SHL AH,1 ;CHECK THAT OF IS CLEAR
JO ERR01 ;GO TO ERR ROUTINE IF ON
; READ/WRITE THE 8088 GENERAL AND SEGMENTATION REGI5TERS
; WITH ALL ONE'S ANO ZEROES'S.
MOV AX,0FFFFH ;SETUP ONE'S PATTERN IN AX
STC
C8: MOV DS,AX ;WRITE PATTERN TO ALL REGS
MOV BX,DS
MOV ES,BX
MOV CX,ES
MOV SS,CX
MOV DX,SS
MOV SP,DX
MOV BP,SP
MOV SI,BP
MOV DI,SI
JNC C9 ; TST1A
XOR AX,DI ;PATTERN MAKE IT THRU ALL REGS
JNZ ERR01 ;NO - GO TO ERR ROUTINE
CLC
JNC C8
C9: ; TST1A
OR AX,DI ;ZERO PATTERN MAKE IT THRU?
JZ C10 ;YES - GO TO NEXT TEST
ERR01: HLT ;HALT SYSTEM
;--------------------------------------------
; TEST.02
; ROS CHECKSUM TEST 1
;DESCRIPTION
; A CHECKSUM IS DONE FOR THE 8K ROS MODULE CONTAINING POD AND BIOS.
;--------------------------------------------
C10:
MOV AL,0 ;DISABLE NMI INTERRUPTS
OUT 0A0H,AL
OUT 83H,AL ;INITIALIZE DMA PAGE REG
MOV AL,99H ;SET 8255 A,C-INPUT,B-OUTPUT
OUT CMD_PORT,AL ;WRITE 8255 CMD/MODE REG
MOV AL,0FCH ;DISABLE PARITY CHECKERS AND
OUT PORT_B,AL ; GATE SNS SWS,CASS MOTOR OFF
SUB AL,AL
MOV DX, 3D8H
OUT DX,AL ;DISABLE COLOR VIDEO
INC AL
MOV DX,3B8H
OUT DX,AL ;DISABLE B/W VIDEO,EN HIGH RES
MOV AX,CODE ;SETUP SS SEG REG
MOV SS,AX
MOV DX,0E000H ;SETUP STARTING ROS ADDR
MOV SP,OFFSET C1 ;SETUP RETURN ADDRESS
JMP ROS_CHECKSUM
C11: JNE ERR01 ;HALT SYSTEM IF ERROR
;--------------------------------------------
;TEST.03
; 8237 DMA INITIALIZATION CHANNEL REGISTER TEST
;DESCRIPTION
; DISABLE THE 8237 DMA CONTROLLER. VERIFY THAT TIMER 1 FUNCTIONS OK.
; WRITE/READ THE CURRENT ADDRESS AND WORD COUNT REGISTERS FOR ALL
; CHANNELS INITIALIZE AND START DMA FOR MEMORY REFRESH.
;------------------------------------------
; DISABLE DMA CONTROLLER
MOV AL,04 ;DISABLE DMA CONTROLLER
OUT DMA08,AL
; VERIFY THAT TIMER 1 FUNCTIONS OK
MOV AL,54H ;SEL TIMER 1,LSB,MODE 2
OUT TIMER+3,AL
SUB CX,CX ;
MOV BL,CL
MOV AL,CL ;SET INITIAL TIMER CNT TO 0
OUT TIMER+1,AL
C12: ; TIMER1_BITS_ON
MOV AL,40H ;LATCH TIMER 1 COUNT
OUT TIMER+3,AL
IN AL,TIMER+1 ;READ TIMER 1 COUNT
OR BL,AL ;ALL BITS ON IN TIMER
CMP BL,0FFH ;YES - SEE IF ALL BITS GO OFF
JE C13 ; TIMER1_BITS_OFF
LOOP C12 ; TIMER1_BITS_ON
JMP SHORT ERR01 ;TIMER 1 FAILURE, HALT SYS
C13: ; TIMER1_BITS_OFF
MOV AL,BL ;SET TIMER 1 CNT
SUB CX,CX
OUT TIMER+1,AL
C14: ; TIMER_LOOP
MOV AL,40H ;LATCH TIMER 1 COUNT
OUT TIMER+3,AL
IN AL,TIMER+1 ;READ TIMER 1 COUNT
AND BL,AL
JZ C15 ; WRAP_DMA_REG
LOOP C14 ; TIMER_LOOP
JMP SHORT ERR01
; INITIALIZE TIMER 1 TO REFRESH MEMORY
C15: ; WRAP_DMA_REG
MOV AL,54H ;SEL TIM 1, LSB, MODE 2
OUT TIMER+3,AL ;WRITE TIMER MODE REG
MOV AL,18 ;SETUP DIVISOR FOR REFRESH
OUT TIMER+1,AL ;WRITE TIMER 1 CNT REG
OUT DMA+0DH,AL ;SEND MASTER CLEAR TO DMA
; WRAP DMA CHANNELS ADDRESS AND COUNT REGISTERS
MOV AL,0FFH ;WRITE PATTERN FFH TO ALL REGS
C16: MOV BL,AL ;SAVE PATTERN FOR COMPARE
MOV BH,AL
MOV CX,8 ;SETUP LOOP CNT
MOV DX,DMA ;SETUP I/O PORT ADDR OF REG
C17: OUT DX,AL ;WRITE PATTERN TO REG, LSB
OUT DX,AL ;MSB OF 16 BIT REG
MOV AX,0101H ;AX TO ANOTHER PAT BEFORE RD
IN AL,DX ;READ 16-BIT DMA CH REG, LSB
MOV AH,AL ;SAVE LSB OF 16-BIT REG
IN AL,DX ;READ MSB OF DMA CH REG
CMP BX,AX ;PATTERN READ AS WRITTEN?
JE C18 ;YES - CHECK NEXT REG
JMP ERR01 ;NO - HALT THE SYSTEM
C18: ; NXT_DMA_CH
INC DX ;SET I/O PORT TO NEXT CH REG
LOOP C17 ;WRITE PATTERN TO NEXT REG
NOT AL ;SET PATTERN TO ZERO
JZ C16 ;WRITE TO CHANNEL REGS
; INITIALIZE AND START DMA FOR MEMORY REFRESH.
MOV AL,0FFH ;SET CNT OF 64K FOR RAM REFRESH
OUT DMA+1,AL
OUT DMA+1,AL
MOV AL,058H ;SET DMA MODE,CH 0,READ,AUOTINT
OUT DMA+0BH,AL ;WRITE DMA MODE REG
MOV AL,0 ;ENABLE DMA CONTROLLER
OUT DMA+8,AL ;SETUP DMA COMMAND REG
OUT DMA+10,AL ;ENABLE CHANNEL 0 FOR REFRESH
MOV AL,41H ;SET MODE FOR CHANNEL 1
OUT DMA+0BH,AL
MOV AL,42H ;SET MODE FOR CHANNEL 2
OUT DMA+0BH,AL ;
MOV AL,43H ;SET MODE FOR CHANNEL 3
OUT DMA+0BH,AL
;--------------------------------------------
;TEST.04
; BASE 16K READ/WRITE STORAGE TEST
;DESCRIPTION
; WRITE/READ/VERIFY DATA PATTERNS FF,55,AA,01, AND 00 TO 1ST 16K OF
; STORAGE. VERIFY STORAGE ADDRESSABILITY.
; INITIALIZE THE 8259 INTERRUPT CONTROLLER CHIP FOR CHECKING
; MANUFACTURING TEST 2 MODE.
;--------------------------------------------
; DETERMINE MEMORY SIZE AND FILL MEMORY WITH DATA
MOV AX,DATA ;POINT DS TO DATA SEG
MOV DS,AX ;
MOV BX,RESET_FLAG ;SAVE RESET_FLAG IN BX
SUB AX,AX ;SET ES AND DS TO 0
MOV ES,AX ;SETUP ES SEGMENT REG
MOV DS,AX
SUB DI,DI
IN AL,PORT_A ;DETERMINE BASE RAM SIZE
AND AL,0CH ;ISOLATE RAM SIZE SWS
ADD AL,4 ; CALCULATE MEMORY SIZE
MOV CL,12
SHL AX,CL
MOV CX,AX
MOV AH,AL
CLD ;SET DIR FLAG TO INCR
C19: STOSB ;FILL BASE RAM WITH DATA
LOOP C19 ; LOOP TIL ALL ZERO
; DETERMINE IO CHANNEL RAM SIZE
IN AL,PORT_C
AND AL,0FH
JZ C21
MOV DX,1000H ; SEGMENT FOR I/O RAM
MOV AH,AL
MOV AL,0
C20: ; FILL_IO
MOV ES,DX
MOV CX,8000H ; FILL 32K BYTE5
SUB DI,DI
REP STOSB
ADD DX,800H ; NEXT SEGMENT VALUE
DEC AH
JNZ C20 ; FILL_IO
;--------------------------------------------
; INITIALIZE THE 8259 INTERRUPT CONTROLLER CHIP
;--------------------------------------------
C21:
MOV AL,13H ;ICW1 - EDGE, SNGL, ICW4
OUT INTA00,AL
MOV AL,8 ;SETUP ICW2 - INT TYPE 8 (8-F)
OUT INTA01,AL
MOV AL,9 ;SETUP ICW4 - BUFFRD,8086 MODE
OUT INTA01,AL
SUB AX,AX ;POINT DS AND ES TO BEGIN
MOV ES,AX ; OF R/W STORAGE
MOV SI,DATA ;POINT DS TO DATA SEG
MOV DS,SI ;
MOV RESET_FLAG,BX ;RESTORE RESET_FLAG
CMP RESET_FLAG,1234H ;RESET_FLAG SET?
JE C25 ;YES - SKIP STG TEST
MOV DS,AX ;POINT DS TO 1ST 16K OF STG
;--------------------------------------------
; CHECK FOR MANUFACTURING TEST 2 TO LOAD TEST PROGRAMS FROM KEYBOARD.
;--------------------------------------------
MOV SP,3FF0H ; ESTABLISH TEMPORARY STACK
MOV SS,AX
MOV DI,AX
MOV BX,24H
MOV WORD PTR [BX],OFFSET D11 ;SET UP KB INTERRUPT
INC BX
INC BX
MOV [BX],CS
CALL KBD_RESET ; READ IN KB RESET CODE TO BL
CMP BL,065H ; IS THIS MANUFACTURING TEST 2?
JNZ C23 ; JUMP IF NOT MAN. TEST
MOV DL,255 ; READ IN TEST PROGRAM
C22: CALL SP_TEST
MOV AL,BL
STOSB
DEC DL
JNZ C22 ; JUMP IF NOT DONE RET
INT 3EH ;SET INTERUPT TYPE 62 ADDRESS FBH
C23: ;CONTINUE IN NORMAL MOOE
PUSH CS ; PUT SS BACK
POP SS
CLI ;
MOV SP,OFFSET C2 ;SETUP RETURN ADDRESS
JMP STGTST ;GO TO RD/WRT STG SUBROUTINE
C24: JE C25 ;GO TO NEXT TEST IF OK
JMP ERR01
; SETUP STACK SEG AND SP
C25:
MOV AX,TSTACK ; GET STACK VALUE
MOV SS,AX ; SET THE STACK UP
MOV SP,OFFSET TOS ; STACK IS READY TO GO
; SETUP THE NMI INTERRUPT VECTOR POINTER
MOV ES:NMI_PTR,OFFSET NMI_INT
MOV ES:NMI_PTR+2,CODE
JMP NEAR PTR TST6 ;GO TO NEXT TEST
ROS_CHECKSUM PROC NEAR ; NEXT_ROS_MODULE
MOV CX,8192 ;NUMBER OF BYTES TO ADD
XOR AL,AL
C26:
ADD AL,CS:[BX]
INC BX ;POINT TO NEXT BYTE
LOOP C26 ;ADD ALL BYTES IN ROS MODULE
OR AL,AL ;SUM = 0?
RET
ROS_CHECKSUM ENDP
;--------------------------------------
; INITIAL RELIABILITY TEST -- PHASE 2
;---------------------------------------
ASSUME CS:CODE,ES:ABS0
D1 DB 'PARITY CHECK 2'
D1L EQU $-D1
D2 DB 'PARITY CHECK 1'
D2L EQU $-D2
;---------------------------------------------
; TEST.06
; 8259 INTERRUPT CONTROLLER TEST
;DESCRIPTION
; READ/WRITE THE INTERRUPT MASK REGISTER (IMR) WITH ALL ONES AND ZEROES
; ENABLE SYSTEM INTERRUPTS. MASK DEVICE INTERRUPTS OFF. CHECK FOR
; HOT INTERRUPTS (UNEXPECTED).
;--------------------------------------------
TST6:
SUB AX,AX ;SET UP ES REG
MOV ES,AX
;------ SET UP THE INTERRUPT 5 POINTER TO A DUMMY
MOV ES:INT5_PTR,OFFSET PRINT_SCREEN ;PRINT SCREEN
MOV ES:INT5_PTR+2,CODE ;
; TEST THE IMR REGISTER
CLI ;DISABLE INTERRUPTS
MOV AL,0
OUT INTA01,AL
IN AL,INTA01 ;READ IMR
OR AL,AL ;IMR = 0?
JNZ D6 ;GO TO ERR ROUTINE IF NOT 0
MOV AL,0FFH ;DISABLE DEVICE INTERRUPTS
OUT INTA01,AL ;WRITE TO IMR
IN AL,INTA01 ;READ IMR
ADD AL,1 ;ALL IMR BITS ON?
JNZ D6 ;NO - GO TO ERR ROUTINE
; CHECK FOR HOT INTERRUPTS
CLD ;SET DIR FLAG TO GO FORWARD
MOV CX,8 ;SETUP TEMP INT RTNE IN PRT TBL
MOV DI,OFFSET INT_PTR ;GET ADDRESS OF INT PROC TABLE
D3: ; VECTBL0
MOV AX,OFFSET D11 ;MOVE ADDR OF INTR PROC TO TBL
STOSW
MOV AX,CODE ;GET ADDR OF INTR PROC SEG
STOSW
ADD BX,4 ;SET BX TO POINT TO NEXT VAL
LOOP D3 ; VECTBL0
; INTERRUPTS ARE MASKED OFF. CHECK THAT NO INTERRUPTS OCCUR
XOR AH,AH ;CLEAR AH REG
STI ;ENABLE EXTERNAL INTERRUPTS
SUB CX,CX ;WAIT 1 SEC FOR ANY INTRS THAT
D4: LOOP D4 ;MIGHT OCCUR
D5: LOOP D5
OR AH,AH ;DID ANY INTERRUPTS OCCUR?
JZ D7 ;NO - GO TO NEXT TEST
D6: MOV DX,101H ;BEEP SPEAKER IF ERROR
CALL ERR_BEEP ;GO TO BEEP SUBROUTINE
CLI
HLT ;HALT THE SYSTEM
;--------------------------------------------
;TEST.7
; 8253 TIMER CHECKOUT
;DESCRIPTION
; VERIFY THAT THE SYSTEM TIMER (0) DOESN'T COUNT TOO FAST NOR TOO
; SLOW.
;--------------------------------------------
D7:
MOV AH,0 ;RESET TIMER INTR RECVD FLAG
XOR CH,CH ;CLEAR THE CH REG
MOV AL,0FEH ;MASK ALL INTRS EXCEPT LVL 0
OUT INTA01,AL ;WRITE THE 8259 IMR
MOV AL,00010000B ;SEL TIM 0, LSB, MODE 0, BINARY
OUT TIM_CTL,AL ;WRITE TIMER CONTROL MODE REG
MOV CL,16H ;SET PGM LOOP CNT
MOV AL,CL ;SET TIMER 0 CNT REG
OUT TIMER0,AL ;WRITE TIMER 0 CNT REG
D8: TEST AH,0FFH ;DID TIMER 0 INTERRUPT OCCUR?
JNZ D9 ; YES - CHECK TIMER OP FOR SLOW TIME
LOOP D8 ;WAIT FOR INTR FOR SPECIFIED TIME
JMP D6 ;TIMER 0 INTR DIDN'T OCCUR - ERR
D9: MOV CL,18 ;SET PGM LOOP CNT
MOV AL,0FFH ;WRITE TIMER 0 CNT REG
OUT TIMER0,AL
MOV AH,0 ;RESET INTR RECEIVED FLAG
MOV AL,0FEH ;REENABLE TIMER 0 INTERRUPTS
OUT INTA01,AL
D10: TEST AH,0FFH ;DID TIMER 0 INTERRUPT OCCUR?
JNZ D6 ;YES - TIMER CNTING TOO FAST, ERR
LOOP D10 ;WAIT FOR INTR FOR SPECIFIED TIME
JMP NEAR PTR TST8 ;GO TO NEXT TEST ROUTINE
;--------------------------------------------
; TEMPORARY INTERRUPT SERVICE ROUTINE
;--------------------------------------------
D11 PROC NEAR
MOV AH,1
PUSH AX ;SAVE REG AX CONTENTS
MOV AL,0FFH ;MASK ALL INTERRUPTS OFF
OUT INTA01,AL
MOV AL,EOI
OUT INTA00,AL
POP AX ;RESTORE REG AX CONTENTS
IRET
D11 ENDP
NMI_INT PROC NEAR
PUSH AX ;SAVE ORIG CONTENTS OF AX
IN AL,PORT_C
TEST AL,40H ;IO CH PARITY CHECK?
JZ D12 ;YES - FLAG IS SET TO 0
MOV SI,OFFSET D1 ;ADDR OF ERROR MSG
MOV CX,D1L ;MSG LENGTH
JMP SHORT D13 ;DISPLAY ERROR MSG
D12:
TEST AL,80H ;PLANAR RAM P-CHECK?
JZ D14 ;NO - AUX INT
MOV SI,OFFSET D2 ;ADDR OF ERROR MSG
MOV CX, D2L ;MSG LENGTH
D13:
MOV AX,0 ;INIT AND SET MODE FOR VIDEO
INT 10H ;CALL VIDEO_IO PROCEDURE
CALL P_MSG ;PRINT ERROR MSG
CLI
HLT ;HALT SYSTEM
D14:
POP AX ;RESTORE ORIG CONTENTS OF AX
IRET
NMI_INT ENDP
;-------------------------------------
; INITIAL RELIABILITY TEST -- PHASE 3
;--------------------------------------
ASSUME CS:CODE,DS:DATA
E1 DB ' 201'
E1L EQU $-E1
; ESTABLISH BIOS SUBROUTINE CALL INTERRUPT VECTORS
TST8:
CLD ;SET DIR FLAG TO GO FORWARD
MOV DI,OFFSET VIDEO_INT ;SETUP ADDR TO INTR AREA
PUSH CS
POP DS ;SETUP ADDR DF VECTOR TABLE
MOV SI,0FF13H ; OFFSET VECTOR_TABLE+32
MOV CX,20H
REP MOVSW ;MOVE VECTOR TABLE TO RAM
; SETUP TIMER 0 TO MODE 3
MOV AL,0FFH ;DISABLE ALL DEVICE INTERRUPTS
OUT INTA01,AL
MOV AL,36H ;SEL TIM 0,LSB,MSB,MODE 3
OUT TIMER+3,AL ;WRITE TIMER MODE PEG
MOV AL,0
OUT TIMER,AL ;WRITE LSB TO TINER 0 REG
OUT TIMER,AL ;WRITE MSB TO TIMER 0 REG
; SETUP TIMER 0 TO BLINK LED IF MANUFACTURING TEST MODE
ASSUME DS:DATA
MOV AX,DATA ;POINT DS TD DATA SEG
MOV DS,AX
CALL KBD_RESET ;SEND SOFTWARE RESET TO KEYBRD
CMP BL,0AAH ;SCAN CODE 'AA' RETURNED?
JE E3 ;YES - CONTINUE (NON MFG MODE)
MOV AL,3CH ;EN KBD, SET KBD CLK LINE LOW
OUT PORT_B,AL ;WRITE 8255 PORT B
NOP
NOP
IN AL,PORT_A ;WAS A BIT CLOCKED IN?
AND AL,0FFH
JNZ E2 ;YES - CONTINUE (NON MFG MODE)
INC MFG_TST ;ELSE SET SW FOR MFG TEST MODE
MOV ES:INT_ADDR,OFFSET BLINK_INT ;SETUP TIMER INTP TO BLINK LED
MOV ES:INT_ADDR+2,CODE
MOV AL,0FEH ;ENABLE TIMER INTERRUPT
OUT INTA01,AL
E2: ; JUMPER_NOT_IN:
MOV AL,0CCH ;RESET THE KEYBOARD
OUT PORT_B,AL
;--------------------------------------------
;TEST.05
; ROS CHECKSUM II
;DESCRIPTION
; A CHECKSUM IS DONE FOR THE 4 ROS MODULES CONTAINING BASIC CODE
;--------------------------------------------
E3:
MOV DL,4 ;NO. OF ROS MODULES TO CHECK
MOV BX,6000H ;SETUP STARTING ROS ADDR
E4: ; CHECK_ROS:
CALL ROS_CHECKSUM
JNE E5 ;BEEP SPEAKER IF ERROR
DEC DL ;ANY MORE TO DO?
JNZ E4 ;YES - CONTINUE
JMP NEAR PTR E6 ;NO - GO TO NEXT TEST
E5: ; ROS_ERRoR:
MOV DX,101H
CALL ERR_BEEP ;BEEP SPEAKER
;--------------------------------------------
;TEST.08
; INITIALIZE AND START CRT CONTROLLER (6845)
; TEST VIDEO READ/WRITE STORAGE.
;DESCRIPTION
; RESET THE VICEO ENABLE SIGNAL.
; SELECT ALPHANUMBERIC MODE, 40 * 25, B & W
; READ/WRITE DATA PATTERNS TO STG. CHECK STG ADDRESSABILITY.
;--------------------------------------------
E6:
IN AL,PORT_A ;READ SENSE SWITCHES
MOV AH,0
MOV EQUIP_FLAG,AX ;STORE SENSE SW INFO
AND AL,30H ;ISOLATE VIDEO SW
JNZ E7 ;VIDEO SWS SET TO 0?
JMP E19 ;SKIP VIDEO TESTS FOR BURN-IN
E7: ; TEST_VIDEO:
XCHG AH,AL
CMP AH,30H ;B/W CARD ATTACHED?
JE E8 ;YES - SET MODE FOR B/W CARD
INC AL ;SET COLOR MODE FOR COLOR CD
CMP AH,20H ;80x25 MODE SELECTED?
JNE E8 ;NO - SET MODE FOR 40X25
MOV AL,3 ;SET MODE FOR 80X25
E8: ; SET_MODE:
PUSH AX ;SAVE VIDEO MODE ON STACK
SUB AH,AH ;INITIALIZE TO ALPHANUMERIC
INT 10H ;CALL VIDEO_IO
POP AX ;RESTORE VIDEO SENSE SWS IN AH
PUSH AX ; RESAVE VALUE
MOV BX,0B000H ;BEG VIDEO RAM ADDR B/W CD
MOV DX,3B8H ;MODE REG FOR B/W
MOV CX,4096 ;RAM BYTE CNT FOR B/W CD
MOV AL,1 ; SET MODE FOR B/W CARD
CMP AH,30H ;B/W VIDED CARD ATTACHED?
JE E9 ;YES - GO TEST VIDEO STG
MOV BX,0B800H ;BEG VIDEO RAM ADDR COLOR CD
MOV DX,3D8H ;MODE REG FOR COLOR CD
MOV CX,4000H ;RAM BYTE CNT FOR COLOR CD
DEC AL ; SET MODE TO 0 FOR COLOR CD
E9: ; TEST_VIDEO_STG:
OUT DX,AL ;DISABLE VIDEO FOR COLOR CD
MOV ES,BX ;POINT ES TD VIDEO RAM STG
MOV AX,DATA ;POINT DS TO DATA SEGMENT
MOV DS,AX
CMP RESET_FLAG,1234H ;POD INITIATED BY KBD RESET?
JE E10 ;YES - SKIP VIDEO RAM TEST
MOV DS,BX ;POINT DS TO VIDEO RAM STG
CALL STGTST_CNT ;GO TEST VIDEO R/W STG
JE E10 ;STG OK - CONTINUE TESTING
MOV DX,102H ;SETUP # OF BEEPS
CALL ERR_BEEP ;GO BEEP SPEAKER
;--------------------------------------------
;TEST.09
; SETUP VIDEO DATA ON SCREEN FOR VIDEO LINE TEST.
;DESCRIPTION
; ENABLE VIDEO SIGNAL AND SET MODE.
; DISPLAY A HORIZONTAL BAR ON SCREEN.
;--------------------------------------------
E10:
POP AX ;GET VIDEO SENSE SWS (AH)
PUSH AX ;SAVE IT
MOV AH,0 ;ENABLE VIDEO AND SET MODE
INT 10H ; VIDEO
MOV AX,7020H ;WRT BLANKS IN REVERSE VIDEO
SUB DI,SI ;SETUP STARTING LOC
MOV CX,40 ;NO. OF BLANKS TO DISPLAY
CLD ;SET DIR FLAG TO INCREMENT
REP STOSW ;WRITE VIDEO STORAGE
;--------------------------------------------
;TEST.10
; CRT INTERFACE LINES TEST
;DESCRIPTION
; SENSE ON/OFF TRANSITION OF THE VIDEO ENABLE AND HORIZONTAL
; SYNC LINES.
;--------------------------------------------
POP AX ;GET VIDEO SENSE SW INFO
PUSH AX ;SAVE IT
CMP AH,30H ;B/W CARD ATTACHED?
MOV DX,03BAH ;SETUP ADDR OF BW STATUS PORT
JE E11 ;YES - GO TEST LINES
MOV DX,03DAH ;COLOR CARD IS ATTACHED
E11: ; LINE_TST:
MOV AH,8
E12: ; OFLOOP_CNT:
SUB CX,CX
E13: IN AL,DX ;READ CRT STATUS PORT
AND AL,AH ;CHECK VIDEO/HORZ LINE
JNZ E14 ;ITS ON - CHECK IF IT GOES OFF
LOOP E13 ;LOOP TILL ON OR TIMEOUT
JMP SHORT E17 ;GO PRINT ERROR MSG
E14: SUB CX,CX
E15: IN AL,DX ;READ CRT STATUS PORT
AND AL,AH ;CHECK VIDEO/HORZ LINE
JZ E16 ;ITS ON - CHECK NEXT LINE
LOOP E15 ;LOOP IF OFF TILL IT GOES ON
JMP SHORT E17
E16: ; NXT_LINE:
MOV CL,3 ;GET NEXT BIT TO CHECK
SHR AH,CL ;
JNZ E12 ;GO CHECK HORIZONTAL LINE
JMP SHORT E18 ;DISPLAY CURSOR ON SCREEN
E17: ; CRT_ERR:
MOV DX,102H
CALL ERR_BEEP ;GO BEEP SPEAKER
E18: ; DISPLAY_CURSOR:
POP AX ;GET VIDEO SENSE SWS (AH)
MOV AH,0 ;SET MODE AND DISPLAY CURSOR
INT 10H ;CALL VIDEO I/O PROCEDURE
;--------------------------------------------
;TEST.11
; ADDITIONAL READ/WRITE STORAGE TEST
;DESCRIPTION
; WRITE/READ DATA PATTERNS TO ANY READ/WRITE STORAGE AFTER THE BASIC
; 16K. STORAGE ADDRESSABILITY IS CHECKED.
;--------------------------------------------
ASSUME DS:DATA
E19:
MOV AX,DATA
MOV DS,AX
;DETERMINE RAM SIZE ON PLANAR BOARD
MOV AH,BYTE PTR EQUIP_FLAG ;GET SENSE SWS INFO
AND AH,0CH ;ISOLATE RAM SIZE SWS
MOV AL,4
MUL AH
ADD AL,16 ;ADD BASIC 16K
MOV DX,AX ;SAVE PLANAR RAM SIZE IN DX
MOV BX,AX ; AND IN BX
; DETERMINE IO CHANNEL RAM SIZE
IN AL,PORT_C ;READ IO CH RAM SIZE SWS
AND AL,0FH ;ISOLATE FROM OTHER BITS
MOV AH,32
MUL AH
MOV IO_RAM_SIZE,AX ;SAVE IO CHANNEL RAM SIZE
CMP BX,40H ;PLANAR RAM SIZE = 64K?
JE E20 ;YES - ADD IO CHN RAM SIZE
SUB AX,AX ;NO - DON'T AOD ANY IO RAM
E20: ; ADD_ID_SIZE:
ADD AX,BX ;SUM TOTAL RAM SIZE
MOV MEMORY_SIZE,AX ;SETUP MEMORY SIZE PARM
CMP RESET_FLAG,1234H ;POD INITIATED BY KBD RESET?
JE E22 ;YES - SKIP MEMORY TEST
; TEST ANY OTHER READ/WRITE STORAGE AVAILABLE
MOV BX,400H
MOV CX,16
E21:
CMP DX,CX ;ANY MORE STG TO BE TESTED?
JBE E23 ;NO - GO TO NEXT TEST
MOV DS,BX ;SETUP STG ADDR IN DS AND ES
MOV ES,BX
ADD CX,16 ;INCREMENT STG BYTE COUNTER
ADD BX,400H ;SET POINTER TD NEXT 16K BLK
PUSH CX ;SAVE REGS
PUSH BX
PUSH DX
CALL STGTST ;GO TEST A 16K BLK OF STG
POP DX
POP BX ;RESTORE REGS
POP CX
JE E21 ;CHECK IF MORE STG TO TEST
; PRINT FAILING ADDRESS AND XOR'ED PATTERN IF DATA COMPARE ERROR
MOV DX,DS ;CONVERT FAILING HIGH-ORDER
MOV CH,AL ;SAVE FAILING BIT PATTERN
MOV AL,DH ;GET FAILING ADDR (HIGH BYTE)
MOV CL,4
SHR AL,CL ;RIGHT-JUSTIFY HIGH BYTE
CALL XLAT_PRINT_CODE ;CONVERT AND PRINT CODE
MOV AL,DH
AND AL,0FH
CALL XLAT_PRINT_CODE ;CONVERT AND PRINT CODE
MOV AL,CH ;GET FAILING BIT PATTERN
MOV CL,4 ; AND ISOLATE LEFTMOST NIBBLE
SHR AL,CL
CALL XLAT_PRINT_CODE ;CONVERT AND PRINT CODE
MOV AL,CH ;GET FAILING BIT PATTERN AND
AND AL,0FH ; ISOLATE RIGHTMOST NIBBLE
CALL XLAT_PRINT_CODE ;CONVERT AND PRINT CODE
MOV SI,OFFSET E1 ;SETUP ADDRESS OF ERROR MSG
MOV CX,E1L ;GET MSG BYTE COUNT
CALL P_MSG ;PRINT ERROR MSG
E22: ; GO_TST12:
JMP NEAR PTR TST12 ;GO TO NEXT TEST
E23: ; STG_TEST_DONE:
MOV AX,DATA ;POINT DS TO DATA SEGMENT
MOV DS,AX ; CHG MADE 3/27/81
MOV DX,IO_RAM_SIZE ;GET IO CHANNEL RAM SIZE
OR DX,DX ;SET FLAG RESULT
JZ E22 ;NO IO RAM, GO TO NEXT TEST
MOV CX,0
CMP BX,1000H ;HAS IO RAM BEEN TESTED
JA E22 ;YES - GO TO NEXT TEST
MOV BX,1000H ;SETUP BEG LOC FOR IO RAM
JMP SHORT E21 ;GO TEST IO CHANNEL RAM
;--------------------------------------------
; CONVERT AND PRINT ASCII CODE
;
; AL MUST CONTAIN NUMBER TO BE CONVERTED.
; AX AND BX DESTROYED.
;--------------------------------------------
XLAT_PRINT_CODE PROC NEAR
PUSH DS ;SAVE DS VALUE
PUSH CS ;POINT DS TO CODE SEG
POP DS
MOV BX,0E4B7H ; OFFSET ASCII_TBL-XLAT TABLE
XLATB
MOV AH,14
MOV BH,0
INT 10H ;CALL VIDEO_IO
POP DS ;RESTORE ORIG VALUE IN DS
RET
XLAT_PRINT_CODE ENDP
;---------------------------------------
; INITIAL RELIABILITY TEST -- PHASE 4
;---------------------------------------
ASSUME CS:CODE,DS:DATA
F1 DB ' 301'
F1L EQU $-F1 ; KEYBDARD MESSAGE
F2 DB '131'
F2L EQU $-F2 ; CASSETTE MESSAGE
F3 DB '601'
F3L EQU $-F3 ; DISKETTE MESSAGE
F4 LABEL WORD ; PRINTER SOURCE TABLE
DW 3BCH
DW 378H
DW 278H
F4E LABEL WORD
ASCII_TBL DB '0123456789ABCDEF'
;--------------------------------------------
;TEST.12
; KEYBOARD TEST
;DESCRIPTION
; RESET THE KEYBOARD AND CHECK THAT SCAN CODE 'AA' IS RETURNED
; TO THE CPU. CHECK FOR STUCK KEYS.
;--------------------------------------------
TST12:
MOV AX,DATA ;POINT DS TO DATA SEG
MOV DS,AX
CMP MFG_TST,1 ;MANUFACTURING TEST MODE?
JE F7 ;YES - SKIP KEYBOARD TEST
CALL KBD_RESET ;ISSUE SOFTWARE RESET TO KEYBRD
JCXZ F6 ;PRINT ERR MSG IF NO INTERRUPT
MOV AL,4DH ;ENABLE KEYBOARD
OUT PORT_B,AL
CMP BL,0AAH ;SCAN CODE AS EXPECTED?
JNE F6 ;NO - DISPLAY ERROR MSG
;CHECK FOR STUCK KEYS
MOV AL,0CCH ;CLR KBD, SET CLK LINE HIGH
OUT PORT_B,AL
MOV AL,4CH ;ENABLE KBD,CLK IN NEXT BYTE
OUT PORT_B,AL
SUB CX,CX
F5: ; KBD_WAIT:
LOOP F5 ;DELAY FOR A WHILE
IN AL,KBD_IN ;CHECK FOR STUCK KEYS
CMP AL,0 ;SCAN CODE = 0?
JE F7 ;YES - CONTINUE TESTING
MOV CH,AL ;SAVE SCAN CODE
MOV CL,4
SHR AL,CL ;RIGHT-JUSTIFY HIGH BYTE
CALL XLAT_PRINT_CODE ;CONVERT AND PRINT
MOV AL,CH ;RECOVER SCAN CODE
AND AL,0FH ;ISOLATE LOW ORDER BYTE
CALL XLAT_PRINT_CODE ;CONVERT AND PRINT
F6: MOV SI,OFFSET F1 ;GET MSG ADDR
MOV CX,F1L ;GET MSG BYTE COUNT
CALL P_MSG ;PRINT MSG ON SCREEN
; SETUP INTERRUPT VECTOR TABLE
F7: ; SETUP_INT_TABLE:
SUB AX,AX
MOV ES,AX
MOV CX,24*2 ;GET VECTOR CNT
PUSH CS ;SETUP DS SEG REG
POP DS
MOV SI,0FEF3H ; OFFSET VECTOR_TABLE
MOV DI,OFFSET INT_PTR
CLD
REP MOVSW
;--------------------------------------------
;TEST.13
; CASSETTE DATA WRAP TEST
;DESCRIPTION
; TURN CASSETTE MOTOR OFF. WRITE A BIT OUT TO THE CASSETTE DATA BUS.
; VERIFY THAT CASSETTE DATA READ IS WITHIN A VALID RANGE.
;--------------------------------------------
; TURN THE CASSETTE MOTOR OFF
MOV AX,DATA ;POINT DS REG TO DATA SEG
MOV DS,AX
MOV AL,04DH ;SET TIMER 2 SPK OUT, AND CASST
OUT PORT_B,AL ;OUT BITS ON, CASSETTE MOT OFF
; WRITE A BIT
MOV AL,0FFH ;DISABLE TIMER INTERRUPTS
OUT INTA01,AL
MOV AL,0B6H ;SEL TIM 2, LSB, MSB, MD 3
OUT TIMER+3,AL ;WRITE 8253 CMD/MODE REG
MOV AX,1235 ;SET TIMER 2 CNT FOR 1000 USEC
OUT TIMER+2,AL ;WRITE TIMER 2 COUNTER REG
MOV AL,AH ;WRITE MSB
OUT TIMER+2,AL
; READ CASSETTE INPUT
IN AL,PORT_C ;READ VALUE OF CASS IN BIT
AND AL,10H ;ISOUTE FROM OTHER BITS
MOV LAST_VAL,AL
CALL READ_HALF_BIT
CALL READ_HALF_BIT
JCXZ F8 ; CAS_ERR
CMP BX,MAX_PERIOD
JNC F8 ; CAS_ERR
CMP BX,MIN_PERIOD
JNC F9 ;GO TO NEXT TEST IF OK
F8: ; CAS_ERR:
MOV SI,OFFSET F2 ;CASSETTE WRAP FAILED
MOV CX,F2L
CALL P_MSG ;GO PRINT ERROR MSG
;--------------------------------------------
;TEST.14
; DISKETTE ATTACHMENT TEST
;DESCRIPTION
; CHECK IF IPL DISKETTE DRIVE IS ATTACHED TO SYSTEM. IF ATTACHED,
; VERIFY STATUS OF NEC FDC AFTER A RESET. ISSUE A RECAL AND SEEK
; CMD TO FDC AND CHECK STATUS. COMPLETE SYSTEM INITIALIZATION THEN
; PASS CONTROL TO THE BOOT LOADER PROGRAM.
;--------------------------------------------
F9:
MOV AL,0FCH ;ENABLE TIMER AND KBD INTS
OUT INTA01,AL
MOV AL,BYTE PTR EQUIP_FLAG ;GET SENSE SWS INFO
TEST AL,01H ;IPL DISKETTE DRIVE ATTCH?
JNZ F10 ;YES - TEST DISKETTE CONTR
JMP F22 ;NO - SKIP THIS TEST
F10: ; DISK-TEST:
MOV AL,0BCH ;ENABLE DISKETTE, KEYBOARD,
OUT INTA01,AL ; AND TIMER INTERRUPTS
MOV AH,0 ;RESET NEC FDC
INT 13H ;VERIFY STATUS AFTER RESET
TEST AH,0FFH ;STATUS OK?
JNZ F13 ;NO - FDC FAILED
; TURN DRIVE 0 MOTOR ON
MOV DX,03F2H ;GET ADDR DF FDC CARD
MOV AL,1CH ;TURN MOTOR ON, EN DMA/INT
OUT DX,AL ;WRITE FDC CONTROL REG
SUB CX,CX
F11: ; MOTOR_WAIT:
LOOP F11 ;WAIT FOR 1 SECOND
F12: ; MOTOR_WAIT1:
LOOP F12
XOR DX,DX ;SELECT DRIVE 0
MOV CH,1 ;SELECT TRACK 1
MOV SEEK_STATUS,DL
CALL SEEK ;RECALIBRATE DISKETTE
JC F13 ;GO TO ERR SUBROUTINE IF ERR
MOV CH,34 ;SELECT TRACK 34
CALL SEEK ;SEEK TO TRACK 34
JNC F14 ;OK, TURN MOTOR OFF
F13: ; DSK_ERR:
MOV SI,OFFSET F3 ;GET ADDR OF MSG
MOV CX,F3L ;GET MSG BYTE COUNT
CALL P_MSG ;GO PRINT ERRDR MSG
; TURN DRIVE 0 MOTOR OFF
F14: ; DR0_OFF:
MOV AL,CH ;TURN DRIVE 0 MOTOR OFF
MOV DX,03F2H ; FDC CTL ADDRESS
OUT DX,AL
; SETUP PRINTER AND RS232 BASE ADDRESSES IF DEVICE ATTACHED
F15: ; JMP_BOOT:
MOV BUFFER_HEAD,OFFSET KB_BUFFER ;SETUP KEYBOARD PARAMETERS
MOV BUFFER_TAIL,OFFSET KB_BUFFER
MOV BP,OFFSET F4 ; PRT_SRC_TBL
MOV SI,0
F16: ; PRT_BASE:
MOV DX,CS:[BP] ;GET PRINTER BASE ADDR
MOV AL,0AAH ;WRITE DATA TO PORT A
OUT DX,AL
SUB AL,AL
IN AL,DX ;READ PORT A
CMP AL,0AAH ;DATA PATTERN SAME
JNE F17 ;NO - CHECK NEXT PRT CD
MOV PRINTER_BASE[SI],DX ;YES - STORE PRT BASE ADDR
INC SI ; INCREMENT TO NEXT WORD
INC SI
F17: ; NO_STORE:
INC BP ;POINT TO NEXT BASE ADDR
INC BP
CMP BP,OFFSET F4E ;ALL POSSIBLE ADDRS CHECKED?
JNE F16 ;PRT_BASE
MOV BX,0 ;POINTER TO RS232 TABLE
MOV DX,3FAH ;CHECK IF RS232 CD 1 ATTCH?
IN AL,DX ;READ INTR ID REG
TEST AL,0F8H
JNZ F18
MOV RS232_BASE[BX],3F8H ;SETUP RS232 CD #1 ADDR
INC BX
INC BX
F18: MOV DX,2FAH ;CHECK IF RS232 CD 2 ATTCH
IN AL,DX ;READ INTERRUPT ID REG
TEST AL,0F8H
JNZ F19 ;BASE_END
MOV RS232_BASE[BX],2F8H ;SETUP RS232 CD #2
INC BX
INC BX
;------ SET UP EQUIP FLAG TO INDICATE NUMBER OF PRINTERS AND RS232 CARDS
F19: ; BASE_END:
MOV AX,SI ; SI HAS 2* NUMBER OF RS232
MOV CL,3 ; SHIFT COUNT
ROR AL,CL ; ROTATE RIGHT 3 POSITIONS
OR AL,BL ; OR IN THE PRINTER COUNT
MOV BYTE PTR EQUIP_FLAG+1,AL ; STORE AS SECOND BYTE
MOV DX,201H
IN AL,DX
TEST AL,0FH
JNZ F20 ; NO_GAME_CARD
OR BYTE PTR EQUIP_FLAG+1,16
F20: ; NO_GAME_CARD:
; ENABLE NMI INTERRUPTS
MOV AL,80H ;ENABLE NMI INTERRUPTS
OUT 0A0H,AL
CMP MFG_TST,1 ;MFG MODE?
JE F21 ; LOAD_BOOT_STRAP
MOV DX,1
CALL ERR_BEEP ;BEEP 1 SHORT TONE
F21: ; LOAD_BOOT_STRAP:
JMP BOOT_STRAP ;GO TO THE BOOT LOADER
F22: ; LOOP_POD:
CMP MFG_TST,1 ;MANUFACTURING TEST MODE?
JNE F23 ;NO - GO TO BOOT LOADER
JMP START ;YES - LOOP POWER-ON-DIAGS
F23: ; GO_TO_BOOT:
JMP F15 ; JMP_BOOT
;--------------------------------------------
; INITIAL RELIABILITY TEST -- SUBROUTINES
;--------------------------------------------
ASSUME CS:CODE,DS:DATA
;--------------------------------------------
; SUBROUTINES FOR POWER ON DIAGNOSTICS
;--------------------------------------------
; THIS PROCEDURE WILL ISSUE ONE LONG TONE (3 SECS) AND ONE OR
; MORE SHORT TONES (1 SEC) TO INDICATE A FAILURE ON THE PLANAR
; BOARD, A BAD RAM MODULE, OR A PROBLEM WITH THE CRT.
;ENTRY PARAMETERS:
; DH = NUMBER OF LONG TONES TO BEEP
; DL = NUMBER OF SHORT TONES TO BEEP.
;--------------------------------------------
ERR_BEEP PROC NEAR
PUSHF ;SAVE FLAGS
CLI ;DISABLE SYSTEM INTERRUPTS
PUSH DS ;SAVE DS REG CONTENTS
MOV AX,DATA ;POINT DS TO DATA SEG
MOV DS,AX
OR DH,DH ; ANY LONG ONES TO BEEP
JZ G3 ; NO, DO THE SHORT ONES
G1: ; LONG_BEEP:
MOV BL,6 ; COUNTER FOR BEEPS
CALL BEEP ; DO THE BEEP
G2: LOOP G2 ; DELAY BETWEEN BEEPS
DEC DH ; ANY MORE TO DO
JNZ G1 ; DO IT
CMP MFG_TST,1 ; MFG TEST MODE?
JNE G3 ; YES - CONTINUE BEEPING SPEAKER
MOV AL,0CDH ; STOP BLINKING LED
OUT PORT_B,AL
JMP SHORT G1
G3: ; SHORT_BEEP:
MOV BL,1 ; COUNTER FOR A SHORT BEEP
CALL BEEP ; DO THE SOUND
G4: LOOP G4 ; DELAY BETWEEN BEEPS
DEC DL ; DONE WITH SHORTS
JNZ G3 ; DO SOME MORE
G5: LOOP G5 ; LONG DELAY BEFORE RETURN
G6: LOOP G6
POP DS ;RESTORE ORIG CONTENTS OF DS
POPF ;RESTORE FLAGS TO ORIG SETTINGS
RET ; RETURN TO CALLER
ERR_BEEP ENDP
; ROUTINE TO SOUND BEEPEP
BEEP PROC NEAR
MOV AL,10110110B ;SEL TIM 2,LSB,MSB,BINARY
OUT TIMER+3,AL ;WRITE THE TIMER MODE REG
MOV AX,533H ;DIVISOR FOR 1000 HZ
OUT TIMER+2,AL ;WRITE TIMER 2 CNT - LSB
MOV AL,AH
OUT TIMER+2,AL ;WRITE TIMER 2 CNT - MSB
IN AL,PORT_B ;GET CURRENT SETTING OF PORT
MOV AH,AL ; SAVE THAT SETTING
OR AL,03 ;TURN SPEAKER ON
OUT PORT_B,AL
SUB CX,CX ;SET SNT TO WAIT 500 MS
G7: LOOP G7 ;DELAY BEFORE TURNING OFF
DEC BL ;DELAY CNT EXPIRED?
JNZ G7 ;NO - CONTINUE BEEPING SPK
MOV AL,AH ; RECOVER VALUE OF PORT
OUT PORT_B,AL
RET ;RETURN TO CALLER
BEEP ENDP
;--------------------------------------------
; THIS PROCEDURE WILL SEND A SOFTWARE RESET TO THE KEYBOARD.
; SCAN CDDE 'AA' SHOULD BE RETURNED TO THE CPU.
;-------------------------------------------
KBD_RESET PROC NEAR
MOV AL,0CH ;SET KBD CLK LINE LOW
OUT PORT_B,AL ;WRITE 8255 PORT B
MOV CX,10582 ;HOLD KBD CLK LOW FOR 20 MS
G8: LOOP G8 ;LOOP FOR 20 MS
MOV AL,0CCH ;SET CLK, ENABLE LINES HIGH
OUT PORT_B,AL
SP_TEST: ; ENTRY FOR MANUFACTURING TEST 2
MOV AL,4CH ;SET KBD CLK HIGH, ENABLE LOW
OUT PORT_B,AL
MOV AL,0FDH ;ENABLE KEYBOARD INTERRUPTS
OUT INTA01,AL ;WRITE 8255 IMR
STI ;ENABLE SYSTEM INTERRUPTS
MOV AH,0 ;RESET INTERRUPT INDICATOR
SUB CX,CX ;SETUP INTERRUPT TIMEOUT CNT
G9: TEST AH,0FFH ;DID A KEYBOARD INTR OCCUR?
JNZ G10 ;YES - READ SCAN CDDE RETURNED
LOOP G9 ;NO - LOOP TILL TIMEOUT
G10: IN AL,PORT_A ;READ KEYBOARD SCAN CDDE
MOV BL,AL ;SAVE SCAN CODE JUST READ
MOV AL,0CCH ;CLEAR KEYBOARD
OUT PORT_B,AL
RET ;RETURN TO CALLER
KBD_RESET ENDP
;--------------------------------------------
; BLINK LED PROCEDURE FOR MFG BURN-IN AND RUN-IN TESTS
; (LED WILL BLINK APPROXIMATELY .25 SECOND)
;--------------------------------------------
BLINK_INT PROC NEAR
STI
PUSH CX ;SAVE CX REG CONTENTS
PUSH AX ;SAVE AX REG CONTENTS
IN AL,PORT_B ;READ CURRENT VAL OF PORT B
AND AL,0BFH
OUT PORT_B,AL ;BLINK LED
SUB CX,CX
G11: LOOP G11
OR AL,40H ;STOP BLINKING LED
OUT PORT_B,AL
MOV AL,EOI
OUT INTA00,AL
POP AX ;RESTORE AX REG
POP CX ;RESTORE CX REG
IRET
BLINK_INT ENDP
;--------------------------------------------
; THIS SUBROUTINE WILL PRINT A MESSAGE ON THE DISPLAY
;
;ENTRY REQUIREMENTS:
; SI = OFFSET (ADDRESS) OF MESSAGE BUFFER
; CX = MESSAGE BYTE COUNT
; MAXIMUM MESSAGE LENGTH IS 36 CHARACTERS
;--------------------------------------------
P_MSG PROC NEAR
MOV AX,DATA ;POINT DS TO DATA SEG
MOV DS,AX
CMP MFG_TST,1 ;MFG TEST MODE?
JNE G12 ;NO - DISPLAY ERROR MSG
MOV DH,1 ;YES - SETUP TO BEEP SPEAKER
JMP ERR_BEEP ;YES - BEEP SPEAKER
G12: ; WRITE_MSG:
MOV AL,CS:[SI] ;PUT CHAR IN AL
INC SI ; POINT TO NEXT CHAR
MOV BH,0 ;SET PAGE # TO ZERO
MOV AH,14 ;WRITE CHAR (TTY-INTERFACE)
INT 10H ;CALL VIDEO_IO
LOOP G12 ;CONTINUE TILL MSG WRITTEN
MOV AX,0E0DH ;PDSITION CURSOR TO NEXT LINE
INT 10H ;SEND CARRIAGE RETURN AND
MOV AX,0E0AH ;LINE FEED CHARS
INT 10H
RET
P_MSG ENDP
;--- INT 19 -----------------------------
;BOOT STRAP LOADER
; IF A 5 1/4" DISKETTE DRIVE IS AVAILABLE
; ON THE SYSTEM, TRACK 0, SECTOR 1 IS READ INTO THE
; BOOT LOCATION (SEGMENT 0, OFFSET 7C00)
; AND CONTROL IS TRANSFERRED THERE.
;
; IF THERE IS NO DISKETTE DRIVE, OR IF THERE IS
; IS A HARDWARE ERROR CONTROL IS TRANSFERRED
; TO THE CASSETTE BASIC ENTRY POINT.
;
; IPL ASSUMPTIONS
; 8255 PORT 60H BIT 0
; = 1 IF IPL FROM DISKETTE
;-----------------------------------------
ASSUME CS:CODE,DS:DATA
BOOT_STRAP PROC NEAR
STI ; ENABLE INTERRUPTS
MOV AX,DATA ; ESTABLISH ADDRESSING
MOV DS,AX
MOV AX,EQUIP_FLAG ; GET THE EQUIPMENT SWITCHES
TEST AL,1 ; ISOLATE IPL SENSE SWITCH
JZ H3 ; GO TO CASSETTE BASIC ENTRY POINT
;------ MUST LOAD SYSTEM FROM DISKETTE -- CX HAS RETRY COUNT
MOV CX,4 ; SET RETRY COUNT
H1: ; IPL_SYSTEM
PUSH CX ; SAVE RETRY COUNT
MOV AH,0 ; RESET THE DISKETTE SYSTEM
INT 13H ; DISKETTE_IO
JC H2 ; IF ERROR, TRY AGAIN
MOV AH,2 ; READ IN THE SINGLE SECTOR
MOV BX,0 ; TO THE BOOT LOCATION
MOV ES,BX
MOV BX,OFFSET BOOT_LOCN
MOV DX,0 ; DRIVE 0, HEAD 0
MOV CX,1 ; SECTOR 1, TRACK 0
MOV AL,1 ; READ ONE SECTOR
INT 13H ; DISKETTE_IO
H2: POP CX ; RECOVER RETRY COUNT
JNC H4 ; CF SET BY UNSUCCESSFUL READ
LOOP H1 ; DO IT FOR RETRY TIMES
;------ UNABLE TO IPL FROM THE DISKETTE
H3: ; CASSETTE_JUMP:
INT 18H ; USE INTERRUPT VECTOR TO GET TO BASIC
;------ IPL WAS SUCCESSFUL
H4:
JMP BOOT_LOCN
BOOT_STRAP ENDP
;-----INT 14---------------------------------
;RS232_IO
; THIS ROUTINE PROVIDES BYTE STREAM I/O TO THE COMMUNICATIONS
; PORT ACCORDING TO THE PARAMETERS:
; (AH)=0 INITIALIZE THE COMMUNICATIONS PORT
; (AL) HAS PARMS FOR INITIALIZATION
;
; 7 6 5 4 3 2 1 0
; ----- BAUD RATE -- -PARITY-- STOPBIT --WORD LENGTH--
;
; 000 - 110 X0 - NONE 0 - 1 10 - 7 BITS
; 001 - 150 01 - ODD 1 - 2 11 - 8 BITS
; 010 - 300 11 - EVEN
; 011 - 600
; 100 - 1200
; 101 - 2400
; 110 - 4800
; 111 - 9600
;
; ON RETURN, CONDITIONS SET AS IN CALL TO COMMO STATUS (AH=3)
; (AH)=1 SEND THE CHARACTER IN (AL) OVER THE COMMO LINE
; (AL) REGISTER IS PRESERVED
; ON EXIT, BIT 7 OF AH IS SET IF THE ROUTINE WAS UNABLE TO
; TO TRANSMIT THE BYTE OF DATA OVER THE LINE. THE
; REMAINDER OF AH IS SET AS IN A STATUS REQUEST,
; REFELECTING THE CURRENT STATUS OF THE LINE.
; (AH)=2 RECEIVE A CHARACTER IN (AL) FROM COMMO LINE BEFORE
; RETURNING TO CALLER
; ON EXIT, AH HAS THE CURRENT LINE STATUS, AS SET BY THE
; THE STATUS ROUTINE, EXCEPT THAT THE ONLY BITS
; LEFT ON ARE THE ERROR BITS (7,4,3,2,1)
; IN THIS CASE, THE TIHE OUT BIT INDICATES DATA SET
; READY WAS NOT RECEIVED.
; THUS, AH IS NON ZERO ONLY WHEN AN ERROR OCCURRED.
; (AH)=3 RETURN THE COMMO PORT STATUS IN (AX)
; AH CONTAINS THE LINE CONTROL STATUS
; BIT 7 = TIME OUT
; BIT 6 = TRANS SHIFT REGISTER EMPTY
; BIT 5 = TRAN HOLDING REGISTER EMPTY
; BIT 4 = BREAK DETECT
; BIT 3 = FRAMING ERROR
; BIT 2 = PARITY ERROR
; BIT 1 = OVERRUN ERROR
; BIT 0 = DATA READY
; AL CONTAINS THE MODEM STATUS
; BIT 7 = RECEVED LINE SIGNAL DETECT
; BIT 6 = RING INDICATOR
; BIT S = DATA SET READY
; BIT 4 = CLEAR TO SEND
; BIT 3 = DELTA RECEIVE LINE SIGNAL DETECT
; BIT 2 = TRAILING EDGE RING DETECTOR
; BIT 1 = DELTA DATA SET READY
; BIT 0 = DELTA CLEAR TO SEND
;
; (DX) = PARAMETER INDICATING WHICH RS232 CARD (0,1 ALLOWED)
; DATA AREA RS232_BASE CONTAINS THE BASE ADDRESS OF THE 8250 ON THE CARD
; LOCATION 400H CONTAINS UP TO 4 RS232 ADDRESSES POSSIBLE
;OUTPUT
; AX MODIFIED ACCORDING TO PARMS OF CALL
; ALL OTHERS UNCHANGED
;------------------------------------
ASSUME CS:CODE,DS:DATA
A1 LABEL WORD
DW 1047 ; 110 BAUD ; TABLE OF INIT VALUE
DW 768 ; 150
DW 384 ; 300
DW 192 ; 600
DW 96 ; 1200
DW 48 ; 2400
DW 24 ; 4800
DW 12 ; 9600
RS232_IO PROC FAR
;------ VECTOR TO APPROPRIATE ROUTINE
STI ; INTERRUPTS BACK ON
PUSH DS ; SAVE SEGMENT
PUSH DX
PUSH SI
PUSH DI
PUSH CX
MOV SI,DX ; RS232 VALUE TO SI
SHL SI,1 ; WORD OFFSET
MOV DX,DATA
MOV DS,DX ; SET UP OUR SEGMENT
MOV DX,RS232_BASE[SI] ; GET BASE ADDRESS
OR DX,DX ; TEST FOR 0 BASE ADDRESS
JZ A3 ; RETURN
OR AH,AH ; TEST FOR (AH)=0
JZ A4 ; COMMUN INIT
DEC AH ; TEST FOR (AH)=1
JZ A5 ; SEND AL
DEC AH ; TEST FOR (AH)=2
JNZ A2
JMP A12 ; RECEIVE INTO AL
A2:
DEC AH ; TEST FOR (AH)=3
JNZ A3
JMP A18 ; COMMUNICATICN STATUS
A3: ; RETURN FROM RS232
POP CX
POP DI
POP SI
POP DX
POP DS
IRET ; RETURN TO CALLER, NO ACTION
;------ INITIALIZE THE COMMUNICATIONS PORT
A4:
MOV AH,AL ; SAVE INIT PARMS IN AH
ADD DX,3 ; POINT TO 8250 CONTROL REGISTER
MOV AL,80H
OUT DX,AL ; SET DLAB=1
;------ DETERMINE BAUD RATE DIVISOR
MOV DL,AH ; GET PARMS TO DL
ROL DL,1
ROL DL,1 ; GET BAUD RATE TERM TO LOW BITS
ROL DL,1
ROL DL,1 ; *2 FOR WORD TABLE ACCESS
AND DX,0EH ; ISOLATE THEM
MOV DI,OFFSET A1 ; BASE OF TABLE
ADD DI,DX ; PUT INTO INDEX REGISTER
MOV DX,RS232_BASE[SI] ; POINT TO HIGH ORDER OF DIVISOR
INC DX
MOV AL,CS:[DI]+1 ; GET HIGH ORDER OF DIVISOR
OUT DX,AL ; SET MS OF DIV TO 0
DEC DX
MOV AL,CS:[DI] ; GET LOW ORDER OF DIVISOR
OUT DX,AL ; SET LOW OF DIVISOR
ADD DX,3
MOV AL,AH ; GET PARMS BACK
AND AL,01FH ; STRIP OFF THE BAUD BITS
OUT DX,AL ; LINE CONTROL TO 8 BITS
SUB DX,2
MOV AL,0
OUT DX,AL ; INTERRUPT ENABLES ALL OFF
JMP SHORT A18 ; COM_STATUS
;------ SEND CHARACTER IN (AL) OVER COMMO LINE
A5:
PUSH AX ; SAVE CHAR TO SEND
ADD DX,4 ; MODEM CONTROL REGISTER
MOV AL,3 ; DTR AND RTS
OUT DX,AL ; DATA TERMINAL READY, REQUEST TO SEND
XOR CX,CX ; INITIALIZE TIME OUT COUNTER
ADD DX,2 ; MODEM STATUS REGISTER
A6: ; WAIT_DATA_SET_READY
IN AL,DX ; GET MODEM STATUS
TEST AL,20H ; DATA SET READY
JNZ A7 ; TEST_CLEAR_TO_SEND
LOOP A6 ; WAIT_DATA_SET_READY
POP AX
OR AH,80 ; INDICATE TIME OUT
JMP A3 ; RETURN
A7: ; TEST_CLEAR_TO_SEND
SUB CX,CX
A8: ; WAIT_CLEAR_TO_SEND
IN AL,DX ; GET MODEM STATUS
TEST AL,10H ; TEST CLEAR TO SEND
JNZ A9 ; CLEAR_TO_SEND
LOOP A8 ; WAIT_CLEAR_TO_SEND
POP AX ; TIME OUT HAS OCCURRED
OR AH,80H
JMP A3 ; RETURN
A9: ; CLEAR_TO_SEND
DEC DX ; LINE STATUS REGISTER
SUB CX,CX ; INITIALIZE WAIT COUNT
A10: ; WAIT_SEND
IN AL,DX ; GET STATUS
TEST AL,20H ; IS TRANSMITTER READY
JNZ A11 ; OUT_CHAR
LOOP A10 ; GO BACK FOR MORE, AND TEST FOR TIME OUT
POP AX ; RECOVER ORIGINAL INPUT
OR AH,80H ; SET THE TIME OUT BIT
JMP NEAR PTR A3 ; RETURN
A11: ; OUT_CHAR
SUB DX,5 ; DATA PORT
POP CX ; RECOVER IN CX TEMPORARILY
MOV AL,CL ; GET OUT CHAR TO AL FOR OUT, STATUS IN AH
OUT DX,AL ; OUTPUT CHARACTER
JMP NEAR PTR A3 ; RETURN
;------ RECEIVE CHARACTER FROM COMMO LINE
A12:
AND BIOS_BREAK,07FH ; TURN OFF BREAK BIT IN BYTE
ADD DX,4 ; MODEM CONTROL REGISTER
MOV AL,1 ; DATA TERMINAL READY
OUT DX,AL
ADD DX,2 ; MODEM STATUS REGISTER
SUB CX,CX ; ESTABLISH TIME OUT COUNT
A13: ; WAIT_DSR
IN AL,DX ; MODEM STATUS
TEST AL,20H ; DATA SET READY
JNZ A15 ; IS IT READY YET
LOOP A13 ; WAIT UNTIL IT IS
A14: ; TIME_OUT_ERR
MOV AH,80H ; SET TIME OUT ERROR
JMP A3 ; RETURN WITH ERROR
A15: ; WAIT_DSR_END
DEC DX ; LINE STATUS REGISTER
A16: ; WAIT_RECV
IN AL,DX ; GET STATUS
TEST AL,1 ; RECEIVE BUFFER FULL
JNZ A17 ; GET CHAR
TEST BIOS_BREAK,80H ; TEST FOR BREAK KEY
JZ A16 ; LOOP IF NOT
JMP A14 ; SET TIME OUT ERROR
A17: ; GET_CHAR
AND AL,00011110B ; TEST FOR ERROR CONDITIONS ON RECV CHAR
MOV AH,AL ; SAVE THIS PART OF STATUS FOR LATER OPERATION
MOV DX,RS232_BASE[SI] ; DATA PORT
IN AL,DX ; GET CHARACTER FROM LINE
JMP A3 ; RETURN
;------ COMMO PORT STATUS ROUTINE
A18:
MOV DX,RS232_BASE[SI]
ADD DX,5 ; CONTROL PORT
IN AL,DX ; GET LINE CONTROL STATUS
MOV AH,AL ; PUT IN AH FOR RETURN
INC DX ; POINT TO MODEM STATUS REGISTER
IN AL,DX ; GET MODEM CONTROL STATUS
JMP A3 ; RETURN
RS232_IO ENDP
;---- INT 16 --------------------------------
; KEYBOARD I/O
; THESE ROUTINES PROVIDE KEYBOARD SUPPORT
; INPUT
; (AH)=0 READ THE NEXT ASCII CHARACTER STRUCK FROM THE KEYBOARD
; RETURN THE RESULT IN (AL), SCAN CODE IN (AH)
; (AH)=1 SET THE Z FLAG TO INDICATE IF AN ASCII CHARACTER IS AVAILABLE
; TO BE READ.
; (ZF)=1 -- NO CODE AVAILABLE
; (ZF)=0 -- CODE IS AVAILABLE
; IF ZF = 0, THE NEXT CHARACTER IN THE BUFFER TO BE READ IS
; IN AX, AND THE ENTRY REMAINS IN THE BUFFER
; (AH)=2 RETURN THE CURRENT SHIFT STATUS IN AL REGISTER
; THE BIT SETTINGS FOR THIS CODE ARE INDICATED IN THE
; THE EQUATES FOR KB_FLAG
; OUTPUT
; AS NOTED ABOVE, ONLY AX AND FLAGS CHANGED
; ALL REGISTERS RETAINED
;----------------------------------------
ASSUME CS:CODE,DS:DATA
KEYBOARD_IO PROC FAR
STI ; INTERRUPTS BACK ON
PUSH DS ; SAVE CURRENT DS
PUSH BX ; SAVE BX TEMPORARILY
MOV BX,DATA ;
MOV DS,BX ; ESTABLISH POINTER TO DATA REGION
OR AH,AH ; AH=0
JZ K1 ; ASCII_READ
DEC AH ; AH=1
JZ K2 ; ASCII_STATUS
DEC AH ; AH=2
JZ K3 ; SHIFT_STATUS
POP BX ; RECOVER REGISTER
POP DS
IRET ; INVALID COMMAND
;------ READ THE KEY TO FIGURE OUT WHAT TO DO
K1: ; ASCII READ
STI ; INTERRUPTS BACK ON DURING LOOP
NOP ; ALLOW AN INTERRUPT TO OCCUR
CLI ; INTERRUPTS BACK OFF
MOV BX,BUFFER_HEAD ; GET POINTER TO HEAD OF BUFFER
CMP BX,BUFFER_TAIL ; TEST END OF BUFFER
JZ K1 ; LOOP UNTIL SOMETHING IN BUFFER
MOV AX,[BX] ; GET SCAN CODE AND ASCII CODE
CALL K4 ; MOVE POINTER TO NEXT POSITION
MOV BUFFER_HEAD,BX ; STORE VALUE IN VARIABLE
POP BX ; RECOVER REGISTER
POP DS ; RECOVER SEGMENT
IRET ; RETURN TO CALLER
;------ ASCII STATUS
K2:
CLI ; INTERRUPTS OFF
MOV BX,BUFFER_HEAD ; GET HEAD POINTER
CMP BX,BUFFER_TAIL ; IF EQUAL (Z=1) THEN NOTHING HERE
MOV AX,[BX]
STI ; INTERRUPTS BACK ON
POP BX ; RECOVER REGISTER
POP DS ; RECOVER SEGMENT
RET 2 ; THROW AWAY FLAGS
;------ SHIFT STATUS
K3:
MOV AL,KB_FLAG ; GET THE SHIFT STATUS FLAGS
POP BX ; RECOVER REGISTER
POP DS ; RECOVER REGISTERS
IRET ; RETURN TO CALLER
KEYBOARD_IO ENDP
;------ INCREMENT A BUFFER POINTER
K4 PROC NEAR
ADD BX,2 ; MOVE TO NEXT WORD IN LIST
CMP BX,OFFSET KB_BUFFER_END ; AT END OF BUFFER?
JNE K5 ; NO, CONTINUE
MOV BX,OFFSET KB_BUFFER ; YES, RESET TO BUFFER BEGINNING
K5:
RET
K4 ENDP
;------ TABLE OF SHIFT KEYS AND MASK VALUES
K6 LABEL BYTE
DB INS_KEY ; INSERT KEY
DB CAPS_KEY,NUM_KEY,SCROLL_KEY,ALT_KEY,CTL_KEY
DB LEFT_KEY,RIGHT_KEY
K6L EQU $-K6
;------ SHIFT_MASK_TABLE
K7 LABEL BYTE
DB INS_SHIFT ; INSERT MODE SHIFT
DB CAPS_SHIFT,NUM_SHIFT,SCROLL_SHIFT,ALT_SHIFT,CTL_SHIFT
DB LEFT_SHIFT,RIGHT_SHIFT
;------ SCAN CODE TABLES
K8 DB 27,-1,0,-1,-1,-1,30,-1
DB -1,-1,-1,31,-1,127,-1,17
DB 23,5,18,20,25,21,9,15
DB 16,27,29,10,-1,1,19
DB 4,6,7,8,10,11,12,-1,-1
DB -1,-1,28,26,24,3,22,2
DB 14,13,-1,-1,-1,-1,-1,-1
DB ' ',-1
;------ CTL TABLE SCAN
K9 LABEL BYTE
DB 94,95,96,97,98,99,100,101
DB 102,103,-1,-1,119,-1,132,-1
DB 115,-1,116,-1,117,-1,118,-1
DB -1
;------ LC TABLE
K10 LABEL BYTE
DB 01BH,'1234567890-=',08H,09H
DB 'quertyuiop[]',0DH,-1,'asdfghjkl;',027H
DB 60H,-1,5CH,'zxcvbnm,./',-1,'*',-1,' '
DB -1
;------ UC TABLE
K11 LABEL BYTE
DB 27,'!@#$',37,05EH,'&*()_+',08H,0
DB 'QWERTYUIOP ',0DH,-1,'ASDFGHJKL:"'
DB 07EH,-1,' ZXCVBNM<>?',-1,0,-1,' ',-1
;------ UC TABLE SCAN
K12 LABEL BYTE
DB 84,85,86,87,88,89,90
DB 91,92,93
;------ ALT TABLE SCAN
K13 LABEL BYTE
DB 104,105,106,107,108
DB 109,110,111,112,113
;------ NUM STATE TABLE
K14 LABEL BYTE
DB '789-456+1230.'
;------ BASE CASE TABLE
K15 LABEL BYTE
DB 71,72,73,-1,75,-1,77
DB -1,79,80,81,82,83
;------ KEYBOARD INTERRUPT ROUTINE
KB_INT PROC FAR
STI ; ALLOW FURTHER INTERRUPTS
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
CLD ; FORWARD DIRECTION
MOV AX,DATA
MOV DS,AX ; SET UP ADDRESSING
IN AL,KB_DATA ; READ IN THE CHARACTER
PUSH AX ; SAVE IT
IN AL,KB_CTL ; GET THE CONTROL PORT
MOV AH,AL ; SAVE VALUE
OR AL,80H ; RESET BIT FOR KEYBOARD
OUT KB_CTL,AL
XCHG AH,AL ; GET BACK ORIGINAL CONTROL
OUT KB_CTL,AL ; KB HAS BEEN RESET
POP AX ; RECOVER SCAN CODE
MOV AH,AL ; SAVE SCAN CODE IN AH ALSO
;------ TEST FOR OVERRUN SCAN CODE FROM KEYBOARD
CMP AL,0FFH ; IS THIS AN OVERRUN CHAR
JNZ K16 ; NO, TEST FOR SHIFT KEY
JMP K62 ; BUFFER_FULL_BEEP
;------ TEST FOR SHIFT KEYS
K16: ; TEST_SHIFT
AND AL,07FH ; TURN OFF THE BREAK BIT
PUSH CS
POP ES ; ESTABLISH ADDRESS OF SHIFT TABLE
MOV DI,OFFSET K6 ; SHIFT KEY TABLE
MOV CX,K6L ; LENGTH
REPNE SCASB ; LOOK THROUGH THE TABLE FOR A MATCH
MOV AL,AH ; RECOVER SCAN CODE
JE K17 ; JUMP IF MATCH FOUND
JMP K25 ; IF NO MATCH, THEN SHIFT NOT FOUND
;------ SHIFT KEY FOUND
K17: SUB DI,OFFSET K6+1 ; ADJUST PTR TO SCAN CODE MTCH
MOV AH,CS:K7[DI] ; GET MASK INTO AH
TEST AL,80H ; TEST FOR BREAK KEY
JNZ K23 ; BREAK_SHIFT_FOUND
;------ SHIFT MAKE FOUND, DETERMINE SET OR TOGGLE
CMP AH,SCROLL_SHIFT
JAE K18 ; IF SCROLL SHIFT OR ABOVE, TOGGLE KEY
;------ PLAIN SHIFT KEY, SET SHIFT ON
OR KB_FLAG,AH ; TURN ON SHIFT BIT
JMP K26 ; INTERRUPT_RETURN
;------ TOGGLED SHIFT KEY, TEST FOR 1ST MAKE OR NOT
K18: ; SHIFT-TOGGLE
TEST KB_FLAG, CTL_SHIFT ; CHECK CTL SHIFT STATE
JNZ K25 ; JUMP IF CTL STATE
CMP AL, INS_KEY ; CHECK FOR INSERT KEY
JNZ K22 ; JUMP IF NOT INSERT KEY
TEST KB_FLAG, ALT_SHIFT ; CHECK FOR ALTERNATE SHIFT
JZ K19 ; JUMP IF NOT ALTERNATE SHIFT
JMP NEAR PTR K25 ; JUMP IF ALTERNATE SHIFT
K19: TEST KB_FLAG, NUM_STATE ; CHECK FOR BASE STATE
JNZ K21 ; JUMP IF NUM LOCK IS ON
TEST KB_FLAG, LEFT_SHIFT+RIGHT_SHIFT
JZ K22 ; JUMP IF BASE STATE
K20: ; NUMERIC ZERO, NOT INSERT KEY
MOV AX, 5230H ; PUT OUT AN ASCII ZERO
JMP K57 ; BUFFER_FILL
K21: ; MIGHT BE NUMERIC
TEST KB_FLAG, LEFT_SHIFT+RIGHT_SHIFT
JZ K20 ; JUMP NUMERIC, NOT INSERT
K22: ; SHIFT TOGGLE KEY HIT; PROCESS IT
TEST AH,KB_FLAG_1 ; IS KEY ALREADY DEPRESSED
JNZ K26 ; JUMP IF KEY ALREDY DEPRESSED
OR KB_FLAG_1,AH ; INDICATE THAT THE KEY IS DEPRESSED
XOR KB_FLAG,AH ; TOGGLE THE SHIFT STATE
CMP AL,INS_KEY ; TEST FOR 1ST MAKE OF INSERT KEY
JNE K26 ; JUMP IF NOT INSERT KEY
MOV AX,INS_KEY*256 ; SET SCAN CODE INTO AH, 0 INTO AL
JMP K57 ; PUT INTO OUTPUT BUFFER
;------ BREAK SHIFT FOUND
K23: ; BREAK-SHIFT-FOUND
CMP AH,SCROLL_SHIFT ; IS THIS A TOGGLE KEY
JAE K24 ; YES, HANDLE BREAK TOGGLE
NOT AH ; INVERT MASK
AND KB_FLAG,AH ; TURN OFF SHIFT BIT
CMP AL,ALT_KEY+80H ; IS THIS ALTERNATE SHIFT RELEASE
JNE K26 ; INTERRUPT_RETURN
;------ ALTERNATE SHIFT KEY RELEASED, GET THE VALUE INTO BUFFER
MOV AL,ALT_INPUT
MOV AH,0 ; SCAN CODE OF 0
MOV ALT_INPUT,AH ; ZERO OUT THE FIELD
CMP AL,0 ; WAS THE INPUT=0
JE K26 ; INTERRUPT_RETURN
JMP K58 ; IT WASN'T, SO PUT IN BUFFER
K24: ; BREAK-TOGGLE
NOT AH ; INVERT MASK
AND KB_FLAG_1,AH ; INDICATE NO LONGER DEPRESSED
JMP SHORT K26 ; INTERRUPT_RETURN
;------ TEST FOR HOLD STATE
K25: ; NO-SHIFT-FOUND
CMP AL,80H ; TEST FOR BREAK KEY
JAE K26 ; NOTHING FOR BREAK CHARS FROM HERE ON
TEST KB_FLAG_1,HOLD_STATE ; ARE WE IN HOLD STATE
JZ K28 ; BRANCH AROUND TEST IF NOT
CMP AL,NUM_KEY
JE K26 ; CAN'T END HOLD ON NUM_LOCK
AND KB_FLAG_1,NOT HOLD_STATE ; TURN OFF THE HOLD STATE BIT
K26: ; INTERRUPT-RETURN
CLI ; TURN OFF INTERRUPTS
MOV AL,EOI ; END OF INTERRUPT COMMAND
OUT 020H,AL ; SEND COMMAND TO INTERRUPT CONTROL PORT
K27: ; INTERRUPT-RETURN-NO-EOI
POP ES
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX ; RESTORE STATE
IRET ; RETURN, INTERRUPTS BACK ON WITH FLAG CHANGE
;------ NOT IN HOLD STATE, TEST FOR SPECIAL CHARS
K28: ; NO-HOLD-STATE
TEST KB_FLAG,ALT_SHIFT ; ARE WE IN ALTERNATE SHIFT
JNZ K29 ; JUMP IF ALTERNATE SHIFT
JMP K38 ; JUMP IF NOT ALTERNATE
; ------ TEST FOR RESET KEY SENTENCE (CTL ALT DEL)
K29: ; TEST-RESET
TEST KB_FLAG,CTL_SHIFT ; ARE WE IN CONTROL SHIFT ALSO
JZ K31 ; NO_RESET
CMP AL,DEL_KEY ; SHIFT STATE IS THERE, TEST KEY
JNE K31 ; NO_RESET
;------ CTL-ALT-DEL HAS BEEN FOUND, DO I/O CLEANUP
MOV RESET_FLAG, 1234H ; SET FLAG FOR RESET FACTION
JMP RESET ; JUMP TO POWER ON DIAGNOSTICS
;------ ALT-INPUT-TABLE
K30 LABEL BYTE
DB 82,79,80,81,75,76,77
DB 71,72,73 ; 10 NUMBERS ON KEYPAD
;------ SUPER-SHIFT-TABLE
DB 16,17,18,19,20,21,22,23 ; A-Z TYPEWRITER CHARS
DB 24,25,30,31,32,33,34,35
DB 36,37,38,44,45,46,47,48
DB 49,50
;------ IN ALTERNATE SHIFT, RESET NOT FOUND
K31: ; NO-RESET
CMP AL,57 ; TEST FOR SPACE KEY
JNE K32 ; NOT THERE
MOV AL,' ' ; SET SPACE CHAR
JMP K57 ; BUFFER_FILL
;------ LOOK FOR KEY PAD ENTRY
K32: ; ALT-KEY-PAD
MOV DI,OFFSET K30 ; ALT-INPUT-TABLE
MOV CX,10 ; LOOK FOR ENTRY USING KEYPAD
REPNE SCASB ; LOOK FOR MATCH
JNE K33 ; NO_ALT_KEYPAD
SUB DI,OFFSET K30+1 ; DI NOW HAS ENTRY VALUE
MOV AL,ALT_INPUT ; GET THE CURRENT BYTE
MOV AH,10 ; MULTIPLY BY 10
MUL AH
ADD AX,DI ; ADD IN THE LATEST ENTRY
MOV ALT_INPUT,AL ; STORE IT ANAY
JMP K26 ; THROW AWAY THAT KETSTROKE
; ----- LOOK FOR SUPERSHIFT ENTRY
K33: ; NO-ALT-KEYPAD
MOV ALT_INPUT,0 ; ZERO ANY PREVIOUS ENTRY INTO INPUT
MOV CX,26 ; DI, ES ALREADY POINTING
REPNE SCASB ; LOOK FOR MATCH IN ALPHABET
JNE K34 ; NOT FOUND, FUNCTION KEY OR OTHER
MOV AL,0 ; ASCII CODE OF ZERO
JMP K57 ; PUT IT IN THE BUFFER
;------ LOOK FOR TOP ROW OF ALTERNATE SHIFT
K34: ; ALT-TOP-ROW
CMP AL,2 ; KEY WITH '1' ON IT
JB K35 ; NOT ONE OF INTERESTING KEYS
CMP AL,14 ; IS IT IN THE REGION
JAE K35 ; ALT-FUNCTION
ADD AH,118 ; CONVERT PSUEDO SCAN CODE TO RANGE
MOV AL,0 ; INDICATE AS SUCH
JMP K57 ; BUFFER_FILL
;------ TRANSLATE ALTERNATE SHIFT PSEUDO SCAN CODES
K35: ; ALT-FUNCTION
CMP AL,59 ; TEST FOR IN TABLE
JAE K37 ; ALT-CONTINUE
K36: ; CLOSE-RETURN
JMP K26 ; IGNORE THE KEY
K37: ; ALT-CONTINUE
CMP AL,71 ; IN KEYPAD REGION
JAE K36 ; IF SO, IGNORE
MOV BX,OFFSET K13 ; ALT SHIFT PSEUDO SCAN TABLE
JMP K63 ; TRANSLATE THAT
;------ NOT IN ALTERNATE SHIFT
K38: ; NOT-ALT-SHIFT
TEST KB_FLAG,CTL_SHIFT ; ARE WE IN CONTROL SHIFT
JZ K44 ; NOT-CTL-SHIFT
;------ CONTROL SHIFT, TEST SPECIAL CHARACTERS
;------ TEST FOR BREAK AND PAUSE KEYS
CMP AL,SCROLL_KEY ; TEST FOR BREAK
JNE K39 ; NO-BREAK
MOV BX,OFFSET KB_BUFFER ; RESET BUFFER TO EMPTY
MOV BUFFER_HEAD,BX ;
MOV BUFFER_TAIL,BX ;
MOV BIOS_BREAK,80H ; TURN ON BIOS_BREAK BIT
INT 1BH ; BREAK INTERRUPT VECTOR
MOV AX,0 ; PUT OUT DUMMY CHARACTER
JMP K57 ; BUFFER_FILL
K39: ; NO-BREAK
CMP AL,NUM_KEY ; LOOK FOR PAUSE KEY
JNE K41 ; NO-PAUSE
OR KB_FLAG_1,HOLD_STATE ; TURN ON THE HOLD FLAG
MOV AL,EOI ; END OF INTERRUPT TO CONTROL PORT
OUT 020H,AL ; ALLOW FURTHER KETSTROKE INTS
;------ DURING PAUSE INTERVAL, TURN CRT BACK ON
CMP CRT_MODE,7 ; IS THIS BLACK AND WHITE CARD
JE K40 ; YES, NOTHING TO DO
MOV DX,03D8H ; PORT FOR COLOR CARD
MOV AL,CRT_MODE_SET ; GET THE VALUE OF THE CURRENT MODE
OUT DX,AL ; SET THE CRT MODE, SO THAT CRT IS ON
K40: ; PAUSE-LOOP
TEST KB_FLAG_1,HOLD_STATE
JNZ K40 ; LOOP UNTIL FLAG TURNED OFF
JMP K27 ; INTERRUPT_RETURN_NO_EOI
K41: ; NO-PAUSE
;------ TEST SPECIAL CASE KEY 55
CMP AL,55
JNE K42 ; NOT-KEY-55
MOV AX,114*256 ; START/STOP PRINTING SWITCH
JMP K57 ; BUFFER_FILL
;------ SET UP TO TRANSLATE CONTROL SHIFT
K42: ; NOT-KEY-55
MOV BX,OFFSET K8 ; SET UP TO TRANSLATE CTL
CMP AL,59 ; IS IT IN TABLE
JAE K43 ; CTL-TABLE-TRANSLATE
JMP NEAR PTR K56 ; YES, GO TRANSLATE CHAR
K43: ; CTL-TABLE-TRANSLATE
MOV BX,OFFSET K9 ; CTL TABLE SCAN
JMP K63 ; TRANSLATE_SCAN
;------ NOT IN CONRTOL SHIFT
K44: ; NOT-CTL-SHIFT
CMP AL,71 ; TEST FOR KEYPAD REGION
JAE K48 ; HANDLE KEYPAD REGION
TEST KB_FLAG,LEFT_SHIFT+RIGHT_SHIFT
JZ K54 ; TEST FOR SHIFT STATE
;------ UPPER CASE, HANDLE SPECIAL CASES
CMP AL,15 ; BACK TAB KEY
JNE K45 ; NOT-BACK-TAB
MOV AX,15*256 ; SET PSEUDO SCAN CODE
JMP NEAR PTR K57 ; BUFFER_FILL
K45: ; NOT-BACK-TAB
CMP AL,55 ; PRINT SCEEN KEY
JNE K46 ; NOT-PRINT-SCREEN
;------ ISSUE INTERRUPT TO INDICATE PRINT SCREEN FUNCTION
MOV AL,EOI ; END OF CURRENT INTERRUPT
OUT 020H,AL ; SO FURTHER THINGS CAN HAPPEN
INT 5H ; ISSUE PRINT SCREEN INTERRUPT
JMP K27 ; G0 BACK WITHOUT EOI OCCURRING
K46: ; NOT-PRINT-SCREEN
CMP AL,59 ; FUNCTION KEYS
JB K47 ; NOT-UPPER-FUNCTION
MOV BX,OFFSET K12 ; UPPER CASE PSEUDO SCAN CODES
JMP K63 ; TRANSLATE_SCAN
K47: ; NOT-UPPER-FUNCTION
MOV BX,OFFSET K11 ; POINT TO UPPER CASE TABLE
JMP SHORT K56 ; OK, TRANSLATE THE CHAR
;------ KEYPAD KEYS, MUST TEST NUM LOCK FOR DETERMINATION
K48: ; KEYPAD-REGION
TEST KB_FLAG,NUM_STATE ; ARE WE IN NUM_LOCK
JNZ K52 ; TEST FOR SURE
TEST KB_FLAG,LEFT_SHIFT+RIGHT_SHIFT ; ARE WE IN SHIFT STATE
JNZ K53 ; IF SHIFTED, REALLY NUM STATE
;------ BASE CASE FOR KEYPAD
K49: ; BASE-CASE
CMP AL,74 ; SPECIAL CASE FOR A COUPLE OF KEYS
JE K50 ; MINUS
CMP AL,78
JE K51
SUB AL,71 ; CONVERT ORIGIN
MOV BX,OFFSET K15 ; BASE CASE TABLE
JMP SHORT K64 ; CONVERT TO PSEUDO SCAN
K50: MOV AX,74*256+'-' ; MINUS
JMP SHORT K57 ; BUFFER_FILL
K51: MOV AX,78*256+'+' ; PLUS
JMP SHORT K57 ; BUFFER_FILL
;------ MIGHT BE NUM LOCK, TEST SHIFT STATUS
K52: ;ALMOST-NUM-STATE
TEST KB_FLAG,LEFT_SHIFT+RIGHT_SHIFT
JNZ K49 ; SHIFTED TEMP OUT OF NUM STATE
K53: ; REALLY_NUM_STATE
SUB AL,70 ; CONVERT ORIGIN
MOV BX,OFFSET K14 ; NUM STATE TABLE
JMP SHORT K56 ; TRANSLATE_CHAR
;------ PLAIN OLD LOWER CASE
K54: ; NOT-SHIFT
CMP AL,59 ; TEST FOR FUNCTION KETS
JB K55 ; NOT-LOWER-FUNCTION
MOV AL,0 ; SCAN CODE IN AH ALREADY
JMP SHORT K57 ; BUFFER_FILL
K55: ; NOT-LOWER-FUNCTION
MOV BX,OFFSET K10 ; LC TABLE
;------TRANSLATE THE CHARACTER
K56: ; TRANSLATE-CHAR
DEC AL ; CONVERT ORIGIN
XLAT CS:K11 ; CONVERT THE SCAN CODE TO ASCII
;------ PUT CHARACTER INTO BUFFER
K57: ; BUFFER-FILL
CMP AL,-1 ; IS THIS AN IGNORE CHAR
JE K59 ; YES, DO NOTHING WITH IT
CMP AH,-1 ; LOOK FOR -1 PSEUDO SCAN
JE K59 ; NEAR_INTERRUPT_RETURN
;------ HANDLE THE CAPS LOCK PROBLEM
K58: ; BUFFER-FILL-NOTEST
TEST KB_FLAG,CAPS_STATE ; ARE WE IN CAPS LOCK STATE
JZ K61 ; SKIP IF NOT
;------ IN CAPS LOCK STATE
TEST KB_FLAG,LEFT_SHIFT+RIGHT_SHIFT ; TEST FOR SHIFT STATE
JZ K60 ; IF NOT SHIFT, CONVERT LOWER TO UPPER
;------ CONVERT ANY UPPER CASE TO LOWER CASE
CMP AL,'A' ; FIND OUT IF ALPHABETIC
JB K61 ; NOT_CAPS_STATE
CMP AL,'Z'
JA K61 ; NOT_CAPS_STATE
ADD AL,'a'-'A' ; CONVERT TO LOWER CASE
JMP SHORT K61 ; NOT_CAPS_STATE
K59: ; NEAR-INTERRUPT-RETURN
JMP K26 ; INTERRUPT_RETURN
;------ CONVVERT ANY LOWER CASE TO UPPER CASE
K60: ; LOWER-TO-UPPER
CMP AL,'a' ; FIND OUT IF ALPHABETIC
JB K61 ; NOT_CAPS_STATE
CMP AL,'z'
JA K61 ; NOT_CAPS_STATE
SUB AL,'a'-'A' ; CONVERT TO UPPER CASE
K61: ; NOT-CAPS-STATE
MOV BX,BUFFER_TAIL ; GET THE END POINTER TO THE BUFFER
MOV SI,BX ; SAVE THE VALUE
CALL K4 ; ADVANCE THE TAIL
CMP BX,BUFFER_HEAD ; HAS THE BUFFER WRAPPED AROUND
JE K62 ; BUFFER_FULL_BEEP
MOV [SI],AX ; STORE THE VALUE
MOV BUFFER_TAIL,BX ; MOVE THE POINTER UP
JMP K26 ; INTERRUPT_RETURN
;------ BUFFER IS FULL, SOUND THE BEEPER
K62: ; BUFFER-FULL-BEEP
CALL ERROR_BEEP
JMP NEAR PTR K26 ; INTERRUPT_RETURN
;------ TRANSLATE SCAN FOR PSEUDO SCAN CODES
K63: ; TRANSLATE-SCAN
SUB AL,59 ; CONVERT ORIGIN TO FUNCTION KEYS
K64: ; TRANSLATE-SCAN-ORGD
XLAT CS:K9 ; CTL TABLE SCAN
MOV AH,AL ; PUT VALUE INTO AH
MOV AL,0 ; ZERO ASCII CODE
JMP K57 ; PUT IT INTO THE BUFFER
KB_INT ENDP
ERROR_BEEP PROC NEAR
PUSH AX ; SAVE REGISTERS
PUSH BX
PUSH CX
MOV BX,0C0H ; NUMBER OF CYCLES FOR 1/8 SECOND TONE
IN AL,KB_CTL ; GET CONTROL INFORMATION
PUSH AX ; SAVE
K65: ; BEEP-CYCLE
AND AL,0FCH ; TURN OFF TIMER GATE AND SPEAKER DATA
OUT KB_CTL,AL ; OUTPUT TO CONTROL
MOV CX,48H ; HALF CYCLE TIME FOR TONE
K66: LOOP K66 ; SPEAKER OFF
OR AL,2 ; TURN ON SPEAKER BIT
OUT KB_CTL,AL ; OUTPUT TO CONTROL
MOV CX,48H ; SET UP COUNT
K67: LOOP K67 ; ANOTHER HALF CYCLE
DEC BX ; TOTAL TIME COUNT
JNZ K65 ; DO ANOTHER CYCLE
POP AX ; RECOVER CONTROL
OUT KB_CTL,AL ; OUTPUT THE CONTROL
POP CX ; RECOVER REGISTERS
POP BX
POP AX
RET
ERROR_BEEP ENDP
;-- INT 13 ----------------------------------
;DISKETTE I/O
; THIS INTERFACE PROVIDES ACCESS TO THE 5 1/4" DISKETTE DRIVES
;INPUT
; (AH)=0 RESET DISKETTE SYSTEM
; HARD RESET TO NEC, PREPARE COMMAND, RECAL REQD ON ALL DRIVES
; (AH)=1 READ THE STATUS OF THE SYSTEM INTO (AL)
; DISKETTE_STATUS FROM LAST OP'N IS USED
; REGISTERS FOR READ/WRITE/VERIFY/FORMAT
; (DL) - DRIVE NUMBER (0-3 ALLOWED, VALUE CHECKED)
; (DH) - HEAD NUMBER (0-1 ALLOWED, NOT VALUE CHECKED)
; (CH) - TRACK NUMBER (0-39, NOT VALUE CHECKED)
; (CL) - SECTOR NUMBER (1-8, NOT VALUE CHECKED)
; (AL) - NUMBER OF SECTORS ( MAX = 8, NOT VALUE CHECKED)
;
; (ES:BX) - ADDRESS OF BUFFER (NOT REQUIRED FOR VERIFY)
;
; (AH)=2 READ THE DESIRED SECTORS INTO MEMORY
; (AH)=3 WRITE THE DESIRED SECTORS FROM MEMORY
; (AH)=4 VERIFY THE DESIRED SECTORS
; (AH)=5 FORMAT THE DESIRED TRACKS
; FOR THE FORMAT OPERATION, THE BUFFER POINTER (ES,BX) MUST
; POINT TO THE COLLECTION OF DESIRED ADDRESS FIELDS FOR THE
; TRACK. EACH FIELD IS COMPOSED OF 4 BYTES, (C,H,R,N), WHERE
; C = TRACK NUMBER, H=HEAD NUMBER, R = SECTOR NUMBER, N= NUMBER
; OF BYTES PER SECTOR (00=128, 01=256, 02=512, 03=1024,)
; THERE MUST BE ONE ENTRY FOR EVERY SECTOR ON THE TRACK.
; THIS INFORMATION IS USED TO FIND THE REQUESTED SECTOR DURING
; READ/WRITE ACCESS.
; DATA VARIABLE -- DISK_POINTER
; DOUBLE WORD POINTER TO THE CURRENT SET OF DISKETTE PARAMETERS
; OUTPUT
; AH = STATUS OF OPERATION
; STATUS BITS ARE DEFINED IN THE EQUATES FOR DISKETTE_STATUS
; VARIABLE IN THE DATA SEGMENT OF THIS MODULE
; CY = 0 SUCCESSFUL OPERATION (AH=0 ON RETURN)
; CY = 1 FAILED OPERATION (AH HAS ERROR REASON)
; FOR READ/WRITE/VERIFY
; DS,BX,DX,CH,CL PRESERVED
; AL = NUMBER OF SECTORS ACTUALLY READ
; ***** AL MAY NOT BE CORRECT IF TIME OUT ERROR OCCURS
; NOTE: IF AN ERROR IS REPORTED BY THE DISKETTE CODE, THE APPROPRIATE
; ACTION IS TO RESET THE DISKETTE, THEN RETRY THE OPERATION.
; ON READ ACCESSES, NO MOTOR START DELAY IS TAKEN, SO THAT
; THREE RETRIES ARE REQUIRED ON READS TO ENSURE THAT THE
; PROBLEM IS NOT DUE TO MOTOR START-UP.
;--------------------------------------------
ASSUME CS:CODE,DS:DATA,ES:DATA
DISKETTE_IO PROC FAR
STI ; INTERRUPTS BACK ON
PUSH BX ; SAVE ADDRESS
PUSH CX
PUSH DS ; SAVE SEGMENT REGISTER VALUE
PUSH SI ; SAVE ALL REGISTERS DURING OPERATION
PUSH DI
PUSH BP
PUSH DX
MOV BP,SP ; SET UP POINTER TO HEAD PARM
MOV SI,DATA
MOV DS,SI ; SET DATA REGION
CALL J1 ; CALL THE REST TO ENSURE DS RESTORED
MOV BX,4 ; GET THE MOTOR WAIT PARAMETER
CALL GET_PARM
MOV MOTOR_COUNT,AH ; SET THE TIMER COST FOR THE MOTOR
MOV AH,DISKETTE_STATUS ; GET STATUS OF OPERATION
CMP AH,1 ; SET THE CARRY FLAG TO INDICATE
CMC ; SUCCESS OR FAILURE
POP DX ; RESTORE ALL REGISTERS
POP BP
POP DI
POP SI
POP DS
POP CX
POP BX ; RECOVER ADDRESS
RET 2 ; THROW AWAY SAVED FLAGS
DISKETTE_IO ENDP
J1 PROC NEAR
MOV DH,AL ; SAVE # SECTORS IN DH
AND MOTOR_STATUS,07FH ; INDICATE A READ OPERATION
OR AH,AH ; AH=0
JZ DISK_RESET
DEC AH ; AH=1
JZ DISK_STATUS
MOV DISKETTE_STATUS,0 ; RESET THE STATUS INDICATOR
CMP DL,4 ; TEST FOR DRIVE IN 0-3 RANGE
JAE J3 ; ERROR IF ABOVE
DEC AH ; AH=2
JZ DISK_READ
DEC AH ; AH=3
JNZ J2 ; TEST_DISK_VERF
JMP DISK_WRITE
J2: ; TEST_DISK_VERF
DEC AH ; AH=4
JZ DISK_VERF
DEC AH ; AH=5
JZ DISK_FORMAT
J3: ; BAD_COMMAND
MOV DISKETTE_STATUS,BAD_CMD ; ERROR CODE, NO SECTORS TRANSFERRED
RET ; UNDEFINED OPERATION
J1 ENDP
;------ RESET THE DISKETTE SYSTEM
DISK_RESET PROC NEAR
MOV DX,03F2H ; ADAPTER CONTROL PORT
CLI ; NO INTERRUPTS
MOV AL,MOTOR_STATUS ; WHICH MOTOR IS ON
MOV CL,4 ; SHIFT COUNT
SAL AL,CL ; MOVE MOTOR VALUE TO HIGH NYBBLE
TEST AL, 20H ; SELECT CORRESPONDING DRIVE
JNZ J5 ; JUMP IF MOTOR ONE IS ON
TEST AL, 40H
JNZ J4 ; JUMP IF MOTOR TWO IS ON
TEST AL, 80H
JZ J6 ; JUMP IF MOTOR ZERO IS ON
INC AL
J4: INC AL
J5: INC AL
J6: OR AL,8 ; TURN ON INTERRUPT ENABLE
OUT DX,AL ; RESET THE ADAPTER
MOV SEEK_STATUS,0 ; SET RECAL REQUIRED ON ALL DRIVES
MOV DISKETTE_STATUS,0 ; SET OK STATUS FOR DISKETTE
OR AL,4 ; TURN OFF RESET
OUT DX,AL ; TURN OFF THE RESET
STI ; REENABLE THE INTERRUPTS
CALL CHK_STAT_2 ; DO SENSE INTERRUPT STATUS FOLLOWING RESET
MOV AL,NEC_STATUS ; IGNORE ERROR RETURN AND DO OWN RESET
CMP AL,0C0H ; TEST FOR DRIVE READY TRANSITION
JZ J7 ; EVERYTHING OK
OR DISKETTE_STATUS,BAD_NEC ; SET ERROR CODE
JMP SHORT J8 ; RESET_RET
;------ SEND SPECIFY COMMAND TO NEC
J7: ; DRIVE_READY
MOV AH,03H ; SPECIFY COMMAND
CALL NEC_OUTPUT ; OUTPUT THE COMMAND
MOV BX,1 ; FIRST BYTE PARM IN BLOCK
CALL GET_PARM ; TO THE NEC CONTROLLER
MOV BX,3 ; SECOND BYTE PARM IN BLOCK
CALL GET_PARM ; TO THE NEC CONTROLLER
J8: ; RESET_RET
RET ; RETURN TO CALLER
DISK_RESET ENDP
;------ DISKETTE STATUS ROUTINE
DISK_STATUS PROC NEAR
MOV AL,DISKETTE_STATUS
RET
DISK_STATUS ENDP
;------ DISKETTE READ
DISK_READ PROC NEAR
MOV AL,046H ; READ COMMAND FOR DMA
J9: ; DISK_READ_CONT
CALL DMA_SETUP ; SET UP THE DMA
MOV AH,066H ; SET UP READ COMMAND FOR NEC CONTROLLER
JMP SHORT RW_OPN ; GO DO THE OPERATION
DISK_READ ENDP
;------ DISKETTE VERIFY
DISK_VERF PROC NEAR
MOV AL,042H ; VERIFY COMMAND FOR DMA
JMP J9 ; DO AS IF DISK READ
DISK_VERF ENDP
;------ DISKETTE FORMAT
DISK_FORMAT PROC NEAR
OR MOTOR_STATUS,80H ; INDICATE WRITE OPERATION
MOV AL,04AH ; WILL WRITE TO THE DISKETTE
CALL DMA_SETUP ; SET UP THE DMA
MOV AH,04DH ; ESTABLISH THE FORMAT COMMAND
JMP SHORT RW_OPN ; DO THE OPERATION
J10: ; CONTINUATION OF RW_OPN FOR FMT
MOV BX,7 ; GET THE
CALL GET_PARM ; BYTES/SECTOR VALUE TO NEC
MOV BX,9 ; GET THE
CALL GET_PARM ; SECTORS/TRACK VALUE TO NEC
MOV BX,15 ; GET THE
CALL GET_PARM ; GAP LENGTH VALUE TO NEC
MOV BX,17 ; GET THE FILLER BYTE
JMP J16 ; TO THE CONTROLLER
DISK_FORMAT ENDP
;------ DISKETTE WRITE ROUTINE
DISK_WRITE PROC NEAR
OR MOTOR_STATUS,80H ; INDICATE WRITE OPERATION
MOV AL,04AH ; DMA WRITE COMMAND
CALL DMA_SETUP
MOV AH,045H ; NEC COMMAND TO WRITE TO DISKETTE
DISK_WRITE ENDP
;----- ALLOW WRITE ROUTINE TO FALL INTO RW_OPN
;---------------------------------------
; RW_OPN
; THIS ROUTINE PERFORMS THE READ/WRITE/VERIFY OPERATION
;---------------------------------------
RW_OPN PROC NEAR
JNC J11 ; TEST FOR DMA ERROR
MOV DISKETTE_STATUS,DMA_BOUNDARY ; SET ERROR
MOV AL,0 ; NO SECTORS TRANSFERRED
RET ; RETURN TO MAIN ROUTINE
J11: ; DO_RW_OPN
PUSH AX ; SAVE THE COMMAND
;------ TURN ON THE MOTOR AND SELECT THE DRIVE
PUSH CX ; SAVE THE T/S PARMS
MOV CL,DL ; GET DRIVE NUMBER AS SHIFT COUNT
MOV AL,1 ; MASK FOR DETERMINING MOTOR BIT
SAL AL,CL ; SHIFT THE MASK BIT
CLI ; NO INTERRUPTS WHILE DETERMINING MOTOR STATUS
MOV MOTOR_COUNT,0FFH ; SET LARGE COUNT DURING OPERATION
TEST AL,MOTOR_STATUS ; TEST THAT MOTOR FOR OPERATING
JNZ J14 ; IF RUNNING, SKIP THE WAIT
AND MOTOR_STATUS,0F0H ; TURN OFF ALL MOTOR BITS
OR MOTOR_STATUS,AL ; TURN ON THE CURRENT MOTOR
STI ; INTERRUPTS BACK ON
MOV AL,10H ; MASK BIT
SAL AL,CL ; DEVELOP BIT MASK FOR MOTOR ENABLE
OR AL,DL ; GET DRIVE SELECT BITS IN
OR AL,0CH ; NO RESET, ENABLE DMA/INT
PUSH DX ; SAVE REG
MOV DX,03F2H ; CONTROL PORT ADDRESS
OUT DX,AL
POP DX ; RECOVER REGISTERS
;------ WAIT FOR MOTOR IF WRITE OPERATION
TEST MOTOR_STATUS,80H ; IS THIS A WRITE
JZ J14 ; NO, CONTINUE WITHOUT WAIT
MOV BX,20 ; GET THE MOTOR WAIT
CALL GET_PARM ; PARAMETER
OR AH,AH ; TEST FOR NO WAIT
J12: ; TEST_WAIT_TIME
JZ J14 ; EXIT WITH TIME EXPIRED
SUB CX,CX ; SET UP 1/8 SECOND LOOP TIME
J13: LOOP J13 ; WAIT FOR THE REQUIRED TIME
DEC AH ; DECREMENT TIME VALUE
JMP J12 ; ARE WE DONE YET
J14: ; MOTOR_RUNNING
STI ; INTERRUPTS BACK ON FOR BYPASS WAIT
POP CX
;------ DO THE SEEK OPERATION
CALL SEEK ; MOVE TO CORRECT TRACK
POP AX ; RECOVER COMMAND
MOV BH,AH ; SAVE COMMAND IN BH
MOV DH,0 ; SET NO SECTORS READ IN CASE OF ERROR
JC J17 ; IF ERROR, THEN EXIT AFTER MOTOR OFF
MOV SI, OFFSET J17 ; DUMMY RETURN ON STACK FOR NEC_OUTPUT
PUSH SI ; SO THAT IT WILL RETURN TO MOTOR OFF LOCATIOH
;------ SEND OUT THE PARAMETERS TO THE CONTROLLER
CALL NEC_OUTPUT ; OUTPUT THE OPERATION COMMAND
MOV AH,[BP+1] ; GET THE CURRENT HEAD NUMBER
SAL AH,1 ; MOVE IT TO BIT 2
SAL AH,1
AND AH,4 ; ISOLATE THAT BIT
OR AH,DL ; OR IN THE DRIVE NUMBER
CALL NEC_OUTPUT
;------ TEST FOR FORMAT COMMAND
CMP BH,04DH ; IS THIS A FORMAT OPERATION
JNE J15 ; NO, CONTINUE WITH R/W/V
JMP J10 ; IF SO, HANDLE SPECIAL
J15: MOV AH,CH ; CYLINDER NUMBER
CALL NEC_OUTPUT
MOV AH,[BP+1] ; HEAD NUMBER FROM STACK
CALL NEC_OUTPUT
MOV AH,CL ; SECTOR NUMBER
CALL NEC_OUTPUT
MOV BX,7 ; BYTES/SECTOR PARM FROM BLOCK
CALL GET_PARM ; TO THE NEC
MOV BX,9 ; EOT PARM FROM BLOCK
CALL GET_PARM ; TO THE NEC
MOV BX,11 ; GAP LENGTH PARM FROM BLOCK
CALL GET_PARM ; TO THE NEC
MOV BX,13 ; DTL PARM FROM BLOCK
J16: ; RW_OPN FINISH
CALL GET_PARM ; TO THE NEC
POP SI ; CAN NOW DISCARD THAT DUMMY RETURN ADDRE5S
;------ LET THE OPERATION HAPPEN
CALL WAIT_INT ; WAIT FOR THE INTERRUPT
J17: ; MOTOR_OFF
JC J21 ; LOOK FOR ERROR
CALL RESULTS ; GET THE NEC STATUS
JC J20 ; LOOK FOR ERROR
;------ CHECK THE RESULTS RETURNED BY THE CONTROLLER
CLD ; SET THE CORRECT DIRECTION
MOV SI,OFFSET NEC_STATUS ; POINT TO STATUS FIELD
LODS NEC_STATUS ; GET ST0
AND AL,0C0H ; TEST FOR NORMAL TERMINATION
JZ J22 ; OPN_OK
CMP AL,040H ; TEST FOR ABNORMAL TERMINATION
JNZ J18 ; NOT ABNORMAL, BAD NEC
;------ ABNORMAL TERMINATION, FIND OUT WHY
LODS NEC_STATUS ; GET ST1
SAL AL,1 ; TEST FOR EOT FOUND
MOV AH,RECORD_NOT_FND
JC J19 ; RW_FAIL
SAL AL,1
SAL AL,1 ; TEST FOR CRC ERROR
MOV AH,BAD_CRC
JC J19 ; RW_FAIL
SAL AL,1 ; TEST FOR DMA OVERRUN
MOV AH,BAD_DMA
JC J19 ; RW_FAIL
SAL AL,1
SAL AL,1 ; TEST FOR RECORD NOT FOUND
MOV AH,RECORD_NOT_FND
JC J19 ; RW_FAIL
SAL AL,1
MOV AH,WRITE_PROTECT ; TEST FOR WRITE PROTECT
JC J19 ; RW_FAIL
SAL AL,1 ; TEST MISSING ADDRESS MARK
MOV AH,BAD_ADDR_MARK
JC J19 ; RW_FAIL
;------ NEC MUST HAVE FAILED
J18: ; RW_NEC_FAIL
MOV AH,BAD_NEC
J19: ; RW_FAIL
OR DISKETTE_STATUS,AH
CALL NUM_TRANS ; HOW MANY WERE REALLY TRANSFERRED
J20: ; RW_ERR
RET ; RETURN TO CALLER
J21: ; RW_ERR_RES
CALL RESULTS ; FLUSH THE RESULTS BUFFER
RET
;------ OPERATION WAS SUCCESSFUL
J22: ; OPN_OK
CALL NUM_TRANS ; HOW MANY GOT MOVED
XOR AH,AH ; NO ERRORS
RET
RW_OPN ENDP
;--------------------------------------------
; NEC_OUTPUT
; THIS ROUTINE SENDS A BYTE TO THE NEC CONTROLLER
; AFTER TESTING FOR CORRECT DIRECTION AND CONTROLLER READY
; THIS ROUTINE WILL TIME OUT IF THE BYTE IS NOT ACCEPTED
; WITHIN A REASONABLE AMOUNT OF TIME, SETTING THE DISKETTE STATUS
; ON COMPLETION
; INPUT
; (AH) BYTE TO BE OUTPUT
; OUTPUT
; CY = 0 SUCCESS
; CY = 1 FAILURE -- DISKETTE STATUS UPDATED
; IF A FAILURE HAS OCCURED, THE RETURN IS MADE ONE LEVEL
; HIGHER THAN THE CALLER OF NEC_OUTPUT
; THIS REMOVES THE REQUIREMENT OF TESTING AFTER EVERY CALL
; OF NEC_OUTPUT
; (AL) DESTROYED
;--------------------------------------------
NEC_OUTPUT PROC NEAR
PUSH DX ; SAVE REGISTERS
PUSH CX
MOV DX,03F4H ; STATUS PORT
XOR CX,CX ; COUNT FOR TIME OUT
J23:
IN AL,DX ; GET STATUS
TEST AL,040H ; TEST DIRECTION BIT
JZ J25 ; DIRECTION OK
LOOP J23
J24: ; TIME_ERROR
OR DISKETTE_STATUS,TIME_OUT
POP CX
POP DX ; SET ERROR CODE AND RESTORE REGS
POP AX ; DISCARD THE RETURN ADDRESS
STC ; INDICATE ERROR TO CALLER
RET
J25:
XOR CX,CX ; RESET THE COUNT
J26:
IN AL,DX ; GET THE STATUS
TEST AL,080H ; IS IT READY
JNZ J27 ; YES, GO OUTPUT
LOOP J26 ; COUNT DOWN AND TRY AGAIN
JMP J24 ; ERROR CONDITION
J27: ; OUTPUT
MOV AL,AH ; GET BYTE TO OUTPUT
MOV DX,03F5H ; DATA PORT
OUT DX,AL ; OUTPUT THE BYTE
POP CX ; RECOVER REGISTERS
POP DX
RET ; CY = 0 FROM TEST INSTRUCTION
NEC_OUTPUT ENDP
;------------------------------------------
; GET_PARM
; THIS ROUTINE FETCHES THE INDEXED POINTER FROM
; THE DISK_BASE BLOCK POINTED AT BY THE DATA
; VARIABLE DISK_POINTER
; A BYTE FROM THAT TABLE IS THEN MOVED INTO AH,
; THE INDEX OF THAT BYTE BEING THE PARM IN BX
; ENTRY --
; BX = INDEX OF BYTE TO BE FETCHED * 2
; IF THE LOW BIT OF BX IS ON, THE BYTE IS IMMEDIATELY
; OUTPUT TO THE NEC CONTROLLER
; EXIT --
; AH = THAT BYTE FROM BLOCK
;--------------------------------------------
GET_PARM PROC NEAR
PUSH DS ; SAVE SEGMENT
SUB AX,AX ; ZERO TO AX
MOV DS,AX
ASSUME DS:ABS0
LDS SI,DISK_POINTER ; POINT TO BLOCK
SHR BX,1 ; DIVIDE BX BY 2, AND SET FLAG FOR EXIT
MOV AH,[SI+BX] ; GET THE WORD
POP DS ; RESTORE SEGMENT
ASSUME DS:DATA
JC NEC_OUTPUT ; IF FLAG SET, OUTPUT TO CONTROLLER
RET ; RETURN TO CALLER
GET_PARM ENDP
;--------------------------------------------
; SEEK
; THIS ROUTINE WILL MOVE THE HEAD ON THE NAMED DRIVE
; TO THE NAMED TRACK. IF THE DRIVE HAS NOT BEEN ACCESSED
; SINCE THE DRIVE RESET COMMAND WAS ISSUED, THE DRIVE WILL BE
; RECALIBRATED.
; INPUT
; (DL) = DRIVE TO SEEK ON
; (CH) = TRACK TO SEEK TO
; OUTPUT
; CY = 0 SUCCESS
; CY = 1 FAILURE -- DISKETTE_STATUS SET ACCORDINGLY
; (AX) DESTROYED
;--------------------------------------------
SEEK PROC NEAR
MOV AL,1 ; ESTABLISH MASK FOR RECAL TEST
PUSH CX ; SAVE INPUT VALUES
MOV CL,DL ; GET DRIVE VALUE INTO CL
ROL AL,CL ; SHIFT IT BY THE DRIVE VALUE
POP CX ; RECOVER TRACK VALUE
TEST AL,SEEK_STATUS ; TEST FOR RECAL REQUIRED
JNZ J28 ; NO_RECAL
OR SEEK_STATUS,AL ; TURN ON THE NO RECAL BIT IN FLAG
MOV AH,07H ; RECALIBRATE COMMAND
CALL NEC_OUTPUT
MOV AH,DL
CALL NEC_OUTPUT ; OUTPUT THE DRIVE NUMBER
CALL CHK_STAT_2 ; GET THE INTEPUPT AN SENSE INT STATUS
JC J32 ; SEEK_ERROR
;----- DRIVE IS IN SYNCH WITH CONTROLLER, SEEK TO TRACK
J28:
MOV AH,0FH ; SEEK COMMAND TO NEC
CALL NEC_OUTPUT
MOV AH,DL ; DRIVE NUMBER
CALL NEC_OUTPUT
MOV AH,CH ; TRACK NUMBER
CALL NEC_OUTPUT
CALL CHK_STAT_2 ; GET ENDING INTERRUPT AND SENSE STATUS
;----- WAIT FOR HEAD SETTLE
PUSHF ; SAVE STATE FLAGS
MOV BX,18 ; GET HEAD SETTLE PARAMETER
CALL GET_PARM
PUSH CX ; SAVE REGISTER
J29: ; HEAD_SETTLE
MOV CX,550 ; 1 MS LOOP
OR AH,AH ; TEST FOR TIME EXPIRED
JZ J31
J30: LOOP J30 ; DELAY FOR 1 MS
DEC AH ; DECREMENT THE COUNT
JMP J29 ; DO IT SOME MORE
J31:
POP CX ; RECOVER STATE
POPF
J32: ; SEEK ERROR
RET ; RETURN TO CALLER
SEEK ENDP
;--------------------------------------------
; DMA_SETUP
; THIS ROUTINE SETS UP THE DMA FOR READ/WRITE/VERIFY
; OPERATIONS.
; INPUT
; (AL) = MODE BYTE FOR THE DMA
; (ES:BX) = ADDRESS TO READ/WRITE THE DATA
; OUTPUT
; (AX) DESTROYED
;--------------------------------------------
DMA_SETUP PROC NEAR
PUSH CX ; SAVE THE REGISTER
OUT DMA+12,AL ; SET THE FIRST/LAST F/F
OUT DMA+11,AL ; OUTPUT THE MODE BYTE
MOV AX,ES ; GET THE ES VALUE
MOV CL,4 ; SHIFT COUNT
ROL AX,CL ; ROTATE LEFT
MOV CH,AL ; GET HIGHEST NYBLE OF ES TO CH
AND AL,0F0H ; ZERO THE LOW NYBBLE FROM SEGMENT
ADD AX,BX ; TEST FOR CARRY FROM ADDITION
JNC J33
INC CH ; CARRY MEANS HIGH 4 BITS MUST BE INC
J33:
PUSH AX ; SAVE START ADDRESS
OUT DMA+4,AL ; OUTPUT LOW ADDRESS
MOV AL,AH
OUT DMA+4,AL ; OUTPUT HIGH ADDRESS
MOV AL,CH ; GET HIGH 4 BITS
AND AL,0FH
OUT 081H,AL ; OUTPUT THE HIGH 4 BITS TO PAGE REGISTER
;------ DETERMINE COUNT
MOV AH,DH ; NUMBER OF SECTORS
SUB AL,AL ; TIMES 256 INTO AX
SHR AX,1 ; SECTORS * 128 INTO AX
PUSH AX
MOV BX,6 ; GET THE BYTES/SECTOR PARM
CALL GET_PARM
MOV CL,AH ; USE AS SHIFT COUNT(0=128,1=256 ETC)
POP AX
SHL AX,CL ; MULTIPLY BY CORRECT AMOUNT
DEC AX ; -1 FOR DMA VALUE
PUSH AX ; SAVE COUNT VALUE
OUT DMA+5,AL ; LOW BYTE OF COUNT
MOV AL,AH
OUT DMA+5,AL ; HIGH BYTE OF COUNT
POP CX ; RECOVER COUNT VAWE
POP AX ; RECOVER ADDRESS VALUE
ADD AX,CX ; ADD, TEST FOR 64K OVERFLOW
POP CX ; RECOVER REGISTER
MOV AL,2 ; MODE FOR 8237
OUT DMA+10,AL ; INIITIALIZE THE DISKETTE CHANNEL
RET ; RETURN TO CALLER, CFL SET BY ABOVE IF ERROR
DMA_SETUP ENDP
;---------------------------------------------
; CHK_STAT_2
; THIS ROUTIINE HANDLES THE INTERRUPT RECEIVED AFTER
; A RECALIBRATE, SEEK, OR RESET TO THE ADAPTER.
; THE INTERRUPT IS WAITED FOR, THE INTERRUPT STATUS SENSED,
; AND THE RESULT RETURNED TO THE CALLER.
; INPUT
; NONE
; OUT~T
; CY = 0 SUCCESS
; CY = 1 FAILURE -- ERROR IS IN DISKETTE_STAUS
; (AX) DESTROYED
;
CHK_STAT_2 PROC NEAR
CALL WAIT_INT ; WAIT FOR THE INTERRUPT
JC J34 ; IF ERROR, RETURN IT
MOV AH,08H ; SENSE INTERRUPT STATUS COMMAND
CALL NEC_OUTPUT
CALL RESULTS ; READ IN THE RESULTS
JC J34 ; CHK2_RETURN
MOV AL,NEC_STATUS ; GET THE FIRST STATUS BYTE
AND AL,060H ; ISOLATE THE BITS
CMP AL,060H ; TEST FOR CORRECT VALUE
JZ J35 ; IF ERROR, GO MARK IT
CLC ; GOOD RETURN
J34:
RET ; RETURN TO CALLER
J35: ; CHK2_ERROR
OR DISKETTE_STATUS,BAD_SEEK
STC ; ERROR RETURN CODE
RET
CHK_STAT_2 ENDP
;------------------------------------------
; WAIT_INT
; THIS ROUTINE WAITS FOR AN INTERRUPT TO OCCUR
; A TIME OUT ROUTINE TAKES PLACE DURING THE WAIT, SO
; THAT AN ERROR MAY BE RETURNED IF THE DRIVE IS NOT READY
; INPUT
; NONE
; OUTPUT
; CY = 0 SUCCESS
; CY = 1 FAILURE -- DISKETTE_STATUS IS SET ACCORDINGLY
; (AX) DESTROYED
;------------------------------------------
WAIT_INT PROC NEAR
STI ; TURN ON INTERRUPTS, JUST IN CASE
PUSH BX
PUSH CX ; SAYE REGISTERS
MOV BL,2 ; CLEAR THE COUNTERS
XOR CX,CX ; FOR 2 SECOND WAIT
J36:
TEST SEEK_STATUS,INT_FLAG ; TEST FOR INTERRUPT OCCURRING
JNZ J37
LOOP J36 ; COUNT DOWN WHILE WAITING
DEC BL ; SECOND LEVEL COUNTER
JNZ J36
OR DISKETTE_STATUS,TIME_OUT ; NOTHING HAPPENED
STC ; ERROR RETURN
J37:
PUSHF ; SAVE CURRENT CARRY
AND SEEK_STATUS,NOT INT_FLAG ; TURN OFF INTERRUPT FLAG
POPF ; RECOVER CARRY
POP CX
POP BX ; RECOVER REGISTERS
RET ; GOOD RETURN CODE COMES FROM TEST INST
WAIT_INT ENDP
;-------------------------------------------
; DISK_INT
; THIS ROUTINE HANDLES THE DISKETTE INTERRUPT
; INPUT
; NONE
; OUTPUT
; THE INTERRUPT FLAG IS SET IS SEEK_STATUS
;--------------------------------------------
DISK_INT PROC FAR
STI ; RE ENABLE INTERRUPTS
PUSH DS
PUSH AX
MOV AX,DATA
MOV DS,AX
OR SEEK_STATUS,INT_FLAG
MOV AL,20H ; END OF INTERRUPT MARKER
OUT 20H,AL ; INTERRUPT CONTROL PORT
POP AX
POP DS ; RECOVER SYSTEM
IRET ; RETURN FROM INTERRUPT
DISK_INT ENDP
;---------------------------------------------
; RESULTS
; THIS ROUTINE WILL READ ANYTHING THAT THE NEC CONTROLLER
; HAS TO SAY FOLLOWING AN INTEPRUPT.
; INPUT
; NONE
; OUTPUT
; CY = 0 SUCCESSFUL TRANSFER
; CY = 1 FAILURE -- TIME OUT IN WAITING FOR STATUS
; NEC_STATUS AREA HAS STATUS BYTE LOADED INTO IT
; (AH) DESTROYED
;--------------------------------------------
RESULTS PROC NEAR
CLD
MOV DI,OFFSET NEC_STATUS ; POINTER TO DATA AREA
PUSH CX ; SAVE COUNTER
PUSH DX
PUSH BX
MOV BL,7 ; MAX STATUS BYTES
;------ WAIT FOR REQUEST FOR MASTER
J38: ; INPUT_LOOP
XOR CX,CX ; COUNTER
MOV DX,03F4H ; STATUS PORT
J39: ; WAIT FOR MASTER
IN AL,DX ; GET STATUS
TEST AL,080H ; MASTER READY
JNZ J40A ; TEST_DIR
LOOP J39 ; WAIT MASTER
OR DISKETTE_STATUS,TIME_OUT
J40: ; RESULTS_ERROR
STC ; SET ERROR RETURN
POP BX
POP DX
POP CX
RET
;------ TEST THE DIRECTION BIT
J40A: IN AL,DX ; GET STATUS REG AGAIN
TEST AL,040H ; TEST DIRECTION BIT
JNZ J42 ; OK TO READ STATUS
J41: ; NEC_FAIL
OR DISKETTE_STATUS,BAD_NEC
JMP J40 ; RESULTS ERROR
;------ READ IN THE STATUS
J42: ; INPUT STATUS
INC DX ; POINT AT DATA PORT
IN AL,DX ; GET THE DATA
MOV [DI],AL ; STORE THE BYTE
INC DI ; INCREMENT THE POINTER
MOV CX,10 ; LOOP TO KILL TIME FOR NEC
J43:
LOOP J43
DEC DX ; POINT AT STATUS PORT
IN AL,DX ; GET STATUS
TEST AL,010H ; TEST FOR NEC STILL BUSY
JZ J44 ; RESULTS DONE
DEC BL ; DECREMENT THE STATUS COUNTER
JNZ J38 ; GO BACK FOR MORE
JMP J41 ; CHIP HAS FAILED
;------ RESULT OPERATION IS DONE
J44:
POP BX
POP DX
POP CX ; RECOVER REGISTERS
RET ; GOOD RETURN CODE FROM TEST INST
;--------------------------------------------
; NUM_TRANS
; THIS ROUTINE CALCULATES THE NUMBER OF SECTORS THAT
; WERE ACTUALLY TRANSFERRED TO/FROM THE DISKETTE
; INPUT
; (CH) = CYLINDER OF OPERATION
; (CL) = START SECTOR OF OPERATION
; OUTPUT
; (AL) = NUMBER ACTUALLY TRANSFERRED
; N0 OTHER REGISTERS MODIFIED
;-------------------------------------------
NUM_TRANS PROC NEAR
MOV AL,NEC_STATUS+3 ; GET CYLINDER ENDED UP ON
CMP AL,CH ; SAME AS THE STARTED
MOV AL,NEC_STATUS+5 ; GET ENDING SECTOR
JZ J45 ; IF ON SAME CYL, THEN NO ADJUST
MOV BX,8
CALL GET_PARM ; GET EOT VALUE
MOV AL,AH ; INTO AL
INC AL ; USE EOT+1 FOR CALCULATION
J45: SUB AL,CL ; SUBTRACT START FROM END
RET
NUM_TRANS ENDP
RESULTS ENDP
;-------------------------------------------
; DISK_BASE
; THIS IS THE SET OF PARAMETERS REQUIRED FOR
; DISKETTE OPERATION, THEY ARE POINTED AT BY THE
; DATA VARIABLE DISK_POINTER. TO MODIFY THE PARAMETERS,
; BUILD ANOTHER PARAMETER BLOCK AND POINT AT IT
;-------------------------------------------
DISK_BASE LABEL BYTE
DB 11001111B ; SRT=C, HD UNLOAD=0F - 1ST SPECIFY BYTE
DB 2 ; HD LOAD=1, MODE=DMA - 2ND SPECIFY BYTE
DB MOTOR_WAIT ; WAIT AFTER OPN TIL MOTOR OFF
DB 2 ; 512 BYTES/SECTOR
DB 8 ; EOT (LAST SECTOR ON TRACK)
DB 02AH ; GAP LENGTH
DB 0FFH ; DTL
DB 050H ; GAP LENGTH FOR FORMAT
DB 0F6H ; FILL BYTE FOR FORMAT
DB 25 ; HEAD SETTLE TIME (MILLISECONDS)
DB 4 ; MOTOR START TIME (1/8 SECONDS)
;--- INT 17 ---------------------------------
; PRINTER_IO
; THIS ROUTINE PROVIDES COMMUNICATI0N WITH THE PRINTER
; (AH)=0 PRINT THE CHARACTER IN (AL)
; ON RETURN, AH=1 IF CHARACTER COULD NOT BE PRINTED (TIME OUT)
; OTHER BITS SET AS ON NORMAL STATUS CALL
; (AH)=1 INITIALIZE THE PRINTER PORT
; RETURNS WITH (AH) SET WITH PRINTER STATUS
; (AH)=2 READ THE PRINTER STATUS INTO (AH)
; 7 6 5 4 3 2-1 0
; | | | | | | _TIME OUT
; | | | | | _UNUSED
; | | | | _1 = I/O ERROR
; | | | _1 = SELECTED
; | | _1 = OUT OF PAPER
; | _1 = ACKNOWLEDGE
; _1 = BUSY
;
; (DX) = PRINTER TO BE USED (0, 1, 2) CORRESPONDING TO ACTUAL VALUES
; IN PRINTER_BASE AREA
; DATA AREA PRINTER BASE CONTAINS THE BASE ADDRESS OF THE PRINTER CARD(S)
; AVAILABLE (LOCATED AT BEGINNING OF DATA SEGMENT, 408H ABSOLUTE, 3 WORDS)
;REGISTERS AH IS MODIFIED
; ALL OTHERS UNCHANGED
;--------------------------------------------
ASSUME CS:CODE,DS:DATA
PRINTER_IO PROC FAR
STI ; INTERRUPTS BACK
PUSH DS ; SAVE SEGMENT
PUSH DX
PUSH SI
PUSH CX
PUSH BX
MOV SI,DATA
MOV DS,SI ; ESTABLISH PRINTER SEGMENT
MOV SI,DX ; GET PRINTER PARM
SHL SI,1 ; WORD OFFSET INTO TABLE
MOV DX,PRINTER_BASE[SI] ; GET BASE ADDRESS FOR PRINTER CARD
OR DX,DX ; TEST DX FOR ZERO, INDICATING NO PRINTER
JZ B1 ; RETURN
OR AH,AH ; TEST FOR (AH)=0
JZ B2 ; PRINT_AL
DEC AH ; TEST FOR (AH)=1
JZ B8 ; INIT_PRT
DEC AH ; TEST FOR (AH)=2
JZ B5 ; PRINTER STATUS
B1: ; RETURN
POP BX
POP CX
POP SI ; RECOVER REGISTERS
POP DX ; RECOVER REGISTERS
POP DS
IRET
;------ PRINT THE CHARACTER IN (AL)
B2 :
PUSH AX ; SAVE VALUE TO PRINT
MOV BL,10 ; TIME OUT VALUE
XOR CX,CX ; ESTABLISH SHIFT COUNT
OUT DX,AL ; OUTPUT CHAR TO PORT
INC DX ; POINT TO STATUS PORT
B3: ; WAIT_BUSY
IN AL,DX ; GET STATUS
MOV AH,AL ; STATUS TO AH ALSO
TEST AL,80H ; IS THE PRINTER CURRENTLY BUSY
JNZ B4 ; OUT_STROBE
LOOP B3 ; DECREMENT COUNT ON TIME OUT
DEC BL
JNZ B3 ; WAIT FOR NOT BUSY
OR AH,1 ; SET ERROR FLAG
AND AH,0F9H ; TURN OFF THE OTHER BITS
JMP SHORT B7 ; RETURN WITH ERROR FLAG SET
B4: ; OUT_STROBE
MOV AL,0DH ; SET THE STROBE HIGH
INC DX ; STROBE IS BIT 0 OF PORT C OF 8255
OUT DX,AL
MOV AL,0CH ; SET THE STROBE LOW
OUT DX,AL
POP AX ; RECOVER THE OUTPUT CHAR
;------ PRINTER STATUS
B5:
PUSH AX ; SAVE AL REG
B6:
MOV DX,PRINTER_BASE[SI]
INC DX
IN AL,DX ; GET PRINTER STATUS
MOV AH,AL
AND AH,0F8H ; TURN OFF USED BITS
B7: ; STATUS_SET
POP DX ; RECOVER AL REG
MOV AL,DL ; GET CHARACTER INTO AL
XOR AH,48H ; FLIP A COUPLE OF BITS
JMP B1 ; RETURN FROM ROUTINE
;------ INITIALIZE THE PRINTER PORT
B8:
PUSH AX ; SAVE AL
ADD DX,2 ; POINT TO OUTPUT PORT
MOV AL,8 ; SET INIT LINE LOW
OUT DX,AL
MOV AX,1000
B9: ; INIT_LOOP
DEC AX ; LOOP FOR RESET TO TAKE
JNZ B9 ; INIT_LOOP
MOV AL,0CH ; NO INTERRUPTS, NON AUTO LF, INIT HIGH
OUT DX,AL
JMP B6 ; PRT_STATUS_1
PRINTER_IO ENDP
;--- INT 10 ---------------------------------
; VIDEO_IO
; THESE ROUTINES PROVIDE THE CRT INTERFACE
; THE FOLLOWING FUNCTIONS ARE PROVIDED:
; (AH)=0 SET MODE (AL) CONTAINS MODE VALUE
; (AL)=0 40X25 BW (POWER ON DEFAULT)
; (AL)=1 40X25 COLOR
; (AL)=2 80X25 BW
; (AL)=3 80X25 COLOR
; GRAPHICS MODES
; (AL)=4 320X200 COLOR
; (AL)=5 320X200 BW
; (AL)=6 640X200 BW
; CRT MODE = 7 80X25 B&W CARD (USED INTERNAL TO VIDEO ONLY)
; *** NOTE BW MODES OPERATE SAME AS COLOR MODES, BUT COLOR
; BURST IS NOT ENABLED
; (AH)=1 SET CURSOR TYPE
; (CH) = BITS 4-0 = START LINE FOR CURSOR
; ** HARDWARE WILL ALWAYS CAUSE BLINK
; ** SETTING BIT 5 OR 6 WILL CAUSE ERRATIC BLINKING
; OR NO CURSOR AT ALL
; (CL) = BITS 4-0 = END LINE FOR CURSOR
; (AH)=2 SET CURSOR POSITION
; (DH,DL) = ROW,COLUMN (0,0) IS UPPER LEFT
; (DH) = PAGE NUMBER (MUST BE 0 FOR GRAPHICS MODES)
; (AH)=3 READ CURSOR POSITION
; (BH) = PAGE NUMBER (MUST BE 0 FOR GRAPHICS MODES)
; ON EXIT (DH,DL) = ROW,COLUMN OF CURRENT CURSOR
; (CH,CL) = CURSOR MODE CURRENTLY SET
; (AH)=4 READ LIGHT PEN POSITION
; ON EXIT:
; (AH) = 0 -- LIGHT PEN SWITCH NOT DOWN/NOT TRIGGERED
; (AH) = 1 -- VALID LIGHT PEN VALUE IN REGISTERS
; (DH,DL) = ROW, COLUMN OF CHARACTER LP POSN
; (CH) = RASTER LINE (0-199)
; (BX) = PIXEL COLUMN (0-319,639)
; (AH)=5 SELECT ACTIVE DISPLAY PAGE (VALID ONLY FOR ALPHA MODES)
; (AL)=NEW PAGE VALUE (0-7 FOR MODES 0&1, 0-3 FOR MODES 2&3)
; (AH)=6 SCROLL ACTIVE PAGE UP
; (AL) = NUMBER OF LINES, INPUT LINES BLANKED AT BOTTOM OF WINDOW
; AL = 0 MEANS BLANK ENTIRE WINDOW
; (CH,CL) = ROW,COLUMN OF UPPER LEFT CORNER OF SCROLL
; (DH,DL) = ROW,COLUMN OF LOWER RIGHT CORNER OF SCROLL
; (BH) = ATTRIBUTE TO BE USED ON BLANK LINE
; (AH)=7 SCROLL ACTIVE PAGE DOWN
; (AL) = NUMBER OF LINES, INPUT LINES BLANKED AT TOP OF WINDOW
; AL = 0 MEANS BLANK ENTIRE WINDOW
; (CH,CL) = ROW,COLUMN OF UPPER LEFT CORNER OF SCROLL
; (DH,DL) = ROW,COLUMN OF LOWER RIGHT CORNER OF SCROLL
; (BH) = ATTRIBUTE TO BE USED ON BLANK LINE
;
; CHARACTER HANDLING ROUTINES
;
; (AH) = 8 READ ATTRIBUTE/CHARACTER AT CURRENT CURSOR POSITION
; (BH) = DISPLAY PAGE (VALID FCR ALPHA MODES ONLY)
; ON EXIT:
; (AL) = CHAR READ
; (AH) = ATTRIBUTE OF CHARACTER READ (ALPHA MODES ONLY)
; (AH) = 9 WRITE ATTRIBUTE/CHARACTER AT CURRENT CURSOR POSITION
; (BH) = DISPLAY PAGE (VALID FOR ALPHA MODES ONLY)
; (CX) = COUNT OF CHARACTERS TO WRITE
; (AL) = CHAR TO WRITE
; (BL) = ATTRIBUTE OF CHARACTER (ALPHA)/COLOR OF CHAR (GRAPHICS)
; SEE NOTE ON WRITE DOT FOR BIT 7 OF BL = 1.
; (AH) = 10 WRITE CHARACTER ONLY AT CURRENT CURSOR POSITION
; (BH) = DISPLAY PAGE (VALID FOR ALPHA MODES ONLY)
; (CX) = COUNT OF CHARACTERS TO WRITE
; (AL) = CHAR TO WRITE
; FOR READ/WRITE CHARACTER INTERFACE WHILE IN GRAPHICS MODE, THE
; CHARACTERS ARE FORMED FROM A CHARACTER GENERATOR IMAGE
; MAINTAINED IN THE SYSTEM ROM. ONLY THE 1ST 128 CHARS
; ARE CONTAINED THERE. TO READ/WRITE THE SECOND 128 CHARS.
; THE USER MUST INITIALIZE THE POINTER AT INTERRUPT 1FH
; (LOCATION 0007CH) TO POINT TO THE 1K BYTE TABLE CONTAINING
; THE CODE POINTS FOR THE SECOND 128 CHARS (128-255).
; FOR WRITE CHARACTER INTERFACE IN GRAPHICS MODE, THE REPLICATION FACTOR
; CONTAINED IN (CX) ON ENTRY WILL PRODUCE VALID RESULTS ONLY
; FOR CHARACTERS CONTAINED ON THE SAME ROW. CONTINUATION TO
; SUCCEEDING LINES WILL NOT PRODUCE CORRECTLY.
;
; GRAPHICS INTERFACE
; (AH) = 11 SET COLOR PALETTE
; (DH) = PALLETTE COLOR ID BEING SET (0-127)
; (BL) = COLOR VALUE TO BE USED WITH THAT COLOR ID
; NOTE: FOR THE CURRENT COLOR CARD, THIS ENTRY POINT HAS
; MEANING ONLY FOR 320X200 GRAPHICS.
; COLOR ID = 0 SELECTS THE BACKGROUND COLOR (0-15)
; COLOR ID = 1 SELECTS THE PALLETTE TO BE USED:
; 0 = GREEN(1)/RED(2)/YELLOW(3)
; 1 = CYAN(1)/MAGENTA(2)/WHITE(3)
; IN 40X25 OR 80X25 ALPHA MODES, THE VALUE SET FOR
; PALLETTE COLOR 0 INDICATES THE BORDER COLOR
; TO BE USED (VALUES 0-31, WHERE 16-31 SELECT THE
; HIGH INTENSITY BACKGROUND SET.
; (AH) = 12 WRITE DOT
; (DX) = ROW NUMBER
; (CX) = COLUMN NUMBER
; (AL) = COLOR VALUE
; IF BIT 7 OF AL = 1, THEN THE COLOR VALUE IS EXCLUSIVE
; OR'D WITH THE CURRENT CONTENTS OF THE DOT
; (AH) = 13 READ DOT
; (DX) = ROW NUMBER
; (CX) = COLUMN NUMBER
; (AL) RETURNS THE DOT READ
;
; ASCII TELETYPE ROUTINE FOR OUTPUT
;
; (AH) = 14 WRITE TELETYPE
; (AL) = CHAR TO WRITE
; (BL) = FOREGROUND COLOR IN GRAPHICS MODE
; (BH) = DISPLAY PAGE IN ALPHA MODE
; NOTE -- SCREEN WIDTH IS CONTROLLED BY PREVIOUS MODE SET
;
; (AH) = 15 CURRENT VIDEO STATE
; RETURNS THE CURRENT VIDEO STATE
; (AL) = MODE CURRENTLY SET (SEE AH=0 FOR EXPLANATION)
; (AH) = NUMBER OF CHARACTER COLUMNS 0N SCREEN
; (BH) = CURRENT ACTIVE DISPLAY PAGE
;
; CS,SS,DS,ES,BX,CX,DX PRESERVED DURING CALL
; ALL OTHERS DESTROYED
;--------------------------------------------
ASSUME CS:CODE,DS:DATA,ES:VIDEO_RAM
M1 LABEL WORD ; TABLE OF ROUTINES WITHIN VIDEO I/O
DW OFFSET SET_MODE
DW OFFSET SET_CTYPE
DW OFFSET SET_CPOS
DW OFFSET READ_CURSOR
DW OFFSET READ_LPEN
DW OFFSET ACT_DISP_PAGE
DW OFFSET SCROLL_UP
DW OFFSET SCROLL_DOWN
DW OFFSET READ_AC_CURRENT
DW OFFSET WRITE_AC_CURRENT
DW OFFSET WRITE_C_CURRENT
DW OFFSET SET_COLOR
DW OFFSET WRITE_DOT
DW OFFSET READ_DOT
DW OFFSET WRITE_TTY
DW OFFSET VIDEO_STATE
M1L EQU $-M1
VIDEO_IO PROC NEAR
STI ; INTERRUPTS BACK ON
CLD ; SET DIRECTION FORWARD
PUSH ES
PUSH DS ; SAVE SEGMENT REGISTERS
PUSH DX
PUSH CX
PUSH BX
PUSH SI
PUSH DI
PUSH AX ; SAVE AX VALUE
MOV AL,AH ; GET INTO LOW BYTE
XOR AH,AH ; ZERO TO HIGH BYTE
SAL AX,1 ; *2 FOR TABLE LOOKUP
MOV SI,AX ; PUT INTO SI FOR BRANCH
CMP AX,M1L ; TEST FOR WITHIN RANGE
JB M2 ; BRANCH AROUND BRANCH
POP AX ; THROW AWAY THE PARAMETER
JMP VIDEO_RETURN ; DO NOTHING IF NOT IN RANGE
M2: MOV AX,DATA
MOV DS,AX
MOV AX,0B800H ; SEGMENT FOR COLOR CARD
MOV DI,EQUIP_FLAG ; GET EQUIPMENT SETTING
AND DI,30H ; ISOLATE CRT SWITCHES
CMP DI,30H ; IS SETTING FOR BW CARD?
JNE M3
MOV AX,0B000H ; SEGMENT FOR BW CARD
M3: MOV ES,AX ; SET UP TO POINT AT VIDEO RAM AREAS
POP AX ; RECOVER VALUE
MOV AH,CRT_MODE ; GET CURRENT MODE INTO AH
JMP WORD PTR CS:[SI+OFFSET M1]
VIDEO_IO ENDP
;------------------------------------------
; SET_MODE
; THIS ROUTINE INITIALIZES THE ATTACHMENT TO
; THE SELECTED MODE. THE SCREEN IS BLANKED.
; INPUT
; (AL) = MODE SELECTED (RANGE 0-9)
; OUTPUT
; NONE
;------------------------------------------
;------ TABLES FOR USE IN SETTING OF MODE
VIDEO_PARMS LABEL BYTE
;------ INIT_TABLE
DB 38H,28H,2DH,0AH,1FH,6,19H ; SET UP FOR 40X25
DB 1CH,2,7,6,7
DB 0,0,0,0
M4 EQU $-VIDEO_PARMS
DB 71H,50H,5AH,0AH,1FH,6,19H ; SET UP FOR 80X25
DB 1CH,2,7,6,7
DB 0,0,0,0
DB 38H,28H,2DH,0AH,7FH,6,64H ; SET UP FOR GRAPHICS
DB 70H,2,1,6,7
DB 0,0,0,0
DB 61H,50H,52H,0FH,19H,6,19H ; SET UP FOR 80X25 B&W CARD
DB 19H,2,0DH,0BH,0CH
DB 0,0,0,0
M5 LABEL WORD ; TABLE OF REGEN LENGTHS
DW 2048 ; 40X25
DW 4096 ; 80X25
DW 16384 ; GRAPHICS
DW 16384 ;
;------ COLUMNS
M6 LABEL BYTE
DB 40,40,80,80,40,40,80,80 ;column offsets
;------ C_REG_TAB
M7 LABEL BYTE ; TABLE OF MODE SETS
DB 2CH,28H,2DH,29H,2AH,2EH,1EH,29H ; 8 different CRT modes
SET_MODE PROC NEAR
MOV DX,03D4H ; ADDRESS OF COLOR CARD
MOV BL,0 ; MODE SET FOR COLOR CARD
CMP DI,30H ; IS BW CARD INSTALLED
JNE M8 ; OK WITH COLOR
MOV AL,7 ; INDICATE BW CARD MODE
MOV DX,03B4H ; ADDRESS OF BW CARD
INC BL ; MODE SET FOR BW CARD
M8: MOV AH,AL ; SAVE MODE IN AH
MOV CRT_MODE,AL ; SAVE IN GLOBAL VARIABLE
MOV ADDR_6845,DX ; SAVE ADDRESS OF BASE
PUSH DS ; SAVE POINTER TO DATA SEGMENT
PUSH AX ; SAVE MODE
PUSH DX ; SAVE OUTPUT PORT VALUE
ADD DX,4 ; POINT TO CONTROL REGISTER
MOV AL,BL ; GET MODE SET FOR CARD
OUT DX,AL ; RESET VIDEO
POP DX ; BACK TO BASE REGISTER
SUB AX,AX ; SET UP FOR ABS0 SEGMENT
MOV DS,AX ; ESTABLISH VECTOR TABLE ADDRESSING
ASSUME DS:ABS0
LDS BX,PARM_PTR ; GET POINTER TO VIDEO PARMS
POP AX ; RECOVER PARMS
ASSUME DS:CODE
MOV CX,M4 ; LENGTH OF EACH ROW OF TABLE
CMP AH,2 ; DETERMINE WHICH ONE TO USE
JC M9 ; MODE IS 0 OR 1
ADD BX,CX ; MOVE TO NEXT ROW OF INIT_TABLE
CMP AH,4
JC M9 ; MODE IS 2 OR 3
ADD BX,CX ; MOVE TO GRAPHICS ROW OF INIT_TABLE
CMP AH,7
JC M9 ; MODE IS 4, 5, OR 6
ADD BX,CX ; MOVE TO BW CARD ROW OF INIT_TABLE
;------ BX POINTS TO CORRECT ROW OF INITIALIZATION TABLE
M9: ; OUT_INIT
PUSH AX ; SAVE MODE IN AH
XOR AH,AH ; AH WILL SERVE AS REGISTER NUMBER DURING LOOP
;------ LOOP THROUGH TABLE, OUTPUTTING REG ADDRESS, THEN VALUE FROM TABLE
M10: ; INIT LOOP
MOV AL,AH ; GET 6845 REGISTER NUMBER
OUT DX,AL
INC DX ; POINT TO DATA PORT
INC AH ; NEXT REGISTER VALUE
MOV AL,[BX] ; GET TABLE VALUE
OUT DX,AL ; OUT TO CHIP
INC BX ; NEXT IN TABLE
DEC DX ; BACK TO POINTER REGISTER
LOOP M10 ; DO THE WHOLE TABLE
POP AX ; GET MODE BACK
POP DS ; RECOVER SEGMENT VALUE
ASSUME DS:DATA
;------ FILL REGEN AREA WITH BLANK
XOR DI,DI ; SET UP POINTER FOR REGEN
MOV CRT_START,DI ; START ADDRESS SAVED IN GLOBAL
MOV ACTIVE_PAGE,0 ; SET PAGE VALUE
MOV CX,8192 ; NIMBER OF WORDS IN COLOR CARD
CMP AH,4 ; TEST FOR GRAPHICS
JC M12 ; NO_GRAPHICS_INIT
CMP AH,7 ; TEST FOR BW CARD
JE M11 ; BW_CARD_INIT
XOR AX,AX ; FILL FOR GRAPHICS MODE
JMP SHORT M13 ; CLEAR_BUFFER
M11: ; BW_CARD_INIT
MOV CX,2048 ; BUFFER SIZE ON BW CARD
M12: ; NO_GRAPHICS_INIT
MOV AX,' '+7*256 ; FILL CHAR FOR ALPHA
M13: ; CLEAR BUFFER
REP STOSW ; FILL THE REGEN BUFFER WITH BLANKS
;------ ENABLE VIDEO AND CORRECT PORT SETTING
MOV CURSOR_MODE,67H ; SET CURRENT CURSOR MODE
MOV AL,CRT_MODE ; GET THE MODE
XOR AH,AH ; INTO AX REGISTER
MOV SI,AX ; TABLE POINTER, INDEXED BY {CRT} MODE
MOV DX,ADDR_6845 ; PREPARE TO OUTPUT TO VIDEO ENABLE PORT
ADD DX,4
MOV AX,CS:[SI+OFFSET M7] ; {was MOV AL...}
OUT DX,AL ; SET VIDEO ENABLE PORT
MOV CRT_MODE_SET,AL ; SAVE THAT VALUE
;------ DETERMINE NUMBER OF COLUMNS, BOTH FOR ENTIRE DISPLAY
;------ AND THE NUMBER TO BE USED FOR TTY INTERFACE
MOV AX,CS:[SI+OFFSET M6] ;{was MOV AL...}
XOR AH,AH
MOV CRT_COLS,AX ; NUMBER OF COLUMNS IN THIS SCREEN
;------ SET CURSOR POSITIONS
AND SI,0EH ; WORD OFFSET INTO CLEAR LENGTH TABLE
MOV CX,CS:[SI+OFFSET M5] ; LENGTH TO CLEAR
MOV CRT_LEN,CX ; SAVE LENGTH OF CRT -- NOT USED FOR BW
MOV CX,8 ; CLEAR ALL CURSOR POSITIONS
MOV DI,OFFSET CURSOR_POSN
PUSH DS ; ESTABLISH SEGMENT
POP ES ; ADDRESSING
XOR AX,AX
REP STOSW ; FILL WITH ZEROES
;------ SET UP OVERSCAN REGISTER
INC DX ; SET OVERSCAN PORT TO A DEFAULT
MOV AL,30H ; VALUE OF 30H FOR ALL MODES EXCEPT 640X200
CMP CRT_MODE,6 ; SEE IF THE MODE IS 640X200 BW
JNZ M14 ; IF IT ISNT 640X200, THEN GOTO REGULAR
MOV AL,3FH ; IF IT IS 640X200, THEN PUT IN 3FH
M14: OUT DX,AL ; OUTPUT THE CORRECT VALUE TO 3D9 PORT
MOV CRT_PALLETTE,AL ; SAVE THE VALUE FOR FUTURE USE
;------ NORMAL RETURN FROM ALL VIDEO RETURNS
VIDEO_RETURN:
POP DI
POP SI
POP BX
M15: ; VIDEO_RETURN_C
POP CX
POP DX
POP DS
POP ES ; RECOVER SEGMENTS
IRET ; ALL DONE
SET_MODE ENDP
;--------------------------------------------
; SET_CTYPE
; THIS ROUTINE SETS THE CURSOR VALUE
; INPUT
; (CX) HAS CURSOR VALUE CH-START LINE, CL-STOP LINE
; OUTPUT
; NONE
;--------------------------------------------
SET_CTYPE PROC NEAR
MOV AH,10 ; 6845 REGISTER FOR CURSOR SET
MOV CURSOR_MODE,CX ; SAVE IN DATA AREA
CALL M16 ; OUTPUT CX REG
JMP VIDEO_RETURN
;------ THIS ROUTINE OUTPUTS THE CX REGISTER TO THE 6845 REGS NAMED IN AH
M16:
MOV DX,ADDR_6845 ; ADDRESS REGISTER
MOV AL,AH ; GET VALUE
OUT DX,AL ; REGISTER SET
INC DX ; DATA REGISTER
MOV AL,CH ; DATA
OUT DX,AL
DEC DX
MOV AL,AH
INC AL ; POINT TO OTHER DATA REGISTER
OUT DX,AL ; SET FOR SECOND REGISTER
INC DX
MOV AL,CL ; SECOND DATA VALUE
OUT DX,AL
RET ; ALL DONE
SET_CTYPE ENDP
;--------------------------------------------
; SET_CPOS
; THIS ROUTINE SETS THE CURRENT CURSOR POSITION TO THE
; NEW X-Y VALUES PASSED
; INPUT
; DX - ROW, COLUMN OF NEW CURSOR
; BH - DISPLAY PAGE OF CURSOR
; OUTPUT
; CURSOR IS SET AT 6845 IF DISPLAY PAGE IS CURRENT DISPLAY
;--------------------------------------------
SET_CPOS PROC NEAR
MOV CL,BH
XOR CH,CH ; ESTABLISH LOOP COUNT
SAL CX,1 ; WORD OFFSET
MOV SI,CX ; USE INDEX REGISTER
MOV [SI+OFFSET CURSOR_POSN],DX ; SAVE THE POINTER
CMP ACTIVE_PAGE,BH
JNZ M17 ; SET_CPOS_RETURN
MOV AX,DX ; GET ROW/COLUMN TO AX
CALL M18 ; CURSOR_SET
M17: ; SET_CPOS_RETURN
JMP VIDEO_RETURN
SET_CPOS ENDP
;------ SET CURSOR POSITION, AX HAS ROW/COLUMN FOR C~SOR
M18 PROC NEAR
CALL POSITION ; DETERMINE LOCATION IN REGEN BUFFER
MOV CX,AX
ADD CX,CRT_START ; ADD IN THE START ADDRESS FOR THIS PAGE
SAR CX,1 ; DIVIDE BY 2 FOR CHAR ONLY COUNT
MOV AH,14 ; REGISTER NUMBER FOR CURSOR
CALL M16 ; OUTPUT THE VALUE TO THE 6845
RET
M18 ENDP
;--------------------------------------------
; READ_CURSOR
; THIS ROUTINE READS THE CURRENT CURSOR VALUE FROM THE
; 6845, FORMATS IT, AND SENDS IT BACK TO THE CALLER
; INPUT
; BH - PAGE OF CURSOR
; OUTPUT
; DX - ROW, COLUMN OF THE CURRENT CURSOR POSITION
; CX - CURRENT CURSOR MODE
;-------------------------------------------
READ_CURSOR PROC NEAR
MOV BL,BH
XOR BH,BH
SAL BX,1 ; WORD OFFSET
MOV DX,[BX+OFFSET CURSOR_POSN]
MOV CX,CURSOR_MODE
POP DI
POP SI
POP BX
POP AX ; DISCARD SAVED CX AND DX
POP AX
POP DS
POP ES
IRET
READ_CURSOR ENDP
;--------------------------------------------
; ACT_DISP_PAGE
; THIS ROUTINE SETS THE ACTIVE DISPLAY PAGE. ALLOWING
; THE FULL USE OF THE RAM SET ASIDE FOR THE VIDEO ATTACHMENT
; INPUT
; AL HAS THE NEW ACTIVE DISPLAY PAGE
; OUTPUT
; THE 6845 IS RESET TO DISPLAY THAT PAGE
;--------------------------------------------
ACT_DISP_PAGE PROC NEAR
MOV ACTIVE_PAGE,AL ; SAVE ACTIVE PAGE VALUE
MOV CX,CRT_LEN ; GET SAVED LENGTH OF REGEN BUFFER
CBW ; CONVERT AL TO WORD
PUSH AX ; SAVE PAGE VALUE
MUL CX ; DISPLAY PAGE TIMES REGEN LENGTH
MOV CRT_START,AX ; SAVE START ADDRESS FOR LATER REQUIREMENTS
MOV CX,AX ; START ADDRESS TO CX
SAR CX,1 ; DIVIDE BY 2 FOR 6845 HANDLING
MOV AH,12 ; 6845 REGISTER FOR START ADDRESS
CALL M16
POP BX ; RECOVER PAGE VALUE
SAL BX,1 ; *2 FOR WORD OFFSET
MOV AX,[BX+OFFSET CURSOR_POSN] ; GET CURSOR FOR THIS PAGE
CALL M18 ; SET THE CURSOR POSITION
JMP VIDEO_RETURN
ACT_DISP_PAGE ENDP
;--------------------------------------------
; SET_COLOR
; THIS ROUTINE WILL ESTABLISH THE BACKGROUND COLOR, THE OVERSCAN COLOR,
; AND THE FOREGROUND COLOR SET FOR MEDIUM RESOLUTION GRAPHICS
; INPUT
; (BH) HAS COLOR ID
; IF BH=0, THE BACKGROUND COLOR VALUE IS SET
; FROM THE LOW BITS OF BL (0-31)
; IF BH=1, THE PALLETTE SELECTION IS MADE
; BASED ON THE LOW BIT OF BL:
; 0 = GREEN, RED, YELLOW FOR COLORS 1,2,3
; 1 = BLUE, CYAN, MAGENTA FOR COLORS 1,2,3
; (BL) HAS THE COLOR VALUE TO BE USED
; OUTPUT
; THE COLOR SELECTION IS UPDATED
;--------------------------------------------
SET_COLOR PROC NEAR
MOV DX,ADDR_6845 ; I/O PORT FOR PALETTE
ADD DX,5 ; OVERSCAN PORT
MOV AL,CRT_PALLETTE ; GET THE CURRENT PALLETTE VALUE
OR BH,BH ; IS THIS COLOR 0?
JNZ M20 ; OUTPUT COLOR 1
;------ HANDLE COLOR 0 BY SETTING THE BACKGROUND COLOR
AND AL,0E0H ; TURN OFF LOW 5 BITS OF CURRENT
AND BL,01FH ; TURN OFF HIGH 3 BITS OF INPUT YALUE
OR AL,BL ; PUT VALUE INTO REGISTER
M19: ; OUTPUT THE PALLETTE
OUT DX,AL ; OUTPUT COLOR SELECTION TO 3D9 PORT
MOV CRT_PALLETTE,AL ; SAVE THE COLOR VALUE
JMP VIDEO_RETURN
;------ HANDLE COLOR 1 BY SELECTING THE PALLETTE TO BE USED
M20:
AND AL,0DFH ; TURN OFF PALLETTE SELECT BIT
SHR BL,1 ; TEST THE LOW ORDER BIT OF BL
JNC M19 ; ALREADY DONE
OR AL,20H ; TURN ON PALLETTE SELECT BIT
JMP M19 ; GO DO IT
SET_COLOR ENDP
;--------------------------------------------
;VIDEO_STATE
; RETURNS THE CURRENT VIDEO STATE IN AX
; AH = NUMBER OF COLUMNS ON THE SCREEN
; AL = CURRENT VIDEO MODE
; BH = CURRENT ACTIVE PAGE
;-------------------------------------------
VIDEO_STATE PROC NEAR
MOV AH,BYTE PTR CRT_COLS ; GET NUMBER OF COLUMNS
MOV AL,CRT_MODE ; CURRENT MODE
MOV BH,ACTIVE_PAGE ; GET CURRENT ACTIVE PAGE
POP DI ; RECOVER REGISTERS
POP SI ;
POP CX ; DISCARD SAVED BX
JMP M15 ; RETURN TO CALLER
VIDEO_STATE ENDP
;-----------------------------------
; POSITION
; THIS SERVICE ROUTINE CALCULATES THE REGEN BUFFER ADDRESS
; OF A CHARACTER IN THE ALPHA MOOE
; INPUT
; AX = ROW, COLUMN POSITION
; OUTPUT
; AX = OFFSET OF CHAR POSITION IN REGEN BUFFER
;------------------------------------
POSITION PROC NEAR
PUSH BX ; SAVE REGISTER
MOV BX,AX
MOV AL,AH ; ROWS TO AL
MUL BYTE PTR CRT_COLS ; DETERMINE BYTES TO ROW
XOR BH,BH
ADD AX,BX ; ADD IN COLUMN VALUE
SAL AX,1 ; * 2 FOR ATTRIBUTE BYTES
POP BX
RET
POSITION ENDP
;------------------------------------------
; SCROLL_UP
; THIS ROUTINE MOVES A BLOCK OF CHARACTERS UP
; ON THE SCREEN
; INPUT
; (AH) = CURRENT CRT MODE
; (AL) = NUMBER OF ROWS TO SCROLL
; (CX) = ROW/COLUMN OF UPPER LEFT CORNER
; (DX) = ROW/COLUMN OF LOWER RIGHT CORNER
; (BH) = ATTRIBUTE TO BE USED ON BLANKED LINE
; (DS) = DATA SEGMENT
; (ES) = REGEN BUFFER SEGNENT
; OUTPUT
; NONE -- THE REGEN BUFFER IS MODIFIED
;-------------------------------------------
ASSUME CS:CODE,DS:DATA,ES:DATA
SCROLL_UP PROC NEAR
MOV BL,AL ; SAVE LINE COUNT IN BL
CMP AH,4 ; TEST FOR GRAPHICS MODE
JC N1 ; HANDLE SEPARATELY
CMP AH,7 ; TEST FOR BW CARD
JE N1
JMP GRAPHICS_UP
N1: ; UP_CONTINUE
PUSH BX ; SAVE FILL ATTRIBUTE IN BH
MOV AX,CX ; UPPER LEFT POSITION
CALL SCROLL_POSITION ; DO SETUP FOR SCROLL
JZ N7 ; BLANK_FIELD
ADD SI,AX ; FROM ADDRESS
MOV AH,DH ; # ROWS IN BLOCK
SUB AH,BL ; # ROWS TO BE MOVED
N2: ; ROW_LOOP
CALL N10 ; MOVE ONE ROW
ADD SI,BP
ADD DI,BP ; POINT TO NEXT LINE IN BLOCK
DEC AH ; COUNT OF LINES TO MOVE
JNZ N2 ; ROW_LOOP
N3: ; CLEAR_ENTRY
POP AX ; RECOVER ATTRIBUTE IN AH
MOV AL,' ' ; FILL WITH BLANKS
N4: ; CLEAR_LOOP
CALL N11 ; CLEAR THE ROW
ADD DI,BP ; POINT TO NEXT LINE
DEC BL ; COUNTER OF LINES TO SCROLL
JNZ N4 ; CLEAR_LOOP
N5: ; SCROLL_END
MOV AX,DATA ; GET LOCATION
MOV DS,AX
CMP CRT_MODE,7 ; IS THIS THE BLACK AND WHITE CARD
JE N6 ; IF SO, SKIP THE MODE RESET
MOV AL,CRT_MODE_SET ; GET THE VALUE OF THE MODE SET
MOV DX,03D8H ; ALWAYS SET COLOR CARD PORT
OUT DX,AL
N6: ; VIDEO_RET_HERE
JMP VIDEO_RETURN
N7: ; BLANK_FIELD
MOV BL,DH ; GET ROW COUNT
JMP N3 ; GO CLEAR THAT AREA
SCROLL_UP ENDP
;----- HANDLE COMMON SCROLL SET UP HERE
SCROLL_POSITION PROC NEAR
CMP CRT_MODE,2 ; TEST FOR SPECIAL CASE HERE
JB N9 ; HAVE TO HANDLE 80X25 SEPARATELY
CMP CRT_MODE,3
JA N9
;------ 80X25 COLOR CARD SCROLL
PUSH DX
MOV DX,3DAH ; GUARANTEED TO BE COLOR CARD HERE
PUSH AX
N8: ; WAIT_DISP_ENABLE
IN AL,DX ; GET PORT
TEST AL,8 ; WAIT FOR VERTICAL RETRACE
JZ N8 ; WAIT_DISP_ENABLE
MOV AL,25H
MOV DX,03D8H
OUT DX,AL ; TURN OFF VIDEO
POP AX ; DURING VERTICAL RETRACE
POP DX
N9: CALL POSITION ; CONVERT TO REGEN POINTER
ADD AX,CRT_START ; OFFSET OF ACTIVE PAGE
MOV DI,AX ; TO ADDRESS FOR SCROLL
MOV SI,AX ; FROM ADDRESS FOR SCROLL
SUB DX,CX ; DX = #ROWS, #COLS IN BLOCK
INC DH
INC DL ; INCREMENT FOR 0 ORIGIN
XOR CH,CH ; SET HIGH BYTE OF COUNT TO ZERO
MOV BP,CRT_COLS ; GET NUMBER OF COLUMNS IN DISPLAY
ADD BP,BP ; TIMES 2 FOR ATTRIBUTE BYTE
MOV AL,BL ; GET LINE COUNT
MUL BYTE PTR CRT_COLS ; DETERMINE OFFSET TO FROM ADDRESS
ADD AX,AX ; *2 FOR ATTRIBUTE BYTE
PUSH ES ; ESTABLISH ADDRESSING TO REGEN BUFFER
POP DS ; FOR BOTH POINTERS
CMP BL,0 ; 0 SCROLL MEANS BLANK FIELD
RET ; RETURN WITH FLAGS SET
SCROLL_POSITION ENDP
;----- MOVE_ROW
N10 PROC NEAR
MOV CL,DL ; GET # OF COLS TO MOVE
PUSH SI
PUSH DI ; SAVE START ADDRESS
REP MOVSW ; MOVE THAT LINE ON SCREEN
POP DI
POP SI ; RECOVER ADDRESSES
RET
N10 ENDP
;------ CLEAR_ROW
N11 PROC NEAR
MOV CL,DL ; GET # COLUMNS TO CLEAR
PUSH DI
REP STOSW ; STORE THE FILL CHARACTER
POP DI
RET
N11 ENDP
;-----------------------------------
; SCROLL_DOWN
; THIS ROUTINE MOVES THE CHARACTERS WITHIN A DEFINED
; BLOCK DOWN ON THE SCREEN, FILLING THE TOP LINES
; WITH A DEFINED CHARACTER
; INPUT
; (AH) = CURRENT CRT MODE
; (AL) = NUMBER OF LINES TO SCROLL
; (CX) = UPPER LEFT CORNER OF REGION
; (DX) = LOWER RIGHT CORNER OF REGION
; (BH) = FILL CHARACTER
; (DS) = DATA SEGMENT
; (ES) = REGEN SEGMENT
; OUTPUT
; NONE -- SCREEN IS SCROLLED
;-----------------------------------
SCROLL_DOWN PROC NEAR
STD ; DIRECTION FOR SCROLL
MOV BL,AL ; LINE COUNT TO BL
CMP AH,4 ; TEST FOR GRAPHICS
JC N12
CMP AH,7 ; TEST FOR BW CARD
JE N12
JMP GRAPHICS_DOWN
N12: ; CONTINUE DOWN
PUSH BX ; SAVE ATTRIBUTE IN BH
MOV AX,DX ; LOWER RIGHT CORNER
CALL SCROLL_POSITION ; GET REGEN LOCATION
JZ N16
SUB SI,AX ; SI IS FROM ADDRESS
MOV AH,DH ; GET TOTAL # ROWS
SUB AH,BL ; COUNT TO MOVE IN SCROLL
N13:
CALL N10 ; MOVE ONE ROW
SUB SI,BP
SUB DI,BP
DEC AH
JNZ N13
N14:
POP AX ; RECOVER ATTRIBUTE IN AH
MOV AL,' '
N15:
CALL N11 ; CLEAR ONE ROW
SUB DI,BP ; GO TO NEXT ROW
DEC BL
JNZ N15
JMP N5 ; SCROLL_END
N16:
MOV BL,DH
JMP N14
SCROLL_DOWN ENDP
; -----------------------------------------
; READ_AC_CURRENT
; THIS ROUTINE READS THE ATTRIBUTE AND CHARACTER AT THE CURRENT
; CURSOR POSITION AND RETURNS THEM TO THE CALLER
; INPUT
; (AH) = CURRENT CRT NODE
; (BH) = DISPLAY PAGE (ALPHA MODES ONLY)
; (DS) = DATA SEGMENT
; (ES) = REGEN SEGMENT
; OUTPUT
; (AL) = CHAR READ
; (AH) = ATTRIBUTE READ
;------------------------------------------
ASSUME CS:CODE,DS:DATA,ES:DATA
READ_AC_CURRENT PROC NEAR
CMP AH,4 ; IS THIS GRAPICS
JC P1
CMP AH,7 ; IS THIS BW CARD
JE P1
JMP GRAPHICS_READ
P1: ; READ_AC_CONTINUE
CALL FIND_POSITION
MOV SI,BX ; ESTABLISH ADDRESSING IN SI
;------ WAIT FOR HORIZONTAL RETRACE
MOV DX,ADDR_6845 ; GET BASE ADDRESS
ADD DX,6 ; POINT AT STATUS PORT
PUSH ES ;
POP DS ; GET SEGMENT FOR QUICK ACCESS
P2: ; WAIT FOR RETRACE LOW
IN AL,DX ; GET STATUS
TEST AL,1 ; IS HORZ RETRACE LOW
JNZ P2 ; WAIT UNTIL IT IS
CLI ; NO MORE INTERRUPTS
P3: ; WAIT FOR RETRACE HIGH
IN AL,DX ; GET STATUS
TEST AL,1 ; IS IT HIGH
JZ P3 ; WAIT UNTIL IT IS
LODSW ; GET THE CHAR/ATTR
JMP VIDEO_RETURN
READ_AC_CURRENT ENDP
FIND_POSITION PROC NEAR
MOV CL,BH ; DISPLAY PAGE TO CX
XOR CH,CH
MOV SI,CX ; MOVE TO SI FOR INDEX
SAL SI,1 ; * 2 FOR WORD OFFSET
MOV AX,[SI+OFFSET CURSOR_POSN] ; GET ROW/COLUMN OF THAT PAGE
XOR BX,BX ; SET START ADDRESS TO ZERO
JCXZ P5 ; NO_PAGE
P4: ; PAGE_LOOP
ADD BX,CRT_LEN ; LENGTH OF BUFFER
LOOP P4
P5: ; NO_PAGE
CALL POSITION ; DETERMINE LOCATION IN REGEN
ADD BX,AX ; ADD TO START OF REGEN
RET
FIND_POSITION ENDP
;-----------------------------------------
; WRITE_AC_CURRENT
; THIS ROUTINE WRITES THE ATTRIBUTE AND CHARACTER AT
; THE CURRENT CURSOR POSITION
; INPUT
; (AH) = CURRENT CRT MODE
; (BH) = DISPLAY PAGE
; (CX) = COUNT OF CHARACTERS TO WRITE
; (AL) = CHAR TO WRITE
; (BL) = ATTRIBUTE OF CHAR TO WRITE
; (DS) = DATA SEGMENT
; (ES) = REGEN SEGMENT
; OUTPUT
; NONE
;------------------------------------------
WRITE_AC_CURRENT PROC NEAR
CMP AH,4 ; IS THIS GRAPHICS
JC P6
CMP AH,7 ; IS THIS BW CARD
JE P6
JMP GRAPHICS_WRITE
P6: ; WRITE_AC_CONTINUE
MOV AH,BL ; GET ATTRIBUTE TO AH
PUSH AX ; SAVE ON STACK
PUSH CX ; SAVE WRITE COUNT
CALL FIND_POSITION
MOV DI,BX ; ADDRESS TO DI RESISTER
POP CX ; WRITE COUNT
POP BX ; CHARACTER IN BX REG
P7: ; WRITE_LOOP
;------ WAIT FOR HORIZONTAL RETRACE
MOV DX,ADDR_6845 ; GET BASE ADDRESS
ADD DX,6 ; POINT AT STATUS PORT
P8:
IN AL,DX ; GET STATUS
TEST AL,1 ; IS IT LOW
JNZ P8 ; WAIT UNTIL IT IS
CLI ; NO MORE INTERRUPTS
P9:
IN AL,DX ; GET STATUS
TEST AL,1 ; IS IT HIGH
JZ P9 ; WAIT UNTIL IT IS
MOV AX,BX ; RECOVER THE CHAR/ATTR
STOSW ; PUT THE CHAR/ATTR
STI ; INTERRUPTS BACK ON
LOOP P7 ; AS MANY TIMES AS REQUESTED
JMP VIDEO_RETURN
WRITE_AC_CURRENT ENDP
;-----------------------------------------
; WRITE_C_CURRENT
; THIS ROUTINE WRITES THE CHARACTER AT
; THE CURRENT CURSOR POSITION, ATTRIBUTE UNCHANGED
; INPUT
; (AH) = CURRENT CRT MODE
; (BH) = DISPLAY PAGE
; (CX) = COUNT OF CHARACTERS TO WRITE
; (AL) = CHAR TO WRITE
; (DS) = DATA SEGMENT
; (ES) = REGEN SEGMENT
;OUTPUT
; NONE
;------------------------------------------
WRITE_C_CURRENT PROC NEAR
CMP AH,4 ; IS THIS GRAPHICS
JC P10
CMP AH,7 ; IS THIS BW CARD
JE P10
JMP GRAPHICS_WRITE
P10:
PUSH AX ; SAVE ON STACK
PUSH CX ; SAVE WRITE COUNT
CALL FIND_POSITION
MOV DI,BX ; ADDRESS TO DI
POP CX ; WRITE COUNT
POP BX ; BL HAS CHAR TO WRITE
P11: ; WRITE_LOOP
;------ WAIT FOR HORIZONTAL RETRACE
MOV DX,ADDR_6845 ; GET BASE ADDRESS
ADD DX,6 ; POINT AT STATUS PORT
P12:
IN AL,DX ; GET STATUS
TEST AL,1 ; IS IT LOW
JNZ P12 ; WAIT UNTIL IT IS
CLI ; NO MORE INTERRUPTS
P13:
IN AL,DX ; GET STATUS
TEST AL,1 ; IS IT HIGH
JZ P13 ; WAIT UNTIL IT IS
MOV AL,BL ; RECOVER CHAR
STOSB ; PUT THE CHAR/ATTR
INC DI ; BUMP POINTER PAST ATTRIBUTE
LOOP P11 ; AS MANY TIMES AS REQUESTED
JMP VIDEO_RETURN
WRITE_C_CURRENT ENDP
;--------------------------------------------
; READ DOT -- WRITE DOT
; THESE ROUTINES WILL WRITE A DOT, OR READ THE
; DOT AT THE INDICATED LOCATION
; ENTRY --
; DX = ROW (0-199) (THE ACTUAL VALUE DEPENDS ON THE MODE)
; CX = COLUMN (0-639) (THE VALUES ARE NOT RANGE CHECKED)
; AL = DOT VALUE TO WRITE (1, 2 OR 4 BITS DEPENDING ON MODE,
; REQ'D FOR WRITE DOT ONLY, RIGHT JUSTIFIED)
; BIT 7 OF AL = 1 INDICATES XOR THE VALUE INTO THE LOCATION
; DS = DATA SEGMENT
; ES = REGEN SEGMENT
;
; EXIT
; AL = DOT VALUE READ, RIGHT JUSTIFIED, READ ONLY
;--------------------------------------------
ASSUME CS:CODE,DS:DATA,ES:DATA
READ_DOT PROC NEAR
CALL R3 ; DETERMINE BYTE POSITION OF DOT
MOV AL,ES:[SI] ; GET THE BYTE
AND AL,AH ; MASK OFF THE OTHER BITS IN THE BYTE
SHL AL,CL ; LEFT JUSTIFY THE VALUE
MOV CL,DH ; GET NUMBER OF BITS IN RESULT
ROL AL,CL ; RIGHT JUSTIFY THE RESULT
JMP VIDEO_RETURN ; RETURN FROM VIDEO IO
READ_DOT ENDP
WRITE_DOT PROC NEAR
PUSH AX ; SAVE DOT VALUE
PUSH AX ; TWICE
CALL R3 ; DETERMINE BYTE POSITION OF THE DOT
SHR AL,CL ; SHIFT TO SET UP THE BITS FOR OUTPUT
AND AL,AH ; STRIP OFF THE OTHER BITS
MOV CL,ES:[SI] ; GET THE CURRENT BYTE
POP BX ; RECOVER XOR FLAG
TEST BL,80H ; IS IT ON
JNZ R2 ; YES, XOR THE DOT
NOT AH ; SET THE MASK TO REMOVE THE INDICATED BITS
AND CL,AH
OR AL,CL ; OR IN THE NEW VALUE OF THOSE BITS
R1: ; FINISH_DOT
MOV ES:[SI],AL ; RESTORE THE BYTE IN MEMORY
POP AX
JMP VIDEO_RETURN ; RETURN FRON VIDEO IO
R2: ; XOR_DOT
XOR AL,CL ; EXCLUSIVE OR THE DOTS
JMP R1 ; FINISH UP THE WRITING
WRITE_DOT ENDP
;--------------------------------------------
; THIS SUBROUTINE DETERMINES THE REGEN BYTE LOCATION OF THE
; INDICATED ROW COLUMN VALUE IN GRAPHICS MODE.
; ENTRY --
; DX = ROW VALUE (0-199)
; CX = COLUMN VALUE (0-639)
; EXIT --
; SI = OFFSET INTO REGEN BUFFER FOF BYTE OF INTEREST
; AH = MASK TO STRIP OFF THE BITS OF INTEREST
; CL = BITS TO SHIFT TO RIGHT JUSTIFY THE MASK IN AH
; DH = BITS IN RESULT
;--------------------------------------------
R3 PROC NEAR
PUSH BX ; SAVE BX DURING OPERATION
PUSH AX ; WILL SAVE AL DURING OPERATION
;------ DETERMINE 1ST BYTE IN INDICATED ROW BY MULTIPLTING ROW VALUE BY 40
;------ (LOW BIT OF ROW DETERMINES EVEN/OOD, 80 BYTES/ROW
MOV AL,40
PUSH DX ; SAVE ROW VALUE
AND DL,0FEH ; STRIP OFF ODD/EVEN BIT
MUL DL ; AX HAS ADDRESS OF 1ST BYTE OF INDICATED ROW
POP DX ; RECOVER IT
TEST DL,1 ; TEST FOR EVEN/ODD
JZ R4 ; JUMP IF EVEN ROW
ADD AX,2000H ; OFFSET TO LOCATION OF ODD ROWS
R4: ; EVEN_ROW
MOV SI,AX ; MOVE POINTER TO SI
POP AX ; RECOVER AL VALUE
MOV DX,CX ; COLUMN VALUE TO DX
;------ DETERMINE GRAPHICS MODE CURRENTLY IN EFFECT
; SET UP THE REGISTERS ACCORDING TO THE MODE
; CH = MASK FOR LOW OF COLUMN ADDRESS (7/3 FOR HIGH/MED RES)
; CL = # OF ADDRESS BITS IN COLUMN VALUE (3/2 FOR H/M)
; BL = MASK TO SELECT BITS FROM POINTED BYTE (80H/C0H FOR H/M)
; BH = NUMBER OF VALID BITS IN POINTED BYTE (1/2 FOR H/M)
MOV BX,2C0H
MOV CX,302H ; SET PARMS FOR MED RES
CMP CRT_MODE,6
JC R5 ; HANDLE IF MED RES
MOV BX,180H
MOV CX,703H ; SET PARMS FOR HIGH RES
;------ DETERMINE BIT OFFSET IN BYTE FROM COLUMN MASK
R5:
AND CH,DL ; ADDRESS OF PEL WITHIN BYTE TO CH
;------ DETERMINE BYTE OFFSET FOR THIS LOCATION IN COLUMN
SHR DX,CL ; SHIFT BY CORRECT AMOUNT
ADD SI,DX ; INCREMENT THE POINTER
MOV DH,BH ; GET THE # OF BITS IN RESULT TO DH
; ------ MULTIPLY BH (VALID BITS IN BYTE) BY CH (BIT OFFSET)
SUB CL,CL ; ZERO INTO STORAGE LOCATION
R6:
ROR AL,1 ; LEFT JUSTIFY THE VALUE IN AL (FOR WRITE)
ADD CL,CH ; ADD IN THE BIT OFFSET VALUE
DEC BH ; LOOP CONTROL
JNZ R6 ; ON EXIT, CL HAS SHIFT COUNT TO RESTORE BITS
MOV AH,BL ; GET MASK TO AH
SHR AH,CL ; MOVE THE MASK TO CORRECT LOCATION
POP BX ; RECOVER REG
RET ; RETURN WITH EVERYTHING SET UP
R3 ENDP
;--------------------------------------------
; SCROLL UP
; THIS ROUTINE SCROLLS UP THE INFORMATION ON THE CRT
; ENTRY --
; CH,CL = UPPER LEFT CORNER OF REGION TO SCROLL
; DH,DL = LOWER RIGHT CORNER OF REGION TO SCROLL
; BOTH OF THE ABOVE ARE IN CHARACTER POSITIONS
; BH = FILL VALUE FOR BLANKED LINES
; AL = # LINES TO SCROLL (AL=0 MEANS BLANK THE ENTIRE FIELD)
; DS = DATA SEGMENT
; ES = REGEN SEGMENT
; EXIT --
; NOTHING, THE SCREEN IS SCROLLED
;--------------------------------------------
GRAPHICS_UP PROC NEAR
MOV BL,AL ; SAVE LINE COUNT IN BL
MOV AX,CX ; GET UPPER LEFT POSITION INTO AX REG
;------ USE CHARACTER SUBROUTINE FOR POSITIONING
;------ ADDRESS RETURNED IS MULTIPUED BY 2 FROM CORRECT VALUE
CALL GRAPH_POSN
MOV DI,AX ; SAVE RESULT AS DESTINATION ADDRESS
;------ DETERMINE SIZE OF WINDOW
SUB DX,CX
ADD DX,101H ; ADJUST VALUES
SAL DH,1 ; MULTIPLY # ROWS BY 4 SINCE 8 VERT DOTS/CHAR
SAL DH,1 ; AND EVEN/OOD ROWS
;------ DETERMINE CRT MODE
CMP CRT_MODE,6 ; TEST FOR MEDIUM RES
JNC R7 ; FIND_SOURCE
;------ MEDIUM RES UP
SAL DL,1 ; # COLUMNS * 2, SINCE 2 BYTES/CHAR
SAL DI,1 ; OFFSET *2 SINCE 2 BYTES/CHAR
;------ DETERMINE THE SOURCE ADDRESS IN THE BUFFER
R7: ; FIND_SOURCE
PUSH ES ; GET SEGMENTS BOTH POINTING TO REGEN
POP DS
SUB CH,CH ; ZERO TO HIGH OF COUNT REG
SAL BL,1 ; MULTIPLY NUMBER OF LINES BY 4
SAL BL,1
JZ R11 ; IF ZERO, THEN BLANK ENTIRE FIELD
MOV AL,BL ; GET NUMBER OF LINES IN AL
MOV AH,80 ; 80 BYTES
MUL AH ; DETERMINE OFFSET TO SOURCE
MOV SI,DI ; SET UP SOURCE
ADD SI,AX ; ADD IN OFFSET TO IT
MOV AH,DH ; NUMBER OF ROWS IN FIELD
SUB AH,BL ; DETERMINE NUMBER TO MOVE
;------ LOOP THROUGH, MOVING ONE ROW AT A TIME, BOTH EVEN AND ODD FIELDS
R8: ; ROW_LOOP
CALL R17 ; MOVE ONE ROW
SUB SI,2000H-80 ; MOVE TO NEXT ROW
SUB DI,2000H-80
DEC AH ; NUMBER OF ROWS TO MOVE
JNZ R8 ; CONTINUE TILL ALL MOVED
;------ FILL IN THE VACATED LINE(S)
R9: ; CLEAR_ENTRY
MOV AL,BH ; ATTRIBUTE TO FILL WITH
R10:
CALL R18 ; CLEAR THAT ROW
SUB DI,2000H-80 ; POINT TO NEXT LINE
DEC BL ; NUMBER OF LINES TO FILL
JNZ R10 ; CLEAR_LOOP
JMP VIDEO_RETURN ; EVERYTHING DONE
R11: ; BLANK_FIELD
MOV BL,DH ; SET BLANK COUNT TO EVERYTHING IN FIELD
JMP R9 ; CLEAR THE FIELD
GRAPHICS_UP ENDP
;--------------------------------------------
; SCROLL DOWN
; THIS ROUTINE SCROLLS DOWN THE INFORMATION ON THE CRT
; ENTRY --
; CH,CL = UPPER LEFT CORNER OF REGION TO SCROLL
; DH,DL = LOWER RIGHT CORNER OF REGION TO SCROLL
; BOTH OF THE ABOVE ARE IN CHARACTER POSITIONS
; BH = FILL VALUE FOR BLANKED LINES
; AL = # LINES TO SCROLL (AL=0 MEANS BLANK THE ENTIRE FIELD)
; DS = DATA SEGMENT
; ES = REGEN SEGMENT
; EXIT --
; NOTHING, THE SCREEN IS SCROLLED
;---------------------------------------------
GRAPHICS_DOWN PROC NEAR
STD ; SET DIRECTION
MOV BL,AL ; SAVE LINE COUNT IN BL
MOV AX,DX ; GET LOWER RIGHT POSITION INTO AX REG
;------ USE CHARACTER SUBROUTINE FOR POSITIONING
;------ ADDRESS RETURNED IS MULTIPLIED BY 2 FROM CORRECT VALUE
CALL GRAPH_POSN
MOV DI,AX ; SAVE RESULT AS DESTINATION ADDRESS
;------ DETERMINE SIZE OF WINDOW
SUB DX,CX
ADD DX,101H ; ADJUST VALUES
SAL DH,1 ; MULTIPLY # ROWS BY 4 SINCE 8 VERT DOTS/CHAR
SAL DH,1 ; AND EVEN/ODD ROWS
;------ DETERMINE CRT MODE
CMP CRT_MODE,6 ; TEST FOR MEDIUM RES
JNC R12 ; FIND_SOURCE_DOWN
;------ MEDIUM RES DOWN
SAL DL,1 ; # COLUMNS * 2, SINCE 2 BYTES/CHAR (OFFSET OK)
SAL DI,1 ; OFFSET *2 SINCE 2 BYTES/CHAR
INC DI ; POINT TO LAST BYTE
;------ DETERMINE THE SOURCE ADDRESS IN THE BUFFER
R12: ; FIND_SOURCE_DOWN
PUSH ES ; BOTH SEGMENTS TO REGEN
POP DS
SUB CH,CH ; ZERO TO HIGH OF COUNT REG
ADD DI,240 ; POINT TO LAST ROW OF PIXELS
SAL BL,1 ; MULTIPLY NUMBER OF LINES BY 4
SAL BL,1
JZ R16 ; IF ZERO, THEN BLANK ENTIRE FIELD
MOV AL,BL ; GET NUMBER OF LINES IN AL
MOV AH,80 ; 80 BYTES/ROW
MUL AH ; DETERMINE OFFSET TO SOURCE
MOV SI,DI ; SET UP SOURCE
SUB SI,AX ; SUBTRACT THE OFFSET
MOV AH,DH ; NUMBER OF ROWS IN FIELD
SUB AH,BL ; DETERMINE NUMBER TO MOVE
;------ LOOP THROUGH, MOVING ONE ROW AT A TIME, BOTH EVEN AND ODD FIELDS
R13: ; ROW_LOOP_DOWN
CALL R17 ; MOVE ONE ROW
SUB SI,2000H+80 ; MOVE TO NEXT ROW
SUB DI,2000H+80
DEC AH ; NUMBER OF ROWS TO MOVE
JNZ R13 ; CONTINUE TILL ALL MOVED
; ------ FILL IN THE VACATED LINE(S)
R14: ; CLEAR_ENTRY_DOWN
MOV AL,BH ; ATTRIBUTE TO FILL WITH
R15: ; CLEAR_LOOP_DOWN
CALL R18 ; CLEAR A ROW
SUB DI,2000H+80 ; POINT TO NEXT LINE
DEC BL ; NUMBER OF LINES TO FILL
JNZ R15 ; CLEAR_LOOP_DOWN
CLD ; RESET THE DIRECTION FLAG
JMP VIDEO_RETURN ; EVERYTHING DONE
R16: ; BLANK_FIELD_DOWN
MOV BL,DH ; SET BLANK COST TO EVERYTHING IN FIELD
JMP R14 ; CLEAR THE FIELD
GRAPHICS_DOWN ENDP
;------ ROUTINE TO MOVE ONE ROW OF INFORMATION
R17 PROC NEAR
MOV CL,DL ; NUMBER OF BYTES IN THE ROW
PUSH SI
PUSH DI ; SAVE POINTERS
REP MOVSB ; MOVE THE EVEN FIELD
POP DI
POP SI
ADD SI,2000H
ADD DI,2000H ; POINT TO THE ODD FIELD
PUSH SI
PUSH DI ; SAVE THE POINTERS
MOV CL,DL ; COUNT BACK
REP MOVSB ; MOVE THE ODD FIELD
POP DI
POP SI ; POINTERS BACK
RET ; RETURN TO CALLER
R17 ENDP
;------ CLEAR A SINGLE ROW
R18 PROC NEAR
MOV CL,DL ; NUMBER OF BYTES IN FIELD
PUSH DI ; SAVE POINTER
REP STOSB ; STORE THE NEW VALUE
POP DI ; POINTER BACK
ADD DI,2000H ; POINT TO ODD FIELD
PUSH DI
MOV CL,DL
REP STOSB ; FILL THE ODD FILELD
POP DI
RET ; RETURN TO CALLER
R18 ENDP
;--------------------------------------------
; GRAPHICS WRITE
; THIS ROUTINE WRITES THE ASCII CHARACTER TO THE CURRENT
; POSITION ON THE SCREEN.
; ENTRY --
; AL = CHARACTER TO WRITE
; BL = COLOR ATTRIBUTE TO BE USED FOR FOREGROUND COLOR
; IF BIT 7 IS SET, THE CHAR IS XOR'D INTO THE REGEN BUFFER
; (0 IS USED FOR THE BACKGROUND COLOR)
; CX = NUMBER OF CHARS TO WRITE
; DS = DATA SEGMENT
; ES = REGEN SEGMENT
; EXIT --
; NOTHING IS RETURNED
;
; GRAPHICS READ
; THIS ROUTINE READS THE ASCII CHARACTER AT THE CURRENT CURSOR
; POSITION ON THE SCREEN BY MATCHING THE DOTS ON THE SCREEN TO THE
; CHARACTER GENERATOR CODE POINTS
; ENTRY --
; NONE (0 IS ASSUMED AS THE BACKGROUND COLOR)
; EXIT --
; AL = CHARACTER READ AT THAT POSITION (0 RETURNED IF NONE FOUND)
;
; FOR BOTH ROUTINES, THE IMAGES USED TO FORM CHARS ARE CONTAINED IN ROM
; FOR THE 1ST 128 CHARS. TO ACCESS CHARS IN THE SECOND HALF, THE USER
; MUST INITIALIZE THE VECTOR AT INTERRUPT 1FH (LOCATION 0007CH) TO
; POINT TO THE USER SUPPLIED TABLE OF GRAPHIC IMAGES (8X8 BOXES).
; FAILURE TO DO SO WILL CAUSE IN STRANGE RESULTS
;--------------------------------------------
ASSUME CS:CODE,DS:DATA,ES:DATA
GRAPHICS_WRITE PROC NEAR
MOV AH,0 ; ZERO TO HIGH OF CODE POINT
PUSH AX ; SAVE CODE POINT VALUE
;------ DETERMINE POSITION IN REGEN BUFFER TO PUT CODE POINTS
CALL S26 ; FIND LOCATION IN REGEN BUFFER
MOV DI,AX ; REGEN POINTER IN DI
;------ DETERMINE REGION TO GET CODE POINTS FROM
POP AX ; RECOVER CODE POINT
CMP AL,80H ; IS IT IN SECOND HALF
JAE S1 ; YES
; ------ IMAGE IS IN FIRST HALF, CONTAINED IN ROM
MOV SI,0FA6EH ; OFFSET CRT_CHAR_GEN-OFFSET OF IMAGES
PUSH CS ; SAVE SEGMENT ON STACK
JMP SHORT S2 ; DETERMINE_MODE
;------ IMAGE IS IN SECOND HALF, IN USER RAM
S1: ; EXTEND_CHAR
SUB AL,80H ; ZERO ORIGIN FOR SECOND HALF
PUSH DS ; SAVE DATA POINTER
SUB SI,SI
MOV DS,SI ; ESTABLISH VECTOR ADDRESSING
ASSUME DS:ABS0
LDS SI,EXT_PTR ; GET THE OFFSET OF THE TABLE
MOV DX,DS ; GET THE SEGMENT OF THE TABLE
ASSUME DS:DATA
POP DS ; RECOVER DATA SEGMENT
PUSH DX ; SAVE TABLE SEGMENT ON STACK
;------ DETERMINE GRAPHICS MODE IN OPERATION
S2: ; DETERMINE_MODE
SAL AX,1 ; MULTIPLY CODE POINT
SAL AX,1 ; VALUE BY 8
SAL AX,1
ADD SI,AX ; SI HAS OFFSET OF DESIRED CODES
CMP CRT_MODE,6
POP DS ; RECOVER TABLE POINTER SEGMENT
JC S7 ; TEST FOR MEDIUM RESOLUTION MODE
;------ HIGH RESOLUTION MODE
S3: ; HIGH_CHAR
PUSH DI ; SAVE REGEN POINTER
PUSH SI ; SAVE CODE POINTER
MOV DH,4 ; NUMBER OF LINES THROUGH LOOP
S4:
LODSB ; GET BYTE FROM CODE POINTS
TEST BL,80H ; SHOULD WE USE THE FUNCTION
JNZ S6 ; TO PUT CHAR IN
STOSB ; STORE IN REGEN BUFFER
LODSB
S5: ;
MOV ES:[DI+2000H-1],AL ; STORE IN SECOND HALF
ADD DI,79 ; MOVE TO NEXT ROW IN REGEN
DEC DH ; DONE WITH LOOP
JNZ S4
POP SI
POP DI ; RECOVER REGEN POINTER
INC DI ; POINT TO NEXT CHAR POSITION
LOOP S3 ; MORE CHARS TO WRITE
JMP VIDEO_RETURN
S6:
XOR AL,ES:[DI] ; EXCLUSIVE OR WITH CURRENT
STOSB ; STORE THE CODE POINT
LODSB ; AGAIN FOR ODD FIELD
XOR AL,ES:[DI+2000H-1] ;
JMP S5 ; BACK TO MAINSTREAM
;------ MEDIUM RESOLUTION WRITE
S7: ; MED_RES_WRITE
MOV DL,BL ; SAVE HIGH COLOR BIT
SAL DI,1 ; OFFSET*2 SINCE 2 BYTES/CHAR
CALL S19 ; EXPAND BL TO FULL WORD OF COLOR
S8: ; MED_CHAR
PUSH DI ; SAVE REGEN POINTER
PUSH SI ; SAVE THE CODE POINTER
MOV DH,4 ; NUMBER OF LOOPS
S9:
LODSB ; GET CODE POINT
CALL S21 ; DOUBLE UP ALL THE BITS
AND AX,BX ; CONVERT THEM TO FOREGROUND COLOR (0 BACK )
TEST DL,80H ; IS THIS XOR FUNCTION
JZ S10 ; NO, STORE IT IN AS IT IS
XOR AH,ES:[DI] ; DO FUNCTICH WITH HALF
XOR AL,ES:[DI+1] ; AND WITH OTHER HALF
S10: ;
MOV ES:[DI],AH ; STORE FIRST BYTE
MOV ES:[DI+1],AL ; STORE SECOND BYTE
LODSB ; GET CODE POINT
CALL S21
AND AX,BX ; CONVERT TO COLOR
TEST DL,80H ; AGAIN, IS THIS XOR FUNCTION
JZ S11 ; NO, JUST STORE THE VALUES
XOR AH,ES:[DI+2000H] ; FUNCTION WITH FIRST HALF
XOR AL,ES:[DI+2001H] ; AND WITH SECOND HALF
S11: ;
MOV ES:[DI+2000H],AH
MOV ES:[DI+2000H+1],AL ; STORE IN SECOND PORTION OF BUFFER
ADD DI,80 ; POINT TO NEXT LOCATION
DEC DH
JNZ S9 ; KEEP GOING
POP SI ; RECOVER CODE POINTER
POP DI ; RECOVER REGEN POINTER
ADD DI,2 ; POINT TO NEXT CHAR POSITION
LOOP S8 ; MORE TO WRITE
JMP VIDEO_RETURN
GRAPHICS_WRITE ENDP
;-----------------------------------------------
; GRAPHICS READ
;-----------------------------------------------
GRAPHICS_READ PROC NEAR
CALL S26 ; CONVERTED TO OFFSET IN REGEN
MOV SI,AX ; SAVE IN SI
SUB SP,8 ; ALLOCATE SPACE TO SAVE THE READ CODE POINTER
MOV BP,SP ; POINTER TO SAVE AREA
;------ DETERMINE GRAPHICS MODES
CMP CRT_MODE,6
PUSH ES
POP DS ; POINT TO REGEN SEGMENT
JC S13 ; MEDIUM RESOLUTION
;------ HIGH RESOLUTION READ
;------ GET VALUES FROM REGEN BUFFER AND CONVERT TO CODE POINT
MOV DH,4 ; NUMBER OF PASSES
S12:
MOV AL,[SI] ; GET FIRST BYTE
MOV [BP],AL ; SAVE IN STORAGE AREA
INC BP ; NEXT LOCATION
MOV AL,[SI+2000H] ; GET LOWER REGION BYTE
MOV [BP],AL ; ADJUST AND STORE
INC BP
ADD SI,80 ; POINTER INTO REGEN
DEC DH ; LOOP CONTROL
JNZ S12 ; DO IT SOME MORE
JMP NEAR PTR S15 ; GO MATCH THE SAVED CODE POINTS
;------ MEDIUM RESOLUTION READ
S13: ; MED_RES_READ
SAL SI,1 ; OFFSET*2 SINCE 2 BYTES/CHAR
MOV DH,4 ; NUMBER OF PASSES
S14:
CALL S23 ; GET PAIR BYTES FROM REGEN INTO SINGLE SAVE
ADD SI,2000H ; GO TO LOWER REGION
CALL S23 ; GET THIS PAIR INTO SAVE
SUB SI,2000H-80 ; ADJUST POINTER BACK INTO UPPER
DEC DH
JNZ S14 ; KEEP GOING UNTIL ALL 8 DONE
;-------- SAVE AREA HAS CHARACTER IN IT, MATCH IT
S15: ; FIND_CHAR
MOV DI,0FA6EH ; OFFSET CRT_CHAR_GEN-ESTABLISH ADDRESSING
PUSH CS
POP ES ; CODE POINTS IN CS
SUB BP,8 ; ADJUST POINTER TO BEGINNING OF SAVE AREA
MOV SI,BP
CLD ; ENSURE DIRECTION
MOV AL,0 ; CURRENT CODE POINT BEING MATCHED
S16:
PUSH SS ; ESTABEISH ADDRESSING TO STACK
POP DS ; FOR THE STRING COMPARE
MOV DX,128 ; NUMBER TO TEST AGAINST
S17:
PUSH SI ; SAVE SAVE AREA POINTER
PUSH DI ; SAVE CODE POINTER
MOV CX,8 ; NUMBER OF BYTES TO MATCH
REPE CMPSB ; COMPARE THE 8 BYTES
POP DI ; RECOVER THE POINTERS
POP SI
JZ S18 ; IF ZERO FLAG SET, THEN MATCH OCCURRED
INC AL ; NO MATCH, MOVE ON TO NEXT
ADD DI,8 ; NEXT CODE POINT
DEC DX ; LOOP CONTROL
JNZ S17 ; DO ALL OF THEM
; ------ CHAR NOT MATCHED, MIGHT BE IN USER SUPPLIED SECOND HALF
CMP AL,0 ; AL<> 0 IF ONLY 1ST HALF SCANNED
JE S18 ; IF = 0, THEN ALL HAS BEEN SCANNED
SUB AX, AX
MOV DS,AX ; ESTABLISH ADDRESSING TO VECTOR
ASSUME DS:ABS0
LES DI,EXT_PTR ; GET POINTER
MOV AX,ES ; SEE IF THE POINTER REALLY EXISTS
OR AX,DI ; IF ALL 0, THEN DOESN'T EXIST
JZ S18 ; NO SENSE LOOKING
MOV AL,128 ; ORIGIN FOR SECOND HALF
JMP S16 ; GO BACK AND TRY FOR IT
ASSUME DS:DATA
;------ CHARACTER IS FOUND (AL=0 IF NOT FOUND)
S18:
ADD SP,8 ; READJUST THE STACK, THROW AWAY SAVE
JMP NEAR PTR VIDEO_RETURN ; ALL DONE
GRAPHICS_READ ENDP
;--------------------------------------------
; EXPAND_MED_COLOR
; THIS ROUTINE EXPANDS THE LOW 2 BITS IN BL TO
; FILL THE ENTIRE BX REGISTER
; ENTRY --
; BL = COLOR TO BE USED (LOW 2 BITS)
; EXIT --
; BX = COLOR TO BE USED (8 REPLICATIONS OF THE 2 COLOR BITS)
;--------------------------------------------
S19 PROC NEAR
AND BL,3 ; ISOLATE THE COLOR BITS
MOV AL,BL ; COPY TO AL
PUSH CX ; SAVE REGISTER
MOV CX,3 ; NUMBER OF TIMES TO DO THIS
S20:
SAL AL,1
SAL AL,1 ; LEFT SHIFT BY 2
OR BL,AL ; ANOTHER COLOR VERSION INTO BL
LOOP S20 ; FILL ALL OF BL
MOV BH,BL ; FILL UPPER PORTION
POP CX ; REGISTER BACK
RET ; ALL DONE
S19 ENDP
;--------------------------------------------
; EXPAND_BYTE
; THIS ROUTINE TAKES THE BYTE IN AL AND DOUBLES ALL
; OF THE BITS, TURNING THE 8 BITS INTO 16 BITS.
; THE RESULT IS LEFT IN AX
;--------------------------------------------
S21 PROC NEAR
PUSH DX ; SAVE REGISTERS
PUSH CX
PUSH BX
MOV DX,0 ; RESULT REGISTER
MOV CX,1 ; MASK REGISTER
S22:
MOV BX,AX ; BASE INTO TEMP
AND BX,CX ; USE MASK TO EXTRACT A BIT
OR DX,BX ; PUT INTO RESULT REGISTER
SHL AX,1
SHL CX,1 ; SHIFT BASE AND MASK BY 1
MOV BX,AX ; BASE TO TEMP
AND BX,CX ; EXTRACT THE SAME BIT
OR DX,BX ; PUT INTO RESULT
SHL CX,1 ; SHIFT ONLY MASK NOW, MOVING TO NEXT BASE
JNC S22 ; USE MASK BIT COMING OUT TO TERMINATE
MOV AX,DX ; RESULT TO PARM REGISTER
POP BX
POP CX ; RECOVER REGISTERS
POP DX
RET ; ALL DONE
S21 ENDP
;--------------------------------------------
; MED_READ_BYTE
; THIS ROUTINE WILL TAKE 2 BYTES FROM THE REGEN BUFFER,
; COMPARE AGAINST THE CURRENT FOREGROUND COLOR, AND PLACE
; THE CORRESPONDING ON/OFF BIT PATTERN INTO THE CURRENT
; POSITION IN THE SAVE AREA
; ENTRY --
; SI,DS = POINTER TO REGEN AREA OF INTEREST
; BX = EXPANDED FOREGROUND COLOR
; BP = POINTER TO SAVE AREA
; EXIT --
; BP IS INCREMENT AFTER SAVE
;---------------------------------------------
S23 PROC NEAR
MOV AH,[SI] ; GET FIRST BYTE
MOV AL,[SI+1] ; GET SECOND BYTE
MOV CX,0C000H ; 2 BIT MASK TO TEST THE ENTRIES
MOV DL,0 ; RESULT REGISTER
S24:
TEST AX,CX ; IS THIS SECTION BACKGROUND?
CLC ; CLEAR CARRY IN HOPES THAT IT IS
JZ S25 ; IF ZERO, IT IS BACKGROUND
STC ; WASN'T, SO SET CARRY
S25: RCL DL,1 ; MOVE THAT BIT INTO THE RESULT
SHR CX,1
SHR CX,1 ; MOVE THE MASK TO THE RIGHT BY 2 BITS
JNC S24 ; DO IT AGAIN IF MASK DIDN'T FALL OUT
MOV [BP],DL ; STORE RESULT IN SAVE AREA
INC BP ; ADJUST POINTER
RET ; ALL DONE
S23 ENDP
;-----------------------------------------
; V4_POSITION
; THIS ROUTINE TAKES THE CURSOR POSITION CONTAINED IN
; THE MEMORY LOCATION, AND CONVERTS IT INTO AN OFFSET
; INTO THE REGEN BUFFER, ASSUMING ONE BYTE/CHAR.
; FOR MEDIUM RESOLUTION GRAPHICS, THE NUMBER MUST
; BE DOUBLED.
; ENTRY -- NO REGISTERS,MEMORY LOCATION CURSOR_POSN IS USED
; EXIT--
; AX CONTAINS OFFSET INTO REGEN BUFFER
;-----------------------------------------
S26 PROC NEAR
MOV AX,CURSOR_POSN ; GET CURRENT CURSOR
GRAPH_POSN LABEL NEAR
PUSH BX ; SAVE REGISTER
MOV BX,AX ; SAVE A COPY OF CURRENT CURSOR
MOV AL,AH ; GET ROWS TO AL
MUL BYTE PTR CRT_COLS ; MULTIPLY BY BYTES/COLUMN
SHL AX,1 ; MULTIPLY * 4 SINCE 4 ROWS/BYTE
SHL AX,1
SUB BH,BH ; ISOLATE COLUMN VALUE
ADD AX,BX ; DETERMINE OFFSET
POP BX ; RECOVER POINTER
RET ; ALL DONE
S26 ENDP
;--------------------------------------------
; WRITE_TTY
; THIS INTERFACE PROVIDES A TELETYPE LIKE INTERFACE TO THE
; VIDEO CARD. THE INPUT CHARACTER IS WRITTEN TO THE CURRENT
; CURSOR POSITION, AND THE CURSOR IS MOVED TO THE NEXT POSITION.
; IF THE CURSOR LEAVES THE LAST COLUMN OF THE FIELD, THE COLUMN
; IS SET TO ZERO, AND THE ROW VALUE IS INCREMNTED. IF THE ROW
; ROW VALUE LEAVES THE FIELD, THE CURSOR IS PLACED ON THE LAST ROW,
; FIRST COLUMN, AND THE ENTIRE SCREEN IS SCROLLED UP ONE LINE.
; WHEN THE SCREEN IS SCROLLED UP, THE ATTRIBUTE FOR FILLING THE
; NEWLY BLANKED LINE IS READ FROM THE CURSOR POSITION ON THE PREVIOUS
; LINE BEFORE THE SCROLL, IN CHARACTER MODE. IN GRAPHICS MODE,
; THE 0 COLOR IS USED.
; ENTRY --
; (AH) = CURRENT CRT MODE
; (AL) = CHARACTER TO BE WRITTEN
; NOTE THAT BACK SPACE, CAR RET, BELL AND LINE FEED ARE HANDLED
; AS COMMANDS RATHER THAN AS DISPLAYABLE GRAPHICS
; (BL) = FOREGROUND COLOR FOR CHAR WRITE IF CURRENTLY IN A GRAPHICS MODE
; EXIT --
; ALL REGISTERS SAVED
;---------------------------------------------
ASSUME CS:CODE,DS:DATA
WRITE_TTY PROC NEAR
PUSH AX ; SAVE REGISTERS
PUSH AX ; SAVE CHAR TO WRITE
MOV AH,3
INT 10H ; READ THE CURRENT CURSOR POSITION
POP AX ; RECOVER CHAR
;------ DX NOW HAS THE CURRENT CURSOR POSITION
CMP AL,8 ; IS IT A BACKSPACE
JE U8 ; BACK_SPACE
CMP AL,0DH ; IS IT CARRIAGE RETURN
JE U9 ; CAR_RET
CMP AL,0AH ; IS IT A LINE FEED
JE U10 ; LINE_FEED
CMP AL,07H ; IS IT A BELL
JE U11 ; BELL
;------ WRITE THE CHAR TO THE SCREEN
MOV BH,ACTIVE_PAGE ; GET THE CURRENT ACTIVE PAGE
MOV AH,10 ; WRITE CHAR ONLY
MOV CX,1 ; ONLY ONE CHAR
INT 10H ; WRITE THE CHAR
;------ POSITION THE CURSOR FOR NEXT CHAR
INC DL
CMP DL,BYTE PTR CRT_COLS ; TEST FOR COLUMN OVERFLOW
JNZ U7 ; SET CURSDR
MOV DL,0 ; COLUMN FOR CURSOR
CMP DH,24
JNZ U6 ; SET_CURSOR_INC
;------ SCROLL REQUIRED
U1:
MOV AH,2
MOV BH,0
INT 10H ; SET THE CURSOR
;------ DETERMINE VALUE TO FILL WITH DURING SCROLL
MOV AL,CRT_MODE ; GET THE CURRENT MODE
CMP AL,4
JC U2 ; READ_CURSOR
CMP AL,7
MOV BH,0 ; FILL WITH BACKGROUND
JNE U3 ; SCROLL_UP
U2: ; READ_CURSOR
MOV AH,8
INT 10H ; READ CHAR/ATTR AT CURRENT CURSOR
MOV BH,AH ; STORE IN BH
U3: ; SCROLL_UP
MOV AX,601H ; SCROLL ONE LINE
MOV CX,0 ; UPPER LEFT CORNER
MOV DH,24 ; LOWER RIGHT ROW
MOV DL,BYTE PTR CRT_COLS ; LOWER RIGHT COLUMN
DEC DL
U4: ; VIDEO_CALL_RETURN
INT 10H ; SCROLL UP THE SCREEN
U5: ; TTY-RETURN
POP AX ; RESTORE THE CHARACTER
JMP VIDEO_RETURN ; RETURN TO CALLER
U6: ; SET_CURSOR_INC
INC DH ; NEXT ROW
U7: ; SET_CURSOR
MOV AH,2
JMP U4 ; ESTABLISH THE NEW CURSOR
;------ BACK SPACE FOUND
U8:
CMP DL,0 ; ALREADY AT END OF LINE
JE U7 ; SET_CURSOR
DEC DL ; NO -- JUST MOVE IT BACK
JMP U7 ; SET_CURSOR
;------ CARRIAGE RETURN FOUND
U9:
MOV DL,0 ; MOVE TO FIRST COLUMN
JMP U7 ; SET_CURSOR
;------ LINE FEED FOUND
U10:
CMP DH,24 ; BOTTOM OF SCREEN
JNE U6 ; YES, SCROLL THE SCREEN
JMP U1 ; NO, JUST SET THE CURSOR
;------ BELL FOUND
U11:
MOV BL,2 ; SET UP COUNT FOR BEEP
CALL BEEP ; SOUND THE POD BELL
JMP U5 ; TTY_RETURN
WRITE_TTY ENDP
;-------------------------------------------
; LIGHT PEN
; THIS ROUTINE TESTS THE LIGHT PEN SWITCH AND THE LIGHT
; PEN TRIGGER. IF BOTH ARE SET, THE LOCATION OF THE LIGHT
; PEN IS DETERMINED. OTHERWISE, A RETURN WITH NO INFORMATION
; IS MADE.
; ON EXIT:
; (AH) = 0 IF NO LIGHT PEN INFORMATION IS AVAILABLE
; BX,CX,DX ARE DESTROYED
; (AH) = 1 IF LIGHT PEN IS AVAILABLE
; (DH,DL) = ROW,COLUMN OF CURRENT LIGHT PEN POSITION
; (CH) = RASTER POSITION
; (BX) = BEST GUESS AT PIXEL HORIZONTAL POSITION
;--------------------------------------------
ASSUME CS:CODE,DS:DATA
;------ SUBTRACT_TABLE
V1 LABEL BYTE
DB 3,3,5,5,3,3,3,4 ;
READ_LPEN PROC NEAR
;------ WAIT FOR LIGHT PEN TO BE DEPRESSED
MOV AH,0 ; SET NO LIGHT PEN RETURN CODE
MOV DX,ADDR_6845 ; GET BASE ADDRESS OF 6845
ADD DX,6 ; POINT TO STATUS REGISTER
IN AL,DX ; GET STATUS REGISTER
TEST AL,4 ; TEST LIGHT PEN SWITCH
JNZ V6 ; NOT SET, RETURN
;------ NOW TEST FOR LIGHT PEN TRIGGER
TEST AL,2 ; TEST LIGHT PEN TRIGGER
JZ V7 ; RETURN WITHOUT RESETTING TRIGGER
;------ TRIGGER HAS BEEN SET, READ THE VALUE IN
MOV AH,16 ; LIGHT PEN REGISTERS IN 6845
;------ INPUT REGS POINTED TO BY AH, AND CONVERT TO ROW COLUMN IN DX
MOV DX,ADDR_6845 ; ADDRESS REGISTER FOR 6845
MOV AL,AH ; REGISTER TO READ
OUT DX,AL ; SET IT UP
INC DX ; DATA REGISTER
IN AL,DX ; GET THE VALUE
MOV CH,AL ; SAVE IN CX
DEC DX ; ADDRESS REGISTER
INC AH
MOV AL,AH ; SECOND DATA REGISTER
OUT DX,AL
INC DX ; POINT TO DATA REGISTER
IN AL,DX ; GET SECOND DATA VALUE
MOV AH,CH ; AX HAS INPUT VALUE
;------ AX HAS THE VALUE READ IN FROM THE 6845
MOV BL,CRT_MODE
SUB BH,BH ; MODE VALUE TO BX
MOV BL,CS:V1[BX] ; DETERMINE AMOUNT TO SUBTRACT
SUB AX,BX ; TAKE IT AWAY
SUB AX,CRT_START ; CONVERT TO CORRECT PAGE ORIGIN
JNS V2 ; IF POSITIVE, DETERMINE MODE
MOV AX,0 ; <0 PLAYS AS 0
;------ DETERMINE MODE OF OPERATION
V2: ; DETERMINE_MODE
MOV CL,3 ; SET *8 SHIFT COUNT
CMP CRT_MODE,4 ; DETERMINE IF GRAPHICS OR ALPHA
JB V4 ; ALPHA_PEN
CMP CRT_MODE,7
JE V4 ; ALPHA_PEH
;------ GRAPHICS MODE
MOV DL,40 ; DIVISOR FCR GRAPHICS
DIV DL ; DETERMINE ROW(AL) AND COLUMN(AH)
; AL RANGE 0-99, AH RANGE 0-39
;------ DETERMINE GRAPHIC ROW POSITION
MOV CH,AL ; SAVE ROW VALUE IN CH
ADD CH,CH ; *2 FOR EVEN/ODD FIELD
MOV BL,AH ; COLUMN VALUE TO BX
SUB BH,BH ; MULTIPLY BY 8 FOR MEDIUM RES
CMP CRT_MODE,6 ; DETERMINE MEDIUM OR HIGH RES
JNE V3 ; NOT_HIGH_RES
MOV CL,4 ; SHIFT VALUE FOR HIGH RES
SAL AH,1 ; COLUMN VALUE TIMES 2 FOR HIGH RES
V3: ; NOT_HIGH_RES
SHL BX,CL ; MULTIPLY *16 FOR HIGH RES
;------ DETERMINE ALPHA CHAR POSITION
MOV DL,AH ; COLUMN VALUE FOR RETURN
MOV DH,AL ; ROW VALUE
SHR DH,1 ; DIVIDE BY 4
SHR DH,1 ; FOR VALUE IN 0-24 RANGE
JMP SHORT V5 ; LIGHT_PEN_RETURN_SET
;------ ALPHA MODE ON LIGHT PEN
V4: ; ALPHA_PEN
DIV BYTE PTR CRT_COLS ; DETERMINE ROW,COLUMN VALUE
MOV DH,AL ; ROWS TO DH
MOV DL,AH ; COLS TO DL
SAL AL,CL ; MULTIPLY ROWS *8
MOV CH,AL ; GET RASTER VALUE TO RETURN REG
MOV BL,AH ; COLUMN VALUE
XOR BH,BH ; TO BX
SAL BX,CL
V5: ; LIGHT_PEN_RETURN_SET
MOV AH,1 ; INDICATE EVERTHING SET
V6: ; LIGHT_PEN_RETURN
PUSH DX ; SAVE RETURN VALUE (IN CASE)
MOV DX,ADDR_6845 ; GET BASE ADDRESS
ADD DX,7 ; POINT TO RESET PARM
OUT DX,AL ; ADDRESS, NOT DATA, IS IMPORTANT
POP DX ; RECOVER VALUE
V7: ; RETURN_NO_RESET
POP DI
POP SI
POP DS ; DISCARD SAVED BX,CX,DX
POP DS
POP DS
POP DS
POP ES
IRET
READ_LPEN ENDP
;--- INT 12 ---------------------------------
; MEMORY_SIZE_DETERMINE
; THIS ROUTINE DETERMINES THE AMOUNT OF MEMORY IN THE SYSTEM
; AS REPRESENTED BY THE SWITCHES ON THE PLANAR. NOTE THAT
; THE SYSTEM MAY NOT BE ABLE TO USE I/O MEMORY UNLESS THERE
; IS A FULL COMPLEMENT OF 64K BYTES ON THE PLANAR.
; INPUT
; NO REGISTERS
; THE MEMOEY_SIZE VARIABLE IS SET DURING POWER ON DIAGNOSTICS
; ACCORDING TO THE FOLLOWING HARDWARE ASSUMPTIONS:
; PORT 60 BITS 3,2 = 00 - 16K BASE RAM
; 01 - 32K BASE RAM
; 10 - 48K BASE RAM
; 11 - 64K BASE RAM
; PORT 62 BITS 3-0 INDICATE AMOUNT OF I/O RAM IN 32K INCREMENTS
; E.G., 0000 - NO RAM IN I/O CHANNEL
; 0010 - 64K RAM IN I/O CHANNEL, ETC.
; OUTPUT
; (AX) = NUMBER OF CONTIGUOUS 1K BLOCKS OF MEMORY
;--------------------------------------------
ASSUME CS:CODE,DS:DATA
MEMORY_SIZE_DETERMINE PROC FAR
STI ; INTERRUPTS BACK ON
PUSH DS ; SAVE SEGMENT
MOV AX,DATA ; ESTABLISH ADDRESSING
MOV DS,AX
MOV AX,MEMORY_SIZE ; GET VALUE
POP DS ; RECOVER SEGMENT
IRET ; RETURN TO CALLER
MEMORY_SIZE_DETERMINE ENDP
;--- INT 11 -----------------------------------
; EQUIPMENT DETERMINATION
; THIS ROUTINE ATTEMPTS TO DETERMINE WHAT OPTIONAL
; DEVICES ARE ATTACHED TO THE SYSTEM.
; INPUT
; NO REGISTERS
; THE EQUIP_FLAG VARIABLE IS SET DURING THE POWER ON DIAGNOSTICS
; USING THE FOLLOWING HARDWARE ASSUMPTIONS:
; PORT 60 = LOW ORDER BYTE OF EQUIPMENT
; PORT 3FA = INTERRUPT ID REGISTER OF 8250
; BITS 7-3 ARE ALWAYS 0
; PORT 378 = OUTPUT PORT OF PRINTER -- 8255 PORT THAT
; CAN BE READ AS WELL AS WRITTEN
; OUTPUT
; (AX) IS SET, BIT SIGNIFICANT, TO INDICATE ATTACHED I/O
; BIT 15,14 = NUMBER OF PRINTERS ATTACHED
; BIT 13 NOT USED
; BIT 12 = GAME I/O ATTACHED
; BIT 11,10,9 = NUMBER OF RS232 CARDS ATTACHED
; BIT 8 UNUSED
; BIT 7,6 = NUMBER OF DISKETTE DRIVES
; 00=1, 01=2, 10-3, 11=4 ONLY IF BIT 0 = 1
; BIT 5,4 = INITIAL VIDEO MODE
; 00 - UNUSED
; 01 - 40x25 BW USING COLOR CARD
; 10 - 80X25 BW USING COLOR CARD
; 11 - 80x25 BW USING BW CARD
; BIT 3,2 = PLANAR RAM SIZE (00=16K,01=32K,10=48K,11=64K)
; BIT 1 NOT USED
; BIT 0 = IPL FROM DISKETTE -- THIS BIT INDICATES THAT THERE ARE DISKETTE
; DRIVES ON THE SYSTEM
;
; NO OTHER REGISTERS AFFECTED
;---------------------------------------------
ASSUME CS:CODE,DS:DATA
EQUIPMENT PROC FAR
STI ; INTERRUPTS BACK ON
PUSH DS ; SAVE SEGMENT REGISTER
MOV AX,DATA ; ESTABLISH ADDRESSING
MOV DS,AX
MOV AX,EQUIP_FLAG ; GET THE CURRENT SETTINGS
POP DS ; RECOVER SEGMENT
IRET ; RETURN TO CALLER
EQUIPMENT ENDP
;--- INT 15 --------------------------------
; CASSETTE I/O
; (AH) = 0 TURN CASSETTE MOTOR ON
; (AH) = 1 TURN CASSETTE MOTOR OFF
; (AH) = 2 READ 1 OR MORE 256 BYTE BLOCKS FROM CASSETTE
; (ES,BX) = POINTER TO DATA BUFFER
; (CX) = COUNT OF BYTES TO READ
; ON EXIT:
; (ES,BX) = POINTER TO LAST BYTE READ + 1
; (DX) = COUNT OF BYTES ACTUALLY READ
; (CY) = 0 IF NO ERROR OCCURRED
; = 1 IF ERROR OCCURRED
; (AH) = ERROR RETURN IF (CY)= 1
; = 01 IF CRC ERROR WAS DETECTED
; = 02 IF DATA TRANSITIONS ARE LOST
; = 04 IF NO DATA WAS FOUND
; (AH) = 3 WRITE 1 OR MORE 256 BYTE BLOCKS TO CASSETTE
; (ES,BX) = POINTER TO DATA BUFFER
; (CX) = COUNT OF BYTES TO WRITE
; ON EXIT:
; (EX,BX) = POINTER TO LAST BYTE WRITTEN + 1
; (CX) = 0
; (AH) = ANY OTHER THAN ABOVE VALUES CAUSES (CY)= 1
; AND (AH)= 80 TO BE RETURNED (INVALID COMMAND).
;--------------------------------------------
ASSUME DS:DATA,ES:NOTHING,SS:NOTHING,CS:CODE
CASSETTE_IO PROC FAR
STI ; INTERRUPTS BACK ON
PUSH DS ; ESTABLISH ADDRESSING TO DATA
PUSH AX
MOV AX,DATA
MOV DS,AX
AND BIOS_BREAK, 7FH ; MAKE SURE BREAK FLAG IS OFF
POP AX
CALL W1 ; CASSETTE_IO_CONT
POP DS
RET 2 ; INTERRUPT RETURN
CASSETTE_IO ENDP
W1 PROC NEAR
;--------------------------------------------
; PURPOSE:
; TO CALL APPROPRIATE ROUTINE DEPENDING ON REG AH
;
; AH ROUTINE
;--------------------------------------------
; 0 MOTOR ON
; 1 MOTOR OFF
; 2 READ CASSETTE BLOCK
; 3 WRITE CASSETTE BLOCK
;--------------------------------------------
OR AH,AH ;TURN ON MOTOR?
JZ MOTOR_ON ;YES, DO IT
DEC AH ;TURN OFF MOTOR?
JZ MOTOR_OFF ;YES, DO IT
DEC AH ;READ CASSETTE BLOCK?
JZ READ_BLOCK ;YES, DO IT
DEC AH ;WRITE CASSETTE BLOCK?
JNZ W2 ; NOT_DEFINED
JMP WRITE_BLOCK ;YES, DO IT
W2: ;COMMAND NOT DEFINED
MOV AH,080H ;ERROR, UNDEFINED OPERATION
STC ;ERROR FLAG
RET
W1 ENDP
MOTOR_ON PROC NEAR
;--------------------------------
; PURPOSE:
; TO TURN ON CASSETTE MOTOR
;---------------------------------
IN AL,PORT_B ;READ CASSETTE OUTPUT
AND AL,NOT 08H ; CLEAR BIT TO TURN ON MOTOR
W3: OUT PORT_B,AL ;WRITE IT OUT
SUB AH,AH ;CLEAR AH
RET
MOTOR_ON ENDP
MOTOR_OFF PROC NEAR
;----------------------------------
; PURPOSE:
; TO TURN CASSETTE MOTOR OFF
;-----------------------------------
IN AL,PORT_B ;READ CASSETTE OUTPUT
OR AL,08H ; SET BIT TO TURN OFF
JMP W3 ;WRITE IT, CLEAR ERROR, RETURN
MOTOR_OFF ENDP
READ_BLOCK PROC NEAR
;--------------------------------------------
; PURPOSE:
; TO READ 1 OR MORE 256 BYTE BLOCKS FROM CASSETTE
;
; ON ENTRY:
; ES IS SEGMENT FOR MEMORY BUFFER (FOR COMPACT CODE)
; BX POINTS TO START OF MEMORY BUFFER
; CX CONTAINS NUMBER OF BYTES TO READ
; ON EXIT:
; BX POINTS 1 BYTE PAST LAST BYTE PUT IN MEM
; CX CONTAINS DECREMENTED BYTE COUNT
; DX CONTAINS NUMBER OF BYTES ACTUALLY READ
;
; CARRY FLAG IS CLEAR IF NO ERROR DETECTED
; CARRY FLAG IS SET IF CRC ERROR DETECTED
;--------------------------------------------
PUSH BX ;SAVE BX
PUSH CX ;SAVE CX
PUSH SI ; SAVE SI
MOV SI,7 ; SET UP RETRY COUNT FOR LEADER
CALL BEGIN_OP ; BEGIN BY STARTING MOTOR
W4: ; SEARCH FOR LEADER
IN AL,PORT_C ;GET INTIAL VALUE
AND AL,010H ;MASK OFF EXTRANEOUS BITS
MOV LAST_VAL,AL ;SAVE IN LOC LAST_VAL
MOV DX,16250 ; # OF TRANSITIONS TO LOOK FOR
W5: ; WAIT_FOR_EDGE
TEST BIOS_BREAK,80H ; CHECK FOR BREAK KEY
JZ W6 ; JUMP IF NO BREAK KEY
JMP W17 ; JUMP IF BREAK KEY HIT
W6: DEC DX
JNZ W7 ; JUMP IF BEGINNING OF LEADER
JMP W17 ; JUMP IF NO LEADER FOUND
W7: CALL READ_HALF_BIT ;IGNORE FIRST EDGE
JCXZ W5 ; JUMP IF NO EDGE DETECTED
MOV DX,0378H ; CHECK FOR HALF BITS
MOV CX,200H ;MUST HAVE AT LEAST THIS MANY ONE SIZE
;PULSES BEFORE CHECKNG FOR SYNC BIT (0)
IN AL,021H ; INTERRUPT MASK REGISTER
OR AL,1 ; DISABLE TIMER INTERRUPTS
OUT 021H,AL
W8: ; SEARCH_LDR
TEST BIOS_BREAK,80H ; CHECK FOR BREAK KEY
JNZ W17 ; JUMP IF BREAK KEY HIT
PUSH CX ;SAVE REG CX
CALL READ_HALF_BIT ;GET PULSE WIDTH
OR CX,CX ; CHECK FOR TRANSITION
POP CX ;RESTORE ONE BIT COUNTER
JZ W4 ; JUMP IF NO TRANSITION
CMP DX,BX ;CHECK PULSE WIDTH
JCXZ W9 ;IF CX=0 THEN WE CAN LOOK
;FOR SYNC BIT (0)
JNC W4 ; JUMP IF ZERO BIT (NOT GOOD LEADER)
LOOP W8 ;DEC CX AND READ ANOTHER HALF ONE BIT
W9: ; FIND_SYNC
JC W8 ; JUMP IF ONE BIT (STILL LEADER)
; A SYNCH BIT HAS BEEN FOUND. READ SYN CHARACTER:
CALL READ_HALF_BIT ;SKIP OTHER HALF OF SYNC BIT (0)
CALL READ_BYTE ; READ SYN BYTE
CMP AL,16H ; SYNCHRONIZATION CHARACTER
JNE W16 ; JUMP IF BAD LEADER FOUND.
;------ GOOD CRC SO READ DATA BLOCK(S)
POP SI ; RESTORE REGS
POP CX
POP BX
;--------------------------------------------
; READ 1 OR MORE 256 BYTE BLOCKS FROM CASSETTE
;
; ON ENTRY:
; ES IS SEGMENT FOR MEMORY BUFFER (FOR COMPACT CODE)
; BX POINTS TO START OF MEMORY BUFFER
; CX CONTAINS NUMBER OF BYTES TO READ
; ON EXIT:
; BX POINTS 1 BYTE PAST LAST BYTE PUT IN MEM
; CX CONTAINS DECREMENTED BYTE COUNT
; DX CONTAINS NUMBER OF BYTES ACTUALLY READ
;--------------------------------------------
PUSH CX ;SAVE BYTE COUNT
W10: ;COME HERE BEFORE EACH
;256 BYTE BLOCK IS READ
MOV CRC_REG,0FFFFH ;INIT CRC REG
MOV DX,256 ;SET CX TO DATA BLOCK SIZE
W11: ; RD_BLK
TEST BIOS_BREAK,80H ; CHECK FOR BREAK KEY
JNZ W13 ; JUMP IF BREAK KEY HIT
CALL READ_BYTE ;READ BYTE FROM CASSETTE
JC W13 ;CY SET INDICATES NO DATA TRANSITIONS
JCXZ W12 ;IF WE'VE ALREADY REACHED
;END OF MEMORY BUFFER
;SKIP REST OF BLOCK
MOV ES:[BX],AL ;STORE DATA BYTE AT BYTE PTR
INC BX ;INC BUFFER PTR
DEC CX ;DEC BYTE CCUNTER
W12: ; LOOP UNTIL DATA BLOCK HAS BEEN READ FROM CASSETTE.
DEC DX ;DEC BLOCK CNT
JG W11 ; RD_BLK
CALL READ_BYTE ;NOW READ TWO CRC BYTES
CALL READ_BYTE
SUB AH,AH ;CLEAR AN
CMP CRC_REG,1D0FH ;IS THE CRC CORRECT
JNE W14 ;IF NOT EQUAL CRC IS BAD
JCXZ W15 ;IF BYTE COUNT IS ZERO
;THEN WE HAVE READ ENOUGH
;SO WE WILL EXIT
JMP W10 ;STILL MORE, SO READ ANOTHER BLOCK
W13: ;MISSING_DATA
;NO DATA TRANSITIONS SO
MOV AH,01H ;SET AH=02 TO INDICATE
;DATA TIMEOUT
W14: ; BAD_CRC
INC AH ;EXIT EARLY ON ERROR
;SET AH=01 TO INDICATE CRC ERROR
W15: ; RD_BLK_EX
POP DX ;CALCULATE COUNT OF
SUB DX,CX ;DATA BYTES ACTUALLY READ
;RETURN COUNT IN REG DX
PUSH AX ;SAVE AX (RET CODE)
TEST AH,03H ; CHECK FOR ERRORS
JNZ W18 ; JUMP IF ERROR DETECTED
CALL READ_BYTE ;READ TRAILER
JMP SHORT W18 ;SKIP TO TURN OFF MOTOR
W16: ; BAD_LEADER
DEC SI ; CHECK RETRIES
JZ W17 ; JUMP IF TOO MANY RETRIES
JMP W4 ; JUMP IF NOT TOO MANY RETRIES
W17: ;NO VALID DATA FOUND
;------ NO DATA FROM CASSETTE ERROR, I.E. TIMEOUT
POP SI ; RESTORE REGS
POP CX ;RESTORE REGS
POP BX
SUB DX,DX ;ZERO NUMBER OF BYTES READ
MOV AH,04H ;TIME OUT ERROR (NO LEADER)
PUSH AX
W18: ; MOT_OFF
IN AL,021H ; RE_ENABLE INTERRUPTS
AND AL,0FFH-1
OUT 021H,AL
CALL MOTOR_OFF ;TURN OFF MOTOR
POP AX ;RESTORE RETURN CODE
CMP AH,01H ;SET CARRY IF ERROR (AH>0)
CMC
RET ;FINISHED
READ_BLOCK ENDP
;------------------------------------------
READ_BYTE PROC NEAR
; PURPOSE:
; TO READ A BYTE FROM CASSETTE
;
; ON EXIT REG AL CONTAINS READ DATA BYTE
;-------------------------------------------
PUSH BX ;SAVE REGS BX,CX
PUSH CX
MOV CL,8H ; SET BIT COUNTER FOR 8 BITS
W19: ; BYTE_ASM
PUSH CX ; SAVE CX
;-------------------------------------------
; READ DATA BIT FROM CASSETTE
;-------------------------------------------
CALL READ_HALF_BIT ;READ ONE PULSE
JCXZ W21 ;IF CX=0 THEN TIMEOUT
;BECAUSE OF NO DATA TRANSITIONS
PUSH BX ;SAVE 1ST HALF BIT'S
;PULSE WIDTH (IN BX)
CALL READ_HALF_BIT ;READ COMPLEMENTARY PULSE
POP AX ;COMPUTE DATA BIT
JCXZ W21 ;IF CX=0 THEN TIMEOUT DUE TO
;NO DATA TRANSITIONS
ADD BX,AX ;PERIOD
CMP BX,06F0H ; CHECK FOR ZERO BIT
CMC ; CARRY IS SET IF ONE BIT
LAHF ;SAVE CARRY IN AH
POP CX ;RESTORE CX
;NOTE:
; MS BIT OF BYTE IS READ FIRST.
; REG CH IS SHIFTED LEFT WITH
; CARRY BEING INSERTED INTO LS
; BIT OF CH.
; AFTER ALL 8 BITS HAVE BEEN
; READ, THE MS BIT QF THE DATA BYTE
; WILL BE IN THE MS BIT OF REG CH
RCL CH,1 ;ROTATE REG CH LEFT WITH CARRY TO
; LS BIT OF REG CH
SAHF ;RESTORE CARRY FOR CRC ROUTINE
CALL CRC_GEN ;GENERATE CRC FOR BIT
DEC CL ;LOOP TILL ALL 8 BITS OF DATA
;ASSEMBLED IN REG CH
JNZ W19 ; BYTE_ASM
MOV AL,CH ;RETURN DATA BYTE IN REG AL
CLC
W20: ; RD_BYT_EX
POP CX ;RESTORE REGS CX,BX
POP BX
RET ;FINISHED
W21: ; NO_DATA
POP CX ;RESTORE CX
STC ;INCICATE ERROR
JMP W20 ; RD_BYT_EX
READ_BYTE ENDP
;--------------------------------------------
READ_HALF_BIT PROC NEAR
; PURPOSE
; TO COMPUTE TIME TILL NEXT DATA
; TRANSITION (EDGE)
;
; ON ENTRY:
; EDGE_CNT CONTAINS LAST EDGE COUNT
;
; ON EXIT:
; AX CONTAINS OLD LAST EDGE COUNT
; BX CONTAINS PULSE WIDTH (HALF BIT)
;----------------------------------------
MOV CX,100 ; SET TIME TO WAIT FOR BIT
MOV AH,LAST_VAL ;GET PRESENT INPUT VALUE
W22: ; RD_H_BIT
IN AL,PORT_C ;INPUT DATA BIT
AND AL,010H ;MASK OFF EXTRANEOUS BITS
CMP AL,AH ;SAME AS BEFORE?
LOOPE W22 ;LOOP TILL IT CHANGES
MOV LAST_VAL,AL ;UPDATE LAST_VAL WITH NEW VALUE
MOV AL,0 ;READ TIMER'S COUNTER COMMAND
OUT TIM_CTL,AL ;LATCH COUNTER
IN AL,TIMER0 ;GET LS BYTE
MOV AH,AL ;SAVE IN AH
IN AL,TIMER0 ;GET MS BYTE
XCHG AL,AH ;XCHG AL,AH
MOV BX,EDGE_CNT ;BX GETS LAST EDGE COUNT
SUB BX,AX ;SET BX EQUAL TO HALF BIT PERIOD
MOV EDGE_CNT,AX ;UPDATE EDGE COUNT
RET
READ_HALF_BIT ENDP
;-----------------------------------------
WRITE_BLOCK PROC NEAR
;
; WRITE 1 OR MORE 256 BYTE BLOCKS TO CASSETTE.
; THE DATA IS PADDED TO FILL OUT THE LAST 256 BYTE BLOCK.
;
; ON ENTRY:
; BX POINTS TO MEMORY BUFFER ADDRESS
; CX CONTAINS NUMBER OF BYTES TO WRITE
;
; ON EXIT:
; BX POINTS 1 BYTE PAST LAST BYTE WRITTEN TO CASSETTE
; CX IS ZERO
;--------------------------------------------
PUSH BX
PUSH CX
IN AL,PORT_B ;DISABLE SPEAKER
AND AL,NOT 02H
OR AL,01H ; ENABLE TIMER
OUT PORT_B,AL
MOV AL,0B6H ; SET UP TIMER -- MODE 3 SOUARE WAVE
OUT TIM_CTL,AL
CALL BEGIN_OP ; START MOTOR AND DELAY
MOV AX,1184 ; SET NORMAL BIT SIZE
CALL W31 ; SET_TIMER
MOV CX,0800H ;SET CX FOR LEADER BYTE COUNT
W23: ; WRITE LEADER
STC ; WRITE ONE BITS
CALL WRITE_BIT ;
LOOP W23 ; LOOP 'TIL LEADER IS WRITTEN
CLC ;WRITE SYNC BIT (0)
CALL WRITE_BIT
POP CX ;RESTORE REGS CX,BX
POP BX
MOV AL,16H ; WRITE SYN CHARACTER
CALL WRITE_BYTE ;
;-------------------------------------------
; WRITE 1 OR MORE 256 BYTE BLOCKS TO CASSETTE
;
; ON ENTRY:
; BX POINTS TO MEMORY BUFFER ADDRESS
; CX CONTAINS NUMBER OF BYTES TO WRITE
;
; ON EXIT:
; BX POINTS 1 BYTE PAST LAST BYTE WRITTEN TO CASSETTE
; CX IS ZERO
;------------------------------------------
WR_BLOCK:
MOV CRC_REG,0FFFFH ;INIT CRC
MOV DX,256 ;FOR 256 BYTES
W24: ; WR_BLK
MOV AL,ES:[BX] ;READ BYTE FROM MEM
CALL WRITE_BYTE ;WRITE IT TO CASSETTE
JCXZ W25 ;UNLESS CX=0, ADVANCE PTRS & DEC COUNT
INC BX ;INC BUFFER POINTER
DEC CX ;DEC BYTE COUNTER
W25: ; SKIP_ADV
DEC DX ;DEC BLOCK CNT
JG W24 ;LOOP TILL 256 BYTE BLOCK
; IS WRITTEN TO TAPE
;------------------ WRITE CRC --------------
; WRITE 1'S COMPLEMENT OF CRC REG TO CASSETTE
; WHICH IS CHECKEC FOR CORRECTNESS WHEN THE BLOCK IS READ
;
; REG AX IS MODIFIED
;-----------------------------------------
MOV AX,CRC_REG ;WRITE THE ONE'S COMPLEMENT OF THE
; TWO BYTE CRC TO TAPE
NOT AX ;FOR 1'S COMPLEMENT
PUSH AX ;SAVE IT
XCHG AH,AL ;WRITE MS BYTE FIRST
CALL WRITE_BYTE ;WRITE IT
POP AX ;GET IT BACK
CALL WRITE_BYTE ;NOW WRITE LS BYTE
OR CX,CX ;IS BYTE COUNT EXHAUSTED?
JNZ WR_BLOCK ;JUMP IF NOT DONE YET
PUSH CX ;SAVE REG CX
MOV CX,32 ;WRITE OUT TRAILER BITS
W26: ; TRAIL_LOOP
STC
CALL WRITE_BIT
LOOP W26 ; WRITE UNTIL TRAILER WRITTEN
POP CX ;RESTORE REG CX
MOV AL,0B0H ; TURN TIMER2 OFF
OUT TIM_CTL,AL
MOV AX,1
CALL W31 ; SET_TIMER
CALL MOTOR_OFF ;TURN MOTOR OFF
SUB AX,AX ;NO ERRORS REPORTED ON WRITE OP
RET ;FINISHED
WRITE_BLOCK ENDP
;------------------------------------------
WRITE_BYTE PROC NEAR
; WRITE A BYTE TO CASSETTE.
; BYTE TO WRITE IS IN REG AL.
;--------------------------------------------
PUSH CX ;SAVE REGS CX,AX
PUSH AX
MOV CH,AL ;AL=BYTE TO WRITE.
; (MS BIT WRITTEN FIRST)
MOV CL,8 ;FOR 8 DATA BITS IN BYTE.
; NOTE: TWO EDGES PER BIT
W27: ; DISASSEMBLE THE DATA BIT
RCL CH,1 ;ROTATE MS BIT INTO CARRY
PUSHF ;SAVE FLAGS.
; NOTE: DATA BIT IS IN CARRY
CALL WRITE_BIT ;WRITE DATA BIT
POPF ;RESTORE CARRY FOR CRC CALC
CALL CRC_GEN ;COMPUTE CRC ON DATA BIT
DEC CL ;LOOP TILL ALL 8 BITS DONE
JNZ W27 ; JUMP IF NOT DONE YET
POP AX ;RESTORE REGS AX,CX
POP CX
RET ;WE ARE FINISHED
WRITE_BYTE ENDP
;-------------------------------------
WRITE_BIT PROC NEAR
; PURPOSE:
;
; TO WRITE A DATA BIT TO CASSETTE
; CARRY FLAG CONTAINS DATA BIT
; I.E. IF SET DATA BIT IS A ONE
; IF CLEAR DATA BIT IS A ZERO
;
; NOTE: TWO EDGES ARE WRITTEN PER BIT
; ONE BIT HAS 500 USEC BETWEEN EDGES
; FOR A 1000 USEC PERIOD (1 MILLISEC)
;
; ZERO BIT HAS 250 USEC BETWEEN EDGES
; FOR A 500 USEC PERIOD (.5 MILLISEC)
; CARRY FLAG IS DATA BIT
;------------------------------------------
;ASSUME IT'S A '1'
MOV AX,1184 ; SET AX TO NOMINAL ONE SIZE
JC W28 ; JUMP IF ONE BIT
MOV AX,592 ; NO, SET TO NOMINAL ZERO SIZE
W28: ; WRITE_BIT_AX
PUSH AX ;WRITE BIT WITH PERIOD EQ TO VALUE AX
W29:
IN AL,PORT_C ;INPUT TIMER_0 OUTPUT
AND AL,020H
JZ W29 ;LOOP TILL HIGH
W30:
IN AL,PORT_C ;NOW WAIT TILL TIMER'S OUTPUT IS LOW
AND AL,020H
JNZ W30
;RELOAD TIMER WITH PERIOD
;FOR NEXT DATA BIT
POP AX ;RESTORE PERIOD COUNT
W31: ; SET TIMER
OUT 042H,AL ; SET LOW BYTE OF TIMER 2
MOV AL,AH
OUT 042H,AL ; SET HIGH BYTE OF TIMER 2
RET
WRITE_BIT ENDP
;----------------------------------------
CRC_GEN PROC NEAR
; UPDATE CRC REGISTER WITH NEXT DATA BIT
;
; CRC IS USED TO DETECT READ ERRORS
;
; ASSUMES DATA BIT IS IN CARRY
;
; REG AX IS MODIFIED
; FLAGS ARE MODIFIED
;----------------------------------------
MOV AX,CRC_REG
;THE FOLLOWING INSTUCTIONS
;WILL SET THE OVERFLOW FLAG
;IF CARRY AND MS BIT OF CRC
;ARE UNEQUAL
RCR AX,1
RCL AX,1
CLC ;CLEAR CARRY
JNO W32 ;SKIP IF NO OVERFLOW
;IF DATA BIT XORED WITH
; CRC REG BIT 15 IS ONE
XOR AX,0810H ;THEN XOR CRC REG WITH
; 0810H
STC ;SET CARRY
W32:
RCL AX,1 ;ROTATE CARRY (DATA BIT)
; INTO CRC REG
MOV CRC_REG,AX ;UPDATE CRC_REG
RET ;FINISHED
CRC_GEN ENDP
;--------------------------------------------
BEGIN_OP PROC NEAR ; START TAPE AND DELAY
;
;--------------------------------------------
CALL MOTOR_ON ;TURN ON MOTOR
MOV BL,42H ;DELAY FOR TAPE DRIVE
;TO GET UP TO SPEED (1/2 SEC)
W33:
MOV CX,700H ;INNER LOOP= APPROX. 10 MILLISEC
W34: LOOP W34
DEC BL
JNZ W33
RET
BEGIN_OP ENDP
;----------------------------------------
; CHARACTER GENERATOR GRAPHICS FOR 320X200 AND 640X200 GRAPHICS
;----------------------------------------
CRT_CHAR_GEN LABEL BYTE
DB 000H,000H,000H,000H,000H,000H,000H,000H ; D_00
DB 07EH,081H,0A5H,081H,0BDH,099H,081H,07EH ; D_01
DB 07EH,0FFH,0DBH,0FFH,0C3H,0E7H,0FFH,07EH ; D_02
DB 06CH,0FEH,0FEH,0FEH,07CH,038H,010H,000H ; D_03
DB 010H,038H,07CH,0FEH,07CH,038H,010H,008H ; D_04
DB 038H,07CH,038H,0FEH,0FEH,07CH,038H,07CH ; D_05
DB 010H,010H,038H,07CH,0FEH,07CH,038H,07CH ; D_06
DB 000H,000H,018H,03CH,03CH,018H,000H,000H ; D_07
DB 0FFH,0FFH,0E7H,0C3H,0C3H,0E7H,0FFH,0FFH ; D_08
DB 000H,03CH,066H,042H,042H,066H,03CH,000H ; D_09
DB 0FFH,0C3H,099H,0BDH,0BDH,099H,0C3H,0FFH ; D_0A
DB 00FH,007H,00FH,07DH,0CCH,0CCH,0CCH,078H ; D_08
DB 03CH,066H,066H,066H,03CH,018H,07EH,018H ; D_0C
DB 03FH,033H,03FH,030H,030H,070H,0F0H,0E0H ; D_0D
DB 07FH,063H,07FH,063H,063H,067H,0E6H,0C0H ; D_0E
DB 099H,05AH,03CH,0E7H,0E7H,03CH,05AH,099H ; D_0F
DB 080H,0E0H,0F8H,0FEH,0F8H,0E0H,080H,000H ; D_10
DB 002H,00EH,03EH,0FEH,03EH,00EH,002H,000H ; D_11
DB 018H,03CH,07EH,018H,018H,07EH,03CH,018H ; D_12
DB 066H,066H,066H,066H,066H,000H,066H,000H ; D_13
DB 07FH,0DBH,0DBH,07BH,01BH,01BH,01BH,000H ; D_14
DB 03EH,063H,038H,06CH,06CH,038H,0CCH,078H ; D_15
DB 000H,000H,000H,000H,07EH,07EH,07EH,000H ; D_16
DB 018H,03CH,07EH,018H,07EH,03CH,018H,0FFH ; D_17
DB 018H,03CH,07EH,018H,018H,018H,018H,000H ; D_18
DB 018H,018H,018H,018H,07EH,03CH,018H,000H ; D_19
DB 000H,018H,00CH,0FEH,00CH,018H,000H,000H ; D_1A
DB 000H,030H,060H,0FEH,060H,030H,000H,000H ; D_1B
DB 000H,000H,0C0H,0C0H,0C0H,0FEH,000H,000H ; D_1C
DB 000H,024H,066H,0FFH,066H,024H,000H,000H ; D_1D
DB 000H,018H,03CH,07EH,0FFH,0FFH,000H,000H ; D_1E
DB 000H,0FFH,0FFH,07EH,03CH,018H,000H,000H ; D_1F
DB 000H,000H,000H,000H,000H,000H,000H,000H ; SP D_20
DB 030H,078H,078H,030H,030H,000H,030H,000H ; ! D_21
DB 06CH,06CH,06CH,000H,000H,000H,000H,000H ; " D_22
DB 06CH,06CH,0FEH,06CH,0FEH,06CH,06CH,000H ; # D_23
DB 030H,07CH,0C0H,078H,00CH,0F8H,030H,000H ; $ D_24
DB 000H,0C6H,0CCH,018H,030H,066H,0C6H,000H ; PER CENT D_25
DB 038H,06CH,038H,076H,0DCH,0CCH,076H,000H ; & D_26
DB 060H,060H,0C0H,000H,000H,000H,000H,000H ; ' D_27
DB 018H,030H,060H,060H,060H,030H,018H,000H ; ( D_28
DB 060H,030H,018H,018H,018H,030H,060H,000H ; ) D_29
DB 000H,066H,03CH,0FFH,03CH,066H,000H,000H ; * D_2A
DB 000H,030H,030H,0FCH,030H,030H,000H,000H ; + D_2B
DB 000H,000H,000H,000H,000H,030H,030H,060H ; , D_2C
DB 000H,000H,000H,0FCH,000H,000H,000H,000H ; - D_2D
DB 000H,000H,000H,000H,000H,030H,030H,000H ; . D_2E
DB 006H,00CH,018H,030H,060H,0C0H,080H,000H ; / D_2F
DB 07CH,0C6H,0CEH,0DEH,0F6H,0E6H,07CH,000H ; 0 D_30
DB 030H,070H,030H,030H,030H,030H,0FCH,000H ; 1 D_31
DB 078H,0CCH,00CH,038H,060H,0CCH,0FCH,000H ; 2 D_32
DB 078H,0CCH,00CH,038H,00CH,0CCH,078H,000H ; 3 D_33
DB 01CH,03CH,06CH,0CCH,0FEH,00CH,01EH,000H ; 4 D_34
DB 0FCH,0C0H,0F8H,00CH,00CH,0CCH,078H,000H ; 5 D_35
DB 038H,060H,0C0H,0F8H,0CCH,0CCH,078H,000H ; 6 D_36
DB 0FCH,0CCH,00CH,018H,030H,030H,030H,000H ; 7 D_37
DB 078H,0CCH,0CCH,078H,0CCH,0CCH,078H,000H ; 8 D_38
DB 078H,0CCH,0CCH,07CH,00CH,018H,070H,000H ; 9 D_39
DB 000H,030H,030H,000H,000H,030H,030H,000H ; : D_3A
DB 000H,030H,030H,000H,000H,030H,030H,060H ; ; D_3B
DB 018H,030H,060H,0C0H,060H,030H,018H,000H ; < D_3C
DB 000H,000H,0FCH,000H,000H,0FCH,000H,000H ; = D_3D
DB 060H,030H,018H,00CH,018H,030H,060H,000H ; > D_3E
DB 078H,0CCH,00CH,018H,030H,000H,030H,000H ; ? D_3F
DB 07CH,0C6H,0DEH,0DEH,0DEH,0C0H,078H,000H ; @ D_40
DB 030H,078H,0CCH,0CCH,0FCH,0CCH,0CCH,000H ; A D_41
DB 0FCH,066H,066H,07CH,066H,066H,0FCH,000H ; B D_42
DB 03CH,066H,0C0H,0C0H,0C0H,066H,03CH,000H ; C D_43
DB 0F8H,06CH,066H,066H,066H,06CH,0F8H,000H ; D D_44
DB 0FEH,062H,068H,078H,068H,062H,0FEH,000H ; E D_45
DB 0FEH,062H,068H,078H,068H,060H,0F0H,000H ; F D_46
DB 03CH,066H,0C0H,0C0H,0CEH,066H,03EH,000H ; G D_47
DB 0CCH,0CCH,0CCH,0FCH,0CCH,0CCH,0CCH,000H ; H D_48
DB 078H,030H,030H,030H,030H,030H,078H,000H ; I D_49
DB 01EH,00CH,00CH,00CH,0CCH,0CCH,078H,000H ; J D_4A
DB 0E6H,066H,06CH,078H,06CH,066H,0E6H,000H ; K D_4B
DB 0F0H,060H,060H,060H,062H,066H,0FEH,000H ; L D_4C
DB 0C6H,0EEH,0FEH,0FEH,0D6H,0C6H,0C6H,000H ; M D_4C
DB 0C6H,0E6H,0F6H,0DEH,0CEH,0C6H,0C6H,000H ; N D_4E
DB 038H,06CH,0C6H,0C6H,0C6H,06CH,038H,000H ; O D_4F
DB 0FCH,066H,066H,07CH,060H,060H,0F0H,000H ; P D_50
DB 078H,0CCH,0CCH,0CCH,0DCH,078H,01CH,000H ; Q D_51
DB 0FCH,066H,066H,07CH,06CH,066H,0E6H,000H ; R D_52
DB 078H,0CCH,0E0H,070H,01CH,0CCH,078H,000H ; S D_53
DB 0FCH,0B4H,030H,030H,030H,030H,078H,000H ; T D_54
DB 0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0FCH,000H ; U D_55
DB 0CCH,0CCH,0CCH,0CCH,0CCH,078H,030H,000H ; V D_56
DB 0C6H,0C6H,0C6H,0D6H,0FEH,0EEH,0C6H,000H ; W D_57
DB 0C6H,0C6H,06CH,038H,038H,06CH,0C6H,000H ; X D_58
DB 0CCH,0CCH,0CCH,078H,030H,030H,078H,000H ; Y D_59
DB 0FEH,0C6H,08CH,018H,032H,066H,0FEH,000H ; Z D_5A
DB 078H,060H,060H,060H,060H,060H,078H,000H ; [ D_5B
DB 0C0H,060H,030H,018H,00CH,006H,002H,000H ; BACKSLASH D_5C
DB 078H,018H,018H,018H,018H,018H,078H,000H ; ] D_5D
DB 010H,038H,06CH,0C6H,000H,000H,000H,000H ; CIRCUMFLEX D_5E
DB 000H,000H,000H,000H,000H,000H,000H,0FFH ; _ D_5F
DB 030H,030H,018H,000H,000H,000H,000H,000H ; D_60
DB 000H,000H,078H,00CH,07CH,0CCH,076H,000H ; LOWER CASE A D_61
DB 0E0H,060H,060H,07CH,066H,066H,0DCH,000H ; L.C. B D_62
DB 000H,000H,078H,0CCH,0C0H,0CCH,078H,000H ; L.C. C D_63
DB 01CH,00CH,00CH,07CH,0CCH,0CCH,076H,000H ; L.C. C D_64
DB 000H,000H,078H,0CCH,0FCH,0C0H,078H,000H ; L.C. E D_65
DB 038H,06CH,060H,0F0H,060H,060H,0F0H,000H ; L.C. F D_66
DB 000H,000H,076H,0CCH,0CCH,07CH,00CH,0F8H ; L.C. G D_67
DB 0E0H,060H,06CH,076H,066H,066H,0E6H,000H ; L.C. H D_68
DB 030H,000H,070H,030H,030H,030H,078H,000H ; L.C. I D_69
DB 00CH,000H,00CH,00CH,00CH,0CCH,0CCH,078H ; L.C. J D_6A
DB 0E0H,060H,066H,06CH,078H,06CH,0E6H,000H ; L.C. K D_6B
DB 070H,030H,030H,030H,030H,030H,078H,000H ; L.C. L D_6C
DB 000H,000H,0CCH,0FEH,0FEH,0D6H,0C6H,000H ; L.C. M D_6D
DB 000H,000H,0F8H,0CCH,0CCH,0CCH,0CCH,000H ; L.C. N D_6E
DB 000H,000H,078H,0CCH,0CCH,0CCH,078H,000H ; L.C. O D_6F
DB 000H,000H,0DCH,066H,066H,07CH,060H,0F0H ; L.C. P D_70
DB 000H,000H,076H,0CCH,0CCH,07CH,00CH,01EH ; L.C. Q D_71
DB 000H,000H,0DCH,076H,066H,060H,0F0H,000H ; L.C. R D_72
DB 000H,000H,07CH,0C0H,078H,00CH,0F8H,000H ; L.C. S D_73
DB 010H,030H,07CH,030H,030H,034H,018H,000H ; L.C. T D_74
DB 000H,000H,0CCH,0CCH,0CCH,0CCH,076H,000H ; L.C. U D_75
DB 000H,000H,0CCH,0CCH,0CCH,078H,030H,000H ; L.C. V D_76
DB 000H,000H,0C6H,0D6H,0FEH,0FEH,06CH,000H ; L.C. W D_77
DB 000H,000H,0C6H,06CH,038H,06CH,0C6H,000H ; L.C. X D_78
DB 000H,000H,0CCH,0CCH,0CCH,07CH,00CH,0F8H ; L.C. Y D_79
DB 000H,000H,0FCH,098H,030H,064H,0FCH,000H ; L.C. Z D_7A
DB 01CH,030H,030H,0E0H,030H,030H,01CH,000H ; D_7B
DB 018H,018H,018H,000H,018H,018H,018H,000H ; D_7C
DB 0E0H,030H,030H,01CH,030H,030H,0E0H,000H ; D_7D
DB 076H,0DCH,000H,000H,000H,000H,000H,000H ; D_7E
DB 000H,010H,038H,06CH,0C6H,0C6H,0FEH,000H ; DELTA D_7F
;--- INT 1A -------------------------------
; TIME_OF_DAY
; THIS ROUTINE ALLOWS THE CLOCK TO BE SET/READ
;
; INPUT
; (AH) = 0 READ THE CURRENT CLOCK SETTING
; RETURNS CX = HIGH PORTION OF COUNT
; DX = LOW PORTION OF COUNT
; AL = 0 IF TIMER HAS NOT PASSED 24 HOURS SINCE LAST READ
; <>0 IF ON ANOTHER DAY
; (AH) = 1 SET THE CURRENT CLOCK
; CX = HIGH PORTION OF COUNT
; DX = LOW PORTION OF COUNT
; NOTE: COUNTS OCCUR AT THE RATE OF 1193180/65536 COUNTS/SEC
; (OR ABOUT 18.2 PER SECOND -- SEE EQUATES BELOW)
;--------------------------------------------
ASSUME CS:CODE,DS:DATA
TIME_OF_DAY PROC FAR
STI ; INTERRUPTS BACK ON
PUSH DS ; SAVE SEGMENT
PUSH AX ; SAVE PARM
MOV AX,DATA
MOV DS,AX ; ESTABLISH ADDRESSING TO VALUES
POP AX ; GET BACK INPUT PARM
OR AH,AH ; AH=0
JZ T2 ; READ_TIME
DEC AH ; AH=1
JZ T3 ; SET_TIME
T1: ; TOD_RETURN
STI ; INTERRUPTS BACK ON
POP DS ; RECOVER SEGMENT
IRET ; RETURN TO CALLER
T2: ; READ_TIME
CLI ; NO TIMER INTERRUPTS WHILE READING
MOV AL,TIMER_OFL
MOV TIMER_OFL,0 ; GET OVERFLOW, AND RESET THE FLAG
MOV CX,TIMER_HIGH
MOV DX,TIMER_LOW
JMP T1 ; TOD_RETURN
T3: ; SET_TIME
CLI ; NO INTERRUPTS WHILE HRITING
MOV TIMER_LOW,DX
MOV TIMER_HIGH,CX ; SET THE TIME
MOV TIMER_OFL,0 ; RESET OVERFLOW
JMP T1 ; TOD_RETURN
TIME_OF_DAY ENDP
;--------------------------------------------
; THIS ROUTINE HANDLES THE TIMER INTERRUPT FROM
; CHANNEL 0 OF THE 8253 TIMER. INPUT FREQUENCY IS 1.19318 MHZ
; AND THE DIVISOR IS 65536, RESULTING IN APPROX. 18.2 INTERRUPTS
; EVERY SECOND.
;
; THE INTERRUPT HANDLER MAINTAINS A COUNT OF INTERRUPTS SINCE POWER
; ON TIME, WHICH MAY BE USED TO ESTABLISH TIME OF DAY.
; THE INTERRUPT HANDLER ALSO DECREMENTS THE MOTOR CONTROL COUNT
; OF THE DISKETTE, AND WHEN IT EXPIRES, WILL TURN OFF THE DISKETTE
; MOTOR, AND RESET THE MOTOR RUNNING FLAGS
; THE INTERRUPT HANDLER WILL ALSO INVOKE A USER ROUTINE THROUGH INTERRUPT
; 1CH AT EVERY TIME TICK. THE USER MUST CODE A ROUTINE AND PLACE THE
; CORRECT ADDRESS IN THE VECTOR TABLE.
;-------------------------------------------
TIMER_INT PROC FAR
STI ; INTERRUPTS BACK ON
PUSH DS
PUSH AX
PUSH DX ; SAVE MACHINE STATE
MOV AX,DATA
MOV DS,AX ; ESTABLISH ADDRESSABILITY
INC TIMER_LOW ; INCREMENT TIME
JNZ T4 ; TEST_DAY
INC TIMER_HIGH ; INCREMENT HIGH WORD OF TIME
T4: ; TEST_DAY
CMP TIMER_HIGH,018H ; TEST FOR COUNT EQUALLING 24 HOURS
JNZ T5 ; DISKETTE_CTL
CMP TIMER_LOW,0B0H
JNZ T5 ; DISKETTE_CTL
;------ TIMER HAS GONE 24 HOURS
MOV TIMER_HIGH,0
MOV TIMER_LOW,0
MOV TIMER_OFL,1
;------ TEST FOR DISKETTE TIME OUT
T5: ; DISKETTE_CTL
DEC MOTOR_COUNT
JNZ T6 ; RETURN IF COUNT NOT OUT
AND MOTOR_STATUS,0F0H ; TURN OFF MOTOR RUNNING BITS
MOV AL,0CH
MOV DX,03F2H ; FDC_CTL_PORT
OUT DX,AL ; TURN OFF THE MOTOR
T6: ; TIMER_RET:
INT 1CH ; TRANSFER CONTROL TO A USER ROUTINE
MOV AL,EOI
OUT 020H,AL ; END OF INTERRUPT TO 8259
POP DX
POP AX
POP DS ; RESET MACHINE STATE
IRET ; RETURN FROM INTERRUPT
TIMER_INT ENDP
;--------------------------------------------
; THESE ARE THE VECTORS WHICH ARE MOVED INTO
; THE 8086 INTEPRUPT AREA DURING POWER ON
;--------------------------------------------
VECTOR_TABLE LABEL WORD ; VECTOR TABLE FOR MOVE TO INTERRUPTS
DW OFFSET TIMER_INT ; INTERRUPT 8
DW CODE
DW OFFSET KB_INT ; INTERRUPT 9
DW CODE
DD 0 ; INTERRUPT A
DD 0 ; INTERRUPT B
DD 0 ; INTERRUPT C
DD 0 ; INTERRUPT D
DW OFFSET DISK_INT ; INTERRUPT E
DW CODE
DD 0 ; INTERRUPT F
DW OFFSET VIDEO_IO ; INTERRUPT 10H
DW CODE
DW OFFSET EQUIPMENT ; INTERRUPT 11H
DW CODE
DW OFFSET MEMORY_SIZE_DETERMINE ; INT 12H
DW CODE
DW OFFSET DISKETTE_IO ; INTERRUPT 13H
DW CODE
DW OFFSET RS232_IO ; INTERRUPT 14H
DW CODE
DW OFFSET CASSETTE_IO ; INTERRUPT 15H
DW CODE
DW OFFSET KEYBOARD_IO ; INTERRUPT 16H
DW CODE
DW OFFSET PRINTER_IO ; INTERRUPT 17H
DW CODE
DW 00000H ; INTERRUPT 18H
DW 0F600H ; ROM BASIC ENTRY POINT
DW OFFSET BOOT_STRAP ; INTERRUPT 19H
DW CODE
DW TIME_OF_DAY ; INTERRUPT 1AH -- TIME OF DAY
DW CODE
DW DUMMY_RETURN ; INTERRUPT 1BH -- KEYBOARD BREAK ADDR
DW CODE
DW DUMMY_RETURN ; INTERRUPT 1CH -- TIMER BREAK ADDR
Dw CODE
DW VIDEO_PARMS ; INTERRUPT 1DH -- VIDEO PARAMETERS
DW CODE
DW OFFSET DISK_BASE ; INTERRUPT 1EH -- DISK PARMS
DW CODE
DD 0 ; INTERRUPT 1FH -- POINTER TO VIDEO EXT
DUMMY_RETURN:
IRET ; DUMMY RETURN FOR BREAK FROM KEYBOARD
;-- INT 5 ----------------------------------
; THIS LOGIC WILL BE INVOKED BY INTERRUPT 05H TO FRINT
; THE SCREEN. THE CURSOR POSITION AT THE TIME THIS ROUTINE
; IS INVOKED WILL BE SAVED AND RESTORED UPON COMPLETION. THE
; ROUTINE IS INTENDED TO RUN WITH INTERRUPTS ENABLED.
; IF A SUBSEQUENT 'PRINT SCREEN KEY IS DEPRESSED DURING THE
; TIME THIS ROUTINE IS PRINTING IT WILL BE IGNORED.
; ADDRESS 50:0 CONTAINS THE STATUS OF THE PRINT SCREEN:
;
; 50:0 =0 EITHER PRINT SCREEN HAS NOT BEEN CALLED
; OR UPON RETURN FROM A CALL THIS INDICATES
; A SUCCESSFUL OPERATION.
;
; =1 PRINT SCREEN IS IN PROGRESS
;
; =377 ERROR ENCOUNTERED DURING PRINTING
;--------------------------------------------
ASSUME CS:CODE,DS:XXDATA
PRINT_SCREEN PROC FAR
STI ;MUST RUN WITH INTERRUPTS ENABLED
PUSH DS ;MUST USE 50:0 FOR DATA AREA STORAGE
PUSH AX
PUSH BX
PUSH CX ;WILL USE THIS LATER FOR CURSOR LIMITS
PUSH DX ;WILL HOLD CURRENT CURSOR POSITION
MOV AX,XXDATA ;HEX 50
MOV DS,AX
CMP STATUS_BYTE,1 ;SEE IF PRINT ALREADY IN PROGRESS
JZ EXIT ; JUMP IF PRINT ALREADY IN PROGRESS
MOV STATUS_BYTE,1 ;INDICATE PRINT NOW IN PROGRESS
MOV AH,15 ;WILL REQUEST THE CURRENT SCREEN MODE
INT 10H ; [AL]=MODE
; [AH]=NUMBER COLUMNS/LINE
; [BH]=VISUAL PAGE
;********************************************
; AT THIS POINT WE KNOW THE COLUMNS/LINE ARE IN
; [AX] AND THE PAGE IF APPLICABLE IS IN [BH]. THE STACK
; HAS DS,AX,BX,CX,DX PUSHED. [AL] HAS VIDEO MODE
;
;********************************************
MOV CL,AH ;WILL MAKE USE OF [CX] REGISTER TO
MOV CH,25 ;CONTROL ROW & COLUMNS
CALL CRLF ;CARRIAGE RETURN LINE FEED ROUTINE
PUSH CX ;SAVE SCREEN BOUNDS
MOV AH,3 ;WILL NOW READ THE CURSOR.
INT 10H ;AND PRESERVE THE POSITION
POP CX ;RECALL SCREEN BOUNDS
PUSH DX ;RECALL [BH]=VISUAL PAGE
XOR DX,DX ;WILL SET CURSOR POSITION TO [0,0]
;********************************************
; THE LOOP FROM PRI10 TO THE INSTRUCTION PRIOR TO PRI20
; IS THE LOOP TO READ EACH CURSOR POSITION FROM THE SCREEN
; AND PRINT.
;********************************************
PRI10: MOV AH,2 ;TO INDICATE CURSOR SET REQUEST
INT 10H ;NEW CURSOR POSITION ESTABLISHED
MOV AH,8 ;TO INDICATE READ CHARACTER
INT 10H ;CHARACTER NOW IN [AL]
OR AL,AL ;SEE IF VALID CHAR
JNZ PRI15 ;JUMP IF VALID CHAR
MOV AL,' ' ;MAKE A BLANK
PRI15:
PUSH DX ;SAVE CURSOR POSITION
XOR DX,DX ;INDICATE PRINTER 1
XOR AH,AH ;TO INDICATE PRINT CHAR IN [AL]
INT 17H ;PRINT THE CHARACTER
POP DX ;RECALL CURSOR POSITION
TEST AH,25H ; TEST FOR PRINTER ERROR
JNZ ERR10 ; JUMP IF ERROR DETECTED
INC DL ;ADVANCE TO NEXT COLUMN
CMP CL,DL ;SEE IF AT END OF LINE
JNZ PRI10 ;IF NOT PROCEED
XOR DL,DL ;BACK TO COLUMN 0
MOV AH,DL ;[AH]=0
PUSH DX ;SAVE NEW CURSOR POSITION
CALL CRLF ; LINE FEED CARRIAGE RETURN
POP DX ;RECALL CURSOR PCSITION
INC DH ;ADVANCE TO NEXT LINE
CMP CH,DH ;FINISHED?
JNZ PRI10 ;IF NOT CONTINUE
PRI20: POP DX ;RECALL CURSOR POSITION
MOV AH,2 ;TO INDICATE CURSOR SET REQUEST
INT 10H ;CURSOR POSITION RESTORED
MOV STATUS_BYTE,0 ;INDICATE FINISHED
JMP SHORT EXIT ;EXIT THE ROUTINE
ERR10: POP DX ;GET CURSOR POSITION
MOV AH,2 ;TO REQUEST CURSOR SET
INT 10H ;CURSOR POSITION RESTORED
ERR20: MOV STATUS_BYTE,0FFH ;INDICATE ERROR
EXIT: POP DX ;RESTORE ALL THE REGISTERS USED
POP CX
POP BX
POP AX
POP DS
IRET
PRINT_SCREEN ENDP
;------ CARRIAGE RETURN, LINE FEED SUBROUTINE
CRLF PROC NEAR
XOR DX,DX ;PRINTER 0
XOR AH,AH ;WILL NOW SEND INITIAL LF,CR TO PRINTER
MOV AL,12Q ;LF
INT 17H ;SEND THE LINE FEED
XOR AH,AH ;NOW FOR THE CR
MOV AL,15Q ;CR
INT 17H ;SEND THE CARRIAGE RETURN
RET
CRLF ENDP
CODE ENDS ;segment move 11/4/97
;----------------------------------
; POWER ON RESET VECTOR
;----------------------------------
VECTOR SEGMENT 'CODE' ;AT 0FFFFH
ORG 0FFF0H
;------ POWER ON RESET
POR:
JMP FAR PTR RESET
DB '04/24/81' ; RELEASE MARKER
NOP ; PLACEHOLDER (11/4/97)
NOP ; COMPUTER_TYPE (11/4/97)
NOP ; CHECKSUM BYTE (11/4/97)
VECTOR ENDS
CODE ENDS
END POR
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment