Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add map method for Valid (backport #4255) #4258

Merged
merged 2 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/main/scala/chisel3/util/Valid.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ class Valid[+T <: Data](gen: T) extends Bundle {
* Inserts the parameterized generator's typeName, e.g. Valid_UInt4
*/
override def typeName = s"${simpleClassName(this.getClass)}_${gen.typeName}"

/** Applies the supplied functor to the bits of this interface, returning a new typed Valid interface.
* @param f The function to apply to this Valid's 'bits' with return type B
* @return a new Valid of type B
*/
def map[B <: Data](f: T => B): Valid[B] = {
val _map_bits = f(bits)
val _map = Wire(Valid(chiselTypeOf(_map_bits)))
_map.bits := _map_bits
_map.valid := valid
_map.readOnly
}
}

/** Factory for generating "valid" interfaces. A "valid" interface is a data-communicating interface between a producer
Expand Down
104 changes: 104 additions & 0 deletions src/test/scala/chiselTests/ValidSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: Apache-2.0

package chiselTests

import chisel3._
import circt.stage.ChiselStage
import chisel3.util.Valid

class ValidSpec extends ChiselFlatSpec {
"Valid.map" should "apply a function to the wrapped Data" in {
val chirrtl = ChiselStage.emitCHIRRTL(new Module {
val in = IO(Flipped(Valid(UInt(8.W))))
val out = IO(Valid(UInt(8.W)))
out :#= in.map(_ + 1.U)
})

// Check for data assignment
chirrtl should include("""node _out_map_bits_T = add(in.bits, UInt<1>(0h1))""")
chirrtl should include("""node _out_map_bits = tail(_out_map_bits_T, 1)""")
chirrtl should include("""connect _out_map.bits, _out_map_bits""")
chirrtl should include("""connect out.bits, _out_map.bits""")

// Check for valid assignment
chirrtl should include("""connect _out_map.valid, in.valid""")
chirrtl should include("""connect out.valid, _out_map.valid""")
}

"Valid.map" should "apply a function to a wrapped Bundle" in {
class TestBundle extends Bundle {
val foo = UInt(8.W)
val bar = UInt(8.W)
val fizz = Bool()
val buzz = Bool()
}

// Add one to foo, subtract one from bar, set fizz to false and buzz to true
def func(t: TestBundle): TestBundle = {
val res = Wire(new TestBundle)

res.foo := t.foo + 1.U
res.bar := t.bar - 1.U
res.fizz := false.B
res.buzz := true.B

res
}

val chirrtl = ChiselStage
.emitCHIRRTL(new Module {
val in = IO(Flipped(Valid(new TestBundle)))
val out = IO(Valid(new TestBundle))
out :#= in.map(func)
})

// Check for data assignment
chirrtl should include("""wire _out_map_bits : { foo : UInt<8>, bar : UInt<8>, fizz : UInt<1>, buzz : UInt<1>}""")

chirrtl should include("""node _out_map_bits_res_foo_T = add(in.bits.foo, UInt<1>(0h1)""")
chirrtl should include("""node _out_map_bits_res_foo_T_1 = tail(_out_map_bits_res_foo_T, 1)""")
chirrtl should include("""connect _out_map_bits.foo, _out_map_bits_res_foo_T_1""")

chirrtl should include("""node _out_map_bits_res_bar_T = sub(in.bits.bar, UInt<1>(0h1)""")
chirrtl should include("""node _out_map_bits_res_bar_T_1 = tail(_out_map_bits_res_bar_T, 1)""")
chirrtl should include("""connect _out_map_bits.bar, _out_map_bits_res_bar_T_1""")

chirrtl should include("""connect _out_map_bits.fizz, UInt<1>(0h0)""")
chirrtl should include("""connect _out_map_bits.buzz, UInt<1>(0h1)""")

chirrtl should include("""connect _out_map.bits, _out_map_bits""")
for ((field, _) <- (new TestBundle).elements) {
chirrtl should include(s"""connect out.bits.$field, _out_map.bits.$field""")
}

// Check for valid assignment
chirrtl should include("""connect _out_map.valid, in.valid""")
chirrtl should include("""connect out.valid, _out_map.valid""")
}

"Valid.map" should "apply a function to a wrapped Bundle and return a different typed Valid" in {
class TestBundle extends Bundle {
val foo = UInt(8.W)
val bar = UInt(8.W)
}

val chirrtl = ChiselStage
.emitCHIRRTL(new Module {
val in = IO(Flipped(Valid(new TestBundle)))
val out = IO(Valid(UInt(8.W)))
out :#= in.map(bundle => bundle.foo & bundle.bar)
})

// Check that the _map wire wraps a UInt and not a TestBundle
chirrtl should include("""wire _out_map : { valid : UInt<1>, bits : UInt<8>}""")

// Check for data assignment
chirrtl should include("""node _out_map_bits = and(in.bits.foo, in.bits.bar)""")
chirrtl should include("""connect _out_map.bits, _out_map_bits""")
chirrtl should include("""connect out.bits, _out_map.bits""")

// Check for valid assignment
chirrtl should include("""connect _out_map.valid, in.valid""")
chirrtl should include("""connect out.valid, _out_map.valid""")
}
}
Loading