Files
gps/hardware/soc/scala/fpga/MAX2771SPI.scala
T
2026-08-06 22:14:52 +03:00

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")))
)
}
}