mirror of
https://github.com/holub/mame
synced 2025-04-24 09:20:02 +03:00
f2mc16: First pass with working IRQs. [R. Belmont]
This commit is contained in:
parent
775b486c73
commit
5864e92aa5
@ -105,6 +105,12 @@ void f2mc16_device::device_reset()
|
||||
m_dpr = 0x01;
|
||||
m_dtb = 0;
|
||||
|
||||
for (int &entry : m_vector_level)
|
||||
{
|
||||
entry = 7;
|
||||
}
|
||||
m_outstanding_irqs = 0;
|
||||
|
||||
m_pc = read_16_vector(0xffffdc);
|
||||
m_pcb = read_8_vector(0xffffde);
|
||||
|
||||
@ -205,12 +211,23 @@ void f2mc16_device::execute_run()
|
||||
{
|
||||
while (m_icount > 0)
|
||||
{
|
||||
if (m_outstanding_irqs)
|
||||
{
|
||||
int cpulevel = m_ps >> 13;
|
||||
|
||||
for (int irq = 0; irq < 256; irq++)
|
||||
{
|
||||
if (m_vector_level[irq] < cpulevel)
|
||||
{
|
||||
take_irq(irq, m_vector_level[irq]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u8 opcode = read_8((m_pcb<<16) | m_pc);
|
||||
|
||||
debugger_instruction_hook((m_pcb<<16) | m_pc);
|
||||
|
||||
// m_icount--;
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00: // NOP
|
||||
@ -322,8 +339,39 @@ void f2mc16_device::execute_run()
|
||||
m_icount -= 2;
|
||||
break;
|
||||
|
||||
// ASRW A
|
||||
case 0x0e:
|
||||
// stream << "ASRW A";
|
||||
m_tmp16 = m_acc & 0xffff;
|
||||
|
||||
// T is set if either carry or T are set beforehand
|
||||
if ((m_ps & F_C) || (m_ps & F_T))
|
||||
{
|
||||
m_ps |= F_T;
|
||||
}
|
||||
// C becomes the previous LSB
|
||||
m_ps &= ~F_C;
|
||||
if (m_tmp16 & 1)
|
||||
{
|
||||
m_ps |= F_C;
|
||||
}
|
||||
|
||||
if (m_tmp16 & 0x8000)
|
||||
{
|
||||
m_tmp16 >>= 1;
|
||||
m_tmp16 |= 0x8000;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tmp16 >>= 1;
|
||||
m_tmp16 &= ~0x8000;
|
||||
}
|
||||
setNZ_16(m_tmp16);
|
||||
|
||||
m_acc &= 0xffff0000;
|
||||
m_acc |= m_tmp16;
|
||||
|
||||
m_pc++;
|
||||
m_icount -= 2;
|
||||
break;
|
||||
|
||||
// LSRW A
|
||||
@ -633,8 +681,13 @@ void f2mc16_device::execute_run()
|
||||
m_icount -= 2;
|
||||
break;
|
||||
|
||||
// NOT A
|
||||
case 0x37:
|
||||
// stream << "NOT A";
|
||||
m_acc ^= 0xff;
|
||||
setNZ_8(m_acc & 0xff);
|
||||
m_ps &= ~F_V;
|
||||
m_pc++;
|
||||
m_icount -= 2;
|
||||
break;
|
||||
|
||||
// ADDW A, #imm16
|
||||
@ -697,8 +750,13 @@ void f2mc16_device::execute_run()
|
||||
m_icount -= 2;
|
||||
break;
|
||||
|
||||
// NOTW A
|
||||
case 0x3f:
|
||||
// stream << "NOTW A";
|
||||
m_acc ^= 0xffff;
|
||||
setNZ_16(m_acc & 0xffff);
|
||||
m_ps &= ~F_V;
|
||||
m_pc++;
|
||||
m_icount -= 2;
|
||||
break;
|
||||
|
||||
// MOV A, dir
|
||||
@ -1004,8 +1062,44 @@ void f2mc16_device::execute_run()
|
||||
// stream << "RET";
|
||||
break;
|
||||
|
||||
// RETI
|
||||
case 0x6b:
|
||||
// stream << "RETI";
|
||||
// there's an IRQ chaining facility, let's do it
|
||||
if (m_outstanding_irqs)
|
||||
{
|
||||
int cpulevel = m_ps >> 13;
|
||||
|
||||
for (int irq = 0; irq < 256; irq++)
|
||||
{
|
||||
if (m_vector_level[irq] < cpulevel)
|
||||
{
|
||||
m_ps = read_16((m_ssb << 16) | m_ssp);
|
||||
m_ps |= F_S;
|
||||
m_ps &= ~0x7000;
|
||||
m_ps |= (m_vector_level[irq] & 7) << 13;
|
||||
|
||||
u32 uVecAddr = 0xfffffc - (irq * 4);
|
||||
m_pc = read_16(uVecAddr);
|
||||
m_pcb = read_8(uVecAddr + 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ps = pull_16_ssp();
|
||||
m_pc = pull_16_ssp();
|
||||
m_tmp16 = pull_16_ssp();
|
||||
m_pcb = m_tmp16 & 0xff;
|
||||
m_dtb = m_tmp16 >> 8;
|
||||
m_tmp16 = pull_16_ssp();
|
||||
m_adb = m_tmp16 & 0xff;
|
||||
m_dpr = m_tmp16 >> 8;
|
||||
m_acc = 0;
|
||||
m_acc = pull_16_ssp();
|
||||
m_acc |= (pull_16_ssp() << 16);
|
||||
m_icount -= 17;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6c: // bit operation instructions
|
||||
@ -2111,10 +2205,9 @@ void f2mc16_device::opcodes_ea76(u8 operand)
|
||||
m_icount -= 10;
|
||||
break;
|
||||
|
||||
// ORW A, @RWx
|
||||
// ORW A, RWx
|
||||
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
|
||||
m_tmp16 = read_rwX(operand & 7);
|
||||
m_tmp16 = read_16(getRWbank(operand & 7, m_tmp16));
|
||||
m_acc |= m_tmp16;
|
||||
setNZ_16(m_acc & 0xffff);
|
||||
m_ps &= ~F_V;
|
||||
@ -2169,3 +2262,38 @@ void f2mc16_device::opcodes_ea78(u8 operand)
|
||||
void f2mc16_device::execute_set_input(int inputnum, int state)
|
||||
{
|
||||
}
|
||||
|
||||
void f2mc16_device::set_irq(int vector, int level)
|
||||
{
|
||||
m_outstanding_irqs++;
|
||||
m_vector_level[vector] = level;
|
||||
//printf("set_irq: vec %d level %d\n", vector, level);
|
||||
}
|
||||
|
||||
void f2mc16_device::clear_irq(int vector)
|
||||
{
|
||||
m_outstanding_irqs--;
|
||||
m_vector_level[vector] = 7;
|
||||
//printf("clear_irq: vec %d\n", vector);
|
||||
}
|
||||
|
||||
// note: this function must not use m_tmp16 unless you change RETI
|
||||
void f2mc16_device::take_irq(int vector, int level)
|
||||
{
|
||||
//printf("take_irq: vector %d, level %d, old PC = %02x%04x\n", vector, level, m_pcb, m_pc);
|
||||
push_16_ssp(m_acc>>16);
|
||||
push_16_ssp(m_acc & 0xffff);
|
||||
push_16_ssp((m_dpr<<8) | m_adb);
|
||||
push_16_ssp((m_dtb<<8) | m_pcb);
|
||||
push_16_ssp(m_pc);
|
||||
push_16_ssp(m_ps);
|
||||
|
||||
m_ps |= F_S;
|
||||
m_ps &= ~0x7000;
|
||||
m_ps |= (level & 7) << 13;
|
||||
|
||||
u32 uVecAddr = 0xfffffc - (vector * 4);
|
||||
m_pc = read_16(uVecAddr);
|
||||
m_pcb = read_8(uVecAddr + 2);
|
||||
//printf("New PC = %02x%04x\n", m_pcb, m_pc);
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
class f2mc16_device : public cpu_device
|
||||
{
|
||||
public:
|
||||
friend class mb9061x_device;
|
||||
|
||||
enum
|
||||
{
|
||||
F2MC16_PC, F2MC16_PS, F2MC16_USP, F2MC16_SSP, F2MC16_ACC,
|
||||
@ -223,6 +225,12 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
inline void push_16_ssp(u16 val)
|
||||
{
|
||||
m_ssp-=2;
|
||||
write_16((m_ssb << 16) | m_ssp, val);
|
||||
}
|
||||
|
||||
inline void push_32(u32 val)
|
||||
{
|
||||
if (m_ps & F_S)
|
||||
@ -271,6 +279,14 @@ private:
|
||||
return rv;
|
||||
}
|
||||
|
||||
inline u16 pull_16_ssp()
|
||||
{
|
||||
u16 rv = read_16((m_ssb << 16) | m_ssp);
|
||||
m_ssp += 2;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
inline u32 pull_32()
|
||||
{
|
||||
u32 rv = 0;
|
||||
@ -431,6 +447,13 @@ private:
|
||||
void opcodes_ea76(u8 operand);
|
||||
void opcodes_ea77(u8 operand);
|
||||
void opcodes_ea78(u8 operand);
|
||||
|
||||
void set_irq(int vector, int level);
|
||||
void clear_irq(int vector);
|
||||
void take_irq(int vector, int level);
|
||||
|
||||
int m_vector_level[256];
|
||||
int m_outstanding_irqs;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(F2MC16, f2mc16_device)
|
||||
|
@ -1192,7 +1192,7 @@ offs_t f2mc16_disassembler::disassemble(std::ostream &stream, offs_t pc, const d
|
||||
break;
|
||||
|
||||
case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
|
||||
util::stream_format(stream, "ORW A, @RW%d", (operand & 0x1));
|
||||
util::stream_format(stream, "ORW A, RW%d", (operand & 0x1));
|
||||
bytes = 2;
|
||||
break;
|
||||
|
||||
|
@ -39,6 +39,9 @@ mb9061x_device::mb9061x_device(const machine_config &mconfig, device_type type,
|
||||
void mb9061x_device::device_start()
|
||||
{
|
||||
f2mc16_device::device_start();
|
||||
|
||||
m_tbtc_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mb9061x_device::tbtc_tick), this));
|
||||
m_tbtc_timer->adjust(attotime::never);
|
||||
}
|
||||
|
||||
|
||||
@ -65,6 +68,8 @@ void mb9061x_device::execute_set_input(int inputnum, int state)
|
||||
/* MB90610 - "Evaluation device" with extra RAM */
|
||||
void mb90610_device::mb90610_map(address_map &map)
|
||||
{
|
||||
map(0x00a9, 0x00a9).rw(FUNC(mb9061x_device::tbtc_r), FUNC(mb9061x_device::tbtc_w));
|
||||
map(0x00b0, 0x00bf).rw(FUNC(mb9061x_device::intc_r), FUNC(mb9061x_device::intc_w));
|
||||
map(0x0100, 0x10ff).ram(); // 4K of internal RAM from 0x100 to 0x1100
|
||||
}
|
||||
|
||||
@ -78,9 +83,107 @@ mb90610_device::mb90610_device(const machine_config &mconfig, device_type type,
|
||||
{
|
||||
}
|
||||
|
||||
/* TBTC: timebase counter */
|
||||
enum
|
||||
{
|
||||
TBTC_TEST = 0x80, // test, must always write 1
|
||||
TBTC_TBIE = 0x10, // interrupt enable
|
||||
TBTC_TBOF = 0x08, // expire flag
|
||||
TBTC_TBR = 0x04, // write 0 to restart
|
||||
TBTC_TBC1 = 0x02, // rate select bit 1
|
||||
TBTC_TBC0 = 0x01 // rate select bit 0
|
||||
};
|
||||
|
||||
READ8_MEMBER(mb9061x_device::tbtc_r)
|
||||
{
|
||||
return m_tbtc;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(mb9061x_device::tbtc_w)
|
||||
{
|
||||
static const float periods[4] = { 1.024, 4.096, 16.384, 131.072 };
|
||||
|
||||
//printf("%02x to TBTC\n", data);
|
||||
if ((!(data & TBTC_TBR)) || ((data & (TBTC_TBC1|TBTC_TBC0)) != (m_tbtc & (TBTC_TBC1|TBTC_TBC0))))
|
||||
{
|
||||
m_tbtc_timer->adjust(attotime(0, ATTOSECONDS_IN_MSEC(periods[data & (TBTC_TBC1|TBTC_TBC0)])));
|
||||
|
||||
if (!(data & TBTC_TBR))
|
||||
{
|
||||
intc_clear_irq(11, 0x22);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(data & TBTC_TBOF) && (m_tbtc & TBTC_TBOF))
|
||||
{
|
||||
intc_clear_irq(11, 0x22);
|
||||
}
|
||||
|
||||
m_tbtc = data;
|
||||
}
|
||||
|
||||
/* INTC: Interrupt controller */
|
||||
TIMER_CALLBACK_MEMBER(mb9061x_device::tbtc_tick)
|
||||
{
|
||||
//printf("TBTC tick\n");
|
||||
m_tbtc_timer->adjust(attotime::never);
|
||||
m_tbtc |= TBTC_TBOF;
|
||||
if (m_tbtc & TBTC_TBIE)
|
||||
{
|
||||
intc_trigger_irq(11, 0x22);
|
||||
}
|
||||
}
|
||||
|
||||
READ8_MEMBER(mb9061x_device::intc_r)
|
||||
{
|
||||
return m_intc[offset];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(mb9061x_device::intc_w)
|
||||
{
|
||||
//printf("INTC ICR %d to %02x\n", offset, data);
|
||||
m_intc[offset] = data;
|
||||
}
|
||||
|
||||
void mb9061x_device::intc_trigger_irq(int icr, int vector)
|
||||
{
|
||||
int level = m_intc[icr] & 7;
|
||||
|
||||
//printf("trigger_irq: ICR %d, level %d\n", icr, level);
|
||||
|
||||
// Extended Intelligent I/O Service?
|
||||
if (m_intc[icr] & 8)
|
||||
{
|
||||
fatalerror("MB9061X: ICR %d (vector %x) calls for EI2OS, not implemented\n", icr, vector);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (level != 7)
|
||||
{
|
||||
set_irq(vector, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mb9061x_device::intc_clear_irq(int icr, int vector)
|
||||
{
|
||||
int level = m_intc[icr] & 7;
|
||||
|
||||
// Make sure this isn't the Extended Intelligent I/O Service
|
||||
if (!(m_intc[icr] & 8))
|
||||
{
|
||||
if (level != 7)
|
||||
{
|
||||
clear_irq(vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* MB90611 - Production version of this series */
|
||||
void mb90611_device::mb90611_map(address_map &map)
|
||||
{
|
||||
map(0x00a9, 0x00a9).rw(FUNC(mb9061x_device::tbtc_r), FUNC(mb9061x_device::tbtc_w));
|
||||
map(0x00b0, 0x00bf).rw(FUNC(mb9061x_device::intc_r), FUNC(mb9061x_device::intc_w));
|
||||
map(0x0100, 0x04ff).ram(); // 1K of internal RAM from 0x100 to 0x500
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,12 @@ class mb9061x_device : public f2mc16_device
|
||||
public:
|
||||
const address_space_config m_program_config;
|
||||
|
||||
// interrupts handled by the interrupt controller
|
||||
enum
|
||||
{
|
||||
ICR0 = 0, ICR1, ICR2, ICR3, ICR4, ICR5, ICR6, ICR7, ICR8, ICR9, ICR10, ICR11, ICR12, ICR13, ICR14, ICR15
|
||||
};
|
||||
|
||||
protected:
|
||||
// construction/destruction
|
||||
mb9061x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor internal_map);
|
||||
@ -36,6 +42,21 @@ protected:
|
||||
virtual space_config_vector memory_space_config() const override;
|
||||
|
||||
private:
|
||||
// TBC
|
||||
TIMER_CALLBACK_MEMBER(tbtc_tick);
|
||||
READ8_MEMBER(tbtc_r);
|
||||
WRITE8_MEMBER(tbtc_w);
|
||||
|
||||
// INTC
|
||||
READ8_MEMBER(intc_r);
|
||||
WRITE8_MEMBER(intc_w);
|
||||
void intc_trigger_irq(int icr, int vector);
|
||||
void intc_clear_irq(int icr, int vector);
|
||||
|
||||
u8 m_tbtc;
|
||||
emu_timer *m_tbtc_timer;
|
||||
|
||||
u8 m_intc[0x10];
|
||||
};
|
||||
|
||||
class mb90610_device : public mb9061x_device
|
||||
|
Loading…
Reference in New Issue
Block a user