mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
palm: improve interrupt handling
* fix debugger register access * consolidate internal state * add ros selection and bus out callbacks * add internal control instruction handler
This commit is contained in:
parent
8203e170a1
commit
34b7c397c1
@ -8,7 +8,7 @@
|
||||
* - IBM 5100 Maintenance Information Manual, SY31-0405-3, Fourth Edition (October 1979), International Business Machines Corporation
|
||||
*
|
||||
* TODO:
|
||||
* - machine check/interrupts
|
||||
* - machine check
|
||||
* - instruction timing
|
||||
*/
|
||||
|
||||
@ -30,6 +30,8 @@ template <typename T, typename U, typename V> constexpr T IBIT(T x, U n, V w)
|
||||
return BIT(x, sizeof(T) * 8 - n - w, w);
|
||||
}
|
||||
|
||||
static u8 constexpr il_priority[] = { 0, 1, 2, 2, 3, 3, 3, 3 };
|
||||
|
||||
DEFINE_DEVICE_TYPE(PALM, palm_device, "palm", "IBM PALM")
|
||||
|
||||
palm_device::palm_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
|
||||
@ -38,29 +40,41 @@ palm_device::palm_device(machine_config const &mconfig, char const *tag, device_
|
||||
, m_rws_config("rws", ENDIANNESS_BIG, 16, 16)
|
||||
, m_ioc_config("ioc", ENDIANNESS_BIG, 8, 4)
|
||||
, m_iod_config("iod", ENDIANNESS_BIG, 8, 4)
|
||||
, m_getb_bus(*this)
|
||||
, m_select_ros(*this)
|
||||
, m_icount(0)
|
||||
, m_r{}
|
||||
, m_il(0)
|
||||
, m_il_pending(0)
|
||||
, m_irpt_req(0)
|
||||
{
|
||||
}
|
||||
|
||||
enum ff_mask : u8
|
||||
{
|
||||
FF_IPL = 0x80, // initial program load
|
||||
FF_MSS = 0x40, // microprogram storage switch
|
||||
|
||||
FF_IE = 0x08, // interrupt enable
|
||||
FF_IR3 = 0x04, // interrupt request 3
|
||||
FF_IR2 = 0x02, // interrupt request 2
|
||||
FF_IR1 = 0x01, // interrupt request 1
|
||||
|
||||
FF_IR = 0x07, // interrupt request
|
||||
};
|
||||
|
||||
void palm_device::device_start()
|
||||
{
|
||||
set_icountptr(m_icount);
|
||||
|
||||
state_add(STATE_GENPC, "GENPC", m_r[m_il][0]).mask(0xfffe).noshow();
|
||||
state_add(STATE_GENPCBASE, "CURPC", m_r[m_il][0]).mask(0xfffe);
|
||||
state_add(STATE_GENPC, "GENPC", m_pc).noshow();
|
||||
state_add<u16>(STATE_GENPCBASE, "CURPC", [this]() { return m_r[m_il][0] & 0xfffeU; });
|
||||
|
||||
state_add(0, "IL", m_il);
|
||||
for (unsigned i = 0; i < std::size(m_r[m_il]); i++)
|
||||
state_add(i + 1, util::string_format("R%d", i).c_str(), m_r[m_il][i]);
|
||||
state_add<u16>(i + 1, util::string_format("R%d", i).c_str(), [this, i]() { return m_r[m_il][i]; }, [this, i](u16 data) { m_r[m_il][i] = data; });
|
||||
|
||||
save_item(NAME(m_pc));
|
||||
save_item(NAME(m_r));
|
||||
save_item(NAME(m_il));
|
||||
save_item(NAME(m_il_pending));
|
||||
save_item(NAME(m_irpt_req));
|
||||
save_item(NAME(m_ff));
|
||||
|
||||
space(AS_ROS).specific(m_ros);
|
||||
space(AS_RWS).specific(m_rws);
|
||||
@ -72,10 +86,13 @@ void palm_device::device_reset()
|
||||
{
|
||||
space(AS_RWS).install_ram(0, sizeof(m_r) - 1, m_r);
|
||||
|
||||
m_il = 0;
|
||||
// select instruction source
|
||||
m_ff = FF_IPL | FF_MSS;
|
||||
m_select_ros((m_ff & FF_MSS) && !(m_ff & FF_IPL));
|
||||
|
||||
// read initial PC from ROS
|
||||
m_r[m_il][0] = m_ros.read_word(0);
|
||||
m_il = 0;
|
||||
m_pc = m_r[m_il][0] = m_ros.read_word(0);
|
||||
}
|
||||
|
||||
#define Rx r[IBIT(op, 4, 4)]
|
||||
@ -88,13 +105,14 @@ void palm_device::execute_run()
|
||||
{
|
||||
while (m_icount > 0)
|
||||
{
|
||||
// immediately switch to highest pending interrupt level
|
||||
if (m_il != m_il_pending)
|
||||
// handle pending interrupts
|
||||
u8 const il = il_priority[m_ff & FF_IR];
|
||||
if ((m_ff & FF_IE) && m_il != il)
|
||||
{
|
||||
m_il = m_il_pending;
|
||||
m_il = il;
|
||||
|
||||
// notify the debugger
|
||||
if (m_il && machine().debug_flags & DEBUG_FLAG_ENABLED)
|
||||
if (m_il && (machine().debug_flags & DEBUG_FLAG_ENABLED))
|
||||
debug()->interrupt_hook(m_il - 1, m_r[m_il][0] & ~1);
|
||||
}
|
||||
|
||||
@ -133,7 +151,13 @@ void palm_device::execute_run()
|
||||
case 0xf: Ry += (7 - count_leading_ones_32(u32(m_iod.read_byte(DA)) << 24)) * 2; break; // get to register and add
|
||||
}
|
||||
break;
|
||||
case 0x1: m_ioc.write_byte(DA, IMM); break; // control
|
||||
case 0x1:
|
||||
// control
|
||||
if (DA == 0)
|
||||
control(IMM);
|
||||
|
||||
m_ioc.write_byte(DA, IMM);
|
||||
break;
|
||||
case 0x2: Rx = m_rws.read_word(IMM * 2); break; // load halfword direct
|
||||
case 0x3: m_rws.write_word(IMM * 2, Rx); break; // store halfword direct
|
||||
case 0x4:
|
||||
@ -185,6 +209,8 @@ void palm_device::execute_run()
|
||||
}
|
||||
else
|
||||
{
|
||||
m_getb_bus(DA, Ry);
|
||||
|
||||
if (MOD < 0xc)
|
||||
{
|
||||
// get byte
|
||||
@ -201,13 +227,12 @@ void palm_device::execute_run()
|
||||
|
||||
// TODO: average instruction time quoted as 1.75µs (~27 machine cycles)
|
||||
m_icount -= 27;
|
||||
m_pc = r[0];
|
||||
}
|
||||
}
|
||||
|
||||
void palm_device::execute_set_input(int irqline, int state)
|
||||
{
|
||||
u8 const il_priority[] = { 0, 1, 2, 3, 3, 3, 3, 3 };
|
||||
|
||||
switch (irqline)
|
||||
{
|
||||
case INPUT_LINE_NMI:
|
||||
@ -217,12 +242,9 @@ void palm_device::execute_set_input(int irqline, int state)
|
||||
default:
|
||||
// interrupt lines are active low
|
||||
if (!state)
|
||||
m_irpt_req |= 1U << irqline;
|
||||
m_ff |= 1U << irqline;
|
||||
else
|
||||
m_irpt_req &= ~(1U << irqline);
|
||||
|
||||
// update pending interrupt level
|
||||
m_il_pending = il_priority[m_irpt_req & 7];
|
||||
m_ff &= ~(1U << irqline);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -278,3 +300,31 @@ s16 palm_device::modifier(unsigned const modifier) const
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void palm_device::control(u8 data)
|
||||
{
|
||||
LOG("control 0x%02x (%s)\n", data, machine().describe_context());
|
||||
|
||||
// 0 reset controller errors
|
||||
|
||||
// 1: 0=disable interrupts
|
||||
// 2: 0=enable interrupts
|
||||
if (!IBIT(data, 1))
|
||||
m_ff &= ~FF_IE;
|
||||
else if (!IBIT(data, 2))
|
||||
m_ff |= FF_IE;
|
||||
|
||||
// TODO: 3 not used?
|
||||
// 4 not used (0:display & select frame on)
|
||||
|
||||
// 5 state transition
|
||||
if (!IBIT(data, 5))
|
||||
{
|
||||
m_ff &= ~FF_IPL;
|
||||
m_ff ^= FF_MSS;
|
||||
|
||||
m_select_ros((m_ff & FF_MSS) && !(m_ff & FF_IPL));
|
||||
}
|
||||
|
||||
// TODO: 6..7 not used (frame bit #1,2?)
|
||||
}
|
||||
|
@ -20,6 +20,9 @@ public:
|
||||
static unsigned constexpr AS_IOC = AS_IO;
|
||||
static unsigned constexpr AS_IOD = 4;
|
||||
|
||||
auto getb_bus() { return m_getb_bus.bind(); }
|
||||
auto select_ros() { return m_select_ros.bind(); }
|
||||
|
||||
palm_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
|
||||
|
||||
protected:
|
||||
@ -43,6 +46,8 @@ protected:
|
||||
bool condition(unsigned const modifier, u16 const data, u8 const mask) const;
|
||||
s16 modifier(unsigned const modifier) const;
|
||||
|
||||
void control(u8 data);
|
||||
|
||||
private:
|
||||
// address spaces
|
||||
address_space_config const m_ros_config;
|
||||
@ -55,13 +60,16 @@ private:
|
||||
memory_access<4, 0, 0, ENDIANNESS_BIG>::specific m_ioc;
|
||||
memory_access<4, 0, 0, ENDIANNESS_BIG>::specific m_iod;
|
||||
|
||||
devcb_write8 m_getb_bus;
|
||||
devcb_write_line m_select_ros;
|
||||
|
||||
// mame state
|
||||
int m_icount;
|
||||
u16 m_pc;
|
||||
|
||||
u16 m_r[4][16]; // registers
|
||||
u8 m_il; // interrupt level
|
||||
u8 m_il_pending; // pending interrupt level
|
||||
u8 m_irpt_req; // interrupt line state
|
||||
u8 m_ff; // controller flip-flops
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(PALM, palm_device)
|
||||
|
Loading…
Reference in New Issue
Block a user