#include "common.h" #include "ppu.c" #include "uxn-fast.c" #include "rom.c" static Uxn u; static Ppu ppu; static Device *devscreen; static Device *devctrl; static Device *devmouse; static Device *devaudio; void nil_talk(Device *d, u8 b0, u8 w) { (void)d; (void)b0; (void)w; } void console_talk(Device *d, u8 b0, u8 w) { char stmp[2]; if(!w) { return; } switch(b0) { case 0x8: stmp[0] = d->dat[0x8]; stmp[1] = 0; uart_puts(stmp); break; // TODO: implement printf for the uart to be able to format // numbers. // case 0x9: txt_printf("0x%02x", d->dat[0x9]); break; // case 0xb: txt_printf("0x%04x", mempeek16(d->dat, 0xa)); break; // case 0xd: txt_printf("%s", &d->mem[mempeek16(d->dat, 0xc)]); break; } } static void docolors(Device *d) { for(size_t i = 0; i < 4; ++i) { u8 r = ((d->dat[0x8 + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11; u8 g = ((d->dat[0xa + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11; u8 b = ((d->dat[0xc + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11; if (rgb_order) { palette[i] = (b << 16) | (g << 8) | r; } else { palette[i] = (r << 16) | (g << 8) | b; } } for(size_t i = 4; i < 16; ++i) { palette[i] = palette[i / 4]; } // Redraw the screen if we change the color palette. reqdraw = 1; redraw_screen(); } void system_talk(Device *d, u8 b0, u8 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 0xf: d->u->ram.ptr = 0x0000; break; } if(b0 > 0x7 && b0 < 0xe) { docolors(d); } } (void)b0; } void screen_talk(Device *d, u8 b0, u8 w) { // uart_puts("screen_talk\n"); if(w && b0 == 0xe) { Uint16 x = mempeek16(d->dat, 0x8); Uint16 y = mempeek16(d->dat, 0xa); Uint8 layer = d->dat[0xe] >> 4 & 0x1; ppu_pixel(&ppu, layer, x, y, d->dat[0xe] & 0x3); reqdraw = 1; } else if(w && b0 == 0xf) { Uint16 x = mempeek16(d->dat, 0x8); Uint16 y = mempeek16(d->dat, 0xa); Uint8 layer = d->dat[0xf] >> 0x6 & 0x1; Uint8 *addr = &d->mem[mempeek16(d->dat, 0xc)]; if(d->dat[0xf] >> 0x7 & 0x1) ppu_2bpp(&ppu, layer, x, y, addr, d->dat[0xf] & 0xf, d->dat[0xf] >> 0x4 & 0x1, d->dat[0xf] >> 0x5 & 0x1); else ppu_1bpp(&ppu, layer, x, y, addr, d->dat[0xf] & 0xf, d->dat[0xf] >> 0x4 & 0x1, d->dat[0xf] >> 0x5 & 0x1); reqdraw = 1; } } static void audio_talk(Device *d, u8 b0, u8 w) { // TODO: Implement... // uart_puts("audio_talk\n"); (void)d; (void)b0; (void)w; } void datetime_talk(Device *d, u8 b0, u8 w) { // TODO: Implement... // uart_puts("datetime_talk\n"); (void)d; (void)b0; (void)w; } void file_talk(Device *d, u8 b0, u8 w) { // TODO: Implement... // uart_puts("file_talk\n"); (void)d; (void)b0; (void)w; } void init_uxn() { uart_puts("Initializing UXN.\n"); // Clear UXN memory. memzero8(&u, sizeof(Uxn)); ppu_init(&ppu, SCREEN_WIDTH / 8, SCREEN_HEIGHT / 8); // Copy rom to VM. memcpy(u.ram.dat + PAGE_PROGRAM, uxn_rom, sizeof(uxn_rom)); // Prepare devices. uxn_port(&u, 0x0, "system", system_talk); uxn_port(&u, 0x1, "console", console_talk); devscreen = uxn_port(&u, 0x2, "screen", screen_talk); devaudio = uxn_port(&u, 0x3, "audio0", audio_talk); uxn_port(&u, 0x4, "audio1", audio_talk); uxn_port(&u, 0x5, "audio2", audio_talk); uxn_port(&u, 0x6, "audio3", audio_talk); uxn_port(&u, 0x7, "---", nil_talk); devctrl = uxn_port(&u, 0x8, "controller", nil_talk); devmouse = uxn_port(&u, 0x9, "mouse", nil_talk); uxn_port(&u, 0xa, "file", file_talk); uxn_port(&u, 0xb, "datetime", datetime_talk); uxn_port(&u, 0xc, "---", nil_talk); uxn_port(&u, 0xd, "---", nil_talk); uxn_port(&u, 0xe, "---", nil_talk); uxn_port(&u, 0xf, "---", nil_talk); mempoke16(devscreen->dat, 2, ppu.width); mempoke16(devscreen->dat, 4, ppu.height); } void clear_bss(void) { extern u64 __bss_start; extern u64 __bss_end; u64 bss_size = &__bss_end - &__bss_start; memzero64(&__bss_start, bss_size); } void main(void) { // Initialization. clear_bss(); uart_init(); init_uxn(); uxn_eval(&u, 0x0100); u64 current_ticks = timer_get_ticks(); while (true) { // Echo input to standard output. uxn_eval(&u, mempeek16(devscreen->dat, 0)); // Blit ppu.pixels to the framebuffer. blit_framebuffer(&ppu); // Sync at 60 Hz. if ((timer_get_ticks() - current_ticks) < 16666) { wait(16666 - (timer_get_ticks() - current_ticks)); } current_ticks = timer_get_ticks(); } }