feat: learning note for pre study phase 5: program execution and simulator.
This commit is contained in:
parent
960dced2a9
commit
1a2eea6900
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,5 @@
|
|||||||
*.o
|
*.o
|
||||||
*.a
|
*.a
|
||||||
*.so
|
*.so
|
||||||
*.out
|
*.out
|
||||||
|
*.bin
|
||||||
@ -100,3 +100,162 @@ while (!halt)
|
|||||||
inst_cycle();
|
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的目录下,运行下面的命令
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
现在让我们试试更加复杂的程序,将**_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
|
||||||
|
```
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
@ -1,13 +1,28 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.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;
|
uint32_t R[32], PC;
|
||||||
uint8_t M[1024] = {
|
uint8_t M[MSIZE]; //1024-Byte memory
|
||||||
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;
|
bool halt = false;
|
||||||
@ -45,13 +60,26 @@ void inst_cycle()
|
|||||||
PC += 4;
|
PC += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
PC = 0;
|
PC = 0;
|
||||||
R[0] = 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)
|
while (!halt)
|
||||||
{
|
{
|
||||||
inst_cycle();
|
inst_cycle();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -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);
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
#define MSIZE 512
|
||||||
Loading…
x
Reference in New Issue
Block a user