rockbox/apps/plugins/varvara/varvara.c

351 lines
11 KiB
C

/* Varvara plugin for rockbox. I have no idea what I'm doing.
Functions taken from uxnemu.c and uxncli.c are 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.
TODO screen vector, de-janking display code, support for greyscale displays
TODO other varvara devices
TODO hardware builds
TODO clean up
*/
#include "uxn.h"
#include "devices/ppu.h"
#include "plugin.h"
#include <stdio.h>
#include <stdint.h>
#include <time.h>
const uint8_t hwrom[] = { /* hello world ROM */
0x20, 0x01, 0x0e, 0x94, 0x80, 0x18, 0x17, 0x21,
0x94, 0x80, 0xf7, 0x0d, 0x22, 0x00, 0x48, 0x65,
0x6c, 0x6c, 0x6f, 0x20, 0x55, 0x78, 0x6e, 0x21,
0x21,
};
const uint8_t uxn_rom[] = { /* screen test ROM */
0x20, 0x01, 0x43, 0x80, 0x20, 0x37, 0x20, 0xf0,
0x7f, 0x80, 0x08, 0x37, 0x20, 0xf0, 0xe0, 0x80,
0x0a, 0x37, 0x20, 0xf0, 0xc0, 0x80, 0x0c, 0x37,
0x80, 0x22, 0x36, 0x80, 0x01, 0x3f, 0x20, 0x00,
0x20, 0x39, 0x80, 0x02, 0x31, 0x80, 0x24, 0x36,
0x80, 0x01, 0x3f, 0x80, 0x04, 0x31, 0x20, 0x01,
0xd4, 0x2e, 0x20, 0x02, 0x2f, 0x2e, 0x20, 0x02,
0x71, 0x2e, 0x20, 0x02, 0xae, 0x2e, 0x20, 0x03,
0x3a, 0x2e, 0x00, 0x80, 0x00, 0x30, 0x21, 0x23,
0x80, 0x00, 0x31, 0x80, 0x02, 0x30, 0x20, 0x00,
0x48, 0x38, 0x80, 0x28, 0x37, 0x80, 0x04, 0x30,
0x20, 0x00, 0x50, 0x39, 0x80, 0x2a, 0x37, 0x80,
0x01, 0x0f, 0x05, 0x03, 0x80, 0x04, 0x1f, 0x80,
0x00, 0x05, 0x80, 0x30, 0x3f, 0x20, 0x03, 0x91,
0x38, 0x80, 0x2c, 0x37, 0xcf, 0x80, 0x2f, 0x17,
0x80, 0x0f, 0x1c, 0x80, 0x00, 0x05, 0x80, 0x30,
0x3f, 0x20, 0x03, 0x91, 0x38, 0x80, 0x2c, 0x37,
0x80, 0x28, 0x36, 0x20, 0x00, 0x08, 0x38, 0x80,
0x28, 0x37, 0xcf, 0x80, 0x2f, 0x17, 0x03, 0x80,
0x04, 0x1f, 0x80, 0x00, 0x05, 0x80, 0x30, 0x3f,
0x20, 0x03, 0x91, 0x38, 0x80, 0x2c, 0x37, 0x80,
0x28, 0x36, 0x20, 0x00, 0x08, 0x38, 0x80, 0x28,
0x37, 0xcf, 0x80, 0x2f, 0x17, 0x80, 0x0f, 0x1c,
0x80, 0x00, 0x05, 0x80, 0x30, 0x3f, 0x20, 0x03,
0x91, 0x38, 0x80, 0x2c, 0x37, 0x80, 0x28, 0x36,
0x20, 0x00, 0x08, 0x38, 0x80, 0x28, 0x37, 0x4f,
0x80, 0x2f, 0x17, 0x00, 0x80, 0x10, 0x80, 0x00,
0x03, 0x80, 0x30, 0x1f, 0x80, 0x00, 0x05, 0x20,
0x03, 0x91, 0x38, 0x80, 0x2c, 0x37, 0x03, 0x80,
0x30, 0x1f, 0x80, 0x00, 0x05, 0x80, 0x02, 0x30,
0x20, 0x00, 0x40, 0x39, 0x38, 0x80, 0x28, 0x37,
0x80, 0x04, 0x30, 0x20, 0x00, 0x50, 0x39, 0x80,
0x2a, 0x37, 0x80, 0x01, 0x80, 0x2f, 0x17, 0x03,
0x80, 0x30, 0x1f, 0x80, 0x00, 0x05, 0x80, 0x04,
0x30, 0x20, 0x00, 0x40, 0x39, 0x38, 0x80, 0x2a,
0x37, 0x80, 0x02, 0x30, 0x20, 0x00, 0x50, 0x39,
0x80, 0x28, 0x37, 0x80, 0x01, 0x80, 0x2f, 0x17,
0x01, 0x8a, 0x80, 0xab, 0x0d, 0x22, 0x6c, 0x20,
0x03, 0x81, 0x80, 0x2c, 0x37, 0x80, 0x00, 0x80,
0x00, 0x03, 0x80, 0x0f, 0x1c, 0x80, 0x40, 0x1f,
0x80, 0x01, 0x1f, 0x80, 0x00, 0x05, 0x80, 0x02,
0x30, 0x20, 0x00, 0x40, 0x39, 0x38, 0x80, 0x28,
0x37, 0x03, 0x80, 0xf0, 0x1c, 0x80, 0x01, 0x1f,
0x80, 0x00, 0x05, 0x80, 0x04, 0x30, 0x20, 0x00,
0x40, 0x39, 0x38, 0x80, 0x2a, 0x37, 0x03, 0x80,
0x2f, 0x17, 0x01, 0x89, 0x80, 0xca, 0x0d, 0x22,
0x6c, 0x80, 0x10, 0x80, 0x00, 0x8f, 0x03, 0x80,
0x02, 0x1f, 0x80, 0x00, 0x05, 0x80, 0x40, 0x3f,
0x80, 0x04, 0x30, 0x20, 0x00, 0x40, 0x39, 0x38,
0x2f, 0x03, 0x80, 0x03, 0x1c, 0x80, 0x00, 0x05,
0x80, 0x40, 0x3f, 0x20, 0x00, 0x40, 0x38, 0x80,
0x02, 0x30, 0x20, 0x00, 0x08, 0x38, 0x38, 0x6f,
0x4f, 0x80, 0x00, 0x20, 0x02, 0xe7, 0x2e, 0x01,
0x8a, 0x80, 0xc9, 0x0d, 0x22, 0x6c, 0x80, 0x10,
0x80, 0x00, 0x8f, 0x03, 0x80, 0x02, 0x1f, 0x80,
0x00, 0x05, 0x80, 0x40, 0x3f, 0x80, 0x04, 0x30,
0x38, 0x2f, 0x03, 0x80, 0x03, 0x1c, 0x80, 0x00,
0x05, 0x80, 0x40, 0x3f, 0x20, 0x00, 0x40, 0x38,
0x80, 0x02, 0x30, 0x20, 0x00, 0x08, 0x38, 0x38,
0x6f, 0x4f, 0x80, 0x80, 0x20, 0x02, 0xe7, 0x2e,
0x01, 0x8a, 0x80, 0xcd, 0x0d, 0x22, 0x6c, 0x18,
0x0f, 0x20, 0x03, 0x81, 0x80, 0x2c, 0x37, 0x80,
0x2a, 0x37, 0x80, 0x28, 0x37, 0x80, 0x00, 0xcf,
0x18, 0x80, 0x2f, 0x17, 0x80, 0x28, 0x36, 0x20,
0x00, 0x08, 0x38, 0x80, 0x28, 0x37, 0x80, 0x10,
0xcf, 0x18, 0x80, 0x2f, 0x17, 0x80, 0x28, 0x36,
0x20, 0x00, 0x08, 0x39, 0x80, 0x28, 0x37, 0x80,
0x2a, 0x36, 0x20, 0x00, 0x08, 0x38, 0x80, 0x2a,
0x37, 0x80, 0x20, 0xcf, 0x18, 0x80, 0x2f, 0x17,
0x80, 0x28, 0x36, 0x20, 0x00, 0x08, 0x38, 0x80,
0x28, 0x37, 0x80, 0x30, 0x4f, 0x18, 0x80, 0x2f,
0x17, 0x6c, 0x80, 0x04, 0x30, 0x20, 0x00, 0x40,
0x39, 0x80, 0x2a, 0x37, 0x80, 0x02, 0x30, 0x20,
0x00, 0x48, 0x38, 0x80, 0x28, 0x37, 0x80, 0x00,
0x80, 0x2e, 0x17, 0x80, 0x02, 0x30, 0x20, 0x00,
0x49, 0x38, 0x80, 0x28, 0x37, 0x80, 0x01, 0x80,
0x2e, 0x17, 0x80, 0x02, 0x30, 0x20, 0x00, 0x4a,
0x38, 0x80, 0x28, 0x37, 0x80, 0x02, 0x80, 0x2e,
0x17, 0x80, 0x02, 0x30, 0x20, 0x00, 0x4b, 0x38,
0x80, 0x28, 0x37, 0x80, 0x03, 0x80, 0x2e, 0x17,
0x6c, 0x0f, 0x38, 0x67, 0x5f, 0xdf, 0xbf, 0xbf,
0xbf, 0x00, 0x07, 0x18, 0x20, 0x23, 0x44, 0x48,
0x48, 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, 0x80,
};
static Uxn u;
static Ppu ppu;
static Device *devsystem, *devconsole, *devscreen;
unsigned int palette[3];
static uint8_t framebuffer[LCD_HEIGHT * LCD_WIDTH * 4];
static void
memzero8(void *src, uint64_t n)
{
uint8_t * ptr = src;
for (size_t i = 0; i < n; i++) {
ptr[i] = 0;
}
}
/* taken from uxncli */
static void
inspect(Stack *s, char *name)
{
Uint8 x, y;
DEBUGF("\n%s\n", name);
for(y = 0; y < 0x04; ++y) {
for(x = 0; x < 0x08; ++x) {
Uint8 p = y * 0x08 + x;
DEBUGF(p == s->ptr ? "[%02x]" : " %02x ",
s->dat[p]);
}
DEBUGF("\n");
}
}
static void
set_palette(Uint8 *addr)
{
#if LCD_DEPTH > 1
int i;
for(i = 0; i < 4; ++i) {
Uint8
r = (*(addr + i / 2) >> (!(i % 2) << 2)) & 0x0f,
g = (*(addr + 2 + i / 2) >> (!(i % 2) << 2)) & 0x0f,
b = (*(addr + 4 + i / 2) >> (!(i % 2) << 2)) & 0x0f;
palette[i] = LCD_RGBPACK(r*8,g*8,b*8);
}
#else
int i;
for(i = 0; i < 4; ++i) {
Uint8
sum = (*(addr + i / 2) >> (!(i % 2) << 2)) & 0x0f;
sum += (*(addr + 2 + i / 2) >> (!(i % 2) << 2)) & 0x0f;
sum += (*(addr + 4 + i / 2) >> (!(i % 2) << 2)) & 0x0f;
palette[i] = sum > 0x17;
}
#endif
}
/* taken from uxncli */
static int
system_talk(Device *d, Uint8 b0, Uint8 w)
{
if(!w) { /* read */
switch(b0) {
case 0x2: d->dat[0x2] = d->u->wst.ptr; break;
case 0x3: d->dat[0x3] = d->u->rst.ptr; break;
}
} else { /* write */
switch(b0) {
case 0x2: d->u->wst.ptr = d->dat[0x2]; break;
case 0x3: d->u->rst.ptr = d->dat[0x3]; break;
case 0xe:
inspect(&d->u->wst, "Working-stack");
inspect(&d->u->rst, "Return-stack");
break;
case 0xf: return 0;
}
if(b0 > 0x7 && b0 < 0xe)
set_palette(&d->dat[0x8]);
}
return 1;
}
/* taken from uxncli */
static int
console_talk(Device *d, Uint8 b0, Uint8 w)
{
if(b0 == 0x1)
d->vector = peek16(d->dat, 0x0);
if(w && b0 > 0x7)
DEBUGF("%c",(char *)&d->dat[b0]);
return 1;
}
/* taken from uxnemu */
static int
screen_talk(Device *d, Uint8 b0, Uint8 w)
{
if(!w) switch(b0) {
case 0x2: d->dat[0x2] = ppu.width >> 8; break;
case 0x3: d->dat[0x3] = ppu.width; break;
case 0x4: d->dat[0x4] = ppu.height >> 8; break;
case 0x5: d->dat[0x5] = ppu.height; break;
}
else
switch(b0) {
case 0x1: d->vector = peek16(d->dat, 0x0); break;
case 0x5:
break;
case 0xe: {
Uint16 x = peek16(d->dat, 0x8);
Uint16 y = peek16(d->dat, 0xa);
Uint8 layer = d->dat[0xe] & 0x40;
ppu_write(&ppu, !!layer, x, y, d->dat[0xe] & 0x3);
if(d->dat[0x6] & 0x01) poke16(d->dat, 0x8, x + 1); /* auto x+1 */
if(d->dat[0x6] & 0x02) poke16(d->dat, 0xa, y + 1); /* auto y+1 */
break;
}
case 0xf: {
Uint16 x = peek16(d->dat, 0x8);
Uint16 y = peek16(d->dat, 0xa);
Uint8 layer = d->dat[0xf] & 0x40;
Uint8 *addr = &d->mem[peek16(d->dat, 0xc)];
if(d->dat[0xf] & 0x80) {
ppu_2bpp(&ppu, !!layer, x, y, addr, d->dat[0xf] & 0xf, d->dat[0xf] & 0x10, d->dat[0xf] & 0x20);
if(d->dat[0x6] & 0x04) poke16(d->dat, 0xc, peek16(d->dat, 0xc) + 16); /* auto addr+16 */
} else {
ppu_1bpp(&ppu, !!layer, x, y, addr, d->dat[0xf] & 0xf, d->dat[0xf] & 0x10, d->dat[0xf] & 0x20);
if(d->dat[0x6] & 0x04) poke16(d->dat, 0xc, peek16(d->dat, 0xc) + 8); /* auto addr+8 */
}
if(d->dat[0x6] & 0x01) poke16(d->dat, 0x8, x + 8); /* auto x+8 */
if(d->dat[0x6] & 0x02) poke16(d->dat, 0xa, y + 8); /* auto y+8 */
break;
}
}
return 1;
}
static int
nil_talk(Device *d, Uint8 b0, Uint8 w)
{
(void)d;
(void)b0;
(void)w;
return 1;
}
// TODO optimise, make build on non-color devices
static void redraw(void)
{
rb->lcd_clear_display();
Uint16 x, y;
for(y = 0; y < ppu.height; ++y)
for(x = 0; x < ppu.width; ++x) {
#if LCD_DEPTH > 1
rb->lcd_set_foreground(palette[ppu_read(&ppu, x, y)]);
rb->lcd_drawpixel(x, y);
#else
if(palette[ppu_read(&ppu, x, y)]) {
rb->lcd_drawpixel(x, y);
}
#endif
}
rb->lcd_update();
ppu.reqdraw = 0;
}
int
uxn_halt(Uxn *u, Uint8 error, char *name, int id)
{
DEBUGF("Halted");
return 0;
}
/* this is the plugin entry point */
enum plugin_status plugin_start(const void* parameter)
{
(void)parameter;
DEBUGF("Setting PPU size\n");
ppu_init(&ppu, LCD_WIDTH, LCD_HEIGHT, framebuffer);
DEBUGF("UXN init\n");
// Clear RAM and copy rom to VM.
DEBUGF("zeroing\n");
memzero8(&u, sizeof(Uxn));
DEBUGF("copying ROM\n");
memcpy(u.ram.dat + PAGE_PROGRAM, uxn_rom, sizeof(uxn_rom));
DEBUGF("registering ports\n");
// Register ports
/* system */ devsystem = uxn_port(&u, 0x0, system_talk);
/* console */ devconsole = uxn_port(&u, 0x1, console_talk);
/* screen */ devscreen = uxn_port(&u, 0x2, screen_talk);
/* audio0 */ uxn_port(&u, 0x3, nil_talk);
/* audio1 */ uxn_port(&u, 0x4, nil_talk);
/* audio2 */ uxn_port(&u, 0x5, nil_talk);
/* audio3 */ uxn_port(&u, 0x6, nil_talk);
/* empty */ uxn_port(&u, 0x7, nil_talk);
/* control */ uxn_port(&u, 0x8, nil_talk);
/* mouse */ uxn_port(&u, 0x9, nil_talk);
/* file */ uxn_port(&u, 0xa, nil_talk);
/* datetime */ uxn_port(&u, 0xb, nil_talk);
/* empty */ uxn_port(&u, 0xc, nil_talk);
/* empty */ uxn_port(&u, 0xd, nil_talk);
/* empty */ uxn_port(&u, 0xe, nil_talk);
/* empty */ uxn_port(&u, 0xf, nil_talk);
DEBUGF("eval\n");
uxn_eval(&u, 0x0100);
redraw();
rb->button_get(true);
return PLUGIN_OK;
}