Hp9845: added 98046 module emulation (#5115)

* hp9845: fixed handling of optional ROMs (nw)

* z80sio: massive enhancement to Z80 SIO driven by HP98046 test sw

* hp9845: implemented the HP98046 serial I/O module
This commit is contained in:
fulivi 2019-05-26 18:00:33 +02:00 committed by R. Belmont
parent ecf043eca1
commit 41c456c3a6
11 changed files with 1624 additions and 350 deletions

View File

@ -3686,6 +3686,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/98046.cpp",
MAME_DIR .. "src/devices/bus/hp9845_io/98046.h",
MAME_DIR .. "src/devices/bus/hp9845_io/hp9885.cpp",
MAME_DIR .. "src/devices/bus/hp9845_io/hp9885.h",
}

View File

@ -0,0 +1,684 @@
// license:BSD-3-Clause
// copyright-holders: F. Ulivi
/*********************************************************************
98046.cpp
98046 module (data communications interface)
Fun fact: I didn't need to dump the fw in 8048 MCU because,
in a way, it's already "dumped" in the test sw. Basically, to
test the correctness of the ROM content, the HP sw reads out the
whole ROM and compares it to the known good image...
Main reference for this module:
HP, 98046B Interface Installation and Service
Test software:
HP, 98046-90449, 98046 Interface Test
(see http://www.hpmuseum.net/display_item.php?sw=324)
*********************************************************************/
#include "emu.h"
#include "98046.h"
// Debugging
#include "logmacro.h"
#define LOG_IFS_MASK (LOG_GENERAL << 1)
#define LOG_IFS(...) LOGMASKED(LOG_IFS_MASK, __VA_ARGS__)
#define LOG_MCU_MASK (LOG_IFS_MASK << 1)
#define LOG_MCU(...) LOGMASKED(LOG_MCU_MASK, __VA_ARGS__)
#define LOG_CPU_MASK (LOG_MCU_MASK << 1)
#define LOG_CPU(...) LOGMASKED(LOG_CPU_MASK, __VA_ARGS__)
#define LOG_SIO_MASK (LOG_CPU_MASK << 1)
#define LOG_SIO(...) LOGMASKED(LOG_SIO_MASK, __VA_ARGS__)
//#undef VERBOSE
//#define VERBOSE (LOG_GENERAL | LOG_MCU_MASK | LOG_CPU_MASK | LOG_SIO_MASK)
// Bit manipulation
namespace {
template<typename T> constexpr T BIT_MASK(unsigned n)
{
return (T)1U << n;
}
template<typename T> void BIT_CLR(T& w , unsigned n)
{
w &= ~BIT_MASK<T>(n);
}
template<typename T> void BIT_SET(T& w , unsigned n)
{
w |= BIT_MASK<T>(n);
}
}
// Timers
enum {
TMR_ID_RXC,
TMR_ID_TXC
};
// device type definition
DEFINE_DEVICE_TYPE(HP98046_IO_CARD, hp98046_io_card_device , "hp98046" , "HP98046 card")
hp98046_io_card_device::hp98046_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: hp9845_io_card_device(mconfig , HP98046_IO_CARD , tag , owner , clock)
, m_cpu(*this , "cpu")
, m_sio(*this , "sio")
, m_rs232(*this , "rs232")
, m_loopback_en(*this , "loop")
{
}
hp98046_io_card_device::~hp98046_io_card_device()
{
}
READ16_MEMBER(hp98046_io_card_device::reg_r)
{
uint16_t res = 0;
switch (offset) {
case 0:
// R4
// Read from rxFIFO
if (!rx_fifo_flag()) {
m_rxfifo_irq = false;
update_irq();
}
res = ~m_rx_fifo.dequeue() & 0x1ff;
// Save bit 8 of new word at output of rx FIFO
if (!m_rx_fifo.empty()) {
m_rx_fifo_out_b8 = BIT(m_rx_fifo.peek() , 8);
}
update_flg();
update_sts();
break;
case 1:
// R5
if (m_rxfifo_overrun) {
BIT_SET(res , 15);
}
BIT_SET(res , 11);
if (m_inten) {
BIT_SET(res , 7);
}
if (!m_r6_r7_pending) {
BIT_SET(res , 0);
}
break;
case 2:
// R6: not mapped
break;
case 3:
// R7: not mapped
break;
default:
break;
}
LOG_CPU("rd R%u=%04x\n" , offset + 4 , res);
return res;
}
WRITE16_MEMBER(hp98046_io_card_device::reg_w)
{
LOG_CPU("wr R%u=%04x\n" , offset + 4 , data);
switch (offset) {
case 0:
// R4
// Write to txFIFO
m_tx_fifo_in = (data ^ 0x00ff) & 0x1ff;
m_tx_fifo_pending = true;
load_tx_fifo();
space.device().execute().yield();
break;
case 1:
// R5
if (BIT(data , 5)) {
// 8048 reset
m_cpu->pulse_input_line(INPUT_LINE_RESET , attotime::zero);
m_inten = false;
} else if (BIT(m_port_2 , 7)) {
// When SIORST is active, inten always sets to 0
m_inten = false;
} else {
m_inten = BIT(data , 7);
}
m_enoutint = BIT(data , 0);
update_irq();
break;
case 2:
// R6
case 3:
// R7
m_r6_r7_select = offset == 3;
m_r6_r7 = ~data & 0xff;
set_r6_r7_pending(true);
break;
default:
break;
}
}
bool hp98046_io_card_device::has_dual_sc() const
{
return true;
}
void hp98046_io_card_device::device_add_mconfig(machine_config &config)
{
I8048(config , m_cpu , 6_MHz_XTAL);
m_cpu->set_addrmap(AS_PROGRAM , &hp98046_io_card_device::cpu_program_map);
m_cpu->set_addrmap(AS_IO , &hp98046_io_card_device::cpu_io_map);
m_cpu->p1_in_cb().set(FUNC(hp98046_io_card_device::p1_r));
m_cpu->p2_out_cb().set(FUNC(hp98046_io_card_device::p2_w));
m_cpu->t1_in_cb().set([this] () { return int(!m_sio_int); });
// Clock to SIO is actually provided by T0 output of CPU
Z80SIO(config , m_sio , 0);
m_sio->out_int_callback().set(FUNC(hp98046_io_card_device::sio_int_w));
m_sio->out_txda_callback().set(FUNC(hp98046_io_card_device::sio_txd_w));
RS232_PORT(config, m_rs232, default_rs232_devices, nullptr);
m_rs232->rxd_handler().set(FUNC(hp98046_io_card_device::rs232_rxd_w));
m_rs232->dcd_handler().set(FUNC(hp98046_io_card_device::rs232_dcd_w));
m_rs232->dsr_handler().set(FUNC(hp98046_io_card_device::rs232_dsr_w));
m_rs232->cts_handler().set(FUNC(hp98046_io_card_device::rs232_cts_w));
config.m_minimum_quantum = attotime::from_hz(5000);
}
static INPUT_PORTS_START(hp98046_port)
PORT_START("SC")
PORT_CONFNAME(0xf , 4 - HP9845_IO_FIRST_SC , "Select Codes")
PORT_CONFSETTING(1 , "2 3")
PORT_CONFSETTING(3 , "4 5")
PORT_CONFSETTING(5 , "6 7")
PORT_CONFSETTING(7 , "8 9")
PORT_CONFSETTING(9 , "10 11")
PORT_CONFSETTING(11 , "12 13")
PORT_START("loop")
PORT_CONFNAME(1 , 0 , "ESK loopback")
PORT_CONFSETTING(0 , DEF_STR(Off))
PORT_CONFSETTING(1 , DEF_STR(On))
INPUT_PORTS_END
ioport_constructor hp98046_io_card_device::device_input_ports() const
{
return INPUT_PORTS_NAME(hp98046_port);
}
ROM_START(hp98046)
ROM_REGION(0x400, "cpu" , 0)
ROM_LOAD("1820-2431.bin" , 0 , 0x400 , CRC(e6a068d6) SHA1(d19c35b18fae52b841060ed879f860fd2cae3482))
ROM_END
const tiny_rom_entry *hp98046_io_card_device::device_rom_region() const
{
return ROM_NAME(hp98046);
}
void hp98046_io_card_device::device_start()
{
m_ram = std::make_unique<uint8_t[]>(1024);
save_pointer(NAME(m_ram) , 1024);
m_rxc_timer = timer_alloc(TMR_ID_RXC);
m_txc_timer = timer_alloc(TMR_ID_TXC);
}
void hp98046_io_card_device::device_reset()
{
m_port_2 = 0;
m_inten = false;
m_enoutint = false;
update_flg();
update_sts();
update_irq();
m_loopback = m_loopback_en->read() != 0;
// Ensure timers are loaded the 1st time BRGs are configured
m_rxc_sel = ~0;
m_txc_sel = ~0;
m_rxc_timer->reset();
m_txc_timer->reset();
}
void hp98046_io_card_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch (id) {
case TMR_ID_RXC:
m_rxc = !m_rxc;
m_sio->rxca_w(m_rxc);
if (m_loopback && (m_txc_sel == 0 || m_txc_sel == 1)) {
m_sio->txca_w(m_rxc);
m_sio->txcb_w(m_rxc);
m_sio->rxcb_w(m_rxc);
}
break;
case TMR_ID_TXC:
m_txc = !m_txc;
m_sio->txca_w(m_txc);
m_sio->txcb_w(m_txc);
m_sio->rxcb_w(m_txc);
if (m_loopback && (m_rxc_sel == 0 || m_rxc_sel == 1)) {
m_sio->rxca_w(m_txc);
}
break;
}
}
void hp98046_io_card_device::cpu_program_map(address_map &map)
{
map.unmap_value_high();
map(0x000 , 0x3ff).rom();
map(0x400 , 0x7ff).r(FUNC(hp98046_io_card_device::ram_r));
}
void hp98046_io_card_device::cpu_io_map(address_map &map)
{
map(0 , 0xff).rw(FUNC(hp98046_io_card_device::cpu_r) , FUNC(hp98046_io_card_device::cpu_w));
}
READ8_MEMBER(hp98046_io_card_device::ram_r)
{
return m_ram[ offset ];
}
READ8_MEMBER(hp98046_io_card_device::cpu_r)
{
if (BIT(m_port_2 , 2)) {
return m_ram[ (offset & 0xff) | (uint16_t(m_port_2 & 3) << 8) ];
} else if (BIT(offset , 2)) {
uint8_t res = ~0;
switch (offset & 3) {
case 0:
// xxxx'x100: read from tx FIFO
res = uint8_t(m_tx_fifo.dequeue());
load_tx_fifo();
update_flg();
update_irq();
break;
case 1:
// xxxx'x101: read HS
res = get_hs_input();
break;
case 2:
// xxxx'x110: clear FIFOs
m_tx_fifo.clear();
m_rx_fifo.clear();
load_tx_fifo();
update_flg();
update_sts();
update_irq();
break;
case 3:
// xxxx'x111: read r6/r7
res = m_r6_r7;
set_r6_r7_pending(false);
break;
}
LOG_MCU("CPU R @%02x=%02x\n" , offset , res);
return res;
} else {
uint8_t res = m_sio->cd_ba_r(offset & 3);
LOG_SIO("SIO R @%u=%02x\n" , offset & 3 , res);
return res;
}
}
WRITE8_MEMBER(hp98046_io_card_device::cpu_w)
{
if (BIT(m_port_2 , 2)) {
m_ram[ (offset & 0xff) | (uint16_t(m_port_2 & 3) << 8) ] = data;
} else if (BIT(offset , 2)) {
LOG_MCU("CPU W @%02x=%02x\n" , offset , data);
switch (offset & 3) {
case 0:
// xxxx'x100: write to rx FIFO
if (BIT(offset , 6)) {
if (m_rx_fifo.full()) {
m_rxfifo_overrun = true;
}
uint16_t w = data;
if (BIT(offset , 7)) {
BIT_SET(w , 8);
}
// If enqueuing first word, store bit 8
if (m_rx_fifo.empty()) {
m_rx_fifo_out_b8 = BIT(w , 8);
}
m_rx_fifo.enqueue(w);
}
if (rx_fifo_flag()) {
m_rxfifo_irq = true;
} else {
// Logic of A1U21A 'LS109 JK FF (J=A3 K/=A4)
switch (offset & 0x18) {
case 0x00:
m_rxfifo_irq = false;
break;
case 0x08:
m_rxfifo_irq = !m_rxfifo_irq;
break;
case 0x10:
break;
case 0x18:
m_rxfifo_irq = true;
break;
}
}
update_flg();
update_sts();
update_irq();
break;
case 1:
// xxxx'x101: write HS
m_hs_out = data;
update_hs_out();
break;
case 2:
// xxxx'x110: clear rx FIFO overrun
m_rxfifo_overrun = false;
update_sts();
break;
case 3:
// xxxx'x111: write to BRGs
set_brgs(data);
break;
}
} else {
LOG_SIO("%.6f SIO W @%u=%02x\n" , machine().time().as_double() , offset & 3 , data);
m_sio->cd_ba_w(offset & 3 , data);
}
}
READ8_MEMBER(hp98046_io_card_device::p1_r)
{
uint8_t res = 0;
// b7: b8 of word @ txFIFO head
if (BIT(m_tx_fifo.peek() , 8)) {
BIT_SET(res , 7);
}
// b6: rxFIFO overrun
if (!m_rxfifo_overrun) {
BIT_SET(res , 6);
}
// b5: rxFIFO not empty
if (!m_rx_fifo.empty()) {
BIT_SET(res , 5);
}
// b4: R6(0)/R7(1)
if (m_r6_r7_select) {
BIT_SET(res , 4);
}
// b3: tx FIFO flag
if (tx_fifo_flag()) {
BIT_SET(res , 3);
}
// b2: tx FIFO not empty
if (!m_tx_fifo.empty()) {
BIT_SET(res , 2);
}
// b1: rx FIFO flag
if (rx_fifo_flag()) {
BIT_SET(res , 1);
}
// b0: rx FIFO not full
if (!m_rx_fifo.full()) {
BIT_SET(res , 0);
}
//LOG("p1=%02x\n" , res);
return res;
}
WRITE8_MEMBER(hp98046_io_card_device::p2_w)
{
LOG_MCU("p2=%02x\n" , data);
uint8_t diff = data ^ m_port_2;
m_port_2 = data;
if (BIT(diff , 7)) {
if (BIT(m_port_2 , 7)) {
m_sio->reset();
set_r6_r7_pending(true);
}
update_hs_out();
}
if (BIT(diff , 6)) {
update_flg();
}
if (BIT(diff , 5)) {
update_sts();
}
}
WRITE_LINE_MEMBER(hp98046_io_card_device::sio_int_w)
{
if (m_sio_int != state) {
LOG_SIO("SIO int=%d\n" , state);
}
m_sio_int = state;
}
WRITE_LINE_MEMBER(hp98046_io_card_device::sio_txd_w)
{
m_sio->rxb_w(state);
if (m_loopback) {
m_sio->rxa_w(state);
} else {
m_rs232->write_txd(state);
}
}
WRITE_LINE_MEMBER(hp98046_io_card_device::rs232_rxd_w)
{
if (!m_loopback) {
m_sio->rxa_w(state);
}
}
WRITE_LINE_MEMBER(hp98046_io_card_device::rs232_dcd_w)
{
if (!m_loopback) {
m_sio->dcda_w(state);
}
}
WRITE_LINE_MEMBER(hp98046_io_card_device::rs232_dsr_w)
{
if (!m_loopback) {
m_sio->dcdb_w(state);
}
}
WRITE_LINE_MEMBER(hp98046_io_card_device::rs232_cts_w)
{
if (!m_loopback) {
m_sio->ctsa_w(state);
}
}
bool hp98046_io_card_device::rx_fifo_flag() const
{
return m_rx_fifo.queue_length() >= 16;
}
bool hp98046_io_card_device::tx_fifo_flag() const
{
return m_tx_fifo.queue_length() >= 16;
}
void hp98046_io_card_device::update_flg()
{
bool flg_e = !m_r6_r7_pending && !m_tx_fifo.full() && BIT(m_port_2 , 6);
bool flg_o = !m_r6_r7_pending && !m_rx_fifo.empty();
LOG_IFS("FLG e/o=%d/%d\n" , flg_e , flg_o);
flg_w(flg_e);
flg_nextsc_w(flg_o);
}
void hp98046_io_card_device::update_sts()
{
bool sts_e = !BIT(m_port_2 , 5);
bool sts_o = !m_rxfifo_overrun && m_rx_fifo_out_b8;
LOG_IFS("STS e/o=%d/%d\n" , sts_e , sts_o);
sts_w(sts_e);
sts_nextsc_w(sts_o);
}
void hp98046_io_card_device::update_irq()
{
bool irq = m_inten && !m_r6_r7_pending && (m_rxfifo_irq || (m_enoutint && !tx_fifo_flag()));
bool irq_e = irq && !m_rxfifo_irq;
bool irq_o = irq && m_rxfifo_irq;
LOG_IFS("IRQ e/o=%d/%d\n" , irq_e , irq_o);
irq_w(irq_e);
irq_nextsc_w(irq_o);
}
void hp98046_io_card_device::update_hs_out()
{
if (BIT(m_port_2 , 7)) {
m_actual_hs_out = ~0;
} else {
m_actual_hs_out = m_hs_out;
}
if (m_loopback) {
m_sio->ctsa_w(BIT(m_actual_hs_out , 4));
m_sio->dcda_w(BIT(m_actual_hs_out , 3));
m_sio->ctsb_w(BIT(m_actual_hs_out , 2));
m_sio->dcdb_w(BIT(m_actual_hs_out , 1));
} else {
m_rs232->write_dtr(BIT(m_actual_hs_out , 5));
m_rs232->write_rts(BIT(m_actual_hs_out , 4));
// b3 (A2J1-13) not mapped
// b2 (A2J1-15) not mapped (Data Rate Select)
// b1 (A2J1-30) not mapped (Secondary RTS)
// b0 (A2J1-24) not mapped
}
}
void hp98046_io_card_device::load_tx_fifo()
{
if (m_tx_fifo_pending && !m_tx_fifo.full()) {
m_tx_fifo.enqueue(m_tx_fifo_in);
m_tx_fifo_pending = false;
update_flg();
update_irq();
}
}
void hp98046_io_card_device::set_r6_r7_pending(bool state)
{
m_r6_r7_pending = state || BIT(m_port_2 , 7);
m_cpu->set_input_line(MCS48_INPUT_IRQ , m_r6_r7_pending ? ASSERT_LINE : CLEAR_LINE);
update_flg();
update_irq();
}
uint8_t hp98046_io_card_device::get_hs_input() const
{
uint8_t res = 0xc1;
if (m_loopback) {
// DTR looped back into RI
if (BIT(m_actual_hs_out , 5)) {
BIT_SET(res , 5);
}
// RTS looped back into CTS
if (BIT(m_actual_hs_out , 4)) {
BIT_SET(res , 4);
}
// A2J1-13 looped back into DCD
if (BIT(m_actual_hs_out , 3)) {
BIT_SET(res , 3);
}
// DRS looped back into SCD
if (BIT(m_actual_hs_out , 2)) {
BIT_SET(res , 2);
}
// SRTS looped back into DSR
if (BIT(m_actual_hs_out , 1)) {
BIT_SET(res , 1);
}
} else {
if (m_rs232->ri_r()) {
BIT_SET(res , 5);
}
if (m_rs232->cts_r()) {
BIT_SET(res , 4);
}
if (m_rs232->dcd_r()) {
BIT_SET(res , 3);
}
// SCD always 1
BIT_SET(res , 2);
if (m_rs232->dsr_r()) {
BIT_SET(res , 1);
}
}
return res;
}
// Frequencies of HD4702 BRGs
// All frequencies are doubled here because the timers expire twice per RxC/TxC period
static const unsigned brg_freq[] = {
// Sel: frequency Divisor
// ============================
0, // 0: external clock -
0, // 1: external clock -
1600, // 2: 50 x16 /3072
2400, // 3: 75 x16 /2048
4267, // 4: ~134.5 x16 /1152
6400, // 5: 200 x16 /768
19200, // 6: 600 x16 /256
76800, // 7: 2400 x16 /64
307200, // 8: 9600 x16 /16
153600, // 9: 4800 x16 /32
57600, // 10: 1800 x16 / 256/3
38400, // 11: 1200 x16 /128
76800, // 12: 2400 x16 /64
9600, // 13: 300 x16 /512
4800, // 14: 150 x16 /1024
3491 // 15: ~110 x16 /1408
};
void hp98046_io_card_device::set_brgs(uint8_t sel)
{
LOG_MCU("BRG=%02x\n" , sel);
uint8_t new_rxc_sel = (sel >> 4) & 0xf;
uint8_t new_txc_sel = sel & 0xf;
if (new_rxc_sel != m_rxc_sel) {
m_rxc_sel = new_rxc_sel;
auto period = attotime::from_hz(brg_freq[ m_rxc_sel ]);
m_rxc_timer->adjust(period , 0 , period);
}
if (new_txc_sel != m_txc_sel) {
m_txc_sel = new_txc_sel;
auto period = attotime::from_hz(brg_freq[ m_txc_sel ]);
m_txc_timer->adjust(period , 0 , period);
}
}

View File

@ -0,0 +1,103 @@
// license:BSD-3-Clause
// copyright-holders: F. Ulivi
/*********************************************************************
98046.h
98046 module (data communications interface)
*********************************************************************/
#ifndef MAME_BUS_HP9845_IO_98046_H
#define MAME_BUS_HP9845_IO_98046_H
#pragma once
#include "hp9845_io.h"
#include "cpu/mcs48/mcs48.h"
#include "machine/z80sio.h"
#include "bus/rs232/rs232.h"
class hp98046_io_card_device : public hp9845_io_card_device
{
public:
// construction/destruction
hp98046_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual ~hp98046_io_card_device();
virtual DECLARE_READ16_MEMBER(reg_r) override;
virtual DECLARE_WRITE16_MEMBER(reg_w) override;
virtual bool has_dual_sc() const override;
protected:
// device-level overrides
virtual void device_add_mconfig(machine_config &config) override;
virtual ioport_constructor device_input_ports() const override;
virtual const tiny_rom_entry *device_rom_region() const override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
required_device<i8048_device> m_cpu;
required_device<z80sio_device> m_sio;
required_device<rs232_port_device> m_rs232;
required_ioport m_loopback_en;
std::unique_ptr<uint8_t[]> m_ram;
util::fifo<uint16_t , 32> m_tx_fifo; // A1U7
util::fifo<uint16_t , 32> m_rx_fifo; // A1U11
bool m_rx_fifo_out_b8; // Bit 8 of rx FIFO output
uint16_t m_tx_fifo_in; // A1U1 & A1U9-8
bool m_tx_fifo_pending; // A1U18-7
uint8_t m_r6_r7; // A1U2
bool m_r6_r7_pending; // A1U18-9
bool m_r6_r7_select; // A1U18-13
bool m_rxfifo_overrun; // A1U21-9
bool m_rxfifo_irq; // A1U21-6
bool m_inten; // A1U15-2
bool m_enoutint; // A1U15-6
uint8_t m_hs_out; // A2U4
uint8_t m_actual_hs_out; // A2U4 output
bool m_sio_int;
uint8_t m_port_2;
bool m_loopback;
emu_timer *m_rxc_timer;
emu_timer *m_txc_timer;
uint8_t m_rxc_sel;
uint8_t m_txc_sel;
bool m_rxc;
bool m_txc;
void cpu_program_map(address_map &map);
void cpu_io_map(address_map &map);
DECLARE_READ8_MEMBER(ram_r);
DECLARE_READ8_MEMBER(cpu_r);
DECLARE_WRITE8_MEMBER(cpu_w);
DECLARE_READ8_MEMBER(p1_r);
DECLARE_WRITE8_MEMBER(p2_w);
DECLARE_WRITE_LINE_MEMBER(sio_int_w);
DECLARE_WRITE_LINE_MEMBER(sio_txd_w);
DECLARE_WRITE_LINE_MEMBER(rs232_rxd_w);
DECLARE_WRITE_LINE_MEMBER(rs232_dcd_w);
DECLARE_WRITE_LINE_MEMBER(rs232_dsr_w);
DECLARE_WRITE_LINE_MEMBER(rs232_cts_w);
bool rx_fifo_flag() const;
bool tx_fifo_flag() const;
void update_flg();
void update_sts();
void update_irq();
void update_hs_out();
void load_tx_fifo();
void set_r6_r7_pending(bool state);
uint8_t get_hs_input() const;
void set_brgs(uint8_t sel);
};
// device type definitions
DECLARE_DEVICE_TYPE(HP98046_IO_CARD, hp98046_io_card_device)
#endif // MAME_BUS_HP9845_IO_98046_H

View File

@ -13,6 +13,7 @@
#include "98032.h"
#include "98035.h"
#include "98034.h"
#include "98046.h"
// device type definition
DEFINE_DEVICE_TYPE(HP9845_IO_SLOT, hp9845_io_slot_device, "hp98x5_io_slot", "HP98x5 I/O Slot")
@ -26,12 +27,16 @@ hp9845_io_slot_device::hp9845_io_slot_device(const machine_config &mconfig, cons
m_irq_cb_func(*this),
m_sts_cb_func(*this),
m_flg_cb_func(*this),
m_irq_nextsc_cb_func(*this),
m_sts_nextsc_cb_func(*this),
m_flg_nextsc_cb_func(*this),
m_dmar_cb_func(*this)
{
option_reset();
option_add("98032_gpio" , HP98032_IO_CARD);
option_add("98034_hpib" , HP98034_IO_CARD);
option_add("98035_rtc" , HP98035_IO_CARD);
option_add("98046" , HP98046_IO_CARD);
set_default_option(nullptr);
set_fixed(false);
}
@ -45,6 +50,9 @@ void hp9845_io_slot_device::device_start()
m_irq_cb_func.resolve_safe();
m_sts_cb_func.resolve_safe();
m_flg_cb_func.resolve_safe();
m_irq_nextsc_cb_func.resolve_safe();
m_sts_nextsc_cb_func.resolve_safe();
m_flg_nextsc_cb_func.resolve_safe();
m_dmar_cb_func.resolve_safe();
hp9845_io_card_device *card = dynamic_cast<hp9845_io_card_device*>(get_card_device());
@ -69,6 +77,21 @@ WRITE_LINE_MEMBER(hp9845_io_slot_device::flg_w)
m_flg_cb_func(state);
}
WRITE_LINE_MEMBER(hp9845_io_slot_device::irq_nextsc_w)
{
m_irq_nextsc_cb_func(state);
}
WRITE_LINE_MEMBER(hp9845_io_slot_device::sts_nextsc_w)
{
m_sts_nextsc_cb_func(state);
}
WRITE_LINE_MEMBER(hp9845_io_slot_device::flg_nextsc_w)
{
m_flg_nextsc_cb_func(state);
}
WRITE_LINE_MEMBER(hp9845_io_slot_device::dmar_w)
{
m_dmar_cb_func(state);
@ -87,6 +110,17 @@ int hp9845_io_slot_device::get_rw_handlers(read16_delegate& rhandler , write16_d
}
}
bool hp9845_io_slot_device::has_dual_sc() const
{
hp9845_io_card_device *card = dynamic_cast<hp9845_io_card_device*>(get_card_device());
if (card != nullptr) {
return card->has_dual_sc();
} else {
return false;
}
}
// +---------------------+
// |hp9845_io_card_device|
// +---------------------+
@ -100,6 +134,11 @@ uint8_t hp9845_io_card_device::get_sc(void)
return m_select_code_port->read() + HP9845_IO_FIRST_SC;
}
bool hp9845_io_card_device::has_dual_sc() const
{
return false;
}
hp9845_io_card_device::hp9845_io_card_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock),
device_slot_card_interface(mconfig, *this),
@ -133,6 +172,27 @@ WRITE_LINE_MEMBER(hp9845_io_card_device::flg_w)
}
}
WRITE_LINE_MEMBER(hp9845_io_card_device::irq_nextsc_w)
{
if (m_slot_dev) {
m_slot_dev->irq_nextsc_w(state);
}
}
WRITE_LINE_MEMBER(hp9845_io_card_device::sts_nextsc_w)
{
if (m_slot_dev) {
m_slot_dev->sts_nextsc_w(state);
}
}
WRITE_LINE_MEMBER(hp9845_io_card_device::flg_nextsc_w)
{
if (m_slot_dev) {
m_slot_dev->flg_nextsc_w(state);
}
}
WRITE_LINE_MEMBER(hp9845_io_card_device::dmar_w)
{
if (m_slot_dev) {

View File

@ -46,22 +46,33 @@ public:
auto irq() { return m_irq_cb_func.bind(); }
auto sts() { return m_sts_cb_func.bind(); }
auto flg() { return m_flg_cb_func.bind(); }
auto irq_nextsc() { return m_irq_nextsc_cb_func.bind(); }
auto sts_nextsc() { return m_sts_nextsc_cb_func.bind(); }
auto flg_nextsc() { return m_flg_nextsc_cb_func.bind(); }
auto dmar() { return m_dmar_cb_func.bind(); }
// irq/sts/flg/dmar signal handlers for card devices
DECLARE_WRITE_LINE_MEMBER(irq_w);
DECLARE_WRITE_LINE_MEMBER(sts_w);
DECLARE_WRITE_LINE_MEMBER(flg_w);
DECLARE_WRITE_LINE_MEMBER(irq_nextsc_w);
DECLARE_WRITE_LINE_MEMBER(sts_nextsc_w);
DECLARE_WRITE_LINE_MEMBER(flg_nextsc_w);
DECLARE_WRITE_LINE_MEMBER(dmar_w);
// getter for r/w handlers
// return value is SC (negative if no card is attached to slot)
int get_rw_handlers(read16_delegate& rhandler , write16_delegate& whandler);
bool has_dual_sc() const;
private:
devcb_write_line m_irq_cb_func;
devcb_write_line m_sts_cb_func;
devcb_write_line m_flg_cb_func;
devcb_write_line m_irq_nextsc_cb_func;
devcb_write_line m_sts_nextsc_cb_func;
devcb_write_line m_flg_nextsc_cb_func;
devcb_write_line m_dmar_cb_func;
};
@ -77,6 +88,8 @@ public:
// SC getter
uint8_t get_sc(void);
virtual bool has_dual_sc() const;
protected:
// construction/destruction
hp9845_io_card_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
@ -89,6 +102,9 @@ protected:
DECLARE_WRITE_LINE_MEMBER(irq_w);
DECLARE_WRITE_LINE_MEMBER(sts_w);
DECLARE_WRITE_LINE_MEMBER(flg_w);
DECLARE_WRITE_LINE_MEMBER(irq_nextsc_w);
DECLARE_WRITE_LINE_MEMBER(sts_nextsc_w);
DECLARE_WRITE_LINE_MEMBER(flg_nextsc_w);
DECLARE_WRITE_LINE_MEMBER(dmar_w);
};

View File

@ -41,6 +41,10 @@ hp_optrom_slot_device::hp_optrom_slot_device(const machine_config &mconfig, cons
m_base_addr(0),
m_end_addr(0)
{
option_reset();
option_add_internal("rom", HP_OPTROM_CART);
set_default_option(nullptr);
set_fixed(false);
}
hp_optrom_slot_device::~hp_optrom_slot_device()
@ -125,8 +129,3 @@ std::string hp_optrom_slot_device::get_default_card_software(get_default_card_so
{
return software_get_default_slot("rom");
}
void hp_optrom_slot_devices(device_slot_interface &device)
{
device.option_add_internal("rom", HP_OPTROM_CART);
}

View File

@ -70,6 +70,4 @@ protected:
DECLARE_DEVICE_TYPE(HP_OPTROM_SLOT, hp_optrom_slot_device)
DECLARE_DEVICE_TYPE(HP_OPTROM_CART, hp_optrom_cart_device)
void hp_optrom_slot_devices(device_slot_interface &device);
#endif // MAME_BUS_HP_OPTROMS_HP_OPTROM_H

File diff suppressed because it is too large Load Diff

View File

@ -167,8 +167,19 @@ protected:
enum : uint8_t
{
TX_FLAG_CRC = 1U << 0, // include in checksum calculation
TX_FLAG_FRAMING = 1U << 1, // tranmitting framing bits
TX_FLAG_SPECIAL = 1U << 2 // transmitting checksum or abort sequence
TX_FLAG_FRAMING = 1U << 1, // transmitting framing bits
TX_FLAG_ABORT_TX= 1U << 2, // transmitting abort sequence
TX_FLAG_CRC_TX = 1U << 3, // transmitting CRC value
TX_FLAG_DATA_TX = 1U << 4 // transmitting frame data
};
// Sync/SDLC FSM states
enum
{
SYNC_FSM_HUNT = 0, // Hunt for start sync/flag
SYNC_FSM_EVICT = 1, // Evict flag from sync SR
SYNC_FSM_1ST_CHAR = 2, // Receiving 1st character
SYNC_FSM_IN_FRAME = 3 // Inside a frame
};
z80sio_channel(
@ -191,7 +202,6 @@ protected:
int get_clock_mode();
int get_rx_word_length();
int get_tx_word_length() const;
int get_tx_word_length(uint8_t data) const;
// receiver state
int m_rx_fifo_depth;
@ -200,26 +210,37 @@ protected:
int m_rx_clock; // receive clock line state
int m_rx_count; // clocks until next sample
bool m_dlyd_rxd; // delayed RxD
int m_rx_bit; // receive data bit (0 = start bit, 1 = LSB, etc.)
int m_rx_bit_limit; // bits to assemble for next character (sync/SDLC)
int m_rx_sync_fsm; // Sync/SDLC FSM state
uint8_t m_rx_one_cnt; // SDLC: counter to delete stuffed zeros
uint16_t m_rx_sr; // receive shift register
uint8_t m_rx_sync_sr; // rx sync SR
uint8_t m_rx_crc_delay; // rx CRC delay SR
uint16_t m_rx_crc; // rx CRC accumulator
bool m_rx_crc_en; // rx CRC enabled
bool m_rx_parity; // accumulated parity
int m_rx_first; // first character received
int m_rx_break; // receive break condition
int m_rxd;
int m_sh; // sync hunt
// transmitter state
uint8_t m_tx_data;
int m_tx_clock; // transmit clock line state
int m_tx_count; // clocks until next bit transition
int m_tx_bits; // remaining bits in shift register
int m_tx_parity; // parity bit position or zero if disabled
uint16_t m_tx_sr; // transmit shift register
bool m_tx_phase; // phase of bit clock
bool m_tx_parity; // accumulated parity
bool m_tx_in_pkt; // In active part of packet (sync mode)
bool m_tx_forced_sync; // Force sync/flag
uint32_t m_tx_sr; // transmit shift register
uint16_t m_tx_crc; // calculated transmit checksum
uint8_t m_tx_hist; // transmit history (for bitstuffing)
uint8_t m_tx_flags; // internal transmit control flags
uint8_t m_tx_delay; // 2-bit tx delay (4 half-bits)
uint8_t m_all_sent_delay; // SR for all-sent delay
int m_txd;
int m_dtr; // data terminal ready
@ -247,17 +268,24 @@ private:
bool transmit_allowed() const;
void receive_enabled();
void enter_hunt_mode();
void sync_receive();
void sdlc_receive();
void receive_data();
void queue_received(uint16_t data, uint32_t error);
void advance_rx_fifo();
uint8_t get_special_rx_mask() const;
bool is_tx_idle() const;
void transmit_enable();
void transmit_complete();
void async_tx_setup();
void sync_tx_sr_empty();
void tx_setup(uint16_t data, int bits, int parity, bool framing, bool special);
void tx_setup(uint16_t data, int bits, bool framing, bool crc_tx, bool abort_tx);
void tx_setup_idle();
bool get_tx_empty() const;
void set_tx_empty(bool prev_state, bool new_state);
void update_crc(uint16_t& crc , bool bit);
void reset_ext_status();
void read_ext();

View File

@ -479,6 +479,10 @@ void hp9845_base_state::device_reset()
if ((sc = m_io_slot[i]->get_rw_handlers(rhandler , whandler)) >= 0) {
logerror("Install R/W handlers for slot %u @ SC = %d\n", i, sc);
m_ppu->space(AS_IO).install_readwrite_handler(sc * 4 , sc * 4 + 3 , rhandler , whandler);
if (m_io_slot[ i ]->has_dual_sc()) {
logerror("Installing dual SC\n");
m_ppu->space(AS_IO).install_readwrite_handler(sc * 4 + 4 , sc * 4 + 7 , rhandler , whandler);
}
}
m_slot_sc[ i ] = sc;
}
@ -668,6 +672,27 @@ void hp9845_base_state::set_flg_slot(unsigned slot , int state)
m_io_sys->set_flg(uint8_t(sc) , state);
}
void hp9845_base_state::set_irq_nextsc_slot(unsigned slot , int state)
{
int sc = m_slot_sc[ slot ];
assert(sc >= 0);
m_io_sys->set_irq(uint8_t(sc + 1) , state);
}
void hp9845_base_state::set_sts_nextsc_slot(unsigned slot , int state)
{
int sc = m_slot_sc[ slot ];
assert(sc >= 0);
m_io_sys->set_sts(uint8_t(sc + 1) , state);
}
void hp9845_base_state::set_flg_nextsc_slot(unsigned slot , int state)
{
int sc = m_slot_sc[ slot ];
assert(sc >= 0);
m_io_sys->set_flg(uint8_t(sc + 1) , state);
}
void hp9845_base_state::set_dmar_slot(unsigned slot , int state)
{
int sc = m_slot_sc[ slot ];
@ -3692,6 +3717,9 @@ void hp9845_base_state::hp9845_base(machine_config &config)
tmp.irq().set([this , slot](int state) { set_irq_slot(slot , state); });
tmp.sts().set([this , slot](int state) { set_sts_slot(slot , state); });
tmp.flg().set([this , slot](int state) { set_flg_slot(slot , state); });
tmp.irq_nextsc().set([this , slot](int state) { set_irq_nextsc_slot(slot , state); });
tmp.sts_nextsc().set([this , slot](int state) { set_sts_nextsc_slot(slot , state); });
tmp.flg_nextsc().set([this , slot](int state) { set_flg_nextsc_slot(slot , state); });
tmp.dmar().set([this , slot](int state) { set_dmar_slot(slot , state); });
}

View File

@ -74,6 +74,9 @@ protected:
void set_irq_slot(unsigned slot , int state);
void set_sts_slot(unsigned slot , int state);
void set_flg_slot(unsigned slot , int state);
void set_irq_nextsc_slot(unsigned slot , int state);
void set_sts_nextsc_slot(unsigned slot , int state);
void set_flg_nextsc_slot(unsigned slot , int state);
void set_dmar_slot(unsigned slot , int state);
// Character generator