📄 malloc.c
字号:
#include "malloc.h"#include "as31glue.h"#include "printf.h"#include <8051.h>/* this "simm_id" type is what will normally be passed around, *//* and declared inside of other structs (like playlists, file *//* lists, etc. You can't actually access memory with it until *//* you pass it through a function to turn it into a proper C *//* xdata pointer (see below) */// defined in malloc.h// typedef unsigned long simm_id;/* Normally this complex union won't be used *//* This funny union represents a block/offset memory address *//* and allows it to be passed between functions as a 32 bit *//* long, because SDCC can't pass structs or unions. */// typedef union dram_memory_pointer_struct {typedef union { struct { unsigned int offset; unsigned int block; } part; simm_id addr32;} simm_id_union;#define DATA_PER_BLOCK 4090struct simm_block_struct { unsigned int free_bytes; unsigned int ref_count; unsigned int next; unsigned char bytes[DATA_PER_BLOCK];};static xdata unsigned int first_malloced_block;static xdata unsigned int last_malloced_block;/* don't try this sort of direct hardware access at home! */volatile static xdata at 0xFF0E unsigned int block7000;static xdata at 0x7000 struct simm_block_struct p7;#define DRAM_PAGE_CFG 0xFF00void init_malloc(void){ block7000 = first_malloced_block = \ last_malloced_block = malloc_blocks(1); //printf("malloc 1st: %d\r\n", block7000); p7.next = 0; p7.free_bytes = DATA_PER_BLOCK; p7.ref_count = 0;}#define USE_ASM_MALLOC#ifndef USE_ASM_MALLOCsimm_id simm_malloc(unsigned int num_bytes){ unsigned int block; xdata simm_id_union mem; unsigned int block7000_save; // printf("simm_malloc begin, f=%d\r\n", first_malloced_block); if (num_bytes > DATA_PER_BLOCK) return 0; //P1_3 = 1; block7000_save = block7000; block7000 = last_malloced_block; if (p7.free_bytes < num_bytes) { block = malloc_blocks(1); //printf("malloc Nth: %d\r\n", block7000); p7.next = last_malloced_block = block; block7000 = block; p7.next = 0; p7.free_bytes = DATA_PER_BLOCK; p7.ref_count = 0; } mem.part.offset = 4096 - p7.free_bytes; p7.free_bytes -= num_bytes; p7.ref_count++; //printf("malloc: %d bytes, returning %lx\r\n", num_bytes, mem.addr32); mem.part.block = block7000; block7000 = block7000_save; //P1_3 = 0; return mem.addr32;}#endif#ifdef USE_ASM_MALLOC#pragma SAVE#pragma LESS_PEDANTICsimm_id simm_malloc(unsigned int num_bytes){ num_bytes; // passed in dptr _asm // if (num_bytes > DATA_PER_BLOCK) return 0; mov a, #(65535 - DATA_PER_BLOCK) & 255 add a, dpl mov a, #(65535 - DATA_PER_BLOCK) >> 8 addc a, dph jnc 00001$ clr a // return 0 mov dpl, a mov dph, a mov b, a ret00001$: mov r2, dpl // put num_bytes into r3/r2 mov r3, dph mov dptr, #_last_malloced_block movx a, @dptr mov r4, a // fetch last_malloced_block into r5/r4 inc dptr movx a, @dptr mov r5, a mov dptr, #DRAM_PAGE_CFG + (7 * 2) movx a, @dptr push acc // save caller's addr7 onto stack mov a, r4 movx @dptr, a // and map last_malloced_block @ 7000 inc dptr movx a, @dptr push acc mov a, r5 movx @dptr, a mov dptr, #0x7000 + 0 movx a, @dptr // read p7.free_bytes into r7/r6 mov r6, a clr c subb a, r2 // and compare with num_bytes mov r0, a // and keep result in r1/r0 inc dptr movx a, @dptr mov r7, a subb a, r3 mov r1, a jnc 00002$ // skip if num_bytes <= p7.free_bytes // get another block from drivers.asm and link it into list // this part is not as speed critical, since the normal activity // is packing more stuff into already allocated blocks. push ar2 push ar3 mov dpl, #1 lcall _malloc_blocks mov r4, dpl // store block in r5/r4 mov r5, dph pop ar3 pop ar2 mov dptr, #_last_malloced_block mov a, r4 movx @dptr, a // last_malloced_block = block inc dptr mov a, r5 movx @dptr, a mov dptr, #0x7000 + 4 mov a, r4 movx @dptr, a // p7.next = block inc dptr mov a, r5 movx @dptr, a mov dptr, #DRAM_PAGE_CFG + (7 * 2) mov a, r4 movx @dptr, a // block7000 = block (map new blk at 7000) inc dptr mov a, r5 movx @dptr, a mov dptr, #0x7000 + 2 clr a movx @dptr, a // p7.ref_count = 0 inc dptr movx @dptr, a inc dptr movx @dptr, a // p7.next = 0 inc dptr movx @dptr, a // need to compute r7/r6 and r1/r0 (used below), based on r3/r2 clr c mov a, #DATA_PER_BLOCK & 255 mov r6, a // r7/r6 = DATA_PER_BLOCK subb a, r2 mov r0, a // r1/r0 = DATA_PER_BLOCK - num_bytes mov a, #DATA_PER_BLOCK >> 8 mov r7, a subb a, r3 mov r1, a // end of code within if (p7.free_bytes < num_bytes) ...00002$: mov dptr, #0x7000 + 0 mov a, r0 movx @dptr, a // store p7.free_bytes -= num_bytes inc dptr mov a, r1 movx @dptr, a mov dptr, #0x7000 + 2 movx a, @dptr add a, #1 // increment p7.ref_count movx @dptr, a inc dptr movx a, @dptr addc a, #0 movx @dptr, a mov dptr, #DRAM_PAGE_CFG + (7 * 2) + 1 pop acc movx @dptr, a // restore caller's addr7 mapping mov dptr, #DRAM_PAGE_CFG + (7 * 2) pop acc movx @dptr, a clr c clr a subb a, r6 // compute 4096 - p7.free_bytes mov dpl, a // and return it as mem.offset mov a, #16 subb a, r7 mov dph, a mov b, r4 // return block number as mem.block mov a, r5 _endasm;}#pragma RESTORE#endifvoid simm_free(simm_id addr32){ unsigned int block, next_block; xdata simm_id_union mem; unsigned int block7000_save; block7000_save = block7000; mem.addr32 = addr32; block7000 = mem.part.block; if (--(p7.ref_count) != 0) return; if (mem.part.block == first_malloced_block) { first_malloced_block = p7.next; free_blocks(mem.part.block); block7000 = block7000_save; return; } next_block = p7.next; free_blocks(mem.part.block); for (block = first_malloced_block; block != 0; block = p7.next) { block7000 = block; if (p7.next == mem.part.block) { p7.next = next_block; if (next_block == 0) { last_malloced_block = block; } block7000 = block7000_save; return; } } block7000 = block7000_save; print("Error: could find freed block\r\n");}volatile xdata at 0xFF0A unsigned int addr5_val;volatile xdata at 0xFF0C unsigned int addr6_val;volatile xdata at 0xFF0E unsigned int addr7_val;#pragma LESS_PEDANTIC/* This is the magic function that takes the "pointer" type *//* from malloc and maps the referenced block into the 8051's *//* address space and returns a SDCC xdata * to the memory *//* See http://www.pjrc.com/tech/mp3/mem_map.html for more *//* details about how the DRAM controller page allocation works */xdata void * addr5(simm_id addr32){ addr32; /* suppress unused variable warning */ _asm push dph ;save offset on stack push dpl xch a, b ;keep msb of block in b mov dptr, #DRAM_PAGE_CFG + (5 * 2) ;always map in 5000-5FFF movx @dptr, a inc dptr mov a, b movx @dptr, a ;map the block to 0x5000 pop dpl pop acc anl a, #15 add a, #0x50 mov dph, a ;now dptr points to the users data _endasm;}xdata void * addr6(simm_id addr32){ addr32; /* suppress unused variable warning */ _asm push dph ;save offset on stack push dpl xch a, b ;keep msb of block in b mov dptr, #DRAM_PAGE_CFG + (6 * 2) ;always map in 6000-6FFF movx @dptr, a inc dptr mov a, b movx @dptr, a ;map the block to 0x6000 pop dpl pop acc anl a, #15 add a, #0x60 mov dph, a ;now dptr points to the users data _endasm;}xdata void * addr7(simm_id addr32){ addr32; /* suppress unused variable warning */ _asm push dph ;save offset on stack push dpl xch a, b ;keep msb of block in b mov dptr, #DRAM_PAGE_CFG + (7 * 2) ;always map in 7000-7FFF movx @dptr, a inc dptr mov a, b movx @dptr, a ;map the block to 0x7000 pop dpl pop acc anl a, #15 add a, #0x70 mov dph, a ;now dptr points to the users data _endasm;}// calling addr6(variable) is the same as addr6p(&variable)// except that addr6p does the 32 bit fetch from xdata much// more efficiently than the compiler-generated code can,// and it saves a lot of code space. A preprocessor macro// called Addr6() allows you to use addr6p more easily by// just changing the 'a' to 'A'.xdata void * addr6p(xdata simm_id * xaddr16){ xaddr16; _asm movx a, @dptr ;fetch offset lsb inc dptr push acc ;keep addr lsb on stack movx a, @dptr ;fetch offset msb inc dptr anl a, #15 add a, #0x60 push acc movx a, @dptr ;fetch block lsb inc dptr mov b, a movx a, @dptr ;fetch block msb mov dptr, #DRAM_PAGE_CFG + (6 * 2) + 1 ;always map in 6000-6FFF movx @dptr, a mov a, b mov dptr, #DRAM_PAGE_CFG + (6 * 2) movx @dptr, a pop dph pop dpl _endasm;}#define USE_GOOD_ADDR7xdata void * addr7p(xdata simm_id * xaddr16){ xaddr16;#ifdef USE_GOOD_ADDR7 _asm movx a, @dptr ;fetch offset lsb inc dptr push acc ;keep addr lsb on stack movx a, @dptr ;fetch offset msb inc dptr anl a, #15 add a, #0x70 push acc movx a, @dptr ;fetch block lsb inc dptr mov b, a movx a, @dptr ;fetch block msb mov dptr, #DRAM_PAGE_CFG + (7 * 2) + 1 ;always map in 7000-7FFF movx @dptr, a mov a, b mov dptr, #DRAM_PAGE_CFG + (7 * 2) movx @dptr, a pop dph pop dpl _endasm;#else // Why does this code not work??? Is there some strange // issue with using dual-dptr that I do not understand??? _asm movx a, @dptr ;fetch offset lsb inc dptr push acc ;keep addr lsb on stack movx a, @dptr ;fetch offset msb inc dptr anl a, #15 add a, #0x70 mov b, a ;keep addr msb in b movx a, @dptr ;fetch block lsb inc dptr inc AUXR1 mov dptr, #DRAM_PAGE_CFG + (7 * 2) ;always map in 7000-7FFF movx @dptr, a inc dptr inc AUXR1 movx a, @dptr ;fetch block msb inc AUXR1 movx @dptr, a inc AUXR1 mov dph, b pop dpl _endasm;#if 0 // This also does not work. Maybe there's some bug in the FPGA where // the write to the msb of the dram page mapping registers is messed // up by the previous read?? _asm movx a, @dptr ;fetch offset lsb inc dptr push acc ;keep addr lsb on stack movx a, @dptr ;fetch offset msb inc dptr anl a, #15 add a, #0x70 mov b, a ;keep addr msb in b movx a, @dptr ;fetch block lsb inc dptr push dpl push dph mov dptr, #DRAM_PAGE_CFG + (7 * 2) ;always map in 7000-7FFF movx @dptr, a pop dph pop dpl movx a, @dptr ;fetch block msb mov dptr, #DRAM_PAGE_CFG + (7 * 2) + 1 movx @dptr, a mov dph, b pop dpl _endasm;#endif#endif}/* this function does the opposite of the addrX functions. *//* if you have a pointer to dynamically allocated memory, *//* (which is currently mapped into the processor's address *//* space, you can pass that 16 bit pointer to this function *//* and get the full 32 bit simm_id that represents where *//* that memory is within the SIMM */simm_id simm_id_from_pointer(xdata void *ptr){ ptr; _asm push dpl ;save the pointer, we need it later push dph mov a, dph swap a anl a, #15 ;acc has page # where mapped rl a mov dpl, a ;(LSB of DRAM_PAGE_CFG assumed to be zero) mov dph, #DRAM_PAGE_CFG >> 8 movx a, @dptr ;read LSB of mapped block number inc dptr mov b, a movx a, @dptr ;read MSB of mapped block number pop dph anl dph, #15 ;offset is lower 12 bits of the pointer pop dpl _endasm;}// TODO: test these push/pop functions... do they really work?#define AUXR1 0xA2void push_addr(unsigned char num){ num; _asm inc AUXR1 pop dph pop dpl inc AUXR1 mov a, dpl rl a mov dpl, a mov dph, #DRAM_PAGE_CFG >> 8 movx a, @dptr push acc inc dptr movx a, @dptr push acc inc AUXR1 clr a jmp @a+dptr _endasm;}void pop_addr(unsigned char num){ num; _asm inc AUXR1 pop dph pop dpl inc AUXR1 mov a, dpl rl a mov dpl, a mov dph, #DRAM_PAGE_CFG >> 8 pop b pop acc movx @dptr, a inc dptr mov a, b movx @dptr, a inc AUXR1 clr a jmp @a+dptr _endasm;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -