diff --git a/.gitignore b/.gitignore index ed1f2bb..b7d15f2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.o *.a *.so -*.out \ No newline at end of file +*.out +*.bin \ No newline at end of file diff --git a/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/README.md b/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/README.md index 6bb8237..8f8cec2 100644 --- a/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/README.md +++ b/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/README.md @@ -100,3 +100,162 @@ while (!halt) inst_cycle(); } ``` + +### 第一版YEMU +向YEMU_first.c中加入如下内容 +```c +#include +#include +#include + + +uint32_t R[32], PC; +uint8_t M[1024] = { + 0x13, 0x05, 0x00, 0x00, 0x93, 0x05, 0x10, 0x04, 0x73, 0x00, 0x10, 0x00, 0x13, 0x05, + 0x10, 0x00, 0x93, 0x05, 0x00, 0x00, 0x73, 0x00, 0x10, 0x00, 0x6f, 0x00, 0x00, 0x00, +}; //64-Byte memory + + +bool halt = false; + +void inst_cycle() +{ + uint32_t inst = *(uint32_t *)&M[PC]; + if (((inst & 0x7f) == 0x13) && ((inst >> 12) & 0x7) == 0) + { // addi + if (((inst >> 7) & 0x1f) != 0) + { + R[(inst >> 7) & 0x1f] = + R[(inst >> 15) & 0x1f] + (((inst >> 20) & 0x7ff) - ((inst & 0x80000000) ? 4096 : 0)); + } + } + else if (inst == 0x00100073) + { // ebreak + if (R[10] == 0) + { + putchar(R[11] & 0xff); + } + else if (R[10] == 1) + { + halt = true; + } + else + { + printf("unsupport ebreak command\n"); + } + } + else + { + printf("unsupported instruction\n"); + } + PC += 4; +} + +int main() +{ + PC = 0; + R[0] = 0; + while (!halt) + { + inst_cycle(); + } + return 0; +} +``` +在shell中执行如下命令 +```shell +gcc ./YEMU_first.c -o a.out && ./a.out +``` +### 第二版YEMU +在第一版YEMU中,我们的程序时写在代码里的,为了让我们的YEMU可以执行其它程序,我们需要在YEMU中读取外部的二进制文件。 + +向YEMU_second.c中加入如下的内容: +```c +#include +#include +#include +#include + + +uint32_t R[32], PC; +uint8_t M[1024]; //1024-Byte memory + + +bool halt = false; + +void inst_cycle() +{ + uint32_t inst = *(uint32_t *)&M[PC]; + if (((inst & 0x7f) == 0x13) && ((inst >> 12) & 0x7) == 0) + { // addi + if (((inst >> 7) & 0x1f) != 0) + { + R[(inst >> 7) & 0x1f] = + R[(inst >> 15) & 0x1f] + (((inst >> 20) & 0x7ff) - ((inst & 0x80000000) ? 4096 : 0)); + } + } + else if (inst == 0x00100073) + { // ebreak + if (R[10] == 0) + { + putchar(R[11] & 0xff); + } + else if (R[10] == 1) + { + halt = true; + } + else + { + printf("unsupport ebreak command\n"); + } + } + else + { + printf("unsupported instruction\n"); + } + PC += 4; +} + +int main(int argc, char* argv[]) +{ + PC = 0; + R[0] = 0; + assert(argc >= 2); + FILE *fp = fopen(argv[1], "r"); + assert(fp != NULL); + int ret = fseek(fp, 0, SEEK_END); + assert(ret != -1); + long fsize = ftell(fp); + assert(fsize != -1); + rewind(fp); + assert(fsize < 1024); + ret = fread(M, 1, 1024, fp); + assert(ret == fsize); + fclose(fp); + while (!halt) + { + inst_cycle(); + } + return 0; +} +``` +然后将之前编译的prog.out复制到YEMU的目录下,运行下面的命令 + +![](https://feng-arch.cn/wp-content/uploads/2025/02/1740041649-YEMU_1.png) + +现在让我们试试更加复杂的程序,将**_start()**换成下面的代码 +```c +void _start() { + putch('H'); putch('e'); putch('l'); putch('l'); putch('o'); putch(','); putch(' '); + putch('R'); putch('I'); putch('S'); putch('C'); putch('-'); putch('V'); putch('!'); + putch('\n'); + halt(0); +} +``` +在shell中执行下面的命令,我们就可以使用YEMU输出"Hello, RISC-V"。 +```shell +riscv64-unknown-elf-gcc -ffreestanding -nostdlib -static -Wl,-Ttext=0 -O2 -march=rv64g -mabi=lp64 -o prog.out ./more_complex_program.c +riscv64-unknown-elf-objcopy -j .text -O binary prog.out prog.bin +./a.out ./prog.bin +``` + diff --git a/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/YEMU_first.c b/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/YEMU_first.c new file mode 100644 index 0000000..b17bc6e --- /dev/null +++ b/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/YEMU_first.c @@ -0,0 +1,57 @@ +#include +#include +#include + + +uint32_t R[32], PC; +uint8_t M[1024] = { + 0x13, 0x05, 0x00, 0x00, 0x93, 0x05, 0x10, 0x04, 0x73, 0x00, 0x10, 0x00, 0x13, 0x05, + 0x10, 0x00, 0x93, 0x05, 0x00, 0x00, 0x73, 0x00, 0x10, 0x00, 0x6f, 0x00, 0x00, 0x00, +}; //64-Byte memory + + +bool halt = false; + +void inst_cycle() +{ + uint32_t inst = *(uint32_t *)&M[PC]; + if (((inst & 0x7f) == 0x13) && ((inst >> 12) & 0x7) == 0) + { // addi + if (((inst >> 7) & 0x1f) != 0) + { + R[(inst >> 7) & 0x1f] = + R[(inst >> 15) & 0x1f] + (((inst >> 20) & 0x7ff) - ((inst & 0x80000000) ? 4096 : 0)); + } + } + else if (inst == 0x00100073) + { // ebreak + if (R[10] == 0) + { + putchar(R[11] & 0xff); + } + else if (R[10] == 1) + { + halt = true; + } + else + { + printf("unsupport ebreak command\n"); + } + } + else + { + printf("unsupported instruction\n"); + } + PC += 4; +} + +int main() +{ + PC = 0; + R[0] = 0; + while (!halt) + { + inst_cycle(); + } + return 0; +} diff --git a/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/YEMU_second.c b/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/YEMU_second.c new file mode 100644 index 0000000..d7a2345 --- /dev/null +++ b/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/YEMU_second.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include + +#define MSIZE 1024 + + +#define Assert(cond, format, ...) \ + do \ + { \ + if (!(cond)) \ + { \ + fprintf(stderr, format "\n", ##__VA_ARGS__); \ + assert(cond); \ + } \ + } while (0) + + +#define Perror(cond, format, ...) Assert(cond, format ": %s", ##__VA_ARGS__, strerror(errno)) + + +uint32_t R[32], PC; +uint8_t M[MSIZE]; //1024-Byte memory + + +bool halt = false; + +void inst_cycle() +{ + uint32_t inst = *(uint32_t *)&M[PC]; + if (((inst & 0x7f) == 0x13) && ((inst >> 12) & 0x7) == 0) + { // addi + if (((inst >> 7) & 0x1f) != 0) + { + R[(inst >> 7) & 0x1f] = + R[(inst >> 15) & 0x1f] + (((inst >> 20) & 0x7ff) - ((inst & 0x80000000) ? 4096 : 0)); + } + } + else if (inst == 0x00100073) + { // ebreak + if (R[10] == 0) + { + putchar(R[11] & 0xff); + } + else if (R[10] == 1) + { + halt = true; + } + else + { + printf("unsupport ebreak command\n"); + } + } + else + { + printf("unsupported instruction\n"); + } + PC += 4; +} + + +int main(int argc, char *argv[]) +{ + PC = 0; + R[0] = 0; + Assert(argc >= 2, "Program is not given"); // 要求至少包含一个参数 + FILE *fp = fopen(argv[1], "r"); + Perror(fp != NULL, "Fail to open %s", argv[1]); // 要求argv[1]是一个可以成功打开的文件 + int ret = fseek(fp, 0, SEEK_END); + Perror(ret != -1, "Fail to seek the end of the file"); // 要求fseek()成功 + long fsize = ftell(fp); + Perror(fsize != -1, "Fail to return the file position"); // 要求ftell()成功 + rewind(fp); + Assert(fsize < MSIZE, "Program size exceeds 1024 Bytes"); // 要求程序大小不超过1024字节 + ret = fread(M, 1, MSIZE, fp); + Assert(ret == fsize, "Fail to load the whole program"); // 要求完全读出程序的内容 + fclose(fp); + while (!halt) + { + inst_cycle(); + } + return 0; +} \ No newline at end of file diff --git a/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/main.c b/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/main.c index b17bc6e..efb270c 100644 --- a/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/main.c +++ b/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/main.c @@ -1,13 +1,28 @@ +#include +#include #include #include #include +#include +#include "yemu.h" + + +#define Assert(cond, format, ...) \ + do \ + { \ + if (!(cond)) \ + { \ + fprintf(stderr, format "\n", ##__VA_ARGS__); \ + assert(cond); \ + } \ + } while (0) + + +#define Perror(cond, format, ...) Assert(cond, format ": %s", ##__VA_ARGS__, strerror(errno)) uint32_t R[32], PC; -uint8_t M[1024] = { - 0x13, 0x05, 0x00, 0x00, 0x93, 0x05, 0x10, 0x04, 0x73, 0x00, 0x10, 0x00, 0x13, 0x05, - 0x10, 0x00, 0x93, 0x05, 0x00, 0x00, 0x73, 0x00, 0x10, 0x00, 0x6f, 0x00, 0x00, 0x00, -}; //64-Byte memory +uint8_t M[MSIZE]; //1024-Byte memory bool halt = false; @@ -45,13 +60,26 @@ void inst_cycle() PC += 4; } -int main() + +int main(int argc, char *argv[]) { PC = 0; R[0] = 0; + Assert(argc >= 2, "Program is not given"); // 要求至少包含一个参数 + FILE *fp = fopen(argv[1], "r"); + Perror(fp != NULL, "Fail to open %s", argv[1]); // 要求argv[1]是一个可以成功打开的文件 + int ret = fseek(fp, 0, SEEK_END); + Perror(ret != -1, "Fail to seek the end of the file"); // 要求fseek()成功 + long fsize = ftell(fp); + Perror(fsize != -1, "Fail to return the file position"); // 要求ftell()成功 + rewind(fp); + Assert(fsize < MSIZE, "Program size exceeds 1024 Bytes"); // 要求程序大小不超过1024字节 + ret = fread(M, 1, MSIZE, fp); + Assert(ret == fsize, "Fail to load the whole program"); // 要求完全读出程序的内容 + fclose(fp); while (!halt) { inst_cycle(); } return 0; -} +} \ No newline at end of file diff --git a/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/more_complex_program.c b/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/more_complex_program.c new file mode 100644 index 0000000..d0ad837 --- /dev/null +++ b/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/more_complex_program.c @@ -0,0 +1,27 @@ +static void ebreak(long arg0, long arg1) +{ + asm volatile("addi a0, x0, %0;" + "addi a1, x0, %1;" + "ebreak" + : + : "i"(arg0), "i"(arg1)); +} + +static void putch(char ch) +{ + ebreak(0, ch); +} + +static void halt(int code) +{ + ebreak(1, code); + while (1) + ; +} + +void _start() { + putch('H'); putch('e'); putch('l'); putch('l'); putch('o'); putch(','); putch(' '); + putch('R'); putch('I'); putch('S'); putch('C'); putch('-'); putch('V'); putch('!'); + putch('\n'); + halt(0); +} \ No newline at end of file diff --git a/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/yemu.h b/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/yemu.h new file mode 100644 index 0000000..e49e449 --- /dev/null +++ b/pre-study_phase/2025_02_20/pre_phase_5_program_execution_and_simulator/YEMU/yemu.h @@ -0,0 +1 @@ +#define MSIZE 512 \ No newline at end of file