* LZW Compression algorithm
*
* Barry Boone  Project begins: 10/31/87
*
* Gut routines finished/working 11/2/87!!!
*
* proposed
* vdp buffer: 0->100 PAB's and arguments
*             >100->400 character set
*             >400->7C0 screen image table
*             >7C0->39C0 file buffers (room for 50 sectors)
* proposed
* CPU RAM: >2000->3FFF decompression stack/compression hash buffer & temporaries
*          >CE00->FFFF compress/decompress hash buffers/temp data buffers
*          >A8F0->CE00 program area (9488 bytes)
*          >A000->A8F0 pack/unpack filename buffer (127*18)+2 bytes
*                      and expendible program area
*
* Constants
*
 
CLEAR  EQU  256    clear code
EOF    EQU  257    EOF marker
FIRSTF EQU  258    first free code
MAXMAX EQU  4096   Max codes + 1
 
NBITS  EQU  4
MAXCOD EQU  5
CODE   EQU  3
NBITSB EQU  7
CODE2  EQU  2
STACK  EQU  9
INPTR  EQU  12
FRECOD EQU  6
BITOFF EQU  10
OUTPTR EQU  8
 
*
* Data Zones
*
 
       DORG >2000
FIRST  BSS  4096*2
STACKB EQU  $
       DORG >CDF8  8 bytes down for Geneve compatibility
NEXT   BSS  4096*2
CHAR   BSS  4096
 
TSTOUT BSS  >100
TSTIN  BSS  >100
 
*
* Program
*
 
       COPY "WDS1.S.LZW2/S"
 
H7C0   DATA >7C0
H21C0  DATA >20C0
H3BC0  DATA >39C0
INBUF  DATA >7C0
INBFEN DATA >20C0
OTBUF  DATA >20C0
OTBFEN DATA >39C0
H100   DATA >100
ENDM   TEXT 'END!'
 
NEWPRE DATA 0
PREFIX DATA 0
K      DATA 0
 
LCINIT DATA >83A0,$+2
       LI   INPTR,TSTIN
       LI   OUTPTR,TSTOUT
       CLR  BITOFF
       CLR  @CURWRD
       BL   @TBINIT
       LI   R0,CLEAR
       BL   @WRTCOD
       BL   @READCH
       SRL  R0,8
L4
L4A    MOV  R0,@PREFIX
       BL   @READCH
       MOVB R0,@K+1
       MOV  @PREFIX,R0
       BL   @LOOKUP
       MOV  R2,R2
       JEQ  L4
       BL   @ADDCOD
       MOV  R0,@NEWPRE
       MOV  @PREFIX,R0
       BL   @WRTCOD
       MOV  @K,R0
       C    @NEWPRE,MAXCOD
       JLT  L4
       CI   NBITS,12
       JLT  L14
       LI   R0,CLEAR
       BL   @WRTCOD
       BL   @TBINIT
       MOV  @K,R0
       JMP  L4
L14    INC  NBITS
       DEC  NBITSB
       SLA  MAXCOD,1
       JMP  L4
LCCLS2 DATA >83A0,LABORT
LCCLOS DATA >83A0,$+2
L17    MOV  @PREFIX,R0
       BL   @WRTCOD
L17X   LI   R0,EOF
       BL   @WRTCOD
       MOV  BITOFF,BITOFF
       JEQ  L17A
       SETO R0
       BL   @WRTCOD   <- write contents of CURWRD to buffer
L17A   CI   OUTPTR,TSTOUT
       JEQ  L17B      <- Empty, close it
       MOV  @OTBUF,R0
       LI   R1,TSTOUT
       LI   R2,>100
       BLWP @VMBW
       A    R2,@OTBUF
L17B   MOV  @OTBUF,@OTBFEN
       BLWP @BLKOUT
LABORT LI   R0,>10
       LI   R1,>0100
       BLWP @VSBW
       MOV  @H19,@>8356
       BL   @INSTAR
       BLWP @DSRLNK
       DATA 8
       JNE  RETWP
       ABS  @NOF9
       JEQ  RETWP
       MOV  R0,*R13
       LI   R14,ERROR
RETWP  RTWP
*
* Initialize LZW table
*
 
TBINIT LI   NBITS,9
       LI   NBITSB,7 (16-NBITS)
       LI   MAXCOD,512
       SETO R0
       LI   R1,FIRST
       LI   R3,NEXT
       LI   R2,256
TBI1   SETO *R1+
       SETO *R3+
       DEC  R2
       JNE  TBI1
       LI   FRECOD,FIRSTF
       RT
 
*
* Write a code
*
CURWRD DATA 0
 
WRTCOD MOV  R0,CODE
       CI   OUTPTR,TSTOUT+>100
       JNE  WRTCD9
       LI   OUTPTR,TSTOUT
       MOV  OUTPTR,R1
       LI   R2,>100
       MOV  @OTBUF,R0
       BLWP @VMBW
       A    R2,@OTBUF
       C    @OTBUF,@OTBFEN
       JNE  WRTCD9
       BLWP @BLKOUT
WRTCD9 CI   CODE,>FFFF
       JNE  WRTCDA
       MOV  @CURWRD,*OUTPTR+
       RT
WRTCDA MOV  NBITS,R0
       SRC  CODE,0         rotate code with left at left
       MOV  BITOFF,R0      0 bits used?
       JEQ  EASYWT         yes, this is easy
       MOV  CODE,CODE2     save a copy
       SRL  CODE,0
       SOC  CODE,@CURWRD
       C    BITOFF,NBITSB
       JL   EASY2
       JNE  WRTCD2
       CLR  BITOFF
       MOV  @CURWRD,*OUTPTR+
       CLR  @CURWRD
       JMP  WRTRT
WRTCD2 MOV  @CURWRD,*OUTPTR+
       A    NBITS,BITOFF
       ANDI BITOFF,>F
       MOV  NBITS,R0
       S    BITOFF,R0
       SLA  CODE2,0      rotate left, axe previously written bits
       MOV  CODE2,@CURWRD
       RT
 
EASYWT MOV  CODE,@CURWRD
EASY2  A    NBITS,BITOFF
WRTRT  RT
 
*
* Get input char
*
LZCMP  DATA >83A0,NOTMP2
 
READCH CI   INPTR,TSTIN+>100
       JNE  READC2
       A    @H100,@INBUF
       MOV  @INBUF,R0
       C    R0,@INBFEN
       JNE  NOTEMP
       RTWP
NOTMP2 MOV  @INBUF,R0
NOTEMP LI   INPTR,TSTIN
       MOV  INPTR,R1
       LI   R2,>100
       BLWP @VMBR
READC2 MOVB *INPTR+,R0
       RT
*
* Lookup a code
*
LCNT   DATA 0
HFFFF  DATA >FFFF
 
LOOKUP CLR  @LCNT
       MOV  R0,R1
       SLA  R1,1
       MOV  @FIRST(R1),R2
       CI   R2,>FFFF
       JEQ  GC4
       INC  @LCNT
GC2    CB   @K+1,@CHAR(R2)
       JNE  GC3
       MOV  R2,R0
       CLR  R2
       RT          R0 = code found
GC3    SLA  R2,1
       MOV  R2,R1
       MOV  @NEXT(R2),R2
       CI   R2,>FFFF
       JNE  GC2
GC4    SETO R2     code not found!
       RT
*
* Add a new code
*
ADDCOD MOV  FRECOD,R2
       MOV  @LCNT,@LCNT
       JEQ  AC1
       MOV  R2,@NEXT(R1)
       JMP  AC2
AC1    MOV  R2,@FIRST(R1)
AC2    CI   R2,MAXMAX
       JEQ  AC3
       MOV  R2,R1
       SLA  R1,1
       SETO @FIRST(R1)
       SETO @NEXT(R1)
       MOVB @K+1,@CHAR(R2)
       INC  FRECOD
AC3    MOV  R2,R0
       RT
 
*
* Decompressor
*
DIRCUR DATA >A000
PARSEF DATA 0
CURCOD DATA 0
OLDCOD DATA 0
INCODE DATA 0
HFF    DATA 255
FINCHR BYTE 0
 
LZDDNE MOV  @OTBUF,R0
       LI   R1,TSTOUT
       LI   R2,>100
       BLWP @VMBW
       A    R2,@OTBUF
       RTWP
 
LDINIT DATA >83A0,$+2
       MOV  @HA000,@DIRCUR
       LI   INPTR,TSTIN
       LI   OUTPTR,TSTOUT
       BL   @INITDC
       LI   STACK,STACKB
       CLR  CODE  \ IS THIS
       CLR  CODE2 / NECESSARY???
       CLR  BITOFF
       RTWP
 
LZPARS DATA >83A0,$+2
DL1    BL   @RDCODE
       CI   R0,EOF
       JNE  DL2
       B    @LZDDNE
DL2    CI   R0,CLEAR
       JNE  DL7
       BL   @INITDC
       BL   @RDCODE
 
       MOV  R0,@CURCOD
       MOV  R0,@OLDCOD
       SWPB R0
       MOVB R0,@K+1
       MOVB R0,@FINCHR
       BL   @WRTCHR
       JMP  DL1
DL7    MOV  R0,@CURCOD
       MOV  R0,@INCODE
       C    R0,FRECOD
       JL   DL11
       MOV  @OLDCOD,@CURCOD
       MOVB @K+1,R0
       DEC  STACK
       MOVB R0,*STACK
DL11   C    @CURCOD,@HFF
       JLE  DL15
       MOV  @CURCOD,R1
       MOVB @CHAR(R1),R0
       DEC  STACK
       MOVB R0,*STACK
       SLA  R1,1
       MOV  @NEXT(R1),@CURCOD
       JMP  DL11
DL15   MOV  @CURCOD,R0
       SLA  R0,8
       MOVB R0,@FINCHR
       MOVB R0,@K+1
       JMP  DL17A
DL17   MOVB *STACK+,R0
DL17A  BL   @WRTCHR
       CI   STACK,STACKB
       JNE  DL17
DL18   BL   @ADDDCD
       MOV  @INCODE,@OLDCOD
       C    FRECOD,MAXCOD
       JL   DL1
       CI   NBITS,12
       JEQ  DL1
       INC  NBITS
       DEC  NBITSB
       SLA  MAXCOD,1
DL23   JMP  DL1
*
* READ A CODE
*
RDCODE CI   INPTR,TSTIN+>100
       JNE  RDCDX
       LI   INPTR,TSTIN
       A    @H100,@INBUF
       C    @INBUF,@INBFEN
       JNE  NOPUL
       BLWP @GETFL2
NOPUL  MOV  @INBUF,R0
       MOV  INPTR,R1
       LI   R2,>100
       BLWP @VMBR
RDCDX  MOV  BITOFF,R0      0 bits used?
       JEQ  RDTATA
       MOV  @CURWRD,CODE
       C    BITOFF,NBITSB  more than 16-#bits used?
       JH   RDCD2
       SLA  CODE,0         this is easy
       MOV  NBITSB,R0
       SRL  CODE,0
       MOV  CODE,R0
       A    NBITS,BITOFF
       RT
RDCD2  SLA  CODE,0         a bit more complex
       MOV  NBITSB,R0
       SRL  CODE,0
       MOV  *INPTR+,CODE2
       MOV  CODE2,@CURWRD
       A    NBITS,BITOFF
       ANDI BITOFF,>F
       LI   R0,16
       S    BITOFF,R0
       SRL  CODE2,0
       SOC  CODE2,CODE
       MOV  CODE,R0
       RT
RDTATA MOV  *INPTR+,CODE   extremely easy
       A    NBITS,BITOFF
       MOV  CODE,@CURWRD
       MOV  NBITSB,R0
       SRL  CODE,0
       MOV  CODE,R0
       RT
*
* Init table
*
INITDC LI   NBITS,9
       LI   NBITSB,7
       LI   MAXCOD,512
       LI   FRECOD,FIRSTF
       RT
*
* Add code to table
*
ADDDCD MOV  FRECOD,R1
       MOVB @K+1,@CHAR(R1)
       SLA  R1,1
       MOV  @OLDCOD,@NEXT(R1)
       INC  FRECOD
       RT
*
*
*
GOTDIR DATA >83A0,WRTCH3
WRTCHR CI   OUTPTR,TSTOUT+>100
       JNE  WRTCH2
       MOVB R0,CODE
       LI   OUTPTR,TSTOUT
       ABS  @PARSEF
       JEQ  WRCHIT
       DEC  @PARSEF
       JNE  WRTCH2
       RTWP
WRCHIT ABS  @GETDIR
       JEQ  WRCHT2
       MOV  @DIRCUR,R0
       MOV  OUTPTR,R1
       LI   R2,>FC
       CI   R0,9*252+>A000
       JNE  WRCHT1
       LI   R2,18
WRCHT1 MOV  *R1+,*R0+
       DECT R2
       JNE  WRCHT1
       MOV  R0,@DIRCUR
       C    @>FC(OUTPTR),@ENDM
       JNE  WRTCH3
       CLR  @GETDIR
       CLR  *R0
       RTWP
WRCHT2 MOV  @OTBUF,R0
       MOV  OUTPTR,R1
       LI   R2,>100
       BLWP @VMBW
       A    R2,@OTBUF
       C    @OTBUF,@OTBFEN
       JNE  WRTCH3
       RTWP
WRTCH3 MOVB CODE,*OUTPTR+
       RT
WRTCH2 MOVB R0,*OUTPTR+
       RT
       COPY "WDS1.S.LZW3/S"
       END
