Starting controller

This commit is contained in:
neauoire 2022-03-26 19:58:48 -07:00
parent 51542bc5ef
commit a34ceda22c
8 changed files with 266 additions and 192 deletions

View File

@ -9,10 +9,10 @@ echo "Building.."
mkdir -p bin mkdir -p bin
# Build(debug) # Build(debug)
gcc -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 src/uxn.c src/devices/system.c src/devices/screen.c src/uxn11.c -o bin/uxn11 -lX11 gcc -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 src/uxn.c src/devices/system.c src/devices/screen.c src/devices/controller.c src/uxn11.c -o bin/uxn11 -lX11
# Build(release) # Build(release)
# gcc src/uxn.c src/devices/system.c src/devices/screen.c src/uxn11.c -o bin/uxn11 -lX11 # gcc src/uxn.c src/devices/system.c src/devices/screen.c src/devices/controller.c src/uxn11.c -o bin/uxn11 -lX11
echo "Running.." echo "Running.."
bin/uxn11 etc/screen.rom bin/uxn11 etc/controller.rom

BIN
etc/controller.rom Normal file

Binary file not shown.

52
src/devices/controller.c Normal file
View File

@ -0,0 +1,52 @@
#include "../uxn.h"
#include "controller.h"
/*
Copyright (c) 2021 Devine Lu Linvega
Copyright (c) 2021 Andrew Alderwick
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/
void
controller_down(Device *d, Uint8 mask)
{
if(mask) {
d->dat[2] |= mask;
uxn_eval(d->u, GETVECTOR(d));
}
}
void
controller_up(Device *d, Uint8 mask)
{
if(mask) {
d->dat[2] &= (~mask);
uxn_eval(d->u, GETVECTOR(d));
}
}
void
controller_key(Device *d, Uint8 key)
{
if(key) {
d->dat[3] = key;
uxn_eval(d->u, GETVECTOR(d));
d->dat[3] = 0x00;
}
}
void
controller_special(Device *d, Uint8 key)
{
if(key) {
d->dat[4] = key;
uxn_eval(d->u, GETVECTOR(d));
d->dat[4] = 0x00;
}
}

16
src/devices/controller.h Normal file
View File

@ -0,0 +1,16 @@
/*
Copyright (c) 2021 Devine Lu Linvega
Copyright (c) 2021 Andrew Alderwick
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/
void controller_down(Device *d, Uint8 mask);
void controller_up(Device *d, Uint8 mask);
void controller_key(Device *d, Uint8 key);
void controller_special(Device *d, Uint8 key);

View File

@ -1,150 +0,0 @@
#include "ppu.h"
/*
Copyright (c) 2021 Devine Lu Linvega
Copyright (c) 2021 Andrew Alderwick
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/
static Uint8 blending[5][16] = {
{0, 0, 0, 0, 1, 0, 1, 1, 2, 2, 0, 2, 3, 3, 3, 0},
{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3},
{1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1},
{2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2},
{1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0}};
static Uint8 font[][8] = {
{0x00, 0x7c, 0x82, 0x82, 0x82, 0x82, 0x82, 0x7c},
{0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10},
{0x00, 0x7c, 0x82, 0x02, 0x7c, 0x80, 0x80, 0xfe},
{0x00, 0x7c, 0x82, 0x02, 0x1c, 0x02, 0x82, 0x7c},
{0x00, 0x0c, 0x14, 0x24, 0x44, 0x84, 0xfe, 0x04},
{0x00, 0xfe, 0x80, 0x80, 0x7c, 0x02, 0x82, 0x7c},
{0x00, 0x7c, 0x82, 0x80, 0xfc, 0x82, 0x82, 0x7c},
{0x00, 0x7c, 0x82, 0x02, 0x1e, 0x02, 0x02, 0x02},
{0x00, 0x7c, 0x82, 0x82, 0x7c, 0x82, 0x82, 0x7c},
{0x00, 0x7c, 0x82, 0x82, 0x7e, 0x02, 0x82, 0x7c},
{0x00, 0x7c, 0x82, 0x02, 0x7e, 0x82, 0x82, 0x7e},
{0x00, 0xfc, 0x82, 0x82, 0xfc, 0x82, 0x82, 0xfc},
{0x00, 0x7c, 0x82, 0x80, 0x80, 0x80, 0x82, 0x7c},
{0x00, 0xfc, 0x82, 0x82, 0x82, 0x82, 0x82, 0xfc},
{0x00, 0x7c, 0x82, 0x80, 0xf0, 0x80, 0x82, 0x7c},
{0x00, 0x7c, 0x82, 0x80, 0xf0, 0x80, 0x80, 0x80}};
void
ppu_palette(Ppu *p, Uint8 *addr)
{
int i, shift;
for(i = 0, shift = 4; i < 4; ++i, shift ^= 4) {
Uint8
r = (addr[0 + i / 2] >> shift) & 0x0f,
g = (addr[2 + i / 2] >> shift) & 0x0f,
b = (addr[4 + i / 2] >> shift) & 0x0f;
p->palette[i] = 0x0f000000 | r << 16 | g << 8 | b;
p->palette[i] |= p->palette[i] << 4;
}
p->fg.changed = p->bg.changed = 1;
}
void
ppu_resize(Ppu *p, Uint16 width, Uint16 height)
{
Uint8
*bg = realloc(p->bg.pixels, width * height),
*fg = realloc(p->fg.pixels, width * height);
if(bg) p->bg.pixels = bg;
if(fg) p->fg.pixels = fg;
if(bg && fg) {
p->width = width;
p->height = height;
ppu_clear(p, &p->bg);
ppu_clear(p, &p->fg);
}
}
void
ppu_clear(Ppu *p, Layer *layer)
{
Uint32 i, size = p->width * p->height;
for(i = 0; i < size; ++i)
layer->pixels[i] = 0x00;
layer->changed = 1;
}
#pragma weak ppu_redraw
void
ppu_redraw(Ppu *p, Uint32 *screen)
{
Uint32 i, size = p->width * p->height, palette[16];
for(i = 0; i < 16; ++i)
palette[i] = p->palette[(i >> 2) ? (i >> 2) : (i & 3)];
for(i = 0; i < size; ++i)
screen[i] = palette[p->fg.pixels[i] << 2 | p->bg.pixels[i]];
p->fg.changed = p->bg.changed = 0;
}
void
ppu_write(Ppu *p, Layer *layer, Uint16 x, Uint16 y, Uint8 color)
{
if(x < p->width && y < p->height) {
Uint32 i = x + y * p->width;
Uint8 prev = layer->pixels[i];
if(color != prev) {
layer->pixels[i] = color;
layer->changed = 1;
}
}
}
void
ppu_blit(Ppu *p, Layer *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy, Uint8 twobpp)
{
int v, h, opaque = blending[4][color];
for(v = 0; v < 8; ++v) {
Uint16 c = sprite[v] | (twobpp ? sprite[v + 8] : 0) << 8;
for(h = 7; h >= 0; --h, c >>= 1) {
Uint8 ch = (c & 1) | ((c >> 7) & 2);
if(opaque || ch)
ppu_write(p,
layer,
x + (flipx ? 7 - h : h),
y + (flipy ? 7 - v : v),
blending[ch][color]);
}
}
}
void
ppu_debug(Ppu *p, Uint8 *stack, Uint8 wptr, Uint8 rptr, Uint8 *memory)
{
Uint8 i, x, y, b;
for(i = 0; i < 0x20; ++i) {
x = ((i % 8) * 3 + 1) * 8, y = (i / 8 + 1) * 8, b = stack[i];
/* working stack */
ppu_blit(p, &p->fg, x, y, font[(b >> 4) & 0xf], 1 + (wptr == i) * 0x7, 0, 0, 0);
ppu_blit(p, &p->fg, x + 8, y, font[b & 0xf], 1 + (wptr == i) * 0x7, 0, 0, 0);
y = 0x28 + (i / 8 + 1) * 8;
b = memory[i];
/* return stack */
ppu_blit(p, &p->fg, x, y, font[(b >> 4) & 0xf], 3, 0, 0, 0);
ppu_blit(p, &p->fg, x + 8, y, font[b & 0xf], 3, 0, 0, 0);
}
/* return pointer */
ppu_blit(p, &p->fg, 0x8, y + 0x10, font[(rptr >> 4) & 0xf], 0x2, 0, 0, 0);
ppu_blit(p, &p->fg, 0x10, y + 0x10, font[rptr & 0xf], 0x2, 0, 0, 0);
/* guides */
for(x = 0; x < 0x10; ++x) {
ppu_write(p, &p->fg, x, p->height / 2, 2);
ppu_write(p, &p->fg, p->width - x, p->height / 2, 2);
ppu_write(p, &p->fg, p->width / 2, p->height - x, 2);
ppu_write(p, &p->fg, p->width / 2, x, 2);
ppu_write(p, &p->fg, p->width / 2 - 0x10 / 2 + x, p->height / 2, 2);
ppu_write(p, &p->fg, p->width / 2, p->height / 2 - 0x10 / 2 + x, 2);
}
}

View File

@ -1,37 +0,0 @@
#include <stdlib.h>
/*
Copyright (c) 2021 Devine Lu Linvega
Copyright (c) 2021 Andrew Alderwick
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/
typedef unsigned char Uint8;
typedef unsigned short Uint16;
typedef unsigned int Uint32;
typedef struct Layer {
Uint8 *pixels;
Uint8 changed;
} Layer;
typedef struct Ppu {
Uint32 palette[4];
Uint16 width, height;
Layer fg, bg;
} Ppu;
void ppu_palette(Ppu *p, Uint8 *addr);
void ppu_resize(Ppu *p, Uint16 width, Uint16 height);
void ppu_clear(Ppu *p, Layer *layer);
void ppu_redraw(Ppu *p, Uint32 *screen);
void ppu_write(Ppu *p, Layer *layer, Uint16 x, Uint16 y, Uint8 color);
void ppu_blit(Ppu *p, Layer *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy, Uint8 twobpp);
void ppu_debug(Ppu *p, Uint8 *stack, Uint8 wptr, Uint8 rptr, Uint8 *memory);

View File

@ -12,6 +12,9 @@
#include "uxn.h" #include "uxn.h"
#include "devices/system.h" #include "devices/system.h"
#include "devices/screen.h" #include "devices/screen.h"
#include "devices/controller.h"
static Device *devctrl;
static int static int
error(char *msg, const char *err) error(char *msg, const char *err)
@ -64,6 +67,18 @@ load(Uxn *u, char *filepath)
return 1; return 1;
} }
/* /usr/include/X11/keysymdef.h */
#define XK_Left 0xff51
#define XK_Up 0xff52
#define XK_Right 0xff53
#define XK_Down 0xff54
#define XK_Home 0xff50
#define XK_Shift 0xffe1
#define XK_Control 0xffe3
#define XK_Alt 0xffe9
void void
processEvent(Display *display, Window window, XImage *ximage, int width, int height) processEvent(Display *display, Window window, XImage *ximage, int width, int height)
{ {
@ -73,6 +88,28 @@ processEvent(Display *display, Window window, XImage *ximage, int width, int hei
case Expose: case Expose:
XPutImage(display, window, DefaultGC(display, 0), ximage, 0, 0, 0, 0, width, height); XPutImage(display, window, DefaultGC(display, 0), ximage, 0, 0, 0, 0, width, height);
break; break;
case KeyPress: {
XKeyPressedEvent *e = (XKeyPressedEvent *)&ev;
if(e->keycode == XKeysymToKeycode(display, XK_Up)) controller_down(devctrl, 0x10);
if(e->keycode == XKeysymToKeycode(display, XK_Down)) controller_down(devctrl, 0x20);
if(e->keycode == XKeysymToKeycode(display, XK_Left)) controller_down(devctrl, 0x40);
if(e->keycode == XKeysymToKeycode(display, XK_Right)) controller_down(devctrl, 0x80);
if(e->keycode == XKeysymToKeycode(display, XK_Control)) controller_down(devctrl, 0x01);
if(e->keycode == XKeysymToKeycode(display, XK_Alt)) controller_down(devctrl, 0x02);
if(e->keycode == XKeysymToKeycode(display, XK_Shift)) controller_down(devctrl, 0x04);
if(e->keycode == XKeysymToKeycode(display, XK_Home)) controller_down(devctrl, 0x08);
} break;
case KeyRelease: {
XKeyPressedEvent *e = (XKeyPressedEvent *)&ev;
if(e->keycode == XKeysymToKeycode(display, XK_Up)) controller_up(devctrl, 0x10);
if(e->keycode == XKeysymToKeycode(display, XK_Down)) controller_up(devctrl, 0x20);
if(e->keycode == XKeysymToKeycode(display, XK_Left)) controller_up(devctrl, 0x40);
if(e->keycode == XKeysymToKeycode(display, XK_Right)) controller_up(devctrl, 0x80);
if(e->keycode == XKeysymToKeycode(display, XK_Control)) controller_up(devctrl, 0x01);
if(e->keycode == XKeysymToKeycode(display, XK_Alt)) controller_up(devctrl, 0x02);
if(e->keycode == XKeysymToKeycode(display, XK_Shift)) controller_up(devctrl, 0x04);
if(e->keycode == XKeysymToKeycode(display, XK_Home)) controller_up(devctrl, 0x08);
} break;
case ButtonPress: case ButtonPress:
exit(0); exit(0);
} }
@ -91,7 +128,7 @@ start(Uxn *u)
/* empty */ uxn_port(u, 0x5, nil_dei, nil_deo); /* empty */ uxn_port(u, 0x5, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0x6, nil_dei, nil_deo); /* empty */ uxn_port(u, 0x6, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0x7, nil_dei, nil_deo); /* empty */ uxn_port(u, 0x7, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0x8, nil_dei, nil_deo); /* control */ devctrl = uxn_port(u, 0x8, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0x9, nil_dei, nil_deo); /* empty */ uxn_port(u, 0x9, nil_dei, nil_deo);
/* file */ uxn_port(u, 0xa, nil_dei, nil_deo); /* file */ uxn_port(u, 0xa, nil_dei, nil_deo);
/* datetime */ uxn_port(u, 0xb, nil_dei, nil_deo); /* datetime */ uxn_port(u, 0xb, nil_dei, nil_deo);
@ -102,6 +139,11 @@ start(Uxn *u)
return 1; return 1;
} }
void
redraw(void)
{
}
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@ -132,10 +174,13 @@ main(int argc, char **argv)
ximage = XCreateImage(display, visual, DefaultDepth(display, DefaultScreen(display)), ZPixmap, 0, (char *)uxn_screen.pixels, uxn_screen.width, uxn_screen.height, 32, 0); ximage = XCreateImage(display, visual, DefaultDepth(display, DefaultScreen(display)), ZPixmap, 0, (char *)uxn_screen.pixels, uxn_screen.width, uxn_screen.height, 32, 0);
XSelectInput(display, window, ButtonPressMask | ExposureMask); XSelectInput(display, window, ButtonPressMask | ExposureMask | KeyPressMask | KeyReleaseMask);
XMapWindow(display, window); XMapWindow(display, window);
while(1) { while(1) {
processEvent(display, window, ximage, uxn_screen.width, uxn_screen.height); processEvent(display, window, ximage, uxn_screen.width, uxn_screen.height);
if(uxn_screen.fg.changed || uxn_screen.bg.changed)
redraw();
} }
return 0; return 0;
} }

148
src/uxncli.c Normal file
View File

@ -0,0 +1,148 @@
#include <stdio.h>
#include <stdlib.h>
#include "uxn.h"
#include "devices/system.h"
#include "devices/file.h"
#include "devices/datetime.h"
/*
Copyright (c) 2021 Devine Lu Linvega
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/
static Device *devfile0;
static int
error(char *msg, const char *err)
{
fprintf(stderr, "Error %s: %s\n", msg, err);
return 0;
}
void
system_deo_special(Device *d, Uint8 port)
{
(void)d;
(void)port;
}
static void
console_deo(Device *d, Uint8 port)
{
FILE *fd = port == 0x8 ? stdout : port == 0x9 ? stderr
: 0;
if(fd) {
fputc(d->dat[port], fd);
fflush(fd);
}
}
static void
file_deo(Device *d, Uint8 port)
{
file_i_deo(d - devfile0, d, port);
}
static Uint8
file_dei(Device *d, Uint8 port)
{
return file_i_dei(d - devfile0, d, port);
}
static Uint8
nil_dei(Device *d, Uint8 port)
{
return d->dat[port];
}
static void
nil_deo(Device *d, Uint8 port)
{
(void)d;
(void)port;
}
static int
console_input(Uxn *u, char c)
{
Device *d = &u->dev[1];
d->dat[0x2] = c;
return uxn_eval(u, GETVECTOR(d));
}
static void
run(Uxn *u)
{
Device *d = &u->dev[0];
while(!d->dat[0xf]) {
int c = fgetc(stdin);
if(c != EOF)
console_input(u, (Uint8)c);
}
}
static int
load(Uxn *u, char *filepath)
{
FILE *f;
int r;
if(!(f = fopen(filepath, "rb"))) return 0;
r = fread(u->ram + PAGE_PROGRAM, 1, 0x10000 - PAGE_PROGRAM, f);
fclose(f);
if(r < 1) return 0;
fprintf(stderr, "Loaded %s\n", filepath);
return 1;
}
static int
start(Uxn *u)
{
if(!uxn_boot(u, (Uint8 *)calloc(0x10000, sizeof(Uint8))))
return error("Boot", "Failed");
/* system */ uxn_port(u, 0x0, system_dei, system_deo);
/* console */ uxn_port(u, 0x1, nil_dei, console_deo);
/* empty */ uxn_port(u, 0x2, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0x3, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0x4, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0x5, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0x6, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0x7, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0x8, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0x9, nil_dei, nil_deo);
/* file0 */ devfile0 = uxn_port(u, 0xa, file_dei, file_deo);
/* file1 */ uxn_port(u, 0xb, file_dei, file_deo);
/* datetime */ uxn_port(u, 0xc, datetime_dei, nil_deo);
/* empty */ uxn_port(u, 0xd, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0xe, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0xf, nil_dei, nil_deo);
return 1;
}
int
main(int argc, char **argv)
{
Uxn u;
int i;
if(argc < 2)
return error("Usage", "uxncli game.rom args");
if(!start(&u))
return error("Start", "Failed");
if(!load(&u, argv[1]))
return error("Load", "Failed");
if(!uxn_eval(&u, PAGE_PROGRAM))
return error("Init", "Failed");
for(i = 2; i < argc; i++) {
char *p = argv[i];
while(*p) console_input(&u, *p++);
console_input(&u, '\n');
}
run(&u);
return 0;
}