Short bio
Colin Raffel is an associate professor at the University of Toronto, an associate research director at the Vector Institute, and a faculty researcher at Hugging Face. His lab works on decentralizing, democratizing, and de-risking large-scale AI.
Longer, more effusive bio
Colin Raffel is an associate professor of computer science at the University of Toronto, an associate research director and faculty member at the Vector Institute, and a faculty researcher at Hugging Face.
Prior to joining the University of Toronto, he was an assistant professor at the University of North Carolina and a research scientist at Google Brain.
He received a PhD in electrical engineering and a Master's in philosophy from Columbia University, supervised by Daniel P. W. Ellis; a Master's in music, science, and technology from Stanford University's Center for Computer Research in Music and Acoustics, supervised by Julius O. Smith III; and a Bachelor's in mathematics from Oberlin College, supervised by Robert Young.
His lab works on decentralizing, democratizing, and de-risking large-scale AI.
His work has received, or has been a runner-up for, a TMLR outstanding paper certification, the ICBS Frontiers of Science Award, a NeurIPS outstanding paper award, the Caspar Bowden Award for Outstanding Research in Privacy Enhancing Technologies, a CACM and SIGPLAN research highlight, and a best paper award at ISMIR.
Bio of rejections
The first time he applied for PhDs, Colin was rejected from every school he applied to.
On the second round, Colin got rejected from every school except for one (Columbia, where he ultimately did his PhD).
When he applied to faculty positions the first time, he was also rejected by every school except for one.
He was rejected by Google three times before he started working there.
Probably half of his papers were rejected at least once before being published.
He has also applied to many more funding opportunities than he has received, and was rejected from every award he has ever applied for.
Bio of non-professional achievements
Colin Raffel is a dad of two living in Toronto.
He is a decent cook and enjoys building and riding bikes.
Once, he DJed a wedding where Girl Talk was a groomsman.
He also built a guitar pedal that is now owned by Adrian Utley of Portishead.
The hardest outdoor bouldering route he climbed was a V6 (he once climbed a V9 indoors, but such achievements are debatable).
Bio hallucinated by a state-of-the-art LLM (generated 7 April 2025; falsehoods underlined)
Colin Raffel is a leading researcher in machine learning, specializing in natural language processing, deep learning, and transfer learning.
He earned his B.Sc. in Computer Science from the University of British Columbia (2010), followed by an M.Sc. (2012) and Ph.D. (2016) in Computer Science from the University of Waterloo, advised by Jimmy Lin.
After his doctorate, Raffel was a postdoctoral researcher at Google Brain (2016–2017) before joining the University of North Carolina at Chapel Hill as an Assistant Professor (2017–2019).
He then returned to Google Brain as a Research Scientist (2019–2023) before moving to Hugging Face in 2023 as a Principal Investigator, while also serving as an Adjunct Assistant Professor at UNC Chapel Hill.
Raffel has received several notable awards, including a Google PhD Fellowship (2014) and a Spotlight Paper Award at NeurIPS (2020) for his work on large-scale transfer learning.
He is also a key contributor to major open-source projects, including TensorFlow and Hugging Face’s Transformers library, shaping modern NLP research and applications.
$TITLE(ROM BIOS FOR IBM PERSONAL COMPUTER)
;------------------------
; 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 AT 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 ; INTERRUPT 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
;----------------------
STACK SEGMENT AT 30H
DW 128 DUP(?)
TOS LABEL WORD
STACK ENDS
;--------------------------------------------
; ROM BIOS DATA AREAS
;--------------------------------------------
DATA SEGMENT AT 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 CODE 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 OPERATION 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 KEYBOARD RESET UNDERWAY
DATA ENDS
;--------------------------------------------
; EXTRA DATA AREA
;--------------------------------------------
XXDATA SEGMENT AT 50H
STATUS_BYTE DB ?
XXDATA ENDS
;--------------------------------------------
; VIDEO DISPLAY BUFFER
;--------------------------------------------
VIDEO_RAM SEGMENT AT 0B800H
REGEN LABEL BYTE
REGENW LABEL WORD
DB 16384 DUP(?)
VIDEO_RAM ENDS
;--------------------------------------------
; ROM RESIDENT CODE
;--------------------------------------------
CODE SEGMENT AT 0F000H
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 STORAGE.
;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 REGISTERS
; WITH ALL ONE'S AND 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 BX,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,AUTOINT
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 BYTES
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 F8H
C23: ;CONTINUE IN NORMAL MODE
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,STACK ; 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 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 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 OF 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 TIMER 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 TO 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 INTR 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 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 VIDEO ENABLE SIGNAL.
; SELECT ALPHANUMERIC 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 VIDEO 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 TO 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,DI ;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 ADD 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 TO 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 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 ; KEYBOARD 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 ;ISOLATE 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 OF 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 ERROR MSG
; TURN DRIVE 0 MOTOR OFF
F14: ; DR0_OFF:
MOV AL,0CH ;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 BEEPER
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 CNT 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 CODE '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 CODE RETURNED
LOOP G9 ;NO - LOOP TILL TIMEOUT
G10: IN AL,PORT_A ;READ KEYBOARD SCAN CODE
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 ;POSITION 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 TIME 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 5 = 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 ; COMMUNICATION 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 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 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 'qwertyuiop[]',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 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 ALREADY 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 AWAY
JMP K26 ; THROW AWAY THAT KEYSTROKE
;------ 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 KEYSTROKE 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 K56 ; YES, GO TRANSLATE CHAR
K43: ; CTL-TABLE-TRANSLATE
MOV BX,OFFSET K9 ; CTL TABLE SCAN
JMP K63 ; TRANSLATE_SCAN
;------ NOT IN CONTROL 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 K57 ; BUFFER_FILL
K45: ; NOT-BACK-TAB
CMP AL,55 ; PRINT SCREEN 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 ; GO 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 KEYS
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
;------ CONVERT 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 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 LOCATION
;------ 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 ADDRESS
;------ 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 OCCURRED, 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 INTERUPT 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 VALUE
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 ; INITIALIZE THE DISKETTE CHANNEL
RET ; RETURN TO CALLER, CFL SET BY ABOVE IF ERROR
DMA_SETUP ENDP
;---------------------------------------------
; CHK_STAT_2
; THIS ROUTINE 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
; OUTPUT
; CY = 0 SUCCESS
; CY = 1 FAILURE -- ERROR IS IN DISKETTE_STATUS
; (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 ; SAVE 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 INTERRUPT.
; 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
; NO 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 COMMUNICATION 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 FOR 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
; (BH) = 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 ON 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
;------ C_REG_TAB
M7 LABEL BYTE ; TABLE OF MODE SETS
DB 2CH,28H,2DH,29H,2AH,2EH,1EH,29H
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 ; NUMBER 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 MODE
MOV DX,ADDR_6845 ; PREPARE TO OUTPUT TO VIDEO ENABLE PORT
ADD DX,4
MOV AL,CS:[SI+OFFSET M7]
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 AL,CS:[SI + OFFSET M6]
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 CURSOR
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 VALUE
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 MODE
; 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 SEGMENT
; 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 MODE
; (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 GRAPHICS
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 REGISTER
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 FROM 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 FOR 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 MULTIPLYING ROW VALUE BY 40
;------ ( LOW BIT OF ROW DETERMINES EVEN/ODD, 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 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 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 FIELD
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 FUNCTION 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 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 ; ESTABLISH 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 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 INCREMENTED. 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 CURSOR
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_PEN
;------ GRAPHICS MODE
MOV DL,40 ; DIVISOR FOR 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 MEMORY_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 COUNTER
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 OF 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 ;INDICATE 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 SQUARE 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 CHECKED 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. D 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 WRITING
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 INTERRUPT 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 PRINT
; 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 POSITION
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
;----------------------------------
; POWER ON RESET VECTOR
;----------------------------------
VECTOR SEGMENT AT 0FFFFH
;------ POWER ON RESET
JMP RESET
DB '04/24/81' ; RELEASE MARKER
VECTOR ENDS
END