本 Wiki 开启了 HTTPS。但由于同 IP 的 Blog 也开启了 HTTPS,因此本站必须要支持 SNI 的浏览器才能浏览。为了兼容一部分浏览器,本站保留了 HTTP 作为兼容。如果您的浏览器支持 SNI,请尽量通过 HTTPS 访问本站,谢谢!
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录前一修订版后一修订版 | 前一修订版 | ||
cs:comp_n_arch:courses:fnti_i:week_4 [2025/05/09 11:53] – [Iteration] codinghare | cs:comp_n_arch:courses:fnti_i:week_4 [2025/05/11 03:11] (当前版本) – [实例:keyboard] codinghare | ||
---|---|---|---|
行 410: | 行 410: | ||
* 测试推荐使用 track table:跟踪每个迭代中每个值的变化,看是否符合预期 | * 测试推荐使用 track table:跟踪每个迭代中每个值的变化,看是否符合预期 | ||
</ | </ | ||
+ | ===Pointers=== | ||
+ | array 的形式在机器语言中是不存在的。取而代之的是,array 是以起始地址 + 偏移量的形式来进行访问的。我们将这种通过地址进行访问的形式称为指针(// | ||
+ | 实现上,我们会通过更新 A 来得到其对应的 M,再对 M进行更新操作。下面是一个例子: | ||
+ | <code cpp> | ||
+ | // 需要模拟的代码 | ||
+ | n = 10; | ||
+ | for (i = 0; i < n; ++i) | ||
+ | { | ||
+ | arr[i] = -1; | ||
+ | } | ||
+ | </ | ||
+ | <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 | ||
+ | </ | ||
+ | ===Input & Output=== | ||
+ | 这部分主要实现的是: | ||
+ | * Screen | ||
+ | * Keyboard | ||
+ | {{ : | ||
+ | ==实例:drawing an rectangle== | ||
+ | * 题目的要求是:画一个自定义 row('' | ||
+ | 首先从高级语言考虑一下这个代码的循环: | ||
+ | <code cpp> | ||
+ | for (i=0; i < n; ++i) | ||
+ | { | ||
+ | // print first black pixels at he beginning of row i | ||
+ | } | ||
+ | </ | ||
+ | 接下来以更机器语言的方式思考该伪代码: | ||
+ | <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 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 | ||
+ | </ | ||
+ | ==keyboard== | ||
+ | - 读取 RAM[24576] 内的内容 | ||
+ | - 如果内容为 '' | ||
+ | - 否则,搜寻对应值的 key 值 |