ここに注意 MN-Core プログラミング
MN-Core 2 プログラミングでの、やや気づきにくい細かい注意点を解説します。
PE命令関係
・「PE命令」と呼ばれるものは、ALU や MAU など PE が使用するユニットを動作させる命令以外に、「MV 命令」以外の L2BM、L1BM、MAB の各ユニットを動作させる命令全てを総称しています。
・PE のメモリ(LM、GRF、T レジスタ、マスクレジスタなど)を出力先に指定できる命令は、他の制約が許す限り出力先を複数指定することが可能です。
imm f"3.14" $ls0v $lr0v $ln0v $t $omr1
d getf $ls0n0c0b0m0p0 1
d getf $lr0n0c0b0m0p0 1
d getf $ln0n0c0b0m0p0 1
d getf $tn0c0b0m0p0 1
出力
DEBUG-GREG1(n0c0b0m0p0,0):(3.14, 3.14) (0x4048f5c3, 0x4048f5c3) #d getf $ls0n0c0b0m0p0 1
DEBUG-GREG0(n0c0b0m0p0,0):(3.14, 3.14) (0x4048f5c3, 0x4048f5c3) #d getf $lr0n0c0b0m0p0 1
DEBUG-LM1(n0c0b0m0p0,0):(3.14, 3.14) (0x4048f5c3, 0x4048f5c3) #d getf $ln0n0c0b0m0p0 1
DEBUG-TREG(n0c0b0m0p0,0):(3.14, 3.14) (0x4048f5c3, 0x4048f5c3) #d getf $ltn0c0b0m0p0 1
・$omr2/$imr1
のように、マスクレジスタにマスクを適用し、マスクフラグの and を取ることができます。
・ただしゼロフラッシュマスクに関して、マスクフラグはゼロフラッシュマスク適用前の値を評価して生成されます。
ALU 関係
・即値は単語 (\(32\) bit) までしか指定できません。出力に $lr0
(長語 \(64\) bit) や $llr0
(2長語 \(128\) bit) を指定した場合は、即値を繰り返した値が書き込まれます。
imm i"9" $llr0 # int (32 bit) 即値
d getf $lr0n0c0b0m0p0 2
imm s"7" $lls0 # short (16 bit) 即値
d getf $ls0n0c0b0m0p0 2
出力
DEBUG-GREG0(n0c0b0m0p0,0):(0, 0) (0x00000009, 0x00000009) #d getf $lr0n0c0b0m0p0 2
DEBUG-GREG0(n0c0b0m0p0,2):(0, 0) (0x00000009, 0x00000009) #d getf $lr0n0c0b0m0p0 2
DEBUG-GREG1(n0c0b0m0p0,0):(0, 0) (0x00070007, 0x00070007) #d getf $ls0n0c0b0m0p0 2
DEBUG-GREG1(n0c0b0m0p0,2):(0, 0) (0x00070007, 0x00070007) #d getf $ls0n0c0b0m0p0 2
・命令は原則として、入力のそれぞれの対応する要素ごとに独立して動作します。
たとえば ALU で半語(\(16\) ビット)単位でシフトを行う場合、シフト量も半語単位で指定する必要があります。
d set $lm0 1 1234abcd1234abcd
imm i"4" $nowrite # 16bit 列としては [0, 4, 0, 4]
slsl $lm0 $aluf $lr0
d geth $lr0n0c0b0m0p0 1
# (0x1234, 0xbcd0, 0x1234, 0xbcd0) # 2 番目, 4 番目だけ左シフトされた
imm s"4" $nowrite # 16bit 列としては [4, 4, 4, 4]
slsl $lm0 $aluf $ln0
d geth $ln0n0c0b0m0p0 1
# (0x2340, 0xbcd0, 0x2340, 0xbcd0) # 全て左シフトされた
・ReLU 命令は、\(1\) 引数ではなく \(2\) 引数命令であり、入力 \(x\) の符号に応じて入力 \(y\) の値を返します。
・整数掛け算、除算、itof 命令はありません。
MAU 関係
MAU に関する命令において、行列レジスタを除き、入力オペランドの先頭に -
を付加することで、符号を反転して入力に与えることができます。
以下の vsm では、\(-mn-1.0\) を計算しています。
imm f"1.0" $nowrite
fvfma $lm0v -$ln0v -$aluf $ln0v
・半精度の積和演算は、half × half + float = float の精度で行われます。
また、add や passa もこの積和演算器を流用しているため、適切に精度の丸めや拡張を行う必要があります。
hvadd の例:half + float = float で行われるので、入出力を half で行いたい場合は、\(2\) 番目の引数を e
で精度拡張し、hvaddr
と指定して出力を half に丸める必要があります。
imm h"3.14" $lr0v
nop
hvaddr $lr0v $lr0ve $lr0v
d geth $lr0n0c0b0m0p0 4
出力
DEBUG-GREG0(n0c0b0m0p0,0):(6.28125, 6.28125, 6.28125, 6.28125) (0x4324, 0x4324, 0x4324, 0x4324) #d geth $lr0n0c0b0m0p0 4
DEBUG-GREG0(n0c0b0m0p0,2):(6.28125, 6.28125, 6.28125, 6.28125) (0x4324, 0x4324, 0x4324, 0x4324) #d geth $lr0n0c0b0m0p0 4
DEBUG-GREG0(n0c0b0m0p0,4):(6.28125, 6.28125, 6.28125, 6.28125) (0x4324, 0x4324, 0x4324, 0x4324) #d geth $lr0n0c0b0m0p0 4
DEBUG-GREG0(n0c0b0m0p0,6):(6.28125, 6.28125, 6.28125, 6.28125) (0x4324, 0x4324, 0x4324, 0x4324) #d geth $lr0n0c0b0m0p0 4
hvpassa の例:half → float で行われるので、入出力を half で行いたい場合は出力を half に丸める必要があります。
imm h"3.14" $llr0v
nop
hvpassar $lr0v $lr0v
d geth $lr0n0c0b0m0p0 4
出力
DEBUG-GREG0(n0c0b0m0p0,0):(3.14062, 3.14062, 3.14062, 3.14062) (0x4124, 0x4124, 0x4124, 0x4124) #d geth $lr0n0c0b0m0p0 4
DEBUG-GREG0(n0c0b0m0p0,2):(3.14062, 3.14062, 3.14062, 3.14062) (0x4124, 0x4124, 0x4124, 0x4124) #d geth $lr0n0c0b0m0p0 4
DEBUG-GREG0(n0c0b0m0p0,4):(3.14062, 3.14062, 3.14062, 3.14062) (0x4124, 0x4124, 0x4124, 0x4124) #d geth $lr0n0c0b0m0p0 4
DEBUG-GREG0(n0c0b0m0p0,6):(3.14062, 3.14062, 3.14062, 3.14062) (0x4124, 0x4124, 0x4124, 0x4124) #d geth $lr0n0c0b0m0p0 4
その他
・MN-Core 2 はリトルエンディアンではなく、ビッグエンディアンです。
・LM, GRF は単語 (\(32\) bit) 基準のアドレッシングですが、L1BM, L2BM, 行列レジスタ は長語 (\(64\) bit) 基準のアドレッシングです。