如何在35年前发布的微处理器中发现错误

K1801VM1A


很难相信,但是有时处理器中的错误实际上比处理器本身的寿命更长。 最近,我偶然通过16位微处理器1801BM1A的实例使这一点变得令人信服,在该实例的基础上,苏联曾一次创建了BK-0010 / 11M家用计算机系列。 关于哈布雷的这个家庭反复写道。


BeKashek活跃的时期是80年代末-上世纪90年代初。 近年来,通过众多爱好者以及小组成员和合作者的共同努力,开发了一系列主要的BC应用程序:游戏,实用程序,各种“ DOS”(磁盘操作系统)。 在软件开发的同时,还创建了外围设备,并在其下编写了系统软件。 通常,这些16位类似PDP的计算机的生态系统是根据相似的原理开发的,例如,基于Intel 8080S-100总线的早期8位开放式体系结构。 后来,随着我们离开卑诗省的功利主义角色,编程的重心已经转移到了演示场景上。


可以通过访问带有程序 集合的 公共 站点来估算BC软件的数量。 当然,例如,与ZX-Spectrum相比,该音量要小得多。 但是,即使如此大的数量,似乎也应该足以解决所有可能的机器代码问题。 经过三十多年的实践,是否有可能在处理器的性能方面发现一些异常现象? 事实证明-是的! 这将在下面讨论。


按时间顺序讲这个故事也许很有意义。 首先,我必须立即指出,我根本不是一个“有经验的程序员”,既不是职业,也不是我上面写过的不列颠哥伦比亚省的一群爱好者。 我以一种about回的方式来到不列颠哥伦比亚省,部分原因是怀念童年和青年的爱好(模拟和数字电子学,《 青年技术员 》杂志, UT-88和其他工艺和缺陷),部分是由于我对体系结构和命令系统PDP-11感兴趣。 我没有“硬件上的BK”,通常会运行BK程序并在Android平板电脑上的bkemu仿真器中对其进行调试。


前一段时间,我对由Li-Chen Wang-a撰写的万花筒程序感兴趣。 该程序是在1976年用机器代码编写的,用于Intel 8080微处理器,是带有Cromemco Dazzler图形适配器的Altair 8800计算机的一部分 。 我想详细解析Li-Chen Wang-a算法,同时将其移植到BC。 我必须说,早先在演示者中就表达了将万花筒移植到BC的愿望,甚至尝试解析该算法,但均未成功。


在我的下一篇文章中,我可能会详细分析该算法(为不耐烦,我将在C中的libSDL下发布指向跨平台万花筒的源的链接)。 对于将来,这足以表明问题已解决,并且万花筒已成功移植到BC。 此外,声音的生成已添加到CD上的算法中,并且由于图像和声音都是由相同的代码生成的,因此我们可以说图像本身就是声音(整个演示适合少于256字节的机器代码,并且,我希望它将在10月下旬在喀山举行的CAFe Demoparty 2019上向公众展示


在模拟器中完成程序的编写和调试后,我求助于Damir(“ Adamych”)Nasyrov (他是CAFe Demoparty的组织者之一,也是演示者中非常知名的人),他要求检查真实BC上的程序执行情况。 我对声音再现特别感兴趣,因为仿真器中的时序可能与真实硬件上的时序不同。 想象一下,当达米尔(Damir)告诉我真实的BC上有图像但没有声音时,我感到失望!


接下来的几个晚上,他们试图从BK-0011M的系统文档电路图中减去,哪里可能有声音错误。 BC中的声音的组织非常简单:具有八进制地址177716的I / O寄存器中的第六位(磁带记录器控制寄存器)通过缓冲区输出到压电扬声器(蜂鸣器)。 除第6类外,同一寄存器的第2位和第5位还连接到具有4个电阻的最简单的数模转换器。 从此转换器的输出,声音可以到达磁带录音机。 一切都非常清楚和合乎逻辑,但无论我尝试将位掩码应用于输出到该寄存器的位掩码的组合如何,实际的BK上都没有顽固的声音。 同时,我知道的所有BK模拟器都已安装并经过测试-并且声音在每个人中都起作用!


在某个时候,我什至几乎设法说服了达米尔(Damir)他的BK有故障,但是在另一台现场BK-0011M和BK-0010上都重复了这一行为。 我没有想法了,BC主题上的电报频道的居民也什么也听不见。但是,此事件像往常一样有所帮助。 在一项实验过程中,Damir在模拟器上启动了一个演示,以确保模拟器中有声音。 在这里,他设法注意到,不仅模拟器中有声音,而且BC上没有声音,而且模拟器和实况BC中的图片也不同! 在这里,我必须提醒您,在我的程序中,图像和声音都是由相同的代码生成的。 因此,一直以来,我一直在错误的地方寻找原因:原因在于生成屏幕内容数据的代码中。


Damir给我发送了一个屏幕截图,很明显,该算法产生的字节的最高4位内容为零,并且巧合的是,这些位被输出到声音中(即始终为零)。 但是,算法以这种方式运行的原因仍然含糊不清。 这是代码中的位置(PDP-11中的汇编器macro11 ,重命名了寄存器r0-r5!):


; renamed registers a = %0 b = %1 c = %2 d = %3 e = %4 h = %5 ... ... asr b ; sets CF bic #177760, b bis b, c bis (h)+, c ; screen address in c movb (c), a ; get a byte from screen RAM bcc 1$ ; check CF bic #177760, a ; keep bits 0-3, clear rest bisb d, a ; fill bits 4-7 br 2$ 1$: bic #177417, a ; keep bits 4-7, clear rest bisb e, a ; fill bits 0-3 2$: ... ... 

由于某种原因,在真实的BC上,总是执行有条件的跳转到$ 1大关。 就是说,尽管ASR移位指令可以将该标志设置为0或1,但bcc指令始终将进位标志视为复位状态。这是怎么回事,因为根据处理器文档,BIC,BIS或MOVB都不应该影响进位标志吗?


此外,在所有仿真器中(根据处理器的说明文件编写的!)是这样的:这些指令不会触及标志C。显然,根据说明文件,真正的处理器1801BM1A在这种情况下不起作用。 仍有待确认。


对于初学者来说,一个明显的快速解决方案:


  ... asr b ; sets CF mfps -(sp) ; store PSW on stack bic #177760, b bis b, c bis (h)+, c ; screen address in c movb (c), a ; get a byte from screen RAM mtps (sp)+ ; restore PSW from stack bcc 1$ ; check CF ... 

在移位指令之后立即将标志保存在堆栈上,并在有条件跳转之前将其还原立即解决了该问题,这表明我处在正确的轨道上。 缩小“犯罪嫌疑人圈子”仍有待解决。 为了检验假设,首先编写了这样的综合测试(此处未重命名寄存器;省略了初始初始化,以免使代码混乱; emt 64是用于打印行的程序中断):


  ... mov #1, r1 jsr pc, test clr r1 jsr pc, test halt test: mov #40000, r2 ; r2 points to screen RAM mov #dummy, r5 ; r5 points to dummy = 200 ; *** begin *** asr r1 ; affects CF bic #177760, r1 bis r1, r2 bis (r5)+, r2 movb (r2), r0 ; *** end *** jsr pc, prt rts pc prt: mov #msg1, r0 bcs l1 mov #msg2, r0 l1: emt 64 rts pc msg1: .asciz /Flag CF set/ msg2: .asciz /Flag CF clear/ dummy: .word 200 ... 

测试...没有用! 程序打印在屏幕上


标记CF集
标记CF清除


原来是什么? 事实证明,最初的假设认为开始结束之间的代码片段只会破坏C标志,这是错误的,需要澄清。 此测试与源代码有什么区别? 并且在“可疑”命令块和条件跳转之间出现了其他指令。 不会影响标志C,但仍会更改处理器的内部状态。 因此,以下测试是这样的:


  ... mov #1, r1 jsr pc, test clr r1 jsr pc, test halt test: mov #40000, r2 mov #dummy, r5 ; *** begin *** asr r1 ; affects CF bic #177760, r1 bis r1, r2 bis (r5)+, r2 movb (r2), r0 bcc l1 ; *** end *** mov #msg1, r0 emt 64 rts pc l1: mov #msg2, r0 emt 64 rts pc msg1: .asciz /Flag CF set/ msg2: .asciz /Flag CF clear/ dummy: .word 200 ... 

现在,此测试已经打印在真实的BK-0011M上:


标记CF清除
标记CF清除


与以前一样,在模拟器上


标记CF集
标记CF清除


进一步是技术问题。 通过逐步简化,获得了一个最小的测试,可以在该测试中重现错误(我引用了整个源代码):


  .title test .psect code .=.+1000 mov #15, r0 emt 63 sec jsr pc, test clc jsr pc, test halt test: movb r0, r0 bcc l1 mov #msg1, r0 emt 64 rts pc l1: mov #msg2, r0 emt 64 rts pc msg1: .asciz /Flag CF set/ msg2: .asciz /Flag CF clear/ .end 

在真实的BK-0011M上,此测试显示


标记CF清除
标记CF清除


也就是说,应归咎于条件分支指令之前的MOVB指令,并且第一个操作数的外观并不重要。 例如,如果在MOVB和BCC之间插入了NOP,则该行为将返回记录的行为,并且程序将打印


标记CF集
标记CF清除


这样就可以提出一个完善的假设(我从电报频道引述自己):


关于该错误:行为似乎已经消除。 就像我想象的那样,由于某些架构功能,MOVB src,dst(顺便说一句,操作数似乎并不重要)会暂时破坏处理器内部的C标志,但不会致命,因为百分比似乎保存了该标志的副本。 结果,如果在MOVB和条件分支之间还有其他命令(不影响C),例如NOP,则行为如文档中所述。

接下来发生了什么? 此外,来自该渠道的同事还帮助将Vyacheslav(@ K1801BM1,以前在晶体管级别反转过该处理器的传奇人物)带入了讨论。 维亚切斯拉夫(Yot)在具有真实1801BM1A(保留拼写和标点符号)的架子上测试行为时的反应:


斯坦尼斯拉夫·马斯洛夫斯基(Stanislav Maslovski):
至少需要两个命令才能进行复制
C中的movb和条件跳转
好吧,在此之前,将标志C设置为已知状态

Yuot:
获得始终复位的标志

斯坦尼斯拉夫·马斯洛夫斯基(Stanislav Maslovski):
是的
现在插入nop

Yuot:
现在永远

Yuot:
交替0 1
真可惜

在维亚切斯拉夫(Vyacheslav)的帮助下,人们发现了细节,即该错误的原因是在处理器中,除了PSW外,还有另一个4位寄存器,该寄存器通常存储PSW中标志的副本。 该寄存器与自动固件连接,条件转换从中获取标志值。 当使用接收器寄存器执行指令MVB,SWAB,MFPS时,由于处理符号扩展的特殊性以及由于微码中的错误,该寄存器中标志C的副本将被丢弃,并且使用该标志的条件转换将无法正常工作。 但是,按照以下说明,可以从PSW恢复临时寄存器的值。 因此,NOP插入可恢复正确的行为。


最后,我还要感谢“ BK0010 / 11M World”电报频道的订阅者参与了对该bug的讨论以及对本文的评论。 文章的标题照片由Manwe_SandS提供 。 更有趣的是,Manwe几乎在发现同一错误的同时,几乎与Damir和我正在努力解决声音问题!


现在由小规模(开个玩笑)决定-使所有仿真器与处理器的实际行为保持一致。 毕竟,处理器本身无法修复。


我将在此结束。 我希望这很有趣。

Source: https://habr.com/ru/post/zh-CN471020/


All Articles