m88000: add basic cmmu support

This commit is contained in:
Patrick Mackinlay 2023-02-03 14:23:49 +07:00
parent bc802bb8ac
commit 1f2ae2d47a
2 changed files with 160 additions and 71 deletions

View File

@ -5,10 +5,6 @@
* Motorola M88000 Family of RISC microprocessors.
*
* TODO:
* - cache/mmu interface
* - misaligned access exceptions
* - floating point exceptions
* - user/supervisor space
* - xip/fip/nip exception flag
* - pipeline and cycles counts
* - mc88110
@ -131,9 +127,8 @@ mc88100_device::mc88100_device(const machine_config &mconfig, const char *tag, d
: cpu_device(mconfig, MC88100, tag, owner, clock)
, m_code_config("code", ENDIANNESS_BIG, 32, 32, 0)
, m_data_config("data", ENDIANNESS_BIG, 32, 32, 0)
, m_xip(0)
, m_nip(0)
, m_fip(0)
, m_cmmu_d(*this, finder_base::DUMMY_TAG)
, m_cmmu_i(*this, finder_base::DUMMY_TAG)
, m_sb(0)
, m_r{ 0 }
, m_cr{ 0 }
@ -161,7 +156,7 @@ device_memory_interface::space_config_vector mc88100_device::memory_space_config
void mc88100_device::device_start()
{
space(AS_PROGRAM).cache(m_inst_cache);
space(AS_PROGRAM).specific(m_inst_space);
if (has_configured_map(AS_DATA))
space(AS_DATA).specific(m_data_space);
@ -191,7 +186,7 @@ void mc88100_device::device_start()
state_add(36 + SR2, "sr2", m_cr[SR2]);
state_add(36 + SR3, "sr3", m_cr[SR3]);
for (int i = 1; i < 32; i++)
for (int i = 0; i < 32; i++)
state_add(i, string_format("r%d", i).c_str(), m_r[i]);
save_item(NAME(m_xip));
@ -246,20 +241,19 @@ void mc88100_device::execute_run()
execute(m_xop);
}
// fetch
if (m_fip & IP_V)
fetch(m_fip & IP_A, m_fop);
if (fetch(m_fip & IP_A, m_fop))
{
// next becomes execute
m_xop = m_nop;
m_xip = m_nip;
// next becomes execute
m_xop = m_nop;
m_xip = m_nip;
// fetch becomes next
m_nop = m_fop;
m_nip = m_fip;
// fetch becomes next
m_nop = m_fop;
m_nip = m_fip;
// increment fetch
m_fip += 4;
// increment fetch
m_fip += 4;
}
m_icount--;
}
@ -1433,9 +1427,22 @@ void mc88100_device::fset(unsigned const td, unsigned const d, float64_t const d
bool mc88100_device::fetch(u32 address, u32 &inst)
{
inst = m_inst_cache.read_dword(address);
if (m_cmmu_i)
{
std::optional<u32> data = m_cmmu_i->read<u32>(address, m_cr[PSR] & PSR_MODE);
if (data.has_value())
inst = data.value();
else
exception(E_INSTRUCTION);
return true;
return data.has_value();
}
else
{
inst = m_inst_space.read_dword(address);
return true;
}
}
template <typename T> void mc88100_device::ld(u32 address, unsigned const reg)
@ -1453,35 +1460,64 @@ template <typename T> void mc88100_device::ld(u32 address, unsigned const reg)
address &= ~(sizeof(T) - 1);
}
if constexpr (sizeof(T) == 1)
if (m_cmmu_d)
{
u32 const data = std::is_signed<T>() ? s32(T(m_data_space.read_byte(address))) : m_data_space.read_byte(address);
if constexpr (sizeof(T) < 8)
{
std::optional<T> const data = m_cmmu_d->read<typename std::make_unsigned<T>::type>(address, m_cr[PSR] & PSR_MODE);
if (reg)
m_r[reg] = data;
if (data.has_value() && reg)
m_r[reg] = std::is_signed<T>() ? s32(data.value()) : data.value();
else if (!data.has_value())
exception(E_DATA);
}
else
{
std::optional<u32> const lo = m_cmmu_d->read<u32>(address + 0, m_cr[PSR] & PSR_MODE);
std::optional<u32> const hi = m_cmmu_d->read<u32>(address + 4, m_cr[PSR] & PSR_MODE);
if (lo.has_value() && hi.has_value())
{
if (reg != 0)
m_r[(reg + 0) & 31] = hi.value();
if (reg != 31)
m_r[(reg + 1) & 31] = lo.value();
}
else
exception(E_DATA);
}
}
else if constexpr (sizeof(T) == 2)
else
{
u32 const data = std::is_signed<T>() ? s32(T(m_data_space.read_word(address))) : m_data_space.read_word(address);
if constexpr (sizeof(T) == 1)
{
u32 const data = std::is_signed<T>() ? s32(T(m_data_space.read_byte(address))) : m_data_space.read_byte(address);
if (reg)
m_r[reg] = data;
}
else if constexpr (sizeof(T) == 4)
{
u32 const data = m_data_space.read_dword(address);
if (reg)
m_r[reg] = data;
}
else if constexpr (sizeof(T) == 2)
{
u32 const data = std::is_signed<T>() ? s32(T(m_data_space.read_word(address))) : m_data_space.read_word(address);
if (reg)
m_r[reg] = data;
}
else if constexpr (sizeof(T) == 8)
{
u64 const data = m_data_space.read_qword(address);
if (reg)
m_r[reg] = data;
}
else if constexpr (sizeof(T) == 4)
{
u32 const data = m_data_space.read_dword(address);
if (reg != 0)
m_r[(reg + 0) & 31] = u32(data >> 32);
if (reg != 31)
m_r[(reg + 1) & 31] = u32(data >> 0);
if (reg)
m_r[reg] = data;
}
else if constexpr (sizeof(T) == 8)
{
u64 const data = m_data_space.read_qword(address);
if (reg != 0)
m_r[(reg + 0) & 31] = u32(data >> 32);
if (reg != 31)
m_r[(reg + 1) & 31] = u32(data >> 0);
}
}
}
@ -1500,16 +1536,42 @@ template <typename T> bool mc88100_device::st(u32 address, unsigned const reg)
address &= ~(sizeof(T) - 1);
}
if constexpr (sizeof(T) == 1)
m_data_space.write_byte(address, m_r[reg]);
else if constexpr (sizeof(T) == 2)
m_data_space.write_word(address, m_r[reg]);
else if constexpr (sizeof(T) == 4)
m_data_space.write_dword(address, m_r[reg]);
else if constexpr (sizeof(T) == 8)
m_data_space.write_qword(address, (u64(m_r[(reg + 0) & 31]) << 32) | m_r[(reg + 1) & 31]);
if (m_cmmu_d)
{
if constexpr (sizeof(T) < 8)
{
bool const result = m_cmmu_d->write(address, T(m_r[reg]), m_cr[PSR] & PSR_MODE);
return true;
if (!result)
exception(E_DATA);
return result;
}
else
{
bool result = true;
result &= m_cmmu_d->write(address + 0, m_r[(reg + 1) & 31], m_cr[PSR] & PSR_MODE);
result &= m_cmmu_d->write(address + 4, m_r[(reg + 0) & 31], m_cr[PSR] & PSR_MODE);
if (!result)
exception(E_DATA);
return result;
}
}
else
{
if constexpr (sizeof(T) == 1)
m_data_space.write_byte(address, m_r[reg]);
else if constexpr (sizeof(T) == 2)
m_data_space.write_word(address, m_r[reg]);
else if constexpr (sizeof(T) == 4)
m_data_space.write_dword(address, m_r[reg]);
else if constexpr (sizeof(T) == 8)
m_data_space.write_qword(address, (u64(m_r[(reg + 0) & 31]) << 32) | m_r[(reg + 1) & 31]);
return true;
}
}
template <typename T> void mc88100_device::xmem(u32 address, unsigned const reg)
@ -1526,28 +1588,48 @@ template <typename T> void mc88100_device::xmem(u32 address, unsigned const reg)
// save source value
T const src = m_r[reg];
if constexpr (sizeof(T) == 1)
if (m_cmmu_d)
{
// read destination
T const dst = m_data_space.read_byte(address);
std::optional<T> const dst = m_cmmu_d->read<T>(address, m_cr[PSR] & PSR_MODE);
if (dst.has_value())
{
// update register
if (reg)
m_r[reg] = dst.value();
// update register
if (reg)
m_r[reg] = dst;
// write destination
m_data_space.write_byte(address, src);
// write destination
if (!m_cmmu_d->write(address, src, m_cr[PSR] & PSR_MODE))
exception(E_DATA);
}
else
exception(E_DATA);
}
else if constexpr (sizeof(T) == 4)
else
{
// read destination
T const dst = m_data_space.read_dword(address);
if constexpr (sizeof(T) == 1)
{
// read destination
T const dst = m_data_space.read_byte(address);
// update register
if (reg)
m_r[reg] = dst;
// update register
if (reg)
m_r[reg] = dst;
// write destination
m_data_space.write_dword(address, src);
// write destination
m_data_space.write_byte(address, src);
}
else if constexpr (sizeof(T) == 4)
{
// read destination
T const dst = m_data_space.read_dword(address);
// update register
if (reg)
m_r[reg] = dst;
// write destination
m_data_space.write_dword(address, src);
}
}
}

View File

@ -11,6 +11,7 @@
#pragma once
#include "machine/mc88200.h"
#include "softfloat3/source/include/softfloat.h"
class mc88100_device : public cpu_device
@ -19,6 +20,9 @@ public:
// construction/destruction
mc88100_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
template <typename T> void set_cmmu_d(T &&tag) { m_cmmu_d.set_tag(std::forward<T>(tag)); }
template <typename T> void set_cmmu_i(T &&tag) { m_cmmu_i.set_tag(std::forward<T>(tag)); }
protected:
// device-level overrides
virtual void device_start() override;
@ -59,9 +63,12 @@ private:
// address spaces
address_space_config m_code_config;
address_space_config m_data_config;
memory_access<32, 2, 0, ENDIANNESS_BIG>::cache m_inst_cache;
memory_access<32, 2, 0, ENDIANNESS_BIG>::specific m_inst_space;
memory_access<32, 2, 0, ENDIANNESS_BIG>::specific m_data_space;
optional_device<mc88200_device> m_cmmu_d;
optional_device<mc88200_device> m_cmmu_i;
// register storage
u32 m_xip; // execute instruction pointer
u32 m_nip; // next instruction pointer