我正努力想出一个更好的头衔。
我是奇塞尔和斯卡拉的新人。下面是定义和测试模块的Chisel代码。
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
class DeviceUnderTest extends Module {
val io = IO(new Bundle {
val a = Input(UInt(2.W))
val b = Input(UInt(2.W))
val out = Output(UInt(2.W))
})
io.out := io.a & io.b
}
class WaveformTestWithIteration extends AnyFlatSpec with ChiselScalatestTester {
"WaveformIteration" should "pass" in {
test(new DeviceUnderTest)
.withAnnotations(Seq(WriteVcdAnnotation)) ( dut => // ???
{
for (a <- 0 until 4; b <- 0 until 4) {
dut.io.a.poke(a.U)
dut.io.b.poke(b.U)
dut.clock.step()
}
}
)
}
}注释???的代码行使我感到非常困惑。变量dut在哪里定义?这似乎是对new DeviceUnderTest获得的实例的引用。
test(new DeviceUnderTest).withAnnotations(Seq(WriteVcdAnnotation))用apply方法返回TestBuilder[T]:
class TestBuilder[T <: Module](...) {
...
def apply(testFn: T => Unit): TestResult = {
runTest(defaults.createDefaultTester(dutGen, finalAnnos))(testFn)
}
...
}那么,dut => {...}是一个函数(T) => Unit吗?但是它看起来不像标准的lambda ((x:T) => {...})?或者是别的什么?
scala中的这个语法到底是什么?
发布于 2022-10-25 10:08:02
考虑具有类似结构的以下简化版本:
def test[A](testedThing: A)(testBody: A => Unit): Unit = testBody(testedThing)本质上,它所做的是获取一个值x: A和一个函数f: A => Unit,并将f应用于x以获得f(x)。
下面是您如何使用它:
test("foo"){ x =>
println(if x == "foo" then "Success" else "Failure")
} // Success
test("bar"){ x =>
println(if x == "baz" then "Success" else "Failure")
} // Failure在这两种情况下,“正在测试的字符串”被简单地传递到“测试”的主体。
现在,您可以在被测试的值的创建和主体的规范之间引入更多的步骤。例如,您可以创建一个TestBuilder[A],它本质上只是一个带有一些铃铛和哨声的值a (在本例中,“注释”列表--以下示例中的简单字符串):
type Annotation = String
case class TestOutcome(annotations: List[Annotation], successful: Boolean)
trait Test:
def run: TestOutcome
// This simply captures the value under test of type `A`
case class TestBuilder[A](
theThingUnderTest: A,
annotations: List[Annotation]
):
// Bells and whistles: adding some metadata
def withAnnotations(moreAnnotations: List[Annotation]): TestBuilder[A] =
TestBuilder(theThingUnderTest, annotations ++ moreAnnotations)
// Combining the value under test with the body of the test produces the
// actual test
def apply(testBody: A => Unit): Test = new Test:
def run =
try {
testBody(theThingUnderTest)
TestOutcome(annotations, true)
} catch {
case t: Throwable => TestOutcome(annotations, false)
}
// This constructs the thing that's being tested, and creates a TestBuilder around it
def test[A](thingUnderTest: A) = TestBuilder(thingUnderTest, Nil)
println(
test("hello")
.withAnnotations(List("size of hello should be 5")){ h =>
assert(h.size == 5)
}
.run
)
println(
test("hello")
.withAnnotations(List("size of hello should be 42")){ h =>
assert(h.size == 42)
}
.run
)原理是一样的:test(a)保存测试值a,然后TestBuilder添加一些配置,一旦向它添加了一个TestBuilder { thingUnderTest => /* assertStuff */ },就可以得到一个完整的Test,然后可以通过run获得一些结果(在本例中是TestOutcome)。因此,上面的片段会产生
TestOutcome(List(size of hello should be 5),true)
TestOutcome(List(size of hello should be 42),false)发布于 2022-10-25 10:08:16
我想我没有注意到有时我们可以省略lambda中的类型声明。
class tester{
def apply( fn: (Int) => Int):Int = fn(5)
}我们可以编写(new tester)(x => {x+1})而不是(new tester)((x:Int) => {x+1})。
https://stackoverflow.com/questions/74191562
复制相似问题