summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/clipper/clipper.h
diff options
context:
space:
mode:
author Patrick Mackinlay <pmackinlay@hotmail.com>2017-11-27 13:48:33 +0700
committer Patrick Mackinlay <pmackinlay@hotmail.com>2017-11-27 13:48:33 +0700
commit3c36e304ed4f9e9fa555122bbcf712c467bfcb70 (patch)
tree1fa565a3b7dd5c7e4c53e0843a403ad668fa2483 /src/devices/cpu/clipper/clipper.h
parent23b9c43e56c271f77c8b718c0a120c51ba27a9a3 (diff)
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
Diffstat (limited to 'src/devices/cpu/clipper/clipper.h')
-rw-r--r--src/devices/cpu/clipper/clipper.h315
1 files changed, 204 insertions, 111 deletions
diff --git a/src/devices/cpu/clipper/clipper.h b/src/devices/cpu/clipper/clipper.h
index 667e835d8c8..1781401fece 100644
--- a/src/devices/cpu/clipper/clipper.h
+++ b/src/devices/cpu/clipper/clipper.h
@@ -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)