summaryrefslogblamecommitdiff
path: root/arm9/source/devices/memory.c
blob: 915aec20c2cdc614e8194ac6bc28329779258acc (plain) (tree)













































































































































                                                                                     
#include "nds.h"
#include "memory.h"

static u8 heap[HEAP_SIZE][256];  // the page heap.
static u8 unallocated[256];      // page to use for all unallocated reads and writes.
static u8 heap_index[HEAP_SIZE];

u8 mem_read1(MemoryDevice *mem) {
    u8 output = mem->point1[mem->byte1++];
    if (mem->byte1 == 0) {
        mem->page1++;
        mem_get_page1(mem);
    }
    return output;
}

u8 mem_read2(MemoryDevice *mem) {
    u8 output = mem->point2[mem->byte2++];
    if (mem->byte2 == 0) {
        mem->page2++;
        mem_get_page2(mem);
    }
    return output;
}

void mem_write1(MemoryDevice *mem, u8 value) {
    mem->point1[mem->byte1++] = value;
    if (mem->byte1 == 0) {
        mem->page1++;
        mem_get_page1(mem);
    }
}

void mem_write2(MemoryDevice *mem, u8 value) {
    mem->point2[mem->byte2++] = value;
    if (mem->byte2 == 0) {
        mem->page2++;
        mem_get_page2(mem);
    }
}


void mem_load_cache1(MemoryDevice *mem) {
    // Set all cached pointers to unallocated.
    for (int i=0; i<256; i++) {
        mem->cache1[i] = (u8*) &unallocated;
    }
    // Iterate over all heap pages, gather our ones.
    int count = 0;
    int cached = 0;
    for (int i=0; i<HEAP_SIZE; i++) {
        if (heap_index[i] == mem->id) {
            if (count >= mem->offset1) {
                mem->cache1[cached] = (u8*) &heap[i];
                cached++;
            }
            count++;
            if (cached == 256) break;
        }
    }
}

void mem_load_cache2(MemoryDevice *mem) {
    // Set all cached pointers to unallocated.
    for (int i=0; i<256; i++) {
        mem->cache2[i] = (u8*) &unallocated;
    }
    // Iterate over all heap pages, gather our ones.
    int count = 0;
    int cached = 0;
    for (int i=0; i<HEAP_SIZE; i++) {
        if (heap_index[i] == mem->id) {
            if (count >= mem->offset2) {
                mem->cache2[cached] = (u8*) &heap[i];
                cached++;
            }
            count++;
            if (cached == 256) break;
        }
    }
}

// Fetch the page1 pointer from cache1.
void mem_get_page1(MemoryDevice *mem) {
    mem->point1 = mem->cache1[mem->page1];
}

// Fetch the page2 pointer from cache2.
void mem_get_page2(MemoryDevice *mem) {
    mem->point2 = mem->cache2[mem->page2];
}

void mem_allocate(MemoryDevice *mem) {
    int count = 0;

    // ALLOCATING
    if (mem->count_write > mem->count) {
        int to_allocate = mem->count_write - mem->count;
        for (int i=0; i<HEAP_SIZE; i++) {
            if (heap_index[i] == 0) {
                heap_index[i] = mem->id;
                count++;
                if (count == to_allocate) {
                    break;
                }
            }
        }
    // DEALLOCATING
    } else if (mem->count_write < mem->count) {
        for (int i=0; i<HEAP_SIZE; i++) {
            if (heap_index[i] == mem->id) {
                count++;
                if (count > mem->count_write) {
                    heap_index[i] = 0;
                    memset(heap[i], 0, 256);
                }
            }
        }
    }

    // Count the number of pages allocated to us.
    mem->count = 0;
    for (int i=0; i<HEAP_SIZE; i++) {
        if (heap_index[i]==mem->id) mem->count++;
    }
    // Reload the pointer caches for each head.
    mem_load_cache1(mem);
    mem_load_cache2(mem);
}


void mem_do_copy(MemoryDevice *mem) {
    int src = mem->offset2;
    int dest = mem->offset1;
    if (src == dest) return;
    for (int i=0; i<mem->copy_write; i++) {
        if (src>=mem->count || dest>=mem->count) {
            return;
        }
        memcpy(&heap[dest++], &heap[src++], 256);
    }
}