package sifive.blocks.devices.i2c
import Chisel._
-import config._
-import util._
-import regmapper._
-import uncore.tilelink2._
-import rocketchip.PeripheryBusConfig
-import util.AsyncResetRegVec
-import sifive.blocks.devices.gpio.{GPIOPinCtrl}
-
-case class I2CConfig(address: BigInt)
-
-trait HasI2CParameters {
- implicit val p: Parameters
- val params: I2CConfig
- val c = params
-}
+import chisel3.experimental.MultiIOModule
+import freechips.rocketchip.config._
+import freechips.rocketchip.regmapper._
+import freechips.rocketchip.tilelink._
+import freechips.rocketchip.util.{AsyncResetRegVec, Majority}
+
+case class I2CParams(address: BigInt)
class I2CPin extends Bundle {
val in = Bool(INPUT)
val sda = new I2CPin
}
-trait I2CBundle extends Bundle with HasI2CParameters {
+trait HasI2CBundleContents extends Bundle {
val port = new I2CPort
}
-trait I2CModule extends Module with HasI2CParameters with HasRegMap {
- val io: I2CBundle
+trait HasI2CModuleContents extends MultiIOModule with HasRegMap {
+ val io: HasI2CBundleContents
+ val params: I2CParams
val I2C_CMD_NOP = UInt(0x00)
val I2C_CMD_START = UInt(0x01)
fSDA := Cat(fSDA, io.port.sda.in)
}
- val sSCL = Reg(init = true.B, next = (new Majority(fSCL.toBools.toSet)).out)
- val sSDA = Reg(init = true.B, next = (new Majority(fSDA.toBools.toSet)).out)
+ val sSCL = Reg(init = true.B, next = Majority(fSCL))
+ val sSDA = Reg(init = true.B, next = Majority(fSDA))
val dSCL = Reg(init = true.B, next = sSCL)
val dSDA = Reg(init = true.B, next = sSDA)
s_bit_wr_a :: s_bit_wr_b :: s_bit_wr_c :: s_bit_wr_d :: Nil) = Enum(UInt(), 18)
val bitState = Reg(init = s_bit_idle)
- val arbLost = Reg(init = false.B, next = (sdaChk && !sSDA && sdaOen) | ((bitState === s_bit_idle) && stopCond && !bitCmdStop))
+ val arbLost = Reg(init = false.B, next = (sdaChk && !sSDA && sdaOen) | ((bitState =/= s_bit_idle) && stopCond && !bitCmdStop))
// bit FSM
when (arbLost) {
// hack: b/c the same register offset is used to write cmd and read status
val nextCmd = Wire(UInt(8.W))
- nextCmd := cmd.asUInt
cmd := (new CommandBundle).fromBits(nextCmd)
+ nextCmd := cmd.asUInt & 0xFE.U // clear IRQ_ACK bit (essentially 1 cycle pulse b/c it is overwritten by regmap below)
+ // Note: This wins over the regmap update of nextCmd (even if something tries to write them to 1, these values take priority).
when (cmdAck || arbLost) {
cmd.start := false.B // clear command bits when done
cmd.stop := false.B // or when aribitration lost
cmd.read := false.B
cmd.write := false.B
}
- cmd.irqAck := false.B // clear IRQ_ACK bit (essentially 1 cycle pulse b/c it is overwritten by regmap below)
status.receivedAck := receivedAck
when (stopCond) {
status.arbLost := false.B
}
status.transferInProgress := cmd.read || cmd.write
- status.irqFlag := (cmdAck || arbLost || status.irqFlag) && !cmd.irqAck
+ status.irqFlag := (cmdAck || arbLost || status.irqFlag) && !cmd.irqAck // interrupt request flag is always generated
+ val statusReadReady = Reg(init = true.B)
+ when (cmdAck || arbLost) { // => cmd.read or cmd.write deassert 1 cycle later => transferInProgress deassert 2 cycles later
+ statusReadReady := false.B // do not allow status read if status.transferInProgress is going to change
+ }
+ .elsewhen (!statusReadReady) {
+ statusReadReady := true.B
+ }
+
+ // statusReadReady,
regmap(
I2CCtrlRegs.prescaler_lo -> Seq(RegField(8, prescaler.lo)),
I2CCtrlRegs.prescaler_hi -> Seq(RegField(8, prescaler.hi)),
I2CCtrlRegs.control -> control.elements.map{ case(name, e) => RegField(e.getWidth, e.asInstanceOf[UInt]) }.toSeq,
I2CCtrlRegs.data -> Seq(RegField(8, r = RegReadFn(receivedData), w = RegWriteFn(transmitData))),
- I2CCtrlRegs.cmd_status -> Seq(RegField(8, r = RegReadFn(status.asUInt), w = RegWriteFn(nextCmd)))
+ I2CCtrlRegs.cmd_status -> Seq(RegField(8, r = RegReadFn{ ready =>
+ (statusReadReady, status.asUInt)
+ },
+ w = RegWriteFn((valid, data) => {
+ when (valid) {
+ statusReadReady := false.B
+ nextCmd := data
+ }
+ true.B
+ }
+ )))
)
// tie off unused bits
interrupts(0) := status.irqFlag & control.intEn
}
-// Copied from UART.scala
-class Majority(in: Set[Bool]) {
- private val n = (in.size >> 1) + 1
- private val clauses = in.subsets(n).map(_.reduce(_ && _))
- val out = clauses.reduce(_ || _)
-}
-
-
// Magic TL2 Incantation to create a TL2 Slave
-class TLI2C(c: I2CConfig)(implicit p: Parameters)
- extends TLRegisterRouter(c.address, interrupts = 1, beatBytes = p(PeripheryBusConfig).beatBytes)(
- new TLRegBundle(c, _) with I2CBundle)(
- new TLRegModule(c, _, _) with I2CModule)
+class TLI2C(w: Int, c: I2CParams)(implicit p: Parameters)
+ extends TLRegisterRouter(c.address, "i2c", Seq("sifive,i2c0"), interrupts = 1, beatBytes = w)(
+ new TLRegBundle(c, _) with HasI2CBundleContents)(
+ new TLRegModule(c, _, _) with HasI2CModuleContents)