从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • 计算机简史

  • 数字电路

  • 计算机组成原理

    • 计算机组成原理(北大-陆俊林)

      • 概述-计算机组成原理(北大-陆俊林)
      • 第1周-计算机组成章节视频简介
      • 101-电子计算机的兴起
      • 102-冯·诺依曼结构的要点
      • 103-冯·诺依曼结构的小故事
      • 104-计算机结构的简化模型
      • 105-计算机执行指令的过程
      • 106-计算机输入和输出
      • 107-冯诺依曼结构和具体实现
      • 201-设计自己的计算机
      • 202-x86 体系结构
      • 203-x86 指令简介
      • 204-复杂的 x86 指令举例
      • 205-MIPS 体系结构
      • 206-MIPS 指令简介
      • 301-算术运算和逻辑运算
      • 302-门电路的基本原理
      • 303-寄存器的基本原理
      • 304-逻辑运算的实现
      • 305-加法和减法的实现
      • 306-加法器的优化
      • 401-乘法的运算过程
      • 402-乘法器的实现
      • 403-乘法器的优化 1
      • 404-乘法器的优化 2
      • 405-除法的运算过程
      • 406-除法器的实现
      • 407-除法器的优化
      • 501-处理器的设计步骤
      • 502-数据通路的建立
      • 503-运算指令的控制信号
      • 504-访存指令的控制信号
      • 505-分支指令的控制信号
      • 506-控制信号的集成
      • 601-流水线的基本原理
      • 602-流水线的优化
      • 603-超标量流水线
      • 604-流水线的冒险
      • 605-数据冒险的处理
      • 606-控制冒险的处理
      • 701-存储层次结构概况
      • 702-DRAM 和 SRAM
      • 703-主存的工作原理
      • 704-主存技术的发展
      • 705-高速缓存的工作原理
      • 706-高速缓存的组织结构
      • 707-存储容量的计算
      • 801-中断和异常的来源
      • 802-中断向量表的结构
      • 803-中断向量表的发展
      • 804-中断的处理过程
      • 805-内部中断分类说明
      • 806-基于中断的功能调用
      • 901-输入输出接口的基本功能
      • 902-输入输出接口的编址方式
      • 903-输入输出的控制方式
      • 904-中断控制方式
      • 905-外部中断的处理过程
      • 906-直接存储器访问方式
    • 字符编码入门

  • 操作系统

  • Linux

  • 计算机网络

  • 数据库

  • 编程工具

  • 装机

  • 计算机基础
  • 计算机组成原理
  • 计算机组成原理(北大-陆俊林)
2023-06-13

201-设计自己的计算机

# 201-设计自己的计算机

什么是指令系统体系结构呢? 要回答这个问题,其实非常的简单。但是想解释清楚,也没有那么容易。我们还是从一个小故事开始吧。

‍

有一天两个小伙伴碰了面,发现对方都很愁苦,一个就问另一个 "嘿你在愁苦什么呀?" 这个说"唉呀,最近遇到了很多运算上的问题。" "运算量好大呀。"对应说,"可不是吗,我也遇到了类似的问题。" "咱们怎么解决呢?" "不如咱们一起设计一个计算机吧!" 就说好啊,两人就一拍即和。 "我们设计计算机怎么分工呢?"一个说,"我显然是软件程序员,我来编写如何运算的软件指令。" 另一个说"那正好,我是硬件工程师,我来设计计算机的硬件,主要是 CPU,那咱们就分头工作吧!" "这事估计得花一年时间才能把 CPU 设计出来,也才能把软件写好。真的就可以这么开始了吗?一年之后我们在碰面,怎么保证你写的软件就能在我做的 CPU 上运行起来呢?" "所以还不能着急,咱们得商量商量,得把咱们的共同规则订好,然后呢才能分头去设计软件和硬件,这样保证之后我们在碰面的时候 软件和硬件能顺利的结合在一起。" 那好,这两个小伙伴就开始商量了,他们要商量的是什么呢? 就是我们要谈的指令系统体系结构。 ‍ 他们要面临的计算任务并不复杂,所以只要一个很简单的计算机指令系统就可以了。 我们要设计多少指令、要设计哪些指令,首先要根据需求来确定。 那看上去我们只需要一些简单的加法。所以首先,我们需要设计一个加法指令。 那这些指令和要运算的数据,都是要放在存储器当中的,如果直接把两个存储器当中的数字相加, 可能会比较复杂。所以我们指令系统设计的时候呢,这个加法指令是这么做的: 将一个寄存器当中的数,和一个存储器当中的数相加,然后存到这个寄存器当中。 寄存器我们用 R 来表示,存储器当中的地址用 M 来表示。 所以我们这个指令系统当中,包含了一条运算类的指令。

但是寄存器当中的数从哪里来呢?自然是从存储器当中来。 把存储器当中的内容,装到寄存器当中来,这条指令就是 LOAD。 就是将后面一个操作数 M,所指向的内存单元中的内容放到前一个操作数 R 所指向的 寄存器当中。有了这两条指令之后,我们可以对内存当中的数 进行加法运算了。但是运算的结果还在寄存器当中。

所以我们还需要一条指令,把寄存器当中的数,再放回到存储器当中。 这条指令,我们记为 STORE,它的作用是将寄存器 R 当中的数, 存入到 M 所指定的存储单元中。这两条指令用于在存储器和寄存器中间传送数据,所以我们称之为传送类的指令。

我们已经知道 CPU 是从内存当中,按照地址,依次取出指令开始执行的, 那有时候我们想改变取指令的位置,这时候就需要用到这条指令,记作 JMP L, 当 CPU 执行这条指令之后,就会转移到 L 所指向的存储器单元中去取出下一条指令来执行, 这样的指令我们称为转移类指令。 然后我们就设计好了我们想要的计算机的指令系统,虽然它很简单,但足够完成我们想要的运- 算任务了。

​

但这还是用英文单字和字母进行的描述,并不是计算机所能识别的二进式代码。 因此我们还要做近一步的规定。这就是指令的具体格式, 首先我们约定,每条指令都是等长的,都是两个字节。 其中第一个字节,我们取了高四位作为操作码,操作码 就是指明了这是一条什么类型的指令。我们现在有四条指令, LOAD、ADD、STORE 和 JMP,我们分别给它分配了四个不同的操作码。 用十进制来表示就是 0、1、2、3, 因为我们预留了四个二进制位,所以以后还可以扩展,最多可以扩展到 16 条指令。 但是现在我们只定义了四条指令, ‍ 接着看第一个字节的低四位,这个四位我们约定了作为寄存器号, 我们现在提供四个寄存器,编号从 0000 到 0011,分别指代 CPU 当中的 R0 到 R3 这四个寄存器, 由于我们预留了四个二进制位,所以以后还可以继续扩展,最多到十六个寄存器。 那就这为我们发展第二代、第三代以及之后的设计时,提供了扩展的空间。

​

这个指令的第二个字节, 我们约定作为存储单元的地址,这样有八个二进制位, 所以我们一共可以使用 2 的八次方,也就是 256 个字节的存储器。 我们看一个例子。如果软件设计人员写了这么一条指令:0001 0010 0000 1001,那从操作码 这四位我们就可以看出来它是一个加法指令。 从这四位指定的寄存器号,就可以看出来他想访问的是 R2 这个寄存器。 然后存储单元的地址,翻译成十进制的话就是 9。所以这条指令的编码想完成的操作,就是将 R2 的内容和存储单元 9 的内容相加,存到 R2 寄存器当中。

但如果软件成员写了这样的指令,0101 1010 0000 1001,如果 CPU 看到了这条指令, 那它是无法识别的,它不知道该做什么样的操作。 因为 0101 这个操作码并没有定义。 1010 这个寄存器号,也没有定义。 当然也许在第二代或第三代的设计中,我们可以再定义了 0101 是减法, 1010 可能是十号寄存器,那么在那个时候的 CPU 上,就可以执行这条指令了。但在我们约定的第一代 CPU 上显然是无法执行的。

那约定好了指令的具体格式,我们再来看一看我们可以做的运算的任务。 假设我们要完成这样一个任务,将存储器地址 M1 中的内容,与存储器 地址 M2 中的内容相加,最后存到 M3 这个存储单元当中, 在完成运算之后,程序转向,存储器当中 L 所指向的位置继续执行。 但这样的任务,我们如何用我们现在有的这个指令系统来实现呢? 我们能用的只有这四条指令,我们没有 提供直接将两个存储单元的数进行相加的指令。

这个程序应该这么写,第一步将 M1 中 的内容送到了一个寄存器,暂且记为 RX, 然后将 RX 的内容和 M2 的内容相加,运算结果存入 RX,再将 RX 的内容送到存储器 M3 当中, 这就完成了运算。再转移到 L,取出下一条指令继续执行。

​

我们假设现实在第一个任务中,M1 指向存储单元地址五,M2 指向 6,M3 指向 7,最后要转移的目标地址 L 是 18, 这几个都是十进制的描述。那基于这样的任务,我们的软件程序员就可以编写出这样的机器语言的程序, 当然初看上去全是 01 的代码,很难分辨,为了便于学习, 我将它按照不同的含义用不同的颜色表示出来。 相同的颜色代表着它们对应的关系,这样我们就可以看出来第一条指令 0000 的操作码,应该是一个 LOAD 指令, 接下来 0011 指定了寄存器的编号,所以它指向那个 R3。 第三部份是存储器的地址,这个二进制数实际上就是十进制的 5,这就可以看出来 我们是用 LOAD 这条指令,将存储单元当中,地址 5 所对应的内容,传送到了 R3 这个寄存器当中。这样我们就可以依次分析出每条指令的功能,

​

当然我还是要先强调一下,编写程序的实际的顺序。 最早的软件程序员,是需要直接编写机器语言指令的, 那么它要编写的就是中间这类的 01 编码,并把这样的 01 编码在穿孔纸带上,钻上对应的小孔,送到计算机当中去, 这样的工作,显然是非常的繁琐、容易出错,效率也很低。

那后来随着技术的进步,程序员就可以编写类似左边这一类的汇编语言程序。 汇编语言程序基本上和机器语言程序可以作到一一对应,那我们通过一些工具,就可以先将汇编语言程序转换成对应的机器语言程序,然后再将机器语言程序输送到计算机当中。 再进一步,人们又可以编写各种高级语言的程序。那当然还是需要更为复杂的工具, 将高级语言经过若干个步骤,最后还是要转换成我们这个表格中间这一列所展示的机器语言。 也就是一系列二进制代码。

现在我们已经写好了这样的程序,我们需要把这样的程序放到存储器当中去。 我们要注意的是,这只是存储器的一个片段,最左边这一列只是要存储器的地址。 我们展示了存储单元从地址 5 一直到地址 18,所保存的内容。 我们从上往下依次看,在地址 5 和 6 这两个存储单元中, 存放了两个我们需要进行运算的源操作数,现在存放的是 12 和 34. 地址单元 7 准备用来存放运算结果的。 现在被初始化为 0。地址单元 8 和 9 这两个字节,存在了 LOAD 这条指令。 为了便于观看,我还是用不同的颜色标出了不同含义的二进制位, 再往下的两个字节,是加法这条指令。 然后是 STORE 这条指令。然后是转移 JMP 这条指令。我们知道 JMP 这条指令会让 CPU 转向地址单元 18,去取出指令来。所以这里所描述的第五条指令是不会被执行的。 在执行完 JMP 这条指令以后,CPU 会取出第六条指令进行执行。

​

我们还是用大家熟悉的模型机的图示进行说明。 假想我们已经把刚才的程序和数据输送到了这个模型机的存储器当中, 与此同时,硬件工程师也设计完成了 CPU,并将 CPU 和存储器进行连接,构建成了完整的计算机的系统。 为了便于阅读,我将存储器当中二进制码进行了转换。我们可以看到,在存储 单元中,依次存放着我们要进行运算的源操作数,准备存放结果的空间, 还有包含了四条指令的这段程序。然后看右边 CPU 当中, 如果 PC 寄存器已经装入了 0000 1000 这样一个地址, 接下来的过程大家应该很熟悉了,PC 中的这个地址会通过 MAR 寄存器,再通过 地址总线送到存储器,存储器就会找到这个单元所对应的那条指令, 也就是 LOAD 这条指令,把这条指令的编码送回 CPU。接下来就会依次完成我们所编写的这个程序。

​ ‍

当然最后还有一个问题,为什么 PC 寄存器当中的地址是这个呢? 其实这是不一定的,这也是我们进行指令系统体系结构设计时。必须要约定的一个内容。 就是 CPU 在启动时,或者说在复位完成之后,第一条指令从哪里开始取出。 这也是最开始,软硬件双方必须商量好的事情。 至于这个地址到底应该是什么,并没有明确的规则。 但通常情况下,我们会约定为这个体系结构所能访问的存储单元的最小地址,也就是 0,或者是接近最高地址的地方。

那大家也可以思考一个很简单的问题,如果我们这个体系结构约定的 CPU 的 起始地址是全 0 的话,存储器当中的程序应该做怎么样的改动呢? 如果要求现在左边这个图中,已经存放的程序和数据的位置都不允许变动呢。 其实解决方法很简单。 留给大家思考。

现在我们已经对什么是指令系统体系结构有了初步的了解, 也知道如何着手开始设计一个属于自己的计算机。

从下一节开始,我们将一起分析几个真实的体系结构。 ‍

上次更新: 2025/5/9 14:55:39
107-冯诺依曼结构和具体实现
202-x86 体系结构

← 107-冯诺依曼结构和具体实现 202-x86 体系结构→

最近更新
01
语雀文档一键下载至本地教程
07-04
02
要成功,就不要低估环境对你的影响
07-03
03
血泪教训:电子设备要定期开机
07-02
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式