YEMU模拟器运行机制

项目工程

Posted by Bruce Lee on 2024-05-08

YEMU模拟器运行机制


#include <stdint.h>
#include <stdio.h>

//------------4个寄存器,16字节地址
#define NREG 4
#define NMEM 16

// define the instruction format
//-----------------联合体用法,总长是8bit,可以引用不同的位域
typedef union {
struct { uint8_t rs : 2, rt : 2, op : 4; } rtype;
struct { uint8_t addr : 4 , op : 4; } mtype;
uint8_t inst;
} inst_t;
//-------------------宏,解码声明定义
#define DECODE_R(inst) uint8_t rt = (inst).rtype.rt, rs = (inst).rtype.rs
#define DECODE_M(inst) uint8_t addr = (inst).mtype.addr

uint8_t pc = 0; // PC, There is no 4-bit data type in C, we use 8-bit type to represent it
uint8_t R[NREG] = {}; // registers
uint8_t M[NMEM] = { // memory, which contains a program that calculates z = x + y
0b11100110, // load 6# | R[0] <- M[y]//加载33
0b00000100, // mov r1, r0 | R[1] <- R[0]//移动到r1寄存器
0b11100101, // load 5# | R[0] <- M[x]//加载16
0b00010001, // add r0, r1 | R[0] <- R[0] + R[1]//相加存储在r0
0b11110111, // store 7# | M[z] <- R[0]//存放内存中
0b00010000, // x = 16
0b00100001, // y = 33
0b00000000, // z = 0
};

int halt = 0; // end marker

// Execute an instruction
void exec_once() {
inst_t this;
this.inst = M[pc]; // instruction fetch
switch (this.rtype.op) {
// op decode operand decode execution
//局部作用域,声明定义解码中的不同域
case 0b0000: { DECODE_R(this); R[rt] = R[rs]; break; }
case 0b0001: { DECODE_R(this); R[rt] += R[rs]; break; }
case 0b1110: { DECODE_M(this); R[0] = M[addr]; break; }
case 0b1111: { DECODE_M(this); M[addr] = R[0]; break; }
default:
printf(“Invalid instruction with opcode = %x, halting…\n”, this.rtype.op);
halt = 1;
break;
}
pc ++; // Update PC
}

int main() {
while (1) {
exec_once();
if (halt) break;
}
printf(“The result of 16 + 33 is %d\n”, M[7]);
return 0;
}


状态模型

项目助解由于只用到了PC, R0, R1, M[7],所以这里的状态机这样表示:
(PC, R0, R1, M[7])
(0, 0, 0, 0) -> (1, 33, 0, 0) -> (2, 33, 33, 0) -> (3, 16, 33, 0) -> (4, 49, 33, 0) -> (5, 49, 33, 49)
注意由于M[6]存储着0b00010000,所以下一个状态是
-> (6, 98, 33, 49) -> RETURN

通过使用union定义指令格式

在该微小模拟器中.根据PC从内存(数组)中取出一个字节,对其opcode进行译码,这里不管是this.rtype.op还是this.mtype.op都是可以的,因为两个指令的op位域是相同的(高4位),然后通过case语句(Look-up Table), 进行不同的译码(使用不同的宏来声明不同指令格式的引用),
然后对齐进行算术操作或者赋值操作.
如果opcode译码阶段错误,则会置halt为1.然后退出.
最后退出,等待下一次调用.

联系/最后

这里体现了,从内存读取指令,执行指令(访问寄存器/访问内存/ALU).

状态模型掩盖了译码阶段,只关注存储器中的值(状态).
后者更加关注过程,行为过程


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. All the images used in the blog are my original works or AI works, if you want to take it,don't hesitate. Thank you !