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