開發 FC 水平的模擬器,需要什麼知識儲備?

如果單人開發一個 8051 / FC / 8086 水平的模擬器

需要哪些如 計算機體系結構 / 編譯原理等課程知識呢?

需要哪些如 C / C++ / 彙編 / 反彙編 / 調試等技術呢?

需要動手實現哪些如 虛擬CPU / 調試器 / 繪圖模塊 等模塊呢?


關於【知識儲備】:

1.要懂彙編(具體包括:a.彙編指令代碼功能。b.寄存器,內存,堆棧概念。c.CPU複位及中斷過程)

2. 會一種程序設計語言。(寫完的模擬器用 printf 就可以看功能了啊,流水燈輕鬆實現啊)

3. 最好了解一些「鏈接器」的知識,和「編譯器」的C語言運行時上下文環境的問題。鏈接器要實現多個程序段的重定位。當然不會不影響,但是對C語言程序怎麼就能執行的會很費解,會有心結的。(不會直接用彙編寫程序嘛...NES模擬器都是彙編的,但是寫個MSP430模擬器什麼的就該有幫助了,這可以看IDE工具的相應的 linker user"s guid 和 compiler user"s guid 或相應的 help)

其他的比如《編譯原理》基本用不到吧,編譯器手冊可能會有些用處,但是和教科書的編譯原理是不一樣的,這裡主要是關注C語言和彙編如何對應。

主要就是組成原理啊,程序就是一條條指令,CPU就是」取指令-&>執行指令「的死循環嘛(第一條指令是複位過程決定的)。就要知道什麼是指令,怎麼執行就行啦。執行時涉及到什麼就看什麼是什麼。簡單的很。還有微機原理的內容理解有助於實現模擬器的一些外設(顯示器,手柄什麼的)模擬,對應情景就是向某個外設寄存器地址寫了什麼值相應模擬器應該如何模仿外設的功能。

關於【NES模擬器實現】:

剛好寫過一個簡單的fc模擬器。

首先還是要懂彙編啦,add,jmp,mov的功能什麼的,再有知道寄存器和內存地址,堆棧這些概念。

然後知道複位,和其他中斷的流程。

這時你就可以根據一個程序來開始寫模擬器了,無非就是看每條指令把哪個操作數,經過什麼變換,放到哪裡去(補充:影響哪些狀態標誌位),複位的位置在哪裡,從哪條指令開始運行,一步步調試了。最簡單的就是switch指令case指令1,指令2...6502是複雜指令集的,指令編碼規律性不大(但是還是有一些的),尋找到指令具體怎麼操作了就看指令的功能了。參見:6502 Instruction Set。

另外調試過程中,6502cpu有一個「全覆蓋」的程序幫助調試,這個程序幾乎包含了所有指令和定址方式的組合,如果結果錯誤就會陷入一個死循環指示錯誤。搜索:Klaus Dormann 的 6502_functional_tests(http://2m5.de/6502_Emu/index.htm)。

這個階段寫的 CPU 模擬器只是保證了 CPU 執行指令的正確性,一般就是通過觀察執行完的指令影響的寄存器或是狀態標誌位和內存內容是不是按照預期變化。這種調試方式。

CPU寫好了之後,顯示的問題就是有個緩衝區是放那些顯示的「模式塊」的,按照它的格式定義轉換成一個RGB數組就可以讓各種 GUI 顯示了。(好吧我就做到這裡 ... 按鍵和聲音什麼的沒有做)。參考【相關網站】有很豐富的資料。(這裡還可以利用後面提到的《VirtuaNES-debug》輔助調試)

這部分就是實現外設的部分了,根據外設的需求在寫入一些特殊地址時要做相應的功能響應。無非也就是將相關的內存內容經過一定變換,選擇合適的方式表現出來(如輸出字元,顯示圖像,輸出聲音之類的)。

【更容易實現的CPU】

還有我給個小提示,寫CPU模擬器可以從MSP430開始,因為MSP430隻有27條指令,精簡指令集的編碼方式(指令編碼規律性強),4種定址方式,相對簡單,資料也多。根據TI的官方文檔基本就可以完成設計,TI文檔寫得很漂亮!包括數據手冊,用戶指南什麼的。

============================

繼續補充一點東西:

當初的實現大體流程(幾天就可以搞定的):

1. 收集資料

2. 大體計劃 :

了解硬體結構(CPU,PPU,APU,控制器...) -&> 實現CPU -&> 實現PPU -&> 實現控制器 -&> 實現APU

3. 初步理解 (10.9,10.10)

電路結構,卡帶分類,CPU的最簡單模式

while(1)

{

取指 -&> 執行;

}

3. 實現 CPU(6502兼容 無十進位運算 dec)

了解指令分類

switch case 實現基本的 指令系統(10.11)

繼續調試完善CPU, 代碼基本完成(10.12)

指令全覆蓋測試程序測試CPU,修復bug(10.13)

繼續完善,寫PPU(10.14)能夠看到PPU中數據

寫 ppu 數據 -&> RGB 的轉換

QT編寫顯示界面,基本完成背景圖像顯示(10.15)

完成精靈的顯示,和滾動的實現(只有X軸)(10.16)

一定要多記筆記啊!我筆記發現沒有記網站!當初有好幾個那麼經典的NEC資料和6502 CPU模擬器的網站的!

【相關網站】:

6502.org: The 6502 Microprocessor Resource 這個講6502CPU模擬器設計資料的

NES info, programs, and demos 這個是 nesdev 有很多關於 NES 遊戲機的資料。

另外有本《小霸王遊戲機的奧秘.PDF》模糊的講了一下NES遊戲機的技術,但是不太深入。但是還是挺有用的。

再另外有個軟體叫《VirtuaNES-debug》這個可以單步執行nes指令,可以調試NES遊戲程序,並可以顯示很多內部的數據結構,在實現過程中很有幫助的!(另外本身這個軟體就是開源的)下面是軟體示意圖:

我以前寫的NES和430的模擬器,寫著玩的,代碼量也不是很大,但是有些夠理解用的基本功能了。都基本上是純C語言寫的,NES的用QT做了個圖形顯示,Cpu部分都是C語言實現。

還寫了一個實現了幾條指令的430CPU但是能跑流水燈了!而且是完全控制台下的流水燈!(c語言就足夠了)


JSNES: A JavaScript NES emulator

其實不難,按部就班地「模擬」就行,這年頭PC的運算能力,基本上隨便你怎麼寫,把遊戲跑起來問題都不大。


FC 硬體雖然繞但是不複雜,然而你沒有卡帶里各種晶元的數據(FC 的卡帶是主機的一部分,直接插匯流排的),只能模擬超瑪一代這種早期遊戲


接好啦,不用謝

http://blog.alexanderdickson.com/javascript-nes-emulator-part-1


正好寫過一個,也補充一下吧。

@加菲貓已經提到了很多,只補充一些我認為有用,答主們沒說到的吧。

關於彙編,需要了解,但是精通沒必要,畢竟這東西是嚴格硬體相關的,你精通X86彙編對寫6502處理器沒有太大的幫助,精通6502彙編對寫FC模擬器也沒有太大幫助,因為你要寫的是執行彙編的環境,而不是用彙編編寫遊戲本身。

關於調試技術,這是整個編寫過程中最重要的環節,好的調試技術和適當的調試工具可以大大加快項目的進度,這裡面一般有兩個選擇,當時我在寫模擬器的時候,我一個網友也在寫,關於調試工具,我們採用的不同的路線,我為了節約時間,只使用了簡單的printf向控制台直接輸出反彙編和調試信息,而我的網友則花費了不短的時間實現了一個比較完整的6502調試環境,最後的結果是我大約用不到2個星期的業餘時間就可以跑1942了,而他則花了幾個月才做到這一步,但是由於我沒有方便高效的調試環境,後期在模擬Mapper4等容量比較大的卡帶的時候相當的麻煩,而這時候他的優勢就體現出來了,至於具體選擇什麼手段,還要看你自己。

@加菲貓的回答提到了VNes的調試版本,這是個非常重要的工具,可以極大的節約你的時間,不過我也會使用No$NES做為輔助工具,No$Nes雖然在兼容性上比VNES差一些,但是在調試環境下的運行效率是VNES不能比的,你試過就知道了,這兩者可以說各有所長吧。

關於文檔,網上能查到的主要是NesDoc,Nes Spec和一個NesDev的wiki,這其中NesDoc比較簡單,而且有幾個翻譯版本,可以用來入門,No$網站上的Nes Spec是我讀過的Nes文檔中最好的一個,而NesDev由於是個多頁面的wiki因此在查找上沒有Nes Spec那麼方便,後者有txt版本,用Ctrl+F就可以方便的檢索。

編寫Nes模擬器需要時刻記住的是他是一個80年代的硬體平台,其使用的很多技術與當今遊戲界流行的方法有較大的差別,不能用現在遊戲程序的思路去考慮他的問題,比如近代遊戲平台提供的背景緩存NES中就不存在,他的所有數據都是直接被繪製在屏幕上的,而且繪製的過程和代碼的執行事實上是交錯進行的,而當前的遊戲一般情況下硬體都是等待程序將圖像完全繪製到背景緩存之後在翻轉到屏幕上,遊戲程序與硬體的繪製過程是獨立的。

最後對模擬的具體遊戲提供一些建議,按我的經驗,依據模擬的難度由易到難的話,最先應該被支持的應該是卡廠的1942,這個遊戲不但容量小(Mapper0)而且對時鐘的模擬要求並不嚴格,也沒有使用任何技巧,是入門的不二之選。千萬不要認為容量越小的遊戲模擬起來就越容易,只有1942一半大小的F1賽車就是一個運用了很多技巧的作品,即使No$Nes都不能很好的支持他,至於任地獄最偉大的作品SuperMarioBro2,差不多是Mapper0技巧的大成者,如果能完整的支持這個作品那基本標誌著你對FC自身硬體的模擬已經完成的差不多了,接下來主要是對卡帶的模擬,這裡說「基本」是因為SMB2沒有利用一個中斷方面的技巧,如果沒有很好的模擬這個,你就無法運行《炸彈人》~~~~

在Mapper0的模擬完成之後,最容易實現的就是Mapper2和3,偉大的魂斗羅就在其中,而且支持他是很簡單的。

餘下的mapper就都比較麻煩了,想完整的模擬就要仔細看各種文檔,不過也都是力氣活,寫模擬器就是這樣,沒什麼技術的門檻,關鍵是要有足夠的耐心~~~~


瀉藥

你邀請我,我也不會呀( ⊙ o ⊙ )!

可以參考一下

WindowsPhone-GameBoy模擬器開發一--走進模擬器:如何編寫模擬器

模擬器開發技術淺談


支持樓上觀點。如果datasheet資料充裕,那做模擬器就是嚴謹的按部就班抽象數據結構。

額,很多年前,要在小靈通上實現一個FC模擬器。

因為開源軟體很多,移植實際上並不花費太多精力。就是時間問題。

FC的硬體級code page很多很雜,感謝上帝開源軟體的大神已經移植好了。

大致注意的就是:

1、了解目標設備的CPU體系結構。幾個寄存器、指令彙編到機器碼的規則、定址範圍、定址模式之類的。抽象數據結構很簡單,C實現的時候,位段、union就足夠了。其內部一個狀態機實現足矣。

偽代碼:

RunStep(parse(cpu-&>IData[cpu-&>current_pc_prt+1]));

2、了解目標設備的外設時序、datasheet、原理圖如果有最好了。諸如液晶、鍵盤、聲音等等。

偽代碼:

OnRightSoftKeyClickDown()

{

SetInput(cpu , peripheral-&>key.A , true);

}

額,大致如此吧。

爛尾項目。匿了比較好。知道我是誰,也別聲張了……


其實題主你不要覺得模擬器就一定需要這些底層的語言。我在研究院的一個同事讀書的時候就用Haskell寫了個FC模擬器還能玩超級瑪麗,FPS還能接受,不過我剛想貼他的鏈接,發現整個博客被刪掉了……

根據他的說法,開發FC模擬器需要的技術儲備是很少的,最麻煩的問題是找不到資料。


編程我不懂,就說幾個大概的印象吧。

我覺得你有個很大的誤會,就是遊戲機機能越弱,模擬器就越簡單,大錯特錯。

在PS以前,遊戲機的硬體不是在遊戲機里,而是在遊戲卡里,搞單片機的人可能對這個比較習慣。模擬遊戲機要比單純模擬一個CPU難得多,CPU簡單不代表機器簡單。越原始的遊戲機模擬器越難開發,最早的遊戲機連軟體都沒有,是純電路的,拿塊電路板自己讀去吧。FC的硬體規格算上遊戲卡我記得有200多種,到現在都是最複雜的模擬器之一,類似MAME這種多硬體模擬器了。

一定要對遊戲機硬體,以及當年相關的電子技術標準有徹底的理解。比如幀緩衝,老遊戲機是緩衝一行畫面,程序輸出的時候就不能輸出一幅畫面,而是要利用中斷一行一行輸出,你做模擬器的時候也要模擬這種緩衝輸出的形式。

容易開發的模擬器,遊戲必須是純軟體的,比如GBA這種採用快閃記憶體卡儲存的。最好硬體也是通用硬體,而不是定製的,否則你找不到晶元的數據手冊就傻了。

不過FC這種老主機,已經有很多很好的例子了,可以先讀別人的作為入門。

有本老書叫任天堂遊戲編程探密,裡面用《大賽車》這個完整的遊戲作為例子,其中用到了行緩衝放縮的技術,非常有參考意義。


推薦博客

http://www.cnblogs.com/YiranXie/

大量模擬器開發的資料整理


C/C++語言用來寫指針操作是很方便的,所以至少你要會C語言,但是如果使用C++11的一些功能,會讓開發起來更方便。彙編語言要會一點,因為你需要自己寫demo(照著教程做),以及閱讀別人的demo來查找實現錯誤(例如指令測試代碼,別人想表達什麼,這時候還需要去猜測別人的意圖)。不需要編譯原理知識,只需要簡單的數據結構知識。

在開發的過程中,你會遇到幾個問題:

1、調試

由於是可視化的程序,所以你得找一種圖像顯示的方法,OpenGL很不錯,學這個比弄模擬器簡單多了。

然後需要做個界面,用Cocoa來開發很不錯,畢竟你想debug,下斷點在Xcode里非常方便。

2、實現指令

這個是核心部分,資料比較好找,甚至現成代碼都有。可是,照搬別人的代碼沒什麼意思,去自己通過閱讀文檔來實現又會出錯,而且幾乎無法校正。後來我找到一份附帶實現代碼的文檔,只是一些函數的調用,看這些函數的調用去理解指令的實現比文檔靠譜多了,而你只需要實現這些函數即可,甚至自己改寫都可以,並不算完全照搬。

3、 查資料

最要命的就是這個,我這裡整理了一些資料,可以看看我的博客文章:

NES模擬器開發資料

嘗試開發NES模擬器

最近剛好實現了一個能跑《超級馬里奧》的FC模擬器,從一開始我就不打算看別人的源碼,決心自己從頭做。反覆閱讀資料,去理解NES的設計,到後來慢慢看著自己的模擬器能夠一點一點進步,從一開始顯示背景,到角色運動,再到後來模擬一些簡單遊戲,最後到馬里奧在屏幕上跳躍,確實很有成就感。而這件事我高中的時候就想去做了,真後悔沒有早點開始,確實能夠收穫頗豐,成長頗豐。

最後說一句,要實現簡單的指令模擬,到顯示圖像,只需要一周時間。而真正完成遊戲模擬,則需要幾周時間,但是堅持就一定能實現。


擼的一個基於JSNES的網站。。

手餅丸|手機當手柄玩FC紅白機模擬器


要完成一個簡單 nes 模擬器,比如能運行超級瑪麗、魂斗羅之類,其實難度不大。代碼量也不算太大。

重點和難點在於搜集、閱讀、理解 nes 的硬體資料。如果你對 nes 的工作原因都了如指掌了,還需要什麼呢?當然是控制不住的編碼衝動,反覆的編碼和調試。

nes 各個部件的具體細節,這裡沒法展開介紹。泛泛而談的原理和模擬方法,許多人也介紹了不少。我就講講一些實際且有指導性的東西。

1. 任天堂遊戲機分為 nes 和 fc 兩種,主要區別在於 nes 是 ntsc 制式,而 fc 是 pal 制式。建議從 ntsc 開始,原因是能找到的多數資料都是 ntsc 制式的。

2. 除了理解 cpu ppu apu 等各個部件的工作原理,請一定研究清楚 nes 內部有多少時鐘類型,以及相互之間的關係。簡單的說有一個主時鐘,我稱之為 mclk,然後 cpu 時鐘與 mclk 的關係是什麼?apu 的時鐘與 mclk 的關係是什麼?是同步還是非同步?

搞清楚以上問題,我們就真正明白,各大部件之間是如何互聯,編寫模擬器時,又是如何保證聯繫和同步的。

3. 調試 cpu 一定要藉助 cpu 的 test rom,而且這也是必經之路。cpu 的模擬,在搞清楚原理之後,說到底不是技術活,是個體力活。等你完成自己的 cpu 模擬代碼後,第一件要做的事情,就是找 cpu test rom 進行 debug,而不是急著去實現其他部分或者跑遊戲 rom,不能急一步一步來,保證每一步的正確性。

各種 test rom 是必須的工具,可以幫助我們快速定位問題,這些工具在 nesdev 上可以找到。等你進入跑遊戲 rom 的 debug 階段,整天就是在折騰這些。

5. 精確模擬、持續 debug 和完善才是難點。如果僅僅是做一個 demo 那當然很容易完成。但是要做一個優秀的模擬器,不僅僅是搞懂原理,寫出代碼這樣簡單,需要的是反覆的持之以恆的調試、優化。


剛用c寫完一個nes模擬器的來回答一下,最重要的是資料資料,不然你根本不知道哪個內存中的哪個位元組中的哪一位是幹嘛用的,cpu模擬不複雜,主要是ppu,ppu部分很繞,需要耐心的看。還有要對定址,偏移等基本的彙編知識要懂,要知道如何把彙編語言轉化成你會的語言,就是靈活運用,^, | , &<&< , &>&>等這些運算符。 = =。


懂基礎高級語言,懂某操作系統下的程序編寫。看懂6502彙編指令作用,方便用其他語言模擬。搞懂CPU與PPU,乃至畫面顯示的邏輯關係。不需要多深的知識儲備,是軟硬體都懂一點就行。


。。。路過 貌似得十分有耐心才行啊


推薦閱讀:

如何學習嵌入式系統?
嵌入式硬體開發愛好者去哪的工作體驗會比較好?
嵌入式 Linux 如何操作 GPIO ?
開源硬體的優勢在哪裡?

TAG:遊戲 | 計算機 | 嵌入式系統 | 紅白機FamilyComputer,FC | 計算機體系架構 |