PageRenderTime 23ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/machine/mipssim.cc

https://gitlab.com/mstreet_fceia/nachos
C++ | 701 lines | 530 code | 92 blank | 79 comment | 99 complexity | 65af5a22aa358b9f51b7fc128c22c1a4 MD5 | raw file
  1. /// @file
  2. /// @author The Regents of the University of California (1992-1993)
  3. /// @author Mariano Street (2014-2016)
  4. /// @copyright See `copyright.h` for copyright notice and limitation of
  5. /// liability and disclaimer of warranty provisions.
  6. ///
  7. /// @brief Simulate a MIPS R2/3000 processor.
  8. ///
  9. /// This code has been adapted from Ousterhout's MIPSSIM package. Byte
  10. /// ordering is little-endian, so we can be compatible with DEC RISC systems.
  11. ///
  12. /// DO NOT CHANGE -- part of the machine emulation.
  13. #include "mipssim.hh"
  14. #include "Debugger.hh"
  15. #include "interrupt.hh"
  16. #include "machine.hh"
  17. #include "Statistics.hh"
  18. #include "../threads/io.hh"
  19. #include "../threads/system.hh"
  20. #include "../threads/thread/Thread.hh"
  21. /***************************************************************************
  22. * Private functions *
  23. ***************************************************************************/
  24. /// Retrieve the register # referred to in an instruction.
  25. static int TypeToReg(RegType reg,
  26. Instruction *instr)
  27. {
  28. switch (reg) {
  29. case RS:
  30. return instr->rs;
  31. case RT:
  32. return instr->rt;
  33. case RD:
  34. return instr->rd;
  35. case EXTRA:
  36. return instr->extra;
  37. default:
  38. return -1;
  39. }
  40. }
  41. /// Simulate R2000 multiplication.
  42. ///
  43. /// The words at `*hiPtr` and `*loPtr` are overwritten with the double-length
  44. /// result of the multiplication.
  45. static void Mult(int a,
  46. int b,
  47. bool signedArith,
  48. int *hiPtr,
  49. int *loPtr)
  50. {
  51. if (a == 0 || b == 0) {
  52. *hiPtr = *loPtr = 0;
  53. return;
  54. }
  55. // Compute the sign of the result, then make everything positive so
  56. // unsigned computation can be done in the main loop.
  57. bool negative = false;
  58. if (signedArith) {
  59. if (a < 0) {
  60. negative = !negative;
  61. a = -a;
  62. }
  63. if (b < 0) {
  64. negative = !negative;
  65. b = -b;
  66. }
  67. }
  68. // Compute the result in unsigned arithmetic (check `a`'s bits one at a
  69. // time, and add in a shifted value of `b`).
  70. unsigned bLo = b;
  71. unsigned bHi = 0;
  72. unsigned lo = 0;
  73. unsigned hi = 0;
  74. for (unsigned i = 0; i < 32; i++) {
  75. if (a & 1) {
  76. lo += bLo;
  77. if (lo < bLo) // Carry out of the low bits?
  78. hi += 1;
  79. hi += bHi;
  80. if ((a & 0xFFFFFFFE) == 0)
  81. break;
  82. }
  83. bHi <<= 1;
  84. if (bLo & 0x80000000)
  85. bHi |= 1;
  86. bLo <<= 1;
  87. a >>= 1;
  88. }
  89. // If the result is supposed to be negative, compute the two's complement
  90. // of the double-word result.
  91. if (negative) {
  92. hi = ~hi;
  93. lo = ~lo;
  94. lo++;
  95. if (lo == 0)
  96. hi++;
  97. }
  98. *hiPtr = static_cast<int>(hi);
  99. *loPtr = static_cast<int>(lo);
  100. }
  101. /***************************************************************************
  102. * Public functions *
  103. ***************************************************************************/
  104. /// Simulate the execution of a user-level program on Nachos.
  105. ///
  106. /// Called by the kernel when the program starts up; never returns.
  107. ///
  108. /// This routine is re-entrant, in that it can be called multiple times
  109. /// concurrently -- one for each thread executing user code.
  110. void Machine::Run()
  111. {
  112. Instruction *instr (new Instruction); // Storage for decoded
  113. // instruction.
  114. Debug('m', "Starting thread `%s` at time %d.\n",
  115. currentThread->GetName(), stats->totalTicks);
  116. interrupt->SetStatus(USER_MODE);
  117. Debugger debugger;
  118. // WARNING: this debugger is never freed.
  119. for (;;) {
  120. OneInstruction(instr);
  121. interrupt->OneTick();
  122. if (singleStep && runUntilTime <= stats->totalTicks)
  123. singleStep = debugger.Debug(&runUntilTime);
  124. }
  125. }
  126. /// Execute one instruction from a user-level program.
  127. ///
  128. /// If there is any kind of exception or interrupt, we invoke the exception
  129. /// handler, and when it returns, we return to `Run`, which will re-invoke us
  130. /// in a loop. This allows us to re-start the instruction execution from the
  131. /// beginning, in case any of our state has changed. On a syscall, the OS
  132. /// software must increment the PC so execution begins at the instruction
  133. /// immediately after the syscall.
  134. ///
  135. /// This routine is re-entrant, in that it can be called multiple times
  136. /// concurrently -- one for each thread executing user code. We get
  137. /// re-entrancy by never caching any data -- we always re-start the
  138. /// simulation from scratch each time we are called (or after trapping back
  139. /// to the Nachos kernel on an exception or interrupt), and we always store
  140. /// all data back to the machine registers and memory before leaving. This
  141. /// allows the Nachos kernel to control our behavior by controlling the
  142. /// contents of memory, the translation table, and the register set.
  143. void Machine::OneInstruction(Instruction *instr)
  144. {
  145. int raw;
  146. int nextLoadReg (0);
  147. int nextLoadValue (0); // Record delayed load operation, to apply in the
  148. // future.
  149. // Fetch instruction.
  150. if (!machine->ReadMem(registers[PC_REG], 4, &raw))
  151. return; // Exception occurred.
  152. instr->value = raw;
  153. instr->Decode();
  154. if (DebugIsFlagEnabled('m')) {
  155. const OpString *str (&OP_STRINGS[(int) instr->opCode]);
  156. ASSERT(instr->opCode <= MAX_OPCODE);
  157. printf("At PC = 0x%04X: ", registers[PC_REG]);
  158. printf(str->string, TypeToReg(str->args[0], instr),
  159. TypeToReg(str->args[1], instr),
  160. TypeToReg(str->args[2], instr));
  161. printf("\n");
  162. }
  163. // Compute next PC, but don't install in case there's an error or branch.
  164. int pcAfter (registers[NEXT_PC_REG] + 4);
  165. int sum, diff, tmp, value;
  166. unsigned int rs, rt, imm;
  167. // Execute the instruction (cf. Kane's book).
  168. switch (instr->opCode) {
  169. case OP_ADD:
  170. sum = registers[(int) instr->rs] + registers[(int) instr->rt];
  171. if (!((registers[(int) instr->rs] ^ registers[(int) instr->rt]) & SIGN_BIT) &&
  172. (registers[(int) instr->rs] ^ sum) & SIGN_BIT) {
  173. RaiseException(OVERFLOW_EXCEPTION, 0);
  174. return;
  175. }
  176. registers[(int) instr->rd] = sum;
  177. break;
  178. case OP_ADDI:
  179. sum = registers[(int) instr->rs] + instr->extra;
  180. if (!((registers[(int) instr->rs] ^ instr->extra) & SIGN_BIT) &&
  181. (instr->extra ^ sum) & SIGN_BIT) {
  182. RaiseException(OVERFLOW_EXCEPTION, 0);
  183. return;
  184. }
  185. registers[(int) instr->rt] = sum;
  186. break;
  187. case OP_ADDIU:
  188. registers[(int) instr->rt] = registers[(int) instr->rs]
  189. + instr->extra;
  190. break;
  191. case OP_ADDU:
  192. registers[(int) instr->rd] = registers[(int) instr->rs]
  193. + registers[(int) instr->rt];
  194. break;
  195. case OP_AND:
  196. registers[(int) instr->rd] = registers[(int) instr->rs]
  197. & registers[(int) instr->rt];
  198. break;
  199. case OP_ANDI:
  200. registers[(int) instr->rt] = registers[(int) instr->rs]
  201. & (instr->extra & 0xFFFF);
  202. break;
  203. case OP_BEQ:
  204. if (registers[(int) instr->rs] == registers[(int) instr->rt])
  205. pcAfter = registers[NEXT_PC_REG] + IndexToAddr(instr->extra);
  206. break;
  207. case OP_BGEZAL:
  208. registers[R31] = registers[NEXT_PC_REG] + 4;
  209. case OP_BGEZ:
  210. if (!(registers[(int) instr->rs] & SIGN_BIT))
  211. pcAfter = registers[NEXT_PC_REG] + IndexToAddr(instr->extra);
  212. break;
  213. case OP_BGTZ:
  214. if (registers[(int) instr->rs] > 0)
  215. pcAfter = registers[NEXT_PC_REG] + IndexToAddr(instr->extra);
  216. break;
  217. case OP_BLEZ:
  218. if (registers[(int) instr->rs] <= 0)
  219. pcAfter = registers[NEXT_PC_REG] + IndexToAddr(instr->extra);
  220. break;
  221. case OP_BLTZAL:
  222. registers[R31] = registers[NEXT_PC_REG] + 4;
  223. case OP_BLTZ:
  224. if (registers[(int) instr->rs] & SIGN_BIT)
  225. pcAfter = registers[NEXT_PC_REG] + IndexToAddr(instr->extra);
  226. break;
  227. case OP_BNE:
  228. if (registers[(int) instr->rs] != registers[(int) instr->rt])
  229. pcAfter = registers[NEXT_PC_REG] + IndexToAddr(instr->extra);
  230. break;
  231. case OP_DIV:
  232. if (registers[(int) instr->rt] == 0) {
  233. registers[LO_REG] = 0;
  234. registers[HI_REG] = 0;
  235. } else {
  236. registers[LO_REG] = registers[(int) instr->rs]
  237. / registers[(int) instr->rt];
  238. registers[HI_REG] = registers[(int) instr->rs]
  239. % registers[(int) instr->rt];
  240. }
  241. break;
  242. case OP_DIVU:
  243. rs = (unsigned int) registers[(int) instr->rs];
  244. rt = (unsigned int) registers[(int) instr->rt];
  245. if (rt == 0) {
  246. registers[LO_REG] = 0;
  247. registers[HI_REG] = 0;
  248. } else {
  249. tmp = rs / rt;
  250. registers[LO_REG] = (int) tmp;
  251. tmp = rs % rt;
  252. registers[HI_REG] = (int) tmp;
  253. }
  254. break;
  255. case OP_JAL:
  256. registers[R31] = registers[NEXT_PC_REG] + 4;
  257. case OP_J:
  258. pcAfter = (pcAfter & 0xF0000000) | IndexToAddr(instr->extra);
  259. break;
  260. case OP_JALR:
  261. registers[(int) instr->rd] = registers[NEXT_PC_REG] + 4;
  262. case OP_JR:
  263. pcAfter = registers[(int) instr->rs];
  264. break;
  265. case OP_LB:
  266. case OP_LBU:
  267. tmp = registers[(int) instr->rs] + instr->extra;
  268. if (!machine->ReadMem(tmp, 1, &value))
  269. return;
  270. if (value & 0x80 && instr->opCode == OP_LB)
  271. value |= 0xffffff00;
  272. else
  273. value &= 0xff;
  274. nextLoadReg = instr->rt;
  275. nextLoadValue = value;
  276. break;
  277. case OP_LH:
  278. case OP_LHU:
  279. tmp = registers[(int)instr->rs] + instr->extra;
  280. if (tmp & 0x1) {
  281. RaiseException(ADDRESS_ERROR_EXCEPTION, tmp);
  282. return;
  283. }
  284. if (!machine->ReadMem(tmp, 2, &value))
  285. return;
  286. if (value & 0x8000 && instr->opCode == OP_LH)
  287. value |= 0xffff0000;
  288. else
  289. value &= 0xffff;
  290. nextLoadReg = instr->rt;
  291. nextLoadValue = value;
  292. break;
  293. case OP_LUI:
  294. Debug('m', "Executing: LUI r%d,%d\n", instr->rt, instr->extra);
  295. registers[(int) instr->rt] = instr->extra << 16;
  296. break;
  297. case OP_LW:
  298. tmp = registers[(int) instr->rs] + instr->extra;
  299. if (tmp & 0x3) {
  300. RaiseException(ADDRESS_ERROR_EXCEPTION, tmp);
  301. return;
  302. }
  303. if (!machine->ReadMem(tmp, 4, &value))
  304. return;
  305. nextLoadReg = instr->rt;
  306. nextLoadValue = value;
  307. break;
  308. case OP_LWL:
  309. tmp = registers[(int) instr->rs] + instr->extra;
  310. // `ReadMem` assumes all 4 byte requests are aligned on an even word
  311. // boundary. Also, the little endian/big endian swap code would fail
  312. // (I think) if the other cases are ever exercised.
  313. ASSERT((tmp & 0x3) == 0);
  314. if (!machine->ReadMem(tmp, 4, &value))
  315. return;
  316. if (registers[LOAD_REG] == instr->rt)
  317. nextLoadValue = registers[LOAD_VALUE_REG];
  318. else
  319. nextLoadValue = registers[(int) instr->rt];
  320. switch (tmp & 0x3) {
  321. case 0:
  322. nextLoadValue = value;
  323. break;
  324. case 1:
  325. nextLoadValue = nextLoadValue & 0xFF | value << 8;
  326. break;
  327. case 2:
  328. nextLoadValue = nextLoadValue & 0xFFFF | value << 16;
  329. break;
  330. case 3:
  331. nextLoadValue = nextLoadValue & 0xFFFFFF | value << 24;
  332. break;
  333. }
  334. nextLoadReg = instr->rt;
  335. break;
  336. case OP_LWR:
  337. tmp = registers[(int) instr->rs] + instr->extra;
  338. // `ReadMem` assumes all 4 byte requests are aligned on an even word
  339. // boundary. Also, the little endian/big endian swap code would fail
  340. // (I think) if the other cases are ever exercised.
  341. ASSERT((tmp & 0x3) == 0);
  342. if (!machine->ReadMem(tmp, 4, &value))
  343. return;
  344. if (registers[LOAD_REG] == instr->rt)
  345. nextLoadValue = registers[LOAD_VALUE_REG];
  346. else
  347. nextLoadValue = registers[(int) instr->rt];
  348. switch (tmp & 0x3) {
  349. case 0:
  350. nextLoadValue = nextLoadValue & 0xFFFFFF00
  351. | value >> 24 & 0xFF;
  352. break;
  353. case 1:
  354. nextLoadValue = nextLoadValue & 0xFFFF0000
  355. | value >> 16 & 0xFFFF;
  356. break;
  357. case 2:
  358. nextLoadValue = nextLoadValue & 0xFF000000
  359. | value >> 8 & 0xFFFFFF;
  360. break;
  361. case 3:
  362. nextLoadValue = value;
  363. break;
  364. }
  365. nextLoadReg = instr->rt;
  366. break;
  367. case OP_MFHI:
  368. registers[(int) instr->rd] = registers[HI_REG];
  369. break;
  370. case OP_MFLO:
  371. registers[(int) instr->rd] = registers[LO_REG];
  372. break;
  373. case OP_MTHI:
  374. registers[HI_REG] = registers[(int) instr->rs];
  375. break;
  376. case OP_MTLO:
  377. registers[LO_REG] = registers[(int) instr->rs];
  378. break;
  379. case OP_MULT:
  380. Mult(registers[(int) instr->rs], registers[(int) instr->rt], true,
  381. &registers[HI_REG], &registers[LO_REG]);
  382. break;
  383. case OP_MULTU:
  384. Mult(registers[(int) instr->rs], registers[(int) instr->rt], false,
  385. &registers[HI_REG], &registers[LO_REG]);
  386. break;
  387. case OP_NOR:
  388. registers[(int) instr->rd] = ~(registers[(int) instr->rs]
  389. | registers[(int) instr->rt]);
  390. break;
  391. case OP_OR:
  392. registers[(int) instr->rd] = registers[(int) instr->rs]
  393. | registers[(int) instr->rs];
  394. break;
  395. case OP_ORI:
  396. registers[(int) instr->rt] = registers[(int) instr->rs]
  397. | instr->extra & 0xFFFF;
  398. break;
  399. case OP_SB:
  400. if (!machine->WriteMem((unsigned)
  401. (registers[(int) instr->rs] + instr->extra),
  402. 1, registers[(int) instr->rt]))
  403. return;
  404. break;
  405. case OP_SH:
  406. if (!machine->WriteMem((unsigned)
  407. (registers[(int) instr->rs] + instr->extra),
  408. 2, registers[(int) instr->rt]))
  409. return;
  410. break;
  411. case OP_SLL:
  412. registers[(int) instr->rd] = registers[(int) instr->rt]
  413. << instr->extra;
  414. break;
  415. case OP_SLLV:
  416. registers[(int) instr->rd] = registers[(int) instr->rt]
  417. << (registers[(int) instr->rs] & 0x1F);
  418. break;
  419. case OP_SLT:
  420. if (registers[(int) instr->rs] < registers[(int) instr->rt])
  421. registers[(int) instr->rd] = 1;
  422. else
  423. registers[(int) instr->rd] = 0;
  424. break;
  425. case OP_SLTI:
  426. if (registers[(int) instr->rs] < instr->extra)
  427. registers[(int) instr->rt] = 1;
  428. else
  429. registers[(int) instr->rt] = 0;
  430. break;
  431. case OP_SLTIU:
  432. rs = registers[(int) instr->rs];
  433. imm = instr->extra;
  434. if (rs < imm)
  435. registers[(int) instr->rt] = 1;
  436. else
  437. registers[(int) instr->rt] = 0;
  438. break;
  439. case OP_SLTU:
  440. rs = registers[(int) instr->rs];
  441. rt = registers[(int) instr->rt];
  442. if (rs < rt)
  443. registers[(int) instr->rd] = 1;
  444. else
  445. registers[(int) instr->rd] = 0;
  446. break;
  447. case OP_SRA:
  448. registers[(int) instr->rd] = registers[(int) instr->rt]
  449. >> instr->extra;
  450. break;
  451. case OP_SRAV:
  452. registers[(int) instr->rd] = registers[(int) instr->rt]
  453. >> (registers[(int) instr->rs] & 0x1f);
  454. break;
  455. case OP_SRL:
  456. tmp = registers[(int) instr->rt];
  457. tmp >>= instr->extra;
  458. registers[(int) instr->rd] = tmp;
  459. break;
  460. case OP_SRLV:
  461. tmp = registers[(int) instr->rt];
  462. tmp >>= registers[(int) instr->rs] & 0x1f;
  463. registers[(int) instr->rd] = tmp;
  464. break;
  465. case OP_SUB:
  466. diff = registers[(int) instr->rs] - registers[(int) instr->rt];
  467. if ((registers[(int) instr->rs] ^ registers[(int) instr->rt]) & SIGN_BIT
  468. && (registers[(int) instr->rs] ^ diff) & SIGN_BIT) {
  469. RaiseException(OVERFLOW_EXCEPTION, 0);
  470. return;
  471. }
  472. registers[(int) instr->rd] = diff;
  473. break;
  474. case OP_SUBU:
  475. registers[(int) instr->rd] = registers[(int) instr->rs]
  476. - registers[(int) instr->rt];
  477. break;
  478. case OP_SW:
  479. if (!machine->WriteMem((unsigned)
  480. (registers[(int) instr->rs] + instr->extra),
  481. 4, registers[(int) instr->rt]))
  482. return;
  483. break;
  484. case OP_SWL:
  485. tmp = registers[(int) instr->rs] + instr->extra;
  486. // The little endian/big endian swap code would fail (I think) if the
  487. // other cases are ever exercised.
  488. ASSERT((tmp & 0x3) == 0);
  489. if (!machine->ReadMem(tmp & ~0x3, 4, &value))
  490. return;
  491. switch (tmp & 0x3) {
  492. case 0:
  493. value = registers[(int) instr->rt];
  494. break;
  495. case 1:
  496. value = value & 0xFF000000
  497. | registers[(int) instr->rt] >> 8 & 0xFFFFFF;
  498. break;
  499. case 2:
  500. value = value & 0xFFFF0000
  501. | registers[(int) instr->rt] >> 16 & 0xFFFF;
  502. break;
  503. case 3:
  504. value = value & 0xFFFFFF00
  505. | registers[(int) instr->rt] >> 24 & 0xFF;
  506. break;
  507. }
  508. if (!machine->WriteMem(tmp & ~0x3, 4, value))
  509. return;
  510. break;
  511. case OP_SWR:
  512. tmp = registers[(int) instr->rs] + instr->extra;
  513. // The little endian/big endian swap code would fail (I think) if the
  514. // other cases are ever exercised.
  515. ASSERT((tmp & 0x3) == 0);
  516. if (!machine->ReadMem(tmp & ~0x3, 4, &value))
  517. return;
  518. switch (tmp & 0x3) {
  519. case 0:
  520. value = value & 0xFFFFFF | registers[(int) instr->rt] << 24;
  521. break;
  522. case 1:
  523. value = value & 0xFFFF | registers[(int) instr->rt] << 16;
  524. break;
  525. case 2:
  526. value = value & 0xFF | registers[(int) instr->rt] << 8;
  527. break;
  528. case 3:
  529. value = registers[(int)instr->rt];
  530. break;
  531. }
  532. if (!machine->WriteMem(tmp & ~0x3, 4, value))
  533. return;
  534. break;
  535. case OP_SYSCALL:
  536. RaiseException(SYSCALL_EXCEPTION, 0);
  537. return;
  538. case OP_XOR:
  539. registers[(int) instr->rd] = registers[(int) instr->rs]
  540. ^ registers[(int) instr->rt];
  541. break;
  542. case OP_XORI:
  543. registers[(int) instr->rt] = registers[(int) instr->rs]
  544. ^ instr->extra & 0xffff;
  545. break;
  546. case OP_RES:
  547. case OP_UNIMP:
  548. RaiseException(ILLEGAL_INSTR_EXCEPTION, 0);
  549. return;
  550. default:
  551. ASSERT(false);
  552. }
  553. // Now we have successfully executed the instruction.
  554. // Do any delayed load operation.
  555. DelayedLoad(nextLoadReg, nextLoadValue);
  556. // Advance program counters.
  557. registers[PREV_PC_REG] = registers[PC_REG]; // For debugging, in case we
  558. // are jumping into
  559. // lala-land.
  560. registers[PC_REG] = registers[NEXT_PC_REG];
  561. registers[NEXT_PC_REG] = pcAfter;
  562. }
  563. /// Simulate effects of a delayed load.
  564. ///
  565. /// NOTE: `RaiseException`/`CheckInterrupts` must also call `DelayedLoad`,
  566. /// since any delayed load must get applied before we trap to the kernel.
  567. void Machine::DelayedLoad(int nextReg,
  568. int nextValue)
  569. {
  570. registers[registers[LOAD_REG]] = registers[LOAD_VALUE_REG];
  571. registers[LOAD_REG] = nextReg;
  572. registers[LOAD_VALUE_REG] = nextValue;
  573. registers[0] = 0; // And always make sure `r0` stays
  574. // zero.
  575. }
  576. /// Decode a MIPS instruction.
  577. void Instruction::Decode()
  578. {
  579. const OpInfo *opPtr;
  580. rs = value >> 21 & 0x1F;
  581. rt = value >> 16 & 0x1F;
  582. rd = value >> 11 & 0x1F;
  583. opPtr = &OP_TABLE[value >> 26 & 0x3F];
  584. opCode = opPtr->opCode;
  585. if (opPtr->format == IFMT) {
  586. extra = value & 0xFFFF;
  587. if (extra & 0x8000) {
  588. extra |= 0xFFFF0000;
  589. }
  590. } else if (opPtr->format == RFMT)
  591. extra = (value >> 6) & 0x1F;
  592. else
  593. extra = value & 0x3FFFFFF;
  594. if (opCode == SPECIAL)
  595. opCode = specialTable[value & 0x3F];
  596. else if (opCode == BCOND) {
  597. int i = value & 0x1F0000;
  598. if (i == 0)
  599. opCode = OP_BLTZ;
  600. else if (i == 0x10000)
  601. opCode = OP_BGEZ;
  602. else if (i == 0x100000)
  603. opCode = OP_BLTZAL;
  604. else if (i == 0x110000)
  605. opCode = OP_BGEZAL;
  606. else
  607. opCode = OP_UNIMP;
  608. }
  609. }