SonicBOOMの動作解析、次はLSUによるロード命令の動作を見てみよう。ロード命令はLSUにより発行されるが、命令自体は整数ユニットとは別のイシューユニットで発行される。
以下のアセンブリ命令を実行して波形を取得した。
.section .text .global simple_load simple_load: la x10, test_data ld x10, 0(x10) ret .section .data .align 3 test_data: .dword 0xdeadbeef00000000 .dword 0xdeadbeef00000001
アドレス生成とリクエストのタイミングダイアグラムはこのようになっていた。mem_unit
でアドレスの計算を行い、それを即時lsu
ユニットに転送する。lsu
ユニットにはDTLBが入っておりアドレスを仮想アドレスに変換してからDCacheへリクエストを行う。ここまでが1サイクルで実行されているっぽい?
DCacheにヒットすると2サイクルで返ってくるようだ。
Chisel側のソースコードを読んでみる。まず、mem_units
はExeUnitの内部に存在しており、それ自体は外部のLSUと接続されている。
src/main/scala/exu/core.scala
// Load/Store Unit & ExeUnits val mem_units = exe_units.memory_units val mem_resps = mem_units.map(_.io.ll_iresp) for (i <- 0 until memWidth) { mem_units(i).io.lsu_io <> io.lsu.exe(i) }
リクエストがmem_unit
側からLSUに渡されるようになっている。LSU
ユニットにはDTLBが入っており、そこで物理アドレスへの変換が行われている。
src/main/scala/lsu/lsu.scala
val dtlb = Module(new NBDTLB( instruction = false, lgMaxSize = log2Ceil(coreDataBytes), rocket.TLBConfig(dcacheParams.nTLBEntries))) io.ptw <> dtlb.io.ptw for (w <- 0 until memWidth) { dtlb.io.req(w).valid := exe_tlb_valid(w) dtlb.io.req(w).bits.vaddr := exe_tlb_vaddr(w) dtlb.io.req(w).bits.size := exe_size(w) dtlb.io.req(w).bits.cmd := exe_cmd(w) dtlb.io.req(w).bits.passthrough := exe_passthr(w) } dtlb.io.kill := exe_kill.reduce(_||_) dtlb.io.sfence := exe_sfence val exe_tlb_miss = widthMap(w => dtlb.io.req(w).valid && (dtlb.io.resp(w).miss || !dtlb.io.req(w).ready)) val exe_tlb_paddr = widthMap(w => Cat(dtlb.io.resp(w).paddr(paddrBits-1,corePgIdxBits), exe_tlb_vaddr(w)(corePgIdxBits-1,0)))
見ている感じでは、DCacheには物理アドレスを入力しているようだ。