| ... | ... |
@@ -15,7 +15,7 @@ clang-format -i emulator.c |
| 15 | 15 |
clang-format -i uxn.h |
| 16 | 16 |
clang-format -i uxn.c |
| 17 | 17 |
rm -f ./uxn |
| 18 |
-cc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined uxn.c emulator.c -o bin/emulator |
|
| 18 |
+cc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined uxn.c emulator.c -L/usr/local/lib -lSDL2 -o bin/emulator |
|
| 19 | 19 |
|
| 20 | 20 |
# run |
| 21 | 21 |
./bin/emulator bin/boot.rom |
| ... | ... |
@@ -1,5 +1,5 @@ |
| 1 |
+#include <SDL2/SDL.h> |
|
| 1 | 2 |
#include <stdio.h> |
| 2 |
-#include "uxn.h" |
|
| 3 | 3 |
|
| 4 | 4 |
/* |
| 5 | 5 |
Copyright (c) 2021 Devine Lu Linvega |
| ... | ... |
@@ -12,6 +12,90 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 12 | 12 |
WITH REGARD TO THIS SOFTWARE. |
| 13 | 13 |
*/ |
| 14 | 14 |
|
| 15 |
+#include "uxn.h" |
|
| 16 |
+ |
|
| 17 |
+#define HOR 32 |
|
| 18 |
+#define VER 16 |
|
| 19 |
+#define PAD 2 |
|
| 20 |
+#define SZ (HOR * VER * 16) |
|
| 21 |
+ |
|
| 22 |
+typedef unsigned char Uint8; |
|
| 23 |
+ |
|
| 24 |
+int WIDTH = 8 * HOR + 8 * PAD * 2; |
|
| 25 |
+int HEIGHT = 8 * (VER + 2) + 8 * PAD * 2; |
|
| 26 |
+int FPS = 30, GUIDES = 1, BIGPIXEL = 0, ZOOM = 2; |
|
| 27 |
+ |
|
| 28 |
+Uint32 theme[] = {
|
|
| 29 |
+ 0x000000, |
|
| 30 |
+ 0xFFFFFF, |
|
| 31 |
+ 0x72DEC2, |
|
| 32 |
+ 0x666666, |
|
| 33 |
+ 0x222222}; |
|
| 34 |
+ |
|
| 35 |
+SDL_Window *gWindow; |
|
| 36 |
+SDL_Renderer *gRenderer; |
|
| 37 |
+SDL_Texture *gTexture; |
|
| 38 |
+Uint32 *pixels; |
|
| 39 |
+ |
|
| 40 |
+int |
|
| 41 |
+error(char *msg, const char *err) |
|
| 42 |
+{
|
|
| 43 |
+ printf("Error %s: %s\n", msg, err);
|
|
| 44 |
+ return 0; |
|
| 45 |
+} |
|
| 46 |
+ |
|
| 47 |
+void |
|
| 48 |
+clear(Uint32 *dst) |
|
| 49 |
+{
|
|
| 50 |
+ int v, h; |
|
| 51 |
+ for(v = 0; v < HEIGHT; v++) |
|
| 52 |
+ for(h = 0; h < WIDTH; h++) |
|
| 53 |
+ dst[v * WIDTH + h] = theme[0]; |
|
| 54 |
+} |
|
| 55 |
+ |
|
| 56 |
+void |
|
| 57 |
+redraw(Uint32 *dst) |
|
| 58 |
+{
|
|
| 59 |
+ SDL_UpdateTexture(gTexture, NULL, dst, WIDTH * sizeof(Uint32)); |
|
| 60 |
+ SDL_RenderClear(gRenderer); |
|
| 61 |
+ SDL_RenderCopy(gRenderer, gTexture, NULL, NULL); |
|
| 62 |
+ SDL_RenderPresent(gRenderer); |
|
| 63 |
+} |
|
| 64 |
+ |
|
| 65 |
+void |
|
| 66 |
+quit(void) |
|
| 67 |
+{
|
|
| 68 |
+ free(pixels); |
|
| 69 |
+ SDL_DestroyTexture(gTexture); |
|
| 70 |
+ gTexture = NULL; |
|
| 71 |
+ SDL_DestroyRenderer(gRenderer); |
|
| 72 |
+ gRenderer = NULL; |
|
| 73 |
+ SDL_DestroyWindow(gWindow); |
|
| 74 |
+ gWindow = NULL; |
|
| 75 |
+ SDL_Quit(); |
|
| 76 |
+ exit(0); |
|
| 77 |
+} |
|
| 78 |
+ |
|
| 79 |
+int |
|
| 80 |
+init(void) |
|
| 81 |
+{
|
|
| 82 |
+ if(SDL_Init(SDL_INIT_VIDEO) < 0) |
|
| 83 |
+ return error("Init", SDL_GetError());
|
|
| 84 |
+ gWindow = SDL_CreateWindow("Uxn", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH * ZOOM, HEIGHT * ZOOM, SDL_WINDOW_SHOWN);
|
|
| 85 |
+ if(gWindow == NULL) |
|
| 86 |
+ return error("Window", SDL_GetError());
|
|
| 87 |
+ gRenderer = SDL_CreateRenderer(gWindow, -1, 0); |
|
| 88 |
+ if(gRenderer == NULL) |
|
| 89 |
+ return error("Renderer", SDL_GetError());
|
|
| 90 |
+ gTexture = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, WIDTH, HEIGHT); |
|
| 91 |
+ if(gTexture == NULL) |
|
| 92 |
+ return error("Texture", SDL_GetError());
|
|
| 93 |
+ if(!(pixels = (Uint32 *)malloc(WIDTH * HEIGHT * sizeof(Uint32)))) |
|
| 94 |
+ return error("Pixels", "Failed to allocate memory");
|
|
| 95 |
+ clear(pixels); |
|
| 96 |
+ return 1; |
|
| 97 |
+} |
|
| 98 |
+ |
|
| 15 | 99 |
void |
| 16 | 100 |
echos(Stack8 *s, Uint8 len, char *name) |
| 17 | 101 |
{
|
| ... | ... |
@@ -49,21 +133,68 @@ echof(Uxn *c) |
| 49 | 133 |
getflag(&c->status, FLAG_COND) != 0); |
| 50 | 134 |
} |
| 51 | 135 |
|
| 136 |
+void |
|
| 137 |
+domouse(SDL_Event *event) |
|
| 138 |
+{
|
|
| 139 |
+ (void)event; |
|
| 140 |
+ printf("mouse\n");
|
|
| 141 |
+} |
|
| 142 |
+ |
|
| 143 |
+void |
|
| 144 |
+dokey(SDL_Event *event) |
|
| 145 |
+{
|
|
| 146 |
+ (void)event; |
|
| 147 |
+ printf("key\n");
|
|
| 148 |
+} |
|
| 149 |
+ |
|
| 52 | 150 |
int |
| 53 |
-main(int argc, char *argv[]) |
|
| 151 |
+start(Uxn *u) |
|
| 54 | 152 |
{
|
| 55 |
- Uxn cpu; |
|
| 153 |
+ int ticknext = 0; |
|
| 154 |
+ evaluxn(u, u->vreset); |
|
| 155 |
+ while(1) {
|
|
| 156 |
+ int tick = SDL_GetTicks(); |
|
| 157 |
+ SDL_Event event; |
|
| 158 |
+ if(tick < ticknext) |
|
| 159 |
+ SDL_Delay(ticknext - tick); |
|
| 160 |
+ ticknext = tick + (1000 / FPS); |
|
| 161 |
+ evaluxn(u, u->vframe); |
|
| 162 |
+ while(SDL_PollEvent(&event) != 0) {
|
|
| 163 |
+ switch(event.type) {
|
|
| 164 |
+ case SDL_QUIT: quit(); break; |
|
| 165 |
+ case SDL_MOUSEBUTTONUP: |
|
| 166 |
+ case SDL_MOUSEBUTTONDOWN: |
|
| 167 |
+ case SDL_MOUSEMOTION: domouse(&event); break; |
|
| 168 |
+ case SDL_KEYDOWN: dokey(&event); break; |
|
| 169 |
+ case SDL_WINDOWEVENT: |
|
| 170 |
+ if(event.window.event == SDL_WINDOWEVENT_EXPOSED) |
|
| 171 |
+ redraw(pixels); |
|
| 172 |
+ break; |
|
| 173 |
+ } |
|
| 174 |
+ } |
|
| 175 |
+ } |
|
| 176 |
+} |
|
| 177 |
+ |
|
| 178 |
+int |
|
| 179 |
+main(int argc, char **argv) |
|
| 180 |
+{
|
|
| 181 |
+ Uxn u; |
|
| 56 | 182 |
|
| 57 | 183 |
if(argc < 2) |
| 58 |
- return error(&cpu, "No input.", 0); |
|
| 59 |
- if(!load(&cpu, argv[1])) |
|
| 60 |
- return error(&cpu, "Load error", 0); |
|
| 61 |
- if(!boot(&cpu)) |
|
| 62 |
- return error(&cpu, "Boot error", 0); |
|
| 63 |
- |
|
| 64 |
- /* print result */ |
|
| 65 |
- echos(&cpu.wst, 0x40, "stack"); |
|
| 66 |
- echom(&cpu.ram, 0x40, "ram"); |
|
| 67 |
- echof(&cpu); |
|
| 184 |
+ return error("Input", "Missing");
|
|
| 185 |
+ if(!bootuxn(&u)) |
|
| 186 |
+ return error("Boot", "Failed");
|
|
| 187 |
+ if(!loaduxn(&u, argv[1])) |
|
| 188 |
+ return error("Load", "Failed");
|
|
| 189 |
+ if(!init()) |
|
| 190 |
+ return error("Init", "Failed");
|
|
| 191 |
+ |
|
| 192 |
+ start(&u); |
|
| 193 |
+ |
|
| 194 |
+ echos(&u.wst, 0x40, "stack"); |
|
| 195 |
+ echom(&u.ram, 0x40, "ram"); |
|
| 196 |
+ echof(&u); |
|
| 197 |
+ |
|
| 198 |
+ quit(); |
|
| 68 | 199 |
return 0; |
| 69 | 200 |
} |
| ... | ... |
@@ -97,24 +97,44 @@ Uint8 opr[][2] = {
|
| 97 | 97 |
/* clang-format on */ |
| 98 | 98 |
|
| 99 | 99 |
int |
| 100 |
-error(Uxn *u, char *name, int id) |
|
| 100 |
+haltuxn(Uxn *u, char *name, int id) |
|
| 101 | 101 |
{
|
| 102 | 102 |
printf("Error: %s#%04x, at 0x%04x\n", name, id, u->counter);
|
| 103 | 103 |
return 0; |
| 104 | 104 |
} |
| 105 | 105 |
|
| 106 |
+void |
|
| 107 |
+inituxn(Uxn *u) |
|
| 108 |
+{
|
|
| 109 |
+ size_t i; |
|
| 110 |
+ char *cptr = (char *)u; |
|
| 111 |
+ for(i = 0; i < sizeof u; i++) |
|
| 112 |
+ cptr[i] = 0; |
|
| 113 |
+} |
|
| 114 |
+ |
|
| 115 |
+int |
|
| 116 |
+loaduxn(Uxn *u, char *filepath) |
|
| 117 |
+{
|
|
| 118 |
+ FILE *f; |
|
| 119 |
+ if(!(f = fopen(filepath, "rb"))) |
|
| 120 |
+ return haltuxn(u, "Missing input.", 0); |
|
| 121 |
+ fread(u->ram.dat, sizeof(u->ram.dat), 1, f); |
|
| 122 |
+ printf("Uxn Loaded: %s\n", filepath);
|
|
| 123 |
+ return 1; |
|
| 124 |
+} |
|
| 125 |
+ |
|
| 106 | 126 |
int |
| 107 |
-doliteral(Uxn *u, Uint8 instr) |
|
| 127 |
+lituxn(Uxn *u, Uint8 instr) |
|
| 108 | 128 |
{
|
| 109 | 129 |
if(u->wst.ptr >= 255) |
| 110 |
- return error(u, "Stack overflow", instr); |
|
| 130 |
+ return haltuxn(u, "Stack overflow", instr); |
|
| 111 | 131 |
wspush8(u, instr); |
| 112 | 132 |
u->literal--; |
| 113 | 133 |
return 1; |
| 114 | 134 |
} |
| 115 | 135 |
|
| 116 | 136 |
int |
| 117 |
-dodevices(Uxn *u) /* experimental */ |
|
| 137 |
+devuxn(Uxn *u) /* experimental */ |
|
| 118 | 138 |
{
|
| 119 | 139 |
if(u->ram.dat[0xfff1]) {
|
| 120 | 140 |
printf("%c", u->ram.dat[0xfff1]);
|
| ... | ... |
@@ -124,7 +144,7 @@ dodevices(Uxn *u) /* experimental */ |
| 124 | 144 |
} |
| 125 | 145 |
|
| 126 | 146 |
int |
| 127 |
-doopcode(Uxn *u, Uint8 instr) |
|
| 147 |
+opcuxn(Uxn *u, Uint8 instr) |
|
| 128 | 148 |
{
|
| 129 | 149 |
Uint8 op = instr & 0x1f; |
| 130 | 150 |
setflag(&u->status, FLAG_SHORT, (instr >> 5) & 1); |
| ... | ... |
@@ -133,61 +153,40 @@ doopcode(Uxn *u, Uint8 instr) |
| 133 | 153 |
if(getflag(&u->status, FLAG_SHORT)) |
| 134 | 154 |
op += 16; |
| 135 | 155 |
if(u->wst.ptr < opr[op][0]) |
| 136 |
- return error(u, "Stack underflow", op); |
|
| 156 |
+ return haltuxn(u, "Stack underflow", op); |
|
| 137 | 157 |
if(u->wst.ptr + opr[op][1] - opr[op][0] >= 255) |
| 138 |
- return error(u, "Stack overflow", instr); |
|
| 158 |
+ return haltuxn(u, "Stack overflow", instr); |
|
| 139 | 159 |
if(!getflag(&u->status, FLAG_COND) || (getflag(&u->status, FLAG_COND) && wspop8(u))) |
| 140 | 160 |
(*ops[op])(u); |
| 141 |
- dodevices(u); |
|
| 142 |
- return 1; |
|
| 143 |
-} |
|
| 144 |
- |
|
| 145 |
-int |
|
| 146 |
-eval(Uxn *u) |
|
| 147 |
-{
|
|
| 148 |
- Uint8 instr = u->ram.dat[u->ram.ptr++]; |
|
| 149 |
- if(u->literal > 0) |
|
| 150 |
- return doliteral(u, instr); |
|
| 151 |
- else |
|
| 152 |
- return doopcode(u, instr); |
|
| 161 |
+ devuxn(u); |
|
| 153 | 162 |
return 1; |
| 154 | 163 |
} |
| 155 | 164 |
|
| 156 | 165 |
int |
| 157 |
-load(Uxn *u, char *filepath) |
|
| 166 |
+evaluxn(Uxn *u, Uint16 vec) |
|
| 158 | 167 |
{
|
| 159 |
- FILE *f; |
|
| 160 |
- if(!(f = fopen(filepath, "rb"))) |
|
| 161 |
- return error(u, "Missing input.", 0); |
|
| 162 |
- fread(u->ram.dat, sizeof(u->ram.dat), 1, f); |
|
| 168 |
+ u->ram.ptr = vec; |
|
| 169 |
+ setflag(&u->status, FLAG_HALT, 0); |
|
| 170 |
+ while(!(u->status & FLAG_HALT)) {
|
|
| 171 |
+ Uint8 instr = u->ram.dat[u->ram.ptr++]; |
|
| 172 |
+ u->counter++; |
|
| 173 |
+ if(u->literal > 0) |
|
| 174 |
+ return lituxn(u, instr); |
|
| 175 |
+ else |
|
| 176 |
+ return opcuxn(u, instr); |
|
| 177 |
+ } |
|
| 163 | 178 |
return 1; |
| 164 | 179 |
} |
| 165 | 180 |
|
| 166 |
-void |
|
| 167 |
-reset(Uxn *u) |
|
| 168 |
-{
|
|
| 169 |
- size_t i; |
|
| 170 |
- char *cptr = (char *)u; |
|
| 171 |
- for(i = 0; i < sizeof u; i++) |
|
| 172 |
- cptr[i] = 0; |
|
| 173 |
-} |
|
| 174 |
- |
|
| 175 | 181 |
int |
| 176 |
-boot(Uxn *u) |
|
| 182 |
+bootuxn(Uxn *u) |
|
| 177 | 183 |
{
|
| 178 |
- reset(u); |
|
| 184 |
+ inituxn(u); |
|
| 179 | 185 |
u->vreset = mempeek16(u, 0xfffa); |
| 180 | 186 |
u->vframe = mempeek16(u, 0xfffc); |
| 181 | 187 |
u->verror = mempeek16(u, 0xfffe); |
| 182 |
- /* eval reset */ |
|
| 183 |
- u->ram.ptr = u->vreset; |
|
| 184 |
- setflag(&u->status, FLAG_HALT, 0); |
|
| 185 |
- while(!(u->status & FLAG_HALT) && eval(u)) |
|
| 186 |
- u->counter++; |
|
| 187 |
- /* eval frame */ |
|
| 188 |
- u->ram.ptr = u->vframe; |
|
| 189 |
- setflag(&u->status, FLAG_HALT, 0); |
|
| 190 |
- while(!(u->status & FLAG_HALT) && eval(u)) |
|
| 191 |
- u->counter++; |
|
| 188 |
+ printf("Uxn Ready.\n");
|
|
| 192 | 189 |
return 1; |
| 193 | 190 |
} |
| 191 |
+ |
|
| 192 |
+/* to start: evaluxn(u, u->vreset); */ |
| ... | ... |
@@ -44,6 +44,6 @@ typedef struct {
|
| 44 | 44 |
|
| 45 | 45 |
void setflag(Uint8 *status, char flag, int b); |
| 46 | 46 |
int getflag(Uint8 *status, char flag); |
| 47 |
-int error(Uxn *c, char *name, int id); |
|
| 48 |
-int load(Uxn *c, char *filepath); |
|
| 49 |
-int boot(Uxn *c); |
|
| 47 |
+int loaduxn(Uxn *c, char *filepath); |
|
| 48 |
+int bootuxn(Uxn *c); |
|
| 49 |
+int evaluxn(Uxn *u, Uint16 vec); |
|
| 50 | 50 |
\ No newline at end of file |