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