记录一下做汇编代码模拟器的过程,根据“程序=状态机”的视角,模拟实现了汇编程序的执行过程,下面就开始进入正题吧。
第一部分:CPU
在状态机的视角下,CPU看作多个寄存器的全部状态,因而可以用一个struct来保存所有寄存器的值。同时,CPU还有MMU来实现虚拟内存向物理内存的切换(目前暂时不实现MMU的功能,而是简单的将虚拟地址取模得到物理地址)。
register.h
#ifndef _REGISTER_
#define _REGISTER_
#include <stdlib.h>
#include <stdint.h>
// 真正拥有的只有CPU和Memory.离散.状态机
typedef struct REG_STRUCT
// 这是对CPU的模拟
{
union
{
struct
{
uint8_t al;
uint8_t ah;
};
uint16_t ax;
uint32_t eax;
uint64_t rax;
};
// 后面rbx..也是一样的写法,这边就偷懒不弄了.
uint64_t rbx;
uint64_t rcx;
uint64_t rdx;
uint64_t rsi;
uint64_t rdi;
uint64_t rbp;
uint64_t rsp;
uint64_t rip;
} reg_t;//register type
reg_t reg;
#endif
mmu.h
#ifndef _MMU_
#define _MMU_
// mmu:memory management unit 内存管理单元
// 实现虚拟地址到物理地址的翻译
#include <stdint.h>
uint64_t va2pa(uint64_t vaddr);
#endif
mmu.c
#include "cpu/mmu.h"
#include "memory/dram.h"
uint64_t va2pa(uint64_t vaddr)
{
return vaddr % MM_LEN;
}
第二部分:内存
物理内存可以看作一个固定长度的数组,指令可以可以看作是操作符+操作数1+操作数2的状态机。
instruction.h
#ifndef _INSTRUCTION_
#define _INSTRUCTION_
#include <stdlib.h>
#include <stdint.h>
#define NUM_INSTRTYPE 30 //OP的数量
typedef enum OP
{
mov_reg_reg, //0
mov_reg_mem, //1
mov_mem_reg, //2
push_reg, //3
pop_reg, //4
call, //5
ret, //6
add_reg_reg //7
} op_t;
typedef enum OD_TYPE
{
EMPTY,
IMM, //立即数寻址:Imm
REG, //寄存器寻址:R[reg]
MM_IMM, //绝对寻址 :M[Imm]
MM_REG, //间接寻址:M[R[reg]]
MM_IMM_REG, //(基址+偏移量)寻址:M[Imm+R[reg]]
MM_REG1_REG2, //变址寻址:M[R[reg1]+R[reg2]]
MM_IMM_REG1_REG2, //变址寻址:M[Imm+R[reg1]+R[reg2]]
MM_REG2_S, //比例变址查询:M[R[reg]*S]
MM_IMM_REG2_S, //比例变址查询:M[Imm+R[reg]*S]
MM_REG1_REG2_S, //比例变址查询:M[R[reg1]+R[reg2]*S]
MM_IMM_REG1_REG2_S //比例变址查询:M[Imm+R[reg1]+R[reg2]*S]
} od_type_t;
typedef struct OD
// 这是对操作数的模拟
{
od_type_t type;
int64_t imm; //立即数
int64_t scal; //乘数
uint64_t *reg1; //寄存器1
uint64_t *reg2; //寄存器2
// 最复杂的是imm(reg1,reg2,scal)
} od_t;
typedef struct INSTRUCT_STRUCT
// 这是对指令的模拟
{
op_t op; // 操作符operator 例如mov push ..
od_t src; // 操作数operand
od_t dst; // 操作数operand
char code[100];
} inst_t;
typedef void (*handler_t)(uint64_t,uint64_t); //handler是void*(uint64_t,uint64_t)的函数指针
handler_t handler_table[NUM_INSTRTYPE]; //函数指针数组
void init_handler_table(); //对指令集初始化
void instruction_cycle();//指令周期
void add_reg_reg_handler(uint64_t src, uint64_t dst);
void mov_reg_reg_handler(uint64_t src, uint64_t dst);
#endif
instruction.c
// 实现译码.
#include "memory/instruction.h"
#include "cpu/mmu.h"
#include "cpu/register.h"
#include "memory/instruction.h"
#include <stdio.h>
static uint64_t decode_od(od_t od)
{
if (od.type == IMM)
{
return *((uint64_t*)&od.imm );
}
else if (od.type == REG)
{
return (uint64_t)od.reg1;
}
else
{
// main memory
uint64_t vaddr = 0;
if (od.type == MM_IMM)
{
vaddr = od.imm;
}
else if (od.type == MM_REG)
{
vaddr = *(od.reg1);
}
else if (od.type == MM_IMM_REG)
{
vaddr = od.imm