diff --git a/cgdoom/d_main.c b/cgdoom/d_main.c index 662c5ff..0554080 100644 --- a/cgdoom/d_main.c +++ b/cgdoom/d_main.c @@ -368,6 +368,20 @@ void D_DoomMain() // int repisode=1; // int rmap=1; + /* CGDOOM: Z_Init is executed early because we rely on the larger heap to + allocate the lump cache and lump info; normal heap isn't enough for WADs + larger than the shareware WAD */ + Z_Init (); + + for (int i = 0; true; i++) + { + int zone_size; + void *zone_base = I_ZoneBase(&zone_size, i); + if (zone_base == NULL) + break; + Z_AddZone (zone_base, zone_size); + } + ok_wad=W_InitMultipleFiles(); if(W_CheckNumForName("MAP01")!=-1) @@ -404,7 +418,7 @@ void D_DoomMain() #endif } - if(maxepisode>1) + if(maxepisode>1) {} #if 0 //TODO ! do { @@ -455,7 +469,7 @@ void D_DoomMain() //printf ("V_Init: Allocate screens\n"); V_Init (); //printf ("Z_Init: Init zone memory allocation daemon \n"); - Z_Init (); + //Z_Init (); //printf ("W_Init: Init WADfiles\n"); W_InitMultipleFiles (); diff --git a/cgdoom/i_system.c b/cgdoom/i_system.c index e7fb260..ee1dfd5 100644 --- a/cgdoom/i_system.c +++ b/cgdoom/i_system.c @@ -57,12 +57,24 @@ int I_GetHeapSize (void) return RAM_I_Zone_SIZE; } -byte* I_ZoneBase (int* size) +byte* I_ZoneBase (int* size, int i) { - *size = RAM_I_Zone_SIZE; - mb_mainzone = (byte *) SystemStack; - ASSERT(RAM_I_Zone_SIZE <= SYSTEM_STACK_SIZE); - return mb_mainzone; + if (i == 0) + { + /* System stack (~500 kiB) */ + *size = RAM_I_Zone_SIZE; + mb_mainzone = (byte *) SystemStack; + ASSERT(RAM_I_Zone_SIZE <= SYSTEM_STACK_SIZE); + return mb_mainzone; + } + if (i == 1) + { + /* Unused part of user stack (~200 kiB); provided by linker script */ + extern byte sextra, eextra; + *size = &eextra - &sextra; + return &sextra; + } + return NULL; } // diff --git a/cgdoom/i_system.h b/cgdoom/i_system.h index f9faa6d..b95f396 100644 --- a/cgdoom/i_system.h +++ b/cgdoom/i_system.h @@ -33,11 +33,13 @@ // A check to determine which control system to compile for //#define EMULATOR_CONTROLS 1 +/* CGDOOM: I_ZoneBase() is extended with a second argument to support multiple + allocation zones, for more memory */ // Called by startup code // to get the ammount of memory to malloc // for the zone management. -byte* I_ZoneBase (int *size); +byte* I_ZoneBase (int *size, int zone_no); // Called by D_DoomLoop, diff --git a/cgdoom/w_wad.c b/cgdoom/w_wad.c index a518280..7e83183 100644 --- a/cgdoom/w_wad.c +++ b/cgdoom/w_wad.c @@ -110,7 +110,16 @@ static int W_AddFile () numlumps += header.numlumps; // Fill in lumpinfo - lumpinfo = (lumpinfo_t *)CGDRealloc (lumpinfo, numlumps*sizeof(lumpinfo_t)); + // TODO: Actual realloc + if (!lumpinfo) + { + lumpinfo = (lumpinfo_t *)Z_Malloc (numlumps*sizeof(lumpinfo_t), PU_STATIC, 0); + } + else + { + I_Error ("realloc lumpinfo!"); + lumpinfo = (lumpinfo_t *)CGDRealloc (lumpinfo, numlumps*sizeof(lumpinfo_t)); + } if (!lumpinfo) I_ErrorI ("CGDrealloc lumpinfo", (int)lumpinfo, numlumps, numlumps*sizeof(lumpinfo_t), 0); @@ -330,9 +339,7 @@ static void* W_CacheLumpNumCommon( int lump, int tag,int iEnableFlash) /*if (lump==1203) printf("sky access, returning %x \n",lumpcache[lump]);*/ - int p1 = ((unsigned int)lumpcache[lump] & 0xf0000000) == 0x80000000; - int p2 = ((unsigned int)lumpcache[lump] & 0xf0000000) == 0xa0000000; - if(lumpcache[lump] == NULL || (!p1 && !p2)) + if(lumpcache[lump] == NULL) I_ErrorI("W_CacheLumpNumCommon", (int)lumpcache[lump], lump, 0, 0); return lumpcache[lump]; diff --git a/cgdoom/z_zone.c b/cgdoom/z_zone.c index 05fca06..89ad32e 100644 --- a/cgdoom/z_zone.c +++ b/cgdoom/z_zone.c @@ -51,9 +51,21 @@ typedef struct memblock_t* rover; } memzone_t; +/* CGDOOM: In order to increase available memory, we need to support multiple + zones. The code below is adapted to do that: -static memzone_t* mainzone; + * Z_ClearZone is already parameterized, nothing to do (it's never called) + * Z_Init is mostly replaced by a new function Z_AddZone() + * Z_Free is changed to detect which zone contains the pointer + * Z_Malloc is changed to try all zones + * Z_FreeTags is changed to iterate on all zones + * Z_CheckHeap is changed to iterate on all zones + * Z_ChangeTag2 operates on a single block and needs no change + * Z_FreeMemory is changed to iterate on all zones */ +static memzone_t *zones[ZONE_MAX]; +static int zone_count; +// static memzone_t* mainzone; // @@ -81,27 +93,36 @@ void Z_ClearZone (memzone_t* zone) // // Z_Init // -void Z_Init (void) +void Z_Init(void) +{ + /* All work is left to Z_AddZone() */ + zone_count = 0; +} + +void Z_AddZone (void *buf, int size) { memblock_t* block; - int size; - mainzone = (memzone_t *)I_ZoneBase (&size); - mainzone->size = size; + if (zone_count >= ZONE_MAX) + return; + + memzone_t* zone = (memzone_t *)buf; + zones[zone_count++] = zone; + zone->size = size; // set the entire zone to one free block - mainzone->blocklist.next = mainzone->blocklist.prev = block = (memblock_t *)( (byte *)mainzone + sizeof(memzone_t) ); + zone->blocklist.next = zone->blocklist.prev = block = (memblock_t *)( (byte *)zone + sizeof(memzone_t) ); - mainzone->blocklist.user = (void **)mainzone; - mainzone->blocklist.tag = PU_STATIC; - mainzone->rover = block; + zone->blocklist.user = (void **)zone; + zone->blocklist.tag = PU_STATIC; + zone->rover = block; - block->prev = block->next = &mainzone->blocklist; + block->prev = block->next = &zone->blocklist; // NULL indicates a free block. block->user = NULL; - block->size = mainzone->size - sizeof(memzone_t); + block->size = zone->size - sizeof(memzone_t); } @@ -113,10 +134,24 @@ void Z_Free (const void* ptr) memblock_t* block; memblock_t* other; - if(PTR_TO_FLASH(ptr)) + if (PTR_TO_FLASH(ptr)) + return; + + memzone_t* zone = NULL; + for (int i = 0; i < zone_count; i++) { + if (ptr >= (void *)zones[i] && ptr < (void *)zones[i] + zones[i]->size) + { + zone = zones[i]; + break; + } + } + if (zone == NULL) + { + I_ErrorI ("Z_Free: Out of zone", (int)ptr, 0, 0, 0); return; } + block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t)); if (block->id != ZONEID) @@ -147,9 +182,9 @@ void Z_Free (const void* ptr) other->next = block->next; other->next->prev = other; - if (block == mainzone->rover) + if (block == zone->rover) { - mainzone->rover = other; + zone->rover = other; } block = other; @@ -163,9 +198,9 @@ void Z_Free (const void* ptr) block->next = other->next; block->next->prev = block; - if (other == mainzone->rover) + if (other == zone->rover) { - mainzone->rover = block; + zone->rover = block; } } } @@ -202,13 +237,6 @@ void* Z_Malloc( int size, int tag, void* user ) } #endif - /*if(size > 64000) - { - char buf[21]; - CGDAppendNum0_999("ENERR:",iCalled,1,buf); - I_Error(buf); - return 0; - }*/ // scan through the block list, // looking for the first free block // of sufficient size, @@ -217,49 +245,71 @@ void* Z_Malloc( int size, int tag, void* user ) // account for size of block header size += sizeof(memblock_t); - // if there is a free block behind the rover, - // back up over them - base = mainzone->rover; + int zone_no = 0; + memzone_t *zone = zones[zone_no]; - if (!base->prev->user) + for (;;) { - base = base->prev; - } + // if there is a free block behind the rover, + // back up over them + base = zone->rover; - rover = base; - start = base->prev; - - do - { - if (rover == start) + if (!base->prev->user) { - // scanned all the way around the list - I_ErrorI ("Z_Malloc failure", size, 0, 0, 0); + base = base->prev; } - if (rover->user) + rover = base; + start = base->prev; + int failed = 0; + + do { - if (rover->tag < PU_PURGELEVEL) + if (rover == start) { - // hit a block that can't be purged, - // so move base past it - base = rover = rover->next; + // scanned all the way around the list + failed = 1; + break; + } + + if (rover->user) + { + if (rover->tag < PU_PURGELEVEL) + { + // hit a block that can't be purged, + // so move base past it + base = rover = rover->next; + } + else + { + // free the rover block (adding the size to base) + + // the rover can be the base block + base = base->prev; + Z_Free ((byte *)rover+sizeof(memblock_t)); + base = base->next; + rover = base->next; + } + } + else + rover = rover->next; + } while (base->user || base->size < size); + + if (failed) + { + if (zone_no + 1 < zone_count) + { + zone = zones[++zone_no]; + continue; } else { - // free the rover block (adding the size to base) - - // the rover can be the base block - base = base->prev; - Z_Free ((byte *)rover+sizeof(memblock_t)); - base = base->next; - rover = base->next; + I_ErrorI ("Z_Malloc failure", size, 0, 0, 0); + return NULL; } } - else - rover = rover->next; - } while (base->user || base->size < size); - + else break; + } // found a block big enough extra = base->size - size; @@ -300,7 +350,7 @@ void* Z_Malloc( int size, int tag, void* user ) base->tag = tag; // next allocation will start looking here - mainzone->rover = base->next; + zone->rover = base->next; base->id = ZONEID; @@ -317,20 +367,25 @@ void Z_FreeTags(int lowtag,int hightag ) memblock_t* block; memblock_t* next; - for(block = mainzone->blocklist.next;block != &mainzone->blocklist;block = next) + for (int i = 0; i < zone_count; i++) { - // get link before freeing - next = block->next; + memzone_t* mainzone = zones[i]; - // free block? - if (!block->user) + for(block = mainzone->blocklist.next;block != &mainzone->blocklist;block = next) { - continue; - } + // get link before freeing + next = block->next; - if (block->tag >= lowtag && block->tag <= hightag) - { - Z_Free ( (byte *)block+sizeof(memblock_t)); + // free block? + if (!block->user) + { + continue; + } + + if (block->tag >= lowtag && block->tag <= hightag) + { + Z_Free ( (byte *)block+sizeof(memblock_t)); + } } } } @@ -342,27 +397,32 @@ void Z_CheckHeap (void) { memblock_t* block; - for (block = mainzone->blocklist.next ; ; block = block->next) + for (int i = 0; i < zone_count; i++) { - if (block->next == &mainzone->blocklist) - { - // all blocks have been hit - break; - } + memzone_t* mainzone = zones[i]; - if((byte *)block + block->size != (byte *)block->next) + for (block = mainzone->blocklist.next ; ; block = block->next) { - I_Error("Z_CheckHeap: block size does not touch the next block\n"); - } + if (block->next == &mainzone->blocklist) + { + // all blocks have been hit + break; + } - if(block->next->prev != block) - { - I_Error("Z_CheckHeap: next block doesn't have proper back link\n"); - } + if((byte *)block + block->size != (byte *)block->next) + { + I_Error("Z_CheckHeap: block size does not touch the next block\n"); + } - if(!block->user && !block->next->user) - { - I_Error("Z_CheckHeap: two consecutive free blocks\n"); + if(block->next->prev != block) + { + I_Error("Z_CheckHeap: next block doesn't have proper back link\n"); + } + + if(!block->user && !block->next->user) + { + I_Error("Z_CheckHeap: two consecutive free blocks\n"); + } } } } @@ -406,11 +466,16 @@ int Z_FreeMemory (void) memblock_t* block; int free = 0; - for(block = mainzone->blocklist.next;block != &mainzone->blocklist;block = block->next) + for (int i = 0; i < zone_count; i++) { - if (!block->user || block->tag >= PU_PURGELEVEL) + memzone_t* mainzone = zones[i]; + + for(block = mainzone->blocklist.next;block != &mainzone->blocklist;block = block->next) { - free += block->size; + if (!block->user || block->tag >= PU_PURGELEVEL) + { + free += block->size; + } } } return free; diff --git a/cgdoom/z_zone.h b/cgdoom/z_zone.h index 3a05481..d5d4721 100644 --- a/cgdoom/z_zone.h +++ b/cgdoom/z_zone.h @@ -54,6 +54,13 @@ void Z_CheckHeap (void); void Z_ChangeTag2 (const void *ptr, int tag); int Z_FreeMemory (void); +/* CGDOOM: Support for multiple zones is added; Z_Init() now does nothing, + zones need to be added manually (see D_DoomMain()). */ +void Z_AddZone (void *zone, int size); + +/* Maximum number of zones. */ +#define ZONE_MAX 16 + typedef struct memblock_s {