rockbox/apps/plugins/varvara/varvara.c

407 lines
13 KiB
C

/* Varvara plugin for rockbox. I have no idea what I'm doing.
copyright (c) 2021 Devine Lu Linvega
copyright (c) 2021 nihilazo
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 de-janking display code, support for greyscale displays
TODO rom loading
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 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 screenrom[] = { /* 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,
};
const Uint8 uxn_rom[] = { // screen vector test ROM
0x20, 0x01, 0x19, 0x80, 0x20, 0x37, 0x20, 0x0f,
0x7f, 0x80, 0x08, 0x37, 0x20, 0x0f, 0xe0, 0x80,
0x0a, 0x37, 0x20, 0x0f, 0xc0, 0x80, 0x0c, 0x37,
0x00, 0x80, 0x00, 0x30, 0x21, 0x23, 0x80, 0x00,
0x31, 0x20, 0x00, 0x00, 0x80, 0x28, 0x37, 0x20,
0x00, 0x00, 0x80, 0x2a, 0x37, 0x80, 0x01, 0x0f,
0x05, 0x03, 0x80, 0x04, 0x1f, 0x80, 0x00, 0x05,
0x80, 0x30, 0x3f, 0x20, 0x01, 0xb2, 0x38, 0x80,
0x2c, 0x37, 0xcf, 0x80, 0x2f, 0x17, 0x80, 0x0f,
0x1c, 0x80, 0x00, 0x05, 0x80, 0x30, 0x3f, 0x20,
0x01, 0xb2, 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, 0x01,
0xb2, 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, 0x01, 0xb2, 0x38,
0x80, 0x2c, 0x37, 0x80, 0x28, 0x36, 0x20, 0x00,
0x08, 0x38, 0x80, 0x28, 0x37, 0x4f, 0x80, 0x2f,
0x17, 0x00, 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 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)
{
rb->splash(HZ, "Halted\n");
return 0;
}
static void run() {
while(!devsystem->dat[0xf]) {
uxn_eval(&u, devscreen->vector);
if(ppu.reqdraw || devsystem->dat[0xe])
redraw();
switch(rb->button_get(false)) {
case BUTTON_NONE: break;
default:
return;
}
rb->sleep(HZ/60);
}
}
/* 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);
run();
return PLUGIN_OK;
}