LEX 'MMLEXV04' TITLE MMLEXV04 ver. <87/04/16> * ************************************************************ * LEX HEADER BLOCK * CON(2) #5E LEX ID, see MMTOKENS for assignment CON(2) #B6 Low Token CON(2) #C0 High Token CON(5) 0 No link NIBHEX F No speed table CON(4) (TxTbSt)+1-(*) Offset to TEXT Table CON(4) 0 No message table REL(5) POLHND Offset to poll handler * ************************************************************ * * STITLE Main Table * CON(3) (TxEn06)-(TxTbSt) REL(5) ENG$ NIBHEX F * CON(3) (TxEn07)-(TxTbSt) REL(5) FIX$ NIBHEX F * CON(3) (TxEn0B)-(TxTbSt) REL(5) SCI$ NIBHEX F * CON(3) (TxEn01)-(TxTbSt) REL(5) ATBIN$ NIBHEX F * CON(3) (TxEn02)-(TxTbSt) REL(5) BTA$ NIBHEX F * CON(3) (TxEn03)-(TxTbSt) REL(5) BTD NIBHEX F * CON(3) (TxEn04)-(TxTbSt) REL(5) CHR2$ NIBHEX F * CON(3) (TxEn05)-(TxTbSt) REL(5) DTBIN$ NIBHEX F * CON(3) (TxEn08)-(TxTbSt) REL(5) INT$ NIBHEX F * CON(3) (TxEn09)-(TxTbSt) REL(5) NUMR NIBHEX F * CON(3) (TxEn0A)-(TxTbSt) REL(5) NUMX NIBHEX F * ************************************************************ * STITLE TEXT TABLE * TxTbSt TxEn01 CON(1) (TxEn02)-(*)-4 NIBASC 'ATBIN$' CON(2) #B9 * TxEn02 CON(1) (TxEn03)-(*)-4 NIBASC 'BTA$' CON(2) #BA * TxEn03 CON(1) (TxEn04)-(*)-4 NIBASC 'BTD' CON(2) #BB * TxEn04 CON(1) (TxEn05)-(*)-4 NIBASC 'CHR2$' CON(2) #BC * TxEn05 CON(1) (TxEn06)-(*)-4 NIBASC 'DTBIN$' CON(2) #BD * TxEn06 CON(1) (TxEn07)-(*)-4 NIBASC 'ENG$' CON(2) #B6 * TxEn07 CON(1) (TxEn08)-(*)-4 NIBASC 'FIX$' CON(2) #B7 * TxEn08 CON(1) (TxEn09)-(*)-4 NIBASC 'INT$' CON(2) #BE * TxEn09 CON(1) (TxEn0A)-(*)-4 NIBASC 'NUMR' CON(2) #BF * TxEn0A CON(1) (TxEn0B)-(*)-4 NIBASC 'NUMX' CON(2) #C0 * TxEn0B CON(1) (TxTbEn)-(*)-4 NIBASC 'SCI$' CON(2) #B8 * TxTbEn NIBHEX 1FF Text table terminator ************************************************************ * STITLE POLL HANDLER * POLHND ?B=0 B VER poll? GOYES VER$P Yes RTNSXM No, exit XM=1, Cy=0 VER$P A=R2 Fetch AVMEMS C=R3 Fetch stack pointer D1=C D1=D1- (VER$en)-(VER$st)-2 allow for our reply CD1EX ?A>C A not enough memory? GOYES VER$Pe exit not handled Cy=1 D1=C restore stack pointer R3=C and save for next file VER$st LCASC ' MM:4' VER$en DAT1=C (VER$en)-(VER$st)-2 Write our reply VER$Pe RTNSXM exit * ************************************************************ * * The purpose of ATBIN$ is to convert a string into its * binary equivalent. For example: * * ATBIN$("A")="01000010" * * There are no restriction on the length of the parameter * string, and the resulting string will always be 8 times * the length of the input parameter, with leading zeroes * added as required. This implementation facilitates further * manipulations with logical operators such as AND$, OR$, ect.. * (See STRBOOL LEX). * * BTA$ performs the inverse operation, transforming * the binary representation (I think of it as a bit map) * back to an ascii string, base 256. * * An important design consideration was ease of use. * Therefore, I wanted BTA$ to handle input parameters with * "missing" leading zeroes... This means that BTA$("11") * is equivalent to BTA$("00000011"), both of which equal * CHR$(3). * * It is important to note that BTA$ does NOT trim leading * CHR$(0) bytes from the output string. The assumption is * that if you have modelled a CPU register to show, for * example, "0000000000000011", you want to model a full * 16 bit register, whose equivalent is CHR$(0)&CHR$(3). * * BTD is a conversion routine that returns the decimal * equivalent of a binary representation. Since the keyword * uses HDFLT, the maximum input parameter is RPT$("1",20), * which corresponds to a 20 bit address buss, with a maximum * address of FFFFF hex, or 1048575 decimal. This provides * a very comprehensive set of binary operators, when used * in conjunction with the HP-IL ROM binary functions BIT, * BINAND, BINCMP, BINEOR and BINIOR. * * DTBIN$ is the almost exact inverse of BTD. Syntax is: * C$=DTBIN$(X [,Y]) where X is the decimal value of the bit pattern * and Y is the length of the string to be created. This causes * and implicit MOD operation since only the Y least-significant bits * are actually converted. Like a register field wrap-around... * * NUMX is a variant of NUM($) that can return the full value of * a 2&1/2 nibble field in an ascii string. See inverse CHR2$(#) * below * SYNTAX: A=NUMX(A$) is equivalent to NUM(A$)*256+NUM(A$[2,2]) * There are some differences: if A$ is a one byte string, then * A=NUM(A$).. and if A$="" then A=0. I find this useful. * * NUMX also supports an optional numeric parameter: * A=NUMX(A$,N) where N>=3, and N<=LEN(A$) * A is a 2&1/2 byte conversion... for example, if * HEX$(A$)="01020304", then NUMX(A$,4)=HTD("20304")=131844 * NUMX(A$,3)=HTD("10203")=66051, and NUMX(A$,<<2 or less>>)=Invalid Arg. error * * The optional parameter allows you to decode/ unpack values up to * 1048575, acting as a true inverse of CHR2$. * * It is important to note that NUMX(A$[N]) may be equal to NUMX(A$,N+1) * but ONLY if HEX$(A$[N-1,N-1)])="?0". * An important applications for NUMX and CHR2$ is manipulating mass * storage pointers... * * NUMR(A$ [,Y]) works almost exactly like NUMX, the difference * being that it reverses the order of the data bytes in the field to be decoded. * This keyword was written originally to speed-up the * handling of HP-71 file length / record length * data in mass storage directory entries, where the least significant byte * is stored in the left-most part of the field - unlike * all other such data fields. This seems to be * an HP-71 implementation. Note that NUMR(A$)=NUM2(A$), where NUM2 is a * function from the Data Acquisition ROM. Thus, NUMR can * be considered an improved version. * * BUG: the method used to screen out invalid arguments for * BTA$ and BTD accept all characters such that MOD(NUM(chr),16)=0 or 1. * This could result in surprises, especially if you could run * into leading or trailing spaces.. To be fixed, maybe. * * Available memory test needs to be implemented for BTA$. * * Author: Mike Markov, 87/03/27 ****************************** NIBHEX 411 ATBIN$ GOSBVL POP1S CD0EX RSTK=C CD1EX D1=C D0=C GOSBVL D=AVMS D1=D1- 16 CD1EX C=C-A A 1 C=C-A A 2 C=C-A A 3 C=C-A A 4 C=C-A A 5 C=C-A A 6 C=C-A A 7 ?C 1/4 CSRB DIVIDE BY 2 ==> 1/8, THE # OF BYTES IN THE DEST. $ ?SB=0 WAS THE COUNT EXACT? GOYES BTA$1 YES, WE DO NOT NEED A PARTIAL BYTE C=C+1 A SORRY, PARTIAL BYTE ALLOWANCE... BTA$1 C=C+C A NOW, BUILD THE DEST. $ HEADER R2=C CSL W CSL W C=C-1 P R1=C SAVE HEADER IN R1 C=R2 C=C+C A C=C+C A C=C+C A C=C-A A CSRB P=C 0 GONC BTA05 B.E.T. BTALP1 P= 0 BTA05 C=0 W BTALP2 D=D-1 A GOC BTAEND A=0 A D0=D0- 2 A=DAT0 1 B=A A B=B-1 B GOC ARGOK IF CARRY, THEN NIB WAS = 0 B=B-1 B GOC ARGOK OR NIB WAS = 1 ... Argerr GOVLNG ARGERR IF NOT, ERROR OUT ARGOK C=C+C B SHIFT PERVIOUS RESULT OUT OF THE WAY 1 BIT C=C+A A STORE BIT P=P+1 INCREMENT BIT COUNTER ?P# 8 HAVE WE PROCESSED 8 BITS? GOYES BTALP2 NO, GO GET THE NEXT D1=D1- 2 OK, WE HAVE A FULL BYTE DAT1=C B STORE THE BYTE GONC BTALP1 B.E.T. GO PROCESS THE NEXT 8 BITS / BYTE BTAEND C=RSTK DONE. RESTORE POINTERS AND EXIT D0=C D1=D1- 16 POINTER TO STRING HEADER C=R1 RECOVER THE HEADER GOVLNG FNRTN4 ARGERR EQU #0BF19 FNRTN4 EQU #0F238 NIBHEX 411 BTD GOSBVL POP1S CD0EX RSTK=C CD1EX D1=C C=C+A A D0=C C=0 W LCHEX #29 ?C>A A GOYES LT20BI GOTO Argerr LT20BI C=0 W C=A A CSRB D=C A the new loop counter C=0 W BTDLP D=D-1 A GOC BTDEND A=0 A D0=D0- 2 A=DAT0 1 B=A A B=B-1 B GOC BTDOK B=B-1 B GOC BTDOK GOTO Argerr BTDOK C=C+C A C=C+A A GONC BTDLP B.E.T. BTDEND A=C W GOTO num30 HDFLT EQU #1B31B *************************************************** * * Michael Markov, 87/4/3 version 2 * * CHR2$(X[,Y]) is a standard string function that, like * CHR$(X), returns (a) string character(s) of equivalent * value. The optional [,Y] parameter allows you to set * the length of the string that is returned. This allows * packing data in the range of 0-65535 into 2 byte string * elements, or data in the range of 0-1048575 into 3 byte * string elements. * -- the Y parameter defaults to 2 if not specified. * -- the Y parameter may vary from 0 to 1048575, and the * length of the string will be MOD(Y,16). * -- CHR2$ fills leading bytes with CHR$(0), as required. * This means that only the last five nibbles can actually * contain non-zero information. * * The default CHR2$(X) can replace X DIV 256,MOD(X,256) * in mass storage utilities that seek to position the read * head of a mass storage device to an absolute address X, * see for example SEND ... DDL 4 DATA CHR2$(2) * * Specifying a string length of 4 can be very handy when you * are building a new directory entry, or changing the offset * of an existing entry with programs like BCOPY... * * (Yes, more new damned keywords & changes to existing mass * storage utilities. some of them are real close to final, * ROMable form). ************************************************************* NIBHEX 8812 DTBIN$ P=C 15 ?P= 2 is the optional parameter being used? GOYES DTBIN yes, go handle accordingly GOSBVL MPOP1N get the bit pattern equivalent GOC DTBERR complex, error-out AR1EX save it in R1 C=0 W clear C[W] LCHEX 14 load the default output string length CAEX W (20 bytes) into A[A] GONC DTB30 B.E.T. to common code DTBIN GOSBVL MPOP2N get both the bit pattern and the string length GOC DTBERR error- at least one complex parm. CAEX W optional parameter, & swap. R1=C again, save the bit map in R1 GOSBVL FLTDH convert the string length parm to hex ?A=0 A is the desired length zero? GOYES null return null$ ?XM=0 GOYES DTB30 parm in range 0-FFFFF, ok DTBERR GOTO Argerr crap-out DTB30 C=0 W LCHEX 14 load max allowed string length (also the default) ?CA A GOYES ArgERR CAEX W CD0EX C=C+A A C=C-1 A C=C-1 A GOTO narg2C NIBHEX 8412 NUMR P=C 15 CD0EX RSTK=C ?P= 2 GOYES NUMR2 NUM2R GOSBVL REVPOP CD1EX D1=C D0=C ?A=0 A GOYES num30 C=0 W CAEX W CSRB C=C-1 A A=DAT0 B C=C-1 A GOC num30 GONC num29 ArgERR GOTO Argerr NIBHEX 8412 NUMX P=C 15 CD0EX RSTK=C ?P= 2 GOYES narg2 NUM2 GOSBVL POP1S CD1EX D1=C C=C+A A D0=C ?A=0 A GOYES num30 C=0 W C=A A CSRB D=C A THE LOOP UPPER LIMIT A=0 W NUMXLP D=D-1 A GOC num30 D0=D0- 2 A=DAT0 B D=D-1 A GOC num30 D0=D0- 2 num29 A=DAT0 4 num30 GOSBVL HDFLT C=RSTK D0=C C=A W D1=D1- 16 GOVLNG FNRTN4 argERR GOTO ArgERR SWPBYT EQU #17A24 REVPOP EQU #0BD31 FNRTN1 EQU #0F216 narg2 GOSBVL MPOP1N GOSBVL FLTDH D1=D1+ 16 C=0 A LCHEX 3 ?C>A A GOYES argERR AR1EX GOSBVL POP1S CD1EX D1=C C=C+A A D0=C D1=D1- 16 C=R1 C=C+C A ?C>A A GOYES argERR CAEX W CD0EX C=C-A A narg2C CD0EX A=DAT0 6 C=0 W C=A A CAEX W GONC num30 STR$SB EQU #18149 internal number to string conversion, uses current fmt DSPFMT EQU #2F6DC storage for N the display mode flags. Also, at * #2F6DD we have the # of display digits data. ***************************************************** * * The INT$ keyword suggested itself after I disassembled STD$ in the * DATA ACQUISITION ROM. What it does is return the same string you * would get by doing STD @ A$=STR$(INT(X)) -- which I do all too * often. This allows you to keep your favorite display format... * all you have to do is A$=INT$(X). * Coded by M. Markov in early March '87 ******************************************************************** NIBHEX 811 one mandatory numeric character INT$ CD0EX get PC into C[A] CSLC shift PC left one nib CSLC again. C[B] is now available D0=(5) DSPFMT pointer to display format data C=DAT0 B R3=C save PC and current display FMT in R3 P= 0 LCHEX 01 set DSPFMT to FIX 0. (STD=00, SCI=02 & ENG=03) DAT0=C B GOSBVL STR$SB does POP1N, convert to string using FIX 0 mode C=R3 get back PC and original display format DAT0=C B restore display format (D0 is unchanged) CSRC Shift PC back into C[A] field CSRC CD0EX restore PC ************************************************************* * at this point, if I only wanted the string in FIX 0 format, all I * would have to do is exit with GOVLNG EXPR. However, I also want to * get rid of the trailing ".", which can be easily accomplished by * moving the string header up one byte, writing over the "." * And, of course, that does mean you must decrement the string length * field in the header by two nibbles. * * Before we stomp over ".", we must make sure we do have a "." * If the # to be converted requires more than 13 bytes for FIX 0 representation, * STR$SB uses instead SCI notation. So, to make * sure the output remains valid: ************************************************************* C=DAT1 W Get the string header into C[W] R1=C temp. storage D1=D1+ 16 pointer to last string byte A=DAT1 B get it LCASC '.' set up comparison (P= 0) D1=D1- 14 pointer to new header store, we hope ?A#C B not a trailing "."? GOYES numlrg yes, not a "." C=R1 no, so we can stomp over "." CSLC shift string length field into C[M] C=C-1 M decrement length by two nibbles C=C-1 M CSRC shift back to original position... GOVLNG FNRTN4 store new header & function exit numlrg D1=D1- 2 The number $ does not end in ".", so leave it alone! GOVLNG #0F23C EXPR reset stack pointer and exit. ***************************************************** * * Syntax: A$=ENG$(X [,Y]) where X is the number to be converted to * a string in ENG Y format, without disturbing the current format * setting. * A$=ENG$(X) uses the value last set with FIX Y, SCI Y or ENG Y * to specify the # of digits to be shown. * * This keyword can help speed-up numeric tabulations by avoiding the * use of DISP USING or PRINT USING. Instead, use TAB, or O$[N]=ENG$(X,Y).. * * The ENG$ keyword suggested itself after I wrote the INT$ keyword. * I usually prefer using the STD display format, but I also often * want to print or display data in ENG 5 format. So, rather than * toggle back and forth between modes, a new keyword! * * Why not DISP USING? ... Because USING is slow! * * It should be noted that if you do ENG 5 @ STD, the * default number of integers / flags remain unchanged at 5. * This means that you can either preset this value as shown above, * or override this information with the optional parameter.. * * Coded by M. Markov in April '87 * * While we are here, we might as well provide the equivalent functions * for PRINTing or DISPlaying numbers in the FIX ? or SCI ? mode formats. * This can be done with almost no additional code, since the only change * required is one nib in the LCHEX instruction. We could also provide STD * formating, but that keyword is already provided by the DATALEX... * ******************************************************************** NIBHEX 8812 one mandatory numeric character, one opt. numeric ENG$ GOSUB ENGSUB LCHEX 3 GONC ENGDO NIBHEX 8812 FIX$ GOSUB ENGSUB LCHEX 1 GONC ENGDO NIBHEX 8812 SCI$ GOSUB ENGSUB LCHEX 2 GONC ENGDO ENGSUB P=C 15 number of parameters used CD0EX get PC into C[A] CSLC shift PC left one nib CSLC again. C[B] is now available D0=(5) DSPFMT pointer to display format data C=DAT0 B save display format in C[B] R3=C save PC and current display FMT in R3 ?P= 1 only one parameter? GOYES ENGdef yes, use existing # of digits (default) GOSBVL MPOP1N no, get the desired # of digits GOC argerr GOSBVL FLTDH convert value to hex D0=D0+ 1 store in 2F6DD ==> (DSPFMT)+1, one nibble DAT0=A 1 D0=D0- 1 reset pointer for later use D1=D1+ 16 move pointer to mandatory argument ENGdef P= 0 the start of common code... C=0 W clear C[W] RTNCC set DSPFMT to ENG. (STD= 0, SCI= 2 & ENG= 3) ENGDO DAT0=C 1 GOSBVL STR$SB does POP1N, convert to string using FIX 0 mode C=R3 get back PC and original display format DAT0=C B restore display format (D0 is unchanged) CSRC Shift PC back into C[A] field CSRC CD0EX restore PC GOVLNG #0F23C EXPR reset stack pointer and exit. argerr GOVLNG ARGERR