计算机系统要素:第七章 虚拟机I:堆栈运算
2014-09-05 10:30
274 查看
这一章的项目和第六章类似,都是用高级语言实现文本翻译的过程。但是,这一章对于VM语言和汇编语言的理解要求较上一章要高得多。所以这一章的学习要点在于,充分理解VM语言实现过程中计算机内存所做的每一个步骤。
HACK机器语言要点复习:
1,@X的意义为把X存入A寄存器,M代表的是Memory[A],即A所代表的地址中所存的数值,A=MM=D两句并列意味着将D中数据存入Memory[A],这是这一章中用得最多的逻辑语句。
2,在实现eq,gt,lt时,需要用汇编语言实现If的选择功能,这里需要用到两个lable,一个有条件jump,一个无条件jump,代码实现为:
学习步骤:
1,按照书中7.5所推荐的实现顺序依次实现5个vm文件的转化。
2,对于每一个文件,先在VMEmulator中运行.vm文件和xxxxVME.tst,通过观察其每一步是如何实现的,深入理解VM语言中push,pop和各个参数的实际意义。
3,自己手写相关的HACK机器语言代码,一定要从简到繁,从push constant这种最简单的语句开始一步一步来。
4,将转换过程用高级语言实现,测试并修改
注意点:
1,第七章中的机器语言和第六章中的机器语言在结构上略有不同,这一章中的语言更加向高级语言靠拢,在有些地方显得“啰嗦”,例如,push constant 7这么一句话,需要@7 D=A @SP A=M M=D @SP M=M+1这么多汇编语言来实现,但是其中每一句话都是有意义的,所以一定要理解每一句VM语言究竟做了哪些事。
2,因为一个vm文件中可能会同时出现许多eq,lt这样的涉及jump的语句,如果每一个lable都相同的话,那么lable就会产生重复冲突,如
@Lable
…
(lable)
…
@lable
…
(lable)
当机器到达第一个@lable点时,就会跳到最后一处(lable)。为了避免这种情况,需要给不同的lable依次加上编号,如lable1, lable2,这儿可以使用定义全局变量来实现。
3,翻译pop segment index的过程中,首先需要获取segment中存储的地址,然后将index加在这个地址上,得到目标地址。最后把当前SP所指向的地址中的值弹入这个目标地址。这个过程是无法用机器语言直接实现的,因为当中涉及两次调用寄存器D。唯一的解决方案就是在翻译过程中用index控制循环语句,让其自动添加index次A=A+1,这样的话就免去了多次调用D寄存器的困难。
Vmtranslator.py,Parser.py这两个文件的实现和第六章类似
Vmtranslator.py
Parser.py
CodeWriter是实现翻译过程的核心文件
CodeWriter.py
HACK机器语言要点复习:
1,@X的意义为把X存入A寄存器,M代表的是Memory[A],即A所代表的地址中所存的数值,A=MM=D两句并列意味着将D中数据存入Memory[A],这是这一章中用得最多的逻辑语句。
2,在实现eq,gt,lt时,需要用汇编语言实现If的选择功能,这里需要用到两个lable,一个有条件jump,一个无条件jump,代码实现为:
// Compare R1=R2 set result in R3 @SP M=M-1 A=M D=M @SP M=M-1 A=M D=D-M @RET_TRUE D;JEQ D=0 // need to return False @CONTINUE 0;JMP (RET_TRUE) D=-1 // need to return True (CONTINUE) @SP A=M M=D @SP M=M+1
学习步骤:
1,按照书中7.5所推荐的实现顺序依次实现5个vm文件的转化。
2,对于每一个文件,先在VMEmulator中运行.vm文件和xxxxVME.tst,通过观察其每一步是如何实现的,深入理解VM语言中push,pop和各个参数的实际意义。
3,自己手写相关的HACK机器语言代码,一定要从简到繁,从push constant这种最简单的语句开始一步一步来。
4,将转换过程用高级语言实现,测试并修改
注意点:
1,第七章中的机器语言和第六章中的机器语言在结构上略有不同,这一章中的语言更加向高级语言靠拢,在有些地方显得“啰嗦”,例如,push constant 7这么一句话,需要@7 D=A @SP A=M M=D @SP M=M+1这么多汇编语言来实现,但是其中每一句话都是有意义的,所以一定要理解每一句VM语言究竟做了哪些事。
2,因为一个vm文件中可能会同时出现许多eq,lt这样的涉及jump的语句,如果每一个lable都相同的话,那么lable就会产生重复冲突,如
@Lable
…
(lable)
…
@lable
…
(lable)
当机器到达第一个@lable点时,就会跳到最后一处(lable)。为了避免这种情况,需要给不同的lable依次加上编号,如lable1, lable2,这儿可以使用定义全局变量来实现。
3,翻译pop segment index的过程中,首先需要获取segment中存储的地址,然后将index加在这个地址上,得到目标地址。最后把当前SP所指向的地址中的值弹入这个目标地址。这个过程是无法用机器语言直接实现的,因为当中涉及两次调用寄存器D。唯一的解决方案就是在翻译过程中用index控制循环语句,让其自动添加index次A=A+1,这样的话就免去了多次调用D寄存器的困难。
Vmtranslator.py,Parser.py这两个文件的实现和第六章类似
Vmtranslator.py
#!/usr/bin/python import sys,os import Parser import CodeWriter filename=sys.argv[1] rfile = open(filename,'r') wfile = CodeWriter.setFileName(filename) wfile.write('@256\nD=A\n@SP\nM=D\n') line=Parser.advance(rfile) flag=Parser.hasMoreCommands(line) while flag: while line == '\n' or line.startswith('//'): line=rfile.readline() ctype=Parser.commandType(line) if ctype == 'C_ARITHMATIC': attribute1=Parser.arg1(line).strip() CodeWriter.writeArithmatic(wfile,attribute1) elif ctype in ('C_PUSH','C_POP'): attribute1=Parser.arg1(line).strip() attribute2=Parser.arg2(line).strip() CodeWriter.writePushPop(wfile,ctype,attribute1,attribute2,filename) line=Parser.advance(rfile) flag=Parser.hasMoreCommands(line) rfile.close() CodeWriter.Close(wfile)
Parser.py
#!/usr/bin/python Arith=('add','sub','neg','eq','gt','lt','and','or','not') def hasMoreCommands(line): if not line: return 0 else: return 1 def advance(rfile): line=rfile.readline() return line def commandType(line): if line.find('push')>=0: return 'C_PUSH' elif line.find('pop')>=0: return 'C_POP' elif line.strip() in Arith: return 'C_ARITHMATIC' def arg1(line): if commandType(line) is 'C_ARITHMATIC': return line.strip() else: spline=line.split(' ') return spline[1] def arg2(line): if commandType(line) in ('C_POP','C_PUSH','C_FUNCTION','C_CALL'): spline=line.split(' ') return spline[2]
CodeWriter是实现翻译过程的核心文件
CodeWriter.py
#!/usr/bin/python import sys,os import Parser CODEFLAG1=0 CODEFLAG2=0 def setFileName(filename): filetuple=os.path.splitext(filename) wfile = open(filetuple[0]+'.asm','w') return wfile def writeArithmatic(wfile,command): global CODEFLAG1,CODEFLAG2 if command == 'add': wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=D+M\n@SP\nM=M+1\n') elif command == 'sub': wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=M-D\n@SP\nM=M+1\n') elif command == 'neg': wfile.write('@SP\nM=M-1\nA=M\nM=-M\n@SP\nM=M+1\n') elif command == 'and': wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=D&M\n@SP\nM=M+1\n') elif command == 'or': wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=D|M\n@SP\nM=M+1\n') elif command == 'not': wfile.write('@SP\nM=M-1\nA=M\nM=!M\n@SP\nM=M+1\n') elif command == 'eq': wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nD=D-M\n@RET_TRUE'+str(CODEFLAG1)+'\ \nD;JEQ\nD=0\n@CONTINUE'+str(CODEFLAG2)+'\n0;JMP\n(RET_TRUE'+str(CODEFLAG1)+')\nD=-1\ \n(CONTINUE'+str(CODEFLAG2)+')\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') CODEFLAG1+=1 CODEFLAG2+=1 elif command == 'gt': wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nD=M-D\n@RET_TRUE'+str(CODEFLAG1)+'\ \nD;JGT\nD=0\n@CONTINUE'+str(CODEFLAG2)+'\n0;JMP\n(RET_TRUE'+str(CODEFLAG1)+')\nD=-1\ \n(CONTINUE'+str(CODEFLAG2)+')\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') CODEFLAG1+=1 CODEFLAG2+=1 elif command == 'lt': wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nD=M-D\n@RET_TRUE'+str(CODEFLAG1)+'\ \nD;JLT\nD=0\n@CONTINUE'+str(CODEFLAG2)+'\n0;JMP\n(RET_TRUE'+str(CODEFLAG1)+')\nD=-1\ \n(CONTINUE'+str(CODEFLAG2)+')\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') CODEFLAG1+=1 CODEFLAG2+=1 def writePushPop(wfile,command,segment,index,filename): if command == 'C_PUSH': if segment == 'constant': wfile.write('@'+index+'\nD=A\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') elif segment == 'local': wfile.write('@LCL\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') elif segment == 'argument': wfile.write('@ARG\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') elif segment == 'this': wfile.write('@THIS\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') elif segment == 'that': wfile.write('@THAT\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') elif segment == 'pointer': if index == '0': wfile.write('@3\n') elif index == '1': wfile.write('@4\n') wfile.write('D=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') <span style="white-space:pre"> </span>elif segment == 'static': <span style="white-space:pre"> </span>staticname=filename.strip('.vm')+'.'+index <span style="white-space:pre"> </span>wfile.write('@'+staticname+'\nD=A\nA=D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') elif command =='C_POP': if segment == 'local': wfile.write('@SP\nM=M-1\nA=M\nD=M\n@LCL\nA=M\n') for i in range (0,int(index)): wfile.write('A=A+1\n') wfile.write('M=D\n') if segment =='argument': wfile.write('@SP\nM=M-1\nA=M\nD=M\n@ARG\nA=M\n') for i in range (0,int(index)): wfile.write('A=A+1\n') wfile.write('M=D\n') if segment == 'this': wfile.write('@SP\nM=M-1\nA=M\nD=M\n@THIS\nA=M\n') for i in range (0,int(index)): wfile.write('A=A+1\n') wfile.write('M=D\n') if segment == 'that': wfile.write('@SP\nM=M-1\nA=M\nD=M\n@THAT\nA=M\n') for i in range (0,int(index)): wfile.write('A=A+1\n') wfile.write('M=D\n') if segment == 'pointer': wfile.write('@SP\nM=M-1\nA=M\nD=M\n') if index == '0': wfile.write('@3\n') else: wfile.write('@4\n') wfile.write('M=D\n') <span style="white-space:pre"></span><span style="white-space:pre"> </span>if segment == 'static': <span style="white-space:pre"> </span>staticname=filename.strip('.vm')+'.'+index <span style="white-space:pre"> </span>wfile.write('@SP\nM=M-1\nA=M\nD=M\n@'+staticname+'\nM=D\n') def Close(wfile): wfile.close()
相关文章推荐
- 计算机系统要素:第八章 虚拟机II 程序控制
- 第七章:虚拟机1:堆栈运算
- 深入理解计算机系统-课后习题-2.13-bis和bic命令实现或和异或运算
- 深入理解计算机系统第七章读书笔记
- 计算机系统要素:第五章 计算机体系结构
- 深入理解计算机系统(第二版) 家庭作业 第七章
- 深入理解计算机系统(2.5)---二进制整数的加、减法运算(重要)
- 深入理解计算机系统-----之 第七章 链接
- 基于逻辑运算的计算机系统
- 深入理解计算机系统(2.6)---二进制整数的乘、除法运算(重要)【困难度高】
- 计算机系统要素:硬件描述语言HDL简介
- 计算机系统要素 project1
- 深入理解计算机系统 - 整型运算
- 计算机系统要素:第十一章 编译器:代码生成
- 计算机系统要素:第十二章 操作系统
- 计算机系统要素:第六章 Part1 汇编编译器(nonsymbol)
- 堆栈的应用--计算机对运算表达式编译
- 读书笔记:深入理解计算机系统 第七章
- 计算机系统要素 从零开始构建现代计算机
- 深入理解计算机系统(2.8)---浮点数的舍入,Java中的舍入例子以及浮点数运算(重要)