几个小问题

  • 什么是机器语言?
    机器语言: 由二进制数字构成的程序, CPU 可以直接对其解释、执行。 不仅是汇编语言, 用C语言、Java等编程语言编写的程序, 也都需要先转换成机器语言才能被执行。 机器语言有时叫做“ 原生代码” (Native Code)

  • 通常把标识内存或 I/O 中存储单元的数字称为什么?
    表示内存或 I/O 中存储单元的数字叫作 “ 地址” 。 内存中有多个数据存储单元。 计算机用从 0 开始的编号标识每个存储单元, 这些编号就是地址(Address)。 I/O 寄存器也可以用地址来标识。 哪个寄存器对应哪个地址, 取决于 CPU 和 I/O 之间的布线方式。

  • CPU 中的标志寄存器(Flags Register)有什么作用?
    一旦执行了算数运算、逻辑运算、 比较运算等指令后, 标志寄存器并不会存放运算结果的值, 而是会把运算后的某些状态存储起来,例如运算结果是否为 0、 是否产生了负数、是否有溢出(Overflow)等。

本章的目标是通过编写程序使诸位亲身体验计算机的运行机制。为了达到这个目的,就需要使用一种叫作“汇编语言”的编程语言来编写程序,然后再把编好的程序通过手工作业转换成 CPU 可以直接执行的机器语言。

这样的转换工作叫做“ 手工汇编”(Hand Assemble)。

3.1 从程序员的角度看硬件

为了体验手工汇编, 下面我们就为之前制作的微型计算机编写一个程序, 因为程序的作用是驱动硬件工作, 所以在编写程序之前必须先了解微型计算机的硬件信息,真正㤇了解的硬件信息只有以下 7 种。
【CPU(处理器)信息】

  • CPU 的种类
  • 时钟信号的频率

【内存信息】

  • 地址空间
  • 每个地址中可以存储多少比特的信息

【I/O 信息】

  • I/O 的种类
  • 地址空间
  • 连接着何种周边设备

可以使用哪种机器语言取决于 CPU 的种类。 所谓机器语言就是只是用 0 和 1 两个进制书写的编程语言。 即便是相同的机器语言, 例如 01010011, 只要 CPU的种类不同,对它的解释也就不同, 有的 CPU会把它解释成是执行加法运算, 有的 CPU 把它解释成向 I/O 输出。 不同的 CPU 对机器语言的解读是不同的。

我们之前所使用的 CPU是 Z80 CPU, 所有要使用适用于 Z80 CPU 的机器语言。 顾名思义, 机器语言就是处理器可以直接理解的编程语言。 机器语言有时也叫作原生代码(Native Code)。

所谓时钟信号的频率,就是由时钟发生器发送给 CPU 的电信号的频率, 表示时钟信号频率的单位是 MHZ。微型计算机使用的是 2.5MHz 的时钟信号。 时钟信号是在 0 和 1两个数之间反复变换的电信号, 就像滴答滴答右摆动的钟摆一样,通常把发出一次滴答的时间称作一个时钟周期。

在机器语言当中,指令执行时所需要的时钟周期数取决于指令的类型

程序员不但可以通过累加时钟周期数估算程序执行的时间
还可以仅在特定的时间执行点亮 LED(发光二极管)等操作。

时钟发生器赋予了计算机时间的概念, 就像钟表赋予了我们时间的概念,有了时间的概念, 进程等概念才能建立。

每个地址都标示着一个内存中的数据存储单元,而这些地址所构成的范围就是内存的地址空间, 在我们的微型计算机中,地址空间为 0~ 255(28), 每一个地址中可以存储 8比特的指令和数据。

连接着 I/O 的种类,就是指连接着微型计算机和周边设备的 I/O 的种类。 在微型计算机中,只安装了一个 I/O ,即上面有 4 个 8 比特寄存器的 Z80 PIO。 只要用 CPU 控制 I/O 的寄存器, 就可以设定 I/O 的功能, 与周边设备进行数据的输入输出。

所谓 I/O 的地址空间, 是指用于指定 I/O 寄存器的地址范围。 在 Z80 PIO 上, 地址空间为 0 ~ 3, 每一个地址对应于一个寄存器。

在内存中,每个地址的功能都一样,既可用于存储指令又可用于存储数据

而 I/O 则不同,地址编号不同(即寄存器的类型不同),功能也就不同。在微型计算机中,是这样分配 Z80 PIO 上的寄存器的:

  • 端口 A 数据寄存器对应 0 号地址,
  • 端口 B 数据寄存器对应 1 号地址,
  • 端口 A 控制寄存器对应 2 号地址,
  • 端口 B 控制寄存器对应 3 号地址。

端口 A 数据寄存器和端口 B 数据寄存器存储的是与周边设备进行输入输
出时所需的数据。其中,端口 A 连接用于输入数据的指拨开关,端口B 连接用于输出数据的 LED。
而端口 A 控制寄存器和端口 B 控制寄存器则存储的是用于设定 Z80 PIO 功能的参数。

3.2 机器语言和汇编语言

这段程序之前已经介绍过了, 功能是把由指拨开关输入的数据输入CPU, 然后CPU 再把输入数据原封不动地输出到 LED。 也就是说,通过拨动指拨开关控制 LED 的亮或灭。

这段由 8个比特二进制构成的机器语言程序总共 23 个字节, 若把这些字节一一依次写入内存中,所占据的内存空间就是 00000000~ 00010110 。 一旦重置了 CPU, CPU就会从 0 号地址开始顺序执行这段程序。

在机器语言程序中,虽然到处都是 0 和 1的组合, 但是每个组合都是有特定含义的指令或数据, 可是对人来说, 如果只看 0 和 1的话,很难判断出各个组合都表示什么。

我们需要面向人类的语言

于是有人发明出了一种编程方法, 根据表示指令功能的英语单词起一个相似的昵称, 并将这个昵称赋予给 0 和 1 的组合。 助记符的诞生, 使用助记符的编程语言叫做 “ 汇编语言” 。

无论使用机器序言和还是汇编语言,所实现的功能都是一样的。

区别只在于程序是用于数字表示还是用助记符表示。

以上的机器语言可以转换成如下所示的汇编语言, 汇编语言的语法十分简单,以至于语法只有一个, 即把“标签” “操作码(指令)”和“操作数(指令的对象)”并排写在一行上,仅此而已。

  • 标签的作用是为该行代码对应的内存地址起一个名字。 用汇编语言编程时可以在任何需要标签的地方“ 贴上” 名称任意的标签。 在上图中, 使用了名称为 “ LOOP:” 的标签。
  • 操作码就是表示“ 做什么” 的指令。 因为用助记符表示的指令是英语单词的缩写, 比如 LD 是 Load(加载)的缩写,所以较容易理解, 汇编语言中提供了多少种助记符, CPU 就有多少种功能。

Z80 CPU 的指令全部加起来有 70 条左右。 这里先把主要的指令列在表中, 在浏览的过程中请注意这些指令的分类, 按功能这些指令可以分成运算、 与内存的输入输出和与 I/O 的输入输出三类,这是因为计算机能做的事业只有输入、运算、输出这三种了。

  • 操作数表示的是指令执行的对象。 CPU 的寄存器、内存地址、I/O地址或者直接给出的数字都可以作为操作数

如果某条指令需要多个操作数, 那么它们之间要用逗号分割。 操作数的个数取决于指令的种类。 也有不需要操作数的指令,比如用于停止 CPU 运转的 HALT 指令。

将汇编语言语法总结一下:

操作(指令)发生的场所 - 操作作用于 -某个对象标签                           操作码       操作数

进制的转换

  • 机器语言: 二进制
  • 汇编语言; 十进制和十六进制。

这里是一些Z80 CPU 的主要指令:

3.3 Z80 CPU 的寄存器结构

我们之前讲过 CPU负责解释、执行程序, 从内存或 I/O 输入数据,在内部进行运算,再把运算结果输出到内存或 I/O , 内存中存放着程序, 程序是指令和数据的集合。 I/O 中临时存放着用于与周边设备进行输入输出的数据。

既然数据的运算是在 CPU中进行的, 那么在 CPU 中应该有存储数据的地方, 这种存储数据的地方叫做 “寄存器” ,虽然和 I/O 的寄存器都叫一个名字, 但是有着不同的地方, CPU的寄存器不仅能存储数据, 还具备对数据进行运算的能力。

CPU带有什么样的寄存器取决于 CPU 的种类

如下所示: ,A、B、C、D等字母是寄存器的名字。在汇编语言当中,可以将寄存器的名字指定为操作数。

IX、IY、SP、PC 这 4 个寄存器的大小是 16 比特,其余寄存器的大小都是 8 比特。寄存器的用途取决于它的类型。有的指令只能将特定的寄存器指定为操作数。

举例来说, A寄存器也叫做 ‘’累加器 ” , 是运算的核心。 所以连接到它上面的导线也一定会比其他寄存器多。

F 寄存器也叫作“标志寄存器”,用于存储运算结果的状态,比如是否发生了进位,数字大小的比较结果等。

PC 寄存器也叫作“程序指针”,存储着指向 CPU 接下来要执行的指令的地址。PC 寄存器的值会随着滴答滴答的时钟信号自动更新,可以说程序就是依靠不断变化的 PC 寄存器的值运行起来的。

SP寄存器 也叫作“栈顶指针”,用于在内存中创建出一块称为“栈”的临时数据存储区域。

寄存器有了一定的了解后。再来看一下之前代码的内容。

这段程序大体上可以分为两部分

  • 设定 Z80 PIO
  • 与 Z80 PIO 进行输入输出

Z80 带有两个端口(端口 A 和端口 B),用于与周边设备输入输出数据。 首先必须为每个端口设定输入输出模式。

  • 首先必须为每个端口设定输入输出模式

这里端口 A用于接收由指拨开关输入的数据, 为了实现这个功能, 需要如下代码。

LD A, 207  -- 把数值 207 写入到寄存器 A 中
OUT (2), A -- 把寄存器 A 的值写入到地址 2 (I/O所对应的 A控制寄存器)中
LD A, 255 -- 把数值 255 写入到寄存器 A中
OUT (2), A  -- 把寄存器 A的值写入到 地址 2中

这里的 207 和 255 是连续向 Z80 PIO 的端口 A控制寄存器(对应地址编号为 2)写入的两个数据, 虽然使用 OUT 指令可以向 I/O 写入数据,但是不能直接把 207、 255 这样的数字作为 OUT 指令的操作数, 操作数必须是已存储在 CPU 寄存器中的数字,这是汇编语言的规定

一旦把 207 写入到端口 A控制寄存器, Z80 PIO 就明白了(想要设定端口 A的输入输出模式)。通过接下来写入的 255, Z80 PIO 就又知道(要把端口 A设定为输入模式)。

端口 B设定为输出模式

LD A, 207
OUT (3), A
LD A, 0  --与 255对应,将端口 B 设定为输出模式
OUT (3), A

完成了 Z80 PIO 的设定后, 就进入了一段死循环处理, 用于把由直播开关输入的数据输出到 LED。

LOOP: IN A, (0)  --不断从地址 0 (端口 A数据寄存器)中读取数据,输入到 CPU的寄存器 A中OUT (1), A -- 把寄存器 A的值写入到地址 1 (B数据寄存器上)JP LOOP  --跳转到 LOOP 继续执行指令

补充:
地址 0 —— 端口 A数据寄存器
地址 1 —— 端口 B数据寄存器
地址 2 —— 端口 A控制寄存器
地址 3 —— 端口 B控制寄存器

3.4 追踪程序的运行过程

** 用汇编语言编写的程序是不能直接运行的,必须先转换成机器语言。

CPU只能理解机器语言, 无论是什么语言都必须最后转化为机器语言。

看下图所示,里面列出了实现转换出来的机器语言,以及对应的汇编语言。

1条汇编语言的指令所对应的机器语言由多个字节构成。
有的指令对应着 1 个字节的机器语言,有的指令则对应着多个字节的机器语言。
汇编语言中的 1 条指令能转换多少条机器语言取决于指令的种类以及操作数的个数。

。代码清单 3.3 中第一个内存地址是 00000000(0 号地址),下一个地址是 00000010(2 号地址),中间隔了 2 个地址,这说明如果从 0 号地址开始存储一条 2 字节的机器语言,那么下一条机器语言就从 2 号地址开始存储。

在这里,我们假设机器语言的程序是向上图代码一样被存储到内存中。

  • 一旦重置了CPU, 00000000就会自动存储到 PC 寄存器中, 这意味着接下里 CPU 将要从 00000000号地址读出程序。

  • 首先 CPU 会从 0000000号地址 读出指令 00111110, 判断这是一个 2个字节构成的指令,紧接着寻找指令的对象(数据)

  • 接下来会从下一个地址读出数据 11001111,把这两个数据汇集到一起解释、执行。 执行的指令是把数值 207 写入到寄存器 A, 用汇编语言表示的话就是“LD A, 207”

由于刚刚从内存读出了一条 2 字节的指令(占用 2 个内存地址),所以 PC 寄存器的值要增加
2,并接着从 00000010 号地址读出指令,解释并执行。

接下来的流程与此类似,通过反复进行“读取指令”“解释、执行指令”“更新 PC 寄存器的值”这 3 个操作,程序就能运行起来了。一旦执行完最后一行的 JP LOOP 所对应的机器语言,PC 寄存器的值就会被设为标签 LOOP 对应的地址 00010000,这样就可以循环执行同样的操作。请诸位重点观察 PC 寄存器是如何控制程序流程的。

3.5 尝试手工汇编

在 CPU 的资料中,明确写有所有可以使用的助记符,以及助记符转换成机器语言后的数值。只要查看这些资料,就可以把用汇编语言编写的程序手工转换成机器语言的程序,这样的工作称为“手工汇编”。进行手工汇编时,要一行一行地把用汇编语言编写的程序转换成机器语言。

下面就实际动手试一试吧。表 3.2 列出了汇编语言中必要指令的助记符、助记符所对应的机器语言,以及执行这些机器语言所需的时钟周期数。
下面就从汇编语言的第 1 行开始转换。第一行的“LD A, 207”匹配“LD A, num”这个模式,所以可以先转换成“00111110 num”。然后将十进制数的 207 转换成 8 比特的二进制数,用这个二进制数替换 num。使用 Windows 自带的计算器程序就可以很方便地把十进制数转换成二进制数。从 Windows 的开始菜单中选择“运行”,输入 calc 后点击“确定”按钮,就可以启动计算器程序。

可以理解为助记符 LD A ,num分为两部分组成,一部分表示为操作行为,比如往寄存器中输入数值(num):这里转化为 00111110 ,另一部分是操作对象(数值 num),然后将助记符中的 num(十进制数) 转化为机器语言的 num(二进制数)。

在计算器中, 207 的二进制为 11001111 ,至此, “LD A 207” 就转换成了机器语言 00111110 11001111 。 由于这条指令存储在内存最开始的部分(00000000号地址),因为它是第一条指令。所以要把这条指令和内存地址想像下面这样并排写下来。


第二部分一样,最终就得到了机器语言 “ 11010011 00000010” ,因为之前内存中已经存储了 2 自己解的机器语言, 所以这条机器语言从 00000010 号地址开始记录。

在这里, 内存中存储如下:

一点重要知识

到最后一句的 JP LOOP 匹配模式 “ JP num”,所以可以先转换成“11000011 num”。

请注意**这里要用 16 比特的二进制数替代作为内存地址的 num**。

在微型计算机中是以 8 比特为单位指定内存地址的,但在Z80 CPU 中用于设定内存地址的引脚却有 16 个,所以在机器语言中也要用 16 比特的二进制数设定内存地址。JP 指令跳转的目的地为00010000,即“LOOP:”标签所标示的语句“LD A, 0”对应的内存地址。把这个地址扩充为 16 比特就是“00000000 00010000”。要扩充到16 位,只需要把高 8 位全部设为 0 就可以了。


还有一点希望诸位注意,在将一个 2 字节的数据存储到内存时,存储顺序是低 8 位在前、高 8 位在后(也就是逆序存储)。这样的存储顺序叫作“小端序”(Little Endian).

与此相反,将数据由高位到低位顺序地存储到内存的存储顺序则叫作“大端序”(Big Endian)。根据CPU 种类的不同,有的 CPU 使用大端序,有的 CPU 使用小端序。Z80CPU 使用的是小端序,因此 JP LOOP 对应的机器语言为“11000011 00010000 00000000”。

3.6 尝试估算程序的执行时间—— 拓展

一直没有考虑过计算机的时间变化问题,在看了这本书之后对计算机的理解又更深了一个层次。

请先向前翻到表 3.2,找出执行每条汇编语言指令所需的时钟周期数。然后把代码清单 3.2 中所用到的每条指令的时钟周期数累加起来。于是可以算出到 LOOP 标签为止的 8 条指令共需要 7+11+7+11+7+11+7+11 = 72 个时钟周期;LOOP 标签之后的 3 条指令共需要 11+11+10 = 32 个时钟周期。

因为微型计算机采用的是2.5 MHz 的晶振, 也就是 1 s 可以产生 250 万个时钟周期。

所以每个时钟周期是 1秒 ÷ 250 万 = 0.0000004 秒 = 0.4 微秒。72 个时钟周期就是 72×0.4 = 28.8 微秒;32 个时钟周期就是 12.8 微秒。

这段程序是用 LED 的亮或灭来表示指拨开关的开关状态,所以 LOOP 标签之后所执行的操作“输入、输出、跳转”每 1 秒可以反复执行 1 秒 ÷12.8 微秒 / 次 = 78125 次之多,可见计算机的计算速度有多么惊人。

《计算机是怎样跑起来的》之 体验一次手工汇编相关推荐

  1. 计算机是怎样跑起来的

    一直对「程序如何在计算机中跑起来的」很感兴趣,也看过一些相关的书籍和文章,前段时间在多看阅读上看到一本相关的书,用了几天时间看完后,觉得很不错,用简单易懂的语言,围绕计算机是怎样跑起来的,把相关的知识 ...

  2. 计算机是怎样跑起来的(读书笔记)

    计算机是怎样跑起来的 计算机的三大原则 计算机的三个根本性基础 输入.运算.输出是硬件的基础 软件是指令和数据的集合 计算机的处理方式和人们的思维习惯不同,对计算机来说什么都是数字 只要理解了三大原则 ...

  3. 《计算机是怎样跑起来的》读书笔记

    目录 · · · · · · 第1章 计算机的三大原则 1 p2 什么是编码? 就是把不是数字的信息转成用数字表示,如:字符编码.颜色编码 1.1 计算机的三个根本性基础 3 p3 计算机的三大要点? ...

  4. 王和平的《计算机是怎样跑起来的》学习笔记

    第1章 计算机的三大原则 初级问题 硬件和软件的区别是什么? 中级问题 存储字符串"中国"需要几个字节? 高级问题 什么是编码(Code)? 初级问题: 硬件是看得见摸得着的设备, ...

  5. 计算机是怎样跑起来的(1)

    看了一下目录,嘶,这不是几天就能读完的,有点困难 后记:看起来难而已,很简单,两天就看完了 计算机的三大原则 1. 计算机是执行输入.运算.输出的机器 2. 程序是指令和数据的集合 3. 计算机的处理 ...

  6. 《计算机是怎样跑起来的》小结

    版权声明:本文为博主原创文章,未经博主允许不得转载 前言: 真正的了解计算机,探索其本质,培养对技术本质的兴趣. 不要把技术当作是黑盒子. 如何学习一门学问:(1)要划出一个"知识的范围&q ...

  7. 《计算机是怎样跑起来的》最全读书笔记--Binrry(冰蕊)

    点击关注,期待Binrry(冰蕊)带给你更多更全的读书笔记-- 这是一本浅显易懂.图文并茂的计算机基础书. 目录 第1章 计算机的三大原则 问题----------------------- 初级问题 ...

  8. 《计算机是怎样跑起来的》学习笔记

    <计算机是怎样跑起来的>学习笔记 前言 1 计算机的三大原则 2 试着制造一台计算机吧 3 体验一次手工编程 4 程序像河水一样流动着 5 与算法成为好朋友的七个要点 5.1 算法中解决问 ...

  9. 计算机是怎样跑起来的笔记摘要

    文章摘抄于矢泽久雄的<计算机是怎样跑起来的>,用于个人学习,内容有不当或错误的地方请见谅.让我们一起学习,共同进步. 文章目录 第一章 计算机三大原则 1.1三个根本性基础 1.2计算机网 ...

最新文章

  1. 关于linux安装前规划分区二三事
  2. 详细讲解-sphinx配置文件
  3. [论文阅读] (03) 清华张超老师 - GreyOne: Discover Vulnerabilities with Data Flow Sensitive Fuzzing
  4. 极速搭建一个个人博客网站
  5. decode 大于比较 小于_6 燃气输配系统6.3 压力不大于1.6Mpa的室外燃气管道城镇燃气设计规范 GB500282006(2020修订版)...
  6. 数据库事务隔离级别-- 脏读、幻读、不可重复读(清晰解释)
  7. HTML中禁用表单控件的两种方法readonly与disabled
  8. 【网站推荐】Solaris 平台编写设备驱动程序
  9. AJAX验证jsp页面验证码
  10. Jquery选择器大全汇总
  11. python入门视频教程-Python入门视频全套教程
  12. [转载] Python OpenCV 基础教程
  13. 用python解算法谜题_【编程的乐趣-用python解算法谜题系列】谜题一 保持一致
  14. 桌面在计算机哪个文件,计算机中win7系统桌面文件在c盘哪个文件夹
  15. WebRTC NACK
  16. mysql将公历农历转换_SQL农历转换函数(显示中文格式,加入润月的显示)
  17. jle汇编_x86汇编指令集大全(带注释)
  18. mysql热备工具_MySQL热备工具Xtrabackup
  19. ECC与Pairing前沿调研
  20. Minecraft1.15 FuHyMC 进服方法

热门文章

  1. 使用cmd命令查看电脑是不是翻新机 如何查看自己电脑是不是翻新机
  2. java工厂模式三种详解(部分转载)
  3. 【网络安全】利用burp进行爆破(普通爆破+验证码爆破)
  4. 男人二十岁后应该学会的东西
  5. mp3gain中文版(MP3调音器)
  6. C语言文法(BNF)
  7. Quartus-II两种方式实现D触发器及时序仿真和波形验证
  8. 虚拟机下安装linux mysql weblogic过程
  9. xgp游戏列表_XGP新增13款游戏:《生化危机7》、《废土3》在列
  10. 群辉+picgo+typora搭建自有图床