Bill Gates's Personal Easter Eggs in 8 Bit BASIC (2008)
比尔·盖茨在 8 位 BASIC 中的个人彩蛋 (2008)
[正文]
比尔·盖茨在 8 位 BASIC 中的个人彩蛋
2008-09-30 by Michael Steil
如果你在配备 BASIC V2 (1979) 的 Commodore PET 上输入 “WAIT6502,1”,屏幕左上角会显示字符串 “MICROSOFT!”。传说 是 这样 说的:比尔·盖茨本人插入了这个彩蛋,“在他与 Commodore 创始人 Jack Tramiel 发生争执之后”,“以防 Commodore 试图声称代码不是来自 Microsoft”。
在这一集 “Computer Archeology” 中,我们不仅会研究这个故事,还会追踪 Microsoft BASIC 在各种计算机上的历史,并了解 Microsoft 如何向 TSR-80 Color Computer 添加第二个彩蛋——因为他们忘记了第一个。
从 Apple 窃取?
整个故事听起来类似于 Apple 在 1983 年将 “Stolen From Apple” 图标嵌入到 Macintosh 固件中,这样,如果克隆者复制了 ROM,在法庭上,Steve Jobs 可以敲击克隆机上的几个键,显示该图标,并证明复制的不仅仅是“功能机制”,而是整个软件的逐字复制。
Altair BASIC
让我们深入研究 Microsoft 的 BASIC 解释器的历史。1975 年,Microsoft(当时仍然拼写为 “Micro-soft”)发布了 Altair BASIC,这是一个用于基于 Intel 8080 的 MITS Altair 8800 的 4 KB BASIC 解释器,尽管它有其他限制,但它包含一个 32 位浮点库。
一个扩展版本 (BASIC-80) 包含 8 KB 代码,其中包含额外的指令和函数,最重要的是,支持字符串。
适用于 6502 的 Microsoft BASIC
1976 年,MOS Technology 推出了 KIM-1,这是一个基于同一公司新推出的 6502 CPU 的评估板。Microsoft 将其适用于 Intel 8080 的 BASIC 转换为在 6502 上运行,保持了解释器的架构及其数据结构不变,并创建了两个版本:一个带有 32 位浮点库(6 位数字)的 8 KB 版本,以及一个带有 40 位浮点支持(9 位数字)的 9 KB 系统。
一些来源声称,虽然适用于 8080 的 BASIC 大小为 8 KB,但 Microsoft 就是无法将 BASIC 6502 放入 8 KB 中,而其他 来源 声称存在适用于 6502 的 8KB 版本。真相介于两者之间。Ohio Scientific Model 500/600(来自 1977/1978 年的类似 KIM 的微型计算机套件)和 Compukit UK101 的 BASIC ROM 确实大小为 8 KB,但与 8080 版本不同,它没有为 OEM 必须添加的特定于机器的 I/O 代码留下足够的空间,因此这些机器需要一个额外的 ROM 芯片,其中包含此 I/O 代码。
1977 年,Microsoft 将 6 位数字浮点代码更改为支持 9 位数字,并包含实际的错误字符串而不是两个字符的代码,同时保持其他一切不变。无论如何,带有 ROM 中 BASIC 的 6502 机器需要超过 8 KB,为什么不让它更大一点来添加额外的功能。6 位数字数学代码仍然是一个汇编时选项;1981 年的 Atari Microsoft BASIC 使用了该代码。
1977 年,Ohio Scientific 推出了 “Model 500”,这是 第一台 在 ROM 中包含(6 位数字)Microsoft BASIC 1.0 的机器。启动时,它会打印:
OSI 6502 BASIC VERSION 1.0 REV 3.2
COPYRIGHT 1977 BY MICROSOFT CO.
OK
同年,MOS 开始销售用于 KIM-1 的 9 位数字 Microsoft BASIC 1.1 的磁带版本。其启动消息为:
MOS TECH 6502 BASIC V1.1
COPYRIGHT 1977 BY MICROSOFT CO.
OK
Woz Integer BASIC
1976 年的 Apple I 是 KIM 之外第一个使用 MOS 6502 CPU 的系统,但 Steve Wozniak 编写了 他自己的 4KB BASIC 解释器,而不是许可 Microsoft 的。Woz 的 “Integer BASIC” 的增强版本出现在 1977 年的 Apple II 的 ROM 中;Microsoft BASIC(称为 “AppleSoft”)作为磁带上的一个选项提供。在 Apple II Plus (1978) 上,AppleSoft II 取代了 Integer BASIC。
Commodore PET
Commodore 于 1976 年 10 月收购了 MOS,并致力于将 KIM 平台转换为完整的计算机系统。他们获得了适用于 6502 的 Microsoft BASIC 的许可(也是 1976 年 10 月),将其重命名为 Commodore BASIC,用 “READY.” 替换了 “OK” 提示符,剥离了版权字符串,并将其运送到 1977 年的第一台 Commodore PET 的 ROM 中。
彩蛋
1979 年,Commodore 开始运送更新的 ROM,其中包含用于现有 PET 的 Commodore BASIC 版本 2。除了数组处理方面的更新外,它还包含 WAIT 6502 彩蛋。
这是彩蛋代码的样子:
.,D710 20 C6 D6 JSR $D6C6 fetch address and value
.,D713 86 46 STX $46 save second parameter
.,D715 A2 00 LDX #$00 default for third parameter
.,D717 20 76 00 JSR $76 CHRGOT get last character
.,D71A F0 29 BEQ $D745 no third parameter
.,D71C 20 CC D6 JSR $D6CC check for comma and fetch parameter
.,D71F 86 47 STX $47 save 3rd parameter
.,D721 A0 00 LDY #$00
.,D723 B1 11 LDA ($11),Y read from WAIT address
.,D725 45 47 EOR $47 second parameter
.,D727 25 46 AND $46 first parameter
.,D729 F0 F8 BEQ $D723 keep waiting
.,D72B 60 RTS back to interpreter loop
在 pre-V2 BASIC 上,$D71A 处的跳转只是跳过了下一行:如果没有第三个参数,则不要获取它。在 V2 上,该行被巧妙地更改为使双参数情况跳转到一个小的补丁例程:
.,D745 A5 11 LDA $11 low byte of address
.,D747 C9 66 CMP #$66 = low of $1966 (=6502)
.,D749 D0 D4 BNE $D71F no, back to original code
.,D74B A5 12 LDA $12 high byte of address
.,D74D E9 19 SBC #$19 = high of $1966 (=6502)
.,D74F D0 CE BNE $D71F no, back to original code
.,D751 85 11 STA $11 low byte of screen buffer = 0
.,D753 A8 TAY index = 0
.,D754 A9 80 LDA #$80 high byte of screen buffer
.,D756 85 12 STA $12 screen buffer := $8000
.,D758 A2 0A LDX #$0A 10 characters
.,D75A BD 81 E0 LDA $E081,X read character
.,D75D 29 3F AND #$3F throw away upper bits
.,D75F 91 11 STA ($11),Y store into screen RAM
.,D761 C8 INY
.,D762 D0 02 BNE $D766 no carry
.,D764 E6 12 INC $12 increment screen buffer high address
.,D766 CA DEX
.,D767 D0 F1 BNE $D75A next character
.,D769 C6 46 DEC $46
.,D76B D0 EB BNE $D758 repeat n times
.,D76D 60 RTS back to interpreter loop
文本 “MICROSOFT!” 存储在 $E082 处的 10 个连续字节中,巧妙地隐藏在用于 SIN() 函数的系数表之后:
.;E063 05 6 coefficients for SIN()
.;E064 84 E6 1A 2D 1B -((2*PI)**11)/11! = -14.3813907
.;E069 86 28 07 FB F8 ((2*PI)**9)/9! = 42.0077971
.;E06E 87 99 68 89 01 -((2*PI)**7)/7! = -76.7041703
.;E073 87 23 35 DF E1 ((2*PI)**5)/5! = 81.6052237
.;E078 86 A5 5D E7 28 -((2*PI)**3)/3! = -41.3147021
.;E07D 83 49 0F DA A2 2*PI = 6.28318531
.;E082 A1 54 46 8F 13 "SOFT!" | backwards and with
.;E087 8F 52 43 89 CD "MICRO" | random upper bits
如果我们反转字节,我们得到
CD 89 43 52 8F 13 8F 46 54 A1
彩蛋代码清除高 2 位,得到
0D 09 03 12 0F 13 0F 06 14 21
彩蛋代码不通过库例程打印字符,而是将值直接写入屏幕 RAM。虽然 BASIC 使用 ASCII 字符编码,但 Commodore 字符集有自己的编码,其中 “A” 从 $01 开始,但将数字和特殊字符保留在与 ASCII 中相同的位置。因此,10 个隐藏和混淆的字节解码为:
MICROSOFT!
Microsoft 的代码?
Commodore 工程师以将彩蛋放入 ROM 中而闻名,但他们没有理由编码字符串 “MICROSOFT!” 并将其隐藏得如此之好。“WAIT 6502” 彩蛋直到版本 2 才出现在 Commodore BASIC 中,这与几乎所有声称 Commodore 以统一费用许可了 Microsoft BASIC 并且从未返回 Microsoft 进行更新,而是继续在内部改进 BASIC 的说法形成对比。
自 V1 以来,Commodore 确实使用 Microsoft 的更改更新了其源代码。6502 大师 Jim Butterfield 表示: Commodore 向 Microsoft 支付了额外费用,以编写对其购买的原始 BASIC 的修订版。除其他事项外,更改了关键字中的空格,移动了零页面,并且(Commodore 不知道)插入了 WAIT 6502,x 笑话。
针对 Commodore?
虽然所有 Microsoft BASIC 仅依赖于 CPU,对它运行的硬件没有其他假设(无论是 Commodore、Apple、Atari、…),并通过调用 BASIC 外部的 ROM 函数来完成所有输入和输出,但彩蛋直接写入 $8000 固定地址的屏幕 RAM,并使用 PET 字符编码:彩蛋显然是专门为 PET 编写的。
我们只能推测 Microsoft 以及可能的比尔·盖茨本人添加彩蛋的原因。一个可能的原因是 Microsoft 想要确保 Commodore 不能因 “Commodore BASIC” 而获得荣誉——类似于 “Stolen From Apple” 案例。
或者仅仅是为了向世界展示谁真正编写了它。Jim Butterfield: 事后看来,Microsoft 希望看到他们的名字出现在屏幕上。但这不在合同中。
Commodore 的反应
彩蛋仅存在于 PET 上的 BASIC 版本 2 中。所有后来的 Commodore 计算机都没有包含它:分支已恢复,额外的代码以及隐藏在 SIN() 系数后的 10 个字节也被删除。
Jim Butterfield: 在实施后不久,我在 CES 展会的 Commodore 展位上向 [Commodore 工程部的] Len Tramiel 展示了这一点。他勃然大怒:“我们有一台内存空间不足的机器,而 #$#!* [盖茨] 把这种东西放进去了!!”
Commodore 员工 Andy Finkel 表示,出于空间原因,必须删除 “盖茨” (!) 彩蛋。它占用了 51 个额外的字节。
有趣的是,从六年后 C128 上的 BASIC V7 开始,Commodore 开始赞扬 Microsoft,如下所示:
COMMODORE BASIC V7.0 122365 BYTES FREE
(C)1985 COMMODORE ELECTRONICS, LTD.
(C)1977 MICROSOFT CORP.
ALL RIGHTS RESERVED
根据 Jim Butterfield 的说法,这可能是由于有关 Amiga 的 Microsoft BASIC 的谈判。
PET 之前的彩蛋
但 Microsoft 并没有专门为 Commodore 编码其公司名称:用于 KIM-1 的 9 位数字 BASIC 6502 版本 1.1 包含 10 个隐藏字节:
.;3FAA 05 6 coefficients for SIN()
.;3FAB 84 E6 1A 2D 1B -((2*PI)^11)/11! = -14.3813907
.;3FB0 86 28 07 FB F8 ((2*PI)^9)/9! = 42.0077971
.;3FB5 87 99 68 89 01 -((2*PI)^7)/7! = -76.7041703
.;3FBA 87 23 35 DF E1 ((2*PI)^5)/5! = 81.6052237
.;3FBF 86 A5 5D E7 28 -((2*PI)^3)/3! = -41.3147021
.;3FC4 83 49 0F DA A2 2*PI = 6.28318531
.;3FC9 A6 D3 C1 C8 D4 "!TFOS"
.;3FCE C8 D5 C4 CE CA "ORCIM"
此处的额外字节为:
A6 D3 C1 C8 D4 C8 D5 C4 CE CA
如果我们用 0x87 对每个字节进行异或,我们得到:
21 54 46 4f 53 4f 52 43 49 4d
同样,它是倒过来的 “MICROSOFT!”,但这次是在 ASCII 编码中。(请注意,在 Commodore BASIC 中找不到任何 XOR 或加/减法用于 10 个字节,这些字节会将它们转换为 ASCII 而不是 PETSCII。另外,感谢 Tom 在这方面的帮助。)
适用于基于 6502 的 Apple II 的 Microsoft BASIC 版本,称为 “AppleSoft”,在 所有 磁带 和 ROM 版本中都包含 SIN() 系数后的相同 10 个字节。例如,在 AppleSoft II 上,它们位于地址 $F075。
KIM-1 BASIC 发布于 1977 年,AppleSoft II 发布于 1978 年春季,PET 的 V2 ROM 发布于 1979 年春季。因此,Microsoft 最初并没有 “针对” Commodore,而是可能将数据放入了所有客户中——可能就在他们将没有彩蛋的 V1 运送到 Commodore 之后。当 Commodore 回来找他们时,他们更改了代码库以不同地编码字符串,并添加了彩蛋代码以显示该字符串。
PET 之后的彩蛋
在第二次源代码交付给 Commodore 后,他们再次删除了 “WAIT6502” 代码,但在其主代码库中保留了 10 个编码字节:每个非 Commodore 的 1978 年后的带有 40 位浮点库的 6502 Microsoft BASIC 都包含 SIN() 系数后的 10 个编码字节——仍然采用 PET 编码:
- Tangerine Microtan 65
- Tangerine Oric-1 和 Oric-Atmos
- Pravetz 8D
这是来自 microtan/tanex_h2.rom 的一个片段:
0000fd8: 0f da a2 **a1 54 46 8f 13** ....TF..
0000fe0: **8f 52 43 89 cd** a5 d5 48 .RC....H
Ohio Scientific Superboard II(及其克隆 Compukit UK101)以及 Atari Microsoft BASIC 磁带的 ROM 基于 32 位浮点版本,并且不包含彩蛋数据。
6800 和 6809 上的 “MICROSOFT!”
它并没有就此止步:即使是 TRS-80 Color Computer 和 TRS-80 MC-10 上的 BASIC 版本,它们分别是 6809 和 6800 CPU 架构的版本(BASIC-69 和 BASIC-68),在 SIN() 系数之后也有编码的 “MICROSOFT!” 字符串。这是 Spectral Associates 的反汇编代码片段,来自他的著作 “Color Basic Unravelled II“
* MODIFIED TAYLOR SERIES SIN COEFFICIENTS
BFC7 05 LBFC7 FCB 6-1 SIX COEFFICIENTS
BFC8 84 E6 1A 2D 1B LBFC8 FCB $84,$E6,$1A,$2D,$1B * -((2*PI)**11)/11!
BFCD 86 28 07 FB F8 LBFC8 FCB $86,$28,$07,$FB,$F8 * ((2*PI)**9)/9!
BFD2 87 99 68 89 01 LBFD2 FCB $87,$99,$68,$89,$01 * -((2*PI)**7)/7!
BFD7 87 23 35 DF E1 LBFD7 FCB $87,$23,$35,$DF,$E1 * ((2*PI)**5)/5!
BFDC 86 A5 5D E7 28 LBFDC FCB $86,$A5,$5D,$E7,$28 * -((2*PI)**3)/3!
BFE1 83 49 0F DA A2 LBFE1 FCB $83,$49,$0F,$DA,$A2 * 2*PI
BFE6 A1 54 46 8F 13 8F LBFE6 FCB **$A1,$54,$46,$8F,$13** UNUSED GARBAGE BYTES
BFEC 52 43 89 CD FCB **$8F,$52,$43,$89,$CD** UNUSED GARBAGE BYTES
你可以看出 Microsoft 没有为剩余的 8 位架构重新实现 BASIC,而是实际上转换了 6502 代码,逐字复制了所有常量,即使是他们不理解的常量,因为这些仍然是 PET 编码中的混淆字节。
Color Computer 上的第二个彩蛋
TSR-80 Color Computer (1980) 在 BASIC 中也有一个彩蛋:如果你输入 “CLS9”(或任何更高的数字),它将清除屏幕并打印 “MICROSOFT”。
让我们看看它是如何完成的:
* CLS
A910 BD 01 A0 CLS JSR RVEC22 HOOK INTO RAM
A913 27 13 BEQ LA928 BRANCH IF NO ARGUMENT
A915 BD B7 0B JSR LB70B CALCULATE ARGUMENT, RETURN VALUE IN ACCB
A918 C1 08 CMPB #8 VALID ARGUMENT?
A91A 22 1B BHI LA937 IF ARGUMENT >8, GO PRINT âMICROSOFTâ
[...]
A937 8D EF LA937 BSR LA928 CLEAR SCREEN
A939 8E A1 65 LDX #LA166-1 *
A93C 7E B9 9C JMP LB99C * PRINT âMICROSOFTâ
要打印的字符串存储在这里:
A166 4D 49 43 52 4F 53 LA166 FCC 'MICROSOFT'
A16C 4F 46 54
A16F 0D 00 LA16F FCB CR,$00
没错,Microsoft 添加了一个不同的彩蛋,并再次包含字符串 “MICROSOFT”,这次是以明文形式。他们似乎忘记了最初从 6502 版本复制到 6800 的为 PET 准备的混淆的 10 个字节,并且仍然存在于 Color Computer ROM 中。
相同的彩蛋存在于基于 6800 的 TRS-80 MC-10 (也是 1980 年) 上,它在 ROM 中也有 10 个 PET 字节:
FBBF 27 13 BEQ $FBD4 ; branch if no argument
FBC1 BD EF 0D JSR $EF0D ; get argument
FBC4 C1 08 CMPB #$08 ; easter egg?
FBC6 22 1D BHI $FBE5 ; yes
[...]
FBE5 8D ED BSR $FBD4 ; clear screen
FBE7 CE F8 33 LDX #$F834-1
FBEA 7E E7 A8 JMP $E7A8 ; print "MICROSOFT"
[...]
F834 4D 49 43 52 4F FCC "MICROSOFT"
F834 53 4F 46 54 0D FCB $0D
F834 00 FCB $00
[...]
F724 A1 54 46 8F 13 FCB $A1,$54,$46,$8F,$13 ; "!TFOS"
F729 8F 52 43 89 CD FCB $8F,$52,$43,$89,$CD ; "ORCIM"
Microsoft BASIC 6502 时间线
- 1.0 版(采用 6 位数字版本)用于 Ohio Scientific,并且在垃圾回收代码中包含一个 主要错误。
- 1.0 版(采用 9 位数字版本)也用在第一台 Commodore PET 中,作为 Commodore BASIC V1。它是已知的最古老的支持 9 位数字浮点的 Microsoft BASIC。
- 1.1 版,其中包含错误修复,用于 KIM-1。它是包含 “MICROSOFT!” 字符串(采用 ASCII)的最古老版本。
- AppleSoft BASIC I 是从 Microsoft BASIC 1.1 分支出来的。它包含 ASCII 字符串。
- Microsoft BASIC 2.0 版将 ASCII 字符串更改为 PET 屏幕代码,添加了彩蛋代码,并提供给 Commodore。
- 在源代码交付给 Commodore 后,代码再次被删除。Tangerine Microtan 基于此。
- Apple、Commodore 和 Tangerine 在没有 Microsoft 参与的情况下继续开发各自的分支。
- 在 VIC-20 和 C64 上使用的 BASIC V2 实际上是 PET BASIC 4.0 的精简版本,而不是 PET BASIC V2 的移植版本。
那么比尔·盖茨自己编写的吗?
Altair BASIC 由比尔·盖茨、Paul Allen(Microsoft 的创始人)和 Monte Davidoff(承包商)编写,如 原始源代码打印输出 中的注释所示:
00560 PAUL ALLEN WROTE THE NON-RUNTIME STUFF.
00580 BILL GATES WROTE THE RUNTIME STUFF.
00600 MONTE DAVIDOFF WROTE THE MATH PACKAGE.
比尔·盖茨编写了 “运行时内容”(可能意味着指令的实现),而不是 “非运行时内容”(可能意味着标记化、内存管理)和 “数学包”。因此,WAIT 命令的实现将是他的工作——至少在 8080 上。
那么谁编写了 6502 版本?KIM-1 BASIC 手册 赞扬了 8080 版本的原始作者 Gates、Allen 和 Davidoff,但它可能只是 手册 为 [