(MESS) MPU-401: preliminary checkpoint. [R. Belmont, kevtris]

This commit is contained in:
R. Belmont 2013-08-11 21:29:58 +00:00
parent 5604fad7eb
commit 47bc16858f
6 changed files with 353 additions and 39 deletions

2
.gitattributes vendored
View File

@ -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

View File

@ -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<isa8_mpu401_device>;
//-------------------------------------------------
// 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::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));
}
//-------------------------------------------------

View File

@ -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<mpu401_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
};

250
src/mess/machine/mpu401.c Normal file
View File

@ -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<mpu401_device>;
//-------------------------------------------------
// 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);
}
}

69
src/mess/machine/mpu401.h Normal file
View File

@ -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<mpu401_device *>(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<m6801_cpu_device> m_ourcpu;
template<class _write> 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__ */

View File

@ -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 \