diff options
Diffstat (limited to 'src/devices/cpu/powerpc/ppccom.cpp')
-rw-r--r-- | src/devices/cpu/powerpc/ppccom.cpp | 249 |
1 files changed, 163 insertions, 86 deletions
diff --git a/src/devices/cpu/powerpc/ppccom.cpp b/src/devices/cpu/powerpc/ppccom.cpp index 4a8a071f903..4e76a3efbb2 100644 --- a/src/devices/cpu/powerpc/ppccom.cpp +++ b/src/devices/cpu/powerpc/ppccom.cpp @@ -205,6 +205,8 @@ DEFINE_DEVICE_TYPE(MPC8240, mpc8240_device, "mpc8240", "IBM PowerPC MPC82 DEFINE_DEVICE_TYPE(PPC403GA, ppc403ga_device, "ppc403ga", "IBM PowerPC 403GA") DEFINE_DEVICE_TYPE(PPC403GCX, ppc403gcx_device, "ppc403gcx", "IBM PowerPC 403GCX") DEFINE_DEVICE_TYPE(PPC405GP, ppc405gp_device, "ppc405gp", "IBM PowerPC 405GP") +DEFINE_DEVICE_TYPE(PPC740, ppc740_device, "ppc740", "IBM PowerPC 740") +DEFINE_DEVICE_TYPE(PPC750, ppc750_device, "ppc750", "IBM PowerPC 750") ppc_device::ppc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int address_bits, int data_bits, powerpc_flavor flavor, uint32_t cap, uint32_t tb_divisor, address_map_constructor internal_map) @@ -212,15 +214,23 @@ ppc_device::ppc_device(const machine_config &mconfig, device_type type, const ch , device_vtlb_interface(mconfig, *this, AS_PROGRAM) , m_program_config("program", ENDIANNESS_BIG, data_bits, address_bits, 0, internal_map) , c_bus_frequency(0) + , c_serial_clock(0) , m_core(nullptr) , m_bus_freq_multiplier(1) , m_flavor(flavor) , m_cap(cap) , m_tb_divisor(tb_divisor) + , m_spu(*this) + , m_dcr_read_func(*this) + , m_dcr_write_func(*this) + , m_dcstore_cb(*this) + , m_ext_dma_read_cb(*this) + , m_ext_dma_write_cb(*this) , m_cache(CACHE_SIZE + sizeof(internal_ppc_state)) , m_drcuml(nullptr) , m_drcfe(nullptr) , m_drcoptions(0) + , m_dasm(powerpc_disassembler()) { m_program_config.m_logaddr_width = 32; m_program_config.m_page_shift = POWERPC_MIN_PAGE_SHIFT; @@ -271,15 +281,31 @@ mpc8240_device::mpc8240_device(const machine_config &mconfig, const char *tag, d } ppc601_device::ppc601_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : ppc_device(mconfig, PPC601, tag, owner, clock, 32, 64, PPC_MODEL_601, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_MFIOC | PPCCAP_601BAT, 0/* no TB */, address_map_constructor()) + : ppc_device(mconfig, PPC601, tag, owner, clock, 32, 64, PPC_MODEL_601, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_MFIOC | PPCCAP_601BAT | PPCCAP_LEGACY_POWER, 0 /* no TB */, address_map_constructor()) { } +std::unique_ptr<util::disasm_interface> ppc601_device::create_disassembler() +{ + // 601 has both POWER and PowerPC instructions + return std::make_unique<powerpc_disassembler>((powerpc_disassembler::implementation)(powerpc_disassembler::I_POWER|powerpc_disassembler::I_POWERPC)); +} + ppc604_device::ppc604_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ppc_device(mconfig, PPC604, tag, owner, clock, 32, 64, PPC_MODEL_604, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_604_MMU, 4, address_map_constructor()) { } +ppc740_device::ppc740_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : ppc_device(mconfig, PPC740, tag, owner, clock, 32, 64, PPC_MODEL_740, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_604_MMU | PPCCAP_750_TLB , 4, address_map_constructor()) +{ +} + +ppc750_device::ppc750_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : ppc_device(mconfig, PPC750, tag, owner, clock, 32, 64, PPC_MODEL_750, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_604_MMU | PPCCAP_750_TLB, 4, address_map_constructor()) +{ +} + void ppc4xx_device::internal_ppc4xx(address_map &map) { map(0x40000000, 0x4000000f).rw(FUNC(ppc4xx_device::ppc4xx_spu_r), FUNC(ppc4xx_device::ppc4xx_spu_w)); @@ -326,9 +352,9 @@ device_memory_interface::space_config_vector ppc_device::memory_space_config() c static inline bool page_access_allowed(int transtype, uint8_t key, uint8_t protbits) { if (key == 0) - return (transtype == TRANSLATE_WRITE) ? (protbits != 3) : true; + return (transtype == device_memory_interface::TR_WRITE) ? (protbits != 3) : true; else - return (transtype == TRANSLATE_WRITE) ? (protbits == 2) : (protbits != 0); + return (transtype == device_memory_interface::TR_WRITE) ? (protbits == 2) : (protbits != 0); } @@ -449,9 +475,9 @@ inline void ppc_device::set_decrementer(uint32_t newdec) if (PRINTF_DECREMENTER) { uint64_t total = total_cycles(); - osd_printf_debug("set_decrementer: olddec=%08X newdec=%08X divisor=%d totalcyc=%08X%08X timer=%08X%08X\n", + osd_printf_debug("set_decrementer: olddec=%08X newdec=%08X divisor=%d totalcyc=%016X timer=%016X\n", curdec, newdec, m_tb_divisor, - (uint32_t)(total >> 32), (uint32_t)total, (uint32_t)(cycles_until_done >> 32), (uint32_t)cycles_until_done); + total, cycles_until_done); } m_dec_zero_cycles = total_cycles() + cycles_until_done; @@ -485,8 +511,7 @@ static inline int is_qnan_double(double x) { uint64_t xi = *(uint64_t*)&x; return( ((xi & DOUBLE_EXP) == DOUBLE_EXP) && - ((xi & 0x0007fffffffffffU) == 0x000000000000000U) && - ((xi & 0x000800000000000U) == 0x000800000000000U) ); + ((xi & 0x0008000000000000U) == 0x0008000000000000U) ); } @@ -694,7 +719,7 @@ void ppc_device::device_start() m_sebr = 0; m_ser = 0; - memset(&m_spu, 0, sizeof(m_spu)); + m_spu.clear(); m_pit_reload = 0; m_irqstate = 0; memset(m_buffered_dma_rate, 0, sizeof(m_buffered_dma_rate)); @@ -702,6 +727,7 @@ void ppc_device::device_start() m_cpu_clock = 0; m_tb_zero_cycles = 0; m_dec_zero_cycles = 0; + m_rtc_zero_cycles = 0; m_arg1 = 0; m_fastram_select = 0; @@ -711,58 +737,64 @@ void ppc_device::device_start() m_debugger_temp = 0; + m_serial_clock = 0; + m_cache_line_size = 32; m_cpu_clock = clock(); m_program = &space(AS_PROGRAM); if(m_cap & PPCCAP_4XX) { - auto cache = m_program->cache<2, 0, ENDIANNESS_BIG>(); - m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); }; - m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); }; + m_program->cache(m_cache32); + m_pr32 = [this](offs_t address) -> u32 { return m_cache32.read_dword(address); }; + m_prptr = [this](offs_t address) -> const void * { return m_cache32.read_ptr(address); }; } else { - auto cache = m_program->cache<3, 0, ENDIANNESS_BIG>(); - m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); }; + m_program->cache(m_cache64); + m_pr32 = [this](offs_t address) -> u32 { return m_cache64.read_dword(address); }; if(space_config()->m_endianness != ENDIANNESS_NATIVE) - m_prptr = [cache](offs_t address) -> const void * { - const u32 *ptr = static_cast<u32 *>(cache->read_ptr(address & ~7)); + m_prptr = [this](offs_t address) -> const void * { + const u32 *ptr = static_cast<u32 *>(m_cache64.read_ptr(address & ~7)); if(!(address & 4)) ptr++; return ptr; }; else - m_prptr = [cache](offs_t address) -> const void * { - const u32 *ptr = static_cast<u32 *>(cache->read_ptr(address & ~7)); + m_prptr = [this](offs_t address) -> const void * { + const u32 *ptr = static_cast<u32 *>(m_cache64.read_ptr(address & ~7)); if(address & 4) ptr++; return ptr; }; } m_system_clock = c_bus_frequency != 0 ? c_bus_frequency : clock(); - m_dcr_read_func = read32_delegate(); - m_dcr_write_func = write32_delegate(); + m_dcr_read_func.set(nullptr); + m_dcr_write_func.set(nullptr); m_tb_divisor = (m_tb_divisor * clock() + m_system_clock / 2 - 1) / m_system_clock; + m_serial_clock = c_serial_clock != 0 ? c_serial_clock : 3'686'400; // TODO: get rid of this hard-coded magic number + if (m_serial_clock > m_system_clock / 2) + fatalerror("%s: PPC: serial clock (%d) must not be more than half of the system clock (%d)\n", tag(), m_serial_clock, m_system_clock); + /* allocate a timer for the compare interrupt */ if ((m_cap & PPCCAP_OEA) && (m_tb_divisor)) - m_decrementer_int_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::decrementer_int_callback), this)); + m_decrementer_int_timer = timer_alloc(FUNC(ppc_device::decrementer_int_callback), this); /* and for the 4XX interrupts if needed */ if (m_cap & PPCCAP_4XX) { - m_fit_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_fit_callback), this)); - m_pit_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_pit_callback), this)); - m_spu.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_spu_callback), this)); + m_fit_timer = timer_alloc(FUNC(ppc_device::ppc4xx_fit_callback), this); + m_pit_timer = timer_alloc(FUNC(ppc_device::ppc4xx_pit_callback), this); + m_spu.timer = timer_alloc(FUNC(ppc_device::ppc4xx_spu_callback), this); } if (m_cap & PPCCAP_4XX) { - m_buffered_dma_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); - m_buffered_dma_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); - m_buffered_dma_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); - m_buffered_dma_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); + m_buffered_dma_timer[0] = timer_alloc(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this); + m_buffered_dma_timer[1] = timer_alloc(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this); + m_buffered_dma_timer[2] = timer_alloc(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this); + m_buffered_dma_timer[3] = timer_alloc(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this); m_buffered_dma_rate[0] = 10000; m_buffered_dma_rate[1] = 10000; @@ -806,6 +838,11 @@ void ppc_device::device_start() state_add(PPC_PC, "PC", m_core->pc).formatstr("%08X"); state_add(PPC_MSR, "MSR", m_core->msr).formatstr("%08X"); state_add(PPC_CR, "CR", m_debugger_temp).callimport().callexport().formatstr("%08X"); + // If the legacy POWER instructions exist, that implies MQ is used and should be shown + if (m_cap & PPCCAP_LEGACY_POWER) + { + state_add(PPC_MQ, "MQ", m_core->spr[SPR601_MQ]).formatstr("%08X"); + } state_add(PPC_LR, "LR", m_core->spr[SPR_LR]).formatstr("%08X"); state_add(PPC_CTR, "CTR", m_core->spr[SPR_CTR]).formatstr("%08X"); state_add(PPC_XER, "XER", m_debugger_temp).callimport().callexport().formatstr("%08X"); @@ -836,7 +873,6 @@ void ppc_device::device_start() state_add(STATE_GENPC, "GENPC", m_core->pc).noshow(); state_add(STATE_GENPCBASE, "CURPC", m_core->pc).noshow(); - state_add(STATE_GENSP, "GENSP", m_core->r[31]).noshow(); state_add(STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).noshow().formatstr("%1s"); set_icountptr(m_core->icount); @@ -851,15 +887,15 @@ void ppc_device::device_start() for (int regnum = 0; regnum < 32; regnum++) { char buf[10]; - sprintf(buf, "r%d", regnum); + snprintf(buf, 10, "r%d", regnum); m_drcuml->symbol_add(&m_core->r[regnum], sizeof(m_core->r[regnum]), buf); - sprintf(buf, "fpr%d", regnum); + snprintf(buf, 10, "fpr%d", regnum); m_drcuml->symbol_add(&m_core->f[regnum], sizeof(m_core->f[regnum]), buf); } for (int regnum = 0; regnum < 8; regnum++) { char buf[10]; - sprintf(buf, "cr%d", regnum); + snprintf(buf, 10, "cr%d", regnum); m_drcuml->symbol_add(&m_core->cr[regnum], sizeof(m_core->cr[regnum]), buf); } m_drcuml->symbol_add(&m_core->xerso, sizeof(m_core->xerso), "xerso"); @@ -1144,7 +1180,7 @@ void ppc_device::device_reset() m_dec_zero_cycles = total_cycles(); if (m_tb_divisor) { - decrementer_int_callback(nullptr, 0); + decrementer_int_callback(0); } } @@ -1195,7 +1231,7 @@ void ppc_device::device_reset() std::unique_ptr<util::disasm_interface> ppc_device::create_disassembler() { - return std::make_unique<powerpc_disassembler>(); + return std::make_unique<powerpc_disassembler>(powerpc_disassembler::I_POWERPC); } @@ -1208,7 +1244,7 @@ void ppc_device::ppccom_dcstore_callback() { if (!m_dcstore_cb.isnull()) { - m_dcstore_cb(*m_program, m_core->param0, 0, 0xffffffff); + m_dcstore_cb(m_core->param0, 0); } } @@ -1224,10 +1260,10 @@ void ppc_device::ppccom_dcstore_callback() filling -------------------------------------------------*/ -uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &address) +uint32_t ppc_device::ppccom_translate_address_internal(int intention, bool debug, offs_t &address) { - int transpriv = ((intention & TRANSLATE_USER_MASK) == 0); // 1 for supervisor, 0 for user - int transtype = intention & TRANSLATE_TYPE_MASK; + int transpriv = ((intention & TR_USER) == 0); // 1 for supervisor, 0 for user + int transtype = intention & TR_TYPE; offs_t hash, hashbase, hashmask; int batbase, batnum, hashnum; uint32_t segreg; @@ -1240,7 +1276,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad fatalerror("MMU enabled but not supported!\n"); /* only check if PE is enabled */ - if (transtype == TRANSLATE_WRITE && (m_core->msr & MSR4XX_PE)) + if (transtype == TR_WRITE && (m_core->msr & MSR4XX_PE)) { /* are we within one of the protection ranges? */ int inrange1 = ((address >> 12) >= (m_core->spr[SPR4XX_PBL1] >> 12) && (address >> 12) < (m_core->spr[SPR4XX_PBU1] >> 12)); @@ -1259,7 +1295,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad return 0x001; /* also no translation necessary if translation is disabled */ - if ((transtype == TRANSLATE_FETCH && (m_core->msr & MSROEA_IR) == 0) || (transtype != TRANSLATE_FETCH && (m_core->msr & MSROEA_DR) == 0)) + if ((transtype == TR_FETCH && (m_core->msr & MSROEA_IR) == 0) || (transtype != TR_FETCH && (m_core->msr & MSROEA_DR) == 0)) return 0x001; /* first scan the appropriate BAT */ @@ -1269,9 +1305,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad { uint32_t upper = m_core->spr[SPROEA_IBAT0U + 2*batnum + 0]; uint32_t lower = m_core->spr[SPROEA_IBAT0U + 2*batnum + 1]; - int privbit = ((intention & TRANSLATE_USER_MASK) == 0) ? 3 : 2; - -// printf("bat %d upper = %08x privbit %d\n", batnum, upper, privbit); + int privbit = ((intention & TR_USER) == 0) ? 3 : 2; // is this pair valid? if (lower & 0x40) @@ -1286,7 +1320,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad /* verify protection; if we fail, return false and indicate a protection violation */ if (!page_access_allowed(transtype, key, upper & 3)) { - return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + return DSISR_PROTECTED | ((transtype == TR_WRITE) ? DSISR_STORE : 0); } /* otherwise we're good */ @@ -1299,7 +1333,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad } else { - batbase = (transtype == TRANSLATE_FETCH) ? SPROEA_IBAT0U : SPROEA_DBAT0U; + batbase = (transtype == TR_FETCH) ? SPROEA_IBAT0U : SPROEA_DBAT0U; for (batnum = 0; batnum < 4; batnum++) { @@ -1318,7 +1352,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad /* verify protection; if we fail, return false and indicate a protection violation */ if (!page_access_allowed(transtype, 1, lower & 3)) { - return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + return DSISR_PROTECTED | ((transtype == TR_WRITE) ? DSISR_STORE : 0); } /* otherwise we're good */ @@ -1340,13 +1374,13 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad /* look up the segment register */ segreg = m_core->sr[address >> 28]; - if (transtype == TRANSLATE_FETCH && (segreg & 0x10000000)) - return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + if (transtype == TR_FETCH && (segreg & 0x10000000)) + return DSISR_PROTECTED | ((transtype == TR_WRITE) ? DSISR_STORE : 0); /* check for memory-forced I/O */ if (m_cap & PPCCAP_MFIOC) { - if ((transtype != TRANSLATE_FETCH) && ((segreg & 0x87f00000) == 0x87f00000)) + if ((transtype != TR_FETCH) && ((segreg & 0x87f00000) == 0x87f00000)) { address = ((segreg & 0xf)<<28) | (address & 0x0fffffff); return 1; @@ -1369,12 +1403,12 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad m_core->mmu603_cmp = 0x80000000 | ((segreg & 0xffffff) << 7) | (0 << 6) | ((address >> 22) & 0x3f); m_core->mmu603_hash[0] = hashbase | ((hash << 6) & hashmask); m_core->mmu603_hash[1] = hashbase | ((~hash << 6) & hashmask); - if ((entry & (VTLB_FLAG_FIXED | VTLB_FLAG_VALID)) == (VTLB_FLAG_FIXED | VTLB_FLAG_VALID)) + if ((entry & (FLAG_FIXED | FLAG_VALID)) == (FLAG_FIXED | FLAG_VALID)) { address = (entry & 0xfffff000) | (address & 0x00000fff); return 0x001; } - return DSISR_NOT_FOUND | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + return DSISR_NOT_FOUND | ((transtype == TR_WRITE) ? DSISR_STORE : 0); } /* loop twice over hashes */ @@ -1397,13 +1431,13 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad /* verify protection; if we fail, return false and indicate a protection violation */ if (!page_access_allowed(transtype, (segreg >> (29 + transpriv)) & 1, pteglower & 3)) - return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + return DSISR_PROTECTED | ((transtype == TR_WRITE) ? DSISR_STORE : 0); /* update page table bits */ - if (!(intention & TRANSLATE_DEBUG_MASK)) + if (!debug) { pteglower |= 0x100; - if (transtype == TRANSLATE_WRITE) + if (transtype == TR_WRITE) pteglower |= 0x080; ptegptr[BYTE_XOR_BE(ptenum * 2 + 1)] = pteglower; } @@ -1419,7 +1453,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad } /* we failed to find any match: not found */ - return DSISR_NOT_FOUND | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + return DSISR_NOT_FOUND | ((transtype == TR_WRITE) ? DSISR_STORE : 0); } @@ -1428,14 +1462,16 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad from logical to physical -------------------------------------------------*/ -bool ppc_device::memory_translate(int spacenum, int intention, offs_t &address) +bool ppc_device::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) { + target_space = &space(spacenum); + /* only applies to the program address space */ if (spacenum != AS_PROGRAM) return true; /* translation is successful if the internal routine returns 0 or 1 */ - return (ppccom_translate_address_internal(intention, address) <= 1); + return (ppccom_translate_address_internal(intention, true, address) <= 1); } @@ -1445,7 +1481,10 @@ bool ppc_device::memory_translate(int spacenum, int intention, offs_t &address) void ppc_device::ppccom_tlb_fill() { - vtlb_fill(m_core->param0, m_core->param1); + offs_t address = m_core->param0; + if(ppccom_translate_address_internal(m_core->param1, false, address) > 1) + return; + vtlb_fill(m_core->param0, address, m_core->param1); } @@ -1476,14 +1515,14 @@ void ppc_device::ppccom_get_dsisr() if (m_core->param1 & 1) { - intent = TRANSLATE_WRITE; + intent = TR_WRITE; } else { - intent = TRANSLATE_READ; + intent = TR_READ; } - m_core->param1 = ppccom_translate_address_internal(intent, m_core->param0); + m_core->param1 = ppccom_translate_address_internal(intent, false, m_core->param0); } /*------------------------------------------------- @@ -1527,11 +1566,11 @@ void ppc_device::ppccom_execute_tlbl() entrynum = ((address >> 12) & 0x1f) | (machine().rand() & 0x20) | (isitlb ? 0x40 : 0); /* determine the flags */ - flags = VTLB_FLAG_VALID | VTLB_READ_ALLOWED | VTLB_FETCH_ALLOWED; + flags = FLAG_VALID | READ_ALLOWED | FETCH_ALLOWED; if (m_core->spr[SPR603_RPA] & 0x80) - flags |= VTLB_WRITE_ALLOWED; + flags |= WRITE_ALLOWED; if (isitlb) - flags |= VTLB_FETCH_ALLOWED; + flags |= FETCH_ALLOWED; /* load the entry */ vtlb_load(entrynum, 1, address, (m_core->spr[SPR603_RPA] & 0xfffff000) | flags); @@ -1604,6 +1643,29 @@ void ppc_device::ppccom_execute_mfspr() } } + /* handle 601 specific SPRs (POWER holdovers) */ + if (m_flavor == PPC_MODEL_601) + { + switch (m_core->param0) + { + case SPR601_PWRDEC: + m_core->param1 = get_decrementer(); + return; + + case SPR601_RTCUR_PWR: + m_core->param1 = (total_cycles() - m_rtc_zero_cycles) / clock(); + return; + + case SPR601_RTCLR_PWR: + { + const uint64_t remainder = (total_cycles() - m_rtc_zero_cycles) % clock(); + const double seconds = remainder / clock(); // get fractional seconds + m_core->param1 = (uint64_t)(seconds * 1'000'000'000); // and convert to nanoseconds + } + return; + } + } + /* handle 602 SPRs */ if (m_flavor == PPC_MODEL_602) { // TODO: Which are read/write only? @@ -1747,6 +1809,21 @@ void ppc_device::ppccom_execute_mtspr() } } + /* handle 601 specific POWER-holdover SPRs */ + if (m_flavor == PPC_MODEL_601) + { + switch (m_core->param0) + { + case SPR601_MQ: + m_core->spr[m_core->param0] = m_core->param1; + return; + + case SPR601_RTCUW_PWR: + m_rtc_zero_cycles = total_cycles(); + break; + } + } + /* handle 602 SPRs */ if (m_flavor == PPC_MODEL_602) { @@ -1828,9 +1905,9 @@ void ppc_device::ppccom_execute_mtspr() case SPR4XX_TCR: m_core->spr[SPR4XX_TCR] = m_core->param1 | (oldval & PPC4XX_TCR_WRC_MASK); if ((oldval ^ m_core->spr[SPR4XX_TCR]) & PPC4XX_TCR_FIE) - ppc4xx_fit_callback(nullptr, false); + ppc4xx_fit_callback(false); if ((oldval ^ m_core->spr[SPR4XX_TCR]) & PPC4XX_TCR_PIE) - ppc4xx_pit_callback(nullptr, false); + ppc4xx_pit_callback(false); return; /* timer status register */ @@ -1843,7 +1920,7 @@ void ppc_device::ppccom_execute_mtspr() case SPR4XX_PIT: m_core->spr[SPR4XX_PIT] = m_core->param1; m_pit_reload = m_core->param1; - ppc4xx_pit_callback(nullptr, false); + ppc4xx_pit_callback(false); return; /* timebase */ @@ -1913,12 +1990,12 @@ void ppc_device::ppccom_execute_mfdcr() /* default handling */ if (m_dcr_read_func.isnull()) { osd_printf_debug("DCR %03X read\n", m_core->param0); - if (m_core->param0 < ARRAY_LENGTH(m_dcr)) + if (m_core->param0 < std::size(m_dcr)) m_core->param1 = m_dcr[m_core->param0]; else m_core->param1 = 0; } else { - m_core->param1 = m_dcr_read_func(*m_program,m_core->param0,0xffffffff); + m_core->param1 = m_dcr_read_func(m_core->param0); } } @@ -2005,10 +2082,10 @@ void ppc_device::ppccom_execute_mtdcr() /* default handling */ if (m_dcr_write_func.isnull()) { osd_printf_debug("DCR %03X write = %08X\n", m_core->param0, m_core->param1); - if (m_core->param0 < ARRAY_LENGTH(m_dcr)) + if (m_core->param0 < std::size(m_dcr)) m_dcr[m_core->param0] = m_core->param1; } else { - m_dcr_write_func(*m_program,m_core->param0,m_core->param1,0xffffffff); + m_dcr_write_func(m_core->param0,m_core->param1); } } @@ -2093,7 +2170,7 @@ TIMER_CALLBACK_MEMBER( ppc_device::decrementer_int_callback ) for detecting datacache stores with dcbst -------------------------------------------------*/ -void ppc_device::ppc_set_dcstore_callback(write32_delegate callback) +void ppc_device::ppc_set_dcstore_callback(write32sm_delegate callback) { m_dcstore_cb = callback; } @@ -2365,7 +2442,7 @@ TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_buffered_dma_callback ) { uint8_t data = m_program->read_byte(dmaregs[DCR4XX_DMADA0]); if (!m_ext_dma_write_cb[dmachan].isnull()) - (m_ext_dma_write_cb[dmachan])(*m_program, 1, data, 0xffffffff); + (m_ext_dma_write_cb[dmachan])(1, data); dmaregs[DCR4XX_DMADA0] += destinc; } while (!ppc4xx_dma_decrement_count(dmachan)); break; @@ -2376,7 +2453,7 @@ TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_buffered_dma_callback ) { uint16_t data = m_program->read_word(dmaregs[DCR4XX_DMADA0]); if (!m_ext_dma_write_cb[dmachan].isnull()) - (m_ext_dma_write_cb[dmachan])(*m_program, 2, data, 0xffffffff); + (m_ext_dma_write_cb[dmachan])(2, data); dmaregs[DCR4XX_DMADA0] += destinc; } while (!ppc4xx_dma_decrement_count(dmachan)); break; @@ -2387,7 +2464,7 @@ TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_buffered_dma_callback ) { uint32_t data = m_program->read_dword(dmaregs[DCR4XX_DMADA0]); if (!m_ext_dma_write_cb[dmachan].isnull()) - (m_ext_dma_write_cb[dmachan])(*m_program, 4, data, 0xffffffff); + (m_ext_dma_write_cb[dmachan])(4, data); dmaregs[DCR4XX_DMADA0] += destinc; } while (!ppc4xx_dma_decrement_count(dmachan)); break; @@ -2656,7 +2733,7 @@ void ppc_device::ppc4xx_spu_rx_data(uint8_t data) uint32_t new_rxin; /* fail if we are going to overflow */ - new_rxin = (m_spu.rxin + 1) % ARRAY_LENGTH(m_spu.rxbuffer); + new_rxin = (m_spu.rxin + 1) % std::size(m_spu.rxbuffer); if (new_rxin == m_spu.rxout) fatalerror("ppc4xx_spu_rx_data: buffer overrun!\n"); @@ -2678,7 +2755,7 @@ void ppc_device::ppc4xx_spu_timer_reset() /* if we're enabled, reset at the current baud rate */ if (enabled) { - attotime clockperiod = attotime::from_hz((m_dcr[DCR4XX_IOCR] & 0x02) ? 3686400 : 33333333); + attotime clockperiod = attotime::from_hz((m_dcr[DCR4XX_IOCR] & 0x02) ? m_serial_clock : m_system_clock); int divisor = ((m_spu.regs[SPU4XX_BAUD_DIVISOR_H] * 256 + m_spu.regs[SPU4XX_BAUD_DIVISOR_L]) & 0xfff) + 1; int bpc = 7 + ((m_spu.regs[SPU4XX_CONTROL] & 8) >> 3) + 1 + (m_spu.regs[SPU4XX_CONTROL] & 1); attotime charperiod = clockperiod * (divisor * 16 * bpc); @@ -2710,7 +2787,7 @@ TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_spu_callback ) { /* if we have a transmit handler, send it that way */ if (!m_spu.tx_cb.isnull()) - (m_spu.tx_cb)(*m_program, 0, m_spu.txbuf, 0xff); + (m_spu.tx_cb)(m_spu.txbuf); /* indicate that we have moved it to the shift register */ m_spu.regs[SPU4XX_LINE_STATUS] |= 0x04; @@ -2735,7 +2812,7 @@ TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_spu_callback ) /* consume the byte and advance the out pointer */ rxbyte = m_spu.rxbuffer[m_spu.rxout]; - m_spu.rxout = (m_spu.rxout + 1) % ARRAY_LENGTH(m_spu.rxbuffer); + m_spu.rxout = (m_spu.rxout + 1) % std::size(m_spu.rxbuffer); /* if we're not full, copy data to the buffer and update the line status */ if (!(m_spu.regs[SPU4XX_LINE_STATUS] & 0x80)) @@ -2766,7 +2843,7 @@ updateirq: ppc4xx_spu_r - serial port read handler -------------------------------------------------*/ -READ8_MEMBER( ppc4xx_device::ppc4xx_spu_r ) +uint8_t ppc4xx_device::ppc4xx_spu_r(offs_t offset) { uint8_t result = 0xff; @@ -2778,7 +2855,7 @@ READ8_MEMBER( ppc4xx_device::ppc4xx_spu_r ) break; default: - if (offset < ARRAY_LENGTH(m_spu.regs)) + if (offset < std::size(m_spu.regs)) result = m_spu.regs[offset]; break; } @@ -2792,7 +2869,7 @@ READ8_MEMBER( ppc4xx_device::ppc4xx_spu_r ) ppc4xx_spu_w - serial port write handler -------------------------------------------------*/ -WRITE8_MEMBER( ppc4xx_device::ppc4xx_spu_w ) +void ppc4xx_device::ppc4xx_spu_w(offs_t offset, uint8_t data) { uint8_t oldstate, newstate; @@ -2842,7 +2919,7 @@ WRITE8_MEMBER( ppc4xx_device::ppc4xx_spu_w ) break; default: - if (offset < ARRAY_LENGTH(m_spu.regs)) + if (offset < std::size(m_spu.regs)) m_spu.regs[offset] = data; break; } @@ -2855,7 +2932,7 @@ WRITE8_MEMBER( ppc4xx_device::ppc4xx_spu_w ) specific TX handler configuration -------------------------------------------------*/ -void ppc4xx_device::ppc4xx_spu_set_tx_handler(write8_delegate callback) +void ppc4xx_device::ppc4xx_spu_set_tx_handler(write8smo_delegate callback) { m_spu.tx_cb = callback; } @@ -2887,7 +2964,7 @@ void ppc4xx_device::ppc4xx_set_dma_read_handler(int channel, read32_delegate cal specific external DMA write handler configuration -------------------------------------------------*/ -void ppc4xx_device::ppc4xx_set_dma_write_handler(int channel, write32_delegate callback, int rate) +void ppc4xx_device::ppc4xx_set_dma_write_handler(int channel, write32sm_delegate callback, int rate) { m_ext_dma_write_cb[channel] = callback; m_buffered_dma_rate[channel] = rate; @@ -2897,7 +2974,7 @@ void ppc4xx_device::ppc4xx_set_dma_write_handler(int channel, write32_delegate c ppc4xx_set_dcr_read_handler -------------------------------------------------*/ -void ppc4xx_device::ppc4xx_set_dcr_read_handler(read32_delegate dcr_read_func) +void ppc4xx_device::ppc4xx_set_dcr_read_handler(read32sm_delegate dcr_read_func) { m_dcr_read_func = dcr_read_func; @@ -2907,7 +2984,7 @@ void ppc4xx_device::ppc4xx_set_dcr_read_handler(read32_delegate dcr_read_func) ppc4xx_set_dcr_write_handler -------------------------------------------------*/ -void ppc4xx_device::ppc4xx_set_dcr_write_handler(write32_delegate dcr_write_func) +void ppc4xx_device::ppc4xx_set_dcr_write_handler(write32sm_delegate dcr_write_func) { m_dcr_write_func = dcr_write_func; } |