Erwan
- fix issue 92 (purple screen). Many thanks to Yeshua and Raphael! - Switched valloc to vram, more recent and faster.
This commit is contained in:
@@ -16,7 +16,7 @@ GENERIC_OBJS = src/JApp.o src/JGBKFont.o \
|
||||
src/tinyxml/tinyxmlparser.o src/tinyxml/tinyxmlerror.o \
|
||||
src/Encoding.o src/JTTFont.o \
|
||||
src/JMD2Model.o src/JOBJModel.o
|
||||
PSP_OBJS = src/JSocket.o src/JGfx.o src/JSfx.o src/JAudio.o src/JMP3.o src/decoder_prx.o src/main.o src/valloc.o
|
||||
PSP_OBJS = src/JSocket.o src/JGfx.o src/JSfx.o src/JAudio.o src/JMP3.o src/decoder_prx.o src/main.o src/vram.o
|
||||
LINUX_OBJS = src/linux/JGfx.o src/linux/JSfx.o src/Xmain.o
|
||||
|
||||
|
||||
|
||||
@@ -83,10 +83,11 @@ public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
static JRenderer* GetInstance();
|
||||
|
||||
/*
|
||||
//START PurpleScreen Debug
|
||||
static int debugged;
|
||||
//END PurpleScreen Debug
|
||||
|
||||
*/
|
||||
static void Destroy();
|
||||
|
||||
static void Set3DFlag(bool flag);
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef _VALLOC_H
|
||||
#define _VALLOC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define vrelptr vGuPointer
|
||||
#define vabsptr vCPUPointer
|
||||
|
||||
size_t vgetMemorySize(unsigned int width, unsigned int height, unsigned int psm);
|
||||
|
||||
// Return a pointer relative to VRAM Base address useable by GU
|
||||
void* vGuPointer( void* ptr );
|
||||
// Return an absolute pointer useable by CPU
|
||||
void* vCPUPointer( void* ptr );
|
||||
|
||||
// Returns an absolute pointer useable by CPU
|
||||
void* valloc( size_t size );
|
||||
void vfree( void* ptr );
|
||||
|
||||
size_t vmemavail();
|
||||
size_t vlargestblock();
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _VALLOC_H
|
||||
54
JGE/include/vram.h
Normal file
54
JGE/include/vram.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Helper for use with the PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under GPL
|
||||
*
|
||||
* vram.c - Standard C high performance VRAM allocation routines.
|
||||
*
|
||||
* Copyright (c) 2007 Alexander Berl 'Raphael' <raphael@fx-world.org>
|
||||
* http://wordpress.fx-world.org
|
||||
*
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#ifndef vram_h__
|
||||
#define vram_h__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void* vrelptr( void *ptr ); // make a pointer relative to memory base address (ATTENTION: A NULL rel ptr is not illegal/invalid!)
|
||||
void* vabsptr( void *ptr ); // make a pointer absolute (default return type of valloc)
|
||||
|
||||
void* valloc( size_t size );
|
||||
void vfree( void* ptr );
|
||||
size_t vmemavail();
|
||||
size_t vlargestblock();
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Debug printf (to stdout) a trace of the current Memblocks
|
||||
void __memwalk();
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ifdef vram_h__
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <pspdebug.h>
|
||||
#include <pspdisplay.h>
|
||||
#include <png.h>
|
||||
#include "../include/valloc.h"
|
||||
#include "../include/vram.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -39,6 +39,7 @@ static unsigned int __attribute__((aligned(16))) list[262144];
|
||||
|
||||
extern void SwizzlePlot(u8* out, PIXEL_TYPE color, int i, int j, unsigned int width);
|
||||
|
||||
/*
|
||||
//START PurpleScreen Debug
|
||||
int JRenderer::debugged = 0;
|
||||
typedef struct
|
||||
@@ -88,7 +89,7 @@ extern GuDisplayList* gu_list;
|
||||
|
||||
//END PurpleScreen Debug
|
||||
|
||||
|
||||
*/
|
||||
|
||||
void Swap(float *a, float *b)
|
||||
{
|
||||
@@ -245,19 +246,19 @@ void JRenderer::InitRenderer()
|
||||
|
||||
sceGuInit();
|
||||
|
||||
fbp0 = ( u32* ) vrelptr ( valloc ( FRAME_BUFFER_SIZE ) );
|
||||
fbp1 = ( u32* ) vrelptr ( valloc ( FRAME_BUFFER_SIZE ) );
|
||||
fbp0 = ( u32* ) valloc ( FRAME_BUFFER_SIZE ) ;
|
||||
fbp1 = ( u32* ) valloc ( FRAME_BUFFER_SIZE );
|
||||
zbp = NULL;
|
||||
|
||||
// setup GU
|
||||
sceGuStart(GU_DIRECT,list);
|
||||
|
||||
sceGuDrawBuffer(BUFFER_FORMAT, fbp0, FRAME_BUFFER_WIDTH);
|
||||
sceGuDispBuffer(SCREEN_WIDTH, SCREEN_HEIGHT, fbp1, FRAME_BUFFER_WIDTH);
|
||||
sceGuDrawBuffer(BUFFER_FORMAT, vrelptr (fbp0), FRAME_BUFFER_WIDTH);
|
||||
sceGuDispBuffer(SCREEN_WIDTH, SCREEN_HEIGHT, vrelptr (fbp1), FRAME_BUFFER_WIDTH);
|
||||
if (m3DEnabled)
|
||||
{
|
||||
zbp = ( u16* ) vrelptr ( valloc ( FRAME_BUFFER_WIDTH*SCREEN_HEIGHT*2) );
|
||||
sceGuDepthBuffer(zbp, FRAME_BUFFER_WIDTH);
|
||||
zbp = ( u16* ) valloc ( FRAME_BUFFER_WIDTH*SCREEN_HEIGHT*2);
|
||||
sceGuDepthBuffer(vrelptr (zbp), FRAME_BUFFER_WIDTH);
|
||||
}
|
||||
|
||||
sceGuOffset(2048 - (SCREEN_WIDTH/2), 2048 - (SCREEN_HEIGHT/2));
|
||||
@@ -359,7 +360,7 @@ void JRenderer::DestroyRenderer()
|
||||
sceGuTerm();
|
||||
vfree(fbp0);
|
||||
vfree(fbp1);
|
||||
debugged = 0;
|
||||
//debugged = 0;
|
||||
if (zbp) vfree(zbp);
|
||||
}
|
||||
|
||||
@@ -382,6 +383,9 @@ void JRenderer::BeginScene()
|
||||
else
|
||||
sceGuTexFilter(GU_LINEAR, GU_LINEAR); // GU_LINEAR good for scaling
|
||||
|
||||
//Keep this until we get rev 2489 (or better) of the SDK
|
||||
//See http://code.google.com/p/wagic/issues/detail?id=92
|
||||
sceGuSendCommandi(210,BUFFER_FORMAT);
|
||||
}
|
||||
|
||||
|
||||
@@ -399,6 +403,7 @@ void JRenderer::EndScene()
|
||||
mCurrentTex = -1;
|
||||
mCurrentBlend = -1;
|
||||
|
||||
/*
|
||||
//START PurpleScreen Debug
|
||||
if (!debugged){
|
||||
debugged = 1;
|
||||
@@ -419,6 +424,7 @@ void JRenderer::EndScene()
|
||||
fclose (pFile);
|
||||
}
|
||||
//END PurpleScreen Debug
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
284
JGE/src/valloc.c
284
JGE/src/valloc.c
@@ -1,284 +0,0 @@
|
||||
/*
|
||||
* Helper for use with the PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed as 'free to use and modify as long as credited appropriately'
|
||||
*
|
||||
* valloc.c - Standard C library VRAM allocation routines.
|
||||
*
|
||||
* Copyright (c) 2006 Alexander Berl <a.berl@gmx.de>
|
||||
*
|
||||
*/
|
||||
//#include <psptypes.h>
|
||||
//#include <pspkernel.h>
|
||||
#include <pspgu.h>
|
||||
#include <malloc.h>
|
||||
#include "valloc.h"
|
||||
|
||||
|
||||
/* Use this to set the default valloc() alignment. */
|
||||
#define DEFAULT_VALIGNMENT 16
|
||||
|
||||
#ifndef ALIGN
|
||||
#define ALIGN(x, align) (((x)+((align)-1))&~((align)-1))
|
||||
#endif
|
||||
|
||||
|
||||
#define VRAM_SIZE 0x200000
|
||||
#define VRAM_BASE ((unsigned int)sceGeEdramGetAddr())
|
||||
|
||||
/* _vram_mem_block_header structure. */
|
||||
typedef struct _vram_mem_header {
|
||||
void * ptr;
|
||||
size_t size;
|
||||
struct _vram_mem_header * prev;
|
||||
struct _vram_mem_header * next;
|
||||
} vram_mem_header_t;
|
||||
|
||||
|
||||
|
||||
void * __valloc_vram_base = (void*)0;
|
||||
vram_mem_header_t *__valloc_vram_head = NULL;
|
||||
vram_mem_header_t *__valloc_vram_tail = NULL;
|
||||
|
||||
|
||||
|
||||
size_t vgetMemorySize(unsigned int width, unsigned int height, unsigned int psm)
|
||||
{
|
||||
switch (psm)
|
||||
{
|
||||
case GU_PSM_T4:
|
||||
return (width * height) >> 1;
|
||||
|
||||
case GU_PSM_T8:
|
||||
return width * height;
|
||||
|
||||
case GU_PSM_5650:
|
||||
case GU_PSM_5551:
|
||||
case GU_PSM_4444:
|
||||
case GU_PSM_T16:
|
||||
return 2 * width * height;
|
||||
|
||||
case GU_PSM_8888:
|
||||
case GU_PSM_T32:
|
||||
return 4 * width * height;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void* vGuPointer( void *ptr )
|
||||
{
|
||||
return (void*)((u32)ptr & ~VRAM_BASE);
|
||||
}
|
||||
|
||||
inline void* vCPUPointer( void *ptr )
|
||||
{
|
||||
return (void*)((u32)ptr | VRAM_BASE);
|
||||
}
|
||||
|
||||
/* Find the smallest block that we can allocate AFTER, returning NULL if there
|
||||
are none. */
|
||||
vram_mem_header_t * _vram_mem_fit(vram_mem_header_t *head, size_t size)
|
||||
{
|
||||
vram_mem_header_t *prev_mem = head, *best_fit = NULL;
|
||||
u32 prev_top, next_bot;
|
||||
size_t best_size = 0;
|
||||
|
||||
if (((u32)head->ptr+head->size+size)<VRAM_SIZE) {
|
||||
best_fit = head;
|
||||
best_size = VRAM_SIZE - ((u32)head->ptr+head->size);
|
||||
}
|
||||
|
||||
while (prev_mem != NULL) {
|
||||
if (prev_mem->next != NULL) {
|
||||
prev_top = (u32)prev_mem->ptr;
|
||||
next_bot = prev_top - ((u32)prev_mem->next->ptr + prev_mem->next->size);
|
||||
if (next_bot >= size) {
|
||||
if (best_fit==NULL || next_bot<best_size) {
|
||||
best_fit = prev_mem->next;
|
||||
best_size = next_bot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prev_mem = prev_mem->next;
|
||||
}
|
||||
|
||||
return best_fit;
|
||||
}
|
||||
|
||||
void * valloc(size_t size)
|
||||
{
|
||||
void *ptr = NULL;
|
||||
vram_mem_header_t *new_mem, *prev_mem;
|
||||
size_t mem_sz;
|
||||
|
||||
mem_sz = size;
|
||||
|
||||
if ((mem_sz & (DEFAULT_VALIGNMENT - 1)) != 0)
|
||||
mem_sz = ALIGN(mem_sz, DEFAULT_VALIGNMENT);
|
||||
|
||||
|
||||
/* If we don't have any allocated blocks, reserve the first block
|
||||
and initialize __valloc_vram_tail. */
|
||||
if (__valloc_vram_head == NULL) {
|
||||
if (size>VRAM_SIZE)
|
||||
return ptr;
|
||||
|
||||
__valloc_vram_head = (vram_mem_header_t *)malloc( sizeof(vram_mem_header_t) );
|
||||
if (__valloc_vram_head == NULL)
|
||||
return ptr;
|
||||
|
||||
ptr = (void *)__valloc_vram_base;
|
||||
|
||||
|
||||
__valloc_vram_head->ptr = ptr;
|
||||
__valloc_vram_head->size = mem_sz;
|
||||
__valloc_vram_head->prev = NULL;
|
||||
__valloc_vram_head->next = NULL;
|
||||
|
||||
__valloc_vram_tail = __valloc_vram_head;
|
||||
|
||||
return vabsptr(ptr);
|
||||
}
|
||||
|
||||
/* Check to see if there's free space at the bottom of the heap.
|
||||
NOTE: This case is now already handled in _vram_mem_fit */
|
||||
/*if (((u32)__valloc_vram_head->ptr + __valloc_vram_head->size + mem_sz) < VRAM_SIZE) {
|
||||
new_mem = (vram_mem_header_t *)malloc( sizeof(vram_mem_header_t) );
|
||||
if (new_mem == NULL)
|
||||
return ptr;
|
||||
ptr = (void *)((u32)__valloc_vram_head->ptr + __valloc_vram_head->size);
|
||||
|
||||
new_mem->ptr = ptr;
|
||||
new_mem->size = mem_sz;
|
||||
new_mem->prev = NULL;
|
||||
new_mem->next = __valloc_vram_head;
|
||||
new_mem->next->prev = new_mem;
|
||||
__valloc_vram_head = new_mem;
|
||||
|
||||
return ptr;
|
||||
}*/
|
||||
|
||||
/* See if we can allocate the block anywhere. */
|
||||
prev_mem = _vram_mem_fit(__valloc_vram_head, mem_sz);
|
||||
if (prev_mem != NULL) {
|
||||
new_mem = (vram_mem_header_t *)malloc( sizeof(vram_mem_header_t) );
|
||||
if (new_mem == NULL)
|
||||
return ptr;
|
||||
ptr = (void *)((u32)prev_mem->ptr + prev_mem->size);
|
||||
|
||||
new_mem->ptr = ptr;
|
||||
new_mem->size = mem_sz;
|
||||
new_mem->prev = prev_mem->prev;
|
||||
if (new_mem->prev!=NULL)
|
||||
new_mem->prev->next = new_mem;
|
||||
new_mem->next = prev_mem;
|
||||
prev_mem->prev = new_mem;
|
||||
if (prev_mem == __valloc_vram_head)
|
||||
__valloc_vram_head = new_mem;
|
||||
|
||||
return vabsptr(ptr);
|
||||
}
|
||||
|
||||
/* Now we have a problem: There's no room at the bottom and also no room in between.
|
||||
So either we do compact the memory (time critical because memcopies needed) or we
|
||||
just return NULL so the application has to handle this case itself.
|
||||
For now we'll just return NULL
|
||||
*/
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vfree(void *ptr)
|
||||
{
|
||||
vram_mem_header_t *cur;
|
||||
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
if (!__valloc_vram_head)
|
||||
return;
|
||||
|
||||
ptr = vrelptr(ptr);
|
||||
|
||||
/* Freeing the head pointer is a special case. */
|
||||
if (ptr == __valloc_vram_head->ptr) {
|
||||
|
||||
cur = __valloc_vram_head->next;
|
||||
free(__valloc_vram_head);
|
||||
|
||||
__valloc_vram_head = cur;
|
||||
|
||||
if (__valloc_vram_head != NULL) {
|
||||
__valloc_vram_head->prev = NULL;
|
||||
} else {
|
||||
__valloc_vram_tail = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cur = __valloc_vram_head;
|
||||
while (ptr != cur->ptr) {
|
||||
/* ptr isn't in our list */
|
||||
if (cur->next == NULL) {
|
||||
return;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
/* Deallocate the block. */
|
||||
if (cur->next != NULL) {
|
||||
cur->next->prev = cur->prev;
|
||||
} else {
|
||||
/* If this block was the last one in the list, shrink the heap. */
|
||||
__valloc_vram_tail = cur->prev;
|
||||
}
|
||||
|
||||
cur->prev->next = cur->next;
|
||||
free( cur );
|
||||
|
||||
}
|
||||
|
||||
|
||||
size_t vmemavail()
|
||||
{
|
||||
if (__valloc_vram_head==NULL)
|
||||
return VRAM_SIZE;
|
||||
|
||||
vram_mem_header_t *cur;
|
||||
size_t size = VRAM_SIZE - ((u32)__valloc_vram_head->ptr + __valloc_vram_head->size);
|
||||
|
||||
cur = __valloc_vram_head;
|
||||
while (cur->next!=NULL) {
|
||||
size += (u32)cur->ptr - ((u32)cur->next->ptr + cur->next->size);
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
size_t vlargestblock()
|
||||
{
|
||||
if (__valloc_vram_head==NULL)
|
||||
return VRAM_SIZE;
|
||||
|
||||
vram_mem_header_t *cur;
|
||||
size_t size = VRAM_SIZE - ((u32)__valloc_vram_head->ptr + __valloc_vram_head->size);
|
||||
size_t new_size;
|
||||
|
||||
cur = __valloc_vram_head;
|
||||
while (cur->next!=NULL) {
|
||||
new_size = (u32)cur->ptr - ((u32)cur->next->ptr + cur->next->size);
|
||||
if (new_size>size) size = new_size;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
275
JGE/src/vram.c
Normal file
275
JGE/src/vram.c
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Helper for use with the PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under GPL
|
||||
*
|
||||
* vram.c - Standard C high performance VRAM allocation routines.
|
||||
*
|
||||
* Copyright (c) 2007 Alexander Berl 'Raphael' <raphael@fx-world.org>
|
||||
* http://wordpress.fx-world.org
|
||||
*
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "vram.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// Configure the memory to be managed
|
||||
#define __MEM_SIZE 0x00200000
|
||||
#define __MEM_START 0x04000000
|
||||
|
||||
// Configure the block size the memory gets subdivided into (page size)
|
||||
// __MEM_SIZE/__BLOCK_SIZE may not exceed 2^15 = 32768
|
||||
// The block size also defines the alignment of allocations
|
||||
// Larger block sizes perform better, because the blocktable is smaller and therefore fits better into cache
|
||||
// however the overhead is also bigger and more memory is wasted
|
||||
#define __BLOCK_SIZE 512
|
||||
#define __MEM_BLOCKS (__MEM_SIZE/__BLOCK_SIZE)
|
||||
#define __BLOCKS(x) ((x+__BLOCK_SIZE-1)/__BLOCK_SIZE)
|
||||
#define __BLOCKSIZE(x) ((x+__BLOCK_SIZE-1)&~(__BLOCK_SIZE-1))
|
||||
|
||||
|
||||
// A MEMORY BLOCK ENTRY IS MADE UP LIKE THAT:
|
||||
// bit: 31 32 30 - 15 14-0
|
||||
// free block prev size
|
||||
//
|
||||
// bit 31: free bit, indicating if block is allocated or not
|
||||
// bit 30: blocked bit, indicating if block is part of a larger block (0) - used for error resilience
|
||||
// bit 30-15: block index of previous block
|
||||
// bit 14- 0: size of current block
|
||||
//
|
||||
// This management can handle a max amount of 2^15 = 32768 blocks, which resolves to 32MB at blocksize of 1024 bytes
|
||||
//
|
||||
#define __BLOCK_GET_SIZE(x) ((x & 0x7FFF))
|
||||
#define __BLOCK_GET_PREV(x) ((x >> 15) & 0x7FFF)
|
||||
#define __BLOCK_GET_FREE(x) ((x >> 31))
|
||||
#define __BLOCK_GET_BLOCK(x) ((x >> 30) & 0x1)
|
||||
#define __BLOCK_SET_SIZE(x,y) x=((x & ~0x7FFF) | ((y) & 0x7FFF))
|
||||
#define __BLOCK_ADD_SIZE(x,y) x=((x & ~0x7FFF) | (((x & 0x7FFF)+((y) & 0x7FFF)) & 0x7FFF))
|
||||
#define __BLOCK_SET_PREV(x,y) x=((x & ~0x3FFF8000) | (((y) & 0x7FFF)<<15))
|
||||
#define __BLOCK_SET_FREE(x,y) x=((x & 0x7FFFFFFF) | (((y) & 0x1)<<31))
|
||||
#define __BLOCK_SET_BLOCK(x,y) x=((x & 0xBFFFFFFF) | (((y) & 0x1)<<30))
|
||||
#define __BLOCK_MAKE(s,p,f,n) (((f & 0x1)<<31) | ((n & 0x1)<<30) | (((p) & 0x7FFF)<<15) | ((s) & 0x7FFF))
|
||||
#define __BLOCK_GET_FREEBLOCK(x) ((x>>30) & 0x3) // returns 11b if block is a starting block and free, 10b if block is a starting block and allocated, 0xb if it is a non-starting block (don't change)
|
||||
#define __BLOCK0 ((__MEM_BLOCKS) | (1<<31) | (1<<30))
|
||||
|
||||
|
||||
unsigned int __mem_blocks[__MEM_BLOCKS] = { 0 };
|
||||
|
||||
|
||||
static int __largest_update = 0;
|
||||
static int __largest_block = __MEM_BLOCKS;
|
||||
static int __mem_free = __MEM_BLOCKS;
|
||||
|
||||
|
||||
inline void* vrelptr( void *ptr )
|
||||
{
|
||||
return (void*)((unsigned int)ptr & ~__MEM_START);
|
||||
}
|
||||
|
||||
inline void* vabsptr( void *ptr )
|
||||
{
|
||||
return (void*)((unsigned int)ptr | __MEM_START);
|
||||
}
|
||||
|
||||
|
||||
static void __find_largest_block()
|
||||
{
|
||||
int i = 0;
|
||||
__largest_block = 0;
|
||||
while (i<__MEM_BLOCKS)
|
||||
{
|
||||
int csize = __BLOCK_GET_SIZE(__mem_blocks[i]);
|
||||
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[i])==3 && csize>__largest_block)
|
||||
__largest_block = csize;
|
||||
i += csize;
|
||||
}
|
||||
__largest_update = 0;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
void __memwalk()
|
||||
{
|
||||
int i = 0;
|
||||
if (__mem_blocks[0]==0) __mem_blocks[0] = __BLOCK0;
|
||||
while (i<__MEM_BLOCKS)
|
||||
{
|
||||
printf("BLOCK %i:\n", i);
|
||||
printf(" free: %i\n", __BLOCK_GET_FREEBLOCK(__mem_blocks[i]));
|
||||
printf(" size: %i\n", __BLOCK_GET_SIZE(__mem_blocks[i]));
|
||||
printf(" prev: %i\n", __BLOCK_GET_PREV(__mem_blocks[i]));
|
||||
i+=__BLOCK_GET_SIZE(__mem_blocks[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void* valloc( size_t size )
|
||||
{
|
||||
// Initialize memory block, if not yet done
|
||||
if (__mem_blocks[0]==0) __mem_blocks[0] = __BLOCK0;
|
||||
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int bsize = __BLOCKS(size);
|
||||
|
||||
if (__largest_update==0 && __largest_block<bsize)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("Not enough memory to allocate %i bytes (largest: %i)!\n",size,vlargestblock());
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("allocating %i bytes, in %i blocks\n", size, bsize);
|
||||
#endif
|
||||
// Find smallest block that still fits the requested size
|
||||
int bestblock = -1;
|
||||
int bestblock_prev = 0;
|
||||
int bestblock_size = __MEM_BLOCKS+1;
|
||||
while (i<__MEM_BLOCKS)
|
||||
{
|
||||
int csize = __BLOCK_GET_SIZE(__mem_blocks[i]);
|
||||
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[i])==3 && csize>=bsize)
|
||||
{
|
||||
if (csize<bestblock_size)
|
||||
{
|
||||
bestblock = i;
|
||||
bestblock_prev = j;
|
||||
bestblock_size = csize;
|
||||
}
|
||||
|
||||
if (csize==bsize)
|
||||
break;
|
||||
}
|
||||
j = i;
|
||||
i += csize;
|
||||
}
|
||||
|
||||
if (bestblock<0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("Not enough memory to allocate %i bytes (largest: %i)!\n",size,vlargestblock());
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
|
||||
i = bestblock;
|
||||
j = bestblock_prev;
|
||||
int csize = bestblock_size;
|
||||
__mem_blocks[i] = __BLOCK_MAKE(bsize,j,0,1);
|
||||
|
||||
int next = i+bsize;
|
||||
if (csize>bsize && next<__MEM_BLOCKS)
|
||||
{
|
||||
__mem_blocks[next] = __BLOCK_MAKE(csize-bsize,i,1,1);
|
||||
int nextnext = i+csize;
|
||||
if (nextnext<__MEM_BLOCKS)
|
||||
{
|
||||
__BLOCK_SET_PREV(__mem_blocks[nextnext], next);
|
||||
}
|
||||
}
|
||||
|
||||
__mem_free -= bsize;
|
||||
if (__largest_block==csize) // if we just allocated from one of the largest blocks
|
||||
{
|
||||
if ((csize-bsize)>(__mem_free/2))
|
||||
__largest_block = (csize-bsize); // there can't be another largest block
|
||||
else
|
||||
__largest_update = 1;
|
||||
}
|
||||
return ((void*)(__MEM_START + (i*__BLOCK_SIZE)));
|
||||
}
|
||||
|
||||
|
||||
void vfree( void* ptr )
|
||||
{
|
||||
if (ptr==0) return;
|
||||
|
||||
int block = ((unsigned int)ptr - __MEM_START)/__BLOCK_SIZE;
|
||||
if (block<0 || block>__MEM_BLOCKS)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("Block is out of range: %i (0x%x)\n", block, (int)ptr);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
int csize = __BLOCK_GET_SIZE(__mem_blocks[block]);
|
||||
#ifdef _DEBUG
|
||||
printf("freeing block %i (0x%x), size: %i\n", block, (int)ptr, csize);
|
||||
#endif
|
||||
|
||||
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[block])!=1 || csize==0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("Block was not allocated!\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark block as free
|
||||
__BLOCK_SET_FREE(__mem_blocks[block],1);
|
||||
__mem_free += csize;
|
||||
|
||||
int next = block+csize;
|
||||
// Merge with previous block if possible
|
||||
int prev = __BLOCK_GET_PREV(__mem_blocks[block]);
|
||||
if (prev<block)
|
||||
{
|
||||
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[prev])==3)
|
||||
{
|
||||
__BLOCK_ADD_SIZE(__mem_blocks[prev], csize);
|
||||
__BLOCK_SET_BLOCK(__mem_blocks[block],0); // mark current block as inter block
|
||||
if (next<__MEM_BLOCKS)
|
||||
__BLOCK_SET_PREV(__mem_blocks[next], prev);
|
||||
block = prev;
|
||||
}
|
||||
}
|
||||
|
||||
// Merge with next block if possible
|
||||
if (next<__MEM_BLOCKS)
|
||||
{
|
||||
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[next])==3)
|
||||
{
|
||||
__BLOCK_ADD_SIZE(__mem_blocks[block], __BLOCK_GET_SIZE(__mem_blocks[next]));
|
||||
__BLOCK_SET_BLOCK(__mem_blocks[next],0); // mark next block as inter block
|
||||
int nextnext = next + __BLOCK_GET_SIZE(__mem_blocks[next]);
|
||||
if (nextnext<__MEM_BLOCKS)
|
||||
__BLOCK_SET_PREV(__mem_blocks[nextnext], block);
|
||||
}
|
||||
}
|
||||
|
||||
// Update if a new largest block emerged
|
||||
if (__largest_block<__BLOCK_GET_SIZE(__mem_blocks[block]))
|
||||
{
|
||||
__largest_block = __BLOCK_GET_SIZE(__mem_blocks[block]);
|
||||
__largest_update = 0; // No update necessary any more, because update only necessary when largest has shrinked at most
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t vmemavail()
|
||||
{
|
||||
return __mem_free * __BLOCK_SIZE;
|
||||
}
|
||||
|
||||
|
||||
size_t vlargestblock()
|
||||
{
|
||||
if (__largest_update) __find_largest_block();
|
||||
return __largest_block * __BLOCK_SIZE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user