?? hdcache.c
字號:
/*===========================================================================================*/
/* */
/* HdCache.c */
/* */
/* Implement whatever caching system you want at the atapi level */
/* */
/* */
/*===========================================================================================*/
#include "chips.h"
#include "basetype.h"
#include "osapi.h"
#include "string.h"
#include "eromdbg.h"
#include "ide.h"
#include "errorcodes.h"
#include "hdcache.h"
#include "assert.h"
#include "dma.h"
extern logical_drive_desc driveDesc[];
static void fast_memcpy(void *out, const void *in, int size)
{
unsigned char fallback=0;
hard_assert(out);
hard_assert(in);
if(size<256){
fallback=1;
}
if(out != (void *)KSEG1(out)) {
fallback=1;
//FIXME - should probably make this print at least once.
//ERomPrintFunc(0,"Warning, someone passed cached buffer %08x into read\n", (unsigned int)out);
}
if(in != (void *)KSEG1(in)) {
fallback=1;
ERomPrintFunc(0,"Warning, internally using cached buffer in read\n");
}
if(fallback) {
memcpy(out, in, size);
} else {
//why did someone make this use ints, instead of pointers?
DmaMoveData((unsigned int)in, (unsigned int)out, size);
}
}
Int32 initCache(cachingSystem *cache, Uint8 type, Uint16 nbPages) {
Int32 i;
if ((type != WRITE_THROUGH_CACHE) && (type != WRITE_BACK_CACHE)) {
DbgPrint("Wrong cache type %d\n", type);
return -1;
}
cache->cache_type = type;
cache->nbPages = nbPages;
soft_assert(cache->pages == NULL);
cache->pages = OS_Malloc(nbPages * sizeof(cachePageData));
if (cache->pages == NULL) {
DbgPrint("No space for cache\n");
cache->nbPages = 0;
return -1;
}
// Malloc the data portion
cache->data = NULL;
cache->data = (Uint8 *)OS_Malloc(nbPages * HD_SECTOR_SIZE * sizeof(Uint8));
soft_assert(cache->data != NULL);
cache->data = (Uint8 *)KSEG1(cache->data);
//cache->pages = (cachePage *) KSEG1(cache->pages);
for (i=0; i<nbPages; i++) {
cache->pages[i].counter = 0;
cache->pages[i].sector = 0;
cache->pages[i].dirty = 0;
cache->pages[i].empty = TRUE;
}
return 0;
}
void closeCache(cachingSystem *cache)
{
soft_assert(cache != NULL);
if (cache->pages != NULL)
{
soft_assert(cache->data != NULL);
OS_Free(cache->pages);
OS_Free((void *)KSEG0(cache->data));
cache->data = NULL;
cache->pages = NULL;
}
else
{
soft_assert(cache->data == NULL);
}
cache->nbPages = 0;
}
Int32 readFromCache(cachingSystem *cache, Uint32 blocknb, Uint8 *buf) {
Int32 page;
//DbgPrint("readFromCache - begin\n");
page = findSector(cache, blocknb);
if (page == -1) {
//DbgPrint("sector: %d not found\n", blocknb);
//DbgPrint("readFromCache - end1\n");
// DbgPrint("Cannot find sector %d in cache to read\n", blocknb);
return -1;
}
// DbgPrint("Sector %d is at page %d\n", blocknb, page);
//DbgPrint("sector %d found in page: %d\n", blocknb, page);
soft_assert(cache->pages[page].sector == blocknb);
//memcpy(buf, cache->pages[page].data, HD_SECTOR_SIZE);
fast_memcpy(buf, (cache->data + (page * HD_SECTOR_SIZE)), HD_SECTOR_SIZE);
/*BeginDmaUse();
DmaMoveData((Uint32)(cache->data + (page * HD_SECTOR_SIZE)), (Uint32)buf, HD_SECTOR_SIZE);
EndDmaUse();*/
updatePageCounter(cache, page);
//DbgPrint("readFromCache - end\n");
return 0;
}
Uint32 getCacheSize(cachingSystem *cache)
{
return cache->nbPages;
}
Int32 bulkLoadToCache(cachingSystem *cache, Uint32 blocknb, Uint32 blockCount, Uint8 **buf)
{
// To do:
// 1. find continuous space of length blockCount * HD_SECTOR_SIZE
// 2. set corresponding data for the contiguous chunk to the right address
// 3. return pointer
Uint32 i, length_count, start_page;
if (blockCount > cache->nbPages)
return -1;
length_count = 0;
start_page = 0;
for (i = 0; i < cache->nbPages; i++)
{
if (length_count == 0)
start_page = i;
if ((cache->pages[i].empty == TRUE) ||
(cache->pages[i].dirty == FALSE))
length_count++;
else
length_count = 0;
if (length_count == blockCount)
break;
}
soft_assert(length_count <= blockCount);
if (length_count != blockCount)
return -2;
// Now set the page data
for (i = 0; i < blockCount; i++)
{
soft_assert((cache->pages[start_page + i].empty == TRUE) ||
(cache->pages[start_page + i].dirty == FALSE));
cache->pages[start_page + i].empty = FALSE;
cache->pages[start_page + i].dirty = FALSE;
incrementCounters(cache, cache->nbPages + 1);
cache->pages[start_page + i].counter = 0;
cache->pages[start_page + i].sector = blocknb + i;
}
(*buf) = cache->data + (start_page * HD_SECTOR_SIZE);
return 0;
}
/* Will create a page if this block is not yet cached, and/or update it */
/* the page will not get dirty - czhu*/
Int32 loadToCache(cachingSystem *cache, Uint32 blocknb, Uint8 *buf) {
Int32 page;
//DbgPrint("loadToCache - begin\n");
page = findSector(cache, blocknb);
if (page == -1) {
//DbgPrint("sector %d not found in cache\n", blocknb);
page = freeOrLeastRecentlyUsedNotDirty(cache);
if (page == -1)
{
//DbgPrint("cache is full\n");
//DbgPrint("loadToCache - end1\n");
return -1;
}
//DbgPrint("Not found Write sector %d to page %d\n", blocknb, page);
//DbgPrint("found page to use: %d\n", page);
cache->pages[page].sector = blocknb;
if (cache->pages[page].empty == FALSE)
{
soft_assert(cache->pages[page].dirty == 0);
}
}
else
{
//DbgPrint("sector %d found in page: %d\n", blocknb, page);
soft_assert(cache->pages[page].empty == FALSE);
soft_assert(cache->pages[page].sector == blocknb);
//DbgPrint("Update sector %d at page %d\n", blocknb, page);
}
//memcpy(cache->pages[page].data, buf, HD_SECTOR_SIZE);
fast_memcpy((cache->data + (page * HD_SECTOR_SIZE)), buf, HD_SECTOR_SIZE);
/*BeginDmaUse();
DmaMoveData((Uint32)buf, (Uint32)(cache->data + (page * HD_SECTOR_SIZE)), HD_SECTOR_SIZE);
EndDmaUse();*/
updatePageCounter(cache, page);
cache->pages[page].empty = FALSE;
//DbgPrint("loadToCache - end\n");
return page;
}
/* Will create a page if this block is not yet cached, and/or update it */
Int32 writeToCache(cachingSystem *cache, Uint32 blocknb, Uint8 *buf) {
Int32 page;
page = loadToCache(cache, blocknb, buf);
if(page == -1)
return -1;
if (cache->cache_type == WRITE_BACK_CACHE)
cache->pages[page].dirty = 1;
else
cache->pages[page].dirty = 0;
//DbgPrint("writeToCache - end\n");
return 0;
}
void invalidateCache(cachingSystem *cache, Uint32 blocknb)
{
Int32 page;
page = findSector(cache, blocknb);
if (page != -1)
{
cache->pages[page].dirty = FALSE;
cache->pages[page].empty = TRUE;
cache->pages[page].sector = 0;
cache->pages[page].counter = 0;
}
}
/* Will update blocknb cache if it exists */
void updateCache(cachingSystem *cache, Uint32 blocknb, Uint8 *buf) {
Int32 page;
page = findSector(cache, blocknb);
if (page != -1) {
// DbgPrint("Update sector %d at page %d\n", blocknb, page);
//memcpy(cache->pages[page].data, buf, HD_SECTOR_SIZE);
fast_memcpy((cache->data + (page * HD_SECTOR_SIZE)), buf, HD_SECTOR_SIZE);
/*BeginDmaUse();
DmaMoveData((Uint32)buf, (Uint32)(cache->data + (page * HD_SECTOR_SIZE)), HD_SECTOR_SIZE);
EndDmaUse();*/
updatePageCounter(cache, page);
if (cache->cache_type == WRITE_BACK_CACHE)
cache->pages[page].dirty = 1;
else
cache->pages[page].dirty = 0;
}
}
/* Returns the block # of the LRU page and the address to the buffer (that should not be modified) */
Uint16 flushLRU(cachingSystem *cache, Uint8 *buf, Uint32 *sector) {
Int32 page;
//DbgPrint("flushLRU - begin\n");
page = leastRecentlyUsedDirty(cache);
if (page == -1)
{
//DbgPrint("flushLRU not found\n");
//DbgPrint("no page to flush\n");
//DbgPrint("flushLRU - end1\n");
(*sector) = 0;
return ERR_NO_FAT_IN_PARTITION;
}
//DbgPrint("freeing page: %d\n", page);
soft_assert(cache->pages[page].empty == FALSE);
soft_assert(cache->pages[page].dirty == 1);
//*buf = cache->pages[page].data;
//memcpy(buf, cache->pages[page].data, HD_SECTOR_SIZE);
fast_memcpy(buf, (cache->data + (page * HD_SECTOR_SIZE)), HD_SECTOR_SIZE);
/*BeginDmaUse();
DmaMoveData((Uint32)(cache->data + (page * HD_SECTOR_SIZE)), (Uint32)buf, HD_SECTOR_SIZE);
EndDmaUse();*/
cache->pages[page].dirty = 0;
cache->pages[page].empty = TRUE;
//DbgPrint("flush page: %d sector: %d\n", page, cache->pages[page].sector);
(*sector) = cache->pages[page].sector;
//DbgPrint("flushLRU - end\n");
return SUCCESS;
}
void reportCache(cachingSystem *cache) {
Int32 i;
//DbgPrint("Cache report : %d pages\n", cache->nbPages);
for (i=0; i<cache->nbPages; i++) {
if (cache->pages[i].empty == FALSE) {
DbgPrint("Page %d: counter %d, sector %d, %s, buf at %x\n", i, cache->pages[i].counter, cache->pages[i].sector, cache->pages[i].dirty ? "Dirty" : "", cache->pages[i].data);
OS_TaskDelay(1);
}
}
}
/*===========================================================================================*/
/* */
/* We are implementing the LRU algorithm (Least recently used), maybe simpler to others */
/* and said to be more effective to LFU for instance. */
/* We use the counter to control the usage. -1 is for an invalid page, 0 is the most */
/* recently used and 1 the following...etc. */
/* */
/*===========================================================================================*/
void updatePageCounter(cachingSystem *cache, Int32 page) {
Uint16 value;
soft_assert(page >= 0);
if (cache->pages[page].empty == FALSE)
{
value = cache->pages[page].counter;
incrementCounters(cache, value);
}
else
{
incrementCounters(cache, cache->nbPages + 1);
}
cache->pages[page].counter = 0;
}
/* Increment all counter if less than max */
void incrementCounters(cachingSystem *cache, Uint16 max) {
Int32 i;
for (i=0; i<cache->nbPages; i++)
{
if ((cache->pages[i].empty == FALSE) && (cache->pages[i].counter < max))
{
cache->pages[i].counter++;
}
}
}
/* Returns the page number of the least recently used page */
Int32 leastRecentlyUsed(cachingSystem *cache) {
Int32 i;
Uint16 maxCounter = 0;
Int32 page=-1;
for (i=0; i<cache->nbPages; i++) {
if (cache->pages[i].empty == TRUE)
return i;
if (cache->pages[i].counter >= maxCounter) {
page = i;
maxCounter = cache->pages[i].counter;
}
}
return page;
}
/* Returns the page number of the least recently used page */
Int32 freeOrLeastRecentlyUsedNotDirty(cachingSystem *cache) {
Int32 i;
Uint16 maxCounter = 0;
Int32 page=-1;
for (i=0; i<cache->nbPages; i++)
{
if (cache->pages[i].empty == TRUE)
{
return i;
}
else
{
soft_assert(cache->pages[i].empty == FALSE);
if (cache->pages[i].dirty == 0)
{
// Not empty and not dirty
// Now check for the largest counter
if (cache->pages[i].counter >= maxCounter)
{
page = i;
maxCounter = cache->pages[i].counter;
}
}
}
#if 0
//DbgPrint("page dirty: %d empty: %d counter: %d\n",
// cache->pages[i].dirty, cache->pages[i].empty, cache->pages[i].counter);
if (cache->pages[i].dirty)
{
continue;
}
if (cache->pages[i].empty == TRUE)
{
return i;
}
if (cache->pages[i].counter >= maxCounter) {
page = i;
maxCounter = cache->pages[i].counter;
}
#endif
}
//DbgPrint("return end page: %d\n", page);
return page;
}
/* Returns the page number of the least recently used page with a counter != -1 */
Int32 leastRecentlyUsedDirty(cachingSystem *cache) {
Int32 i;
Uint16 maxCounter = 0;
Int32 page=-1;
for (i=0; i<cache->nbPages; i++)
{
if ((cache->pages[i].empty == FALSE) &&
(cache->pages[i].dirty == 1))
{
if (cache->pages[i].counter >= maxCounter)
{
page = i;
maxCounter = cache->pages[i].counter;
}
}
#if 0
if (!cache->pages[i].dirty)
continue;
if (cache->pages[i].empty == TRUE)
continue;
if (cache->pages[i].counter >= maxCounter) {
page = i;
maxCounter = cache->pages[i].counter;
}
#endif
}
if (!cache->pages[page].dirty)
return -1;
return page;
}
Int32 findSector(cachingSystem *cache,Uint32 sector) {
Int32 i;
for (i=0; i<cache->nbPages; i++)
{
if ((cache->pages[i].empty == FALSE) &&
(cache->pages[i].sector == sector))
{
return i;
}
}
return -1;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -