xiaoma@xiaoma-virtual-machine:~/Downloads/ics/ics_pa/nemu$ make run /home/xiaoma/Downloads/ics/ics_pa/nemu/build/riscv32-nemu-interpreter --log=/home/xiaoma/Downloads/ics/ics_pa/nemu/build/nemu-log.txt [src/utils/log.c:30 init_log] Log is written to /home/xiaoma/Downloads/ics/ics_pa/nemu/build/nemu-log.txt [src/memory/paddr.c:50 init_mem] physical memory area [0x80000000, 0x87ffffff] [src/monitor/monitor.c:51 load_img] No image is given. Use the default build-in image. [src/monitor/monitor.c:28 welcome] Trace: ON [src/monitor/monitor.c:29 welcome] If trace is enabled, a log file will be generated to record the trace. This may lead to a large log file. If it is not necessary, you can disable it in menuconfig [src/monitor/monitor.c:32 welcome] Build time: 04:58:17, Apr 6 2024 Welcome to riscv32-NEMU! For help, type "help" [src/monitor/monitor.c:35 welcome] Exercise: Please remove me in the source code and compile NEMU again. (nemu) c [src/cpu/cpu-exec.c:120 cpu_exec] nemu: HIT GOOD TRAP at pc = 0x8000000c [src/cpu/cpu-exec.c:88 statistic] host time spent = 119 us [src/cpu/cpu-exec.c:89 statistic] total guest instructions = 4 [src/cpu/cpu-exec.c:90 statistic] simulation frequency = 33,613 inst/s
voidinit_rand(); voidinit_log(constchar *log_file); voidinit_mem(); voidinit_difftest(char *ref_so_file, long img_size, int port); voidinit_device(); voidinit_sdb(); voidinit_disasm(constchar *triple);
staticvoidwelcome() { Log("Trace: %s", MUXDEF(CONFIG_TRACE, ANSI_FMT("ON", ANSI_FG_GREEN), ANSI_FMT("OFF", ANSI_FG_RED))); IFDEF(CONFIG_TRACE, Log("If trace is enabled, a log file will be generated " "to record the trace. This may lead to a large log file. " "If it is not necessary, you can disable it in menuconfig")); Log("Build time: %s, %s", __TIME__, __DATE__); printf("Welcome to %s-NEMU!\n", ANSI_FMT(str(__GUEST_ISA__), ANSI_FG_YELLOW ANSI_BG_RED)); printf("For help, type \"help\"\n"); Log("Exercise: Please remove me in the source code and compile NEMU again."); // assert(0); }
A disk image is a snapshot of a storage device’s structure and data typically stored in one or more computer files on another storage device.[1][2] Traditionally, disk images were bit-by-bit copies of every sector on a hard disk often created for digital forensic purposes, but it is now common to only copy allocated data to reduce storage space.[3][4]Compression and deduplication are commonly used to reduce the size of the image file set.[3][5] Disk imaging is done for a variety of purposes including digital forensics,[6][2]cloud computing,[7]system administration,[8] as part of a backup strategy,[1] and legacy emulation as part of a digital preservation strategy.[9] Disk images can be made in a variety of formats depending on the purpose. Virtual disk images (such as VHD and VMDK) are intended to be used for cloud computing,[10][11]ISO images are intended to emulate optical media[12] and raw disk images) are used for forensic purposes.[2] Proprietary formats are typically used by disk imaging software. Despite the benefits of disk imaging the storage costs can be high,[3] management can be difficult[6] and they can be time consuming to create.[13][9]
// this is not consistent with uint8_t // but it is ok since we do not access the array directly staticconstuint32_t img [] = { 0x00000297, // auipc t0,0 0x00028823, // sb zero,16(t0) 0x0102c503, // lbu a0,16(t0) 0x00100073, // ebreak (used as nemu_trap) 0xdeadbeef, // some data };
staticvoidrestart() { /* Set the initial program counter. */ cpu.pc = RESET_VECTOR;
/* The zero register is always 0. */ cpu.gpr[0] = 0; }
/* The assembly code of instructions executed is only output to the screen * when the number of instructions executed is less than this value. * This is useful when you use the `si' command. * You can modify this value as you want. */ #define MAX_INST_TO_PRINT 10
CPU_state cpu = {}; uint64_t g_nr_guest_inst = 0; staticuint64_t g_timer = 0; // unit: us staticbool g_print_step = false;
/* Simulate how the CPU works. */ voidcpu_exec(uint64_t n) { g_print_step = (n < MAX_INST_TO_PRINT); switch (nemu_state.state) { case NEMU_END: case NEMU_ABORT: printf("Program execution has ended. To restart the program, exit NEMU and run again.\n"); return; default: nemu_state.state = NEMU_RUNNING; }
switch (nemu_state.state) { case NEMU_RUNNING: nemu_state.state = NEMU_STOP; break;
case NEMU_END: case NEMU_ABORT: Log("nemu: %s at pc = " FMT_WORD, (nemu_state.state == NEMU_ABORT ? ANSI_FMT("ABORT", ANSI_FG_RED) : (nemu_state.halt_ret == 0 ? ANSI_FMT("HIT GOOD TRAP", ANSI_FG_GREEN) : ANSI_FMT("HIT BAD TRAP", ANSI_FG_RED))), nemu_state.halt_pc); // fall through case NEMU_QUIT: statistic(); } }
在指令执行后,它再次检查状态。如果CPU仍在运行(NEMU_RUNNING),它会将状态更改为NEMU_STOP,表示当前一批指令已经执行完毕。 如果状态是NEMU_END或NEMU_ABORT,它会记录一条消息。这条消息包括程序是正常结束(HIT GOOD TRAP),出现错误(HIT BAD TRAP),还是被中止,并打印达到该状态时的程序计数器(pc)。
/* Simulate how the CPU works. */ voidcpu_exec(uint64_t n) { g_print_step = (n < MAX_INST_TO_PRINT); switch (nemu_state.state) { case NEMU_END: case NEMU_ABORT: printf("Program execution has ended. To restart the program, exit NEMU and run again.\n"); return; default: nemu_state.state = NEMU_RUNNING; }
switch (nemu_state.state) { case NEMU_RUNNING: nemu_state.state = NEMU_STOP; break;
case NEMU_END: case NEMU_ABORT: Log("nemu: %s at pc = " FMT_WORD, (nemu_state.state == NEMU_ABORT ? ANSI_FMT("ABORT", ANSI_FG_RED) : (nemu_state.halt_ret == 0 ? ANSI_FMT("HIT GOOD TRAP", ANSI_FG_GREEN) : ANSI_FMT("HIT BAD TRAP", ANSI_FG_RED))), nemu_state.halt_pc); // fall through case NEMU_QUIT: statistic(); } }
staticvoidout_of_bound(paddr_t addr) { panic("address = " FMT_PADDR " is out of bound of pmem [" FMT_PADDR ", " FMT_PADDR "] at pc = " FMT_WORD, addr, PMEM_LEFT, PMEM_RIGHT, cpu.pc); }
/* convert the guest physical address in the guest program to host virtual address in NEMU */ uint8_t* guest_to_host(paddr_t paddr); /* convert the host virtual address in NEMU to guest physical address in the guest program */ paddr_thost_to_guest(uint8_t *haddr);
/ macro testing // See https://stackoverflow.com/questions/26099745/test-if-preprocessor-symbol-is-defined-inside-macro #define CHOOSE2nd(a, b, ...) b #define MUX_WITH_COMMA(contain_comma, a, b) CHOOSE2nd(contain_comma a, b) #define MUX_MACRO_PROPERTY(p, macro, a, b) MUX_WITH_COMMA(concat(p, macro), a, b) // define placeholders for some property #define __P_DEF_0 X, #define __P_DEF_1 X, #define __P_ONE_1 X, #define __P_ZERO_0 X, // define some selection functions based on the properties of BOOLEAN macro #define MUXDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, X, Y) #define MUXNDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, Y, X) #define MUXONE(macro, X, Y) MUX_MACRO_PROPERTY(__P_ONE_, macro, X, Y) #define MUXZERO(macro, X, Y) MUX_MACRO_PROPERTY(__P_ZERO_,macro, X, Y)
/*************************************************************************************** * Copyright (c) 2014-2022 Zihao Yu, Nanjing University * * NEMU is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * * See the Mulan PSL v2 for more details. ***************************************************************************************/
// strlen() for string constant #define STRLEN(CONST_STR) (sizeof(CONST_STR) - 1)
// calculate the length of an array #define ARRLEN(arr) (int)(sizeof(arr) / sizeof(arr[0]))
// macro concatenation #define concat_temp(x, y) x ## y #define concat(x, y) concat_temp(x, y) #define concat3(x, y, z) concat(concat(x, y), z) #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)
// macro testing // See https://stackoverflow.com/questions/26099745/test-if-preprocessor-symbol-is-defined-inside-macro #define CHOOSE2nd(a, b, ...) b #define MUX_WITH_COMMA(contain_comma, a, b) CHOOSE2nd(contain_comma a, b) #define MUX_MACRO_PROPERTY(p, macro, a, b) MUX_WITH_COMMA(concat(p, macro), a, b) // define placeholders for some property #define __P_DEF_0 X, #define __P_DEF_1 X, #define __P_ONE_1 X, #define __P_ZERO_0 X, // define some selection functions based on the properties of BOOLEAN macro #define MUXDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, X, Y) #define MUXNDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, Y, X) #define MUXONE(macro, X, Y) MUX_MACRO_PROPERTY(__P_ONE_, macro, X, Y) #define MUXZERO(macro, X, Y) MUX_MACRO_PROPERTY(__P_ZERO_,macro, X, Y)
// test if a boolean macro is defined #define ISDEF(macro) MUXDEF(macro, 1, 0) // test if a boolean macro is undefined #define ISNDEF(macro) MUXNDEF(macro, 1, 0) // test if a boolean macro is defined to 1 #define ISONE(macro) MUXONE(macro, 1, 0) // test if a boolean macro is defined to 0 #define ISZERO(macro) MUXZERO(macro, 1, 0) // test if a macro of ANY type is defined // NOTE1: it ONLY works inside a function, since it calls `strcmp()` // NOTE2: macros defined to themselves (#define A A) will get wrong results #define isdef(macro) (strcmp("" #macro, "" str(macro)) != 0)
// simplification for conditional compilation #define __IGNORE(...) #define __KEEP(...) __VA_ARGS__ // keep the code if a boolean macro is defined #define IFDEF(macro, ...) MUXDEF(macro, __KEEP, __IGNORE)(__VA_ARGS__) // keep the code if a boolean macro is undefined #define IFNDEF(macro, ...) MUXNDEF(macro, __KEEP, __IGNORE)(__VA_ARGS__) // keep the code if a boolean macro is defined to 1 #define IFONE(macro, ...) MUXONE(macro, __KEEP, __IGNORE)(__VA_ARGS__) // keep the code if a boolean macro is defined to 0 #define IFZERO(macro, ...) MUXZERO(macro, __KEEP, __IGNORE)(__VA_ARGS__)
// functional-programming-like macro (X-macro) // apply the function `f` to each element in the container `c` // NOTE1: `c` should be defined as a list like: // f(a0) f(a1) f(a2) ... // NOTE2: each element in the container can be a tuple #define MAP(c, f) c(f)
#define BITMASK(bits) ((1ull << (bits)) - 1) #define BITS(x, hi, lo) (((x) >> (lo)) & BITMASK((hi) - (lo) + 1)) // similar to x[hi:lo] in verilog #define SEXT(x, len) ({ struct { int64_t n : len; } __x = { .n = x }; (uint64_t)__x.n; })