mirror of
https://github.com/holub/mame
synced 2025-04-23 17:00:53 +03:00
(MESS) MPU-401: preliminary checkpoint. [R. Belmont, kevtris]
This commit is contained in:
parent
5604fad7eb
commit
47bc16858f
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
|
@ -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
250
src/mess/machine/mpu401.c
Normal 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
69
src/mess/machine/mpu401.h
Normal 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__ */
|
||||
|
||||
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user