diff options
Diffstat (limited to 'src/memory.c')
| -rw-r--r-- | src/memory.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 0000000..373ca27 --- /dev/null +++ b/src/memory.c @@ -0,0 +1,140 @@ +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> +#include <stdbool.h> +#include <SDL3/SDL.h> +#include <sys/mman.h> +#include "main.h" +#include "procfs.h" +#include "hash.h" +#include "curve.h" +#include "panic.h" +#include "memory.h" + +uintptr_t to_addr(int x, int y) { + unsigned int ux, uy; + memcpy(&ux, &x, sizeof(unsigned int)); + memcpy(&uy, &y, sizeof(unsigned int)); + uintptr_t page = zorder(ux / PAGE_WIDTH, uy / PAGE_HEIGHT); + int offset = + x % PAGE_WIDTH / CHAR_BIT + y % PAGE_HEIGHT * PAGE_WIDTH / CHAR_BIT; + return page * PAGE_SIZE + offset; +} + +void to_pos(uintptr_t addr, int *x, int *y) { + int px, py; + unzorder(addr / PAGE_SIZE, &px, &py); + int offset = addr % PAGE_SIZE; + int ux = px * PAGE_WIDTH + offset % PAGE_WIDTH; + int uy = py * PAGE_HEIGHT + offset / PAGE_WIDTH; + memcpy(x, &ux, sizeof(int)); + memcpy(y, &uy, sizeof(int)); +} + +int init_page_list(page_list *l, int fd) { + l->fd = fd; +} + +static void free_page(page *p) { + if (p->tex) { + SDL_DestroyTexture(p->tex); + } + free(p); +} + +void free_page_list(page_list *l) { + page *p = l->first; + while (p) { + page *next = p->next; + free_page(p); + p = next; + } + l->fd = -1; + l->first = NULL; +} + +void free_unused_pages(page_list *l) { + page **prev_link = &l->first; + page *p = l->first; + while (p) { + page *next = p->next; + if (!p->in_use) { + *prev_link = next; + free_page(p); + } else { + prev_link = &p->next; + p->in_use = false; + } + p = next; + } +} + +page *get_page(page_list *l, uintptr_t addr) { + addr = addr - addr % PAGE_SIZE; + for (page *p = l->first; p; p = p->next) { + if (p->address == addr) { + return p; + } + } + page *p = calloc(1, sizeof(page)); + if (!p) panic("out of memory"); + p->address = addr; + p->l = l; + p->next = l->first; + l->first = p; + return p; +} + +static SDL_Palette *texture_palette() { + SDL_Color colors[] = {{0x00, 0x00, 0x00, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}}; + static SDL_Palette *palette = NULL; + if (!palette) { + palette = must(SDL_CreatePalette(2)); + must(SDL_SetPaletteColors(palette, colors, 0, 2)); + } + return palette; +} + +SDL_Texture *get_texture(page *p) { + static char data[PAGE_SIZE]; + if (read_mem(p->l->fd, p->address, data, PAGE_SIZE) != 0) { + return NULL; + } + uint32_t hash = fnv(data, PAGE_SIZE); + if (p->hash != hash) { + if (p->tex) SDL_DestroyTexture(p->tex); + SDL_Surface *surface = must(SDL_CreateSurfaceFrom( + PAGE_WIDTH, PAGE_HEIGHT, SDL_PIXELFORMAT_INDEX1LSB, data, + PAGE_WIDTH / 8 + )); + p->tex = must(SDL_CreateTextureFromSurface(renderer, surface)); + must(SDL_SetTexturePalette(p->tex, texture_palette())); + SDL_DestroySurface(surface); + } + p->hash = hash; + p->in_use = true; + return p->tex; +} + +static void write_bit(int fd, int x, int y, bool bit) { + uintptr_t addr = to_addr(x, y); + int bit_offs = x % CHAR_BIT; + uint8_t byte; + if (read_mem(fd, addr, &byte, 1) == -1) return; + byte = (byte & ~(1 << bit_offs)) | (bit << bit_offs); + write_mem(fd, addr, &byte, 1); +} + +void draw_line(page_list *l, + double x1, double y1, double x2, double y2, bool bit) { + double dx = (x2 - x1); + double dy = (y2 - y1); + int step = abs(dx) >= abs(dy) ? abs(dx) : abs(dy); + dx = dx / step; dy = dy / step; + double x = x1; double y = y1; + for (int i = 0; i <= step; i++) { + write_bit(l->fd, x, y, bit); + x = x + dx; + y = y + dy; + } +} |
