From 47bc16858f775ee9e6a6d666414a4341d7527561 Mon Sep 17 00:00:00 2001 From: "R. Belmont" Date: Sun, 11 Aug 2013 21:29:58 +0000 Subject: [PATCH] (MESS) MPU-401: preliminary checkpoint. [R. Belmont, kevtris] --- .gitattributes | 2 + src/mess/machine/isa_mpu401.c | 58 +++----- src/mess/machine/isa_mpu401.h | 10 +- src/mess/machine/mpu401.c | 250 ++++++++++++++++++++++++++++++++++ src/mess/machine/mpu401.h | 69 ++++++++++ src/mess/mess.mak | 3 +- 6 files changed, 353 insertions(+), 39 deletions(-) create mode 100644 src/mess/machine/mpu401.c create mode 100644 src/mess/machine/mpu401.h diff --git a/.gitattributes b/.gitattributes index a5174819e20..647a0547c7b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7633,6 +7633,8 @@ src/mess/machine/mos8726.c svneol=native#text/plain src/mess/machine/mos8726.h svneol=native#text/plain src/mess/machine/mpc105.c svneol=native#text/plain src/mess/machine/mpc105.h svneol=native#text/plain +src/mess/machine/mpu401.c svneol=native#text/plain +src/mess/machine/mpu401.h svneol=native#text/plain src/mess/machine/msm6222b.c svneol=native#text/plain src/mess/machine/msm6222b.h svneol=native#text/plain src/mess/machine/msx.c svneol=native#text/plain diff --git a/src/mess/machine/isa_mpu401.c b/src/mess/machine/isa_mpu401.c index 0539c881c95..46a39a44e61 100644 --- a/src/mess/machine/isa_mpu401.c +++ b/src/mess/machine/isa_mpu401.c @@ -11,6 +11,12 @@ #include "isa_mpu401.h" #include "machine/pic8259.h" +#define MPU_CORE_TAG "mpu401" + +MACHINE_CONFIG_FRAGMENT( isa8mpu401 ) + MCFG_MPU401_ADD(MPU_CORE_TAG, WRITELINE(isa8_mpu401_device, mpu_irq_out)) +MACHINE_CONFIG_END + /* DIP-SWs 1-2-3-4 @@ -29,40 +35,8 @@ DIP-SWs 1 irq7 */ -READ8_MEMBER( isa8_mpu401_device::mpu401_r ) +WRITE_LINE_MEMBER( isa8_mpu401_device::mpu_irq_out ) { - UINT8 res; - - if(offset == 0) // data - { - res = 0xff; - } - else // status - { - res = 0x3f | 0x80; // bit 7 queue empty (DSR), bit 6 DRR (Data Receive Ready?) - } - - return res; -} - -WRITE8_MEMBER( isa8_mpu401_device::mpu401_w ) -{ - if(offset == 0) // data - { - printf("%02x %02x\n",offset,data); - } - else // command - { - printf("%02x %02x\n",offset,data); - - switch(data) - { - case 0xff: // reset - //m_isa->irq2_w(1); - break; - } - } - } //************************************************************************** @@ -71,6 +45,16 @@ WRITE8_MEMBER( isa8_mpu401_device::mpu401_w ) const device_type ISA8_MPU401 = &device_creator; +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_mpu401_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( isa8mpu401 ); +} + //************************************************************************** // LIVE DEVICE @@ -81,8 +65,9 @@ const device_type ISA8_MPU401 = &device_creator; //------------------------------------------------- isa8_mpu401_device::isa8_mpu401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, ISA8_MPU401, "Roland MPU-401 Sound Card", tag, owner, clock, "isa_mpu401", __FILE__), - device_isa8_card_interface( mconfig, *this ) + : device_t(mconfig, ISA8_MPU401, "Roland MPU-401 MIDI Interface", tag, owner, clock, "isa_mpu401", __FILE__), + device_isa8_card_interface( mconfig, *this ), + m_mpu401(*this, MPU_CORE_TAG) { } @@ -93,7 +78,8 @@ isa8_mpu401_device::isa8_mpu401_device(const machine_config &mconfig, const char void isa8_mpu401_device::device_start() { set_isa_device(); - m_isa->install_device(0x330, 0x0331, 0, 0, read8_delegate(FUNC(isa8_mpu401_device::mpu401_r), this), write8_delegate(FUNC(isa8_mpu401_device::mpu401_w), this)); + + m_isa->install_device(0x330, 0x0331, 0, 0, READ8_DEVICE_DELEGATE(m_mpu401, mpu401_device, mpu_r), WRITE8_DEVICE_DELEGATE(m_mpu401, mpu401_device, mpu_w)); } //------------------------------------------------- diff --git a/src/mess/machine/isa_mpu401.h b/src/mess/machine/isa_mpu401.h index 6332986c817..7fabb06b70e 100644 --- a/src/mess/machine/isa_mpu401.h +++ b/src/mess/machine/isa_mpu401.h @@ -5,6 +5,7 @@ #include "emu.h" #include "machine/isa.h" +#include "machine/mpu401.h" //************************************************************************** // TYPE DEFINITIONS @@ -20,13 +21,18 @@ public: // construction/destruction isa8_mpu401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - DECLARE_READ8_MEMBER(mpu401_r); - DECLARE_WRITE8_MEMBER(mpu401_w); + required_device m_mpu401; + + // called back by the MPU401 core to set the IRQ line state + DECLARE_WRITE_LINE_MEMBER(mpu_irq_out); + // optional information overrides protected: // device-level overrides virtual void device_start(); virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + private: // internal state }; diff --git a/src/mess/machine/mpu401.c b/src/mess/machine/mpu401.c new file mode 100644 index 00000000000..4d206cf0473 --- /dev/null +++ b/src/mess/machine/mpu401.c @@ -0,0 +1,250 @@ +/*************************************************************************** + + Roland MPU-401 core + + This emulates the MPU-401 external box with the 6801, ASIC, and RAM in it. + + We do it this way to facilitate the various PC, Apple II, C64, and other + possible hookups. + + 6801 GPIO port hookups (from the schematics) + + P10 / P11 / P12: drive the metronome and speaker + P13 / P14 / P15: drive 3 pins on the SYNC OUT connector + P16: to DSRD on gate array + P17: to DRRD on gate array + + P20: to SYC OUT on gate array + P21: to SYC IN on gate array, pulled up to Vcc via 4.7K resistor + programmed as output of timer (OLVL) + P22: to SRCK on gate array, inverted + P23: MIDI IN serial data (SCI in) + P24: MIDI OUT serial data (SCI out) + + ASIC addresses from the 6801: + 0x20: (r) read pending byte from the PC (w) apparently nothing + 0x21: (r) ASIC status, see STAT_xxx bits below (w) send new byte to PC data port + + Theory of operation: 6801's timer/counter is set up to drive a pulse stream + out P21 to the ASIC's SYC IN pin. The ASIC in turn generates the MIDI baud + rate (times 8) and returns that on pin P22. + + The 6801 is believed to run in mode 2, based on a combination of the + schematics and the behavior (ie, internal RAM from 80-FF is clearly + present from the program's behavior, and ports 3/4 are obviously external + address/data buses) + +***************************************************************************/ + +#include "machine/mpu401.h" + +#define M6801_TAG "mpu6801" +#define ROM_TAG "mpurom" + +#define P2_SYNC_OUT (0x01) +#define P2_SYNC_IN (0x02) +#define P2_SRCK_OUT (0x04) +#define P2_MIDI_IN (0x08) +#define P2_MIDI_OUT (0x10) + +#define STAT_CMD_PORT (0x01) // set if the new byte indicated by TX FULL was written to the command port, clear for data port +#define STAT_TX_FULL (0x40) // indicates the PC has written a new byte we haven't read yet +#define STAT_RX_EMPTY (0x80) // indicates we've written a new byte the PC hasn't read yet + +static ADDRESS_MAP_START( mpu401_map, AS_PROGRAM, 8, mpu401_device ) + AM_RANGE(0x0000, 0x001f) AM_READWRITE(regs_mode2_r, regs_mode2_w) + AM_RANGE(0x0020, 0x0021) AM_READWRITE(asic_r, asic_w) + AM_RANGE(0x0080, 0x00ff) AM_RAM // on-chip RAM + AM_RANGE(0x0800, 0x0fff) AM_RAM // external RAM + AM_RANGE(0xf000, 0xffff) AM_ROM AM_REGION(ROM_TAG, 0) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( mpu401_io_map, AS_IO, 8, mpu401_device ) + AM_RANGE(M6801_PORT1, M6801_PORT1) AM_READWRITE(port1_r, port1_w) + AM_RANGE(M6801_PORT2, M6801_PORT2) AM_READWRITE(port2_r, port2_w) +ADDRESS_MAP_END + +MACHINE_CONFIG_FRAGMENT( mpu401 ) + MCFG_CPU_ADD(M6801_TAG, M6801, 4000000) /* 4 MHz as per schematics */ + MCFG_CPU_PROGRAM_MAP(mpu401_map) + MCFG_CPU_IO_MAP(mpu401_io_map) +MACHINE_CONFIG_END + +ROM_START( mpu401 ) + ROM_REGION(0x1000, ROM_TAG, 0) + ROM_LOAD( "roland_6801v0b55p.bin", 0x000000, 0x001000, CRC(65d3a151) SHA1(00efbfb96aeb997b69bb16981c6751d3c784bb87) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type MPU401 = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor mpu401_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mpu401 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *mpu401_device::device_rom_region() const +{ + return ROM_NAME( mpu401 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mpu401_device - constructor +//------------------------------------------------- + +mpu401_device::mpu401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MPU401, "Roland MPU-401", tag, owner, clock, "mpu401", __FILE__), + m_ourcpu(*this, M6801_TAG), + write_irq(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mpu401_device::device_start() +{ + write_irq.resolve_safe(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mpu401_device::device_reset() +{ + m_port2 = 0xff & ~P2_SRCK_OUT; + m_command = 0; + m_mpudata = 0; + m_gatearrstat = 0; +} + +READ8_MEMBER(mpu401_device::regs_mode2_r) +{ + switch (offset) + { + case 4: + case 5: + case 6: + case 7: + case 0xf: + printf("MPU401: read @ unk %x (PC=%x)\n", offset, space.device().safe_pc()); + break; + + default: + return m_ourcpu->m6801_io_r(space, offset); + } + + return 0xff; +} + +WRITE8_MEMBER(mpu401_device::regs_mode2_w) +{ + switch (offset) + { + case 4: + case 5: + case 6: + case 7: + case 0xf: + printf("MPU401: %02x @ unk %x (PC=%x)\n", data, offset, space.device().safe_pc()); + break; + + default: + return m_ourcpu->m6801_io_w(space, offset, data); + } +} + +READ8_MEMBER(mpu401_device::port1_r) +{ + return 0xff; +} + +WRITE8_MEMBER(mpu401_device::port1_w) +{ + printf("port1_w: %02x met %x syncout %x DSRD %d DRRD %d\n", data, data & 3, (data>>3) & 3, (data>>6) & 1, (data>>7) & 1); +} + +READ8_MEMBER(mpu401_device::port2_r) +{ + printf("Read P2 (PC=%x)\n", space.device().safe_pc()); + return m_port2; +} + +WRITE8_MEMBER(mpu401_device::port2_w) +{ + printf("port2_w: %02x SYCOUT %d SYCIN %d SRCK %d MIDI OUT %d\n", data, (data & 1), (data>>1) & 1, (data>>2) & 1, (data>>4) & 1); +} + +READ8_MEMBER(mpu401_device::mpu_r) +{ +// printf("mpu_r @ %d\n", offset); + + if (offset == 1) // status + { + return m_gatearrstat; + } + else // data + { + write_irq(CLEAR_LINE); + m_gatearrstat |= STAT_RX_EMPTY; + return m_mpudata; + } +} + +WRITE8_MEMBER(mpu401_device::mpu_w) +{ +// printf("%02x to MPU-401 @ %d\n", data, offset); + m_command = data; + m_gatearrstat |= STAT_TX_FULL; + + if (offset == 1) + { + m_gatearrstat |= STAT_CMD_PORT; + } +} + +READ8_MEMBER(mpu401_device::asic_r) +{ + if (offset == 0) + { + m_gatearrstat &= ~STAT_TX_FULL; + return m_command; + } + else if (offset == 1) + { + return m_gatearrstat; + } + + return 0xff; +} + +WRITE8_MEMBER(mpu401_device::asic_w) +{ +// printf("MPU401: %02x to gate array @ %d\n", data, offset); + + if (offset == 1) + { + m_mpudata = data; + m_gatearrstat &= ~STAT_RX_EMPTY; + write_irq(ASSERT_LINE); + } +} + diff --git a/src/mess/machine/mpu401.h b/src/mess/machine/mpu401.h new file mode 100644 index 00000000000..9a6c59101f4 --- /dev/null +++ b/src/mess/machine/mpu401.h @@ -0,0 +1,69 @@ +#pragma once + +#ifndef __MPU401_H__ +#define __MPU401_H__ + +#include "emu.h" +#include "cpu/m6800/m6800.h" + +#define MCFG_MPU401_ADD(_tag, _irqf ) \ + MCFG_DEVICE_ADD(_tag, MPU401, 0) \ + MCFG_IRQ_FUNC(_irqf) + +#define MCFG_IRQ_FUNC(_irqf) \ + downcast(device)->set_irqf(DEVCB2_##_irqf); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class mpu401_device : public device_t +{ +public: + // construction/destruction + mpu401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + required_device m_ourcpu; + + template void set_irqf(_write wr) + { + write_irq.set_callback(wr); + } + + devcb2_write_line write_irq; + + DECLARE_READ8_MEMBER(regs_mode2_r); + DECLARE_WRITE8_MEMBER(regs_mode2_w); + DECLARE_READ8_MEMBER(asic_r); + DECLARE_WRITE8_MEMBER(asic_w); + DECLARE_READ8_MEMBER(port1_r); + DECLARE_WRITE8_MEMBER(port1_w); + DECLARE_READ8_MEMBER(port2_r); + DECLARE_WRITE8_MEMBER(port2_w); + + // public API - call for reads/writes at I/O 330/331 on PC, C0n0/C0n1 on Apple II, etc. + DECLARE_READ8_MEMBER(mpu_r); + DECLARE_WRITE8_MEMBER(mpu_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual const rom_entry *device_rom_region() const; + +private: + UINT8 m_port2; + UINT8 m_command; + UINT8 m_mpudata; + UINT8 m_gatearrstat; +}; + +// device type definition +extern const device_type MPU401; + +#endif /* __MPU401_H__ */ + + diff --git a/src/mess/mess.mak b/src/mess/mess.mak index e0ec2ca60bd..0df085aca1f 100644 --- a/src/mess/mess.mak +++ b/src/mess/mess.mak @@ -751,6 +751,7 @@ $(MESSOBJ)/shared.a: \ $(MESS_MACHINE)/midiinport.o \ $(MESS_MACHINE)/midioutport.o \ $(MESS_MACHINE)/mpc105.o \ + $(MESS_MACHINE)/mpu401.o \ $(MESS_MACHINE)/msm6222b.o \ $(MESS_MACHINE)/ncr5380.o \ $(MESS_MACHINE)/ncr5380n.o \ @@ -791,7 +792,7 @@ $(MESSOBJ)/isa.a: \ $(MESS_MACHINE)/isa_gus.o \ $(MESS_MACHINE)/isa_hdc.o \ $(MESS_MACHINE)/isa_ibm_mfc.o \ - $(MESS_MACHINE)/isa_mpu401.o\ + $(MESS_MACHINE)/isa_mpu401.o \ $(MESS_MACHINE)/isa_sblaster.o \ $(MESS_MACHINE)/isa_stereo_fx.o \ $(MESS_MACHINE)/isa_ssi2001.o \