Compare commits
19 Commits
9d02f530fc
...
ml507
Author | SHA1 | Date | |
---|---|---|---|
b49f5cfa78 | |||
700e6b640d | |||
12cb1c2fa5 | |||
7e53be49f9 | |||
77694a6741 | |||
589e9960c0 | |||
2707fa59a4 | |||
3797385a8c | |||
79b53cf2ae | |||
5bcc4e82fd | |||
9c06418352 | |||
b2b19cc822 | |||
5db71d11c2 | |||
f4ae1d469f | |||
0b421d5645 | |||
8329b232e2 | |||
2ff28e6af6 | |||
41362a1cb5 | |||
e9625bf8ee |
@ -0,0 +1,199 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package sifive.fpgashells.devices.xilinx.xilinxml507mig
|
||||
|
||||
import Chisel._
|
||||
import chisel3.core.{Input, Output}
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.subsystem.{AsynchronousCrossing, HasCrossing}
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
case class XilinxML507MIGParams(
|
||||
address: Seq[AddressSet]
|
||||
)
|
||||
|
||||
class MemoryController extends BlackBox {
|
||||
val io = IO(new Bundle {
|
||||
val sys = new MemorySysIO
|
||||
val ddr2 = new MemoryDDR2IO
|
||||
|
||||
val request_addr = Input(UInt(28.W))
|
||||
val request_type = Input(Bool())
|
||||
val request_data = Input(UInt(256.W))
|
||||
val request_mask = Input(UInt(32.W))
|
||||
val request_valid = Input(Bool())
|
||||
val request_ready = Output(Bool())
|
||||
|
||||
val response_data = Output(UInt(256.W))
|
||||
val response_valid = Output(Bool())
|
||||
// no ready, as the mig does not wait
|
||||
})
|
||||
|
||||
override def desiredName: String = "memory_controller"
|
||||
}
|
||||
|
||||
class ResponseQueueIO extends Bundle {
|
||||
val read = Bool()
|
||||
val source = UInt()
|
||||
val size = UInt()
|
||||
}
|
||||
|
||||
class XilinxML507MIGToTL(c: XilinxML507MIGParams)(implicit p: Parameters) extends LazyModule with HasCrossing {
|
||||
// Corresponds to MIG interface with 64 bit width and a burst length of 4
|
||||
val width = 256
|
||||
val beatBytes = width/8 // 32 byte (half a cache-line, fragmented)
|
||||
|
||||
val address_range = AddressRange.fromSets(c.address).head
|
||||
require(log2Ceil(address_range.size) == 28, "Max 256MiB DIMMs supported")
|
||||
val crossing = AsynchronousCrossing(1)
|
||||
|
||||
val device = new MemoryDevice
|
||||
val node = TLManagerNode(
|
||||
Seq(TLManagerPortParameters(
|
||||
Seq(TLManagerParameters(
|
||||
address = c.address,
|
||||
resources = device.reg,
|
||||
regionType = RegionType.UNCACHED,
|
||||
executable = true,
|
||||
supportsGet = TransferSizes(1, beatBytes),
|
||||
supportsPutFull = TransferSizes(1, beatBytes),
|
||||
fifoId = Some(0) // in-order
|
||||
)),
|
||||
beatBytes = beatBytes
|
||||
))
|
||||
)
|
||||
// We could possibly also support supportsPutPartial, as we need support
|
||||
// for masks anyway because of the possibility of transfers smaller that
|
||||
// the data width (size signal, see below).
|
||||
// Seems we can: TL$7.3
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val io = IO(new Bundle {
|
||||
val port_sys = new MemorySysIO
|
||||
val port_ddr2 = new MemoryDDR2IO
|
||||
})
|
||||
|
||||
val controller = Module(new MemoryController)
|
||||
io.port_sys <> controller.io.sys
|
||||
io.port_ddr2 <> controller.io.ddr2
|
||||
|
||||
// in: TLBundle, edge: TLEdgeIn
|
||||
val (in, edge) = node.in(0)
|
||||
|
||||
// Due to the TLFragmenter defined below, all messages are 32 bytes or
|
||||
// smaller. The data signal of the TL channels is also 32 bytes, so
|
||||
// all messages will be transfered in a single beat.
|
||||
// Also, TL guarantees (see TL$4.6) that the payload of a data message
|
||||
// is always aligned to the width of the beat, e.g. in case of a 32
|
||||
// byte data signal, data[7:0] will always have address 0x***00000 and
|
||||
// data[255:247] address 0x***11111. It is also guaranteed that the
|
||||
// mask bits always correctly reflect the active bytes inside the beat
|
||||
// with respect to the size and address. So we can directly forward
|
||||
// the mask, (relative) address and data to the MIG interface.
|
||||
|
||||
// An AddressSet is always aligned, so we don't need to subtract the
|
||||
// base address, we can just take the lower bits. The lowest 5 bits
|
||||
// are used for indexing the 32 byte word of the MIG.
|
||||
val address = in.a.bits.address(27, 0) & "hFFFFFE0".U
|
||||
|
||||
// Save the source, size and type of the requests in a queue so we
|
||||
// can synthesize the right responses in fifo order. The length also
|
||||
// determines the maximum number of in-flight requests.
|
||||
val ack_queue = Module(new Queue(new ResponseQueueIO, 2))
|
||||
|
||||
// Pass data directly to the controller
|
||||
controller.io.request_addr := address
|
||||
controller.io.request_type := !edge.hasData(in.a.bits)
|
||||
controller.io.request_data := in.a.bits.data
|
||||
// TL uses high to indicate valid data while mig uses low
|
||||
controller.io.request_mask := ~ in.a.bits.mask
|
||||
|
||||
ack_queue.io.enq.bits.read := !edge.hasData(in.a.bits)
|
||||
ack_queue.io.enq.bits.source := in.a.bits.source
|
||||
ack_queue.io.enq.bits.size := in.a.bits.size
|
||||
|
||||
// We are ready when the controller and the queue input are ready
|
||||
in.a.ready := controller.io.request_ready && ack_queue.io.enq.ready
|
||||
// Both queues only latch data if the other is ready, so that data
|
||||
// is latched into both queues or not at all
|
||||
controller.io.request_valid := in.a.valid && ack_queue.io.enq.ready
|
||||
ack_queue.io.enq.valid := in.a.valid && controller.io.request_ready
|
||||
|
||||
|
||||
// We have to buffer the responses from the MIG as it has no internal
|
||||
// buffer and will output its read responses only for one cycle. To
|
||||
// avoid losing any responses, this queue *must* be at least as wide
|
||||
// as the ack queue, so that we can catch all responses, even if the
|
||||
// ack queue is completely filled with read requests.
|
||||
val response_queue = Module(new Queue(controller.io.response_data, 2))
|
||||
|
||||
response_queue.io.enq.bits := controller.io.response_data
|
||||
response_queue.io.enq.valid := controller.io.response_valid
|
||||
// MIG does not support delaying a response, so we ignore enq.ready.
|
||||
// This will result in lost reads and returning wrong data in further
|
||||
// AccessAckData messages, so this must be avoided (see above).
|
||||
|
||||
// Acks may or may not contain data depending on the request, but we
|
||||
// can always pass the data, even if it is invalid in the write case,
|
||||
// because it is ignored for AccessAck responses
|
||||
val response_read = ack_queue.io.deq.bits.read
|
||||
in.d.bits.opcode := Mux(response_read, TLMessages.AccessAckData, TLMessages.AccessAck)
|
||||
in.d.bits.param := UInt(0) // reserved, must be 0
|
||||
in.d.bits.size := ack_queue.io.deq.bits.size
|
||||
in.d.bits.source := ack_queue.io.deq.bits.source
|
||||
in.d.bits.sink := UInt(0) // ignored
|
||||
in.d.bits.data := response_queue.io.deq.bits
|
||||
in.d.bits.error := Bool(false)
|
||||
|
||||
// The data is valid when the ack queue data is valid (write case) or
|
||||
// when the ack *and* response queues are valid (read case)
|
||||
in.d.valid := ack_queue.io.deq.valid && (!response_read ||
|
||||
response_queue.io.deq.valid)
|
||||
// Let the ack queue dequeue when the master is ready (write case) or
|
||||
// when the master is ready *and* there is a valid response (read case)
|
||||
ack_queue.io.deq.ready := in.d.ready && (!response_read ||
|
||||
response_queue.io.deq.valid)
|
||||
// Let the response queue dequeue when the master is ready and there
|
||||
// is a valid read ack waiting
|
||||
response_queue.io.deq.ready := in.d.ready && response_read &&
|
||||
ack_queue.io.deq.valid
|
||||
|
||||
|
||||
// Tie off unused channels
|
||||
in.b.valid := Bool(false)
|
||||
in.c.ready := Bool(true)
|
||||
in.e.ready := Bool(true)
|
||||
}
|
||||
}
|
||||
|
||||
class XilinxML507MIG(c : XilinxML507MIGParams)(implicit p: Parameters) extends LazyModule {
|
||||
// The Fragmenter will not fragment messages <= 32 bytes, so all
|
||||
// slaves have to support this size. 64 byte specifies the maximum
|
||||
// supported transfer size that the slave side of the fragmenter supports
|
||||
// against the master (here the main memory bus). Specifying alwaysMin as
|
||||
// true results in all messages being fragmented to the minimal size
|
||||
// (32 byte). In TL1 terms, slaves correspond roughly to managers and
|
||||
// masters to clients (confusingly…).
|
||||
val fragmenter = LazyModule(new TLFragmenter(32, 64, alwaysMin=true))
|
||||
val island = LazyModule(new XilinxML507MIGToTL(c))
|
||||
|
||||
val node: TLInwardNode =
|
||||
island.node := island.crossTLIn := fragmenter.node
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val io = IO(new Bundle {
|
||||
val port_sys = new MemorySysIO
|
||||
val port_ddr2 = new MemoryDDR2IO
|
||||
})
|
||||
|
||||
io.port_sys <> island.module.io.port_sys
|
||||
io.port_ddr2 <> island.module.io.port_ddr2
|
||||
|
||||
// The MIGToTL module lives in a separate clock domain together with
|
||||
// the MIG, which is why it is called "island".
|
||||
island.module.clock := io.port_sys.clk0
|
||||
island.module.reset := io.port_sys.reset
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package sifive.fpgashells.devices.xilinx.xilinxml507mig
|
||||
|
||||
import Chisel._
|
||||
import chisel3.core.{Input, Output}
|
||||
import chisel3.experimental.Analog
|
||||
import freechips.rocketchip.config.Field
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.subsystem.BaseSubsystem
|
||||
|
||||
case object MemoryML507Key extends Field[XilinxML507MIGParams]
|
||||
|
||||
trait HasMemoryML507 { this: BaseSubsystem =>
|
||||
val memory = LazyModule(new XilinxML507MIG(p(MemoryML507Key)))
|
||||
|
||||
memory.node := memBuses.head.toDRAMController(Some("xilinxml507mig"))()
|
||||
}
|
||||
|
||||
class MemorySysIO extends Bundle {
|
||||
val clk0 = Input(Clock())
|
||||
val clk90 = Input(Clock())
|
||||
val clkdiv0 = Input(Clock())
|
||||
val clk_locked = Input(Bool())
|
||||
val clk_idelay = Input(Clock())
|
||||
val reset = Input(Bool())
|
||||
}
|
||||
|
||||
class MemoryDDR2IO extends Bundle {
|
||||
val dq = Analog(64.W)
|
||||
val a = Output(Bits(13.W))
|
||||
val ba = Output(Bits(2.W))
|
||||
val ras_n = Output(Bits(1.W))
|
||||
val cas_n = Output(Bits(1.W))
|
||||
val we_n = Output(Bits(1.W))
|
||||
val cs_n = Output(Bits(1.W))
|
||||
val odt = Output(Bits(1.W))
|
||||
val cke = Output(Bits(1.W))
|
||||
val dm = Output(Bits(8.W))
|
||||
val dqs = Analog(8.W)
|
||||
val dqs_n = Analog(8.W)
|
||||
val ck = Output(Bits(2.W))
|
||||
val ck_n = Output(Bits(2.W))
|
||||
}
|
||||
|
||||
trait HasMemoryML507Bundle {
|
||||
val ddr_sys: MemorySysIO
|
||||
val ddr2: MemoryDDR2IO
|
||||
}
|
||||
|
||||
trait HasMemoryML507ModuleImp extends LazyModuleImp with HasMemoryML507Bundle {
|
||||
val outer: HasMemoryML507
|
||||
val ddr_sys = IO(new MemorySysIO)
|
||||
val ddr2 = IO(new MemoryDDR2IO)
|
||||
|
||||
ddr_sys <> outer.memory.module.io.port_sys
|
||||
ddr2 <> outer.memory.module.io.port_ddr2
|
||||
}
|
@ -94,6 +94,37 @@ object PowerOnResetFPGAOnly {
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// ml507 clocks (DCM_ADV)
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
class ml507_sys_clock extends BlackBox {
|
||||
val io = new Bundle {
|
||||
val CLKIN_IN = Clock(INPUT)
|
||||
val CLKFX_OUT = Clock(OUTPUT)
|
||||
val LOCKED_OUT = Bool(OUTPUT)
|
||||
}
|
||||
}
|
||||
|
||||
class ml507_dvi_clock extends BlackBox {
|
||||
val io = new Bundle {
|
||||
val CLKIN_IN = Clock(INPUT)
|
||||
val CLKFX_OUT = Clock(OUTPUT)
|
||||
val LOCKED_OUT = Bool(OUTPUT)
|
||||
}
|
||||
}
|
||||
|
||||
class ml507_ddr2_clock extends BlackBox {
|
||||
val io = new Bundle {
|
||||
val CLKIN_P_IN = Clock(INPUT)
|
||||
val CLKIN_N_IN = Clock(INPUT)
|
||||
val CLK0_OUT = Clock(OUTPUT)
|
||||
val CLK90_OUT = Clock(OUTPUT)
|
||||
val CLKDV_OUT = Clock(OUTPUT)
|
||||
val LOCKED_OUT = Bool(OUTPUT)
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// vc707_sys_clock_mmcm
|
||||
//-------------------------------------------------------------------------
|
||||
|
249
src/main/scala/shell/xilinx/ML507Shell.scala
Normal file
249
src/main/scala/shell/xilinx/ML507Shell.scala
Normal file
@ -0,0 +1,249 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.fpgashells.shell.xilinx.ml507shell
|
||||
|
||||
import Chisel._
|
||||
import chisel3.core.{Input, Output, attach}
|
||||
import chisel3.experimental.{RawModule, Analog, withClockAndReset}
|
||||
|
||||
import freechips.rocketchip.config._
|
||||
import freechips.rocketchip.devices.debug._
|
||||
import freechips.rocketchip.util.{SyncResetSynchronizerShiftReg, ElaborationArtefacts, HeterogeneousBag}
|
||||
|
||||
import sifive.blocks.devices.gpio._
|
||||
import sifive.blocks.devices.spi._
|
||||
import sifive.blocks.devices.uart._
|
||||
import sifive.blocks.devices.chiplink._
|
||||
import sifive.blocks.devices.terminal._
|
||||
|
||||
import sifive.fpgashells.devices.xilinx.xilinxml507mig._
|
||||
import sifive.fpgashells.ip.xilinx.{PowerOnResetFPGAOnly, sdio_spi_bridge, ml507_ddr2_clock, ml507_dvi_clock, ml507_sys_clock, vc707reset}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// ML507Shell
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// TODO: trait HasDDR2 { … }
|
||||
|
||||
trait HasDebugJTAG { this: ML507Shell =>
|
||||
// JTAG
|
||||
val jtag_TCK = IO(Input(Clock()))
|
||||
val jtag_TMS = IO(Input(Bool()))
|
||||
val jtag_TDI = IO(Input(Bool()))
|
||||
val jtag_TDO = IO(Output(Bool()))
|
||||
|
||||
def connectDebugJTAG(dut: HasPeripheryDebugModuleImp, fmcxm105: Boolean = true): SystemJTAGIO = {
|
||||
val djtag = dut.debug.systemjtag.get
|
||||
|
||||
djtag.jtag.TCK := jtag_TCK
|
||||
djtag.jtag.TMS := jtag_TMS
|
||||
djtag.jtag.TDI := jtag_TDI
|
||||
jtag_TDO := djtag.jtag.TDO.data
|
||||
|
||||
djtag.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W)
|
||||
|
||||
djtag.reset := PowerOnResetFPGAOnly(dut_clock)
|
||||
dut_ndreset := dut.debug.ndreset
|
||||
djtag
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract class ML507Shell(implicit val p: Parameters) extends RawModule {
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Interface
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
// 100Mhz sysclk
|
||||
val sys_clock = IO(Input(Clock()))
|
||||
|
||||
// 200MHz ddrclk
|
||||
val ddr_clock_p = IO(Input(Clock()))
|
||||
val ddr_clock_n = IO(Input(Clock()))
|
||||
|
||||
// active high async reset
|
||||
val reset = IO(Input(Bool()))
|
||||
|
||||
// LED
|
||||
val led = IO(Output(Vec(8, Bool())))
|
||||
|
||||
// DIP switches
|
||||
val dip = IO(Input(Vec(8, Bool())))
|
||||
|
||||
// UART
|
||||
val uart_tx = IO(Output(Bool()))
|
||||
val uart_rx = IO(Input(Bool()))
|
||||
|
||||
// SDIO
|
||||
val sdio_clk = IO(Output(Bool()))
|
||||
val sdio_cmd = IO(Analog(1.W))
|
||||
val sdio_dat = IO(Analog(4.W))
|
||||
|
||||
// Feedback
|
||||
val clock_led = IO(Output(Clock()))
|
||||
val reset_led = IO(Output(Bool()))
|
||||
|
||||
val dvi = IO(new TerminalDVIIO)
|
||||
val ddr2 = IO(new MemoryDDR2IO)
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Wire declrations
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
// async resets
|
||||
val sys_reset = Wire(Bool())
|
||||
val do_reset = Wire(Bool())
|
||||
val dut_ndreset = Wire(Bool())
|
||||
|
||||
val dut_clock = Wire(Clock())
|
||||
val dut_reset = Wire(Bool())
|
||||
|
||||
val dvi_clock = Wire(Clock())
|
||||
val dvi_reset = Wire(Bool())
|
||||
|
||||
val ddr_clk0 = Wire(Clock())
|
||||
val ddr_clk90 = Wire(Clock())
|
||||
val ddr_clkdiv0 = Wire(Clock())
|
||||
val ddr_clk_locked = Wire(Bool())
|
||||
val ddr_reset = Wire(Bool())
|
||||
|
||||
val sd_spi_sck = Wire(Bool())
|
||||
val sd_spi_cs = Wire(Bool())
|
||||
val sd_spi_dq_i = Wire(Vec(4, Bool()))
|
||||
val sd_spi_dq_o = Wire(Vec(4, Bool()))
|
||||
|
||||
val clk_locked = Wire(Bool())
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// System reset
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
// Allow the debug module to reset everything. Resets the MIG
|
||||
sys_reset := reset | dut_ndreset
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Clock generators
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
// 80 MHz (processor clock)
|
||||
val ml507_sys_clock = Module(new ml507_sys_clock)
|
||||
ml507_sys_clock.io.CLKIN_IN := sys_clock
|
||||
dut_clock := ml507_sys_clock.io.CLKFX_OUT
|
||||
|
||||
// 48 MHz (DVI pixel clock for SDR 640x480x60)
|
||||
val ml507_dvi_clock = Module(new ml507_dvi_clock)
|
||||
ml507_dvi_clock.io.CLKIN_IN := sys_clock
|
||||
dvi_clock := ml507_dvi_clock.io.CLKFX_OUT
|
||||
|
||||
// 200 MHz (DDR2 and IDELAY clock)
|
||||
val ml507_ddr2_clock = Module(new ml507_ddr2_clock)
|
||||
ml507_ddr2_clock.io.CLKIN_P_IN := ddr_clock_p
|
||||
ml507_ddr2_clock.io.CLKIN_N_IN := ddr_clock_n
|
||||
ddr_clk0 := ml507_ddr2_clock.io.CLK0_OUT
|
||||
ddr_clk90 := ml507_ddr2_clock.io.CLK90_OUT
|
||||
ddr_clkdiv0 := ml507_ddr2_clock.io.CLKDV_OUT
|
||||
ddr_clk_locked := ml507_ddr2_clock.io.LOCKED_OUT
|
||||
|
||||
// Clocks locked?
|
||||
clk_locked := ml507_sys_clock.io.LOCKED_OUT &
|
||||
ml507_dvi_clock.io.LOCKED_OUT &
|
||||
ddr_clk_locked
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// System reset
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
do_reset := !clk_locked || sys_reset
|
||||
|
||||
// synchronize async resets
|
||||
val safe_reset = Module(new vc707reset)
|
||||
|
||||
safe_reset.io.areset := do_reset
|
||||
safe_reset.io.clock1 := ddr_clk0
|
||||
ddr_reset := safe_reset.io.reset1
|
||||
safe_reset.io.clock2 := dut_clock
|
||||
safe_reset.io.clock3 := dvi_clock
|
||||
dvi_reset := safe_reset.io.reset3
|
||||
safe_reset.io.clock4 := dut_clock
|
||||
dut_reset := safe_reset.io.reset4
|
||||
|
||||
// Setup feedback
|
||||
clock_led := dut_clock
|
||||
reset_led := dut_reset
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Terminal
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
def connectTerminal(dut: HasPeripheryTerminalModuleImp): Unit = {
|
||||
dvi <> dut.dvi
|
||||
dut.terminal.clk := dvi_clock
|
||||
dut.terminal.reset := dvi_reset
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Memory controller
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
def connectDDRMemory(dut: HasMemoryML507ModuleImp): Unit = {
|
||||
ddr2 <> dut.ddr2
|
||||
|
||||
dut.ddr_sys.clk0 := ddr_clk0
|
||||
dut.ddr_sys.clk90 := ddr_clk90
|
||||
dut.ddr_sys.clkdiv0 := ddr_clkdiv0
|
||||
dut.ddr_sys.clk_locked := ddr_clk_locked
|
||||
dut.ddr_sys.clk_idelay := ddr_clk0
|
||||
dut.ddr_sys.reset := ddr_reset
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// UART
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
def connectUART(dut: HasPeripheryUARTModuleImp): Unit = {
|
||||
val uartParams = p(PeripheryUARTKey)
|
||||
if (!uartParams.isEmpty) {
|
||||
// uart connections
|
||||
dut.uart(0).rxd := SyncResetSynchronizerShiftReg(uart_rx, 2, init = Bool(true), name=Some("uart_rxd_sync"))
|
||||
uart_tx := dut.uart(0).txd
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// SPI
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
def connectSPI(dut: HasPeripherySPIModuleImp): Unit = {
|
||||
// SPI
|
||||
sd_spi_sck := dut.spi(0).sck
|
||||
sd_spi_cs := dut.spi(0).cs(0)
|
||||
|
||||
dut.spi(0).dq.zipWithIndex.foreach {
|
||||
case(pin, idx) =>
|
||||
sd_spi_dq_o(idx) := pin.o
|
||||
pin.i := sd_spi_dq_i(idx)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// SDIO <> SPI Bridge
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
val ip_sdio_spi = Module(new sdio_spi_bridge())
|
||||
|
||||
ip_sdio_spi.io.clk := dut_clock
|
||||
ip_sdio_spi.io.reset := dut_reset
|
||||
|
||||
// SDIO
|
||||
attach(sdio_dat, ip_sdio_spi.io.sd_dat)
|
||||
attach(sdio_cmd, ip_sdio_spi.io.sd_cmd)
|
||||
sdio_clk := ip_sdio_spi.io.spi_sck
|
||||
|
||||
// SPI
|
||||
ip_sdio_spi.io.spi_sck := sd_spi_sck
|
||||
ip_sdio_spi.io.spi_cs := sd_spi_cs
|
||||
sd_spi_dq_i := ip_sdio_spi.io.spi_dq_i.toBools
|
||||
ip_sdio_spi.io.spi_dq_o := sd_spi_dq_o.asUInt
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user