|
DataMuseum.dkPresents historical artifacts from the history of: CP/M |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about CP/M Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 46080 (0xb400) Types: TextFile Names: »DFDBIOS.A86«
└─⟦be0857eee⟧ Bits:30004395 CP/M-86 files - CR8 Dual floppy └─ ⟦this⟧ »DFDBIOS.A86«
TITLE 'CR8 - CP/M-86 BIOS VERS. 3.0' PAGESIZE 56 PAGEWIDTH 111 ; AUTHOR: LARS WINTHER DATE: 841801 ; MODIFIED FOR DUAL FLOPPY ONLY BY Leif Neland ;****************************************************************************** ; CHRISTIAN ROVSING A/S, CP/M-86 BASIC I/O MODULE FOR MP2 BOARD ; AND MINI FLOPPIES. ;****************************************************************************** ; ; ; THIS CP/M-86 BIOS IS SETUP FOR CP/M-86 ON A MP2 BOARD. ; CONSOLE,PRINTER AND FLOPPY DISK I/O IS HANDLED VIA Z80 BASED ; DRIVERS USING THE ONBOARD FLOPPY AND SERIAL I/O CONTROLLER CHIPS. ; ; ; ACCESS AND CONTROL OF THE MINI FLOPPY WILL BE THROUGH ; THE DISK CONTROLLER CIRCUITRY OF THE MP2 BOARD USING Z80 BASED DRIVERS. ; THIS BIOS CONFIGURATION WILL SUPPORT TWO MINI FLOPPY DRIVES. ; ; MINI FLOPPY FORMAT IS AS FOLLOWS: ; ; 77 TRACKS ; 16 RECORDS PER TRACK ; TWO HEADS/SIDES ; 256 BYTE RECORDS ; ; ; BIOS ACCESS TO THE MINI FLOPPY IS DONE IN REAL PAIRS OF 256 BYTE ; SECTORS TO AND FROM THE 512 BYTE HOST BUFFER. ; REAL ACCESS TO THE SECTOR PAIRS IS AS FOLLOWS: ; ; 1,2; 5,6; 9,10; 13,14; 3,4; 7,8; 11,12; 15,16; ; ; ; EJECT ; ;DEFINE TRUE AND FALSE ASSEMBLY PARAMETERS ; TRUE EQU -1 ;DEFINE TRUE FALSE EQU NOT TRUE ;DEFINE FALSE ; ; ;CP/M-86 SYSTEM PARAMETERS ; BDOS EQU 0B06H ;BDOS ENTRY POINT BIOS EQU 2500H ;START OF BIOS JUMP VECTOR TABLE SYSINT EQU 224 ;SYSTEM CALL INTERRUPT ; ; ;VERSION NUMBER AND DATE ; VERSION EQU 30 ;VERSION NUMBER MONTH EQU 01 ;MONTH DAY EQU 18 YEAR EQU 84 ;YEAR LAST TWO DIGITS ; ; ;ASCII CHARACTER DEFINITIONS ; BS EQU 008H ;ASCII BACK SPACE CHARACTER LF EQU 00AH ;ASCII LINE FEED CHARACTER CR EQU 00DH ;ASCII CARRIAGE RETURN CHARACTER ESC EQU 01BH ;ASCII ESCAPE CHARACTER RUBOUT EQU 07FH ;ASCII RUBOUT CHARACTER ; ; ;BDOS CONSTANTS ON ENTRY TO "WRITE" ; WRALL EQU 0 ;WRITE TO ALLOCATED BLOCK WRDIR EQU 1 ;WRITE TO DIRECTORY WRUAL EQU 2 ;WRITE TO UNALLOCATED BLOCK ; EJECT ;****************************************************************************** ; INTER-CPU COMMUNICATION CONSTANTS ;****************************************************************************** ; ; IFTOFF EQU 8020H ;INTERFACE TABLE OFFSET IN Z80 RAM CHANNEL EQU 40H ;NBR OF BYTES PR INTERFACE CHANNEL QUEUE EQU 10H ;NBR OF BYTES PR QUEUE ; TXE EQU 0*QUEUE ;OFFSET IN CHANNEL TO TX EMPTY QUEUE TXF EQU 1*QUEUE ;OFFSET IN CHANNEL TO TX FULL QUEUE RXF EQU 2*QUEUE ;OFFSET IN CHANNEL TO RX FULL QUEUE RXE EQU 3*QUEUE ;OFFSET IN CHANNEL TO RX EMPTY QUEUE ; BC EQU 01 ;OFFSET IN QUEUE TO BUFFER COUNT FB EQU 02 ;OFFSET IN QUEUE TO "FIRST" POINTER LB EQU 04 ;OFFSET IN QUEUE TO "LAST" POINTER SF EQU 06 ;OFFSET IN QUEUE TO SLAVE FLAG MF EQU 08 ;OFFSET IN QUEUE TO MASTER FLAG ; RETQ EQU -2 ;OFFSET FROM BUFFER POINTER TO RETURN Q CHAIN EQU 00 ;OFFSET FROM BUFFER POINTER TO CHAIN BYTEC EQU 02 ;OFFSET FROM BUFFER POINTER TO BYTECNT DPTR EQU 04 ;OFFSET FROM BUFFER POINTER TO DATAPTR ; CONCHA EQU CHANNEL*2 ;CONSOLE CHANNEL OFFSET IN I/F TABLE CONOPC EQU 0FFH ;CONSOLE DATA OPCODE ; LPCHA EQU CHANNEL*3 ;LINE PRINTER CH. OFFSET IN I/F TABLE LPOPC EQU 0FFH ;LINE PRINTER DATA OPCODE ; ENTDLDU EQU 03H ;BUFFER TYPE FOR ENTIRE DATA LDU ENTCLDU EQU 07H ;BUFFER TYPE FOR COMMAND/STATUS LDU ; OPENOPC EQU 04H ;OPEN OPCODE OPFORM EQU 10H ;SERIAL OPEN PARAMETER FORMAT CODE ; CBLENGTH EQU 20H ;MAX BYTECOUNT IN SERIAL BUFFERS LBLENGTH EQU 20H ;...DEFINED IN SCRIMP/M ; EJECT ; ;****************************************************************************** ; ;CP/M-86 TO HOST DISK CONSTANTS ; BLKSIZ EQU 2048 ;CP/M-86 ALLOCATION SIZE HSTSIZ EQU 512 ;HOST DISK SECTOR SIZE ; ; HDSPT EQU 18 ;HOST HARD DISK SECTORS/TRACK ; FDSPT EQU 8 ;HOST MINI FLOPPY DISK 256 BYTE SECTOR ;PAIRS PER TRACK HSTBLK EQU HSTSIZ/128 ;CP/M-86 SECTS/HOST BUFF ; ;CPMSPT EQU HSTBLK * HSTSPT ;CP/M-86 SECTORS/TRACK ; ;THIS VALUE CHANGES ACCORDING TO ; ;MINI OR HARD DISK. ; ; ;SECTOR SKEW INTERLACE FACTOR ; SKEW EQU 00 ;SECTOR SKEW FACTOR ; SECMSK EQU 03 ;SECTOR MASK SECSHF EQU 02 ;SECTOR SHIFT FACTOR (LOG2(SECMSK)) ; EJECT ;****************************************************************************** ; CP/M-86 BIOS DISK CONFIGURATION SELECTION OPTIONS ;****************************************************************************** ; DEFDSK EQU 00H ;DEFAULT BOOTED DISK ; 00=A: ; 01=B: MAXDISK EQU 2 ; A: AND B: ; RECSIZE EQU 0200H ;512 BYTE RECORDS ; ; ;FLOPPY DISK INTERFACE DRIVER CONSTANTS ; FDCHA EQU CHANNEL*4 ;FLOPPY CHANNEL OFFSET IN I/F TABLE COMOPC EQU 09H ;COMMAND OPCODE RESTORE EQU 00H ;RESTORE COMMAND CODE READFD EQU 01H ;READ DISK COMMAND CODE WRITEFD EQU 02H ;WRITE DISK COMMAND CODE WRTRACK EQU 03H ;FORMAT TRACK COMMAND CODE ; CPUSYNC EQU 0FDH ;FLOPPY DRIVER SYNCHRONIZATION ERROR ; ; PIOB EQU 09H ;CHANNEL B PIO DATA ADDRESS ; TIMER EQU 20H ;INT.CTLR BASE VECTOR TYPE TICKI EQU 2 ;INT LEVEL USED FOR TICK INT RTC EQU (TIMER+TICKI)*4 ;RTC INT. VECTOR OFFSET ; EJECT ;HOST ADAPTER I/O PORT ADDRESSING PARAMETERS ; IOBASE EQU 090H ;BASE I/O PORT ADDRESS OF CONTROLLER ; CSR EQU IOBASE ;CHANNEL STATUS REGISTER PORT CCSR EQU IOBASE+1 ;COMMAND COMPLETION STATUS REGISTER DADDRL EQU IOBASE+2 ;DATA BUFFER LOW ADDRESS PORT DADDRM EQU IOBASE+3 ;DATA BUFFER MID ADDRESS PORT CADDRL EQU IOBASE+4 ;COMMAND BUFFER LOW ADDRESS PORT CADDRM EQU IOBASE+5 ;COMMAND BUFFER MID ADDRESS PORT DADDRH EQU IOBASE+6 ;DATA BUFFER HIGH ADDRESS PORT CADDRH EQU IOBASE+7 ;COMMAND BUFFER HIGH ADDRESS PORT ; EJECT ; CSEG ; ORG 0 CCP: ORG BIOS ;START OF BIOS ; ;****************************************************************************** ;I/O JUMP VECTOR. THIS IS WHERE CP/M-86 CALLS WHENEVER IT NEEDS TO DO ;ANY INPUT/OUTPUT OPERATION. USER PROGRAMS MAY USE THESE ENTRY POINTS ;****************************************************************************** ; JMP INIT ;FROM COLD START LOADER JMP WBOOT ;FROM WARM BOOT JMP CONST ;CHECK CONSOLE KB STATUS JMP CONIN ;READ CONSOLE CHARACTER JMP CONOUT ;WRITE CONSOLE CHARACTER JMP LPTOUT ;WRITE LISTING CHAR JMP PUNCH ;WRITE PUNCH CHAR JMP READER ;READ READER CHAR JMP HOME ;MOVE DISK TO TRACK ZERO JMP SELDSK ;SELECT DISK DRIVE JMP SETTRK ;SEEK TO TRACK IN REG A JMP SETSEC ;SET SECTOR NUMBER JMP SETDMA ;SET DMA OFFSET ADDRESS JMP READ ;READ SELECTED SECTOR JMP WRITE ;WRITE SELECTED JMP LPTSTAT ;RETURN LIST STATUS JMP SECTRAN ;SECTOR TRANSLATE JMP SETDMAB ;SET DMA SEGMENT ADDRESS JMP GETSEGB ;GET MEM DESCRIB TABLE OFFSET JMP GETIOB ;GET I/O MAPPING BYTE JMP SETIOB ;SET I/O MAPPING BYTE ; EJECT ;****************************************************************************** ; ROUTINE TO CALL SIMPLE I/O FUNCTIONS VIA VECTABLE JUMP VECTORS ;****************************************************************************** ; SIMPLEIO: PUSH DS PUSH CS POP DS PUSH DX MOV DX,SI ADD SI,DX ADD SI,DX ;MULTIPLY SI BY 3 ADD SI,OFFSET VECTABLE POP DX CALL SI ;INDIRECT CALL THRU ADDRESS FIELDS OF PUSHF POP SI ;RETURN FLAGS TO CALLER IN SI REG. POP DS IRET ;...SIMPLE I/O VECTOR TABLE ; EJECT ;****************************************************************************** ; COLD BOOT INITIALIZATION ROUTINE ;****************************************************************************** ; INIT: CLI ;LOCK OUT INTERRUPTS MOV AX,CS ;GET OS SEGMENT ADDRESS MOV SS,AX ;INITIALIZE STACK SEGMENT MOV SP,OFFSET STKBASE ;...AND INITIALIZATION STACK MOV AX,0 MOV DS,AX ;PREPARE FOR INT VECTOR INIT MOV ES,AX MOV INT0OFF,OFFSET TRAP ;SETUP INT0 TO ADDRESS TRAP ROUTINE MOV INT0SEG,CS ;THIS IS 4-BYTE VECTORS MOV DI,4 MOV SI,0 MOV CX,510 ;SET REPEAT COUNTER CLD ;SET FORWARD DIRECTION REP MOVS AX,AX ;PROPAGATE TRAP VECTOR TO ALL OF TABLE MOV BDOSOFF,BDOS ;INIT SYSTEM CALL VECTOR MOV RTCOFF,OFFSET RTCINT ;INIT REAL TIME CLOCK VECTOR MOV BIOSOFF,OFFSET SIMPLEIO ; ; *** INTERRUPT VECTORS INITIALIZED, NOW INIT SYSTEM WORKING STORAGE *** ; MOV AX,CS ;GET OS SEGMENT ADDRESS MOV DS,AX ;INITIALIZE DATA SEGMENT MOV ES,AX ;...AND EXTRA SEGMENT MOV IOERR,0 ;START OF ZERO FILL AREA MOV SI,OFFSET IOERR MOV DI,OFFSET IOERR+1 MOV CX,WORD PTR (ENDZ-STARTZ)-1 CLD ;SET FORWARD DIRECTION REP MOVS AL,AL ;DO THE ZERO FILL ; ; ; *** INITIALIZE MEMMORY REGION TABLE *** ; IN AL,PIOB ;GET SWITCH SETTING AND AL,0CH ;LEAVE ONLY SWITCH 3 AND 4 BITS XOR AL,0CH ;IF BOTH SWITCHES ARE OPEN JZ NOEXTRAM ;THEN ASSUME NO RAM BOARD INSTALLED SHR AL,1 SHR AL,1 MOV CL,AL ;COMPUTED SHIFT COUNT MOV AH,10H ;COMPUTE MEMMORY SEGMENT SIZE SHL AH,CL ;...IN PARAGRAPH UNITS MOV AL,0 MOV WORD PTR MTR+7,AX ;SAVE IN TABLE MOV WORD PTR MTR+5,4000H ;SAVE START OF EXTRA RAM BOARD MOV BYTE PTR MTR,02 ;ELSE ASSUME TWO RAM SEGMENTS NOEXTRAM: ; ; *** INITIALIZE INTERRUPT CONTROLER *** ; MOV AL,13H OUT 0C0H,AL ;SEND ICW1 MOV AL,TIMER OUT 0C1H,AL ;SEND ICW2 MOV AL,03 OUT 0C1H,AL ;SEND ICW4 MOV AL,0FBH OUT 0C1H,AL ;ENABLE PIT-0 INTERRUPTS STI ;LET IN REAL TIME CLOCK ; ; *** PRINT HELLO MESSAGE ON CONSOLE *** ; MOV BX,OFFSET SMSG ;PRINT OPENING MESSAGE CALL PRTMSG ;PRINT MESSAGE STRING MOV CL,DEFDSK ;GIVE CP/M-86 "DISK SELECTED" NUMBER JMP CCP ;JUMP TO CCP WITH MINI SET CODE ; EJECT ;****************************************************************************** ; WARM BOOT ROUTINE ;****************************************************************************** ; WBOOT: MOV AL,0 ;SELECT HEAD ZERO (SELECTED DISK = A:) MOV SEKMHD,AL ;SET FLAGS TO HARD DISK FOR POSSIBLE ERROR MOV HSTMHD,AL ;..ROUTINE SCAN MOV HSTACT,AL ;SET HOST BUFFER INACTIVE MOV UNACNT,AL ;CLEAR UNALLOCATED COUNT JMP CCP+6 ;GO BACK TO CP/M-86 ; ; ; ;****************************************************************************** ; CONSOLE STATUS ROUTINE ; RETURNS AL=00H IF NO INPUT READY ; RETURNS AL=FFH IF INPUT READY ;****************************************************************************** ; CONST: PUSH ES TEST PCIB,0FFFFH ;TEST IF CONSOLE INPUT BUFFER PENDING JNZ PIB ;...FLAG INPUT READY IF SO ; MOV AX,2000H ;INITIALIZE ES TO START MOV ES,AX ;...OF MP2-Z80 RAM MOV BX,IFTOFF+CONCHA+RXF ;QUEUE OFFSET CALL LOOKQ ;GET NBR OF BUFFERS IN QUEUE AND AL,AL JZ CSEXIT ;EXIT IF QUEUE EMPTY PIB: MOV AL,0FFH ;FLAG QUEUE NOT EMPTY CSEXIT: POP ES RET ; EJECT ;****************************************************************************** ; CONSOLE INPUT ROUTINE ; GETS CHAR TO (AL) REGISTER ;****************************************************************************** ; CONIN: PUSH ES MOV AX,2000H ;Z80 RAM BASE ADDRESS MOV ES,AX TEST PCIB,0FFFFH ;TEST IF BUFFER PENDING JNZ CONIN3 ;GO PICK NEXT CHARACTER THERE ; ; ;NO BUFFER PENDING, TRY TO GET ONE. ; CONIN1: MOV BX,IFTOFF+CONCHA+RXF ;QUEUE OFFSET CALL DEQ ;GET BUFFER JNC CONIN1 ;WAIT IF NO BUFFER IN QUEUE XCHG BX,DX ;GET BUFFER ADDRESS INTO BX MOV DX,ES:ÆBXÅ+DPTR ;GET 1. DATA ADDR. FROM QHEAD XCHG BX,DX CMP ES:BYTE PTR ÆBXÅ,ENTDLDU;MUST BE ENTIRE DATA LDU JE CONIN2 ;GO GET DATA IF LDU TYPE OK MOV BX,IFTOFF+CONCHA+RXE ;ELSE CALL ENQ ;RELEASE BUFFER AND JMPS CONIN1 ;...GO TRY AGAIN ; ; ;INSTALL NEWLY RECEIVED BUFFER AS PENDING. ; CONIN2: MOV PCIB,DX ;SAVE BUFFER ADDRESS INC BX INC BX ;POINT TO DATABYTE MOV CIBP,BX ;SAVE POINTER TO NEXT CHARACTER MOV BX,DX DEC ES:WORD PTR BYTECÆBXÅ ;DECREMENT BYTECOUNT BY TWO DEC ES:WORD PTR BYTECÆBXÅ ; EJECT ; ; ;GET CHARACTER FROM PENDING BUFFER. ; CONIN3: MOV BX,CIBP ;GET DATAPOINTER MOV AL,ES:ÆBXÅ ;GET DATA FROM BUFFER INC BX ;UPDATE POINTER MOV CIBP,BX ;SAVE NEW POINTER MOV BX,PCIB ;GET BUFFER ADDRESS DEC ES:WORD PTR BYTECÆBXÅ ;DECREMENT BYTECOUNT IN BUFFER JNZ NOTMTY ;EXIT IF NOT EMPTY ; ; ;NO MORE JUICE IN THAT ONE, RELEASE IT. ; MOV DX,PCIB ;GET BUFFER ADDRESS MOV BX,IFTOFF+CONCHA+RXE ;EMPTY QUEUE OFFSET PUSH AX ;SAVE CHARACTER CALL ENQ ;RETURN BUFFER MOV PCIB,0 ;NO BUFFER PENDING POP AX ; ; ;THAT'S ALL FOLKS, RETURN TO CALLER ; NOTMTY: POP ES AND AL,7FH ;MASK OFF PARITYBIT RET ; EJECT ; ; ;CONSOLE OUTPUT ROUTINE ; SENDS CHAR IN (CL) REGISTER ; CONOUT: MOV AX,2000H ;Z80 RAM BASE ADDRESS MOV CONSEMAP,AH ;LOCKOUT FORWARD TIMER PUSH ES MOV ES,AX MOV BX,CONPTR ;GET CONSOLE BUFFER DATA POINTER OR BX,BX ;IF OLD POINTER INVALID JZ NEWCBUF ;...GO INITIATE NEW CONSOLE BUFFER ; MOV ES:ÆBXÅ,CL ;ELSE SAVE CHARACTER IN PENDING BUFFER INC CONPTR ;UPDATE POINTER MOV BX,CONBUF ;GET BUFFER ADDRESS MOV CL,ES:BYTECÆBXÅ ;GET OLD BYTECOUNT FROM BUFFERHEAD INC CL MOV ES:BYTECÆBXÅ,CL ;STORE NEW BYTECOUNT CMP CL,CBLENGTH ;TEST IF BUFFER IS FULL JB CONOEXIT ;...EXIT IF NOT ; MOV CONPTR,0 ;FLAG POINTER AS INVALID MOV DX,IFTOFF+CONCHA+TXF ;QUEUE OFFSET XCHG BX,DX CALL ENQ ;SEND BUFFER TO Z80 JMPS CONOEXIT ;EXIT CONOUT ; EJECT ; NEWCBUF: PUSH CX ;SAVE CHARACTER IN CL CONOUT1: MOV BX,IFTOFF+CONCHA+TXE ;QUEUE OFFSET CALL DEQ ;GET EMPTY BUFFER JNC CONOUT1 ;WAIT IF NO BUFFER IN QUEUE ; MOV CONBUF,DX MOV BX,0FH ADD BX,DX ;COMPUTE NEXT-DATA POINTER MOV CONPTR,BX ;SAVE TILL NEXT CONOUT OPERATION DEC BX POP AX ;RESTORE CHARACTER INTO AL MOV ES:ÆBXÅ,AL ;SAVE CHARACTER IN BUFFER DEC BX MOV ES:BYTE PTR ÆBXÅ,CONOPC ;NO LDU NUMBERS DEC BX MOV ES:BYTE PTR ÆBXÅ,ENTDLDU;BUFFER IS ENTIRE DATA LDU XCHG BX,DX MOV ES:DPTRÆBXÅ,DX ;SAVE POINTER IN QHEAD MOV ES:WORD PTR BYTECÆBXÅ,3 ;SET BYTECOUNT CONOEXIT: POP ES ;RESTORE SEGMENT MOV CONSEMAP,0 ;LET IN FORWARD TIMER RET ; EJECT ; ;PUNCH PAPER TAPE, DEFAULT IS SERIAL PRINTER CHANNEL ; PUNCH: JMP LPTOUT ;SEND PUNCH TO SERIAL OUTPUT ;RETURN THROUGH LPTOUT ; ; ;READ PAPER TAPE, DEFAULT IS SERIAL PRINTER CHANNEL ; READER: JMP LPTINP ;READ FROM SERIAL INPUT ;RETURN THROUGH LPTINP ; ; ; ; ;LINEPRINTER STATUS ROUTINE ; RETURNS AL=00H IF LP NOT READY ; RETURNS AL=FFH IF LP READY LPTSTAT: PUSH ES MOV AX,2000H ;INITIALIZE ES TO START MOV ES,AX ;...OF MP2-Z80 RAM MOV BX,IFTOFF+LPCHA+TXE ;QUEUE OFFSET CALL LOOKQ ;GET NBR OF BUFFERS IN QUEUE AND AL,AL JZ LPEXIT ;EXIT IF QUEUE EMPTY MOV AL,0FFH ;FLAG QUEUE NOT EMPTY LPEXIT: POP ES RET ; EJECT ; ;LINEPRINTER OUTPUT ROUTINE ; SEND CHARACTER IN (CL) REGISTER ; LPTOUT: MOV AX,2000H ;Z80 RAM BASE ADDRESS MOV LPTSEMAP,AH ;LOCK OUT FORWARD TIMER PUSH ES MOV ES,AX MOV BX,LPTPTR ;GET PRINTER BUFFER DATA POINTER OR BX,BX ;IF OLD POINTER INVALID JZ NEWPBUF ;...GO INITIATE NEW PRINTER BUFFER ; MOV ES:ÆBXÅ,CL ;ELSE SAVE CHARACTER IN PENDING BUFFER INC LPTPTR ;UPDATE POINTER MOV BX,LPTBUF ;GET BUFFER ADDRESS MOV CL,ES:BYTECÆBXÅ ;GET OLD BYTECOUNT FROM BUFFERHEAD INC CL MOV ES:BYTECÆBXÅ,CL ;STORE NEW BYTECOUNT CMP CL,LBLENGTH ;TEST IF BUFFER IS FULL JB LPTOEXIT ;...EXIT IF NOT ; MOV LPTPTR,0 ;FLAG POINTER AS INVALID MOV DX,IFTOFF+LPCHA+TXF ;QUEUE OFFSET XCHG BX,DX CALL ENQ ;SEND BUFFER TO Z80 JMPS LPTOEXIT ;EXIT LPTOUT ; EJECT ; NEWPBUF: PUSH CX ;SAVE CHARACTER IN CL LPTOUT1: MOV BX,IFTOFF+LPCHA+TXE ;QUEUE OFFSET CALL DEQ ;GET EMPTY BUFFER JNC LPTOUT1 ;WAIT IF NO BUFFER IN QUEUE ; MOV LPTBUF,DX MOV BX,0FH ADD BX,DX ;COMPUTE NEXT-DATA POINTER MOV LPTPTR,BX ;SAVE TILL NEXT LPTOUT OPERATION DEC BX POP AX ;RESTORE CHARACTER INTO AL MOV ES:ÆBXÅ,AL ;SAVE CHARACTER IN BUFFER DEC BX MOV ES:BYTE PTR ÆBXÅ,LPOPC ;NO LDU NUMBERS DEC BX MOV ES:BYTE PTR ÆBXÅ,ENTDLDU;BUFFER IS ENTIRE DATA LDU XCHG BX,DX MOV ES:DPTRÆBXÅ,DX ;SAVE POINTER IN QHEAD MOV ES:WORD PTR BYTECÆBXÅ,3 ;SET BYTECOUNT LPTOEXIT: POP ES ;RESTORE SEGMENT MOV LPTSEMAP,0 ;LET IN FORWARD TIMER RET ; EJECT ; ;SELECT DISK NUMBER ACCORDING TO (CL) ; ; 0=A:,1=B: ; SELDSK: MOV BX,0 ;RETURN 0000 IN BX IF ERROR CMP CL,MAXDISK ;IS SELECT MORE THAN MAX TABLE ENTRY JB SEL1 ;RETURN WITH ERROR, IF NOT VALID TABLE ENTRY RET SEL1: PUSH BX ;CHECK IF VALID FROM TABLE MOV BL,CL SHL BL,1 ;MAKE UNIT SELECT TABLE INDEX SHL BL,1 ADD BX,OFFSET DSTAB ;DRIVE SETUP TABLE BASE MOV AL,ÆBXÅ ;GET VALIDITY BYTE THIS UNIT OR AL,AL ;ZERO = ILLEGAL XCHG BX,DX ;SAVE POINTER IF NO EXIT POP BX ;GET BACK BX TO ZERO FOR ERROR EXIT JNZ SEL2 ;RETURN ON ILLEGAL UNIT RET SEL2: MOV SEKDSK,CL ; XCHG BX,DX ;IS A LEGAL SELECT THEN PROCESS ;PARAMETERS INC BX ;POINT TO DRIVE PHYSICAL UNIT NUMBER ;DRIVE PHYSICAL UNIT NUMBER NOT USED ;TILL I/O ROUTINES WHEN THE DRIVE IS USED ; INC BX ;POINT TO MINI/HARD FLAG MOV AL,ÆBXÅ MOV SEKMHD,AL ;SET CURRENTLY SELECTED TYPE FLAG ; INC BX ;POINT TO CP/M-86 DISK PARAMETER TABLE INDEX MOV BL,ÆBXÅ ;MAKE DOUBLE TABLE INDEX*16 MOV BH,00H SHL BX,1 SHL BX,1 SHL BX,1 SHL BX,1 ADD BX,OFFSET DPBASE ;BX=POINTER TO DRIVE PARAMETER TABLE RET ; ; ; ; ;SUBROUTINE TO GET THE PHYSICAL DRIVE NUMBER OUT OF THE DRIVE ;SELECT PARAMETER TABLE INTO (CL) ; GETDRNO: MOV BL,HSTDSK ;GET UNIT CP/M-86 THINKS WE HAVE SHL BL,1 ;SETUP INDEX INTO FOUR BYTE TABLE SHL BL,1 ;ENTRIES MOV BH,0 MOV CL,OFFSET DSTAB+1ÆBXÅ ;GET PHYSICAL NUMBER INTO (CL) RET ; EJECT ;****************************************************************************** ; SELECT TRACK ZERO FOR NEXT DISK ACCESS (HOME DISK) ;****************************************************************************** ; HOME: MOV AL,HSTWRT ;CHECK FOR PENDING WRITE OR AL,AL JNZ HOMEIT MOV HSTACT,AL ;CLEAR HOST ACTIVE FLAG HOMEIT: MOV SEKTRK,0000H ;ITS LIKE WE ARE GOING TO TRACK 0 XOR AL,AL RET ;RETURN FROM HOME, O.K. ; ; ;SET TRACK NUMBER SPECIFIED BY CX REG. ; SETTRK: MOV SEKTRK,CX ;TRACK TO SEEK RET ; ; ; ;TRANSLATE THE SECTOR GIVEN BY CX REG. ; ; NO TRANSLATE DONE AT THIS TIME. ; WE WILL TRANSLATE THE MINI FLOPPY AT THE PHYSICAL SECTOR ; BASIS IN THE MINI FLOPPY READ/WRITE SETUP ROUTINE. ; SECTRAN: MOV BX,CX RET ;RETURN FROM SECTRAN ; ; ; ; ;SET DISK SECTOR NUMBER ; SETSEC: MOV SEKSEC,CL ;SECTOR TO SEEK RET ;RETURN FROM SETSEC EJECT ; ; ;SET DISK DMA OFFSET ; SETDMA: MOV DMAADR,CX ;PUT AT DMA ADR ADDRESS RET ;RETURN FROM SETDMA ; ; ; ;SET DMA SEGMENT ; SETDMAB: MOV DEFDMASG,CX RET ; ; ; ;GET MEMMORY REGION TABLE OFFSET ; GETSEGB: MOV BX,OFFSET MTR RET ; ; ; ;GET IOBYTE ; GETIOB: MOV AL,IOBYTE RET ; ; ; ;SET IOBYTE ; SETIOB: MOV IOBYTE,CL RET ; EJECT ; ; *** READ THE SELECTED CP/M-86 SECTOR *** ; READ: XOR AL,AL MOV UNACNT,AL ;CLEAR UNALLOCATED COUNT INC AL MOV READOP,AL ;READ OPERATION MOV RSFLAG,AL ;MUST READ DATA MOV AL,WRUAL MOV WRTYPE,AL ;TREAT AS UNALLOCCATED JMP RWOPER ;TO PERFORM THE READ ; ; ; *** WRITE THE SELECTED CP/M-86 SECTOR *** ; WRITE: MOV READOP,0 ;NOT A READ OPERATION MOV WRTYPE,CL CMP CL,WRUAL ;WRITE UNALLOCATED? JNE CHKUNA ;CHECK FOR UNALLOCATED ; ;WRITE TO UNALLOCATED, SET PARAMETERS ; MOV UNACNT,BLKSIZ/128 ;NEXT UNALLOCATED RECORDS MOV AL,SEKDSK ;DISK TO SEEK MOV UNADSK,AL ;UNADSK = SEKDSK MOV BX,SEKTRK MOV UNATRK,BX ;UNATRK = SECTRK MOV AL,SEKSEC MOV UNASEC,AL ;UNASEC = SEKSEC ; ;CHECK FOR WRITE TO UNALLOCATED SECTOR ; CHKUNA: MOV AL,UNACNT ;ANY UNALLOCATED REMAINING? OR AL,AL JZ ALLOC ;SKIP IF NOT ; EJECT ; ;MORE UNALLOCATED RECORDS REMAIN ; DEC AL ;UNACNT = UNACNT-1 MOV UNACNT,AL MOV AL,SEKDSK ;SAME DISK? CMP AL,UNADSK ;SEKDSK = UNADSK? JNE ALLOC ;SKIP IF NOT ; ; ;DISKS ARE THE SAME ; MOV BX,UNATRK CMP BX,SEKTRK ;SEKTRK = UNATRK? JNE ALLOC ;SKIP IF NOT ; ; ;TRACKS ARE THE SAME ; MOV AL,SEKSEC ;SAME SECTOR? MOV BX,OFFSET UNASEC CMP AL,ÆBXÅ ;SEKSEC = UNASEC? JNE ALLOC ;SKIP IF NOT ; EJECT ; ;MATCH, MOVE TO NEXT SECTOR FOR FUTURE REFERENCE ; INC AL MOV ÆBXÅ,AL ;UNASEC=UNASEC+1 MOV AH,HDSPT ;USE HARD DISK SECTORS PER TRACK TEST SEKMHD,0FFH ;CHECK KIND OF DISK JZ MTCHCMP ;HARD DISK MATCH MOV AH,FDSPT ;USE MINI DISK SPT MTCHCMP: CMP AL,AH JB NOOVF ;SKIP IF NO OVERFLOW ; ; ;OVERFLOW TO NEXT TRACK ; MOV BYTE PTR ÆBXÅ,0 ;UNASEC = 0 INC WORD PTR UNATRK ;UNATRK = UNATRK+1 ; ; ;MATCH FOUND, MARK AS UNNECESSARY READ ; NOOVF: MOV RSFLAG,0 ;RSFLAG = 0 JMPS RWOPER ;TO PERFORM THE WRITE ; ; ;NOT AN UNALLOCATED RECORD, REQUIRES PRE-READ ; ALLOC: XOR AL,AL ;0 TO A REG. MOV UNACNT,AL ;UNACNT = 0 INC AL ;1 TO A REG. MOV RSFLAG,AL ;RSFLAG = 1 ; EJECT ;****************************************************************************** ; COMMON CODE FOR READ AND WRITE OPERATIONS ;****************************************************************************** ; RWOPER: ;ENTER HERE TO PERFORM THE READ/WRITE MOV ERFLAG,0 ;NO ERRORS (YET) MOV AL,SEKSEC ;COMPUTE HOST SECTOR MOV CL,SECSHF SHR AL,CL ; ; ;OUR DISK CONTROLLER NUMBERS ITS RECORDS FROM 1 AND NOT ZERO ;SO FIXUP THE "SEKHST" SECTOR NUMBER ; INC AL MOV SEKHST,AL ;HOST SECTOR TO SEEK ; ; ;ACTIVE HOST SECTOR? ; MOV BX,OFFSET HSTACT ;HOST ACTIVE FLAG MOV AL,ÆBXÅ MOV BYTE PTR ÆBXÅ,1 ;ALWAYS BECOMES 1 OR AL,AL ;WAS IT ALREADY? JZ FILHST ;FILL HOST IF NOT ; ; ;HOST BUFFER ACTIVE, SAME AS SEEK BUFFER? ; MOV AL,SEKDSK CMP AL,HSTDSK ;SAME DISK? JNE NOMATCH ; ; ;SAME DISK, SAME TRACK? ; MOV BX,HSTTRK CMP BX,SEKTRK ;SEKTRK = HSTTRK? JNE NOMATCH ; EJECT ; ;SAME DISK, SAME TRACK, SAME BUFFER? ; MOV AL,SEKHST CMP AL,HSTSEC ;SEKHST = HSTSEC? JE MATCH ;SKIP IF MATCH ; ; ;PROPER DISK, BUT NOT CORRECT SECTOR ; NOMATCH: TEST HSTWRT,0FFH ;HOST WRITTEN? JZ FILHST CALL WRITEHST ;CLEAR HOST BUFF OR AL,AL ;CHECK FOR WRITE ERRORS JZ FILHST RET ;BALE OUT TO BDOS IF ERROR ; ; ;MAY HAVE TO FILL THE HOST BUFFER ; FILHST: MOV AL,SEKMHD ;COPY SELECTED TYPE TO OPERATION TYPE MOV HSTMHD,AL MOV AL,SEKDSK ;COPY SELECTED DISK TO OPERATION DISK MOV HSTDSK,AL MOV BX,SEKTRK ;COPY SELECTED TRACK TO OPERATION TRACK MOV HSTTRK,BX MOV AL,SEKHST ;COPY SELECTED PHYS SECTOR TO OPERATION SECTOR MOV HSTSEC,AL TEST RSFLAG,0FFH ;NEED TO READ? JZ MATCH ;SKIP PREREAD ; CALL READHST ;YES, IF 1 MOV HSTWRT,0 ;NO PENDING WRITE OR AL,AL ;CHECK ERROR ON PREREAD? JZ MATCH RET ;BACK TO BDOS IF ERROR IN READING ; EJECT ; ;COPY DATA TO OR FROM BUFFER ; MATCH: MOV BL,SEKSEC ;MASK BUFFER NUMBER AND BL,SECMSK ;LEAST SIGNIF BITS MOV BH,0 ; SHL BX,1 SHL BX,1 SHL BX,1 SHL BX,1 SHL BX,1 SHL BX,1 SHL BX,1 ;SHIFT INTO HOST BUFFER OFFSET ; ; ;BX HAS RELATIVE HOST BUFFER ADDRESS ; MOV SI,OFFSET HSTBUF ADD SI,BX ;SI = HOST ADDRESS MOV DI,DMAADR ;GET DESTIGNATION OFFSET FOR READ MOV ES,DEFDMASG ;GET DESTIGNATION SEGMENT FOR READ MOV CX,128 ;LENGTH OF MOVE (CP/M-86 SECTOR SIZE) TEST READOP,0FFH ;WHICH WAY? JNZ RWMOVE ;SKIP IF READ ; ; ;WRITE OPERATION, MARK AND SWITCH DIRECTION ; MOV HSTWRT,1 ;HSTWRT = 1 XCHG SI,DI ;SOURCE/DESTINATION SWAP MOV AX,ES PUSH DS POP ES MOV DS,AX ;SWAP ALSO INVOLVED SEGMENTS ; EJECT ; ;CX INITIALLY 128, DX IS SOURCE, BX IS DESTINATION ; RWMOVE: CLD ;SET FORWARD DIRECTION REP MOVS AL,AL ;MOVE IT MOV AX,CS MOV DS,AX MOV ES,AX ;RESTORE SEGMENT REGISTERS ; ;DATA HAS BEEN MOVED TO/FROM HOST BUFFER ; MOV AL,WRTYPE ;WRITE TYPE CMP AL,WRDIR ;TO DIRECTORY? MOV AL,ERFLAG ;IN CASE OF ERRORS JZ CHB RET ;NO FURTHER PROCESSING ; ; ;CLEAR HOST BUFFER FOR DIRECTORY WRITE ; CHB: OR AL,AL ;ERRORS? JZ CHB1 RET ;SKIP IF SO CHB1: MOV HSTWRT,0 ;BUFFER WRITTEN CALL WRITEHST RET ; EJECT ;PERFORMS THE PHYSICAL WRITE TO THE HOST DISK. ;HSTDSK = HOST DISK NUMBER, HSTTRK = HOST TRACK NUMBER, ;HSTSEC = HOST SECT NUMBER. WRITE "HSTSIZ" BYTES ;FROM HSTBUF AND RETURN ERROR FLAG IN ERFLAG. ;RETURN: AL = ERFLAG = NON-ZERO IF ERROR ; WRITEHST: CALL MIOPB ;SET MINI FLOPPY IOPB CALL MWRIT ;GO WRITE MINI FLOPPY SECTOR OR AL,AL JNZ WRTERR ;EXIT FOR WRITE ERROR MOV ERFLAG,AL ;RESET ERROR FLAG RET ;RETURN FROM "WRITEHST", IF O.K. WRTERR: CALL EREXIT ;PRINT BIOS ERROR MESSAGE MOV AL,01H ;SET ERROR FLAG MOV ERFLAG,AL RET ; ; ;HSTDSK = HOST DISK NUMBER, HSTTRK = HOST TRACK NUMBER, ;HSTSEC = HOST SECT NUMBER. READ "HSTSIZ" BYTES ;INTO HSTBUF AND RETURN ERROR FLAG IN ERFLAG AND AL. ; READHST: CALL MIOPB ;SETUP MINI FLOPPY IOPB CALL MREAD ;GO READ MINI FLOPPY SECTOR OR AL,AL JNZ RDERR ;EXIT FOR READ ERROR MOV ERFLAG,AL RET RDERR: CALL EREXIT ;PRINT BIOS ERROR MESSAGE MOV AL,01H ;SET ERROR FLAG MOV ERFLAG,AL RET EJECT ;READ/WRITE BIOS ERROR PRINT ROUTINE ;WAITS FOR USER RESPONSE ON CONSOLE AFTER PRINTING MESSAGE ;AND THEN RETURNS TO THE CALLER ; EREXIT: MOV IOERR,AL ;SAVE ERROR STATUS MOV BX,OFFSET ERRMSF ;MINI FLOPPY ERROR MESSAGE CALL PRTMSG MOV AL,IOERR ;PRINT ERROR CODE PUSH AX MOV CL,4 SHR AL,CL CALL HEXOUT POP AX CALL HEXOUT MOV BX,OFFSET ERRMS2 ;PRINT REST OF MESSAGE CALL PRTMSG MOV AL,HSTDSK ;PRINT CP/M-86 DRIVE DESIGNATOR WITH ERROR ADD AL,'A' MOV CL,AL CALL CONOUT MOV BX,OFFSET ERRMS3 ;PRINT MESSAGE CLOSE CALL PRTMSG CALL CONIN ;WAIT FOR OPERATOR RESPONSE CMP AL,03 ;IF CTL-C THEN GO DO WARM BOOT JNZ ERR1 JMP WBOOT ERR1: MOV BX,OFFSET ERRMS4 CALL PRTMSG RET ;BACK TO CP/M-86 EJECT ; ;SUBROUTINE TO SEND A HEX CHAR TO THE CONSOLE ; HEXOUT: AND AL,0FH ;LOW NIBBLE ONLY CMP AL,0AH ;GREATER THAN 9? JB HEX1 ADD AL,07H ;ADD OFFSET FOR A-F HEX1: ADD AL,030H ;ADD IN ASCII OFFSET MOV CL,AL ;PRINT RESULT CALL CONOUT RET ; ;MINI FLOPPY I/O PARAMETER BLOCK SET UP ROUTINE ; MIOPB: CALL GETDRNO ;GET PHYSICAL DRIVE NUMBER FROM CALL MUNIT ;..FROM DRIVE SELECT TABLE MOV CX,HSTTRK ;GET TRACK NUMBER AND CL,01H ;FIND OUT WHAT THE SIDE NUMBER IS CALL MSURF ;SET MINI HEAD NUMBER MOV CX,HSTTRK ;GET TRACK NUMBER SHR CX,1 ;DIVIDE TRACK BY 2 CALL MCYL MOV CL,00H ;SET SIZE CODE TO 256 BYTES CALL MSIZE MOV CL,02H ;SET SECTOR COUNT TO 2 CALL MCNT MOV BL,HSTSEC ;CONVERT SECTOR NUMBER TO PROPER SKEW DEC BL ;NOW ZERO BASED FOR INDEXING XOR BH,BH ;DOUBLE BYTE INDEX WORD MOV CL,MFSTRANÆBXÅ CALL MREC ;SET ACTUAL SECTOR TO START READ UPON MOV CX,OFFSET HSTBUF ;SET FLOPPY BUFFER ADDRESS CALL MBADDR MOV CX,1040H ;GLOBAL SEGMENT TO HOST BUFFER CALL MSEG RET EJECT ;****************************************************************************** ; ; ;PRINT THE MESSAGE AT BX UNTIL A ZERO ; ; PRTMSG: MOV CL,ÆBXÅ ;GET CHARACTER TO PRINT OR CL,CL ;SET FLAGS JZ PRTDONE ;RETURN, IF END OF STRING FLAG PUSH BX ;SAVE MESSAGE POINTER CALL CONOUT ;PRINT CHARACTER, CONSOLE OUTPUT POP BX ;GET POINTER BACK INC BX ;BUMP MESSAGE POINTER JMPS PRTMSG PRTDONE: RET ; ; ; ; ; ;****************************************************************************** ; ;DUMMY INTERRUPT TRAP ROUTINE ; TRAP: IRET ; EJECT ;****************************************************************************** ; ; FIXED ADDRESS I/O ROUTINES TO BE UTILIZED BY CP/M-86 ON MINI FLOPPY, ; HARD DISK, CONSOLE I/O, LINE PRINTER I/O. THESE ROUTINES ARE USED BY ; UTILITIES, SUCH AS DISK FORMATTING AND SYSTEM TRACK ACCESS UTILITIES. ; AN EXTRA ENTRY IN THE BIOS JUMP VECTOR TABLE (CS:253FH) HAS BEEN ; ADDED. THIS ROUTINE WILL RETURN BX = OFFSET VECTABLE ; VECTABLE: ;VECTOR TABLE BASE OFFSET ; LPTINP: JMP LPIN ;GET CHARACTER FROM LINEPRINTER LOOKQ: JMP LQ ;GET QUEUE STATUS DEQ: JMP DQ ;GET BUFFER FROM QUEUE ENQ: JMP NQ ;PUT BUFFER INTO QUEUE HUNIT: JMP HDUMMY ;SELECT HARD DISK UNIT NUMBER HPLAT: JMP HDUMMY ;SELECT HARD DISK PLATTER NUMBER HSURF: JMP HDUMMY ;SELECT HARD DISK SURFACE(HEAD) NUMBER HCYL: JMP HDUMMY ;SELECT HARD DISK CYLINDER NUMBER HREC: JMP HDUMMY ;SELECT HARD DISK RECORD NUMBER HCNT: JMP HDUMMY ;SELECT HARD DISK SECTOR COUNT HBADDR: JMP HDUMMY ;SET DATA BUFFER OFFSET HSEG: JMP HDUMMY ;SET DATA BUFFER SEGMENT HREST: JMP HDUMMY ;RESTORE SELECTED HARD DISK UNIT HREAD: JMP HDUMMY ;READ SELECTED SECTOR(S) HVERF: JMP HDUMMY ;VERIFY SELECTED SECTOR(S) HWRIT: JMP HDUMMY ;WRITE SELECTED SECTOR(S); HEXEC: JMP HDUMMY ;EXECUTE SPECIAL COMMAND OF DTC HRESET: JMP HDUMMY ;RESTART HARD DISK CONTROLLER MUNIT: JMP MSETUNIT ;SELECT MINI FLOPPY UNIT NUMBER MSURF: JMP MSETSUR ;SELECT MINI FLOPPY SURFACE(HEAD) NUMBER MCYL: JMP MSETCYL ;SELECT MINI FLOPPY CYLINDER (TRACK) NUMBER MREC: JMP MSETREC ;SELECT MINI FLOPPY RECORD NUMBER MCNT: JMP MSETCNT ;SELECT MINI FLOPPY PHYSICAL SECTOR COUNT MSIZE: JMP MSETSIZE ;SET MINI FLOPPY SECTOR SIZE (00=256 BYTES) MBADDR: JMP MSETBUF ;SET FLOPPY DISK DATA BUFFER ADDRESS MSEG: JMP MSETSEG ;SET FLOPPY DISK DATA BUFFER SEGMENT MREST: JMP FRESTR ;RESTORE SELECTED MINI FLOPPY UNIT MVERF: JMP MVERSEC ;VERIFY (READ) SELECTED SECTOR MWRIT: JMP MPUTSEC ;WRITE SELECTED SECTOR MREAD: JMP MGETSEC ;READ SELECTED SECTOR MWTRK: JMP MWRTTRK ;WRITE SELECTED FLOPPY TRACK ; HDUMMY: MOV AL,01 ;RETURN ERROR FOR CALLS TO RET ;HARD DISK ROUTINES. ;(NOT AVAILABLE) ; ;****************************************************************************** ; LINEPRINTER INPUT ROUTINE ; GETS CHAR TO (AL) REGISTER ;****************************************************************************** ; LPIN: PUSH ES MOV AX,2000H ;Z80 RAM BASE ADDRESS MOV ES,AX TEST PLIB,0FFFFH ;TEST IF BUFFER PENDING JNZ LPIN3 ;GO PICK NEXT CHARACTER THERE ; ;NO BUFFER PENDING, TRY TO GET ONE. ; LPIN1: MOV BX,IFTOFF+LPCHA+RXF ;QUEUE OFFSET CALL DEQ ;GET BUFFER JNC LPIN1 ;WAIT IF NO BUFFER IN QUEUE XCHG BX,DX ;GET BUFFER ADDRESS INTO BX MOV DX,ES:ÆBXÅ+DPTR ;GET 1. DATA ADDR. FROM QHEAD XCHG BX,DX CMP ES:BYTE PTR ÆBXÅ,ENTDLDU;MUST BE ENTIRE DATA LDU JE LPIN2 ;GO GET DATA IF LDU TYPE OK MOV BX,IFTOFF+LPCHA+RXE ;ELSE CALL ENQ ;RELEASE BUFFER AND JMPS LPIN1 ;...GO TRY AGAIN ; ;INSTALL NEWLY RECEIVED BUFFER AS PENDING. ; LPIN2: MOV PLIB,DX ;SAVE BUFFER ADDRESS INC BX INC BX ;POINT TO DATABYTE MOV LIBP,BX ;SAVE POINTER TO NEXT CHARACTER MOV BX,DX DEC ES:WORD PTR BYTECÆBXÅ ;DECREMENT BYTECOUNT BY TWO DEC ES:WORD PTR BYTECÆBXÅ EJECT ; ; ;GET CHARACTER FROM PENDING BUFFER. ; LPIN3: MOV BX,LIBP ;GET DATAPOINTER MOV AL,ES:ÆBXÅ ;GET DATA FROM BUFFER INC BX ;UPDATE POINTER MOV LIBP,BX ;SAVE NEW POINTER MOV BX,PLIB ;GET BUFFER ADDRESS DEC ES:WORD PTR BYTECÆBXÅ ;DECREMENT BYTECOUNT IN BUFFER JNZ LBNMTY ;EXIT IF NOT EMPTY ; ; ;NO MORE JUICE IN THAT ONE, RELEASE IT. ; MOV DX,PLIB ;GET BUFFER ADDRESS MOV BX,IFTOFF+LPCHA+RXE ;EMPTY QUEUE OFFSET PUSH AX ;SAVE CHARACTER CALL ENQ ;RETURN BUFFER MOV PLIB,0 ;NO BUFFER PENDING POP AX ; ; ;THAT'S ALL FOLKS, RETURN TO CALLER ; LBNMTY: POP ES AND AL,7FH ;MASK OFF PARITYBIT RET ; EJECT ; ;****************************************************************************** ; THIS MODULE CONTAINS THE INTERFACE ROUTINES NESSESARY FOR ; INTER-CPU COMMUNICATION VIA THE CHRISTIAN ROVSING A/S CR80 - ; LTU STANDARD QUEUE INTERFACE. ;****************************************************************************** ; ; ; THE MODULE CONSISTS OF THE FOLLOWING ROUTINES: ; ; LOOKQ: RETURNS AL = NBR. OF BUFFERS IN QUEUE ; ; DEQ: POLL DESIRED QUEUE ; ; ENQ: SEND BUFFER TO DESIRED QUEUE ; ; ALL ROUTINES EXPECTS REG. ES TO CONTAIN THE BASE ADDRESS OF THE ; BOARD IN WHICH THE QUEUE EXISTS. WHEN COMMUNICATING WITH A ; SCI BOARD THIS BASE MUST BE COMPENSATED BECAUSE THE SCI RAM ; HAS DIFFERENT BASE ADDRESS SEEN FROM THE MULTIBUS THAN SEEN ; FROM THE ONBOARD CPU, WHILE THE Z80 RAM ON THE MP2-BOARD HAS ; GOT SAME BASE ADDRESS SEEN FROM BOTH SIDES (LOWER 16 BITS). ; THIS STATES THE FOLLOWING VALUES FOR ES: ; MP2: ES=2000 SCI: ES=BOARD ADR.-200H ; ; ;****************************************************************************** EJECT ;****************************************************************************** ; ; THIS ROUTINE WILL POLL THE SPECIFIED QUEUE FOR A BUFFER COUNT. ; ; ENTRY: ; ES = BOARD/RAM BASE ADDRESS ; BX = QUEUE OFFSET FROM BASE ; ; EXIT: ; AL = NBR OF BUFFERS IN QUEUE ; LQ: MOV ES:BYTE PTR ÆBXÅ+SF,01 ;SET SLAVE FLAG TEST ES:BYTE PTR ÆBXÅ+MF,01 ;TEST MASTER FLAG JZ LOOKACC ;JUMP IF ACCESS GRANDED MOV ES:BYTE PTR ÆBXÅ+SF,00 ;CLEAR SLAVE FLAG LOOKBSY: CALL QDELAY ;DON'T USE ALL OF HIS BUS TIME TEST ES:BYTE PTR ÆBXÅ+MF,01 ;SEE IF MASTER ACCESS COMPLETED JNZ LOOKBSY ;WAIT IF NOT JMPS LQ ;GO TRY TO GET GRAND AGAIN LOOKACC: MOV AL,ES:ÆBXÅ+BC ;GET BUFFERCOUNT FROM QUEUE MOV ES:BYTE PTR ÆBXÅ+SF,00 ;CLEAR SLAVE FLAG RET ; ; ; ; QDELAY: NOP NOP RET ; EJECT ;****************************************************************************** ; ; THIS ROUTINE WILL POLL THE SPECIFIED QUEUE FOR A BUFFER. ; ; ENTRY: ; ES = BOARD/RAM BASE ADDRESS ; BX = QUEUE OFFSET FROM BASE ; ; EXIT: ; IF CARRY=1, DX=POINTER TO BUFFER ; IF CARRY=0, DX UNDEFINED ; DQ: MOV ES:BYTE PTR ÆBXÅ+SF,01 ;SET SLAVE FLAG TEST ES:BYTE PTR ÆBXÅ+MF,01 ;TEST MASTER FLAG JZ DEQACC ;JUMP IF ACCESS GRANDED MOV ES:BYTE PTR ÆBXÅ+SF,00 ;CLEAR SLAVE FLAG DEQBSY: CALL QDELAY ;DON'T USE ALL OF HIS BUS TIME TEST ES:BYTE PTR ÆBXÅ+MF,01 ;SEE IF MASTER ACCESS COMPLETED JNZ DEQBSY ;WAIT IF NOT JMPS DQ ;GO TRY TO GET GRAND AGAIN DEQACC: TEST ES:BYTE PTR ÆBXÅ+BC,0FFH;TEST IF QUEUE IS EMPTY (+CY:=0) JZ DEQMTY ;EXIT IF NO BUFFERS IN QUEUE DEC ES:BYTE PTR ÆBXÅ+BC ;DECREMENT BUFFERCOUNT MOV DX,ES:ÆBXÅ+FB ;GET BUFFER ADDRESS FROM QUEUE XCHG BX,DX MOV AX,ES:ÆBXÅ ;GET POINTER TO NEXT BUFFER IN QUEUE XCHG BX,DX MOV ES:ÆBXÅ+FB,AX ;INSERT AS FIRST BUFFER IN QUEUE STC ;FLAG BUFFER RECEIVED DEQMTY: MOV ES:BYTE PTR ÆBXÅ+SF,00 ;CLEAR SLAVE FLAG RET ; EJECT ;****************************************************************************** ; ; THIS ROUTINE WILL APPEND A BUFFER TO THE SPECIFIED QUEUE. ; ; ENTRY: ; BX = POINTER TO QUEUE ; DX = POINTER TO BUFFER ; ES = BOARD/RAM BASE ADDRESS ; ; EXIT: ; ES UNCHANGED, NO PARAMETERS ; NQ: MOV ES:BYTE PTR ÆBXÅ+MF,01 ;SET MASTER FLAG ENQBSY: TEST ES:BYTE PTR ÆBXÅ+SF,01 ;SEE IF SLAVE IS IN THERE JZ ENQACC ;PROCEED IF NOT CALL QDELAY ;DON'T USE ALL OF HIS BUS TIME JMPS ENQBSY ;WAIT UNTIL HE COMES OUT ENQACC: MOV AX,ES:ÆBXÅ+LB ;GET OLD LAST BUFFER MOV ES:ÆBXÅ+LB,DX ;SAVE NEW LAST BUFFER TEST ES:BYTE PTR ÆBXÅ+BC,0FFH;TEST BUFFERCOUNT IN QUEUE JZ ENQMTY ;JUMP IF QUEUE WAS EMPTY ; XCHG BX,AX MOV ES:ÆBXÅ,DX ;UPDATE ITS CHAIN ELEMENT XCHG BX,AX JMPS ENQXIT ENQMTY: MOV ES:ÆBXÅ+FB,DX ;UPDATE ALSO FIRST BUFFER POINTER ENQXIT: INC ES:BYTE PTR ÆBXÅ+BC ;INCREMENT BUFFER COUNT IN QUEUE MOV ES:BYTE PTR ÆBXÅ+MF,00 ;CLEAR MASTER FLAG RET ; EJECT ;****************************************************************************** ; ; SHORT DELAY ROUTINE FOR TIME DELAYS OF (AL) X 1 MSEC ; ; SDLY: MOV CX,250 ;ONE MILLISECOND TIME FACTOR SDLOP: LOOP SDLOP DEC AL JNZ SDLY RET ; EJECT ;****************************************************************************** ; MINI FLOPPY DISK CONTROLLER I/O ROUTINES ;****************************************************************************** ; ; ; ;SELECT MINI FLOPPY UNIT NUMBER ;(CL)=FLOPPY PHYSICAL UNIT NUMBER ; MSETUNIT: MOV FUNIT,CL RET ; ; ; ;SELECT MINI FLOPPY SURFACE(HEAD) NUMBER ;(CL)=FLOPPY SIDE NUMBER ; MSETSUR: MOV FSIDE,CL RET ; ; ; ;SELECT MINI FLOPPY CYLINDER (TRACK) NUMBER ;(CL)=FLOPPY TRACK NUMBER ; MSETCYL: MOV FTRK,CL RET ; ; ; ;SELECT MINI FLOPPY RECORD NUMBER ;(CL)=FLOPPY SECTOR NUMBER ; MSETREC: MOV FSEC,CL RET ; EJECT ; ; ; ;SELECT MINI FLOPPY PHYSICAL SECTOR COUNT ;(CL)=MINI FLOPPY SECTOR COUNT ; MSETCNT: MOV FCNT,CL RET ; ; ; ;SET FLOPPY SECTOR SIZE SELECT ;(CL)=SECTOR SIZE IN BYTES UP TO (00)=256 BYTES ; MSETSIZE: MOV FSIZE,CL RET ; ; ; ;SET FLOPPY DISK DATA BUFFER OFFSET ;(CX)=FLOPPY BUFFER OFFSET ; MSETBUF: MOV XFRPNT,CX ;STORE FLOPPY DATA BUFFER OFFSET RET ; ; ; ;SET FLOPPY DISK DATA BUFFER SEGMENT ;(CX)=FLOPPY BUFFER SEGMENT ; MSETSEG: MOV XFRSEG,CX ;STORE FLOPPY DATA BUFFER SEGMENT RET ; EJECT ; ; ; FRESTR: MOV AL,RESTORE CALL FDCMD ;GO EXECUTE RESTORE RET ; ; ; MVERSEC: MOV AL,0FFH RET ; ; ; MPUTSEC: MOV AL,WRITEFD CALL FDCMD ;GO EXECUTE FLOPPY WRITE RET ; ; ; MGETSEC: MOV AL,READFD CALL FDCMD ;GO EXECUTE FLOPPY READ RET ; ; ; MWRTTRK: MOV AL,WRTRACK CALL FDCMD ;GO FORMAT TRACK RET ; EJECT ;****************************************************************************** ; ; THIS ROUTINE WILL EXECUTE THE FLOPPY COMMAND IN (AL), USING THE ; THE PARAMETERS STORED IN THE FLOPPY PARAMETER I/O BLOCK. ; ; ENTRY: AL = FLOPPY COMMAND ; EXIT: IF COMMAND SUCCESSFULL, AL = 0 ; IF COMMAND FAILED, AL = ERROR STATUS ; FDCMD: MOV FINST,AL ;SAVE COMMAND TYPE PUSH ES MOV AX,2000H ;Z80 RAM BASE ADDRESS MOV ES,AX FDCMD1: MOV BX,IFTOFF+FDCHA+TXE ;QUEUE OFFSET CALL DEQ ;GET EMPTY BUFFER JNC FDCMD1 ;WAIT IF NO BUFFER IN QUEUE ; MOV BX,12 ADD BX,DX ;COMPUTE 1. DATA POINTER MOV DI,BX MOV SI,OFFSET FDIOPB ;GET PARAMETER BLOCK ADDRESS MOV CX,ENDFDIO-FDIOPB ;GET NBR.OF BYTES TO MOVE REP MOVS AL,AL ;MOVE PARAMETERS INTO BUFFER XCHG BX,DX MOV ES:ÆBXÅ+DPTR,DX ;SAVE POINTER IN QHEAD MOV ES:WORD PTR ÆBXÅ+BYTEC,ENDFDIO-FDIOPB ;SET BYTECOUNT XCHG BX,DX MOV BX,IFTOFF+FDCHA+TXF ;QUEUE OFFSET CALL ENQ ;SEND BUFFER TO Z80 ; EJECT ; ;COMMAND SEND, NOW WAIT FOR RESPONCE ; FDWAIT: MOV BX,IFTOFF+FDCHA+RXF ;QUEUE OFFSET CALL DEQ ;GET BUFFER JNC FDWAIT ;WAIT IF NO BUFFER IN QUEUE XCHG BX,DX ;GET BUFFER ADDRESS INTO BX MOV DX,ES:ÆBXÅ+DPTR ;GET 1. DATA ADDR. FROM QHEAD XCHG BX,DX CMP ES:BYTE PTR ÆBXÅ,ENTCLDU;MUST BE ENTIRE COMMAND LDU JE FDW1 ;GO GET STATUS TYPE IF LDU TYPE OK FDERR: MOV AL,CPUSYNC ;FLAG ERROR JMPS FDEXIT FDW1: INC BX INC BX ;POINT TO STATUS TYPE MOV AL,ES:ÆBXÅ ;GET STATUS TYPE FROM BUFFER CMP AL,FINST ;MUST MATCH COMMAND TYPE JNE FDERR ;ERROR EXIT IF NOT ; INC BX ;POINT TO STATUS BYTE MOV AL,ES:ÆBXÅ ;GET DATA FROM BUFFER FDEXIT: MOV BX,IFTOFF+FDCHA+RXE ;EMPTY QUEUE OFFSET PUSH AX ;SAVE CHARACTER CALL ENQ ;RETURN BUFFER POP AX POP ES ;RESTORE SEGMENT RET ; EJECT ;****************************************************************************** ; REAL TIME CLOCK INTERRUPT SERVICE ROUTINE ;****************************************************************************** ; RTCINT: PUSH DS ;SAVE DATA SEGMENT PUSH ES PUSH AX PUSH BX PUSH DX PUSH CS POP DS TEST CONSEMAP,0FFH ;IF SEMAPHORE SET JNZ TESTLPT ;...GO LOOK AT PRINTER TEST CONPTR,0FFFFH ;TEST IF BUFFER PENDING JZ TESTLPT ;DON'T FORGET THE PRINTER MOV CONPTR,0 ;REMOVE PENDING BUFFER MOV AX,2000H MOV ES,AX ;GET Z80-RAM BASE ADDRESS MOV BX,IFTOFF+CONCHA+TXF ;GET QUEUE OFFSET MOV DX,CONBUF ;GET BUFFER ADDRESS CALL ENQ ;FORWARD BUFFER TESTLPT: TEST LPTSEMAP,0FFH ;IF SEMAPHORE SET JNZ RTCEXIT ;...EXIT INTERRUPT TEST LPTPTR,0FFFFH ;TEST IF BUFFER PENDING JZ RTCEXIT ;...EXIT IF NOT MOV LPTPTR,0 ;REMOVE PENDING BUFFER MOV AX,2000H MOV ES,AX ;GET Z80-RAM BASE ADDRESS MOV BX,IFTOFF+LPCHA+TXF ;GET QUEUE OFFSET MOV DX,LPTBUF ;GET BUFFER ADDRESS CALL ENQ ;FORWARD BUFFER RTCEXIT: POP DX POP BX POP AX POP ES POP DS ;RESTORE DATA SEGMENT IRET ; EJECT ; DATAOFF EQU OFFSET $ DSEG ORG DATAOFF ; INCLUDE FDDISK.LIB ; ;VALID DISK DRIVE SELECT TABLES ; ; TABLE ENTRIES CONTAIN VALUES FOR VARIOUS DISK CONFIGURATIONS ; AND ALLOW QUICK INDEXING TO THE DRIVE SELECT CODE PARAMETERS. ; EACH ENTRY CONSISTS OF: ; FIRST BYTE: LEGAL/ILLEGAL 0=ILLEGAL, 0FFH=LEGAL ; SECOND BYTE: PHYSICAL UNIT SELECT CODE 00 TO 03 ; THIRD BYTE: MINI/HARD FLAG 0=HARD UNIT, 0FFH=MINI FLOPPY ; FOURTH BYTE: DISK PARAMETER TABLE INDEX (FROM DISKDEF) ; DSTAB: DB 0FFH,000H,0FFH,000H ;FLOPPY DISK DRIVE 0 DB 0FFH,001H,0FFH,001H ;FLOPPY DISK DRIVE 1 DB 000H,000H,000H,000H DB 000H,000H,000H,000H DB 000H,000H,000H,000H DB 000H,000H,000H,000H ; EJECT ; ;HDBIOS SIGNON MESSAGE ; SMSG DB CR,LF,ESC,'Æ7m' DB 'CHRISTIAN ROVSING A/S CR8 - CP/M-86 Vers. 1.1 ' DB YEAR/10+'0',YEAR MOD 10+'0' DB MONTH/10+'0',MONTH MOD 10+'0' DB DAY/10+'0',DAY MOD 10+'0' DB CR,LF,ESC,'Æm' DB 'DUAL 5 1/4 INCH MINI FLOPPY BIOS Version ' DB VERSION/10+'0','.',VERSION MOD 10+'0',' ' DB YEAR/10+'0',YEAR MOD 10+'0' DB MONTH/10+'0',MONTH MOD 10+'0' DB DAY/10+'0',DAY MOD 10+'0' DB 0 ; EJECT ; ;ERROR ROUTINE MESSAGES ; ; ERRMSF DB CR,LF,CR,LF,' *** MINI FLOPPY DISK ERROR (#',0 ERRMS2 DB ') - DRIVE ',0 ERRMS3 DB ': *** ',0 ERRMS4 DB CR,LF,0 ; EJECT ;**************************************************************************** ; ; STORAGE AREA FOR VARIABLES BEGINS HERE... ; ; THE NEXT SEVERAL BYTES, BETWEEN STARTZ AND ; ENDZ, ARE SET TO ZERO AT COLD BOOT TIME ; STARTZ EQU OFFSET $ ;START OF ZEROED AREA ; ; ;NOTE: THIS LOCATION STORES THE DISK CONTROLLER ;I/O ERROR CODE FOR DEBUGGING PURPOSES. ; IOERR RB 1 ;DISK I/O ERROR TYPE ; ; ; ; ;HOST DISK BLOCKING/DE-BLOCKING DATA AREA ; ; ;(FOLLOWING TWO VARIABLES MUST BE KEPT TOGETHER HERE TO PERMIT WORD ; REFERENCE TO THEM DURING THE DISK HOME ROUTINE) ; TEMPMHD RB 1 ;TEMP STORAGE FOR CURRENT TYPE OF DRIVE; TEMPDSK RB 1 ;TEMPORARY STORAGE FOR LOGGED DISK ; MINIHARD RB 1 ;FLAG FOR MINI OR HARD DISK SELECTED ; SEKMHD RB 1 ;FLAG FOR SELECTED DRIVE TYPE FLAG SEKDSK RB 1 ;SEEK DISK NUMBER SEKTRK RW 1 ;SEEK TRACK NUMBER SEKSEC RB 1 ;SEEK SECTOR NUMBER ; EJECT ;(FOLLOWING TWO VARIABLES MUST BE KEPT TOGETHER HERE TO PERMIT WORD ; REFERENCE TO THEM DURING THE DISK HOME ROUTINE) ; HSTMHD RB 1 ;HOST DISK TYPE FLAG HSTDSK RB 1 ;HOST DISK NUMBER HSTTRK RW 1 ;HOST TRACK NUMBER HSTSEC RB 1 ;HOST SECTOR NUMBER ; SEKHST RB 1 ;SEEK SHR SECSHF HSTACT RB 1 ;HOST ACTIVE FLAG HSTWRT RB 1 ;HOST WRITTEN FLAG ; UNACNT RB 1 ;UNALLOCATED RECORD COUNT UNADSK RB 1 ;LAST UNALLOCATED DISK UNATRK RW 1 ;LAST UNALLOCATED TRACK UNASEC RB 1 ;LAST UNALLOCATED SECTOR ; ERFLAG RB 1 ;ERROR REPORTING RSFLAG RB 1 ;READ SECTOR FLAG READOP RB 1 ;1 IF READ OPERATION WRTYPE RB 1 ;WRITE OPERATION TYPE DMAADR RW 1 ;DISK DMA TRANSFER ADDRESS ; DEFDMASG RW 1 ;STORAGE FOR DMA SEGMENT VALUE IOBYTE RB 1 ;STORAGE FOR IOBYTE ; CONPTR RW 1 ;CONSOLE BUFFER FILLING POINTER CONBUF RW 1 ;CONSOLE BUFFER ADDRESS STORAGE CONSEMAP RB 1 ;CONSOLE BUFFER ACCESS SEMAPHORE ; LPTPTR RW 1 ;PRINTER BUFFER FILLING POINTER LPTBUF RW 1 ;PRINTER BUFFER ADDRESS STORAGE LPTSEMAP RB 1 ;PRINTER BUFFER ACCESS SEMAPHORE ; ENDZ EQU OFFSET $ ;END OF ZEROED AREA ; CIBP DW 0 ;PENDING BUFFER DATA POINTER PCIB DW 0 ;PENDING BUFFER VALID, BUFFER ADDRESS ; EJECT ;****************************************************************************** ; MEMORY REGION TABLE (MAX 5 MEMORY BLOCKS) ;****************************************************************************** ; MTR DB 01 ;NBR OF MEMMORY REGIONS DW STARTTPA ;START OF FIXED SEGMENT DW 1000H-STARTTPA ;LENGTH OF FIXED SEGMENT RW 4*2 ;MAX 4 EXTRA SEGMENTS MAY BE SPECIFIED ; ; ; ;HOST DATA BUFFER MEMORY AREA MUST BE ACCESSABLE VIA ;DMA AND BY THE HARD DISK CONTROLLER BOARD. ; ; HSTBUF RB HSTSIZ ;HOST BUFFER ; ; ; ;SCRATCH RAM AREA FOR BDOS USE ; ; ENDEF ;LET DISKDEF FIXUP BDOS BUFFERS ; ; ; ; ; ; ;MINI FLOPPY PHYSICAL SECTOR TRANSLATE TABLE ; MFSTRAN DB 1,5,9,13,3,7,11,15 ; LIBP DW 0 ;PENDING BUFFER DATA POINTER PLIB DW 0 ;PENDING BUFFER VALID, BUFFER ADDRESS ; EJECT ;****************************************************************************** ; MINI FLOPPY DRIVE ACCESS PARAMETER BLOCK ;****************************************************************************** ; FDIOPB EQU OFFSET $ ; DB ENTCLDU ;ENTIRE COMMAND LDU DB COMOPC ;COMMAND BUFFER FLAG FINST DB 0 ;DISK ACCESS INSTRUCTION BYTE FUNIT DB 0 ;SELECTED UNIT NUMBER FSIDE DB 0 ;SELECTED SIDE NUMBER FTRK DB 0 ;SELECTED TRACK NUMBER FSEC DB 1 ;SELECTED SECTOR NUMBER FCNT DB 2 ;SELECTED 256 BYTE SECTOR COUNT XFRPNT DW OFFSET HSTBUF ;READ/WRITE BUFFER OFFSET XFRSEG DW 1040H ;READ/WRITE BUFFER SEGMENT BASE ; ENDFDIO EQU OFFSET $ ; FSIZE DB 00 ;SECTOR SIZE DEFAULT TO 256 BYTES ; ; ; RW 32 ;INITIALIZATION STACK STKBASE DB 0 ; ***** END OF OS ***** ; ; ; ;DEFINE TPA SEGMENT START ADDRESS ; STARTTPA EQU ((OFFSET STKBASE)+15+400H)/16 EJECT ; ; DEFINE INTERRUPT VECTORS ; DSEG 0 ORG 0 ; INT0OFF RW 1 INT0SEG RW 1 STEPOFF RW 1 STEPSEG RW 1 NMIOFF RW 1 NMISEG RW 1 TYP3OFF RW 1 TYP3SEG RW 1 OVRFOFF RW 1 OWRFSEG RW 1 ; ORG RTC RTCOFF RW 1 ; ORG 378H BIOSOFF RW 1 ; ORG 380H BDOSOFF RW 1 BDOSSEG RW 1 ; END «eof»