feat: learning note for pre study phase 5: program execution and simulator.

This commit is contained in:
feng-arch 2025-02-20 17:23:08 +08:00
parent 960dced2a9
commit 1a2eea6900
7 changed files with 366 additions and 7 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
*.a
*.so
*.out
*.bin

View File

@ -100,3 +100,162 @@ while (!halt)
inst_cycle();
}
```
### 第一版YEMU
向YEMU_first.c中加入如下内容
```c
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
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 <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
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
```

View File

@ -0,0 +1,57 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
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;
}

View File

@ -0,0 +1,86 @@
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#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;
}

View File

@ -1,13 +1,28 @@
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#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,10 +60,23 @@ 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();

View File

@ -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);
}

View File

@ -0,0 +1 @@
#define MSIZE 512