新聞中心
背景知識(shí):《機(jī)器人大戰(zhàn):2084》(英文:Robotron: 2084,也常簡(jiǎn)稱為Robotron) 是由Vid Kidz開發(fā)、Williams Electronics于1982年發(fā)行的一款街機(jī)游戲。它是一款2D射擊游戲。游戲設(shè)定在2084年的一個(gè)虛構(gòu)世界,在那兒機(jī)器人起來反抗人類的統(tǒng)治。 玩家的任務(wù)是擊退一波又一波的機(jī)器人,拯救幸存的人類,并贏取盡可能多的分?jǐn)?shù)。

創(chuàng)新互聯(lián)是一家專注于網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站建設(shè)與策劃設(shè)計(jì),大東網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)十年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:大東等地區(qū)。大東做網(wǎng)站價(jià)格咨詢:13518219792
介紹:
- 『拐角射擊失靈』,所有Robotron的ROM原始程序里頭有個(gè)bug,當(dāng)玩家對(duì)在戰(zhàn)場(chǎng)邊緣行進(jìn)的暴徒射擊的時(shí)候,程序會(huì)讀取代碼里一個(gè)錯(cuò)誤的位置。導(dǎo)致代碼不知道接下來做什么,程序監(jiān)視器就會(huì)重置游戲到地毯模式。
- Eugene Jarvis 提到:1987年前后,一個(gè)叫Christian Gingras的加拿大小孩完整地分析了ROM里頭的機(jī)器代碼, 綜合得到了源程序列表。他發(fā)給我們他通過讀代碼發(fā)現(xiàn)的7個(gè)bug,然后我們修復(fù)了這些bug。這其中就有一個(gè)很著名的拐角射擊崩潰bug。
- Sean Riddl提到:Williams Arcade Classics(一款游戲)出 現(xiàn)于1995年,我假設(shè)Eugene(Robotron游戲的設(shè)計(jì)者)已經(jīng)修復(fù)了ROM里頭的bug,我試用了一下程序然后回復(fù)了作者,他做了一些ROM 的改動(dòng),這些改動(dòng)讓仿真容易一點(diǎn)。(他把Stargate重做成了Defender II, 這肯定是非常多的工作),Sean Riddle寫道:我用 google搜索了一下,好像人們認(rèn)為拐角射擊的bug修復(fù)了。之后補(bǔ)丁出來了,在補(bǔ)丁里頭可以看到“1987修改”。我想我是從 Williams Arcade Classics Widows95版里頭找到的補(bǔ)丁。
備注:雖然 Robotron 讓 Christian 獲得了聲望,但實(shí)際上他酷愛另一款游戲 Joust。
Christian 的自述(2012年11月)
1982年的時(shí)候我在電子方面是很超前的,我可以設(shè)計(jì)模擬和數(shù)字系統(tǒng)。這些年出現(xiàn)的電子游戲表明,Joust/Robotron主板上100個(gè)芯片就可以讓系統(tǒng)執(zhí)行比標(biāo)準(zhǔn)晶體管邏輯門上更復(fù)雜的功能,比如說Williams的游戲。
詳細(xì)地研究原理圖,有一個(gè)很明顯的選擇:在Joust里頭,摩托羅拉6809微處理器相當(dāng)于大腦,而用來創(chuàng)建電腦控制有智能行為的鳥的數(shù)據(jù),保存在12個(gè)電可編程序只讀存儲(chǔ)器(EPROM)里頭。
我意識(shí)到,如果我要自己設(shè)計(jì)復(fù)雜的電子系統(tǒng),我必須了解摩托羅拉6809是如何工作的。如果我是個(gè)幸運(yùn)的孩子可以訪問大型主機(jī),我會(huì)拿6809作為參考來學(xué)習(xí)微處理器。
但是我能擁有的最強(qiáng)大的計(jì)算機(jī)是街機(jī)游戲機(jī)。這些游戲比當(dāng)時(shí)的家庭計(jì)算機(jī)比如TRS-80或者TI99a快幾個(gè)數(shù)量級(jí)。
用不了多長(zhǎng)時(shí)間我就找到了最快的游戲, Robotron 2084有10波全速的120個(gè)對(duì)象,很顯然是最快的。在Joust里頭,只有10只鳥 3個(gè)翼龍和兩個(gè)玩家。相對(duì)于Joust而言,Robotron 2084性能更具有挑戰(zhàn)性。如果我們用Z80處理器,比如Miss Pac-man,來處 理4個(gè)鬼魂,一個(gè)水果和一個(gè)玩家,6809微處理器明顯要快很多
我花了幾年的時(shí)間才找到一個(gè)專家,他把Robotron主板上的EPROM去掉,并且讓我讀EPROM里頭的程序然后還可以寫回去。這是1984年或者1985年的事。
那個(gè)時(shí)候,我在Radio Shack買了一臺(tái)彩色電腦COCO2, 里頭有一個(gè)微軟寫的6809的調(diào)試器edtasm。我反向工程破解了 edtasm,于是我明白了6809的匯編和反匯編程序是怎么創(chuàng)建的。但是我覺得Robotron:2084是如此復(fù)雜,所以我沒有敢研究它。1985年 還是1986年,我反向工程研究了COCO2里8K大的ROM,這個(gè)ROM創(chuàng)建了COCO2的基本語言。然后我也研究了很多其他的應(yīng)用比如磁帶軟盤拷貝應(yīng) 用,為了節(jié)約我的工作,我也通過研究一些游戲來了解如何訪問COCO2的圖形模式。
最后在1986年8月,我準(zhǔn)備好了要開始研究Robotron:2084。我做了一個(gè)定制的edtasm,它可以從EPROM里頭每次讀4K的二進(jìn) 制數(shù)據(jù),并且反編譯代碼同時(shí)把實(shí)際硬件地址映射成虛擬的地址。不是在屏幕上顯示, 反編譯器把結(jié)果傳到打印端。總共用了3天才打印完512頁(yè)程序。我時(shí)不 時(shí)往墨盒里頭加點(diǎn)紅色或者黑色或者藍(lán)色的墨水。為了節(jié)約紙的空間還有錢,我打印了雙面的。這些包含了反編譯的6個(gè)EPROM的所有程序。
我前些年研究過一些6809的應(yīng)用,我很高興我能用相似的方式讀懂這些代碼。不過有些明顯的區(qū)別:
Robotron: 2084用了一些變址指令比如:“LDA A,Y++, STB B,X+$0A”(從地址為寄存器X值的內(nèi)存里讀一個(gè)字節(jié),增加那個(gè)寄存器,把那個(gè)字節(jié)寫道寄存器Y指向的內(nèi)存地址的第10個(gè)字節(jié))
它證明Robotron:2084雖然是匯編寫的,卻是很干凈的面向?qū)ο蟮拇a。
Robotron依賴一些共享方法來做一些操作,比如分配內(nèi)存,休眠一段時(shí)間,在這中間處理器可以做一些其他的操作,休眠結(jié)束之后會(huì)重新執(zhí)行之前的代碼。
這說明Robotron是一個(gè)完全的多線程應(yīng)用,每個(gè)移動(dòng)對(duì)象都是由不同的線程來控制的。
如果我沒記錯(cuò),IRQ中斷每秒執(zhí)行300次,是一個(gè)高優(yōu)先級(jí)的線程負(fù)責(zé)執(zhí)行高優(yōu)先級(jí)的任務(wù),比如說當(dāng)陰極射線管(CRT)掃描的距離某個(gè)地方足夠遠(yuǎn) 的時(shí)候,繪制屏幕的一部分來避免閃爍。一個(gè)狀態(tài)機(jī)讀取CRT垂直掃描的位置,然后選擇當(dāng)前對(duì)象列表里頭的可以安全刷新的對(duì)象。比如說,如果我們用手柄控制 一個(gè)玩家到接近屏幕的頂部,
重繪操作只會(huì)當(dāng)CRT掃描在屏幕中間和底部的之間執(zhí)行。
我用了8個(gè)月來學(xué)習(xí)這512頁(yè)代碼,在我當(dāng)保安的地方,每天晚上在物業(yè)檢查的間歇里,我會(huì)打開那卷紙,用彩色的筆畫箭頭來標(biāo)記那些執(zhí)行了特殊功能或者讀寫了特殊端口的地方。
幾個(gè)月之后,我得到了 “為什么Robotron:2084會(huì)這么快”的答案。位塊傳送器(blitter,一個(gè)垂直或者水平的直接內(nèi)存控制芯片) 是高性能的主要因素。但是Defender(一款游戲)屏幕繪制的速度和Robotron一樣,但它沒有blitter(blitter是 Robotron的設(shè)計(jì),Stargate(一款游戲)額外宣揚(yáng)了blitter芯片)
我決定接著研究Robotron,同時(shí)也看看Joust 和Stargate,來比較它們的相同和不同特性。有些代碼處理一些很難的算法,給了我很深的印象,比如說:它如何用6809的MUL指令來做除法,用“固定點(diǎn)數(shù)(相對(duì)于浮點(diǎn)數(shù))”來做二進(jìn)制計(jì)算。
當(dāng)研究代碼如何處理游戲事務(wù)的時(shí)候,我就能猜到這些代碼過去引起過一些問題。 有些測(cè)試可以核實(shí)可能的問題,比如用4堵墻來比較子彈的位置,從而確 認(rèn)子彈被限制在可視的屏幕范圍之內(nèi)??偣?8K的內(nèi)存有40K用來顯示每個(gè)象素,剩下的8K用來作為代碼的棧指針,“對(duì)象”(和C++的對(duì)象概念相似,一 小段內(nèi)存用來記錄enforcer,坦克,子彈的位置還有其他對(duì)象的參數(shù)),局部變量和全局變量。如果一個(gè)對(duì)象被錯(cuò)誤地被繪制里屏幕的右邊太遠(yuǎn),這樣就有 可能污染這8K的程序內(nèi)存。
#p#
在后來的4個(gè)月里,我研究到了管理enforcers的代碼。我很好奇,沒有正弦余弦對(duì)數(shù)值數(shù)的代碼是怎么樣讓子彈是怎么做螺旋運(yùn)動(dòng)的。我也想明 白,當(dāng)一個(gè)enforcer在屏幕左邊慢慢接近玩家的時(shí)候,被驚嚇的小狗飛到屏幕的右邊,然后慢下來,劃了一條優(yōu)美的曲線回到玩家身邊。后來這個(gè)被證明是 個(gè)錯(cuò)誤,代碼里頭留下了一個(gè)8個(gè)字節(jié)的二進(jìn)制溢出。屏幕320像素寬,但是8位寄存器只能保存從左邊開始的256個(gè)像素,所以Enforcer可能會(huì)認(rèn)為 玩家在屏幕的右邊其實(shí)玩家就在旁邊很近的位置上,于是enforcer會(huì)計(jì)算新的速度去追蹤它想象中的玩家。然后,再這個(gè)瘋狂賽跑的中 間,enforcer會(huì)感知到玩家的正確位置在左邊,所以他會(huì)減慢速度,修改自己的方向,劃出優(yōu)雅的曲線。
通過對(duì)這個(gè)bug的研究,我也弄清楚了這個(gè)多線程多任務(wù)高性能軟件的另一個(gè)特性:每個(gè)enforcer都有自己私有的數(shù)據(jù)塊,這個(gè)私有的數(shù)據(jù)塊讓每 個(gè)enforcer保持獨(dú)立。Enforcer的數(shù)據(jù)結(jié)構(gòu)里有一個(gè)8位的變量,來記錄enforcer應(yīng)該保持當(dāng)前的狀態(tài)多久(多少個(gè)刷新循環(huán)),然后在 改變主意前做點(diǎn)其它的事情。當(dāng)enforcer錯(cuò)誤地朝右邊飛行的時(shí)候,它會(huì)追蹤這個(gè)實(shí)際上不在那里的玩家一段時(shí)間,當(dāng)上面提到的那個(gè)變量減少到 零,enforcer就會(huì)重新評(píng)估玩家在哪里,然后采取新的動(dòng)作。走過一條螺旋曲線到達(dá)玩家的位置。
六個(gè)月的研究讓我看到了代碼的每個(gè)細(xì)節(jié),我創(chuàng)建了一個(gè)函數(shù)調(diào)用的列表(誰調(diào)用了誰,調(diào)用了多少次的一個(gè)交叉參考),相似地,我也列出了所有的全局變 量,這些全局變量可以被DP寄存器用8位指針的方式訪問。我記錄下了所有可以讀寫這些變量的代碼位置。我可以看到有些變量指揮被射擊單位(坦 克,enforcer)使用。有些僅僅被分配內(nèi)存的神秘代碼和其他的操作(操作系統(tǒng),實(shí)時(shí)多任務(wù)使用者)使用
我也找到所有的加密文本和所有的代碼保護(hù)措施,這些秘密指令防止別人盜版Robotron這個(gè)游戲。Joust這個(gè)游戲里,如果有人把Williams修改成另外一個(gè)名字,這游戲就不能工作。但是如果我想修復(fù)那個(gè)隨機(jī)重置的bug,我就必須禁用這些保護(hù)措施。
我知道“fancy模式”是防止隨即重置bug的一個(gè)辦法,如果關(guān)閉,射擊的時(shí)候就不會(huì)繪制爆炸,越來越清楚地表明這爆炸的繪制引起了隨機(jī)重置的問題。
1986年秋天,我決定寫信給Eugene P. Jarvis 和Larry E. DeMar,告訴他們我已詳細(xì)研究了 Robotron:2084,而且我可能修改了那個(gè)bug。我從一個(gè)游戲機(jī)雜志上面知道了他們的名字。當(dāng)我解密一部分代碼里頭的加密文本的時(shí)候,我又看到 這兩個(gè)名字,所以我確信他們就是這個(gè)游戲的設(shè)計(jì)者。
當(dāng)我等待回信的時(shí)候,我得了肺炎。我意識(shí)到我有可能不能戰(zhàn)勝疾?。ㄎ乙郧皼]有吃過抗生素,不知道醫(yī)生能幫什么,我訪問了所有的以前有聯(lián)系方式的醫(yī) 生,他們不在乎而且什么忙都幫不了)。我感到了總結(jié)我一生中最重要工作的緊迫性,如果我不在了,這些工作都會(huì)浪費(fèi)掉,我身邊沒有人知道我做的工作。
我用了我所有的精力來修改代碼,而且寫了一封詳細(xì)的信給Eugene 和Larry。我記錄了所有我發(fā)現(xiàn)的錯(cuò)誤,解釋了錯(cuò)誤行為和原因,還有解決辦 法。我記錄了6個(gè)字節(jié)來執(zhí)行我的測(cè)試,只有Eugene 和 Larry會(huì)知道什么意思。我不想讓他們以為我是某些非法贊助人雇傭的黑客來攻破這些保護(hù)。 我謹(jǐn)慎地說明我絕對(duì)理解代碼的每一部分,當(dāng)我修復(fù)隨機(jī)重置bug的時(shí)候,沒有愚蠢地觸發(fā)保護(hù)措施。6頁(yè)信里有關(guān)于bug的濃縮后的精確技術(shù)描述。
在信的結(jié)尾我寫到:我所有這些研究都是因?yàn)槲覠釔塾布?6809基于圖形顯示),軟件(難以置信高效的多任務(wù)代碼)和它的設(shè)計(jì)者。這48K代碼就像 一部小說或者一個(gè)很精彩的故事,為向作者的天資致敬,所以我寫了信的最后一部分。事實(shí)上,這些工作是有自己生命的,無數(shù)人付出汗水和精力推動(dòng)手柄來挑戰(zhàn)機(jī) 器。也許比一部?jī)?yōu)秀小說的一些角色更加讓人動(dòng)情。
如果使用一個(gè)555電子振蕩器來產(chǎn)生IRQ中斷(把6809上面的300赫茲的IRQ卸載,然后接上555振蕩器),然后調(diào)整振蕩器頻率到足夠高, 這樣CPU會(huì)被占用而只剩下很少的時(shí)間也就是幾千赫茲周期來執(zhí)行代碼, 這樣我就可以讓player用很多分鐘初始化爆炸,而且游戲的速度非常低。我用了 幾小時(shí)來玩這個(gè)慢游戲,享受著更加容易毫無壓力的游戲。即使粗魯?shù)剡`反計(jì)時(shí),代碼居然沒有任何問題,這讓我挺驚訝。我知道我只要把Player挪動(dòng)到左上 角,游戲就會(huì)崩潰。我發(fā)現(xiàn)如果我關(guān)掉fancy模式,不用初始化爆炸,機(jī)器就不會(huì)有任何崩潰的情況。簡(jiǎn)而言之,這個(gè)bug跟繪制爆炸相關(guān)的線索又多了一 條。優(yōu)秀的選手,比如雙胞胎兄弟Ian 和Yvan Girouard發(fā)誓他們發(fā)現(xiàn)每次機(jī)器崩潰的時(shí)候都有一個(gè)enforcer在左上角。這些聰明的玩家 學(xué)會(huì)了避免斜對(duì)角線設(shè)計(jì),這樣他們用一個(gè)游戲幣就可以玩好幾個(gè)小時(shí)。
幾個(gè)星期后,一個(gè)星期六早上電話響了,有人說英語。我(加拿大人估計(jì)說法語的)告訴我的同伴Michel-Guy起來跟那個(gè)人說話,來電話的是Robotron設(shè)計(jì)者,Michel告訴我說他們想見我,他們會(huì)給我提供費(fèi)用包括火車旅館等等。
去芝加哥的那天,我打印了繪制對(duì)角線爆炸的程序,然后開始耐心地給每個(gè)分支劃箭頭來表明代碼流程。當(dāng)差不多到芝加哥的時(shí)候,我又一次發(fā)現(xiàn)6809執(zhí) 行了從指針列表里頭跳轉(zhuǎn)的指令。當(dāng)對(duì)象離墻太近的時(shí)候,這段代碼允許CPU跳過繪制太多的線,因?yàn)檫@個(gè)時(shí)候已經(jīng)無法完全顯示爆炸的形狀了。所以,如果 enforcer靠近墻的時(shí)候,只需要繪制比較少的線條。一種極端情況,如果enforcer靠墻太近,甚至容不下一條線會(huì)怎么樣?重新看了一下跳轉(zhuǎn)表, 如果沒有線條可以繪制,BEQ(結(jié)果為零跳轉(zhuǎn)指令)就會(huì)避開跳轉(zhuǎn)表,然后CPU會(huì)跳轉(zhuǎn)到6809的OP-Code決定的地址,導(dǎo)致處理器失敗,監(jiān)視器發(fā)現(xiàn) 了這個(gè)“死亡代碼”之后硬件重置了CPU。
我異常高興,我終于可以告訴Eugene 和Larry導(dǎo)致機(jī)器崩潰的真正bug。
當(dāng)我們討論那個(gè)bug的時(shí)候,他們兩個(gè)就像被嚇倒的小動(dòng)物,小心地走過來,然后拋開,然后又猶豫著回來。我問他們:是不是一個(gè)溢出?是一個(gè)用320水平像素來計(jì)算但實(shí)際上只有256像素。你們實(shí)際上早就發(fā)現(xiàn)了這個(gè)問題卻由他去,作為enforcers的一個(gè)復(fù)雜行為。
Larry笑了并且確認(rèn)了我的直覺。然后Larry停下來跟我說:“最近5年,我從來沒有跟任何人討論過Robotron的設(shè)計(jì)。我的朋友們不能理 解這樣的技術(shù)問題。但是今天,一個(gè)不會(huì)說我們語言的陌生人,我們一起討論就像我們?cè)?jīng)在一起工作一樣,就像你也是Robotron最初的設(shè)計(jì)者一樣?!?/p>
后來我問他們?cè)趺丛u(píng)價(jià)我對(duì)Robotron的理解,Larry說很好,不過當(dāng)然沒有超過他和Eugene。Eugene說我對(duì)代碼的每一部分都清晰地理解,從啟動(dòng)測(cè)試到操作系統(tǒng)的其他部分,還有游戲本身。他覺得從系統(tǒng)整體上我的理解超過了他和Larry。
那天晚些時(shí)候,Larry需要離開我們。他推薦我做Joust的設(shè)計(jì)者,Eugene有些懊惱,因?yàn)楸绕餜obotron我更喜歡Joust。我告 訴設(shè)計(jì)者我找不到任何問題。我不喜歡IRQ程序里頭的測(cè)試,這個(gè)測(cè)試可能會(huì)引起自動(dòng)重置,但是我明白了除非硬件問題這些代碼永遠(yuǎn)不會(huì)觸發(fā)的。 Mister Newcommer解釋給我說他發(fā)現(xiàn)了一個(gè)鳥和平臺(tái)的沖突。他用RAM里頭地一個(gè)數(shù)組發(fā)現(xiàn)了一個(gè)有些粗略但是有效的沖突,這個(gè)數(shù)組的修改用 來反映平臺(tái)的增加或者移動(dòng)。
Larry堅(jiān)持回來并且開車送我到機(jī)場(chǎng)。當(dāng)他過分地朝一個(gè)公交車司機(jī)按喇叭打算從他那里切過去的時(shí)候,我感覺這一切就是我一生的課堂。
原文鏈接:www.robotron2084guidebook.com/technical/christiangingras/
譯文鏈接:blog.jobbole.com/44847/
網(wǎng)站標(biāo)題:ChristianGingras:那個(gè)直接在機(jī)器碼中改Bug的家伙
標(biāo)題鏈接:http://fisionsoft.com.cn/article/cohhsds.html


咨詢
建站咨詢
