もうすぐコンテストがあるそうなので、予習してみました。(書きかけです)
機械語の読み方
引数を設定してvsm
ファイルをアセンブラに投げると読みやすくなる
--print-asm
をつけるとコードの後ろに元の命令がコメントで付く
$ /assemble3 hello.vsm --print-asm
i 01000000...000000000000001100000000000000 # imm ui"0" $n0
--print-csv
をつけると、フィールドごとに分割してくれる
i,ll,pe.mrc.imr,pe.mrc.wl,...,l2bm.darwrite,wd
m,valid,mmode,tmode,...,adrb,nw,priority
i,="01",="00000",="0",="0",="0",="0",...,="000",="11",="0000",="0",="0",="00000000",
一行目はi
命令のコラム名一覧で、二行目はm
命令のコラム名一覧になる。
i
命令はPE命令のauto strideモードの機械語
m
命令はMV命令の機械語
ここではi
命令だけに注目する
PE命令のフィールド
PE命令は以下のフィールドを持つ
PE命令 | ||||||||||||
i | ll | pe | l1bm | l2bm | wd | |||||||
mrc | trc | rfc0 | rfc1 | lm0 | lm1 | mauc | aluc | |||||
i | 2bit | 20bit | 3bit | 41bit | 41bit | 32bit | 31bit | 29bit | 17bit | 40bit | 28bit | 8bit |
各フィールドに対応するコンポーネントは以下のようになる
フィールド | コントローラ |
---|---|
pe.mrc | マスクレジスタ |
pe.trc | Tレジスタ(t) |
pe.rfc0 | RF0レジスタ(r) |
pe.rfc1 | RF1レジスタ(s) |
pe.lm0 | LM0メモリ(m) |
pe.lm1 | LM1メモリ(n) |
pe.mauc | MAU |
pe.aluc | ALUC |
l1bm | L1BM(b) |
l2bm | L2BM(c) |
さらに細かいフィールドは各コンポーネントごとに記述する
PE命令の複数の出力オペランド
PE命令は複数の出力オペランドを指定できる。これは以下のような仕組みでコード化する。
例としてALUの計算結果を複数の出力先(t, r, s, m, n)に保存する命令は
PE命令 | ||||||||||||
i | ll | pe | l1bm | l2bm | wd | |||||||
mrc | trc | rfc0 | rfc1 | lm0 | lm1 | mauc | aluc | |||||
i | - | - | write=1 | write=1 | write=1 | write=1 | write=1 | - | ALUOP | - | - | - |
isel=ALU | isel=ALU | isel=ALU | isel=ALU | isel=ALU |
このようにaluc
で計算を指定し、各々の出力先(trc, rfc0, rfc1, lm0, lm1)の書き込みを有効にし(write=1)、入力セレクタにALUを指定(isel=ALU)する。
同様にMAUとALUで計算して結果を(r, s, t, m, n)に分けて保存したい場合は
PE命令 | ||||||||||||
i | ll | pe | l1bm | l2bm | wd | |||||||
mrc | trc | rfc0 | rfc1 | lm0 | lm1 | mauc | aluc | |||||
i | - | - | write=1 | write=1 | write=1 | write=1 | write=1 | MAUOP | ALUOP | - | - | - |
isel=MAU | isel=ALU | isel=MAU | isel=ALU | isel=MAU |
のようにコード化される。このコード化により複数出力オペランドが可能となる。
PE命令の入力オペランド
ALUは2つの入力オペランドAとBを持つ。命令によってオペランド数は0、1、2の場合がある。
MAUは3つの入力オペランドAとBとCを持つ。命令によってはBは行列となり、行列レジスタxかyを使う。
例えば、ALUの入力オペランドAがr
の場合は次のようにコード化する。
PE命令 | ||||||||||||
i | ll | pe | l1bm | l2bm | wd | |||||||
mrc | trc | rfc0 | rfc1 | lm0 | lm1 | mauc | aluc | |||||
i | - | - | - | radr=アドレス | - | - | - | - | ALUOP | - | - | - |
isela=r |
このようにコード化する。出力オペランドのときとは逆にALU側のiselを設定し、データソース側はアドレスを指定する。
ALUとMAUがr
から同じデータを受け取って計算する場合は次のようにコード化する。
PE命令 | ||||||||||||
i | ll | pe | l1bm | l2bm | wd | |||||||
mrc | trc | rfc0 | rfc1 | lm0 | lm1 | mauc | aluc | |||||
i | - | - | - | radr=アドレス | - | - | - | MAUOP | ALUOP | - | - | - |
isela=r | isela=r |
このように同じアドレスを読む限りで、MAUとALUに同時にr
から入力可能となる。
ALUのポートA
ALUのポートAは以下の入力をiselに指定できる。このポートは$peid
などの固定値を指定できる。(TODO: 15個しかないので1つ忘れてるかも???)
入力 |
---|
r |
s |
t |
m |
n |
$peid |
$l1bid |
$l2bid |
$msb1 |
$subpeid |
$mabid |
$mauf |
$aluf |
$lbf |
$mreadf |
ALUのポートB
ALUのポートBは以下の入力をiselに指定できる。Aと異なり固定値は指定できないのと$mreadf
も指定できない。
入力 |
---|
r |
s |
t |
m |
n |
$mauf |
$aluf |
$lbf |
MAUのポート
MAUのポートは以下の入力をiselに指定できる。ALUのポートBと同じ。
入力 |
---|
r |
s |
t |
m |
n |
$mauf |
$aluf |
$lbf |
TRC
Tレジスタの制御を行う。
フィールドは以下の通り。
pe | |
trc | |
write | isel |
1bit | 2bit |
write=1
のときはisel
で指定した入力から書き込みを行う。そうでないときは読み出しのみ行う。
アドレス指定やワード長指定はなく、2長語×4サイクルのアクセスで固定。(TODO: iselの計算結果が1長語のときを調べる)
isel
に指定できる入力
isel |
---|
MAU |
ALU |
L1BM |
MREAD |
ハザード: 書き込み後は1ステップ休む
RFC0とRFC1
レジスタファイルの制御を行う。
フィールドは以下の通り。
pe | |||||||||||||||
rfc0/rfc1 | |||||||||||||||
write | isel | wadr | wadri | wwl | radr | radri | rwl | ||||||||
1bit | 2bit | 9bit | 8bit | 2bit | 9bit | 8bit | 2bit |
write=1
のときはisel
で指定した入力から書き込みを行う。そうでないときは読み出しのみ行う。
wadr
とwadri
とwwl
で書き込みアドレス、書き込みアドレス増分、書き込みワード長を指定する。
radr
とradri
とrwl
で読み出しアドレス、読み出しアドレス増分、読み出しワード長を指定する。
アクセスするアドレスはサイクルごとに
サイクル | アドレス |
---|---|
0 | adr + adri * 2 * wl * 0 |
1 | adr + adri * 2 * wl * 1 |
2 | adr + adri * 2 * wl * 2 |
3 | adr + adri * 2 * wl * 3 |
コード例(TODO: 動作確認して)
コード | adr | adri | wl | アドレス |
---|---|---|---|---|
$lr4 |
4 | 0 | 1 | (4, 4, 4, 4) |
$lr4v |
4 | 1 | 1 | (4, 6, 8, 10) |
$lr4v2 |
4 | 1 | 1 | (4, 6, 8, 10) |
$llr4v4 |
4 | 1 | 2 | (4, 8, 12, 16) |
isel
に指定できる入力
isel |
---|
MAU |
ALU |
L1BM |
MREAD |
ハザード: 書き込み後は1ステップ休む(アドレスごとに独立)。
続きはまた書く