C000 SOLOS: ORG 0C000H ; C000 00 START: DB 0 C001 C3E8C1 INIT: JMP STRTA ;SYSTEM RESTART ENTRY POINT ; ; ENTRY POINTS ; C004 C303C2 RETRN: JMP COMND ;RETURN TO SYSTEM ENTRY POINT C007 C30AC6 FOPEN: JMP BOPEN ;FILE OPEN ENTRY C00A C32EC6 FCLOS: JMP PCLOS ;FILE CLOSE ENTRY C00D C364C6 RDBYT: JMP RTBYT ;CASSETTE READ BYTE ENTRY C010 C3A1C6 WRBYT: JMP WTBYT ;CASSETTE WRITE BYTE ENTRY C013 C3FEC6 RDBLK: JMP RTAPE ;CASSETTE READ BLOCK ENTRY C016 C3C4C6 WRBLK: JMP WTAPE ;CASSETTE WRITE BLOCK ENTRY ; ; SYSTEM I/O ENTRY POINTS ; ; 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 ; C019 3A07C8 SOUT: LDA OPORT ;SOUT ENTRY POINT C01C C32EC0 AOUT: JMP OUTPR ;AOUT ENTRY POINT C01F 3A06C8 SINP: LDA IPORT ;SINP ENTRY POINT C022 E5 AINP: PUSH H ;AINP ENTRY POINT C023 21D2C2 LXI H,ITAB ; ; THIS ROUTINE PROCESSES THE I/O REQUESTS. ; C026 E603 IOPRC: ANI 3 ;KEEP REGISTER "A" TO FOUR VALUES C028 07 RLC ;COMPUTE ENTRY ADDRESS C029 85 ADD L C02A 6F MOV L,A ;WE HAVE ADDRESS C02B C35EC2 JMP DISPT ;DISPATCH TO IT C02E E5 OUTPR: PUSH H ;SAVE REGS C02F 21CAC2 LXI H,OTAB ;POINT TO OUTPUT TABLE C032 C326C0 JMP IOPRC ;DISPATCH TO OUTPUT ROUTINE ; KEYBOARD INPUT DRIVER ; C035 DBFA KSTAT: IN STAPT ;GET STATUS WORK C037 2F CMA ;INVERT IT FOR PROPER RETURN C038 E601 ANI KDR ;TEST KEYBOARD BIT C03A C8 RZ ;ZERO IS NO CHARACTER RECEIVED C03B DBFC IN KDATA ;GET CHARACTER C03D FEB2 CPI 0B2H C03F C244C0 JNZ KST1 C042 3E1A MVI A,'Z'-40H ;SOL'S STD DOWN KEY C044 FEB1 KST1: CPI 0B1H C046 C24BC0 JNZ KST2 C049 3E17 MVI A,'W'-40H ;SOL'S STD UP KEY C04B FEB0 KST2: CPI 0B0H C04D C252C0 JNZ KST3 C050 3E01 MVI A,'A'-40H ;SOL'S STD LEFT KEY C052 FEAE KST3: CPI 0AEH C054 C259C0 JNZ KST4 C057 3E13 MVI A,'S'-40H ;SOL'S STD RIGHT KEY C059 B7 KST4: ORA A ;MAKE IT NON-ZERO C05A C9 RET ;GO BACK WITH IT ; ; SERIAL INPUT DRIVER ; C05B DBF8 SSTAT: IN SERST ;GET SERIAL STATUS WORD C05D E640 ANI SDR ;TEST FOR SERIAL DATA READY C05F C8 RZ ;FLAGS ARE SET C060 DBF9 IN SDATA ;GET DATA BYTE C062 C9 RET ;WE HAVE IT ; ; SERIAL DATA OUTPUT ; C063 DBF8 SDROT: IN SERST ;GET PORT STATUS C065 17 RAL ;PUT HIGH BIT IN CARRY C066 D263C0 JNC SDROT ;LOOP TILL XMTR BUFFER IS EMPTY C069 78 MOV A,B ;GET THE CHARACTER BACK C06A D3F9 OUT SDATA ;SEND IT OUT C06C C9 RET ;AND WE'RE DONE ; ; PARALLEL INPUT DRIVER ; C06D DBFA PASTAT: IN STAPT C06F 2F CMA ;INVERT STATUS FLAGS C070 E602 ANI PDR ;TEST BIT C072 C8 RZ C073 DBFD IN PDATA ;GET DATA C075 C9 RET ; ; PARALLEL OUTPUT HANDLER ; C076 DBFA PROUT: IN STAPT ;GET STATUS C078 E604 ANI PXDR ;TEST IF DEVICE IS READY C07A C276C0 JNZ PROUT ;LOOP UNTIL GO C07D 78 MOV A,B ; C07E D3FD OUT PDATA C080 C9 RET ; ; COMBINATION ERROR/USER DEFINED I/O ROUTINES ; C081 E5 ERRIT: PUSH H ;SAVE H,L ONCE AGAIN C082 2A00C8 LHLD UIPRT ;GET USER INPUT PORT ADDRESS C085 C38CC0 JMP ERRO1 ;AND GO PROCESS C088 E5 ERROT: PUSH H ; C089 2A02C8 LHLD UOPRT ;GET USER OUTPUT PORT ADDRESS C08C 7D ERRO1: MOV A,L ;TEST HL FOR ZERO C08D B4 ORA H C08E CAF9C1 JZ RESIO ;IF ZERO RETURN TO COMMAND MODE C091 E3 XTHL ;ADDRESS TO STACK-OLD HL TO HL C092 C9 RET ;GO TO DRIVER ; ; VIDEO DISPLAY ROUTINES ; ; CHAR IN B; ALL REGS PRESERVED EXCEPT ACC. & PSW ; C093 E5 VDMOT: PUSH H ;SAVE MOST REGISTERS C094 D5 PUSH D C095 C5 PUSH B ; ; TEST IF ESC SEQUENCE HAS BEEN STARTED ; C096 3A0CC8 LDA ESCFL ;GET ESCAPE FLAG C099 B7 ORA A C09A C298C1 JNZ ESCS ;IF NON-ZERO GO PROCESS THE REST ; C09D 78 CHPCK: MOV A,B ;SAVE B - STRIP PARITY C09E E67F ANI 7FH ;CLR PARITY TO LOCATE IN TBL C0A0 47 MOV B,A ;KEEP IT W/OUT PARITY IN B TOO C0A1 CABBC0 JZ GOBK ;DO A QUICK EXIT IF A NULL C0A4 21A8C2 LXI H,TBL ;POINT TO SPECIAL CHARACTER TABLE C0A7 CDC1C0 CALL TSRCH ;GO PROCESS ; C0AA CD55C1 GOBACK: CALL VDADD ;GET SCREEN ADDRESS C0AD 7E MOV A,M ;GET PRESENT CURSOR CHARACTER C0AE F680 ORI 80H C0B0 77 MOV M,A ;CURSOR IS BACK ON C0B1 2A0AC8 LHLD SPEED-1 ;GET DELAY SPEED C0B4 2C INR L ;MAKE SURE IT IS NON-ZERO C0B5 AF XRA A ;DELAY WILL END WHEN H=0 C0B6 2B TIMER: DCX H ;TIMER DELAYS HERE C0B7 BC CMP H ;DONE WITH DELAY YET C0B8 C2B6C0 JNZ TIMER ;KEEP DELAYING C0BB C1 GOBK: POP B C0BC D1 POP D ;RESTORE REGISTERS C0BD E1 POP H C0BE C9 RET ;EXIT FROM VDMOT ; C0BF 23 NEXT: INX H C0C0 23 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. ; C0C1 7E TSRCH: MOV A,M ;GET CHR FROM TABLE C0C2 B7 ORA A C0C3 CAD3C0 JZ CHAR ;ZERO IS THE LAST C0C6 B8 CMP B ;TEST THE CHR C0C7 23 INX H ;POINT FORWARD C0C8 C2BFC0 JNZ NEXT C0CB E5 PUSH H ;FOUND ONE...SAVE ADDRESS C0CC CD6FC1 CALL CREM ;REMOVE CURSOR C0CF E3 XTHL ;GET DISPATCH ADDRESS TO HL C0D0 C35EC2 JMP DISPT ;DISPATCH NOW ; ; PUT CHARACTER TO SCREEN ; C0D3 CD55C1 CHAR: CALL VDADD ;GET SCREEN ADDRESS C0D6 70 MOV M,B ;PUT CHR ON SCREEN C0D7 3A08C8 LDA NCHAR ;GET CHARACTER POSITION C0DA FE3F CPI 63 ;END OF LINE? C0DC DAFCC0 JC OK C0DF 3A09C8 LDA LINE C0E2 FE0F CPI 15 ;END OF SCREEN? C0E4 C2FCC0 JNZ OK ; ; END OF SCREEN...ROLL UP ONE LINE ; C0E7 AF SCROLL: XRA A C0E8 3208C8 STA NCHAR ;BACK TO FIRST CHAR POSITION C0EB 4F SROL: MOV C,A C0EC CD5CC1 CALL VDAD ;CALCULATE LINE TO BE BLANKED C0EF AF XRA A C0F0 CD33C1 CALL CLIN1 ;CLEAR IT C0F3 3A0AC8 LDA BOT C0F6 3C INR A C0F7 E60F ANI 0FH C0F9 C327C1 JMP ERAS3 ; ; INCREMENT LINE COUNTER IF NECESSARY ; C0FC 3A08C8 OK: LDA NCHAR ;GET CHR POSITION C0FF 3C INR A C100 E63F ANI 3FH ;MOD 64 AND WRAP C102 3208C8 STA NCHAR C105 C0 RNZ ;DIDN'T HIT END OF LINE, OK C106 3A09C8 PDOWN: LDA LINE ;GET THE LINE COUNT C109 3C INR A C10A E60F CURSC: ANI 0FH ;STORE THE NEW C10C 3209C8 CUR: STA LINE ;STORE THE NEW C10F C9 RET ; ; ERASE SCREEN ; C110 2100CC PERSE: LXI H,VDMEM ;POINT TO SCREEN C113 36A0 MVI M,80H+' ' ;THIS IS THE CURSOR C115 23 INX H ;BUMP 1ST C116 3620 ERAS1: MVI M,' ' ;BLANK IT OUT C118 23 INX H ;NEXT C119 7C MOV A,H ;SEE IF END OF SCREEN YET C11A D6D0 SUI 0D0H C11C DA16C1 JC ERAS1 ;NO--KEEP BLANKING C11F 37 STC ;CARRY WILL SAY COMPLETE ERASE ; C120 210000 PHOME: LXI H,0 ; C123 2208C8 SHLD NCHAR ;COL 0 LINE 0 C126 D0 RNC ;NO CARRY ==> DONE WITH HOME ; C127 D3FE ERAS3: OUT DSTAT ;RESET SCROOL PARAMETERS C129 320AC8 STA BOT ;BEGINNING OF TEXT OFFSET C12C C9 RET ; C12D CD55C1 CLINE: CALL VDADD ;GET CURRENT SCREEN ADDRESS C130 3A08C8 LDA NCHAR ;CURRENT CURSOR POSITION C133 FE40 CLIN1: CPI 64 ;NO MORE THAN 63 C135 D0 RNC ;ALL DONE C136 3620 MVI M,' ' ;ALL SPACED OUT C138 23 INX H C139 3C INR A C13A C333C1 JMP CLIN1 ;LOOP TO END OF LINE ; ; ROUTINE TO MOVE THE CURSOR UP ONE LINE ; C13D 3A09C8 PUP: LDA LINE ;GET LINE COUNT C140 3D DCR A C141 C30AC1 JMP CURSC ;MERGE TO HANDLE CURSOR ; ; MOVE CURSOR LEFT ONE POSITION ; C144 3A08C8 PLEFT: LDA NCHAR C147 3D DCR A C148 E63F PCUR: ANI 3FH ;LET CURSOR WRAP C14A 3208C8 STA NCHAR ;UPDATED CURSOR C14D C9 RET ; ; CURSOR RIGHT ONE POSITION ; C14E 3A08C8 PRIT: LDA NCHAR C151 3C INR A C152 C348C1 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' ; C155 3A08C8 VDADD: LDA NCHAR ;GET CHARACTER POSITION C158 4F MOV C,A ;'C' KEEPS IT C159 3A09C8 VDAD2: LDA LINE ;LINE POSITION C15C 6F VDAD: MOV L,A ;INTO 'L' C15D 3A0AC8 LDA BOT ;GET TEXT OFFSET C160 85 ADD L ;ADD IT TO THE LINE POSITION C161 0F RRC ;TIMES TWO C162 0F RRC ;MADES FOUR C163 6F MOV L,A ;L HAS IT C164 E603 ANI 3 ;MOD THREE FOR LATER C166 C6CC ADI VDMEM SHR 8 ;LOW SCREEN OFFSET C168 67 MOV H,A ;NOW H IS DONE C169 7D MOV A,L ;TWIST L'S ARM C16A E6C0 ANI 0C0H C16C 81 ADD C C16D 6F MOV L,A C16E C9 RET ;H & L ARE NOW PERVERTED ; ; ROUTINE TO REMOVE CURSOR ; C16F CD55C1 CREM: CALL VDADD ;GET CURRENT SCREEN ADDRESS C172 7E MOV A,M C173 E67F ANI 7FH ;STRIP OFF THE CURSOR C175 77 MOV M,A C176 C9 RET ; ; ROUTINE TO BACKSPACE ; C177 CD44C1 PBACK: CALL PLEFT C17A CD55C1 CALL VDADD ;GET SCREEN ADDRESS C17D 3620 MVI M,' ' ;PUT A BLANK THERE C17F C9 RET ; ; ROUTINE TO PROCESS A CARRIAGE RETURN ; C180 CD2DC1 PCR: CALL CLINE ;REWIND TO BEGINNING OF LINE C183 C348C1 JMP PCUR ;AND STORE THE NEW VALUE ; ; ROUTINE TO PROCESS A LINEFEED ; C186 3A09C8 PLF: LDA LINE ;GET LINE COUNT C189 3C INR A C18A E60F ANI 15 ;SEE IF IT WRAPPED AROUND C18C C20CC1 JNZ CUR ;NO--NO NEED TO SCROLL C18F C3EBC0 JMP SROL ;YES--THEN SCROLL ; ; SET ESCAPE PROCESS FLAG ; C192 3EFF PESC: MVI A,0FFH C194 320CC8 STA ESCFL ;SET FLAG C197 C9 RET ; ; PROCESS ESCAPE SEQUENCE ; C198 CD6FC1 ESCS: CALL CREM ;REMOVE CURSOR C19B CDA1C1 CALL ESCSP ;PROCESS NEXT PART OF SEQUENCE C19E C3AAC0 JMP GOBACK C1A1 3A0CC8 ESCSP: LDA ESCFL ;GET ESCAPE FLAG C1A4 FEFF CPI 0FFH ;TEST FLAG C1A6 CAC9C1 JZ SECOND ; ; PROCESS THIRD CHR OF ESC SEQUENCE ; C1A9 210CC8 LXI H,ESCFL C1AC 3600 MVI M,0 ;NO MORE PARTS TO THE SEQUENCE C1AE FE02 CPI 2 C1B0 DAC1C1 JC SETX ;SET X IF IS ONE C1B3 CAC5C1 JZ SETY ;SET Y IF IS TWO C1B6 FE08 CPI 8 C1B8 CAE9C5 JZ STSPD ;SET NEW DISPLAY SPEED IF "8" C1BB FE09 CPI 9 C1BD DAD3C0 JC CHAR ;PUT IT ON THE SCREEN C1C0 C0 RNZ ; ; TAB ABSOLUTE TO VALUE IN REG B ; C1C1 78 SETX: MOV A,B ;GET CHARACTER C1C2 C348C1 JMP PCUR ; ; SET CURSOR TO LINE "B" ; C1C5 78 SETY: MOV A,B C1C6 C30AC1 JMP CURSC ; ; PROCESS SECOND CHR OF ESC SEPUENCE ; C1C9 78 SECOND: MOV A,B ;GET WHICH C1CA FE03 CPI 3 C1CC CADFC1 JZ CURET ;RETURN CURSOR PARAMETERS C1CF FE04 CPI 4 C1D1 C2DBC1 JNZ ARET2 ; ; ESC <4> RETURN ABSOLUTE SCREEN ADDRESS ; C1D4 44 ARET: MOV B,H C1D5 4D MOV C,L ;SCRN ADDRESS TO BC FOR RETURN C1D6 E1 ARET1: POP H ;RETURN ADDRESS C1D7 D1 POP D ;OLD B C1D8 C5 PUSH B C1D9 E5 PUSH H C1DA AF XRA A C1DB 320CC8 ARET2: STA ESCFL C1DE C9 RET ; ; RETURN PRESENT SCREEN PARAMETERS IN "BC" ; C1DF 2108C8 CURET: LXI H,NCHAR C1E2 46 MOV B,M ;CHARACTER POSITION C1E3 23 INX H C1E4 4E MOV C,M ;LINE POSITION C1E5 C3D6C1 JMP ARET1 ; ; ***** START UP SYSTEM ***** ; ; CLEAR SCREEN AND THE FIRST 256 BYTES OF GLOBAL RAM ; THEN ENTER THE COMMAND MODE ; C1E8 AF STRTA: XRA A C1E9 4F MOV C,A C1EA 2100C8 LXI H,SYSRAM ;CLEAR THE FIRST PAGE C1ED 77 CLERA: MOV M,A C1EE 23 INX H C1EF 0C INR C C1F0 C2EDC1 JNZ CLERA C1F3 3100CC LXI SP,SYSTP ;SET UP THE STACK FOR CALL C1F6 CD10C1 CALL PERSE C1F9 AF RESIO: XRA A ; C1FA 3207C8 STA OPORT C1FD 3206C8 STA IPORT C200 AF COMN1: XRA A C201 D3FA OUT STAPT ;BE SURE TAPES ARE OFF ; ; ***** COMMAND MODE ***** ; ; THIS ROUTINE GETS AND PROCESSES COMMANDS ; C203 3100CC COMND: LXI SP,SYSTP ;SET STACK POINTER C206 3A07C8 LDA OPORT ;GET PORT C209 F5 PUSH PSW ;SAVE IT C20A AF XRA A ;MAKE VDM-1 C20B 3207C8 STA OPORT ;THE CURRENT OUTPUT PORT C20E CDFFC2 CALL PROMPT ;PUT PROMPT ON SCREEN C211 CD1EC2 CALL GCLIN ;GET COMMAND LINE C214 F1 POP PSW ;GET PORT BACK C215 3207C8 STA OPORT ;RESTORE IT C218 CD3FC2 CALL COPRC ;PROCESS THE LINE C21B C303C2 JMP COMND ;OVER AND OVER ; ; THIS ROUTINE READS A COMMAND LINE ; FROM THE SYSTEM KEYBOARD ; ; C/R TERMINATES THE SEQUENCE ERASING ALL ; CHARS TO THE RIGHT OF THE CURSOR ; L/F TERMINATES THE SEQUENCE ; MODE RESTARTS THE COMMAND LINE ; C21E CD1FC0 GCLIN: CALL SINP ;READ INPUT DEVICE C221 CA1EC2 JZ GCLIN C224 E67F ANI 7FH ;CLEAR PARITY BIT C226 CA00C2 JZ COMN1 ;THIS WAS A MODE (OR EVEN CTRL-@) C229 47 MOV B,A C22A FE0D CPI CR ;CARRIAGE RETURN C22C CA2DC1 JZ CLINE ;YES--DONE WITH LINE C22F FE0A CPI LF ;LINE FEED C231 C8 RZ ;YES--DONE WITH LINE, LEAVE AS IS C232 FE7F CPI 7FH ;DELETE CHR? C234 C239C2 JNZ CONT C237 065F MVI B,BACKS ;REPLACE IT C239 CD19C0 CONT: CALL SOUT C23C C31EC2 JMP GCLIN ; ; FIND AND PROCESS COMMAND ; C23F CD6FC1 COPRC: CALL CREM ;REMOVE THE CURSOR C242 0E01 MVI C,1 ;SET FOR CHARACTER POSITION C244 CD59C1 CALL VDAD2 ;GET SCREEN ADDRESS C247 EB XCHG C248 2100C0 LXI H,START ;MAKE SURE HL PT TO SOLOS START C24B E5 PUSH H ;SAVE IT FOR LATER DISPT C24C CD2FC3 CALL SCHR ;SCAN PAST BLANKS C24F CAEBC4 JZ ERR1 ;NO COMMAND? C252 EB XCHG ;HL HAS FIRST CHR C253 117BC2 LXI D,COMTAB ;POINT TO COMMAND TABLE C256 CD69C2 CALL FDCOM ;SEE IF IN PRIMARY COMMAND TABLE C259 CAECC4 DISPO: JZ ERR2 ;NOT VALID, ERROR C25C 13 INX D ;BUMP TO PTR OF RTN C25D EB 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. ; C25E 7E DISPT: MOV A,M ;LO ADDR C25F 23 INX H C260 66 MOV H,M ;HI ADDR C261 6F MOV L,A ;HL NOW COMPLETE C262 E3 DISP1: XTHL ;XCHG HL W/HL ON STACK C263 7D MOV A,L ;ALSO COPY HERE FOR SETS C264 C9 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. ; ; (ENTRY IS AT FDCOM) ; C265 13 NCOM: INX D ;GO TO NEXT ENTRY C266 13 INX D C267 13 INX D C268 E1 POP H ;GET BACK ORIG. ADDR C269 1A FDCOM: LDAX D C26A B7 ORA A ;TEST FOR TABLE END C26B C8 RZ ;NOT FOUND..COMMAND ERROR C26C E5 PUSH H ;SAVE START OF SCAN ADDRESS C26D BE CMP M ;TEST FIRST CHR C26E 13 INX D C26F C265C2 JNZ NCOM C272 23 INX H C273 1A LDAX D C274 BE CMP M ;NOW SECOND CHARACTER C275 C265C2 JNZ NCOM ;GOODNESS C278 E1 POP H ;RESTORE ORIGINAL SCAN ADDR C279 B7 ORA A ;SET NON-ZERO FLAG SAYING FOUND C27A C9 RET ;WITH NON-ZERO SET ; ; ***** COMMAND TABLE ***** ; ; THIS TABLE DESCRIBES THE VALID COMMANDS FOR SOLOS ; C27B 4455 COMTAB: DW 'DU' ;DUMP C27D 66C3 DW DUMP C27F 454E DW 'EN' ;ENTER C281 15C4 DW ENTER C283 4558 DW 'EX' ;EXECUTE C285 50C4 DW EXEC C287 4745 DW 'GE' ;GET A FILE C289 FAC4 DW TLOAD C28B 5341 DW 'SA' ;SAVE A FILE C28D 39C5 DW TSAVE C28F 5845 DW 'XE' ;AUTO-EXECUTE A FILE C291 F9C4 DW TXEQ C293 4341 DW 'CA' ;CATALOG OF TAPE FILES C295 7EC5 DW TLIST C297 5345 DW 'SE' ;SET COMMAND C299 CBC5 DW CSET C29B 4350 DW 'CP' ;CP/M COMMAND C29D A1C4 DW CPM C29F 4D54 DW 'MT' ;MEMORY TEST C2A1 58C4 DW MTEST C2A3 4444 DW 'DD' ;DDT RST 7 RETURN TO CP/M DDT C2A5 FFC7 DW DDT C2A7 00 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. ; C2A8 0B TBL: DB CLEAR-80H ;CLEAR SCREEN C2A9 10C1 DW PERSE C2AB 17 DB UP-80H ;UP CURSOR C2AC 3DC1 DW PUP C2AE 1A DB DOWN-80H ;DOWN CURSOR C2AF 06C1 DW PDOWN C2B1 01 DB LEFT-80H ;LEFT CURSOR C2B2 44C1 DW PLEFT C2B4 13 DB RIGHT-80H ;RIGHT CURSOR C2B5 4EC1 DW PRIT C2B7 0E DB HOME-80H ;HOME CURSOR C2B8 20C1 DW PHOME C2BA 0D DB CR ;CARRIAGE RETURN C2BB 80C1 DW PCR C2BD 0A DB LF ;LINE FEED C2BE 86C1 DW PLF C2C0 5F DB BACKS ;BACKSPACE C2C1 77C1 DW PBACK C2C3 1B DB ESC ;ESCAPE KEY C2C4 92C1 DW PESC C2C6 08 DB 08H ;ADDED STD ASCII BACKSPACE C2C7 44C1 DW PLEFT ;FOR CP/M C2C9 00 DB 0 ;END OF TABLE ; ; OUTPUT DEVICE TABLE ; C2CA 93C0 OTAB: DW VDMOT ;VDM DRIVER C2CC 63C0 DW SDROT ;SERIAL OUTPUT C2CE 76C0 DW PROUT ;PARALLAL OUTPUT C2D0 88C0 DW ERROT ;ERROR OR USER DRIVER HANDLER ; ; INPUT DEVICE TABLE ; C2D2 35C0 ITAB: DW KSTAT ;KEYBOARD INPUT C2D4 5BC0 DW SSTAT ;SERIAL INPUT C2D6 6DC0 DW PASTAT ;PARALLEL INPUT C2D8 81C0 DW ERRIT ;ERROR OR USER DRIVER HANDLER ; ; SECONDARY COMMAND TABLE FOR SET COMMAND ; C2DA 5441 SETAB: DW 'TA' ;SET TAPE SPEED C2DC DFC5 DW TASPD C2DE 533D DW 'S=' ;SET DISPLAY SPEED C2E0 EAC5 DW DISPD C2E2 493D DW 'I=' ;SET INPUT PORT C2E4 EEC5 DW SETIN C2E6 4F3D DW 'O=' ;SET OUTPUT PORT C2E8 F2C5 DW SETOT C2EA 4349 DW 'CI' ;SET CUSTOM DRIVER ADDRESS C2EC F6C5 DW SETCI C2EE 434F DW 'CO' ;SET CUSTOM OUTPUT DRIVER ADDRESS C2F0 FAC5 DW SETCO C2F2 5845 DW 'XE' ;SET HEADER XEQ ADDRESS C2F4 02C6 DW SETXQ C2F6 5459 DW 'TY' ;SET HEADER TYPE C2F8 FEC5 DW SETTY C2FA 4352 DW 'CR' ;SET TO ALLOW CRC ERRORS C2FC 06C6 DW SETCR C2FE 00 DB 0 ;END OF TABLE MARK ; ; OUTPUT A CR/LF FOLLOWED BY A PROMPT ; C2FF CD07C3 PROMPT: CALL CRLF C302 063E MVI B,'>' ;THE PROMPT C304 C319C0 JMP SOUT ;PUT IT ON THE SCREEN ; C307 060A CRLF: MVI B,LF ;LINE FEED C309 CD19C0 CALL SOUT C30C 060D MVI B,CR ;CARRIAGE RETURN C30E C319C0 JMP SOUT ; ; 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. ; C311 CD1CC3 PSCAN: CALL SBLK C314 3E01 MVI A,1 ;DEFAULT VALUE C316 C8 RZ ;IF NONE C317 CD41C3 CALL SHEX ;CONVERT VALUE C31A 7D MOV A,L ;GET LOWER HALF C31B C9 RET ; ; SCAN OVER UP TO 12 CHARACTERS LOOKING FOR A BLANK ; C31C 0E0C SBLK: MVI C,12 ;MAXIMUM COMMAND STRING C31E 1A SBLK1: LDAX D C31F FE20 CPI BLANK C321 CA2FC3 JZ SCHR ;GOT A BLANK NOW SCAN PAST IT C324 13 INX D C325 FE3D CPI '=' ;ALSO ALLOW EQUAL TO STOP US C327 CA2FC3 JZ SCHR ;IF SO, PTR AT CHAR FOLLOWING C32A 0D DCR C ;NO MORE THAN TWELVE C32B C21EC3 JNZ SBLK1 C32E C9 RET ;GO BACK WITH ZERO FLAG SET ; ; SCAN PAST UP TO 10 BLANK POSITIONS LOOKING FOR ; A NON-BLANK CHARACTER ; C32F 0E0A SCHR: MVI C,10 ;SCAN TO FIRST NONBLANK CHR IN 10 C331 1A SCHR1: LDAX D ;GET NEXT CHARACTER C332 FE20 CPI SPACE C334 C0 RNZ ;WE'RE PAST THEM C335 13 INX D ;NEXT SCAN ADDRESS C336 0D DCR C C337 C8 RZ ;COMMAND ERROR C338 C331C3 JMP SCHR1 ;KEEP LOOPING ; ; THIS ROUTINE SCANS OVER CHARACTERS, PAST BLANKS AND ; CONVERTS THE FOLLOWING VALUE TO HEX. ERRORS RETURN TO ; THE ERROR HANDLER. ; C33B CD1CC3 SCONV: CALL SBLK ;FIND IF VALUE IS PRESENT C33E CAEBC4 JZ ERR1 ;ABORT TO ERROR IF NONE ; ; ASCII TO BINARY CONVERSION ; C341 210000 SHEX: LXI H,0 ;CLEAR H & L C344 1A SHE1: LDAX D ;GET CHARACTER C345 FE20 CPI 20H ;IS IT A SPACE C347 C8 RZ ;IF SO C348 FE2F CPI '/' ;SLASH IS ALSO LEGAL C34A C8 RZ C34B FE3A CPI ':' ;EVEN THE COLON IS ALLOWED C34D C8 RZ C34E 29 HCONV: DAD H ;MAKE ROOM FOR THE NEW ONE C34F 29 DAD H C350 29 DAD H C351 29 DAD H C352 D630 SUI 30H ;REMOVE ASCII BIAS C354 FE0A CPI 0AH C356 DA5DC3 JC HCOV1 C359 D607 SUI 7 ;IF ITS A LETTER C35B FE10 CPI 10H C35D D2EBC4 HCOV1: JNC ERR1 ;NOT VALID HEXIDECIMAL VALUE C360 85 ADD L C361 6F MOV L,A ;MOVE IT IN C362 13 INX D ;BUMP THE POINTER C363 C344C3 JMP SHE1 ; ; ***** DUMP COMMAND ***** ; C366 CD3BC3 DUMP: CALL SCONV ;SCAN 1ST ADDR AND CONVERT IT C369 E5 PUSH H ;SAVE THE VALUE C36A CD11C3 CALL PSCAN ;SEE IF SECOND WAS GIVIN C36D D1 POP D C36E EB XCHG ;HL HAS START, DE HAS END C36F E5 DLOOP: PUSH H ;SAVE H,L C370 213CC8 LXI H,ASCDA ;POINT TO ASCII BUILD UP AREA C373 2204C8 SHLD ASPTR ;INITIALIZE POINTER C376 E1 POP H ;RESTORE REGISTER C377 CD07C3 CALL CRLF C37A CDD5C3 CALL ADOUT ;OUTPUT ADDRESS C37D CDF8C3 CALL BOUT ;ANOTHER SPACE - KEEP IT PRETTY C380 0E08 MVI C,8 ;VALUES PER LINE C382 7E DLP1: MOV A,M ;GET THE CHAR C383 C5 PUSH B ;SAVE VALUE COUNT C384 CDFDC3 CALL HEOUT ;SEND IT OUT C387 CDB5C3 CALL ASBLD ;BUILD ASCII C38A 23 INX H ;POINT TO NEXT C38B 7E MOV A,M ;GET THE CHAR C38C CDDAC3 CALL HBOUT ;SEND IT OUT WITH A BLANK C38F CDB5C3 CALL ASBLD ;BUILD ASCII C392 C1 POP B ;VALUES PER LINE C393 23 INX H C394 0D DCR C ;BUMP THE LINE COUNT C395 C282C3 JNZ DLP1 ;NOT ZERO IF MORE FOR THIS LINE ; ;PRINT THE BUILT UP ASCII ; C398 E5 ASOUT: PUSH H ;SAVE H,L C399 213CC8 LXI H,ASCDA ;POINT TO ASCII DATA C39C 0E10 MVI C,16 C39E CDF8C3 CALL BOUT C3A1 46 ASOU1: MOV B,M ;GET ASCII CHAR C3A2 CD19C0 CALL SOUT C3A5 23 INX H ;POINT TO NEXT ASCII CHAR C3A6 0D DCR C ;DCR COUNT C3A7 C2A1C3 JNZ ASOU1 C3AA E1 POP H ;RESTORE REGS C3AB 7D CK4END: MOV A,L ;COMPARE DE & HL - CHECK DONE C3AC 93 SUB E C3AD 7C MOV A,H C3AE 9A SBB D C3AF DA6FC3 JC DLOOP ;NOT DONE C3B2 C303C2 JMP COMND ;ALL DONE ; ;ASCII BUILD FOR THE ASCII PART OF THE DUMP ; C3B5 E5 ASBLD: PUSH H ;SAVE H,L C3B6 2A04C8 LHLD ASPTR ;GET ASCII POINTER C3B9 79 MOV A,C ;GET THE CHAR C3BA FE20 CPI 20H ;CNTL CHAR ? C3BC DACCC3 JC NOPRT ;NOT IF THERE WASN'T A CARRY C3BF FE7F CPI 7FH ;CHECK DELETES OR HIGH CONTROLS C3C1 D2CCC3 JNC NOPRT ;DON'T PRINT THEM C3C4 FE5F CPI 5FH ;CHECK FOR LEFT ARROW C3C6 CACCC3 JZ NOPRT ;DON'T PRINT IT C3C9 C3CEC3 JMP OKYDOK ;PRINT CHAR IF NONE OF ABOVE C3CC 3E2E NOPRT: MVI A,'.' ;SUBSTITUTE '.' FOR CNTL CHAR C3CE 77 OKYDOK: MOV M,A ;PUT CHAR IN BUFFER C3CF 23 INX H ;INR BUFFER C3D0 2204C8 SHLD ASPTR ;SAVE POINTER C3D3 E1 POP H ;RESTORE H C3D4 C9 RET ;DONE BUILDING ; ; OUTPUT HL AS HEX 16 BIT VALUE ; C3D5 7C ADOUT: MOV A,H ;H FIRST C3D6 CDFDC3 CALL HEOUT C3D9 7D MOV A,L ;THEN L FOLLOWED BY A SPACE C3DA CDFDC3 HBOUT: CALL HEOUT C3DD CD1FC0 CALL SINP ;SEE IF A CHAR WAITING C3E0 CAF8C3 JZ BOUT ;NO C3E3 E67F ANI 7FH ;CLR PARITY FIRST THO C3E5 CA03C2 JZ COMND ;EITHER MODE OR CTRL-@ C3E8 FE13 CPI 'S'-40H ;IS IT A CNTL S C3EA CAF2C3 JZ WTLP1 ;NO...IGNORE THE CHAR C3ED FE20 CPI ' ' ;SPACE ? C3EF C2F8C3 JNZ BOUT ;IGNORE THAT, TOO C3F2 CD1FC0 WTLP1: CALL SINP ;WAIT UNTIL KEY HIT C3F5 CAF2C3 JZ WTLP1 ;THIS ALLOWS LOOKING AT THE DISPLAY C3F8 0620 BOUT: MVI B,' ' C3FA C319C0 JMP SOUT ;PUT IT OUT ; C3FD 4F HEOUT: MOV C,A ;GET THE CHARACTER C3FE 0F RRC ;MOVE THE HIGH FOUR DOWN C3FF 0F RRC C400 0F RRC C401 0F RRC C402 CD06C4 CALL HEOU1 ;PUT THEM OUT C405 79 MOV A,C ;THIS TIME THE LOW FOUR C406 E60F HEOU1: ANI 0FH ;FOUR ON THE FLOOR C408 C630 ADI 48 ;WE WORK WITH ASCII HERE C40A FE3A CPI 58 ;0-9? C40C DA11C4 JC OUTH ;YUP C40F C607 ADI 7 ;MAKE IT A LETTER C411 47 OUTH: MOV B,A ;OUTPUT IT FROM REGISTER 'B' C412 C319C0 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. ; C415 CD3BC3 ENTER: CALL SCONV ;SCAN OVER CHARS AND GET ADDRESS C418 E5 PUSH H ;SAVE ADDRESS C419 AF XRA A C41A 3207C8 STA OPORT ;ENTER VALUES TO SCREEN BUFFER ; C41D CD07C3 ENLOP: CALL CRLF C420 063A MVI B,':' C422 CD39C2 CALL CONT ;GET LINE OF INPUT C425 CD6FC1 CALL CREM ;REMOVE THE CURSOR C428 0E01 MVI C,1 ;START SCAN C42A CD59C1 CALL VDAD2 ;GET ADDRESS C42D EB XCHG ;....TO DE ; ; C42E 0E03 ENLO1: MVI C,3 ;MAX 3 SPACES BETWEEN VALUES C430 CD31C3 CALL SCHR1 ;SCAN TO NEXT VALUE C433 CA1DC4 JZ ENLOP ;LAST ENTRY FOUND, START NEW LINE ; C436 FE2F CPI '/' ;COMMAND TERMINATOR C438 CA00C2 JZ COMN1 ;IF SO, RETURN TO STANDARD INPUT C43B CD41C3 CALL SHEX ;CONVERT VALUE C43E FE3A CPI ':' ;ADDRESS TERMINATOR C440 CA4BC4 JZ ENLO3 ;GO PROCESS IF SO C443 7D MOV A,L ;GET LOW PART AS CONVERTED C444 E1 POP H ;GET MEMORY ADDRESS C445 77 MOV M,A ;PUT IN THE VALUE C446 23 INX H C447 E5 PUSH H ;BACK GOES THE ADDRESS C448 C32EC4 JMP ENLO1 ;CONTINUE THE SCAN ; C44B E3 ENLO3: XTHL ;PUT NEW ADDRESS ON STACK C44C 13 INX D ;MOVE SCAN PAST TERMINATOR C44D C32EC4 JMP ENLO1 ; ; ***** EXECUTE COMMAND ***** ; C450 CD3BC3 EXEC: CALL SCONV ;SCAN PAST BLANKS & GET PARMS C453 E5 EXEC1: PUSH H ;PUT GO ADDRESS ON STACK C454 2100C0 LXI H,START ;TELL PROGRAM WHERE WE CAME FROM C457 C9 RET ;AND DISPATCH IT ; ;MEMORY TEST PGM ; C458 CD3BC3 MTEST: CALL SCONV ;GET 1ST ADDR C45B 220EC8 SHLD STRT ;SAVE AT START ADDR C45E CD11C3 CALL PSCAN ;GET 2ND ADDR C461 EB XCHG C462 13 INX D ; C463 AF XRA A ;GET A ZERO C464 3212C8 STA PATT ;SAVE AS PATTERN C467 4F MOV C,A ;TO C C468 2A0EC8 LHLD STRT ;START ADDR TO H,L C46B 71 WRO: MOV M,C ;STORE C IN MEMORY C46C 23 INX H ;POINT TO NEXT LOC TO TEST C46D CD9BC4 CALL CHECK ;SEE IF END C470 DA6BC4 JC WRO ;IF NOT DONE C473 2A0EC8 TRST: LHLD STRT ;START OVER C476 7E RCW: MOV A,M ;READ A BYTE C477 B9 CMP C ;SAME AS EXPECTED ? C478 CA8AC4 JZ GOOD ;YES - SKIP ERR. STUFF C47B 2214C8 SHLD ERRADR ;NO - SAVE BAD ADDR C47E 3213C8 STA DATERR ;SAVE BAD DATA C481 2112C8 LXI H,PATT ;H,L POINT TO START OF DUMP AREA C484 110EC8 LXI D,STRT ;D,E POINT TO END C487 C36FC3 JMP DLOOP ;DO A DUMP C48A 3C GOOD: INR A ;GO TO NEXT PATTERN C48B 77 MOV M,A ;READ TO SAVE TIME C48C 23 INX H ;WHERE TO LOOK NEXT C48D CD9BC4 CALL CHECK ;CHECK FOR END C490 DA76C4 JC RCW ;IF NOT, CONTINUE C493 0C INR C ;INCREMENT PATTERN C494 79 MOV A,C ;TO A C495 3212C8 STA PATT ;FOR REFERENCE C498 C373C4 JMP TRST ;START AGAIN ; ;TEST FOR END OF TEST RANGE ; C49B 7C CHECK: MOV A,H ;GET HIGH ORDER BYTE C49C BA CMP D ;CHECK HIGH ADDR C49D D8 RC ;RET IF NOT DONE WITH CARRY SET C49E 7D MOV A,L ;HIGH BYTES SAME - CHECK LOWS C49F BB CMP E ; C4A0 C9 RET ; ;CPM DISK BOOTSTRAP COMMAND ; C4A1 3EB2 CPM: MVI A,0B2H ;SEL DISK 0 & HARDWARE RESTORE C4A3 D3EC OUT WAIT ;DO IT C4A5 3E03 MVI A,3 ;LOWEST SPEED 1771 HOME COMND C4A7 D3E8 OUT DCOM ;ISSUE IT C4A9 DBEC IN WAIT ;WAIT FOR COMPLETE C4AB 3EF2 MVI A,0F2H ;DISK 0 SELECT COMMAND C4AD D3EC OUT WAIT ;ISSUE IT C4AF AF XRA A ;GET A ZERO C4B0 6F MOV L,A ;L=0 C4B1 67 MOV H,A ;H=0 C4B2 E5 PUSH H ;0 IS BOOT ENTRY POINT C4B3 3C INR A ;A=1 C4B4 D3EA OUT SECT ;SECTOR=1 C4B6 3E8C MVI A,8CH ;READ SECTOR COMMAND C4B8 D3E8 OUT DCOM ;ISSUE IT TO 1771 C4BA DBEC RLOOP: IN WAIT ;WAIT FOR DRQ OR INTRQ C4BC B7 ORA A ;SET FLAGS C4BD F2C7C4 JP RDONE ;DONE IF INTRQ C4C0 DBEB IN DDATA ;GET A BYTE FROM THE DISK C4C2 77 MOV M,A ;STASH IT C4C3 23 INX H ;INR POINTER C4C4 C3BAC4 JMP RLOOP ;DO IT AGAIN C4C7 DBE8 RDONE: IN DSKST ;READ DISK STATUS C4C9 B7 ORA A ;SET FLAGS C4CA C8 RZ ;JUMP TO BOOTSTRAP IF ZERO C4CB 4F MOV C,A ;SAVE STATUS C4CC CD07C3 CALL CRLF C4CF 79 MOV A,C ;GET BACK STATUS C4D0 CDDAC3 CALL HBOUT ;PRINT IT C4D3 C303C2 JMP COMND ;BACK TO SOLOS ; ; THIS ROUTINE GETS A NAME OF UP TO 5 CHARS ; C4D6 211CC8 NAMES: LXI H,THEAD ;POINT TO INTERNAL HEADER C4D9 CD1CC3 NAME: CALL SBLK ;SCAN OVER TO FIRST CHRS C4DC 0606 MVI B,6 ;UP TO SIX ARE ACCEPTED C4DE 1A NAME1: LDAX D ;GET CHARACTER C4DF FE20 CPI ' ' ;NO UNIT DELIMITER C4E1 CAF1C4 JZ NFIL C4E4 77 MOV M,A C4E5 13 INX D ;BUMP THE SCAN POINTER C4E6 23 INX H C4E7 05 DCR B C4E8 C2DEC4 JNZ NAME1 ;FALL THRU IF TOO MANY CHARS ; ; ***** SOLOS ERROR HANDLER ***** ; C4EB EB ERR1: XCHG ;GET SCAN ADDRESS TO HL C4EC 363F ERR2: MVI M,'?' ;PUT QUESTION MARK ON SCREEN C4EE C300C2 JMP COMN1 ;AND RETURN TO COMMAND MODE ; ; ZERO FILL NAMES LESS THAN 5 CHARS. ; C4F1 3600 NFIL: MVI M,0 ;PUT IN AT LEAST ONE ZERO C4F3 23 INX H C4F4 05 DCR B C4F5 C2F1C4 JNZ NFIL ;LOOP UNTIL B IS ZERO C4F8 C9 RET ; ; THIS ROUTINE PROCESSES THE XEQ AND GET COMMANDS ; C4F9 3E TXEQ: DB 3EH ;THIS BEGINS "MVI A,0AFH" C4FA AF TLOAD: XRA A ;A=0 MEANS TLOAD, ELSE TXEQ C4FB F5 PUSH PSW ;SAVE FLAG FOR LATER C4FC 212CC8 LXI H,DHEAD ;PLACE DUMMY HEADER HERE C4FF CDD9C4 CALL NAME ;SET IN NAME AND UNIT C502 210000 LXI H,0 ;PRETEND NO SECOND VALUE C505 CD11C3 CALL PSCAN ;GO GET THE ADDRESS (IF PRESENT) C508 EB TLOA2: XCHG ;PUT ADDRESS IN DE C509 212CC8 LXI H,DHEAD ;POINT TO DUMMY HDR W/NAME TO LOAD C50C 7E MOV A,M ;SEE IF A NAME WAS ENTERED C50D B7 ORA A ;IS THERE A NAME? C50E C214C5 JNZ TLOA3 ;YES...SEARCH FOR IT C511 211CC8 LXI H,THEAD ;NO NAME, LOAD 1ST FILE C514 E5 TLOA3: PUSH H ;SAVE PTR TO NAME TO LOAD C515 CD9BC5 CALL ALOAD ;GET UNIT AND SPEED C518 E1 POP H ;RESTORE PTR TO HDR TO LOAD C519 CDFEC6 CALL RTAPE ;READ IN THE TAPE C51C DA67C5 JC TAERR ;TAPE ERROR? C51F CDA1C5 CALL NAOUT ;PUT OUT THE HEADER PARMS C522 F1 POP PSW ;RESTORE FLAG FROM ORIGINAL ENTRY C523 B7 ORA A C524 C8 RZ ;AUTO XEQ NOT WANTED C525 3A22C8 LDA HTYPE ;CHECK TYPE C528 B7 ORA A ;SET FLAGS C529 FA67C5 JM TAERR ;TYPE IS NOW XEQ C52C 3A21C8 LDA THEAD+5 ;GET CHARACTER PAST NAME C52F B7 ORA A C530 C267C5 JNZ TAERR ;BYTE MUST = 0 FOR AUTO XEQ C533 2A27C8 LHLD XEQAD ;GET THE TAPE ADDRESS C536 C353C4 JMP EXEC1 ;AND GO TO IT ; ; ***** SAVE COMMAND ***** ; C539 CDD6C4 TSAVE: CALL NAMES ;GET NAME AND UNIT C53C CD3BC3 CALL SCONV ;GET START ADDRESS C53F E5 PUSH H ;USE THE STACK AS A REGISTER C540 CD3BC3 CALL SCONV ;GET END ADDRESS C543 E3 XTHL ;END ON STACK, GET BACK START C544 E5 PUSH H ;SAVE START ON TOP OF STACK C545 CD11C3 CALL PSCAN ;OPT. HEADER ADDR GIVEN ? C548 2225C8 SHLD LOADR ;PUT HEADER ADDRESS IN PLACE C54B E1 POP H ;"FROM" ADDRESS TO HL C54C D1 POP D ;GET BACK END ADDRESS C54D E5 PUSH H ;SAVE FROM AGAIN FOR LATER C54E 7B MOV A,E ;NOW CALCULATE SIZE C54F 95 SUB L ;SIZE=END-START+1 C550 6F MOV L,A C551 7A MOV A,D C552 9C SBB H C553 67 MOV H,A C554 23 INX H C555 2223C8 SHLD BLOCK ;STORE THE SIZE C558 E5 PUSH H ;SAVE IT FOR THE READ ALSO C559 CD9BC5 CALL ALOAD ;GET UNIT AND SPEED C55C 211CC8 LXI H,THEAD ;POINT TO HEADER C55F CDAFC7 CALL WHEAD ;AND WRITE IT OUT ; NOW WRITE OUT THE DATA C562 D1 POP D ;GET SIZE TO DE C563 E1 POP H ;GET BACK "FROM" ADDRESS C564 C3D5C6 JMP WRLO1 ;WRITE OUT THE DATA AND RETURN ; ; OUTPUT ERROR AND HEADER ; C567 CD07C3 TAERR: CALL CRLF C56A 1606 MVI D,6 C56C 2178C5 LXI H,ERRM ;POINT TO ERROR MESSAGE C56F CDBBC5 CALL NLOOP ;OUTPUT ERROR C572 CDA1C5 CALL NAOUT ;THEN THE HEADER C575 C300C2 JMP COMN1 ;AND TURN TAPE UNITS OFF ; C578 4552524F52ERRM: DB 'ERROR ' ; ; CATALOG COMMAND ; C57E CDD6C4 TLIST: CALL NAMES ;SET UP UNIT IF GIVEN C581 CD07C3 CALL CRLF C584 CD9BC5 LLIST: CALL ALOAD C587 0601 MVI B,1 C589 CDEFC7 CALL TON ;TURN ON THE TAPE C58C CD56C7 LIST1: CALL RHEAD C58F DA00C2 JC COMN1 ;TURN OFF THE TAPE UNIT C592 C28CC5 JNZ LIST1 C595 CDA1C5 CALL NAOUT ;OUTPUT THE HEADER C598 C38CC5 JMP LIST1 ;LOOP UNTIL MODE IS DEPRESSED ; ; THIS ROUTINE GETS THE CASSETTE UNIT NUMBER AND ; SPEED TO REGISTER "A" FOR THE TAPE CALLS ; C59B 3A0DC8 ALOAD: LDA TSPD ;GET THE SPEED C59E F680 ORI 80H ;AND UNIT 1 KEY C5A0 C9 RET ;AND GO BACK ; ; THIS ROUTINE OUTPUTS THE NAME AND PARAMETERS OF ; THEAD TO THE OUTPUT DEVICE. ; C5A1 1608 NAOUT: MVI D,8 C5A3 211BC8 LXI H,THEAD-1 ;POINT TO THE HEADER C5A6 CDBBC5 CALL NLOOP ;OUTPUT THE HEADER C5A9 CDF8C3 CALL BOUT ;ANOTHER BLANK C5AC 2A25C8 LHLD LOADR ;NOW THE LOAD ADDRESS C5AF CDD5C3 CALL ADOUT ;PUT IT OUT C5B2 2A23C8 LHLD BLOCK ;AND THE BLOCK SIZE C5B5 CDD5C3 CALL ADOUT C5B8 C307C3 JMP CRLF ;DO THE CRLF AND RETURN ; C5BB 7E NLOOP: MOV A,M ;GET CHARACTER C5BC B7 ORA A C5BD C2C2C5 JNZ CHRLI ;IF IT ISN'T A ZERO C5C0 3E20 MVI A,' ' C5C2 CD11C4 CHRLI: CALL OUTH ;OUTPUT CHAR NOW C5C5 23 INX H C5C6 15 DCR D C5C7 C2BBC5 JNZ NLOOP C5CA C9 RET ; ; ***** SET COMMAND ***** ; ; THIS ROUTINE GETS THE ASSOCIATED PARAMETER AND ; DISPATCHES TO THE PROPER ROUTINE FOR SETTING ; GLOBAL VALUES. ; C5CB CD1CC3 CSET: CALL SBLK ;LOOK FOR SET NAME C5CE CAEBC4 JZ ERR1 ;MUST HAVE SOMETHING! C5D1 D5 PUSH D ;SAVE SCAN ADDRESS C5D2 CD3BC3 CALL SCONV ;CONVERT FOLLOWING VALUE C5D5 E3 XTHL ;SCAN ADDR TO H,L & VALU ON STK C5D6 11DAC2 LXI D,SETAB ;SECONDARY COMMAND TABLE C5D9 CD69C2 CALL FDCOM ;SEE IF IN TABLE C5DC C359C2 JMP DISPO ;AND EITHER ERR OR OFF TO IT ; ; THIS ROUTINE SETS THE TAPE SPEED ; C5DF B7 TASPD: ORA A ;IS IT ZERO? C5E0 CAE5C5 JZ SETSP ;YES...THAT'S A VALID SPEED C5E3 3E20 MVI A,32 ;SET TO SLOW IF NON-ZERO C5E5 320DC8 SETSP: STA TSPD ;SPEED IS STORED HERE C5E8 C9 RET ; C5E9 78 STSPD: MOV A,B ;ESCAPE COMES HERE TO SET SPEED C5EA 320BC8 DISPD: STA SPEED ;SET DISPLAY SPEED C5ED C9 RET ; ; SET INPUT DRIVER ; C5EE 3206C8 SETIN: STA IPORT C5F1 C9 RET ; ; SET OUTPUT DRIVER ; C5F2 3207C8 SETOT: STA OPORT C5F5 C9 RET ; ; SET USERS CUSTOM INPUT DRIVER ADDRESS ; C5F6 2200C8 SETCI: SHLD UIPRT C5F9 C9 RET ; ; SET USERS CUSTOM OUTPUT DRIVER ADDRESS ; C5FA 2202C8 SETCO: SHLD UOPRT C5FD C9 RET ; ; SET TYPE BYTE INTO HEADER ; C5FE 3222C8 SETTY: STA HTYPE C601 C9 RET ; ; SET EXECUTE ADDRESS INTO HEADER ; C602 2227C8 SETXQ: SHLD XEQAD C605 C9 RET ; C606 3211C8 SETCR: STA IGNCR ;FF=IGNORE ERRORS, ELSE=NORMAL C609 C9 RET ; ; 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 ; ; C60A E5 BOPEN: PUSH H ;SAVE HEADER ADDRESS C60B CD5DC6 CALL LFCB ;GET ADDRESS OF FILE CONTROL C60E C225C6 JNZ TERE2 ;FILE WAS ALREADY OPEN C611 3601 MVI M,1 ;NOW IT IS C613 23 INX H ;POINT TO READ COUNT C614 77 MOV M,A ;ZERO C615 23 INX H ;POINT TO BUFFER CURSOR C616 77 MOV M,A ;PUT IN THE ZERO COUNT ; ; ALLOCATE THE BUFFER ; C617 1163C8 LXI D,FBUF1 ;POINT TO BUFFER AREA C61A C1 UBUF: POP B ;HEADER ADDRESS C61B B7 ORA A ;CLR CARRY TO RET AFT STORING PARMS C61C 23 PSTOR: INX H C61D 71 MOV M,C C61E 23 INX H C61F 70 MOV M,B C620 23 INX H C621 73 MOV M,E C622 23 INX H C623 72 MOV M,D C624 C9 RET ; ; GENERAL ERROR RETURN POINTS FOR STACK CONTROL ; C625 E1 TERE2: POP H C626 D1 TERE1: POP D C627 AF TERE0: XRA A ;CLEAR ALL FLAGS C628 37 STC ;SET ERROR C629 C9 RET ; C62A 3D EOFER: DCR A ;SET MINUS FLAGS C62B 37 STC ;AND CARRY C62C D1 POP D ;CLEAR THE STACK C62D C9 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 ; C62E CD5DC6 PCLOS: CALL LFCB ;GET CONTROL BLOCK ADDRESS C631 C8 RZ ;NOT OPEN, CARRY SET FROM LFCR C632 B7 ORA A ;CLEAR CARRY C633 3C INR A ;SET CONDITION FLAGS C634 3600 MVI M,0 ;CLOSE THE CONTROL BYTE C636 C8 RZ ;READING -- DONE ; ; 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 ; C637 23 INX H C638 23 INX H C639 7E MOV A,M ;GET CURSOR POSITION C63A CDF2C6 CALL PLOAD ;HDR ADDR TO B,C - BUFR ADDR TO D,E C63D C5 PUSH B ;HEADER TO STACK C63E 210700 LXI H,BLKOF ;OFFSET TO BLOCK SIZE C641 09 DAD B C642 B7 ORA A ;TEST COUNT C643 CA55C6 JZ EOFW ;NO BYTES...JUST WRITE EOF ; ; WRITE LAST BLOCK ; C646 E5 PUSH H ;SAVE BLOCK SIZE POINTER FOR EOF C647 77 MOV M,A ;PUT IN COUNT C648 23 INX H C649 3600 MVI M,0 ;ZERO THE HIGHER BYTE C64B 23 INX H C64C 73 MOV M,E ;BUFFER ADDRESS C64D 23 INX H C64E 72 MOV M,D C64F 60 MOV H,B C650 69 MOV L,C ;PUT HEADER ADDRESS IN HL C651 CDC1C6 CALL WFBLK ;GO WRITE IT OUT C654 E1 POP H ;BLOCK SIZE POINTER ; ; NOW WRITE END OF FILE TO CASSETTE ; C655 AF EOFW: XRA A ;PUT IN ZEROS FOR SIZE ;EOF MARK IS ZERO BYTES! C656 77 MOV M,A C657 23 INX H C658 77 MOV M,A C659 E1 POP H ;HEADER ADDRESS C65A C3C1C6 JMP WFBLK ;WRITE IT OUT AND RETURN ; ; SEE IF FCB IS ALREADY ALLOCATED ; C65D 2155C8 LFCB: LXI H,FCBAS ;POINT TO FCB C660 7E MOV A,M ;PICK UP FLAGS FROM FCB C661 B7 ORA A ;SET FLAGS BASED ON CONTROL WORD C662 37 STC ;SET CARRY FOR IMMEDIATE ERROR RET C663 C9 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 ; C664 CD5DC6 RTBYT: CALL LFCB ;LOCATE THE FILE CONTROL BLOCK C667 C8 RZ ;FILE NOT OPEN C668 3C INR A ;TEST IF FF C669 FA27C6 JM TERE0 ;ERROR WAS WRITING C66C 36FF MVI M,0FFH ;SET IT AS READ C66E 23 INX H C66F 7E MOV A,M ;GET READ COUNT C670 E5 PUSH H ;SAVE COUNT ADDRESS C671 23 INX H C672 CDF2C6 CALL PLOAD ;GET THE OTHER PARAMETERS C675 E1 POP H C676 B7 ORA A C677 C293C6 JNZ GTBYT ;IF NOT EMPTY GO GET BYTE ; ; CURSOR POSITION WAS ZERO...READ A NEW BLOCK ; INTO THE BUFFER. ; C67A D5 RDNBLK: PUSH D ;BUFFER POINTER C67B E5 PUSH H ;TABLE ADDRESS C67C 23 INX H C67D CDE2C6 CALL PHEAD ;PREPARE THE HEADER FOR READ C680 CDFBC6 CALL RFBLK ;READ IN THE BLOCK C683 DA25C6 JC TERE2 ;ERROR POP OFF STACK BEFORE RETURN C686 E1 POP H C687 7B MOV A,E ;LOW BYTE OF COUNT (ZERO IF 256) C688 B2 ORA D ;SEE IF BOTH ARE ZERO C689 CA2AC6 JZ EOFER ;BYTE COUNT WAS ZERO...END OF FILE C68C 73 MOV M,E ;NEW COUNT (ZERO IS 256 AT THIS POINT) C68D 23 INX H ;BUFFER LOCATION POINTER C68E 3600 MVI M,0 C690 2B DCX H C691 7B MOV A,E ;GET BACK BUFFER ADDRESS C692 D1 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. ; C693 3D GTBYT: DCR A ;BUMP THE COUNT C694 77 MOV M,A ;RESTORE IT C695 23 INX H C696 77 MOV M,A ;GET BUFFER POSITION C697 34 INR M ;BUMP IT C698 83 ADD E C699 5F MOV E,A ;DE POINT TO CORRECT BUFFER POSITION C69A D29EC6 JNC RT1 C69D 14 INR D C69E 1A RT1: LDAX D ;GET CHARACTER FROM BUFFER C69F B7 ORA A ;CLEAR CARRY C6A0 C9 RET ;ALL DONE ; ; THIS ROUTINE IS USED TO WRITE A BYTE TO THE FILE ; ; ON ENTRY: A - HAS FILE NUMBER ; B - HAS DATA BYTE ; C6A1 CD5DC6 WTBYT: CALL LFCB ;GET CONTROL BLOCK C6A4 C8 RZ ;FILE WASN'T OPEN C6A5 3C INR A C6A6 C8 RZ ;FILE WAS READ C6A7 36FE MVI M,0FEH ;SET IT TO WRITE C6A9 23 INX H C6AA 23 INX H C6AB 78 MOV A,B ;GET CHARACTER C6AC F5 PUSH PSW C6AD E5 PUSH H ;SAVE CONTROL ADDRESS+2 ; ; NOW DO THE WRITE ; C6AE CDF2C6 CALL PLOAD ;BC GETS HEADER ADDR ;DE BUFFER ADDRESS C6B1 E1 POP H C6B2 7E MOV A,M ;COUNT BYTE C6B3 83 ADD E C6B4 5F MOV E,A C6B5 D2B9C6 JNC WT1 C6B8 14 INR D C6B9 F1 WT1: POP PSW ;CHARACTER C6BA 12 STAX D ;PUT CHR IN BUFFER C6BB B7 ORA A ;CLEAR FLAGS C6BC 34 INR M ;INCREMENT THE COUNT C6BD C0 RNZ ;RETURN IF COUNT DIDN'T ROLL OVER ; ; THE BUFFER IS FULL. WRITE IT TO TAPE ; AND RESET CONTROL BLOCK. ; C6BE CDE2C6 CALL PHEAD ;PREPARE THE HEADER ; ; THIS ROUTINE GETS THE CORRECT UNIT FOR SYSTEM WRITES ; C6C1 CD9BC5 WFBLK: CALL ALOAD ;SET UP A WITH UNIT AND SPEED ; ; ***** WRITE TAPE BLOCK ROUTINE ***** ; ; ON ENTRY: A - HAS UNIT AND SPEED ; HL - HAS POINTER TO HEADER ; C6C4 E5 WTAPE: PUSH H ;SAVE HEADER ADDRESS C6C5 CDAFC7 CALL WHEAD ;TURN ON, THEN WRITE HEADER C6C8 E1 POP H C6C9 110700 LXI D,BLKOF ;OFFSET TO BLOCK SIZE IN HEADER C6CC 19 DAD D ;HL POINT TO BLOCK SIZE C6CD 5E MOV E,M C6CE 23 INX H C6CF 56 MOV D,M ;DE HAS SIZE C6D0 23 INX H C6D1 7E MOV A,M C6D2 23 INX H C6D3 66 MOV H,M C6D4 6F MOV L,A ;HL HAS STARTING ADDRESS ; ; THIS ROUTINE WRITES ONE PHYSICAL BLOCK ON THE ; TAPE "DE" BYTES LONG FROM ADDRESS "HL". ; C6D5 E5 WRLO1: PUSH H ;A DUMMY PUSH FOR LATER EXIT C6D6 CD48C7 WTAP2: CALL DCRCT ;DROP COUNT IN DE AND SET UP B ;WITH LENGTH THIS BLOCK C6D9 CA3EC7 JZ TOFF ;RETURNS ZERO IF ALL DONE C6DC CDC3C7 CALL WTBL ;WRITE BLOCK FOR BYTES IN B (256) C6DF C3D6C6 JMP WTAP2 ;LOOP UNTIL ALL DONE ; ; THIS ROUTINE PUTS THE BLOCK SIZE (256) AND BUFFER ; ADDRESS IN THE FILE HEADER. ; C6E2 CDF2C6 PHEAD: CALL PLOAD ;GET HEADER AND BUFFER ADDRESSES C6E5 C5 PUSH B ;HEADER ADDRESS C6E6 210600 LXI H,BLKOF-1 ;PSTOR DOES AN INCREMENT C6E9 09 DAD B ;HL POINTS TO BLOCKSIZE ENTRY C6EA 010001 LXI B,256 C6ED CD1CC6 CALL PSTOR C6F0 E1 POP H ;HL RETURN WITH HEADER ADDRESS C6F1 C9 RET ; C6F2 23 PLOAD: INX H C6F3 4E MOV C,M C6F4 23 INX H C6F5 46 MOV B,M C6F6 23 INX H C6F7 5E MOV E,M C6F8 23 INX H C6F9 56 MOV D,M C6FA C9 RET ; ;THIS ROUTINE SETS THE CORRECT UNIT FOR SYSTEM READS ; C6FB CD9BC5 RFBLK: CALL ALOAD ;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 ; C6FE D5 RTAPE: PUSH D ;SAVE OPTIONAL ADDRESS C6FF 0603 MVI B,3 ;SHORT DELAY C701 CDEFC7 CALL TON C704 DBFB IN TDATA ;CLEAR THE UART FLAGS C706 E5 PTAP1: PUSH H ;HEADER ADDRESS C707 CD56C7 CALL RHEAD ;GO READ HEADER C70A E1 POP H C70B DA39C7 JC TERR ;IF AN ERROR OR ESC WAS RECEIVED C70E C206C7 JNZ PTAP1 ;IF VALID HEADER NOT FOUND ; ; FOUND A VALID HEADER NOW DO COMPARE ; C711 E5 PUSH H ;GET BACK AND RESAVE ADDRESS C712 111CC8 LXI D,THEAD C715 CDE1C7 CALL DHCMP ;COMPARE DE/HL HEADERS C718 E1 POP H C719 C206C7 JNZ PTAP1 C71C D1 POP D ;OPTIONAL "PUT" ADDRESS C71D 7A MOV A,D C71E B3 ORA E ;SEE IF DE IS ZERO C71F 2A23C8 LHLD BLOCK ;GET BLOCK SIZE C722 EB XCHG ;....TO DE ; DE HAS HBLOCK...HL HAS USER OPTION C723 C229C7 JNZ RTAP ;IF DE WAS 0 GET TAPE LOAD ADDR C726 2A25C8 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 ; C729 D5 RTAP: PUSH D ;SAVE SIZE FOR CALLER C72A CD48C7 RTAP2: CALL DCRCT ;DROP COUNT, B=LEN THIS BLOCK C72D CA43C7 JZ RTOFF ;ZERO=ALL DONE C730 CD77C7 CALL RHED1 ;READ THAT MANY BYTES C733 DA39C7 JC TERR ;IF ERROR OR ESC C736 CA2AC7 JZ RTAP2 ;RD OK...READ SOME MORE ; ; ERROR RETURN ; C739 AF TERR: XRA A C73A 37 STC ;SET ERROR FLAGS C73B C344C7 JMP RTOF1 ; C73E 0601 TOFF: MVI B,1 C740 CDF1C7 CALL DELAY C743 AF RTOFF: XRA A C744 D3FA RTOF1: OUT TAPPT C746 D1 POP D ;RETURN BYTE COUNT C747 C9 RET ; C748 AF DCRCT: XRA A ;CLR FOR LATER TESTS C749 47 MOV B,A ;SET THIS BLK LEN = 256 C74A B2 ORA D ;IS ANMT LEFT < 256 C74B C253C7 JNZ DCRC2 ;NO...REDUCE AMNT BY 256 C74E B3 ORA E ;IS ENTIRE COUNT ZERO C74F C8 RZ ;ALL DONE..ZERO=THIS CONDITION C750 43 MOV B,E ;BLK LEN = AMNT REMAINING C751 5A MOV E,D ;MAKE ENTIRE COUNT ZERO NOW C752 C9 RET ;ALL DONE (NON-ZERO FLAG) C753 15 DCRC2: DCR D ;DROP BY 256 C754 B7 ORA A ;FORCE NON-ZERO FLAG C755 C9 RET ;NON-ZERO=NOT DONE (BLKSIZ=256) ; ; READ THE HEADER ; C756 060A RHEAD: MVI B,10 ;FIND 10 NULLS C758 CD90C7 RHEA1: CALL STAT C75B D8 RC ;IF ESCAPE C75C DBFB IN TDATA ;IGNORE ERROR CONDITIONS C75E B7 ORA A ;ZERO? C75F C256C7 JNZ RHEAD C762 05 DCR B C763 C258C7 JNZ RHEA1 ;LOOP UNTIL 10 IN A ROW ; ; WAIT FOR THE START CHARACTER ; C766 CDA2C7 SOHL: CALL TAPIN C769 D8 RC ;ERROR OR ESCAPE C76A FE01 CPI 1 ;10 NULLS THEN 01 C76C DA66C7 JC SOHL ;STILL A NULL, KEEP WAITING C76F C256C7 JNZ RHEAD ;START SEQ OVER AGAIN ; ; NOW GET THE HEADER ; C772 211CC8 LXI H,THEAD ;POINT TO BUFFER C775 0610 MVI B,HLEN ;LENGTH TO READ C777 0E00 RHED1: MVI C,0 ;INITALIZE THE CRC C779 CDA2C7 RHED2: CALL TAPIN ;GET A BYTE C77C D8 RC C77D 77 MOV M,A ;STORE IT C77E 23 INX H ;INCREMENT ADDRESS C77F CDDAC7 CALL DOCRC ;GO COMPUTE THE CRC C782 05 DCR B ;WHOLE HEADER YET? C783 C279C7 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. ; C786 CDA2C7 CALL TAPIN ;GET CRC BYTE C789 A9 XRA C ;CLR CARRY AND SET ZERO IF MATCH ;ELSE NON-ZERO C78A C8 RZ ;CRC WAS FINE C78B 3A11C8 LDA IGNCR ;GET CRC OVERIDE FLAG C78E 3C INR A ;FF=IGNORE CRC ERRORS C78F C9 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. ; C790 DBFA STAT: IN TAPPT ;TAPE STATUS PORT C792 E640 ANI TDR C794 C0 RNZ C795 CD1FC0 CALL SINP ;CHECK INPUT C798 CA90C7 JZ STAT ;NOTHING THERE YET C79B E67F ANI 7FH ;CLR PARITY FIRST C79D C290C7 JNZ STAT ;NOT A MODE (OR EVEN CTRL-@) C7A0 37 STC ;SET ERROR FLAG C7A1 C9 RET ;AND RETURN ; C7A2 CD90C7 TAPIN: CALL STAT ;WAIT TILL CHARACTER AVAILABLE C7A5 D8 RC ; C7A6 DBFA TREDY: IN TAPPT ;TAPE STATUS C7A8 E618 ANI TFE+TOE ;DATA ERROR? C7AA DBFB IN TDATA ;GET THE DATA C7AC C8 RZ ;IF NO ERRORS C7AD 37 STC ;SET ERROR FLAG C7AE C9 RET ; ; THIS ROUTINE WRITES THE HEADER POINTED TO BY ; HL TO THE TAPE. ; C7AF CDEDC7 WHEAD: CALL WTON ;TURN IT ON, THEN WRITE HEADER C7B2 1632 MVI D,50 ;WRITE 50 ZEROS C7B4 AF NULOP: XRA A C7B5 CDCFC7 CALL WRTAP C7B8 15 DCR D C7B9 C2B4C7 JNZ NULOP C7BC 3E01 MVI A,1 C7BE CDCFC7 CALL WRTAP C7C1 0610 MVI B,HLEN ;LENGTH TO WRITE OUT C7C3 0E00 WTBL: MVI C,0 ;RESET CRC BYTE C7C5 7E WLOOP: MOV A,M ;GET CHARACTER C7C6 CDCFC7 CALL WRTAP ;WRITE IT TO THE TAPE C7C9 05 DCR B C7CA 23 INX H C7CB C2C5C7 JNZ WLOOP C7CE 79 MOV A,C ;GET CRC C7CF F5 WRTAP: PUSH PSW C7D0 DBFA WRWAT: IN TAPPT ;TAPE STATUS C7D2 E680 ANI TTBE ;IS TAPE READY FOR A CHAR YET C7D4 CAD0C7 JZ WRWAT ;NO...WAIT C7D7 F1 POP PSW ;YES...RESTORE CHAR TO OUTPUT C7D8 D3FB OUT TDATA ;SEND CHAR TO TAPE C7DA 91 DOCRC: SUB C C7DB 4F MOV C,A C7DC A9 XRA C C7DD 2F CMA C7DE 91 SUB C C7DF 4F MOV C,A C7E0 C9 RET ;ONE BYTE NOW WRITTEN ; ; 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 ; C7E1 0605 DHCMP: MVI B,5 C7E3 1A DHLOP: LDAX D C7E4 BE CMP M C7E5 C0 RNZ C7E6 05 DCR B C7E7 C8 RZ ;IF ALL FIVE COMPARED C7E8 23 INX H C7E9 13 INX D C7EA C3E3C7 JMP DHLOP ; C7ED 0604 WTON: MVI B,4 ;SET LOOP DELAY, (LONGER ON WRITE) C7EF D3FA TON: OUT TAPPT ;GET TAPE MOVING, THEN DELAY ; C7F1 110000 DELAY: LXI D,0 C7F4 1B DLOP1: DCX D C7F5 7A MOV A,D C7F6 B3 ORA E C7F7 C2F4C7 JNZ DLOP1 C7FA 05 DCR B C7FB C2F1C7 JNZ DELAY C7FE C9 RET ; ;RST 7 FOR DDT COMMAND ; C7FF FF DDT: DB 0FFH ; ;********* END OF PROGRAM ************ ; ; ; ; ; ; SOL SYSTEM EQUATES ; ; ; VDM PARAMETERS ; CC00 = VDMEM EQU 0CC00H ;VDM SCREEN MEMORY 00CC = HIBYTE EQU 0CCH ;MEMORY HIGH BYTE ; ; ; KEYBOARD SPECIAL KEY ASSIGNMENTS ; 009A = DOWN EQU 9AH 0097 = UP EQU 97H 0081 = LEFT EQU 81H 0093 = RIGHT EQU 93H 0080 = MODE EQU 80H 008B = CLEAR EQU 8BH 008E = HOME EQU 08EH 005F = BACKS EQU 5FH ;BACKSPACE 000A = LF EQU 10 000D = CR EQU 13 0020 = BLANK EQU ' ' 0020 = SPACE EQU BLANK 0018 = CX EQU 'X'-40H 001B = ESC EQU 1BH ; ; PORT ASSIGNMENTS ; 00FA = STAPT EQU 0FAH ;STATUS PORT GENERAL 00F8 = SERST EQU 0F8H ;SERIAL STATUS PORT 00F9 = SDATA EQU 0F9H ;SERIAL DATA 00FA = TAPPT EQU 0FAH ;TAPE STATUS PORT 00FB = TDATA EQU 0FBH ;TAPE DATA 00FC = KDATA EQU 0FCH ;KEYBOARD DATA 00FD = PDATA EQU 0FDH ;PARALLEL DATA 00FE = DSTAT EQU 0FEH ;VDM DISPLAY PARAMETER PORT 00FF = SENSE EQU 0FFH ;SENSE SWITCHES 00E8 = DCOM EQU 0E8H ;DISK COMMAND PORT 00E8 = DSKST EQU DCOM ;DISK STATUS PORT 00EA = SECT EQU DCOM+2 ;DISK SECTOR PORT 00EB = DDATA EQU DCOM+3 ;DISK DATA PORT 00EC = WAIT EQU DCOM+4 ;DISK WAIT PORT ; ; ; BIT ASSIGNMENT MASKS ; 0001 = SCD EQU 1 ;SERIAL CARRIER DETECT 0002 = SDSR EQU 2 ;SERIAL DATA SET READY 0004 = SPE EQU 4 ;SERIAL PARITY ERROR 0008 = SFE EQU 8 ;SERIAL FRAMING ERROR 0010 = SOE EQU 16 ;SERIAL OVERRUN ERROR 0020 = SCTS EQU 32 ;SERIAL CLEAR TO SEND 0040 = SDR EQU 64 ;SERIAL DATA READY 0080 = STBE EQU 128 ;SERIAL XMTR BUFFER EMPTY ; 0001 = KDR EQU 1 ;KEYBOARD DAYA READY 0002 = PDR EQU 2 ;PARALLEL DATA READY 0004 = PXDR EQU 4 ;PARALLEL DEVICE READY 0008 = TFE EQU 8 ;TAPE FRAMING ERROR 0010 = TOE EQU 16 ;TAPE OVERRUN ERROR 0040 = TDR EQU 64 ;TAPE DATA READY 0080 = TTBE EQU 128 ;TAPE TRANSMITTER BUFFER EMPTY ; 0001 = SOK EQU 1 ;SCROLL OK FLAG ; 0080 = TAPE1 EQU 80H ;1=TURN TAPE ONE ON 0040 = TAPE2 EQU 40H ;1=TURN TAPE TWO ON ; ; ; ; SOL SYSTEM GLOBAL AREA ; C800 ORG SOLOS+800H ; C800 = SYSRAM EQU $ ;START OF RAM AREA CC00 = SYSTP EQU $+1024 ;STACK IS AT THE TOP ; ; ***** PARAMETERS STORED IN RAM ***** ; C800 UIPRT DS 2 ;USER INPUT RTN IF NON-ZERO C802 UOPRT DS 2 ;USER OUTPUT RTN IF NON-ZERO C804 ASPTR DS 2 ;ASCII POINTER FOR DUMP COMMAND C806 IPORT DS 1 ;CRNT INPUT PSEUDO PORT C807 OPORT DS 1 ;CRNT OUTPUT PSEUDO PORT C808 NCHAR DS 1 ;CURRENT CHARACTER POSITION C809 LINE DS 1 ;CURRENT LINE POSITION C80A BOT DS 1 ;BEGINNING OF TEXT DISPLACEMENT C80B SPEED DS 1 ;SPEED CONTROL BYTE C80C ESCFL DS 1 ;ESCAPE FLAG CONTROL BYTE C80D TSPD DS 1 ;CURRENT TAPE SPEED C80E STRT DS 2 ;START ADDR FOR MEMORY TEST C810 DS 1 ;FOR COMPATIBILITY C811 IGNCR DS 1 ;FF=IGNORE CRC ERR., ELSE NORM C812 PATT DS 1 ;PATTERN FOR MEMORY TEST C813 DATERR DS 1 ;BAD DATA FOR MEMORY TEST C814 ERRADR DS 2 ;BAD ADDR FOR MEMORY TEST C816 DS 6 ;FOR COMPATIBILITY ; ; ; THIS IS THE HEADER LAYOUT ; C81C THEAD DS 5 ;NAME C821 DS 1 ;THIS BYTE MUST BE ZERO C822 HTYPE DS 1 ;TYPE C823 BLOCK DS 2 ;BLOCK SIZE C825 LOADR DS 2 ;LOAD ADDRESS C827 XEQAD DS 2 ;AUTO-EXECUTE ADDRESS C829 HSPR DS 3 ;SPARES ; 0010 = HLEN EQU $-THEAD ;LENGTH OF HEADER 0007 = BLKOF EQU BLOCK-THEAD ;OFFSET TO BLOCK SIZE C82C DHEAD DS HLEN ;DUMMY HDR FOR COMPARES WHILE RDING ; ; ;FOLLOWING REPLACES CUSTOM COMMAND TABLE ; C83C ASCDA DS 16 ;ASCII BUFFER FOR DUMP C84C DS 8 ;FOR COMPATABILITY ; C854 FNUMF DS 1 ;FOR COMPATIBILITY C855 FCBAS DS 7 ;1ST FILE CONTROL BLOCK C85C FCBA2 DS 7 ;FOR COMPATIBILITY C863 FBUF1 DS 256 ;SYSTEM FILE BUFFER BASE ; C963 END