+-------------------------+} ! APOLOGY TO CHRIS BUNSEN !} +-------------------------+} } This Titan File must start with an apology to Chris Bunsen, an HP employee who has written some wonderful software for the HP-71. (I mentioned his GRAPH71 in HPX Exchange V1 N1 P25, Q26). It seems that I obtained a copy of SPLEX from an imprudent source, and believed it to be "freeware". With this in mind, I ran the LEXSPLIT program on it, to remove the LIST$ and MODIFY keywords, and thus created the lexfile known as BASICLEX. This has been proliferating among the HP-71 community for almost two years now, and only last Saturday did I learn from Brian that it is in fact "pirated" software.} } So besides publicly apologizing to Chris Bunsen, who wrote SPLEX for his HP-71 spreadsheet program, I must also ask all of you kind folks who have a copy of BASICLEX to immediately PURGE it from memory, disk, tape and cards! It does not have the support of the author, to put it mildly. I just finished chatting with him on the phone, and he was relieved to hear that I had not copied it from a purchased copy of his spreadsheet, but still wants the record set straight.} } PURGE BASICLEX!!! It's not on the official swapdiscs, but it may be on one of your copies, so please check.} } One reason for killing BASICLEX is that it reportedly contains bugs that SPLEX does not contain. I have not verified this, but no sense tempting fate, so use SPLEX instead of BASICLEX. This is possible because Chris kindly donated SPLEX to the Markov Swapdisc program. You can find it on SWAP07, along with source code listings disassembled and commented by Mike Markov.} } Final note: until this morning's chat with Chris, he was not aware of the LIST$ bug mentioned in the CHHU Chronicle and in the BUFSTO10 documentation on SWAP07. The bug works like this. Type 10 DIM A(MEM/16). Then type A$=LIST$(10). You will immediately see Memory Lost! The problem is the MEM in the DIMension. In general, any lexfile function (including LEX 01, the built-in lexfile) used in a DIM statement of any kind (like INTEGER, COMPLEX, etc.) when pulled out by the LIST$ function during an assignment to a string variable, causes Memory Lost. So anything like A$=LIST$(10,F$) when F$'s line 10 is INTEGER M(MAXRC) will always wipe out. Perhaps Chris will track this bug down and give us a debugged version of SPLEX. If so, it'll be on the next swapdisc!} } } +--------------+} ! THEOLOGY ROM !} +--------------+} } As the astute noticed, the Quick Reference Guide in "HP-71 BASIC Made Easy" (pg. 147) refers to the CREATE ALL statement in the THEOLOGY ROM. This is just one of the many keywords to be found in this huge lexfile. It is based on a higher source code, which unfortunately this magazine is too small to contain. But I just have to tell you about CREATE ALL; you are sure to get a big bang out of it!} } CREATE ALL, as the name implies, creates everything. Since this is such an immense task, it takes about six DAYS (!) to finish, after which the configuration code works for another 24 hours making sure that what was CREATEd is indeed good, during which time the HP-71 will appear to have gone into deep sleep. Of course, CREATE ALL only works if ALL does not already exist. If ALL already exists, CREATE ALL gives the "File already exists" error. If this occurs, it isn't enough to PURGE ALL or even DESTROY ALL. The THEOLOGY ROM has an expanded version of END ALL that does the trick. Proper use of END ALL is vital, since further action by users who have ENDed is impossible. The following is suggested: "END ALL @ CREATE ALL" on one line!} } If interested in CREATE ALL and END ALL, please look for a subset lexfile called GENESIS on a future swapdisc! But PLEASE use it carefully!} } } +-----------------------+} ! HARD DISK IN A MODULE !} +-----------------------+} } Looking for the perfect Christmas Stocking-stuffer gift for a loved one who already has an HP-71? Here it is!} } Diebstahl Electro-Acoustical Products, Inc (DEAP) has designed the most amazing HP-71 peripheral ever. Thanks to a new, esoteric and mendacious technology, DEAP has managed to fit a complete hard-disk Winchester drive and controller board INSIDE one (1) HP-71 module package!} } DEAP, formed in the early 70's by several Triangle Fraternity EE's at Illinois Institute of Technology (IIT), has often been showered with adumbration, but has remained unknown to most OEM's. Now, their new product may obviate facing the problems related to sudden fortune and fame.} } Although not yet officially announced, an interview between your Titan File editor and DEAP's hot-line modem and ALPO bulletin board system revealed the following incredible details regarding the new disk module:} } The device plugs directly into any HP-71 port and addresses the data in file format just like the 9114 disk drive from HP. Approximately 3142 megabytes (that's over 3KKK) are on-line. Special commands allow storing/recalling files, buffers, alternate operating systems, and digitized images. Rumors that disk access is so fast that files can be run without copying them back into RAM are tantalizing.} } The drive was actually a design mistake. DEAP had programmed the IIT computer to generate any conceivable device when given the electronic and packaging parameters. One day they tried to design a large-memory, low-power 3.5-inch Winchester drive, but somebody typed .5 by mistake. To their amazement, the program found a solution and designed the new HP-71 disk drive.} } The module is designed with a piggy-back bus. If one is not enough, you can just plug another one into the one already there. Due to the daisy-chain logic, however, access time rapidly degenerates after more than one terabyte is on-line. Also, the battery drain becomes considerable.} } One design oddity is that data is not erasable once it has been written to disk. There are two heads: a write head, and a read head. Since they cannot move over each other, the write head is always ahead of the read head, and writes sequentially only. Updating files is done by copying it with the desired revisions to a whole new file. This is not a design mistake; DEAP points out that with over a gigabyte of storage, you could fill 100K a day and still not fill the disk in 83 years. Besides, you can specify which version of a file you wish to access, in case your updating takes a wrong turn.} } The storage is so mind-bogglingly capacious that DEAP includes as a free demo file on disk of all the U.S. census data from 1890 to date, and a digitized image of Warnock & Geschke printing out a digitized image of themselves on an HP LaserJet from an HP Vectra, via Postscript. Although it is not mentioned in the manual, prototypes have also been found to contain every HP-65 program in the Users' Library, plus an HP-67 program that translates them into HP-67 code so that HP-71 Translator Pac owners can run them. The technical-minded reader may be interested to know that the pack is formatted into 10,606 cylinders of 296,209 bytes each.} } The secret to the bit density and miniature package is the low flying height of the disk head, which is measured in thousandths of an angstrom. Since this would cause problems with large air molecules (carbon monoxide is okay, but carbon dioxide is too big and can cause misreads), the module is permanently sealed in an almost perfect vacuum. This design, called Micro-Angstrom-Gap Go-One-Time technology, or MAGGOT for short, is smaller and more expandable than WORM drives.} } Functions that allow the 9114 disk drive to interface directly with the MAGGOT have been provided for making backups. Although a full MAGGOT would fill more 3.5-inch floppies (sometimes called "stiffies") than HP could ship in a century, this says less about the MAGGOT's or 9114's capacity than it does about HP's famous shipping schedule.} } DEAP is currently designing an add-on that allows disk dumps at 18,000 baud to videocassette systems. Under consideration is an interface to a print-image microfilmer, for those who would like their HP-71 to run one of these $75,000 devices.} } Only one problem prevents the MAGGOT from being released to the market. Relativity Theory states that rotation and acceleration are non-uniform motions. DEAP sidestepped this problem by uniformly accelerating the rotation. Eventually the near-light-speed velocity of the disk pack creates a strong gyroscopic effect, so much so that any motion of the HP-71 with any angular differential to the plane of rotation (such as lifting the HP-71 from the desk, or bumping the desk, or even pressing any HP-71 key) instantly results in a head crash, which in turn emits an intense stream of sub-atomic particles from friction fission. DEAP does not like to study this phenomenon, however, because every HP-71 that has run afoul this way was instantly reduced to plasma, rendering the date code unreadable and thus voiding the warranty.} } As soon as this minor bug is exorcised, DEAP promises to announce the MAGGOT hard disk module to the press, at a price based on the 9114's list price times the storage capacity difference. At that price, I hope it comes with a copy of the THEOLOGY ROM!} } } +------------------+} ! USES OF PEEKUTIL !} +------------------+} } If you'd like to go spelunking through HP-71 files, but aren't sure what's where, here's everything you need to know, all in one handy place. Keep this page marked for future reference, or make a photocopy of it.} } You'll need a copy of PEEKUTIL, written by Flavio Casetta. You can find it on Markov's swapdiscs (CHHU02 and CHHU06) or you can get it by sending me one blank mag card and a self-addressed stamped envelope. If you write PEEKUTIL on the card, no further note will be necessary. If you don't mind typing the whole lexfile into the MAKELEX program, you can find PEEKUTIL listed in the CHHU Chronicle, V2 N7 P13.} } First, assuming the file we wish to explore is called FRED, then do this:} } +----------------------+} ! A=HTD(ADDR$("FRED")) !} +----------------------+} } This puts FRED's address into A. If you change memory in any way that might move FRED, be sure to recalculate A in the way shown above.} } Now, for any filetype at all:} } TEXT$(A,8) = "FRED " (full 8-character file name)} RPEEK$(A+16,4) = FRED's filetype in hex} RED(PEEK(A+16,4),2^15) = FRED's filetype in signed decimal} PEEK(A+20) = FRED's file protection as follows:} 0 = no protection} 1 = SECURE only} 2 = PRIVATE only} 3 = EXECUTE ONLY (both SECURE and PRIVATE)} RPEEK$(A+22,4) = FRED's creation time in HHMM format} RPEEK$(A+26,6) = FRED's creation date in YYMMDD format} PEEK(A+32,5)+32 = FRED's total length in nibbles} ADPEEK$(A+32,5) = Hex address of file after FRED in CATalog} ADPEEK(A+32,5) = Decimal address of file after FRED in CATalog} } +--------------------------+} ! If FRED is an SDATA file !} +--------------------------+} } PEEK(A+32,5) DIV 16 = number of records in FRED} RPEEK$(A+37+16*N,16) = Contents of Nth record (record 0 is first)} } +------------------------+} ! If FRED is a DATA file !} +------------------------+} } PEEK(A+37,4) = Number of records in FRED} PEEK(A+41,4) = Number of bytes in each record in FRED} } +-----------------------+} ! If FRED is a LEX file !} +-----------------------+} } PEEK(a+37,2) = FRED's lex ID in decimal} RPEEK$(A+37,2) = FRED's lex ID in hex} PEEK(A+39,2) = FRED's lowest token number in decimal} RPEEK$(A+39,2) = FRED's lowest token number in hex} PEEK(A+41,2) = FRED's highest token number in decimal} RPEEK$(A+41,2) = FRED's highest token number in hex} PEEK(A+43,5) = Distance to next linked lex table (0 if none)} If that's not 0, then:} ADPEEK(A+43,5) = decimal address of next linked lex table} ADPEEK$(A+43,5) = hex address of next linked lex table} (NB: Linked lex tables are all within one lexfile)} PEEK(A+48) = Speed Table existence flag (15 if none)} If that's 0, then LET A=A+79 to skip over speed table} PEEK(A+49,4) = Distance to Text Table (0 if none)} If that's not 0, then:} ADPEEK(A+49,4,-1) = decimal address of text table} ADPEEK$(A+49,4,-1) = hex address of text table} PEEK(A+53,4) = Distance to Message Table (0 if none)} If that's not 0, then:} ADPEEK(A+53,4) = decimal addresss of message table} ADPEEK$(A+53,4) = hex addresss of message table} PEEK(A+57,5) = Distance to Poll Handler (0 if none)} If that's not 0, then:} ADPEEK(A+57,5) = decimal address of poll handler} ADPEEK$(A+57,5) = hex address of poll handler} A+62 = decimal address of Main Table} } +-------------------------+} ! If FRED is a BASIC file !} +-------------------------+} } RPEEK$(A+37,5) = Hex distance to the first SUB or END SUB} If 00000, then RUN or RENUMBER and try again} If FFFFF, then there are no SUBs nor END SUBs} RPEEK$(A+42,5) = Hex distance to first label or DEF FN} If 00000, then RUN or RENUMBER and try again} If FFFFF, then there are no labels nor DEF FNs} RPEEK$(A+47,2) = "F0", the End-Of-Line (EOL) marker} VAL(RPEEK$(A+49,4)) = first line number} PEEK(A+53,2)-2 = length of first statement in nibbles} If you LET L=PEEK(A+53,2)-2, then:} PEEK$(A+55,L) = hex contents of first statement} RPEEK$(A+55+L,2) = EOL or @} If F0, it's an EOL followed by another line number} If F4, it's an @ followed by another length byte} and so on, until the end of the file is reached.} } } With these tools, you can explore any type of file. Here are a few ideas that} came from this:} } } +---------------------------+} ! TOKENIZE in one keystroke !} +---------------------------+} } In the CHHU Chronicle, V1 N3 P29, a program called TOKENIZE was listed, which enabled you to see how BASIC changes keywords into hex tokens internally. Here is the same idea, but on a simple key definition instead of a whole program:} } KEY 'f4','J=PEEK(193885,5)@I=PEEK(J+53,2)-2@PEEK$(J+55,I);" (";STR$(I);")"':} } After making this key assignment, merely pressing [f][4] (the SIN key) will show the tokenized version of the first statement of the current BASIC file, no matter what it is. This is followed by a nibble count, in parentheses. This is useful in comparing the byte length of different approaches to the same task.} } } +---------------------------+} ! LEXCAT lexfile catalogger !} +---------------------------+} } Run LEXCAT (or CALL LEXCAT(F$) with a filename in F$), and see the hex address of the specified lexfile, the address of its poll handler(s), the address of the next file, and all the keywords in the lexfile with their execution code address (entry point), lex ID and token number, and function syntax. This is an invaluable program for those of us who use lexfiles a lot. It is based on a program by HP, with a few more bells and whistles, cleaner output, and much faster thanks to PEEKUTIL.} } 5 ! Requires PEEKUTIL & HPILROM} 10 INPUT 'LEX File: ';F$ @ CALL LEXCAT(F$)} 20 SUB LEXCAT(F$) @ ON ERROR GOTO 290 @ A1=HTD(ADDR$(F$))} 30 IF PEEK(A1+16,2)#8 THEN DISP "ERR:Not LEX file" @ END } 40 S=A1+37 @ F$=UPRC$(F$)} 50 C=S+25+NOT PEEK(S+11)*79 @ T$=DTH$(C)&RPEEK$(S,6)} 80 IF LEN(F$) THEN PRINT @ PRINT "*** ";F$;" ***" @ PRINT "(";DTH$(A1);") File Header"} 90 M=HTD(T$[8,9]) @ B=ADPEEK(C-13,4)} 100 IF PEEK(C-5,5) THEN PRINT "(";ADPEEK$(C-5,5);") Poll Handler"} 120 IF PEEK(B,2)=255 THEN 300} 130 L=PEEK(B-1)+1 @ W$=TEXT$(B,L/2) @ S$=RPEEK$(B+L,2) @ D=C+(HTD(S$)-M)*9} 140 PRINT "(";ADPEEK$(D+3,5);") ";T$[10];"/"; @ B=B+L+3} 150 IF NOT HTD(S$) THEN PRINT "-- ";W$;" ffn" @ GOTO 110} 160 PRINT S$;" ";W$; @ E=PEEK(D+8) @ IF NOT E THEN PRINT " postfix" @ GOTO 110} 170 IF E#15 THEN 250} 180 E=RMD(ADPEEK(D+3,5,-2),1048576) @ P=PEEK(E) @ Q=PEEK(E+1)} 190 IF Q THEN PRINT "("; ELSE PRINT " fn" @ GOTO 110} 200 FOR I=1 TO Q @ IF I#1 THEN PRINT ",";} 210 E=E-1 @ X=PEEK(E) @ IF I>P THEN PRINT "?";} 220 IF X>11 THEN PRINT "#/$"; ELSE IF X>7 THEN PRINT "#"; ELSE PRINT "$";} 230 IF RMD(X,4) THEN PRINT "()";} 240 NEXT I @ PRINT ")" @ GOTO 110} 250 IF NOT BIT(E,3) THEN PRINT " *P";} 260 IF NOT BIT(E,2) THEN PRINT " *I";} 270 IF NOT BIT(E,0) THEN PRINT " *K";} 280 PRINT @ GOTO 110} 290 DISP "ERR:";ERRM$ @ BEEP @ END } 300 IF KEY$="#38" THEN END } 310 IF NOT HTD(T$[10]) THEN END } 330 IF PEEK(S+6,5) THEN S=ADPEEK(S+6,5) @ F$="" @ GOTO 50} 340 DISP "(";ADPEEK$(A1+32,5);") Next File Header"} 350 END SUB} } If run on SPLEX, you'll see (with varying addresses):} } *** SPLEX ***} (80008) File Header} (80077) Poll Handler} (800D5) 52/24 LIST$(#,?$)} (80281) 52/23 MODIFY} (808C4) Poll Handler} (80900) 53/55 MAXRC fn} (809F1) Next File Header} } which means SPLEX's file header begins at hex address 80008; its first poll handler begins execution at hex 80077; the LIST$ function starts execution at hex address 800D5, it has lex ID 52 (hex), token 24 (hex), and takes one numeric argument, followed by an optional string argument; the MODIFY keyword is a statement (no clue to its syntax!); there's another poll handler at 808C4; MAXRC is a function with no arguments; and the file ends at 809F0.} } Next Titan File: Self-modifying BASIC programs!} } Joseph K. Horn} 1042 Star Route} Orange, CA 92667}