##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,否则为0static 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截图