Trying to build a forth runtime in C
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
forth/src/fh_mem.c

172 lines
3.8 KiB

3 years ago
#include <string.h>
3 years ago
#include "fh_print.h"
#include "fh_error.h"
3 years ago
#include "fh_runtime.h"
#include "fh_mem.h"
3 years ago
void fh_setbase(struct fh_thread_s *fh, uint32_t base) {
LOG("BASE = %d", base);
fh->base = base;
}
3 years ago
enum fh_error fh_fetch(struct fh_thread_s *fh, uint32_t addr, uint32_t *dst)
{
switch (addr) {
case MAGICADDR_BASE:
*dst = fh->base;
break;
case MAGICADDR_HERE:
*dst = fh->heap_top;
break;
3 years ago
default:
if (addr & 3) {
LOGE("Address 0x%08x is not aligned!", addr);
return FH_ERR_ILLEGAL_FETCH;
}
if (addr < HEAP_SIZE - 4) {
*dst = *((uint32_t*)&fh->heap[addr]);
} else {
LOGE("Address 0x%08x too high!", addr);
return FH_ERR_ILLEGAL_FETCH;
}
}
return FH_OK;
}
enum fh_error fh_fetch_char(struct fh_thread_s *fh, uint32_t addr, char *dst)
{
if (addr < HEAP_SIZE - 4) {
*dst = (char) fh->heap[addr];
} else {
LOGE("Address 0x%08x too high!", addr);
return FH_ERR_ILLEGAL_FETCH;
}
return FH_OK;
}
enum fh_error fh_store(struct fh_thread_s *fh, uint32_t addr, uint32_t val)
{
switch (addr) {
case MAGICADDR_BASE:
3 years ago
fh_setbase(fh, val);
3 years ago
break;
case MAGICADDR_HERE:
LOGE("HERE is read-only!");
return FH_ERR_ILLEGAL_STORE;
3 years ago
default:
if (addr & 3) {
LOGE("Address 0x%08x is not aligned!", addr);
return FH_ERR_ILLEGAL_STORE;
3 years ago
}
if (addr <= HEAP_SIZE - 4) {
*((uint32_t*)&fh->heap[addr]) = val;
} else {
LOGE("Address 0x%08x too high!", addr);
return FH_ERR_ILLEGAL_STORE;
3 years ago
}
}
return FH_OK;
}
enum fh_error fh_store_char(struct fh_thread_s *fh, uint32_t addr, char val)
{
if (addr < HEAP_SIZE) {
fh->heap[addr] = val;
} else {
LOGE("Address 0x%08x too high!", addr);
return FH_ERR_ILLEGAL_FETCH;
}
return FH_OK;
}
3 years ago
/** Allocate a heap region, e.g. for a string. The address is stored to `addr` */
enum fh_error fh_heap_reserve(
struct fh_thread_s *fh,
size_t len,
uint32_t *addr
)
{
uint32_t p = fh->heap_top;
3 years ago
if (p + len > HEAP_SIZE) {
return FH_ERR_HEAP_FULL;
}
if (addr) {
*addr = p;
}
3 years ago
fh->heap_top = WORDALIGNED(p + len);
return FH_OK;
}
/** Write bytes to heap at a given location. The region must have been previously allocated! */
void fh_heap_write(struct fh_thread_s *fh, uint32_t addr, const void *src, uint32_t len)
{
memcpy(&fh->heap[addr], src, len);
}
/** Allocate heap region and write bytes to it */
enum fh_error fh_heap_put(struct fh_thread_s *fh, const void *src, uint32_t len)
{
enum fh_error rv;
uint32_t addr;
TRY(fh_heap_reserve(fh, len, &addr));
fh_heap_write(fh, addr, src, len);
return FH_OK;
}
/** Copy bytes from compile area to heap. The region must have been previously allocated! */
void fh_heap_copy_from_compile(struct fh_thread_s *fh, uint32_t addr, uint32_t srcaddr, uint32_t len)
{
memcpy(&fh->heap[addr], &fh->compile[srcaddr], len);
}
/** Reserve space in the compile memory area */
enum fh_error fh_compile_reserve(
struct fh_thread_s *fh,
size_t len,
uint32_t *addr
)
{
uint32_t p = fh->compile_top; // FIXME this shouldn't be needed
3 years ago
if (p + len > COMPILED_BUFFER_SIZE) {
return FH_ERR_HEAP_FULL;
}
if (addr) {
*addr = p;
}
3 years ago
fh->compile_top = WORDALIGNED(p + len);
return FH_OK;
}
/** Write bytes to compile area at a given location. The region must have been previously allocated! */
void fh_compile_write(struct fh_thread_s *fh, uint32_t addr, const void *src, uint32_t len)
{
memcpy(&fh->compile[addr], src, len);
}
/** Allocate compile region and write bytes to it */
enum fh_error fh_compile_put(struct fh_thread_s *fh, const void *src, uint32_t len)
{
enum fh_error rv;
uint32_t addr;
TRY(fh_compile_reserve(fh, len, &addr));
fh_compile_write(fh, addr, src, len);
return FH_OK;
}