summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/3dom2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/3dom2.cpp')
-rw-r--r--src/mame/machine/3dom2.cpp2091
1 files changed, 2091 insertions, 0 deletions
diff --git a/src/mame/machine/3dom2.cpp b/src/mame/machine/3dom2.cpp
new file mode 100644
index 00000000000..82487d46c9b
--- /dev/null
+++ b/src/mame/machine/3dom2.cpp
@@ -0,0 +1,2091 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/***************************************************************************
+
+ 3DO M2 Bulldog ASIC
+
+***************************************************************************/
+
+#include "emu.h"
+#include "3dom2.h"
+#include <algorithm> // std::min
+#include "screen.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+// Device type definitions
+DEFINE_DEVICE_TYPE(M2_BDA, m2_bda_device, "m2bda", "3DO M2 Bulldog ASIC")
+DEFINE_DEVICE_TYPE(M2_POWERBUS, m2_powerbus_device, "m2powerbus", "BDA PowerBus Controller")
+DEFINE_DEVICE_TYPE(M2_MEMCTL, m2_memctl_device, "m2memctl", "BDA Memory Controller")
+DEFINE_DEVICE_TYPE(M2_VDU, m2_vdu_device, "m2vdu", "BDA VDU")
+DEFINE_DEVICE_TYPE(M2_CTRLPORT, m2_ctrlport_device, "m2ctrlport", "BDA Control Ports")
+DEFINE_DEVICE_TYPE(M2_MPEG, m2_mpeg_device, "m2mpeg", "3DO MPEG Decoder")
+DEFINE_DEVICE_TYPE(M2_CDE, m2_cde_device, "m2cde", "3DO M2 CDE ASIC")
+
+
+
+//**************************************************************************
+// VDU REGISTER DEFINITIONS
+//**************************************************************************
+
+#define VDU_VLOC 0x00
+#define VDU_VINT 0x04
+#define VDU_VDC0 0x08
+#define VDU_VDC1 0x0c
+#define VDU_FV0A 0x10
+#define VDU_FV1A 0x14
+#define VDU_AVDI 0x1c
+#define VDU_VDLI 0x20
+#define VDU_VCFG 0x24
+#define VDU_DMT0 0x28
+#define VDU_DMT1 0x2c
+#define VDU_LFSR 0x30
+#define VDU_VRST 0x34
+
+//-------------------------------------------------
+// VLOC
+//-------------------------------------------------
+#define VDU_VLOC_VCOUNT_MASK 0x00003FF8
+#define VDU_VLOC_VCOUNT_SHIFT 3
+#define VDU_VLOC_VIDEOFIELD 0x00004000
+#define VDU_VLOC_RESERVED 0xFFFF8007
+
+//-------------------------------------------------
+// VINT
+//-------------------------------------------------
+#define VDU_VINT_VINT0 0x80000000
+#define VDU_VINT_VLINE0_MASK 0x7FF00000
+#define VDU_VINT_VLINE0_SHIFT 20
+#define VDU_VINT_VINT1 0x00008000
+#define VDU_VINT_VLINE1_MASK 0x00007FF0
+#define VDU_VINT_VLINE1_SHIFT 4
+#define VDU_VINT_RESERVED 0x000F000F
+
+//-------------------------------------------------
+// VDC0/VDC1
+//-------------------------------------------------
+#define VDU_VDC_HINT 0x02000000
+#define VDU_VDC_VINT 0x01000000
+#define VDU_VDC_DITHER 0x00400000
+#define VDU_VDC_MTXBYP 0x00200000
+#define VDU_VDC_RESERVED 0xFC9FFFFF
+
+//-------------------------------------------------
+// AVDI
+//-------------------------------------------------
+#define VDU_AVDI_HSTART_MASK 0xFFE00000
+#define VDU_AVDI_HWIDTH_MASK 0x0003FF80
+#define VDU_AVDI_HDOUBLE 0x00000008
+#define VDU_AVDI_VDOUBLE 0x00000004
+#define VDU_AVDI_RESERVED 0x001C0073
+#define VDU_AVDI_HSTART_SHIFT 21
+#define VDU_AVDI_HWIDTH_SHIFT 7
+
+//-------------------------------------------------
+// VDLI
+//-------------------------------------------------
+#define VDU_VDLI_BYPASSTYPE 0x10000000
+#define VDU_VDLI_FBFORMAT 0x04000000
+#define VDU_VDLI_ONEVINTDIS 0x00400000
+#define VDU_VDLI_RANDOMDITHER 0x00200000
+#define VDU_VDLI_RESERVED 0xEB9FFFFF
+#define VDU_VDLI_BYPASSTYPE_MSB 0
+#define VDU_VDLI_BYPASSTYPE_LSB 0x10000000
+#define VDU_VDLI_FBFORMAT_16 0
+#define VDU_VDLI_FBFORMAT_32 0x04000000
+
+//-------------------------------------------------
+// VCFG
+//-------------------------------------------------
+
+//-------------------------------------------------
+// VRST
+//-------------------------------------------------
+#define VDU_VRST_DVERESET 0x00000002
+#define VDU_VRST_VIDRESET 0x00000001
+#define VDU_VRST_RESERVED 0xFFFFFFFC
+
+
+//-------------------------------------------------
+// VDL DMA CONTROL WORD
+//-------------------------------------------------
+#define VDL_DMA_MOD_MASK 0xFF000000
+#define VDL_DMA_ENABLE 0x00200000
+#define VDL_DMA_NOBUCKET 0x00020000
+#define VDL_DMA_LDLOWER 0x00010000
+#define VDL_DMA_LDUPPER 0x00008000
+#define VDL_DMA_NWORDS_MASK 0x00007E00
+#define VDL_DMA_NLINES_MASK 0x000001FF
+#define VDL_DMA_RESERVED 0x00DC0000
+#define VDL_DMA_NWORDS_SHIFT 9
+#define VDL_DMA_MOD_SHIFT 24
+#define VDL_DMA_NLINES_SHIFT 0
+
+//-------------------------------------------------
+// VDL DC CONTROL WORD
+//-------------------------------------------------
+#define VDL_DC 0x80000000
+#define VDL_DC_0 0x00000000
+#define VDL_DC_1 0x10000000
+#define VDL_DC_HINTCTL_MASK 0x00060000
+#define VDL_DC_HINTCTL_SHIFT 17
+#define VDL_DC_VINTCTL_MASK 0x00018000
+#define VDL_DC_VINTCTL_SHIFT 15
+#define VDL_DC_DITHERCTL_MASK 0x00001800
+#define VDL_DC_DITHERCTL_SHIFT 11
+#define VDL_DC_MTXBYPCTL_MASK 0x00000600
+#define VDL_DC_MTXBYPCTL_SHIFT 9
+#define VDL_DC_RESERVED 0x0FF861FF
+#define VDL_CTL_DISABLE 0
+#define VDL_CTL_ENABLE 1
+#define VDL_CTL_NOP 2
+
+//-------------------------------------------------
+// VDL AV CONTROL WORD
+//-------------------------------------------------
+#define VDL_AV 0xA0000000
+#define VDL_AV_HSTART_MASK 0x1FFC0000
+#define VDL_AV_HSTART_SHIFT 18
+#define VDL_AV_LD_HSTART 0x00020000
+#define VDL_AV_HWIDTH_MASK 0x0001FFC0
+#define VDL_AV_HWIDTH_SHIFT 6
+#define VDL_AV_LD_HWIDTH 0x00000020
+#define VDL_AV_HDOUBLE 0x00000010
+#define VDL_AV_VDOUBLE 0x00000008
+#define VDL_AV_LD_HDOUBLE 0x00000004
+#define VDL_AV_LD_VDOUBLE 0x00000002
+#define VDL_AV_RESERVED 0x00000001
+
+//-------------------------------------------------
+// VDL LC CONTROL WORD
+//-------------------------------------------------
+#define VDL_LC 0xC0000000
+#define VDL_LC_BYPASSTYPE 0x02000000
+#define VDL_LC_FBFORMAT 0x00800000
+#define VDL_LC_ONEVINTDIS 0x00080000
+#define VDL_LC_RANDOMDITHER 0x00040000
+#define VDL_LC_LD_BYPASSTYPE 0x00002000
+#define VDL_LC_LD_FBFORMAT 0x00001000
+#define VDL_LC_RESERVED 0x1D73CFFF
+#define VDL_LC_BYPASSTYPE_MSB 0x00000000
+#define VDL_LC_BYPASSTYPE_LSB 0x02000000
+#define VDL_LC_FBFORMAT_16 0x00000000
+#define VDL_LC_FBFORMAT_32 0x00800000
+
+//-------------------------------------------------
+// VDL DMA CONTROL WORD
+//-------------------------------------------------
+
+#define VDL_NOP 0xe1000000
+
+
+
+/***************************************************************************
+ SUPPORT FUNCTIONS
+***************************************************************************/
+
+static void write_m2_reg(uint32_t &reg, uint32_t data, reg_wmode mode)
+{
+ switch (mode)
+ {
+ case REG_WRITE: reg = data; break;
+ case REG_SET: reg |= data; break;
+ case REG_CLEAR: reg &= ~data; break;
+ default:
+ assert_always(false, "Bad register write mode");
+ }
+}
+
+
+
+//**************************************************************************
+// BDA DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// m2_bda_device - constructor
+//-------------------------------------------------
+
+m2_bda_device::m2_bda_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, M2_BDA, tag, owner, clock),
+ m_cpu1(*this, finder_base::DUMMY_TAG),
+ m_cpu2(*this, finder_base::DUMMY_TAG),
+ m_videores_in(*this),
+ m_memctl(*this, "memctl"),
+ m_powerbus(*this, "powerbus"),
+ m_vdu(*this, "vdu"),
+ m_ctrlport(*this, "ctrlport"),
+ m_dspp(*this, "dspp"),
+ m_mpeg(*this, "mpeg"),
+ m_te(*this, "te"),
+ m_dac_l(*this),
+ m_dac_r(*this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_bda_device::device_start()
+{
+ // Resolve callbacks
+ m_videores_in.resolve_safe(0);
+ m_dac_l.resolve_safe();
+ m_dac_r.resolve_safe();
+
+ // Allocate RAM
+ uint32_t ram_size = (m_rambank_size[0] + m_rambank_size[1]) * 1024 * 1024;
+ m_ram = auto_alloc_array(machine(), uint32_t, ram_size / sizeof(uint32_t));
+ m_ram_mask = ram_size - 1;
+
+ // Install RAM and handlers into the CPU address spaces
+ configure_ppc_address_map(m_cpu1->space(AS_PROGRAM));
+ configure_ppc_address_map(m_cpu2->space(AS_PROGRAM));
+
+ // Register state for saving
+ save_pointer(NAME(m_ram), ram_size / sizeof(uint32_t));
+
+ // Set a timer to pull data from the DSPP FIFO into the DACs
+ m_dac_timer = timer_alloc(0);
+ m_dac_timer->adjust(attotime::from_hz(16.9345));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_bda_device::device_reset()
+{
+
+}
+
+
+//-------------------------------------------------
+// device_post_load - device-specific post-load
+//-------------------------------------------------
+
+void m2_bda_device::device_post_load()
+{
+
+}
+
+
+//-------------------------------------------------
+// machine_config_fragment - declare sub-devices
+//-------------------------------------------------
+
+void m2_bda_device::device_add_mconfig(machine_config &config)
+{
+ M2_MEMCTL(config, m_memctl, DERIVED_CLOCK(1, 1));
+
+ M2_POWERBUS(config, m_powerbus, DERIVED_CLOCK(1, 1));
+
+ M2_VDU(config, m_vdu, DERIVED_CLOCK(1, 1));
+ m_vdu->vint0_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_VINT0_LINE>));
+ m_vdu->vint1_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_VINT1_LINE>));
+
+ M2_CTRLPORT(config, m_ctrlport, DERIVED_CLOCK(1, 1));
+
+ M2_MPEG(config, m_mpeg, DERIVED_CLOCK(1, 1));
+// m_mpeg->int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_MPEG_LINE>));
+
+ DSPP(config, m_dspp, DERIVED_CLOCK(1, 1));
+ m_dspp->int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_DSP_LINE>));
+ m_dspp->dma_read_handler().set(FUNC(m2_bda_device::read_bus8));
+ m_dspp->dma_write_handler().set(FUNC(m2_bda_device::write_bus8));
+
+ M2_TE(config, m_te, DERIVED_CLOCK(1, 1));
+ m_te->general_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_TRIGEN_LINE>));
+ m_te->dfinstr_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_TRIDFINST_LINE>));
+ m_te->iminstr_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_TRIDMINST_LINE>));
+ m_te->listend_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_TRILISTEND_LINE>));
+ m_te->winclip_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_TRIWINCLIP_LINE>));
+}
+
+
+//-------------------------------------------------
+// device_timer - device-specific timers
+//-------------------------------------------------
+
+void m2_bda_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case 0:
+ {
+ m_dac_l(m_dspp->read_output_fifo());
+ m_dac_r(m_dspp->read_output_fifo());
+ m_dac_timer->adjust(attotime::from_hz(44100));
+ break;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// cpu_id_r - read from CPU ID register
+//-------------------------------------------------
+
+READ32_MEMBER( m2_bda_device::cpu_id_r )
+{
+ uint32_t data = 0;
+
+ // .x...... ........ ........ ........ - Video type (0 = Arcade, 1 = NTSC/PAL)
+ // x....... ........ ........ ........ - CPU ID (0 = CPU1, 1 = CPU2)
+
+ if (&space.device() == m_cpu2)
+ data |= 0x80000000;
+
+ if (m_videores_in() != 0)
+ data |= 0x40000000;
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// cpu_id_w - Write to CPU ID register
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_bda_device::cpu_id_w )
+{
+ // TODO: How should this work?
+ logerror("%s: CPUID: %x\n", machine().describe_context(), data);
+}
+
+
+//-------------------------------------------------
+// read_bus8 - Read 8-bit data from the PowerBus
+//-------------------------------------------------
+
+uint8_t m2_bda_device::read_bus8(offs_t offset)
+{
+ assert(offset >= RAM_BASE && offset <= RAM_BASE + m_ram_mask);
+
+ offset &= m_ram_mask;
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_ram[0]) + BYTE8_XOR_BE(offset);
+ return *ptr;
+}
+
+
+//-------------------------------------------------
+// read_bus16 - Read 16-bit data from the PowerBus
+//-------------------------------------------------
+
+uint16_t m2_bda_device::read_bus16(offs_t offset)
+{
+ assert(offset >= RAM_BASE && offset <= RAM_BASE + m_ram_mask);
+
+ offset &= m_ram_mask;
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_ram[0]) + WORD2_XOR_BE(offset);
+ return *reinterpret_cast<uint16_t *>(ptr);
+}
+
+
+//-------------------------------------------------
+// read_bus32 - Read 32-bit data from the PowerBus
+//-------------------------------------------------
+
+uint32_t m2_bda_device::read_bus32(offs_t offset)
+{
+ assert(offset >= RAM_BASE && offset <= RAM_BASE + m_ram_mask);
+
+ offset &= m_ram_mask;
+
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_ram[0]) + DWORD_XOR_BE(offset);
+ return *reinterpret_cast<uint32_t *>(ptr);
+}
+
+
+//-------------------------------------------------
+// write_bus8 - Write 8-bit data to the PowerBus
+//-------------------------------------------------
+
+void m2_bda_device::write_bus8(offs_t offset, uint8_t data)
+{
+ assert(offset >= RAM_BASE && offset <= RAM_BASE + m_ram_mask);
+
+ offset &= m_ram_mask;
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_ram[0]) + BYTE8_XOR_BE(offset);
+ *ptr = data;
+}
+
+
+//-------------------------------------------------
+// write_bus16 - Write 16-bit data to the PowerBus
+//-------------------------------------------------
+
+void m2_bda_device::write_bus16(offs_t offset, uint16_t data)
+{
+ assert(offset >= RAM_BASE && offset <= RAM_BASE + m_ram_mask);
+
+ offset &= m_ram_mask;
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_ram[0]) + WORD2_XOR_BE(offset);
+ *reinterpret_cast<uint16_t *>(ptr) = data;
+}
+
+
+//-------------------------------------------------
+// write_bus32 - Write 32-bit data to the PowerBus
+//-------------------------------------------------
+
+void m2_bda_device::write_bus32(offs_t offset, uint32_t data)
+{
+ assert(offset >= RAM_BASE && offset <= RAM_BASE + m_ram_mask);
+
+ offset &= m_ram_mask;
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_ram[0]) + DWORD_XOR_BE(offset);
+ *reinterpret_cast<uint32_t *>(ptr) = data;
+}
+
+
+
+/***************************************************************************
+ PRIVATE FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// configure_ppc_address_map -
+//-------------------------------------------------
+
+void m2_bda_device::configure_ppc_address_map(address_space &space)
+{
+ // Install shared RAM
+ space.install_ram(RAM_BASE, RAM_BASE + m_ram_mask, m_ram);
+
+ // Install TE texture RAM window
+ space.install_ram(TE_TRAM_BASE, TE_TRAM_BASE + TE_TRAM_MASK, m_te->tram_ptr());
+
+ // Install BDA sub-devices
+ space.install_readwrite_handler(POWERBUS_BASE, POWERBUS_BASE + DEVICE_MASK,read32_delegate(FUNC(m2_powerbus_device::read), &(*m_powerbus)), write32_delegate(FUNC(m2_powerbus_device::write), &(*m_powerbus)), 0xffffffffffffffffULL);
+ space.install_readwrite_handler(MEMCTL_BASE, MEMCTL_BASE + DEVICE_MASK, read32_delegate(FUNC(m2_memctl_device::read), &(*m_memctl)), write32_delegate(FUNC(m2_memctl_device::write), &(*m_memctl)), 0xffffffffffffffffULL);
+ space.install_readwrite_handler(VDU_BASE, VDU_BASE + DEVICE_MASK, read32_delegate(FUNC(m2_vdu_device::read), &(*m_vdu)), write32_delegate(FUNC(m2_vdu_device::write), &(*m_vdu)), 0xffffffffffffffffULL);
+ space.install_readwrite_handler(TE_BASE, TE_BASE + DEVICE_MASK, read32_delegate(FUNC(m2_te_device::read), &(*m_te)), write32_delegate(FUNC(m2_te_device::write), &(*m_te)), 0xffffffffffffffffULL);
+ space.install_readwrite_handler(DSP_BASE, DSP_BASE + DEVICE_MASK, read32_delegate(FUNC(dspp_device::read), &(*m_dspp)), write32_delegate(FUNC(dspp_device::write), &(*m_dspp)), 0xffffffffffffffffULL);
+ space.install_readwrite_handler(CTRLPORT_BASE, CTRLPORT_BASE + DEVICE_MASK,read32_delegate(FUNC(m2_ctrlport_device::read), &(*m_ctrlport)), write32_delegate(FUNC(m2_ctrlport_device::write), &(*m_ctrlport)), 0xffffffffffffffffULL);
+ space.install_readwrite_handler(MPEG_BASE, MPEG_BASE + DEVICE_MASK, read32_delegate(FUNC(m2_mpeg_device::read), &(*m_mpeg)), write32_delegate(FUNC(m2_mpeg_device::write), &(*m_mpeg)), 0xffffffffffffffffULL);
+
+ space.install_readwrite_handler(CPUID_BASE, CPUID_BASE + DEVICE_MASK, read32_delegate(FUNC(m2_bda_device::cpu_id_r), this), write32_delegate(FUNC(m2_bda_device::cpu_id_w), this), 0xffffffffffffffffULL);
+
+
+ // Find and install the CDE
+ m2_cde_device *cde = downcast<m2_cde_device *>(machine().device("cde"));
+
+ if (cde == NULL)
+ throw emu_fatalerror("BDA: Could not find the CDE device!");
+
+ space.install_readwrite_handler(SLOT4_BASE, SLOT4_BASE + SLOT_MASK, read32_delegate(FUNC(m2_cde_device::read), cde), write32_delegate(FUNC(m2_cde_device::write), cde), 0xffffffffffffffffULL);
+}
+
+
+
+//**************************************************************************
+// POWERBUS DEVICE
+//**************************************************************************
+
+
+//-------------------------------------------------
+// m2_powerbus_device - constructor
+//-------------------------------------------------
+
+m2_powerbus_device::m2_powerbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, M2_POWERBUS, tag, owner, clock),
+ m_int_handler(*this)
+{
+
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_powerbus_device::device_start()
+{
+ // Resolve callbacks
+ m_int_handler.resolve();
+
+ // Register state for saving
+ save_item(NAME(m_ctrl));
+ save_item(NAME(m_int_enable));
+ save_item(NAME(m_int_status));
+ save_item(NAME(m_err_status));
+ save_item(NAME(m_err_address));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_powerbus_device::device_reset()
+{
+ m_ctrl = 0;
+ m_int_enable = 0;
+ m_int_status = 0;
+ m_err_status = 0;
+ m_err_address = 0;
+}
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ32_MEMBER( m2_powerbus_device::read )
+{
+ const uint32_t byte_offs = offset << 2;
+ uint32_t data = 0;
+
+ switch (byte_offs)
+ {
+ case BDAPCTL_PBINTENSET:
+ {
+ data = m_int_enable;
+ break;
+ }
+ case BDAPCTL_PBINTSTAT:
+ {
+ data = m_int_status;
+ break;
+ }
+ default:
+ logerror("%s: POWERBUS R: [%x] %x\n", machine().describe_context(), byte_offs, data);
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_powerbus_device::write )
+{
+ uint32_t byte_offs = offset << 2;
+
+ switch (byte_offs & ~0x400)
+ {
+ case BDAPCTL_PBINTENSET:
+ {
+ write_m2_reg(m_int_enable, data, byte_offs & 0x400 ? REG_CLEAR : REG_SET);
+ update_interrupts();
+ break;
+ }
+ case BDAPCTL_ERRSTAT:
+ {
+#if 1 // TODO
+ if (byte_offs & 0x400)
+ {
+ write_m2_reg(m_int_status, data, REG_CLEAR);
+ }
+ else
+ {
+ if (data == 1)
+ write_m2_reg(m_int_status, data, REG_SET);
+ }
+ update_interrupts();
+#endif
+ break;
+ }
+ default:
+ logerror("%s: POWERBUS W: [%x] %x (PC:%x)\n", machine().describe_context(), byte_offs, data);
+ }
+}
+
+
+/***************************************************************************
+ PRIVATE FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// update_interrupts -
+//-------------------------------------------------
+
+void m2_powerbus_device::update_interrupts()
+{
+ m_int_handler(m_int_status & m_int_enable ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+
+//**************************************************************************
+// MEMORY CONTROLLER DEVICE
+//**************************************************************************
+
+
+//-------------------------------------------------
+// m2_memctl_device - constructor
+//-------------------------------------------------
+
+m2_memctl_device::m2_memctl_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, M2_MEMCTL, tag, owner, clock),
+ m_gpio_in{{*this}, {*this}, {*this}, {*this}},
+ m_gpio_out{{*this}, {*this}, {*this}, {*this}}
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_memctl_device::device_start()
+{
+ // Resolve our callbacks
+ for (int i = 0; i < 4; i++)
+ {
+ m_gpio_in[i].resolve_safe(0);
+ m_gpio_out[i].resolve_safe();
+ }
+
+ // TODO: DELETE ME
+ m2_bda_device *m_bda = (m2_bda_device*)owner(); // TEMP
+
+ // Configure the memory configuration register
+ uint32_t bank1 = m_bda->get_rambank_size(0);
+ uint32_t bank2 = m_bda->get_rambank_size(1);
+
+ m_mcfg = (ramsize_to_mcfg_field(bank2) << MCFG_SS1_SHIFT) | (ramsize_to_mcfg_field(bank1) << MCFG_SS0_SHIFT);
+
+ // Register state for saving
+ save_item(NAME(m_mcfg));
+ save_item(NAME(m_mref));
+ save_item(NAME(m_mcntl));
+ save_item(NAME(m_reset));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_memctl_device::device_reset()
+{
+ // TODO: Need postload to set GPIO also?
+ m_mref = 0;
+}
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ32_MEMBER( m2_memctl_device::read )
+{
+ uint32_t byte_offs = offset << 2;
+ uint32_t data = 0;
+
+ switch (byte_offs)
+ {
+ case MCTL_MCONFIG:
+ {
+ data = m_mcfg;
+ break;
+ }
+ case MCTL_MREF:
+ {
+ if ((m_mref & MREF_GPIO0_GP) && !(m_mref & MREF_GPIO0_OUT))
+ {
+ if (m_gpio_in[0]())
+ m_mref |= MREF_GPIO0_VALUE;
+ else
+ m_mref &= ~MREF_GPIO0_VALUE;
+ }
+
+ if ((m_mref & MREF_GPIO1_GP) && !(m_mref & MREF_GPIO1_OUT))
+ {
+ if (m_gpio_in[1]())
+ m_mref |= MREF_GPIO1_VALUE;
+ else
+ m_mref &= ~MREF_GPIO1_VALUE;
+ }
+
+ if ((m_mref & MREF_GPIO2_GP) && !(m_mref & MREF_GPIO2_OUT))
+ {
+ if (m_gpio_in[2]())
+ m_mref |= MREF_GPIO2_VALUE;
+ else
+ m_mref &= ~MREF_GPIO2_VALUE;
+ }
+
+ if ((m_mref & MREF_GPIO3_GP) && !(m_mref & MREF_GPIO3_OUT))
+ {
+ if (m_gpio_in[3]())
+ m_mref |= MREF_GPIO3_VALUE;
+ else
+ m_mref &= ~MREF_GPIO3_VALUE;
+ }
+
+ data = m_mref;
+ break;
+ }
+ case MCTL_MCNTL:
+ case MCTL_MRESET:
+ //logerror("%s: MEMCTL READ: %x %x\n", machine().describe_context(), byte_offs, mem_mask);
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_memctl_device::write )
+{
+ uint32_t byte_offs = offset << 2;
+
+ switch (byte_offs)
+ {
+ case MCTL_MCONFIG:
+ {
+ m_mcfg = data;
+ break;
+ }
+ case MCTL_MREF:
+ {
+ // Set any general purpose outputs
+ if (data & (MREF_GPIO0_GP | MREF_GPIO0_OUT))
+ m_gpio_out[0](data & MREF_GPIO0_VALUE ? 1 : 0);
+
+ if (data & (MREF_GPIO1_GP | MREF_GPIO1_OUT))
+ m_gpio_out[1](data & MREF_GPIO1_VALUE ? 1 : 0);
+
+ if (data & (MREF_GPIO2_GP | MREF_GPIO2_OUT))
+ m_gpio_out[2](data & MREF_GPIO2_VALUE ? 1 : 0);
+
+ if (data & (MREF_GPIO3_GP | MREF_GPIO3_OUT))
+ m_gpio_out[3](data & MREF_GPIO3_VALUE ? 1 : 0);
+
+ m_mref = data;
+ break;
+ }
+ case MCTL_MCNTL:
+ case MCTL_MRESET:
+ //logerror("%s: MEMCTL WRITE: %x %x %x\n", machine().describe_context(), data, byte_offs);
+ break;
+ }
+}
+
+
+
+//**************************************************************************
+// VDU DEVICE
+//**************************************************************************
+
+
+//-------------------------------------------------
+// m2_vdu_device - constructor
+//-------------------------------------------------
+
+m2_vdu_device::m2_vdu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, M2_VDU, tag, owner, clock),
+ m_screen(*this, finder_base::DUMMY_TAG),
+ m_vint0_int_handler(*this),
+ m_vint1_int_handler(*this)
+{
+
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_vdu_device::device_start()
+{
+ // Resolve callbacks
+ m_vint0_int_handler.resolve_safe();
+ m_vint1_int_handler.resolve_safe();
+
+ // Initialize line interrupt timers
+ m_vint0_timer = timer_alloc(TIMER_ID_VINT0);
+ m_vint1_timer = timer_alloc(TIMER_ID_VINT1);
+
+ // Calculate H/V count bias values (1 = start of blanking)
+ const rectangle visarea = m_screen->visible_area();
+
+ m_hstart = visarea.min_x;
+ m_htotal = visarea.max_x + 1;
+
+ m_vstart = visarea.min_y;
+ m_vtotal = visarea.max_y + 1;
+
+ // Register state for saving
+ save_item(NAME(m_vint));
+ save_item(NAME(m_vdc0));
+ save_item(NAME(m_vdc1));
+ save_item(NAME(m_fv0a));
+ save_item(NAME(m_fv1a));
+ save_item(NAME(m_avdi));
+ save_item(NAME(m_vdli));
+ save_item(NAME(m_vcfg));
+ save_item(NAME(m_dmt0));
+ save_item(NAME(m_dmt1));
+ save_item(NAME(m_vrst));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_vdu_device::device_reset()
+{
+ m_fv0a = 0;
+ m_fv1a = 0;
+ m_avdi = 0;
+ m_vdli = 0;
+ m_vint = 0;
+ m_vcfg = 0;
+ m_dmt0 = 0;
+ m_dmt1 = 0;
+
+ m_vint0_timer->adjust(attotime::never);
+ m_vint1_timer->adjust(attotime::never);
+}
+
+
+//-------------------------------------------------
+// device_timer - device-specific timers
+//-------------------------------------------------
+
+void m2_vdu_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_ID_VINT0:
+ {
+ m_vint |= VDU_VINT_VINT0;
+ m_vint0_int_handler(ASSERT_LINE);
+ set_vint_timer(0);
+ break;
+ }
+ case TIMER_ID_VINT1:
+ {
+ m_vint |= VDU_VINT_VINT1;
+ m_vint1_int_handler(ASSERT_LINE);
+ set_vint_timer(1);
+ break;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ32_MEMBER( m2_vdu_device::read )
+{
+ uint32_t byte_offs = offset << 2;
+ uint32_t data = 0;
+
+ switch (byte_offs)
+ {
+ case VDU_VLOC:
+ {
+ // TODO: Check me
+ uint32_t mpos = m_screen->vpos();
+ uint32_t vpos = ((mpos + m_vstart) % m_vtotal) + 1;
+ data = vpos << VDU_VLOC_VCOUNT_SHIFT;
+ break;
+ }
+ case VDU_VINT:
+ {
+ data = m_vint;
+ break;
+ }
+ case VDU_VDC0:
+ case VDU_VDC1:
+ case VDU_FV0A:
+ case VDU_FV1A:
+ case VDU_AVDI:
+ case VDU_VDLI:
+ case VDU_VCFG:
+ case VDU_DMT0:
+ case VDU_DMT1:
+ case VDU_LFSR:
+ {
+ //logerror("%s: VDU READ: %x %x\n", machine().describe_context(), byte_offs, mem_mask);
+ break;
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_vdu_device::write )
+{
+ uint32_t byte_offs = offset << 2;
+ reg_wmode wmode = byte_offs & 0x400 ? REG_CLEAR : REG_WRITE;
+
+// logerror("%s: VDU WRITE: %03x %08x %x\n", machine().describe_context(), byte_offs, data, mem_mask);
+ byte_offs &= ~0x400;
+ switch (byte_offs)
+ {
+ case VDU_VINT:
+ {
+ uint32_t old = m_vint;
+ write_m2_reg(m_vint, data, wmode);
+
+ // Update line interrupts if changed
+ if ((m_vint & VDU_VINT_VLINE0_MASK) != (old & VDU_VINT_VLINE0_MASK))
+ set_vint_timer(0);
+
+ if ((m_vint & VDU_VINT_VLINE1_MASK) != (old & VDU_VINT_VLINE1_MASK))
+ set_vint_timer(1);
+
+ // Clear interrupt bits
+ if ((old & VDU_VINT_VINT0) && !(m_vint & VDU_VINT_VINT0))
+ m_vint0_int_handler(CLEAR_LINE);
+
+ if ((old & VDU_VINT_VINT1) && !(m_vint & VDU_VINT_VINT1))
+ m_vint1_int_handler(CLEAR_LINE);
+
+ break;
+ }
+ case VDU_FV0A:
+ {
+ m_fv0a = data;
+ break;
+ }
+ case VDU_FV1A:
+ {
+ m_fv1a = data;
+ break;
+ }
+ case VDU_VCFG:
+ {
+ m_vcfg = data;
+ break;
+ }
+ case VDU_VRST:
+ {
+ m_vrst = data;
+ break;
+ }
+ default:
+ {
+ logerror("%s: VDU WRITE: %x %x %x\n", machine().describe_context(), byte_offs, data, mem_mask);
+ break;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// parse_dc_word -
+//-------------------------------------------------
+
+void m2_vdu_device::parse_dc_word(uint32_t cmd)
+{
+ // Determine the control register
+ uint32_t &vdc = cmd & VDL_DC_1 ? m_vdc1 : m_vdc0;
+
+ // Horizontal interpolation
+ uint32_t hint = (cmd & VDL_DC_HINTCTL_MASK) >> VDL_DC_HINTCTL_SHIFT;
+
+ if (hint == VDL_CTL_ENABLE)
+ vdc |= VDU_VDC_HINT;
+ else if (hint == VDL_CTL_DISABLE)
+ vdc &= ~VDU_VDC_HINT;
+
+
+ // Vertical interpolation
+ uint32_t vint = (cmd & VDL_DC_VINTCTL_MASK) >> VDL_DC_VINTCTL_SHIFT;
+
+ if (vint == VDL_CTL_ENABLE)
+ vdc |= VDU_VDC_VINT;
+ else if (vint == VDL_CTL_DISABLE)
+ vdc &= ~VDU_VDC_VINT;
+
+
+ // Dithering
+ uint32_t dith = (cmd & VDL_DC_DITHERCTL_MASK) >> VDL_DC_DITHERCTL_SHIFT;
+
+ if (dith == VDL_CTL_ENABLE)
+ vdc |= VDU_VDC_DITHER;
+ else if (dith == VDL_CTL_DISABLE)
+ vdc &= ~VDU_VDC_DITHER;
+
+
+ // MTXBYP (?)
+ uint32_t mtxbyp = (cmd & VDL_DC_MTXBYPCTL_MASK) >> VDL_DC_MTXBYPCTL_SHIFT;
+
+ if (mtxbyp == VDL_CTL_ENABLE)
+ vdc |= VDU_VDC_MTXBYP;
+ else if (mtxbyp == VDL_CTL_DISABLE)
+ vdc &= ~VDU_VDC_MTXBYP;
+}
+
+
+//-------------------------------------------------
+// parse_av_word -
+//-------------------------------------------------
+
+void m2_vdu_device::parse_av_word(uint32_t cmd)
+{
+ if (cmd & VDL_AV_LD_HSTART)
+ {
+ uint32_t hstart = (cmd & VDL_AV_HSTART_MASK) >> VDL_AV_HSTART_SHIFT;
+ m_avdi &= ~VDU_AVDI_HSTART_MASK;
+ m_avdi |= hstart << VDU_AVDI_HSTART_SHIFT;
+ }
+ if (cmd & VDL_AV_LD_HWIDTH)
+ {
+ uint32_t hwidth = (cmd & VDL_AV_HWIDTH_MASK) >> VDL_AV_HWIDTH_SHIFT;
+ m_avdi &= ~VDU_AVDI_HWIDTH_MASK;
+ m_avdi |= hwidth << VDU_AVDI_HWIDTH_SHIFT;
+ }
+ if (cmd & VDL_AV_LD_HDOUBLE)
+ {
+ if (cmd & VDL_AV_HDOUBLE)
+ m_avdi |= VDU_AVDI_HDOUBLE;
+ else
+ m_avdi &= ~VDU_AVDI_HDOUBLE;
+ }
+ if (cmd & VDL_AV_LD_VDOUBLE)
+ {
+ if (cmd & VDL_AV_VDOUBLE)
+ m_avdi |= VDU_AVDI_VDOUBLE;
+ else
+ m_avdi &= ~VDU_AVDI_VDOUBLE;
+ }
+}
+
+
+//-------------------------------------------------
+// parse_lc_word -
+//-------------------------------------------------
+
+void m2_vdu_device::parse_lc_word(uint32_t cmd)
+{
+ // TODO: This may not be used
+ if (cmd & VDL_LC_LD_BYPASSTYPE)
+ {
+ m_vdli &= ~VDU_VDLI_BYPASSTYPE;
+ m_vdli |= (cmd & VDU_VDLI_BYPASSTYPE) == VDU_VDLI_BYPASSTYPE_MSB ? VDU_VDLI_BYPASSTYPE_MSB : VDU_VDLI_BYPASSTYPE_LSB;
+ }
+ if (cmd & VDL_LC_LD_FBFORMAT)
+ {
+ m_vdli &= ~VDU_VDLI_FBFORMAT;
+ m_vdli |= (cmd & VDL_LC_FBFORMAT) == VDL_LC_FBFORMAT_32 ? VDU_VDLI_FBFORMAT_32 : VDU_VDLI_FBFORMAT_16;
+ }
+
+ // Seems these two are always set by the command word
+ if (cmd & VDL_LC_RANDOMDITHER)
+ m_vdli |= VDU_VDLI_RANDOMDITHER;
+ else
+ m_vdli &= ~VDU_VDLI_RANDOMDITHER;
+
+ if (cmd & VDL_LC_ONEVINTDIS)
+ m_vdli |= VDU_VDLI_ONEVINTDIS;
+ else
+ m_vdli &= ~VDU_VDLI_ONEVINTDIS;
+}
+
+
+//-------------------------------------------------
+// draw_scanline - Draw a scanline
+//-------------------------------------------------
+
+void m2_vdu_device::draw_scanline(uint32_t *dst, uint32_t srclower, uint32_t srcupper)
+{
+ m2_bda_device *m_bda = (m2_bda_device*)owner(); // TEMP
+
+ uint32_t hs = (m_avdi & VDU_AVDI_HSTART_MASK) >> VDU_AVDI_HSTART_SHIFT;
+ uint32_t hw = (m_avdi & VDU_AVDI_HWIDTH_MASK) >> VDU_AVDI_HWIDTH_SHIFT;
+
+ bool is32bpp = m_vdli & VDU_VDLI_FBFORMAT_32 ? true : false;
+// bool bypassmsb = m_vdli & VDU_VDLI_BYPASSTYPE_MSB ? true : false;
+// bool randomdith = m_vdli & VDU_VDLI_RANDOMDITHER ? true : false;
+
+ uint32_t h = 0;
+
+ // Left border
+ while (h < hs)
+ {
+ *dst++ = rgb_t::black();
+ ++h;
+ }
+
+ // Active video area
+ uint32_t vismax = std::min<uint32_t>(h + hw, m_htotal);
+
+ if (is32bpp)
+ {
+ while (h < vismax)
+ {
+ *dst++ = m_bda->read_bus32(srclower);
+ srclower += 4;
+ ++h;
+ }
+ }
+ else
+ {
+ while (h < vismax)
+ {
+ uint16_t srcdata = m_bda->read_bus16(srclower);
+ *dst++ = pal555(srcdata, 10, 5, 0);
+ srclower += 2;
+ ++h;
+ }
+ }
+
+ // Right border
+ while (h < m_htotal)
+ {
+ *dst++ = rgb_t::black();
+ ++h;
+ }
+}
+
+
+//-------------------------------------------------
+// draw_scanline_double - Draw a pixel-doubled scanline
+//-------------------------------------------------
+
+void m2_vdu_device::draw_scanline_double(uint32_t *dst, uint32_t srclower, uint32_t srcupper)
+{
+ m2_bda_device *m_bda = (m2_bda_device*)owner(); // TEMP
+
+ uint32_t hs = (m_avdi & VDU_AVDI_HSTART_MASK) >> VDU_AVDI_HSTART_SHIFT;
+ uint32_t hw = (m_avdi & VDU_AVDI_HWIDTH_MASK) >> VDU_AVDI_HWIDTH_SHIFT;
+
+ bool is32bpp = m_vdli & VDU_VDLI_FBFORMAT_32 ? true : false;
+// bool bypassmsb = m_vdli & VDU_VDLI_BYPASSTYPE_MSB ? true : false;
+// bool randomdith = m_vdli & VDU_VDLI_RANDOMDITHER ? true : false;
+
+ uint32_t h = 0;
+
+ // Left border
+ while (h < hs)
+ {
+ *dst++ = rgb_t::black();
+ ++h;
+ }
+
+ // Active video area
+ uint32_t vismax = std::min<uint32_t>(h + hw, m_htotal);
+
+ if (is32bpp)
+ {
+ while (h < vismax)
+ {
+ uint32_t srcdata = m_bda->read_bus32(srclower);
+
+ srclower += 4;
+ *dst++ = srcdata;
+ *dst++ = srcdata;
+ ++h;
+ }
+ }
+ else
+ {
+ while (h < vismax)
+ {
+ uint32_t srcdata = m_bda->read_bus16(srclower);
+ srcdata = pal555(srcdata, 10, 5, 0);
+
+ srclower += 2;
+ *dst++ = srcdata;
+ *dst++ = srcdata;
+ ++h;
+ }
+ }
+
+ // Right border
+ while (h < m_htotal)
+ {
+ *dst++ = rgb_t::black();
+ ++h;
+ }
+}
+
+
+//-------------------------------------------------
+// core_update_screen -
+//-------------------------------------------------
+
+
+
+//-------------------------------------------------
+// screen_update -
+//-------------------------------------------------
+
+uint32_t m2_vdu_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ m2_bda_device *m_bda = (m2_bda_device*)owner(); // TEMP
+
+ // TODO: Interlace mode
+ uint32_t addr = m_fv0a;//screen.frame_number() & 1 ? m_fv1a : m_fv0a;
+
+ // Fill entire screen with black if disabled
+ if ((m_vrst & (VDU_VRST_VIDRESET | VDU_VRST_DVERESET)) || addr == 0)
+ {
+ bitmap.fill(rgb_t::black());
+ return 0;
+ }
+
+ // Processing begins at VSYNC
+ uint32_t v = 0;
+
+ // Process VDLs until all lines are exhausted
+ while (v < m_vtotal)
+ {
+ // Fetch the 4 header words
+ uint32_t dmactl = m_bda->read_bus32(addr);
+ uint32_t lower = m_bda->read_bus32(addr + 4);
+ uint32_t upper = m_bda->read_bus32(addr + 8);
+ uint32_t next = m_bda->read_bus32(addr + 12);
+
+ addr += 16;
+
+ // Word count includes the header
+ uint32_t words = (dmactl & VDL_DMA_NWORDS_MASK) >> VDL_DMA_NWORDS_SHIFT;
+ words -= 4;
+
+ // Check and adjust the line count
+ uint32_t lines = (dmactl & VDL_DMA_NLINES_MASK) >> VDL_DMA_NLINES_SHIFT;
+
+ if (lines > 0)
+ {
+ uint32_t vend = v + lines;
+
+ if (vend > m_vtotal)
+ lines = vend - m_vtotal;
+ }
+ else
+ {
+ // A zero count denotes all of the remaining screen lines
+ lines = m_vtotal - v;
+ }
+
+ // Parse the command list and update video registers accordingly
+ while (words-- > 0)
+ {
+ uint32_t cmd = m_bda->read_bus32(addr);
+ addr += 4;
+
+ switch (cmd & 0xe0000000)
+ {
+ case VDL_DC:
+ {
+ parse_dc_word(cmd);
+ break;
+ }
+ case VDL_AV:
+ {
+ parse_av_word(cmd);
+ break;
+ }
+ case VDL_LC:
+ {
+ parse_lc_word(cmd);
+ break;
+ }
+ default:
+ {
+ if (cmd != VDL_NOP)
+ fatalerror("VDU: Unknown VDL command word\n");
+ break;
+ }
+ }
+ }
+
+ // DMA from RAM to the display
+ if (dmactl & VDL_DMA_ENABLE)
+ {
+ bool hdouble = m_avdi & VDU_AVDI_HDOUBLE ? true : false;
+ bool vdouble = m_avdi & VDU_AVDI_VDOUBLE ? true : false;
+// bool onevintdis = m_vdli & VDU_VDLI_ONEVINTDIS ? true : false;
+
+ uint32_t srclower = lower;
+ uint32_t srcupper = upper;
+ uint32_t mod = ((dmactl & VDL_DMA_MOD_MASK) >> VDL_DMA_MOD_SHIFT) << 5;
+
+ // Draw these lines
+ while (lines--)
+ {
+ // Line doubling is easily handled
+ for (uint32_t ys = vdouble ? 2 : 1; ys > 0; --ys)
+ {
+ if (hdouble)
+ draw_scanline_double(&bitmap.pix32(v, 0), srclower, srcupper);
+ else
+ draw_scanline(&bitmap.pix32(v, 0), srclower, srcupper);
+
+ ++v;
+ }
+ // Update the source addresses
+ srclower += mod;
+ srcupper += mod;
+ }
+ }
+ else
+ {
+ // Blank this block of lines if DMA is disabled
+ while (lines--)
+ {
+ uint32_t *dst = &bitmap.pix32(v, cliprect.min_x);
+
+ for (uint32_t x = cliprect.min_x; x <= cliprect.max_x; ++x)
+ *dst++ = rgb_t::black();
+
+ ++v;
+ }
+ }
+
+ // Jump to the next VDL
+ addr = next;
+ }
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// set_vint_timer -
+//-------------------------------------------------
+
+void m2_vdu_device::set_vint_timer(uint32_t id)
+{
+ uint32_t v;
+ emu_timer *timer = (id == 0) ? m_vint0_timer : m_vint1_timer;
+
+ if (id == 0)
+ v = (m_vint & VDU_VINT_VLINE0_MASK) >> VDU_VINT_VLINE0_SHIFT;
+ else
+ v = (m_vint & VDU_VINT_VLINE1_MASK) >> VDU_VINT_VLINE1_SHIFT;
+
+ if (v == 0)
+ {
+ // Apparently 0 is invalid
+ timer->adjust(attotime::never);
+ }
+ else
+ {
+ // Adjust the count to what the core expects
+ uint32_t vadj = (v - 1 + (m_vtotal - m_vstart)) % m_vtotal;
+ timer->adjust(m_screen->time_until_pos(vadj));
+ }
+}
+
+
+
+//**************************************************************************
+// CONTROL PORTS DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// m2_ctrlport_device - constructor
+//-------------------------------------------------
+
+m2_ctrlport_device::m2_ctrlport_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, M2_CTRLPORT, tag, owner, clock)
+{
+
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_ctrlport_device::device_start()
+{
+
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_ctrlport_device::device_reset()
+{
+
+}
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ32_MEMBER( m2_ctrlport_device::read )
+{
+ //const uint32_t byte_offs = offset << 2;
+ uint32_t data = machine().rand();
+
+ //switch (byte_offs)
+ //{
+ //default:
+ //logerror("%s: CTRLPORT R: [%x] %x\n", machine().describe_context(), byte_offs, data);
+ //}
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_ctrlport_device::write )
+{
+ //uint32_t byte_offs = offset << 2;
+
+ //switch (byte_offs)
+ //{
+ //default:
+ //logerror("%s: CTRLPORT W: [%x] %x\n", machine().describe_context(), byte_offs, data);
+ //}
+}
+
+
+/***************************************************************************
+ PRIVATE FUNCTIONS
+***************************************************************************/
+
+
+
+
+
+//**************************************************************************
+// CDE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// m2_cde_device - constructor
+//-------------------------------------------------
+
+m2_cde_device::m2_cde_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, M2_CDE, tag, owner, clock),
+ m_cpu1(*this, finder_base::DUMMY_TAG),
+ m_int_handler(*this),
+ m_sdbg_out_handler(*this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_cde_device::device_start()
+{
+ // Find our friend the BDA
+ m_bda = downcast<m2_bda_device *>(machine().device("bda"));
+ assert(m_bda != NULL);
+
+ if (m_bda == NULL)
+ throw device_missing_dependencies();
+
+ // Resolve callbacks
+ m_int_handler.resolve_safe();
+ m_sdbg_out_handler.resolve_safe();
+
+ // Init DMA
+ m_dma[0].m_timer = timer_alloc(TIMER_ID_DMA1);
+ m_dma[1].m_timer = timer_alloc(TIMER_ID_DMA2);
+
+ // Register state for saving
+ save_item(NAME(m_sdbg_cntl));
+ save_item(NAME(m_int_status));
+ save_item(NAME(m_int_enable));
+ save_item(NAME(m_bblock_en));
+ save_item(NAME(m_visa_dis));
+
+ for (uint32_t i = 0; i < 8; ++i)
+ {
+ save_item(NAME(m_bio_device[i].m_setup), i);
+ save_item(NAME(m_bio_device[i].m_cycle_time), i);
+ }
+
+ for (uint32_t i = 0; i < 2; ++i)
+ {
+ save_item(NAME(m_dma[i].m_cntl), i);
+ save_item(NAME(m_dma[i].m_cbad), i);
+ save_item(NAME(m_dma[i].m_cpad), i);
+ save_item(NAME(m_dma[i].m_ccnt), i);
+ save_item(NAME(m_dma[i].m_nbad), i);
+ save_item(NAME(m_dma[i].m_npad), i);
+ save_item(NAME(m_dma[i].m_ncnt), i);
+ // timer
+ }
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_cde_device::device_reset()
+{
+ m_sdbg_cntl = 0;
+ m_int_status = 0;
+ m_int_enable = 0;
+
+ // TODO? Boot block is clear on reset
+ m_bblock_en = 1; // ?
+ m_visa_dis = 0;
+
+ reset_dma(0);
+ reset_dma(1);
+}
+
+
+//-------------------------------------------------
+// device_post_load - device-specific post-load
+//-------------------------------------------------
+
+void m2_cde_device::device_post_load()
+{
+
+}
+
+
+//-------------------------------------------------
+// device_timer - a timer
+//-------------------------------------------------
+
+void m2_cde_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_ID_READY:
+ // TODO ?
+ set_interrupt(CDE_ID_READY);
+ break;
+
+ case TIMER_ID_DMA1:
+ next_dma(0);
+ break;
+
+ case TIMER_ID_DMA2:
+ next_dma(1);
+ break;
+
+ default:
+ assert_always(false, "Unknown CDE timer ID");
+ }
+}
+
+
+//-------------------------------------------------
+// set_interrupt -
+//-------------------------------------------------
+
+void m2_cde_device::set_interrupt(uint32_t intmask)
+{
+ m_int_status |= (uint32_t)intmask;
+ update_interrupts();
+}
+
+
+//-------------------------------------------------
+// update_interrupts -
+//-------------------------------------------------
+
+void m2_cde_device::update_interrupts()
+{
+ if (m_int_status & m_int_enable)
+ m_int_handler(ASSERT_LINE);
+ else
+ m_int_handler(CLEAR_LINE);
+}
+
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ32_MEMBER( m2_cde_device::read )
+{
+ const uint32_t byte_offs = offset << 2;
+ uint32_t data = 0;
+
+ switch (byte_offs)
+ {
+ case CDE_DEVICE_ID:
+ {
+ data = 0x00010000;
+ break;
+ }
+ case CDE_VERSION:
+ {
+ data = 0; // TODO
+ break;
+ }
+ case CDE_SDBG_CNTL:
+ {
+ data = m_sdbg_cntl;
+ break;
+ }
+ case CDE_SDBG_RD:
+ {
+ data = m_sdbg_in;
+ break;
+ }
+ case CDE_INT_STS:
+ {
+ data = m_int_status;
+ break;
+ }
+ case CDE_CD_STS_RD:
+ {
+ data = 0x000; // Status ready = 0x100
+ break;
+ }
+ case CDE_INT_ENABLE:
+ {
+ data = m_int_enable;
+ break;
+ }
+ case CDE_DEV_DETECT:
+ {
+ data = 0x0; // ?
+ break;
+ };
+ case CDE_BBLOCK:
+ {
+ // 8, 80
+ data = 0x80; // Needs to be non-zero
+ break;
+ }
+ case CDE_UNIQ_ID_RD:
+ {
+ data = 0xffffffff; // ?
+ break;
+ }
+ case CDE_BBLOCK_EN:
+ {
+ data = m_bblock_en;
+ break;
+ }
+ case CDE_SYSTEM_CONF:
+ {
+ data = m_syscfg;
+ break;
+ }
+ case CDE_MICRO_STATUS:
+ {
+ data = 0x20; // TODO
+ break;
+ }
+ case CDE_MICRO_RWS:
+ {
+ break;
+ }
+ case CDE_VISA_DIS:
+ {
+ data = m_visa_dis;
+ break;
+ }
+ case CDE_DMA1_CNTL:
+ case CDE_DMA2_CNTL:
+ {
+ uint32_t ch = (byte_offs & 0x20) ? 1 : 0;
+ data = m_dma[ch].m_cntl;
+ break;
+ }
+ default:
+ {
+ //logerror("%s: CDE_R UNHANDLED: 0x%.8x 0x%.8x\n", machine().describe_context(), byte_offs, mem_mask));
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_cde_device::write )
+{
+ uint32_t byte_offs = offset << 2;
+ uint32_t dmach = byte_offs & 0x20 ? 1 : 0;
+
+ reg_wmode wm_cw = byte_offs & 0x400 ? REG_CLEAR : REG_WRITE;
+ reg_wmode wm_cs = byte_offs & 0x400 ? REG_CLEAR : REG_SET;
+
+ byte_offs &= ~0x400;
+
+ switch (byte_offs)
+ {
+ case CDE_SDBG_CNTL:
+ {
+ // ........ ........ xxxxxxxx xxxx.... Clock scaler (written with 33MHz/38400 = 868)
+ write_m2_reg(m_sdbg_cntl, data, wm_cw);
+ break;
+ }
+ case CDE_SDBG_WRT:
+ {
+ m_sdbg_out_handler(data);
+ set_interrupt(CDE_SDBG_WRT_DONE);
+ break;
+ }
+ case CDE_INT_STS:
+ {
+ write_m2_reg(m_int_status, data, wm_cw);
+ update_interrupts();
+ break;
+ }
+ case CDE_INT_ENABLE:
+ {
+ write_m2_reg(m_int_enable, data, wm_cs);
+ update_interrupts();
+ break;
+ }
+ case CDE_RESET_CNTL:
+ {
+ if (data & 1)
+ {
+ // TODO: Should we reset both CPUs?
+ downcast<cpu_device *>(&space.device())->pulse_input_line(INPUT_LINE_RESET, attotime::zero);
+
+ // TODO: Is this correct?
+ m_bblock_en = 0;
+ }
+ else if (data & 2)
+ {
+ // TODO: Hard reset
+ }
+
+ break;
+ }
+ case CDE_CD_CMD_WRT:
+ {
+ //set_interrupt(CDE_CD_CMD_WRT_DONE); // ?
+ //set_interrupt(CDE_CD_STS_FL_DONE); // ?
+ break;
+ };
+ case CDE_UNIQ_ID_CMD:
+ {
+ // TODO: What is this?
+ timer_set(attotime::from_usec(250), TIMER_ID_READY);
+ break;
+ }
+ case CDE_BBLOCK:
+ {
+ break;
+ }
+
+ case CDE_DEV0_SETUP:
+ case CDE_DEV1_SETUP:
+ case CDE_DEV2_SETUP:
+ case CDE_DEV3_SETUP:
+ case CDE_DEV4_SETUP:
+ case CDE_DEV5_SETUP:
+ case CDE_DEV6_SETUP:
+ case CDE_DEV7_SETUP:
+ {
+ uint32_t id = (byte_offs - CDE_DEV0_SETUP) >> 3;
+ write_m2_reg(m_bio_device[id].m_setup, data, wm_cw);
+ break;
+ }
+
+ case CDE_DEV0_CYCLE_TIME:
+ case CDE_DEV1_CYCLE_TIME:
+ case CDE_DEV2_CYCLE_TIME:
+ case CDE_DEV3_CYCLE_TIME:
+ case CDE_DEV4_CYCLE_TIME:
+ case CDE_DEV5_CYCLE_TIME:
+ case CDE_DEV6_CYCLE_TIME:
+ case CDE_DEV7_CYCLE_TIME:
+ {
+ uint32_t id = (byte_offs - CDE_DEV0_CYCLE_TIME) >> 3;
+ write_m2_reg(m_bio_device[id].m_cycle_time, data, wm_cw);
+ break;
+ }
+
+// case CDE_SYSTEM_CONF:
+ case CDE_VISA_DIS:
+ {
+ write_m2_reg(m_visa_dis, data, wm_cw);
+ break;
+ }
+ case CDE_MICRO_RWS:
+ case CDE_MICRO_WI:
+ case CDE_MICRO_WOB:
+ case CDE_MICRO_WO:
+ case CDE_MICRO_STATUS:
+ {
+ break;
+ }
+
+ case CDE_DMA1_CNTL:
+ case CDE_DMA2_CNTL:
+ {
+ uint32_t &ctrl = m_dma[dmach].m_cntl;
+ uint32_t old = ctrl;
+
+ write_m2_reg(ctrl, data, wm_cw);
+
+ if (!(old & CDE_DMA_RESET) && (ctrl & CDE_DMA_RESET))
+ reset_dma(dmach);
+
+ if (!(old & CDE_DMA_CURR_VALID) && (ctrl & CDE_DMA_CURR_VALID))
+ start_dma(dmach);
+
+ break;
+ }
+ case CDE_DMA1_CBAD:
+ case CDE_DMA2_CBAD:
+ {
+ write_m2_reg(m_dma[dmach].m_cbad, data, wm_cw);
+ break;
+ }
+ case CDE_DMA1_CPAD:
+ case CDE_DMA2_CPAD:
+ {
+ write_m2_reg(m_dma[dmach].m_cpad, data, wm_cw);
+ break;
+ }
+ case CDE_DMA1_CCNT:
+ case CDE_DMA2_CCNT:
+ {
+ write_m2_reg(m_dma[dmach].m_ccnt, data, wm_cw);
+ break;
+ }
+ default:
+ {
+ //logerror("%s: CDE_W UNHANDLED: 0x%.8x 0x%.8x 0x%.8x\n", machine().describe_context(), byte_offs, data, mem_mask);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// sdbg_in -
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_cde_device::sdbg_in )
+{
+ m_sdbg_in = data;
+ set_interrupt(CDE_SDBG_RD_DONE);
+}
+
+
+
+
+/***************************************************************************
+ PRIVATE FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// reset_dma - Reset a DMA channel
+//-------------------------------------------------
+
+void m2_cde_device::reset_dma(uint32_t ch)
+{
+ m_dma[ch].m_cntl = 0;
+ m_dma[ch].m_timer->adjust(attotime::never);
+}
+
+
+//-------------------------------------------------
+// start_dma - DMA between the PowerBus and BioBus
+//-------------------------------------------------
+
+void m2_cde_device::start_dma(uint32_t ch)
+{
+ dma_channel &dma_ch = m_dma[ch];
+ address_space *dma_space = &m_cpu1->space();
+
+ // TODO: DMA timing is probably inaccurate
+ attotime delay = attotime::from_nsec(10);// * dma_ch.m_ccnt;
+
+// attotime delay = clocks_to_attotime(4 * dma_ch.m_ccnt);
+ dma_ch.m_timer->adjust(delay);
+
+ if (dma_ch.m_cntl & CDE_DMA_DIRECTION)
+ {
+ // PowerBus to BioBus
+ assert_always(false, "CDE PowerBus to BioBus DMA currently unsupported");
+ }
+ else
+ {
+ // BioBus to PowerBus
+#if 0
+ logerror("%s: CDE DMA %u: [%.8x] -> [%.8x], 0x%.8x bytes\n", machine().describe_context(), ch, dma_ch.m_cbad, dma_ch.m_cpad, dma_ch.m_ccnt);
+#endif
+ // Determine the BioBus device from the address
+ const uint32_t slot = address_to_biobus_slot(dma_ch.m_cbad);
+
+ // Get the device parameters
+ const uint32_t setup = m_bio_device[slot].m_setup;
+
+ if (setup & CDE_DATAWIDTH_16)
+ {
+ // 16-bit case
+ assert_always((dma_ch.m_ccnt & 1) == 0, "16-bit DMA: Byte count must be even?");
+ assert_always((dma_ch.m_cpad & 1) == 0, "16-bit DMA: DMA destination must be word aligned?");
+
+ const uint32_t srcinc = setup & CDE_READ_SETUP_IO ? 0 : 2;
+
+ while (dma_ch.m_ccnt > 0)
+ {
+ uint16_t data = dma_space->read_word_unaligned(dma_ch.m_cbad); // FIX ME
+ dma_space->write_word(dma_ch.m_cpad, data);
+
+ dma_ch.m_cbad += srcinc;
+ dma_ch.m_cpad += 2;
+ dma_ch.m_ccnt -= 2;
+ }
+ }
+ else
+ {
+ // 8-bit case
+ const uint32_t srcinc = setup & CDE_READ_SETUP_IO ? 0 : 1;
+
+ fatalerror("8-bit DMA untested\n");
+
+ while (dma_ch.m_ccnt > 0)
+ {
+ uint8_t data = dma_space->read_byte(dma_ch.m_cbad);
+ dma_space->write_byte(dma_ch.m_cpad, data);
+
+ dma_ch.m_cbad += srcinc;
+ dma_ch.m_cpad += 1;
+ dma_ch.m_ccnt -= 1;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------
+// next_dma - Start the next DMA if set
+//-------------------------------------------------
+
+void m2_cde_device::next_dma(uint32_t ch)
+{
+ dma_channel &dma_ch = m_dma[ch];
+
+ // TODO: HACK!
+#if 1
+ m_cpu1->set_cache_dirty();
+#endif
+
+ assert_always(dma_ch.m_ccnt == 0, "DMA count non-zero during next DMA");
+
+ if (dma_ch.m_cntl & CDE_DMA_NEXT_VALID)
+ {
+ logerror("NEXT DMA CODE UNTESTED");
+
+ // Update current address and count registers
+ dma_ch.m_cbad = dma_ch.m_nbad;
+ dma_ch.m_cpad = dma_ch.m_npad;
+ dma_ch.m_ccnt = dma_ch.m_ncnt;
+ dma_ch.m_cntl |= CDE_DMA_CURR_VALID;
+
+ // Disable looping
+ if (!(dma_ch.m_cntl & CDE_DMA_GO_FOREVER))
+ dma_ch.m_cntl &= ~CDE_DMA_NEXT_VALID;
+
+ start_dma(ch);
+ }
+ else
+ {
+ // DMA complete
+ dma_ch.m_cntl &= ~CDE_DMA_CURR_VALID;
+ set_interrupt(ch == 0 ? CDE_DMA1_DONE : CDE_DMA2_DONE);
+ }
+}
+
+
+/***************************************************************************
+ MPEG DEVICE
+ ***************************************************************************/
+
+//-------------------------------------------------
+// m2_mpeg_device - constructor
+//-------------------------------------------------
+
+m2_mpeg_device::m2_mpeg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, M2_MPEG, tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_mpeg_device::device_start()
+{
+
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_mpeg_device::device_reset()
+{
+
+}
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+READ32_MEMBER( m2_mpeg_device::read )
+{
+ logerror("%s: MPEG READ: %08X\n", machine().describe_context(), offset);
+ return 0;
+}
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_mpeg_device::write )
+{
+ logerror("%s: MPEG WRITE: %08X %08X\n", machine().describe_context(), offset, data);
+}