:TITLE[Htfind.0mc, October 19, 1983 3:50 PM, van Melle]; * RV[Probe, IP[lspNargs]]; RV[Case, IP[lspDefx0]]; RV[Entry, IP[lspDefx1]]; @GcRef: * TOS -> TOS if cnt went to zero, NIL otherwise Case ← 100000c, opcode[025]; * = explicit punt if collision T ← NextData[IBuf]; Case ← (Case) + T; T ← Stack&-1; * L0,1 ← TOS lspL1 ← T; T ← Stack&+1, loadpage[pgHtFind]; lspL0 ← T, call[GcLookup]; lu ← (Entry) and (htStkCnt), goto[TOSGetsNILifNeq]; * Smash TOS with NIL unless Stackbit = refcnt = 0 onpage[pgHtFind]; * GcLookup subroutine L0,1 = Pointer, Case = operation; returns Entry, which * is guaranteed to be valid in collision bit and count field if no collision * Smashes lspLN, lspNargs, lspL5, AC2/Hi, and Case & Entry (lspDefx0,1). GcLookup: UseCTask; GcLookupWithCTask: T ← APC&APCTask, task; lspL5 ← T; * Save return address T ← lspL0 ← rhmask[lspL0]; * mask out any garbage in hi 8 bits T ← lsh[lspL0, 7]; * T ← lsh[lspL0, 7], skip[NoH2Bit8]; * goto[htAtom]; * This catches invalid addrs in the 200b range * Too bad I can't get the 100b ones so cheaply T ← (rsh[lspL1, 11]) or T; PFetch1[MDSTypeBaseBr, lspLN]; * get Type table entry AC2Hi ← (htMainSpace); * Set up base register while waiting AC2 ← (htMainBase), task; T ← rsh[lspL1, 1]; * Location to make probe in hash table lu ← (lspLN) and (40000c), goto[htAtom, R<0]; * sign bit = no gcref * skip[alu=0]; * test "no gcref in microcode" bit * goto[htPunt]; * Entry needs to be set PFetch1[AC2, Entry]; * Get Hash table entry * Cannot fault because table locked lu ← Entry, skip[Reven]; * Pointer to collision entry if odd goto[htPunt]; T ← lsh[lspL0, 1], goto[htNotEmpty, alu#0]; * Is entry empty? Entry ← T; * Empty means Entry has count of 1 Entry ← (Entry) or (ht1cnt), goto[htDisp]; htNotEmpty: T ← ldf[Entry, 7, 10]; * get hi bits of hash table entry lu ← (lspL0) xor T; * compare with the pointer lu ← (Entry) + (ht2Cnt), skip[alu=0]; Entry ← 1c, goto[htPunt]; * Not same, is a collision goto[htPunt, carry]; * Cnt field is full or about to be, so punt it to Lisp htDisp: dispatch[Case, 16, 2]; lspLN ← (htStkCnt), disp[htProbe]; htProbe: T ← Entry ← (Entry) + (ht1Cnt), goto[htStore], disptable[3]; * [0]: addref T ← Entry ← (Entry) - (ht1Cnt), goto[htStore]; * [1]: delref T ← Entry ← (Entry) or (htStkBit), goto[htStore]; * [2]: stkref htStore: * store modified entry lspLN ← (lspLN) and T; * Mask out all but Stk & Cnt fields lu ← (lspLN) xor (ht1Cnt); lspLN ← T, skip[alu#0]; lspLN ← 0c; * Entry with cnt=1, stk=0 not stored T ← rsh[lspL1, 1]; PStore1[AC2, lspLN], goto[htDone]; * Update entry in hash table htAtom: Entry ← (ht1Cnt), goto[htDone]; * atoms etc never in table htDone: lspL0 ← rhmask[lspL0], call[retLBL]; * Mask out garbage from Punt * And task, because next return won't APC&APCTask ← lspL5, goto[retLBL]; htPunt: * add case,,L0,1 to HT overflow table T ← lsh[Case, 10], goto[htCallUfn, R<0]; lspL0 ← (lspL0) + T; * OR case into hi L0 T ← 100000c, call[.+1]; * Offset of overflow table PFetch1[AC2, lspLN]; * fetch entry lu ← lspLN; * Zeros end the table skip[alu=0], Case ← (Case) or (GcOverflowPunt); * signal punt for end of op T ← (Form2[AllOnes]) + T, return; * T ← T+2, return to PFetch1 PStore2[AC2, lspL0], goto[htDone]; * Store entry htCallUfn: * Can't defer this punt lspUFN ← 025c, goto[ufnLBL]; * RplPtr.n(base, ptr): store TOS at n off TOS-1, preserving the hi byte at TOS-1 @RplPtr: loadpage[pgHStack], call[CheckElt2P4], opcode[24]; :IF[0]; *** old code loadpage[pgRplPtr]; nop; onpage[pgRplPtr]; Stack&-2, call[PopL2]; * Set L3,2 to ptr T ← NextData[IBuf]; * get offset lspL2 ← (lspL2) + T; goto[RplPtrA1, no carry]; lspL3 ← (lspL3) + (400c); * crossed segment goto[RplPtrA1]; * because just wrote hi base for next PFetch PopL2: * put TOS in L3,2 for addressing * leaves stack level alone T ← Stack&-1; lspL2 ← T; T ← rhmask[Stack&+1]; lspL3 ← T; lspL3 ← (lsh[lspL3, 10]) + T + 1, return; :ELSE; **** new code Stack&-2; * Point at base T ← NextData[IBuf]; * word offset T ← (Stack&-1) + T, loadpage[pgRplPtr]; * form low base lspL2 ← T, FreezeResult; onpage[pgRplPtr]; T ← lsh[Stack&+1, 10], skip[Carry']; * form hi base T ← (R400) + T; * Segment cross lspL3 ← T; nop; * wait for hi base to write :ENDIF; RplPtrA1: * from Rplaca, Rplacd. * Stack points at PTR, new item is above that * L3,2 points at cell to replace in PFetch2[lspL2, lspL0, 0]; * get old contents. CAN FAULT T ← lhmask[lspL0]; RplPtrA2: * from Rplaca XBuf ← T, loadpage[pgHTFind]; Case ← 1c, callp[GcLookup]; * Deleteref old value StkState ← rsh[StkState, 1]; Stack&+2; * point at new item T ← Stack&-1; lspL1 ← T; T ← XBuf; * old hi byte,,0 T ← (rhmask[Stack&-1]) or T; lspL0 ← T; * L0,1 ← old hi byte,,new item RplPtr1: * From GVAR←. L0,1 = words to store at L3,2 PStore2[lspL2, lspL0, 0]; * Store new value, no fault loadpage[pgHTFind]; * Case ← 0 in rh, punt flag remains Case ← lhmask[Case], callp[GcLookup]; * Addref new value GcExit: * Come here at end of gcreffing instructions * normal finish, unless htpunt was called for lu ← (Case) and (GcPunts); lu ← (Case) and (CreateCellPunt), skip[alu#0]; NextOpCode; lspDefx1 ← (atomGCOVERFLOW), skip[alu=0]; lspDefx1 ← (atomGCGENPUNT); * more general punt needed loadpage[pgFrame]; lspNargs ← 1c, gotop[lspCallFn0]; * Gvar←, op 27: Set top value of atom alpha,beta to TOS @SetGvar: loadpage[pgRplPtr], opcode[27]; lspL3 ← (VALspace); onpage[pgRplPtr]; T ← NextData[IBuf]; lspL2 ← T; T ← NextData[IBuf]; lspL2 ← (lsh[lspL2, 10]) or T, task; * L2 ← atom number to set lspL2 ← lsh[lspL2, 1]; * Point at value cell SetGvar1: * Here from SETF PFetch2[lspL2, lspL0, 0]; * fetch old top value; CAN FAULT loadpage[pgHTFind]; Case ← 1c, callp[GcLookup]; * Deleteref old value T ← Stack&-1; lspL1 ← T; * L0,1 ← TOS T ← Stack&+1; lspL0 ← T, goto[RplPtr1]; * Rplaca (LST ITEM) @Rplaca: loadpage[pgHStack], call[CheckElt2P4], opcode[030]; Stack&-2, call[lspTyp]; * check type of LST (below ITEM) loadpage[pgRplPtr]; lu ← (lspType) - (listType); onpage[pgRplPtr]; skip[alu=0]; * ok if listp lspUFN← 30c, goto[ufnLBL]; * LST is now in L3,2 from lspTyp PFetch2[lspL2, lspL0, 0]; * look at old cdrcode,,car T ← lhmask[lspL0]; * cdrcode goto[RplPtrA2, alu#0]; * cdrcode#0 is normal, do Rplptr T ← lsh[lspL0, 10]; * indirect: this is hiloc shifted lspL3 ← T; T ← lspL1; * loloc indirect lspl2 ← T, goto[RplPtrA1]; * go do RPLPTR with fetch @Rplacd: lspUFN← (031c), goto[lspUfnxP4], opcode[031]; * Rplacd % @Rplacd: * (RPLACD LST NEWCDR) => LST loadpage[pgHStack], call[CheckElt2P4], opcode[031]; Stack&-2, call[lspTyp]; * get LST in L3,2, type in lspType loadpage[pgRplacd]; lu ← (lspType) - (listtype); onpage[pgRplacd]; lspUFN ← 31c, skip[alu=0]; goto[ufnLBL]; RplacdFetch: Pfetch2[lspL2, lspL0, 0]; * fetch contents of cell T ← lhmask[lspL0]; * get cdrcode XBuf1 ← T, goto[Rplacd1, alu#0]; T ← lspL0; lspL3 ← T; * follow indirect... T ← lspL1; lspL2 ← T, goto RplacdFetch; Rplacd1: * contents of cell in 0,1 goto[RplacdIndirect, alu>=0]; * indirect on page Stack&+2; * Point Stack back at NEWCDR T ← Stack&-1; lspL1 ← T; T ← Stack&-1; * Stack points at LST now lspL4 ← T, goto[RplacdNIL, alu=0]; * NEWCDR in 4,1 lu ← (lspL3) xor T; * compare hi words of LST, NEWCDR skip[alu=0]; goto[ufnLBL]; * NEWCDR not on LST's page T ← lhmask[lspL1]; T ← (lhmask[lspL2]) xor T; * compare lo parts of page numbers skip[alu=0]; goto[ufnLBL]; * NEWCDR not on LST's page T ← lsh[lspL1, 7]; * cell # of NEWCDR in left half T ← (rhmask[lspL0]) or T; * new contents of LST, minus 200 bit XBuf2← T; * save it T ← lspL4; lspL0 ← T, loadpage[pgHtFind]; * NEWCDR now in 0,1 Case← 0c, callp[GcLookup]; * Addref NEWCDR RplacdSmash: * Old cdrcode in lh of XBuf1 * almost new cdr code word in XBuf2 * LST in L3,2 T ← XBuf1 ← ldf[XBuf1, 1, 10]; * 2 * old cdrcode T ← (lhmask[lspL2]) + 2; * point at old cdr lspL1 ← T; T ← lspL3; lspL0 ← T, loadpage[pgHtFind]; * old cdr now in 0,1 Case ← (lhmask[Case]) + 1, callp[GcLookup]; * deleteref old cdr XBuf2 ← (XBuf2) or (100000c); * set cdr on page bit PStore1[lspL2, XBuf2, 0]; * update LST's cdr code loadpage[pgRplPtr]; StkState←rsh[StkState,1], gotop[GcExit]; * done, having popped once, check for punt RplacdNIL: * Hiloc(NEWCDR) = 0 lu ← lspL1; * Loloc(NEWCDR) XBuf2 ← 0c, goto[RplacdSmash, alu=0]; goto[ufnLBL]; * NEWCDR not NIL, so punt RplacdIndirect: * indirect on page, cdrcode in XBuf1 T ← ldf[XBuf1, 1, 10], loadpage[pgRplptr]; * 2 * old cdrcode lspL2 ←(lhmask[lspL2]) + T, gotop[RplptrA1]; * point 3,2 at loc of cdr, go do RplPtr on it % * GcScan1, op 173 @GcScan1: T ← 0c, goto[GcScanx], opcode[173]; * GcScan2, op 174 @GcScan2: T ← 100c, opcode[174]; lspL0 ← (htStkBit); * Pattern = Collision bit or Stack bit lspL0 ← (lspL0) + 1, goto[GcScanx]; GcScanx: Saluf ← T, T ← Stack&-1; * MB ← 0 for GcScan1, 1 for GcScan2 lspGenBrHi ← (htMainSpace); lspGenBr ← (htMainBase); lspLN ← T, loadpage[pgGcScan]; PFetch4[lspGenBr, XBuf]; onpage[pgGcScan]; GcScanRestart: Dispatch[lspLN, 16, 2]; T ← lspLN ← (lspLN) and not (3c), disp[.+1]; lu ← 0c, goto[GcSa0], disptable[4]; * == instr at GcSa0+1 lu ← 0c, goto[GcSa1]; * == T ← XBuf, goto[GcSa0]; lu ← 0c, goto[GcSa2]; * == T ← XBuf1, goto[GcSa1]; lu ← 0c, goto[GcSa3]; * == T ← XBuf2, goto[GcSa2]; GcScanLoop: PFetch4[lspGenBr, XBuf], call[retLBL]; * get 4 words, task T ← XBuf3; GcSa3: T ← XBuf2, goto[GcSc3, alu#0]; GcSa2: T ← XBuf1, goto[GcSc2, alu#0]; GcSa1: T ← XBuf, goto[GcSc1, alu#0]; GcSa0: lu ← lspLN, goto[GcSc0, alu#0]; T ← lspLN ← (lspLN) - (4c), dblgoto[GcScanLoop, GcScanDone, alu#0]; GcSc3: lspLN ← (lspLN) + (3c); T ← XBuf3, dblgoto[GcCheck2, GcCheck1, MB]; GcSc2: lspLN ← (lspLN) + (2c); T ← XBuf2, dblgoto[GcCheck2, GcCheck1, MB]; GcSc1: lspLN ← (lspLN) + (1c); T ← XBuf1, dblgoto[GcCheck2, GcCheck1, MB]; GcSc0: T ← XBuf, dblgoto[GcCheck2, GcCheck1, MB]; GcCheck1: * In GcScan1: Check for collision or stk=cnt=0 lspL1 ← T; lu ← (lspL1) and (htStkCnt), skip[Reven]; T ← lspLN, goto[GcScanFound]; * Collision bit on skip[alu#0]; T ← lspLN, goto[GcScanFound]; * Stk=cnt=0 goto[GcScanRestart]; * combine with GcCheck2+1? (senses are reversed) GcCheck2: * In GcScan2: Check for collision or stk lu ← (lspL0) and T; * L0 set up the desired pattern at init T ← lspLN, dblgoto[GcScanFound, GcScanRestart, alu#0]; GcScanDone: T ← Stack ← 0c; * TOS ← NIL when done GcScanFound: Stack&+1 ← T, goto[nxiLBL]; * TOS ← offset of find @ReclaimCell: * (PTR) => newptr or NIL * lspUFN ← (172c), goto[lspUfnxP5], opcode[172]; * ReclaimCell loadpage[pgReclaim], opcode[172]; nop; onpage[pgReclaim]; loadpage[pgTyp]; callp[lspTyp]; lu ← (lspType) - (listtype); lspUFN ← 172c, skip[alu=0]; goto[ufnLBL]; * punt if nlistp PFetch2[lspL2, lspL0, 0]; * contents of cell -> L0,1 T ← lhmask[lspL0]; * get cdrcode skip[alu#0]; goto[ufnLBL]; * punt on full indirect (cdrcode=0) %--------- T ← lhmask[lspL0], skip[R<0]; * get cdrcode, skip if 200 bit on goto[ufnLBL]; * punt on indirect cases ---------% XBuf ← T, call[FreeListCell]; * save cdr code, free cell L2,3 loadpage[pgHtFind]; Case ← 1c, call[GcLookup]; * deleteref car Stack&-1 ← 0c; * TOS ← NIL Stack&+1 ← 0c, call[ReclaimCheck]; * Put car on stack if cnt is zero T ← ldf[XBuf, 1, 10]; * cdrcode lsh 1 goto[ReclaimDone, alu=0], T ← lspL2← (lhmask[lspL2]) + T; * point at cdr cell, or finished if cdr nil lu ← XBuf, goto[ReclaimCdr1, R<0]; * Case 1 is cdr on page, easy PFetch2[lspL2, lspL0, 0]; * Get contents of cdr's cell call[FreeListCell]; * Free the cell itself T ← rhmask[lspL0], goto[ReclaimCdr2]; * cdr = contents of cell ReclaimCdr1: lspL1 ← T; * lo half of cdr T ← rsh[lspL3, 10]; ReclaimCdr2: lspL0 ← T, loadpage[pgHtFind]; * hi half call[GcLookup]; * deleteref cdr call[ReclaimCheck]; * put cdr on stack if cnt is zero ReclaimDone: loadpage[pgRplPtr]; gotop[GcExit]; * check for htpunt ReclaimCheck: * Replace TOS with L0,1 if Entry is a zero-count ht entry lu ← (Entry) and (htstkcnt), skip [REven]; return; * Collision entry, so unknown T ← lspL0, skip[alu=0]; return; * Stkbit,,cnt nonzero Stack&-1 ← T; T ← lspL1; Stack&+1 ← T, return; FreeListCell: * L3,2 points at cell to free. L0 is contents of its first word. * Smashes L3,2 to point at pagebase. Smashes L4, lh[L0], XBuf2,3 T ← rhmask[lspL2]; * offset in page lspL2 ← lhmask[lspL2]; * point to page base Pfetch2[lspL2, XBuf2, 0]; * get count,,nextcell, nextpage lspL4 ← T; * save offset lu ← XBuf3, skip[R>=0]; * nextpage = -1 is punt case. * NOTE: Assumes < 24-bit addrs, or no lists on negative pages goto[ufnLBL]; * punt if this page not in free chain T ← lsh[XBuf2, 10]; * next cell, shifted to high byte lspL0 ← (rhmask[lspL0]) or T; * make it cdr code at cell T ← lspL4; Pstore1[lspL2, lspL0]; * store it back in cell XBuf2 ← (XBuf2) + (400c); * increment count XBuf2 ← (lhmask[XBuf2]) or T; * make it count,,celloffset :IF[BreakPoints]; lu ← XBuf2, skip[REven]; breakpoint; :ENDIF; Pstore1[lspL2, XBuf2, 0]; * store it back on page return; * allow XBuf2 write :END[Htfind];