2010年11月16日 星期二

Add new instruction to SimpleScalar (1) - Modify Simple Scalar

這份教學主要包含三個部份

1. 加指令到 SimpleScalar  (實驗中採用該版本 http://www4.ncsu.edu/~hhashem/mase-alphalinux.htm)
2. 加指令到 gas (Binutils 2.20)
3. 加指令到 gcc (GCC 4.4.3)

不過著重在前兩項, 第三項沒背景知識一時半刻也弄不來

教學範例是為 Alpha 加上整數除法!

(Alpha真他媽的畸形 有浮點數除法沒整數除法)


為你的SimpleScalar增加新的指令!

雖然這鬼東西已經夠老了, 不過可怕的是中文資源幾乎都只教怎麼安裝

沒教怎麼改

而增加指令只有首頁那該死的 def file format 可以參考

去年面對的時候選擇了逃避

沒想到其實沒有想像中的難...

就進入正題吧

http://www.simplescalar.com/docs/README-def.txt

有空還是請記得讀一下官方文件



1. 加指令到 SimpleScalar

為了達到增加指令的裡面,我們必須要先了解 SimpleScalar 是怎麼 decode 的

首先 SimpleScalar 採用一種名為 Decode Tree 的鬼東西,大致上來說就是需要在新增指令的時候大概按照他的樹狀結構編排

Decode Tree 的開端來自於 MD_TOP_OP(INST) 這個 Macro


這個是來自 ARM 的

#define MD_TOP_OP(INST) (((INST) >> 24) & 0x0f)

ARM 使用 23~27 bit 當主要的 Opcode
28~31被拿去當 Condition Code

這個是來自 Alpha 的

#define MD_TOP_OP(INST)         (((INST) >> 26) & 0x3f)

Alpha 則是前 7 bit 都抓去當 Opcode

所以有了 MD_TOP_OP 後我們可以開始建構 Decode Tree 了

以Alpha 為例

LDA 的 OPCODE 是 0x08

那麼我們就直接定義


DEFINST(LDA,                    0x08,
        "lda",                  "a,o(b)",
        IntALU,                 F_ICOMP,
        DGPR(RA), DNA,          DNA, DGPR(RB), DNA)

第一個參數是拿來辨別的
第二個參數是OPCODE
第三個參數是拿來 disasm 用的資訊
第四個參數也是拿來 disasm 用的資訊
第五個參數是會用到哪個 Functional Unit, 這個在 sim-outorder 下會有影響
第六個參數則是分類該指令, 同樣的也是在 sim-outorder 下會有影響
接下來六七個是 Output Register , 拿來控制 Dependency 用的
八九十則是 Input Register , 也是拿來控制 Dependency 用的
所以後五個參數, 請直接跟同類型的指令拷貝

注意一下 ARM 的參數個數有點不太一樣, 主要差在後面不止五個

接著請記得在這個 Marco 的前面定義一個

LDA_IMPL 的 Macro


#define LDA_IMPL                    \
{                                   \
  SET_GPR(RA, GPR(RB) + SEXT(OFS)); \
}

這個是用來實作該指令的功能的


看到這邊應該正常來講已經可以做到基本的增加指令了

但是通常事情沒那麼簡單

常常有 OPCODE 外還會有 Function Code , Alpha 中Operate Instruction 就是這樣, 在 MIPS 中也有

那麼我們就不能直接像 LDA 般那麼歡樂的加指令

這時候套個 SimpleScalar 說明文件的術語

我們需要 Sub Decode Tree !

意思是說我們用 OPCODE 分了某類後想要再依照某些欄位分類的話就要 Sub Decode Tree

阿 Sub Decode Tree 到底是什麼 ?

簡單的說就是類似再一次的設定 MD_TOP_OP 的那種感覺

不過已經不是 TOP 而是 SECOND 了, 喔 這不是重點

接下來我們需要 DEFLINK 這個東西來定義 Sub Decode Tree Root

例如以 Alpha add, sub 等等的 OPCODE 0x10 為例



我們只要這樣定義


DEFLINK(INTA, 0x10, "inta", 5, 0x7f)

第一個欄位是該  Sub Decode Tree 的名稱
第二個欄位是OPCODE
第三個欄位是註解
第四個欄位是新的OPCODE的偏移量
第五個欄位是新的OPCODE的MASK

所以這個 DEFLINK 的效用大概會等於

MD_SECOND_OP(INST) ((INST >> 5) & 0x7f)

喔, 不過沒有 MD_SECOND_OP 這麼 Macro , 別真的去宣告


就會出現一顆 Sub Decode Tree 了


接下來很重要的是我們需要 CONNECT 兩棵 Decode Tree

CONNECT(INTA)

然後就只要符合 MD_TOP_OP(INST) = 0x10 的都會掉進這顆叫 INTA 的 Sub Decode Tree 了~

接著我們只要開心的 DEFINST 就可以了~

不過其實很多情況下我們並不只想要兩層 Decode Tree 就解決, 有時候可能會需要三層甚至四層, 這時候該怎麼辦呢?

方法就是在該 Sub Decode Tree 的 CONNECT 後再 DEFLINK

那麼這個 DEFLINK 就會是 Sub Sub Decode Tree 了

在 Alpha 中就用這種無聊的技巧來分別第三個 Operand 是 Imm 還是 Reg

對, 真的很無聊...明明就用個 if 就解決了, 還要靠這該死的 Decode Tree

如果無聊去看實作的話會發現這樣做只是比較慢而且免費讓 DEF 膨脹到快兩倍而已






下集待續吧~

2010年11月7日 星期日

Qt Creator for CentOS 5.x

用 CentOS 最 g8 的就是一堆比較新的套件都不太能用

要碼自己編不然就放棄
(而且還會遇到一堆套件版本相依性問題!

最近要用到 qt creator 簡直是麻煩到爆炸了

還好有個好心的老外有提供

http://joseph.freivald.com/linux/


安裝方法

1.

rpm -ivh http://software.freivald.com/centos/software.freivald.com-1.0.0-1.noarch.rpm
2.
然後就可以開心的用 yum 安裝了
yum install qt-creator
歐~人生真是美好~

DebugStream for C++

千年發文

其實這是剛才心血來潮寫的小 helper class

主要用途是來控制輸出資訊用的

並且可以在輸出時指定輸出等級, 例如 lv 3 以上才輸出之類的

廢話不多說先來段使用範例

#include "DebugStream.hpp" 
// 使用前只要 include header 就可以了
#include <iomanip>  
// iomanip for std::setprecision
int main(){
  DebugStream ds(10);       
  // 開一個 DebugStream, debug level 設為 10
  ds[3] << "abc\n";   
  // verbose level 3, 小於debug level 所以會被印出來
  ds[11] << "XD\n";   
  // verbose level 11, 大於debug level 所以不會被印出來
  ds[8] << 123 << std::endl;
  ds.precision(2);          
  // 跟平常使用 cout 習慣一樣喔~
  ds[5] << 0.54321 << std::endl; 
  ds[5] << std::setprecision(4) << 0.12354 << std::endl; 
  // 當然也可以採用這種方式~
  return 0;
}

預計未來可能應該大概會加入 printf 的功能來達到 ds[3].printf("%d", 3); 之類的功能

code 按這裡取得完整程式碼

2010年3月19日 星期五

ARM System call in SimpleScalar

對ARM的認知大致上都是從課堂跟GCC的md檔來的

但是對於這些OS底層實作相關的知識還真是薄弱

說正確一點是弱到不行

SimpleScalar 的 system call實作上大致上是在

target-arm/syscall.c裡面

有時候遇到

warning: invalid/unimplemented syscall xxx, PC=0x0001c454, winging it

的時候可以直接略過沒關係,但是...事情總不會那麼順利

而且SimpleScalar早就沒在更新了,也大概不用期待下一版會解決這種事發生

以rename來當例子好了,忘記是哪個benchmark需要用到,少了就不能正常運作

rename 的 system call 編號是 38

所以其實要補system call的第一步是先查出缺什麼,並且它是不是必要的,
(必要的定義在於沒補齊就會跑不出數據...

接著把編號拿去syscall.c裡面查查看是啥

以38為例

#define ARM_SYS_rename 38

由此可知編號38是rename,接著丟到Google大神去查一下各參數的功能是啥

int rename ( const char * oldname, const char * newname );

rename就如他名字一般,就是拿來改檔案的

所以我們其實只要把參數在丟到對應的system call就好

第一個參數會放在R0

第二個則在R1

所以直覺上我們這樣寫

regs->regs_R[MD_REG_R0] =
rename(regs->regs_R[MD_REG_R0], regs->regs_R[MD_REG_R1]);

不過會發現一件事,regs->regs_R[MD_REG_R0]所存的指標不是host所用的address

直接傳進去可能會segment fault,或是發生其他不可預期的事

參考一下其他system call的實作可以發現有一個函數可以用

char buf[MAXBUFSIZE];
mem_strcpy(mem_fn, mem, Read, /*fname*/regs->regs_R[MD_REG_R0], buf);

從simulator 所用的記憶體中搬出東西來,第二個參數也照做就行了

接著補上頭跟尾
case ARM_SYS_rename:
{
char buf[MAXBUFSIZE];
char buf2[MAXBUFSIZE];
/* copy filename to host memory */
mem_strcpy(mem_fn, mem, Read, /*fname*/regs->regs_R[MD_REG_R0], buf);
mem_strcpy(mem_fn, mem, Read, /*fname*/regs->regs_R[MD_REG_R1], buf2);
/* chmod the file */
/*result*/
regs->regs_R[MD_REG_R0] =
rename(buf, buf2);

break;
}


然後補上錯誤處理部份

case ARM_SYS_rename:
{
char buf[MAXBUFSIZE];
char buf2[MAXBUFSIZE];
/* copy filename to host memory */
mem_strcpy(mem_fn, mem, Read, /*fname*/regs->regs_R[MD_REG_R0], buf);
mem_strcpy(mem_fn, mem, Read, /*fname*/regs->regs_R[MD_REG_R1], buf2);
/* chmod the file */
/*result*/
regs->regs_R[MD_REG_R0] =
rename(buf, buf2);

/* check for an error condition */
if (regs->regs_R[MD_REG_R0] == (qword_t)-1)
/* got an error, return details */
regs->regs_R[MD_REG_R0] = -errno;
break;
}

會用qword_t則是有一些歷史原因,simplescalar最原本是porting到alpha上用的,大概是因此沿用下來的慣例

俗話說的好要入境隨俗,所以留著吧

然後再把這段code插入sys_syscall的那個超大switch中的某個適合的地方就可以了



後記:

其實最讓我驚訝的還是在

system call的時候

第五個參數竟然就直接放在r4,這跟原本認知第五個參數以後要丟stack不一樣

至於第六個或更多參數呢...目前還沒看到,遇到再補完這邊文章

2010年2月10日 星期三

Chrome for CentOS 5.4

http://www.cs.bham.ac.uk/~cxs548/chrome




wget http://www.cs.bham.ac.uk/~cxs548/chrome.tar.gz

tar -zxf chrome.tar.gz

cd chrome

./chrome-wrapper