29、P1 W4 U4.8 HACK编程3(待深入)

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

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

    上节课,我们学会了 判断语句,变量使用,循环判断。
    这节课,讲 指针 和 输入输出



    一、指针 Pointer

    如下图:

    注:for 循环: 是编程里最常用的一种类似上节课最后的循环判断。
    意思就是,设 i = 0,当i < n 时,执行{}里语句(此时i=0),最后 i + 1。然后在去判断 i + 1 后,是否 < n , 如果依然小于n,再去执行{}里语句(此时 i=i+1)。直到大于等于n时,循环退出。

    这个循环判断不是重点(我假设你学过计算机简单的编程,如果不明白,搜索学习一下for循环吧),根据上节课学习的,琢磨一下可以写出来。

    重点是 arr[i],编过程序的知道这是一个数组,也听说过数组的变量名(arr)代表的就是指针。

    那么从最底层的语言,来看看这个指针(下图的arr)是什么工作的。

    用指针实现一个任务

    如下图:老师设计了一个任务来讲解指针的使用。
    任务是将RAM[100]开始往后10个寄存器,都设置成-1。当然我们是通过用指针的方式实现。

    首先

    1.初始化Pointer指针

    初始化分别实现3步:

    // 伪代码 
    arr = 100 
    n = 10 
    i = 0
    // 为什么是这三个,去看for循环的完整语句,这3个是for循环里重要的三个变量
    

    也就是如上图里
    RAM[16] 写入 100,RAM[17] 写入 10,RAM[18] 写入 0。
    (为什么是16、17、18,第六周做汇编器的时候就知道了,总之就是汇编器这么设计的,当然我们写代码时不用关心,这是汇编器自动分配的。)

    对应HACK的汇编语言如下:

    // 初始化Pointer指针
    
    // 第1步:arr = 100
    @100 //将A寄存器 放入100
    D=A 
    @arr //声明一个arr 变量,并将M寄存器对应此变量。
    M=D //将D里的100 赋值给arr对应的M寄存器
    
    // 第2步:n = 10
    @10
    D=A
    @n
    M=D
    
    // 第3步:i = 0
    @i
    M=0
    

    解释:把100存入RAM[arr]。中间用D寄存器传递了一下数值100,另外@arr是汇编器从RAM第16个开始找到的空闲寄存器的“门牌号”,图里就是16,也就是给 RAM[16] 写入100。

    初始化 变量

    2.写循环代码

    这里老师也让停下来。最好自己把最终代码想出来,在和下图左边对比一下。

    这里唯一值得注意的是。在之前我们只用 @value 对 A寄存器操作过。从没有直接 像下图里 红色 A = D + M 这样操作过。

    (LOOP)
      // 判断 i 是否已循环 n 次
      @i
      D=M
      @n
      D=D-M
      @END
      D;JEQ //如果判读i-n=0,那么就跳转到END结束for循环。
    
      // 执行循环操作( 赋值 -1)
      @arr
      D=M
      @i
      A=D+M  //如果你看A寄存器被放左边这么使用,那通常就是在做指针操作。
      //上面4行就是在用指针操作来确定要被赋值的M
      M=-1 //执行赋值-1
    
      // 记录循环次数 ( i 加 1)  
      @i
      M=M+1
    
      @LOOP
      0;JMP //无条件跳转
    
    (END) //程序结束
      @END
      0;JMP
    

    注:在接下来 访问输入输出设备时,就会经常用到指针。

    最终代码



    二、输入输出 Input/Output

    之前讲过 I/O设备的 存储映射,如果忘了,回顾U4.6

    下图给出了 Hack小电脑实际的映射图,当然由老师提前架构设计好的。

    图中可以看出,HACK的RAM里一开始是 16k个寄存器,应该是数据存储区。
    然后紧跟着 8k个寄存器的 屏幕映射区,然后是1个寄存器的键盘映射。

    之前U4.6也提到了,有两个“别名”,方便使用:

    SCREEN = 16384
    KBD = 24576

    在汇编器 预处理时,会把“别名”分别转换成这两个数。

    HACK小电脑RAM 的 功能区域划分

    1.屏幕 Screen

    1.1 屏幕定义:
    256 行,每行由 32个寄存器 代表。
    512 列,
    左上角为 0行0列。

    1.2 设置一个任务:
    写一个程序,加载到CPU Emulator,程序操作屏幕映射存取区,使对应屏幕里显示一个矩形(矩形 长边 50像素,短边16像素)。

    1.3 任务提示:
    画这个矩形就是把 ,前50行 的 第一个 寄存器 全部 设为 -1(-1的二进制等于16个1)

    U4.5 对屏幕操作 有详细说明

    1.4 任务演示:

    课程视频里有一段写好的代码,演示如何画出矩形,之后在详细说明代码。
    从12分10 到 18分55

    代码,加载后会在ROM窗口显示,代码不会完全一样,因为已经被预处理了。也就是那些帮助我们写代码的“别名”都变成数字了。这一步CPUEmulator,提前帮我们预处理了,另外也可以切换显示二进制的机器码。

    如下图 红色箭头标注


    之后在做汇编器Assembler时,都会一步一步实现现在CPUEmulator帮我们先做好的这些预处理 和 编译 的工作

    然后点击 一步步执行,大概到 20行的时候,就会发现 屏幕区域 在第一行 最左侧画出一个 16 像素的横线。


    一步步执行

    点击下图两个红圈处,自动快速动画 执行全部代码,直到画完全部矩形。

    自动快速执行

    还有一种更快的办法,瞬间完成。如下图设置

    无动画瞬间完成

    那么看过演示实际的运行规律,分析一下代码如何写。

    在写汇编程序时,老师建议的最佳实践,是先写出伪代码。如图下图左侧是伪代码。

    1.5 代码分析:

    (指针)初始化设置:
    addr :SCREEN在RAM里的启示“门牌号”
    n:要画的长方形多高(多少行),需要在CPUEmulator执行前,自行在RAM区域设置。

    循环执行:
    然后每行都把 第一个寄存器 设置成 -1 也就是二级制的16个1。
    然后 addr 加 32,找到第二行第一个寄存器,同样 设置成 -1。
    直到循环 n 次,最红画完长方形。

    上图是伪代码。是为了自己在脑子里验证逻辑是否正确。然后人脑翻译成可运行的程序写出来。 一种辅助思考的手段,伪代码可读性更高。但实际上并不能在任何地方执行。就跟写文章,先打个草稿一个意思

    最终 把伪代码 用人工脑力 转成 汇编语言,如下图:

    红色高亮处 体现了 指针的作用。具体代码就不分析了。文章开始指针处已经讲过了

    画长方形 的 汇编程序(左侧是指针初始化部分)(右侧是循环部分)

    2.键盘 Keyboard

    接下来看一下 输入设备 键盘,键盘映射 的 就是一个 单个寄存器。

    RAM中 “门牌号”为 24576 的寄存器,有个“别名” KBD方便我们使用这个数。

    当键盘没有按下时,这个键盘映射的寄存器,就是0

    如果当按住一个键比如 k,那么对应 键盘映射的寄存器就会显示一个 对应这个键的 值,图中是75。

    这个 键 和 值的对应表 在U4.5里也有给出。

    那么某时刻 要想知道 键盘的输入,就是对这个KBD寄存器进行 读操作。

    键盘讲的不多,下节课作业有一个相关的,再去实践代码吧。

    这里我有两个疑问,一个是 物理上,键盘和映射的寄存器如何实现联动?一个是 键 和 值 的对应表,在哪里物理实现的?也许后面两周会说明。





    最后题外话:

    三、编译 compilation

    HACK的汇编程序,是一种 低级语言,对应有高级语言,比如java。

    高级语言 就像上面的 伪代码,可读性更高。

    如果发明出一个高级语言 ,再做出 对应的 编译器 (compiler)。

    这样理论上,我们就只用写 可读性更高的 高级语言(就像我们写伪代码那么容易),然后由 对应的编译器,来帮助我们翻译成 低级语言,例如汇编语言,当然,再然后才是 汇编器 (assembler),翻译成 机器语言 (0101xxx)

    关于 编译器 和 对应Hack汇编语言 的 Hack高级语言,是在nand2tetris的Part2 软件部分讲授

    高级语言 => 编译器 => 汇编语言

    最后老师赞扬了一下 机器语言。

    虽然低级。但却由很简单的东西组成。例如只有A和C两种指令。

    (待深入)

    这两种指令我随便想了想,很大部分由ALU决定。而ALU又是只用一个加法操作 和 与非门自带的逻辑运算组成(好像还有时序 => 时间),加法器也是一个逻辑单元,所有的又都可以用一种“与非门”组成,与非门再抽象是什么?逻辑?,目前抽象总结是 时间 和 逻辑 ,想想真奇妙。







    the simple-minded people are impressed by sophisticated things. the sophisticated people are impressed by simple things.

    相关文章

      网友评论

        本文标题:29、P1 W4 U4.8 HACK编程3(待深入)

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