diff options
Diffstat (limited to 'src/devices/cpu/mcs96/i8x9x.cpp')
-rw-r--r-- | src/devices/cpu/mcs96/i8x9x.cpp | 199 |
1 files changed, 139 insertions, 60 deletions
diff --git a/src/devices/cpu/mcs96/i8x9x.cpp b/src/devices/cpu/mcs96/i8x9x.cpp index b550c422642..be53f4075dd 100644 --- a/src/devices/cpu/mcs96/i8x9x.cpp +++ b/src/devices/cpu/mcs96/i8x9x.cpp @@ -12,24 +12,24 @@ #include "i8x9x.h" #include "i8x9xd.h" -i8x9x_device::i8x9x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) : - mcs96_device(mconfig, type, tag, owner, clock, 8, address_map_constructor(FUNC(i8x9x_device::internal_regs), this)), - m_ach_cb{{*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}}, +i8x9x_device::i8x9x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int data_width) : + mcs96_device(mconfig, type, tag, owner, clock, data_width, address_map_constructor(FUNC(i8x9x_device::internal_regs), this)), + m_ach_cb(*this, 0), m_hso_cb(*this), m_serial_tx_cb(*this), - m_in_p0_cb(*this), - m_out_p1_cb(*this), m_in_p1_cb(*this), - m_out_p2_cb(*this), m_in_p2_cb(*this), - base_timer2(0), ad_done(0), hsi_mode(0), hso_command(0), ad_command(0), hso_time(0), ad_result(0), pwm_control(0), - ios0(0), ios1(0), ioc0(0), ioc1(0), sbuf(0), sp_con(0), sp_stat(0), serial_send_buf(0), serial_send_timer(0) + m_in_p0_cb(*this, 0), + m_out_p1_cb(*this), m_in_p1_cb(*this, 0xff), + m_out_p2_cb(*this), m_in_p2_cb(*this, 0xc2), + base_timer2(0), ad_done(0), hsi_mode(0), hsi_status(0), hso_command(0), ad_command(0), hso_active(0), hso_time(0), ad_result(0), pwm_control(0), + port1(0), port2(0), + ios0(0), ios1(0), ioc0(0), ioc1(0), extint(false), + sbuf(0), sp_con(0), sp_stat(0), serial_send_buf(0), serial_send_timer(0), baud_reg(0), brh(false) { for (auto &hso : hso_info) { - hso.active = false; hso.command = 0; hso.time = 0; } - hso_cam_hold.active = false; hso_cam_hold.command = 0; hso_cam_hold.time = 0; } @@ -39,25 +39,15 @@ std::unique_ptr<util::disasm_interface> i8x9x_device::create_disassembler() return std::make_unique<i8x9x_disassembler>(); } -void i8x9x_device::device_resolve_objects() -{ - for (auto &cb : m_ach_cb) - cb.resolve(); - m_hso_cb.resolve_safe(); - m_serial_tx_cb.resolve_safe(); - m_in_p0_cb.resolve_safe(0); - m_out_p1_cb.resolve_safe(); - m_in_p1_cb.resolve_safe(0); - m_out_p2_cb.resolve_safe(); - m_in_p2_cb.resolve_safe(0); -} - void i8x9x_device::device_start() { mcs96_device::device_start(); cycles_scaling = 3; state_add(I8X9X_HSI_MODE, "HSI_MODE", hsi_mode); + state_add<u8>(I8X9X_HSI_STATUS, "HSI_STATUS", + [this]() -> u8 { return hsi_status; }, + [this](u8 data) { hsi_status = (data & 0x55) | (hsi_status & 0xaa); }); state_add(I8X9X_HSO_TIME, "HSO_TIME", hso_time); state_add(I8X9X_HSO_COMMAND, "HSO_COMMAND", hso_command); state_add(I8X9X_AD_COMMAND, "AD_COMMAND", ad_command).mask(0xf); @@ -68,33 +58,36 @@ void i8x9x_device::device_start() state_add(I8X9X_SP_CON, "SP_CON", sp_con).mask(0x1f); state_add(I8X9X_SP_STAT, "SP_STAT", sp_stat).mask(0xe0); state_add(I8X9X_BAUD_RATE, "BAUD_RATE", baud_reg); + if (i8x9x_has_p1()) + state_add<u8>(I8X9X_PORT1, "PORT1", [this]() -> u8 { return port1; }, [this](u8 data) { port1_w(data); }); + state_add<u8>(I8X9X_PORT2, "PORT2", [this]() -> u8 { return port2; }, [this](u8 data) { port2_w(data); }).mask(i8x9x_p2_mask()); state_add(I8X9X_IOC0, "IOC0", ioc0).mask(0xfd); state_add(I8X9X_IOC1, "IOC1", ioc1); - state_add(I8X9X_IOS0, "IOS0", ios0); + state_add<u8>(I8X9X_IOS0, "IOS0", [this]() -> u8 { return ios0; }, [this](u8 data) { ios0_w(data); }); state_add(I8X9X_IOS1, "IOS1", ios1); - for(int i = 0; i < 8; i++) - { - save_item(NAME(hso_info[i].active), i); - save_item(NAME(hso_info[i].command), i); - save_item(NAME(hso_info[i].time), i); - } - save_item(NAME(hso_cam_hold.active)); + save_item(STRUCT_MEMBER(hso_info, command)); + save_item(STRUCT_MEMBER(hso_info, time)); save_item(NAME(hso_cam_hold.command)); save_item(NAME(hso_cam_hold.time)); save_item(NAME(base_timer2)); save_item(NAME(ad_done)); save_item(NAME(hsi_mode)); + save_item(NAME(hsi_status)); save_item(NAME(hso_command)); save_item(NAME(ad_command)); + save_item(NAME(hso_active)); save_item(NAME(hso_time)); save_item(NAME(ad_result)); + save_item(NAME(port1)); + save_item(NAME(port2)); save_item(NAME(pwm_control)); save_item(NAME(ios0)); save_item(NAME(ios1)); save_item(NAME(ioc0)); save_item(NAME(ioc1)); + save_item(NAME(extint)); save_item(NAME(sbuf)); save_item(NAME(sp_con)); save_item(NAME(sp_stat)); @@ -107,12 +100,12 @@ void i8x9x_device::device_start() void i8x9x_device::device_reset() { mcs96_device::device_reset(); - for (auto &hso : hso_info) - hso.active = false; - hso_cam_hold.active = false; + hso_active = 0; hso_command = 0; hso_time = 0; timer2_reset(total_cycles()); + port1 = 0xff; + port2 = 0xc1 & i8x9x_p2_mask(); // P2.5 is cleared ios0 = ios1 = 0x00; ioc0 &= 0xaa; ioc1 = (ioc1 & 0xae) | 0x01; @@ -123,21 +116,25 @@ void i8x9x_device::device_reset() sp_stat &= 0x80; serial_send_timer = 0; brh = false; + m_out_p1_cb(0xff); + m_out_p2_cb(0xc1); m_hso_cb(0); } void i8x9x_device::commit_hso_cam() { for(int i=0; i<8; i++) - if(!hso_info[i].active) { + if(!BIT(hso_active, i)) { //logerror("hso cam %02x %04x in slot %d (%04x)\n", hso_command, hso_time, i, PPC); - hso_info[i].active = true; + hso_active |= 1 << i; + if(hso_active == 0xff) + ios0 |= 0x40; hso_info[i].command = hso_command; hso_info[i].time = hso_time; internal_update(total_cycles()); return; } - hso_cam_hold.active = true; + ios0 |= 0xc0; hso_cam_hold.command = hso_command; hso_cam_hold.time = hso_time; } @@ -145,7 +142,9 @@ void i8x9x_device::commit_hso_cam() void i8x9x_device::ad_start(u64 current_time) { ad_result = 8 | (ad_command & 7); - if (m_ach_cb[ad_command & 7].isnull()) + if (!BIT(i8x9x_p0_mask(), ad_command & 7)) + logerror("Analog input on ACH%d does not exist on this device\n", ad_command & 7); + else if (m_ach_cb[ad_command & 7].isunset()) logerror("Analog input on ACH%d not configured\n", ad_command & 7); else ad_result |= m_ach_cb[ad_command & 7]() << 6; @@ -170,7 +169,7 @@ void i8x9x_device::serial_send_done() void i8x9x_device::internal_regs(address_map &map) { - map(0x00, 0x01).lr16("r0", []() -> u16 { return 0; }).nopw(); + map(0x00, 0x01).lr16([] () -> u16 { return 0; }, "r0").nopw(); map(0x02, 0x03).r(FUNC(i8x9x_device::ad_result_r)); // 8-bit access map(0x02, 0x02).w(FUNC(i8x9x_device::ad_command_w)); map(0x03, 0x03).w(FUNC(i8x9x_device::hsi_mode_w)); @@ -230,9 +229,7 @@ void i8x9x_device::hso_command_w(u8 data) u8 i8x9x_device::hsi_status_r() { - if (!machine().side_effects_disabled()) - logerror("read hsi status (%04x)\n", PPC); - return 0x00; + return hsi_status; } void i8x9x_device::sbuf_w(u8 data) @@ -256,7 +253,7 @@ void i8x9x_device::watchdog_w(u8 data) u16 i8x9x_device::timer1_r() { u16 data = timer_value(1, total_cycles()); - if (!machine().side_effects_disabled()) + if (0 && !machine().side_effects_disabled()) logerror("read timer1 %04x (%04x)\n", data, PPC); return data; } @@ -287,29 +284,40 @@ u8 i8x9x_device::port0_r() last = m_in_p0_cb(); logerror("read p0 %02x\n", last); } - return m_in_p0_cb(); + return m_in_p0_cb() & i8x9x_p0_mask(); } void i8x9x_device::port1_w(u8 data) { - logerror("io port 1 %02x (%04x)\n", data, PPC); + if (!i8x9x_has_p1()) + { + logerror("%s: Write %02x to nonexistent port 1\n", machine().describe_context(), data); + return; + } + + port1 = data; m_out_p1_cb(data); } u8 i8x9x_device::port1_r() { - return m_in_p1_cb(); + if (!i8x9x_has_p1()) + return 0xff; + + return m_in_p1_cb() & port1; } void i8x9x_device::port2_w(u8 data) { - logerror("io port 2 %02x (%04x)\n", data, PPC); + data &= 0xe1 & i8x9x_p2_mask(); + port2 = data; m_out_p2_cb(data); } u8 i8x9x_device::port2_r() { - return m_in_p2_cb(); + // P2.0 and P2.5 are for output only (but can be read back despite what Intel claims?) + return (m_in_p2_cb() | 0x25 | ~i8x9x_p2_mask()) & (port2 | (extint ? 0x1e : 0x1a)); } void i8x9x_device::sp_con_w(u8 data) @@ -340,6 +348,14 @@ u8 i8x9x_device::ios0_r() return ios0; } +void i8x9x_device::ios0_w(u8 data) +{ + u8 mask = (data ^ ios0) & 0x3f; + ios0 = (data & 0x3f) | (ios0 & 0xc0); + if (mask != 0) + m_hso_cb(0, data & 0x3f, mask); +} + void i8x9x_device::ioc1_w(u8 data) { ioc1 = data; @@ -392,10 +408,29 @@ void i8x9x_device::timer2_reset(u64 current_time) base_timer2 = current_time; } +void i8x9x_device::set_hsi_state(int pin, bool state) +{ + if(pin == 0 && !BIT(hsi_status, 1) && state) { + if(BIT(ioc1, 1)) { + pending_irq |= IRQ_HSI0; + check_irq(); + } + if((ioc0 & 0x28) == 0x28) + timer2_reset(total_cycles()); + } + + if(state) + hsi_status |= 2 << (pin * 2); + else + hsi_status &= ~(2 << (pin * 2)); +} + void i8x9x_device::trigger_cam(int id, u64 current_time) { hso_cam_entry &cam = hso_info[id]; - cam.active = false; + if(hso_active == 0xff && !BIT(ios0, 7)) + ios0 &= 0xbf; + hso_active &= ~(1 << id); switch(cam.command & 0x0f) { case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: set_hso(1 << (cam.command & 7), BIT(cam.command, 5)); @@ -448,7 +483,7 @@ void i8x9x_device::internal_update(u64 current_time) u16 current_timer2 = timer_value(2, current_time); for(int i=0; i<8; i++) - if(hso_info[i].active) { + if(BIT(hso_active, i)) { u8 cmd = hso_info[i].command; u16 t = hso_info[i].time; if(((cmd & 0x40) && t == current_timer2) || @@ -471,38 +506,82 @@ void i8x9x_device::internal_update(u64 current_time) u64 event_time = 0; for(int i=0; i<8; i++) { - if(!hso_info[i].active && hso_cam_hold.active) { + if(!BIT(hso_active, i) && BIT(ios0, 7)) { hso_info[i] = hso_cam_hold; - hso_cam_hold.active = false; - logerror("%s: hso cam %02x %04x in slot %d from hold\n", tag(), hso_cam_hold.command, hso_cam_hold.time, i); + hso_active |= 1 << i; + ios0 &= 0x7f; + if(hso_active == 0xff) + ios0 |= 0x40; + logerror("hso cam %02x %04x in slot %d from hold\n", hso_cam_hold.command, hso_cam_hold.time, i); } - if(hso_info[i].active) { + if(BIT(hso_active, i)) { u64 new_time = timer_time_until(hso_info[i].command & 0x40 ? 2 : 1, current_time, hso_info[i].time); if(!event_time || new_time < event_time) event_time = new_time; } } - if(ad_done && ad_done < event_time) + if(ad_done && (!event_time || ad_done < event_time)) event_time = ad_done; - if(serial_send_timer && serial_send_timer < event_time) + if(serial_send_timer && (!event_time || serial_send_timer < event_time)) event_time = serial_send_timer; recompute_bcount(event_time); } -c8095_device::c8095_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : - i8x9x_device(mconfig, C8095, tag, owner, clock) +void i8x9x_device::execute_set_input(int linenum, int state) +{ + switch(linenum) { + case EXTINT_LINE: + if(!extint && state && !BIT(ioc1, 1)) { + pending_irq |= IRQ_EXTINT; + check_irq(); + } + extint = state; + break; + + case HSI0_LINE: + set_hsi_state(0, state); + break; + + case HSI1_LINE: + set_hsi_state(1, state); + break; + + case HSI2_LINE: + set_hsi_state(2, state); + break; + + case HSI3_LINE: + set_hsi_state(3, state); + break; + } +} + +c8095_90_device::c8095_90_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + i8x9x_device(mconfig, C8095_90, tag, owner, clock, 16) +{ +} + +n8097bh_device::n8097bh_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + i8x9x_device(mconfig, N8097BH, tag, owner, clock, 16) { } p8098_device::p8098_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : - i8x9x_device(mconfig, P8098, tag, owner, clock) + i8x9x_device(mconfig, P8098, tag, owner, clock, 8) +{ +} + +p8798_device::p8798_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + i8x9x_device(mconfig, P8798, tag, owner, clock, 8) { } -DEFINE_DEVICE_TYPE(C8095, c8095_device, "c8095", "Intel C8095") +DEFINE_DEVICE_TYPE(C8095_90, c8095_90_device, "c8095_90", "Intel C8095-90") +DEFINE_DEVICE_TYPE(N8097BH, n8097bh_device, "n8097bh", "Intel N8097BH") DEFINE_DEVICE_TYPE(P8098, p8098_device, "p8098", "Intel P8098") +DEFINE_DEVICE_TYPE(P8798, p8798_device, "p8798", "Intel P8798") #include "cpu/mcs96/i8x9x.hxx" |