home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
beehive
/
compress
/
ql40.arc
/
UNC.LIB
< prev
next >
Wrap
Text File
|
1991-08-11
|
21KB
|
978 lines
;------------------------------------------------------------------------------
; unc.asm
; xlate2 translation of unc.mac to z80mr & z1 format
; orig 09-09-87
; rev 11-30-87
; v2.5 02-14-88
;
; QL v2.5 changes: MEMTOP (top of memory) is retreived from previously
; defined variable "BDOSBASE" rather than reading directly from 0006H.
; Also, all data has been moved to QL's DSEG data area, where it should be.
;
; unc & uncrel uncrunch module'
; original version by steven greenberg. revised by c.b. falconer
; QL specific version re-revised by steven greenberg
;
; copyright (c) 86/11/24 by
; steven greenberg 201-670-8724
; and c.b. falconer 203-281-1438.
; may be reproduced for non-profit use only.
; error codes (0 for no error)
VERSION EQU 1 ; Newer uncrunch version required
ISNOTCR EQU 2 ; File is not crunched
FOULED EQU 3 ; File is fouled
MEMORY EQU 4 ; Memory or stack overflow
OBSLETE EQU 5 ; "Older uncrunch version required"
; move right n columns, same row
IF M80
RIGHT MACRO N ; Macro syntax for m80 / z80asm
LD A,H
ADD A,&N*10H
LD H,A
ENDM
ELSE
RIGHT MACRO #N ; Macro syntax for z80mr / z1
LD A,H
ADD A,#N*10H
LD H,A
ENDM ; RIGHT
ENDIF ; M80
SIGREV EQU 20H ; Significant revision level
IMPRED EQU 07FFFH ; Impossible pred, can never be matched
NOPRED EQU 0FFFFH ; No predecessor code
VACANT EQU 080H ; Value for a vacant entry
GUARD EQU 07FH ; Protect table entry from use
ESCAPE EQU 090H ; Repeated byte encoding
; for version 2 algorithm
INITW EQU 9 ; Initial cell width
MAXWIDE EQU 12 ; Max width of cells
TBLSIZE EQU 5003
; version 2 special codes
EOFCOD EQU 0100H
RSTCOD EQU 0101H ; Adaptive reset signal
NULCOD EQU 0102H ; Nop
SPRCOD EQU 0103H ; Spare for future use
; Following are lo-bytes of above, expressed in a manner generically accept-
; able to a variety of assemblers. Eqiv to "LO(x)" or "x AND 0FFH", etc.
LO_EOFCOD EQU EOFCOD-256*(EOFCOD/256)
LO_RSTCOD EQU RSTCOD-256*(RSTCOD/256)
LO_NULCOD EQU NULCOD-256*(NULCOD/256)
LO_SPRCOD EQU SPRCOD-256*(SPRCOD/256)
N01 EQU 1
N02 EQU 2
N08 EQU 8
N0F EQU 000FH
N10 EQU 0010H
N14 EQU 0014H
N20 EQU 0020H
N28 EQU 0028H
N30 EQU 0030H
NDF EQU 00DFH
NFE EQU 00FEH
NFF EQU 00FFH
T0FFF EQU 0FFFH
T1000 EQU 1000H
T2000 EQU 2000H
T2800 EQU 2800H
T4000 EQU 4000H
; Various error exits
XNOTCR: LD A,ISNOTCR
JR ERROR
XSTKOV: LD A,MEMORY
JR ERROR
XBADF: LD A,FOULED
JR ERROR
XNEWV: LD A,VERSION
JR ERROR
TOOLD: LD A,OBSLETE
ERROR: SCF
EXIT: LD HL,(SPSAVE)
LD SP,HL
RET
EXITOK: XOR A
JR EXIT
; entry here if application has already read the header, and
; validated the initial id bytes. this avoids rewinding the file.
; the next input byte must be the revision level.
UNC: CALL MALLOC ; Returns hl = new stack
JR C,XSTKOV
LD SP,HL ; Ok, now switch stacks
JR UNCRB
;
; set up memory allocation. base pointer in hl
; carry if insufficient space (stack overflow incipient)
MALLOC: EX DE,HL
LD HL,2 ; Allow for call malloc
ADD HL,SP
LD (SPSAVE),HL ; Save return from main
LD HL,255
ADD HL,DE ; Round up to page boundary
LD L,0
LD (@TABLE),HL
LD A,N30 ; '0'
ADD A,H
LD H,A
LD (XLATBL),HL ; For version 2 system
LD A,N28 ; '('
ADD A,H
LD H,A
PUSH HL
CPL
LD H,A ; 4 less bytes than z80 coding
INC H ; L was zero
LD (STKLIM),HL
POP HL
LD A,H
ADD A,N08 ; Proposed stack page
LD H,A ; Check stack page a suitable
LD L,0
EX DE,HL ; Check memory against memtop
LD HL,(BDOSBASE) ; (was MEMTOP)
LD A,H ; @table thru newstack
SUB D ; (can exit because stack saved)
RET C ; Not enough system memory
LD A,(SPSAVE+1)
LD HL,(@TABLE)
CP H
JR C,STKCK1 ; Input stack below table, ok
LD H,A ; Input stack page
LD A,D ; New stack page
CP H
STKCK1: CCF
EX DE,HL
RET ; With carry if stack overflow
UNCRB: CALL INIT ; Variables etc
CALL GETBYT ; Ignore revision level
CALL GETBYT ; Significant revision level
PUSH AF
CALL GETBYT ; Ignore checksum flag
CALL GETBYT ; And spare byte
POP AF
CP SIGREV+1
JR NC,XNEWV ; Need newer version
CP SIGREV
JR NC,UNCRC ; Ver 20 uncrunching
; ver 10 uncrunching
IF VER1 ;
CALL UNC1I
JR UNC1
ELSE ; Not ver1
JR TOOLD ; (ie ver1 types not supported, rtn w/ error)
ENDIF ; Not ver1
UNCRC: CALL UNC2I ; Ver. 2, initialize tables
JR UNC2
IF VER1
; version 10 uncrunching initialize. returns de := nopred
UNC1I: LD HL,T0FFF
LD (TROOM),HL
CALL CLRMEM
LD A,12
LD (WIDTH),A ; Ver 10 tokens are 12 bits
XOR A
LD (KIND),A ; 0 for version 10 operation
ENDIF ; Ver1
; initialize atomic entries. set de := nopred
ATOMS: XOR A
LD HL,NOPRED
ATOMS1: PUSH AF
PUSH HL
CALL ENTERX ; Make entry { hl, a }
POP HL
POP AF
INC A
JR NZ,ATOMS1
EX DE,HL ; De := nopred
RET
; version 20 setup. returns de := nopred
UNC2I: CALL CLRTBL
LD A,1
LD (KIND),A ; Version 20 signal
LD A,N20 ; Force non-bumpable atomic entries
LD (FFFLAG),A
CALL ATOMS ; Init atomic entries
LD B,LO_SPRCOD+1 ;
UNC2I2: PUSH BC
LD HL,IMPRED ; Impossible pred
XOR A
CALL ENTERX ; Reserve eof thru sprcod
POP BC ; Unmatchable and unbumpable
DEC B
JR NZ,UNC2I2 ;
XOR A
LD (FFFLAG),A ; Reset flag
LD H,A
LD L,A
LD (TROOM),HL ; Re-used as re-assignment counter
LD DE,NOPRED
RET
IF VER1
; ver 10 uncrunching loop
UNC1:
EX DE,HL
LD (LASTPR),HL
CALL GETOK ; New 12 bit code to de
JP C,EXITOK ; Eof or eof node
PUSH DE
CALL DECODE
LD HL,ENTFLG
LD A,(HL)
LD (HL),0
OR A
CALL Z,ENTLAST ; Make new table entry if not done
POP DE
LD A,(FULFLG)
OR A
JR Z,UNC1 ; Continue
; speed up when table full, no more entries need be made/checked
UNC1B: CALL GETOK
JP C,EXITOK
PUSH DE
CALL DECODE
POP DE
JR UNC1B ; Continue
ENDIF ; Ver1
; version 2 uncrunching
UNC2: EX DE,HL
LD (LASTPR),HL
CALL GETKN
JR C,UNC2C ; Eof or reset etc.
PUSH DE
CALL DECODE
LD HL,ENTFLG
LD A,(HL)
LD (HL),0
OR A
CALL Z,ENTLAST ; If not made, then make entry
POP DE
LD A,(FULFLG)
OR A
JR Z,UNC2 ; Adaptive system reset
CP NFE ; When this becomes 0ffh all done. first
JR NZ,UNC2B ; It becomes 0feh, when one more loop
INC A ; Is required, and set it to 0ffh.
LD (FULFLG),A
JR UNC2 ; Do the extra loop
; table is full. no new entries needed
UNC2B: EX DE,HL
LD (LASTPR),HL
CALL GETKN
JR C,UNC2C ; Eof etc
PUSH DE
CALL DECODE
LD HL,(LASTPR)
LD A,(CHAR)
CALL RECOD ; Check for code re-assignment
POP DE
JR UNC2B
; here for input codes in range 100h..103h (eof..sprcod).
UNC2C: LD A,E ; Special code, (eof or adaptive reset)
CP LO_EOFCOD
JP Z,EXITOK ; Done
CP LO_RSTCOD
JP NZ,XNOTCR
; adaptive reset
XOR A
LD H,A
LD L,A
LD (CODES),HL ; Init current code to 0
LD (FULFLG),A ; Clear
CALL UNC2I
LD A,INITW
LD (WIDTH),A ; Reset input code width
LD A,N02
LD (TRGMSK),A
LD A,N01
LD (ENTFLG),A ; 1st entry always a special case
JR UNC2
; var b : byte; (* global *)
;
; procedure decode(x : index);
;
; var ix : index; (* index is a record *)
;
; begin (* decode *)
; ix := lookup(x);
; if ix.pred = nil then enter(x, b);
; if ix.pred = nopred then b := ix.byte
; else decode(ix.pred);
; send(ix.byte);
; end; (* decode *)
;
; the char associated with the bottomost recursion level is saved in
; "char" and is used later to make the next table entry.
;
; the code at "ugly" has to do with a peculiar string sequence where
; the encode "knows" about a string before the decoder so the decoder
; has to make an emergency entry. fortunately there is enough inform-
; ation available to do this. it has been shown that this case is
; unique and that the assumptions are valid. to understand the lzw
; algorithm the "ugly" code may be ignored.
;
; universal decoder
; a,f,b,c,d,e,h,l
DECODE: LD A,(KIND)
OR A
JR Z,DCDA ; Version 1, no setup needed
PUSH DE
EX DE,HL
LD A,(@TABLE+1)
ADD A,H
LD H,A ; Convert code to table adr.
LD A,(HL)
OR 020H ; Mark referenced (not bumpable)
LD (HL),A
POP DE
; decode/output the index in de. recursive
; a,f,b,c,d,e,h,l
DCDA: LD HL,(STKLIM)
ADD HL,SP
JP NC,XSTKOV ; Stack overflow
LD A,(@TABLE+1) ; Convert index de to address hl
ADD A,D
LD H,A
LD L,E
LD A,(HL)
AND NDF ; (for 2 only)
CP VACANT
JR NZ,DCDA1 ; Not vacant, normal case
; the "ugly" exception. term due to k. williams
LD A,N01
LD (ENTFLG),A
PUSH HL
LD A,N20 ; (for 2 only)
LD (FFFLAG),A
CALL ENTLAST ; Make emergency entry
XOR A
LD (FFFLAG),A ; (for 2 only)
POP HL
LD A,(HL)
CP VACANT
JP Z,XBADF ; If vacant file is invalid
DCDA1: LD D,(HL) ; Get "pred" (hi)
RIGHT 1 ; Move to "pred" (lo)
LD E,(HL) ; Get it. if msb of hi byte is set value
LD A,D ; Must be ff (nopred) because not 80h
AND 0DFH ; ~20h
JP M,DECODX ; Nopred, terminate recursion
LD D,A ; (for 2, remove any accessed flag)
PUSH HL
CALL DCDA ; Recursive
POP HL
RIGHT 1 ; Move ahead to "suffix" byte
LD A,(HL)
JR SEND ; Output suffix byte & exit
; exit from decoding recursion. unloads all the stacked items.
DECODX: RIGHT 1 ; Move ahead to "suffix" byte
LD A,(HL) ; Get & save as 1st char of decoded
LD (CHAR),A ; String. used later to make a new
; Table entry. send & exit
; send char with repeat expansion etc.
; a,f,b,c,h,l
SEND: LD C,A ; Output char
LD HL,(OUTFLG)
INC H
DEC H
JR NZ,SEND2 ; Repeat flag set
CP ESCAPE
JR Z,SEND1 ; Escape char, set flag
LD L,A ; Save char for possible repeat coming
DEC H ; Cancel coming inr, not repeat
CALL OUT
SEND1: INC H ; Set repeat flag
LD (OUTFLG),HL
RET
SEND2: LD H,0 ; Clear repeat flag
LD (OUTFLG),HL ; Save result (with l = repeat char)
OR A
JR Z,SEND4 ; Escape 0 represents escape
DEC A
RET Z ; Take care of repeat = 1
LD H,A ; Set repeat count
LD A,L ; Repeaat char
SEND3: CALL OUT
DEC H
JR NZ,SEND3
RET
SEND4: LD A,ESCAPE
JP OUT
; enter lastpr/char into table
; a,f,b,c,d,e,h,l
ENTLAST:
LD HL,(LASTPR)
LD A,(CHAR)
; enter { <pred>, <suffix> } into table, passed in {hl, a} regs.
; a,f,b,c,d,e,h,l
ENTERX:
LD B,A
LD A,(KIND)
OR A
LD A,B
JR NZ,ENT2X ; Version 2 decoding
IF VER1
; else ... version 1 decoding
; enter { <pred>, <suffix> } into table, passed in {hl, a} regs.
; a,f,b,c,d,e,h,l
ENT1X: PUSH AF
PUSH HL
CALL MIDSQ ; Hash index into al
LD H,A
LD A,(@TABLE+1) ; Page address
ADD A,H
LD H,A ; Into address
POP DE ; Pred
POP AF ; Suffix
LD C,A
ENT1X1: LD B,H ; Check for match
LD A,(HL)
CP VACANT
JR Z,ENT1X3 ; Entry does not exist, make it
RIGHT 3 ; Move to link column
LD A,(HL) ; Link(hi)
OR A
JR Z,ENT1X2 ; No link
LD B,A ; Save
RIGHT 1 ; Move to link(lo) field
LD L,(HL)
LD H,B ; Hl := link address
JR ENT1X1 ; And repeat
ENT1X2: LD H,B ; Restore h to left hand column
CALL FFREE ; Find new spot and link in. returns
; HL pointing to new entry.
ENT1X3: CALL LINK ; Make the entry. pred(hi)
RIGHT 1
LD (HL),C ; Suffix
LD HL,(TROOM)
DEC HL
LD (TROOM),HL
LD A,H
OR L
RET NZ ; Not full
DEC A
LD (FULFLG),A ; Else set full flag
RET
ENDIF ; Ver1
; link entry de at location hl^
LINK: LD (HL),D ; High
RIGHT 1
LD (HL),E ; Lo
RET
; version 2 table entry
ENT2X: PUSH AF
PUSH HL
CALL TBLADR ; To physical loc only, affects nothing
POP DE ; And check width etc??
LD HL,(CODES)
LD A,(@TABLE+1)
ADD A,H
LD H,A ; Convert to address
; entry is made here, but normally flagged as "unreferenced" (until
; received by decode). until then entries are "bumpable". if ffflag
; is 020h the reference is flagged now, to protect atomic entries and
; wswsw string emergency entries (from decode, despite not received)
LD A,(FFFLAG)
OR D ; May set "referenced" bit
LD (HL),A ; Pred(hi)
RIGHT 1
LD (HL),E ; Pred(lo)
RIGHT 1
POP AF
LD (HL),A ; Suffix
LD HL,(CODES) ; Advance entry counter
INC HL
LD (CODES),HL
INC HL ; Allow for crunch/uncrunch skew delay
LD A,(TRGMSK) ; See if new code length needed
CP H
RET NZ
RLA ; Carry was clear. change to new length
LD (TRGMSK),A ; New target mask
LD A,(WIDTH)
INC A
CP MAXWIDE+1
JR Z,ENT2X1 ; Mark table full
LD (WIDTH),A ; Advance to new width
RET
ENT2X1: LD A,NFE ; Mark table full, at max width
LD (FULFLG),A
RET
CLRMEM: LD HL,(@TABLE)
LD (HL),GUARD ; Disallow entry #0
INC HL ; (used, but unmatchable)
LD E,VACANT
LD BC,T1000 ; Mark entries vacant
CALL FILL
LD BC,T4000
; fill hl^ for bc with zero
FILLZ: LD E,0
; fill hl^ for bc with e
FILL: LD (HL),E
INC HL
DEC BC
LD A,B
OR C
JR NZ,FILL
RET
IF VER1
; find a free entry in the event of a hash collision. algorithm is to
; first add 101 (decimal) to the current (end-of-chain) entry. if
; that entry is not free keep adding 1. when a free entry is found
; the link pointer of the original entry is set to the found entry.
; called with adr of an entry in hl, returns hl = adr of new entry.
; a,f,h,l
FFREE: PUSH BC
PUSH DE
PUSH HL ; Save pointer to old entry for update
LD A,L
ADD A,101 ; Relatively prime to table size
LD L,A
JR NC,FFREE1 ; No carry, thus no wrap
INC H
LD A,(@TABLE+1)
ADD A,N10
CP H
JR NZ,FFREE1 ; No wrap-around
LD A,(@TABLE+1) ; Set to table bottom
LD H,A
FFREE1: LD A,(@TABLE+1) ; Compute # of remaining entries,
ADD A,N0F ; Counting up (last entry + 1
SUB H ; - current entry)
LD B,A
LD A,L ; As far as the low byte is concerned
CPL ; We know we are subtracting from 0.
INC A
JR NZ,FFREE2
INC B
FFREE2: LD C,A ; Result in bc
LD D,H ; Keep copy
LD E,L
CALL CMPM ; Search for empty entry
JR NC,FFREE3 ; Found vacant entry
LD HL,(@TABLE) ; Else wrap to start of table
LD A,(@TABLE+1)
LD B,A
LD A,D
SUB B ; (adr to index# conversion)
LD B,A
LD C,E ; Target value
CALL CMPM ; Continue search
JP C,XNOTCR ; Not found. should not occur
FFREE3: EX DE,HL
POP HL ; Original pointer to link
RIGHT 3 ; Move to link(hi) field
CALL LINK ; Link to new entry
EX DE,HL ; Returned in hl
POP DE
POP BC
RET
; search for vacant entry from hl^ up. carry if not found
; carry clear if found when hl points to found entry
; a,f,b,c,h,l
CMPM: LD A,(HL)
CP VACANT
RET Z
INC HL
DEC BC
LD A,B
OR C
JR NZ,CMPM
SCF ; Signal not found
RET
;..............................................................................
;
; return the mid-square of number of "pred" + "suffix" (actually the
; mid-square of # or 0800h). entry a = suffix, hl = pred. returns
; result in a|l (not hl), ready to add a table offset.
;
; mid-square means the midddle n bits of the square of an n-bit num.
; here n is 12. results accumulate in a 16 bit register, with
; extraneous information overflowing off both ends of the register.
;
; hash via mid-square of 12 bit input or'd with 800h.
; input is hl + a. output in al registers.
; note anomalous results for input out of range. special handling
; since really needs to operate on 13 bit words to match the original.
; the algorithm is due to robert a. freed. this runs on 8080s, takes
; the identical code space as mr. freeds z80 implementation, and has
; miniscule or no average performance penalty. by c.b. falconer.
;
; entry: a = suffix; hl = pred. exit al = midsq
; a,f,b,c,d,e,h,l
MIDSQ: ADD A,L ; Hl := hl + a
LD L,A ; Max result fffh+0ffh=010feh
ADC A,H ; (normal, except special case)
SUB L
LD D,A ; Save for special test
OR 8 ; Or with 800h. max 18feh
; following should be 0fh, but modified to agree with original
AND 1FH ; Mask to 13 bits. max 1fffh
RRA
LD H,A ; Max 7ffh
LD B,A ; M := bc := hl := input div 2
LD A,L ; Using n*n = 4 * (m * m) (n even)
RRA ; Or 4 * m * (m+1)+1 (n odd)
LD L,A ; And any final "1" gets discarded.
LD C,A
JR NC,MIDSQ1 ; Even, use m
INC HL ; Hl := m+1
; special case test, input = 0ffffh+0 must hash to 800h
; from initial 1 byte string prefix = nopred, suffix = 0.
LD A,D
OR A ; Did input have high bit?
LD A,H ; Holds 800h in this case
RRA ; Because using 13, not 12 bits
RET M ; Yes, return 0800h
; multiplication. hl := bc * hl (12 lo bits of hl only)
MIDSQ1: LD A,12 ; Bits in m * m' multiplication
ADD HL,HL
ADD HL,HL ; Reposition multiplier
ADD HL,HL
ADD HL,HL ; Using 12, not 16 bit multiply
EX DE,HL ; Multiplier to de
LD L,0 ; Clear necessary portion
MIDSQ2: ADD HL,HL ; Left shift accum. main loop.
EX DE,HL ; Discarding overflow past 16 bits
ADD HL,HL ; Left shift multiplier
EX DE,HL
JR NC,MIDSQ3 ; Multiplier bit = 0
ADD HL,BC ; =1, add in
MIDSQ3: DEC A
JR NZ,MIDSQ2 ; More bits
ADD HL,HL ; Reposition 12 bit result
RLA
ADD HL,HL ; Shift 4 bits to a
RLA
ADD HL,HL
RLA
ADD HL,HL
RLA
LD L,H ; Move down low 8 bits of result
AND 0FH ; Mask off. result in a & l
RET
ENDIF ; Ver1
; get input token, variable width. check nops etc
; carry for eof
; a,f,b,c,d,e
GETKN: CALL GETOK
LD A,D
DEC A
AND A ; Clear any carry
RET NZ ; Code not 01xx
LD A,E
CP LO_SPRCOD+1 ; Codes used
RET NC
CP LO_NULCOD ; Lo byte of "nulcod"
JR NC,GETKN ; Ignore null and spare codes, nop
RET ; Must be rstcod or eof, cy set
; get input token, variable width
; a,f,b,c,d,e
GETOK: LD DE,0
LD A,(WIDTH)
LD B,A
LD A,(LFTOVR)
LD C,A
GETOK1: LD A,C
ADD A,A ; Bit to cy, flags on remainder
CALL Z,MOREIN ; Lftovr was empty, get more
LD C,A ; And keep the remainder
LD A,E
RLA
LD E,A ; Shift into de
LD A,D
RLA
LD D,A
DEC B
JR NZ,GETOK1 ; More bits to unpack
LD A,C
LD (LFTOVR),A ; Save any remainder
LD A,D
OR E
RET NZ
SCF ; Carry for 0 value (eof)
RET
; subroutine for getok. next input byte positioned etc.
MOREIN: CALL GETBYT
SCF
RLA ; Bit to carry, set end marker
RET
; clear version 2 tables ??
CLRTBL: LD HL,(@TABLE) ; 4096 rows * 3 cols, main table
LD BC,T1000
LD E,VACANT
CALL FILL
LD BC,T2000
CALL FILLZ
LD HL,(XLATBL) ; Physical to logical translation table
LD (HL),GUARD
INC HL
LD BC,T2800 ; 1400h * 2 entries
LD E,VACANT
JP FILL
; figure out what physical loc'n the cruncher put its entry at by
; reproducing the hashing process. insert the entry # into the
; corresponding physical location in xlatbl.
TBLADR: LD B,A
CALL HASH ; To hl
TBLAD1: LD C,H
LD A,(HL)
CP VACANT
JR Z,TBLAD2 ; No entry, make it
CALL REHASH
JR TBLAD1
TBLAD2: EX DE,HL
LD HL,(CODES) ; Logical entry #
EX DE,HL
LD (HL),D
LD A,H ; Right 1 for this table
ADD A,N14
LD H,A
LD (HL),E
LD A,(XLATBL+1)
LD H,A
LD A,C
SUB H
LD H,A
RET
; rehash
REHASH: EX DE,HL
LD HL,(NEXTX) ; Displacement from hash
ADD HL,DE
LD A,(XLATBL+1) ; Page address
LD D,A
LD A,H
CP D
RET NC
LD DE,TBLSIZE
ADD HL,DE
RET
; check for code reassignment?
RECOD: LD B,A
LD A,NFF
LD (AVAIL+1),A
LD A,B
CALL HASH ; To hl
RECOD1: LD C,H
LD A,(HL)
CP VACANT
JR Z,RECOD4 ; End chain. try make entry (elsewhere)
LD A,(AVAIL+1)
CP NFF
JR NZ,RECOD3 ; Have an entry
PUSH HL ; Physical table pointer
LD D,(HL) ; Entry # (hi)
LD A,H
ADD A,N14 ; Right 1
LD H,A
LD L,(HL) ; Entry # (lo)
LD A,(@TABLE+1) ; Convert to addres
ADD A,D
LD H,A
LD A,(HL)
AND 020H
JR NZ,RECOD2 ; Not bumpable, try next
LD (AVAIL),HL ; Save resulting entry # for later use
RECOD2: POP HL
RECOD3: CALL REHASH ; To next link in chain
JR RECOD1
RECOD4: LD HL,(AVAIL) ; Reassign the entry pointed to by avail
LD A,H ; (if any), redefine "last pred entrd"
CP NFF ; And "last suffix" vars.
RET Z ; None available
EX DE,HL
LD HL,(TROOM)
INC HL
LD (TROOM),HL ; Keep track of codes re-assigned
LD HL,(LASTPR)
EX DE,HL
LD A,(CHAR)
LD B,A
CALL LINK
RIGHT 1
LD (HL),B
HASH: LD E,L
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL
XOR H
LD L,A
LD A,E
AND N0F
LD H,A
LD A,(XLATBL+1) ; Add in table offset
ADD A,H
LD H,A
INC HL ; Eliminate 0 case
PUSH HL
EX DE,HL
LD HL,(TBLTOP)
ADD HL,DE ; Make index dependant, not address
LD (NEXTX),HL ; Rehash value, -ve no.
POP HL
RET
; initialize variables, pointers, limits
INIT: LD HL,(XLATBL) ; Hi byte is 0
LD DE,-TBLSIZE
LD A,E
SUB L
LD L,A
LD A,D
SBC A,H
LD H,A
LD (TBLTOP),HL ; -(xlatbl + tblsize)
LD HL,ITABLE
LD DE,FULFLG ; Copy the "shadow"
LD BC,ITBSIZE
LDIR
RET
; initializing table ("shadow") for data area
ITABLE: DEFB 0
DEFW NOPRED
DEFB 1
DEFW 0
DEFB VACANT
DEFB INITW ; Initial cell width
DEFB 2
DEFW 0
ITBSIZE EQU $-ITABLE
; end of UNC.ASM include file
;
;------------------------------------------------------------------------------