fpu add FCVT_X_X
This commit is contained in:
parent
82dfd10dba
commit
9a25a12879
|
@ -223,6 +223,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{
|
|||
is(p.Opcode.FMV_X_W) { useRs1 := True }
|
||||
is(p.Opcode.FMV_W_X) { useRd := True }
|
||||
is(p.Opcode.FCLASS ) { useRs1 := True }
|
||||
is(p.Opcode.FCVT_X_X ) { useRd := True; useRs1 := True }
|
||||
}
|
||||
|
||||
val hits = List((useRs1, s0.rs1), (useRs2, s0.rs2), (useRs3, s0.rs3), (useRd, s0.rd)).map{case (use, reg) => use && rf.lock.map(l => l.valid && l.source === s0.source && l.address === reg).orR}
|
||||
|
@ -289,7 +290,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{
|
|||
load.payload.assignSomeByName(read.output.payload)
|
||||
load.i2f := input.opcode === FpuOpcode.I2F
|
||||
|
||||
val shortPipHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FCLASS).map(input.opcode === _).orR
|
||||
val shortPipHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FCLASS, FpuOpcode.FCVT_X_X).map(input.opcode === _).orR
|
||||
val shortPip = Stream(ShortPipInput())
|
||||
input.ready setWhen(shortPipHit && shortPip.ready)
|
||||
shortPip.valid := input.valid && shortPipHit
|
||||
|
@ -715,8 +716,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{
|
|||
)
|
||||
|
||||
|
||||
val minMaxResult = ((rs1Smaller ^ input.arg(0)) && !input.rs1.isNan || input.rs2.isNan) ? input.rs1 | input.rs2
|
||||
when(input.rs1.isNan && input.rs2.isNan) { minMaxResult.setNanQuiet }
|
||||
val minMaxSelectRs2 = !(((rs1Smaller ^ input.arg(0)) && !input.rs1.isNan || input.rs2.isNan))
|
||||
val minMaxSelectNanQuiet = input.rs1.isNan && input.rs2.isNan
|
||||
val cmpResult = B(rs1Smaller && !bothZero && !input.arg(1) || (rs1Equal || bothZero) && !input.arg(0))
|
||||
when(input.rs1.isNan || input.rs2.isNan) { cmpResult := 0 }
|
||||
val sgnjResult = (input.rs1.sign && input.arg(1)) ^ input.rs2.sign ^ input.arg(0)
|
||||
|
@ -742,7 +743,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{
|
|||
is(FpuOpcode.FCLASS) { result(31 downto 0) := fclassResult.resized }
|
||||
}
|
||||
|
||||
val toFpuRf = List(FpuOpcode.MIN_MAX, FpuOpcode.SGNJ).map(input.opcode === _).orR
|
||||
val toFpuRf = List(FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FCVT_X_X).map(input.opcode === _).orR
|
||||
|
||||
rfOutput.valid := input.valid && toFpuRf && !halt
|
||||
rfOutput.source := input.source
|
||||
|
@ -751,19 +752,31 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{
|
|||
rfOutput.roundMode := input.roundMode
|
||||
if(p.withDouble) rfOutput.format := input.format
|
||||
rfOutput.scrap := False
|
||||
rfOutput.value.assignDontCare()
|
||||
switch(input.opcode){
|
||||
is(FpuOpcode.MIN_MAX){
|
||||
rfOutput.value.sign := minMaxResult.sign
|
||||
rfOutput.value.exponent := minMaxResult.exponent
|
||||
rfOutput.value.mantissa := minMaxResult.mantissa @@ U"0"
|
||||
rfOutput.value.special := minMaxResult.special
|
||||
}
|
||||
is(FpuOpcode.SGNJ){
|
||||
rfOutput.value.sign := sgnjResult
|
||||
rfOutput.value.sign := input.rs1.sign
|
||||
rfOutput.value.exponent := input.rs1.exponent
|
||||
rfOutput.value.mantissa := input.rs1.mantissa @@ U"0"
|
||||
rfOutput.value.special := input.rs1.special
|
||||
|
||||
switch(input.opcode){
|
||||
is(FpuOpcode.MIN_MAX){
|
||||
when(minMaxSelectRs2) {
|
||||
rfOutput.value.sign := input.rs2.sign
|
||||
rfOutput.value.exponent := input.rs2.exponent
|
||||
rfOutput.value.mantissa := input.rs2.mantissa @@ U"0"
|
||||
rfOutput.value.special := input.rs2.special
|
||||
}
|
||||
when(minMaxSelectNanQuiet){
|
||||
rfOutput.value.setNanQuiet
|
||||
}
|
||||
}
|
||||
is(FpuOpcode.SGNJ){
|
||||
rfOutput.value.sign := sgnjResult
|
||||
}
|
||||
if(p.withDouble) is(FpuOpcode.FCVT_X_X){
|
||||
rfOutput.format := ((input.format === FpuFormat.FLOAT) ? FpuFormat.DOUBLE | FpuFormat.FLOAT)
|
||||
when(input.rs1.isNan){
|
||||
rfOutput.value.setNanQuiet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -772,7 +785,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{
|
|||
val rs2Nan = input.rs2.isNan
|
||||
val rs1NanNv = input.rs1.isNan && (!input.rs1.isQuiet || signalQuiet)
|
||||
val rs2NanNv = input.rs2.isNan && (!input.rs2.isQuiet || signalQuiet)
|
||||
val nv = (input.opcode === FpuOpcode.CMP || input.opcode === FpuOpcode.MIN_MAX) && (rs1NanNv || rs2NanNv)
|
||||
val nv = List(FpuOpcode.CMP, FpuOpcode.MIN_MAX, FpuOpcode.FCVT_X_X).map(input.opcode === _).orR && rs1NanNv ||
|
||||
List(FpuOpcode.CMP, FpuOpcode.MIN_MAX).map(input.opcode === _).orR && rs2NanNv
|
||||
flag.NV setWhen(input.valid && nv)
|
||||
|
||||
input.ready := !halt && (toFpuRf ? rfOutput.ready | io.port.map(_.rsp.ready).read(input.source))
|
||||
|
|
|
@ -85,7 +85,7 @@ case class FpuFloat(exponentSize: Int,
|
|||
}
|
||||
|
||||
object FpuOpcode extends SpinalEnum{
|
||||
val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP, DIV, SQRT, MIN_MAX, SGNJ, FMV_X_W, FMV_W_X, FCLASS = newElement()
|
||||
val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP, DIV, SQRT, MIN_MAX, SGNJ, FMV_X_W, FMV_W_X, FCLASS, FCVT_X_X = newElement()
|
||||
}
|
||||
|
||||
object FpuFormat extends SpinalEnum{
|
||||
|
|
|
@ -102,6 +102,8 @@ class FpuPlugin(externalFpu : Boolean = false,
|
|||
FMV_W_X -> (fmvWx)
|
||||
))
|
||||
|
||||
//TODO FMV_X_X + doubles
|
||||
|
||||
port = FpuPort(p)
|
||||
if(externalFpu) master(port)
|
||||
|
||||
|
|
|
@ -130,6 +130,18 @@ class FpuTest extends FunSuite{
|
|||
val a,b = (s.nextLong(16))
|
||||
(b2d(a), b2d(b), s.nextInt(16))
|
||||
}
|
||||
|
||||
|
||||
def f32_f64_i32 = {
|
||||
val s = new Scanner(next)
|
||||
val a,b = nextLong(s)
|
||||
(b2f(a.toInt), b2d(b), s.nextInt(16))
|
||||
}
|
||||
def f64_f32_i32 = {
|
||||
val s = new Scanner(next)
|
||||
val a,b = nextLong(s)
|
||||
(b2d(a), b2f(b.toInt), s.nextInt(16))
|
||||
}
|
||||
}
|
||||
lazy val RAW = build("")
|
||||
lazy val RNE = build("-rnear_even")
|
||||
|
@ -168,12 +180,16 @@ class FpuTest extends FunSuite{
|
|||
val sgnjx = new TestCase(s"${f}_eq")
|
||||
val sqrt = new TestCase(s"${f}_sqrt")
|
||||
val div = new TestCase(s"${f}_div")
|
||||
val f32 = new TestCase(s"${f}_eq")
|
||||
val f64 = new TestCase(s"${f}_eq")
|
||||
}
|
||||
|
||||
val f32 = new TestVector("f32")
|
||||
val f64 = new TestVector("f64")
|
||||
val f32 = new TestVector("f32"){
|
||||
val f64 = new TestCase(s"f32_eq")
|
||||
val cvt64 = new TestCase(s"f32_to_f64")
|
||||
}
|
||||
val f64 = new TestVector("f64"){
|
||||
val f32 = new TestCase(s"f64_eq")
|
||||
val cvt32 = new TestCase(s"f64_to_f32")
|
||||
}
|
||||
|
||||
val cpus = for(id <- 0 until portCount) yield new {
|
||||
val cmdQueue = mutable.Queue[FpuCmd => Unit]()
|
||||
|
@ -201,7 +217,7 @@ class FpuTest extends FunSuite{
|
|||
|
||||
def flagMatch(ref : Int, report : String): Unit ={
|
||||
waitUntil(pendingMiaou == 0)
|
||||
softAssert(flagAccumulator == ref, s"Flag missmatch dut=$flagAccumulator ref=$ref $report")
|
||||
assert(flagAccumulator == ref, s"Flag missmatch dut=$flagAccumulator ref=$ref $report")
|
||||
flagAccumulator = 0
|
||||
}
|
||||
def flagClear(): Unit ={
|
||||
|
@ -586,6 +602,27 @@ class FpuTest extends FunSuite{
|
|||
}
|
||||
|
||||
|
||||
def testCvtF32F64Raw(a : Float, ref : Double, flag : Int, rounding : FpuRoundMode.E): Unit ={
|
||||
val rs, rd = Random.nextInt(32)
|
||||
load(rs, a)
|
||||
fpuF2f(rd, rs, Random.nextInt(32), Random.nextInt(32), FpuOpcode.FCVT_X_X, Random.nextInt(3), rounding, FpuFormat.FLOAT)
|
||||
store(rd){v =>
|
||||
assert(d2b(v) == d2b(ref), f"testCvtF32F64Raw $a $ref $rounding")
|
||||
}
|
||||
flagMatch(flag, f"testCvtF32F64Raw $a $ref $rounding")
|
||||
}
|
||||
|
||||
def testCvtF64F32Raw(a : Double, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={
|
||||
val rs, rd = Random.nextInt(32)
|
||||
load(rs, a)
|
||||
fpuF2f(rd, rs, Random.nextInt(32), Random.nextInt(32), FpuOpcode.FCVT_X_X, Random.nextInt(3), rounding, FpuFormat.DOUBLE)
|
||||
storeFloat(rd){v =>
|
||||
assert(d2b(v) == d2b(ref), f"testCvtF64F32Raw $a $ref $rounding")
|
||||
}
|
||||
flagMatch(flag, f"testCvtF64F32Raw $a $ref $rounding")
|
||||
}
|
||||
|
||||
|
||||
def testClassRaw(a : Float) : Unit = {
|
||||
val rd = Random.nextInt(32)
|
||||
|
||||
|
@ -620,48 +657,12 @@ class FpuTest extends FunSuite{
|
|||
fma(rd,rs1,rs2,rs3, FpuRoundMode.RNE, FpuFormat.FLOAT)
|
||||
storeFloat(rd){v =>
|
||||
val ref = a.toDouble * b.toDouble + c.toDouble
|
||||
println(f"$a%.20f * $b%.20f + $c%.20f = $v%.20f, $ref%.20f")
|
||||
val mul = a.toDouble * b.toDouble
|
||||
if((mul.abs-c.abs)/mul.abs > 0.1) assert(checkFloat(ref.toFloat, v))
|
||||
if((mul.abs-c.abs)/mul.abs > 0.1) assert(checkFloat(ref.toFloat, v), f"$a%.20f * $b%.20f + $c%.20f = $v%.20f, $ref%.20f")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def testDivRaw(a : Float, b : Float): Unit ={
|
||||
val rs = new RegAllocator()
|
||||
val rs1, rs2, rs3 = rs.allocate()
|
||||
val rd = Random.nextInt(32)
|
||||
load(rs1, a)
|
||||
load(rs2, b)
|
||||
|
||||
div(rd,rs1,rs2, FpuRoundMode.RNE, FpuFormat.FLOAT)
|
||||
storeFloat(rd){v =>
|
||||
val refUnclamped = a/b
|
||||
val refClamped = ((a)/(b))
|
||||
val ref = refClamped
|
||||
val error = Math.abs(ref-v)/ref
|
||||
println(f"$a / $b = $v, $ref $error")
|
||||
assert(checkFloat(ref, v))
|
||||
}
|
||||
}
|
||||
|
||||
def testSqrtRaw(a : Float): Unit ={
|
||||
val rs = new RegAllocator()
|
||||
val rs1, rs2, rs3 = rs.allocate()
|
||||
val rd = Random.nextInt(32)
|
||||
load(rs1, a)
|
||||
|
||||
sqrt(rd,rs1, FpuRoundMode.RNE, FpuFormat.FLOAT)
|
||||
storeFloat(rd){v =>
|
||||
val ref = Math.sqrt(a).toFloat
|
||||
val error = Math.abs(ref-v)/ref
|
||||
println(f"sqrt($a) = $v, $ref $error")
|
||||
assert(checkFloat(ref, v))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
def testSqrtExact(a : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={
|
||||
val rs = new RegAllocator()
|
||||
val rs1, rs2, rs3 = rs.allocate()
|
||||
|
@ -671,8 +672,7 @@ class FpuTest extends FunSuite{
|
|||
sqrt(rd,rs1, FpuRoundMode.RNE, FpuFormat.FLOAT)
|
||||
storeFloat(rd){v =>
|
||||
val error = Math.abs(ref-v)/ref
|
||||
println(f"sqrt($a) = $v, $ref $error $rounding")
|
||||
assert(checkFloat(ref, v))
|
||||
assert(checkFloat(ref, v), f"sqrt($a) = $v, $ref $error $rounding")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -686,8 +686,7 @@ class FpuTest extends FunSuite{
|
|||
div(rd,rs1, rs2, FpuRoundMode.RNE, FpuFormat.FLOAT)
|
||||
storeFloat(rd){v =>
|
||||
val error = Math.abs(ref-v)/ref
|
||||
println(f"div($a, $b) = $v, $ref $error $rounding")
|
||||
assert(checkFloat(ref, v))
|
||||
assert(checkFloat(ref, v), f"div($a, $b) = $v, $ref $error $rounding")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -975,6 +974,16 @@ class FpuTest extends FunSuite{
|
|||
testTransferF32F64Raw(a, Random.nextBoolean())
|
||||
}
|
||||
|
||||
def testCvtF32F64() : Unit = {
|
||||
val rounding = FpuRoundMode.elements.randomPick()
|
||||
val (a,r,f) = f32.cvt64(rounding).f32_f64_i32
|
||||
testCvtF32F64Raw(a, r, f, rounding)
|
||||
}
|
||||
def testCvtF64F32() : Unit = {
|
||||
val rounding = FpuRoundMode.elements.randomPick()
|
||||
val (a,r,f) = f64.cvt32(rounding).f64_f32_i32
|
||||
testCvtF64F32Raw(a, r, f, rounding)
|
||||
}
|
||||
|
||||
def testClass() : Unit = {
|
||||
val (a,b,r,f) = f32.fclass.RAW.f32_f32_i32
|
||||
|
@ -1057,6 +1066,12 @@ class FpuTest extends FunSuite{
|
|||
//TODO test boxing
|
||||
//TODO double <-> simple convertions
|
||||
if(p.withDouble) {
|
||||
for(_ <- 0 until 10000) testCvtF32F64()
|
||||
println("FCVT_S_D done")
|
||||
for(_ <- 0 until 10000) testCvtF64F32()
|
||||
println("FCVT_D_S done")
|
||||
|
||||
|
||||
|
||||
for(_ <- 0 until 10000) testAddF64()
|
||||
for(_ <- 0 until 10000) testSubF64()
|
||||
|
|
Loading…
Reference in New Issue