vme/enp10: add new device [CJ, System Source Computer Museum]

This commit is contained in:
Patrick Mackinlay 2023-08-16 18:49:12 +07:00
parent f83830751a
commit b877d9c15e
3 changed files with 219 additions and 0 deletions

View file

@ -2641,6 +2641,8 @@ end
if (BUSES["VME"]~=null) then
files {
MAME_DIR .. "src/devices/bus/vme/enp10.cpp",
MAME_DIR .. "src/devices/bus/vme/enp10.h",
MAME_DIR .. "src/devices/bus/vme/mvme187.cpp",
MAME_DIR .. "src/devices/bus/vme/mvme187.h",
MAME_DIR .. "src/devices/bus/vme/tp881v.cpp",

View file

@ -0,0 +1,166 @@
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay
/*
* Communication Machinery Corporation Ethernet Node Processor (ENP-10)
*
* Sources:
* - Ethernet Node Processor ENP-30 Reference Guide (6213000-05B), Communication Machinery Corporation, November 15, 1988
*
* TODO:
* - vme interface
* - address/interrupt configuration
* - verify registers
* - uart?
*/
/*
* WIP
* ---
* - 0xef'8010-0xef'802f appears to be a uart, but doesn't match scn2681 per ENP-30 documentation?
* - following text is output to 0xef'008025 at startup:
* CMC ENP/10 CMOS - 112708 Bytes Free
* Ethernet Address: 02CF1F123456
* Allocating 30 receive buffers
* Allocating 30 transmit buffers
*/
#include "emu.h"
#include "enp10.h"
#define VERBOSE 0
#include "logmacro.h"
DEFINE_DEVICE_TYPE(CMC_ENP10, cmc_enp10_device, "cmc_enp10", "CMC ENP-10")
cmc_enp10_device::cmc_enp10_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
: device_t(mconfig, CMC_ENP10, tag, owner, clock)
, device_vme_card_interface(mconfig, *this)
, m_cpu(*this, "cpu")
, m_net(*this, "net")
, m_led(*this, "led%u", 0U)
, m_boot(*this, "boot")
{
}
ROM_START(enp10)
ROM_REGION16_BE(0x4000, "eprom", 0)
ROM_SYSTEM_BIOS(0, "enp10", "CMC ENP/10 CMOS")
ROMX_LOAD("link_10_2.0_nh_rev.4.1h.u4", 0x0000, 0x2000, CRC(7532f2b1) SHA1(bdef6c525f451fbc67f3d4625c9db18975e7e1e4), ROM_SKIP(1) | ROM_BIOS(0)) // AM2764A
ROMX_LOAD("link_10_2.0_nh_rev.k4.1l.u3", 0x0001, 0x2000, CRC(f2decb78) SHA1(795623274bfff6273790c30445e4dca4064859ed), ROM_SKIP(1) | ROM_BIOS(0)) // AM2764A
// hand-crafted prom containing address 02:cf:1f:12:34:56
ROM_REGION16_BE(0x20, "mac", 0)
ROM_LOAD("mac.bin", 0x00, 0x20, CRC(99ac9577) SHA1(b4d6bba88dd376cc492738d57742628f42e9265e))
ROM_END
static INPUT_PORTS_START(enp10)
INPUT_PORTS_END
const tiny_rom_entry *cmc_enp10_device::device_rom_region() const
{
return ROM_NAME(enp10);
}
ioport_constructor cmc_enp10_device::device_input_ports() const
{
return INPUT_PORTS_NAME(enp10);
}
void cmc_enp10_device::device_start()
{
m_led.resolve();
save_item(NAME(m_ier));
save_item(NAME(m_tir));
save_item(NAME(m_rir));
save_item(NAME(m_uir));
save_item(NAME(m_exr));
save_item(NAME(m_csr));
save_item(NAME(m_rer));
save_item(NAME(m_hir));
}
void cmc_enp10_device::device_reset()
{
m_boot.select(0);
m_ier = 0;
m_tir = 0;
m_rir = 0;
m_uir = 0;
m_exr = 0;
m_csr = 0;
m_rer = 0;
m_hir = 0;
}
void cmc_enp10_device::device_add_mconfig(machine_config &config)
{
M68000(config, m_cpu, 10_MHz_XTAL / 2);
m_cpu->set_addrmap(AS_PROGRAM, &cmc_enp10_device::cpu_mem);
AM7990(config, m_net, 20_MHz_XTAL / 2);
m_net->intr_out().set_inputline(m_cpu, INPUT_LINE_IRQ6).invert();
m_net->dma_in().set([this](offs_t offset) { return m_cpu->space(0).read_word(offset); });
m_net->dma_out().set([this](offs_t offset, u16 data, u16 mem_mask) { m_cpu->space(0).write_word(offset, data, mem_mask); });
}
void cmc_enp10_device::cpu_mem(address_map &map)
{
map(0xf8'0000, 0xf8'3fff).rom().region("eprom", 0).mirror(0x02'0000);
map(0x00'0000, 0xf1'ffff).view(m_boot);
// map 1k of eprom at 0x00'0000
m_boot[0](0x00'0000, 0x00'0fff).rom().region("eprom", 0);
m_boot[0](0xf0'0000, 0xf1'ffff).ram().share("ram");
// map 1k of ram at 0x00'0000, unmap at 0xf0'0000
m_boot[1](0x00'0000, 0x01'ffff).ram().share("ram");
m_boot[1](0x00'1000, 0x01'ffff).unmaprw();
m_boot[1](0xf0'0000, 0xf1'ffff).ram().share("ram");
m_boot[1](0xf0'0000, 0xf0'0fff).unmaprw();
// uart: 16 byte registers 10-2f?
map(0xef'8010, 0xef'802f).noprw();
// fe'0080 vector? w:host vectored interrupt, r:slave address msb
map(0xfe'00a0, 0xfe'00a1).umask16(0x00ff).lrw8(
[this]() { return m_csr; }, "csr_r",
[this](u8 data)
{
LOG("csr_w 0x%02x\n", data);
m_led[0] = BIT(data, 6); // fail?
m_led[1] = BIT(data, 5); // run?
m_csr = data;
}, "csr_w");
map(0xfe'00c0, 0xfe'00c1).umask16(0x00ff).lrw8(NAME([this]() { return m_ier; }), NAME([this](u8 data) { m_ier = data; interrupt(); }));
map(0xfe'00c2, 0xfe'00c3).umask16(0x00ff).lrw8(NAME([this]() { return m_tir; }), NAME([this](u8 data) { m_tir = data; interrupt(); }));
map(0xfe'00c4, 0xfe'00c5).umask16(0x00ff).lrw8(NAME([this]() { return m_rir; }), NAME([this](u8 data) { m_rir = data; interrupt(); }));
map(0xfe'00c6, 0xfe'00c7).umask16(0x00ff).lrw8(NAME([this]() { return m_uir; }), NAME([this](u8 data) { m_uir = data; interrupt(); }));
map(0xfe'00ce, 0xfe'00cf).umask16(0x00ff).lrw8(NAME([this]() { return m_rer; }), NAME([this](u8 data) { m_rer = data; m_boot.select(BIT(data, 7)); }));
map(0xfe'00e0, 0xfe'00e1).umask16(0x00ff).lrw8(NAME([this]() { return m_exr; }), NAME([this](u8 data) { m_exr = data; })); // TODO: bit 1 parity error?
map(0xfe'00ee, 0xfe'00ef).umask16(0x00ff).lr8(NAME([]() { return 0; })); // TODO: bit 1 enables additional ram test?
map(0xfe'0200, 0xfe'0203).rw(m_net, FUNC(am7990_device::regs_r), FUNC(am7990_device::regs_w));
map(0xfe'0400, 0xfe'041f).rom().region("mac", 0);
// TODO: verify the next two registers
map(0xfe'0e00, 0xfe'0e01).umask16(0x00ff).lrw8(NAME([this]() { return m_hir; }), NAME([this](u8 data) { m_hir = data; interrupt(); }));
map(0xfe'0f00, 0xfe'0f01).umask16(0x00ff).lrw8(NAME([this]() { reset(); return 0; }), NAME([this](u8 data) { reset(); }));
}
void cmc_enp10_device::interrupt()
{
bool const enable = BIT(m_ier, 7);
m_cpu->set_input_line(INPUT_LINE_IRQ2, enable && BIT(m_uir, 7));
m_cpu->set_input_line(INPUT_LINE_IRQ3, enable && BIT(m_hir, 7));
m_cpu->set_input_line(INPUT_LINE_IRQ4, enable && BIT(m_tir, 7));
m_cpu->set_input_line(INPUT_LINE_IRQ5, enable && BIT(m_rir, 7));
}

View file

@ -0,0 +1,51 @@
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay
#ifndef MAME_BUS_VME_ENP10_H
#define MAME_BUS_VME_ENP10_H
#pragma once
#include "cpu/m68000/m68000.h"
#include "machine/am79c90.h"
#include "bus/vme/vme.h"
class cmc_enp10_device
: public device_t
, public device_vme_card_interface
{
public:
cmc_enp10_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
protected:
virtual const tiny_rom_entry *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
virtual ioport_constructor device_input_ports() const override;
virtual void device_start() override;
virtual void device_reset() override;
private:
void cpu_mem(address_map &map);
void interrupt();
required_device<m68000_device> m_cpu;
required_device<am7990_device> m_net;
output_finder<2> m_led;
u8 m_ier; // interrupt enable register
u8 m_tir; // transmit interrupt register
u8 m_rir; // receive interrupt register
u8 m_uir; // utility interrupt register
u8 m_exr; // exception register
u8 m_csr; // control/status register
u8 m_rer; // ram/rom enable register
u8 m_hir; // host interrupt register
memory_view m_boot;
};
DECLARE_DEVICE_TYPE(CMC_ENP10, cmc_enp10_device)
#endif // MAME_BUS_VME_ENP10_H