📄 hw_memory.c
字号:
/* get the address from the stack */ { int nr_cells = device_nr_address_cells(device_parent(me)); if (alignment != 0) { if (n_stack_args != stackp) { if (n_stack_args == stackp + nr_cells) DTRACE(memory, ("claim - extra address argument ignored\n")); else device_error(me, "claim - incorrect number of arguments (optional addr)"); } address = 0; } else { int i; if (n_stack_args != stackp + nr_cells) device_error(me, "claim - incorrect number of arguments (addr missing)"); for (i = 0; i < nr_cells - 1; i++) { if (stack_args[stackp] != 0) device_error(me, "claim - multi-cell addresses not supported"); stackp++; } address = stack_args[stackp]; } } /* check that there is space for the result */ if (n_stack_returns != 0 && n_stack_returns != device_nr_address_cells(device_parent(me))) device_error(me, "claim - invalid number of return arguments"); /* find a chunk candidate, either according to address or alignment */ if (alignment == 0) { chunk = hw_memory->heap; while (chunk != NULL) { if ((address + size) <= (chunk->address + chunk->size)) break; chunk = chunk->next; } if (chunk == NULL || address < chunk->address || !chunk->available) device_error(me, "failed to allocate %ld bytes at 0x%lx", (unsigned long)size, (unsigned long)address); DTRACE(memory, ("claim - address=0x%lx size=0x%lx\n", (unsigned long)address, (unsigned long)size)); } else { /* adjust the alignment so that it is a power of two */ unsigned_word align_mask = 1; while (align_mask < alignment && align_mask != 0) align_mask <<= 1; if (align_mask == 0) device_error(me, "alignment 0x%lx is to large", (unsigned long)alignment); align_mask -= 1; /* now find an aligned chunk that fits */ chunk = hw_memory->heap; while (chunk != NULL) { address = ((chunk->address + align_mask) & ~align_mask); if ((chunk->available) && (chunk->address + chunk->size >= address + size)) break; chunk = chunk->next; } if (chunk == NULL) device_error(me, "failed to allocate %ld bytes with alignment %ld", (unsigned long)size, (unsigned long)alignment); DTRACE(memory, ("claim - size=0x%lx alignment=%ld (0x%lx), address=0x%lx\n", (unsigned long)size, (unsigned long)alignment, (unsigned long)alignment, (unsigned long)address)); } /* break off a bit before this chunk if needed */ ASSERT(address >= chunk->address); if (address > chunk->address) { hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk); /* insert a new chunk */ next_chunk->next = chunk->next; chunk->next = next_chunk; /* adjust the address/size */ next_chunk->address = address; next_chunk->size = chunk->address + chunk->size - next_chunk->address; next_chunk->available = 1; chunk->size = next_chunk->address - chunk->address; /* make this new chunk the one to allocate */ chunk = next_chunk; } ASSERT(address == chunk->address); /* break off a bit after this chunk if needed */ ASSERT(address + size <= chunk->address + chunk->size); if (address + size < chunk->address + chunk->size) { hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk); /* insert it in to the list */ next_chunk->next = chunk->next; chunk->next = next_chunk; /* adjust the address/size */ next_chunk->address = address + size; next_chunk->size = chunk->address + chunk->size - next_chunk->address; next_chunk->available = 1; chunk->size = next_chunk->address - chunk->address; } ASSERT(address + size == chunk->address + chunk->size); /* now allocate/return it */ chunk->available = 0; hw_memory_set_available(device_instance_device(instance), hw_memory); if (n_stack_returns > 0) { int i; for (i = 0; i < n_stack_returns - 1; i++) stack_returns[i] = 0; stack_returns[n_stack_returns - 1] = address; } return 0;}static inthw_memory_instance_release(device_instance *instance, int n_stack_args, unsigned_cell stack_args[/*n_stack_args*/], int n_stack_returns, unsigned_cell stack_returns[/*n_stack_returns*/]){ hw_memory_device *hw_memory = device_instance_data(instance); device *me = device_instance_device(instance); unsigned_word length; unsigned_word address; int stackp = 0; hw_memory_chunk *chunk; /* get the length from the stack */ { int i; int nr_cells = device_nr_size_cells(device_parent(me)); if (n_stack_args < stackp + nr_cells) device_error(me, "release - incorrect number of arguments (length missing)"); for (i = 0; i < nr_cells - 1; i++) { if (stack_args[stackp] != 0) device_error(me, "release - multi-cell length not supported"); stackp++; } length = stack_args[stackp]; stackp++; } /* get the address from the stack */ { int i; int nr_cells = device_nr_address_cells(device_parent(me)); if (n_stack_args != stackp + nr_cells) device_error(me, "release - incorrect number of arguments (addr missing)"); for (i = 0; i < nr_cells - 1; i++) { if (stack_args[stackp] != 0) device_error(me, "release - multi-cell addresses not supported"); stackp++; } address = stack_args[stackp]; } /* returns ok */ if (n_stack_returns != 0) device_error(me, "release - nonzero number of results"); /* try to free the corresponding memory chunk */ chunk = hw_memory->heap; while (chunk != NULL) { if (chunk->address == address && chunk->size == length) { /* an exact match */ if (chunk->available) device_error(me, "memory chunk 0x%lx (size 0x%lx) already available", (unsigned long)address, (unsigned long)length); else { /* free this chunk */ DTRACE(memory, ("release - address=0x%lx, length=0x%lx\n", (unsigned long) address, (unsigned long) length)); chunk->available = 1; break; } } else if (chunk->address >= address && chunk->address + chunk->size <= address + length) { /* a sub region */ if (!chunk->available) { DTRACE(memory, ("release - address=0x%lx, size=0x%lx within region 0x%lx length 0x%lx\n", (unsigned long) chunk->address, (unsigned long) chunk->size, (unsigned long) address, (unsigned long) length)); chunk->available = 1; } } chunk = chunk->next; } if (chunk == NULL) { printf_filtered("warning: released chunks within region 0x%lx..0x%lx\n", (unsigned long)address, (unsigned long)(address + length - 1)); } /* check for the chance to merge two adjacent available memory chunks */ chunk = hw_memory->heap; while (chunk != NULL) { if (chunk->available && chunk->next != NULL && chunk->next->available) { /* adjacent */ hw_memory_chunk *delete = chunk->next; ASSERT(chunk->address + chunk->size == delete->address); chunk->size += delete->size; chunk->next = delete->next; zfree(delete); } else { chunk = chunk->next; } } /* update the corresponding property */ hw_memory_set_available(device_instance_device(instance), hw_memory); return 0;}static device_instance_methods hw_memory_instance_methods[] = { { "claim", hw_memory_instance_claim }, { "release", hw_memory_instance_release }, { NULL, },};static device_instance_callbacks const hw_memory_instance_callbacks = { hw_memory_instance_delete, NULL /*read*/, NULL /*write*/, NULL /*seek*/, hw_memory_instance_methods};static device_instance *hw_memory_create_instance(device *me, const char *path, const char *args){ return device_create_instance_from(me, NULL, device_data(me), /* nothing better */ path, args, &hw_memory_instance_callbacks);}static device_callbacks const hw_memory_callbacks = { { hw_memory_init_address, }, { NULL, }, /* address */ { NULL, }, /* IO */ { NULL, }, /* DMA */ { NULL, }, /* interrupt */ { NULL, }, /* unit */ hw_memory_create_instance,};const device_descriptor hw_memory_device_descriptor[] = { { "memory", hw_memory_create, &hw_memory_callbacks }, { NULL },};#endif /* _HW_MEMORY_C_ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -