f2mc16: First pass with working IRQs. [R. Belmont]

This commit is contained in:
arbee 2019-07-24 22:54:45 -04:00
parent 775b486c73
commit 5864e92aa5
5 changed files with 285 additions and 10 deletions

View File

@ -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);
}

View File

@ -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)

View File

@ -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;

View File

@ -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
}

View File

@ -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