From 5656f36cbe5083dda099c48827925cae874472d8 Mon Sep 17 00:00:00 2001
From: Recolic Keghart <root@recolic.net>
Date: Wed, 25 Dec 2019 02:28:37 +0800
Subject: [PATCH] >  Manual commit:  [DO NOT BUILD] debugging U201614531
 recolic Linux RECOLICPC 5.4.2-arch1-1 #1 SMP PREEMPT Thu, 05 Dec 2019
 12:29:40 +0000 x86_64 GNU/Linux  02:28:37 up 2 days,  7:36,  1 user,  load
 average: 1.26, 1.14, 0.98 891cd7f6081506f251fda067a38894cb71507ef

---
 nemu/include/common.h         |  2 ++
 nemu/include/cpu/decode.h     |  4 ++++
 nemu/include/cpu/rtl.h        | 12 ++++++++++--
 nemu/include/macro.h          |  6 ++++++
 nemu/src/cpu/decode/decode.cc |  2 +-
 nemu/src/cpu/exec/all-instr.h |  7 +++++++
 nemu/src/cpu/exec/control.cc  | 32 ++++++++++++++++++++++++++++++--
 nemu/src/cpu/exec/data-mov.cc | 20 ++++++++++++++++++--
 nemu/src/cpu/exec/exec.cc     |  6 +++---
 nemu/src/memory/memory.cc     |  2 ++
 10 files changed, 83 insertions(+), 10 deletions(-)

diff --git a/nemu/include/common.h b/nemu/include/common.h
index b6e40c4..d765817 100644
--- a/nemu/include/common.h
+++ b/nemu/include/common.h
@@ -37,4 +37,6 @@ inline std::string num2hex(uint32_t n) {
     return ss.str();
 }
 
+#include <rlib/stdio.hpp>
+
 #endif
diff --git a/nemu/include/cpu/decode.h b/nemu/include/cpu/decode.h
index e8c6191..df6a347 100644
--- a/nemu/include/cpu/decode.h
+++ b/nemu/include/cpu/decode.h
@@ -22,6 +22,10 @@ typedef struct {
   char str[OP_STR_SIZE];
 } Operand;
 
+inline std::ostream & operator<< (std::ostream &os, const Operand &operand) {
+  return os << "Operand{type=" << operand.type << ",width=" << operand.width << ",union{reg/addr/imm/simm}=" << std::hex << operand.reg << ",val=" << operand.val << std::dec << ",str=" << operand.str << "}";
+}
+
 typedef struct {
   uint32_t opcode;
   vaddr_t seq_eip;  // sequential eip
diff --git a/nemu/include/cpu/rtl.h b/nemu/include/cpu/rtl.h
index dd2b41a..1352785 100644
--- a/nemu/include/cpu/rtl.h
+++ b/nemu/include/cpu/rtl.h
@@ -21,6 +21,10 @@ static inline void interpret_rtl_mv(rtlreg_t* dest, const rtlreg_t *src1) {
   *dest = *src1;
 }
 
+// TODO: Optimize: change rtlreg_t* to rtlreg_t&, which barries the compiler optimization.
+
+// TODO: Optimize: DO NOT use `at` register in `addi`/subi... instructions. It's unnecessarily slow.
+
 #define make_rtl_arith_logic(name) \
   static inline void concat(interpret_rtl_, name) (rtlreg_t* dest, const rtlreg_t* src1, const rtlreg_t* src2) { \
     *dest = concat(c_, name) (*src1, *src2); \
@@ -158,16 +162,20 @@ static inline void rtl_sext(rtlreg_t* dest, const rtlreg_t* src1, int width) {
   TODO();
 }
 
+template <int OperandBytes>
 static inline void rtl_push(const rtlreg_t* src1) {
   // esp <- esp - 4
   // M[esp] <- src1
-  TODO();
+  rtl_subi(&cpu.esp, &cpu.esp, OperandBytes);
+  interpret_rtl_sm(&cpu.esp, src1, OperandBytes);
 }
 
+template <int OperandBytes>
 static inline void rtl_pop(rtlreg_t* dest) {
   // dest <- M[esp]
   // esp <- esp + 4
-  TODO();
+  interpret_rtl_lm(dest, &cpu.esp, OperandBytes);
+  rtl_addi(&cpu.esp, &cpu.esp, OperandBytes);
 }
 
 static inline void rtl_setrelopi(uint32_t relop, rtlreg_t *dest,
diff --git a/nemu/include/macro.h b/nemu/include/macro.h
index a08559b..68b9399 100644
--- a/nemu/include/macro.h
+++ b/nemu/include/macro.h
@@ -9,4 +9,10 @@
 #define concat4(x, y, z, w) concat3(concat(x, y), z, w)
 #define concat5(x, y, z, v, w) concat4(concat(x, y), z, v, w)
 
+#ifdef DEBUG
+#define RLIB_MACRO_DEBUG_ASSERT(expr) assert(expr)
+#else
+#define RLIB_MACRO_DEBUG_ASSERT(expr)
+#endif
+
 #endif
diff --git a/nemu/src/cpu/decode/decode.cc b/nemu/src/cpu/decode/decode.cc
index 036c330..ecd0665 100644
--- a/nemu/src/cpu/decode/decode.cc
+++ b/nemu/src/cpu/decode/decode.cc
@@ -42,7 +42,7 @@ static inline make_DopHelper(SI) {
    *
    op->simm = ???
    */
-  TODO();
+  op->simm = instr_fetch(eip, op->width);
 
   rtl_li(&op->val, op->simm);
 
diff --git a/nemu/src/cpu/exec/all-instr.h b/nemu/src/cpu/exec/all-instr.h
index 613d8f2..d63f2ec 100644
--- a/nemu/src/cpu/exec/all-instr.h
+++ b/nemu/src/cpu/exec/all-instr.h
@@ -6,3 +6,10 @@ make_EHelper(operand_size);
 
 make_EHelper(inv);
 make_EHelper(nemu_trap);
+
+make_EHelper(ret);
+make_EHelper(call);
+make_EHelper(push);
+make_EHelper(pop);
+//make_EHelper();
+//make_EHelper();
diff --git a/nemu/src/cpu/exec/control.cc b/nemu/src/cpu/exec/control.cc
index 676a2bd..f58ec10 100644
--- a/nemu/src/cpu/exec/control.cc
+++ b/nemu/src/cpu/exec/control.cc
@@ -26,13 +26,41 @@ make_EHelper(jmp_rm) {
 
 make_EHelper(call) {
   // the target address is calculated at the decode stage
-  TODO();
+  const bool near = true;
+  if(near) {
+    if(decoding.is_operand_size_16) {
+      throw std::runtime_error("call operand size 16 not implemented.");
+    }
+    else {
+      // operand size 32b
+      rlib::println("debug: call touched.", std::hex);
+      rtl_push<4>(&cpu.eip);
+      rlib::println("debug: idsrc.val=", id_src->val, "eip from=", cpu.eip);
+      rtl_add(&cpu.eip, &cpu.eip, &id_src->val);
+      rlib::println("debug: idsrc.val=", id_src->val, "eip to=", cpu.eip);
+    }
+  }
+ // TODO: support far call
+  // TODO();
 
   print_asm("call %x", decoding.jmp_eip);
 }
 
 make_EHelper(ret) {
-  TODO();
+  const bool near = true;
+  if(near) {
+    if(decoding.is_operand_size_16) {
+      throw std::runtime_error("call operand size 16 not implemented.");
+    }
+    else {
+      // operand size 32b
+      rtl_pop<4>(&cpu.eip);
+    }
+    rlib::println("debug: decoding.src=", decoding.src);
+  }
+
+ // TODO: support far ret
+  // TODO();
 
   print_asm("ret");
 }
diff --git a/nemu/src/cpu/exec/data-mov.cc b/nemu/src/cpu/exec/data-mov.cc
index 49ba2f1..9bf9883 100644
--- a/nemu/src/cpu/exec/data-mov.cc
+++ b/nemu/src/cpu/exec/data-mov.cc
@@ -6,13 +6,29 @@ make_EHelper(mov) {
 }
 
 make_EHelper(push) {
-  TODO();
+  static_assert(sizeof(paddr_t) * 8 == 32);
+  if(decoding.is_operand_size_16) {
+    // 16b push
+    rtl_push<2>(&id_src->val);
+  }
+  else {
+    // 32b push
+    rtl_push<4>(&id_src->val);
+  }
 
   print_asm_template1(push);
 }
 
 make_EHelper(pop) {
-  TODO();
+  static_assert(sizeof(paddr_t) * 8 == 32);
+  if(decoding.is_operand_size_16) {
+    // 16b
+    rtl_pop<2>(&id_src->val);
+  }
+  else {
+    // 32b
+    rtl_pop<4>(&id_src->val);
+  }
 
   print_asm_template1(pop);
 }
diff --git a/nemu/src/cpu/exec/exec.cc b/nemu/src/cpu/exec/exec.cc
index 373d4c3..f05726b 100644
--- a/nemu/src/cpu/exec/exec.cc
+++ b/nemu/src/cpu/exec/exec.cc
@@ -4,7 +4,7 @@
 typedef struct {
   DHelper decode;
   EHelper execute;
-  int width;
+  int width; // ByteWidth. If width is 0, using its default value: OperandSize (2Byte or 4Byte)
 } opcode_entry;
 
 #define IDEXW(id, ex, w)   {make_DHelper_funcname(id), make_EHelper_funcname(ex), w}
@@ -120,7 +120,7 @@ opcode_entry opcode_table [512] = {
   /* 0xb4 */	IDEXW(mov_I2r, mov, 1), IDEXW(mov_I2r, mov, 1), IDEXW(mov_I2r, mov, 1), IDEXW(mov_I2r, mov, 1),
   /* 0xb8 */	IDEX(mov_I2r, mov), IDEX(mov_I2r, mov), IDEX(mov_I2r, mov), IDEX(mov_I2r, mov),
   /* 0xbc */	IDEX(mov_I2r, mov), IDEX(mov_I2r, mov), IDEX(mov_I2r, mov), IDEX(mov_I2r, mov),
-  /* 0xc0 */	IDEXW(gp2_Ib2E, gp2, 1), IDEX(gp2_Ib2E, gp2), EMPTY, EMPTY,
+  /* 0xc0 */	IDEXW(gp2_Ib2E, gp2, 1), IDEX(gp2_Ib2E, gp2), IDEX(I, ret), EX(ret),
   /* 0xc4 */	EMPTY, EMPTY, IDEXW(mov_I2E, mov, 1), IDEX(mov_I2E, mov),
   /* 0xc8 */	EMPTY, EMPTY, EMPTY, EMPTY,
   /* 0xcc */	EMPTY, EMPTY, EMPTY, EMPTY,
@@ -130,7 +130,7 @@ opcode_entry opcode_table [512] = {
   /* 0xdc */	EMPTY, EMPTY, EMPTY, EMPTY,
   /* 0xe0 */	EMPTY, EMPTY, EMPTY, EMPTY,
   /* 0xe4 */	EMPTY, EMPTY, EMPTY, EMPTY,
-  /* 0xe8 */	EMPTY, EMPTY, EMPTY, EMPTY,
+  /* 0xe8 */  IDEX(J, call), EMPTY, EMPTY, EMPTY,
   /* 0xec */	EMPTY, EMPTY, EMPTY, EMPTY,
   /* 0xf0 */	EMPTY, EMPTY, EMPTY, EMPTY,
   /* 0xf4 */	EMPTY, EMPTY, IDEXW(E, gp3, 1), IDEX(E, gp3),
diff --git a/nemu/src/memory/memory.cc b/nemu/src/memory/memory.cc
index 2637056..0206211 100644
--- a/nemu/src/memory/memory.cc
+++ b/nemu/src/memory/memory.cc
@@ -19,10 +19,12 @@ void paddr_write(paddr_t addr, uint32_t data, int len) {
   memcpy(guest_to_host(addr), &data, len);
 }
 
+// len is Bytes.
 uint32_t vaddr_read(vaddr_t addr, int len) {
   return paddr_read(addr, len);
 }
 
+// len is Bytes.
 void vaddr_write(vaddr_t addr, uint32_t data, int len) {
   paddr_write(addr, data, len);
 }
-- 
GitLab