diff options
-rw-r--r-- | scripts/src/cpu.lua | 1 | ||||
-rw-r--r-- | src/devices/cpu/sparc/mb86901.cpp | 244 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparc.h | 9 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparcdefs.h | 61 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparcv8ops.ipp | 293 |
5 files changed, 433 insertions, 175 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index d4538b11abb..ef9263c6485 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -2378,6 +2378,7 @@ end if (CPUS["MB86901"]~=null) then files { MAME_DIR .. "src/devices/cpu/sparc/mb86901.cpp", + MAME_DIR .. "src/devices/cpu/sparc/sparcv8ops.ipp", MAME_DIR .. "src/devices/cpu/sparc/sparcdasm.h", MAME_DIR .. "src/devices/cpu/sparc/sparcdefs.h", MAME_DIR .. "src/devices/cpu/sparc/sparc.h", diff --git a/src/devices/cpu/sparc/mb86901.cpp b/src/devices/cpu/sparc/mb86901.cpp index 61dc5043530..2c32279b267 100644 --- a/src/devices/cpu/sparc/mb86901.cpp +++ b/src/devices/cpu/sparc/mb86901.cpp @@ -22,8 +22,6 @@ #include "sparc.h" #include "sparcdefs.h" -#define SPARCV8 (0) - const device_type MB86901 = &device_creator<mb86901_device>; const int mb86901_device::NWINDOWS = 7; @@ -510,6 +508,10 @@ void mb86901_device::execute_set_input(int inputnum, int state) } +#if SPARCV8 +#include "sparcv8ops.ipp" +#endif + //------------------------------------------------- // execute_add - execute an add-type opcode //------------------------------------------------- @@ -541,16 +543,16 @@ void mb86901_device::execute_add(UINT32 op) UINT32 operand2 = USEIMM ? SIMM13 : RS2REG; UINT32 result = 0; - if (OP3 == 0 || OP3 == 16) + if (ADD || ADDCC) result = RS1REG + operand2; - else if (OP3 == 8 || OP3 == 24) + else if (ADDX || ADDXCC) result = RS1REG + operand2 + ICC_C; if (RD != 0) RDREG = result; - if (OP3 & 16) + if (ADDCC || ADDXCC) { CLEAR_ICC; PSR |= (BIT31(result)) ? PSR_N_MASK : 0; @@ -603,7 +605,7 @@ void mb86901_device::execute_taddcc(UINT32 op) (!BIT31(RS1REG) && !BIT31(operand2) && BIT31(result)) || ((RS1REG & 3) != 0 || (RS1REG & 3) != 0) ? true : false; - if (OP3 == 34 && temp_v) + if (TADDCCTV && temp_v) { m_trap = 1; m_tag_overflow = true; @@ -655,15 +657,15 @@ void mb86901_device::execute_sub(UINT32 op) UINT32 operand2 = USEIMM ? SIMM13 : RS2REG; UINT32 result = 0; - if (OP3 == 4 || OP3 == 20) + if (SUB || SUBCC) result = RS1REG - operand2; - else if (OP3 == 12 || OP3 == 28) + else if (SUBX || SUBXCC) result = RS1REG - operand2 - ICC_C; if (RD != 0) RDREG = result; - if (OP3 & 16) + if (SUBCC || SUBXCC) { CLEAR_ICC; PSR |= (BIT31(result)) ? PSR_N_MASK : 0; @@ -717,7 +719,7 @@ void mb86901_device::execute_tsubcc(UINT32 op) (!BIT31(RS1REG) && BIT31(operand2) && BIT31(result)) || ((RS1REG & 3) != 0 || (RS1REG & 3) != 0) ? true : false; - if (OP3 == 35 && temp_v) + if (TSUBCCTV && temp_v) { m_trap = 1; m_tag_overflow = 1; @@ -771,31 +773,36 @@ void mb86901_device::execute_logical(UINT32 op) UINT32 result = 0; switch (OP3) { - case 1: - case 17: + case OP3_AND: + case OP3_ANDCC: result = RS1REG & operand2; break; - case 5: - case 21: + case OP3_ANDN: + case OP3_ANDNCC: result = RS1REG & ~operand2; break; - case 2: case 18: + case OP3_OR: + case OP3_ORCC: result = RS1REG | operand2; break; - case 6: case 22: + case OP3_ORN: + case OP3_ORNCC: result = RS1REG | ~operand2; break; - case 3: case 19: + case OP3_XOR: + case OP3_XORCC: result = RS1REG ^ operand2; break; - case 7: case 23: + case OP3_XNOR: + case OP3_XNORCC: result = RS1REG ^ ~operand2; break; } - if (RD != 0) RDREG = result; + if (RD != 0) + RDREG = result; - if (OP3 & 16) + if (ANDCC || ANDNCC || ORCC || ORNCC || XORCC || XNORCC) { CLEAR_ICC; PSR |= (BIT31(result)) ? PSR_N_MASK : 0; @@ -824,11 +831,11 @@ void mb86901_device::execute_shift(UINT32 op) */ UINT32 shift_count = USEIMM ? (SIMM13 & 31) : (RS2REG & 31); - if (OP3 == 37 && RD != 0) + if (SLL && RD != 0) RDREG = RS1REG << shift_count; - else if (OP3 == 38 && RD != 0) + else if (SRL && RD != 0) RDREG = UINT32(RS1REG) >> shift_count; - else if (OP3 == 39 && RD != 0) + else if (SRA && RD != 0) RDREG = INT32(RS1REG) >> shift_count; } @@ -907,7 +914,7 @@ void mb86901_device::execute_rdsr(UINT32 op) ); */ - if (((OP3 == 41 || OP3 == 42 || OP3 == 43) || (OP3 == 40 && m_privileged_asr[RS1])) && IS_USER) + if (((WRPSR || WRWIM || WRTBR) || (WRASR && m_privileged_asr[RS1])) && IS_USER) { m_trap = 1; m_privileged_instruction = 1; @@ -919,14 +926,19 @@ void mb86901_device::execute_rdsr(UINT32 op) } else if (RD != 0) { - switch (OP3) + if (RDASR) { - 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; + if (RS1 == 0) + { + RDREG = Y; + } } + else if (RDPSR) + RDREG = PSR; + else if (RDWIM) + RDREG = WIM; + else if (RDTBR) + RDREG = TBR; } } @@ -985,11 +997,11 @@ void mb86901_device::execute_wrsr(UINT32 op) UINT32 result = RS1REG ^ operand2; - if (OP3 == 48 && RD == 0) + if (WRASR && RD == 0) { Y = result; } - else if (OP3 == 48) + else if (WRASR) { if (m_privileged_asr[RD] && IS_USER) { @@ -1006,7 +1018,7 @@ void mb86901_device::execute_wrsr(UINT32 op) // SPARCv8 } } - else if (OP3 == 49) + else if (WRPSR) { if (IS_USER) { @@ -1023,7 +1035,7 @@ void mb86901_device::execute_wrsr(UINT32 op) PSR = result &~ PSR_ZERO_MASK; } } - else if (OP3 == 50) + else if (WRWIM) { if (IS_USER) { @@ -1035,7 +1047,7 @@ void mb86901_device::execute_wrsr(UINT32 op) WIM = result & 0x7f; } } - else if (OP3 == 51) + else if (WRTBR) { if (IS_USER) { @@ -1182,7 +1194,7 @@ void mb86901_device::execute_saverestore(UINT32 op) UINT32 operand2 = USEIMM ? SIMM13 : RS2REG; UINT32 result = 0; - if (OP3 == OP3_SAVE) + if (SAVE) { UINT8 new_cwp = ((CWP + NWINDOWS) - 1) % NWINDOWS; if ((WIM & (1 << new_cwp)) != 0) @@ -1196,7 +1208,7 @@ void mb86901_device::execute_saverestore(UINT32 op) CWP = new_cwp; } } - else if (OP3 == OP3_RESTORE) + else if (RESTORE) { UINT8 new_cwp = (CWP + 1) % NWINDOWS; if ((WIM & (1 << new_cwp)) != 0) @@ -1351,142 +1363,22 @@ void mb86901_device::execute_group2(UINT32 op) break; #if 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 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; - } - 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; - if (quotient > (0xffffffffL + (divisor - 1))) - { - quotient = 0xffffffff; - } - SET_RDREG((UINT32)quotient); - break; - } - 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; - if (quotient > 0) - { - INT32 absdivisor = (divisor < 0) ? -divisor : divisor; - if (quotient > (0x7fffffffL + (absdivisor - 1))) - { - quotient = 0x7fffffff; - } - } - else if (quotient < 0) - { - if (quotient < (INT64)0xffffffff80000000L) - { - quotient = 0x80000000; - } - } - SET_RDREG((UINT32)quotient); - break; - } - 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 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); + case OP3_UMUL: + case OP3_SMUL: + case OP3_UMULCC: + case OP3_SMULCC: + execute_mul(op); break; - } - 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; - bool v = false; - if (quotient > (0xffffffffL + (divisor - 1))) - { - quotient = 0xffffffff; - v = true; - } - - TEST_ICC_NZ((UINT32)quotient); - if (v) - ICC_V_SET; - - SET_RDREG((UINT32)quotient); + case OP3_UDIV: + case OP3_SDIV: + case OP3_UDIVCC: + case OP3_SDIVCC: + execute_div(op); break; - } - 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; - bool v = false; - if (quotient > 0) - { - INT32 absdivisor = (divisor < 0) ? -divisor : divisor; - if (quotient > (0x7fffffffL + (absdivisor - 1))) - { - quotient = 0x7fffffff; - v = true; - } - } - else if (quotient < 0) - { - if (quotient < (INT64)0xffffffff80000000L) - { - quotient = 0x80000000; - v = true; - } - } - - if (v) - ICC_V_SET; - TEST_ICC_NZ((UINT32)quotient); - - SET_RDREG((UINT32)quotient); - break; - } - case OP3_CPOP1: // SPARCv8 - break; - case OP3_CPOP2: // SPARCv8 + case OP3_CPOP1: + case OP3_CPOP2: break; #endif @@ -2333,10 +2225,12 @@ void mb86901_device::execute_group3(UINT32 op) execute_ldstub(op); break; - case OP3_SWAP: // SPARCv8 - break; - case OP3_SWAPA: // SPARCv8 +#if SPARCV8 + case OP3_SWAP: + case OP3_SWAPA: + execute_swap(op); break; +#endif } if (MAE || HOLD_BUS) @@ -2805,12 +2699,12 @@ void mb86901_device::dispatch_instruction(UINT32 op) 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)) + if (((OP == OP_ALU && (FPOP1 || 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)) + if (((OP == OP_ALU && (CPOP1 || CPOP2)) || (OP == OP_TYPE0 && OP2 == OP2_CBCCC)) && (!EC || !m_bp_cp_present)) { m_trap = 1; m_cp_disabled = 1; @@ -2924,7 +2818,7 @@ void mb86901_device::execute_step() { dispatch_instruction(op); - if (OP3 == OP3_FPOP1 || OP3 == OP3_FPOP2) + if (FPOP1 || FPOP2) { complete_fp_execution(op); } diff --git a/src/devices/cpu/sparc/sparc.h b/src/devices/cpu/sparc/sparc.h index bb6c33d9933..b9fd75dbee5 100644 --- a/src/devices/cpu/sparc/sparc.h +++ b/src/devices/cpu/sparc/sparc.h @@ -11,6 +11,8 @@ #include "sparcdasm.h" +#define SPARCV8 (0) + #define SPARC_NO_TRAP 256 #define SPARC_RESET 0 #define SPARC_INSTRUCTION_ACCESS_EXCEPTION 1 @@ -100,11 +102,18 @@ protected: void execute_rett(UINT32 op); void execute_saverestore(UINT32 op); void execute_jmpl(UINT32 op); +#if SPARCV8 + void execute_mul(UINT32 op); + void execute_div(UINT32 op); +#endif void execute_group2(UINT32 op); void execute_load(UINT32 op); void execute_store(UINT32 op); void execute_ldstub(UINT32 op); +#if SPARCV8 + void execute_swap(UINT32 op); +#endif void execute_group3(UINT32 op); bool evaluate_condition(UINT32 op); diff --git a/src/devices/cpu/sparc/sparcdefs.h b/src/devices/cpu/sparc/sparcdefs.h index bf2319d7bb7..2b306323314 100644 --- a/src/devices/cpu/sparc/sparcdefs.h +++ b/src/devices/cpu/sparc/sparcdefs.h @@ -319,7 +319,68 @@ #define TICC (OP3 == OP3_TICC) #define RETT (OP3 == OP3_RETT) +#define SWAP (OP3 == OP3_SWAP) +#define SWAPA (OP3 == OP3_SWAPA) + +#define FPOP1 (OP3 == OP3_FPOP1) +#define FPOP2 (OP3 == OP3_FPOP2) +#define CPOP1 (OP3 == OP3_CPOP1) +#define CPOP2 (OP3 == OP3_CPOP2) + #define LDSTUB (OP3 == OP3_LDSTUB) #define LDSTUBA (OP3 == OP3_LDSTUBA) +#define ADD (OP3 == OP3_ADD) +#define ADDX (OP3 == OP3_ADDX) +#define ADDCC (OP3 == OP3_ADDCC) +#define ADDXCC (OP3 == OP3_ADDXCC) + +#define SUB (OP3 == OP3_SUB) +#define SUBX (OP3 == OP3_SUBX) +#define SUBCC (OP3 == OP3_SUBCC) +#define SUBXCC (OP3 == OP3_SUBXCC) + +#define TADDCCTV (OP3 == OP3_TADDCCTV) +#define TSUBCCTV (OP3 == OP3_TSUBCCTV) + +#define AND (OP3 == OP3_AND) +#define OR (OP3 == OP3_OR) +#define XOR (OP3 == OP3_XOR) +#define ANDN (OP3 == OP3_ANDN) +#define ORN (OP3 == OP3_ORN) +#define XNOR (OP3 == OP3_XNOR) +#define ANDCC (OP3 == OP3_ANDCC) +#define ORCC (OP3 == OP3_ORCC) +#define XORCC (OP3 == OP3_XORCC) +#define ANDNCC (OP3 == OP3_ANDNCC) +#define ORNCC (OP3 == OP3_ORNCC) +#define XNORCC (OP3 == OP3_XNORCC) + +#define SLL (OP3 == OP3_SLL) +#define SRL (OP3 == OP3_SRL) +#define SRA (OP3 == OP3_SRA) + +#define RDASR (OP3 == OP3_RDASR) +#define RDPSR (OP3 == OP3_RDPSR) +#define RDWIM (OP3 == OP3_RDWIM) +#define RDTBR (OP3 == OP3_RDTBR) + +#define WRASR (OP3 == OP3_WRASR) +#define WRPSR (OP3 == OP3_WRPSR) +#define WRWIM (OP3 == OP3_WRWIM) +#define WRTBR (OP3 == OP3_WRTBR) + +#define SAVE (OP3 == OP3_SAVE) +#define RESTORE (OP3 == OP3_RESTORE) + +#define UMUL (OP3 == OP3_UMUL) +#define UMULCC (OP3 == OP3_UMULCC) +#define SMUL (OP3 == OP3_SMUL) +#define SMULCC (OP3 == OP3_SMULCC) + +#define UDIV (OP3 == OP3_UDIV) +#define UDIVCC (OP3 == OP3_UDIVCC) +#define SDIV (OP3 == OP3_SDIV) +#define SDIVCC (OP3 == OP3_SDIVCC) + #endif // __MB86901_DEFS_H__
\ No newline at end of file diff --git a/src/devices/cpu/sparc/sparcv8ops.ipp b/src/devices/cpu/sparc/sparcv8ops.ipp new file mode 100644 index 00000000000..0bb8e9e675e --- /dev/null +++ b/src/devices/cpu/sparc/sparcv8ops.ipp @@ -0,0 +1,293 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +//================================================================ +// +// sparcv8ops.ipp - Emulation for SPARCv8-class instructions +// +//================================================================ + + +//------------------------------------------------- +// execute_swap - execute a swap instruction +//------------------------------------------------- + +void mb86901_device::execute_swap(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 (SWAP) 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 (SWAPA) 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[rs1]; + addr_space <- asi + ) + ); + next; + if (trap = 0) then ( + temp <- r[rd]; + while ( (pb_block_ldst_byte = 1) or (pb_block_ldst_word = 1) ) ( + { wait for lock(s) to be lifted } + { an implementation actually need only block when another SWAP is pending on + the same word in memory as the one addressed by this SWAP, or a LDSTUB is + pending on any byte of the word in memory addressed by this SWAP } + ); + next; + pb_block_ldst_word <- 1; + next; + (word, MAE) <- memory_read(addr_space, address); + next; + if (MAE = 1) then ( + trap <- 1; + data_access_exception = 1 + ) + next; + if (trap = 0) then ( + MAE <- memory_write(addr_space, address, 1111, temp); + next; + pb_block_ldst_word <- 0; + if (MAE = 1) then ( { MAE = 1 only due to a "non-resumable machine-check error" } + trap <- 1; + data_access_exception <- 1 + ) else ( + if (rd != 0) then r[rd] <- word + ) + ); + */ + + UINT32 address = 0; + UINT8 addr_space = 0; + if (SWAP) + { + address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + addr_space = (IS_USER ? 10 : 11); + } + else if (SWAPA) + { + 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 word = 0; + UINT32 temp = 0; + if (!m_trap) + { + temp = RDREG; + 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 SWAP is pending on + // the same word in memory as the one addressed by this SWAP, or a LDSTUB is + // pending on any byte of the word in memory addressed by this SWAP } + } + + m_pb_block_ldst_word = 1; + + word = read_sized_word(addr_space, address, 4); + + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + } + } + if (!m_trap) + { + write_sized_word(addr_space, address, temp, 4); + + m_pb_block_ldst_word = 0; + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + } + else + { + if (RD != 0) + RDREG = word; + } + } +} + + +//------------------------------------------------- +// execute_mul - execute a multiply opcode +//------------------------------------------------- + +void mb86901_device::execute_mul(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 175, "Appendix C - ISP Descriptions - Multiply Instructions" (SPARCv8.pdf, pg. 172) + + operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); + + if (UMUL or UMULScc) then (Y, result) <- multiply_unsigned(r[rs1], operand2) + else if (SMUL or SMULcc) then (Y, result) <- multiply_signed(r[rs1], operand2) + next; + if (rd != 0) then ( + r[rd] <- result; + ) + if (UMULcc or SMULcc) then ( + N <- result<31>; + Z <- if (result = 0) then 1 else 0; + V <- 0 + C <- 0 + ); + */ + + UINT32 operand2 = (USEIMM ? SIMM13 : RS2REG); + + UINT32 result = 0; + if (UMUL || UMULCC) + { + UINT64 dresult = (UINT64)RS1REG * (UINT64)operand2; + Y = (UINT32)(dresult >> 32); + result = (UINT32)dresult; + } + else if (SMUL || SMULCC) + { + INT64 dresult = (INT64)(INT32)RS1REG * (INT64)(INT32)operand2; + Y = (UINT32)(dresult >> 32); + result = (UINT32)dresult; + } + + if (RD != 0) + { + RDREG = result; + } + if (UMULCC || SMULCC) + { + CLEAR_ICC; + PSR |= BIT31(result) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + } +} + + +//------------------------------------------------- +// execute_div - execute a divide opcode +//------------------------------------------------- + +void mb86901_device::execute_div(UINT32 op) +{ + /* The SPARC Instruction Manual: Version 8, page 176, "Appendix C - ISP Descriptions - Multiply Instructions" (SPARCv8.pdf, pg. 173) + + operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); + + next; + if (operand2 = 0) then ( + trap <- 1; + division_by_zero <- 1 + ) else ( + if (UDIV or UDIVcc) then ( + temp_64bit <- divide_unsigned(Y[]r[rs1], operand2); + next; + result <- temp_64bit<31:0>; + temp_V <- if (temp_64bit<63:32> = 0) then 0 else 1; + ) else if (SDIV or SDIVcc) then ( + temp_64bit <- divide_signed(Y[]r[rs1], operand2); + next; + result <- temp_64bit<31:0>; + temp_V <- if (temp_64bit<63:31> = 0) or + (temp_64bit<63:31> = (2^33 - 1)) ) then 0 else 1; + ) ; + next; + + if (temp_V) then ( + { result overflowed 32 bits; return largest appropriate integer } + if (UDIV or UDIVcc) then result <- 2^32 - 1; + else if (SDIV or SDIVcc) then ( + if (temp_64bit > 0) then result <- 2^31 - 1; + else result <- -2^31 + ) + ); + next; + + if (rd != 0) then ( + r[rd] <- result + ) ; + if (UDIVcc or SDIVcc) then ( + N <- result<31>; + Z <- if (result = 0) then 1 else 0; + V <- temp_V; + C <- 0 + ) + ); + */ + + UINT32 operand2 = (USEIMM ? SIMM13 : RS2REG); + + if (operand2 == 0) + { + m_trap = 1; + m_division_by_zero = 1; + } + else + { + UINT32 result = 0; + bool temp_v = false; + INT64 temp_64bit; + if (UDIV || UDIVCC) + { + temp_64bit = INT64(UINT64((UINT64(Y) << 32) | UINT64(RS1REG)) / operand2); + + result = UINT32(temp_64bit); + + temp_v = ((temp_64bit & 0xffffffff00000000) == 0) ? false : true; + } + else if (SDIV || SDIVCC) + { + temp_64bit = INT64(INT64((UINT64(Y) << 32) | UINT64(RS1REG)) / operand2); + + result = UINT32(temp_64bit); + + UINT64 shifted = UINT64(temp_64bit) >> 31; + temp_v = (shifted == 0 || shifted == 0x1ffffffff) ? false : true; + } + + if (temp_v) + { + if (UDIV || UDIVCC) + { + result = 0xffffffff; + } + else if (SDIV || SDIVCC) + { + if (temp_64bit > 0) + result = 0x7fffffff; + else + result = 0x80000000; + } + } + + if (RD != 0) + RDREG = result; + + if (UDIVCC || SDIVCC) + { + CLEAR_ICC; + PSR |= BIT31(result) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + PSR |= temp_v ? PSR_V_MASK : 0; + } + } +} |