顯示具有 SimpleScalar 標籤的文章。 顯示所有文章
顯示具有 SimpleScalar 標籤的文章。 顯示所有文章

2012年11月3日 星期六

使用 buildroot 建置可用於 SimpleScalar 的 ARM toolchain

0. 前言

剛好最近有人來信詢問,就順便整理先前的一些文件一下,雖然 SimpleScalar 相對於現階段 ARM 的發展而言還停留在 ARMv4 的指令集,但若是在學術用途方面的話,還算是個相當有用的工具。

但在研究初期最容易遇到的問題就是 toolchain 的問題,官方附贈的過舊,要自行建置則網路上資訊過於零散,建立出來也不見得能用...

而在這篇文章中會透過 buildroot 來建立一串基礎的 ARM toolchain ,來簡化整個建置的過程,若一般用途而言這樣的方式就夠了

另外此篇文章假設你已經有一個已經建立好的 SimpleScalar ARM 可以用了


1. 使用 buildroot 建置 ARM toolchain

buildroot 的官方網站是 http://buildroot.uclibc.org/download.html
以下操作以 2012.08 的版本為例子,其它版本操作上大同小異,但部份路徑可能會有不同,第一次建議使用相同版本操作較為保險

目前作過測試是到 gcc 4.6 都可以在 SimpleScalar ARM 上運作沒有問題

gcc 4.7 因為不支援 ARM oabi 的部份所以會有點問題 (需要對 SimpleScalar 作一些修改)

i. 抓取 buildroot

wget http://buildroot.uclibc.org/downloads/buildroot-2012.08.tar.bz2

ii. 解壓縮 buildroot

tar -jxf buildroot-2012.08.tar.bz2

iii. 組態 buildroot

打入 make menuconfig 進入選單,會有 console 版本的選單出現
make menuconfig
# 接著會進入選單
Target Architecture 按 enter 選 ARM (little endian)
Target Architecture Variant 保留 generic_arm ,simplescalar 只支援 arm v4
Target ABI 選 oabi <--這是大重點,eabi 會不能動
Toolchain 點進去可以選 gcc 跟 binutils 版本
  uClibc C library Version 選 uClibc 0.9.31.x ,太新會沒辦法用(需要用到 bx 指令, armv4 不支援)
  需要 g++ 的話在  Enable C++ support 那邊按空白打 *
  需要使用 hard floating point 則 Use software floating point by default 的 * 按空白拿掉
其它看無就不用動

選擇最下面 Save an Alternate Configuration File
你會看到有一串
/home/kito/xxxxxxx/buildroot-2012.08/.config 之類的路徑
不要改
直接按 enter
然後 exit (左右可以移動下面的按鈕)
接著 make
然後轉身去泡杯咖啡,需要一點時間下載跟建置

build 完後在 buildroot 資料夾底下的
./output/host/usr/
這個資料夾
裡面就有 arm toolchain 了

iii. 測試 buildroot

先弄一個 Hello World
echo "int main() {printf(\"hello world\");}" > hello.c
編譯 Hello World ,-static 一定要加, simplescalar 只支援 static link
./output/host/usr/bin/arm-linux-gcc hello.c -o hello -static
使用 SimpleScalar ARM 測試,前面的 path 記得自行替換成 simplescalar 的路徑
/<path-to-simplescalar>/sim-uop hello
看到下面那一沱就代表你成功了!

sim-uop: SimpleScalar/ARM Tool Set version 3.0 of November, 2000.
Copyright (c) 1994-2000 by Todd M. Austin.  All Rights Reserved.
This version of SimpleScalar is licensed for academic non-commercial use only.

sim: command line: /home/kito/simulators/simplesim-arm-v2/sim-uop hello

sim: simulation started @ Mon Oct 22 20:25:18 2012, options follow:

sim-safe: This simulator implements a functional simulator.  This
functional simulator is the simplest, most user-friendly simulator in the
simplescalar tool set.  Unlike sim-fast, this functional simulator checks
for all instruction errors, and the implementation is crafted for clarity
rather than speed.

# -config                     # load configuration from a file
# -dumpconfig                 # dump configuration to a file
# -h                    false # print help message
# -v                    false # verbose operation
# -i                    false # start in Dlite debugger
-seed                       1 # random number generator seed (0 for timer seed)
# -q                    false # initialize and terminate immediately
# -chkpt               <null> # restore EIO trace execution from <fname>
# -redir:sim           <null> # redirect simulator output to file
(non-interactive only)
# -redir:prog          <null> # redirect simulated program output to file
-nice                       0 # simulator scheduling priority
-max:inst                   0 # maximum number of inst's to execute
-trigger:inst               0 # trigger instruction

sim: ** starting functional simulation **
warning: unsupported ioctl call: ioctl(21505, ...)
warning: unsupported ioctl call: ioctl(21505, ...)
hello world
sim: ** simulation statistics **
sim_num_insn                   5276 # total number of instructions executed
sim_num_uops                   7095 # total number of UOPs executed
sim_avg_flowlen              1.3448 # uops per instruction
sim_num_refs                   1259 # total number of loads and stores executed
sim_elapsed_time                  1 # total simulation time in seconds
sim_inst_rate             5276.0000 # simulation speed (in insts/sec)
ld_text_base           0x00008094 # program text (code) segment base
ld_text_bound          0x0000c54c # program text (code) segment bound
ld_text_size                  17592 # program text (code) size in bytes
ld_data_base           0x0000c54c # program initialized data segment base
ld_data_bound          0x000177d0 # program initialized data segment bound
ld_data_size                  45700 # program init'ed `.data' and
uninit'ed `.bss' size in bytes
ld_stack_base          0xc0000000 # program stack segment base
(highest address in stack)
ld_stack_size                 16384 # program initial stack size
ld_prog_entry          0x000080b0 # program entry point (initial PC)
ld_environ_base        0xbfffc000 # program environment base address address
ld_target_big_endian              0 # target executable endian-ness,
non-zero if big endian
mem.page_count                   11 # total number of pages allocated
mem.page_mem                    44k # total size of memory pages allocated
mem.ptab_misses                  11 # total first level page table misses
mem.ptab_accesses             63794 # total page table accesses
mem.ptab_miss_rate           0.0002 # first level page table miss rate

2. 將 GCC, Bintuils 及 uClibc 拉出來重新建置

這個段落主要是給需要修改到編譯器的屠龍人士看的,如果你只是要 ARM Toolchain 或著是要修改 Simulator 的話這段可以直接略過。

i. 建立一個要放等一下所有東西的資料夾

mkdir ~/arm-linux-gcc

ii. 把整串 toolchain 拉出來

cp -a buildroot-2012.08/output/host/usr ~/arm-linux-gcc/

iii. 資料夾重新命名為 arm-linux-gcc

mv ~/arm-linux-gcc/usr ~/arm-linux-gcc/arm-linux-gcc

iv. gcc, binutils, uclibc 等 source code 拉出來

cp -a buildroot-2012.08/output/toolchain/gcc-4.5.4 ~/arm-linux-gcc/
cp -a buildroot-2012.08/output/toolchain/uClibc-0.9.31.1/ ~/arm-linux-gcc/
tar -jxf buildroot-2012.08/dl/binutils-2.21.tar.bz2 -C ~/arm-linux-gcc

v. 建立 bulid-* 資料夾準備

cd ~/arm-linux-gcc
mkdir build-gcc
mkdir build-binutils

vi. 重新 build bintuils

cd build-binutils

vii. 開啟bintuils 的 config log 看一下怎麼下

vim ~/buildroot-2012.08/output/build/host-binutils-2.21/config.log
大約在第七行會有類似的東西
  $ ./configure --prefix=/home/kito/buildroot-2012.08/output/host/usr
--sysconfdir=/home/kito/buildroot-2012.08/output/host/etc
--enable-shared --disable-static --disable-multilib --disable-werror
--target=arm-unknown-linux-uclibc --disable-shared --enable-static
--with-sysroot=/home/kito/buildroot-2012.08/output/host/usr/arm-unknown-linux-uclibc/sysroot

viii. 產生新的 configure 參數

接著把 configure 中所有路徑更新一下, 然後 --sysconfdir 可以拿掉
note : 這邊路徑用我家示範,--prefix 跟 --with-sysroot 都要改
../binutils-2.21/configure
--prefix=/home/kito/arm-linux-gcc/arm-linux-gcc --enable-shared
--disable-static --disable-multilib --disable-werror
--target=arm-unknown-linux-uclibc --disable-shared --enable-static
--with-sysroot=/home/kito/arm-linux-gcc/arm-linux-gcc
/arm-unknown-linux-uclibc/sysroot

ix. 建置並安裝 buildroot

make -j8
make install

x. 重新 build gcc

cd build-gcc

xi. 偷看 buildroot config 怎麼下

~/arm-linux-gcc/arm-linux-gcc/bin/arm-linux-gcc -v
應該會吐出下面訊息,看到 Configured with: 那一段,抄過來修改
Using built-in specs.
COLLECT_GCC=/home/kito/buildroots/buildroot-2012.08/output/host/usr/bin/arm-linux-gcc
COLLECT_LTO_WRAPPER=/home/kito/buildroots/buildroot-2012.08/output/host/usr/libexec/gcc/arm-unknown-linux-uclibc/4.5.4/lto-wrapper
Target: arm-unknown-linux-uclibc
Configured with:
/home/kito/buildroots/buildroot-2012.08/output/toolchain/gcc-4.5.4/configure
--prefix=/home/kito/buildroots/buildroot-2012.08/output/host/usr
--build=x86_64-unknown-linux-gnu --host=x86_64-unknown-linux-gnu
--target=arm-unknown-linux-uclibc --enable-languages=c
--with-sysroot=/home/kito/buildroots/buildroot-2012.08/output/host/usr/arm-unknown-linux-uclibc/sysroot
--with-build-time-tools=/home/kito/buildroots/buildroot-2012.08/output/host/usr/arm-unknown-linux-uclibc/bin
--disable-__cxa_atexit --enable-target-optspace --disable-libquadmath
--disable-libgomp --with-gnu-ld --disable-libssp --disable-multilib
--disable-tls --enable-shared
--with-gmp=/home/kito/buildroots/buildroot-2012.08/output/host/usr
--with-mpfr=/home/kito/buildroots/buildroot-2012.08/output/host/usr
--with-mpc=/home/kito/buildroots/buildroot-2012.08/output/host/usr
--disable-nls --enable-threads --disable-decimal-float
--with-float=soft --with-abi=apcs-gnu --disable-largefile
--with-pkgversion='Buildroot 2012.08'
--with-bugurl=http://bugs.buildroot.net/
Thread model: posix
gcc version 4.5.4 (Buildroot 2012.08)

xii. 產生新的 gcc 的 configure 參數

接著把 configure 中所有路徑更新一下, 然後 --with-bugurl, --with-pkgversion 可以拿掉 build 跟 host 也可以拔掉,它會自己抓,這樣整串指令就不會太長
note1 : mpfr, gmp, mpc 如果你系統有裝的話可以使用系統的就好, 如果使用系統的話--with-gmp --with-mpfr --with-mpc 這三個可以拔掉
note2 : 這邊路徑用我家示範,--prefix --with-sysroot 跟 --with-build-time-tools= 都要改
note3 : 需要 g++ 的話,把--enable-languages=c 改成 --enable-languages=c,c++
../gcc-4.5.4/configure --prefix=/home/kito/arm-linux-gcc/arm-linux-gcc
--target=arm-unknown-linux-uclibc --enable-languages=c
--with-sysroot=/home/kito/arm-linux-gcc/arm-linux-gcc/arm-unknown-linux-uclibc/sysroot
--with-build-time-tools=/home/kito/arm-linux-gcc/arm-linux-gcc/arm-unknown-linux-uclibc/bin
--disable-__cxa_atexit --enable-target-optspace --disable-libquadmath
--disable-libgomp --with-gnu-ld --disable-libssp --disable-multilib
--disable-tls --enable-shared --disable-nls --enable-threads
--disable-decimal-float --with-float=soft --with-abi=apcs-gnu
--disable-largefile

xiii. 建置 gcc !

make! 另外注意一下 gcc 4.4 不支援 make -jx 的功能
make -j8
make install

xiv. 檢查 gcc

~/arm-linux-gcc/arm-linux-gcc/bin/arm-linux-gcc -v
輸出會跟第一次很像但 Configured with: 後面已經換成新的參數,這樣就代表有覆蓋掉舊的了
Using built-in specs.
COLLECT_GCC=/home/kito/arm-linux-gcc/arm-linux-gcc/bin/arm-linux-gcc
COLLECT_LTO_WRAPPER=/home/kito/arm-linux-gcc/arm-linux-gcc/libexec/gcc/arm-unknown-linux-uclibc/4.5.4/lto-wrapper
Target: arm-unknown-linux-uclibc
Configured with: ../gcc-4.5.4/configure
--prefix=/home/kito/arm-linux-gcc/arm-linux-gcc
--target=arm-unknown-linux-uclibc --enable-languages=c
--with-sysroot=/home/kito/arm-linux-gcc/arm-linux-gcc/arm-unknown-linux-uclibc/sysroot
--with-build-time-tools=/home/kito/arm-linux-gcc/arm-linux-gcc/arm-unknown-linux-uclibc/bin
--disable-__cxa_atexit --enable-target-optspace --disable-libquadmath
--disable-libgomp --with-gnu-ld --disable-libssp --disable-multilib
--disable-tls --enable-shared --disable-nls --enable-threads
--disable-decimal-float --with-float=soft --with-abi=apcs-gnu
--disable-largefile : (reconfigured) ../gcc-4.5.4/configure
--prefix=/home/kito/arm-linux-gcc/arm-linux-gcc
--target=arm-unknown-linux-uclibc --enable-languages=c,c++
--with-sysroot=/home/kito/arm-linux-gcc/arm-linux-gcc/arm-unknown-linux-uclibc/sysroot
--with-build-time-tools=/home/kito/arm-linux-gcc/arm-linux-gcc/arm-unknown-linux-uclibc/bin
--disable-__cxa_atexit --enable-target-optspace --disable-libquadmath
--disable-libgomp --with-gnu-ld --disable-libssp --disable-multilib
--disable-tls --enable-shared --disable-nls --enable-threads
--disable-decimal-float --with-float=soft --with-abi=apcs-gnu
--disable-largefile
Thread model: posix
gcc version 4.5.4 (GCC)

xv. 重新 build uClibc

cd ~/arm-linux-gcc/uClibc-0.9.31.1

xvi. 將 buildroot 中 linux header 複製過來

cp -a ~/buildroot-2012.08/output/toolchain/linux/ .

xvii. 更新 uClibc 組態

vim .config
# 修改以下地方
KERNEL_HEADERS="/home/kito/buildroot-2012.08/output/toolchain/linux/include"
改成
KERNEL_HEADERS="/home/kito/arm-linux-gcc/uClibc-0.9.31.1/linux/include"

RUNTIME_PREFIX="/"
改成
RUNTIME_PREFIX="/home/kito/arm-linux-gcc/arm-linux-gcc/"

DEVEL_PREFIX="/usr/"
改成
DEVEL_PREFIX="/home/kito/arm-linux-gcc/arm-linux-gcc/"

CROSS_COMPILER_PREFIX="/home/kito/buildroots/buildroot-2012.08/output/host/usr/bin/arm-unknown-linux-uclibc-"
改成
CROSS_COMPILER_PREFIX="/home/kito/arm-linux-gcc/arm-linux-gcc/bin/arm-unknown-linux-uclibc-"
# 然後存檔離開

xviii. 重新 build uClibc !

make -j8
make install

xix. 往後更動 gcc 步驟

大功告成,往後如果有更動到 gcc
uClibc 必須清掉重新 build 一次
make clean
make -j8
make install

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 膨脹到快兩倍而已






下集待續吧~