1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
package vexriscv.ip.fpu
import spinal.core._
import spinal.lib.math.{UnsignedDividerCmd, UnsignedDividerRsp}
import spinal.lib._
import spinal.lib.sim.{StreamDriver, StreamMonitor, StreamReadyRandomizer}
import scala.collection.mutable
import scala.util.Random
case class FpuDivCmd(mantissaWidth : Int) extends Bundle{
val a,b = UInt(mantissaWidth bits)
}
case class FpuDivRsp(mantissaWidth : Int) extends Bundle{
val result = UInt(mantissaWidth+1 + 2 bits)
val remain = UInt(mantissaWidth+1 bits)
}
case class FpuDiv(val mantissaWidth : Int) extends Component {
assert(mantissaWidth % 2 == 0)
val io = new Bundle{
val input = slave Stream(FpuDivCmd(mantissaWidth))
val output = master Stream(FpuDivRsp(mantissaWidth))
}
val iterations = (mantissaWidth+2+2)/2
val counter = Reg(UInt(log2Up(iterations) bits))
val busy = RegInit(False) clearWhen(io.output.fire)
val done = RegInit(False) setWhen(busy && counter === iterations-1) clearWhen(io.output.fire)
val shifter = Reg(UInt(mantissaWidth + 3 bits))
val result = Reg(UInt(mantissaWidth+1+2 bits))
val div1, div3 = Reg(UInt(mantissaWidth+3 bits))
val div2 = div1 |<< 1
val sub1 = shifter -^ div1
val sub2 = shifter -^ div2
val sub3 = shifter -^ div3
io.output.valid := done
io.output.result := (result << 0).resized
io.output.remain := (shifter >> 2).resized
io.input.ready := !busy
when(!done){
counter := counter + 1
val sel = CombInit(shifter)
result := result |<< 2
when(!sub1.msb){
sel := sub1.resized
result(1 downto 0) := 1
}
when(!sub2.msb){
sel := sub2.resized
result(1 downto 0) := 2
}
when(!sub3.msb){
sel := sub3.resized
result(1 downto 0) := 3
}
shifter := sel |<< 2
}
when(!busy){
counter := 0
shifter := (U"1" @@ io.input.a @@ U"").resized
div1 := (U"1" @@ io.input.b).resized
div3 := (U"1" @@ io.input.b) +^ (((U"1" @@ io.input.b)) << 1)
busy := io.input.valid
}
}
object FpuDivTester extends App{
import spinal.core.sim._
for(w <- List(16, 20)) {
val config = SimConfig
config.withFstWave
config.compile(new FpuDiv(w)).doSim(seed=2){dut =>
dut.clockDomain.forkStimulus(10)
val (cmdDriver, cmdQueue) = StreamDriver.queue(dut.io.input, dut.clockDomain)
val rspQueue = mutable.Queue[FpuDivRsp => Unit]()
StreamMonitor(dut.io.output, dut.clockDomain)( rspQueue.dequeue()(_))
StreamReadyRandomizer(dut.io.output, dut.clockDomain)
def test(a : Int, b : Int): Unit ={
cmdQueue +={p =>
p.a #= a
p.b #= b
}
rspQueue += {p =>
val x = (a | (1 << dut.mantissaWidth)).toLong
val y = (b | (1 << dut.mantissaWidth)).toLong
val result = (x << dut.mantissaWidth+2) / y
val remain = (x << dut.mantissaWidth+2) % y
assert(p.result.toLong == result, f"$x%x/$y%x=${p.result.toLong}%x instead of $result%x")
assert(p.remain.toLong == remain, f"$x%x %% $y%x=${p.remain.toLong}%x instead of $remain%x")
}
}
val s = dut.mantissaWidth-16
val f = (1 << dut.mantissaWidth)-1
test(0xE000 << s, 0x8000 << s)
test(0xC000 << s, 0x4000 << s)
test(0xC835 << s, 0x4742 << s)
test(0,0)
test(0,f)
test(f,0)
test(f,f)
for(i <- 0 until 10000){
test(Random.nextInt(1 << dut.mantissaWidth), Random.nextInt(1 << dut.mantissaWidth))
}
waitUntil(rspQueue.isEmpty)
dut.clockDomain.waitSampling(100)
}
}
}
object FpuDivTester2 extends App{
val mantissaWidth = 52
val a = BigInt(0xfffffff810000l)
val b = BigInt(0x0000000000FF0l)
val x = (a | (1l << mantissaWidth))
val y = (b | (1l << mantissaWidth))
val result = (x << mantissaWidth+2) / y
val remain = (x << mantissaWidth+2) % y
println("done")
}
|