SonicBOOMのデザインを読み解く続き。フロントエンドデザインを波形を見ながら読み解いていくことにする。最初のブート部分の波形を表示すると以下のようになる。
まず、F0ステージからICacheへのリクエストを出し、F2ステージにレスポンスが無ければキャッシュミスしたものとみなす。F3ステージではキューが置かれており、ここにはとりあえずフェッチしてきた命令が挿入される。
// **** F3 **** // -------------------------------------------------------- val f3_clear = WireInit(false.B) val f3 = withReset(reset.toBool || f3_clear) { Module(new Queue(new FrontendResp, 1, pipe=true, flow=false)) } ... f3.io.enq.valid := (s2_valid && !f2_clear && (icache.io.resp.valid || ((s2_tlb_resp.ae.inst || s2_tlb_resp.pf.inst) && !s2_tlb_miss)) ) f3.io.enq.bits.pc := s2_vpc f3.io.enq.bits.data := Mux(s2_xcpt, 0.U, icache.io.resp.bits.data) f3.io.enq.bits.ghist := s2_ghist f3.io.enq.bits.mask := fetchMask(s2_vpc) f3.io.enq.bits.xcpt := s2_tlb_resp f3.io.enq.bits.fsrc := s2_fsrc f3.io.enq.bits.tsrc := s2_tsrc
一方で、F4のキューはCompressed命令を展開して再度格納する。F3のキューは同時に2命令(64ビット)だったものが、F4のキューは同時に4命令(16ビット命令を最大まで展開したもの)を格納することができるようになっている。
if (w == 0) { val inst0 = Cat(bank_data(15,0), f3_prev_half) val inst1 = bank_data(31,0) val exp_inst0 = ExpandRVC(inst0) val exp_inst1 = ExpandRVC(inst1) val pc0 = (f3_aligned_pc + (i << log2Ceil(coreInstBytes)).U - 2.U) val pc1 = (f3_aligned_pc + (i << log2Ceil(coreInstBytes)).U) val bpd_decoder0 = Module(new BranchDecode) bpd_decoder0.io.inst := exp_inst0 ... bpd_decoder.io.inst := exp_inst bpd_decoder.io.pc := pc bank_insts(w) := inst f3_fetch_bundle.insts(i) := inst f3_fetch_bundle.exp_insts(i) := exp_inst bpu.io.pc := pc brsigs := bpd_decoder.io.out if (w == 1) {
そしてfb(Fetch Buffer)ではこれらの展開した命令を格納している。
ftqも同様のタイミングでキューに命令を挿入している。一方でキューから取り出すタイミングは命令がコミットされたタイミングだ。
// ------------------------------------------------------- // **** To Core (F5) **** // ------------------------------------------------------- io.cpu.fetchpacket <> fb.io.deq io.cpu.get_pc <> ftq.io.get_ftq_pc ftq.io.deq := io.cpu.commit ftq.io.brupdate := io.cpu.brupdate ...