// See LICENSE.SiFive for license details. package freechips.rocketchip.fpga import chisel3._ import chisel3.experimental.IntParam import chisel3.util._ import org.chipsalliance.cde.config._ import org.chipsalliance.diplomacy.bundlebridge._ import org.chipsalliance.diplomacy.lazymodule._ import freechips.rocketchip.diplomacy.AddressSet import freechips.rocketchip.amba.apb.{APBSlaveNode, APBSlaveParameters, APBSlavePortParameters} import freechips.rocketchip.devices.tilelink.{BootROM, BootROMLocated, BootROMParams, MaskROM, MaskROMLocated} import freechips.rocketchip.interrupts.{IntRange, IntSourceNode, IntSourceParameters, IntSourcePortParameters} import freechips.rocketchip.regmapper.{RegField, RegFieldDesc, RegReadFn, RegWriteFn} import freechips.rocketchip.resources.SimpleDevice import freechips.rocketchip.rocket.{RocketTileConfig, WithNSmallCores} import freechips.rocketchip.subsystem._ import freechips.rocketchip.system.BaseConfig import freechips.rocketchip.tile.FPUParams import freechips.rocketchip.tilelink.{TLFragmenter, TLRAM, TLRegisterNode, TLToAPB, TLWidthWidget} import freechips.rocketchip.prci.SynchronousCrossing import freechips.rocketchip.util.{ResetCatchAndSync, SystemFileName} object FpgaBuildSettings { // Makefiles pass user-facing DTIM_BASE/DTIM_SIZE as ROCKET_DTIM_* Java properties. // Reading env too keeps direct generator invocations scriptable without a new Config class. private def parseBigInt(text: String): BigInt = { val clean = text.trim.replace("_", "") if (clean.startsWith("0x") || clean.startsWith("0X")) { BigInt(clean.drop(2), 16) } else { BigInt(clean, 10) } } def bigInt(name: String, default: BigInt): BigInt = scala.sys.props.get(name).orElse(scala.sys.env.get(name)).map(parseBigInt).getOrElse(default) } case class FpgaUARTParams( address: BigInt = 0x10013000L, clockFrequency: Int = 100000000, baudRate: Int = 115200) class FpgaUARTPort extends Bundle { val rxd = Input(Bool()) val txd = Output(Bool()) } class TLFpgaUART(params: FpgaUARTParams, beatBytes: Int)(implicit p: Parameters) extends LazyModule { val device = new SimpleDevice("uart", Seq("rocket,fpga-uart")) val rxdNode = BundleBridgeSink[Bool]() val txdNode = 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 rxd = rxdNode.bundle val txd = Wire(Bool()) txdNode.bundle := txd private val resetDivisor = (params.clockFrequency + params.baudRate / 2) / params.baudRate val clockFrequency = RegInit(params.clockFrequency.U(32.W)) val baudRate = RegInit(params.baudRate.U(32.W)) val divisor = RegInit((resetDivisor max 2).U(32.W)) val divisorMinusOne = Mux(divisor <= 1.U, 1.U, divisor - 1.U) val rxStartDelay = Mux(divisor <= 1.U, 1.U, divisor + (divisor >> 1) - 1.U) val txReg = RegInit(1.U(10.W)) val txBusy = RegInit(false.B) val txDiv = RegInit(0.U(32.W)) val txCount = RegInit(0.U(4.W)) txd := txReg(0) when(txBusy) { when(txDiv === divisorMinusOne) { txDiv := 0.U txReg := Cat(1.U(1.W), txReg(9, 1)) when(txCount === 0.U) { txBusy := false.B txReg := Fill(10, 1.U(1.W)) }.otherwise { txCount := txCount - 1.U } }.otherwise { txDiv := txDiv + 1.U } } val rxSync = RegNext(RegNext(rxd, true.B), true.B) val rxPrev = RegNext(rxSync, true.B) val rxBusy = RegInit(false.B) val rxDiv = RegInit(0.U(32.W)) val rxCount = RegInit(0.U(4.W)) val rxShift = RegInit(0.U(8.W)) val rxData = RegInit(0.U(8.W)) val rxValid = RegInit(false.B) when(!rxBusy && rxPrev && !rxSync) { rxBusy := true.B rxDiv := rxStartDelay rxCount := 0.U }.elsewhen(rxBusy) { when(rxDiv === 0.U) { rxDiv := divisorMinusOne when(rxCount < 8.U) { rxShift := Cat(rxSync, rxShift(7, 1)) rxCount := rxCount + 1.U }.otherwise { rxBusy := false.B when(rxSync) { rxData := rxShift rxValid := true.B } } }.otherwise { rxDiv := rxDiv - 1.U } } val txWrite = RegWriteFn { (valid, data) => when(valid && !txBusy) { txReg := Cat(1.U(1.W), data(7, 0), 0.U(1.W)) txBusy := true.B txDiv := 0.U txCount := 9.U } true.B } val rxRead = RegReadFn { ready => when(ready) { rxValid := false.B } (true.B, rxData) } node.regmap( 0x00 -> Seq(RegField.w(8, txWrite, RegFieldDesc("txdata", "write byte to transmit"))), 0x04 -> Seq(RegField.r(8, rxRead, RegFieldDesc("rxdata", "read received byte"))), 0x08 -> Seq(RegField.r(1, !txBusy, RegFieldDesc("txready", "transmitter can accept a byte"))), 0x0c -> Seq(RegField.r(1, rxValid, RegFieldDesc("rxvalid", "receiver has a byte"))), 0x10 -> Seq(RegField(32, clockFrequency, RegFieldDesc("clockfreq", "UART input clock frequency"))), 0x14 -> Seq(RegField(32, baudRate, RegFieldDesc("baudrate", "UART baud rate"))), 0x18 -> Seq(RegField(32, divisor, RegFieldDesc("divisor", "UART baud clock divisor"))) ) } } case class FpgaSPIParams( address: BigInt = 0x10014000L, clockDiv: Int = 8, deviceName: String = "spi", compatibility: Seq[String] = Seq("rocket,fpga-spi")) class FpgaSPIPort extends Bundle { val sck = Output(Bool()) val csn = Output(Bool()) val dq_i = Input(UInt(4.W)) val dq_o = Output(UInt(4.W)) val dq_oe = Output(UInt(4.W)) } class TLFpgaSPI(params: FpgaSPIParams, beatBytes: Int)(implicit p: Parameters) extends LazyModule { val device = new SimpleDevice(params.deviceName, params.compatibility) val sckNode = BundleBridgeSource(() => Bool()) val csnNode = BundleBridgeSource(() => Bool()) val dqInNode = BundleBridgeSink[UInt]() val dqOutNode = BundleBridgeSource(() => UInt(4.W)) val dqOeNode = BundleBridgeSource(() => UInt(4.W)) 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 dq_i = dqInNode.bundle val sck_o = Wire(Bool()) val csn_o = Wire(Bool()) val dq_o = Wire(UInt(4.W)) val dq_oe = Wire(UInt(4.W)) sckNode.bundle := sck_o csnNode.bundle := csn_o dqOutNode.bundle := dq_o dqOeNode.bundle := dq_oe val csn = RegInit(true.B) val sck = RegInit(false.B) val quad = RegInit(false.B) val cpol = RegInit(false.B) val cpha = RegInit(false.B) val txShift = RegInit(0.U(32.W)) val rxShift = RegInit(0.U(32.W)) val bitsLeft = RegInit(0.U(6.W)) val busy = RegInit(false.B) val div = RegInit(0.U(log2Ceil(params.clockDiv max 2).W)) csn_o := csn sck_o := sck dq_o := Mux(quad, txShift(31, 28), Cat(0.U(3.W), txShift(31))) dq_oe := Mux(csn || !busy, 0.U, Mux(quad, "b1111".U, "b0001".U)) when(busy) { when(div === (params.clockDiv - 1).U) { div := 0.U sck := ~sck val step = Mux(quad, 4.U, 1.U) /* * `sck` is the pre-toggle level. The edge away from CPOL is the * leading edge; CPHA selects leading (0) or trailing (1) sampling. * TX advances only after the active sample edge, so all four standard * SPI modes retain a full half-cycle of setup time. */ val leadingEdge = sck === cpol val sampleEdge = Mux(cpha, !leadingEdge, leadingEdge) when(sampleEdge) { rxShift := Mux(quad, Cat(rxShift(27, 0), dq_i), Cat(rxShift(30, 0), dq_i(1))) } /* * CPHA=0 completes on the trailing edge after the final leading-edge * sample. CPHA=1 samples and completes on the final trailing edge. */ val advanceEdge = Mux(cpha, sampleEdge, !sampleEdge) when(advanceEdge) { txShift := Mux(quad, Cat(txShift(27, 0), 0.U(4.W)), Cat(txShift(30, 0), 0.U(1.W))) when(bitsLeft <= step) { busy := false.B sck := cpol bitsLeft := 0.U }.otherwise { bitsLeft := bitsLeft - step } } }.otherwise { div := div + 1.U } } val ctrl = Wire(UInt(32.W)) ctrl := Cat(0.U(27.W), cpha, cpol, quad, csn, busy) val ctrlWrite = RegWriteFn { (valid, data) => when(valid && !busy) { csn := data(1) quad := data(2) cpol := data(3) cpha := data(4) sck := data(3) } true.B } val txWrite = RegWriteFn { (valid, data) => when(valid && !busy) { txShift := data rxShift := 0.U bitsLeft := Mux(quad, 32.U, 8.U) busy := true.B div := 0.U sck := cpol } true.B } node.regmap( 0x00 -> Seq(RegField(32, ctrl, ctrlWrite, RegFieldDesc("ctrl", "bit0 busy RO, bit1 csn RW, bit2 quad RW, bit3 CPOL RW, bit4 CPHA RW"))), 0x04 -> Seq(RegField.w(32, txWrite, RegFieldDesc("tx", "start transfer"))), 0x08 -> Seq(RegField.r(32, rxShift, RegFieldDesc("rx", "last received shift register"))), 0x0c -> Seq(RegField.r(1, !busy, RegFieldDesc("ready", "controller ready"))) ) } } class WithVCU118UART(address: BigInt = 0x10013000L, clockFrequency: Int = 100000000, baudRate: Int = 115200) extends Config((site, here, up) => { case VCU118UARTKey => Some(FpgaUARTParams(address, clockFrequency, baudRate)) }) class WithVCU118SPI(address: BigInt = 0x10014000L) extends Config((site, here, up) => { case VCU118SPIKey => Some(FpgaSPIParams(address)) }) class WithVCU118PmodSPI(address: BigInt = 0x10015000L) extends Config((site, here, up) => { case VCU118PmodSPIKey => Some(FpgaSPIParams( address = address, deviceName = "pmod-spi", compatibility = Seq("rocket,fpga-pmod-spi", "rocket,fpga-spi"))) }) case class FpgaGPSParams( baseAddress: BigInt = 0x10020000L, trackingCount: Int = 9, windowBytes: BigInt = 0x1000L) { require(trackingCount > 0) require(windowBytes == 0x1000L, "GPS APB wrappers use 12-bit APB register offsets") def acqAddress: BigInt = baseAddress def trackingAddress(index: Int): BigInt = baseAddress + ((index + 1) * windowBytes) def ppsAddress: BigInt = baseAddress + ((trackingCount + 1) * windowBytes) } class GpsAcqBlackBox(localAddrBits: Int = 12) extends BlackBox(Map( "HIGH_ADDRESS" -> IntParam((BigInt(1) << localAddrBits) - 1), "LOW_ADDRESS" -> IntParam(0), "DATA_BUS_WIDTH" -> IntParam(32), "ADDR_BUS_WIDTH" -> IntParam(localAddrBits))) { override def desiredName: String = "acq_wrapper" val io = IO(new Bundle { val PCLK = Input(Clock()) val PRESETN = Input(Bool()) val PADDR = Input(UInt(localAddrBits.W)) val PSEL = Input(Bool()) val PENABLE = Input(Bool()) val PWRITE = Input(Bool()) val PWDATA = Input(UInt(32.W)) val PREADY = Output(Bool()) val PRDATA = Output(UInt(32.W)) val PSLVERR = Output(Bool()) val afe_start = Output(Bool()) val sample_counter_clear = Output(Bool()) val clk_80mhz = Input(Clock()) val rf_clk = Input(Clock()) val acq_resetn = Input(Bool()) val afe_resetn = Input(Bool()) val rf_data = Input(UInt(4.W)) val sample_align = Input(Bool()) val start_acq_manuel = Input(Bool()) val acq_intr = Output(Bool()) }) } class GpsTrackingBlackBox(localAddrBits: Int = 12) extends BlackBox(Map( "HIGH_ADDRESS" -> IntParam((BigInt(1) << localAddrBits) - 1), "LOW_ADDRESS" -> IntParam(0), "DATA_BUS_WIDTH" -> IntParam(32), "ADDR_BUS_WIDTH" -> IntParam(localAddrBits))) { override def desiredName: String = "tracking_wrapper" val io = IO(new Bundle { val PCLK = Input(Clock()) val PRESETN = Input(Bool()) val PADDR = Input(UInt(localAddrBits.W)) val PSEL = Input(Bool()) val PENABLE = Input(Bool()) val PWRITE = Input(Bool()) val PWDATA = Input(UInt(32.W)) val PREADY = Output(Bool()) val PRDATA = Output(UInt(32.W)) val PSLVERR = Output(Bool()) val trck_resetn = Input(Bool()) val afe_resetn = Input(Bool()) val trck_clk = Input(Clock()) val afe_clk = Input(Clock()) val afe_data = Input(UInt(4.W)) val sample_align = Input(Bool()) val sample_counter = Input(UInt(32.W)) val gps_frame_ready = Output(Bool()) val pps_capture = Output(Bool()) }) } class GpsPpsBlackBox(localAddrBits: Int = 12, captureChannels: Int = 9) extends BlackBox(Map( "HIGH_ADDRESS" -> IntParam((BigInt(1) << localAddrBits) - 1), "LOW_ADDRESS" -> IntParam(0), "DATA_BUS_WIDTH" -> IntParam(32), "ADDR_BUS_WIDTH" -> IntParam(localAddrBits), "NUM_CAPTURE_CHANNELS" -> IntParam(captureChannels))) { override def desiredName: String = "pps_wrapper" val io = IO(new Bundle { val PCLK = Input(Clock()) val PRESETN = Input(Bool()) val PADDR = Input(UInt(localAddrBits.W)) val PSEL = Input(Bool()) val PENABLE = Input(Bool()) val PWRITE = Input(Bool()) val PWDATA = Input(UInt(32.W)) val PREADY = Output(Bool()) val PRDATA = Output(UInt(32.W)) val PSLVERR = Output(Bool()) val pps_clk = Input(Clock()) val pps_resetn = Input(Bool()) val capture_i = Input(UInt(captureChannels.W)) val pps_out = Output(Bool()) val pps_valid = Output(Bool()) }) } class GpsAfeTopBlackBox extends BlackBox { override def desiredName: String = "afe_top" val io = IO(new Bundle { val afe_rstn = Input(Bool()) val trk_rstn = Input(Bool()) val afe_clk = Input(Clock()) val trk_clk = Input(Clock()) val start_i = Input(Bool()) val sample_counter_clear_i = Input(Bool()) val sample_align_o = Output(Bool()) val sample_counter_o = Output(UInt(32.W)) val rf_data_o = Output(UInt(4.W)) }) } class APBGpsBlock(params: FpgaGPSParams, beatBytes: Int)(implicit p: Parameters) extends LazyModule { private val localAddrBits = log2Ceil(params.windowBytes) private val acqDevice = new SimpleDevice("gps-acq", Seq("anka,gps-acq-apb")) private val trackingDevices = Seq.tabulate(params.trackingCount)(i => new SimpleDevice(s"gps-tracking$i", Seq("anka,gps-tracking-apb"))) private val ppsDevice = new SimpleDevice("gps-pps", Seq("anka,gps-pps-apb")) private val addresses = params.acqAddress +: (Seq.tabulate(params.trackingCount)(params.trackingAddress) :+ params.ppsAddress) private val devices = acqDevice +: (trackingDevices :+ ppsDevice) private val interruptDevices = acqDevice +: trackingDevices private val apertures = addresses.map(addr => AddressSet(addr, params.windowBytes - 1)) val intnode = IntSourceNode(Seq(IntSourcePortParameters( interruptDevices.zipWithIndex.map { case (device, index) => IntSourceParameters(IntRange(index, index + 1), device.int) }))) val node = APBSlaveNode(Seq(APBSlavePortParameters( slaves = apertures.zip(devices).map { case (aperture, device) => APBSlaveParameters( address = Seq(aperture), resources = device.reg, supportsRead = true, supportsWrite = true, device = Some(device)) }, beatBytes = beatBytes))) val acqClockNode = BundleBridgeSink[Clock]() val trackingClockNode = BundleBridgeSink[Clock]() val afeClockNode = BundleBridgeSink[Clock]() val rfDataNode = BundleBridgeSink[UInt]() val ppsOutNode = BundleBridgeSource(() => Bool()) lazy val module = new Impl class Impl extends LazyModuleImp(this) { val (apb, _) = node.in(0) val acq = Module(new GpsAcqBlackBox(localAddrBits)) val afe = Module(new GpsAfeTopBlackBox) val tracking = Seq.tabulate(params.trackingCount)(_ => Module(new GpsTrackingBlackBox(localAddrBits))) val pps = Module(new GpsPpsBlackBox(localAddrBits, params.trackingCount)) val localAddr = apb.paddr(localAddrBits - 1, 0) val sel = VecInit(apertures.map(_.contains(apb.paddr))) val hit = sel.asUInt.orR // GDB ndmreset reaches this reset. Deassert it inside each GPS clock domain so // APB, acquisition, tracking, and RF/AFE logic do not leave reset on an async edge. val apbReset = ResetCatchAndSync(clock, reset.asBool, 3, "gps_apb_reset") val acqReset = ResetCatchAndSync(acqClockNode.bundle, reset.asBool, 3, "gps_acq_reset") val trckReset = ResetCatchAndSync(trackingClockNode.bundle, reset.asBool, 3, "gps_trck_reset") val afeReset = ResetCatchAndSync(afeClockNode.bundle, reset.asBool, 3, "gps_afe_reset") val apbResetn = !apbReset val acqResetn = !acqReset val trckResetn = !trckReset val afeResetn = !afeReset afe.io.afe_rstn := afeResetn afe.io.trk_rstn := trckResetn afe.io.afe_clk := afeClockNode.bundle afe.io.trk_clk := trackingClockNode.bundle afe.io.start_i := acq.io.afe_start afe.io.sample_counter_clear_i := acq.io.sample_counter_clear acq.io.PCLK := clock acq.io.PRESETN := apbResetn acq.io.PADDR := localAddr acq.io.PSEL := apb.psel && sel(0) acq.io.PENABLE := apb.penable acq.io.PWRITE := apb.pwrite acq.io.PWDATA := apb.pwdata(31, 0) acq.io.clk_80mhz := acqClockNode.bundle acq.io.rf_clk := afeClockNode.bundle acq.io.acq_resetn := acqResetn acq.io.afe_resetn := afeResetn acq.io.rf_data := rfDataNode.bundle acq.io.sample_align := afe.io.sample_align_o acq.io.start_acq_manuel := false.B tracking.zipWithIndex.foreach { case (trck, index) => trck.io.PCLK := clock trck.io.PRESETN := apbResetn trck.io.PADDR := localAddr trck.io.PSEL := apb.psel && sel(index + 1) trck.io.PENABLE := apb.penable trck.io.PWRITE := apb.pwrite trck.io.PWDATA := apb.pwdata(31, 0) trck.io.trck_resetn := trckResetn trck.io.afe_resetn := afeResetn trck.io.trck_clk := trackingClockNode.bundle trck.io.afe_clk := afeClockNode.bundle trck.io.afe_data := rfDataNode.bundle trck.io.sample_align := afe.io.sample_align_o trck.io.sample_counter := afe.io.sample_counter_o } pps.io.PCLK := clock pps.io.PRESETN := apbResetn pps.io.PADDR := localAddr pps.io.PSEL := apb.psel && sel(params.trackingCount + 1) pps.io.PENABLE := apb.penable pps.io.PWRITE := apb.pwrite pps.io.PWDATA := apb.pwdata(31, 0) pps.io.pps_clk := trackingClockNode.bundle pps.io.pps_resetn := trckResetn pps.io.capture_i := VecInit(tracking.map(_.io.pps_capture)).asUInt ppsOutNode.bundle := pps.io.pps_out val pready = acq.io.PREADY +: (tracking.map(_.io.PREADY) :+ pps.io.PREADY) val prdata = acq.io.PRDATA +: (tracking.map(_.io.PRDATA) :+ pps.io.PRDATA) val pslverr = acq.io.PSLVERR +: (tracking.map(_.io.PSLVERR) :+ pps.io.PSLVERR) apb.pready := Mux(hit, Mux1H(sel, pready), true.B) apb.prdata := Mux1H(sel, prdata.map(_.pad(apb.params.dataBits))) apb.pslverr := Mux(hit, Mux1H(sel, pslverr), true.B) intnode.out.foreach { case (out, _) => out(0) := acq.io.acq_intr tracking.zipWithIndex.foreach { case (trck, index) => out(index + 1) := trck.io.gps_frame_ready } } } } class WithVCU118GPS(baseAddress: BigInt = 0x10020000L, trackingCount: Int = 9) extends Config((site, here, up) => { case VCU118GPSKey => Some(FpgaGPSParams(baseAddress, trackingCount)) }) class WithVCU118TLRAM(base: BigInt = 0x80000000L, size: BigInt = 0x20000L) extends Config((site, here, up) => { case VCU118RAMKey => Some(AddressSet(base, size - 1)) }) // Defaults stay at the original 1 MiB DTIM, but board Makefiles may override base/size. class WithVCU118OneMiBDTIM( base: BigInt = FpgaBuildSettings.bigInt("ROCKET_DTIM_BASE", 0x80000000L), size: BigInt = FpgaBuildSettings.bigInt("ROCKET_DTIM_SIZE", 0x100000L)) extends RocketTileConfig(tp => tp.copy( core = tp.core.copy(useVM = false), dcache = tp.dcache.map { dc => require(size > 0, s"DTIM size $size must be positive") require(base % dc.blockBytes == 0, s"DTIM base $base must be aligned to blockBytes ${dc.blockBytes}") require(size % dc.blockBytes == 0, s"DTIM size $size must be a multiple of blockBytes ${dc.blockBytes}") dc.copy( nSets = (size / dc.blockBytes).toInt, nWays = 1, nMSHRs = 0, scratch = Some(base)) } )) class WithVCU118HardDoubleFPU extends RocketTileConfig(tp => tp.copy( core = tp.core.copy(fpu = Some(FPUParams(minFLen = 32, fLen = 64, divSqrt = true))) )) class WithVCU118FlashBootROM(file: String = "./soc/out/software/bootloader/bootloader.img") extends Config((site, here, up) => { case BootROMLocated(InSubsystem) => Seq(BootROMParams( hang = 0x10000, appendDTB = false, contentFileName = SystemFileName(file))) }) case object VCU118UARTKey extends Field[Option[FpgaUARTParams]](None) case object VCU118SPIKey extends Field[Option[FpgaSPIParams]](None) case object VCU118PmodSPIKey extends Field[Option[FpgaSPIParams]](None) case object VCU118GPSKey extends Field[Option[FpgaGPSParams]](None) case object VCU118RAMKey extends Field[Option[AddressSet]](None) class VCU118RocketSystem(implicit p: Parameters) extends RocketSubsystem with HasAsyncExtInterrupts { val bootROM = p(BootROMLocated(location)).map { BootROM.attach(_, this, CBUS) } val maskROMs = p(MaskROMLocated(location)).map { MaskROM.attach(_, this, CBUS) } val uartRXSourceNode = p(VCU118UARTKey).map(_ => BundleBridgeSource(() => Bool())) val gpsAcqClockSourceNode = p(VCU118GPSKey).map(_ => BundleBridgeSource(() => Clock())) val gpsTrackingClockSourceNode = p(VCU118GPSKey).map(_ => BundleBridgeSource(() => Clock())) val gpsRfClockSourceNode = p(VCU118GPSKey).map(_ => BundleBridgeSource(() => Clock())) val gpsRfDataSourceNode = p(VCU118GPSKey).map(_ => BundleBridgeSource(() => UInt(4.W))) private val pmodIRQDevice = new SimpleDevice("pmod-sensor-irq", Seq("rocket,pmod-sensor-irq")) val pmodIRQIntNode = IntSourceNode(Seq(IntSourcePortParameters(Seq( IntSourceParameters(IntRange(0, 1), pmodIRQDevice.int))))) val ram = p(VCU118RAMKey).map { address => val tlram = LazyModule(new TLRAM(address, beatBytes = locateTLBusWrapper(SBUS).beatBytes, devName = Some("fpga-sram"))) tlram.node := locateTLBusWrapper(SBUS).coupleTo("fpga_sram") { TLFragmenter(locateTLBusWrapper(SBUS).beatBytes, locateTLBusWrapper(SBUS).blockBytes) := _ } tlram } val uart = p(VCU118UARTKey).map { params => val pbus = locateTLBusWrapper(PBUS) val domain = pbus.generateSynchronousDomain("FPGAUART").suggestName("fpga_uart_domain") val dev = domain { LazyModule(new TLFpgaUART(params, pbus.beatBytes)) } domain { dev.node := pbus.coupleTo("fpga_uart") { TLFragmenter(pbus, Some("FPGAUART")) := _ } } uartRXSourceNode.foreach { source => dev.rxdNode := source } dev } val uartTXSinkNode = uart.map(_.txdNode.makeSink()) val spiDQISourceNode = p(VCU118SPIKey).map(_ => BundleBridgeSource(() => UInt(4.W))) val spi = p(VCU118SPIKey).map { params => val pbus = locateTLBusWrapper(PBUS) val domain = pbus.generateSynchronousDomain("FPGASPI").suggestName("fpga_spi_domain") val dev = domain { LazyModule(new TLFpgaSPI(params, pbus.beatBytes)) } domain { dev.node := pbus.coupleTo("fpga_spi") { TLFragmenter(pbus, Some("FPGASPI")) := _ } } spiDQISourceNode.foreach { source => dev.dqInNode := source } dev } val spiSCKSinkNode = spi.map(_.sckNode.makeSink()) val spiCSNSinkNode = spi.map(_.csnNode.makeSink()) val spiDQOSinkNode = spi.map(_.dqOutNode.makeSink()) val spiDQOESinkNode = spi.map(_.dqOeNode.makeSink()) val pmodSPIDQISourceNode = p(VCU118PmodSPIKey).map(_ => BundleBridgeSource(() => UInt(4.W))) val pmodSPI = p(VCU118PmodSPIKey).map { params => val pbus = locateTLBusWrapper(PBUS) val domain = pbus.generateSynchronousDomain("FPGAPMODSPI").suggestName("fpga_pmod_spi_domain") val dev = domain { LazyModule(new TLFpgaSPI(params, pbus.beatBytes)) } domain { dev.node := pbus.coupleTo("fpga_pmod_spi") { TLFragmenter(pbus, Some("FPGAPMODSPI")) := _ } } pmodSPIDQISourceNode.foreach { source => dev.dqInNode := source } dev } val pmodSPISCKSinkNode = pmodSPI.map(_.sckNode.makeSink()) val pmodSPICSNSinkNode = pmodSPI.map(_.csnNode.makeSink()) val pmodSPIDQOSinkNode = pmodSPI.map(_.dqOutNode.makeSink()) val pmodSPIDQOESinkNode = pmodSPI.map(_.dqOeNode.makeSink()) val gps = p(VCU118GPSKey).map { params => val pbus = locateTLBusWrapper(PBUS) val domain = pbus.generateSynchronousDomain("FPGAGPS").suggestName("fpga_gps_domain") val gpsApbBeatBytes = 4 val dev = domain { LazyModule(new APBGpsBlock(params, gpsApbBeatBytes)) } domain { dev.node := TLToAPB() := pbus.coupleTo("gps") { TLFragmenter(gpsApbBeatBytes, pbus.blockBytes, nameSuffix = Some("FPGAGPS")) :*= TLWidthWidget(pbus) := _ } ibus.fromSync := dev.intnode } gpsAcqClockSourceNode.foreach { source => dev.acqClockNode := source } gpsTrackingClockSourceNode.foreach { source => dev.trackingClockNode := source } gpsRfClockSourceNode.foreach { source => dev.afeClockNode := source } gpsRfDataSourceNode.foreach { source => dev.rfDataNode := source } dev } val gpsPPSSinkNode = gps.map(_.ppsOutNode.makeSink()) ibus { ibus.fromAsync := pmodIRQIntNode } override lazy val module = new VCU118RocketSystemModuleImp(this) } class VCU118RocketSystemModuleImp[+L <: VCU118RocketSystem](_outer: L) extends RocketSubsystemModuleImp(_outer) with HasRTCModuleImp with HasExtInterruptsModuleImp with freechips.rocketchip.util.DontTouch { val uart_rxd = _outer.uartRXSourceNode.map(_.makeIO("uart_rxd")) val uart_txd = _outer.uartTXSinkNode.map(_.makeIO("uart_txd")) val spi_sck = _outer.spiSCKSinkNode.map(_.makeIO("spi_sck")) val spi_csn = _outer.spiCSNSinkNode.map(_.makeIO("spi_csn")) val spi_dq_i = _outer.spiDQISourceNode.map(_.makeIO("spi_dq_i")) val spi_dq_o = _outer.spiDQOSinkNode.map(_.makeIO("spi_dq_o")) val spi_dq_oe = _outer.spiDQOESinkNode.map(_.makeIO("spi_dq_oe")) val pmod_spi_sck = _outer.pmodSPISCKSinkNode.map(_.makeIO("pmod_spi_sck")) val pmod_spi_csn = _outer.pmodSPICSNSinkNode.map(_.makeIO("pmod_spi_csn")) val pmod_spi_dq_i = _outer.pmodSPIDQISourceNode.map(_.makeIO("pmod_spi_dq_i")) val pmod_spi_dq_o = _outer.pmodSPIDQOSinkNode.map(_.makeIO("pmod_spi_dq_o")) val pmod_spi_dq_oe = _outer.pmodSPIDQOESinkNode.map(_.makeIO("pmod_spi_dq_oe")) val pmod_irq = IO(Input(Bool())) val gps_acq_clk = _outer.gpsAcqClockSourceNode.map(_.makeIO("gps_acq_clk")) val gps_trck_clk = _outer.gpsTrackingClockSourceNode.map(_.makeIO("gps_trck_clk")) val gps_rf_clk = _outer.gpsRfClockSourceNode.map(_.makeIO("gps_rf_clk")) val gps_rf_data = _outer.gpsRfDataSourceNode.map(_.makeIO("gps_rf_data")) val gps_pps = _outer.gpsPPSSinkNode.map(_.makeIO("gps_pps")) _outer.pmodIRQIntNode.out.foreach { case (out, _) => out(0) := pmod_irq } } class VCU118RocketConfig extends Config( new WithVCU118FlashBootROM ++ new WithDebugSBA ++ new WithoutTLMonitors ++ new WithNoMemPort ++ new WithNoMMIOPort ++ new WithNoSlavePort ++ new WithNMemoryChannels(0) ++ new WithNBanks(0) ++ new WithVCU118HardDoubleFPU ++ new WithVCU118OneMiBDTIM ++ new WithVCU118UART(0x10013000L, 100000000, 115200) ++ new WithVCU118SPI(0x10014000L) ++ new WithVCU118PmodSPI(0x10015000L) ++ new WithVCU118GPS(0x10020000L, 9) ++ new WithNExtTopInterrupts(0) ++ new WithNSmallCores(1) ++ new WithIncoherentBusTopology ++ new BaseConfig) class VCU118RocketJtagConfig extends Config( new WithJtagDTM ++ new VCU118RocketConfig)