Marie.js CPU仿真器学习笔记&仿真器简单教程

传送门: ① Marie使用手册

0、内容声明

        本文章内容源于Marie.js使用手册,代码摘自Marie.js的样例代码,若有错误,敬请斧正。

1、Marie.js简介

        这是一个非常精简易用的CPU仿真器,笔者曾自己用MFC写过类似的东西,但是效果和这个差了十万八千里。该仿真器是一个16位机,有三个通用寄存器,和一个只有16个指令的指令集,内存配置只有4K,不过这足够初学者研究一段时间了,但是它非常简单易用,满足了各种常用的X86架构和ARM架构处理器的指令。

2、配置介绍

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWWluZ19MYW5n,size_18,color_FFFFFF,t_70,g_se,x_16

         如上图,共7个寄存器,意义如下:

AC 寄存器:通用寄存器、累加器,保存中间过程、累加、暂存等功能。

PC 寄存器:程序计数器,指向内存中下一条要执行的指令

MAR 寄存器:内存访问寄存器,简简单单的与地址线相连

MBR 寄存器:内存缓冲寄存器,简简单单的与数据线相连

IR 寄存器:指令寄存器,存放当前在执行的指令

Out、In寄存器:通用寄存器,I/O会使用这两个寄存器,不是用I/O时,可以当做通用寄存器用

        7个寄存器和内存共8中调取数据的方式,正好可以使用3位表示。其中,MAR和PC因为和内存地址交互,只有12位,其余5个寄存器和内存中的字均为16位。

3、指令集

数学逻辑运算

Add X将X作为操作数,与AC相加,并保存到AC中gif.latex?AC%5Cleftarrow%20AC+X
Subt X将X作为操作数,用AC减之,并保存到AC中gif.latex?AC%5Cleftarrow%20AC-X
Addl X将X作为操作数的指针,与AC相加,并保存到AC中gif.latex?AC%5Cleftarrow%20AC+%5BX%5D
Clear将AC清零gif.latex?AC%5Cleftarrow%200

 与内存的数据交换

Load X从内存地址X中取数存值ACgif.latex?AC%5Cleftarrow%20X
Store X将AC存入地址为X的内存中gif.latex?X%5Cleftarrow%20AC
Loadl X将X处存储的内容作为指针,获取操作数存入ACgif.latex?AC%5Cleftarrow%20%5BX%5D
Storel X将X处存储的内容作为指针,将AC的值存入指向的内存gif.latex?%5BX%5D%5Cleftarrow%20AC

 I/O

Input要求用户输入一个值替换当前AC----
Output将AC的值输出----

 分支

Jump XPC跳转到X的地址

----

Skipcond(C)基于AC和C跳过下一条语句的执行

跳转条件:

C=000&&AC<0

C=400&&AC=0

C=800&&AC>0

 子程序

JnS X将PC存至X的地址并且跳转至X+1

gif.latex?X%5Cleftarrow%20PC

Jump X+1

Jumpl XPC跳转到X指向的地方gif.latex?PC%5Cleftarrow%20X

         后续单有一部分说明子程序/子函数的执行过程

 程序终止

Halt程序终止----

共16个指令,可以用4位表示

4、寻址方式

        按照指令集中的指令名称,可以发现有部分指令有两种形式,即不带‘l'的形式和带'l'的形式。如:

AddAddl
LoadLoadl
StoreStorel
JumpJumpl

        左侧的一列为不含‘l’的指令,右侧为含‘l’的指令,左侧直接将存储空间X中存储的内容作为操作数,为直接寻址;右侧将存储空间X中存储的内容作为指针,使用指针寻找操作数,为间接寻址。

        类似的直接寻址指令还有subt等;类似的间接寻址指令还有JnS等。

5、简单代码示例与注释

加法代码

//输入X和Y,并存储至内存
Input
Store X
Input 
Store Y

//AC中当前存储的是Y,所以Add X即可完成加法过程
Add X
Output
Halt

//声明内存空间
X, DEC 0
Y, DEC 0

HelloWorld

LOOP, Load PTR
// 输出字符
LoadI PTR
Output

// 字符串指针自增
Load PTR
Add ONE
Store PTR

// 计数器自增
Load CTR
Add ONE
Store CTR

// 检查计数个数,是否完全输出字符串
Subt WORDS
Skipcond 400
Jump LOOP
Halt

// 数据空间
ONE, DEC 1
CTR, DEC 0
WORDS, DEC 12

// 初始化指针指向字符串
PTR, ADR S

// "Hello World!"
S, HEX 48
HEX 45 
HEX 4C
HEX 4C
HEX 4F
HEX 20
HEX 57
HEX 4F
HEX 52
HEX 4C
HEX 44
HEX 21

6、子程序/子函数代码过程

先上代码

//调用子函数
JnS func
Halt
func, HEX 000 // 此处保存要返回的地址
    ...
    Jumpl func

        这段代码中,func是一个函数的入口地址,JnS将PC指向func的下一字,跳过的一字保存这跳之前指针的下一位置,跳之前语句为JnS,那么下一个位置(本程序中为Halt),也就是函数返回之后要继续执行的位置。

        那么代码是如何返回的呢?func函数执行完毕后,Jumpl将func作为指针间接寻址,将其地址赋值给PC,本程序中也就是Halt语句的地址被赋值给了PC,那么程序就可以正常返回了!

7、其它注意事项        

        Marie中对数据段和代码段没有加以区分,为了避免将数据当作代码执行,应当将数据放置于代码之后,但是有特殊情况,如子程序中,程序的返回地址会放在程序开头的位置,也正是因为这样的机制,可以让如此精简的Marie可以使用子函数的功能。

        关于内存中“数据段”中数据的常见表示格式,见下表:

DEC十进制
HEX十六进制
ADR地址标签(一般做指针用)

         内存的4K容量为内存中字的数量,共4K个16位的字,实际内存为8KB。

        推荐的代码格式:

        先数据再代码

Jump begin

//此为数据段
    ...
//数据段结束

begin,
//此为主程序
    ...
    Halt
//主程序结束

func1,Hex 000
//子程序1
    ...
    Jumpl func1
//子程序1结束

...

 先代码再数据


//此为主程序
...
Halt
//主程序结束

func1,Hex 000
//子程序1
    ...
    Jumpl func1
//子程序1结束

...

//此为数据段
    ...
//数据段结束

每个子函数前有所需数据

Jump begin

//主程序数据段

begin,
//此为主程序
    ...
    Halt
//主程序结束


//子程序1数据段

func1,Hex 000
//子程序1
    ...
    Jumpl func1
//子程序1结束


...

        关于注释的问题:单斜线'/'即可完成整行的注释,上述代码中写双斜线是为了满足CSDN的C++代码的格式要求,如果个人习惯双斜线,也可以使用

  • 11
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值