fpu add FCVT_X_X

This commit is contained in:
Dolu1990 2021-02-11 17:40:35 +01:00
parent 82dfd10dba
commit 9a25a12879
4 changed files with 92 additions and 61 deletions

View File

@ -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))

View File

@ -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{

View File

@ -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)

View File

@ -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()