Compare commits
2 Commits
890cada87e
...
af8df2bd6f
| Author | SHA1 | Date |
|---|---|---|
|
|
af8df2bd6f | |
|
|
a217f2bd39 |
|
|
@ -3,6 +3,12 @@
|
|||
#define BLOCK_SIZE (64 * 1024)
|
||||
#define BLOCK_1MB 16
|
||||
|
||||
typedef struct header {
|
||||
size_t size : 31;
|
||||
uint8_t is_free : 1;
|
||||
} header_t;
|
||||
static header_t* head;
|
||||
|
||||
static uintptr_t bump_pointer = (uintptr_t)&__heap_base;
|
||||
static uintptr_t heap_end = BLOCK_1MB * BLOCK_SIZE;
|
||||
IMPORT(grow) void grow(uint32_t blocks);
|
||||
|
|
@ -19,11 +25,117 @@ static void* bump_alloc(uintptr_t n) {
|
|||
return (void*)r;
|
||||
}
|
||||
|
||||
void* malloc(uintptr_t n) {
|
||||
return bump_alloc(n);
|
||||
static header_t* get_next_header(header_t* block) {
|
||||
if (!block) {
|
||||
return NULL;
|
||||
}
|
||||
uint8_t* data = (uint8_t*)(block + 1);
|
||||
uint8_t* next_header = data + block->size;
|
||||
if ((uintptr_t)next_header >= bump_pointer) {
|
||||
return NULL;
|
||||
}
|
||||
return (header_t*)next_header;
|
||||
}
|
||||
|
||||
void free(void* p) { (void)p; }
|
||||
static header_t* get_prev_header(header_t* block) {
|
||||
header_t* curr = head;
|
||||
while (curr) {
|
||||
header_t* next = get_next_header(curr);
|
||||
if (next == block) {
|
||||
return curr;
|
||||
}
|
||||
curr = next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static header_t* get_free_block(size_t size) {
|
||||
header_t* curr = head;
|
||||
while (curr) {
|
||||
if (curr->is_free && curr->size >= size) {
|
||||
return curr;
|
||||
}
|
||||
curr = get_next_header(curr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* malloc(size_t size) {
|
||||
if (!size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
header_t* header = get_free_block(size);
|
||||
if (header) {
|
||||
header->is_free = 0;
|
||||
if (header->size > size + sizeof(header_t) * 2) {
|
||||
size_t old_size = header->size;
|
||||
header->size = size;
|
||||
|
||||
header_t* next = get_next_header(header);
|
||||
next->size = old_size - size - sizeof(header_t);
|
||||
next->is_free = 1;
|
||||
}
|
||||
return (void*)(header + 1);
|
||||
}
|
||||
size_t total_size = sizeof(header_t) + size;
|
||||
|
||||
void* block = bump_alloc(total_size);
|
||||
if (!block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
header = block;
|
||||
header->size = size;
|
||||
header->is_free = 0;
|
||||
|
||||
if (!head) {
|
||||
head = header;
|
||||
}
|
||||
|
||||
return (void*)(header + 1);
|
||||
}
|
||||
|
||||
void free(void* block) {
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
|
||||
header_t* header = ((header_t*)block) - 1;
|
||||
if (header->is_free) {
|
||||
return;
|
||||
}
|
||||
header->is_free = 1;
|
||||
|
||||
header_t* next_header = get_next_header(header);
|
||||
if (next_header && next_header->is_free) {
|
||||
header->size += next_header->size + sizeof(header_t);
|
||||
}
|
||||
|
||||
header_t* prev_header = get_prev_header(header);
|
||||
if (prev_header && prev_header->is_free) {
|
||||
prev_header->size += header->size + sizeof(header_t);
|
||||
}
|
||||
}
|
||||
|
||||
void* realloc(void* block, size_t size) {
|
||||
header_t* header;
|
||||
void* ret;
|
||||
|
||||
if (!block || !size)
|
||||
return malloc(size);
|
||||
|
||||
header = (header_t*)block - 1;
|
||||
if (header->size >= size)
|
||||
return block;
|
||||
|
||||
ret = malloc(size);
|
||||
if (ret) {
|
||||
memcpy(ret, block, header->size);
|
||||
free(block);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* memset(void* s, uint8_t c, uint32_t n) {
|
||||
uint8_t* p = (uint8_t*)s;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,12 @@ extern unsigned char __heap_base;
|
|||
#define IMPORT(name) __attribute__((import_module("env"), import_name(#name)))
|
||||
#define EXPORT(name) __attribute__((export_name(#name)))
|
||||
|
||||
EXPORT(malloc) void* malloc(uintptr_t);
|
||||
void free(void*);
|
||||
#define NULL ((void*)0)
|
||||
|
||||
typedef uint32_t size_t;
|
||||
|
||||
EXPORT(malloc) void* malloc(size_t);
|
||||
EXPORT(free) void free(void*);
|
||||
|
||||
void* memset(void* s, uint8_t c, uint32_t n);
|
||||
void* memcpy(void* dest, const void* src, uint32_t n);
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ const canvas = createCanvas(width, height);
|
|||
const context = canvas.getContext('2d')!;
|
||||
const imageData = context.createImageData(width, height);
|
||||
|
||||
const initField = life.initField as CallableFunction;
|
||||
const step = life.step as CallableFunction;
|
||||
const pixels = new Uint8Array(life.memory.buffer, life.getPixels(), width * height * 4);
|
||||
let pixels: Uint8Array;
|
||||
|
||||
export default function main() {
|
||||
initField(Date.now());
|
||||
const pixelsPtr = life.initField(Date.now());
|
||||
pixels = new Uint8Array(life.memory.buffer, pixelsPtr, width * height * 4);
|
||||
|
||||
console.log(life, pixels.length);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,27 +4,28 @@
|
|||
#define width 512
|
||||
#define height 512
|
||||
|
||||
static uint8_t field[width * height];
|
||||
static uint8_t nextField[width * height];
|
||||
static uint8_t pixels[width * height * 4];
|
||||
static uint8_t* field;
|
||||
static uint8_t* nextField;
|
||||
static uint8_t* pixels;
|
||||
|
||||
static uint8_t rand8(void);
|
||||
static int countNeighbours(int x, int y);
|
||||
|
||||
EXPORT(getWidth) int get_width(void) { return width; }
|
||||
EXPORT(getHeight) int get_height(void) { return height; }
|
||||
EXPORT(getPixels) uint8_t* get_pixels(void) { return pixels; }
|
||||
|
||||
EXPORT(step) void step(void)
|
||||
{
|
||||
EXPORT(step) void step(void) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int count = countNeighbours(x, y);
|
||||
uint8_t currentCell = field[x + y * width];
|
||||
int nextCell = currentCell;
|
||||
if (currentCell && count < 2) nextCell = 0;
|
||||
else if (currentCell && count > 3) nextCell = 0;
|
||||
else if (!currentCell && count == 3) nextCell = 1;
|
||||
if (currentCell && count < 2)
|
||||
nextCell = 0;
|
||||
else if (currentCell && count > 3)
|
||||
nextCell = 0;
|
||||
else if (!currentCell && count == 3)
|
||||
nextCell = 1;
|
||||
|
||||
nextField[x + y * width] = nextCell;
|
||||
}
|
||||
|
|
@ -47,12 +48,12 @@ EXPORT(step) void step(void)
|
|||
}
|
||||
}
|
||||
|
||||
static int countNeighbours(int x, int y)
|
||||
{
|
||||
static int countNeighbours(int x, int y) {
|
||||
int count = 0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
if (i == 0 && j == 0) continue;
|
||||
if (i == 0 && j == 0)
|
||||
continue;
|
||||
|
||||
int xx = (x + i + width) % width;
|
||||
int yy = (y + j + height) % height;
|
||||
|
|
@ -71,10 +72,9 @@ static int countNeighbours(int x, int y)
|
|||
#define MULT_LO (MULT & 255)
|
||||
#define MULT_HI (MULT & 256)
|
||||
|
||||
static uint8_t rand_state[STATE_BYTES] = { 0x87, 0xdd, 0xdc, 0x10, 0x35, 0xbc, 0x5c };
|
||||
static uint8_t rand_state[STATE_BYTES] = {0x87, 0xdd, 0xdc, 0x10, 0x35, 0xbc, 0x5c};
|
||||
|
||||
static uint8_t rand8(void)
|
||||
{
|
||||
static uint8_t rand8(void) {
|
||||
static uint16_t c = 0x42;
|
||||
static uint32_t i = 0;
|
||||
uint16_t t;
|
||||
|
|
@ -93,11 +93,16 @@ static uint8_t rand8(void)
|
|||
return x;
|
||||
}
|
||||
|
||||
EXPORT(initField) void init_field(uint32_t randomSeed)
|
||||
{
|
||||
EXPORT(initField) uint8_t* init_field(uint32_t randomSeed) {
|
||||
*((uint32_t*)&rand_state[STATE_BYTES - sizeof(uint32_t)]) = randomSeed; // Voodoo
|
||||
|
||||
field = malloc(width * height);
|
||||
nextField = malloc(width * height);
|
||||
pixels = malloc(width * height * 4);
|
||||
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
field[i] = rand8() & 1;
|
||||
}
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue