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_X_W) { useRs1 := True }
|
||||||
is(p.Opcode.FMV_W_X) { useRd := True }
|
is(p.Opcode.FMV_W_X) { useRd := True }
|
||||||
is(p.Opcode.FCLASS ) { useRs1 := 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}
|
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.payload.assignSomeByName(read.output.payload)
|
||||||
load.i2f := input.opcode === FpuOpcode.I2F
|
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())
|
val shortPip = Stream(ShortPipInput())
|
||||||
input.ready setWhen(shortPipHit && shortPip.ready)
|
input.ready setWhen(shortPipHit && shortPip.ready)
|
||||||
shortPip.valid := input.valid && shortPipHit
|
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
|
val minMaxSelectRs2 = !(((rs1Smaller ^ input.arg(0)) && !input.rs1.isNan || input.rs2.isNan))
|
||||||
when(input.rs1.isNan && input.rs2.isNan) { minMaxResult.setNanQuiet }
|
val minMaxSelectNanQuiet = input.rs1.isNan && input.rs2.isNan
|
||||||
val cmpResult = B(rs1Smaller && !bothZero && !input.arg(1) || (rs1Equal || bothZero) && !input.arg(0))
|
val cmpResult = B(rs1Smaller && !bothZero && !input.arg(1) || (rs1Equal || bothZero) && !input.arg(0))
|
||||||
when(input.rs1.isNan || input.rs2.isNan) { cmpResult := 0 }
|
when(input.rs1.isNan || input.rs2.isNan) { cmpResult := 0 }
|
||||||
val sgnjResult = (input.rs1.sign && input.arg(1)) ^ input.rs2.sign ^ input.arg(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 }
|
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.valid := input.valid && toFpuRf && !halt
|
||||||
rfOutput.source := input.source
|
rfOutput.source := input.source
|
||||||
|
@ -751,19 +752,31 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{
|
||||||
rfOutput.roundMode := input.roundMode
|
rfOutput.roundMode := input.roundMode
|
||||||
if(p.withDouble) rfOutput.format := input.format
|
if(p.withDouble) rfOutput.format := input.format
|
||||||
rfOutput.scrap := False
|
rfOutput.scrap := False
|
||||||
rfOutput.value.assignDontCare()
|
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){
|
switch(input.opcode){
|
||||||
is(FpuOpcode.MIN_MAX){
|
is(FpuOpcode.MIN_MAX){
|
||||||
rfOutput.value.sign := minMaxResult.sign
|
when(minMaxSelectRs2) {
|
||||||
rfOutput.value.exponent := minMaxResult.exponent
|
rfOutput.value.sign := input.rs2.sign
|
||||||
rfOutput.value.mantissa := minMaxResult.mantissa @@ U"0"
|
rfOutput.value.exponent := input.rs2.exponent
|
||||||
rfOutput.value.special := minMaxResult.special
|
rfOutput.value.mantissa := input.rs2.mantissa @@ U"0"
|
||||||
|
rfOutput.value.special := input.rs2.special
|
||||||
|
}
|
||||||
|
when(minMaxSelectNanQuiet){
|
||||||
|
rfOutput.value.setNanQuiet
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is(FpuOpcode.SGNJ){
|
is(FpuOpcode.SGNJ){
|
||||||
rfOutput.value.sign := sgnjResult
|
rfOutput.value.sign := sgnjResult
|
||||||
rfOutput.value.exponent := input.rs1.exponent
|
}
|
||||||
rfOutput.value.mantissa := input.rs1.mantissa @@ U"0"
|
if(p.withDouble) is(FpuOpcode.FCVT_X_X){
|
||||||
rfOutput.value.special := input.rs1.special
|
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 rs2Nan = input.rs2.isNan
|
||||||
val rs1NanNv = input.rs1.isNan && (!input.rs1.isQuiet || signalQuiet)
|
val rs1NanNv = input.rs1.isNan && (!input.rs1.isQuiet || signalQuiet)
|
||||||
val rs2NanNv = input.rs2.isNan && (!input.rs2.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)
|
flag.NV setWhen(input.valid && nv)
|
||||||
|
|
||||||
input.ready := !halt && (toFpuRf ? rfOutput.ready | io.port.map(_.rsp.ready).read(input.source))
|
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{
|
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{
|
object FpuFormat extends SpinalEnum{
|
||||||
|
|
|
@ -102,6 +102,8 @@ class FpuPlugin(externalFpu : Boolean = false,
|
||||||
FMV_W_X -> (fmvWx)
|
FMV_W_X -> (fmvWx)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
//TODO FMV_X_X + doubles
|
||||||
|
|
||||||
port = FpuPort(p)
|
port = FpuPort(p)
|
||||||
if(externalFpu) master(port)
|
if(externalFpu) master(port)
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,18 @@ class FpuTest extends FunSuite{
|
||||||
val a,b = (s.nextLong(16))
|
val a,b = (s.nextLong(16))
|
||||||
(b2d(a), b2d(b), s.nextInt(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 RAW = build("")
|
||||||
lazy val RNE = build("-rnear_even")
|
lazy val RNE = build("-rnear_even")
|
||||||
|
@ -168,12 +180,16 @@ class FpuTest extends FunSuite{
|
||||||
val sgnjx = new TestCase(s"${f}_eq")
|
val sgnjx = new TestCase(s"${f}_eq")
|
||||||
val sqrt = new TestCase(s"${f}_sqrt")
|
val sqrt = new TestCase(s"${f}_sqrt")
|
||||||
val div = new TestCase(s"${f}_div")
|
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 f32 = new TestVector("f32"){
|
||||||
val f64 = new TestVector("f64")
|
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 cpus = for(id <- 0 until portCount) yield new {
|
||||||
val cmdQueue = mutable.Queue[FpuCmd => Unit]()
|
val cmdQueue = mutable.Queue[FpuCmd => Unit]()
|
||||||
|
@ -201,7 +217,7 @@ class FpuTest extends FunSuite{
|
||||||
|
|
||||||
def flagMatch(ref : Int, report : String): Unit ={
|
def flagMatch(ref : Int, report : String): Unit ={
|
||||||
waitUntil(pendingMiaou == 0)
|
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
|
flagAccumulator = 0
|
||||||
}
|
}
|
||||||
def flagClear(): Unit ={
|
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 = {
|
def testClassRaw(a : Float) : Unit = {
|
||||||
val rd = Random.nextInt(32)
|
val rd = Random.nextInt(32)
|
||||||
|
|
||||||
|
@ -620,48 +657,12 @@ class FpuTest extends FunSuite{
|
||||||
fma(rd,rs1,rs2,rs3, FpuRoundMode.RNE, FpuFormat.FLOAT)
|
fma(rd,rs1,rs2,rs3, FpuRoundMode.RNE, FpuFormat.FLOAT)
|
||||||
storeFloat(rd){v =>
|
storeFloat(rd){v =>
|
||||||
val ref = a.toDouble * b.toDouble + c.toDouble
|
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
|
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 ={
|
def testSqrtExact(a : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={
|
||||||
val rs = new RegAllocator()
|
val rs = new RegAllocator()
|
||||||
val rs1, rs2, rs3 = rs.allocate()
|
val rs1, rs2, rs3 = rs.allocate()
|
||||||
|
@ -671,8 +672,7 @@ class FpuTest extends FunSuite{
|
||||||
sqrt(rd,rs1, FpuRoundMode.RNE, FpuFormat.FLOAT)
|
sqrt(rd,rs1, FpuRoundMode.RNE, FpuFormat.FLOAT)
|
||||||
storeFloat(rd){v =>
|
storeFloat(rd){v =>
|
||||||
val error = Math.abs(ref-v)/ref
|
val error = Math.abs(ref-v)/ref
|
||||||
println(f"sqrt($a) = $v, $ref $error $rounding")
|
assert(checkFloat(ref, v), f"sqrt($a) = $v, $ref $error $rounding")
|
||||||
assert(checkFloat(ref, v))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -686,8 +686,7 @@ class FpuTest extends FunSuite{
|
||||||
div(rd,rs1, rs2, FpuRoundMode.RNE, FpuFormat.FLOAT)
|
div(rd,rs1, rs2, FpuRoundMode.RNE, FpuFormat.FLOAT)
|
||||||
storeFloat(rd){v =>
|
storeFloat(rd){v =>
|
||||||
val error = Math.abs(ref-v)/ref
|
val error = Math.abs(ref-v)/ref
|
||||||
println(f"div($a, $b) = $v, $ref $error $rounding")
|
assert(checkFloat(ref, v), f"div($a, $b) = $v, $ref $error $rounding")
|
||||||
assert(checkFloat(ref, v))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -975,6 +974,16 @@ class FpuTest extends FunSuite{
|
||||||
testTransferF32F64Raw(a, Random.nextBoolean())
|
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 = {
|
def testClass() : Unit = {
|
||||||
val (a,b,r,f) = f32.fclass.RAW.f32_f32_i32
|
val (a,b,r,f) = f32.fclass.RAW.f32_f32_i32
|
||||||
|
@ -1057,6 +1066,12 @@ class FpuTest extends FunSuite{
|
||||||
//TODO test boxing
|
//TODO test boxing
|
||||||
//TODO double <-> simple convertions
|
//TODO double <-> simple convertions
|
||||||
if(p.withDouble) {
|
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) testAddF64()
|
||||||
for(_ <- 0 until 10000) testSubF64()
|
for(_ <- 0 until 10000) testSubF64()
|
||||||
|
|
Loading…
Reference in New Issue