mirror of
https://github.com/holub/mame
synced 2025-06-16 09:20:04 +03:00
sun1: refactor into multibus cage/card
* added more firmware revisions * added mmu emulation
This commit is contained in:
parent
3cec2ae67f
commit
c2ccf4cf6e
@ -43703,7 +43703,6 @@ sothello
|
||||
tonton
|
||||
|
||||
@source:sun/sun1.cpp
|
||||
multibox
|
||||
sun1
|
||||
|
||||
@source:sun/sun2.cpp
|
||||
|
@ -8,6 +8,7 @@
|
||||
Sun-1
|
||||
|
||||
Processor(s): 68000
|
||||
P/N: 270-0001
|
||||
Notes: Large black desktop boxes with 17" monitors.
|
||||
Uses the original Stanford-designed video board
|
||||
and a parallel microswitch keyboard (type 1) and
|
||||
@ -55,14 +56,18 @@
|
||||
|
||||
04/04/2011 Modernised, added terminal keyboard.
|
||||
|
||||
TODO:
|
||||
- graphic cards
|
||||
- network cards
|
||||
- storage cards
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "bus/rs232/rs232.h"
|
||||
#include "cpu/m68000/m68000.h"
|
||||
#include "machine/am9513.h"
|
||||
#include "machine/z80sio.h"
|
||||
|
||||
#include "sun1_cpu.h"
|
||||
|
||||
#include "bus/multibus/multibus.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -71,144 +76,51 @@ class sun1_state : public driver_device
|
||||
public:
|
||||
sun1_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag)
|
||||
, m_maincpu(*this, "maincpu")
|
||||
, m_iouart(*this, "iouart")
|
||||
, m_p_ram(*this, "p_ram")
|
||||
, m_bus(*this, "slot")
|
||||
{
|
||||
}
|
||||
|
||||
void sun1(machine_config &config);
|
||||
void cyb(machine_config &config);
|
||||
|
||||
private:
|
||||
void sun1_mem(address_map &map) ATTR_COLD;
|
||||
void cyb_mem(address_map &map) ATTR_COLD;
|
||||
virtual void machine_start() override ATTR_COLD;
|
||||
virtual void machine_reset() override ATTR_COLD;
|
||||
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_device<upd7201_device> m_iouart;
|
||||
required_shared_ptr<uint16_t> m_p_ram;
|
||||
required_device<multibus_device> m_bus;
|
||||
};
|
||||
|
||||
|
||||
void sun1_state::sun1_mem(address_map &map)
|
||||
void sun1_state::machine_start()
|
||||
{
|
||||
map.unmap_value_high();
|
||||
map(0x00000000, 0x001fffff).ram().share("p_ram"); // 512 KB RAM / ROM at boot
|
||||
map(0x00200000, 0x00203fff).rom().region("monitor", 0);
|
||||
map(0x00600000, 0x00600007).mirror(0x1ffff8).rw(m_iouart, FUNC(upd7201_device::ba_cd_r), FUNC(upd7201_device::ba_cd_w)).umask16(0xff00);
|
||||
map(0x00800000, 0x00800003).mirror(0x1ffffc).rw("timer", FUNC(am9513_device::read16), FUNC(am9513_device::write16));
|
||||
map(0x00a00000, 0x00bfffff).unmaprw(); // page map
|
||||
map(0x00c00000, 0x00dfffff).unmaprw(); // segment map
|
||||
map(0x00e00000, 0x00ffffff).unmaprw(); // context register
|
||||
}
|
||||
|
||||
void sun1_state::cyb_mem(address_map &map)
|
||||
{
|
||||
sun1_mem(map);
|
||||
map(0x00400000, 0x00403fff).rom().region("cyb", 0);
|
||||
}
|
||||
|
||||
/* Input ports */
|
||||
static INPUT_PORTS_START( sun1 )
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
void sun1_state::machine_reset()
|
||||
{
|
||||
uint8_t* user1 = memregion("monitor")->base();
|
||||
|
||||
memcpy((uint8_t*)m_p_ram.target(),user1,0x4000);
|
||||
}
|
||||
|
||||
static void sun1_cards(device_slot_interface &device)
|
||||
{
|
||||
device.option_add("sun1cpu", MULTIBUS_SUN1CPU);
|
||||
}
|
||||
|
||||
void sun1_state::sun1(machine_config &config)
|
||||
{
|
||||
/* basic machine hardware */
|
||||
M68000(config, m_maincpu, 16_MHz_XTAL / 2);
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &sun1_state::sun1_mem);
|
||||
// FIXME: CPU board can optionally drive Multibus clocks
|
||||
MULTIBUS(config, m_bus, 19.6608_MHz_XTAL / 2);
|
||||
|
||||
am9513_device &timer(AM9513(config, "timer", 16_MHz_XTAL / 4));
|
||||
timer.fout_cb().set("timer", FUNC(am9513_device::gate1_w));
|
||||
timer.out1_cb().set_nop(); // Watchdog; generates BERR/Reset
|
||||
timer.out2_cb().set_inputline(m_maincpu, M68K_IRQ_6); // User timer
|
||||
timer.out3_cb().set_inputline(m_maincpu, M68K_IRQ_7); // Refresh timer (2 ms)
|
||||
timer.out4_cb().set(m_iouart, FUNC(upd7201_device::rxca_w));
|
||||
timer.out4_cb().append(m_iouart, FUNC(upd7201_device::txca_w));
|
||||
timer.out5_cb().set(m_iouart, FUNC(upd7201_device::rxcb_w));
|
||||
timer.out5_cb().append(m_iouart, FUNC(upd7201_device::txcb_w));
|
||||
|
||||
UPD7201(config, m_iouart, 16_MHz_XTAL / 4);
|
||||
m_iouart->out_txda_callback().set("rs232a", FUNC(rs232_port_device::write_txd));
|
||||
m_iouart->out_dtra_callback().set("rs232a", FUNC(rs232_port_device::write_dtr));
|
||||
m_iouart->out_rtsa_callback().set("rs232a", FUNC(rs232_port_device::write_rts));
|
||||
m_iouart->out_txdb_callback().set("rs232b", FUNC(rs232_port_device::write_txd));
|
||||
m_iouart->out_dtrb_callback().set("rs232b", FUNC(rs232_port_device::write_dtr));
|
||||
m_iouart->out_rtsb_callback().set("rs232b", FUNC(rs232_port_device::write_rts));
|
||||
m_iouart->out_int_callback().set_inputline(m_maincpu, M68K_IRQ_5);
|
||||
|
||||
rs232_port_device &rs232a(RS232_PORT(config, "rs232a", default_rs232_devices, "terminal"));
|
||||
rs232a.rxd_handler().set(m_iouart, FUNC(upd7201_device::rxa_w));
|
||||
rs232a.cts_handler().set(m_iouart, FUNC(upd7201_device::ctsa_w));
|
||||
rs232a.dcd_handler().set(m_iouart, FUNC(upd7201_device::dcda_w));
|
||||
|
||||
rs232_port_device &rs232b(RS232_PORT(config, "rs232b", default_rs232_devices, nullptr));
|
||||
rs232b.rxd_handler().set(m_iouart, FUNC(upd7201_device::rxb_w));
|
||||
rs232b.cts_handler().set(m_iouart, FUNC(upd7201_device::ctsb_w));
|
||||
rs232b.dcd_handler().set(m_iouart, FUNC(upd7201_device::dcdb_w));
|
||||
// slot 1 is physically located at top, only slots 1-3 have P2
|
||||
MULTIBUS_SLOT(config, "slot:1", sun1_cards, nullptr, false); // memory expansion 2
|
||||
MULTIBUS_SLOT(config, "slot:2", sun1_cards, nullptr, false); // memory expansion 1
|
||||
MULTIBUS_SLOT(config, "slot:3", sun1_cards, "sun1cpu", false); // processor
|
||||
MULTIBUS_SLOT(config, "slot:4", sun1_cards, nullptr, false); // bus master 1
|
||||
MULTIBUS_SLOT(config, "slot:5", sun1_cards, nullptr, false); // bus master 2
|
||||
MULTIBUS_SLOT(config, "slot:6", sun1_cards, nullptr, false); // multibus memory, optional
|
||||
MULTIBUS_SLOT(config, "slot:7", sun1_cards, nullptr, false); // graphics
|
||||
}
|
||||
|
||||
void sun1_state::cyb(machine_config &config)
|
||||
{
|
||||
sun1(config);
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &sun1_state::cyb_mem);
|
||||
}
|
||||
|
||||
/* ROM definition */
|
||||
ROM_START( sun1 )
|
||||
ROM_REGION16_BE(0x4000, "monitor", 0)
|
||||
ROM_DEFAULT_BIOS("1.0")
|
||||
|
||||
ROM_SYSTEM_BIOS(0, "1.0", "Sun Monitor 1.0")
|
||||
ROMX_LOAD("v10.8.bin", 0x0000, 0x2000, CRC(3528a0f8) SHA1(be437dd93d1a44eccffa6f5e05935119482beab0), ROM_SKIP(1) | ROM_BIOS(0))
|
||||
ROMX_LOAD("v10.0.bin", 0x0001, 0x2000, CRC(1ad4c52a) SHA1(4bc1a19e8f202378d5d7baa8b95319275c040a6d), ROM_SKIP(1) | ROM_BIOS(0))
|
||||
|
||||
ROM_SYSTEM_BIOS(1, "diag", "Interactive Tests")
|
||||
ROMX_LOAD("8mhzdiag.8.bin", 0x0000, 0x2000, CRC(808a549e) SHA1(d2aba014a5507c1538f2c1a73e1d2524f28034f4), ROM_SKIP(1) | ROM_BIOS(1))
|
||||
ROMX_LOAD("8mhzdiag.0.bin", 0x0001, 0x2000, CRC(7a92d506) SHA1(5df3800f7083293fc01bb6a7e7538ad425bbebfb), ROM_SKIP(1) | ROM_BIOS(1))
|
||||
|
||||
ROM_REGION(0x0a40, "gfx", 0)
|
||||
ROM_LOAD("gfxu605.g4.bin", 0x0000, 0x0200, CRC(274b7b3d) SHA1(40d8be2cfcbd03512a05925991bb5030d5d4b5e9))
|
||||
ROM_LOAD("gfxu308.g21.bin", 0x0200, 0x0200, CRC(35a6eed8) SHA1(25cb2dd8e5343cd7927c3045eb4cb96dc9935a37))
|
||||
ROM_LOAD("gfxu108.g20.bin", 0x0400, 0x0200, CRC(ecee335e) SHA1(5f4d32dc918af15872cd6e700a04720caeb6c657))
|
||||
ROM_LOAD("gfxu105.g0.bin", 0x0600, 0x0200, CRC(8e1a24b3) SHA1(dad2821c3a3137ad69e78b6fc29ab582e5d78646))
|
||||
ROM_LOAD("gfxu104.g1.bin", 0x0800, 0x0200, CRC(86f7a483) SHA1(8eb3778f5497741cd4345e81ff1a903c9a63c8bb))
|
||||
ROM_LOAD("gfxu307.g61.bin", 0x0a00, 0x0020, CRC(b190f25d) SHA1(80fbdc843f1eb68a2d3713499f04d99dab88ce83))
|
||||
ROM_LOAD("gfxu107.g60.bin", 0x0a20, 0x0020, CRC(425d3a98) SHA1(9ae4ce3761c2f995d00bed8d752c55224d274062))
|
||||
|
||||
ROM_REGION(0x0240, "cpu", 0)
|
||||
ROM_LOAD("cpuu503.p2.bin", 0x0000, 0x0200, CRC(12d9a6be) SHA1(fca99f9c5afc630ac67cbd4e5ba4e5242b826848))
|
||||
ROM_LOAD("cpuu602.p1.bin", 0x0200, 0x0020, CRC(ee1e5a14) SHA1(0d3346cb3b647fa2475bd7b4fa36ea6ecfdaf805))
|
||||
ROM_LOAD("cpuu502.p0.bin", 0x0220, 0x0020, CRC(20eb1183) SHA1(9b268792b28d858d6b6a1b6c4148af88a8d6b735))
|
||||
ROM_END
|
||||
|
||||
ROM_START( multibox )
|
||||
ROM_REGION16_BE(0x4000, "monitor", 0)
|
||||
// "Sun Network Monitor, Version 0.10"
|
||||
ROM_LOAD16_BYTE("cybu103-sun10v.bin", 0x0000, 0x2000, CRC(32e53691) SHA1(5b0a3c4b5352d4c19067d9eb4db6cd1f76427892))
|
||||
ROM_LOAD16_BYTE("cybu101-sun10v.bin", 0x0001, 0x2000, CRC(900b725c) SHA1(90343de9e64ff8227c7e58c9d4df02783ecf5a76))
|
||||
|
||||
ROM_REGION16_BE(0x4000, "cyb", 0)
|
||||
// "CYB Monitor - Version 2.1 6/23/84"
|
||||
ROM_LOAD16_BYTE("cybu104-autov.bin", 0x0000, 0x2000, CRC(46570c0e) SHA1(42ad96ffb7cb0e2d9c0aa0ace283ff646eaa4584))
|
||||
ROM_LOAD16_BYTE("cybu102-autov.bin", 0x0001, 0x2000, CRC(6198c5f6) SHA1(7d880395c4da03ac5130905c850ad638cd4b86e9))
|
||||
ROM_START(sun1)
|
||||
ROM_END
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
/* Driver */
|
||||
|
||||
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
|
||||
COMP( 1982, sun1, 0, 0, sun1, sun1, sun1_state, empty_init, "Sun Microsystems", "Sun-1", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
|
||||
COMP( 1984, multibox, 0, 0, cyb, sun1, sun1_state, empty_init, "CYB Systems", "Multibox", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
|
||||
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
|
||||
COMP( 1982, sun1, 0, 0, sun1, 0, sun1_state, empty_init, "Sun Microsystems", "Sun-1", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
|
||||
|
408
src/mame/sun/sun1_cpu.cpp
Normal file
408
src/mame/sun/sun1_cpu.cpp
Normal file
@ -0,0 +1,408 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Miodrag Milanovic, Patrick Mackinlay
|
||||
|
||||
/*
|
||||
* This device emulates the Multibus Sun-1 CPU board, which consists of the
|
||||
* following key components:
|
||||
*
|
||||
* - 68000 CPU @ 8/10MHz
|
||||
* - Sun-1 memory management unit
|
||||
* - 256KiB RAM + up to 32KiB EPROM
|
||||
* - Am9513 system timing controller
|
||||
* - i8247/μPD7201 dual UART
|
||||
*
|
||||
* Sources:
|
||||
* - Sun-1 System Reference Manual, Draft Version 1.0, July 27, 1982, Sun Microsystems, Inc.
|
||||
* - Sun 68000 Board User's Manual, Revision B, February 1983, Sun Microsystems Inc.
|
||||
*
|
||||
* TODO:
|
||||
* - second generation Sun-1.5 variant
|
||||
* - variants from other companies
|
||||
* - keyboard, mouse
|
||||
* - jumpers
|
||||
*/
|
||||
|
||||
/*
|
||||
* WIP:
|
||||
* - bios 1: "t" enters CYB monitor
|
||||
* - bios 6: top 3 bits of parallel register control tests
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
#include "sun1_cpu.h"
|
||||
|
||||
#include "bus/rs232/rs232.h"
|
||||
#include "machine/clock.h"
|
||||
|
||||
#define LOG_DOG (1U << 2)
|
||||
|
||||
//#define VERBOSE (LOG_GENERAL|LOG_DOG)
|
||||
#include "logmacro.h"
|
||||
|
||||
enum irq_mask : u8
|
||||
{
|
||||
WATCHDOG = 0x80,
|
||||
};
|
||||
|
||||
DEFINE_DEVICE_TYPE(MULTIBUS_SUN1CPU, sun1cpu_device, "sun1cpu", "Sun-1 CPU")
|
||||
|
||||
sun1cpu_device::sun1cpu_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
|
||||
: device_t(mconfig, MULTIBUS_SUN1CPU, tag, owner, clock)
|
||||
, device_multibus_interface(mconfig, *this)
|
||||
, m_cpu(*this, "cpu")
|
||||
, m_mmu(*this, "mmu")
|
||||
, m_duart(*this, "duart")
|
||||
, m_stc(*this, "stc")
|
||||
, m_boot(*this, "boot")
|
||||
{
|
||||
}
|
||||
|
||||
ROM_START(sun1)
|
||||
/*
|
||||
* These different firmware versions expect slightly different hardware/timer
|
||||
* configurations and probably come from CPU boards that were made or modified
|
||||
* by other companies. The standard configuration according to the available
|
||||
* documentation should be:
|
||||
*
|
||||
* - stc @ 5MHz
|
||||
* - counter 1: watchdog (@2.98ms)
|
||||
* - counter 2: user irq 6
|
||||
* - cuonter 3: refresh irq 7 (@2ms)
|
||||
* - counter 4: uarta (16x baud)
|
||||
* - counter 5: uartb (16x baud)
|
||||
*
|
||||
* Most of these firmware versions do not configure timer 1 as a watchdog, and
|
||||
* probably rely on a dedicated watchdog timer circuit like that described in
|
||||
* the VSI schematics instead.
|
||||
*
|
||||
* The "aj" firmware is quite different: it does not use the STC for the DUART
|
||||
* clocks, and uses counter 5 for refresh.
|
||||
*
|
||||
*/
|
||||
ROM_SYSTEM_BIOS(0, "sun1", "Sun Monitor, Version 1.0") // osc=16, div=4
|
||||
ROM_SYSTEM_BIOS(1, "cyb", "Sun Network Monitor, Version 0.10 (CYB)") // osc=16, div=4
|
||||
ROM_SYSTEM_BIOS(2, "test", "Interactive Tests") // osc=16, div=2
|
||||
ROM_SYSTEM_BIOS(3, "fti10_11", "Sun Monitor, Version 1.1 (FTI10)") // osc=19.6, div=8
|
||||
ROM_SYSTEM_BIOS(4, "fti10_10", "Sun Monitor, Version 1.0 (FTI10)") // osc=19.6, div=8
|
||||
ROM_SYSTEM_BIOS(5, "smi10", "Sun Monitor, Version 1.1 (SMI10)") // osc=19.6, div=4, watchdog=1
|
||||
ROM_SYSTEM_BIOS(6, "aj", "Sun-1 Workstation Monitor; PROM 1&3: Rev AJ; PROM 2&4: Rev AJ") // osc=20, div=4, watchdog=1
|
||||
|
||||
/*
|
||||
* The prom0 region at 0x02'0000 holds the primary firmware, and is also
|
||||
* readable from address 0x00'0000 until boot mode is disabled.
|
||||
*/
|
||||
ROM_REGION16_BE(0x4000, "prom0", ROMREGION_ERASEFF)
|
||||
|
||||
// stc @ 4MHz (16MHz / 4)
|
||||
// counter 3 mode 0b22 load=8000 == 2ms
|
||||
// counter 4 mode 0b22 load=13
|
||||
// counter 5 mode 0b22 load=13
|
||||
ROMX_LOAD("v10.8.u103", 0x0000, 0x2000, CRC(3528a0f8) SHA1(be437dd93d1a44eccffa6f5e05935119482beab0), ROM_SKIP(1) | ROM_BIOS(0))
|
||||
ROMX_LOAD("v10.0.u101", 0x0001, 0x2000, CRC(1ad4c52a) SHA1(4bc1a19e8f202378d5d7baa8b95319275c040a6d), ROM_SKIP(1) | ROM_BIOS(0))
|
||||
|
||||
// Sun Network Monitor, Version 0.10
|
||||
// stc @ 4MHz (16MHz / 4)
|
||||
// counter 3 mode 0b22 load=8000 == 2ms
|
||||
// counter 4 mode 0b22 load=13
|
||||
// counter 5 mode 0b22 load=13
|
||||
ROMX_LOAD("cybu103-sun10v.u103", 0x0000, 0x2000, CRC(32e53691) SHA1(5b0a3c4b5352d4c19067d9eb4db6cd1f76427892), ROM_SKIP(1) | ROM_BIOS(1))
|
||||
ROMX_LOAD("cybu101-sun10v.u101", 0x0001, 0x2000, CRC(900b725c) SHA1(90343de9e64ff8227c7e58c9d4df02783ecf5a76), ROM_SKIP(1) | ROM_BIOS(1))
|
||||
|
||||
// Interactive Tests
|
||||
// stc @ 8MHz (16MHz / 2)
|
||||
// counter 3 mode 0b22 load=16000 == 2ms
|
||||
// counter 4 mode 0b22 load=26
|
||||
// counter 5 mode 0b22 load=26
|
||||
ROMX_LOAD("8mhzdiag.8.u103", 0x0000, 0x2000, CRC(808a549e) SHA1(d2aba014a5507c1538f2c1a73e1d2524f28034f4), ROM_SKIP(1) | ROM_BIOS(2))
|
||||
ROMX_LOAD("8mhzdiag.0.u101", 0x0001, 0x2000, CRC(7a92d506) SHA1(5df3800f7083293fc01bb6a7e7538ad425bbebfb), ROM_SKIP(1) | ROM_BIOS(2))
|
||||
|
||||
// Sun Monitor, Version 1.1
|
||||
// stc @ 2.4576MHz (19.6MHz / 8)
|
||||
// counter 3 mode 0b22 load=4915 == ~2ms
|
||||
// counter 4 mode 0b22 load=8
|
||||
// counter 5 mode 0b22 load=8
|
||||
ROMX_LOAD("fti10_11.u103", 0x0000, 0x1000, CRC(1a5befa5) SHA1(cd7fc4c88a76ae393ada6a3f427993fbacb8a9c6), ROM_SKIP(1) | ROM_BIOS(3))
|
||||
ROMX_LOAD("fti10_11.u101", 0x0001, 0x1000, CRC(ac733618) SHA1(baff471248b355d761a5dab375fc88d861cb6853), ROM_SKIP(1) | ROM_BIOS(3))
|
||||
|
||||
// Sun Monitor, Version 1.0
|
||||
// stc @ 2.4576MHz (19.6MHz / 8)
|
||||
// counter 3 mode 0b22 load=4915 == ~2ms
|
||||
// counter 4 mode 0b22 load=8
|
||||
// counter 5 mode 0b22 load=8
|
||||
ROMX_LOAD("fti10_10.u103", 0x0000, 0x1000, CRC(fb5e599b) SHA1(5ab1ac61034aac956fd6e39b964996e0f9d0da97), ROM_SKIP(1) | ROM_BIOS(4))
|
||||
ROMX_LOAD("fti10_10.u101", 0x0001, 0x1000, CRC(e7371fd6) SHA1(5a377a4363b59c5508f941c356d8827594a72dc8), ROM_SKIP(1) | ROM_BIOS(4))
|
||||
|
||||
// Sun Monitor, Version 1.1
|
||||
// stc @ 4.9152MHz (19.6MHz / 4)
|
||||
// counter 1 mode 0621 load=7568 == ~3ms
|
||||
// counter 3 mode 0622 load=4915 == ~2ms
|
||||
// counter 4 mode 0b22 load=16
|
||||
// counter 5 mode 0b22 load=16
|
||||
ROMX_LOAD("smi10_11.u103", 0x0000, 0x1000, CRC(89e1a6ed) SHA1(2dfcba08fb6e4582e05b803c4507419c25dbdaa8), ROM_SKIP(1) | ROM_BIOS(5))
|
||||
ROMX_LOAD("smi10_11.u101", 0x0001, 0x1000, CRC(432db053) SHA1(99a54a653f18b914ae15f230a35ac55c5d076a4c), ROM_SKIP(1) | ROM_BIOS(5))
|
||||
|
||||
// PROM 1&3: Rev AJ
|
||||
// stc @ 5MHz (20MHz / 4)
|
||||
// counter 1 mode 0621 load=7450 == 2.98ms
|
||||
// counter 5 mode 0622 load=5000 == 2ms
|
||||
// uarts fixed @ 9600
|
||||
ROMX_LOAD("sun1c_1h.u103", 0x0000, 0x2000, CRC(4c58de6c) SHA1(f417a0a013d4ca3aaf565b0e7a88dcf3da1347c1), ROM_SKIP(1) | ROM_BIOS(6))
|
||||
ROMX_LOAD("sun1c_1l.u101", 0x0001, 0x2000, CRC(41c47355) SHA1(a38df286ab8ba9a462862ab1cc9fa28b79fb9949), ROM_SKIP(1) | ROM_BIOS(6))
|
||||
|
||||
/*
|
||||
* The prom1 region at 0x04'0000 holds secondary/optional diagnostic or
|
||||
* boot firmware.
|
||||
*/
|
||||
ROM_REGION16_BE(0x4000, "prom1", ROMREGION_ERASEFF)
|
||||
|
||||
// CYB Monitor - Version 2.1 6/23/84
|
||||
ROMX_LOAD("cybu104-autov.u104", 0x0000, 0x2000, CRC(46570c0e) SHA1(42ad96ffb7cb0e2d9c0aa0ace283ff646eaa4584), ROM_SKIP(1) | ROM_BIOS(1))
|
||||
ROMX_LOAD("cybu102-autov.u102", 0x0001, 0x2000, CRC(6198c5f6) SHA1(7d880395c4da03ac5130905c850ad638cd4b86e9), ROM_SKIP(1) | ROM_BIOS(1))
|
||||
|
||||
// PROM 2&4: Rev AJ
|
||||
ROMX_LOAD("sun1c_2h.u104", 0x0000, 0x2000, CRC(b5cbcb2b) SHA1(8f906dbdc9b2af90bc8f942eebe7006be0ff4e86), ROM_SKIP(1) | ROM_BIOS(6))
|
||||
ROMX_LOAD("sun1c_2l.u102", 0x0001, 0x2000, CRC(dc82578b) SHA1(65bf18a8a40171ec08137a0c446da3b272b9ccbc), ROM_SKIP(1) | ROM_BIOS(6))
|
||||
|
||||
// TODO: move the following firmware to a graphics card
|
||||
ROM_REGION(0x10000, "gfx", ROMREGION_ERASEFF)
|
||||
ROM_LOAD("gfxu605.g4.bin", 0x0000, 0x0200, CRC(274b7b3d) SHA1(40d8be2cfcbd03512a05925991bb5030d5d4b5e9))
|
||||
ROM_LOAD("gfxu308.g21.bin", 0x0200, 0x0200, CRC(35a6eed8) SHA1(25cb2dd8e5343cd7927c3045eb4cb96dc9935a37))
|
||||
ROM_LOAD("gfxu108.g20.bin", 0x0400, 0x0200, CRC(ecee335e) SHA1(5f4d32dc918af15872cd6e700a04720caeb6c657))
|
||||
ROM_LOAD("gfxu105.g0.bin", 0x0600, 0x0200, CRC(8e1a24b3) SHA1(dad2821c3a3137ad69e78b6fc29ab582e5d78646))
|
||||
ROM_LOAD("gfxu104.g1.bin", 0x0800, 0x0200, CRC(86f7a483) SHA1(8eb3778f5497741cd4345e81ff1a903c9a63c8bb))
|
||||
ROM_LOAD("gfxu307.g61.bin", 0x0a00, 0x0020, CRC(b190f25d) SHA1(80fbdc843f1eb68a2d3713499f04d99dab88ce83))
|
||||
ROM_LOAD("gfxu107.g60.bin", 0x0a20, 0x0020, CRC(425d3a98) SHA1(9ae4ce3761c2f995d00bed8d752c55224d274062))
|
||||
|
||||
ROM_REGION(0x10000, "cpu", ROMREGION_ERASEFF)
|
||||
ROM_LOAD("cpuu503.p2.bin", 0x0000, 0x0200, CRC(12d9a6be) SHA1(fca99f9c5afc630ac67cbd4e5ba4e5242b826848))
|
||||
ROM_LOAD("cpuu602.p1.bin", 0x0200, 0x0020, CRC(ee1e5a14) SHA1(0d3346cb3b647fa2475bd7b4fa36ea6ecfdaf805))
|
||||
ROM_LOAD("cpuu502.p0.bin", 0x0220, 0x0020, CRC(20eb1183) SHA1(9b268792b28d858d6b6a1b6c4148af88a8d6b735))
|
||||
ROM_END
|
||||
|
||||
const tiny_rom_entry *sun1cpu_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME(sun1);
|
||||
}
|
||||
|
||||
static INPUT_PORTS_START(sun1)
|
||||
INPUT_PORTS_END
|
||||
|
||||
ioport_constructor sun1cpu_device::device_input_ports() const
|
||||
{
|
||||
return INPUT_PORTS_NAME(sun1);
|
||||
}
|
||||
|
||||
void sun1cpu_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_irq));
|
||||
save_item(NAME(m_watchdog));
|
||||
save_item(NAME(m_parity));
|
||||
|
||||
m_cpu->space(AS_PROGRAM).specific(m_cpu_mem);
|
||||
m_cpu->space(m68000_device::AS_CPU_SPACE).specific(m_cpu_spc);
|
||||
|
||||
m_irq = 0;
|
||||
}
|
||||
|
||||
void sun1cpu_device::device_reset()
|
||||
{
|
||||
// HACK: configure oscillator, divisor and watchdog type to match selected
|
||||
// firmware until more accurate board type/configuration can be determined
|
||||
XTAL oscillator = 16_MHz_XTAL;
|
||||
unsigned divisor = 4;
|
||||
m_watchdog = false;
|
||||
|
||||
switch (system_bios())
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
divisor = 2;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
oscillator = 19.6608_MHz_XTAL;
|
||||
divisor = 8;
|
||||
break;
|
||||
case 6:
|
||||
oscillator = 19.6608_MHz_XTAL;
|
||||
m_watchdog = true;
|
||||
break;
|
||||
case 7:
|
||||
oscillator = 20_MHz_XTAL;
|
||||
m_watchdog = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// configure cpu, stc and duart clocks
|
||||
m_cpu->set_clock(oscillator / 2);
|
||||
m_stc->set_clock(oscillator / divisor);
|
||||
m_duart->set_clock(oscillator / divisor);
|
||||
|
||||
m_parity = false;
|
||||
|
||||
if (!boot())
|
||||
{
|
||||
m_cpu->set_current_mmu(this);
|
||||
|
||||
// disable interrupts
|
||||
for (unsigned i = 0; i < 7; i++)
|
||||
if (BIT(m_irq, i))
|
||||
m_cpu->set_input_line(M68K_IRQ_1 + i, CLEAR_LINE);
|
||||
|
||||
m_boot.select(0);
|
||||
}
|
||||
}
|
||||
|
||||
void sun1cpu_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
M68000(config, m_cpu, 0);
|
||||
m_cpu->set_current_mmu(this);
|
||||
m_cpu->set_addrmap(AS_PROGRAM, &sun1cpu_device::cpu_mem);
|
||||
|
||||
// route multibus interrupts 1..4 to cpu
|
||||
int_callback<1>().set(FUNC(sun1cpu_device::irq_w<M68K_IRQ_1>)).invert();
|
||||
int_callback<2>().set(FUNC(sun1cpu_device::irq_w<M68K_IRQ_2>)).invert();
|
||||
int_callback<3>().set(FUNC(sun1cpu_device::irq_w<M68K_IRQ_3>)).invert();
|
||||
int_callback<4>().set(FUNC(sun1cpu_device::irq_w<M68K_IRQ_4>)).invert();
|
||||
|
||||
SUN1MMU(config, m_mmu);
|
||||
m_mmu->error().set(
|
||||
[this](int state)
|
||||
{
|
||||
// check multibus access pending
|
||||
if (state == sun1mmu_device::MMU_DEFER)
|
||||
{
|
||||
if (!m_watchdog || (m_irq & WATCHDOG))
|
||||
{
|
||||
LOGMASKED(LOG_DOG, "watchdog bus error\n");
|
||||
m_cpu->trigger_bus_error();
|
||||
m_mmu->reset();
|
||||
}
|
||||
else
|
||||
m_cpu->defer_access();
|
||||
}
|
||||
else
|
||||
m_cpu->trigger_bus_error();
|
||||
});
|
||||
|
||||
// default configuration (1=watchdog, 2=user, 3=refresh, 4=uarta, 5=uartb)
|
||||
AM9513(config, m_stc, 0);
|
||||
m_stc->fout_cb().set(m_stc, FUNC(am9513_device::gate1_w));
|
||||
m_stc->out1_cb().set(FUNC(sun1cpu_device::watchdog_w));
|
||||
m_stc->out2_cb().set(FUNC(sun1cpu_device::irq_w<M68K_IRQ_6>));
|
||||
m_stc->out3_cb().set(FUNC(sun1cpu_device::irq_w<M68K_IRQ_7>));
|
||||
m_stc->out4_cb().set(m_duart, FUNC(upd7201_device::rxca_w));
|
||||
m_stc->out4_cb().append(m_duart, FUNC(upd7201_device::txca_w));
|
||||
m_stc->out5_cb().set(m_duart, FUNC(upd7201_device::rxcb_w));
|
||||
m_stc->out5_cb().append(m_duart, FUNC(upd7201_device::txcb_w));
|
||||
|
||||
if (false)
|
||||
{
|
||||
// TODO: "aj" firmware has refresh on counter 5, and fixed-speed uarts
|
||||
m_stc->out3_cb().set_nop();
|
||||
m_stc->out4_cb().set_nop();
|
||||
m_stc->out5_cb().set(FUNC(sun1cpu_device::irq_w<M68K_IRQ_7>));
|
||||
|
||||
// assume duart rxc/txc driven at 9600baud (x16 clock)
|
||||
CLOCK(config, "duart_clock", 9600 * 16).signal_handler().set(
|
||||
[this](int state)
|
||||
{
|
||||
m_duart->txca_w(state);
|
||||
m_duart->rxca_w(state);
|
||||
m_duart->txcb_w(state);
|
||||
m_duart->rxcb_w(state);
|
||||
});
|
||||
}
|
||||
|
||||
// port A: txd, rxd, rts, cts, dsr, dtr
|
||||
// port B: txd, rxd
|
||||
UPD7201(config, m_duart, 0);
|
||||
m_duart->out_txda_callback().set("rs232a", FUNC(rs232_port_device::write_txd));
|
||||
m_duart->out_dtra_callback().set("rs232a", FUNC(rs232_port_device::write_dtr));
|
||||
m_duart->out_rtsa_callback().set("rs232a", FUNC(rs232_port_device::write_rts));
|
||||
m_duart->out_txdb_callback().set("rs232b", FUNC(rs232_port_device::write_txd));
|
||||
m_duart->out_int_callback().set(FUNC(sun1cpu_device::irq_w<M68K_IRQ_5>));
|
||||
|
||||
rs232_port_device &rs232a(RS232_PORT(config, "rs232a", default_rs232_devices, "terminal"));
|
||||
rs232a.rxd_handler().set(m_duart, FUNC(upd7201_device::rxa_w));
|
||||
rs232a.cts_handler().set(m_duart, FUNC(upd7201_device::ctsa_w));
|
||||
rs232a.dcd_handler().set(m_duart, FUNC(upd7201_device::dcda_w));
|
||||
|
||||
rs232_port_device &rs232b(RS232_PORT(config, "rs232b", default_rs232_devices, nullptr));
|
||||
rs232b.rxd_handler().set(m_duart, FUNC(upd7201_device::rxb_w));
|
||||
}
|
||||
|
||||
void sun1cpu_device::device_config_complete()
|
||||
{
|
||||
m_mmu.lookup()->set_space<0>(m_cpu, AS_PROGRAM);
|
||||
m_mmu.lookup()->set_space<1>(m_cpu, m68000_device::AS_CPU_SPACE);
|
||||
m_mmu.lookup()->set_space<2>(m_bus, AS_PROGRAM);
|
||||
m_mmu.lookup()->set_space<3>(m_bus, AS_IO);
|
||||
}
|
||||
|
||||
void sun1cpu_device::cpu_mem(address_map &map)
|
||||
{
|
||||
map(0x00'0000, 0x03'ffff).ram();
|
||||
|
||||
map(0x00'0000, 0x1f'ffff).view(m_boot);
|
||||
m_boot[0](0x00'0000, 0x00'3fff).mirror(0x03'c000).rom().region("prom0", 0);
|
||||
|
||||
map(0x20'0000, 0x20'3fff).mirror(0x03'c000).rom().region("prom0", 0).w(FUNC(sun1cpu_device::prom0_w));
|
||||
map(0x40'0000, 0x40'3fff).mirror(0x03'c000).rom().region("prom1", 0);
|
||||
map(0x60'0000, 0x60'0007).mirror(0x1ffff8).rw(m_duart, FUNC(upd7201_device::ba_cd_r), FUNC(upd7201_device::ba_cd_w)).umask16(0xff00);
|
||||
map(0x80'0000, 0x80'0003).mirror(0x1ffffc).rw(m_stc, FUNC(am9513_device::read16), FUNC(am9513_device::write16));
|
||||
map(0xa0'0000, 0xbf'ffff).rw(m_mmu, FUNC(sun1mmu_device::page_r), FUNC(sun1mmu_device::page_w));
|
||||
map(0xc0'0000, 0xdf'ffff).rw(m_mmu, FUNC(sun1mmu_device::segment_r), FUNC(sun1mmu_device::segment_w));
|
||||
map(0xe0'0000, 0xe0'0001).mirror(0x1f'fffe).r(FUNC(sun1cpu_device::parallel_r));
|
||||
map(0xe0'0000, 0xe0'0001).mirror(0x1f'fffe).w(m_mmu, FUNC(sun1mmu_device::context_w));
|
||||
}
|
||||
|
||||
void sun1cpu_device::watchdog_w(int state)
|
||||
{
|
||||
if (state)
|
||||
m_irq |= WATCHDOG;
|
||||
else
|
||||
m_irq &= ~WATCHDOG;
|
||||
|
||||
if (!BIT(m_irq, 6))
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
LOGMASKED(LOG_DOG, "watchdog reset\n");
|
||||
reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned N> void sun1cpu_device::irq_w(int state)
|
||||
{
|
||||
if (state)
|
||||
m_irq |= 1U << (N - M68K_IRQ_1);
|
||||
else
|
||||
m_irq &= ~(1U << (N - M68K_IRQ_1));
|
||||
|
||||
if (!boot())
|
||||
m_cpu->set_input_line(N, state);
|
||||
}
|
||||
|
||||
void sun1cpu_device::prom0_w(u16 data)
|
||||
{
|
||||
m_parity = BIT(data, 0);
|
||||
|
||||
if (boot())
|
||||
{
|
||||
LOG("boot mode disabled (%s)\n", machine().describe_context());
|
||||
|
||||
m_cpu->set_current_mmu(m_mmu);
|
||||
|
||||
// enable interrupts
|
||||
for (unsigned i = 0; i < 7; i++)
|
||||
if (BIT(m_irq, i))
|
||||
m_cpu->set_input_line(M68K_IRQ_1 + i, ASSERT_LINE);
|
||||
|
||||
m_boot.disable();
|
||||
}
|
||||
}
|
69
src/mame/sun/sun1_cpu.h
Normal file
69
src/mame/sun/sun1_cpu.h
Normal file
@ -0,0 +1,69 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Miodrag Milanovic, Patrick Mackinlay
|
||||
|
||||
#ifndef MAME_SUN_SUN1_CPU_H
|
||||
#define MAME_SUN_SUN1_CPU_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sun1_mmu.h"
|
||||
|
||||
#include "bus/multibus/multibus.h"
|
||||
#include "cpu/m68000/m68000.h"
|
||||
#include "machine/am9513.h"
|
||||
#include "machine/z80sio.h"
|
||||
|
||||
class sun1cpu_device
|
||||
: public device_t
|
||||
, public device_multibus_interface
|
||||
, public m68000_device::mmu
|
||||
{
|
||||
public:
|
||||
sun1cpu_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
|
||||
|
||||
protected:
|
||||
// device_t implementation
|
||||
virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD;
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
virtual void device_config_complete() override ATTR_COLD;
|
||||
virtual ioport_constructor device_input_ports() const override ATTR_COLD;
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
|
||||
void cpu_mem(address_map &map);
|
||||
|
||||
void prom0_w(u16 data);
|
||||
u16 parallel_r() { return 0x1fff; }
|
||||
|
||||
void watchdog_w(int state);
|
||||
template <unsigned N> void irq_w(int state);
|
||||
|
||||
// m68000_device::mmu boot mode implementation
|
||||
virtual u16 read_program(offs_t logical, u16 mem_mask) override { return m_cpu_mem.read_word(logical, mem_mask); }
|
||||
virtual void write_program(offs_t logical, u16 data, u16 mem_mask) override { m_cpu_mem.write_word(logical, data, mem_mask); }
|
||||
virtual u16 read_data(offs_t logical, u16 mem_mask) override { return m_cpu_mem.read_word(logical, mem_mask); }
|
||||
virtual void write_data(offs_t logical, u16 data, u16 mem_mask) override { m_cpu_mem.write_word(logical, data, mem_mask); }
|
||||
virtual u16 read_cpu(offs_t logical, u16 mem_mask) override { return m_cpu_spc.read_word(logical, mem_mask); }
|
||||
virtual void set_super(bool super) override {}
|
||||
|
||||
bool boot() const { return m_boot.entry().has_value(); }
|
||||
|
||||
private:
|
||||
required_device<m68000_device> m_cpu;
|
||||
required_device<sun1mmu_device> m_mmu;
|
||||
required_device<upd7201_device> m_duart;
|
||||
required_device<am9513_device> m_stc;
|
||||
|
||||
memory_view m_boot;
|
||||
|
||||
memory_access<24, 1, 0, ENDIANNESS_BIG>::specific m_cpu_mem;
|
||||
memory_access<24, 1, 0, ENDIANNESS_BIG>::specific m_cpu_spc;
|
||||
|
||||
u8 m_irq;
|
||||
bool m_watchdog;
|
||||
bool m_parity;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(MULTIBUS_SUN1CPU, sun1cpu_device)
|
||||
|
||||
#endif // MAME_SUN_SUN1_CPU_H
|
309
src/mame/sun/sun1_mmu.cpp
Normal file
309
src/mame/sun/sun1_mmu.cpp
Normal file
@ -0,0 +1,309 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
/*
|
||||
* This device emulates the Sun-1 memory management unit.
|
||||
*
|
||||
* Sources:
|
||||
* - Sun-1 System Reference Manual, Draft Version 1.0, July 27, 1982, Sun Microsystems, Inc.
|
||||
* - Sun 68000 Board User's Manual, Revision B, February 1983, Sun Microsystems Inc.
|
||||
*
|
||||
* TODO:
|
||||
* - everything
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
#include "sun1_mmu.h"
|
||||
|
||||
#define VERBOSE (LOG_GENERAL)
|
||||
#include "logmacro.h"
|
||||
|
||||
enum segment_mask : u16
|
||||
{
|
||||
SEGMENT_PPTR = 0x003f,
|
||||
SEGMENT_PROT = 0x0f00,
|
||||
SEGMENT_CTXT = 0xf000,
|
||||
};
|
||||
enum page_mask : u16
|
||||
{
|
||||
PAGE_ADDR = 0x0fff,
|
||||
PAGE_TYPE = 0x3000, // 0=on-board memory, 1=nonexistent, 2=multibus memory, 3=multibus i/o
|
||||
PAGE_MOD = 0x4000,
|
||||
PAGE_ACC = 0x8000,
|
||||
};
|
||||
enum mode_mask : unsigned
|
||||
{
|
||||
P_R = 0x04, // read
|
||||
P_W = 0x02, // write
|
||||
P_X = 0x01, // execute
|
||||
|
||||
P_RX = P_R | P_X,
|
||||
P_RW = P_R | P_W,
|
||||
P_RWX = P_R | P_W | P_X,
|
||||
};
|
||||
|
||||
DEFINE_DEVICE_TYPE(SUN1MMU, sun1mmu_device, "sun1mmu", "Sun-1 MMU")
|
||||
|
||||
sun1mmu_device::sun1mmu_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
|
||||
: device_t(mconfig, SUN1MMU, tag, owner, clock)
|
||||
, m_space{
|
||||
{*this, finder_base::DUMMY_TAG, 0},
|
||||
{*this, finder_base::DUMMY_TAG, 1},
|
||||
{*this, finder_base::DUMMY_TAG, 2},
|
||||
{*this, finder_base::DUMMY_TAG, 3},
|
||||
}
|
||||
, m_error(*this)
|
||||
, m_context(0)
|
||||
, m_segment{}
|
||||
, m_page{}
|
||||
, m_super(true)
|
||||
{
|
||||
}
|
||||
|
||||
void sun1mmu_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_context));
|
||||
save_item(NAME(m_segment));
|
||||
save_item(NAME(m_page));
|
||||
save_item(NAME(m_stall));
|
||||
save_item(NAME(m_super));
|
||||
|
||||
m_space[0]->specific(m_cpu_mem);
|
||||
m_space[1]->specific(m_cpu_spc);
|
||||
m_space[2]->specific(m_bus_mem);
|
||||
m_space[3]->specific(m_bus_pio);
|
||||
}
|
||||
|
||||
void sun1mmu_device::device_reset()
|
||||
{
|
||||
m_stall = false;
|
||||
}
|
||||
|
||||
static bool access(bool const super, unsigned const code, unsigned const mode)
|
||||
{
|
||||
static constexpr unsigned protection[2][16] =
|
||||
{
|
||||
// user mode
|
||||
{
|
||||
0 , 0 , 0 , 0 , 0 , 0 , P_R , P_R ,
|
||||
P_RW , P_RW , P_RX , P_RWX, P_RX , P_RX , P_X , P_RWX,
|
||||
},
|
||||
// supervisor mode
|
||||
{
|
||||
0 , P_X , P_R , P_RX , P_RW , P_RWX, P_R , P_RW ,
|
||||
P_R , P_RW , P_RW , P_RW , P_RX , P_RWX, P_RWX, P_RWX,
|
||||
},
|
||||
};
|
||||
|
||||
return protection[super][code] & mode;
|
||||
}
|
||||
|
||||
void sun1mmu_device::context_w(u16 data)
|
||||
{
|
||||
LOG("context 0x%04x (%s)\n", data, machine().describe_context());
|
||||
|
||||
m_context = data & 0xf000U;
|
||||
}
|
||||
|
||||
u16 sun1mmu_device::segment_r(offs_t offset)
|
||||
{
|
||||
return m_context | m_segment[m_context >> 12][BIT(offset, 14, 6)];
|
||||
}
|
||||
|
||||
void sun1mmu_device::segment_w(offs_t offset, u16 data, u16 mem_mask)
|
||||
{
|
||||
LOG("segment[0x%x][0x%02x] 0x%04x (%s)\n", m_context >> 12, BIT(offset, 14, 6), data, machine().describe_context());
|
||||
|
||||
m_segment[m_context >> 12][BIT(offset, 14, 6)] = data & 0x0fffU;
|
||||
}
|
||||
|
||||
u16 sun1mmu_device::page_r(offs_t offset)
|
||||
{
|
||||
u16 const segment = m_segment[m_context >> 12][BIT(offset, 14, 6)];
|
||||
|
||||
return m_page[(segment & SEGMENT_PPTR) << 4 | BIT(offset, 10, 4)];
|
||||
}
|
||||
|
||||
void sun1mmu_device::page_w(offs_t offset, u16 data, u16 mem_mask)
|
||||
{
|
||||
u16 const segment = m_segment[m_context >> 12][BIT(offset, 14, 6)];
|
||||
|
||||
LOG("page[0x%03x] 0x%04x (%s)\n", (segment & SEGMENT_PPTR) << 4 | BIT(offset, 10, 4), data, machine().describe_context());
|
||||
|
||||
m_page[(segment & SEGMENT_PPTR) << 4 | BIT(offset, 10, 4)] = data;
|
||||
}
|
||||
|
||||
std::optional<std::pair<unsigned, offs_t>> sun1mmu_device::translate(offs_t const logical, unsigned const mode)
|
||||
{
|
||||
// check for mapped address
|
||||
if (logical < 0x20'0000)
|
||||
{
|
||||
u16 const segment = m_segment[m_context >> 12][BIT(logical, 15, 6)];
|
||||
|
||||
// check segment map error
|
||||
if (access(m_super, BIT(segment, 8, 4), mode) || machine().side_effects_disabled())
|
||||
{
|
||||
u16 &page = m_page[(segment & SEGMENT_PPTR) << 4 | BIT(logical, 11, 4)];
|
||||
|
||||
// update reference and modify bits
|
||||
if (!machine().side_effects_disabled())
|
||||
{
|
||||
if (mode & P_W)
|
||||
page |= PAGE_ACC | PAGE_MOD;
|
||||
else
|
||||
page |= PAGE_ACC;
|
||||
}
|
||||
|
||||
return std::pair<unsigned, offs_t>(BIT(page, 12, 2), (page & PAGE_ADDR) << 11 | BIT(logical, 0, 11));
|
||||
}
|
||||
else
|
||||
LOG("segment map error 0x%08x context %d segment 0x%04x mode %c (%s)\n",
|
||||
logical, m_context, segment, (mode == P_R) ? 'R' : (mode == P_W) ? 'W' : 'X', machine().describe_context());
|
||||
}
|
||||
else if (m_super || machine().side_effects_disabled())
|
||||
// unmapped supervisor access
|
||||
return std::pair<unsigned, offs_t>(0, logical);
|
||||
else
|
||||
LOG("system space error 0x%08x (%s)\n", logical, machine().describe_context());
|
||||
|
||||
// protection error
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <bool Execute> u16 sun1mmu_device::mmu_read(offs_t logical, u16 mem_mask)
|
||||
{
|
||||
u16 data = 0;
|
||||
|
||||
if (m_stall)
|
||||
{
|
||||
m_error(MMU_DEFER);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto const t = translate(logical, Execute ? P_X : P_R);
|
||||
|
||||
if (t.has_value())
|
||||
{
|
||||
auto const [type, physical] = t.value();
|
||||
u16 flags = 0;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
// on-board memory
|
||||
data = m_cpu_mem.read_word(physical, mem_mask);
|
||||
break;
|
||||
case 1:
|
||||
// nonexistent
|
||||
LOG("nonexistent_r 0x%08x translated 0x%08x (%s)\n", logical, physical, machine().describe_context());
|
||||
m_error(MMU_ERROR);
|
||||
break;
|
||||
case 2:
|
||||
// multibus memory
|
||||
std::tie(data, flags) = m_bus_mem.read_word_flags(physical, mem_mask);
|
||||
if (flags)
|
||||
{
|
||||
LOG("multibus_r mem 0x%08x translated 0x%08x (%s)\n", logical, physical, machine().describe_context());
|
||||
m_stall = true;
|
||||
m_error(MMU_DEFER);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// mutibus i/o
|
||||
std::tie(data, flags) = m_bus_pio.read_word_flags(physical, mem_mask);
|
||||
if (flags)
|
||||
{
|
||||
LOG("multibus_r i/o 0x%08x translated 0x%08x (%s)\n", logical, physical, machine().describe_context());
|
||||
m_stall = true;
|
||||
m_error(MMU_DEFER);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_error(MMU_ERROR);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void sun1mmu_device::mmu_write(offs_t logical, u16 data, u16 mem_mask)
|
||||
{
|
||||
if (m_stall)
|
||||
{
|
||||
m_error(MMU_DEFER);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto const t = translate(logical, P_W);
|
||||
|
||||
if (t.has_value())
|
||||
{
|
||||
auto const [type, physical] = t.value();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
// on-board memory
|
||||
m_cpu_mem.write_word(physical, data, mem_mask);
|
||||
break;
|
||||
case 1:
|
||||
// nonexistent
|
||||
LOG("nonexistent write 0x%08x translated 0x%08x (%s)\n", logical, physical, machine().describe_context());
|
||||
m_error(MMU_ERROR);
|
||||
break;
|
||||
case 2:
|
||||
// multibus memory
|
||||
if (m_bus_mem.write_word_flags(physical, data, mem_mask))
|
||||
{
|
||||
LOG("multibus_w mem 0x%08x translated 0x%08x (%s)\n", logical, physical, machine().describe_context());
|
||||
m_stall = true;
|
||||
m_error(MMU_DEFER);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// mutibus i/o
|
||||
if (m_bus_pio.write_word_flags(physical, data, mem_mask))
|
||||
{
|
||||
LOG("multibus_w i/o 0x%08x translated 0x%08x (%s)\n", logical, physical, machine().describe_context());
|
||||
m_stall = true;
|
||||
m_error(MMU_DEFER);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_error(MMU_ERROR);
|
||||
}
|
||||
|
||||
u16 sun1mmu_device::read_program(offs_t logical, u16 mem_mask)
|
||||
{
|
||||
return mmu_read<true>(logical, mem_mask);
|
||||
}
|
||||
|
||||
void sun1mmu_device::write_program(offs_t logical, u16 data, u16 mem_mask)
|
||||
{
|
||||
mmu_write(logical, data, mem_mask);
|
||||
}
|
||||
|
||||
u16 sun1mmu_device::read_data(offs_t logical, u16 mem_mask)
|
||||
{
|
||||
return mmu_read<false>(logical, mem_mask);
|
||||
}
|
||||
|
||||
void sun1mmu_device::write_data(offs_t logical, u16 data, u16 mem_mask)
|
||||
{
|
||||
mmu_write(logical, data, mem_mask);
|
||||
}
|
||||
|
||||
u16 sun1mmu_device::read_cpu(offs_t logical, u16 mem_mask)
|
||||
{
|
||||
return m_cpu_spc.read_word(logical, mem_mask);
|
||||
}
|
||||
|
||||
void sun1mmu_device::set_super(bool super)
|
||||
{
|
||||
m_super = super;
|
||||
}
|
73
src/mame/sun/sun1_mmu.h
Normal file
73
src/mame/sun/sun1_mmu.h
Normal file
@ -0,0 +1,73 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
#ifndef MAME_SUN_SUN1_MMU_H
|
||||
#define MAME_SUN_SUN1_MMU_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpu/m68000/m68000.h"
|
||||
|
||||
class sun1mmu_device
|
||||
: public device_t
|
||||
, public m68000_device::mmu
|
||||
{
|
||||
public:
|
||||
template <unsigned N, typename T> void set_space(T &&tag, int spacenum) { m_space[N].set_tag(std::forward<T>(tag), spacenum); }
|
||||
template <unsigned N> void set_space(device_t &base, char const *tag, int spacenum) { m_space[N].set_tag(base, tag, spacenum); }
|
||||
|
||||
enum error_type : unsigned
|
||||
{
|
||||
MMU_DEFER = 0, // invalid multibus access
|
||||
MMU_ERROR = 1, // bus error (system space, segment protection, nonexistent page)
|
||||
};
|
||||
auto error() { return m_error.bind(); }
|
||||
|
||||
sun1mmu_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0);
|
||||
|
||||
// register access
|
||||
void context_w(u16 data);
|
||||
u16 segment_r(offs_t offset);
|
||||
void segment_w(offs_t offset, u16 data, u16 mem_mask);
|
||||
u16 page_r(offs_t offset);
|
||||
void page_w(offs_t offset, u16 data, u16 mem_mask);
|
||||
|
||||
protected:
|
||||
// device_t implementation
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
|
||||
// m68000_device::mmu implementation
|
||||
virtual u16 read_program(offs_t addr, u16 mem_mask) override;
|
||||
virtual void write_program(offs_t addr, u16 data, u16 mem_mask) override;
|
||||
virtual u16 read_data(offs_t addr, u16 mem_mask) override;
|
||||
virtual void write_data(offs_t addr, u16 data, u16 mem_mask) override;
|
||||
virtual u16 read_cpu(offs_t addr, u16 mem_mask) override;
|
||||
virtual void set_super(bool super) override;
|
||||
|
||||
std::optional<std::pair<unsigned, offs_t>> translate(offs_t const address, unsigned const mode);
|
||||
template <bool Execute> u16 mmu_read(offs_t logical, u16 mem_mask);
|
||||
void mmu_write(offs_t logical, u16 data, u16 mem_mask);
|
||||
|
||||
private:
|
||||
required_address_space m_space[4];
|
||||
devcb_write_line m_error;
|
||||
|
||||
memory_access<24, 1, 0, ENDIANNESS_BIG>::specific m_cpu_mem;
|
||||
memory_access<24, 1, 0, ENDIANNESS_BIG>::specific m_cpu_spc;
|
||||
|
||||
// only 20 of the possible 24 memory address lines are connected
|
||||
memory_access<20, 1, 0, ENDIANNESS_LITTLE>::specific m_bus_mem;
|
||||
memory_access<16, 1, 0, ENDIANNESS_LITTLE>::specific m_bus_pio;
|
||||
|
||||
u16 m_context;
|
||||
u16 m_segment[16][64];
|
||||
u16 m_page[1024];
|
||||
|
||||
bool m_stall;
|
||||
bool m_super;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(SUN1MMU, sun1mmu_device)
|
||||
|
||||
#endif // MAME_SUN_SUN1_MMU_H
|
Loading…
Reference in New Issue
Block a user