逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

图0:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

据我所记,那两款芯片体积相当庞大。而且上市时间相当迟——我们遇到了诸多问题。[…] 有时优雅的解决方案未必是最佳方案。” ——戴夫·豪斯在“英特尔8080微处理器开发与推广口述历史座谈会”上提及8271芯片时插话 [链接], 2007年4月26日,加州山景城计算机历史博物馆。

引言

1977年左右,英特尔推出了一款名为8271的软盘控制器(FDC)芯片。这款控制器知名度不高,主要应用于商用计算机和存储解决方案领域,但它在消费级市场的唯一突破是搭载于1981年发布的英国本土计算机BBC Micro

图1:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

英特尔8271芯片(左侧)搭载于BBC微机B型第3版机型中

除了一份实用的数据手册外,网上关于该芯片的公开资料寥寥无几。加之用户观察到越来越多的异常行为,使得这款芯片颇具神秘色彩。当我意外触发某种狂野测试模式时,这枚芯片彻底点燃了我的兴趣——尽管软盘设有写保护卡扣,它竟仍成功损毁了我的磁盘!详情可参阅此文:

疯狂的漏洞:1970年代英特尔8271磁盘芯片吞噬我的数据!

我们能否通过逆向工程深入理解其工作原理?又将发现怎样的奇迹?

元素周期表

鸣谢

本文所述成果源于一支临时组建的虚拟团队对该芯片的联合研究。众多关键成员的贡献不可或缺,特别感谢:

  • 奈杰尔·巴恩斯。促成MAME社区与BBC微机社区的协作,并寻得具备芯片去封装技术的专家。
  • BeebMaster。提供了数枚用于拆封的8271芯片样本。
  • 肖恩·里德尔。完成芯片拆封并提供精美高清图像。
  • ZXGuesserDiminished。负责硬件级逆向工程,包括精确提取ROM位数据。
  • 肯·希里夫。提供硅片宏观结构笔记,并寻获极具价值的历史文献。
  • 里奇·塔尔博特-沃特金斯克里斯·埃文斯(即本人)。完成指令集架构计算与ROM反汇编工作。

野兽之美:回顾与剖析

回顾:我们发现若干迹象表明这颗芯片极具研究价值。从前文提及的特殊测试模式,到数据手册暗示存在大量内部寄存器(仅少数被记录)等线索均指向这一结论。

剖析:

图2:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

(参见文末参考资料获取超高分辨率图片)

这颗FDC芯片结构极其复杂!其内部存在大量大型结构单元,且排列极为密集。为说明这一点,我们可以将其与BBC微机的核心部件——那颗久负盛名的6502处理器进行对比。这款经典芯片曾广泛应用于80年代标志性设备中,例如苹果II、Commodore 64和任天堂红白机:

图3:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

左侧8271,右侧6502

8271不仅体积远大于主CPU,据各方记载其成本也更高:

“Acorn公司明智地为BBC微机选用了英特尔8271磁盘控制器——这款控制器在BBC微机上市前可能已过时。Acorn磁盘升级套件包含8271芯片、若干标准TTL集成电路、Acorn DFS只读存储器及磁盘手册。这些集成电路需插入主板上预留的空插座。

_少数硬核玩家尝试单独采购零件——这本无可厚非,但单个8271芯片动辄要价109英镑,且_还得碰运气才能找到…” — [来源链接]

相比之下,6502处理器据称1981年售价约7.45美元,两者价格差距悬殊。

获取ROM芯片

粗略观察8271芯片,可见大量类似PLA的结构,但最令人振奋的是左下角那块大型矩形ROM区域。我们当即意识到:若存在ROM程序,这_确实可能_是一颗通用微控制器CPU。工作重心随即转向ROM提取。

ZXGuesser与Diminished付出了艰辛努力,先是手工抄录ROM位数据,后借助工具辅助并交叉核对。若想了解手抄ROM位数据的模样,大致如下:

图4:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

仔细看,那些青色标注其实是0和1!

该ROM矩阵由64×108位单元构成,总容量达864字节。

即便获取了ROM位数据,仍面临将其重组为正确序列字节流的挑战。这并非想象中简单,尤其当缺乏可靠验证手段时更显艰难——本案例正是如此。研究过程中我发现:

所幸,ROM逆向工程师们还考察了连接ROM的行/列电路,并给出了相当可靠的结论:ROM位/字节的排列方式为:

  • 从左至右,自上而下。
  • 相对于上图初始解码结果,位序相反。
  • 位序为最高位在前。
  • 字节由每组线性8位中的1位构成。

由此得出ROM的前几个字节如下:

图5:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

这恰好是正确的解码结果,尽管我们曾一度无法确定。

架构线索

当我和Rich在毫无指令集架构(ISA)预先知识的情况下尝试反汇编ROM时,有幸与Ken Shirriff(righto.com)就这款有趣的芯片展开讨论。出乎意料的是,他找到了1977年的一篇详细会议摘要[ 摘要全文链接]。

摘要中的这张示意图想必令人眼熟(想象旋转90度后的形态):

图6:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

摘要其余内容堪称宝藏。该论文题为《双处理器串行数据控制器芯片》,开篇写道:

“本文将介绍一款采用专用架构实现高速串行数据控制的双处理器微程序芯片。该芯片尺寸为218密耳×244密耳,内含22,000个晶体管…”

22,000个晶体管!!我们早知这芯片体积不小,但作为参考:6502芯片仅有3,218个晶体管;8080芯片为6,000个晶体管;而8086芯片则达29,000个晶体管。没错,8271芯片的晶体管数量与8086相差并不远。

这张说明性表格和示意图同样摘自摘要:

图7:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

这证实了我们的推测——我们确实面对的是一个通用CPU,并配备了I/O加速功能。该通用CPU具备预期特性,包括程序计数器、栈、算术逻辑单元、累加器、寄存器以及总线访问能力。摘要中进一步提及“32个8位寄存器”和“四级栈”。

配备250纳秒周期时间的位处理器(可视为协处理器)的存在,解决了“通用CPU”理论中的核心疑难。当时的通用CPU可能无法在磁盘数据传输速率下快速计算CRC16校验值。然而,侧面加装的专用PLA驱动位运算引擎则完全胜任。

摘要最后指出:“迄今已实现两款独立微程序控制器:软盘控制器与同步数据链路控制器(SDLC)”。我们已确认软盘控制器为8271,同期英特尔的SDLC则是8273。再次感谢肖恩·里德尔——这位明星人物——经过牺牲一两块芯片后,我们获得了最终结果:

图8:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

8271 左,8273 右

肯还发现了与该双核设计相关的专利!即US4152761。[更完整的版本链接]。专利中包含大量有价值的架构细节,包括这份关键组件的有趣总结。

图9:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

From US4,152,761

[完整版本链接]。该专利包含大量有价值的架构细节,其中包括这份关键组件的精要概述。

如图所示,这里描述的额外复杂性超出了传统CPU的预期范畴。除了程序计数器和指令寄存器外,还存在调度请求、优先级解析、“案例”寄存器和“地址”寄存器。这涉及某种调度机制,我们将在后续内容中探讨。

最后附上肯提供的示意图。这是对现有文档中架构如何映射至硅片的初步推测。作为双处理器巨兽,请注意其配备双算术逻辑单元、双寄存器组、大量可编程逻辑阵列(包括“控制”标签左右两侧的阵列),以及诸多功能未知的硅片区域。

图10:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

从位到字节到指令集架构(ISA)

掌握架构全貌后,我们更能预判指令集中可能出现的操作码类型。当头脑中拼图碎片愈发完整,面对复杂多变的难题时,我们建立抽象关联的能力就愈发强大。

最初对ROM的反汇编尝试主要基于这样一种理论:CPU核心可能基于英特尔MCS-48微控制器系列。该系列包含著名的8048,并有多个变体,例如功能略有削减的8020(I/O线路减少)。那么为何核心不能基于进一步精简的8020?这完全吻合:1K ROM、64个寄存器、13条I/O线。时间线也吻合:MCS-48系列1976年首发,意味着核心在8271发布前就已存在。按此推论,若1970年代的英特尔员工不直接去同事的零件箱里搜刮资源抢占先机,简直是疯了。

MCS-48理论看似完美契合…却最终被证伪。无论如何调整ROM位/字节,都无法得到合理的MCS-48反汇编结果。

我们重回设计阶段,重新审视了“可能正确的”ROM解码方案,并基于对控制器工作原理及磁盘记录机制的理解,分析其中是否存在8271 ROM应有的特征模式。以下发现令人豁然开朗:

图11:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

最显著的是常量组合 $FE + $C7(中间框)与 $E5 + $FF(下方框)在相同上下文中出现。这些常量正是FM(单密度)格式化光盘格式化程序中预期出现的数据字节+时钟字节组合。$FE + $C7是扇区头标记,$E5 + $FF则是新格式化扇区的默认填充字节。额外发现是连续出现的四个$E9可能代表左右移位指令,而$FD或许是RET指令。综合来看,这些间接证据强烈支持当前解码方案的正确性。

当MCS-48指令集列表与我们的ROM不匹配后,我们耗费大量时间尝试推导替代指令集。

但这非常困难,就像面对所有拼图碎片颜色完全相同的拼图游戏。由于存在无数种可能性,难以找到突破口。研究成果往往被包装成完美结论,却鲜少提及背后的艰辛。我认为这会让新人望而却步。所以请务必明白:这确实是场持久战;过程中充满咒骂;最终成功的关键在于毅力和坚韧,而非特定的技术能力。

当硬件调查成功解析出字节处理器关联指令PLA之一的布线与内容时,突破性进展就此催生。该PLA实为上图中“控制”标签左侧较深色的矩形模块,其配置如下:

图12:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

感谢Diminished!

解码指令PLA后,可通过追踪激活线至寄存器、栈、ALU等单元,解析每个8位操作码的作用。但我们仅凭该PLA提供的操作码范围就实现了突破。Rich提供的以下范围尤为关键:

1111 1100   FC
1111 1101   FD
[...]
0010 xxxx   20-2F
[...]
0011 xxxx   30-3F
[...]
001x xxxx   20-3F

专用指令$FC和$FD印证了我们对CALL和RET指令的推测,但更关键的是$20-$3F区间——该范围被划分为两个16位宽的区块。我当即推测这可能是“寄存器移位至累加器”与“累加器移位至寄存器”指令,后续验证证实了这一推测。此外我注意到,在$2?或$3?之前,$0?指令码更为常见,例如:

05D:   04 22 03 35

由此推断这些是寄存器库选择指令码。类似于MCS-48架构,由于指令码数量不足以同时调用全部32个寄存器,必然存在库选择机制。这一推测同样被证实正确。事实上,随着这些拼图碎片的拼合,整个图景开始逐渐清晰,拼合速度也越来越快。

部分ROM代码示例

对于这些代码示例,请注意:据我们所知,本文所示的指令集架构(ISA)尚未公开发布。我们不得不自行设计汇编助记符,尽管这些助记符旨在让熟悉汇编语言的人士感到亲切。具体说明如下:

  • SEL RB 表示 SELect Register Bank(选择寄存器库),提供寄存器访问的基础索引 (乘以8即可获得实际索引值)。
  • 请注意所有寄存器引用均采用索引形式,而非寄存器编号。寄存器编号可通过索引值与寄存器库组合计算得出。

1) 读取特殊寄存器

.command_READ_SPECIAL_REGISTER
32E   00	SEL RB 0
32F   27	MOV A, I7		; R7 ($07) (param 1)
330   30	MOV I0, A		; R0 ($00) = register index
331   F8	MOV A, [I0]		; read special register value to A
332   02	SEL RB 2
333   36	MOV I6, A		; R22 ($16) (ext RESULT) = A
334   0E	SEL RB 14
335   EE	SYS 2, RB		; JMP (2,E,0) => $288, .post_command_tidy_up

读取特殊寄存器指令是最基础的操作之一。正如预期,外部定义的“特殊寄存器”在内部实现上仅是“32个寄存器的索引访问”。我们还能注意到许多有趣之处:

  • 稍后将看到的命令设置代码会将参数写入R7及以下寄存器。
  • 间接读写操作通过特殊操作码实现,这些操作码经由I0寄存器(通常但非必然是R0)进行间接访问,符合MCS-48架构规范。
  • 部分内部寄存器与用于与主CPU交互的外部总线寄存器存在交互关系。R22寄存器用于写入值,这些值将出现在“外部结果”中——该结果由BBC Micro的6502处理器从内存地址$FE81读取。
  • “寄存器库”概念似乎被复用为SYS 2指令的RB操作码提供查找索引。这可视为一种次要的权宜之计。
  • 为在结尾处从第3页($3??)跳转至第2页($2??),需使用特殊SYS操作码。常规JMP/CALL指令仅支持8位操作数,且只能跳转至当前页。SYS操作码则通过硬编码表查找10位程序计数器值。
  • 该命令通过跳转至通用退出例程.post_command_tidy_up终止。该例程会禁用芯片大部分功能,包括位处理器和事件处理。此操作后续将至关重要。

2) SPECIFY

.command_SPECIFY
066   00	SEL RB 0
067   27	MOV A, I7		; R7 ($07) (param 1)
068   30	MOV I0, A		; R0 ($00) = destination index
069   F1 03	MOV I1, #$03		; R1 ($01) = count of 3 extra parameters
06B   14	YIELDTO 4		; seems to set PARAM callback to
					; .wakeup_PARAM_4_SPECIFY, then YIELD
; ** entry point (3, segment 9, routine 4 5 6 7 C D E F)
.wakeup_PARAM_4_SPECIFY
06C   03	SEL RB 3
06D   2E	MOV A, IE		; R30 ($1E) (ext PARAM)
06E   00	SEL RB 0
06F   E8	MOV [I0], A
070   00	SEL RB 0
071   80	INC I0
072   A1	DEC I1			; R1 ($01), decrement count
073   8A 8C	BZ $08C                 ; branch if done
					; lands at SEL RB 14, JMP RB
					; which jumps to .post_command_tidy_up
075   FF	YIELD

SPECIFY同样是简单指令。严格而言并非必需指令,因其效果等同于连续执行三次WRITE SPECIAL REGISTER指令写入特定寄存器号。鉴于ROM和芯片空间的紧缺,该指令的存在意义尚不明确,但数据手册确实描述了通过多次调用此指令初始化8271芯片。其他注意事项:

  • SPECIFY 接受并立即执行寄存器写入操作,在每次写入间执行 YIELD(休眠/空闲)等待主机 CPU 提供下一个寄存器。这意味着根据芯片编程方式,SPECIFY 命令可能长期处于部分完成状态且永不完全完成,此特性后续将产生重要影响。
  • SPECIFY内部将R0用作寄存器值写入的目标索引,R1用作完成计数。这使其成为进行黑盒测试的理想对象,可验证芯片行为是否与源代码反汇编结果一致。具体而言,我已尝试并确认:
    • 将第一个参数传给SPECIFY时设为0,表示我们将从R0开始写入寄存器值。请注意,根据代码,R0在SPECIFY内部被占用。
    • 将第二个参数传为$22。该值将被写入R0(因为R0当前指向R0本身),并被递增,最终使R0存储$23。这导致R0被“破坏”。
    • 第三参数传入$48。该值将写入MMIO寄存器R35(即$23),应能启动驱动电机。
    • 无需传入第四参数。尽管未完整填写命令的四个参数,我们预期第三参数的写入将产生上述效果。实际硬件中确实如此

3) 外部命令寄存器处理机制

.wakeup_COMMAND
014   02	SEL RB 2
015   F6 00	MOV I6, #$00		; R22 ($16) = $00 (ext RESULT)
017   CF BF	AND I7, #$BF		; R23 ($17) (ext STATUS) !CMD_FULL
019   00	SEL RB 0
01A   F5 01	MOV I5, #$01		; R5 ($05) = $01 (param 3 default $01)
					; That’s 1x 128 byte sector in many cases.
01C   F4 01	MOV I4, #$01		; R4 ($04) = $01 (param 4 default $01)
01E   03	SEL RB 3
01F   98 05	MOV A, #$05		; 5 parameters expected
021   6F 18 27	TBZ IF, #$18, $027	; R31 ($1F) (ext CMD), jump if 5 param                                                ; command
					; matches SCAN, FORMAT
024   2F	MOV A, IF		; R31 ($1F) (ext CMD)
025   9C 03	AND A, #$03		; (CMD & 3) parameters expected
027   00	SEL RB 0
028   31	MOV I1, A		; R1 ($01) = A = parameters expected
029   8A 3D	BZ $03D    		; if no parameters, start command
02B   F0 07	MOV I0, #$07		; R0 ($00) = $07 (put parameters at $07 down)
02D   BC 01	TASK 4, 1		; select .wakeup_PARAM_1_accept
					; 3 9 (1, 3, 9, B) = $035
02F   FF	YIELD

若需追踪ROM主入口点,应从该处开始读取。8271字节处理器在此处被唤醒,此时外部主机CPU会向外部命令寄存器(BBC微机上为$FE80)写入数据。此处仍有若干值得注意的细节:

  • 除SCAN和FORMAT指令外,预期参数数量实际编码在指令字节的低位。此设计无疑节省了ROM空间。通过简单测试即可验证ROM代码描述的行为:
    • 选取需1个参数的指令(如READ SPECIAL REGISTER)。
    • 将命令字节递增后,将其提供给8271处理器。
    • 我们预期8271启动命令需两个参数,但实际会忽略第二个参数,表现如同使用单参数版本。此现象在真实硬件中确有观察到
  • 部分默认参数值已被部署。这些参数用于数据手册中称为“128字节单记录格式”的命令。推测此设计再次实现了ROM空间节省。

4) 完整ROM反汇编

截至撰写本文时,完整ROM反汇编文件可在此处查阅:[链接]。该副本将保持静态状态。该分析基本完整,所有“主”路径均已完全追踪,包括寻道(SEEK)、读取数据(READ DATA)、写入数据(WRITE DATA)和格式化磁道(FORMAT TRACK)。

1970年代芯片上的JavaScript

现在该解析指令集里那些听起来特别的指令了:

  • YIELD. $FF. 此指令指示处理器切换至最高优先级的调度请求,或(更常见的情况)在无活跃调度请求时进入空闲状态。
  • TASK t, r。$B8-$BF,2字节。该指令更改指定任务的回调例程。回调例程以整数形式指定,该整数构成查找ROM地址表的键值的一部分。
  • YIELDTO r。$10-$1F。更改当前执行任务的回调例程并让出控制权。
  • SYS 0, RB, A. $EC. 跳转至地址寄存器 PLA 中键值 (0, RB, A) 对应的 ROM 地址。RB 来自 SEL RB 指令的当前寄存器库,A 为累加器值。
  • SYS 1, RB, R. $ED. 跳转至地址PLA中键值(1, RB, R)对应的ROM地址。RB为SEL RB指令设定的当前寄存器组,R为当前例程值。
  • SYS 2, RB. $EE. 跳转至地址PLA中键值(2, RB, 0)对应的ROM地址。RB为当前寄存器组。

此处涉及诸多概念。若您感到概念交织混乱,实属正常。字节处理器CPU中非传统部分的设计,在我看来也颇具临时性。让我们通过具体示例——SPECIFY指令处理程序来解析:即上文示例块2中的.command_SPECIFY代码。

要触发.command_SPECIFY执行,主CPU需向外部命令寄存器提供命令$35,并向外部参数寄存器提供1个初始预期参数。字节处理器CPU在.wakeup_PARAM_1_accept处被唤醒。此时上下文为:

  • PC == $035
  • TASK == 4
  • SEGMENT == 9, ROUTINE == 1

向外部参数寄存器写入数据唤醒任务4这一事实是硬编码的。执行的程序计数器由该任务选定的例程决定,当时为1。这用于生成键值(3,9,1),该键值在地址PLA中查找地址$035。地址PLA是硬编码的。任务4采用(3,9,x)形式进行键值查找的事实是硬编码的。

.command_SPECIFY指令在此结束,因为它是唯一执行后决定让出控制权以等待3个参数的指令:

06B   14	YIELDTO 4		; seems to set PARAM callback to
					; .wakeup_PARAM_4_SPECIFY, then YIELD

这条特殊指令将当前任务的回调例程设为4。这意味着下次外部参数寄存器写入的回调代码将在地址寄存器PLA中以(3,9,4)为键值查找。该地址即程序计数器$06C,亦即.wakeup_PARAM_4_SPECIFY。

可将其类比为JavaScript的运行机制。所有执行基于事件驱动;特定事件的处理程序可被修改(由其自身或无关处理程序修改);除非显式让出,否则不存在抢占机制。

字节处理器已知的接入事件包括:

  • 0:完全不反转。似乎与SCAN指令相关,但BBC Micro因缺乏DMA而未启用该指令。
  • 1:位处理器事件,例如发现同步、丢失同步、CRC错误。
  • 2:位处理器,读取字节就绪。
  • 3:位处理器,需要写入字节。
  • 4:外部参数寄存器写入完成。
  • 5:似乎未被使用。(可能永久连接到外部命令寄存器?)
  • 6:磁盘驱动器索引脉冲。
  • 7:未被使用。

在“常规”JavaScript模型之上,还存在任务优先级概念。这些优先级在指令集架构中不可见,且很可能是硬编码的。在软盘控制器中,此机制可能发挥作用的场景是:当磁盘驱动器索引脉冲(每转一次发出一次)与位处理器需要写入字节的时机重合时(虽然跨索引写入不常见,但确实可能发生)。此时,为位处理器提供数据字节的任务比处理索引脉冲更具实时性,因此应优先处理。

是的,这在通用CPU典型复杂度之上又增添了相当程度的复杂性。尤其值得注意的是,它提供了超越标准JMP/CALL/RET指令的多种控制流处理方式。事实上——且令人有些痛苦的是——各种控制流可能性被混杂在一起!以下是众多扇区读取操作的命令处理程序示例,可略窥其恐怖之处:

.command_READ_DATA
.command_READ_DATA_AND_DEL_DATA
.command_VERIFY_DATA_AND_DEL_DATA
0A7   FC C9	CALL $0C9       ; .do_common_path_from_seek
			        ; very gnarly because this CALL does a YIELD
			        ; context on RET is from
                                ; .wakeup_BITPROC_EVENT_1_check_header_crc
		                ; if we get a matching sector header,
                                ; the RET at $255 fires
0A9   BA 0B	TASK 2, 11	; select .wakeup_BITPROC_READ_10_11_count_GAP2
			        ; (3,5,(10,11)) = $1B8
0AB   12	YIELDTO 2	; select
                                ; .wakeup_BITPROC_EVENT_2_check_for_data_marker
				; (3,4,2) = $2D0
				; and YIELD

可见,CALL子程序在不展开栈的情况下执行YIELD操作。这或许应被视为反模式?由于栈是所有任务共享的资源,只能祈祷两个不同任务不会同时执行此操作而相互干扰。更复杂的是,当CALL返回时,执行环境的各个方面(任务、例程、资源块等)很可能已经发生改变。

所有这些使得ROM的读写路径极其难以追踪,即便面对完全反汇编并添加注释的ROM也是如此!

ISA的特殊特性

1) 缺乏对称性

我们发现的与递增、递减、加减相关的操作码如下:

$80-$83:	INC Ix
$84-$87:	ADC A, Ix
[...]
$A0-$A7:	DEC Ix
[...]
$90-$93:	ADC Ix			does INC Ix if carry
$94-$97:	SBB A, Ix

这点颇为耐人寻味,因为不同寄存器在递增与递减操作上存在不对称性。某些寄存器完全无法递增——即便启用寄存器分页机制也无济于事,因为分页机制以8的倍数运作,而递增操作码仅有4种。

一种理论认为芯片设计者受限于硅片空间,试图在算术逻辑单元中省略加减运算支持。目前仅有间接证据佐证此说,例如:- 操作码空间存在被截断的范围;- 除磁盘寻道实现代码外,常规代码基本不涉及加减运算;- 未发现比较指令(目前——存在未知指令); 在$240和$24F处使用异或运算实现等值检测;以及常见分支指令(见下文第2项)仅支持直接等值检测或掩码检测。不过大胆猜测也很有趣,不是吗?

2) 3字节操作码

整整四分之一(!)的操作码空间被分配给四条条件分支指令:

$40-$4F:        BEQ Ix, #imm, abs	branch if Ix == imm
$50-$5F:        BNE Ix, #imm, abs	branch if Ix != imm
$60-$6F:        TBZ Ix, #imm, abs	test and branch if zero
$70-$7F:        TBNZ Ix, #imm, abs	test and branch if not zero

这些操作码均为三字节长度,这与当时英特尔其他微控制器的设计有所不同。虽然占用了大量操作码空间,但它们能以小博大——例如来自.do_seek的这段代码:

13E   62 01 3E	TBZ I2, #$01, $13E   ; MMIO R34 ($22) (drive in), wait until CNT/OPI
141   72 01 41	TBNZ I2, #$01, $141  ; MMIO R34 ($22) (drive in), wait until !CNT/OPI

对于某种(较少使用的)寻道模式,这6字节足以实现忙循环:先等待驱动器启动寻道,再接收完成确认。

这三字节指令集的发现源于前文提及的“拼图”类比。当命令输入函数被完全反汇编后,仅剩$021处的三字节指令无法匹配,此时唯一符合行为要求的解释便是:

3) 无定时器、端口I/O或IRQ

为节省芯片面积,字节处理器CPU取消了定时器、专用端口I/O指令及IRQ功能。MCS-48处理器虽具备这些特性,

但实际无需依赖它们。诸如寻道步骤所需的毫秒级延迟,仅通过忙循环即可实现。

4) 自主掌控冒险进程

撰写本文时,我们的操作码列表位于此处:[链接]。该列表尚未完整。8271 ROM中尚未反汇编的部分——扫描处理模块——至少使用了$9A、$9B和$8C这三个操作码。(我们忽略扫描功能是因为其需要DMA连接,而BBC Micro应用中并未实现该功能。)此外,可编程逻辑阵列(PLA)的布局暗示着8271 ROM中未出现的其他操作码范围可能具有特殊功能。这包括$A8-$AF和$B0-$B7范围。欢迎自行查阅!

位处理器接口

既然已解析字节处理器的结构,现在该关注位处理器的接口及其行为。毕竟连接磁盘驱动器控制线和数据线的正是位处理器!

我们最初假设字节处理器CPU会像MCS-48那样具备某种端口I/O指令集,但事实证明并非如此。实际机制更为简单:它采用MMIO(内存映射输入/输出)。这意味着访问特定寄存器索引时,实际操作的是位处理器而非字节处理器的寄存器。原理很简单:地址0-31指向字节处理器寄存器,地址32-39则指向位处理器寄存器。为简化解码过程,位处理器的8个寄存器地址在32-63范围内进行了4次镜像映射。整个0-63地址范围随后在0-255的完整可寻址范围内再次进行4次镜像映射。

图13:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

寄存器0-63,在真实BBC Micro计算机上读取,展示位处理器寄存器的镜像特性

此外,字节处理器代码中对位处理器的引用上下文明确表明其接口极为简单。其结构之简洁使我们认为无需进一步逆向工程分析位处理器。位处理器寄存器分配如下:

  • 0:控制寄存器,4位
    • 位0 (0x01) => 获取CRC(?)
    • 位 1 (0x02) => 完成 CRC (?)
    • 位 2 (0x04) => 1 表示读取,0 表示写入
    • 位 3 (0x08) => 空闲状态
  • 1:状态寄存器,指示同步数据字节类型、CRC 错误等
  • 2:驱动输入,读取驱动状态
  • 3:驱动输出,控制步进/写入等信号线
  • 4:时钟输出字节
  • 5:数据输出字节
  • 6:数据输入字节
  • 7:未使用?(返回0xFF,字节处理器ROM依赖此位!)

敏锐的读者或许会问:既然位处理器寄存器属于MMIO,是否意味着可直接通过WRITE SPECIAL REGISTER命令编程?答案是肯定的!但需注意以下严重限制:

  • 通用命令入口代码会在进入时破坏位处理器状态。
  • 通用命令退出代码会在退出时重置位处理器及相关回调函数(但奇怪的是,WRITE SPECIAL REGISTER命令除外,这反而颇为实用)。
  • WRITE SPECIAL REGISTER命令的延迟极其严重

最后一点,糟糕的延迟,实在令人遗憾。约211微秒的延迟意味着完全无法实现诸如每次写入时将时钟脉冲与数据字节同步传输的优化技巧。延迟过大的根源在于字节处理器在命令输入路径上执行了大量指令,包括驱动器状态检测与缓存、逐个参数读取、选定驱动器变更检测等操作。

不过直接写入驱动器输出寄存器确实很有用。我正是通过这种方式,利用8271芯片实现了直接写入“弱位”的技巧!更多细节请参阅我关于弱位的博客文章。[链接]

挑战不可写领域

既然已洞悉这头怪兽的运作机制,自然该转向搞点小动作了。能否让芯片执行“不该”执行的操作?当然可以,而惯例操作就是违背数据手册:

图14:逆向工程解析被遗忘的1970年代英特尔双核猛兽:8271,一种全新的指令集架构

我们将专门违背“在另一条命令执行期间发出命令是非法的”这条规定。通过阅读和分析代码,我们现在完全有能力预见这种操作的后果:当外部命令寄存器被写入时触发的回调函数会立即执行,完全不考虑当前是否存在未完成命令,因此会产生以下副作用:

  • 内部命令寄存器本身已损坏,即与当前执行的命令不匹配。由于该寄存器会被不时调用,此特性可能对我们有所助益。
  • 非法命令将改变内部寄存器值,可能影响当前命令的执行。
  • 非法命令可能修改或禁用回调函数,或重置/重新配置位处理器。

综合考虑上述因素,我们将尝试写入任意FM比特流。实现此目标后,便能利用8271重现理论上不可写入的防拷贝光盘表面。记住,孩子们:

我们将通过分离数据字节写入方式与特殊扇区标记时钟字节写入方式来实现此目标。写入完整磁道数据字节虽易,但单独无用。具体步骤如下:

  • 使用单个扇区头格式化磁道
  • 对该扇区发出8192字节大小的WRITE DATA命令。磁道实际仅3125字节(完美校准驱动器条件下),因此:
    • 首次环绕时开始写入目标字节序列
    • 约3125字节后,在第二次环绕时通过重置控制器中止命令。

仅此数据字节轨道将无法使用。若尝试读取其中扇区,将报错$18(即“扇区未找到”)。识别扇区头与扇区数据所需的特殊时钟字节标记将缺失。

FM编码的工作原理非常简单:它以4微秒为周期交替传输时钟位、数据位、时钟位、数据位……通常所有时钟位均为1,以维持时序并确保驱动电子元件正常工作。但在扇区头或数据标记处,会省略若干时钟位,以便软盘控制器在无法确定位置的比特流中定位目标。

因此在执行WRITE DATA命令期间,我们将巧妙插入并行SPECIFY命令,在不干扰当前命令的前提下“破坏”其寄存器。具体而言,我们仅在关键时刻破坏时钟字节寄存器(MMIO R36),使其写入非0xFF的时钟字节值。整体操作流程如下:

奇迹般地,此方案确实奏效,轻松复制了当年BBC微机复制机无法企及的磁盘。例如《The Sentinel》[链接]就属于难以复制的磁盘之一。这张磁盘配有精美标签和包装,自然要附上张无谓的图片:

实现该方案存在诸多特殊情况和注意事项。为完整起见,简要列举如下:

    • 为解决延迟问题,本程序采用SPECIFY指令替代WRITE SPECIAL REGISTER指令。通过传递指令及首个参数可对SPECIFY指令进行“预置”,使得第二个参数(待写入的首个寄存器值)能在恰当时机以低延迟执行写入操作。
    • WRITE SPECIAL REGISTER 命令退出时不会重置位处理器或清除所有 I/O 回调。遗憾的是,SPECIFY 命令并非如此。所幸我们无需退出 SPECIFY 命令!该命令具有在完成前写入内部寄存器的实用副作用。之后可反复重启该命令,使其永不完成。
    • 命令分派过程会破坏MMIO时钟字节寄存器!这种现象虽出人意料,但源于其在计算选定磁盘驱动器(0或1)及状态变更时,将MMIO R36用作临时存储区。值得关注的是:
      .parameters_complete_launch_command
      03D   FC 5D	CALL $05D	; .read_drive_status
      03F   BC 00	TASK 4, 0	; select .wakeup_PARAM_0_no_action
      				; (3,9,(0,2,8,A)) => $030
      041   03	SEL RB 3
      042   2F	MOV A, IF	; R31 ($1F) (ext CMD)
      043   CF 3C	AND I7, #$3C	; R31 ($1F) (select bits + param count masked out)
      045   9C C0	AND A, #$C0	; A now contains drive select bits
      047   04	SEL RB 4
      048   34	MOV I4, A	; MMIO R36 ($24) (???) (temp storage?)
      049   E3	XOR A, I3	; MMIO R35 ($23) (drive out)
      04A   9C C0	AND A, #$C0
      04C   8A 53	BZ $053    	; only update drive out if select bits changed
      				; .command_dispatch
      04E   98 20	MOV A, #$20	; bit for side select (drive 0 vs. 2)
      050   C3	AND A, I3	; MMIO R35 ($23) (drive out)
      051   D4	OR A, I4	; MMIO R36 ($24) merge back select bits?
      052   33	MOV I3, A	; MMIO R35 ($23) (drive out)
      				; only drive select bits and side select kept
      				; clears write enable, head load, and others
      				; matches data sheet

      橙色标注的这行代码正是问题所在。最初反编译时,我因其异常表现而用???标记为存疑项。但事实证明它完全正确——真实机器中时钟数据的损坏现象,恰如代码所描述的那般精准呈现。损坏时钟值(写入驱动器0时为$40)在上图中以橙色标注。一旦明确其存在及成因,最简便的规避方案是让时钟损坏落在不会引发问题的区域。当与$FF数据字节配对时,它不会在磁盘表面产生弱位,且控制器读取时似乎会直接跳过该区域。

    • 写入I/O路径存在幸运机制:每次写入I/O回调都会将时钟字节重置为$FF。这为我们省去大量麻烦:
      .wakeup_BITPROC_WRITE_3_set_clocks_and_count_host_bytes
      318   F4 FF	MOV I4, #$FF	; MMIO R36 ($24), standard clocks
      [...]
  • 需精确控制时序。数据流从外部数据寄存器经内部位处理器数据寄存器,最终到达实际输出脉冲装置,形成流水线结构,必须对此进行考量。

综合这些特性,我确信若没有彻底逆向工程并反汇编ROM,我永远无法实现或接近这个目标。

其他成功与失败

通过仔细研读ROM代码实现或验证的其他功能:

  • beebjit现已拥有更精确的8271驱动程序。
  • 此前读取逻辑轨道ID为$FF的扇区时出现的异常现象,现已确认是坏轨道处理中的整数溢出所致。
  • 位于非零物理磁道但逻辑磁道标识为零的扇区,曾被认为“不可能”读取。我通过“命令嵌套命令”技巧成功实现了读取。当READ DATA指令安全执行(包括处理寻道请求并进入空闲状态)后,可通过WRITE SPECIAL REGISTER将R7(指令参数1,即请求磁道)改为零,此时扇区即可正常读取。问题在于寻道代码中对逻辑磁道0的引用始终被强制解释为物理磁道0。必须绕过此机制。

未实现功能:

  • 读写MFM(双倍密度)——似乎根本不可能实现。硬连线位处理器似乎不具备此功能。
  • 在芯片上执行任意代码。这令人遗憾,因为字节处理器本身是台性能不错的CPU!谁知道我们能用个协处理器做什么呢?阻碍因素包括:
    • 代码与数据在独立地址空间中分离。
    • 除CALL和RET指令外无法访问栈结构
    • 间接跳转目标存储于只读PLA中(微软CFG? 🙂
    • …有趣的是,这些无意间形成的防御机制,竟与2000年后研究部署的防御技术如出一辙。看来1970年代的发明…

总结

8271芯片的表现远超预期!该从何说起呢?这颗巨型芯片集成了双核架构和类似JavaScript的执行模型——请记住,这可是1970年代中期的事。其通用CPU采用英特尔指令集架构,据我所知至今尚未公开文档。能遇到全新的英特尔指令集架构实属难得。

我们始终未能彻底解析引发本次调查的诡异测试模式。字节处理器ROM中毫无其踪迹,说明它必定由芯片上的其他组件控制。或许这值得另择时机深入探究。

目睹芯片的复杂程度后,每当我的BBC微机成功加载磁盘时,我仍会感到惊讶。

尾声

考虑到8271存在成本、发热、供应链、复杂度及缺乏MFM支持等问题,英特尔对8271和8273架构感到厌倦并不奇怪。他们勇敢地推出了8272,该芯片引入了MFM支持——等等,让我们看看被切掉封装的8272芯片…

从左至右:英特尔8271、NEC D765、英特尔8272

这可真够狡猾的!8272芯片虽标注“8272 (c) Intel 1979”,实则与NEC D765采用相同晶圆,后者印有“NEC D765B”字样。看来英特尔可能获得了NEC的设计授权。NEC芯片的晶体尺寸看似相差无几,但布局明显更简洁清爽。诡异的是,英特尔生产的8272芯片面积竟远大于NEC版本。

补充参考资料

  • StarDot 论坛讨论串,调查过程在此展开: [链接]
  • Sean Riddle 的 decap 页面: [链接]
  • beebjit 的 8271 驱动程序: [链接]
  • BBC Micro 平台的 8271 测试工具(警告:粗糙版):[链接]
  • 8271反汇编实时文档: [链接]
  • 8271与8273芯片超高分辨率实物照片(注意:可能导致浏览器卡死!):[链接]

本文文字及图片出自 Reverse engineering a forgotten 1970s Intel dual core beast: 8271, a new ISA

共有 60 条评论

  1. 我只对英特尔8272略知一二(通过Amstrad CPC中的NEC uPD765软盘控制器接触过),但这些老式软盘控制器芯片最迷人之处在于其“API”的高级程度以及完全自主的运行方式。

    芯片能接收“寻址至xyz轨道”、‘格式化轨道’、“读取轨道”或“读写特定扇区范围”等指令,随后便自行执行操作(数据传输可选DMA模式——但CPC不支持此功能),几秒后便会反馈“操作完成”或“发生错误”。。

    人们通常更期待这类功能由高级操作系统程序或软件驱动程序实现,而非直接固化在硬件中。这也解释了该芯片的复杂性(例如22k晶体管,是6502的6倍,Z80的2.5倍)——因为它本质上就是个完整的CPU,配备微代码ROM,外加些软盘控制器模块 😉

    • > 通常人们更期待这类功能由高级操作系统函数实现

      几乎违背直觉的是,早期软盘驱动器相较于CPU其实速度极快。DMA传输的主要目的在于绕过CPU处理。针对CHS寻址,某些格式会采用扇区交错存储方案(例如:1,6,2,7,3,8,4,9,5)。这种设计刻意将连续数据分散存放,使CPU在处理跳跃数据时有时间处理连续数据段。增加CPU负载会加剧这种现象,这也是专用FDC芯片始终存在的原因。

      有趣的是,ISA DMA接口的采用导致现代主板无法搭载功能完整的原生软盘控制器——这种设计已不复存在。

      • 若控制器本身具备足够速度和内存,是否真的需要DMA?难道不能用现代硬件模拟这种行为吗?

        • 在PC平台上,软盘驱动器硬连线连接到DMA通道2。DMA“通道”最初由Intel 8237A DMA控制器或兼容器件提供,这属于ISA设备。

          DMA和FDC控制器功能已被芯片组接管。ISA演变为LPC总线,该总线至今仍存在——我认为它会继续存在,因为TPM模块仍在使用它。但不确定现代PCH是否仍保留ISA DMA功能。软盘驱动器曾是唯一依赖该功能的设备。

          PC软盘驱动器并非必须使用DMA,也可采用PIO模式。

          因此…

          – 您需要为操作系统创建PIO软盘驱动程序

          • 你需要一个能将软盘控制器信号转换为LPC信号的设备(两者信号格式不同),而这样的设备并不存在(只能靠FPGA爱好者项目来解决)

          – 你需要将该设备接入现代PC的LPC总线,这意味着必须将LPC引脚物理连接至主板上的LPC调试接口(前提是主板具备该接口——若无则需自行加装排针)

          – 接着需将电源供应器的SATA电源转换为软盘所需的四针迷你Molex接口。现有标准方案是通过大号Molex(IDE硬盘接口)转双迷你Molex适配器,配合SATA转Molex转换器即可实现“拼装”。

          • LPC完全支持DMA,市面上有现成的LPC超级I/O芯片支持软盘驱动器。还有这个项目试图从LPC复活ISA总线https://www.vogons.org/viewtopic.php?t=93291

            >ISA演变为LPC总线,至今仍存续——且我认为将持续存在,因为TPM

            已被近十年历史的eSPI取代。而eSPI已取消DMA支持。

    • >ISA演变为LPC总线,该总线至今仍在使用——我认为它将持续存在,因为TPM技术早已被问世近十年的eSPI所取代。而eSPI则取消了DMA支持功能。

      这段历史发生在我出生之前,但我认为这种设计思路源于小型计算机——在首批控制器芯片问世时,软盘的主要应用场景正是小型计算机。小型计算机接口板(至少我熟悉的PDP-11型号如此)既能卸载主CPU的实时处理任务,又能为不同物理硬件提供统一的软件接口。此外,小型机环境的经济性考量也倾向于采用更复杂的接口板,而非拖慢CPU速度并增加操作系统复杂度。需注意的是,当时尚未形成现代设备驱动的概念——若运行Unix V7系统,需向内核代码库添加源代码并重新编译才能支持新型设备。这种机制使得在操作系统层面,新硬件往往被视为旧硬件的变体。采用更复杂的接口板更易实现这种设计。

      • 1979年左右,我们通过前面板拨动开关从磁带启动DG Nova 2计算机,读取初始引导程序。这种方式颇为实用:只需几条指令就能让智能驱动控制器将磁带首块数据加载到内存零地址,随后添加跳转至零地址的指令即可。这省去了购买ROM卡的开销。我手指间记住的切换启动序列动作,如同背诵巴赫赋格曲般精准流畅。

    • 我认为这是史蒂夫·沃兹尼亚克的洞见之一,正是这种理念使他们能将Apple II硬件设计得比竞争对手更简洁、更廉价。他们将这类技术理念融入了操作系统。

      Commodore同样采用复杂芯片——例如1541磁盘驱动器竟与C64主机共用6502处理器!他们能在80年代保持价格竞争力,全赖掌控核心芯片供应商MOS科技。

      • 这取决于具体应用场景。有时为加速上市和简化工程设计,英特尔方案相当不错——尽管显然有些特立独行。毕竟不是每个人口袋里都装着个沃兹。

      • Mac IIfx/Q900/Q950系列的软盘API处于类似水平,由其中一个IOP协处理器实现。

    • 这与现代磁盘控制器的自主性相当。

      而Commodore磁盘驱动器则更高级。它们的工作层级接近文件服务器,能处理“列出目录”等命令。DOS系统直接运行在驱动器上。

      • 这本质上属于不同层级的架构。PET磁盘外壳内部集成了软盘控制器和CPU,用现代术语来说更接近网络文件服务器。

      • 这大概是我第一次觉得DOS这个名字名副其实呢 🙂

    • 人们更希望这类功能能在高级操作系统函数或某种软件驱动程序中实现,而非直接固化在硬件中。

      仅就常见于众多MSX软盘系统的TMS2793芯片而言。诸如“寻道”之类的操作,本质上是FDC脉冲发送若干次“磁头步进”信号,并(可选地)尝试读取磁盘上的扇区标记以验证读写磁头是否到达正确磁道。

      诸如“读取扇区”或“格式化磁道”等操作并非由该FDC独立完成,它仅作为启动该过程的指令。CPU(此处为Z80)通过轮询FDC状态位,将待格式化磁道内容逐字节传递给FDC,整个过程由紧密编程的循环控制(每轮约10微秒,无DMA支持)。

      部分数据需计算CRC校验值,据我所知该操作由FDC硬件完成。

      因此总体而言,该FDC内置的“智能”功能相当有限。我认为当时大多数FDC都如此,而本文所述的8271实属例外。当然,对于更先进/后期的FDC(如奔腾时代及后续PC芯片组内置的型号),情况可能截然不同。

      • IBM PC使用的NEC765控制器同样属于“高级”类型,后续所有兼容机型亦是如此。该控制器不存在读写原始数据的指令,用户需指定(起始)扇区号,控制器开始读取磁盘后,仅在发现匹配的头部字段时才会通过DMA传输数据字段。

    • 某些386/486主板的设计更显蹊跷,不熟悉其结构者绝难猜中处理器型号,例如:

      http://www.amoretro.de/2012/05/386sxa-ver-4-0-motherboard-mi

      https://theretroweb.com/motherboards/s/ampro-little-board-48

  2. (2020)

    相关讨论参见:https://news.ycombinator.com/item?id=25115916

  3. 我认为Acorn在软盘驱动器上采用这些芯片是个重大失误,它们价格昂贵且供货不稳定。本应选用WDC1770替代,但事已至此。

    • Acorn最终确实意识到这个问题,自1984年起改用177x系列芯片。

    • Acorn的管理实在糟糕透顶。BBC微机推广计划堪称金钱能买到的最佳营销,可Acorn竟在销售大量BBC微机/大师机的同时,连BBC的专利费都付不起。

  4. 我超爱这些芯片解密攻略。不过选这个芯片实在太奇怪了——几乎没人用它做量产硬件。WD 17xx系列才是70年代到80年代初软盘控制器的王者(当然,如果你忽略沃兹那块分立逻辑的杰作的话)。

    既然要逆向分析冷门芯片,选个应用场景更奇特的芯片岂不是更有趣?

    • 我们当然追求趣味性!这可以从两方面理解:1)因应用场景独特/标志性而有趣,或2)因芯片本身独特而有趣。这次显然属于后者:一块拥有有趣历史的奇特芯片。

      • 下个目标应该是为它编写演示程序,参加2021年Demosplash大赛。

    • > 沃兹的杰作,采用分立逻辑设计

      其缺点在于需要精确时序控制。若想在机器中实现更快的(甚至稍有改进的)6502处理器,这便成了问题。

      唉…

      • 不过苹果II的所有竞争对手都没能利用这个优势。当时整个软件生态都围绕着严格的硬件假设构建。雅达利、VIC、Commodore,没有一家公司推出过更快的CPU。这需要等到后续架构的出现。

        不,Disk II绝对是杰作。请重读链接文章,想想这颗极其复杂的芯片实现了多少功能,然后想想沃兹用六颗在Radio Shack就能买到的芯片和两块微型ROM,就做出了功能完全相同的卡。

        • 我熟悉这个设计。当时唯一对时序依赖性更低的计算机是S-100和CP/M机型——只要内存速度允许,你就能直接更换更快的CPU。

          我不认为这是错误——当时没人预见到我们最终会每隔几年就把软件迁移到更快的计算机上。沃兹固然天才,但他不可能预见到这一点,正如你指出的,几乎无人能预见。

      • 这让我意识到Zip芯片远比儿时的我想象复杂得多:

        https://en.wikipedia.org/wiki/Apple_II_accelerators#Zip_Chip

        • 这些东西堪称惊人的工程杰作。现在肯定有人在为复古计算机爱好者复刻类似产品。

          用现今技术,完全可以在模块内保留全部内存,只需异步输出部分写入操作(视频和I/O)就能达到Apple II的运行速度。

      • 当年没人预料到微型计算机硬件架构能拥有长生命周期,更不会想到每年都能实现CPU的渐进式升级。

  5. 软盘驱动器控制器芯片的成本和性能都优于主CPU,这让我想起自己的一些Arduino项目。

    比如我曾用AT Mega 8位微控制器编程驱动GSM调制解调器(通过串口连接),而该调制解调器内部搭载了相对先进的ARM SoC芯片。这个项目在教育意义上很棒,但过程着实令人捧腹 🙂

    • Commodore 64的磁盘驱动器性能甚至超越了CPU,不仅搭载了相同的6502处理器,还配备了一对6522控制器。有趣的是,某些程序会将数学运算任务上传至磁盘驱动器以加速处理。

      https://www.lemon64.com/forum/viewtopic.php?t=27911

      • 早期激光打印机亦是如此。初代Apple Laserwriter搭载的68000处理器时钟频率高于初代128k/512k Mac机型。

        • 但它确实需要运行PostScript,而该语言在早期设备上运行极为缓慢。

  6. 许多专用集成电路本质上是带掩模ROM(有时是EEPROM,会产生有趣的后果)的通用处理器,因为编写不同功能的“固件”比设计整颗“硬编码”芯片更简单——各类USB转X接口适配器就是典型例子。

    • 几天前,我买了一块不知名厂商生产的USB转串口芯片。发现RX/TX端口能正常工作,但控制信号失效。用示波器检测芯片时,发现相关引脚处于高阻抗状态,芯片甚至没有尝试输出任何信号。联系技术支持后,对方告知需购买新芯片——因我的芯片属于未实现该功能的旧批次(我猜是设计缺陷),但他们可在保密协议下提供固件更新。

      这完全是微控制器在作祟。

      趣闻:灰色市场上的假冒FTDI FT232芯片也是如此制造的。造假者直接选用廉价的通用微控制器批量生产,并为其编写掩模ROM。有趣的是,这些假冒芯片的工艺节点反而优于正品(当然这并不意味着性能更优)。

      https://zeptobars.com/en/read/FTDI-FT232RL-real-vs-fake-supe

      • 但仿制品确实有所改进:它们修复了原版FTDI芯片存在的缺陷(这些缺陷严重到让某些模式完全无法使用)。

        https://twitter.com/marcan42/status/695292366639378433?s=19

        切勿购买FTDI芯片;其恶意驱动事件曾导致克隆芯片变砖(通过利用其芯片自身EEPROM写入支持中的_另一个_漏洞!),这足以让所有电路板设计师敬而远之。

        • 仿制芯片未必更优,它们或许修复了原版芯片的部分缺陷,但可能存在自身问题。虽然可能存在优质仿品,但无法确认你获得的芯片是否可靠。最好完全避开FTDI芯片,无论真伪。需要说明的是,自那次驱动程序事件后我从未使用或购买过任何FTDI芯片,我提到的芯片并非FTDI产品。

        • 我需要USB转串口转换器时,正是因为那次恶意驱动事件,特意避开了所有基于FTDI的型号。

          • 我使用过基于Microchip MCP2200、SiLabs CP2102、Prolific PL2303或WCH CH341的产品,避开FTDI其实很简单 😉

      • USB蓝牙适配器同样如此——许多产品宣称采用剑桥硅无线电(CSR,现属高通)芯片,实则使用廉价替代品。

        这些仿制品往往存在各种怪癖,Linux驱动程序中为此添加的变通方案相当可观。8.5版及以上内核似乎已整合了大部分修复,但在此之前可参考如下补丁:

        https://gist.github.com/nevack/6b36b82d715dc025163d9e9124840

        尽管驱动程序维护者付出了巨大努力,我还是找到一个廉价的“CSR 4”加密狗,日志里满是各种错误且无法正常工作。目前正在等待基于博通芯片的替代品到货。

    • 大量Realtek产品采用某种形式的MIPS核心(至少曾经如此)。

    • 此设计决策还涉及安全层面——若有人能找到向这些微控制器注入任意代码的方法,将导致各类权限被彻底开放。

  7. BBC微机选用此芯片(而非威盛芯片)的决策,让我不禁思考:经典计算机设计中是否还存在其他事后看来明显糟糕/怪异/临时拼凑的选择?

    PC-AT用键盘控制器控制A20信号和CPU复位的设计便令人印象深刻。

    还有其他例子吗?

    • 当年几款游戏机(如Magnavox Odyssey 2和Entex Adventurevision)竟采用本文提及的MCS-48微控制器,而非当时更主流的6502或Z80处理器,这确实有些奇怪。

      作为同时接触过MCS-48和6502汇编语言的人,我可以肯定这绝非为了简化软件开发。:) 我推测或许是因为围绕微控制器设计硬件更便捷?…当然也可能存在其他原因…

      • 6502和Z80这两款处理器最初的设计初衷是用于嵌入式系统,而非它们后来声名鹊起的通用计算机领域。

  8. 我猜想,当时Acorn公司的某位经理询问工程师们推荐使用哪种磁盘控制器时,工程师们显然开玩笑地回答了“8271”。

    等他们意识到自己说了什么时,为时已晚。

    • 若指BBC微机,Acorn此前在“System”和“Atom”机型[1]中已采用8271支持软盘,因此很可能是延续了既往设计惯性。

      至于更早的系统,有人知道WD 1771(更常见的替代方案)的具体日期吗?维基百科页面显示的数据手册日期为1979年4月,若此为发布日期,那么在1979/80年System和Atom机型推出时,相较于英特尔芯片,它仍属未经市场检验的新元件(前提是软驱属于早期升级部件——同样,我手头没有确切日期)。

      [1] http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/Aco

      • 谷歌图书显示WD1771于1977年上市并投入使用,1978年采用该芯片的产品数量增加。

        (谷歌图书对此类历史考证极具价值。将时间范围设为“1977-1980”,搜索“wd1771”,再按日期排序即可。虽非详尽无遗,但能以极低成本获得整体概览。)

        • 感谢你的研究。既然如此,我猜这更像是1979年在零件选择上押错了注吧。

        • 题外话:真希望谷歌也能对网页搜索结果提供类似功能——能按数年前的索引状态精确检索,只显示当时实际收录的内容。

      • 完全可信——机构惯性使然,他们宁愿沿用熟悉的芯片,也不愿采用刚上市的新品。新芯片或许更优,但集成过程可能耗费一两个月开发时间,这还是假设不会遇到意外漏洞的前提下。

        不过后续机型转向更便宜且技术更先进的芯片,倒也不足为奇。

  9. 目前是否有技术能在家中拆解并拍摄芯片照片?例如对老式PAL芯片进行逆向工程?

    • 这些芯片采用陶瓷封装,拆封只需用凿子沿接缝轻敲即可。若需高质量晶圆照片,则需配备金属显微镜——其通过透镜垂直投射光源。我的显微镜购自eBay。收集大量晶圆照片后,可用Hugin等软件进行拼接处理。

    • 扫描仅需显微镜和开源全景拼接软件:http://www.righto.com/2015/12/creating-high-resolution-integ

      据我所知,家庭去封装是可行的,但需要使用“硝酸熏蒸”和“喷枪”等方法,这两种方法我现在都不太想尝试。

      resilicon.reddit.com 正在变得相当活跃,如果你感兴趣的话。

  10. D765实为D765B,可能是缩小版,故芯片尺寸不同。

  11. 我的BBC微机里就装着这玩意儿,真没想到竟是双核怪兽。难怪当年售价如此高昂。

  12. 太不可思议了!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注


京ICP备12002735号