Files
erkyrath.infocom-zcode-terps/apple/yzip/rel.13/read.asm
Andrew Plotkin b642da811e Initial commit.
2023-11-16 18:19:54 -05:00

698 lines
16 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
STTL "--- READ HANDLER ---"
PAGE
; ----
; READ
; ----
; READ LINE INTO TABLE [ARG1] ; PARSE INTO TABLE [ARG2] (IF ARG2 IS THERE)
MAXWORDS DB 0 ; maximum number of words in table
WORDCNT DB 0 ; how many words read so far
WORDSTART DB 0 ; table offset of word
SAVESPC DS 3 ; SPC that points to Word Count
ZREAD:
lda ARG1+HI ; MAKE THE TABLE ADDRESSES
sta RDTBL1+HI ; AND PLACE IT HERE TO USE
lda ARG1+LO
sta RDTBL1+LO ; LSBS NEED NOT CHANGE
lda #0 ; TURN OFF FLAGS
sta PSVFLG ; FOR ZLEX
sta VOCFLG
ldx NARGS
dex ; IF 2ND TBL ADDR 0 OR NOT THERE
beq ONLYRD ; JUST READ IN DON'T DO CONVERSION (X)
ldx #0 ; JIC
lda ARG2+HI
ora ARG2+LO
beq ONLYRD
lda ARG2+HI
sta RDTBL2+HI
lda ARG2+LO
sta RDTBL2+LO
ldx #1 ; 1 = DO IT ALL (X)
ONLYRD:
stx RDFLAG ; CHECK AGAIN AFTER READ IN WHAT TO DO
jsr INPUT ; READ LINE; RETURN LENGTH IN [RDTBL1],1
lda RDFLAG ; FLAG (X)
beq RDEX ; IF INPUT ONLY, LEAVE NOW
jsr DOREST
RDEX:
lda #$F0 ; RETURN NOW ONLY WANTED READ PART
sta RDFLAG
lda BRKCHR ; GET BREAK CHAR
ldx #0
jmp PUTBYT ; RETURN IT
;
; IF TIMEOUT, [A]=0 SO WILL QUIT W/NO RESULTS
;
DOREST:
lda RDTBL2+HI ; get max number of words
jsr SETPC ; tell me memory and bank
sta FPCH ; save page
sty FPCBNK ; and bank
lda RDTBL2+LO ; and for LSB
sta FPCL ; it is same
jsr FETCHB ; get max # of words in table
beq RDERR ; (5/14/85 - FORCE # WORDS TO
cmp #59 ; BE BETWEEN 1 AND 59)
bcc RD0
RDERR:
lda #58 ; (5/16/86 - MAKE IT 58, 59 LOST)
RD0:
sta MAXWORDS ; save max words
lda #0 ; start at 0 words
sta WORDCNT ; save it
sta WRDLEN ; INIT # CHARS IN WORD COUNTER
lda #2
sta SOURCE ; INIT SOURCE TABLE PNTR
;
; now futz with destination table a little
;
jsr NEXTFPC ; now we point to # words read
lda FPCBNK ; and save this pointer
sta SAVESPC ; for stashing at the end
lda FPCH
sta SAVESPC+1
lda FPCL
sta SAVESPC+2
lda #4 ; offset to end of first entry
jsr ADDFPC ; and point to end of first entry
jsr FP2SP ; now put RDTBL2 into stash pointer
;
; now get source table
;
lda RDTBL1+HI ; get page
jsr SETPC ; and tell me what mem page and bank
sta FPCH ; set up fetch counter
sty FPCBNK ; and bank
lda RDTBL1+LO ; and lo stays the same
sta FPCL ; and save it
jsr NEXTFPC ; get # of chars in buffer
jsr FETCHB ; and tell me about it
sta LINLEN ; SAVE # CHARS IN LINE
jsr NEXTFPC ; now point to first char in line
;
; MAIN LOOP STARTS HERE
;
READL:
lda MAXWORDS ; how we doin'?
cmp WORDCNT ; see if we have maxxed out
bcc RLEX ; all done, thank you
lda LINLEN
ora WRDLEN ; OUT OF CHARS AND WORDS?
bne RL2 ; NOT YET
RLEX:
lda SAVESPC ; now set SPC to point to # words
sta SPCBNK ; read byte, as saved at the beginning
lda SAVESPC+1
sta SPCH
lda SAVESPC+2
sta SPCL
lda WORDCNT ; get word count
jsr STASHB ; and save it
rts
RL2:
lda WRDLEN ; GET WORD LENGTH
cmp #9 ; 9 CHARS DONE? (EZIP)
bcc RL3 ; NO, KEEP GOING
jsr FLUSHW ; ELSE FLUSH REMAINDER OF WORD
RL3:
lda WRDLEN ; GET WORD LENGTH AGAIN
bne READL2 ; CONTINUE IF NOT FIRST CHAR
;
; START A NEW WORD
;
ldx #8 ; CLEAR Z-WORD INPUT BUFFER
RLL: sta IN,X ; [A] = 0
dex
bpl RLL
lda SOURCE ; STORE THE START POS OF THE WORD
sta WORDSTART ; and save it for later
jsr FETCHB ; GET A CHAR FROM SOURCE BUFFER
jsr SIB ; IS IT A SELF-INSERTING BREAK?
bcs DOSIB ; YES IF CARRY WAS SET
jsr NORM ; IS IT A "NORMAL" BREAK?
bcc READL2 ; NO, CONTINUE
inc SOURCE ; ELSE FLUSH THE STRANDED BREAK
jsr NEXTFPC ; and point to next char
dec LINLEN ; UPDATE # CHARS LEFT IN LINE
jmp READL ; AND LOOP
READL2:
lda LINLEN ; OUT OF CHARS YET?
beq READL3 ; LOOKS THAT WAY
jsr FETCHB ; Grab the char
jsr BREAK ; IS IT A BREAK?
bcs READL3 ; YES IF CARRY WAS SET
ldx WRDLEN ; ELSE STORE THE CHAR
sta IN,X ; INTO THE INPUT BUFFER
dec LINLEN ; ONE LESS CHAR IN LINE
inc WRDLEN ; ONE MORE IN WORD
inc SOURCE ; and update next source
jsr NEXTFPC ; POINT TO NEXT CHAR IN SOURCE
jmp READL ; AND LOOP BACK
;
; handle self-inserting breaks
DOSIB:
sta IN ; put the break into 1st word slot
dec LINLEN ; one less char in line
inc WRDLEN ; one more in word buffer
inc SOURCE ; and update next source
jsr NEXTFPC ; point to next source char
READL3:
lda WRDLEN ; ANY CHARS IN WORD YET?
bne READL31 ; yup, so deal with word
jmp READL ; then go get next word
READL31:
jsr CONZST ; CONVERT ASCII IN [IN] TO Z-STRING
jsr FINDW ; AND LOOK IT UP IN VOCABULARY
lda WORDSTART ; get where it starts
jsr STASHB ; and save it
jsr PREVSPC ; step backwards to point to length
lda WRDLEN ; and get length
jsr STASHB ; and save it away
jsr PREVSPC ; and backwards to LSB of offset
ldx #6 ; offset to point to end of next entry
inc WORDCNT ; increment # words read
lda PSVFLG ; IF SHOULD PRESERVE WHAT'S IN
beq READL4
lda VALUE+HI ; RDTBL2 AND NOT FOUND (VALUE = 0)
ora VALUE+LO
beq READL5 ; JUST SKIP OVER
READL4:
lda VALUE+LO ; GET LSB OF VOCAB ENTRY ADDRESS
jsr STASHB ; and stash it away
jsr PREVSPC ; point to MSB part
lda VALUE+HI ; ALSO STORE MSB IN 2ND SLOT
jsr STASHB ; and send it out
ldx #7 ; offset to point to end of next entry
READL5:
lda #0
sta WRDLEN ; CLEAR # CHARS IN WORD
txa ; get offset
jsr ADDSPC ; and point to end of next entry
jmp READL ; AND LOOP BACK
; ---
; LEX
; ---
; DO PARSE OF TBL1 INTO TBL2 (2ND HALF OF READ)
ZLEX:
LDA ARG1+HI ; MAKE THE TABLE ADDRESSES
STA RDTBL1+HI ; AND PLACE IT HERE TO USE
LDA ARG1+LO
STA RDTBL1+LO ; LSBS NEED NOT CHANGE
LDA ARG2+HI
STA RDTBL2+HI
LDA ARG2+LO
STA RDTBL2+LO
DEC NARGS
DEC NARGS
BEQ NORMLEX ; USE NORMAL VOCAB TBL
LDA #1 ; USE ARG3 VOCAB TBL
STA VOCFLG
LDA #0
DEC NARGS
BEQ NOSAVE ; ZERO UNFOUND WORDS
LDA #1 ; PRESERVE UNFOUND WORD SLOT FLAG
NOSAVE: STA PSVFLG
JMP DOLEX
NORMLEX: LDA #0
STA VOCFLG ; USE NORMAL VOCAB TBL
STA PSVFLG ; AND WILL BE NO PRESERVING
DOLEX: JMP DOREST ; GO DO LEXICAL CONVERSION AND JUST RETURN
; -----
; ZWSTR
; -----
; CONVERT A WORD TO A ZWORD, PLACE IN ARG4 TBL
ZWSTR:
lda ARG1+HI ; Make ARG1 be the FPC
jsr SETPC ; so get absolute mem bank/page
sty FPCBNK ; save bank and
sta FPCH ; page
lda ARG1+LO
sta FPCL ; LSBS NEED NOT CHANGE
;
; (IGNORE WORD LENGTH CAUSE CHECK FOR BREAK CHAR (9 CHAR MAX))
;
lda ARG3+LO ; ADD OFFSET INTO INBUF
jsr ADDFPC ; add it to the FPC
lda ARG4+HI ; now fix the SPC too
jsr SETPC ; get me bank and page
sty SPCBNK ; save bank
sta SPCH ; save page
lda ARG4+LO
sta SPCL ; LSB doesn't change
;
; START A NEW WORD
;
lda #9
sta LINLEN ; 1 WORD'S WORTH
lda #0
sta WRDLEN
ldx #8 ; CLEAR Z-WORD INPUT BUFFER
WSTR1: sta IN,X ; [A] = 0
dex
bpl WSTR1
;
; THIS LOOP READS FROM INBUF TIL BREAK OR 9 CHARS READ
;
WSTR2:
jsr FETCHB ; grab the next char
jsr BREAK ; IS IT A BREAK?
bcs WSTR3 ; YES IF CARRY WAS SET
ldx WRDLEN ; ELSE STORE THE CHAR
sta IN,X ; INTO THE INPUT BUFFER
inc WRDLEN ; ONE MORE CHAR IN WORD
dec LINLEN ; ONE LESS IN LINE
jsr NEXTFPC ; point to next char
bne WSTR2 ; AND LOOP BACK TIL DONE
WSTR3:
lda WRDLEN ; ANY CHARS IN WORD YET?
beq WOOPS ; APPARENTLY NOT, OOPS
jsr CONZST ; CONVERT ASCII IN [IN] TO Z-STRING
ldx #0 ; MOVE FROM [OUT] TO RDTBL2
WSTR4: lda OUT,X
jsr STASHB ; and stash it into ZWORD table
jsr NEXTSPC ; and point to next byte
inx
cpx #6 ; max 6 word table
bne WSTR4 ; not done yet
WOOPS:
rts
; ----------
; FLUSH WORD
; ----------
FLUSHW:
lda LINLEN ; ANY CHARS LEFT IN LINE?
beq FLEX ; NO, SCRAM
jsr FETCHB ; GRAB A CHAR
jsr BREAK ; IS IT A BREAK?
bcs FLEX ; EXIT IF SO
dec LINLEN ; ELSE UPDATE CHAR COUNT
inc WRDLEN ; AND WORD-CHAR COUNT
inc SOURCE ; AND CHAR POINTER
jsr NEXTFPC ; and FPC pointer too
jmp FLUSHW ; AND LOOP BACK (ALWAYS)
FLEX:
rts
; ---------------------------------
; IS CHAR IN [A] ANY TYPE OF BREAK?
; ---------------------------------
; ------------------
; NORMAL BREAK CHARS
; ------------------
BRKTBL: DB '!?,.' ; IN ORDER OF
DB $0D ; ASCII ENDING FREQUENCY
DB SPACE ; SPACE CHAR IS TESTED FIRST FOR SPEED
DB 0 ; ZERO ADDED FOR ZWSTR (X)
NBRKS EQU $-BRKTBL ; # NORMAL BREAKS
BREAK: JSR SIB ; CHECK FOR A SIB FIRST
BCS FBRK ; EXIT NOW IF MATCHED
; ELSE FALL THROUGH ...
; --------------------------------
; IS CHAR IN [A] A "NORMAL" BREAK?
; --------------------------------
NORM: LDX #NBRKS-1 ; NUMBER OF "NORMAL" BREAKS
NBL: CMP BRKTBL,X ; MATCHED?
BEQ FBRK ; YES, EXIT
DEX
BPL NBL ; NO, KEEP LOOKING
CLC ; NO MATCH, CLEAR CARRY
RTS ; AND RETURN
; ---------------------
; IS CHAR IN [A] A SIB?
; ---------------------
SIB: STA IOCHAR ; SAVE TEST CHAR
lda VOCAB+ABANK ; get bank
sta MPCBNK ; and save it
lda VOCAB+HI ; and hi part
sta MPCPNT+HI ; and save it
lda ZBEGIN+ZVOCAB+0 ; GET 1ST BYTE IN VOCAB TABLE
LDY ZBEGIN+ZVOCAB+1
STA MPCM
STY MPCL
LDA #0
STA MPCH ; now everything is set up
JSR GETBYT ; HAS # SIBS
STA J ; USE AS AN INDEX
SBL: JSR GETBYT ; GET NEXT SIB
CMP IOCHAR ; MATCHED?
BEQ FBRK0 ; YES, REPORT IT
DEC J
BNE SBL ; ELSE KEEP LOOPING
LDA IOCHAR
CLC ; NO MATCH, SO
RTS ; EXIT WITH CARRY CLEAR
FBRK0: LDA IOCHAR
FBRK: SEC ; EXIT WITH CARRY SET
RTS ; IF MATCHED WITH A BREAK CHAR
; -----------------
; VOCABULARY SEARCH
; -----------------
; ENTRY: 6-BYTE TARGET Z-WORD IN [OUT]
; EXIT: VIRTUAL ENTRY ADDRESS IN [VALUE] IF FOUND ;
; OTHERWISE [VALUE] = 0
VWLEN EQU I ; **********
VWCUR EQU J+HI
FINDW:
lda VOCFLG ; USE WHAT VOCAB TBL?
beq FWL2 ; NORMAL
lda ARG3+HI ; IF ALTERNATE VOCTBL
ldy ARG3+LO ; IT'S ADDR IS IN ARG3
jmp FWL3
FWL2:
lda DIDVTBL ; have we done default vocab table?
beq FWLNEW ; nope, so do it the first time
ldx #2 ; restore pointers
FWRSTL:
lda VOCMPC,X ; get it
sta MPC,X ; save it
lda VCESVE,X ; save VOCEND too
sta VOCEND,X ; okay, we have
lda VWLSVE,X ; and starting length
sta VWLEN,X ; we have
dex ; count
bpl FWRSTL ; okay, next one
jmp FWLOOP ; and go do it
FWLNEW:
lda #$FF ; show we are doing default table
sta DIDVTBL ; we shall
lda ZBEGIN+ZVOCAB ; GET VIRTUAL ADDR OF VOCAB TBL
ldy ZBEGIN+ZVOCAB+1
FWL3:
STA MPCM
STY MPCL
LDA #0
STA MPCH
JSR VLDMPC ; SET TO NEW PAGE
JSR GETBYT ; GET # SIBS
CLC
ADC MPCL ; GET ACTUAL BASE ADDR OF VOCAB ENTRIES
STA MPCL
BCC FWL0
INC MPCM
FWL0: JSR VLDMPC ; SET TO NEW PAGE
JSR GETBYT ; GET # BYTES PER ENTRY (AND MOVE TO NEXT BYTE)
STA ESIZE ; SAVE IT HERE
STA VWLEN+0 ; AND HERE
LDA #0 ; CLEAR REST OF COUNTER
STA VWLEN+1
STA VWLEN+2
JSR GETBYT ; GET # OF ENTRIES IN TBL (MSB)
STA NENTS+HI ; AND STUFF IT IN [NENTS]
JSR GETBYT ; DON'T FORGET THE LSB!
STA NENTS+LO
LDA NENTS+HI
BPL SORTED
JMP UNSORTED ; VOCAB LIST IS UNSORTED, HANDLE DIFFERENTLY
SORTED:
LDA #0 ; FIND SIZE OF VAOCAB TBL
STA VOCEND ; TO LOCATE THE END OF IT
STA VOCEND+1
STA VOCEND+2
LDX ESIZE
FWL1:
CLC
LDA VOCEND ; (# OF ENTRIES) * (ENTRY SIZE)
ADC NENTS+LO
STA VOCEND
LDA VOCEND+1
ADC NENTS+HI
STA VOCEND+1
bcc FWL11
inc VOCEND+2
FWL11:
DEX
BNE FWL1
CLC
LDA VOCEND ; AND ADD LENGTH TO START OF TBL
ADC MPCL ; TO GET END OF TBL
STA VOCEND
LDA VOCEND+1
ADC MPCM
STA VOCEND+1
LDA VOCEND+2
ADC MPCH
STA VOCEND+2 ; TO SAVE FOR TESTING IF PAST END
LDA VOCEND ; SUBTRACT [ESIZE] SO THAT
SEC ; [VOCEND] POINTS TO REAL LAST ENTRY
SBC ESIZE
STA VOCEND
LDA VOCEND+1
SBC #0
STA VOCEND+1
;
; BEGIN THE SEARCH! [MPC] NOW POINTS TO 1ST ENTRY
;
LSR NENTS+HI ; 2 ALIGN # OF ENTRIES
ROR NENTS+LO ; 2 point to middle of table
FWCALC: ASL VWLEN+0 ; CALCULATE INITIAL OFFSET FOR SEARCH
ROL VWLEN+1
ROL VWLEN+2
LSR NENTS+HI
ROR NENTS+LO
BNE FWCALC
CLC ; ADD 1ST OFFSET INTO START OF VOCABULARL
LDA MPCL ; WHICH IS CURRENTLY IN MPC
ADC VWLEN+0
STA MPCL
LDA MPCM
ADC VWLEN+1
STA MPCM
LDA MPCH
ADC VWLEN+2
STA MPCH
SEC ; AVOID FENCE-POST BUG FOR
LDA MPCL ; EXACT-POWER-OF-2 TBL (DUNCAN)
SBC ESIZE
STA MPCL
BCS FWSAVE
LDA MPCM
SEC
SBC #1
STA MPCM
BCS FWSAVE
LDA MPCH
SBC #0
STA MPCH
FWSAVE:
lda DIDVTBL ; are we installing default table?
bpl FWLOOP ; already have?
ldx #2 ; save MPC
stx DIDVTBL ; show we have saved it
FWSVL:
lda MPC,X ; get it
sta VOCMPC,X ; save it
lda VOCEND,X ; save VOCEND too
sta VCESVE,X ; okay, we have
lda VWLEN,X ; and starting length
sta VWLSVE,X ; we have
dex ; count
bpl FWSVL ; okay, next one
FWLOOP:
lsr VWLEN+2 ; SET FOR NEXT OFFSET,
ror VWLEN+1 ; WHICH IS HALF THIS ONE
ror VWLEN+0
lda MPCL ; HOLD START ADDR, MPC WILL BE A MESS
sta VWCUR+0
lda MPCM
sta VWCUR+1
lda MPCH
sta VWCUR+2
jsr VLDMPC ; SET TO NEW PAGE
jsr GETBYT ; GET 1ST BYTE OF ENTRY
cmp OUT ; MATCH 1ST BYTE OF TARGET?
bcc WNEXT ; LESS
bne FWPREV ; GREATER
jsr GETBYT
cmp OUT+1 ; 2ND BYTE MATCHED?
bcc WNEXT
bne FWPREV ; NOPE
jsr GETBYT
cmp OUT+2 ; 3RD BYTE?
bcc WNEXT
bne FWPREV ; SORRY ...
jsr GETBYT
cmp OUT+3 ; 4TH BYTE
bcc WNEXT
BNE FWPREV
JSR GETBYT
CMP OUT+4 ; 5TH BYTE?
BCC WNEXT
BNE FWPREV ; SORRY ...
JSR GETBYT
CMP OUT+5 ; LAST BYTE?
BEQ FWSUCC ; FOUND IT!
BCS FWPREV ; ELSE BACK UP ...
WNEXT:
LDA VWCUR+0 ; TO MOVE UP, JUST ADD
CLC ; OFFSET FROM START OF THIS
ADC VWLEN+0 ; ENTRY
STA MPCL
LDA VWCUR+1
ADC VWLEN+1
BCS WNXT2 ; SAVES CODE (?)
STA MPCM
LDA #0
STA MPCH
WNXT0:
LDA MPCM ; GONE PAST END?
CMP VOCEND+1
BEQ WNXT1 ; MAYBE
BCS WNXT2 ; YES
BCC FWMORE ; NO
WNXT1:
LDA MPCL
CMP VOCEND
BCC FWMORE ; NO
BEQ FWMORE ; NO, EQUAL
WNXT2:
LDA VOCEND ; YES, SO POINT TO END OF TBL
STA MPCL
LDA VOCEND+1
STA MPCM
LDA VOCEND+2
STA MPCH
JMP FWMORE
FWPREV:
LDA VWCUR+0 ; TO MOVE DOWN, JUST SUBTRACT
SEC ; OFFSET FROM START OF THIS
SBC VWLEN+0 ; ENTRY
STA MPCL
LDA VWCUR+1
SBC VWLEN+1
STA MPCM
LDA VWCUR+2
SBC VWLEN+2
STA MPCH
FWMORE:
LDA VWLEN+2 ; IF OFFSET >GE< 1 WORD, CONTINUE
BNE FWM1
LDA VWLEN+1
BNE FWM1
LDA VWLEN+0
CMP ESIZE
BCC FWFAIL
FWM1:
JMP FWLOOP ; AND TRY AGAIN
FWSUCC: LDA VWCUR+0 ; ENTRY MATCHED! RETRIEVE START OF WORD
STA VALUE+LO
LDA VWCUR+1
STA VALUE+HI ; MUST BE 64K LIMIT AS ONLY
RTS ; WORD VALUE RETURNABLE
FWFAIL:
LDA #0 ; NOT FOUND
STA VALUE+LO
STA VALUE+HI
RTS ; THEN RETURN WITH [VALUE] = 0
;
; DO UNSORTED SEARCH ON VOCAB TBL IN MPC
;
UNSORTED:
LDA #$FF ; 2'S COMPLEMENT LENGTH
EOR NENTS+HI ; TO GET REAL LENGTH
STA NENTS+HI ; WAS NEGATIVE TO SIGNIFY
LDA #$FF ; UNSORTED VOCAB TBL
EOR NENTS+LO
STA NENTS+LO
INC NENTS+LO ; 2'S CMPL
BNE UNSRT0
INC NENTS+HI
UNSRT0:
LDA MPCL ; HOLD START ADDR, MPC WILL BE A MESS
STA VWCUR+0
LDA MPCM
STA VWCUR+1
LDA MPCH
STA VWCUR+2
JSR GETBYT ; GET 1ST BYTE OF ENTRY
CMP OUT ; MATCH 1ST BYTE OF TARGET?
BNE FNEXT ; LESS
JSR GETBYT
CMP OUT+1 ; 2ND BYTE MATCHED?
BNE FNEXT
JSR GETBYT
CMP OUT+2 ; 3RD BYTE?
BNE FNEXT
JSR GETBYT
CMP OUT+3 ; 4TH BYTE
BNE FNEXT
JSR GETBYT
CMP OUT+4 ; 5TH BYTE?
BNE FNEXT
JSR GETBYT
CMP OUT+5 ; LAST BYTE?
BEQ FWSUCC ; FOUND IT!
FNEXT: LDA VWCUR+LO ; TO MOVE UP, JUST ADD
CLC ; OFFSET FROM START OF THIS
ADC ESIZE ; ENTRY
STA MPCL
BCC FNEXT0
LDA VWCUR+HI ; PICK UP CARRY
ADC #0
STA MPCM
LDA #0
STA MPCH
JSR VLDMPC ; CROSSED PAGE SO RE-VALIDATE
FNEXT0: DEC NENTS+LO ; CHECKED ALL ENTRIES?
BNE UNSRT0
LDA NENTS+HI
BEQ FWFAIL ; GO INDICATE NO FIND
DEC NENTS+HI ; OR DO NEXT 256 ENTRIES
JMP UNSRT0
END