如何运行?
1.在开始菜单选在它的图标,或者直接运行 Emu8086.EXE
2.在"FILE"菜单中选择"SAMPLE"
3.点击"Compile and Emulate"按纽(或者按快捷键 F5)
4.点击"Single Step"按纽(或者按快捷键 F8),可以查看代码如何运行.
十进制系统
目前使用最多的是十进制.十进制系统有10个数字0,1,2,3,4,5,6,7,8,
9 利用这些数字能表示任何数值,例如754这些数字是由每一位数字乘以“基数”的幂
累加而成的(上一个例子中基数是 10 因为十进制中有十个数字)。
位置对于每一个数字是很重要的。例如,你将上一个例子中的“7”放到结尾:547
数值就成为:
特别提醒特别提醒特别提醒特别提醒:任何数字的 0 次幂都是 1,0 的 0 次幂也是 1
二进制
计算机没有人类聪明(至少现在是这样),制造一个只有开关或者称为 0,1 两种状态的电
子机器很容易。计算机使用二进制系统,只有两个数字 0,0,0,0, 1111 基地为 2 每一位二进制数称作
一位(BIT),4 BIT 组成一个半字节(NIBBLE),8BIT 组成一个字节(BYTE),两个字节
组成一个字(WORD),两个字组成一个双字(DOUBLE WORD)(很少使用):
习惯上在一串二进制后面加上“b”,这样,我们可以知道 101b 是二进制表示十进制的 5。
10100101b
10100101b
二进制 10100101b
10100101b 表示十进制的 165,计算方法如下:
十六进制系统
十六进制系统使用 16 个数字 0,0,0,0, 1,1,1,1, 2,2,2,2, 3,3,3,3, 4,4,4,4, 5,5,5,5, 6,6,6,6, 7,7,7,7, 8,8,8,8, 9,9,9,9, A,A,A,A, B,B,B,B, C,C,C,C, D,D,D,D, E,E,E,E, FFFF 基底基底基底基底是 16161616.
十六进制非常紧凑,便于阅读。将二进制转换为十六进制很容易,半字节(4bits) 对应一
位十六进制如下表
Decimal
(base 10)
Binary
(base 2)
Hexadecimal
(base 16)
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
习惯上我们在一个十六进制数的后面加上 """"HHHH"""",以便和其他进制区别, 这样我们就知道 5Fh
是一个十六进制数表示十进制的 95。习惯上,我们也在以字母开头(从A到F)的十六进
1234h
0E120h
制数前面 加上"0""0""0""0" 例如:例如:例如:例如: 0E120h
0E120h
1234h
0E120h. 十六进制 1234h
1234h 等于 4660:
十进制到另外进制的换算
在换算中,将十进制数不断除以目标进制的基底,每一次都要记录下商商商商和余数余数余数余数,直到商0。
余数余数余数余数用来表示结果。
下面是一个十进制39(基底是10)到十六进制(基底是16)的换算:
43868
43868
上例中所有的余数都小于10,不必使用字母。再举一个更复杂的例子:十进制 43868
43868 换
算为十六进制:
结果为 27272727HHHH
0AB5Ch
0AB5Ch
结果是 0AB5Ch
0AB5Ch, 使用 上面提到的表 将大于9的数字替换成字母。 运用同样的原理,我们
可以换算为二进制(用2作除数),或者是先换算成十六进制,再用上面的表 换算成二进
制:
1010101101011100b
1010101101011100b
于是,得到二进制: 1010101101011100b
1010101101011100b
有符号数
有符号数
有符号数
有符号数
0FFh0FFh0FFh 无法确定它是正数还是负数,因为它可以表示十进制的"255255255255" 或者
对于十六进制数 0FFh
"---- 1111"。
8位可以表示256256256256个状态,于是,我们可以假定前128128128128个表示正数(从从从从 0000 到到到到 127127127127),接下
来的128个数(从从从从 128128128128 到到到到 256256256256)表示负数 。如果想表示"---- 5555",我们从256中减去5,即
256256256256 ---- 5555 ==== 251251251251。用这种复杂的方法表示一个负数有着数学依据的,数学上"---- 5555" 加上 "5555"
等于0。当我们将两个8位的数字 5555 和 251251251251 相加时,结果超过255,溢出处理为0!
128128128128 到到到到 256256256256 高位始终是1111,,,,这个可以作为数字符号的标记 对于字(16位),16位有 6553
6553
65536666
6553
个状态,头32768个状态(从从从从 0000 到到到到 32767
32767)用来表示正数,下面的32768个状态(从从从从
32767
32767
32767 到到到到 65535
32767
65535
65535
32767
32767
65535) 表示负数
Emu8086 带有数制转换工具,也可以计算各种数值表达式。选择菜单 Math
MathMathMath 项:
Convertor
Number
Number
Convertor
Number Convertor
Number
Convertor (数制转换)可以实现任意数制之间的转换。在文本框中填写源
Expression
数值,将自动转换到任意的数制。 可以作 8888 位位位位 或者 16161616 位位位位转换。Expression
Evaluator
Expression
Evaluator
Expression Evaluator
Evaluator
(表达式计算))))可以用来计算不同数制的计算以及从一个进制到另一个进制的转换。输入表
(表达式计算
(表达式计算
(表达式计算
Signedddd
Signe
Signe
达式,按下回车,结果就会以你选定的进制表示。最长可以进行32位的计算。当在 Signe
0FFFFFFFFh
0FFFFFFFFh
打钩选中时(除了八进制和双字),最前面的一位将被认作是符号位。这样以来,0FFFFFFFFh
0FFFFFFFFh
将被认为是十进制的 -1-1-1-1。例如,你计算 0FFFFh * 10h + 0FFFFh ( 8086 CPU 所能访
Word
Signed
Signed
Word
Signed 和 Word
问的最大内存地址)。如果你选中 Signed
Word 选项,结果是 -17 (因为表达式被
Signed
Signed
认为是 (-1) * 16 + (-1) )。如果想按照无符号数计算,请不要选择 Signed
Signed 表达式
Number
Convertor
Convertor
Number
为 65535 * 16 + 65535 计算结果将是 1114095 同样你可以使用 Number
Convertor 将非
Number Convertor
符号的十进制
符号的十进制
十进制换算为有符号的十进制
符号的十进制,然后根据十进制计算。支持如下运算:
~~~~
****
////
%%%%
++++
----
notnotnotnot
(inverts allallallall bits).
(inverts
bits).
(inverts
bits).
(inverts
bits).
multiply.
multiply.
multiply.
multiply.
divide
divide
divide
divide.
modulus
modulus
modulus
modulus.
sumsumsumsum.
subtract
subtract
subtract
subtract (and
unary
(and(and(and unary
unary -).-).-).-).
unary
<<<<<<<<
shift
left.
shift
left.
shift left.
shift
left.
>>>>>>>>
&&&&
^^^^
shift
right.
shift
right.
shift right.
shift
right.
bitwise
bitwise ANDANDANDAND.
bitwise
bitwise
bitwise
bitwise XORXORXORXOR.
bitwise
bitwise
bitwise
bitwise OR.OR.OR.OR.
bitwise
bitwise
||||
二进制必须有“b”作结尾,例如 00011011b 十六进制必须有"hhhh"作结尾,另外,当地一位
是字母时,最前面必须加上0,例如:0ABCDh 八进制必须有"oooo"作结尾,例如:77o
什么是汇编语言?
汇编语言是底层编程语言。为了学习这门语言,你需要对于计算机结构有所了解。计算
机系统模型如下:
系统总线系统总线系统总线系统总线 system
system
system busbusbusbus(图中黄色部分)是将计算机各个部分连接到一起的部件。CPUCPUCPUCPU 是计
system
算机的心脏,大部分的运算都是在 CPU 中完成的。RAMRAMRAMRAM 是读取并且存放将要执行的程序的地
方。
CPUCPUCPUCPU 内部内部内部内部
通用寄存器
8086CPU 有 8 个通用寄存器,每一个寄存器都有自己的名称:
•
•
•
•
•
•
•
•
AXAXAXAX 累加寄存器 accumulator register(分为 AHAHAHAH //// ALALALAL).
BXBXBXBX 基址寄存器 base address register (分为 BHBHBHBH //// BLBLBLBL).
CXCXCXCX 计数寄存器 count register(分为 CHCHCHCH //// CLCLCLCL ).
DXDXDXDX 数据寄存器 data register (分为 DHDHDHDH //// DLDLDLDL).
SISISISI 源变址寄存器 source index register.
DIDIDIDI 目的变址寄存器 destination index register.
BPBPBPBP 基址指针寄存器 base pointer.
SPSPSPSP 堆栈寄存器 stack pointer.
编程中,由程序员决定通用寄存器的具体用途。寄存器的主要目 的是保存数值(变量)。
0011000000111001b
12345
0011000000111001b
12345
0011000000111001b (二进制),或者 12345
上面提到的寄存器是 16 位的,意思是: 0011000000111001b
12345(十
进制形式)。4 个通用寄存器(AX, BX, CX, DX) 在使用时分为两个 8 位寄存器,例如 假设
00111001
00110000bbbb AL=00111001
00110000
00111001bbbb,AH=00110000
00111001
00110000
00111001bbbb。
00110000
00111001
00110000
00111001
0011000000111001
AX= 00110000
当你修改其中任意 8 位值,整个 16 位寄存器的值同样改变。同样对于其他的 3 个寄存器,
“H”表示高 8 位,“L”表示低 8 位。寄存器在 CPU 内部,访问中它们速度远远超过内存。
因为,访问内存需要经过系统总线,所以时间要长一些。而访问寄存器中的数据几乎不需要
时间。于是,编程中,应当尽量在寄存器中保存数据。虽然寄存器很小,并且这些寄存器都
有具体用途,但他们依然是存放计算中临时数据的好地方。
段寄存器
•
•
•
•
CSCSCSCS 代码段寄存器,用来存放当前正在运行的指令
DSDSDSDS 数据段寄存器,用来存放当前运行程序所用的数据
ESESESES 附加段寄存器,由程序员决定用途
SSSSSSSS 堆栈段寄存器,指出堆栈所在区域
尽管容许在段寄存器中存放任何数据,但是这决不是 一个好主意。段寄存器有着非常特别
的目的--指出可以访问内存块的地址。段寄存器与通用寄存器协同工作就可以访问任意的
12345h
12345h
内存区域。例如,如果我们打算访问物理地址是 12345h
12345h(十六进制)的内存单元,我们应
0045h
1230h SISISISI ==== 0045h
1230h
设置 DSDSDSDS ==== 1230h
1230h
0045h
0045h 这样以来,我们便能访问超过一个寄存器(16 位)所能表
示的内存地址的范围。CPU 计算物理地址的方法是将段寄存器乘以 10H 在加上一个特定的通
用寄存器。(1230h * 10h + 45h = 12345h):
这种,由两个寄存器生成的地址被称为有效地址 (effective address)
默认下,BX, SI 及 DI 与 DS 协同工作,BP SP 与 SS 寄存器协同工作。其余的通用寄存
器不能形成有效地址!同样,尽管 BX 可以形成有效地址,但是 BH BL 不能!控制寄存 IP 指
令指针寄存器 instruction pointer 、Flags Register 状态标志寄存器
IP 始终同 CS 协同工作,指出当前执行的指令。 Flags Register 完成一次数学运算后,
由 CPU 自动修改,通过它可以得到当前结果类型,也可以作为跳转语句条件。通常你无法直
接访问它们。
寻址方式
我们可以通过下面的四个寄存器来寻址 BX, SI, DI, BP.
通过计算[]符号中的值,我们可以访问到不同内存单元的值。具体组合请看下表:
[BX + SI]
[BX + DI]
[BP + SI]
[BP + DI]
[SI] + d8
[DI] + d8
[BP] + d8
[BX] + d8
[SI]
[DI]
d16 (variable offset only)
[BX]
[BX + SI] + d8
[BX + DI] + d8
[BP + SI] + d8
[BP + DI] + d8
[BX + SI] + d16
[BX + DI] + d16
[BP + SI] + d16
[BP + DI] + d16
[SI] + d16
[DI] + d16
[BP] + d16
[BX] + d16
d8 - 表示8位偏移量 d16 - 表示16位偏移量
偏移量可以是一个立即数或者是一个变量的偏移,或者二者兼备。这取决于编译器如何计算
单独的立即数。偏移量可以在[]符号里面或者外面,这不影响编译器生成相同的机器码。
偏移量是一个有符号数,可以是正数或者负数。一般说来,8 位或者 16 位,对于编译后的
结果是有影响的。例如,假定 DS = 100, BX = 30, SI = 70。
如下寻址方式 [BX + SI] + 25 计算物理地址为 100 * 16 + 30 + 70 + 25 = 1725
默认下,DS 寄存器应用在除了 BP 寄存器之外的所有物理地址计算中,寄存器是和 SS 寄存
器一起工作的。用过下面的表,你可以和轻松记住谁和谁是关联在一起使用的。
上表中,你可以从每一列中选择一个或者忽略任意一个列。比如,可以看到,BX 和 BP 始
终不会选到一起。SI 和 DI 不会选到一起。这是一个计算地址模式[BX+5] 段寄存器(CS, DS,