summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices
diff options
context:
space:
mode:
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
commit8b70a55e7df2cffbebdea70272b39234f0add571 (patch)
tree197112e49f61084eeebafbe9e24dbd5b91b12c53 /src/devices
parentbcefd9527534b1197cd28b45dec4dec95ce3ee50 (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.cpp228
-rw-r--r--src/devices/bus/hp80_io/82939.h60
-rw-r--r--src/devices/bus/hp80_io/hp80_io.cpp2
-rw-r--r--src/devices/machine/1mb5.cpp63
-rw-r--r--src/devices/machine/1mb5.h8
-rw-r--r--src/devices/machine/ins8250.cpp32
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()