做数学
所有计算都在寄存器之间进行。算术指令先指定目标,然后是两个它读取的源: 表示 dest = src1 + src2。
算术运算
t2, t0, t1←add
将位置 t0 和 t1 添加到 t2 中。
t0 和 t1,始终按这个顺序。无论正在运行的是加法、减法、乘法、除法还是取余,它们都以相同的形状进入。两个值进入,执行一次运算,一个结果从右侧输出到 t2。 先指定 t2,因为结果就落在那里,这与本课中每条算术指令都遵循的唯一排序规则一致。加法和减法
取两个寄存器中保存的数字,并把它们的和存入第三个寄存器。 对减法做同样的事: 计算 t0 - t1。两条指令都只从寄存器读取。
注册算术
add t2, t0, t1 # t2 = t0 + t1sub t2, t0, t1 # t2 = t0 - t1
需要知道一件事:一个寄存器只能保存 32 位,所以存在上限。如果结果太大而放不下,不会引发错误。该值会悄悄地回绕成非常小的数字,执行继续。日常的值不会达到这个限制,但这个上限值得了解。
要用固定数字代替第二个寄存器,就加上字母 i,它代表立即数: 加上常量 1。没有 subi,所以要减去一个常量,就加上一个负数:。
💡
加的是一个常量。 加的是两个寄存器。混淆这两者是最常见的初学者错误。
乘法和除法
把两个寄存器相乘。 把它们作为整数相除并丢弃小数部分,所以 7 / 2 得到 3。 给出余数,所以 7 % 2 得到 1。除法永远不会导致崩溃。除以零返回 -1。
乘法、除法、余数
mul t2, t0, t1 # t2 = t0 * t1div t2, t0, t1 # t2 = t0 / t1 (整数)rem t2, t0, t1 # t2 = t0 % t1 (余数)
整合
将两个数字相加并输出结果
li t0, 7li t1, 5add t1, t0, t1 # t1 = 7 + 5 = 12mv a0, t1 # 打印服务读取 a0li a7, 1ecallli a7, 10ecall
把 7 加载到 t0。 把 5 加载到 t1。 把它们相加并把 12 写入 t1。 把结果复制到 a0,因为 print 服务总是从 a0 读取它的值。然后 选择 print-integer 服务, 运行它。最后, 和 结束程序。
附加内容:利用移位进行乘法运算
当因数是 2 的幂时,存在比 更快的方法。(逻辑左移)把寄存器的位向左移动,每移动一个位置都会使该值翻倍:移 1 位是乘以 2,移 2 位是乘以 4,移 3 位是乘以 8。移位的开销比乘法小,所以编译器经常使用它。
使用位移进行8的乘法运算
li t0, 5 # 从 5 开始# 左移 3 位 (5 * 2^3 = 5 * 8)sll a0, t0, 3 # a0 = 40li a7, 1 # 打印整数ecallli a7, 10ecall
把 5 放入 t0。 把它的位向左移动三个位置。每个位置都使该值翻倍,所以 5 翻倍三次(5、10、20、40),在 a0 中得到 40。其余部分沿用之前的 print 模式。试着把 3 改成 1 或 2,并在运行前预测结果。
通过移位相乘
5sll a0, t0, 0
×2 →10sll a0, t0, 1
×2 →20sll a0, t0, 2
×2 →40sll a0, t0, 3
0
0
0
0
0
1
0
1
5 左移 0 位仍为 5。
