diff --git a/.devcontainer.json b/.devcontainer.json index 4d3b00d..377fa15 100644 --- a/.devcontainer.json +++ b/.devcontainer.json @@ -1,3 +1,4 @@ { - "image": "datenlord/spinal-cocotb:1.5.0" + "image": "datenlord/spinal-cocotb:1.6.0", + "extensions": ["scalameta.metals"] } diff --git a/exercises/Dockerfile b/exercises/Dockerfile index a05a8db..40c6744 100644 --- a/exercises/Dockerfile +++ b/exercises/Dockerfile @@ -2,7 +2,7 @@ FROM ubuntu ARG JDK_VERSION=11 ARG MILL_VERSION=0.9.7 -ARG SCALA_VERSION=2.12.13 +ARG SCALA_VERSION=2.13.6 ENV DEBIAN_FRONTEND=noninteractive # Install dependencies diff --git a/exercises/Examples/src/main/scala/exercises/ApbArbiter.scala b/exercises/Examples/src/main/scala/exercises/ApbArbiter.scala index 4dbc195..99d4dbc 100644 --- a/exercises/Examples/src/main/scala/exercises/ApbArbiter.scala +++ b/exercises/Examples/src/main/scala/exercises/ApbArbiter.scala @@ -11,7 +11,7 @@ class ApbArbiter( require(numInputSlaves > 0) val io = new Bundle { - val en = in Bool + val en = in Bool () val masterOut = master(Apb3(apbConfig)) val slavesIn = Vec(slave(Apb3(apbConfig)), numInputSlaves) } diff --git a/exercises/Examples/src/main/scala/exercises/Booth.scala b/exercises/Examples/src/main/scala/exercises/Booth.scala index db619f4..07772e6 100644 --- a/exercises/Examples/src/main/scala/exercises/Booth.scala +++ b/exercises/Examples/src/main/scala/exercises/Booth.scala @@ -11,19 +11,22 @@ class Booth(width: Int) extends Component { require(width > 1) val io = new Bundle { - val load = in Bool + val load = in Bool () val multiplicand = in SInt (width bits) val multipler = in SInt (width bits) - val ready = out Bool + val ready = out Bool () val product = out SInt (2 * width bits) } - val buf = Reg(SInt(2 * width + 1 bits)) init (0) simPublic () - val upperPart = buf(2 * width downto width + 1) simPublic () - val lowerPart = buf(width downto 0) simPublic () - + val buf = Reg(SInt(2 * width + 1 bits)) init (0) + val upperPart = buf(2 * width downto width + 1) + val lowerPart = buf(width downto 0) val cnt = CounterFreeRun(stateCount = width + 2) - cnt.value simPublic () + + buf.simPublic() + upperPart.simPublic() + lowerPart.simPublic() + cnt.value.simPublic() when(io.load) { buf := S(0, width bits) @@ io.multipler @@ S(0, 1 bit) diff --git a/exercises/Examples/src/main/scala/exercises/FifoCC.scala b/exercises/Examples/src/main/scala/exercises/FifoCC.scala index 1e7eded..fd547ea 100644 --- a/exercises/Examples/src/main/scala/exercises/FifoCC.scala +++ b/exercises/Examples/src/main/scala/exercises/FifoCC.scala @@ -16,11 +16,11 @@ class FifoCC[T <: Data]( val io = new Bundle { val wData = in(dataType()) - val wEn = in Bool - val wFull = out Bool + val wEn = in Bool () + val wFull = out Bool () val rData = out(dataType()) - val rEn = in Bool - val rEmpty = out Bool + val rEn = in Bool () + val rEmpty = out Bool () } val ADDR_WIDTH = log2Up(depth + 1) diff --git a/exercises/Examples/src/main/scala/exercises/HandShakePipe.scala b/exercises/Examples/src/main/scala/exercises/HandShakePipe.scala index 3335d0e..30b60c0 100644 --- a/exercises/Examples/src/main/scala/exercises/HandShakePipe.scala +++ b/exercises/Examples/src/main/scala/exercises/HandShakePipe.scala @@ -1,24 +1,24 @@ // https://www.itdev.co.uk/blog/pipelining-axi-buses-registered-ready-signals +// http://fpgacpu.ca/fpga/Pipeline_Skid_Buffer.html package exercises import spinal.core._ -import spinal.core.sim._ import spinal.lib._ -import spinal.sim._ +import spinal.lib.fsm._ class HandShakePipe(width: Int) extends Component { val io = new Bundle { val input = new Bundle { - val valid = in Bool + val valid = in Bool () val payload = in UInt (width bits) - val ready = out Bool + val ready = out Bool () } val output = new Bundle { - val valid = out Bool + val valid = out Bool () val payload = out UInt (width bits) - val ready = in Bool + val ready = in Bool () } } } @@ -154,3 +154,68 @@ class BothHandShakePipe2( } } } + +class BothHandShakePipe3( + width: Int +) extends HandShakePipe(width) { + + object SkidBufState extends SpinalEnum { + val EMPTY, BUSY, FULL = newElement() + } + + val load = Bool() + val unload = Bool() + val flow = Bool() + val fill = Bool() + val flush = Bool() + + val insert = io.input.valid && io.input.ready + val remove = io.output.valid && io.output.ready + + val skidBufferReg = Reg(UInt(width bits)) init (0) + val outBufferReg = Reg(UInt(width bits)) init (0) + + val state = Reg(SkidBufState) init (SkidBufState.EMPTY) + + load := state === SkidBufState.EMPTY && insert && !remove + unload := state === SkidBufState.BUSY && !insert && remove + flow := state === SkidBufState.BUSY && insert && remove + fill := state === SkidBufState.BUSY && insert && !remove + flush := state === SkidBufState.FULL && !insert && remove + + when(flush) { + outBufferReg := skidBufferReg + } elsewhen (load || flow) { + outBufferReg := io.input.payload + } + when(fill) { + skidBufferReg := io.input.payload + } + + val nextState = SkidBufState() + nextState := state + switch(state) { + is(SkidBufState.EMPTY) { + when(load) { + nextState := SkidBufState.BUSY + } + } + is(SkidBufState.BUSY) { + when(fill) { + nextState := SkidBufState.FULL + } elsewhen (unload) { + nextState := SkidBufState.EMPTY + } + } + is(SkidBufState.FULL) { + when(flush) { + nextState := SkidBufState.BUSY + } + } + } + state := nextState + + io.input.ready := state =/= SkidBufState.FULL + io.output.valid := state =/= SkidBufState.EMPTY + io.output.payload := outBufferReg +} diff --git a/exercises/Examples/test/src/scala/exercises/HandShakePipeTest.scala b/exercises/Examples/test/src/scala/exercises/HandShakePipeTest.scala index 0c3c219..8f7d825 100644 --- a/exercises/Examples/test/src/scala/exercises/HandShakePipeTest.scala +++ b/exercises/Examples/test/src/scala/exercises/HandShakePipeTest.scala @@ -117,7 +117,15 @@ class HandShakePipeTest extends AnyFunSuite { stream.io.simPublic() } - def simTest(dut: PipeTB) { + class BothPipe3TB(width: Int) extends PipeTB(width) { + override val pipe = new BothHandShakePipe3(width) + override val stream = new BothPipeStream2(width) + + pipe.io.simPublic() + stream.io.simPublic() + } + + def simTest(dut: PipeTB): Unit = { SimTimeout(1000) dut.clockDomain.forkStimulus(2) @@ -145,7 +153,10 @@ class HandShakePipeTest extends AnyFunSuite { dut.stream.io.sin.valid #= true dut.stream.io.sin.payload #= din dut.clockDomain.waitSampling() - assert(dut.pipe.io.input.ready.toBoolean == dut.stream.io.sin.ready.toBoolean) + assert( + dut.pipe.io.input.ready.toBoolean == dut.stream.io.sin.ready.toBoolean, + s"pipe ri=${dut.pipe.io.input.ready.toBoolean} not match stream ri=${dut.stream.io.sin.ready.toBoolean}" + ) if (dut.pipe.io.input.valid.toBoolean && dut.pipe.io.input.ready.toBoolean) { din += 1 } @@ -159,11 +170,14 @@ class HandShakePipeTest extends AnyFunSuite { dut.pipe.io.output.ready #= randBool dut.stream.io.sout.ready #= randBool dut.clockDomain.waitSampling() - assert(dut.pipe.io.output.valid.toBoolean == dut.stream.io.sout.valid.toBoolean) + assert( + dut.pipe.io.output.valid.toBoolean == dut.stream.io.sout.valid.toBoolean, + s"pipe vo=${dut.pipe.io.output.valid.toBoolean} not match stream vo=${dut.stream.io.sout.valid.toBoolean}" + ) if (dut.pipe.io.output.valid.toBoolean && dut.pipe.io.output.ready.toBoolean) { assert( dut.pipe.io.output.payload.toInt == dut.stream.io.sout.payload.toInt, - s"dout=${dut.pipe.io.output.payload.toInt} != ${dut.stream.io.sout.payload.toInt}" + s"pipe dout=${dut.pipe.io.output.payload.toInt} not match stream dout=${dut.stream.io.sout.payload.toInt}" ) matchCnt += 1 if (matchCnt > 100) { @@ -224,5 +238,12 @@ class HandShakePipeTest extends AnyFunSuite { .compile(new BothPipe2TB(width)) .doSim(simTest(_)) } + + test("pipeline fsm") { + SimConfig + .withWave + .compile(new BothPipe3TB(width)) + .doSim(simTest(_)) + } } diff --git a/exercises/build.sc b/exercises/build.sc index 104144d..8259440 100644 --- a/exercises/build.sc +++ b/exercises/build.sc @@ -2,10 +2,10 @@ import $ivy.`com.goyeau::mill-scalafix:0.2.2` import com.goyeau.mill.scalafix.ScalafixModule import mill._, scalalib._, scalafmt._ -val SpinalVersion = "1.5.0" +val SpinalVersion = "1.6.0" trait CommonSpinalModule extends ScalaModule with ScalafmtModule with ScalafixModule { - def scalaVersion = "2.12.13" + def scalaVersion = "2.13.6" def scalacOptions = Seq("-unchecked", "-deprecation", "-feature") def ivyDeps = Agg( @@ -19,14 +19,9 @@ trait CommonSpinalModule extends ScalaModule with ScalafmtModule with ScalafixMo def scalafixIvyDeps = Agg(ivy"com.github.liancheng::organize-imports:0.5.0") } - object Examples extends CommonSpinalModule { - object test extends Tests { - def ivyDeps = Agg( - ivy"org.scalatest::scalatest:3.2.2", - ) - def testFrameworks = Seq("org.scalatest.tools.Framework") - + object test extends Tests with TestModule.ScalaTest { + def ivyDeps = Agg(ivy"org.scalatest::scalatest:3.2.2") def testOnly(args: String*) = T.command { super.runMain("org.scalatest.run", args: _*) }