interpro: various improvements

Many changes, most notable end result is the ability to boot the "blue screen" rebuild floppy, and nearly booting CLIX (hangs trying to mount the filesystems).

Summary of changes:
* added a softlist
* refactored cpu/mmu memory access
* added alignment faults
* implemented most c400 instructions
* fixed wait instruction
* corrections to interpro driver
* removed broken forced interrupt handling
* added support for dma virtual addressing
This commit is contained in:
Patrick Mackinlay 2018-02-27 17:54:29 +07:00
parent 2bd73cc977
commit 421d6dd2cc
12 changed files with 1232 additions and 831 deletions

248
hash/interpro.xml Normal file
View File

@ -0,0 +1,248 @@
<?xml version="1.0"?>
<!DOCTYPE softwarelist SYSTEM "softwarelist.dtd">
<softwarelist name="interpro" description="Intergraph InterPro software">
<!--
Intergraph distributed all InterPro software, including that from 3rd
parties, on CD-ROM disc sets. A base 4-CD set of system software
contains the CLIX operating system and other programs such as editors,
compilers and graphics tools. Additional sets were typically organised
according to lines of business such as "Plant and Building Solutions",
"Architecture, Engineering and Construction", etc., and contained
application software aimed at companies in those industries.
All CD-ROM software is installed using the DELTOOLS package, and the
"newprod" utility in particular. In some cases, valid load keys (serial
numbers) are required to decrypt the delivered software and enable it
to be installed. In addition, some software has other runtime licensing
which must be configured before the programs will operate.
Finally, there are two sets of floppy disks that can be created via the
REBUILD and DIAG products. The REBUILD floppy disks are used to boot the
initial blue screen utility which allows configuring the system and
preparing a hard disk for installation, and to initiate the installation
process. The DIAG disks are used to launch the full suite of system
hardware diagnostic routines, via the FDMDISK monitor.
-->
<software name="iss">
<description>Intergraph System Software</description>
<year>1999</year>
<publisher>Intergraph</publisher>
<info name="date" value="05-MAY-1999"/>
<!-- System Software Disc I#05-MAY-1999#050599#FMDA0320N -->
<part name="disc1" interface="cdrom">
<feature name="part_id" value="System Software Disc I" />
<diskarea name="cdrom">
<disk name="iss_050599_1" sha1="5d556b4df2dccdc681095fedcf836a5b0a7782a0" writeable="no" />
</diskarea>
</part>
<!-- System Software Disc II#05-MAY-1999#050599#FMDA0320N -->
<part name="disc2" interface="cdrom">
<feature name="part_id" value="System Software Disc II" />
<diskarea name="cdrom">
<disk name="iss_050599_2" sha1="3813db83871668eed97b43f2384b7e95a649598a" writeable="no" />
</diskarea>
</part>
<!-- System Software Disc III#05-MAY-1999#050599#FMDA0320N -->
<part name="disc3" interface="cdrom">
<feature name="part_id" value="System Software Disc III" />
<diskarea name="cdrom">
<disk name="iss_050599_3" sha1="c8b08cd45ef1614b3db1cd0fb8e6539e3bcc5725" writeable="no" />
</diskarea>
</part>
<!-- System Software Disc IV#05-MAY-1999#050599#FMDA0170B -->
<part name="disc4" interface="cdrom">
<feature name="part_id" value="System Software Disc IV" />
<diskarea name="cdrom">
<disk name="iss_050599_4" sha1="2681b4cd8d355b6abfcfebb1b40a6d8a5ef37fe9" writeable="no" />
</diskarea>
</part>
</software>
<!--
The REBUILD product allows a set of system rebuild floppy disks to be
created from source binary data. When using the software, the user is
prompted to select from the following options, causing different
combinations of "boot" and "root" source data to be written to disk.
1) 125/32C/220/225 Systems (80186 IOP and ROP Graphics)
2) 200/240 Systems (80186 IOP and optional IFB Graphics)
3) 300/400/3000/4000 Systems (80386 IOP and optional IFB Graphics)
4) 2000 Systems (C300 Clipper IOP and optional MMG Graphics)
5) 6000 Systems (C300 Clipper IOP and optional EDGE Graphics)
6) 2400 Systems (C4T Clipper GTPLUS Graphics)
7) 6440/6480 Systems (C4T Clipper EDGE Graphics)
8) 6400/6450 Systems (C4T Clipper GTII Graphics)
9) 6640/6680 Systems (C400 Clipper EDGE graphics)
10) 6600 Servers (C400 Clipper Servers)
11) 6700/6800 Servers (C400I Clipper Server)
12) 6740/6780/6840/6880 Systems (C400I Clipper EDGE graphics)
13) 6750/6850 Systems (C400I Clipper GT graphics)
14) 2500/2700/2800 Systems (C400I Clipper Servers)
15) 2530/2730/2830 Systems (C400I Clipper GT graphics)
Ignoring the first 3 options which are unsupported in MAME at this point,
the remaining systems use one of 3 possible boot images: CLIPPER, C400 or
C400E.
-->
<software name="rebuild">
<description>Rebuild Floppies</description>
<year>1998</year>
<publisher>Intergraph</publisher>
<info name="product_id" value="SS01003AA-0706A" />
<info name="product_title" value="Rebuild Floppies" />
<info name="product_date" value="10-JAN-1998" />
<info name="product_name" value="REBUILD" />
<info name="product_version" value="07.06.00.09" />
<info name="product_class" value="System Nucleus" />
<!-- rebuild boot floppies for C300, C400E and C400 respectively -->
<part name="boot_clipper" interface="floppy_3_5">
<feature name="part_id" value="C300 Rebuild Boot Floppy" />
<feature name="compatibility" value="2000,2020,6000,6040" />
<dataarea name="flop" size="1474560">
<rom name="clipper.img" size="1474560" offset="0" crc="f182eb64" sha1="0e104e4db9f666ccc0d618b402666d90f025a3b4" />
</dataarea>
</part>
<part name="boot_c400e" interface="floppy_3_5">
<feature name="part_id" value="C400E Rebuild Boot Floppy" />
<feature name="compatibility" value="6600,6640,6680" />
<dataarea name="flop" size="1474560">
<rom name="c400e.img" size="1474560" offset="0" status="nodump" />
</dataarea>
</part>
<part name="boot_c400" interface="floppy_3_5">
<feature name="part_id" value="C400 Rebuild Boot Floppy" />
<feature name="compatibility" value="2400,2430,6440,6480,6400,6450,6750,6850,6740,6780,6840,6880,6700,6800,2500,2700,2800,2530,2730,2830" />
<dataarea name="flop" size="1474560">
<rom name="c400.img" size="1474560" offset="0" crc="7e739d42" sha1="ca3f2244d1167553482cd73c59cea74e181f37c7" />
</dataarea>
</part>
<!-- rebuild root floppies for 2000 and 2020 systems -->
<part name="20x0_root2" interface="floppy_3_5">
<feature name="part_id" value="Rebuild Floppy #2/4" />
<feature name="compatibility" value="2000,2020"/>
<dataarea name="flop" size="1474560">
<rom name="20x0_root2.img" size="1474560" offset="0" crc="66ee95eb" sha1="9b6e316f4c038ef471a84a82e396376b361c970a" />
</dataarea>
</part>
<part name="20x0_root3" interface="floppy_3_5">
<feature name="part_id" value="Rebuild Floppy #3/4" />
<feature name="compatibility" value="2000,2020"/>
<dataarea name="flop" size="1474560">
<rom name="20x0_root3.img" size="1474560" offset="0" crc="de490556" sha1="882c46e193a5467b66ffe2cd0ac8518df087d112" />
</dataarea>
</part>
<part name="20x0_root4" interface="floppy_3_5">
<feature name="part_id" value="Rebuild Floppy #4/4" />
<feature name="compatibility" value="2000,2020"/>
<dataarea name="flop" size="1474560">
<rom name="20x0_root4.img" size="1474560" offset="0" crc="2b0e3f01" sha1="e191057117aee120301143f25d5446f55789009c" />
</dataarea>
</part>
<!-- rebuild root floppies for 2400 and 2430 systems -->
<part name="24x0_root2" interface="floppy_3_5">
<feature name="part_id" value="Rebuild Floppy #2/4" />
<feature name="compatibility" value="2400,2430"/>
<dataarea name="flop" size="1474560">
<rom name="24x0_root2.img" size="1474560" offset="0" crc="f6a7ba45" sha1="c810cec284f61921ab1ffffe5e71b291d0a295a6" />
</dataarea>
</part>
<part name="24x0_root3" interface="floppy_3_5">
<feature name="part_id" value="Rebuild Floppy #3/4" />
<feature name="compatibility" value="2400,2430"/>
<dataarea name="flop" size="1474560">
<rom name="24x0_root3.img" size="1474560" offset="0" crc="1659399b" sha1="9ad4b4492654e76f4d5284af15b0235553b63f46" />
</dataarea>
</part>
<part name="24x0_root4" interface="floppy_3_5">
<feature name="part_id" value="Rebuild Floppy #4/4" />
<feature name="compatibility" value="2400,2430"/>
<dataarea name="flop" size="1474560">
<rom name="24x0_root4.img" size="1474560" offset="0" crc="594b2c9c" sha1="b69812399b7b32abbe81d00945b0d96a27b04c19" />
</dataarea>
</part>
<!-- TODO: root floppy images for all other systems -->
</software>
<!--
The DIAG product allows a set of system hardware diagnostic floppy disks
to be created from source binary data. When using the software, the user is
prompted to select from the following options, causing different
combinations of source data to be written to disk.
1) amethyst - 32C/100/200
2) emerald - 6000/6100/6200/6500/6600
3) topaz - 300/3000/4000/5000
4) turquoise - 2000
5) IOP based 6500 ( Manufacturing Test Only )
6) sapphire - 2400/2500/6400/2700/6700/6800/2800
Currently only the Turquoise and Sapphire systems are supported. Turquoise
diagnostics consists of a single floppy, while Sapphire systems have a 4
disk set. The first Sapphire disk contains a flash ROM image, with the
remaining 3 disks holding the diagnostic utilities.
-->
<software name="diag">
<description>Diagnostic Floppies</description>
<year>1994</year>
<publisher>Intergraph</publisher>
<info name="product_id" value="SS01086AA-0703A" />
<info name="product_title" value="Workstation/Server Diagnostics" />
<info name="product_date" value="30-MAR-1994" />
<info name="product_name" value="DIAG" />
<info name="product_version" value="07.03.15.00" />
<info name="product_class" value="Hardware Diagnostics" />
<!-- Turquoise systems have a single diagnostic floppy -->
<part name="turq" interface="floppy_3_5">
<feature name="part_id" value="Turqouise Diagnostic Floppy" />
<feature name="compatibility" value="2000,2020" />
<dataarea name="flop" size="1474560">
<rom name="turq.img" size="1474560" offset="0" crc="70e2980a" sha1="3fa2f0c54ef27e16e579563db9cd70b68e11e403" />
</dataarea>
</part>
<!-- Sapphire systems have a four-disk set of diagnostic floppies -->
<part name="sapphire" interface="floppy_3_5">
<feature name="part_id" value="Sapphire Flash ROM Floppy" />
<feature name="compatibility" value="2400,2430,6440,6480,6400,6450,6750,6850,6740,6780,6840,6880,6700,6800,2500,2700,2800,2530,2730,2830" />
<dataarea name="flop" size="1474560">
<rom name="sapphire.img" size="1474560" offset="0" crc="1721d7d1" sha1="fc25109c4c7b2d94d0fd55e7cebaa03e7177ad5e" />
</dataarea>
</part>
<part name="sapphire1" interface="floppy_3_5">
<feature name="part_id" value="Sapphire Diagnostic Floppy #1/3" />
<feature name="compatibility" value="2400,2430,6440,6480,6400,6450,6750,6850,6740,6780,6840,6880,6700,6800,2500,2700,2800,2530,2730,2830" />
<dataarea name="flop" size="1474560">
<rom name="sapphire1.img" size="1474560" offset="0" crc="e0db6354" sha1="75fb42ae87d78daaeac30390bef335419425da09" />
</dataarea>
</part>
<part name="sapphire2" interface="floppy_3_5">
<feature name="part_id" value="Sapphire Diagnostic Floppy #2/3" />
<feature name="compatibility" value="2400,2430,6440,6480,6400,6450,6750,6850,6740,6780,6840,6880,6700,6800,2500,2700,2800,2530,2730,2830" />
<dataarea name="flop" size="1474560">
<rom name="sapphire2.img" size="1474560" offset="0" crc="955065d1" sha1="6df92a7986a83d31e91189c8097b9b4f8d02960f" />
</dataarea>
</part>
<part name="sapphire3" interface="floppy_3_5">
<feature name="part_id" value="Sapphire Diagnostic Floppy #3/3" />
<feature name="compatibility" value="2400,2430,6440,6480,6400,6450,6750,6850,6740,6780,6840,6880,6700,6800,2500,2700,2800,2530,2730,2830" />
<dataarea name="flop" size="1474560">
<rom name="sapphire3.img" size="1474560" offset="0" crc="2f14fcb2" sha1="2d33087273c14597fc065e13d05e1ce9d1841704" />
</dataarea>
</part>
</software>
</softwarelist>

View File

@ -8,7 +8,7 @@
*
* TODO:
* - save/restore state
* - unimplemented C400 instructions
* - unimplemented C400 instructions (cdb, cnvx[ds]w, loadts, waitd)
* - correct boot logic
* - condition codes for multiply instructions
* - instruction timing
@ -57,25 +57,29 @@ DEFINE_DEVICE_TYPE(CLIPPER_C400, clipper_c400_device, "clipper_c400", "C400 CLIP
clipper_c100_device::clipper_c100_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: clipper_device(mconfig, CLIPPER_C100, tag, owner, clock, ENDIANNESS_LITTLE, 0)
, m_icammu(*this, "^cammu_i")
, m_dcammu(*this, "^cammu_d")
{
}
clipper_c300_device::clipper_c300_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: clipper_device(mconfig, CLIPPER_C300, tag, owner, clock, ENDIANNESS_LITTLE, 0)
, m_icammu(*this, "^cammu_i")
, m_dcammu(*this, "^cammu_d")
{
}
clipper_c400_device::clipper_c400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: clipper_device(mconfig, CLIPPER_C400, tag, owner, clock, ENDIANNESS_LITTLE, SSW_ID_C400R4)
, m_cammu(*this, "^cammu")
{
}
clipper_device::clipper_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, const endianness_t endianness, const u32 cpuid)
: cpu_device(mconfig, type, tag, owner, clock)
, m_insn_config("insn", endianness, 32, 32, 0)
, m_data_config("data", endianness, 32, 32, 0)
, m_insn(nullptr)
, m_data(nullptr)
, m_main_config("main", endianness, 32, 32, 0)
, m_io_config("io", endianness, 32, 32, 0)
, m_boot_config("boot", endianness, 32, 32, 0)
, m_icount(0)
, m_psw(endianness == ENDIANNESS_BIG ? PSW_BIG : 0)
, m_ssw(cpuid)
@ -110,9 +114,12 @@ inline u64 rotr64(u64 x, u8 shift)
void clipper_device::device_start()
{
// get our address spaces
m_insn = &space(AS_PROGRAM);
m_data = &space(AS_DATA);
// map spaces to system tags
std::vector<address_space *> spaces = { &space(0), &space(0), &space(0), &space(0), &space(1), &space(2), nullptr, nullptr };
// configure the cammu address spaces
get_icammu().set_spaces(spaces);
get_dcammu().set_spaces(spaces);
// set our instruction counter
m_icountptr = &m_icount;
@ -156,6 +163,8 @@ void clipper_device::device_reset()
* ssw: EI, TP, M, U, K, KU, UU, P cleared, ID set from hardware, others undefined
*/
m_wait = false;
// clear the psw and ssw
set_psw(0);
set_ssw(0);
@ -205,11 +214,15 @@ void clipper_device::execute_run()
// acknowledge interrupt
standard_irq_callback(INPUT_LINE_IRQ0);
LOGMASKED(LOG_EXCEPTION, "transferring control to ivec 0x%02x\n", m_ivec);
m_ip = intrap(EXCEPTION_INTERRUPT_BASE + m_ivec * 8, m_ip);
LOGMASKED(LOG_EXCEPTION, "transferring control to ivec 0x%02x address 0x%08x\n", m_ivec, m_ip);
}
}
if (m_wait)
m_icount = 0;
while (m_icount > 0)
{
debugger_instruction_hook(this, m_ip);
@ -282,6 +295,9 @@ void clipper_device::execute_run()
void clipper_device::execute_set_input(int inputnum, int state)
{
if (state)
m_wait = false;
switch (inputnum)
{
case INPUT_LINE_IRQ0:
@ -294,15 +310,12 @@ void clipper_device::execute_set_input(int inputnum, int state)
}
}
/*
* The CLIPPER has a true Harvard architecture. In the InterPro, these are tied back together
* again by the MMU, which then directs the access to one of 3 address spaces: main, i/o or boot.
*/
device_memory_interface::space_config_vector clipper_device::memory_space_config() const
{
return space_config_vector {
std::make_pair(AS_PROGRAM, &m_insn_config),
std::make_pair(AS_DATA, &m_data_config)
std::make_pair(0, &m_main_config),
std::make_pair(1, &m_io_config),
std::make_pair(2, &m_boot_config)
};
}
@ -324,17 +337,15 @@ WRITE16_MEMBER(clipper_device::set_exception)
*/
bool clipper_device::decode_instruction()
{
// fetch instruction word
u16 insn = m_insn->read_word(m_ip + 0);
if (m_exception)
// fetch and decode the primary parcel
if (!get_icammu().fetch<u16>(m_ssw, m_ip + 0, [this](u16 insn) {
m_info.opcode = insn >> 8;
m_info.subopcode = insn & 0xff;
m_info.r1 = (insn & 0x00f0) >> 4;
m_info.r2 = insn & 0x000f;
}))
return false;
// decode the primary parcel
m_info.opcode = insn >> 8;
m_info.subopcode = insn & 0xff;
m_info.r1 = (insn & 0x00f0) >> 4;
m_info.r2 = insn & 0x000f;
// initialise the other fields
m_info.imm = 0;
m_info.macro = 0;
@ -343,112 +354,93 @@ bool clipper_device::decode_instruction()
// default instruction size is 2 bytes
int size = 2;
if ((insn & 0xf800) == 0x3800)
if ((m_info.opcode & 0xf8) == 0x38)
{
// instruction has a 16 bit immediate operand
// fetch 16 bit immediate and sign extend
m_info.imm = (s16)m_insn->read_word(m_ip + 2);
if (m_exception)
if (!get_icammu().fetch<s16>(m_ssw, m_ip + 2, [this](s32 v) { m_info.imm = v; }))
return false;
size = 4;
}
else if ((insn & 0xd300) == 0x8300)
else if ((m_info.opcode & 0xd3) == 0x83)
{
// instruction has an immediate operand, either 16 or 32 bit
if (insn & 0x0080)
if (m_info.subopcode & 0x80)
{
// fetch 16 bit immediate and sign extend
m_info.imm = (s16)m_insn->read_word(m_ip + 2);
if (m_exception)
if (!get_icammu().fetch<s16>(m_ssw, m_ip + 2, [this](s32 v) { m_info.imm = v; }))
return false;
size = 4;
}
else
{
// fetch 32 bit immediate
m_info.imm = m_insn->read_dword_unaligned(m_ip + 2);
if (m_exception)
if (!get_icammu().fetch<u32>(m_ssw, m_ip + 2, [this](u32 v) { m_info.imm = v; }))
return false;
size = 6;
}
}
else if ((insn & 0xc000) == 0x4000)
else if ((m_info.opcode & 0xc0) == 0x40)
{
// instructions with addresses
if (insn & 0x0100)
if (m_info.opcode & 0x01)
{
// instructions with complex modes
u16 temp;
switch (insn & 0x00f0)
switch (m_info.subopcode & 0xf0)
{
case ADDR_MODE_PC32:
m_info.address = m_ip + m_insn->read_dword_unaligned(m_ip + 2);
if (m_exception)
if (!get_icammu().fetch<u32>(m_ssw, m_ip + 2, [this](u32 v) { m_info.address = m_ip + v; }))
return false;
size = 6;
break;
case ADDR_MODE_ABS32:
m_info.address = m_insn->read_dword_unaligned(m_ip + 2);
if (m_exception)
if (!get_icammu().fetch<u32>(m_ssw, m_ip + 2, [this](u32 v) { m_info.address = v; }))
return false;
size = 6;
break;
case ADDR_MODE_REL32:
m_info.r2 = m_insn->read_word(m_ip + 2) & 0xf;
if (m_exception)
if (!get_icammu().fetch<u16>(m_ssw, m_ip + 2, [this](u16 v) { m_info.r2 = v & 0xf; }))
return false;
m_info.address = m_r[insn & 0xf] + m_insn->read_dword_unaligned(m_ip + 4);
if (m_exception)
if (!get_icammu().fetch<u32>(m_ssw, m_ip + 4, [this](u32 v) { m_info.address = m_r[m_info.subopcode & 0xf] + v; }))
return false;
size = 8;
break;
case ADDR_MODE_PC16:
m_info.address = m_ip + (s16)m_insn->read_word(m_ip + 2);
if (m_exception)
if (!get_icammu().fetch<s16>(m_ssw, m_ip + 2, [this](s16 v) { m_info.address = m_ip + v; }))
return false;
size = 4;
break;
case ADDR_MODE_REL12:
temp = m_insn->read_word(m_ip + 2);
if (m_exception)
if (!get_icammu().fetch<s16>(m_ssw, m_ip + 2, [this](s16 v) {
m_info.r2 = v & 0xf;
m_info.address = m_r[m_info.subopcode & 0xf] + (v >> 4); }))
return false;
m_info.r2 = temp & 0xf;
m_info.address = m_r[insn & 0xf] + ((s16)temp >> 4);
size = 4;
break;
case ADDR_MODE_ABS16:
m_info.address = (s16)m_insn->read_word(m_ip + 2);
if (m_exception)
if (!get_icammu().fetch<s16>(m_ssw, m_ip + 2, [this](s32 v) { m_info.address = v; }))
return false;
size = 4;
break;
case ADDR_MODE_PCX:
temp = m_insn->read_word(m_ip + 2);
if (m_exception)
if (!get_icammu().fetch<u16>(m_ssw, m_ip + 2, [this](u16 v) {
m_info.r2 = v & 0xf;
m_info.address = m_ip + m_r[(v >> 4) & 0xf]; }))
return false;
m_info.r2 = temp & 0xf;
m_info.address = m_ip + m_r[(temp >> 4) & 0xf];
size = 4;
break;
case ADDR_MODE_RELX:
temp = m_insn->read_word(m_ip + 2);
if (m_exception)
if (!get_icammu().fetch<u16>(m_ssw, m_ip + 2, [this](u16 v) {
m_info.r2 = v & 0xf;
m_info.address = m_r[m_info.subopcode & 0xf] + m_r[(v >> 4) & 0xf]; }))
return false;
m_info.r2 = temp & 0xf;
m_info.address = m_r[insn & 0xf] + m_r[(temp >> 4) & 0xf];
size = 4;
break;
@ -461,11 +453,10 @@ bool clipper_device::decode_instruction()
// relative addressing mode
m_info.address = m_r[m_info.r1];
}
else if ((insn & 0xfd00) == 0xb400)
else if ((m_info.opcode & 0xfd) == 0xb4)
{
// macro instructions
m_info.macro = m_insn->read_word(m_ip + 2);
if (m_exception)
if (!get_icammu().fetch<u16>(m_ssw, m_ip + 2, [this](u16 v) { m_info.macro = v; }))
return false;
size = 4;
}
@ -479,9 +470,6 @@ bool clipper_device::decode_instruction()
void clipper_device::execute_instruction()
{
// memory fetch temporary
u64 temp;
switch (m_info.opcode)
{
case 0x00: // noop
@ -511,27 +499,25 @@ void clipper_device::execute_instruction()
break;
case 0x13:
// ret: return from subroutine
temp = m_data->read_dword(m_r[R2]);
if (!m_exception)
{
m_ip = temp;
get_dcammu().load<u32>(m_ssw, m_r[R2], [this](u32 v) {
m_ip = v;
m_r[R2] += 4;
}
});
// TRAPS: C,U,A,P,R
break;
case 0x14:
// pushw: push word
m_data->write_dword(m_r[R1] - 4, m_r[R2]);
m_r[R1] -= 4;
if (get_dcammu().store<u32>(m_ssw, m_r[R1] - 4, m_r[R2]))
m_r[R1] -= 4;
// TRAPS: A,P,W
break;
case 0x16:
// popw: pop word
m_r[R1] += 4;
temp = m_data->read_dword(m_r[R1] - 4);
if (!m_exception)
m_r[R2] = temp;
get_dcammu().load<u32>(m_ssw, m_r[R1], [this](u32 v) {
m_r[R1] += 4;
m_r[R2] = v;
});
// TRAPS: C,U,A,P,R
break;
@ -774,8 +760,7 @@ void clipper_device::execute_instruction()
case 0x44:
case 0x45:
// call: call subroutine
m_data->write_dword(m_r[R2] - 4, m_ip);
if (!m_exception)
if (get_dcammu().store<u32>(m_ssw, m_r[R2] - 4, m_ip))
{
m_ip = m_info.address;
m_r[R2] -= 4;
@ -818,9 +803,7 @@ void clipper_device::execute_instruction()
case 0x60:
case 0x61:
// loadw: load word
temp = m_data->read_dword(m_info.address);
if (!m_exception)
m_r[R2] = temp;
get_dcammu().load<u32>(m_ssw, m_info.address, [this](u32 v) { m_r[R2] = v; });
// TRAPS: C,U,A,P,R,I
break;
case 0x62:
@ -832,92 +815,77 @@ void clipper_device::execute_instruction()
case 0x64:
case 0x65:
// loads: load single floating
temp = m_data->read_dword(m_info.address);
if (!m_exception)
set_fp(R2, (float32)temp, F_NONE);
get_dcammu().load<float32>(m_ssw, m_info.address, [this](float32 v) { set_fp(R2, v, F_NONE); });
// TRAPS: C,U,A,P,R,I
break;
case 0x66:
case 0x67:
// loadd: load double floating
temp = m_data->read_qword(m_info.address);
if (!m_exception)
set_fp(R2, (float64)temp, F_NONE);
get_dcammu().load<float64>(m_ssw, m_info.address, [this](float64 v) { set_fp(R2, float64(v), F_NONE); });
// TRAPS: C,U,A,P,R,I
break;
case 0x68:
case 0x69:
// loadb: load byte
temp = s64(s8(m_data->read_byte(m_info.address)));
if (!m_exception)
m_r[R2] = temp;
get_dcammu().load<s8>(m_ssw, m_info.address, [this](s32 v) { m_r[R2] = v; });
// TRAPS: C,U,A,P,R,I
break;
case 0x6a:
case 0x6b:
// loadbu: load byte unsigned
temp = m_data->read_byte(m_info.address);
if (!m_exception)
m_r[R2] = temp;
get_dcammu().load<u8>(m_ssw, m_info.address, [this](u32 v) { m_r[R2] = v; });
// TRAPS: C,U,A,P,R,I
break;
case 0x6c:
case 0x6d:
// loadh: load halfword
temp = s64(s16(m_data->read_word(m_info.address)));
if (!m_exception)
m_r[R2] = temp;
get_dcammu().load<s16>(m_ssw, m_info.address, [this](s32 v) { m_r[R2] = v; });
// TRAPS: C,U,A,P,R,I
break;
case 0x6e:
case 0x6f:
// loadhu: load halfword unsigned
temp = m_data->read_word(m_info.address);
if (!m_exception)
m_r[R2] = temp;
get_dcammu().load<u16>(m_ssw, m_info.address, [this](u32 v) { m_r[R2] = v; });
// TRAPS: C,U,A,P,R,I
break;
case 0x70:
case 0x71:
// storw: store word
m_data->write_dword(m_info.address, m_r[R2]);
get_dcammu().store<u32>(m_ssw, m_info.address, m_r[R2]);
// TRAPS: A,P,W,I
break;
case 0x72:
case 0x73:
// tsts: test and set
temp = m_data->read_dword(m_info.address);
if (!m_exception)
{
m_data->write_dword(m_info.address, temp | 0x80000000U);
if (!m_exception)
m_r[R2] = temp;
}
get_dcammu().modify<u32>(m_ssw, m_info.address, [this](u32 v) {
m_r[R2] = v;
return v | 0x80000000U;
});
// TRAPS: C,U,A,P,R,W,I
break;
case 0x74:
case 0x75:
// stors: store single floating
m_data->write_dword(m_info.address, get_fp32(R2));
get_dcammu().store<float32>(m_ssw, m_info.address, get_fp32(R2));
// TRAPS: A,P,W,I
break;
case 0x76:
case 0x77:
// stord: store double floating
m_data->write_qword(m_info.address, get_fp64(R2));
get_dcammu().store<float64>(m_ssw, m_info.address, get_fp64(R2));
// TRAPS: A,P,W,I
break;
case 0x78:
case 0x79:
// storb: store byte
m_data->write_byte(m_info.address, m_r[R2]);
get_dcammu().store<u8>(m_ssw, m_info.address, m_r[R2]);
// TRAPS: A,P,W,I
break;
case 0x7c:
case 0x7d:
// storh: store halfword
m_data->write_word(m_info.address, m_r[R2]);
get_dcammu().store<u16>(m_ssw, m_info.address, m_r[R2]);
// TRAPS: A,P,W,I
break;
@ -1163,7 +1131,7 @@ void clipper_device::execute_instruction()
// store ri at sp - 4 * (15 - i)
for (int i = R2; i < 15 && !m_exception; i++)
m_data->write_dword(m_r[15] - 4 * (15 - i), m_r[i]);
get_dcammu().store<u32>(m_ssw, m_r[15] - 4 * (15 - i), m_r[i]);
// decrement sp after push to allow restart on exceptions
if (!m_exception)
@ -1179,11 +1147,8 @@ void clipper_device::execute_instruction()
while (m_r[0])
{
const u8 byte = m_data->read_byte(m_r[1]);
if (m_exception)
break;
get_dcammu().load<u8>(m_ssw, m_r[1], [this](u8 byte) { get_dcammu().store<u8>(m_ssw, m_r[2], byte); });
m_data->write_byte(m_r[2], byte);
if (m_exception)
break;
@ -1197,8 +1162,7 @@ void clipper_device::execute_instruction()
// initc: initialise r0 bytes at r1 with value in r2
while (m_r[0])
{
m_data->write_byte(m_r[1], m_r[2]);
if (m_exception)
if (!get_dcammu().store<u8>(m_ssw, m_r[1], m_r[2]))
break;
m_r[0]--;
@ -1215,18 +1179,15 @@ void clipper_device::execute_instruction()
while (m_r[0])
{
// set condition codes and abort the loop if the current byte does not match
s32 byte1 = s8(m_data->read_byte(m_r[1]));
if (m_exception)
// read and compare bytes (as signed 32 bit integers)
get_dcammu().load<s8>(m_ssw, m_r[1], [this](s32 byte1) {
get_dcammu().load<s8>(m_ssw, m_r[2], [this, byte1](s32 byte2) {
if (byte1 != byte2)
FLAGS(C_SUB(byte2, byte1), V_SUB(byte2, byte1), byte2 == byte1, byte2 < byte1); }); });
// abort on exception or mismatch
if (m_exception || !PSW(Z))
break;
s32 byte2 = s8(m_data->read_byte(m_r[2]));
if (m_exception)
break;
if (byte1 != byte2)
{
FLAGS(C_SUB(byte2, byte1), V_SUB(byte2, byte1), byte2 == byte1, byte2 < byte1)
break;
}
m_r[0]--;
m_r[1]++;
@ -1241,13 +1202,8 @@ void clipper_device::execute_instruction()
// restwN..restw12: pop registers rN:r14
// load ri from sp + 4 * (i - N)
for (int i = R2; i < 15; i++)
{
temp = m_data->read_dword(m_r[15] + 4 * (i - R2));
if (m_exception)
break;
m_r[i] = temp;
}
for (int i = R2; i < 15 && !m_exception; i++)
get_dcammu().load<u32>(m_ssw, m_r[15] + 4 * (i - R2), [this, i](u32 v) { m_r[i] = v; });
// increment sp after pop to allow restart on exceptions
if (!m_exception)
@ -1261,7 +1217,7 @@ void clipper_device::execute_instruction()
// store fi at sp - 8 * (8 - i)
for (int i = R2; i < 8 && !m_exception; i++)
m_data->write_qword(m_r[15] - 8 * (8 - i), get_fp64(i));
get_dcammu().store<float64>(m_ssw, m_r[15] - 8 * (8 - i), get_fp64(i));
// decrement sp after push to allow restart on exceptions
if (!m_exception)
@ -1273,13 +1229,8 @@ void clipper_device::execute_instruction()
// restd0..restd7: pop registers fN:f7
// load fi from sp + 8 * (i - N)
for (int i = R2; i < 8; i++)
{
temp = m_data->read_qword(m_r[15] + 8 * (i - R2));
if (m_exception)
break;
set_fp(i, (float64)temp, F_NONE);
}
for (int i = R2; i < 8 && !m_exception; i++)
get_dcammu().load<float64>(m_ssw, m_r[15] + 8 * (i - R2), [this, i](float64 v) { set_fp(i, v, F_NONE); });
// increment sp after pop to allow restart on exceptions
if (!m_exception)
@ -1438,7 +1389,7 @@ void clipper_device::execute_instruction()
case 0x02:
// saveur: save user registers
for (int i = 0; i < 16 && !m_exception; i++)
m_data->write_dword(m_rs[(m_info.macro >> 4) & 0xf] - 4 * (i + 1), m_ru[15 - i]);
get_dcammu().store<u32>(m_ssw, m_rs[(m_info.macro >> 4) & 0xf] - 4 * (i + 1), m_ru[15 - i]);
if (!m_exception)
m_rs[(m_info.macro >> 4) & 0xf] -= 64;
@ -1446,13 +1397,8 @@ void clipper_device::execute_instruction()
break;
case 0x03:
// restur: restore user registers
for (int i = 0; i < 16; i++)
{
temp = m_data->read_dword(m_rs[(m_info.macro >> 4) & 0xf] + 4 * i);
if (m_exception)
break;
m_ru[i] = temp;
}
for (int i = 0; i < 16 && !m_exception; i++)
get_dcammu().load<u32>(m_ssw, m_rs[(m_info.macro >> 4) & 0xf] + 4 * i, [this, i](u32 v) { m_ru[i] = v; });
if (!m_exception)
m_rs[(m_info.macro >> 4) & 0xf] += 64;
@ -1465,7 +1411,7 @@ void clipper_device::execute_instruction()
break;
case 0x05:
// wait: wait for interrupt
m_ip = m_pc;
m_wait = true;
// TRAPS: S
break;
@ -1486,17 +1432,16 @@ void clipper_device::execute_instruction()
u32 clipper_device::reti()
{
u32 new_psw = 0, new_ssw = 0, new_pc = 0;
// fetch the psw, ssw and pc from the supervisor stack
const u32 new_psw = m_data->read_dword(m_rs[(m_info.macro >> 4) & 0xf] + 0);
if (m_exception)
if (!get_dcammu().load<u32>(m_ssw, m_rs[(m_info.macro >> 4) & 0xf] + 0, [&new_psw](u32 v) { new_psw = v; }))
fatalerror("reti unrecoverable fault 0x%04x read psw address 0x%08x pc 0x%08x\n", m_exception, m_rs[(m_info.macro >> 4) & 0xf] + 0, m_pc);
const u32 new_ssw = m_data->read_dword(m_rs[(m_info.macro >> 4) & 0xf] + 4);
if (m_exception)
if (!get_dcammu().load<u32>(m_ssw, m_rs[(m_info.macro >> 4) & 0xf] + 4, [&new_ssw](u32 v) { new_ssw = v; }))
fatalerror("reti unrecoverable fault 0x%04x read ssw address 0x%08x pc 0x%08x\n", m_exception, m_rs[(m_info.macro >> 4) & 0xf] + 4, m_pc);
const u32 new_pc = m_data->read_dword(m_rs[(m_info.macro >> 4) & 0xf] + 8);
if (m_exception)
if (!get_dcammu().load<u32>(m_ssw, m_rs[(m_info.macro >> 4) & 0xf] + 8, [&new_pc](u32 v) { new_pc = v; }))
fatalerror("reti unrecoverable fault 0x%04x read pc address 0x%08x pc 0x%08x\n", m_exception, m_rs[(m_info.macro >> 4) & 0xf] + 8, m_pc);
LOGMASKED(LOG_EXCEPTION, "reti r%d ssp 0x%08x pc 0x%08x ssw 0x%08x psw 0x%08x new_pc 0x%08x new_ssw 0x%08x new_psw 0x%08x\n",
@ -1522,6 +1467,7 @@ u32 clipper_device::intrap(const u16 vector, const u32 old_pc)
{
const u32 old_ssw = m_ssw;
const u32 old_psw = m_psw;
u32 new_pc = 0, new_ssw = 0;
// clear ssw bits to enable supervisor memory access
m_ssw &= ~(SSW_U | SSW_K | SSW_UU | SSW_KU);
@ -1530,13 +1476,10 @@ u32 clipper_device::intrap(const u16 vector, const u32 old_pc)
m_exception = 0;
// fetch next pc and ssw from interrupt vector
const u32 new_pc = m_data->read_dword(vector + get_evpc_offset());
if (m_exception)
fatalerror("intrap unrecoverable fault 0x%04x read pc address 0x%08x pc 0x%08x\n", m_exception, vector + get_evpc_offset(), old_pc);
const u32 new_ssw = m_data->read_dword(vector + get_evssw_offset());
if (m_exception)
fatalerror("intrap unrecoverable fault 0x%04x read ssw address 0x%08x pc 0x%08x\n", m_exception, vector + get_evssw_offset(), old_pc);
if (!get_dcammu().load<u32>(m_ssw, vector + 0, [&new_pc](u32 v) { new_pc = v; }))
fatalerror("intrap unrecoverable fault 0x%04x load pc address 0x%08x pc 0x%08x\n", m_exception, vector + 0, old_pc);
if (!get_dcammu().load<u32>(m_ssw, vector + 4, [&new_ssw](u32 v) { new_ssw = v; }))
fatalerror("intrap unrecoverable fault 0x%04x load ssw address 0x%08x pc 0x%08x\n", m_exception, vector + 4, old_pc);
LOGMASKED(LOG_EXCEPTION, "intrap vector 0x%04x pc 0x%08x ssp 0x%08x new_pc 0x%08x new_ssw 0x%08x\n", vector, old_pc, m_rs[15], new_pc, new_ssw);
@ -1581,18 +1524,107 @@ u32 clipper_device::intrap(const u16 vector, const u32 old_pc)
}
// push pc, ssw and psw onto supervisor stack
m_data->write_dword(m_rs[15] - 0x4, old_pc);
if (m_exception)
fatalerror("intrap unrecoverable fault 0x%04x write pc address 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x4, old_pc);
m_data->write_dword(m_rs[15] - 0x8, old_ssw);
if (m_exception)
fatalerror("intrap unrecoverable fault 0x%04x write ssw address 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x8, old_pc);
m_data->write_dword(m_rs[15] - 0xc, (old_psw & ~(PSW_CTS | PSW_MTS)) | source);
if (m_exception)
fatalerror("intrap unrecoverable fault 0x%04x write psw address 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0xc, old_pc);
if (!get_dcammu().store<u32>(m_ssw, m_rs[15] - 0x4, old_pc))
fatalerror("intrap unrecoverable fault 0x%04x push pc ssp 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x4, old_pc);
if (!get_dcammu().store<u32>(m_ssw, m_rs[15] - 0x8, old_ssw))
fatalerror("intrap unrecoverable fault 0x%04x push ssw ssp 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x8, old_pc);
if (!get_dcammu().store<u32>(m_ssw, m_rs[15] - 0xc, (old_psw & ~(PSW_CTS | PSW_MTS)) | source))
fatalerror("intrap unrecoverable fault 0x%04x push psw ssp 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0xc, old_pc);
// decrement supervisor stack pointer
m_rs[15] -= get_eframe_size();
m_rs[15] -= 12;
// set ssw from vector and previous mode
set_ssw((new_ssw & ~SSW_P) | (old_ssw & SSW_U) << 1);
// clear psw
set_psw(0);
// return new pc from trap vector
return new_pc;
}
u32 clipper_c400_device::intrap(const u16 vector, const u32 old_pc)
{
const u32 old_ssw = m_ssw;
const u32 old_psw = m_psw;
u32 new_pc = 0, new_ssw = 0;
// clear ssw bits to enable supervisor memory access
m_ssw &= ~(SSW_U | SSW_K | SSW_UU | SSW_KU);
// clear exception state
m_exception = 0;
// fetch ssw and pc from interrupt vector (C400 reversed wrt C100/C300)
if (!get_dcammu().load<u32>(m_ssw, vector + 0, [&new_ssw](u32 v) { new_ssw = v; }))
fatalerror("intrap unrecoverable fault 0x%04x load ssw address 0x%08x pc 0x%08x\n", m_exception, vector + 0, old_pc);
if (!get_dcammu().load<u32>(m_ssw, vector + 4, [&new_pc](u32 v) { new_pc = v; }))
fatalerror("intrap unrecoverable fault 0x%04x load pc address 0x%08x pc 0x%08x\n", m_exception, vector + 4, old_pc);
LOGMASKED(LOG_EXCEPTION, "intrap vector 0x%04x pc 0x%08x ssp 0x%08x new_pc 0x%08x new_ssw 0x%08x\n", vector, old_pc, m_rs[15], new_pc, new_ssw);
// derive cts and mts from vector
u32 source = 0;
switch (vector)
{
// data memory trap group
case EXCEPTION_D_CORRECTED_MEMORY_ERROR:
case EXCEPTION_D_UNCORRECTABLE_MEMORY_ERROR:
case EXCEPTION_D_ALIGNMENT_FAULT:
case EXCEPTION_D_PAGE_FAULT:
case EXCEPTION_D_READ_PROTECT_FAULT:
case EXCEPTION_D_WRITE_PROTECT_FAULT:
// instruction memory trap group
case EXCEPTION_I_CORRECTED_MEMORY_ERROR:
case EXCEPTION_I_UNCORRECTABLE_MEMORY_ERROR:
case EXCEPTION_I_ALIGNMENT_FAULT:
case EXCEPTION_I_PAGE_FAULT:
case EXCEPTION_I_EXECUTE_PROTECT_FAULT:
source = (vector & MTS_VMASK) << (MTS_SHIFT - MTS_VSHIFT);
break;
// integer arithmetic trap group
case EXCEPTION_INTEGER_DIVIDE_BY_ZERO:
source = CTS_DIVIDE_BY_ZERO;
break;
// illegal operation trap group
case EXCEPTION_ILLEGAL_OPERATION:
source = CTS_ILLEGAL_OPERATION;
break;
case EXCEPTION_PRIVILEGED_INSTRUCTION:
source = CTS_PRIVILEGED_INSTRUCTION;
break;
// diagnostic trap group
case EXCEPTION_TRACE:
source = CTS_TRACE_TRAP;
break;
}
// push pc, ssw and psw onto supervisor stack
if (!get_dcammu().store<u32>(m_ssw, m_rs[15] - 0x4, old_pc))
fatalerror("intrap unrecoverable fault 0x%04x push pc ssp 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x4, old_pc);
if (!get_dcammu().store<u32>(m_ssw, m_rs[15] - 0x8, old_ssw))
fatalerror("intrap unrecoverable fault 0x%04x push ssw ssp 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x8, old_pc);
if (!get_dcammu().store<u32>(m_ssw, m_rs[15] - 0xc, (old_psw & ~(PSW_CTS | PSW_MTS)) | source))
fatalerror("intrap unrecoverable fault 0x%04x push psw ssp 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0xc, old_pc);
// TODO: push pc1
// TODO: push pc2
// push delayed branch pc onto supervisor stack
if (!get_dcammu().store<u32>(m_ssw, m_rs[15] - 0x18, m_db_pc))
fatalerror("intrap unrecoverable fault 0x%04x push db_pc address 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x18, old_pc);
// decrement supervisor stack pointer
m_rs[15] -= 24;
// set ssw from vector and previous mode
set_ssw((new_ssw & ~SSW_P) | (old_ssw & SSW_U) << 1);
@ -1736,37 +1768,119 @@ void clipper_device::fp_exception()
void clipper_c400_device::execute_instruction()
{
// update delay slot pointer
switch (PSW(DSP))
{
case DSP_S1:
// take delayed branch
m_psw &= ~PSW_DSP;
m_ip = m_db_pc;
return;
case DSP_SALL:
// one delay slot still active
m_psw &= ~PSW_DSP;
m_psw |= DSP_S1;
break;
case DSP_SETUP:
// two delay slots active
m_psw &= ~PSW_DSP;
m_psw |= DSP_SALL;
break;
}
// if executing a delay slot instruction, test for valid type
if (PSW(DSP))
{
switch (m_info.opcode)
{
case 0x13: // ret
case 0x44: // call
case 0x45:
case 0x48: // b*
case 0x49:
case 0x4a: // cdb
case 0x4b:
case 0x4c: // cdbeq
case 0x4d:
case 0x4e: // cdbne
case 0x4f:
case 0x50: // db*
case 0x51:
// TODO: this should throw some kind of illegal instruction trap, not abort
fatalerror("instruction type 0x%02x invalid in branch delay slot pc 0x%08x\n", m_info.opcode, m_pc);
default:
break;
}
}
switch (m_info.opcode)
{
#ifdef UNIMPLEMENTED_C400
case 0x46:
case 0x47:
// loadd2:
// loadd2: load double floating double
// TODO: 128-bit load
get_dcammu().load<float64>(m_ssw, m_info.address + 0, [this](float64 v) { set_fp(R2 + 0, v, F_NONE); });
get_dcammu().load<float64>(m_ssw, m_info.address + 8, [this](float64 v) { set_fp(R2 + 1, v, F_NONE); });
// TRAPS: C,U,A,P,R,I
break;
case 0x4a:
case 0x4b:
// cdb:
break;
// cdb: call with delayed branch?
// emulate.h: "cdb is special because it does not support all addressing modes", 2-3 parcels
fatalerror("cdb pc 0x%08x\n", m_pc);
case 0x4c:
case 0x4d:
// cdbeq:
break;
// cdbeq: call with delayed branch if equal?
fatalerror("cdbeq pc 0x%08x\n", m_pc);
case 0x4e:
case 0x4f:
// cdbne:
break;
// cdbne: call with delayed branch if not equal?
fatalerror("cdbne pc 0x%08x\n", m_pc);
case 0x50:
case 0x51:
// db*:
// db*: delayed branch on condition
if (evaluate_branch())
{
m_psw |= DSP_SETUP;
m_db_pc = m_info.address;
}
break;
case 0xb0:
// abss: absolute value single floating?
if (float32_lt(get_fp32(R1), 0))
set_fp(R2, float32_mul(get_fp32(R1), int32_to_float32(-1)), F_IVUX);
else
set_fp(R2, get_fp32(R1), F_IVUX);
break;
case 0xb2:
// absd: absolute value double floating?
if (float64_lt(get_fp64(R1), 0))
set_fp(R2, float64_mul(get_fp64(R1), int32_to_float64(-1)), F_IVUX);
else
set_fp(R2, get_fp64(R1), F_IVUX);
break;
case 0xb4:
// unprivileged macro instructions
switch (m_info.subopcode)
{
case 0x44:
// cnvxsw: ??
fatalerror("cnvxsw pc 0x%08x\n", m_pc);
case 0x46:
// cnvxdw: ??
fatalerror("cnvxdw pc 0x%08x\n", m_pc);
default:
clipper_device::execute_instruction();
break;
}
break;
case 0xb6:
@ -1777,19 +1891,29 @@ void clipper_c400_device::execute_instruction()
{
case 0x07:
// loadts: unknown?
fatalerror("loadts pc 0x%08x\n", m_pc);
default:
clipper_device::execute_instruction();
break;
}
}
else
m_exception = EXCEPTION_PRIVILEGED_INSTRUCTION;
break;
case 0xbc:
// waitd:
if (!SSW(U))
; // TODO: don't know what this instruction does
else
m_exception = EXCEPTION_PRIVILEGED_INSTRUCTION;
break;
case 0xc0:
// s*:
// s*: set register on condition
m_r[R1] = evaluate_branch() ? 1 : 0;
break;
#endif
default:
clipper_device::execute_instruction();

View File

@ -10,6 +10,9 @@
#include "softfloat/milieu.h"
#include "softfloat/softfloat.h"
#include "cpu/clipper/common.h"
#include "machine/cammu.h"
// convenience macros for dealing with the psw and ssw
#define PSW(mask) (m_psw & PSW_##mask)
#define SSW(mask) (m_ssw & SSW_##mask)
@ -17,22 +20,9 @@
class clipper_device : public cpu_device
{
public:
DECLARE_READ32_MEMBER(get_ssw) const { return m_ssw; }
DECLARE_WRITE8_MEMBER(set_ivec) { m_ivec = data; }
DECLARE_WRITE16_MEMBER(set_exception);
enum addressing_modes : u8
{
ADDR_MODE_PC32 = 0x10, // pc relative with 32 bit displacement
ADDR_MODE_ABS32 = 0x30, // 32 bit absolute
ADDR_MODE_REL32 = 0x60, // relative with 32 bit displacement
ADDR_MODE_PC16 = 0x90, // pc relative with 16 bit displacement
ADDR_MODE_REL12 = 0xa0, // relative with 12 bit displacement
ADDR_MODE_ABS16 = 0xb0, // 16 bit absolute
ADDR_MODE_PCX = 0xd0, // pc indexed
ADDR_MODE_RELX = 0xe0 // relative indexed
};
// branch conditions (first description for comparison, second for move/logical)
enum branch_conditions : u8
{
@ -94,73 +84,21 @@ public:
FR_3 = 0x00018000 // round toward zero
};
enum ssw : u32
enum psw_dsp : u32
{
SSW_IN = 0x0000000f, // interrupt number (4 bits)
SSW_IL = 0x000000f0, // interrupt level (4 bits)
SSW_EI = 0x00000100, // enable interrupts
SSW_ID = 0x0001fe00, // cpu rev # and type (8 bits)
// unused (5 bits)
SSW_FRD = 0x00400000, // floating registers dirty
SSW_TP = 0x00800000, // trace trap pending
SSW_ECM = 0x01000000, // enable corrected memory error
SSW_DF = 0x02000000, // fpu disabled
SSW_M = 0x04000000, // mapped mode
SSW_KU = 0x08000000, // user protect key
SSW_UU = 0x10000000, // user data mode
SSW_K = 0x20000000, // protect key
SSW_U = 0x40000000, // user mode
SSW_P = 0x80000000 // previous mode
DSP_NONE = 0x00000000, // no delayed branch active
DSP_S1 = 0x00100000, // delayed branch slot 1 active
DSP_SALL = 0x00200000, // delayed branch slots 0 and 1 active
DSP_SETUP = 0x00300000 // delayed branch taken
};
enum ssw_id : u32
{
SSW_ID_C400R0 = 0x00000,
SSW_ID_C400R1 = 0x04000,
SSW_ID_C400R2 = 0x08000,
SSW_ID_C400R3 = 0x0c000,
SSW_ID_C400R4 = 0x10000
};
enum exception_vectors : u16
{
// data memory trap group
EXCEPTION_D_CORRECTED_MEMORY_ERROR = 0x108,
EXCEPTION_D_UNCORRECTABLE_MEMORY_ERROR = 0x110,
EXCEPTION_D_ALIGNMENT_FAULT = 0x120,
EXCEPTION_D_PAGE_FAULT = 0x128,
EXCEPTION_D_READ_PROTECT_FAULT = 0x130,
EXCEPTION_D_WRITE_PROTECT_FAULT = 0x138,
// floating-point arithmetic trap group
EXCEPTION_FLOATING_INEXACT = 0x180,
EXCEPTION_FLOATING_UNDERFLOW = 0x188,
EXCEPTION_FLOATING_DIVIDE_BY_ZERO = 0x190,
EXCEPTION_FLOATING_OVERFLOW = 0x1a0,
EXCEPTION_FLOATING_INVALID_OPERATION = 0x1c0,
// integer arithmetic trap group
EXCEPTION_INTEGER_DIVIDE_BY_ZERO = 0x208,
// instruction memory trap group
EXCEPTION_I_CORRECTED_MEMORY_ERROR = 0x288,
EXCEPTION_I_UNCORRECTABLE_MEMORY_ERROR = 0x290,
EXCEPTION_I_ALIGNMENT_FAULT = 0x2a0,
EXCEPTION_I_PAGE_FAULT = 0x2a8,
EXCEPTION_I_EXECUTE_PROTECT_FAULT = 0x2b0,
// illegal operation trap group
EXCEPTION_ILLEGAL_OPERATION = 0x300,
EXCEPTION_PRIVILEGED_INSTRUCTION = 0x308,
// diagnostic trap group
EXCEPTION_TRACE = 0x380,
// supervisor calls (0x400-0x7f8)
EXCEPTION_SUPERVISOR_CALL_BASE = 0x400,
// prioritized interrupts (0x800-0xff8)
EXCEPTION_INTERRUPT_BASE = 0x800
SSW_ID_C400R0 = 0x00800,
SSW_ID_C400R1 = 0x04800,
SSW_ID_C400R2 = 0x08800,
SSW_ID_C400R3 = 0x0c800,
SSW_ID_C400R4 = 0x10800
};
// trap source values are shifted into the correct field in the psw
@ -230,13 +168,17 @@ protected:
// device_disasm_interface overrides
virtual util::disasm_interface *create_disassembler() override;
// mmu helpers
virtual cammu_device &get_icammu() const = 0;
virtual cammu_device &get_dcammu() const = 0;
// cpu execution logic
bool decode_instruction();
virtual void execute_instruction();
bool evaluate_branch() const;
// exception entry and return helpers
u32 intrap(const u16 vector, const u32 old_pc);
virtual u32 intrap(const u16 vector, const u32 old_pc);
u32 reti();
// cpu state helpers
@ -248,11 +190,6 @@ protected:
virtual int get_ireg_count() const { return 16; }
virtual int get_freg_count() const { return 8; }
// exception vector and frame helpers
virtual int get_eframe_size() const { return 12; }
virtual int get_evpc_offset() const { return 0; }
virtual int get_evssw_offset() const { return 4; }
// floating point helpers
float32 get_fp32(const u8 reg) const { return m_f[reg & 0xf]; }
float64 get_fp64(const u8 reg) const { return m_f[reg & 0xf]; }
@ -317,11 +254,9 @@ protected:
};
// emulation state
address_space_config m_insn_config;
address_space_config m_data_config;
address_space *m_insn;
address_space *m_data;
address_space_config m_main_config;
address_space_config m_io_config;
address_space_config m_boot_config;
enum registers
{
@ -333,6 +268,7 @@ protected:
};
int m_icount; // instruction cycle count
bool m_wait;
// program-visible cpu state
u32 m_pc; // current instruction address
@ -372,12 +308,28 @@ class clipper_c100_device : public clipper_device
{
public:
clipper_c100_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
virtual cammu_device &get_icammu() const override { return *m_icammu; }
virtual cammu_device &get_dcammu() const override { return *m_dcammu; }
private:
required_device<cammu_device> m_icammu;
required_device<cammu_device> m_dcammu;
};
class clipper_c300_device : public clipper_device
{
public:
clipper_c300_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
virtual cammu_device &get_icammu() const override { return *m_icammu; }
virtual cammu_device &get_dcammu() const override { return *m_dcammu; }
private:
required_device<cammu_device> m_icammu;
required_device<cammu_device> m_dcammu;
};
class clipper_c400_device : public clipper_device
@ -386,19 +338,20 @@ public:
clipper_c400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
virtual u32 intrap(const u16 vector, const u32 old_pc) override;
// C400 has additional 8 floating point registers
virtual int get_freg_count() const override { return 16; }
// C400 creates a 24 byte exception frame (C100/C300 is 12 bytes), but the
// service routine must increment sp by 12 prior to executing reti
// exception frame size
virtual int get_eframe_size() const override { return 24; }
// C400 pc and ssw are reversed in exception vector compared to C100/C300
virtual int get_evpc_offset() const override { return 4; }
virtual int get_evssw_offset() const override { return 0; }
virtual void execute_instruction() override;
virtual cammu_device &get_icammu() const override { return *m_cammu; }
virtual cammu_device &get_dcammu() const override { return *m_cammu; }
private:
u32 m_db_pc; // delayed branch pc
required_device<cammu_device> m_cammu;
};
DECLARE_DEVICE_TYPE(CLIPPER_C100, clipper_c100_device)

View File

@ -2,6 +2,7 @@
// copyright-holders:Patrick Mackinlay
#include "emu.h"
#include "cpu/clipper/common.h"
#include "clipperd.h"
/*
@ -297,6 +298,10 @@ offs_t clipper_disassembler::disassemble(std::ostream &stream, offs_t pc, const
case 0x3e: util::stream_format(stream, "trapfn"); break;
case 0x3f: util::stream_format(stream, "loadfs r%d,f%d", (opcodes.r16(pc+2) & 0xf0) >> 4, opcodes.r16(pc+2) & 0xf); break;
#if C400_INSTRUCTIONS
case 0x44: util::stream_format(stream, "cnvxsw f%d,f%d", (opcodes.r16(pc + 2) & 0xf0) >> 4, opcodes.r16(pc + 2) & 0xf); break;
case 0x46: util::stream_format(stream, "cnvxdw f%d,f%d", (opcodes.r16(pc + 2) & 0xf0) >> 4, opcodes.r16(pc + 2) & 0xf); break;
#endif
default:
util::stream_format(stream, "macro 0x%04x 0x%04x", opcodes.r16(pc), opcodes.r16(pc+2));
break;

View File

@ -16,22 +16,8 @@ public:
virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
private:
enum addressing_modes : u8
{
ADDR_MODE_PC32 = 0x10, // pc relative with 32 bit displacement
ADDR_MODE_ABS32 = 0x30, // 32 bit absolute
ADDR_MODE_REL32 = 0x60, // relative with 32 bit displacement
ADDR_MODE_PC16 = 0x90, // pc relative with 16 bit displacement
ADDR_MODE_REL12 = 0xa0, // relative with 12 bit displacement
ADDR_MODE_ABS16 = 0xb0, // 16 bit absolute
ADDR_MODE_PCX = 0xd0, // pc indexed
ADDR_MODE_RELX = 0xe0 // relative indexed
};
static const char *const cc[];
std::string address (offs_t pc, const data_buffer &opcodes);
};
#endif

View File

@ -0,0 +1,83 @@
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay
#ifndef MAME_CPU_CLIPPER_COMMON_H
#define MAME_CPU_CLIPPER_COMMON_H
#pragma once
enum addressing_modes : u8
{
ADDR_MODE_PC32 = 0x10, // pc relative with 32 bit displacement
ADDR_MODE_ABS32 = 0x30, // 32 bit absolute
ADDR_MODE_REL32 = 0x60, // relative with 32 bit displacement
ADDR_MODE_PC16 = 0x90, // pc relative with 16 bit displacement
ADDR_MODE_REL12 = 0xa0, // relative with 12 bit displacement
ADDR_MODE_ABS16 = 0xb0, // 16 bit absolute
ADDR_MODE_PCX = 0xd0, // pc indexed
ADDR_MODE_RELX = 0xe0 // relative indexed
};
enum ssw_mask : u32
{
SSW_IN = 0x0000000f, // interrupt number (4 bits)
SSW_IL = 0x000000f0, // interrupt level (4 bits)
SSW_EI = 0x00000100, // enable interrupts
SSW_ID = 0x0001fe00, // cpu rev # and type (8 bits)
// unused (5 bits)
SSW_FRD = 0x00400000, // floating registers dirty
SSW_TP = 0x00800000, // trace trap pending
SSW_ECM = 0x01000000, // enable corrected memory error
SSW_DF = 0x02000000, // fpu disabled
SSW_M = 0x04000000, // mapped mode
SSW_KU = 0x08000000, // user protect key
SSW_UU = 0x10000000, // user data mode
SSW_K = 0x20000000, // protect key
SSW_U = 0x40000000, // user mode
SSW_P = 0x80000000, // previous mode
SSW_PL = 0x78000000 // protection level relevant bits
};
enum exception_vector : u16
{
// data memory trap group
EXCEPTION_D_CORRECTED_MEMORY_ERROR = 0x108,
EXCEPTION_D_UNCORRECTABLE_MEMORY_ERROR = 0x110,
EXCEPTION_D_ALIGNMENT_FAULT = 0x120,
EXCEPTION_D_PAGE_FAULT = 0x128,
EXCEPTION_D_READ_PROTECT_FAULT = 0x130,
EXCEPTION_D_WRITE_PROTECT_FAULT = 0x138,
// floating-point arithmetic trap group
EXCEPTION_FLOATING_INEXACT = 0x180,
EXCEPTION_FLOATING_UNDERFLOW = 0x188,
EXCEPTION_FLOATING_DIVIDE_BY_ZERO = 0x190,
EXCEPTION_FLOATING_OVERFLOW = 0x1a0,
EXCEPTION_FLOATING_INVALID_OPERATION = 0x1c0,
// integer arithmetic trap group
EXCEPTION_INTEGER_DIVIDE_BY_ZERO = 0x208,
// instruction memory trap group
EXCEPTION_I_CORRECTED_MEMORY_ERROR = 0x288,
EXCEPTION_I_UNCORRECTABLE_MEMORY_ERROR = 0x290,
EXCEPTION_I_ALIGNMENT_FAULT = 0x2a0,
EXCEPTION_I_PAGE_FAULT = 0x2a8,
EXCEPTION_I_EXECUTE_PROTECT_FAULT = 0x2b0,
// illegal operation trap group
EXCEPTION_ILLEGAL_OPERATION = 0x300,
EXCEPTION_PRIVILEGED_INSTRUCTION = 0x308,
// diagnostic trap group
EXCEPTION_TRACE = 0x380,
// supervisor calls (0x400-0x7f8)
EXCEPTION_SUPERVISOR_CALL_BASE = 0x400,
// prioritized interrupts (0x800-0xff8)
EXCEPTION_INTERRUPT_BASE = 0x800
};
#endif // MAME_CPU_CLIPPER_COMMON_H

View File

@ -7,7 +7,7 @@
*
* The first systems were built using the original C100 CLIPPER CPU, and used
* an additional Intel 80186 as an I/O processor, later moving to a C300 with
* 80386 IOP. Around 1989, the CLIPPER became fast enough to obviate the need
* 80386 IOP. Around 1990, the CLIPPER became fast enough to obviate the need
* for the separate I/O processor, and systems from that point used the main
* CPU for both compute and I/O, along with some custom ASICs.
*
@ -17,66 +17,77 @@
* Year Family Models CPU
* 1986 amethyst 32C/100/200 C100 (80186 IOP)
* 1988 topaz 300/3000/4000/5000 C300/C300Plus (80386 IOP)
* 1989 turquoise 2000 C300
* 1989 emerald 6000/6100/6200/6500/6600 C300/C300Plus (C4T in 6600?)
* 1991 sapphire 2400/6400 C4T
* 1992 sapphire 2500/2700/6700/6800/2800 C4I
* 1990 emerald 6000/6100/6200/6500 C300/C300Plus
* 1990 turquoise 2000 C300
* 1991 emerald? 6600 C4?
* 1992 sapphire 2400/6400 C4T
* 1993 sapphire 2500/2700/6700/6800 C4I
* 1994 sapphire 2800 C4I
*
* Individual models and some of their specific attributes include:
*
* Model Year CPU Clock Family
* 2000 1989 C300 turquoise
* 6000 1989 C300 emerald
* 2400 1991? C4T 40MHz? sapphire
* 6400 1991 C4T 40MHz sapphire
* 6600 C400 emerald (IOI, SRX bus?)
* 6700 1992 C400I 70MHz? sapphire
* 6800 1993 C400I 80MHz? sapphire
* 2500 1993? C400I 50MHz? sapphire
* 2700 1992 C400I 70MHz? sapphire
* 2800 1994 C400I 80MHz? sapphire
* Model Year CPU Performance Clock Family Bus
* 6000 1990 C300 10 MIPS 40MHz emerald SRX
* 6100 1990 14 MIPS emerald IOI?, 6105 has 5-slot chassis
* 6500 C300+ emerald IOI, QWIC bus?
* 6200 1990 C300+ 14 MIPS 60MHz emerald
* 1991 18 MIPS
* 2000 1990 C300 12.5 MIPS 50MHz? turquoise CBUS
* 6600 1991 C400 40 MIPS emerald? IOI, SRX bus?
* 2400 1992 C4T 36 MIPS/33 SPECmarks 40MHz? sapphire CBUS
* 6400 1992 C4T 36 MIPS/33 SPECmarks 40MHz sapphire SRX
* 2700 1993 C400I 40.1 SPECmark89 sapphire 2 CBUS
* 6700 1993 C400I 40.1 SPECmark89 sapphire 2 SRX
* 6800 1993 C400I 67.2 SPECmark89 sapphire 3 SRX
* 2500 1993 C400I 19.9 SPECint92 sapphire
* 2800 1994 C400I sapphire 3 CBUS?
*
* 6100 emerald (IOI)
* 6200 1989 C300Plus 60MHz emerald
* 6500 C300Plus emerald (IOI, QWIC bus?)
* IOI == I/O Interface (another type of bus?)
* Sapphire 2 w/CBUS supports RETRY (maybe bus retry?)
*
* With many exceptions, the general model numbering system is ABCD, where:
* With some exceptions, system models are numbered ABCD, where:
*
* A: case type (2=desktop, 6=tower)
* A: case type (2=desktop, 6=minicase)
* B: CPU type (0=C300, 4=C4T, 6=C400?, 7/8/5 = C400I)
* C: graphics type (0=none, 3/5=GT, 4/8 = EDGE)
* D: always 0?
* C: graphics type (0=none, 3/5=GT, 4=EDGE-1, 8 = EDGE-2)
* D: usually 0, 6xxx systems have 5, 7 and 9 options (backplane type?)
*
* Both the desktop and tower units supported an expansion bus with a variety
* Graphics type 3 is for GT graphics fitted to a 2xxx system, and type 5 when
* fitted to a 6xxx system. The latter is possibly also known as GTDB.
*
* Both the desktop and minicase units supported expansion slots with a variety
* of cards, although with different profiles and connectors between 2xxx and
* 6xxx systems. The bus is referred to as SR, SRX, SR Bus, CBUS and some
* combinations of these in various places, but all appears to be compatible or
* combinations of these in various places, but all appear to be compatible or
* identical, possibly with SRX being an enhanced version. The bus supported a
* range of add-in cards, ranging from expanded SCSI and serial controllers,
* to specialised scanning and plotting controllers, a VME bridge, and most
* importantly various single and dual-headed graphics boards.
*
* The InterPro graphics options included the GT range, generally fitted to the
* desktop systems, and EDGE graphics for the towers. Systems with no graphics
* were operated through a serial console on serial port 2, and were branded as
* InterServe rather than InterPro systems.
* desktops, and EDGE graphics for the 6xxx systems. Systems with no graphics
* were operated through a serial terminal on serial port 2, and were branded
* InterServe rather than InterPro.
*
* Model Year Performance
* GT 1990? 360k 2D vec/s (in a 2020)
* EDGE-1
* EDGE-2
* EDGE-1 8 planes + 1 highlight plane, double buffered (6040)
* EDGE-2 24 bit, 400k 2D vec/s, 350k 3D vec/s (6280)
* GT+ 760k 2D vec/s, 530k 3D vec/s (in a 2730)
* GTII 830k 2D vec/s, 640k 3D vec/s (in a 6750)
* 900k 2D vec/s, 700k 3D vec/s (in a 6850)
* EDGE II+ 50k Gouraud-shaded poly/s (in a 6780)
*
* GT graphics are also referred to in various places as Memory Mapped Graphics
* or MMG. EDGE stands for Extensible Display Geometry Engine.
*
* This emulation currently supports the Turquoise and Sapphire desktop systems (i.e. models
* 2000/2400/2500/2700/2800). Base GT graphics can be used with any of these models, or the
* graphics and keyboard removed and the systems used with a serial terminal instead.
*
* Key parts lists for the supported models are as follows.
*
* 2000 Turquoise (C300 @ 40MHz?, main board PCB962)
* 2000 Turquoise (C300 @ 50MHz?, main board PCB962)
*
* Ref Part Function
* U37 Intel 82072 Floppy drive controller
@ -103,16 +114,16 @@
* U34 Xilinix XC3020-50 Plotter control FPGA?
* U35 128 kB EPROM (MPRGW510B) Boot ROM
* U43? (MPRGM610P) Bitstream for XC3020?
* U44 Intel 82596SX Ethernet controller (20MHz)
* U67 Intel N28F010-200 128Kx8 flash memory (200ns)
* U44 Intel 82596SX-20 Ethernet controller
* U67 Intel N28F010-200 128Kx8 flash memory (Y226 0B03 0592)
* U68 CYID21603 TC150G89AF
* U71 LSI L1A6104 CICD 95801 Intergraph I/O gate array
* U76 Intel N28F010-200 128Kx8 flash memory (200ns)
* U76 Intel N28F010-200 128Kx8 flash memory (Y225 0B?? 27??)
* U81 NCR 53C94 SCSI controller
* U86 24.0 MHz crystal Clock source for 53C94?
* U87 4.9152 MHz crystal Clock source for 8530s?
* U88 20.0 MHz crystal Clock source for 82596?
* U91 Intel N82077AA Floppy drive controller
* U91 Intel N82077AA-1 Floppy drive controller
* U96 32.0 MHz crystal
* U97 40.0 MHz crystal
* U112? (MPRG4230A) node ID prom?
@ -129,23 +140,40 @@
* U34 Xilinix XC3020-70 Plotter control FPGA?
* U35 128 kB EPROM (MPRGZ530A) Boot ROM
* U43? (MPRGM610P) Bitstream for XC3020?
* U44 Intel 82596SX? Ethernet controller
* U44 Intel 82596SX-20 Ethernet controller
* U68 CYID21603 TC150G89AF
* U67 Intel N28F010 128Kx8 flash memory
* U67 Intel N28F010 128Kx8 flash memory (Y226 0C30 4291)
* U71 LSI L1A7374 CIDC094A3 Intergraph I/O gate array
* U76 Intel N28F010 128Kx8 flash memory
* U76 Intel N28F010 128Kx8 flash memory (Y225 0C30 4220)
* U81 NCR 53C94 SCSI controller
* U86 24.0 MHz crystal Clock source for 53C94?
* U86 24.0 MHz crystal Clock source for 82077
* U87 4.9152 MHz crystal Clock source for 8530s?
* U88 20.0 MHz crystal Clock source for 82596?
* U91 Intel N82077AA? Floppy drive controller
* U96 32.0 MHz crystal?
* U91 Intel N82077SL-1 Floppy drive controller
* U96 29.0 MHz crystal
* U97 40.0 MHz crystal
* U112? (MPRGZ260E) node ID prom?
* U113? Dallas DS12887 RTC and NVRAM
* U113 Dallas DS12887 RTC and NVRAM
* U117? diagnostic 7-segment LED?
* U118? ()
* U155 CYID212?4 TC140G54AF?
*
* CPU daughter-boards
* PCB824 Rev J - 2000 (also has label MPCBA5507)
* SMT082 (MSMT0820B, 36MHz?) - 6400 (SMT046 "6400 36-MHz Series System Board")
* SMT03? 2400/6400 - (MSMT03804 -> rev 2 cammu, goes with "6400 36-MHz Series System Board", MSMT0380A eco 3+ use rev 3 cammu)
* SMT019 (MSMT019 C4E CPU Assembly)
* SMT104 Rev A - 2700/6700 (aka MSMT1040A "C4I CPU", C4 CPU REV 3 + C4 FPU REV 3 + C4I CAMMU)
*
* PCB962 2000 System Board MPCB824 C300
* SMT046 6400 36-MHz Series System Board MSMT03804 rev 2 CAMMU/30MHz Kryptonite Rev 3 CAMMU/32MHz Kryptonite Rev 3 CAMMU/MSMT0820B(36MHz)
* SMT047 2400 Series System Board MSMT03804 rev 2 CAMMU/MSMT0380A eco 3+ Rev 3 CAMMU
* SMT098A 6400 32-MHz Sapphire System Board
* SMT098B 6400 32-MHz Sapphire System Board
* SMT127 6700 Series System Board MSMT1040A C4I: C4 CPU Rev 3 + C4 FPU Rev 3 + C4I CAMMU
* SMT128 2700 Series System Board MSMT1040A C4I: C4 CPU Rev 3 + C4 FPU Rev 3 + C4I CAMMU
* SMT144 6800 Series System Board
* SMT145 2800 Series System Board
*/
#include "emu.h"
@ -184,12 +212,6 @@ void interpro_state::machine_reset()
DRIVER_INIT_MEMBER(interpro_state, common)
{
}
DRIVER_INIT_MEMBER(turquoise_state, turquoise)
{
interpro_state::init_common();
// FIXME: not all memory sizes are reported properly using fdm "5 inqhw" and
// "optimum_memory" commands
@ -200,25 +222,7 @@ DRIVER_INIT_MEMBER(turquoise_state, turquoise)
// 256 = reports 256M, 32x8
// map the configured ram
m_d_cammu->space(0).install_ram(0, m_ram->mask(), m_ram->pointer());
m_i_cammu->space(0).install_ram(0, m_ram->mask(), m_ram->pointer());
}
DRIVER_INIT_MEMBER(sapphire_state, sapphire)
{
interpro_state::init_common();
// FIXME: not all memory sizes are reported properly using fdm "5 inqhw" and
// "optimum_memory" commands
// 16 = reports 16M, banks empty?
// 32 = reports 16M, banks empty?
// 64 = reports 128M, 16x8
// 128 = reports 128M, 16x8
// 256 = reports 256M, 32x8
// map the configured ram
m_mmu->space(0).install_ram(0, m_ram->mask(), m_ram->pointer());
m_maincpu->space(0).install_ram(0, m_ram->mask(), m_ram->pointer());
}
WRITE16_MEMBER(interpro_state::sreg_led_w)
@ -275,7 +279,7 @@ READ16_MEMBER(interpro_state::sreg_error_r)
return result;
}
READ32_MEMBER(interpro_state::unmapped_r)
READ32_MEMBER(sapphire_state::unmapped_r)
{
// check if non-existent memory errors are enabled
if (!machine().side_effects_disabled())
@ -291,7 +295,7 @@ READ32_MEMBER(interpro_state::unmapped_r)
return space.unmap();
}
WRITE32_MEMBER(interpro_state::unmapped_w)
WRITE32_MEMBER(sapphire_state::unmapped_w)
{
// check if non-existent memory errors are enabled
if (m_arbga->tctrl_r(space, offset, mem_mask) & interpro_arbga_device::TCTRL_ENNEM)
@ -319,23 +323,6 @@ READ8_MEMBER(interpro_state::nodeid_r)
return space.unmap();
}
// these maps connect the cpu virtual addresses to the mmu
ADDRESS_MAP_START(interpro_state::c300_insn_map)
AM_RANGE(0x00000000, 0xffffffff) AM_DEVREAD(INTERPRO_MMU_TAG "_i", cammu_device, read)
ADDRESS_MAP_END
ADDRESS_MAP_START(interpro_state::c300_data_map)
AM_RANGE(0x00000000, 0xffffffff) AM_DEVREADWRITE(INTERPRO_MMU_TAG "_d", cammu_device, read, write)
ADDRESS_MAP_END
ADDRESS_MAP_START(interpro_state::c400_insn_map)
AM_RANGE(0x00000000, 0xffffffff) AM_DEVREAD(INTERPRO_MMU_TAG, cammu_device, read)
ADDRESS_MAP_END
ADDRESS_MAP_START(interpro_state::c400_data_map)
AM_RANGE(0x00000000, 0xffffffff) AM_DEVREADWRITE(INTERPRO_MMU_TAG, cammu_device, read, write)
ADDRESS_MAP_END
ADDRESS_MAP_START(interpro_state::interpro_common_map)
// FIXME: don't know what this range is for
AM_RANGE(0x08000000, 0x08000fff) AM_NOP
@ -343,7 +330,6 @@ ADDRESS_MAP_START(interpro_state::interpro_common_map)
AM_RANGE(0x4f007e00, 0x4f007eff) AM_DEVICE(INTERPRO_SGA_TAG, interpro_sga_device, map)
AM_RANGE(0x7f000100, 0x7f00011f) AM_DEVICE8(INTERPRO_FDC_TAG, upd765_family_device, map, 0x000000ff)
AM_RANGE(0x7f000200, 0x7f0002ff) AM_DEVICE(INTERPRO_ARBGA_TAG, interpro_arbga_device, map)
AM_RANGE(0x7f000300, 0x7f000303) AM_READ16(sreg_error_r, 0x0000ffff)
AM_RANGE(0x7f000304, 0x7f000307) AM_READWRITE16(sreg_status_r, sreg_led_w, 0x0000ffff)
AM_RANGE(0x7f000308, 0x7f00030b) AM_READWRITE16(sreg_ctrl1_r, sreg_ctrl1_w, 0x0000ffff)
@ -356,25 +342,10 @@ ADDRESS_MAP_START(interpro_state::interpro_common_map)
;map(0x7f000500, 0x7f000503).lrw8("rtc_rw", [this](address_space &space, offs_t offset, u8 mem_mask){ return m_rtc->read(space, offset^1, mem_mask); }, [this](address_space &space, offs_t offset, u8 data, u8 mem_mask){ m_rtc->write(space, offset^1, data, mem_mask); }).umask32(0x000000ff);
AM_RANGE(0x7f000600, 0x7f000603) AM_DEVWRITE8(INTERPRO_RTC_TAG, mc146818_device, write, 0x000000ff)
AM_RANGE(0x7f000600, 0x7f00060f) AM_READ8(nodeid_r, 0xff)
// the system board id prom
AM_RANGE(0x7f000700, 0x7f00077f) AM_ROM AM_REGION(INTERPRO_IDPROM_TAG, 0)
// scsi registers have unusual address mapping
AM_RANGE(0x7f001000, 0x7f001003) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, tcounter_lo_r, tcount_lo_w, 0x0000ff00)
AM_RANGE(0x7f001100, 0x7f001103) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, tcounter_hi_r, tcount_hi_w, 0x0000ff00)
AM_RANGE(0x7f001200, 0x7f001203) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, fifo_r, fifo_w, 0x0000ff00)
AM_RANGE(0x7f001300, 0x7f001303) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, command_r, command_w, 0x0000ff00)
AM_RANGE(0x7f001400, 0x7f001403) AM_DEVREAD8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, status_r, 0xff00) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, bus_id_w, 0x0000ff00)
AM_RANGE(0x7f001500, 0x7f001503) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, istatus_r, timeout_w, 0x0000ff00)
AM_RANGE(0x7f001600, 0x7f001603) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, seq_step_r, sync_period_w, 0x0000ff00)
AM_RANGE(0x7f001700, 0x7f001703) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, fifo_flags_r, sync_offset_w, 0x0000ff00)
AM_RANGE(0x7f001800, 0x7f001803) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, conf_r, conf_w, 0x0000ff00)
AM_RANGE(0x7f001900, 0x7f001903) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, clock_w, 0x0000ff00)
AM_RANGE(0x7f001a00, 0x7f001a03) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, test_w, 0x0000ff00)
AM_RANGE(0x7f001b00, 0x7f001b03) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, conf2_r, conf2_w, 0x0000ff00)
AM_RANGE(0x7f0fff00, 0x7f0fffff) AM_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, map)
ADDRESS_MAP_END
@ -382,7 +353,24 @@ ADDRESS_MAP_START(turquoise_state::turquoise_base_map)
AM_IMPORT_FROM(interpro_common_map)
AM_RANGE(0x40000000, 0x4000003f) AM_DEVICE(INTERPRO_MCGA_TAG, interpro_mcga_device, map)
// scsi registers have unusual address mapping
AM_RANGE(0x7f000200, 0x7f000203) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, tcounter_lo_r, tcount_lo_w, 0x0000ff00)
AM_RANGE(0x7f000204, 0x7f000207) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, tcounter_hi_r, tcount_hi_w, 0x0000ff00)
AM_RANGE(0x7f000208, 0x7f00020b) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, fifo_r, fifo_w, 0x0000ff00)
AM_RANGE(0x7f00020c, 0x7f00020f) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, command_r, command_w, 0x0000ff00)
AM_RANGE(0x7f000210, 0x7f000213) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, status_r, bus_id_w, 0x0000ff00)
AM_RANGE(0x7f000214, 0x7f000217) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, istatus_r, timeout_w, 0x0000ff00)
AM_RANGE(0x7f000218, 0x7f00021b) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, seq_step_r, sync_period_w, 0x0000ff00)
AM_RANGE(0x7f00021c, 0x7f00021f) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, fifo_flags_r, sync_offset_w, 0x0000ff00)
AM_RANGE(0x7f000220, 0x7f000223) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, conf_r, conf_w, 0x0000ff00)
AM_RANGE(0x7f000224, 0x7f000227) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, clock_w, 0x0000ff00)
AM_RANGE(0x7f000228, 0x7f00022b) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, test_w, 0x0000ff00)
AM_RANGE(0x7f00022c, 0x7f00022f) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, conf2_r, conf2_w, 0x0000ff00)
AM_RANGE(0x7f000300, 0x7f000303) AM_WRITE8(sreg_error_w, 0x000000ff)
AM_RANGE(0x7f000600, 0x7f00067f) AM_ROM AM_REGION(INTERPRO_NODEID_TAG, 0)
ADDRESS_MAP_END
ADDRESS_MAP_START(turquoise_state::turquoise_main_map)
@ -396,6 +384,23 @@ ADDRESS_MAP_START(sapphire_state::sapphire_base_map)
AM_IMPORT_FROM(interpro_common_map)
AM_RANGE(0x40000000, 0x4000004f) AM_DEVICE(INTERPRO_MCGA_TAG, interpro_fmcc_device, map)
AM_RANGE(0x7f000200, 0x7f0002ff) AM_DEVICE(INTERPRO_ARBGA_TAG, interpro_arbga_device, map)
AM_RANGE(0x7f000600, 0x7f00060f) AM_READ8(nodeid_r, 0xff)
// scsi registers have unusual address mapping
AM_RANGE(0x7f001000, 0x7f001003) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, tcounter_lo_r, tcount_lo_w, 0x0000ff00)
AM_RANGE(0x7f001100, 0x7f001103) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, tcounter_hi_r, tcount_hi_w, 0x0000ff00)
AM_RANGE(0x7f001200, 0x7f001203) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, fifo_r, fifo_w, 0x0000ff00)
AM_RANGE(0x7f001300, 0x7f001303) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, command_r, command_w, 0x0000ff00)
AM_RANGE(0x7f001400, 0x7f001403) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, status_r, bus_id_w, 0x0000ff00)
AM_RANGE(0x7f001500, 0x7f001503) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, istatus_r, timeout_w, 0x0000ff00)
AM_RANGE(0x7f001600, 0x7f001603) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, seq_step_r, sync_period_w, 0x0000ff00)
AM_RANGE(0x7f001700, 0x7f001703) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, fifo_flags_r, sync_offset_w, 0x0000ff00)
AM_RANGE(0x7f001800, 0x7f001803) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, conf_r, conf_w, 0x0000ff00)
AM_RANGE(0x7f001900, 0x7f001903) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, clock_w, 0x0000ff00)
AM_RANGE(0x7f001a00, 0x7f001a03) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, test_w, 0x0000ff00)
AM_RANGE(0x7f001b00, 0x7f001b03) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, conf2_r, conf2_w, 0x0000ff00)
AM_RANGE(0x7f001c00, 0x7f001c03) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, conf3_w, 0x0000ff00)
AM_RANGE(0x7f001f00, 0x7f001f03) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, fifo_align_w, 0x0000ff00)
ADDRESS_MAP_END
@ -448,9 +453,8 @@ static SLOT_INTERFACE_START(interpro_floppies)
SLOT_INTERFACE("35hd", FLOPPY_35_HD)
SLOT_INTERFACE_END
MACHINE_CONFIG_START(interpro_state::interpro_serial1)
MCFG_SCC85C30_ADD(INTERPRO_SCC1_TAG, XTAL(4'915'200), 0, 0, 0, 0)
MACHINE_CONFIG_START(interpro_state::interpro_scc1)
MCFG_DEVICE_MODIFY(INTERPRO_SCC1_TAG)
MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(INTERPRO_SERIAL_PORT1_TAG, rs232_port_device, write_txd))
MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE(INTERPRO_SERIAL_PORT2_TAG, rs232_port_device, write_txd))
MCFG_Z80SCC_OUT_INT_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir11_w))
@ -468,8 +472,8 @@ MACHINE_CONFIG_START(interpro_state::interpro_serial1)
MCFG_RS232_CTS_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, ctsb_w))
MACHINE_CONFIG_END
MACHINE_CONFIG_START(interpro_state::interpro_serial2)
MCFG_SCC85C30_ADD(INTERPRO_SCC2_TAG, XTAL(4'915'200), 0, 0, 0, 0)
MACHINE_CONFIG_START(interpro_state::interpro_scc2)
MCFG_DEVICE_MODIFY(INTERPRO_SCC2_TAG)
MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(INTERPRO_KEYBOARD_PORT_TAG, interpro_keyboard_port_device, write_txd))
MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE(INTERPRO_SERIAL_PORT0_TAG, rs232_port_device, write_txd))
MCFG_Z80SCC_OUT_INT_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir11_w))
@ -542,9 +546,6 @@ MACHINE_CONFIG_START(interpro_state::interpro)
// floppy
// srx arbiter gate array
MCFG_DEVICE_ADD(INTERPRO_ARBGA_TAG, INTERPRO_ARBGA, 0)
// serial
// real-time clock/non-volatile memory
@ -557,8 +558,8 @@ MACHINE_CONFIG_START(interpro_state::interpro)
MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":0", interpro_scsi_devices, "harddisk", false)
MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":1", interpro_scsi_devices, nullptr, false)
MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":2", interpro_scsi_devices, nullptr, false)
MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":3", interpro_scsi_devices, "cdrom", false)
MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":4", interpro_scsi_devices, nullptr, false)
MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":3", interpro_scsi_devices, nullptr, false)
MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":4", interpro_scsi_devices, "cdrom", false)
MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":5", interpro_scsi_devices, nullptr, false)
MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":6", interpro_scsi_devices, nullptr, false)
@ -568,32 +569,29 @@ MACHINE_CONFIG_START(interpro_state::interpro)
// sr bus and slots
MCFG_DEVICE_ADD(INTERPRO_SRBUS_TAG, SR, 0)
MCFG_SR_OUT_IRQ0_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir6_w))
MCFG_SR_SLOT_ADD(INTERPRO_SRBUS_TAG, INTERPRO_SRBUS_TAG ":0", sr_cards, "mpcb963", false)
MCFG_SR_SLOT_ADD(INTERPRO_SRBUS_TAG, INTERPRO_SRBUS_TAG ":1", sr_cards, nullptr, false)
// system layout
MCFG_DEFAULT_LAYOUT(layout_interpro)
// software lists
MCFG_SOFTWARE_LIST_ADD("softlist", "interpro")
MACHINE_CONFIG_END
MACHINE_CONFIG_START(turquoise_state::turquoise)
interpro(config);
MCFG_CPU_ADD(INTERPRO_CPU_TAG, CLIPPER_C300, XTAL(12'500'000))
MCFG_CPU_PROGRAM_MAP(c300_insn_map)
MCFG_CPU_DATA_MAP(c300_data_map)
MCFG_DEVICE_ADDRESS_MAP(0, turquoise_main_map)
MCFG_DEVICE_ADDRESS_MAP(1, turquoise_io_map)
MCFG_DEVICE_ADDRESS_MAP(2, interpro_boot_map)
MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, acknowledge_interrupt)
MCFG_DEVICE_ADD(INTERPRO_MMU_TAG "_i", CAMMU_C3, 0)
MCFG_DEVICE_ADDRESS_MAP(0, turquoise_main_map)
MCFG_DEVICE_ADDRESS_MAP(1, turquoise_io_map)
MCFG_DEVICE_ADDRESS_MAP(2, interpro_boot_map)
MCFG_CAMMU_SSW_CB(DEVREAD32(INTERPRO_CPU_TAG, clipper_device, get_ssw))
MCFG_CAMMU_EXCEPTION_CB(DEVWRITE16(INTERPRO_CPU_TAG, clipper_device, set_exception))
MCFG_DEVICE_ADD(INTERPRO_MMU_TAG "_d", CAMMU_C3, 0)
MCFG_DEVICE_ADDRESS_MAP(0, turquoise_main_map)
MCFG_DEVICE_ADDRESS_MAP(1, turquoise_io_map)
MCFG_DEVICE_ADDRESS_MAP(2, interpro_boot_map)
MCFG_CAMMU_SSW_CB(DEVREAD32(INTERPRO_CPU_TAG, clipper_device, get_ssw))
MCFG_CAMMU_EXCEPTION_CB(DEVWRITE16(INTERPRO_CPU_TAG, clipper_device, set_exception))
MCFG_CAMMU_LINK(INTERPRO_MMU_TAG "_i")
@ -617,8 +615,10 @@ MACHINE_CONFIG_START(turquoise_state::turquoise)
MCFG_FLOPPY_DRIVE_SOUND(false)
// serial controllers and ports
interpro_serial1(config);
interpro_serial2(config);
MCFG_SCC85C30_ADD(INTERPRO_SCC1_TAG, XTAL(4'915'200), 0, 0, 0, 0)
interpro_scc1(config);
MCFG_SCC85C30_ADD(INTERPRO_SCC2_TAG, XTAL(4'915'200), 0, 0, 0, 0)
interpro_scc2(config);
// scsi controller
MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":7", turquoise_scsi_devices, INTERPRO_SCSI_ADAPTER_TAG, true)
@ -631,25 +631,23 @@ MACHINE_CONFIG_START(turquoise_state::turquoise)
// i/o gate array
MCFG_DEVICE_ADD(INTERPRO_IOGA_TAG, TURQUOISE_IOGA, 0)
MCFG_INTERPRO_IOGA_MEMORY(INTERPRO_MMU_TAG "_d", 0)
MCFG_INTERPRO_IOGA_MEMORY(INTERPRO_CPU_TAG, 0)
ioga(config);
MCFG_DEVICE_MODIFY(INTERPRO_SRBUS_TAG)
MCFG_SR_MEMORY(INTERPRO_MMU_TAG "_d", 0, 1)
MCFG_SR_MEMORY(INTERPRO_CPU_TAG, 0, 1)
MACHINE_CONFIG_END
MACHINE_CONFIG_START(sapphire_state::sapphire)
interpro(config);
MCFG_CPU_ADD(INTERPRO_CPU_TAG, CLIPPER_C400, XTAL(12'500'000))
MCFG_CPU_PROGRAM_MAP(c400_insn_map)
MCFG_CPU_DATA_MAP(c400_data_map)
MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, acknowledge_interrupt)
MCFG_DEVICE_ADD(INTERPRO_MMU_TAG, CAMMU_C4T, 0)
MCFG_DEVICE_ADDRESS_MAP(0, sapphire_main_map)
MCFG_DEVICE_ADDRESS_MAP(1, sapphire_io_map)
MCFG_DEVICE_ADDRESS_MAP(2, interpro_boot_map)
MCFG_CAMMU_SSW_CB(DEVREAD32(INTERPRO_CPU_TAG, clipper_device, get_ssw))
MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, acknowledge_interrupt)
// FIXME: 2400/6400 should be C4T cammu?
MCFG_DEVICE_ADD(INTERPRO_MMU_TAG, CAMMU_C4I, 0)
MCFG_CAMMU_EXCEPTION_CB(DEVWRITE16(INTERPRO_CPU_TAG, clipper_device, set_exception))
// memory control gate array
@ -665,22 +663,27 @@ MACHINE_CONFIG_START(sapphire_state::sapphire)
MCFG_FLOPPY_DRIVE_ADD("fdc:1", interpro_floppies, "35hd", interpro_state::floppy_formats)
MCFG_FLOPPY_DRIVE_SOUND(false)
// srx arbiter gate array
MCFG_DEVICE_ADD(INTERPRO_ARBGA_TAG, INTERPRO_ARBGA, 0)
// serial controllers and ports
interpro_serial1(config);
interpro_serial2(config);
MCFG_SCC85230_ADD(INTERPRO_SCC1_TAG, XTAL(4'915'200), 0, 0, 0, 0)
interpro_scc1(config);
MCFG_SCC85C30_ADD(INTERPRO_SCC2_TAG, XTAL(4'915'200), 0, 0, 0, 0)
interpro_scc2(config);
// scsi controller
MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":7", sapphire_scsi_devices, INTERPRO_SCSI_ADAPTER_TAG, true)
MCFG_DEVICE_CARD_MACHINE_CONFIG(INTERPRO_SCSI_ADAPTER_TAG, interpro_scsi_adapter)
// ethernet controller
MCFG_DEVICE_ADD(INTERPRO_ETH_TAG, I82596_LE32, XTAL(20'000'000))
MCFG_DEVICE_ADD(INTERPRO_ETH_TAG, I82596_LE16, XTAL(20'000'000))
MCFG_I82586_IRQ_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir12_w))
MCFG_DEVICE_ADDRESS_MAP(0, interpro_82596_map)
// i/o gate array
MCFG_DEVICE_ADD(INTERPRO_IOGA_TAG, SAPPHIRE_IOGA, 0)
MCFG_INTERPRO_IOGA_MEMORY(INTERPRO_MMU_TAG, 0)
MCFG_INTERPRO_IOGA_MEMORY(INTERPRO_CPU_TAG, 0)
ioga(config);
// flash memory
@ -689,42 +692,72 @@ MACHINE_CONFIG_START(sapphire_state::sapphire)
// sr bus address spaces
MCFG_DEVICE_MODIFY(INTERPRO_SRBUS_TAG)
MCFG_SR_MEMORY(INTERPRO_MMU_TAG, 0, 1)
MCFG_SR_MEMORY(INTERPRO_CPU_TAG, 0, 1)
MACHINE_CONFIG_END
MACHINE_CONFIG_START(turquoise_state::ip2000)
turquoise(config);
//MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG)
//MCFG_DEVICE_CLOCK(XTAL(40'000'000))
MCFG_SOFTWARE_LIST_FILTER("softlist", "2000")
MACHINE_CONFIG_END
MACHINE_CONFIG_START(sapphire_state::ip2400)
sapphire(config);
//MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG)
//MCFG_DEVICE_CLOCK(XTAL(40'000'000))
//MCFG_DEVICE_CLOCK(XTAL(50'000'000))
MCFG_DEVICE_MODIFY(INTERPRO_MMU_TAG)
MCFG_CAMMU_ID(cammu_c4i_device::CID_C4IR0)
MCFG_DEVICE_MODIFY(INTERPRO_SRBUS_TAG ":0")
MCFG_SLOT_DEFAULT_OPTION("mpcb070")
MCFG_SOFTWARE_LIST_FILTER("softlist", "2400")
MACHINE_CONFIG_END
MACHINE_CONFIG_START(sapphire_state::ip2500)
sapphire(config);
//MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG)
//MCFG_DEVICE_CLOCK(XTAL(50'000'000))
//MCFG_DEVICE_CLOCK(XTAL(?)
// FIXME: don't know which cammu revision
MCFG_DEVICE_MODIFY(INTERPRO_MMU_TAG)
MCFG_CAMMU_ID(cammu_c4i_device::CID_C4IR0)
MCFG_SOFTWARE_LIST_FILTER("softlist", "2500")
MACHINE_CONFIG_END
MACHINE_CONFIG_START(sapphire_state::ip2700)
sapphire(config);
//MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG)
//MCFG_DEVICE_CLOCK(XTAL_70MHz)
//MCFG_DEVICE_CLOCK(?)
MCFG_DEVICE_MODIFY(INTERPRO_MMU_TAG)
MCFG_CAMMU_ID(cammu_c4i_device::CID_C4IR2)
MCFG_SOFTWARE_LIST_FILTER("softlist", "2700")
MACHINE_CONFIG_END
MACHINE_CONFIG_START(sapphire_state::ip2800)
sapphire(config);
//MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG)
//MCFG_DEVICE_CLOCK(XTAL_80MHz)
//MCFG_DEVICE_CLOCK(?)
// FIXME: don't know which cammu revision
MCFG_DEVICE_MODIFY(INTERPRO_MMU_TAG)
MCFG_CAMMU_ID(cammu_c4i_device::CID_C4IR2)
MCFG_SOFTWARE_LIST_FILTER("softlist", "2800")
MACHINE_CONFIG_END
ROM_START(ip2000)
ROM_REGION(0x80, INTERPRO_NODEID_TAG, 0)
ROM_LOAD32_BYTE("nodeid.bin", 0x0, 0x20, CRC(a38397a6) SHA1(9f45fb932bbe231c95b3d5470dcd1fa1c846486f))
ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0)
ROM_LOAD32_BYTE("mpcb962a.bin", 0x0, 0x20, CRC(712f5ba9) SHA1(93ccdcb68be4038bb35b02cee612927ad4451190))
ROM_LOAD32_BYTE("mpcb962a.bin", 0x0, 0x20, CRC(e391342c) SHA1(02e03aad760b6651b8599c3a41c7c457983ee97d))
ROM_REGION(0x0040000, INTERPRO_EPROM_TAG, 0)
ROM_SYSTEM_BIOS(0, "ip2000", "InterPro 2000 EPROM")
@ -734,7 +767,7 @@ ROM_END
ROM_START(ip2400)
ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0)
ROM_LOAD32_BYTE("msmt047a.bin", 0x0, 0x20, CRC(3078d84d) SHA1(2876b8b8054bb7528680d259fea428db6f1712b4))
ROM_LOAD32_BYTE("msmt0470.bin", 0x0, 0x20, CRC(498c80df) SHA1(18a49732ac9d04b20a77747c1b946c2e88abb087))
ROM_REGION(0x0020000, INTERPRO_EPROM_TAG, 0)
ROM_SYSTEM_BIOS(0, "ip2400", "InterPro 2400 EPROM")
@ -749,7 +782,7 @@ ROM_END
ROM_START(ip2500)
ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0)
ROM_LOAD32_BYTE("msmt100a.bin", 0x0, 0x20, CRC(46647cdf) SHA1(581a3424a9b7028e619a7f03fa86ebdee3cf2494))
ROM_LOAD32_BYTE("msmt1000.bin", 0x0, 0x20, CRC(548046c0) SHA1(ce7646e868f3aa35642d7f9348f6b9e91693918e))
ROM_REGION(0x0020000, INTERPRO_EPROM_TAG, 0)
ROM_SYSTEM_BIOS(0, "ip2500", "InterPro 2500 EPROM")
@ -764,7 +797,7 @@ ROM_END
ROM_START(ip2700)
ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0)
ROM_LOAD32_BYTE("msmt128a.bin", 0x0, 0x20, CRC(6d8e68e8) SHA1(a649097df730c79b03bbf777b788f0721e072f03))
ROM_LOAD32_BYTE("msmt1280.bin", 0x0, 0x20, CRC(32d833af) SHA1(7225c5f5670fe49d86556a2cb453ae6fe09e3e19))
ROM_REGION(0x0020000, INTERPRO_EPROM_TAG, 0)
ROM_SYSTEM_BIOS(0, "ip2700", "InterPro 2700 EPROM")
@ -779,7 +812,7 @@ ROM_END
ROM_START(ip2800)
ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0)
ROM_LOAD32_BYTE("msmt145a.bin", 0x0, 0x20, CRC(e1c265e3) SHA1(105d646552d56c7af2f403aac1aa97b047b6a50e))
ROM_LOAD32_BYTE("msmt1450.bin", 0x0, 0x20, CRC(61c7a305) SHA1(efcd045cbdfda8df44eaad761b0ba99367973cd7))
ROM_REGION(0x0020000, INTERPRO_EPROM_TAG, 0)
ROM_SYSTEM_BIOS(0, "ip2800", "InterPro 2800 EPROM")
@ -793,8 +826,8 @@ ROM_START(ip2800)
ROM_END
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
COMP( 1989, ip2000, 0, 0, ip2000, interpro, turquoise_state, turquoise, "Intergraph", "InterPro 2000", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
COMP( 1991?, ip2400, 0, 0, ip2400, interpro, sapphire_state, sapphire, "Intergraph", "InterPro 2400", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
COMP( 1993?, ip2500, 0, 0, ip2500, interpro, sapphire_state, sapphire, "Intergraph", "InterPro 2500", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
COMP( 1992, ip2700, 0, 0, ip2700, interpro, sapphire_state, sapphire, "Intergraph", "InterPro 2700", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
COMP( 1994, ip2800, 0, 0, ip2800, interpro, sapphire_state, sapphire, "Intergraph", "InterPro 2800", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
COMP( 1990, ip2000, 0, 0, ip2000, interpro, turquoise_state, common, "Intergraph", "InterPro 2000", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
COMP( 1992, ip2400, 0, 0, ip2400, interpro, sapphire_state, common, "Intergraph", "InterPro 2400", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
COMP( 1993, ip2500, 0, 0, ip2500, interpro, sapphire_state, common, "Intergraph", "InterPro 2500", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
COMP( 1993, ip2700, 0, 0, ip2700, interpro, sapphire_state, common, "Intergraph", "InterPro 2700", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
COMP( 1994, ip2800, 0, 0, ip2800, interpro, sapphire_state, common, "Intergraph", "InterPro 2800", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)

View File

@ -33,9 +33,10 @@
#include "bus/interpro/keyboard/keyboard.h"
#include "formats/pc_dsk.h"
#include "softlist.h"
#define INTERPRO_CPU_TAG "cpu"
#define INTERPRO_MMU_TAG "mmu"
#define INTERPRO_MMU_TAG "cammu"
#define INTERPRO_MCGA_TAG "mcga"
#define INTERPRO_SGA_TAG "sga"
#define INTERPRO_FDC_TAG "fdc"
@ -53,6 +54,7 @@
#define INTERPRO_ETH_TAG "eth"
#define INTERPRO_IOGA_TAG "ioga"
#define INTERPRO_NODEID_TAG "nodeid"
#define INTERPRO_IDPROM_TAG "idprom"
#define INTERPRO_EPROM_TAG "eprom"
#define INTERPRO_FLASH_TAG "flash"
@ -69,12 +71,10 @@ public:
, m_mcga(*this, INTERPRO_MCGA_TAG)
, m_sga(*this, INTERPRO_SGA_TAG)
, m_fdc(*this, INTERPRO_FDC_TAG)
, m_arbga(*this, INTERPRO_ARBGA_TAG)
, m_scc1(*this, INTERPRO_SCC1_TAG)
, m_scc2(*this, INTERPRO_SCC2_TAG)
, m_rtc(*this, INTERPRO_RTC_TAG)
, m_scsibus(*this, INTERPRO_SCSI_TAG)
, m_scsi(*this, INTERPRO_SCSI_DEVICE_TAG)
, m_eth(*this, INTERPRO_ETH_TAG)
, m_ioga(*this, INTERPRO_IOGA_TAG)
{
@ -86,12 +86,10 @@ public:
required_device<interpro_mcga_device> m_mcga;
required_device<interpro_sga_device> m_sga;
required_device<upd765_family_device> m_fdc;
required_device<interpro_arbga_device> m_arbga;
required_device<z80scc_device> m_scc1;
required_device<z80scc_device> m_scc2;
required_device<mc146818_device> m_rtc;
required_device<nscsi_bus_device> m_scsibus;
required_device<ncr53c90a_device> m_scsi;
required_device<i82586_base_device> m_eth;
required_device<interpro_ioga_device> m_ioga;
@ -156,22 +154,16 @@ public:
DECLARE_READ8_MEMBER(nodeid_r);
DECLARE_READ32_MEMBER(unmapped_r);
DECLARE_WRITE32_MEMBER(unmapped_w);
DECLARE_FLOPPY_FORMATS(floppy_formats);
void ioga(machine_config &config);
void interpro_serial1(machine_config &config);
void interpro_serial2(machine_config &config);
void interpro_scc1(machine_config &config);
void interpro_scc2(machine_config &config);
void interpro(machine_config &config);
static void interpro_scsi_adapter(device_t *device);
void c300_data_map(address_map &map);
void c300_insn_map(address_map &map);
void c400_data_map(address_map &map);
void c400_insn_map(address_map &map);
void interpro_boot_map(address_map &map);
void interpro_common_map(address_map &map);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
@ -192,15 +184,16 @@ public:
: interpro_state(mconfig, type, tag)
, m_d_cammu(*this, INTERPRO_MMU_TAG "_d")
, m_i_cammu(*this, INTERPRO_MMU_TAG "_i")
, m_scsi(*this, INTERPRO_SCSI_DEVICE_TAG)
{
}
DECLARE_DRIVER_INIT(turquoise);
DECLARE_WRITE8_MEMBER(sreg_error_w) { m_sreg_error = data; }
required_device<cammu_c3_device> m_d_cammu;
required_device<cammu_c3_device> m_i_cammu;
required_device<ncr53c90a_device> m_scsi;
void turquoise(machine_config &config);
void ip2000(machine_config &config);
void interpro_82586_map(address_map &map);
@ -215,19 +208,23 @@ public:
sapphire_state(const machine_config &mconfig, device_type type, const char *tag)
: interpro_state(mconfig, type, tag)
, m_mmu(*this, INTERPRO_MMU_TAG)
, m_scsi(*this, INTERPRO_SCSI_DEVICE_TAG)
, m_arbga(*this, INTERPRO_ARBGA_TAG)
, m_flash_lo(*this, INTERPRO_FLASH_TAG "_lo")
, m_flash_hi(*this, INTERPRO_FLASH_TAG "_hi")
{
}
DECLARE_DRIVER_INIT(sapphire);
virtual DECLARE_WRITE16_MEMBER(sreg_ctrl2_w) override;
DECLARE_READ32_MEMBER(unmapped_r);
DECLARE_WRITE32_MEMBER(unmapped_w);
required_device<cammu_c4_device> m_mmu;
required_device<ncr53c94_device> m_scsi;
required_device<interpro_arbga_device> m_arbga;
required_device<intel_28f010_device> m_flash_lo;
required_device<intel_28f010_device> m_flash_hi;
void sapphire(machine_config &config);
void ip2500(machine_config &config);
void ip2400(machine_config &config);

View File

@ -23,7 +23,6 @@
*
* TODO
* - fault register values
* - alignment faults
* - c3 protection faults
* - hard-wired and dynamic tlb
* - cache
@ -112,18 +111,17 @@ DEFINE_DEVICE_TYPE(CAMMU_C4I, cammu_c4i_device, "c4i", "C4I CAMMU")
DEFINE_DEVICE_TYPE(CAMMU_C3, cammu_c3_device, "c3", "C1/C3 CAMMU")
cammu_c4t_device::cammu_c4t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: cammu_c4_device(mconfig, CAMMU_C4T, tag, owner, clock, CID_C4T)
: cammu_c4_device(mconfig, CAMMU_C4T, tag, owner, clock)
{
}
cammu_c4i_device::cammu_c4i_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: cammu_c4_device(mconfig, CAMMU_C4I, tag, owner, clock, CID_C4I)
: cammu_c4_device(mconfig, CAMMU_C4I, tag, owner, clock)
{
}
cammu_c4_device::cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 cammu_id)
cammu_c4_device::cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: cammu_device(mconfig, type, tag, owner, clock)
, m_control(cammu_id)
{
}
@ -136,42 +134,13 @@ cammu_c3_device::cammu_c3_device(const machine_config &mconfig, const char *tag,
cammu_device::cammu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, device_memory_interface(mconfig, *this)
, m_main_space_config("main", ENDIANNESS_LITTLE, 32, 32, 0)
, m_io_space_config("io", ENDIANNESS_LITTLE, 32, 32, 0)
, m_boot_space_config("boot", ENDIANNESS_LITTLE, 32, 32, 0)
, m_main_space(nullptr)
, m_io_space(nullptr)
, m_boot_space(nullptr)
, m_ssw_func(*this)
, m_exception_func(*this)
{
}
device_memory_interface::space_config_vector cammu_device::memory_space_config() const
{
return space_config_vector {
std::make_pair(0, &m_main_space_config),
std::make_pair(1, &m_io_space_config),
std::make_pair(2, &m_boot_space_config)
};
}
void cammu_c3_device::static_add_linked(device_t &device, const char *const tag)
{
cammu_c3_device &parent = downcast<cammu_c3_device &>(device);
parent.m_linked.push_back(downcast<cammu_c3_device *>(parent.siblingdevice(tag)));
}
void cammu_device::device_start()
{
m_ssw_func.resolve();
m_exception_func.resolve();
m_main_space = &space(0);
m_io_space = &space(1);
m_boot_space = &space(2);
}
void cammu_device::device_reset()
@ -246,238 +215,168 @@ void cammu_c3_device::device_reset()
m_reset = 0;
}
READ32_MEMBER(cammu_device::read)
void cammu_device::set_spaces(std::vector<address_space *> spaces)
{
const u32 virtual_address = (offset << 2) | (
(mem_mask & 0x00ffffff) == 0 ? 0x3 :
(mem_mask & 0x0000ffff) == 0 ? 0x2 :
(mem_mask & 0x000000ff) == 0 ? 0x1 : 0x0);
offs_t physical_address;
assert_always(spaces.size() == 8, "exactly 8 address space pointers are required");
LOGMASKED(LOG_ACCESS, "%s read address 0x%08x mem_mask 0x%08x (%s)\n",
space.name(), virtual_address, mem_mask, machine().describe_context());
address_space *physical_space = translate_address(virtual_address, space.spacenum() == AS_PROGRAM ? ACCESS_X : ACCESS_R, &physical_address);
if (physical_space != nullptr)
return physical_space->read_dword(physical_address, mem_mask);
else
return space.unmap();
for (int i = 0; i < spaces.size(); i++)
m_space[i] = spaces[i];
}
WRITE32_MEMBER(cammu_device::write)
cammu_device::translated_t cammu_device::translate_address(const u32 ssw, const u32 virtual_address, const access_size size, const access_type mode)
{
const u32 virtual_address = (offset << 2) | (
(mem_mask & 0x00ffffff) == 0 ? 0x3 :
(mem_mask & 0x0000ffff) == 0 ? 0x2 :
(mem_mask & 0x000000ff) == 0 ? 0x1 : 0x0);
offs_t physical_address;
// get effective user/supervisor mode
const bool user = mode == EXECUTE ? ssw & SSW_U : ssw & (SSW_U | SSW_UU);
LOGMASKED(LOG_ACCESS, "%s write address 0x%08x data 0x%08x mem_mask 0x%08x (%s)\n",
space.name(), virtual_address, data, mem_mask, machine().describe_context());
// check for alignment faults
if (get_alignment() && !machine().side_effects_disabled())
{
if ((mode == EXECUTE && (virtual_address & 0x1)) || (mode != EXECUTE && virtual_address & (size - 1)))
{
set_fault_address(virtual_address);
m_exception_func(mode == EXECUTE ? EXCEPTION_I_ALIGNMENT_FAULT : EXCEPTION_D_ALIGNMENT_FAULT);
address_space *physical_space = translate_address(virtual_address, ACCESS_W, &physical_address);
if (physical_space != nullptr)
physical_space->write_dword(physical_address, data, mem_mask);
}
address_space *cammu_device::translate_address(const offs_t virtual_address, const access_t mode, offs_t *physical_address)
{
// get ssw and user/supervisor mode
const u32 ssw = m_ssw_func();
const bool user = mode == ACCESS_X ? ssw & SSW_U : ssw & (SSW_U | SSW_UU);
// TODO: check for alignment faults
return { nullptr, 0 };
}
}
// in supervisor mode, the first 8 pages are always mapped via the hard-wired tlb
if (!user && (virtual_address & ~0x7fff) == 0)
{
switch (virtual_address & 0x7000)
{
case 0x0000:
case 0x1000:
case 0x2000:
case 0x3000:
// pages 0-3: main space pages 0-3
*physical_address = virtual_address & 0x3fff;
return m_main_space;
case 0x0000: return { m_space[ST1], virtual_address & 0x3fff };
case 0x1000: return { m_space[ST2], virtual_address & 0x3fff };
case 0x2000: return { m_space[ST3], virtual_address & 0x3fff };
case 0x3000: return { m_space[ST3], virtual_address & 0x3fff };
case 0x4000:
case 0x5000:
// pages 4-5: i/o space pages 0-1
*physical_address = virtual_address & 0x1fff;
return m_io_space;
case 0x4000: return { m_space[ST4], virtual_address & 0x1fff };
case 0x5000: return { m_space[ST4], virtual_address & 0x1fff };
case 0x6000:
case 0x7000:
// pages 6-7: boot space pages 0-1
*physical_address = virtual_address & 0x1fff;
return m_boot_space;
case 0x6000: return { m_space[ST5], virtual_address & 0x1fff };
case 0x7000: return { m_space[ST5], virtual_address & 0x1fff };
}
}
// if not in mapped mode, use unmapped system tag
if ((ssw & SSW_M) == 0)
{
*physical_address = virtual_address;
return get_ust_space();
}
return { m_space[get_ust_space()], virtual_address };
// get the page table entry
const u32 pte = get_pte(virtual_address, user);
pte_t pte = get_pte(virtual_address, user);
// check for page faults
if (pte & PTE_F)
if (pte.entry & PTE_F)
{
if (!machine().side_effects_disabled())
{
LOG("%s page fault address 0x%08x ssw 0x%08x pte 0x%08x (%s)\n",
mode == ACCESS_X ? "instruction" : "data",
virtual_address, ssw, pte, machine().describe_context());
mode == EXECUTE ? "instruction" : "data",
virtual_address, ssw, pte.entry, machine().describe_context());
set_fault_address(virtual_address);
m_exception_func(mode == ACCESS_X ? EXCEPTION_I_PAGE_FAULT : EXCEPTION_D_PAGE_FAULT);
m_exception_func(mode == EXECUTE ? EXCEPTION_I_PAGE_FAULT : EXCEPTION_D_PAGE_FAULT);
}
return nullptr;
return { nullptr, 0 };
}
// check for protection level faults
if (!machine().side_effects_disabled() && !get_access(mode, pte, ssw))
if (!machine().side_effects_disabled() && !get_access(mode, pte.entry, ssw))
{
LOG("%s protection fault address 0x%08x ssw 0x%08x pte 0x%08x (%s)\n",
mode == ACCESS_X ? "execute" : mode == ACCESS_R ? "read" : "write",
virtual_address, ssw, pte, machine().describe_context());
mode == EXECUTE ? "execute" : mode == READ ? "read" : "write",
virtual_address, ssw, pte.entry, machine().describe_context());
set_fault_address(virtual_address);
m_exception_func(
mode == ACCESS_X ? EXCEPTION_I_EXECUTE_PROTECT_FAULT :
mode == ACCESS_R ? EXCEPTION_D_READ_PROTECT_FAULT :
mode == EXECUTE ? EXCEPTION_I_EXECUTE_PROTECT_FAULT :
mode == READ ? EXCEPTION_D_READ_PROTECT_FAULT :
EXCEPTION_D_WRITE_PROTECT_FAULT);
return nullptr;
return { nullptr, 0 };
}
// set pte referenced and dirty flags
if (mode & WRITE && !(pte.entry & PTE_D))
m_space[ST0]->write_dword(pte.address, pte.entry | PTE_D | PTE_R);
else if (!(pte.entry & PTE_R))
m_space[ST0]->write_dword(pte.address, pte.entry | PTE_R);
// translate the address
*physical_address = (pte & ~CAMMU_PAGE_MASK) | (virtual_address & CAMMU_PAGE_MASK);
LOGMASKED(LOG_DTU, "%s address translated 0x%08x\n", mode == ACCESS_X ? "instruction" : "data", *physical_address);
LOGMASKED(LOG_DTU, "%s address translated 0x%08x\n", mode == EXECUTE ? "instruction" : "data",
(pte.entry & ~CAMMU_PAGE_MASK) | (virtual_address & CAMMU_PAGE_MASK));
// return the physical space based on the system tag
switch (pte & PTE_ST)
{
case ST_0:
case ST_1:
case ST_2:
case ST_3:
// main memory space
return m_main_space;
case ST_4:
// i/o space
return m_io_space;
case ST_5:
// boot space
return m_boot_space;
case ST_6:
// cache purge
case ST_7:
// main memory, slave mode
if (!machine().side_effects_disabled())
fatalerror("%s page table entry system tag %d not supported\n",
mode == ACCESS_X ? "instruction" : "data", (pte & PTE_ST) >> 9);
break;
}
return nullptr;
// return the system tag and translated address
return { m_space[system_tag_t((pte.entry & PTE_ST) >> PTE_ST_SHIFT)], (pte.entry & ~CAMMU_PAGE_MASK) | (virtual_address & CAMMU_PAGE_MASK) };
}
// return the page table entry for a given virtual address
u32 cammu_device::get_pte(const u32 va, const bool user)
cammu_device::pte_t cammu_device::get_pte(const u32 va, const bool user)
{
const u32 tlb_index = user ? 1 : 0;
if ((va & ~CAMMU_PAGE_MASK) != m_tlb[tlb_index].va)
{
// get page table directory origin from user or supervisor pdo register
const u32 pdo = get_pdo(user);
// get page table directory origin from user or supervisor pdo register
const u32 pdo = get_pdo(user);
// get page table directory index from top 12 bits of virtual address
const u32 ptdi = (va & VA_PTDI) >> 20;
// get page table directory index from top 12 bits of virtual address
const u32 ptdi = (va & VA_PTDI) >> 20;
// fetch page table directory entry
const u32 ptde = m_main_space->read_dword(pdo | ptdi);
// fetch page table directory entry
const u32 ptde = m_space[ST0]->read_dword(pdo | ptdi);
LOGMASKED(LOG_DTU, "get_pte pdo 0x%08x ptdi 0x%08x ptde 0x%08x\n", pdo, ptdi, ptde);
LOGMASKED(LOG_DTU, "get_pte pdo 0x%08x ptdi 0x%08x ptde 0x%08x\n", pdo, ptdi, ptde);
// check for page table directory entry fault
if (ptde & PTDE_F)
return PTE_F;
// check for page table directory entry fault
if (ptde & PTDE_F)
return { PTE_F, pdo | ptdi };
// get the page table origin from the page table directory entry
const u32 pto = ptde & PTDE_PTO;
// get the page table origin from the page table directory entry
const u32 pto = ptde & PTDE_PTO;
// get the page table index from the middle 12 bits of the virtual address
const u32 pti = (va & VA_PTI) >> 10;
// get the page table index from the middle 12 bits of the virtual address
const u32 pti = (va & VA_PTI) >> 10;
// fetch page table entry
const u32 pte = m_main_space->read_dword(pto | pti);
// fetch page table entry
pte_t pte = { m_space[ST0]->read_dword(pto | pti), pto | pti };
LOGMASKED(LOG_DTU, "get_pte pto 0x%08x pti 0x%08x pte 0x%08x\n", pto, pti, pte);
LOGMASKED(LOG_DTU, "get_pte pto 0x%08x pti 0x%08x pte 0x%08x\n", pto, pti, pte.entry);
// check for page table entry fault
if (pte & PTE_F)
return PTE_F;
// check for page table entry fault
if (!(pte.entry & PTE_F))
LOGMASKED(LOG_DTU, "get_pte address 0x%08x pte 0x%08x (%s)\n", va, pte.entry, machine().describe_context());
// add the pte to the tlb
m_tlb[tlb_index].va = va & ~CAMMU_PAGE_MASK;
m_tlb[tlb_index].pte = pte;
LOGMASKED(LOG_DTU, "get_pte address 0x%08x pte 0x%08x (%s)\n", va, pte, machine().describe_context());
}
return m_tlb[tlb_index].pte;
return pte;
}
address_space *cammu_c4i_device::get_ust_space() const
{
switch (m_control & CNTL_UMM)
{
case UMM_MM: return m_main_space;
case UMM_MMRIO: return m_main_space; // FIXME: what determines main or i/o?
case UMM_IO: return m_io_space;
}
return m_main_space;
}
bool cammu_c4_device::get_access(const access_t mode, const u32 pte, const u32 ssw) const
bool cammu_c4_device::get_access(const access_type mode, const u32 pte, const u32 ssw) const
{
switch (mode)
{
case ACCESS_R: return pte & 0x20;
case ACCESS_W: return pte & 0x10;
case ACCESS_X: return pte & 0x08;
case READ: return pte & 0x20;
case WRITE: return pte & 0x10;
case RMW: return (pte & 0x30) == 0x30;
case EXECUTE: return pte & 0x08;
}
return false;
}
bool cammu_c3_device::get_access(const access_t mode, const u32 pte, const u32 ssw) const
bool cammu_c3_device::get_access(const access_type mode, const u32 pte, const u32 ssw) const
{
// FIXME: logic is not correct yet
return true;
const u8 column = (mode == ACCESS_X ? i_cammu_column : d_cammu_column)[(ssw & SSW_PL) >> 9];
const u8 column = (mode == EXECUTE ? i_cammu_column : d_cammu_column)[(ssw & SSW_PL) >> 9];
const u8 access = cammu_matrix[column][(pte & PTE_PL) >> 3];
switch (mode)
{
case ACCESS_R: return access & R;
case ACCESS_W: return access & W;
case ACCESS_X: return access & E;
case READ: return access & R;
case WRITE: return access & W;
case RMW: return (access & (R | W)) == (R | W);
case EXECUTE: return access & E;
}
return false;
@ -494,5 +393,3 @@ const cammu_c3_device::c3_access_t cammu_c3_device::cammu_matrix[][16] =
{ N, N, RW, RW, RW, R, R, RWE, N, N, RE, RE, N, RE, N, N },
{ N, N, N, RW, R, R, R, RWE, N, N, N, RE, RE, N, RE, N }
};

View File

@ -6,53 +6,25 @@
#pragma once
#define MCFG_CAMMU_SSW_CB(_sswcb) \
devcb = &downcast<cammu_device &>(*device).set_ssw_callback(DEVCB_##_sswcb);
#include "cpu/clipper/common.h"
#define MCFG_CAMMU_ID(_id) \
downcast<cammu_c4_device &>(*device).set_cammu_id(_id);
#define MCFG_CAMMU_EXCEPTION_CB(_exceptioncb) \
devcb = &downcast<cammu_device &>(*device).set_exception_callback(DEVCB_##_exceptioncb);
#define MCFG_CAMMU_LINK(_tag) \
cammu_c3_device::static_add_linked(*device, _tag);
downcast<cammu_c3_device &>(*device).add_linked(_tag);
class cammu_device : public device_t, public device_memory_interface
class cammu_device : public device_t
{
public:
template <class Object> devcb_base &set_ssw_callback(Object &&cb) { return m_ssw_func.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_exception_callback(Object &&cb) { return m_exception_func.set_callback(std::forward<Object>(cb)); }
static const u32 CAMMU_PAGE_SIZE = 0x1000;
static const u32 CAMMU_PAGE_MASK = (CAMMU_PAGE_SIZE - 1);
enum ssw_mask : u32
{
SSW_M = 0x04000000, // mapped mode
SSW_KU = 0x08000000, // user protect key
SSW_UU = 0x10000000, // user data mode
SSW_K = 0x20000000, // protect key
SSW_U = 0x40000000, // user mode
SSW_PL = 0x78000000 // protection level relevant bits
};
enum exception_vectors : u16
{
// data memory trap group
EXCEPTION_D_CORRECTED_MEMORY_ERROR = 0x108,
EXCEPTION_D_UNCORRECTABLE_MEMORY_ERROR = 0x110,
EXCEPTION_D_ALIGNMENT_FAULT = 0x120,
EXCEPTION_D_PAGE_FAULT = 0x128,
EXCEPTION_D_READ_PROTECT_FAULT = 0x130,
EXCEPTION_D_WRITE_PROTECT_FAULT = 0x138,
// instruction memory trap group
EXCEPTION_I_CORRECTED_MEMORY_ERROR = 0x288,
EXCEPTION_I_UNCORRECTABLE_MEMORY_ERROR = 0x290,
EXCEPTION_I_ALIGNMENT_FAULT = 0x2a0,
EXCEPTION_I_PAGE_FAULT = 0x2a8,
EXCEPTION_I_EXECUTE_PROTECT_FAULT = 0x2b0,
};
enum pdo_mask : u32
{
PDO_MASK = 0xfffff000
@ -79,17 +51,7 @@ public:
PTE_LOCK = 0x00000100 // page lock (software)
};
enum pte_st_mask : u32
{
ST_0 = 0x00000000, // private, write-through, main memory space
ST_1 = 0x00000200, // shared, write-through, main memory space
ST_2 = 0x00000400, // private, copy-back, main memory space
ST_3 = 0x00000600, // noncacheable, main memory space
ST_4 = 0x00000800, // noncacheable, i/o space
ST_5 = 0x00000a00, // noncacheable, boot space
ST_6 = 0x00000c00, // cache purge
ST_7 = 0x00000e00 // slave i/o
};
static const int PTE_ST_SHIFT = 9;
enum va_mask : u32
{
@ -98,10 +60,100 @@ public:
VA_PTDI = 0xffc00000 // page table directory index
};
enum system_tag_t : u8
{
ST0 = 0, // private, write-through, main memory space
ST1 = 1, // shared, write-through, main memory space
ST2 = 2, // private, copy-back, main memory space
ST3 = 3, // noncacheable, main memory space
ST4 = 4, // noncacheable, i/o space
ST5 = 5, // noncacheable, boot space
ST6 = 6, // cache purge
ST7 = 7 // slave i/o
};
virtual void map(address_map &map) = 0;
DECLARE_READ32_MEMBER(read);
DECLARE_WRITE32_MEMBER(write);
void set_spaces(std::vector<address_space *> spaces);
template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> load(const u32 ssw, const u32 address, U &&apply)
{
translated_t t = translate_address(ssw, address, access_size(sizeof(T)), READ);
if (t.space != nullptr)
{
switch (sizeof(T))
{
case 1: apply(T(t.space->read_byte(t.address))); break;
case 2: apply(T(t.space->read_word(t.address))); break;
case 4: apply(T(t.space->read_dword(t.address))); break;
case 8: apply(T(t.space->read_qword(t.address))); break;
default: fatalerror("unhandled load size %d\n", access_size(sizeof(T)));
}
return true;
}
else
return false;
}
template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, bool> store(const u32 ssw, const u32 address, U data)
{
translated_t t = translate_address(ssw, address, access_size(sizeof(T)), WRITE);
if (t.space != nullptr)
{
switch (sizeof(T))
{
case 1: t.space->write_byte(t.address, T(data)); break;
case 2: t.space->write_word(t.address, T(data)); break;
case 4: t.space->write_dword(t.address, T(data)); break;
case 8: t.space->write_qword(t.address, T(data)); break;
default: fatalerror("unhandled store size %d\n", access_size(sizeof(T)));
}
return true;
}
else
return false;
}
template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<T(T)>>::value, bool> modify(const u32 ssw, const u32 address, U &&apply)
{
translated_t t = translate_address(ssw, address, access_size(sizeof(T)), RMW);
if (t.space != nullptr)
{
switch (sizeof(T))
{
case 4: t.space->write_dword(t.address, apply(T(t.space->read_dword(t.address)))); break;
default: fatalerror("unhandled modify size %d\n", access_size(sizeof(T)));
}
return true;
}
else
return false;
}
template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> fetch(const u32 ssw, const u32 address, U &&apply)
{
translated_t t = translate_address(ssw, address, access_size(sizeof(T)), EXECUTE);
if (t.space != nullptr)
{
switch (sizeof(T))
{
case 2: apply(T(t.space->read_word(t.address))); break;
case 4: apply(T(t.space->read_dword_unaligned(t.address))); break;
default: fatalerror("unhandled fetch size %d\n", access_size(sizeof(T)));
}
return true;
}
else
return false;
}
protected:
cammu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
@ -110,52 +162,55 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
// device_memory_interface overrides
virtual space_config_vector memory_space_config() const override;
//virtual bool memory_translate(int spacenum, int intention, offs_t &address) override;
enum access_t
enum access_size : u8
{
ACCESS_R = 1,
ACCESS_W = 2,
ACCESS_X = 3
BYTE = 1,
WORD = 2,
DWORD = 4,
QWORD = 8
};
address_space *translate_address(const offs_t virtual_address, const access_t mode, offs_t *physical_address);
enum access_type : u8
{
READ = 1,
WRITE = 2,
RMW = 3,
EXECUTE = 4
};
u32 get_pte(const u32 va, const bool user);
private:
// address translation
struct translated_t
{
address_space *const space;
const u32 address;
};
translated_t translate_address(const u32 ssw, const u32 virtual_address, const access_size size, const access_type mode);
virtual bool get_access(const access_t mode, const u32 pte, const u32 ssw) const = 0;
struct pte_t
{
const u32 entry;
const u32 address;
};
pte_t get_pte(const u32 va, const bool user);
// helpers
virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const = 0;
virtual bool get_alignment() const = 0;
virtual u32 get_pdo(const bool user) const = 0;
virtual address_space *get_ust_space() const = 0;
virtual system_tag_t get_ust_space() const = 0;
virtual void set_fault_address(const u32 va) = 0;
address_space_config m_main_space_config;
address_space_config m_io_space_config;
address_space_config m_boot_space_config;
address_space *m_main_space;
address_space *m_io_space;
address_space *m_boot_space;
devcb_read32 m_ssw_func;
devcb_write16 m_exception_func;
struct
{
u32 va;
u32 pte;
}
m_tlb[2];
private:
address_space *m_space[8];
};
class cammu_c4_device : public cammu_device
{
public:
void set_cammu_id(const u32 cammu_id) { m_control = cammu_id; }
DECLARE_READ32_MEMBER(s_pdo_r) { return m_s_pdo; }
DECLARE_WRITE32_MEMBER(s_pdo_w) { m_s_pdo = ((m_s_pdo & ~mem_mask) | (data & mem_mask)) & PDO_MASK; }
DECLARE_READ32_MEMBER(u_pdo_r) { return m_u_pdo; }
@ -180,11 +235,11 @@ public:
DECLARE_WRITE32_MEMBER(fault_data_2_hi_w) { m_fault_data_2_hi = data; }
protected:
cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 cammu_id);
cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
virtual void device_start() override;
virtual bool get_access(const access_t mode, const u32 pte, const u32 ssw) const override;
virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const override;
virtual u32 get_pdo(const bool user) const override { return user ? m_u_pdo : m_s_pdo; }
virtual void set_fault_address(const u32 va) override { m_fault_address_1 = va; }
@ -274,7 +329,7 @@ protected:
virtual void device_start() override;
virtual bool get_alignment() const override { return (m_control & CNTL_ATD) == 0; }
virtual address_space *get_ust_space() const override { return (m_control & CNTL_IOTS) ? m_io_space : m_main_space; }
virtual system_tag_t get_ust_space() const override { return system_tag_t((m_control & (CNTL_IOTS | CNTL_UST)) >> 4); }
private:
u32 m_ram_line;
@ -333,9 +388,11 @@ public:
CRR_OFF = 0x00700000, // refresh off
};
// c4i cammu identification (rev 2 and rev 3 known to have existed)
enum control_cid_mask : u32
{
CID_C4I = 0x02000000 // c4i cammu identification
CID_C4IR0 = 0x00000000,
CID_C4IR2 = 0x02000000
};
virtual DECLARE_READ32_MEMBER(control_r) override { return m_control; }
@ -374,7 +431,8 @@ protected:
virtual void device_start() override;
virtual bool get_alignment() const override { return (m_control & CNTL_ATD) == 0; }
virtual address_space *get_ust_space() const override;
// FIXME: don't really know how unmapped mode works on c4i
virtual system_tag_t get_ust_space() const override { return (m_control & UMM_IO) ? ST4 : ST3; }
private:
u32 m_reset;
@ -391,11 +449,11 @@ class cammu_c3_device : public cammu_device
public:
cammu_c3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
static void static_add_linked(device_t &device, const char *const tag);
virtual void map(address_map &map) override;
virtual void map_global(address_map &map);
void add_linked(const char *const tag) { m_linked.push_back(downcast<cammu_c3_device *>(siblingdevice(tag))); }
enum control_mask : u32
{
CNTL_EP = 0x00000001, // enable prefetch
@ -443,10 +501,10 @@ protected:
virtual void device_reset() override;
virtual void device_start() override;
virtual bool get_access(const access_t mode, const u32 pte, const u32 ssw) const override;
virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const override;
virtual bool get_alignment() const override { return m_control & CNTL_ATE; }
virtual u32 get_pdo(const bool user) const override { return user ? m_u_pdo : m_s_pdo; }
virtual address_space *get_ust_space() const override { return m_main_space; }
virtual system_tag_t get_ust_space() const override { return system_tag_t((m_control & CNTL_UST) >> 4); }
virtual void set_fault_address(const u32 va) override { m_fault = va; }

View File

@ -124,6 +124,7 @@ ADDRESS_MAP_START(interpro_ioga_device::map)
AM_RANGE(0x94, 0x97) AM_READ(error_address_r)
AM_RANGE(0x98, 0x9b) AM_READ(error_businfo_r)
AM_RANGE(0x9c, 0x9f) AM_READWRITE16(arbctl_r, arbctl_w, 0x0000ffff)
//AM_RANGE(0x9c, 0x9f) AM_READWRITE16(?, ?, 0xffff0000) // ip2000 boot code writes 0x7f18
AM_RANGE(0xa0, 0xa3) AM_READWRITE(timer2_count_r, timer2_count_w)
AM_RANGE(0xa4, 0xa7) AM_READWRITE(timer2_value_r, timer2_value_w)
AM_RANGE(0xa8, 0xab) AM_READWRITE(timer3_r, timer3_w)
@ -507,48 +508,20 @@ WRITE16_MEMBER(interpro_ioga_device::icr_w)
LOGIRQ(offset, "irq: interrupt vector %d = 0x%04x (%s)\n", offset, data, machine().describe_context());
if (data & IRQ_PENDING)
{
// record interrupt pending forced
m_hwint_forced |= 1 << offset;
// store all bits except pending
m_hwicr[offset] = (m_hwicr[offset] & IRQ_PENDING) | (data & ~IRQ_PENDING);
// store all bits except pending
m_hwicr[offset] = (m_hwicr[offset] & IRQ_PENDING) | (data & ~IRQ_PENDING);
// FIXME: is it possible trigger a pending interrupt by unmasking it here?
}
else if (m_hwint_forced & (1 << offset))
{
// interrupt is being forced
m_hwicr[offset] = data;
// clear forced flag
m_hwint_forced &= ~(1 << offset);
// FIXME: in/ex
LOGIRQ(offset, "irq: forcing interrupt vector %d\n", offset);
set_int_line(INT_HARD_IN, offset, ASSERT_LINE);
}
else
// otherwise just store the value
m_hwicr[offset] = data;
// scan for pending interrupts
m_interrupt_timer->adjust(attotime::zero);
}
WRITE8_MEMBER(interpro_ioga_device::softint_w)
{
// check for forced interrupts
const u8 forced = m_softint & ~data;
// store the written value
m_softint = data;
// FIXME: forced interrupt handling
COMBINE_DATA(&m_softint);
// force interrupts if needed
if (forced != 0)
{
for (int i = 0; i < 8; i++)
if (forced & (1 << i))
set_int_line(INT_SOFT_LO, i, ASSERT_LINE);
}
m_interrupt_timer->adjust(attotime::zero);
}
WRITE8_MEMBER(interpro_ioga_device::nmictrl_w)
@ -569,15 +542,11 @@ WRITE8_MEMBER(interpro_ioga_device::nmictrl_w)
WRITE16_MEMBER(interpro_ioga_device::softint_vector_w)
{
// check for forced interrupt
const bool forced = (m_swicr[offset] & IRQ_PENDING) && !(data & IRQ_PENDING);
// store the written value
m_swicr[offset] = data;
COMBINE_DATA(&m_swicr[offset]);
// force interrupt if needed
if (forced)
set_int_line(INT_SOFT_HI, offset, ASSERT_LINE);
m_interrupt_timer->adjust(attotime::zero);
}
/*
@ -599,43 +568,80 @@ TIMER_CALLBACK_MEMBER(interpro_ioga_device::dma)
if ((m_arbctl & dma_channel.arb_mask) == 0)
{
// set bus wait flag and abort
dma_channel.control |= DMA_CTRL_WAIT;
//dma_channel.control |= DMA_CTRL_WAIT;
continue;
}
else
// clear bus wait flag
dma_channel.control &= ~DMA_CTRL_WAIT;
//else
// // clear bus wait flag
// dma_channel.control &= ~DMA_CTRL_WAIT;
//LOGMASKED(LOG_DMA, "dma: transfer %s device begun, channel = %d, control 0x%08x, real address 0x%08x, virtual address 0x%08x, count 0x%08x\n",
// translate address when DMA_CTRL_VIRTUAL is set
// FIXME: what happens when we span a page?
if (dma_channel.control & DMA_CTRL_VIRTUAL)
{
const u32 ptde = m_memory_space->read_dword(dma_channel.virtual_address);
if ((ptde & 0x1) == 0)
{
dma_channel.real_address = (ptde & ~0xfff) | (dma_channel.real_address & 0xfff);
dma_channel.control &= ~DMA_CTRL_VIRTUAL;
LOGDMA(dma_channel.channel, "dma: translated virtual address 0x%08x\n", dma_channel.real_address);
// FIXME: what about protection levels and system tags?
// set referenced and dirty page table entry flags
m_memory_space->write_dword(dma_channel.virtual_address, ptde | ((dma_channel.control & DMA_CTRL_WRITE) ? 0x2 : 0x6));
}
else
{
// page fault
// FIXME: error status
dma_channel.control |= DMA_CTRL_BERR | DMA_CTRL_ERR;
LOGDMA(dma_channel.channel, "dma: page fault translating virtual address 0x%08x ptde 0x%08x\n", dma_channel.virtual_address, ptde);
break;
}
}
//LOGDMA(dma_channel.channel, "dma: transfer %s device begun, channel = %d, control 0x%08x, real address 0x%08x, virtual address 0x%08x, count 0x%08x\n",
// (dma_channel.control & DMA_CTRL_WRITE) ? "to" : "from", dma_channel.channel, dma_channel.control, dma_channel.real_address, dma_channel.virtual_address, dma_channel.transfer_count);
// transfer from the memory to device or device to memory
while (dma_channel.transfer_count && dma_channel.drq_state)
{
// transfer from the memory to device or device to memory
// TODO: implement virtual addressing when DMA_CTRL_VIRTUAL is set
if (dma_channel.control & DMA_CTRL_WRITE)
dma_channel.device_w(m_memory_space->read_byte(dma_channel.real_address));
else
m_memory_space->write_byte(dma_channel.real_address, dma_channel.device_r());
// increment addresses and decrement count
// increment address and decrement count
dma_channel.real_address++;
dma_channel.virtual_address++;
dma_channel.transfer_count--;
// check for page wrap
if (dma_channel.transfer_count && (dma_channel.real_address & 0xfff) == 0)
{
LOGDMA(dma_channel.channel, "dma: wrapped to next memory page\n");
dma_channel.virtual_address += 4;
dma_channel.control |= DMA_CTRL_VIRTUAL;
m_dma_timer->adjust(attotime::zero);
break;
}
}
// check if the transfer is complete
if (dma_channel.transfer_count == 0)
{
LOGMASKED(LOG_DMA, "dma: transfer %s device ended, channel = %d, control 0x%08x, real address 0x%08x, virtual address 0x%08x, count 0x%08x\n",
LOGDMA(dma_channel.channel, "dma: transfer %s device ended, channel = %d, control 0x%08x, real address 0x%08x, virtual address 0x%08x, count 0x%08x\n",
(dma_channel.control & DMA_CTRL_WRITE) ? "to" : "from", dma_channel.channel, dma_channel.control, dma_channel.real_address, dma_channel.virtual_address, dma_channel.transfer_count);
if (dma_channel.channel == DMA_FLOPPY)
{
LOGMASKED(LOG_DMA | LOG_FLOPPY, "dma: asserting fdc terminal count line\n");
LOGDMA(dma_channel.channel, "dma: asserting fdc terminal count line\n");
m_fdc_tc_func(ASSERT_LINE);
m_fdc_tc_func(CLEAR_LINE);
@ -725,9 +731,7 @@ void interpro_ioga_device::drq(int state, int channel)
// log every 256 bytes
if ((dma_channel.transfer_count & 0xff) == 0)
{
LOGMASKED(LOG_DMA, "dma: drq for channel %d %s transfer_count 0x%08x\n", channel, state ? "asserted" : "deasserted", dma_channel.transfer_count);
}
LOGDMA(channel, "dma: drq for channel %d %s transfer_count 0x%08x\n", channel, state ? "asserted" : "deasserted", dma_channel.transfer_count);
if (state)
m_dma_timer->adjust(attotime::zero);
@ -764,28 +768,33 @@ void interpro_ioga_device::dma_w(address_space &space, offs_t offset, u32 data,
switch (offset)
{
case 0:
LOGMASKED(LOG_DMA, "dma: channel %d real address = 0x%08x (%s)\n", channel, data, machine().describe_context());
dma_channel.real_address = data;
LOGDMA(channel, "dma: channel %d real address 0x%08x mem_mask 0x%08x (%s)\n",
channel, data, mem_mask, machine().describe_context());
COMBINE_DATA(&dma_channel.real_address);
break;
case 1:
LOGMASKED(LOG_DMA, "dma: channel %d virtual address = 0x%08x (%s)\n", channel, data, machine().describe_context());
dma_channel.virtual_address = data & ~0x3;
LOGDMA(channel, "dma: channel %d virtual address = 0x%08x mem_mask 0x%08x (%s)\n",
channel, data, mem_mask, machine().describe_context());
COMBINE_DATA(&dma_channel.virtual_address);
break;
case 2:
LOGMASKED(LOG_DMA, "dma: channel %d transfer count = 0x%08x (%s)\n", channel, data, machine().describe_context());
dma_channel.transfer_count = data;
LOGDMA(channel, "dma: channel %d transfer count = 0x%08x mem_mask 0x%08x (%s)\n",
channel, data, mem_mask, machine().describe_context());
COMBINE_DATA(&dma_channel.transfer_count);
break;
case 3:
LOGMASKED(LOG_DMA, "dma: channel %d control = 0x%08x (%s)\n", channel, data, machine().describe_context());
LOGDMA(channel, "dma: channel %d control = 0x%08x mem_mask 0x%08x (%s)\n",
channel, data, mem_mask, machine().describe_context());
COMBINE_DATA(&dma_channel.control);
// (7.0272) if bus error flag is set, clear existing bus error (otherwise retain existing state)
if (data & DMA_CTRL_BERR)
dma_channel.control = data & DMA_CTRL_WMASK;
else
dma_channel.control = (data & DMA_CTRL_WMASK) | (dma_channel.control & DMA_CTRL_BERR);
//if (data & DMA_CTRL_BERR)
// dma_channel.control = data & DMA_CTRL_WMASK;
//else
// dma_channel.control = (data & DMA_CTRL_WMASK) | (dma_channel.control & DMA_CTRL_BERR);
dma_channel.state = COMMAND;
break;
@ -1097,7 +1106,12 @@ READ32_MEMBER(interpro_ioga_device::mouse_status_r)
// clear xpos and ypos fields
if (!machine().side_effects_disabled())
m_mouse_status &= ~(MOUSE_XPOS | MOUSE_YPOS);
{
if (mem_mask & MOUSE_XPOS)
m_mouse_status &= ~(MOUSE_XPOS);
if (mem_mask & MOUSE_YPOS)
m_mouse_status &= ~(MOUSE_YPOS);
}
return result;
}
@ -1120,6 +1134,10 @@ INPUT_CHANGED_MEMBER(interpro_ioga_device::mouse_button)
else
m_mouse_status &= ~(field.mask() << 16);
// FIXME: this isn't right, but the rebuild code only
// reads the button status if the x/y status is non-zero?
m_mouse_status |= MOUSE_COUNTER;
set_int_line(INT_HARD_IN, IRQ_MOUSE, ASSERT_LINE);
}
@ -1148,7 +1166,7 @@ INPUT_CHANGED_MEMBER(interpro_ioga_device::mouse_y)
else if (delta < -0x80)
delta += 0x100;
// set new x delta
// set new y delta
m_mouse_status &= ~MOUSE_YPOS;
m_mouse_status |= ((delta << 0) & MOUSE_YPOS);
@ -1265,29 +1283,29 @@ WRITE32_MEMBER(sapphire_ioga_device::eth_control_w)
}
}
WRITE32_MEMBER(sapphire_ioga_device::eth_w)
WRITE16_MEMBER(sapphire_ioga_device::eth_w)
{
// top two bits give channel (0=A, 4=B, 8=C, f=?)
const int channel = offset >> 28;
u32 address = (offset << 2) & 0x3fffffff;
const int channel = offset >> 29;
u32 address = (offset << 1) & 0x3fffffff;
if ((m_eth_control & ETH_MAPEN) && (address & ETH_MAPPG) == (m_eth_mappg & ETH_MAPPG))
{
address &= ~(m_eth_mappg & ETH_MAPPG);
address |= (m_eth_remap & ETH_REMAP_ADDR);
LOGMASKED(LOG_NETWORK, "eth_w address 0x%08x remapped 0x%08x\n", offset << 2, address);
LOGMASKED(LOG_NETWORK, "eth_w address 0x%08x remapped 0x%08x\n", offset << 1, address);
}
LOGMASKED(LOG_NETWORK, "eth_w channel %c address 0x%08x mask 0x%08x data 0x%08x\n", channel + 'A', address, mem_mask, data);
m_memory_space->write_dword(address, data, mem_mask);
LOGMASKED(LOG_NETWORK, "eth_w channel %c address 0x%08x mask 0x%08x data 0x%04x\n", channel + 'A', address, mem_mask, data);
m_memory_space->write_word(address, data, mem_mask);
}
READ32_MEMBER(sapphire_ioga_device::eth_r)
READ16_MEMBER(sapphire_ioga_device::eth_r)
{
// top two bits give channel (0=A, 4=B, 8=C, f=?)
const int channel = offset >> 28;
u32 address = (offset << 2) & 0x3fffffff;
const int channel = offset >> 29;
u32 address = (offset << 1) & 0x3fffffff;
if ((m_eth_control & ETH_MAPEN) && (address & ETH_MAPPG) == (m_eth_mappg & ETH_MAPPG))
{
@ -1295,11 +1313,11 @@ READ32_MEMBER(sapphire_ioga_device::eth_r)
address |= (m_eth_remap & ETH_REMAP_ADDR);
address &= 0x3fffffff;
LOGMASKED(LOG_NETWORK, "eth_r address 0x%08x remapped 0x%08x\n", offset << 2, address);
LOGMASKED(LOG_NETWORK, "eth_r address 0x%08x remapped 0x%08x\n", offset << 1, address);
}
u32 data = m_memory_space->read_dword(address, mem_mask);
LOGMASKED(LOG_NETWORK, "eth_r channel %c address 0x%08x mask 0x%08x data 0x%08x\n", channel + 'A', address, mem_mask, data);
u16 data = m_memory_space->read_word(address, mem_mask);
LOGMASKED(LOG_NETWORK, "eth_r channel %c address 0x%08x mask 0x%08x data 0x%04x\n", channel + 'A', address, mem_mask, data);
return data;
}

View File

@ -196,10 +196,9 @@ public:
DMA_CTRL_ERR = 0x00800000, // checked for in scsi isr
DMA_CTRL_BGR = 0x01000000, // cleared when command complete (maybe bus grant required?)
DMA_CTRL_WAIT = 0x02000000, // waiting for bus grant
DMA_CTRL_VIRTUAL = 0x02000000, // virtual address translation required
DMA_CTRL_DOUBLE = 0x04000000, // double transfer size (double or quad quad)
DMA_CTRL_VIRTUAL = 0x20000000, // use virtual addressing
DMA_CTRL_WRITE = 0x40000000, // memory to device transfer
DMA_CTRL_QUAD = 0x80000000, // select quad transfer size (quad quad when combined with double)
@ -513,8 +512,8 @@ public:
virtual void map(address_map &map) override;
DECLARE_WRITE32_MEMBER(eth_w);
DECLARE_READ32_MEMBER(eth_r);
DECLARE_WRITE16_MEMBER(eth_w);
DECLARE_READ16_MEMBER(eth_r);
protected:
virtual TIMER_CALLBACK_MEMBER(eth_reset) override;