LEX 'POLLDATA' HP-71 POLL ANALYSER, M.Markov ID #5D Scratch ID 12/1987 MSG 0 POLL POLHND ENTRY FPTIM CHAR #F ENTRY MAXPOL See MMTOKEN2 for resource allocations CHAR #F ENTRY OCCUR CHAR #F ENTRY POLDAT CHAR #D ENTRY RESET CHAR #D ENTRY SLOCOU CHAR #F ENTRY SPTIM CHAR #F ENTRY TOTCOU CHAR #F KEY 'FPTIME' returns poll handler shell execution time with TOKEN #8D fast polls. See warning below. KEY 'MAXPOLL' N=MAXPOLL, function w/o parm TOKEN #8E returns poll # (0-255) with the highest count KEY 'POLCOUNT' X=POLCOUNT(poll #) where 0<=poll #<=255 TOKEN #8F KEY 'POLLDATA' POLLDATA ON/OFF enables / disables the TOKEN #90 poll counter in this LEX only. KEY 'RSTCOUNT' RSTCOUNT or RSTCOUNT ALL TOKEN #91 clears count for poll # equal to /ALL KEY 'SLOCOUNT' Syntax: S=SLOCOUNT, function w/o parameters TOKEN #92 returns count for all slow polls issued KEY 'SPTIME' returns shell execution time for slow polls TOKEN #93 KEY 'TOTCOUNT' Syntax: T=TOTCOUNT, function w/o parameters TOKEN #94 returns count for all polls issued NIBHEX 1FF end of table * * This LEX file is a tool for determining the frequency distribution of polls * issued by a specific HP-71. The intent is to help people know what is really * going-on in the HP-71, and hopefully to develop a database that would help * us write optimized poll handler shells. * * FAST POLLS CANNOT BE SAFELY ISSUED FROM MAIN RAM SINCE POLL HANDLERS COULD * MAKE MEMORY MOVE.. FSTIME COULD THEREFORE TAKE YOU TO NEVER-NEVER LAND.. * It should work safely in IRAM, and be the memory you save may be your own... * However, pTEST is the one poll that should NEVER be handled or otherwise * processed. See IDS. Therefore we should be safe enough (I hope). * * SPTIME and FPTIME are not very accurate. They will be affected by all kinds * of factors such as machine speed-up, condition of the batteries, and more. * They provide an indication of how much delay is introduced as you add LEX * files to an HP-71.. In one test, the SPTIME value increased from about 10 to * 43 while the FSTIME value increased from 7 to 25. FSTIME should always be * less than SPTIME, since FPOLL saves much less information than POLL. * Unless I am misunderstanding things, we are talking of 1/512 of a second * units. In a future version, I would modify SPTIME and FPTIME to disable * the POLLDATA poll handler while issuing pTEST. * * THIS FILE CANNOT BE USED IN ROM! * A block of 258*5+1 nibbles INSIDE THE LEX is used for data storage. * This file processes EVERY poll for analytical purposes. This introduces * some undesirable delays under normal conditions. The code could be modified * (with considerable trouble) to use a buffer instead of RAM reserved inside * POLLDATA. However, this would introduce considerable undesirable delays.. * * THE LOCATION OF THIS FILE IN THE HP-71 WILL AFFECT RESULTS! * In order to record every single poll issued, this file must be the first * LEX file in the :MAIN directory. Otherwise, takeover polls may never be * passed on to our POLHND routine. * * You could put a LEX between two copies of TESTPLX to determine whether it * takes over any polls. if you want to do this, you should change both the * spelling of the keywords and the token allocations for the second copy. * Otherwise, you will not be able to access the data stored in the second file * while the first remains in RAM. * * The poll handler will increment a storage register associated with a given * poll everytime the poll is issued. It also increments a 'total' register. * This process is disabled if either the total register is full, value FFFFF, * or POLLDATA OFF is executed. This provides a mean of avoiding overflows * and / or analyzing specific types of events under program control. * Finally, the number of slow polls issued is also stored. * * See program POLLDAT1 for the latest version of the program I use to print-out * information collected with POLLDATA LEX. * * Note that POLCOUNT(n) tells you how many times poll n was issued. * RSTCOUNT N resets the count stored for poll N to zero to allow us to use * MAXPOLL to identify the poll with the next highest count * RSTCOUNT ALL clears all the information previously collected, to include * TOTCOUNT, SLOCOUNT and all the individual poll counts. POLLDATA ON/OFF * status is not affected. * SLOCOUNT returns the number of slow polls issued. This is primarily useful * as a percentage of the total count, which is obtained with TOTCOUNT. * * When you initially assemble the file, the storage registers are filled with * a test pattern I found useful in the test & debug stage. This test pattern * must be cleared with RSTCOUNT ALL before you can begin monitoring polls. * * Enjoy, and may this LEX be of some use! * * The code has been thoroughly tested, but it has not been optimized for lenght * * Mike Markov 12/20/1987 * FLTDH EQU #1B223 RESPTR EQU #03172 NUMCK EQU #0369D FIXDC EQU #05493 EXPEXC EQU #0F186 NXTSTM EQU #08A48 POP1N EQU #0BD1C BSERR EQU #0939A POP1R EQU #0E8FD FNRTN4 EQU #0F238 FNRTN1 EQU #0F216 HDFLT EQU #1B31B GNXTCR EQU #03064 R3=D10 EQU #03526 EXPPAR EQU #03FD9 D1C=R3 EQU #03047 IVEXPe EQU #02E35 tALL EQU #000F8 GTEXT1 EQU #051A5 EOLXC* EQU #052EC * ***************************************************************** * parmck GOSBVL POP1R read parameter, error-out if not real expression GOSBVL FLTDH convert to HEX form in A[A] GOC OCUR01 are we valid ?(0 to FFFFF) eIVARG LC(4) #000B load eIVARG GOVLNG BSERR basic error exit OCUR01 C=0 A now, test for the range I allow, 0 to 255 LCHEX #FF ?A>C A not in range? GOYES eIVARG sorry, invalid argument. RTN parm is 0 to 255 NIBHEX 8 numeric parameter NIBHEX 11 one mandatory parameter OCCUR GOSUB parmck read parameter, error-out if 0 to 255 CD0EX Save D0 RSTK=C P= 10 to find TBL00 GOSUB FINDR find the storage register according to A[A] A=DAT0 A read the blessed data. C=RSTK now, restore the D0 pointer CD0EX GOSBVL HDFLT convert the count to 12 digit float form C=A W GOVLNG FNRTN4 function return. Done for the moment. * ***************************************************************** * * The statment RSTCOUNT clears the storage registers * according to the value of the expression. RSTCOUNT ALL clears * everything in storage space except the ONOFF status. The value of * the expression must be between 0 and 255, or Invalid Argument is invoked. * * ERRORS IN THIS PART OF THE CODE PROVIDE A QUICK MEMORY LOST * *********** RSTp GOSBVL GNXTCR get next non-blank character in the input stream GOSBVL R3=D10 now that we are past optional blanks, save D1, D0 GOSBVL EXPPAR try to parse an expression ?ST=0 3 is it a valid string expression? GOYES RSTp1 then, go invalid expression, we only do numerics ?ST=1 0 invalid expression? GOYES tALLp ok, not numeric, try to parse tALL GOVLNG RESPTR numeric expression, done! tALLp GOSBVL D1C=R3 restore D1, input pointer C=R3 C[A]= original D0 D0=C restore D0. We are now ready to try parsing tALL GOSBVL WRDSCN token parser CON(2) tALL we allow only tALL REL(3) parse branch to parse if tALL, see ONp code CON(2) 0 end of this table RSTp1 GOSBVL D1C=R3 not tALL, not numeric expression. Restore input ST=1 4 to point to bad text in input stream GOVLNG IVEXPe invalid expression parse routine * the RSTp parse routine is adapted from NUMCK. Here we use the invalid numeric * expression exit to try to parse the tokens of our choice. * *********** * RSTd1 GOSBVL GTEXT1 decompile tokens if greater than 6A GONC RSTd2 B.E.T. RSTd LC(2) tALL check for tALL token ?C=A B GOYES RSTd1 it is tALL, go decompile it! RSTd2 GOSBVL EOLXC* if tALL (via RSTd1) then we are at end-of-statment, so * we never return. If not, then we continue. GOVLNG FIXDC we returned, so it must be a numeric expression. * * This decompile routine was adapted from PURGDC to handle tALL/numerics, * substituting the numeric expression decompiler for the filespec decompiler * *********** REL(5) RSTd REL(5) RSTp RESET A=0 A clear A[A] A=DAT0 B read tALL token, if it is there LC(2) tALL ?A=C B is it tALL? GOYES RST50 yes, go clear everything GOSBVL EXPEXC not tALL, so evaluate the numeric expression GOSUB parmck pop from stack, make sure it is real, 0 to 255 CD0EX Once again, save D0 RSTK=C P= 10 we clear a specific register according to A[A] GOSUB FINDR set D0 to the register C=0 A store 00000 at address RST40 DAT0=C A RST41 C=RSTK restore D0 pointer CD0EX GOVLNG NXTSTM let's go do something else! RST50 CD0EX clear ALL storage registers RSTK=C save D0 P= 0 compute address of TBLST GOSUB FINDR and set D0 @ TBLST B=0 B Use B[B] as the critical loop counter C=0 A overwrite with 00000 DAT0=C A wipe total count D0=D0+ 5 pointer to SLOCNT register WIPE DAT0=C A wipe register D0=D0+ 5 move to next register B=B+1 B increment counter GONC WIPE loop until we overflow on last register GOTO RST40 exit using common code * ****************************************************************** FINDR GOSUB WHERE FINDR sets D0 to the desired register. GOSUB loads the REL(5) ONOFF address of the REL(5) data in RSTK, the offset to the WHERE C=RSTK POLLDATA ON/OFF storage nibble. Get this address, B=C A save it in B[A] CD0EX go read this offset, C=DAT0 A read the offset C=C+B A C[A] = (address of TBLST register)-1 C+P+1 add desired offset,P= 0 for TBLST, 5 for SLOCNT, * 10 for TBLST ?P# 10 if we are looking for TBLST or SLOCNT, we need are done GOYES FINDR2 skip other additions C=C+A A A[A] holds the register # in hex A=A+A A we increment the address by 5 nibbles per register A=A+A A C=C+A A FINDR2 CD0EX store it in D0 RTN done ****************************************************************** * NIBHEX 00 function w/o parameters MAXPOL CD0EX save D0 on RSTK RSTK=C P= 0 find address of storage register 00 GOSUB FINDR D0=D0+ 10 alternative was extra steps with P=10 @A=0 A A=DAT0 A read register 00. This is our reference value B=0 A B[B] is the current register number. B[3,2] is the * register number associated with the value in A[A]. * Initially, both are 00 00. AGAIN B=B+1 B increment the current register counter GOC DONE overflow means register FF has already been read D0=D0+ 5 not done, so increment pointer to next register C=DAT0 A and read it ?C<=A A is it less than or equal to the previous high value? GOYES AGAIN yes, try the next register CAEX A no, it is higher. Therefore, it becomes the reference C=B B save the current register index value BSL A and shift the valye into B[3,2] BSL A B=C B Now, B[3,0] will be xyXY, where xy is the index for the GOTO AGAIN highest value (in A[A]) and XY is the register where we * last looked. Right now, xy=XY. So, keep looking! DONE BSR A we have looked at the last register. Index associated BSR A with max value is in B[3,2], must be shifted to B[B] A=0 A clear A[A] for conversion of index to 12 digit float ABEX B Index is now in A[A] MAXP50 C=RSTK restore D0 CD0EX MAXP60 GOSBVL HDFLT convert to 12 digit float form C=A W an exit by way of FNRTN1 GOVLNG FNRTN1 ***************************************************************** NIBHEX 00 function w/o parameters SLOCOU CD0EX save pointer RSTK=C P= 5 for SLOCNT SLO10 GOSUB FINDR A=DAT0 A read SLOCNT GOTO MAXP50 exit using common code with MAXPOL ***************************************************************** NIBHEX 00 function w/o parameters TOTCOU CD0EX save D0 RSTK=C P= 0 GOTO SLO10 * ***************************************************************** * * * Since the POLHND processes EVERY poll that may be issued, it is * very important to save just about everything. POLHND uses only * D0, C[A], C[S], P and two levels of RSTK. All other CPU registers remain * unchanged. D0 is restored to its original value on exit from POLHND, * and P is set to zero, to insure proper operation of other poll handlers. * POLHND SETHEX P= 1 save carry flag status in P GONC SLOPOL P= 0 P is zero for fast polls, 1 otherwise SLOPOL CD0EX save D0 on RSTK RSTK=C GOSUB INCR1 Put ONOFF address on RSTK ONOFF CON(1) #0 POLLDATA is disabled when initially assembled TBLST CON(5) #FFFFF "total" register. FFFFF means storage is full. SLOCNT CON(5) #200 TBL00 CON(5) 0 Storage registers 00 to FF follow, filled with test CON(5) 1 pattern that is meaningless, must do RSTCOUNT 256 CON(5) 2 to initialize storage for normal use. Each CON(5) CON(5) 3 instruction reserves 5 nibbles for a storage register CON(5) 4 CON(5) 5 CON(5) 6 CON(5) 7 CON(5) 8 CON(5) 9 CON(5) 10 CON(5) 11 CON(5) 12 CON(5) 13 CON(5) 14 CON(5) 15 CON(5) 16 CON(5) 17 CON(5) 18 CON(5) 19 CON(5) 20 CON(5) 21 CON(5) 22 CON(5) 23 CON(5) 24 CON(5) 25 CON(5) #FFFFF CON(5) 27 CON(5) #FFFFF CON(5) 29 CON(5) 30 CON(5) 31 CON(5) 32 CON(5) 33 CON(5) 34 CON(5) 35 CON(5) 36 CON(5) 37 CON(5) 38 CON(5) 39 CON(5) 40 CON(5) 41 CON(5) 42 CON(5) 43 CON(5) 44 CON(5) 45 CON(5) 46 CON(5) 47 CON(5) 48 CON(5) 49 CON(5) 50 CON(5) 51 CON(5) 52 CON(5) 53 CON(5) 54 CON(5) 55 CON(5) 56 CON(5) 57 CON(5) 58 CON(5) 59 CON(5) 60 CON(5) 61 CON(5) 62 CON(5) 63 CON(5) 64 CON(5) 65 CON(5) 66 CON(5) 67 CON(5) 68 CON(5) 69 CON(5) 70 CON(5) 71 CON(5) 72 CON(5) 73 CON(5) 74 CON(5) 75 CON(5) 76 CON(5) 77 CON(5) 78 CON(5) 79 CON(5) 80 CON(5) 81 CON(5) 82 CON(5) 83 CON(5) 84 CON(5) 85 CON(5) 86 CON(5) 87 CON(5) 88 CON(5) 89 CON(5) 90 CON(5) 91 CON(5) 92 CON(5) 93 CON(5) 94 CON(5) 95 CON(5) 96 CON(5) 97 CON(5) 98 CON(5) 99 CON(5) 100 CON(5) 101 CON(5) 102 CON(5) 103 CON(5) 104 CON(5) 105 CON(5) 106 CON(5) 107 CON(5) 108 CON(5) 109 CON(5) 110 CON(5) 111 CON(5) 112 CON(5) 113 CON(5) 114 CON(5) 115 CON(5) 116 CON(5) 117 CON(5) 118 CON(5) 119 CON(5) 120 CON(5) 121 CON(5) 122 CON(5) 123 CON(5) 124 CON(5) 125 CON(5) 126 CON(5) 127 CON(5) 128 CON(5) 129 CON(5) 130 CON(5) 131 CON(5) 132 CON(5) 133 CON(5) 134 CON(5) 135 CON(5) 136 CON(5) 137 CON(5) 138 CON(5) 139 CON(5) 140 CON(5) 141 CON(5) 142 CON(5) 143 CON(5) 144 CON(5) 145 CON(5) 146 CON(5) 147 CON(5) 148 CON(5) 149 CON(5) 150 CON(5) 151 CON(5) 152 CON(5) 153 CON(5) 154 CON(5) 155 CON(5) 156 CON(5) 157 CON(5) 158 CON(5) 159 CON(5) 160 CON(5) 161 CON(5) 162 CON(5) 163 CON(5) 164 CON(5) 165 CON(5) 166 CON(5) 167 CON(5) 168 CON(5) 169 CON(5) 170 CON(5) 171 CON(5) 172 CON(5) 173 CON(5) 174 CON(5) 175 CON(5) 176 CON(5) 177 CON(5) 178 CON(5) 179 CON(5) 180 CON(5) 181 CON(5) 182 CON(5) 183 CON(5) 184 CON(5) 185 CON(5) 186 CON(5) 187 CON(5) 188 CON(5) 189 CON(5) 190 CON(5) 191 CON(5) 192 CON(5) 193 CON(5) 194 CON(5) 195 CON(5) 196 CON(5) 197 CON(5) 198 CON(5) 199 CON(5) 200 CON(5) 201 CON(5) 202 CON(5) 203 CON(5) 204 CON(5) 205 CON(5) 206 CON(5) 207 CON(5) 208 CON(5) 209 CON(5) 210 CON(5) 211 CON(5) 212 CON(5) 213 CON(5) 214 CON(5) 215 CON(5) 216 CON(5) 217 CON(5) 218 CON(5) 219 CON(5) 220 CON(5) 221 CON(5) 222 CON(5) 223 CON(5) 224 CON(5) 225 CON(5) 226 CON(5) 227 CON(5) 228 CON(5) 229 CON(5) 230 CON(5) 231 CON(5) 232 CON(5) 233 CON(5) 234 CON(5) 235 CON(5) 236 CON(5) 237 CON(5) 238 CON(5) 239 CON(5) 240 CON(5) 241 CON(5) 242 CON(5) 243 CON(5) 244 CON(5) 245 CON(5) 246 CON(5) 247 CON(5) 248 CON(5) 249 CON(5) 250 CON(5) 251 CON(5) 252 CON(5) 253 CON(5) 254 CON(5) 255 Last storage register, for poll FF INCR1 C=RSTK C[A] is ONOFF address D0=C set pointer to ONOFF C=DAT0 S ?C=0 S are we disabled? GOYES NtHndl yes, clean-up and exit! D0=D0+ 1 advance one nibble to TBLST register C=DAT0 A read 'total' register C=C+1 A increment to reflect this poll GOC NtHndl sorry, storage is full, clean-up, restore D0 @ exit DAT0=C A not full, store incremented value D0=D0+ 5 point at SLOCNT register ?P= 0 is this a fast poll? GOYES INCR3 yes, no need to increment SLOCNT C=DAT0 A no, increment SLOCNT C=C+1 A DAT0=C A INCR3 CD0EX C[A] is SLOCNT address C=C+B A increment by 5 times the poll number, to the address C=C+B A of the storage register specified by B[B] C=C+B A 3 C=C+B A 4 C=C+B A CD0EX D0=D0+ 5 allows for the SLOCNT register. D0 points at register C=DAT0 A read it C=C+1 A increment it by 1 DAT0=C A store the new value NtHndl C=RSTK exit path, restores D0, clears carry, ect. CD0EX D0 is restored P= 0 we may have set P= 1, we MUST reset it to 0 C=-C-1 A clear carry, it may be set if TBLST overflows RTNSXM done, at last! * * Since every poll issued that is intercepted by our POLHND routine exits * by way of NtHndl, we could respond to any poll, such as VER$P by inserting * suitable code ahead of RTNSXM above. (?B=0 B GOYES VER$P, ect.) * ***************************************************************** * SPTIM1 GOSBVL SAVD0 save D0 and D1 in FUNCR0, FUNCR0+5 D0=C keeping the current values as-is GOSBVL SAVD1 D1=C GOSBVL CMPT read time. we should make sure the data is R3=C stable, ie., reread until two consecutive values CD1EX are equal, but we are only looking for an approximation CD0EX So, save the current time in R3, CD1EX exchange D0 and D1 - See POLL documentation GOSBVL AVE=D0 D0 => top of mathstack, and set available memory to D0 RTN we are now ready to issue either a fast or a slow poll *--------------------------------------------------------- * Actually, we should be saving the PC pointer on the GOSUB stack in case * memory moves, but no one is supposed to do anything when pTEST is issued. * If somebody violates this, well, they deserve memory lost! *--------------------------------------------------------- NIBHEX 00 function w/o parameters SPTIM GOSUB SPTIM1 get ready to issue poll GOSBVL POLL issue it as a slow poll (saves everything) CON(2) #F0 pTEST SPTIM2 GOC bserr routine error-trapping. Not enough mem to issue poll? ?XM=0 was the process handled?(should never happen) GOYES err well, let's try to avoid crash GOSBVL CMPT let find out how long this took A=C W C=R3 A=A-C A subtract current time from earlier value saved in R3 GOSBVL RSTD0 CMPT uses D0, D1, restore ORIGINAL values GOSBVL RSTD1 GOTO MAXP60 convert hex time difference, using common funtion code err P= 0 LC(4) #001F eDATTY, data type error to indicate handled problem bserr GOVLNG BSERR ***************************************************************** CMPT EQU #125B2 FPOLL EQU #1250A POLL EQU #12337 D=AVEME EQU #1A476 AVE=D0 EQU #01494 SAVD0 EQU #1C587 SAVD1 EQU #1C578 RSTD0 EQU #06832 RSTD1 EQU #1C596 ***************************************************************** NIBHEX 00 now do the same job, but issue a fast poll. FPTIM GOSUB SPTIM1 using common code... GOSBVL FPOLL CON(2) #F0 GOTO SPTIM2 ***************************************************************** tON EQU #000E0 tOFF EQU #000E1 MSPARe EQU #02E5C TRACDC EQU #052FC WRDSCN EQU #02C2A ONd GOVLNG TRACDC ON/OFF token decompile ONp GOSBVL WRDSCN ON/OFF token parse CON(2) tON REL(3) parse CON(2) tOFF REL(3) parse CON(2) 0 end of allowable tokens table ST=0 4 neither ON or OFF, so error exit GOVLNG MSPARe parse RTNCC parsed ok, end of parse REL(5) ONd REL(5) ONp POLDAT A=DAT0 B read tON/tOFF token after POLLDATA keyword CD0EX save D0 pointer RSTK=C P= 0 probably not required, P should be 0 already GOSUB FINDR D0 is set to TBLST A=A-1 WP convert second nibble of tON / tOFF to F or 0 D0=D0- 1 set D0 to ONOFF nibble DAT0=A 1 store either 0 or F at ONOFF nibble * Nibble=0 means OFF, =F means ON, inverts logic GOTO RST41 restore D0, and exit via NXTSTM