第95話で、two-bit data 10はdraft count 2へ戻った。
でもrestore carrierは動かない。
data decoded 2
operation selected none
instruction started 0
イトはblue data cardを持ち上げた。
「これをinstruction slotへ入れれば、二件を運ぶって分かるかな」
red bridgeへ近づける。
toy decoderのpreview lampが点いた。
input context instruction
raw pattern 10
toy opcode CLEAR_TEST_QUEUE
commit 0
count railでは2だった10が、instruction railではqueue clearへ変わった。
同じbits。
違う読み方。
イトの指が止まった。
「数字を入れたのに、命令として読まれた」
bitsだけでは、dataかinstructionか決まらない
CPUが扱うinstructionもdataも、下ではbitsとして表せる。
bitsの見た目だけで、片方を自動的にinstructionと決めるわけではない。
どこからinstructionをfetchするか。
どのinstruction set architecture、ISAでdecodeするか。
どのbitsをoperationやoperandとして読むか。
programとexecution environmentの約束が必要だ。
今回のtoy ISAでは、instruction slotの10をCLEAR_TEST_QUEUEへ割り当てている。
この対応はlab fixtureだけの約束で、real CPUに共通のopcodeではない。
イト
10だから2、とは限らない。どのdecoderへ入ったかで意味が変わるんだ
ユイ
data railのschemaと、instruction railのISAは別の読み方なんですね
マコト
raw bitsだけで高い階層の目的まで決めないことだね
Picoはcardを差し替えない。
data holder、instruction memory、decoderを三つのinspection lightで分けた。
program counterは、次に読むinstructionを指す
CPUには、次に処理するinstructionの位置を追うstateがある。
ここではprogram counter、PCと呼ぶ。
simple fixtureの流れはこうだ。
PC -> instruction fetch -> decode -> operand read -> execute
-> architectural state update -> next PC
instruction fetchは、PC / control flowが選んだ位置からencoded instructionを取る。
decodeは、ISAに従ってoperationとoperand指定を読む。
load instructionならdataを読むことがある。
store instructionならresultを指定先へ書くことがある。
branchやjumpなら、next PCが順番どおりの次位置ではなく変わることがある。
CPUはmemoryにあるすべてのbitsを、端から自動実行するわけではない。
control flowがinstructionとしてfetchしたものを処理する。
fetch・decode・executeは、四人の固定係ではない
fetch → decode → execute → state updateは、仕組みを追うconceptual modelとして役に立つ。
ただしすべてのCPUが、四つの独立した台を一instructionずつ直列に通すわけではない。
real implementationでは複数instructionのstageをoverlapさせるpipelineがある。
先のinstructionを予測してfetchすることもある。
内部ではout-of-orderに進め、ISAから見える結果を正しい順序へ確定する設計もある。
cache hit / miss、branch、interrupt、exceptionによって進み方も変わる。
だからkey一回が必ず何instruction、必ず何cycleとは固定しない。
application、OS、input method、current state、hardwareで変わる。
この記事では、見える因果をsingle-stepできるclosed toy CPUだけを使う。
よくある誤解:電源中のCPUは、命令を休まず流し続ける
実行するworkがある間、CPUはinstructionを進める。
でも「電源が入っていれば、全coreが常に同じ速さで命令を実行し続ける」とは限らない。
OSやfirmwareはidle loopやwait operationを使える。
architectureには、interruptなどのeventを待つinstructionがある場合もある。
coreをstall、idle、sleep、low-power stateへ移すか、waitをhintとして扱うかはarchitecture / implementation / power managementで違う。
interruptやeventで再開する場合もある。
今回のtoy fixtureではWAIT_EVENTを実行すると、次のeventまでinstruction started 0になる。
これもreal CPU全体へ同じbinary encodingを一般化しない。
「命令札は眠らない」は比喩としても強すぎる。
止まる条件と再開するeventを観測する。
restore handoffまで残り21秒
draft count 2を、restore slot count registerへ渡す。
残り二十一秒。
source draftはread-onlyに保つ。
instruction memoryは承認済みthree-card fixtureだけを使う。
PC 0からsingle-stepする。
decoded operation、operand、result、next PCが予定と違えば、次stepへ進まない。
最後はWAIT_EVENTで止まり、二slot以外を開かない。
イトはdata bridgeの前へ、三枚のroute cardを置いた。
イト
A。dataの10をinstruction slotへ入れ、decoderが選んだoperationをそのままcommitする
イト
B。PCとdecodeを飛ばし、output registerへ2を直接押し込む
イト
C。data railを守り、three-instruction programをPC 0から一stepずつ実行する
Aは、data schemaをtoy opcodeへ誤変換する。
Bは、結果だけを作ってどのinstructionが書いたかを失う。
Cなら、instructionとdataを別railに保ち、state changeを一つずつ確かめられる。
イトがdata-to-opcode bridgeを閉じ、ordered instruction railを開いた
イトは左手で、data-to-opcode bridgeのred gateを閉じた。
direct-output crankにもdark lockを掛ける。
右手で、three-card instruction railのguardを開いた。
PC markerを最初のcardへ置く。

10をopcodeへ変えず、PCが指すthree-instruction programを一stepずつ進める。lower data railには、blue draft_count = 10 cardを残す。
upper instruction railには、fixture専用の三cardだけを置いた。
PC 0 LOAD_COUNT_TO_R0
PC 1 STORE_R0_TO_SLOT_COUNT
PC 2 WAIT_EVENT
これはlab用pseudocodeであり、特定real ISAのmachine instructionではない。
PicoはPC markerとcurrent instruction cardの境界だけを照らす。
card、PC、register、gateへ触れない。
三stepで、二つのslotが開いてCPUは待った
イトはstep leverを一度だけ引いた。
before PC 0
fetched LOAD_COUNT_TO_R0
operand data 10
decoded count 2
after R0 2
next PC 1
queue clear lampは点かない。
二度目。
before PC 1
fetched STORE_R0_TO_SLOT_COUNT
operand R0 2
slot count 2
next PC 2
二つのrestore slotが開いた。
三度目。
before PC 2
fetched WAIT_EVENT
core state waiting
instruction started after wait 0
next PC 3
test queue cleared 0
source drafts changed 0
restore slots open 2
unexpected PC 0
イトはstep leverから手を離した。
「dataを命令にしなくても、programがdataを読んで結果を書けた」
single-stepしたため、automatic runより時間はかかった。
でもどのinstructionが、どのoperandを読み、何を書いたかをtraceへ残せた。
今回の三stepはtoy fixtureのinstruction数であり、real applicationのkey一回に必要な数やcycle数ではない。
CPU traceを確認する順番
最初にexecution contextを固定する。
対象ISA、mode、program image、start PC。
次にcurrent instructionを確認する。
PCの位置。
fetchされたbits。
decodeされたoperation。
source / destination operand。
実行前後のregister、memory、visible output。
next PC。
raw bitsだけを見て、high-level intentを決めない。
illegal instruction、instruction fetch不可、unexpected branch、operand mismatchが出たら、推測で次stepへ進まない。
simple modelで説明するときも、pipeline overlapやspeculationがないと断定しない。
反対に内部順序が複雑でも、ISAから見えるresult、exception、control flowの境界へ戻って調べる。
一つのlaneへ、千件のwork cardが来た
WAIT_EVENT中の工房へ、新しいbellが鳴った。
CPU laneが再開する。
奥のdistributorから、同じ形のwork cardが千枚届いた。
independent work items 1000
current general lane 1
first round active 1
waiting items 999
イトはthree-card programを千回copyしようとした。
隣のdoorが開く。
片方には、少数の大きなgeneral-purpose lane。
もう片方には、同じ形のworkを並べる細いlaneが何百本も続いていた。
さらに奥では、決まった計算形に合わせたmatrix floorが光る。
同じbitsを実行できても、同じworkloadで同じ速さや効率になるとは限らない。
イトは一枚目を配る前に、work cardの形を見直した。
次回、ピコルート第97話。
イトは、千件を一人の工房長へ並べた|CPU・GPU・NPUは何が違う?

