diff options
author | fulivi <fulivi@users.noreply.github.com> | 2020-03-01 20:11:01 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-01 14:11:01 -0500 |
commit | 8b70a55e7df2cffbebdea70272b39234f0add571 (patch) | |
tree | 197112e49f61084eeebafbe9e24dbd5b91b12c53 /src/devices | |
parent | bcefd9527534b1197cd28b45dec4dec95ce3ee50 (diff) |
hp80: HP82939 serial I/O module added (#6366)
* hp80: added HP82939 serial I/O module.
Fixed a small bug in INS8250 that prevented module self-test to pass.
Improved the interrupt handling of hp80 systems.
* hp80: changed scheduling to use "set_perfect_quantum"
Diffstat (limited to 'src/devices')
-rw-r--r-- | src/devices/bus/hp80_io/82939.cpp | 228 | ||||
-rw-r--r-- | src/devices/bus/hp80_io/82939.h | 60 | ||||
-rw-r--r-- | src/devices/bus/hp80_io/hp80_io.cpp | 2 | ||||
-rw-r--r-- | src/devices/machine/1mb5.cpp | 63 | ||||
-rw-r--r-- | src/devices/machine/1mb5.h | 8 | ||||
-rw-r--r-- | src/devices/machine/ins8250.cpp | 32 |
6 files changed, 327 insertions, 66 deletions
diff --git a/src/devices/bus/hp80_io/82939.cpp b/src/devices/bus/hp80_io/82939.cpp new file mode 100644 index 00000000000..a65c375396c --- /dev/null +++ b/src/devices/bus/hp80_io/82939.cpp @@ -0,0 +1,228 @@ +// license:BSD-3-Clause +// copyright-holders: F. Ulivi +/********************************************************************* + + 82939.cpp + + 82939 module (RS232 interface) + + Thanks to Tim Nye & Everett Kaser for dumping the 8049 ROM + + Main reference for this module is: + HP 82939-90001, jun 81, HP82939A Serial Interface - Installation + and Theory of operation manual + +*********************************************************************/ + +#include "emu.h" +#include "82939.h" +#include "coreutil.h" + +// Debugging +#define VERBOSE 0 +#include "logmacro.h" + +// Bit manipulation +namespace { + template<typename T> constexpr T BIT_MASK(unsigned n) + { + return (T)1U << n; + } + + template<typename T> void BIT_SET(T& w , unsigned n) + { + w |= BIT_MASK<T>(n); + } +} + +hp82939_io_card_device::hp82939_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig , HP82939_IO_CARD , tag , owner , clock), + device_hp80_io_interface(mconfig, *this), + m_cpu(*this , "cpu"), + m_translator(*this , "xlator"), + m_rs232(*this , "rs232"), + m_uart(*this , "uart"), + m_sw12(*this , "sw12") +{ +} + +hp82939_io_card_device::~hp82939_io_card_device() +{ +} + +void hp82939_io_card_device::install_read_write_handlers(address_space& space , uint16_t base_addr) +{ + space.install_readwrite_handler(base_addr, base_addr + 1, read8_delegate(*m_translator, FUNC(hp_1mb5_device::cpu_r)), write8_delegate(*m_translator, FUNC(hp_1mb5_device::cpu_w))); +} + +void hp82939_io_card_device::inten() +{ + m_translator->inten(); +} + +void hp82939_io_card_device::clear_service() +{ + m_translator->clear_service(); +} + +static INPUT_PORTS_START(hp82939_port) + PORT_HP80_IO_SC(10) + PORT_START("sw12") + PORT_DIPNAME(0x40 , 0 , "Auto Handshake") + PORT_DIPLOCATION("S1:1") + PORT_DIPSETTING(0x00 , "Ignore") + PORT_DIPSETTING(0x40 , DEF_STR(On)) + PORT_DIPNAME(0x20 , 0 , "Parity tx") + PORT_DIPLOCATION("S2:1") + PORT_DIPSETTING(0x00 , DEF_STR(Off)) + PORT_DIPSETTING(0x20 , DEF_STR(On)) + PORT_DIPNAME(0x10 , 0 , "Parity") + PORT_DIPLOCATION("S2:2") + PORT_DIPSETTING(0x00 , "Odd") + PORT_DIPSETTING(0x10 , "Even") + PORT_DIPNAME(0x08 , 0x08 , "Parity enable") + PORT_DIPLOCATION("S2:3") + PORT_DIPSETTING(0x00 , DEF_STR(Off)) + PORT_DIPSETTING(0x08 , DEF_STR(On)) + PORT_DIPNAME(0x04 , 0 , "Stop bits") + PORT_DIPLOCATION("S2:4") + PORT_DIPSETTING(0x00 , "1") + PORT_DIPSETTING(0x04 , "2") + PORT_DIPNAME(0x03 , 0x02 , "Character size") + PORT_DIPLOCATION("S2:5,6") + PORT_DIPSETTING(0x00 , "5") + PORT_DIPSETTING(0x01 , "6") + PORT_DIPSETTING(0x02 , "7") + PORT_DIPSETTING(0x03 , "8") + PORT_DIPNAME(0x780 , 0x300 , "Baud rate") + PORT_DIPLOCATION("S2:7,8,9,10") + PORT_DIPSETTING(0x000 , "50") + PORT_DIPSETTING(0x080 , "75") + PORT_DIPSETTING(0x100 , "110") + PORT_DIPSETTING(0x180 , "134.5") + PORT_DIPSETTING(0x200 , "150") + PORT_DIPSETTING(0x280 , "200") + PORT_DIPSETTING(0x300 , "300") + PORT_DIPSETTING(0x380 , "600") + PORT_DIPSETTING(0x400 , "1200") + PORT_DIPSETTING(0x480 , "1800") + PORT_DIPSETTING(0x500 , "2000") + PORT_DIPSETTING(0x580 , "2400") + PORT_DIPSETTING(0x600 , "3600") + PORT_DIPSETTING(0x680 , "4800") + PORT_DIPSETTING(0x700 , "7200") + PORT_DIPSETTING(0x780 , "9600") +INPUT_PORTS_END + +ioport_constructor hp82939_io_card_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(hp82939_port); +} + +void hp82939_io_card_device::device_start() +{ +} + +ROM_START(hp82939) + ROM_REGION(0x800 , "cpu" , 0) + ROM_LOAD("1820-2438.bin" , 0 , 0x800 , CRC(3a2f42a2) SHA1(0f6a70eb8981a8a87c7514ce8226ff1af3ac1668)) +ROM_END + +READ8_MEMBER(hp82939_io_card_device::p1_r) +{ + uint8_t res = uint8_t(m_sw12->read() & 0x7f); + + BIT_SET(res , 7); + + return res; +} + +WRITE8_MEMBER(hp82939_io_card_device::p1_w) +{ + if (BIT(data , 7)) { + m_uart->reset(); + } +} + +READ8_MEMBER(hp82939_io_card_device::p2_r) +{ + uint8_t res = uint8_t((m_sw12->read() >> 7) & 0xf); + + if (m_rs232->cts_r()) { + BIT_SET(res , 4); + } + if (m_rs232->dsr_r()) { + BIT_SET(res , 5); + } + // RI always reads 1 + BIT_SET(res , 6); + if (m_rs232->dcd_r()) { + BIT_SET(res , 7); + } + + return res; +} + +READ8_MEMBER(hp82939_io_card_device::cpu_r) +{ + if ((offset & 0x82) == 0x00) { + return m_translator->uc_r(space , offset & 1 , mem_mask); + } else if ((offset & 0x83) == 0x82) { + return m_uart->ins8250_r((offset >> 2) & 7); + } else { + return 0xff; + } +} + +WRITE8_MEMBER(hp82939_io_card_device::cpu_w) +{ + if ((offset & 0x82) == 0x00) { + m_translator->uc_w(space , offset & 1 , data , mem_mask); + } else if ((offset & 0x83) == 0x82) { + m_uart->ins8250_w((offset >> 2) & 7 , data); + } +} + +void hp82939_io_card_device::cpu_io_map(address_map &map) +{ + map.unmap_value_high(); + map(0x00 , 0xff).rw(FUNC(hp82939_io_card_device::cpu_r) , FUNC(hp82939_io_card_device::cpu_w)); +} + +const tiny_rom_entry *hp82939_io_card_device::device_rom_region() const +{ + return ROM_NAME(hp82939); +} + +void hp82939_io_card_device::device_add_mconfig(machine_config &config) +{ + I8049(config, m_cpu, XTAL(5'529'600)); + m_cpu->set_addrmap(AS_IO, &hp82939_io_card_device::cpu_io_map); + m_cpu->t1_in_cb().set("xlator", FUNC(hp_1mb5_device::int_r)); + m_cpu->set_t0_clk_cb("uart" , FUNC(device_t::set_unscaled_clock_int)); + m_cpu->p1_in_cb().set(FUNC(hp82939_io_card_device::p1_r)); + m_cpu->p1_out_cb().set(FUNC(hp82939_io_card_device::p1_w)); + m_cpu->p2_in_cb().set(FUNC(hp82939_io_card_device::p2_r)); + + HP_1MB5(config, m_translator, 0); + m_translator->irl_handler().set(FUNC(hp82939_io_card_device::irl_w)); + m_translator->halt_handler().set(FUNC(hp82939_io_card_device::halt_w)); + m_translator->reset_handler().set_inputline(m_cpu , INPUT_LINE_RESET); + + RS232_PORT(config, m_rs232, default_rs232_devices, nullptr); + + INS8250(config , m_uart , 0); + m_uart->out_int_callback().set_inputline(m_cpu , MCS48_INPUT_IRQ); + m_uart->out_tx_callback().set(m_rs232 , FUNC(rs232_port_device::write_txd)); + m_uart->out_dtr_callback().set(m_rs232 , FUNC(rs232_port_device::write_dtr)); + m_uart->out_rts_callback().set(m_rs232 , FUNC(rs232_port_device::write_rts)); + m_uart->out_out1_callback().set(m_rs232 , FUNC(rs232_port_device::write_spds)); + + m_rs232->rxd_handler().set(m_uart , FUNC(ins8250_device::rx_w)); + m_rs232->dcd_handler().set(m_uart , FUNC(ins8250_device::dcd_w)); + m_rs232->dsr_handler().set(m_uart , FUNC(ins8250_device::dsr_w)); + m_rs232->cts_handler().set(m_uart , FUNC(ins8250_device::cts_w)); +} + +// device type definition +DEFINE_DEVICE_TYPE(HP82939_IO_CARD, hp82939_io_card_device, "hp82939", "HP82939 card") diff --git a/src/devices/bus/hp80_io/82939.h b/src/devices/bus/hp80_io/82939.h new file mode 100644 index 00000000000..6e66bde00fd --- /dev/null +++ b/src/devices/bus/hp80_io/82939.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders: F. Ulivi +/********************************************************************* + + 82939.h + + 82939 module (RS232 interface) + +*********************************************************************/ + +#ifndef MAME_BUS_HP80_IO_82939_H +#define MAME_BUS_HP80_IO_82939_H + +#pragma once + +#include "hp80_io.h" +#include "cpu/mcs48/mcs48.h" +#include "machine/1mb5.h" +#include "machine/ins8250.h" +#include "bus/rs232/rs232.h" + +class hp82939_io_card_device : public device_t, public device_hp80_io_interface +{ +public: + // construction/destruction + hp82939_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + virtual ~hp82939_io_card_device(); + +protected: + virtual void device_start() override; + + // device-level overrides + virtual ioport_constructor device_input_ports() const override; + virtual const tiny_rom_entry *device_rom_region() const override; + virtual void device_add_mconfig(machine_config &config) override; + + virtual void install_read_write_handlers(address_space& space , uint16_t base_addr) override; + + virtual void inten() override; + virtual void clear_service() override; + +private: + required_device<i8049_device> m_cpu; + required_device<hp_1mb5_device> m_translator; + required_device<rs232_port_device> m_rs232; + required_device<ins8250_device> m_uart; + required_ioport m_sw12; + + DECLARE_READ8_MEMBER(p1_r); + DECLARE_WRITE8_MEMBER(p1_w); + DECLARE_READ8_MEMBER(p2_r); + DECLARE_READ8_MEMBER(cpu_r); + DECLARE_WRITE8_MEMBER(cpu_w); + void cpu_io_map(address_map &map); +}; + +// device type definition +DECLARE_DEVICE_TYPE(HP82939_IO_CARD, hp82939_io_card_device) + +#endif // MAME_BUS_HP80_IO_82939_H diff --git a/src/devices/bus/hp80_io/hp80_io.cpp b/src/devices/bus/hp80_io/hp80_io.cpp index 6124a15b80d..86946007419 100644 --- a/src/devices/bus/hp80_io/hp80_io.cpp +++ b/src/devices/bus/hp80_io/hp80_io.cpp @@ -143,8 +143,10 @@ WRITE_LINE_MEMBER(device_hp80_io_interface::halt_w) } #include "82937.h" +#include "82939.h" void hp80_io_slot_devices(device_slot_interface &device) { device.option_add("82937_hpib" , HP82937_IO_CARD); + device.option_add("82939_serial" , HP82939_IO_CARD); } diff --git a/src/devices/machine/1mb5.cpp b/src/devices/machine/1mb5.cpp index 50a3ea59365..8ed4384e3f5 100644 --- a/src/devices/machine/1mb5.cpp +++ b/src/devices/machine/1mb5.cpp @@ -76,26 +76,27 @@ READ8_MEMBER(hp_1mb5_device::cpu_r) case 1: // Read IB res = m_ib; - m_ibf = false; - update_halt(); + if (m_ibf) { + m_ibf = false; + update_halt(); + } break; } - //LOG("RD %u=%02x\n" , offset , res); + LOG("RD %u=%02x\n" , offset , res); return res; } WRITE8_MEMBER(hp_1mb5_device::cpu_w) { - //LOG("WR %u=%02x\n" , offset , data); - bool need_resched = false; + LOG("WR %u=%02x\n" , offset , data); switch (offset) { case 0: // Write CR m_cr = data; - need_resched |= set_reset(BIT(m_cr , 7)); - need_resched |= set_int(!BIT(m_cr , 0)); + set_reset(BIT(m_cr , 7)); + set_int(!BIT(m_cr , 0)); break; case 1: @@ -105,16 +106,11 @@ WRITE8_MEMBER(hp_1mb5_device::cpu_w) update_halt(); break; } - if (need_resched) { - LOG("resched %s\n" , space.device().tag()); - space.device().execute().yield(); - } } READ8_MEMBER(hp_1mb5_device::uc_r) { uint8_t res = 0; - bool need_resched = false; switch (offset) { case 0: @@ -132,14 +128,10 @@ READ8_MEMBER(hp_1mb5_device::uc_r) // Read OB res = m_ob; m_obf = false; - need_resched |= update_halt(); + update_halt(); break; } - if (need_resched) { - LOG("resched %s\n" , space.device().tag()); - space.device().execute().spin(); - } //LOG("RDU %u=%02x\n" , offset , res); return res; } @@ -147,32 +139,25 @@ READ8_MEMBER(hp_1mb5_device::uc_r) WRITE8_MEMBER(hp_1mb5_device::uc_w) { //LOG("WRU %u=%02x SR=%02x\n" , offset , data , m_sr); - bool need_resched = false; switch (offset) { case 0: // Write SR if (!BIT(m_sr , 0) && BIT(data , 0)) { - need_resched |= set_service(true); + set_service(true); } m_sr = data; m_hlten = BIT(m_sr , 7); - if (update_halt() && !m_halt) { - need_resched = true; - } + update_halt(); break; case 1: // Write IB m_ib = data; m_ibf = true; - need_resched |= update_halt(); + update_halt(); break; } - if (need_resched) { - LOG("resched %s\n" , space.device().tag()); - space.device().execute().spin(); - } } READ_LINE_MEMBER(hp_1mb5_device::irl_r) @@ -246,50 +231,38 @@ void hp_1mb5_device::device_reset() m_int_handler(true); } -bool hp_1mb5_device::set_service(bool new_service) +void hp_1mb5_device::set_service(bool new_service) { if (new_service != m_service) { m_service = new_service; - //LOG("irl=%d\n" , m_service); + LOG("irl=%d\n" , m_service); m_irl_handler(m_service); - return true; - } else { - return false; } } -bool hp_1mb5_device::update_halt() +void hp_1mb5_device::update_halt() { bool new_halt = m_hlten && m_obf && !m_ibf; if (new_halt != m_halt) { - //LOG("HALT=%d\n" , new_halt); + LOG("HALT=%d\n" , new_halt); m_halt = new_halt; m_halt_handler(m_halt); - return true; - } else { - return false; } } -bool hp_1mb5_device::set_reset(bool new_reset) +void hp_1mb5_device::set_reset(bool new_reset) { if (new_reset != m_reset) { m_reset = new_reset; m_reset_handler(m_reset); - return true; - } else { - return false; } } -bool hp_1mb5_device::set_int(bool new_int) +void hp_1mb5_device::set_int(bool new_int) { if (new_int != m_cint) { m_cint = new_int; LOG("cint=%d\n" , m_cint); m_int_handler(m_cint); - return true; - } else { - return false; } } diff --git a/src/devices/machine/1mb5.h b/src/devices/machine/1mb5.h index 18f8107896a..351b1f25d6c 100644 --- a/src/devices/machine/1mb5.h +++ b/src/devices/machine/1mb5.h @@ -71,10 +71,10 @@ private: bool m_reset; bool m_halt; - bool set_service(bool new_service); - bool update_halt(); - bool set_reset(bool new_reset); - bool set_int(bool new_int); + void set_service(bool new_service); + void update_halt(); + void set_reset(bool new_reset); + void set_int(bool new_int); }; // device type definition diff --git a/src/devices/machine/ins8250.cpp b/src/devices/machine/ins8250.cpp index 9c6121e9a2d..4dff4f85964 100644 --- a/src/devices/machine/ins8250.cpp +++ b/src/devices/machine/ins8250.cpp @@ -385,8 +385,9 @@ void ins8250_uart_device::ins8250_w(offs_t offset, u8 data) This register can be written, but if you write a 1 bit into any of bits 3 - 0, you could cause an interrupt if the appropriate IER bit is set. + Bits 7 - 4 are read-only. */ - m_regs.msr = data; + m_regs.msr = (m_regs.msr & 0xf0) | (data & 0x0f); if ( m_regs.msr & 0x0f ) trigger_int(COM_INT_PENDING_MODEM_STATUS_REGISTER); @@ -530,27 +531,24 @@ void ns16550_device::tra_complete() void ins8250_uart_device::rcv_complete() { + // According to datasheet (and HP82939 self-test) the received character is always + // extracted and stored in RBR even in case of overrun + receive_register_extract(); if(m_regs.lsr & INS8250_LSR_DR) { m_regs.lsr |= INS8250_LSR_OE; //overrun - trigger_int(COM_INT_PENDING_RECEIVER_LINE_STATUS); - receive_register_reset(); } - else - { - m_regs.lsr |= INS8250_LSR_DR; - receive_register_extract(); - - if (is_receive_framing_error()) - m_regs.lsr |= INS8250_LSR_FE; - if (is_receive_parity_error()) - m_regs.lsr |= INS8250_LSR_PE; - if ((m_regs.lsr & (INS8250_LSR_BI | INS8250_LSR_PE | INS8250_LSR_FE)) != 0) - trigger_int(COM_INT_PENDING_RECEIVER_LINE_STATUS); + m_regs.lsr |= INS8250_LSR_DR; - m_regs.rbr = get_received_char(); - trigger_int(COM_INT_PENDING_RECEIVED_DATA_AVAILABLE); - } + if (is_receive_framing_error()) + m_regs.lsr |= INS8250_LSR_FE; + if (is_receive_parity_error()) + m_regs.lsr |= INS8250_LSR_PE; + if ((m_regs.lsr & (INS8250_LSR_BI | INS8250_LSR_PE | INS8250_LSR_FE | INS8250_LSR_OE)) != 0) + trigger_int(COM_INT_PENDING_RECEIVER_LINE_STATUS); + + m_regs.rbr = get_received_char(); + trigger_int(COM_INT_PENDING_RECEIVED_DATA_AVAILABLE); } void ins8250_uart_device::tra_complete() |