Y86小实验————模块概述

【说明】

              这个Y86小实验 总计 3300行代码,用标准C写的。所以其实在windows上也能编译运行,这一章就来简单讲一下各个模块的作用。

 

【AS汇编器】

             1】address.c

                   用来管理链接地址,其实在这里就是指令应该放在内存什么位置

                   这个模块实现了地址增长,对齐操作,这个模块很简单

      

              2】file_op.c

                    对于文件的操作全在这个模块中,包括初始化文件指针,往反汇编文件或者二进制文件中打印信息等等。

                    这里使用了一个小技巧,就是往文件中打印的时候,函数会返回打印的中途,可能需要重定位的地方的文件偏移值。

                    这样调用者如果发现需要重定位,就可以放心的直接打印,然后接收返回值,保存到重定位表中。

                    其实本质上就是每次打印立即数前都会返回文件偏移,因为只有立即数可能需要重定位(因为汇编中可以用符号来代替立即数)

 

 

              3】line.c

                     这个模块包含了所有对于处理当前汇编行的操作,比如读取下一行,得到该行中的指令部分,分解参数,判断参数类型等等

                     这个模块中主要是字符串处理,至于具体的参数值,或者说寄存器合不合法都不是它的事

                     另外,该模块维护着当前处理的行号

 

 

               4】instr.c

                      这个模块名字取得不太好,其实它和处理指令的具体细节没有关系

                      它只不过包含了一些,忽略空格,忽略注释,查找指定命令的处理函数(后面会讲)并执行的操作。

 

 

               5】symbols.c

                      这个模块负责维护符号表,符号表是一个数组,默认大小是1024,也就是最多只能有1024个符号

                      符号不能重复定义,否则给出错误提示,每当遇到一个以":" 结束的指令,都认为是一个符号,而非指令

                      将其存入符号表,当然还有它的值也一并保存

                      在符号后面是可以跟指令的,比如例子中的 init: 后面就跟着指令

                      所以处理符号的函数在处理完符号后要需要调用一次指令处理命令,将符号后面的字符串当成新的指令解析

 

 

               6】relocat.c

                      这个模块用于符号的重定位,在解析指令的过程中,会遇到指令的参数中出现当前符号表中没有的符号

                      这个符号其实可能是存在在那个指令的下面,只不过还没处理到。。

                      这时候我们就应该将这个信息保存到重定位表中,指明我在处理这个指令的时候,发现了未出现的符号

                      等到文件解析好后所有的符号都保存在符号表中了,这时候就应该根据重定位表,重写刚才的指令的数据部分了

                      当然,重写也就是要往二进制文件和反汇编文件的指定偏移处写数据,在file_op 中提供了相应函数

 

 

                7】y86_asm_instr.c

                       该模块真正包含了所有指令的处理函数。

                       我定义了一个结构体,里面包含有指令的汇编名,指令的机器码代号,指令的处理函数。

                       然后初始化了一个数组,里面包含了所有Y86汇编指令的信息,最后一项为“..”代表结束

                       然后设计了一个函数,可以根据指令名返回对应的处理函数

                       这样,我们就把对指令的具体处理,比如指令需要后面是什么参数,以及指令机器码格式等提了出来,单独在处理函数中

                       在instr 模块中,只需要根据从line 中解析出来的指令名(根本就不需要知道具体是什么),直接传给上边那个函数得到处理函数

                       不用管是哪个指令的处理函数,执行就可以。 

                       寄存器也用的同样的技巧,初始化一个含有寄存器名字,对应机器码的结构体数组,以".." 结束

                       定义一个函数,用寄存器名字直接返回其机器码,没找到寄存器直接返回0XFF

                      这样调用者就无需知道系统到底定义了多少寄存器,也无需知道他们名字,直接从line 提出认为应该是寄存器名字的字符串,用上边函数得到机器码

                      如果得到0XFF  说明用户汇编码书写错误,根据就不存在这个寄存器名字。

 

                   8】AS.c

                        主模块非常简单,初始化文件,循环读取下一行

                        将指令分为3类:空白行,注释行,指令行。

                        分别调用instr中的处理函数就可以了

                        instr 中自己处理掉了空白行和注释行,而指令行,正如上边讲的。。直接根据指令得到处理函数。调用它。

                        这样就把对于指令的处理转移到y86_asm_instr 模块中了。 

 

 

【Y86_SYS迷你虚拟机】

                       1】mm.c

                              这个模块是内存的维护模块,内存其实就是一个1MB大小的unsigned char 数组

                              模块提供了内存读写函数,函数中有边界判错,如果读写出错,就认为是非法内存地址 返回-1

                              另外该模块还提供了读入二进制映像的函数,该函数从传入的文件指针中读取二进制到数组中

                               额外的,读取二进制文件的时也会搞一个内存的备份,用来最后打印(因为打印出的是改动过的内存)

                        2】cpu.c

                              最重要的模块,模块负责维护系统的状态,以及运行指令。

                              和前面对于指令的维护类似,这里也用了数组中得到处理函数并调用的方式。所以框架变得很简单

                              首先由一个run 函数,,只有系统停止的时候才返回,返回值是系统停止的原因

                              HLT表示halt 指令正常停止, ADR表示非法地址 ,INS表示指令执行错误,比如非法指令,非法寄存器等

                              run中循环调用do_nextInstr(),这个函数作用是根据当前PC的值,读取一个字节,并认为是一个指令的机器码

                              用这个字节去获得对应的处理函数,并执行,返回值应和处理函数相同,因为只有处理函数才知道,到底是正常执行还是出错了

                      3】y86_Sys.c

                               这个是主模块,里边首先用用户指定的文件去初始化内存,然后调用run 运行

                               运行好后调用 printReg打印寄存器信息,调用 printMm 打印内存信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值