这是一篇从简书上转载的博客,原文地址:学堂在线《汇编语言程序设计》题解及答案


《汇编语言程序设计》是鄙系的张悠慧老师开的一门自主进度的课程,它以计算机系小学期《汇编语言程序设计》为蓝本,但是课程的设计并不太好,结构有些杂乱,而且,习题没有答案,很多地方都非常坑爹。所以我决定来写个题解啦……

课程内容

在清华计算机系,汇编语言程序设计通常作为本科生接触到的第一门计算机系统课程,被定位为该系列的入门课,起到“承上启下”的作用。主要的授课内容包括:(1)汇编语言与计算机系统结构、指令集初步、数制与整数表示、浮点数表示;(2)80x86计算机组织与保护模式、X86指令系统与寻址方式、C与X86汇编、X86汇编编程;(3)MIPS汇编。课程强调汇编语言的软硬件分界与桥梁作用,使得学习者能把程序的执行与计算机的工作过程紧密联系起来,以便深入地感知、理解和体会计算机的逻辑功能以及各种软件系统的原理,逐步形成软件系统功能构筑在其上,硬件系统功能运行于其下的计算机系统思维能力。与以往的讲法不同,本课程突出了“承上启下”这一理念,在内容编排上进一步突出了与相关课程的衔接,尤其是与C语言编程、编译原理、组成原理的衔接。比如说,(1)强化与高级语言的联系,从典型的C语言代码段入手,通过编译成汇编代码来详细解释程序员角度的X86结构运行模型。掌握这两种语言的对应可以将程序的执行与计算机的工作过程紧密联系起来,直接体现汇编语言本身固有的特点,即它是最易于将“程序”和“机器”统一起来的一个结合点。(2)进一步的通过对不同汇编代码的解释来给出微体系结构方面的差异。比如,同一段C代码通过不同的编译器/编译器开关所生成的代码是不一样的,为什么不一样?这就可以通过处理器微体系结构的差异来简单解释。这种做法可以为后续课程,如编译原理、计算机组成原理等提供一些先导知识,并有利于学生从整个系统构成的角度来理解各个课程的作用与位置。(3)加入MIPS汇编(包括部分体系结构的内容),为后续的以MIPS为核心的计算机组成原理、编译原理、操作系统等专业课程奠定MIPS汇编语言的基础。

课程内容与目标 题解

文字填空题

请写出ISA这个缩写的全名(单词首字母大写,单词间以"/"间隔)
答案:= Instruction/Set/Architecture

指令集简介 题解

单选题

只有LOAD和STORE指令可以访问存储器的指令系统属于RISC还是CISC?

  • RISC(√)
  • CISC

分析:这是RISC和CISC指令集的重要区别。

单选题

X86指令系统属于RISC还是CISC?

  • CISC(√)
  • RISC

单选题

X86指令至多只有一个操作数在()中。

  • 内存(√)
  • 寄存器

分析:而MIPS32指令的操作数必须都在寄存器中。

整数的机器表示 题解

单选题

X86处理器的存储字节序是()。

  • 小端(√)
  • 大端

分析:小端表示即所谓“低对低,高对高”(高位有效数字存在内存的高位中)。X86的字节序为小端,ARM、MIPS和IA64的字节序可配置,网络传输一般采取大端序。详见https://en.wikipedia.org/wiki/Endianness

无符号整数与带符号整数 题解

文字填空题

已知某32位整数X,其值为-101(十进制),则其16进制补码为(),另一32位整数Y的补码为0xFFFFFF6A,则X+Y的16进制补码(32位)为(),X-Y的16进制补码为()。(本题一共三个空,十六进制表示示例:0xFFFFFFFF 注意开头与字母大小写。答案之间以‘/‘符号隔开)

答案:0xFFFFFF9B/0xFFFFFF05/0x00000031
分析:正数的补码与原码相等,负数的补码等于原码取反+1。

(其实我这道题一直没有通过,但我觉得计算结果是对的)

判断题

以下几道判断题都与本题条件相同。已知x、y为int类型; unsigned int ux = x; unsigned int uy = y.判断以下等式是否成立?(x>y)==(-x<-y)

  • 正确
  • 错误(√)

分析:若y=-2147483648,则-y=-2147483648,等式不成立。

判断题

(x|-x)>>31 == -1

  • 正确
  • 错误(√)

分析:取x=0,显然原式是错的。不过,当x不等于0时,原式是正确的,因为x和-x中至少有一个是负数,则(x|-x)的最高位必然为1,算术右移31位后,就全是1了。

判断题

¬x+¬y == ¬(x+y)

  • 正确
  • 错误(√)

分析:随便举个例子就会发现这是错的。

判断题

(int)(ux-uy) == -(y-x)

  • 正确(√)
  • 错误

分析:可以这样思考:无符号整数和带符号整数的内部表示形式和运算规则都是一样的,区别只在于解释的方法。

浮点数的机器表示 题解

数值填空题

单精度浮点数的exp域的位宽是()位?
答案:8

数值填空题

单精度浮点数的frac域位宽是()位。
答案:23

判断题

已知 int x = …; float f = …; double d = …;且d 与 f 都不是 NaN。判断以下关系式是否成立?x == (int)(float) x

  • 正确
  • 错误(√)

分析:float的frac域宽度不够,可能会有精度损失。

判断题

条件同上题
x == (int)(double) x

  • 正确(√)
  • 错误

分析:double的frac域足够放下int,不会有精度损失。

判断题

f == (float)(double) f

  • 正确(√)
  • 错误

分析:float转换成double不会有精度损失。

判断题

d == (float) d

  • 正确
  • 错误(√)

分析:double转换成float可能会有精度损失。

判断题

f == -(-f)

  • 正确(√)
  • 错误

分析:浮点数取负只改变符号位,不会溢出。

判断题

2/3 == 2/3.0

  • 正确
  • 错误(√)

分析:2/3的结果是整数,但2/3.0的结果是浮点数。

判断题

(d < 0.0) == ((d*2) < 0.0)

  • 正确(√)
  • 错误

分析:浮点数的下溢是逐步下溢,不像整数会从负数变成正数。

判断题

(d > f) == (-f > -d)

  • 正确(√)
  • 错误

分析:浮点数取负不会溢出。

判断题

(d+f)-d == f

  • 正确
  • 错误(√)

分析:d+f可能会溢出,损失精度。

80x80汇编与C语言-2 题解

文字填空题

已知寄存器edx内的数值为0x8000,ecx内的则为0x10;请给出地址表达式0x4 (%edx,%ecx,4)所表示的地址值。

答案:0x8044

分析:D(Rb, Ri, S) = Rb + S*Ri +D

数值填空题

x86-64体系结构具有()个通用寄存器,而x86-32只有()个。

答案:16;8

判断题

leal (%edx,%eax),%ecx这条指令在执行过程中需要访问内存数据。

  • 正确
  • 错误(√)

分析:leal指令只计算地址,不访存。因此leal指令也可以用于整数运算。

单选题

请问哪个条件码可用于检测无符号整数运算的溢出?

  • CF(√)
  • SF
  • ZF
  • OF

分析:CF(Carry Flag),无符号整数运算溢出时置位;SF(Sign Flag),计算结果<0时置位;ZF(Zero Flag),计算结果=0时置位;OF(Overflow Flag),带符号整数运算溢出时置位。

单选题

seta、setb指令适用于无符号还是带符号整数的条件码读取?

  • 无符号(√)
  • 带符号

分析:seta和setb中的a、b分别指的是above和below。带符号整数对应的是setg和setl(greater和less)。

文字填空题

请补充与下图中C语言对应的汇编代码中的遗漏部分(x86-32结构下编译生成)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pushl %ebp
movl %esp, %ebp
pushl %ebx
movl 8(%ebp), %ecx
movl 12(%ebp), %edx
movl %ecx, %ebx
subl %edx, %ebx
movl %edx, %eax
subl %ecx, %eax
cmpl %edx, %ecx
_____ %ebx, %eax
popl %ebx
popl %ebp
ret

答案:cmovg

分析:将汇编代码“翻译”如下:

1
2
3
4
5
6
7
8
9
ecx = x
edx = y
ebx = x
ebx = x - y
eax = y
eax = y - x
Compare x to y
if (?) (eax = x - y)
return eax

由分析可知,此处应该填写条件移动指令cmovg(若x>y则传送)。

80x80汇编与C语言-2(续) 题解

文字填空题

左侧的C语言程序段编译为右侧的汇编代码(x86-32体系结构),请填空

左图

右图

答案:.L8.L3.L4.L9.L8.L6.L6

分析:由switch的特性可知,7个空分别对应的是x=0x=6时的跳转结果。经过分析可知,.L8对应的是默认情况(x=0及其他);.L6对应的是x=5或6;.L9对应的是x=3.L4对应的是x=2.L3对应的是x=1.L12对应的是返回。

80x80汇编与C语言-3 题解

文字填空题

下图给出了一个C函数,并由gcc编译成相应的汇编代码(AT&T语法格式),请补全这段代码里头被省去的部分。(X86-32结构)

C函数
汇编代码

答案:%esp;8;12;%ecx%ecx%edx%ebx

分析:下面用表格给出每行汇编代码的解释。

汇编 解释
pushl %ebp setup, save old ebp
movl %esp, %ebp setup
movl 8(%ebp), %edx edx = x
movl 12(%ebp), %ecx ecx = y
pushl %ebx save old ebx
movl 12(%ebp), %eax eax = z
movl %edx, %ebx ebx = edx = x
addl $40, %edx edx += 40 (edx = x + 40 = t3)
imull %ecx, %ebx ebx *= y (ebx = x * y = t1)
addl %ecx, %ecx ecx += y (ecx = 2*y = t4)
sarl %cl, %edx edx >>= cl (cl = t4, edx = t5)
subl %ebx, %eax eax -= ebx (eax = z - t1 = t2)
imull %edx, %eax eax *= edx (eax = t2 * t5 = rval)
popl %ebx reset ebx
popl %ebp reset ebp
ret return eax (rval)

文字填空题

在X86-32位体系结构中,当前运行函数的帧(Frame)基址寄存器所指向的栈地址的“上方”(高地址)由低到高存放的是函数返回地址、____;“下方”存放的是____、____(此处无需考虑顺序)。

答案:输入参数;局部变量;临时存储分析:其实有很多填法(比如,把临时存储换成“保存的寄存器值”),不过这是标准答案了。

80x80汇编与C语言-4 题解

文字填空题

请按顺序填写图左侧汇编代码对应的C代码(e.g. 右3)

答案:右3;右5;右1

分析:值得注意的是右5和对应的汇编代码。众所周知,算术右移指令对应的除法的取整模式是向下取整,而C语言要求的除法的取整模式是向0取整,因此负数除法的取整会出问题,正确的计算方法是:a<0时,a/2^b = (a+2^b−1)>>b
。这就解释了汇编代码中testl %eax, %eaxjge .L4的意义。jge .L4的意义是:当条件码满足SF=OF时,跳到.L4(即不是负数,不用加上15)。testl做的事是,取后面两个操作数的与,根据运算结果置条件码。当%eax>=0时,运算结果仍为%eax,SF为0,OF也为0,满足条件,跳转;当%eax<0时,SF为1,不符合条件,不跳转。

文字填空题

已知三个二维矩阵的定义如下,并已初始化。

1
2
3
4
#define n 10
int a[n][n] ;
int b[n][n] ;
int c[n][n] ;

需要进行矩阵乘,即矩阵a x b结果置于c。下面这段C代码是一个矩阵乘函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
void column()
{
int j, k , i;
int r;
for (j=0; j<n; j++)
{
for (k=0; k<n; k++) {
r = b[k][j];
for (i=0; i<n; i++)
c[i][j] += a[i][k] * r;
}
}
}

答案:%esp%ebp%edi%eax%eax-20%edx%esi$9$9$8

分析:下面以表格形式给出汇编代码和解释。

汇编 解释
_matrix:
pushl %ebp setup, save old ebp
movl %esp, %ebp setup
pushl %edi save edi
pushl %esi save esi
pushl %ebx save ebx
subl $8, %esp esp -= 8
movl $0, -16(%ebp) j = 0 (-16(%ebp) = j)
L13: the start of j loop
movl -16(%ebp), %eax eax = j
xorl %edi, %edi edi = 0 (edi = k)
leal b_start_addr(, %eax, 4), %eax eax = &b[4*j]
movl %eax, -20(%ebp) -20(%ebp) = &b[4\*j + (40*k)]
L12: the start of k loop
movl -20(%ebp), %edx edx = &b[4\*j + (40*k)]
xorl %ecx, %ecx ecx = 0 (ecx = i * 10)
movl $9, %ebx ebx = 9 // as "i"
movl (%edx), %esi esi = b[k][j], or r = b[k][j] (esi = r)
L11: the start of i loop
movl -16(%ebp), %edx edx = j
leal (%ecx, %edx), %eax eax = ecx + edx = 10 * i + j
leal (%ecx, %edi), %edx edx = ecx + edi = 10 * i + k
movl a_start_addr(,%edx, 4), %edx edx = a[4*edx] (edx = a[i][k])
addl $10, %ecx ecx += 10 (ecx = i * 10)
imull %esi, %edx edx *= r (edx = a[i][k] * r)
addl %edx, c_start_addr(, %eax, 4) c[4*eax] += edx (c[i][j] += a[i][k] * r)
decl %ebx ebx-- // as "i"
jns L11 if (ebx > 0) goto L11 the end of i loop
addl $40, -20(%ebp) -20(%ebp) += 40 (-20(%ebp) = 40\*k+4*j)
incl %edi edi++ (k++)
cmpl $9, %edi compare k : 9
jle L12 if (k <= 9) goto L12 the end of k loop
incl -16(%ebp) -16(%ebp)++ (-16(%ebp)=j) (j++)
cmpl $9, -16(%ebp) compare j : 9
jle L13 if (j <= 9) goto L13 the end of j loop
addl $8, %esp esp += 8
popl %ebx finish, reset ebx
popl %esi finish, reset esi
popl %edi finish, reset edi
popl %ebp finish, reset ebp
ret return

80x80汇编编程-1 题解

文字填空题

在X86-32位编程中有一种简单的获得所运行的指令地址的方法(X86-32位结构下eip寄存器是无法直接访问的)。比如说我们要获得下面程序中XXXX这条指令的地址并置于eax寄存器中,那么可以采用如下代码段。请补充完函数GetAddress的第一条语句(AT&T语法)。

1
2
movl ____, ____
ret
1
2
call GetAddress
xxxx

答案:(%esp)%eax

分析:在call之后,GetAddress的返回地址,也就是xxxx的地址被压栈。此时,只需将栈顶所指向位置的内容((%esp)),注意括号代表访存)存入eax中再返回。

(其实第二空我没过,但老师告诉我填%eax是对的。)

数值填空题

已知一个c语言结构类型的定义如下图所示,请问在X86 32位Linux系统下变量p所占的空间大小是多少字节,对齐的要求为多少字节对齐?

答案:24;4

分析:

TagStruct的内存分布:

k[0] (4 bytes) k[1] (4 bytes) c2 (1 byte) padding (3 bytes)

大小为12字节,4对齐。

S1的内存分布:

c (1 byte) padding(3 bytes) i[0] (4 bytes) i[1] (4 bytes) v (12 bytes)

大小为24字节,4对齐。

80x86汇编编程-2(程序链接) 题解

文字填空题

有如下的C代码以及对应的反汇编出来的汇编代码(x86-32体系结构):当strcpy调用完成返回到foo过程时,buf[0]buf[1]buf[2]的值分别是多少?在执行0x0804850dret指令前(popl后),ebp的值是多少?上述ret指令执行后,eip的值是多少?用32位16进制表示,注意大小端。e.g. 0x00000000 字符的十六进制转换表已给出

C代码
汇编代码
字符转换表

答案:0x646362610x686766650x080400690x686766650x08040069

分析:

通过分析可以画出调用strcpy之前完整的栈(具体分析过程略)如下表(每个格子代表4个字节,address向下递减)

内容 指向该位置的指针
callfoo过程保存的%ebp
empty
empty
empty
empty
empty
string address (0x0804859c)
foo过程的返回地址 (0x08048523)
foo过程保存的%ebp %ebp
buf
empty
empty
empty
empty
empty
empty
empty
string address (strcpy的第二个参数)
%ebp - 4 (buf)

可以看出,传递给strcpybuf指针就是%ebp-4,在复制了字符串"abcdefghi"之后,会发生溢出,破坏栈中保存的%ebp和返回地址。但现在的问题是,在考虑大小端之后,栈中的实际内容到底应该是什么样子的呢?

由于X86的字节序为小端(“低对低,高对高”),可以画出从buf指针开始向上到string address位置中实际的保存内容(一个格子代表一个字节,地址从上往下递减):

描述 内容
string address (高) 08
04
85
string address (低) 9c
foo的返回地址 (高) 08
04
85
foo的返回地址 (低) 23
保存的%ebp (高) ??
??
??
保存的%ebp (低) ??
buf[0] (高) ??
??
??
buf[0] (低) ??

在向以buf开头的地址中写入字符串"abcdefghi\0"(转换成16进制,就是0x61626364656667686900)时,由于char类型的大小只有一个字节,大小端对它来说是无所谓的,只要从低地址向高地址覆写就可以。于是,我们得到了修改过的栈帧:

描述 内容
string address (高) 08
04
85
string address (低) 9c
foo的返回地址 (buf[2]) (高) 08
04
85 00
foo的返回地址 (buf[2]) (低) 23 69
保存的%ebp (buf[1]) (高) ?? 68
?? 67
?? 66
保存的%ebp (buf[1]) (低) ?? 65
buf[0] (高) ?? 64
?? 63
?? 62
buf[0] (低) ?? 61

而寄存器会以小端模式来解释内存中的内容,因此可得,buf[0] = 0x64636261buf[1] = 0x68676665buf[2] = 0x08040069popl后得到的%ebp0x68676665,执行ret%eip的值(也就是要返回到什么地址)为0x08040069

MIPS32指令集与编程 题解

文字填空题

异常(exception)可以分类为 ____ 和____两类,其中系统调用属于____异常、时钟中断属于____异常、Page Fault是 ____异常、机器cold reset是 ____异常。

答案:同步;异步;同步;异步;同步;异步

分析:同步异常一般是指令引起的,异步异常一般是硬件引起的。

文字填空题

位于某个跳转指令的Branch Delay Slot中的指令(这一slot中的指令地址为A)发生了异常,那么异常处理完成后,恢复执行的指令地址是 ____;如果该跳转指令是JAL,那么该跳转指令执行完成后31号寄存器的内容是 ____。

答案:A-4;A+4

分析:精确异常处理要求,延迟槽中的指令如果发生异常,恢复执行的指令是跳转指令;函数返回到下一条指令。

期末考试\

期末考试中有许多题是重复的,不再一一列出。因为考试不给具体的题目对错,我至今也没有刷到100分,因此也请大家帮忙纠正一下我是不是有题目做错了……

文字填空题\

X、Y的数据宽度均为16位,计算结果也用16进制表示)已知[X]补=0019H,[Y]补=FE6AH,则[X+Y]补=____,[X-Y]补=____。

答案:FE83H;00AFH

分析:显然,X是正数,Y是负数。

[X+Y]补=X补+Y补=0x0019+0xFE6A=0xFE83

−Y原=(Y补−1)反=0x0096

[X−Y]补=X补−Y原=0x0019+0x0096=0x00AF

文字填空题

在X86-32位体系结构中,C语言过程调用的默认传参规则是将过程参数从____至____压入栈,过程返回值(32位)通过____寄存器传出。

答案:右;左;%eax

文字填空题

给出13/8这一数字的32位浮点数(符合IEEE 754标准)表示,即exp= ____;frac= ____

答案:01111111;10100000000000000000000

分析:13/8=(1101)2/2^3=(1.101)2

因此E=0,exp=E+bias=0+(2^(E_length−1)−1)=0+(01111111)2=(01111111)2

省略掉有效数字开头的1,frac=10100000000000000000000

。(后面一共20个0)

文字填空题

寄存器EAX,EBX内存储的为带符号32位整数,若%EAX >%EBX,则指令cmpl %EAX,%EBX执行后 SF=____,OF= ____。(若不确定,可以填“不确定”)

答案:不确定;不确定

分析:cmpl指令根据%ebx - %eax的值设置条件码。因为补码加法可能溢出也可能不溢出,带符号数的减法结果可能溢出到正数也可能不溢出,所以两空均为不确定。

文字填空题

X86 32位linux系统下的float类型的数据对齐要求是____字节对齐,double类型的是____字节对齐;X86 32位Windows系统下的double类型数据是____字节对齐。

答案:4;4;8

文字填空题

lw $t6, 65536($sp)经过MIPS 32汇编器处理后,产生的代码如下,请补全。

1
2
3
lui $1,____ 
addu $1, $1,____
lw $t6, 0($1)

答案:1;$sp
分析:lui将立即数装载到寄存器的高16位,低16位清零,而65536=(10000000000000000)2,因此,执行lui指令后,$1=65536。

文字填空题

li $6, 0x345678 经过MIPS 32汇编器处理后,产生的代码如下,请补全

1
2
lui $1, ____
____ $6, $1, ____

答案:0x34ori/addiu0x5678

分析:lui的作用同上题;ori作用的是寄存器的低16位。

这是关于《物理实验B(2)》中的塞曼效应实验的总结。我记得一共要求做6次实验,我好像写了3次总结,现在只能找到2篇了。这是一篇搬运过来的旧博客,进行了一定的修改。


简单来说,塞曼效应就是原子在外磁场中获得能量,谱线分裂。具体原理大家都知道,什么汞原子546.1nm谱线在磁场中分裂成9条,这里就不写了。这个实验是用F-P标准具观察谱线的分裂,然后用测量望远镜去测干涉圆环的直径。

实验地点:6B605

实验时间:2小时57分钟

实验难度:中等偏简单(毕竟光学实验还要调光路,但不难调,而且老师挺友善的会帮你调。要测的数据也不多。之所以时间长了,是因为我脑抽测错数据了,又重来了一遍)

实验装置

因为是光学实验,所以屋里(和照片)比较暗。

下图是实验装置,从左到右依次是电磁铁、聚光透镜(上面可安装偏振片)、干涉滤光片、F-P标准具和测量望远镜。后面那个带显示屏的白箱子是励磁稳压稳流电源。

实验装置

下图左上是测量望远镜(和它可以拧的那个部分),右下是电源特写。

测量望远镜和电源

下图仍然是F-P标准具和测量望远镜。

F-P标准具和测量望远镜特写

下图中的线圈是还没关灯的时候拍下来的电磁铁和汞灯。汞灯发出的光是蓝色的,通过滤光片之后是绿色的。

电磁铁和汞灯

实验步骤

1. 点燃汞灯

就直接打开开关就行。汞灯是蓝的。

2. 调节光路

在这一步应该先把偏振片和滤光片拿下来,用白纸挡在F-P标准具前看一下,光是不是差不多都进入镜头中了。如果不行,就需要调节高度。然后调节望远镜的高度、消视差、消空程,使得望远镜里能看到比较清晰的几圈亮环;不行的话可以找老师问一下,没准还能看到几个老师热烈地讨论光学问题。此处没图,忘了拍没分裂的谱线状态了,总之是好多圈绿线。我上一个做实验的人大概挺靠谱的,调都没调就大概是准的。

然后把滤光片装上(因为实验室的滤光片不是特别精确,所以可能需要旋转一下,找一个从望远镜里看起来最亮的方向)。

然后把偏振片也装上。

3. 观察零场花样

旋转偏振片,从望远镜里观察谱线的状况(6或3条),记录偏振片读数方向和方位。偏振片上有个小白纸片指示方位。

这一条只是我照着实验指导书随便写出来的,因为我忘了测了。准确的说,因为我不知道应该看到什么,所以觉得偏振片转了一圈都没什么变化……

4. 加磁场

取下偏振片。 先把稳流电源的电压调到最大(不然会带不动电流),电流调到0,然后再打开开关,电流调到3.50A。(调到2.50A、3.00A、4.50A显然原理相同)

5. 测量$D^2_{k}(\lambda_{2})$、$D^2_{k}(\lambda_{1})$和$D^2_{k-1}(\lambda_{1})$

测量方法如下图(这些圈当然应该是绿的)。

灵魂示意图

而在测量过程中,实际上会看到的是下图。

实际图片

可以看到上图中刻度4、亮斑中心和叉丝中心对齐了。

要测的直径如图。(最后将用到的波数计算公式是$\Delta\tilde{v} = \frac{1}{2d} \frac{D^2_{k}(\lambda_{2}) - D^2_{k-1}(\lambda_{1})}{D^2_{k-1}(\lambda_{1}) - D^2_{k}(\lambda_{1})}$)

公式中的第$k$级表明了谱线环距中心的远近,$λ_2$指波长,它反映了它是一套圆环(我说的“套”是指相距比较近的9个谱线环……看上图应该能意会是什么意思,它们是从一条谱线分裂来的)里的第几个环,靠里的编号小。任选两种中间有间隔的不同波长的光形成的谱线环,测编号大的谱线环的第$k$级直径,和编号小的谱线环的第$k$级、第$k-1$级直径。

如果搞不清楚,那就直接测相邻的两套圆环里从左往右数第3条和第7条的直径,都测完了回去再算(x)。从上图可以看出来,第3、5、7条线最亮,所以这么选择也有一定的道理。

具体的测量直径的方法是,先调整中心亮斑对准十字叉丝(可能需要上下调整,如果看不清叉丝,可以用小台灯补一点光),然后就可以去读待测圆环的左右位置并计算出直径了。机械误差好像很大,所以要测3-5次时直接从一边打轮到另一边(中间尽量不要向回转)测一次,再从这一边转到这一边再测就行(就会有相当的误差)。

除此之外,我得到了一些这样的经验教训:

  • 转螺旋测微器(我不知道学名是什么……大概意会一下)时扶着镜筒,不然镜头可能会晃动甚至移位
  • 尽量使镜头最中间的刻度(应该是4)、叉丝和亮斑中心对齐。不调到4也一样能测,但问题是,粗测的范围只有0-8,如果不使刻度在两边均匀分布,可能测到比较大的圆环刻度就没了。
  • 电流可能会有微小的变化。建议勤加观察,微调一下。

6. 收拾东西

关闭稳流电源时先把电流调到0再关闭电源,因为有大电感。

不要乱摸F-P标准具。虽然它长得很好看。

实验计算

数据处理的公式书上已经给了。

计算波数差:

$$\Delta\tilde{v} = \frac{1}{2d} \frac{D^2_{k}(\lambda_{2}) - D^2_{k-1}(\lambda_{1})}{D^2_{k-1}(\lambda_{1}) - D^2_{k}(\lambda_{1})}$$

计算$L$(7和3当然是根据你测的是哪些谱线决定的):

$$L = \frac{\Delta\tilde{v}}{M_2g_2-M_1g_1} = 2\frac{\Delta\tilde{v}}{7 - 3}$$

计算$B$:

$$B = L / 0.467cm^{-1}$$

一些说明:

  • 波数差公式里的$d$是F-P标准具的间距,本实验中是2mm。
  • 我也没搞懂为什么$L$是这么算,量子物理没学好。嗯,有没有人愿意告诉我……(2018.7.14 UPDATE:至今也没人告诉我)
  • 算$B$的时候注意单位。

其他

还有几张没太拍好的实验过程图,不过手机能拍下来我已经很感动了。

一张糊了的图

一张歪了的图


2018.7.14 UPDATE:回头看这篇文章的时候,虽然感觉写得很详细,但我完全想不起来实验到底应该怎么做,为什么要这么做了。一部分原因是当时我也没搞懂原理……这样的话,总结简直毫无意义,以后我尽量以自己过一年还能看懂自己写的是什么为目标写总结好了。

这是关于《数字逻辑实验》的第一次正式实验,“点亮数字人生”的总结。这是一篇搬运过来的旧博客,进行了一定的修改。


实验指导书截图

数字逻辑实验箱

注意事项

电路调试提示

实验步骤

1. 在老师处获取一个实验箱

没错,就是刚才你们看到的那个箱子。里面肯定还配芯片、电源、连接线、等等,请收好。以后作业就靠它了。今年有两个班改版了(包括我们班),收到的应该是积木形状的。

数字逻辑实验箱新版,由积木块构成

2. 安装必要的软件

2.1 在电脑上下载Quartus II

一位善良的同学提供了官网下载链接。

因为他登录之后发现下载只不过是普通的网址,于是便记录下来,这样便可避免登录,还可使用下载软件提速、断点续下。

我把Quartus-lite-16.1.0.196-windows.tar的资源放在百度网盘上了:
链接:http://pan.baidu.com/s/1pLHdq6R 密码:cyy4

至于其他版本呢……有同学是在北邮人上下载了9.0版和13版。13版同样没有什么问题,但9.0版需要破解,否则会缺少.pof文件。在虚拟机上安装的同学还会遇到驱动问题,此事待会再谈。

2.2 开始安装Quartus II

我在Windows10上安装了Quartus-lite-16.1.0.196-windows。在安装过程中,我遇到了这样的问题:

因为所需空间不足而报错

面临这种情况,其实只需要选中原本的软件和MAX II/V两个版本就行,盘不会满的。模拟需要安装那个免费版的ModelSim,但是单纯的烧录不需要。以后如果你发现自己装的少了,还可以用那个安装包去更新。

如果使用的是破解软件或者在虚拟机上安装,还可能会出很多其他的问题,不过我这里差不多这样就装好了。

3. 开始建项目、写程序、绑引脚

具体项目建立过程书上都有,不再赘述。

这次的程序代码也是从书上抄的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

entity digital_7 is
port(
key:in std_logic_vector(3 downto 0);
display:out std_logic_vector(6 downto 0);
display_4:out std_logic_vector(3 downto 0)
);
end digital_7;

architecture bhv of digital_7 is
begin
display_4<=key;

process(key)
begin
case key is
when "0000" => display <= "1111110"; --0
when "0001" => display <= "0110000"; --1
when "0010" => display <= "1101101"; --2
when "0011" => display <= "1111001"; --3
when "0100" => display <= "0110011"; --4
when "0101" => display <= "1011011"; --5
when "0110" => display <= "0011111"; --6
when "0111" => display <= "1110000"; --7
when "1000" => display <= "1111111"; --8
when "1001" => display <= "1110011"; --9
when "1010" => display <= "1110111"; --10
when "1011" => display <= "0011111"; --11
when "1100" => display <= "1001110"; --12
when "1101" => display <= "0111101"; --13
when "1110" => display <= "1001111"; --14
when "1111" => display <= "1000111"; --15
when others => display <= "0000000"; --others
end case;
end process;
end bhv;

下面是代码截图。(下图的程序是干什么的,我已经想不起来了。)

不知道是干什么用的代码截图

写完代码之后,绑定引脚,编译。

绑定引脚并编译

这之后可以把USB线插到电脑上,进行设置,准备下载。

硬件连接设置

有时候在硬件连接那一步会出问题。如果插电以后显示驱动未安装,就需要到Altera的安装目录里找到driver里面的驱动安装之。在虚拟机Windows10,Quartus 9.0环境下,有时候可能会安装不了驱动(安全警报),可以尝试进入Win10调试模式后再安装。

4. 下载

而在这一切都做完之后,我迫不及待地点击了Programmer,想把程序下载到硬件。

结果这个界面上什么都没有

结果我发现找不到.pof文件,尝试烧录,也毫无效果。而且,9.0版本软件如果不能破解,好像就没法编译出.pof文件,无法输出程序。

我在这个网站上找到了相关的建议(虽然既没图,又和我们用的器件不一样):

Quartus Prime Lite » Tools » Programmer (or double-click Program Device in the task list)

  • Click Hardware Setup, and select USB-Blaster [USB-0]
  • Click Add File, and select your SRAM object file (.sof) in the output_files directory
  • Click Start
  • Save as example1.cdf, so it opens with these settings next time
  • Great! We did it, the design is now on the FPGA (until we remove the power)

于是,我在工程目录下的output_files文件夹找到了这个vhd1.pof,加载进去,就能下载了。

加载了正确的pof之后的Programmer

我猜测,如果没有指定正确的pof文件,编译只会把空的那个文件烧上去,所以无效。

5. 运行

之后的事情就真的很简单了。我的机器必须在烧好之后重开一次电源键,否则程序无法正常显示。下面两张图是我的电路完成图。

我搭的电路,正在显示9

电路和线全貌

下面两张图是从同学的朋友圈里找到的普通箱子的完成图,因为时间过去太久,很难考证到底是谁的图了,非常感谢他们的图,侵删。

从同学那里抄来的完成图

从同学那里抄来的完成图之二

如果在下载的时候没开电源,可能会在Quartus主窗口中报错"can't access JTAG chain"(上课时就有同学遇到这种故障),报这种错误的原因可能包括

  • 下载有时受环境影响很大。比如,在嘈杂的环境下就可能下载不进去。
  • 电源按钮没有打开或者是工作模式没有跳到"RUN”
  • 电路板问题(电源,负载,虚焊等)
  • FPGA器件上的JTAG相关引脚出现故障
  • USB-Blaster坏了
  • 10针JTAG线缆没有压制好
  • JTAG的PCB不正确
  • ……

大多时候原因就是没开电源,打开电源就可以往上烧了。

实验总结

最后还是很开心的。看到自己按了开关之后数字就能变化,开心。但是紧接下来就又要有加法器的实验了,希望自己仍能存活下来。(2018.7.14 UPDATE:我还活着。)