mirror of
https://github.com/holub/mame
synced 2025-04-19 15:11:37 +03:00
hphybrid: found 2 undocumented instructions
This commit is contained in:
parent
01657a63c1
commit
996a4fd9c0
@ -1,10 +1,31 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:F. Ulivi
|
||||
|
||||
// I found 2 undocumented instructions in 5061-3001. First I noticed that PPU processor in
|
||||
// hp9845b emulator executed 2 unknown instructions at each keyboard interrupt whose opcodes
|
||||
// were 0x7026 & 0x7027.
|
||||
// I searched for a while for any kind of documentation about them but found nothing at all.
|
||||
// Some time later I found the mnemonics in the binary dump of assembly development option ROM:
|
||||
// CIM & SIM, respectively. From the mnemonic I deduced their function: Clear & Set Interrupt Mask.
|
||||
// I think they are basically used to temporarily disable/enable interrupt recognition inside
|
||||
// ISRs. This is consistent with their usage in PPU firmware and test ROM. The official EIR &
|
||||
// DIR instructions cannot be used while servicing an interrupt because they probably reset
|
||||
// the "in ISR" condition of the processor.
|
||||
// Using CIM&SIM only makes sense in low-level ISRs because high-level ones can't be interrupted
|
||||
// by anyone.
|
||||
// Now, I still have some doubts about the "polarity" of interrupt mask. Is interrupt
|
||||
// recognition disabled when the mask is cleared or is it the opposite?
|
||||
// I'm leaning towards the "no interrupts with mask cleared" interpretation, but I'm not 100%
|
||||
// convinced. CIM & SIM at the moment are implemented with this interpretation (see also
|
||||
// NO_ISR_WITH_IM_CLEARED macro below).
|
||||
|
||||
#include "emu.h"
|
||||
#include "debugger.h"
|
||||
#include "hphybrid.h"
|
||||
|
||||
// Define this to have "IM cleared" == "No interrupt recognition"
|
||||
#define NO_ISR_WITH_IM_CLEARED
|
||||
|
||||
enum {
|
||||
HPHYBRID_A,
|
||||
HPHYBRID_B,
|
||||
@ -58,6 +79,7 @@ enum {
|
||||
#define HPHYBRID_STS_BIT 13 // Status flag
|
||||
#define HPHYBRID_FLG_BIT 14 // "Flag" flag
|
||||
#define HPHYBRID_DC_BIT 15 // Decimal carry
|
||||
#define HPHYBRID_IM_BIT 16 // Interrupt mask
|
||||
|
||||
#define HPHYBRID_IV_MASK 0xfff0 // IV mask
|
||||
|
||||
@ -512,6 +534,7 @@ UINT16 hp_hybrid_cpu_device::execute_one_sub(UINT16 opcode)
|
||||
memmove(&m_reg_PA[ 0 ] , &m_reg_PA[ 1 ] , HPHYBRID_INT_LVLS);
|
||||
m_pa_changed_func((UINT8)CURRENT_PA);
|
||||
}
|
||||
BIT_CLR(m_flags, HPHYBRID_IM_BIT);
|
||||
}
|
||||
tmp = RM(AEC_CASE_C , m_reg_R--) + (opcode & 0x1f);
|
||||
return BIT(opcode , 5) ? tmp - 0x20 : tmp;
|
||||
@ -878,6 +901,21 @@ UINT16 hp_hybrid_cpu_device::get_skip_addr_sc(UINT16 opcode , UINT16& v , unsign
|
||||
return get_skip_addr(opcode , val);
|
||||
}
|
||||
|
||||
UINT16 hp_hybrid_cpu_device::get_skip_addr_sc(UINT16 opcode , UINT32& v , unsigned n)
|
||||
{
|
||||
bool val = BIT(v , n);
|
||||
|
||||
if (BIT(opcode , 7)) {
|
||||
if (BIT(opcode , 6)) {
|
||||
BIT_SET(v , n);
|
||||
} else {
|
||||
BIT_CLR(v , n);
|
||||
}
|
||||
}
|
||||
|
||||
return get_skip_addr(opcode , val);
|
||||
}
|
||||
|
||||
void hp_hybrid_cpu_device::do_pw(UINT16 opcode)
|
||||
{
|
||||
UINT16 tmp;
|
||||
@ -969,7 +1007,7 @@ void hp_hybrid_cpu_device::do_pw(UINT16 opcode)
|
||||
|
||||
void hp_hybrid_cpu_device::check_for_interrupts(void)
|
||||
{
|
||||
if (!BIT(m_flags , HPHYBRID_INTEN_BIT) || BIT(m_flags , HPHYBRID_IRH_SVC_BIT)) {
|
||||
if (!BIT(m_flags , HPHYBRID_INTEN_BIT) || BIT(m_flags , HPHYBRID_IRH_SVC_BIT) || BIT(m_flags , HPHYBRID_IM_BIT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -979,6 +1017,9 @@ void hp_hybrid_cpu_device::check_for_interrupts(void)
|
||||
// Service high-level interrupt
|
||||
BIT_SET(m_flags , HPHYBRID_IRH_SVC_BIT);
|
||||
irqline = HPHYBRID_IRH;
|
||||
if (BIT(m_flags , HPHYBRID_IRL_SVC_BIT)) {
|
||||
logerror("H pre-empted L @ %06x\n" , m_genpc);
|
||||
}
|
||||
} else if (BIT(m_flags , HPHYBRID_IRL_BIT) && !BIT(m_flags , HPHYBRID_IRL_SVC_BIT)) {
|
||||
// Service low-level interrupt
|
||||
BIT_SET(m_flags , HPHYBRID_IRL_SVC_BIT);
|
||||
@ -1014,12 +1055,20 @@ void hp_hybrid_cpu_device::check_for_interrupts(void)
|
||||
// lasts for 32 cycles
|
||||
m_icount -= 32;
|
||||
|
||||
// Allow special processing in 5061-3001
|
||||
enter_isr();
|
||||
|
||||
// Do a double-indirect JSM IV,I instruction
|
||||
WM(AEC_CASE_C , ++m_reg_R , m_reg_P);
|
||||
m_reg_P = RM(AEC_CASE_I , m_reg_IV + CURRENT_PA);
|
||||
m_reg_I = fetch();
|
||||
}
|
||||
|
||||
void hp_hybrid_cpu_device::enter_isr(void)
|
||||
{
|
||||
// Do nothing special
|
||||
}
|
||||
|
||||
void hp_hybrid_cpu_device::handle_dma(void)
|
||||
{
|
||||
// Patent hints at the fact that terminal count is detected by bit 15 of dmac being 1 after decrementing
|
||||
@ -1428,6 +1477,34 @@ UINT16 hp_5061_3001_cpu_device::execute_no_bpc_ioc(UINT16 opcode)
|
||||
do_mpy();
|
||||
break;
|
||||
|
||||
case 0x7026:
|
||||
// CIM
|
||||
// Undocumented instruction, see beginning of this file
|
||||
// Probably "Clear Interrupt Mask"
|
||||
// No idea at all about exec. time: make it 9 cycles
|
||||
m_icount -= 9;
|
||||
#ifndef NO_ISR_WITH_IM_CLEARED
|
||||
BIT_CLR(m_flags, HPHYBRID_IM_BIT);
|
||||
#else
|
||||
BIT_SET(m_flags, HPHYBRID_IM_BIT);
|
||||
#endif
|
||||
logerror("hp-5061-3001: CIM, P = %06x flags = %05x\n" , m_genpc , m_flags);
|
||||
break;
|
||||
|
||||
case 0x7027:
|
||||
// SIM
|
||||
// Undocumented instruction, see beginning of this file
|
||||
// Probably "Set Interrupt Mask"
|
||||
// No idea at all about exec. time: make it 9 cycles
|
||||
m_icount -= 9;
|
||||
#ifndef NO_ISR_WITH_IM_CLEARED
|
||||
BIT_SET(m_flags, HPHYBRID_IM_BIT);
|
||||
#else
|
||||
BIT_CLR(m_flags, HPHYBRID_IM_BIT);
|
||||
#endif
|
||||
logerror("hp-5061-3001: SIM, P = %06x flags = %05x\n" , m_genpc , m_flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((opcode & 0xfec0) == 0x74c0) {
|
||||
// SDS
|
||||
@ -1576,6 +1653,14 @@ void hp_5061_3001_cpu_device::write_non_common_reg(UINT16 addr , UINT16 v)
|
||||
}
|
||||
}
|
||||
|
||||
void hp_5061_3001_cpu_device::enter_isr(void)
|
||||
{
|
||||
// Set interrupt mask when entering an ISR
|
||||
#ifndef NO_ISR_WITH_IM_CLEARED
|
||||
BIT_SET(m_flags, HPHYBRID_IM_BIT);
|
||||
#endif
|
||||
}
|
||||
|
||||
hp_5061_3011_cpu_device::hp_5061_3011_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: hp_hybrid_cpu_device(mconfig, HP_5061_3011, "HP-5061-3011", tag, owner, clock, "5061-3011", 16)
|
||||
{
|
||||
|
@ -161,7 +161,7 @@ protected:
|
||||
UINT16 m_reg_IV; // Register IV
|
||||
UINT16 m_reg_W; // Register W
|
||||
UINT8 m_reg_PA[ HPHYBRID_INT_LVLS + 1 ]; // Stack of register PA (4 bit-long)
|
||||
UINT16 m_flags; // Flags
|
||||
UINT32 m_flags; // Flags
|
||||
UINT8 m_dmapa; // DMA peripheral address (4 bits)
|
||||
UINT16 m_dmama; // DMA address
|
||||
UINT16 m_dmac; // DMA counter
|
||||
@ -179,8 +179,10 @@ private:
|
||||
UINT32 get_ea(UINT16 opcode);
|
||||
void do_add(UINT16& addend1 , UINT16 addend2);
|
||||
UINT16 get_skip_addr_sc(UINT16 opcode , UINT16& v , unsigned n);
|
||||
UINT16 get_skip_addr_sc(UINT16 opcode , UINT32& v , unsigned n);
|
||||
void do_pw(UINT16 opcode);
|
||||
void check_for_interrupts(void);
|
||||
virtual void enter_isr(void);
|
||||
void handle_dma(void);
|
||||
|
||||
UINT16 RIO(UINT8 pa , UINT8 ic);
|
||||
@ -225,6 +227,8 @@ private:
|
||||
UINT16 m_reg_r26; // R26 register
|
||||
UINT16 m_reg_r27; // R27 register
|
||||
UINT16 m_reg_aec[ HP_REG_R37_ADDR - HP_REG_R32_ADDR + 1 ]; // AEC registers R32-R37
|
||||
|
||||
virtual void enter_isr(void) override;
|
||||
};
|
||||
|
||||
class hp_5061_3011_cpu_device : public hp_hybrid_cpu_device
|
||||
|
@ -355,6 +355,9 @@ static const dis_entry_t dis_table_emc[] = {
|
||||
{0xffff , 0x7b40 , "MRY" , param_none , 0 },
|
||||
{0xffff , 0x7b61 , "MLY" , param_none , 0 },
|
||||
{0xffff , 0x7b8f , "MPY" , param_none , 0 },
|
||||
// *** Undocumented instructions of 5061-3001 ***
|
||||
{0xffff , 0x7026 , "CIM" , param_none , 0 },
|
||||
{0xffff , 0x7027 , "SIM" , param_none , 0 },
|
||||
// *** END ***
|
||||
{0 , 0 , nullptr , nullptr , 0 }
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user