2010年1月8日 星期五

操作的必要性與不方便的必要性

Nita來訪, 確實給我許多啟發, 對孩子的教養就不提了, 因為這部分太多了我需要時間去消化.

偶然間, 她提到安藤的建築. 以下圖片是google來的, 要是有人覺得我這樣有點違反規則, 留一下言, 我把他刪了就是.

ap_20070724022248243



住吉的長屋據說是他為人設計但是之後買回來當自己事務所的房子. 這房子把一大堆地坪分給了天空, 然後把房子一分為二, 你要從房子的一邊到另一邊, 天氣好的時候可以曬一下太陽, 對健康有益, 要是遇到下雨, 恐怕要撐一下傘, 每一間房間都不大, 動線也不是太好, 總而言之是不太方便使用的那種, 看起來平凡簡樸至極, 可是卻是常被拿來討論的屋子, 傢俱據說也都不是方便大氣的那類, 因為擺不下. 看了下面幾張圖, 請自己揣摩一下.

7f0a6d5d

房子已經不大, 入口更小, 大約就是70~100cm寬的門.

sumiyoshi_no_nagaya_01

這房子住起來肯定沒有時下台灣所謂的豪宅舒服與方便, 以安氏而言, 電視裡面老是愛宣傳的那類超大豪宅他是絕對住得起的, 不過人家可是在這不太方便又小小的屋子裡面構想與誕生出一堆很棒的設計. Nita說得好, 就是要這麼不方便, 住在裡面的人就是要這麼遷就這建築才行. 不這樣, 無法有操作的機會, 不這樣, 無法有傑作誕生, 歷來一位作者一生中最好的藝術作品不都是作者在不方便, 甚至困頓的情況下誕生的嗎?

大哉斯言!

一個人必須透過不斷的操作, 包括心理與身體兩方面, 才可能可以有源源不斷的創意與作品誕生, 待在過於安逸的狀態是不足以產生好的東西的, 甚至連產生普通好的東西都不行. 好友吳鳴兄說, 要嫻熟一樣技藝, 或甚至只是初窺堂奧, 起碼需要一萬小時, 假如每天練習6小時, 那麼要四年多的時間才夠. 要成一家之言, 那非得日思夜想, 超過十年才行.

這讓我想起近年來, 物品越來越方便, 於是人類靠自己的雙手操作,  靠自己的感官判斷的機會越來越少, 當然由身體力行進而刺激思考的機會也就會更少, 接受新知識與新觀念的能力也就連帶的下降了. 所以人就會越來越退步了, 最後就像是提前衰老的人, 再也想不出新的東西來了. 很可悲的.

所以思想上與身體上的操作行為是必要的, 而要有機會操作, 那麼適當的不方便也是必要的了. 但是請不要誤會我的意思, 我並沒說一切都要不方便才行,  但是你必須知道你需要的是哪一類的不方便才行喔!

這讓我想起我的黑膠系統, 不方便的盤,  不方便的唱臂(沒有自動上下與舉臂停臂器), 要唱一張唱片要進行的儀式與過程以及要忍受的黑膠唱片的一些不完美很多, 這也許是現代用慣 CD, iPod, 甚至電腦音源的人所無法習慣的, 可是透過這些操作, 我似乎學到一點點道理, 也許就像是這住吉之長屋一樣, 不方便歸不方便, 它內在真正的好處還是要使用的人去體會才是. 雖然我自己做的東西不是頂極的東西, 多數頂極的東西在操作上面通常是需要下一點工夫的. 就像Stereo Sound裡描述的頂級音響一樣, 人是需要花以年為計算單位的時間去熟悉與操作, 才可以把器材的潛力帶出來的. 有一些東西, 為了達到終極功能的目的, 操作上的方便在設計時是可能被忽略或故意被忽略的.

DSC01872

DSC01871 

最後想到自己以前還是學生的時候, 那時的硬體與系統軟體工具都不方便, 所以要把一個硬體系統叫起來模擬需要一大堆前置步驟, 而每一個步驟之間的格式轉換多半要靠自己寫程式來弄, 因為沒有現成的人家寫好的code可以用, 所有的路徑, 目錄, script都要自己寫與管理. 所以還沒開始模擬就先花一個小時了. 不過因為這樣, 每一個步驟都清楚他在做什麼, 可是現在多的是人家編好的工具與寫好的script, 一旦叫不起來,  多數學生只能傻眼, 然後接下來就不知道怎麼辦了. 其實, 只要挖進去, 一步步了解他的步驟裡的所有動作以及去了解這些動作的意義, 一切就開朗了.

可惜的是, 當初我的訓練是一剛開始就從零開始, 所以這些步驟我很清楚, 現在的學生則是多半沒經過那樣子的訓練, 所以在解讀步驟時會不知道怎麼辦. 反過來說, 我自己就不知道那些script與伴隨那些script的那些工具的確實功能, 反之, 因為我自己沒寫過那樣子的script, 新的工具用新的語法或語言寫的, 而過去多半的工具是自己用很爛的程式寫的, 這也是因為我後來在這方面欠缺操作的原因. 不過終究script與工具如何寫在多數議題上是末節, 原理要是知道就容易解讀了. 以我的年紀以及目前與未來我所要做的工作內容, 如何寫出更好更方便的script與工具是不必要的就是了, 也就是我再也不需要去操作這類東西, 但是對於年輕學生來說, 這卻常常是他們在不遠的將來找工作與做研究時所需要的, 不了解這些我所謂的末節反而是不行的. 時代在變嘛! 無有辦法!

所以方便有時不見得是一件好事, 不方便也不見得是一件壞事, 反之亦然. 多數時候, 假如這是你該好好懂的東西, 當然不方便是有其必要性的. 至於你該讓哪些不方便的東西來訓練你產生操作的行為進而成為某方面的專家, 就只有你自己才知道的了.

關於這最後與最重要的一點, 安藤忠雄的住吉的長屋的例子可以給我們不少的啟發.

2009年12月23日 星期三

OpenSparc T2 in FPGA - 哲榮

------------------
2009 12 23 三
------------------
這禮拜把cygwin裝起來
然後執行yl學長說得指令sim xxx
可是沒有開啟modelsim

再加上我對sim這個script的內容不太瞭解
請aaa幫忙看之後,發現有文件!可以參考

目前正在看這份文件
想說先找出memory.hex如何產生的
然後直接放到之前的專案裡面一起跑
因為直接執行它的script還是需要nc-verilog或synopsys


------------------
2009 12 16 三
------------------
目的是希望能夠把Sparc t2燒入FPGA中
並接上TLM2.0的bus
將Sparc作為一個運算的component

目前下載OpenSparc的opensource
http://www.opensparc.net/opensparc-t2/download.html

短期目標希望先在pc上跑RTL simulation
然後在program rom裡面寫入一個簡單的loop program
能夠正常執行後接下來再把program更換為一個小型的os或者更小的管理程式
來處理sparc與周邊的資料傳輸

原本直接把t2的verilog code直接放到ModelSim上跑simulation
但是compile的時候會遇到dump.v裡面出現error:
(vlog-2155)Global declarations are illegal in Verilog 2001 syntax

後來看了一下dump.v裡面只是在做VCD和FSDB(fast signal database) dumpfile
加上file list裡面又沒有dump.v 所以直接把它拿掉xd
當初會放進去的原因是因為他跟top module t2.v放在同個資料夾,沒注意到他不在file list裡面

後來simulation過程中又出現了
**Warning:(vsim-7) Failed to open readmem file "memory0.hex" in read mode
#No such file or directory.(errno = ENOENT)

似乎是memory map file沒有讀到
但是搜尋下載的t2檔案裡面又找不到memory0.hex

後來問了一下aaa,還是決定在linux底下裝NC-Verilog 來跑simulation
因為readme file裡面有教怎麼在NC-Verilog上跑,照著作應該比較不會有問題


2009年11月25日 星期三

出國遊學玩樂感。kiki。

大家好 ,我是老人一枚-kiki~奉老師之命來po個出國遊學之感想!

出國前
一開始是想要去Working Holiday的,但是跟爸媽談過之後她們怕太危險怕很大,最後覺得遊學可以達到我的目的,也可以學一些東西~所以~就讓我年輕瘋狂一次吧!

雖然五月就出國了,不過我也是二月才開始Survey學校,一開始什麼都不知道,就從身邊有出國的朋友們下手,然後上ptt(沒有錯我是鄉民!)看相關資料,最後跑去代辦中心詢問,因為代辦實在有點貴,所以我就開始自己動手找學校啦!心裡想要的學校大概就是幾個方向,是大學附屬的(不想要只去一般學校~很像補習班)+交通方便,所以最後就找到了BU啦!在美麗的Boston,大家都說很棒的地方,所以就決定他了。附上很方便的網站 ~就是她讓我完成手續地!

出國了
學校課程是每天的早上9~1點,下午會有一些club可以參加,晚上做作業後,再去gym跑跑步就差不多晚上該睡覺了。每天規律的學生生活,超懷念的!而課程我選擇的是Business Class,個人覺得師資還不錯,會請starbucks之類的公司經理人來講課,很特別!課程只有三個月,咻一下就過去了,去遊學的孩子好像通常都會待個一年,只待三個月的真的不多。

我的室友是日本醫生正妹,在出國前就一直想要認識日本女生,結果非常lucky的就遇到啦 !我跟她踏遍了Boston的大街小巷,任何大大小小的活動都參加,學校的老師行政人員都因此認得我們,我們也因此認識了更多朋友。不過挺可惜的是,我去的時候剛好是暑假,所以沒有很多學生在學校,無法真的感受到她們的校園生活。

Boston是個很漂亮又有著方便地鐵的小城市,聽說是全美最多學校的城市,最高學府都在這裡,這裡的台灣圈很小,所以不小心就認識了高檔的MIT media lab的小妹妹,還有一群Harvard/MIT的高材生,每個人都懷抱著夢想,很閃亮!

課程結束之後,就開始了美國東岸趴趴走行程了。第一趟是跟著學校同學一起參加國內旅行團,去了Washington DC+Niagara Falls,這些景點太經典,但是開車又不方便,跟團便宜又免煩惱!結束後就開始到東岸的朋友家寄生啦!首推ya+0小朋友,他在NY念MBA唷,所以我就以他家為主,到處去玩耍啦!

第二趟是ya+0加上俊一的老婆一起的Orlando-Disney之旅,好像重回小時後時光耶!其中四天都泡在Disney裡,每天都看著唐老鴨米老鼠,連做夢都會夢到耶~哈哈。Orlando與Boston感覺差很多,飯店附近都很度假~南洋棕梠樹風,市區附近則很退休有錢風,好像每天都很悠閒。

第三趟是飛到北卡找我高中同學,他在Duke念博士,超級優秀的孩子,不過北卡真的就非常大自然風,我從飛機上看下去都是綠通通的樹一大片,我為了入境隨俗,所以這裡的行程都是參觀校園~Duke+UNC+NCSU~沒有城市的塵囂味,非常舒服,沒有什麼誘惑所以可以好好念書。

第四趟則是到NY State比較北邊的Binghamton,這裡跟Boston的緯度一樣,只是在內陸一點,所以比較冷一點,但是他的感覺反而跟北卡比較像,因為都是走大自然風,沒有車無法生存的地方,也因此我又去參觀了名校:Cornell+也叫做BU的Binghamton University!超漂亮的!空氣都是甜的呢!!

最後一個星期我就乖乖的待在NY遊蕩了,因為Ya+0開學加上有在打工,很可憐很辛苦,所以我就上ptt去找人一起遊NY啦!台灣人見面格外親切,可以有人幫你拍照,也有人陪你聊天,超讚地!就這樣我的旅行就在NY畫下句點啦。

出國後
這樣出國也出去了四個半月,英文學好當然是必要的,但是最重要的是認識了好多不同國家的朋友喔!最多的是日本韓國朋友~還有哈薩克~多明尼加~阿拉伯ㄚ之類等等的,超級大開眼界的,每個國家的風俗名情都不一樣,產石油的國家真的都有比較有錢XD。。。

現在就算回國了,還是很努力的跟朋友保持聯絡,有認識這麼多朋友真是太划算了!有夢想就去實現他!這真的是我這生最棒的旅程啊!

詳細行程記錄在我的blog啦~一開始寫得很認真,後來都縮在一起啦~哈哈。報告結束,謝謝大家收看落落長文。

2009年11月23日 星期一

Google Chrome OS


義崧、禹鴻、跟唯中這個週末撥空南下巡視 …喔不,是南下探視成大的鄉親們,周大師甚至不棄嫌的願意下塌在小弟家,工業區晚上很冷清野狗又多的,大師一來連我家狗狗都不會吠他。


在聊天聊到半夜四點(?)的話題中,唯中提到Google宣佈了他們打算出產自家OS的消息,並且有初步的概念,很快的我訂閱的blog中也有人提到此事,所以貼上來分享給大家知道一下。目前我找到的project是Chromium,官方也釋出了有趣的介紹影片。

由影片中的介紹我們可以了解,他們的OS透過Chorme流覽器來當作我們習慣的「桌面」,使用他們的OS一定要接上網路,所有的資料都會透過網路來存取及計算,可想而知這是他們發展雲端計算後的下一步。以後開發程式可能不再是用C, C++,而是HTML5, CSS3, JavaScript …。

Who knows ?

2009年11月13日 星期五

Leon3, an OpenCore SoC system

Hello Everybody,

Long time no see... :)

I find that I'm losing to follow what everybody did since the blog are not up-to-date. However, I'd give a brief introduction of the SoC system adopted here. I especially highlight its debugging utility, being treated as a reference of 8051 project.

The SoC system is provided by AreoFlex. It consists of IP cores, OSs, compilers, debugger and simulators. Most are open-source following GPL licensing and some are commercial. The Leon3 is the processor core using the SPARC V8 architecture. The SoC system contains AMBA bus with plug&play functionality, so modules connect to the bus. Essential IPs are built in the package, as shown in the figure below. This system doesn't bound to any boards or processes. It means you can use it on whether Xilinx/altera FPGA and ASIC design. However, they collect various FPGA boards and fit the SoC system on them, including the peripherals on the board. A tool to configure the IPs is included. It helps you to construct the system you want, even without modifying any codes. You also can build multi-core system by configuring.

After configuring, synthesizing, and programming onto FPGA, you can execute program on the LEON3 processor. The GrMon is provided as a debugger. It can obtain the information from processors and other AHB slave by using the debug link module, which is a AHB master, as shown above. However, to access the registers in the processor, an additional debug support unit (DSU) is designed. The DSU is a separate AHB slave module, accessing the processor only when the processor is in debug mode. Once the GrMon tends to access the status of processor, its corresponding debug link module will signal the DSU. The DSU will enforce the processor to enter debug mode and halt, so that DSU can work. A DSU can cope with up to 16 processors.
As mentioned above, the SoC system has no limitation to FPGA boards, so their debugging environment is adaptable by providing various debug link modules. For example, it supports Xilinx standard USB-JTAG download cable for debugging. Some may question if there is no interface for the existing debug link. Don't worry. If you can connect your FPGA board with PC, all you need to do are to design your own debug link master module connecting to PC with interface on the board and to enable GRMon control your hardware module by implementing a set of pre-defined callback functions being invoked by GRMon. This makes it possible to build the system on the existing FPGA boards in our lab. :p
Moreover, the GRMon is an Eclipse plug-in and can attach with GDB for debugging. More information here.

Okay, that's it!

 

2009年10月29日 星期四

Cell Programming Tool - ㄚ凡

====================== 09.10.29 ======================

現在傳值的部分OK了
就是PPE裡給他一個array
讓它經過各個SPE運算
最後傳回PPE做輸出
現在開始寫API的說明跟整個tool的介紹
還要把codegen改好

====================== 09.10.15 ======================

目前
「PPE傳給SPE一個陣列
然後陣列在SPE之間計算傳遞
最後再傳回給PPE輸出」
已經OK了

之前因為系統只回傳一個 SPE_RUNTIME_EXCEPTION
只能一行一行註解來找 到底問題在哪
後來發現是在SPE收到PPE傳來的東西後
要更新read address時出的問題

因為大家的address丟來丟去
有時候是Local Storage的位址
有時候是effective address
沒轉換好 記憶體就會有問題

現在PPE可以傳東西給SPE
可是因為無法更新read address 所以只能傳一次
只要找出來read address是在哪裡算錯 就能解決了

接下來看Queue的相關函式能不能合併一下
測試一下大一點的陣列傳遞
就能根據這些程式碼來改codegen了

====================== 09.09.16 ======================

先說一下Double Buffer
學長提到的non-blocking DMA
是不是要問這兩個spe之間的同步機制

對每2個frame來說
spe1 :
    wait_dma_complete(TAG10);
        <IMC的動作>
    FE_enqueue(&MyFrame, TAG10, &P_PPE);
    OutputSel = (++nFrameCount)&0x1;
        <PB的動作>

spe2 :
        <PB的動作>
    OutputSel = (++nFrameCount)&0x1;
    wait_dma_complete(TAG10);
        <IMC的動作>
    FE_enqueue(&MyFrame, TAG10, &P_PPE);

利用 wait_dma_complete(TAG10); 這個函式
來作waiting,直到上一筆傳輸確定做完

在呼叫 FE_enqueue(&MyFrame, TAG10, &P_PPE);
將這一個frame的運算結果傳回PPE時
不用等到傳輸結束
就可以先開始進行
下一個frame的PB運算

--

上禮拜說要寫個例子
因為還沒寫完 所以這禮拜也沒辦法報

====================== 09.09.08 ======================


目前Queue SPE->PPE的function改好了 也測試過了
Queue PPE->SPE的部分寫出來了 可是還沒測過
接下來想寫一個簡單的例子
把資料從PPE傳進SPE 算完後傳回PPE 輸出
等到這部分完成後 再來改codgen的部分

下面來個示意圖 說明一下不同Queue的初始化
方形的框是SPE
SPE旁邊長的兩個小框 上面是in_mbox 下面是out_mbox
圓的是PPE
然後箭頭則是初始化的步驟 (綠色是consumer 紅色是producer)
1. Consumer送 queue address
2. Producer拿 queue address
3. Producer送 read address
4. Consumer拿 read address


由上而下分別表示SPE->SPE、SPE->PPE、PPE->SPE
三種初始化傳位址方式
(這邊寫得比較簡化 實際上queue address是放在MAIL MESSAGE中
再把MAIL address 傳到producer那邊
而read address就直接傳給consumer 不透過MAIL MESSAGE)

====================== 09.09.01 ======================

Queue的重點主要在初始化的部分
需要經過4個步驟
1. Consumer送 queue address
2. Producer拿 queue address
3. Producer送 read address
4. Consumer拿 read address

目前spe之間的queue初始化
都是把address寫入對方spe的in_mbox
而ppe與spe之間的queue初始化所需的溝通
則是利用spe的in_mbox與out_mbox來完成

這邊舉例說明一下
假設spe1為producer spe2為consumer
spe2要將queue address 傳給spe1 :
首先spe2把要傳的queue address放進MAIL (傳遞用的資料型態)
再把MAIL address用mfc_put放入spe1的in_mbox中
接著spe1從自己的in_mbox中讀出MAIL address
再用mfc_get從這個位址取得MAIL
再從MAIL裡拿出queue address

只是PPE在扮演producer或consumer時
照這樣寫 又得多出8個類似的function
我想把它們盡量簡化 不然queue的初始化會非常複雜

接下來是資料的input
目前input是在module裡
也就是data flow中第一個執行的module若是VLD
就在VLD的function裡 取得bitstream
只有在運算完成 在data flow中最後一個module
負責把output送回ppe 由ppe來播放
這樣的流程不知道需不需要更動

另外 在學長的code中 spe1與spe2有使用double buffer
由這兩個spe輪流作輸出
我還看不太懂為什麼這樣實作
不過 我們的tool裡應該不用實作這部分吧

====================== 09.08.18 ======================

關於學長的程式
整個結構跟流程懂了
至於每個部分的實作細節
(由xml經過schedular來決定每個spe要放哪些module)
現在是有概念 但沒有說每一行都仔細看過
大致上是不需要改動的
不過學長當時有跟我說一些小地方 還有討論的空間
(都在schedular裡)
這些地方需不需要修改 等我codegen改的差不多了再決定

Queue的使用也知道了
實作上還有點看不懂 為什麼要這樣做
(會這樣寫一定有特定的理由 我還得再想想)
在queue的初始化部分
看懂了 可是覺得有點不直觀 可能會稍作修改

另外 因為是要open給人家用的
所以產生的程式碼必須加一些註解
至少讓使用者知道每一段程式碼分別在作什麼

queue的實作部分目前只有spe之間
接下來得寫出ppe用的版本
(memory access的function不同)

====================== 09.07.29 ======================

昨天請教學長之後知道

要透過schdular來安排資料在spe之間的流向
所以我們可以幫使用者做好資料傳輸的部分
使用者只需要填入他所要傳的資料當參數即可

所要產生的程式碼包含 :
ppe用的程式碼,負責初始化spe及餵資料
最後的輸出動作等
spe用的程式碼,由於我們已經知道資料的流向,使用者只須負責每個module內部的運算部分

至於傳輸資料的實作部分,我還有一些問題需要釐清,待明天跟學長討論之後再上來說

====================== 09.07.28 ======================

這篇討論串的目的是希望能開發一個generalize的tool
以便使用者在Cell上開發自己的程式

本來希望能將之前的圖形介面改寫成更一般化
能藉由拉進一個個module
再指定module之間要使用的傳輸方式
產生code 使用者只需要自己補完程式中運算的部分
ppe與spe、spe與spe之間的傳輸由我們的tool來產生

不過 之前的GUI是針對schedular設計
只需要指定module間的資料流向
程式碼的產生由schedular負責

而現在我們所要產生的code不包含程式的運算部分
也就是module要在何時將資料送到下一個module
而且傳多大的資料 我們並不知道
只能提供一個預先定義好的function 供使用者傳輸資料用
這麼做的話
我們似乎就不需要去考慮使用者有幾個module
以及這幾個module之間的資料流向
我們能提供的只有ppe及spe的程式碼範本
以及一個可簡單使用的傳輸資料function

之前師公所寫的codegen已可產生所需的程式碼
至於傳輸資料的function 我想使用之前學長寫的queue
稍加包裝應該就能供一般使用者用了
而要怎麼加入GUI 怎麼讓使用者能簡單的開發自己的程式
我還要在跟老師討論一下

2009年10月20日 星期二

GDB for 8051 - 品皓

======================11/25=======================

meeting投影片

延續上禮拜做的給做完。之前的loop因為寫得太單調了所以感覺沒用到幾個branch instruction,改的複雜一點就可以看出差別:
Function call -> LJMP, RET
while loop -> SJMP, CJNE
For loop -> SJMP, JNC
If-else -> JZ, JNZ
但仍然有少數的branch instruction我試不出來。最後沒辦法只好寫inline assembly自己測試:
ACALL, AJMP, LCALL, DJNZ, JB, JNB, JBC

======================11/18=======================
實作decoder加入判斷branch目標位子的功能。測試程式我是寫了簡單的while loop, for loop, 和function call來測試,但是看了對應的assembly code發現有些branch指令還是沒測到。之後會直接inline assembly繼續測試。

======================11/10=======================
寫了一個簡的測試程式,把每一行C code設breakpoint測試,都有停下來。同理用next step一步步執行也都有停到預期的program address;除了branch instruction。

因為只能根據目前的instruction長度判斷下一個instruction的位子來設定breakpoint,如果停下的點是branch instruction,則設定的breakpoint位子可能是執行不到的。譬如無限迴圈while(1);在assembly code就只是sjmp當下位子,我breakpoint則會設定到迴圈之外。

簡決方法是單步執行的decoder還必須能判斷branch的位子。

======================11/04=======================
原本Breakpoint的指令是用timer達成,現在已經改成學長的建議用software interrupt: SETB TF0。

上禮拜關於GDB的單步執行(next)會卡死的原因,發現單步執行所給予的breakpoint位子不可能走的到,我判斷是GDB端的問題。GDB處理signal step的地方當初是直接延用bbb的risc32,也就是判斷下一個instruction的位子是目前PC直接+4,所以才會造成GDB會產生一個不可能走到的breakpoint。又因為8051是CISC,下一個instruction的位子等於目前PC值加上目前instruction的長度,所以加上一個簡單的decoder判斷目前instruction的長度。

目前build GDB失敗......

======================10/28=======================

主要是實作8051 stub處理breakpoint的問題。8051 stub接到breakpoint指令後,啟動timer0 interrupt。利用timer interrupt每執行一個instruction都進handle_exception()檢查目前PC值和之前設定的breakpoint是否相同。
不同則表示還沒到breakpoint,return。
相同則表示已經走到breakpoint,進入無限迴圈等待GDB的指令。

目前測試看來是成功的,不過奇怪的是GDB的單步執行(next)會卡死,懷疑可能是GDB端給的program memory address有誤,目前還在debug。
======================10/21=======================

處理breakpoint之前,我想先完成單步執行的功能,因為breakpoint可以利用單步執行,每執行一instruction就比對一次目前的PC值是否和breakpoint table裡任一數值相吻合。

另一方面,GDB的單步執行(next)也差不多是如此;GDB的繼續指行(continue)就是跳出handle_exception繼續執行直到遇到breakpoint後又進去handle_exception。GDB的單步執行(next)則是根據symbol table知道下一步instruction的位子,設定breakpoint在那位子後,繼續執行(continue)。

處理單步執行我是用timer0 interrupt,簡單的驗證方式是觀察每一步的PC差距,更進一步應該是要比對binary code的instruction。還沒完成是因為遇到bug,應該只是個小錯誤,還在debug中。======================10/16=======================
我試著插入breakpoint於測試程式中,觀察設定breakpoint後GDB傳給8051 stub的program memory address內容有誤。直到觀察assembly code才發現某些C code沒有對應的assembly code。

因為我的測試程式寫得太簡單,裡面一些簡單的變數運算可能sdcc判斷為無用。更進一步去觀察測試程式所設定的變數,變數設定太簡單,sdcc會直接定為某個register,而不是給予一個記憶體位子。這樣會間接導致那些變數編譯完後也不存在於symbol table中。

後來變數加入volatile的設定而解決,主要目的是程式對volatile的變數作存取時必須直接到他的位子作讀寫而不是經過暫存器或者cache之類的。這樣的設定也會強制sdcc必須安排volatile的變數一個記憶體位子,而不是定為某個register。

======================10/08=======================
paper投影片

BEE2 是由四個user FPGA和一個control FPGA組成,根據FPGA提供的功能如I/O pins和其要求如供電壓等作設計,最後加上其他周邊硬體如usb, rs232等完成整個平台。
平台裡每個FPGA都加入PowerPC的架構並在control FPGA執行Linux,主要用於控制周邊硬體,監控等。
======================10/06=======================

常常會忘記自己做的東西是很底層的,很多是事情其實直接用inline asm解決即可;也有很多問題是必須trace assembly code才會知道錯誤在哪。

上禮拜是驗證8051 stub回傳的PC是否正確,這禮拜是驗證其他registers(r0-r7 sp)。
驗證方法很簡單,在進入function handle_exception()之前用inline asm隨意指定r0-r7的數值,之後觀察8051 stub回傳的r0-r7和之前指定的數值是否一致。

接下來是之前提到的,回傳的memory數值不正確。
原因是為了8051 stub回傳registers方便,我宣告一些全域變數用來儲存registers的參數;並為了inline asm撰寫方便,宣告時也指定那些全域變數的位子。我本來以為compiler會處理其他(如區域變數)的位子並避開前面我指定位子的全域變數,結果並不會。簡單的判斷方法就是宣告幾個同位子的變數看compiler是否有warning或error。我之所以認為compiler會處理這問題是因為Keil C51就會在變數位子的宣告有重疊時會產生warning,但是我目前用的SDCC卻不會。這問題就會影響到8051 stub回傳memory數值的錯誤,我用以下範例說明。

reg_PC一變數是我宣告用來儲存中斷點的位子,也就是handle_exception function return的位子。所以一開始8051 stub與GDB連線時,stub會進入handle_exception function並回傳所有registers的數值,其中包含PC值,所以在這一點我是直接回傳reg_PC的數值,也是上禮拜用來確定回傳的PC值是否正確的依據。

但是reg_PC也是一個變數可以在symbol table找到,所以可以用指令display reg_PC調出他的數值。用display指令和之前回傳register的方式不太一樣,前者是回傳目標記憶體位子的數值;後者則是直接回傳指定變數的數值。之前會回傳錯誤資訊的原因是因為handle_exception function的區域變數會覆蓋到reg_PC的位子。解決方式就是不要指定位子,全部給compiler分配就好了。

======================9/29========================

8051 stub方面,有個問題是不知道怎麼在C程式裡得到processor暫存器(pc,sp,r0-r7)的資料,後來直接寫inline assembly code來解決。首先宣告一個固定位值的變數如: data unsigned char at 0x20 reg_temp[8],表示變數reg_temp陣列在iram裡的0x20-0x27位子,接著用inline asm 如: mov 0x20, r0 的方式把r0-r7的資料存到reg_temp陣列裡,最後reg_temp就保存了r0-r7的資料了。pc也是用類似的方法,只是inline asm 是用pop push得到進入handle_exception function前的pc值。(handle_exception是stub裡的function,主要是收送GDB端讀寫的封包,一般在程式走到breakpoint會進入的function)

目前我只能驗證stub回傳的pc值是正確的,假設handle_exception function的進入點是在main function裡,可以從symbol table得知main function的起始位子,簡單的計算就可得知stub回傳的pc是否正確了。

接下來的問題是回傳的memory數值不正確,不過應該只是stub哪裡寫錯了,詳細情形我還在找原因。

GDB方面,之前有提到說把register的數值列印出來的指令會導致GDB當掉,原因是出在我GDB裡的TARGET-tdep.c裡對於每個register的宣告上(function enum gdb_regnum)我設定9個register,然而在(function TARGET_analyze_control_transfer)裡分析register裡,也就是switch case裡我少設定一個register,導致找不到那缺少的register case而在default case裡回傳error message的動作。改完後就可以正常的列印出暫存器數值了。

======================8/30========================


debugging stub透過COM port與GDB溝通的方式為RSP(Remote Serial Protocol),其封包格式很簡單: $ddd...#hh。 '$' 是封包的開頭,'ddd...'是十六進位資料且並無限定長度,'#'表示結尾,'hh'為十六進位的兩個checksum。

GDB遠端連線建立好後,會先送出"qSupport",stub收到後回傳"T05"表示停下來的原因是breakpoint,接著stub回傳所有register的資料。以上資訊傳輸完後,GDB就會列印出目前的位值和等待使用者的指令,stub也是在一個無線迴圈內等待GDB的封包。

我目前的遇到的問題是,連線建立後,輸入指令如列印出某暫存器的數值後GDB會死當,根據找的文件是說這可能是BFD那邊的問題,也就是symbol table的問題,真正問題的原因我還在尋找。

至於上個禮拜關於debugging stub回傳暫存器的數值有誤的問題,本來以為燒錄器的問題: 因為同一個程式燒入兩次卻有不同的結果。但是後來請aaa幫忙修理才知道燒錄器沒問題,是晶片at89c51燒壞了。

======================8/24========================

GDB for 8051我想粗分成以下幾個階段:
1. GDB透過COM port能與8051硬體相連,傳輸最基本的功能就是讀寫registers和memory。
2. GDB端的symbol table
3. 支援breakpoint

我目前還在第一階段,想說先架起最基本功能的debugger,可以根據兩端傳輸的資料看出我哪一端有修改錯誤。GDB端要做修改的地方應該比較簡單,主要是修改TARGET-tdep.c和TARGET-dis.c對暫存器的宣告(TARGET=8051)讓GDB認得TARGET的架構;8051硬體端,也就是debugging stub,負責與GDB做溝通,目前最基本的功能就是讀寫暫存器和記憶體。

測試程式方面我是用SDCC (small device c compiler)編譯,產生binary執行檔格式為Intel Hex format。GDB認得這格式為executable file,但是卻會顯示找不到symbol table,因為裡面純粹是程式的資料。不過少了symbol table,GDB應該還是可以讀寫暫存器和記憶體。
目前是卡在debugging stub回傳暫存器的數值有誤,我還在尋找出錯的原因。

第二階段是關於GDB需要的symbol table方面。SDCC編譯C程式可以產生8051的執行檔(Intel Hex Format)和symbol table(CDB format),主要是用於SDCC提供的8051模擬器SDCDB。麻煩的是GDB不支援CDB格式的symbol table,我目前也找不到工具可以將CDB轉成GDB已知的格式如ELF或者COFF等。

GDB認得symbol table的格式定義在BFD,修改BFD讓GDB可以看的懂CDB格式的symbol table,
這應該會是我第二階段要做的。

最後支援breakpoint階段我想等前面的問題釐清後再討論。

======================8/11========================

這是我在meeting時報的paper: Functional Simulation Using Sim-nML
由於時間比較緊迫,我並沒有仔細讀完全部的,上台報告的像是Sim-nML教學。
paper大略的內容是利用Sim-nML語法模擬出一個processor model,作者的Functional Simulator Generator可以parse此model成一個c++的class,並產生一個屬於此processor的simulator。

這simulator可以執行模擬的processor的執行檔,且利用GDB作為介面,remote control這個simulator。

投影片
論文


在meeting的時候提出的討論:
1. (pg. 6) SystemC is targeted more toward system level modeling rather than processor modeling.
對這句話有疑問,systemC不一定就是要用system level來描寫。
2. (pg. 25)—Methods for handling traps and other synchronized events
是指關於interrupt時processor處理的行為,白算盤裡有詳細的解釋。
3. 關於Sim-nML,是有compiler等工具支援,發展至少有十年歷史。

2009年10月15日 星期四

MPEG-4 code SIMD 化 -- 雙魚

=========== 2009.10.15===========

還是拿原本的code來改 , 主要把第一次改的換種方法
以及 找了第二個可以改成SIMD的部分

(1) 第一部分的別種方法:

->本來的方法是圖的上半部 , vector先裝入IDCT_Coeffo [0~3]的數值
讓IDCT_Coeffo 和 V0 相乘結果先暫存在 temp
再把暫存在 temp中的四個數值相加後放進去R0[i]
R0[i] = temp[0] + temp[1] + temp[2] + temp[3] ;
老師有提過 這邊一堆+ 可能會影響速度 , 所以換種方法


-> 後來的方法是圖的下半部 , 先把 IDCT_Coeffo 陣列轉置
轉置的結果IDCT_Coeffo 陣列順序變成 0 4 8 12 ......
讓vector先裝入IDCT_Coeffo [0 4 8 12] 的數值 再和V0相乘
相乘的結果就可以直接放入R0[0~3] 中

下次vector則裝入IDCT_Coeffo [1 5 9 13] 的數值 再和V0相乘
相乘的結果直接和上一次的R0[0~3] 累加 , 使用vec_madd()去累加


(2) 第二部分的改寫 原始code如下 :

for(i = 0; i <= 7; i++) { k = i& 3 ; if(i & 4) { k ^= 3; temp0 = R0[k] - R1[k]; .... } else { temp0 = R0[k] + R1[k]; ... } .....(略) } -> 觀察一下原本的內容 , 發現迴圈跑8次要做的事情就是產生
R0[0] + R1[0] ,R0[1] + R1[1] ,R0[2] + R1[2] ,R0[3] + R1[3] ,
R0[3] - R1[3] ,R0[2] - R1[2] ,R0[1] - R1[1] ,R0[0] - R1[0]

-> R0 R1在迴圈之前已經計算好 , 迴圈裡面只要他們之間相加減的數值
於是想說新開一個長度8的一維陣列 , 直接把相加減的數值給放好
如此一來 迴圈裡面的這個部份就可以抽掉

R0[k]+R1[k] / R0[k]-R0[k] 可用SIMD提供的 add / sub函式來完成計算
R0[k]-R0[k] 放入btmp[8]的順序如圖 , 從k=3放回來
計算時的vector是從k=0~3裝入 , 相減的結果要先交換位置才能放入btmp


(3) 數據結果 程式跑10000次 :

1. 原始程式在PPE環境下: 1.48 sec
改寫的程式在PPE環境下: 1.15 sec

2. 原始程式在SPE環境下: 1.28 sec
改寫的程式在SPE環境下: 0.48 sec

-> PPE和SPE都是一樣的程式 , 只是使用的函式不同
因為兩個環境支援的函式名稱是不一樣的 , 但是數據差距有點大
PPE只比原本的少了0.3 , 但SPE少了快三倍

我有請小新學長看一下程式 , 應該沒漏掉或放錯迴圈次數
我們兩個對於PPE為什麼只少0.3 都感到很奇怪

=========== 2009.10.8 ===========

整理了在PPE和SPE下寫的兩個範例
一個是4*4矩陣 , 另一個陣列比大小
範例的寫法也有附上解釋
會和大鈞學長討論哪裡還需要做修改



=========== 2009.09.24 ===========

SIMD程式分為使用VMX指令的PPE和使用SPU SIMD指令的SPE
當初會想用PPE是因為不知道怎樣把SPE裡面的時間傳出來
後來可以把測的時間傳出來 , 於是可以去測SPE提供的指令時間

下午報告的數據 因為迴圈次數給錯 , 導致vec_madd()的時間會較慢
所以我把數據重測了一次 , 結果如下:

(1) 一維陣列相乘


(2) 4*4矩陣相乘


從(1)(2)數據看來 , PPE的vec_madd()函式會比原本節省大約3倍
SPE的spu_mul()函式會比原本節省大約4倍

因為兩種函式都有大幅度的降低時間 , 但是改寫的code效果沒有很好
可能要更改原本程式 , 讓原本的程式能比較適合用在SIMD上


=========== 2009.09.16 ===========

把改寫成SIMD的部分下去測時間 , 時間比較如下:


會發現改寫成SIMD的程式時間 比原本的程式還慢
主要改寫後的程式如下:
原本 : R0[i] += IDCT_Coeff0[k+0] * V0[i];
SIMD : tmp[q] = vec_madd( id_c0[i] , v0[q] , vzero );
R0[i] = Tmp[i] + Tmp[i+1] + Tmp[i+2] + Tmp[i+3] ;

-> 做法是 , 一次讓IDCT_Coeff0[k+0] * V0[i] 的計算做完
把數值存在tmp陣列裡面 , 接著把陣列數值相加再給R0

老師提到 , 把數值給R0[i]用到很多個+ , 可能是這邊導致速度變慢
因為之前沒有實際測過 SIMD支援的函式 是否真的有加速功能
這個禮拜會寫簡單的例子去測時間 .
小新學長說先寫簡單的一維陣列相乘 , 確定SIMD的函式是否有加快
如果有加快 , 再寫矩陣相乘的範例 , 然後去測時間


=========== 2009.08.31 ===========

原本cpp檔需要傳入的參數有7個 , 參照小新學長的意見
除了Mode不是等於0 就是 1 , 其他6個都當成64的一維陣列
這7個參數直接在cpp檔設定 , 一維陣列的數值先隨意給 , 設定如下:
int Mode=0 ;
int BlockLT[64] __attribute__((aligned(16)));
int BlockRT[64] __attribute__((aligned(16)));
int BlockLB[64] __attribute__((aligned(16)));
int BlockRB[64] __attribute__((aligned(16)));
int BlockU[64] __attribute__((aligned(16)));
int BlockV[64] __attribute__((aligned(16)));


在compile時遇到幾個問題或錯誤:
(1) compile時指令的改變
之前寫的範例都是 .c檔 , 這次則是 .cpp檔
所以把指令中的 " gcc " 換成 " g++ " , 這樣就可以了

(2) spu_mul()的語法錯誤
一開始是寫 tmp = spu_mul( id_c0[k], v0) ;
tmp 和 v0這兩個vector所乘載的陣列大小只有4
剛好vector一次就是裝四個 , 以為這樣可以 , 但是compile會有錯誤
後來改成 tmp[q] = spu_mul( id_c0[k] , v0[q] ) ; 變數 q=0
雖然 tmp 和 v0大小只有4 , 但還是要告知vector的起始點

另外 要使用spu_mul() , vector宣告的型態要為float
原本程式V0型態為 int
所以寫成 __vector int *v0 = (__vector int *) V0 ;
compile時會顯示錯誤 , 上網找資料看到都是用float
改成 __vector float *v0 = (__vector float *) V0 ;
這樣執行起來就不會出現錯誤了

測試方面使用SPU SIMD指令的方式
寫了PPE+SPE , SPE裡面就放cpp檔內容
打入compile需要的指令 , 目前不會出現錯誤
但是SPE裡面不能用printf , 這樣無法看到算出來的數字對不對

想說把要印的數值傳到PPE裡 , 執行後印出的數字都是0
可能是要印出的數值沒有傳好 , 或者是數值上有算錯
這邊會想辦法去解決


=========== 2009.08.24 ===========

參考aaa學長提出的兩個方法 , 覺得第二種方法比較簡單
利用這種方法 , 程式碼中原本 d0~d11的變數就可以拿掉
但是第二種方法的問題出在下圖這段程式碼

R0[i] += IDCT_Coeff0[k+0] * V0[0];
R0[i] += IDCT_Coeff0[k+1] * V0[1];
R0[i] += IDCT_Coeff0[k+2] * V0[2];
R0[i] += IDCT_Coeff0[k+3] * V0[3];

--> 這等於把 IDCT_Coeff0陣列和V0陣列相乘的數值都放在R0[i]
SIMD語法中好像沒有這種計算的函式 , 所以不能直接這樣寫


所以把程式碼改寫 如下:

Tmp[i] = IDCT_Coeff0[k+0] * V0[0];
Tmp[i+1] = IDCT_Coeff0[k+1] * V0[1];
Tmp[i+2] = IDCT_Coeff0[k+2] * V0[2];
Tmp[i+3] = IDCT_Coeff0[k+3] * V0[3];

R0[i] = Tmp[i] + Tmp[i+1] + Tmp[i+2] + Tmp[i+3] ;

--> 新開一個tmp[4]陣列,用來暫存 IDCT_Coeff0和V0相乘的數值
把 tmp陣列中四個數值相加後 , 再放回R0[i]
這樣一來 IDCT_Coeff0陣列和V0陣列相乘 的部分就可以一次作

測試的方法: 幫 原本的cpp 和 SIMD化的cpp 各寫PPE+SPE
然後給入一樣的參數數值 , 再去看兩者時間的差別有多少
目前在寫這兩個的PPE+SPE , 但傳入的參數還弄不清楚
所以還無法把程式跑起來



=========== 2009.08.12 ===========


從bbb學長給的mpeg-4檔案中 , 找出要做SIMD的檔案
主要就是改 MacroBlock_DCT_IDCT.cpp
下圖是目前要改成SIMD的地方


(1) 上圖第一個框框的部分, 希望可以用vector去裝變數d0~d11
這樣一次就可以assign 四個變數


(2) 同一個迴圈內, A0=B0+C0 , A1=B1+C1, ..... 這種計算可以改寫
但是 A0=B0+C0 , A1=D1+C1 , A2=B0+C3 ,... 這種不行
所以我把第二個框框的迴圈內容想成下面這樣

希望藉著此種想法 , 讓迴圈內的程式可以改成SIMD化

2009年10月12日 星期一

Special Topic on ESL and Multi-core Tool Design

Syllabus

1. SystemC Simulation Kernel
2. Advanced OpenESL tool development
3. TLM2.X
4. ARM Processor ESL Model
5. Multi-core Virtual Model
6. Multi-core Programming on Virtual Model
7. Multi-core application programming using CUDA
8. Debugging tool for microprocessors

09/23 - 10/07

大鈞陳大鈞_投影片.rar
阿凡EM_for_GMM_on_CUDA.ppt
宗胤8051 SystemC Model.pptx
8051 ISS Implement in SystemC.pptx
品皓gdb_for_8051_品皓.ppt
塞公Memory Locality Exploitation Strategies for FFT on the CUDA Architecture.pptx
rurusystemC kernel.pptx
小聽Course_進度_090923.pptx
Course_進度_090930.pptx
Course_進度_091007.pptx
龍哥Arm9 Cpu.pptx

2009年10月3日 星期六

C++ 中 struct 與 class keywords 的差異

C++ 中允許使用者在宣告(declare)、定義(define)型別時,使用 struct, class 兩個不同的關鍵字(keyword)。由於兩種都可以,因此很容易讓人好奇兩者是否存在必要性的差異。

在宣告時,使用 struct 或 class 都可以告訴 compiler 這是一個新的自訂型別,但在定義(define)時則有差異,根據最新 C++ standard
的描述, class 和 struct 對於 class definition 的差別在於:
1. 對於 member 的 default access level 不同(std.11);
2. 對於 base class 的default access level 不同(std.11.2)。

其不同在於 struct 是寬鬆的,都以 public 為預設。

上面的敘述很簡單,會引發一些聯想、甚至遐想:

Q1: 所以也可以使用 struct 寫多重繼承?多形?實現建構/解構子概念? 或者實作interface?就算可以,那為何會有class的產生?它不正是為了延伸structure的概念,達到更方便的OOP設計嗎?class 跟 struct 是可以互相繼承的嗎?
A1: 是的,可以。

Q2: 如果 Q1 的程式存成 .c ,可以compile過嗎?
A2: 沒辦法,C 語言不支援

Q3: 剛提到的差異是 class definition 上的,至於其他地方有差異嗎?
A3: 有的,像是 template 的 parameter list 只允許 class, typename ,無法使用 struct,因為 template 的設計,一開始就沒有打算和 C 相容。

Q4: 扣除些微差異,class 和 struct 幾乎是一樣的東西,為什麼 C++ 會同時引入兩個 keywords 呢?
A3: C++ 原本叫做: C with Class 。它的重要理念之一是與 C 相容,不過確實也是有不相容的地方,C++ Standard 的附錄 C 就列舉了 C++ 與 C 不相容的部份。因此為了這相容性,不可能將 struct keyword 拿掉,引入 class 這個新的 keyword ,它所帶來的不只是 parser 要多 parse 一個字,更重要的是其背後的抽象性、封裝性以及滿足人們對於 OO 的期待心理。而且以 Google 上"C++ struct class?"的搜尋,會先冒出一堆兩者的差異、比較的網頁就知道,class 的確辦到了"混淆視聽"的效果 : )

Q5: 都聽你在講,有沒有權威一點的說法啊?
A5:  Stanley Lippman 的著作: Inside The C++ Object Model,裡頭有一個章節叫做:Keywords, Schmeewords;開頭就是這樣說的:

One answer to the question of when, if ever, you should use a struct declaration rather than a class declaration then, is whenever it makes one feel better.

是的,重點在於 struct, class 定義出的 attributes, member functions 是否能符合你的需求期望。兩者的差異在於主觀的感覺: struct 用在 data aggregation,class 用在 Object oriented 或 object based 上。

Q6: 那為什麼不在 C++ 內限制 struct 只能宣告一般 aggregation type,不能有 access level 、member function 等能力呢?
A6: 其實原因很簡單:只是為了 C 到 C++ 遷移順利。 C++ 草創之初,除了效能是個大家關注的議題之外,什麼時候使用 struct 取代 class 也是常被問起的問題,與其涇渭分明的兩套標準,不如以一貫之,Bjarnet Stroustup 在 The Design and Evolution of C++ 這樣講著:

Maybe we could have lived with two set of rules, but a single concept provides a smoother integration of features and simpler implementation.尤其重要的是,嚴格區分兩者可能使得社群分裂(原文: community would fall into two distinct camps that would soon stop communicating.)

ㄜ,除了上面講的顏色對不對外,你覺得下面的 code 該編譯過還是不過呢?
// Forward Declaration
struct MyClass;
// Definition
class MyClass {
...
};
這應該是一致性問題,還是我們得一定要 compiler 嚴守 langauage 規範,幫我們挑出來呢? (以上很哲學又考古! )

Q7: 那我可以說 struct 原本要被幹掉嗎?
A7: 不算是要被幹掉,因為一開始就打算與 C 相容,所以不會幹掉,考量是:
1. 要不要引入新的 keywrod -- class
2. 引入 class 後,是否要讓 struct 與 class 不相容,使用兩套 rules。
而後的決定是:引入 class ,class 和 struct 使用同一套 rules (只差別在 default accessibility),而事實也證明 class 帶來令人滿意的效果,不管是心理的、實務上的。心理的上的話,套句 Lippman 的話:你會講 base class 還是 base struct ,雖然只是小小的哲學問題,卻還是得到滿足。

Q8: 我搞混了,那到底什麼時候該用 struct 、什麼時候該用 class?
A8: 我想 C++ 期望使用者自決。但我想可以分成兩個層面來看。先說心理層面:這是個 makes one feel better 的問題。
xxx MyClass {
public:
    void func();
private:
    int val_;
};
xxx 是 class or struct 都好,因為實際描述 MyClass 行為的是 class body 中的程式碼,而不是 struct 或 class。
另一個層面則比較實務:我想要 struct 或 class 定義出來的型別,其所產生的 object 與 C 是真正相容的,那就得考慮到 C++ 的 object model 和相關運算,簡單來說:要在 C++ 產生跟 C 相容的 object ,你的 C++ 型別必須是個 POD (Plain Old Data),standard 對於 POD 有其定義(std.9),或是上 Google 搜尋都可以看到,偷偷引用 wiki 的描述:
A POD type is a C++ type that has an equivalent in C, and that uses the same rules as C uses for
1. initialization
2. copying
3. layout
4. addressing
對我自己來說,什麼時候會使用 struct:
1. 想產生與 C 相容的 object 時,我會使用 struct 這個關鍵字,因為它帶有我對 C 的遐想,然後嚴格遵守 standard 對 POD 的規範。
2. 某些型別描述的對象很簡單(不太有(甚至沒有)繼承架構、抽象介面、生命週期短等),使用 setter, getter 又很麻煩時,那我會選使用 struct ,像是:
struct ParserResult {
bool Match;
int lineNo;
};
每個人都可以有自己一套結論!

Q8: 我試過了你這篇文章上弔詭(Paradox)的code:
struct MyClass;
class MyClass {};
/*
*warning C4099: 'MyClass' : type name first seen using 'struct' now  seen using 'class'
*
*是的,可以通過編譯,但會出現如此警告。
*因此將class、struct調換過來如下:
*/
class MyClass {};
struct MyClass;
/*
*錯誤訊息如下:
*warning C4099: 'MyClass' : type name first seen using 'class' now  seen using 'struct'
*/
A8: 揪甘心,這就是答案。記住:你的血統(class, struct)不代表什麼,重要的是你的所作所為(class body)