PcPluginの実装の解析
とりあえずまずはChatGPTにこのソースコードを解説してもらおうと思う。
- ジャンプロジックの設定: ジャンプロジックでは、登録されたジャンプ要求を優先度に応じてソートし、優先度が高いものから順に評価します。 ジャンプ命令が有効であれば、それに応じてプログラムカウンタが更新されます。これは、異なるジャンプグループを適切に扱うことで複数のジャンプ要求をまとめて処理します。 - プログラムカウンタの初期化とインクリメントロジック: 初期化ロジックでは、システムが完全に起動するまでのサイクル数を計算し、その間はプログラムカウンタの更新を遅延させます。 PCの計算では、ジャンプ命令による更新がない場合は通常のインクリメントを行います。ジャンプ命令が発行された場合は、プログラムカウンタをジャンプ先のアドレスに設定し直します。
最初のジャンプロジックの設定は以下のソースコードの部分だと思われる:
val jump = new Area { val sortedByStage = jumpsSpec.sortWith(_.priority > _.priority) val valids = sortedByStage.map(_.interface.valid) val cmds = sortedByStage.map(_.interface.payload) val oh = OHMasking.firstV2(valids.asBits) val grouped = sortedByStage.groupByLinked(_.aggregationPriority).toList.sortBy(_._1).map(_._2) var target = PC() for(group <- grouped){ val indexes = group.map(e => sortedByStage.indexOf(e)) val goh = indexes.map(i => oh(i)) val mux = OhMux.or(goh, group.map(_.interface.pc)) if(group == grouped.head) target := mux else when(goh.orR){ KeepAttribute(target) target \= mux } } val pcLoad = Flow(JumpCmd(pcWidth = widthOf(PC))) pcLoad.valid := jumpsSpec.map(_.interface.valid).orR pcLoad.pc := target }
これが以下のようにVerilogに変換されている。もう何が何だか分からない。
reg [39:0] PcPlugin_logic_jump_target_1; wire [5:0] _zz_PcPlugin_logic_jump_oh; wire _zz_PcPlugin_logic_jump_oh_1; wire _zz_PcPlugin_logic_jump_oh_2; wire _zz_PcPlugin_logic_jump_oh_3; wire _zz_PcPlugin_logic_jump_oh_4; wire _zz_PcPlugin_logic_jump_oh_5; reg [5:0] _zz_PcPlugin_logic_jump_oh_6; wire [5:0] PcPlugin_logic_jump_oh; (* keep , syn_keep *) wire [39:0] PcPlugin_logic_jump_target /* synthesis syn_keep = 1 */ ; wire _zz_PcPlugin_logic_jump_target_1; wire PcPlugin_logic_jump_pcLoad_valid; wire [39:0] PcPlugin_logic_jump_pcLoad_payload_pc; PcPlugin_logic_jump_target_1 = PcPlugin_logic_jump_target; PcPlugin_logic_jump_target_1 = (_zz_PcPlugin_logic_jump_target_1 ? BtbPlugin_setup_btbJump_payload_pc : 40'h0000000000); assign _zz_PcPlugin_logic_jump_oh = {BtbPlugin_setup_btbJump_valid,{FetchCachePlugin_setup_redoJump_valid,{AlignerPlugin_setup_sequenceJump_valid,{DecoderPredictionPlugin_setup_decodeJump_valid,{CommitPlugin_setup_jump_valid,PrivilegedPlugin_setup_jump_valid}}}}}; assign _zz_PcPlugin_logic_jump_oh_1 = _zz_PcPlugin_logic_jump_oh[0]; assign _zz_PcPlugin_logic_jump_oh_2 = _zz_PcPlugin_logic_jump_oh[1]; assign _zz_PcPlugin_logic_jump_oh_3 = _zz_PcPlugin_logic_jump_oh[2]; assign _zz_PcPlugin_logic_jump_oh_4 = _zz_PcPlugin_logic_jump_oh[3]; assign _zz_PcPlugin_logic_jump_oh_5 = _zz_PcPlugin_logic_jump_oh[4]; _zz_PcPlugin_logic_jump_oh_6[0] = (_zz_PcPlugin_logic_jump_oh_1 && (! 1'b0)); _zz_PcPlugin_logic_jump_oh_6[1] = (_zz_PcPlugin_logic_jump_oh_2 && (! _zz_PcPlugin_logic_jump_oh_1)); _zz_PcPlugin_logic_jump_oh_6[2] = (_zz_PcPlugin_logic_jump_oh_3 && (! (|{_zz_PcPlugin_logic_jump_oh_2,_zz_PcPlugin_logic_jump_oh_1}))); _zz_PcPlugin_logic_jump_oh_6[3] = (_zz_PcPlugin_logic_jump_oh_4 && (! (|{_zz_PcPlugin_logic_jump_oh_3,{_zz_PcPlugin_logic_jump_oh_2,_zz_PcPlugin_logic_jump_oh_1}}))); _zz_PcPlugin_logic_jump_oh_6[4] = (_zz_PcPlugin_logic_jump_oh_5 && (! (|{_zz_PcPlugin_logic_jump_oh_4,{_zz_PcPlugin_logic_jump_oh_3,{_zz_PcPlugin_logic_jump_oh_2,_zz_PcPlugin_logic_jump_oh_1}}}))); _zz_PcPlugin_logic_jump_oh_6[5] = (_zz_PcPlugin_logic_jump_oh[5] && (! (|{_zz_PcPlugin_logic_jump_oh_5,{_zz_PcPlugin_logic_jump_oh_4,{_zz_PcPlugin_logic_jump_oh_3,{_zz_PcPlugin_logic_jump_oh_2,_zz_PcPlugin_logic_jump_oh_1}}}}))); assign PcPlugin_logic_jump_oh = _zz_PcPlugin_logic_jump_oh_6; assign PcPlugin_logic_jump_target = ((((PcPlugin_logic_jump_oh[0] ? PrivilegedPlugin_setup_jump_payload_pc : 40'h0000000000) | (PcPlugin_logic_jump_oh[1] ? CommitPlugin_setup_jump_payload_pc : 40'h0000000000)) | ((PcPlugin_logic_jump_oh[2] ? DecoderPredictionPlugin_setup_decodeJump_payload_pc : 40'h0000000000) | (PcPlugin_logic_jump_oh[3] ? AlignerPlugin_setup_sequenceJump_payload_pc : 40'h0000000000))) | (PcPlugin_logic_jump_oh[4] ? FetchCachePlugin_setup_redoJump_payload_pc : 40'h0000000000)); assign _zz_PcPlugin_logic_jump_target_1 = PcPlugin_logic_jump_oh[5]; assign when_PcPlugin_l55 = (|_zz_PcPlugin_logic_jump_target_1); assign PcPlugin_logic_jump_pcLoad_valid = (|{PrivilegedPlugin_setup_jump_valid,{CommitPlugin_setup_jump_valid,{BtbPlugin_setup_btbJump_valid,{DecoderPredictionPlugin_setup_decodeJump_valid,{AlignerPlugin_setup_sequenceJump_valid,FetchCachePlugin_setup_redoJump_valid}}}}}); assign PcPlugin_logic_jump_pcLoad_payload_pc = PcPlugin_logic_jump_target_1; if(PcPlugin_logic_jump_pcLoad_valid) begin if(PcPlugin_logic_jump_pcLoad_valid) begin PcPlugin_logic_fetchPc_pc = PcPlugin_logic_jump_pcLoad_payload_pc; if(PcPlugin_logic_jump_pcLoad_valid) begin
例えば jump_oh
の実装は以下の感じでめっちゃややこしくなっている。
assign _zz_PcPlugin_logic_jump_oh = {BtbPlugin_setup_btbJump_valid,{FetchCachePlugin_setup_redoJump_valid,{AlignerPlugin_setup_sequenceJump_valid,{DecoderPredictionPlugin_setup_decodeJump_valid,{CommitPlugin_setup_jump_valid,PrivilegedPlugin_setup_jump_valid}}}}}; assign _zz_PcPlugin_logic_jump_oh_1 = _zz_PcPlugin_logic_jump_oh[0]; assign _zz_PcPlugin_logic_jump_oh_2 = _zz_PcPlugin_logic_jump_oh[1]; assign _zz_PcPlugin_logic_jump_oh_3 = _zz_PcPlugin_logic_jump_oh[2]; assign _zz_PcPlugin_logic_jump_oh_4 = _zz_PcPlugin_logic_jump_oh[3]; assign _zz_PcPlugin_logic_jump_oh_5 = _zz_PcPlugin_logic_jump_oh[4]; _zz_PcPlugin_logic_jump_oh_6[0] = (_zz_PcPlugin_logic_jump_oh_1 && (! 1'b0)); _zz_PcPlugin_logic_jump_oh_6[1] = (_zz_PcPlugin_logic_jump_oh_2 && (! _zz_PcPlugin_logic_jump_oh_1)); _zz_PcPlugin_logic_jump_oh_6[2] = (_zz_PcPlugin_logic_jump_oh_3 && (! (|{_zz_PcPlugin_logic_jump_oh_2,_zz_PcPlugin_logic_jump_oh_1}))); _zz_PcPlugin_logic_jump_oh_6[3] = (_zz_PcPlugin_logic_jump_oh_4 && (! (|{_zz_PcPlugin_logic_jump_oh_3,{_zz_PcPlugin_logic_jump_oh_2,_zz_PcPlugin_logic_jump_oh_1}}))); _zz_PcPlugin_logic_jump_oh_6[4] = (_zz_PcPlugin_logic_jump_oh_5 && (! (|{_zz_PcPlugin_logic_jump_oh_4,{_zz_PcPlugin_logic_jump_oh_3,{_zz_PcPlugin_logic_jump_oh_2,_zz_PcPlugin_logic_jump_oh_1}}}))); _zz_PcPlugin_logic_jump_oh_6[5] = (_zz_PcPlugin_logic_jump_oh[5] && (! (|{_zz_PcPlugin_logic_jump_oh_5,{_zz_PcPlugin_logic_jump_oh_4,{_zz_PcPlugin_logic_jump_oh_3,{_zz_PcPlugin_logic_jump_oh_2,_zz_PcPlugin_logic_jump_oh_1}}}}))); assign PcPlugin_logic_jump_oh = _zz_PcPlugin_logic_jump_oh_6; assign PcPlugin_logic_jump_target = ((((PcPlugin_logic_jump_oh[0] ? PrivilegedPlugin_setup_jump_payload_pc : 40'h0000000000) | (PcPlugin_logic_jump_oh[1] ? CommitPlugin_setup_jump_payload_pc : 40'h0000000000)) | ((PcPlugin_logic_jump_oh[2] ? DecoderPredictionPlugin_setup_decodeJump_payload_pc : 40'h0000000000) | (PcPlugin_logic_jump_oh[3] ? AlignerPlugin_setup_sequenceJump_payload_pc : 40'h0000000000))) | (PcPlugin_logic_jump_oh[4] ? FetchCachePlugin_setup_redoJump_payload_pc : 40'h0000000000));
次のfetchPCがPCのインクリメントの部分だと思われる。
val fetchPc = new Area{ //PC calculation without Jump val output = Stream(PC) val pcReg = Reg(PC) init(resetVector) addAttribute(Verilator.public) val correction = False val correctionReg = RegInit(False) setWhen(correction) clearWhen(output.fire) val corrected = correction || correctionReg val pcRegPropagate = False val inc = RegInit(False) clearWhen(correction || pcRegPropagate) setWhen(output.fire) clearWhen(!output.valid && output.ready) val pc = pcReg + (U(inc) << sliceRange.high+1) val flushed = False when(inc) { pc(sliceRange) := 0 } when(jump.pcLoad.valid) { correction := True pc := jump.pcLoad.pc flushed := True } when(init.booted && (output.ready || correction || pcRegPropagate)){ pcReg := pc } pc(0) := False if(!RVC) pc(1) := False val fetcherHalt = False output.valid := !fetcherHalt && init.booted output.payload := pc }
これも以下のようにVerilogに変換されていた。
assign _zz_PcPlugin_logic_fetchPc_pc_1 = ({3'd0,PcPlugin_logic_fetchPc_inc} <<< 2'd3); assign _zz_PcPlugin_logic_fetchPc_pc = {36'd0, _zz_PcPlugin_logic_fetchPc_pc_1}; PcPlugin_logic_fetchPc_correction = 1'b0; PcPlugin_logic_fetchPc_correction = 1'b1; assign PcPlugin_logic_fetchPc_output_fire = (PcPlugin_logic_fetchPc_output_valid && PcPlugin_logic_fetchPc_output_ready); assign PcPlugin_logic_fetchPc_corrected = (PcPlugin_logic_fetchPc_correction || PcPlugin_logic_fetchPc_correctionReg); assign PcPlugin_logic_fetchPc_pcRegPropagate = 1'b0; assign when_PcPlugin_l82 = (PcPlugin_logic_fetchPc_correction || PcPlugin_logic_fetchPc_pcRegPropagate); assign when_PcPlugin_l82_1 = ((! PcPlugin_logic_fetchPc_output_valid) && PcPlugin_logic_fetchPc_output_ready); PcPlugin_logic_fetchPc_pc = (PcPlugin_logic_fetchPc_pcReg + _zz_PcPlugin_logic_fetchPc_pc); if(PcPlugin_logic_fetchPc_inc) begin PcPlugin_logic_fetchPc_pc[2 : 2] = 1'b0; PcPlugin_logic_fetchPc_pc = PcPlugin_logic_jump_pcLoad_payload_pc; PcPlugin_logic_fetchPc_pc[0] = 1'b0; PcPlugin_logic_fetchPc_pc[1] = 1'b0; PcPlugin_logic_fetchPc_flushed = 1'b0; PcPlugin_logic_fetchPc_flushed = 1'b1; assign when_PcPlugin_l98 = (PcPlugin_logic_init_booted && ((PcPlugin_logic_fetchPc_output_ready || PcPlugin_logic_fetchPc_correction) || PcPlugin_logic_fetchPc_pcRegPropagate)); assign PcPlugin_logic_fetchPc_fetcherHalt = 1'b0; assign PcPlugin_logic_fetchPc_output_valid = ((! PcPlugin_logic_fetchPc_fetcherHalt) && PcPlugin_logic_init_booted); assign PcPlugin_logic_fetchPc_output_payload = PcPlugin_logic_fetchPc_pc; assign PcPlugin_logic_fetchPc_output_ready = FetchPlugin_stages_0_ready; assign FetchPlugin_stages_0_valid = PcPlugin_logic_fetchPc_output_valid; assign FetchPlugin_stages_0_Fetch_FETCH_PC = PcPlugin_logic_fetchPc_output_payload; PcPlugin_logic_fetchPc_pcReg <= 40'h0080000000; PcPlugin_logic_fetchPc_correctionReg <= 1'b0; PcPlugin_logic_fetchPc_inc <= 1'b0; if(PcPlugin_logic_fetchPc_correction) begin PcPlugin_logic_fetchPc_correctionReg <= 1'b1; if(PcPlugin_logic_fetchPc_output_fire) begin PcPlugin_logic_fetchPc_correctionReg <= 1'b0; PcPlugin_logic_fetchPc_inc <= 1'b0; if(PcPlugin_logic_fetchPc_output_fire) begin PcPlugin_logic_fetchPc_inc <= 1'b1; PcPlugin_logic_fetchPc_inc <= 1'b0; PcPlugin_logic_fetchPc_pcReg <= PcPlugin_logic_fetchPc_pc;