403 lines
11 KiB
C
403 lines
11 KiB
C
/*****************************************************************************\
|
|
* libfat - General purpose FAT library *
|
|
* ---------------------------------- *
|
|
* *
|
|
* Filename : ioman.c *
|
|
* Description : The IO Manager receives all requests for sectors in a central *
|
|
* allowing it to make smart decision regarding caching. *
|
|
* The IOMAN_NUMBUFFER parameter determines how many sectors *
|
|
* ioman can cache. ioman also supports overallocating and *
|
|
* backtracking sectors *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU General Public License *
|
|
* as published by the Free Software Foundation; version 2 *
|
|
* of the License. *
|
|
*
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* As a special exception, if other files instantiate templates or *
|
|
* use macros or inline functions from this file, or you compile this *
|
|
* file and link it with other works to produce a work based on this file, *
|
|
* this file does not by itself cause the resulting work to be covered *
|
|
* by the GNU General Public License. However the source code for this *
|
|
* file must still be made available in accordance with section (3) of *
|
|
* the GNU General Public License. *
|
|
* *
|
|
* This exception does not invalidate any other reasons why a work based *
|
|
* on this file might be covered by the GNU General Public License. *
|
|
* *
|
|
* (c)2006 Lennart Yseboodt *
|
|
* (c)2006 Michael De Nil *
|
|
\*****************************************************************************/
|
|
|
|
/*****************************************************************************/
|
|
#include "ioman_v2.h"
|
|
/*****************************************************************************/
|
|
|
|
esint8 ioman_init(IOManager *ioman, hwInterface *iface, euint8* bufferarea)
|
|
{
|
|
ioman->iface=iface;
|
|
|
|
ioman->bufptr = ioman_getBuffer(ioman,bufferarea);
|
|
ioman->numbuf = IOMAN_NUMBUFFER;
|
|
ioman->numit = IOMAN_NUMITERATIONS;
|
|
|
|
ioman_reset(ioman);
|
|
return(0);
|
|
}
|
|
|
|
void ioman_reset(IOManager *ioman)
|
|
{
|
|
euint16 nb,ni;
|
|
|
|
memClr(ioman->sector,sizeof(euint32)*ioman->numbuf);
|
|
memClr(ioman->status,sizeof(euint8) *ioman->numbuf);
|
|
memClr(ioman->usage ,sizeof(euint8) *ioman->numbuf);
|
|
memClr(ioman->itptr ,sizeof(euint8) *ioman->numbuf);
|
|
|
|
for(nb=0;nb<ioman->numbuf;nb++){
|
|
for(ni=0;ni<ioman->numit;ni++){
|
|
ioman->stack[nb][ni].sector=0;
|
|
ioman->stack[nb][ni].status=0;
|
|
ioman->stack[nb][ni].usage =0;
|
|
}
|
|
}
|
|
}
|
|
|
|
euint8* ioman_getBuffer(IOManager *ioman,euint8* bufferarea)
|
|
{
|
|
static euint8 buf[512 * IOMAN_NUMBUFFER];
|
|
return(buf);
|
|
}
|
|
|
|
void ioman_setAttr(IOManager *ioman,euint16 bufplace,euint8 attribute,euint8 val)
|
|
{
|
|
if(bufplace>=ioman->numbuf)return; /* Out of bounds */
|
|
|
|
if(val){
|
|
ioman->status[bufplace]|=1<<attribute;
|
|
}else{
|
|
ioman->status[bufplace]&=~(1<<attribute);
|
|
}
|
|
}
|
|
|
|
euint8 ioman_getAttr(IOManager *ioman,euint16 bufplace,euint8 attribute)
|
|
{
|
|
if(bufplace>=ioman->numbuf)
|
|
return(0xFF); /* Out of bounds */
|
|
|
|
return(ioman->status[bufplace]&(1<<attribute));
|
|
}
|
|
|
|
euint8 ioman_getUseCnt(IOManager *ioman,euint16 bufplace)
|
|
{
|
|
if(bufplace>=ioman->numbuf)return(0x00);
|
|
return(ioman->usage[bufplace]);
|
|
}
|
|
|
|
void ioman_incUseCnt(IOManager *ioman,euint16 bufplace)
|
|
{
|
|
if(bufplace>=ioman->numbuf)return;
|
|
if(ioman->usage[bufplace]==0xFF)return;
|
|
else ioman->usage[bufplace]++;
|
|
}
|
|
|
|
void ioman_decUseCnt(IOManager *ioman,euint16 bufplace)
|
|
{
|
|
if(bufplace>=ioman->numbuf)return;
|
|
if(ioman->usage[bufplace]==0x0)return;
|
|
else ioman->usage[bufplace]--;
|
|
}
|
|
|
|
void ioman_resetUseCnt(IOManager *ioman,euint16 bufplace)
|
|
{
|
|
if(bufplace>=ioman->numbuf)return;
|
|
ioman->usage[bufplace]=0x00;
|
|
}
|
|
|
|
euint8 ioman_getRefCnt(IOManager *ioman,euint16 bufplace)
|
|
{
|
|
if(bufplace>=ioman->numbuf)return(0x00);
|
|
return(ioman->reference[bufplace]);
|
|
}
|
|
|
|
void ioman_incRefCnt(IOManager *ioman,euint16 bufplace)
|
|
{
|
|
if(bufplace>=ioman->numbuf)return;
|
|
if(ioman->reference[bufplace]==0xFF)return;
|
|
else ioman->reference[bufplace]++;
|
|
}
|
|
|
|
void ioman_decRefCnt(IOManager *ioman,euint16 bufplace)
|
|
{
|
|
if(bufplace>=ioman->numbuf)return;
|
|
if(ioman->reference[bufplace]==0x00)return;
|
|
else ioman->reference[bufplace]--;
|
|
}
|
|
|
|
void ioman_resetRefCnt(IOManager *ioman,euint16 bufplace)
|
|
{
|
|
if(bufplace>=ioman->numbuf)return;
|
|
ioman->reference[bufplace]=0x00;
|
|
}
|
|
|
|
esint8 ioman_pop(IOManager *ioman,euint16 bufplace)
|
|
{
|
|
if(bufplace>=ioman->numbuf)return(-1);
|
|
if(ioman->itptr[bufplace]==0 || ioman->itptr[bufplace]>IOMAN_NUMITERATIONS)return(-1);
|
|
ioman->sector[bufplace] = ioman->stack[bufplace][ioman->itptr[bufplace]].sector;
|
|
ioman->status[bufplace] = ioman->stack[bufplace][ioman->itptr[bufplace]].status;
|
|
ioman->usage[bufplace] = ioman->stack[bufplace][ioman->itptr[bufplace]].usage;
|
|
ioman->itptr[bufplace]--;
|
|
return(0);
|
|
}
|
|
|
|
esint8 ioman_push(IOManager *ioman,euint16 bufplace)
|
|
{
|
|
if(bufplace>=ioman->numbuf)return(-1);
|
|
if(ioman->itptr[bufplace]>=IOMAN_NUMITERATIONS)return(-1);
|
|
ioman->itptr[bufplace]++;
|
|
ioman->stack[bufplace][ioman->itptr[bufplace]].sector = ioman->sector[bufplace];
|
|
ioman->stack[bufplace][ioman->itptr[bufplace]].status = ioman->status[bufplace];
|
|
ioman->stack[bufplace][ioman->itptr[bufplace]].usage = ioman->usage[bufplace];
|
|
return(0);
|
|
}
|
|
|
|
euint8* ioman_getPtr(IOManager *ioman,euint16 bufplace)
|
|
{
|
|
if(bufplace>=ioman->numbuf)return(0);
|
|
return(ioman->bufptr+bufplace*512);
|
|
}
|
|
|
|
esint16 ioman_getBp(IOManager *ioman,euint8* buf)
|
|
{
|
|
if(buf<(ioman->bufptr) || buf>=( ioman->bufptr+(ioman->numbuf*512) )){
|
|
return(-1);
|
|
}
|
|
return((buf-(ioman->bufptr))/512);
|
|
}
|
|
|
|
esint8 ioman_readSector(IOManager *ioman,euint32 address,euint8* buf)
|
|
{
|
|
esint8 r;
|
|
|
|
/*DBG((TXT("ioman_readSector::Requesting address %u to be put in %p.\n"),address,buf));*/
|
|
if(buf==0){
|
|
/*DBG((TXT("Refused to read sector, buf=0\n")));*/
|
|
return(-1);
|
|
}
|
|
|
|
r=if_readBuf(ioman->iface,address,buf);
|
|
|
|
if(r!=0){
|
|
return(-1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
esint8 ioman_writeSector(IOManager *ioman, euint32 address, euint8* buf)
|
|
{
|
|
esint8 r;
|
|
|
|
if(buf==0)return(-1);
|
|
|
|
r=if_writeBuf(ioman->iface,address,buf);
|
|
|
|
if(r<=0){
|
|
return(-1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
void ioman_resetCacheItem(IOManager *ioman,euint16 bufplace)
|
|
{
|
|
ioman->sector[bufplace] = 0;
|
|
ioman->status[bufplace] = 0;
|
|
ioman->usage[bufplace] = 0;
|
|
ioman->reference[bufplace] = 0;
|
|
}
|
|
|
|
esint32 ioman_findSectorInCache(IOManager *ioman, euint32 address)
|
|
{
|
|
euint16 c;
|
|
|
|
for(c=0;c<ioman->numbuf;c++){
|
|
if(ioman_isValid(c) && ioman->sector[c] == address)return(c);
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
esint32 ioman_findFreeSpot(IOManager *ioman)
|
|
{
|
|
euint16 c;
|
|
|
|
for(c=0;c<ioman->numbuf;c++){
|
|
if(!ioman_isValid(c))return(c);
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
esint32 ioman_findUnusedSpot(IOManager *ioman)
|
|
{
|
|
esint32 r=-1;
|
|
euint16 c;
|
|
euint8 fr=0,lr=0xFF;
|
|
|
|
for(c=0;c<ioman->numbuf;c++){
|
|
if(ioman_getUseCnt(ioman,c)==0){
|
|
if(!ioman_isWritable(c) && !fr){
|
|
fr=1;
|
|
lr=0xFF;
|
|
r=-1;
|
|
}
|
|
if(ioman_isWritable(c) && !fr){
|
|
if(ioman_getRefCnt(ioman,c)<=lr){
|
|
r=c;
|
|
lr=ioman_getRefCnt(ioman,c);
|
|
}
|
|
}
|
|
if(fr && !ioman_isWritable(c)){
|
|
if(ioman_getRefCnt(ioman,c)<=lr){
|
|
r=c;
|
|
lr=ioman_getRefCnt(ioman,c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(r);
|
|
}
|
|
|
|
esint32 ioman_findOverallocableSpot(IOManager *ioman)
|
|
{
|
|
euint8 points,lp=0xFF;
|
|
euint16 c;
|
|
esint32 r=-1;
|
|
|
|
for(c=0;c<ioman->numbuf;c++){
|
|
if(ioman->itptr[c]<ioman->numit){
|
|
points = 0;
|
|
if(ioman_isWritable(c))points+=0x7F;
|
|
points += ((euint16)(ioman->itptr[c]*0x4D))/(ioman->numit);
|
|
points += ((euint16)(ioman_getRefCnt(ioman,c)*0x33))/0xFF;
|
|
if(points<lp){
|
|
lp=points;
|
|
r=c;
|
|
}
|
|
}
|
|
}
|
|
return(r);
|
|
}
|
|
|
|
esint8 ioman_putSectorInCache(IOManager *ioman, euint32 address, euint16 bufplace)
|
|
{
|
|
euint8* buf;
|
|
|
|
if((buf = ioman_getPtr(ioman,bufplace))==0)return(-1);
|
|
if((ioman_readSector(ioman,address,buf)))return(-1);
|
|
ioman_setValid(bufplace);
|
|
ioman->sector[bufplace]=address;
|
|
return(0);
|
|
}
|
|
|
|
esint8 ioman_flushSector(IOManager *ioman, euint16 bufplace)
|
|
{
|
|
euint8* buf;
|
|
|
|
if((buf = ioman_getPtr(ioman,bufplace))==0)return(-1);
|
|
if(!ioman_isWritable(bufplace))return(-1);
|
|
if(!(ioman_writeSector(ioman,ioman->sector[bufplace],buf)))return(-1);
|
|
return(0);
|
|
}
|
|
|
|
euint8* ioman_getSector(IOManager *ioman,euint32 address, euint8 mode)
|
|
{
|
|
esint32 bp;
|
|
|
|
if((bp=ioman_findSectorInCache(ioman,address))!=-1){
|
|
if(mode==IOM_MODE_READWRITE){
|
|
ioman_setWritable(bp);
|
|
}
|
|
ioman_incUseCnt(ioman,bp);
|
|
ioman_incRefCnt(ioman,bp);
|
|
return(ioman_getPtr(ioman,bp));
|
|
}
|
|
|
|
if((bp=ioman_findFreeSpot(ioman))==-1){
|
|
if(((bp=ioman_findUnusedSpot(ioman))!=-1)&&(ioman_isWritable(bp))){
|
|
ioman_flushSector(ioman,bp);
|
|
}
|
|
}
|
|
|
|
if(bp!=-1){
|
|
ioman_resetCacheItem(ioman,bp);
|
|
if((ioman_putSectorInCache(ioman,address,bp))){
|
|
return(0);
|
|
}
|
|
if(mode==IOM_MODE_READWRITE){
|
|
ioman_setWritable(bp);
|
|
}
|
|
ioman_incUseCnt(ioman,bp);
|
|
ioman_incRefCnt(ioman,bp);
|
|
return(ioman_getPtr(ioman,bp));
|
|
}
|
|
|
|
if((bp=ioman_findOverallocableSpot(ioman))!=-1){
|
|
if(ioman_isWritable(bp)){
|
|
ioman_flushSector(ioman,bp);
|
|
}
|
|
if(ioman_push(ioman,bp)){
|
|
return(0);
|
|
}
|
|
ioman_resetCacheItem(ioman,bp);
|
|
if((ioman_putSectorInCache(ioman,address,bp))){
|
|
return(0);
|
|
}
|
|
if(mode==IOM_MODE_READWRITE){
|
|
ioman_setWritable(bp);
|
|
}
|
|
ioman_incUseCnt(ioman,bp);
|
|
ioman_incRefCnt(ioman,bp);
|
|
return(ioman_getPtr(ioman,bp));
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
esint8 ioman_releaseSector(IOManager *ioman,euint8* buf)
|
|
{
|
|
euint16 bp;
|
|
|
|
bp=ioman_getBp(ioman,buf);
|
|
ioman_decUseCnt(ioman,bp);
|
|
|
|
if(ioman_getUseCnt(ioman,bp)==0 && ioman->itptr!=0){
|
|
if(ioman_isWritable(bp)){
|
|
ioman_flushSector(ioman,bp);
|
|
}
|
|
ioman_pop(ioman,bp);
|
|
ioman_putSectorInCache(ioman,ioman->sector[bp],bp);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
void ioman_printStatus(IOManager *ioman)
|
|
{
|
|
euint16 c;
|
|
|
|
DBG((TXT("IO-Manager -- Report\n====================\n\n")));
|
|
DBG((TXT("Buffer is %i sectors, from %p to %p\n"),
|
|
ioman->numbuf,ioman->bufptr,ioman->bufptr+(ioman->numbuf*512)));
|
|
for(c=0;c<ioman->numbuf;c++){
|
|
if(ioman_isValid(c)){
|
|
DBG((TXT("BP %3i\t SC %i\t\t US %i\t RF %i\t %s %s\n"),
|
|
c,ioman->sector[c],ioman_getUseCnt(ioman,c),ioman_getRefCnt(ioman,c),
|
|
ioman_isUserBuf(c) ? "USRBUF" : " ",
|
|
ioman_isWritable(c) ? "WRITABLE" : "READONLY"));
|
|
}
|
|
}
|
|
}
|