TITLE DSKDRV - FORTRAN-80 DISK DRIVER .8080 MAXLUN EQU 10 ;MAX # OF LUN'S ALLOWED ;BDOS FUNCTION CALLS, FCB OFFSETS BDOS EQU 5 ;CP/M BDOS ENTRY POINT .RSET EQU 13 ;DISK RESET .SELCT EQU 14 ;SELECT DISK .OPEN EQU 15 ;OPEN FILE .CLOSE EQU 16 ;CLOSE FILE .DELET EQU 19 ;DELETE FILE .MAKE EQU 22 ;CREATE FILE .STDMA EQU 26 ;SET DMA ADDRESS FCB.FT EQU 9 ;FILE TYPE FCB.EX EQU 12 ;EXTENT BYTE FCB.RC EQU 15 ;RECORD COUNT BYTE FCB.NR EQU 32 ;NEXT RECORD BYTE FCB.RR EQU 33 ;RANDOM RECORD NUMBER (2.X) FCBLEN EQU 36 ;FCB SIZE SECSIZ EQU 128 ;SECTOR SIZE (RECORD LENGTH) ; GLOBAL DEFINITIONS EXTRN $CPMVN,$CPMRF,$CPMWF,$BL,$BF,$ERR EXTRN $IOERR,$REC,$UN,$LUNTB,$CLSFL ENTRY $DSKER,$FLFLG,$MEMRY,DSKDRV DSEG ;DATA AREA ; I/O ERROR CODE DEFNS OBOVF EQU 016Q ;OUTPUT BUFFER LIMIT EXCEEDED IRECER EQU 022Q ;INPUT RECORD TOO LONG NOFILE EQU 236Q ;FILE NOT FOUND FULERR EQU 237Q ;DISK FULL LUNERR EQU 240Q ;LUN TOO LARGE NOMEM EQU 241Q ;OUT-OF-MEMORY ; I/O MODE DEFN BYTE MD.ALC EQU 80H ;80H ALLOCATED BUFFER AND FCB MD.OPN EQU 40H ;40H FILE IS OPEN MD.OUT EQU 20H ;20H IF OUTPUT MD.BIN EQU 10H ;10H IF UNFORMATTED I/O MD.WRT EQU 08H ;08H WRITE-DATA-IN-BUFFER MD.RND EQU 04H ;04H IF RANDOM I/O $FLFLG: DS MAXLUN ;I/O MODE BYTE FOR EACH LUN $FLCNT: DS MAXLUN ;I/O BUFFER INDEX FOR EACH LUN $FLBUF: DS MAXLUN*2 ;BUFFER LOCATION FOR EACH LUN $FLFCB: DS MAXLUN*2 ;FCB LOCATION FOR EACH LUN $DSKER: DS 1 ;STATUS OF LAST I/O CLSADR: DS 2 $MEMRY: DS 2 ;FOR LOADER TO STORE TOP OF MEM INTO CSEG ;CODE AREA FILTXT: DB "FORT",0 ;DEFAULT FILENAME TEXT FILEXT: DB "DAT",0 PAGE ; I/O DISPATCH TABLE ; LUN'S 6 THRU MAXLUN POINT TO THIS TABLE VIA $LUNTB. ; AN EXPLICIT OPEN VIA CALL OPEN () ALLOW ; OTHER UNITS TO USE THE DISK ALSO... DSKDRV: DW DSKFRD ;FORMATTED READ DW DSKFWR ;FORMATTED WRITE DW DSKURD ;UNFORMATTED READ DW DSKUWR ;UNFORMATTED WRITE DW DSKREW ;REWIND DW $IOERR ;BACKSPACE (NOT SUPPORTED). DW DSKCLS ;ENDFILE FNFERR: CALL $ERR DB NOFILE ;FILE NOT FOUND DSKFUL: CALL $ERR DB FULERR ;DISK FULL LUNOVF: CALL $ERR DB LUNERR ;LUN TOO LARGE MEMERR: CALL $ERR DB NOMEM ;OUT-OF-MEMORY ;------------------------------------------------------ ; ; GET MODE BYTE(LUN) FROM $FLFLG ; GTMODE: LXI H,$FLFLG-1 LDA $UN ;GET UNIT # MVI D,0 MOV E,A DAD D ;[HL] POINTS TO FLAG MOV A,M ;GET FLAG RET ;------------------------------------------------------ ; ; SET DMA TO DATA BUFFER(LUN) ; SETBUF: PUSH B PUSH D CALL GETBUF ;GET BUFFER ADR MVI C,.STDMA CALL BDOS POP D POP B RET ;------------------------------------------------------ GETBUF: LDA $UN ADD A MOV E,A MVI D,0 LXI H,$FLBUF-2 DAD D MOV E,M INX H MOV D,M RET ;------------------------------------------------------ ; ; GET DATA.BUFFER.OFFSET(LUN) ; GTBOFF: LXI H,$FLCNT-1 LDA $UN MVI D,0 MOV E,A DAD D MOV A,M ;GET OFFSET RET ;------------------------------------------------------ ; ; GET ADR OF FCB(LUN) IN [DE] ; GTFCB: LXI H,$FLFCB-2 LDA $UN ADD A MOV E,A MVI D,0 DAD D ;POINT TO ADR OF FCB MOV E,M INX H MOV D,M RET ;------------------------------------------------------ ; ; GET READ/WRITE RECORD NUMBER FOR LUN ; ON RETURN: ; [HL] = FCB.RR(LUN) ADR OF RND REC NUM. ; [DE] = $REC 00 OR RND REC NUM. ; GTREC: CALL GTFCB LXI H,FCB.RR DAD D XCHG LHLD $REC XCHG RET ;------------------------------------------------------ ; ZERO FCB FROM EXTENT BYTE TO END. ; CLRFCB: CALL GTFCB LXI H,FCB.EX DAD D LXI B,FCBLEN-FCB.EX CLRFCL: MOV M,B INX H DCR C JNZ CLRFCL RET ;------------------------------------------------------ ; COPY BYTES FROM [DE] TO [HL] UNTIL NULL (00). ; CPYTXT: MOV M,A ;COPY FROM [DE] TO [HL] INX H ;UNTIL NULL. INX D LDAX D ORA A JNZ CPYTXT RET PAGE ;------------------------------------------------------ ; ; OPNCHK - ASSURE THAT FILE IS OPEN AND BUFFERS ALLOCATED. ; IF NOT THEN: ; 1. ALLOCATE DATA BUFFER AND FCB FROM $MEMRY. ; 2. OPEN FILE WITH NAME OF FORT##.DAT WHERE: ; ## IS LOGICAL-UNIT-NUMBER (LUN) OF FILE. OPNCHK: LDA $UN CPI MAXLUN+1 ; JNC LUNOVF ;LUN IS TOO LARGE ; ---------------- PUSH B ;SAVE OPEN MODE REQUEST. CALL GTMODE ;GET FLAG ORA A ;ALLOCATED BUFFER,FCB? CP ALCBUF ;NO, GET SPACE AND SET PTRS ; ---------------- POP B ;GET I/O MODE IN [C] ANI MD.OPN ;WAS OPEN? CZ OPNFIL ;NO, OPEN FILE. ;------------------------------------------------------ ; ; SETREC - SET UP RECORD NUMBER ; SETREC: CALL GTREC ;GET CURRENT & LAST RECORD NUMBERS MOV A,D ;[DE] = $REC ORA E ;IF RANDOM I/O JNZ SETRND ;USE VALUE IN $REC ; ---------------- MOV E,M ;..ELSE INX H ;USE CURRENT RECORD MOV D,M ;SET BY SEQ READ/WRITE. PUSH D ;SAVE REC NO. CALL GTMODE ANI NOT MD.RND ;SET SEQUENTIAL MODE MOV M,A POP D ;RESTORE REC NO. JMP SETSEQ ; ---------------- SETRND: CALL GTMODE ANI MD.WRT ;WRITE-DATA-IN-BUFFER? CNZ FRCOUT ;YES, FLUSH IT FIRST. CALL GTMODE ORI MD.RND ;SET RANDOM MODE MOV M,A CALL GTREC ;RESTORE REC NO'S. DCX D ;ADJUST RANDOM REC NO. MOV M,E INX H ;STORE AT FCB.RR FOR NEXT I/O MOV M,D INX H MVI M,0 ; ---------------- SETSEQ: LDA $CPMVN ;CP/M VERSION FLAG ORA A ;VERSION 1.X ? RZ ;NO, VERSION 2.X NOTHING ELSE NEEDED. ;------------------------------------------------------ ; ; SPLIT RANDOM RECORD INTO EXTENT AND RELATIVE RECORD ; FOR VERSION 1.X ; SETV1: MOV A,E RAL MOV A,D RAL MOV B,A MOV A,E ANI X'7F' MOV C,A ; ---------------- CALL GTFCB ;[DE] = ADR OF FCB(LUN) LXI H,FCB.EX DAD D MOV A,M ;FETCH CURRENT EXTENT CMP B JZ SAMEXT ;IF SAME AS REQUESTED EXTENT ; ; CLOSE CURRENT EXTENT, OPEN REQUESTED ONE ; PUSH B ;EXT/REC PUSH D ;FCB ADR LXI H,FCB.NR DAD D MVI M,0 ;ZERO THE RECORD NUMBER LHLD $MEMRY ;GET SCRATCH BUFFER XCHG ;FROM TOP OF HEAP FOR OPEN/CLOSE MVI C,.STDMA CALL BDOS CALL GTMODE ANI MD.OUT ;OPEN FOR OUTPUT? JZ OPNXT ;NO, SKIP THIS CLOSE POP D PUSH D ;FCB MVI C,.CLOSE CALL BDOS OPNXT: POP D ;FCB POP B ;EXT/REC PUSH B PUSH D LXI H,FCB.EX DAD D MOV M,B ;SET NEW EXTENT NUMBER MVI C,.OPEN CALL BDOS INR A JNZ SKEXT ;IF IT EXISTS POP D PUSH D ;FCB CALL MAKEXT ;CREATE NEW EXTENT SKEXT: POP D ;FCB POP B ;EXT/REC SAMEXT: LXI H,FCB.NR DAD D MOV M,C ;SET RECORD NUMBER RET PAGE ;------------------------------------------------------ ; ALLOCATE FCB AND BUFFER FOR UNIT . ALLOCATES UP FROM ; $MEMRY AND STORES PTRS IN TABLE. ALCBUF: PUSH H LHLD $MEMRY ;GET CURRENT TOP XCHG ;IN [DE] ; ---------------- LXI H,-256 DAD SP MOV A,L SUB E ;IF MEMTOP-256 < $MEMRY, MOV A,H ;THEN GIVE OUT-OF-MEMORY SBB D ;ERROR AND EXIT... JC MEMERR ; ---------------- LXI H,$FLBUF-2 LDA $UN ADD A MVI B,0 MOV C,A ;[BC]= 2*UNIT# DAD B ;GET ADR OF PTR TO BUFFER MOV M,E INX H MOV M,D ;STORE $MEMRY AS ADR LXI H,SECSIZ DAD D ;GET NEW TOP PUSH H ;SAVE FCB ADR CALL GTFCB ;GET [HL]=ENTRY+1 POP D PUSH D ;SAVE FCB ADR MOV M,D DCX H MOV M,E ;STORE ADR OF FCB LXI H,FCBLEN DAD D ;GET NEW TOP OF ALLOC SHLD $MEMRY ;STORE AWAY ; ---------------- POP H ;FCB ADR. MVI M,0 ;DEFAULT TO CURRENT DISK INX H LXI D,FILTXT ;DEFAULT NAME INITIALLY FORT##.DAT LDAX D CALL CPYTXT ;MOVE "FORT" TO FCB LDA $UN MOV B,A ;SAVE UNIT # SUI 10 ;CARRY SET IF NOT UNIT 10 SBB A ADI "1" ;"1" IF 10 ELSE "0" MOV M,A ;STORE DIGIT 1 OF # MOV A,B CPI 10 ;WAS IT 10? JC SKPSTZ ;NO, DON'T SET ZERO XRA A SKPSTZ: ADI "0" ;GET 2ND DIGIT INX H MOV M,A MVI A," " INX H MOV M,A INX H LXI D,FILEXT-1 ;EXTENSION CALL CPYTXT ;MOVE "DAT" TO FCB ; ---------------- POP H ;GET PTR TO FLAG MVI A,MD.ALC ;NOW ALLOCATED. MOV M,A ;SET FLAG RET PAGE ;------------------------------------------------------ ; ; OPEN FILE GIVEN BY LUN AND CLEAR BUFFER INDEX. ; ENTRY: [DE] = ADR OF FCB ; EXIT: [HL] = ADR OF MODE BYTE ; [A] = MODE BYTE - ALLOCATED & OPEN. ; OPNFIL: PUSH B ;SAVE I/O MODE CALL GTBOFF ;GET BUFFER.OFFSET(LUN) MOV M,D ;CLEAR BUFFER INDEX ; ---------------- LHLD $CLSFL LXI D,CLSALL MOV A,H SUB D JNZ STRADR ;NOT US, STORE ROUTINE ADR MOV A,L SUB E JZ STRCLS ;US, DON'T STORE AGAIN STRADR: SHLD CLSADR STRCLS: XCHG SHLD $CLSFL ;ON EXIT, CLOSE ALL FILES CALL CLRFCB ;ZERO FCB & RECORD NUMBER. CALL SETBUF ;SET DMA TO FILE BUFFER. ; ---------------- POP B ;I/O MODE PUSH B MOV A,C ANI MD.OUT JZ OPNINP ;BRIF OPEN INPUT ;------------------------------------------------------ ; ; OPEN NEW FILE FOR OUTPUT OR RANDOM. ; PUSH D ;SAVE FCB ADR MVI C,.DELET ;DELETE OLD FILE CALL BDOS POP D PUSH D CALL MAKEXT ;CREATE NEW FILE. POP D ;RESTORE FCB ADR ;------------------------------------------------------ ; ; OPEN EXISTING FILE FOR INPUT OR RANDOM. ; OPNINP: MVI C,.OPEN ;OPEN FILE CALL BDOS INR A JZ FNFERR ;BRIF FILE NOT FOUND (FATAL). OPNDON: CALL GTMODE POP B ;GET I/O MODE. MOV A,C ORI MD.ALC+MD.OPN MOV M,A ;MODE ALLOCATED/OPEN + I/O RET ;------------------------------------------------------ ; ; MAKE NEW FILE OR EXTENT. ; MAKEXT: MVI C,.MAKE ;CREATE NEW FILE CALL BDOS INR A JZ DSKFUL ;BRIF DISK FULL ERROR. RET PAGE ;------------------------------------------------------ ; ; REWIND UNIT # ; DSKREW: CALL GTMODE ANI MD.OPN ;FILE OPEN? CNZ DSKCLS ;YES, CLOSE IT NOCLOS: XRA A ;GOOD RETURN RET ;------------------------------------------------------ ; ; ENDFILE UNIT # ; DSKCLS: CALL GTMODE ADD A ;OPEN? JP NOCLOS ;NO, DON'T CLOSE MVI M,MD.ALC ;FLAG CLOSED NOW ADD A ;OUTPUT FILE? CM FRCBUF ;YES, DUMP LAST IF NEEDED CALL GTFCB ;GET ADDR OF FCB CALL SETBUF ;SET DMA ADR MVI C,.CLOSE ;CLOSE FILE CALL BDOS XRA A ;NEVER AN ERROR RET ;------------------------------------------------------ ; ; CLOSE ALL FILES. CALLED FROM EXIT ; CLSALL: LXI D,1 CLSAL1: LXI H,$FLFLG-1 DAD D MOV A,M ADD A ;SET MINUS IF OPEN PUSH D ;SAVE UNIT # MOV A,E STA $UN ;SET UP FOR OTHERS CM DSKCLS ;CLOSE FILE IF OPEN POP D ;GET # BACK INX D ;BUMP IT LDA $LUNTB ;GET MAX LUN CMP E ;DONE ALL? JNZ CLSAL1 ;NO, DO NEXT RET ;RETURN PAGE ;------------------------------------------------------ ; ; UNFORMATTED WRITE ; DSKUWR: MVI C,MD.OUT+MD.BIN CALL OPNCHK ;OPEN IF NOT OPEN LHLD $BF ;GET BUFFER ADR PUSH H XCHG LHLD $BL ;GET LENGTH OF DATA MVI H,0 ;# OF BYTES XCHG DAD D ;PTR TO 1ST TO CLEAR XRA A DCR E DSKWCL: INR E ;CLEARED REST OF BUFFER? JM DSKUW1 ;YES, DONE MOV M,A INX H JMP DSKWCL ;CLEAR END OF BUFFER DSKUW1: POP D ;GET BUFFER ADR MVI C,.STDMA ;SET DMA TO BUFFER CALL BDOS CALL WRITE ;WRITE RECORD ORA A ;ERROR? RZ ;NO, GOOD RETURN STC RET PAGE ;------------------------------------------------------ ; ; UNFORMATTED READ ; DSKURD: MVI C,MD.BIN CALL OPNCHK ;OPEN IF NEEDED LHLD $BF XCHG MVI C,.STDMA ;SET DMA TO $BF CALL BDOS MVI A,128 STA $BL ;ALWAYS 1 SECTOR CALL READ ;READ RECORD INTO $BF ORA A ;EOF OR GOOD RZ CPI 2 CMC RET ; PAGE ;------------------------------------------------------ ; ; FORMATTED WRITE ; DSKFWR: MVI C,MD.OUT CALL OPNCHK ;OPEN FILE IF NEEDED XRA A STA $DSKER ;CLEAR COUNT LDA $BL ;GET # TO WRITE ORA A RZ ;IGNORE NULL BUFFERS LDA $BL ORA A JP DSKFW0 CALL $ERR ;WARN USER OF.. DB OBOVF ;OUTPUT BUFFER LIMIT EXCEEDED MVI A,127 ;AND TRUNCATE TO 127 BYTES. DSKFW0: CALL RNDCHK ;IF RND MODE, SET OFFSET TO 0. LHLD $BF ;GET BUFFER PTR DSKFW2: PUSH PSW ;SAVE COUNT MOV A,M CALL DSKOUT ;SEND OUT BYTE INX H ;INCREMENT BUFFER PTR POP PSW ;RETRIEVE COUNT DCR A ;DECREMENT COUNT JNZ DSKFW2 ;ONE MORE TIME ; DSKWDN: MVI A,15Q CALL DSKOUT ;PUT OUT CALL GTMODE ;MARK MODE BYTE WITH ORI MD.WRT ;WRITE-DATA-IN-BUFFER. MOV M,A LDA $DSKER ;GET $DSKEROR STATUS ORA A ;ERROR? RZ ;NO STC ;YES RET ; PAGE ;------------------------------------------------------ ; ; FORMATTED READ ; DSKFRD: MVI C,0 CALL OPNCHK ;OPEN IF NEEDED XRA A STA $BL ;CLEAR LENGTH OF RECORD STA $DSKER ;CLEAR $DSKEROR CALL RNDCHK ;IF RND MODE, SET OFFSET TO 0. DSKFR1: CALL DSKIN ;GET CHAR JC DSKRDN ;JUMP IF EOF CPI 32Q ;CP/M EOF? JZ DSKEOF ;YES LHLD $BL MVI H,0 XCHG LHLD $BF ;BASE DAD D ;GET WHERE TO PUT BYTE MOV M,A ;STORE CHAR INX D ;BUMP OFFSET XCHG SHLD $BL ;UPDATE OFFSET CPI 15Q ;? JZ DSKRDN ;YES, HAVE RECORD MOV A,L ;GET OFFSET CPI 128 ;BUFFER FULL? JC DSKFR1 ;NO, GET NEXT CALL $ERR ;WARN USER OF.. DB IRECER ;INPUT RECORD TOO LONG. XRA A RET ; DSKRDN: LDA $DSKER ;GET STATUS ORA A RZ ;NO ERROR CPI 2 CMC RET DSKEOF: ORA A ;SET CC'S RET ; PAGE ;------------------------------------------------------ ; ; RESET BUFFER OFFSET IF RANDOM READ OR WRITE ; RNDCHK: PUSH PSW CALL GTMODE ANI MD.RND JZ RNDCHX ;DO NOTHING IF SEQUENTIAL MODE. CALL GTBOFF ;ELSE ZERO BUFFER OFFSET SO.. MVI M,0 ;NEXT READ/WRITE STARTS AT BEGINNING. RNDCHX: POP PSW RET ;------------------------------------------------------ ; ; DISK INPUT ROUTINE ; DSKIN: CALL GTBOFF ;BUFFER.OFFSET(LUN) ORA A ;BUFFER EMPTY? CZ REDBUF ;YES, REFIL RC ;EOF DCR M ;DECR. # LEFT LXI H,$FLBUF-2 DAD D DAD D ;GET $FLBUF PTR CMA ADI 129 ;128-#LEFT=OFFSET ADD M MOV E,A INX H MVI A,0 ADC M MOV D,A LDAX D ;GET CHAR ORA A RET ;------------------------------------------------------ ; ; READ BUFFER FROM DISK ; REDBUF: PUSH H PUSH D CALL SETBUF CALL READ ;READ RECORD STA $DSKER ;STORE STATUS ORA A POP D POP H MVI A,128 ;FULL BUFFER MOV M,A ;STORE COUNT RZ ;IF NO ERROR STC RET ;------------------------------------------------------ ; ; DISK OUTPUT ROUTINE ; DSKOUT: PUSH H PUSH PSW CALL GTBOFF ;GET BUFFER OFFSET ORA A ;BUFFER FULL? CM DMPBUF ;YES, DUMP INR M LXI H,$FLBUF-2 DAD D DAD D ;POINT TO ADR OF BUFFER ADD M MOV E,A INX H MVI A,0 ADC M MOV D,A ;POINTS TO FREE POP PSW ;GET CHAR BACK STAX D ;STORE CHAR POP H RET ;------------------------------------------------------ ; ; FORCE FORMATTED BUFFER OUT ON CLOSE ; FRCBUF: ADD A ;UNFORMATTED I/O? JM FRCOUT ;YES, FORCE OUT LAST IF NEEDED MVI A,32Q CALL DSKOUT ;SET END OF FILE FRCOUT: CALL GTBOFF ;BUFFER.OFFSET(LUN) ORA A ;EMPTY? MVI M,0 ;CLEAR OFFSET RZ ;YES, DO NOTHING PUSH PSW ;SAVE OFFSET CALL GETBUF ;GET BUFFER ADR POP PSW MOV L,A MVI H,0 DAD D ;POINT TO 1ST UNUSED CHKFIL: ORA A ;SET MINUS IF FULL JM DMPBF1 ;NOTHING TO FILL MVI M,0 ;CLEAR BYTE INX H INR A ;BUMP OFFSET JMP CHKFIL ;------------------------------------------------------ ; ; DUMP BUFFER TO DISK ; DMPBF1: DCX H ;SO THAT DRIVE # ISN'T CLEARED DMPBUF: PUSH H PUSH D CALL SETBUF CALL WRITE ;WRITE RECORD STA $DSKER ;STORE STATUS CALL GTMODE ANI NOT MD.WRT ;CLEAR WRITE-DATA BIT MOV M,A POP D POP H XRA A MOV M,A ;CLEAR BUFFER OFFSET RET ;------------------------------------------------------ ; ; READ RECORD/WRITE RECORD PRIMITIVES ; READ: CALL GTFCB ;GET ADDR OF FCB LDA $CPMRF ;CP/M 1.X OR 2.X MOV C,A ;RANDOM READ FUNCTION JMP IOCALL WRITE: CALL GTFCB ;GET ADDR OF FCB LDA $CPMWF ;CP/M 1.X OR 2.X MOV C,A ;RANDOM WRITE FUNCTION IOCALL: CALL BDOS ;DO APPROPRIATE FUNCTION PUSH PSW ;SAVE ERROR RESULT CALL GTREC ;POINT TO RECORD NUMBER INR M ;UPDATE SEQUENTIAL JNZ POPART ; RECORD NUMBER INX H INR M POPART: POP PSW ;RESTORE ERROR RET PAGE ;------------------------------------------------------ ; ; CALL OPEN(UNIT #,FILENAME,DRIVE #) ; ENTRY OPEN EXT $IOINIT OPEN: LDA $LUNTB ;GET MAX LUN DCR A CMP M ;OUT OF RANGE? JC LUNOVF ;YES, LUN TOO LARGE. MOV A,M ;FETCH LUN STA $UN ;SET IT UP PUSH D ;SAVE REGISTERS PUSH B ;SAVE FILPTR CALL $IOINIT ;INITIALIZE IF NOT ALREADY DONE CALL GTMODE ORA A ;ALLOCATED? CP ALCBUF ;NO, ALLOCATE POP B CALL GTFCB XCHG POP D ;[DE]=NAME PTR LDAX B ;GET DRIVE # MOV M,A ;STORE DRIVE # MVI B,11 ;COPY FILE NAME TO FCB FILLOP: LDAX D ORA A ;ZERO BYTE? JZ FILLEN ;YES, LEAVE REST AS BEFORE INX D INX H MOV M,A DCR B ;FINISHED MOVING NAME? JNZ FILLOP ;NO, DO REST FILLEN: LDA $UN ;GET UNIT # ADD A ;*2 FOR TABLE INDEX MVI D,0 MOV E,A LXI H,$LUNTB ;INDEX INTO LUN TABLE DAD D LXI B,DSKDRV ;REPLACE CURRENT LUNTB ENTRY MOV M,B ; WITH ADDRESS OF DISK DRIVER DCX H ; DISPATCH ADDRESS MOV M,C RET END