mirror of
https://github.com/holub/mame
synced 2025-06-05 04:16:28 +03:00
interpro: cpu and mmu improvements
* implemented most clipper cpu and mmu exceptions * completed c300 instructions, adjusted for c400 * improved cammu dynamic translation and added faults * refactored c300 cammu into separate instruction/data instances * configurable ioga and sr bus memory access
This commit is contained in:
parent
23b9c43e56
commit
3c36e304ed
@ -266,16 +266,16 @@ sr_slot_device::sr_slot_device(const machine_config &mconfig, const char *tag, d
|
||||
: device_t(mconfig, SR_SLOT, tag, owner, clock)
|
||||
, device_slot_interface(mconfig, *this)
|
||||
, m_sr_tag(nullptr)
|
||||
, m_sr_slottag(nullptr)
|
||||
, m_sr_slot_tag(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void sr_slot_device::static_set_sr_slot(device_t &device, const char *tag, const char *slottag)
|
||||
void sr_slot_device::static_set_sr_slot(device_t &device, const char *tag, const char *slot_tag)
|
||||
{
|
||||
sr_slot_device &sr_card = dynamic_cast<sr_slot_device &>(device);
|
||||
|
||||
sr_card.m_sr_tag = tag;
|
||||
sr_card.m_sr_slottag = slottag;
|
||||
sr_card.m_sr_slot_tag = slot_tag;
|
||||
}
|
||||
|
||||
void sr_slot_device::device_start()
|
||||
@ -283,28 +283,38 @@ void sr_slot_device::device_start()
|
||||
device_sr_card_interface *dev = dynamic_cast<device_sr_card_interface *>(get_card_device());
|
||||
|
||||
if (dev)
|
||||
device_sr_card_interface::static_set_sr_tag(*dev, m_sr_tag, m_sr_slottag);
|
||||
device_sr_card_interface::static_set_sr_tag(*dev, m_sr_tag, m_sr_slot_tag);
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_TYPE(SR, sr_device, "sr", "InterPro SR bus")
|
||||
|
||||
sr_device::sr_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
|
||||
: device_t(mconfig, SR, tag, owner, clock)
|
||||
, m_data_space(nullptr)
|
||||
, m_io_space(nullptr)
|
||||
, m_out_irq0_cb(*this)
|
||||
, m_out_irq1_cb(*this)
|
||||
, m_out_irq2_cb(*this)
|
||||
, m_memory_tag(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void sr_device::static_set_memory(device_t &device, const char *const tag, const int data_spacenum, const int io_spacenum)
|
||||
{
|
||||
sr_device &sr = dynamic_cast<sr_device &>(device);
|
||||
|
||||
sr.m_memory_tag = tag;
|
||||
sr.m_data_spacenum = data_spacenum;
|
||||
sr.m_io_spacenum = io_spacenum;
|
||||
}
|
||||
|
||||
void sr_device::device_start()
|
||||
{
|
||||
// grab the main memory space from the mmu
|
||||
device_memory_interface *mmu;
|
||||
siblingdevice("mmu")->interface(mmu);
|
||||
m_data_space = &mmu->space(0);
|
||||
m_io_space = &mmu->space(1);
|
||||
assert_always(m_memory_tag != nullptr, "memory tag and address spaces must be configured");
|
||||
|
||||
// get the memory spaces
|
||||
device_memory_interface *memory;
|
||||
siblingdevice(m_memory_tag)->interface(memory);
|
||||
m_data_space = &memory->space(m_data_spacenum);
|
||||
m_io_space = &memory->space(m_io_spacenum);
|
||||
|
||||
// resolve callbacks
|
||||
m_out_irq0_cb.resolve_safe();
|
||||
@ -325,7 +335,7 @@ device_sr_card_interface::device_sr_card_interface(const machine_config &mconfig
|
||||
: device_slot_card_interface(mconfig, device)
|
||||
, m_sr(nullptr)
|
||||
, m_sr_tag(nullptr)
|
||||
, m_sr_slottag(nullptr)
|
||||
, m_sr_slot_tag(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@ -333,12 +343,12 @@ device_sr_card_interface::~device_sr_card_interface()
|
||||
{
|
||||
}
|
||||
|
||||
void device_sr_card_interface::static_set_sr_tag(device_t &device, const char *tag, const char *slottag)
|
||||
void device_sr_card_interface::static_set_sr_tag(device_t &device, const char *tag, const char *slot_tag)
|
||||
{
|
||||
device_sr_card_interface &sr_card = dynamic_cast<device_sr_card_interface &>(device);
|
||||
|
||||
sr_card.m_sr_tag = tag;
|
||||
sr_card.m_sr_slottag = slottag;
|
||||
sr_card.m_sr_slot_tag = slot_tag;
|
||||
}
|
||||
|
||||
void device_sr_card_interface::set_sr_device()
|
||||
|
@ -23,6 +23,9 @@
|
||||
#define MCFG_SR_SLOT_REMOVE(_tag) \
|
||||
MCFG_DEVICE_REMOVE(_tag)
|
||||
|
||||
#define MCFG_SR_MEMORY(_tag, _data_spacenum, _io_spacenum) \
|
||||
sr_device::static_set_memory(*device, _tag, _data_spacenum, _io_spacenum);
|
||||
|
||||
class sr_slot_device : public device_t, public device_slot_interface
|
||||
{
|
||||
public:
|
||||
@ -30,7 +33,8 @@ public:
|
||||
sr_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
// inline configuration
|
||||
static void static_set_sr_slot(device_t &device, const char *tag, const char *slottag);
|
||||
static void static_set_sr_slot(device_t &device, const char *tag, const char *slot_tag);
|
||||
|
||||
protected:
|
||||
sr_slot_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
@ -38,7 +42,8 @@ protected:
|
||||
virtual void device_start() override;
|
||||
|
||||
// configuration
|
||||
const char *m_sr_tag, *m_sr_slottag;
|
||||
const char *m_sr_tag;
|
||||
const char *m_sr_slot_tag;
|
||||
};
|
||||
|
||||
class device_sr_card_interface;
|
||||
@ -54,6 +59,8 @@ public:
|
||||
template <class Object> static devcb_base &set_out_irq1_callback(device_t &device, Object &&cb) { return downcast<sr_device &>(device).m_out_irq1_cb.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> static devcb_base &set_out_irq2_callback(device_t &device, Object &&cb) { return downcast<sr_device &>(device).m_out_irq2_cb.set_callback(std::forward<Object>(cb)); }
|
||||
|
||||
static void static_set_memory(device_t &device, const char *const tag, const int data_spacenum, const int io_spacenum);
|
||||
|
||||
static const u32 SR_BASE = 0x87000000;
|
||||
static const u32 SR_SIZE = 0x08000000;
|
||||
static const int SR_COUNT = 16;
|
||||
@ -97,6 +104,10 @@ protected:
|
||||
private:
|
||||
device_sr_card_interface *m_slot[SR_COUNT];
|
||||
int m_slot_count;
|
||||
|
||||
const char *m_memory_tag;
|
||||
int m_data_spacenum;
|
||||
int m_io_spacenum;
|
||||
};
|
||||
|
||||
class device_sr_card_interface : public device_slot_card_interface
|
||||
@ -110,13 +121,14 @@ public:
|
||||
void set_sr_device();
|
||||
|
||||
// inline configuration
|
||||
static void static_set_sr_tag(device_t &device, const char *tag, const char *slottag);
|
||||
static void static_set_sr_tag(device_t &device, const char *tag, const char *slot_tag);
|
||||
|
||||
protected:
|
||||
device_sr_card_interface(const machine_config &mconfig, device_t &device);
|
||||
|
||||
sr_device *m_sr;
|
||||
const char *m_sr_tag, *m_sr_slottag;
|
||||
const char *m_sr_tag;
|
||||
const char *m_sr_slot_tag;
|
||||
};
|
||||
|
||||
class sr_card_device_base : public device_t, public device_sr_card_interface
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,55 +19,48 @@ 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);
|
||||
|
||||
protected:
|
||||
enum registers
|
||||
enum addressing_modes : u8
|
||||
{
|
||||
CLIPPER_R0, CLIPPER_R1, CLIPPER_R2, CLIPPER_R3, CLIPPER_R4, CLIPPER_R5, CLIPPER_R6, CLIPPER_R7,
|
||||
CLIPPER_R8, CLIPPER_R9, CLIPPER_R10, CLIPPER_R11, CLIPPER_R12, CLIPPER_R13, CLIPPER_R14, CLIPPER_R15,
|
||||
|
||||
CLIPPER_F0, CLIPPER_F1, CLIPPER_F2, CLIPPER_F3, CLIPPER_F4, CLIPPER_F5, CLIPPER_F6, CLIPPER_F7,
|
||||
CLIPPER_F8, CLIPPER_F9, CLIPPER_F10, CLIPPER_F11, CLIPPER_F12, CLIPPER_F13, CLIPPER_F14, CLIPPER_F15,
|
||||
|
||||
CLIPPER_PSW,
|
||||
CLIPPER_SSW,
|
||||
CLIPPER_PC,
|
||||
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 addressing_modes
|
||||
// branch conditions (first description for comparison, second for move/logical)
|
||||
enum branch_conditions : u8
|
||||
{
|
||||
ADDR_MODE_PC32 = 0x10,
|
||||
ADDR_MODE_ABS32 = 0x30,
|
||||
ADDR_MODE_REL32 = 0x60,
|
||||
ADDR_MODE_PC16 = 0x90,
|
||||
ADDR_MODE_REL12 = 0xa0,
|
||||
ADDR_MODE_ABS16 = 0xb0,
|
||||
ADDR_MODE_PCX = 0xd0,
|
||||
ADDR_MODE_RELX = 0xe0,
|
||||
BRANCH_T = 0x0, // always
|
||||
BRANCH_LT = 0x1, // less than greater than
|
||||
BRANCH_LE = 0x2, // less or equal greater or equal
|
||||
BRANCH_EQ = 0x3, // equal
|
||||
BRANCH_GT = 0x4, // greater than less than
|
||||
BRANCH_GE = 0x5, // greater or equal less or equal
|
||||
BRANCH_NE = 0x6, // not equal
|
||||
BRANCH_LTU = 0x7, // less than unsigned greater than unsigned
|
||||
BRANCH_LEU = 0x8, // less or equal unsigned greater or equal unsigned
|
||||
BRANCH_GTU = 0x9, // greater than unsigned less than unsigned
|
||||
BRANCH_GEU = 0xa, // greater or equal unsigned less or equal unsigned
|
||||
BRANCH_V = 0xb, // overflow
|
||||
BRANCH_NV = 0xc, // not overflow
|
||||
BRANCH_N = 0xd, // negative
|
||||
BRANCH_NN = 0xe, // not negative
|
||||
BRANCH_FN = 0xf // floating unordered
|
||||
};
|
||||
|
||||
// branch conditions
|
||||
enum branch_conditions
|
||||
enum bf_conditions : u8
|
||||
{
|
||||
BRANCH_T = 0x0,
|
||||
BRANCH_LT = 0x1,
|
||||
BRANCH_LE = 0x2,
|
||||
BRANCH_EQ = 0x3,
|
||||
BRANCH_GT = 0x4,
|
||||
BRANCH_GE = 0x5,
|
||||
BRANCH_NE = 0x6,
|
||||
BRANCH_LTU = 0x7,
|
||||
BRANCH_LEU = 0x8,
|
||||
BRANCH_GTU = 0x9,
|
||||
BRANCH_GEU = 0xa,
|
||||
BRANCH_V = 0xb,
|
||||
BRANCH_NV = 0xc,
|
||||
BRANCH_N = 0xd,
|
||||
BRANCH_NN = 0xe,
|
||||
BRANCH_FN = 0xf,
|
||||
BF_ANY = 0x0, // floating any exception
|
||||
BF_BAD = 0x1 // floating bad result
|
||||
};
|
||||
|
||||
enum psw
|
||||
enum psw : u32
|
||||
{
|
||||
PSW_N = 0x00000001, // negative
|
||||
PSW_Z = 0x00000002, // zero
|
||||
@ -90,10 +83,10 @@ protected:
|
||||
PSW_BIG = 0x00400000, // c400 - big endian (hardware)
|
||||
PSW_T = 0x00800000, // trace trap
|
||||
PSW_CTS = 0x0f000000, // cpu trap status (4 bits)
|
||||
PSW_MTS = 0xf0000000, // memory trap status (4 bits)
|
||||
PSW_MTS = 0xf0000000 // memory trap status (4 bits)
|
||||
};
|
||||
|
||||
enum psw_fr
|
||||
enum psw_fr : u32
|
||||
{
|
||||
FR_0 = 0x00000000, // round to nearest
|
||||
FR_1 = 0x00008000, // round toward + infinity
|
||||
@ -101,7 +94,7 @@ protected:
|
||||
FR_3 = 0x00018000 // round toward zero
|
||||
};
|
||||
|
||||
enum ssw
|
||||
enum ssw : u32
|
||||
{
|
||||
SSW_IN = 0x0000000f, // interrupt number (4 bits)
|
||||
SSW_IL = 0x000000f0, // interrupt level (4 bits)
|
||||
@ -110,17 +103,17 @@ protected:
|
||||
// unused (5 bits)
|
||||
SSW_FRD = 0x00400000, // floating registers dirty
|
||||
SSW_TP = 0x00800000, // trace trap pending
|
||||
SSW_ECM = 0x01000000, // enabled corrected memory error
|
||||
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_P = 0x80000000 // previous mode
|
||||
};
|
||||
|
||||
enum ssw_id
|
||||
enum ssw_id : u32
|
||||
{
|
||||
SSW_ID_C400R0 = 0x00000,
|
||||
SSW_ID_C400R1 = 0x04000,
|
||||
@ -129,7 +122,7 @@ protected:
|
||||
SSW_ID_C400R4 = 0x10000
|
||||
};
|
||||
|
||||
enum exception_vectors
|
||||
enum exception_vectors : u16
|
||||
{
|
||||
// data memory trap group
|
||||
EXCEPTION_D_CORRECTED_MEMORY_ERROR = 0x108,
|
||||
@ -167,37 +160,55 @@ protected:
|
||||
EXCEPTION_SUPERVISOR_CALL_BASE = 0x400,
|
||||
|
||||
// prioritized interrupts (0x800-0xff8)
|
||||
EXCEPTION_INTERRUPT_BASE = 0x800,
|
||||
EXCEPTION_INTERRUPT_BASE = 0x800
|
||||
};
|
||||
|
||||
// trap source values are shifted into the correct field in the psw
|
||||
enum cpu_trap_sources
|
||||
static const int CTS_SHIFT = 24;
|
||||
enum cpu_trap_sources : u32
|
||||
{
|
||||
CTS_NO_CPU_TRAP = 0 << 24,
|
||||
CTS_DIVIDE_BY_ZERO = 2 << 24,
|
||||
CTS_ILLEGAL_OPERATION = 4 << 24,
|
||||
CTS_PRIVILEGED_INSTRUCTION = 5 << 24,
|
||||
CTS_TRACE_TRAP = 7 << 24,
|
||||
CTS_NO_CPU_TRAP = 0 << CTS_SHIFT,
|
||||
CTS_DIVIDE_BY_ZERO = 2 << CTS_SHIFT,
|
||||
CTS_ILLEGAL_OPERATION = 4 << CTS_SHIFT,
|
||||
CTS_PRIVILEGED_INSTRUCTION = 5 << CTS_SHIFT,
|
||||
CTS_TRACE_TRAP = 7 << CTS_SHIFT
|
||||
};
|
||||
|
||||
enum memory_trap_sources
|
||||
static const int MTS_SHIFT = 28;
|
||||
enum memory_trap_sources : u32
|
||||
{
|
||||
MTS_NO_MEMORY_TRAP = 0 << 28,
|
||||
MTS_CORRECTED_MEMORY_ERROR = 1 << 28,
|
||||
MTS_UNCORRECTABLE_MEMORY_ERROR = 2 << 28,
|
||||
MTS_ALIGNMENT_FAULT = 4 << 28,
|
||||
MTS_PAGE_FAULT = 5 << 28,
|
||||
MTS_READ_OR_EXECUTE_PROTECT_FAULT = 6 << 28,
|
||||
MTS_WRITE_PROTECT_FAULT = 7 << 28,
|
||||
MTS_NO_MEMORY_TRAP = 0 << MTS_SHIFT,
|
||||
MTS_CORRECTED_MEMORY_ERROR = 1 << MTS_SHIFT,
|
||||
MTS_UNCORRECTABLE_MEMORY_ERROR = 2 << MTS_SHIFT,
|
||||
MTS_ALIGNMENT_FAULT = 4 << MTS_SHIFT,
|
||||
MTS_PAGE_FAULT = 5 << MTS_SHIFT,
|
||||
MTS_READ_OR_EXECUTE_PROTECT_FAULT = 6 << MTS_SHIFT,
|
||||
MTS_WRITE_PROTECT_FAULT = 7 << MTS_SHIFT
|
||||
};
|
||||
|
||||
enum ivec_mask
|
||||
// extract an mts code from a vector
|
||||
static const u32 MTS_VMASK = 0x00000038;
|
||||
static const int MTS_VSHIFT = 3;
|
||||
|
||||
enum ivec_mask : u8
|
||||
{
|
||||
IVEC_NUMBER = 0x0f,
|
||||
IVEC_LEVEL = 0xf0
|
||||
};
|
||||
|
||||
clipper_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, const u32 cpuid);
|
||||
// combinations of floating point exceptions (from softfloat flags)
|
||||
enum fp_exception_mask : u8
|
||||
{
|
||||
F_NONE = (0),
|
||||
F_I = (float_flag_invalid),
|
||||
F_X = (float_flag_inexact),
|
||||
F_IX = (float_flag_invalid | float_flag_inexact),
|
||||
F_IVUX = (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact),
|
||||
F_IVDUX = (float_flag_invalid | float_flag_overflow | float_flag_divbyzero | float_flag_underflow | float_flag_inexact)
|
||||
};
|
||||
|
||||
protected:
|
||||
clipper_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, const endianness_t endianness, const u32 cpuid);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
@ -214,77 +225,147 @@ protected:
|
||||
virtual space_config_vector memory_space_config() const override;
|
||||
|
||||
// device_state_interface overrides
|
||||
#if 0
|
||||
virtual void state_import(const device_state_entry &entry) override;
|
||||
virtual void state_export(const device_state_entry &entry) override;
|
||||
#endif
|
||||
virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
|
||||
|
||||
// device_disasm_interface overrides
|
||||
virtual util::disasm_interface *create_disassembler() override;
|
||||
|
||||
void set_ssw(u32 data) { m_ssw = (m_ssw & SSW(ID)) | (data & ~SSW(ID)); }
|
||||
// cpu execution logic
|
||||
bool decode_instruction();
|
||||
virtual void execute_instruction();
|
||||
bool evaluate_branch() const;
|
||||
|
||||
inline float32 get_fp32(const u8 reg) const { return m_f[reg & 0xf]; };
|
||||
inline float64 get_fp64(const u8 reg) const { return m_f[reg & 0xf]; };
|
||||
inline void set_fp32(const u8 reg, const float32 data);
|
||||
inline void set_fp64(const u8 reg, const float64 data);
|
||||
// exception entry and return helpers
|
||||
u32 intrap(const u16 vector, const u32 old_pc);
|
||||
u32 reti();
|
||||
|
||||
// core registers
|
||||
u32 m_pc;
|
||||
u32 m_psw;
|
||||
u32 m_ssw;
|
||||
// cpu state helpers
|
||||
void set_psw(const u32 psw);
|
||||
void set_ssw(const u32 ssw);
|
||||
void fp_exception();
|
||||
|
||||
// integer registers
|
||||
u32 *m_r; // active registers
|
||||
u32 m_ru[16]; // user registers
|
||||
u32 m_rs[16]; // supervisor registers
|
||||
// register count helpers
|
||||
virtual int get_ireg_count() const { return 16; }
|
||||
virtual int get_freg_count() const { return 8; }
|
||||
|
||||
// floating point registers
|
||||
u64 m_f[16];
|
||||
// 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; }
|
||||
|
||||
u32 m_fp_pc; // address of floating point instruction causing exception
|
||||
u64 m_fp_dst; // original value of destination register during fp exception
|
||||
// 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]; }
|
||||
template <typename T> void set_fp(const u8 reg, const T data, const fp_exception_mask exception_mask)
|
||||
{
|
||||
// suppress unexpected exceptions
|
||||
float_exception_flags &= exception_mask;
|
||||
|
||||
// save floating exception state
|
||||
m_fp_pc = m_pc;
|
||||
m_fp_dst = m_f[reg & 0xf];
|
||||
|
||||
// assign data
|
||||
if (float_exception_flags & float_flag_overflow && PSW(EFV))
|
||||
{
|
||||
/*
|
||||
* If the EFV flag is set, the computed result is delivered to the
|
||||
* destination with the normalized rounded fraction of the true
|
||||
* result (though the delivered exponent is usually wrong because
|
||||
* of missing additional leading bits in the exponent field). For
|
||||
* single-precision overflows, if the biased exponent of the true
|
||||
* result is 255, then biased exponent 255 is delivered to the
|
||||
* destination. If the true biased exponent of the result is
|
||||
* 256..408, then the true biased exponent minus 256 is delivered
|
||||
* to the destination. Note that this is not the exponent wrapped
|
||||
* result called for by the IEEE 754 specification; the wrap must
|
||||
* be adjusted by system software before delivery to a user's trap
|
||||
* handler. This is done to allow the user to provide software that
|
||||
* handles traps in an application-specific way. For double-
|
||||
* precision, the overflow exponents (biased) lie in the range
|
||||
* 2047..3120. These are mapped to 2047 and 0..1072 respectively.
|
||||
* These must be adjusted by (3/4)x2^11 (1536) to obtain the IEEE
|
||||
* Standard wrapped exponent.
|
||||
*/
|
||||
// FIXME: implement non-IEEE behaviour described above
|
||||
m_f[reg & 0xf] = data;
|
||||
}
|
||||
else if (float_exception_flags & float_flag_underflow && PSW(EFU))
|
||||
{
|
||||
/*
|
||||
* If EFU is set, the floating underflow exception is signalled
|
||||
* when the result of an operation (before rounding) has a biased
|
||||
* exponent less than the minimum representable biased exponent for
|
||||
* a normalized number. If the true biased exponent of the result
|
||||
* is zero, then biased exponent zero is delivered to the
|
||||
* destination. If the true biased exponent is less than zero, then
|
||||
* the exponent delivered to the destination is true biased
|
||||
* exponent plus 256 (2048 for double). The exponent must be
|
||||
* adjusted by system software before delivery to the program's
|
||||
* trap handler in order to conform to the IEEE 754 specification.
|
||||
* The range of underflowed biased exponents for single-precision
|
||||
* is 0..-275; for double-precision the range is 0..-1125.
|
||||
*/
|
||||
// FIXME: implement non-IEEE behaviour described above
|
||||
m_f[reg & 0xf] = data;
|
||||
}
|
||||
else
|
||||
m_f[reg & 0xf] = data;
|
||||
|
||||
// set floating dirty flag
|
||||
m_ssw |= SSW_FRD;
|
||||
};
|
||||
|
||||
// emulation state
|
||||
address_space_config m_insn_config;
|
||||
address_space_config m_data_config;
|
||||
|
||||
address_space *m_insn;
|
||||
address_space *m_data;
|
||||
|
||||
private:
|
||||
int m_icount;
|
||||
enum registers
|
||||
{
|
||||
CLIPPER_IREG = 0,
|
||||
CLIPPER_FREG = 16,
|
||||
CLIPPER_PSW = 32,
|
||||
CLIPPER_SSW = 33,
|
||||
CLIPPER_PC = 34,
|
||||
};
|
||||
|
||||
int m_irq;
|
||||
int m_nmi;
|
||||
u8 m_ivec;
|
||||
int m_icount; // instruction cycle count
|
||||
|
||||
// program-visible cpu state
|
||||
u32 m_pc; // current instruction address
|
||||
u32 m_psw; // program status word
|
||||
u32 m_ssw; // system status word
|
||||
|
||||
u32 *m_r; // active registers
|
||||
u32 m_ru[16]; // user registers
|
||||
u32 m_rs[16]; // supervisor registers
|
||||
|
||||
u64 m_f[16]; // floating point registers
|
||||
u32 m_fp_pc; // address of floating point instruction causing exception
|
||||
u64 m_fp_dst; // original value of destination register during fp exception
|
||||
|
||||
// non-visible cpu state
|
||||
u32 m_ip; // next instruction address
|
||||
int m_irq; // interrupt request state
|
||||
int m_nmi; // non-maskable interrupt state
|
||||
u8 m_ivec; // interrupt vector
|
||||
u16 m_exception; // pending exception
|
||||
|
||||
// decoded instruction information
|
||||
struct decode
|
||||
{
|
||||
// various decoded instruction fields
|
||||
u8 opcode, subopcode;
|
||||
u8 r1, r2;
|
||||
u32 imm;
|
||||
u16 macro;
|
||||
|
||||
// total size of instruction in bytes
|
||||
u32 size;
|
||||
|
||||
// computed effective address
|
||||
u32 address;
|
||||
u8 opcode; // primary instruction opcode
|
||||
u8 subopcode; // secondary instruction opcode
|
||||
u8 r1; // r1 instruction operand
|
||||
u8 r2; // r2 instruction operand
|
||||
u32 imm; // immediate value operand
|
||||
u16 macro; // macro instruction operands
|
||||
u32 address; // computed effective address
|
||||
}
|
||||
m_info;
|
||||
|
||||
void decode_instruction(u16 insn);
|
||||
int execute_instruction();
|
||||
bool evaluate_branch() const;
|
||||
|
||||
void fp_rounding();
|
||||
void fp_exception();
|
||||
|
||||
protected:
|
||||
virtual u32 intrap(u16 vector, u32 pc, u32 cts = CTS_NO_CPU_TRAP, u32 mts = MTS_NO_MEMORY_TRAP);
|
||||
};
|
||||
|
||||
class clipper_c100_device : public clipper_device
|
||||
@ -305,7 +386,19 @@ public:
|
||||
clipper_c400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
protected:
|
||||
virtual u32 intrap(u16 vector, u32 pc, u32 cts = CTS_NO_CPU_TRAP, u32 mts = MTS_NO_MEMORY_TRAP) 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;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(CLIPPER_C100, clipper_c100_device)
|
||||
|
@ -16,17 +16,16 @@ public:
|
||||
virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override;
|
||||
|
||||
private:
|
||||
// the CLIPPER addressing modes (unshifted)
|
||||
enum
|
||||
enum addressing_modes : u8
|
||||
{
|
||||
ADDR_MODE_PC32 = 0x10,
|
||||
ADDR_MODE_ABS32 = 0x30,
|
||||
ADDR_MODE_REL32 = 0x60,
|
||||
ADDR_MODE_PC16 = 0x90,
|
||||
ADDR_MODE_REL12 = 0xa0,
|
||||
ADDR_MODE_ABS16 = 0xb0,
|
||||
ADDR_MODE_PCX = 0xd0,
|
||||
ADDR_MODE_RELX = 0xe0
|
||||
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[];
|
||||
|
@ -182,8 +182,14 @@ void interpro_state::machine_reset()
|
||||
m_sreg_ctrl1 = CTRL1_FLOPLOW;
|
||||
}
|
||||
|
||||
DRIVER_INIT_MEMBER(interpro_state, interpro)
|
||||
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
|
||||
|
||||
@ -193,11 +199,26 @@ DRIVER_INIT_MEMBER(interpro_state, interpro)
|
||||
// 128 = reports 128M, 16x8
|
||||
// 256 = reports 256M, 32x8
|
||||
|
||||
// grab the main memory space from the mmu
|
||||
address_space &space = m_mmu->space(0);
|
||||
// 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
|
||||
space.install_ram(0, m_ram->mask(), m_ram->pointer());
|
||||
m_mmu->space(0).install_ram(0, m_ram->mask(), m_ram->pointer());
|
||||
}
|
||||
|
||||
WRITE16_MEMBER(interpro_state::sreg_led_w)
|
||||
@ -299,12 +320,20 @@ READ8_MEMBER(interpro_state::nodeid_r)
|
||||
}
|
||||
|
||||
// these maps connect the cpu virtual addresses to the mmu
|
||||
static ADDRESS_MAP_START(clipper_insn_map, AS_PROGRAM, 32, interpro_state)
|
||||
AM_RANGE(0x00000000, 0xffffffff) AM_DEVREAD32(INTERPRO_MMU_TAG, cammu_device, insn_r, 0xffffffff)
|
||||
static ADDRESS_MAP_START(c300_insn_map, AS_PROGRAM, 32, interpro_state)
|
||||
AM_RANGE(0x00000000, 0xffffffff) AM_DEVREAD(INTERPRO_MMU_TAG "_i", cammu_device, read)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(clipper_data_map, AS_DATA, 32, interpro_state)
|
||||
AM_RANGE(0x00000000, 0xffffffff) AM_DEVREADWRITE32(INTERPRO_MMU_TAG, cammu_device, data_r, data_w, 0xffffffff)
|
||||
static ADDRESS_MAP_START(c300_data_map, AS_DATA, 32, interpro_state)
|
||||
AM_RANGE(0x00000000, 0xffffffff) AM_DEVREADWRITE(INTERPRO_MMU_TAG "_d", cammu_device, read, write)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(c400_insn_map, AS_PROGRAM, 32, interpro_state)
|
||||
AM_RANGE(0x00000000, 0xffffffff) AM_DEVREAD(INTERPRO_MMU_TAG, cammu_device, read)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(c400_data_map, AS_DATA, 32, interpro_state)
|
||||
AM_RANGE(0x00000000, 0xffffffff) AM_DEVREADWRITE(INTERPRO_MMU_TAG, cammu_device, read, write)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(interpro_common_map, 0, 32, interpro_state)
|
||||
@ -381,13 +410,15 @@ static ADDRESS_MAP_START(sapphire_main_map, 0, 32, sapphire_state)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(turquoise_io_map, 1, 32, interpro_state)
|
||||
AM_RANGE(0x00000000, 0x00001fff) AM_DEVICE(INTERPRO_MMU_TAG, cammu_device, map)
|
||||
AM_RANGE(0x00000800, 0x000009ff) AM_DEVICE(INTERPRO_MMU_TAG "_d", cammu_c3_device, map)
|
||||
AM_RANGE(0x00000a00, 0x00000bff) AM_DEVICE(INTERPRO_MMU_TAG "_i", cammu_c3_device, map)
|
||||
AM_RANGE(0x00000c00, 0x00000dff) AM_DEVICE(INTERPRO_MMU_TAG "_d", cammu_c3_device, map_global)
|
||||
|
||||
AM_IMPORT_FROM(turquoise_base_map)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(sapphire_io_map, 1, 32, interpro_state)
|
||||
AM_RANGE(0x00000000, 0x00001fff) AM_DEVICE(INTERPRO_MMU_TAG, cammu_device, map)
|
||||
AM_RANGE(0x00000000, 0x00001fff) AM_DEVICE(INTERPRO_MMU_TAG, cammu_c4_device, map)
|
||||
|
||||
AM_IMPORT_FROM(sapphire_base_map)
|
||||
ADDRESS_MAP_END
|
||||
@ -486,8 +517,6 @@ static MACHINE_CONFIG_START(ioga)
|
||||
// ioga floppy terminal count, ethernet channel attention
|
||||
MCFG_INTERPRO_IOGA_FDCTC_CB(DEVWRITELINE(INTERPRO_FDC_TAG, upd765_family_device, tc_line_w))
|
||||
MCFG_INTERPRO_IOGA_ETH_CA_CB(DEVWRITELINE(INTERPRO_ETH_TAG, i82586_base_device, ca))
|
||||
|
||||
MCFG_INTERPRO_IOGA_DMA_BUS(INTERPRO_CAMMU_TAG, 0)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
static INPUT_PORTS_START(interpro)
|
||||
@ -541,15 +570,24 @@ MACHINE_CONFIG_END
|
||||
|
||||
static MACHINE_CONFIG_DERIVED(turquoise, interpro)
|
||||
MCFG_CPU_ADD(INTERPRO_CPU_TAG, CLIPPER_C300, XTAL_12_5MHz)
|
||||
MCFG_CPU_PROGRAM_MAP(clipper_insn_map)
|
||||
MCFG_CPU_DATA_MAP(clipper_data_map)
|
||||
MCFG_CPU_PROGRAM_MAP(c300_insn_map)
|
||||
MCFG_CPU_DATA_MAP(c300_data_map)
|
||||
MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, acknowledge_interrupt)
|
||||
|
||||
MCFG_DEVICE_ADD(INTERPRO_MMU_TAG, CAMMU_C3, 0)
|
||||
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")
|
||||
|
||||
// boot fails memory test without this
|
||||
MCFG_DEVICE_MODIFY(RAM_TAG)
|
||||
@ -587,13 +625,17 @@ static MACHINE_CONFIG_DERIVED(turquoise, interpro)
|
||||
|
||||
// i/o gate array
|
||||
MCFG_DEVICE_ADD(INTERPRO_IOGA_TAG, TURQUOISE_IOGA, 0)
|
||||
MCFG_INTERPRO_IOGA_MEMORY(INTERPRO_MMU_TAG "_d", 0)
|
||||
MCFG_FRAGMENT_ADD(ioga)
|
||||
|
||||
MCFG_DEVICE_MODIFY(INTERPRO_SRBUS_TAG)
|
||||
MCFG_SR_MEMORY(INTERPRO_MMU_TAG "_d", 0, 1)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
static MACHINE_CONFIG_DERIVED(sapphire, interpro)
|
||||
MCFG_CPU_ADD(INTERPRO_CPU_TAG, CLIPPER_C400, XTAL_12_5MHz)
|
||||
MCFG_CPU_PROGRAM_MAP(clipper_insn_map)
|
||||
MCFG_CPU_DATA_MAP(clipper_data_map)
|
||||
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)
|
||||
@ -601,6 +643,7 @@ static MACHINE_CONFIG_DERIVED(sapphire, interpro)
|
||||
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_CAMMU_EXCEPTION_CB(DEVWRITE16(INTERPRO_CPU_TAG, clipper_device, set_exception))
|
||||
|
||||
// memory control gate array
|
||||
MCFG_DEVICE_ADD(INTERPRO_MCGA_TAG, INTERPRO_FMCC, 0)
|
||||
@ -632,11 +675,16 @@ static MACHINE_CONFIG_DERIVED(sapphire, interpro)
|
||||
|
||||
// i/o gate array
|
||||
MCFG_DEVICE_ADD(INTERPRO_IOGA_TAG, SAPPHIRE_IOGA, 0)
|
||||
MCFG_INTERPRO_IOGA_MEMORY(INTERPRO_MMU_TAG, 0)
|
||||
MCFG_FRAGMENT_ADD(ioga)
|
||||
|
||||
// flash memory
|
||||
MCFG_DEVICE_ADD(INTERPRO_FLASH_TAG "_lo", INTEL_28F010, 0)
|
||||
MCFG_DEVICE_ADD(INTERPRO_FLASH_TAG "_hi", INTEL_28F010, 0)
|
||||
|
||||
// sr bus address spaces
|
||||
MCFG_DEVICE_MODIFY(INTERPRO_SRBUS_TAG)
|
||||
MCFG_SR_MEMORY(INTERPRO_MMU_TAG, 0, 1)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
MACHINE_CONFIG_DERIVED(ip2000, turquoise)
|
||||
@ -734,9 +782,9 @@ ROM_START(ip2800)
|
||||
ROM_LOAD_OPTIONAL("y226.u67", 0x00000, 0x20000, CRC(54d95730) SHA1(a4e114dee1567d8aa31eed770f7cc366588f395c))
|
||||
ROM_END
|
||||
|
||||
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
|
||||
COMP( 1989, ip2000, 0, 0, ip2000, interpro, turquoise_state, interpro, "Intergraph", "InterPro 2000", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
|
||||
COMP( 1991?, ip2400, 0, 0, ip2400, interpro, sapphire_state, interpro, "Intergraph", "InterPro 2400", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
|
||||
COMP( 1993?, ip2500, 0, 0, ip2500, interpro, sapphire_state, interpro, "Intergraph", "InterPro 2500", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
|
||||
COMP( 1992, ip2700, 0, 0, ip2700, interpro, sapphire_state, interpro, "Intergraph", "InterPro 2700", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
|
||||
COMP( 1994, ip2800, 0, 0, ip2800, interpro, sapphire_state, interpro, "Intergraph", "InterPro 2800", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
|
||||
/* 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)
|
||||
|
@ -65,7 +65,6 @@ public:
|
||||
interpro_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag)
|
||||
, m_maincpu(*this, INTERPRO_CPU_TAG)
|
||||
, m_mmu(*this, INTERPRO_MMU_TAG)
|
||||
, m_ram(*this, RAM_TAG)
|
||||
, m_mcga(*this, INTERPRO_MCGA_TAG)
|
||||
, m_sga(*this, INTERPRO_SGA_TAG)
|
||||
@ -78,10 +77,10 @@ public:
|
||||
, m_scsi(*this, INTERPRO_SCSI_DEVICE_TAG)
|
||||
, m_eth(*this, INTERPRO_ETH_TAG)
|
||||
, m_ioga(*this, INTERPRO_IOGA_TAG)
|
||||
{ }
|
||||
{
|
||||
}
|
||||
|
||||
required_device<clipper_device> m_maincpu;
|
||||
required_device<cammu_device> m_mmu;
|
||||
required_device<ram_device> m_ram;
|
||||
|
||||
required_device<interpro_mcga_device> m_mcga;
|
||||
@ -96,7 +95,7 @@ public:
|
||||
required_device<i82586_base_device> m_eth;
|
||||
required_device<interpro_ioga_device> m_ioga;
|
||||
|
||||
DECLARE_DRIVER_INIT(interpro);
|
||||
DECLARE_DRIVER_INIT(common);
|
||||
|
||||
enum sreg_error_mask
|
||||
{
|
||||
@ -180,9 +179,17 @@ class turquoise_state : public interpro_state
|
||||
public:
|
||||
turquoise_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: interpro_state(mconfig, type, tag)
|
||||
{}
|
||||
, m_d_cammu(*this, INTERPRO_MMU_TAG "_d")
|
||||
, m_i_cammu(*this, INTERPRO_MMU_TAG "_i")
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
class sapphire_state : public interpro_state
|
||||
@ -190,14 +197,20 @@ class sapphire_state : public interpro_state
|
||||
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_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;
|
||||
|
||||
required_device<cammu_c4_device> m_mmu;
|
||||
|
||||
required_device<intel_28f010_device> m_flash_lo;
|
||||
required_device<intel_28f010_device> m_flash_hi;
|
||||
|
||||
virtual DECLARE_WRITE16_MEMBER(sreg_ctrl2_w) override;
|
||||
};
|
||||
|
||||
#endif // MAME_INCLUDES_INTERPRO_H
|
||||
|
@ -2,29 +2,44 @@
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
/*
|
||||
* An implementation of the Fairchild/Intergraph Cache and Memory Management Unit (CAMMU) designed for use with the CLIPPER CPU family.
|
||||
* An implementation of the Fairchild/Intergraph Cache and Memory Management
|
||||
* Unit (CAMMU) designed for use with the CLIPPER CPU family.
|
||||
*
|
||||
* Primary reference: http://bitsavers.trailing-edge.com/pdf/fairchild/clipper/CLIPPER%20C300%2032-Bit%20Compute%20Engine.pdf
|
||||
* The C100 and C300 designs used a pair of identical CAMMU devices, each
|
||||
* containing a cache, TLB and dynamic translation unit. One device was
|
||||
* configured and used for instruction memory, the other for data. It is
|
||||
* possible to write to multiple CAMMU devices sharing a common system bus by
|
||||
* using "global" register addresses.
|
||||
*
|
||||
* C400 designs initially implemented the memory management and cache functions
|
||||
* using discrete logic, later using a more highly integrated memory management
|
||||
* implementation, but still using discrete cache memory. In these systems, the
|
||||
* mmu is consolidated into a single logical unit handling both instruction and
|
||||
* data memory, with distinctly different program-visible architectures on the
|
||||
* C4I and C4E/T devices. Almost no documentation for these has been located.
|
||||
*
|
||||
* Primary reference: http://bitsavers.org/pdf/fairchild/clipper/CLIPPER%20C300%2032-Bit%20Compute%20Engine.pdf
|
||||
* Another reference: http://www.eecs.berkeley.edu/Pubs/TechRpts/1986/CSD-86-289.pdf
|
||||
*
|
||||
* This implementation is currently at a very early stage, and is only sufficient to handle the bare minimum of boot/diagnostic code.
|
||||
*
|
||||
* TODO
|
||||
* - almost everything
|
||||
* - refactor hardware tlb
|
||||
* - faults
|
||||
* - tlb
|
||||
* - fault register values
|
||||
* - alignment faults
|
||||
* - c3 protection faults
|
||||
* - hard-wired and dynamic tlb
|
||||
* - cache
|
||||
* - bus errors
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
#define VERBOSE 0
|
||||
#define DTU 1 // enable preliminary/incomplete address translation
|
||||
|
||||
#include "cammu.h"
|
||||
|
||||
#define LOG_GENERAL (1U << 0)
|
||||
#define LOG_ACCESS (1U << 1)
|
||||
#define LOG_DTU (1U << 2)
|
||||
|
||||
//#define VERBOSE (LOG_GENERAL | LOG_ACCESS | LOG_DTU)
|
||||
#include "logmacro.h"
|
||||
|
||||
// each variant of the cammu has different registers and a different addressing map
|
||||
DEVICE_ADDRESS_MAP_START(map, 32, cammu_c4t_device)
|
||||
AM_RANGE(0x008, 0x00b) AM_READWRITE(ram_line_r, ram_line_w)
|
||||
@ -75,28 +90,21 @@ DEVICE_ADDRESS_MAP_START(map, 32, cammu_c4i_device)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
DEVICE_ADDRESS_MAP_START(map, 32, cammu_c3_device)
|
||||
// the first AM_NOP in each range is in fact the TLB in the C3 CAMMU
|
||||
AM_RANGE(0x000, 0x0ff) AM_NOP // tlb
|
||||
AM_RANGE(0x104, 0x107) AM_READWRITE(s_pdo_r, s_pdo_w)
|
||||
AM_RANGE(0x108, 0x10b) AM_READWRITE(u_pdo_r, u_pdo_w)
|
||||
AM_RANGE(0x110, 0x113) AM_READWRITE(fault_r, fault_w)
|
||||
AM_RANGE(0x140, 0x143) AM_READWRITE(control_r, control_w)
|
||||
AM_RANGE(0x180, 0x183) AM_READWRITE(reset_r, reset_w)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
AM_RANGE(0x800, 0x8ff) AM_NOP
|
||||
AM_RANGE(0x904, 0x907) AM_READWRITE(d_s_pdo_r, d_s_pdo_w)
|
||||
AM_RANGE(0x908, 0x90b) AM_READWRITE(d_u_pdo_r, d_u_pdo_w)
|
||||
AM_RANGE(0x910, 0x913) AM_READWRITE(d_fault_r, d_fault_w)
|
||||
AM_RANGE(0x940, 0x943) AM_READWRITE(d_control_r, d_control_w)
|
||||
AM_RANGE(0x980, 0x983) AM_READWRITE(d_reset_r, d_reset_w)
|
||||
|
||||
AM_RANGE(0xa00, 0xaff) AM_NOP
|
||||
AM_RANGE(0xb04, 0xb07) AM_READWRITE(i_s_pdo_r, i_s_pdo_w)
|
||||
AM_RANGE(0xb08, 0xb0b) AM_READWRITE(i_u_pdo_r, i_u_pdo_w)
|
||||
AM_RANGE(0xb10, 0xb13) AM_READWRITE(i_fault_r, i_fault_w)
|
||||
AM_RANGE(0xb40, 0xb43) AM_READWRITE(i_control_r, i_control_w)
|
||||
AM_RANGE(0xb80, 0xb83) AM_READWRITE(i_reset_r, i_reset_w)
|
||||
|
||||
AM_RANGE(0xc00, 0xcff) AM_NOP
|
||||
AM_RANGE(0xd04, 0xd07) AM_WRITE(g_s_pdo_w)
|
||||
AM_RANGE(0xd08, 0xd0b) AM_WRITE(g_u_pdo_w)
|
||||
AM_RANGE(0xd10, 0xd13) AM_WRITE(g_fault_w)
|
||||
AM_RANGE(0xd40, 0xd43) AM_WRITE(g_control_w)
|
||||
AM_RANGE(0xd80, 0xd83) AM_WRITE(g_reset_w)
|
||||
DEVICE_ADDRESS_MAP_START(map_global, 32, cammu_c3_device)
|
||||
AM_RANGE(0x000, 0x0ff) AM_NOP // global tlb
|
||||
AM_RANGE(0x104, 0x107) AM_WRITE(g_s_pdo_w)
|
||||
AM_RANGE(0x108, 0x10b) AM_WRITE(g_u_pdo_w)
|
||||
AM_RANGE(0x110, 0x113) AM_WRITE(g_fault_w)
|
||||
AM_RANGE(0x140, 0x143) AM_WRITE(g_control_w)
|
||||
AM_RANGE(0x180, 0x183) AM_WRITE(g_reset_w)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
DEFINE_DEVICE_TYPE(CAMMU_C4T, cammu_c4t_device, "c4t", "C4E/C4T CAMMU")
|
||||
@ -104,48 +112,39 @@ 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)
|
||||
: cammu_c4_device(mconfig, CAMMU_C4T, tag, owner, clock, CID_C4T)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
: cammu_c4_device(mconfig, CAMMU_C4I, tag, owner, clock, CID_C4I)
|
||||
{
|
||||
}
|
||||
|
||||
cammu_c4_device::cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t 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_device(mconfig, type, tag, owner, clock)
|
||||
, m_control(cammu_id)
|
||||
{
|
||||
}
|
||||
|
||||
cammu_c3_device::cammu_c3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: cammu_device(mconfig, CAMMU_C3, tag, owner, clock)
|
||||
, m_control(CID_C3)
|
||||
, m_linked{ this }
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
void cammu_device::device_start()
|
||||
{
|
||||
m_ssw_func.resolve();
|
||||
|
||||
m_main_space = &space(0);
|
||||
m_io_space = &space(1);
|
||||
m_boot_space = &space(2);
|
||||
}
|
||||
|
||||
void cammu_device::device_reset()
|
||||
, 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)
|
||||
{
|
||||
}
|
||||
|
||||
@ -158,259 +157,342 @@ device_memory_interface::space_config_vector cammu_device::memory_space_config()
|
||||
};
|
||||
}
|
||||
|
||||
READ32_MEMBER(cammu_device::insn_r)
|
||||
void cammu_c3_device::static_add_linked(device_t &device, const char *const tag)
|
||||
{
|
||||
u32 ssw = m_ssw_func();
|
||||
u32 va = offset << 2;
|
||||
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()
|
||||
{
|
||||
}
|
||||
|
||||
void cammu_c4_device::device_start()
|
||||
{
|
||||
cammu_device::device_start();
|
||||
|
||||
save_item(NAME(m_s_pdo));
|
||||
save_item(NAME(m_u_pdo));
|
||||
save_item(NAME(m_control));
|
||||
|
||||
save_item(NAME(m_i_fault));
|
||||
save_item(NAME(m_fault_address_1));
|
||||
save_item(NAME(m_fault_address_2));
|
||||
save_item(NAME(m_fault_data_1_lo));
|
||||
save_item(NAME(m_fault_data_1_hi));
|
||||
save_item(NAME(m_fault_data_2_lo));
|
||||
save_item(NAME(m_fault_data_2_hi));
|
||||
}
|
||||
|
||||
void cammu_c4i_device::device_start()
|
||||
{
|
||||
cammu_c4_device::device_start();
|
||||
|
||||
save_item(NAME(m_reset));
|
||||
save_item(NAME(m_clr_s_data_tlb));
|
||||
save_item(NAME(m_clr_u_data_tlb));
|
||||
save_item(NAME(m_clr_s_insn_tlb));
|
||||
save_item(NAME(m_clr_u_insn_tlb));
|
||||
save_item(NAME(m_test_data));
|
||||
save_item(NAME(m_test_address));
|
||||
}
|
||||
|
||||
void cammu_c4t_device::device_start()
|
||||
{
|
||||
cammu_c4_device::device_start();
|
||||
|
||||
save_item(NAME(m_ram_line));
|
||||
save_item(NAME(m_htlb_offset));
|
||||
save_item(NAME(m_c4_bus_poll));
|
||||
save_item(NAME(m_bio_control));
|
||||
save_item(NAME(m_bio_address_tag));
|
||||
|
||||
save_item(NAME(m_cache_data_lo));
|
||||
save_item(NAME(m_cache_data_hi));
|
||||
save_item(NAME(m_cache_cpu_tag));
|
||||
save_item(NAME(m_cache_system_tag_valid));
|
||||
save_item(NAME(m_cache_system_tag));
|
||||
save_item(NAME(m_tlb_va_line));
|
||||
save_item(NAME(m_tlb_ra_line));
|
||||
}
|
||||
|
||||
void cammu_c3_device::device_start()
|
||||
{
|
||||
cammu_device::device_start();
|
||||
|
||||
save_item(NAME(m_s_pdo));
|
||||
save_item(NAME(m_u_pdo));
|
||||
save_item(NAME(m_fault));
|
||||
save_item(NAME(m_control));
|
||||
save_item(NAME(m_reset));
|
||||
}
|
||||
|
||||
void cammu_c3_device::device_reset()
|
||||
{
|
||||
cammu_device::device_reset();
|
||||
|
||||
m_control = (m_control & CNTL_CID) | (CNTL_ATE | UST_3 | CNTL_EWIR | CNTL_EWIW | CNTL_EWCW | CNTL_EP);
|
||||
m_reset = 0;
|
||||
}
|
||||
|
||||
READ32_MEMBER(cammu_device::read)
|
||||
{
|
||||
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;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
WRITE32_MEMBER(cammu_device::write)
|
||||
{
|
||||
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;
|
||||
|
||||
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());
|
||||
|
||||
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
|
||||
|
||||
// in supervisor mode, the first 8 pages are always mapped via the hard-wired tlb
|
||||
if ((ssw & 0x40000000) == 0 && (va & ~0x7fff) == 0)
|
||||
if (!user && (virtual_address & ~0x7fff) == 0)
|
||||
{
|
||||
switch (va & 0xf000)
|
||||
switch (virtual_address & 0x7000)
|
||||
{
|
||||
case 0x0000:
|
||||
case 0x1000:
|
||||
case 0x2000:
|
||||
case 0x3000:
|
||||
// pages 0-3: main space pages 0-3
|
||||
return m_main_space->read_dword(va, mem_mask);
|
||||
*physical_address = virtual_address & 0x3fff;
|
||||
return m_main_space;
|
||||
|
||||
case 0x4000:
|
||||
case 0x5000:
|
||||
// pages 4-5: i/o space pages 0-1
|
||||
return m_io_space->read_dword(va & 0x1fff, mem_mask);
|
||||
*physical_address = virtual_address & 0x1fff;
|
||||
return m_io_space;
|
||||
|
||||
case 0x6000:
|
||||
case 0x7000:
|
||||
// pages 6-7: boot space pages 0-1
|
||||
return m_boot_space->read_dword(va & 0x1fff, mem_mask);
|
||||
*physical_address = virtual_address & 0x1fff;
|
||||
return m_boot_space;
|
||||
}
|
||||
}
|
||||
|
||||
// if not in mapped mode, default to main memory space
|
||||
if ((ssw & 0x04000000) == 0)
|
||||
return m_main_space->read_dword(va);
|
||||
|
||||
#if DTU
|
||||
// get the page table entry
|
||||
u32 pte = get_pte(va, ssw & 0x40000000, false);
|
||||
|
||||
// translate the address
|
||||
u32 ra = (pte & 0xfffff000) | (va & 0xfff);
|
||||
|
||||
// execute the read based on the system tag
|
||||
switch ((pte & 0xe00) >> 9)
|
||||
// if not in mapped mode, use unmapped system tag
|
||||
if ((ssw & SSW_M) == 0)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return m_main_space->read_dword(ra, mem_mask);
|
||||
*physical_address = virtual_address;
|
||||
|
||||
case 4:
|
||||
return m_io_space->read_dword(ra, mem_mask);
|
||||
|
||||
case 5:
|
||||
return m_boot_space->read_dword(ra, mem_mask);
|
||||
|
||||
case 6: // cache purge
|
||||
case 7: // main memory, slave mode
|
||||
fatalerror("system tag %d not supported %s\n", (pte & 0xe00) >> 9, machine().describe_context().c_str());
|
||||
return get_ust_space();
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
// FIXME: currently maps addresses with upper bits 0x00 or 0x7f1 to main memory and everything else to I/O
|
||||
if ((va & 0xff000000) == 0x00000000 || (va & 0xfff00000) == 0x7f100000)
|
||||
return m_main_space->read_dword(va, mem_mask);
|
||||
else
|
||||
return m_io_space->read_dword(va, mem_mask);
|
||||
#endif
|
||||
}
|
||||
// get the page table entry
|
||||
const u32 pte = get_pte(virtual_address, user);
|
||||
|
||||
READ32_MEMBER(cammu_device::data_r)
|
||||
{
|
||||
u32 ssw = m_ssw_func();
|
||||
u32 va = offset << 2;
|
||||
|
||||
// in supervisor mode (and not user data mode), the first 8 pages are always mapped via the hard-wired tlb
|
||||
if (((ssw & 0x50000000) == 0) && ((va & ~0x7fff) == 0))
|
||||
// check for page faults
|
||||
if (pte & PTE_F)
|
||||
{
|
||||
switch (va & 0xf000)
|
||||
if (!machine().side_effect_disabled())
|
||||
{
|
||||
case 0x0000:
|
||||
case 0x1000:
|
||||
case 0x2000:
|
||||
case 0x3000:
|
||||
// pages 0-3: main space pages 0-3
|
||||
return m_main_space->read_dword(va, mem_mask);
|
||||
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());
|
||||
|
||||
case 0x4000:
|
||||
case 0x5000:
|
||||
// pages 4-5: i/o space pages 0-1
|
||||
return m_io_space->read_dword(va & 0x1fff, mem_mask);
|
||||
|
||||
case 0x6000:
|
||||
case 0x7000:
|
||||
// pages 6-7: boot space pages 0-1
|
||||
return m_boot_space->read_dword(va & 0x1fff, mem_mask);
|
||||
set_fault_address(virtual_address);
|
||||
m_exception_func(mode == ACCESS_X ? EXCEPTION_I_PAGE_FAULT : EXCEPTION_D_PAGE_FAULT);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// if not in mapped mode, default to main memory space
|
||||
if ((ssw & 0x04000000) == 0)
|
||||
return m_main_space->read_dword(va);
|
||||
// check for protection level faults
|
||||
if (!machine().side_effect_disabled() && !get_access(mode, pte, 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());
|
||||
|
||||
#if DTU
|
||||
// get the page table entry
|
||||
u32 pte = get_pte(va, ssw & 0x50000000, space.spacenum() == AS_DATA);
|
||||
set_fault_address(virtual_address);
|
||||
m_exception_func(
|
||||
mode == ACCESS_X ? EXCEPTION_I_EXECUTE_PROTECT_FAULT :
|
||||
mode == ACCESS_R ? EXCEPTION_D_READ_PROTECT_FAULT :
|
||||
EXCEPTION_D_WRITE_PROTECT_FAULT);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// translate the address
|
||||
u32 ra = (pte & 0xfffff000) | (va & 0xfff);
|
||||
*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);
|
||||
|
||||
// execute the read based on the system tag
|
||||
switch ((pte & 0xe00) >> 9)
|
||||
// return the physical space based on the system tag
|
||||
switch (pte & PTE_ST)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return m_main_space->read_dword(ra, mem_mask);
|
||||
case ST_0:
|
||||
case ST_1:
|
||||
case ST_2:
|
||||
case ST_3:
|
||||
// main memory space
|
||||
return m_main_space;
|
||||
|
||||
case 4:
|
||||
return m_io_space->read_dword(ra, mem_mask);
|
||||
case ST_4:
|
||||
// i/o space
|
||||
return m_io_space;
|
||||
|
||||
case 5:
|
||||
return m_boot_space->read_dword(ra, mem_mask);
|
||||
case ST_5:
|
||||
// boot space
|
||||
return m_boot_space;
|
||||
|
||||
case 6: // cache purge
|
||||
case 7: // main memory, slave mode
|
||||
fatalerror("data_r: system tag %d not supported at %s\n", (pte & 0xe00) >> 9, machine().describe_context().c_str());
|
||||
case ST_6:
|
||||
// cache purge
|
||||
case ST_7:
|
||||
// main memory, slave mode
|
||||
if (!machine().side_effect_disabled())
|
||||
fatalerror("%s page table entry system tag %d not supported\n",
|
||||
mode == ACCESS_X ? "instruction" : "data", (pte & PTE_ST) >> 9);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
// FIXME: currently maps addresses with upper bits 0x00 or 0x7f1 to main memory and everything else to I/O
|
||||
if ((va & 0xff000000) == 0x00000000 || (va & 0xfff00000) == 0x7f100000)
|
||||
return m_main_space->read_dword(va, mem_mask);
|
||||
else
|
||||
return m_io_space->read_dword(va, mem_mask);
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WRITE32_MEMBER(cammu_device::data_w)
|
||||
// return the page table entry for a given virtual address
|
||||
u32 cammu_device::get_pte(const u32 va, const bool user)
|
||||
{
|
||||
u32 ssw = m_ssw_func();
|
||||
u32 va = offset << 2;
|
||||
|
||||
// in supervisor mode (and not user data mode), the first 8 pages are always mapped via the hard-wired tlb
|
||||
if (((ssw & 0x50000000) == 0) && ((va & ~0x7fff) == 0))
|
||||
const u32 tlb_index = user ? 1 : 0;
|
||||
if ((va & ~CAMMU_PAGE_MASK) != m_tlb[tlb_index].va)
|
||||
{
|
||||
switch (va & 0xf000)
|
||||
{
|
||||
case 0x0000:
|
||||
case 0x1000:
|
||||
case 0x2000:
|
||||
case 0x3000:
|
||||
// pages 0-3: main space pages 0-3
|
||||
m_main_space->write_dword(va, data, mem_mask);
|
||||
return;
|
||||
// get page table directory origin from user or supervisor pdo register
|
||||
const u32 pdo = get_pdo(user);
|
||||
|
||||
case 0x4000:
|
||||
case 0x5000:
|
||||
// pages 4-5: i/o space pages 0-1
|
||||
m_io_space->write_dword(va & 0x1fff, data, mem_mask);
|
||||
return;
|
||||
// get page table directory index from top 12 bits of virtual address
|
||||
const u32 ptdi = (va & VA_PTDI) >> 20;
|
||||
|
||||
case 0x6000:
|
||||
case 0x7000:
|
||||
// pages 6-7: boot space pages 0-1
|
||||
m_boot_space->write_dword(va & 0x1fff, data, mem_mask);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// fetch page table directory entry
|
||||
const u32 ptde = m_main_space->read_dword(pdo | ptdi);
|
||||
|
||||
// if not in mapped mode, default to main memory space
|
||||
if ((ssw & 0x04000000) == 0)
|
||||
{
|
||||
m_main_space->write_dword(va, data, mem_mask);
|
||||
return;
|
||||
}
|
||||
LOGMASKED(LOG_DTU, "get_pte pdo 0x%08x ptdi 0x%08x ptde 0x%08x\n", pdo, ptdi, ptde);
|
||||
|
||||
#if DTU
|
||||
// get the page table entry
|
||||
u32 pte = get_pte(va, ssw & 0x50000000, space.spacenum() == AS_DATA);
|
||||
// check for page table directory entry fault
|
||||
if (ptde & PTDE_F)
|
||||
return PTE_F;
|
||||
|
||||
// translate the address
|
||||
u32 ra = (pte & 0xfffff000) | (va & 0xfff);
|
||||
// get the page table origin from the page table directory entry
|
||||
const u32 pto = ptde & PTDE_PTO;
|
||||
|
||||
// execute the read based on the system tag
|
||||
switch ((pte & 0xe00) >> 9)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
m_main_space->write_dword(ra, data, mem_mask);
|
||||
break;
|
||||
// get the page table index from the middle 12 bits of the virtual address
|
||||
const u32 pti = (va & VA_PTI) >> 10;
|
||||
|
||||
case 4:
|
||||
m_io_space->write_dword(ra, data, mem_mask);
|
||||
break;
|
||||
// fetch page table entry
|
||||
const u32 pte = m_main_space->read_dword(pto | pti);
|
||||
|
||||
case 5:
|
||||
m_boot_space->write_dword(ra, data, mem_mask);
|
||||
break;
|
||||
LOGMASKED(LOG_DTU, "get_pte pto 0x%08x pti 0x%08x pte 0x%08x\n", pto, pti, pte);
|
||||
|
||||
case 6: // cache purge
|
||||
case 7: // main memory, slave mode
|
||||
fatalerror("data_w: system tag %d not supported at %s\n", (pte & 0xe00) >> 9, machine().describe_context().c_str());
|
||||
break;
|
||||
}
|
||||
#else
|
||||
// FIXME: currently maps addresses with upper bits 0x00 or 0x7f1 to main memory and everything else to I/O
|
||||
if ((va & 0xff000000) == 0x00000000 || (va & 0xfff00000) == 0x7f100000)
|
||||
m_main_space->write_dword(va, data, mem_mask);
|
||||
else
|
||||
m_io_space->write_dword(va, data, mem_mask);
|
||||
#endif
|
||||
}
|
||||
// check for page table entry fault
|
||||
if (pte & PTE_F)
|
||||
return PTE_F;
|
||||
|
||||
u32 cammu_c4_device::get_pte(u32 va, int user, bool data)
|
||||
{
|
||||
u32 tlb_index = (user ? 2 : 0) + (data ? 1 : 0);
|
||||
if ((va & 0xfffff000) != m_tlb[tlb_index].va)
|
||||
{
|
||||
// return the page table entry for a given virtual address
|
||||
u32 pdo = user ? m_u_pdo : m_s_pdo;
|
||||
|
||||
u32 pto = m_main_space->read_dword(pdo | (va & 0xffc00000) >> 20);
|
||||
if (pto & 0x1)
|
||||
fatalerror("can't deal with pto faults va 0x%08x %s\n", va, machine().describe_context().c_str());
|
||||
|
||||
u32 pte = m_main_space->read_dword((pto & 0xfffff000) | (va & 0x003ff000) >> 10);
|
||||
if (pte & 0x1)
|
||||
fatalerror("can't deal with pte faults va 0x%08x %s\n", va, machine().describe_context().c_str());
|
||||
|
||||
m_tlb[tlb_index].va = va & 0xfffff000;
|
||||
// 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;
|
||||
}
|
||||
|
||||
u32 cammu_c3_device::get_pte(u32 va, int user, bool data)
|
||||
address_space *cammu_c4i_device::get_ust_space() const
|
||||
{
|
||||
// return the page table entry for a given virtual address
|
||||
u32 pdo = user ? (data ? m_d_u_pdo : m_i_u_pdo) : (data ? m_d_s_pdo : m_i_s_pdo);
|
||||
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;
|
||||
}
|
||||
|
||||
u32 pto = m_main_space->read_dword(pdo | (va & 0xffc00000) >> 20);
|
||||
if (pto & 0x1)
|
||||
fatalerror("can't deal with pto faults va 0x%08x %s\n", va, machine().describe_context().c_str());
|
||||
|
||||
u32 pte = m_main_space->read_dword((pto & 0xfffff000) | (va & 0x003ff000) >> 10);
|
||||
if (pte & 0x1)
|
||||
fatalerror("can't deal with pte faults va 0x%08x %s\n", va, machine().describe_context().c_str());
|
||||
|
||||
return pte;
|
||||
return m_main_space;
|
||||
}
|
||||
|
||||
bool cammu_c4_device::get_access(const access_t 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;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cammu_c3_device::get_access(const access_t 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 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;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// C100/C300 CAMMU protection level matrix
|
||||
const u8 cammu_c3_device::i_cammu_column[] = { 1, 1, 0, 0, 1, 1, 0, 0, 3, 3, 2, 2, 3, 3, 2, 2 };
|
||||
const u8 cammu_c3_device::d_cammu_column[] = { 1, 1, 0, 0, 3, 2, 3, 2, 3, 3, 2, 2, 3, 3, 2, 2 };
|
||||
|
||||
const cammu_c3_device::c3_access_t cammu_c3_device::cammu_matrix[][16] =
|
||||
{
|
||||
{ RW, RW, RW, RW, RW, RW, RW, RWE, RE, R, R, R, N, N, N, N },
|
||||
{ N, RW, RW, RW, RW, RW, R, RWE, N, RE, R, R, RE, N, N, N },
|
||||
{ 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 }
|
||||
};
|
||||
|
||||
|
||||
|
@ -9,17 +9,99 @@
|
||||
#define MCFG_CAMMU_SSW_CB(_sswcb) \
|
||||
devcb = &cammu_device::static_set_ssw_callback(*device, DEVCB_##_sswcb);
|
||||
|
||||
#define MCFG_CAMMU_EXCEPTION_CB(_exceptioncb) \
|
||||
devcb = &cammu_device::static_set_exception_callback(*device, DEVCB_##_exceptioncb);
|
||||
|
||||
#define MCFG_CAMMU_LINK(_tag) \
|
||||
cammu_c3_device::static_add_linked(*device, _tag);
|
||||
|
||||
class cammu_device : public device_t, public device_memory_interface
|
||||
{
|
||||
public:
|
||||
template <class Object> static devcb_base &static_set_ssw_callback(device_t &device, Object &&cb) { return downcast<cammu_device &>(device).m_ssw_func.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> static devcb_base &static_set_exception_callback(device_t &device, Object &&cb) { return downcast<cammu_device &>(device).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
|
||||
};
|
||||
|
||||
enum ptde_mask : u32
|
||||
{
|
||||
PTDE_F = 0x00000001, // page fault
|
||||
PTDE_PTO = 0xfffff000 // page table origin
|
||||
};
|
||||
|
||||
enum pte_mask : u32
|
||||
{
|
||||
PTE_F = 0x00000001, // page fault
|
||||
PTE_R = 0x00000002, // referenced flag
|
||||
PTE_D = 0x00000004, // dirty flag
|
||||
PTE_PL = 0x00000078, // protection level
|
||||
PTE_S = 0x00000180, // system reserved
|
||||
PTE_ST = 0x00000e00, // system tag
|
||||
PTE_RA = 0xfffff000, // real address
|
||||
|
||||
PTE_CW = 0x00000040, // copy on write (c400)
|
||||
PTE_NDREF = 0x00000080, // secondary reference (software) / copy on write (fault)?
|
||||
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
|
||||
};
|
||||
|
||||
enum va_mask : u32
|
||||
{
|
||||
VA_POFS = 0x00000fff, // page offset
|
||||
VA_PTI = 0x003ff000, // page table index
|
||||
VA_PTDI = 0xffc00000 // page table directory index
|
||||
};
|
||||
|
||||
virtual DECLARE_ADDRESS_MAP(map, 32) = 0;
|
||||
|
||||
DECLARE_READ32_MEMBER(insn_r);
|
||||
|
||||
DECLARE_READ32_MEMBER(data_r);
|
||||
DECLARE_WRITE32_MEMBER(data_w);
|
||||
DECLARE_READ32_MEMBER(read);
|
||||
DECLARE_WRITE32_MEMBER(write);
|
||||
|
||||
protected:
|
||||
cammu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
@ -30,59 +112,82 @@ protected:
|
||||
|
||||
// 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;
|
||||
|
||||
virtual u32 get_pte(u32 va, int user, bool data) = 0;
|
||||
enum access_t
|
||||
{
|
||||
ACCESS_R = 1,
|
||||
ACCESS_W = 2,
|
||||
ACCESS_X = 3
|
||||
};
|
||||
|
||||
address_space *translate_address(const offs_t virtual_address, const access_t mode, offs_t *physical_address);
|
||||
|
||||
u32 get_pte(const u32 va, const bool user);
|
||||
|
||||
virtual bool get_access(const access_t 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 void set_fault_address(const u32 va) = 0;
|
||||
|
||||
private:
|
||||
address_space_config m_main_space_config;
|
||||
address_space_config m_io_space_config;
|
||||
address_space_config m_boot_space_config;
|
||||
|
||||
protected:
|
||||
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[4];
|
||||
}
|
||||
m_tlb[2];
|
||||
|
||||
private:
|
||||
devcb_read32 m_ssw_func;
|
||||
};
|
||||
|
||||
class cammu_c4_device : public cammu_device
|
||||
{
|
||||
public:
|
||||
cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
DECLARE_READ32_MEMBER(s_pdo_r) const { 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) const { return m_u_pdo; }
|
||||
DECLARE_WRITE32_MEMBER(u_pdo_w) { m_u_pdo = ((m_u_pdo & ~mem_mask) | (data & mem_mask)) & PDO_MASK; }
|
||||
|
||||
DECLARE_READ32_MEMBER(s_pdo_r) { return m_s_pdo; }
|
||||
DECLARE_WRITE32_MEMBER(s_pdo_w) { m_s_pdo = data; }
|
||||
DECLARE_READ32_MEMBER(u_pdo_r) { return m_u_pdo; }
|
||||
DECLARE_WRITE32_MEMBER(u_pdo_w) { m_u_pdo = data; }
|
||||
|
||||
virtual DECLARE_READ32_MEMBER(control_r) = 0;
|
||||
virtual DECLARE_READ32_MEMBER(control_r) const = 0;
|
||||
virtual DECLARE_WRITE32_MEMBER(control_w) = 0;
|
||||
|
||||
DECLARE_READ32_MEMBER(i_fault_r) { return m_i_fault; }
|
||||
DECLARE_READ32_MEMBER(i_fault_r) const { return m_i_fault; }
|
||||
DECLARE_WRITE32_MEMBER(i_fault_w) { m_i_fault = data; }
|
||||
DECLARE_READ32_MEMBER(fault_address_1_r) { return m_fault_address_1; }
|
||||
DECLARE_READ32_MEMBER(fault_address_1_r) const { return m_fault_address_1; }
|
||||
DECLARE_WRITE32_MEMBER(fault_address_1_w) { m_fault_address_1 = data; }
|
||||
DECLARE_READ32_MEMBER(fault_address_2_r) { return m_fault_address_2; }
|
||||
DECLARE_READ32_MEMBER(fault_address_2_r) const { return m_fault_address_2; }
|
||||
DECLARE_WRITE32_MEMBER(fault_address_2_w) { m_fault_address_2 = data; }
|
||||
DECLARE_READ32_MEMBER(fault_data_1_lo_r) { return m_fault_data_1_lo; }
|
||||
DECLARE_READ32_MEMBER(fault_data_1_lo_r) const { return m_fault_data_1_lo; }
|
||||
DECLARE_WRITE32_MEMBER(fault_data_1_lo_w) { m_fault_data_1_lo = data; }
|
||||
DECLARE_READ32_MEMBER(fault_data_1_hi_r) { return m_fault_data_1_hi; }
|
||||
DECLARE_READ32_MEMBER(fault_data_1_hi_r) const { return m_fault_data_1_hi; }
|
||||
DECLARE_WRITE32_MEMBER(fault_data_1_hi_w) { m_fault_data_1_hi = data; }
|
||||
DECLARE_READ32_MEMBER(fault_data_2_lo_r) { return m_fault_data_2_lo; }
|
||||
DECLARE_READ32_MEMBER(fault_data_2_lo_r) const { return m_fault_data_2_lo; }
|
||||
DECLARE_WRITE32_MEMBER(fault_data_2_lo_w) { m_fault_data_2_lo = data; }
|
||||
DECLARE_READ32_MEMBER(fault_data_2_hi_r) { return m_fault_data_2_hi; }
|
||||
DECLARE_READ32_MEMBER(fault_data_2_hi_r) const { return m_fault_data_2_hi; }
|
||||
DECLARE_WRITE32_MEMBER(fault_data_2_hi_w) { m_fault_data_2_hi = data; }
|
||||
|
||||
protected:
|
||||
u32 get_pte(u32 va, int user, bool data) override;
|
||||
cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 cammu_id);
|
||||
|
||||
virtual void device_start() override;
|
||||
|
||||
virtual bool get_access(const access_t 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; }
|
||||
|
||||
u32 m_s_pdo;
|
||||
u32 m_u_pdo;
|
||||
@ -104,36 +209,73 @@ public:
|
||||
|
||||
virtual DECLARE_ADDRESS_MAP(map, 32) override;
|
||||
|
||||
DECLARE_READ32_MEMBER(ram_line_r) { return m_ram_line; }
|
||||
DECLARE_READ32_MEMBER(ram_line_r) const { return m_ram_line; }
|
||||
DECLARE_WRITE32_MEMBER(ram_line_w) { m_ram_line = data; }
|
||||
|
||||
DECLARE_READ32_MEMBER(htlb_offset_r) { return m_htlb_offset; }
|
||||
DECLARE_READ32_MEMBER(htlb_offset_r) const { return m_htlb_offset; }
|
||||
DECLARE_WRITE32_MEMBER(htlb_offset_w) { m_htlb_offset = data; }
|
||||
|
||||
DECLARE_READ32_MEMBER(c4_bus_poll_r) { return m_c4_bus_poll; }
|
||||
DECLARE_READ32_MEMBER(c4_bus_poll_r) const { return m_c4_bus_poll; }
|
||||
DECLARE_WRITE32_MEMBER(c4_bus_poll_w) { m_c4_bus_poll = data; }
|
||||
virtual DECLARE_READ32_MEMBER(control_r) override { return m_control | 0x00000000; }
|
||||
virtual DECLARE_WRITE32_MEMBER(control_w) override { m_control = data & 0x00ffffff; }
|
||||
DECLARE_READ32_MEMBER(bio_control_r) { return m_bio_control; }
|
||||
|
||||
enum control_mask : u32
|
||||
{
|
||||
CNTL_RUV = 0x00000001, // reset user valid
|
||||
CNTL_RSV = 0x00000002, // reset supervisor valid
|
||||
CNTL_DBWR = 0x00000004, // disable bus watch read
|
||||
CNTL_ATD = 0x00000008, // alignment trap disable
|
||||
CNTL_UST = 0x00000030, // unmapped system tag
|
||||
CNTL_IOTS = 0x00000040, // i/o tag select
|
||||
CNTL_UVS = 0x00000080, // user valid status
|
||||
CNTL_PB = 0x00000100, // purge busy
|
||||
CNTL_CICT = 0x00000200, // clear i-side cache tags
|
||||
CNTL_CFR = 0x00000400, // clear trap registers
|
||||
CNTL_HTLBD = 0x00000800, // htlb disable
|
||||
CNTL_CDCT = 0x00001000, // clear d-side cache tags
|
||||
CNTL_CID = 0xff000000 // cammu id
|
||||
};
|
||||
|
||||
enum control_ust_mask : u32
|
||||
{
|
||||
UST_NCA = 0x00, // unmapped system tag, noncacheable
|
||||
UST_PWT = 0x10, // unmapped system tag, write through
|
||||
UST_PCB = 0x20, // unmapped system tag, copy back
|
||||
UST_PGE = 0x30 // unmapped system tag, purge mode
|
||||
};
|
||||
|
||||
enum control_cid_mask : u32
|
||||
{
|
||||
CID_C4T = 0x00000000 // unknown
|
||||
};
|
||||
|
||||
virtual DECLARE_READ32_MEMBER(control_r) const override { return m_control; }
|
||||
virtual DECLARE_WRITE32_MEMBER(control_w) override { m_control = ((m_control & (~mem_mask | CNTL_CID)) | (data & (mem_mask & ~CNTL_CID))); }
|
||||
DECLARE_READ32_MEMBER(bio_control_r) const { return m_bio_control; }
|
||||
DECLARE_WRITE32_MEMBER(bio_control_w) { m_bio_control = data; }
|
||||
DECLARE_READ32_MEMBER(bio_address_tag_r) { return m_bio_address_tag; }
|
||||
DECLARE_READ32_MEMBER(bio_address_tag_r) const { return m_bio_address_tag; }
|
||||
DECLARE_WRITE32_MEMBER(bio_address_tag_w) { m_bio_address_tag = data; }
|
||||
|
||||
DECLARE_READ32_MEMBER(cache_data_lo_r) { return m_cache_data_lo; }
|
||||
DECLARE_READ32_MEMBER(cache_data_lo_r) const { return m_cache_data_lo; }
|
||||
DECLARE_WRITE32_MEMBER(cache_data_lo_w) { m_cache_data_lo = data; }
|
||||
DECLARE_READ32_MEMBER(cache_data_hi_r) { return m_cache_data_hi; }
|
||||
DECLARE_READ32_MEMBER(cache_data_hi_r) const { return m_cache_data_hi; }
|
||||
DECLARE_WRITE32_MEMBER(cache_data_hi_w) { m_cache_data_hi = data; }
|
||||
DECLARE_READ32_MEMBER(cache_cpu_tag_r) { return m_cache_cpu_tag; }
|
||||
DECLARE_READ32_MEMBER(cache_cpu_tag_r) const { return m_cache_cpu_tag; }
|
||||
DECLARE_WRITE32_MEMBER(cache_cpu_tag_w) { m_cache_cpu_tag = data; }
|
||||
DECLARE_READ32_MEMBER(cache_system_tag_valid_r) { return m_cache_system_tag_valid; }
|
||||
DECLARE_READ32_MEMBER(cache_system_tag_valid_r) const { return m_cache_system_tag_valid; }
|
||||
DECLARE_WRITE32_MEMBER(cache_system_tag_valid_w) { m_cache_system_tag_valid = data; }
|
||||
DECLARE_READ32_MEMBER(cache_system_tag_r) { return m_cache_system_tag; }
|
||||
DECLARE_READ32_MEMBER(cache_system_tag_r) const { return m_cache_system_tag; }
|
||||
DECLARE_WRITE32_MEMBER(cache_system_tag_w) { m_cache_system_tag = data; }
|
||||
DECLARE_READ32_MEMBER(tlb_va_line_r) { return m_tlb_va_line; }
|
||||
DECLARE_READ32_MEMBER(tlb_va_line_r) const { return m_tlb_va_line; }
|
||||
DECLARE_WRITE32_MEMBER(tlb_va_line_w) { m_tlb_va_line = data; }
|
||||
DECLARE_READ32_MEMBER(tlb_ra_line_r) { return m_tlb_ra_line; }
|
||||
DECLARE_READ32_MEMBER(tlb_ra_line_r) const { return m_tlb_ra_line; }
|
||||
DECLARE_WRITE32_MEMBER(tlb_ra_line_w) { m_tlb_ra_line = data; }
|
||||
|
||||
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; }
|
||||
|
||||
private:
|
||||
u32 m_ram_line;
|
||||
u32 m_htlb_offset;
|
||||
@ -157,27 +299,83 @@ public:
|
||||
|
||||
virtual DECLARE_ADDRESS_MAP(map, 32) override;
|
||||
|
||||
virtual DECLARE_READ32_MEMBER(control_r) override { return m_control | 0x02000000; }
|
||||
virtual DECLARE_WRITE32_MEMBER(control_w) override { m_control = data & 0x00ffffff; }
|
||||
enum control_mask : u32
|
||||
{
|
||||
CNTL_LRAS = 0x00000001, // tlb line replacement
|
||||
CNTL_BWWD = 0x00000002, // buswatch write disable
|
||||
CNTL_BWRD = 0x00000004, // buswatch read disable
|
||||
CNTL_FSR = 0x00000010, // fake system response
|
||||
CNTL_ATD = 0x00000100, // alignment trap disable
|
||||
CNTL_UMM = 0x00003000, // unmapped mode address space select
|
||||
CNTL_POLL = 0x00030000, // poll bus signals
|
||||
CNTL_BM = 0x00040000, // burst mode address space select
|
||||
CNTL_PZBS = 0x00080000, // page 0 boot select
|
||||
CNTL_CRR = 0x00700000, // cache memory refresh rate
|
||||
CNTL_CID = 0xff000000 // cammu identification
|
||||
};
|
||||
|
||||
DECLARE_READ32_MEMBER(reset_r) { return m_reset; }
|
||||
enum control_umm_mask : u32
|
||||
{
|
||||
UMM_MM = 0x00000000, // mm space, noncacheable
|
||||
UMM_MMRIO = 0x00001000, // mm or i/o space, noncacheable
|
||||
UMM_IO = 0x00002000 // i/o space noncacheable
|
||||
};
|
||||
|
||||
enum control_crr_mask : u32
|
||||
{
|
||||
CRR_GT131 = 0x00000000, // clock rate over 131 MHz
|
||||
CRR_GT66 = 0x00100000, // clock rate over 66 MHz
|
||||
CRR_GT33 = 0x00200000, // clock rate over 33 MHz
|
||||
CRR_GT8 = 0x00300000, // clock rate over 8 MHz
|
||||
CRR_GT2 = 0x00400000, // clock rate over 2 MHz
|
||||
CRR_GT1 = 0x00500000, // clock rate over 1 MHz
|
||||
CRR_GTHALF = 0x00600000, // clock rate over 0.5 MHz
|
||||
CRR_OFF = 0x00700000, // refresh off
|
||||
};
|
||||
|
||||
enum control_cid_mask : u32
|
||||
{
|
||||
CID_C4I = 0x02000000 // c4i cammu identification
|
||||
};
|
||||
|
||||
virtual DECLARE_READ32_MEMBER(control_r) const override { return m_control; }
|
||||
virtual DECLARE_WRITE32_MEMBER(control_w) override { m_control = ((m_control & (~mem_mask | CNTL_CID)) | (data & (mem_mask & ~CNTL_CID))); }
|
||||
|
||||
enum reset_mask : u32
|
||||
{
|
||||
RESET_CDCT = 0x00000001, // clear data cache tags
|
||||
RESET_RDUV = 0x00000100, // reset all d-side uv flags
|
||||
RESET_RDSV = 0x00001000, // reset all d-side sv flags
|
||||
RESET_CICT = 0x00010000, // clear ins. cache tags
|
||||
RESET_RIUV = 0x01000000, // reset all i-side uv flags
|
||||
RESET_RISV = 0x10000000, // reset all i-side sv flags
|
||||
RESET_FLUSH = 0x40000000, // flush out burst io buffer
|
||||
RESET_CFR = 0x80000000 // clear fault registers
|
||||
};
|
||||
DECLARE_READ32_MEMBER(reset_r) const { return m_reset; }
|
||||
DECLARE_WRITE32_MEMBER(reset_w) { m_reset = data; }
|
||||
|
||||
DECLARE_READ32_MEMBER(clr_s_data_tlb_r) { return m_clr_s_data_tlb; }
|
||||
DECLARE_READ32_MEMBER(clr_s_data_tlb_r) const { return m_clr_s_data_tlb; }
|
||||
DECLARE_WRITE32_MEMBER(clr_s_data_tlb_w) { m_clr_s_data_tlb = data; }
|
||||
DECLARE_READ32_MEMBER(clr_u_data_tlb_r) { return m_clr_u_data_tlb; }
|
||||
DECLARE_READ32_MEMBER(clr_u_data_tlb_r) const { return m_clr_u_data_tlb; }
|
||||
DECLARE_WRITE32_MEMBER(clr_u_data_tlb_w) { m_clr_u_data_tlb = data; }
|
||||
DECLARE_READ32_MEMBER(clr_s_insn_tlb_r) { return m_clr_s_insn_tlb; }
|
||||
DECLARE_READ32_MEMBER(clr_s_insn_tlb_r) const { return m_clr_s_insn_tlb; }
|
||||
DECLARE_WRITE32_MEMBER(clr_s_insn_tlb_w) { m_clr_s_insn_tlb = data; }
|
||||
DECLARE_READ32_MEMBER(clr_u_insn_tlb_r) { return m_clr_u_insn_tlb; }
|
||||
DECLARE_READ32_MEMBER(clr_u_insn_tlb_r) const { return m_clr_u_insn_tlb; }
|
||||
DECLARE_WRITE32_MEMBER(clr_u_insn_tlb_w) { m_clr_u_insn_tlb = data; }
|
||||
|
||||
DECLARE_READ32_MEMBER(test_data_r) { return m_test_data; }
|
||||
DECLARE_READ32_MEMBER(test_data_r) const { return m_test_data; }
|
||||
DECLARE_WRITE32_MEMBER(test_data_w) { m_test_data = data; }
|
||||
|
||||
DECLARE_READ32_MEMBER(test_address_r) { return m_test_address; }
|
||||
DECLARE_READ32_MEMBER(test_address_r) const { return m_test_address; }
|
||||
DECLARE_WRITE32_MEMBER(test_address_w) { m_test_address = data; }
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
u32 m_reset;
|
||||
u32 m_clr_s_data_tlb;
|
||||
@ -193,50 +391,88 @@ 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 DECLARE_ADDRESS_MAP(map, 32) override;
|
||||
virtual DECLARE_ADDRESS_MAP(map_global, 32);
|
||||
|
||||
DECLARE_READ32_MEMBER(d_s_pdo_r) { return m_d_s_pdo; }
|
||||
DECLARE_WRITE32_MEMBER(d_s_pdo_w) { m_d_s_pdo = data; }
|
||||
DECLARE_READ32_MEMBER(d_u_pdo_r) { return m_d_u_pdo; }
|
||||
DECLARE_WRITE32_MEMBER(d_u_pdo_w) { m_d_u_pdo = data; }
|
||||
DECLARE_READ32_MEMBER(d_fault_r) { return m_d_fault; }
|
||||
DECLARE_WRITE32_MEMBER(d_fault_w) { m_d_fault = data; }
|
||||
DECLARE_READ32_MEMBER(d_control_r) { return m_d_control; }
|
||||
DECLARE_WRITE32_MEMBER(d_control_w) { m_d_control = data; }
|
||||
DECLARE_READ32_MEMBER(d_reset_r) { return m_d_reset; }
|
||||
DECLARE_WRITE32_MEMBER(d_reset_w) { m_d_reset = data; }
|
||||
enum control_mask : u32
|
||||
{
|
||||
CNTL_EP = 0x00000001, // enable prefetch
|
||||
CNTL_EWCW = 0x00000002, // enable watch cpu writes
|
||||
CNTL_EWIW = 0x00000004, // enable watch i/o writes
|
||||
CNTL_EWIR = 0x00000008, // enable watch i/o reads
|
||||
CNTL_UST = 0x00000030, // unmapped system tag
|
||||
CNTL_CV = 0x00000100, // clear valid
|
||||
CNTL_ATE = 0x00000200, // alignment trap enable
|
||||
CNTL_CID = 0xff000000 // cammu id
|
||||
};
|
||||
|
||||
DECLARE_READ32_MEMBER(i_s_pdo_r) { return m_i_s_pdo; }
|
||||
DECLARE_WRITE32_MEMBER(i_s_pdo_w) { m_i_s_pdo = data; }
|
||||
DECLARE_READ32_MEMBER(i_u_pdo_r) { return m_i_u_pdo; }
|
||||
DECLARE_WRITE32_MEMBER(i_u_pdo_w) { m_i_u_pdo = data; }
|
||||
DECLARE_READ32_MEMBER(i_fault_r) { return m_i_fault; }
|
||||
DECLARE_WRITE32_MEMBER(i_fault_w) { m_i_fault = data; }
|
||||
DECLARE_READ32_MEMBER(i_control_r) { return m_i_control; }
|
||||
DECLARE_WRITE32_MEMBER(i_control_w) { m_i_control = data; }
|
||||
DECLARE_READ32_MEMBER(i_reset_r) { return m_i_reset; }
|
||||
DECLARE_WRITE32_MEMBER(i_reset_w) { m_i_reset = data; }
|
||||
enum ust_mask : u32
|
||||
{
|
||||
UST_0 = 0x00000000, // private, write-through, main memory space
|
||||
UST_1 = 0x00000010, // shared, write-through, main memory space
|
||||
UST_2 = 0x00000020, // private, copy-back, main memory space
|
||||
UST_3 = 0x00000030 // noncacheable, main memory space
|
||||
};
|
||||
|
||||
DECLARE_WRITE32_MEMBER(g_s_pdo_w) { d_s_pdo_w(space, offset, data, mem_mask); i_s_pdo_w(space, offset, data, mem_mask); }
|
||||
DECLARE_WRITE32_MEMBER(g_u_pdo_w) { d_u_pdo_w(space, offset, data, mem_mask); i_u_pdo_w(space, offset, data, mem_mask); }
|
||||
DECLARE_WRITE32_MEMBER(g_fault_w) { d_fault_w(space, offset, data, mem_mask); i_fault_w(space, offset, data, mem_mask); }
|
||||
DECLARE_WRITE32_MEMBER(g_control_w) { d_control_w(space, offset, data, mem_mask); i_control_w(space, offset, data, mem_mask); }
|
||||
DECLARE_WRITE32_MEMBER(g_reset_w) { d_reset_w(space, offset, data, mem_mask); i_reset_w(space, offset, data, mem_mask); }
|
||||
enum control_cid_mask : u32
|
||||
{
|
||||
CID_C3 = 0x00000000 // unknown
|
||||
};
|
||||
|
||||
DECLARE_READ32_MEMBER(s_pdo_r) const { 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) const { return m_u_pdo; }
|
||||
DECLARE_WRITE32_MEMBER(u_pdo_w) { m_u_pdo = ((m_u_pdo & ~mem_mask) | (data & mem_mask)) & PDO_MASK; }
|
||||
DECLARE_READ32_MEMBER(fault_r) const { return m_fault; }
|
||||
DECLARE_WRITE32_MEMBER(fault_w) { m_fault = data; }
|
||||
DECLARE_READ32_MEMBER(control_r) const { return m_control; }
|
||||
DECLARE_WRITE32_MEMBER(control_w) { m_control = ((m_control & (~mem_mask | CNTL_CID)) | (data & (mem_mask & ~CNTL_CID))); }
|
||||
DECLARE_READ32_MEMBER(reset_r) const { return m_reset; }
|
||||
DECLARE_WRITE32_MEMBER(reset_w) { m_reset = data; }
|
||||
|
||||
// global methods - relay to each linked device
|
||||
DECLARE_WRITE32_MEMBER(g_s_pdo_w) { for (cammu_c3_device *dev : m_linked) dev->s_pdo_w(space, offset, data, mem_mask); }
|
||||
DECLARE_WRITE32_MEMBER(g_u_pdo_w) { for (cammu_c3_device *dev : m_linked) dev->u_pdo_w(space, offset, data, mem_mask); }
|
||||
DECLARE_WRITE32_MEMBER(g_fault_w) { for (cammu_c3_device *dev : m_linked) dev->fault_w(space, offset, data, mem_mask); }
|
||||
DECLARE_WRITE32_MEMBER(g_control_w) { for (cammu_c3_device *dev : m_linked) dev->control_w(space, offset, data, mem_mask); }
|
||||
DECLARE_WRITE32_MEMBER(g_reset_w) { for (cammu_c3_device *dev : m_linked) dev->reset_w(space, offset, data, mem_mask); }
|
||||
|
||||
protected:
|
||||
u32 get_pte(u32 va, int user, bool data) override;
|
||||
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_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 void set_fault_address(const u32 va) override { m_fault = va; }
|
||||
|
||||
private:
|
||||
u32 m_d_s_pdo;
|
||||
u32 m_d_u_pdo;
|
||||
u32 m_d_fault;
|
||||
u32 m_d_control;
|
||||
u32 m_d_reset;
|
||||
u32 m_i_s_pdo;
|
||||
u32 m_i_u_pdo;
|
||||
u32 m_i_fault;
|
||||
u32 m_i_control;
|
||||
u32 m_i_reset;
|
||||
enum c3_access_t : u8
|
||||
{
|
||||
N = 0, // no access
|
||||
R = 1, // read permitted
|
||||
W = 2, // write permitted
|
||||
RW = 3, // read and write permitted
|
||||
E = 4, // execute permitted
|
||||
RE = 5, // read and execute permitted
|
||||
RWE = 7 // read, write and execute permitted
|
||||
};
|
||||
|
||||
static const u8 i_cammu_column[];
|
||||
static const u8 d_cammu_column[];
|
||||
static const c3_access_t cammu_matrix[][16];
|
||||
|
||||
u32 m_s_pdo;
|
||||
u32 m_u_pdo;
|
||||
u32 m_fault;
|
||||
u32 m_control;
|
||||
u32 m_reset;
|
||||
|
||||
std::vector<cammu_c3_device *> m_linked;
|
||||
};
|
||||
|
||||
// device type definitions
|
||||
|
@ -165,6 +165,7 @@ DEFINE_DEVICE_TYPE(SAPPHIRE_IOGA, sapphire_ioga_device, "ioga_s", "I/O Gate Arra
|
||||
|
||||
interpro_ioga_device::interpro_ioga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, type, tag, owner, clock)
|
||||
, m_memory_tag(nullptr)
|
||||
, m_memory_space(nullptr)
|
||||
, m_out_nmi_func(*this)
|
||||
, m_out_irq_func(*this)
|
||||
@ -192,13 +193,22 @@ sapphire_ioga_device::sapphire_ioga_device(const machine_config &mconfig, const
|
||||
{
|
||||
}
|
||||
|
||||
void interpro_ioga_device::static_set_memory(device_t &device, const char *const tag, const int spacenum)
|
||||
{
|
||||
interpro_ioga_device &ioga = dynamic_cast<interpro_ioga_device &>(device);
|
||||
|
||||
ioga.m_memory_tag = tag;
|
||||
ioga.m_memory_spacenum = spacenum;
|
||||
}
|
||||
|
||||
void interpro_ioga_device::device_start()
|
||||
{
|
||||
// TODO: parameterise the cammu name and space number
|
||||
// grab the main memory space from the mmu so we can do DMA to/from it
|
||||
device_memory_interface *mmu;
|
||||
siblingdevice("mmu")->interface(mmu);
|
||||
m_memory_space = &mmu->space(0);
|
||||
assert_always(m_memory_tag != nullptr, "memory tag and address space number must be configured");
|
||||
|
||||
// get the memory space
|
||||
device_memory_interface *memory;
|
||||
siblingdevice(m_memory_tag)->interface(memory);
|
||||
m_memory_space = &memory->space(m_memory_spacenum);
|
||||
|
||||
// resolve callbacks
|
||||
m_out_nmi_func.resolve();
|
||||
|
@ -29,7 +29,8 @@
|
||||
#define MCFG_INTERPRO_IOGA_ETH_CA_CB(_ca) \
|
||||
devcb = &interpro_ioga_device::static_set_eth_ca_callback(*device, DEVCB_##_ca);
|
||||
|
||||
#define MCFG_INTERPRO_IOGA_DMA_BUS(_mmu, _space)
|
||||
#define MCFG_INTERPRO_IOGA_MEMORY(_tag, _spacenum) \
|
||||
interpro_ioga_device::static_set_memory(*device, _tag, _spacenum);
|
||||
|
||||
class interpro_ioga_device : public device_t
|
||||
{
|
||||
@ -115,6 +116,8 @@ public:
|
||||
template<class _Object> static devcb_base &static_set_fdc_tc_callback(device_t &device, _Object object) { return downcast<interpro_ioga_device &>(device).m_fdc_tc_func.set_callback(object); }
|
||||
template<class _Object> static devcb_base &static_set_eth_ca_callback(device_t &device, _Object object) { return downcast<interpro_ioga_device &>(device).m_eth_ca_func.set_callback(object); }
|
||||
|
||||
static void static_set_memory(device_t &device, const char *const tag, const int spacenum);
|
||||
|
||||
virtual DECLARE_ADDRESS_MAP(map, 32) = 0;
|
||||
|
||||
// interrupt request lines
|
||||
@ -317,6 +320,8 @@ protected:
|
||||
virtual void device_reset() override;
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
|
||||
const char *m_memory_tag;
|
||||
int m_memory_spacenum;
|
||||
address_space *m_memory_space;
|
||||
|
||||
// callbacks
|
||||
|
Loading…
Reference in New Issue
Block a user