mirror of
https://github.com/antonblanchard/chiselwatt.git
synced 2026-01-11 23:53:33 +00:00
Merge pull request #22 from antonblanchard/fix-divide
Complete divide support
This commit is contained in:
commit
121d967375
@ -1,8 +1,6 @@
|
||||
import chisel3._
|
||||
import chisel3.util.{Valid, Decoupled, log2Ceil}
|
||||
|
||||
import Helpers._
|
||||
|
||||
class DividerInput(val bits: Int) extends Bundle {
|
||||
val dividend = UInt(bits.W)
|
||||
val divisor = UInt(bits.W)
|
||||
@ -22,8 +20,11 @@ class SimpleDivider(val bits: Int) extends Module {
|
||||
val divisor = Reg(UInt(bits.W))
|
||||
val quotient = Reg(UInt(bits.W))
|
||||
val is32bit = Reg(Bool())
|
||||
//val signed = Reg(Bool())
|
||||
val negativeResult = Reg(Bool())
|
||||
val signed = Reg(Bool())
|
||||
val modulus = Reg(Bool())
|
||||
val overflow = Reg(UInt(1.W))
|
||||
val overflow32 = Reg(UInt(1.W))
|
||||
val count = Reg(UInt(log2Ceil(bits+1).W))
|
||||
val busy = RegInit(false.B)
|
||||
|
||||
@ -31,25 +32,38 @@ class SimpleDivider(val bits: Int) extends Module {
|
||||
|
||||
when (io.in.valid && !busy) {
|
||||
when (io.in.bits.is32bit) {
|
||||
when (io.in.bits.extended) {
|
||||
dividend := io.in.bits.dividend(31, 0) ## 0.U(32.W)
|
||||
val dividendTemp = WireDefault(io.in.bits.dividend(31, 0))
|
||||
when (io.in.bits.signed) {
|
||||
dividendTemp := io.in.bits.dividend(31, 0).asSInt.abs().asUInt
|
||||
divisor := io.in.bits.divisor(31, 0).asSInt.abs().asUInt
|
||||
negativeResult := (io.in.bits.dividend(31) =/= io.in.bits.divisor(31))
|
||||
} .otherwise {
|
||||
dividend := io.in.bits.dividend(31, 0)
|
||||
divisor := io.in.bits.divisor(31, 0)
|
||||
negativeResult := 0.U
|
||||
}
|
||||
divisor := io.in.bits.divisor(31, 0)
|
||||
|
||||
dividend := Mux(io.in.bits.extended, dividendTemp ## 0.U(32.W), dividendTemp)
|
||||
} .otherwise {
|
||||
when (io.in.bits.extended) {
|
||||
dividend := io.in.bits.dividend ## 0.U(bits.W)
|
||||
val dividendTemp = WireDefault(io.in.bits.dividend)
|
||||
when (io.in.bits.signed) {
|
||||
dividendTemp := io.in.bits.dividend.asSInt.abs().asUInt
|
||||
divisor := io.in.bits.divisor.asSInt.abs().asUInt
|
||||
negativeResult := (io.in.bits.dividend(bits-1) =/= io.in.bits.divisor(bits-1))
|
||||
} .otherwise {
|
||||
dividend := 0.U((bits+1).W) ## io.in.bits.dividend
|
||||
divisor := io.in.bits.divisor
|
||||
negativeResult := 0.U
|
||||
}
|
||||
divisor := io.in.bits.divisor
|
||||
|
||||
dividend := Mux(io.in.bits.extended, dividendTemp ## 0.U(bits.W), dividendTemp)
|
||||
}
|
||||
|
||||
is32bit := io.in.bits.is32bit
|
||||
quotient := 0.U
|
||||
count := 0.U
|
||||
signed := io.in.bits.signed
|
||||
modulus := io.in.bits.modulus
|
||||
overflow := 0.U
|
||||
overflow32 := 0.U
|
||||
count := 0.U
|
||||
busy := true.B
|
||||
}
|
||||
|
||||
@ -61,21 +75,27 @@ class SimpleDivider(val bits: Int) extends Module {
|
||||
dividend := dividend((bits*2-1), 0) ## 0.U(1.W)
|
||||
quotient := quotient(bits-2, 0) ## 0.U(1.W)
|
||||
}
|
||||
|
||||
overflow := quotient(bits-1)
|
||||
overflow32 := overflow32 | quotient(32-1)
|
||||
count := count + 1.U
|
||||
}
|
||||
|
||||
// Did we shift out a 1? This also handles divide by zero
|
||||
val overflow = Reg(Bool())
|
||||
overflow := quotient(bits-1)
|
||||
val sResult = Mux(negativeResult, -(0.U(1.W) ## quotient), 0.U(1.W) ## quotient)
|
||||
|
||||
// Catch unsigned and signed overflow, from Paul
|
||||
val resultOverflow = WireDefault(false.B)
|
||||
when (is32bit) {
|
||||
overflow := quotient(63, 31).orR
|
||||
resultOverflow := overflow32.asBool || (signed && (sResult(32) ^ sResult(32-1)))
|
||||
} .otherwise {
|
||||
resultOverflow := overflow.asBool || (signed && (sResult(bits) ^ sResult(bits-1)))
|
||||
}
|
||||
|
||||
val result = WireDefault(quotient)
|
||||
when (overflow) {
|
||||
val result = WireDefault(sResult(bits-1, 0))
|
||||
when (resultOverflow) {
|
||||
result := 0.U
|
||||
} .elsewhen (is32bit && !modulus) {
|
||||
result := 0.U(32.W) ## quotient(31, 0)
|
||||
result := sResult(31, 0)
|
||||
}
|
||||
|
||||
io.out.bits := RegNext(result)
|
||||
|
||||
@ -14,29 +14,55 @@ class SimpleDividerUnitTester extends FlatSpec with ChiselScalatestTester with M
|
||||
y <- testValuesRealShort
|
||||
} yield (x, y)
|
||||
|
||||
def divide(a: BigInt, b: BigInt): BigInt = (a / b) & BigInt("ffffffffffffffff", 16)
|
||||
def twosComplement(a: BigInt, bits: Int) = (~a+1) & ((BigInt("1") << bits) - 1)
|
||||
def addSign(a: BigInt, bits: Int) = if (a.testBit(bits-1)) -twosComplement(a, bits) else a
|
||||
def removeSign(a: BigInt, bits: Int) = if (a < 0) twosComplement(-a, bits) else a
|
||||
|
||||
def divideExtended(a: BigInt, b: BigInt): BigInt = (((a << 64) / b) >> 64) & BigInt("ffffffffffffffff", 16)
|
||||
def divide(a: BigInt, b: BigInt): BigInt = if (b == 0) 0 else (a / b)
|
||||
|
||||
def divideSigned(a: BigInt, b: BigInt): BigInt = {
|
||||
val d = removeSign(divide(addSign(a, 64), addSign(b, 64)), 65)
|
||||
|
||||
// Check for overflow
|
||||
if (d.testBit(64) != d.testBit(64-1)) 0 else (d & ~(BigInt("1") << 64))
|
||||
}
|
||||
|
||||
def divideExtended(a: BigInt, b: BigInt): BigInt = {
|
||||
val d = divide((a << 64), b)
|
||||
if ((d >> 64) == 0) d else 0
|
||||
}
|
||||
|
||||
def runOneTest(m: SimpleDivider, divide: (BigInt, BigInt) => BigInt) = {
|
||||
for ((x, y) <- tests) {
|
||||
|
||||
while (m.io.in.ready.peek().litToBoolean == false) {
|
||||
m.clock.step(1)
|
||||
}
|
||||
|
||||
m.io.in.bits.dividend.poke(x.U)
|
||||
m.io.in.bits.divisor.poke(y.U)
|
||||
m.io.in.valid.poke(true.B)
|
||||
m.clock.step(1)
|
||||
m.io.in.valid.poke(false.B)
|
||||
|
||||
while (m.io.out.valid.peek().litToBoolean == false) {
|
||||
m.clock.step(1)
|
||||
}
|
||||
|
||||
m.io.out.bits.expect(divide(x, y).U)
|
||||
}
|
||||
}
|
||||
|
||||
it should "pass a unit test" in {
|
||||
test(new SimpleDivider(64)) { m =>
|
||||
for ((x, y) <- tests) {
|
||||
while (m.io.in.ready.peek().litToBoolean == false) {
|
||||
m.clock.step(1)
|
||||
}
|
||||
runOneTest(m, divide)
|
||||
|
||||
m.io.in.bits.dividend.poke(x.U)
|
||||
m.io.in.bits.divisor.poke(y.U)
|
||||
m.io.in.valid.poke(true.B)
|
||||
m.clock.step(1)
|
||||
m.io.in.valid.poke(false.B)
|
||||
m.io.in.bits.extended.poke(true.B)
|
||||
runOneTest(m, divideExtended)
|
||||
|
||||
while (m.io.out.valid.peek().litToBoolean == false) {
|
||||
m.clock.step(1)
|
||||
}
|
||||
|
||||
m.io.out.bits.expect(divide(x, y).U)
|
||||
}
|
||||
m.io.in.bits.extended.poke(false.B)
|
||||
m.io.in.bits.signed.poke(true.B)
|
||||
runOneTest(m, divideSigned)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user