mirror of
https://github.com/holub/mame
synced 2025-04-22 08:22:15 +03:00
dmac_0266: new device
This commit is contained in:
parent
0b6dd07e04
commit
4d679b4b58
195
src/mame/machine/dmac_0266.cpp
Normal file
195
src/mame/machine/dmac_0266.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
/*
|
||||
* Sony 0266 DMA Controller gate array.
|
||||
*
|
||||
* This device is a single-channel DMA controller for the CXD1180 SCSI chip
|
||||
* (NCR5380 derivative) in Sony NEWS NWS-1[2457]x0 workstations.
|
||||
*
|
||||
* Sources:
|
||||
* - https://github.com/NetBSD/src/blob/trunk/sys/arch/news68k/dev/dmac_0266.h
|
||||
* - https://github.com/NetBSD/src/blob/trunk/sys/arch/news68k/dev/si.c
|
||||
*
|
||||
* TODO:
|
||||
* - tczero vs interrupt status
|
||||
* - verify if eop output exists
|
||||
* - verify map count/width
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "dmac_0266.h"
|
||||
|
||||
#define VERBOSE 0
|
||||
#include "logmacro.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(DMAC_0266, dmac_0266_device, "dmac_0266", "Sony 0266 DMA Controller")
|
||||
|
||||
dmac_0266_device::dmac_0266_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
|
||||
: device_t(mconfig, DMAC_0266, tag, owner, clock)
|
||||
, m_bus(*this, finder_base::DUMMY_TAG, -1, 32)
|
||||
, m_eop(*this)
|
||||
, m_dma_r(*this)
|
||||
, m_dma_w(*this)
|
||||
{
|
||||
}
|
||||
|
||||
void dmac_0266_device::map(address_map &map)
|
||||
{
|
||||
map(0x00, 0x03).w(FUNC(dmac_0266_device::control_w));
|
||||
map(0x04, 0x07).r(FUNC(dmac_0266_device::status_r));
|
||||
map(0x08, 0x0b).w(FUNC(dmac_0266_device::tcount_w));
|
||||
map(0x0c, 0x0f).w(FUNC(dmac_0266_device::tag_w));
|
||||
map(0x10, 0x13).w(FUNC(dmac_0266_device::offset_w));
|
||||
map(0x14, 0x17).w(FUNC(dmac_0266_device::entry_w));
|
||||
}
|
||||
|
||||
void dmac_0266_device::device_start()
|
||||
{
|
||||
m_eop.resolve();
|
||||
|
||||
m_dma_r.resolve_safe(0);
|
||||
m_dma_w.resolve_safe();
|
||||
|
||||
save_item(NAME(m_status));
|
||||
save_item(NAME(m_tcount));
|
||||
save_item(NAME(m_tag));
|
||||
save_item(NAME(m_offset));
|
||||
save_item(NAME(m_map));
|
||||
|
||||
save_item(NAME(m_eop_state));
|
||||
save_item(NAME(m_drq_state));
|
||||
|
||||
m_dma_check = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dmac_0266_device::dma_check), this));
|
||||
|
||||
m_eop_state = false;
|
||||
m_drq_state = false;
|
||||
}
|
||||
|
||||
void dmac_0266_device::device_reset()
|
||||
{
|
||||
for (u32 &entry : m_map)
|
||||
entry = 0;
|
||||
|
||||
soft_reset();
|
||||
}
|
||||
|
||||
void dmac_0266_device::soft_reset()
|
||||
{
|
||||
// soft reset does not clear map entries
|
||||
m_status = 0;
|
||||
m_tcount = 0;
|
||||
m_tag = 0;
|
||||
m_offset = 0;
|
||||
|
||||
set_eop(false);
|
||||
m_dma_check->enable(false);
|
||||
}
|
||||
|
||||
void dmac_0266_device::drq_w(int state)
|
||||
{
|
||||
m_drq_state = bool(state);
|
||||
|
||||
if (m_drq_state)
|
||||
m_dma_check->adjust(attotime::zero);
|
||||
}
|
||||
|
||||
void dmac_0266_device::set_eop(bool eop_state)
|
||||
{
|
||||
if (eop_state != m_eop_state)
|
||||
{
|
||||
m_eop_state = eop_state;
|
||||
m_eop(eop_state);
|
||||
}
|
||||
}
|
||||
|
||||
void dmac_0266_device::control_w(u32 data)
|
||||
{
|
||||
LOG("control_w 0x%08x (%s)\n", data, machine().describe_context());
|
||||
|
||||
if (!(data & RESET))
|
||||
{
|
||||
if ((data ^ m_status) & ENABLE)
|
||||
{
|
||||
if (data & ENABLE)
|
||||
{
|
||||
LOG("transfer started address 0x%08x count 0x%x\n",
|
||||
(m_map[m_tag & 0x7f] << 12) | (m_offset & 0xfff), m_tcount);
|
||||
|
||||
m_dma_check->adjust(attotime::zero);
|
||||
}
|
||||
else
|
||||
m_dma_check->enable(false);
|
||||
}
|
||||
|
||||
m_status = data & (ENABLE | DIRECTION);
|
||||
}
|
||||
else
|
||||
soft_reset();
|
||||
}
|
||||
|
||||
void dmac_0266_device::dma_check(void *ptr, s32 param)
|
||||
{
|
||||
// check drq active
|
||||
if (!m_drq_state)
|
||||
return;
|
||||
|
||||
// check enabled
|
||||
if (!(m_status & ENABLE))
|
||||
return;
|
||||
|
||||
// check transfer count
|
||||
if (!m_tcount)
|
||||
return;
|
||||
|
||||
u32 const address = u32(m_map[m_tag & 0x7f]) << 12 | (m_offset & 0xfff);
|
||||
|
||||
// assert eop during last transfer
|
||||
if (m_tcount == 1)
|
||||
set_eop(true);
|
||||
|
||||
// perform dma transfer
|
||||
if (m_status & DIRECTION)
|
||||
{
|
||||
// device to memory
|
||||
u8 const data = m_dma_r();
|
||||
|
||||
LOG("dma_r data 0x%02x address 0x%08x\n", data, address);
|
||||
|
||||
m_bus->write_byte(address, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// memory to device
|
||||
u8 const data = m_bus->read_byte(address);
|
||||
|
||||
LOG("dma_w data 0x%02x address 0x%08x\n", data, address);
|
||||
|
||||
m_dma_w(data);
|
||||
}
|
||||
|
||||
// increment offset
|
||||
if ((m_offset & 0xfff) == 0xfff)
|
||||
{
|
||||
// advance to next page
|
||||
m_tag++;
|
||||
m_offset = 0;
|
||||
}
|
||||
else
|
||||
m_offset++;
|
||||
|
||||
// decrement count
|
||||
m_tcount--;
|
||||
|
||||
// set terminal count flag
|
||||
if (!m_tcount)
|
||||
{
|
||||
LOG("transfer complete\n");
|
||||
m_status &= ~ENABLE;
|
||||
m_status |= INTERRUPT | TCZERO;
|
||||
|
||||
set_eop(false);
|
||||
}
|
||||
else
|
||||
m_dma_check->adjust(attotime::zero);
|
||||
}
|
75
src/mame/machine/dmac_0266.h
Normal file
75
src/mame/machine/dmac_0266.h
Normal file
@ -0,0 +1,75 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
#ifndef MAME_MACHINE_DMAC_0266_H
|
||||
#define MAME_MACHINE_DMAC_0266_H
|
||||
|
||||
#pragma once
|
||||
|
||||
class dmac_0266_device : public device_t
|
||||
{
|
||||
public:
|
||||
dmac_0266_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
|
||||
|
||||
// configuration
|
||||
template <typename T> void set_bus(T &&tag, int spacenum) { m_bus.set_tag(std::forward<T>(tag), spacenum); }
|
||||
|
||||
auto out_eop_cb() { return m_eop.bind(); }
|
||||
auto dma_r_cb() { return m_dma_r.bind(); }
|
||||
auto dma_w_cb() { return m_dma_w.bind(); }
|
||||
|
||||
void map(address_map &map);
|
||||
|
||||
void drq_w(int state);
|
||||
|
||||
protected:
|
||||
// device_t overrides
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
// register handlers
|
||||
void control_w(u32 data);
|
||||
u32 status_r() { return m_status; }
|
||||
void tcount_w(offs_t offset, u32 data, u32 mem_mask) { COMBINE_DATA(&m_tcount); }
|
||||
void tag_w(offs_t offset, u32 data, u32 mem_mask) { COMBINE_DATA(&m_tag); }
|
||||
void offset_w(offs_t offset, u32 data, u32 mem_mask) { COMBINE_DATA(&m_offset); }
|
||||
void entry_w(offs_t offset, u32 data, u32 mem_mask) { COMBINE_DATA(&m_map[m_tag & 0x7f]); }
|
||||
|
||||
// dma logic
|
||||
void soft_reset();
|
||||
void set_eop(bool eop_state);
|
||||
void dma_check(void *ptr, s32 param);
|
||||
|
||||
private:
|
||||
required_address_space m_bus;
|
||||
|
||||
devcb_write_line m_eop;
|
||||
devcb_read8 m_dma_r;
|
||||
devcb_write8 m_dma_w;
|
||||
|
||||
emu_timer *m_dma_check;
|
||||
|
||||
enum status_mask : u32
|
||||
{
|
||||
ENABLE = 0x01,
|
||||
DIRECTION = 0x02,
|
||||
RESET = 0x04,
|
||||
INTERRUPT = 0x08,
|
||||
TCZERO = 0x10,
|
||||
};
|
||||
|
||||
// registers
|
||||
u32 m_status;
|
||||
u32 m_tcount;
|
||||
u32 m_tag;
|
||||
u32 m_offset;
|
||||
u32 m_map[128];
|
||||
|
||||
// internal state
|
||||
bool m_eop_state;
|
||||
bool m_drq_state;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(DMAC_0266, dmac_0266_device)
|
||||
|
||||
#endif // MAME_MACHINE_DMAC_0266_H
|
Loading…
Reference in New Issue
Block a user