chipmunk
chipmunk copied to clipboard
Enhance CHISEL for Smooth and Comfortable Chip Design
🐿️ CHIPMUNK: Enhance CHISEL for Smooth and Comfortable Chip Design
CHIPMUNK is a Scala package to extend the functionality of CHISEL. It features:
- Extra convenient methods for CHISEL's built-in types,
- Several syntactic sugar to sweeten your CHISEL experience,
- A set of commonly used components and interfaces.
WARNING: The code contained in this repo are provided AS IS, and I cannot make any guarantees for availability and correctness. Most of them have only been silicon-verified in academic research (and some even not). You should carefully review every line of code before using it in production.
Please open an issue if you have any questions.
Installation
CHIPMUNK is an extension of Chisel, so it needs to be used together with CHISEL.
Mill is required to build and publish CHIPMUNK.
mill chipmunk.publishLocal
Then add CHIPMUNK to your build file.
// Mill
def ivyDeps = Agg(..., ivy"com.zhutmost::chipmunk:0.1-SNAPSHOT")
// SBT
libraryDependencies ++= Seq(..., "com.zhutmost" %% "chipmunk" % "0.1-SNAPSHOT")
Import it as well as chisel3 in your Scala RTL code.
import chisel3._
import chisel3.util._
import chipmunk._
Documentation
CHIPMUNK documents are provided in the docs folder.
Extra convenient Methods for Chisel types
View detailed document
Code example:
val myUInt = Wire(UInt(3.W)).dontTouch // equivalent to `DontTouch(...)`, but more convenient
when(...) {
myUInt.setAllTo(someBits.lsBit) // set all bits to true or false
} otherwise {
myUInt.clearAll()
}
val emptyStream = Decoupled(new EmptyBundle) // Bundle without elements
Define Bundle Direction with Master/Slave
View detailed document
Code example:
class AxiIO extends Bundle with IsMasterSlave {
val aw = Master(new AxiWriteAddrChannelIO)
val ar = Master(new AxiReadAddrChannelIO)
val r = Slave(new AxiReadDataChannelIO)
val w = Master(new AxiWriteDataChannelIO)
val b = Slave(new AxiWriteRespChannelIO)
def isMaster = true // indicate this bundle is a Master
}
class AxiSlave extends Module {
val io = IO(new Bundle {
val axi = Slave(new AxiIO) // automatically flip the signal directions
})
// ...
}
Registers triggered on the falling clock edge
View detailed document
Code example:
withClockAndReset(clock, reset) {
val regNeg1 = RegNegNext(nextVal)
val regNeg2 = RegNegEnable(nextVal, initVal, enable)
}
Finite State Machine
View detailed document
Code example:
val fsm = new StateMachine {
val s1 = new State with EntryPoint
val s2 = new State
s1
.whenIsActive {
when(io.a) {
goto(s2)
}
}
s2
.whenIsActive {
when(io.b) {
goto(s1)
}
}
}
io.out := fsm.isExiting(fsm.s2)
Asynchronous Reset Synchronous Dessert
View detailed document
Code example:
val reset1 = AsyncResetSyncDessert.withImplicitClockDomain()
val reset2 = AsyncResetSyncDessert.withSpecificClockDomain(clockSys, coreReset, resetChainIn = reset1)
Out-of-box Simulation with Scala-written Testbench
View detailed document
Code example:
import org.scalatest.Assertions
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class TestRunnerSpec extends AnyFlatSpec with Assertions with Matchers with VerilatorTestRunner {
val compiled = TestRunnerConfig(withWaveform = true).compile(new Module {
val io = IO(new Bundle {
val a = Input(SInt(3.W))
val b = Output(SInt(3.W))
val c = Output(UInt(3.W))
})
io.b := io.a
io.c := io.a.asUInt
})
"TestRunner" should "compile DUT and run simulation" in {
compiled.runSim { dut =>
import TestRunnerUtils._
dut.clock.step()
dut.io.a #= -1.S(3.W)
dut.clock.step()
dut.io.b expect -1
dut.io.c expect 7
}
}
}
Clock Domain Crossing Blocks
View detailed document
Code example:
TODO
StreamIO/FlowIO: Decouple Dataflow with Handshake
View detailed document
Code example:
TODO
(Not all above document pages are ready yet.)
I am sorry they are written in Chinese (Machine translation driven by AI is good enough now :D).
Acknowledgement
CHIPMUNK is standing on the shoulder of giants. Thanks for CHISEL, SpinalHDL and many other open-sourced projects.