From d68d16405b013967e0faa12f9dfc608e3bb3d0d4 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Wed, 19 Apr 2023 17:58:04 +0200 Subject: Update uxn core and fix some new ppu bugs --- src/main.c | 162 +++++++++++++++++++++++++++++++++++++------------------------ src/ppu.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++----------- src/uxn.c | 160 +++++++++++++++++++++++++++++++----------------------------- src/uxn.h | 8 +-- 4 files changed, 318 insertions(+), 174 deletions(-) diff --git a/src/main.c b/src/main.c index 1193e9e..ba835ff 100644 --- a/src/main.c +++ b/src/main.c @@ -13,16 +13,16 @@ #include #include "common.h" -#include "bitmap.h" #include "filesystem.c" -#include "rom.c" #include "uxn.c" #include "ppu.c" #include "apu.c" #include "file.c" #include "text.h" +#include "rom.c" + // // Config parameters. // @@ -37,6 +37,8 @@ #define CONTROL_METHODS CONTROL_CONTROLLER,CONTROL_MOUSE,CONTROL_KEYBOARD #endif +#define PROF_ENABLE 1 + #ifdef PROF_ENABLE #if PROF_ENABLE == 0 #define TEXT_ENABLE 1 @@ -148,20 +150,29 @@ screen_deo(u8 *ram, u8 *d, u8 port) { switch(port) { case 0xe: { u16 x, y; - u8 layer = d[0xe] & 0x40; - PEKDEV(x, 0x8); - PEKDEV(y, 0xa); - PROF(ppu_pixel(layer ? ppu.fg : ppu.bg, x, y, d[0xe] & 0x3), ppu_pixel_cycles); - if(d[0x6] & 0x01) POKDEV(0x8, x + 1); /* auto x+1 */ - if(d[0x6] & 0x02) POKDEV(0xa, y + 1); /* auto y+1 */ + u8 *layer = (d[0xe] & 0x40) ? ppu.fg : ppu.bg; + x = PEEK2(d + 0x8); + y = PEEK2(d + 0xa); + if(d[0xe] & 0x80) { + screen_fill(layer, + (d[0xe] & 0x10) ? 0 : x, + (d[0xe] & 0x20) ? 0 : y, + (d[0xe] & 0x10) ? x : SCREEN_WIDTH, + (d[0xe] & 0x20) ? y : SCREEN_HEIGHT, + (d[0xe] & 0x03)); + } else { + PROF(ppu_pixel(layer, x, y, d[0xe] & 0x3), ppu_pixel_cycles); + if(d[0x6] & 0x01) POKE2(d + 0x8, x + 1); /* auto x+1 */ + if(d[0x6] & 0x02) POKE2(d + 0xa, y + 1); /* auto y+1 */ + } break; } case 0xf: { u16 x, y, dx, dy, addr; u8 n, twobpp = !!(d[0xf] & 0x80); - PEKDEV(x, 0x8); - PEKDEV(y, 0xa); - PEKDEV(addr, 0xc); + x = PEEK2(d + 0x8); + y = PEEK2(d + 0xa); + addr = PEEK2(d + 0xc); n = d[0x6] >> 4; dx = (d[0x6] & 0x01) << 3; dy = (d[0x6] & 0x02) << 2; @@ -181,9 +192,9 @@ screen_deo(u8 *ram, u8 *d, u8 port) { } addr += (d[0x6] & 0x04) << (1 + twobpp); } - POKDEV(0xc, addr); /* auto addr+length */ - POKDEV(0x8, x + dx); /* auto x+8 */ - POKDEV(0xa, y + dy); /* auto y+8 */ + POKE2(d + 0xc, addr); /* auto addr+length */ + POKE2(d + 0x8, x + dx); /* auto x+8 */ + POKE2(d + 0xa, y + dy); /* auto y+8 */ break; } } @@ -195,7 +206,7 @@ audio_dei(int instance, u8 *d, u8 port) { switch(port) { // case 0x4: return apu_get_vu(instance); case 0x2: { - POKDEV(0x2, c->pos); + POKE2(d + 0x2, c->pos); c->pos <<= 12; // fixed point. break; } @@ -211,9 +222,9 @@ audio_deo(int instance, u8 *d, u8 port, Uxn *u) { u16 adsr = 0; u16 addr = 0; u8 pitch = d[0xf] & 0x7f; - PEKDEV(adsr, 0x8); - PEKDEV(length, 0xa); - PEKDEV(addr, 0xc); + adsr = PEEK2(d + 0x8); + length = PEEK2(d + 0xa); + addr = PEEK2(d + 0xc); u8 *data = &u->ram[addr]; u32 vol = MAX(d[0xe] >> 4, d[0xe] & 0xf) * 4 / 3; bool loop = !(d[0xf] & 0x80); @@ -248,7 +259,7 @@ file_dei(u8 id, u8 *d, u8 port) { case 0xc: case 0xd: { res = file_read(c, &d[port], 1); - POKDEV(0x2, res); + POKE2(d + 0x2, res); break; } } @@ -261,41 +272,41 @@ file_deo(u8 id, u8 *ram, u8 *d, u8 port) { UxnFile *f = &uxn_file[id]; switch(port) { case 0x5: { - PEKDEV(a, 0x4); - PEKDEV(b, 0xa); + a = PEEK2(d + 0x4); + b = PEEK2(d + 0xa); if(b > 0x10000 - a) { b = 0x10000 - a; } res = file_stat(f, &ram[a], b); - POKDEV(0x2, res); + POKE2(d + 0x2, res); } break; case 0x6: { // TODO: no file deletion for now // res = file_delete(); - // POKDEV(0x2, res); + // POKE2(d + 0x2, res); } break; case 0x9: { - PEKDEV(a, 0x8); + a = PEEK2(d + 0x8); res = file_init(f, &ram[a]); - POKDEV(0x2, res); + POKE2(d + 0x2, res); } break; case 0xd: { - PEKDEV(a, 0xc); - PEKDEV(b, 0xa); + a = PEEK2(d + 0xc); + b = PEEK2(d + 0xa); if(b > 0x10000 - a) { b = 0x10000 - a; } res = file_read(f, &ram[a], b); - POKDEV(0x2, res); + POKE2(d + 0x2, res); } break; case 0xf: { - PEKDEV(a, 0xe); - PEKDEV(b, 0xa); + a = PEEK2(d + 0xe); + b = PEEK2(d + 0xa); if(b > 0x10000 - a) { b = 0x10000 - a; } res = file_write(f, &ram[a], b, d[0x7]); - POKDEV(0x2, res); + POKE2(d + 0x2, res); } break; } } @@ -313,16 +324,42 @@ console_deo(u8 *d, u8 port) { } } +#define RAM_PAGES 0x10 + +static void +system_cmd(u8 *ram, u16 addr) { + // if(ram[addr] == 0x01) { + // u16 i, length = PEEK2(ram + addr + 1); + // u16 a_page = PEEK2(ram + addr + 1 + 2); + // u16 a_addr = PEEK2(ram + addr + 1 + 4); + // u16 b_addr = PEEK2(ram + addr + 1 + 8); + // u8 *rom = uxn_rom; + // for(i = 0; i < length; i++) { + // switch (a_page % RAM_PAGES) { + // case 0: { rom = uxn_rom; } break; + // case 1: { rom = uxn_rom_2; } break; + // case 2: { rom = uxn_rom_3; } break; + // case 3: { rom = uxn_rom_4; } break; + // case 4: { rom = uxn_rom_5; } break; + // case 5: { rom = uxn_rom_6; } break; + // case 6: { rom = uxn_rom_7; } break; + // } + // ram[(u16)(b_addr + i)] = rom[(u16)(a_addr + i)]; + // } + // } +} + void system_deo(Uxn *u, u8 *d, u8 port) { switch(port) { - case 0x2: u->wst = (Stack *)(u->ram + (d[port] ? (d[port] * 0x100) : 0x10000)); break; - case 0x3: u->rst = (Stack *)(u->ram + (d[port] ? (d[port] * 0x100) : 0x10100)); break; + case 0x3: { + system_cmd(u->ram, PEEK2(d + 2)); + } break; } } u8 -emu_dei(Uxn *u, u8 addr) { +uxn_dei(Uxn *u, u8 addr) { u8 p = addr & 0x0f, d = addr & 0xf0; switch(d) { case 0x20: return screen_dei(&u->dev[d], p); @@ -338,24 +375,23 @@ emu_dei(Uxn *u, u8 addr) { } void -emu_deo(Uxn *u, u8 addr, u8 v) { - u8 p = addr & 0x0f, d = addr & 0xf0; - u->dev[addr] = v; - switch(d) { - case 0x00: - system_deo(u, &u->dev[d], p); - if(p > 0x7 && p < 0xe) - putcolors(&u->dev[0x8]); - break; - case 0x10: console_deo(&u->dev[d], p); break; - case 0x20: screen_deo(u->ram, &u->dev[d], p); break; - case 0x30: audio_deo(0, &u->dev[d], p, u); break; - case 0x40: audio_deo(1, &u->dev[d], p, u); break; - case 0x50: audio_deo(2, &u->dev[d], p, u); break; - case 0x60: audio_deo(3, &u->dev[d], p, u); break; - case 0xa0: file_deo(0, u->ram, &u->dev[d], p); break; - case 0xb0: file_deo(1, u->ram, &u->dev[d], p); break; - } +uxn_deo(Uxn *u, u8 addr) { + u8 p = addr & 0x0f, d = addr & 0xf0; + switch(d) { + case 0x00: + system_deo(u, &u->dev[d], p); + if(p > 0x7 && p < 0xe) + putcolors(&u->dev[0x8]); + break; + case 0x10: console_deo(&u->dev[d], p); break; + case 0x20: screen_deo(u->ram, &u->dev[d], p); break; + case 0x30: audio_deo(0, &u->dev[d], p, u); break; + case 0x40: audio_deo(1, &u->dev[d], p, u); break; + case 0x50: audio_deo(2, &u->dev[d], p, u); break; + case 0x60: audio_deo(3, &u->dev[d], p, u); break; + case 0xa0: file_deo(0, u->ram, &u->dev[d], p); break; + case 0xb0: file_deo(1, u->ram, &u->dev[d], p); break; + } } void @@ -363,7 +399,7 @@ init_uxn(Uxn *u) { // Initialize uxn. u32 fill = 0; dma_fill(umem, fill, 0x10300, 3); - uxn_boot(u, umem, emu_dei, emu_deo); + uxn_boot(u, umem, uxn_dei, uxn_deo); // Copy rom to VM. memcpy(u->ram + PAGE_PROGRAM, uxn_rom, sizeof(uxn_rom)); @@ -379,16 +415,16 @@ handle_input(Uxn *u) { case CONTROL_CONTROLLER: { u8 *d = &u->dev[0x80]; d[2] = 0; - uxn_eval(u, GETVEC(d)); + uxn_eval(u, PEEK2(d)); d[3] = 0; } break; case CONTROL_MOUSE: { u8 *d = &u->dev[0x90]; d[6] = 0; d[7] = 0; - POKDEV(0x2, -10); - POKDEV(0x4, -10); - uxn_eval(u, GETVEC(d)); + POKE2(d + 0x2, -10); + POKE2(d + 0x4, -10); + uxn_eval(u, PEEK2(d)); } break; case CONTROL_KEYBOARD: { toggle_keyboard(); @@ -451,7 +487,7 @@ handle_input(Uxn *u) { } if (key_prev != key_curr) { - uxn_eval(u, GETVEC(d)); + uxn_eval(u, PEEK2(d)); } d[3] = 0; } else if (ctrl_methods[ctrl_idx] == CONTROL_MOUSE) { @@ -500,10 +536,10 @@ handle_input(Uxn *u) { } // Eval mouse. - POKDEV(0x2, mouse.x); - POKDEV(0x4, mouse.y); + POKE2(d + 0x2, mouse.x); + POKE2(d + 0x4, mouse.y); if (event) { - uxn_eval(u, GETVEC(d)); + uxn_eval(u, PEEK2(d)); } } else if (ctrl_methods[ctrl_idx] == CONTROL_KEYBOARD) { u8 *d = &u->dev[0x80]; @@ -549,7 +585,7 @@ handle_input(Uxn *u) { d[3] = symbol; } break; } - uxn_eval(u, GETVEC(d)); + uxn_eval(u, PEEK2(d)); d[3] = 0; } } @@ -588,7 +624,7 @@ main(void) { while(true) { bios_vblank_wait(); PROF(handle_input(&u), input_cycles); - PROF(uxn_eval(&u, GETVEC(&u.dev[0x20])), eval_cycles); + PROF(uxn_eval(&u, PEEK2(&u.dev[0x20])), eval_cycles); PROF(sound_mix(), mix_cycles); PROF_SHOW(); PROF(flipbuf(&ppu), flip_cycles); diff --git a/src/ppu.c b/src/ppu.c index c258fe2..afde963 100644 --- a/src/ppu.c +++ b/src/ppu.c @@ -247,6 +247,118 @@ ppu_pixel(u32 *layer, u16 x, u16 y, u8 clr) { dirty_tiles[tile_y] |= 1 << tile_x; } +IWRAM_CODE +void +ppu_rect(u32 *layer, size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) { + BOUNDCHECK_SCREEN(x0, y0); + BOUNDCHECK_SCREEN(x1, y1); + + // Find row positions for the given x/y coordinates. + size_t tile_x0 = x0 / 8; + size_t tile_y0 = y0 / 8; + size_t tile_x1 = x1 / 8; + size_t tile_y1 = y1 / 8; + size_t start_col0 = x0 % 8; + size_t start_col1 = x1 % 8; + size_t start_row0 = y0 % 8; + size_t start_row1 = y1 % 8; + + // Get a pointer to the backbuffer and the tile row. + u32 *buf_top = &layer[start_row0 + (tile_x0 + tile_y0 * 32) * 8]; + u32 *buf_bot = &layer[start_row1 + (tile_x0 + tile_y1 * 32) * 8]; + + size_t dx = tile_x1 - tile_x0; + size_t dy = tile_y1 - tile_y0; + + // We can update two lines at a time, which is faster than calling draw_line + // four times. + if (dx < 1) { + u32 row_mask = 0xFFFFFFFF; + row_mask >>= (7 - start_col1 - dx) * 4; + row_mask &= 0xFFFFFFFF << start_col0 * 4; + u32 row = (0x11111111 * clr) & row_mask; + buf_top[0] = (buf_top[0] & ~row_mask) | row; + buf_bot[0] = (buf_bot[0] & ~row_mask) | row; + dirty_tiles[tile_y0] |= 1 << tile_x0; + dirty_tiles[tile_y1] |= 1 << tile_x0; + } else { + size_t shift_left = start_col0 * 4; + size_t shift_right = (7 - start_col1) * 4; + u32 row_mask = 0xFFFFFFFF; + u32 row = 0x11111111 * clr; + buf_top[0] = buf_top[0] & ~(row_mask << shift_left); + buf_top[0] |= row << shift_left; + buf_bot[0] = buf_bot[0] & ~(row_mask << shift_left); + buf_bot[0] |= row << shift_left; + dirty_tiles[tile_y0] |= 1 << tile_x0; + dirty_tiles[tile_y1] |= 1 << tile_x0; + for (size_t i = 1; i < dx; i++) { + buf_top[i * 8] = row; + buf_bot[i * 8] = row; + dirty_tiles[tile_y0] |= 1 << (tile_x0 + i); + dirty_tiles[tile_y1] |= 1 << (tile_x0 + i); + } + buf_top[dx * 8] = buf_top[dx * 8] & ~(row_mask >> shift_right); + buf_top[dx * 8] |= row >> shift_right; + buf_bot[dx * 8] = buf_bot[dx * 8] & ~(row_mask >> shift_right); + buf_bot[dx * 8] |= row >> shift_right; + dirty_tiles[tile_y0] |= 1 << (tile_x0 + dx); + dirty_tiles[tile_y1] |= 1 << (tile_x0 + dx); + } + u32 row_mask_left = 0xF << start_col0 * 4; + u32 row_mask_right = 0xF << start_col1 * 4; + u32 row_left = (0x11111111 * clr) & row_mask_left; + u32 row_right = (0x11111111 * clr) & row_mask_right; + if (dy < 1) { + for (size_t i = 1; i < y1 - y0; i++, buf_top++) { + buf_top[1] = buf_top[1] & ~row_mask_left; + buf_top[1] |= row_left; + buf_top[1 + 8 * dx] = buf_top[1 + 8 * dx] & ~row_mask_right; + buf_top[1 + 8 * dx] |= row_right; + } + } else { + for (size_t i = 1; i < (8 - start_row0); i++, buf_top++) { + buf_top[1] = buf_top[1] & ~row_mask_left; + buf_top[1] |= row_left; + buf_top[1 + 8 * dx] = buf_top[1 + 8 * dx] & ~row_mask_right; + buf_top[1 + 8 * dx] |= row_right; + } + buf_top += 8 * 31; + for (size_t j = 1; j < dy; j++) { + for (size_t i = 0; i < 8; i++, buf_top++) { + buf_top[1] = buf_top[1] & ~row_mask_left; + buf_top[1] |= row_left; + buf_top[1 + 8 * dx] = buf_top[1 + 8 * dx] & ~row_mask_right; + buf_top[1 + 8 * dx] |= row_right; + } + buf_top += 8 * 31; + dirty_tiles[tile_y0 + j] |= 1 << tile_x0; + dirty_tiles[tile_y0 + j] |= 1 << (tile_x0 + dx); + } + for (size_t i = 0; i < start_row1; i++, buf_top++) { + buf_top[1] = buf_top[1] & ~row_mask_left; + buf_top[1] |= row_left; + buf_top[1 + 8 * dx] = buf_top[1 + 8 * dx] & ~row_mask_right; + buf_top[1 + 8 * dx] |= row_right; + } + } +} + +IWRAM_CODE +void +screen_fill(u32 *layer, u16 x0, u16 y0, u16 x1, u16 y1, u8 clr) { + BOUNDCHECK_SCREEN(x0, y0); + BOUNDCHECK_SCREEN(x1, y1); + + size_t dx = x1 - x0; + size_t dy = y1 - y0; + size_t n_rect = MIN(dx, dy); + n_rect = n_rect / 2 + 1; + for (size_t i = 0; i < n_rect; i++) { + ppu_rect(layer, x0 + i, y0 + i, x1 - i, y1 - i, clr); + } +} + #if NEW_PPU == 0 IWRAM_CODE void @@ -315,34 +427,28 @@ ppu_1bpp(u32 *layer, u16 x, u16 y, u8 *sprite, u8 clr, u8 flip_x, u8 flip_y) { u32 *dst = &layer[start_row + (tile_x + tile_y * 32) * 8]; u32 *lut = flip_x ? dec_byte_flip_x : dec_byte; if (blending[4][clr]) { - u64 mask = ~((u64)0xFFFFFFFF); + u32 mask = 0xFFFFFFFF; if (!flip_y) { for(size_t v = 0; v < 8; v++, dst++) { if ((y + v) >= SCREEN_HEIGHT) break; u8 ch1 = sprite[v]; u32 color_1 = lut[ch1]; - u32 color_2 = (color_1 ^ 0xffffffff) & 0x11111111; + u32 color_2 = (color_1 ^ 0xFFFFFFFF) & 0x11111111; u32 color = (color_1 * (clr & 3)) | (color_2 * (clr >> 2)); - if (start_col == 0) { - dst[0] = (dst[0] & mask) | color; - } else { - dst[0] = (dst[0] & (mask << shift_left)) | color; - dst[8] = (dst[8] & (mask >> shift_right)) | (color >> shift_right); - } + dst[0] = (dst[0] & ~(mask << shift_left)) | (color << shift_left); + dst[8] = (dst[8] & ~(mask >> shift_right)) | (color >> shift_right); + if ((start_row + v) == 7) dst += (32 - 1) * 8; } } else { for(size_t v = 0; v < 8; v++, dst++) { if ((y + v) >= SCREEN_HEIGHT) break; u8 ch1 = sprite[(7 - v)]; u32 color_1 = lut[ch1]; - u32 color_2 = (color_1 ^ 0xffffffff) & 0x11111111; + u32 color_2 = (color_1 ^ 0xFFFFFFFF) & 0x11111111; u32 color = (color_1 * (clr & 3)) | (color_2 * (clr >> 2)); - if (start_col == 0) { - dst[0] = (dst[0] & mask) | color; - } else { - dst[0] = (dst[0] & (mask << shift_left)) | color; - dst[8] = (dst[8] & (mask >> shift_right)) | (color >> shift_right); - } + dst[0] = (dst[0] & ~(mask << shift_left)) | (color << shift_left); + dst[8] = (dst[8] & ~(mask >> shift_right)) | (color >> shift_right); + if ((start_row + v) == 7) dst += (32 - 1) * 8; } } } else { @@ -359,6 +465,7 @@ ppu_1bpp(u32 *layer, u16 x, u16 y, u8 *sprite, u8 clr, u8 flip_x, u8 flip_y) { dst[0] = (dst[0] & ~(mask << shift_left)) | (color << shift_left); dst[8] = (dst[8] & ~(mask >> shift_right)) | (color >> shift_right); } + if ((start_row + v) == 7) dst += (32 - 1) * 8; } } else { for(size_t v = 0; v < 8; v++, dst++) { @@ -373,6 +480,7 @@ ppu_1bpp(u32 *layer, u16 x, u16 y, u8 *sprite, u8 clr, u8 flip_x, u8 flip_y) { dst[0] = (dst[0] & ~(mask << shift_left)) | (color << shift_left); dst[8] = (dst[8] & ~(mask >> shift_right)) | (color >> shift_right); } + if ((start_row + v) == 7) dst += (32 - 1) * 8; } } } @@ -529,6 +637,7 @@ ppu_2bpp(u32 *layer, u16 x, u16 y, u8 *sprite, u8 clr, u8 flip_x, u8 flip_y) { dst[0] = (dst[0] & (mask << shift_left)) | color; dst[8] = (dst[8] & (mask >> shift_right)) | (color >> shift_right); } + if ((start_row + v) == 7) dst += (32 - 1) * 8; } } else { for(size_t v = 0; v < 8; v++, dst++) { @@ -542,10 +651,11 @@ ppu_2bpp(u32 *layer, u16 x, u16 y, u8 *sprite, u8 clr, u8 flip_x, u8 flip_y) { dst[0] = (dst[0] & (mask << shift_left)) | color; dst[8] = (dst[8] & (mask >> shift_right)) | (color >> shift_right); } + if ((start_row + v) == 7) dst += (32 - 1) * 8; } } } else if (blending[4][clr]) { - u64 mask = ~((u64)0xFFFFFFFF << shift_left); + u32 mask = 0xFFFFFFFF; u8 clr0 = blending[0][clr]; u8 clr1 = blending[1][clr]; u8 clr2 = blending[2][clr]; @@ -567,12 +677,9 @@ ppu_2bpp(u32 *layer, u16 x, u16 y, u8 *sprite, u8 clr, u8 flip_x, u8 flip_y) { (clr1 * col1mask) | (clr2 * col2mask) | (clr3 * col3mask); - if (start_col == 0) { - dst[0] = (dst[0] & mask) | color; - } else { - dst[0] = (dst[0] & (mask << shift_left)) | color; - dst[8] = (dst[8] & (mask >> shift_right)) | (color >> shift_right); - } + dst[0] = (dst[0] & ~(mask << shift_left)) | (color << shift_left); + dst[8] = (dst[8] & ~(mask >> shift_right)) | (color >> shift_right); + if ((start_row + v) == 7) dst += (32 - 1) * 8; } } else { for(size_t v = 0; v < 8; v++, dst++) { @@ -591,12 +698,9 @@ ppu_2bpp(u32 *layer, u16 x, u16 y, u8 *sprite, u8 clr, u8 flip_x, u8 flip_y) { (clr1 * col1mask) | (clr2 * col2mask) | (clr3 * col3mask); - if (start_col == 0) { - dst[0] = (dst[0] & mask) | color; - } else { - dst[0] = (dst[0] & (mask << shift_left)) | color; - dst[8] = (dst[8] & (mask >> shift_right)) | (color >> shift_right); - } + dst[0] = (dst[0] & ~(mask << shift_left)) | (color << shift_left); + dst[8] = (dst[8] & ~(mask >> shift_right)) | (color >> shift_right); + if ((start_row + v) == 7) dst += (32 - 1) * 8; } } } else { @@ -625,6 +729,7 @@ ppu_2bpp(u32 *layer, u16 x, u16 y, u8 *sprite, u8 clr, u8 flip_x, u8 flip_y) { dst[0] = (dst[0] & (mask << shift_left)) | color; dst[8] = (dst[8] & (mask >> shift_right)) | (color >> shift_right); } + if ((start_row + v) == 7) dst += (32 - 1) * 8; } } else { for(size_t v = 0; v < 8; v++, dst++) { @@ -648,6 +753,7 @@ ppu_2bpp(u32 *layer, u16 x, u16 y, u8 *sprite, u8 clr, u8 flip_x, u8 flip_y) { dst[0] = (dst[0] & (mask << shift_left)) | color; dst[8] = (dst[8] & (mask >> shift_right)) | (color >> shift_right); } + if ((start_row + v) == 7) dst += (32 - 1) * 8; } } } diff --git a/src/uxn.c b/src/uxn.c index 5c39803..d525ff1 100644 --- a/src/uxn.c +++ b/src/uxn.c @@ -11,87 +11,93 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ -/* a,b,c: general use. bs: byte/short bool. src, dst: stack ptrs, swapped in return mode. - pc: program counter. sp: ptr to src stack ptr. kptr: "keep" mode copy of src stack ptr. - x,y: macro in params. d: macro in device. j: macro temp variables. o: macro out param. */ +#define T s->dat[s->ptr - 1] +#define N s->dat[s->ptr - 2] +#define L s->dat[s->ptr - 3] +#define H2 PEEK2(s->dat + s->ptr - 3) +#define T2 PEEK2(s->dat + s->ptr - 2) +#define N2 PEEK2(s->dat + s->ptr - 4) +#define L2 PEEK2(s->dat + s->ptr - 6) -#define HALT(c) { return uxn_halt(u, instr, (c), pc - 1); } -#define JUMP(x) { if(bs) pc = (x); else pc += (s8)(x); } -#define PUSH8(s, x) { if(s->ptr == 0xff) HALT(2) s->dat[s->ptr++] = (x); } -#define PUSH16(s, x) { if((j = s->ptr) >= 0xfe) HALT(2) k = (x); s->dat[j] = k >> 8; s->dat[j + 1] = k; s->ptr = j + 2; } -#define PUSH(s, x) { if(bs) { PUSH16(s, (x)) } else { PUSH8(s, (x)) } } -#define POP8(o) { if(!(j = *sp)) HALT(1) o = (u16)src->dat[--j]; *sp = j; } -#define POP16(o) { if((j = *sp) <= 1) HALT(1) o = (src->dat[j - 2] << 8) + src->dat[j - 1]; *sp = j - 2; } -#define POP(o) { if(bs) { POP16(o) } else { POP8(o) } } -#define POKE(x, y) { if(bs) { u->ram[(x)] = (y) >> 8; u->ram[(x) + 1] = (y); } else { u->ram[(x)] = y; } } -#define PEEK16(o, x) { o = (u->ram[(x)] << 8) + u->ram[(x) + 1]; } -#define PEEK(o, x) { if(bs) PEEK16(o, x) else o = u->ram[(x)]; } -#define DEVR(o, x) { o = u->dei(u, x); if (bs) o = (o << 8) + u->dei(u, (x) + 1); } -#define DEVW(x, y) { if (bs) { u->deo(u, (x), (y) >> 8); u->deo(u, (x) + 1, (y)); } else { u->deo(u, x, (y)); } } +/* Registers + +[ . ][ . ][ . ][ L ][ N ][ T ] < +[ . ][ . ][ . ][ H2 ][ T ] < +[ L2 ][ N2 ][ T2 ] < + +*/ + + +u16 deo_mask[] = {0xff08, 0x0300, 0xc028, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0x0000, 0x0000, 0xa260, 0xa260, 0x0000, 0x0000, 0x0000, 0x0000}; +u16 dei_mask[] = {0x0000, 0x0000, 0x003c, 0x0014, 0x0014, 0x0014, 0x0014, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07ff, 0x0000, 0x0000, 0x0000}; + +#define POKE2(d, v) { (d)[0] = (v) >> 8; (d)[1] = (v); } +#define PEEK2(d) ((d)[0] << 8 | (d)[1]) +#define HALT(c) { return uxn_halt(u, ins, (c), pc - 1); } +#define SET(mul, add) { if(mul > s->ptr) HALT(1) tmp = s->ptr + k * mul + add; if(tmp > 254) HALT(2) s->ptr = tmp; } +#define PUT(o, v) { s->dat[(u8)(s->ptr - 1 - (o))] = (v); } +#define PUT2(o, v) { tmp = (v); s->dat[(u8)(s->ptr - o - 2)] = tmp >> 8; s->dat[(u8)(s->ptr - o - 1)] = tmp; } +#define PUSH(stack, v) { if(s->ptr > 254) HALT(2) stack->dat[stack->ptr++] = (v); } +#define PUSH2(stack, v) { if(s->ptr > 253) HALT(2) tmp = (v); stack->dat[stack->ptr] = tmp >> 8; stack->dat[stack->ptr + 1] = tmp; stack->ptr += 2; } +#define DEO(a, b) { u->dev[(a)] = (b); if((deo_mask[(a) >> 4] >> ((a) & 0xf)) & 0x1) uxn_deo(u, (a)); } +#define DEI(a, b) { PUT((a), ((dei_mask[(b) >> 4] >> ((b) & 0xf)) & 0x1) ? uxn_dei(u, (b)) : u->dev[(b)]) } IWRAM_CODE int -uxn_eval(Uxn *u, u16 pc) -{ - u8 kptr, *sp; - u16 a, b, c, j, k, bs, instr, opcode; - Stack *src, *dst; - if(!pc || u->dev[0x0f]) return 0; - for(;;) { - instr = u->ram[pc++]; - /* Return Mode */ - if(instr & 0x40) { src = u->rst; dst = u->wst; } - else { src = u->wst; dst = u->rst; } - /* Keep Mode */ - if(instr & 0x80) { kptr = src->ptr; sp = &kptr; } - else sp = &src->ptr; - /* Short Mode */ - bs = instr & 0x20; - opcode = instr & 0x1f; - switch(opcode - (!opcode * (instr >> 5))) { - /* Literals/Calls */ - case -0x0: /* BRK */ return 1; - case -0x1: /* JCI */ POP8(b) if(!b) { pc += 2; break; } // fallthrough - case -0x2: /* JMI */ PEEK16(a, pc) pc += a + 2; break; - case -0x3: /* JSI */ PUSH16(u->rst, pc + 2) PEEK16(a, pc) pc += a + 2; break; - case -0x4: /* LIT */ - case -0x6: /* LITr */ a = u->ram[pc++]; PUSH8(src, a) break; - case -0x5: /* LIT2 */ - case -0x7: /* LIT2r */ PEEK16(a, pc) PUSH16(src, a) pc += 2; break; - /* ALU */ - case 0x01: /* INC */ POP(a) PUSH(src, a + 1) break; - case 0x02: /* POP */ POP(a) break; - case 0x03: /* NIP */ POP(a) POP(b) PUSH(src, a) break; - case 0x04: /* SWP */ POP(a) POP(b) PUSH(src, a) PUSH(src, b) break; - case 0x05: /* ROT */ POP(a) POP(b) POP(c) PUSH(src, b) PUSH(src, a) PUSH(src, c) break; - case 0x06: /* DUP */ POP(a) PUSH(src, a) PUSH(src, a) break; - case 0x07: /* OVR */ POP(a) POP(b) PUSH(src, b) PUSH(src, a) PUSH(src, b) break; - case 0x08: /* EQU */ POP(a) POP(b) PUSH8(src, b == a) break; - case 0x09: /* NEQ */ POP(a) POP(b) PUSH8(src, b != a) break; - case 0x0a: /* GTH */ POP(a) POP(b) PUSH8(src, b > a) break; - case 0x0b: /* LTH */ POP(a) POP(b) PUSH8(src, b < a) break; - case 0x0c: /* JMP */ POP(a) JUMP(a) break; - case 0x0d: /* JCN */ POP(a) POP8(b) if(b) JUMP(a) break; - case 0x0e: /* JSR */ POP(a) PUSH16(dst, pc) JUMP(a) break; - case 0x0f: /* STH */ POP(a) PUSH(dst, a) break; - case 0x10: /* LDZ */ POP8(a) PEEK(b, a) PUSH(src, b) break; - case 0x11: /* STZ */ POP8(a) POP(b) POKE(a, b) break; - case 0x12: /* LDR */ POP8(a) b = pc + (s8)a; PEEK(c, b) PUSH(src, c) break; - case 0x13: /* STR */ POP8(a) POP(b) c = pc + (s8)a; POKE(c, b) break; - case 0x14: /* LDA */ POP16(a) PEEK(b, a) PUSH(src, b) break; - case 0x15: /* STA */ POP16(a) POP(b) POKE(a, b) break; - case 0x16: /* DEI */ POP8(a) DEVR(b, a) PUSH(src, b) break; - case 0x17: /* DEO */ POP8(a) POP(b) DEVW(a, b) break; - case 0x18: /* ADD */ POP(a) POP(b) PUSH(src, b + a) break; - case 0x19: /* SUB */ POP(a) POP(b) PUSH(src, b - a) break; - case 0x1a: /* MUL */ POP(a) POP(b) PUSH(src, (u32)b * a) break; - case 0x1b: /* DIV */ POP(a) POP(b) if(!a) HALT(3) PUSH(src, b / a) break; - case 0x1c: /* AND */ POP(a) POP(b) PUSH(src, b & a) break; - case 0x1d: /* ORA */ POP(a) POP(b) PUSH(src, b | a) break; - case 0x1e: /* EOR */ POP(a) POP(b) PUSH(src, b ^ a) break; - case 0x1f: /* SFT */ POP8(a) POP(b) PUSH(src, b >> (a & 0x0f) << ((a & 0xf0) >> 4)) break; - } - } +uxn_eval(Uxn *u, u16 pc) { + u8 ins, opc, k; + u16 t, n, l, tmp; + Stack *s; + if(!pc || u->dev[0x0f]) return 0; + for(;;) { + ins = u->ram[pc++]; + k = !!(ins & 0x80); + s = ins & 0x40 ? u->rst : u->wst; + opc = !(ins & 0x1f) ? 0 - (ins >> 5) : ins & 0x3f; + switch(opc) { + /* IMM */ + case 0x00: /* BRK */ return 1; + case 0xff: /* JCI */ pc += !!s->dat[--s->ptr] * PEEK2(u->ram + pc) + 2; break; + case 0xfe: /* JMI */ pc += PEEK2(u->ram + pc) + 2; break; + case 0xfd: /* JSI */ PUSH2(u->rst, pc + 2) pc += PEEK2(u->ram + pc) + 2; break; + case 0xfc: /* LIT */ PUSH(s, u->ram[pc++]) break; + case 0xfb: /* LIT2 */ PUSH2(s, PEEK2(u->ram + pc)) pc += 2; break; + case 0xfa: /* LITr */ PUSH(s, u->ram[pc++]) break; + case 0xf9: /* LIT2r */ PUSH2(s, PEEK2(u->ram + pc)) pc += 2; break; + /* ALU */ + case 0x01: /* INC */ t=T; SET(1, 0) PUT(0, t + 1) break; case 0x21: t=T2; SET(2, 0) PUT2(0, t + 1) break; + case 0x02: /* POP */ SET(1,-1) break; case 0x22: SET(2,-2) break; + case 0x03: /* NIP */ t=T; SET(2,-1) PUT(0, t) break; case 0x23: t=T2; SET(4,-2) PUT2(0, t) break; + case 0x04: /* SWP */ t=T;n=N; SET(2, 0) PUT(0, n) PUT(1, t) break; case 0x24: t=T2;n=N2; SET(4, 0) PUT2(0, n) PUT2(2, t) break; + case 0x05: /* ROT */ t=T;n=N;l=L; SET(3, 0) PUT(0, l) PUT(1, t) PUT(2, n) break; case 0x25: t=T2;n=N2;l=L2; SET(6, 0) PUT2(0, l) PUT2(2, t) PUT2(4, n) break; + case 0x06: /* DUP */ t=T; SET(1, 1) PUT(0, t) PUT(1, t) break; case 0x26: t=T2; SET(2, 2) PUT2(0, t) PUT2(2, t) break; + case 0x07: /* OVR */ t=T;n=N; SET(2, 1) PUT(0, n) PUT(1, t) PUT(2, n) break; case 0x27: t=T2;n=N2; SET(4, 2) PUT2(0, n) PUT2(2, t) PUT2(4, n) break; + case 0x08: /* EQU */ t=T;n=N; SET(2,-1) PUT(0, n == t) break; case 0x28: t=T2;n=N2; SET(4,-3) PUT(0, n == t) break; + case 0x09: /* NEQ */ t=T;n=N; SET(2,-1) PUT(0, n != t) break; case 0x29: t=T2;n=N2; SET(4,-3) PUT(0, n != t) break; + case 0x0a: /* GTH */ t=T;n=N; SET(2,-1) PUT(0, n > t) break; case 0x2a: t=T2;n=N2; SET(4,-3) PUT(0, n > t) break; + case 0x0b: /* LTH */ t=T;n=N; SET(2,-1) PUT(0, n < t) break; case 0x2b: t=T2;n=N2; SET(4,-3) PUT(0, n < t) break; + case 0x0c: /* JMP */ t=T; SET(1,-1) pc += (s8)t; break; case 0x2c: t=T2; SET(2,-2) pc = t; break; + case 0x0d: /* JCN */ t=T;n=N; SET(2,-2) pc += !!n * (s8)t; break; case 0x2d: t=T2;n=L; SET(3,-3) if(n) pc = t; break; + case 0x0e: /* JSR */ t=T; SET(1,-1) PUSH2(u->rst, pc) pc += (s8)t; break; case 0x2e: t=T2; SET(2,-2) PUSH2(u->rst, pc) pc = t; break; + case 0x0f: /* STH */ t=T; SET(1,-1) PUSH((ins & 0x40 ? u->wst : u->rst), t) break; case 0x2f: t=T2; SET(2,-2) PUSH2((ins & 0x40 ? u->wst : u->rst), t) break; + case 0x10: /* LDZ */ t=T; SET(1, 0) PUT(0, u->ram[t]) break; case 0x30: t=T; SET(1, 1) PUT2(0, PEEK2(u->ram + t)) break; + case 0x11: /* STZ */ t=T;n=N; SET(2,-2) u->ram[t] = n; break; case 0x31: t=T;n=H2; SET(3,-3) POKE2(u->ram + t, n) break; + case 0x12: /* LDR */ t=T; SET(1, 0) PUT(0, u->ram[pc + (s8)t]) break; case 0x32: t=T; SET(1, 1) PUT2(0, PEEK2(u->ram + pc + (s8)t)) break; + case 0x13: /* STR */ t=T;n=N; SET(2,-2) u->ram[pc + (s8)t] = n; break; case 0x33: t=T;n=H2; SET(3,-3) POKE2(u->ram + pc + (s8)t, n) break; + case 0x14: /* LDA */ t=T2; SET(2,-1) PUT(0, u->ram[t]) break; case 0x34: t=T2; SET(2, 0) PUT2(0, PEEK2(u->ram + t)) break; + case 0x15: /* STA */ t=T2;n=L; SET(3,-3) u->ram[t] = n; break; case 0x35: t=T2;n=N2; SET(4,-4) POKE2(u->ram + t, n) break; + case 0x16: /* DEI */ t=T; SET(1, 0) DEI(0, t) break; case 0x36: t=T; SET(1, 1) DEI(1, t) DEI(0, t + 1) break; + case 0x17: /* DEO */ t=T;n=N; SET(2,-2) DEO(t, n) break; case 0x37: t=T;n=N;l=L; SET(3,-3) DEO(t, l) DEO(t + 1, n) break; + case 0x18: /* ADD */ t=T;n=N; SET(2,-1) PUT(0, n + t) break; case 0x38: t=T2;n=N2; SET(4,-2) PUT2(0, n + t) break; + case 0x19: /* SUB */ t=T;n=N; SET(2,-1) PUT(0, n - t) break; case 0x39: t=T2;n=N2; SET(4,-2) PUT2(0, n - t) break; + case 0x1a: /* MUL */ t=T;n=N; SET(2,-1) PUT(0, n * t) break; case 0x3a: t=T2;n=N2; SET(4,-2) PUT2(0, n * t) break; + case 0x1b: /* DIV */ t=T;n=N; SET(2,-1) PUT(0, n / t) break; case 0x3b: t=T2;n=N2; SET(4,-2) PUT2(0, n / t) break; + case 0x1c: /* AND */ t=T;n=N; SET(2,-1) PUT(0, n & t) break; case 0x3c: t=T2;n=N2; SET(4,-2) PUT2(0, n & t) break; + case 0x1d: /* ORA */ t=T;n=N; SET(2,-1) PUT(0, n | t) break; case 0x3d: t=T2;n=N2; SET(4,-2) PUT2(0, n | t) break; + case 0x1e: /* EOR */ t=T;n=N; SET(2,-1) PUT(0, n ^ t) break; case 0x3e: t=T2;n=N2; SET(4,-2) PUT2(0, n ^ t) break; + case 0x1f: /* SFT */ t=T;n=N; SET(2,-1) PUT(0, n >> (t & 0xf) << (t >> 4)) break; case 0x3f: t=T;n=H2; SET(3,-1) PUT2(0, n >> (t & 0xf) << (t >> 4)) break; + } + } } int diff --git a/src/uxn.h b/src/uxn.h index f9bee16..04aba84 100644 --- a/src/uxn.h +++ b/src/uxn.h @@ -13,12 +13,6 @@ WITH REGARD TO THIS SOFTWARE. #define PAGE_PROGRAM 0x0100 -/* clang-format off */ - -#define GETVEC(d) ((d)[0] << 8 | (d)[1]) -#define POKDEV(x, y) { d[(x)] = (y) >> 8; d[(x) + 1] = (y); } -#define PEKDEV(o, x) { (o) = (d[(x)] << 8) + d[(x) + 1]; } - /* clang-format on */ typedef struct { @@ -35,6 +29,8 @@ typedef struct Uxn { typedef u8 Dei(Uxn *u, u8 addr); typedef void Deo(Uxn *u, u8 addr, u8 value); +u8 uxn_dei(Uxn *u, u8 addr); +void uxn_deo(Uxn *u, u8 addr); int uxn_halt(Uxn *u, u8 instr, u8 err, u16 addr); int uxn_boot(Uxn *u, u8 *ram, Dei *dei, Deo *deo); int uxn_eval(Uxn *u, u16 pc); -- cgit v1.2.1