summaryrefslogtreecommitdiff
path: root/libpsx/src/memory.c
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
commit7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch)
treec28d0748652ad4b4222309e46e6cfc82c0906220 /libpsx/src/memory.c
parenta2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff)
downloadpsxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'libpsx/src/memory.c')
-rw-r--r--libpsx/src/memory.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/libpsx/src/memory.c b/libpsx/src/memory.c
new file mode 100644
index 0000000..e6bb806
--- /dev/null
+++ b/libpsx/src/memory.c
@@ -0,0 +1,215 @@
+/*
+ * memory.c
+ *
+ * PSXSDK malloc() family functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern int __bss_start[];
+extern int __bss_end[];
+
+unsigned int first_free_page;
+
+// 1K granularity and "pages", so more allocations which are small can be done
+
+unsigned char busy_pages[2048];
+unsigned int alloc_size[2048];
+
+// RAM memory map on the PSX
+// 0x80000000 - 0x8000FFFF RAM used by the BIOS
+// 0x80010000 - 0x801FFFFF Program memory
+
+void malloc_setup()
+{
+ int x;
+
+ dprintf("malloc setup.\n");
+
+ first_free_page = (unsigned int) __bss_end;
+ first_free_page-= 0x80000000;
+
+ if(first_free_page & 0x3ff)
+ first_free_page = (first_free_page | 0x3ff) + 1;
+
+ first_free_page>>=10;
+
+ //printf("First free page: %d, bss_end: %x\n", first_free_page, __bss_end);
+
+ for(x = 0; x < first_free_page; x++)
+ {
+ busy_pages[x] = 1; // RAM occupied by program, data and BIOS looks always allocated
+ alloc_size[x] = 1; // Fake that 1K was required
+ }
+
+ for(x = first_free_page; x < 2048; x++)
+ {
+ busy_pages[x] = 0;
+ alloc_size[x] = 0;
+ }
+}
+
+void *malloc(size_t size)
+{
+ dprintf("malloc(%d)\n", size);
+
+ int x, y;
+
+// Round size
+
+ if(size & 0x3ff)
+ size = (size | 0x3ff) + 1;
+
+// Divide it by 1024
+ size >>= 10;
+ //printf("Allocating %dKb\n", size);
+
+// Find a free page
+ for(x = 0; x < 2048; x++)
+ {
+ if(busy_pages[x] == 0)
+ {
+ // If we find a free page, check how many free pages follow it.
+ // If it's enough for the memory we want to allocate, then return
+ // the pointer to the free page we found, otherwise keep finding
+
+ // printf("Page found at %dKb\n", x);
+
+ for(y = 0; y < size; y++)
+ if(busy_pages[x+y] == 1) goto malloc_keep_finding;
+
+ // We found the memory we wanted, now make it busy
+
+ for(y = 0; y < size; y++)
+ busy_pages[x+y] = 1;
+
+ // Store allocation size, it is essential for free()
+
+ alloc_size[x] = size;
+ // printf("malloc(): alloc_size[%d] = %d\n", x, size);
+
+ return (void*)((unsigned int)0x80000000 + (x<<10));
+ }
+malloc_keep_finding:
+ ; // Useless statement to make GCC not bail out...
+ }
+
+// We couldn't find anything, return NULL
+ return NULL;
+}
+
+void *calloc(size_t number, size_t size)
+{
+ void *ptr = malloc(number * size);
+ unsigned char *cptr = (unsigned char*)ptr;
+ int x;
+
+ if(ptr == NULL)
+ ptr = NULL;
+
+ for(x = 0; x < (number * size); x++)
+ cptr[x] = 0;
+
+ return ptr;
+}
+
+void free(void *ptr)
+{
+ dprintf("free(%x)\n", (unsigned int)ptr);
+
+ unsigned int ptri = (unsigned int)ptr;
+ ptri -= 0x80000000;
+ int x;
+
+ if((ptri & 0x3ff) || (busy_pages[ptri>>10] == 0) || (alloc_size[ptri>>10] == 0))
+ {
+ // If the pointer address is not a multiplier of 1K, or the page
+ // is free, it means that memory not allocated by malloc() was passed to free.
+ // Print a warning message and return.
+
+ printf("** free() ** : tried to free memory with invalid pointer at %x\n",
+ ptri + 0x80000000);
+
+ return;
+ }
+
+// Divide ptri by 1024, getting initial page
+
+ ptri>>=10;
+
+// printf("Freeing page at %dKb\n", ptri);
+
+// Free pages
+
+// printf("alloc_size[%d] = %d\n", ptri, alloc_size[ptri]);
+
+ for(x = 0; x < alloc_size[ptri]; x++)
+ {
+ dprintf("ptri + x = %d\n", ptri + x);
+ busy_pages[ptri + x] = 0;
+ }
+
+// Set allocation size to 0, finally freeing initial page
+
+ alloc_size[ptri] = 0;
+
+ /*for(x=150;x<170;x++)
+ printf("%d: %d, %d\n", x, busy_pages[x], alloc_size[x]);*/
+}
+
+void *realloc(void *ptr, size_t size)
+{
+ unsigned int ptri = (unsigned int)ptr;
+ int x;
+ void *newptr;
+
+ if(ptr == NULL)
+ return malloc(size);
+
+ ptri -= 0x80000000;
+
+ size |= 0x3ff;
+ size++;
+
+ size>>=10;
+
+ if((ptri & 0x3ff) || (busy_pages[ptri>>10] == 0) || (alloc_size[ptri>>10] == 0))
+ {
+ // If the pointer address is not a multiplier of 1K, or the page
+ // is free, it means that memory not allocated by malloc() was passed to realloc.
+ // Print a warning message and return.
+
+ printf("** realloc() ** : tried to reallocate memory with invalid pointer at %x\n",
+ ptri + 0x80000000);
+
+ return NULL;
+ }
+
+// Get page
+
+ ptri>>=10;
+
+ if(size < alloc_size[ptri]) // New size smaller than old size
+ {
+ for(x = size; x < alloc_size[ptri]; x++)
+ busy_pages[ptri + x] = 0;
+
+ alloc_size[ptri] = size;
+ }
+ else if(size > alloc_size[ptri]) // New size bigger than old size
+ {
+ newptr = malloc(size * 1024);
+
+ if(newptr == NULL)
+ return NULL;
+
+ memcpy(newptr, ptr, alloc_size[ptri]);
+ free(ptr);
+
+ ptr = newptr;
+ }
+
+ return ptr;
+}