1 REM Ins{nd av: Kristoffer Eriksson <5357>    1988-04-02 03.09.59 (WRITE)
; Fil: KERMPACK.ASM
; Av:  Kristoffer Eriksson, "SKE" <5357>, 1987.
;
;-Ver--/-Datum----/-Sign-/-Kommentar----------------------------------
; 1.00 / 87-08-15 / SKE  / KERMPACK
;
; Packnings- och uppackningsrutiner till Bo Kullmars Kermit-program K.


;*  Packa upp buffert.
;*  In: DE pekare till inparametrar enligt:

UInbuff:    =  +0  ;W   Inbuffertens adress
UInbuffs:   =  +2  ;B   Inbuffertens slutposition eller l{ngd-1 (0-255)
UUtbuff:    =  +3  ;W   Utbuffertens adress
UUtbuffl:   =  +5  ;B   Utbuffertens l{ngd i antal byte (94-255)
Qctl:       =  +6  ;B   Tecken som markerar "tecken XOR 64"
Qbin:       =  +7  ;B   Tecken som markerar "tecken OR 128"
Rept:       =  +8  ;B   Tecken som markerar "tecken1-32 stycken tecken2"

;*  In- och utbuffertarnas f|rsta byte anger n{sta oanv{nda position i resp
;*  buffert, r{knat med sig sj{lva som position noll. De uppdateras med
;*  aktuella v{rden vid retur.
;*
;*  Inbuffertens position kan bli upp till 5 h|gre {n dess slutposition,
;*  vilket inneb{r att om slutpositionen {r 251 eller mer kan man f|rlora
;*  positionens mest signifikanta bittar, varvid v{rdet blir 256 f|r l}gt.
;*  Detta beror p} att positionen bara kontrolleras mot l{ngden en g}ng f|r
;*  varje avkodat tecken, och varje tecken kan vara kodat med upp till 5 byte.
;*  [ven om bufferten bara inneh}ller korrekta koder, slutar positionen 1
;*  steg f|rbi slutpositionen (det blir ju f|rsta oanv{nda position), och
;*  {r l{ngden 255 blir det 0 som lagras som position.
;*
;*  Rutinen avbryts n{r n{sta inposition blir st|rre {n slutpositionen
;*  (Inpos > Inslut), eller det blir 93 eller f{rre tecken kvar i utbufferten
;*  (Utpos >= Utl{ngd - 93). Det senare vilkoret {r f|r att garantera att
;*  en Rept-sekvens f}r plats vid uppackning. Den kan bli max 94 tecken.
;*
;*  Rutinen returnerar i HL aktuell inposition - inl{ngden. Observera att
;*  h{r f|rlorar man inte n}gra signifikanta bittar i positionen.
;*
;*  Qctl, Qbin och Rept kan vara noll f|r att markera att de inte anv{nds.


; DE = Aktuell adress i utbuff, D' = Position i utbuff, E' = L{ngd av utbuff,
; HL = Aktuell adress i inbuff, BC' = Position i inbuff,
; B = Repetitionsfaktor, C = OR-faktor.

; Inbuff-positionen ligger i ett dubbelregister eftersom den inte kontrolleras
; mot l{ngden vid varje |kning, och d{rf|r kan r}ka bli h|gre {n 255.

Unpbuff:    push   de
            pop    ix
            ld     l,(ix+UUtbuff)
            ld     h,(ix+UUtbuff+1)
            ld     c,(hl)
            ld     b,0
            add    hl,bc
            ex     de,hl              ; DE <- Aktuell adress i utbuffert.
            ld     a,c
            exx
            ld     d,a                ; D' <- Position i utbuffert.
            ld     e,(ix+UUtbuffl)    ; E' <- Utbuffertens l{ngd.
            exx

            ld     l,(ix+UInbuff)
            ld     h,(ix+UInbuff+1)
            ld     c,(hl)             ; (B = 0)
            add    hl,bc              ; HL <- Aktuell adress i inbuffert.
            push   bc
            exx
            pop    bc                 ; BC' <- Position i inbuffert.

ULoop:      ld     a,e
            sub    94
            cp     d                  ; J{mf|r  (E' - 94) med D'
            jr c   UEnd               ; Avsluta om Utpos > Utl{ngd - 94.
            ld     a,b
            and    a
            jr nz  UEnd               ; Inpos > 255, allts} Inpos > Inslut.
            ld     a,(ix+UInbuffs)
            cp     c
            jr c   UEnd               ; Avsluta om Inpos > Inslut.

UCont:      inc    bc                 ; \ka Inpos i BC'.
            exx
            ld     a,(hl)             ; L{s Inbuffert och |ka Inadress.
            inc    hl
            ld     bc,1 << 8 + 0      ; B <- Reptfaktor 1, C <- OR-faktor 0.
            and    a                  ; Ingen id` att j{mf|ra tecknet 0 med
            jr z   UStoreChar         ; specialtecknen, f|r {r de noll
                                      ; betyder det bara att de inte anv{nds.
UchkRept:   cp     (ix+Rept)
            jr nz  UchkQbin
            ld     a,(hl)             ; H{mta n{sta byte = Repetitionsfaktor.
            inc    hl
            sub    32
            cp     94
            jr c   Ux1                ; A <- max(A,94). S{kerhetskontroll,
            ld     a,94               ;            borde snarare meddela fel.
Ux1:        ld     b,a                ; B <- Repetitionsfaktor.
            ld     a,(hl)             ; A <- Repeterat tecken.
            inc    hl
            exx
            inc    bc                 ; \ka Inpos.
            inc    bc
            exx

UchkQbin:   cp     (ix+Qbin)
            jr nz  UchkQctl
            ld     c,128              ; OR-faktor f|r teckenkod.
            ld     a,(hl)             ; A <- P}verkat tecken.
            inc    hl
            exx
            inc    bc                 ; \ka Inpos.
            exx

UchkQctl:   cp     (ix+Qctl)
            jr nz  UStoreChar
            ld     a,(hl)             ; A <- P}verkat tecken.
            inc    hl
            exx
            inc    bc                 ; \ka Inpos.
            ld     l,a                ; L' <- A  (tempor{r lagring).
            and    127
            jr z   Ux2
            cp     (ix+Rept)          ; S}lla bort tecken som inte p}verkas.
            jr z   Ux3
            cp     (ix+Qbin)
            jr z   Ux3
            cp     (ix+Qctl)
            jr z   Ux3
Ux2:        ld     a,l
            xor    64
            jr     Ux4
Ux3:        ld     a,l
Ux4:        exx

UStoreChar: or     c                  ; OR-faktor
UStoreLoop: ld     (de),a             ; Lagra tecken i Utbuffert.
            inc    de
            exx
            inc    d                  ; \ka Utpos.
            exx
            djnz   UStoreLoop         ; Repetitionsfaktor.

            exx
            jr     ULoop

UEnd:       ld     l,(ix+UUtbuff)
            ld     h,(ix+UUtbuff+1)
            ld     (hl),d             ; (Utbuff) <- D' = Position i utbuffert.
            ld     l,(ix+UInbuff)
            ld     h,(ix+UInbuff+1)
            ld     (hl),c             ; (Inbuff) <- BC' = Position i inbuffert.
            ld     l,c
            ld     h,b
            ld     c,(ix+UInbuffs)
            xor    a                  ; Nolla carry och A.
            ld     b,a
            sbc    hl,bc              ; Returv{rde HL <- Inposition - Inl{ngd.
            ret



;*  Packa buffert.
;*  In: DE pekare till inparametrar enligt:

PUtbuff:    =  +0  ;W   Inbuffertens adress
PUtbuffl:   =  +2  ;B   Inbuffertens l{ngd i antal byte (10-255)
PInbuff:    =  +3  ;W   Utbuffertens adress
ReptPos:    =  +5  ;B   (Intern variabel, aktuell utpos vid start av rept.)
;Qctl:      =  +6  ;B   Tecken som markerar "tecken XOR 64"
;Qbin:      =  +7  ;B   Tecken som markerar "tecken OR 128"
;Rept:      =  +8  ;B   Tecken som markerar "tecken1-32 stycken tecken2"

;*  In- och utbuffertarnas f|rsta byte anger n{sta oanv{nda position i resp
;*  buffert, r{knat med sig sj{lva som position noll. Dessa uppdateras med
;*  aktuella v{rden f|re retur. Inbuffertens andra byte anger dess l{ngd
;*  (0-255) i antal byte inklusive position och l{ngd-bytes.
;*
;*  Rutinen avbryts n{r det }terst}r nio eller f{rre tecken i utbufferten
;*  (Utpos >= Utl{ngd - 9) eller inbuffert {r slut (Inpos >= Inl{ngd).
;*  Marginalen i utbufferten {r till f|r att kodningen av n{sta tecken
;*  garanterat ska f} plats. Fast den {r on|digt stor, eftersom kodningen
;*  av ett tecken kan bli max 5 tecken.
;*
;*  Returnerar i HL -1 om aktuell inposition {r lika med inl{ngden, annars 0.
;*
;*  Qctl, Qbin och Rept kan vara noll f|r att markera att de inte anv{nds.

; DE = Aktuell adress i utbuff, D' = Position i utbuff, E' = L{ngd av utbuff,
; HL = Aktuell adress i inbuff, B' = Position i inbuff, C' = L{ngd av inbuff,
; HL' = Adress i utbuff f|r ev repetionssekvens, B = Repetitionsr{knare.

Packbuff:   push   de
            pop    ix
            ld     l,(ix+PUtbuff)
            ld     h,(ix+PUtbuff+1)
            ld     c,(hl)             ; Position.
            ld     b,0
            add    hl,bc
            ex     de,hl              ; DE <- Aktuell adress i utbuffert.
            ld     a,c
            exx
            ld     d,a                ; D' <- Position i utbuffert.
            ld     e,(ix+PUtbuffl)    ; E' <- Utbuffertens l{ngd.
            exx

            ld     l,(ix+PInbuff)
            ld     h,(ix+PInbuff+1)
            ld     c,(hl)             ; Position.
            inc    hl
            ld     b,(hl)             ; L{ngd.
            dec    hl
            push   bc
            ld     b,0
            add    hl,bc              ; HL <- Aktuell adress i inbuffert.
            exx
            pop    hl
            ld     b,l                ; B' <- Position i inbufferten.
            ld     c,h                ; C' <- Inbuffertens l{ngd.
                                      ; Repetitionsr{knaren B {r nu noll.
PLoop:      ld     a,e
            sub    10
            cp     d                  ; J{mf|r  (E' - 10) med D'
            jr c   PEnd               ; Avsluta om Utpos > Utl{ngd - 10.
            ld     a,c
            cp     b                  ; J{mf|r C' med B'.
            jr z   PEnd
            jr nc  PCont              ; Avsluta om Inpos >= Inl{ngd.

PEnd:       ld     l,(ix+PUtbuff)
            ld     h,(ix+PUtbuff+1)
            ld     (hl),d             ; (Utbuff) <- D' = Position i utbuffert.
            ld     l,(ix+PInbuff)
            ld     h,(ix+PInbuff+1)
            ld     (hl),b             ; (Inbuff) <- B' = Position i inbuffert.
            inc    hl
            ld     (hl),c             ; (Inbuff+1) <- C' = L{ngd.
            ld     a,b
            cp     c
            ld     hl,0
            ret nz
            dec    hl                 ; Returv{rde HL <- Inpos = Inl{ngd.
            ret

PCont:      inc    b                  ; \ka Inpos i B' redan nu.
            exx
            ld     a,(ix+Rept)
            and    a
            jr z   PchkQbin           ; Ingen repetitionskomprimering.

            ld     a,(hl)             ; Aktuellt tecken.
            dec    hl
            cp     (hl)               ; J{mf|r tecknet med f|rra tecknet.
            inc    hl
            jr nz  PInitRept
            inc    b                  ; \ka repetitionsr{knaren.
            ld     a,b
            cp     5
            jr c   Px1                ; Hoppa om inte B > 4.
            push   bc
            ld     a,(ix+Rept)
            exx
            ld     (hl),a             ; Anv{nd den sparade utpekaren och
            inc    hl                 ; {ndra i utbufferten till repetitions-
            pop    af   ; A <- B = Rept.r{kn.                   sekvens med
            add    32                 ; <Rept><Antal+32>, samt }terst{ll
            ld     (hl),a             ; utadressen och utpositionen till
            push   hl                 ; slutet av denna sekvens.
            dec    hl
            ld     d,(ix+ReptPos)
            inc    d
            inc    d
            exx
            pop    de
            inc    de
            cp     94+32              ; J{mf|r B med 94. (A {r nu B+32)
            jr nz  PchkQbin
            ld     b,0                ; Avbryt repeteringsbehandling efter
            jr     PchkQbin           ; maxantalet 94 upprepningar.

PLoop2:     jr     PLoop              ; (F|r l}ngt f|r ett enda jr-hopp.)

Px1:        dec    a                  ; Om f|rra v{rdet p} rept-r{knaren var
            jr nz  PchkQbin           ; noll, ska den startas om.

PInitRept:  ld     b,1                ; Tecknet {r inte likt f|reg}ende.
            push   de                 ; Starta om repetitionsr{knare och
            exx                       ; spara utadress och utposition.
            pop    hl
            ld     (ix+ReptPos),d
            exx

PchkQbin:   ld     a,(hl)             ; Aktuellt tecken.
            inc    hl                 ; Inbuffertadressen|kas f|rst nu.
            ld     c,a
            cp     128
            jr c   PchkQctl           ; Behandla tecken >= 128 med Qbin
            ld     a,(ix+Qbin)
            and    a
            jr z   PchkQctl           ; Avst{ngt.
            ld     (de),a             ; Lagra <Qbin>.
            inc    de
            exx
            inc    d                  ; \ka Utpos.
            exx
            ld     a,c
            and    127                ; Nu slipper vi h|ga bitten.
            ld     c,a

PchkQctl:   ld     a,(ix+Qctl)
            and    a
            jr z   PStoreChar         ; Ingen hantering av ctrl-tecken.
            ld     a,c
            and    127
            cp     127                ; Tecken < 32 och = 127 kod{ndras.
            jr z   PCtrl
            cp     32
            jr c   PCtrl
            cp     (ix+Qctl)          ; Dessa tecken f|reg}as av Qctl men
            jr z   PQctl              ; kod{ndras inte.
            cp     (ix+Qbin)
            jr z   PQctl
            cp     (ix+Rept)
            jr z   PQctl
            jr     PStoreChar
PCtrl:      ld     a,c
            xor    64
            ld     c,a
PQctl:      ld     a,(ix+Qctl)
            ld     (de),a             ; Lagra <Qctl>.
            inc    de
            exx
            inc    d                  ; \ka Utpos.
            exx
PStoreChar: ld     a,c
            ld     (de),a             ; Lagra tecknet.
            inc    de
            exx
            inc    d                  ; \ka Utpos.

            jr     PLoop2
