forked from davidgiven/cpm65
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
317 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
/* | ||
* pound - half a kilo editor | ||
* | ||
* Copyright © 2024 by Ivo van Poorten | ||
* | ||
* Based on Build Your Own Text Editor | ||
* (https://viewsourcecode.org/snaptoken/kilo/) | ||
*/ | ||
|
||
//#include <stdio.h> | ||
#include <stdint.h> | ||
#include <stdbool.h> | ||
#include <string.h> | ||
#include <cpm.h> | ||
#include "lib/zmalloc.h" | ||
#include "lib/screen.h" | ||
|
||
struct erow { | ||
int size; | ||
char *chars; | ||
}; | ||
|
||
struct editorConfig { | ||
uint8_t screenrows, screencols; | ||
unsigned int cx, cy; | ||
unsigned int numrows; | ||
struct erow *row; | ||
} E; | ||
|
||
#define CTRL(x) ((x)&0x1f) | ||
|
||
void die(char *reason, bool clear) { | ||
if (clear) screen_clear(); | ||
cpm_printstring(reason); | ||
cpm_printstring("\r\n"); | ||
cpm_warmboot(); | ||
} | ||
|
||
// -------------------- ROW OPERATIONS -------------------- | ||
|
||
// XXX check return values of zrealloc and zmalloc | ||
void editorAppendRow(char *s, size_t len) { | ||
E.row = zrealloc(E.row, sizeof(struct erow) * (E.numrows + 1)); | ||
|
||
int at = E.numrows; | ||
E.row[at].size = len; | ||
E.row[at].chars = zmalloc(len + 1); | ||
memcpy(E.row[at].chars, s, len); | ||
E.row[at].chars[len] = '\0'; | ||
E.numrows++; | ||
} | ||
|
||
// -------------------- FILE INPUT -------------------- | ||
|
||
void editorOpen(void) { | ||
cpm_fcb.cr = 0; | ||
if (cpm_open_file(&cpm_fcb)) die("Unable to read file", false); | ||
|
||
cpm_set_dma(cpm_default_dma); | ||
|
||
char *line = "Hello, world!"; | ||
size_t linelen = 13; | ||
|
||
editorAppendRow(line, linelen); | ||
editorAppendRow(line, linelen); | ||
editorAppendRow(line, linelen); | ||
|
||
cpm_close_file(&cpm_fcb); | ||
} | ||
|
||
// -------------------- SCREEN OUTPUT -------------------- | ||
|
||
void editorRefreshScreen(void) { | ||
screen_showcursor(0); | ||
for (int y=0; y<E.screenrows; y++) { | ||
if (y >= E.numrows) { | ||
screen_setcursor(0,y); | ||
screen_putchar('~'); | ||
} else { | ||
screen_setcursor(0,y); | ||
int len = E.row[y].size; | ||
if (len > E.screencols) len = E.screencols; | ||
for (int x=0; x<len; x++) | ||
screen_putchar(E.row[y].chars[x]); | ||
} | ||
screen_clear_to_eol(); | ||
} | ||
screen_setcursor(E.cx, E.cy); | ||
screen_showcursor(1); | ||
} | ||
|
||
// -------------------- KEYBOARD INPUT -------------------- | ||
|
||
void editorProcessKeypress(void) { | ||
static bool ctrlk = false; | ||
char c = screen_waitchar(); | ||
|
||
if (ctrlk) { | ||
switch(c) { | ||
case 'q': | ||
case 'Q': | ||
case CTRL('Q'): | ||
die("Done.", true); | ||
break; | ||
} | ||
ctrlk = false; | ||
return; | ||
} | ||
|
||
switch(c) { | ||
case CTRL('E'): // up | ||
if (E.cy) E.cy--; | ||
break; | ||
case CTRL('X'): // down | ||
if (E.cy != E.screenrows-1) E.cy++; | ||
break; | ||
case CTRL('S'): // left | ||
if (E.cx) E.cx--; | ||
break; | ||
case CTRL('D'): // right | ||
if (E.cx != E.screencols-1) E.cx++; | ||
break; | ||
case CTRL('R'): // page up | ||
break; | ||
case CTRL('C'): // page down | ||
break; | ||
case CTRL('K'): | ||
ctrlk = true; | ||
break; | ||
} | ||
} | ||
|
||
// -------------------- INIT -------------------- | ||
|
||
void initEditor(void) { | ||
if (!screen_init()) die("No SCREEN", false); | ||
|
||
uint16_t tpa = cpm_bios_gettpa(); | ||
uint8_t *top = (uint8_t *) (tpa & 0xff00); | ||
zmalloc_init(cpm_ram, 4096); // test low RAM | ||
// zmalloc_init(cpm_ram, top - cpm_ram); | ||
|
||
screen_getsize(&E.screencols, &E.screenrows); | ||
E.screencols++; | ||
E.screenrows++; | ||
E.cx = E.cy = 0; | ||
E.numrows = 0; | ||
E.row = NULL; | ||
} | ||
|
||
// -------------------- MAIN -------------------- | ||
|
||
void main(void) { | ||
initEditor(); | ||
editorOpen(); | ||
|
||
while(1) { | ||
editorRefreshScreen(); | ||
editorProcessKeypress(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* | ||
* Simple first-fit memory allocator for a fixed size memory pool | ||
* | ||
* Copyright © 2024 by Ivo van Poorten | ||
* | ||
* Use case: small memory systems without an OS, retro computing | ||
* | ||
* zmalloc: first-fit, fit at end of free block (faster mallocs, mostly) | ||
* zfree: free and merge with previous and/or next free blocks | ||
* zrealloc: smaller than current size - block_info_size - 1, shrink and | ||
* create new free block, possible merged with next free | ||
* bigger, alloc new, copy, free old | ||
*/ | ||
|
||
#include <stdbool.h> | ||
#include <string.h> // memset, memcpy | ||
#include <stdlib.h> // abort | ||
|
||
static void *base; | ||
|
||
struct block_info; | ||
|
||
struct block_info { | ||
bool free; | ||
size_t size; | ||
struct block_info *prev; | ||
struct block_info *next; | ||
}; | ||
|
||
#define block_info_size (sizeof(struct block_info)) | ||
|
||
void zmalloc_init(void *start, size_t size) { | ||
base = start; | ||
struct block_info *p = base; | ||
p->free = 1; | ||
p->size = size - block_info_size; | ||
p->prev = p->next = NULL; | ||
} | ||
|
||
void *zmalloc(size_t size) { | ||
if (!size) return NULL; | ||
|
||
struct block_info *p; | ||
|
||
for (p = base; p && !(p->free && p->size >= size); p = p->next) ; // find | ||
if (!p) return NULL; | ||
|
||
if (p->size - size > block_info_size) { // split, alloc at end | ||
struct block_info *q = (void *) p + p->size - size; | ||
p->size -= size + block_info_size; | ||
q->size = size; | ||
q->next = p->next; | ||
p->next = q; | ||
q->prev = p; | ||
if (q->next) q->next->prev = q; | ||
p = q; | ||
} | ||
|
||
p->free = 0; | ||
return (void *) p + block_info_size; | ||
} | ||
|
||
void *zcalloc(size_t nmemb, size_t size) { | ||
size_t nsize = nmemb * size; | ||
void *p = zmalloc(nsize); | ||
if (p) memset(p, 0, nsize); | ||
return p; | ||
} | ||
|
||
static void merge_with_next_free(struct block_info *p) { | ||
if (p->next && p->next->free) { | ||
struct block_info *q = p->next; | ||
p->size += q->size + block_info_size; | ||
p->next = q->next; | ||
if (p->next) p->next->prev = p; | ||
} | ||
} | ||
|
||
void zfree(void *ptr) { | ||
if (!ptr) abort(); | ||
|
||
struct block_info *p = ptr - block_info_size; | ||
p->free = 1; | ||
|
||
if (p->prev && p->prev->free) { // if free, merge with previous block | ||
struct block_info *q = p->prev; | ||
q->size += p->size + block_info_size; | ||
q->next = p->next; | ||
if (q->next) q->next->prev = q; | ||
p = q; | ||
} | ||
merge_with_next_free(p); | ||
} | ||
|
||
void *zrealloc(void *ptr, size_t size) { | ||
if (!ptr) return zmalloc(size); | ||
if (!size) { zfree(ptr); return NULL; } | ||
|
||
struct block_info *p = (void *) ptr - block_info_size; | ||
|
||
if (size > p->size) { // bigger | ||
// allocate new, copy, and free old | ||
void *q = zmalloc(size); | ||
if (!q) return NULL; | ||
memcpy(q, ptr, p->size); | ||
zfree(ptr); | ||
return q; | ||
} else if (p->size > size + block_info_size + 1) { // smaller enough | ||
// split and create new free block | ||
struct block_info *q = p + block_info_size + size; | ||
q->next = p->next; | ||
p->next = q; | ||
q->prev = p; | ||
if (q->next) q->next->prev = q; | ||
q->size = p->size - block_info_size - size; | ||
p->size = size; | ||
q->free = 1; | ||
merge_with_next_free(q); | ||
} | ||
return ptr; | ||
} | ||
|
||
#ifdef ZMALLOC_DEBUG | ||
#include <stdio.h> | ||
void print_memory(void) { | ||
struct block_info *p; | ||
int c; | ||
|
||
for (c = 0, p = base ; p ; p = p->next, c++) { | ||
printf("block %d, %s, size: %ld\n", c, p->free ? "free" : "used", p->size); | ||
} | ||
putchar('\n'); | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#pragma once | ||
#include <stddef.h> | ||
|
||
void zmalloc_init(void *start, size_t size); | ||
void *zmalloc(size_t size); | ||
void *zcalloc(size_t nmemb, size_t size); | ||
void zfree(void *ptr); | ||
void *zrealloc(void *ptr, size_t size); | ||
|
||
#ifdef ZMALLOC_DEBUG | ||
void print_memory(void); | ||
#endif |