;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ; ; ; ; ; ; MRS SOURCE ; ; ; version 2.6 ; ; ; Copyright 1983 OCCO inc. ; ; ; ; ;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ; ; ; ; MRS CONSTANTS ; ; MRSENT: EQU 0E000H ;STARTING ADDRESS OF MRS BIOS: EQU 0F000H ;STARTING ADDRESS OF BIOS USER: EQU 00100H ;USER STARTING ADDRESS VERSON: EQU 0026H ;VERSION 2.6 SCRSIZ: EQU 23 ;CONSOLE SCREEN SIZE JMP: EQU 0C3H ;JUMP INSTRUCTION RST0: EQU 0C7H ;RESTART 0 INSTRUCTION FCB1: EQU 0005CH ;1ST USER FCB FCB2: EQU 0006CH ;2ND USER FCB CMDLIN: EQU 0007FH ;USER COMMAND LINE ADDRESS LGLCD: EQU 81 ;LEGAL CODES (2*40+1) ; ; MRS STATUS BYTE BIT DEFINITION ; CNOUT: EQU 0 ;CONSOLE OUTPUT ENABLE PECHO: EQU 1 ;PRINTER OUTPUT ENABLE SHALT: EQU 2 ;SCREEN HALT ENABLE LDZERO: EQU 3 ;LEADING ZERO FLAG DSKRD: EQU 4 ;DISK READ/WRITE FLAG FCBFLG: EQU 5 ;FCB CURRENT/TOTAL FLAG USRDIO: EQU 6 ;USER DISK I/O REQUEST LVREC: EQU 7 ;LOGICAL/VIRTUAL RECORD FLAG ; ; DISK DRIVE STATUS BIT DEFINITION ; ALOFLG: EQU 0 ;ALLOCATION FLAG WRPFLG: EQU 1 ;WRITE PROTECT FLAG CSTRSZ: EQU 2 ;CLUSTER# SIZE FLAG ; ; ; CONSOLE CHARACTERS ; LINFED: EQU 0AH ;LINE FEED CARRET: EQU 0DH ;CARRAGE RETURN SPACE: EQU 20H ;SPACE DELETE: EQU 7FH ;DELETE-RUBOUT BAKSPC: EQU 08H ;BACKSPACE TAB: EQU 09H ;TAB CNTRL: EQU 5EH ;CONTROL CHAR INDICATOR CNTRLC: EQU 03H ;CONTROL-C = SYSTEM RESET CNTRLP: EQU 10H ;CONTROL-P = PRINTER OUTPUT ENABLE CNTRLQ: EQU 11H ;CONTROL-Q = PRINTER OUTPUT DISABLE CNTRLR: EQU 12H ;CONTROL-R = VECTOR TO PROM CONTROL CNTRLS: EQU 13H ;CONTROL-S = SCROLL HALT ENABLE CNTRLT: EQU 14H ;CONTROL-T = SCROLL HALT DISABLE CNTRLU: EQU 15H ;CONTROL-U = MOVE USER MEMORY CNTRLV: EQU 16H ;CONTROL-V = SYNC. DISABLE BATCH MODE CNTRLW: EQU 17H ;CONTROL-W = RESTART USER PROGRAM ; ;********************************************************************** ; ; MRS BIOS addressing definition ; ;********************************************************************** ; ; COLDB: EQU BIOS+0 ;COLD BOOT WARMB: EQU BIOS+3 ;WARM BOOT CONSTA: EQU BIOS+6 ;INPUT CONSOLE STATUS (RETURNED IN 'A') CONIN: EQU BIOS+9 ;GET CONSOLE CHARACTER (RETURNED IN 'A') CONOUT: EQU BIOS+12 ;WRITE TO CONSOLE (FROM 'C') PRNTOT: EQU BIOS+15 ;PRINTER OUTPUT (FROM 'C') PNCHOT: EQU BIOS+18 ;PUNCH OUTPUT (FROM 'C') READIN: EQU BIOS+21 ;READER INPUT (RETURNED IN 'A') DSKHOM: EQU BIOS+24 ;HOME DRIVE HEAD SELDSK: EQU BIOS+27 ;SELECT DISK (FROM 'C') SELTRK: EQU BIOS+30 ;SELECT TRACK (FROM 'C') SELSEC: EQU BIOS+33 ;SELECT SECOR (FROM 'C') SELBUF: EQU BIOS+36 ;SELECT DMA BUFFER (FROM 'BC') RDDSK: EQU BIOS+39 ;READ FROM DISK WRDSK: EQU BIOS+42 ;WRITE TO DISK LSTSTA: EQU BIOS+45 ;GET PRINTER STATUS STRAN: EQU BIOS+48 ;TRANSLATE LOGICAL TO PHYSICAL SECTOR ; ;********************************************************************** ; ; MRSIO jump table: used by MRS to access the I/O exclusively ; ;********************************************************************** ; ; ; ORG MRSENT ; ; OSENT: JP ENTOS ;MRS ENTRY POINT CBOOT: JP COLDB ;COLD BOOT ; WBOOT: JP WARMB ;WARM BOOT ; CSTAT: CALL SAVREG ;SAVE REGISTERS CALL CONSTA ;INPUT CONSOLE STATUS (RETURNED IN 'A') JP GETREG ;RESTORE USER REGISTERS ; CIN: CALL SAVREG ;SAVE REGISTERS CALL CONIN ;GET CONSOLE CHARACTER (RETURNED IN 'A') JP GETREG ;RESTORE USER REGISTERS ; COUT: CALL SAVREG ;SAVE REGISTERS CALL CONOUT ;WRITE TO CONSOLE (FROM 'C') JP GETREG ;RESTORE USER REGISTERS ; LOUT: CALL SAVREG ;SAVE REGISTERS CALL PRNTOT ;PRINTER OUTPUT (FROM 'C') JP GETREG ;RESTORE USER REGISTERS ; POUT: CALL SAVREG ;SAVE REGISTERS CALL PNCHOT ;PUNCH OUTPUT (FROM 'C') JP GETREG ;RESTORE USER REGISTERS ; RIN: CALL SAVREG ;SAVE REGISTERS CALL READIN ;READER INPUT (RETURNED IN 'A') JP GETREG ;RESTORE USER REGISTERS ; HOME: CALL SAVREG ;SAVE REGISTERS CALL DSKHOM ;HOME DRIVE HEAD JP GETREG ;RESTORE USER REGISTERS ; SETDSK: CALL SAVREG ;SAVE REGISTERS CALL SELDSK ;SELECT DISK (FROM 'C') EX (SP),HL ;SAVE DPH ADDRESS IN HL JP GETREG ;RESTORE USER REGISTERS ; SETTRK: CALL SAVREG ;SAVE REGISTERS CALL SELTRK ;SELECT TRACK (FROM 'C') JP GETREG ;RESTORE USER REGISTERS ; SETSEC: CALL SAVREG ;SAVE REGISTERS CALL SELSEC ;SELECT SECOR (FROM 'C') JP GETREG ;RESTORE USER REGISTERS ; SETBUF: CALL SAVREG ;SAVE REGISTERS CALL SELBUF ;SELECT DMA BUFFER (FROM 'BC') JP GETREG ;RESTORE USER REGISTERS ; READ: CALL SAVREG ;SAVE REGISTERS CALL RDDSK ;READ FROM DISK JP GETREG ;RESTORE USER REGISTERS ; WRITE: CALL SAVREG ;SAVE REGISTERS CALL WRDSK ;WRITE TO DISK JP GETREG ;RESTORE USER REGISTERS ; LSTAT: CALL SAVREG ;SAVE REGISTERS CALL LSTSTA ;GET PRINTER STATUS (RETURNED IN 'A') JP GETREG ;RESTORE USER REGISTERS ; SECTRA: CALL SAVREG ;SAVE REGISTERS CALL STRAN ;TRANSLATE LOGICAL SECTOR TO PHYSICAL EX (SP),HL ;SAVE SECTOR# IN HL JP GETREG ;RESTORE USER REGISTERS ; ; SAVE USER REGISTERS ; SAVREG: EX (SP),IY ;GET PC & SAVE IY PUSH IX PUSH DE PUSH BC PUSH HL PUSH IY RET ; ; RESTORE USER REGISTERS ; GETREG: POP HL POP BC POP DE POP IX POP IY RET ; ;********************************************************************** ; ; MRS entry point: save user registers ; check for illegal request code ; get routine address from address tables ; vector to requested routine ; ;********************************************************************** ; ; ; ENTOS: LD (USRHL),HL ;SAVE USER REGISTERS LD (USRDE),DE LD (USRBC),BC LD (USRIX),IX LD (USRIY),IY LD (USRSP),SP LD SP,STAK+64 ;INIT STACK PUSH AF POP IY LD (USRF),IY LD IX,SYSTAT ;SYSTEM STATUS ARRAY LD IY,ADRT1 ;1ST ADDR TABLE SLA C ;CHECK MSB AND DOUBLE OFFSET JR NC,OSENT1 ;NOT AN ENHANCED CODE LD IY,ADRT2 ;YES - USE 2ND ADDR TABLE OSENT1: LD A,C ;GET CODE CP LGLCD ;LEGAL CODE ? JP NC,ILLGL ;NO LD B,0 ADD IY,BC ;ADDR=BASE+OFFSET LD C,(IY+0) ;GET ROUTINE ADDRESS LD B,(IY+1) LD IY,RTRN ;RETURN ADDR PUSH IY ;ONTO STACK PUSH BC ;ROUTINE ADDR LD BC,(USRBC) ;RESTORE USER REGISTERS LD IY,(USRDE) ;FCB OR CONSOLE BUFFER RET ;VECTOR TO ROUTINE ; ;********************************************************************** ; ; return to user: restore user registers ; return to user through user stack ; ;********************************************************************** ; ; RTRN: LD HL,(USRF) ;RESTORE USER 'AF' PUSH HL POP AF LD HL,(USRHL) ;AND REST OF USER REGISTERS LD DE,(USRDE) LD BC,(USRBC) LD IX,(USRIX) LD IY,(USRIY) LD SP,(USRSP) RET ; ;********************************************************************** ; ; MRS user interface: write MRS prompt ; check for BATCH operation ; get command line ; check for MRS supervisor commands ; format user command file name to system FCB ; find & format 1st two file names ; read in user command file ; set MRS parameters ; vector to user program ; ;********************************************************************** ; ; MONIT: LD SP,OSENT ;USE USER STACK SPACE LD A,(CURDRV) ;GET CURRENT DRIVE# OR A,40H ;ADD ASCII BITS LD (PRMPT),A ;ADD TO PROMPT LINE LD DE,PRMPT ;PROMPT ADDRESS CALL WRBUF ;WRITE OUT PROMPT ; LD A,(PRGCDE) ;GET BATCH CODE OR A,A ;BATCH MODE RUNNING? JR Z,MONIT1 ;NO LD HL,BTHCMD ;YES-SETUP COMMAND LINE LD DE,CMDLIN LD BC,80 LDIR JR EXCMD ;EXECUTE BATCH COMMAND ; MONIT1: LD DE,CMDLIN ;COMMAND BUFFER ADDRESS LD A,80 ;MAX # OF CHAR'S LD (DE),A LD C,10 ;OS REQ CODE CALL OSENT ;GET COMMAND LINE LD A,LINFED ;ECHO LINE FEED CALL CHROUT ;WRITE LF ; EXCMD: LD SP,OSENT ;REINIT STACK FOR USER ENTRY POINT LD A,(CMDLIN+2) ;GET 1ST CMD CHAR OR A,A ;ANY INPUT? JR Z,MONIT ;NO ; CP A,CNTRLR ;BOOT COMMAND? JP Z,CBOOT ;YES-GOTO COLD BOOT ; CP A,CNTRLW ;RESTART USER PROGRAM? JR NZ,EXCMD1 ;NO-CONTINUE LD HL,0 ;YES-FIRST CLEAR COMMAND LINE LD (CMDLIN+1),HL ;CHARACTER COUNT & LAST CHARACTER JP MONITI ;RESTART USER PROGRAM ; EXCMD1: CP A,CNTRLU ;MOVE MEMORY? JR NZ,MONIT3 ;NO LD HL,OSENT-2001H ;MOVE USER MEMORY LD DE,OSENT-1 ;UP 8K BYTES LD BC,OSENT-2001H LDDR JP MONIT ; MONIT3: LD HL,CMDLIN+2 ;1ST CHAR ADDRESS LD DE,SYSFCB ;OS FCB LD C,134 ;OS CODE CALL OSENT ;FORMAT 1ST WORD LD A,(SYSFCB+1) ;GET 1ST CHAR OF WORD CP A,SPACE ;DISK SPEC ONLY? JR NZ,MONIT4 ;NO LD A,(SYSFCB) ;YES-GET DISK SPEC CALL CHKDRV ;CHECK FOR VALID DRIVE# LD (CURDRV),A ;NOW CURRENT DRIVE# JP MONIT ; MONIT4: LD DE,CMDLIN+2 ;MOVE CMD LINE LD BC,80 ;OVER 1ST WORD LDIR LD HL,(USRHL) ;GET NEXT CHAR ADDRESS LD DE,-129 ;GET 1ST WORD POSITION ADD HL,DE LD A,(CMDLIN+1) ;GET CMD LINE LENGTH SUB A,L ;GET NEW LINE LENGTH LD (CMDLIN+1),A ;SET NEW CMD LINE LENGTH ; LD HL,NEWFCB ;INIT USER FCB LD DE,FCB1 LD BC,12 LDIR LD HL,NEWFCB ;INIT OTHER USER FCB LD DE,FCB2 LD BC,12 LDIR ; LD HL,CMDLIN+2 ;INIT CHARACTER POINTER LD DE,FCB1 ;INIT FCB POINTER LD (TEMP3),DE MONIT8: LD A,(HL) ;GET NEXT CHAR OR A,A ;END OF LINE? JR Z,MONITE ;YES-START PROGRAM CP A,'/' ;NO-SWITCHES? JR Z,MONITS ;YES-SKIP SWITCHES CALL CHRTST ;TEST CHAR TYPE JR NZ,MONIT0 ;CHAR = FILE TYPE INC HL ;ELSE-BUMP POINTER JR MONIT8 ;AND CONTINUE FILE SEARCH ; MONITS: INC HL ;FIND NEXT SEPARATOR CHAR LD A,(HL) ;GET CHAR CALL CHRTST ;TEST CHAR TYPE JR NZ,MONITS ;LOOP IF NOT SEPARATOR JR MONIT8 ;ELSE START CONTINUE ; MONIT0: LD DE,(TEMP3) ;GET FCB POINTER LD C,134 ;OS FORMAT CODE CALL OSENT ;FORMAT FILE NAE LD A,(TEMP3) ;GET LSB'S OF FCB POINTER CP A,FCB2 ;2ND FCB USED? JR Z,MONITE ;YES-LOAD USER PROGRAM ADD A,16 ;NO-BUMP FCB POINTER LD (TEMP3),A JR MONIT8 ;& CONTINUE LINE SCAN ; MONITE: LD (IX+57),'C' ;SET USER EXT TO "COM" LD (IX+58),'O' LD (IX+59),'M' LD A,(SYSFCB) ;GET DISK# OR A,A ;CURRENT DISK? JR NZ,MONITF ;NO LD A,(CURDRV) ;YES-USE CURRENT DISK# LD (SYSFCB),A MONITF: LD DE,SYSFCB ;OPEN USER FILE LD C,15 CALL OSENT AND A,80H ;FILE FOUND? JR Z,MONITG ;YES DEC (IX+48) ;NO-TRY NEXT DISK BIT 7,(IX+48) ;ALL DISKS TRIED? JR Z,MONITF ;NO-TRY AGAIN LD (IX+3),8 ;TRIED ALL DISKS-SET RESET CODE JP RESET ;RESET SYSTEM MONITG: LD A,RST0 ;INIT 1ST USER INSTRUCTION LD (USER),A ;IN CASE NO PROGRAM READ LD HL,USER ;INIT DISK BUFFER ADDRESS LD (USRBF),HL MONITH: LD DE,SYSFCB ;READ NEXT RECORD LD C,20 CALL OSENT LD DE,128 ;INCR DISK BUFFER ADDRESS ADD HL,DE LD (USRBF),HL OR A,A ;ANYTHING READ? JR Z,MONITH ;YES-CONTINUE READ LOOP ; MONITI: LD HL,80H ;INIT DATA BUFFER POINTER LD (USRBF),HL LD (IX+3),0 ;INIT RESET CODE LD SP,USER ;INIT USER STACK POINTER JP USER ;VECTOR TO USER PROGRAM ; ;********************************************************************** ; ; MRS reset routine: initialize lower memory ; reset steered I/O to console ; write reset message ; kill BATCH operations if error ; reset disk system ; vector to MRS user interface ; ;********************************************************************** ; ; RESET: LD IX,SYSTAT ;SYSTEM STATUS ARRAY LD SP,STAK+64 ;SYSTEM STACK LD A,JMP ;INIT BOTTOM OF MEMORY LD (0),A ;WITH JUMP VECTORS LD (5),A LD (38H),A LD HL,WARMB ;WARM BOOT VECTOR LD (1),HL LD HL,OSENT ;OS CALL VECTOR LD (6),HL LD HL,RSTVCT ;RESTART VECTOR LD (39H),HL SET 0,(IX+0) ;ENABLE CONSOLE OUTPUT RES 1,(IX+0) ;DISABLE PRINTER OUTPUT LD DE,MSG ;WRITE CRLF CALL WRBUF LD A,(RSTCD) ;GET RESET CODE CP A,2 ;ERROR? JR C,RESET2 ;NO LD IY,(USRSP) ;YES-GET USER PC LD A,(IY+0) ;GET PC LSB'S LD (MSGE+14),A ;STORE IN MESSAGE LD A,(IY+1) ;PC MSB'S LD (MSGE+12),A LD DE,MSGE ;1ST PART OF ERROR MESSAGE CALL WRBUF ;WRITE TO CONSOLE LD (IX+4),0 ;KILL BATCH OPERATION ; RESET2: LD E,(IX+3) ;GET RESET CODE LD D,0 SLA E ;DOUBLE CODE# LD IY,MSGTAB ;MESSAGE TABLE ADD IY,DE ;GET ADDRESS OF MESSAGE LD E,(IY+0) LD D,(IY+1) CALL WRBUF ;WRITE MESSAGE TO CONSOLE LD DE,MSG ;WRITE CRLF CALL WRBUF CALL DSKRST ;RESET DISK SYSTEM LD (IX+3),0 ;CLEAR RESET CODE LD HL,0 ;RESET ^C ADDRESS LD (CADDR),HL JP MONIT ;GO TO USER MONITOR ; ;********************************************************************** ; ; illegal user request code: set reset code ; init reset message with call code ; vector to MRS reset routine ; ;********************************************************************** ; ; ILLGL: LD (IX+3),3 ;SET RESET CODE LD A,(USRBC) ;GET OS REQ. CODE LD (MSG3+21),A ;SET INTO MESSAGE JP RESET ;********************************************************************** ; ; unimplemented MRS request: init warning message with call code ; write warning message to console ; return to user ; ;********************************************************************** ; ; WARN: LD A,C ;GET OS REQ. CODE LD (MSGW+33),A ;SET INTO MESSAGE LD DE,MSGW ;WRITE WARNING JP WRBUF ;& RETURN ;********************************************************************** ; ; restart vector: started if cpu executes an "FF" opcode ; set reset code ; fall through to MRS reset routine ; ;********************************************************************** ; ; RSTVCT: LD A,6 ;SET RESET CODE LD (RSTCD),A JP RESET ;RESET SYSTEM ; ;********************************************************************** ; ; set MRS control-C routine address from user register DE ; ;********************************************************************** ; ; CNTRC: LD (CADDR),DE ;STORE USER ADDRESS RET ;********************************************************************** ; ; set BATCH code: user register A gets current code ; new code set from user register E ; ;********************************************************************** ; ; SRBAT: LD A,(PRGCDE) ;GET OLD CODE LD (USRA),A ;GIVE TO USER LD (IX+4),E ;SAVE NEW CODE RET ;********************************************************************** ; ; read/set user code: if user register E=-1 ; user register A gets current code ; ; if user register E<>-1 ; new user code = user register E ; ;********************************************************************** ; ; USRCD: LD A,E ;GET NEW USER CODE CP A,-1 ;READ CODE ? JR NZ,USRCD2 ;NO-CONTINUE LD A,(USRCOD) ;YES-GET CURRENT CODE LD (USRA),A ;GIVE TO USER USRCD2: LD (USRCOD),A ;SET NEW CODE RET ; ;********************************************************************** ; ; user register A = byte from memory location 3 ; ;********************************************************************** ; ; RDIO: LD A,(3) ;GET I/O BYTE LD (USRA),A ;GIVE TO USER RET ;********************************************************************** ; ; memory location 3 = user register E ; ;********************************************************************** ; ; WRIO: LD A,E ;GET I/O BYTE LD (3),A ;SET IN SYSTEM RET ;********************************************************************** ; ; set the system date in MRS status array ; ;********************************************************************** ; ; WRDAT: LD (IX+83),B ;STORE SYSTEM DAY LD (IX+84),D ;STORE SYSTEM MONTH LD (IX+85),E ;STORE SYSTEM YEAR RET ; ;********************************************************************** ; ; read the system date from the MRS status array ; ;********************************************************************** ; ; RDDAT: LD A,(SYSDAY) ;GIVE USER DAY LD (USRA),A LD D,(IX+84) ;GIVE USER MONTH LD E,(IX+85) ;& YEAR LD (USRDE),DE RET ;********************************************************************** ; ; set the system time in the MRS status array ; ;********************************************************************** ; ; WRTIM: LD (IX+86),B ;STORE SYSTEM SECOND LD (IX+87),D ;STORE SYSTEM MINUTE LD (IX+88),E ;STORE SYSTEM HOUR RET ;********************************************************************** ; ; read the system time from the MRS status array ; ;********************************************************************** ; ; RDTIM: LD A,(SYSSEC) ;GIVE USER SECOND LD (USRA),A LD D,(IX+87) ;GIVE USER MINUTE LD E,(IX+88) ;& HOUR LD (USRDE),DE RET ; ;********************************************************************** ; ; give the MRS version number to user register HL ; ;********************************************************************** ; ; VERSN: LD HL,VERSON ;CURRENT VERSION # LD (USRHL),HL ;GIVE TO USER LD (IX-1),L ;REGISTER 'A' FOR COMPATABILITY RET ;********************************************************************** ; ; multiply: multiply user registers HL,DE ; user register DE gets 16 lsb's of answer ; ;********************************************************************** ; ; MULT: CALL MULTP ;MULTIPLY LD (USRDE),HL ;GIVE ANSWER TO USER RET ;********************************************************************** ; ; divide: divide user registers HL/DE ; user register HL=quotient ; user register DE=remainder ; ;********************************************************************** ; ; DIVID: LD BC,(USRHL) ;GET DIVIDEND CALL DIVD ;DIVIDE LD (USRDE),HL ;REMAINDER LD (USRHL),BC ;QUOTENT RET ; ;********************************************************************** ; ; read MRS I/O status: user register A = 2 lsb's of MRS status byte ; ;********************************************************************** ; ; REDIO: LD A,(SYSTAT) ;GET STATUS BYTE AND A,03H ;KEEP 2 LSB'S LD (USRA),A ;GIVE TO USER RET ;********************************************************************** ; ; set I/O status: 2 lsb's of user register E ; go to MRS status byte ; ;********************************************************************** ; ; SETIO: LD A,E ;GET I/O STATUS BITS AND A,03H ;KEEP 2 LSB'S ONLY LD E,A ;& SAVE THEM LD A,(SYSTAT) ;GET STATUS BYTE AND A,0FCH ;REMOVE 2 LSB'S OR A,E ;INSERT 2 NEW BITS LD (SYSTAT),A ;RESTORE STATUS BYTE RET ;********************************************************************** ; ; get reader byte: user register A = byte from reader ; ;********************************************************************** ; ; READR: CALL RIN ;GET CHARACTER LD (USRA),A ;GIVE TO USER RET ; ;********************************************************************** ; ; punch output: punch output gets user register E ; ;********************************************************************** ; ; PUNCH: LD C,E ;CHARACTER TO OUTPUT REGISTER JP POUT ;WRITE TO PUNCH ;********************************************************************** ; ; output to printer: printer gets user register E ; ;********************************************************************** ; ; PRTC: LD C,E ;GET CHARACTER CALL LOUT ;PRINT IT JP CHRIN ;CHECK FOR ^C ;********************************************************************** ; ; direct console I/O: if user register E=-1 ; user register A=0 if no character from console ; user register A=character from console ; ; if user register E<>-1 ; console gets user register E ; ;********************************************************************** ; ; DIRIO: LD C,E ;CHAR. TO OUTPUT REGISTER LD A,E ;GET CHARACTER CP A,0FEH ;OUTPUT CHARACTER? JP C,COUT ;YES-OUTPUT & RETURN CALL CSTA ;GET CONSOLE INPUT STATUS LD (USRA),A ;GIVE TO USER BIT 0,E ;CHARACTER=FEH? RET Z ;YES-RETURN WITH STATUS ONLY OR A,A ;CHARACTER=FFH - ANY INPUT? RET Z ;NO-DONE CALL CIN ;YES-GET CHARACTER FROM CONSOLE LD (USRA),A ;AND GIVE TO USER RET ; ;********************************************************************** ; ; get console input status: user register A = status ; ;********************************************************************** ; ; CSTA: CALL CSTAT ;GET STATUS LD (USRA),A ;GIVE TO USER RET ;********************************************************************** ; ; get console character: user register A = console input ; write input to console ; ;********************************************************************** ; ; RDCE: CALL RDC ;GET CHARACTER JP CHROUT ;ECHO CHARACTER ;********************************************************************** ; ; console input: user register A = console input ; ;********************************************************************** ; ; RDC: CALL CHRIN ;GET CHARACTER JR Z,RDC LD (USRA),A ;GIVE TO USER RET ;********************************************************************** ; ; console output: console gets user register E ; using MRS console supervisor ; ;********************************************************************** ; ; WRTC: LD A,E ;GET CHARACTER JP CHROUT ;WRITE IT ; ;********************************************************************** ; ; get console line: put console input into buffer ; check for delete character ; check for control character (special echo) ; terminate with carrage return or ; when buffer full ; ;********************************************************************** ; ; RDBUF: LD B,(IY+0) ;LOOP COUNT=MAX COUNT INC DE ;SET POINTER TO INC DE ;1ST CHARACTER RDBF2: CALL CHRIN ;GET CHARACTER JR Z,RDBF2 LD (DE),A ;INSERT CHAR INTO BUFFER ; CP A,DELETE ;DELETE CHAR? JR NZ,RDBF4 LD A,(IY+0) ;GET BUFFER SIZE CP A,B ;ANY CHAR IN BUFFER? JR Z,RDBF2 ;NO-IGNORE CHAR LD A,DELETE ;ECHO CHARACTER CALL CHROUT INC B ;DEC CHAR COUNT DEC DE ;BACKUP 1 CHARACTER LD A,(DE) ;GET CHAR CP A,SPACE ;CONTROL CHAR? LD A,DELETE ;2 DELETES IF CONTROL CALL C,CHROUT ;SEND IF CONTROL CHAR JR RDBF2 ;& CONTINUE ; RDBF4: CP A,CARRET ;CR? JR NZ,RDBF6 ;CONTINUE IF NOT CALL CHROUT ;ECHO IT XOR A,A ;LAST CHAR=0 LD (DE),A JR RDBFE ; RDBF6: CP A,SPACE ;CONTROL CHAR? JR NC,RDBF8 ;NO PUSH AF ;YES-SAVE CHAR LD A,CNTRL ;SENT CONTROL INDICATOR CALL CHROUT POP AF ;GET CHAR OR A,40H ;MAKE READABLE CHAR ; RDBF8: CALL CHROUT ;SEND CHAR INC DE ;BUMP POINTER DJNZ RDBF2 ;CONTINUE LOOP ; RDBFE: LD A,(IY+0) ;GET MAX COUNT SUB A,B ;ACTUAL=MAX-LOOP COUNT LD (IY+1),A ;STORE IN BUFFER RET ; ;********************************************************************** ; ; console output: write buffer to console ; using console supervisor ; check for HEX character format ; check for DECIMAL character format ; check for control characters (special output) ; terminate output on "$" character ; ;********************************************************************** ; ; WRBUF: LD A,(DE) ;GET CHARACTER CP A,'$' ;END OF BUFFER? RET Z ;YES-DONE ; CP A,80H ;HEX CHARACTER FOLLOWING? JR NZ,WRBUF2 ;NO-CONTINUE INC DE ;GET BYTE LD A,(DE) CALL HEXOUT ;WRITE IN HEX INC DE ;POINTER TO NXT CHAR JR WRBUF ;CONTINUE ; WRBUF2: CP A,82H ;DECIMAL# ? JR NZ,WRBUF4 ;NO PUSH HL ;YES-SAVE REGISTER EX DE,HL INC HL LD E,(HL) ;GET# INC HL LD D,(HL) EX DE,HL ;HL=# CALL DECOUT ;WRITE OUT # POP HL ;RESTORE REGISTER INC DE ;BUMP POINTER JR WRBUF ;CONTINUE LOOP ; WRBUF4: CALL CHROUT ;WRITE CHARACTER INC DE ;BUMP POINTER JR WRBUF ; ;********************************************************************** ; ; MRS console supervisor: character in register A ; expand tabs to 8 spaces ; keep track of cursor line position ; implement screen halt function ; implement delete function ; steer console/printer output ; ;********************************************************************** ; ; CHROUT: CP A,TAB ;TAB CHAR? JR NZ,CHROT2 CHROT0: LD A,SPACE ;WRITE SPACES CALL CHOUT ;TO CONSOLE LD A,(CONPOS) ;CHECK FOR 8TH POSITION AND A,07H JR NZ,CHROT0 RET CHROT2: CP A,CARRET ;CARRAGE RETURN? JR NZ,CHROT4 LD (IX+1),0 ;CURSOR TO FIRST POSITION JP CHOUT ;WRITE OUT CR CHROT4: CP A,LINFED ;LINE FEED? JR NZ,CHROT6 CALL CHOUT ;WRITE IT OUT CALL CHRIN ;CHECK FOR CONTROL CHAR DEC (IX+2) ;DECR CONSOLE LINE # RET NZ ;DONE IF NOT BOTTOM OF SCREEN BIT 2,(IX+0) ;HALT ENABLED? RET Z ;NO-DONE LD (IX+2),SCRSIZ ;INIT LINE COUNT CHROT5: CALL CHRIN ;WAIT FOR CHARACTER JR Z,CHROT5 RET ;THEN-DONE CHROT6: CP A,DELETE ;RUBOUT CHARACTER? JR NZ,CHOUT ;NO-WRITE OUT CHAR DEC (IX+1) ;SET CURSOR BACK DEC (IX+1) LD A,BAKSPC ;BACKUP CURSOR CALL CHOUT LD A,SPACE ;DELETE CHARACTER CALL CHOUT LD A,BAKSPC ;BACK TO LAST POSITION CHOUT: LD C,A ;SETUP REGISTER BIT 0,(IX+0) ;CONSOLE OUTPUT ENABLED? CALL NZ,COUT ;WRITE TO CONSOLE IF ENABLED BIT 1,(IX+0) ;PRINTER OUTPUT ENABLED? CALL NZ,LOUT ;PRINT IF YES LD A,C ;GET CHAR CP A,SPACE ;CONTROL CHAR? RET C ;YES-DONE INC (IX+1) ;BUMP CURSOR POSITION RET ; ;********************************************************************** ; ; hex output: translate byte in register A to two HEX ; characters and write through console supervisor ; ;********************************************************************** ; ; HEXOUT: PUSH AF ;SAVE CHARACTER SRL A ;GET 4 MSB'S SRL A SRL A SRL A CALL HXOUT0 ;WRITE 4 MSB'S POP AF ;GET 4 LSB'S HXOUT0: AND A,0FH ;KEEP 4 LSB'S OR A,30H ;ADD ASCII CP A,3AH ;NUMERICAL? JP C,CHOUT ;YES ADD A,7 ;CONVERT TO ALPHA JP CHOUT ;WRITE & RETURN ; ;********************************************************************** ; ; decimal output: convert register HL to an unsigned ; decimal number and write to output ; through console supervisor ; ;********************************************************************** ; ; DECOUT: PUSH IY ;SAVE REGISTERS PUSH DE PUSH BC LD IY,DECTAB ;CONVERSION TABLE SET 3,(IX+0) ;LEADING '0' INDICATOR LD B,5 ;5 DIGITS MAX DEC2: LD C,0 ;INIT DIGIT VALUE LD E,(IY+0) ;GET TABLE VALUE LD D,(IY+1) DEC4: INC C ;BUMP DIGIT VALUE OR A,A ;CLEAR CARRY FLAG SBC HL,DE ;#=#-TABLE VALUE JR NC,DEC4 ;LOOP WHILE #>TABLE VALUE ADD HL,DE ;RESTORE LAST# DEC C ;GET ACTUAL DIGIT# JR NZ,DEC6 ;IF DIGIT<>0 BIT 3,(IX+0) ;ANY OUTPUT YET? JR NZ,DEC8 ;NO DEC6: RES 3,(IX+0) ;SET OUTPUT FLAG LD A,C ;GET DIGIT OR A,30H ;ADD ASCII BITS CALL CHROUT ;WRITE OUT DEC8: LD DE,2 ;BUMP TABLE POINTER ADD IY,DE DJNZ DEC2 ;LOOP THRU ALL OF TABLE LD A,'0' ;LAST DIGIT BIT 3,(IX+0) ;ANY OUTPUT YET? CALL NZ,CHROUT ;NO-WRITE OUT '0' POP BC ;RESTORE REGISTERS POP DE POP IY RET ; ;********************************************************************** ; ; console input: if no input return with register A=0 ; if console input present ; check for supervisor commands ; if input is supervisor command register A=0 ; else register A= console input character ; ;********************************************************************** ; CHRIN: CALL CSTAT ;GET INPUT STATUS OR A,A ;ANY INPUT? RET Z ;NO-DONE CALL CIN ;GET CONSOLE CHARACTER ; CP A,CNTRLC ;CONTROL-C? JR NZ,CHRIN2 ;NO-CONTINUE LD A,(CADDR+1) ;GET ^C ADDRESS MSB'S INC A ;-1 (DISABLED) ? RET Z ;DONE IF DISABLED LD (IX+3),2 ;SET RESET CODE FOR ^C LD HL,(CADDR) ;TEST FOR SYSTEM RESET LD A,L OR A,H JP Z,RESET ;SYSTEM RESET IF ADDRESS=0 LD (IX+3),0 ;USER FUNCTION-NO RESET CODE USED LD SP,(USRSP) PUSH HL ;NEW USER RETURN ADDRESS LD (USRSP),SP LD SP,STAK+64 ;RESET SYSTEM STACK CALL DSKRST ;RESET DISK SYSTEM JP RTRN ;VECTOR TO USER ROUTINE CHRIN2: CP A,CNTRLS ;START SCREEN HALT? JR NZ,CHRIN4 SET 2,(IX+0) ;ENABLE HALT LD (IX+2),1 ;STOP AFTER NEXT LINE XOR A,A ;NO CHAR INPUT RET CHRIN4: CP A,CNTRLT ;STOP SCREEN HALT? JR NZ,CHRIN6 RES 2,(IX+0) ;DISABLE SCREEN HALT XOR A,A ;NO CHAR INPUT RET CHRIN6: CP A,CNTRLP ;PRINTER ECHO ENABLED? JR NZ,CHRIN8 SET 1,(IX+0) ;ENABLE ECHO XOR A,A ;NO CHAR INPUT RET CHRIN8: CP A,CNTRLQ ;PRINTER ECHO DISABLE? JR NZ,CHRIN9 ;NO RES 1,(IX+0) ;DISABLE ECHO XOR A,A ;NO CHAR INPUT RET CHRIN9: CP A,CNTRLV ;BATCH DISABLE? RET NZ ;NO-RETURN CHARACTER LD (IX+4),0 ;CLEAR BATCH CODE XOR A,A ;NO CHAR INPUT RET ; ;********************************************************************** ; ; set user disk buffer address ; ;********************************************************************** ; ; BUFSET: LD (USRBF),DE ;SET NEW ADDRESS RET ;********************************************************************** ; ; home drive head: select drive ; home head ; ;********************************************************************** ; ; HOMHD: LD A,B ;GET DISK# CALL CHKDRV ;SELECT DRIVE CALL HOME ;HOME HEAD RET ; ;********************************************************************** ; ; select current disk: check for valid disk# ; set new disk# into MRS status array ; ;********************************************************************** ; ; DSKSEL: LD A,E ;GET DISK# INC A CALL CHKDRV ;SELECT DISK LD (CURDRV),A ;NOW CURRENT DRIVE RET ;********************************************************************** ; ; get current disk#: user register A = disk# ; ;********************************************************************** ; ; CURDSK: LD A,(CURDRV) ;GET CURRENT DISK# DEC A LD (USRA),A ;GIVE TO USER RET ; ;********************************************************************** ; ; set disk log byte: for each disk logged in ; set corresponding bit ; in user register HL ; ;********************************************************************** ; ; LOGIN: LD DE,DSKSTA+15 ;DISK STATUS ARRAY POINTER LD B,16 ;TOTAL ARRAY SIZE LOGINA: LD A,(DE) ;GET DISK STATUS BYTE RRA ;ALLOCATION BYTE TO CARRY FLAG ADC HL,HL ;THEN TO HL DEC DE ;BUMP POINTER DJNZ LOGINA ;CONTINUE SCAN LD (USRHL),HL ;GIVE USER VECTOR LD (IX-1),L ;REGISTER 'A' FOR COMPATABILITY RET ; ;********************************************************************** ; ; compute record#: random record number= ; FCB extent# * 128 + sequential record pointer ; ; store answer in FCB ; clear msb's of 3 byte record number ; ;********************************************************************** ; ; COMREC: LD L,0 ;INIT RECORD# LD D,0 LD H,(IY+12) ;GET EXTENT# LD E,(IY+32) ;GET RECORD POINTER BIT 7,E ;END OF EXTENT? JR Z,COMRCA LD E,0 ;YES-SET TO NEXT EXTENT INC H COMRCA: SRL H ;HL=EXTENT# * 128 RR L ADD HL,DE ;HL=RANDOM#=EXTENT*128+POINTER LD (IY+33),L ;SET IN FCB LD (IY+34),H LD (IY+35),0 ;CLEAR MSB'S OF RECORD# RET ; ;********************************************************************** ; ; compute file size: clear user FCB ; scan directory for highest numbered FCB ; initialize FCB with directory entry ; compute record number of last record+1 ; ;********************************************************************** ; ; COMSIZ: LD HL,12 ;GET ADDRESS OF FCB DATA ARRAY ADD HL,DE PUSH HL ;DESTINATION REGISTER+ POP DE ;SOURCE REGISTER+1 INC DE LD BC,23 ;DATA ARRAY+POINTERS CLEARED LD (HL),0 LDIR ; LD A,(IY+0) ;GET DISK# CALL SCHFST ;INITIALIZE FOR SEARCH COMSZ1: LD DE,(USRDE) ;FCB ADDRESS CALL SCHNXT ;FIND ENTRY JR NZ,COMSZ2 ;EXIT LOOP IF NOT FOUND BIT 0,(IX+16) ;VALID ENTRY? JR NZ,COMSZ1 ;NO-TRY AGAIN LD A,(IX+28) ;GET EXTENT# CP A,(IY+12) ;GREATER EXTENT# ? JR C,COMSZ1 ;NO-CONTINUE SEARCH LD HL,ENTRY+1 ;YES-TRANSFER ENTRY TO FCB LD DE,(USRDE) ;FCB ADDRESS INC DE ;SKIP DISK DESIGNATOR LD BC,31 ;TOTAL ENTRY-1ST BYTE LDIR JR COMSZ1 ;CONTINUE DIRECTORY SCAN ; COMSZ2: LD A,(IY+15) ;SET RECORD POINTER LD (IY+32),A ;TO LAST RECORD# +1 LD A,(IY+12) ;INIT FCB TOTAL EXTENT# LD (IY+14),A LD (IY+13),0 ;INIT RESERVED BYTE JP COMREC ;NOW COMPUTE RECORD# ; ;********************************************************************** ; ; format file name: check for disk designator ; check for universal characters ; check for name extension ; ;********************************************************************** ; FORMAT: LD HL,NEWFCB ;INIT FCB LD BC,12 LDIR LD HL,(USRHL) ;ADDRESS OF DISK SPECIFIER LD DE,(USRDE) ;ADDRESS OF FCB LD A,(HL) ;GET DISK SPECIFIER AND A,0FH ;KEEP LSB'S LD (DE),A ;STORE TO FCB INC HL ;ADDR OF SEPARATOR LD A,(HL) INC HL ;ADDRESS OF NAME CP A,':' ;SEPARATOR THERE? JR Z,FORMT2 XOR A,A ;NO-SET DISK# TO CURRENT DISK LD (DE),A ;USE IN FCB LD HL,(USRHL) ;ADDRESS OF NAME FORMT2: LD BC,08FFH ;MAX CHAR'S IN NAME INC DE ;ADDR OF NAME IN FCB CALL FORMT6 ;TRANSFER NAME LD A,(HL) ;GET NEXT CHAR CP A,'.' ;EXTENSION STARTED? JR NZ,FORMT4 PUSH HL ;SAVE ADDRESS OF NAME LD HL,(USRDE) ;CALCULATE ADDR OF EXTENSION LD DE,9 ;IN FCB ADD HL,DE EX DE,HL ;RESET REGISTERS POP HL INC HL ;POINT TO 1ST CHAR OF EXTENSION LD BC,03FFH ;MAX CHAR'S IN EXTENSION CALL FORMT6 ;TRANSFER EXTENSION FORMT4: LD (USRHL),HL ;SAVE ADDR OF TERMINATOR RET FORMT6: LD A,(HL) ;GET CHAR CP A,'*' ;UNIVERSAL CHAR? JR Z,FORMT8 CALL CHRTST ;TEST FOR CHAR RET Z ;DONE IF TERMINATOR CHAR LDI ;ELSE TRANSFER CHAR DJNZ FORMT6 ;CONTINUE TRANSFER RET FORMT8: LD A,'?' ;SET REST OF CHARACTERS IN NAME LD (DE),A ;TO UNIVERSAL INC DE DJNZ FORMT8 INC HL ;POINT TO NEXT CHAR RET ; ;********************************************************************** ; ; test for file name separators ; ;********************************************************************** ; ; CHRTST: CP A,'.' ;PERIOD? RET Z ;'Z' FLAG SET FOR SEPARATOR CHAR CP A,',' ;COMMA? RET Z CP A,'=' ;EQUALS? RET Z CP A,'/' ;SLASH? RET Z CP A,':' ;COLON? RET Z CP A,';' ;SEMICOLON? RET Z CP A,' ' ;SPACE? RET NC ;CHAR IF >SPACE BIT 7,A ;RESET 'Z' FLAG RET ; ;********************************************************************** ; ; get disk allocation vector: user HL=allocation vector address ; ;********************************************************************** ; ; ALOVCT: XOR A,A ;USE CURRENT DISK# CALL CHKDRV ;SELECT & ALLOCATE DISK LD HL,(ALV) ;GET ADDRESS OF ALLOCATION VECTOR LD (USRHL),HL ;& GIVE TO USER RET ;********************************************************************** ; ; read/write logical record: set read/write parameter ; test for legal record# ; setup disk I/O parameters ; read/write disk ; ;********************************************************************** ; ; RDLOG: SET 4,(IX+0) ;SET READ PARAMETER JR LRECIO WRLOG: RES 4,(IX+0) ;SET WRITE PARAMETER LRECIO: LD A,B ;GET DISK# CALL CHKDRV ;SELECT DISK SET 7,(IX+0) ;SET LOGICAL RECORD FLAG LD DE,(USRDE) ;GET LOGICAL RECORD# LD BC,(USRBF) ;& USER BUFFER ADDRESS CALL RCDIO ;DO DISK I/O LD (USRA),A ;GIVE USER RESULT RES 7,(IX+0) ;SET RECORD FLAG FOR VIRTUAL RET ;********************************************************************** ; ; get disk parameter array address ; ;********************************************************************** ; ; GETDPB: XOR A,A ;USE CURRENT DISK# CALL CHKDRV ;SELECT DISK LD HL,(DPBA) ;GIVE DPB ADDRESS TO USER LD (USRHL),HL RET ; ;********************************************************************** ; ; reset disk system: for each active drive: ; reset allocation & write protect bits ; compute the allocation vector size ; set current disk to "A" ; set user buffer to default ; ;********************************************************************** ; ; DSKRST: LD HL,DSKSTA ;CLEAR DISK STATUS ARRAY LD DE,DSKSTA+1 LD BC,15 LD (HL),0 LDIR LD (IX+90),16 ;DESELECT ALL DISKS LD HL,80H ;RESET USER DISK BUFFER LD (USRBF),HL LD (IX-1),0 ;SET USER RETURN PARAMETER RET ; ;********************************************************************** ; ; mark directory entries with protect flag as in FCB ; ;********************************************************************** ; ; SETFLG: LD A,(DE) ;INIT FOR FILE SEARCH CALL SCHFST SETFGA: LD DE,(USRDE) ;SEARCH FOR ENTRY CALL SCHNXT JR NZ,SETFGB ;NONE FOUND-DONE BIT 0,(IX+16) ;ENTRY USED? JR NZ,SETFGA ;NO-CONTINUE SEARCH SLA (IX+25) ;SETUP FLAG BIT IN ENTRY LD A,(IY+9) ;GET FLAG IN FCB RLA ;PUT FLAG INTO CARRY RR (IX+25) ;PUT FLAG INTO ENTRY CALL UPDAT ;WRITE ENTRY TO DISK INC (IX+12) ;BUMP FILE COUNT JR SETFGA ;CONTINUE SEARCH SETFGB: LD A,(FILCNT) ;GET FILE COUNT LD (USRA),A ;GIVE TO USER RET ;********************************************************************** ; ; file name search: initialize search parameters ; find 1st occurence of file name in directory ; ;********************************************************************** ; ; SRCH: EX DE,HL ;HL=FILE NAME ADDRESS LD DE,SYSFCB ;XFER FILE NAME LD BC,12 ;TO SYSTEM FCB LDIR LD A,(SYSFCB) ;GET DISK# CALL SCHFST ;INIT FOR DISK SEARCH SRCHN: LD DE,SYSFCB ;POINT TO FILE NAME CALL SCHNXT ;FIND ENTRY WITH FILE NAME LD (USRA),A ;GIVE USER FOUND PARAMETER RET NZ ;NO FILE FOUND LD HL,(DIRBUF) ;XFER DIRECTORY BLOCK LD DE,(USRBF) ;TO USER BUFFER LD BC,128 LDIR LD A,(ENTNUM) ;GIVE USER ENTRY# LD (USRA),A LD HL,ENTRY ;& ENTRY ADDRESS LD (USRHL),HL RET ;********************************************************************** ; ; write directory entry back to disk directory ; ;********************************************************************** ; ; UPDAT: LD L,(IX+15) ;GET ENTRY# LD H,0 ADD HL,HL ;MULTIPLY BY 32 ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL LD DE,(DIRBUF) ;BASE ADDRESS OF DIRECTORY BLOCK ADD HL,DE ;HL = ADDRESS OF ENTRY IN BLOCK LD DE,ENTRY ;MOVE ENTRY TO DISK BUFFER EX DE,HL LD BC,32 LDIR LD E,(IX+14) ;GET DIRECTORY LD D,0 ;LOGICAL RECORD# LD BC,(DIRBUF) ;DIRECTORY BUFFER ADDRESS RES 4,(IX+0) CALL RCDIO ;WRITE DIRECTORY BLOCK RET ; ;********************************************************************** ; ; rename file: find directory entries with file name ; substitute new file name for old ; write directory entries back to disk ; ;********************************************************************** ; ; RENAM: LD A,(DE) ;GET DISK# CALL SCHFST ;INIT SEARCH PARAMETERS RENAM2: LD DE,(USRDE) ;GET ADDRESS OF NAME CALL SCHNXT ;SEARCH FOR FILE JR NZ,RENAMD ;IF FILE NOT FOUND BIT 0,(IX+16) ;ENTRY USED? JR NZ,RENAM2 ;NO BIT 7,(IX+25) ;FILE PROTECTED? PUSH AF ;SAVE FLAG INC (IX+12) ;INCR FILE COUNT LD HL,(USRDE) ;CALCULATE ADDRESS LD DE,17 ;OF NEW FILE NAME ADD HL,DE LD DE,ENTRY+1 ;CURRENT FILE NAME ADDRESS LD BC,11 ;CHARACTERS/NAME LDIR ;TRANSFER NEW NAME POP AF ;GET PROTECT FLAG JR Z,RENAM3 ;SKIP IF UNPROTECTED SET 7,(IX+25) ;ELSE SET PROTECT FLAG RENAM3: CALL UPDAT ;WRITE OUT TO DISK JR RENAM2 ;CONTINUE RENAMD: LD A,(FILCNT) ;GIVE FILE COUNT TO USER LD (USRA),A RET ; ;********************************************************************** ; ; create file: delete file from directory ; find open directory entry ; initialize FCB ; copy FCB to directory entry ; write directory entry to disk ; ;********************************************************************** ; ; CREAT: CALL DELET ;DELETE FILE FIRST LD A,(IY+0) ;GET DISK# CALL SCHFST ;INIT FOR FILE SEARCH CREAT2: LD DE,GENRAL ;SEARCH FOR GENERAL FILE CALL SCHNXT LD (USRA),A ;GIVE USER SEARCH PARAMETER RET NZ ;DONE IF NO FILE BIT 0,(IX+16) ;ENTRY IN USE? JR Z,CREAT2 ;CONTINUE IF YES LD HL,(USRDE) ;COMPUTE DATA ARRAY LD DE,12 ;ADDRESS IN FCB ADD HL,DE PUSH HL ;& SETUP TO INIT FCB POP DE INC DE LD BC,20 LD (HL),0 LDIR ;BY WRITING ZEROS TO ARRAY LD HL,(USRDE) ;NOW TRANSFER FCB TO ENTRY LD DE,ENTRY LD BC,32 LDIR LD (IX+16),0 ;ENTRY MARKED USED CALL UPDAT ;WRITE TO DISK LD A,(ENTNUM) ;GET ENTRY# LD (USRA),A ;GIVE TO USER RET ; ;********************************************************************** ; ; delete file: find all directory entries which match file name ; mark entries as unused ; write entries back to disk ; ;********************************************************************** ; ; DELET: LD A,(DE) ;GET DISK# CALL SCHFST ;INIT FOR FILE SEARCH DELET2: LD DE,(USRDE) ;GET ADDRESS OF FILE NAME CALL SCHNXT ;FIND FILE JR NZ,DELET4 ;FILE NOT FOUND BIT 0,(IX+16) ;ENTRY USED? JR NZ,DELET2 ;NO LD (IX+3),9 ;PROTECT RESET CODE BIT 7,(IX+25) ;FILE PROTECTED? JP NZ,RESET ;YES-RESET LD (IX+3),0 ;NO-CLEAR RESET CODE INC (IX+12) ;INCR FILE COUNT LD (IX+16),0E5H ;MARK FILE AS UNUSED CALL UPDAT ;UPDATE DIRECTORY JR DELET2 ;CONTINUE DELET4: LD A,(FILCNT) ;GET FILE COUNT LD (USRA),A ;GIVE TO USER RES 0,(IX+98) ;DEALLOCATE DISK RET ;********************************************************************** ; ; write zero's: init user buffer with zero's ; write file record to disk (random record) ; ;********************************************************************** ; ; WRZRO: LD HL,(USRBF) ;USER BUFFER ADDRESS LD DE,(USRBF) INC DE ;NOW FILL BUFFER WITH 0'S LD BC,127 LD (HL),0 LDIR LD DE,(USRDE) ;RESTORE USER REGISTER JP WRFIL ;NOW WRITE AS RANDOM RECORD ; ;********************************************************************** ; ; open file: find 1st extent of file in directory ; copy entry to FCB ; init FCB pointer ; ;********************************************************************** ; ; OPEN: LD (IY+12),0 ;SET FCB FOR 1ST EXTENT OPENA: CALL FNDFIL ;FIND FILE LD (USRA),A ;GIVE SEARCH PARA. TO USER RET NZ ;DONE IF NOT FOUND LD HL,ENTRY+1 ;INIT FCB WITH ENTRY LD DE,(USRDE) INC DE LD BC,31 LDIR LD A,(IY+12) ;INIT FCB EXTENT TOTAL LD (IY+14),A LD (IY+12),0 ;INIT CURRENT EXTENT RES 7,(IY+11) ;CLEAR THE WRITE BIT LD (IY+32),0 ;INIT NEXT RCD# LD A,(ENTNUM) ;GIVE ENTRY# TO USER LD (USRA),A RET ;********************************************************************** ; ; close file: find directory entry corresponding to FCB ; copy FCB to entry ; write entry to disk directory ; ;********************************************************************** ; ; CLOSE: LD (IX-1),0 ;INIT USER RETURN CODE BIT 7,(IY+11) ;FCB WRITTEN FROM? RET Z ;NO-NO NEED TO CLOSE IT RES 7,(IY+11) ;CLEAR WRITE BIT FOR DIRECTORY LD A,(IY+14) ;PUT TOTAL EXTENT INTO LD (IY+12),A ;CURRENT EXTENT BYTE LD (IY+13),0 ;CLEAR FCB RESERVED BYTES LD (IY+14),0 CALL FNDFIL ;SEARCH FOR FILE LD (USRA),A ;RETURN PARAMETER TO USER RET NZ ;DONE IF FILE NOT FOUND LD HL,(USRDE) ;INIT ENTRY WITH USER FCB LD DE,ENTRY LD BC,32 LDIR LD (IX+16),0 ;ENTRY MARKED USED CALL UPDAT ;WRITE ENTRY TO DISK LD A,(ENTNUM) ;GIVE USER ENTRY# LD (USRA),A RET ; ;********************************************************************** ; ; write protect disk: set write protect bit in disk status byte ; ;********************************************************************** ; ; WRPRT: XOR A,A ;CURRENT DISK# CALL CHKDRV ;GET STATUS BYTE ADDRESS SET 1,(IX+98) ;PROTECT DISK RET ;********************************************************************** ; ; get read only byte: for each disk with write protect bit set: ; set corresponding bit in user register HL ; ;********************************************************************** ; ; ROVCT: LD DE,DSKSTA+15 ;STATUS ARRAY POINTER LD B,16 ;ARRAY SIZE ROVCTA: LD A,(DE) ;GET STATUS BYTE RRA ;MOVE WRITE PROTECT BIT RRA ;INTO CARRY ADC HL,HL ;THEN INTO HL DEC DE ;BUMP POINTER DJNZ ROVCTA ;CONTINUE SCAN LD (USRHL),HL ;GIVE VECTOR TO USER LD (IX-1),L ;REGISTER 'A' FOR COMPATABILITY RET ; ;********************************************************************** ; ; sequential file access : set read/write flag ; load parameter registers ; check record pointer ; execute cluster I/O ; increment record pointer ; ;********************************************************************** ; ; WRREC: RES 6,(IX+0) ;WRITE - SET WRITE FLAG JR SEQIO ;START SEQUENTIAL ACCESS ; RDREC: SET 6,(IX+0) ;READ - SET READ FLAG ; SEQIO: LD L,(IY+32) ;GET RECORD POINTER LD H,(IY+12) ;GET EXTENT BIT 7,L ;RECORD POINTER OVER RANGE? JR Z,SEQIOA ;NO LD L,0 ;YES-SET TO START EXTENT INC H ;SET TO NEXT EXTENT SEQIOA: CALL CSTRIO ;EXECUTE CLUSTER I/O INC (IY+32) ;BUMP RECORD POINTER RET ; ;********************************************************************** ; ; random record file access : set read/write flag ; get random record pointer ; convert pointer to extent/rcd pointer ; execute cluster I/O ; ;********************************************************************** ; ; WRFIL: RES 6,(IX+0) ;WRITE - SET WRITE FLAG JR RMDIO ;START RANDOM FILE ACCESS ; RDFIL: SET 6,(IX+0) ;READ - SET READ FLAG ; RMDIO: LD L,(IY+33) ;GET RANDOM FILE POINTER LD H,(IY+34) ADD HL,HL ;H = EXTENT# = RND PNTR / 128 SRL L ;L = RCD PNTR = RMD(RND PNTR / 128) CALL CSTRIO ;EXECUTE CLUSTER I/O RET ; ;********************************************************************** ; ; cluster I/O : select disk ; check for valid FCB ; if FCB not valid : ; close current FCB ; setup new FCB ; open new FCB in directory ; if no new FCB in directory : ; create entry in directory ; get cluster value ; check cluster value & get new one as required ; compute logical record# from cluster + rcd pointer ; do disk I/O ; ;********************************************************************** ; ; CSTRIO: LD (IX+7),H ;SAVE NEW EXTENT# LD (IX+8),L ;& NEW RCD PNTR LD A,(IY+0) ;SELECT DISK CALL CHKDRV ; CSTRA: LD A,(TMPEXT) ;SET NEW EXTENT# TO MAX VALUE OR A,(IX+111) ;BY ADDING EXTENT MASK LD C,A LD A,(IY+14) ;SET TOTAL EXTENT# TO MAX VALUE OR A,(IX+111) ;THE SAME WAY CP A,C ;SAME FCB? JR Z,CSTRB ;YES ; CALL CLOSE ;CLOSE CURRENT EXTENT BIT 7,(IX-1) ;CLOSE SUCCESSFUL? LD (IX-1),3 ;RETURN PARAMETER RET NZ ;DONE IF NOT CLOSED LD A,(TMPEXT) ;ELSE INIT FCB LD (IY+12),A ;FOR NEW EXTENT CALL OPENA ;& OPEN NEW EXTENT BIT 7,(IX-1) ;NEW FCB FOUND? JR Z,CSTRB ;YES BIT 6,(IX+0) ;NO-THIS A READ? LD (IX-1),1 ;EOF RETURN PARAMETER RET NZ ;YES-EOF-DONE ; CSTRA1: LD (IX-1),5 ;DISK FULL RETURN PARAMETER LD A,(IY+0) ;INIT FOR ENTRY SEARCH CALL SCHFST CSTRA2: LD DE,GENRAL ;SEARCH EACH ENTRY CALL SCHNXT ;IN THE DIRECTORY RET NZ ;DONE IF DIRECTORY FULL BIT 0,(IX+16) ;ENTRY IN USE? JR Z,CSTRA2 ;YES-CONTINUE SEARCH LD HL,(USRDE) ;INIT FCB LD DE,12 ADD HL,DE ;BY CLEARING DATA ARRAY PUSH HL POP DE INC DE LD BC,19 LD (HL),0 LDIR LD A,(TMPEXT) ;USE CURRENT EXTENT# LD (IY+12),A ;AS TOTAL FOR ENTRY LD HL,(USRDE) ;XFER FCB TO ENTRY LD DE,ENTRY LD BC,32 LDIR LD (IX+16),0 ;MARK ENTRY AS USED CALL UPDAT ;WRITE ENTRY TO DIRECTORY ; CSTRB: LD H,(IX+7) ;INIT FCB WITH CURRENT EXTENT# LD (IY+12),H LD L,(IX+8) ;& RECORD POINTER LD (IY+32),L LD D,(IY+14) ;GET TOTAL EXTENT# LD E,(IY+15) ;GET TOTAL RECORD COUNT RES 5,(IX+0) ;SET FLAG = CUR >= TOTAL OR A,A ;CLEAR CARRY SBC HL,DE ;CUR >= TOTAL ? JR NC,CSTRC ;YES SET 5,(IX+0) ;NO-SET FLAG FOR CUR < TOTAL ; CSTRC: LD A,(IY+12) ;COMPUTE CLUSTER ADDRESS AS AND A,(IX+111) ; ADDR = (EXT and EXM) LD C,A JR Z,CSTRC2 ;SKIP NEXT IF NO EXTENT OFFSET LD A,7 SUB A,(IX+109) ; * (2 ** (7-BSH)) JR Z,CSTRC2 ;SKIP NEXT IF TOTAL EXTENT USED LD B,A CSTRC1: SLA C DJNZ CSTRC1 CSTRC2: LD B,(IX+109) ; + RCDPNTR/(2 ** BSH) LD A,(IY+32) CSTRC3: SRL A DJNZ CSTRC3 ADD A,C AND A,0FH ;KEEP ANSWER TO <16 LD HL,(USRDE) ; + FCB ADDRESS LD DE,16 ; + ARRAY OFFSET ADD HL,DE LD E,A ADD HL,DE LD (TEMP),HL ;SAVE ADDRESS LD E,(HL) ;GET CSTR# BIT 2,(IX+98) ;1 BYTE/CLUSTER? JR Z,CSTRC4 ;YES INC HL ;NO-GET 2ND BYTE LD D,(HL) CSTRC4: LD (TEMP1),DE ;SAVE CLUSTER# ; CSTRD: LD A,E ;CSTR# = 0 ? OR A,D JR NZ,CSTRF ;NO LD (IX-1),1 ;YES-SET RETURN PARAMETER BIT 6,(IX+0) ;THIS A READ? RET NZ ;YES-EOF-DONE ; CSTRE: LD IY,(ALV) ;ALLOCATION VECTOR POINTER LD HL,0 ;INIT CLUSTER# LD DE,8 ;INIT CLUSTER INCR (8/BYTE) LD BC,(ALSIZ) ;ALLOCATION VECTOR SIZE CSTRE1: LD A,(IY+0) ;GET ALLOCATION BYTE CP A,-1 ;ANYTHING OPEN? JR NZ,CSTRE2 ;YES INC IY ;NO-BUMP POINTER ADD HL,DE ;& CLUSTER# DEC BC ;DECR COUNTER LD A,C OR A,B ;END OF VECTOR? JR NZ,CSTRE1 ;NO-CONTINUE SCAN CSTRE2: SLA A ;FIND OPEN CLUSTER IN BYTE JR NC,CSTRE3 ;EXIT LOOP WHEN FOUND INC HL ;ELSE BUMP CLUSTER# JR CSTRE2 ;& CONTINUE CSTRE3: LD (TEMP1),HL ;SAVE CLUSTER# LD DE,(DSM) ;GET MAX CLUSTER# INC DE OR A,A ;CLEAR CARRY SBC HL,DE ;CLUSTER# IN RANGE? LD (IX-1),5 ;SET RETURN PARAMETER LD IY,(USRDE) ;RESTORE FCB POINTER RET NC ;DONE IF NO MORE ROOM ON DISK LD DE,(TEMP1) ;NOW ALLOCATE CLUSTER CALL SETMAP SET 7,(IY+11) ;MARK FCB FOR LATER CLOSE OPERATION LD HL,(TEMP) ;STORE CLUSTER# IN FCB LD (HL),E BIT 2,(IX+98) ;1 BYTE/CLUSTER ? JR Z,CSTRF ;YES INC HL ;NO-STORE MSB'S LD (HL),D ; CSTRF: BIT 6,(IX+0) ;READ? JR Z,CSTRG ;NO-SKIP TO NEXT SECTION LD (IX-1),1 ;SET RETURN PARAMETER BIT 5,(IX+0) ;CUR >= TOTAL (EOF) RET Z ;YES-EOF-DONE SET 4,(IX+0) ;SET SYSTEM READ/WRITE FLAG JR CSTRH ;SKIP NEXT SECTION ; CSTRG: LD (IX+3),9 ;PROTECT RESET CODE BIT 7,(IY+9) ;FILE PROTECTED? JP NZ,RESET ;YES-RESET SYSTEM LD (IX+3),0 ;NO-CLEAR RESET CODE RES 4,(IX+0) ;SET SYSTEM READ/WRITE FLAG ; CSTRH: LD HL,(TEMP1) ;GET CSTR# LD B,(IX+109) ;LOGICAL RECORD# = CSTRH1: ADD HL,HL ;CSTR# * (2 ** BSH) DJNZ CSTRH1 LD A,(IY+32) ; + (RCD PNTR and BLM) AND A,(IX+110) LD E,A LD D,0 ADD HL,DE EX DE,HL ;SETUP REGISTERS LD BC,(USRBF) CALL RCDIO ;& DO DISK I/O LD (USRA),A ;RETURN PARAMETER TO USER BIT 5,(IX+0) ;CUR >= TOTAL ? RET NZ ;NO-DONE LD A,(IY+12) ;YES-TOTAL GETS CURRENT VALUES LD (IY+14),A ;EXTENT LD A,(IY+32) ;RECORD POINTER INC A ;TOTAL=CURRENT+1 LD (IY+15),A RET ; ;********************************************************************** ; ; multiply: HL=product of HL * DE ; DE,B=0 ; ;********************************************************************** ; ; MULTP: LD B,16 ;16 BITS PUSH HL ;SAVE MULTIPLIER LD HL,0 ;INIT PRODUCT MULTP2: ADD HL,HL ;SHIFT PRODUCT LEFT EX (SP),HL ;GET MULTIPLIER ADD HL,HL ;TEST NEXT MSB EX (SP),HL ;GET PRODUCT JR NC,MULTP4 ADD HL,DE ;IF BIT=1 MULTP4: DJNZ MULTP2 ;LOOP 16 TIMES POP DE ;MULTIPLIER OFF STACK RET ;********************************************************************** ; ; divide: HL=remainder BC/DE ; BC=quotient BC/DE ; ;********************************************************************** ; ; DIVD: LD HL,0 ;INIT 16 MSB'S OF DIVIDEND LD A,16 ;16 BIT LOOP COUNT DIVD2: SLA C ;CLEAR NEXT QUOTENT BIT RL B ;& LEFT SHIFT DIVIDEND ADC HL,HL PUSH HL ;SAVE DIVIDEND SBC HL,DE ;DIVIDEND:DIVISOR JR C,DIVD4 ;DIVIDEND