次はBOOMのFPUについて解析する。BOOMのFPUパイプラインは以下のファイルで定義されている。
src/main/scala/exu/fp-pipeline.scala
//********************************** // construct all of the modules val exe_units = new boom.exu.ExecutionUnits(fpu=true) val issue_unit = Module(new IssueUnitCollapsing( issueParams.find(_.iqType == IQT_FP.litValue).get, numWakeupPorts)) issue_unit.suggestName("fp_issue_unit") val fregfile = Module(new RegisterFileSynthesizable(numFpPhysRegs, exe_units.numFrfReadPorts, exe_units.numFrfWritePorts + memWidth, fLen+1, // No bypassing for any FP units, + memWidth for ll_wb Seq.fill(exe_units.numFrfWritePorts + memWidth){ false } ))
fregfile
はFPUのレジスタファイルだが、ワード数は定義通りだとしても、ビット幅がfLEN+1
で定義されている。これはFPUがHardFloatのRecodedフォーマットなので、fLEN
+1ビット必要という訳だ。
実行ユニットは、FPU(fpu=1)の場合はHardFloatのモジュールがインスタンス化されるようになっている。
class ExecutionUnits(val fpu: Boolean)(implicit val p: Parameters) extends HasBoomCoreParameters { val totalIssueWidth = issueParams.map(_.issueWidth).sum
} else { val fp_width = issueParams.find(_.iqType == IQT_FP.litValue).get.issueWidth for (w <- 0 until fp_width) { val fpu_exe_unit = Module(new FPUExeUnit(hasFpu = true, hasFdiv = usingFDivSqrt && (w==0), hasFpiu = (w==0))) exe_units += fpu_exe_unit } }
FPUExeUnit
の中身は以下のようになっている。パラメータとして、FP除算をサポートするか、整数との変換をサポートするかを指定できる。
class FPUExeUnit( hasFpu : Boolean = true, hasFdiv : Boolean = false, hasFpiu : Boolean = false ) (implicit p: Parameters) extends ExecutionUnit( readsFrf = true, writesFrf = true, writesLlIrf = hasFpiu, writesIrf = false, numBypassStages = 0, dataWidth = p(tile.TileKey).core.fpu.get.fLen + 1, bypassable = false, hasFpu = hasFpu, hasFdiv = hasFdiv, hasFpiu = hasFpiu) with tile.HasFPUParameters {
FPUUnit
がおそらくFMAの実体らしい。
// FPU Unit ----------------------- var fpu: FPUUnit = null val fpu_resp_val = WireInit(false.B) val fpu_resp_fflags = Wire(new ValidIO(new FFlagsResp())) fpu_resp_fflags.valid := false.B if (hasFpu) { fpu = Module(new FPUUnit()) fpu.io.req.valid := io.req.valid && (io.req.bits.uop.fu_code_is(FU_FPU) || io.req.bits.uop.fu_code_is(FU_F2I)) // TODO move to using a separate unit fpu.io.req.bits.uop := io.req.bits.uop fpu.io.req.bits.rs1_data := io.req.bits.rs1_data fpu.io.req.bits.rs2_data := io.req.bits.rs2_data fpu.io.req.bits.rs3_data := io.req.bits.rs3_data fpu.io.req.bits.pred_data := false.B fpu.io.req.bits.kill := io.req.bits.kill fpu.io.fcsr_rm := io.fcsr_rm fpu.io.brupdate := io.brupdate fpu.io.resp.ready := DontCare fpu_resp_val := fpu.io.resp.valid fpu_resp_fflags := fpu.io.resp.bits.fflags fu_units += fpu }
FPUUnit
から先は見たことのあるHardFloatの実装となっていた。
class FPUUnit(implicit p: Parameters) extends PipelinedFunctionalUnit( numStages = p(tile.TileKey).core.fpu.get.dfmaLatency, numBypassStages = 0, earliestBypassStage = 0, dataWidth = 65, needsFcsr = true)