- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
外部结构就是封装出来的输入输出引脚。8086/8088有40个引脚.
- 8086片内片外的数据总线都是16位
- 8088片内16位,而片外8位
如此前绪论所说,部分引脚专用,部分引脚复用,复用部分需要掌握其时序.
CPU的这些引脚功能:
举个例子讲解一下这些引脚:
当CPU向外部(存储器/IO接口)写数据时,上图的WR引脚应为有效(低电平) 。
RD是读信号.
而区分操作存储器和I/O接口的是M/IO引脚 。
在此基础上可以设计逻辑电路来控制更具体的事情,比如WR和M/IO连接一个或门,就能产生IOW信号等.
8086CPU有20条地址线A 19 A<sub>16</sub>、A<sub>15</sub> A 0 ,可以寻址 \(2^{20}\) 字节的空间,也就是1M空间,地址空间大小为1MB.
总线竞争:多个设备端口同时激活.
端口如下图右下角部分所示:
具体而言,外设芯片是有手册的,当我们操作显卡,就要查VGA相关的手册,鼠标和键盘就有另一个芯片来管理.
手册上会详细说明端口的作用,在程序中用指令向端口赋值即可.
上面提到,一个IO端口至少占用一个IO地址----IO端口地址。根据端口地址和存储器是否一起编址,有:
统一编址 。
独立编制 。
举个例子 。
某个I/O端口的地址为2000H,则访问如果要输出数据到该端口,汇编语言应该这样写:
mov AL,01H
;这里是要输出的数据量,仅是一个参考
;该课程中这里要点一个灯
mov DX,2000H
mov DX,AL
;注意这里跟存储器的并不同,没有中括号
不论CPU型号如何,其内部基本都有以下结构:
ALU:必须,算术逻辑运算 。
地址寄存器可以充当数据寄存器 。
数据寄存器不能充当地址寄存器 。
控制器:负责取指令,放在指令寄存器中,译码 。
I/O控制逻辑:与外部I/O打交道,使得CPU可以响应I/O设备发出的中断请求.
这部分要与其实跟计组没多大差别了,要结合CPU"取指执行"的思想来理解.
学到这里突然想复习 流水线 Verilog 什么的了.
因为上面的图还是很笼统,怎么判断、怎么控制时序都还没有涉及。先忍住,把接口部分学完.
上图并不完整,如果从存储器中取出的是数据data而不是指令 instructions ,则直接放入数据寄存器或者指定寄存器(也不属于控制器的范畴了) 。
来自计操的补充:
- 说 堆 特指 堆
- 说 堆栈 指的是 栈
堆栈在存储器空间中,大小和位置都是编程自定义的.
8086中堆栈必须按字操作 。
堆栈操作的代表性指令是 。
push ax
pop ax
;如果是8086的按字操作规定,目的寄存器就不能是AL
堆栈基址寄存器:sp,初始置向栈底+1(也就是栈底再向下的一个存储单元),这个位置是程序设定的.
假如执行以下操作:
push ax;第1步
push bx;第2步
第1步中,sp先-2空出一个字,然后AX分高低八位分别存入这个空字的高低存储单元.
第2步重复第1步操作.
如果要pop堆栈中的值,则是上述逆过程,先取出栈顶的值,再sp+2.
堆栈溢出:
2.3节讲解的是处理器的工作思路,或是说 “取指执行”的计算机思想。下面介绍8086CPU的内部结构(仍然符合2.3节的大致思路).
有一个问题,地址总线20位,意味着可以寻址1MB地址空间;而CPU内部寄存器只有16位.
如何 用16位寄存器存放20位的地址信息 呢?
8086的设计是:讲存储器分为逻辑段,一个寄存器负责寻址段,一个寄存器负责寻址段内空间,也就是一个段内最多64KB( \(2^{16}\) byte)空间.
各种段基址寄存器以及指令寄存器就在上图BIU右上角 。
这里的转化的具体过程就是在上图的地址产生与总线控制单元进行的.
转化公式为:
CS:IP(CS左移4位+IP),也就是 。
(CS << 4) + IP 。
BIU右下角的指令队列充当的是2.3节的IR指令寄存器的角色,8086中有6个字节,8088中4个字节.
这是两个CPU内部结构唯一的区别.
总结,BIU负责外部存储器取出指令、取出数据,并将取出的指令放入指令队列,对应 “取指”。数据通过ALU总线直接送入EU.
总结放在前面:负责从指令队列中获取指令,对该指令译码并执行,对应“执行”.
这里可以看出,指令队列的存在,可以使得两个部分的性能都得到提升.
而外部总线在上图过程中始终处于忙状态,总线的使用率也上升.
8086内部 共有14个16位寄存器
通用寄存器 (EU左上角) 。
地址指针寄存器与变址寄存器 。
地址指针寄存器 。
SP:堆栈指针寄存器 。
BP:地址指针寄存器 。
BP与BX在做地址指针时的区别:
mov BX,002H mov BP,002H mov AL,34H mov [BX],AL;1 mov [BP],AL;2
1处AL值 默认 放到了数据段的BX偏移处,2处AL值 默认 放到了堆栈段的BP偏移处.
如果要使它们不默认,可以将上面代码表示地址的中括号内加上它们的目的段基址寄存器如:
mov SS:[BX],AL ;此时BX表示堆栈偏移 mov DS:[BP],AL ;此时BP表示数据段偏移
变址寄存器 。
SI:源变址寄存器 。
DI:目的变址寄存器 。
找到的都是DS段的地址 。
变址寄存器中“变”的概念来自于8086对字符串的处理.
具体涉及8086指令系统中的字符串操作指令.
如将字符串搬运到存储器另一个位置,源字符串的位置需要定义在DS:SI,目的字符串的位置定义在DS:DI.
DS:SI==(DS<<4)+SI 。
当使用movsb或movsw(无操作数指令),自动从源字符串搬运到目的字符串。(两者的区别是按字节搬运和按字搬运) 。
在这个字符串操作过程中,DI和SI是在 自动增加 的,所以其名字中的“变”不言而喻.
当DI和SI像BP一样进行普通数据段操作时,不会自己增加.
段寄存器 。
8086汇编程序结构分为若干逻辑段,汇编后放到存储器的不同段.
CS:代码段基址寄存器 。
DS:数据段基址寄存器 。
ES:附加数据段基址寄存器 。
SS:堆栈段基址寄存器 。
在代码段开始时,赋值DS ES SS,使其符合自己安排的位置,而CS由操作系统安排.
所以不会出现 mov CS,AX 。
突然感觉这个原理有点古董.
控制寄存器 。
IP:指令指针寄存器,相当于2.3节的程序计数器PC 。
代码段的偏移地址 。
PSW:处理器状态字寄存器,设置9个状态位.
6个状态位表达ALU运算后的程序状态.
控制标志:控制CPU的运行状态 。
DF方向控制,在字符串操作中,DF 0,变址寄存器SI DI自增;DF 1,SI DI自减 。
即控制SI DI的变化方向 。
IF中断允许标志,IF=1时,CPU可以响应可屏蔽中断请求(也就是外部中断);IF=0时,CPU不响应中断请求.
中断是操作系统中很重要的概念,开中断和闭中断的指令为 sti cli 。
TF陷阱标志/单步标志:TF=1时,CPU处于单步执行方式,每次执行一条指令自动执行一次特定的内部中断,具体应用就是Debug.
汇编语言中的 pushF 表示将PSW标志寄存器压栈, popF 表示将栈顶出给PSW 。
地址线:A19-A16,A15-A10,A9-A0 。
8086给存储器编址20根地址线,IO16根地址线(A0~A15) 。
在早期IBM pc机中,给IO分配A9-A0地址线来寻址1KB空间, 。
三种格式:字节型、字型、双字型 。
字节型数据:
一个字节型数据对应一个地址单元.
汇编语言设计中,字节型数据定义在存储器中的 DS段 ,具体用DB这个伪指令来定义 。
伪指令用于汇编器如何来翻译汇编代码.
字型数据:
对应两个相邻的地址单元.
定义伪指令为DW,如将字型数据5678H放入存储器0003H和0004H位置,则78H放在字的低地址0003H,56放在字的高地址0004H.
这里有一个对准和不对准的问题。如果字数据地址为奇地址,则称为未对准,偶地址则对准(比如上面的例子就是未对准) 。
对准的数据 进行 访存指令花费时间更短。未对准会多花费一个时间周期,这与数据总线的传输机制有关.
为了防止自己脑袋忘记,提示:对准情况下,高字节对应高地址,地址单元为奇,走高八位数据线(一个是线,一个是字节) 。
双字型数据:
对应两个字,也就是4个存储单元.
定义伪指令为DD.
在汇编语言中使用[BX /BP/ SI/ DI],是指 寄存器所存的内容 ,也就是地址;使用BX BP SI DI—指的是 寄存器本身 .
为什么要分段 。
如何分段:
一个逻辑段最大64K,每个逻辑段的 起始地址 必须可以被16整除 。
因此理论上讲,1MB的地址空间,可以分64K( \(2^{16}\) )个逻辑段,正好是16位寄存器可以描述的.
物理地址 。
这个上面3.1部分也提到过,要从段基址(段的起始地址)+段偏移的形式重新得到真实的物理地址.
物理地址的唯一性:
由于段相互有叠加(按照被16整除的判断标准),所以一个单元的逻辑地址只是可能不同。但是物理地址一定不同,物理地址是站在存储器全局为每个单元分配的门牌号.
虽然段在理论上(按16整除)会重叠,但实际上,汇编源程序是自己定义的各个段,操作系统分别将其装入内存, 不会发生段覆盖的情况.
编程、调试都是逻辑地址 。
物理地址(PA)的形成 。
也就是上面3.1节的转化公式.
物理地址=段基址X16(16进制左移一位)+段内偏移地址(段内有效地址).
取指令 。
CPU如何实现取指令?
CS:IP 。
即 CS(段基地址)X16+IP(段内偏移地址),取指令所存储的物理地址 。
接着8086按照计算后的物理地址去存储器找指令取出.
课程这里(11讲21分钟时)提到了无条件跳转,老师讲的是代码段间的无条件跳转.
据我所知,这部分比较复杂,老师估计是想强调一下cs:ip的存储器取指特性,所以具体的后续再提.
特性:CS和IP是用户不可写入的,CS是操作系统将代码从磁盘放入内存后初始化的,IP不可写入但是会改变,除了自增外还会跳转.
为了更明确说明物理地址的形成,再举一个例子,存储器写操作
mov [bx],ax
这就是将ax中的值写入ds:bx中去,如果硬要扯一下第3部分EU BIU的知识,那就是EU先将16位地址BX沿内部数据总线传送到BIU,BIU停下取指操作,配合EU去进行写存储器的操作,BIU将BX放到加法器中产生物理地址,输出20位物理地址后放到地址线,AX值放到数据线.
如果对齐,一个时间周期完成;如果不对齐,两个时间周期.
堆栈操作(SS:SP),跟上述过程相似.
这部分跟指令系统中的寻址方式是分不开的,指令系统会在下一部分整理.
关于各种逻辑段偏移寄存器指定与不可指定的灵活性,下面是一个小总结:
这个表里总结了操作中的默认寄存器以及可以替代的寄存器,比如取指令CS必须与IP搭配,不得自己指定寄存器寻址或者段地址.
最后此篇关于微机原理与系统设计笔记2|8086CPU结构与功能的文章就讲到这里了,如果你想了解更多关于微机原理与系统设计笔记2|8086CPU结构与功能的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我目前正在尝试基于哈希表构建字典。逻辑是:有一个名为 HashTable 的结构,其中包含以下内容: HashFunc HashFunc; PrintFunc PrintEntry; CompareF
如果我有一个指向结构/对象的指针,并且该结构/对象包含另外两个指向其他对象的指针,并且我想删除“包含这两个指针的对象而不破坏它所持有的指针”——我该怎么做这样做吗? 指向对象 A 的指针(包含指向对象
像这样的代码 package main import "fmt" type Hello struct { ID int Raw string } type World []*Hell
我有一个采用以下格式的 CSV: Module, Topic, Sub-topic 它需要能够导入到具有以下格式的 MySQL 数据库中: CREATE TABLE `modules` ( `id
通常我使用类似的东西 copy((uint8_t*)&POD, (uint8_t*)(&POD + 1 ), back_inserter(rawData)); copy((uint8_t*)&PODV
错误 : 联合只能在具有兼容列类型的表上执行。 结构(层:字符串,skyward_number:字符串,skyward_points:字符串)<> 结构(skyward_number:字符串,层:字符
我有一个指向结构的指针数组,我正在尝试使用它们进行 while 循环。我对如何准确初始化它并不完全有信心,但我一直这样做: Entry *newEntry = malloc(sizeof(Entry)
我正在学习 C,我的问题可能很愚蠢,但我很困惑。在这样的函数中: int afunction(somevariables) { if (someconditions)
我现在正在做一项编程作业,我并没有真正完全掌握链接,因为我们还没有涉及它。但是我觉得我需要它来做我想做的事情,因为数组还不够 我创建了一个结构,如下 struct node { float coef;
给定以下代码片段: #include #include #define MAX_SIZE 15 typedef struct{ int touchdowns; int intercepti
struct contact list[3]; int checknullarray() { for(int x=0;x<10;x++) { if(strlen(con
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Empty “for” loop in Facebook ajax what does AJAX call
我刚刚在反射器中浏览了一个文件,并在结构构造函数中看到了这个: this = new Binder.SyntaxNodeOrToken(); 我以前从未见过该术语。有人能解释一下这个赋值在 C# 中的
我经常使用字符串常量,例如: DICT_KEY1 = 'DICT_KEY1' DICT_KEY2 = 'DICT_KEY2' ... 很多时候我不介意实际的文字是什么,只要它们是独一无二的并且对人类读
我是 C 的新手,我不明白为什么下面的代码不起作用: typedef struct{ uint8_t a; uint8_t* b; } test_struct; test_struct
您能否制作一个行为类似于内置类之一的结构,您可以在其中直接分配值而无需调用属性? 前任: RoundedDouble count; count = 5; 而不是使用 RoundedDouble cou
这是我的代码: #include typedef struct { const char *description; float value; int age; } swag
在创建嵌套列表时,我认为 R 具有对列表元素有用的命名结构。我有一个列表列表,并希望应用包含在任何列表中的每个向量的函数。 lapply这样做但随后剥离了列表的命名结构。我该怎么办 lapply嵌套列
我正在做一个用于学习目的的个人组织者,我从来没有使用过 XML,所以我不确定我的解决方案是否是最好的。这是我附带的 XML 文件的基本结构:
我是新来的 nosql概念,所以当我开始学习时 PouchDB ,我找到了这个转换表。我的困惑是,如何PouchDB如果可以说我有多个表,是否意味着我需要创建多个数据库?因为根据我在 pouchdb
我是一名优秀的程序员,十分优秀!