_evidence/vol2/ 脚本算出、可复跑;外部资料=邮件、官方说明、扫描原件,附出处;推断标为作者推导。比喻单独标注,不算证据。本册沿用第一册的行号纪律:差异清单里的 5 位数是被对比文件自身的行号 × 10;这两个文件与行号主基准树并不逐行对齐,正文行号一律以主基准树(3_source_code)为准、逐处直读核对。第一册停在 1981 年 4 月 28 日:86-DOS 1.00 定版。基准源码文件 86DOS.ASM 有 3,622 行,分发表有 42 个功能槽,其中 5 个仍是空壳。本册比较 5 月 5 日和 6 月 16 日两个文件之间的差异。按照本册的分块规则,一共得到 117 个改动块;「改动块」是本文的分析单位,不是原作者留下的提交记录。标题中的 42 天,指这两个文件头时间戳之间的日期差。问题也随之明确:这 117 个块分别改变了什么,哪些变化可以解释,哪些只能停在未知?
标题中的 42 天来自差异清单文件头,而不是 4 月 28 日到 6 月 16 日的日历差。4 月 28 日是 1.00 的定版日,写在源码台账上;5 月 5 日 10:56 是差异清单 File 1 的时间戳,Paterson 认为它与 4 月 28 日的 v1.00 非常接近,可能对应上传到微软服务器的日期;6 月 16 日 14:25 是 File 2 开发快照的创建时间。因此,86DOS.DIF 比较的是 5 月 5 日的 86DOS.ASM 和 6 月 16 日的 86DOS.A86,两端相差 42 天;书名《四十天》取的是便于阅读的约数。清单中的 5 位数字(如 00230、38750)属于被比较文件自身的打印行号。它们在这份清单中按源码行号乘 10 编排,但被比较的旧文件与 3_source_code 主基准树并不逐行一致:旧侧卷首多一个空行,FAT 注释也有合并和拆分。所以正文的行号一律回到主基准树直读,打印行号只用于引用差异清单本身。
差异清单用星号行分节:四个星号分隔旧侧和新侧,十个或更多星号才表示一个改动块结束。按这个规则切分,共得到 117 块:两侧行数相同的修改 25 块,新侧更多的新增 57 块,旧侧更多的删除 35 块。改动分散在各个区域,没有出现连续的大段整体替换;这支持「局部演化多于推倒重来」的判断,但它本身不能证明每一块改动的原因。
117 块里,96 块落在功能实现区(占 82%),9 块在系统调用分发表,剩下 12 块分散在头部、数据结构、入口和数据区。按每 400 源码行分格,前 400 行有 22 块,2800–3199 行有 17 块。前者覆盖常量、数据结构和入口,后者主要落在字符输入输出等功能实现区域;第 5 章会分别说明这些区域的改动内容。
1.00 已经是一个可以发布的操作系统。为什么四十二天之后,它还需要被大改?这些改动是在加功能、修问题,还是在为 IBM PC 这个即将到来的硬件环境重新塑形?
117 个改动块是材料,不是结论。本文对每组变化依次检查:改了什么、位于哪一层、是否能从其他材料解释其作用,以及后续版本是否保留了它。为了便于比较,改动先按保留、替换、新增和移除四种结果归类。
这份差异清单是打印件的转录,可能包含誊抄噪声。改动块可以证明源码文本发生了什么变化,但不能单独证明作者为什么这样改;涉及动机时,本文会另找批注、当事人材料或上下文,并把推断单独标出。117 块中有 86 块没有得到可靠的自动初判,初筛结果只覆盖 31 块。这 86 块仍然需要逐块阅读,不能把关键词分类当成最终结论。
| 档位 | 事实 | 出处 | 复核方式 |
|---|---|---|---|
| 外部资料 | 差异清单文件头:File 1) 86DOS.ASM created 05-MAY-1981;File 2) 86DOS.A86 created 16-JUNE-1981 | 86DOS.DIF 文件头原文(bundle_08) | 直读;天数由 vol2_catalog.py 计算 |
| 数据实证 | 117 块;增 57 / 删 35 / 改 25;96 块落在功能实现区(82%);最密段为源码前 400 行(22 块) | vol2_catalog.py 与 vol2_change_catalog.csv | 分块规则与换算写在脚本头部,可复跑 |
| 源码实证 | 4/28 定版(Renumber for general release) | 86DOS.ASM:15(第一册第 1 章) | 直读 |
| 外部资料 | 5/5 与 4/28 的关系(上传服务器时间戳口径) | Tim_Paterson_24Apr2025_emails.txt | 邮件原文 |
第一处改动只改了一行常量:SMALLDIR 在 1.00 中为 1,在 6 月 16 日快照中变为 0。这个开关与 0.42 引入的 32 字节目录项有关;关闭它,会让一批只在汇编期保留的旧格式分支不再进入产物。本章先说明这一行改动牵连了哪些代码,再讨论它后来如何退出。
SMALLDIR: EQU 1 对 SMALLDIR: EQU 0,中间用四个星号隔开旧侧与新侧,整块以十四个星号结束。同一页往下还有第 2、3 块(DSKTEST 与 MAXCOM/ESCCH),MAXCOM/ESCCH 将在第 4 章讨论,DSKTEST 的变化见第 6 章。纸是连续纸,左侧是进纸链孔,右下角是页码 090247。差异清单的第一块,新旧两侧各只有两行,改的就是那个常量:
从 1 到 0。清单上没有写原因,也没有写这一天还发生了什么,清单只记录「两份文件在这里不一样」。要知道这行常量改变了什么,得回到源码里逐项统计。
SMALLDIR 是一个汇编期开关:汇编器在读到 IF SMALLDIR 时,按它的值决定底下那段代码要不要编进系统。它不是运行时才判断的变量,关掉它,等于让一整片代码在汇编阶段就消失。
vol2_smalldir.py 逐条统计了两个版本中的出现位置。1.00 共 15 处:定义 1、条件汇编分支 13、引用 1;6/16 剩 13 处:定义 1、分支 12,引用消失。6/16 中的 12 个条件分支分布在 111、537、578、617、814、880、961、1092、2434、2518、3723、3733 行,从目录项处理一直延伸到数据区;3723 行还使用了 IF SMALLDIR-1,表示开关为 0 时编入另一支代码。因此,改变一个 EQU 值会改变多处汇编期选择;这里的「牵连」只统计源码文本,不等同于运行时影响。
差异清单第 48 号改动块还显示了一个具体后果:旧侧 1028 行附近的 XOR AX,AX 被删去,新侧保留了 IF SMALLDIR 的分支开头。开关值变为 0 后,与旧目录格式有关的那段清零动作不会进入汇编产物。
SMALLDIR 保护的是目录格式相关的汇编分支。0.42 把目录项从 16 字节扩到 32 字节后,数据区起点和可用簇数都会变化;源码因此准备了两套参数:FIRREC1/MAXCLUS1 对应 16 字节目录,FIRREC2/MAXCLUS2 对应 32 字节目录。13 个条件分支分布在目录项处理、搜索、FAT 读取和数据区等位置。当开关为 0 时,条件汇编会把其中属于旧格式的代码排除在产物之外。
清单没有写原因,动机就不能当作源码事实。能摆上桌面的只有三点:第一,关闭发生在 6 月 16 日的开发快照里,同一时期的代码正在为 IBM PC 适配新的硬件假设(见下一章);第二,如果目标发行形态已经不再需要 SCP 旧目录格式,继续编入这套兼容分支的收益自然会下降,但这只是与时间线相容的解释,不是材料明说的决定;第三,SMALLDIR 在 1.20 的修订台账中被写成 Kill SMALLDIR,后来确实从系统里消失。把这三点放在一起,可以看出它的退场方向;至于 Paterson 当时的具体考虑,纸上没有留下答案。
从现有版本可以确认,SMALLDIR 的值经历了 1 → 0,随后在 1.25 的修订台账中被删除。这说明旧目录格式的兼容路径先被关闭,之后连相关定义也退出了源码。至于关闭它时是否明确针对 IBM PC,差异清单本身没有留下直接说明。
| 档位 | 事实 | 出处 | 复核方式 |
|---|---|---|---|
| 源码实证 | SMALLDIR 在 1.00 牵连 15 处(定义 1 / 分支 13 / 引用 1),在 6/16 牵连 13 处(定义 1 / 分支 12) | vol2_smalldir.py 输出;1.00 :22,118,507,539,578,737,810,893,1006,1015,1041,2330,2415,3381,3391;6/16 :22,111,537,578,617,814,880,961,1092,2434,2518,3723,3733 | 全部出现位置逐条列出,注释行不计入;口径毛边留档:1.00 :1015 的 IF 1-SMALLDIR 同为取反,因不是行首 IF SMALLDIR 被计入「引用」而非「分支」 |
| 源码实证 | 差异清单第一块:SMALLDIR EQU 1 → 0(两侧行号同为 00230) | 86DOS.DIF 第一改动块 | 直读 |
| 源码实证 | 开关关掉后相关代码被删(旧侧含 XOR AX,AX 与 IF SMALLDIR) | 86DOS.DIF 第 48 号改动块(旧侧 1028 行附近删 1 行) | catalog + 直读 |
| 源码实证 | 1.20 台账写 Kill SMALLDIR | MS-DOS_1.25/MSDOS.ASM 修订台账 | 直读(第一册第 6 章已引) |
| 作者推导 | 关闭动机与 IBM PC 即将到来相关(三条事实并列,方向清楚;具体想法纸上没写) | 由时间线与发行配置推得 | 推断已标注;不冒充源码证据 |
117 个改动块中,有一部分改的是硬件假设,而不是面向用户的新功能。1.00 把 BIOS 段地址和内存检测方式写在内核里;6 月 16 日快照则修改了这些位置,同时把部分硬件访问收进内核自己的例程。把这几组改动放在一起,可以看出代码如何适应新的运行平台。
BIOS 是机器提供的底层输入输出程序,早期系统通常通过固定入口调用它。8086 使用段地址访问内存;可以把段号暂时理解为一段内存区域的编号。在 1.00 中,BIOS 所在段被写成一个符号:
6 月 16 日快照把 BIOSSEG 改为 60H。1.00 中的 BIOS 远调用都通过 BIOSSEG 这个符号取得段地址,所以同一个常量的变化会影响所有采用这种写法的调用点。这是符号寻址带来的整体替换效果;它不等于所有硬件访问都已经完成抽象。
按 CALL BIOSxxx,BIOSSEG 形式统计,1.00 有 18 个直接调用点,6/16 剩下 15 个。6/16 中可以找到 AUXIN(:363)、AUXOUT(:370)、LISTOUT(:3093)和 STATCHK(:2968)等内核例程,部分设备访问因此先经过内核自己的接口,再由接口调用 BIOS。控制台和磁盘路径仍保留直接调用,所以这里描述的是局部收拢,而不是完整的硬件抽象层。
另一处变化是内存检测。1.00 中有 MEMSCAN 例程,内核通过读写高位地址来探测内存边界;6/16 快照删除了这段循环,改用 INT 12H 请求 BIOS 报告内存大小(以 1K blocks 计)。
这组改动把「内核自行探测」换成了「向平台询问」。同一份差异清单还显示,BIOS 返回的内存大小被放进数据区,供后续初始化使用。因此可以说,6/16 快照把一部分硬件知识交给 BIOS;但这只是对这几处改动的概括,并不表示整个内核已经与硬件完全解耦。
| 档位 | 事实 | 出处 | 复核方式 |
|---|---|---|---|
| 源码实证 | BIOSSEG 从 40H 改为 60H,全部 BIOS 调用经同一符号寻址 | 1.00 :132;差异清单第 7 块 | 直读 + 差异清单 |
| 数据实证 | 直接 BIOS 调用点 18 → 15;6/16 新增内部例程 AUXIN :363 / AUXOUT :370 / LISTOUT :3093 / STATCHK :2968 | vol2_data.py A 节输出 | 两版本按行型正则统计 |
| 源码实证 | MEMSCAN 循环被删除,替换为 INT 12H 取内存大小 | 差异清单第 114 块(旧侧 MEMSCAN:/HAVMEM,新侧 INT 12H) | 直读 |
| 作者推导 | 「硬件知识从操作系统挪到 BIOS 层」是对这三组改动的概括 | 由上述三处合成 | 推断已标注;改动本身是源码事实 |
6/16 快照新增了 42–45 四个日期时间入口。手写批注把这项工作联系到 IBM 时钟;源码则可以把它拆成四个层次:接口、实现、可写状态和文件中的日期字段。本章按这四层检查一项日期时间需求如何进入内核。
6/16 快照的系统调用分发表(源码 :325)末尾新增四个入口:42 取日期、43 置日期、44 取时间、45 置时间。1.00 的分发表中没有这四项;日期时间功能从这些编号进入内核。
四个功能各有实现体(:3373、:3386、:3436、:3485)。读取路径中的 GETDATE 和 GETTIME 会调用 READTIME(:3324),源码注释说明它负责处理跨午夜的日期变化;SETDATE 和 SETTIME 则在参数检查后直接调用时钟服务。以 GETDATE 为例(6/16 快照 :3373 起),它从内部变量取出年份和日序,把年份加回 1980,再把月日写入用户寄存器。
READTIME 使用的 YEAR(:3552)、DAY 等变量位于源码末尾的 DATA AREA(:3537 起)。日期时间功能除了新增四个例程,也新增了保存运行状态所需的变量;这说明接口变化会继续传到内核的数据区。
日期字段在 1.00 中已经存在两个位置:FCB 的 FDATE(:65),以及目录项偏移 24 起的位场日期(:83)。6/16 快照又调整了这两处的注释和相关结构(:70、:89)。因此,新增的不是「第一次保存日期」,而是面向应用程序的日期时间调用,以及与之配套的读取、设置和状态管理路径。
SMALLDIR 的变化减少了一条旧格式路径,DATE/TIME 的变化增加了一组新接口。同一份差异清单里,兼容路径的关闭和平台功能的增加同时发生;这比单独统计 117 个改动块,更能说明这轮修改同时包含删减和扩展。
| 档位 | 事实 | 出处 | 复核方式 |
|---|---|---|---|
| 源码实证 | DISPATCH 末尾四格(42–45 日期时间)只在 6/16 出现 | 6/16 快照 :325 附近;1.00 :302–346 无此四格 | vol2_data.py C 节 + 直读 |
| 源码实证 | 四个例程与 READTIME、YEAR 变量的行号 | 6/16 快照 :3373 / :3386 / :3436 / :3485 / :3324 / :3552 | 脚本定位 + 直读;读取路径与设置路径分别检查 |
| 源码实证 | GETDATE 处理跨天、年偏置 +1980、结果写回 CX/DX | 6/16 快照 :3373–3384 | 直读(第一册第 6 章已引) |
| 外部资料 | 手写批注 DATE/TIME FUNCTIONS ADDED FOR IBM CLOCK | archive.org paterson_listings 之 images/listings.jpg | 裁切放大逐字确认(第一册已核) |
第 3 章新增了日期时间功能;本章只看接口编号本身如何变化。6/16 快照有两处需要分开理解的事实:12 号槽从 VERSION 改为 FLUSHKB,同时 MAXCOM 从 41 变为 45。前者是一个槽位的语义替换,后者是中断入口允许的上限变化。
第一册讲过 1.00 的分发表有 42 格,6/16 快照有 46 格;而 MAXCOM 是 41 抬到 45。这两组数字不是一回事:
上限表示允许调用的最大功能号,表长表示分发表中实际有多少个表项。1.00 的功能号从 0 到 41,所以 MAXCOM=41 对应 42 个表项;6/16 从 0 到 45,所以 MAXCOM=45 对应 46 个表项。两者相差 1,只是因为编号从 0 开始。
1.00 的 12 号槽指向 VERSION,其函数体只把 AL 清零后返回。6/16 快照中,VERSION 标号消失,12 号槽改指 FLUSHKB,后者直接重置 IBM PC BIOS 数据区中的键盘缓冲指针。这是槽位语义的替换,不只是函数改名。1.00 空壳簇中的其他标号大多仍被保留,其中 GETIO、SETIO 原本就没有被分发表引用;后续版本对这些空壳的处理并不完全相同。
MAXCOM 从 41 变为 45,数值上正好覆盖新增的四个日期时间槽;MAXCALL 仍为 36,因此这些新增槽不属于 CALL 5 的兼容入口。按同一套 CP/M 2 对齐口径,1.00 的对齐槽为 34 个,6/16 为 33 个,1.25 为 32 个。分发表扩大与对齐槽减少,是同一条接口演化中的两个不同指标。
| 档位 | 事实 | 出处 | 复核方式 |
|---|---|---|---|
| 源码实证 | VERSION 标号自 6/16 起消失,12 号槽改为 FLUSHKB;其余六个空壳标号保留 | vol1_evolve.py 空壳去向表(第一册管线);6/16 快照无 VERSION 标号 | 脚本比对 + 直读 |
| 源码实证 | MAXCOM 41 → 45;MAXCALL 不变(36) | 差异清单第 3 块;1.00 :44–45 与 6/16 快照同位置 | 直读 |
| 数据实证 | 上限与表长恒差 1(功能号自 0 编起):41/42 → 45/46 | vol2_catalog.py 的 DISPATCH 提取 | 脚本可复跑 |
| 作者推导 | 「容量变大、重叠变小发生在同一张表上」是对两组数字的概括 | 由第 4 章数据合成 | 综合判断 |
把 117 个改动块按旧侧起点放回源码,可以看到它们并不均匀分布。前 400 行有 22 块,2800–3199 行有 17 块。这只是文本变化的密度,不是开发时间或工作量的测量;本章只讨论改动集中在哪里,以及这些区域各自改了什么。
按旧侧起点每 400 行分组,块数依次为:0–399 行 22 块,400–799 行 18 块,800–1199 行 16 块,1200–1599 行 9 块,1600–1999 行 7 块,2000–2399 行 6 块,2400–2799 行 11 块,2800–3199 行 17 块,3200–3599 行 11 块。前 400 行覆盖常量、数据结构、入口和分发表;2800–3199 行则落在字符输入输出等功能实现区域。
前 400 行的 22 块主要涉及常量、开关和表,包括第 1 章的 SMALLDIR、第 2 章的 BIOSSEG 和第 4 章的 MAXCOM。这些位置的共同特点是:一行定义可能被多个调用点引用,所以文本改动很小,影响范围却可能较大。
这 17 块可以按内容分成三类。第一类是行编辑器:ENTERINS 和 EXITINS 两个命令合并为 TOGGLINS(第 90、91 块),按键表随之调整。第二类是字符设备输出:LISTOUT、STATCHK 等例程(第 93–95、100 块)把状态检查和 Ctrl-S 暂停等逻辑集中到更明确的调用路径中。第三类是 FCB 构造和输入解析:MAKEFCB 一带(第 101–105 块)增加了引号、控制字符和大小写处理。同一区域还出现了 DATE16 例程,和第 3 章的日期功能有关。
1600–1999 行只有 7 块,主要对应顺序读写和随机读写实现。这只能说明本次差异清单在这段的文本变化较少,不能单独证明相关代码已经完全稳定或没有问题。把它和前 400 行、2800–3199 行的高密度区域对照,可以确认本轮修改更集中在接口骨架、硬件适配、字符输入输出和 FCB 解析等位置。
| 档位 | 事实 | 出处 | 复核方式 |
|---|---|---|---|
| 数据实证 | 每 400 行一格的块数分布(22/18/16/9/7/6/11/17/11,按差异清单旧侧起点行 ÷10 计);96 块(82%)落在功能实现区 | vol2_catalog.py 输出 | 分格统计可复跑 |
| 源码实证 | 高密段 2800–3199 的 17 块内容:行编辑命令合并(TOGGLINS)、LISTOUT/STATCHK 例程、FCB 构造的字符处理、DATE16 例程 | catalog 第 90–106 号块 + 6/16 快照对应行 | 逐块直读 |
| 作者推导 | 三组故事的归纳(行编辑/设备收拢/FCB 强化)与「密度低=已稳定」的解读 | 由块内容与分区对照得出 | 归纳已标注 |
第一章统计了 SMALLDIR 在两个版本中的出现次数。本章把这个统计拆开,说明定义、条件分支、引用和数据定义分别有多少处。这里使用「源码牵连度」这个名称,是因为统计对象是源码文本中的位置,不直接判断运行时哪些路径会被执行。
SMALLDIR 在 1.00 中出现 15 处:定义 1 处、条件汇编分支 13 处、引用 1 处。其中第 1015 行的 IF 1-SMALLDIR 是取反分支,处理开关为 0 时的路径。FIRREC1/FIRREC2 和 MAXCLUS1/MAXCLUS2 等参数也与这套分支对应,但它们属于结构上的关联,不计入上面的 15 处文本统计。因此,本章把文本计数和结构推断分开呈现。
同样的统计也应用到其他五个符号:SMALLDIR 15 → 13(分支 13→12,引用 1→0);DSKTEST 6 → 4;ESCCH 5 → 3;BIOSSEG 20 → 17;INTBASE 8 → 8;MAXCOM 2 → 2,但值从 41 变为 45。这组数字说明,部分符号在新版本中的文本引用减少,部分符号保持不变;它描述的是源码结构变化,不直接说明运行时行为。
SMALLDIR 是编译期开关,不是运行时变量。它的值会决定 12 个条件分支是否进入 6/16 的汇编产物,也会决定使用哪套目录参数。因此,改动虽然只有一行 EQU,结果却会出现在目录处理、搜索、FAT 读取和数据区等多处;「牵连度」能量化这些文本位置,但不能把它直接换算成开发成本或运行时影响。
| 档位 | 事实 | 出处 | 复核方式 |
|---|---|---|---|
| 数据实证 | SMALLDIR 的 15 处 / 13 处逐条明细(含行号与行型) | vol2_smalldir.py 输出 | 全量列出,注释行不计入 |
| 数据实证 | DSKTEST/ESCCH/BIOSSEG/INTBASE/MAXCOM 的牵连度对照 | vol2_ripple.py 输出 | 定义/引用/分支/数据四分量分别统计 |
| 作者推导 | 间接影响(磁盘参数)计入牵连;「十二个决策点」是对 12 个条件分支的解释 | 由 1.00 :118–3391 与 :118–123 的关系读出 | 解释已标注;分支计数是源码事实 |
117 个改动块中,关键词初筛只为 31 块给出唯一类别,其余 86 块因为未命中或命中多个类别而需要人工复核。本章用四个例子说明:关键词能帮助整理材料,但不能替代对代码上下文的阅读。
第 3 号块改动了 MAXCOM: EQU 41 → 45、ESCCH: EQU 1BH → 0,并保留 INTBASE。这些变化涉及接口上限和输入控制,但关键词表没有把 MAXCOM 或 ESCCH 列入任何类别,因此该块只能进入待复核清单。仅靠关键词,无法从常量名推断改动作用。
第 114 号块删除 MEMSCAN 循环,换成 INT 12H 请求 BIOS 报告内存大小。块文本同时命中兼容性和硬件适配关键词,脚本按规则给出兼容性初判并标记待复核。结合前后源码后,这一块更适合归入硬件适配:它改变的是内存检测方式,而不是 CP/M 接口。
第 20 号块调整了功能表附近的标号:旧侧有 READER,新侧出现 INUSE 和 GETDSKPT。脚本同时命中硬件适配、新功能和稳定性类别,并把它放入人工复核。结合分发表位置后,更准确的描述是接口布局调整;预设的三个类别都不完全合适。
第 101、105 号块修改了 FCB 构造中的字符终止、引号处理和大小写屏蔽。这些变化没有命中关键词,但读源码上下文可以看出它们属于输入解析。关键词没有命中,并不等于改动没有语义。
四种情况说明,自动分类只能用于初筛。31 块得到唯一类别,86 块则逐块对照旧侧、新侧和周边代码,再给出类别和置信度,并把结果写入 vol2_change_catalog.csv。脚本减少了机械查找,最终的语义判断仍然依赖源码上下文。
| 档位 | 事实 | 出处 | 复核方式 |
|---|---|---|---|
| 数据实证 | 自动初筛 31 块 / 待人工 86 块;四种失败模式各有一个真实案例(块 3 盲区、块 114 判错、块 20 多判、块 101/105 沉默) | vol2_taxonomy.py 的 classify 对 catalog 逐块重跑 | 本页可复现 |
| 作者推导 | 四个失败模式的命名与「初筛/复核」的分工 | 本文的方法论概括 | 作者推导;块的原文与初判是脚本输出 |
前面的章节分别看了兼容开关、硬件适配、新功能、接口槽位和改动分布。本章把这些证据合在一起,回答一个限定的问题:5 月 5 日到 6 月 16 日的变化,更接近局部演化,还是一次重新实现?
如果这四十二天是推倒重写,通常会期待看到大段代码整体替换、旧接口大量消失、数据结构断裂或版本记录中断。现有材料呈现的是另一种形态:117 个改动块分散在旧侧打印行号 230 到 38,750 之间,没有出现连续的大段替换;FCB、磁盘参数块和入口代码仍保持相同的总体结构;功能槽位的变化集中在少数位置,6/16 仍保留大部分原有槽位。这些证据更支持「在既有内核上持续修改」,但不能据此排除局部代码曾经重写。
把前面几条主线分别归纳:SMALLDIR 的值从 1 变为 0,12 个条件汇编分支不再按旧格式编入;其后 1.20 台账记录了 Kill SMALLDIR。BIOSSEG 从 40H 变为 60H,采用该符号的 BIOS 远调用随之改变目标段;这能证明 6/16 的硬件布局假设发生了变化,不能仅凭这两个快照断言该寻址方式此后一直保留。DATE/TIME 新增 42–45 四个槽、四个例程和状态变量;7 月批注把它联系到 IBM 时钟,1.25 仍保留这些日期时间入口。FLUSHKB 取代了 12 号槽的 VERSION,实现上负责重置键盘缓冲指针;1.25 的 12 号槽仍由 FLUSHKB 占用。其中「为什么改」只有日期时间的硬件联系有批注支持,其余动机都应按推断或未知处理。
综合这些证据,5 月 5 日到 6 月 16 日的变化更接近连续演化,而不是重新实现。理由是结构仍然连续,绝大多数接口槽位保留,改动分散在多个区域,且变化集中在硬件适配、日期时间和旧目录开关等少数主题。但这个结论的范围只到现有两份源码和差异清单;它不排除局部例程被重写,也不能还原每一次改动的具体动机。源码行数从 3,622 增至 3,888,净增 266 行;这个数字表示文本规模变化,不等于新增代码量。
| 档位 | 事实 | 出处 | 复核方式 |
|---|---|---|---|
| 作者推导 | 四条主线的五问回答与「连续演化」结论 | 由第 1–7 章证据合成 | 反事实与结论均为作者推导;所依据的事实(117 块分布、33/34 对齐、台账连续、266 行)见前七章 |
| 数据实证 | 净增 266 行(3,622 → 3,888);对齐槽数 34 → 33 | vol1_evolve.py / vol1_cpm.py(第一册管线) | 可复跑 |
前八章主要依据纸面材料。最后这一章再加上执行侧证据:先把源码汇编成机器码,再在仿真环境里观察它的行为。汇编和 1.00 侧运行实验已经完成;6/16 侧因缺少匹配的 DOSIO/初始化契约,仍停在静态和部分入口验证。
素材核对完成后,证据包在一台 Linux 环境中用 NASM 编译了社区对 Paterson 汇编器(SCP ASM 2.44)的重实现,再对 86DOS.ASM 执行汇编。这里使用的是现代兼容实现,不是 1981 年的原始汇编器;每一环都有日志和产物留存:
_evidence/vol2/remote_build/),命令与日志可复跑49 个字节表示源码编译内核与现代 IBM PC 适配复刻盘内核之间的差异,不是汇编器产生的错误数量。独立复核把它们分成五类:24 字节键位表、19 字节 BIOS 段基址、2 字节搜索检查旁路、1 字节 FCB 寻址修正和 3 字节行编辑引子。公开复现项目把这组变化概括为键盘映射补丁,但字节级证据显示,不能把 49 个字节全部归入键盘;每一类改动的历史动机也不能仅凭最终字节恢复。
汇编通过只能证明源码副本能被这份现代兼容汇编器接受并产出机器码,不能单独证明历史机器上的运行行为。49 个字节是 1.00 编译产物与现代 IBM PC 适配复刻盘之间的差异,不能作为 6/16 快照的通用补丁。1.00 侧的功能 12 实验已经完成;6/16 侧因为缺少匹配的 DOSIO 和初始化契约,完整引导尚未完成。
功能 12 是一个清晰的对照点:1.00 的槽位指向空壳,6/16 的槽位指向 FLUSHKB。但两个版本只有在匹配的 I/O 层和初始化表下才具有可比的完整运行环境。当前证据因此分成两层:1.00 有运行时结果;6/16 有汇编、机器码和部分入口探针结果,完整的清空行为仍未验证。
| 档位 | 事实 | 出处 | 复核方式 |
|---|---|---|---|
| 机器实证 | 源码 60,124 字节经 SCP ASM 2.44 重实现汇编,Error Count = 0,产出 5,446 字节内核;与现代 IBM PC 适配盘内核差异 49 字节 | BUILD_RECORD.md(`_evidence/vol2/remote_build/`) | 证明该源码副本能被兼容汇编器接受并产出机器码;49 字节分类见第四册 |
| 机器实证 | 1.00 侧功能 12 行为已完成;6/16 侧完整运行未完成 | 第四册第 5 章;`_evidence/vol4/E4_SUCCESS.md` / `E4_ATTEMPT.md` | 1.00 红屏已记录;6/16 因缺少匹配 DOSIO/初始化契约,按未验证处理 |
| 外部资料 | asm244l 来自 pts-86-dos-reconstruction;IBM PC 适配映像来自 TheBrokenPipe/86-DOS_PCAdaptation | 两个公开仓库 | 出处已在构建记录中注明 |
_evidence/vol2/ 下的脚本算出:catalog(117 块归档)、taxonomy(五类初筛)、ripple 与 smalldir(牵连明细)。差异清单是打印件转录,可能含誊抄噪声;关键块均已回两个快照源码核对。动机类表述均为推断并已标注。本页自包含:无外部请求、无脚本、样式全内联。