PA2.2&PA2.3

版权声明:本文为DmrfCoder原创作品,如有转载请注明出处 https://blog.csdn.net/qq_36982160/article/details/80210964

##PA2.2
###讲义中的问题
####堆和栈在哪里?
首先明确什么是堆和栈:

  • 栈(stack):是自动分配变量,以及函数调用所使用的一些空间(所谓的局部变量),地址由高向低减少;
  • 堆(heap):由malloc,new等分配的空间的地址,地址由低向高增长。

####为什么堆和栈的内容没有放进可执行文件里?
因为堆和栈中数据的变化比较频繁,如果放进可执行文件中读取速度会变慢。
####程序运行时刻用到的堆和栈是怎么来的?
程序运行时从内存中动态申请的。
####堆和栈在哪里?
在内存里。
###实现更多的指令

本阶段需要实现以下所有指令:

  • Data Movement Instructions:mov,push,pop,leave,cltd (在i386手册中为 cdq), movsx,movzx

  • Binary Arithmetic Instructions:add ,inc ,sub , dec,cmp,neg,adc, sbb,mul,imul,div,idiv

  • Logical Instructions:not,and,or,xor,sal(shl),shr,sar ,setcc,test

  • Control Transfer Instructions:jmp,jcc,call,ret

  • Miscellaneous Instructions:lea,nop
    其中xor、push、pop、call、ret、sub在PA2.1已实现,只需实现其余指令即可:
    ####完成makegroup

    /* 0x80, 0x81, 0x83 */
    make_group(gp1,
    EXW(add,1), EMPTY, EMPTY, EMPTY,
    EXW(and,1), EXW(sub,1), EMPTY, EXW(cmp,1))

    /* 0xc0, 0xc1, 0xd0, 0xd1, 0xd2, 0xd3 */
    

    make_group(gp2,
    EMPTY, EMPTY, EMPTY, EMPTY,
    EXW(shl,1), EX(shr), EMPTY, EXW(sar,1))

    /* 0xf6, 0xf7 */
    

    make_group(gp3,
    IDEX(test_I,test), EMPTY, EX(not), EMPTY,
    EX(mul), EX(imul1),EX(div), EX(idiv))

    /* 0xfe */
    

    make_group(gp4,
    EMPTY, EXW(dec,1), EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY)

    /* 0xff */
    

    make_group(gp5,
    EX(inc), EX(dec), EX(call_rm), EX(call),
    EX(jmp_rm), EMPTY, EX(push),EMPTY)

    /* 0x0f 0x01*/
    

    make_group(gp7,
    EMPTY, EMPTY, EMPTY, EMPTY,
    EMPTY, EMPTY, EMPTY, EMPTY)

####完成opcode_table

  • mov

        /* 0xb0 */	IDEXW(mov_I2r, mov, 1), IDEXW(mov_I2r, mov, 1), IDEXW(mov_I2r, mov, 1), IDEXW(mov_I2r, mov, 1),
        /* 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, EX(ret),
        /* 0xc4 */	EMPTY, EMPTY, IDEXW(mov_I2E, mov, 1), IDEX(mov_I2E, mov),
    
  • leave

           /* 0xc8 */	EMPTY, EX(leave), EMPTY, EMPTY,
    
  • cltd

      	   /* 0x98 */    EX(cwtl), EX(cltd), EMPTY, EMPTY,
    
  • movsx

         /* 0xbc */	EMPTY, EMPTY, IDEXW(mov_E2G, movsx, 1), IDEXW(mov_E2G, movsx, 2),
    
  • movzx

        /* 0xb4 */	EMPTY, EMPTY, IDEXW(mov_E2G, movzx, 1), IDEXW(mov_E2G, movzx, 2),
    
  • add

        /* 0x00 */	IDEXW(G2E,add,1), IDEX(G2E,add), IDEXW(E2G,add,1), IDEX(E2G,add),
    
  • inc

        /* 0x40 */	IDEX(r, inc), IDEX(r, inc), IDEX(r, inc), IDEX(r, inc),
        /* 0x44 */	IDEX(r, inc), IDEX(r, inc), IDEX(r, inc), IDEX(r, inc),	
    
  • sub

         /* 0x28 */	IDEXW(G2E, sub, 1), IDEX(G2E, sub), IDEXW(E2G, sub, 1), IDEX(E2G, sub),
        /* 0x2c */	IDEXW(I2a, sub, 1), IDEX(I2a, sub), EMPTY, EMPTY,
    
  • dec

        /* 0x48 */	IDEX(r, dec), IDEX(r, dec), IDEX(r, dec), IDEX(r, dec),
        /* 0x4c */	IDEX(r, dec), IDEX(r, dec), IDEX(r, dec), IDEX(r, dec),
    
  • cmp

        /* 0x38 */	IDEXW(G2E, cmp, 1), IDEX(G2E, cmp), IDEXW(E2G, cmp, 1), IDEX(E2G, cmp),
        /* 0x3c */	IDEXW(I2a, cmp, 1), IDEX(I2a, cmp), EMPTY, EMPTY,
    
  • adc

      	  /* 0x10 */	IDEXW(G2E, adc, 1), IDEX(G2E, adc), IDEXW(E2G, adc, 1), IDEX(E2G, adc),
             /* 0x14 */	IDEXW(I2a, adc, 1), IDEX(I2a, adc), EMPTY, EMPTY,
    
  • sbb

        /* 0x18 */	IDEXW(G2E, sbb, 1), IDEX(G2E, sbb), IDEXW(E2G, sbb, 1), IDEX(E2G, sbb),
        /* 0x1c */	IDEXW(I2a, sbb, 1), IDEX(I2a, sbb), EMPTY, EMPTY,
    
  • imul

        /* 0xac */	EMPTY, EMPTY, EMPTY, IDEX(E2G, imul2),
    
  • and

        /* 0x20 */	IDEXW(G2E, and, 1), IDEX(G2E, and), IDEXW(E2G, and, 1), IDEX(E2G, and),
         /* 0x24 */	EMPTY, IDEX(I2a, and), EMPTY, EMPTY,
    
  • or

        /* 0x08 */	IDEXW(G2E, or, 1), IDEX(G2E, or), IDEXW(E2G, or, 1), IDEX(E2G, or),
        /* 0x0c */	IDEXW(I2a, or, 1), IDEX(I2a, or), EMPTY, EX(2byte_esc),
    
  • setcc

       /* 0x90 */	IDEXW(E, setcc, 1), IDEXW(E, setcc, 1), IDEXW(E, setcc, 1), IDEXW(E, setcc, 1),
          /* 0x94 */	IDEXW(E, setcc, 1), IDEXW(E, setcc, 1), IDEXW(E, setcc, 1), IDEXW(E, setcc, 1),
          /* 0x98 */	IDEXW(E, setcc, 1), IDEXW(E, setcc, 1), IDEXW(E, setcc, 1), IDEXW(E, setcc, 1),
          /* 0x9c */	IDEXW(E, setcc, 1), IDEXW(E, setcc, 1), IDEXW(E, setcc, 1), IDEXW(E, setcc, 1),
    
  • test

         /* 0x84 */	IDEXW(G2E, test, 1), IDEX(G2E,test), EMPTY, EMPTY,
          /* 0xa8 */	IDEXW(I2a, test, 1), IDEX(I2a, test), EMPTY, EMPTY,
    
  • jmp

        /* 0xe8 */	IDEX(J, call), IDEX(J, jmp), EMPTY, IDEXW(J,jmp,1),
    
  • jcc

       /* 0x80 */	IDEX(J, jcc), IDEX(J, jcc), IDEX(J, jcc), IDEX(J, jcc),
       /* 0x84 */	IDEX(J, jcc), IDEX(J, jcc), IDEX(J, jcc), IDEX(J, jcc),
       /* 0x88 */	IDEX(J, jcc), IDEX(J, jcc), IDEX(J, jcc), IDEX(J, jcc),
       /* 0x8c */	IDEX(J, jcc), IDEX(J, jcc), IDEX(J, jcc), IDEX(J, jcc),
    
  • lea

        /* 0x8c */	EMPTY, IDEX(lea_M2G,lea), EMPTY, EMPTY,
    
  • nop

      /* 0x90 */	EX(nop), EMPTY, EMPTY, EMPTY,
    
  • cltd

        /* 0x98 */	EX(cwtl), EX(cltd), EMPTY, EMPTY,
    

####使⽤RTL实现正确的执⾏函数
⾸先进⼊ rtl.h ,需要实现的框架函数都已经给出,并且内部都有注释,只需要根据注释填充对应内容即可,⼀些读取和写⼊操作需要使⽤ rtl.h 内部已经定义写好的 rtl 函数,具体实现如下:

  • rtl_mv
    将src1的值赋给dest
static inline void rtl_mv(rtlreg_t *dest, const rtlreg_t *src1) {
		    // dest <- src1 xfg
		    *dest = *src1;
		}
  • rtl_not
    将dest取反
static inline void rtl_not(rtlreg_t *dest) {
		    // dest <- ~dest xfg
		    *dest = ~*dest;
		}
  • rtl_sext

      static inline void rtl_sext(rtlreg_t *dest, const rtlreg_t *src1, int width) {
          // dest <- signext(src1[(width * 8 - 1) .. 0]) xfg
          int32_t dm = (int32_t) * src1;
          dm <<= 32 - (8 * width);
          dm >>= 32 - (8 * width);
          *dest = dm;
      }
    
  • rtl_eqi
    如果src1==imm,则*dest为1,否则为0

static inline void rtl_eqi(rtlreg_t *dest, const rtlreg_t *src1, int imm) {
		    // dest <- (src1 == imm ? 1 : 0) xfg
		    *dest = (*src1 == imm);
		}
  • rtl_neq0
    如果src1不等于0则dest为1,否则为0

      static inline void rtl_neq0(rtlreg_t *dest, const rtlreg_t *src1) {
          // dest <- (src1 != 0 ? 1 : 0) xfg
          *dest = (*src1 != 0);
      }
    

####在all-instr.h中声明不同指令对应的make_EHlper函数

make_EHelper(lea);
make_EHelper(and);
make_EHelper(nop);
make_EHelper(add);
make_EHelper(cmp);
make_EHelper(setcc);
make_EHelper(movzx);
make_EHelper(test);
make_EHelper(jcc);
make_EHelper(adc);
make_EHelper(or);
make_EHelper(shl);
make_EHelper(sar);
make_EHelper(shr);
make_EHelper(dec);
make_EHelper(inc);
make_EHelper(not);
make_EHelper(jmp);
make_EHelper(mul);
make_EHelper(imul1);
make_EHelper(imul2);
make_EHelper(movsx);
make_EHelper(leave);
make_EHelper(call_rm);
make_EHelper(jmp_rm);
make_EHelper(sbb);
make_EHelper(cwtl);
make_EHelper(cltd);
make_EHelper(div);
make_EHelper(idiv);

####实现不同指令的make_EHelper函数体

#####leave

  • 所在位置:nemu/src/cpu/exec/data-mov.c

  • 实现思路:利用rtl_mv和rtl_pop实现leave指令

      make_EHelper(leave) {
          rtl_mv(&cpu.esp,&cpu.ebp);
          rtl_pop(&cpu.ebp);
      
        print_asm("leave");
      }
    

#####cltd

  • 所在位置:nemu/src/cpu/exec/data-mov.c

  • 实现思路:首先判断decoding.is_operand_size_16的值,根据不同的两种情况(0和1)使用已经完成的rtl_lr_w、rtl_sext、rtl_sari、rtl_sr_w、rtl_lr_l、rtl_sr_l实现cltd

      make_EHelper(cltd) {
      	    if (decoding.is_operand_size_16) {
      	        rtl_lr_w(&t0, R_AX);
      	        rtl_sext(&t0, &t0, 2);
      	        rtl_sari(&t0, &t0, 16);
      	        rtl_sr_w(R_DX, &t0);
      	    } else {
      	        rtl_lr_l(&t0, R_EAX);
      	        rtl_sari(&t0, &t0, 31);
      	        rtl_sari(&t0, &t0, 1);
      	        rtl_sr_l(R_EDX, &t0);
          }
      
        print_asm(decoding.is_operand_size_16 ? "cwtl" : "cltd");
      }
    

#####cwtl

  • 所在位置:nemu/src/cpu/exec/data-mov.c
  • 实现思路:类似cltd的实现方法,根据decoding.is_operand_size_16值的不同使用已经完成的rtl_lr_b、rtl_sext、rtl_sr_w、rtl_sr_l实现cwtl
make_EHelper(cwtl) {
    if (decoding.is_operand_size_16) {
        rtl_lr_b(&t0, R_AX);
        rtl_sext(&t0, &t0, 1);
        rtl_sr_w(R_AX, &t0);
    }
    else {
        rtl_lr_w(&t0, R_AX);
        rtl_sext(&t0, &t0, 2);
        rtl_sr_l(R_EAX, &t0);
    }

  print_asm(decoding.is_operand_size_16 ? "cbtw" : "cwtl");
}

#####call_rm

  • 所在位置:/home/dmrf/PA/ics2017/nemu/src/cpu/exec/control.c
  • 实现思路:首先给is_jmp赋值1,然后给jmp_eip赋值id_dest->val,最后push&decoding.seq_eip
make_EHelper(call_rm) {
    decoding.is_jmp = 1;
    decoding.jmp_eip = id_dest->val;
    rtl_push(&decoding.seq_eip);

  print_asm("call *%s", id_dest->str);
}

#####test

  • 所在位置:/home/dmrf/PA/ics2017/nemu/src/cpu/exec/logic.c
  • 实现思路:利用rtl_and、rtl_update_ZFSF、rtl_set_CF、rtl_set_OF实现test
make_EHelper(test) {
    rtl_and(&t0, &id_dest->val, &id_src->val);
    rtl_update_ZFSF(&t0, id_dest->width);
    rtl_set_CF(&tzero);
    rtl_set_OF(&tzero);

  print_asm_template2(test);
}

#####and

  • 所在位置:/home/dmrf/PA/ics2017/nemu/src/cpu/exec/logic.c
  • 实现思路:使用rtl_and、rtl_update_ZFSF、rtl_set_OF、rtl_set_CF实现and
make_EHelper(and) {
    rtl_and(&t0, &id_dest->val, &id_src->val);
    operand_write(id_dest, &t0);

    rtl_update_ZFSF(&t0, id_dest->width);
    rtl_set_OF(&tzero);
    rtl_set_CF(&tzero);

  print_asm_template2(and);
}

#####or

  • 所在位置:/home/dmrf/PA/ics2017/nemu/src/cpu/exec/logic.c
  • 实现思路:使用rtl_or、operand_write、rtl_update_ZFSF、rtl_set_OF、rtl_set_CF实现or
make_EHelper (or) {
    rtl_or(&t2, &id_dest->val, &id_src->val);
    printf("id_dest->val:%x\n", id_dest->val);
    printf("id_src->val:%x,t2:%d\n", id_src->val, t2);

    operand_write(id_dest, &t2);
    rtl_update_ZFSF(&t2, id_dest->width);
    rtl_set_OF(&tzero);
    rtl_set_CF(&tzero);

    print_asm_template2(or);
}

#####sar

  • 所在位置:/home/dmrf/PA/ics2017/nemu/src/cpu/exec/logic.c
  • 实现思路:使用rtl_sar、operand_write、rtl_update_ZFSF、print_asm_template2实现sar


make_EHelper (sar) {
    rtl_sar(&id_dest->val, &id_dest->val, &id_src->val);
    operand_write(id_dest, &id_dest->val);
    rtl_update_ZFSF(&id_dest->val,id_dest->width);
    // unnecessary to update CF and OF in NEMU

    print_asm_template2(sar);
}

#####shl

  • 所在位置:/home/dmrf/PA/ics2017/nemu/src/cpu/exec/logic.c
  • 实现思路:使用已经写好的rtl_shl和operand_write实现shl,最后注意update_ZFSF
make_EHelper (shl) {
    rtl_shl(&id_dest->val, &id_dest->val, &id_src->val);
    operand_write(id_dest, &id_dest->val);
    rtl_update_ZFSF(&id_dest->val,id_dest->width);
    // unnecessary to update CF and OF in NEMU

    print_asm_template2(shl);
}

#####shr

  • 所在位置:/home/dmrf/PA/ics2017/nemu/src/cpu/exec/logic.c
  • 实现思路:使用已经写好的rtl_shr和operand_write实现shr,最后注意update_ZFSF
make_EHelper (shr) {
    rtl_shr(&id_dest->val, &id_dest->val, &id_src->val);
    operand_write(id_dest, &id_dest->val);
    rtl_update_ZFSF(&id_dest->val,id_dest->width);
    // unnecessary to update CF and OF in NEMU

    print_asm_template2(shr);
}

#####not

  • 所在位置:/home/dmrf/PA/ics2017/nemu/src/cpu/exec/logic.c
  • 实现思路:使用已经写好的rtl_mv、rtl_not和operand_write实现not
make_EHelper (not) {
    rtl_mv(&t0, &id_dest->val);
    rtl_not(&t0);
    operand_write(id_dest, &t0);

    print_asm_template1(not);
}

#####add

  • 所在位置:/home/dmrf/PA/ics2017/nemu/src/cpu/exec/arith.c
  • 实现思路:使用rtl_add和operand_write实现add,注意最后update_ZFSF
make_EHelper(add) {
    rtl_add(&t2, &id_dest->val, &id_src->val);
    //rtl_get_CF(&t1);
    operand_write(id_dest, &t2);
    rtl_update_ZFSF(&t2, id_dest->width);

    rtl_sltu(&t0,&t2,&id_dest->val);

    rtl_set_CF(&t0);

    rtl_xor(&t0, &id_dest->val, &id_src->val);
    rtl_not(&t0);
    rtl_xor(&t1, &id_dest->val, &t2);
    rtl_and(&t0, &t0, &t1);
    rtl_msb(&t0, &t0, id_dest->width);
    rtl_set_OF(&t0);

  print_asm_template2(add);
}

#####cmp

  • 所在位置:/home/dmrf/PA/ics2017/nemu/src/cpu/exec/arith.c
make_EHelper(cmp) {
    rtl_sub(&t2, &id_dest->val, &id_src->val);
    rtl_update_ZFSF(&t2, id_dest->width);
    rtl_sltu(&t0, &id_dest->val, &t2);
   
    rtl_set_CF(&t0);

    rtl_xor(&t0, &id_dest->val, &id_src->val);
    rtl_xor(&t1, &id_dest->val, &t2);
    rtl_and(&t0, &t0, &t1);
    rtl_msb(&t0, &t0, id_dest->width);
    rtl_set_OF(&t0);

  print_asm_template2(cmp);
}

#####inc

  • 所在位置:/home/dmrf/PA/ics2017/nemu/src/cpu/exec/arith.c
  • 实现思路:使用rtl_addi和operand_write实现inc,最后注意update_ZFSF
make_EHelper(inc) {
    rtl_addi(&t2, &id_dest->val, 1);
   
    operand_write(id_dest, &t2);
    rtl_update_ZFSF(&t2, id_dest->width);



    rtl_xori(&t0, &id_dest->val, 1);
    rtl_not(&t0);
    rtl_xor(&t1, &id_dest->val, &t2);
    rtl_and(&t0, &t0, &t1);
    rtl_msb(&t0, &t0, id_dest->width);
    rtl_set_OF(&t0);


    print_asm_template1(inc);
}

#####dec

make_EHelper(dec) {
    rtl_subi(&t2, &id_dest->val, 1);

    operand_write(id_dest, &t2);
    rtl_update_ZFSF(&t2, id_dest->width);


    rtl_xor(&t0, &id_dest->val, &id_src->val);
    rtl_xor(&t1, &id_dest->val, &t2);
    rtl_and(&t0, &t0, &t1);
    rtl_msb(&t0, &t0, id_dest->width);
    rtl_set_OF(&t0);

  print_asm_template1(dec);
}

#####neg

  • 所在位置:/home/dmrf/PA/ics2017/nemu/src/cpu/exec/arith.c
make_EHelper(neg) {
    if(!id_dest->val){
        rtl_set_CF(&tzero);
    }else{
        rtl_addi(&t0,&tzero,1);
        rtl_set_CF(&t0);
    }
    rtl_add(&t0,&tzero,&id_dest->val);
    t0=-t0;
    operand_write(id_dest,&t0);
    rtl_update_ZFSF(&t2, id_dest->width);
    rtl_xor(&t0, &id_dest->val, &id_src->val);
    rtl_xor(&t1, &id_dest->val, &t2);
    rtl_and(&t0, &t0, &t1);
    rtl_msb(&t0, &t0, id_dest->width);
    rtl_set_OF(&t0);

    print_asm_template1(neg);
}

####完成rtl_setcc函数
+代码位置:/home/dmrf/PA/ics2017/nemu/src/cpu/exec/cc.c

void rtl_setcc(rtlreg_t* dest, uint8_t subcode) {
    rtlreg_t t,t1,t2,t3;
  bool invert = subcode & 0x1;
  enum {
    CC_O, CC_NO, CC_B,  CC_NB,
    CC_E, CC_NE, CC_BE, CC_NBE,
    CC_S, CC_NS, CC_P,  CC_NP,
    CC_L, CC_NL, CC_LE, CC_NLE
  };

  // TODO: Query EFLAGS to determine whether the condition code is satisfied.
  // dest <- ( cc is satisfied ? 1 : 0)
  switch (subcode & 0xe) {
    case CC_O: {
      rtl_get_OF(dest);
      break;
    }
    case CC_B: {
      rtl_get_CF(dest);
      break;
    }
    case CC_E: {
      rtl_get_ZF(dest);
      // printf("cpu.ZF:%d\n",*dest);
      break;
    }
    case CC_BE: {
      rtl_get_CF(&t);
      rtl_get_ZF(&t1);
      rtl_or(dest, &t, &t1);
      break;
    }
    case CC_S: {
      rtl_get_SF(dest);
      break;
    }
    case CC_L: {
      rtl_get_SF(&t);
      rtl_get_OF(&t1);
      rtl_li(dest, (t != t1));
      break;
    }
    case CC_LE:
      rtl_get_ZF(&t);
          rtl_get_SF(&t1);
          rtl_get_OF(&t2);
          temp3 = (t1 != t2 ? 1 : 0);
          rtl_or(dest, &t, &t3);
          break;
    default:
      panic("should not reach here");
    case CC_P:
      panic("n86 does not have PF");
  }

  if (invert) {
    rtl_xori(dest, dest, 0x1);
  }
}

####测试结果(一键回归测试)
这里写图片描述

###实现differential testing
首先将nemu/include/common.h中的宏DIFF-TEST打开:
这里写图片描述
然后make run就可以看到提示Connect to QEMU successfully :
这里写图片描述
然后实现difftest_step中的核心功能,只需按照提示比较NEMU和QEMU中寄存器的状态然后改变diff标志的值即可:

 if ( r.eax != cpu.eax
    || r.ecx != cpu.ecx
    || r.edx != cpu.edx
    || r.ebx != cpu.ebx
    || r.esp != cpu.esp
    || r.ebp != cpu.ebp
    || r.esi != cpu.esi
    || r.edi != cpu.edi
    || r.eip != cpu.eip)
  {
    diff = true;
  }

###捕捉死循环
这个没实现。。。
#PA2.3
##运行hello world
首先打开 nemu/include/common.h中的宏定义HAS_IOE:
这里写图片描述
##实现in和out指令:
###完成opcode_table

 /* 0xe4 */	IDEXW(in_I2a, in, 1), IDEX(in_I2a, in), IDEXW(out_a2I, out, 1), IDEX(out_a2I, out),
 /* 0xec */ IDEXW(in_dx2a, in, 1), IDEX(in_dx2a, in), IDEXW(out_a2dx, out, 1), IDEX(out_a2dx, out),

###在all-instr.h中声明make_EHelper:

 make_EHelper(in);
make_EHelper(out);

###完成make_EHelper函数:

  • 代码位置:system.c
    ####in
	make_EHelper(in) {
	   t1 = pio_read(id_src->val, id_dest->width);
	  operand_write(id_dest, &t1);
	
	  print_asm_template2(in);
	
	#ifdef DIFF_TEST
	  diff_test_skip_qemu();
	#endif
	}

####out

	make_EHelper(out) {
	  pio_write(id_dest->val, id_dest->width, id_src->val);
	
	  print_asm_template2(out);
	
	  print_asm_template2(out);
	
	#ifdef DIFF_TEST
	  diff_test_skip_qemu();
	#endif
	}

然后在/nexus-am/apps/hello下运行make run,结果如下:
这里写图片描述
###遇到的问题
刚开始make run的画风是这样的:
这里写图片描述
一堆log,hello world埋在log里面,刚开始以为是自己之前实现指令的时候使用了太多的printf没有注掉,所以就一个文件一个文件地注释printf,但是注释之后还是有很多log信息,这时才想到这可能是debug时的输出,最后把debug关掉就正常了。
##时钟
###实现_uptime():

  • 代码位置:ioe.c文件中
unsigned long _uptime() {
 return inl(RTC_PORT) - boot_time;
}

然后在tests/timetest下执行make run,就会每隔一秒打印出来一句话:
这里写图片描述
###运行跑分程序
####dhrystone
这个没跑成功…一直这样:
这里写图片描述
####coremark
这里写图片描述
####microbench
这里写图片描述

##键盘
###实现_read_key()

int _read_key() {
   uint32_t key_code = _KEY_NONE;

  if (inb(0x64) & 0x1)
    key_code = inl(0x60);

  return key_code;
}

###运行keytest程序:
这里写图片描述

##VGA

###实现paddr_read()和paddr_write()

  • 代码位置:/nemu/src/memory/memory.c
    ####paddr_read
uint32_t paddr_read(paddr_t addr, int len) {
 int mmio_n;
  if ((mmio_n = is_mmio(addr)) != -1)
    return mmio_read(addr, len, mmio_n);
  else
    return pmem_rw(addr, uint32_t) & (~0u >> ((4 - len) << 3));
}

####paddr_write

void paddr_write(paddr_t addr, int len, uint32_t data) {
  int mmio_n;
  if ((mmio_n = is_mmio(addr)) != -1)
    mmio_write(addr, len, data, mmio_n);
  else
    memcpy(guest_to_host(addr), &data, len);
}

要注意包含头文件:

#include "device/mmio.h"
#include "memory/mmu.h"

###运行videotest:
这里写图片描述
###实现_draw_rect():

void _draw_rect(const uint32_t *pixels, int x, int y, int w, int h) {
  int c, r;
  for (r = y; r < y + h; r++)
    for (c = x; c < x + w; c++) 
      fb[c+r*_screen.width] = pixels[(r-y)*w+(c-x)];
}

###运行videotest
这里写图片描述

###运行打字小游戏
这里写图片描述
###必答题
####一
只去掉static:
我去掉了好几个函数的static都没报错,我也很绝望啊…但是如果去掉static势必导致某些静态函数无法调用该函数,可能会报类似的错误…
去掉inline:
static inline void rtl_li(rtlreg_t* dest, uint32_t imm) {
dest = imm;
}
报错如下:
这里写图片描述
这里报错说该函数定义了但是没有使用,可能是调用该函数的地方都是以inline的方式编译的,所以如果这里去掉了inline相当于没有被调用过,所以就报了这个错…
去掉static和inline:
void rtl_li(rtlreg_t
dest, uint32_t imm) {
*dest = imm;
}
报错如下:
的
这个原因不清楚…
####二

  • 在 nemu/include/common.h 中添加一行 volatile static int dummy; 然后重新编译NEMU. 请问重新编译后的NEMU含有多少个 dummy 变量的实体? 你是如何得到这个结果的?
因为static是静态变量,所以应该只有一个。
  • 添加上题中的代码后, 再在 nemu/include/debug.h 中添加一行 volatile static intdummy; 然后重新编译NEMU. 请问此时的NEMU含有多少个 dummy 变量的实体?与上题中 dummy 变量实体数目进行比较, 并解释本题的结果.
虽然声明了两个,但是因为有覆盖现象,所以应该还是只有一个。
  • 修改添加的代码, 为两处 dummy 变量进行初始化: volatile static int dummy = 0;然后重新编译NEMU. 你发现了什么问题? 为什么之前没有出现这样的问题? (回答完本题后可以删除添加的代码.)
我发现报错了....
具体原因还没想明白...
  • 了解Makefile 请描述你在 nemu 目录下敲入 make 后, make 程序如何组织.c和.h文件,最终生成可执行文件 nemu/build/nemu . (这个问题包括两个方面: Makefile 的工作方式和编译链接的过程.) 关于 Makefile 工作方式的提示:
    Makefile 中使用了变量, 包含文件等特性
    Makefile 运用并重写了一些implicit rules
    在 man make 中搜索 -n 选项, 也许会对你有帮助
    RTFM
这个课上讲过:demo.c->demo.h->demo.s->demo.o

##gitlog截图
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_36982160/article/details/80210964
pa
今日推荐