hp9k_3xx: add HP98620 DMA controller (#4094)

* hp9k_3xx: add HP98620 DMA controller

* hp98620: remove unused defines (nw)
This commit is contained in:
dxl 2018-10-09 19:46:35 +02:00 committed by R. Belmont
parent 98e4553718
commit ad3ad560a6
6 changed files with 531 additions and 25 deletions

View File

@ -891,6 +891,8 @@ if (BUSES["HPDIO"]~=null) then
MAME_DIR .. "src/devices/bus/hp_dio/hp98603a.h",
MAME_DIR .. "src/devices/bus/hp_dio/hp98603b.cpp",
MAME_DIR .. "src/devices/bus/hp_dio/hp98603b.h",
MAME_DIR .. "src/devices/bus/hp_dio/hp98620.cpp",
MAME_DIR .. "src/devices/bus/hp_dio/hp98620.h",
MAME_DIR .. "src/devices/bus/hp_dio/hp98644.cpp",
MAME_DIR .. "src/devices/bus/hp_dio/hp98644.h",
MAME_DIR .. "src/devices/bus/hp_dio/human_interface.cpp",

View File

@ -0,0 +1,383 @@
// license:BSD-3-Clause
// copyright-holders:Sven Schnelle
/***************************************************************************
HP98620 DMA controller
***************************************************************************/
#include "emu.h"
#define VERBOSE 0
#include "logmacro.h"
#include "hp98620.h"
DEFINE_DEVICE_TYPE_NS(HPDIO_98620, bus::hp_dio, dio16_98620_device, "hp98620", "HP98620 DMA Controller")
namespace bus {
namespace hp_dio {
dio16_98620_device::dio16_98620_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
dio16_98620_device(mconfig, HPDIO_98620, tag, owner, clock)
{
}
dio16_98620_device::dio16_98620_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_dio32_card_interface(mconfig, *this),
m_irq_state(false)
{
}
static INPUT_PORTS_START(hp98620_port)
INPUT_PORTS_END
ioport_constructor dio16_98620_device::device_input_ports() const
{
return INPUT_PORTS_NAME(hp98620_port);
}
void dio16_98620_device::device_start()
{
m_installed_io = false;
save_item(NAME(m_regs[0].address));
save_item(NAME(m_regs[0].tc));
save_item(NAME(m_regs[0].control));
save_item(NAME(m_regs[0].irq_level));
save_item(NAME(m_regs[0].tsz));
save_item(NAME(m_regs[0].subcount));
save_item(NAME(m_regs[0].irq));
save_item(NAME(m_regs[0].ie));
save_item(NAME(m_regs[0].armed));
save_item(NAME(m_regs[0].dma_out));
save_item(NAME(m_regs[0].dma_pri));
save_item(NAME(m_regs[0].lword));
save_item(NAME(m_regs[0].word));
save_item(NAME(m_regs[1].address));
save_item(NAME(m_regs[1].tc));
save_item(NAME(m_regs[1].control));
save_item(NAME(m_regs[1].irq_level));
save_item(NAME(m_regs[1].tsz));
save_item(NAME(m_regs[1].subcount));
save_item(NAME(m_regs[1].irq));
save_item(NAME(m_regs[1].ie));
save_item(NAME(m_regs[1].armed));
save_item(NAME(m_regs[1].dma_out));
save_item(NAME(m_regs[1].dma_pri));
save_item(NAME(m_regs[1].lword));
save_item(NAME(m_regs[1].word));
save_item(NAME(m_installed_io));
save_item(NAME(m_control));
save_item(NAME(m_data));
save_item(NAME(m_irq_state));
save_item(NAME(dmar));
}
void dio16_98620_device::map(address_map &map)
{
}
void dio16_98620_device::device_reset()
{
if (!m_installed_io)
{
program_space()->install_readwrite_handler(0x500000, 0x50020f,
read16_delegate(FUNC(dio16_98620_device::dma_r), this),
write16_delegate(FUNC(dio16_98620_device::dma_w), this));
m_installed_io = true;
}
m_control = 0;
m_irq_state = false;
}
uint16_t dio16_98620_device::get_ctrl(const int channel)
{
uint16_t ret = 0;
if (m_regs[channel].ie)
ret |= REG_CONTROL_IE;
if (m_regs[channel].tsz == 2)
ret |= REG_CONTROL_WORD;
if (m_regs[channel].tsz == 4)
ret |= REG_1TQ4_CONTROL_LWORD;
if (m_regs[channel].dma_out)
ret |= REG_CONTROL_OUT;
if (m_regs[channel].dma_pri)
ret |= REG_CONTROL_PRI;
ret |= ((m_regs[channel].irq_level-3) & REG_CONTROL_INT_MASK) << REG_CONTROL_INT_SHIFT;
return ret;
}
READ16_MEMBER(dio16_98620_device::dma_r)
{
uint16_t ret = 0;
switch(offset << 1) {
case REG0_RESET_ARM_INT:
m_regs[0].irq = false;
m_regs[0].armed = false;
update_irq();
ret = 0x00;
break;
case REG1_RESET_ARM_INT:
m_regs[1].irq = false;
m_regs[1].armed = false;
update_irq();
ret = 0x00;
break;
case REG0_TRANSFER_COUNT:
ret = m_regs[0].tc & 0xffff;
break;
case REG1_TRANSFER_COUNT:
ret = m_regs[1].tc & 0xffff;
break;
case REG0_STATUS:
ret = 0;
if (m_regs[0].armed)
ret |= REG_STATUS_ARMED;
if (m_regs[0].irq)
ret |= REG_STATUS_INT;
break;
case REG1_STATUS:
ret = 0;
if (m_regs[1].armed)
ret |= REG_STATUS_ARMED;
if (m_regs[1].irq)
ret |= REG_STATUS_INT;
break;
case REG_1TQ4_ID_LOW:
ret = 0x3230;
break;
case REG_1TQ4_ID_HIGH:
ret = 0x4330;
break;
case REG0_1TQ4_ADDRESS_LOW:
ret = m_regs[0].address & 0xffff;
break;
case REG0_1TQ4_ADDRESS_HIGH:
ret = m_regs[0].address >> 16;
break;
case REG1_1TQ4_ADDRESS_LOW:
ret = m_regs[1].address & 0xffff;
break;
case REG1_1TQ4_ADDRESS_HIGH:
ret = m_regs[1].address >> 16;
break;
case REG0_1TQ4_TRANSFER_COUNT_LOW:
ret = m_regs[0].tc & 0xffff;
break;
case REG0_1TQ4_TRANSFER_COUNT_HIGH:
ret = m_regs[0].tc >> 16;
break;
case REG1_1TQ4_TRANSFER_COUNT_LOW:
ret = m_regs[1].tc & 0xffff;
break;
case REG1_1TQ4_TRANSFER_COUNT_HIGH:
ret = m_regs[1].tc >> 16;
break;
case REG0_1TQ4_CONTROL:
ret = m_regs[0].control;
break;
case REG1_1TQ4_CONTROL:
ret = m_regs[1].control;
break;
case REG0_1TQ4_STATUS:
ret = 0;
break;
case REG1_1TQ4_STATUS:
ret = 0;
break;
default:
LOG("%s: unknown register read: %02X\n", __FUNCTION__, offset << 1);
break;
}
LOG("dma_r: offset=%02X ret=%02X\n", offset << 1, ret);
return ret;
}
void dio16_98620_device::update_ctrl(const int channel, const uint16_t data, const bool is_1tq4)
{
assert(channel < 2);
m_regs[channel].control = data;
m_regs[channel].ie = data & REG_CONTROL_IE;
m_regs[channel].irq_level = 3 + ((data >> REG_CONTROL_INT_SHIFT) & REG_CONTROL_INT_MASK);
m_regs[channel].lword = (data & REG_1TQ4_CONTROL_LWORD) && is_1tq4;
m_regs[channel].word = data & REG_CONTROL_WORD;
m_regs[channel].dma_out = data & REG_CONTROL_OUT;
if (data & REG_1TQ4_CONTROL_LWORD)
m_regs[channel].tsz = 4;
else if (data & REG_CONTROL_WORD)
m_regs[channel].tsz = 2;
else
m_regs[channel].tsz = 1;
if ((data & REG_1TQ4_CONTROL_START) || !is_1tq4) {
LOG("DMA Channel %d: addr %08x, tc %d, size %d, int %sabled on IRQ %d\n", channel,
m_regs[channel].address,
(m_regs[channel].tc+1)*m_regs[channel].tsz,
m_regs[channel].tsz,
m_regs[channel].ie ? "en" : "dis",
m_regs[channel].irq_level);
m_regs[channel].subcount = m_regs[channel].tsz-1;
m_regs[channel].armed = true;
m_regs[channel].irq = false;
if (dmar[channel])
dma_transfer(channel);
}
}
WRITE16_MEMBER(dio16_98620_device::dma_w)
{
LOG("dma_w: offset=%02X, data=%02X\n", offset << 1, data);
switch(offset << 1) {
case REG0_1TQ4_ADDRESS_HIGH:
case REG0_ADDRESS_HIGH:
m_regs[0].address &= 0xffff;
m_regs[0].address |= (data << 16);
break;
case REG0_1TQ4_ADDRESS_LOW:
case REG0_ADDRESS_LOW:
m_regs[0].address &= 0xffff0000;
m_regs[0].address |= data;
break;
case REG1_1TQ4_ADDRESS_HIGH:
case REG1_ADDRESS_HIGH:
m_regs[1].address &= 0xffff;
m_regs[1].address |= (data << 16);
break;
case REG1_1TQ4_ADDRESS_LOW:
case REG1_ADDRESS_LOW:
m_regs[1].address &= 0xffff0000;
m_regs[1].address |= data;
break;
case REG0_TRANSFER_COUNT:
m_regs[0].tc = data;
break;
case REG0_1TQ4_TRANSFER_COUNT_HIGH:
m_regs[0].tc &= 0xffff;
m_regs[0].tc |= (data << 16);
break;
case REG0_1TQ4_TRANSFER_COUNT_LOW:
m_regs[0].tc &= 0xffff0000;
m_regs[0].tc |= data;
break;
case REG1_1TQ4_TRANSFER_COUNT_HIGH:
m_regs[1].tc &= 0xffff;
m_regs[1].tc |= (data << 16);
break;
case REG1_1TQ4_TRANSFER_COUNT_LOW:
m_regs[1].tc &= 0xffff0000;
m_regs[1].tc |= data;
break;
case REG1_TRANSFER_COUNT:
m_regs[1].tc = data;
break;
case REG0_CONTROL_ARM:
update_ctrl(0, data, false);
break;
case REG1_CONTROL_ARM:
update_ctrl(1, data, false);
break;
case REG0_1TQ4_CONTROL:
update_ctrl(0, data, true);
break;
case REG1_1TQ4_CONTROL:
update_ctrl(1, data, true);
break;
default:
LOG("%s: unknown register write: %02X\n", __FUNCTION__, offset << 1);
break;
}
}
void dio16_98620_device::update_irq()
{
irq3_out((m_regs[0].irq_level == 3 && m_regs[0].irq && m_regs[0].ie) ||
(m_regs[1].irq_level == 3 && m_regs[1].irq && m_regs[1].ie));
irq4_out((m_regs[0].irq_level == 4 && m_regs[0].irq && m_regs[0].ie) ||
(m_regs[1].irq_level == 4 && m_regs[1].irq && m_regs[1].ie));
irq5_out((m_regs[0].irq_level == 5 && m_regs[0].irq && m_regs[0].ie) ||
(m_regs[1].irq_level == 5 && m_regs[1].irq && m_regs[1].ie));
irq6_out((m_regs[0].irq_level == 6 && m_regs[0].irq && m_regs[0].ie) ||
(m_regs[1].irq_level == 6 && m_regs[1].irq && m_regs[1].ie));
irq7_out((m_regs[0].irq_level == 7 && m_regs[0].irq && m_regs[0].ie) ||
(m_regs[1].irq_level == 7 && m_regs[1].irq && m_regs[1].ie));
}
void dio16_98620_device::dma_transfer(int channel)
{
assert(channel < 2);
if (!(m_regs[channel].armed))
return;
LOG("dma_transfer %s: tc %d/%d\n", m_regs[channel].dma_out ? "out" : "in",
m_regs[channel].tc, m_regs[channel].subcount);
if (m_regs[channel].dma_out) {
dmack_w_out(channel, program_space()->read_byte(m_regs[channel].address++));
} else {
program_space()->write_byte(m_regs[channel].address++, dmack_r_out(channel));
}
if (m_regs[channel].subcount == 0) {
if (m_regs[channel].tc-- == 0) {
LOG("DMA%d done\n", channel);
m_regs[channel].armed = false;
m_regs[channel].irq = true;
update_irq();
return;
}
m_regs[channel].subcount = m_regs[channel].tsz;
}
m_regs[channel].subcount--;
}
WRITE_LINE_MEMBER(dio16_98620_device::dmar0_in)
{
LOG("%s: %d\n", __FUNCTION__, state);
dmar[0] = state;
if (!state)
return;
dma_transfer(0);
}
WRITE_LINE_MEMBER(dio16_98620_device::dmar1_in)
{
LOG("%s: %d\n", __FUNCTION__, state);
dmar[1] = state;
if (!state)
return;
dma_transfer(1);
}
} // namespace bus::hp_dio
} // namespace bus

View File

@ -0,0 +1,128 @@
// license:BSD-3-Clause
// copyright-holders:Sven Schnelle
#ifndef MAME_BUS_HPDIO_98620_H
#define MAME_BUS_HPDIO_98620_H
#pragma once
#include "hp_dio.h"
namespace bus {
namespace hp_dio {
class dio16_98620_device :
public device_t,
public device_dio32_card_interface
{
public:
// construction/destruction
dio16_98620_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
void map(address_map &map);
protected:
dio16_98620_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
virtual ioport_constructor device_input_ports() const override;
DECLARE_READ16_MEMBER(dma_r);
DECLARE_WRITE16_MEMBER(dma_w);
DECLARE_WRITE_LINE_MEMBER(irq_w);
private:
static constexpr int REG0_RESET_ARM_INT = 0x00;
static constexpr int REG0_ADDRESS_HIGH = 0x00;
static constexpr int REG0_ADDRESS_LOW = 0x02;
static constexpr int REG0_TRANSFER_COUNT = 0x04;
static constexpr int REG0_CONTROL_ARM = 0x06;
static constexpr int REG0_STATUS = 0x06;
static constexpr int REG1_RESET_ARM_INT = 0x08;
static constexpr int REG1_ADDRESS_HIGH = 0x08;
static constexpr int REG1_ADDRESS_LOW = 0x0a;
static constexpr int REG1_TRANSFER_COUNT = 0x0c;
static constexpr int REG1_CONTROL_ARM = 0x0e;
static constexpr int REG1_STATUS = 0x0e;
static constexpr uint8_t REG_CONTROL_IE = 1 << 0;
static constexpr uint8_t REG_CONTROL_WORD = 1 << 1;
static constexpr uint8_t REG_CONTROL_OUT = 1 << 2;
static constexpr uint8_t REG_CONTROL_PRI = 1 << 3;
static constexpr uint8_t REG_CONTROL_INT_MASK = 0x7;
static constexpr int REG_CONTROL_INT_SHIFT = 4;
static constexpr uint8_t REG_STATUS_ARMED = 1 << 0;
static constexpr uint8_t REG_STATUS_INT = 1 << 1;
/* general control registers */
static constexpr int REG_1TQ4_ID_LOW = 0x10;
static constexpr int REG_1TQ4_ID_HIGH = 0x12;
/* channel specific registers */
static constexpr int REG0_1TQ4_ADDRESS_LOW = 0x100;
static constexpr int REG0_1TQ4_ADDRESS_HIGH = 0x102;
static constexpr int REG0_1TQ4_TRANSFER_COUNT_LOW = 0x104;
static constexpr int REG0_1TQ4_TRANSFER_COUNT_HIGH = 0x106;
static constexpr int REG0_1TQ4_CONTROL = 0x108;
static constexpr int REG0_1TQ4_STATUS = 0x10a;
static constexpr uint16_t REG_1TQ4_CONTROL_LWORD = 1 << 8;
static constexpr uint16_t REG_1TQ4_CONTROL_START = 1 << 15;
/* registers */
static constexpr int REG1_1TQ4_ADDRESS_HIGH = 0x200;
static constexpr int REG1_1TQ4_ADDRESS_LOW = 0x202;
static constexpr int REG1_1TQ4_TRANSFER_COUNT_HIGH = 0x204;
static constexpr int REG1_1TQ4_TRANSFER_COUNT_LOW = 0x206;
static constexpr int REG1_1TQ4_CONTROL = 0x208;
static constexpr int REG1_1TQ4_STATUS = 0x20a;
WRITE_LINE_MEMBER(dmar0_in) override;
WRITE_LINE_MEMBER(dmar1_in) override;
void dma_transfer(int channel);
void update_irq();
void update_ctrl(const int channel, const uint16_t data, const bool is_1tq4);
uint16_t get_ctrl(const int channel);
bool m_installed_io;
uint8_t m_control;
uint8_t m_data;
bool m_irq_state;
struct dma_regs {
uint32_t address;
uint32_t tc;
uint32_t control;
/* control register */
int irq_level;
int tsz;
int subcount;
bool irq;
bool ie;
bool armed;
bool dma_out;
bool dma_pri; // TODO
bool lword;
bool word;
} m_regs[2];
bool dmar[2];
};
}
}
DECLARE_DEVICE_TYPE_NS(HPDIO_98620, bus::hp_dio, dio16_98620_device)
#endif // MAME_BUS_HPDIO_98620_H

View File

@ -12,7 +12,9 @@
#include "hp98544.h"
#include "hp98603a.h"
#include "hp98603b.h"
#include "hp98620.h"
#include "hp98644.h"
#include "human_interface.h"
//**************************************************************************
// GLOBAL VARIABLES
@ -350,11 +352,17 @@ void device_dio32_card_interface::interface_pre_start()
} // namespace bus::hp_dio
} // namespace bus
void hpdio_cards(device_slot_interface & device)
void dio16_cards(device_slot_interface & device)
{
device.option_add("hp98543", HPDIO_98543);
device.option_add("hp98544", HPDIO_98544);
device.option_add("hp98603a", HPDIO_98603A);
device.option_add("hp98603b", HPDIO_98603B);
device.option_add("hp98644", HPDIO_98644);
device.option_add("98543", HPDIO_98543);
device.option_add("98544", HPDIO_98544);
device.option_add("98603a", HPDIO_98603A);
device.option_add("98603b", HPDIO_98603B);
device.option_add("98644", HPDIO_98644);
device.option_add("human_interface", HPDIO_HUMAN_INTERFACE);
}
void dio32_cards(device_slot_interface & device)
{
device.option_add("98620", HPDIO_98620);
}

View File

@ -290,6 +290,7 @@ DECLARE_DEVICE_TYPE_NS(DIO32, bus::hp_dio, dio32_device)
DECLARE_DEVICE_TYPE_NS(DIO32_SLOT, bus::hp_dio, dio32_slot_device)
DECLARE_DEVICE_TYPE_NS(DIO16, bus::hp_dio, dio16_device)
void hpdio_cards(device_slot_interface &device);
void dio16_cards(device_slot_interface &device);
void dio32_cards(device_slot_interface &device);
#endif // MAME_BUS_HPDIO_HPDIO_H

View File

@ -58,14 +58,7 @@
#include "logmacro.h"
#include "cpu/m68000/m68000.h"
#include "machine/6840ptm.h"
#include "sound/sn76496.h"
#include "bus/hp_dio/hp_dio.h"
#include "bus/hp_dio/hp98543.h"
#include "bus/hp_dio/hp98544.h"
#include "bus/hp_dio/hp98603a.h"
#include "bus/hp_dio/hp98603b.h"
#include "bus/hp_dio/hp98644.h"
#include "bus/hp_dio/human_interface.h"
#include "screen.h"
#include "softlist_dev.h"
@ -324,16 +317,6 @@ WRITE32_MEMBER(hp9k3xx_state::buserror_w)
m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE);
}
static void dio16_cards(device_slot_interface &device)
{
device.option_add("98543", HPDIO_98543); /* 98543 Medium Resolution Color Card */
device.option_add("98544", HPDIO_98544); /* 98544 High Resolution Monochrome Card */
device.option_add("98603a", HPDIO_98603A); /* 98603A ROM BASIC (4.0) */
device.option_add("98603b", HPDIO_98603B); /* 98603B ROM BASIC (5.1) */
device.option_add("98644", HPDIO_98644); /* 98644 Async serial interface */
device.option_add("human_interface", HPDIO_HUMAN_INTERFACE);
}
MACHINE_CONFIG_START(hp9k3xx_state::hp9k300)
ptm6840_device &ptm(PTM6840(config, PTM6840_TAG, 250000)); // from oscillator module next to the 6840
ptm.set_external_clocks(250000.0f, 0.0f, 250000.0f);
@ -387,7 +370,8 @@ MACHINE_CONFIG_START(hp9k3xx_state::hp9k320)
DIO32_SLOT(config, "sl1", 0, "diobus", dio16_cards, "98544", false);
DIO32_SLOT(config, "sl2", 0, "diobus", dio16_cards, "98603b", false);
DIO32_SLOT(config, "sl3", 0, "diobus", dio16_cards, "98644", false);
DIO32_SLOT(config, "sl4", 0, "diobus", dio16_cards, nullptr, false);
DIO32_SLOT(config, "sl4", 0, "diobus", dio32_cards, "98620", false);
DIO32_SLOT(config, "sl5", 0, "diobus", dio16_cards, nullptr, false);
MACHINE_CONFIG_END
MACHINE_CONFIG_START(hp9k3xx_state::hp9k330)