Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 7 | 7 |
| 8 // Only build the simulator if not compiling for real MIPS hardware. | 8 // Only build the simulator if not compiling for real MIPS hardware. |
| 9 #if !defined(HOST_ARCH_MIPS) | 9 #if !defined(HOST_ARCH_MIPS) |
| 10 | 10 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 95 } | 95 } |
| 96 | 96 |
| 97 | 97 |
| 98 void Simulator::Format(Instr* instr, const char* format) { | 98 void Simulator::Format(Instr* instr, const char* format) { |
| 99 OS::PrintErr("Simulator - unknown instruction: %s\n", format); | 99 OS::PrintErr("Simulator - unknown instruction: %s\n", format); |
| 100 UNIMPLEMENTED(); | 100 UNIMPLEMENTED(); |
| 101 } | 101 } |
| 102 | 102 |
| 103 void Simulator::DecodeSpecial(Instr* instr) { | 103 void Simulator::DecodeSpecial(Instr* instr) { |
| 104 switch (instr->FunctionField()) { | 104 switch (instr->FunctionField()) { |
| 105 case ADDU: { | |
| 106 ASSERT(instr->SaField() == 0); | |
| 107 // Format(instr, "addu 'rd, 'rs, 'rt"); | |
| 108 int32_t rs_val = get_register(instr->RsField()); | |
| 109 int32_t rt_val = get_register(instr->RtField()); | |
| 110 set_register(instr->RdField(), rs_val + rt_val); | |
| 111 break; | |
| 112 } | |
| 113 case AND: { | |
| 114 ASSERT(instr->SaField() == 0); | |
| 115 // Format(instr, "and 'rd, 'rs, 'rt"); | |
| 116 int32_t rs_val = get_register(instr->RsField()); | |
| 117 int32_t rt_val = get_register(instr->RtField()); | |
| 118 set_register(instr->RdField(), rs_val & rt_val); | |
| 119 break; | |
| 120 } | |
| 121 case DIV: { | |
| 122 ASSERT(instr->RdField() == 0); | |
| 123 ASSERT(instr->SaField() == 0); | |
| 124 // Format(instr, "div 'rs, 'rt"); | |
| 125 int32_t rs_val = get_register(instr->RsField()); | |
| 126 int32_t rt_val = get_register(instr->RtField()); | |
| 127 if (rt_val == 0) { | |
| 128 // Results are unpredictable | |
| 129 set_hi_register(0); | |
| 130 set_lo_register(0); | |
| 131 return; | |
|
regis
2013/03/08 21:09:03
Why return instead of break?
Maybe we should drop
| |
| 132 } | |
| 133 | |
| 134 if ((rs_val == static_cast<int32_t>(0x80000000)) && | |
| 135 (rt_val == static_cast<int32_t>(0xffffffff))) { | |
| 136 set_lo_register(0x80000000); | |
| 137 set_hi_register(0); | |
| 138 } else { | |
| 139 set_lo_register(rs_val / rt_val); | |
| 140 set_hi_register(rs_val % rt_val); | |
| 141 } | |
| 142 break; | |
| 143 } | |
| 144 case DIVU: { | |
| 145 ASSERT(instr->RdField() == 0); | |
| 146 ASSERT(instr->SaField() == 0); | |
| 147 // Format(instr, "divu 'rs, 'rt"); | |
| 148 uint32_t rs_val = get_register(instr->RsField()); | |
| 149 uint32_t rt_val = get_register(instr->RtField()); | |
| 150 if (rt_val == 0) { | |
| 151 // Results are unpredictable | |
| 152 set_hi_register(0); | |
| 153 set_lo_register(0); | |
| 154 return; | |
|
regis
2013/03/08 21:09:03
ditto
| |
| 155 } | |
| 156 | |
| 157 set_lo_register(rs_val / rt_val); | |
| 158 set_hi_register(rs_val % rt_val); | |
| 159 break; | |
| 160 } | |
| 161 case MFHI: { | |
| 162 ASSERT(instr->RsField() == 0); | |
| 163 ASSERT(instr->RtField() == 0); | |
| 164 ASSERT(instr->SaField() == 0); | |
| 165 // Format(instr, "mfhi 'rd"); | |
| 166 set_register(instr->RdField(), get_hi_register()); | |
| 167 break; | |
| 168 } | |
| 169 case MFLO: { | |
| 170 ASSERT(instr->RsField() == 0); | |
| 171 ASSERT(instr->RtField() == 0); | |
| 172 ASSERT(instr->SaField() == 0); | |
| 173 // Format(instr, "mflo 'rd"); | |
| 174 set_register(instr->RdField(), get_lo_register()); | |
| 175 break; | |
| 176 } | |
| 105 case SLL: { | 177 case SLL: { |
| 178 ASSERT(instr->RsField() == 0); | |
| 106 if ((instr->RdField() == R0) && | 179 if ((instr->RdField() == R0) && |
| 107 (instr->RtField() == R0) && | 180 (instr->RtField() == R0) && |
| 108 (instr->SaField() == 0)) { | 181 (instr->SaField() == 0)) { |
| 109 // Format(instr, "nop"); | 182 // Format(instr, "nop"); |
| 110 // Nothing to be done for NOP. | 183 // Nothing to be done for NOP. |
| 111 } else { | 184 } else { |
| 112 Format(instr, "sll 'rd, 'rt, 'sa"); | 185 int32_t rt_val = get_register(instr->RtField()); |
| 186 int sa = instr->SaField(); | |
| 187 set_register(instr->RdField(), rt_val << sa); | |
| 113 } | 188 } |
| 114 break; | 189 break; |
| 115 } | 190 } |
| 116 case JR: { | 191 case JR: { |
| 117 ASSERT(instr->RtField() == R0); | 192 ASSERT(instr->RtField() == R0); |
| 118 ASSERT(instr->RdField() == R0); | 193 ASSERT(instr->RdField() == R0); |
| 119 ASSERT(!delay_slot_); | 194 ASSERT(!delay_slot_); |
| 120 // Format(instr, "jr'hint 'rs"); | 195 // Format(instr, "jr'hint 'rs"); |
| 121 uword next_pc = get_register(instr->RsField()); | 196 uword next_pc = get_register(instr->RsField()); |
| 122 ExecuteDelaySlot(); | 197 ExecuteDelaySlot(); |
| 123 pc_ = next_pc - Instr::kInstrSize; // Account for regular PC increment. | 198 pc_ = next_pc - Instr::kInstrSize; // Account for regular PC increment. |
| 124 break; | 199 break; |
| 125 } | 200 } |
| 126 default: { | 201 default: { |
| 127 OS::PrintErr("DecodeSpecial: 0x%x\n", instr->InstructionBits()); | 202 OS::PrintErr("DecodeSpecial: 0x%x\n", instr->InstructionBits()); |
| 128 UNREACHABLE(); | 203 UNREACHABLE(); |
| 129 break; | 204 break; |
| 130 } | 205 } |
| 131 } | 206 } |
| 132 } | 207 } |
| 133 | 208 |
| 134 | 209 |
| 210 void Simulator::DecodeSpecial2(Instr* instr) { | |
| 211 switch (instr->FunctionField()) { | |
| 212 case CLO: { | |
| 213 ASSERT(instr->SaField() == 0); | |
| 214 ASSERT(instr->RtField() == instr->RdField()); | |
| 215 // Format(instr, "clo 'rd, 'rs"); | |
| 216 int32_t rs_val = get_register(instr->RsField()); | |
| 217 int32_t bitcount = 0; | |
| 218 while (rs_val < 0) { | |
| 219 bitcount++; | |
| 220 rs_val <<= 1; | |
| 221 } | |
| 222 set_register(instr->RdField(), bitcount); | |
| 223 break; | |
| 224 } | |
| 225 case CLZ: { | |
| 226 ASSERT(instr->SaField() == 0); | |
| 227 ASSERT(instr->RtField() == instr->RdField()); | |
| 228 // Format(instr, "clz 'rd, 'rs"); | |
| 229 int32_t rs_val = get_register(instr->RsField()); | |
| 230 int32_t bitcount = 0; | |
| 231 if (rs_val != 0) { | |
| 232 while (rs_val > 0) { | |
| 233 bitcount++; | |
| 234 rs_val <<= 1; | |
| 235 } | |
| 236 } else { | |
| 237 bitcount = 32; | |
| 238 } | |
| 239 set_register(instr->RdField(), bitcount); | |
| 240 break; | |
| 241 } | |
| 242 default: { | |
| 243 OS::PrintErr("DecodeSpecial2: 0x%x\n", instr->InstructionBits()); | |
| 244 UNREACHABLE(); | |
| 245 break; | |
| 246 } | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 | |
| 135 void Simulator::InstructionDecode(Instr* instr) { | 251 void Simulator::InstructionDecode(Instr* instr) { |
| 136 switch (instr->OpcodeField()) { | 252 switch (instr->OpcodeField()) { |
| 137 case SPECIAL: { | 253 case SPECIAL: { |
| 138 DecodeSpecial(instr); | 254 DecodeSpecial(instr); |
| 139 break; | 255 break; |
| 140 } | 256 } |
| 257 case SPECIAL2: { | |
| 258 DecodeSpecial2(instr); | |
| 259 break; | |
| 260 } | |
| 261 case ADDI: { | |
| 262 // Format(instr, "addi 'rt, 'rs, 'immu"); | |
| 263 int32_t rs_val = get_register(instr->RsField()); | |
| 264 int32_t imm_val = instr->SImmField(); | |
| 265 int32_t res = rs_val + imm_val; | |
| 266 // Rt is not set on overflow | |
|
regis
2013/03/08 21:09:03
period
| |
| 267 if (!(((res < 0) && (rs_val > 0) && (imm_val > 0)) || | |
| 268 ((res > 0) && (rs_val < 0) && (imm_val < 0)))) { | |
|
regis
2013/03/08 21:09:03
Is this correct? Can't you produce an overflow wit
| |
| 269 set_register(instr->RtField(), res); | |
| 270 } | |
| 271 break; | |
| 272 } | |
| 273 case ADDIU: { | |
| 274 // Format(instr, "addiu 'rt, 'rs, 'immu"); | |
| 275 int32_t rs_val = get_register(instr->RsField()); | |
| 276 int32_t imm_val = instr->SImmField(); | |
| 277 int32_t res = rs_val + imm_val; | |
| 278 // Rt is set even on overflow | |
|
regis
2013/03/08 21:09:03
period
| |
| 279 set_register(instr->RtField(), res); | |
| 280 break; | |
| 281 } | |
| 282 case ANDI: { | |
| 283 // Format(instr, "andi 'rt, 'rs, 'immu"); | |
| 284 int32_t rs_val = get_register(instr->RsField()); | |
| 285 set_register(instr->RtField(), rs_val & instr->UImmField()); | |
| 286 break; | |
| 287 } | |
| 141 case ORI: { | 288 case ORI: { |
| 142 // Format(instr, "ori 'rt, 'rs, 'immu"); | 289 // Format(instr, "ori 'rt, 'rs, 'immu"); |
| 143 int32_t rs_val = get_register(instr->RsField()); | 290 int32_t rs_val = get_register(instr->RsField()); |
| 144 set_register(instr->RtField(), rs_val | instr->UImmField()); | 291 set_register(instr->RtField(), rs_val | instr->UImmField()); |
| 145 break; | 292 break; |
| 146 } | 293 } |
| 147 default: { | 294 default: { |
| 148 OS::PrintErr("Undecoded instruction: 0x%x\n", instr->InstructionBits()); | 295 OS::PrintErr("Undecoded instruction: 0x%x\n", instr->InstructionBits()); |
| 149 UNREACHABLE(); | 296 UNREACHABLE(); |
| 150 break; | 297 break; |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 271 // Restore the SP register and return R1:R0. | 418 // Restore the SP register and return R1:R0. |
| 272 set_register(SP, sp_before_call); | 419 set_register(SP, sp_before_call); |
| 273 return Utils::LowHighTo64Bits(get_register(V0), get_register(V1)); | 420 return Utils::LowHighTo64Bits(get_register(V0), get_register(V1)); |
| 274 } | 421 } |
| 275 | 422 |
| 276 } // namespace dart | 423 } // namespace dart |
| 277 | 424 |
| 278 #endif // !defined(HOST_ARCH_MIPS) | 425 #endif // !defined(HOST_ARCH_MIPS) |
| 279 | 426 |
| 280 #endif // defined TARGET_ARCH_MIPS | 427 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |