120 lines
4.4 KiB
Scala
120 lines
4.4 KiB
Scala
package freechips.rocketchip.fpga
|
|
|
|
import chisel3._
|
|
import chisel3.experimental.IntParam
|
|
import chisel3.util.Cat
|
|
|
|
import org.chipsalliance.cde.config.Parameters
|
|
import org.chipsalliance.diplomacy.bundlebridge._
|
|
import org.chipsalliance.diplomacy.lazymodule._
|
|
|
|
import freechips.rocketchip.diplomacy.AddressSet
|
|
import freechips.rocketchip.regmapper.{RegField, RegFieldDesc, RegWriteFn}
|
|
import freechips.rocketchip.resources.SimpleDevice
|
|
import freechips.rocketchip.tilelink.TLRegisterNode
|
|
|
|
case class MAX2771SPIParams(
|
|
address: BigInt = 0x10016000L,
|
|
inputClockHz: Int = 100000000,
|
|
maxSclkHz: Int = 4000000) {
|
|
require(inputClockHz > 0, "MAX2771 SPI input clock must be positive")
|
|
require(maxSclkHz > 0 && maxSclkHz <= 4000000,
|
|
"MAX2771 data sheet limits SCLK to 4 MHz")
|
|
|
|
val halfPeriodCycles: Int = (inputClockHz + 2 * maxSclkHz - 1) / (2 * maxSclkHz)
|
|
val actualSclkHz: Int = inputClockHz / (2 * halfPeriodCycles)
|
|
}
|
|
|
|
class MAX2771SPIEngineBlackBox(params: MAX2771SPIParams) extends BlackBox(Map(
|
|
"CLOCK_HZ" -> IntParam(params.inputClockHz),
|
|
"MAX_SCLK_HZ" -> IntParam(params.maxSclkHz))) {
|
|
override def desiredName: String = "max2771_spi_engine"
|
|
|
|
val io = IO(new Bundle {
|
|
val clk = Input(Clock())
|
|
val rst_n = Input(Bool())
|
|
val start = Input(Bool())
|
|
val read_not_write = Input(Bool())
|
|
val address = Input(UInt(4.W))
|
|
val write_data = Input(UInt(32.W))
|
|
val read_data = Output(UInt(32.W))
|
|
val busy = Output(Bool())
|
|
val ready = Output(Bool())
|
|
val sclk = Output(Bool())
|
|
val csn = Output(Bool())
|
|
val sdata_i = Input(Bool())
|
|
val sdata_o = Output(Bool())
|
|
val sdata_oe = Output(Bool())
|
|
})
|
|
}
|
|
|
|
class TLMAX2771SPI(params: MAX2771SPIParams, beatBytes: Int)(implicit p: Parameters)
|
|
extends LazyModule {
|
|
val device = new SimpleDevice("max2771-spi", Seq("analog-devices,max2771-spi"))
|
|
val sclkNode = BundleBridgeSource(() => Bool())
|
|
val csnNode = BundleBridgeSource(() => Bool())
|
|
val sdataInNode = BundleBridgeSink[Bool]()
|
|
val sdataOutNode = BundleBridgeSource(() => Bool())
|
|
val sdataOeNode = BundleBridgeSource(() => Bool())
|
|
val node = TLRegisterNode(
|
|
address = Seq(AddressSet(params.address, 0xfff)),
|
|
device = device,
|
|
beatBytes = beatBytes,
|
|
concurrency = 1)
|
|
|
|
lazy val module = new Impl
|
|
class Impl extends LazyModuleImp(this) {
|
|
val engine = Module(new MAX2771SPIEngineBlackBox(params))
|
|
val writeData = RegInit(0.U(32.W))
|
|
val start = WireDefault(false.B)
|
|
val commandRead = WireDefault(false.B)
|
|
val commandAddress = WireDefault(0.U(4.W))
|
|
|
|
engine.io.clk := clock
|
|
engine.io.rst_n := !reset.asBool
|
|
engine.io.start := start
|
|
engine.io.read_not_write := commandRead
|
|
engine.io.address := commandAddress
|
|
engine.io.write_data := writeData
|
|
engine.io.sdata_i := sdataInNode.bundle
|
|
|
|
sclkNode.bundle := engine.io.sclk
|
|
csnNode.bundle := engine.io.csn
|
|
sdataOutNode.bundle := engine.io.sdata_o
|
|
sdataOeNode.bundle := engine.io.sdata_oe
|
|
|
|
val commandWrite = RegWriteFn { (valid, data) =>
|
|
commandRead := data(8)
|
|
commandAddress := data(3, 0)
|
|
start := valid && engine.io.ready
|
|
engine.io.ready
|
|
}
|
|
|
|
val writeDataWrite = RegWriteFn { (valid, data) =>
|
|
when(valid && engine.io.ready) { writeData := data }
|
|
engine.io.ready
|
|
}
|
|
|
|
val status = Cat(0.U(30.W), engine.io.busy, engine.io.ready)
|
|
|
|
node.regmap(
|
|
0x00 -> Seq(RegField.w(32, commandWrite,
|
|
RegFieldDesc("command", "bits[3:0] register address, bit8 read; write starts one 48-clock frame"))),
|
|
0x04 -> Seq(RegField.w(32, writeDataWrite,
|
|
RegFieldDesc("write_data", "32-bit MAX2771 register write data"))),
|
|
0x08 -> Seq(RegField.r(32, engine.io.read_data,
|
|
RegFieldDesc("read_data", "last 32-bit MAX2771 register read data"))),
|
|
0x0c -> Seq(RegField.r(32, status,
|
|
RegFieldDesc("status", "bit0 ready, bit1 busy"))),
|
|
0x10 -> Seq(RegField.r(32, params.inputClockHz.U,
|
|
RegFieldDesc("input_clock_hz", "peripheral input clock frequency"))),
|
|
0x14 -> Seq(RegField.r(32, params.actualSclkHz.U,
|
|
RegFieldDesc("sclk_hz", "actual integer MAX2771 serial clock frequency"))),
|
|
0x18 -> Seq(RegField.r(32, params.halfPeriodCycles.U,
|
|
RegFieldDesc("half_period_cycles", "input-clock cycles per SCLK half-period"))),
|
|
0x1c -> Seq(RegField.r(32, "h4d415831".U,
|
|
RegFieldDesc("identification", "ASCII MAX1 peripheral identification")))
|
|
)
|
|
}
|
|
}
|