Added SDL layer
This commit is contained in:
parent
5e80946097
commit
75b0fd06d9
2
build.sh
2
build.sh
|
@ -15,7 +15,7 @@ clang-format -i emulator.c
|
||||||
clang-format -i uxn.h
|
clang-format -i uxn.h
|
||||||
clang-format -i uxn.c
|
clang-format -i uxn.c
|
||||||
rm -f ./uxn
|
rm -f ./uxn
|
||||||
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
|
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
|
||||||
|
|
||||||
# run
|
# run
|
||||||
./bin/emulator bin/boot.rom
|
./bin/emulator bin/boot.rom
|
||||||
|
|
157
emulator.c
157
emulator.c
|
@ -1,5 +1,5 @@
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "uxn.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2021 Devine Lu Linvega
|
Copyright (c) 2021 Devine Lu Linvega
|
||||||
|
@ -12,6 +12,90 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
WITH REGARD TO THIS SOFTWARE.
|
WITH REGARD TO THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "uxn.h"
|
||||||
|
|
||||||
|
#define HOR 32
|
||||||
|
#define VER 16
|
||||||
|
#define PAD 2
|
||||||
|
#define SZ (HOR * VER * 16)
|
||||||
|
|
||||||
|
typedef unsigned char Uint8;
|
||||||
|
|
||||||
|
int WIDTH = 8 * HOR + 8 * PAD * 2;
|
||||||
|
int HEIGHT = 8 * (VER + 2) + 8 * PAD * 2;
|
||||||
|
int FPS = 30, GUIDES = 1, BIGPIXEL = 0, ZOOM = 2;
|
||||||
|
|
||||||
|
Uint32 theme[] = {
|
||||||
|
0x000000,
|
||||||
|
0xFFFFFF,
|
||||||
|
0x72DEC2,
|
||||||
|
0x666666,
|
||||||
|
0x222222};
|
||||||
|
|
||||||
|
SDL_Window *gWindow;
|
||||||
|
SDL_Renderer *gRenderer;
|
||||||
|
SDL_Texture *gTexture;
|
||||||
|
Uint32 *pixels;
|
||||||
|
|
||||||
|
int
|
||||||
|
error(char *msg, const char *err)
|
||||||
|
{
|
||||||
|
printf("Error %s: %s\n", msg, err);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clear(Uint32 *dst)
|
||||||
|
{
|
||||||
|
int v, h;
|
||||||
|
for(v = 0; v < HEIGHT; v++)
|
||||||
|
for(h = 0; h < WIDTH; h++)
|
||||||
|
dst[v * WIDTH + h] = theme[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
redraw(Uint32 *dst)
|
||||||
|
{
|
||||||
|
SDL_UpdateTexture(gTexture, NULL, dst, WIDTH * sizeof(Uint32));
|
||||||
|
SDL_RenderClear(gRenderer);
|
||||||
|
SDL_RenderCopy(gRenderer, gTexture, NULL, NULL);
|
||||||
|
SDL_RenderPresent(gRenderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
quit(void)
|
||||||
|
{
|
||||||
|
free(pixels);
|
||||||
|
SDL_DestroyTexture(gTexture);
|
||||||
|
gTexture = NULL;
|
||||||
|
SDL_DestroyRenderer(gRenderer);
|
||||||
|
gRenderer = NULL;
|
||||||
|
SDL_DestroyWindow(gWindow);
|
||||||
|
gWindow = NULL;
|
||||||
|
SDL_Quit();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
init(void)
|
||||||
|
{
|
||||||
|
if(SDL_Init(SDL_INIT_VIDEO) < 0)
|
||||||
|
return error("Init", SDL_GetError());
|
||||||
|
gWindow = SDL_CreateWindow("Uxn", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH * ZOOM, HEIGHT * ZOOM, SDL_WINDOW_SHOWN);
|
||||||
|
if(gWindow == NULL)
|
||||||
|
return error("Window", SDL_GetError());
|
||||||
|
gRenderer = SDL_CreateRenderer(gWindow, -1, 0);
|
||||||
|
if(gRenderer == NULL)
|
||||||
|
return error("Renderer", SDL_GetError());
|
||||||
|
gTexture = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, WIDTH, HEIGHT);
|
||||||
|
if(gTexture == NULL)
|
||||||
|
return error("Texture", SDL_GetError());
|
||||||
|
if(!(pixels = (Uint32 *)malloc(WIDTH * HEIGHT * sizeof(Uint32))))
|
||||||
|
return error("Pixels", "Failed to allocate memory");
|
||||||
|
clear(pixels);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
echos(Stack8 *s, Uint8 len, char *name)
|
echos(Stack8 *s, Uint8 len, char *name)
|
||||||
{
|
{
|
||||||
|
@ -49,21 +133,68 @@ echof(Uxn *c)
|
||||||
getflag(&c->status, FLAG_COND) != 0);
|
getflag(&c->status, FLAG_COND) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
main(int argc, char *argv[])
|
domouse(SDL_Event *event)
|
||||||
{
|
{
|
||||||
Uxn cpu;
|
(void)event;
|
||||||
|
printf("mouse\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dokey(SDL_Event *event)
|
||||||
|
{
|
||||||
|
(void)event;
|
||||||
|
printf("key\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
start(Uxn *u)
|
||||||
|
{
|
||||||
|
int ticknext = 0;
|
||||||
|
evaluxn(u, u->vreset);
|
||||||
|
while(1) {
|
||||||
|
int tick = SDL_GetTicks();
|
||||||
|
SDL_Event event;
|
||||||
|
if(tick < ticknext)
|
||||||
|
SDL_Delay(ticknext - tick);
|
||||||
|
ticknext = tick + (1000 / FPS);
|
||||||
|
evaluxn(u, u->vframe);
|
||||||
|
while(SDL_PollEvent(&event) != 0) {
|
||||||
|
switch(event.type) {
|
||||||
|
case SDL_QUIT: quit(); break;
|
||||||
|
case SDL_MOUSEBUTTONUP:
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
case SDL_MOUSEMOTION: domouse(&event); break;
|
||||||
|
case SDL_KEYDOWN: dokey(&event); break;
|
||||||
|
case SDL_WINDOWEVENT:
|
||||||
|
if(event.window.event == SDL_WINDOWEVENT_EXPOSED)
|
||||||
|
redraw(pixels);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
Uxn u;
|
||||||
|
|
||||||
if(argc < 2)
|
if(argc < 2)
|
||||||
return error(&cpu, "No input.", 0);
|
return error("Input", "Missing");
|
||||||
if(!load(&cpu, argv[1]))
|
if(!bootuxn(&u))
|
||||||
return error(&cpu, "Load error", 0);
|
return error("Boot", "Failed");
|
||||||
if(!boot(&cpu))
|
if(!loaduxn(&u, argv[1]))
|
||||||
return error(&cpu, "Boot error", 0);
|
return error("Load", "Failed");
|
||||||
|
if(!init())
|
||||||
|
return error("Init", "Failed");
|
||||||
|
|
||||||
/* print result */
|
start(&u);
|
||||||
echos(&cpu.wst, 0x40, "stack");
|
|
||||||
echom(&cpu.ram, 0x40, "ram");
|
echos(&u.wst, 0x40, "stack");
|
||||||
echof(&cpu);
|
echom(&u.ram, 0x40, "ram");
|
||||||
|
echof(&u);
|
||||||
|
|
||||||
|
quit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
89
uxn.c
89
uxn.c
|
@ -97,24 +97,44 @@ Uint8 opr[][2] = {
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
int
|
int
|
||||||
error(Uxn *u, char *name, int id)
|
haltuxn(Uxn *u, char *name, int id)
|
||||||
{
|
{
|
||||||
printf("Error: %s#%04x, at 0x%04x\n", name, id, u->counter);
|
printf("Error: %s#%04x, at 0x%04x\n", name, id, u->counter);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
inituxn(Uxn *u)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
char *cptr = (char *)u;
|
||||||
|
for(i = 0; i < sizeof u; i++)
|
||||||
|
cptr[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
doliteral(Uxn *u, Uint8 instr)
|
loaduxn(Uxn *u, char *filepath)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
if(!(f = fopen(filepath, "rb")))
|
||||||
|
return haltuxn(u, "Missing input.", 0);
|
||||||
|
fread(u->ram.dat, sizeof(u->ram.dat), 1, f);
|
||||||
|
printf("Uxn Loaded: %s\n", filepath);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lituxn(Uxn *u, Uint8 instr)
|
||||||
{
|
{
|
||||||
if(u->wst.ptr >= 255)
|
if(u->wst.ptr >= 255)
|
||||||
return error(u, "Stack overflow", instr);
|
return haltuxn(u, "Stack overflow", instr);
|
||||||
wspush8(u, instr);
|
wspush8(u, instr);
|
||||||
u->literal--;
|
u->literal--;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
dodevices(Uxn *u) /* experimental */
|
devuxn(Uxn *u) /* experimental */
|
||||||
{
|
{
|
||||||
if(u->ram.dat[0xfff1]) {
|
if(u->ram.dat[0xfff1]) {
|
||||||
printf("%c", u->ram.dat[0xfff1]);
|
printf("%c", u->ram.dat[0xfff1]);
|
||||||
|
@ -124,7 +144,7 @@ dodevices(Uxn *u) /* experimental */
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
doopcode(Uxn *u, Uint8 instr)
|
opcuxn(Uxn *u, Uint8 instr)
|
||||||
{
|
{
|
||||||
Uint8 op = instr & 0x1f;
|
Uint8 op = instr & 0x1f;
|
||||||
setflag(&u->status, FLAG_SHORT, (instr >> 5) & 1);
|
setflag(&u->status, FLAG_SHORT, (instr >> 5) & 1);
|
||||||
|
@ -133,61 +153,40 @@ doopcode(Uxn *u, Uint8 instr)
|
||||||
if(getflag(&u->status, FLAG_SHORT))
|
if(getflag(&u->status, FLAG_SHORT))
|
||||||
op += 16;
|
op += 16;
|
||||||
if(u->wst.ptr < opr[op][0])
|
if(u->wst.ptr < opr[op][0])
|
||||||
return error(u, "Stack underflow", op);
|
return haltuxn(u, "Stack underflow", op);
|
||||||
if(u->wst.ptr + opr[op][1] - opr[op][0] >= 255)
|
if(u->wst.ptr + opr[op][1] - opr[op][0] >= 255)
|
||||||
return error(u, "Stack overflow", instr);
|
return haltuxn(u, "Stack overflow", instr);
|
||||||
if(!getflag(&u->status, FLAG_COND) || (getflag(&u->status, FLAG_COND) && wspop8(u)))
|
if(!getflag(&u->status, FLAG_COND) || (getflag(&u->status, FLAG_COND) && wspop8(u)))
|
||||||
(*ops[op])(u);
|
(*ops[op])(u);
|
||||||
dodevices(u);
|
devuxn(u);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
eval(Uxn *u)
|
evaluxn(Uxn *u, Uint16 vec)
|
||||||
{
|
{
|
||||||
Uint8 instr = u->ram.dat[u->ram.ptr++];
|
u->ram.ptr = vec;
|
||||||
if(u->literal > 0)
|
setflag(&u->status, FLAG_HALT, 0);
|
||||||
return doliteral(u, instr);
|
while(!(u->status & FLAG_HALT)) {
|
||||||
else
|
Uint8 instr = u->ram.dat[u->ram.ptr++];
|
||||||
return doopcode(u, instr);
|
u->counter++;
|
||||||
|
if(u->literal > 0)
|
||||||
|
return lituxn(u, instr);
|
||||||
|
else
|
||||||
|
return opcuxn(u, instr);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
load(Uxn *u, char *filepath)
|
bootuxn(Uxn *u)
|
||||||
{
|
{
|
||||||
FILE *f;
|
inituxn(u);
|
||||||
if(!(f = fopen(filepath, "rb")))
|
|
||||||
return error(u, "Missing input.", 0);
|
|
||||||
fread(u->ram.dat, sizeof(u->ram.dat), 1, f);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
reset(Uxn *u)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
char *cptr = (char *)u;
|
|
||||||
for(i = 0; i < sizeof u; i++)
|
|
||||||
cptr[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
boot(Uxn *u)
|
|
||||||
{
|
|
||||||
reset(u);
|
|
||||||
u->vreset = mempeek16(u, 0xfffa);
|
u->vreset = mempeek16(u, 0xfffa);
|
||||||
u->vframe = mempeek16(u, 0xfffc);
|
u->vframe = mempeek16(u, 0xfffc);
|
||||||
u->verror = mempeek16(u, 0xfffe);
|
u->verror = mempeek16(u, 0xfffe);
|
||||||
/* eval reset */
|
printf("Uxn Ready.\n");
|
||||||
u->ram.ptr = u->vreset;
|
|
||||||
setflag(&u->status, FLAG_HALT, 0);
|
|
||||||
while(!(u->status & FLAG_HALT) && eval(u))
|
|
||||||
u->counter++;
|
|
||||||
/* eval frame */
|
|
||||||
u->ram.ptr = u->vframe;
|
|
||||||
setflag(&u->status, FLAG_HALT, 0);
|
|
||||||
while(!(u->status & FLAG_HALT) && eval(u))
|
|
||||||
u->counter++;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* to start: evaluxn(u, u->vreset); */
|
||||||
|
|
6
uxn.h
6
uxn.h
|
@ -44,6 +44,6 @@ typedef struct {
|
||||||
|
|
||||||
void setflag(Uint8 *status, char flag, int b);
|
void setflag(Uint8 *status, char flag, int b);
|
||||||
int getflag(Uint8 *status, char flag);
|
int getflag(Uint8 *status, char flag);
|
||||||
int error(Uxn *c, char *name, int id);
|
int loaduxn(Uxn *c, char *filepath);
|
||||||
int load(Uxn *c, char *filepath);
|
int bootuxn(Uxn *c);
|
||||||
int boot(Uxn *c);
|
int evaluxn(Uxn *u, Uint16 vec);
|
Loading…
Reference in New Issue