home *** CD-ROM | disk | FTP | other *** search
- ;
- ; TITLE BOB VAN VALZAH'S INPUT/OUTPUT SYSTEM (FOR CP/M)
- ; AND FOR UCSD PASCAL, TOO (AS OF VERSION 8)
- ; FILENAME BVIOS.ASM
- ; AUTHOR ROBERT A. VAN VALZAH 2/22/79
- ; LAST REVISOR R. A. V. 12/15/79
- ; REASON CONDITIONALIZE DIABLO DRIVER
- ;
- ;
- ;
- CBIVERS EQU 14 ;CBIOS VERSION NUMBER
- CPMVERS EQU 14 ;CP/M VERSION NUMBER
- ;
- ; CONDITIONAL ASSEMBLY EQUATES
- ;
- FALSE EQU 0
- TRUE EQU NOT FALSE
- ;
- REL EQU FALSE ;TRUE TO GENERATE RELOCATABLE CODE
- MSIZE EQU 47 ;MEMORY AND CP/M SYSTEM SIZE
- NODISKS EQU 1 ;NUMBER OF PHYSICAL DRIVES IN SYSTEM
- ; NOTE: BACKSPC CAN'T BE TRUE IF PASCAL IS TRUE & NODISKS=1
- BACKSPC EQU FALSE ;TRUE TO GENERATE CURSOR BACKUP CODE
- PASCAL EQU FALSE ;TRUE TO GENERATE UCSD PASCAL I/O CODE
- LCASE EQU TRUE ;TRUE TO GENERATE SOFTWARE LOWER CASE
- VDM EQU TRUE ;TRUE TO GENERATE VDM CONSOLE OUT
- DIABLO EQU FALSE ;TRUE TO GENERATE DIABLO Hy-Type DRIVER
- ;
- ; BASE OF DOS (CCP) LOAD COMPUTATION
- ;
- IF REL
- BIAS EQU 0100H ;FOR RELOCATION, ASSUME CCP STARTS AT 0
- ENDIF
- ;
- IF NOT REL ;OTHERWISE USE REAL CCP STARTING ADDR.
- BIAS EQU (MSIZE-16)*1024+2900H
- ENDIF
- ;
- ; OTHER ENTRY CP/M ENTRY POINTS
- ;
- CPMB EQU BIAS ;CCP START
- BDOS EQU CPMB+806H ;BDOS ENTRY POINT
- CBIOS EQU CPMB+1500H ;CBIOS START
- DOSEND EQU CPMB+1700H ;END OF DOS LOAD +1
- ;
- ; COMPUTE NUMBER OF SECTORS TO LOAD
- ;
- DOSSECT EQU (CBIOS-CPMB)/128
- ;
- ; DISK I/O PORT NUMBERS
- ;
- DBASE EQU 0F8H ;BASE ADDRESS OF CONTROLLER CARD
- COMMAND EQU DBASE ;FD1771 COMMAND OUTPUT
- STATUS EQU DBASE ;FD1771 STATUS INPUT
- TRACK EQU DBASE+1 ;TRACK INPUT/OUTPUT
- SECT EQU DBASE+2 ;SECTOR OUTPUT
- DATA EQU DBASE+3 ;DATA INPUT & OUTPUT
- WAIT EQU DBASE+4 ;DATA SYNCRONIZATION & INTRQ INPUT
- CONTROL EQU DBASE+4 ;CONTROL OUTPUT
- ;
- ; FD1771 COMMANDS
- ;
- HOMECMD EQU 0 ;RESTORE (HOME) COMMAND
- SEEKCMD EQU 10H ;SEEK TRACK COMMAND
- READCMD EQU 88H ;READ IBM FORMAT
- WRITCMD EQU 0A8H ;WRITE IN IBM FORMAT
- FINTCMD EQU 0D0H ;FORCE INTERRUPT
- ;
- ; OPTION BITS WITHIN COMMANDS
- ;
- LOADHEAD EQU 08H ;LOAD HEAD WHILE SEEKING
- RATE EQU 10B ;STEP RATE OF 10MS.
- ;
- ; VDM EQUATES
- ;
- SCREEN EQU 0CC00H ;STARTING SCREEN ADDRESS
- SCRLPT EQU 0C8H ;SCROLL PORT
- ;
- ;
- ; DEFINE CBIOS RAM AREAS
- ;
- ; NON-INITIALIZED RAM
- ; SEE ALSO - AREA PAST JUMP TABLE FOR INITIALIZED RAM
- ;
- ORG 4H ;THIS IS WHERE CP/M STORES THE
- DISKNO: DS 1 ;CURRENTLY LOGGED DRIVE
- ;
- ORG 40H ;SCRATCH AREA FOR CBIOS
- IOD DS 2 ;DMA ADDRESS
- ;
- ORG 4CH ;DIABLO PARAMETER RAM
- ;
- ; ram parameter area
- ;
- linhgt ds 1 ;line height in increments
- chwid ds 1 ;character width in increments
- lpp ds 1 ;lines per page
- ;
- ;
- ; ROUTINES WITHIN THE CBIOS MAY BE INTERNALLY REFERENCED (CALLED
- ; FROM WITHIN THE CBIOS), EXTERNALLY REFERENCED (CALLED BY CP/M)
- ; OR BOTH. ANY ROUTINE WHICH IS EXTERNALLY REFERENCED IS
- ; ASSUMED TO CLOBBER ALL REGISTERS. REGISTER USAGE OF ROUTINES
- ; REFERENCED ONLY INTERNALLY IS DECLARED IN THE PRE-ROUTINE
- ; COMMENT BLOCK. ANY REGISTERS NOT MENTIONED ARE PRESERVED.
- ;
- ;
- ORG CBIOS ;ORG TO START OF CBIOS AREA
- ;
- ; I/O JUMP VECTOR
- ; THIS IS WHERE CPM CALLS WHENEVER IT NEEDS
- ; TO DO ANY INPUT/OUTPUT OPERATION.
- ; USER PROGRAMS MAY USE THESE ENTRY POINTS
- ; ALSO, BUT NOTE THAT THE LOCATION OF THIS
- ; VECTOR CHANGES WITH THE MEMORY SIZE.
- ;
- IF PASCAL
- JMP $ ;NOT USED IN PASCAL SYSTEM
- JMP $ ;HANG IF USER COMES HERE
- ELSE
- JMP CBOOT ;FROM COLD START LOADER
- WBOOTE:
- JMP WBOOT ;WARM BOOT ENTRY
- ENDIF
- JMP CONST ;CONSOLE STATUS
- ;REG A = 000H IF NO HCARACTER READY
- ;REG A = 0FFH IF CHARACTER IS READY
- JMP CONIN ;CONSOLE CHARACTER IN (TO REG A)
- JMP CONOUT ;CONSOLE CHARACTER OUT (FROM REG C)
- JMP LIST ;LIST OUT (FROM REG C)
- JMP PUNCH ;PUNCH OUT (FROM REG C)
- JMP READER ;PAPER TAPE READER IN (TO REG A)
- JMP HOME ;MOVE DISK HEAD TO TRACK 00
- JMP SELDSK ;SELECT THE DISK GIVEN BY REG C
- JMP SETTRK ;SET TRACK ADDRESS (0,...76) FOR I/O
- JMP SETSEC ;SET SECTOR ADDRESS (1,...26) FOR I/O
- JMP SETDMA ;SET DMA ADDRESS FOR I/O
- JMP READ ;READ A SECTOR
- JMP WRITE ;WRITE A SECTOR
- ;
- ; INITIALIZED RAM AREAS
- ;
- ;***********************NOTE: THE FOLLOWING BYTES MUST
- ; BE IN ADJACENT RAM LOCATIONS
- ; AND NOT CROSS A 256 BYTE PAGE BOUNDRY
- IOT DS 1 ;TRACK
- IOS DS 1 ;SECTOR
- SELREQ DS 1 ;CURRENT DRIVE SELECT REQUEST
- LASTSEL DB 0 ;LAST DRIVE ACTUALLY SELECTED
- DHPOS DB 1 ;HEAD POSITION TABLE
- DS NODISKS-1 ;STORAGE FOR DISKS B THRU D
- IF VDM
- CURSOR DW SCREEN+3C0H
- ENDIF
- IF BACKSPC
- RUBFLG DB 0 ;NON ZERO IF RUBOUT WAS LAST CHR TYPED
- ENDIF
- IF PASCAL
- BKCHR DB 0 ;BREAK CHARACTER, 0 IF EMPTY
- FLUSH DB 0 ;FLUSH OUTPUT IF NON ZERO
- ENDIF
- IF LCASE
- ULTG DB 0FFH ;UPPER CASE=0, LOWER CASE OTHERWISE
- ENDIF
- ;
- ; COLD BOOT
- ; EXTERNALLY REFERENCED
- ; THIS SECTION IS EXECUTED WHENEVER RESET AND RUN
- ; IS PUSHED, AFTER THE COLDSTART LOADER READS IN
- ; THE CPM SYSTEM.
- ;
- IF NOT PASCAL
- CBOOT:
- LXI SP,100H ;SET STACK FOR INITILIZATION
- ;NOTE: SOME RAM INITIALIZATION HAS BEEN DB'D
- ;INTO THE RAM DEFINITION ABOVE
- if diablo
- mvi a,6 ;init diablo character width
- sta chwid
- mvi a,8 ;init diablo line height
- sta linhgt
- mvi a,66 ;init diablo lines per page
- sta lpp
- endif
- XRA A ;COME UP ON DRIVE A
- STA DISKNO
- IF VDM
- OUT SCRLPT ;INITIALIZE VDM SCROLL PORT
- ENDIF
- CALL MSGP ;PRINT SINGNON MESSAGE
- IF REL
- DB '00' ;A MESSAGE THAT DOESN'T CHANGE WITH
- ;DIFFERENT MEMORY SIZES
- ENDIF
- IF NOT REL
- DB '0'+MSIZE/10, '0'+MSIZE MOD 10
- ENDIF
- DB 'K CP/M VERS '
- DB '0'+CPMVERS/10, '.', '0'+CPMVERS MOD 10
- DB '-'
- DB '0'+CBIVERS/10, '.', '0'+CBIVERS MOD 10 + 80H
- JMP GOCPM ;SET LO MEM JMPS AND ENTER CP/M
- ;
- ; WARM BOOT
- ; EXTERNALLY REFERENCED
- ; READ THE CCP AND BDOS IN TO MEMORY AFTER TRANSIENT EXECUTION
- ;
- WBOOT:
- LXI SP,100H ;SET STACK DURING BOOT
- XRA A ;BOOT FROM DRIVE A
- STA SELREQ
- CALL HOME ;BOOT FROM TRACK 0
- ;NEXT SECTOR TO READ - 1 KEPT IN REG D
- ;NUMBER OF SECTORS TO GO IN REG E
- LXI D,(1 SHL 8) + DOSSECT
- LXI H,CPMB ;START LOADING AT BASE OF CCP
- BOOTSEC:
- INR D ;ADD ONE TO SECTOR NUMBER
- MOV A,D ;END OF FIRST TRACK?
- CPI 26+1
- JNZ SAMTRK ;NO - STAY ON SAME TRACK
- MVI D,1 ;YES - RESET SECTOR NUMBER TO 1
- MOV A,D ;AND STEP IN TO TRACK 1
- STA IOT
- SAMTRK:
- STA IOS ;STORE SECTOR FOR READ
- SHLD IOD ;STORE DMA ADDRESS FOR READ
- PUSH D ;SAVE SECTOR & COUNT WHILE READING
- CALL READ ;READ A SECTOR
- POP D ;RESTORE SECTOR & COUNT
- DCR E ;DECREMENT COUNT (DONE LOADING?)
- JNZ BOOTSEC ;NO - KEEP LOADING
- ;YES - FALL THRU TO BRING UP CP/M
- ;
- ; DONE WITH LOAD, SO SET UP LOW MEMORY JMP VECTORS AND
- ; RESET DMA ADDRESS
- ;
- GOCPM:
- IF DIABLO
- CALL INIT ;INTIALIZE DIABLO
- ENDIF
- LXI H,80H ;SET DEFAULT DMA ADDRESS
- SHLD IOD
- MVI L,0 ;NOW REG HL = 0
- MVI M,JMP ;PUT 'JMP WBOOTE' AT LOCATION 0
- INX H
- MVI M,LOW WBOOTE
- INX H
- MVI M,HIGH WBOOTE
- INX H
- INX H ;NOW POINTING TO DISKNO (REG HL = 4)
- MOV C,M ;GET LAST LOGGED DISK NUMBER FOR CCP
- INX H ;POINT TO BDOS JUMP (REG HL = 5)
- MVI M,JMP ;PUT 'JMP BDOS' AT LOCATION 5
- INX H
- MVI M,LOW BDOS
- INX H
- MVI M,HIGH BDOS
- JMP CPMB
- ENDIF ;END OF IF NOT PASCAL CONDITIONAL
- ;
- ; HOME DISK HEAD TO TRACK 0
- ; INTERNALLY AND EXTERNALLY REFERENCED
- ;
- HOME:
- IF NODISKS NE 1 ;IF MULTI-DRIVE SYSTEM
- CALL DO$SEL ;SELECT CORRECT DRIVE BEFORE HOMING
- MVI A,RATE ;ISSUE HOME COMMAND
- CALL CMD$TY1
- ;IGNORE ERRORS
- ENDIF
- MVI C,0 ;AND FALL THRU TO SET TRACK
- IF NODISKS NE 1
- CALL HPADR ;RESET HEAD POSITION BYTE FOR DRIVE
- MOV M,C
- ENDIF
- ;
- ; SET TRACK NUMBER FOR DISK I/O
- ; EXTERNALLY REFERENCED
- ; ENTRY C TRACK NUMBER (0...76)
- ;
- SETTRK:
- MVI L,IOT AND 0FFH
- DB 11H ;GENERATE LXI D TO SKIP NEXT MVI L
- ;
- ; SET SECTOR NUMBER FOR DISK I/O
- ; EXTERNALLY REFERENCED
- ; ENTRY C SECTOR NUMBER (1...26)
- ;
- SETSEC:
- MVI L,IOS AND 0FFH
- DB 11H ;GENERATE LXI D TO SKIP NEXT MVI L
- ;
- ; SET DISK DRIVE NUMBER FOR DISK I/O
- ; EXTERNALLY REFERENCED
- ; ENTRY C DRIVE NUMBER (0...3)=(A...D)
- ;
- SELDSK:
- MVI L,SELREQ AND 0FFH
- MVI H,IOT SHR 8
- MOV M,C
- RET
- ;
- ; SET DMA ADDRESS FOR DISK I/O
- ; EXTERNALLY REFERENCED
- ; ENTRY BC DMA ADDRESS (0000H-0FFFFH)
- ;
- SETDMA:
- MOV H,B
- MOV L,C
- SHLD IOD
- RET
- ;
- ; WRITE A SECTOR TO DISK
- ; EXTERNALLY REFERENCED
- ;
- WRITE:
- MVI E,WRITCMD
- DB 1 ;GENERATE LXI B TO SKIP MVI E FOLLOWING
- ;
- ; READ A SECTOR FROM DISK
- ; INTERNALLY AND EXTERNALLY REFERENCED
- ; EXIT HL (IOD)+128 DMA ADDRESS + 128
- ; B,C,D CLOBBERED
- ;
- READ:
- MVI E,READCMD
- CALL DO$SEL ;SELECT CORRECT DRIVE F╧R I/O
- IF PASCAL
- MVI A,1 ;READY TO RETURN FAILURE CODE
- RC ;EXIT IF SELECTED DRIVE NOT READY
- ENDIF
- RTRY: ;RETRY RE-ENTRY POINT
- IF NODISKS EQ 1
- LDA IOT ;GET REQUESTED TRACK
- ELSE
- CALL HPADR ;GET ADDRESS OF HEAD POSITION BYTE
- LDA IOT ;GET REQUESTED TRACK
- MOV M,A ;STORE IT AS NEW HEAD POSITION
- ENDIF
- OUT DATA ;SEND REQUESTED TRACK TO 1771
- MVI A,SEEKCMD+LOADHEAD+RATE
- CALL CMD$TY1 ;COMMAND DISK TO SEEK REQUESTED TRACK
- JNZ ERROR ;ISSUE ERROR IF SEEK FAILED
- LDA IOS ;SEND REQUESTED SECTOR TO 1771
- OUT SECT
- LHLD IOD ;GET REQUESTED DMA ADDRESS
- CALL XFER ;PERFROM DISK I/O TRANSFER
- IN STATUS ;SEE IF SUCCUSSFULL
- ANI 1111$1100B ;CHECK FOLLOWING BITS X/X/X/X$X/X/X/XB
- ;NOT READY/WRITE PROTECT/WRITE FAULT/
- ;RECORD NOT FOUND$CRC ERROR/LOST DATA//
- RZ ;YES - RETURN WITH REG A = 0
- ERROR:
- PUSH PSW ;SAVE ERROR BITS
- CALL MSGP ;PRINT FIRST PART OF ERROR MESSAGE
- DB 13, 10, 'Error bits', '='+80H
- POP PSW ;GET ERROR BITS BACK
- CALL PHEX ;PRINT THEM AS A HEX NUMBER
- FOOL:
- CALL MSGP ;PRINT REST OF ERROR MESSAGE
- DB ',Retry or Ignore', '?'+80H
- CALL CONIN ;GET USERS RESPONSE
- ANI 5FH ;CONVERT LOWER TO UPPER CASE
- PUSH PSW ;SAVE DURRING ECHO
- MOV C,A ;ECHO RESPONSE
- CALL CONOUT
- POP PSW ;GET RESPONSE BACK
- SUI 'I' ;IGNORE?
- RZ ;YES - SEND ALL OK FLAG BACK TO CP/M
- CPI 'R'-'I' ;RETRY?
- JNZ FOOL ;NO - RE-ISSUE MESSAGE
- MVI A,RATE ;YES - SEEK HOME AND TRY AGAIN
- CALL CMD$TY1 ;ISSUE HOME COMMAND
- JNZ ERROR ;ERROR IN HOMING
- JMP RTRY ;NO ERROR - TRY OPERATION AGAIN
- ;
- ; SEND A TYPE ONE COMMAND TO THE CONTROLLER, WAIT FOR FINISH
- ; INTERNALLY REFERENCED
- ; EXIT A ERROR BITS
- ; ZERO SET IF SUCCESS
- ;
- CMD$TY1:
- OUT COMMAND ;SEND COMMAND
- IN WAIT
- IN STATUS ;GET ALL STATUS BITS
- ANI 1001$1001B ;LEAVE ONLY THE FOLLOWING
- ;NOT READY///SEEK ERROR$
- ;CRC ERROR///BUSY
- RET ;RETURN ERROR BITS TO CALLER
- ;
- ; SEND COMMAND TO 1771 AND PERFORM DISK I/O TRANSFER
- ; HEAD WILL BE LOADED FIRST IF HARDWARE TIMEOUT HAS UNLOADED IT
- ; INTERNALLY REFERENCED
- ; ENTRY E 1771 COMMAND
- ; HL I/O ADDRESS
- ; EXIT E PRESERVED
- ; HL I/O ADDRESS+128
- ; A,FLAGS CLOBBERED
- ;
- XFER:
- MVI A,FINTCMD ;INTERRUPT 1771 TO GENERATE STATUS
- OUT COMMAND
- XTHL
- XTHL
- IN STATUS ;GET NEW STATUS
- ANI 0010$0000B ;TRANSFORM HEAD LOADED STATUS INTO
- XRI 0010$0000B
- RAR ;HEAD LOAD BIT FOR COMMAND
- RAR
- RAR
- ORA E ;OR HEAD LOAD BIT IN WITH COMMAND
- OUT COMMAND ;SEND COMMAND TO CONTROLLER
- CPI WRITCMD ;SEE IF READING OR WRITING
- JNC XWLOOP ;WRITING
- XRLOOP:
- IN WAIT ;WAIT FOR DATA OR INTRQ
- ORA A ;SET POSITIVE IF INTRQ
- RP
- IN DATA ;DATA IS READ - GO GET IT
- MOV M,A ;LOAD INTO DMA ADDR
- INX H
- JMP XRLOOP
- XWLOOP:
- IN WAIT ;WAIT FOR DRQ OR INTRQ
- ORA A ;SET POSITIVE IF INTRQ
- RP
- MOV A,M ;GET DATA FOR DISK
- OUT DATA
- INX H
- JMP XWLOOP
- ;
- ; ACTUALLY PERFORM DRIVE SELECTION
- ; INTERNALLY REFERENCED
- ; ENTRY (SELREQ) DRIVE TO BE SELECTED
- ; EXIT A,C,FLAGS,HL CLOBBERED
- ; IN PASCAL VERSIONS: AS ABOVE EXCEPT
- ; EXIT CARRY SET IF DRIVE NOT READY OR NON-EXISTANT
- ;
- DO$SEL:
- IF NODISKS EQ 1 ;GENERATE LOGICAL SEL CODE
- LXI H,SELREQ ;GET REQUEST
- MOV A,M
- IF PASCAL
- CPI 1 ;CLEAR CARRY IF DRIVE B THRU D SELECTED
- CMC ;SET CARRY IF ABOVE
- RC
- ENDIF
- INX H ;POINT TO LAST DRIVE SELECTED
- CMP M ;IS REQUEST SAME AS LAST SELECTED?
- RZ ;IF SO - SELECT DOES NOTHING
- MOV M,A ;IF NOT - UPDATE LAST SELECTED=REQUEST
- CALL MSGP ;GIVE MOUNT MESSAGE
- DB 13, 10, 'MOUNT', ' '+80H
- MVI A,'A' ;CONVERT REQUEST TO ASCII DRIVE NAME
- ADD M
- MOV C,A ;PRINT REQUESTED DRIVE NAME
- CALL CONOUT
- IN 0 ;CLEAR ANY CHAR WHICH MIGHT BE WAITING
- ;GO TO CONIN TO WAIT FOR MOUNTING
- ELSE ;GENERATE PHYSICAL DRIVE SELECT CODE
- LDA SELREQ ;GET DRIVE TO SELECT TO REG A
- CMA ;COMPLIMENT FOR CONTROL LATCH PORT
- ADD A ! ADD A ! ADD A ! ADD A ;ROTATE INTO POSITION
- ORI 2 ;MAKE IT A DRIVE SELECT COMMAND
- OUT CONTROL ;SEND COMMAND TO CARD
- CALL HPADR ;TELL 1771 WHERE WE LEFT THE HEAD OF
- MOV A,M ;THE NEW DRIVE BEING SELECTED
- OUT TRACK
- MVI A,FINTCMD ;INTERRUPT 1771 TO GENERATE STATUS
- OUT COMMAND
- XTHL ;WAIT FOR STATUS TO MATERIALIZE
- XTHL
- IN STATUS ;GET ALL STATUS BITS
- RAL ;DRIVE NOT READY BIT INTO CARRY
- RET
- ENDIF
- ;
- ; READ A CHARACTER FROM CONSOLE
- ; INTERNALLY AND EXTERNALLY REFERENCED
- ; EXIT A CHARACTER READ, PARITY RESET
- ; FLAGS CLOBBERED
- ;
- CONIN:
- IF PASCAL
- XRA A ;CLEAR FLUSH OUTPUT FLAG
- STA FLUSH
- PUSH H ;SAVE CALLERS REG HL
- LXI H,BKCHR ;SEE IF A GOBBLED CHR IS WAITING
- MOV A,M
- MVI M,0 ;RESET IT IF IT WAS
- POP H ;RESTORE CALLERS REG HL
- ORA A ;RESET Z IF ONE WAS WAITING
- RNZ ;RETURN GOBBLED CHR
- HCONIN: ;HARD CONSOLE IN ENTRY, BKCHR IS IGNORED
- ENDIF
- IN 1
- RAR
- JNC CONIN
- IN 0
- ANI 0111$1111B ;MASK PARITY
- IF BACKSPC
- CPI 7FH ;WAS RUBOUT TYPED?
- IF LCASE
- JNZ CSTEST ;NO - CHECK FOR CASE CONVERSION
- ELSE
- RNZ ;NO - LEAVE FLAG ALONE
- ENDIF
- STA RUBFLG ;YES - SET RUBOUT FLAG
- ENDIF
- IF LCASE
- CSTEST:
- MOV B,A ;SAVE CHR TYPED IN REG B
- CPI 11H ;ESCAPED TYPED?
- LDA ULTG
- JZ ESCP ;YES - GO COMPLIMENT FLAG
- ORA A ;NO - IS MODE = UPPER?
- MOV A,B ;PREPARE TO RETURN CHR IF SO
- RZ ;MODE IS UPPER
- CPI 'A' ;IS CHR A LETTER?
- RC ;NO - SKIP CONVERSION
- CPI 'Z'+1
- RNC ;STILL NOT A LETTER
- ADI 20H ;IS A LETTER - CONVERT TO LOWER CASE
- ENDIF
- RET
- IF LCASE
- ESCP:
- CMA ;COMPLIMENT CASE TOGGLE
- STA ULTG
- JMP CONIN
- ENDIF
- ;
- ; CALCULATE HEAD POSITION BYTE ADDRESS
- ; INTERNALLY REFERENCED
- ; ENTRY (SELREQ) DESIRED DRIVE NUMBER
- ; EXIT HL ADDRESS OF HEAD POSITION BYTE FOR DRIVE
- ; A,FLAGS CLOBBERED
- ;
- IF NODISKS NE 1
- HPADR:
- LDA SELREQ ;GET REQUESTED DRIVE
- ADI LOW DHPOS ;ADD TO BASE OF HEAD POSITION TABLE
- MOV L,A ;RESULT OF ADD TO REG HL
- MVI H,HIGH DHPOS
- RET
- ENDIF
- ;
- ; CHECK CONSOLE INPUT STATUS
- ; INTERNALLY AND EXTERNALLY REFERENCED
- ; EXIT A 0FFH IF CHRACTER IS READY, 0H IF NOT READY
- ; FLAGS CLOBBERED
- ;
- CONST:
- IF PASCAL
- LDA BKCHR ;IF CONOUT GOBBLED A CHARACTER
- ORA A ;RESET ZERO
- MVI A,0FFH ;PREPARE TO RETURN READY FLAG
- RNZ ;SEND READY FLAG FOR GOBBLED CHR
- HCONST: ;HARD CONSOLE STATUS CHECK ENTRY
- ;CONTENTS OF BKCHR IS IGNORED
- ENDIF
- IN 1
- RAR
- SBB A
- PUNCH: ;DUMMY DEVICE
- READER: ;DUMMY DEVICE
- RET
- ;
- ; OUTPUT CHARACTER TO LIST DEVICE
- ; EXTERNALLY REFERENCED
- ; ENTRY C CHARACTER
- ; EXIT A,FLAGS CLOBBERED
- ;
- LIST:
- IF PASCAL
- LDA FLUSH ;ARE WE FLUSHING OUTPUT?
- ORA A
- RNZ ;YES - FLUSH PRINTER TOO
- ENDIF
- ;
- ; YOUR PRINTER DRI╓ER HERE
- ;
- IF DIABLO
- JMP PRINT ;SEND TO DIABLO
- ENDIF
- ;
- ; IN-LINE MESSAGE PRINTER
- ; THE MESSAGE MUST BE TERMINATED BY BIT 7 HIGH ON THE LAST
- ; CHARACTER.
- ; INTERNALLY REFERENCED
- ; ENTRY STACK TOP MESSAGE ADDRESS (RETURN ADDRESS)
- ; EXIT C,A,FLAGS CLOBBERED
- ; NOTE: MODIFYS RETURN ADDRESS AND RETURNS ONE BYTE PAST
- ; END OF MESSAGE.
- ;
- MSGP:
- XTHL ;GET MESSAGE ADDRESS TO REG HL
- MSG1:
- MOV C,M ;GET A CHR FROM MESSAGE
- CALL CONOUT ;PRINT IT
- MOV A,M ;GET CHR BACK
- INX H ;POINT TO NEXT
- ORA A ;WAS BIT 7 SET ON LAST CHR?
- JP MSG1 ;YES - KEEP PRINTING
- XTHL ;NO - PUT RETURN ADDRESS BACK
- RET
- ;
- ; PRINT TWO HEX DIGITS
- ; INTERNALLY REFERENCED ROUTINE
- ; ENTRY A 8-BIT VALUE TO BE PRINTED AS TWO HEX DIGITS
- ; EXIT A,C,FLAGS CLOBBERED
- ;
- PHEX:
- PUSH PSW ;SAVE LOW NIBBLE
- RAR ! RAR ! RAR ! RAR ;POSITION HIGH NIBBLE FOR PRINT
- CALL PNIB ;PRINT HIGH NIBBLE
- POP PSW ;GET LOW NIBBLE BACK AND . .
- ;FALL THRU TO PRINT IT
- ;
- ; PRINT ONE HEX DIGIT
- ; INTERNALLY REFERENCED
- ; ENTRY A B3-B0 NIBBLE TO BE PRINTED AS A HEX DIGIT
- ; EXIT A,C,FLAGS CLOBBERED
- ;
- PNIB:
- ANI 0000$1111B ;LEAVE ONLY LOW NIBBLE
- ADI 90H ;CAUSE CARRY IF > 9
- DAA
- ADI 40H
- DAA
- MOV C,A ;PASS ASCII CHAR TO CONOUT
- ;FALL THRU TO CONOUT
- ;
- ; OUTPUT A CHARACTER TO CONSOLE
- ; INTERNALLY AND EXTERNALLY REFERENCED
- ; ENTRY C ASCII CHARACTER TO BE SENT
- ; EXIT A,FLAGS CLOBBERED
- ;
- CONOUT:
- IF PASCAL
- LDA FLUSH ;IS FLUSH FLAG SET?
- ORA A ;RESET Z IF SO
- JNZ FTEST ;YES - SKIP OUTPUT OF CHARACTER
- ENDIF
- IF NOT VDM ;THEN GENERATE NORMAL CONSOLE OUT
- IF BACKSPC
- MOV A,C ;SET Z IF RUBOUT
- CPI 7FH ;IGNORE RUBOUTS
- IF PASCAL
- JZ FTEST ;GO CHECK FOR FLUSH
- ELSE
- RZ
- ENDIF
- LDA RUBFLG ;WAS RUBOUT THE LAST CHR INPUT?
- ORA A
- JZ CONO1 ;NO - JUST OUTPUT NORMALY
- XRA A ;YES - RESET RUBOUT FLAG
- STA RUBFLG
- ; WE NOW KNOW THAT CP/M IS ECHOING THE DELETED
- ; CHARACTER WHICH WE CAN IGNORE
- MVI C,8 ;MOVE CURSOR OVER DELETED CHR
- CALL CONO1
- MVI C,' ' ;OVERWRITE IT WITH A BLANK
- CALL CONO1 ;DELETING IT
- MVI C,8 ;ADJUST CURSOR TO NEW END OF LINE
- ;FALL THRU TO CONO1
- ENDIF ;END OF IF BACKSPC CONDITIONAL
- CONO1:
- IN 0
- RAR
- RAR
- JNC CONO1
- MOV A,C
- OUT 1
- ELSE ;ELSE OF IF NOT VDM, SO HERE VDM IS T
- MOV A,C
- ANI 0111$1111B ;MASK PARITY
- CPI 13 ;IGNORE CARRIAGE RETURNS
- RZ
- IF BACKSPC
- CPI 7FH ;IGNORE RUBOUTS
- RZ
- ENDIF
- PUSH H
- LHLD CURSOR
- CPI 10 ;LF?
- JZ NEWLINE
- MOV M,A
- IF BACKSPC
- LDA RUBFLG ;WAS RUBOUT LAST THING TYPED?
- ORA A
- JNZ CURLEFT ;YES - GO MOVE CURSOR LEFT
- ENDIF
- INX H
- MOV A,H
- CPI SCREEN/256+4
- JNZ EXIT
- NEWLINE:
- MVI M,' ' ;TURN OFF OLD CURSOR
- PUSH D
- LXI H,SCREEN
- LXI D,SCREEN+40H
- BLOCKMOVE:
- LDAX D
- MOV M,A
- INX D
- INX H
- MOV A,D
- CPI SCREEN/256+4
- JNZ BLOCKMOVE
- PUSH H
- BLNK:
- MVI M,' '
- INX H
- MOV A,H
- CPI SCREEN/256+4
- JNZ BLNK
- POP H
- POP D
- EXIT:
- MVI M,' '+80H
- SHLD CURSOR
- POP H
- ENDIF ;END OF IF NOT VDM CONDITIONAL
- ;
- IF PASCAL
- FTEST:
- CALL HCONST ;SEE IF CHR IS WAITING
- RZ ;NO - JUST EXIT FROM CONOUT
- CALL HCONIN ;YES - GO GET IT
- CPI 'S'-40H ;CONTROL S?
- JZ CONIN ;YES - GO WAIT FOR ANOTHER KEY TO CONT
- CPI 'F'-40H ;CONTROL F?
- JZ CNTLF ;YES - GO COMPLIMENT FLUSH FLAG
- STA BKCHR ;NO - STORE IT AS THE BREAK CHARACTER
- RET
- CNTLF:
- LDA FLUSH ;GET CURRENT FLUSH FLAG
- CMA ;COMPLIMENT
- STA FLUSH ;WRITE IT BACK
- RET
- ELSE ;NOT PASCAL I/O
- RET
- ENDIF ;END OF IF PASCAL CONDITIONAL
- ;
- IF VDM AND BACKSPC ;GENERATE VDM CURSOR LEFT CODE
- CURLEFT:
- XRA A ;RESET RUBOUT FLAG
- STA RUBFLG
- MVI M,' ' ;BLANK EXISTING CHARACTER
- DCX H ;BACK UP TO THE LEFT
- JMP EXIT ;TURN ON NEW CURSOR & EXIT
- ENDIF ;END OF IF VDM AND BACKSPC CONDITIONAL
- IF DIABLO
- ;
- ;
- ; TITLE BI-DIRECTIONAL DIABLO PRINTER DRIVER
- ; FILENAME BIDI.LIB
- ; AUTHOR Robert A. Van Valzah 9/30/79
- ; LAST REVISOR R.A.V. 11/10/79
- ; REASON byte squeezing
- ;
- ;
- ; plan of attack:
- ; ===============
- ; characters come in one at a time and are stored into
- ; a buffer until a line feed comes in. at this point,
- ; the line in the buffer is analized and a decision is
- ; made to print it forward or backward so as to mininmize
- ; the head movement.
- ;
- ; the gory details:
- ; =================
- ; characters which are printable are just stored in the
- ; buffer. blanks, on the other hand, are accumulated
- ; and the number of blanks to move is stored with a bias
- ; of 80h. the first byte of the buffer is an exception:
- ; it is initialized to 0h and is used to accumulate the
- ; number of spaces between the left margin and the first
- ; printable character (this is the location leolpos).
- ; the position of the rightmost printable character is
- ; keep track of as characters come in the location reolpos.
- ;
- ; as the head is moved across the page, its position is
- ; recorded in hpos. this information is used in
- ; conjunction with leolpos and reolpos to determine if
- ; printing forward or backward will cause the shortest
- ; printhead movement. if the printhead is currently to
- ; the left of the centerpoint of the line, then it is
- ; shortest to move to the left end and start printing.
- ; otherwise, it is shortest to move to the right end
- ; and print backward. if the printhead is exactly at
- ; the midpoint, the line is printed backward so as to
- ; leave the printhead as close to the left margin
- ; as possible.
- ;
- ;
- ; port i/o number equates
- ;
- base equ 0f4h
- datal equ base
- datah equ base+1
- cmand equ base+2
- stats equ base
- ;
- ; print formatting equates
- ;
- ncols equ 120 ;max number of cols/line (must be <=126)
- ;
- ; command bits
- ;
- restr equ 1 ;restore carriage
- chstb equ 2 ;character strobe
- xstb equ 4 ;carriage strobe
- ystb equ 8 ;paper feed strobe
- selpr equ 10h ;select printer
- selry equ 20h ;select ready
- rblft equ 40h ;ribbon lift
- ;
- ; status bits
- ;
- chrdy equ 8 ;character ready
- xrdy equ 10h ;carriage ready
- yrdy equ 20h ;paper feed ready
- ;
- ;
- ; print character in reg c
- ;
- print:
- mov a,c ;get char to print to reg a
- ani 7fh ;strip parity
- mov c,a
- lhld nbufad ;and pointer to next buffer address
- cpi 13 ;test for special characters
- rz ;ignore carriage return
- cpi 10
- jz plf ;line feed
- cpi 12
- jz pff ;form feed
- inr m ;assume a space
- cpi ' '
- rz ;was a space, all done
- dcr m ;un-do assumption
- rc ;was some other control char, ignore
- ;must be a printable character
- mov a,l ;see if buffer is about overflow
- cpi low(buf+ncols-2)
- rz
- cpi low(buf) ;see if this is first character
- mov a,m ;get amt to move before printing
- jz gotamt ;jump if first character
- cpi 81h
- jz noblank ;no blanks between last & this char
- sui 80h ;subtract flag value
- gotamt: ;amount to move in reg a
- inx h ;move over number of blanks
- db 11h ;lxi trick to skip following mvi a
- noblank:
- mvi a,1 ;like one blank between character
- mov m,c ;store the character comming in
- inx h ;point to next buffer location
- mvi m,81h ;init to one blank to next char
- shld nbufad ;update buffer pointer
- lxi h,reolpos ;update right end of line position
- add m
- mov m,a
- ret
- ;
- ; print line feed
- ;
- plf:
- mov a,l ;see if nbufad = buf
- cpi low(buf) ;if = then blank line
- jz lfend ;=, so don't print anything
- lda leolpos ;get left end of line position
- mov b,a ;save it in reg b
- lda reolpos ;get right end of line position
- add b ;add leolpos to reolpos
- rar ;divide by two to find midpoint
- mov b,a ;save line center point in reg b
- lda hpos ;get current head position
- sub b ;hpos-(leolpos+reolpos)/2
- jc forward ;middle > hpos
- ;
- ; print the buffer backward
- ;
- backward:
- mvi a,80h ;put end of buffer marker at left end
- sta buf
- lda reolpos ;get absolute position of right eol
- lxi h,hpos ;compute amount to move to get there
- sub m ;reolpos-hpos
- lhld nbufad ;get right most character to print
- dcx h
- bkwd1:
- ;signed distance to move is now in reg a
- call movprt ;move as needed and print a character
- dcx h ;point to movement amount
- mov a,m ;amount to move to reg a
- sui 80h ;test for eob mark
- jz lfend ;hit end of line
- dcx h ;assume this is a movement
- cma ;two's comp for leftward movement
- inr a
- jnc bkwd1 ;it was, reg a has amount to move
- inx h ;it wasn't, fix buffer pointer
- mvi a,0ffh ;move one space to the left
- jmp bkwd1
- ;
- ; print buffer forwards
- ;
- forward:
- mvi m,80h ;put in eob mark (also ignores trailing blanks)
- lxi h,buf ;pointer into buffer
- mov a,m ;absolute pos of leftmost char to reg a
- inx h ;point to first printable character
- push h ;save buffer pointer
- lxi h,hpos ;compute amount to move to get to leolpos
- sub m ;leolpos-hpos
- pop h ;restore buffer pointer
- fwd1:
- ;signed distance to move is now in reg a
- call movprt ;move and print a character
- inx h ;point to next character
- mov a,m ;get it
- sui 80h ;test for end of line
- jz lfend ;hit end of line
- inx h ;point to character
- jnc fwd1 ;was a movement, reg a has distance
- dcx h ;was a character, backup pointer
- mvi a,1 ;and set amount to move to 1
- jmp fwd1 ;go print next character
- ;
- ; common finish up routine for print line feed
- ;
- lfend:
- lxi h,lfstodo ;add one to line feeds to do before
- inr m ;printing next line
- jmp init1 ;reset pointers
- ;
- ; print a form feed
- ;
- pff:
- lda lpp ;get lines per page
- lxi h,lonp ;subtract lines printed on this page
- sub m ;leaving lines left on this page
- sta lfstodo ;which is the number of lfs to do
- ret
- ;
- ; move the number of character positions in reg a (taken as a
- ; signed number, + to the right, - to the left) and
- ; print the character pointed to by reg hl.
- ;
- movprt:
- mov c,m ;get character to print
- push h ;save while printing
- mov e,a ;save amount to move in reg e
- movr:
- in stats ;wait for all movement to stop
- ani chrdy+xrdy+yrdy
- jnz movr
- lxi h,hpos ;update the head position byte
- mov a,e
- add m ;add amount we are moving
- mov m,a
- mvi b,xstb ;ready x strobe for movstb
- lda chwid ;load up character muliplicaton factor
- call movstb ;send necessary x movement
- lda lpp ;lines per page to reg b
- mov b,a
- lxi h,lfstodo ;number of pending line feeds
- mov a,m ;skip movement if zero
- ora a
- jz noymov ;no y movement
- mov e,a ;movement to reg e for movstb
- mvi m,0 ;there will be none to do now
- lxi h,lonp ;keep track of line on page
- add m
- mov m,a
- sub b ;see if started new page
- jc samepage ;nope
- mov m,a ;yes - take lonp mod lpp
- samepage:
- lda linhgt ;load up line multiplicaton factor
- mvi b,ystb ;ready y strobe for movstb
- call movstb ;send necessary y movement
- noymov:
- mov e,c ;send character
- mvi b,chstb ;send character strobe
- mvi a,1 ;dummy multiplication factor
- call movstb
- pop h
- ret
- ;
- ; move the signed amount in reg e using value in reg a as
- ; a mulitplication factor to get the number of increments
- ; then send strobe in reg b.
- ;
- movstb:
- push psw ;save multiplication factor
- mov a,e ;form a 16 bit amount to move in reg de
- ral ;sign of movement into carry
- sbb a ;generate sign extention
- mov d,a ;16-bit signed movement now in reg de
- pop psw ;get multiplication factor
- lxi h,0 ;initialize product
- mulbyw: ;multiply
- dad d
- dcr a
- jnz mulbyw ;keep multiplying
- mov a,h ;is this leftward movement?
- ora a
- jp posmov ;no - distance is ok
- xra a ;yes - negate distance
- sub l ;reg a = 0 - low order
- mov l,a ;which is low order compliment
- sbb h ;now subtract out high order and
- sub l ;subtract out excess low order
- ;complimented distance now in reg a and reg l
- ori 4 ;and set negative motion bit
- posmov:
- cma ;high order data is active low
- out datah ;send high order data
- mov a,l ;get low order data
- cma ;it too is active low
- out datal ;send low order data
- ;fall thru to strobe
- ;
- ; pulse strobe in reg b
- ;
- strobe:
- xra a ;delay a while for data set-up time
- dlay:
- dcr a
- jnz dlay
- mvi a,0ffh-selpr-rblft-selry
- push psw ;save bits which are allways high
- sub b ;lower appropriate strobe bit
- out cmand ;send strobe bit low
- pop psw ;and send it high
- out cmand
- ret
- ;
- ; init for printing
- ;
- init:
- mvi b,restr ;pulse restore line to
- call strobe ;reset printer
- xra a ;set software head position to zero
- sta hpos
- sta lonp ;reset line counter to top of page
- sta lfstodo ;zero out number of line feeds to do
- init1: ;empty buffer entry point
- xra a ;reset right end of line position
- sta reolpos
- lxi h,buf ;next buffer address pointer
- shld nbufad
- mov m,a ;inits left end of line position
- ret
- ;
- ; ram areas
- ;
- lonp ds 1 ;current line on page, 0 = first line
- lfstodo ds 1 ;line feeds to do before printing
- hpos ds 1
- reolpos ds 1
- nbufad ds 2
- buf:
- leolpos: ;address of byte containing left eol
- ds 1
- lmostch: ;address of left most character
- ds ncols
- ;
- ENDIF ;END OF IF DIABLO
- ;
- END