; MICRO-DECISION ; CP/M 2.2 ; BIOS REV 3.1 ; COPYRIGHT 1982,1983,1984 ; MORROW DESIGNS, INC. ; SAN LEANDRO, CA. ; ; 5/2/84 ; ;*********************************************************************** ; DOUBLE SIDED ;*********************************************************************** ; ; 12/24/83 LST: default changed to parallel port. ; Step rate set to 6 ms. ; CONST set to return false when IMS is on. ; 4/6/84 Move SELDSK to ROM. ; 4/10/84 Improve CONIN and CONST handling of IMS. ; 4/23/84 Move CONOUT translation code to rom. ; 5/2/84 Add over-run and re-syncronization handling ; for function keys to conin. ; .Z80 ; MEMSIZE EQU 9 ; REV EQU 31H ; CPM EQU (MEMSIZE-9)*1024+100H BDOS EQU CPM+806H BIOS EQU CPM+1600H ; .PHASE BIOS ; ; ROM EQU 0 ; HMRM EQU ROM+6 WRHSRÍ EQÕ ROM+0CH RDHSRM EQU ROM+9 DISRM EQU ROM+0FH BTERM EQU ROM+18H ROMDATX EQU ROM+1BH MSGRM EQU ROM+3 CENTDRV EQU ROM+1DH ;ROM ENTRY POINT FOR CENTRONICS DRIVER RDLSEC EQU ROM+20H WRTLSEC EQU ROM+23H SELROM EQU ROM+26H ROMOUT EQU ROM+29H ; ; CONTROL BITS WITHIN DFLAG BYTE HSTACT EQU 0 ;Host buffer active flag. ;Buffer contains nothing if = 0. ;Buffer contains a sector if = 1. ; HSTWRT EQU 1 ;Host buffer dirty flag. ;Buffer has not been written to if = 0. ;Buffer has been written to if = 1. ; RSFLAG EQU 2 ;Read sector flag. ;Sector need not be read if = 0. ;Sector must be read if = 1. ; READOP EQU 3 ;Read if = 1. Write if = 0. ; HNDSHK EQU 4 ;Handshake with DSR and CTS if 1, just CTS if 0. ; LSTMAP EQU 5 ;1=>Cent. is LST:, SER2 is PUN: ;0=>SER2 is LST:, Cent. is PUN: ; IMS EQU 6 ;In Memory Submit flag. ;I.M.S. in-active if = 0. ;I.M.S. active if = 1. ; IMSBUF EQU 7 ;In Memory Submit buffer empty flag. ;I.M.S. buffer is empty if = 0. ;I.M.S. buffer is not empty if = 1. ; ; ; CONTROL BITS WITHIN SFLAG BYTE ; PCSTAT EQU 0 ;Physical console status flag. ;No character has been received if = 0. ;Character has been received if = 1. ; IMSTAT EQU 1 ;I.M.S. CONST flag. ;CONST returns physical status if = 0. ;CONST returns OR of physical and I.M.S. status if = 1. ; FUNSEQ EQU 6 ;Function key sequence flag. ;Last character was NOT part of a function key sequence if = 0. ;Last character was a function key lead-in or code if = 1. ; FUNCODE EQU 7 ;Function key code flag. ;Last character was NOT a function key code if = 0. ;Last character was a function key code if = 1. ; ROMCTL EQU 0F6H ; DPHOFF EQU 10 ; BDFM EQU 5 NRDY EQU 6 SIZMSK EQU 18H DSM EQU 2 ; ; WRALL EQU 0 WRDIR EQU 1 WRUAL EQU 2 ; ; S1STAT EQU 0FDH S1DATA EQU 0FCH ; S2DATA EQU 0FEH S2STAT EQU 0FFH ; CSTAT EQU 0F5H CTCSEL EQU 0F3H ; CHANNEL SELECT PORT FOR CTC CH1DIV EQU 0F1H ; PORT FOR SETTING BAUD RATE OF 1st SERIAL PORT CH2DIV EQU 0F2H ; PORT FOR SETTING BAUD RATE OF 2nd SERIAL PORT DFLT1 EQU 06h ; default baud rate for 1st serial port DFLT2 EQU 03h ; default baud rate for 2nd serial port ; CR EQU 0DH LF EQU 0AH ASC0 EQU 30H CTLS EQU 13H CTLQ EQU 11H CTLC EQU 3 CTLX EQU 18H FAST EQU 9FH SLOW EQU 9DH ; START: JP BOOT WBOT: JP WBOOT JP CONST JP CONIN JP CONOUT JP LST JP PUN JP PTR JP HOME JP SELDSK JP SETTRK JP SETSEC JP SETDMA JP READ JP WRITE JP LISTST JP SECTRAN ; JP CVMSG ;CHANGE VIRTUAL DRIVE MESG. ; JP RDBLK ;DIRECT DISK READ JP WRBLK ;DIRECT DISK WR JP DISCIO ;DIRECT DISK I/O ; DB REV DW RAMDATX DW RAMDATY DW MTAB DW XLTAB ; ETBLPTR:DW ESCTBL CTBLPTR:DW CTRLTBL EVCTPTR:DW ESCVECT CVCTPTR:DW CTVECT DW DCASTRT ; JP INITCTC ;CTC init routine JP INJECT_IMS ; ; WBOOT: LD SP,STACK LD DE,DSKBUF PUSH DE POP IX LD BC,DATXLN OUT (ROMCTL),A ;TURN ON ROM LD HL,(ROMDATX) LDIR ; LD IY,RAMDATY ; LD (IX+HSTSEC),2 LD (IX+SECCNT),8 LD (IX+SECSIZ+1),81H LD (IX+HSTBUF+1),HIGH CPM ; CALL RDHST OR A JR NZ,BTERR ; LD (IX+HSTSEC),1 LD (IX+HSTTRK),1 LD (IX+SECCNT),3 LD (IX+HSTBUF+1),HIGH CPM + 16 ; CALL RDHST OR A JR NZ,BTERR ; LD HL,CPM+3 ; GOCPM: LD BC,80H CALL SETDMA ; LD A,0C3H LD (0),A LD (5),A ; XOR A LD (3),A ; PUSH HL LD HL,WBOT LD (1),HL ; LD HL,BDOS LD (6),HL ; LD HL,(VNUMB) LD (8),HL ; LD A,(IY+DFLAG) AND 0B0H ;MASK IMSBUF FLAG, DON'T CHANGE BITS 4 OR 5 SET IMS,A ;ACTIVATE IMS LD (IY+DFLAG),A ; RES IMSTAT,(IY+SFLAGIY) ; LD (IY+UNACNT),0 LD (IY+SCNTIY),0FFH ; LD A,(4) LD C,A ; POP HL JP (HL) ; BTERR: OUT (ROMCTL),A JP BTERM ; ; INITCTC: ; SET BAUD RATES FOR BOTH SERIAL PORTS LD A,(SER1BAUD) ; GET BAUD RATE FOR 1st SERIAL PORT CALL GETVAL ; POINT TO DIVISOR LD C,CH1DIV ; SET UP TO LOAD DIVISOR FOR CHANNEL 1 LD A,07EH ; SELECT CTC CHANNEL 1 CALL SETBAUD ; SET BAUD RATE FOR 1st SERIAL PORT LD A,(SER2BAUD) ; GET BAUD RATE FOR 2nd SERIAL PORT CALL GETVAL ; POINT TO DIVISOR LD C,CH2DIV ; SET UP TO LOAD DIVISOR FOR CHANNEL 2 LD A,0BEH ; SELECT CTC CHANNEL 2 CALL SETBAUD ; SET IT RET ; GETVAL: ; SET HL TO POINT TO DIVISOR FOR SELECTED ; BAUD RATE. A IS OFFSET FROM BASE ON ENTRY LD HL,BAUDTBL ; POINT TO BASE OF TABLE LD C,A LD B,0 ADD HL,BC ADD HL,BC ; HL NOW POINTS TO DIVISOR FOR SELECTED BAUD RATE RET ; SETBAUD: ; OUTPUT THE VALUES POINTED TO BY HL TO THE OUT (CTCSEL),A ; PORT SELECTED IN REG. C. LD A,(HL) ; GET LOW BYTE OF DIVISOR OUT (C),A ; OUTPUT IT INC HL ; POINT TO HIGH BYTE LD A,(HL) ; GET THE HIGH BYTE OF DIVISOR OUT (C),A ; OUTPUT IT RET ; baudtbl: ; DIVISOR TABLE FOR BAUD RATES ; DW 1136 ;110 DW 417 ;300 DW 208 ;600 DW 104 ;1200 DW 52 ;2400 DW 26 ;4800 DW 13 ;9600 ; CONST: CALL CPHY ;GET PHYSICAL CONST PUSH AF ;SAVE PHYSICAL CONST LD A,(RAMDATY+DFLAG) AND 0C0H CP 0C0H JR NZ,NO_IMS ;JUMP IF IMS NOT ACTIVE POP AF BIT IMSTAT,(HL) ;CHECK STATUS BIT RET Z ;RETURN PHYSICAL STATUS IF 0 LD A,0FFH ;CHAR FLAG RET ;RETURN CHAR IF 1 NO_IMS: POP AF RET ; CPHY: LD HL,SFLAG ;POINTER TO SFLAG RES PCSTAT,(HL) ;CLEAR CONST FLAG ; IN A,(S1STAT) ;CONSOLE STATUS ROUTINE AND 2 ;SEE IF RDY RET Z ;RETURN WITH 0 IF NOT RDY ; SET PCSTAT,(HL) ;SET CONST FLAG LD A,0FFH ;RETURN WITH FF IF RDY RET ; pconin: call getchar ;wait for char jr z,pconin ret ; getchar:ld hl,sflag ;pointer to sflag ld e,(hl) res pcstat,(hl) ;reset physical CONIN flag in a,(s1stat) bit 1,a ;see if rdy ret z ;ret if not rdy in a,(s1data) ;get character res parity,a ;clear parity bit push af ;save char. & flags push hl ld hl,scount inc (hl) jr nz,cnt_ok dec (hl) cnt_ok: ld a,(hl) ld d,a pop hl bit funcode,(hl) res funcode,(hl) jr nz,not_fnc bit funseq,(hl) jr z,not_fnc set funcode,(hl) res funseq,(hl) cp 0dh jr nc,not_1c not_fnc:pop af push af cp 1ch jr nz,not_1c set funseq,(hl) res funcode,(hl) not_1c: in a,(s1stat) bit 4,a jr z,noe ;jump if no over-run ; xor a ld (scount),a ld a,37h ;clear over-run error bit out (s1stat),a ld a,0c0h and e jr z,noef ;jump if not function key ; pop af push af cp 1ch jr z,not_fnc ;jump if in sync ; res funseq,(hl) ;syncronize flags set funcode,(hl) ; noe: pop af ;syncronize function key sequence ; ret ; noef: ld a,0ch cp d jr nc,noe pop af ld a,0 ret conin: call getchar ;get character chk_sync: push af ;save char & status jr z,no_char ;jump if no char bit funseq,(hl) ;check if 1st char of function key jr z,no_char ;jump if not pop af resync: call pconin ;wait for next char of function key jr chk_sync no_char:ld a,(ramdaty+dflag) ;get dflag and 0c0h ;mask out IMS flags cp 0c0h ;check if IMS active jp z,submt ;jump if IMS active pop af jr z,conin bit funcode,(hl) ;check if 2nd char of function key ret z ;return if not ; pfunc: push af ;save char ld a,0fch ;function table call find inc hl pop af ;restore char call scan ;look for key set parity,a ;mark as function with parity bit=1 ret c ;ret if not found fcn2: ld a,(hl) ;check for string length = 0 or a ex de,hl ;[de]->string.length call nz,inject_ims ;inject string into ims jr conin ;get first character in sequence ;recurse if required ;---------------------------------------------------------------------- ; Ims Injection Routines ;------------------------------ ; inject_ims: ld a,(de) ;get length byte inject_ims2: ld c,a ;save ld b,0 inc de ;point at string text push de ;save string address ld a,0ffh ;free marker call find ;[de]=free length ;[hl]->free.leng(hi) push hl ;save free address ld h,d ld l,e ;[hl]=free length or a ;[cy]=0 sbc hl,bc ;free.len = free.len - string.len jr c,noims ;if not out of space, ex de,hl ;[de]=new free.len ex (sp),hl ;[hl]=free.address (save old length) ld (hl),d ;write new free.len(hi) dec hl ld (hl),e ;write new free.len(lo) inc hl inc hl ;[hl] -> free.data_area pop de ;[de] = old free.len add hl,de ;point at IMS.head (=fd) inc hl ;[hl] -> ims.len(lo) ld e,(hl) ;read ims.len inc hl ld d,(hl) ex de,hl ;[hl]=ims.len, [de]->ims.len(hi) add hl,bc ;ims.len = ims.len + string.len ex de,hl ;[hl] -> ims.len(hi) sbc hl,bc ;ims.address = ims.address - string.len ld (hl),d ;write new ims header, ims.len(hi) dec hl ld (hl),e dec hl ld (hl),0fdh ;ims head complete inc hl inc hl inc hl ;[hl] -> destination, ims buffer pop de ;[de] -> source, text ex de,hl ;set direction for ldir ldir ;copy string to ims buffer ld hl,ramdaty+dflag bit imsbuf,(hl) jr z,fcn4 ;if ims already contains characters, bit ims,(hl) jr nz,fcn4 ;but is deactivated, dec de ; then point at last char, this string, ld a,(de) set parity,a ; and mark it to turn-off ims at end of this string ld (de),a fcn4: set imsbuf,(hl) ;activate ims set ims,(hl) xor a ;exit with carry = clear ret noims: ;enter here if no ims available pop de ;drop pop de ;drop ret ;exit with carry = set ;---------------------------------------------------------------------- ; SCAN - Search for key in table ;------------------------------- ; enter with [hl] -> table to be searched ; [a] = key to search for ; form of table is: ; element_count (byte) ; element_list (string) ; :: element = length (byte) ; string (text) ; scan: ld d,0 ld b,(hl) ;element count inc b inc hl ;point at key jr scan1 scan0: cp (hl) ;key we're looking for? inc hl ;point at string.length ret z ld e,(hl) ;not key, so get length inc e ;same as inc hl add hl,de ;next element scan1: djnz scan0 ;do until out of elements scf ;abnormal exit ret drop_ims: ;empty the ims buffer ld a,0fdh ;ims call find ;get count push de ;save length ld a,0ffh ;free call find ex de,hl ;[hl]=free.len pop bc ;[bc]=ims.len add hl,bc ;[hl]=total space ex de,hl ;[hl]=free.len(hi) ld (hl),d dec hl ld (hl),e ;reset free length inc hl inc hl ;[hl] -> free.data space add hl,de ;[hl] -> end of free space ld (hl),0fdh ;ims header inc hl ld (hl),0 inc hl ld (hl),0 ;reset ims.len ld hl,ramdaty+dflag ;de-activate ims ld a,(hl) and 3fh ld (hl),a ld a,18h ret ; ; SUBMT locates the submit string block within the BIOS ram area, ; the next character is taken from the buffer and passed to CP/M. ; The free block and submit string block pointers are updated. ; If this was the last character in the buffer, then the IMSBUF ; bit in dflag is cleared. ; If the parity bit is set on the character, then the IMS bit in ; dflag is cleared, which de-activates IMS until the next warm ; boot. ; ; PARITY EQU 7 ; SUBMT: POP AF JR Z,SUBGO BIT FUNCODE,(HL) JR NZ,SUBGO CP CTLC ;COMPARE TO CTL-C JR Z,DROP_IMS BIT IMSTAT,(HL) ;CHECK SPEED FLAG JR NZ,SUBGO ;JUMP IF FAST BIT PCSTAT,E ;CHECK PHYSICAL CONST FLAG JR Z,SUBGO ;JUMP IF FALSE CP CTLS ;SEE IF CTL-S RET Z ;RETURN IF SO LD A,CTLQ ;A=CTL-Q RET ; SUBGO: LD A,0FFH ;FREE SPACE CODE CALL FIND ;FIND FREE SPACE ; INC DE ;UPDATE FREE SPACE POINTER LD (HL),D DEC HL LD (HL),E ; ADD HL,DE ;SET HL ==> IMS BUFFER INC HL INC HL ; LD E,(HL) ;UPDATE IMS BUFFER HEADER LD (HL),0FDH INC HL LD D,(HL) DEC DE LD (HL),E INC HL ; LD A,E ;SEE IF LAST CHAR. OR D LD A,(SFLAG) LD E,A LD A,(HL) ;GET CHAR. LD (HL),D ;FINISH UPDATING IMS BLOCK HEADER LD HL,RAMDATY+DFLAG JR NZ,SKP1 ;JMP IF NOT LAST CHAR. ; RES IMSBUF,(HL) ;CLEAR IMSBUF FLAG ; SKP1: BIT PARITY,A ;CHECK PARITY BIT OF CHAR. RES PARITY,A ;CLEAR PARITY BIT RET Z ;RETURN IF PARITY 0 ; CP SLOW-80H JR NZ,SKP2 RES IMSTAT,E JR SKP4 ; SKP2: CP FAST-80H JR NZ,SKP3 SET IMSTAT,E SKP4: LD A,E LD (SFLAG),A XOR A PUSH AF JP NO_CHAR ; SKP3: RES IMS,(HL) ;DE-ACTIVATE IMS RET ;RETURN ; ; FIND searches BIOS ram area for the block ; header contained in A. ; FIND: LD HL,XLTAB ;POINTER TO RAM AREA FINDLP: CP (HL) ;SEE IF HEADER CODE MATCHES INC HL ;INCREMENT POINTER ; LD E,(HL) ;GET OFFSET TO NEXT BLOCK INC HL LD D,(HL) ; RET Z ;RETURN IF BLOCK FOUND ; INC HL ;SET POINTER TO NEXT BLOCK ADD HL,DE JR FINDLP ;KEEP LOOKING ; ; ; On entry to CONOUT register C contains the character to be output. ; A test is made to see if the system is in the process of outputing ; a multiple character escape sequence, or if the character is a ; Morrow Standars Control Code. If neither test is true, than the ; character is output. ; If the character is part of a multiple character escape sequence, ; then the character is passed to the ESCAPE routine. If the ; character is a MSCC, then it is converted to the appropriate ; sequence, and output. ; conout: call mstk ;fix stack push ix ;save index regs. push iy ld ix,cout ;pointer to physical output routine ld iy,etblptr ;pointer to table of pointers out (romctl),a ;turn on rom call romout ;call rom jp cretn ;return ; COUT: IN A,(S1STAT) ;CONSOLE OUTPUT ROUTINE BIT 0,A ;SEE IF RDY JR Z,COUT ;JMP IF NOT RDY ; LD A,C ;OUTPUT CHARACTER OUT (S1DATA),A RET ; cnout: call conout out (romctl),a ret ; ;XON/XOFF PROTOCOL HANDLER FOR MICRO DECISION CBIOS ; LST: LD A,(RAMDATY+DFLAG) ; GET FLAG BYTE TO CHECK WHICH OUTPUT DRIVER BIT 5,A ; SEE IF CENTRONICS BIT SET JR NZ,CENTOUT ; IF SO, USE CENTRONICS DRIVER ; ELSE, USE SERIAL PORT DRIVER LSTDRV: CALL SSTAT ; STATUS OF LSTFLG JR Z,LSTDRV ; IF NOT READY, LOOP OVER: LD A,C ; ELSE, GET CHAR OUT (S2DATA),A ; XMIT IT RET ; ; LISTST: LD A,(RAMDATY+DFLAG) ; GET PORT MAPPING BIT 5,A ; SEE IF CENTRONICS PORT JR NZ,CENTSTAT ; IF CENTRONICS, CHECK IT'S STATUS SSTAT: CALL RDRSTAT ; GET A CHARACTER, OR NULL CP 13H ; IF XOFF R'CVD... JR NZ,NXTCHK ; IF NOT, CHECK IF XON XOR A ; SET FLAG TO NOT RDY LD (LSTFLG),A RET ; RETURN NOT RDY NXTCHK: CP 11H ; IF XON, THEN IT MIGHT BE READY JR NZ,CHKFLG ; ELSE, STATE NOT CHANGING LD A,0FFH LD (LSTFLG),A ; SET FLAG TO RDY CHKFLG: LD A,(LSTFLG) ; GET STATUS FLAG LSTRET: OR A ; SET FLAGS RET Z ; IF ZERO, THEN XOFF PENDING LD A,(RAMDATY+DFLAG) ;SEE IF HRDWR HNDSHKNG ENABLED BIT 4,A LD L,5H ; STATUS ONLY MASK JR Z,CTS ; IF 0, THEN USE ONLY CTS HANDSHAKING LD L,85H ; DSR & STATUS MASK CTS: IN A,(S2STAT) ; TEST STATUS AND L ; GET TBRE FLAG CP L ; SET FLAGS ON STATUS OF TBRE STAT: LD A,0 ; SET NOT READY STATUS JR NZ,LSTRET ; JMP IF NOT READY DEC A ; SET READY STATUS RET ; AND RETURN IT. ; ; RDRSTAT: IN A,(S2STAT) ; GET STATUS AND 2 RET Z ; RETURN IF NO CHAR IN A,(S2DATA) ; ELSE, GET CHAR AND 7FH ; MASK PARITY SCF ; SET FLAG RET ; CENTSTAT: IN A,(CSTAT) ; CHECK CENTRONICS RDY STATUS BIT 4,A LD A,0 RET NZ DEC A RET ; ; PTR: CALL RDRSTAT ;GET STATUS OR CHAR. JR NC,PTR ;LOOP IF NO CHAR. RET ; PUN: LD A,(RAMDATY+DFLAG) ;CHECK IF CENT. OR SERIAL BIT 5,A JR NZ,LSTDRV ;IF NOT 0,THEN USE SERIAL PORT DRIVER CENTOUT: CALL MSTK ; SAVE STACK OUT (ROMCTL),A ; TURN ON ROM CALL CENTDRV ; USE ROM CENTRONICS DRIVER IN A,(ROMCTL) ; TURN OFF ROM POP HL ; RESTORE STACK LD SP,HL RET ; SETXY: POP HL ;GET RETURN ADDRESS ; PUSH IX ;SAVE IX & IY PUSH IY ; LD IX,RAMDATX ;INIT IX & IY LD IY,RAMDATY ; OUT (ROMCTL),A ;TURN ON ROM ; JP (HL) ;RETURN ; HOME: CALL MSTK ;FIX STACK CALL SETXY ;SAVE AND INIT IX & IY, TURN ON ROM ; CALL HMRM ;CALL ROM ; CRETN: IN A,(ROMCTL) ;TURN OFF ROM POP IY ;RESTORE IX & IY POP IX ; POP HL LD SP,HL ;FIX STACK ; RET ; MSTK: POP DE ;SAVE RET. ADDR. ; LD HL,0 ;GET CURRENT STACK ADD HL,SP ;IN HL. ; LD A,SP_PAGE CP H JR Z,SKP_STK LD SP,STACK ;MOVE STACK SKP_STK:PUSH HL ;SAVE OLD STACK ; PUSH DE ;RESTORE RET. ADDR. RET ; SELDSK: LD B,E CALL MSTK ;FIX STACK LD E,B CALL SETXY ;SAVE AND INIT IX & IY, TURN ON ROM ; LD HL,DPBASE CALL SELROM ; PUSH AF IN A,(ROMCTL) ;ROM OFF POP AF JP DIRET ; BDRV: LD HL,4 ;RETURN ERROR CODE LD (HL),H ;SET TO DRIVE A LD L,H RET ; SETTRK: LD A,C ;SET TRACK IN RAMDATY LD (SEKTRK+RAMDATY),A RET ; ; SETSEC: LD A,C ;SET SECTOR IN RAMDATY LD (SEKSEC+RAMDATY),A RET ; ; SETDMA: LD (DMAADR+RAMDATY),BC ;SET DMA ADDRESS IN RAMDATY RET ; ; READ: CALL MSTK ;FIX THE STACK CALL SETXY ;SAVE AND INIT IX & IY, TURN ON ROM ; CALL RDLSEC ; READ A LOGICAL SECTOR JR RWMOVE ; MOVE DATA ; WRITE: CALL MSTK ;FIX THE STACK CALL SETXY ;SAVE AND INIT IX & IY, TURN ON ROM ; CALL WRTLSEC ; WRITE A LOGICAL SECTOR ; ; RWMOVE: OR A ; SET FLAGS ON ACC LD B,A ; SAVE ERROR CODE IN A,(ROMCTL) ; TURN OFF ROM LD A,B ; RESTORE ERROR CODE JR NZ,DIRET ; JUMP IF ERROR DURING READ OR WRITE LDIR ; MOVE SECTOR ; LD A,(IY+WRTYPE) ;CHECK IF DIR WRITE CP WRDIR LD A,0 ;A=NO ERROR STATUS IN CASE WE'RE DONE JR NZ,DIRET ;JMP IF NOT DIR WRITE ; RES HSTWRT,(IY+DFLAG) ;CLEAR WRITE FLAG ; CALL WRTHST ;WRITE BUFFER ; DIRET: POP IY ;RESTORE IX & IY POP IX ; POP HL ;RESTORE STACK LD SP,HL ; EX DE,HL CP BDFM ;SEE IF UNREADABLE JP Z,BDRV ;JMP IF UNREADABLE ; CP NRDY ;SEE IF NOT READY JP Z,BDRV ;JMP IF NOT READY ; RET ; SECTRAN:LD L,C ;HL=BC LD H,B ; INC HL ;START SECTORS AT 1 ; LD A,D ;SEE IF XLAT TABLE OR E RET Z ;RETURN IF NO XLAT ; EX DE,HL ;HL=XLT ; ADD HL,BC ;ADD TO TABLE LD L,(HL) ;GET XLATED SECTOR LD H,0 ; RET ; ; WRTHST: OUT (ROMCTL),A ;TURN THE ROM ON ; CALL WRHSRM ;CALL THE ROM ; HSTRET: IN A,(ROMCTL) ;TURN OFF THE ROM ; LD A,(IX+ERFLAG) ;GET STATUS ; RET ; RDHST: OUT (ROMCTL),A ;TURN ON ROM ; CALL RDHSRM ;CALL ROM ; JR HSTRET ;RETURN ; ; RDBLK: LD IY,RAMDATY ;INIT IY ; CALL MSTK ;FIX THE STACK ; CALL RDHST ;CALL ROM ; DRET: POP HL ;RESTORE THE STACK LD SP,HL ; RET ; WRBLK: LD IY,RAMDATY ;INIT IY ; CALL MSTK ;FIX STACK ; CALL WRTHST ;CALL ROM ; JR DRET ; DISCIO: LD IY,RAMDATY ; CALL MSTK ;FIX THE STACK ; OUT (ROMCTL),A ;TURN ON THE ROM ; CALL DISRM ;CALL THE ROM ; IN A,(ROMCTL) ;TURN OFF ROM ; LD A,(IX+ERFLAG) ; JR DRET ;RETURN ; ; ; CVMSG IS A ROUTINE TO CHANGE THE VIRTUAL DRIVE MESSAGE. ; ON ENTRY: HL POINTS TO THE BEGINING OF THE NEW MESSAGE. ; DE POINTS TO THE LOCATION OF THE CHARACTER ; WHICH WILL BE SET TO THE LOGICAL DRIVE ; THAT THE VIRTUAL DRIVE IS TO BECOME. ; BC IS THE LENGTH OF THE NEW MESSAGE. ; ; AF,BC,DE,HL ARE CHANGED, ALL OTHER REGS. ARE UNCHANGED. ; CVMSG: PUSH HL EX DE,HL XOR A SBC HL,DE LD DE,VMSG ADD HL,DE LD (VDRVP+RAMDATY),HL ; POP HL LDIR RET ; DPBASE EQU $ DPE0: DW XLT1K DW 0 DW 0 DW 0 DW DIRBUF DW DPB0 DW CSV0 DW ALV0 ; DPE1: DW XLT1K DW 0 DW 0 DW 0 DW DIRBUF DW DPB1 DW CSV1 DW ALV1 ; DPE2: DW XLT1K DW 0 DW 0 DW 0 DW DIRBUF DW DPB2 DW CSV2 DW ALV2 ; DPE3: DW XLT1K DW 0 DW 0 DW 0 DW DIRBUF DW DPB3 DW CSV3 DW ALV3 ; DPE4: DW XLT1K DW 0 DW 0 DW 0 DW DIRBUF DW DPB4 DW CSV4 DW ALV4 ; DPB0: DW 40 DB 4 DB 15 DB 1 DW 194 DW 191 DB 0E0H DB 0 DW 48 DW 2 ; DPB1: DW 40 DB 4 DB 15 DB 1 DW 194 DW 191 DB 0E0H DB 0 DW 48 DW 2 ; DPB2: DW 40 DB 4 DB 15 DB 1 DW 194 DW 191 DB 0E0H DB 0 DW 48 DW 2 ; DPB3: DW 40 DB 4 DB 15 DB 1 DW 194 DW 191 DB 0E0H DB 0 DW 48 DW 2 ; DPB4: DW 40 DB 4 DB 15 DB 1 DW 194 DW 191 DB 0E0H DB 0 DW 48 DW 2 ; ; RAMDATX: HSTDSK EQU $-RAMDATX DB 0 HSTTRK EQU $-RAMDATX DB 0 HSTSEC EQU $-RAMDATX DB 0 SECCNT EQU $-RAMDATX DB 1 RETRY EQU $-RAMDATX DB 20 HSTBUF EQU $-RAMDATX DW DSKBUF ERFLAG EQU $-RAMDATX DB 0 PHYTRK EQU $-RAMDATX DB 0 PHYHD EQU $-RAMDATX DB 0 IOADD EQU $-RAMDATX DW 0 SECSIZ EQU $-RAMDATX DW 0 STADD EQU $-RAMDATX DW 0 DW 0 DW 0 DB 0 CMDCNT EQU $-RAMDATX DB 9 CMDBUF EQU $-RAMDATX DW 0 DW 0 DW 0 DW 0 DB 0 ; DATXLN EQU $-RAMDATX ; SCOUNT: DB 0FFH SFLAG: DB 0 ; SER1BAUD: DB DFLT1 ;index in Baud rate table for SER1 default baud rate SER2BAUD: DB DFLT2 ;index in Baud rate table for SER2 default baud rate DS 2,0ffh ;reserved for future expansion ; VNUMB: DB 3 ; # OF PHYSICAL DRIVES - 1 TLEV: DB 0 ; TERMINAL LEVEL ; ; RAMDATY: SCNTIY EQU SCOUNT-RAMDATY SFLAGIY EQU SFLAG-RAMDATY ; SEKDSK EQU $-RAMDATY DS 1 SEKTRK EQU $-RAMDATY DS 1 SEKSEC EQU $-RAMDATY DS 1 ; SEKHST EQU $-RAMDATY DS 1 ; UNACNT EQU $-RAMDATY DS 1 UNADSK EQU $-RAMDATY DS 1 UNATRK EQU $-RAMDATY DS 1 UNASEC EQU $-RAMDATY DS 1 UNAMAX EQU $-RAMDATY DS 1 SECTRK EQU $-RAMDATY DS 1 ; WRTYPE EQU $-RAMDATY DS 1 DFLAG EQU $-RAMDATY DB 20H TRSEC EQU $-RAMDATY DS 1 ; VMSGP EQU $-RAMDATY DW VMSG VDRVP EQU $-RAMDATY DW VDRV ; CDSK EQU $-RAMDATY DB 0FFH PDSK EQU $-RAMDATY DB 0 VDSK EQU $-RAMDATY DB 0 ; DMAADR EQU $-RAMDATY DS 2 OUTP EQU $-RAMDATY DW CNOUT INP EQU $-RAMDATY DW PCONIN ; ; MTAB contains one 9 byte entry for each logical drive. ; The bytes of each entry are defined as follows: ; ; Byte 0 DSKDEF0: ; Bit 0-2 Motor control bit ; Bit 3-4 Double sided mode: ; 00=Even tracks on side 0, ; Odd tracks on side 1. ; 01=1st 40 (or 80) tracks ; on side 0, remaining ; tracks on side 1. ; 10=Both sides are treated ; as a single track with ; twice as many sectors. ; Bit 5 Double sided drive if = 1. ; Bit 6 Sectors start a 0 if = 1. ; Bit 7 Foreign drive format if = 1. ; ; Byte 1 DSKDEF1: ; Bit 0-1 Physical drive address. ; Bit 2 Double sided media if = 1. ; Bit 3-4 Sector size: ; 00=128 ; 01=256 ; 10=512 ; 11=1024. ; Bit 5 Tracks: 0=40; 1=80. ; Bit 6 Density: 0=single; 1=double. ; Bit 7 Virtual drive: 1=virtual. ; ; Byte 2 Motor on wait time in increments of 4 ms. ; ; Byte 3 Head settle time (after seek) in increments ; of 4 ms. ; ; Byte 4-5 The two parameter bytes for the FDC specify ; command: Byte 4 = SRT/HUT ; Byte 5 = HLT/ND ; ND must be 1. ; ; Byte 6 EOT byte for FDC read or write commands. ; ; Byte 7 GPL byte for FDC read or write commands. ; ; Byte 8 Current track. ; MTAB: MTOFF EQU $-RAMDATY DB 21H DB 0DCH DB 125 DB 4 DB 0DFH DB 3 DB 5 DB 28 DB 0FFH ; DB 22H DB 5DH DB 125 DB 4 DB 0DFH DB 3 DB 5 DB 28 DB 0FFH ; DB 24H DB 5EH DB 125 DB 4 DB 0DFH DB 3 DB 5 DB 28 DB 0FFH ; DB 24H DB 5FH DB 125 DB 4 DB 0DFH DB 3 DB 5 DB 28 DB 0FFH ; DB 21H DB 0DCH DB 125 DB 4 DB 0DFH DB 3 DB 5 DB 28 DB 0FFH ; DIRBUF: DS 128 ; ALV0: DS 25 CSV0: DS 48 ALV1: DS 25 CSV1: DS 48 ALV2: DS 25 CSV2: DS 48 ALV3: DS 25 CSV3: DS 48 ALV4: DS 25 CSV4: DS 48 ; VMSGº ÄB cr,lf,'Your lower drive is being re-assigned as drive ' VDRV: DB 'A.',cr,lf,'Exchange diskettes and press [RETURN]',0 ; LSTFLG: DB 0FFH ; PRINTER READY FLAG ; ; dcastrtº äb 1bh,3dh,0ffh » dcá prefiø string Š ds 3,0ffh ; dcamid: ds 6,0ffh ; dca seperator ; dcaend: ds 6,0ffh ; dca terminator string ; esc_lvlº äb 0 ;indicateó esã sequencå level offset1: db 0 ;first character offset offset2: db 0 ;second character offset order: db 0 ;Bit 0 = 0 --> row, then column, ; = 1 --> column, then row ;Bit 1 = 0 --> binary cursor adresses ; 1 --> ascii cursor addresses first: db 0 ; temporary storage of first second: db 0 ; temporary storage of second ; XLTAB: DB 0 DW 40 XLT1K: DB 1,2,3,4,5,6,7,8 DB 25,26,27,28,29,30,31,32 DB 9,10,11,12,13,14,15,16 DB 33,34,35,36,37,38,39,40 DB 17,18,19,20,21,22,23,24 ; DB 0FEH ; CONSOLE XLT TABLE DW CLEN esctbl: DB 0FFH ctrltbl:DB 0FFH escvect:DW 0 ctvect: DW 0 ; ; TRANSLATION STRINGS FOR THE TERMINAL GO HERE ; CLEN EQU $-ESCTBL ; DB 0FFH ;EOT DW BIOS+0A00H-$-60-FLEN ;SPACE FOR MORE XLT'S DS (BIOS+0A00H-$-58-41),0 ; DB 0FDH ;IMS BUFFER HEADER DW 0 ; DB 0FCH ;FUNCTION KEY HEADER DW FLEN ; FTAB: DB 15 ;TABLE ENTRIES ; DB 4CH,1,8H ;LEFT ARROW DB 6CH,0 DB 0CH,1,CTLX ; DB 4DH,1,':' ;RIGHT ARROW DB 6DH,1,':' DB 0DH,1,':' ; DB 4AH,1,'*' ;UP ARROW DB 6AH,1,'*' DB 0AH,1,'*' ; DB 4BH,0 ;DOWN ARROW DB 6BH,0 DB 0BH,0 ; DB 49H,1,8H ;ERASE DB 69H,0 DB 9H,1,CTLX ; FLEN EQU $-FTAB ; DS 52,0 ;STACK SPACE ; DSKBUF EQU $ STACK EQU $ SP_PAGE EQU ($/256)-1 ; SIGNON: DB 0DH,0AH,'Micro-Decision -- 64K CP/M Vers. 2.2 -- Rev. ' DB ((REV AND 0F0H) SHR 4)+ASC0,'.',(REV AND 0FH)+ASC0 DB CR,LF DB "Copyright '76,'77,'78,'79,'80 Digital Research, Inc." DB CR,LF DB 'Copyright 1982,1983,1984 Morrow Designs, Inc.' DB CR,LF,LF DB '************** Double Sided System **************' DB CR,LF,0 ; ; BOOT: LD SP,STACK LD IY,RAMDATY CALL INITCTC ;initialize baud rates LD DE,SIGNON OUT (ROMCTL),A ;TURN ON ROM CALL MSGRM IN A,(ROMCTL) ;TURN OFF ROM ; XOR A LD (3),A LD (4),A ; LD HL,CPM ; JP GOCPM ; END