计算机系统要素-从零开始构建现代计算机--第四章,03-HACK机器语言示例

第四章,03-HACK机器语言示例

学完前一篇的机器语言规范,仍然是懵圈的,对于作业无从下手,还好视频中有一些示例,摘抄到这里,并附上了详细注释:

操作寄存器和内存

前一篇可以知道,HACK机器语言中有三个寄存器:

  • D:data register,数据寄存器
  • A:address register/data register,地址与数据寄存器
  • M:M=RAM[A]

A指令作用:
@17之后A=17,M=RAM[17]

HACK的所有功能都通过对这三个寄存器的操作来实现。

基本用法:

// D=10
@10   // A指令引入常量
D=A   // 将常量传递给D寄存器

// D++
D=D+1 // 可以直接对D+1

// D=RAM[17]
@17  // A指令保存17到A寄存器,此时M=RAM[A]就代表RAM[17]
D=M // 将RAM[17]赋给D

// RAM[17]=10
@10  // A指令取常量10
D=A  // 将常量10传递给D
@17 // A指令取常量17,此时M=RAM[A]就代表RAM[17]
M=D  // 将常量10从D中传递到RAM[17]

// RAM[5]=RAM[3]
@3  // A指令取常量3,此时M=RAM[A]就代表RAM[3]
D=M // D=RAM[3]
@5  // M=RAM[5]
M=D  // RAM[5]=RAM[3]

小试牛刀,计算RAM[2]=RAM[0]+RAM[1]:

// Add2.asm
@0   
D=M  // D=RAM[0]

@1
D=D+M  // D=D+RAM[1]

@2
M=D   //RAM[2] = D

分支

完成基本的if-else结构:

if R0>0
    R1=1
else
    R1=0

汇编代码:

0:  @R0  //rR0表示0,因此表示@0,下面的@R1同理
1:  D=M   // D=RAM[0]

2:  @8
3:  0;JGT  // IF R0>0 goto line 8

4:  @R1
5:  M=0   // RAM[1] = 0

6:  @10
7:  0;JMP  // 程序结束

8:  @R1
9:  M=1  // R1=1

10: @10
11: 0;JMP

上面代码特意标上了行号,是为了引出标签:

  @R0
  D=M   // D=RAM[0]

  @POSITIVE
  0;JGT  // IF R0>0 goto line 8

  @R1
  M=0

  @END
  0;JMP

(POSITIVE)
  @R1
  M=1

(END)
  @END
  0;JMP

行号在开发过程中是时时改变的,如果要记行号,那就是灾难,使用标签替代行号,就友好多了。

变量

完成两个内存单元,RAM[0]和RAM[1]数值的交换,需要声明一个中间变量temp:

// temp=R0
// R0=R1
// R1=temp

  @R0
  D=M  //将RAM[0]保存到D
  @temp  // 没有声明的标签视为对内存地址的引用,因为R0-R15已经有特殊声明,所以地址从16开始。
  M=D  // 将RAM[0]保存到temp内存

  @R0
  D=M  // D=RAM[R0], R0保存到D
  @R1
  M=D  // R1=R0

  @temp
  D=M  // D=temp
  @R0
  M=D  // R0=temp

(END)
  @END
  0;JMP

如果有多个变量,内存地址会从16开始一直递增:16,17,18…

循环

计算:1+2+…+n
如果直接编写汇编代码,会比较痛苦。
按课程中提倡的方法,先列伪代码,伪代码逻辑没问题,再实现为汇编代码。
伪代码:

// 计算 RAM[1] = 1+2+...+RAM[0]
  n=R0
  I=1
  sum=0
LOOP:
  if i>n goto STOP
  sum=sum+i
  i=i+1
  goto LOOP
STOP:
  R1=sum

伪代码逻辑ok后,将伪代码用汇编实现即可,这时伪代码可作为代码注释:

  @R0
  D=M  //D=RAM[R0]
  @n   //@16,M=RAM[16],取RAM[16]
  M=D  //n=R0
  @i  //@17
  M=1  //i=1
  @sum  //@18
  M=0  //sum=0

(LOOP)
  @i  //@17,M=RAM[17],取RAM[17]
  D=M  //D=i
  @n  //@16,M=RAM[16],取RAM[16]
  D=D-M  //D=D-RAM[16],比较i和n的大小
  @STOP
  D;JGT  // if i>n goto STOP,循环出口

  @sum //@18,M=RAM[18],取RAM[18]
  D=M //D=sum
  @i  //@17,M=RAM[17],取RAM[17]
  D=D+M  //D=sum+i
  @sum
  M=D  // sum=sum+i
  @i
  M=M+1   //i=i+1
  @LOOP
  0;JMP   // 无条件跳转到LOOP位置

(STOP)
  @sum  // 循环退出后跳到这里,保存sum到RAM[1]
  D=M   // sum地址的值保存到D
  @R1
  M=D  //RAM[1]=sum

(END)
  @END
  0;JMP

最后可以推演一下在循环中变量的变化过程:
在这里插入图片描述

指针

在汇编语言中,只有内存片段和寄存器,没有数组这样的概念,因此以下的操作需要借助额外的技术:

for (i=0;i<n;i++){
    arr[i]=-1
}

汇编语言中只有内存地址,在汇编中对数组支持是通过数组名称arr和下标i共同实现的
将arr[i]看成两部分:

  • arr,表示一个内存基地址,是一个内存单元
  • i表示相对基地址的偏移量,arr[i]表示离基地址arr距离为i的内存单元

伪代码:

  arr=100  //假设基地址为100
  n=10  //假设循环10次
  i=0  //偏移从0开始
LOOP
  if (i==n) goto END
  RAM[arr+i]=-1
  i++
END

因此可以实现如下:

  //arr=100
  @100
  D=A
  @arr
  M=D   // 假设基地址为100

  //n=10
  @10
  D=A
  @n
  M=D

  //i=0
  @i
  M=0

(LOOP)
  //if (i==n) goto END
  @i
  D=M
  @n
  D=D-M
  @END
  0;JEQ

  //RAM[arr+i]=-1
  @arr
  D=M
  @i
  A=D+M
  M=-1

  //i++
  @i
  M=M+1
  @LOOP
  0;JMP

(END)
  @END
  0;JMP

经过三次循环后内存状态:
在这里插入图片描述

输入输出

输入是键盘KBD
输出是屏幕SCREEN
关于HACK中屏幕和键盘的操作可参考输入输出处理
视频中只提到了屏幕操作的例子,例子任务是在屏幕左上角画一个宽为16的矩形,也即每行只操作第一个寄存器。
伪代码:

  addr=SCREEN
  n=RAM[0]
  i=0
LOOP:
  if i>n goto END   // 画n行后结束
  RAM[addr]=-1  //1111111111111111,表示将RAM[addr]内存对应的屏幕上16个像素改成黑色
  // 到屏幕下一行
  addr = addr+32   // 每行有32个寄存器,+32正好落到下一行的第一个寄存器上
  i=i+1
  goto LOOP
END
  goto END

汇编:

  @SCREEN
  D=A
  @addr
  M=D  //addr=16384,屏幕基地址
  
  @0
  D=M
  @n
  M=D  //n=RAM[0]
  @i
  M=0  //i=0

(LOOP)
  @i
  D=M
  @n
  D=D-M
  @END
  D;JGT  //if i>n goto END

  @addr
  A=M
  M=-1  //RAM[addr]=1111111111111111
  
  @i
  M=M+1  //i=i+1
  @32
  D=A
  @addr
  M=D+M  //addr=addr+32

  @LOOP
  0;JMP  //goto LOOP

(END)
  @END
  0;JMP
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值