; NOTE: THIS IS A HACKED UP VERSION OF THE "OFFICIAL" V1.3 SOLOS ; SOURCE CODE. IT WAS TWEAKED TO MATCH THE EXISTING BINARY ; FOUND IN A PERSONALITY MODULE OF A PARTICULAR MACHINE. ; ; JIM BATTLE 12/15/99 ; ; ; ******** 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) ; ; ; C000 ORG 0C000H ; ; ; ; AUTO-STARTUP CODE ; C000 00 START: DB 0 C001 C3AFC1 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. ; C004 C3C9C1 RETRN: JMP COMND ;RETURN TO SYSTEM ENTRY POINT C007 C3DDC5 FOPEN: JMP BOPEN ;FILE OPEN ENTRY C00A C300C6 FCLOS: JMP PCLOS ;FILE CLOSE ENTRY C00D C343C6 RDBYT: JMP RTBYT ;CASSETTE READ BYTE ENTRY C010 C380C6 WRBYT: JMP WTBYT ;CASSETTE WRITE BYTE ENTRY C013 C3C8C6 RDBLK: JMP RTAPE ;CASSETTE READ BLOCK ENTRY C016 C37CC7 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 ; C019 3A07C8 SOUT: LDA OPORT ;SOUT ENTRY POINT C01C C33BC0 AOUT: JMP OUTPR ;AOUT ENTRY POINT C01F 3A06C8 SINP: LDA IPORT ;SINP ENTRY POINT C022 = AINP: EQU $ ;AINP ENTRY POINT ;******** END OF SYSTEM ENTRY POINTS ********* C022 E5 PUSH H ;THIS IS ACTUALLY AINP C023 219AC2 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. ; 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 C327C2 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 ; C02E DBFA KSTAT: IN STAPT ;GET STATUS WORK C030 2F CMA ;INVERT IT FOR PROPER RETURN C031 E601 ANI KDR ;TEST KEYBOARD BIT C033 C8 RZ ;ZERO IS NO CHARACTER RECEIVED ; C034 DBFC IN KDATA ;GET CHARACTER C036 C9 RET ;GO BACK WITH IT ; ; ; THIS JUMP IS PART OF THE AUTO START UP CODE ; C037 00 DB 0 ;VERIFY ADDR=C037 C038 C301C0 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" ; C03B E5 OUTPR: PUSH H C03C 2192C2 LXI H,OTAB ;POINT TO OUTPUT TABLE C03F C326C0 JMP IOPRC ;AND DISPATCH TO OUTPUT ROUTINE ; ; ; ; SERIAL INPUT DRIVER ; C042 DBF8 SSTAT: IN SERST ;GET SERIAL STATUS WORD C044 E640 ANI SDR ;TEST FOR SERIAL DATA READY C046 C8 RZ ;FLAGS ARE SET ; C047 DBF9 IN SDATA ;GET DATA BYTE C049 C9 RET ;WE HAVE IT ; ; ; SERIAL DATA OUTPUT ; C04A DBF8 SDROT: IN SERST ;GET PORT STATUS C04C 17 RAL ;PUT HIGH BIT IN CARRY C04D D24AC0 JNC SDROT ;LOOP UNTIL TRANSMITTER BUFFER IS EMPTY C050 78 MOV A,B ;GET THE CHARACTER BACK C051 D3F9 OUT SDATA ;SEND IT OUT C053 C9 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. ; ; C054 E5 VDMOT: PUSH H ;SAVE MOST REGISTERS C055 D5 PUSH D C056 C5 PUSH B ; ; TEST IS ESC SEPUENCE HAS BEEN STARTED ; C057 3A0CC8 LDA ESCFL ;GET ESCAPE FLAG C05A B7 ORA A C05B C25FC1 JNZ ESCS ;IF NON-ZERO GO PROCESS THE REST ; ; C05E 78 CHPCK: MOV A,B ;SAVE IN B...STRIP PARITY BEFORE SCREEN! C05F E67F ANI 7FH ;CLR PARITY TO LOCATE IN TBL C061 47 MOV B,A ;KEEP IT W/OUT PARITY IN B TOO C062 CA7CC0 JZ GOBK ;DO A QUICK EXIT IF A NULL C065 2173C2 LXI H,TBL ;POINT TO SPECIAL SHARACTER TABLE C068 CD82C0 CALL TSRCH ;GO PROCESS ; C06B CD1CC1 GOBACK: CALL VDADD ;GET SCREEN ADDRESS C06E 7E MOV A,M ;GET PRESENT CURSOR CHARACTER C06F F680 ORI 80H C071 77 MOV M,A ;CURSOR IS BACK ON C072 2A0AC8 LHLD SPEED-1 ;GET DELAY SPEED C075 2C INR L ;MAKE SURE IT IS NON-ZERO C076 AF XRA A ;DELAY WILL END WHEN H=0 C077 2B TIMER: DCX H ;TIMER DELAYS HERE C078 BC CMP H ;DONE WITH DELAY YET C079 C277C0 JNZ TIMER ;KEEP DELAYING C07C C1 GOBK: POP B C07D D1 POP D ;RESTORE REGISTERS C07E E1 POP H C07F C9 RET ;EXIT FROM VDMOT ; C080 23 NEXT: INX H C081 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. ; C082 7E TSRCH: MOV A,M ;GET CHR FROM TABLE C083 B7 ORA A C084 CA94C0 JZ CHAR ;ZERO IS THE LAST C087 B8 CMP B ;TEST THE CHR C088 23 INX H ;POINT FORWARD C089 C280C0 JNZ NEXT C08C E5 PUSH H ;FOUND ONE...SAVE ADDRESS C08D CD36C1 CALL CREM ;REMOVE CURSOR C090 E3 XTHL ;GET DISPATCH ADDRESS TO HL C091 C327C2 JMP DISPT ;DISPATCH NOW ; ; PUT CHARACTER TO SCREEN ; C094 78 CHAR: MOV A,B ;GET CHARACTER C095 FE7F CPI 7FH ;IS IT A DEL? C097 C8 RZ ;GO BACK IF SO ; ; ; C098 = OCHAR: EQU $ ;ACTUALLY PUT CHAR TO SCREEN NOW C098 CD1CC1 CALL VDADD ;GET SCREEN ADDRESS C09B 70 MOV M,B ;PUT CHR ON SCREEN ; C09C 3A08C8 LDA NCHAR ;GET CHARACTER POSITION C09F FE3F CPI 63 ;END OF LINE? C0A1 DAC1C0 JC OK C0A4 3A09C8 LDA LINE C0A7 FE0F CPI 15 ;END OF SCREEN? C0A9 C2C1C0 JNZ OK ; ; END OF SCREEN...ROLL UP ONE LINE ; C0AC AF SCROLL: XRA A C0AD 3208C8 STA NCHAR ;BACK TO FIRST CHAR POSITION C0B0 4F SROL: MOV C,A C0B1 CD23C1 CALL VDAD ;CALCULATE LINE TO BE BLANKED C0B4 AF XRA A C0B5 CDFAC0 CALL CLIN1 ;CLEAR IT C0B8 3A0AC8 LDA BOT C0BB 3C INR A C0BC E60F ANI 0FH C0BE C3EEC0 JMP ERAS3 ; ; INCREMENT LINE COUNTER IF NECESSARY ; C0C1 3A08C8 OK: LDA NCHAR ;GET CHR POSITION C0C4 3C INR A C0C5 E63F ANI 3FH ;MOD 64 AND WRAP C0C7 3208C8 STA NCHAR C0CA C0 RNZ ;DIDN'T HIT END OF LINE, OK C0CB = PDOWN: EQU $ ;CURSOR DOWN ONE LINE HERE C0CB 3A09C8 LDA LINE ;GET THE LINE COUNT C0CE 3C INR A C0CF E60F CURSC: ANI 0FH ;STORE THE NEW C0D1 3209C8 CUR: STA LINE ;STORE THE NEW C0D4 C9 RET ; ; ERASE SCREEN ; C0D5 2100CC PERSE: LXI H,VDMEM ;POINT TO SCREEN C0D8 36A0 MVI M,80H+' ' ;THIS IS THE CURSOR ; C0DA 23 INX H ;BUMP 1ST C0DB = ERAS1: EQU $ ;LOOPS HERE TO ERASE SCREEN C0DB 3620 MVI M,' ' ;BLANK IT OUT C0DD 23 INX H ;NEXT C0DE 7C MOV A,H ;SEE IF END OF SCREEN YET C0DF FED0 CPI 0D0H C0E1 DADBC0 JC ERAS1 ;NO--KEEP BLANKING C0E4 37 STC ;CARRY WILL SAY COMPLETE ERASE ; C0E5 3E00 PHOME: MVI A,0 ;RESET CURSOR--CARRY=ERASE, ELSE HOME C0E7 3209C8 STA LINE ;ZERO LINE C0EA 3208C8 STA NCHAR ;LEFT SIDE OF SCREEN C0ED D0 RNC ;IF NO CARRY, WE ARE DONE WITH HOME ; C0EE D3FE ERAS3: OUT DSTAT ;RESET SCROOL PARAMETERS C0F0 320AC8 STA BOT ;BEGINNING OF TEXT OFFSET C0F3 C9 RET ; ; C0F4 CD1CC1 CLINE: CALL VDADD ;GET CURRENT SCREEN ADDRESS C0F7 3A08C8 LDA NCHAR ;CURRENT CURSOR POSITION C0FA FE40 CLIN1: CPI 64 ;NO MORE THAN 63 C0FC D0 RNC ;ALL DONE C0FD 3620 MVI M,' ' ;ALL SPACED OUT C0FF 23 INX H C100 3C INR A C101 C3FAC0 JMP CLIN1 ;LOOP TO END OF LINE ; ; ; ROUTINE TO MOVE THE CURSOR UP ONE LINE ; C104 3A09C8 PUP: LDA LINE ;GET LINE COUNT C107 3D DCR A C108 C3CFC0 JMP CURSC ;MERGE TO HANDLE CURSOR ; ; MOVE CURSOR LEFT ONE POSITION ; C10B 3A08C8 PLEFT: LDA NCHAR C10E 3D DCR A C10F = PCUR: EQU $ ;CURSOR ON SAME LINE C10F E63F ANI 3FH ;LET CURSOR WRAP C111 3208C8 STA NCHAR ;UPDATED CURSOR C114 C9 RET ; ; CURSOR RIGHT ONE POSITION ; C115 3A08C8 PRIT: LDA NCHAR C118 3C INR A C119 C30FC1 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' ; C11C 3A08C8 VDADD: LDA NCHAR ;GET CHARACTER POSITION C11F 4F MOV C,A ;'C' KEEPS IT C120 3A09C8 VDAD2: LDA LINE ;LINE POSITION C123 6F VDAD: MOV L,A ;INTO 'L' C124 3A0AC8 LDA BOT ;GET TEXT OFFSET C127 85 ADD L ;ADD IT TO THE LINE POSITION C128 0F RRC ;TIMES TWO C129 0F RRC ;MADES FOUR C12A 6F MOV L,A ;L HAS IT C12B E603 ANI 3 ;MOD THREE FOR LATER C12D C6CC ADI VDMEM SHR 8 ;LOW SCREEN OFFSET C12F 67 MOV H,A ;NOW H IS DONE C130 7D MOV A,L ;TWIST L'S ARM C131 E6C0 ANI 0C0H C133 81 ADD C C134 6F MOV L,A C135 C9 RET ;H & L ARE NOW PERVERTED ; ; ROUTINE TO REMOVE CURSOR ; C136 CD1CC1 CREM: CALL VDADD ;GET CURRENT SCREEN ADDRESS C139 7E MOV A,M C13A E67F ANI 7FH ;STRIP OFF THE CURSOR C13C 77 MOV M,A C13D C9 RET ; ; ROUTINE TO BACKSPACE ; C13E CD0BC1 PBACK: CALL PLEFT C141 CD1CC1 CALL VDADD ;GET SCREEN ADDRESS C144 3620 MVI M,' ' ;PUT A BLANK THERE C146 C9 RET ; ; ROUTINE TO PROCESS A CARRIAGE RETURN ; C147 CDF4C0 PCR: CALL CLINE ;ERASE ANY CHARS TO THE RIGHT OF THE CURSOR C14A C30FC1 JMP PCUR ;AND STORE THE NEW VALUE ; ; ROUTINE TO PROCESS A LINEFEED ; C14D 3A09C8 PLF: LDA LINE ;GET LINE COUNT C150 3C INR A C151 E60F ANI 15 ;SEE IF IT WRAPPED AROUND C153 C2D1C0 JNZ CUR ;NO--NO NEED TO SCROLL C156 C3B0C0 JMP SROL ;YES--THEN SCROLL ; ; SET ESCAPE PROCESS FLAG ; C159 3EFF PESC: MVI A,(-1) AND 0FFH C15B 320CC8 STA ESCFL ;SET FLAG C15E C9 RET ; ; PROCESS ESCAPE SEQUENCE ; C15F CD36C1 ESCS: CALL CREM ;REMOVE CURSOR C162 CD68C1 CALL ESCSP ;PROCESS THE NEXT PART OF SEQUENCE C165 C36BC0 JMP GOBACK ; C168 3A0CC8 ESCSP: LDA ESCFL ;GET ESCAPE FLAG C16B FEFF CPI (-1) AND 0FFH ;TEST FLAG C16D CA90C1 JZ SECOND ; ; PROCESS THIRD CHR OF ESC SEQUENCE ; C170 210CC8 LXI H,ESCFL C173 3600 MVI M,0 ;NO MORE PARTS TO THE SEQUENCE C175 FE02 CPI 2 C177 DA88C1 JC SETX ;SET X IF IS ONE C17A CA8CC1 JZ SETY ;SET Y IF IS TWO C17D FE08 CPI 8 C17F CA95C5 JZ STSPD ;SET NEW DISPLAY SPEED IF "8" C182 FE09 CPI 9 C184 DA98C0 JC OCHAR ;PUT IT ON THE SCREEN C187 C0 RNZ ; ; TAB ABSOLUTE TO VALUE IN REG B ; C188 78 SETX: MOV A,B ;GET CHARACTER C189 C30FC1 JMP PCUR ; ; SET CURSOR TO LINE "B" ; C18C 78 SETY: MOV A,B C18D C3CFC0 JMP CURSC ; ; ; PROCESS SECOND CHR OF ESC SEPUENCE ; C190 78 SECOND: MOV A,B ;GET WHICH C191 FE03 CPI 3 C193 CAA6C1 JZ CURET ;RETURN CURSOR PARAMETERS C196 FE04 CPI 4 C198 C2A2C1 JNZ ARET2 ; ; ESC <4> RETURN ABSOLUTE SCREEN ADDRESS ; C19B 44 ARET: MOV B,H C19C 4D MOV C,L ;PRESENT SCREEN ADDRESS TO BC FOR RETURN ; C19D E1 ARET1: POP H ;RETURN ADDRESS C19E D1 POP D ;OLD B C19F C5 PUSH B C1A0 E5 PUSH H C1A1 AF XRA A C1A2 320CC8 ARET2: STA ESCFL C1A5 C9 RET ; ; ; RETURN PRESENT SCREEN PARAMETERS IN "BC" ; C1A6 2108C8 CURET: LXI H,NCHAR C1A9 46 MOV B,M ;CHARACTER POSITION C1AA 23 INX H C1AB 4E MOV C,M ;LINE POSITION C1AC C39DC1 JMP ARET1 ; ; ; ***** START UP SYSTEM ***** ; ; CLEAR SCREEN AND THE FIRST 256 BYTES OF GLOBAL RAM ; THEN ENTER THE COMMAND MODE ; C1AF AF STRTA: XRA A C1B0 4F MOV C,A C1B1 2100C8 LXI H,SYSRAM ;CLEAR THR FIRST PAGE ; C1B4 77 CLERA: MOV M,A C1B5 23 INX H C1B6 0C INR C C1B7 C2B4C1 JNZ CLERA ; C1BA 31FFCB LXI SP,SYSTP ;SET UP THE STACK FOR CALL C1BD CDD5C0 CALL PERSE C1C0 AF COMN1: XRA A C1C1 D3FA OUT STAPT ;BE SURE TAPES ARE OFF C1C3 3207C8 STA OPORT C1C6 3206C8 STA IPORT ; ; ; ; ***** COMMAND MODE ***** ; ; ; THIS ROUTINE GETS AND PROCESSES COMMANDS ; C1C9 31FFCB COMND: LXI SP,SYSTP ;SET STACK POINTER C1CC 3A07C8 LDA OPORT ;GET PORT C1CF F5 PUSH PSW C1D0 AF XRA A C1D1 3207C8 STA OPORT ;FORCE SCREEN OPERATIONS C1D4 CDF1C2 CALL PROMPT ;PUT PROMPT ON SCREEN C1D7 CDE4C1 CALL GCLIN ;GET COMMAND LINE C1DA F1 POP PSW C1DB 3207C8 STA OPORT ;RESTORE DEFAULT PORT C1DE CD05C2 CALL COPRC ;PROCESS THE LINE C1E1 C3C9C1 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 ; C1E4 CD1FC0 GCLIN: CALL SINP ;READ INPUT DEVICE C1E7 CAE4C1 JZ GCLIN ; 008C = LOADKEY EQU 8CH C1EA FE8C CPI LOADKEY ; IF THE USER TYPES THE LOAD KEY ... C1EC CA00E9 JZ 0E900H ; ... THEN JUMP TO 0XE900 C1EF E67F ANI 7FH ;CLEAR PARITY BIT C1F1 CAC0C1 JZ COMN1 ;THIS WAS A MODE (OR EVEN CTRL-@) C1F4 47 MOV B,A C1F5 FE0D CPI CR ;CARRIAGE RETURN ; C1F7 C8 RZ ;YES--DONE WITH LINE, LEAVE AS IS C1F8 FE7F CPI 7FH ;DELETE CHR? C1FA C2FFC1 JNZ CONT C1FD 065F MVI B,BACKS ;REPLACE IT ; C1FF CD19C0 CONT: CALL SOUT C202 C3E4C1 JMP GCLIN ; ; ; FIND AND PROCESS COMMAND ; C205 CD36C1 COPRC: CALL CREM ;REMOVE THE CURSOR C208 0E01 MVI C,1 ;SET FOR CHARACTER POSITION C20A CD20C1 CALL VDAD2 ;GET SCREEN ADDRESS C20D EB XCHG C20E 2100C0 LXI H,START ;MAKE SURE HL PT TO SOLOS START C211 E5 PUSH H ;SAVE IT FOR LATER DISPT C212 CD2EC3 CALL SCHR ;SCAN PAST BLANKS C215 CA7DC4 JZ ERR1 ;NO COMMAND? C218 EB XCHG ;HL HAS FIRST CHR ; C219 114AC2 LXI D,COMTAB ;POINT TO COMMAND TABLE C21C CD31C2 CALL FDCOM ;SEE IF IN PRIMARY COMMAND TABLE C21F CC2EC2 CZ FDCOU ;IF NOT, TRY CUSTOM TABLE NEXT C222 = DISPO: EQU $ ;HERE TO SEE IF ERROR OR DISP C222 CA7EC4 JZ ERR2 ;NOT VALID, ERROR C225 13 INX D ;BUMP TO PTR OF RTN C226 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. ; C227 = DISPT: EQU $ ;OFF TO A ROUTINE C227 7E MOV A,M ;LO ADDR C228 23 INX H C229 66 MOV H,M ;HI ADDR C22A 6F MOV L,A ;HL NOW COMPLETE C22B = DISP1: EQU $ ;HERE TO GO OFF TO HL C22B E3 XTHL ;XCHG HL W/HL ON STACK C22C 7D MOV A,L ;ALSO COPY HERE FOR SETS C22D 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. ; C22E 113CC8 FDCOU: LXI D,CUTAB ;HERE TO SCAN CUSTOM TBL ONLY ; C231 1A FDCOM: LDAX D C232 B7 ORA A ;TEST FOR TABLE END C233 C8 RZ ;NOT FOUND..COMMAND ERROR C234 E5 PUSH H ;SAVE START OF SCAN ADDRESS C235 BE CMP M ;TEST FIRST CHR C236 13 INX D C237 C243C2 JNZ NCOM ; C23A 23 INX H C23B 1A LDAX D C23C BE CMP M ;NOW SECOND CHARACTER C23D C243C2 JNZ NCOM ;GOODNESS ; C240 E1 POP H ;RESTORE ORIGINAL SCAN ADDR C241 B7 ORA A ;SET NON-ZERO FLAG SAYING FOUND C242 C9 RET ;WITH NON-ZERO SET ; ; C243 13 NCOM: INX D ;GO TO NEXT ENTRY C244 13 INX D C245 13 INX D C246 E1 POP H ;GET BACK ORIGINAL ADDRESS C247 C331C2 JMP FDCOM ;CONTINUE SEARCH ; ; ; ***** COMMAND TABLE ***** ; ; THIS TABLE DESCRIBES THE VALID COMMANDS FOR SOLOS ; C24A 5445 COMTAB: DW 'TE' ;TERMINAL MODE C24C 67C3 DW TERM C24E 4455 DW 'DU' ;DUMP C250 BFC3 DW DUMP C252 454E DW 'EN' ;ENTER C254 23C4 DW ENTER C256 4558 DW 'EX' ;EXECUTE C258 5EC4 DW EXEC C25A 4745 DW 'GE' ;GET A FILE C25C A4C4 DW TLOAD C25E 5341 DW 'SA' ;SAVE A FILE C260 E3C4 DW TSAVE C262 5845 DW 'XE' ;AUTO-EXECUTE A FILE C264 A3C4 DW TXEQ C266 4341 DW 'CA' ;CATALOG OF TAPE FILES C268 28C5 DW TLIST C26A 5345 DW 'SE' ;SET COMMAND C26C 77C5 DW CSET C26E 4355 DW 'CU' ;CUSTOM COMMAND C270 BAC5 DW CUSET C272 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. ; C273 0B TBL: DB CLEAR-80H ;CLEAR SCREEN C274 D5C0 DW PERSE C276 17 DB UP-80H ;UP CURSOR C277 04C1 DW PUP C279 1A DB DOWN-80H ;DOWN CURSOR C27A CBC0 DW PDOWN C27C 01 DB LEFT-80H ;LEFT CURSOR C27D 0BC1 DW PLEFT C27F 13 DB RIGHT-80H ;RIGHT CURSOR C280 15C1 DW PRIT C282 0E DB HOME-80H ;HOME CURSOR C283 E5C0 DW PHOME C285 0D DB CR ;CARRIAGE RETURN C286 47C1 DW PCR C288 0A DB LF ;LINE FEED C289 4DC1 DW PLF C28B 5F DB BACKS ;BACKSPACE C28C 3EC1 DW PBACK C28E 1B DB ESC ;ESCAPE KEY C28F 59C1 DW PESC C291 00 DB 0 ;END OF TABLE ; ; ; OUTPUT DEVICE TABLE ; C292 54C0 OTAB: DW VDMOT ;VDM DRIVER C294 4AC0 DW SDROT ;SERIAL OUTPUT C296 E6C2 DW PROUT ;PARALLAL OUTPUT C298 D2C2 DW ERROT ;ERROR OR USER DRIVER HANDLER ; ; ; INPUT DEVICE TABLE ; C29A 2EC0 ITAB: DW KSTAT ;KEYBOARD INPUT C29C 42C0 DW SSTAT ;SERIAL INPUT C29E DDC2 DW PASTAT ;PARALLEL INPUT C2A0 CBC2 DW ERRIT ;ERROR OR USER DRIVER HANDLER ; ; ; SECONDARY COMMAND TABLE FOR SET COMMAND ; C2A2 5441 SETAB: DW 'TA' ;SET TAPE SPEED C2A4 8BC5 DW TASPD C2A6 533D DW 'S=' ;SET DISPLAY SPEED C2A8 96C5 DW DISPD C2AA 493D DW 'I=' ;SET INPUT PORT C2AC 9AC5 DW SETIN C2AE 4F3D DW 'O=' ;SET OUTPUT PORT C2B0 9EC5 DW SETOT C2B2 4E3D DW 'N=' ;SET NULLS C2B4 B2C5 DW SETNU C2B6 4349 DW 'CI' ;SET CUSTOM DRIVER ADDRESS C2B8 A2C5 DW SETCI C2BA 434F DW 'CO' ;SET CUSTOM OUTPUT DRIVER ADDRESS C2BC A6C5 DW SETCO C2BE 5845 DW 'XE' ;SET HEADER XEQ ADDRESS C2C0 AEC5 DW SETXQ C2C2 5459 DW 'TY' ;SET HEADER TYPE C2C4 AAC5 DW SETTY C2C6 4352 DW 'CR' ;SET CRC TO ALLOW IGNORING OF CRC ERRORS C2C8 B6C5 DW SETCR C2CA 00 DB 0 ;END OF TABLE MARK ; ; ; SOLOS PORT ERROR HANDLER ; C2CB E5 ERRIT: PUSH H ;SAVE HL ONCE AGAIN C2CC 2A00C8 LHLD UIPRT ;GET USER INPUT PORT ADDRESS C2CF C3D6C2 JMP ERRO1 ;AND GO PROCESS ; C2D2 E5 ERROT: PUSH H C2D3 2A02C8 LHLD UOPRT ;GET USER OUTPUT PORT ADDRESS C2D6 7D ERRO1: MOV A,L ;TEST HL FOR ZERO C2D7 B4 ORA H C2D8 CAC0C1 JZ COMN1 ;IF ZERO RETURN TO COMMAND MODE C2DB E3 XTHL ;ADDRESS TO STACK...OLD HL TO HL C2DC C9 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 ; C2DD DBFA PASTAT: IN STAPT C2DF 2F CMA ;INVERT STATUS FLAGS C2E0 E602 ANI PDR ;TEST BIT C2E2 C8 RZ C2E3 DBFD IN PDATA ;GET DATA C2E5 C9 RET ; ; PARALLEL OUTPUT HANDLER ; C2E6 DBFA PROUT: IN STAPT ;GET STATUS C2E8 E604 ANI PXDR ;TEST IF DEVICE IS READY C2EA C2E6C2 JNZ PROUT ;LOOP UNTIL SO C2ED 78 MOV A,B C2EE D3FD OUT PDATA C2F0 C9 RET ; ; ; OUTPUT A CR/LF FOLLOWED BY A PROMPT ; C2F1 CDF9C2 PROMPT: CALL CRLF C2F4 063E MVI B,'>' ;THE PROMPT C2F6 C319C0 JMP SOUT ;PUT IT ON THE SCREEN ; ; C2F9 060A CRLF: MVI B,LF ;LINE FEED C2FB CD19C0 CALL SOUT C2FE 060D MVI B,CR ;CARRIAGE RETURN C300 CD19C0 CALL SOUT ; NOW OUTPUT THE NULLS C303 3A10C8 LDA NUCNT ;GET DESIRED COUNT C306 4F MOV C,A ;STORE IN C C307 0D NULOT: DCR C C308 F8 RM ;RETURN WHEN PAST ZERO C309 AF XRA A ;GET A NULL C30A CD1FC4 CALL OUTH C30D C307C3 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. ; C310 CD1BC3 PSCAN: CALL SBLK C313 3E01 MVI A,1 ;DEFAULT VALUE C315 C8 RZ ;IF NONE C316 CD40C3 CALL SHEX ;CONVERT VALUE C319 7D MOV A,L ;GET LOWER HALF C31A C9 RET ; ; ; SCAN OVER UP TO 12 CHARACTERS LOOKING FOR A BLANK ; C31B 0E0C SBLK: MVI C,12 ;MAXIMUM COMMAND STRING C31D 1A SBLK1: LDAX D C31E FE20 CPI BLANK C320 CA2EC3 JZ SCHR ;GOT A BLANK NOW SCAN PAST IT C323 13 INX D C324 FE3D CPI '=' ;ALSO ALLOW EQUAL TO STOP US C326 CA2EC3 JZ SCHR ;IF SO, PTR AT CHAR FOLLOWING C329 0D DCR C ;NO MORE THAN TWELVE C32A C21DC3 JNZ SBLK1 C32D C9 RET ;GO BACK WITH ZERO FLAG SET ; ; ; SCAN PAST UP TO 10 BLANK POSITIONS LOOKING FOR ; A NON-BLANK CHARACTER ; C32E 0E0A SCHR: MVI C,10 ;SCAN TO FIRST NONBLANK CHR IN 10 C330 1A SCHR1: LDAX D ;GET NEXT CHARACTER C331 FE20 CPI SPACE C333 C0 RNZ ;WE'RE PAST THEM C334 13 INX D ;NEXT SCAN ADDRESS C335 0D DCR C C336 C8 RZ ;COMMAND ERROR C337 C330C3 JMP SCHR1 ;KEEP LOOPING ; ; ; THIS ROUTINE SCANS OVER CHARACTERS, PAST BLANKS AND ; CONVERTS THE FOLLOWING VALUE TO HEX. ERRORS RETURN TO ; THE ERROR HANDLER. ; C33A CD1BC3 SCONV: CALL SBLK ;FIND IF VALUE IS PRESENT C33D CA7DC4 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. ; C340 210000 SHEX: LXI H,0 ;CLEAR H & L C343 1A SHE1: LDAX D ;GET CHARACTER C344 FE20 CPI 20H ;IS IT A SPACE C346 C8 RZ ;IF SO C347 FE2F CPI '/' ;SLASH IS ALSO LEGAL C349 C8 RZ C34A FE3A CPI ':' ;EVEN THE COLON IS ALLOWED C34C C8 RZ ; C34D 29 HCONV: DAD H ;MAKE ROOM FOR THE NEW ONE C34E 29 DAD H C34F 29 DAD H C350 29 DAD H C351 CD5DC3 CALL HCOV1 ;DO THE CONVERSION C354 D27DC4 JNC ERR1 ;NOT VALID HEXIDECIMAL VALUE C357 85 ADD L C358 6F MOV L,A ;MOVE IT IN C359 13 INX D ;BUMP THE POINTER C35A C343C3 JMP SHE1 ; C35D D630 HCOV1: SUI 48 ;REMOVE ASCII BIAS C35F FE0A CPI 10 C361 D8 RC ;IF LESS THAN 9 C362 D607 SUI 7 ;IT'S A LETTER C364 FE10 CPI 10H C366 C9 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. ; ; ; C367 CD10C3 TERM: CALL PSCAN ;FIND IF INPUT PARAMETER IS PRESENT C36A 3206C8 STA IPORT ;SINP WILL USE THIS DRIVER (DEFAULT IS 1) C36D CD10C3 CALL PSCAN ;NOW FOR THE OUTPUT DRIVER C370 3207C8 STA OPORT ; C373 CD2EC0 TERM1: CALL KSTAT ;IS THERE ONE WAITING? C376 CA8BC3 JZ TIN ;IF NOT C379 47 MOV B,A ;SAVE IT IN B C37A FE80 CPI MODE ;IS IT MODE? C37C CAC0C1 JZ COMN1 ;YES...RESET AND QUIT TERM C37F DA88C3 JC TOUT ;NON-CURSOR KEY...SEND TO TERM PORT C382 CD54C0 CALL VDMOT ;PROCESS IT C385 C38BC3 JMP TIN ; C388 CD19C0 TOUT: CALL SOUT ;OUTPUT IT TO THE SERIAL PORT C38B CD1FC0 TIN: CALL SINP ;GET INPUT STATUS C38E CA73C3 JZ TERM1 ;LOOP IF NOT C391 E67F ANI 7FH ;NO HIGH BITS FROM HERE C393 CA73C3 JZ TERM1 ;A NULL IS IGNORED C396 47 MOV B,A ;IT'S OUTPUT FROM 'B' C397 FE1B CPI 1BH ;IS IT A CONTROL CHAR TO BE IGNORED C399 D2B9C3 JNC TERM2 ;NO...TO VDM AS IS THEN C39C FE0D CPI CR ;CR OR LF ARE SPECIAL CASES THOUGH C39E CAB9C3 JZ TERM2 ;AND MUST BE PASSED STD MODE TO VDM C3A1 FE0A CPI LF C3A3 CAB9C3 JZ TERM2 C3A6 3A0CC8 LDA ESCFL ;A CTRL CHAR...ARE WE W/IN ESC SEQUENCE? C3A9 B7 ORA A ;IF YES, THEN OUTPUT CTRL CHAR DIRECTLY TO VDM C3AA C2B9C3 JNZ TERM2 ;WE SURE ARE, LET VDM DRIVER HANDLE IT C3AD C5 PUSH B ;SAVE THE CHARACTER C3AE 061B MVI B,ESC ;CTRL CHAR TO VDM VIA ESC SEQUENCE C3B0 CD54C0 CALL VDMOT C3B3 0607 MVI B,7 ;SAY TO PUT OUT NEXT CHAR AS IS C3B5 CD54C0 CALL VDMOT ;ALMOST READY C3B8 C1 POP B ;RESTORE CHAR C3B9 = TERM2: EQU $ ;ALL READY TO OUTPUT THE CHAR C3B9 CD54C0 CALL VDMOT ;PUT IT ON THE SCREEN C3BC C373C3 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. ; C3BF CD3AC3 DUMP: CALL SCONV ;SCAN TO FIRST ADDRESS AND CONVERT IT C3C2 E5 PUSH H ;SAVE THE VALUE C3C3 CD10C3 CALL PSCAN ;SEE IF SECOND WAS GIVIN C3C6 D1 POP D C3C7 EB XCHG ;HL HAS START, DE HAS END ; C3C8 CDF9C2 DLOOP: CALL CRLF C3CB CDE8C3 CALL ADOUT ;OUTPUT ADDRESS C3CE CD06C4 CALL BOUT ;ANOTHER SPACE TO KEEP IT PRETTY C3D1 0E10 MVI C,16 ;VALUES PER LINE ; C3D3 7E DLP1: MOV A,M ;GET THE CHAR C3D4 C5 PUSH B ;SAVE VALUE COUNT C3D5 CDEDC3 CALL HBOUT ;SEND IT OUT WITH A BLANK C3D8 7D MOV A,L ;COMPARE DE AND HL C3D9 93 SUB E C3DA 7C MOV A,H C3DB 9A SBB D C3DC D2C9C1 JNC COMND ;ALL DONE C3DF C1 POP B ;VALUES PER LINE C3E0 23 INX H C3E1 0D DCR C ;BUMP THE LINE COUNT C3E2 C2D3C3 JNZ DLP1 ;NOT ZERO IF MORE FOR THIS LINE C3E5 C3C8C3 JMP DLOOP ;DO A LFCR BEFORE THE NEXT ; ; ; OUTPUT HL AS HEX 16 BIT VALUE ; C3E8 7C ADOUT: MOV A,H ;H FIRST C3E9 CD0BC4 CALL HEOUT C3EC 7D MOV A,L ;THEN L FOLLOWED BY A SPACE ; C3ED CD0BC4 HBOUT: CALL HEOUT C3F0 CD1FC0 CALL SINP ;SEE IF A CHAR WAITING C3F3 CA06C4 JZ BOUT ;NO C3F6 E67F ANI 7FH ;CLR PARITY FIRST THO C3F8 CAC9C1 JZ COMND ;EITHER MODE OR CTRL-@ C3FB FE20 CPI ' ' ;IS IT A SPACE C3FD C206C4 JNZ BOUT ;NO...IGNORE THE CHAR C400 CD1FC0 WTLP1: CALL SINP ;IF SPACE, WAIT UNTIL ANY OTHER KEY HIT C403 CA00C4 JZ WTLP1 ;THIS ALLOWS LOOKING AT THE DISPLAY C406 0620 BOUT: MVI B,' ' C408 C319C0 JMP SOUT ;PUT IT OUT ; C40B 4F HEOUT: MOV C,A ;GET THE CHARACTER C40C 0F RRC ;MOVE THE HIGH FOUR DOWN C40D 0F RRC C40E 0F RRC C40F 0F RRC C410 CD14C4 CALL HEOU1 ;PUT THEM OUT C413 79 MOV A,C ;THIS TIME THE LOW FOUR ; C414 E60F HEOU1: ANI 0FH ;FOUR ON THE FLOOR C416 C630 ADI 48 ;WE WORK WITH ASCII HERE C418 FE3A CPI 58 ;0-9? C41A DA1FC4 JC OUTH ;YUP C41D C607 ADI 7 ;MAKE IT A LETTER C41F 47 OUTH: MOV B,A ;OUTPUT IT FROM REGISTER 'B' C420 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. ; C423 CD3AC3 ENTER: CALL SCONV ;SCAN OVER CHARS AND GET ADDRESS C426 E5 PUSH H ;SAVE ADDRESS C427 AF XRA A C428 3207C8 STA OPORT ;ENTER VALUES TO SCREEN BUFFER ; C42B CDF9C2 ENLOP: CALL CRLF C42E 063A MVI B,':' C430 CDFFC1 CALL CONT ;GET LINE OF INPUT C433 CD36C1 CALL CREM ;REMOVE THE CURSOR C436 0E01 MVI C,1 ;START SCAN C438 CD20C1 CALL VDAD2 ;GET ADDRESS C43B EB XCHG ;....TO DE ; ; C43C 0E03 ENLO1: MVI C,3 ;NO MORE THAN THREE SPACES BETWEEN VALUES C43E CD30C3 CALL SCHR1 ;SCAN TO NEXT VALUE C441 CA2BC4 JZ ENLOP ;LAST ENTRY FOUND, START NEW LINE ; C444 FE2F CPI '/' ;COMMAND TERMINATOR C446 CAC0C1 JZ COMN1 ;IF SO, RETURN TO STANDARD INPUT C449 CD40C3 CALL SHEX ;CONVERT VALUE C44C FE3A CPI ':' ;ADDRESS TERMINATOR C44E CA59C4 JZ ENLO3 ;GO PROCESS IF SO C451 7D MOV A,L ;GET LOW PART AS CONVERTED C452 E1 POP H ;GET MEMORY ADDRESS C453 77 MOV M,A ;PUT IN THE VALUE C454 23 INX H C455 E5 PUSH H ;BACK GOES THE ADDRESS C456 C33CC4 JMP ENLO1 ;CONTINUE THE SCAN ; C459 E3 ENLO3: XTHL ;PUT NEW ADDRESS ON STACK C45A 13 INX D ;MOVE SCAN PAST TERMINATOR C45B C33CC4 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. ; ; C45E CD3AC3 EXEC: CALL SCONV ;SCAN PAST BLANKS AND GET PARAMETER C461 E5 EXEC1: PUSH H ;PUT GO ADDRESS ON STACK C462 2100C0 LXI H,START ;TELL THE PROGRAM WHERE WE CAME FROM C465 C9 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. ; ; C466 211CC8 NAMES: LXI H,THEAD ;POINT TO INTERNAL HEADER N NAME: CALL SBLK ;SCAN OVER TO FIRST CHRS C469 0606 MVI B,6 ;UP TO SIX ARE ACCEPTED ; C46B 1A NAME1: LDAX D ;GET CHARACTER C46C FE20 CPI ' ' ;NO UNIT DELIMITER C46E CA83C4 JZ NFIL C471 FE2F CPI '/' ;UNIT DELIMITER C473 CA83C4 JZ NFIL C476 77 MOV M,A C477 13 INX D ;BUMP THE SCAN POINTER C478 23 INX H C479 05 DCR B C47A C26BC4 JNZ NAME1 ;FALL THROUGH TO ERR1 IF TOO MANY CHRS IN NAME ; ; ; ***** SOLOS ERROR HANDLER ***** ; C47D EB ERR1: XCHG ;GET SCAN ADDRESS TO HL C47E 363F ERR2: MVI M,'?' ;PUT QUESTION MARK ON SCREEN C480 C3C0C1 JMP COMN1 ;AND RETURN TO COMMAND MODE ; ; ; HERE WE HAVE SCANNED OFF THE NAME. ZERO FILL FOR ; NAMES LESS THAN FIVE CHARACTERS. ; C483 3600 NFIL: MVI M,0 ;PUT IN AT LEAST ONE ZERO C485 23 INX H C486 05 DCR B C487 C283C4 JNZ NFIL ;LOOP UNTIL B IS ZERO ; C48A FE2F CPI '/' ;IS THERE A UNIT SPECIFICATION? C48C 3E01 MVI A,1 ;PRETEND NOT C48E C297C4 JNZ DEFLT C491 13 INX D ;MOVE PAST THE TERMINATOR C492 CD2EC3 CALL SCHR ;GO GET UNIT SPEC C495 D630 SUI '0' ;REMOVE ASCII BIAS ; C497 = DEFLT: EQU $ ;MOVE OVER TO INTERNAL REPRESENTATION C497 E601 ANI 1 ;JUST BIT ZERO C499 3E80 MVI A,TAPE1 ;ASSUME TAPE ONE C49B C29FC4 JNZ STUNT ;IF NON-ZERO, ITS ONE C49E 1F RAR C49F 3254C8 STUNT: STA FNUMF ;SET IT IN C4A2 C9 RET ; ; ; ; THIS ROUTINE PROCESSES THE XEQ AND GET COMMANDS ; ; C4A3 3E TXEQ: DB 3EH ;THIS BEGINS "MVI A,0AFH" C4A4 AF TLOAD: XRA A ;A=0 MEANS TLOAD, ELSE TXEQ C4A5 F5 PUSH PSW ;SAVE FLAG FOR LATER C4A6 212CC8 LXI H,DHEAD ;PLACE DUMMY HEADER HERE EC4A9 CD0000 CALL NAME ;SET IN NAME AND UNIT C4AC 210000 LXI H,0 ;PRETEND NO SECOND VALUE C4AF CD10C3 CALL PSCAN ;GO GET THE ADDRESS (IF PRESENT) ; C4B2 EB TLOA2: XCHG ;PUT ADDRESS IN DE C4B3 212CC8 LXI H,DHEAD ;POINT TO DUMMY HEADER WITH NAME TO LOAD C4B6 7E MOV A,M ;SEE IF A NAME WAS ENTERED C4B7 B7 ORA A ;IS THERE A NAME? C4B8 C2BEC4 JNZ TLOA3 ;YES...SEARCH FOR IT C4BB 211CC8 LXI H,THEAD ;NO NAME, LOAD 1ST FILE C4BE E5 TLOA3: PUSH H ;SAVE PTR TO NAME TO LOAD C4BF CD45C5 CALL ALOAD ;GET UNIT AND SPEED C4C2 E1 POP H ;RESTORE PTR TO HDR TO LOAD C4C3 CDC8C6 CALL RTAPE ;READ IN THE TAPE C4C6 DA11C5 JC TAERR ;TAPE ERROR? ; C4C9 CD4DC5 CALL NAOUT ;PUT OUT THE HEADER PARAMETERS C4CC F1 POP PSW ;RESTORE FLAG FROM ORIGINAL ENTRY C4CD B7 ORA A C4CE C8 RZ ;AUTO XEQ NOT WANTED C4CF 3A22C8 LDA HTYPE ;CHECK TYPE C4D2 B7 ORA A ;SET FLAGS C4D3 FA11C5 JM TAERR ;TYPE IS NOW XEQ C4D6 3A21C8 LDA THEAD+5 ;GET CHARACTER PAST NAME C4D9 B7 ORA A C4DA C211C5 JNZ TAERR ;THE BYTE MUST BE ZERO FOR AUTO XEQ C4DD 2A27C8 LHLD XEQAD ;GET THE TAPE ADDRESS C4E0 C361C4 JMP EXEC1 ;AND GO TO IT ; ; ; ***** GET COMMAND ***** ; ; THIS ROUTINE IS USED TO SAVE PROGRAMS AND DATA ON ; THE CASSETTE UNIT ; ; C4E3 CD66C4 TSAVE: CALL NAMES ;GET NAME AND UNIT C4E6 CD3AC3 CALL SCONV ;GET START ADDRESS C4E9 E5 PUSH H ;USE THE STACK AS A REGISTER C4EA CD3AC3 CALL SCONV ;GET END ADDRESS C4ED E3 XTHL ;PUT END ON STACK, GET BACK START C4EE E5 PUSH H ;SAVE START ON TOP OF STACK C4EF CD10C3 CALL PSCAN ;SEE IF OPTIONAL HEADER ADDRESS WAS GIVEN C4F2 2225C8 SHLD LOADR ;PUT HEADER ADDRESS IN PLACE ; C4F5 E1 POP H ;"FROM" ADDRESS TO HL C4F6 D1 POP D ;GET BACK END ADDRESS C4F7 E5 PUSH H ;SAVE FROM AGAIN FOR LATER C4F8 7B MOV A,E ;NOW CALCULATE SIZE C4F9 95 SUB L ;SIZE=END-START+1 C4FA 6F MOV L,A C4FB 7A MOV A,D C4FC 9C SBB H C4FD 67 MOV H,A C4FE 23 INX H C4FF 2223C8 SHLD BLOCK ;STORE THE SIZE C502 E5 PUSH H ;SAVE IT FOR THE READ ALSO ; C503 CD45C5 CALL ALOAD ;GET UNIT AND SPEED C506 211CC8 LXI H,THEAD ;POINT TO HEADER C509 CDACC7 CALL WHEAD ;AND WRITE IT OUT ; NOW WRITE OUT THE DATA C50C D1 POP D ;GET SIZE TO DE C50D E1 POP H ;GET BACK "FROM" ADDRESS C50E C38DC7 JMP WRLO1 ;WRITE OUT THE DATA AND RETURN ; ; ; OUTPUT ERROR AND HEADER ; C511 CDF9C2 TAERR: CALL CRLF C514 1606 MVI D,6 C516 2122C5 LXI H,ERRM ;POINT TO ERROR MESSAGE C519 CD67C5 CALL NLOOP ;OUTPUT ERROR C51C CD4DC5 CALL NAOUT ;THEN THE HEADER C51F C3C0C1 JMP COMN1 ;AND BE SURE THE TAPE UNITS ARE OFF ; C522 4552524F52ERRM: DB 'ERROR ' ; ; ; THIS ROUTINE READS HEADERS FROM THE TAPE AND OUTPUTS ; THEM TO THE OUTPUT DEVICE. IT CONTINUES UNTIL THE ; MODE KEY IS DEPRESSED. ; C528 CD66C4 TLIST: CALL NAMES ;SET UP UNIT IF GIVEN C52B CDF9C2 CALL CRLF ; ; C52E CD45C5 LLIST: CALL ALOAD C531 0601 MVI B,1 C533 CDECC7 CALL TON ;TURN ON THE TAPE ; C536 CD20C7 LIST1: CALL RHEAD C539 DAC0C1 JC COMN1 ;TURN OFF THE TAPE UNIT C53C C236C5 JNZ LIST1 C53F CD4DC5 CALL NAOUT ;OUTPUT THE HEADER C542 C336C5 JMP LIST1 ;LOOP UNTIL MODE IS DEPRESSED ; ; ; THIS ROUTINE GETS THE CASSETTE UNIT NUMBER AND ; SPEED TO REGISTER "A" FOR THE TAPE CALLS ; C545 2154C8 ALOAD: LXI H,FNUMF ;POINT TO THE UNIT SPECIFICATION C548 3A0DC8 LDA TSPD ;GET THE TAPE SPEED C54B B6 ORA M ;PUT THEM TOGETHER C54C C9 RET ;AND GO BACK ; ; ; THIS ROUTINE OUTPUTS THE NAME AND PARAMETERS OF ; THEAD TO THE OUTPUT DEVICE. ; ; C54D 1608 NAOUT: MVI D,8 C54F 211BC8 LXI H,THEAD-1 ;POINT TO THE HEADER C552 CD67C5 CALL NLOOP ;OUTPUT THE HEADER C555 CD06C4 CALL BOUT ;ANOTHER BLANK C558 2A25C8 LHLD LOADR ;NOW THE LOAD ADDRESS C55B CDE8C3 CALL ADOUT ;PUT IT OUT C55E 2A23C8 LHLD BLOCK ;AND THE BLOCK SIZE C561 CDE8C3 CALL ADOUT C564 C3F9C2 JMP CRLF ;DO THE CRLF AND RETURN ; ; C567 7E NLOOP: MOV A,M ;GET CHARACTER C568 B7 ORA A C569 C26EC5 JNZ CHRLI ;IF IT ISN'T A ZERO C56C 3E20 MVI A,' ' C56E CD1FC4 CHRLI: CALL OUTH ;OUTPUT CHAR NOW C571 23 INX H C572 15 DCR D C573 C267C5 JNZ NLOOP C576 C9 RET ; ; ; ; ; ***** SET COMMAND ***** ; ; THIS ROUTINE GETS THE ASSOCIATED PARAMETER AND ; DISPATCHES TO THE PROPER ROUTINE FOR SETTING ; GLOBAL VALUES. ; C577 = CSET: EQU $ ;THIS IS THE SET COMMAND C577 CD1BC3 CALL SBLK ;LOOK FOR SET NAME C57A CA7DC4 JZ ERR1 ;MUST HAVE A LEAST SOMETHING!! C57D D5 PUSH D ;SAVE SCAN ADDRESS C57E CD3AC3 CALL SCONV ;CONVERT FOLLOWING VALUE C581 E3 XTHL ;GET SCAN ADDR BACK...SAVE VALUE ON STACK C582 11A2C2 LXI D,SETAB ;SECONDARY COMMAND TABLE C585 CD31C2 CALL FDCOM ;SEE IF IN TABLE C588 C322C2 JMP DISPO ;AND EITHER ERR OR OFF TO IT ; ; ; THIS ROUTINE SETS THE TAPE SPEED ; C58B B7 TASPD: ORA A ;IS IT ZERO? C58C CA91C5 JZ SETSP ;YES...THAT'S A VALID SPEED C58F 3E20 MVI A,32 ;SET TO SLOW IF NON-ZERO C591 320DC8 SETSP: STA TSPD ;SPEED IS STORED HERE C594 C9 RET ; ; C595 78 STSPD: MOV A,B ;ESCAPE COMES HERE TO SET SPEED C596 320BC8 DISPD: STA SPEED ;SET DISPLAY SPEED C599 C9 RET ; ; SET INPUT DRIVER ; C59A = SETIN: EQU $ C59A 3206C8 STA IPORT C59D C9 RET ; ; SET OUTPUT DRIVER ; C59E = SETOT: EQU $ C59E 3207C8 STA OPORT C5A1 C9 RET ; ; SET USERS CUSTOM INPUT DRIVER ADDRESS ; C5A2 2200C8 SETCI: SHLD UIPRT C5A5 C9 RET ; ; SET USERS CUSTOM OUTPUT DRIVER ADDRESS ; C5A6 2202C8 SETCO: SHLD UOPRT C5A9 C9 RET ; ; SET TYPE BYTE INTO HEADER ; C5AA 3222C8 SETTY: STA HTYPE C5AD C9 RET ; ; SET EXECUTE ADDRESS INTO HEADER ; C5AE 2227C8 SETXQ: SHLD XEQAD C5B1 C9 RET ; ; C5B2 3210C8 SETNU: STA NUCNT ;SET THE NULL COUNT C5B5 C9 RET ;THAT'S DONE ; ; C5B6 = SETCR: EQU $ ;SET TO IGNORE CRC ERRORS C5B6 3211C8 STA IGNCR ;FF=IGNORE ERRORS, ELSE=NORMAL C5B9 C9 RET ; ; ; ; CUSTOM COMMAND NAME AND ADDRESS INTO CUSTOM COMMAND ; C5BA CD66C4 CUSET: CALL NAMES ;CUSTOM COMMAND ENTRY/REMOVAL C5BD 21C9C1 LXI H,COMND ;DEFAULT ADDR IF NONE GIVEN C5C0 CD10C3 CALL PSCAN ;GET RTN ADDRESS C5C3 E5 PUSH H ;SAVE RTN ADDRESS C5C4 211CC8 LXI H,THEAD ;POINT AT NAME TO SEARCH C5C7 CD2EC2 CALL FDCOU ;SEARCH IT IN CUSTOM TABLE C5CA CAD0C5 JZ CUSE2 ;NOT IN TABLE...ENTER IT C5CD 1B DCX D ;IN TABLE, REMOVE IT C5CE 3600 MVI M,0 ;CHANGE NEW NAME TO BE ZERO C5D0 7E CUSE2: MOV A,M ;GET 1ST CHAR OF NAME C5D1 12 STAX D ;ENTER IT INTO TABLE C5D2 13 INX D ;AND THE 2ND NAME C5D3 23 INX H C5D4 7E MOV A,M C5D5 12 STAX D ;NAME NOW ENTERED C5D6 13 INX D ;GET SET TO ENTER ADDRESS C5D7 E1 POP H ;RESTORE RTN ADDR C5D8 EB XCHG C5D9 73 MOV M,E ;SET ADDR IN NOW C5DA 23 INX H ;AND HI BYTE OF ADDR C5DB 72 MOV M,D C5DC C9 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 ; ; C5DD E5 BOPEN: PUSH H ;SAVE HEADER ADDRESS C5DE CD30C6 CALL LFCB ;GET ADDRESS OF FILE CONTROL C5E1 C2F7C5 JNZ TERE2 ;FILE WAS ALREADY OPEN C5E4 3601 MVI M,1 ;NOW IT IS C5E6 23 INX H ;POINT TO READ COUNT C5E7 77 MOV M,A ;ZERO C5E8 23 INX H ;POINT TO BUFFER CURSOR C5E9 77 MOV M,A ;PUT IN THE ZERO COUNT ; ; ALLOCATE THE BUFFER ; C5EA 1163C8 LXI D,FBUF1 ;POINT TO BUFFER AREA C5ED 3A54C8 LDA FNUMF ;GET WHICH ONE WE ARE GOING TO USE C5F0 82 ADD D C5F1 57 MOV D,A ;256 BIT ADD ; C5F2 C1 UBUF: POP B ;HEADER ADDRESS C5F3 B7 ORA A ;CLEAR CARRY AND RET AFTER STORING PARAMS C5F4 C3B3C6 JMP PSTOR ;STORE THE VALUES ; ; GENERAL ERROR RETURN POINTS FOR STACK CONTROL ; C5F7 E1 TERE2: POP H C5F8 D1 TERE1: POP D C5F9 AF TERE0: XRA A ;CLEAR ALL FLAGS C5FA 37 STC ;SET ERROR C5FB C9 RET ; ; C5FC 3D EOFER: DCR A ;SET MINUS FLAGS C5FD 37 STC ;AND CARRY C5FE D1 POP D ;CLEAR THE STACK C5FF 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 ; ; C600 CD30C6 PCLOS: CALL LFCB ;GET CONTROL BLOCK ADDRESS C603 C8 RZ ;WASN'T OPEN, CARRY IS SET FROM LFCR C604 B7 ORA A ;CLEAR CARRY C605 3C INR A ;SET CONDITION FLAGS C606 3600 MVI M,0 ;CLOSE THE CONTROL BYTE C608 C8 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 ; ; C609 23 INX H C60A 23 INX H C60B 7E MOV A,M ;GET CURSOR POSITION C60C 7E MOV A,M ;ACCIDENT? C60D CDBCC6 CALL PLOAD ;BC GET HEADER ADDRESS, DE BUFFER ADDRESS C610 C5 PUSH B ;HEADER TO STACK C611 210700 LXI H,BLKOF ;OFFSET TO BLOCK SIZE C614 09 DAD B C615 B7 ORA A ;TEST COUNT C616 CA28C6 JZ EOFW ;NO BYTES...JUST WRITE EOF ; ; WRITE LAST BLOCK ; C619 E5 PUSH H ;SAVE BLOCK SIZE POINTER FOR EOF C61A 77 MOV M,A ;PUT IN COUNT C61B 23 INX H C61C 3600 MVI M,0 ;ZERO THE HIGHER BYTE C61E 23 INX H C61F 73 MOV M,E ;BUFFER ADDRESS C620 23 INX H C621 72 MOV M,D C622 60 MOV H,B C623 69 MOV L,C ;PUT HEADER ADDRESS IN HL C624 CD79C7 CALL WFBLK ;GO WRITE IT OUT C627 E1 POP H ;BLOCK SIZE POINTER ; ; NOW WRITE END OF FILE TO CASSETTE ; C628 AF EOFW: XRA A ;PUT IN ZEROS FOR SIZE ;EOF MARK IS ZERO BYTES! C629 77 MOV M,A C62A 23 INX H C62B 77 MOV M,A C62C E1 POP H ;HEADER ADDRESS C62D C379C7 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. ; ; C630 2155C8 LFCB: LXI H,FCBAS ;POINT TO THE BASE OF IT C633 1F RAR ;MOVE THE 1 & 2 TO 0 & 1 C634 E601 ANI 1 ;SMALL NUMBERS ARE THE RULE C636 3254C8 STA FNUMF ;CURRENT ACCESS FILE NUMBER C639 CA3FC6 JZ LFCB1 ;UNIT ONE (VALUE OF ZERO) C63C 215CC8 LXI H,FCBA2 ;UNIT TWO--POINT TO ITS FCB C63F = LFCB1: EQU $ ;HL POINT TO PROPER FCB C63F 7E MOV A,M ;PICK UP FLAGS FROM FCB C640 B7 ORA A ;SET FLAGS BASED ON CONTROL WORD C641 37 STC ;SET CARRY IN CASE OF IMMEDIATE ERROR RET C642 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 ; ; ; ; C643 CD30C6 RTBYT: CALL LFCB ;LOCATE THE FILE CONTROL BLOCK C646 C8 RZ ;FILE NOT OPEN C647 3C INR A ;TEST IF FF C648 FAF9C5 JM TERE0 ;ERROR WAS WRITING C64B 36FF MVI M,(-1) AND 0FFH ;SET IT AS READ (IN CASE IT WAS JUST OPENED) C64D 23 INX H C64E 7E MOV A,M ;GET READ COUNT C64F E5 PUSH H ;SAVE COUNT ADDRESS C650 23 INX H C651 CDBCC6 CALL PLOAD ;GET THE OTHER PARAMETERS C654 E1 POP H C655 B7 ORA A C656 C272C6 JNZ GTBYT ;IF NOT EMPTY GO GET BYTE ; ; CURSOR POSITION WAS ZERO...READ A NEW BLOCK ; INTO THE BUFFER. ; C659 D5 RDNBLK: PUSH D ;BUFFER POINTER C65A E5 PUSH H ;TABLE ADDRESS C65B 23 INX H C65C CDA3C6 CALL PHEAD ;PREPARE THE HEADER FOR READ C65F CDC5C6 CALL RFBLK ;READ IN THE BLOCK C662 DAF7C5 JC TERE2 ;ERROR POP OFF STACK BEFORE RETURN C665 E1 POP H C666 7B MOV A,E ;LOW BYTE OF COUNT (WILL BE ZERO IF 256) C667 B2 ORA D ;SEE IF BOTH ARE ZERO C668 CAFCC5 JZ EOFER ;BYTE COUNT WAS ZERO...END OF FILE C66B 73 MOV M,E ;NEW COUNT (ZERO IS 256 AT THIS POINT) C66C 23 INX H ;BUFFER LOCATION POINTER C66D 3600 MVI M,0 C66F 2B DCX H C670 7B MOV A,E ;GET BACK BUFFER ADDRESS C671 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. ; C672 3D GTBYT: DCR A ;BUMP THE COUNT C673 77 MOV M,A ;RESTORE IT C674 23 INX H C675 7E MOV A,M ;GET BUFFER POSITION C676 34 INR M ;BUMP IT ; C677 83 ADD E C678 5F MOV E,A ;DE NOW POINT TO CORRECT BUFFER POSITION C679 D27DC6 JNC RT1 C67C 14 INR D C67D 1A RT1: LDAX D ;GET CHARACTER FROM BUFFER C67E B7 ORA A ;CLEAR CARRY C67F 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 ; ; C680 CD30C6 WTBYT: CALL LFCB ;GET CONTROL BLOCK C683 C8 RZ ;FILE WASN'T OPEN C684 3C INR A C685 C8 RZ ;FILE WAS READ C686 36FE MVI M,0FEH ;SET IT TO WRITE C688 23 INX H C689 23 INX H C68A 78 MOV A,B ;GET CHARACTER C68B F5 PUSH PSW C68C E5 PUSH H ;SAVE CONTROL ADDRESS+2 ; ; NOW DO THE WRITE ; C68D CDBCC6 CALL PLOAD ;BC GETS HEADER ADDR ;DE BUFFER ADDRESS C690 E1 POP H C691 7E MOV A,M ;COUNT BYTE C692 83 ADD E C693 5F MOV E,A C694 D298C6 JNC WT1 C697 14 INR D C698 F1 WT1: POP PSW ;CHARACTER C699 12 STAX D ;PUT CHR IN BUFFER C69A B7 ORA A ;CLEAR FLAGS C69B 34 INR M ;INCREMENT THE COUNT C69C C0 RNZ ;RETURN IF COUNT DIDN'T ROLL OVER ; ; THE BUFFER IS FULL. WRITE IT TO TAPE ; AND RESET CONTROL BLOCK. ; C69D CDA3C6 CALL PHEAD ;PREPARE THE HEADER C6A0 C379C7 JMP WFBLK ;WRITE IT OUT AND RETURN ; ; ; ; ; THIS ROUTINE PUTS THE BLOCK SIZE (256) AND BUFFER ; ADDRESS IN THE FILE HEADER. ; C6A3 CDBCC6 PHEAD: CALL PLOAD ;GET HEADER AND BUFFER ADDRESSES C6A6 C5 PUSH B ;HEADER ADDRESS C6A7 210600 LXI H,BLKOF-1 ;PSTOR DOES AN INCREMENT C6AA 09 DAD B ;HL POINTS TO BLOCKSIZE ENTRY C6AB 010001 LXI B,256 C6AE CDB3C6 CALL PSTOR C6B1 E1 POP H ;HL RETURN WITH HEADER ADDRESS C6B2 C9 RET ; ; C6B3 23 PSTOR: INX H C6B4 71 MOV M,C C6B5 23 INX H C6B6 70 MOV M,B C6B7 23 INX H C6B8 73 MOV M,E C6B9 23 INX H C6BA 72 MOV M,D C6BB C9 RET ; ; C6BC 23 PLOAD: INX H C6BD 4E MOV C,M C6BE 23 INX H C6BF 46 MOV B,M C6C0 23 INX H C6C1 5E MOV E,M C6C2 23 INX H C6C3 56 MOV D,M C6C4 C9 RET ; ; ; ; ;THIS ROUTINE SETS THE CORRECT UNIT FOR SYSTEM READS ; C6C5 CDDBC7 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 ; ; C6C8 D5 RTAPE: PUSH D ;SAVE OPTIONAL ADDRESS C6C9 0603 MVI B,3 ;SHORT DELAY C6CB CDECC7 CALL TON C6CE DBFB IN TDATA ;CLEAR THE UART FLAGS ; C6D0 E5 PTAP1: PUSH H ;HEADER ADDRESS C6D1 CD20C7 CALL RHEAD ;GO READ HEADER C6D4 E1 POP H C6D5 DA03C7 JC TERR ;IF AN ERROR OR ESC WAS RECEIVED C6D8 C2D0C6 JNZ PTAP1 ;IF VALID HEADER NOT FOUND ; ; FOUND A VALID HEADER NOW DO COMPARE ; C6DB E5 PUSH H ;GET BACK AND RESAVE ADDRESS C6DC 111CC8 LXI D,THEAD C6DF CDCFC7 CALL DHCMP ;COMPARE DE/HL HEADERS C6E2 E1 POP H C6E3 C2D0C6 JNZ PTAP1 ; ; C6E6 D1 POP D ;OPTIONAL "PUT" ADDRESS C6E7 7A MOV A,D C6E8 B3 ORA E ;SEE IF DE IS ZERO C6E9 2A23C8 LHLD BLOCK ;GET BLOCK SIZE C6EC EB XCHG ;....TO DE ; DE HAS HBLOCK...HL HAS USER OPTION C6ED C2F3C6 JNZ RTAP ;IF DE WAS 0 GET TAPE LOAD ADDR C6F0 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 ; C6F3 D5 RTAP: PUSH D ;SAVE SIZE FOR RETURN TO CALLING PROGRAM ; C6F4 = RTAP2: EQU $ ;HERE TO LOOP RDING BLKS C6F4 CD12C7 CALL DCRCT ;DROP COUNT, B=LEN THIS BLOCK C6F7 CA0DC7 JZ RTOFF ;ZERO=ALL DONE ; C6FA CD41C7 CALL RHED1 ;READ THAT MANY BYTES C6FD DA03C7 JC TERR ;IF ERROR OR ESC C700 CAF4C6 JZ RTAP2 ;RD OK...READ SOME MORE ; ; ERROR RETURN ; C703 AF TERR: XRA A C704 37 STC ;SET ERROR FLAGS C705 C30EC7 JMP RTOF1 ; ; C708 0601 TOFF: MVI B,1 C70A CDEEC7 CALL DELAY C70D AF RTOFF: XRA A C70E D3FA RTOF1: OUT TAPPT C710 D1 POP D ;RETURN BYTE COUNT C711 C9 RET ; ; C712 = DCRCT: EQU $ ;COMMON RTN TO COUNT DOWN BLK LENGTHS C712 AF XRA A ;CLR FOR LATER TESTS C713 47 MOV B,A ;SET THIS BLK LEN = 256 C714 B2 ORA D ;IS ANMT LEFT < 256 C715 C21DC7 JNZ DCRC2 ;NO...REDUCE AMNT BY 256 C718 B3 ORA E ;IS ENTIRE COUNT ZERO C719 C8 RZ ;ALL DONE..ZERO=THIS CONDITION C71A 43 MOV B,E ;SET THIS BLK LEN TO AMNT REMAINING C71B 5A MOV E,D ;MAKE ENTIRE COUNT ZERO NOW C71C C9 RET ;ALL DONE (NON-ZERO FLAG) C71D = DCRC2: EQU $ ;REDUCE COUNT BY 256 C71D 15 DCR D ;DROP BY 256 C71E B7 ORA A ;FORCE NON-ZERO FLAG C71F C9 RET ;NON-ZERO=NOT DONE YET (BLK LEN=256) ; ; ; READ THE HEADER ; C720 060A RHEAD: MVI B,10 ;FIND 10 NULLS C722 CD5AC7 RHEA1: CALL STAT C725 D8 RC ;IF ESCAPE C726 DBFB IN TDATA ;IGNORE ERROR CONDITIONS C728 B7 ORA A ;ZERO? C729 C220C7 JNZ RHEAD C72C 05 DCR B C72D C222C7 JNZ RHEA1 ;LOOP UNTIL 10 IN A ROW ; ; WAIT FOR THE START CHARACTER ; C730 CD6CC7 SOHL: CALL TAPIN C733 D8 RC ;ERROR OR ESCAPE C734 FE01 CPI 1 ;AT LEAST 10 NULLS FOLLOWED BY A 01 C736 DA30C7 JC SOHL ;STILL A NULL, KEEP WAITING C739 C220C7 JNZ RHEAD ;NON-ZERO, START SEQUENCE OVER AGAIN ; ; NOW GET THE HEADER ; C73C 211CC8 LXI H,THEAD ;POINT TO BUFFER C73F 0610 MVI B,HLEN ;LENGTH TO READ ; C741 = RHED1: EQU $ ;RD A BLOCK INTO HL FOR B BYTES C741 0E00 MVI C,0 ;INITALIZE THE CRC C743 = RHED2: EQU $ ;LOOP HERE C743 CD6CC7 CALL TAPIN ;GET A BYTE C746 D8 RC C747 77 MOV M,A ;STORE IT C748 23 INX H ;INCREMENT ADDRESS C749 CDA5C7 CALL DOCRC ;GO COMPUTE THE CRC C74C 05 DCR B ;WHOLE HEADER YET? C74D C243C7 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. ; C750 CD6CC7 CALL TAPIN ;GET CRC BYTE C753 A9 XRA C ;CLR CARRY AND SET ZERO IF MATCH ; ELSE NON-ZERO C754 C8 RZ ;CRC WAS FINE C755 3A11C8 LDA IGNCR ;GET POSSIBLE OVERRIDE CRC ERROR FLAG C758 3C INR A ;FF=IGNORE CRC ERRORS C759 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. ; C75A DBFA STAT: IN TAPPT ;TAPE STATUS PORT C75C E640 ANI TDR C75E C0 RNZ C75F CD1FC0 CALL SINP ;CHECK INPUT C762 CA5AC7 JZ STAT ;NOTHING THERE YET C765 E67F ANI 7FH ;CLR PARITY FIRST C767 C25AC7 JNZ STAT ;NOT A MODE (OR EVEN CTRL-@) C76A 37 STC ;SET ERROR FLAG C76B C9 RET ;AND RETURN ; ; ; C76C CD5AC7 TAPIN: CALL STAT ;WAIT UNTIL A CHARACTER IS AVAILABLE C76F D8 RC ; C770 DBFA TREDY: IN TAPPT ;TAPE STATUS C772 E618 ANI TFE+TOE ;DATA ERROR? C774 DBFB IN TDATA ;GET THE DATA C776 C8 RZ ;IF NO ERRORS C777 37 STC ;SET ERROR FLAG C778 C9 RET ; ; ; THIS ROUTINE GETS THE CORRECT UNIT FOR SYSTEM WRITES ; C779 CDDBC7 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 ; ; C77C = WTAPE: EQU $ ;HERE TO WRITE TAPE C77C E5 PUSH H ;SAVE HEADER ADDRESS C77D CDACC7 CALL WHEAD ;TURN ON, THEN WRITE HEADER C780 E1 POP H C781 110700 LXI D,BLKOF ;OFFSET TO BLOCK SIZE IN HEADER C784 19 DAD D ;HL POINT TO BLOCK SIZE C785 5E MOV E,M C786 23 INX H C787 56 MOV D,M ;DE HAS SIZE C788 23 INX H C789 7E MOV A,M C78A 23 INX H C78B 66 MOV H,M C78C 6F MOV L,A ;HL HAS STARTING ADDRESS ; ; THIS ROUTINE WRITES ONE PHYSICAL BLOCK ON THE ; TAPE "DE" BYTES LONG FROM ADDRESS "HL". ; ; C78D = WRLO1: EQU $ ;HERE FOR THE EXTRA PUSH C78D E5 PUSH H ;A DUMMY PUSH FOR LATER EXIT C78E = WTAP2: EQU $ ;LOOP HERE UNTIL ENTIRE AMOUNT READ C78E CD12C7 CALL DCRCT ;DROP COUNT IN DE AND SET UP B ;WITH LENGTH THIS BLOCK C791 CA08C7 JZ TOFF ;RETURNS ZERO IF ALL DONE C794 CDC0C7 CALL WTBL ;WRITE BLOCK FOR BYTES IN B (256) C797 C38EC7 JMP WTAP2 ;LOOP UNTIL ALL DONE ; ; C79A F5 WRTAP: PUSH PSW C79B DBFA WRWAT: IN TAPPT ;TAPE STATUS C79D E680 ANI TTBE ;IS TAPE READY FOR A CHAR YET C79F CA9BC7 JZ WRWAT ;NO...WAIT C7A2 F1 POP PSW ;YES...RESTORE CHAR TO OUTPUT C7A3 D3FB OUT TDATA ;SEND CHAR TO TAPE ; C7A5 = DOCRC: EQU $ ;A COMMON CRC COMPUTATION ROUTINE C7A5 91 SUB C C7A6 4F MOV C,A C7A7 A9 XRA C C7A8 2F CMA C7A9 91 SUB C C7AA 4F MOV C,A C7AB C9 RET ;ONE BYTE NOW WRITTEN ; ; ; THIS ROUTINE WRITES THE HEADER POINTED TO BY ; HL TO THE TAPE. ; C7AC = WHEAD: EQU $ ;HERE TO FIRST TURN ON THE TAPE C7AC CDEAC7 CALL WTON ;TURN IT ON, THEN WRITE HEADER C7AF 1632 MVI D,50 ;WRITE 50 ZEROS C7B1 AF NULOP: XRA A C7B2 CD9AC7 CALL WRTAP C7B5 15 DCR D C7B6 C2B1C7 JNZ NULOP ; C7B9 3E01 MVI A,1 C7BB CD9AC7 CALL WRTAP C7BE 0610 MVI B,HLEN ;LENGTH TO WRITE OUT ; C7C0 0E00 WTBL: MVI C,0 ;RESET CRC BYTE C7C2 7E WLOOP: MOV A,M ;GET CHARACTER C7C3 CD9AC7 CALL WRTAP ;WRITE IT TO THE TAPE C7C6 05 DCR B C7C7 23 INX H C7C8 C2C2C7 JNZ WLOOP C7CB 79 MOV A,C ;GET CRC C7CC C39AC7 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 ; C7CF 0605 DHCMP: MVI B,5 C7D1 1A DHLOP: LDAX D C7D2 BE CMP M C7D3 C0 RNZ C7D4 05 DCR B C7D5 C8 RZ ;IF ALL FIVE COMPARED C7D6 23 INX H C7D7 13 INX D C7D8 C3D1C7 JMP DHLOP ; C7DB = GTUNT: EQU $ ;SET A=SPEED + UNIT C7DB 3A54C8 LDA FNUMF ;GET UNIT C7DE B7 ORA A ;SEE WHICH UNIT C7DF 3A0DC8 LDA TSPD ;BUT FIRST GET SPEED C7E2 C2E7C7 JNZ GTUN2 ;MAKE IT UNIT TWO C7E5 C640 ADI TAPE2 ;THIS ONCE=UNIT 2, TWICE=UNIT 1 C7E7 C640 GTUN2: ADI TAPE2 ;UNIT AND SPEED NOW SET IN A C7E9 C9 RET ;ALL DONE ; C7EA 0604 WTON: MVI B,4 ;SET LOOP DELAY, (BIT LONGER ON WRITE) C7EC = TON: EQU $ ;HERE TO TURN A TAPE ON THEN DELAY C7EC D3FA OUT TAPPT ;GET TAPE MOVING, THEN DELAY ; C7EE 110000 DELAY: LXI D,0 C7F1 1B DLOP1: DCX D C7F2 7A MOV A,D C7F3 B3 ORA E C7F4 C2F1C7 JNZ DLOP1 C7F7 05 DCR B C7F8 C2EEC7 JNZ DELAY C7FB C9 RET C7FC 00 NOP ; PAD OUT TO EXACTLY FILL 2KB ; ; ;********* 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 ; ; ; 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 TRANSMITTER 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 0C800H ;START OF 1K RAM AREA ; C800 = SYSRAM EQU $ ;START OF SYSTEM RAM CBFF = SYSTP EQU $+1023 ;STACK IS AT THE TOP ; ; ; ***** PARAMETERS STORED IN RAM ***** ; C800 UIPRT DS 2 ;USER DEFINED INPUT RTN IF NON-ZERO C802 UOPRT DS 2 ;USER DEFINED OUTPUT RTN IF NON-ZERO C804 DFLTS DS 2 ;DEFAULT PSUEDO I/O PORTS ; (ALWAYS ZERO IN SOLOS) 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 INPTR DS 2 ;FOR COMPATABILITY W/CUTER C810 NUCNT DS 1 ;NUMBER OF NULLS AFTER CRLF C811 IGNCR DS 1 ;FF=IGNORE CRC ERRORE, ELSE NORMAL ; C812 DS 10 ;ROOM FOR FUTURE EXPANSION ; ; ; 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 ;A DUMMY HDR FOR COMPARES WHILE RDING ; ; C83C CUTAB DS 6*4 ;ROOM FOR UP TO 6 CUSTOM USER COMMANDS ; ; C854 FNUMF DS 1 ;FOR CURRENT FILE OPERATIONS C855 FCBAS DS 7 ;1ST FILE CONTROL BLOCK C85C FCBA2 DS 7 ;2ND FILE CONTROL BLOCK C863 FBUF1 DS 2*256 ;SYSTEM FILE BUFFER BASE CA63 DS 81 ;THIS IS AN AREA USED BY CUTER CAB4 = USARE EQU $ ;START OF USER AREA ***************** ; REMEMBER THAT THE STACK WORKS ITS WAY DOWN FROM ; THE END OF THIS 1K RAM AREA. ; ; ; CAB4 END