hp9825: hp98036 serial I/O module added (#7024)

This commit is contained in:
fulivi 2020-08-01 18:35:59 +02:00 committed by GitHub
parent 9414a219a9
commit 206767bf56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 605 additions and 0 deletions

View File

@ -4096,6 +4096,8 @@ if (BUSES["HP9845_IO"]~=null) then
MAME_DIR .. "src/devices/bus/hp9845_io/98034.h",
MAME_DIR .. "src/devices/bus/hp9845_io/98035.cpp",
MAME_DIR .. "src/devices/bus/hp9845_io/98035.h",
MAME_DIR .. "src/devices/bus/hp9845_io/98036.cpp",
MAME_DIR .. "src/devices/bus/hp9845_io/98036.h",
MAME_DIR .. "src/devices/bus/hp9845_io/98046.cpp",
MAME_DIR .. "src/devices/bus/hp9845_io/98046.h",
MAME_DIR .. "src/devices/bus/hp9845_io/hp9885.cpp",

View File

@ -0,0 +1,505 @@
// license:BSD-3-Clause
// copyright-holders: F. Ulivi
/*********************************************************************
98036.cpp
98036 module (RS232 interface)
Main reference for this module:
HP, 98036A Serial I/O interface installation & service manual
*********************************************************************/
#include "98036.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);
}
}
// device type definitions
DEFINE_DEVICE_TYPE(HP98036_IO_CARD, hp98036_io_card_device, "hp98036" , "HP98036 card")
hp98036_io_card_device::hp98036_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, HP98036_IO_CARD, tag, owner, clock)
, device_hp9845_io_interface(mconfig, *this)
, m_uart(*this , "uart")
, m_clock_gen(*this , "clock_gen")
, m_rs232(*this , "rs232")
, m_s1_input(*this , "s1")
, m_s2_input(*this , "s2")
, m_s3_input(*this , "s3")
, m_jumper_input(*this , "jumper")
, m_loopback_en(*this , "loop")
{
}
hp98036_io_card_device::~hp98036_io_card_device()
{
}
uint16_t hp98036_io_card_device::reg_r(address_space &space, offs_t offset)
{
uint16_t res = 0;
switch (offset) {
case 0:
// R4IN
m_r4_dir = false;
res = m_r4in_data;
break;
case 1:
// R5IN
if (m_tx_int_en) {
BIT_SET(res, 0);
}
if (m_rx_int_en) {
BIT_SET(res, 1);
}
BIT_SET(res, 4);
if (m_int_en) {
BIT_SET(res, 7);
}
break;
case 2:
// R6IN
// Bits 3&4: jumpers
res = (m_jumper_input->read() & 3) << 3;
if (m_loopback) {
res |= m_lineout;
} else {
if (!m_rs232->dcd_r()) {
BIT_SET(res, 0);
}
if (!m_rs232->ri_r()) {
BIT_SET(res, 1);
}
// Bit 2: secondary CD, always 0
}
BIT_SET(res, 5);
BIT_SET(res, 6);
BIT_SET(res, 7);
break;
default:
logerror("Unmapped read @%u\n" , offset);
break;
}
LOG("RD R%u=%02x\n" , offset + 4 , res);
return res;
}
void hp98036_io_card_device::reg_w(address_space &space, offs_t offset, uint16_t data)
{
LOG("WR R%u=%02x\n" , offset + 4 , data);
switch (offset) {
case 0:
// R4OUT
m_r4_dir = true;
m_wrrq = true;
m_r4out_data = data;
uart_wr();
update_flg();
break;
case 1:
// R5OUT
m_uart_cmd = BIT(data , 0);
m_tx_int_en = BIT(data , 1);
m_rx_int_en = BIT(data , 2);
m_int_en = BIT(data , 7);
if (BIT(data , 5)) {
int_reset();
} else {
uart_rd();
uart_wr();
update_irq();
update_flg();
}
break;
case 2:
// R6OUT
m_half_baud = BIT(data , 4);
m_lineout = data & 7;
break;
case 3:
// R7OUT
if (!m_r4_dir) {
m_rdrq = true;
uart_rd();
update_irq();
update_flg();
}
break;
default:
logerror("Unmapped write @%u\n" , offset);
break;
}
}
void hp98036_io_card_device::device_add_mconfig(machine_config &config)
{
I8251(config , m_uart , 0);
m_uart->txd_handler().set(FUNC(hp98036_io_card_device::txd_w));
m_uart->dtr_handler().set(FUNC(hp98036_io_card_device::dtr_w));
m_uart->rts_handler().set(FUNC(hp98036_io_card_device::rts_w));
m_uart->rxrdy_handler().set(FUNC(hp98036_io_card_device::rxrdy_w));
m_uart->txrdy_handler().set(FUNC(hp98036_io_card_device::txrdy_w));
MC14411(config , m_clock_gen , 1.8432_MHz_XTAL);
m_clock_gen->out_f<1>().set(FUNC(hp98036_io_card_device::bit_rate_clock));
m_clock_gen->out_f<3>().set(FUNC(hp98036_io_card_device::bit_rate_clock));
m_clock_gen->out_f<5>().set(FUNC(hp98036_io_card_device::bit_rate_clock));
m_clock_gen->out_f<6>().set(FUNC(hp98036_io_card_device::bit_rate_clock));
m_clock_gen->out_f<7>().set(FUNC(hp98036_io_card_device::bit_rate_clock));
m_clock_gen->out_f<8>().set(FUNC(hp98036_io_card_device::bit_rate_clock));
m_clock_gen->out_f<9>().set(FUNC(hp98036_io_card_device::bit_rate_clock));
m_clock_gen->out_f<11>().set(FUNC(hp98036_io_card_device::bit_rate_clock));
m_clock_gen->out_f<13>().set(FUNC(hp98036_io_card_device::bit_rate_clock));
m_clock_gen->out_f<14>().set(FUNC(hp98036_io_card_device::bit_rate_clock));
m_clock_gen->out_f<12>().set(FUNC(hp98036_io_card_device::slow_clock));
RS232_PORT(config , m_rs232 , default_rs232_devices , nullptr);
m_rs232->rxd_handler().set(FUNC(hp98036_io_card_device::rxd_w));
m_rs232->dsr_handler().set(FUNC(hp98036_io_card_device::dsr_w));
m_rs232->cts_handler().set(FUNC(hp98036_io_card_device::cts_w));
}
static INPUT_PORTS_START(hp98036_port)
PORT_HP9845_IO_SC(11)
PORT_START("s1")
PORT_DIPNAME(3 , 3 , "Clock factor")
PORT_DIPLOCATION("S1:1,2")
PORT_DIPSETTING(1 , "x1")
PORT_DIPSETTING(2 , "x16")
PORT_DIPSETTING(3 , "x64")
PORT_DIPNAME(0x0c , 0x0c , "Character length")
PORT_DIPLOCATION("S1:3,4")
PORT_DIPSETTING(0x00 , "5")
PORT_DIPSETTING(0x04 , "6")
PORT_DIPSETTING(0x08 , "7")
PORT_DIPSETTING(0x0c , "8")
PORT_DIPNAME(0x10 , 0 , "Parity enable")
PORT_DIPLOCATION("S1:5")
PORT_DIPSETTING(0x00 , DEF_STR(Off))
PORT_DIPSETTING(0x10 , DEF_STR(On))
PORT_DIPNAME(0x20 , 0 , "Parity")
PORT_DIPLOCATION("S1:6")
PORT_DIPSETTING(0x00 , "Odd")
PORT_DIPSETTING(0x20 , "Even")
PORT_DIPNAME(0xc0 , 0xc0 , "Stop bits")
PORT_DIPLOCATION("S1:7,8")
PORT_DIPSETTING(0x40 , "1")
PORT_DIPSETTING(0x80 , "1.5")
PORT_DIPSETTING(0xc0 , "2")
PORT_START("s2")
PORT_DIPNAME(1 , 1 , "CTS")
PORT_DIPLOCATION("S2:1")
PORT_DIPSETTING(0 , "Device controlled")
PORT_DIPSETTING(1 , "Always active")
PORT_START("s3")
PORT_CONFNAME(0xf , 6 , "Baud rate")
PORT_CONFSETTING(0 , "9600")
PORT_CONFSETTING(1 , "4800")
PORT_CONFSETTING(2 , "2400")
PORT_CONFSETTING(3 , "1800")
PORT_CONFSETTING(4 , "1200")
PORT_CONFSETTING(5 , "600")
PORT_CONFSETTING(6 , "300")
PORT_CONFSETTING(7 , "150")
PORT_CONFSETTING(8 , "110")
PORT_CONFSETTING(9 , "75")
PORT_START("jumper")
PORT_CONFNAME(1 , 0 , "J1")
PORT_CONFSETTING(0 , DEF_STR(Off))
PORT_CONFSETTING(1 , DEF_STR(On))
PORT_CONFNAME(2 , 0 , "J2")
PORT_CONFSETTING(0 , DEF_STR(Off))
PORT_CONFSETTING(2 , DEF_STR(On))
PORT_START("loop")
PORT_CONFNAME(1 , 0 , "Test loopback")
PORT_CONFSETTING(0 , DEF_STR(Off))
PORT_CONFSETTING(1 , DEF_STR(On))
INPUT_PORTS_END
ioport_constructor hp98036_io_card_device::device_input_ports() const
{
return INPUT_PORTS_NAME(hp98036_port);
}
void hp98036_io_card_device::device_start()
{
save_item(NAME(m_init_state));
save_item(NAME(m_irq));
save_item(NAME(m_int_en));
save_item(NAME(m_tx_int_en));
save_item(NAME(m_rx_int_en));
save_item(NAME(m_txrdy));
save_item(NAME(m_rxrdy));
save_item(NAME(m_wrrq));
save_item(NAME(m_rdrq));
save_item(NAME(m_uart_cmd));
save_item(NAME(m_uart_wr_mode));
save_item(NAME(m_flg));
save_item(NAME(m_half_baud));
save_item(NAME(m_baud_div));
save_item(NAME(m_r4_dir));
save_item(NAME(m_r4in_data));
save_item(NAME(m_r4out_data));
save_item(NAME(m_lineout));
}
void hp98036_io_card_device::device_reset()
{
sts_w(true);
ioport_value baud_sel = m_s3_input->read();
m_clock_gen->timer_enable(mc14411_device::TIMER_F1 , baud_sel == 0);
m_clock_gen->timer_enable(mc14411_device::TIMER_F3 , baud_sel == 1);
m_clock_gen->timer_enable(mc14411_device::TIMER_F5 , baud_sel == 2);
m_clock_gen->timer_enable(mc14411_device::TIMER_F6 , baud_sel == 3);
m_clock_gen->timer_enable(mc14411_device::TIMER_F7 , baud_sel == 4);
m_clock_gen->timer_enable(mc14411_device::TIMER_F8 , baud_sel == 5);
m_clock_gen->timer_enable(mc14411_device::TIMER_F9 , baud_sel == 6);
m_clock_gen->timer_enable(mc14411_device::TIMER_F11 , baud_sel == 7);
m_clock_gen->timer_enable(mc14411_device::TIMER_F13 , baud_sel == 8);
m_clock_gen->timer_enable(mc14411_device::TIMER_F14 , baud_sel == 9);
m_loopback = m_loopback_en->read() != 0;
if (!m_loopback && BIT(m_s2_input->read() , 0)) {
m_uart->write_cts(0);
}
int_reset();
}
WRITE_LINE_MEMBER(hp98036_io_card_device::bit_rate_clock)
{
if (m_half_baud) {
if (state) {
m_baud_div = !m_baud_div;
m_uart->write_txc(m_baud_div);
m_uart->write_rxc(m_baud_div);
}
} else {
m_uart->write_txc(state);
m_uart->write_rxc(state);
}
}
WRITE_LINE_MEMBER(hp98036_io_card_device::slow_clock)
{
switch (m_init_state) {
case 0:
// Reset
if (state) {
m_init_state++;
}
break;
case 1:
// Write mode word
if (state) {
m_init_state++;
} else {
write_uart(true , uint8_t(m_s1_input->read()));
}
break;
case 2:
// Write default control word
if (state) {
m_init_state++;
update_flg();
} else {
write_uart(true , 0x05);
}
break;
default:
break;
}
}
WRITE_LINE_MEMBER(hp98036_io_card_device::txd_w)
{
if (m_loopback) {
m_uart->write_rxd(state);
} else {
m_rs232->write_txd(state);
}
}
WRITE_LINE_MEMBER(hp98036_io_card_device::dtr_w)
{
if (m_loopback) {
m_uart->write_dsr(state);
} else {
m_rs232->write_dtr(state);
}
}
WRITE_LINE_MEMBER(hp98036_io_card_device::rts_w)
{
if (m_loopback) {
m_uart->write_cts(state);
} else {
m_rs232->write_rts(state);
}
}
WRITE_LINE_MEMBER(hp98036_io_card_device::txrdy_w)
{
if (m_txrdy != state) {
m_txrdy = state;
LOG("txrdy %d\n" , m_txrdy);
uart_wr();
update_irq();
update_flg();
}
}
WRITE_LINE_MEMBER(hp98036_io_card_device::rxrdy_w)
{
if (m_rxrdy != state) {
m_rxrdy = state;
LOG("rxrdy %d\n" , m_rxrdy);
uart_rd();
update_irq();
update_flg();
}
}
WRITE_LINE_MEMBER(hp98036_io_card_device::rxd_w)
{
if (!m_loopback) {
m_uart->write_rxd(state);
}
}
WRITE_LINE_MEMBER(hp98036_io_card_device::dsr_w)
{
if (!m_loopback) {
m_uart->write_dsr(state);
}
}
WRITE_LINE_MEMBER(hp98036_io_card_device::cts_w)
{
if (!m_loopback && !BIT(m_s2_input->read() , 0)) {
m_uart->write_cts(state);
}
}
void hp98036_io_card_device::int_reset()
{
m_init_state = 0;
m_r4in_data = 0;
m_r4out_data = 0;
m_wrrq = false;
m_rdrq = false;
m_int_en = false;
m_tx_int_en = false;
m_rx_int_en = false;
m_uart_cmd = false;
m_uart_wr_mode = true;
m_half_baud = false;
m_lineout = 0;
m_clock_gen->rate_select_w(0);
m_flg = true; // Ensure update in update_flg
update_flg();
m_irq = true; // Ensure update in update_irq
update_irq();
m_uart->reset();
}
void hp98036_io_card_device::update_flg()
{
bool new_flg = (m_init_state == 3) && (!m_wrrq || m_tx_int_en) && (!m_rdrq || m_rx_int_en);
if (m_flg != new_flg) {
m_flg = new_flg;
LOG("FLG %d\n" , m_flg);
flg_w(m_flg);
}
}
void hp98036_io_card_device::update_irq()
{
bool new_irq = m_int_en && ((m_tx_int_en && m_txrdy) || (m_rx_int_en && !m_rdrq));
if (m_irq != new_irq) {
m_irq = new_irq;
LOG("IRQ %d\n" , m_irq);
irq_w(m_irq);
}
}
void hp98036_io_card_device::uart_rd()
{
if (m_rdrq && (m_rxrdy || m_uart_cmd)) {
m_rdrq = false;
m_r4in_data = m_uart->read(m_uart_cmd);
LOG("uart rd%d=%02x\n" , m_uart_cmd , m_r4in_data);
update_flg();
}
}
void hp98036_io_card_device::uart_wr()
{
if (m_wrrq && (m_txrdy || m_uart_cmd)) {
m_wrrq = false;
write_uart(m_uart_cmd , m_r4out_data);
update_flg();
}
}
void hp98036_io_card_device::write_uart(bool cmd , uint8_t data)
{
if (cmd && m_uart_wr_mode) {
// Capture bits 1 & 0 of mode word (clock factor) and
// adjust rate selection in clock generator
// Mode word RSB/RSA Factor
// 0 0 0 0 -- INVALID --
// 0 1 0 0 x1
// 1 0 1 0 x16
// 1 1 1 1 x64
m_clock_gen->rate_select_w((BIT(data , 1) ? mc14411_device::RSB : 0) | ((BIT(data , 1) && BIT(data , 0)) ? mc14411_device::RSA : 0));
LOG("RS %u\n" , data & 3);
}
if (cmd) {
if (BIT(data , 6)) {
m_uart_wr_mode = !m_uart_wr_mode;
} else {
m_uart_wr_mode = false;
}
}
LOG("uart wr%d=%02x\n" , cmd , data);
m_uart->write(cmd , data);
}

View File

@ -0,0 +1,96 @@
// license:BSD-3-Clause
// copyright-holders: F. Ulivi
/*********************************************************************
98036.h
98036 module (RS232 interface)
*********************************************************************/
#ifndef MAME_BUS_HP9845_IO_98036_H
#define MAME_BUS_HP9845_IO_98036_H
#pragma once
#include "hp9845_io.h"
#include "machine/i8251.h"
#include "machine/mc14411.h"
#include "bus/rs232/rs232.h"
class hp98036_io_card_device : public device_t, public device_hp9845_io_interface
{
public:
// construction/destruction
hp98036_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual ~hp98036_io_card_device();
virtual uint16_t reg_r(address_space &space, offs_t offset) override;
virtual void reg_w(address_space &space, offs_t offset, uint16_t data) override;
protected:
// device-level overrides
virtual void device_add_mconfig(machine_config &config) override;
virtual ioport_constructor device_input_ports() const override;
virtual void device_start() override;
virtual void device_reset() override;
private:
required_device<i8251_device> m_uart;
required_device<mc14411_device> m_clock_gen;
required_device<rs232_port_device> m_rs232;
required_ioport m_s1_input;
required_ioport m_s2_input;
required_ioport m_s3_input;
required_ioport m_jumper_input;
required_ioport m_loopback_en;
DECLARE_WRITE_LINE_MEMBER(bit_rate_clock);
DECLARE_WRITE_LINE_MEMBER(slow_clock);
DECLARE_WRITE_LINE_MEMBER(txd_w);
DECLARE_WRITE_LINE_MEMBER(dtr_w);
DECLARE_WRITE_LINE_MEMBER(rts_w);
DECLARE_WRITE_LINE_MEMBER(txrdy_w);
DECLARE_WRITE_LINE_MEMBER(rxrdy_w);
DECLARE_WRITE_LINE_MEMBER(rxd_w);
DECLARE_WRITE_LINE_MEMBER(dsr_w);
DECLARE_WRITE_LINE_MEMBER(cts_w);
// State of initialization FSM
// State U11A-Q U11B-Q
// 0 0 0
// 1 1 0 Load mode word
// 2 1 1 Load control word
// 3 0 1 Done
uint8_t m_init_state;
bool m_irq; // U9-2
bool m_int_en; // U10-2
bool m_tx_int_en; // U10-10
bool m_rx_int_en; // U10-7
bool m_txrdy; // U31-15
bool m_rxrdy; // U31-14
bool m_wrrq; // U19-13
bool m_rdrq; // U19-7
bool m_uart_cmd; // U10-15
bool m_uart_wr_mode;// U17-15
bool m_flg; // U9-10
bool m_half_baud; // U21-13
bool m_baud_div; // U21-1
bool m_r4_dir; // U19-4
bool m_loopback;
uint8_t m_r4in_data; // U29, U30
uint8_t m_r4out_data; // U26, U27
uint8_t m_lineout; // U28
void int_reset();
void update_flg();
void update_irq();
void uart_rd();
void uart_wr();
void write_uart(bool cmd , uint8_t data);
};
// device type definitions
DECLARE_DEVICE_TYPE(HP98036_IO_CARD, hp98036_io_card_device)
#endif // MAME_BUS_HP9845_IO_98036_H

View File

@ -12,6 +12,7 @@
#include "hp9845_io.h"
#include "98032.h"
#include "98035.h"
#include "98036.h"
#include "98034.h"
#include "98046.h"
@ -36,6 +37,7 @@ hp9845_io_slot_device::hp9845_io_slot_device(const machine_config &mconfig, cons
option_add("98032_gpio" , HP98032_IO_CARD);
option_add("98034_hpib" , HP98034_IO_CARD);
option_add("98035_rtc" , HP98035_IO_CARD);
option_add("98036" , HP98036_IO_CARD);
option_add("98046" , HP98046_IO_CARD);
set_default_option(nullptr);
set_fixed(false);