home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / ENTERPRS / CPM / UTILS / S / SQ-USQ.ARC / FU18.DOC < prev    next >
Text File  |  1989-10-07  |  29KB  |  890 lines

  1. ;***********************************************************************
  2. ;*                                       *
  3. ;*               Fast Z-80 Unsqueezer                   *
  4. ;*              (w/ wildcards)                   *
  5. ;*                                       *
  6. ;*     Original version and algorithm by Steven Greenberg, 1/10/86     *
  7. ;***********************************************************************
  8.  
  9.     ASEG            ; (See note concerning ASEG / CSEG
  10.                 ;   controversy at end of program where
  11.     ORG    100H        ;   "CODTBL" is defined.
  12.  
  13. ;-----------------------------------------------------------------------
  14. ; v1.8 - 03/04/86
  15. ;   The  search-and-optional-erase of the destination file was    re-
  16. ; moved in favor of a "blind" delete file call.  The open-file call
  17. ; immediately  after  the make-file has been eliminated.   The    TPA
  18. ; size    check has been changed to take into account  that  versions
  19. ; 1.1+ require the CCP to remain resident.  Slightly  increased the
  20. ; input buffer size for this assembly;    prog now req's memory up to
  21. ; to an even 9000H.  If anyone has memory problems, change the buf-
  22. ; fer size equ's at the end ("IBUFSZ","OBUFSZ",or "MAXFLS"). I made
  23. ; Sigi's wildcard expansion buffer size settable at assembly time &
  24. ; is checked for overflow at run time.    - SGG
  25. ;
  26. ; v1.7 - 03/01/86
  27. ;   Found a pre-stack-save Z80 test that I THINK everyone can agree
  28. ; on (it also works for HD64180s & NSC800s), went back to Z80  code
  29. ; for all stack pointer moves, converted Sigi's wildcard sorter  to
  30. ; Zilog  mnemonics  so non-M80 folks can assemble it and  threw  in
  31. ; some    JRs  here and there. Restored the disk write error  message
  32. ; routine from another(!) version 1.3  (not  documented  here) done
  33. ; by Bill Duerr.            - Bruce Morgen
  34. ;
  35. ; v1.6 - 02/18/86
  36. ;   Added wildcard support and suppress non-*?Q?-files    completely.
  37. ; Moved code where it belongs (CSEG)!    - Sigi Kluger
  38. ;
  39. ; v1.5 - 02/18/86
  40. ;   One  of the changes made in v1.1 has been reversed-  Apparently
  41. ; the BIOS for some machines (Kaypro & Osborne?) clobber the alter-
  42. ; nate registers.  Thanks to Keith Peterson for info on this.
  43. ;   No more tricks at "FATAL" or OS stack size assumptions;   Built
  44. ; CR/LF  into the message routine; removed extraneous OR A's  after
  45. ; INC A's from the modified file open success tests.
  46. ;   Most of the changes are in the form of improved  documentation,
  47. ; and some code segments have been shifted in position.
  48. ;   Another  v1.2 (similar M80 compatible) version, courtesy  Harry
  49. ; Kaemmerer, appeared almost simultaneously with the one  mentioned
  50. ; below.   Harry  suggested a shorter (tested?) Z-80 test,  but  it
  51. ; involves  execution  of opcode "18H" (undefined for  the  8080  &
  52. ; 8085).   The    test used here should be clean for an  8085.   Does
  53. ; anyone  have a clean solution? (not time dependent!).   Obviously
  54. ; this isn't a very important aspect of this program.
  55. ;                    - Steven Greenberg
  56. ;
  57. ; v1.4 - 02/17/86 [intermediate unreleased version]
  58. ;
  59. ; v1.3 - 02/17/86
  60. ;   Changed  stack  save and load routines to the old  8080  method
  61. ; since they must run even if you try to use an 8080 processor    and
  62. ; get the error message.        - D. Jewett, III
  63. ;
  64. ; v1.2 - 02/15/86
  65. ;   Fixed source code so it could used with the M80 assembler which
  66. ; is  owned by more CP/M users than all other Z80  assemblers com-
  67. ; bined (and by a wide margin at that).  It can still be  assembled
  68. ; with the SLR Z80ASM for which it was originally written.
  69. ;                    - Irv Hoff
  70. ;
  71. ; v1.1 - 02/09/86
  72. ;   Various small changes to the CP/M interface aspect of the code.
  73. ; Fixed the test for file-open success (BDOS won't always return  a
  74. ; zero).  Moved local stack to Copyright message and saved OS stack
  75. ; to  beginning of same, eliminating warm boot-on-exit (the  algor-
  76. ; ithm    is so fast that the CCP reload often took as much  time  as
  77. ; the unsqueezing itself).  Took out now unnecessary stack trick at
  78. ; FATAL:  and slimmed down on PUSH/POPs at BDOSAV: (BDOS  does    not
  79. ; use Z80 specific registers).        - Bruce Morgen
  80. ;
  81. ;-----------------------------------------------------------------------
  82. ;
  83. ; (FOR CP/M 2.2+, Z-80 only)
  84. ;
  85. ; v1.0 - 01/10/86
  86. ;   This  program  unsqueezes standard    (Greenlaw  style)  squeezed
  87. ; programs.  This is the original (no frills) version simply  spec-
  88. ; ify the filename to be unsqueezed on the command line.  The  res-
  89. ; ult  filename will be generated automatically and written to    the
  90. ; default drive.  The difference between this unsqueezer and others
  91. ; lies in its unique architecture.  This results in speed increases
  92. ; ranging  from a factor of about 2 (compared to  fastest  assembly
  93. ; coded  programs  previously available) on up to  factors  greater
  94. ; than    5 (compared to standard C coded versions).  Also note  that
  95. ; the current .COM file is less than 1K in length.
  96. ;
  97. ;   The architecture, very briefly, is as follows.  First the "dic-
  98. ; tionary" info contained in the squeezed file is "compiled" into a
  99. ; decoding program, which sits in memory just above the .COM  file.
  100. ; Since  each squeezed file generates its own unique  program,    the
  101. ; program  is a highly efficient subroutine for performing the    ac-
  102. ; tual unsqueeze operation.
  103. ;
  104. ;  Thanks to Jeff D. Wilson for many worthwhile suggestions.
  105. ;
  106. ;   Note:  This  version requires a minimum TPA of about  28k,    but
  107. ; input  & output buffer sizes could be easily changed by  changing
  108. ; the equ's for "ibufsz" & "obufsz" at the end of this program    and
  109. ; reassembling it.  Another version could perform a dynamic assign-
  110. ; ment of these buffers based on available memory.  I have not done
  111. ; tests  on  the relative speed / memory tradeoffs.   This  version
  112. ; sion    has  a 2.25k input buffer & a 16k output buffer.   It  also
  113. ; automatically  allocates  a worst case size of  8K  for  "codtbl"
  114. ; another  version could allocate only the exact amount needed    for
  115. ; the file being un-squeezed.
  116. ;
  117. ;   This  program was assembled on an Z80ASM SLR  SuperFast  assem-
  118. ; bler.  No macros are used however, or anything else too assembler
  119. ; specific.
  120. ;                      -Steven Greenberg
  121. ;-----------------------------------------------------------------------
  122.  
  123. ; Opcode equates
  124.  
  125. JPOP    EQU    0C3H        ; Opcode for "JP" instruction
  126.  
  127. ; ASCII equates
  128.  
  129. CR    EQU    0DH
  130. LF    EQU    0AH
  131.  
  132. ; CP/M address equates
  133.  
  134. DFCB    EQU    5CH        ; Default file control block
  135. DDMA    EQU    80H        ; Default DMA address
  136. CPM    EQU    0000H        ; Warm boot jump address
  137. BDOS    EQU    0005H        ; BDOS entrypoint
  138.  
  139. ; BDOS function equates
  140.  
  141. PRTSTR    EQU    9        ; Print string to console
  142. OPEN    EQU    15        ; Open file
  143. CLOSE    EQU    16        ; Close file
  144. ERASE    EQU    19        ; Erase file
  145. READ    EQU    20        ; Read file (sequential)
  146. WRITE    EQU    21        ; Write file (sequential)
  147. MAKE    EQU    22        ; Make file
  148. SETDMA    EQU    26        ; Set DMA address
  149. ;-----------------------------------------------------------------------
  150.  
  151. ENTRY:    JP    START
  152.  
  153. OLDSTK:    DEFB    'Copyright (c) Steven Greenberg 1/10/86  201-670-8724; '
  154.     DEFB    'may be freely reproduced for non-profit applications.'
  155.  
  156. START:
  157.     LD    A,7FH        ; Find out if Z80 with flag test
  158.     ADD    A,A        ; Add 7FH to 7FH
  159.     JP    PE,Z80        ; Parity (overflow)=Z80
  160.     LD    DE,WRNGUP    ; "Program requires Z80 processor"
  161.     JP    MESAGE        ; Non-Z80s: print up and go home
  162. ;
  163. Z80:    LD    (OLDSTK),SP    ; Save the operating system stack
  164.     LD    SP,START    ; Set local stack
  165.     LD    A,(BDOS+2)    ; Size up the TPA
  166.     SUB    EOBFHI+10    ; (Includes 2K for the CCP)
  167.     JR    NC,ENOUGH    ;
  168.     LD    DE,LAKMEM    ; "Not enough memory..."
  169.     JP    FATAL        ; (fatal error)
  170. ;
  171. ENOUGH:    LD    DE,LOGO        ; Version#, etc
  172.     CALL    MESAGE
  173.     LD    DE,DFCB        ; Open input file spec'd on command line
  174.     LD    A,'Q'        ; FORCE .?Q? !!!
  175.     LD    (DFCB+10),A
  176.     LD    DE,DFCB        ; Point to specified file
  177.     LD    HL,FNBUFF    ; And to filename buffer
  178.     CALL    WILDEX        ; Do wildcard expansion
  179.     LD    (NMBFLS),HL    ; Save number of matching files
  180.     JR    Z,WERR        ; Get out if error
  181.     LD    DE,MAXFLS    ; Check if too many matching files
  182.     AND    A        ; Clear carry
  183.     SBC    HL,DE
  184.     JR    NC,TOOMNY
  185.  
  186.     LD    HL,FNBUFF    ; Get name buffer
  187.     LD    (BUFPTR),HL    ; Set up buffer pointer
  188. ;-----------------------------------------------------------------------
  189.  
  190. ; Come here for each new file
  191.  
  192. NXTFIL:    LD    DE,DFCB+1    ; Clean input FCB
  193.     PUSH    DE
  194.     CALL    ZERFCB
  195.     LD    HL,(BUFPTR)
  196.     POP    DE
  197.     PUSH    HL        ; Save filepointer
  198.     LD    BC,11        ; 11 characters
  199.     INC    HL
  200.     LDIR            ; Move next filename in place
  201.     LD    DE,OFCB+1
  202.     CALL    ZERFCB        ; Clean output fcb
  203.     POP    HL
  204.     LD    DE,16        ; Offset to next filename
  205.     ADD    HL,DE
  206.     LD    (BUFPTR),HL
  207.     LD    DE,DFCB
  208.     LD    C,OPEN
  209.     CALL    BDOSAV
  210.     INC    A
  211.     JR    NZ,CLONE    ; Br if successful
  212. ;
  213. WERR:    LD    DE,ERR1        ; Else, "Input file not found"
  214.     JP    FATAL
  215. ;
  216. TOOMNY:    LD    DE,ERR3        ; "Too many matching files"
  217.     JP    FATAL
  218.  
  219.  
  220. ; Before going too much further, take this opportunity to "clone" a
  221. ; 16 byte template of code into memory 512 times.  This forms the
  222. ; skeleton for the compiled block of code "CODTBL".  Various specific
  223. ; instructions and data will overwrite sections of this template after
  224. ; the dictionary info is read.
  225.  
  226. CLONE:    LD    HL,TMPLAT    ; Xfer one copy to the beg of "CODTBL"
  227.     LD    DE,CODTBL
  228.     LD    BC,16
  229.     LDIR
  230.     LD    HL,CODTBL    ; Now copy it 511 more times.
  231.     LD    BC,511*16    ; DE already points to "CODTBL+16"
  232.     LDIR            ; That does it
  233.  
  234.  
  235. ; Now load up the input buffer.  The input buffer, the output buffer,
  236. ; and "CODTBL" are all page aligned and of page multiple lengths.  There
  237. ; are no other criteria for the lengths of the 2 buffers, except that the
  238. ; input buffer should have a minimum length of 2K plus 1 more page. This
  239. ; guarantees that the entire dictionary (plus miscellaneous header info)
  240. ; will be read in on the 1st pass, simplifying the program.
  241.  
  242.     CALL    RELOAD        ; "RELOAD" leaves HL pointing to
  243.     LD    A,(HL)        ; The beginning of "IBUF"
  244.     CP    76H        ; Check for "Squeezed File Header"
  245.                 ; Code 76H,FFH
  246.     JR    NZ,NTSQZD    ; Br if not a squeezed file
  247.     INC    L        ; Note buffer starts on a page boundary
  248.     INC    (HL)        ; Chk for FF [clobber it along the way]
  249. ;
  250. NTSQZD:    LD    DE,NSQMSG    ; Meanwhile , prep for poss err msg
  251.     JP    NZ,FATAL    ; Fatal "not squeezed" condition
  252.     LD    DE,ARROW    ; "---->"
  253.     CALL    MESAGE        ; Ok, print an arrow
  254.     LD    HL,(IBUF+2)    ; Get the 16 bit checksum and save
  255.     LD    (CHKSUM),HL    ; Goes there
  256.     LD    HL,IBUF+3    ; Init pointer past 76FF and 2 byte
  257.                 ; Checksum (-1)
  258.     LD    IX,OFCB+1    ; Init pointer to filename of output FCB
  259. ;
  260. EATLP:    INC    L        ; Filename << 256 chars
  261.     LD    A,(HL)        ; Eat up the file name
  262.     OR    A        ; A zero byte indicates end of filename
  263.     JR    Z,ATEIT        ; Br when that is encountered
  264.     CP    '.'        ; Check for name / ext division char
  265.     JR    Z,ISDOT        ; Br when encountered
  266.     LD    (IX+0),A    ; Else copy filename char to output FCB
  267.     INC    IX        ; And incr that pointer
  268.     JR    EATLP        ; Continue
  269.  
  270.  
  271. ; When "." is encountered, skip to the file extension bytes of the output
  272. ; FCB.    (Any remaining non-extension bytes were init'd to blank).  Do not
  273. ; copy the "." to the output FCB.
  274.  
  275. ISDOT:    LD    IX,OFCB+9    ; Skip...
  276.     JR    EATLP        ; And continue
  277. ;
  278. ATEIT:    LD    (HL),'$'    ; Clobber the zero with a '$' for
  279.                 ; Below function call
  280.     LD    DE,IBUF+4    ; Beg of file name
  281.     CALL    PRINT        ; Print the filename to the console
  282.     LD    DE,OFCB        ; Output FCB
  283.     LD    C,ERASE        ; "Blind erase" the dest file if it exists
  284.     CALL    BDOSAV        ; (*** implement a prompt here? ***)
  285.     LD    C,MAKE        ; In any case, make the new file
  286.     CALL    BDOSAV
  287.     INC    A
  288.     JR    NZ,MAKTBL    ; Err cond check
  289.     LD    DE,ERR2        ; "File open error"
  290.     JP    FATAL        ; Exit
  291.  
  292.  
  293. ;    Now  create  "CODTBL"  by overwriting  certain sections of the
  294. ; template  created above.  The dictionary contains 4  byte  nodes-
  295. ; these  are  con-verted into 16 byte code segments.   The  maximum
  296. ; length  of the original dictionary is (257*4) bytes or  about  2K
  297. ; corresponding to a maximum "CODTBL" length of 8K.
  298. ;
  299. ;    NODE DEFINITION:  As mentioned above, a "node" consists of two
  300. ; pairs  of bytes.  The first pair corresponds to a zero  bit,    the
  301. ; latter to a "1".  To decode a character, we start at node #0. A
  302. ; bit is pulled off the bit stream. We then use the 1st or 2nd byte
  303. ; pair    depending on the bit value.  The byte pair takes on 1 of  2
  304. ; forms  "nn FF" or "xx 0x".  The "nn FF" type is a terminal  node,
  305. ; it means we have our next output value - that value  specifically
  306. ; being  the 1's complement (makes it more mysterious) of "nn".  If
  307. ; the  node is of the second type, it is a pointer to another  node
  308. ; (an  absolute offset from the beg of the dictionary in  terms  of
  309. ; node#, must be multiplied by 4 for a byte offset.  It has a  max-
  310. ; imum    value  of  513, and is expressed as  a    16-bit    #,  lo-byte
  311. ; first).   In this case we go to that node, pull another  bit    off
  312. ; the input stream, and continue the process.
  313. ;
  314. ;    There  is actually a 3rd node type, which just comes up  once.
  315. ; Its  form is "FF FE".  It's a special end-of-file  marker  called
  316. ; "SPEOF".
  317. ;
  318. ;    HOW THE PROGRAM WORKS:  Each node is converted into a  16-byte
  319. ; (actually  13  plus 3 nop's) series of instructions.     These    in-
  320. ; structions  later perform the unsqueezing operation.     The  whole
  321. ; block of code starts at "CODTBL" (which is also the  entrypoint).
  322. ; Each 13 byte "node code" consists of a 7 byte header.  The header
  323. ; shifts out the next bit from reg "b", then conditionally branches
  324. ; to  the first or second half of the remaining code (3  bytes    per
  325. ; half;  7+3+3    = 13).    The 3 bytes in each half are either  the  2
  326. ; instruc-tions "LD A,<byte>" followed by "RET" (terminal node)  or
  327. ; the  single  instruction "JP <nxtnode>".  All calls  to  "CODTBL"
  328. ; even-tually hit a terminal node and perform a normal return.    The
  329. ; only exception is the special end-of-file node which compiles  to
  330. ; "JP  SPEOF"; on this particular return the stack is manually    ad-
  331. ; justed to compensate for the lack of a "RET" instruction.
  332. ;
  333. ; THE TEMPLATE: This is the "template" which was "cloned" earlier
  334. ;
  335. ;    The  following 3 instructions form the header code  for  every
  336. ; node.  They are identical for every node (since the jump is  rel-
  337. ; ative).
  338.  
  339. TMPLAT:    SRL    B        ; Shift out next bit
  340.     CALL    Z,REFILL    ; Refill reg when empty
  341.     JR    C,BITIS1    ; If bit is "1"
  342.  
  343.  
  344. ;    After  the header code gets executed, one of 2 halves  of    the
  345. ; remainder  of the node gets executed.  Which half depends on    the
  346. ; bit shifted out above ("0" for the first half, "1" for the  2nd).
  347. ; Each    half-node has two possible forms.  The terminal form  loads
  348. ; an appropriate value and returns.  The non-terminal form jumps to
  349. ; the  header  of another node. This 16-byte  "node-code  template"
  350. ; assumes  the former case by default, since 2 of 3 bytes  in  that
  351. ; case    are fixed (only the value need be in-serted).  If it  turns
  352. ; out to be the latter case, all 3 bytes will be overwritten with a
  353. ; "jmp" opcode plus an appropriate address.
  354.  
  355. BITIS0:    LD    A,00H        ; (00H gets replaced with actual value
  356.     RET            ; To be returned.)
  357. ;
  358. BITIS1:    LD    A,00H        ; 2nd half of the node, likewise
  359.     RET            ;
  360.     NOP            ; }
  361.     NOP            ; } So the template is exactly 16 bytes
  362.     NOP            ; }
  363.  
  364. ; Create the "node code" table
  365.  
  366. MAKTBL:    INC    L        ; Now points one past the filename EOF
  367.     LD    E,(HL)        ; Get #of nodes (lo byte)
  368.     INC    L
  369.     LD    D,(HL)        ; Hi byte of same
  370.     INC    L
  371.     LD    A,D
  372.  
  373. ; An additional file validity check: though the #of nodes could in theory
  374. ; theory as high as 0201H or so, it should never approach 0300H or higher.
  375.  
  376.     SUB    3        ; If this happens, assume it is not a
  377.     JP    NC,NTSQZD    ; Squeezed file.
  378.  
  379. ; HL indexes through source dictionary (already initialized), & HL' is
  380. ; current dest pointer (indexes thru "codtbl").  DE is initialized to the
  381. ; # of nodes and is decreased to 0.
  382.  
  383.     EXX            ; Init some constants
  384.     LD    DE,10        ; Used for incrementing HL'
  385.     LD    HL,CODTBL+7    ; Init HL' itself
  386.     EXX            ;
  387.  
  388.  
  389. ; Remember, the whole "header" code and some other instructions are
  390. ; already there (from when "template" was duplicated).    Only specific
  391. ; details need now be filled in.
  392.  
  393. NODELP:    CALL    MAKHAF        ; Make the first ("0") half-node
  394.     CALL    MAKHAF        ; 2nd ("1") half-node
  395.  
  396.  
  397. ; Source pointer has already been incremented 4 times, as desired. Dest
  398. ; pointer has only been incremented 6 times, however.
  399.  
  400.     EXX            ; }
  401.     ADD    HL,DE        ; } So take care of that
  402.     EXX            ; }
  403.  
  404.     DEC    DE        ; Loop counter
  405.     LD    A,D
  406.     OR    E
  407.     JR    NZ,NODELP    ; Continue till done
  408.     JR    RUN        ; Go run, HL is is ready, pointing to
  409.                 ; The first byte of squeezed code
  410. ; Create a "half-node"
  411.  
  412. MAKHAF:    LD    C,(HL)
  413.     INC    HL
  414.     LD    A,(HL)        ; Get a byte pair from the dictionary
  415.     INC    HL
  416.     OR    A        ; If it is negative, it is "terminal"
  417.     JP    M,TERMOD    ; Branch if that is the case.
  418.  
  419. ; Else create code for one half-node of the non-terminal variety.
  420. ; Byte pair is in A,C.    Multiply it by 16 (bytes/node in "codtbl")
  421.  
  422.     SLA    C
  423.     RLA
  424.     SLA    C
  425.     RLA
  426.     SLA    C
  427.     RLA
  428.     SLA    C
  429.     RLA
  430.     ADD    A,CDTBLH    ; Add offset to beginning of "CODTBL",
  431.                 ; (page aligned)
  432.     LD    B,A        ; Now BC has the jump address
  433. ;
  434. ALTENT:    PUSH    BC        ; Save it
  435.     EXX            ; Switch to dest pointers
  436.     LD    (HL),JPOP    ; Insert the "jp" opcode
  437.     INC    L        ; Remember "codtbl" is page aligned
  438.     POP    BC        ; Get addr back
  439.     LD    (HL),C        ; Jump addr, lo
  440.     INC    L        ;
  441.     LD    (HL),B        ; Jump addr, hi
  442.     INC    L        ;
  443.     EXX            ; Back to source pointers
  444.     RET            ; Thats all
  445.  
  446. ; Create a half-node of the terminal variety
  447.  
  448. TERMOD:    CP    0FEH        ; Check for special EOF terminal node
  449.     JR    Z,SPEOF        ; Br for that unique case
  450.     LD    A,C        ; Else this byte is the complement of
  451.                 ; The returned value
  452.     CPL
  453.     EXX            ; Switch to dest pointers
  454.     INC    L        ; Just 2nd of 3 bytes need be inserted
  455.     LD    (HL),A        ; Put it in
  456.     INC    L        ;
  457.     INC    L        ; But make sure HL gets incr'd 3 times
  458.     EXX            ;
  459.     RET            ; That's all
  460.  
  461.  
  462. ; Special EOF returns to a special address in mainline code, rather
  463. ; than using "RET".  Stack is adjusted accordingly there.
  464.  
  465. SPEOF:    LD    BC,DONE        ; The special address
  466.     JR    ALTENT        ; Use convenient code subsection above
  467.  
  468.  
  469. ; Code to refill register 'B' with the next byte
  470.  
  471. REFILL:    INC    L
  472.     JR    Z,POSRLD    ; If L is zero, may be at end of buffer
  473. ;
  474. CONT:    LD    B,(HL)        ; Else get next byte
  475.  
  476.  
  477. ; Now we pre-shift out the next bit, shifting in a "1" from the left.
  478. ; Since the leftmost bit in the reg is a  guaranteed "1", testing the
  479. ; zero stat of the reg is a necesssary and sufficient condition for
  480. ; determining that all the bits in the reg have   been used up (see
  481. ; header code for "TMPLATE").  The only things to be careful of is that
  482. ; the the last bit is NOT used, and that the bit now in the carry flag
  483. ; IS used upon return from this subroutine.
  484.  
  485.     SCF            ; To shift in the flag bit
  486.     RR    B        ; Shift out real bit as described
  487.     RET            ; That's it
  488. ;
  489. POSRLD:    INC    H        ; Check if time to reload the input
  490.     LD    A,EIBFHI    ; Buffer with additional data.
  491.     CP    H        ;
  492.     CALL    Z,RELOAD    ; Reload if necessary (resets HL)
  493.     JR    CONT
  494.  
  495.  
  496. ; Main code to perform the unsqueeze. In general, the alternate regs
  497. ; are used as output pointers, flags, etc. while the primary registers
  498. ; are used for input pointing and general purpose use.
  499.  
  500. RUN:    EXX            ; First initialize the alternate regs
  501.     LD    HL,OBUF        ; HL', output pntr, to beg of output bfr
  502.     LD    BC,0        ; C always has a copy of the previous
  503.     EXX            ; Char output;    B is a "repeat flag".
  504.  
  505.                 ; Primary register initialization:
  506.     DEC    HL        ; Init HL, the input pntr, to point to
  507.                 ; The first byte of squeezed code -1.
  508.     LD    DE,0        ; Initialize checksum accumulator to zero
  509.     LD    B,D        ; And initialize 'B' to zero so first
  510.                 ; Call will immediately call in the
  511.                 ; Actual first byte.
  512. ;
  513. MAINLP:    CALL    CODTBL        ; Unsqueeze a character
  514.     CALL    SEND        ; Output it to the output buffer
  515.     JR    MAINLP        ; And repeat "forever" (see "SPEOF"
  516.  
  517.  
  518. ; Reload the input buffer, & reset HL to point to the beginning of it.
  519. ; Assumes input bfr starts page boundry and is of page multiple length.
  520.  
  521. RELOAD:    PUSH    AF
  522.     PUSH    BC
  523.     PUSH    DE
  524.     LD    B,IBUFSZ    ; Loop counter, buffer length in pages
  525.     LD    D,IBUFHI    ; Beg of buffer (hi)
  526. ;
  527. RLDLP:    LD    E,0        ; Lo byte of current dma
  528.     CALL    RDSEC        ; Read in 128 bytes (1/2 page)
  529.     JR    NZ,RLDRTN    ; (return if eof enecountered)
  530.     LD    E,80H        ; To read in the next half page
  531.     CALL    RDSEC        ; Do that
  532.     JR    NZ,RLDRTN    ; As above
  533.     INC    D        ; Next page
  534.     DJNZ    RLDLP        ; Loop till done
  535. ;
  536. RLDRTN:    POP    DE        ; Restore regs
  537.     POP    BC
  538.     POP    AF
  539.     LD    HL,IBUF        ; Reset input pointer
  540.     RET            ; And return
  541.  
  542.  
  543. ; Subr for abover, reads 128 bytes to memory starting at HL
  544.  
  545. RDSEC:    PUSH    DE        ; Save DMA before clobbering it with FCB
  546.     LD    C,SETDMA    ; Set DMA function
  547.     CALL    BDOSAV        ;
  548.     LD    DE,DFCB        ; Input FCB
  549.     LD    C,READ        ;
  550.     CALL    BDOSAV        ; Read a record
  551.     POP    DE        ; Restore DMA to original DMA address
  552.     OR    A        ; Set non-zero status
  553.     RET
  554.  
  555.  
  556. ; When "SPEOF" is encountered, a jump to here is made to exit "CODTBL"
  557. ; rather than the normal RET instruction.
  558.  
  559. DONE:    INC    SP        ; So adjust the stack immediately!
  560.     INC    SP        ;
  561.     LD    A,(CHKSUM+0)    ; Make sure the checksum checks out
  562.     CP    E        ; Lo-byte
  563.     JR    NZ,NFG        ; Br if nfg
  564.     LD    A,(CHKSUM+1)    ; Likewise
  565.     CP    D        ;
  566.     JR    Z,CKSMOK    ; Ok
  567.  
  568.  
  569. ; If a checksum error is detected, report the warning. Let the guy
  570. ; have his file anyway, for whats its worth.
  571.  
  572. NFG:    LD    DE,CHKERR    ; "Checksum error detected"
  573.     CALL    MESAGE        ;
  574.  
  575.  
  576. ; Switch to alternate regs for output. The total #of bytes generated
  577. ; should always be a multiple of 128.  This assumption is not made,
  578. ; however, as it may not be true if the file was squeezed on non-CP/M
  579. ; systems.  Compute # of sectors to write- specifically subtract the
  580. ; buffer start addr from the current pointer value, add 7FH and divide
  581. ; by 128. If the byte count  was in fact a multiple of 128, this has
  582. ; no effect; otherwise it makes sure the final sector gets written.
  583.  
  584. CKSMOK:    EXX            ; Switch to alt regs
  585.     AND    A        ; Clear carry
  586.     LD    DE,OBUF-7FH    ; Take care of adding 7FH in advance
  587.     SBC    HL,DE        ; Subtract
  588.     SLA    L        ; Divide by 128
  589.     RL    H        ; Result now in H
  590.     LD    B,H        ; Use 'B' as the counter
  591.     CALL    WRTOUT        ; Writes 'B' sectors to the output file
  592.     EXX            ; Back to primary regs
  593.     LD    DE,OFCB        ; Close the output file
  594.     LD    C,CLOSE
  595.     CALL    BDOSAV
  596.     LD    DE,DFCB        ; Likewise the input file
  597.     LD    C,CLOSE
  598.     CALL    BDOSAV
  599.  
  600. ; Fall through
  601.  
  602. EXIT:    LD    HL,(NMBFLS)
  603.     DEC    HL
  604.     LD    (NMBFLS),HL
  605.     LD    A,H
  606.     OR    L
  607.     JP    NZ,NXTFIL    ; Next file
  608.     LD    SP,(OLDSTK)    ; Restore OS stack
  609.     RET            ; To CCP
  610.  
  611. ; Write 'B' 128 byte sectors to the output file
  612.  
  613. WRTOUT:    LD    DE,OBUF        ; Init DMA addr to beg of output bfr
  614. ;
  615. WRTLP:    LD    C,SETDMA    ; Set DMA to there
  616.     CALL    BDOSAV
  617.     PUSH    DE        ; Save that address
  618.     LD    DE,OFCB        ; Specify the output file
  619.     LD    C,WRITE        ; Write a record
  620.     CALL    BDOSAV
  621.     OR    A
  622.     JR    NZ,WRTERR
  623.     POP    DE        ; Address as saved above
  624.     DJNZ    NEXSEC        ; Decrement counter & continue if not done
  625.     RET
  626. ;
  627. NEXSEC:    LD    E,80H        ; Else increase by 128 bytes
  628.     LD    C,SETDMA
  629.     CALL    BDOSAV
  630.     PUSH    DE        ; Save DMA pointer
  631.     LD    DE,OFCB        ; Output FCB
  632.     LD    C,WRITE        ; Write another sec
  633.     CALL    BDOSAV
  634.     OR    A        ; Need the test here also
  635.     JR    NZ,WRTERR
  636.     POP    DE        ; Get back orig pointer
  637.     INC    D        ; Inc hi-byte, 0 the lo to effect
  638.     LD    E,0        ; Another 80H incr
  639.     DJNZ    WRTLP        ; Loop till done
  640.     RET
  641. ;
  642. BDOSAV:    EXX            ; BDOS call w/ all regs and alts saved
  643.     PUSH    BC        ; Except for AF, AF', IX, & IY
  644.     PUSH    DE
  645.     PUSH    HL
  646.     EXX
  647.     PUSH    BC
  648.     PUSH    DE
  649.     PUSH    HL
  650.     CALL    BDOS
  651.     POP    HL
  652.     POP    DE
  653.     POP    BC
  654.     EXX
  655.     POP    HL
  656.     POP    DE
  657.     POP    BC
  658.     EXX
  659.     RET
  660. ;
  661. WRTERR:    LD    DE,WRTMSG
  662.  
  663. ; For fatal errors- print the message, restore the os stack & return
  664.  
  665. FATAL:    CALL    MESAGE        ;
  666.     LD    SP,(OLDSTK)    ; Restore stack pointer Z80-style
  667.     RET            ;
  668. ;
  669. MESAGE:    EX    DE,HL        ; Save pntr to message (supplied in DE)
  670.     LD    DE,CRLF        ; First print a CR/LF sequence
  671.     LD    C,PRTSTR
  672.     CALL    BDOSAV
  673.     EX    DE,HL        ; Then the message in question
  674. ;
  675. PRINT:    LD    C,PRTSTR    ; Entry here if no cr/lf desired
  676.     JP    BDOSAV
  677.  
  678. ; Send character to the output buffer, plus related processing
  679.  
  680. SEND:    EXX            ; Alt regs used for output processing
  681.     SRL    B        ; If reg is "1", repeat flag is set
  682.                 ; (note, clears itself automatically)
  683.     JR    C,REPEAT    ; Go perf the repeat
  684.     CP    90H        ; Else see if char is the repeat spec
  685.     JR    Z,SETRPT    ; Br if so
  686.     LD    C,A        ; Else nothing special- but always keep
  687.     CALL    OUT        ; Else just output the char;
  688.     EXX            ; Back to normal regs
  689.     RET            ;
  690.  
  691.  
  692. ; Set repeat flag; count value will come as the next byte. (Note: don't
  693. ; clobber C with the "90H"- it still has the prev character, the one to
  694. ; be repeated)
  695.  
  696. SETRPT:    INC    B        ; Set flag
  697.     EXX            ; Switch to primary regs & return.
  698.     RET
  699.  
  700.  
  701. ; Repeat flag was previously set; current byte in a is a count value.
  702. ; A zero count is a special case which means send 90H itself.  Otherwise
  703. ; use B (was the flag) as a counter. The byte itself goes in A.
  704.  
  705. REPEAT:    OR    A        ; Check for special case
  706.     JR    Z,SND90H    ; Jump if so
  707.     DEC    A        ; Compute "count-1"
  708.     LD    B,A        ; Juggle registers
  709.     LD    A,C        ;
  710. ;
  711. AGAIN:    CALL    OUT        ; Repeat B occurrences of byte in 'A'
  712.     DJNZ    AGAIN        ; Leaves B, the rpt flag, 0 as desired
  713.     EXX            ; Restore regs & rtn
  714.     RET
  715. ;
  716. SND90H:    LD    A,90H        ; Special case code to send the byte 90H
  717.     CALL    OUT        ; Itself
  718.     EXX            ;
  719.     RET            ; (90H "squeezes" into 2 bytes!)
  720.  
  721. ; Output character in 'A' directly to the output buffer
  722.  
  723. OUT:    EXX            ; Back to primary regs briefly
  724.     LD    C,A        ; Save A in C
  725.     ADD    A,E        ; DE is the running checksum
  726.     LD    E,A
  727.     JR    NC,NOCARY
  728.     INC    D
  729. ;
  730. NOCARY:    LD    A,C        ; Put the char back into A
  731.     EXX            ; Back to output (alternate) regs
  732.     LD    (HL),A        ; Put byte into the next avail position
  733.     INC    L        ; Increment pointer
  734.     RET    NZ        ; Return if not passing a page boundry
  735.     INC    H        ; Incr pointer high byte, check limit
  736.     LD    L,A        ; Use L, which is 0, for temp storage
  737.     LD    A,EOBFHI    ; Limit
  738.     CP    H        ; Check
  739.     LD    A,L        ; But first restore regs
  740.     LD    L,0        ;
  741.     RET    NZ        ; Ret if limit not reached
  742.     PUSH    AF
  743.     PUSH    BC
  744.     LD    B,OBUFSZ*2    ; Number of 128 byte records to write
  745.     CALL    WRTOUT
  746.     POP    BC
  747.     POP    AF
  748.     LD    HL,OBUF
  749.     RET
  750.  
  751. ; Clean up FCB
  752.  
  753. ZERFCB:    LD    B,11        ; Fill filename with blanks
  754.     LD    A,' '
  755.     CALL    ZL
  756.     LD    B,24        ; Then zero remainder
  757.     XOR    A
  758. ;
  759. ZL:    LD    (DE),A
  760.     INC    DE
  761.     DJNZ    ZL
  762.     RET
  763.  
  764. ;-----------------------------------------------------------------------
  765. LOGO:    DEFB    'FU  Fast Unsqueezer v1.8$'
  766. ERR1:    DEFB    'Input file not found.$'
  767. ERR2:    DEFB    'File open error.$'
  768. ERR3:    DEFB    'Too many matching files.$'
  769. ARROW:    DEFB    '----> $'
  770. LAKMEM:    DEFB    'Out of memory.$'
  771. NSQMSG:    DEFB    'Not a squeezed file.$'
  772. CHKERR:    DEFB    'Checksum error detected.$'
  773. WRNGUP:    DEFB    'Program requires Z80 uP.$'
  774. WRTMSG:    DEFB    'Output error, program aborted.$'
  775. CRLF:    DEFB    CR,LF,'$'
  776.  
  777. OFCB:    DEFB    0,'           ',0,0,0,0,0,0,0,0
  778.     DEFB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  779.  
  780. CHKSUM:    DS    2
  781. ;-----------------------------------------------------------------------
  782.  
  783. ; ENTRY:
  784. ;    HL = .buffer
  785. ;    DE = .afn fcb
  786. ;
  787. ; EXIT:
  788. ;    HL = number of files
  789. ;    ACC= zero flag set if error
  790. ;    The buffer contains HL file names of 16 characters each
  791. ;    Character 0 contains the user number
  792. ;
  793. SFIRST    EQU    17
  794. SNEXT    EQU    18
  795. ;
  796. WILDEX:    LD    (BUFPTR),HL
  797.     LD    HL,0
  798.     LD    (COUNT),HL
  799.     LD    C,SFIRST
  800.     CALL    BDOSAV
  801.     CP    0FFH
  802.     RET    Z        ; Nothing found -- error
  803.     CALL    MOVEN        ; Move name
  804. ;
  805. WLOOP:    LD    C,SNEXT        ; Search for next
  806.     CALL    BDOSAV
  807.     CP    0FFH
  808.     JR    Z,DONEW        ; Finished
  809.     CALL    MOVEN
  810.     JR    WLOOP
  811. ;
  812. DONEW:    OR    A
  813.     LD    HL,(COUNT)
  814.     RET
  815. ;
  816. MOVEN:    PUSH    DE
  817.     LD    HL,(BUFPTR)
  818.     ADD    A,A
  819.     ADD    A,A
  820.     ADD    A,A
  821.     ADD    A,A
  822.     ADD    A,A
  823.     ADD    A,80H
  824.     LD    C,A
  825.     LD    B,0
  826.     LD    D,16        ; Move 16 characters
  827. ;
  828. MOVLP:    LD    A,(BC)
  829.     LD    (HL),A
  830.     INC    HL
  831.     INC    BC
  832.     DEC    D
  833.     JR    NZ,MOVLP
  834.     LD    (BUFPTR),HL
  835.     POP    DE
  836.     LD    HL,(COUNT)
  837.     INC    HL
  838.     LD    (COUNT),HL
  839.     RET
  840. ;
  841. BUFPTR:    DEFW    0
  842. COUNT:    DEFW    0
  843. NMBFLS:    DEFW    0
  844.  
  845. MAXFLS    EQU    425        ; Buffer size (in files) for wildcard ex-
  846.                 ; Pansions. Room for this many files will
  847.                 ; Will be allocated. (425 should do it!)
  848.  
  849. FNBUFF    EQU    $        ; Beg of that buffer
  850. ENDFNB    EQU    (FNBUFF+16*MAXFLS) ; End of buffer
  851.  
  852.  
  853. ; Compute next page boundary following the end of the above buffer. Do
  854. ; this by adding 0FFH and "anding" with 0FF00H. This will become the
  855. ; beginning of "CODTBL".
  856. ;
  857. ; *** NOTE ***
  858. ;
  859. ;       If this code is CSEG'd, M80 will reject this. You can fake
  860. ;    out the assembler using a "HIGH" , then multiplying by 256,
  861. ;    but then it will link incorrectly. If you just EQU "codtbl",
  862. ;    the resulting code isn't really relocatable anyway...
  863. ;       I think there are ways around this, but they involve the
  864. ;    assumption that this whole file is "page relocatable" only.
  865.  
  866. CODTBL    EQU    (ENDFNB+0FFH) AND 0FF00H ; (works with ASEG only)
  867.  
  868. ; Minimum input buffer size is 9 pages to guarantee that the max possible
  869. ; dictionary size (512 bytes plus overhead) will be read in the first
  870. ; pass.
  871.  
  872. IBUFSZ    EQU    16        ; Input buffer size (pages)
  873.                 ; (was "9" prior to v1.8)
  874.  
  875. ; Output buffer can be any page multiple length (note it too is also page
  876. ; aligned).  Increases beyond 64 pages (16k) may do little to improve perf.
  877.  
  878. OBUFSZ    EQU    64        ; Output buffer size (pages)
  879. ;
  880. IBUF    EQU    CODTBL+(16*512)    ; Beginning of input buffer
  881. OBUF    EQU    IBUF+(IBUFSZ*100H) ; Likewise output buffer
  882. EOBUF    EQU    OBUF+(OBUFSZ*100H) ; End of output buffer
  883. ;
  884. CDTBLH    EQU    HIGH CODTBL    ; }
  885. IBUFHI    EQU    HIGH IBUF    ; } high bytes of the beginning addresses
  886. EIBFHI    EQU    HIGH OBUF    ; }  of the buffers just defined
  887. EOBFHI    EQU    HIGH EOBUF    ; }
  888. ;
  889.     END
  890.