我们从数学协处理器8087的晶体中提取常数

1980年,英特尔推出了8087芯片,以加速8086处理器上浮点数的处理,并在原始IBM PC中使用了该芯片。由于第一个微处理器仅使用整数,因此使用浮点数的运算速度很慢,并且具有反正切或对数等先验函数,因此情况甚至更糟。将8087协处理器芯片添加到系统中后,浮点数最多可加速100倍。

我打开了8087芯片,并在显微镜下拍摄了几张照片。下图显示了一个微小的硅芯片晶体。在其侧面,细小的导体将其与40条外部支脚相连。图片中主要功能块的标记是我通过逆向工程完成的。如果仔细研究该芯片,则可以从其ROM中提取各种常数-计算中芯片使用的π等数字。英特尔8087芯片芯片,用于浮点操作,带有标记的主要功能块。具有常量的ROM以绿色标记。可点击的。




在芯片的上半部分是控制电路。执行浮点指令可能需要多达1000个步骤; 8087使用微码描述了这些步骤。在水晶的照片中,您可以看到从微码启动程序的“机制”。实际上,它是一个简单的CPU。它旁边是一个大ROM,用于存储微代码。

芯片底部是处理浮点数的电路。浮点数由小数部分(也称为数字或尾数的有效部分),指数和符号位组成。以十进制表示法,数字6.02×10 23尾数为6.02,指数为23。单独的芯片电路同时处理尾数和指数。尾数处理方案支持67位值-一个64位尾数和三个附加位以确保准确性。尾数运算方案从左到右由具有常数的ROM,移位寄存器,加法器/减法器和寄存器堆栈组成。本文的主题是具有常量的ROM;在照片中以绿色突出显示。

8087是8086处理器的协处理器,当8086处理器遇到与浮点数有关的特殊指令时,它会忽略它,并为8087提供了并行执行的机会。 8086和8087的交互安排得相当巧妙。为了简化,然后8087查看指令流8086,并执行与8087相关的任何指令。困难之处在于8086具有预取指令的缓冲区,因此8086当前正在接收的指令与该指令不匹配。他表演。因此,8087复制了指令8086的正向样本的缓冲区(或指令8088的正向样本的较小缓冲区),以便知道8086忙于什么(此处将描述更多详细信息))另一个困难与使用8086内部寄存器的复杂8086寻址模式有关。8087无法执行这些寻址模式,因为它无法访问8086寄存器,而是当8086看到8087的指令时,它从内存中的指定位置请求数据并忽略结果。同时,如果他需要,8087从总线上获取地址。在您看来,如果未安装8087,则会在此位置形成陷阱-但这不会发生。在没有8087的系统上,链接器将重写8087指令,并将其替换为来自仿真库的子例程调用。

我不会详细介绍8087的内部工作原理,但通常来说,浮点运算是通过整数的加法,减法和移位来实现的。要添加或减去两个浮点数,请先将数字转换为8087,直到二进制逗号对齐(类似于小数点,仅在二进制系统中),然后再添加或减去尾数。乘法,除法和取平方根由连续的移位和加法/减法执行。超越函数(正切,反正切,对数,度)使用CORDIC算法,该算法使用移位和特殊常数相加来提高计算效率。

ROM实施


本文介绍了用于存储常量的ROM。不要将其与存储微码的更大的四级ROM混淆-这最后一个是使用一种不寻常的技术实现的,该技术每个晶体管存储两位。使用三种不同尺寸的晶体管或在每个位置都没有晶体管来完成此操作。这四个选项指示两位。为了将大型ROM装入8087芯片,需要此项复杂的技术

常数ROM使用标准技术来存储8087计算所需的常数(例如π,ln(2)和√2)。下图显示了带有常量的ROM的一部分。为了看到晶体本身,已从其中去除了金属层。浅粉红色的区域是带有杂质的硅,赋予其不同的性能,浅红色和绿色的线条是多晶硅,一种特殊的硅布线位于顶部。注意ROM的结构,类似于正确的晶格。 ROM由两列存储位的晶体管组成。为了解释其工作方案,我将从晶体管的工作方案开始。


带有常数的ROM的一部分,带有去除的金属层。三列较大的晶体管用于选择行。

1970年代的高密度集成电路(IC)通常由N-MOS晶体管制成(现代计算机由CMOS制成,由与它们相反的N-MOS和P-MOS组成)。下图显示了N-MOS晶体管的结构。IC由在其上形成晶体管的硅基板组装而成。将杂质添加到硅部位,从而产生具有所需电性能的“扩散”区域。晶体管可以看作是一个开关,它允许电流在扩散的两个部分之间流动,这两个部分称为源极和漏极。晶体管由特殊类型的硅-多晶硅制成的栅极控制。向栅极施加电压可使电流在源极和漏极之间流动;否则,没有电流流过。8087非常复杂,上面装有约40,000个晶体管。

不同的来源为8087提供了不同数量的晶体管:英特尔说大约40,000,维基百科说大约45,000。也许整个问题在于不同的计算方法。由于ROM,PLA或其他类似结构中的晶体管数量取决于存储的数据,因此源通常指示“潜在”晶体管的数量,而不是实际晶体管的数量。您也可以考虑或不考虑上拉晶体管,或者将高电流驱动器视为一个晶体管或几个并联的晶体管。


IP中实现的MOS结构

通过放大,可以考虑单个ROM晶体管。浅粉红色的区域是硅,杂质形成源极和漏极。多晶硅垂直选择总线形成晶体管栅极。硅的标记区域接地,并下拉每个晶体管的一侧。圆圈是VIA,即上面的硅和金属轮胎之间的夹层通孔。对于照片,将金属轮胎拆下;橙色线显示其中一个的位置。


带有常数的ROM的一部分。每个采样总线选择一个特定的常数。晶体管以黄色显示。 X标记对应于位0的缺少的晶体管。橙色线表示金属导体的位置。

ROM的一个重要特征是缺少一些晶体管-上排没有第一个,下排则有两个标有X的晶体管。通过改变向硅中添加杂质的电路来对ROM中的位进行编程,从而形成晶体管或留下绝缘区域。每个可用或缺少的晶体管代表一位。激活采样总线后,此列中的所有晶体管都会打开,从而拉低相应的输出总线。但是,如果在所选位置没有晶体管,则相应的输出将保持高电平。因此,通过激活采样总线从ROM读取值,该采样总线将值从ROM输出到输出总线。

ROM内容


具有常数的ROM由143行和21列组成。它包含134行21位,左上角有一个6×6晶体管。因此,具有常数的ROM的物理大小为2946位。



根据ROM方案,缺少部分意味着前12个常量是64位而不是67位。这些是与CORDIC无关的常数,并且显然不需要额外的精度。

在显微镜下,ROM位模式可见,因此可以从那里删除。但是,以后如何解释这些位一点也不明显。第一个问题是晶体管的存在指示0还是1(后来证明晶体管的存在为1)。第二个问题是如何将134×21位网格转换为值。

可以用两种方式定义位编码。第一个是跟踪从ROM读取数据的电路,并查看其用法。第二个是在原始数据中寻找模式并尝试理解它们。由于8087非常复杂,因此在研究常量时我想避免进行完全逆向工程,因此我使用了第二种方法。

芯片的数据路径由67个水平行组成,因此很明显ROM中的134行对应两组67位常量。我从奇数序列中提取了一组常量,从偶数序列中提取了另一组常量,但是获得的值没有意义。再想一想,我意识到行并没有交替,而是重复了ABBA顺序。

这些行的顺序为ABBAABBAABBA ...,其中A行包含一组常量的位,而B行包含另一组常量的位。使用这种电路来代替简单地交替使用ABAW,可能是因为一个触点可以控制两个相邻的晶体管。即,一个导体可以选择组AA和BB中的每一个。

当考虑ABBA顺序时,我得到了一堆熟悉的常数,包括π和1。下图显示了这些常数的位。在照片中,位1为绿色条,位0为红色。在二进制系统中,π为11.001001 ...,并且该值在标记位的上一行中可见。下限值是常数1。


上一行是数字π,下一行是1。与其他图表相比,该图旋转了90°。

解释的下一个困难是仅尾数存储在ROM中,而不存储在指数中(到目前为止,我还没有找到包含指数的单独ROM)。我尝试了各种参展商,直到获得有意义的价值。有些立即清楚了:例如,常数1.204120 使用指数2 -2给出对数10(2)。其他的则较难理解,例如1,734723。最后,我意识到1.734723×2 59 = 10 18。为什么在8087中会有这样的常数?也许是因为8087支持18个字符的压缩二进制十进制代码

有些指数很难找到,我使用了蛮力法来查看结果是否会产生任何对数或一定数量的度数。最困难的是确定ln(2)/ 3的常数。我不清楚这个数字的重要性。

这是ROM中常量的完整列表。“含义”列是我对含义的描述。

常数十进制值含义
1.204120×2 -20.3010300日志10(2)
1.386294×2 -10.6931472ln(2)
1.442695×2 01.426950日志2(e)
1.570796×2 13.1415927π
1.000000×2 01.0000001个
1.660964×2 13.219281日志2(10)
1.734723×2 591.00e + 1810 18
1.734723×2 591.00e + 1810 18
1.848392×2-30.2310491ln(2)/3
1.082021×224.2808513*log2(e)
1.442695×201.426950log2 (e)
1.414214×201.4142136√2
1.570796×2-10.7853982atan(20)
1.854590×2-20.4636476atan(2-1)
2.000000×2-150.0000610atan(2-14)
2.000000×2-160.0000305atan(2-15)
1.959829×2-30.2449787atan(2-2)
1.989680×2-40.1243550atan(2-3)
2.000000×2-130.0002441atan(2-12)
2.000000×2-140.0001221atan(2-13)
1.997402×2-50.0624188atan(2-4)
1.999349×2-60.0312398atan(2-5)
1.999999×2-110.0009766atan(2-10)
2.000000×2-120.0004883atan(2-11)
1.999837×2-70.0156237atan(2-6)
1.999959×2-80.0078123atan(2-7)
1.999990×2-90.0039062atan(2-8)
1.999997×2-100.0019531atan(2-9)
1.441288×2-90.0028150log2(1+2-9)
1.439885×2-80.0056245log2(1+2-8)
1.437089×2-70.0112273log2(1+2-7)
1.431540×2-60.0223678log2(1+2-6)
1.442343×2-110.0007043log2(1+2-11)
1.441991×2-100.0014082log2(1+2-10)
1.420612×2-50.0443941log2(1+2-5)
1.399405×2-40.0874628log2(1+2-4)
1.442607×2-130.0001761log2(1+2-13)
1.442519×2-120.0003522log2(1+2-12)
1.359400×2-30.1699250log2(1+2-3)
1.287712×2-20.3219281log2(1+2-2)
1.442673×2-150.0000440log2(1+2-15)
1.442651×2-140.0000881log2(1+2-14)


不知道为什么重复10 18-也许差异是指数的。

在物理上,常数位于三组中。第一组是用户能够加载(1,π,登录值2 10,登录2 E,日志10 2和Ln),以及在内部使用(值10 18,LN(2)/ 3,3 * log 2(e),log 2(e)和√2)。第二组由16个反正切常数组成,第三组由14个log 2常数组成

在8087中,有七个直接加载常量的指令。指令FDLZ,FLD1,FLDPI,FLD2T,FLD2E,FLDLG2和FLDLN2将常数0、1,π,log 2 10,log 2加载到堆栈中e,分别记录10 2和ln 2。除了0以外,所有这些常量都存储在ROM中。

最后两组常数用于使用CORDIC算法计算先验函数。

CORDIC算法


通过ROM中的常量,您可以找到8087算法的一些操作细节.ROM包含16个反正切值,反正切从2 -n值开始。在(1 + 2 -n的基数2上还存储了14个对数。这样的值看似不寻常,但它们被用于1958年发明的高效CORDIC算法中。

CORDIC的想法是可以通过将矢量旋转这些角度将角度分成更小的角度来计算切线和反正切。诀窍是,如果选择合适的较小角度,则可以通过有效的移位和加法运算而不是三角函数来计算每次旋转。假设我们需要找到tan(z)。我们可以将z分成小角度的和:z≈{atan(2 -1)或0} + {atan(2 -2)或0} + {atan(2 -3)或0} + ... + {atan(2 -16或0}。您可以通过乘以2 -2并相加来将向量旋转atan(2 -2。最重要的是,乘以2 -2是通过快速按位移位进行的,考虑到所有这些,您可以通过将z与atan常数进行比较来计算tan(z),然后经过16个加法和移位循环,在铁上快速完成。预先计算出atan并将其存储在ROM中,反正切的计算方法与此类似,反之亦然-在旋转过程中,对角度(来自具有常数的ROM)求和并给出最终的角度。

在计算对数和指数时,还使用CORDIC算法及其对应的对数常数。这里最主要的是,可以借助移位和加法快速完成(1 + 2 -n)的乘法运算。对数和指数可以通过将方程的一侧与一系列值相乘,然后将对应的对数常数加到另一侧来计算。根据用于计算8087文档的对数和指数的算法,我没有找到它。我认为它们与下一篇文章中描述的相似,只有8087使用基数2而不是e。我不明白为什么8087没有该算法所需的log 2常数(1 + 2 -1)。

在8087中对先验功能的支持并不像您期望的那样广泛。它仅支持切线和反正切,没有正弦和余弦。要计算后者,必须应用三角恒等式。对数和指数仅支持2的底数-对于10或e的底数,用户将必须应用比例因子。一次,8087扩展了芯片容量的限制,因此指令的数量减至最少。

结论


8087是一个复杂的芯片,乍一看它看上去就像是一个无望的纠结迷宫。但是,在大多数情况下,经过仔细研究后可以理解。在其ROM中存储了42个常量,可以使用显微镜提取它们的值。预期某些常数(例如π),而其他常数(例如ln(2)/ 3)提出了更多问题。许多常量用于使用CORDIC算法计算正切,反正切,对数和度。不含金属层的晶体8087的照片。可点击的。




尽管40年前就推出了用于浮点运算的英特尔8087,但仍能感受到它的影响。他催生了用于大多数算术计算的IEEE 754标准浮点数,并且8087指令仍然是大多数计算机上使用的x86处理器的一部分。

All Articles