/************************************************/ /* */ /* File : rockfifo_private.c */ /* Description : ROCK FIFO specific library */ /* private part */ /* */ /* Author: Sfiligoi Igor */ /* */ /* Created : 17.02.1997 */ /* Last modified: 12.03.1997 */ /* */ /************************************************/ #include <stdlib.h> #include <Error.h> #include "rockfifo_private.h" /* return the number of elements held in the cache */ unsigned int rock_fifo_cache_get_nrels(ROCK_FIFO_id fifo_id) { if (fifo_id->head==fifo_id->tail) return 0; /* empty */ else if (fifo_id->head<fifo_id->tail) return fifo_id->tail-fifo_id->head; else return ROCK_FIFO_CACHE_SIZE+fifo_id->tail-fifo_id->head; } int rock_fifo_cache_read(ROCK_FIFO_id fifo_id, /* IN : fifo id */ unsigned int nrels, /* IN : nr. of elements to read */ unsigned int *data) /* OUT: data from the cache, must be allocated by caller */ { int csize; int i; csize = rock_fifo_cache_get_nrels(fifo_id); if (csize<nrels) return ROCK_ERROR_FIFO_EMPTY; for (i=0; i<nrels; i++) { data[i] = rockb_get_fifodata(fifo_id->cache[fifo_id->head]); fifo_id->head++; if (fifo_id->head>=ROCK_FIFO_CACHE_SIZE) fifo_id->head=0; /* wrap */ } return ROCK_ERROR_OK; } int rock_fifo_cache_read_bits(ROCK_FIFO_id fifo_id, /* IN : fifo id */ unsigned int nrels, /* IN : nr. of elements to read */ ROCK_EDFIFO_bits *data) /* OUT: data from the cache, must be allocated by caller */ { int csize; int i; csize = rock_fifo_cache_get_nrels(fifo_id); if (csize<nrels) return ROCK_ERROR_FIFO_EMPTY; for (i=0; i<nrels; i++) { rockb_nr2edfifo(fifo_id->cache[fifo_id->head],data[i]); fifo_id->head++; if (fifo_id->head>=ROCK_FIFO_CACHE_SIZE) fifo_id->head=0; /* wrap */ } return ROCK_ERROR_OK; } int rock_fifo_cache_return_bits(ROCK_FIFO_id fifo_id, /* IN : fifo_id */ ROCK_EDFIFO_bits *data, /* IN : data to be returned to the cache */ unsigned int nrels) /* IN : nr. of elements of data to return */ { int i; for (i=nrels; i>0; i--) { if (fifo_id->head>0) fifo_id->head--; else fifo_id->head = ROCK_FIFO_CACHE_SIZE-1; if (fifo_id->head==fifo_id->tail) { /* ERROR, cache overflow */ ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_cache_return","Cache overflow."); return ROCK_ERROR_UNKNOWN; } fifo_id->cache[fifo_id->head] = rockb_edfifo2nr(data[i-1]); } return ROCK_ERROR_OK; } void rock_fifo_flags(ROCK_FIFO_id fifo_id, /* IN : fifo id */ ROCKB_EDFIFO_bits *flags) /* OUT: only ff,hf and ef elements are valid */ { ROCK_FIFO_bits bits; rock_read_fifo(fifo_id->rock_id,bits); if (fifo_id->fifotype==ROCK_FIFO_EFIFO) { flags->ff = bits.eff; flags->hf = bits.ehf; flags->ef = bits.eef; } else { flags->ff = bits.dff; flags->hf = bits.dhf; flags->ef = bits.def; } } /* this routine needs the data to be at the fisical start of the cache */ /* no range checking is done */ /* read the data field by field */ int rock_fifo_fillcache_singular(ROCK_FIFO_id fifo_id, /* IN : fifo id */ unsigned int nrels) /* IN : nr of elements to read, ignore actual size */ { ROCKB_EDFIFO_bits bits; unsigned int i; rock_fifo_flags(fifo_id,&bits); for (i=0; (bits.ef==ROCK_BIT_OFF)&&(i<nrels); i++) { if (fifo_id->fifotype==ROCK_FIFO_EFIFO) rock_read_efifo(fifo_id->rock_id,bits); else rock_read_dfifo(fifo_id->rock_id,bits); if (bits.nvd==ROCK_BIT_ON) break; /* exit as if an Empty Fifo was found */ else { fifo_id->cache[fifo_id->tail++] = rockb_edfifo2nr(bits); } } if (i<nrels) return ROCK_ERROR_FIFO_EMPTY; else return ROCK_ERROR_OK; } /* this routine needs the data to be at the fisical start of the cache */ /* no range checking is done */ /* read the data field by field */ int rock_fifo_fillcache_block(ROCK_FIFO_id fifo_id, /* IN : fifo id */ unsigned int nrels) /* IN : nr of elements to read, ignore actual size */ { int err; unsigned int readels; unsigned char oldboe; /* set boe off to prevent errors */ oldboe = rock_get_boe(fifo_id->rock_id); if (oldboe!=ROCK_BIT_OFF) rock_set_boe(fifo_id->rock_id,ROCK_BIT_OFF); readels = nrels; if (fifo_id->fifotype==ROCK_FIFO_EFIFO) err = rockh_readfifo_efifo(fifo_id->rock_id,readels,&(fifo_id->cache[fifo_id->tail])); else err = rockh_readfifo_dfifo(fifo_id->rock_id,readels,&(fifo_id->cache[fifo_id->tail])); if (oldboe!=ROCK_BIT_OFF) rock_set_boe(fifo_id->rock_id,oldboe); fifo_id->tail+=readels; if ((err==ROCK_ERROR_OK)&&(readels!=nrels)) return ROCK_ERROR_FIFO_EMPTY; else return err; } int rock_fifo_fillcache(ROCK_FIFO_id fifo_id, /* IN : fifo id */ unsigned int nrels) /* IN : fill the cache at least with the nr elements */ /* if more than ROCK_FIFO_FIFO_SIZE, truncated to ROCK_FIFO_FIFO_SIZE */ { int csize; unsigned int minread; unsigned int maxread; /* max elements that can be read */ int err; if (nrels>ROCK_FIFO_FIFO_SIZE) nrels=ROCK_FIFO_FIFO_SIZE; csize = rock_fifo_cache_get_nrels(fifo_id); if (csize>=nrels) return ROCK_ERROR_OK; /* nothing to do */ if (csize>0) { /* put the data at fisical start of the cache */ unsigned int *buffer; buffer = (unsigned int *) malloc(csize*sizeof(unsigned int)); rock_fifo_cache_read(fifo_id,csize,buffer); memcpy(fifo_id->cache,buffer,csize*sizeof(unsigned int)); fifo_id->head = 0; fifo_id->tail = csize; free(buffer); } else { /* this simplifies the cache */ fifo_id->head=0; fifo_id->tail=0; } /* now all the data is at the fisical start of the cache */ /* read only the missing elements */ minread = nrels - csize; maxread = ROCK_FIFO_FIFO_SIZE - csize; err = ROCK_ERROR_OK; switch (fifo_id->cancache) { case ROCK_FIFO_CACHE_OFF: { ROCKB_EDFIFO_bits flags; rock_fifo_flags(fifo_id,&flags); if (flags.ef==ROCK_BIT_ON) { /* fifo empty, do nothing */ } else if (flags.hf==ROCK_BIT_OFF) { /* less than HF */ err = rock_fifo_fillcache_singular(fifo_id,minread); } else if (flags.ff==ROCK_BIT_OFF) { /* more than half */ if (minread>ROCK_FIFO_FIFO_SIZE_HALF) { /* minread is larger than half cache */ err = rock_fifo_fillcache_block(fifo_id,ROCK_FIFO_FIFO_SIZE_HALF); if (err==ROCK_ERROR_OK) err = rock_fifo_fillcache_singular(fifo_id,minread-ROCK_FIFO_FIFO_SIZE_HALF); } else { /* minread if less than half cache */ err = rock_fifo_fillcache_block(fifo_id,minread); } } else { /* full */ err = rock_fifo_fillcache_block(fifo_id,minread); } } break; case ROCK_FIFO_CACHE_MINIMAL: { ROCKB_EDFIFO_bits flags; rock_fifo_flags(fifo_id,&flags); if (flags.ef==ROCK_BIT_ON) { /* fifo empty, do nothing */ } else if (flags.hf==ROCK_BIT_OFF) { /* less than HF */ err = rock_fifo_fillcache_singular(fifo_id,minread); } else if (flags.ff==ROCK_BIT_OFF) { /* more than half */ if (minread>ROCK_FIFO_FIFO_SIZE_HALF) { /* minread is larger than half cache */ err = rock_fifo_fillcache_block(fifo_id,ROCK_FIFO_FIFO_SIZE_HALF); if (err==ROCK_ERROR_OK) err = rock_fifo_fillcache_singular(fifo_id,minread-ROCK_FIFO_FIFO_SIZE_HALF); } else { /* minread if less than half cache => read half cache*/ if (maxread>ROCK_FIFO_FIFO_SIZE_HALF) err = rock_fifo_fillcache_block(fifo_id,ROCK_FIFO_FIFO_SIZE_HALF); else err = rock_fifo_fillcache_block(fifo_id,maxread); } } else { /* full */ err = rock_fifo_fillcache_block(fifo_id,maxread); } } break; case ROCK_FIFO_CACHE_ADVANCED: { ROCKB_EDFIFO_bits flags; rock_fifo_flags(fifo_id,&flags); if (flags.ef==ROCK_BIT_ON) { /* fifo empty, do nothing */ } else if (flags.hf==ROCK_BIT_ON) { /* less than HF */ err = rock_fifo_fillcache_singular(fifo_id,maxread); } else if (flags.ff==ROCK_BIT_OFF) { /* more than half */ if (maxread>ROCK_FIFO_FIFO_SIZE_HALF) { /* maxread is larger than half cache */ err = rock_fifo_fillcache_block(fifo_id,ROCK_FIFO_FIFO_SIZE_HALF); if (err==ROCK_ERROR_OK) err = rock_fifo_fillcache_singular(fifo_id,maxread-ROCK_FIFO_FIFO_SIZE_HALF); } else { /* maxread if less than half cache */ err = rock_fifo_fillcache_block(fifo_id,maxread); } } else { /* full */ err = rock_fifo_fillcache_block(fifo_id,maxread); } } break; case ROCK_FIFO_CACHE_BLOCK: err = rock_fifo_fillcache_block(fifo_id,minread); break; case ROCK_FIFO_CACHE_BLOCK_ADVANCED: err = rock_fifo_fillcache_block(fifo_id,maxread); break; default: /* ERROR */ ErrorSetF(ROCK_ERROR_UNKNOWN,"rock_fifo_fillcache","Invalid cancache: %i",fifo_id->cancache); return ROCK_ERROR_UNKNOWN; } if ((err!=ROCK_ERROR_OK)&&(err!=ROCK_ERROR_FIFO_EMPTY)) { /* serious error */ ErrorSetF(err,"rock_fifo_fillcache","Error found: %s",ErrorGetMessage()); return err; } /* no error */ /* reget csize */ csize = rock_fifo_cache_get_nrels(fifo_id); if (csize<nrels) return ROCK_ERROR_FIFO_EMPTY; /* the fillcache has not obtained enough elements */ else return ROCK_ERROR_OK; }