等GacUI 1.0 release之后,当做完新的parser gen和Gac UI中intellisense的支持之后,写一个专栏,从模拟一台电脑开始,一步一步做到动态语言。
- 拥有固定大小的内存、硬盘空间和显示器,有足够的指令和中断去操作他们,所有缓存都从内存中切割出来。
- 虚拟机启动的时候从硬盘的0位开始加载程序,然后执行。
- 设置好系统堆栈的位置。
- 0-7为非法内存值,此处浪费一点空间。
[8, 1024)
为保留空间,这段空间可以被R/W系列之令随意操作。这段空间的每一个位置都有指定的功能,以后再设计。- 虚拟机加载程序之后,程序会要求在1024之后再保留一段空间被使用。
- 寄存器:r0, r1, f0, f1, s0, s1, i0(当前指令), i1(下一条指令), ef(异常处理帧), en(异常编号),t0(保存所有额外信息)
- 执行i指向的指令的时候,分别
- 译码
- i1指向下一条指令
- 执行译码后的结果
- i1复制进i0
- 每次跳转的时候,i0和i1都会指向同一个值,即跳转目标
- LDI {int64}: 加载一个整数到r0。
- LDF {double}:加载一个浮点数到f0。
- R1, R2, R4, R8, RF4, RF8:把r1指向的内存中的数据按不同的类型写进0号寄存器。
- W1, W2, W4, W8, WF4, WF8:把0号寄存器的内容按不同的类型写进r1指向的内存中。
- I2F:从f0转整形到r0。
- F2I:从r0转浮点到f0。
- SWPI:r0和r1交换。
- SWPF:f0和f1交换。
- ADDS, ADDU, ADDF:加法,结果存放在0号寄存器。
- 还有SUB, MUL, DIV, MOD(没有浮点)
- AND, OR, XOR(无符号整数)
- NEG(*-1)
- REV(^0xFFFFFFFF,无符号整数)
- CS, CU, CF:把0和1号寄存器的数据进行比较,结果写进r0(小于为-1,等于为0,大于为1)。
- C0:把r0与0进行比较,如果不等于0,把r0改写为0xFFFFFFFF。
- JZN:当r0为0的时候,把i1写进r0,跳转到地址(r0+有符号整数r1的结果)。
- JZF:当r0为0的时候,把i1写进r0,跳转到地址(r1)。
- CALL {int64}:利用r0保存的地址信息,在堆栈上开辟足够的空间,并且留出参数那么大的自由空间。空间超出了t0指向的描述的限制则溢出。
- RET:撤销上一次CALL的堆栈分配并返回到CALL指令记录下来的r0地址。如果r0为0xFFFFFFFF,则关机。
- LDS:把s1复制进r0。假设CALL指令为x,那么
[r0, r0+x)
为堆栈的自由空间,可任意修改。 - THRD:把所有寄存器的值保存进t0的描述,把t0改为r0,把t0描述的值复制回所有寄存器,继续运行。
- INIT {int64}:初始化。
- s0设置为可用内存最大值
- r0r1f0f1清0
- 开辟堆栈空间的return address和old s0都为0xFFFFFFFF
- ef为0
- en为-1
- HALT:关机。
- INT {int64}:执行中断。中断号码为指令参数,r0作为附加参数。所有硬件信息都由INT来完成
- ef指向的结构:
|exception handler address|old ef|
- 每次触发异常的时候,都会
- 复制所有寄存器的值
- 如果en不为-1,直接蓝屏
- 把ef指向的异常处理地址保留下来
- POPEF
- 跳转到指定的地址
- LDE:把保存异常信息的地址复制到r0,把异常编号复制到r1。r0指向的结构为
|r0|r1|f0|f1|s0|s1|i0|i1|ef|en|
。 - ERR:抛出6号异常。
- CLRERR:把en设置为-1,结束异常处理。
- THROW:放弃异常处理,执行RET,但是不跳转,重新触发一次异常(从第3步开始)。
- PUSHEF:把地址(i1+有符号整数r0的结果)和其他信息,存放到r1指定的地址中,并把r1复制进ef。
- POPEF:PUSHEF的反向操作。
- 堆栈溢出,无法异常处理,直接蓝屏
- 内存读写越界
- 跳转地址越界
- 非法指令(二进制)
- 整数除0
- 触发异常的时候en不为-1,无法处理异常,直接蓝屏
- 主动抛异常
s1 s0
| |
|free space|return address|old s0|
- 超级简单的多任务单线程操作系统
- 文件系统
- 内存管理(malloc、free)
- 屏幕管理
- 简化后的C语言编译器(外部)