home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol040 / comp2.asm < prev    next >
Assembly Source File  |  1984-04-29  |  8KB  |  233 lines

  1. ;                COMP2.ASM as of April 29, 1981
  2. ;  This  routine is extracted and CP/Mified from an  article 
  3. ; 'An  Inroduction  to Data Compression' by  Harold  Corbin, 
  4. ; that appeared in the April 1981 issue of Byte magazine.
  5. ; CP/Mified by: Kelly Smith, CP/M-Net "SYSOP" April 29, 1981
  6. ;  COMP2  (text  compression  routine) takes  keyboard  text 
  7. ; (uppercase  letters  ONLY) and compresses them  using  the 
  8. ; Huffman coding technique.  The first two bytes in the data 
  9. ; buffer (dbuf) are the bit count. Encoded data is stored in 
  10. ; the data buffer in packed form, 8 bits to the data byte.
  11. ;  The Huffman Code was derived for the following table,  by 
  12. ; the  relative frequency of occurence in a random  sampling 
  13. ; of English text.  Frequently used characters are  assigned 
  14. ; shorter  bit 'code' patterns,  and seldom used  characters 
  15. ; are  assigned longer bit 'code' patterns.  Note:  with any 
  16. ; set of codes generated, it is important that no code has a 
  17. ; shorter code as part of its beginning. For example, if the 
  18. ; letter  'E'  is 100,  then 10010 cannot be  the  code  for 
  19. ; another  letter...because in scanning the bit stream  from 
  20. ; left  to right (using EXP2,  the text expansion  routine), 
  21. ; the decoding algorithm would think that 10010 is 'E' (100) 
  22. ; followed  by  10  and NOT the different  letter  that  was 
  23. ; intended.
  24. ;           Letter    Frequency (%)  Huffman Code
  25. ;           E         13.0           100
  26. ;           T         10.5           001
  27. ;           A          8.1           1111
  28. ;           O          7.9           1110
  29. ;           N          7.1           1100
  30. ;           R          6.8           1011
  31. ;           I          6.3           1010
  32. ;           S          6.1           0110
  33. ;           H          5.2           0101
  34. ;           D          3.8           11011
  35. ;           L          3.4           01111
  36. ;           F          2.9           01001
  37. ;           C          2.7           01000
  38. ;           M          2.5           00011
  39. ;           U          2.4           00010
  40. ;           G          2.0           00001
  41. ;           Y          1.9           00000
  42. ;           P          1.9           110101
  43. ;           W          1.5           011101
  44. ;           B          1.4           011100
  45. ;           V           .9           1101001
  46. ;           K           .4           110100011
  47. ;           X           .15          110100001
  48. ;           J           .13          110100000
  49. ;           Q           .11          1101000101
  50. ;           Z           .07          1101000100
  51. ;  The  COMP2  program  takes  characters  entered  via  the 
  52. ; keyboard,  checks for a legal character, finds the Huffman 
  53. ; Code  corresponding  to  the entered  character,  and  the 
  54. ; serial  bit stream that results from the encoding  process 
  55. ; is packed and stored 8 bits to the byte.
  56. ;  The heart of the program's operation is the table  lookup 
  57. ; and shifting function.  Based upon a letter ASCII code, an 
  58. ; index  is computed that is then added to the base  address 
  59. ; of  the  encoding  table.  This table  has  the  following 
  60. ; format: two 8 bit words are required for each letter to be 
  61. ; encoded;  the low order 4 bits of the first word in memory 
  62. ; contain  a count of the number of bits required to  encode 
  63. ; the  letter.  The remaining 12 bits,  8 in the second byte 
  64. ; followed  by 4 in the top half of the first byte are  used 
  65. ; to  store the compressed code.  The code is  stored  left-
  66. ; justified in the 12 bit word.
  67. ;  With  the compressing code located,  it is serialized  by 
  68. ; shifting  left according to the count in the 4 bit part of 
  69. ; the table. As each bit is shifted out, the total bit count 
  70. ; in  the  buffer is updated.  The processing of  the  input 
  71. ; stream  continues  until a period  (.)  is  detected,  and 
  72. ; control  returns to CP/M.  The data buffer at address 4000 
  73. ; Hex then remains intact for expansion by EXP2.
  74. true    equ    -1    ; define true
  75. false    equ    not true; define false
  76. ;
  77. stdcpm    equ    true    ; true if regular CP/M (base address 0000h)
  78. altcpm    equ    false    ; true if alternate CP/M (base address 4200h)
  79. ;
  80.     if    stdcpm    ; if standard CP/M...
  81. base    equ    0000h    ; bsae for standard CP/M system
  82.     endif        ; end if...
  83. ;
  84.     if    altcpm    ; if alternate CP/M...
  85. base    equ    4200h    ; base for H8 or TRS-80 CP/M system
  86.     endif        ; end if...
  87. ;
  88. bdos    equ    base+5    ; CP/M BDOS entry address for function call
  89. ;
  90. rdcon    equ    1    ; read console character
  91. ;
  92. dbuf    equ    04000h    ; data buffer for compressed data
  93. ;
  94.     org    base+100h
  95.  
  96. start:    lxi    h,0    ; save "old" CP/M stack pointer
  97.     shld    dbuf    ; clear compressed bit count
  98.     dad    sp
  99.     shld    oldstk
  100.     lxi    sp,stack; make "new" stack pointer
  101.     lxi    h,dbuf+2; store pointer to next bit location in data buffer
  102.     shld    dadd
  103.     xra    a    ; clear bit position
  104.     sta    pos
  105. ;
  106. ; get character from keyboard, check if end of text '.' character
  107. ;
  108. get$character:
  109. ;
  110.     push    b    ; save reigisters
  111.     push    d
  112.     push    h
  113.     mvi    c,rdcon    ; read console character function
  114.     call    bdos
  115.     pop    h    ; restore registers
  116.     pop    d
  117.     pop    b
  118.     ani    07fh    ; mask-off parity bit
  119.     cpi    '.'    ; end of text?
  120.     jnz    process    ; if not, process this character
  121.     lhld    dadd    ; clean up partial byte remaining
  122.     lda    pos    ; compute remaining shift count
  123.     mov    b,a
  124.     mvi    a,8
  125.     sub    b
  126.     ani    7
  127.     mov    b,a    ; keep shift count
  128.     mov    a,m    ; get compressed byte
  129. shift:    jz    exit    ; exit to CP/M, if all bytes processed
  130.     ral
  131.     dcr    b
  132.     mov    m,a    ; replace compressed byte
  133.     jmp    shift    ; loop 'till done
  134. process:sui    'A'    ; character < 'A'?
  135.     jc    get$character
  136.     cpi    'Z'-'A'+1    ; character > 'Z'?
  137.     jnc    get$character
  138.     add    a    ; multiply by 2 to get table index
  139.     mov    c,a
  140.     mvi    b,0    ; make index bias to table
  141.     lxi    h,compression$table    ; point to base of table
  142.     dad    b    ; add index bias to table pointer
  143.     mov    e,m    ; get encoded value
  144.     inx    h
  145.     mov    d,m
  146.     mov    a,e    ; get bit count for this character
  147.     ani    00fh    ; mask-off high nibble
  148.     mov    b,a    ; keep bit count
  149.     xchg        ; swap pointer for encoded value
  150. next:    xra    a
  151.     dad    h    ; shift out bit stream...
  152.     ral        ; ...MSB first
  153.     ani    1    ; mask-off all but output bit
  154.     push    h
  155.     lhld    dadd    ; get pointer to next bit location
  156.     mov    d,a
  157.     lda    pos    ; get current bit position
  158.     mov    e,a    ; keep it
  159.     mov    a,m    ; get "old" compressed data
  160.     ral        ; make room...
  161.     ora    d    ; ...compress
  162.     mov    m,a    ; save it, done with this compression
  163.     inr    e    ; update position
  164.     mov    a,e
  165.     cpi    8    ; full byte processed?
  166.     jnz    stor
  167.     xra    a    ; clear position
  168.     inx    h    ; bump for next bit location
  169.     shld    dadd
  170. stor:    sta    pos
  171.     lhld    dbuf    ; update compressed bit count
  172.     inx    h
  173.     shld    dbuf
  174.     pop    h
  175.     dcr    b    ; de-bump count
  176.     jnz    next    ; continue compression, if not done
  177.     jmp    get$character    ; get next character, and compress
  178. ;
  179. exit:    lhld    oldstk    ; get "old" CP/M stack pointer
  180.     sphl        ; and restore...
  181.     ret        ; return to CP/M
  182. ;
  183. compression$table:
  184. ;
  185.     dw    0f004h    ; 'A'
  186.     dw    07006h    ; 'B'
  187.     dw    04005h    ; 'C'
  188.     dw    0d805h    ; 'D'
  189.     dw    08003h    ; 'E'
  190.     dw    04805h    ; 'F'
  191.     dw    00805h    ; 'G'
  192.     dw    05004h    ; 'H'
  193.     dw    0a004h    ; 'I'
  194.     dw    0d009h    ; 'J'
  195.     dw    0d189h    ; 'K'
  196.     dw    07805h    ; 'L'
  197.     dw    01805h    ; 'M'
  198.     dw    0c004h    ; 'N'
  199.     dw    0e004h    ; 'O'
  200.     dw    0d406h    ; 'P'
  201.     dw    0d14ah    ; 'Q'
  202.     dw    0b004h    ; 'R'
  203.     dw    06004h    ; 'S'
  204.     dw    02003h    ; 'T'
  205.     dw    01005h    ; 'U'
  206.     dw    0d207h    ; 'V'
  207.     dw    07406h    ; 'W'
  208.     dw    0d089h    ; 'X'
  209.     dw    00005h    ; 'Y'
  210.     dw    0d10ah    ; 'Z'
  211. ;
  212. dadd:    dw    0    ; next bit location
  213. ;
  214. pos:    ds    1    ; current bit location
  215. ;
  216. oldstk:    ds    2    ; storage for "old" CP/M stack pointer
  217.     ds    32    ; storage for 16 level stack
  218. stack    equ    $    ; top of local stack
  219. ;
  220.     end    start
  221.