From 6c18f897c639c7e250fa77a7861362c7a2944505 Mon Sep 17 00:00:00 2001 From: mooinglemur Date: Mon, 3 Jul 2023 19:17:02 +0000 Subject: [PATCH 01/13] Port experimental FX feature from x16emu (#99) * port FX feature from x16emu * fix windows builds * clean up whitespace * whitespace nits * missed the ADDRx_H read --- src/vera/vera_video.cpp | 578 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 561 insertions(+), 17 deletions(-) diff --git a/src/vera/vera_video.cpp b/src/vera/vera_video.cpp index d10ad2a..f8aee85 100644 --- a/src/vera/vera_video.cpp +++ b/src/vera/vera_video.cpp @@ -53,6 +53,11 @@ // When rendering a layer line, we can amortize some of the cost by calculating multiple pixels at a time. #define LAYER_PIXELS_PER_ITERATION 8 +// Version +#define VERA_VERSION_MAJOR 0x00 +#define VERA_VERSION_MINOR 0x03 +#define VERA_VERSION_PATCH 0x01 + static bool is_fullscreen = false; static uint8_t video_ram[0x20000]; @@ -72,7 +77,9 @@ static uint8_t isr; static uint16_t irq_line; static uint8_t reg_layer[2][7]; -static uint8_t reg_composer[8]; + +#define COMPOSER_SLOTS 4*64 +static uint8_t reg_composer[COMPOSER_SLOTS]; static uint8_t layer_line[2][SCREEN_WIDTH]; static uint8_t sprite_line_col[SCREEN_WIDTH]; @@ -93,6 +100,63 @@ static int cheat_mask = 0; static bool log_video = false; static bool shadow_safety_frame[4] = { false, false, true, true }; +//////////////////////////////////////////////////////////// +// FX registers +//////////////////////////////////////////////////////////// +static uint8_t fx_addr1_mode; + +// These are all 16.16 fixed point in the emulator +// even though the VERA uses smaller bit widths +// for the whole and fractional parts. +// +// Sign extension is done manually when assigning negative numbers +// +// Native VERA bit widths are shown below. +static uint32_t fx_x_pixel_increment; // 11.9 fixed point (6.9 without 32x multiplier, 11.4 with 32x multiplier on) +static uint32_t fx_y_pixel_increment; // 11.9 fixed point (6.9 without 32x multiplier, 11.4 with 32x multiplier on) +static uint32_t fx_x_pixel_position; // 11.9 fixed point +static uint32_t fx_y_pixel_position; // 11.9 fixed point + +static uint16_t fx_poly_fill_length; // 10 bits + +static uint32_t fx_affine_tile_base; +static uint32_t fx_affine_map_base; + +static uint8_t fx_affine_map_size; + +static bool fx_4bit_mode; +static bool fx_16bit_hop; +static bool fx_cache_byte_cycling; +static bool fx_cache_fill; +static bool fx_cache_write; +static bool fx_trans_writes; + +static bool fx_2bit_poly; +static bool fx_2bit_poking; + +static bool fx_cache_increment_mode; +static bool fx_cache_nibble_index; +static uint8_t fx_cache_byte_index; +static bool fx_multiplier; +static bool fx_subtract; + +static bool fx_affine_clip; + +static uint8_t fx_16bit_hop_align; + +static bool fx_nibble_bit[2]; +static bool fx_nibble_incr[2]; + +static uint8_t fx_cache[4]; + +static int32_t fx_mult_accumulator; + +static const uint8_t vera_version_string[] = {'V', + VERA_VERSION_MAJOR, + VERA_VERSION_MINOR, + VERA_VERSION_PATCH +}; + static uint8_t framebuffer[SCREEN_WIDTH * SCREEN_HEIGHT * 4]; static const uint16_t default_palette[] = { @@ -125,6 +189,49 @@ void vera_video_reset() reg_composer[5] = 640 >> 2; reg_composer[7] = 480 >> 1; + // Initialize FX registers + fx_addr1_mode = 0; + fx_x_pixel_position = 0x8000; + fx_y_pixel_position = 0x8000; + fx_x_pixel_increment = 0; + fx_y_pixel_increment = 0; + + fx_cache_write = false; + fx_cache_fill = false; + fx_4bit_mode = false; + fx_16bit_hop = false; + fx_subtract = false; + fx_cache_byte_cycling = false; + fx_trans_writes = false; + fx_multiplier = false; + + fx_mult_accumulator = 0; + + fx_2bit_poly = false; + fx_2bit_poking = false; + + fx_cache_nibble_index = 0; + fx_cache_byte_index = 0; + fx_cache_increment_mode = 0; + + fx_cache[0] = 0; + fx_cache[1] = 0; + fx_cache[2] = 0; + fx_cache[3] = 0; + + fx_16bit_hop_align = 0; + + fx_nibble_bit[0] = false; + fx_nibble_bit[1] = false; + fx_nibble_incr[0] = false; + fx_nibble_incr[1] = false; + + fx_poly_fill_length = 0; + fx_affine_tile_base = 0; + fx_affine_map_base = 0; + fx_affine_map_size = 2; + fx_affine_clip = false; + // init sprite data memset(sprite_data, 0, sizeof(sprite_data)); @@ -1003,10 +1110,71 @@ static const int increments[32] = { -640, }; -static uint32_t get_and_inc_address(uint8_t sel) +static uint32_t get_and_inc_address(uint8_t sel, bool write) { uint32_t address = io_addr[sel]; - io_addr[sel] += increments[io_inc[sel]]; + int16_t incr = increments[io_inc[sel]]; + + if (fx_4bit_mode && fx_nibble_incr[sel] && !incr) { + if (fx_nibble_bit[sel]) { + if ((io_inc[sel] & 1) == 0) io_addr[sel] += 1; + fx_nibble_bit[sel] = 0; + } else { + if (io_inc[sel] & 1) io_addr[sel] -= 1; + fx_nibble_bit[sel] = 1; + } + } + + if (sel == 1 && fx_16bit_hop) { + if (incr == 4) { + if (fx_16bit_hop_align == (address & 0x3)) + incr = 1; + else + incr = 3; + } else if (incr == 320) { + if (fx_16bit_hop_align == (address & 0x3)) + incr = 1; + else + incr = 319; + } + } + + io_addr[sel] += incr; + + if (sel == 1 && fx_addr1_mode == 1) { // FX line draw mode + fx_x_pixel_position += fx_x_pixel_increment; + if (fx_x_pixel_position & 0x10000) { + fx_x_pixel_position &= ~0x10000; + if (fx_4bit_mode && fx_nibble_incr[0]) { + if (fx_nibble_bit[1]) { + if ((io_inc[0] & 1) == 0) io_addr[1] += 1; + fx_nibble_bit[1] = 0; + } else { + if (io_inc[0] & 1) io_addr[1] -= 1; + fx_nibble_bit[1] = 1; + } + } + io_addr[1] += increments[io_inc[0]]; + } + } else if (fx_addr1_mode == 2 && write == false) { // FX polygon fill mode + fx_x_pixel_position += fx_x_pixel_increment; + fx_y_pixel_position += fx_y_pixel_increment; + fx_poly_fill_length = ((int32_t) fx_y_pixel_position >> 16) - ((int32_t) fx_x_pixel_position >> 16); + if (sel == 0 && fx_cache_byte_cycling && !fx_cache_fill) { + fx_cache_byte_index = (fx_cache_byte_index + 1) & 3; + } + if (sel == 1) { + if (fx_4bit_mode) { + io_addr[1] = io_addr[0] + (fx_x_pixel_position >> 17); + fx_nibble_bit[1] = (fx_x_pixel_position >> 16) & 1; + } else { + io_addr[1] = io_addr[0] + (fx_x_pixel_position >> 16); + } + } + } else if (sel == 1 && fx_addr1_mode == 3 && write == false) { // FX affine mode + fx_x_pixel_position += fx_x_pixel_increment; + fx_y_pixel_position += fx_y_pixel_increment; + } return address; } @@ -1019,6 +1187,59 @@ uint8_t vera_video_space_read(uint32_t address) return video_ram[address & 0x1FFFF]; } +void fx_affine_prefetch(void) +{ + if (fx_addr1_mode != 3) return; // only if affine mode is selected + + uint32_t address; + uint8_t affine_x_tile = (fx_x_pixel_position >> 19) & 0xff; + uint8_t affine_y_tile = (fx_y_pixel_position >> 19) & 0xff; + uint8_t affine_x_sub_tile = (fx_x_pixel_position >> 16) & 0x07; + uint8_t affine_y_sub_tile = (fx_y_pixel_position >> 16) & 0x07; + + if (!fx_affine_clip) { // wrap + affine_x_tile &= fx_affine_map_size - 1; + affine_y_tile &= fx_affine_map_size - 1; + } + + if (affine_x_tile >= fx_affine_map_size || affine_y_tile >= fx_affine_map_size) { + // We clipped, return value for tile 0 + address = fx_affine_tile_base + (affine_y_sub_tile << (3 - fx_4bit_mode)) + (affine_x_sub_tile >> (uint8_t)fx_4bit_mode); + if (fx_4bit_mode) fx_nibble_bit[1] = 0; + } else { + // Get the address within the tile map + address = fx_affine_map_base + (affine_y_tile * fx_affine_map_size) + affine_x_tile; + // Now translate that to the tile base address + uint8_t affine_tile_idx = vera_video_space_read(address); + address = fx_affine_tile_base + (affine_tile_idx << (6 - fx_4bit_mode)); + // Now add the sub-tile address + address += (affine_y_sub_tile << (3 - fx_4bit_mode)) + (affine_x_sub_tile >> (uint8_t)fx_4bit_mode); + if (fx_4bit_mode) fx_nibble_bit[1] = affine_x_sub_tile & 1; + } + io_addr[1] = address; + io_rddata[1] = vera_video_space_read(address); +} + +void fx_vram_cache_write(uint32_t address, uint8_t value, uint8_t mask) +{ + if (!fx_trans_writes || value > 0) { + switch (mask) { + case 0: + video_ram[address & 0x1FFFF] = value; + break; + case 1: + video_ram[address & 0x1FFFF] = (video_ram[address & 0x1FFFF] & 0x0f) | (value & 0xf0); + break; + case 2: + video_ram[address & 0x1FFFF] = (video_ram[address & 0x1FFFF] & 0xf0) | (value & 0x0f); + break; + case 3: + // Do nothing + break; + } + } +} + void vera_video_space_read_range(uint8_t *dest, uint32_t address, uint32_t size) { address &= 0x1FFFF; @@ -1032,6 +1253,33 @@ void vera_video_space_read_range(uint8_t *dest, uint32_t address, uint32_t size) } } +void fx_vera_video_space_write(uint32_t address, bool nibble, uint8_t value) +{ + if (fx_4bit_mode) { + if (nibble) { + if (!fx_trans_writes || (value & 0x0f) > 0) { + video_ram[address & 0x1FFFF] = (video_ram[address & 0x1FFFF] & 0xf0) | (value & 0x0f); + } + } else { + if (!fx_trans_writes || (value & 0xf0) > 0) { + video_ram[address & 0x1FFFF] = (video_ram[address & 0x1FFFF] & 0x0f) | (value & 0xf0); + } + } + } else { + if (!fx_trans_writes || value > 0) video_ram[address & 0x1FFFF] = value; + } + + if (address >= ADDR_PSG_START && address < ADDR_PSG_END) { + psg_writereg(address & 0x3f, value); + } else if (address >= ADDR_PALETTE_START && address < ADDR_PALETTE_END) { + palette[address & 0x1ff] = value; + video_palette.dirty = true; + } else if (address >= ADDR_SPRDATA_START && address < ADDR_SPRDATA_END) { + sprite_data[(address >> 3) & 0x7f][address & 0x7] = value; + refresh_sprite_properties((address >> 3) & 0x7f); + } +} + void vera_video_space_write(uint32_t address, uint8_t value) { video_ram[address & 0x1FFFF] = value; @@ -1060,7 +1308,7 @@ uint8_t vera_debug_video_read(uint8_t reg) switch (reg & 0x1F) { case 0x00: return io_addr[io_addrsel] & 0xff; case 0x01: return (io_addr[io_addrsel] >> 8) & 0xff; - case 0x02: return (io_addr[io_addrsel] >> 16) | (io_inc[io_addrsel] << 3); + case 0x02: return (io_addr[io_addrsel] >> 16) | (fx_nibble_bit[io_addrsel] << 1) | (fx_nibble_incr[io_addrsel] << 2) | (io_inc[io_addrsel] << 3); case 0x03: case 0x04: return io_rddata[reg - 3]; @@ -1073,8 +1321,58 @@ uint8_t vera_debug_video_read(uint8_t reg) case 0x09: case 0x0A: case 0x0B: - case 0x0C: return reg_composer[reg - 0x09 + (io_dcsel ? 4 : 0)]; - + case 0x0C: { + int i = reg - 0x09 + (io_dcsel << 2); + switch (i) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + // DCSEL = [0,1] with any composer register, or [2] at $9f29 + return reg_composer[i]; + break; + case 0x16: // DCSEL=5, 0x9F2B + if (fx_poly_fill_length >= 768) { + return ((fx_2bit_poly && fx_addr1_mode == 2) ? 0x00 : 0x80); + } + if (fx_4bit_mode) { + if (fx_2bit_poly && fx_addr1_mode == 2) { + return ((fx_y_pixel_position & 0x00008000) >> 8) | + ((fx_x_pixel_position >> 11) & 0x60) | + ((fx_x_pixel_position >> 14) & 0x10) | + ((fx_poly_fill_length & 0x0007) << 1) | + ((fx_x_pixel_position & 0x00008000) >> 15); + } else { + return ((!!(fx_poly_fill_length & 0xfff8)) << 7) | + ((fx_x_pixel_position >> 11) & 0x60) | + ((fx_x_pixel_position >> 14) & 0x10) | + ((fx_poly_fill_length & 0x0007) << 1); + } + } else { + return ((!!(fx_poly_fill_length & 0xfff0)) << 7) | + ((fx_x_pixel_position >> 11) & 0x60) | + ((fx_poly_fill_length & 0x000f) << 1); + } + break; + case 0x17: // DCSEL=5, 0x9F2C + return ((fx_poly_fill_length & 0x03f8) >> 2); + break; + case 0x18: // DCSEL=6, 0x9F29, would affect multiplier + case 0x19: // DCSEL=6, 0x9F2A, would affect multiplier + default: + // The rest of the space is write-only, + // so reading the values out instead returns the version string. + // fall out of the switch + break; + } + return vera_version_string[i % 4]; + break; + } case 0x0D: case 0x0E: case 0x0F: @@ -1109,14 +1407,38 @@ uint8_t vera_video_read(uint8_t reg) switch (reg & 0x1F) { case 0x00: return io_addr[io_addrsel] & 0xff; case 0x01: return (io_addr[io_addrsel] >> 8) & 0xff; - case 0x02: return (io_addr[io_addrsel] >> 16) | (io_inc[io_addrsel] << 3); + case 0x02: return (io_addr[io_addrsel] >> 16) | (fx_nibble_bit[io_addrsel] << 1) | (fx_nibble_incr[io_addrsel] << 2) | (io_inc[io_addrsel] << 3); case 0x03: case 0x04: { - uint32_t address = get_and_inc_address(reg - 3); + uint32_t address = get_and_inc_address(reg - 3, false); uint8_t value = io_rddata[reg - 3]; - io_rddata[reg - 3] = vera_video_space_read(io_addr[reg - 3]); + + if (reg == 4 && fx_addr1_mode == 3) + fx_affine_prefetch(); + else + io_rddata[reg - 3] = vera_video_space_read(io_addr[reg - 3]); + + if (fx_cache_fill) { + if (fx_4bit_mode) { + if (fx_cache_nibble_index) { + fx_cache[fx_cache_byte_index] = (fx_cache[fx_cache_byte_index] & 0xf0) | (value & 0x0f); + fx_cache_nibble_index = 0; + fx_cache_byte_index = ((fx_cache_byte_index + 1) & 0x3); + } else { + fx_cache[fx_cache_byte_index] = (fx_cache[fx_cache_byte_index] & 0x0f) | (value & 0xf0); + fx_cache_nibble_index = 1; + } + } else { + fx_cache[fx_cache_byte_index] = value; + if (fx_cache_increment_mode) + fx_cache_byte_index = (fx_cache_byte_index & 0x2) | ((fx_cache_byte_index + 1) & 0x1); + else + fx_cache_byte_index = ((fx_cache_byte_index + 1) & 0x3); + } + } + if (log_video) { printf("READ video_space[$%X] = $%02X\n", address, value); @@ -1131,8 +1453,71 @@ uint8_t vera_video_read(uint8_t reg) case 0x09: case 0x0A: case 0x0B: - case 0x0C: return reg_composer[reg - 0x09 + (io_dcsel ? 4 : 0)]; - + case 0x0C: { + int i = reg - 0x09 + (io_dcsel << 2); + switch (i) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + // DCSEL = [0,1] with any composer register, or [2] at $9f29 + return reg_composer[i]; + break; + case 0x16: // DCSEL=5, 0x9F2B + if (fx_poly_fill_length >= 768) { + return ((fx_2bit_poly && fx_addr1_mode == 2) ? 0x00 : 0x80); + } + if (fx_4bit_mode) { + if (fx_2bit_poly && fx_addr1_mode == 2) { + return ((fx_y_pixel_position & 0x00008000) >> 8) | + ((fx_x_pixel_position >> 11) & 0x60) | + ((fx_x_pixel_position >> 14) & 0x10) | + ((fx_poly_fill_length & 0x0007) << 1) | + ((fx_x_pixel_position & 0x00008000) >> 15); + } else { + return ((!!(fx_poly_fill_length & 0xfff8)) << 7) | + ((fx_x_pixel_position >> 11) & 0x60) | + ((fx_x_pixel_position >> 14) & 0x10) | + ((fx_poly_fill_length & 0x0007) << 1); + } + } else { + return ((!!(fx_poly_fill_length & 0xfff0)) << 7) | + ((fx_x_pixel_position >> 11) & 0x60) | + ((fx_poly_fill_length & 0x000f) << 1); + } + break; + case 0x17: // DCSEL=5, 0x9F2C + return ((fx_poly_fill_length & 0x03f8) >> 2); + break; + case 0x18: // DCSEL=6, 0x9F29 + fx_mult_accumulator = 0; + // fall out of the switch + break; + case 0x19: { + // DCSEL=6, 0x9F2A + ; // <- avoids the error in some compilers about a declaration after a label + int32_t m_result = (int16_t)((fx_cache[1] << 8) | fx_cache[0]) * (int16_t)((fx_cache[3] << 8) | fx_cache[2]); + if (fx_subtract) + fx_mult_accumulator -= m_result; + else + fx_mult_accumulator += m_result; + // fall out of the switch + break; + } + default: + // The rest of the space is write-only, + // so reading the values out instead returns the version string. + // fall out of the switch + break; + } + return vera_version_string[i % 4]; + break; + } case 0x0D: case 0x0E: case 0x0F: @@ -1167,7 +1552,14 @@ void vera_video_write(uint8_t reg, uint8_t value) // printf("ioregisters[%d] = $%02X\n", reg, value); switch (reg & 0x1F) { case 0x00: - io_addr[io_addrsel] = (io_addr[io_addrsel] & 0x1ff00) | value; + if (fx_2bit_poly && fx_4bit_mode && fx_addr1_mode == 2 && io_addrsel == 1) { + fx_2bit_poking = true; + io_addr[1] = (io_addr[1] & 0x1fffc) | (value & 0x3); + } else { + io_addr[io_addrsel] = (io_addr[io_addrsel] & 0x1ff00) | value; + if (fx_16bit_hop && io_addrsel == 1) + fx_16bit_hop_align = value & 3; + } io_rddata[io_addrsel] = vera_video_space_read(io_addr[io_addrsel]); break; case 0x01: @@ -1176,16 +1568,74 @@ void vera_video_write(uint8_t reg, uint8_t value) break; case 0x02: io_addr[io_addrsel] = (io_addr[io_addrsel] & 0x0ffff) | ((value & 0x1) << 16); + fx_nibble_bit[io_addrsel] = (value >> 1) & 0x1; + fx_nibble_incr[io_addrsel] = (value >> 2) & 0x1; io_inc[io_addrsel] = value >> 3; io_rddata[io_addrsel] = vera_video_space_read(io_addr[io_addrsel]); break; case 0x03: case 0x04: { - uint32_t address = get_and_inc_address(reg - 3); + if (fx_2bit_poking && fx_addr1_mode) { + fx_2bit_poking = false; + uint8_t mask = value >> 6; + switch (mask) { + case 0x00: + video_ram[io_addr[1] & 0x1FFFF] = (fx_cache[fx_cache_byte_index] & 0xc0) | (io_rddata[1] & 0x3f); + break; + case 0x01: + video_ram[io_addr[1] & 0x1FFFF] = (fx_cache[fx_cache_byte_index] & 0x30) | (io_rddata[1] & 0xcf); + break; + case 0x02: + video_ram[io_addr[1] & 0x1FFFF] = (fx_cache[fx_cache_byte_index] & 0x0c) | (io_rddata[1] & 0xf3); + break; + case 0x03: + video_ram[io_addr[1] & 0x1FFFF] = (fx_cache[fx_cache_byte_index] & 0x03) | (io_rddata[1] & 0xfc); + break; + } + break; // break out of the enclosing switch statement early, too + } + bool nibble = fx_nibble_bit[reg - 3]; + uint32_t address = get_and_inc_address(reg - 3, true); if (log_video) { printf("WRITE video_space[$%X] = $%02X\n", address, value); } - vera_video_space_write(address, value); + + if (fx_cache_write) { + address &= 0x1fffc; + if (fx_cache_byte_cycling) { + fx_vram_cache_write(address+0, fx_cache[fx_cache_byte_index], value & 0x03); + fx_vram_cache_write(address+1, fx_cache[fx_cache_byte_index], (value >> 2) & 0x03); + fx_vram_cache_write(address+2, fx_cache[fx_cache_byte_index], (value >> 4) & 0x03); + fx_vram_cache_write(address+3, fx_cache[fx_cache_byte_index], value >> 6); + } else { + if (fx_multiplier) { + int32_t m_result = (int16_t)((fx_cache[1] << 8) | fx_cache[0]) * (int16_t)((fx_cache[3] << 8) | fx_cache[2]); + if (fx_subtract) + m_result = fx_mult_accumulator - m_result; + else + m_result = fx_mult_accumulator + m_result; + fx_vram_cache_write(address+0, (m_result) & 0xff, value & 0x03); + fx_vram_cache_write(address+1, (m_result >> 8) & 0xff, (value >> 2) & 0x03); + fx_vram_cache_write(address+2, (m_result >> 16) & 0xff, (value >> 4) & 0x03); + fx_vram_cache_write(address+3, (m_result >> 24) & 0xff, value >> 6); + } else { + fx_vram_cache_write(address+0, fx_cache[0], value & 0x03); + fx_vram_cache_write(address+1, fx_cache[1], (value >> 2) & 0x03); + fx_vram_cache_write(address+2, fx_cache[2], (value >> 4) & 0x03); + fx_vram_cache_write(address+3, fx_cache[3], value >> 6); + } + } + } else { + if (fx_cache_byte_cycling) { + if (fx_4bit_mode) { + fx_vram_cache_write(address, fx_cache[fx_cache_byte_index], nibble+1); + } else { + fx_vram_cache_write(address, fx_cache[fx_cache_byte_index], 0); + } + } else { + fx_vera_video_space_write(address, nibble, value); // Normal write + } + } io_rddata[reg - 3] = vera_video_space_read(io_addr[reg - 3]); break; @@ -1194,7 +1644,7 @@ void vera_video_write(uint8_t reg, uint8_t value) if (value & 0x80) { vera_video_reset(); } - io_dcsel = (value >> 1) & 1; + io_dcsel = (value >> 1) & 0x3f; io_addrsel = value & 1; break; case 0x06: @@ -1212,7 +1662,7 @@ void vera_video_write(uint8_t reg, uint8_t value) case 0x0A: case 0x0B: case 0x0C: { - int i = reg - 0x09 + (io_dcsel ? 4 : 0); + int i = reg - 0x09 + (io_dcsel << 2); if (i == 0) { // interlace field bit is read-only reg_composer[0] = (reg_composer[0] & ~0x7f) | (value & 0x7f); @@ -1220,9 +1670,103 @@ void vera_video_write(uint8_t reg, uint8_t value) } else { reg_composer[i] = value; } + switch (i) { + case 0x08: // DCSEL=2, $9F29 + fx_addr1_mode = value & 0x03; + fx_4bit_mode = (value & 0x04) >> 2; + fx_16bit_hop = (value & 0x08) >> 3; + fx_cache_byte_cycling = (value & 0x10) >> 4; + fx_cache_fill = (value & 0x20) >> 5; + fx_cache_write = (value & 0x40) >> 6; + fx_trans_writes = (value & 0x80) >> 7; + break; + case 0x09: // DCSEL=2, $9F2A + fx_affine_tile_base = (value & 0xfc) << 9; + fx_affine_clip = (value & 0x02) >> 1; + fx_2bit_poly = (value & 0x01); + break; + case 0x0a: // DCSEL=2, $9F2B + fx_affine_map_base = (value & 0xfc) << 9; + fx_affine_map_size = 2 << ((value & 0x03) << 1); + break; + case 0x0b: // DCSEL=2, $9F2C + fx_cache_increment_mode = value & 0x01; + fx_cache_nibble_index = (value & 0x02) >> 1; + fx_cache_byte_index = (value & 0x0c) >> 2; + fx_multiplier = (value & 0x10) >> 4; + fx_subtract = (value & 0x20) >> 5; + if (value & 0x40) { // accumulate + int32_t m_result = (int16_t)((fx_cache[1] << 8) | fx_cache[0]) * (int16_t)((fx_cache[3] << 8) | fx_cache[2]); + if (fx_subtract) + fx_mult_accumulator -= m_result; + else + fx_mult_accumulator += m_result; + } + if (value & 0x80) { // reset accumulator + fx_mult_accumulator = 0; + } + break; + case 0x0c: // DCSEL=3, $9F29 + fx_x_pixel_increment = ((((reg_composer[0x0d] & 0x7f) << 15) + (reg_composer[0x0c] << 7)) // base value + | ((reg_composer[0x0d] & 0x40) ? 0xffc00000 : 0)) // sign extend if negative + << 5*(!!(reg_composer[0x0d] & 0x80)); // multiply by 32 if flag set + break; + case 0x0d: // DCSEL=3, $9F2A + fx_x_pixel_increment = ((((reg_composer[0x0d] & 0x7f) << 15) + (reg_composer[0x0c] << 7)) // base value + | ((reg_composer[0x0d] & 0x40) ? 0xffc00000 : 0)) // sign extend if negative + << 5*(!!(reg_composer[0x0d] & 0x80)); // multiply by 32 if flag set + // Reset subpixel to 0.5 + fx_x_pixel_position = (fx_x_pixel_position & 0x07ff0000) | 0x00008000; + break; + case 0x0e: // DCSEL=3, $9F2B + fx_y_pixel_increment = ((((reg_composer[0x0f] & 0x7f) << 15) + (reg_composer[0x0e] << 7)) // base value + | ((reg_composer[0x0f] & 0x40) ? 0xffc00000 : 0)) // sign extend if negative + << 5*(!!(reg_composer[0x0f] & 0x80)); // multiply by 32 if flag set + break; + case 0x0f: // DCSEL=3, $9F2C + fx_y_pixel_increment = ((((reg_composer[0x0f] & 0x7f) << 15) + (reg_composer[0x0e] << 7)) // base value + | ((reg_composer[0x0f] & 0x40) ? 0xffc00000 : 0)) // sign extend if negative + << 5*(!!(reg_composer[0x0f] & 0x80)); // multiply by 32 if flag set + // Reset subpixel to 0.5 + fx_y_pixel_position = (fx_y_pixel_position & 0x07ff0000) | 0x00008000; + break; + case 0x10: // DCSEL=4, $9F29 + fx_x_pixel_position = (fx_x_pixel_position & 0x0700ff80) | (value << 16); + fx_affine_prefetch(); + break; + case 0x11: // DCSEL=4, $9F2A + fx_x_pixel_position = (fx_x_pixel_position & 0x00ffff00) | ((value & 0x7) << 24) | (value & 0x80); + fx_affine_prefetch(); + break; + case 0x12: // DCSEL=4, $9F2B + fx_y_pixel_position = (fx_y_pixel_position & 0x0700ff80) | (value << 16); + fx_affine_prefetch(); + break; + case 0x13: // DCSEL=4, $9F2C + fx_y_pixel_position = (fx_y_pixel_position & 0x00ffff00) | ((value & 0x7) << 24) | (value & 0x80); + fx_affine_prefetch(); + break; + case 0x14: // DCSEL=5, $9F29 + fx_x_pixel_position = (fx_x_pixel_position & 0x07ff0080) | (value << 8); + break; + case 0x15: // DCSEL=5, $9F2A + fx_y_pixel_position = (fx_y_pixel_position & 0x07ff0080) | (value << 8); + break; + case 0x18: // DCSEL=6, $9F29 + fx_cache[0] = value; + break; + case 0x19: // DCSEL=6, $9F2A + fx_cache[1] = value; + break; + case 0x1a: // DCSEL=6, $9F2B + fx_cache[2] = value; + break; + case 0x1b: // DCSEL=6, $9F2C + fx_cache[3] = value; + break; + } break; } - case 0x0D: case 0x0E: case 0x0F: From a305e30995c7f3bdc9edba0c25535f6beb5208cd Mon Sep 17 00:00:00 2001 From: indigodarkwolf Date: Wed, 5 Jul 2023 14:55:20 -0500 Subject: [PATCH 02/13] Rebind esc->esc --- src/keyboard.cpp | 64 +++++++++++++------------- tools/generate_sdl_to_keynum_table.cpp | 2 +- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/keyboard.cpp b/src/keyboard.cpp index 6259b18..ac0fe40 100644 --- a/src/keyboard.cpp +++ b/src/keyboard.cpp @@ -47,38 +47,38 @@ static std::list Keyboard_event_list; static ring_buffer Keyboard_buffer; static const uint16_t SDL_to_keynum_table[] = { - 0x0000, 0x0000, 0x0000, 0x0000, 0x001f, 0x0032, 0x0030, 0x0021, 0x0013, 0x0022, 0x0023, 0x0024, 0x0018, 0x0025, 0x0026, 0x0027, - 0x0034, 0x0033, 0x0019, 0x001a, 0x0011, 0x0014, 0x0020, 0x0015, 0x0017, 0x0031, 0x0012, 0x002f, 0x0016, 0x002e, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x002b, 0x007e, 0x000f, 0x0010, 0x003d, 0x000c, 0x000d, 0x001b, - 0x001c, 0x001d, 0x0000, 0x0028, 0x0029, 0x0001, 0x0035, 0x0036, 0x0037, 0x001e, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, - 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x0000, 0x007d, 0x007e, 0x004b, 0x0050, 0x0055, 0x004c, 0x0051, 0x0056, 0x0059, - 0x004f, 0x0054, 0x0053, 0x0000, 0x005f, 0x0064, 0x0069, 0x006a, 0x006c, 0x005d, 0x0062, 0x0067, 0x005c, 0x0061, 0x0066, 0x005b, - 0x0060, 0x0065, 0x0063, 0x0068, 0x002d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x003a, 0x002c, 0x003c, 0x003b, 0x0040, 0x0039, 0x003e, 0x003f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x001f, 0x0032, 0x0030, 0x0021, 0x0013, 0x0022, 0x0023, 0x0024, 0x0018, 0x0025, 0x0026, 0x0027, + 0x0034, 0x0033, 0x0019, 0x001a, 0x0011, 0x0014, 0x0020, 0x0015, 0x0017, 0x0031, 0x0012, 0x002f, 0x0016, 0x002e, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x002b, 0x006e, 0x000f, 0x0010, 0x003d, 0x000c, 0x000d, 0x001b, + 0x001c, 0x001d, 0x0000, 0x0028, 0x0029, 0x0001, 0x0035, 0x0036, 0x0037, 0x001e, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, + 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x0000, 0x007d, 0x007e, 0x004b, 0x0050, 0x0055, 0x004c, 0x0051, 0x0056, 0x0059, + 0x004f, 0x0054, 0x0053, 0x0000, 0x005f, 0x0064, 0x0069, 0x006a, 0x006c, 0x005d, 0x0062, 0x0067, 0x005c, 0x0061, 0x0066, 0x005b, + 0x0060, 0x0065, 0x0063, 0x0068, 0x002d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x003a, 0x002c, 0x003c, 0x003b, 0x0040, 0x0039, 0x003e, 0x003f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; static bool process_key_event(const key_event_data &data) diff --git a/tools/generate_sdl_to_keynum_table.cpp b/tools/generate_sdl_to_keynum_table.cpp index 58a96f3..f1cadff 100644 --- a/tools/generate_sdl_to_keynum_table.cpp +++ b/tools/generate_sdl_to_keynum_table.cpp @@ -10,7 +10,7 @@ using namespace std; #define EXTENDED_FLAG 0x100 -#define ESC_IS_BREAK /* if enabled, Esc sends Break/Pause key instead of Esc */ +//#define ESC_IS_BREAK /* if enabled, Esc sends Break/Pause key instead of Esc */ uint16_t keynum_from_SDL_Scancode(SDL_Scancode scancode) { From 7a5707c61f8c5d74df67c16109b5ae019170087a Mon Sep 17 00:00:00 2001 From: mooinglemur Date: Thu, 31 Aug 2023 15:11:27 -0700 Subject: [PATCH 03/13] Move VIA1 interrupt to IRQ to match hardware (#101) --- src/main.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index de1964a..fd35899 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -429,7 +429,6 @@ void emulator_loop() cpu_visualization_step(); uint8_t clocks = (uint8_t)(clockticks6502 - old_clockticks6502); bool new_frame = vera_video_step(MHZ, clocks); - bool via1_irq_old = via1_irq(); via1_step(clocks); via2_step(clocks); rtc_step(clocks); @@ -458,12 +457,7 @@ void emulator_loop() #endif } - if (!via1_irq_old && via1_irq()) { - nmi6502(); - debugger_interrupt(); - } - - if (vera_video_get_irq_out() || YM_irq() || via2_irq()) { + if (vera_video_get_irq_out() || YM_irq() || via1_irq() || via2_irq()) { irq6502(); debugger_interrupt(); } From 74b5e145cea59f24d218be2a8d3850bce26fb27a Mon Sep 17 00:00:00 2001 From: Cameron Nelson <72891927+cnelson20@users.noreply.github.com> Date: Fri, 1 Sep 2023 22:30:30 -0400 Subject: [PATCH 04/13] Update README.md to link to X16Community repo (#102) * Update README.md to link to X16Community repo Change link in README to link to X16Community repo of x16emu that is now the primary location for all X16-related software * Update other links in README.md Update more links in README to point to X16Community repos --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ca8e07a..7507b73 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Build status](https://github.com/indigodarkwolf/box16/actions/workflows/build.yml/badge.svg)](https://github.com/indigodarkwolf/box16/actions/workflows/build.yml)
[![Release](https://img.shields.io/github/v/release/indigodarkwolf/box16)](https://github.com/indigodarkwolf/box16/releases) -This is an emulator for the Commander X16 computer system. Unlike [the official emulator](https://github.com/commanderx16/x16-emulator), this has a few more dependencies, see the build instructions below. It compiles on Windows, Debian Linux, and Raspbian, and probably +This is an emulator for the Commander X16 computer system. Unlike [the official emulator](https://github.com/X16Community/x16-emulator), this has a few more dependencies, see the build instructions below. It compiles on Windows, Debian Linux, and Raspbian, and probably other Linux-based platforms. Don't expect official "releases" until the physical X16 is out. Until then, there will be "non-releases" of Box16. @@ -49,7 +49,7 @@ loaded from the directory containing the emulator binary, or you can use the `-r > __WARNING:__ Older versions of the ROM might not work in newer versions of the emulator, and vice versa. -You can build a ROM image yourself using the [build instructions](https://github.com/commanderx16/x16-rom#releases-and-building) in the [x16-rom](https://github.com/commanderx16/x16-rom) repo. The `rom.bin` included in the [_latest_ release](https://github.com/commanderx16/x16-emulator/releases) of the emulator may also work with the HEAD of this repo, but this is not guaranteed. +You can build a ROM image yourself using the [build instructions](https://github.com/X16Community/x16-rom#releases-and-building) in the [x16-rom](https://github.com/X16Community/x16-rom) repo. The `rom.bin` included in the [_latest_ release](https://github.com/X16Community/x16-emulator/releases) of the emulator may also work with the HEAD of this repo, but this is not guaranteed. ### Linux Build @@ -355,7 +355,7 @@ Forum Wiki ---- -[https://github.com/commanderx16/x16-emulator/wiki](https://github.com/commanderx16/x16-emulator/wiki) +[https://github.com/commanderx16/x16-emulator/wiki](https://github.com/X16Community/x16-emulator/wiki) License From f59c13a4d372c24a7935b25aea5e654c06d575c1 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 5 Oct 2023 00:59:04 +0200 Subject: [PATCH 05/13] Add the three emulator debug registers to write characters to the console (+ add clock snapshot behavior too) (#103) * Add the three emulator debug registers to write characters to the console. * use proper conversion routine to output character * add clock snapshot behavior to emulator debug registers * make clock snapshot same type as clock itself * Returning clock_snap instead of clockticks6502 in debug_emu_read. --------- Co-authored-by: indigodarkwolf --- src/memory.cpp | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/memory.cpp b/src/memory.cpp index d3bd8f1..9b96eb1 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -16,6 +16,7 @@ #include "gif_recorder.h" #include "glue.h" #include "hypercalls.h" +#include "unicode.h" #include "vera/vera_video.h" #include "via.h" #include "wav_recorder.h" @@ -35,6 +36,8 @@ uint8_t rom_bank_register; static uint64_t *RAM_written; static uint8_t addr_ym = 0; +static uint64_t clock_snap = 0UL; +static uint64_t clock_base = 0UL; #define DEVICE_EMULATOR (0x9fb0) @@ -239,10 +242,10 @@ uint8_t debug_emu_read(uint8_t reg) case 5: return gif_recorder_get_state(); case 6: return wav_recorder_get_state(); case 7: return Options.no_keybinds ? 1 : 0; - case 8: return (clockticks6502 >> 0) & 0xff; - case 9: return (clockticks6502 >> 8) & 0xff; - case 10: return (clockticks6502 >> 16) & 0xff; - case 11: return (clockticks6502 >> 24) & 0xff; + case 8: return (clock_snap >> 0) & 0xff; // don't do snapshotting here because no state should be changed + case 9: return (clock_snap >> 8) & 0xff; + case 10: return (clock_snap >> 16) & 0xff; + case 11: return (clock_snap >> 24) & 0xff; // case 12: return -1; case 13: return Options.keymap; case 14: return '1'; // emulator detection @@ -262,10 +265,12 @@ uint8_t real_emu_read(uint8_t reg) case 5: return gif_recorder_get_state(); case 6: return wav_recorder_get_state(); case 7: return Options.no_keybinds ? 1 : 0; - case 8: return (clockticks6502 >> 0) & 0xff; - case 9: return (clockticks6502 >> 8) & 0xff; - case 10: return (clockticks6502 >> 16) & 0xff; - case 11: return (clockticks6502 >> 24) & 0xff; + case 8: + clock_snap = clockticks6502 - clock_base; + return (clock_snap >> 0) & 0xff; + case 9: return (clock_snap >> 8) & 0xff; + case 10: return (clock_snap >> 16) & 0xff; + case 11: return (clock_snap >> 24) & 0xff; // case 12: return -1; case 13: return Options.keymap; case 14: return '1'; // emulator detection @@ -291,6 +296,20 @@ void emu_write(uint8_t reg, uint8_t value) case 5: gif_recorder_set((gif_recorder_command_t)value); break; case 6: wav_recorder_set((wav_recorder_command_t)value); break; case 7: Options.no_keybinds = v; break; + case 8: clock_base = clockticks6502; break; + case 9: printf("User debug 1: $%02x\n", value); break; + case 10: printf("User debug 2: $%02x\n", value); break; + case 11: { + if (value == 0x09 || value == 0x0a || value == 0x0d || (value >= 0x20 && value < 0x7f)) { + putchar(value); + } else if (value >= 0xa1) { + print_iso8859_15_char((char) value); + } else { + printf("\xef\xbf\xbd"); // � + } + fflush(stdout); + break; + } default: break; // printf("WARN: Invalid register %x\n", DEVICE_EMULATOR + reg); } } From f9bba45bf5526c3b474f59527d12fd69e322fc5e Mon Sep 17 00:00:00 2001 From: mooinglemur Date: Sun, 8 Oct 2023 02:45:03 +0000 Subject: [PATCH 06/13] Port MCIOUT hypercall from x16-emulator, fix MACPTR bug (#104) --- src/hypercalls.cpp | 48 ++++++++++++++++++++++++++++++---------------- src/ieee.cpp | 39 +++++++++++++++++++++++++++++++++++-- src/ieee.h | 1 + 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/src/hypercalls.cpp b/src/hypercalls.cpp index 027263d..d2d302a 100644 --- a/src/hypercalls.cpp +++ b/src/hypercalls.cpp @@ -16,6 +16,7 @@ #include "vera/sdcard.h" #include "zlib.h" +#define KERNAL_MCIOUT (0xfeb1) #define KERNAL_MACPTR (0xff44) #define KERNAL_SECOND (0xff93) #define KERNAL_TKSA (0xff96) @@ -35,7 +36,7 @@ static uint16_t Kernal_status = 0; static bool Has_boot_tasks = false; static bool prg_finished_loading = false; -static bool (*Hypercall_table[0x100])(void); +static bool (*Hypercall_table[0x200])(void); static bool is_kernal() { @@ -159,7 +160,22 @@ void hypercalls_update() memset(Hypercall_table, 0, sizeof(Hypercall_table)); if (ieee_hypercalls_allowed()) { - Hypercall_table[KERNAL_MACPTR & 0xff] = []() -> bool { + Hypercall_table[KERNAL_MCIOUT & 0x1ff] = []() -> bool { + uint16_t count = state6502.a; + const int s = MCIOUT(state6502.y << 8 | state6502.x, &count, state6502.status & 0x01); + state6502.x = count & 0xff; + state6502.y = count >> 8; + if (s == -2) { + state6502.status |= 1; // SEC (unsupported, or in this case, no open context) + } else { + state6502.status &= 0xfe; // clear C -> supported + } + + set_kernal_status(s); + return true; + }; + + Hypercall_table[KERNAL_MACPTR & 0x1ff] = []() -> bool { uint16_t count = state6502.a; const int s = MACPTR(state6502.y << 8 | state6502.x, &count, state6502.status & 0x01); @@ -172,19 +188,19 @@ void hypercalls_update() return true; }; - Hypercall_table[KERNAL_SECOND & 0xff] = []() -> bool { + Hypercall_table[KERNAL_SECOND & 0x1ff] = []() -> bool { const int s = SECOND(state6502.a); set_kernal_status(s); return true; }; - Hypercall_table[KERNAL_TKSA & 0xff] = []() -> bool { + Hypercall_table[KERNAL_TKSA & 0x1ff] = []() -> bool { TKSA(state6502.a); return true; }; - Hypercall_table[KERNAL_ACPTR & 0xff] = []() -> bool { + Hypercall_table[KERNAL_ACPTR & 0x1ff] = []() -> bool { const int s = ACPTR(&state6502.a); state6502.status = (state6502.status & ~3) | (!state6502.a << 1); @@ -193,19 +209,19 @@ void hypercalls_update() return true; }; - Hypercall_table[KERNAL_CIOUT & 0xff] = []() -> bool { + Hypercall_table[KERNAL_CIOUT & 0x1ff] = []() -> bool { const int s = CIOUT(state6502.a); set_kernal_status(s); return true; }; - Hypercall_table[KERNAL_UNTLK & 0xff] = []() -> bool { + Hypercall_table[KERNAL_UNTLK & 0x1ff] = []() -> bool { UNTLK(); return true; }; - Hypercall_table[KERNAL_UNLSN & 0xff] = []() -> bool { + Hypercall_table[KERNAL_UNLSN & 0x1ff] = []() -> bool { const int s = UNLSN(); if (s == -2) { // special error behavior state6502.status = (state6502.status | 1); // SEC @@ -226,19 +242,19 @@ void hypercalls_update() return true; }; - Hypercall_table[KERNAL_LISTEN & 0xff] = []() -> bool { + Hypercall_table[KERNAL_LISTEN & 0x1ff] = []() -> bool { LISTEN(state6502.a); return true; }; - Hypercall_table[KERNAL_TALK & 0xff] = []() -> bool { + Hypercall_table[KERNAL_TALK & 0x1ff] = []() -> bool { TALK(state6502.a); return true; }; } // if (!sdcard_is_attached()) { - // Hypercall_table[KERNAL_LOAD & 0xff] = []() -> bool { + // Hypercall_table[KERNAL_LOAD & 0x1ff] = []() -> bool { // if (RAM[FA] == 8) { // LOAD(); // return true; @@ -246,7 +262,7 @@ void hypercalls_update() // return false; // }; - // Hypercall_table[KERNAL_SAVE & 0xff] = []() -> bool { + // Hypercall_table[KERNAL_SAVE & 0x1ff] = []() -> bool { // if (RAM[FA] == 8) { // SAVE(); // return true; @@ -256,7 +272,7 @@ void hypercalls_update() // } if (Has_boot_tasks) { - Hypercall_table[KERNAL_CHRIN & 0xff] = []() -> bool { + Hypercall_table[KERNAL_CHRIN & 0x1ff] = []() -> bool { // as soon as BASIC starts reading a line... if (!Options.prg_path.empty()) { std::filesystem::path prg_path = options_get_hyper_path() / Options.prg_path; @@ -327,7 +343,7 @@ void hypercalls_update() } if (Options.echo_mode != echo_mode_t::ECHO_MODE_NONE) { - Hypercall_table[KERNAL_CHROUT & 0xff] = []() -> bool { + Hypercall_table[KERNAL_CHROUT & 0x1ff] = []() -> bool { uint8_t c = state6502.a; if (Options.echo_mode == echo_mode_t::ECHO_MODE_COOKED) { if (c == 0x0d) { @@ -360,11 +376,11 @@ void hypercalls_update() void hypercalls_process() { - if (!is_kernal() || state6502.pc < 0xFF44) { + if (!is_kernal() || state6502.pc < 0xFEB1) { return; } - const auto hypercall = Hypercall_table[state6502.pc & 0xff]; + const auto hypercall = Hypercall_table[state6502.pc & 0x1ff]; if (hypercall != nullptr) { if (hypercall()) { state6502.pc = (RAM[0x100 + state6502.sp + 1] | (RAM[0x100 + state6502.sp + 2] << 8)) + 1; diff --git a/src/ieee.cpp b/src/ieee.cpp index 7b34944..1f867ef 100644 --- a/src/ieee.cpp +++ b/src/ieee.cpp @@ -1277,7 +1277,7 @@ int ACPTR(uint8_t *a) int CIOUT(uint8_t a) { - int ret = -1; + int ret = 0; if (log_ieee) { printf("%s $%02x\n", __func__, a); } @@ -1386,7 +1386,7 @@ int MACPTR(uint16_t addr, uint16_t *c, uint8_t stream_mode) write6502(0, ram_bank); } } - if (ret >= 0) { + if (ret > 0) { break; } } while (i < count); @@ -1396,3 +1396,38 @@ int MACPTR(uint16_t addr, uint16_t *c, uint8_t stream_mode) *c = i; return ret; } + +int MCIOUT(uint16_t addr, uint16_t *c, uint8_t stream_mode) +{ + if (log_ieee) { + printf("%s $%04x $%04x $%02x\n", __func__, addr, *c, stream_mode); + } + + int ret = 0; + int count = (*c != 0) ? (*c) : 256; + uint8_t ram_bank = read6502(0); + int i = 0; + if (channels[channel].f && channels[channel].write) { + do { + uint8_t byte; + byte = read6502(addr); + i++; + if (!stream_mode) { + addr++; + if (addr == 0xc000) { + addr = 0xa000; + ram_bank++; + write6502(0, ram_bank); + } + } + ret = CIOUT(byte); + if (ret > 0) { + break; + } + } while(i < count); + } else { + ret = -2; + } + *c = i; + return ret; +} diff --git a/src/ieee.h b/src/ieee.h index b5e2297..65ba070 100644 --- a/src/ieee.h +++ b/src/ieee.h @@ -16,5 +16,6 @@ int UNLSN(); void LISTEN(uint8_t a); void TALK(uint8_t a); int MACPTR(uint16_t addr, uint16_t *count, uint8_t stream_mode); +int MCIOUT(uint16_t addr, uint16_t *count, uint8_t stream_mode); #endif From daefae65ff040d4247f392607d1fb272cd05e8c5 Mon Sep 17 00:00:00 2001 From: mooinglemur Date: Wed, 29 Nov 2023 01:41:45 +0000 Subject: [PATCH 07/13] Port corrected PCM underflow behavior from x16-emulator (#105) --- src/vera/vera_pcm.cpp | 66 ++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/src/vera/vera_pcm.cpp b/src/vera/vera_pcm.cpp index 9b6e56b..8bd1efc 100644 --- a/src/vera/vera_pcm.cpp +++ b/src/vera/vera_pcm.cpp @@ -114,29 +114,49 @@ void pcm_render(int16_t *buf, unsigned num_samples) uint8_t old_phase = phase; phase += rate; if ((old_phase & 0x80) != (phase & 0x80)) { - switch ((ctrl >> 4) & 3) { - case 0: { // mono 8-bit - cur_l = (int16_t)read_fifo() << 8; - cur_r = cur_l; - break; - } - case 1: { // stereo 8-bit - cur_l = read_fifo() << 8; - cur_r = read_fifo() << 8; - break; - } - case 2: { // mono 16-bit - cur_l = read_fifo(); - cur_l |= read_fifo() << 8; - cur_r = cur_l; - break; - } - case 3: { // stereo 16-bit - cur_l = read_fifo(); - cur_l |= read_fifo() << 8; - cur_r = read_fifo(); - cur_r |= read_fifo() << 8; - break; + if (fifo_cnt == 0) { + cur_l = 0; + cur_r = 0; + } else { + switch ((ctrl >> 4) & 3) { + case 0: { // mono 8-bit + cur_l = (int16_t)read_fifo() << 8; + cur_r = cur_l; + break; + } + case 1: { // stereo 8-bit + if (fifo_cnt < 2) { + fifo_cnt = 0; + fifo_rdidx = fifo_wridx; + } else { + cur_l = read_fifo() << 8; + cur_r = read_fifo() << 8; + } + break; + } + case 2: { // mono 16-bit + if (fifo_cnt < 2) { + fifo_cnt = 0; + fifo_rdidx = fifo_wridx; + } else { + cur_l = read_fifo(); + cur_l |= read_fifo() << 8; + cur_r = cur_l; + } + break; + } + case 3: { // stereo 16-bit + if (fifo_cnt < 4) { + fifo_cnt = 0; + fifo_rdidx = fifo_wridx; + } else { + cur_l = read_fifo(); + cur_l |= read_fifo() << 8; + cur_r = read_fifo(); + cur_r |= read_fifo() << 8; + } + break; + } } } } From 4d195abb473ed36753216e94f2f46ab226204b42 Mon Sep 17 00:00:00 2001 From: mooinglemur Date: Wed, 29 Nov 2023 01:41:57 +0000 Subject: [PATCH 08/13] port proposed t256 bit reuse feature for tile mode palette (#106) --- src/overlay/overlay.cpp | 13 +++++++++++-- src/vera/vera_video.cpp | 14 ++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/overlay/overlay.cpp b/src/overlay/overlay.cpp index 5c7e67c..3eb8f81 100644 --- a/src/overlay/overlay.cpp +++ b/src/overlay/overlay.cpp @@ -1399,8 +1399,12 @@ class tmap_visualizer for (uint32_t i = 0; i < num_dots; i++) { uint8_t tdat = tile_data[i]; - if (tdat > 0 && tdat < 16) // 8bpp quirk handling + if (tdat > 0 && tdat < 16) { // 8bpp quirk handling tdat += palette_offset; + if (t256c) { + tdat |= 0x80; + } + } pixels[i] = palette[tdat]; } } else { @@ -1450,8 +1454,13 @@ class tmap_visualizer for (int tj = 0; tj < tile_width; tj++) { uint8_t tdat = tile_data[src2]; src2 += src2_add; - if (tdat > 0 && tdat < 16) + if (tdat > 0 && tdat < 16) { tdat += pal; + if (t256c) { + tdat |= 0x80; + } + } + pixels[dst2++] = palette[tdat]; } } diff --git a/src/vera/vera_video.cpp b/src/vera/vera_video.cpp index f8aee85..5f98971 100644 --- a/src/vera/vera_video.cpp +++ b/src/vera/vera_video.cpp @@ -56,7 +56,7 @@ // Version #define VERA_VERSION_MAJOR 0x00 #define VERA_VERSION_MINOR 0x03 -#define VERA_VERSION_PATCH 0x01 +#define VERA_VERSION_PATCH 0x02 static bool is_fullscreen = false; @@ -761,8 +761,11 @@ static void render_layer_line_tile(uint16_t y) uint8_t col_index = (s >> color_shift) & props->color_mask; // Apply Palette Offset - if (palette_offset && col_index > 0 && col_index < 16) { + if (col_index > 0 && col_index < 16) { col_index += palette_offset; + if (props->text_mode_256c) { + col_index |= 0x80; + } } layer_line[layer][i] = col_index; @@ -810,8 +813,11 @@ static void render_layer_line_bitmap(uint16_t y) uint8_t col_index = (s >> (props->first_color_pos - ((xx & props->color_fields_max) << props->color_depth))) & props->color_mask; // Apply Palette Offset - if (palette_offset && col_index > 0 && col_index < 16) { + if (col_index > 0 && col_index < 16) { col_index += palette_offset << 4; + if (props->text_mode_256c) { + col_index |= 0x80; + } } layer_line[layer][i] = col_index; @@ -2109,4 +2115,4 @@ vera_video_rect vera_video_get_scan_visible() VGA_Y_OFFSET, VGA_Y_OFFSET + SCREEN_HEIGHT }; } -} \ No newline at end of file +} From bb03daa913516685135a4fc0192ee8f235e52572 Mon Sep 17 00:00:00 2001 From: indigodarkwolf Date: Mon, 4 Dec 2023 21:27:07 -0600 Subject: [PATCH 09/13] SmartStack improvements. Can now detect the rti shim for restoring banks when leaving interrupt logic. --- src/cpu/fake6502.cpp | 31 ++++++++------ src/cpu/fake6502.h | 43 ++++++++++++++++---- src/cpu/instructions_6502.h | 58 ++++++++++++++++++++++++++- src/cpu/instructions_65c02.h | 20 +++++++++ src/cpu/support.h | 14 ++++--- src/glue.h | 1 + src/main.cpp | 2 +- src/overlay/overlay.cpp | 78 ++++++++++++++++++++++++++++-------- 8 files changed, 201 insertions(+), 46 deletions(-) diff --git a/src/cpu/fake6502.cpp b/src/cpu/fake6502.cpp index 9d1d822..5f8f1eb 100644 --- a/src/cpu/fake6502.cpp +++ b/src/cpu/fake6502.cpp @@ -94,7 +94,8 @@ uint8_t debug6502 = 0; uint8_t penaltyop, penaltyaddr; uint8_t waiting = 0; -_smart_stack stack6502[256]; +_smart_stack stack6502[256]; +uint8_t stack6502_underflow = 0; // externally supplied functions extern uint8_t read6502(uint16_t address); @@ -128,9 +129,11 @@ static void putvalue(uint16_t saveval) void nmi6502() { - auto &ss = stack6502[state6502.sp_depth++]; - ss.source_pc = state6502.pc; + auto &ss = stack6502[state6502.sp_depth++]; + ss.source_pc = state6502.pc; ss.source_bank = bank6502(state6502.pc); + ss.push_depth = 0; + state6502.sp_unwind_depth = state6502.sp_depth; push16(state6502.pc); push8(state6502.status & ~FLAG_BREAK); @@ -140,18 +143,21 @@ void nmi6502() state6502.pc = (uint16_t)read6502(0xFFFA) | ((uint16_t)read6502(0xFFFB) << 8); waiting = 0; - ss.dest_pc = state6502.pc; + ss.dest_pc = state6502.pc; ss.dest_bank = bank6502(state6502.pc); - ss.op_type = _stack_op_type::nmi; - ss.opcode = 0; + ss.op_type = _stack_op_type::nmi; + ss.pop_type = _stack_pop_type::unknown; + ss.opcode = 0; } void irq6502() { if (!(state6502.status & FLAG_INTERRUPT)) { - auto &ss = stack6502[state6502.sp_depth++]; - ss.source_pc = state6502.pc; + auto &ss = stack6502[state6502.sp_depth++]; + ss.source_pc = state6502.pc; ss.source_bank = bank6502(state6502.pc); + ss.push_depth = 0; + state6502.sp_unwind_depth = state6502.sp_depth; push16(state6502.pc); push8(state6502.status & ~FLAG_BREAK); @@ -160,10 +166,11 @@ void irq6502() vp6502(); state6502.pc = (uint16_t)read6502(0xFFFE) | ((uint16_t)read6502(0xFFFF) << 8); - ss.dest_pc = state6502.pc; + ss.dest_pc = state6502.pc; ss.dest_bank = bank6502(state6502.pc); ss.op_type = _stack_op_type::irq; - ss.opcode = 0; + ss.pop_type = _stack_pop_type::unknown; + ss.opcode = 0; } waiting = 0; } @@ -198,7 +205,7 @@ void exec6502(uint32_t tickcount) (*addrtable[opcode])(); (*optable[opcode])(); - if (debug6502 & (DEBUG6502_READ | DEBUG6502_WRITE)) { + if ((debug6502 & (DEBUG6502_READ | DEBUG6502_WRITE)) || stack6502_underflow) { state6502 = debug_state6502; clockticks6502 = debug_clockticks6502; return; @@ -240,7 +247,7 @@ void step6502() (*addrtable[opcode])(); (*optable[opcode])(); - if (debug6502 & (DEBUG6502_READ | DEBUG6502_WRITE)) { + if ((debug6502 & (DEBUG6502_READ | DEBUG6502_WRITE)) || stack6502_underflow) { state6502 = debug_state6502; clockticks6502 = debug_clockticks6502; return; diff --git a/src/cpu/fake6502.h b/src/cpu/fake6502.h index c22929c..259483f 100644 --- a/src/cpu/fake6502.h +++ b/src/cpu/fake6502.h @@ -13,23 +13,50 @@ struct _state6502 { uint16_t pc; - uint8_t sp_depth; + uint8_t sp_depth; + uint8_t sp_unwind_depth; uint8_t sp, a, x, y, status; }; enum class _stack_op_type : uint8_t { - op, nmi, irq, + jsr, + smart, +}; + +enum class _stack_pop_type : uint8_t { + unknown, + rts, + rti +}; + +enum class _push_op_type : uint8_t { + unknown, + a, + x, + y, + status +}; + +struct _smart_stack_ex { + _push_op_type push_type; + _push_op_type pull_type; + uint8_t value; }; struct _smart_stack { - uint16_t source_pc; - uint16_t dest_pc; - uint8_t source_bank; - uint8_t dest_bank; - _stack_op_type op_type; - uint8_t opcode; + uint16_t source_pc; + uint16_t dest_pc; + uint8_t source_bank; + uint8_t dest_bank; + _stack_op_type op_type; + _stack_pop_type pop_type; + uint16_t pop_pc; + uint8_t pop_bank; + uint8_t opcode; + uint8_t push_depth; + _smart_stack_ex pushed_bytes[256]; }; extern void init6502(); diff --git a/src/cpu/instructions_6502.h b/src/cpu/instructions_6502.h index d0b4e9c..e1d0c94 100644 --- a/src/cpu/instructions_6502.h +++ b/src/cpu/instructions_6502.h @@ -375,13 +375,16 @@ jsr() auto &ss = stack6502[state6502.sp_depth++]; ss.source_pc = state6502.pc; ss.source_bank = bank6502(state6502.pc); + ss.push_depth = 0; + state6502.sp_unwind_depth = state6502.sp_depth; push16(state6502.pc - 1); state6502.pc = ea; ss.dest_pc = state6502.pc; ss.dest_bank = bank6502(state6502.pc); - ss.op_type = _stack_op_type::op; + ss.op_type = _stack_op_type::jsr; + ss.pop_type = _stack_pop_type::unknown; ss.opcode = opcode; } @@ -466,12 +469,38 @@ static void pha() { push8(state6502.a); + auto &ss = stack6502[(state6502.sp_depth + 255) & 0xff]; + auto &ssx = ss.pushed_bytes[ss.push_depth++]; + ssx.push_type = _push_op_type::a; + ssx.pull_type = _push_op_type::unknown; + ssx.value = state6502.a; } static void php() { push8(state6502.status | FLAG_BREAK); + auto &ss = stack6502[(state6502.sp_depth + 255) & 0xff]; + auto &ssx = ss.pushed_bytes[ss.push_depth++]; + ssx.push_type = _push_op_type::status; + ssx.pull_type = _push_op_type::unknown; + ssx.value = state6502.status | FLAG_BREAK; + + if (ss.op_type != _stack_op_type::jsr && ss.push_depth == 5) { + ss.push_depth -= 3; + + auto &ss2 = stack6502[state6502.sp_depth++]; + ss2.source_pc = (static_cast(ss.pushed_bytes[ss.push_depth].value) << 8) | static_cast(ss.pushed_bytes[ss.push_depth+1].value); + ss2.source_bank = bank6502(state6502.pc); + ss2.push_depth = 0; + state6502.sp_unwind_depth = state6502.sp_depth; + + ss2.dest_pc = state6502.pc; + ss2.dest_bank = bank6502(state6502.pc); + ss2.op_type = _stack_op_type::smart; + ss2.pop_type = _stack_pop_type::unknown; + ss2.opcode = 0; + } } static void @@ -481,12 +510,22 @@ pla() zerocalc(state6502.a); signcalc(state6502.a); + + auto &ss = stack6502[(state6502.sp_depth + 255) & 0xff]; + ss.push_depth -= !!ss.push_depth; + auto &ssx = ss.pushed_bytes[ss.push_depth]; + ssx.pull_type = _push_op_type::a; } static void plp() { state6502.status = pull8() | FLAG_CONSTANT; + + auto &ss = stack6502[(state6502.sp_depth + 255) & 0xff]; + ss.push_depth -= !!ss.push_depth; + auto &ssx = ss.pushed_bytes[ss.push_depth]; + ssx.pull_type = _push_op_type::status; } static void @@ -521,18 +560,33 @@ ror() static void rti() { + const uint16_t old_pc = state6502.pc; state6502.status = pull8(); value = pull16(); state6502.pc = value; + stack6502_underflow |= !state6502.sp_depth; state6502.sp_depth -= !!state6502.sp_depth; + + auto &ss = stack6502[state6502.sp_depth]; + ss.pop_type = _stack_pop_type::rti; + ss.pop_pc = old_pc - 1; + ss.pop_bank = bank6502(old_pc); } static void rts() { - value = pull16(); + const uint16_t old_pc = state6502.pc; + + value = pull16(); state6502.pc = value + 1; + stack6502_underflow |= !state6502.sp_depth; state6502.sp_depth -= !!state6502.sp_depth; + + auto &ss = stack6502[state6502.sp_depth]; + ss.pop_type = _stack_pop_type::rts; + ss.pop_pc = old_pc - 1; + ss.pop_bank = bank6502(old_pc); } static void diff --git a/src/cpu/instructions_65c02.h b/src/cpu/instructions_65c02.h index bff4cb4..26642eb 100644 --- a/src/cpu/instructions_65c02.h +++ b/src/cpu/instructions_65c02.h @@ -84,6 +84,11 @@ static void phx() { push8(state6502.x); + auto &ss = stack6502[(state6502.sp_depth + 255) & 0xff]; + auto &ssx = ss.pushed_bytes[ss.push_depth++]; + ssx.push_type = _push_op_type::x; + ssx.pull_type = _push_op_type::unknown; + ssx.value = state6502.x; } static void @@ -93,12 +98,22 @@ plx() zerocalc(state6502.x); signcalc(state6502.x); + + auto &ss = stack6502[(state6502.sp_depth + 255) & 0xff]; + ss.push_depth -= !!ss.push_depth; + auto &ssx = ss.pushed_bytes[ss.push_depth]; + ssx.pull_type = _push_op_type::x; } static void phy() { push8(state6502.y); + auto &ss = stack6502[(state6502.sp_depth + 255) & 0xff]; + auto &ssx = ss.pushed_bytes[ss.push_depth++]; + ssx.push_type = _push_op_type::y; + ssx.pull_type = _push_op_type::unknown; + ssx.value = state6502.y; } static void @@ -108,6 +123,11 @@ ply() zerocalc(state6502.y); signcalc(state6502.y); + + auto &ss = stack6502[(state6502.sp_depth + 255) & 0xff]; + ss.push_depth -= !!ss.push_depth; + auto &ssx = ss.pushed_bytes[ss.push_depth]; + ssx.pull_type = _push_op_type::y; } // ******************************************************************************************* diff --git a/src/cpu/support.h b/src/cpu/support.h index 9993ed5..b6e844d 100644 --- a/src/cpu/support.h +++ b/src/cpu/support.h @@ -85,13 +85,15 @@ uint8_t pull8() void reset6502() { vp6502(); - state6502.pc = (uint16_t)read6502(0xFFFC) | ((uint16_t)read6502(0xFFFD) << 8); - state6502.sp_depth = 0; - state6502.a = 0; - state6502.x = 0; - state6502.y = 0; - state6502.sp = 0xFD; + state6502.pc = (uint16_t)read6502(0xFFFC) | ((uint16_t)read6502(0xFFFD) << 8); + state6502.sp_depth = 0; + state6502.sp_unwind_depth = 0; + state6502.a = 0; + state6502.x = 0; + state6502.y = 0; + state6502.sp = 0xFD; state6502.status |= FLAG_CONSTANT | FLAG_BREAK; + stack6502_underflow = 0; setinterrupt(); cleardecimal(); waiting = 0; diff --git a/src/glue.h b/src/glue.h index bd8827a..c843d68 100644 --- a/src/glue.h +++ b/src/glue.h @@ -28,6 +28,7 @@ extern _state6502 state6502; extern uint8_t waiting; extern _smart_stack stack6502[256]; +extern uint8_t stack6502_underflow; extern uint8_t *RAM; extern uint8_t ROM[ROM_SIZE]; diff --git a/src/main.cpp b/src/main.cpp index fd35899..8cc6c01 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -418,7 +418,7 @@ void emulator_loop() uint64_t old_clockticks6502 = clockticks6502; step6502(); - if (debug6502) { + if (debug6502 || stack6502_underflow) { debugger_process_cpu(); if (debugger_is_paused()) { continue; diff --git a/src/overlay/overlay.cpp b/src/overlay/overlay.cpp index 3eb8f81..6d3ac3b 100644 --- a/src/overlay/overlay.cpp +++ b/src/overlay/overlay.cpp @@ -172,7 +172,18 @@ static void draw_debugger_cpu_status() ImGui::TableNextColumn(); if (ImGui::BeginTable("smart stack", 1, ImGuiTableFlags_ScrollY)) { - for (uint16_t i = state6502.sp_depth - 1; i < state6502.sp_depth; --i) { + if (stack6502_underflow) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::TextDisabled("%s", "(Underflow)"); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text("%s", "There appears to have been a smartstack underflow.\nThis usually means there was a mismatched jsr / rts pair,\nor an rti executed outside of an interrupt.\n\nBox16's SmartStack cannot currently track manual stack manipulation very well."); + ImGui::EndTooltip(); + } + ImGui::TableNextRow(); + } + for (uint16_t i = state6502.sp_unwind_depth - 1; i < state6502.sp_unwind_depth; --i) { ImGui::TableNextColumn(); auto do_label = [](uint16_t pc, uint8_t bank, bool allow_disabled) { char const *label = disasm_get_label(pc); @@ -213,21 +224,30 @@ static void draw_debugger_cpu_status() } } }; - switch (stack6502[i].op_type) { - case _stack_op_type::nmi: - ImGui::PushStyleColor(ImGuiCol_TextDisabled, 0xFF003388); - ImGui::PushStyleColor(ImGuiCol_Text, 0xFF0077FF); - break; - case _stack_op_type::irq: - ImGui::PushStyleColor(ImGuiCol_TextDisabled, 0xFF007788); - ImGui::PushStyleColor(ImGuiCol_Text, 0xFF00FFFF); - break; - case _stack_op_type::op: - ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled)); - ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text)); - break; - default: - break; + if (i > state6502.sp_depth) { + ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled)); + ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled)); + } else { + switch (stack6502[i].op_type) { + case _stack_op_type::nmi: + ImGui::PushStyleColor(ImGuiCol_TextDisabled, 0xFF003388); + ImGui::PushStyleColor(ImGuiCol_Text, 0xFF0077FF); + break; + case _stack_op_type::irq: + ImGui::PushStyleColor(ImGuiCol_TextDisabled, 0xFF007788); + ImGui::PushStyleColor(ImGuiCol_Text, 0xFF00FFFF); + break; + case _stack_op_type::smart: + ImGui::PushStyleColor(ImGuiCol_TextDisabled, 0xFF883300); + ImGui::PushStyleColor(ImGuiCol_Text, 0xFFFFFF00); + break; + case _stack_op_type::jsr: + ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled)); + ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + break; + default: + break; + } } ImGui::PushID(i); do_label(stack6502[i].dest_pc, stack6502[i].dest_bank, true); @@ -262,13 +282,37 @@ static void draw_debugger_cpu_status() case _stack_op_type::irq: ImGui::Text("%s", "IRQ"); break; - case _stack_op_type::op: + case _stack_op_type::jsr: ImGui::Text("%s", mnemonics[stack6502[i].opcode]); break; default: break; } + if (i >= state6502.sp_depth) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::TextDisabled("%s", "Pop Address:"); + ImGui::TableSetColumnIndex(1); + do_label(stack6502[i].pop_pc, stack6502[i].pop_bank, false); + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::TextDisabled("%s", "Pop Cause:"); + ImGui::TableSetColumnIndex(1); + switch (stack6502[i].pop_type) { + case _stack_pop_type::rti: + ImGui::Text("%s", "rti"); + break; + case _stack_pop_type::rts: + ImGui::Text("%s", "rts"); + break; + case _stack_pop_type::unknown: + ImGui::Text("%s", "(unknown)"); + break; + } + } + ImGui::EndTable(); } From 71672dafac912f635029e6685f77e3ec9831f98b Mon Sep 17 00:00:00 2001 From: indigodarkwolf Date: Mon, 4 Dec 2023 21:39:25 -0600 Subject: [PATCH 10/13] Smart stack will no longer cause a debug break on a detected stack underflow. --- src/cpu/fake6502.cpp | 4 ++-- src/main.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cpu/fake6502.cpp b/src/cpu/fake6502.cpp index 5f8f1eb..5c689c4 100644 --- a/src/cpu/fake6502.cpp +++ b/src/cpu/fake6502.cpp @@ -205,7 +205,7 @@ void exec6502(uint32_t tickcount) (*addrtable[opcode])(); (*optable[opcode])(); - if ((debug6502 & (DEBUG6502_READ | DEBUG6502_WRITE)) || stack6502_underflow) { + if (debug6502 & (DEBUG6502_READ | DEBUG6502_WRITE)) { state6502 = debug_state6502; clockticks6502 = debug_clockticks6502; return; @@ -247,7 +247,7 @@ void step6502() (*addrtable[opcode])(); (*optable[opcode])(); - if ((debug6502 & (DEBUG6502_READ | DEBUG6502_WRITE)) || stack6502_underflow) { + if (debug6502 & (DEBUG6502_READ | DEBUG6502_WRITE)) { state6502 = debug_state6502; clockticks6502 = debug_clockticks6502; return; diff --git a/src/main.cpp b/src/main.cpp index 8cc6c01..fd35899 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -418,7 +418,7 @@ void emulator_loop() uint64_t old_clockticks6502 = clockticks6502; step6502(); - if (debug6502 || stack6502_underflow) { + if (debug6502) { debugger_process_cpu(); if (debugger_is_paused()) { continue; From 5f7df96ab042864093c975ed3fdcbec1bc19f178 Mon Sep 17 00:00:00 2001 From: indigodarkwolf Date: Mon, 4 Dec 2023 23:14:44 -0600 Subject: [PATCH 11/13] More smart stack: Showing additional byte pushes within a stack frame. --- src/cpu/fake6502.cpp | 2 + src/cpu/fake6502.h | 6 +- src/cpu/instructions_6502.h | 58 ++++++++++-------- src/cpu/instructions_65c02.h | 6 ++ src/overlay/overlay.cpp | 112 +++++++++++++++++++++++++++++++---- 5 files changed, 147 insertions(+), 37 deletions(-) diff --git a/src/cpu/fake6502.cpp b/src/cpu/fake6502.cpp index 5c689c4..6f9f455 100644 --- a/src/cpu/fake6502.cpp +++ b/src/cpu/fake6502.cpp @@ -133,6 +133,7 @@ void nmi6502() ss.source_pc = state6502.pc; ss.source_bank = bank6502(state6502.pc); ss.push_depth = 0; + ss.push_unwind_depth = 0; state6502.sp_unwind_depth = state6502.sp_depth; push16(state6502.pc); @@ -157,6 +158,7 @@ void irq6502() ss.source_pc = state6502.pc; ss.source_bank = bank6502(state6502.pc); ss.push_depth = 0; + ss.push_unwind_depth = 0; state6502.sp_unwind_depth = state6502.sp_depth; push16(state6502.pc); diff --git a/src/cpu/fake6502.h b/src/cpu/fake6502.h index 259483f..659e170 100644 --- a/src/cpu/fake6502.h +++ b/src/cpu/fake6502.h @@ -36,13 +36,16 @@ enum class _push_op_type : uint8_t { a, x, y, - status + status, + smart, }; struct _smart_stack_ex { _push_op_type push_type; _push_op_type pull_type; uint8_t value; + uint16_t pc; + uint8_t bank; }; struct _smart_stack { @@ -56,6 +59,7 @@ struct _smart_stack { uint8_t pop_bank; uint8_t opcode; uint8_t push_depth; + uint8_t push_unwind_depth; _smart_stack_ex pushed_bytes[256]; }; diff --git a/src/cpu/instructions_6502.h b/src/cpu/instructions_6502.h index e1d0c94..75b2b9d 100644 --- a/src/cpu/instructions_6502.h +++ b/src/cpu/instructions_6502.h @@ -372,10 +372,11 @@ jmp() static void jsr() { - auto &ss = stack6502[state6502.sp_depth++]; - ss.source_pc = state6502.pc; - ss.source_bank = bank6502(state6502.pc); - ss.push_depth = 0; + auto &ss = stack6502[state6502.sp_depth++]; + ss.source_pc = state6502.pc; + ss.source_bank = bank6502(state6502.pc); + ss.push_depth = 0; + ss.push_unwind_depth = 0; state6502.sp_unwind_depth = state6502.sp_depth; push16(state6502.pc - 1); @@ -469,30 +470,39 @@ static void pha() { push8(state6502.a); - auto &ss = stack6502[(state6502.sp_depth + 255) & 0xff]; - auto &ssx = ss.pushed_bytes[ss.push_depth++]; - ssx.push_type = _push_op_type::a; - ssx.pull_type = _push_op_type::unknown; - ssx.value = state6502.a; + auto &ss = stack6502[(state6502.sp_depth + 255) & 0xff]; + auto &ssx = ss.pushed_bytes[ss.push_depth++]; + ssx.push_type = _push_op_type::a; + ssx.pull_type = _push_op_type::unknown; + ssx.value = state6502.a; + ssx.pc = state6502.pc - 1; + ssx.bank = bank6502(state6502.pc - 1); + ss.push_unwind_depth = ss.push_depth; } static void php() { push8(state6502.status | FLAG_BREAK); - auto &ss = stack6502[(state6502.sp_depth + 255) & 0xff]; - auto &ssx = ss.pushed_bytes[ss.push_depth++]; - ssx.push_type = _push_op_type::status; - ssx.pull_type = _push_op_type::unknown; - ssx.value = state6502.status | FLAG_BREAK; + auto &ss = stack6502[(state6502.sp_depth + 255) & 0xff]; + auto &ssx = ss.pushed_bytes[ss.push_depth++]; + ssx.push_type = _push_op_type::status; + ssx.pull_type = _push_op_type::unknown; + ssx.value = state6502.status | FLAG_BREAK; + ssx.pc = state6502.pc - 1; + ssx.bank = bank6502(state6502.pc - 1); + ss.push_unwind_depth = ss.push_depth; if (ss.op_type != _stack_op_type::jsr && ss.push_depth == 5) { ss.push_depth -= 3; - - auto &ss2 = stack6502[state6502.sp_depth++]; - ss2.source_pc = (static_cast(ss.pushed_bytes[ss.push_depth].value) << 8) | static_cast(ss.pushed_bytes[ss.push_depth+1].value); - ss2.source_bank = bank6502(state6502.pc); - ss2.push_depth = 0; + for (int i = 0; i < 3; ++i) { + ss.pushed_bytes[ss.push_depth + i].pull_type = _push_op_type::smart; + } + auto &ss2 = stack6502[state6502.sp_depth++]; + ss2.source_pc = (static_cast(ss.pushed_bytes[ss.push_depth].value) << 8) | static_cast(ss.pushed_bytes[ss.push_depth + 1].value); + ss2.source_bank = bank6502(state6502.pc); + ss2.push_depth = 0; + ss2.push_unwind_depth = 0; state6502.sp_unwind_depth = state6502.sp_depth; ss2.dest_pc = state6502.pc; @@ -561,13 +571,13 @@ static void rti() { const uint16_t old_pc = state6502.pc; - state6502.status = pull8(); - value = pull16(); - state6502.pc = value; + state6502.status = pull8(); + value = pull16(); + state6502.pc = value; stack6502_underflow |= !state6502.sp_depth; state6502.sp_depth -= !!state6502.sp_depth; - auto &ss = stack6502[state6502.sp_depth]; + auto &ss = stack6502[state6502.sp_depth]; ss.pop_type = _stack_pop_type::rti; ss.pop_pc = old_pc - 1; ss.pop_bank = bank6502(old_pc); @@ -578,7 +588,7 @@ rts() { const uint16_t old_pc = state6502.pc; - value = pull16(); + value = pull16(); state6502.pc = value + 1; stack6502_underflow |= !state6502.sp_depth; state6502.sp_depth -= !!state6502.sp_depth; diff --git a/src/cpu/instructions_65c02.h b/src/cpu/instructions_65c02.h index 26642eb..d7ed194 100644 --- a/src/cpu/instructions_65c02.h +++ b/src/cpu/instructions_65c02.h @@ -89,6 +89,9 @@ phx() ssx.push_type = _push_op_type::x; ssx.pull_type = _push_op_type::unknown; ssx.value = state6502.x; + ssx.pc = state6502.pc - 1; + ssx.bank = bank6502(state6502.pc - 1); + ss.push_unwind_depth = ss.push_depth; } static void @@ -114,6 +117,9 @@ phy() ssx.push_type = _push_op_type::y; ssx.pull_type = _push_op_type::unknown; ssx.value = state6502.y; + ssx.pc = state6502.pc - 1; + ssx.bank = bank6502(state6502.pc - 1); + ss.push_unwind_depth = ss.push_depth; } static void diff --git a/src/overlay/overlay.cpp b/src/overlay/overlay.cpp index 6d3ac3b..ce2b75a 100644 --- a/src/overlay/overlay.cpp +++ b/src/overlay/overlay.cpp @@ -171,10 +171,15 @@ static void draw_debugger_cpu_status() ImGui::TableNextColumn(); - if (ImGui::BeginTable("smart stack", 1, ImGuiTableFlags_ScrollY)) { + if (ImGui::BeginTable("smart stack", 2, ImGuiTableFlags_ScrollY)) { + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 10); + ImGui::TableSetupColumn("Address"); + + ImGui::TableHeadersRow(); + if (stack6502_underflow) { ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); + ImGui::TableSetColumnIndex(1); ImGui::TextDisabled("%s", "(Underflow)"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); @@ -184,7 +189,14 @@ static void draw_debugger_cpu_status() ImGui::TableNextRow(); } for (uint16_t i = state6502.sp_unwind_depth - 1; i < state6502.sp_unwind_depth; --i) { - ImGui::TableNextColumn(); + const auto &ss = stack6502[i]; + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + if (i == state6502.sp_depth - 1) { + ImGui::Text("%s", ">"); + } + ImGui::TableSetColumnIndex(1); auto do_label = [](uint16_t pc, uint8_t bank, bool allow_disabled) { char const *label = disasm_get_label(pc); bool pushed = false; @@ -224,11 +236,11 @@ static void draw_debugger_cpu_status() } } }; - if (i > state6502.sp_depth) { + if (i >= state6502.sp_depth) { ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled)); ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled)); } else { - switch (stack6502[i].op_type) { + switch (ss.op_type) { case _stack_op_type::nmi: ImGui::PushStyleColor(ImGuiCol_TextDisabled, 0xFF003388); ImGui::PushStyleColor(ImGuiCol_Text, 0xFF0077FF); @@ -250,7 +262,7 @@ static void draw_debugger_cpu_status() } } ImGui::PushID(i); - do_label(stack6502[i].dest_pc, stack6502[i].dest_bank, true); + do_label(ss.dest_pc, ss.dest_bank, true); ImGui::PopID(); ImGui::PopStyleColor(2); @@ -262,20 +274,20 @@ static void draw_debugger_cpu_status() ImGui::TableSetColumnIndex(0); ImGui::TextDisabled("%s", "Source address:"); ImGui::TableSetColumnIndex(1); - do_label(stack6502[i].source_pc, stack6502[i].source_bank, false); + do_label(ss.source_pc, ss.source_bank, false); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImGui::TextDisabled("%s", "Destination address:"); ImGui::TableSetColumnIndex(1); - do_label(stack6502[i].dest_pc, stack6502[i].dest_bank, false); + do_label(ss.dest_pc, ss.dest_bank, false); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImGui::TextDisabled("%s", "Cause:"); ImGui::TableSetColumnIndex(1); - switch (stack6502[i].op_type) { + switch (ss.op_type) { case _stack_op_type::nmi: ImGui::Text("%s", "NMI"); break; @@ -283,7 +295,10 @@ static void draw_debugger_cpu_status() ImGui::Text("%s", "IRQ"); break; case _stack_op_type::jsr: - ImGui::Text("%s", mnemonics[stack6502[i].opcode]); + ImGui::Text("%s", mnemonics[ss.opcode]); + break; + case _stack_op_type::smart: + ImGui::Text("%s", "smart"); break; default: break; @@ -294,13 +309,13 @@ static void draw_debugger_cpu_status() ImGui::TableSetColumnIndex(0); ImGui::TextDisabled("%s", "Pop Address:"); ImGui::TableSetColumnIndex(1); - do_label(stack6502[i].pop_pc, stack6502[i].pop_bank, false); + do_label(ss.pop_pc, ss.pop_bank, false); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImGui::TextDisabled("%s", "Pop Cause:"); ImGui::TableSetColumnIndex(1); - switch (stack6502[i].pop_type) { + switch (ss.pop_type) { case _stack_pop_type::rti: ImGui::Text("%s", "rti"); break; @@ -316,6 +331,79 @@ static void draw_debugger_cpu_status() ImGui::EndTable(); } + if (ss.push_unwind_depth > 0) { + ImGui::TextDisabled("%s", "Additional byte pushes in this frame:"); + if (ImGui::BeginTable("additional pushes table", 5, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX)) { + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 10); + ImGui::TableSetupColumn("Address"); + ImGui::TableSetupColumn("Push Op"); + ImGui::TableSetupColumn("Value"); + ImGui::TableSetupColumn("Pull Op"); + ImGui::TableHeadersRow(); + + for (uint16_t j = ss.push_unwind_depth - 1; j < ss.push_unwind_depth; --j) { + const auto &ssx = ss.pushed_bytes[j]; + ImGui::TableNextRow(); + + ImGui::TableSetColumnIndex(0); + ImGui::Text("%s", (j == ss.push_depth - 1) ? ">" : " "); + + ImGui::TableSetColumnIndex(1); + do_label(ssx.pc, ssx.bank, false); + + ImGui::TableSetColumnIndex(2); + switch (ssx.push_type) { + case _push_op_type::a: + ImGui::Text("%s", "pha"); + break; + case _push_op_type::x: + ImGui::Text("%s", "phx"); + break; + case _push_op_type::y: + ImGui::Text("%s", "phy"); + break; + case _push_op_type::status: + ImGui::Text("%s", "php"); + break; + case _push_op_type::unknown: + ImGui::Text("%s", "(?)"); + break; + case _push_op_type::smart: + ImGui::Text("%s", "smart"); + break; + } + + ImGui::TableSetColumnIndex(3); + ImGui::Text("$%02x", ssx.value); + + if (j >= ss.push_depth) { + ImGui::TableSetColumnIndex(4); + switch (ssx.pull_type) { + case _push_op_type::a: + ImGui::Text("%s", "pla"); + break; + case _push_op_type::x: + ImGui::Text("%s", "plx"); + break; + case _push_op_type::y: + ImGui::Text("%s", "ply"); + break; + case _push_op_type::status: + ImGui::Text("%s", "plp"); + break; + case _push_op_type::unknown: + ImGui::Text("%s", "(?)"); + break; + case _push_op_type::smart: + ImGui::Text("%s", "smart"); + break; + } + } + } + ImGui::EndTable(); + } + } + ImGui::EndTooltip(); } } From 5d84aee43df49d59d2da22d2f7c3c3c8edddc8c3 Mon Sep 17 00:00:00 2001 From: indigodarkwolf Date: Thu, 28 Dec 2023 16:08:30 -0600 Subject: [PATCH 12/13] Small fix to vsync, which wasn't fully disabling with `-vsync none` --- src/display.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/display.cpp b/src/display.cpp index da9e5ab..40be8d7 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -80,12 +80,12 @@ static float Max_anisotropy = 1.0f; static bool vsync_is_enabled() { - return static_cast(Options.vsync_mode) > static_cast(vsync_mode_t::VSYNC_MODE_DISABLED); + return static_cast(Options.vsync_mode) > static_cast(vsync_mode_t::VSYNC_MODE_NONE); } static bool vsync_is_disabled() { - return static_cast(Options.vsync_mode) < static_cast(vsync_mode_t::VSYNC_MODE_DISABLED); + return static_cast(Options.vsync_mode) < static_cast(vsync_mode_t::VSYNC_MODE_NONE); } bool icon_set::load_file(const char *filename, int icon_width, int icon_height) From 4d2cc3649c060f1d4a8bc39b300d92f6668bdb71 Mon Sep 17 00:00:00 2001 From: indigodarkwolf Date: Thu, 28 Dec 2023 18:09:05 -0600 Subject: [PATCH 13/13] Fixing some unsafe snprintf usage. --- src/ieee.cpp | 3 +-- src/overlay/overlay.cpp | 4 ++++ src/overlay/psg_overlay.cpp | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ieee.cpp b/src/ieee.cpp index 1f867ef..670b248 100644 --- a/src/ieee.cpp +++ b/src/ieee.cpp @@ -678,8 +678,7 @@ static void set_activity(bool active) static void set_error(int e, int t, int s) { - snprintf(error, sizeof(error), "%02x,%s,%02d,%02d\r", e, error_string(e), t, s); - error_len = static_cast(strlen(error)); + error_len = snprintf(error, sizeof(error), "%02x,%s,%02d,%02d\r", e, error_string(e), t, s); error_pos = 0; uint8_t cbdos_flags = get_kernal_cbdos_flags(); if (e < 0x10 || e == 0x73) { diff --git a/src/overlay/overlay.cpp b/src/overlay/overlay.cpp index ce2b75a..2b32d09 100644 --- a/src/overlay/overlay.cpp +++ b/src/overlay/overlay.cpp @@ -206,11 +206,13 @@ static void draw_debugger_cpu_status() ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled)); char stack_line[256]; snprintf(stack_line, sizeof(stack_line), "$%02X:$%04X", bank, pc); + stack_line[255] = '\0'; pushed = ImGui::Selectable(stack_line, false, 0, ImGui::CalcTextSize(stack_line)); ImGui::PopStyleColor(); } else { char stack_line[256]; snprintf(stack_line, sizeof(stack_line), "$%02X:$%04X: %s", bank, pc, label); + stack_line[255] = '\0'; pushed = ImGui::Selectable(stack_line, false, 0, ImGui::CalcTextSize(stack_line)); } } else { @@ -218,11 +220,13 @@ static void draw_debugger_cpu_status() ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled)); char stack_line[256]; snprintf(stack_line, sizeof(stack_line), "$%04X", pc); + stack_line[255] = '\0'; pushed = ImGui::Selectable(stack_line, false, 0, ImGui::CalcTextSize(stack_line)); ImGui::PopStyleColor(); } else { char stack_line[256]; snprintf(stack_line, sizeof(stack_line), "$%04X: %s", pc, label); + stack_line[255] = '\0'; pushed = ImGui::Selectable(stack_line, false, 0, ImGui::CalcTextSize(stack_line)); } } diff --git a/src/overlay/psg_overlay.cpp b/src/overlay/psg_overlay.cpp index a07364b..b0369eb 100644 --- a/src/overlay/psg_overlay.cpp +++ b/src/overlay/psg_overlay.cpp @@ -314,6 +314,7 @@ void draw_debugger_vera_psg() char rate_txt[15]; float rate_hz = rate <= 128 ? (float)SAMPLERATE * rate / 128 : 0; snprintf(rate_txt, 15, "%d (%.0f Hz)", rate, rate_hz); + rate_txt[14] = '\0'; ImGui::SetNextItemWidth(avail / 2 - 48); if (ImGui::SliderInt("Rate", &rate_i, 0, 128, rate_txt, ImGuiSliderFlags_AlwaysClamp)) { pcm_write_rate(rate_i);