31、P1 W4 U4.10 总结、作业4答案

作者: shazizm | 来源:发表于2019-08-10 19:44 被阅读0次

    视频:
    如果本次课程对应的 Coursera 的视频打不开,可以点击下面链接
    P1W4U4.10 - Perspectives

    1. Hack的机器语言,和普通我们使用的电脑有什么区别呢?
      Hack是专为这个教学用的,它的机器语言的指令非常精简,但能清晰传达计算机核心概念。普通电脑为了提高效率会有很多提高计算性能的设计,比如会把 乘法 和 除法 从硬件层面 设计出对应的指令。Hack也可以实现乘法和除法,这要在之后的 nand2tetris Part2 软件部分涉及。

    2. 取地址,然后存数。其它电脑的机器语言也是这样操作吗?
      一般都会这样。普通电脑不像Hack指令,只有16位。有的位数多的,是可以在一个指令里完成上面两步操作。

    3.Hack的机器语言跟其他电脑的机器语言 语法上区别大吗?
    还好,自己看吧

    例如
    Hack:D = D+M
    其它:ADD D ,M
    又例如
    Hack:D = M
    其它:LOAD D,M

    1. 真的有必要写这些机器语言吗?
      一般还真不写这种底层的机器语言,之后有了编译器就都写高级语言了,然后用编译器和汇编器,来翻译成机器语言。

    作业:

    Mult.asm
    Fill.asm

    写作业前。我基本忘了这周都讲啥了。回顾一下

    1、回顾工具:


    CPU Emulator CPU 仿真器 。跟之前的硬件模拟器放在一个目录里nand2tetris/tools/CPUEmulator.xxx,Mac、Linux用户找到CPUEmulator.sh运行。Windows用户双击CPUEmulator.bin

    2、回顾U4.3(A指令和C指令)

    3、回顾U4.6(D、A、M、寄存器操作)
    代码最后要有无条件循环,
    @END
    0;JMP

    4、回顾U4.7
    虚拟寄存器:R0-R15、SCREEN、KBD
    符号LABEL:()定义,@使用

    5、回顾U4.8
    指针的初始化,和循环用法。

    6、工作流:


    工作流

    7、作业提示:

    能用 “别名” 和 变量 表示存储器的“门牌号”。就千万不要用具体的地址数字。
    别名 和 变量,起名字的时候要能让人看懂啥意思。
    变量用小写。
    别名用大写。
    用缩进?使排版美观。
    写汇编前,可以打打草稿(伪代码)。

    一、Mult.asm

    写一个程序 使 R0 乘 R1 的结果写入 R2

    提示:

    循环 和 加法。
    R0*R1=R2
    循环R1次相加

    既然需要 循环,可参考回顾U4.8

    1、初始化部分:

    (R0=3,R1=4,R2=0)

    // 假设做一个 R0*R1 => 3*4 
    // R0 = 3
    @3
    D=A
    @R0
    M=D //测试发现R0、R1、寄存器没法直接赋值(0和1除外)。
    
    // R1 = 4
    @4 
    D=A
    @R1
    M=D
    
    // R2 = 0
    @R2
    M=0
    
    // 记录当前循环次数
    @i 
    M=0
    

    2、循环加部分:

    (LOOP)
      // 判断 i 是否已循环 R1 次
      @i
      D=M
      @R1
      D=D-M
      @END
      D;JEQ //如果判读i-R1=0,那么就跳转到END结束for循环。
    
      // 执行循环操作( R2 + R0)
      @R0
      D=M
      @R2
      M=D+M 
    
      // 记录循环次数 ( i 加 1)  
      @i
      M=M+1
    
      @LOOP
      0;JMP //无条件跳转
    
    (END) //程序结束
      @END
      0;JMP
    

    上面代码,可以点击单步运行,一步步查看计算结果。

    也可以把 Mult.asm 修改成可测试代码(把R0和R1的初始化去掉):

    3、最终可测试代码:

    // This file is part of www.nand2tetris.org
    // and the book "The Elements of Computing Systems"
    // by Nisan and Schocken, MIT Press.
    // File name: projects/04/Mult.asm
    
    // Multiplies R0 and R1 and stores the result in R2.
    // (R0, R1, R2 refer to RAM[0], RAM[1], and RAM[2], respectively.)
    
    // Put your code here.
    //初始化
    
    // R0 赋值
    //@3
    //D=A
    //@R0
    //M=D
    
    // R1 赋值
    //@4
    //D=A
    //@R1
    //M=D
    
    // R0 和 R1 不用赋值,跑 Mult.tst 测试代码的时候会赋值
    
    @R2
    M=0
    
    @i
    M=0
    //循环加(乘法)
    (LOOP)
      // 判断 i 是否已循环 R1 次
      @i
      D=M
      @R1
      D=D-M
      @END
      D;JEQ //如果判读i-R1=0,那么就跳转到END结束for循环。
    
      // 执行循环操作( R2 + R0)
      @R0
      D=M
      @R2
      M=D+M 
    
      // 记录循环次数 ( i 加 1)  
      @i
      M=M+1
    
      @LOOP
      0;JMP //无条件跳转
    
    (END) //程序结束
      @END
      0;JMP
    
    

    测试:
    Mult.tst如果报错说找不到“Mult.hack”。就改成“Mult.asm”。

    // This file is part of www.nand2tetris.org
    // and the book "The Elements of Computing Systems"
    // by Nisan and Schocken, MIT Press.
    // File name: projects/04/mult/Mult.tst
    
    load Mult.hack, //修改成 load Mult.asm(要被测试的文件名)
    

    测试成功。



    二、Fill.asm

    写一个程序 当键盘上,任意键按下时,就黑屏。抬起键,就白屏。

    提示:写一个循环,一直监听键盘,然后对应做出反应。黑屏,就是把所有屏幕映射区的寄存器,全部写-1。

    1、监听键盘:

    写一个无限循环,读KBD寄存器,判断如果不是0,就白屏。(貌似每次都循环写白屏,比较浪费计算资源。可以设置一个标志寄存器。来记录当前屏幕状态)

    //循环
    (LOOP)
    
      ...读KBD寄存器
    
      @LOOP
      0;JMP
    
    //读KBD寄存器
    @KBD
    D=M
    @BLACK
    D;JNE //不等于0,跳转到@BLACK
    @WHITE
    0;JMP //等于0,跳转到@WHITE
    
    //设 FLAG = 0 表示 白屏。FLAG = 1 表示 黑屏。
    @FLAG
    M=0
    
    // 初始化屏幕指针
    // 第1步:arr = @SCREEN
    @SCREEN //将SCREEN的寄存器地址 存入D
    D=A 
    @arr //声明一个arr 变量,并将M寄存器对应此变量。
    M=D //将D里的SCREEN地址赋值给arr对应的M寄存器
    
    // 第2步:屏幕:256 行,每行由 32个寄存器 代表。n = 256*32 = 8192
    @8192
    D=A
    @n
    M=D
    
    // 第3步:i = 0
    @i
    M=0
    

    2、设置屏幕:

    设置黑,就是循环就是把SCREEN的所有寄存器,的8bit位都赋值1。也就是给 M = -1。
    设置白,反之,M = 0。

    (BLACK)
      @FLAG
      D=M-1
      @LOOP
      D;JEQ  //如果现在状态是黑,就不再设置屏幕了,跳回LOOP处继续扫描键盘
      //否则,修改FLAG 为1(黑屏)
      @FLAG
      M = 1
      //把i回0
      @i
      M=0
      //然后设置 黑屏
      (SETBLACKLOOP)   
        // 判断 i 是否已循环 n 次
        @i
        D=M
        @n
        D=D-M
        @LOOP //
        D;JEQ //如果判读i-n=0,就代表设置完屏幕颜色了。跳回继续扫描键盘
    
        // 执行循环操作( 赋值 -1)
        @arr
        D=M
        @i
        A=D+M  //如果你看A寄存器被放左边这么使用,那通常就是在做指针操作。
        //上面4行就是在用指针操作来确定要被赋值的M
        M=-1 //执行赋值-1,设置黑屏
    
        // 记录循环次数 ( i 加 1)  
        @i
        M=M+1
    
        @SETBLACKLOOP
        0;JMP //无条件跳转
    
    (WHITE)
      @FLAG
      D=M
      @LOOP
      D:JEQ //如果现在状态是白,就不再设置屏幕了,跳回LOOP处继续扫描键盘
      //否则,修改FLAG 为0(白屏)
      @FLAG
      M = 0
      //把i回0
      @i
      M=0
      //然后设置 白屏
      (SETWHITELOOP)
        // 判断 i 是否已循环 n 次
        @i
        D=M
        @n
        D=D-M
        @LOOP //
        D;JEQ //如果判读i-n=0,就代表设置完屏幕颜色了。跳回继续扫描键盘
    
        // 执行循环操作( 赋值 -1)
        @arr
        D=M
        @i
        A=D+M  //如果你看A寄存器被放左边这么使用,那通常就是在做指针操作。
        //上面4行就是在用指针操作来确定要被赋值的M
        M=0 //执行赋值0 ,设白屏
    
        // 记录循环次数 ( i 加 1)  
        @i
        M=M+1
    
        @SETWHITELOOP
        0;JMP //无条件跳转
    

    3、最终完整代码:

    // This file is part of www.nand2tetris.org
    // and the book "The Elements of Computing Systems"
    // by Nisan and Schocken, MIT Press.
    // File name: projects/04/Fill.asm
    
    // Runs an infinite loop that listens to the keyboard input.
    // When a key is pressed (any key), the program blackens the screen,
    // i.e. writes "black" in every pixel;
    // the screen should remain fully black as long as the key is pressed. 
    // When no key is pressed, the program clears the screen, i.e. writes
    // "white" in every pixel;
    // the screen should remain fully clear as long as no key is pressed.
    
    // Put your code here.
    //初始化FLAG
    //设 FLAG = 0 表示 白屏。FLAG = 1 表示 黑屏。
    @FLAG
    M=0
    
    //初始化 用来循环刷新屏幕寄存器的循环指针
    // 第1步:arr = @SCREEN
    @SCREEN //将SCREEN的寄存器地址 存入D
    D=A 
    @arr //声明一个arr 变量,并将M寄存器对应此变量。
    M=D //将D里的SCREEN地址赋值给arr对应的M寄存器
    // 第2步:屏幕:256 行,每行由 32个寄存器 代表。n = 256*32 = 8192
    @8192
    D=A
    @n
    M=D
    // 第3步:i = 0
    @i
    M=0
    
    // 开始循环扫描键盘
    (LOOP)
    
      //读KBD寄存器
      @KBD
      D=M
      @BLACK
      D;JNE //不等于0,跳转到@BLACK
      @WHITE
      D;JEQ //等于0,跳转到@WHITE
    
      @LOOP
      0;JMP
    
    // 循环设置黑屏 和 白屏
    (BLACK)
      @FLAG
      D=M-1
      @LOOP
      D;JEQ  //如果现在状态是黑,就不再设置屏幕了,跳回LOOP处继续扫描键盘
      //否则,修改FLAG 为1(黑屏)
      @FLAG
      M=1
      //把i回0
      @i
      M=0
      //然后设置 黑屏
      (SETBLACKLOOP)   
        // 判断 i 是否已循环 n 次
        @i
        D=M
        @n
        D=D-M
        @LOOP //
        D;JEQ //如果判读i-n=0,就代表设置完屏幕颜色了。跳回继续扫描键盘
    
        // 执行循环操作( 赋值 -1)
        @arr
        D=M
        @i
        A=D+M  //如果你看A寄存器被放左边这么使用,那通常就是在做指针操作。
        //上面4行就是在用指针操作来确定要被赋值的M
        M=-1 //执行赋值-1,设置黑屏
    
        // 记录循环次数 ( i 加 1)  
        @i
        M=M+1
    
        @SETBLACKLOOP
        0;JMP //无条件跳转
    
    (WHITE)
      @FLAG
      D=M
      @LOOP
      D;JEQ //如果现在状态是白,就不再设置屏幕了,跳回LOOP处继续扫描键盘
      //否则,修改FLAG 为0(白屏)
      @FLAG
      M=0
      //把i回0
      @i
      M=0
      //然后设置 白屏
      (SETWHITELOOP)
        // 判断 i 是否已循环 n 次
        @i
        D=M
        @n
        D=D-M
        @LOOP //
        D;JEQ //如果判读i-n=0,就代表设置完屏幕颜色了。跳回继续扫描键盘
    
        // 执行循环操作( 赋值 -1)
        @arr
        D=M
        @i
        A=D+M  //如果你看A寄存器被放左边这么使用,那通常就是在做指针操作。
        //上面4行就是在用指针操作来确定要被赋值的M
        M=0 //执行赋值0 ,设白屏
    
        // 记录循环次数 ( i 加 1)  
        @i
        M=M+1
    
        @SETWHITELOOP
        0;JMP //无条件跳转
    

    3、测试
    测试成功

    相关文章

      网友评论

        本文标题:31、P1 W4 U4.10 总结、作业4答案

        本文链接:https://www.haomeiwen.com/subject/wgfdjctx.html