Compare commits
	
		
			14 Commits
		
	
	
		
			master
			...
			589e9960c0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 589e9960c0 | |||
| 2707fa59a4 | |||
| 3797385a8c | |||
| 79b53cf2ae | |||
| 5bcc4e82fd | |||
| 9c06418352 | |||
| b2b19cc822 | |||
| 5db71d11c2 | |||
| f4ae1d469f | |||
| 0b421d5645 | |||
| 8329b232e2 | |||
| 2ff28e6af6 | |||
| 41362a1cb5 | |||
| e9625bf8ee | 
| @@ -0,0 +1,147 @@ | ||||
| // 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_read = 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 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 crossing = AsynchronousCrossing(8) | ||||
|  | ||||
|     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). | ||||
|  | ||||
|     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 Fragmenter defined above, 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 possibly | ||||
|         // data to the MIG interface. | ||||
|         // Put requests can be acknowledged as soon as they are latched into | ||||
|         // the write fifo of the MIG (possibly combinatorily). | ||||
|         // For read requests, we have to store the source id and size in a | ||||
|         // queue for later acknowledgment. | ||||
|         // We are ready if both the MIG and the response data queue are not | ||||
|         // full. | ||||
|  | ||||
|         // Widths of the A channel: | ||||
|         // addressBits: 32 | ||||
|         // dataBits:    256 | ||||
|         // sourceBits:  6 | ||||
|         // sinkBits:    1 | ||||
|         // sizeBits:    3 | ||||
|  | ||||
|         // source (from): in.a.bits.source | ||||
|         // adresse (to): edgeIn.address(in.a.bits) | ||||
|         // size: edgeIn.size(in.a.bits) | ||||
|         // isPut: edgeIn.hasData(in.a.bits) | ||||
|  | ||||
|         // bits kommt von Decoupled: ready, valid + bits | ||||
|  | ||||
|         println("a parameters: " + in.a.bits.params) | ||||
|  | ||||
|         in.a.ready := Bool(false) | ||||
|         in.d.valid := Bool(false) | ||||
|  | ||||
|         // 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,26 @@ 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) | ||||
|   } | ||||
| } | ||||
|  | ||||
| //------------------------------------------------------------------------- | ||||
| // vc707_sys_clock_mmcm | ||||
| //------------------------------------------------------------------------- | ||||
|   | ||||
							
								
								
									
										221
									
								
								src/main/scala/shell/xilinx/ML507Shell.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								src/main/scala/shell/xilinx/ML507Shell.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,221 @@ | ||||
| // 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_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())) | ||||
|  | ||||
|   // 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 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 | ||||
|  | ||||
|   // Clocks locked? | ||||
|   clk_locked := ml507_sys_clock.io.LOCKED_OUT & | ||||
|                 ml507_dvi_clock.io.LOCKED_OUT | ||||
|  | ||||
|   //----------------------------------------------------------------------- | ||||
|   // 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 := dut_clock | ||||
|   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 | ||||
|   } | ||||
|  | ||||
|   //----------------------------------------------------------------------- | ||||
|   // 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