What & How & Why

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录前一修订版
后一修订版
前一修订版
cs:comp_n_arch:courses:fnti_i:week_4 [2025/05/09 11:50] – [Iteration] codingharecs:comp_n_arch:courses:fnti_i:week_4 [2025/05/11 03:11] (当前版本) – [实例:keyboard] codinghare
行 406: 行 406:
     0;JMP     0;JMP
 </code> </code>
 +<WRAP center round box 100%>
 +  * 推荐先写伪代码,再翻译为 HACK program
 +  * 测试推荐使用 track table:跟踪每个迭代中每个值的变化,看是否符合预期
 +</WRAP>
 +===Pointers===
 +array 的形式在机器语言中是不存在的。取而代之的是,array 是以起始地址 + 偏移量的形式来进行访问的。我们将这种通过地址进行访问的形式称为指针(//Pointer//)。
 +实现上,我们会通过更新 A 来得到其对应的 M,再对 M进行更新操作。下面是一个例子:
 +<code cpp>
 +// 需要模拟的代码
 +n = 10;
 +for (i = 0; i < n; ++i)
 +{
 +    arr[i] = -1;
 +}
 +</code>
 +<code bash>
 +# 初始化
 +# 假设 array arr 的起始地址为 100
 +
 +# 初始化 arr
 +@100
 +D = A
 +@arr
 +M = D # 将 arr 的初始值设为 100
 +
 +# 初始化 n
 +@10
 +D = A 
 +@n
 +M = D # 将 n 的初始值设为 10
 +
 +# 初始化 i
 +@i
 +M = 0 # 将 i 的初始值设为 0
 +
 +# 开始进入循环
 +(LOOP)
 +    # 如果 i == n,循环结束
 +    @i
 +    D = M
 +    @n
 +    D = D - M # D 是判断条件,存储 i - n 的结果
 +    
 +    @END
 +    D;JEQ # i == n 则跳转至 END
 +    
 +    # 如果不相等,则循环继续
 +    
 +    # 获取 arr 的起始地址
 +    @arr
 +    D=M
 +    @i
 +    A = D+M # 计算偏移量,也就是指针的地址 arr + i
 +    # 更新对应的地址
 +    # 注意此时的 M 已经变化了,不再是 i 对应的寄存器,而是 A 对应的寄存器
 +    # A 更新后访问 M 的 side effect: M 会与 RAM[A] 关联
 +    M = -1 # RAM[arr+i] = -1
 +    
 +    @i
 +    M = M + 1 # ++i
 +    
 +    @LOOP # 循环结束
 +    0;JMP
 +
 +(END)
 +    @END
 +    0;JMP
 +</code>
 +===Input & Output===
 +这部分主要实现的是:
 +  * Screen
 +  * Keyboard
 +{{ :cs:comp_n_arch:courses:fnti_i:hack_memory_distribution.svg?150 |}}
 +==实例:drawing an rectangle==
 +  * 题目的要求是:画一个自定义 row(''n'') 的,宽度(列)为 16 bits 的矩形。
 +首先从高级语言考虑一下这个代码的循环:
 +<code cpp>
 +for (i=0; i < n; ++i)
 +{
 +    // print first black pixels at he beginning of row i
 +}
 +</code>
 +接下来以更机器语言的方式思考该伪代码:
 +<code bash>
 +# init
 +addr = SCREEN # 写入的首地址是 SCREEN 对应的内存起始点
 +n = RAM[0] # 从 R0 中获取 n 的初始值
 +i = 0 
 +
 +# Looping
 +LOOP:
 +    if i > n goto END # 循环结束条件是 i > n
 +    # draw pixels
 +    RAM[addr] = -1 # -1的二进制表示是 1111111111111111
 +    # update status
 +    addr += 32 # 换行,由于屏幕宽度是 512,每一行需要 32 个寄存器才可以完全表示,因此换行是直接去第 33 个寄存器
 +    i += 1 # 更新循环条件
 +    goto LOOP
 +    
 +END:
 +    goto END
 +</code>
 +实现如下:
 +<code bash>
 +@SCREEN 
 +D = A
 +@addr # 使用 SCREEN 地址初始化 addr, 16384 号寄存器
 +M = D
 +@R0
 +D = M
 +@n
 +M = D # 使用 R0 内容初始化 n
 +@i
 +M = 0 # 初始化 i 为 0
 +
 +(LOOP)
 +    @i
 +    D = M
 +    @n
 +    D = D - M
 +    @END
 +    D;JGT # 如果 i > n, 结束循环
 +
 +    @addr
 +    A = M 
 +    M = -1 # RAM[addr] = 1111 1111 1111 1111
 +
 +    # 更新循环状态
 +    @i 
 +    M = M + 1
 +
 +    @32
 +    D = A # 注意,所有的常量都需要用 A 类寄存器获取
 +    @addr 
 +    M = M + D
 +    
 +    @LOOP
 +    0;JMP
 +
 +(END)
 +    @END
 +    0;JMP
 +</code>
 +==keyboard==
 +  - 读取 RAM[24576] 内的内容
 +  - 如果内容为 ''0'' ,那么没有键被按下
 +  - 否则,搜寻对应值的 key 值