// license:BSD-3-Clause // copyright-holders:Ryan Holtz #include "emu.h" #include "debugger.h" #include "superfx.h" DEFINE_DEVICE_TYPE(SUPERFX, superfx_device, "superfx", "Nintendo SuperFX") superfx_device::superfx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : cpu_device(mconfig, SUPERFX, tag, owner, clock) , m_program_config("program", ENDIANNESS_LITTLE, 8, 32, 0) , m_out_irq_func(*this), m_pipeline(0), m_ramaddr(0), m_sfr(0), m_pbr(0), m_rombr(0), m_rambr(0), m_cbr(0), m_scbr(0), m_scmr(0), m_colr(0), m_por(0) , m_bramr(0), m_vcr(0), m_cfgr(0), m_clsr(0), m_romcl(0), m_romdr(0), m_ramcl(0), m_ramar(0), m_ramdr(0), m_sreg(nullptr), m_sreg_idx(0), m_dreg(nullptr) , m_dreg_idx(0), m_r15_modified(0), m_irq(0), m_cache_access_speed(0), m_memory_access_speed(0), m_program(nullptr), m_icount(0), m_debugger_temp(0) { } device_memory_interface::space_config_vector superfx_device::memory_space_config() const { return space_config_vector { std::make_pair(AS_PROGRAM, &m_program_config) }; } #define SUPERFX_SFR_OV_SET ((m_sfr & SUPERFX_SFR_OV) ? 1 : 0) #define SUPERFX_SFR_OV_CLEAR ((m_sfr & SUPERFX_SFR_OV) ? 0 : 1) #define SUPERFX_SFR_S_SET ((m_sfr & SUPERFX_SFR_S) ? 1 : 0) #define SUPERFX_SFR_S_CLEAR ((m_sfr & SUPERFX_SFR_S) ? 0 : 1) #define SUPERFX_SFR_CY_SET ((m_sfr & SUPERFX_SFR_CY) ? 1 : 0) #define SUPERFX_SFR_CY_CLEAR ((m_sfr & SUPERFX_SFR_CY) ? 0 : 1) #define SUPERFX_SFR_Z_SET ((m_sfr & SUPERFX_SFR_Z) ? 1 : 0) #define SUPERFX_SFR_Z_CLEAR ((m_sfr & SUPERFX_SFR_Z) ? 0 : 1) void superfx_device::superfx_regs_reset() { m_sfr &= ~(SUPERFX_SFR_B | SUPERFX_SFR_ALT3); m_sreg = &m_r[0]; m_dreg = &m_r[0]; m_dreg_idx = 0; m_sreg_idx = 0; } void superfx_device::superfx_update_speed() { m_cache_access_speed = (m_clsr ? 1 : 2); m_memory_access_speed = (m_clsr ? 5 : 6); if(m_clsr) { m_cfgr &= ~SUPERFX_CFGR_MS0; // Cannot use high-speed multiplication in 21MHz mode } } void superfx_device::superfx_cache_flush() { uint32_t n = 0; for(n = 0; n < 32; n++) { m_cache.valid[n] = 0; } } uint8_t superfx_device::superfx_cache_mmio_read(uint32_t addr) { addr = (addr + m_cbr) & 0x1ff; return m_cache.buffer[addr]; } void superfx_device::superfx_cache_mmio_write(uint32_t addr, uint8_t data) { addr = (addr + m_cbr) & 0x1ff; m_cache.buffer[addr] = data; if((addr & 15) == 15) { m_cache.valid[addr >> 4] = 1; } } void superfx_device::superfx_memory_reset() { uint32_t n = 0; for(n = 0; n < 0x200; n++) { m_cache.buffer[n] = 0x00; } for(n = 0; n < 0x20; n++) { m_cache.valid[n] = 0; } for(n = 0; n < 2; n++) { m_pixelcache[n].offset = ~0; m_pixelcache[n].bitpend = 0x00; } } uint8_t superfx_device::superfx_bus_read(uint32_t addr) { return m_program->read_byte(addr); } void superfx_device::superfx_bus_write(uint32_t addr, uint8_t data) { m_program->write_byte(addr, data); } void superfx_device::superfx_pixelcache_flush(int32_t line) { uint8_t x = m_pixelcache[line].offset << 3; uint8_t y = m_pixelcache[line].offset >> 5; uint32_t cn = 0; uint32_t bpp = 2 << ((m_scmr & SUPERFX_SCMR_MD) - ((m_scmr & SUPERFX_SCMR_MD) >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 }; uint32_t addr; uint32_t n = 0; if(m_pixelcache[line].bitpend == 0x00) { return; } switch(((m_por & SUPERFX_POR_OBJ) ? SUPERFX_SCMR_HT3 : (m_scmr & SUPERFX_SCMR_HT_MASK))) { case SUPERFX_SCMR_HT0: cn = ((x & 0xf8) << 1) + ((y & 0xf8) >> 3); break; case SUPERFX_SCMR_HT1: cn = ((x & 0xf8) << 1) + ((x & 0xf8) >> 1) + ((y & 0xf8) >> 3); break; case SUPERFX_SCMR_HT2: cn = ((x & 0xf8) << 1) + ((x & 0xf8) << 0) + ((y & 0xf8) >> 3); break; case SUPERFX_SCMR_HT3: cn = ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); break; } addr = 0x700000 + (cn * (bpp << 3)) + (m_scbr << 10) + ((y & 0x07) * 2); for(n = 0; n < bpp; n++) { uint32_t byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 }; uint8_t data = 0x00; uint32_t x32 = 0; for(x32 = 0; x32 < 8; x32++) { data |= ((m_pixelcache[line].data[x32] >> n) & 1) << x32; } if(m_pixelcache[line].bitpend != 0xff) { superfx_add_clocks_internal(m_memory_access_speed); data &= m_pixelcache[line].bitpend; data |= superfx_bus_read(addr + byte) & ~m_pixelcache[line].bitpend; } superfx_add_clocks_internal(m_memory_access_speed); superfx_bus_write(addr + byte, data); } m_pixelcache[line].bitpend = 0x00; } void superfx_device::superfx_plot(uint8_t x, uint8_t y) { uint8_t color = m_colr; uint16_t offset = (y << 5) + (x >> 3); if((m_por & SUPERFX_POR_DITHER) != 0 && (m_scmr & SUPERFX_SCMR_MD) != 3) { if((x ^ y) & 1) { color >>= 4; } color &= 0x0f; } if((m_por & SUPERFX_POR_TRANSPARENT) == 0) { if((m_scmr & SUPERFX_SCMR_MD) == 3) { if(m_por & SUPERFX_POR_FREEZEHIGH) { if((color & 0x0f) == 0) { return; } } else { if(color == 0) { return; } } } else { if((color & 0x0f) == 0) { return; } } } if(offset != m_pixelcache[0].offset) { superfx_pixelcache_flush(1); m_pixelcache[1] = m_pixelcache[0]; m_pixelcache[0].bitpend = 0x00; m_pixelcache[0].offset = offset; } x = (x & 7) ^ 7; m_pixelcache[0].data[x] = color; m_pixelcache[0].bitpend |= 1 << x; if(m_pixelcache[0].bitpend == 0xff) { superfx_pixelcache_flush(1); m_pixelcache[1] = m_pixelcache[0]; m_pixelcache[0].bitpend = 0x00; } } uint8_t superfx_device::superfx_rpix(uint8_t x, uint8_t y) { uint32_t cn = 0; uint32_t bpp; uint32_t addr; uint8_t data = 0x00; uint32_t n = 0; superfx_pixelcache_flush(1); superfx_pixelcache_flush(0); bpp = 2 << ((m_scmr & SUPERFX_SCMR_MD) - ((m_scmr & SUPERFX_SCMR_MD) >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 }; switch((m_por & SUPERFX_POR_OBJ) ? SUPERFX_SCMR_HT3 : (m_scmr & SUPERFX_SCMR_HT_MASK)) { case SUPERFX_SCMR_HT0: cn = ((x & 0xf8) << 1) + ((y & 0xf8) >> 3); break; case SUPERFX_SCMR_HT1: cn = ((x & 0xf8) << 1) + ((x & 0xf8) >> 1) + ((y & 0xf8) >> 3); break; case SUPERFX_SCMR_HT2: cn = ((x & 0xf8) << 1) + ((x & 0xf8) << 0) + ((y & 0xf8) >> 3); break; case SUPERFX_SCMR_HT3: cn = ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); break; } addr = 0x700000 + (cn * (bpp << 3)) + (m_scbr << 10) + ((y & 0x07) * 2); x = (x & 7) ^ 7; for(n = 0; n < bpp; n++) { uint32_t byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 }; superfx_add_clocks_internal(m_memory_access_speed); data |= ((superfx_bus_read(addr + byte) >> x) & 1) << n; } return data; } uint8_t superfx_device::superfx_color(uint8_t source) { if(m_por & SUPERFX_POR_HIGHNIBBLE) { return (m_colr & 0xf0) | (source >> 4); } if(m_por & SUPERFX_POR_FREEZEHIGH) { return (m_colr & 0xf0) | (source & 0x0f); } return source; } void superfx_device::superfx_rambuffer_sync() { if(m_ramcl) { superfx_add_clocks_internal(m_ramcl); } } uint8_t superfx_device::superfx_rambuffer_read(uint16_t addr) { superfx_rambuffer_sync(); return superfx_bus_read(0x700000 + (m_rambr << 16) + addr); } void superfx_device::superfx_rambuffer_write(uint16_t addr, uint8_t data) { superfx_rambuffer_sync(); m_ramcl = m_memory_access_speed; m_ramar = addr; m_ramdr = data; } void superfx_device::superfx_rombuffer_sync() { if(m_romcl) { superfx_add_clocks_internal(m_romcl); } } void superfx_device::superfx_rombuffer_update() { m_sfr |= SUPERFX_SFR_R; m_romcl = m_memory_access_speed; } uint8_t superfx_device::superfx_rombuffer_read() { superfx_rombuffer_sync(); return m_romdr; } void superfx_device::superfx_gpr_write(uint8_t r, uint16_t data) { m_r[r] = data; if(r == 14) { superfx_rombuffer_update(); } else if(r == 15) { m_r15_modified = 1; } } uint8_t superfx_device::superfx_op_read(uint16_t addr) { uint16_t offset = addr - m_cbr; if(offset < 512) { if(!m_cache.valid[offset >> 4]) { uint32_t dp = offset & 0xfff0; uint32_t sp = (m_pbr << 16) + ((m_cbr + dp) & 0xfff0); uint32_t n = 0; for(n = 0; n < 16; n++) { superfx_add_clocks_internal(m_memory_access_speed); m_cache.buffer[dp++] = superfx_bus_read(sp++); } m_cache.valid[offset >> 4] = 1; } else { superfx_add_clocks_internal(m_memory_access_speed); } return m_cache.buffer[offset]; } if(m_pbr <= 0x5f) { //$[00-5f]:[0000-ffff] ROM superfx_rombuffer_sync(); superfx_add_clocks_internal(m_memory_access_speed); return superfx_bus_read((m_pbr << 16) + addr); } else { //$[60-7f]:[0000-ffff] RAM superfx_rambuffer_sync(); superfx_add_clocks_internal(m_memory_access_speed); return superfx_bus_read((m_pbr << 16) + addr); } } uint8_t superfx_device::superfx_peekpipe() { uint8_t result = m_pipeline; m_pipeline = superfx_op_read(m_r[15]); m_r15_modified = 0; return result; } uint8_t superfx_device::superfx_pipe() { uint8_t result = m_pipeline; m_pipeline = superfx_op_read(++m_r[15]); m_r15_modified = 0; return result; } /*****************************************************************************/ /* reads to SuperFX RAM only happen if this returns 1 */ int superfx_device::access_ram() { if ((m_sfr & SUPERFX_SFR_G) && (m_scmr & SUPERFX_SCMR_RAN)) return 0; return 1; } /* reads to SuperFX ROM only happen if this returns 1 */ int superfx_device::access_rom() { if ((m_sfr & SUPERFX_SFR_G) && (m_scmr & SUPERFX_SCMR_RON)) return 0; return 1; } uint8_t superfx_device::mmio_read(uint32_t addr) { addr &= 0xffff; if(addr >= 0x3100 && addr <= 0x32ff) { return superfx_cache_mmio_read(addr - 0x3100); } if(addr >= 0x3000 && addr <= 0x301f) { return m_r[(addr >> 1) & 0xf] >> ((addr & 1) << 3); } switch(addr) { case 0x3030: return m_sfr >> 0; case 0x3031: { uint8_t r = m_sfr >> 8; m_sfr &= ~SUPERFX_SFR_IRQ; m_irq = 0; m_out_irq_func(m_irq); return r; } case 0x3034: return m_pbr; case 0x3036: return m_rombr; case 0x303b: return m_vcr; case 0x303c: return m_rambr; case 0x303e: return m_cbr >> 0; case 0x303f: return m_cbr >> 8; } return 0; } void superfx_device::mmio_write(uint32_t addr, uint8_t data) { addr &= 0xffff; //printf( "superfx_mmio_write: %08x = %02x\n", addr, data ); if(addr >= 0x3100 && addr <= 0x32ff) { superfx_cache_mmio_write(addr - 0x3100, data); return; } if(addr >= 0x3000 && addr <= 0x301f) { uint32_t n = (addr >> 1) & 0xf; if((addr & 1) == 0) { m_r[n] = (m_r[n] & 0xff00) | data; } else { m_r[n] = (data << 8) | (m_r[n] & 0xff); } if(addr == 0x301f) { m_sfr |= SUPERFX_SFR_G; } return; } switch(addr) { case 0x3030: { uint8_t g = (m_sfr & SUPERFX_SFR_G) ? 1 : 0; m_sfr = (m_sfr & 0xff00) | (data << 0); if(g == 1 && !(m_sfr & SUPERFX_SFR_G)) { m_cbr = 0x0000; superfx_cache_flush(); } break; } case 0x3031: m_sfr = (data << 8) | (m_sfr & 0x00ff); break; case 0x3033: m_bramr = data & 1; break; case 0x3034: m_pbr = data & 0x7f; superfx_cache_flush(); break; case 0x3037: m_cfgr = data; superfx_update_speed(); break; case 0x3038: m_scbr = data; break; case 0x3039: m_clsr = data & 1; superfx_update_speed(); break; case 0x303a: m_scmr = data; break; } } void superfx_device::superfx_add_clocks_internal(uint32_t clocks) { if(m_romcl) { m_romcl -= std::min(clocks, m_romcl); if(m_romcl == 0) { m_sfr &= ~SUPERFX_SFR_R; m_romdr = superfx_bus_read((m_rombr << 16) + m_r[14]); } } if(m_ramcl) { m_ramcl -= std::min(clocks, m_ramcl); if(m_ramcl == 0) { superfx_bus_write(0x700000 + (m_rambr << 16) + m_ramar, m_ramdr); } } } void superfx_device::superfx_timing_reset() { superfx_update_speed(); m_r15_modified = 0; m_romcl = 0; m_romdr = 0; m_ramcl = 0; m_ramar = 0; m_ramdr = 0; } void superfx_device::add_clocks(int32_t clocks) { superfx_add_clocks_internal(clocks); } /*****************************************************************************/ void superfx_device::device_start() { for(auto & elem : m_r) { elem = 0; } m_sfr = 0; m_pbr = 0; m_rombr = 0; m_rambr = 0; m_cbr = 0; m_scbr = 0; m_scmr = 0; m_colr = 0; m_por = 0; m_bramr = 0; m_vcr = 0x04; m_cfgr = 0; m_clsr = 0; m_pipeline = 0x01; // nop m_ramaddr = 0; m_r15_modified = 0; m_irq = 0; m_cache_access_speed = 0; m_memory_access_speed = 0; m_debugger_temp = 0; m_romcl = 0; m_romdr = 0; m_ramcl = 0; m_ramar = 0; m_ramdr = 0; superfx_regs_reset(); superfx_memory_reset(); superfx_update_speed(); m_program = &space(AS_PROGRAM); m_out_irq_func.resolve(); save_item(NAME(m_pipeline)); save_item(NAME(m_ramaddr)); save_item(NAME(m_r)); save_item(NAME(m_sfr)); save_item(NAME(m_pbr)); save_item(NAME(m_rombr)); save_item(NAME(m_rambr)); save_item(NAME(m_cbr)); save_item(NAME(m_scbr)); save_item(NAME(m_scmr)); save_item(NAME(m_colr)); save_item(NAME(m_por)); save_item(NAME(m_bramr)); save_item(NAME(m_vcr)); save_item(NAME(m_cfgr)); save_item(NAME(m_clsr)); save_item(NAME(m_romcl)); save_item(NAME(m_romdr)); save_item(NAME(m_ramcl)); save_item(NAME(m_ramar)); save_item(NAME(m_ramdr)); save_item(NAME(m_sreg_idx)); save_item(NAME(m_dreg_idx)); save_item(NAME(m_r15_modified)); save_item(NAME(m_irq)); save_item(NAME(m_cache_access_speed)); save_item(NAME(m_memory_access_speed)); save_item(NAME(m_cache.buffer)); save_item(NAME(m_cache.valid)); for (int i = 0; i < 2; i++) { save_item(NAME(m_pixelcache[i].offset), i); save_item(NAME(m_pixelcache[i].bitpend), i); save_item(NAME(m_pixelcache[i].data), i); } state_add( SUPERFX_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%06X"); state_add( SUPERFX_DREG, "DREG", m_dreg_idx).mask(0xf).formatstr("%02u"); state_add( SUPERFX_SREG, "SREG", m_sreg_idx).mask(0xf).formatstr("%02u"); state_add( SUPERFX_R0, "R0", m_r[0]).formatstr("%04X"); state_add( SUPERFX_R1, "R1", m_r[1]).formatstr("%04X"); state_add( SUPERFX_R2, "R2", m_r[2]).formatstr("%04X"); state_add( SUPERFX_R3, "R3", m_r[3]).formatstr("%04X"); state_add( SUPERFX_R4, "R4", m_r[4]).formatstr("%04X"); state_add( SUPERFX_R5, "R5", m_r[5]).formatstr("%04X"); state_add( SUPERFX_R6, "R6", m_r[6]).formatstr("%04X"); state_add( SUPERFX_R7, "R7", m_r[7]).formatstr("%04X"); state_add( SUPERFX_R8, "R8", m_r[8]).formatstr("%04X"); state_add( SUPERFX_R9, "R9", m_r[9]).formatstr("%04X"); state_add( SUPERFX_R10, "R10", m_r[10]).formatstr("%04X"); state_add( SUPERFX_R11, "R11", m_r[11]).formatstr("%04X"); state_add( SUPERFX_R12, "R12", m_r[12]).formatstr("%04X"); state_add( SUPERFX_R13, "R13", m_r[13]).formatstr("%04X"); state_add( SUPERFX_R14, "R14", m_r[14]).formatstr("%04X"); state_add( SUPERFX_R15, "R15", m_r[15]).formatstr("%04X"); state_add( SUPERFX_SFR, "SFR", m_sfr).formatstr("%04X"); state_add( SUPERFX_PBR, "PBR", m_pbr).formatstr("%02X"); state_add( SUPERFX_ROMBR, "ROMBR", m_rombr).formatstr("%02X"); state_add( SUPERFX_RAMBR, "RAMBR", m_rambr).formatstr("%02X"); state_add( SUPERFX_CBR, "CBR", m_cbr).formatstr("%04X"); state_add( SUPERFX_SCBR, "SCBR", m_scbr).formatstr("%02X"); state_add( SUPERFX_SCMR, "SCMR", m_scmr).formatstr("%02X"); state_add( SUPERFX_COLR, "COLR", m_colr).formatstr("%02X"); state_add( SUPERFX_POR, "POR", m_por).formatstr("%02X"); state_add( SUPERFX_BRAMR, "BRAMR", m_bramr).formatstr("%02X"); state_add( SUPERFX_VCR, "VCR", m_vcr).formatstr("%02X"); state_add( SUPERFX_CFGR, "CFGR", m_cfgr).formatstr("%02X"); state_add( SUPERFX_CLSR, "CLSR", m_clsr).formatstr("%02X"); state_add( SUPERFX_ROMCL, "ROMCL", m_romcl).formatstr("%08X"); state_add( SUPERFX_ROMDR, "ROMDR", m_romdr).formatstr("%02X"); state_add( SUPERFX_RAMCL, "RAMCL", m_ramcl).formatstr("%08X"); state_add( SUPERFX_RAMAR, "RAMAR", m_ramar).formatstr("%04X"); state_add( SUPERFX_RAMDR, "RAMDR", m_ramdr).formatstr("%02X"); state_add( SUPERFX_RAMADDR, "RAMADDR", m_ramaddr).formatstr("%04X"); state_add( STATE_GENPC, "GENPC", m_debugger_temp).callexport().formatstr("%06X"); state_add( STATE_GENPCBASE, "CURPC", m_debugger_temp).callexport().formatstr("%06X"); m_icountptr = &m_icount; } void superfx_device::state_import(const device_state_entry &entry) { switch (entry.index()) { case SUPERFX_PC: m_r[15] = m_debugger_temp; break; } } void superfx_device::state_export(const device_state_entry &entry) { switch (entry.index()) { case STATE_GENPC: case STATE_GENPCBASE: case SUPERFX_PC: m_debugger_temp = ( (m_pbr << 16) | m_r[15] ) - 1; break; } } void superfx_device::device_reset() { int i; for(i = 0; i < 16; i++) { m_r[i] = 0; } m_sfr = 0; m_pbr = 0; m_rombr = 0; m_rambr = 0; m_cbr = 0; m_scbr = 0; m_scmr = 0; m_colr = 0; m_por = 0; m_bramr = 0; m_vcr = 0x04; m_cfgr = 0; m_clsr = 0; m_pipeline = 0x01; // nop m_ramaddr = 0; superfx_regs_reset(); superfx_timing_reset(); } void superfx_device::superfx_dreg_sfr_sz_update() { m_sfr &= ~(SUPERFX_SFR_S | SUPERFX_SFR_Z); m_sfr |= (*(m_dreg) & 0x8000) ? SUPERFX_SFR_S : 0; m_sfr |= (*(m_dreg) == 0) ? SUPERFX_SFR_Z : 0; } void superfx_device::execute_run() { uint8_t op; if(!(m_sfr & SUPERFX_SFR_G)) { superfx_add_clocks_internal(6); m_icount = std::min(m_icount, 0); } while (m_icount > 0 && (m_sfr & SUPERFX_SFR_G)) { if(!(m_sfr & SUPERFX_SFR_G)) { superfx_add_clocks_internal(6); m_icount = std::min(m_icount, 0); break; } debugger_instruction_hook(this, (m_pbr << 16) | m_r[15]); op = superfx_peekpipe(); switch(op) { case 0x00: // STOP if((m_cfgr & SUPERFX_CFGR_IRQ) == 0) { m_sfr |= SUPERFX_SFR_IRQ; m_irq = 1; m_out_irq_func(m_irq ? ASSERT_LINE : CLEAR_LINE ); } m_sfr &= ~SUPERFX_SFR_G; m_pipeline = 0x01; superfx_regs_reset(); break; case 0x01: // NOP superfx_regs_reset(); break; case 0x02: // CACHE if(m_cbr != (m_r[15] & 0xfff0)) { m_cbr = m_r[15] & 0xfff0; superfx_cache_flush(); } superfx_regs_reset(); break; case 0x03: // LSR m_sfr &= ~SUPERFX_SFR_CY; m_sfr |= (*(m_sreg) & 1) ? SUPERFX_SFR_CY : 0; superfx_gpr_write(m_dreg_idx, *(m_sreg) >> 1); superfx_dreg_sfr_sz_update(); superfx_regs_reset(); break; case 0x04: // ROL { uint16_t carry = *(m_sreg) & 0x8000; superfx_gpr_write(m_dreg_idx, (*(m_sreg) << 1) | SUPERFX_SFR_CY_SET); m_sfr &= ~SUPERFX_SFR_CY; m_sfr |= carry ? SUPERFX_SFR_CY : 0; superfx_dreg_sfr_sz_update(); superfx_regs_reset(); break; } case 0x05: // BRA { int32_t e = (int8_t)superfx_pipe(); superfx_gpr_write(15, m_r[15] + e); break; } case 0x06: // BLT { int32_t e = (int8_t)superfx_pipe(); if((SUPERFX_SFR_S_SET ^ SUPERFX_SFR_OV_SET) == 0) { superfx_gpr_write(15, m_r[15] + e); } break; } case 0x07: // BGE { int32_t e = (int8_t)superfx_pipe(); if((SUPERFX_SFR_S_SET ^ SUPERFX_SFR_OV_SET) == 1) { superfx_gpr_write(15, m_r[15] + e); } break; } case 0x08: // BNE { int32_t e = (int8_t)superfx_pipe(); if(SUPERFX_SFR_Z_SET == 0) { superfx_gpr_write(15, m_r[15] + e); } break; } case 0x09: // BEQ { int32_t e = (int8_t)superfx_pipe(); if(SUPERFX_SFR_Z_SET == 1) { superfx_gpr_write(15, m_r[15] + e); } break; } case 0x0a: // BPL { int32_t e = (int8_t)superfx_pipe(); if(SUPERFX_SFR_S_SET == 0) { superfx_gpr_write(15, m_r[15] + e); } break; } case 0x0b: // BMI { int32_t e = (int8_t)superfx_pipe(); if(SUPERFX_SFR_S_SET == 1) { superfx_gpr_write(15, m_r[15] + e); } break; } case 0x0c: // BCC { int32_t e = (int8_t)superfx_pipe(); if(SUPERFX_SFR_CY_SET == 0) { superfx_gpr_write(15, m_r[15] + e); } break; } case 0x0d: // BCS { int32_t e = (int8_t)superfx_pipe(); if(SUPERFX_SFR_CY_SET == 1) { superfx_gpr_write(15, m_r[15] + e); } break; } case 0x0e: // BVC { int32_t e = (int8_t)superfx_pipe(); if(SUPERFX_SFR_OV_SET == 0) { superfx_gpr_write(15, m_r[15] + e); } break; } case 0x0f: // BVS { int32_t e = (int8_t)superfx_pipe(); if(SUPERFX_SFR_OV_SET == 1) { superfx_gpr_write(15, m_r[15] + e); } break; } case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: // TO if((m_sfr & SUPERFX_SFR_B) == 0) { m_dreg = &m_r[op & 0xf]; m_dreg_idx = op & 0xf; } else { superfx_gpr_write(op & 0xf, *(m_sreg)); superfx_regs_reset(); } break; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: // WITH m_sreg = &m_r[op & 0xf]; m_sreg_idx = op & 0xf; m_dreg = &m_r[op & 0xf]; m_dreg_idx = op & 0xf; m_sfr |= SUPERFX_SFR_B; break; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3a: case 0x3b: // STW_IR / STB_IR if((m_sfr & SUPERFX_SFR_ALT1) == 0) { // STW_IR m_ramaddr = m_r[op & 0xf]; superfx_rambuffer_write(m_ramaddr ^ 0, (*(m_sreg)) >> 0); superfx_rambuffer_write(m_ramaddr ^ 1, (*(m_sreg)) >> 8); superfx_regs_reset(); } else { // STB_IR m_ramaddr = m_r[op & 0xf]; superfx_rambuffer_write(m_ramaddr, *(m_sreg)); superfx_regs_reset(); } break; case 0x3c: // LOOP superfx_gpr_write(12, m_r[12] - 1); m_sfr &= ~(SUPERFX_SFR_S | SUPERFX_SFR_Z); m_sfr |= (m_r[12] & 0x8000) ? SUPERFX_SFR_S : 0; m_sfr |= (m_r[12] == 0) ? SUPERFX_SFR_Z : 0; if(!(m_sfr & SUPERFX_SFR_Z)) { superfx_gpr_write(15, m_r[13]); } superfx_regs_reset(); break; case 0x3d: // ALT1 m_sfr &= ~SUPERFX_SFR_B; m_sfr |= SUPERFX_SFR_ALT1; break; case 0x3e: // ALT2 m_sfr &= ~SUPERFX_SFR_B; m_sfr |= SUPERFX_SFR_ALT2; break; case 0x3f: // ALT3 m_sfr &= ~SUPERFX_SFR_B; m_sfr |= SUPERFX_SFR_ALT1; m_sfr |= SUPERFX_SFR_ALT2; break; case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: // LDW_IR / LDB_IR if((m_sfr & SUPERFX_SFR_ALT1) == 0) { // LDW_IR uint16_t data; m_ramaddr = m_r[op & 0xf]; data = superfx_rambuffer_read(m_ramaddr ^ 0) << 0; data |= superfx_rambuffer_read(m_ramaddr ^ 1) << 8; superfx_gpr_write(m_dreg_idx, data); superfx_regs_reset(); } else { // LDB_IR m_ramaddr = m_r[op & 0xf]; superfx_gpr_write(m_dreg_idx, superfx_rambuffer_read(m_ramaddr)); superfx_regs_reset(); } break; case 0x4c: // PLOT / RPIX if((m_sfr & SUPERFX_SFR_ALT1) == 0) { // PLOT superfx_plot(m_r[1], m_r[2]); superfx_gpr_write(1, m_r[1] + 1); superfx_regs_reset(); } else { // RPIX superfx_gpr_write(m_dreg_idx, superfx_rpix(m_r[1], m_r[2])); superfx_dreg_sfr_sz_update(); superfx_regs_reset(); } break; case 0x4d: // SWAP superfx_gpr_write(m_dreg_idx, (*(m_sreg) >> 8) | (*(m_sreg) << 8)); superfx_dreg_sfr_sz_update(); superfx_regs_reset(); break; case 0x4e: // COLOR / CMODE if((m_sfr & SUPERFX_SFR_ALT1) == 0) { // COLOR m_colr = superfx_color(*(m_sreg)); superfx_regs_reset(); } else { // CMODE m_por = *(m_sreg); superfx_regs_reset(); } break; case 0x4f: // NOT superfx_gpr_write(m_dreg_idx, ~(*(m_sreg))); superfx_dreg_sfr_sz_update(); superfx_regs_reset(); break; case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: // ADD / ADC / ADDI / ADCI { int32_t r = *(m_sreg); m_sfr &= ~(SUPERFX_SFR_OV | SUPERFX_SFR_S | SUPERFX_SFR_Z); switch(m_sfr & SUPERFX_SFR_ALT) { case SUPERFX_SFR_ALT0: // ADD r += m_r[op & 0xf]; m_sfr |= (~(*(m_sreg) ^ m_r[op & 0xf]) & (m_r[op & 0xf] ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; break; case SUPERFX_SFR_ALT1: // ADC r += m_r[op & 0xf] + SUPERFX_SFR_CY_SET; m_sfr |= (~(*(m_sreg) ^ m_r[op & 0xf]) & (m_r[op & 0xf] ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; break; case SUPERFX_SFR_ALT2: // ADDI r += op & 0xf; m_sfr |= (~(*(m_sreg) ^ (op & 0xf)) & ((op & 0xf) ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; break; case SUPERFX_SFR_ALT3: // ADCI r += (op & 0xf) + SUPERFX_SFR_CY_SET; m_sfr |= (~(*(m_sreg) ^ (op & 0xf)) & ((op & 0xf) ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; break; } m_sfr &= ~SUPERFX_SFR_CY; m_sfr |= (r & 0x8000) ? SUPERFX_SFR_S : 0; m_sfr |= (r >= 0x10000) ? SUPERFX_SFR_CY : 0; m_sfr |= ((uint16_t)r == 0) ? SUPERFX_SFR_Z : 0; superfx_gpr_write(m_dreg_idx, r); superfx_regs_reset(); break; } case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: // SUB / SBC / SUBI / CMP { int32_t r = 0; m_sfr &= ~(SUPERFX_SFR_OV | SUPERFX_SFR_S | SUPERFX_SFR_Z); switch(m_sfr & SUPERFX_SFR_ALT) { case SUPERFX_SFR_ALT0: // SUB r = *(m_sreg) - m_r[op & 0xf]; m_sfr |= ((*(m_sreg) ^ m_r[op & 0xf]) & (*(m_sreg) ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; superfx_gpr_write(m_dreg_idx, r); break; case SUPERFX_SFR_ALT1: // SBC r = *(m_sreg) - m_r[op & 0xf] - SUPERFX_SFR_CY_CLEAR; m_sfr |= ((*(m_sreg) ^ m_r[op & 0xf]) & (*(m_sreg) ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; superfx_gpr_write(m_dreg_idx, r); break; case SUPERFX_SFR_ALT2: // SUBI r = *(m_sreg) - (op & 0xf); m_sfr |= ((*(m_sreg) ^ (op & 0xf)) & (*(m_sreg) ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; superfx_gpr_write(m_dreg_idx, r); break; case SUPERFX_SFR_ALT3: // CMP r = *(m_sreg) - m_r[op & 0xf]; m_sfr |= ((*(m_sreg) ^ m_r[op & 0xf]) & (*(m_sreg) ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; break; } m_sfr &= ~SUPERFX_SFR_CY; m_sfr |= (r & 0x8000) ? SUPERFX_SFR_S : 0; m_sfr |= (r >= 0x0) ? SUPERFX_SFR_CY : 0; m_sfr |= ((uint16_t)r == 0) ? SUPERFX_SFR_Z : 0; superfx_regs_reset(); break; } case 0x70: // MERGE superfx_gpr_write(m_dreg_idx, (m_r[7] & 0xff00) | (m_r[8] >> 8)); m_sfr &= ~(SUPERFX_SFR_OV | SUPERFX_SFR_S | SUPERFX_SFR_CY | SUPERFX_SFR_Z); m_sfr |= (*(m_dreg) & 0xc0c0) ? SUPERFX_SFR_OV : 0; m_sfr |= (*(m_dreg) & 0x8080) ? SUPERFX_SFR_S : 0; m_sfr |= (*(m_dreg) & 0xe0e0) ? SUPERFX_SFR_CY : 0; m_sfr |= (*(m_dreg) & 0xf0f0) ? SUPERFX_SFR_Z : 0; superfx_regs_reset(); break; case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: // AND / BIC / ANDI / BICI switch(m_sfr & SUPERFX_SFR_ALT) { case SUPERFX_SFR_ALT0: // AND superfx_gpr_write(m_dreg_idx, *(m_sreg) & m_r[op & 0xf]); break; case SUPERFX_SFR_ALT1: // BIC superfx_gpr_write(m_dreg_idx, *(m_sreg) & ~m_r[op & 0xf]); break; case SUPERFX_SFR_ALT2: // ANDI superfx_gpr_write(m_dreg_idx, *(m_sreg) & (op & 0xf)); break; case SUPERFX_SFR_ALT3: // BICI superfx_gpr_write(m_dreg_idx, *(m_sreg) & ~(op & 0xf)); break; } superfx_dreg_sfr_sz_update(); superfx_regs_reset(); break; case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: // MULT / UMULT / MULTI / UMULTI switch(m_sfr & SUPERFX_SFR_ALT) { case SUPERFX_SFR_ALT0: // MULT superfx_gpr_write(m_dreg_idx, (int8_t)(*(m_sreg)) * (int8_t)(m_r[op & 0xf])); break; case SUPERFX_SFR_ALT1: // UMULT superfx_gpr_write(m_dreg_idx, (uint8_t)(*(m_sreg)) * (uint8_t)(m_r[op & 0xf])); break; case SUPERFX_SFR_ALT2: // MULTI superfx_gpr_write(m_dreg_idx, (int8_t)(*(m_sreg)) * (int8_t)(op & 0xf)); break; case SUPERFX_SFR_ALT3: // UMULTI superfx_gpr_write(m_dreg_idx, (uint8_t)(*(m_sreg)) * (uint8_t)(op & 0xf)); break; } superfx_dreg_sfr_sz_update(); superfx_regs_reset(); if(!(m_cfgr & SUPERFX_CFGR_MS0)) { superfx_add_clocks_internal(2); } break; case 0x90: // SBK superfx_rambuffer_write(m_ramaddr ^ 0, *(m_sreg) >> 0); superfx_rambuffer_write(m_ramaddr ^ 1, *(m_sreg) >> 8); superfx_regs_reset(); break; case 0x91: case 0x92: case 0x93: case 0x94: // LINK superfx_gpr_write(11, m_r[15] + (op & 0xf)); superfx_regs_reset(); break; case 0x95: // SEX superfx_gpr_write(m_dreg_idx, (int8_t)(*(m_sreg))); superfx_dreg_sfr_sz_update(); superfx_regs_reset(); break; case 0x96: // ASR / DIV2 if((m_sfr & SUPERFX_SFR_ALT1) == 0) { // ASR m_sfr &= ~SUPERFX_SFR_CY; m_sfr |= (*(m_sreg) & 1) ? SUPERFX_SFR_CY : 0; superfx_gpr_write(m_dreg_idx, (int16_t)(*(m_sreg)) >> 1); superfx_dreg_sfr_sz_update(); superfx_regs_reset(); } else { // DIV2 m_sfr &= ~SUPERFX_SFR_CY; m_sfr |= (*(m_sreg) & 1) ? SUPERFX_SFR_CY : 0; superfx_gpr_write(m_dreg_idx, ((int16_t)(*(m_sreg)) >> 1) + ((uint32_t)(*(m_sreg) + 1) >> 16)); superfx_dreg_sfr_sz_update(); superfx_regs_reset(); } break; case 0x97: // ROR { uint16_t carry = *(m_sreg) & 1; superfx_gpr_write(m_dreg_idx, (SUPERFX_SFR_CY_SET << 15) | ((uint16_t)(*(m_sreg)) >> 1)); m_sfr &= ~SUPERFX_SFR_CY; m_sfr |= carry ? SUPERFX_SFR_CY : 0; superfx_dreg_sfr_sz_update(); superfx_regs_reset(); break; } case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: // JMP / LJMP if((m_sfr & SUPERFX_SFR_ALT1) == 0) { // JMP superfx_gpr_write(15, m_r[op & 0xf]); superfx_regs_reset(); } else { // LJMP m_pbr = m_r[op & 0xf] & 0x7f; superfx_gpr_write(15, *(m_sreg)); m_cbr = m_r[15] & 0xfff0; superfx_cache_flush(); superfx_regs_reset(); } break; case 0x9e: // LOB superfx_gpr_write(m_dreg_idx, (uint16_t)(*(m_sreg)) & 0x00ff); m_sfr &= ~(SUPERFX_SFR_S | SUPERFX_SFR_Z); m_sfr |= (*(m_dreg) & 0x80) ? SUPERFX_SFR_S : 0; m_sfr |= (*(m_dreg) == 0) ? SUPERFX_SFR_Z : 0; superfx_regs_reset(); break; case 0x9f: // FMULT / LMULT { uint32_t result = (int16_t)(*(m_sreg)) * (int16_t)(m_r[6]); if(m_sfr & SUPERFX_SFR_ALT1) { // LMULT superfx_gpr_write(4, result); } superfx_gpr_write(m_dreg_idx, result >> 16); m_sfr &= ~SUPERFX_SFR_CY; m_sfr |= (result & 0x8000) ? SUPERFX_SFR_CY : 0; superfx_dreg_sfr_sz_update(); superfx_regs_reset(); superfx_add_clocks_internal(4 + ((m_cfgr & SUPERFX_CFGR_MS0) ? 4 : 0)); break; } case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: // IBT / LMS / SMS / LMS switch(m_sfr & SUPERFX_SFR_ALT) { case SUPERFX_SFR_ALT0: // IBT superfx_gpr_write(op & 0xf, (int8_t)superfx_pipe()); superfx_regs_reset(); break; case SUPERFX_SFR_ALT2: // SMS m_ramaddr = superfx_pipe() << 1; superfx_rambuffer_write(m_ramaddr ^ 0, m_r[op & 0xf] >> 0); superfx_rambuffer_write(m_ramaddr ^ 1, m_r[op & 0xf] >> 8); superfx_regs_reset(); break; case SUPERFX_SFR_ALT1: // LMS case SUPERFX_SFR_ALT3: // LMS { uint16_t data; m_ramaddr = superfx_pipe() << 1; data = superfx_rambuffer_read(m_ramaddr ^ 0) << 0; data |= superfx_rambuffer_read(m_ramaddr ^ 1) << 8; superfx_gpr_write(op & 0xf, data); superfx_regs_reset(); break; } } break; case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: // FROM if((m_sfr & SUPERFX_SFR_B) == 0) { m_sreg = &(m_r[op & 0xf]); m_sreg_idx = op & 0xf; } else { superfx_gpr_write(m_dreg_idx, m_r[op & 0xf]); m_sfr &= ~SUPERFX_SFR_OV; m_sfr |= (*(m_dreg) & 0x80) ? SUPERFX_SFR_OV : 0; superfx_dreg_sfr_sz_update(); superfx_regs_reset(); } break; case 0xc0: // HIB superfx_gpr_write(m_dreg_idx, (*(m_sreg)) >> 8); m_sfr &= ~(SUPERFX_SFR_S | SUPERFX_SFR_Z); m_sfr |= (*(m_dreg) & 0x80) ? SUPERFX_SFR_S : 0; m_sfr |= (*(m_dreg) == 0) ? SUPERFX_SFR_Z : 0; superfx_regs_reset(); break; case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: // OR / XOR / ORI / XORI switch(m_sfr & SUPERFX_SFR_ALT) { case SUPERFX_SFR_ALT0: // OR superfx_gpr_write(m_dreg_idx, *(m_sreg) | m_r[op & 0xf]); break; case SUPERFX_SFR_ALT1: // XOR superfx_gpr_write(m_dreg_idx, *(m_sreg) ^ m_r[op & 0xf]); break; case SUPERFX_SFR_ALT2: // ORI superfx_gpr_write(m_dreg_idx, *(m_sreg) | (op & 0xf)); break; case SUPERFX_SFR_ALT3: // XORI superfx_gpr_write(m_dreg_idx, *(m_sreg) ^ (op & 0xf)); break; } superfx_dreg_sfr_sz_update(); superfx_regs_reset(); break; case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: // INC superfx_gpr_write(op & 0xf, m_r[op & 0xf] + 1); m_sfr &= ~(SUPERFX_SFR_S | SUPERFX_SFR_Z); m_sfr |= (m_r[op & 0xf] & 0x8000) ? SUPERFX_SFR_S : 0; m_sfr |= (m_r[op & 0xf] == 0) ? SUPERFX_SFR_Z : 0; superfx_regs_reset(); break; case 0xdf: // GETC / RAMB / ROMB switch(m_sfr & SUPERFX_SFR_ALT) { case SUPERFX_SFR_ALT0: // GETC case SUPERFX_SFR_ALT1: // GETC m_colr = superfx_color(superfx_rombuffer_read()); superfx_regs_reset(); break; case SUPERFX_SFR_ALT2: // RAMB superfx_rambuffer_sync(); m_rambr = ((*(m_sreg)) & 1) ? 1 : 0; superfx_regs_reset(); break; case SUPERFX_SFR_ALT3: // ROMB superfx_rombuffer_sync(); m_rombr = *(m_sreg) & 0x7f; superfx_regs_reset(); break; } break; case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: // DEC superfx_gpr_write(op & 0xf, m_r[op & 0xf] - 1); m_sfr &= ~(SUPERFX_SFR_S | SUPERFX_SFR_Z); m_sfr |= (m_r[op & 0xf] & 0x8000) ? SUPERFX_SFR_S : 0; m_sfr |= (m_r[op & 0xf] == 0) ? SUPERFX_SFR_Z : 0; superfx_regs_reset(); break; case 0xef: // GETB / GETBH / GETBL / GETBS { uint8_t byte = superfx_rombuffer_read(); switch(m_sfr & SUPERFX_SFR_ALT) { case SUPERFX_SFR_ALT0: // GETB superfx_gpr_write(m_dreg_idx, byte); break; case SUPERFX_SFR_ALT1: // GETBH superfx_gpr_write(m_dreg_idx, (byte << 8) | (*(m_sreg) & 0x00ff)); break; case SUPERFX_SFR_ALT2: // GETBL superfx_gpr_write(m_dreg_idx, (*(m_sreg) & 0xff00) | (byte << 0)); break; case SUPERFX_SFR_ALT3: // GETBS superfx_gpr_write(m_dreg_idx, (int8_t)byte); break; } superfx_regs_reset(); break; } case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: // IWT / LM / SM / LM { uint16_t data; switch(m_sfr & SUPERFX_SFR_ALT) { case SUPERFX_SFR_ALT0: // IWT data = superfx_pipe() << 0; data |= superfx_pipe() << 8; superfx_gpr_write(op & 0xf, data); superfx_regs_reset(); break; case SUPERFX_SFR_ALT2: // SM m_ramaddr = superfx_pipe() << 0; m_ramaddr |= superfx_pipe() << 8; superfx_rambuffer_write(m_ramaddr ^ 0, m_r[op & 0xf] >> 0); superfx_rambuffer_write(m_ramaddr ^ 1, m_r[op & 0xf] >> 8); superfx_regs_reset(); break; case SUPERFX_SFR_ALT1: case SUPERFX_SFR_ALT3: // LM m_ramaddr = superfx_pipe() << 0; m_ramaddr |= superfx_pipe() << 8; data = superfx_rambuffer_read(m_ramaddr ^ 0) << 0; data |= superfx_rambuffer_read(m_ramaddr ^ 1) << 8; superfx_gpr_write(op & 0xf, data); superfx_regs_reset(); break; } break; } } if(!m_r15_modified) { m_r[15]++; } //printf( " r0:%04x r1:%04x r2:%04x r3:%04x r4:%04x r5:%04x r6:%04x r7:%04x\n", m_r[0], m_r[1], m_r[2], m_r[3], m_r[4], m_r[5], m_r[6], m_r[7] ); //printf( " r8:%04x r9:%04x r10:%04x r11:%04x r12:%04x r13:%04x r14:%04x r15:%04x\n", m_r[8], m_r[9], m_r[10], m_r[11], m_r[12], m_r[13], m_r[14], m_r[15] ); //printf( "sfr:%04x\n", m_sfr ); --m_icount; } } u16 superfx_device::get_alt() const { return m_sfr & SUPERFX_SFR_ALT; } std::unique_ptr superfx_device::create_disassembler() { return std::make_unique(this); }