diff options
author | 2017-11-27 13:48:33 +0700 | |
---|---|---|
committer | 2017-11-27 13:48:33 +0700 | |
commit | 3c36e304ed4f9e9fa555122bbcf712c467bfcb70 (patch) | |
tree | 1fa565a3b7dd5c7e4c53e0843a403ad668fa2483 /src/devices/cpu/clipper/clipper.h | |
parent | 23b9c43e56c271f77c8b718c0a120c51ba27a9a3 (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.h | 315 |
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) |