2016年12月12日 星期一

C#使用指標雜談

C#使用指標並不是什麼很厲害的技術,新手除外,稍微對C#有更深入一些經驗的人,我猜多數都有在C#使用指標的經驗,所以我這邊主要也不是要介紹C#使用指標這件事情,而是雜談些別的.

C#雖然可以使用指標,但如果是一般的方式
https://msdn.microsoft.com/zh-tw/library/f58wzh21.aspx
也就是搭配 fixed 陳述式 , 跟 C 指標操作存取相比會顯得非常沒彈性 , 所以在C#達不到C操作指標的靈活度.......但如果使用 Marshal 來進行 unmanaged 的記憶體配置拿到指標 , 則在C#中則"幾乎"(還有不少確認和爭議空間)可以達到 C 操作指標的靈活度

Marshal.AllocHGlobal
Marshal.FreeHGlobal

這兩的東西好用至極,之後要存取物件的習慣也幾乎跟C一樣,詳細的使用介紹就自行google,不多談.

這邊要說到的是有了這項能力後,處理模擬器其中一個問題顯然簡單而且有效率很多,電腦世界中雖然最基本的資料單位是 bits , 但硬體上資料能存取的最基本單元是 bytes , 8bit CPU 要模擬記憶體的硬體機本上宣告一個固定大小以byte為資料型態的array即可 , 不過到了32bit CPU一次存取可能就是 half-word (2bytes) 或是 word (4byte) , 有時候你從一個位址讀資料可能是要讀一個 byte , 有時候可能是一個 ushort , 有時候可能是一個 uint .



如果要讀4個byte, 你可以自己對 byte array 讀取4次  , 然後用 bitwise 的操作自己串成一個 uint ,顯然是麻煩 , 使用指標的狀況下 ,你可直接指定說我要從這指標的某個offset讀取 byte ushort uint 位元長度資料.

            byte* bytepointer = (byte*)Marshal.AllocHGlobal(sizeof(byte) * 16);

            bytepointer[0] = 0x00;
            bytepointer[1] = 0x11;
            bytepointer[2] = 0x22;
            bytepointer[3] = 0x33;
            bytepointer[4] = 0x44;
            bytepointer[5] = 0x55;
            bytepointer[6] = 0x66;
            bytepointer[7] = 0x77;
            bytepointer[8] = 0x88;
            bytepointer[9] = 0x99;
            bytepointer[10] = 0xaa;
            bytepointer[11] = 0xbb;
            bytepointer[12] = 0xcc;
            bytepointer[13] = 0xdd;
            bytepointer[14] = 0xee;
            bytepointer[15] = 0xff;

            ushort t_us;
            t_us =   ((ushort*) &bytepointer[4])[0];
            Console.WriteLine(t_us.ToString("x4"));
            t_us = ((ushort*)&bytepointer[9])[0];
            Console.WriteLine(t_us.ToString("x4"));

            uint t_ui;
            t_ui = ((uint*)&bytepointer[2])[2];
            Console.WriteLine(t_ui.ToString("x8"));
            t_ui = ((uint*)&bytepointer[4])[1];
            Console.WriteLine(t_ui.ToString("x8"));
            t_ui = ((uint*)&bytepointer[9])[0];
            Console.WriteLine(t_ui.ToString("x8"));
            Marshal.FreeHGlobal((IntPtr)bytepointer);

資料存取變得像切豆腐一樣容易,對於資料長度讀取的轉換可以任意有彈性來做.

不管是Read 8/16/32 或是 Write 8/16/32 ,把資料長度型態改變, 對可以對應了.

2016年12月6日 星期二

移植雜談

測試了一下網路上別人寫出的ntsc掃描線模擬函庫,出來的效果完全是我的想要的效果,太完美了,嘗試實作自己的一套,但要去理解ntsc畫面訊號規格太複雜,至少對我來說需要不少時間,於是打算使用移植的方式,從C移植到C#去,最後C#整個都在跟指標打交道,出現照理來說C#不常看到的 -> & 等等符號...但其實從C/C++移植最難的反來不是指標(甚至照理來說應該要把指標的處理方式給改寫掉比較符合風格上的正確),而是寫C的人很習慣把玩巨集和一些前置條件,而寫C++寫到狂的人則超愛用一堆複雜的樣板到讓人有走火入魔的感覺,還有一堆詭異C++近年來的新語法規格,這些移植到C#都相當麻煩.

2016年11月19日 星期六

Win3mu

作者解說
https://hackernoon.com/win3mu-part-1-why-im-writing-a-16-bit-windows-emulator-2eae946c935d#.ca6ygh8cl

專案發佈站
http://www.win3mu.com/

可以在現在64位元 win10環境下跑以前 win3時代16bit的應用軟體.

作者手法相當有趣.

cpu是撰寫出來模擬的,但跟api服務有關的部分全都靠remp到64位元系統相似api去吃.

由 upernes 談起...

http://blog.vreemdelabs.com/2016/05/08/upernes-a-nes-to-supernes-game-recompiler-passing-the-tests/


這專案的概念其實有相當多的討論議題延伸,大概簡單說一下, nes 主機用的是 6502 , snes 用的是 65c816 , 其實可以視為是 6502的16bit功能延伸版,本身其實有設計8bit相容模式,所以曾傳聞超級任天堂有考慮過向下相容任天堂紅白機遊戲,但因為cost考量取消這相容能力....

到這邊大家會想到,那既然如此有沒有可能將任天堂的遊戲放到超任上跑,透過某些轉換的方式?

理論上當然可以,但實際上問題當然很多....程式能否執行cpu相容的問題其實只佔部分比例,還有很多層面的問題要考量,光snes硬體的memory map 跟 gpu 等等架構就跟 nes 不同了, 光cpu指令理論上可以達成相容互通又如何??

這專案的確示範了某種概念,但發展有限,可以執行很簡單的demo,估計是做了很多 remap 的工作.

而像是任天堂的GBA或是NDS用的是ARM系列CPU,現在手機很多也多數是用ARM處理器,當然隨著ARM版本不同,指令集會有部分差異,所以理論上在ARM環境上最高效率的執行ARM遊戲主機遊戲的方式應該是透過一個轉換器,針對少部分指令的差異重編達成相容,然後只需要模擬CPU以外的硬體環境即可,但想也可以知道理論上好像越簡單的東西,實作上問題就是更多,目前也沒有看過任何人發展出這種方式來執行.

目前也只有看過把NES的ROM透過LLVM工具編譯成執行檔在X86環境上執行.

簡單來說,能否執行光只靠CPU能互通這點條件是不足的.

由xBRZ filter淺談平行處理問題

xBRz是目前我用過在cpu cost與畫質上cp值頗高的影像放大濾鏡演算法
https://sourceforge.net/projects/xbrz
原始版本是C++ , 有人移植到C# ,我再接手進行一些效率優化的處理以及把一些最新xBRZ C++官方版本的最新功能加入,至少套用在電玩畫面的高效率輸出,即使用C#來寫效率也是OK的 .

但這演算法有一套很可惜的地方,導致移植到平行處理的方式會有問題,只能用某些折中的方式來進行平行多核處理.

首先這套演算法有每一條平行線與平行線之間的計算順序上的前後相依性,而且目前我還沒辦法找到方式去改寫這塊,因為這似乎就是xBrz演算法其中必須的核心精神要項之一,要拆除順序相依的問題,可能得自己研發變種版xBRZ.

因為這種相依性,平行計算下去,在計算順序無法控制預期的狀況下,出來的結果就是亂七八糟的.

目前找到兩套解法各有優缺點.

1.把畫面切成4大塊,4大概各自平行處理,效率滿好的,缺點只有兩個,一個是四塊區域銜接的邊界其實運算結果有可能是錯誤的,但因為其實原始只佔一pixl的誤差,一般沒很刻意去注意和比較根本不可能查覺,二是目前有太多電腦cpu核心數量其實超過4核,把整個運算切成4份,其實還浪費掉其他閒置率高的cpu.

2.跟線與線有關的順序性結果先算好出來,這部分沒平行加速幫忙,因為也幫不上忙,剩下再用平行的處理方式下去跑 (高的長度處理迴圈用parallel) , 缺點當然是有部分的計算是單核跑,且跟第一個方法比起來,context switch的cost當然也高不少(這還有改善空間就是,未必要以高度數量來當工作數量),優點來說的話就至少算出來的畫面是沒有瑕疵的,且cpu核心至少在處理高度迴圈時是有整個盡用的.

像這種順序相依問題一但拆解不掉,拿到GPU去跑一樣無法,甚至更慘,以前曾想過拿GPU來算一些結果,特別是畫面的計算這塊,但後來發現結果沒比CPU好,好壞結果真的很難論,最後未必有絕對性的優勢下,考慮利弊拿捏,最後沒往那方向走.

先撇開相依性的問題不談,假設一個龐大的計算工作,可以同時拆解成很多小任務丟給GPU跑,光是把計算資料COPY到GPU記憶體,和把GPU算好結果COPY回一般記憶體這段這段COST就把優勢佔光了....還不包括GPU計算初始化時間....這種問題,比較新的opencl加特定條件的硬體環境,似乎可以改善,總之大概就是這樣,平行處理並不是萬能仙丹,滿多問題會導致無法使用這種計算方式,即使可以算很多因素也未必說效率就一定會提高,應該是特定問題的處理適用.

至於透過網路來分散平行處理,更不用說...網路傳輸cost成本必定得計算在內.



2016年11月16日 星期三

再談任天堂紅白機撰寫心得

http://baxermux.byethost18.com/myemu/AprNes

任天堂紅白機模擬器撰寫已經到了一個段落,後續就是持續修bug和準確度修正.mapper支援追加等等工作,但由於開發目標是以學習為目的,是否要(或是說是否能夠)發展到達成專業完善水準反來是其次問題,就隨緣看興致吧.

所謂 "台上10分鐘台下10年功" 這句話放在模擬器開發上也非常適合...

願意或是不願意去嘗試撰寫,這是可能與不可能的差異.

有寫出基礎作品跟寫不出來,這是一個滿大的層次上的差異.

寫出基礎作品.跟寫出一個中等程度的作品,這是一種程度上的差異.

寫出中等程度的半熟作品與專業成熟完善作品,這可能是幾年累積差異的結果,或是神人與凡人差別.

總而言之技術和能力上的不足,只要肯用心都有可能花時間去彌補,熱情和興趣常常才是能不能堅持到最後的差異,對於平凡眾生來說.

PS.也不知道怎麼搞的,大名名鼎鼎的 NO$系列 出的NO$NES模擬器竟然連洛克人玩起來都可以出嚴重問題直接跳掉....這倒是讓我滿訝異的,洛克人3.4.6代全都屬於不能玩的階段.....但NO$網站所寫的硬體資訊確又相當詳細(雖然那種文件真的不適合初學者拿來當學習入門).

2016年10月26日 星期三

Nes Rom header

特定檔案類型的標頭照理來說應該要是一個嚴謹而且有組織單位背書的標準規範,但這種事情其實也不是那麼一定,特別是從社群發展的東西有時候牽涉到各個社群的風俗習慣或是發展者的個人想法,在沒有特定單位出面嚴格處理標準化的制定問題下,就會產生標準不一樣的問題,這對開發者來說並不是好事情.

以任天堂的ROM檔來說目前最主流最主流使用的header格式稱為 INES header,標頭共16Bytes大小,緊接著後面連貫的是RPG-ROM與CHR-ROM實際內容,理論上搞定INES header就可以,但實際上這格式內容卻有些新舊衝突的問題要謹慎處理,這東西是由社群和領導制定者產生的東西.

ines header最大的公約數是開頭一定是 'N' 'E' 'S' \0x1a 這四個字元(檔案內容byte 0~3),接著是一個byte的RPG-ROM count (byte 4) , 接著是一個byte的CHR-ROM count (byte 5) , 以及擁有mapper與rom重要屬性flag的 byte 6 與 byte 7 , 接著 byte 8 ~15 是實作上比較沒那麼重要的資訊,輔助性質的一些東西,隨著 ines版本或是各dumper者習慣而有資訊多寡不同,簡單來說如果你找相關介紹資訊,會發現byte 8~15 的定義有些差異 , 通常舊的ines header byte 8~15內容都為 0x00,新版的 nes 2.0 ines header延伸規範則會有新的屬性.

撇開新版的ines 延伸規格 nes 2.0不談 , 就算是舊版只討論 byte 0 ~ 7 的內容,也還是會有些衝突問題會導致mapper解讀錯誤,最主要是早期某些rom 對 mapper的解讀定義是不會理會到 byte 7這邊,從 byte 7 ~ byte 15 會填入 DiskDude! 這幾個ASII code , 如果你拿到這種rom用新的正確規範去解讀,就會踩到地雷,從mapper 0 變成 mapper 64.


Early ROM processing tools were not aware of Flags 7 because the earliest emulators ignored it. For example, one tool put 0x44 (ASCII for 'D', the first character of "DiskDude!") here. This confuses newer emulators, which combine the nibbles from Flags 6 and Flags 7 to form an incorrect mapper number. NES 2.0 redefines the unused bits to always equal binary 10, which happens not to match any of the patterns used by these ROM processing tools:

簡單來說需要有一個判斷方式去對這種特立做解讀mapper上的修正.

流程大概是 

1.如果 byte 7 低4bits 為 0 , 進行標準ines規範maper解讀,
mapper = (byte)(((byte6 & 0xf0) >> 4) | (byte7 & 0xf0));



2.如果 byte 7 低 4bit 不為 0 ,且   byte 7 bit3為1 & byte 7 bit2為 0 ,認定此為遵守nes 2.0延伸規範的header定譯內容.

3.如果 byte 7 低 4bit 不為 0 , 且byte 7的 "bit3與bit2"不為 "1與0" , 則是早期非標準的版本.
mapper = (byte6 & 0xf0) >> 4;



以上.....社群零散發展起來的東西其實就會有這樣的狀況,就算組織單位也常常會有規範衝突的問題,但又是別種層面的狀況.

其實ines的規範標準並不是說很方便完整,也有新的規範方式出現,不過並不普及,模擬器多數實作也不一定會支援,如果我是當初的制定者,我大概會給mapper一個完整的byte,而屬性控制則獨立一個byte分開來放置,不需要把mapper硬切高低 4bits 放置到兩個 byte 跟 屬性控制bits混雜,有可能最早時候沒考慮到 mapper的數量會超過於 4bit範圍這問題.



2016年10月3日 星期一

任天堂紅白機模擬器



去年年初撰寫了任天堂紅白主機的模擬器雛型,大概如上圖,好像有一回事,但其實相當不完善,任天堂紅白機跟GameBoy初代兩台主機相比,若是以初學來說,我會建議學習選擇gameboy做為起步入門的嘗試,因為即使到現在我都還沒辦法將紅白機給摸透 (悟性不夠阿... orz....) , 在整個系統的 timing 模擬設計與記憶體mapping.register與vram address相互影響要摸熟都有一定的複雜度,能實做擁有正確畫面 scroll 效果需要不少功夫的, 這也就是為何我 demo 的遊戲畫面只選擇定格於同一背景的類型.

總覺得這東西沒有好好完成很可惜,想繼續完整實做,這次也放棄單靠閱讀文件來做全部理解 ,應該會參考別的project來輔助理解,甚至部分改採移植的動作,再慢慢理解.

8086模擬器專案目前在io周邊裝置實作上遇到一些瓶頸,也覺得有點疲備,先換個口味吧....如果沒又荒廢掉的話,希望能夠在今年年底或是明年初推出正式的版本.

2016年9月17日 星期六

Apr8086 雛形Demo

https://dl.dropboxusercontent.com/u/61164954/project/Apr8086/index.htm


趁著連假這幾天趕了一下進度,開始檢查和修正之前寫好的8086 cpu code指令模擬的bug,利用fakePC這個project加以修改,匯出執行每一個步驟的各暫存器的log,用來檢查自己的專案正確性,持續修正到將BIOS畫面輸出,由於尚未時做控制周邊IO,目前會讀到IO的回傳部分是依賴fakePC記錄輸出(建立步驟與io回應的關係),記錄了步驟從從1~1100000 其中會回傳io read的部分,順利到達系統記憶體checking階段,然後就暫時先停止運作,等待日後更完整實作.

目前撰寫起來,雖然8086 cpu模擬也還稱不上困難(相對於arm解碼, 8086已經算是很好處理了),但這顆16bits的cpu相較前身8008來說整體運作已經付雜很多,主要是x86的節區運作觀念,幾個節區暫存器怎樣的狀況下使用哪個,又記憶址分成 effective address (EA) 與 physical address (PA),每種狀況下換算用的方式又盡不同,以及所謂的prefix指令,最後就是雜七雜八的定址法,跟8bits cpu時代相比完全不可一概而喻了,但CPU要用軟體模擬只要規則搞懂,flag沒搞錯,基本上也就是規格書怎麼描述,你就依樣畫葫就是,所以錯得再怎麼多,只要有耐性,跟別人的的steps log比對,看看問題出在哪還節哪個指令,慢慢修正下去,都還可以處理.

比較麻煩的,對於像我這種悟性比較不足.硬體接觸經驗又相對不足的人來說,幾個周邊裝置io的了解與模擬,我認為才是後面階段的大重點.

由於這並非是我我的工作,只是我的興趣與休閒,因此之後進度也沒很刻意要求,一切隨意.

2016年8月17日 星期三

8086 指令集模擬完成後

單只有CPU不能稱上是一部電腦,若只是把指令集模擬完成,還是沒有任何作用,於是開始進入相關電腦周邊控制模擬的階段,簡單來說cpu可以透過 IN OUT 兩個指令對 IO port 做溝通,在8086中這個 IO port 很相似於一個獨立的記憶體介面位址(只是讀寫的是裝置) , port 位址從 0x0 ~ 0xffff  (不確定 8086之後是不是也是這樣) , 鍵盤.滑鼠.軟碟片.顯示卡...有的沒的基本周邊都要透過 IO port去溝通存取控制, 而且各自的控制器都有各自的規則特性 , 需要去了解 , 完成了cpu的指令模擬真的才完成整個專案的一小塊部分,所以還有一段路得走.

列出參考  http://wiki.osdev.org/I/O_Ports

每一個裝置控制器要了解又得花不少功夫(至少對我這種平凡的人來說)......

其實後來看別人的project sources做法,有些似乎沒有真正完整實做這些周邊的功能特性(控制器規則等等),只是把DOS跟BIOS用到的中斷服務最後結果給做出來,簡單來這算是一種取巧的做法,這種作法有利有弊,優點大概就是程式較為簡略些,我只要管呼叫這個中斷要得到什麼正確的結果,更底層 IN OUT對周邊的動作控制細節不用真的處理到,速度理論上也比較快.缺點大概是相容性有限,如果是別的作業系統中斷功能定義跟DOS不同,當然就有問題 ,這種差異大概就像是 Dosbox 和  Bochs 兩種實做的差異 , dosbox官翻網站所言

https://www.dosbox.com/links.php

 Bochs emulates a full x86 based pc. Unlike DOSBox that tries to mainly emulate dos programs.

至於現在,因為這專案偏於學習使用,剛好趁這機會也多了解一些東西,姑且先以 full x86 base pc為開發目的,若以後有別想法或是難以實現,視情況再修改做法.

2016年7月12日 星期二

GNU lightning jit 應用例子

對模擬器的喜好來自於對遊戲主機童年時期的熱愛(約佔70%),以及本身是資訊人,多少對技術方面的東西會更有興趣些,所以偶而會找找相關資訊看看.

其中剛好看到了一個利用JIT加入效能的範例如下

http://jeffq.com/blog/nds4droid-release-35-beta/

用的是 GNU lightning 這套JIT加速library

https://www.gnu.org/software/lightning

相當有趣.

隨著資訊技術這幾年的發展,很多新的技術都慢慢被應用在模擬器的開發上.

8086 指令解碼

x86 模擬器裝案的進展荒廢許久,最近把顯示卡的部分K一K了解一下,打算重新再來過,反正姑且一試,第一個步驟還是習慣先從CPU本身的核心開始撰寫起,當然16Bit的CPU指令複雜度已經沒像8bit CPU那麼容易了,但我個人覺得比起ARM,x86的8086這顆cpu指令解碼複雜程度相對來說還是簡單許多.

8086這顆cpu的指令已經無法使用拿指令的第一個byte用窮舉法搭配 switch case的方式來做完全的剖析,一定會有重覆的衝突,不過無所謂,只有少數幾個指令需要用第二個byte的 bit 5~3 這三個bits再做一次分析,還是可以用窮舉法,只是某幾個地方需要用到兩層.

最聰明的decode策略應該是完全了解指令的格式規則,然後用樹狀關係圖去分層出解碼的步驟,但這種方法未必會比較快,最笨的窮舉法直接靠table查詢,理論上應該是最快,但就是怕缺漏掉一些項目.

8086 格式
http://aturing.umcs.maine.edu/~meadow/courses/cos335/8086-instformat.pdf

datasheet
http://www.ece.cmu.edu/~ece740/f11/lib/exe/fetch.php?media=wiki:8086-datasheet.pdf

286開始有保護模式,386第一顆32bit cpu,486直接附帶浮點函數計算能力與相關指令,一越新的硬體越複雜,先從簡單開始,至少8086已經可以跑win 3.0了 ( 3.1需要跑在最低286上).

最後不得提醒一下,不要以為官方出版的資料或是規格書之類的東西就100%不會有錯誤,實際上就還是會有可能遇到,而且我在兩分資料中各遇到了兩次....

舉個例子來說


2016年7月7日 星期四

x86 電腦研究心得

看 8086tiny 這專案剛看會給人誤會,以為要模擬PC X86模擬器不會是太複雜的事情,再追究下去,會發現這專案用了很多相當聰明的方式簡化了所包含的CODE數量,但簡化的道理卻因為對硬體沒有夠詳細的了解,也不知所以然來,於是放棄了以這專案為學習的開始,改以 V86 https://github.com/copy/v86 這款js pc的模擬器為學習對象,完整度可以執行到win98不是問題,重點是很紮實地去跑了system bios跟vga bios,追著這專案跑,一跑到VGA那塊馬上發現自己的無知,原來電腦VGA顯卡還是有很多學問,很多對應port的Register各自有各自的功能,然後記憶體排列的原理和規則等等,要搞懂也不是那麼簡單,像這種東西在早期有很多相關的書或是資料,但現在可以找到的說明越來越少,能找到的多數是英文,但解釋的也未必很清楚

http://wiki.osdev.org/VGA_Hardware
這篇有很多vga卡 port的作用和記憶體屬性規則在各種顯示模式下的說明

很多東西還得再細看和實際demo測試....不是說那麼好懂.

2016年1月29日 星期五

z80 , 8008 , 8086 , 6502

純心得文.

GameBoy用的z80特殊修改版(簡化掉一些功能.修改掉一些功能) , 以前實作過 , 所以還算熟 , 定址模式不會很複雜 , 反來是同期的 6502 定址模式多不少,相對複雜 , 但有趣的是後來才知道 z80原來就是 Intel 8008 的相容實作 ,然而在8086這顆Intel 16Bit版本的cpu卻反來充滿了 6502 的一些影子在 ,  不知道這中間是有啥商業合作關係或是設計關係在 , 總之8086有著模仿的影子 , 但模仿對象相似對象卻不是自己上代 8008 ,反來是 相異產品 6502 ,滿有趣的.

目前正在邊學邊實作8086電腦,看到那堆定址模式給我的直覺聯想到的是6502,定址模式複雜沒關係,反正做啥就做啥,一板一眼的應該是還好,但PC模擬器周邊裝置的模擬反來複雜些,目前正在慢慢理解如何實作軟碟機.硬碟.光碟和一些裝置IO這塊,總之東看西看,慢慢來.,..期待有機會完成一個基礎的8086 PC.

目前大概的心得是,PC模擬器似乎不用考慮到如同遊戲機嚴謹的timing問題,顯示的部分也簡單很多,理論上應該會比遊戲機的模擬容易一點,但相對的PC的裝置周邊這塊又是遊戲模擬器所沒有的部分,反來需要比較多功夫.


模擬器兩方向發展議題

過去多數模擬器採用的是直譯式的運作方式,直到現在還是一樣,但俗著近年來很多技術從實驗階段到發展成熟到普遍應用,像是最有名的JIT或是LLVM之類的工具或是概念,也影響到模擬器的實作方式,網路上開始零星(數量還不多)出現一些採用非直譯方式的模擬器,下面就是一個例子

http://andrewkelley.me/post/jamulator.html

多數是採取8bit的遊戲主機為範本,讓異質的機械碼編譯成x86原生碼.

wii模擬器Dolphin中,也看得到模擬模式中有類似含意的選項.

這是非常有趣的嘗試,不過因為技術層次比較高,多數人會先採取將較為簡單的機械碼做轉換,所以才通常是會8bit遊戲主機的模擬器來學習,但實際上如果以實用性來說,CPU 模擬的運算在古早主機中負擔比例其實很低,反來是GPU等等部分模擬代價較高,通常會這樣做多數可能是基於研究或是學習立場,並沒有真的帶來很多好處.

不過如果是近年來的進階機種,cpu模擬耗用運算可能就不低了,這時候這種效能比直譯佳的運作模式,就帶來很多好處.

這種東西其實有很多進階討論的空間,而且不單單能在遊戲模擬器上發揮,試想著ARM與X86透過編譯步驟的方式,就能快速擁有雙邊硬體的相容性,這是多夢幻的"未來"....


跟上面這種往高階領域剛好相反的模擬方式(上面是軟體發展的進步),是由於近年來硬體效能快速發展下產生的,那就是往更低的領域發展,電晶體準確層次的模擬器,也就是說它的模擬基礎是從電路邏輯層開始,這種設計方式反來耗用更高的運算資源,不過有著其他方式無法取代的優點,像是絕對準確的tinimg特性.保證原汁原味的功能等等,目前也已經開始有零星實作出現,但通常是技術宣示性質,執行效能還得做不少改善,才能到實用的地步.

想像一下如果真的是在未來,電腦主機效能強大到無法想像的地步,模擬一台主機所要做的是把遊戲主機拆解,邏輯晶片打開,拍張照,把線路layout匯出描述,接著就可以跑了,也是一件很夢幻的事情...誰知道那天何時到來?  就像是當初誰也想不到現金一台手機的效能,就打死過去一整台桌機一樣.

目前是受限效能,因為邏輯電路是平行的運作方式一層一層下去,從這層次去模擬代價是相當多倍的運算資源,不過讓我發想的倒是這種運作方式在平行運算的超級電腦上似乎還ok,又或者是近年來利用顯卡異構計算的平行處理運算資源輔助?  這似乎也是一個方向.

相關參考
http://www.mobile01.com/topicdetail.php?f=514&t=1799027
http://blog.visual6502.org/2014/10/atari-2600-simulation.html
http://psxdev.ru/news
http://hackaday.com/2014/12/18/counting-transistors-in-the-playstation/
http://sourceforge.net/projects/dice/

ideal很多,不代表我有辦法在現在去做一些想法驗證,多數還是看看資訊.整理資訊而已.


2016年1月11日 星期一

8086tiny 相當有趣的 8086 PC 模擬器專案

Intel 8086介紹
http://www.mynikko.com/CPU/8086.html

專案網址 8086tiny
https://github.com/adriancable/8086tiny

別人再次延伸功能與修改版本 8086tiny plus
http://jaybertsoftware.weebly.com/8086-tiny-plus.html

原本對PC模擬器比較沒興趣,但就剛好看到這別人的專案,短短的不到800行code,完整實作8086電腦PC,完成度跑遊戲 WIN3.0 都不是問題,真的是滿神奇的.

回想起以前用ET3跟PE2.DOS的歲月....雖然它是以8086為對象,8086跟現在電腦相比少了非常多非常多功能,但是卻是80x86系列的開山始祖(比8086更早前的Intel處理器差異比較大,一般大家是把8086定義成為x86的開端),某種意義上算是一個簡化的雛型實作,16bit的暫存器.最大1MB記憶體定址.只有真實模式雖然陽春但跑跑一些早期的東西也不是問題了.

大體上看了一下專案的內容,作者真的把8086指令集K的很透徹,所以大幅減少CPU這塊處理的程式碼,另外文字模式直接借用現成環境 console 輸出,也是少了很大一部分,因此這款模擬器會在進入到繪圖模式時另外跳出SDL視窗.....雖然很怪異,但也因為簡化.簡單,讓人可以很快地了解整台電腦的基礎運作,也方便做最簡易的實作.

比起遊戲主機,似乎PC的模擬器並不用做cycle時序性處理的問題,有的也只有怕現在電腦太快,所以有在一些環節加上delay,調整速度,但並沒有一個很精確的速度模擬.

滿有趣的東西....

這種做法是一種方式,大概略知一二 ,dosbox 或是 bosch 都是這樣 , 但進階的像是QEMU dynamic binary translation 模擬方式,或是更快的  virtualization 技術層次又更高,效率又更好了,只是實作門檻想必然更高.

PS.補充一個CANON EOS相機的移植版
http://www.magiclantern.fm/forum/index.php?topic=14853

2016年1月3日 星期日

C# 效能校調優化感想

總是會好奇C#效率表現的最高點為何,特別像是video filter處理那塊的效率,因此做一些code的調整,零零星星的大原則處理完畢後,接著是一些比較偏向於編譯器那塊細節的部分,這麼說也不太正確,因為我還沒摸到編譯器內部處理本身,除非自己玩opensource,而是指修改一些code的寫法,盡量讓編譯器產生比較有效率的code....多數都是用stopwatch實際測試看看,平平兩種寫法,在運算吃重時候就是會有差異,但往往會覺得...奇怪? 並不是自己觀念中預料的方式會比較好,有時候自以為簡化運算或是優化,結果反來會有反效果,又x86.x64模式的不同 . .net framework版本不同 . 一般模是執行或debug模是執行 . 是否有開啟優化處理 ,都會有些不太一樣 , 於是整個優化的修改過程比較像是try error , 反正stopwatch數據哪個好就用那種方式去寫,有一種被黑盒子遮蔽住的感覺,特別像是 .net 或是 java 這種會產生中介碼的技術,除了如何產生中介碼本身是一個變數環節外,之後JIT階段如何執行又是一個變數,因此形成一種讓人難以捉摸的感覺,你不知道你的CODE會被編譯器編譯出怎樣的中介碼,然後你也不知道這些中介碼會如何被 JIT 詮釋..

因此得到的結論是,如果真的要掌握和控制,追到中介碼反組譯是不夠的,連 JIT 產生怎樣的Native Code都要下去看看,才知道到底怎麼回事.....

目前是沒摸到這塊,也許以後興致來了再看看吧.

不過想起來很妙,人類傾向將底層的技術包裝起來變成越高階抽象方便的工具 ( ASM -> C -> C++ -> C# ) , 但用了方便的高階工具後又因為想掌握細節和自由,所以從高階抽象的那一層鑽研回底層低階的那塊 .