From b2d8908f6c8e2cc46a42ec61f9aa031805a4267c Mon Sep 17 00:00:00 2001 From: Discreater Date: Thu, 4 Jan 2024 00:35:34 +0800 Subject: [PATCH] Add convert DecodeTableAnnotation regression test (#698) * Add convert decode regression test * add decode table annotation convert * Ignore DecodeTableAnnotation * Format test --- .../chiseltest/simulator/ChiselBridge.scala | 3 + .../regressions/ConvertDecodeTableTest.scala | 86 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 src/test/scala/chiseltest/regressions/ConvertDecodeTableTest.scala diff --git a/src/main/scala/chiseltest/simulator/ChiselBridge.scala b/src/main/scala/chiseltest/simulator/ChiselBridge.scala index dfac1323c..a6f0360c7 100644 --- a/src/main/scala/chiseltest/simulator/ChiselBridge.scala +++ b/src/main/scala/chiseltest/simulator/ChiselBridge.scala @@ -4,6 +4,7 @@ import chisel3.RawModule import chisel3.stage._ import chisel3.stage.phases._ import chisel3.experimental.EnumAnnotations.{EnumComponentAnnotation, EnumDefAnnotation, EnumVecAnnotation} +import chisel3.util.experimental.decode.DecodeTableAnnotation import firrtl.passes.InlineAnnotation import firrtl.transforms.FlattenAnnotation // this imports the [[firrtl]] package from Chisel (not to be confused with the firrtl2 compiler! @@ -150,6 +151,8 @@ private object ChiselBridge { Some(firrtl2.annotations.EnumDefAnnotation(typeName, definition)) case EnumVecAnnotation(target, typeName, fields) => Some(firrtl2.annotations.EnumVecAnnotation(convertNamed(target), typeName, fields)) + // ignoreDecodeTableAnnotation since it is not needed by the firrtl compiler + case _: DecodeTableAnnotation => None // case _ => throw new NotImplementedError(s"TODO: convert ${anno}") } diff --git a/src/test/scala/chiseltest/regressions/ConvertDecodeTableTest.scala b/src/test/scala/chiseltest/regressions/ConvertDecodeTableTest.scala new file mode 100644 index 000000000..d0d8d6499 --- /dev/null +++ b/src/test/scala/chiseltest/regressions/ConvertDecodeTableTest.scala @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chiseltest.regressions + +import chisel3._ +import chisel3.util.experimental.decode.{decoder, TruthTable} +import chisel3.util.{BitPat, Cat, Fill} +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +// https://github.com/sequencer/arithmetic/blob/dd9bd585a8d444399eb5a31d088567e0ef56f43a/arithmetic/src/multiplier/Booth.scala +class Booth(width: Int)(radixLog2: Int, signed: Boolean = true) extends Module { + val input = IO(Input(UInt(width.W))) + val output = IO( + Output( + Vec( + width / radixLog2 + 1, // = ceil(width / radixLog2) + SInt((radixLog2 + 1).W) + ) + ) + ) + def extend(x: Bits, len: Int, signed: Boolean = true): Bits = { + if (x.getWidth >= len) + x + else { + val fillBit = if (signed) x.head(1) else 0.B + Fill(len - x.getWidth, fillBit) ## x.asUInt + } + } + + /** Because .asUInt() do not set .litOption properly */ + def sIntToBitPat(x: Int, w: Int): BitPat = { + if (x >= 0) + BitPat(x.U(w.W)) + else + BitPat((x + (1 << w)).U(w.W)) + } + + val paddingLeftWidth = width + radixLog2 - width % radixLog2 + val paddedInput = Cat(extend(input, paddingLeftWidth, signed), 0.U(1.W)) + + val boothEncodingCoeff = Seq.tabulate(radixLog2 + 1) { + case i if i == radixLog2 => -(1 << (radixLog2 - 1)) + case i if i == 0 => 1 + case i => 1 << (i - 1) + } + + val boothEncodingTable = TruthTable( + Seq + .tabulate(1 << (radixLog2 + 1)) { i => + Seq + .tabulate(radixLog2 + 1)((bit: Int) => if (BigInt(i).testBit(bit)) 1 else 0) + .zip(boothEncodingCoeff) + .map { case (a, b) => + a * b + } + .sum + } + .zipWithIndex + .map { case (o, i) => + val w = radixLog2 + 1 + (sIntToBitPat(i, w), sIntToBitPat(o, w)) + }, + BitPat.dontCare(radixLog2 + 1) + ) + + output := Seq + .tabulate(output.size) { i => + decoder(paddedInput(radixLog2 * (i + 1), radixLog2 * i), boothEncodingTable) + } + .map(_.asSInt) +} + +class ConvertDecodeTableAnnotation extends AnyFlatSpec with ChiselScalatestTester with Matchers { + behavior.of("Convert DecodeTableAnnotation Regression") + + it should "work" in { + test(new Booth(16)(8)) { dut => + dut.input.poke(7.U) + dut.output(0).expect(7.S) + dut.output(1).expect(0.S) + dut.output(2).expect(0.S) + } + } +}