; ******** SOLOS OPERATING SYSTEM ******** ; ; PROCESSOR TECHNOLOGY CORP. ; EMERYVILLE, CALIFORNIA ; ; ; VERSION 1.3 ; RELEASE 3/27/77 ; ; ; ; ; ; THIS 2048 BYTE PROGRAM IS THE STANDARD SOL STAND ; ALONE OPERATING SYSTEM. IT IS CONFIGURED TO OPTIMIZE ; THE CONVENIENCE AND POWER OF THE SOL-20 AND ONE OR TWO ; CASSETTE RECORDERS IN STAND ALONE COMPUTER APPLICATIONS. ; ; ;COMMANDS: ; TE TERMINAL MODE ; DU SSSS EEEE DUMP (START ADDR END ADDR) ; EN SSSS ENTER HEX TO MEMORY ; EX SSSS EXECUTE ; GE FILENAME/U GET (U=TAPE UNIT 0 OR 1, DFLT=1) ; SA FNAME/U SSSS EEEE SAVE ON TAPE (UNIT 0 OR 1) ; XE FILENAME/U AUTO LOAD/EXECUTE ; CA CATALOG OF TAPE FILES ; CU LL SSSS CUSTOM COMMAND (LL=LABLE) ; SET TA N SET TAPE SPEED (N:0=FAST,1=SLOW) ; SET S=NN SET DISPLAY SPEED (O-->FF) ; SET I=N SET IN PSEUDO PORT (N=0 - 3) ; SET O=N SET OUT PSEUDO PORT (N=0 - 3) ; SET N=NN SET NULLS (N=0 - FF) ; SET CI SSSS SET CUSTOM INPUT DRIVER ADDR ; SET CO SSSS SET CUSTOM OUTPUT DRIVER ADDR ; SET XE SSSS SET AUTO-EXECUTE ADDRESS FOR TAPE SAVE ; SET TY NN SET FILE TYPE FOR TAPE HEADER ; SET CR NN OVERRIDE CRC ERRORS (FF=IGNORE ERRORS) ; ; ; PSEUDO PORTS: 0 = KEYBOARD/VIDEO ; 1 = SERIAL PORT ; 2 = PARALLEL PORT ; 3 = USER DEFINED (SET CI, SET CO) ; ; ; ORG 0C000H ; ; ; ; AUTO-STARTUP CODE ; START: DB 0 INIT: JMP STRTA ;SYSTEM RESTART ENTRY POINT ; ; ; ENTRY POINTS ; ; THESE JUMP POINTS ARE PROVIDED TO ALLOW COMMON ENTRY ; LOCATIONS FOR ALL VERSIONS OF SOLOS. THEY ARE USED ; EXTENSIVLY BY SOL SYSTEM PROGRAMS AND IT IS RECOMMENDED ; THAT USER ROUTINES ACCESS SOLOS THROUGH THESE POINTS. ; RETRN: JMP COMND ;RETURN TO SYSTEM ENTRY POINT FOPEN: JMP BOPEN ;FILE OPEN ENTRY FCLOS: JMP PCLOS ;FILE CLOSE ENTRY RDBYT: JMP RTBYT ;CASSETTE READ BYTE ENTRY WRBYT: JMP WTBYT ;CASSETTE WRITE BYTE ENTRY RDBLK: JMP RTAPE ;CASSETTE READ BLOCK ENTRY WRBLK: JMP WTAPE ;CASSETTE WRITE BLOCK ENTRY ; ; ; SYSTEM I/O ENTRY POINTS ; ; THESE ROUTINES PERFORM SYSTEM I/O ; THERE ARE TWO ENTRY TYPES: ; SINP/SOUT REG "A" WILL BE SET TO THE STANDARD ; SYSTEM PSEUDO PORT. ; AINP/AOUT REG "A" MUST BE SET BY THE USER AND ; WILL SPECIFY THE DESIRED PSEUDO PORT. ; ; THE FOLLOWING ARE THE PSEUDO PORTS: ; PORT DESCRIPTION ; ---- -------------------------------- ; 0 KEYBOARD WHEN INPUT, AND VDM WHEN OUTPUT ; 1 SERIAL I/O PORT ; 2 PARALLEL I/O PORT ; 3 USER DEFINED I/O PORT ; SOUT: LDA OPORT ;SOUT ENTRY POINT AOUT: JMP OUTPR ;AOUT ENTRY POINT SINP: LDA IPORT ;SINP ENTRY POINT AINP: EQU $ ;AINP ENTRY POINT ;******** END OF SYSTEM ENTRY POINTS ********* PUSH H ;THIS IS ACTUALLY AINP LXI H,ITAB ; ; ; THIS ROUTINE PROCESSES THE I/O REQUESTS BY DISPATCHING ; TO THE DRIVER REQUESTED IN REGISTER "A". ON ENTRY HL ; HAS THE PROPER DISPATCH TABLE. ; IOPRC: ANI 3 ;KEEP REGISTER "A" TO FOUR VALUES RLC ;COMPUTE ENTRY ADDRESS ADD L MOV L,A ;WE HAVE ADDRESS JMP DISPT ;DISPATCH TO IT ; ; ; ***** SOL SYSTEM I/O ROUTINES ***** ; ; ; THIS ROUTINE IS A MODEL OF ALL INPUT ROUTINES WITHIN ; SOLOS. EACH ROUTINE FIRST TESTS THE STATUS INPUT FOR ; DATA AVAILABLE. IF NO CHARACTERHAS BEEN RECEIVED THE ; ROUTINE RETURNS WITH THE ZERO FLAG SEG. OTHERWISE THE ; CHARACTER IS INPUT AND A RETURN MADE WITH THE CHARACTER ; IN THE ACCUMULATOR AND THE ZERO FLAG RESET. ; ; ; KEYBOARD INPUT DRIVER ; KSTAT: IN STAPT ;GET STATUS WORK CMA ;INVERT IT FOR PROPER RETURN ANI KDR ;TEST KEYBOARD BIT RZ ;ZERO IS NO CHARACTER RECEIVED ; IN KDATA ;GET CHARACTER RET ;GO BACK WITH IT ; ; ; THIS JUMP IS PART OF THE AUTO START UP CODE ; DB 0 ;VERIFY ADDR=C037 JMP INIT ;THIS SHOULD BE C038 ; ; ; JMP TABLE OUTPUT ROUTINES ; ; THIS ROUTINE SETS UP THE DISPATCH TABLE FOR OUTPUT ; ROUTINES. THE CHARACTER FOR OUTPUT IS IN REGISTER "B". ; OUTPUT IS MADE TO THE DRIVER POINTED TO BY THE REGISTER ; "A". THE DEVICE DRIVERS ARE DEFINED AS FOLLOWS: ; ; 0 - DISPLAY SCREEN ; 1 - SERIAL OUTPUT PORT ; 2 - PARALLEL OUTPUT PORT ; 3 - USER DEFINED OR ERROR FLAG ; ; ENTRY AT: SOUT SELECTS CURRENT OUTPUT DEVICE ; AOUT SELECTS DEVICE IN REGISTER "A" ; OUTPR: PUSH H LXI H,OTAB ;POINT TO OUTPUT TABLE JMP IOPRC ;AND DISPATCH TO OUTPUT ROUTINE ; ; ; ; SERIAL INPUT DRIVER ; SSTAT: IN SERST ;GET SERIAL STATUS WORD ANI SDR ;TEST FOR SERIAL DATA READY RZ ;FLAGS ARE SET ; IN SDATA ;GET DATA BYTE RET ;WE HAVE IT ; ; ; SERIAL DATA OUTPUT ; SDROT: IN SERST ;GET PORT STATUS RAL ;PUT HIGH BIT IN CARRY JNC SDROT ;LOOP UNTIL TRANSMITTER BUFFER IS EMPTY MOV A,B ;GET THE CHARACTER BACK OUT SDATA ;SEND IT OUT RET ;AND WE'RE DONE ; ; ; ; ; VIDEO DISPLAY ROUTINES ; ; ; THESE ROUTINES ALLOW FOR STANDARD VIDEO TERMINAL ; OPERATIONS. ON ENTRY, THE CHARACTER FOR OUTPUT IS IN ; REGISTER B AND ALL REGISTERS EXCEPT "A" AND FLAGS ARE ; UNALTERED ON RETURN. ; ; VDMOT: PUSH H ;SAVE MOST REGISTERS PUSH D PUSH B ; ; TEST IS ESC SEPUENCE HAS BEEN STARTED ; LDA ESCFL ;GET ESCAPE FLAG ORA A JNZ ESCS ;IF NON-ZERO GO PROCESS THE REST ; ; CHPCK: MOV A,B ;SAVE IN B...STRIP PARITY BEFORE SCREEN! ANI 7FH ;CLR PARITY TO LOCATE IN TBL MOV B,A ;KEEP IT W/OUT PARITY IN B TOO JZ GOBK ;DO A QUICK EXIT IF A NULL LXI H,TBL ;POINT TO SPECIAL SHARACTER TABLE CALL TSRCH ;GO PROCESS ; GOBACK: CALL VDADD ;GET SCREEN ADDRESS MOV A,M ;GET PRESENT CURSOR CHARACTER ORI 80H MOV M,A ;CURSOR IS BACK ON LHLD SPEED-1 ;GET DELAY SPEED INR L ;MAKE SURE IT IS NON-ZERO XRA A ;DELAY WILL END WHEN H=0 TIMER: DCX H ;TIMER DELAYS HERE CMP H ;DONE WITH DELAY YET JNZ TIMER ;KEEP DELAYING GOBK: POP B POP D ;RESTORE REGISTERS POP H RET ;EXIT FROM VDMOT ; NEXT: INX H INX H ; ; ; THIS ROUTINE SEARCHES THROUGH A SINGLE CHARACTER ; TABLE FOR A MATCH TO THE CHARACTER IN "B". IF FOUND ; A DISPATCH IS MADE TO THE ADDRESS FOLLOWING THE MATCHED ; CHARACTER. IF NOT FOUND THE CHARACTER IS DISPLAYED ON ; THE MONITOR. ; TSRCH: MOV A,M ;GET CHR FROM TABLE ORA A JZ CHAR ;ZERO IS THE LAST CMP B ;TEST THE CHR INX H ;POINT FORWARD JNZ NEXT PUSH H ;FOUND ONE...SAVE ADDRESS CALL CREM ;REMOVE CURSOR XTHL ;GET DISPATCH ADDRESS TO HL JMP DISPT ;DISPATCH NOW ; ; PUT CHARACTER TO SCREEN ; CHAR: MOV A,B ;GET CHARACTER CPI 7FH ;IS IT A DEL? RZ ;GO BACK IF SO ; ; ; OCHAR: EQU $ ;ACTUALLY PUT CHAR TO SCREEN NOW CALL VDADD ;GET SCREEN ADDRESS MOV M,B ;PUT CHR ON SCREEN ; LDA NCHAR ;GET CHARACTER POSITION CPI 63 ;END OF LINE? JC OK LDA LINE CPI 15 ;END OF SCREEN? JNZ OK ; ; END OF SCREEN...ROLL UP ONE LINE ; SCROLL: XRA A STA NCHAR ;BACK TO FIRST CHAR POSITION SROL: MOV C,A CALL VDAD ;CALCULATE LINE TO BE BLANKED XRA A CALL CLIN1 ;CLEAR IT LDA BOT INR A ANI 0FH JMP ERAS3 ; ; INCREMENT LINE COUNTER IF NECESSARY ; OK: LDA NCHAR ;GET CHR POSITION INR A ANI 3FH ;MOD 64 AND WRAP STA NCHAR RNZ ;DIDN'T HIT END OF LINE, OK PDOWN: EQU $ ;CURSOR DOWN ONE LINE HERE LDA LINE ;GET THE LINE COUNT INR A CURSC: ANI 0FH ;STORE THE NEW CUR: STA LINE ;STORE THE NEW RET ; ; ERASE SCREEN ; PERSE: LXI H,VDMEM ;POINT TO SCREEN MVI M,80H+' ' ;THIS IS THE CURSOR ; INX H ;BUMP 1ST ERAS1: EQU $ ;LOOPS HERE TO ERASE SCREEN MVI M,' ' ;BLANK IT OUT INX H ;NEXT MOV A,H ;SEE IF END OF SCREEN YET CPI 0D0H JC ERAS1 ;NO--KEEP BLANKING STC ;CARRY WILL SAY COMPLETE ERASE ; PHOME: MVI A,0 ;RESET CURSOR--CARRY=ERASE, ELSE HOME STA LINE ;ZERO LINE STA NCHAR ;LEFT SIDE OF SCREEN RNC ;IF NO CARRY, WE ARE DONE WITH HOME ; ERAS3: OUT DSTAT ;RESET SCROOL PARAMETERS STA BOT ;BEGINNING OF TEXT OFFSET RET ; ; CLINE: CALL VDADD ;GET CURRENT SCREEN ADDRESS LDA NCHAR ;CURRENT CURSOR POSITION CLIN1: CPI 64 ;NO MORE THAN 63 RNC ;ALL DONE MVI M,' ' ;ALL SPACED OUT INX H INR A JMP CLIN1 ;LOOP TO END OF LINE ; ; ; ROUTINE TO MOVE THE CURSOR UP ONE LINE ; PUP: LDA LINE ;GET LINE COUNT DCR A JMP CURSC ;MERGE TO HANDLE CURSOR ; ; MOVE CURSOR LEFT ONE POSITION ; PLEFT: LDA NCHAR DCR A PCUR: EQU $ ;CURSOR ON SAME LINE ANI 3FH ;LET CURSOR WRAP STA NCHAR ;UPDATED CURSOR RET ; ; CURSOR RIGHT ONE POSITION ; PRIT: LDA NCHAR INR A JMP PCUR ; ; ROUTINE TO CALCULATE SCREEN ADDRESS ; ; ENTRY AT: RETURNS: ; ; VDADD CURRENT SCREEN ADDRESS ; VDAD2 ADDRESS OF CURRENT LINE, CHAR "C" ; VDAD LINE "A", CHARACTER POSITION 'C' ; VDADD: LDA NCHAR ;GET CHARACTER POSITION MOV C,A ;'C' KEEPS IT VDAD2: LDA LINE ;LINE POSITION VDAD: MOV L,A ;INTO 'L' LDA BOT ;GET TEXT OFFSET ADD L ;ADD IT TO THE LINE POSITION RRC ;TIMES TWO RRC ;MADES FOUR MOV L,A ;L HAS IT ANI 3 ;MOD THREE FOR LATER ADI VDMEM SHR 8 ;LOW SCREEN OFFSET MOV H,A ;NOW H IS DONE MOV A,L ;TWIST L'S ARM ANI 0C0H ADD C MOV L,A RET ;H & L ARE NOW PERVERTED ; ; ROUTINE TO REMOVE CURSOR ; CREM: CALL VDADD ;GET CURRENT SCREEN ADDRESS MOV A,M ANI 7FH ;STRIP OFF THE CURSOR MOV M,A RET ; ; ROUTINE TO BACKSPACE ; PBACK: CALL PLEFT CALL VDADD ;GET SCREEN ADDRESS MVI M,' ' ;PUT A BLANK THERE RET ; ; ROUTINE TO PROCESS A CARRIAGE RETURN ; PCR: XRA A ;REWIND TO BEGINNING OF LINE ; ;ORIGINAL HAD 'CALL CLINE' INSTEAD OF 'XRA A' AS SHOWN ;ABOVE. THIS CAUSED DISK COMMANDS TO DISAPPEAR FROM THE ;SCREEN AS CP/M MUST OUTPUT TWO 'CR' CHARACTERS. ; JMP PCUR ;AND STORE THE NEW VALUE ; ; ROUTINE TO PROCESS A LINEFEED ; PLF: LDA LINE ;GET LINE COUNT INR A ANI 15 ;SEE IF IT WRAPPED AROUND JNZ CUR ;NO--NO NEED TO SCROLL JMP SROL ;YES--THEN SCROLL ; ; SET ESCAPE PROCESS FLAG ; PESC: MVI A,(-1) AND 0FFH STA ESCFL ;SET FLAG RET ; ; PROCESS ESCAPE SEQUENCE ; ESCS: CALL CREM ;REMOVE CURSOR CALL ESCSP ;PROCESS THE NEXT PART OF SEQUENCE JMP GOBACK ; ESCSP: LDA ESCFL ;GET ESCAPE FLAG CPI (-1) AND 0FFH ;TEST FLAG JZ SECOND ; ; PROCESS THIRD CHR OF ESC SEQUENCE ; LXI H,ESCFL MVI M,0 ;NO MORE PARTS TO THE SEQUENCE CPI 2 JC SETX ;SET X IF IS ONE JZ SETY ;SET Y IF IS TWO CPI 8 JZ STSPD ;SET NEW DISPLAY SPEED IF "8" CPI 9 JC OCHAR ;PUT IT ON THE SCREEN RNZ ; ; TAB ABSOLUTE TO VALUE IN REG B ; SETX: MOV A,B ;GET CHARACTER JMP PCUR ; ; SET CURSOR TO LINE "B" ; SETY: MOV A,B JMP CURSC ; ; ; PROCESS SECOND CHR OF ESC SEPUENCE ; SECOND: MOV A,B ;GET WHICH CPI 3 JZ CURET ;RETURN CURSOR PARAMETERS CPI 4 JNZ ARET2 ; ; ESC <4> RETURN ABSOLUTE SCREEN ADDRESS ; ARET: MOV B,H MOV C,L ;PRESENT SCREEN ADDRESS TO BC FOR RETURN ; ARET1: POP H ;RETURN ADDRESS POP D ;OLD B PUSH B PUSH H XRA A ARET2: STA ESCFL RET ; ; ; RETURN PRESENT SCREEN PARAMETERS IN "BC" ; CURET: LXI H,NCHAR MOV B,M ;CHARACTER POSITION INX H MOV C,M ;LINE POSITION JMP ARET1 ; ; ; ***** START UP SYSTEM ***** ; ; CLEAR SCREEN AND THE FIRST 256 BYTES OF GLOBAL RAM ; THEN ENTER THE COMMAND MODE ; STRTA: XRA A MOV C,A LXI H,SYSRAM ;CLEAR THR FIRST PAGE ; CLERA: MOV M,A INX H INR C JNZ CLERA ; LXI SP,SYSTP ;SET UP THE STACK FOR CALL CALL PERSE COMN1: XRA A OUT STAPT ;BE SURE TAPES ARE OFF STA OPORT STA IPORT ; ; ; ; ***** COMMAND MODE ***** ; ; ; THIS ROUTINE GETS AND PROCESSES COMMANDS ; COMND: LXI SP,SYSTP ;SET STACK POINTER LDA OPORT ;GET PORT PUSH PSW XRA A STA OPORT ;FORCE SCREEN OPERATIONS CALL PROMPT ;PUT PROMPT ON SCREEN CALL GCLIN ;GET COMMAND LINE POP PSW STA OPORT ;RESTORE DEFAULT PORT CALL COPRC ;PROCESS THE LINE JMP COMND ;OVER AND OVER ; ; ; ; THIS ROUTINE READS A COMMAND LINE ; FROM THE SYSTEM KEYBOARD ; ; C/R TERMINATES THE SWQUENCE ERASING ALL ; CHARS TO THE RIGHT OF THE CURSOR ; L/F TERMINATES THE SEQUENCE ; MODE RESTARTS THE COMMAND LINE ; GCLIN: CALL SINP ;READ INPUT DEVICE JZ GCLIN ANI 7FH ;CLEAR PARITY BIT JZ COMN1 ;THIS WAS A MODE (OR EVEN CTRL-@) MOV B,A CPI CR ;CARRIAGE RETURN JZ CLINE ;YES--DONE WITH LINE CPI LF ;LINE FEED RZ ;YES--DONE WITH LINE, LEAVE AS IS CPI 7FH ;DELETE CHR? JNZ CONT MVI B,BACKS ;REPLACE IT ; CONT: CALL SOUT JMP GCLIN ; ; ; FIND AND PROCESS COMMAND ; COPRC: CALL CREM ;REMOVE THE CURSOR MVI C,1 ;SET FOR CHARACTER POSITION CALL VDAD2 ;GET SCREEN ADDRESS XCHG LXI H,START ;MAKE SURE HL PT TO SOLOS START PUSH H ;SAVE IT FOR LATER DISPT CALL SCHR ;SCAN PAST BLANKS JZ ERR1 ;NO COMMAND? XCHG ;HL HAS FIRST CHR ; LXI D,COMTAB ;POINT TO COMMAND TABLE CALL FDCOM ;SEE IF IN PRIMARY COMMAND TABLE CZ FDCOU ;IF NOT, TRY CUSTOM TABLE NEXT DISPO: EQU $ ;HERE TO SEE IF ERROR OR DISP JZ ERR2 ;NOT VALID, ERROR INX D ;BUMP TO PTR OF RTN XCHG ;HL PT TO RTN ADDR ; ; ; THIS IS THE DISPATCH ROUTINE ; HL PT TO RTN ADDRESS, HL WILL BE RESTORED FROM STACK ; SO THAT HL ARE RESTORED BEFORE DISPATCH. ; DISPT: EQU $ ;OFF TO A ROUTINE MOV A,M ;LO ADDR INX H MOV H,M ;HI ADDR MOV L,A ;HL NOW COMPLETE DISP1: EQU $ ;HERE TO GO OFF TO HL XTHL ;XCHG HL W/HL ON STACK MOV A,L ;ALSO COPY HERE FOR SETS RET ;AND GO OFF TO THE RTN ; ; ; THIS ROUTINE SEARCHES THROUGH A TABLE, POINTED TO ; BY 'DE', FOR A DOUBLE CHARACTER MATCH OF THE 'HL' ; MEMORY CONTENT. IF NO MATCH IS FOUND THE SCAN ENDS ; WITH HL POINTING TO ORIGINAL VALUE AND ZERO FLAG SET. ; FDCOU: LXI D,CUTAB ;HERE TO SCAN CUSTOM TBL ONLY ; FDCOM: LDAX D ORA A ;TEST FOR TABLE END RZ ;NOT FOUND..COMMAND ERROR PUSH H ;SAVE START OF SCAN ADDRESS CMP M ;TEST FIRST CHR INX D JNZ NCOM ; INX H LDAX D CMP M ;NOW SECOND CHARACTER JNZ NCOM ;GOODNESS ; POP H ;RESTORE ORIGINAL SCAN ADDR ORA A ;SET NON-ZERO FLAG SAYING FOUND RET ;WITH NON-ZERO SET ; ; NCOM: INX D ;GO TO NEXT ENTRY INX D INX D POP H ;GET BACK ORIGINAL ADDRESS JMP FDCOM ;CONTINUE SEARCH ; ; ; ***** COMMAND TABLE ***** ; ; THIS TABLE DESCRIBES THE VALID COMMANDS FOR SOLOS ; COMTAB: DW 'TE' ;TERMINAL MODE DW TERM DW 'DU' ;DUMP DW DUMP DW 'EN' ;ENTER DW ENTER DW 'EX' ;EXECUTE DW EXEC DW 'GE' ;GET A FILE DW TLOAD DW 'SA' ;SAVE A FILE DW TSAVE DW 'XE' ;AUTO-EXECUTE A FILE DW TXEQ DW 'CA' ;CATALOG OF TAPE FILES DW TLIST DW 'SE' ;SET COMMAND DW CSET DW 'CU' ;CUSTOM COMMAND DW CUSET DB 0 ;END OF TABLE MARK ; ; ; DISPLAY DRIVER COMMAND TABLE ; ; THIS TABLE DEFINES THE CHARACTERS FOR SPECIAL ; PROCESSING. IF THE CHARACTER IS NOT IN THE TABLE IT ; GOES TO THE SCREEN. ; TBL: DB CLEAR-80H ;CLEAR SCREEN DW PERSE DB UP-80H ;UP CURSOR DW PUP DB DOWN-80H ;DOWN CURSOR DW PDOWN DB LEFT-80H ;LEFT CURSOR DW PLEFT DB RIGHT-80H ;RIGHT CURSOR DW PRIT DB HOME-80H ;HOME CURSOR DW PHOME DB CR ;CARRIAGE RETURN DW PCR DB LF ;LINE FEED DW PLF DB BACKS ;BACKSPACE DW PBACK DB ESC ;ESCAPE KEY DW PESC DB 0 ;END OF TABLE ; ; ; OUTPUT DEVICE TABLE ; OTAB: DW VDMOT ;VDM DRIVER DW SDROT ;SERIAL OUTPUT DW PROUT ;PARALLAL OUTPUT DW ERROT ;ERROR OR USER DRIVER HANDLER ; ; ; INPUT DEVICE TABLE ; ITAB: DW KSTAT ;KEYBOARD INPUT DW SSTAT ;SERIAL INPUT DW PASTAT ;PARALLEL INPUT DW ERRIT ;ERROR OR USER DRIVER HANDLER ; ; ; SECONDARY COMMAND TABLE FOR SET COMMAND ; SETAB: DW 'TA' ;SET TAPE SPEED DW TASPD DW 'S=' ;SET DISPLAY SPEED DW DISPD DW 'I=' ;SET INPUT PORT DW SETIN DW 'O=' ;SET OUTPUT PORT DW SETOT DW 'N=' ;SET NULLS DW SETNU DW 'CI' ;SET CUSTOM DRIVER ADDRESS DW SETCI DW 'CO' ;SET CUSTOM OUTPUT DRIVER ADDRESS DW SETCO DW 'XE' ;SET HEADER XEQ ADDRESS DW SETXQ DW 'TY' ;SET HEADER TYPE DW SETTY DW 'CR' ;SET CRC TO ALLOW IGNORING OF CRC ERRORS DW SETCR DB 0 ;END OF TABLE MARK ; ; ; SOLOS PORT ERROR HANDLER ; ERRIT: PUSH H ;SAVE HL ONCE AGAIN LHLD UIPRT ;GET USER INPUT PORT ADDRESS JMP ERRO1 ;AND GO PROCESS ; ERROT: PUSH H LHLD UOPRT ;GET USER OUTPUT PORT ADDRESS ERRO1: MOV A,L ;TEST HL FOR ZERO ORA H JZ COMN1 ;IF ZERO RETURN TO COMMAND MODE XTHL ;ADDRESS TO STACK...OLD HL TO HL RET ;GO TO THE DRIVER ; ; THIS ROUTINE IS THE PARALLEL DEVICE HANGLER ; NO PROVISION IS MADE FOR CONTROLLING THE PORT ; CONTROL BIT. ; ; ; PARALLEL INPUT DRIVER ; PASTAT: IN STAPT CMA ;INVERT STATUS FLAGS ANI PDR ;TEST BIT RZ IN PDATA ;GET DATA RET ; ; PARALLEL OUTPUT HANDLER ; PROUT: IN STAPT ;GET STATUS ANI PXDR ;TEST IF DEVICE IS READY JNZ PROUT ;LOOP UNTIL SO MOV A,B OUT PDATA RET ; ; ; OUTPUT A CR/LF FOLLOWED BY A PROMPT ; PROMPT: CALL CRLF MVI B,'>' ;THE PROMPT JMP SOUT ;PUT IT ON THE SCREEN ; ; CRLF: MVI B,LF ;LINE FEED CALL SOUT MVI B,CR ;CARRIAGE RETURN CALL SOUT ; NOW OUTPUT THE NULLS LDA NUCNT ;GET DESIRED COUNT MOV C,A ;STORE IN C NULOT: DCR C RM ;RETURN WHEN PAST ZERO XRA A ;GET A NULL CALL OUTH JMP NULOT ; ; ; SCAN OFF OPTIONAL PARAMETER. IF PRESENT RETURN WITH ; VALUE IN HL AND COPY OF 'L' IN 'A'. IF NOT PRESENT ; RETURN WITH A "1" IN 'A' AND HL UNTOUCHED. ; PSCAN: CALL SBLK MVI A,1 ;DEFAULT VALUE RZ ;IF NONE CALL SHEX ;CONVERT VALUE MOV A,L ;GET LOWER HALF RET ; ; ; SCAN OVER UP TO 12 CHARACTERS LOOKING FOR A BLANK ; SBLK: MVI C,12 ;MAXIMUM COMMAND STRING SBLK1: LDAX D CPI BLANK JZ SCHR ;GOT A BLANK NOW SCAN PAST IT INX D CPI '=' ;ALSO ALLOW EQUAL TO STOP US JZ SCHR ;IF SO, PTR AT CHAR FOLLOWING DCR C ;NO MORE THAN TWELVE JNZ SBLK1 RET ;GO BACK WITH ZERO FLAG SET ; ; ; SCAN PAST UP TO 10 BLANK POSITIONS LOOKING FOR ; A NON-BLANK CHARACTER ; SCHR: MVI C,10 ;SCAN TO FIRST NONBLANK CHR IN 10 SCHR1: LDAX D ;GET NEXT CHARACTER CPI SPACE RNZ ;WE'RE PAST THEM INX D ;NEXT SCAN ADDRESS DCR C RZ ;COMMAND ERROR JMP SCHR1 ;KEEP LOOPING ; ; ; THIS ROUTINE SCANS OVER CHARACTERS, PAST BLANKS AND ; CONVERTS THE FOLLOWING VALUE TO HEX. ERRORS RETURN TO ; THE ERROR HANDLER. ; SCONV: CALL SBLK ;FIND IF VALUE IS PRESENT JZ ERR1 ;ABORT TO ERROR IF NONE ; ; ; THIS ROUTINE CONVERTS ASCII DIGITS INTO BINARY FOLLOWING ; A STANDARD HEX CONVERSION. THE SCAN STOPS WHEN AN ASCII ; SPACE IS ENCOUNTERED. PARAMETER ERRORS REPLACE THE ERROR ; CHARACTER ON THE SCREEN WITH A QUESTION MARK. ; SHEX: LXI H,0 ;CLEAR H & L SHE1: LDAX D ;GET CHARACTER CPI 20H ;IS IT A SPACE RZ ;IF SO CPI '/' ;SLASH IS ALSO LEGAL RZ CPI ':' ;EVEN THE COLON IS ALLOWED RZ ; HCONV: DAD H ;MAKE ROOM FOR THE NEW ONE DAD H DAD H DAD H CALL HCOV1 ;DO THE CONVERSION JNC ERR1 ;NOT VALID HEXIDECIMAL VALUE ADD L MOV L,A ;MOVE IT IN INX D ;BUMP THE POINTER JMP SHE1 ; HCOV1: SUI 48 ;REMOVE ASCII BIAS CPI 10 RC ;IF LESS THAN 9 SUI 7 ;IT'S A LETTER CPI 10H RET ;WITH TEST IN HAND ; ; ; ***** TERMINAL COMMAND ***** ; ; THIS ROUTINE GETS CHARACTERS FROM THE SYSTEM KEYBOARD ; AND OUTPUTS THEM TO THE SELECTED OUTPUT PORT. IT IS ; INTENDED TO CONFIGURE THE SOL AS A STANDARD VIDEO ; TERMINAL. COMMAND KEYS ARE NOT OUTPUT TO THE OUTPUT ; PORT BUT ARE INTERPRETED AS DIRECT SOL COMMANDS. ; THE MODE COMMAND, RECEIVED BY THE KEYBOARD, PUTS THE SOL ; IN THE COMMAND MODE. ; ; ; TERM: CALL PSCAN ;FIND IF INPUT PARAMETER IS PRESENT STA IPORT ;SINP WILL USE THIS DRIVER (DEFAULT IS 1) CALL PSCAN ;NOW FOR THE OUTPUT DRIVER STA OPORT ; TERM1: CALL KSTAT ;IS THERE ONE WAITING? JZ TIN ;IF NOT MOV B,A ;SAVE IT IN B CPI MODE ;IS IT MODE? JZ COMN1 ;YES...RESET AND QUIT TERM JC TOUT ;NON-CURSOR KEY...SEND TO TERM PORT CALL VDMOT ;PROCESS IT JMP TIN ; TOUT: CALL SOUT ;OUTPUT IT TO THE SERIAL PORT TIN: CALL SINP ;GET INPUT STATUS JZ TERM1 ;LOOP IF NOT ANI 7FH ;NO HIGH BITS FROM HERE JZ TERM1 ;A NULL IS IGNORED MOV B,A ;IT'S OUTPUT FROM 'B' CPI 1BH ;IS IT A CONTROL CHAR TO BE IGNORED JNC TERM2 ;NO...TO VDM AS IS THEN CPI CR ;CR OR LF ARE SPECIAL CASES THOUGH JZ TERM2 ;AND MUST BE PASSED STD MODE TO VDM CPI LF JZ TERM2 LDA ESCFL ;A CTRL CHAR...ARE WE W/IN ESC SEQUENCE? ORA A ;IF YES, THEN OUTPUT CTRL CHAR DIRECTLY TO VDM JNZ TERM2 ;WE SURE ARE, LET VDM DRIVER HANDLE IT PUSH B ;SAVE THE CHARACTER MVI B,ESC ;CTRL CHAR TO VDM VIA ESC SEQUENCE CALL VDMOT MVI B,7 ;SAY TO PUT OUT NEXT CHAR AS IS CALL VDMOT ;ALMOST READY POP B ;RESTORE CHAR TERM2: EQU $ ;ALL READY TO OUTPUT THE CHAR CALL VDMOT ;PUT IT ON THE SCREEN JMP TERM1 ;LOOP OVER AND OVER ; ; ; ; ***** DUMP COMMAND ***** ; ; THIS ROUTINE DUMPS CHARACTERS FROM MEMORY TO THE ; CURRENT OUTPUT DEVICE. ALL VALUES ARE DISPLATED AS ; ASCII HEX. ; ; THE COMMAND FORM IS A FOLLOWS: ; ; DU ADDR1 ADDR2 ; ; THE VALUES FROM ADDR1 TO ADDR2 ARE THEN OUTPUT TO THE ; OUTPUT DEVICE. IF ONLY ADDR1 IS SPECIFIED THEN THE ; VALUE AT THAT ADDRESS IS OUTPUT. ; DUMP: CALL SCONV ;SCAN TO FIRST ADDRESS AND CONVERT IT PUSH H ;SAVE THE VALUE CALL PSCAN ;SEE IF SECOND WAS GIVIN POP D XCHG ;HL HAS START, DE HAS END ; DLOOP: CALL CRLF CALL ADOUT ;OUTPUT ADDRESS CALL BOUT ;ANOTHER SPACE TO KEEP IT PRETTY MVI C,16 ;VALUES PER LINE ; DLP1: MOV A,M ;GET THE CHAR PUSH B ;SAVE VALUE COUNT CALL HBOUT ;SEND IT OUT WITH A BLANK MOV A,L ;COMPARE DE AND HL SUB E MOV A,H SBB D JNC COMND ;ALL DONE POP B ;VALUES PER LINE INX H DCR C ;BUMP THE LINE COUNT JNZ DLP1 ;NOT ZERO IF MORE FOR THIS LINE JMP DLOOP ;DO A LFCR BEFORE THE NEXT ; ; ; OUTPUT HL AS HEX 16 BIT VALUE ; ADOUT: MOV A,H ;H FIRST CALL HEOUT MOV A,L ;THEN L FOLLOWED BY A SPACE ; HBOUT: CALL HEOUT CALL SINP ;SEE IF A CHAR WAITING JZ BOUT ;NO ANI 7FH ;CLR PARITY FIRST THO JZ COMND ;EITHER MODE OR CTRL-@ CPI ' ' ;IS IT A SPACE JNZ BOUT ;NO...IGNORE THE CHAR WTLP1: CALL SINP ;IF SPACE, WAIT UNTIL ANY OTHER KEY HIT JZ WTLP1 ;THIS ALLOWS LOOKING AT THE DISPLAY BOUT: MVI B,' ' JMP SOUT ;PUT IT OUT ; HEOUT: MOV C,A ;GET THE CHARACTER RRC ;MOVE THE HIGH FOUR DOWN RRC RRC RRC CALL HEOU1 ;PUT THEM OUT MOV A,C ;THIS TIME THE LOW FOUR ; HEOU1: ANI 0FH ;FOUR ON THE FLOOR ADI 48 ;WE WORK WITH ASCII HERE CPI 58 ;0-9? JC OUTH ;YUP ADI 7 ;MAKE IT A LETTER OUTH: MOV B,A ;OUTPUT IT FROM REGISTER 'B' JMP SOUT ; ; ; ***** ENTER COMMAND ***** ; ; THIS ROUTINE GETS VALUES FROM THE KEYBOARD AND ENTERS ; THEM INTO MEMORY. THE INPUT VALUES ARE SCANNED FOLLOWING ; A STANDARD 'GCLIN' INPUT SO ON SCREEN EDITING MAY TAKE ; PLACE PRIOR TO THE LINE TERMINATOR. A BACK SLASH '/' ; ENDS THE ROUTINE AND RETURNS CONTROL TO THE COMMAND MODE. ; A COLON ':' SETS THE PREVIOUS VALUE AS A NEW ADDRESS FOR ; ENTRY. ; ENTER: CALL SCONV ;SCAN OVER CHARS AND GET ADDRESS PUSH H ;SAVE ADDRESS XRA A STA OPORT ;ENTER VALUES TO SCREEN BUFFER ; ENLOP: CALL CRLF MVI B,':' CALL CONT ;GET LINE OF INPUT CALL CREM ;REMOVE THE CURSOR MVI C,1 ;START SCAN CALL VDAD2 ;GET ADDRESS XCHG ;....TO DE ; ; ENLO1: MVI C,3 ;NO MORE THAN THREE SPACES BETWEEN VALUES CALL SCHR1 ;SCAN TO NEXT VALUE JZ ENLOP ;LAST ENTRY FOUND, START NEW LINE ; CPI '/' ;COMMAND TERMINATOR JZ COMN1 ;IF SO, RETURN TO STANDARD INPUT CALL SHEX ;CONVERT VALUE CPI ':' ;ADDRESS TERMINATOR JZ ENLO3 ;GO PROCESS IF SO MOV A,L ;GET LOW PART AS CONVERTED POP H ;GET MEMORY ADDRESS MOV M,A ;PUT IN THE VALUE INX H PUSH H ;BACK GOES THE ADDRESS JMP ENLO1 ;CONTINUE THE SCAN ; ENLO3: XTHL ;PUT NEW ADDRESS ON STACK INX D ;MOVE SCAN PAST TERMINATOR JMP ENLO1 ; ; ; ***** EXECUTE COMMAND ***** ; ; THIS ROUTINE GETS THE FOLLOWING PARAMETER AND DOES A ; PROGRAM JUMP TO THE LOCATION GIVEN BY IT. IF PROPER ; STACK OPERATIONS ARE USED WITHIN THE EXTERNAL PROGRAM ; IT CAN DO A STANDARD 'RET'URN TO THE SOLOS COMMAND MODE. ; THE STARTING ADDRESS OF SOLOS IS PASSED TO THE PROGRAM ; IN REGISTER PAIR HL SO IT CAN ADJUST INTERNAL PARAMETERS ; FOR SOLOS OPERATION. ; ; EXEC: CALL SCONV ;SCAN PAST BLANKS AND GET PARAMETER EXEC1: PUSH H ;PUT GO ADDRESS ON STACK LXI H,START ;TELL THE PROGRAM WHERE WE CAME FROM RET ;AND DISPATCH IT ; ; ; THIS ROUTINE GETS A NAME OF UP TO 5 CHARACTERS ; FROM THE INPUT STRING. IF THE TERMINATOR IS A ; SLASH (/) THEN THE CHARACTER FOLLOWING IS TAKEN ; AS THE CASSETTE UNIT SPECIFICATION. ; ; NAMES: LXI H,THEAD ;POINT TO INTERNAL HEADER NAME: CALL SBLK ;SCAN OVER TO FIRST CHRS MVI B,6 ;UP TO SIX ARE ACCEPTED ; NAME1: LDAX D ;GET CHARACTER CPI ' ' ;NO UNIT DELIMITER JZ NFIL CPI '/' ;UNIT DELIMITER JZ NFIL MOV M,A INX D ;BUMP THE SCAN POINTER INX H DCR B JNZ NAME1 ;FALL THROUGH TO ERR1 IF TOO MANY CHRS IN NAME ; ; ; ***** SOLOS ERROR HANDLER ***** ; ERR1: XCHG ;GET SCAN ADDRESS TO HL ERR2: MVI M,'?' ;PUT QUESTION MARK ON SCREEN JMP COMN1 ;AND RETURN TO COMMAND MODE ; ; ; HERE WE HAVE SCANNED OFF THE NAME. ZERO FILL FOR ; NAMES LESS THAN FIVE CHARACTERS. ; NFIL: MVI M,0 ;PUT IN AT LEAST ONE ZERO INX H DCR B JNZ NFIL ;LOOP UNTIL B IS ZERO ; CPI '/' ;IS THERE A UNIT SPECIFICATION? MVI A,1 ;PRETEND NOT JNZ DEFLT INX D ;MOVE PAST THE TERMINATOR CALL SCHR ;GO GET UNIT SPEC SUI '0' ;REMOVE ASCII BIAS ; DEFLT: EQU $ ;MOVE OVER TO INTERNAL REPRESENTATION ANI 1 ;JUST BIT ZERO MVI A,TAPE1 ;ASSUME TAPE ONE JNZ STUNT ;IF NON-ZERO, ITS ONE RAR STUNT: STA FNUMF ;SET IT IN RET ; ; ; ; THIS ROUTINE PROCESSES THE XEQ AND GET COMMANDS ; ; TXEQ: DB 3EH ;THIS BEGINS "MVI A,0AFH" TLOAD: XRA A ;A=0 MEANS TLOAD, ELSE TXEQ PUSH PSW ;SAVE FLAG FOR LATER LXI H,DHEAD ;PLACE DUMMY HEADER HERE CALL NAME ;SET IN NAME AND UNIT LXI H,0 ;PRETEND NO SECOND VALUE CALL PSCAN ;GO GET THE ADDRESS (IF PRESENT) ; TLOA2: XCHG ;PUT ADDRESS IN DE LXI H,DHEAD ;POINT TO DUMMY HEADER WITH NAME TO LOAD MOV A,M ;SEE IF A NAME WAS ENTERED ORA A ;IS THERE A NAME? JNZ TLOA3 ;YES...SEARCH FOR IT LXI H,THEAD ;NO NAME, LOAD 1ST FILE TLOA3: PUSH H ;SAVE PTR TO NAME TO LOAD CALL ALOAD ;GET UNIT AND SPEED POP H ;RESTORE PTR TO HDR TO LOAD CALL RTAPE ;READ IN THE TAPE JC TAERR ;TAPE ERROR? ; CALL NAOUT ;PUT OUT THE HEADER PARAMETERS POP PSW ;RESTORE FLAG FROM ORIGINAL ENTRY ORA A RZ ;AUTO XEQ NOT WANTED LDA HTYPE ;CHECK TYPE ORA A ;SET FLAGS JM TAERR ;TYPE IS NOW XEQ LDA THEAD+5 ;GET CHARACTER PAST NAME ORA A JNZ TAERR ;THE BYTE MUST BE ZERO FOR AUTO XEQ LHLD XEQAD ;GET THE TAPE ADDRESS JMP EXEC1 ;AND GO TO IT ; ; ; ***** GET COMMAND ***** ; ; THIS ROUTINE IS USED TO SAVE PROGRAMS AND DATA ON ; THE CASSETTE UNIT ; ; TSAVE: CALL NAMES ;GET NAME AND UNIT CALL SCONV ;GET START ADDRESS PUSH H ;USE THE STACK AS A REGISTER CALL SCONV ;GET END ADDRESS XTHL ;PUT END ON STACK, GET BACK START PUSH H ;SAVE START ON TOP OF STACK CALL PSCAN ;SEE IF OPTIONAL HEADER ADDRESS WAS GIVEN SHLD LOADR ;PUT HEADER ADDRESS IN PLACE ; POP H ;"FROM" ADDRESS TO HL POP D ;GET BACK END ADDRESS PUSH H ;SAVE FROM AGAIN FOR LATER MOV A,E ;NOW CALCULATE SIZE SUB L ;SIZE=END-START+1 MOV L,A MOV A,D SBB H MOV H,A INX H SHLD BLOCK ;STORE THE SIZE PUSH H ;SAVE IT FOR THE READ ALSO ; CALL ALOAD ;GET UNIT AND SPEED LXI H,THEAD ;POINT TO HEADER CALL WHEAD ;AND WRITE IT OUT ; NOW WRITE OUT THE DATA POP D ;GET SIZE TO DE POP H ;GET BACK "FROM" ADDRESS JMP WRLO1 ;WRITE OUT THE DATA AND RETURN ; ; ; OUTPUT ERROR AND HEADER ; TAERR: CALL CRLF MVI D,6 LXI H,ERRM ;POINT TO ERROR MESSAGE CALL NLOOP ;OUTPUT ERROR CALL NAOUT ;THEN THE HEADER JMP COMN1 ;AND BE SURE THE TAPE UNITS ARE OFF ; ERRM: DB 'ERROR ' ; ; ; THIS ROUTINE READS HEADERS FROM THE TAPE AND OUTPUTS ; THEM TO THE OUTPUT DEVICE. IT CONTINUES UNTIL THE ; MODE KEY IS DEPRESSED. ; TLIST: CALL NAMES ;SET UP UNIT IF GIVEN CALL CRLF ; ; LLIST: CALL ALOAD MVI B,1 CALL TON ;TURN ON THE TAPE ; LIST1: CALL RHEAD JC COMN1 ;TURN OFF THE TAPE UNIT JNZ LIST1 CALL NAOUT ;OUTPUT THE HEADER JMP LIST1 ;LOOP UNTIL MODE IS DEPRESSED ; ; ; THIS ROUTINE GETS THE CASSETTE UNIT NUMBER AND ; SPEED TO REGISTER "A" FOR THE TAPE CALLS ; ALOAD: LXI H,FNUMF ;POINT TO THE UNIT SPECIFICATION LDA TSPD ;GET THE TAPE SPEED ORA M ;PUT THEM TOGETHER RET ;AND GO BACK ; ; ; THIS ROUTINE OUTPUTS THE NAME AND PARAMETERS OF ; THEAD TO THE OUTPUT DEVICE. ; ; NAOUT: MVI D,8 LXI H,THEAD-1 ;POINT TO THE HEADER CALL NLOOP ;OUTPUT THE HEADER CALL BOUT ;ANOTHER BLANK LHLD LOADR ;NOW THE LOAD ADDRESS CALL ADOUT ;PUT IT OUT LHLD BLOCK ;AND THE BLOCK SIZE CALL ADOUT JMP CRLF ;DO THE CRLF AND RETURN ; ; NLOOP: MOV A,M ;GET CHARACTER ORA A JNZ CHRLI ;IF IT ISN'T A ZERO MVI A,' ' CHRLI: CALL OUTH ;OUTPUT CHAR NOW INX H DCR D JNZ NLOOP RET ; ; ; ; ; ***** SET COMMAND ***** ; ; THIS ROUTINE GETS THE ASSOCIATED PARAMETER AND ; DISPATCHES TO THE PROPER ROUTINE FOR SETTING ; GLOBAL VALUES. ; CSET: EQU $ ;THIS IS THE SET COMMAND CALL SBLK ;LOOK FOR SET NAME JZ ERR1 ;MUST HAVE A LEAST SOMETHING!! PUSH D ;SAVE SCAN ADDRESS CALL SCONV ;CONVERT FOLLOWING VALUE XTHL ;GET SCAN ADDR BACK...SAVE VALUE ON STACK LXI D,SETAB ;SECONDARY COMMAND TABLE CALL FDCOM ;SEE IF IN TABLE JMP DISPO ;AND EITHER ERR OR OFF TO IT ; ; ; THIS ROUTINE SETS THE TAPE SPEED ; TASPD: ORA A ;IS IT ZERO? JZ SETSP ;YES...THAT'S A VALID SPEED MVI A,32 ;SET TO SLOW IF NON-ZERO SETSP: STA TSPD ;SPEED IS STORED HERE RET ; ; STSPD: MOV A,B ;ESCAPE COMES HERE TO SET SPEED DISPD: STA SPEED ;SET DISPLAY SPEED RET ; ; SET INPUT DRIVER ; SETIN: EQU $ STA IPORT RET ; ; SET OUTPUT DRIVER ; SETOT: EQU $ STA OPORT RET ; ; SET USERS CUSTOM INPUT DRIVER ADDRESS ; SETCI: SHLD UIPRT RET ; ; SET USERS CUSTOM OUTPUT DRIVER ADDRESS ; SETCO: SHLD UOPRT RET ; ; SET TYPE BYTE INTO HEADER ; SETTY: STA HTYPE RET ; ; SET EXECUTE ADDRESS INTO HEADER ; SETXQ: SHLD XEQAD RET ; ; SETNU: STA NUCNT ;SET THE NULL COUNT RET ;THAT'S DONE ; ; SETCR: EQU $ ;SET TO IGNORE CRC ERRORS STA IGNCR ;FF=IGNORE ERRORS, ELSE=NORMAL RET ; ; ; ; CUSTOM COMMAND NAME AND ADDRESS INTO CUSTOM COMMAND ; CUSET: CALL NAMES ;CUSTOM COMMAND ENTRY/REMOVAL LXI H,COMND ;DEFAULT ADDR IF NONE GIVEN CALL PSCAN ;GET RTN ADDRESS PUSH H ;SAVE RTN ADDRESS LXI H,THEAD ;POINT AT NAME TO SEARCH CALL FDCOU ;SEARCH IT IN CUSTOM TABLE JZ CUSE2 ;NOT IN TABLE...ENTER IT DCX D ;IN TABLE, REMOVE IT MVI M,0 ;CHANGE NEW NAME TO BE ZERO CUSE2: MOV A,M ;GET 1ST CHAR OF NAME STAX D ;ENTER IT INTO TABLE INX D ;AND THE 2ND NAME INX H MOV A,M STAX D ;NAME NOW ENTERED INX D ;GET SET TO ENTER ADDRESS POP H ;RESTORE RTN ADDR XCHG MOV M,E ;SET ADDR IN NOW INX H ;AND HI BYTE OF ADDR MOV M,D RET ;NAME IS NOW ENTERED OR CLEARED ; ; ; ; THE FOLLOWING ROUTINES PROVIDE "BYTE BY BYTE" ACCESS ; TO THE CASSETTE TAPES ON EITHER A READ ORWRITE BASIS. ; ; THE TAPE IS READ ONE BLOCK AT A TIME AND INDIVIDUAL ; TRANSFERS OF DATA HANDLED BY MANAGING A BUFFER AREA. ; ; THE BUFFER AREA IS CONTROLLED BY A FILE CONTROL BLOCK ; (FCB) WHOSE STRUCTURE IS: ; ; 7 BYTES FOR EACH OF THE TWO FILES STRUCTURED AS ; FOLLOWS: ; ; 1 BYTE - ACCESS CONTROL 00 IF CLOSED ; FF IF READING ; FEIF WRITING ; 1 BYTE - READ COUNTER ; 1 BYTE - BUFFER POSITION POINTER ; 2 BYTE - CONTROL HEADER ADDRESS ; 2 BYTE - BUFFER LOCATION ADDRESS ; ; ; ; THIS ROUTINE "OPENS" THE CASSETTE UNIT FOR ACCESS ; ; ON ENTRY: A - HAS THE TAPE UNIT NUMBER (1 OR 2) ; HL - HAS USER SUPPLIED HEADER FOR TAPE FILE ; ; ; NORMAL RETURN: ALL REGISTERS ARE ALTERED ; BLOCK IS READY FOR ACCESS ; ; ERROR RETURN: CARRY BIT IS SET ; ; ERRORS: BLOCK ALREADY OPEN ; ; BOPEN: PUSH H ;SAVE HEADER ADDRESS CALL LFCB ;GET ADDRESS OF FILE CONTROL JNZ TERE2 ;FILE WAS ALREADY OPEN MVI M,1 ;NOW IT IS INX H ;POINT TO READ COUNT MOV M,A ;ZERO INX H ;POINT TO BUFFER CURSOR MOV M,A ;PUT IN THE ZERO COUNT ; ; ALLOCATE THE BUFFER ; LXI D,FBUF1 ;POINT TO BUFFER AREA LDA FNUMF ;GET WHICH ONE WE ARE GOING TO USE ADD D MOV D,A ;256 BIT ADD ; UBUF: POP B ;HEADER ADDRESS ORA A ;CLEAR CARRY AND RET AFTER STORING PARAMS JMP PSTOR ;STORE THE VALUES ; ; GENERAL ERROR RETURN POINTS FOR STACK CONTROL ; TERE2: POP H TERE1: POP D TERE0: XRA A ;CLEAR ALL FLAGS STC ;SET ERROR RET ; ; EOFER: DCR A ;SET MINUS FLAGS STC ;AND CARRY POP D ;CLEAR THE STACK RET ;THE FLAGS TELL ALL ; ; ; ; ; THIS ROUTINE CLOSES THE FILE BUFFER TO ALLOW ACCESS ; FOR A DIFFERENT CASSETTE OF PROGRAM. IF THE TILE ; OPERATIONS WERE "WRITE" THEN THE LAST BLOCK IS WRITTEN ; OUT AND AN "END OF FILE" WRITTEN TO THE TAPE. IF ; THE OPERATIONS WERE "READS" THEN THE FILE IS JUST ; MADE READY FOR NEW USE. ; ; ON ENTRY: A - HAS WHICH UNIT (1 OR 2) ; ; ERROR RETURNS: FILE WASN'T OPEN ; ; PCLOS: CALL LFCB ;GET CONTROL BLOCK ADDRESS RZ ;WASN'T OPEN, CARRY IS SET FROM LFCR ORA A ;CLEAR CARRY INR A ;SET CONDITION FLAGS MVI M,0 ;CLOSE THE CONTROL BYTE RZ ;WE WERE READING...NOTHING MORE TO DO ; ; THE FILE OPERATIONS WERE "WRITES" ; ; PUT THE CURRENT BLOCK ON THE TAPE ; (EVEN IF ONLY ONE BYTE) ; THEN WRITE AN END OF FILE TO THE TAPE ; ; INX H INX H MOV A,M ;GET CURSOR POSITION CALL PLOAD ;BC GET HEADER ADDRESS, DE BUFFER ADDRESS PUSH B ;HEADER TO STACK LXI H,BLKOF ;OFFSET TO BLOCK SIZE DAD B ORA A ;TEST COUNT JZ EOFW ;NO BYTES...JUST WRITE EOF ; ; WRITE LAST BLOCK ; PUSH H ;SAVE BLOCK SIZE POINTER FOR EOF MOV M,A ;PUT IN COUNT INX H MVI M,0 ;ZERO THE HIGHER BYTE INX H MOV M,E ;BUFFER ADDRESS INX H MOV M,D MOV H,B MOV L,C ;PUT HEADER ADDRESS IN HL CALL WFBLK ;GO WRITE IT OUT POP H ;BLOCK SIZE POINTER ; ; NOW WRITE END OF FILE TO CASSETTE ; EOFW: XRA A ;PUT IN ZEROS FOR SIZE ;EOF MARK IS ZERO BYTES! MOV M,A INX H MOV M,A POP H ;HEADER ADDRESS JMP WFBLK ;WRITE IT OUT AND RETURN ; ; ; ; ; THIS ROUTINE LOCATES THE FILE CONTROL BLOCK POINTED TO ; BY REGISTER "A". ON RETURN HL POINTS TO THE CONTROL BYTE ; AND REGISTER "A" HAS THE CONTROL WORD WITH THE FLAGS ; SET FOR IMMEDIATE CONDITION DECISIONS. ; ; LFCB: LXI H,FCBAS ;POINT TO THE BASE OF IT RAR ;MOVE THE 1 & 2 TO 0 & 1 ANI 1 ;SMALL NUMBERS ARE THE RULE STA FNUMF ;CURRENT ACCESS FILE NUMBER JZ LFCB1 ;UNIT ONE (VALUE OF ZERO) LXI H,FCBA2 ;UNIT TWO--POINT TO ITS FCB LFCB1: EQU $ ;HL POINT TO PROPER FCB MOV A,M ;PICK UP FLAGS FROM FCB ORA A ;SET FLAGS BASED ON CONTROL WORD STC ;SET CARRY IN CASE OF IMMEDIATE ERROR RET RET ; ; ; ; ; READ TAPE BYTE ROUTINE ; ; ENTRY: - A - HAS FILE NUMBER ; EXIT: NORMAL - A - HAS BYTE ; ERROR ; CARRY SET - IF FILE NOT OPEN OR ; PREVIOUS OPERATIONS WERE WRITE ; CARRY & MINUS - END OF FILE ENCOUNTERED ; ; ; ; RTBYT: CALL LFCB ;LOCATE THE FILE CONTROL BLOCK RZ ;FILE NOT OPEN INR A ;TEST IF FF JM TERE0 ;ERROR WAS WRITING MVI M,(-1) AND 0FFH ;SET IT AS READ (IN CASE IT WAS JUST OPENED) INX H MOV A,M ;GET READ COUNT PUSH H ;SAVE COUNT ADDRESS INX H CALL PLOAD ;GET THE OTHER PARAMETERS POP H ORA A JNZ GTBYT ;IF NOT EMPTY GO GET BYTE ; ; CURSOR POSITION WAS ZERO...READ A NEW BLOCK ; INTO THE BUFFER. ; RDNBLK: PUSH D ;BUFFER POINTER PUSH H ;TABLE ADDRESS INX H CALL PHEAD ;PREPARE THE HEADER FOR READ CALL RFBLK ;READ IN THE BLOCK JC TERE2 ;ERROR POP OFF STACK BEFORE RETURN POP H MOV A,E ;LOW BYTE OF COUNT (WILL BE ZERO IF 256) ORA D ;SEE IF BOTH ARE ZERO JZ EOFER ;BYTE COUNT WAS ZERO...END OF FILE MOV M,E ;NEW COUNT (ZERO IS 256 AT THIS POINT) INX H ;BUFFER LOCATION POINTER MVI M,0 DCX H MOV A,E ;GET BACK BUFFER ADDRESS POP D ; ; ; ; THIS ROUTINE GETS ONE BYTE FROM THE BUFFER ; AND RETURNS IT IN REGISTER "A". IF THE END ; OF THE BUFFER IS REACHED IT MOVES THE POINTER ; TO THE BEGINNING OF THE BUFFER FOR THE NEXT ; LOAD. ; GTBYT: DCR A ;BUMP THE COUNT MOV M,A ;RESTORE IT INX H MOV M,A ;GET BUFFER POSITION INR M ;BUMP IT ; ADD E MOV E,A ;DE NOW POINT TO CORRECT BUFFER POSITION JNC RT1 INR D RT1: LDAX D ;GET CHARACTER FROM BUFFER ORA A ;CLEAR CARRY RET ;ALL DONE ; ; ; ; THIS ROUTINE IS USED TO WRITE A BYTE TO THE FILE ; ; ON ENTRY: A - HAS FILE NUMBER ; B - HAS DATA BYTE ; ; WTBYT: CALL LFCB ;GET CONTROL BLOCK RZ ;FILE WASN'T OPEN INR A RZ ;FILE WAS READ MVI M,0FEH ;SET IT TO WRITE INX H INX H MOV A,B ;GET CHARACTER PUSH PSW PUSH H ;SAVE CONTROL ADDRESS+2 ; ; NOW DO THE WRITE ; CALL PLOAD ;BC GETS HEADER ADDR ;DE BUFFER ADDRESS POP H MOV A,M ;COUNT BYTE ADD E MOV E,A JNC WT1 INR D WT1: POP PSW ;CHARACTER STAX D ;PUT CHR IN BUFFER ORA A ;CLEAR FLAGS INR M ;INCREMENT THE COUNT RNZ ;RETURN IF COUNT DIDN'T ROLL OVER ; ; THE BUFFER IS FULL. WRITE IT TO TAPE ; AND RESET CONTROL BLOCK. ; CALL PHEAD ;PREPARE THE HEADER JMP WFBLK ;WRITE IT OUT AND RETURN ; ; ; ; ; THIS ROUTINE PUTS THE BLOCK SIZE (256) AND BUFFER ; ADDRESS IN THE FILE HEADER. ; PHEAD: CALL PLOAD ;GET HEADER AND BUFFER ADDRESSES PUSH B ;HEADER ADDRESS LXI H,BLKOF-1 ;PSTOR DOES AN INCREMENT DAD B ;HL POINTS TO BLOCKSIZE ENTRY LXI B,256 CALL PSTOR POP H ;HL RETURN WITH HEADER ADDRESS RET ; ; PSTOR: INX H MOV M,C INX H MOV M,B INX H MOV M,E INX H MOV M,D RET ; ; PLOAD: INX H MOV C,M INX H MOV B,M INX H MOV E,M INX H MOV D,M RET ; ; ; ; ;THIS ROUTINE SETS THE CORRECT UNIT FOR SYSTEM READS ; RFBLK: CALL GTUNT ;SET UP A=UNIT WITH SPEED ; ; ; ***** TAPE READ ROUTINES ***** ; ; ON ENTRY: A - HAS UNIT AND SPEED ; HL - POINTS TO HEADER BLOCK ; DE - HAS OPTIONAL PUT ADDRESS ; ; ON EXIT: CARRY IS SET IF ERROR OCCURED ; TAPE UNITS ARE OFF ; ; RTAPE: PUSH D ;SAVE OPTIONAL ADDRESS MVI B,3 ;SHORT DELAY CALL TON IN TDATA ;CLEAR THE UART FLAGS ; PTAP1: PUSH H ;HEADER ADDRESS CALL RHEAD ;GO READ HEADER POP H JC TERR ;IF AN ERROR OR ESC WAS RECEIVED JNZ PTAP1 ;IF VALID HEADER NOT FOUND ; ; FOUND A VALID HEADER NOW DO COMPARE ; PUSH H ;GET BACK AND RESAVE ADDRESS LXI D,THEAD CALL DHCMP ;COMPARE DE/HL HEADERS POP H JNZ PTAP1 ; ; POP D ;OPTIONAL "PUT" ADDRESS MOV A,D ORA E ;SEE IF DE IS ZERO LHLD BLOCK ;GET BLOCK SIZE XCHG ;....TO DE ; DE HAS HBLOCK...HL HAS USER OPTION JNZ RTAP ;IF DE WAS 0 GET TAPE LOAD ADDR LHLD LOADR ;GET TAPE LOAD ADDRESS ; ; ; THIS ROUTINE READS "DE" BYTES FROM THE TAPE ; TO ADDRESS HL. THE BYTES MUST BY FROM ONE ; CONTIGUOUS PHYSICAL BLOCK ON THE TAPE. ; ; HL HAS "PUT" ADDRESS ; DE HAS SIZE OF TAPE BLOCK ; RTAP: PUSH D ;SAVE SIZE FOR RETURN TO CALLING PROGRAM ; RTAP2: EQU $ ;HERE TO LOOP RDING BLKS CALL DCRCT ;DROP COUNT, B=LEN THIS BLOCK JZ RTOFF ;ZERO=ALL DONE ; CALL RHED1 ;READ THAT MANY BYTES JC TERR ;IF ERROR OR ESC JZ RTAP2 ;RD OK...READ SOME MORE ; ; ERROR RETURN ; TERR: XRA A STC ;SET ERROR FLAGS JMP RTOF1 ; ; TOFF: MVI B,1 CALL DELAY RTOFF: XRA A RTOF1: OUT TAPPT POP D ;RETURN BYTE COUNT RET ; ; DCRCT: EQU $ ;COMMON RTN TO COUNT DOWN BLK LENGTHS XRA A ;CLR FOR LATER TESTS MOV B,A ;SET THIS BLK LEN = 256 ORA D ;IS ANMT LEFT < 256 JNZ DCRC2 ;NO...REDUCE AMNT BY 256 ORA E ;IS ENTIRE COUNT ZERO RZ ;ALL DONE..ZERO=THIS CONDITION MOV B,E ;SET THIS BLK LEN TO AMNT REMAINING MOV E,D ;MAKE ENTIRE COUNT ZERO NOW RET ;ALL DONE (NON-ZERO FLAG) DCRC2: EQU $ ;REDUCE COUNT BY 256 DCR D ;DROP BY 256 ORA A ;FORCE NON-ZERO FLAG RET ;NON-ZERO=NOT DONE YET (BLK LEN=256) ; ; ; READ THE HEADER ; RHEAD: MVI B,10 ;FIND 10 NULLS RHEA1: CALL STAT RC ;IF ESCAPE IN TDATA ;IGNORE ERROR CONDITIONS ORA A ;ZERO? JNZ RHEAD DCR B JNZ RHEA1 ;LOOP UNTIL 10 IN A ROW ; ; WAIT FOR THE START CHARACTER ; SOHL: CALL TAPIN RC ;ERROR OR ESCAPE CPI 1 ;AT LEAST 10 NULLS FOLLOWED BY A 01 JC SOHL ;STILL A NULL, KEEP WAITING JNZ RHEAD ;NON-ZERO, START SEQUENCE OVER AGAIN ; ; NOW GET THE HEADER ; LXI H,THEAD ;POINT TO BUFFER MVI B,HLEN ;LENGTH TO READ ; RHED1: EQU $ ;RD A BLOCK INTO HL FOR B BYTES MVI C,0 ;INITALIZE THE CRC RHED2: EQU $ ;LOOP HERE CALL TAPIN ;GET A BYTE RC MOV M,A ;STORE IT INX H ;INCREMENT ADDRESS CALL DOCRC ;GO COMPUTE THE CRC DCR B ;WHOLE HEADER YET? JNZ RHED2 ;DO ALL THE BYTES ; ; THIS ROUTINE GETS THE NEXT BYTE AND COMPARES IT ; TO THE VALUE IN REGISTER C. THE FLAGS ARE SET ON ; RETURN. ; CALL TAPIN ;GET CRC BYTE XRA C ;CLR CARRY AND SET ZERO IF MATCH ; ELSE NON-ZERO RZ ;CRC WAS FINE LDA IGNCR ;GET POSSIBLE OVERRIDE CRC ERROR FLAG INR A ;FF=IGNORE CRC ERRORS RET ;ELSE PROCESS CRC ERROR ; ; ; THIS ROUTINE GETS THE NEXT AVAILABLE BYTE FROM THE ; TAPE. WHILE WAITING FOR THE BYTE THE KEYBOARD IS TESTED ; FOR AN ESC COMMAND. IF RECEIVED THE TAPE LOAD IS ; TERMINATED AND A RETURN TO THE COMMAND MODE IS MADE. ; STAT: IN TAPPT ;TAPE STATUS PORT ANI TDR RNZ CALL SINP ;CHECK INPUT JZ STAT ;NOTHING THERE YET ANI 7FH ;CLR PARITY FIRST JNZ STAT ;NOT A MODE (OR EVEN CTRL-@) STC ;SET ERROR FLAG RET ;AND RETURN ; ; ; TAPIN: CALL STAT ;WAIT UNTIL A CHARACTER IS AVAILABLE RC ; TREDY: IN TAPPT ;TAPE STATUS ANI TFE+TOE ;DATA ERROR? IN TDATA ;GET THE DATA RZ ;IF NO ERRORS STC ;SET ERROR FLAG RET ; ; ; THIS ROUTINE GETS THE CORRECT UNIT FOR SYSTEM WRITES ; WFBLK: CALL GTUNT ;SET UP A WITH UNIT AND SPEED ; ; ; ***** WRITE TAPE BLOCK ROUTINE ***** ; ; ON ENTRY: A - HAS UNIT AND SPEED ; HL - HAS POINTER TO HEADER ; ; WTAPE: EQU $ ;HERE TO WRITE TAPE PUSH H ;SAVE HEADER ADDRESS CALL WHEAD ;TURN ON, THEN WRITE HEADER POP H LXI D,BLKOF ;OFFSET TO BLOCK SIZE IN HEADER DAD D ;HL POINT TO BLOCK SIZE MOV E,M INX H MOV D,M ;DE HAS SIZE INX H MOV A,M INX H MOV H,M MOV L,A ;HL HAS STARTING ADDRESS ; ; THIS ROUTINE WRITES ONE PHYSICAL BLOCK ON THE ; TAPE "DE" BYTES LONG FROM ADDRESS "HL". ; ; WRLO1: EQU $ ;HERE FOR THE EXTRA PUSH PUSH H ;A DUMMY PUSH FOR LATER EXIT WTAP2: EQU $ ;LOOP HERE UNTIL ENTIRE AMOUNT READ CALL DCRCT ;DROP COUNT IN DE AND SET UP B ;WITH LENGTH THIS BLOCK JZ TOFF ;RETURNS ZERO IF ALL DONE CALL WTBL ;WRITE BLOCK FOR BYTES IN B (256) JMP WTAP2 ;LOOP UNTIL ALL DONE ; ; WRTAP: PUSH PSW WRWAT: IN TAPPT ;TAPE STATUS ANI TTBE ;IS TAPE READY FOR A CHAR YET JZ WRWAT ;NO...WAIT POP PSW ;YES...RESTORE CHAR TO OUTPUT OUT TDATA ;SEND CHAR TO TAPE ; DOCRC: EQU $ ;A COMMON CRC COMPUTATION ROUTINE SUB C MOV C,A XRA C CMA SUB C MOV C,A RET ;ONE BYTE NOW WRITTEN ; ; ; THIS ROUTINE WRITES THE HEADER POINTED TO BY ; HL TO THE TAPE. ; WHEAD: EQU $ ;HERE TO FIRST TURN ON THE TAPE CALL WTON ;TURN IT ON, THEN WRITE HEADER MVI D,50 ;WRITE 50 ZEROS NULOP: XRA A CALL WRTAP DCR D JNZ NULOP ; MVI A,1 CALL WRTAP MVI B,HLEN ;LENGTH TO WRITE OUT ; WTBL: MVI C,0 ;RESET CRC BYTE WLOOP: MOV A,M ;GET CHARACTER CALL WRTAP ;WRITE IT TO THE TAPE DCR B INX H JNZ WLOOP MOV A,C ;GET CRC JMP WRTAP ;PUT IT ON THE TAPE AND RETURN ; ; ; THIS ROUTINE COMPARES THE HEADER IN THEAD TO ; THE USER SUPPLIED HEADER IN ADDRESS HL. ; ON RETURN IF ZERO IS SET THE TWO NAMES COMPARED ; DHCMP: MVI B,5 DHLOP: LDAX D CMP M RNZ DCR B RZ ;IF ALL FIVE COMPARED INX H INX D JMP DHLOP ; GTUNT: EQU $ ;SET A=SPEED + UNIT LDA FNUMF ;GET UNIT ORA A ;SEE WHICH UNIT LDA TSPD ;BUT FIRST GET SPEED JNZ GTUN2 ;MAKE IT UNIT TWO ADI TAPE2 ;THIS ONCE=UNIT 2, TWICE=UNIT 1 GTUN2: ADI TAPE2 ;UNIT AND SPEED NOW SET IN A RET ;ALL DONE ; WTON: MVI B,4 ;SET LOOP DELAY, (BIT LONGER ON WRITE) TON: EQU $ ;HERE TO TURN A TAPE ON THEN DELAY OUT TAPPT ;GET TAPE MOVING, THEN DELAY ; DELAY: LXI D,0 DLOP1: DCX D MOV A,D ORA E JNZ DLOP1 DCR B JNZ DELAY RET ; ; ;********* END OF PROGRAM ************ ; ; ; ; ; ; SOL SYSTEM EQUATES ; ; ; VDM PARAMETERS ; VDMEM EQU 0CC00H ;VDM SCREEN MEMORY HIBYTE EQU 0CCH ;MEMORY HIGH BYTE ; ; ; KEYBOARD SPECIAL KEY ASSIGNMENTS ; DOWN EQU 9AH UP EQU 97H LEFT EQU 81H RIGHT EQU 93H MODE EQU 80H CLEAR EQU 8BH HOME EQU 08EH BACKS EQU 5FH ;BACKSPACE LF EQU 10 CR EQU 13 BLANK EQU ' ' SPACE EQU BLANK CX EQU 'X'-40H ESC EQU 1BH ; ; PORT ASSIGNMENTS ; STAPT EQU 0FAH ;STATUS PORT GENERAL SERST EQU 0F8H ;SERIAL STATUS PORT SDATA EQU 0F9H ;SERIAL DATA TAPPT EQU 0FAH ;TAPE STATUS PORT TDATA EQU 0FBH ;TAPE DATA KDATA EQU 0FCH ;KEYBOARD DATA PDATA EQU 0FDH ;PARALLEL DATA DSTAT EQU 0FEH ;VDM DISPLAY PARAMETER PORT SENSE EQU 0FFH ;SENSE SWITCHES ; ; ; BIT ASSIGNMENT MASKS ; SCD EQU 1 ;SERIAL CARRIER DETECT SDSR EQU 2 ;SERIAL DATA SET READY SPE EQU 4 ;SERIAL PARITY ERROR SFE EQU 8 ;SERIAL FRAMING ERROR SOE EQU 16 ;SERIAL OVERRUN ERROR SCTS EQU 32 ;SERIAL CLEAR TO SEND SDR EQU 64 ;SERIAL DATA READY STBE EQU 128 ;SERIAL TRANSMITTER BUFFER EMPTY ; KDR EQU 1 ;KEYBOARD DAYA READY PDR EQU 2 ;PARALLEL DATA READY PXDR EQU 4 ;PARALLEL DEVICE READY TFE EQU 8 ;TAPE FRAMING ERROR TOE EQU 16 ;TAPE OVERRUN ERROR TDR EQU 64 ;TAPE DATA READY TTBE EQU 128 ;TAPE TRANSMITTER BUFFER EMPTY ; SOK EQU 1 ;SCROLL OK FLAG ; TAPE1 EQU 80H ;1=TURN TAPE ONE ON TAPE2 EQU 40H ;1=TURN TAPE TWO ON ; ; ; ; SOL SYSTEM GLOBAL AREA ; ORG 0C800H ;START OF 1K RAM AREA ; SYSRAM EQU $ ;START OF SYSTEM RAM SYSTP EQU $+1024 ;STACK IS AT THE TOP ; ; ; ***** PARAMETERS STORED IN RAM ***** ; UIPRT DS 2 ;USER DEFINED INPUT RTN IF NON-ZERO UOPRT DS 2 ;USER DEFINED OUTPUT RTN IF NON-ZERO DFLTS DS 2 ;DEFAULT PSUEDO I/O PORTS ; (ALWAYS ZERO IN SOLOS) IPORT DS 1 ;CRNT INPUT PSEUDO PORT OPORT DS 1 ;CRNT OUTPUT PSEUDO PORT NCHAR DS 1 ;CURRENT CHARACTER POSITION LINE DS 1 ;CURRENT LINE POSITION BOT DS 1 ;BEGINNING OF TEXT DISPLACEMENT SPEED DS 1 ;SPEED CONTROL BYTE ESCFL DS 1 ;ESCAPE FLAG CONTROL BYTE TSPD DS 1 ;CURRENT TAPE SPEED INPTR DS 2 ;FOR COMPATABILITY W/CUTER NUCNT DS 1 ;NUMBER OF NULLS AFTER CRLF IGNCR DS 1 ;FF=IGNORE CRC ERRORE, ELSE NORMAL ; DS 10 ;ROOM FOR FUTURE EXPANSION ; ; ; THIS IS THE HEADER LAYOUT ; THEAD DS 5 ;NAME DS 1 ;THIS BYTE MUST BE ZERO HTYPE DS 1 ;TYPE BLOCK DS 2 ;BLOCK SIZE LOADR DS 2 ;LOAD ADDRESS XEQAD DS 2 ;AUTO-EXECUTE ADDRESS HSPR DS 3 ;SPARES ; HLEN EQU $-THEAD ;LENGTH OF HEADER BLKOF EQU BLOCK-THEAD ;OFFSET TO BLOCK SIZE DHEAD DS HLEN ;A DUMMY HDR FOR COMPARES WHILE RDING ; ; CUTAB DS 6*4 ;ROOM FOR UP TO 6 CUSTOM USER COMMANDS ; ; FNUMF DS 1 ;FOR CURRENT FILE OPERATIONS FCBAS DS 7 ;1ST FILE CONTROL BLOCK FCBA2 DS 7 ;2ND FILE CONTROL BLOCK FBUF1 DS 2*256 ;SYSTEM FILE BUFFER BASE DS 81 ;THIS IS AN AREA USED BY CUTER USARE EQU $ ;START OF USER AREA ***************** ; REMEMBER THAT THE STACK WORKS ITS WAY DOWN FROM ; THE END OF THIS 1K RAM AREA. ; ; ; END