
* This file: pipe v0.01

* (c) 1990 by The DM

   XDEF     f_push
   XDEF     f_pull
   XDEF     f_clear

   XREF     _LVOAllocMem
   XREF     _LVOFreeMem

MAXDEPTH    EQU   254

   SECTION  pipe,CODE

* error = f_push(value)
*   Z            d0

* Will push d0.l to dynamically allocated linked list of memory
* that represents pipe (fifo). Pointers _Head and _Tail should be
* initialized to 0 before first call. Define MAXDEPTH to # of
* longwords to be stored in one chunk of memory.
* If Z is set (result zero) no memory was left.

* All registers are preserved.

* Structure:
*
* LONG next       ; points to previous structure
* WORD used       ; offset from beginning, points to 1st used long.
* WORD free       ; offset from beginning, points to 1st free long.
* LONG data [0]   ; 1st longword of data
* ...
* LONG data [MAXDEPTH-1]


f_push:
         movem.l  a0-a2/a6/d0-d2,-(a7)
         move.l   d0,d2
         move.l   _Head,a0
         move.l   a0,d0
         bne.s    1$

* This is first time we are called so
         bsr.s    _push1
         beq.s    3$          ; error, no memory
         move.l   a0,_Tail    ; this pointer also needs to be initialized
1$:
         cmp.w    #(MAXDEPTH*4)+4+2+2,6(a0)
         bcs.s    4$

* This hunk is full, allocate next one
         move.l   a0,a2
         bsr.s    _push1
         beq.s    3$          ; error, no memory!
         move.l   a0,(a2)     ; link hunks
4$:
         move.w   6(a0),d0    ; free
         move.l   d2,0(a0,d0.w)
         addq.w   #4,6(a0)    ; result is nonzero
3$:                           ; if brach here, result is zero
         movem.l  (a7)+,a0-a2/a6/d0-d2
         rts

* Here we allocate one block.
* nextblock/a0 , Z/error = _push1 ()
_push1:
         move.l   #(MAXDEPTH*4)+4+2+2,d0
         moveq    #0,d1
         move.l   $4,a6
         jsr      _LVOAllocMem(a6)
         tst.l    d0
         beq.s    2$


         move.l   d0,a0
         clr.l    (a0)        ; next field set to zero
         move.w   #8,4(a0)    ; used initialized to 4 (offset)
         move.w   #8,6(a0)    ; free initialized to 8 (offset)
         move.l   a0,_Head    ; result is nonzero
2$:                           ; if branch here, result is zero
         rts                  ; if error, Z will be set


* value = f_pull ()
*  d0

* Will pull d0.l from dynamically allocated linked list of memory
* that represents pipe. If client is trying to pull from empty
* pipe, -1 will be returned and Z will be set.
* Will automagically deallocate any memory.

* NOTE: if you do not pull everything you have pushed, memory
* will be lost!

f_pull:
         movem.l  a0-a2/a6/d1-d2,-(a7)
         move.l   _Tail,a2
         moveq    #-1,d0
         move.l   a2,d1
         beq.s    1$          ; Pipe is empty

         addq.w   #4,4(a2)
         move.w   4(a2),d0
         move.l   -4(a2,d0.w),d2  ; Pipe contains at least one value
*                 ^^ This is because I just accidentally incremented d0

         cmp.w    6(a2),d0       ; if used == free, time to free this block
         bne.s    2$

* Done with this block, deallocate it and move to next
         move.l   a2,a1
         move.l   (a1),a2
         move.l   #(MAXDEPTH*4)+4+2+2,d0
         move.l   $4,a6
         jsr      _LVOFreeMem(a6)
         move.l   a2,_Tail
         bne.s    2$             ; if this was last block,
         clr.l    _Head          ; clear _Head as well.
2$:
         move.l   d2,d0
         moveq    #-1,d1         ; this is surely nonzero
1$:
         movem.l  (a7)+,a0-a2/a6/d1-d2
         rts


* f_clear ()

* Will deallocate our pipe quickly, cleanly and completely in case there
* is no need to process the remaining stuff in the pipe.

f_clear:
         movem.l  a0-a2/a6/d0-d1,-(a7)
         move.l   _Tail,a2
         move.l   $4,a6
1$:
         move.l   a2,a1
         move.l   a2,d0
         beq.s    2$

* This block is valid, deallocate it & back up
         move.l   (a1),a2
         move.l   #(MAXDEPTH*4)+4+2+2,d0
         jsr      _LVOFreeMem(a6)
         bra.s    1$
2$:
* Ups! Almost forget:
         clr.l    _Head
         clr.l    _Tail
         movem.l  (a7)+,a0-a2/a6/d0-d1
         rts

* In order to save space, these are right here in program segment...

_Head:   dc.l  0     ; initialized to zero!
_Tail:   dc.l  0
   END
