diff --git a/src/devices/cpu/sparc/mb86901.cpp b/src/devices/cpu/sparc/mb86901.cpp index f2e737b7265..4758d76e520 100644 --- a/src/devices/cpu/sparc/mb86901.cpp +++ b/src/devices/cpu/sparc/mb86901.cpp @@ -26,7 +26,7 @@ const device_type MB86901 = &device_creator; -const int mb86901_device::WINDOW_COUNT = 7; +const int mb86901_device::NWINDOWS = 7; //------------------------------------------------- // mb86901_device - constructor @@ -42,43 +42,120 @@ mb86901_device::mb86901_device(const machine_config &mconfig, const char *tag, d void mb86901_device::device_start() { - m_trap_priorities[0] = 1; - m_trap_priorities[1] = 2; - m_trap_priorities[2] = 3; - m_trap_priorities[3] = 4; - m_trap_priorities[4] = 5; - m_trap_priorities[5] = 6; - m_trap_priorities[6] = 6; - m_trap_priorities[7] = 7; - m_trap_priorities[8] = 8; - m_trap_priorities[9] = 10; - m_trap_priorities[10] = 11; - for (int i = 11; i <= 16; i++) - m_trap_priorities[i] = 31; - m_trap_priorities[17] = 27; - m_trap_priorities[18] = 26; - m_trap_priorities[19] = 25; - m_trap_priorities[20] = 24; - m_trap_priorities[21] = 23; - m_trap_priorities[22] = 22; - m_trap_priorities[23] = 21; - m_trap_priorities[24] = 20; - m_trap_priorities[25] = 19; - m_trap_priorities[26] = 18; - m_trap_priorities[27] = 17; - m_trap_priorities[28] = 16; - m_trap_priorities[29] = 15; - m_trap_priorities[30] = 14; - m_trap_priorities[31] = 13; - for (int i = 32; i < 128; i++) - m_trap_priorities[i] = 31; - for (int i = 128; i < 256; i++) - m_trap_priorities[i] = 12; + m_bp_reset_in = false; + m_bp_irl = 0; + m_bp_fpu_present = false; + m_bp_cp_present = false; + m_pb_error = false; + m_pb_block_ldst_byte = false; + m_pb_block_ldst_word = false; memset(m_dbgregs, 0, 24 * sizeof(UINT32)); + memset(m_illegal_instruction_asr, 0, 32 * sizeof(bool)); + memset(m_privileged_asr, 1, 32 * sizeof(bool)); + m_privileged_asr[0] = false; + + memset(m_alu_op3_assigned, 0, 64 * sizeof(bool)); + m_alu_op3_assigned[OP3_ADD] = true; + m_alu_op3_assigned[OP3_AND] = true; + m_alu_op3_assigned[OP3_OR] = true; + m_alu_op3_assigned[OP3_XOR] = true; + m_alu_op3_assigned[OP3_SUB] = true; + m_alu_op3_assigned[OP3_ANDN] = true; + m_alu_op3_assigned[OP3_ORN] = true; + m_alu_op3_assigned[OP3_XNOR] = true; + m_alu_op3_assigned[OP3_ADDX] = true; + m_alu_op3_assigned[OP3_SUBX] = true; + m_alu_op3_assigned[OP3_ADDCC] = true; + m_alu_op3_assigned[OP3_ANDCC] = true; + m_alu_op3_assigned[OP3_ORCC] = true; + m_alu_op3_assigned[OP3_XORCC] = true; + m_alu_op3_assigned[OP3_SUBCC] = true; + m_alu_op3_assigned[OP3_ANDNCC] = true; + m_alu_op3_assigned[OP3_ORNCC] = true; + m_alu_op3_assigned[OP3_XNORCC] = true; + m_alu_op3_assigned[OP3_ADDXCC] = true; + m_alu_op3_assigned[OP3_SUBXCC] = true; + m_alu_op3_assigned[OP3_TADDCC] = true; + m_alu_op3_assigned[OP3_TSUBCC] = true; + m_alu_op3_assigned[OP3_TADDCCTV] = true; + m_alu_op3_assigned[OP3_TSUBCCTV] = true; + m_alu_op3_assigned[OP3_MULSCC] = true; + m_alu_op3_assigned[OP3_SLL] = true; + m_alu_op3_assigned[OP3_SRL] = true; + m_alu_op3_assigned[OP3_SRA] = true; + m_alu_op3_assigned[OP3_RDASR] = true; + m_alu_op3_assigned[OP3_RDPSR] = true; + m_alu_op3_assigned[OP3_RDWIM] = true; + m_alu_op3_assigned[OP3_RDTBR] = true; + m_alu_op3_assigned[OP3_WRASR] = true; + m_alu_op3_assigned[OP3_WRPSR] = true; + m_alu_op3_assigned[OP3_WRWIM] = true; + m_alu_op3_assigned[OP3_WRTBR] = true; + m_alu_op3_assigned[OP3_FPOP1] = true; + m_alu_op3_assigned[OP3_FPOP2] = true; + m_alu_op3_assigned[OP3_JMPL] = true; + m_alu_op3_assigned[OP3_RETT] = true; + m_alu_op3_assigned[OP3_TICC] = true; + m_alu_op3_assigned[OP3_SAVE] = true; + m_alu_op3_assigned[OP3_RESTORE] = true; +#if SPARCV8 + m_alu_op3_assigned[OP3_UMUL] = true; + m_alu_op3_assigned[OP3_SMUL] = true; + m_alu_op3_assigned[OP3_UDIV] = true; + m_alu_op3_assigned[OP3_SDIV] = true; + m_alu_op3_assigned[OP3_UMULCC] = true; + m_alu_op3_assigned[OP3_SMULCC] = true; + m_alu_op3_assigned[OP3_UDIVCC] = true; + m_alu_op3_assigned[OP3_SDIVCC] = true; + m_alu_op3_assigned[OP3_CPOP1] = true; + m_alu_op3_assigned[OP3_CPOP2] = true; +#endif m_program = &space(AS_PROGRAM); + memset(m_ldst_op3_assigned, 0, 64 * sizeof(bool)); + m_ldst_op3_assigned[OP3_LD] = true; + m_ldst_op3_assigned[OP3_LDUB] = true; + m_ldst_op3_assigned[OP3_LDUH] = true; + m_ldst_op3_assigned[OP3_LDD] = true; + m_ldst_op3_assigned[OP3_ST] = true; + m_ldst_op3_assigned[OP3_STB] = true; + m_ldst_op3_assigned[OP3_STH] = true; + m_ldst_op3_assigned[OP3_STD] = true; + m_ldst_op3_assigned[OP3_LDSB] = true; + m_ldst_op3_assigned[OP3_LDSH] = true; + m_ldst_op3_assigned[OP3_LDSTUB] = true; + m_ldst_op3_assigned[OP3_LDA] = true; + m_ldst_op3_assigned[OP3_LDUBA] = true; + m_ldst_op3_assigned[OP3_LDUHA] = true; + m_ldst_op3_assigned[OP3_LDDA] = true; + m_ldst_op3_assigned[OP3_STA] = true; + m_ldst_op3_assigned[OP3_STBA] = true; + m_ldst_op3_assigned[OP3_STHA] = true; + m_ldst_op3_assigned[OP3_STDA] = true; + m_ldst_op3_assigned[OP3_LDSBA] = true; + m_ldst_op3_assigned[OP3_LDSHA] = true; + m_ldst_op3_assigned[OP3_LDSTUBA] = true; + m_ldst_op3_assigned[OP3_LDFPR] = true; + m_ldst_op3_assigned[OP3_LDFSR] = true; + m_ldst_op3_assigned[OP3_LDDFPR] = true; + m_ldst_op3_assigned[OP3_STFPR] = true; + m_ldst_op3_assigned[OP3_STFSR] = true; + m_ldst_op3_assigned[OP3_STDFQ] = true; + m_ldst_op3_assigned[OP3_STDFPR] = true; +#if SPARCV8 + m_ldst_op3_assigned[OP3_SWAP] = true; + m_ldst_op3_assigned[OP3_SWAPA] = true; + m_ldst_op3_assigned[OP3_LDCPR] = true; + m_ldst_op3_assigned[OP3_LDCSR] = true; + m_ldst_op3_assigned[OP3_LDDCPR] = true; + m_ldst_op3_assigned[OP3_STCPR] = true; + m_ldst_op3_assigned[OP3_STCSR] = true; + m_ldst_op3_assigned[OP3_STDCQ] = true; + m_ldst_op3_assigned[OP3_STDCPR] = true; +#endif + // register our state for the debugger state_add(STATE_GENPC, "GENPC", m_pc).noshow(); state_add(STATE_GENFLAGS, "GENFLAGS", m_psr).callimport().callexport().formatstr("%6s").noshow(); @@ -130,14 +207,51 @@ void mb86901_device::device_start() state_add(SPARC_R0 + i, rname, m_r[i]).formatstr("%08X"); } - // register with the savestate system save_item(NAME(m_r)); + save_item(NAME(m_fpr)); + save_item(NAME(m_fsr)); + save_item(NAME(m_ftt)); save_item(NAME(m_pc)); save_item(NAME(m_npc)); save_item(NAME(m_psr)); save_item(NAME(m_wim)); save_item(NAME(m_tbr)); save_item(NAME(m_y)); + save_item(NAME(m_bp_reset_in)); + save_item(NAME(m_bp_irl)); + save_item(NAME(m_bp_fpu_present)); + save_item(NAME(m_bp_cp_present)); + save_item(NAME(m_pb_block_ldst_byte)); + save_item(NAME(m_pb_block_ldst_word)); + save_item(NAME(m_trap)); + save_item(NAME(m_tt)); + save_item(NAME(m_ticc_trap_type)); + save_item(NAME(m_interrupt_level)); + save_item(NAME(m_privileged_instruction)); + save_item(NAME(m_illegal_instruction)); + save_item(NAME(m_mem_address_not_aligned)); + save_item(NAME(m_fp_disabled)); + save_item(NAME(m_fp_exception)); + save_item(NAME(m_cp_disabled)); + save_item(NAME(m_cp_exception)); + save_item(NAME(m_unimplemented_FLUSH)); + save_item(NAME(m_r_register_access_error)); + save_item(NAME(m_instruction_access_error)); + save_item(NAME(m_instruction_access_exception)); + save_item(NAME(m_data_access_error)); + save_item(NAME(m_data_store_error)); + save_item(NAME(m_data_access_exception)); + save_item(NAME(m_division_by_zero)); + save_item(NAME(m_trap_instruction)); + save_item(NAME(m_window_underflow)); + save_item(NAME(m_window_overflow)); + save_item(NAME(m_tag_overflow)); + save_item(NAME(m_reset_mode)); + save_item(NAME(m_reset_trap)); + save_item(NAME(m_execute_mode)); + save_item(NAME(m_error_mode)); + save_item(NAME(m_fpu_sequence_err)); + save_item(NAME(m_cp_sequence_err)); save_item(NAME(m_impl)); save_item(NAME(m_ver)); save_item(NAME(m_icc)); @@ -148,35 +262,56 @@ void mb86901_device::device_start() save_item(NAME(m_ps)); save_item(NAME(m_et)); save_item(NAME(m_cwp)); - save_item(NAME(m_insn_asi)); - save_item(NAME(m_data_asi)); save_item(NAME(m_asi)); - save_item(NAME(m_queued_tt)); - save_item(NAME(m_queued_priority)); + save_item(NAME(m_mae)); + save_item(NAME(m_annul)); + save_item(NAME(m_hold_bus)); // set our instruction counter m_icountptr = &m_icount; } + void mb86901_device::device_stop() { } + void mb86901_device::device_reset() { - m_queued_tt = 0; - m_queued_priority = SPARC_NO_TRAP; + m_trap = 0; + m_tt = 0; + m_ticc_trap_type = 0; + m_privileged_instruction = 0; + m_illegal_instruction = 0; + m_mem_address_not_aligned = 0; + m_fp_disabled = 0; + m_cp_disabled = 0; + m_instruction_access_exception = 0; + m_trap_instruction = 0; + m_window_underflow = 0; + m_window_overflow = 0; + m_tag_overflow = 0; + m_reset_mode = 1; + m_reset_trap = 0; + m_execute_mode = 0; + m_error_mode = 0; + m_fpu_sequence_err = 0; + m_cp_sequence_err = 0; + m_asi = 0; MAE = false; HOLD_BUS = false; + m_annul = false; PC = 0; nPC = 4; memset(m_r, 0, sizeof(UINT32) * 120); + memset(m_fpr, 0, sizeof(UINT32) * 32); - m_wim = 0; - m_tbr = 0; - m_y = 0; + WIM = 0; + TBR = 0; + Y = 0; m_impl = 0; m_ver = 0; @@ -189,9 +324,6 @@ void mb86901_device::device_reset() m_et = false; m_cwp = 0; - m_insn_asi = 9; - m_data_asi = 11; - MAKE_PSR; for (int i = 0; i < 8; i++) { @@ -218,80 +350,56 @@ const address_space_config *mb86901_device::memory_space_config(address_spacenum } } + //------------------------------------------------- -// read_byte - read an 8-bit value from a given -// address space +// read_sized_word - read a value from a given +// address space and address, shifting the data +// that is read into the appropriate location of +// a 32-bit word in a big-endian system. //------------------------------------------------- -UINT32 mb86901_device::read_byte(UINT8 asi, UINT32 address) +UINT32 mb86901_device::read_sized_word(UINT8 asi, UINT32 address, int size) { m_asi = asi; - // TODO: data_access_exception, data_access_error traps - return m_program->read_byte(address); + if (size == 1) + { + return m_program->read_byte(address) << ((3 - (address & 3)) * 8); + } + else if (size == 2) + { + return m_program->read_word(address) << ((1 - (address & 1)) * 16); + } + else + { + return m_program->read_dword(address); + } } -INT32 mb86901_device::read_signed_byte(UINT8 asi, UINT32 address) -{ - m_asi = asi; - // TODO: data_access_exception, data_access_error traps - return (((INT32)m_program->read_byte(address) << 24) >> 24); -} -UINT32 mb86901_device::read_half(UINT8 asi, UINT32 address) -{ - m_asi = asi; - // TODO: data_access_exception, data_access_error traps - return m_program->read_word(address); -} +//------------------------------------------------- +// write_sized_word - write a value to a given +// address space and address, shifting the data +// that is written into the least significant +// bits as appropriate in order to write the +// value to a memory system with separate data +// size handlers +//------------------------------------------------- -INT32 mb86901_device::read_signed_half(UINT8 asi, UINT32 address) +void mb86901_device::write_sized_word(UINT8 asi, UINT32 address, UINT32 data, int size) { m_asi = asi; - // TODO: data_access_exception, data_access_error traps - return (((INT32)m_program->read_word(address) << 16) >> 16); -} - -UINT32 mb86901_device::read_word(UINT8 asi, UINT32 address) -{ - m_asi = asi; - // TODO: data_access_exception, data_access_error traps - return m_program->read_dword(address); -} - -UINT64 mb86901_device::read_doubleword(UINT8 asi, UINT32 address) -{ - m_asi = asi; - // TODO: data_access_exception, data_access_error traps - return (((UINT64)m_program->read_dword(address) << 32) | m_program->read_dword(address+4)); -} - -void mb86901_device::write_byte(UINT8 asi, UINT32 address, UINT8 data) -{ - m_asi = asi; - // TODO: data_access_exception, data_access_error traps - m_program->write_byte(address, data); -} - -void mb86901_device::write_half(UINT8 asi, UINT32 address, UINT16 data) -{ - m_asi = asi; - // TODO: data_access_exception, data_access_error traps - m_program->write_word(address, data); -} - -void mb86901_device::write_word(UINT8 asi, UINT32 address, UINT32 data) -{ - m_asi = asi; - // TODO: data_access_exception, data_access_error traps - m_program->write_dword(address, data); -} - -void mb86901_device::write_doubleword(UINT8 asi, UINT32 address, UINT64 data) -{ - m_asi = asi; - // TODO: data_access_exception, data_access_error traps - m_program->write_dword(address, (UINT32)(data >> 32)); - m_program->write_dword(address+4, (UINT32)data); + if (size == 1) + { + m_program->write_byte(address, data >> ((3 - (address & 3)) * 8)); + } + else if (size == 2) + { + m_program->write_word(address, data >> ((1 - (address & 1)) * 16)); + } + else + { + m_program->write_dword(address, data); + } } @@ -403,83 +511,868 @@ void mb86901_device::execute_set_input(int inputnum, int state) //------------------------------------------------- -// save_restore_update_cwp - update cwp after -// a save or restore opcode with no trap taken +// execute_add - execute an add-type opcode //------------------------------------------------- -void mb86901_device::save_restore_update_cwp(UINT32 op, UINT8 new_cwp) +void mb86901_device::execute_add(UINT32 op) { - UINT32 arg1 = RS1REG; - UINT32 arg2 = USEIMM ? SIMM13 : RS2REG; + /* The SPARC Instruction Manual: Version 8, page 173, "Appendix C - ISP Descriptions - Add Instructions" (SPARCv8.pdf, pg. 170) + + operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); + + if (ADD or ADDcc) then + result <- r[rs1] + operand2; + else if (ADDX or ADDXcc) then + result <= r[rs1] + operand2 + C; + next; + + if (rd != 0) then + r[rd] <- result; + + if (ADDcc or ADDXcc) then ( + N <- result<31>; + Z <- if (result = 0) then 1 else 0; + V <- (r[rs1]<31> and operand2<31> and (not result<31>)) or + ((not r[rs1]<31>) and (not operand2<31>) and result<31>); + C <- (r[rs1]<31> and operand2<31>) or + ((not result<31>) and (r[rs1]<31> or operand2<31>)) + ); + */ + UINT32 operand2 = USEIMM ? SIMM13 : RS2REG; + + UINT32 result = 0; + if (OP3 == 0 || OP3 == 16) + result = RS1REG + operand2; + else if (OP3 == 8 || OP3 == 24) + result = RS1REG + operand2 + ICC_C; + + + if (RD != 0) + RDREG = result; + + if (OP3 & 16) + { + CLEAR_ICC; + PSR |= (BIT31(result)) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + PSR |= ((BIT31(RS1REG) && BIT31(operand2) && !BIT31(result)) || + (!BIT31(RS1REG) && !BIT31(operand2) && BIT31(result))) ? PSR_V_MASK : 0; + PSR |= ((BIT31(RS1REG) && BIT31(operand2)) || + (!BIT31(result) && (BIT31(RS1REG) || BIT31(operand2)))) ? PSR_C_MASK : 0; + } +} + + +//------------------------------------------------- +// execute_taddcc - execute a tagged add-type +// opcode +//------------------------------------------------- + +void mb86901_device::execute_taddcc(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 173, "Appendix C - ISP Descriptions - Tagged Add Instructions" (SPARCv8.pdf, pg. 170) + + operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); + + result <- r[rs1] + operand2; + next; + + temp_V <- (r[rs1]<31> and operand2<31> and (not result<31>)) or + ((not r[rs1]<31>) and (not operand2<31>) and result<31>) or + (r[rs1]<1:0> != 0 or operand2<1:0> != 0); + next; + + if (TADDccTV and (temp_V = 1)) then ( + trap <- 1; + tag_overflow <- 1 + ) else ( + N <- result<31>; + Z <- if (result = 0) then 1 else 0; + V <- temp_V; + C <- (r[rs1]<31> and operand2<31>) or + ((not result<31>) and (r[rs1]<31> or operand2<31>)); + if (rd != 0) then + r[rd] <- result; + ); + */ + UINT32 operand2 = USEIMM ? SIMM13 : RS2REG; + + UINT32 result = RS1REG + operand2; + + bool temp_v = (BIT31(RS1REG) && BIT31(operand2) && !BIT31(result)) || + (!BIT31(RS1REG) && !BIT31(operand2) && BIT31(result)) || + ((RS1REG & 3) != 0 || (RS1REG & 3) != 0) ? true : false; + + if (OP3 == 34 && temp_v) + { + m_trap = 1; + m_tag_overflow = true; + } + else + { + CLEAR_ICC; + PSR |= (BIT31(result)) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + PSR |= temp_v ? PSR_V_MASK : 0; + PSR |= ((BIT31(RS1REG) && BIT31(operand2)) || + (!BIT31(result) && (BIT31(RS1REG) || BIT31(operand2)))) ? PSR_C_MASK : 0; + + if (RD != 0) + RDREG = result; + } +} + + +//------------------------------------------------- +// execute_sub - execute a subtraction-type +// opcode +//------------------------------------------------- + +void mb86901_device::execute_sub(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 174, "Appendix C - ISP Descriptions - Subtract Instructions" (SPARCv8.pdf, pg. 171) + + operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); + + if (SUB or SUBcc) then + result <- r[rs1] - operand2; + else if (SUBX or SUBXcc) then + result <= r[rs1] - operand2 - C; + next; + + if (rd != 0) then + r[rd] <- result; + + if (SUBcc or SUBXcc) then ( + N <- result<31>; + Z <- if (result = 0) then 1 else 0; + V <- (r[rs1]<31> and (not operand2<31>) and (not result<31>)) or + ((not r[rs1]<31>) and operand2<31> and result<31>); + C <- ((not r[rs1]<31>) and operand2<31>) or + (result<31> and ((not r[rs1]<31>) or operand2<31>)) + ); + */ + UINT32 operand2 = USEIMM ? SIMM13 : RS2REG; + + UINT32 result = 0; + if (OP3 == 4 || OP3 == 20) + result = RS1REG - operand2; + else if (OP3 == 12 || OP3 == 28) + result = RS1REG - operand2 - ICC_C; + + if (RD != 0) + RDREG = result; + + if (OP3 & 16) + { + CLEAR_ICC; + PSR |= (BIT31(result)) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + PSR |= ((BIT31(RS1REG) && !BIT31(operand2) && !BIT31(result)) || + (!BIT31(RS1REG) && BIT31(operand2) && BIT31(result))) ? PSR_V_MASK : 0; + PSR |= ((!BIT31(RS1REG) && BIT31(operand2)) || + (BIT31(result) && (!BIT31(RS1REG) || BIT31(operand2)))) ? PSR_C_MASK : 0; + } +} + + +//-------------------------------------------------- +// execute_tsubcc - execute a tagged subtract-type +// opcode +//-------------------------------------------------- + +void mb86901_device::execute_tsubcc(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 174, "Appendix C - ISP Descriptions - Tagged Subtract Instructions" (SPARCv8.pdf, pg. 171) + + operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); + + result <- r[rs1] - operand2; + next; + + temp_V <- (r[rs1]<31> and (not operand2<31>) and (not result<31>)) or + ((not r[rs1]<31>) and operand2<31> and result<31>) or + (r[rs1]<1:0> != 0 or operand2<1:0> != 0); + next; + + if (TSUBccTV and (temp_V = 1)) then ( + trap <- 1; + tag_overflow <- 1 + ) else ( + N <- result<31>; + Z <- if (result = 0) then 1 else 0; + V <- temp_V; + C <- ((not r[rs1]<31>) and operand2<31>) or + (result<31> and ((not r[rs1]<31>) or operand2<31>)); + if (rd != 0) then + r[rd] <- result; + ); + */ + + UINT32 operand2 = USEIMM ? SIMM13 : RS2REG; + + UINT32 result = RS1REG - operand2; + + bool temp_v = (BIT31(RS1REG) && !BIT31(operand2) && !BIT31(result)) || + (!BIT31(RS1REG) && BIT31(operand2) && BIT31(result)) || + ((RS1REG & 3) != 0 || (RS1REG & 3) != 0) ? true : false; + + if (OP3 == 35 && temp_v) + { + m_trap = 1; + m_tag_overflow = 1; + } + else + { + CLEAR_ICC; + PSR |= (BIT31(result)) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + PSR |= temp_v ? PSR_V_MASK : 0; + PSR |= ((!BIT31(RS1REG) && BIT31(operand2)) || + (BIT31(result) && (!BIT31(RS1REG) || BIT31(operand2)))) ? PSR_C_MASK : 0; + + if (RD != 0) + RDREG = result; + } +} + + +//------------------------------------------------- +// execute_logical - execute a logical-type +// opcode, and/or/xor/andn/orn/xnor +//------------------------------------------------- + +void mb86901_device::execute_logical(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 172, "Appendix C - ISP Descriptions - Logical Instructions" (SPARCv8.pdf, pg. 169) + + operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); + + if ( AND or ANDcc) then result <- r[rs1] and operand2 + if (ANDN or ANDNcc) then result <- r[rs1] and not operand2 + if ( OR or ORcc) then result <- r[rs1] or operand2 + if ( ORN or ORNcc) then result <- r[rs1] or not operand2 + if ( XOR or XORcc) then result <- r[rs1] xor operand2 + if (XNOR or XNORcc) then result <- r[rs1] xor not operand2; + next; + + if (rd != 0) then r[rd] <- result; + + if (ANDcccc or ANDNcc or ORcc or ORNcc or XORcc or XNORcc) then ( + N <- result<31>; + Z <- if (result = 0) then 1 else 0; + V <- 0 + C <- 0 + ); + */ + + UINT32 operand2 = USEIMM ? SIMM13 : RS2REG; + + UINT32 result = 0; + switch (OP3) + { + case 1: + case 17: + result = RS1REG & operand2; + break; + case 5: + case 21: + result = RS1REG & ~operand2; + break; + case 2: case 18: + result = RS1REG | operand2; + break; + case 6: case 22: + result = RS1REG | ~operand2; + break; + case 3: case 19: + result = RS1REG ^ operand2; + break; + case 7: case 23: + result = RS1REG ^ ~operand2; + break; + } + + if (RD != 0) RDREG = result; + + if (OP3 & 16) + { + CLEAR_ICC; + PSR |= (BIT31(result)) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + } +} + + +//------------------------------------------------- +// execute_shift - execute a shift-type opcode, +// sll/srl/sra +//------------------------------------------------- + +void mb86901_device::execute_shift(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 172, "Appendix C - ISP Descriptions - Shift Instructions" (SPARCv8.pdf, pg. 169) + + shift_count := if (i = 0) then r[rs2]<4:0> else shcnt; + + if (SLL and (rd != 0) ) then + r[rd] <- shift_left_logical(r[rs1], shift_count) + else if (SRL and (rd != 0) ) then + r[rd] <- shift_right_logical(r[rs1], shift_count) + else if (SRA and (rd != 0) ) then + r[rd] <- shift_right_arithmetic(r[rs1], shift_count) + */ + UINT32 shift_count = USEIMM ? (SIMM13 & 31) : (RS2REG & 31); + + if (OP3 == 37 && RD != 0) + RDREG = RS1REG << shift_count; + else if (OP3 == 38 && RD != 0) + RDREG = UINT32(RS1REG) >> shift_count; + else if (OP3 == 39 && RD != 0) + RDREG = INT32(RS1REG) >> shift_count; +} + + +//-------------------------------------------------- +// execute_mulscc - execute a multiply step opcode +//-------------------------------------------------- + +void mb86901_device::execute_mulscc(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 175, "Appendix C - ISP Descriptions - Multiply Step Instruction" (SPARCv8.pdf, pg. 172) + + operand1 := (N xor V) [] (r[rs1]<31:1>); + + operand2 := ( + if (Y<0> = 0) then 0 + else if (i = 0) then r[rs2] else sign_extend(simm13) + ); + + result <- operand1 + operand2; + Y <- r[rs1]<0> [] Y<31:1>; + next; + + if (rd != 0) then ( + r[rd] <- result; + ) + N <- result<31>; + Z <- if (result = 0) then 1 else 0; + V <- (operand1<31> and operand2<31> and (not result<31>)) or + ((not operand1<31>) and (not operand2<31>) and result<31>); + C <- (operand1<31> and operand2<31>) or + ((not result<31>) and (operand1<31> or operand2<31>)) + */ + UINT32 operand1 = (ICC_N != ICC_V ? 0x80000000 : 0) | (RS1REG >> 1); + + UINT32 operand2 = (Y & 1) ? 0 : (USEIMM ? SIMM13 : RS2REG); + + UINT32 result = operand1 + operand2; + Y = ((RS1REG & 1) ? 0x80000000 : 0) | (Y >> 1); + + if (RD != 0) + RDREG = result; + + CLEAR_ICC; + PSR |= (BIT31(result)) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + PSR |= ((BIT31(operand1) && BIT31(operand2) && !BIT31(result)) || + (!BIT31(operand1) && !BIT31(operand2) && BIT31(result))) ? PSR_V_MASK : 0; + PSR |= ((BIT31(operand1) && BIT31(operand2)) || + (!BIT31(result) && (BIT31(operand1) || BIT31(operand2)))) ? PSR_C_MASK : 0; +} + + +//------------------------------------------------- +// execute_rdsr - execute a status register read +// opcode +//------------------------------------------------- + +void mb86901_device::execute_rdsr(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 182, "Appendix C - ISP Descriptions - Read State Register Instructions" (SPARCv8.pdf, pg. 179) + + if ((RDPSR or RDWIM or RDBTR + or (RDASR and (privileged_ASR(rs1) = 1))) and (S = 0)) then ( + trap <- 1; + privileged_instruction <- 1; + else if (illegal_instruction_ASR(rs1) = 1) then ( + trap <- 1; + illegal_instruction <- 1 + else if (rd != 0) then ( + if (RDY) then r[rd] <- Y + else if (RDASR) then r[rd] <- ASR[rs1] + else if (RDPSR) then r[rd] <- PSR + else if (RDWIM) then r[rd] <- WIM + else if (RDTBR) then r[rd] <- TBR; + ); + */ + + if (((OP3 == 41 || OP3 == 42 || OP3 == 43) || (OP3 == 40 && m_privileged_asr[RS1])) && IS_USER) + { + m_trap = 1; + m_privileged_instruction = 1; + } + else if (m_illegal_instruction_asr[RS1]) + { + m_trap = 1; + m_illegal_instruction = 1; + } + else if (RD != 0) + { + switch (OP3) + { + case OP3_RDASR: + if (RS1 == 0) RDREG = Y; break; + case OP3_RDPSR: RDREG = PSR; break; + case OP3_RDWIM: RDREG = WIM; break; + case OP3_RDTBR: RDREG = TBR; break; + } + } +} + + +//------------------------------------------------- +// execute_wrsr - execute a status register write +// opcode +//------------------------------------------------- + +void mb86901_device::execute_wrsr(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 183, "Appendix C - ISP Descriptions - Write State Register Instructions" (SPARCv8.pdf, pg. 180) + + operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); + result := r[rs1] xor operand2; + + if (WRY) then ( + Y'''' <- result + ) else if (WRASR) then ( + if ( (privileged_ASR(rd) = 1) and (S = 0) ) then ( + trap <- 1; + privileged_instruction <- 1 + ) else if (illegal_instruction_ASR(rd) = 1) then ( + trap <- 1; + illegal_instruction <- 1 + ) else ( + ASR[rd]'''' <- result + ) + ) else if (WRPSR) then ( + if (S = 0) then ( + trap <- 1; + privileged_instruction <- 1 + ) else if (result<4:0> >= NWINDOWS) then ( + trap <- 1; + illegal_instruction <- 1 + ) else ( + PSR'''' <- result + ) + ) else if (WRWIM) then ( + if (S = 0) then ( + trap <- 1; + privileged_instruction <- 1 + ) else ( + WIM'''' <- result + ) + ) else if (WRBTR) then ( + if (S = 0) then ( + trap <- 1; + privileged_instruction <- 1 + ) else ( + WIM'''' <- result + ) + ); + */ + UINT32 operand2 = USEIMM ? SIMM13 : RS2REG; + + UINT32 result = RS1REG ^ operand2; + + if (OP3 == 48 && RD == 0) + { + Y = result; + } + else if (OP3 == 48) + { + if (m_privileged_asr[RD] && IS_USER) + { + m_trap = 1; + m_privileged_instruction = 1; + } + else if (m_illegal_instruction_asr[RD]) + { + m_trap = 1; + m_illegal_instruction = 1; + } + else + { + // SPARCv8 + } + } + else if (OP3 == 49) + { + if (IS_USER) + { + m_trap = 1; + m_privileged_instruction = 1; + } + else if ((result & 31) >= NWINDOWS) + { + m_trap = 1; + m_illegal_instruction = 1; + } + else + { + PSR = result &~ PSR_ZERO_MASK; + } + } + else if (OP3 == 50) + { + if (IS_USER) + { + m_trap = 1; + m_privileged_instruction = 1; + } + else + { + WIM = result & 0x7f; + } + } + else if (OP3 == 51) + { + if (IS_USER) + { + m_trap = 1; + m_privileged_instruction = 1; + } + else + { + TBR = result & 0xfffff000; + } + } +} + + +//------------------------------------------------- +// execute_rett - execute a return-from-trap +// opcode +//------------------------------------------------- + +void mb86901_device::execute_rett(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 181, "Appendix C - ISP Descriptions - Return from Trap Instructions" (SPARCv8.pdf, pg. 178) + + new_cwp <- (CWP + 1) modulo NWINDOWS; + address <- r[rs1] + (if (i = 0) then r[rs2] else sign_extend(simm13)); + next; + if (ET = 1) then ( + trap <- 1; + if (S = 0) then privileged_instruction <- 1 + else if (S != 0) then illegal_instruction <- 1 + ) else if (S = 0) then ( + trap <- 1; + privileged_instruction <- 1 + tt <- 00000011; { trap type for privileged_instruction } + execute_mode <- 0; + error_mode = 1 + ) else if ((WIM and (1 << new_cwp)) != 0) then ( + trap <- 1; + window_underflow <- 1; + tt <- 00000110; { trap type for window_underflow } + execute_mode = 0; + error_mode = 1 + ) else if (address<1:0> != 0) then ( + trap = 1; + mem_address_not_aligned = 1; + tt = 7; { trap type for mem_address_not_aligned } + execute_mode = 0; + error_mode = 1 + ) else ( + ET <- 1; + PC <- nPC; + nPC <- address; + CWP <- new_cwp; + S <- PS + ) + */ + + UINT8 new_cwp = (CWP + 1) % NWINDOWS; + UINT32 address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + if (ET) + { + m_trap = 1; + if (IS_USER) m_privileged_instruction = 1; + else m_illegal_instruction = 1; + } + else if (IS_USER) + { + m_trap = 1; + m_privileged_instruction = 1; + m_tt = 3; + m_execute_mode = 0; + m_error_mode = 1; + } + else if ((WIM & (1 << new_cwp)) != 0) + { + m_trap = 1; + m_window_underflow = 1; + m_tt = 6; + m_execute_mode = 0; + m_error_mode = 1; + + } + else if (address & 3) + { + m_trap = 1; + m_mem_address_not_aligned = 1; + m_tt = 7; + m_execute_mode = 0; + m_error_mode = 1; + } + else + { + ET = 1; + PC = nPC; + nPC = address; + CWP = new_cwp; + S = PS; + } + + MAKE_PSR; + update_gpr_pointers(); +} + + + +//------------------------------------------------- +// execute_saverestore - execute a save or restore +// opcode +//------------------------------------------------- + +void mb86901_device::execute_saverestore(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 177, "Appendix C - ISP Descriptions - SAVE and RESTORE Instructions" (SPARCv8.pdf, pg. 174) + + operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); + + if (SAVE) then ( + new_cwp <- (CWP - 1) modulo NWINDOWS; + next; + if ((WIM and (1 << new_cwp)) != 0) then ( + trap <- 1; + window_overflow <- 1 + ) else ( + result <- r[rs1] + operand2; { operands from old window } + CWP <- new_cwp + ) + ) else if (RESTORE) then ( + new_cwp <- (CWP + 1) modulo NWINDOWS; + next; + if ((WIM and (1 << new_cwp)) != 0) then ( + trap <- 1; + window_overflow <- 1 + ) else ( + result <- r[rs1] + operand2; { operands from old window } + CWP <- new_cwp + ) + ); + next; + if ((trap = 0) and (rd != 0)) then + r[rd] <- result { destination in new window } + */ + + UINT32 rs1 = RS1REG; + UINT32 operand2 = USEIMM ? SIMM13 : RS2REG; + + UINT32 result = 0; + if (OP3 == OP3_SAVE) + { + UINT8 new_cwp = ((CWP + NWINDOWS) - 1) % NWINDOWS; + if ((WIM & (1 << new_cwp)) != 0) + { + m_trap = 1; + m_window_overflow = 1; + } + else + { + result = rs1 + operand2; + CWP = new_cwp; + } + } + else if (OP3 == OP3_RESTORE) + { + UINT8 new_cwp = (CWP + 1) % NWINDOWS; + if ((WIM & (1 << new_cwp)) != 0) + { + m_trap = 1; + m_window_underflow = 1; + } + else + { + result = rs1 + operand2; + CWP = new_cwp; + } + } - m_cwp = new_cwp; MAKE_PSR; update_gpr_pointers(); - SET_RDREG(arg1 + arg2); + if (m_trap == 0 && RD != 0) + RDREG = result; } + +//------------------------------------------------- +// execute_jmpl - execute a jump and link opcode +//------------------------------------------------- + +void mb86901_device::execute_jmpl(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 180, "Appendix C - ISP Descriptions - SAVE and RESTORE Instructions" (SPARCv8.pdf, pg. 177) + + jump_address <- r[rs1] + (if (i = 0) then r[rs2] else sign_extend(simm13)); + next; + if (jump_address<1:0> != 0) then ( + trap <- 1; + mem_address_not_aligned <- 1 + ) else ( + if (rd != 0) then r[rd] <- PC; + PC <- nPC; + nPC <- jump_address + ) + */ + + UINT32 jump_address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + + if (jump_address & 3) + { + m_trap = 1; + m_mem_address_not_aligned = 1; + } + else + { + if (RD != 0) + RDREG = PC; + PC = nPC; + nPC = jump_address; + } +} + + //------------------------------------------------- // execute_group2 - execute an opcode in group 2, // mostly ALU ops //------------------------------------------------- -bool mb86901_device::execute_group2(UINT32 op) +void mb86901_device::execute_group2(UINT32 op) { - UINT32 arg1 = RS1REG; - UINT32 arg2 = USEIMM ? SIMM13 : RS2REG; - switch (OP3) { - case 0: // add - SET_RDREG(arg1 + arg2); + case OP3_ADD: + case OP3_ADDX: + case OP3_ADDCC: + case OP3_ADDXCC: + execute_add(op); break; - case 1: // and - SET_RDREG(arg1 & arg2); + + case OP3_SUB: + case OP3_SUBX: + case OP3_SUBCC: + case OP3_SUBXCC: + execute_sub(op); break; - case 2: // or - SET_RDREG(arg1 | arg2); + + case OP3_TADDCC: + case OP3_TADDCCTV: + execute_taddcc(op); break; - case 3: // xor - SET_RDREG(arg1 ^ arg2); + + case OP3_TSUBCC: + case OP3_TSUBCCTV: + execute_tsubcc(op); break; - case 4: // sub - SET_RDREG(arg1 - arg2); + + case OP3_AND: + case OP3_OR: + case OP3_XOR: + case OP3_ANDN: + case OP3_ORN: + case OP3_XNOR: + case OP3_ANDCC: + case OP3_ORCC: + case OP3_XORCC: + case OP3_ANDNCC: + case OP3_ORNCC: + case OP3_XNORCC: + execute_logical(op); break; - case 5: // andn - SET_RDREG(arg1 & ~arg2); + + case OP3_MULSCC: + execute_mulscc(op); break; - case 6: // orn - SET_RDREG(arg1 | ~arg2); + + case OP3_SLL: + case OP3_SRL: + case OP3_SRA: + execute_shift(op); break; - case 7: // xnor - SET_RDREG(arg1 ^ ~arg2); + + case OP3_RDASR: + case OP3_RDPSR: + case OP3_RDWIM: + case OP3_RDTBR: + execute_rdsr(op); break; - case 8: // addx - SET_RDREG(arg1 + arg2 + (ICC_C_SET ? 1 : 0)); + + case OP3_WRASR: + case OP3_WRPSR: + case OP3_WRWIM: + case OP3_WRTBR: + execute_wrsr(op); break; + + case OP3_FPOP1: + case OP3_FPOP2: + // Not yet implemented + break; + + case OP3_JMPL: + execute_jmpl(op); + break; + + case OP3_RETT: + execute_rett(op); + break; + + case OP3_TICC: + execute_ticc(op); + break; + + case OP3_SAVE: + case OP3_RESTORE: + execute_saverestore(op); + break; + #if SPARCV8 - case 10: // umul, SPARCv8 + case OP3_UMUL: // SPARCv8 { + UINT32 arg1 = RS1REG; + UINT32 arg2 = USEIMM ? SIMM13 : RS2REG; UINT64 result = (UINT64)arg1 * (UINT64)arg2; Y = (UINT32)(result >> 32); SET_RDREG((UINT32)result); break; } - case 11: // smul, SPARCv8 + case OP3_SMUL: // SPARCv8 { + UINT32 arg1 = RS1REG; + UINT32 arg2 = USEIMM ? SIMM13 : RS2REG; INT64 result = (INT64)(INT32)arg1 * (INT64)(INT32)arg2; Y = (UINT32)((UINT64)result >> 32); SET_RDREG((UINT32)result); break; } -#endif - case 12: // subx - SET_RDREG(arg1 - arg2 - (ICC_C_SET ? 1 : 0)); - break; -#if SPARCV8 - case 14: // udiv, SPARCv8 + case OP3_UDIV: // SPARCv8 { + UINT32 arg1 = RS1REG; + UINT32 arg2 = USEIMM ? SIMM13 : RS2REG; UINT64 dividend = ((UINT64)Y << 32) || arg1; UINT32 divisor = arg2; UINT64 quotient = dividend / divisor; @@ -490,8 +1383,10 @@ bool mb86901_device::execute_group2(UINT32 op) SET_RDREG((UINT32)quotient); break; } - case 15: // sdiv, SPARCv8 + case OP3_SDIV: // SPARCv8 { + UINT32 arg1 = RS1REG; + UINT32 arg2 = USEIMM ? SIMM13 : RS2REG; INT64 dividend = ((INT64)(INT32)Y << 32) || arg1; INT32 divisor = arg2; INT64 quotient = dividend / divisor; @@ -513,118 +1408,30 @@ bool mb86901_device::execute_group2(UINT32 op) SET_RDREG((UINT32)quotient); break; } -#endif - case 16: // addcc - { - UINT32 result = arg1 + arg2; - TEST_ICC_NZ(result); - if ((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000)) - SET_ICC_V_FLAG; - if (result < arg1 || result < arg2) - SET_ICC_C_FLAG; - SET_RDREG(result); - break; - } - case 17: // andcc - { - UINT32 result = arg1 & arg2; - TEST_ICC_NZ(result); - SET_RDREG(result); - break; - } - case 18: // orcc - { - UINT32 result = arg1 | arg2; - TEST_ICC_NZ(result); - SET_RDREG(result); - break; - } - case 19: // xorcc - { - UINT32 result = arg1 ^ arg2; - TEST_ICC_NZ(result); - SET_RDREG(result); - break; - } - case 20: // subcc - { - UINT32 result = arg1 - arg2; - TEST_ICC_NZ(result); - if ((arg1 & 0x80000000) != (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000)) - SET_ICC_V_FLAG; - if (result > arg1) - SET_ICC_C_FLAG; - SET_RDREG(result); - break; - } - case 21: // andncc - { - UINT32 result = arg1 & ~arg2; - TEST_ICC_NZ(result); - SET_RDREG(result); - break; - } - case 22: // orncc - { - UINT32 result = arg1 | ~arg2; - TEST_ICC_NZ(result); - SET_RDREG(result); - break; - } - case 23: // xnorcc - { - UINT32 result = arg1 ^ ~arg2; - TEST_ICC_NZ(result); - SET_RDREG(result); - break; - } - case 24: // addxcc - { - UINT32 c = (ICC_C_SET ? 1 : 0); - UINT32 argt = arg2 + c; - UINT32 result = arg1 + argt; - TEST_ICC_NZ(result); - if (((arg1 & 0x80000000) == (argt & 0x80000000) && (arg1 & 0x80000000) != (result & 0x80000000)) || (c != 0 && arg2 == 0x7fffffff)) - SET_ICC_V_FLAG; - if (result < arg1 || result < arg2 || (result == arg1 && arg2 != 0)) - SET_ICC_C_FLAG; - SET_RDREG(result); - break; - } -#if SPARCV8 - case 26: // umulcc, SPARCv8 + case OP3_UMULCC: // SPARCv8 { + UINT32 arg1 = RS1REG; + UINT32 arg2 = USEIMM ? SIMM13 : RS2REG; UINT64 result = (UINT64)arg1 * (UINT64)arg2; Y = (UINT32)(result >> 32); TEST_ICC_NZ(result); SET_RDREG((UINT32)result); break; } - case 27: // smulcc, SPARCv8 + case OP3_SMULCC: // SPARCv8 { + UINT32 arg1 = RS1REG; + UINT32 arg2 = USEIMM ? SIMM13 : RS2REG; INT64 result = (INT64)(INT32)arg1 * (INT64)(INT32)arg2; Y = (UINT32)((UINT64)result >> 32); TEST_ICC_NZ(result); SET_RDREG((UINT32)result); break; } -#endif - case 28: // subxcc - { - UINT32 c = (ICC_C_SET ? 1 : 0); - UINT32 argt = arg2 + c; - UINT32 result = arg1 - argt; - TEST_ICC_NZ(result); - if (((arg1 & 0x80000000) != (argt & 0x80000000) && (arg1 & 0x80000000) != (result & 0x80000000)) || (c != 0 && arg2 == 0x80000000)) - SET_ICC_V_FLAG; - if (result > arg1 || (result == arg1 && arg2 != 0)) - SET_ICC_C_FLAG; - SET_RDREG(result); - break; - } -#if SPARCV8 - case 30: // udivcc, SPARCv8 + case OP3_UDIVCC: // SPARCv8 { + UINT32 arg1 = RS1REG; + UINT32 arg2 = USEIMM ? SIMM13 : RS2REG; UINT64 dividend = ((UINT64)Y << 32) || arg1; UINT32 divisor = arg2; UINT64 quotient = dividend / divisor; @@ -643,8 +1450,10 @@ bool mb86901_device::execute_group2(UINT32 op) SET_RDREG((UINT32)quotient); break; } - case 31: // sdiv, SPARCv8 + case OP3_SDIVCC: // SPARCv8 { + UINT32 arg1 = RS1REG; + UINT32 arg2 = USEIMM ? SIMM13 : RS2REG; INT64 dividend = ((INT64)(INT32)Y << 32) || arg1; INT32 divisor = arg2; INT64 quotient = dividend / divisor; @@ -675,327 +1484,17 @@ bool mb86901_device::execute_group2(UINT32 op) SET_RDREG((UINT32)quotient); break; } -#endif - case 32: // taddcc - { - UINT32 result = arg1 + arg2; - TEST_ICC_NZ(result); - if (((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000)) || ((arg1 & 3) != 0) || ((arg2 & 3) != 0)) - SET_ICC_V_FLAG; - if (result < arg1 || result < arg2) - SET_ICC_C_FLAG; - SET_RDREG(result); + case OP3_CPOP1: // SPARCv8 break; - } - case 33: // tsubcc - { - UINT32 result = arg1 - arg2; - TEST_ICC_NZ(result); - if (((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000)) || ((arg1 & 3) != 0) || ((arg2 & 3) != 0)) - SET_ICC_V_FLAG; - if (result > arg1) - SET_ICC_C_FLAG; - SET_RDREG(result); - break; - } - case 34: // taddcctv - { - UINT32 result = arg1 + arg2; - bool v = ((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000)) || ((arg1 & 3) != 0) || ((arg2 & 3) != 0); - if (v) - { - trap(SPARC_TAG_OVERFLOW); - } - else - { - TEST_ICC_NZ(result); - if (result < arg1 || result < arg2) - SET_ICC_C_FLAG; - SET_RDREG(result); - } - break; - } - case 35: // tsubcctv - { - UINT32 result = arg1 - arg2; - bool v = ((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000)) || ((arg1 & 3) != 0) || ((arg2 & 3) != 0); - if (v) - { - trap(SPARC_TAG_OVERFLOW); - } - else - { - TEST_ICC_NZ(result); - if (result > arg1) - SET_ICC_C_FLAG; - SET_RDREG(result); - } - break; - } - case 36: // mulscc - { - // Explanatory quotes from The SPARC Architecture Manual Version 8, pg. 112 (pg. 110 in sparcv8.pdf) - - // (1) The multiplier is established as r[rs2] if the i field is zero, or sign_ext(simm13) if the i field is one. - UINT32 multiplier = arg2; - - // (2) A 32-bit value is computed by shifting r[rs1] right by one bit with "N xor V" from the PSR replacing the - // high-order bit. (This is the proper sign for the previous partial product.) - UINT32 rs1 = arg1; - bool n = ICC_N_SET; - bool v = ICC_V_SET; - UINT32 shifted = (rs1 >> 1) | ((n ^ v) ? 0x80000000 : 0); - - if (m_y & 1) - { // (3) If the least significant bit of the Y register = 1, the shifted value from step (2) is added to the multiplier. - arg1 = multiplier; - arg2 = shifted; - } - else - { // If the LSB of the Y register = 0, then 0 is added to the shifted value from step (2). - arg1 = shifted; - arg2 = 0; - } - - // (4) The sum from step (3) is written into r[rd]. - UINT32 result = arg1 + arg2; - SET_RDREG(result); - - // (5) The integer condition codes, icc, are updated according to the addition performed in step (3). - TEST_ICC_NZ(result); - if ((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000)) - SET_ICC_V_FLAG; - if (result < arg1 || result < arg2) - SET_ICC_C_FLAG; - - // (6) The Y register is shifted right by one bit, with the LSB of the unshifted r[rs1] replacing the MSB of Y. - m_y = (m_y >> 1) | ((rs1 & 1) ? 0x80000000 : 0); - break; - } - case 37: // sll - SET_RDREG(arg1 << arg2); - break; - case 38: // srl - SET_RDREG(arg1 >> arg2); - break; - case 39: // sra - SET_RDREG(INT32(arg1) >> arg2); - break; - case 40: // rdy - if (RS1 == 0) - { // rd y - SET_RDREG(m_y); - } -#if SPARCV8 - else if (RS1 == 15 && RD == 0) - { // stbar, SPARCv8 - // no-op, as this implementation assumes Total Store Ordering - } - else - { // rd asr, SPARCv8 - logerror("Unimplemented instruction: rd asr"); - } -#endif - break; - case 41: // rd psr - if (IS_USER) - { - trap(SPARC_PRIVILEGED_INSTRUCTION); - } - else - { - SET_RDREG(m_psr); - } - break; - case 42: // rd wim - if (IS_USER) - { - trap(SPARC_PRIVILEGED_INSTRUCTION); - } - else - { - SET_RDREG(m_wim); - } - break; - case 43: // rd tbr - if (IS_USER) - { - trap(SPARC_PRIVILEGED_INSTRUCTION); - } - else - { - SET_RDREG(m_tbr); - } - break; - case 48: - if (RD == 0) - { // wr y - m_y = arg1 ^ arg2; - } -#if SPARCV8 - else - { // wr asr, SPARCv8 - logerror("Unimplemented instruction: wr asr"); - } -#endif - break; - case 49: // wr psr - if (IS_USER) - { - trap(SPARC_PRIVILEGED_INSTRUCTION); - } - else - { - UINT32 new_psr = (arg1 ^ arg2) & ~PSR_ZERO_MASK; - if ((new_psr & PSR_CWP_MASK) >= WINDOW_COUNT) - { - trap(SPARC_ILLEGAL_INSTRUCTION); - } - else - { - m_psr = new_psr; - BREAK_PSR; - } - } - break; - case 50: // wr wim - if (IS_USER) - { - trap(SPARC_PRIVILEGED_INSTRUCTION); - } - else - { - m_wim = (arg1 ^ arg2) & 0x7f; - } - break; - case 51: // wr tbr - if (IS_USER) - { - trap(SPARC_PRIVILEGED_INSTRUCTION); - } - else - { - m_tbr = (arg1 ^ arg2) & 0xfffff000; - printf("wr (%08x ^ %08x) & 0xfffff000 (%08x),tbr", arg1, arg2, m_tbr); - } - break; - case 52: // FPop1 - if (FPU_DISABLED) - { - trap(SPARC_FLOATING_POINT_DISABLED); - } - break; - case 53: // FPop2 - if (FPU_DISABLED) - { - trap(SPARC_FLOATING_POINT_DISABLED); - } - break; - case 56: // jmpl - { - UINT32 addr = ADDRESS; - m_icount--; - if (addr & 3) - { - trap(SPARC_MEM_ADDRESS_NOT_ALIGNED); - } - else - { - SET_RDREG(PC); - PC = nPC; - nPC = addr; - return false; - } - break; - } - case 57: // rett - { - UINT8 new_cwp = (m_cwp + 1) % WINDOW_COUNT; - if (TRAPS_ENABLED) - { - if (IS_USER) - { - trap(SPARC_PRIVILEGED_INSTRUCTION); - } - else - { - trap(SPARC_ILLEGAL_INSTRUCTION); - } - break; - } - else - { - if (IS_USER) - { - trap(SPARC_RESET, SPARC_PRIVILEGED_INSTRUCTION); - break; - } - else if (m_wim & (1 << new_cwp)) - { - trap(SPARC_RESET, SPARC_WINDOW_UNDERFLOW); - break; - } - else if (ADDRESS & 3) - { - trap(SPARC_RESET, SPARC_MEM_ADDRESS_NOT_ALIGNED); - break; - } - } - - m_cwp = new_cwp; - - m_s = m_ps; - m_insn_asi = m_s ? 9 : 8; - m_data_asi = m_s ? 11 : 10; - m_et = true; - - UINT32 target = arg1 + arg2; - PC = nPC; - nPC = target; - return false; - } - case 58: // ticc - return execute_ticc(op); -#if SPARCV8 - case 59: - // SPARCv8 - if (RD == 0) - { // flush, SPARCv8 - } + case OP3_CPOP2: // SPARCv8 break; #endif - case 60: // save - { - UINT8 new_cwp = ((m_cwp + WINDOW_COUNT) - 1) % WINDOW_COUNT; - if (m_wim & (1 << new_cwp)) - { - trap(SPARC_WINDOW_OVERFLOW); - } - else - { - save_restore_update_cwp(op, new_cwp); - } - break; - } - case 61: // restore - { - UINT8 new_cwp = (m_cwp + 1) % WINDOW_COUNT; - if (m_wim & (1 << new_cwp)) - { - trap(SPARC_WINDOW_UNDERFLOW); - } - else - { - save_restore_update_cwp(op, new_cwp); - } - break; - } + default: - trap(SPARC_ILLEGAL_INSTRUCTION); + m_trap = 1; + m_illegal_instruction = 1; break; } - - return true; } @@ -1009,33 +1508,766 @@ void mb86901_device::update_gpr_pointers() { for (int i = 0; i < 8; i++) { - m_regs[ 8 + i] = &m_r[8 + (( 0 + m_cwp * 16 + i) % (WINDOW_COUNT * 16))]; - m_regs[16 + i] = &m_r[8 + (( 8 + m_cwp * 16 + i) % (WINDOW_COUNT * 16))]; - m_regs[24 + i] = &m_r[8 + ((16 + m_cwp * 16 + i) % (WINDOW_COUNT * 16))]; + m_regs[ 8 + i] = &m_r[8 + (( 0 + m_cwp * 16 + i) % (NWINDOWS * 16))]; + m_regs[16 + i] = &m_r[8 + (( 8 + m_cwp * 16 + i) % (NWINDOWS * 16))]; + m_regs[24 + i] = &m_r[8 + ((16 + m_cwp * 16 + i) % (NWINDOWS * 16))]; } } -bool mb86901_device::check_main_traps(UINT32 op, bool privileged, UINT32 alignment, UINT8 registeralign, bool noimmediate) + +//------------------------------------------------- +// execute_store - execute a store-type opcode +//------------------------------------------------- + +void mb86901_device::execute_store(UINT32 op) { - bool trap_queued = false; - if (privileged && !m_s) + /* The SPARC Instruction Manual: Version 8, page 165, "Appendix C - ISP Descriptions - Store Instructions" (SPARCv8.pdf, pg. 162) + + if ( (S = 0) and (STDA or STA or STHA or STBA or STDFQ or STDCQ) ) then ( + trap <- 1; + privileged_instruction <- 1 + ) else if ((i = 1) and (STDA or STA or STHA or STBA)) then ( + trap <- 1; + illegal_instruction <- 1 + ); + next; + if (trap = 0) then ( + if (STD or ST or STH or STB or STF or STDF or STFSR or STDFQ or STCSR or STC or STDC or STDCQ) then ( + address <- r[rs1] + (if (i = 0) then r[rs2] else sign_extend(simm13)); + addr_space <- (if (S = 0) then 10 else 11) + ) else if (STDA or STA or STHA or STBA) then ( + address <- r[rs1] + r[rs2]; + addr_space <- asi + ); + if ((STF or STDF or STFSR or STDFQ) and + ((EF = 0) or (bp_FPU_present = 0)) ) then ( + trap <- 1; + fp_disabled <- 1; + ); + if ((STC or STDC or STCSR or STDCQ) and + ((EC = 0) or (bp_CP_present = 0)) ) then ( + trap <- 1; + cp_disabled <- 1; + ) + ); + next; + if (trap = 0) then ( + if ((STH or STHA) and (address<0> != 0)) then ( + trap <- 1; + mem_address_not_aligned <- 1 + ) else if ((ST or STA or STF or STFSR or STC or STCSR) and (address<1:0> != 0)) then ( + trap <- 1; + mem_address_not_aligned <- 1 + ) else if ((STD or STDA or STDF or STDFQ or STDC or STDCQ) and (address<2:0> != 0)) then ( + trap <- 1; + mem_address_not_aligned <- 1 + ) else ( + if (STDFQ and ((implementation has no floating-point queue) or (FSR.qne = 0))) then ( + trap <- 1; + fp_exception <- 1; + ftt <- sequence_error; + ); + if (STDCQ and ((implementation has no coprocessor queue)) then ( + trap <- 1; + cp_exception <- 1; + { possibly additional implementation-dependent actions } + ); + if (STDF and (rd<0> != 0)) then ( + trap <- 1; + fp_exception <- 1; + ftt <- invalid_fp_register; + ) + ) + ); + next; + if (trap = 0) then ( + if (STF) then ( byte_mask <- 1111; data0 <- f[rd] ) + else if (STC) then ( byte_mask <- 1111; data0 <- implementation_dependent_value ) + else if (STDF) then ( byte_mask <- 1111; data0 <- f[rd & 0x1e] ) + else if (STDC) then ( byte_mask <- 1111; data0 <- implementation_dependent_value ) + else if (STD or STDA) then ( byte_mask <- 1111; data0 <- r[rd & 0x1e] ) + else if (STDFQ) then ( byte_mask <- 1111; data0 <- implementation_dependent_value ) + else if (STDCQ) then ( byte_mask <- 1111; data0 <- implementation_dependent_value ) + else if (STFSR) then ( + while ((FSR.qne = 1) and (trap = 0)) ( + // wait for pending floating-point instructions to complete + ) + next; + byte_mask <- 1111; data0 <- FSR + ) else if (STCSR) then ( + { implementation-dependent actions } + byte_mask <- 1111; data0 <- CSR + ) else if (ST or STA) then ( byte_mask <- 1111; data0 = r[rd] ) + else if (STH or STHA) then ( + if (address<1:0> = 0) then ( + byte_mask <- 1100; data0 <- shift_left_logical(r[rd], 16) ) + else if (address<1:0> = 2) then ( + byte_mask <- 0011; data0 <- r[rd] ) + ) else if (STB or STBA) then ( + if (address<1:0> = 0) then ( + byte_mask <- 1000; data0 <- shift_left_logical(r[rd], 24) ) + ) else if (address<1:0> = 1) then ( + byte_mask <- 0100; data0 <- shift_left_logical(r[rd], 16) ) + ) else if (address<1:0> = 2) then ( + byte_mask <- 0010; data0 <- shift_left_logical(r[rd], 8) ) + ) else if (address<1:0> = 3) then ( + byte_mask <- 0001; data0 <- r[rd] ) + ) + ); + ); + next; + if (trap = 0) then ( + MAE <- memory_write(addr_space, address, byte_mask, data1); + next; + if (MAE = 1) then ( + trap <- 1; + data_access_exception <- 1 + ) + ); + if ((trap = 0) and (STD or STDA or STDF or STDC or STDFQ or STDCQ)) then ( + if (STD or STDA) then ( data1 <- r[rd or 00001] ) + else if (STDF) then ( data1 <- f[rd or 00001] ) + else if (STDC) then ( data1 <- implementation_dependent_value } + else if (STDFQ) then ( data1 <- implementation_dependent_value } + else if (STDCQ) then ( data1 <- implementation_dependent_value } + next; + MAE <- memory_write(addr_space, address + 4, 1111, data1); + next; + if (MAE = 1) then ( { MAE = 1 only due to a "non-resumable machine-check error" } + trap <- 1; + data_access_exception <- 1 + ) + ); + */ + + if (IS_USER && (STDA || STA || STHA || STBA || STDFQ || STDCQ)) { - trap(SPARC_PRIVILEGED_INSTRUCTION); - trap_queued = true; + m_trap = 1; + m_privileged_instruction = 1; } - if (alignment & ADDRESS) + else if (USEIMM && (STDA || STA || STHA || STBA)) { - trap(SPARC_MEM_ADDRESS_NOT_ALIGNED); - trap_queued = true; + m_trap = 1; + m_illegal_instruction = 1; } - if ((registeralign & RD) || (noimmediate && USEIMM)) + + UINT32 address = 0; + UINT8 addr_space = 0; + if (!m_trap) { - trap(SPARC_ILLEGAL_INSTRUCTION); - trap_queued = true; + if (STD || ST || STH || STB || STF || STDF || STFSR || STDFQ || STCSR || STC || STDC || STDCQ) + { + address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + addr_space = (IS_USER ? 10 : 11); + } + else if (STDA || STA || STHA || STBA) + { + address = RS1REG + RS2REG; + addr_space = ASI; + } + if ((STF || STDF || STFSR || STDFQ) && (!EF || !m_bp_fpu_present)) + { + m_trap = 1; + m_fp_disabled = 1; + } + if ((STC || STDC || STCSR || STDCQ) && (!EC || !m_bp_cp_present)) + { + m_trap = 1; + m_cp_disabled = 1; + } + } + + if (!m_trap) + { + if ((STH || STHA) && ((address & 1) != 0)) + { + m_trap = 1; + m_mem_address_not_aligned = 1; + } + else if ((ST || STA || STF || STFSR || STC || STCSR) && ((address & 3) != 0)) + { + m_trap = 1; + m_mem_address_not_aligned = 1; + } + else if ((STD || STDA || STDF || STDFQ || STDC || STDCQ) && ((address & 7) != 0)) + { + m_trap = 1; + m_mem_address_not_aligned = 1; + } + else + { + if (STDFQ) + { + // assume no floating-point queue for now + m_trap = 1; + m_fp_exception = 1; + m_ftt = m_fpu_sequence_err; + } + if (STDCQ) + { + // assume no coprocessor queue for now + m_trap = 1; + m_cp_exception = 1; + // { possibly additional implementation-dependent actions } + } + if (STDF && ((RD & 1) != 0)) + { + m_trap = 1; + m_fp_exception = 1; + m_ftt = 0xff; + } + } + } + + UINT32 data0 = 0; + if (!m_trap) + { + //UINT8 byte_mask; + if (STF) + { + //byte_mask = 15; + data0 = FREG(RD); + } + else if (STC) + { + //byte_mask = 15; + data0 = 0; + } + else if (STDF) + { + //byte_mask = 15; + data0 = FREG(RD & 0x1e); + } + else if (STDC) + { + //byte_mask = 15; + data0 = 0; + } + else if (STD || STDA) + { + //byte_mask = 15; + data0 = REG(RD & 0x1e); + } + else if (STDFQ) + { + //byte_mask = 15; + data0 = 0; + } + else if (STDCQ) + { + //byte_mask = 15; + data0 = 0; + } + else if (STFSR) + { + // while ((FSR.qne = 1) and (trap = 0)) ( + // wait for pending floating-point instructions to complete + // ) + // next; + //byte_mask = 15; + data0 = FSR; + } + else if (STCSR) + { + // { implementation-dependent actions } + //byte_mask = 15; + data0 = 0; + } + else if (ST || STA) + { + //byte_mask = 15; + data0 = REG(RD); + } + else if (STH or STHA) + { + if ((address & 3) == 0) + { + //byte_mask = 12; + data0 = REG(RD) << 16; + } + else if ((address & 3) == 2) + { + //byte_mask = 3; + data0 = REG(RD); + } + } + else if (STB or STBA) + { + if ((address & 3) == 0) + { + //byte_mask = 8; + data0 = REG(RD) << 24; + } + else if ((address & 3) == 1) + { + //byte_mask = 4; + data0 = REG(RD) << 16; + } + else if ((address & 3) == 2) + { + //byte_mask = 2; + data0 = REG(RD) << 8; + } + else if ((address & 3) == 3) + { + //byte_mask = 1; + data0 = REG(RD); + } + } + } + + if (!m_trap) + { + write_sized_word(addr_space, address, data0, (ST || STA || STD || STDA || STF || STDF || STDFQ || STFSR || STC || STDC || STDCQ || STCSR) ? 4 : ((STH || STHA) ? 2 : 1)); + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + } + } + if (!m_trap && (STD || STDA || STDF || STDC || STDFQ || STDCQ)) + { + UINT32 data1 = 0; + if (STD || STDA) + { + data1 = REG(RD | 1); + } + else if (STDF) + { + data1 = FREG(RD | 1); + } + else if (STDC) + { + data1 = 0; + } + else if (STDFQ) + { + data1 = 0; + } + else if (STDCQ) + { + data1 = 0; + } + + write_sized_word(addr_space, address + 4, data1, 4); + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + } } - return trap_queued; } +//------------------------------------------------- +// execute_load - execute a load-type opcode +//------------------------------------------------- + +void mb86901_device::execute_load(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 163, "Appendix C - ISP Descriptions - C.9. Instruction Defintions - Load Instructions" (SPARCv8.pdf, pg. 160) + + if (LDD or LD or LDSH or LDUH or LDSB or LDUB or LDDF or LDF or LDFSR or LDDC or LDC or LDCSR) then ( + address <- r[rs1] + (if (i = 0) then r[rs2] else sign_extend(simm13)); + addr_space <- (if (S = 0) then 10 else 11) + ) else if (LDDA or LDA or LDSHA or LDUHA or LDSBA or LDUBA) then ( + if (S = 0) then ( + trap <- 1; + privileged_instruction <- 1 + ) else if (i = 1) then ( + trap <- 1; + illegal_instruction <- 1 + ) else ( + address <- r[rs1] + r[rs2]; + addr_space <- asi + ) + ) + next; + if (trap = 0) then ( + if ( (LDF or LDDF or LDFSR) and ((EF = 0) or (bp_FPU_present = 0)) then ( + trap <- 1; + fp_disabled <- 1 + ) else if ( (LDC or LDDC or LDCSR) and ((EC = 0) or (bp_CP_present = 0)) then ( + trap <- 1; + cp_disabled <- 1 + ) else if ( ( (LDD or LDDA or LDDF or LDDC) and (address<2:0> != 0)) or + ((LD or LDA or LDF or LDFSR or LDC or LDCSR) and (address<1:0> != 0)) or + ((LDSH or LDSHA or LDUH or LDUHA) and address<0> != 0) ) then ( + trap <- 1; + mem_address_not_aligned <- 1 + ) else if (LDDF and (rd<0> != 0)) then ( + trap <- 1; + fp_exception <- 1; + ftt <- invalid_fpr_register + ) else if ((LDF or LDDF or LDFSR) and (an FPU sequence error is detected)) then ( + trap <- 1; + fp_exception <- 1; + ftt <- sequence_error + ) else if ((LDC or LDDC or LDCSR) and (a CP sequence error is detected)) then ( + trap <- 1; + cp_exception <- 1; + { possibly additional implementation-dependent actions } + ) + ); + next; + if (trap = 0) then { + (data, MAE) <- memory_read(addr_space, address); + next; + if (MAE = 1) then ( + trap <- 1; + data_access_exception <- 1; + ) else ( + if (LDSB or LDSBA or LDUB or LDUBA) then ( + if (address<1:0> = 0) then byte <- data<31:24> + else if (address<1:0> = 1) then byte <- data<23:16> + else if (address<1:0> = 2) then byte <- data<15: 8> + else if (address<1:0> = 3) then byte <- data< 7: 0> + next; + if (LDSB or LDSBA) then + word0 <- sign_extend_byte(byte) + else + word0 <- zero_extend_byte(byte) + ) else if (LDSH or LDSHA or LDUH or LDUHA) then ( + if (address<1:0> = 0) then halfword <- data<31:16> + else if (address<1:0> = 2) then halfword <- data<15: 0> + next; + if (LDSH or LDSHA) then + word0 <- sign_extend_halfword(halfword) + else + word0 <- zero_extend_halfword(halfword) + ) else + word0 <- data + ) + ); + next; + if (trap = 0) then ( + if ( (rd != 0) and (LD or LDA or LDSH or LDSHA + or LDUHA or LDUH or LDSB or LDSBA or LDUB or LDUBA) ) then + r[rd] <- word0 + else if (LDF) then f[rd] <- word0 + else if (LDC) then { implementation-dependent actions } + else if (LDFSR) then FSR <- word0 + else if (LDCSR) then CSR <- word0 + else if (LDD or LDDA) then r[rd and 11110] <- word0 + else if (LDDF) then f[rd and 11110] <- word0 + else if (LDDC) then { implementation-dependent actions } + ); + next; + if (((trap = 0) and (LDD or LDDA or LDDF or LDDC)) then ( + (word1, MAE) <- memory_read(addr_space, address + 4); + next; + if (MAE = 1) then ( { MAE = 1 only due to a "non-resumable machine-check error" } + trap <- 1; + data_access_exception <- 1 ) + else if (LDD or LDDA) then r[rd or 1] <- word1 + else if (LDDF) then f[rd or 1] <- word1 + else if (LDDC) then { implementation-dependent actions } + ); + */ + + UINT32 address = 0; + UINT8 addr_space = 0; + if (LDD || LD || LDSH || LDUH || LDSB || LDUB || LDDF || LDF || LDFSR || LDDC || LDC || LDCSR) + { + address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + addr_space = (IS_USER ? 10 : 11); + } + else if (LDDA || LDA || LDSHA || LDUHA || LDSBA || LDUBA) + { + if (IS_USER) + { + m_trap = 1; + m_privileged_instruction = 1; + } + else if (USEIMM) + { + m_trap = 1; + m_illegal_instruction = 1; + } + else + { + address = RS1REG + RS2REG; + addr_space = ASI; + } + } + + if (!m_trap) + { + if ((LDF || LDDF || LDFSR) && (EF == 0 || m_bp_fpu_present == 0)) + { + m_trap = 1; + m_fp_disabled = 1; + } + else if ((LDC || LDDC || LDCSR) && (EC == 0 || m_bp_cp_present == 0)) + { + m_trap = 1; + m_cp_disabled = 1; + } + else if (((LDD || LDDA || LDDF || LDDC) && ((address & 7) != 0)) || + ((LD || LDA || LDF || LDFSR || LDC || LDCSR) && ((address & 3) != 0)) || + ((LDSH || LDSHA || LDUH || LDUHA) && ((address & 1) != 0))) + { + m_trap = 1; + m_mem_address_not_aligned = 1; + } + else if (LDDF && ((RD & 1) != 0)) + { + m_trap = 1; + m_fp_exception = 1; + m_ftt = 0xff; + } + else if ((LDF || LDDF || LDFSR) && m_fpu_sequence_err != 0) + { + m_trap = 1; + m_fp_exception = 1; + m_ftt = m_fpu_sequence_err; + } + else if ((LDC || LDDC || LDCSR) && m_cp_sequence_err != 0) + { + m_trap = 1; + m_cp_exception = 1; + // possibly additional implementation-dependent actions + } + } + + UINT32 word0; + if (!m_trap) + { + UINT32 data = read_sized_word(addr_space, address, (LD || LDD || LDA || LDDA) ? 4 : ((LDUH || LDSH || LDUHA || LDSHA) ? 2 : 1)); + + if (m_mae) + { + m_trap = 1; + m_data_access_exception = 1; + } + else + { + if (LDSB || LDSBA || LDUB || LDUBA) + { + UINT8 byte = 0; + if ((address & 3) == 0) byte = (data >> 24) & 0xff; + else if ((address & 3) == 1) byte = (data >> 16) & 0xff; + else if ((address & 3) == 2) byte = (data >> 8) & 0xff; + else if ((address & 3) == 3) byte = data & 0xff; + + if (LDSB || LDSBA) + word0 = (((INT32)byte) << 24) >> 24; + else + word0 = byte; + } + else if (LDSH || LDSHA || LDUH || LDUHA) + { + UINT16 halfword = 0; + if ((address & 3) == 0) halfword = (data >> 16) & 0xffff; + else if ((address & 3) == 2) halfword = data & 0xffff; + + if (LDSH || LDSHA) + word0 = (((INT32)halfword) << 16) >> 16; + else + word0 = halfword; + } + else + { + word0 = data; + } + } + } + + if (!m_trap) + { + if ((RD != 0) && (LD || LDA || LDSH || LDSHA || LDUHA || LDUH || LDSB || LDSBA || LDUB || LDUBA)) + { + RDREG = word0; + } + else if (LDF) FDREG = word0; + else if (LDC) { } // implementation-dependent actions + else if (LDFSR) FSR = word0; + else if (LDD || LDDA) REG(RD & 0x1e) = word0; + else if (LDDF) FREG(RD & 0x1e) = word0; + else if (LDDC) { } // implementation-dependent actions + } + + if (!m_trap) + { + UINT32 word1 = read_sized_word(addr_space, address + 4, 4); + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + } + else if (LDD || LDDA) REG(RD | 1) = word1; + else if (LDDF) FREG(RD | 1) = word1; + else if (LDDC) { } // implementation-dependent actions + } +} + + +//------------------------------------------------- +// execute_ldstub - execute an atomic load-store +// instruction +//------------------------------------------------- + +void mb86901_device::execute_ldstub(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 169, "Appendix C - ISP Descriptions - Atomic Load-Store Unsigned Byte Instructions" (SPARCv8.pdf, pg. 166) + + if (LDSTUB) then ( + address <- r[rs1] + (if (i = 0) then r[rs2] else sign_extend(simm13)); + addr_space <- (if (S = 0) then 10 else 11) + } else if (LDSTUBA) then ( + if (S = 0) then ( + trap <- 1; + privileged_instruction <- 1 + ) else if (i = 1) then ( + trap <- 1; + illegal_instruction <- 1 + ) else ( + address <- r[rs1] + r[rs2]; + addr_space <- asi + ) + ); + next; + if (trap = 0) then ( + while ( (pb_block_ldst_byte = 1) or (pb_block_ldst_word = 1) ) then ( + { wait for lock(s) to be lifted } + { an implementation actually need only block when another LDSTUB or SWAP + is pending on the same byte in memory as the one addressed by this LDSTUB } + }; + next; + pb_block_ldst_byte <- 1; + next; + (data, MAE) <- memory_read(addr_space, address); + next; + if (MAE = 1) then ( + trap <- 1; + data_access_exception <- 1 + ) + ) + next; + if (trap = 0) then ( + if (address<1:0> = 0) then ( byte_mask <- 1000 ) + else if (address<1:0> = 1) then ( byte_mask <- 0100 ) + else if (address<1:0> = 2) then ( byte_mask <- 0010 ) + else if (address<1:0> = 3) then ( byte_mask <- 0001 ) + ; + next; + MAE <- memory_write(addr_space, address, byte_mask, FFFFFFFF); + next; + pb_block_ldst_byte <- 0; + if (MAE = 1) then ( { MAE = 1 only due to a "non-resumable machine-check error" } + trap <- 1; + data_access_exception <- 1 + ) else ( + if (address<1:0> = 0) then word <- zero_extend_byte(data<31:24>) + else if (address<1:0> = 1) then word <- zero_extend_byte(data<23:24>) + else if (address<1:0> = 2) then word <- zero_extend_byte(data<15: 8>) + else if (address<1:0> = 3) then word <- zero_extend_byte(data< 7: 0>) + next; + if (rd != 0) then r[rd] <- word + ) + ); + */ + + UINT32 address = 0; + UINT8 addr_space = 0; + if (LDSTUB) + { + address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + addr_space = (IS_USER ? 10 : 11); + } + else if (LDSTUBA) + { + if (IS_USER) + { + m_trap = 1; + m_privileged_instruction = 1; + } + else if (USEIMM) + { + m_trap = 1; + m_illegal_instruction = 1; + } + else + { + address = RS1REG + RS2REG; + addr_space = ASI; + } + } + + UINT32 data; + if (!m_trap) + { + while (m_pb_block_ldst_byte || m_pb_block_ldst_word) + { + // { wait for lock(s) to be lifted } + // { an implementation actually need only block when another LDSTUB or SWAP + // is pending on the same byte in memory as the one addressed by this LDSTUB } + } + + m_pb_block_ldst_byte = 1; + + data = read_sized_word(addr_space, address, 1); + + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + } + } + + if (!m_trap) + { + //UINT8 byte_mask; + if ((address & 3) == 0) + { + //byte_mask = 8; + } + else if ((address & 3) == 1) + { + //byte_mask = 4; + } + else if ((address & 3) == 2) + { + //byte_mask = 2; + } + else if ((address & 3) == 3) + { + //byte_mask = 1; + } + write_sized_word(addr_space, address, 0xffffffff, 1); + + m_pb_block_ldst_byte = 0; + + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + } + else + { + UINT32 word; + if ((address & 3) == 0) + { + word = (data >> 24) & 0xff; + } + else if ((address & 3) == 1) + { + word = (data >> 16) & 0xff; + } + else if ((address & 3) == 2) + { + word = (data >> 8) & 0xff; + } + else if ((address & 3) == 3) + { + word = data & 0xff; + } + if (RD != 0) + RDREG = word; + } + } +} + + //------------------------------------------------- // execute_group3 - execute an opcode in group 3 // (load/store) @@ -1056,221 +2288,54 @@ void mb86901_device::execute_group3(UINT32 op) switch (OP3) { - case 0: // ld - { - check_main_traps(op, false, 3, 0, false); - UINT32 result = read_word(m_data_asi, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); + case OP3_LD: + case OP3_LDUB: + case OP3_LDUH: + case OP3_LDD: + case OP3_LDSB: + case OP3_LDSH: + case OP3_LDA: + case OP3_LDUBA: + case OP3_LDUHA: + case OP3_LDDA: + case OP3_LDSBA: + case OP3_LDSHA: + case OP3_LDFPR: + case OP3_LDFSR: + case OP3_LDDFPR: + case OP3_LDCPR: + case OP3_LDCSR: + case OP3_LDDCPR: + execute_load(op); break; - } - case 1: // ldub - { - UINT32 result = read_byte(m_data_asi, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); + + case OP3_ST: + case OP3_STB: + case OP3_STH: + case OP3_STD: + case OP3_STA: + case OP3_STBA: + case OP3_STHA: + case OP3_STDA: + case OP3_STFPR: + case OP3_STFSR: + case OP3_STDFQ: + case OP3_STDFPR: + case OP3_STCPR: + case OP3_STCSR: + case OP3_STDCQ: + case OP3_STDCPR: + execute_store(op); break; - } - case 2: // lduh - { - check_main_traps(op, false, 1, 0, false); - UINT32 result = read_half(m_data_asi, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); + + case OP3_LDSTUB: + case OP3_LDSTUBA: + execute_ldstub(op); break; - } - case 3: // ldd - { - check_main_traps(op, false, 7, 1, false); - UINT32 result = read_word(m_data_asi, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); - result = read_word(m_data_asi, ADDRESS+4); - if (MAE || HOLD_BUS) - break; - REG(RD+1) = result; + + case OP3_SWAP: // SPARCv8 break; - } - case 4: // st - check_main_traps(op, false, 3, 0, false); - write_word(m_data_asi, ADDRESS, RDREG); - break; - case 5: // stb - write_byte(m_data_asi, ADDRESS, UINT8(RDREG)); - break; - case 6: // sth - check_main_traps(op, false, 1, 0, false); - write_word(m_data_asi, ADDRESS, UINT16(RDREG)); - break; - case 7: // std - check_main_traps(op, false, 7, 1, false); - write_word(m_data_asi, ADDRESS, RDREG); - if (MAE || HOLD_BUS) - break; - write_word(m_data_asi, ADDRESS+4, REG(RD+1)); - break; - case 9: // ldsb - { - UINT32 result = read_signed_byte(m_data_asi, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); - break; - } - case 10: // lsdh - { - check_main_traps(op, false, 1, 0, false); - UINT32 result = read_signed_half(m_data_asi, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); - break; - } - case 13: // ldstub - { - UINT32 result = read_byte(m_data_asi, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); - write_byte(m_data_asi, ADDRESS, 0xff); - break; - } - case 15: // swap, SPARCv8 - break; - case 16: // lda - { - check_main_traps(op, true, 3, 0, true); - UINT32 result = read_word(ASI, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); - break; - } - case 17: // lduba - { - check_main_traps(op, true, 0, 0, true); - UINT32 result = read_byte(ASI, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); - break; - } - case 18: // lduha - { - check_main_traps(op, true, 1, 0, true); - UINT32 result = read_half(ASI, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); - break; - } - case 19: // ldda - { - check_main_traps(op, true, 7, 1, true); - UINT32 result = read_word(ASI, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); - result = read_word(ASI, ADDRESS+4); - if (MAE || HOLD_BUS) - break; - REG(RD+1) = result; - break; - } - case 20: // sta - check_main_traps(op, true, 3, 0, true); - write_word(ASI, ADDRESS, RDREG); - break; - case 21: // stba - check_main_traps(op, true, 0, 0, true); - write_byte(ASI, ADDRESS, UINT8(RDREG)); - break; - case 22: // stha - check_main_traps(op, true, 1, 0, true); - write_half(ASI, ADDRESS, UINT16(RDREG)); - break; - case 23: // stda - check_main_traps(op, true, 7, 1, true); - write_word(ASI, ADDRESS, RDREG); - if (MAE || HOLD_BUS) - break; - write_word(ASI, ADDRESS+4, REG(RD+1)); - break; - case 25: // ldsba - { - check_main_traps(op, true, 0, 0, true); - UINT32 result = read_signed_byte(ASI, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); - break; - } - case 26: // ldsha - { - check_main_traps(op, true, 1, 0, true); - UINT32 result = read_signed_half(ASI, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); - break; - } - case 29: // ldstuba - { - check_main_traps(op, true, 0, 0, true); - UINT32 result = read_byte(ASI, ADDRESS); - if (MAE || HOLD_BUS) - break; - SET_RDREG(result); - write_byte(ASI, ADDRESS, 0xff); - break; - } - case 31: // swapa, SPARCv8 - break; - case 32: // ld fpr - if (FPU_DISABLED) - trap(SPARC_FLOATING_POINT_DISABLED); - break; - case 33: // ld fsr - if (FPU_DISABLED) - trap(SPARC_FLOATING_POINT_DISABLED); - break; - case 35: // ldd fpr - if (FPU_DISABLED) - trap(SPARC_FLOATING_POINT_DISABLED); - break; - case 36: // st fpr - if (FPU_DISABLED) - trap(SPARC_FLOATING_POINT_DISABLED); - break; - case 37: // st fsr - if (FPU_DISABLED) - trap(SPARC_FLOATING_POINT_DISABLED); - break; - case 38: // std fq, SPARCv8 - if (FPU_DISABLED) - trap(SPARC_FLOATING_POINT_DISABLED); - break; - case 39: // std fpr - if (FPU_DISABLED) - trap(SPARC_FLOATING_POINT_DISABLED); - break; - case 40: // ld cpr, SPARCv8 - break; - case 41: // ld csr, SPARCv8 - break; - case 43: // ldd cpr, SPARCv8 - break; - case 44: // st cpr, SPARCv8 - break; - case 45: // st csr, SPARCv8 - break; - case 46: // std cq, SPARCv8 - break; - case 47: // std cpr, SPARCv8 + case OP3_SWAPA: // SPARCv8 break; } @@ -1299,7 +2364,7 @@ bool mb86901_device::evaluate_condition(UINT32 op) case 0: take = false; break; // bn ba case 1: take = z; break; // bz bne case 2: take = z | (n ^ z); break; // ble bg - case 3: take = n ^ z; break; // bl bge + case 3: take = n ^ v; break; // bl bge case 4: take = c | z; break; // bleu bgu case 5: take = c; break; // bcs bcc case 6: take = n; break; // bneg bpos @@ -1312,35 +2377,60 @@ bool mb86901_device::evaluate_condition(UINT32 op) return take; } + //------------------------------------------------- // execute_bicc - execute a branch opcode //------------------------------------------------- -bool mb86901_device::execute_bicc(UINT32 op) +void mb86901_device::execute_bicc(UINT32 op) { - bool branch_taken = evaluate_condition(op); + /* The SPARC Instruction Manual: Version 8, page 178, "Appendix C - ISP Descriptions - Branch on Integer Condition Instructions" (SPARCv8.pdf, pg. 175) + eval_icc := ( + if (BNE) then (if (Z = 0) then 1 else 0); + if (BE) then (if (Z = 1) then 1 else 0); + if (BG) then (if ((Z or (N xor V)) = 0) then 1 else 0); + if (BLE) then (if ((Z or (N xor V)) = 1) then 1 else 0); + if (BGE) then (if ((N xor V) = 0) then 1 else 0); + if (BL) then (if ((N xor V) = 1) then 1 else 0); + if (BGU) then (if ((C = 0) and (Z = 0)) then 1 else 0); + if (BLEU) then (if ((C = 1) or (Z = 1)) then 1 else 0); + if (BCC) then (if (C = 0) then 1 else 0); + if (BCS) then (if (C = 1) then 1 else 0); + if (BPOS) then (if (N = 0) then 1 else 0); + if (BNEG) then (if (N = 1) then 1 else 0); + if (BVC) then (if (V = 0) then 1 else 0); + if (BVS) then (if (V = 1) then 1 else 0); + if (BA) then 1; + if (BN) then 0; + ) + PC <- nPC; + if (eval_icc = 1) then ( + nPC <- PC + sign_extend(disp22[]00); + if (BA and (a = 1)) then + annul <- 1 { only for annulling Branch-Always } + ) else ( + nPC <- nPC + 4; + if (a = 1) then + annul <- 1 { only for annulling branches other than BA } + ) + */ + + bool branch_taken = evaluate_condition(op); + UINT32 pc = PC; + PC = nPC; if (branch_taken) { - UINT32 brpc = PC + DISP22; - PC = nPC; - nPC = brpc; - return false; + nPC = pc + DISP22; + if (COND == COND_BA && ANNUL) + m_annul = 1; } else { - m_icount--; + nPC = nPC + 4; + if (ANNUL) + m_annul = 1; } - - if (ANNUL && (!branch_taken || COND == 8)) - { - PC = nPC; - nPC = PC + 4; - m_icount -= 1; - return false; - } - - return true; } @@ -1348,93 +2438,566 @@ bool mb86901_device::execute_bicc(UINT32 op) // execute_ticc - execute a conditional trap //------------------------------------------------- -bool mb86901_device::execute_ticc(UINT32 op) +void mb86901_device::execute_ticc(UINT32 op) { - bool trap_taken = evaluate_condition(op); + /* The SPARC Instruction Manual: Version 8, page 182, "Appendix C - ISP Descriptions - Trap on Integer Condition Instructions" (SPARCv8.pdf, pg. 179) - printf("ticc @ %x\n", PC); - if (trap_taken) + trap_eval_icc := ( + if (TNE) then (if (Z = 0) then 1 else 0); + if (TE) then (if (Z = 1) then 1 else 0); + if (TG) then (if ((Z or (N xor V)) = 0) then 1 else 0); + if (TLE) then (if ((Z or (N xor V)) = 1) then 1 else 0); + if (TGE) then (if ((N xor V) = 0) then 1 else 0); + if (TL) then (if ((N xor V) = 1) then 1 else 0); + if (TGU) then (if ((C = 0) and (Z = 0)) then 1 else 0); + if (TLEU) then (if ((C = 1) or (Z = 1)) then 1 else 0); + if (TCC) then (if (C = 0) then 1 else 0); + if (TCS) then (if (C = 1) then 1 else 0); + if (TPOS) then (if (N = 0) then 1 else 0); + if (TNEG) then (if (N = 1) then 1 else 0); + if (TVC) then (if (V = 0) then 1 else 0); + if (TVS) then (if (V = 1) then 1 else 0); + if (TA) then 1; + if (TN) then 0; + ) + + trap_number := r[rs1] + (if (i = 0) then r[rs2] else sign_extend(software_trap#)); + + if (Ticc) then ( + if (trap_eval_icc = 1) then ( + trap <- 1; + trap_instruction <- 1; + ticc_trap_type <- trap_number<6:0> + ) else ( + PC <- nPC; + nPC <- nPC + 4; + ) + ); + */ + + bool trap_eval_icc = evaluate_condition(op); + + UINT8 trap_number = RS1REG + (USEIMM ? SIMM7 : RS2REG); + + if (COND) { - UINT32 arg2 = USEIMM ? SIMM7 : RS2REG; - UINT8 tt = 128 + ((RS1REG + arg2) & 0x7f); - trap(SPARC_TRAP_INSTRUCTION, tt); - m_icount -= 3; - return false; + if (trap_eval_icc) + { + m_trap = 1; + m_trap_instruction = 1; + m_ticc_trap_type = trap_number & 0x7f; + } + else + { + PC = nPC; + nPC = nPC + 4; + } } +} - return true; + + +//------------------------------------------------- +// select_trap - prioritize traps and perform any +// additional functions from taking them +//------------------------------------------------- + +void mb86901_device::select_trap() +{ + if (!m_trap) + return; + + if (m_reset_trap) + { + m_trap = 0; + return; + } + else if (!ET) + { + m_execute_mode = 0; + m_error_mode = 1; + } + else if (m_data_store_error) + m_tt = 0x2b; + else if (m_instruction_access_error) + m_tt = 0x21; + else if (m_r_register_access_error) + m_tt = 0x20; + else if (m_instruction_access_exception) + m_tt = 0x01; + else if (m_privileged_instruction) + m_tt = 0x03; + else if (m_illegal_instruction) + m_tt = 0x02; + else if (m_fp_disabled) + m_tt = 0x04; + else if (m_cp_disabled) + m_tt = 0x24; + else if (m_unimplemented_FLUSH) + m_tt = 0x25; + else if (m_window_overflow) + m_tt = 0x05; + else if (m_window_underflow) + m_tt = 0x06; + else if (m_mem_address_not_aligned) + m_tt = 0x07; + else if (m_fp_exception) + m_tt = 0x08; + else if (m_cp_exception) + m_tt = 0x28; + else if (m_data_access_error) + m_tt = 0x29; + else if (m_data_access_exception) + m_tt = 0x09; + else if (m_tag_overflow) + m_tt = 0x0a; + else if (m_division_by_zero) + m_tt = 0x2a; + else if (m_trap_instruction) + m_tt = 0x80 | m_ticc_trap_type; + else if (m_interrupt_level > 0) + m_tt = 0x10 | m_interrupt_level; + + m_instruction_access_exception = 0; + m_illegal_instruction = 0; + m_privileged_instruction = 0; + m_fp_disabled = 0; + m_cp_disabled = 0; + m_window_overflow = 0; + m_window_underflow = 0; + m_mem_address_not_aligned = 0; + m_fp_exception = 0; + m_cp_exception = 0; + m_data_access_exception = 0; + m_tag_overflow = 0; + m_division_by_zero = 0; + m_trap_instruction = 0; + m_interrupt_level = 0; } //------------------------------------------------- -// trap - flag an incoming trap of a given -// type +// execute_trap - prioritize and invoke traps +// that have been flagged by the previous +// instructions, if any. //------------------------------------------------- -void mb86901_device::trap(UINT8 type, UINT8 tt_override) +void mb86901_device::execute_trap() { - if (type == SPARC_RESET) + /* The SPARC Instruction Manual: Version 8, page 161, "Appendix C - C.8. Traps" (SPARCv8.pdf, pg. 158) + + select_trap; { see below } + next; + + if (error_mode = 0) then ( + ET <- 0; + PS <- S; + CWP <- (CWP - 1) modulo NWINDOWS; + + next; + if (annul = 0) then ( + r[17] <- PC; + r[18] <- nPC; + ) else { annul != 0) } ( + r[17] <- nPC; + r[18] <- nPC + 4; + annul <- 0; + ) + + next; + S <- 1; + if (reset_trap = 0) then ( + PC <- TBR; + nPC <- TBR + 4; + ) else { reset_trap = 1 } ( + PC <- 0; + nPC <- 4; + reset_trap <- 0; + ) + ); + + select_trap := ( + if (reset_trap = 1) then { ignore ET, and leave tt unchanged } + else if (ET = 0) then ( + execute_mode <- 0; + error_mode <- 1 ) + else if (data_store_error = 1) then tt <- 00101011 + else if (instruction_access_error = 1) then tt <- 00100001 + else if (r_register_access_error = 1) then tt <- 00100000 + else if (instruction_access_exception = 1) then tt <- 00000001 + else if (privileged_instruction = 1) then tt <- 00000011 + else if (illegal_instruction = 1) then tt <- 00000010 + else if (fp_disabled = 1) then tt <- 00000100 + else if (cp_disabled = 1) then tt <- 00100100 + else if (unimplemented_FLUSH = 1) then tt <- 00100101 + else if (window_overflow = 1) then tt <- 00000101 + else if (window_underflow = 1) then tt <- 00000110 + else if (mem_address_not_aligned = 1) then tt <- 00000111 + else if (fp_exception = 1) then tt <- 00001000 + else if (cp_exception = 1) then tt <- 00101000 + else if (data_access_error = 1) then tt <- 00101001 + else if (data_access_exception = 1) then tt <- 00001001 + else if (tag_overflow = 1) then tt <- 00001010 + else if (division_by_zero = 1) then tt <- 00101010 + else if (trap_instruction = 1) then tt <- 1[]ticc_trap_type + else if (interrupt_level > 0) then tt <- 0001[]interrupt_level; + + next; + + trap <- 0; + instruction_access_exception <- 0; + illegal_instruction <- 0; + privileged_instruction <- 0; + fp_disabled <- 0; + cp_disabled <- 0; + window_overflow <- 0; + window_underflow <- 0; + mem_address_not_aligned <- 0; + fp_exception <- 0; + cp_exception <- 0; + data_access_exception <- 0; + tag_overflow <- 0; + division_by_zero <- 0; + trap_instruction <- 0; + interrupt_level <- 0; + ); + */ + + if (!m_trap) + return; + + select_trap(); + + if (!m_error_mode) { - m_queued_priority = m_trap_priorities[0]; - m_queued_tt = tt_override; - } - else - { - if (type == SPARC_TRAP_INSTRUCTION) + ET = 0; + PS = S; + CWP = ((CWP + NWINDOWS) - 1) % NWINDOWS; + + if (m_annul == 0) { - type = tt_override; + REG(17) = PC; + REG(18) = nPC; + } + else + { + REG(17) = nPC; + REG(18) = nPC + 4; + m_annul = 0; } - if (type >= SPARC_INT1 && type <= SPARC_INT14) + S = 1; + if (!m_reset_trap) { - if (!ET) - return; - int irl = (type - SPARC_INT1) + 1; - if (irl <= PIL) - return; + PC = TBR; + nPC = TBR + 4; } - if (m_trap_priorities[type] < m_queued_priority) + else { - m_queued_priority = m_trap_priorities[type]; - m_queued_tt = type; + PC = 0; + nPC = 4; + m_reset_trap = 0; + } + } + + MAKE_PSR; + update_gpr_pointers(); +} + + +//------------------------------------------------- +// complete_instruction_execution - execute a +// single fetched instruction that has been +// checked for FP-disabled, CP-disabled, and +// validity. +//------------------------------------------------- + +void mb86901_device::complete_instruction_execution(UINT32 op) +{ + switch (OP) + { + case OP_TYPE0: // Bicc, SETHI, FBfcc + switch (OP2) + { + case OP2_UNIMP: // unimp + printf("unimp @ %x\n", PC); + break; + case OP2_BICC: // branch on integer condition codes + execute_bicc(op); + break; + case OP2_SETHI: // sethi + SET_RDREG(IMM22); + break; + case OP2_FBFCC: // branch on floating-point condition codes + printf("fbfcc @ %x\n", PC); + break; +#if SPARCV8 + case OP2_CBCCC: // branch on coprocessor condition codes, SPARCv8 + break; +#endif + default: + printf("unknown %08x @ %x\n", op, PC); + break; + } + break; + + case OP_CALL: // call + { + UINT32 pc = PC; + UINT32 callpc = PC + DISP30; + PC = nPC; + nPC = callpc; + + REG(15) = pc; + break; + } + + case OP_ALU: + execute_group2(op); + break; + + case OP_LDST: + execute_group3(op); + break; + default: + break; + } +} + + +//------------------------------------------------- +// dispatch_instruction - dispatch the previously +// fetched instruction +//------------------------------------------------- + +void mb86901_device::dispatch_instruction(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 159, "Appendix C - ISP Descriptions - C.6. Instruction Dispatch" (SPARCv8.pdf, pg. 156) + + illegal_IU_instr :- ( + if ( ( (op == 00) and (op2 == 000) ) { UNIMP instruction } + or + ( ((op=11) or (op=10)) and (op3=unassigned) ) + then 1 else 0 + + if (illegal_IU_instr = 1) then ( + trap <- 1 + illegal_instruction <- 1 + ); + if ((FPop1 or FPop2 or FBfcc) and ((EF = 0) or (bp_FPU_present = 0))) then ( + trap <- 1; + fp_disabled <- 1 + ); + if (CPop1 or CPop2 or CBccc) and ((EC = 0) or (bp_CP_present = 0))) then ( + trap <- 1; + cp_disabled <- 1 + ); + next; + if (trap = 0) then ( + { code for specific instruction, defined below } + ); + */ + bool illegal_IU_instr = (OP == 0 && OP2 == 0) || ((OP == 3 && !m_ldst_op3_assigned[OP3]) || (OP == 2 && !m_alu_op3_assigned[OP3])); + + if (illegal_IU_instr) + { + m_trap = 1; + m_illegal_instruction = 1; + + } + if (((OP == OP_ALU && (OP3 == OP3_FPOP1 || OP3 == OP3_FPOP2)) || (OP == OP_TYPE0 && OP2 == OP2_FBFCC)) && (!EF || !m_bp_fpu_present)) + { + m_trap = 1; + m_fp_disabled = 1; + } + if (((OP == OP_ALU && (OP3 == OP3_CPOP1 || OP3 == OP3_CPOP2)) || (OP == OP_TYPE0 && OP2 == OP2_CBCCC)) && (!EC || !m_bp_cp_present)) + { + m_trap = 1; + m_cp_disabled = 1; + } + + if (!m_trap) + { + complete_instruction_execution(op); + } +} + + +//------------------------------------------------- +// complete_fp_execution - completes execution +// of a floating-point operation +//------------------------------------------------- + +void mb86901_device::complete_fp_execution(UINT32 /*op*/) +{ +} + + +//------------------------------------------------- +// execute_step - perform one step in execute +// mode (versus error or reset modes) +//------------------------------------------------- + +void mb86901_device::execute_step() +{ + /* The SPARC Instruction Manual: Version 8, page 156, "Appendix C - ISP Descriptions - C.5. Processor States and Instruction Dispatch" (SPARCv8.pdf, pg. 153) + + if (bp_reset_in = 1) then ( + execute_mode <- 0; + reset_mode <- 1; + break { out of while (execute_mode = 1) loop } + ) else if ((ET = 1) and ((bp_IRL = 15) or (bp_IRL > PIL))) then ( + trap <- 1; + interrupt_level <- bp_IRL + ); + next; + + if (trap = 1) then execute_trap; { See Section C.8 } + + if (execute_mode = 1) then ( { execute_trap may have set execute_mode to 0 } + + { the following code emulates the delayed nature of the write-state-register instructions. + PSR <- PSR'; PSR' <- PSR''; PSR'' <- PSR'''; PSR''' <- PSR''''; + ASR <- ASR'; ASR' <- ASR''; ASR'' <- ASR'''; ASR''' <- ASR''''; + TBR <- TBR'; TBR' <- TBR''; TBR'' <- TBR'''; TBR''' <- TBR''''; + WIM <- WIM'; WIM' <- WIM''; WIM'' <- WIM'''; WIM''' <- WIM''''; + Y <- Y'; Y' <- Y''; Y'' <- Y'''; Y''' <- Y''''; + next; + + addr_space := (if (S = 0) then 8 else 9); + (instruction, MAE) <- memory_read(addr_space, PC); + next; + + if ( (MAE = 1) and (annul = 0) ) then ( + trap <- 1; + instruction_access_exception <- 1 + ) else ( + if (annul = 0) then ( + dispatch_instruction ; { See Section C.6 } + next; + if (FPop1 or FPop2) then ( + complete_fp_execution { See Section C.7 } + ) + next; + if ( (trap = 0) and + not (CALL or RETT or JMPL or Bicc or FBfcc or CBccc or Ticc) ) then ( + PC <- nPC; + nPC <- nPC + 4 + ) + ) else { annul != 0 } ( + annul <- 0; + PC <- nPC; + nPC <- nPC + 4 + ) + ) + ) + */ + if (m_bp_reset_in) + { + m_execute_mode = 0; + m_reset_mode = 1; + return; + } + else if (ET && (m_bp_irl == 15 || m_bp_irl > PIL)) + { + m_trap = 1; + m_interrupt_level = m_bp_irl; + } + + if (m_trap) execute_trap(); + + if (m_execute_mode) + { + // write-state-register delay not yet implemented + + UINT32 addr_space = (IS_USER ? 8 : 9); + UINT32 op = read_sized_word(addr_space, PC, 4); + + if (MAE && !m_annul) + { + m_trap = 1; + m_instruction_access_exception = 1; + } + else + { + if (!m_annul) + { + dispatch_instruction(op); + + if (OP3 == OP3_FPOP1 || OP3 == OP3_FPOP2) + { + complete_fp_execution(op); + } + + if (m_trap == 0 && !(OP == OP_CALL || (OP == OP_TYPE0 && (OP2 == OP2_BICC || OP2 == OP2_FBFCC || OP2 == OP2_CBCCC)) || (OP == OP_ALU && (JMPL || TICC || RETT)))) + { + PC = nPC; + nPC = nPC + 4; + } + } + else + { + + m_annul = 0; + PC = nPC; + nPC = nPC + 4; + } } } } //------------------------------------------------- -// invoke_queued_traps - prioritize and invoke -// traps that have been queued by the previous -// instruction, if any. Returns true if a trap -// was invoked. +// reset_step - step one cycle in reset mode //------------------------------------------------- -bool mb86901_device::invoke_queued_traps() +void mb86901_device::reset_step() { - if (m_queued_priority != SPARC_NO_TRAP) + /* The SPARC Instruction Manual: Version 8, page 156, "Appendix C - ISP Descriptions - C.5. Processor States and Instruction Dispatch" (SPARCv8.pdf, pg. 153) + + while (reset_mode = 1) ( + if (bp_reset_in = 0) then ( + reset_mode <- 0; + execute_mode <- 1; + trap <- 1; + reset_trap <- 1; + ) + ); + */ + + if (!m_bp_reset_in) { - m_et = false; - m_ps = m_s; - m_s = true; - m_cwp = ((m_cwp + WINDOW_COUNT) - 1) % WINDOW_COUNT; - - MAKE_PSR; - update_gpr_pointers(); - - REG(17) = PC; - REG(18) = nPC; - - m_tbr |= m_queued_tt << 4; - - PC = m_tbr; - nPC = m_tbr + 4; - - m_queued_priority = SPARC_NO_TRAP; - m_queued_tt = 0; - return true; + m_reset_mode = 0; + m_execute_mode = 1; + m_trap = 1; + m_reset_trap = 1; } +} - return false; + +//------------------------------------------------- +// error_step - step one cycle in error mode +//------------------------------------------------- + +void mb86901_device::error_step() +{ + /* The SPARC Instruction Manual: Version 8, page 157, "Appendix C - ISP Descriptions - C.5. Processor States and Instruction Dispatch" (SPARCv8.pdf, pg. 154) + + while (error_mode = 1) ( + if (bp_reset_in = 1) then ( + error_mode <- 0; + reset_mode <- 1; + pb_error <- 0 + ) + ); + */ + + if (m_bp_reset_in) + { + m_error_mode = 0; + m_reset_mode = 1; + m_pb_error = 0; + } } @@ -1449,79 +3012,25 @@ void mb86901_device::execute_run() while (m_icount > 0) { - bool trap_was_queued = invoke_queued_traps(); - if (trap_was_queued) - { - m_icount -= 4; - continue; - } - - debugger_instruction_hook(this, m_pc); - if (HOLD_BUS) { m_icount--; continue; } - UINT32 op = GET_OPCODE; - bool update_npc = true; + debugger_instruction_hook(this, m_pc); - switch (OP) + if (m_reset_mode) { - case 0: // Bicc, SETHI, FBfcc - switch (OP2) - { - case 0: // unimp - printf("unimp @ %x\n", PC); - break; - case 2: // branch on integer condition codes - update_npc = execute_bicc(op); - break; - case 4: // sethi - SET_RDREG(IMM22); - break; - case 6: // branch on floating-point condition codes - printf("fbfcc @ %x\n", PC); - break; -#if SPARCV8 - case 7: // branch on coprocessor condition codes, SPARCv8 - break; -#endif - default: - printf("unknown %08x @ %x\n", op, PC); - break; - } - break; - case 1: // call - { - UINT32 pc = PC; - UINT32 callpc = PC + DISP30; - PC = nPC; - nPC = callpc; - - REG(15) = pc; - - update_npc = false; - break; + reset_step(); } - case 2: - update_npc = execute_group2(op); - break; - case 3: // loads, stores - execute_group3(op); - break; - default: - break; - } - - REG(0) = 0; - - bool trap_taken = invoke_queued_traps(); - if (!trap_taken && update_npc && !HOLD_BUS) + else if (m_error_mode) { - PC = nPC; - nPC = PC + 4; + error_step(); + } + else if (m_execute_mode) + { + execute_step(); } if (debug) diff --git a/src/devices/cpu/sparc/sparc.h b/src/devices/cpu/sparc/sparc.h index a5e31751ed2..bb6c33d9933 100644 --- a/src/devices/cpu/sparc/sparc.h +++ b/src/devices/cpu/sparc/sparc.h @@ -16,7 +16,7 @@ #define SPARC_INSTRUCTION_ACCESS_EXCEPTION 1 #define SPARC_ILLEGAL_INSTRUCTION 2 #define SPARC_PRIVILEGED_INSTRUCTION 3 -#define SPARC_FLOATING_POINT_DISABLED 4 +#define SPARC_FP_DISABLED 4 #define SPARC_WINDOW_OVERFLOW 5 #define SPARC_WINDOW_UNDERFLOW 6 #define SPARC_MEM_ADDRESS_NOT_ALIGNED 7 @@ -40,6 +40,7 @@ #define SPARC_INT15 31 #define SPARC_TRAP_INSTRUCTION 128 +#define SPARC_FPU_SEQUENCE_ERROR // TODO: when there are more SPARC CPUs, move setter to a base class #define MCFG_SPARC_ADD_ASI_DESC(desc) \ mb86901_device::add_asi_desc(*device, desc); @@ -85,35 +86,56 @@ public: protected: template void add_asi_desc(const T &desc) { m_dasm.add_asi_desc(desc); } - bool invoke_queued_traps(); - bool check_main_traps(UINT32 op, bool privileged, UINT32 alignment, UINT8 registeralign, bool noimmediate); - void update_gpr_pointers(); - void save_restore_update_cwp(UINT32 op, UINT8 new_cwp); - bool execute_group2(UINT32 op); + + void execute_add(UINT32 op); + void execute_taddcc(UINT32 op); + void execute_sub(UINT32 op); + void execute_tsubcc(UINT32 op); + void execute_logical(UINT32 op); + void execute_shift(UINT32 op); + void execute_mulscc(UINT32 op); + void execute_rdsr(UINT32 op); + void execute_wrsr(UINT32 op); + void execute_rett(UINT32 op); + void execute_saverestore(UINT32 op); + void execute_jmpl(UINT32 op); + void execute_group2(UINT32 op); + + void execute_load(UINT32 op); + void execute_store(UINT32 op); + void execute_ldstub(UINT32 op); void execute_group3(UINT32 op); - bool execute_bicc(UINT32 op); - bool execute_ticc(UINT32 op); + bool evaluate_condition(UINT32 op); + void execute_bicc(UINT32 op); + void execute_ticc(UINT32 op); + void select_trap(); + void execute_trap(); + + void complete_instruction_execution(UINT32 op); + void dispatch_instruction(UINT32 op); + void complete_fp_execution(UINT32 /*op*/); + void execute_step(); + + void reset_step(); + void error_step(); // address spaces const address_space_config m_program_config; // memory access - UINT32 read_byte(UINT8 asi, UINT32 address); - INT32 read_signed_byte(UINT8 asi, UINT32 address); - UINT32 read_half(UINT8 asi, UINT32 address); - INT32 read_signed_half(UINT8 asi, UINT32 address); - UINT32 read_word(UINT8 asi, UINT32 address); - UINT64 read_doubleword(UINT8 asi, UINT32 address); - void write_byte(UINT8 asi, UINT32 address, UINT8 data); - void write_half(UINT8 asi, UINT32 address, UINT16 data); - void write_word(UINT8 asi, UINT32 address, UINT32 data); - void write_doubleword(UINT8 asi, UINT32 address, UINT64 data); + UINT32 read_sized_word(UINT8 asi, UINT32 address, int size); + void write_sized_word(UINT8 asi, UINT32 address, UINT32 data, int size); // general-purpose registers UINT32 m_r[120]; + // FPU registers + UINT32 m_fpr[32]; + UINT32 m_fsr; + UINT8 m_ftt; + // control/status registers UINT32 m_pc; UINT32 m_npc; @@ -122,6 +144,45 @@ protected: UINT32 m_tbr; UINT32 m_y; + bool m_bp_reset_in; + UINT8 m_bp_irl; + bool m_bp_fpu_present; + bool m_bp_cp_present; + bool m_pb_error; + bool m_pb_block_ldst_byte; + bool m_pb_block_ldst_word; + + // trap and error registers + bool m_trap; + UINT8 m_tt; + UINT8 m_ticc_trap_type; + UINT8 m_interrupt_level; + bool m_privileged_instruction; + bool m_illegal_instruction; + bool m_mem_address_not_aligned; + bool m_fp_disabled; + bool m_fp_exception; + bool m_cp_disabled; // SPARCv8 + bool m_cp_exception; // SPARCv8 + bool m_unimplemented_FLUSH; // SPARCv8 + bool m_r_register_access_error; // SPARCv8 + bool m_instruction_access_error; // SPARCv8 + bool m_instruction_access_exception; + bool m_data_access_error; // SPARCv8 + bool m_data_store_error; // SPARCv8 + bool m_data_access_exception; + bool m_division_by_zero; // SPARCv8 + bool m_trap_instruction; + bool m_window_underflow; + bool m_window_overflow; + bool m_tag_overflow; + bool m_reset_mode; + bool m_reset_trap; + bool m_execute_mode; + bool m_error_mode; + UINT8 m_fpu_sequence_err; + UINT8 m_cp_sequence_err; + // fields separated out from PSR (Processor State Register) UINT8 m_impl; // implementation (always 0 in MB86901) UINT8 m_ver; // version (always 0 in MB86901) @@ -134,19 +195,20 @@ protected: bool m_et; // enable traps UINT8 m_cwp; // current window pointer + bool m_alu_op3_assigned[64]; + bool m_ldst_op3_assigned[64]; + // register windowing helpers UINT32* m_regs[32]; // addressing helpers - UINT8 m_insn_asi; - UINT8 m_data_asi; UINT8 m_asi; // other internal states - UINT32 m_trap_priorities[256]; - UINT32 m_queued_tt; - UINT32 m_queued_priority; + bool m_privileged_asr[32]; + bool m_illegal_instruction_asr[32]; bool m_mae; + bool m_annul; bool m_hold_bus; int m_icount; @@ -158,7 +220,7 @@ protected: address_space *m_program; // processor configuration - static const int WINDOW_COUNT; + static const int NWINDOWS; }; // device type definition diff --git a/src/devices/cpu/sparc/sparcdefs.h b/src/devices/cpu/sparc/sparcdefs.h index 2d988c5605c..ec2d52eee51 100644 --- a/src/devices/cpu/sparc/sparcdefs.h +++ b/src/devices/cpu/sparc/sparcdefs.h @@ -12,8 +12,6 @@ #ifndef __MB86901_DEFS_H__ #define __MB86901_DEFS_H__ -#define GET_OPCODE 0; { m_asi = m_insn_asi; op = m_program->read_dword(m_pc); } - #define PSR_CWP_MASK 0x0000001f #define PSR_ET_SHIFT 5 #define PSR_ET_MASK 0x00000020 @@ -43,21 +41,25 @@ #define PSR_ZERO_MASK (PSR_IMPL_MASK | PSR_VER_MASK | PSR_RES_MASK) #define ICC_N_SET (m_psr & PSR_N_MASK) +#define ICC_N (ICC_N_SET ? 1 : 0) #define ICC_N_CLEAR (!ICC_N_SET) #define SET_ICC_N_FLAG do { m_psr |= PSR_N_MASK; } while(0); #define CLEAR_ICC_N_FLAG do { m_psr &= ~PSR_N_MASK; } while(0); #define ICC_Z_SET (m_psr & PSR_Z_MASK) +#define ICC_Z (ICC_Z_SET ? 1 : 0) #define ICC_Z_CLEAR (!ICC_Z_SET) #define SET_ICC_Z_FLAG do { m_psr |= PSR_Z_MASK; } while(0); #define CLEAR_ICC_Z_FLAG do { m_psr &= ~PSR_Z_MASK; } while(0); #define ICC_V_SET (m_psr & PSR_V_MASK) -#define ICC_V_CLEAR (!ICC_B_SET) +#define ICC_V (ICC_V_SET ? 1 : 0) +#define ICC_V_CLEAR (!ICC_V_SET) #define SET_ICC_V_FLAG do { m_psr |= PSR_V_MASK; } while(0); #define CLEAR_ICC_V_FLAG do { m_psr &= ~PSR_V_MASK; } while(0); #define ICC_C_SET (m_psr & PSR_C_MASK) +#define ICC_C (ICC_C_SET ? 1 : 0) #define ICC_C_CLEAR (!ICC_C_SET) #define SET_ICC_C_FLAG do { m_psr |= PSR_C_MASK; } while(0); #define CLEAR_ICC_C_FLAG do { m_psr &= ~PSR_C_MASK; } while(0); @@ -66,18 +68,23 @@ #define TEST_ICC_NZ(x) do { m_psr &= ~PSR_ICC_MASK; m_psr |= (x & 0x80000000) ? PSR_N_MASK : 0; m_psr |= (x == 0) ? PSR_Z_MASK : 0; } while (0); -#define MAKE_PSR do { m_psr = (m_impl << PSR_IMPL_SHIFT) | (m_ver << PSR_VER_SHIFT) | (m_icc << PSR_ICC_SHIFT) | (m_ec ? PSR_EC_MASK : 0) | (m_ef ? PSR_EF_MASK : 0) | (m_pil << PSR_PIL_SHIFT) | (m_s ? PSR_S_MASK : 0) | (m_ps ? PSR_PS_MASK : 0) | (m_et ? PSR_ET_MASK : 0) | m_cwp; m_insn_asi = m_s ? 9 : 8; m_data_asi = m_s ? 11 : 10; } while(0); -#define BREAK_PSR do { m_icc = (m_psr & PSR_ICC_MASK) >> PSR_ICC_SHIFT; m_ec = m_psr & PSR_EC_MASK; m_ef = m_psr & PSR_EF_MASK; m_pil = (m_psr & PSR_PIL_MASK) >> PSR_PIL_SHIFT; m_s = m_psr & PSR_S_MASK; m_ps = m_psr & PSR_PS_MASK; m_et = m_psr & PSR_ET_MASK; m_cwp = m_psr & PSR_CWP_MASK; m_insn_asi = m_s ? 9 : 8; m_data_asi = m_s ? 11 : 10; } while(0); +#define MAKE_PSR do { m_psr = (m_impl << PSR_IMPL_SHIFT) | (m_ver << PSR_VER_SHIFT) | (m_icc << PSR_ICC_SHIFT) | (m_ec ? PSR_EC_MASK : 0) | (m_ef ? PSR_EF_MASK : 0) | (m_pil << PSR_PIL_SHIFT) | (m_s ? PSR_S_MASK : 0) | (m_ps ? PSR_PS_MASK : 0) | (m_et ? PSR_ET_MASK : 0) | m_cwp; } while(0); +#define BREAK_PSR do { m_icc = (m_psr & PSR_ICC_MASK) >> PSR_ICC_SHIFT; m_ec = m_psr & PSR_EC_MASK; m_ef = m_psr & PSR_EF_MASK; m_pil = (m_psr & PSR_PIL_MASK) >> PSR_PIL_SHIFT; m_s = m_psr & PSR_S_MASK; m_ps = m_psr & PSR_PS_MASK; m_et = m_psr & PSR_ET_MASK; m_cwp = m_psr & PSR_CWP_MASK; } while(0); #define MAKE_ICC do { m_icc = (m_psr & PSR_ICC_MASK) >> PSR_ICC_SHIFT; } while(0); +#define CWP m_cwp +#define S m_s +#define PS m_ps + #define IS_SUPERVISOR (m_psr & PSR_S_MASK) #define IS_USER (!IS_SUPERVISOR) #define TRAPS_ENABLED (m_psr & PSR_ET_MASK) #define TRAPS_DISABLED (!TRAPS_ENABLED) -#define FPU_ENABLED (m_psr & PSR_EF_MASK) -#define FPU_DISABLED (!FPU_ENABLED) +#define PSR m_psr +#define WIM m_wim +#define TBR m_tbr #define OP (op >> 30) // gangnam style #define OP2 ((op >> 22) & 7) @@ -121,11 +128,15 @@ #define RS1 ((op >> 14) & 31) #define RS2 (op & 31) -#define REG(x) *m_regs[x] +#define FREG(x) m_fpr[(x)] +#define FDREG m_fpr[RD] +#define FSR m_fsr + +#define REG(x) *m_regs[(x)] #define RDREG *m_regs[RD] #define RS1REG *m_regs[RS1] #define RS2REG *m_regs[RS2] -#define SET_RDREG(x) if(RD) { RDREG = x; } +#define SET_RDREG(x) if(RD) { RDREG = (x); } #define ADDRESS (USEIMM ? (RS1REG + SIMM13) : (RS1REG + RS2REG)) #define PC m_pc @@ -134,8 +145,180 @@ #define Y m_y #define ET m_et +#define EF m_ef +#define EC m_ec #define PIL m_pil #define MAE m_mae #define HOLD_BUS m_hold_bus + +#define BIT31(x) ((x) & 0x80000000) + +#define UPDATE_PC true +#define PC_UPDATED false + +#define OP_TYPE0 0 +#define OP_CALL 1 +#define OP_ALU 2 +#define OP_LDST 3 + +#define OP2_UNIMP 0 +#define OP2_BICC 2 +#define OP2_SETHI 4 +#define OP2_FBFCC 6 +#define OP2_CBCCC 7 + +#define OP3_ADD 0 +#define OP3_AND 1 +#define OP3_OR 2 +#define OP3_XOR 3 +#define OP3_SUB 4 +#define OP3_ANDN 5 +#define OP3_ORN 6 +#define OP3_XNOR 7 +#define OP3_ADDX 8 +#define OP3_UMUL 10 +#define OP3_SMUL 11 +#define OP3_SUBX 12 +#define OP3_UDIV 14 +#define OP3_SDIV 15 +#define OP3_ADDCC 16 +#define OP3_ANDCC 17 +#define OP3_ORCC 18 +#define OP3_XORCC 19 +#define OP3_SUBCC 20 +#define OP3_ANDNCC 21 +#define OP3_ORNCC 22 +#define OP3_XNORCC 23 +#define OP3_ADDXCC 24 +#define OP3_UMULCC 26 +#define OP3_SMULCC 27 +#define OP3_SUBXCC 28 +#define OP3_UDIVCC 30 +#define OP3_SDIVCC 31 +#define OP3_TADDCC 32 +#define OP3_TSUBCC 33 +#define OP3_TADDCCTV 34 +#define OP3_TSUBCCTV 35 +#define OP3_MULSCC 36 +#define OP3_SLL 37 +#define OP3_SRL 38 +#define OP3_SRA 39 +#define OP3_RDASR 40 +#define OP3_RDPSR 41 +#define OP3_RDWIM 42 +#define OP3_RDTBR 43 +#define OP3_WRASR 48 +#define OP3_WRPSR 49 +#define OP3_WRWIM 50 +#define OP3_WRTBR 51 +#define OP3_FPOP1 52 +#define OP3_FPOP2 53 +#define OP3_JMPL 56 +#define OP3_RETT 57 +#define OP3_TICC 58 +#define OP3_SAVE 60 +#define OP3_RESTORE 61 + +#define OP3_LD 0 +#define OP3_LDUB 1 +#define OP3_LDUH 2 +#define OP3_LDD 3 +#define OP3_ST 4 +#define OP3_STB 5 +#define OP3_STH 6 +#define OP3_STD 7 +#define OP3_LDSB 9 +#define OP3_LDSH 10 +#define OP3_LDSTUB 13 +#define OP3_SWAP 15 +#define OP3_LDA 16 +#define OP3_LDUBA 17 +#define OP3_LDUHA 18 +#define OP3_LDDA 19 +#define OP3_STA 20 +#define OP3_STBA 21 +#define OP3_STHA 22 +#define OP3_STDA 23 +#define OP3_LDSBA 25 +#define OP3_LDSHA 26 +#define OP3_LDSTUBA 29 +#define OP3_SWAPA 31 +#define OP3_LDFPR 32 +#define OP3_LDFSR 33 +#define OP3_LDDFPR 35 +#define OP3_STFPR 36 +#define OP3_STFSR 37 +#define OP3_STDFQ 38 +#define OP3_STDFPR 39 +#define OP3_LDCPR 40 +#define OP3_LDCSR 41 +#define OP3_LDDCPR 43 +#define OP3_STCPR 44 +#define OP3_STCSR 45 +#define OP3_STDCQ 46 +#define OP3_STDCPR 47 +#define OP3_CPOP1 54 +#define OP3_CPOP2 55 + +#define COND_BN 0 +#define COND_BE 1 +#define COND_BLE 2 +#define COND_BL 3 +#define COND_BLEU 4 +#define COND_BCS 5 +#define COND_BNEG 6 +#define COND_BVS 7 +#define COND_BA 8 +#define COND_BNE 9 +#define COND_BG 10 +#define COND_BGE 11 +#define COND_BGU 12 +#define COND_BCC 13 +#define COND_BPOS 14 +#define COND_BVC 15 + +#define LDD (OP3 == OP3_LDD) +#define LD (OP3 == OP3_LD) +#define LDSH (OP3 == OP3_LDSH) +#define LDUH (OP3 == OP3_LDUH) +#define LDSB (OP3 == OP3_LDSB) +#define LDUB (OP3 == OP3_LDUB) +#define LDDF (OP3 == OP3_LDDFPR) +#define LDF (OP3 == OP3_LDFPR) +#define LDFSR (OP3 == OP3_LDFSR) +#define LDDC (OP3 == OP3_LDDCPR) +#define LDC (OP3 == OP3_LDCPR) +#define LDCSR (OP3 == OP3_LDCSR) +#define LDDA (OP3 == OP3_LDDA) +#define LDA (OP3 == OP3_LDA) +#define LDSHA (OP3 == OP3_LDSHA) +#define LDUHA (OP3 == OP3_LDUHA) +#define LDSBA (OP3 == OP3_LDSBA) +#define LDUBA (OP3 == OP3_LDUBA) + +#define STD (OP3 == OP3_STD) +#define ST (OP3 == OP3_ST) +#define STH (OP3 == OP3_STH) +#define STB (OP3 == OP3_STB) +#define STDA (OP3 == OP3_STDA) +#define STA (OP3 == OP3_STA) +#define STHA (OP3 == OP3_STHA) +#define STBA (OP3 == OP3_STBA) +#define STF (OP3 == OP3_STFPR) +#define STFSR (OP3 == OP3_STFSR) +#define STDFQ (OP3 == OP3_STDFQ) +#define STDF (OP3 == OP3_STDFPR) +#define STC (OP3 == OP3_STCPR) +#define STCSR (OP3 == OP3_STCSR) +#define STDCQ (OP3 == OP3_STDCQ) +#define STDC (OP3 == OP3_STDCPR) + +#define JMPL (OP3 == OP3_JMPL) +#define TICC (OP3 == OP3_TICC) +#define RETT (OP3 == OP3_RETT) + +#define LDSTUB (OP3 == OP3_LDSTUB) +#define LDSTUBA (OP3 == OP3_LDSTUBA) + #endif // __MB86901_DEFS_H__ \ No newline at end of file