******************************************************************************* * This file defines a circular buffer with a C interface. * * To use this data structure in a C program, put the following in buf.h: * * /* In: mem - space in which to put buffer structure * * sz - size (in bytes) of array starting at mem * * Out: -1 - indicates error * * if insufficient space * * if declared space is odd in length (i.e., if sz is odd) * * 0 - successful initialization * */ * short new(char * mem, unsigned short sz); * /* In: buf - a pointer to memory that has been initialized via new * * data - to put into buffer * * Out: -1 - indicates error * * if insufficient space * * 0 - successful put * */ * short put(char * buf, unsigned short data); * /* In: buf - a pointer to memory that has been initialized via new * * rdata - a pointer to a word where the get'ed data should be put * * Out: -1 - indicates error * * if buffer is empty * * 0 - successful get * */ * short get(char * buf, unsigned short * rdata); * * Then place * * #include "buf.h" * * at the top of the C file. * * Circular buffers are described in 9.3.4, pp. 301-303. Our implementation is * similar in most regards. According to the C interface specification for * the software in the lab, we need not preserve d0, d1, a0, a1 in functions. * We manage to use only these registers in the following code, so we don't * use 'movem.l' or 'link'. ******************************************************************************* * if we're using the asm68k assembler, uncomment these lines: * * xdef _new * xdef _put * xdef _get * Use 'equ' directives to define "fields" of the buffer structure qend equ 0 ; pointer to one byte beyond given space qhd equ 4 ; "head" qtl equ 8 ; "tail" qdata equ 12 ; beginning of data section of structure spc_min equ 14 ; minimum required bytes needed in _new ******************************************************************************* * See specification in header comments. _new: move.w #-1,d0 move.l 4(sp),a0 ; mem move.w 8(sp),d1 ; sz cmp.w #spc_min,d1 bmi ex_new ; not enough space btst #0,d1 ; odd amount of space? bne ex_new ; don't like odd space ; initialize queue structure move.l a0,a1 ; compute end of given space andi.l #$FFFFFFFF,d1 ; adding unsigned word to long, so 0 out top adda.l d1,a1 move.l a1,qend(a0) lea qdata(a0),a1 move.l a1,qtl(a0) move.l a1,qhd(a0) ; initially empty clr.l d0 ; indicate success ex_new rts ******************************************************************************* * See specification in header comments. _put: move.l 4(sp),a0 ; buf move.l qtl(a0),a1 ; free space ("tail" of queue) move.w 8(sp),(a1) ; put data into free space adda.l #2,a1 ; increment qtl (temporarily held in a1) cmpa.l qend(a0),a1 ; wrap around? bcs chk_spc lea qdata(a0),a1 ; wrap around chk_spc move.w #-1,d0 cmpa.l qhd(a0),a1 ; out of space? beq ex_put move.l a1,qtl(a0) ; have space, so complete the put clr.w d0 ex_put rts ******************************************************************************* * See specification in header comments. _get: move.l 4(sp),a0 ; buf move.l qhd(a0),a1 ; get head move.w #-1,d0 cmpa.l qtl(a0),a1 ; empty? (when qtl == qhd) beq ex_get move.w (a1),d1 ; get data ("head" of queue) adda.l #2,a1 ; increment qhd (temporarily held in a1) cmpa.l qend(a0),a1 ; wrap around? bcs trnsfr lea qdata(a0),a1 ; wrap around trnsfr move.l a1,qhd(a0) ; have data, so complete the get move.l 8(sp),a1 ; rdata (pointer) move.w d1,(a1) ; transfer data to indicated space in memory clr.w d0 ; indicate success ex_get rts ******************************************************************************* * Added 9/29 for problem session. See specification in p8.h. _space: move.l 4(sp),a0 ; buf move.l a2,-(sp) move.l qhd(a0),a1 move.l qtl(a0),a2 cmpa.l a1,a2 bcs tl_hd * head before tail: (total bytes - (tl - hd + 2)) / 2 suba.l a1,a2 ; tl - hd adda.w #2,a2 ; +2 move.l qend(a0),a1 lea qdata(a0),a0 suba.l a0,a1 ; total bytes suba.l a2,a1 ; total bytes - (tl - hd + 2) move.l a1,d0 lsr.l #1,d0 ; /2 bra ex_space * tail before head: (hd - tl - 2) / 2 tl_hd suba.l a2,a1 ; hd - tl suba.w #2,a1 ; - 2 move.l a1,d0 lsr.l #1,d0 ; /2 ex_space move.l (sp)+,a2 rts