先週の復習
CPUのprogramming modelは、以下の要素からなる。
すべてのCPUに詳しくなる必要はないが、どれか一つの専門家にはなって
いたい所である。
どちらが優れているかという議論はあったが、現在では卵のとがっている
方から割るか、丸い方から割るかぐらいの違いしかないと認識されている
ようだ。
これらの問題は、普通のプログラミングでは考える必要はないが、
効率の良いMachine Languageを生成する場合には考慮する必要が
ある。
現在のプログラミングでは、配列(array)やリスト(list)、構造体(structure) のアクセスが重要なので、Addressing mode は、それを1命令で実現しやすい ように設計されているのが普通だ。だいたい図のようなAddressing mode を採用しているものが多い。
Addressing modeには以下のようなものがある。
Immediate LDA #$F0 constantをloadする extended LDA $F000 指定されたaddressからloadする indexed LDA 5,X indexとoffsetで示されたaddress からload する accumulator offset indexed LDA A,X indexed + post increment LDA A,X+ loadしたあと X を一つ増やす indexed + pre decrement LDA A,-X loadする前に X を一つ減らすさらに、これらを一段間接にしたindirect addressing も用意されている。 演算は、基本的にaccumulatorとmemory間で行われる。
8bit CPU(8080)の拡張によってできたCPUなので、32bit modeでも それをかなり引きずっている。命令はMC6809と同じ8bitの可変長命 令である。80386によって、16bit/32bit切替と仮想記憶がサポート され爆発的な成功を納めた。最近のPentinumPro では、内部でRISC 命令に変換してから実行するというようなことをしている。16bit ではregisterの役割が偏っていたが、32bitでは若干対称性が良く なっている。4本のAccumulator、4本のIndex register を持つ。
Addressing modeには以下のようなものがある。
Immediate movb al,$F0 constantをloadする extended movb al,[$F000] 指定されたaddressからloadする indexed movb al,[EAX+5] indexとoffsetで示されたaddress からload する accumulator offset indexed mov [EBX+EAX] accumulator offset indexed mov [EBX+EAX+5]さらに、x86には segement register というのがあり、それによっ てvirtual memory (メモリ空間) を切り替えることができる。しか し、普通はすべて同じメモリ空間が設定されている。他のCPUでも データ(data)とコード(code)は別空間にできるものが多い。
演算はレジスタとレジスタの間で行うことが多い。
IBMPC は、pw上でcompile すれば良い。Sparc は、nirai, kanai または fish1, fish2 上でcompileすれば良い。 MC6809のcompilerとemulatorは、 /usr/open/lectures/kono/compiler/mc に太田昌宏氏によるcompilerと、 /usr/open/lectures/kono/compiler/util09 にBenschopによる6809 emulatorがある。
gdb というdebuggerを使って、そのAssemberの実行を一命令づつ 調べることができる。
int a[10]; main() { return a[4]; }は、gcc -O -S test.c によって、(RISCの場合は-Oを付けた方がより 分かりやすいコードがでることが多い)
.file "test.c" gcc2_compiled.: ___gnu_compiled_c: .text .align 2 .globl _main _main: pushl %ebp movl %esp,%ebp call ___main movl _a+16,%eax leave ret .comm _a,40という形にcompileされる。(一部だけ抜きだしている。実際には、その他の 部分がたくさんある) これをgdbで実行するには、
% gcc -g test.c % gdb a.out gdb) b main Breakpoint 1 at 0x10ac: file test.c, line 4. (gdb) r Starting program: /usr/home/teacher/kono/a.out Breakpoint 1, main () at test.c:4 4 return a[4]; (gdb) stepi 5 } (gdb) disassemble main Dump of assembler code for function main: 0x10a4とすれば良い。: pushl %ebp 0x10a5 : movl %esp,%ebp 0x10a7 : call 0x1128 <__main> 0x10ac : movl 0x520c,%eax 0x10b1 : leave 0x10b2 : ret 0x10b3 : addb %dl,0xffffff89(%ebp) End of assembler dump. (gdb) si
MC6809の場合は、 /usr/open/lectures/kono/compiler/mc/mc test.c とする。すると、c.out というファイルにassemblerが出力される。
a EQU 0 main PSHS U LEAU ,S LDD 8,Y SYNC PULS U,PC _1 RTS _INITIALIZE EQU _1 _GLOBALS EQU 20 ENDという感じになる。このままでは止まらないので、PULSの前にSYNCという 命令を入れてある。これを以下のようにassembleする。
/usr/open/lectures/kono/compiler/util09/a09 c.outすると、c というファイルができる。これを、
/usr/open/lectures/kono/compiler/util09/v09t cとして実行の様子を見ることができる。
IBMPC上で、6809 CPU用のGCC cross compilerを作成し、 それから6809CPU上で動作するGCCを作成する手順をI-T図で示せ。
以下のprogram check_endian.c がある。
int check = 0x12345678; main() { char i, *ptr; ptr = (char *)✓ i = ptr[1]; return i; }このprogramをcompileしたassemblerを、どれか一つのCPUで表示 させて見よ。また、gdb で i にどのような値が入るかを 確認せよ。そのCPUは、Little-Endian か Big-Endian かを答えよ。 また、 trace の結果を、
Subject: compiler report 10/19というSubjectのメールにして、kono@ie.u-ryukyu.ac.jp まで送ること。 また授業を受けなかったものは、課題を、
Subject: compiler lecture 10/19というサブジェクトで送ること。