1
0
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:
Anton Blanchard 2020-02-24 09:47:03 +11:00 committed by GitHub
commit 121d967375
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 82 additions and 36 deletions

View File

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

View File

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