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.c
|
||||
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
|
||||
./bin/emulator bin/boot.rom
|
||||
|
|
157
emulator.c
157
emulator.c
|
@ -1,5 +1,5 @@
|
|||
#include <SDL2/SDL.h>
|
||||
#include <stdio.h>
|
||||
#include "uxn.h"
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#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
|
||||
echos(Stack8 *s, Uint8 len, char *name)
|
||||
{
|
||||
|
@ -49,21 +133,68 @@ echof(Uxn *c)
|
|||
getflag(&c->status, FLAG_COND) != 0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
void
|
||||
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)
|
||||
return error(&cpu, "No input.", 0);
|
||||
if(!load(&cpu, argv[1]))
|
||||
return error(&cpu, "Load error", 0);
|
||||
if(!boot(&cpu))
|
||||
return error(&cpu, "Boot error", 0);
|
||||
return error("Input", "Missing");
|
||||
if(!bootuxn(&u))
|
||||
return error("Boot", "Failed");
|
||||
if(!loaduxn(&u, argv[1]))
|
||||
return error("Load", "Failed");
|
||||
if(!init())
|
||||
return error("Init", "Failed");
|
||||
|
||||
/* print result */
|
||||
echos(&cpu.wst, 0x40, "stack");
|
||||
echom(&cpu.ram, 0x40, "ram");
|
||||
echof(&cpu);
|
||||
start(&u);
|
||||
|
||||
echos(&u.wst, 0x40, "stack");
|
||||
echom(&u.ram, 0x40, "ram");
|
||||
echof(&u);
|
||||
|
||||
quit();
|
||||
return 0;
|
||||
}
|
||||
|
|
89
uxn.c
89
uxn.c
|
@ -97,24 +97,44 @@ Uint8 opr[][2] = {
|
|||
/* clang-format on */
|
||||
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
inituxn(Uxn *u)
|
||||
{
|
||||
size_t i;
|
||||
char *cptr = (char *)u;
|
||||
for(i = 0; i < sizeof u; i++)
|
||||
cptr[i] = 0;
|
||||
}
|
||||
|
||||
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)
|
||||
return error(u, "Stack overflow", instr);
|
||||
return haltuxn(u, "Stack overflow", instr);
|
||||
wspush8(u, instr);
|
||||
u->literal--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
dodevices(Uxn *u) /* experimental */
|
||||
devuxn(Uxn *u) /* experimental */
|
||||
{
|
||||
if(u->ram.dat[0xfff1]) {
|
||||
printf("%c", u->ram.dat[0xfff1]);
|
||||
|
@ -124,7 +144,7 @@ dodevices(Uxn *u) /* experimental */
|
|||
}
|
||||
|
||||
int
|
||||
doopcode(Uxn *u, Uint8 instr)
|
||||
opcuxn(Uxn *u, Uint8 instr)
|
||||
{
|
||||
Uint8 op = instr & 0x1f;
|
||||
setflag(&u->status, FLAG_SHORT, (instr >> 5) & 1);
|
||||
|
@ -133,61 +153,40 @@ doopcode(Uxn *u, Uint8 instr)
|
|||
if(getflag(&u->status, FLAG_SHORT))
|
||||
op += 16;
|
||||
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)
|
||||
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)))
|
||||
(*ops[op])(u);
|
||||
dodevices(u);
|
||||
devuxn(u);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
eval(Uxn *u)
|
||||
evaluxn(Uxn *u, Uint16 vec)
|
||||
{
|
||||
Uint8 instr = u->ram.dat[u->ram.ptr++];
|
||||
if(u->literal > 0)
|
||||
return doliteral(u, instr);
|
||||
else
|
||||
return doopcode(u, instr);
|
||||
u->ram.ptr = vec;
|
||||
setflag(&u->status, FLAG_HALT, 0);
|
||||
while(!(u->status & FLAG_HALT)) {
|
||||
Uint8 instr = u->ram.dat[u->ram.ptr++];
|
||||
u->counter++;
|
||||
if(u->literal > 0)
|
||||
return lituxn(u, instr);
|
||||
else
|
||||
return opcuxn(u, instr);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
load(Uxn *u, char *filepath)
|
||||
bootuxn(Uxn *u)
|
||||
{
|
||||
FILE *f;
|
||||
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);
|
||||
inituxn(u);
|
||||
u->vreset = mempeek16(u, 0xfffa);
|
||||
u->vframe = mempeek16(u, 0xfffc);
|
||||
u->verror = mempeek16(u, 0xfffe);
|
||||
/* eval reset */
|
||||
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++;
|
||||
printf("Uxn Ready.\n");
|
||||
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);
|
||||
int getflag(Uint8 *status, char flag);
|
||||
int error(Uxn *c, char *name, int id);
|
||||
int load(Uxn *c, char *filepath);
|
||||
int boot(Uxn *c);
|
||||
int loaduxn(Uxn *c, char *filepath);
|
||||
int bootuxn(Uxn *c);
|
||||
int evaluxn(Uxn *u, Uint16 vec);
|
Loading…
Reference in New Issue