.title getput ; vers. 1.0 Glenn C. Everhart 1989 ; get_in and put_out functions for LZW compress/decompress ; These are the "hard" codes. ; They assume a structure passed to them of form: ;stream: .word nextbyte ; .word size_array-used ; .byte nextbit,sizbit ;so nextbyte-nextbit should be less than size-arr-sizbit ; .blkb nnnn ;nnnn big "enough" ;When a clear code is put out (code bigger than fits in outbits) then put ; zeroes nextbyte and nextbit. These represent the starting BITS in the array ; to be used for the next in or out data move. ; ; Calls: ; status=put_out(outbits,stream,code) ; status=get_in(outbits,stream,code) ; ; get_in will return error when attempting to grab a char beyond end of nextbyte/nextbit ; n.b. - ALWAYS call with big enough buffers not to overflow! nxtbyt: .long 0 ;next byte local store nxtbit: .long 0 ;next bit local store code: .long 0 ;code local store bits: .long 0 ;char size local store strma: .long 0 ;address of "Stream" arg local copy siz: .long 0 ;array size ; table of max char sizes for powers of 2 bitmax: .long 1,2,4,8,16,32,64 .long 128,256,512,1024,2048,4096,8192,16384,32768,65536 .globl put_out,get_in ;put a character code of bits size into data stream .entry put_out,^m puto: movl @4(ap),bits ;get bit count movl 8(ap),strma ;save address of stream movl @12(Ap),code ;get code movl strma,r3 movzwl (r3)+,r4 ;get next byte within array movzwl (r3)+,siz ;save size movzbl (r3)+,r5 ;get byte number movl r5,nxtbit ;save bit number also tstb (r3)+ ;pass size-bit addl2 r3,r4 ;get abs address movl r4,nxtbyt ;save locally ;first test for code larger than fits into bits movl bits,r6 ;prepare to index cmpl code,bitmax[r6] ;see if code is = or > max blssu 1$ ;if lower, normal ; this is a clear operation. Zero the offsets and return movl strma,r3 ;get context address clrl (r3)+ ;clear byte offset/size max clrw (r3)+ ;zero bit offset/size bit offset movl #ss$_normal,r0 ;say all well ret 1$: ;use bit-field instructions to store data. movl nxtbyt,r7 insv code,nxtbit,bits,(r7) addl3 bits,nxtbit,r7 ;compute new next bit 2$: cmpl r7,#8 ;.ge.8 bits off? blss 3$ ;if not, go finish up incw @strma ;bump context byte offset word incl nxtbyt ;bump next-byte counter subl2 #8,r7 ;subtract off 8 bits brb 2$ ;go for it again 3$: movl r7,nxtbit ;save next bit now ;store context info for next time movl strma,r3 movw (r3)+,(r3)+ ;Copy size used to array size area movb nxtbit,(r3)+ ;store next bit for next time. movb nxtbit,(r3)+ ;store next bit for next time. movl #ss$_normal,r0 ;say all well ret ;get a character code of bits size from data stream .entry get_in,^m geti: movl @4(ap),bits ;get bit count movl 8(ap),strma ;save address of stream ; movl @12(Ap),code ;get code movl strma,r3 movzwl (r3)+,r4 ;get next byte within array movzwl (r3)+,siz ;store size of array locally addl2 r3,r4 ;get abs address addl2 #2,r4 ;(pass bit counter bytes) movl r4,nxtbyt ;save locally movzbl (r3)+,r5 ;get bit number movl r5,nxtbit ;save bit number also ;use bit-field instructions to store data. movl nxtbyt,r7 ;see if we got to the end of the buffer movl strma,r3 cmpw (r3)+,(r3)+ ;use pointer at or past end? blssu 100$ ;if not, normal, so branch cmpb (r3)+,(r3)+ ;bit number before end? blssu 100$ ;yes, branch ;past end of data. Return error flag movl #4,r0 ret 100$: extzv nxtbit,bits,(r7),code movl code,@12(ap) ;send code to caller addl3 bits,nxtbit,r7 ;compute new next bit 2$: cmpl r7,#8 ;.ge.8 bits off? blss 3$ ;if not, go finish up incw @strma ;bump context byte offset word incl nxtbyt ;bump next-byte counter subl2 #8,r7 ;subtract off 8 bits brb 2$ ;go for it again 3$: movl r7,nxtbit ;save next bit now ;store context info for next time movl strma,r3 tstw (r3)+ ;pass next-byte tstw (r3)+ ;pass size in bytes movb nxtbit,(r3) ;store next bit for next time. movl #ss$_normal,r0 ;say all well ret .entry get_out,^m ; get_out(stream,char) returns next character from its' stream ;(which is just a byte array) ;First word of the array is current position, second is size geto: movl 4(ap),r3 ;get context movzwl (r3)+,r4 ;r4 = offset in bytes movzwl (r3)+,r5 ;r5 = size cmpl r4,r5 ;past end or at end? bgeq 10$ ;if so error return addl2 r3,r4 ;form address movb (r4),@8(ap) ;return the char incw @4(ap) ;bump current offset movl #ss$_normal,r0 ret 10$: movl #4,r0 ;error clrw @4(ap) ;zero pointer then too ret .entry put_in,^m ; put_in(stream,char) puts char into stream ;(which is just a byte array) ;First word of the array is current position, second is size puti: movl 4(ap),r3 ;get context movzwl (r3)+,r4 ;r4 = offset in bytes movzwl (r3)+,r5 ;r5 = size cmpl r4,r5 ;past end or at end? bgeq 10$ ;if so error return addl2 r3,r4 ;form address movb @8(ap),(r4) ;store the char incw @4(ap) ;bump current offset movl #ss$_normal,r0 ret 10$: movl #4,r0 ;error clrw @4(ap) ;zero pointer then too ret .globl get,put .entry put,^m cmpb (ap),#2 ;call to put_in??? bneq 30$ ;no,branch jmp puti 30$: cmpb (ap),#3 bneq 40$ ;put_out call? jmp puto 40$: movl #4,r0 ret ;else error .entry get,^m cmpb (ap),#2 ;call to get_out??? bneq 30$ ;no,branch jmp geto 30$: cmpb (ap),#3 bneq 40$ ;get_in call? jmp geti 40$: movl #4,r0 ret ;else error .end