From 1786546d4eb00dac2b8c619b59f8aea35b51a5ec Mon Sep 17 00:00:00 2001 From: Boran Car Date: Mon, 11 Feb 2019 00:04:03 +0000 Subject: [PATCH] Clone relevant sifive/freedom sifive/freedom commit id cloned is 3624efff1819e52cec30c72f9085158189f8b53f. --- .gitignore | 5 + .gitmodules | 3 + LICENSE | 202 ++++ Makefile.e300artydevkit | 22 + bootrom/xip/Makefile | 45 + bootrom/xip/xip.S | 16 + build.sbt | 38 + common.mk | 114 ++ fpga-shells/.gitignore | 1 + fpga-shells/microsemi/common/tcl/libero.tcl | 217 ++++ .../constraints/PF_EvalKit_DDR3_fp.pdc | 34 + .../constraints/PF_EvalKit_DDR3_io.pdc | 319 +++++ .../constraints/PF_EvalKit_PCIe_fp.pdc | 29 + .../constraints/PF_EvalKit_PCIe_io.pdc | 133 +++ .../constraints/PF_EvalKit_base_io.pdc | 199 ++++ .../constraints/PF_EvalKit_fp.pdc | 3 + .../constraints/chiplink_io.pdc | 432 +++++++ .../constraints/clock_groups.sdc | 5 + .../vera/constraints/false_paths.sdc | 49 + .../microsemi/vera/constraints/floor_plan.pdc | 46 + .../vera/constraints/pin_constraints.pdc | 1059 +++++++++++++++++ .../src/main/scala/clocks/Bundles.scala | 17 + .../src/main/scala/clocks/ClockGroup.scala | 33 + fpga-shells/src/main/scala/clocks/Nodes.scala | 70 ++ .../src/main/scala/clocks/PLLFactory.scala | 91 ++ .../src/main/scala/clocks/Parameters.scala | 77 ++ .../src/main/scala/clocks/ResetWrangler.scala | 44 + .../MicrosemiPolarFireDDR3.scala | 165 +++ .../MicrosemiPolarFireDDR3Periphery.scala | 37 + .../MicrosemiPolarFireDDR4.scala | 166 +++ .../MicrosemiPolarFireDDR4Periphery.scala | 37 + .../PolarFireEvalKitPCIeX4.scala | 75 ++ .../PolarFireEvalKitPCIeX4Periphery.scala | 35 + .../main/scala/devices/xilinx/xdma/XDMA.scala | 52 + .../scala/devices/xilinx/xdma/package.scala | 10 + .../xilinxvc707mig/XilinxVC707MIG.scala | 170 +++ .../XilinxVC707MIGPeriphery.scala | 35 + .../xilinxvc707pciex1/XilinxVC707PCIeX1.scala | 76 ++ .../XilinxVC707PCIeX1Periphery.scala | 32 + .../xilinxvcu118mig/XilinxVCU118MIG.scala | 163 +++ .../XilinxVCU118MIGPeriphery.scala | 35 + .../corejtagdebug/corejtagdebug.scala | 71 ++ .../main/scala/ip/microsemi/polarfire.scala | 32 + .../polarfire_ccc/PolarFireCCC.scala | 86 ++ .../PolarFireClockDivider.scala | 40 + .../polarfire_ddr3/PolarFireDDR3.scala | 129 ++ .../polarfire_ddr4/PolarFireDDR4.scala | 132 ++ .../polarfire_dll/PolarFireDLL.scala | 46 + .../PolarFireGlitchlessMux.scala | 41 + .../PolarFireInitMonitor.scala | 42 + .../PolarFireOscillator.scala | 37 + .../PolarFirePCIeRootPort.scala | 610 ++++++++++ .../polarfire_reset/PolarFireReset.scala | 44 + .../polarfire_tx_pll/PolarFireTxPLL.scala | 45 + .../PolarFireTransceiverRefClk.scala | 46 + .../src/main/scala/ip/xilinx/Unisim.scala | 370 ++++++ .../src/main/scala/ip/xilinx/Xilinx.scala | 355 ++++++ .../ip/xilinx/ibufds_gte2/ibufds_gte2.scala | 18 + .../vc707axi_to_pcie_x1.scala | 491 ++++++++ .../scala/ip/xilinx/vc707mig/vc707mig.scala | 534 +++++++++ .../scala/ip/xilinx/vcu118mig/vcu118mig.scala | 179 +++ .../src/main/scala/ip/xilinx/xdma/xdma.scala | 466 ++++++++ .../main/scala/shell/ChipLinkOverlay.scala | 50 + .../src/main/scala/shell/ClockOverlay.scala | 36 + .../src/main/scala/shell/DDROverlay.scala | 21 + .../src/main/scala/shell/IOShell.scala | 158 +++ .../main/scala/shell/JTAGDebugOverlay.scala | 39 + .../src/main/scala/shell/LEDOverlay.scala | 23 + .../src/main/scala/shell/PCIeOverlay.scala | 23 + .../src/main/scala/shell/SDIOOverlay.scala | 67 ++ fpga-shells/src/main/scala/shell/Shell.scala | 61 + .../src/main/scala/shell/SwitchOverlay.scala | 23 + .../src/main/scala/shell/UARTOverlay.scala | 54 + .../microsemi/PolarFireEvalKitShell.scala | 659 ++++++++++ .../scala/shell/microsemi/VeraShell.scala | 286 +++++ .../src/main/scala/shell/package.scala | 10 + .../main/scala/shell/xilinx/ArtyShell.scala | 247 ++++ .../scala/shell/xilinx/ChipLinkOverlay.scala | 71 ++ .../scala/shell/xilinx/ClockOverlay.scala | 24 + .../scala/shell/xilinx/JTAGDebugOverlay.scala | 13 + .../main/scala/shell/xilinx/LEDOverlay.scala | 26 + .../main/scala/shell/xilinx/SDIOOverlay.scala | 13 + .../scala/shell/xilinx/SwitchOverlay.scala | 33 + .../main/scala/shell/xilinx/UARTOverlay.scala | 13 + .../scala/shell/xilinx/UltraScaleShell.scala | 81 ++ .../scala/shell/xilinx/VC707NewShell.scala | 237 ++++ .../main/scala/shell/xilinx/VC707Shell.scala | 611 ++++++++++ .../scala/shell/xilinx/VCU118NewShell.scala | 308 +++++ .../main/scala/shell/xilinx/VCU118Shell.scala | 274 +++++ .../main/scala/shell/xilinx/XilinxShell.scala | 76 ++ fpga-shells/xilinx/Makefile | 42 + .../xilinx/arty/constraints/arty-config.xdc | 5 + .../xilinx/arty/constraints/arty-master.xdc | 240 ++++ fpga-shells/xilinx/arty/tcl/board.tcl | 5 + fpga-shells/xilinx/arty/tcl/ip.tcl | 44 + .../arty_a7_100/constraints/arty-config.xdc | 5 + .../arty_a7_100/constraints/arty-master.xdc | 240 ++++ fpga-shells/xilinx/arty_a7_100/tcl/board.tcl | 5 + fpga-shells/xilinx/arty_a7_100/tcl/ip.tcl | 44 + fpga-shells/xilinx/common/tcl/bitstream.tcl | 10 + fpga-shells/xilinx/common/tcl/boards.tcl | 9 + fpga-shells/xilinx/common/tcl/init.tcl | 48 + fpga-shells/xilinx/common/tcl/opt.tcl | 7 + fpga-shells/xilinx/common/tcl/place.tcl | 13 + fpga-shells/xilinx/common/tcl/prologue.tcl | 119 ++ fpga-shells/xilinx/common/tcl/report.tcl | 44 + fpga-shells/xilinx/common/tcl/route.tcl | 10 + fpga-shells/xilinx/common/tcl/synth.tcl | 10 + fpga-shells/xilinx/common/tcl/util.tcl | 24 + fpga-shells/xilinx/common/tcl/vivado.tcl | 38 + .../xilinx/common/tcl/write_cfgmem.tcl | 26 + .../xilinx/common/vsrc/PowerOnResetFPGAOnly.v | 16 + .../xilinx/vc707/constraints/vc707-master.xdc | 6 + fpga-shells/xilinx/vc707/tcl/board.tcl | 4 + fpga-shells/xilinx/vc707/tcl/clocks.tcl | 50 + fpga-shells/xilinx/vc707/tcl/ios.tcl | 68 ++ fpga-shells/xilinx/vc707/vsrc/sdio.v | 58 + fpga-shells/xilinx/vc707/vsrc/vc707reset.v | 78 ++ .../vcu118/constraints/vcu118-master.xdc | 12 + fpga-shells/xilinx/vcu118/tcl/board.tcl | 6 + fpga-shells/xilinx/vcu118/vsrc/sdio.v | 59 + fpga-shells/xilinx/vcu118/vsrc/vcu118reset.v | 78 ++ rocket-chip | 1 + sifive-blocks/.gitignore | 2 + sifive-blocks/LICENSE | 202 ++++ .../src/main/resources/BlackBoxDelayBuffer.v | 14 + .../main/scala/devices/chiplink/Bundles.scala | 93 ++ .../src/main/scala/devices/chiplink/CAM.scala | 37 + .../scala/devices/chiplink/ChipLink.scala | 238 ++++ .../scala/devices/chiplink/Parameters.scala | 140 +++ .../main/scala/devices/chiplink/Partial.scala | 106 ++ .../src/main/scala/devices/chiplink/RX.scala | 91 ++ .../main/scala/devices/chiplink/SinkA.scala | 65 + .../main/scala/devices/chiplink/SinkB.scala | 62 + .../main/scala/devices/chiplink/SinkC.scala | 63 + .../main/scala/devices/chiplink/SinkD.scala | 60 + .../main/scala/devices/chiplink/SinkE.scala | 33 + .../main/scala/devices/chiplink/SourceA.scala | 105 ++ .../main/scala/devices/chiplink/SourceB.scala | 69 ++ .../main/scala/devices/chiplink/SourceC.scala | 87 ++ .../main/scala/devices/chiplink/SourceD.scala | 83 ++ .../main/scala/devices/chiplink/SourceE.scala | 21 + .../src/main/scala/devices/chiplink/TX.scala | 110 ++ .../src/main/scala/devices/gpio/GPIO.scala | 255 ++++ .../scala/devices/gpio/GPIOCtrlRegs.scala | 22 + .../scala/devices/gpio/GPIOPeriphery.scala | 21 + .../main/scala/devices/gpio/GPIOPins.scala | 40 + .../src/main/scala/devices/gpio/IOF.scala | 64 + .../src/main/scala/devices/i2c/I2C.scala | 613 ++++++++++ .../main/scala/devices/i2c/I2CCtrlRegs.scala | 13 + .../main/scala/devices/i2c/I2CPeriphery.scala | 24 + .../src/main/scala/devices/i2c/I2CPins.scala | 31 + .../main/scala/devices/jtag/JTAGPins.scala | 37 + .../main/scala/devices/mockaon/MockAON.scala | 101 ++ .../devices/mockaon/MockAONPeriphery.scala | 53 + .../devices/mockaon/MockAONWrapper.scala | 173 +++ .../src/main/scala/devices/mockaon/PMU.scala | 154 +++ .../src/main/scala/devices/mockaon/RTC.scala | 38 + .../scala/devices/mockaon/WatchdogTimer.scala | 66 + .../main/scala/devices/msi/MSIMaster.scala | 79 ++ .../main/scala/devices/pinctrl/PinCtrl.scala | 110 ++ .../src/main/scala/devices/pwm/PWM.scala | 128 ++ .../main/scala/devices/pwm/PWMPeriphery.scala | 22 + .../src/main/scala/devices/pwm/PWMPins.scala | 28 + .../devices/spi/BlackBoxDelayBuffer.scala | 14 + .../src/main/scala/devices/spi/SPI.scala | 101 ++ .../main/scala/devices/spi/SPIArbiter.scala | 42 + .../main/scala/devices/spi/SPIBundle.scala | 108 ++ .../main/scala/devices/spi/SPIConsts.scala | 33 + .../src/main/scala/devices/spi/SPIFIFO.scala | 62 + .../src/main/scala/devices/spi/SPIFlash.scala | 171 +++ .../src/main/scala/devices/spi/SPIMedia.scala | 125 ++ .../main/scala/devices/spi/SPIPeriphery.scala | 39 + .../main/scala/devices/spi/SPIPhysical.scala | 225 ++++ .../src/main/scala/devices/spi/SPIPins.scala | 38 + .../src/main/scala/devices/spi/SPIRegs.scala | 32 + .../src/main/scala/devices/spi/TLSPI.scala | 192 +++ .../main/scala/devices/spi/TLSPIFlash.scala | 132 ++ .../scala/devices/stream/PseudoStream.scala | 118 ++ .../devices/stream/PseudoStreamRegs.scala | 9 + .../src/main/scala/devices/uart/UART.scala | 179 +++ .../scala/devices/uart/UARTCtrlRegs.scala | 15 + .../scala/devices/uart/UARTPeriphery.scala | 25 + .../main/scala/devices/uart/UARTPins.scala | 25 + .../src/main/scala/devices/uart/UARTRx.scala | 93 ++ .../src/main/scala/devices/uart/UARTTx.scala | 46 + .../ip/xilinx/ibufds_gte2/ibufds_gte2.scala | 18 + .../scala/util/DeglitchShiftRegister.scala | 28 + .../src/main/scala/util/RegMapFIFO.scala | 48 + .../src/main/scala/util/SRLatch.scala | 12 + .../src/main/scala/util/SlaveRegIF.scala | 19 + sifive-blocks/src/main/scala/util/Timer.scala | 251 ++++ sifive-blocks/vsrc/SRLatch.v | 22 + .../everywhere/e300artydevkit/Config.scala | 65 + .../everywhere/e300artydevkit/FPGAChip.scala | 193 +++ .../everywhere/e300artydevkit/Platform.scala | 177 +++ .../everywhere/e300artydevkit/System.scala | 50 + 197 files changed, 19626 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 LICENSE create mode 100644 Makefile.e300artydevkit create mode 100644 bootrom/xip/Makefile create mode 100644 bootrom/xip/xip.S create mode 100644 build.sbt create mode 100644 common.mk create mode 100644 fpga-shells/.gitignore create mode 100644 fpga-shells/microsemi/common/tcl/libero.tcl create mode 100644 fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_DDR3_fp.pdc create mode 100644 fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_DDR3_io.pdc create mode 100644 fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_PCIe_fp.pdc create mode 100644 fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_PCIe_io.pdc create mode 100644 fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_base_io.pdc create mode 100644 fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_fp.pdc create mode 100644 fpga-shells/microsemi/polarfireevalkit/constraints/chiplink_io.pdc create mode 100644 fpga-shells/microsemi/polarfireevalkit/constraints/clock_groups.sdc create mode 100644 fpga-shells/microsemi/vera/constraints/false_paths.sdc create mode 100644 fpga-shells/microsemi/vera/constraints/floor_plan.pdc create mode 100644 fpga-shells/microsemi/vera/constraints/pin_constraints.pdc create mode 100644 fpga-shells/src/main/scala/clocks/Bundles.scala create mode 100644 fpga-shells/src/main/scala/clocks/ClockGroup.scala create mode 100644 fpga-shells/src/main/scala/clocks/Nodes.scala create mode 100644 fpga-shells/src/main/scala/clocks/PLLFactory.scala create mode 100644 fpga-shells/src/main/scala/clocks/Parameters.scala create mode 100644 fpga-shells/src/main/scala/clocks/ResetWrangler.scala create mode 100644 fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr3/MicrosemiPolarFireDDR3.scala create mode 100644 fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr3/MicrosemiPolarFireDDR3Periphery.scala create mode 100644 fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr4/MicrosemiPolarFireDDR4.scala create mode 100644 fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr4/MicrosemiPolarFireDDR4Periphery.scala create mode 100644 fpga-shells/src/main/scala/devices/microsemi/polarfire_pcie/PolarFireEvalKitPCIeX4.scala create mode 100644 fpga-shells/src/main/scala/devices/microsemi/polarfire_pcie/PolarFireEvalKitPCIeX4Periphery.scala create mode 100644 fpga-shells/src/main/scala/devices/xilinx/xdma/XDMA.scala create mode 100644 fpga-shells/src/main/scala/devices/xilinx/xdma/package.scala create mode 100644 fpga-shells/src/main/scala/devices/xilinx/xilinxvc707mig/XilinxVC707MIG.scala create mode 100644 fpga-shells/src/main/scala/devices/xilinx/xilinxvc707mig/XilinxVC707MIGPeriphery.scala create mode 100644 fpga-shells/src/main/scala/devices/xilinx/xilinxvc707pciex1/XilinxVC707PCIeX1.scala create mode 100644 fpga-shells/src/main/scala/devices/xilinx/xilinxvc707pciex1/XilinxVC707PCIeX1Periphery.scala create mode 100644 fpga-shells/src/main/scala/devices/xilinx/xilinxvcu118mig/XilinxVCU118MIG.scala create mode 100644 fpga-shells/src/main/scala/devices/xilinx/xilinxvcu118mig/XilinxVCU118MIGPeriphery.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/corejtagdebug/corejtagdebug.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/polarfire.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/polarfire_ccc/PolarFireCCC.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/polarfire_clock_divider/PolarFireClockDivider.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/polarfire_ddr3/PolarFireDDR3.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/polarfire_ddr4/PolarFireDDR4.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/polarfire_dll/PolarFireDLL.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/polarfire_glitchless_mux/PolarFireGlitchlessMux.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/polarfire_init_monitor/PolarFireInitMonitor.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/polarfire_oscillator/PolarFireOscillator.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/polarfire_pcie_rootport/PolarFirePCIeRootPort.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/polarfire_reset/PolarFireReset.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/polarfire_tx_pll/PolarFireTxPLL.scala create mode 100644 fpga-shells/src/main/scala/ip/microsemi/polarfire_xcvr_refclk/PolarFireTransceiverRefClk.scala create mode 100644 fpga-shells/src/main/scala/ip/xilinx/Unisim.scala create mode 100644 fpga-shells/src/main/scala/ip/xilinx/Xilinx.scala create mode 100644 fpga-shells/src/main/scala/ip/xilinx/ibufds_gte2/ibufds_gte2.scala create mode 100644 fpga-shells/src/main/scala/ip/xilinx/vc707axi_to_pcie_x1/vc707axi_to_pcie_x1.scala create mode 100644 fpga-shells/src/main/scala/ip/xilinx/vc707mig/vc707mig.scala create mode 100644 fpga-shells/src/main/scala/ip/xilinx/vcu118mig/vcu118mig.scala create mode 100644 fpga-shells/src/main/scala/ip/xilinx/xdma/xdma.scala create mode 100644 fpga-shells/src/main/scala/shell/ChipLinkOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/ClockOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/DDROverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/IOShell.scala create mode 100644 fpga-shells/src/main/scala/shell/JTAGDebugOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/LEDOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/PCIeOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/SDIOOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/Shell.scala create mode 100644 fpga-shells/src/main/scala/shell/SwitchOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/UARTOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/microsemi/PolarFireEvalKitShell.scala create mode 100644 fpga-shells/src/main/scala/shell/microsemi/VeraShell.scala create mode 100644 fpga-shells/src/main/scala/shell/package.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/ArtyShell.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/ChipLinkOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/ClockOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/JTAGDebugOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/LEDOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/SDIOOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/SwitchOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/UARTOverlay.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/UltraScaleShell.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/VC707NewShell.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/VC707Shell.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/VCU118NewShell.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/VCU118Shell.scala create mode 100644 fpga-shells/src/main/scala/shell/xilinx/XilinxShell.scala create mode 100644 fpga-shells/xilinx/Makefile create mode 100644 fpga-shells/xilinx/arty/constraints/arty-config.xdc create mode 100644 fpga-shells/xilinx/arty/constraints/arty-master.xdc create mode 100644 fpga-shells/xilinx/arty/tcl/board.tcl create mode 100644 fpga-shells/xilinx/arty/tcl/ip.tcl create mode 100644 fpga-shells/xilinx/arty_a7_100/constraints/arty-config.xdc create mode 100644 fpga-shells/xilinx/arty_a7_100/constraints/arty-master.xdc create mode 100644 fpga-shells/xilinx/arty_a7_100/tcl/board.tcl create mode 100644 fpga-shells/xilinx/arty_a7_100/tcl/ip.tcl create mode 100644 fpga-shells/xilinx/common/tcl/bitstream.tcl create mode 100644 fpga-shells/xilinx/common/tcl/boards.tcl create mode 100644 fpga-shells/xilinx/common/tcl/init.tcl create mode 100644 fpga-shells/xilinx/common/tcl/opt.tcl create mode 100644 fpga-shells/xilinx/common/tcl/place.tcl create mode 100644 fpga-shells/xilinx/common/tcl/prologue.tcl create mode 100644 fpga-shells/xilinx/common/tcl/report.tcl create mode 100644 fpga-shells/xilinx/common/tcl/route.tcl create mode 100644 fpga-shells/xilinx/common/tcl/synth.tcl create mode 100644 fpga-shells/xilinx/common/tcl/util.tcl create mode 100644 fpga-shells/xilinx/common/tcl/vivado.tcl create mode 100644 fpga-shells/xilinx/common/tcl/write_cfgmem.tcl create mode 100644 fpga-shells/xilinx/common/vsrc/PowerOnResetFPGAOnly.v create mode 100644 fpga-shells/xilinx/vc707/constraints/vc707-master.xdc create mode 100644 fpga-shells/xilinx/vc707/tcl/board.tcl create mode 100644 fpga-shells/xilinx/vc707/tcl/clocks.tcl create mode 100644 fpga-shells/xilinx/vc707/tcl/ios.tcl create mode 100644 fpga-shells/xilinx/vc707/vsrc/sdio.v create mode 100644 fpga-shells/xilinx/vc707/vsrc/vc707reset.v create mode 100644 fpga-shells/xilinx/vcu118/constraints/vcu118-master.xdc create mode 100644 fpga-shells/xilinx/vcu118/tcl/board.tcl create mode 100644 fpga-shells/xilinx/vcu118/vsrc/sdio.v create mode 100644 fpga-shells/xilinx/vcu118/vsrc/vcu118reset.v create mode 160000 rocket-chip create mode 100644 sifive-blocks/.gitignore create mode 100644 sifive-blocks/LICENSE create mode 100644 sifive-blocks/src/main/resources/BlackBoxDelayBuffer.v create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/Bundles.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/CAM.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/ChipLink.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/Parameters.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/Partial.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/RX.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/SinkA.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/SinkB.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/SinkC.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/SinkD.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/SinkE.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/SourceA.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/SourceB.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/SourceC.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/SourceD.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/SourceE.scala create mode 100644 sifive-blocks/src/main/scala/devices/chiplink/TX.scala create mode 100644 sifive-blocks/src/main/scala/devices/gpio/GPIO.scala create mode 100644 sifive-blocks/src/main/scala/devices/gpio/GPIOCtrlRegs.scala create mode 100644 sifive-blocks/src/main/scala/devices/gpio/GPIOPeriphery.scala create mode 100644 sifive-blocks/src/main/scala/devices/gpio/GPIOPins.scala create mode 100644 sifive-blocks/src/main/scala/devices/gpio/IOF.scala create mode 100644 sifive-blocks/src/main/scala/devices/i2c/I2C.scala create mode 100644 sifive-blocks/src/main/scala/devices/i2c/I2CCtrlRegs.scala create mode 100644 sifive-blocks/src/main/scala/devices/i2c/I2CPeriphery.scala create mode 100644 sifive-blocks/src/main/scala/devices/i2c/I2CPins.scala create mode 100644 sifive-blocks/src/main/scala/devices/jtag/JTAGPins.scala create mode 100644 sifive-blocks/src/main/scala/devices/mockaon/MockAON.scala create mode 100644 sifive-blocks/src/main/scala/devices/mockaon/MockAONPeriphery.scala create mode 100644 sifive-blocks/src/main/scala/devices/mockaon/MockAONWrapper.scala create mode 100644 sifive-blocks/src/main/scala/devices/mockaon/PMU.scala create mode 100644 sifive-blocks/src/main/scala/devices/mockaon/RTC.scala create mode 100644 sifive-blocks/src/main/scala/devices/mockaon/WatchdogTimer.scala create mode 100644 sifive-blocks/src/main/scala/devices/msi/MSIMaster.scala create mode 100644 sifive-blocks/src/main/scala/devices/pinctrl/PinCtrl.scala create mode 100644 sifive-blocks/src/main/scala/devices/pwm/PWM.scala create mode 100644 sifive-blocks/src/main/scala/devices/pwm/PWMPeriphery.scala create mode 100644 sifive-blocks/src/main/scala/devices/pwm/PWMPins.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/BlackBoxDelayBuffer.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/SPI.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/SPIArbiter.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/SPIBundle.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/SPIConsts.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/SPIFIFO.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/SPIFlash.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/SPIMedia.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/SPIPeriphery.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/SPIPhysical.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/SPIPins.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/SPIRegs.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/TLSPI.scala create mode 100644 sifive-blocks/src/main/scala/devices/spi/TLSPIFlash.scala create mode 100644 sifive-blocks/src/main/scala/devices/stream/PseudoStream.scala create mode 100644 sifive-blocks/src/main/scala/devices/stream/PseudoStreamRegs.scala create mode 100644 sifive-blocks/src/main/scala/devices/uart/UART.scala create mode 100644 sifive-blocks/src/main/scala/devices/uart/UARTCtrlRegs.scala create mode 100644 sifive-blocks/src/main/scala/devices/uart/UARTPeriphery.scala create mode 100644 sifive-blocks/src/main/scala/devices/uart/UARTPins.scala create mode 100644 sifive-blocks/src/main/scala/devices/uart/UARTRx.scala create mode 100644 sifive-blocks/src/main/scala/devices/uart/UARTTx.scala create mode 100644 sifive-blocks/src/main/scala/ip/xilinx/ibufds_gte2/ibufds_gte2.scala create mode 100644 sifive-blocks/src/main/scala/util/DeglitchShiftRegister.scala create mode 100644 sifive-blocks/src/main/scala/util/RegMapFIFO.scala create mode 100644 sifive-blocks/src/main/scala/util/SRLatch.scala create mode 100644 sifive-blocks/src/main/scala/util/SlaveRegIF.scala create mode 100644 sifive-blocks/src/main/scala/util/Timer.scala create mode 100644 sifive-blocks/vsrc/SRLatch.v create mode 100644 src/main/scala/everywhere/e300artydevkit/Config.scala create mode 100644 src/main/scala/everywhere/e300artydevkit/FPGAChip.scala create mode 100644 src/main/scala/everywhere/e300artydevkit/Platform.scala create mode 100644 src/main/scala/everywhere/e300artydevkit/System.scala diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..37adcae0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/builds + +# sbt directories +/target +/project/target diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..79df47d8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "rocket-chip"] + path = rocket-chip + url = https://github.com/ucb-bar/rocket-chip.git diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..56daab28 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 SiFive, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile.e300artydevkit b/Makefile.e300artydevkit new file mode 100644 index 00000000..110c08ae --- /dev/null +++ b/Makefile.e300artydevkit @@ -0,0 +1,22 @@ +# See LICENSE for license details. +base_dir := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) +BUILD_DIR := $(base_dir)/builds/e300artydevkit +FPGA_DIR := $(base_dir)/fpga-shells/xilinx +MODEL := E300ArtyDevKitFPGAChip +PROJECT := sifive.freedom.everywhere.e300artydevkit +export CONFIG_PROJECT := sifive.freedom.everywhere.e300artydevkit +export CONFIG := E300ArtyDevKitConfig +export BOARD := arty +export BOOTROM_DIR := $(base_dir)/bootrom/xip + +rocketchip_dir := $(base_dir)/rocket-chip +sifiveblocks_dir := $(base_dir)/sifive-blocks +VSRCS := \ + $(rocketchip_dir)/src/main/resources/vsrc/AsyncResetReg.v \ + $(rocketchip_dir)/src/main/resources/vsrc/plusarg_reader.v \ + $(sifiveblocks_dir)/vsrc/SRLatch.v \ + $(FPGA_DIR)/common/vsrc/PowerOnResetFPGAOnly.v \ + $(BUILD_DIR)/$(CONFIG_PROJECT).$(CONFIG).rom.v \ + $(BUILD_DIR)/$(CONFIG_PROJECT).$(CONFIG).v + +include common.mk diff --git a/bootrom/xip/Makefile b/bootrom/xip/Makefile new file mode 100644 index 00000000..57f94d49 --- /dev/null +++ b/bootrom/xip/Makefile @@ -0,0 +1,45 @@ +# RISCV environment variable must be set + +CC=$(RISCV)/bin/riscv64-unknown-elf-gcc +OBJCOPY=$(RISCV)/bin/riscv64-unknown-elf-objcopy +CFLAGS=-march=rv32imac -mabi=ilp32 -O2 -std=gnu11 -Wall -I. -nostartfiles -fno-common -g +LFLAGS=-static -nostdlib + +dtb := $(BUILD_DIR)/$(CONFIG_PROJECT).$(CONFIG).dtb +$(dtb): $(BUILD_DIR)/$(CONFIG_PROJECT).$(CONFIG).dts + dtc -I dts -O dtb -o $@ $< + +.PHONY: dtb +dtb: $(dtb) + +elf := $(BUILD_DIR)/xip.elf +$(elf): xip.S $(dtb) + $(CC) $(CFLAGS) -DXIP_TARGET_ADDR=0x20400000 -DDEVICE_TREE='"$(dtb)"' $(LFLAGS) -o $@ $< + +.PHONY: elf +elf: $(elf) + +bin := $(BUILD_DIR)/xip.bin +$(bin): $(elf) + $(OBJCOPY) -O binary $< $@ + +.PHONY: bin +bin: $(bin) + +hex := $(BUILD_DIR)/xip.hex +$(hex): $(bin) + od -t x4 -An -w4 -v $< > $@ + +.PHONY: hex +hex: $(hex) + +romgen := $(BUILD_DIR)/rom.v +$(romgen): $(hex) + $(rocketchip_dir)/scripts/vlsi_rom_gen $(ROMCONF) $< > $@ + +.PHONY: romgen +romgen: $(romgen) + +.PHONY: clean +clean:: + rm -rf $(hex) $(elf) diff --git a/bootrom/xip/xip.S b/bootrom/xip/xip.S new file mode 100644 index 00000000..7445f4c9 --- /dev/null +++ b/bootrom/xip/xip.S @@ -0,0 +1,16 @@ +// See LICENSE for license details. +// Execute in place +// Jump directly to XIP_TARGET_ADDR + + .section .text.init + .option norvc + .globl _start +_start: + csrr a0, mhartid + la a1, dtb + li t0, XIP_TARGET_ADDR + jr t0 + + .section .rodata +dtb: + .incbin DEVICE_TREE diff --git a/build.sbt b/build.sbt new file mode 100644 index 00000000..a87bc508 --- /dev/null +++ b/build.sbt @@ -0,0 +1,38 @@ +// See LICENSE for license details. +organization := "com.sifive" +name := "freedom" +version := "0.1.0" + +lazy val commonSettings = Seq( + scalaVersion := "2.12.4", // This needs to match rocket-chip's scalaVersion + scalacOptions ++= Seq( + "-deprecation", + "-feature", + "-unchecked", + "-Xsource:2.11", + "-language:reflectiveCalls" + ) +) + +// A RootProject (not well-documented) tells sbt to treat the target directory +// as its own root project, reading its build settings. If we instead used the +// normal `project in file()` declaration, sbt would ignore all of rocket-chip's +// build settings, and therefore not understand that it has its own dependencies +// on chisel, etc. +lazy val rocketChip = RootProject(file("rocket-chip")) + +lazy val sifiveBlocks = (project in file("sifive-blocks")). + dependsOn(rocketChip). + settings(commonSettings: _*) + +lazy val nvdlaBlocks = (project in file("nvidia-dla-blocks")). + dependsOn(rocketChip). + settings(commonSettings: _*) + +lazy val fpgaShells = (project in file("fpga-shells")). + dependsOn(rocketChip, sifiveBlocks). + settings(commonSettings: _*) + +lazy val freedomPlatforms = (project in file(".")). + dependsOn(rocketChip, sifiveBlocks, nvdlaBlocks, fpgaShells). + settings(commonSettings: _*) diff --git a/common.mk b/common.mk new file mode 100644 index 00000000..90dba306 --- /dev/null +++ b/common.mk @@ -0,0 +1,114 @@ +# See LICENSE for license details. + +# Required variables: +# - MODEL +# - PROJECT +# - CONFIG_PROJECT +# - CONFIG +# - BUILD_DIR +# - FPGA_DIR + +# Optional variables: +# - EXTRA_FPGA_VSRCS + +# export to bootloader +export ROMCONF=$(BUILD_DIR)/$(CONFIG_PROJECT).$(CONFIG).rom.conf + +# export to fpga-shells +export FPGA_TOP_SYSTEM=$(MODEL) +export FPGA_BUILD_DIR=$(BUILD_DIR)/$(FPGA_TOP_SYSTEM) +export fpga_common_script_dir=$(FPGA_DIR)/common/tcl +export fpga_board_script_dir=$(FPGA_DIR)/$(BOARD)/tcl + +export BUILD_DIR + +EXTRA_FPGA_VSRCS ?= +PATCHVERILOG ?= "" +BOOTROM_DIR ?= "" + +base_dir := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) +export rocketchip_dir := $(base_dir)/rocket-chip +SBT ?= java -jar $(rocketchip_dir)/sbt-launch.jar ++2.12.4 + +# Build firrtl.jar and put it where chisel3 can find it. +FIRRTL_JAR ?= $(rocketchip_dir)/firrtl/utils/bin/firrtl.jar +FIRRTL ?= java -Xmx2G -Xss8M -XX:MaxPermSize=256M -cp $(FIRRTL_JAR) firrtl.Driver + +$(FIRRTL_JAR): $(shell find $(rocketchip_dir)/firrtl/src/main/scala -iname "*.scala") + $(MAKE) -C $(rocketchip_dir)/firrtl SBT="$(SBT)" root_dir=$(rocketchip_dir)/firrtl build-scala + touch $(FIRRTL_JAR) + mkdir -p $(rocketchip_dir)/lib + cp -p $(FIRRTL_JAR) rocket-chip/lib + mkdir -p $(rocketchip_dir)/chisel3/lib + cp -p $(FIRRTL_JAR) $(rocketchip_dir)/chisel3/lib + +# Build .fir +firrtl := $(BUILD_DIR)/$(CONFIG_PROJECT).$(CONFIG).fir +$(firrtl): $(shell find $(base_dir)/src/main/scala -name '*.scala') $(FIRRTL_JAR) + mkdir -p $(dir $@) + $(SBT) "runMain freechips.rocketchip.system.Generator $(BUILD_DIR) $(PROJECT) $(MODEL) $(CONFIG_PROJECT) $(CONFIG)" + +.PHONY: firrtl +firrtl: $(firrtl) + +# Build .v +verilog := $(BUILD_DIR)/$(CONFIG_PROJECT).$(CONFIG).v +$(verilog): $(firrtl) $(FIRRTL_JAR) + $(FIRRTL) -i $(firrtl) -o $@ -X verilog +ifneq ($(PATCHVERILOG),"") + $(PATCHVERILOG) +endif + +.PHONY: verilog +verilog: $(verilog) + +romgen := $(BUILD_DIR)/$(CONFIG_PROJECT).$(CONFIG).rom.v +$(romgen): $(verilog) +ifneq ($(BOOTROM_DIR),"") + $(MAKE) -C $(BOOTROM_DIR) romgen + mv $(BUILD_DIR)/rom.v $@ +endif + +.PHONY: romgen +romgen: $(romgen) + +f := $(BUILD_DIR)/$(CONFIG_PROJECT).$(CONFIG).vsrcs.F +$(f): + echo $(VSRCS) > $@ + +bit := $(BUILD_DIR)/obj/$(MODEL).bit +$(bit): $(romgen) $(f) + cd $(BUILD_DIR); vivado \ + -nojournal -mode batch \ + -source $(fpga_common_script_dir)/vivado.tcl \ + -tclargs \ + -top-module "$(MODEL)" \ + -F "$(f)" \ + -ip-vivado-tcls "$(shell find '$(BUILD_DIR)' -name '*.vivado.tcl')" \ + -board "$(BOARD)" + + +# Build .mcs +mcs := $(BUILD_DIR)/obj/$(MODEL).mcs +$(mcs): $(bit) + cd $(BUILD_DIR); vivado -nojournal -mode batch -source $(fpga_common_script_dir)/write_cfgmem.tcl -tclargs $(BOARD) $@ $< + +.PHONY: mcs +mcs: $(mcs) + +# Build Libero project +prjx := $(BUILD_DIR)/libero/$(MODEL).prjx +$(prjx): $(verilog) + cd $(BUILD_DIR); libero SCRIPT:$(fpga_common_script_dir)/libero.tcl SCRIPT_ARGS:"$(BUILD_DIR) $(MODEL) $(PROJECT) $(CONFIG) $(BOARD)" + +.PHONY: prjx +prjx: $(prjx) + +# Clean +.PHONY: clean +clean: +ifneq ($(BOOTROM_DIR),"") + $(MAKE) -C $(BOOTROM_DIR) clean +endif + $(MAKE) -C $(FPGA_DIR) clean + rm -rf $(BUILD_DIR) diff --git a/fpga-shells/.gitignore b/fpga-shells/.gitignore new file mode 100644 index 00000000..b83d2226 --- /dev/null +++ b/fpga-shells/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/fpga-shells/microsemi/common/tcl/libero.tcl b/fpga-shells/microsemi/common/tcl/libero.tcl new file mode 100644 index 00000000..a5158892 --- /dev/null +++ b/fpga-shells/microsemi/common/tcl/libero.tcl @@ -0,0 +1,217 @@ +#============================================================================== +# Build a Libero project from Chisel generated Verilog and the Libero TCL +# scriplets generated by each IP block FPGA-Shell. +#============================================================================== + +######### Script arguments ######### + +if {$argc != 5} { + puts "!!! ERROR !!!: This script takes 5 arguments from the Chisel build environment: BUILD_DIR MODEL PROJECT CONFIG BOARD" + exit +} + +puts "*****************************************************************" +puts "******************** Building Libero project ********************" +puts "*****************************************************************" + +set chisel_build_dir [lindex $argv 0] +set chisel_model [lindex $argv 1] +set chisel_project [lindex $argv 2] +set chisel_config [lindex $argv 3] +set chisel_board [lindex $argv 4] + +puts "Number of arguments: $argc" +puts "Chisel build directory: $chisel_build_dir" +puts "Chisel model: $chisel_model" +puts "Chisel project: $chisel_project" +puts "Chisel config: $chisel_config" +puts "Chisel board: $chisel_board" + +set Prjname "$chisel_model" +set Proj "./Libero/$Prjname" + +set FPExpressDir "$chisel_build_dir/FlashProExpress" +puts "FlashPro Express folder: $FPExpressDir" +file mkdir $FPExpressDir + +########################################### +set CoreJTAGDebugver {2.0.100} +set PF_DDR3ver {2.1.101} +set PF_DDR4ver {2.1.101} +set PF_CCCver {1.0.112} +set PF_INIT_MONITORver {2.0.101} +set PF_CORERESETPFver {2.0.112} +set PF_PCIEver {1.0.230} +set PF_XCVR_REF_CLKver {1.0.103} +set PF_TX_PLLver {1.0.109} + +set use_enhanced_constraint_flow 1 +set tb {testbench} +file delete -force "$Proj" +set rootcomp {Top_SD} +set rootcomp1 Top_SD +set TOP Top_SD + +set SimTime 100us +set NUM_TX_PLL 1 +set quad 1 +set txpll_refclk_mode "ded" +set xcvrrefclk_refclk_mode "diff" + +#########ORIGINAl SETTINGS############# + +#Device Selection +set family {PolarFire} +set die {MPF300TS_ES} +set package {FCG1152} +set speed {-1} +set die_voltage {1.0} +set part_range {EXT} + +#Device Settings +set IOTech {LVCMOS 1.8V} +set ResProbe {1} +set ResSPI {0} + +#Analysis operating conditions +set TEMPR {EXT} +set VOLTR {EXT} +set IOVOLTR_12 {EXT} +set IOVOLTR_15 {EXT} +set IOVOLTR_18 {EXT} +set IOVOLTR_25 {EXT} +set IOVOLTR_33 {EXT} + +#Design Flow +set HDL {VERILOG} +set Block 0 +set SAPI 0 +set vmflow 1 +set synth 1 +set fanout {10} + +#########ORIGINAl SETTINGS############# + +new_project -ondemand_build_dh 1 -location "$Proj" -name "$Prjname" -project_description {} -block_mode $Block -standalone_peripheral_initialization $SAPI -use_enhanced_constraint_flow $use_enhanced_constraint_flow -hdl $HDL -family $family -die $die -package $package -speed $speed -die_voltage $die_voltage -part_range $part_range -adv_options IO_DEFT_STD:$IOTech -adv_options RESTRICTPROBEPINS:$ResProbe -adv_options RESTRICTSPIPINS:$ResSPI -adv_options TEMPR:$TEMPR -adv_options VCCI_1.2_VOLTR:$IOVOLTR_12 -adv_options VCCI_1.5_VOLTR:$IOVOLTR_15 -adv_options VCCI_1.8_VOLTR:$IOVOLTR_18 -adv_options VCCI_2.5_VOLTR:$IOVOLTR_25 -adv_options VCCI_3.3_VOLTR:$IOVOLTR_33 -adv_options VOLTR:$VOLTR + +# +# Import Chisel generated verilog files into Libero project +# +import_files \ + -convert_EDN_to_HDL 0 \ + -hdl_source "$chisel_build_dir/$chisel_project.$chisel_config.v" \ + -hdl_source "../../rocket-chip/src/main/resources/vsrc/AsyncResetReg.v" \ + -hdl_source "../../rocket-chip/src/main/resources/vsrc/plusarg_reader.v" + +# +# Execute all design entry scripts generated from Chisel flow. +# +set tclfiles [glob -directory $chisel_build_dir *.tcl ] + +foreach f $tclfiles { + puts "---------- Executing Libero TCL script: $f ----------" + source $f +} + +# +# Build design hierarchy and set project root to design's top level +# +build_design_hierarchy + +#set_root -module {U500PolarFireEvalKitFPGAChip::work} +set proj_root $chisel_model +append proj_root "::work" +puts "project root: $proj_root" +set_root -module $proj_root + +# +# Import IO, Placement and timing constrainst +# +puts "-----------------------------------------------------------------" +puts "------------------ Applying design constraints ------------------" +puts "-----------------------------------------------------------------" + +import_files \ + -io_pdc ../../fpga-shells/microsemi/$chisel_board/constraints/pin_constraints.pdc + +import_files \ + -fp_pdc ../../fpga-shells/microsemi/$chisel_board/constraints/floor_plan.pdc + +import_files \ + -convert_EDN_to_HDL 0 \ + -sdc ../../fpga-shells/microsemi/$chisel_board/constraints/false_paths.sdc + +organize_tool_files -tool {PLACEROUTE} \ + -file $Proj/constraint/io/pin_constraints.pdc \ + -file $Proj/constraint/fp/floor_plan.pdc \ + -file $Proj/constraint/false_paths.sdc \ + -module $proj_root -input_type {constraint} + +organize_tool_files -tool {VERIFYTIMING} \ + -file $Proj/constraint/false_paths.sdc \ + -module $proj_root -input_type {constraint} + +run_tool -name {CONSTRAINT_MANAGEMENT} +derive_constraints_sdc + + +# +# Synthesis +# +puts "-----------------------------------------------------------------" +puts "--------------------------- Synthesis ---------------------------" +puts "-----------------------------------------------------------------" +run_tool -name {SYNTHESIZE} + +# +# Place and route +# +puts "-----------------------------------------------------------------" +puts "------------------------ Place and Route ------------------------" +puts "-----------------------------------------------------------------" +configure_tool -name {PLACEROUTE} -params {EFFORT_LEVEL:true} -params {REPAIR_MIN_DELAY:true} -params {TDPR:true} +run_tool -name {PLACEROUTE} + +# +# Generate programming files +# +puts "-----------------------------------------------------------------" +puts "------------------ Generate programming files -------------------" +puts "-----------------------------------------------------------------" +run_tool -name {GENERATEPROGRAMMINGDATA} + +run_tool -name {GENERATEPROGRAMMINGFILE} + +export_prog_job \ + -job_file_name $chisel_model \ + -export_dir $FPExpressDir \ + -bitstream_file_type {TRUSTED_FACILITY} \ + -bitstream_file_components {} + + +#proc export_programming_job_g5 { name location components } { +# export_prog_job \ +# -job_file_name $name \ +# -export_dir $location \ +# -bitstream_file_type {TRUSTED_FACILITY} \ +# -bitstream_file_components $components +#} + +#Export programming job file +#export_programming_job_g5 "PF_JOB" "./srcs" {FABRIC SNVM} + +#export_bitstream_file \ +# -file_name $Proj \ +# -export_dir $Proj/designer/$Proj/export \ +# -format {STP} + + +# -master_file 0 \ +# -master_file_components {} \ +# -encrypted_uek1_file 0 \ +# -encrypted_uek1_file_components {} \ +# -encrypted_uek2_file 0 \ +# -encrypted_uek2_file_components {} \ +# -trusted_facility_file 1 \ +# -trusted_facility_file_components {FABRIC SNVM} + diff --git a/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_DDR3_fp.pdc b/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_DDR3_fp.pdc new file mode 100644 index 00000000..58c1aeff --- /dev/null +++ b/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_DDR3_fp.pdc @@ -0,0 +1,34 @@ +# Microsemi Physical design constraints file + +# Version: PolarFire v2.0 12.200.0.20 + +# Design Name: U500PolarFireEvalKitFPGAChip + +# Input Netlist Format: EDIF + +# Family: PolarFire , Die: MPF300TS_ES , Package: FCG1152 , Speed grade: -1 + +# Date generated: Mon Jan 8 10:19:51 2018 + + +# +# Local clock constraints +# + + +# +# Region constraints +# + + +# +# Core cell constraints +# + +set_location -inst_name iofpga/polarfireddr/island/blackbox/DDRPHY_BLK_0/LANE_0_CTRL/I_LANECTRL -fixed true -x 1967 -y 378 +set_location -inst_name iofpga/polarfireddr/island/blackbox/DDRPHY_BLK_0/IOD_BCLK_TRAINING/I_IOD_0 -fixed true -x 2388 -y 378 +set_location -inst_name iofpga/polarfireddr/island/blackbox/DDRPHY_BLK_0/LANE_1_CTRL/I_LANECTRL -fixed true -x 1823 -y 378 +set_location -inst_name iofpga/polarfireddr/island/blackbox/DDRPHY_BLK_0/LANE_1_IOD_READ_TRAINING/I_IOD_0 -fixed true -x 1812 -y 378 +set_location -inst_name iofpga/polarfireddr/island/blackbox/DDRPHY_BLK_0/LANE_0_IOD_READ_TRAINING/I_IOD_0 -fixed true -x 1956 -y 378 +set_location -inst_name iofpga/polarfireddr/island/blackbox/CCC_0/pll_inst_0 -fixed true -x 2460 -y 377 + diff --git a/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_DDR3_io.pdc b/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_DDR3_io.pdc new file mode 100644 index 00000000..ac3826f5 --- /dev/null +++ b/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_DDR3_io.pdc @@ -0,0 +1,319 @@ +# Microsemi I/O Physical Design Constraints file + +# User I/O Constraints file + +# Version: PolarFire v2.0 12.200.0.20 + +# Family: PolarFire , Die: MPF300TS_ES , Package: FCG1152 + +set_io -port_name {ddr_A[0]} \ + -pin_name AL27 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[1]} \ + -pin_name AL26 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[2]} \ + -pin_name AM27 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[3]} \ + -pin_name AN27 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[4]} \ + -pin_name AN26 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[5]} \ + -pin_name AP25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[6]} \ + -pin_name AL25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[7]} \ + -pin_name AK25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[8]} \ + -pin_name AJ23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[9]} \ + -pin_name AH23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[10]} \ + -pin_name AJ25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[11]} \ + -pin_name AJ24 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[12]} \ + -pin_name AL22 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[13]} \ + -pin_name AK23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[14]} \ + -pin_name AL24 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[15]} \ + -pin_name AL23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_BA[0]} \ + -pin_name AE25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_BA[1]} \ + -pin_name AD23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_BA[2]} \ + -pin_name AD25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_CAS_N \ + -pin_name AF25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_CK0 \ + -pin_name AP26 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_CK0_N \ + -pin_name AP27 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_CKE \ + -pin_name AF22 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_CS_N \ + -pin_name AE22 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_DM[0]} \ + -pin_name AN23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_DM[1]} \ + -pin_name AL20 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_DQS[0]} \ + -pin_name AP23 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQS[1]} \ + -pin_name AH22 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQS_N[0]} \ + -pin_name AP24 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQS_N[1]} \ + -pin_name AJ21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[0]} \ + -pin_name AN22 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[1]} \ + -pin_name AN21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[2]} \ + -pin_name AM24 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[3]} \ + -pin_name AN24 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[4]} \ + -pin_name AP21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[5]} \ + -pin_name AP20 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[6]} \ + -pin_name AP19 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[7]} \ + -pin_name AN19 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[8]} \ + -pin_name AM21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[9]} \ + -pin_name AK22 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[10]} \ + -pin_name AK21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[11]} \ + -pin_name AK20 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[12]} \ + -pin_name AJ20 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[13]} \ + -pin_name AH21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[14]} \ + -pin_name AG21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[15]} \ + -pin_name AM19 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name ddr_ODT \ + -pin_name AF23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_RAS_N \ + -pin_name AE23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_RESET_N \ + -pin_name AG22 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_SHIELD0 \ + -pin_name AM22 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_SHIELD1 \ + -pin_name AM20 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_WE_N \ + -pin_name AF24 \ + -fixed true \ + -DIRECTION OUTPUT + diff --git a/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_PCIe_fp.pdc b/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_PCIe_fp.pdc new file mode 100644 index 00000000..46d891f5 --- /dev/null +++ b/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_PCIe_fp.pdc @@ -0,0 +1,29 @@ +# Microsemi Physical design constraints file + +# Version: PolarFire v2.0 12.200.0.20 + +# Design Name: U500PolarFireEvalKitFPGAChip + +# Input Netlist Format: EDIF + +# Family: PolarFire , Die: MPF300TS_ES , Package: FCG1152 , Speed grade: -1 + +# Date generated: Mon Jan 8 10:19:51 2018 + + +# +# Local clock constraints +# + + +# +# Region constraints +# + + +# +# Core cell constraints +# + +set_location -inst_name pf_xcvr_ref_clk/transceiver_refclk_0/I_IO -fixed true -x 2468 -y 236 +set_location -inst_name pf_tx_pll/transmit_pll_0/txpll_isnt_0 -fixed true -x 2466 -y 239 diff --git a/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_PCIe_io.pdc b/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_PCIe_io.pdc new file mode 100644 index 00000000..f6a68f41 --- /dev/null +++ b/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_PCIe_io.pdc @@ -0,0 +1,133 @@ +# Microsemi I/O Physical Design Constraints file + +# User I/O Constraints file + +# Version: PolarFire v2.1 12.200.10.7 + +# Family: PolarFire , Die: MPF300TS_ES , Package: FCG1152 + +# Date generated: Fri Feb 9 16:31:44 2018 + +# +# User Locked I/O Bank Settings +# + +# +# Unlocked I/O Bank Settings +# The I/O Bank Settings can be locked by directly editing this file +# or by making changes in the I/O Attribute Editor +# + +# +# User Locked I/O settings +# + + + +# +# Dedicated Peripheral I/O Settings +# + + +# +# Unlocked I/O settings +# The I/Os in this section are unplaced or placed but are not locked +# the other listed attributes have been applied +# + + +# +#Ports using Dedicated Pins + +# + +set_io -port_name pcie_PCIESS_LANE_RXD0_N \ + -pin_name V30 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD0_P \ + -pin_name V29 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD1_N \ + -pin_name W32 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD1_P \ + -pin_name W31 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD2_N \ + -pin_name Y30 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD2_P \ + -pin_name Y29 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD3_N \ + -pin_name AB30 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD3_P \ + -pin_name AB29 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD0_N \ + -pin_name V34 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD0_P \ + -pin_name V33 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD1_N \ + -pin_name Y34 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD1_P \ + -pin_name Y33 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD2_N \ + -pin_name AA32 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD2_P \ + -pin_name AA31 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD3_N \ + -pin_name AB34 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD3_P \ + -pin_name AB33 \ + -DIRECTION OUTPUT + + +set_io -port_name ref_clk_pad_n \ + -pin_name W28 \ + -DIRECTION INPUT + + +set_io -port_name ref_clk_pad_p \ + -pin_name W27 \ + -DIRECTION INPUT + + diff --git a/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_base_io.pdc b/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_base_io.pdc new file mode 100644 index 00000000..9466a666 --- /dev/null +++ b/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_base_io.pdc @@ -0,0 +1,199 @@ +# Microsemi I/O Physical Design Constraints file + +# +# User Locked I/O Bank Settings +# + +# +# Unlocked I/O Bank Settings +# The I/O Bank Settings can be locked by directly editing this file +# or by making changes in the I/O Attribute Editor +# + +# +# User Locked I/O settings +# + +#set_io -port_name btn_0 \ +# -pin_name B19 \ +# -fixed true \ +# -DIRECTION OUTPUT + + +#set_io -port_name btn_1 \ +# -pin_name C21 \ +# -fixed true \ +# -DIRECTION OUTPUT + + +#set_io -port_name btn_2 \ +# -pin_name A25 \ +# -fixed true \ +# -DIRECTION OUTPUT + + +#set_io -port_name btn_3 \ +# -pin_name B27 \ +# -fixed true \ +# -DIRECTION OUTPUT + + +set_io -port_name led_0 \ + -pin_name F22 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name led_1 \ + -pin_name B26 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name led_2 \ + -pin_name C26 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name led_3 \ + -pin_name D25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name led_4 \ + -pin_name C27 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name led_5 \ + -pin_name F23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name led_6 \ + -pin_name H22 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name led_7 \ + -pin_name H21 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ref_clk0 \ + -pin_name E25 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name pf_user_reset_n \ + -pin_name K22 \ + -fixed true \ + -DIRECTION INPUT + + +#set_io -port_name uart_rx \ +# -pin_name H18 \ +# -fixed true \ +# -DIRECTION INPUT + + +set_io -port_name uart_tx \ + -pin_name G17 \ + -fixed true \ + -DIRECTION OUTPUT + + +# +# SPI flash +# + +set_io -port_name spi_flash_hold \ + -pin_name A22 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name spi_flash_reset \ + -pin_name A24 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name spi_flash_sck \ + -pin_name H19 \ + -fixed true \ + -DIRECTION OUTPUT + + +#set_io -port_name spi_flash_sdi \ +# -pin_name C18 \ +# -fixed true \ +# -DIRECTION INPUT + + +set_io -port_name spi_flash_sdo \ + -pin_name G19 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name spi_flash_ss \ + -pin_name A20 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name spi_flash_wp \ + -pin_name A27 \ + -fixed true \ + -DIRECTION OUTPUT + + +# +# Debug +# + +set_io -port_name debug_io1 \ + -pin_name C17 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name debug_io2 \ + -pin_name A17 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name debug_io3 \ + -pin_name B17 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name debug_io4 \ + -pin_name A18 \ + -fixed true \ + -DIRECTION OUTPUT + +set_io -port_name ddr_CTRLR_READY \ + -pin_name A19 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name jtag_TDO \ + -pin_name A3 \ + -fixed true \ + -DIRECTION OUTPUT + + + + diff --git a/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_fp.pdc b/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_fp.pdc new file mode 100644 index 00000000..e813990d --- /dev/null +++ b/fpga-shells/microsemi/polarfireevalkit/constraints/PF_EvalKit_fp.pdc @@ -0,0 +1,3 @@ + +set_location -inst_name hart_clk_ccc/hart_clk_ccc_0/pll_inst_0 -fixed true -x 2461 -y 377 +set_location -inst_name ddr3_clk_ccc/ddr3_clk_ccc_0/pll_inst_0 -fixed true -x 2460 -y 5 diff --git a/fpga-shells/microsemi/polarfireevalkit/constraints/chiplink_io.pdc b/fpga-shells/microsemi/polarfireevalkit/constraints/chiplink_io.pdc new file mode 100644 index 00000000..8b45d2ca --- /dev/null +++ b/fpga-shells/microsemi/polarfireevalkit/constraints/chiplink_io.pdc @@ -0,0 +1,432 @@ +# Microsemi I/O Physical Design Constraints file + +# User I/O Constraints file + +# Version: PolarFire v2.0 12.200.0.20 + +# Family: PolarFire , Die: MPF300TS_ES , Package: FCG1152 + +# +# Chiplink IOs +# + +set_io -port_name chiplink_b2c_clk \ + -pin_name D13 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[0]} \ + -pin_name H9 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[1]} \ + -pin_name H8 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[2]} \ + -pin_name G9 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[3]} \ + -pin_name F9 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[4]} \ + -pin_name L19 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[5]} \ + -pin_name L18 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[6]} \ + -pin_name H16 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[7]} \ + -pin_name H17 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[8]} \ + -pin_name J18 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[9]} \ + -pin_name J19 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[10]} \ + -pin_name F14 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[11]} \ + -pin_name F15 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[12]} \ + -pin_name G15 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[13]} \ + -pin_name G16 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[14]} \ + -pin_name K15 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[15]} \ + -pin_name J15 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[16]} \ + -pin_name J14 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[17]} \ + -pin_name J13 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[18]} \ + -pin_name L17 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[19]} \ + -pin_name M17 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[20]} \ + -pin_name J16 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[21]} \ + -pin_name K16 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[22]} \ + -pin_name K18 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[23]} \ + -pin_name K17 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[24]} \ + -pin_name F12 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[25]} \ + -pin_name E12 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[26]} \ + -pin_name H14 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[27]} \ + -pin_name G14 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[28]} \ + -pin_name F13 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[29]} \ + -pin_name E13 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[30]} \ + -pin_name A7 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[31]} \ + -pin_name A8 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name chiplink_b2c_rst \ + -pin_name D11 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name chiplink_b2c_send \ + -pin_name D10 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name chiplink_c2b_clk \ + -pin_name C11 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[0]} \ + -pin_name F8 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[1]} \ + -pin_name F7 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[2]} \ + -pin_name G5 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[3]} \ + -pin_name F5 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[4]} \ + -pin_name C6 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[5]} \ + -pin_name B6 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[6]} \ + -pin_name B9 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[7]} \ + -pin_name A9 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[8]} \ + -pin_name H13 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[9]} \ + -pin_name H12 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[10]} \ + -pin_name D8 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[11]} \ + -pin_name C8 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[12]} \ + -pin_name C7 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[13]} \ + -pin_name B7 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[14]} \ + -pin_name E10 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[15]} \ + -pin_name E11 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[16]} \ + -pin_name J11 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[17]} \ + -pin_name H11 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[18]} \ + -pin_name G12 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[19]} \ + -pin_name G11 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[20]} \ + -pin_name E6 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[21]} \ + -pin_name D6 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[22]} \ + -pin_name D9 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[23]} \ + -pin_name C9 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[24]} \ + -pin_name B10 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[25]} \ + -pin_name A10 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[26]} \ + -pin_name G10 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[27]} \ + -pin_name F10 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[28]} \ + -pin_name E7 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[29]} \ + -pin_name E8 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[30]} \ + -pin_name E1 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[31]} \ + -pin_name D1 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name chiplink_c2b_rst \ + -pin_name G7 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name chiplink_c2b_send \ + -pin_name H7 \ + -fixed true \ + -DIRECTION OUTPUT + + diff --git a/fpga-shells/microsemi/polarfireevalkit/constraints/clock_groups.sdc b/fpga-shells/microsemi/polarfireevalkit/constraints/clock_groups.sdc new file mode 100644 index 00000000..77ebb483 --- /dev/null +++ b/fpga-shells/microsemi/polarfireevalkit/constraints/clock_groups.sdc @@ -0,0 +1,5 @@ +#set_clock_groups -name {Coreplex} -logically_exclusive -group [ get_clocks { hart_clk_ccc/hart_clk_ccc_0/pll_inst_0/OUT0 } ] +set_clock_groups -name {PCIe_AXI} -logically_exclusive -group [ get_clocks { hart_clk_ccc/hart_clk_ccc_0/pll_inst_0/OUT1 } ] +set_clock_groups -name {DDR_subsystem} -logically_exclusive -group [ get_clocks { iofpga/polarfireddr/island/blackbox/CCC_0/pll_inst_0/OUT1 } ] + + diff --git a/fpga-shells/microsemi/vera/constraints/false_paths.sdc b/fpga-shells/microsemi/vera/constraints/false_paths.sdc new file mode 100644 index 00000000..d2e8b736 --- /dev/null +++ b/fpga-shells/microsemi/vera/constraints/false_paths.sdc @@ -0,0 +1,49 @@ +set_false_path -from [ get_ports { ereset_n }] + +# The c2b_clk comes from a phase-shifted output of the PLL +create_generated_clock -name {chiplink_c2b_clk} \ + -divide_by 1 -phase 0 \ + -source [ get_pins { hart_clk_ccc/hart_clk_ccc_0/pll_inst_0/OUT2 } ] \ + [ get_ports { chiplink_c2b_clk } ] + +set_clock_groups -asynchronous \ + -group [ get_clocks { chiplink_b2c_clk \ + iofpga/chiplink_rx_pll/chiplink_rx_pll_0/pll_inst_0/OUT1 } ] \ + -group [ get_clocks { ref_clk0 \ + hart_clk_ccc/hart_clk_ccc_0/pll_inst_0/OUT1 \ + hart_clk_ccc/hart_clk_ccc_0/pll_inst_0/OUT2 \ + chiplink_c2b_clk } ] \ + -group [ get_clocks { osc_rc160mhz } ] \ + -group [ get_clocks { ref_clk_pad_p } ] \ + -group [ get_clocks { iofpga/pf_ddr4/island/blackbox/CCC_0/pll_inst_0/OUT1 } ] + +# RX side: want to latch almost anywhere except on the rising edge of the clock +# The data signals coming from Aloe have: clock - 1.2 <= transition <= clock + 0.8 +# Let's add 0.6ns of safety for trace jitter+skew on both sides: +# min = hold = -1.2 - 0.6 +# max = period - setup = 0.8 + 0.6 +# We add a full period because RX clock insertion adds more than a full period of delay +# Due to what is most likely a bug in Libero, we measured we need an additional 5ns shift +set_input_delay -min 11.2 -clock {chiplink_b2c_clk} [ get_ports { chiplink_b2c_data* chiplink_b2c_rst chiplink_b2c_send } ] +set_input_delay -max 14.4 -clock {chiplink_b2c_clk} [ get_ports { chiplink_b2c_data* chiplink_b2c_rst chiplink_b2c_send } ] + +# TX side: want to transition almost anywhere except on the rising edge of the clock +# The data signals going to Aloe must have: clock - 1.85 <= NO transition <= clock + 0.65 +# Let's add 0.6ns of safey for trace jitter+skew on both sides: +# min = -hold = -0.65 - 0.6 +# max = setup = 1.85 + 0.6 +set_output_delay -min -1.25 -clock {chiplink_c2b_clk} [ get_ports { chiplink_c2b_data* chiplink_c2b_rst chiplink_c2b_send } ] +set_output_delay -max 2.45 -clock {chiplink_c2b_clk} [ get_ports { chiplink_c2b_data* chiplink_c2b_rst chiplink_c2b_send } ] +# phase = 31.5 -> 0.55ns setup slack, 0.45ns hold slack + + +# DDR4 multicycle paths +set_multicycle_path -setup_only 2 -from [ get_cells { iofpga/pf_ddr4/island/blackbox/*/*al_selec* } ] -to [ get_clocks { iofpga/pf_ddr4/island/blackbox/CCC_0/pll_inst_0/OUT1 } ] +set_multicycle_path -setup_only 2 -from [ get_cells { iofpga/pf_ddr4/island/blackbox/*/*cal_select* } ] -to [ get_clocks { iofpga/pf_ddr4/island/blackbox/CCC_0/pll_inst_0/OUT1 } ] +set_multicycle_path -setup_only 2 -from [ get_cells { iofpga/pf_ddr4/island/blackbox/*/*al_init_mr_add* } ] -to [ get_clocks { iofpga/pf_ddr4/island/blackbox/CCC_0/pll_inst_0/OUT1 } ] +set_multicycle_path -setup_only 2 -from [ get_cells { iofpga/pf_ddr4/island/blackbox/*/*cal_init_mr_addr* } ] -to [ get_clocks { iofpga/pf_ddr4/island/blackbox/CCC_0/pll_inst_0/OUT1 } ] +set_multicycle_path -setup_only 2 -from [ get_cells { iofpga/pf_ddr4/island/blackbox/*/*al_init_cs_* } ] -to [ get_clocks { iofpga/pf_ddr4/island/blackbox/CCC_0/pll_inst_0/OUT1 } ] +set_multicycle_path -setup_only 2 -from [ get_cells { iofpga/pf_ddr4/island/blackbox/*/*cal_init_cs_i* } ] -to [ get_clocks { iofpga/pf_ddr4/island/blackbox/CCC_0/pll_inst_0/OUT1 } ] + +set_multicycle_path -setup_only 2 -from [ get_pins { iofpga/pf_ddr4/island/blackbox/DDRPHY_BLK_0/IOD_TRAINING_0/COREDDR_TIP_INT_U/reset_n_int*/CLK } ] \ + -to [ get_clocks { iofpga/pf_ddr4/island/blackbox/CCC_0/pll_inst_0/OUT1 } ] diff --git a/fpga-shells/microsemi/vera/constraints/floor_plan.pdc b/fpga-shells/microsemi/vera/constraints/floor_plan.pdc new file mode 100644 index 00000000..1e3279bc --- /dev/null +++ b/fpga-shells/microsemi/vera/constraints/floor_plan.pdc @@ -0,0 +1,46 @@ +# Microsemi Physical design constraints file + +# Version: PolarFire v2.0 12.200.0.20 + +# Design Name: U500PolarFireEvalKitFPGAChip + +# Input Netlist Format: EDIF + +# Family: PolarFire , Die: MPF300TS_ES , Package: FCG1152 , Speed grade: -1 + +# Date generated: Mon Jan 8 10:19:51 2018 + + +# +# Local clock constraints +# + + +# +# Region constraints +# + + +# +# Core cell constraints +# + +set_location -inst_name pf_xcvr_ref_clk/transceiver_refclk_0/I_IO -fixed true -x 2468 -y 236 +set_location -inst_name pf_tx_pll/transmit_pll_0/txpll_isnt_0 -fixed true -x 2466 -y 239 + +set_location -inst_name pf_glitchless_mux/pf_glitchless_mux_0/I_NGMUX_1 -fixed true -x 2466 -y 163 +set_location -inst_name pf_glitchless_mux/pf_glitchless_mux_0/I_NGMUX -fixed true -x 2465 -y 163 + +set_location -inst_name hart_clk_ccc/hart_clk_ccc_0/pll_inst_0 -fixed true -x 1 -y 377 +set_location -inst_name iofpga/chiplink_rx_pll/chiplink_rx_pll_0/pll_inst_0 -fixed true -x 0 -y 377 + +set_location -inst_name iofpga/pf_ddr4/island/blackbox/CCC_0/pll_inst_0 -fixed true -x 2460 -y 377 + + +set_location -inst_name iofpga/pf_ddr4/island/blackbox/DDRPHY_BLK_0/IOD_BCLK_TRAINING/I_IOD_0 -fixed true -x 2388 -y 378 +set_location -inst_name iofpga/pf_ddr4/island/blackbox/DDRPHY_BLK_0/LANE_0_CTRL/I_LANECTRL -fixed true -x 1967 -y 378 +set_location -inst_name iofpga/pf_ddr4/island/blackbox/DDRPHY_BLK_0/LANE_0_IOD_READ_TRAINING/I_IOD_0 -fixed true -x 1956 -y 378 +set_location -inst_name iofpga/pf_ddr4/island/blackbox/DDRPHY_BLK_0/LANE_1_IOD_READ_TRAINING/I_IOD_0 -fixed true -x 1812 -y 378 +set_location -inst_name iofpga/pf_ddr4/island/blackbox/CCC_0/pll_inst_0 -fixed true -x 2460 -y 377 +set_location -inst_name iofpga/pf_ddr4/island/blackbox/DDRPHY_BLK_0/LANE_1_CTRL/I_LANECTRL -fixed true -x 1823 -y 378 + diff --git a/fpga-shells/microsemi/vera/constraints/pin_constraints.pdc b/fpga-shells/microsemi/vera/constraints/pin_constraints.pdc new file mode 100644 index 00000000..e3475797 --- /dev/null +++ b/fpga-shells/microsemi/vera/constraints/pin_constraints.pdc @@ -0,0 +1,1059 @@ +# Microsemi I/O Physical Design Constraints file + +# User I/O Constraints file + +# Version: PolarFire v2.0 12.200.0.20 + +# Family: PolarFire , Die: MPF300TS_ES , Package: FCG1152 + +# Date generated: Wed Mar 28 18:43:15 2018 + + +# +# User Locked I/O Bank Settings +# + +set_iobank -bank_name Bank0 \ + -vcci 1.80 \ + -fixed true + +set_iobank -bank_name Bank1 \ + -vcci 1.20 \ + -fixed true + +set_iobank -bank_name Bank2 \ + -vcci 3.30 \ + -fixed true + +set_iobank -bank_name Bank4 \ + -vcci 1.80 \ + -fixed true + +set_iobank -bank_name Bank5 \ + -vcci 3.30 \ + -fixed true + +set_iobank -bank_name Bank6 \ + -vcci 1.80 \ + -fixed true + +set_iobank -bank_name Bank7 \ + -vcci 1.80 \ + -fixed true + + +# +# Unlocked I/O Bank Settings +# The I/O Bank Settings can be locked by directly editing this file +# or by making changes in the I/O Attribute Editor +# + + +# +# User Locked I/O settings +# + +#set_io -port_name PCIE_0_INTERRUPT_OUT \ +# -pin_name AN17 \ +# -fixed true \ +# -DIRECTION OUTPUT + + +#set_io -port_name {PCIE_0_LTSSM[0]} \ +# -pin_name AD14 \ +# -fixed true \ +# -DIRECTION OUTPUT + + +#set_io -port_name {PCIE_0_LTSSM[1]} \ +# -pin_name AJ9 \ +# -fixed true \ +# -DIRECTION OUTPUT + + +#set_io -port_name {PCIE_0_LTSSM[2]} \ +# -pin_name AK8 \ +# -fixed true \ +# -DIRECTION OUTPUT + + +#set_io -port_name {PCIE_0_LTSSM[3]} \ +# -pin_name AL18 \ +# -fixed true \ +# -DIRECTION OUTPUT + + +#set_io -port_name {PCIE_0_LTSSM[4]} \ +# -pin_name AM17 \ +# -fixed true \ +# -DIRECTION OUTPUT + + +#set_io -port_name ref_clk0 \ +# -pin_name AG4 \ +# -fixed true \ +# -DIRECTION INPUT + +set_io -port_name ereset_n \ + -pin_name U5 \ + -fixed true \ + -DIRECTION INPUT + + + +#set_io -port_name pf_user_reset_n \ +# -pin_name AK18 \ +# -fixed true \ +# -DIRECTION INPUT + +set_io -port_name chiplink_b2c_clk \ + -pin_name U10 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[0]} \ + -pin_name V13 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[1]} \ + -pin_name W13 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[2]} \ + -pin_name T5 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[3]} \ + -pin_name T4 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[4]} \ + -pin_name V14 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[5]} \ + -pin_name W14 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[6]} \ + -pin_name R3 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[7]} \ + -pin_name R2 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[8]} \ + -pin_name W6 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[9]} \ + -pin_name Y6 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[10]} \ + -pin_name U2 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[11]} \ + -pin_name U1 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[12]} \ + -pin_name T3 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[13]} \ + -pin_name T2 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[14]} \ + -pin_name W1 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[15]} \ + -pin_name Y1 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[16]} \ + -pin_name V3 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[17]} \ + -pin_name V4 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[18]} \ + -pin_name AA4 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[19]} \ + -pin_name AA5 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[20]} \ + -pin_name V1 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[21]} \ + -pin_name V2 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[22]} \ + -pin_name Y3 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[23]} \ + -pin_name Y2 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[24]} \ + -pin_name W4 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[25]} \ + -pin_name W3 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[26]} \ + -pin_name AA3 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[27]} \ + -pin_name AA2 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[28]} \ + -pin_name Y7 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[29]} \ + -pin_name AA7 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[30]} \ + -pin_name AB2 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name {chiplink_b2c_data[31]} \ + -pin_name AB1 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name chiplink_b2c_rst \ + -pin_name AC8 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name chiplink_b2c_send \ + -pin_name U9 \ + -fixed true \ + -DIRECTION INPUT + + +set_io -port_name chiplink_c2b_clk \ + -pin_name T9 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[0]} \ + -pin_name AB9 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[1]} \ + -pin_name AA8 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[2]} \ + -pin_name AB5 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[3]} \ + -pin_name AC4 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[4]} \ + -pin_name AC1 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[5]} \ + -pin_name AD1 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[6]} \ + -pin_name AB4 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[7]} \ + -pin_name AC3 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[8]} \ + -pin_name W10 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[9]} \ + -pin_name Y10 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[10]} \ + -pin_name AB7 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[11]} \ + -pin_name AB6 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[12]} \ + -pin_name W8 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[13]} \ + -pin_name Y8 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[14]} \ + -pin_name Y12 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[15]} \ + -pin_name Y13 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[16]} \ + -pin_name AA10 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[17]} \ + -pin_name AA9 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[18]} \ + -pin_name W11 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[19]} \ + -pin_name Y11 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[20]} \ + -pin_name AC7 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[21]} \ + -pin_name AC6 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[22]} \ + -pin_name AA14 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[23]} \ + -pin_name AA13 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[24]} \ + -pin_name AB11 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[25]} \ + -pin_name AB10 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[26]} \ + -pin_name AB14 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[27]} \ + -pin_name AC13 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[28]} \ + -pin_name AC11 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[29]} \ + -pin_name AC12 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[30]} \ + -pin_name AB12 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {chiplink_c2b_data[31]} \ + -pin_name AA12 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name chiplink_c2b_rst \ + -pin_name AD5 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name chiplink_c2b_send \ + -pin_name AD3 \ + -fixed true \ + -DIRECTION OUTPUT + +set_io -port_name debug_io0 \ + -pin_name AK8 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name debug_io1 \ + -pin_name AJ9 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name debug_io2 \ + -pin_name AD14 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name debug_io3 \ + -pin_name AD11 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name debug_io4 \ + -pin_name AD10 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name debug_io5 \ + -pin_name AE11 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name led2 \ + -pin_name AK17 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name led3 \ + -pin_name AN17 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name led4 \ + -pin_name AM17 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name led5 \ + -pin_name AL17 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name pf_rstb \ + -pin_name AG15 \ + -fixed true \ + -DIRECTION OUTPUT + +set_io -port_name perst_x1_slot \ + -pin_name B4 \ + -fixed true \ + -io_std LVCMOS33 \ + -DIRECTION OUTPUT + +set_io -port_name perst_x16_slot \ + -pin_name A4 \ + -fixed true \ + -io_std LVCMOS33 \ + -DIRECTION OUTPUT + +set_io -port_name perst_m2_slot \ + -pin_name B5 \ + -fixed true \ + -io_std LVCMOS33 \ + -DIRECTION OUTPUT + +set_io -port_name perst_sata_slot \ + -pin_name A5 \ + -fixed true \ + -io_std LVCMOS33 \ + -DIRECTION OUTPUT + + +set_io -port_name ref_clk0 \ + -pin_name AG4 \ + -fixed true \ + -DIRECTION INPUT + +#set_io -port_name link_up \ +# -pin_name AK17 \ +# -fixed true \ +# -DIRECTION OUTPUT + + +#set_io -port_name pcie_switch_resetn_o \ +# -pin_name AG15 \ +# -fixed true \ +# -DIRECTION OUTPUT + + + +# +# Dedicated Peripheral I/O Settings +# + + +# +# Unlocked I/O settings +# The I/Os in this section are unplaced or placed but are not locked +# the other listed attributes have been applied +# + + +# +#Ports using Dedicated Pins + +# + +set_io -port_name pcie_PCIESS_LANE_RXD0_N \ + -pin_name V30 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD0_P \ + -pin_name V29 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD1_N \ + -pin_name W32 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD1_P \ + -pin_name W31 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD2_N \ + -pin_name Y30 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD2_P \ + -pin_name Y29 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD3_N \ + -pin_name AB30 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_RXD3_P \ + -pin_name AB29 \ + -DIRECTION INPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD0_N \ + -pin_name V34 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD0_P \ + -pin_name V33 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD1_N \ + -pin_name Y34 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD1_P \ + -pin_name Y33 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD2_N \ + -pin_name AA32 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD2_P \ + -pin_name AA31 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD3_N \ + -pin_name AB34 \ + -DIRECTION OUTPUT + + +set_io -port_name pcie_PCIESS_LANE_TXD3_P \ + -pin_name AB33 \ + -DIRECTION OUTPUT + + + +# +# DDR4 +# +set_io -port_name {ddr_A[0]} \ + -pin_name AL27 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[1]} \ + -pin_name AL26 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[2]} \ + -pin_name AM27 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[3]} \ + -pin_name AN27 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[4]} \ + -pin_name AN26 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[5]} \ + -pin_name AP25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[6]} \ + -pin_name AL25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[7]} \ + -pin_name AK25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[8]} \ + -pin_name AJ23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[9]} \ + -pin_name AH23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[10]} \ + -pin_name AJ25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[11]} \ + -pin_name AJ24 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[12]} \ + -pin_name AL22 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_A[13]} \ + -pin_name AK23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_BA[0]} \ + -pin_name AE25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_BA[1]} \ + -pin_name AD23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_BG[0]} \ + -pin_name AF25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_BG[1]} \ + -pin_name AF24 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_CAS_N \ + -pin_name AL23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_CK0 \ + -pin_name AP26 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_CK0_N \ + -pin_name AP27 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_CKE \ + -pin_name AF22 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_CS_N \ + -pin_name AE22 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_DM_N[0]} \ + -pin_name AN23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_DM_N[1]} \ + -pin_name AL20 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name {ddr_DQS[0]} \ + -pin_name AP23 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQS[1]} \ + -pin_name AH22 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQS_N[0]} \ + -pin_name AP24 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQS_N[1]} \ + -pin_name AJ21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[0]} \ + -pin_name AN22 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[1]} \ + -pin_name AN21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[2]} \ + -pin_name AM24 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[3]} \ + -pin_name AN24 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[4]} \ + -pin_name AP21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[5]} \ + -pin_name AP20 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[6]} \ + -pin_name AP19 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[7]} \ + -pin_name AN19 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[8]} \ + -pin_name AM21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[9]} \ + -pin_name AK22 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[10]} \ + -pin_name AK21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[11]} \ + -pin_name AK20 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[12]} \ + -pin_name AJ20 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[13]} \ + -pin_name AH21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[14]} \ + -pin_name AG21 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name {ddr_DQ[15]} \ + -pin_name AM19 \ + -fixed true \ + -DIRECTION INOUT + + +set_io -port_name ddr_ODT \ + -pin_name AF23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_RAS_N \ + -pin_name AD25 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_SHIELD0 \ + -pin_name AM22 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_SHIELD1 \ + -pin_name AM20 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_WE_N \ + -pin_name AL24 \ + -fixed true \ + -DIRECTION OUTPUT + +set_io -port_name ddr_ACT_N \ + -pin_name AE23 \ + -fixed true \ + -DIRECTION OUTPUT + + +set_io -port_name ddr_RESET_N \ + -pin_name AG22 \ + -fixed true \ + -DIRECTION OUTPUT + + + + +set_io -port_name REF_CLK_PAD_N \ + -pin_name W28 \ + -DIRECTION INPUT + + +set_io -port_name REF_CLK_PAD_P \ + -pin_name W27 \ + -DIRECTION INPUT + + diff --git a/fpga-shells/src/main/scala/clocks/Bundles.scala b/fpga-shells/src/main/scala/clocks/Bundles.scala new file mode 100644 index 00000000..7fa93bde --- /dev/null +++ b/fpga-shells/src/main/scala/clocks/Bundles.scala @@ -0,0 +1,17 @@ +// See LICENSE.SiFive for license details. +package sifive.fpgashells.clocks + +import Chisel._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.util._ + +class ClockBundle(params: ClockBundleParameters) extends GenericParameterizedBundle(params) +{ + val clock = Clock() + val reset = Bool() +} + +class ClockGroupBundle(params: ClockGroupBundleParameters) extends GenericParameterizedBundle(params) +{ + val member = HeterogeneousBag(params.members.map(p => new ClockBundle(p))) +} diff --git a/fpga-shells/src/main/scala/clocks/ClockGroup.scala b/fpga-shells/src/main/scala/clocks/ClockGroup.scala new file mode 100644 index 00000000..c4f744a4 --- /dev/null +++ b/fpga-shells/src/main/scala/clocks/ClockGroup.scala @@ -0,0 +1,33 @@ +// See LICENSE.SiFive for license details. +package sifive.fpgashells.clocks + +import Chisel._ +import chisel3.internal.sourceinfo.SourceInfo +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ + +case class ClockGroupNode(groupName: String)(implicit valName: ValName) + extends MixedNexusNode(ClockGroupImp, ClockImp)( + dFn = { _ => ClockSourceParameters() }, + uFn = { seq => ClockGroupSinkParameters(name = groupName, members = seq) }) + +class ClockGroup(groupName: String)(implicit p: Parameters) extends LazyModule +{ + val node = ClockGroupNode(groupName) + + lazy val module = new LazyModuleImp(this) { + val (in, _) = node.in(0) + val (out, _) = node.out.unzip + + require (node.in.size == 1) + require (in.member.size == out.size) + + (in.member zip out) foreach { case (i, o) => o := i } + } +} + +object ClockGroup +{ + def apply()(implicit p: Parameters, valName: ValName) = + LazyModule(new ClockGroup(valName.name)).node +} diff --git a/fpga-shells/src/main/scala/clocks/Nodes.scala b/fpga-shells/src/main/scala/clocks/Nodes.scala new file mode 100644 index 00000000..2593bf5d --- /dev/null +++ b/fpga-shells/src/main/scala/clocks/Nodes.scala @@ -0,0 +1,70 @@ +// See LICENSE.SiFive for license details. +package sifive.fpgashells.clocks + +import Chisel._ +import chisel3.internal.sourceinfo.SourceInfo +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ + +object ClockImp extends SimpleNodeImp[ClockSourceParameters, ClockSinkParameters, ClockEdgeParameters, ClockBundle] +{ + def edge(pd: ClockSourceParameters, pu: ClockSinkParameters, p: Parameters, sourceInfo: SourceInfo) = ClockEdgeParameters(pd, pu, p, sourceInfo) + def bundle(e: ClockEdgeParameters) = new ClockBundle(e.bundle) + def render(e: ClockEdgeParameters) = RenderedEdge(colour = "#00cc00" /* green */) +} + +case class ClockSourceNode(val portParams: Seq[ClockSourceParameters])(implicit valName: ValName) extends SourceNode(ClockImp)(portParams) +case class ClockSinkNode(val portParams: Seq[ClockSinkParameters])(implicit valName: ValName) extends SinkNode(ClockImp)(portParams) +case class ClockAdapterNode( + sourceFn: ClockSourceParameters => ClockSourceParameters = { m => m }, + sinkFn: ClockSinkParameters => ClockSinkParameters = { s => s })( + implicit valName: ValName) + extends AdapterNode(ClockImp)(sourceFn, sinkFn) +case class ClockIdentityNode()(implicit valName: ValName) extends IdentityNode(ClockImp)() + +object ClockSinkNode +{ + def apply( + freqMHz: Double, + dutyCycle: Double = 50, + phaseDeg: Double = 0, + // Create SDC/TCL constraints that the clock matches these requirements: + phaseErrorDeg: Double = 5, + freqErrorPPM: Double = 10000, + jitterPS: Double = 300)(implicit valName: ValName): ClockSinkNode = + ClockSinkNode(Seq(ClockSinkParameters( + phaseDeg = phaseDeg, + phaseErrorDeg = phaseErrorDeg, + freqErrorPPM = freqErrorPPM, + jitterPS = jitterPS, + take = Some(ClockParameters( + freqMHz = freqMHz, + dutyCycle = dutyCycle))))) +} + +object ClockSourceNode +{ + def apply( + freqMHz: Double, + dutyCycle: Double = 50, + jitterPS: Double = 300)(implicit valName: ValName): ClockSourceNode = + ClockSourceNode(Seq(ClockSourceParameters( + jitterPS = Some(jitterPS), + give = Some(ClockParameters( + freqMHz = freqMHz, + dutyCycle = dutyCycle))))) +} + +object ClockGroupImp extends SimpleNodeImp[ClockGroupSourceParameters, ClockGroupSinkParameters, ClockGroupEdgeParameters, ClockGroupBundle] +{ + def edge(pd: ClockGroupSourceParameters, pu: ClockGroupSinkParameters, p: Parameters, sourceInfo: SourceInfo) = ClockGroupEdgeParameters(pd, pu, p, sourceInfo) + def bundle(e: ClockGroupEdgeParameters) = new ClockGroupBundle(e.bundle) + def render(e: ClockGroupEdgeParameters) = RenderedEdge(colour = "#00cc00" /* green */) +} + +case class ClockGroupAdapterNode( + sourceFn: ClockGroupSourceParameters => ClockGroupSourceParameters = { m => m }, + sinkFn: ClockGroupSinkParameters => ClockGroupSinkParameters = { s => s })( + implicit valName: ValName) + extends AdapterNode(ClockGroupImp)(sourceFn, sinkFn) +case class ClockGroupIdentityNode()(implicit valName: ValName) extends IdentityNode(ClockGroupImp)() diff --git a/fpga-shells/src/main/scala/clocks/PLLFactory.scala b/fpga-shells/src/main/scala/clocks/PLLFactory.scala new file mode 100644 index 00000000..92812ce8 --- /dev/null +++ b/fpga-shells/src/main/scala/clocks/PLLFactory.scala @@ -0,0 +1,91 @@ +// See LICENSE for license details. +package sifive.fpgashells.clocks + +import chisel3._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import sifive.fpgashells.shell._ +import scala.collection.immutable.ListMap + +case class PLLNode(val feedback: Boolean)(implicit valName: ValName) + extends MixedNexusNode(ClockImp, ClockGroupImp)( + dFn = { _ => ClockGroupSourceParameters() }, + uFn = { _ => ClockSinkParameters() }) + +case class PLLInClockParameters( + freqMHz: Double, + jitter: Double = 50, + feedback: Boolean = false) + +case class PLLOutClockParameters( + freqMHz: Double, + phaseDeg: Double = 0, + dutyCycle: Double = 50, // in percent + // used to create constraints: + jitterPS: Double = 300, + freqErrorPPM: Double = 10000, + phaseErrorDeg: Double = 5) + +case class PLLParameters( + name: String, + input: PLLInClockParameters, + req: Seq[PLLOutClockParameters]) + +trait PLLInstance { + def getInput: Clock + def getReset: Option[Bool] + def getLocked: Bool + def getClocks: Seq[Clock] + def getClockNames: Seq[String] +} + +case object PLLFactoryKey extends Field[PLLFactory] +class PLLFactory(scope: IOShell, maxOutputs: Int, gen: PLLParameters => PLLInstance) +{ + private var pllNodes: Seq[PLLNode] = Nil + + def apply(feedback: Boolean = false)(implicit valName: ValName, p: Parameters): PLLNode = { + val node = scope { PLLNode(feedback) } + pllNodes = node +: pllNodes + node + } + + scope { InModuleBody { + // Require all clock group names to be distinct + val sdcGroups = Map() ++ pllNodes.flatMap { case node => + require (node.in.size == 1) + val (in, edgeIn) = node.in(0) + val (out, edgeOut) = node.out.unzip + + val params = PLLParameters( + name = node.valName.name, + input = PLLInClockParameters( + freqMHz = edgeIn.clock.freqMHz, + jitter = edgeIn.source.jitterPS.getOrElse(50), + feedback = node.feedback), + req = edgeOut.flatMap(_.members).map { e => + PLLOutClockParameters( + freqMHz = e.clock.freqMHz, + phaseDeg = e.sink.phaseDeg, + dutyCycle = e.clock.dutyCycle, + jitterPS = e.sink.jitterPS, + freqErrorPPM = e.sink.freqErrorPPM, + phaseErrorDeg = e.sink.phaseErrorDeg)}) + + val pll = gen(params) + pll.getInput := in.clock + pll.getReset.foreach { _ := in.reset } + (out.flatMap(_.member) zip pll.getClocks) foreach { case (o, i) => + o.clock := i + o.reset := !pll.getLocked || in.reset + } + + val groupLabels = edgeOut.flatMap(e => Seq.fill(e.members.size) { e.sink.name }) + groupLabels zip pll.getClocks.map(x => IOPin(x)) + }.groupBy(_._1).mapValues(_.map(_._2)) + + // Ensure there are no clock groups with the same name + require (sdcGroups.size == pllNodes.map(_.edges.out.size).sum) + sdcGroups.foreach { case (_, clockPins) => scope.sdc.addGroup(pins = clockPins) } + } } +} diff --git a/fpga-shells/src/main/scala/clocks/Parameters.scala b/fpga-shells/src/main/scala/clocks/Parameters.scala new file mode 100644 index 00000000..80477d49 --- /dev/null +++ b/fpga-shells/src/main/scala/clocks/Parameters.scala @@ -0,0 +1,77 @@ +// See LICENSE.SiFive for license details. +package sifive.fpgashells.clocks + +import Chisel._ +import chisel3.internal.sourceinfo.SourceInfo +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import scala.math.max + +// All Clock parameters specify only the PLL values required at power-on +// Dynamic control of the PLL from software can take the values out-of-range + +case class ClockParameters( + freqMHz: Double, + dutyCycle: Double = 50) //in percent +{ + require (freqMHz > 0) + require (0 < dutyCycle) + require (dutyCycle < 100) +} + +case class ClockSourceParameters( + jitterPS: Option[Double] = None, // if known at chisel elaboration + give: Option[ClockParameters] = None) + +case class ClockSinkParameters( + phaseDeg: Double = 0, + // Create SDC/TCL constraints that the clock matches these requirements: + phaseErrorDeg: Double = 5, + freqErrorPPM: Double = 10000, + jitterPS: Double = 200, + take: Option[ClockParameters] = None) +{ + require (phaseErrorDeg >= 0) + require (freqErrorPPM >= 0) +} + +case class ClockBundleParameters() + +case class ClockEdgeParameters( + source: ClockSourceParameters, + sink: ClockSinkParameters, + params: Parameters, + sourceInfo: SourceInfo) +{ + // Unify the given+taken ClockParameters + require (!source.give.isEmpty || !sink.take.isEmpty) + val clock = source.give.orElse(sink.take).get + source.give.foreach { x => require (clock == x) } + sink.take.foreach { x => require (clock == x) } + + val bundle = ClockBundleParameters() +} + +// ClockGroups exist as the output of a PLL + +case class ClockGroupSourceParameters() +case class ClockGroupSinkParameters( + name: String, + members: Seq[ClockSinkParameters]) + +case class ClockGroupBundleParameters( + members: Seq[ClockBundleParameters]) + +case class ClockGroupEdgeParameters( + source: ClockGroupSourceParameters, + sink: ClockGroupSinkParameters, + params: Parameters, + sourceInfo: SourceInfo) +{ + val sourceParameters = ClockSourceParameters() + val members = sink.members.map { s => + ClockEdgeParameters(sourceParameters, s, params, sourceInfo) + } + + val bundle = ClockGroupBundleParameters(members.map(_.bundle)) +} diff --git a/fpga-shells/src/main/scala/clocks/ResetWrangler.scala b/fpga-shells/src/main/scala/clocks/ResetWrangler.scala new file mode 100644 index 00000000..1ef97d45 --- /dev/null +++ b/fpga-shells/src/main/scala/clocks/ResetWrangler.scala @@ -0,0 +1,44 @@ +// See LICENSE for license details. +package sifive.fpgashells.clocks + +import chisel3._ +import chisel3.util._ +import chisel3.experimental.{withClockAndReset} +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.util._ + +class ResetWrangler(debounceNs: Double = 100000)(implicit p: Parameters) extends LazyModule +{ + val node = ClockAdapterNode() + + lazy val module = new LazyRawModuleImp(this) { + val (in, _) = node.in.unzip + val (out, _) = node.out.unzip + + val status = IO(Output(UInt(in.size.W))) + status := Cat(in.map(_.reset).reverse) + + val causes = in.map(_.reset).foldLeft(false.B)(_ || _) + val (slowIn, slowEdge) = node.in.minBy(_._2.clock.freqMHz) + val slowPeriodNs = 1000 / slowEdge.clock.freqMHz + val slowTicks = math.ceil(debounceNs/slowPeriodNs).toInt max 7 + val slowBits = log2Ceil(slowTicks+1) + + // debounce + val increment = Wire(Bool()) + val incremented = Wire(UInt(slowBits.W)) + val debounced = withClockAndReset(slowIn.clock, causes) { + AsyncResetReg(incremented, 0, increment, Some("debounce")) + } + increment := debounced =/= slowTicks.U + incremented := debounced + 1.U + val deglitched = AsyncResetReg(increment, slowIn.clock, causes, true, Some("deglitch")) + + // catch and sync increment to each domain + (in zip out) foreach { case (i, o) => + o.clock := i.clock + o.reset := ResetCatchAndSync(o.clock, deglitched) + } + } +} diff --git a/fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr3/MicrosemiPolarFireDDR3.scala b/fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr3/MicrosemiPolarFireDDR3.scala new file mode 100644 index 00000000..0cd535ce --- /dev/null +++ b/fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr3/MicrosemiPolarFireDDR3.scala @@ -0,0 +1,165 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.microsemi.polarfireddr3 + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.amba.axi4._ +import freechips.rocketchip.config.Parameters +//import freechips.rocketchip.coreplex._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts._ +import sifive.fpgashells.ip.microsemi.polarfireddr3.{PolarFireEvalKitDDR3IOClocksReset, PolarFireEvalKitDDR3IODDR, DDR3_Subsys} + +case class PolarFireEvalKitDDR3Params( + address : Seq[AddressSet] +) + +class PolarFireEvalKitDDR3Pads(depth : BigInt) extends PolarFireEvalKitDDR3IODDR(depth) { + def this(c : PolarFireEvalKitDDR3Params) { + this(AddressRange.fromSets(c.address).head.size) + } +} + +class PolarFireEvalKitDDR3IO(depth : BigInt) extends PolarFireEvalKitDDR3IODDR(depth) with PolarFireEvalKitDDR3IOClocksReset + +class PolarFireEvalKitDDR3Island(c : PolarFireEvalKitDDR3Params)(implicit p: Parameters) extends LazyModule with CrossesToOnlyOneClockDomain { + val ranges = AddressRange.fromSets(c.address) + require (ranges.size == 1, "DDR range must be contiguous") + val offset = ranges.head.base + val depth = ranges.head.size + val crossing = AsynchronousCrossing(8) + + require((depth<=0x100000000L),"PolarFire Evaluation Kit supports upto 4GB depth configuraton") + + val device = new MemoryDevice + val node = AXI4SlaveNode(Seq(AXI4SlavePortParameters( + slaves = Seq(AXI4SlaveParameters( + address = c.address, + resources = device.reg, + regionType = RegionType.UNCACHED, + executable = true, + supportsWrite = TransferSizes(1, 256*8), + supportsRead = TransferSizes(1, 256*8))), + beatBytes = 8))) + + lazy val module = new LazyModuleImp(this) { + val io = IO(new Bundle { + val port = new PolarFireEvalKitDDR3IO(depth) + }) + + //MIG black box instantiation + val blackbox = Module(new DDR3_Subsys(depth)) + val (axi_async, _) = node.in(0) + + //pins to top level + + //inouts + attach(io.port.DQ,blackbox.io.DQ) + attach(io.port.DQS_N,blackbox.io.DQS_N) + attach(io.port.DQS,blackbox.io.DQS) + + //outputs + io.port.A := blackbox.io.A + io.port.BA := blackbox.io.BA + io.port.RAS_N := blackbox.io.RAS_N + io.port.CAS_N := blackbox.io.CAS_N + io.port.WE_N := blackbox.io.WE_N + io.port.RESET_N := blackbox.io.RESET_N + io.port.CK0 := blackbox.io.CK0 + io.port.CK0_N := blackbox.io.CK0_N + io.port.CKE := blackbox.io.CKE + io.port.CS_N := blackbox.io.CS_N + io.port.DM := blackbox.io.DM + io.port.ODT := blackbox.io.ODT + + io.port.CTRLR_READY := blackbox.io.CTRLR_READY + io.port.SHIELD0 := blackbox.io.SHIELD0 + io.port.SHIELD1 := blackbox.io.SHIELD1 + + //inputs + val awaddr = axi_async.aw.bits.addr - UInt(offset) + val araddr = axi_async.ar.bits.addr - UInt(offset) + + //slave AXI interface write address ports + blackbox.io.axi0_awid := axi_async.aw.bits.id + blackbox.io.axi0_awaddr := awaddr //truncated + blackbox.io.axi0_awlen := axi_async.aw.bits.len + blackbox.io.axi0_awsize := axi_async.aw.bits.size + blackbox.io.axi0_awburst := axi_async.aw.bits.burst + blackbox.io.axi0_awlock := axi_async.aw.bits.lock + blackbox.io.axi0_awcache := UInt("b0011") + blackbox.io.axi0_awprot := axi_async.aw.bits.prot + blackbox.io.axi0_awvalid := axi_async.aw.valid + axi_async.aw.ready := blackbox.io.axi0_awready + + //slave interface write data ports + blackbox.io.axi0_wdata := axi_async.w.bits.data + blackbox.io.axi0_wstrb := axi_async.w.bits.strb + blackbox.io.axi0_wlast := axi_async.w.bits.last + blackbox.io.axi0_wvalid := axi_async.w.valid + axi_async.w.ready := blackbox.io.axi0_wready + + //slave interface write response + blackbox.io.axi0_bready := axi_async.b.ready + axi_async.b.bits.id := blackbox.io.axi0_bid + axi_async.b.bits.resp := blackbox.io.axi0_bresp + axi_async.b.valid := blackbox.io.axi0_bvalid + + //slave AXI interface read address ports + blackbox.io.axi0_arid := axi_async.ar.bits.id + blackbox.io.axi0_araddr := araddr // truncated + blackbox.io.axi0_arlen := axi_async.ar.bits.len + blackbox.io.axi0_arsize := axi_async.ar.bits.size + blackbox.io.axi0_arburst := axi_async.ar.bits.burst + blackbox.io.axi0_arlock := axi_async.ar.bits.lock + blackbox.io.axi0_arcache := UInt("b0011") + blackbox.io.axi0_arprot := axi_async.ar.bits.prot + blackbox.io.axi0_arvalid := axi_async.ar.valid + axi_async.ar.ready := blackbox.io.axi0_arready + + //slace AXI interface read data ports + blackbox.io.axi0_rready := axi_async.r.ready + axi_async.r.bits.id := blackbox.io.axi0_rid + axi_async.r.bits.data := blackbox.io.axi0_rdata + axi_async.r.bits.resp := blackbox.io.axi0_rresp + axi_async.r.bits.last := blackbox.io.axi0_rlast + axi_async.r.valid := blackbox.io.axi0_rvalid + + //misc + blackbox.io.AXI0_AWUSERTAG := UInt("b0000") + blackbox.io.SYS_RESET_N :=io.port.SYS_RESET_N + blackbox.io.PLL_REF_CLK :=io.port.PLL_REF_CLK + + io.port.SYS_CLK := blackbox.io.SYS_CLK + io.port.PLL_LOCK := blackbox.io.PLL_LOCK + } +} + +class PolarFireEvalKitDDR3(c : PolarFireEvalKitDDR3Params)(implicit p: Parameters) extends LazyModule { + val ranges = AddressRange.fromSets(c.address) + val depth = ranges.head.size + + val buffer = LazyModule(new TLBuffer) + val toaxi4 = LazyModule(new TLToAXI4(adapterName = Some("mem"), stripBits = 1)) + val indexer = LazyModule(new AXI4IdIndexer(idBits = 4)) + val deint = LazyModule(new AXI4Deinterleaver(p(CacheBlockBytes))) + val yank = LazyModule(new AXI4UserYanker) + val island = LazyModule(new PolarFireEvalKitDDR3Island(c)) + + val node: TLInwardNode = + island.crossAXI4In(island.node) := yank.node := deint.node := indexer.node := toaxi4.node := buffer.node + + lazy val module = new LazyModuleImp(this) { + val io = IO(new Bundle { + val port = new PolarFireEvalKitDDR3IO(depth) + }) + + io.port <> island.module.io.port + + // Shove the island + island.module.clock := io.port.SYS_CLK + island.module.reset := !io.port.CTRLR_READY + } +} diff --git a/fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr3/MicrosemiPolarFireDDR3Periphery.scala b/fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr3/MicrosemiPolarFireDDR3Periphery.scala new file mode 100644 index 00000000..476218e1 --- /dev/null +++ b/fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr3/MicrosemiPolarFireDDR3Periphery.scala @@ -0,0 +1,37 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.microsemi.polarfireddr3 + +import Chisel._ +import freechips.rocketchip.config._ +//import freechips.rocketchip.coreplex.HasMemoryBus +import freechips.rocketchip.subsystem.BaseSubsystem +import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, AddressRange} + +case object MemoryMicrosemiDDR3Key extends Field[PolarFireEvalKitDDR3Params] + +//trait HasMemoryPolarFireEvalKitDDR3 extends HasMemoryBus { +trait HasMemoryPolarFireEvalKitDDR3 { this: BaseSubsystem => + val module: HasMemoryPolarFireEvalKitDDR3ModuleImp + + val polarfireddrsubsys = LazyModule(new PolarFireEvalKitDDR3(p(MemoryMicrosemiDDR3Key))) + + polarfireddrsubsys.node := mbus.toDRAMController(Some("PolarFireDDR"))() +} + +trait HasMemoryPolarFireEvalKitDDR3Bundle { + val polarfireddrsubsys: PolarFireEvalKitDDR3IO + def connectPolarFireEValKitDDR3ToPads(pads: PolarFireEvalKitDDR3Pads) { + pads <> polarfireddrsubsys + } +} + +trait HasMemoryPolarFireEvalKitDDR3ModuleImp extends LazyModuleImp + with HasMemoryPolarFireEvalKitDDR3Bundle { + val outer: HasMemoryPolarFireEvalKitDDR3 + val ranges = AddressRange.fromSets(p(MemoryMicrosemiDDR3Key).address) + require (ranges.size == 1, "DDR range must be contiguous") + val depth = ranges.head.size + val polarfireddrsubsys = IO(new PolarFireEvalKitDDR3IO(depth)) + + polarfireddrsubsys <> outer.polarfireddrsubsys.module.io.port +} diff --git a/fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr4/MicrosemiPolarFireDDR4.scala b/fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr4/MicrosemiPolarFireDDR4.scala new file mode 100644 index 00000000..77c91566 --- /dev/null +++ b/fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr4/MicrosemiPolarFireDDR4.scala @@ -0,0 +1,166 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.microsemi.polarfireddr4 + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.amba.axi4._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts._ +import sifive.fpgashells.ip.microsemi.polarfireddr4.{PolarFireEvalKitDDR4IOClocksReset, PolarFireEvalKitDDR4IODDR, DDR4_Subsys} + +case class PolarFireEvalKitDDR4Params( + address : Seq[AddressSet] +) + +class PolarFireEvalKitDDR4Pads(depth : BigInt) extends PolarFireEvalKitDDR4IODDR(depth) { + def this(c : PolarFireEvalKitDDR4Params) { + this(AddressRange.fromSets(c.address).head.size) + } +} + +class PolarFireEvalKitDDR4IO(depth : BigInt) extends PolarFireEvalKitDDR4IODDR(depth) with PolarFireEvalKitDDR4IOClocksReset + +class PolarFireEvalKitDDR4Island(c : PolarFireEvalKitDDR4Params)(implicit p: Parameters) extends LazyModule with CrossesToOnlyOneClockDomain { + val ranges = AddressRange.fromSets(c.address) + require (ranges.size == 1, "DDR range must be contiguous") + val offset = ranges.head.base + val depth = ranges.head.size + val crossing = AsynchronousCrossing(8) + require((depth<=0x100000000L),"PF Eval Kit supports upto 4GB depth configuraton") + + val device = new MemoryDevice + val node = AXI4SlaveNode(Seq(AXI4SlavePortParameters( + slaves = Seq(AXI4SlaveParameters( + address = c.address, + resources = device.reg, + regionType = RegionType.UNCACHED, + executable = true, + supportsWrite = TransferSizes(1, 128), + supportsRead = TransferSizes(1, 128))), + beatBytes = 8))) + + lazy val module = new LazyModuleImp(this) { + val io = IO(new Bundle { + val port = new PolarFireEvalKitDDR4IO(depth) + }) + + // DDR block black box instantiation + val blackbox = Module(new DDR4_Subsys(depth)) + val (axi_async, _) = node.in(0) + + //pins to top level + + //inouts + attach(io.port.DQ,blackbox.io.DQ) + attach(io.port.DQS_N,blackbox.io.DQS_N) + attach(io.port.DQS,blackbox.io.DQS) + + //outputs + io.port.A := blackbox.io.A + io.port.ACT_N := blackbox.io.ACT_N + io.port.BA := blackbox.io.BA + io.port.BG := blackbox.io.BG + io.port.RAS_N := blackbox.io.RAS_N + io.port.CAS_N := blackbox.io.CAS_N + io.port.WE_N := blackbox.io.WE_N + io.port.RESET_N := blackbox.io.RESET_N + io.port.CK0 := blackbox.io.CK0 + io.port.CK0_N := blackbox.io.CK0_N + io.port.CKE := blackbox.io.CKE + io.port.CS_N := blackbox.io.CS_N + io.port.DM_N := blackbox.io.DM_N + io.port.ODT := blackbox.io.ODT + + io.port.CTRLR_READY := blackbox.io.CTRLR_READY + io.port.SHIELD0 := blackbox.io.SHIELD0 + io.port.SHIELD1 := blackbox.io.SHIELD1 + + //inputs + val awaddr = axi_async.aw.bits.addr - UInt(offset) + val araddr = axi_async.ar.bits.addr - UInt(offset) + + //slave AXI interface write address ports + blackbox.io.axi0_awid := axi_async.aw.bits.id + blackbox.io.axi0_awaddr := awaddr //truncated + blackbox.io.axi0_awlen := axi_async.aw.bits.len + blackbox.io.axi0_awsize := axi_async.aw.bits.size + blackbox.io.axi0_awburst := axi_async.aw.bits.burst + blackbox.io.axi0_awlock := axi_async.aw.bits.lock + blackbox.io.axi0_awcache := UInt("b0011") + blackbox.io.axi0_awprot := axi_async.aw.bits.prot + blackbox.io.axi0_awvalid := axi_async.aw.valid + axi_async.aw.ready := blackbox.io.axi0_awready + + //slave interface write data ports + blackbox.io.axi0_wdata := axi_async.w.bits.data + blackbox.io.axi0_wstrb := axi_async.w.bits.strb + blackbox.io.axi0_wlast := axi_async.w.bits.last + blackbox.io.axi0_wvalid := axi_async.w.valid + axi_async.w.ready := blackbox.io.axi0_wready + + //slave interface write response + blackbox.io.axi0_bready := axi_async.b.ready + axi_async.b.bits.id := blackbox.io.axi0_bid + axi_async.b.bits.resp := blackbox.io.axi0_bresp + axi_async.b.valid := blackbox.io.axi0_bvalid + + //slave AXI interface read address ports + blackbox.io.axi0_arid := axi_async.ar.bits.id + blackbox.io.axi0_araddr := araddr + blackbox.io.axi0_arlen := axi_async.ar.bits.len + blackbox.io.axi0_arsize := axi_async.ar.bits.size + blackbox.io.axi0_arburst := axi_async.ar.bits.burst + blackbox.io.axi0_arlock := axi_async.ar.bits.lock + blackbox.io.axi0_arcache := UInt("b0011") + blackbox.io.axi0_arprot := axi_async.ar.bits.prot + blackbox.io.axi0_arvalid := axi_async.ar.valid + axi_async.ar.ready := blackbox.io.axi0_arready + + //slace AXI interface read data ports + blackbox.io.axi0_rready := axi_async.r.ready + axi_async.r.bits.id := blackbox.io.axi0_rid + axi_async.r.bits.data := blackbox.io.axi0_rdata + axi_async.r.bits.resp := blackbox.io.axi0_rresp + axi_async.r.bits.last := blackbox.io.axi0_rlast + axi_async.r.valid := blackbox.io.axi0_rvalid + + //misc + blackbox.io.AXI0_AWUSERTAG := UInt("b0000") + blackbox.io.SYS_RESET_N :=io.port.SYS_RESET_N + blackbox.io.PLL_REF_CLK :=io.port.PLL_REF_CLK + + io.port.SYS_CLK := blackbox.io.SYS_CLK + io.port.RESET_N := blackbox.io.RESET_N + io.port.PLL_LOCK := blackbox.io.PLL_LOCK + } +} + +class PolarFireEvalKitDDR4(c : PolarFireEvalKitDDR4Params)(implicit p: Parameters) extends LazyModule { + val ranges = AddressRange.fromSets(c.address) + val depth = ranges.head.size + + val buffer = LazyModule(new TLBuffer) + val toaxi4 = LazyModule(new TLToAXI4(adapterName = Some("mem"), stripBits = 1)) + val indexer = LazyModule(new AXI4IdIndexer(idBits = 4)) + val deint = LazyModule(new AXI4Deinterleaver(p(CacheBlockBytes))) + val yank = LazyModule(new AXI4UserYanker) + val island = LazyModule(new PolarFireEvalKitDDR4Island(c)) + + val node: TLInwardNode = + island.crossAXI4In(island.node) := yank.node := deint.node := indexer.node := toaxi4.node := buffer.node + + lazy val module = new LazyModuleImp(this) { + val io = IO(new Bundle { + val port = new PolarFireEvalKitDDR4IO(depth) + }) + + io.port <> island.module.io.port + + // Shove the island + island.module.clock := io.port.SYS_CLK + island.module.reset := !io.port.CTRLR_READY + } +} diff --git a/fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr4/MicrosemiPolarFireDDR4Periphery.scala b/fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr4/MicrosemiPolarFireDDR4Periphery.scala new file mode 100644 index 00000000..6a95c4ca --- /dev/null +++ b/fpga-shells/src/main/scala/devices/microsemi/polarfire_ddr4/MicrosemiPolarFireDDR4Periphery.scala @@ -0,0 +1,37 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.microsemi.polarfireddr4 + +import Chisel._ +import freechips.rocketchip.config._ +//import freechips.rocketchip.coreplex.HasMemoryBus +import freechips.rocketchip.subsystem.BaseSubsystem +import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, AddressRange} + +case object MemoryMicrosemiDDR4Key extends Field[PolarFireEvalKitDDR4Params] + +//trait HasMemoryPolarFireEvalKitDDR4 extends HasMemoryBus { +trait HasMemoryPolarFireEvalKitDDR4 { this: BaseSubsystem => + val module: HasMemoryPolarFireEvalKitDDR4ModuleImp + + val polarfireddrsubsys = LazyModule(new PolarFireEvalKitDDR4(p(MemoryMicrosemiDDR4Key))) + + polarfireddrsubsys.node := mbus.toDRAMController(Some("PolarFireDDR"))() +} + +trait HasMemoryPolarFireEvalKitDDR4Bundle { + val polarfireddrsubsys: PolarFireEvalKitDDR4IO + def connectPolarFireEValKitDDR4ToPads(pads: PolarFireEvalKitDDR4Pads) { + pads <> polarfireddrsubsys + } +} + +trait HasMemoryPolarFireEvalKitDDR4ModuleImp extends LazyModuleImp + with HasMemoryPolarFireEvalKitDDR4Bundle { + val outer: HasMemoryPolarFireEvalKitDDR4 + val ranges = AddressRange.fromSets(p(MemoryMicrosemiDDR4Key).address) + require (ranges.size == 1, "DDR range must be contiguous") + val depth = ranges.head.size + val polarfireddrsubsys = IO(new PolarFireEvalKitDDR4IO(depth)) + + polarfireddrsubsys <> outer.polarfireddrsubsys.module.io.port +} diff --git a/fpga-shells/src/main/scala/devices/microsemi/polarfire_pcie/PolarFireEvalKitPCIeX4.scala b/fpga-shells/src/main/scala/devices/microsemi/polarfire_pcie/PolarFireEvalKitPCIeX4.scala new file mode 100644 index 00000000..51b86f7a --- /dev/null +++ b/fpga-shells/src/main/scala/devices/microsemi/polarfire_pcie/PolarFireEvalKitPCIeX4.scala @@ -0,0 +1,75 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.microsemi.polarfireevalkitpciex4 + +import Chisel._ +import freechips.rocketchip.amba.axi4._ +//import freechips.rocketchip.coreplex.CacheBlockBytes +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.util._ +import freechips.rocketchip.subsystem.{CrossesToOnlyOneClockDomain, CacheBlockBytes} + +import sifive.fpgashells.ip.microsemi.polarfirepcierootport._ + +trait PolarFireEvalKitPCIeRefClk extends Bundle{ +//TODO: bring reference clock connection in here +// val REFCLK_rxp = Bool(INPUT) +// val REFCLK_rxn = Bool(INPUT) +} + +class PolarFireEvalKitPCIeX4Pads extends Bundle + with PolarFirePCIeIOSerial + with PolarFireEvalKitPCIeRefClk + +class PolarFireEvalKitPCIeX4IO extends Bundle + with PolarFireEvalKitPCIeRefClk + with PolarFirePCIeIOSerial + with PolarFirePCIeIODebug + with PolarFirePCIeIOClocksReset { + val axi_ctl_aresetn = Bool(INPUT) +} + +class PolarFireEvalKitPCIeX4(implicit p: Parameters) extends LazyModule with CrossesToOnlyOneClockDomain { + val crossing = SynchronousCrossing() + val axi_to_pcie = LazyModule(new PolarFirePCIeX4) + + val slave: TLInwardNode = + (axi_to_pcie.slave + := AXI4Buffer() + := AXI4UserYanker() + := AXI4Deinterleaver(p(CacheBlockBytes)) + := AXI4IdIndexer(idBits=4) + := TLToAXI4(adapterName = Some("pcie-slave"))) + + val control: TLInwardNode = + (axi_to_pcie.control + := TLToAPB(false) + := TLBuffer() + := TLFragmenter(4, p(CacheBlockBytes))) + + val master: TLOutwardNode = + (TLWidthWidget(8) + := AXI4ToTL() + := AXI4UserYanker(capMaxFlight=Some(8)) + := AXI4Fragmenter() + := AXI4IdIndexer(idBits=2) + := AXI4Buffer() + := axi_to_pcie.master) + + val TLScope = LazyModule(new SimpleLazyModule with LazyScope) + val intnode: IntOutwardNode = IntSyncCrossingSink() := TLScope { + IntSyncCrossingSource(alreadyRegistered = true) := axi_to_pcie.intnode + } + + lazy val module = new LazyModuleImp(this) { + val io = IO(new Bundle { + val port = new PolarFireEvalKitPCIeX4IO + }) + + io.port <> axi_to_pcie.module.io.port + TLScope.module.clock := io.port.PCIE_1_TL_CLK_125MHz + TLScope.module.reset := ResetCatchAndSync(io.port.PCIE_1_TL_CLK_125MHz, reset) + } +} diff --git a/fpga-shells/src/main/scala/devices/microsemi/polarfire_pcie/PolarFireEvalKitPCIeX4Periphery.scala b/fpga-shells/src/main/scala/devices/microsemi/polarfire_pcie/PolarFireEvalKitPCIeX4Periphery.scala new file mode 100644 index 00000000..4131d35d --- /dev/null +++ b/fpga-shells/src/main/scala/devices/microsemi/polarfire_pcie/PolarFireEvalKitPCIeX4Periphery.scala @@ -0,0 +1,35 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.microsemi.polarfireevalkitpciex4 + +import Chisel._ +//import freechips.rocketchip.coreplex.{HasInterruptBus, HasSystemBus} +import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, BufferParams} +import freechips.rocketchip.subsystem.BaseSubsystem +import freechips.rocketchip.tilelink._ + +//trait HasSystemPolarFireEvalKitPCIeX4 extends HasSystemBus with HasInterruptBus { +trait HasSystemPolarFireEvalKitPCIeX4 { this: BaseSubsystem => + val pf_eval_kit_pcie = LazyModule(new PolarFireEvalKitPCIeX4) + private val cname = "polarfirepcie" + sbus.coupleFrom(s"master_named_$cname") { _ :=* TLFIFOFixer(TLFIFOFixer.all) :=* pf_eval_kit_pcie.crossTLOut(pf_eval_kit_pcie.master) } + sbus.coupleTo(s"slave_named_$cname") { pf_eval_kit_pcie.crossTLIn(pf_eval_kit_pcie.slave) :*= TLWidthWidget(sbus.beatBytes) :*= _ } + sbus.coupleTo(s"controller_named_$cname") { pf_eval_kit_pcie.crossTLIn(pf_eval_kit_pcie.control) :*= TLWidthWidget(sbus.beatBytes) :*= _ } + ibus.fromSync := pf_eval_kit_pcie.crossIntOut(pf_eval_kit_pcie.intnode) +} + +trait HasSystemPolarFireEvalKitPCIeX4Bundle { + val pf_eval_kit_pcie: PolarFireEvalKitPCIeX4IO + def connectPolarFireEvalKitPCIeX4ToPads(pads: PolarFireEvalKitPCIeX4Pads) { + pads <> pf_eval_kit_pcie + } +} + +trait HasSystemPolarFireEvalKitPCIeX4ModuleImp extends LazyModuleImp + with HasSystemPolarFireEvalKitPCIeX4Bundle { + val outer: HasSystemPolarFireEvalKitPCIeX4 + val pf_eval_kit_pcie = IO(new PolarFireEvalKitPCIeX4IO) + + pf_eval_kit_pcie <> outer.pf_eval_kit_pcie.module.io.port + + outer.pf_eval_kit_pcie.module.clock := outer.pf_eval_kit_pcie.module.io.port.AXI_CLK +} diff --git a/fpga-shells/src/main/scala/devices/xilinx/xdma/XDMA.scala b/fpga-shells/src/main/scala/devices/xilinx/xdma/XDMA.scala new file mode 100644 index 00000000..d5c4a16d --- /dev/null +++ b/fpga-shells/src/main/scala/devices/xilinx/xdma/XDMA.scala @@ -0,0 +1,52 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.xilinx.xdma + +import chisel3._ +import freechips.rocketchip.amba.axi4._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.subsystem.{CrossesToOnlyOneClockDomain, CacheBlockBytes} +import sifive.fpgashells.ip.xilinx.xdma._ + +class XDMA(c: XDMAParams)(implicit p: Parameters, val crossing: ClockCrossingType = AsynchronousCrossing(8)) + extends LazyModule with CrossesToOnlyOneClockDomain +{ + val imp = LazyModule(new DiplomaticXDMA(c)) + + val slave: TLInwardNode = + (imp.slave + := AXI4Buffer() + := AXI4UserYanker() + := AXI4Deinterleaver(p(CacheBlockBytes)) + := AXI4IdIndexer(idBits=c.sIDBits) + := TLToAXI4(adapterName = Some("pcie-slave"))) + + val control: TLInwardNode = + (imp.control + := AXI4Buffer() + := AXI4UserYanker(capMaxFlight = Some(2)) + := TLToAXI4() + := TLFragmenter(4, p(CacheBlockBytes), holdFirstDeny = true)) + + val master: TLOutwardNode = + (TLWidthWidget(c.busBytes) + := AXI4ToTL() + := AXI4UserYanker(capMaxFlight=Some(16)) + := AXI4Fragmenter() + := AXI4IdIndexer(idBits=2) + := imp.master) + + val intnode: IntOutwardNode = imp.intnode + + lazy val module = new LazyModuleImp(this) { + val io = IO(new Bundle { + val pads = new XDMAPads(c.lanes) + val clocks = new XDMAClocks + }) + + io.pads <> imp.module.io.pads + io.clocks <> imp.module.io.clocks + } +} diff --git a/fpga-shells/src/main/scala/devices/xilinx/xdma/package.scala b/fpga-shells/src/main/scala/devices/xilinx/xdma/package.scala new file mode 100644 index 00000000..97df7e0e --- /dev/null +++ b/fpga-shells/src/main/scala/devices/xilinx/xdma/package.scala @@ -0,0 +1,10 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.xilinx + +package object xdma +{ + type XDMAPads = sifive.fpgashells.ip.xilinx.xdma.XDMAPads + type XDMAClocks = sifive.fpgashells.ip.xilinx.xdma.XDMAClocks + type XDMAParams = sifive.fpgashells.ip.xilinx.xdma.XDMAParams + val XDMAParams = sifive.fpgashells.ip.xilinx.xdma.XDMAParams +} diff --git a/fpga-shells/src/main/scala/devices/xilinx/xilinxvc707mig/XilinxVC707MIG.scala b/fpga-shells/src/main/scala/devices/xilinx/xilinxvc707mig/XilinxVC707MIG.scala new file mode 100644 index 00000000..0b287f6f --- /dev/null +++ b/fpga-shells/src/main/scala/devices/xilinx/xilinxvc707mig/XilinxVC707MIG.scala @@ -0,0 +1,170 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.xilinx.xilinxvc707mig + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.amba.axi4._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts._ +import sifive.fpgashells.ip.xilinx.vc707mig.{VC707MIGIOClocksReset, VC707MIGIODDR, vc707mig} + +case class XilinxVC707MIGParams( + address : Seq[AddressSet] +) + +class XilinxVC707MIGPads(depth : BigInt) extends VC707MIGIODDR(depth) { + def this(c : XilinxVC707MIGParams) { + this(AddressRange.fromSets(c.address).head.size) + } +} + +class XilinxVC707MIGIO(depth : BigInt) extends VC707MIGIODDR(depth) with VC707MIGIOClocksReset + +class XilinxVC707MIGIsland(c : XilinxVC707MIGParams, val crossing: ClockCrossingType = AsynchronousCrossing(8))(implicit p: Parameters) extends LazyModule with CrossesToOnlyOneClockDomain { + val ranges = AddressRange.fromSets(c.address) + require (ranges.size == 1, "DDR range must be contiguous") + val offset = ranges.head.base + val depth = ranges.head.size + require((depth<=0x100000000L),"vc707mig supports upto 4GB depth configuraton") + + val device = new MemoryDevice + val node = AXI4SlaveNode(Seq(AXI4SlavePortParameters( + slaves = Seq(AXI4SlaveParameters( + address = c.address, + resources = device.reg, + regionType = RegionType.UNCACHED, + executable = true, + supportsWrite = TransferSizes(1, 128), + supportsRead = TransferSizes(1, 128))), + beatBytes = 8))) + + lazy val module = new LazyRawModuleImp(this) { + val io = IO(new Bundle { + val port = new XilinxVC707MIGIO(depth) + }) + + childClock := io.port.ui_clk + childReset := io.port.ui_clk_sync_rst + + //MIG black box instantiation + val blackbox = Module(new vc707mig(depth)) + val (axi_async, _) = node.in(0) + + //pins to top level + + //inouts + attach(io.port.ddr3_dq,blackbox.io.ddr3_dq) + attach(io.port.ddr3_dqs_n,blackbox.io.ddr3_dqs_n) + attach(io.port.ddr3_dqs_p,blackbox.io.ddr3_dqs_p) + + //outputs + io.port.ddr3_addr := blackbox.io.ddr3_addr + io.port.ddr3_ba := blackbox.io.ddr3_ba + io.port.ddr3_ras_n := blackbox.io.ddr3_ras_n + io.port.ddr3_cas_n := blackbox.io.ddr3_cas_n + io.port.ddr3_we_n := blackbox.io.ddr3_we_n + io.port.ddr3_reset_n := blackbox.io.ddr3_reset_n + io.port.ddr3_ck_p := blackbox.io.ddr3_ck_p + io.port.ddr3_ck_n := blackbox.io.ddr3_ck_n + io.port.ddr3_cke := blackbox.io.ddr3_cke + io.port.ddr3_cs_n := blackbox.io.ddr3_cs_n + io.port.ddr3_dm := blackbox.io.ddr3_dm + io.port.ddr3_odt := blackbox.io.ddr3_odt + + //inputs + //NO_BUFFER clock + blackbox.io.sys_clk_i := io.port.sys_clk_i + + io.port.ui_clk := blackbox.io.ui_clk + io.port.ui_clk_sync_rst := blackbox.io.ui_clk_sync_rst + io.port.mmcm_locked := blackbox.io.mmcm_locked + blackbox.io.aresetn := io.port.aresetn + blackbox.io.app_sr_req := Bool(false) + blackbox.io.app_ref_req := Bool(false) + blackbox.io.app_zq_req := Bool(false) + //app_sr_active := unconnected + //app_ref_ack := unconnected + //app_zq_ack := unconnected + + val awaddr = axi_async.aw.bits.addr - UInt(offset) + val araddr = axi_async.ar.bits.addr - UInt(offset) + + //slave AXI interface write address ports + blackbox.io.s_axi_awid := axi_async.aw.bits.id + blackbox.io.s_axi_awaddr := awaddr //truncated + blackbox.io.s_axi_awlen := axi_async.aw.bits.len + blackbox.io.s_axi_awsize := axi_async.aw.bits.size + blackbox.io.s_axi_awburst := axi_async.aw.bits.burst + blackbox.io.s_axi_awlock := axi_async.aw.bits.lock + blackbox.io.s_axi_awcache := UInt("b0011") + blackbox.io.s_axi_awprot := axi_async.aw.bits.prot + blackbox.io.s_axi_awqos := axi_async.aw.bits.qos + blackbox.io.s_axi_awvalid := axi_async.aw.valid + axi_async.aw.ready := blackbox.io.s_axi_awready + + //slave interface write data ports + blackbox.io.s_axi_wdata := axi_async.w.bits.data + blackbox.io.s_axi_wstrb := axi_async.w.bits.strb + blackbox.io.s_axi_wlast := axi_async.w.bits.last + blackbox.io.s_axi_wvalid := axi_async.w.valid + axi_async.w.ready := blackbox.io.s_axi_wready + + //slave interface write response + blackbox.io.s_axi_bready := axi_async.b.ready + axi_async.b.bits.id := blackbox.io.s_axi_bid + axi_async.b.bits.resp := blackbox.io.s_axi_bresp + axi_async.b.valid := blackbox.io.s_axi_bvalid + + //slave AXI interface read address ports + blackbox.io.s_axi_arid := axi_async.ar.bits.id + blackbox.io.s_axi_araddr := araddr // truncated + blackbox.io.s_axi_arlen := axi_async.ar.bits.len + blackbox.io.s_axi_arsize := axi_async.ar.bits.size + blackbox.io.s_axi_arburst := axi_async.ar.bits.burst + blackbox.io.s_axi_arlock := axi_async.ar.bits.lock + blackbox.io.s_axi_arcache := UInt("b0011") + blackbox.io.s_axi_arprot := axi_async.ar.bits.prot + blackbox.io.s_axi_arqos := axi_async.ar.bits.qos + blackbox.io.s_axi_arvalid := axi_async.ar.valid + axi_async.ar.ready := blackbox.io.s_axi_arready + + //slace AXI interface read data ports + blackbox.io.s_axi_rready := axi_async.r.ready + axi_async.r.bits.id := blackbox.io.s_axi_rid + axi_async.r.bits.data := blackbox.io.s_axi_rdata + axi_async.r.bits.resp := blackbox.io.s_axi_rresp + axi_async.r.bits.last := blackbox.io.s_axi_rlast + axi_async.r.valid := blackbox.io.s_axi_rvalid + + //misc + io.port.init_calib_complete := blackbox.io.init_calib_complete + blackbox.io.sys_rst :=io.port.sys_rst + //mig.device_temp :- unconnceted + } +} + +class XilinxVC707MIG(c : XilinxVC707MIGParams, crossing: ClockCrossingType = AsynchronousCrossing(8))(implicit p: Parameters) extends LazyModule { + val ranges = AddressRange.fromSets(c.address) + val depth = ranges.head.size + + val buffer = LazyModule(new TLBuffer) + val toaxi4 = LazyModule(new TLToAXI4(adapterName = Some("mem"), stripBits = 1)) + val indexer = LazyModule(new AXI4IdIndexer(idBits = 4)) + val deint = LazyModule(new AXI4Deinterleaver(p(CacheBlockBytes))) + val yank = LazyModule(new AXI4UserYanker) + val island = LazyModule(new XilinxVC707MIGIsland(c, crossing)) + + val node: TLInwardNode = + island.crossAXI4In(island.node) := yank.node := deint.node := indexer.node := toaxi4.node := buffer.node + + lazy val module = new LazyModuleImp(this) { + val io = IO(new Bundle { + val port = new XilinxVC707MIGIO(depth) + }) + + io.port <> island.module.io.port + } +} diff --git a/fpga-shells/src/main/scala/devices/xilinx/xilinxvc707mig/XilinxVC707MIGPeriphery.scala b/fpga-shells/src/main/scala/devices/xilinx/xilinxvc707mig/XilinxVC707MIGPeriphery.scala new file mode 100644 index 00000000..933c9860 --- /dev/null +++ b/fpga-shells/src/main/scala/devices/xilinx/xilinxvc707mig/XilinxVC707MIGPeriphery.scala @@ -0,0 +1,35 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.xilinx.xilinxvc707mig + +import Chisel._ +import freechips.rocketchip.config._ +import freechips.rocketchip.subsystem.BaseSubsystem +import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, AddressRange} + +case object MemoryXilinxDDRKey extends Field[XilinxVC707MIGParams] + +trait HasMemoryXilinxVC707MIG { this: BaseSubsystem => + val module: HasMemoryXilinxVC707MIGModuleImp + + val xilinxvc707mig = LazyModule(new XilinxVC707MIG(p(MemoryXilinxDDRKey))) + + xilinxvc707mig.node := mbus.toDRAMController(Some("xilinxvc707mig"))() +} + +trait HasMemoryXilinxVC707MIGBundle { + val xilinxvc707mig: XilinxVC707MIGIO + def connectXilinxVC707MIGToPads(pads: XilinxVC707MIGPads) { + pads <> xilinxvc707mig + } +} + +trait HasMemoryXilinxVC707MIGModuleImp extends LazyModuleImp + with HasMemoryXilinxVC707MIGBundle { + val outer: HasMemoryXilinxVC707MIG + val ranges = AddressRange.fromSets(p(MemoryXilinxDDRKey).address) + require (ranges.size == 1, "DDR range must be contiguous") + val depth = ranges.head.size + val xilinxvc707mig = IO(new XilinxVC707MIGIO(depth)) + + xilinxvc707mig <> outer.xilinxvc707mig.module.io.port +} diff --git a/fpga-shells/src/main/scala/devices/xilinx/xilinxvc707pciex1/XilinxVC707PCIeX1.scala b/fpga-shells/src/main/scala/devices/xilinx/xilinxvc707pciex1/XilinxVC707PCIeX1.scala new file mode 100644 index 00000000..851d85e7 --- /dev/null +++ b/fpga-shells/src/main/scala/devices/xilinx/xilinxvc707pciex1/XilinxVC707PCIeX1.scala @@ -0,0 +1,76 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.xilinx.xilinxvc707pciex1 + +import Chisel._ +import freechips.rocketchip.amba.axi4._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.subsystem.{CrossesToOnlyOneClockDomain, CacheBlockBytes} +import sifive.fpgashells.ip.xilinx.vc707axi_to_pcie_x1.{VC707AXIToPCIeX1, VC707AXIToPCIeX1IOClocksReset, VC707AXIToPCIeX1IOSerial} +import sifive.fpgashells.ip.xilinx.ibufds_gte2.IBUFDS_GTE2 + +trait VC707AXIToPCIeRefClk extends Bundle{ + val REFCLK_rxp = Bool(INPUT) + val REFCLK_rxn = Bool(INPUT) +} + +class XilinxVC707PCIeX1Pads extends Bundle + with VC707AXIToPCIeX1IOSerial + with VC707AXIToPCIeRefClk + +class XilinxVC707PCIeX1IO extends Bundle + with VC707AXIToPCIeRefClk + with VC707AXIToPCIeX1IOSerial + with VC707AXIToPCIeX1IOClocksReset { + val axi_ctl_aresetn = Bool(INPUT) +} + +class XilinxVC707PCIeX1(implicit p: Parameters, val crossing: ClockCrossingType = AsynchronousCrossing(8)) + extends LazyModule with CrossesToOnlyOneClockDomain +{ + val axi_to_pcie_x1 = LazyModule(new VC707AXIToPCIeX1) + + val slave: TLInwardNode = + (axi_to_pcie_x1.slave + := AXI4Buffer() + := AXI4UserYanker() + := AXI4Deinterleaver(p(CacheBlockBytes)) + := AXI4IdIndexer(idBits=4) + := TLToAXI4(adapterName = Some("pcie-slave"))) + + val control: TLInwardNode = + (axi_to_pcie_x1.control + := AXI4Buffer() + := AXI4UserYanker(capMaxFlight = Some(2)) + := TLToAXI4() + := TLFragmenter(4, p(CacheBlockBytes), holdFirstDeny = true)) + + val master: TLOutwardNode = + (TLWidthWidget(8) + := AXI4ToTL() + := AXI4UserYanker(capMaxFlight=Some(8)) + := AXI4Fragmenter() + := axi_to_pcie_x1.master) + + val intnode: IntOutwardNode = axi_to_pcie_x1.intnode + + lazy val module = new LazyRawModuleImp(this) { + val io = IO(new Bundle { + val port = new XilinxVC707PCIeX1IO + }) + + childClock := io.port.axi_aclk_out + childReset := ~io.port.axi_aresetn + + io.port <> axi_to_pcie_x1.module.io.port + + //PCIe Reference Clock + val ibufds_gte2 = Module(new IBUFDS_GTE2) + axi_to_pcie_x1.module.io.REFCLK := ibufds_gte2.io.O + ibufds_gte2.io.CEB := UInt(0) + ibufds_gte2.io.I := io.port.REFCLK_rxp + ibufds_gte2.io.IB := io.port.REFCLK_rxn + } +} diff --git a/fpga-shells/src/main/scala/devices/xilinx/xilinxvc707pciex1/XilinxVC707PCIeX1Periphery.scala b/fpga-shells/src/main/scala/devices/xilinx/xilinxvc707pciex1/XilinxVC707PCIeX1Periphery.scala new file mode 100644 index 00000000..caf570b9 --- /dev/null +++ b/fpga-shells/src/main/scala/devices/xilinx/xilinxvc707pciex1/XilinxVC707PCIeX1Periphery.scala @@ -0,0 +1,32 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.xilinx.xilinxvc707pciex1 + +import Chisel._ +import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, BufferParams} +import freechips.rocketchip.subsystem.BaseSubsystem +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts.IntSyncCrossingSink + +trait HasSystemXilinxVC707PCIeX1 { this: BaseSubsystem => + val xilinxvc707pcie = LazyModule(new XilinxVC707PCIeX1) + private val cname = "xilinxvc707pcie" + sbus.coupleFrom(s"master_named_$cname") { _ :=* TLFIFOFixer(TLFIFOFixer.all) :=* xilinxvc707pcie.crossTLOut(xilinxvc707pcie.master) } + sbus.coupleTo(s"slave_named_$cname") { xilinxvc707pcie.crossTLIn(xilinxvc707pcie.slave) :*= TLWidthWidget(sbus.beatBytes) :*= _ } + sbus.coupleTo(s"controller_named_$cname") { xilinxvc707pcie.crossTLIn(xilinxvc707pcie.control) :*= TLWidthWidget(sbus.beatBytes) :*= _ } + ibus.fromSync := xilinxvc707pcie.crossIntOut(xilinxvc707pcie.intnode) +} + +trait HasSystemXilinxVC707PCIeX1Bundle { + val xilinxvc707pcie: XilinxVC707PCIeX1IO + def connectXilinxVC707PCIeX1ToPads(pads: XilinxVC707PCIeX1Pads) { + pads <> xilinxvc707pcie + } +} + +trait HasSystemXilinxVC707PCIeX1ModuleImp extends LazyModuleImp + with HasSystemXilinxVC707PCIeX1Bundle { + val outer: HasSystemXilinxVC707PCIeX1 + val xilinxvc707pcie = IO(new XilinxVC707PCIeX1IO) + + xilinxvc707pcie <> outer.xilinxvc707pcie.module.io.port +} diff --git a/fpga-shells/src/main/scala/devices/xilinx/xilinxvcu118mig/XilinxVCU118MIG.scala b/fpga-shells/src/main/scala/devices/xilinx/xilinxvcu118mig/XilinxVCU118MIG.scala new file mode 100644 index 00000000..91411260 --- /dev/null +++ b/fpga-shells/src/main/scala/devices/xilinx/xilinxvcu118mig/XilinxVCU118MIG.scala @@ -0,0 +1,163 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.xilinx.xilinxvcu118mig + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.amba.axi4._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts._ +import sifive.fpgashells.ip.xilinx.vcu118mig.{VCU118MIGIOClocksReset, VCU118MIGIODDR, vcu118mig} + +case class XilinxVCU118MIGParams( + address : Seq[AddressSet] +) + +class XilinxVCU118MIGPads(depth : BigInt) extends VCU118MIGIODDR(depth) { + def this(c : XilinxVCU118MIGParams) { + this(AddressRange.fromSets(c.address).head.size) + } +} + +class XilinxVCU118MIGIO(depth : BigInt) extends VCU118MIGIODDR(depth) with VCU118MIGIOClocksReset + +class XilinxVCU118MIGIsland(c : XilinxVCU118MIGParams)(implicit p: Parameters) extends LazyModule with CrossesToOnlyOneClockDomain { + val ranges = AddressRange.fromSets(c.address) + require (ranges.size == 1, "DDR range must be contiguous") + val offset = ranges.head.base + val depth = ranges.head.size + val crossing = AsynchronousCrossing(8) + require((depth<=0x80000000L),"vcu118mig supports upto 2GB depth configuraton") + + val device = new MemoryDevice + val node = AXI4SlaveNode(Seq(AXI4SlavePortParameters( + slaves = Seq(AXI4SlaveParameters( + address = c.address, + resources = device.reg, + regionType = RegionType.UNCACHED, + executable = true, + supportsWrite = TransferSizes(1, 256*8), + supportsRead = TransferSizes(1, 256*8))), + beatBytes = 8))) + + lazy val module = new LazyModuleImp(this) { + val io = IO(new Bundle { + val port = new XilinxVCU118MIGIO(depth) + }) + + //MIG black box instantiation + val blackbox = Module(new vcu118mig(depth)) + val (axi_async, _) = node.in(0) + + //pins to top level + + //inouts + attach(io.port.c0_ddr4_dq,blackbox.io.c0_ddr4_dq) + attach(io.port.c0_ddr4_dqs_c,blackbox.io.c0_ddr4_dqs_c) + attach(io.port.c0_ddr4_dqs_t,blackbox.io.c0_ddr4_dqs_t) + attach(io.port.c0_ddr4_dm_dbi_n,blackbox.io.c0_ddr4_dm_dbi_n) + + //outputs + io.port.c0_ddr4_adr := blackbox.io.c0_ddr4_adr + io.port.c0_ddr4_bg := blackbox.io.c0_ddr4_bg + io.port.c0_ddr4_ba := blackbox.io.c0_ddr4_ba + io.port.c0_ddr4_reset_n := blackbox.io.c0_ddr4_reset_n + io.port.c0_ddr4_act_n := blackbox.io.c0_ddr4_act_n + io.port.c0_ddr4_ck_c := blackbox.io.c0_ddr4_ck_c + io.port.c0_ddr4_ck_t := blackbox.io.c0_ddr4_ck_t + io.port.c0_ddr4_cke := blackbox.io.c0_ddr4_cke + io.port.c0_ddr4_cs_n := blackbox.io.c0_ddr4_cs_n + io.port.c0_ddr4_odt := blackbox.io.c0_ddr4_odt + + //inputs + //NO_BUFFER clock + blackbox.io.c0_sys_clk_i := io.port.c0_sys_clk_i + + io.port.c0_ddr4_ui_clk := blackbox.io.c0_ddr4_ui_clk + io.port.c0_ddr4_ui_clk_sync_rst := blackbox.io.c0_ddr4_ui_clk_sync_rst + blackbox.io.c0_ddr4_aresetn := io.port.c0_ddr4_aresetn + + val awaddr = axi_async.aw.bits.addr - UInt(offset) + val araddr = axi_async.ar.bits.addr - UInt(offset) + + //slave AXI interface write address ports + blackbox.io.c0_ddr4_s_axi_awid := axi_async.aw.bits.id + blackbox.io.c0_ddr4_s_axi_awaddr := awaddr //truncated + blackbox.io.c0_ddr4_s_axi_awlen := axi_async.aw.bits.len + blackbox.io.c0_ddr4_s_axi_awsize := axi_async.aw.bits.size + blackbox.io.c0_ddr4_s_axi_awburst := axi_async.aw.bits.burst + blackbox.io.c0_ddr4_s_axi_awlock := axi_async.aw.bits.lock + blackbox.io.c0_ddr4_s_axi_awcache := UInt("b0011") + blackbox.io.c0_ddr4_s_axi_awprot := axi_async.aw.bits.prot + blackbox.io.c0_ddr4_s_axi_awqos := axi_async.aw.bits.qos + blackbox.io.c0_ddr4_s_axi_awvalid := axi_async.aw.valid + axi_async.aw.ready := blackbox.io.c0_ddr4_s_axi_awready + + //slave interface write data ports + blackbox.io.c0_ddr4_s_axi_wdata := axi_async.w.bits.data + blackbox.io.c0_ddr4_s_axi_wstrb := axi_async.w.bits.strb + blackbox.io.c0_ddr4_s_axi_wlast := axi_async.w.bits.last + blackbox.io.c0_ddr4_s_axi_wvalid := axi_async.w.valid + axi_async.w.ready := blackbox.io.c0_ddr4_s_axi_wready + + //slave interface write response + blackbox.io.c0_ddr4_s_axi_bready := axi_async.b.ready + axi_async.b.bits.id := blackbox.io.c0_ddr4_s_axi_bid + axi_async.b.bits.resp := blackbox.io.c0_ddr4_s_axi_bresp + axi_async.b.valid := blackbox.io.c0_ddr4_s_axi_bvalid + + //slave AXI interface read address ports + blackbox.io.c0_ddr4_s_axi_arid := axi_async.ar.bits.id + blackbox.io.c0_ddr4_s_axi_araddr := araddr // truncated + blackbox.io.c0_ddr4_s_axi_arlen := axi_async.ar.bits.len + blackbox.io.c0_ddr4_s_axi_arsize := axi_async.ar.bits.size + blackbox.io.c0_ddr4_s_axi_arburst := axi_async.ar.bits.burst + blackbox.io.c0_ddr4_s_axi_arlock := axi_async.ar.bits.lock + blackbox.io.c0_ddr4_s_axi_arcache := UInt("b0011") + blackbox.io.c0_ddr4_s_axi_arprot := axi_async.ar.bits.prot + blackbox.io.c0_ddr4_s_axi_arqos := axi_async.ar.bits.qos + blackbox.io.c0_ddr4_s_axi_arvalid := axi_async.ar.valid + axi_async.ar.ready := blackbox.io.c0_ddr4_s_axi_arready + + //slace AXI interface read data ports + blackbox.io.c0_ddr4_s_axi_rready := axi_async.r.ready + axi_async.r.bits.id := blackbox.io.c0_ddr4_s_axi_rid + axi_async.r.bits.data := blackbox.io.c0_ddr4_s_axi_rdata + axi_async.r.bits.resp := blackbox.io.c0_ddr4_s_axi_rresp + axi_async.r.bits.last := blackbox.io.c0_ddr4_s_axi_rlast + axi_async.r.valid := blackbox.io.c0_ddr4_s_axi_rvalid + + //misc + io.port.c0_init_calib_complete := blackbox.io.c0_init_calib_complete + blackbox.io.sys_rst :=io.port.sys_rst + } +} + +class XilinxVCU118MIG(c : XilinxVCU118MIGParams)(implicit p: Parameters) extends LazyModule { + val ranges = AddressRange.fromSets(c.address) + val depth = ranges.head.size + + val buffer = LazyModule(new TLBuffer) + val toaxi4 = LazyModule(new TLToAXI4(adapterName = Some("mem"), stripBits = 1)) + val indexer = LazyModule(new AXI4IdIndexer(idBits = 4)) + val deint = LazyModule(new AXI4Deinterleaver(p(CacheBlockBytes))) + val yank = LazyModule(new AXI4UserYanker) + val island = LazyModule(new XilinxVCU118MIGIsland(c)) + + val node: TLInwardNode = + island.crossAXI4In(island.node) := yank.node := deint.node := indexer.node := toaxi4.node := buffer.node + + lazy val module = new LazyModuleImp(this) { + val io = IO(new Bundle { + val port = new XilinxVCU118MIGIO(depth) + }) + + io.port <> island.module.io.port + + // Shove the island + island.module.clock := io.port.c0_ddr4_ui_clk + island.module.reset := io.port.c0_ddr4_ui_clk_sync_rst + } +} diff --git a/fpga-shells/src/main/scala/devices/xilinx/xilinxvcu118mig/XilinxVCU118MIGPeriphery.scala b/fpga-shells/src/main/scala/devices/xilinx/xilinxvcu118mig/XilinxVCU118MIGPeriphery.scala new file mode 100644 index 00000000..bde5149e --- /dev/null +++ b/fpga-shells/src/main/scala/devices/xilinx/xilinxvcu118mig/XilinxVCU118MIGPeriphery.scala @@ -0,0 +1,35 @@ +// See LICENSE for license details. +package sifive.fpgashells.devices.xilinx.xilinxvcu118mig + +import Chisel._ +import freechips.rocketchip.config._ +import freechips.rocketchip.subsystem.BaseSubsystem +import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, AddressRange} + +case object MemoryXilinxDDRKey extends Field[XilinxVCU118MIGParams] + +trait HasMemoryXilinxVCU118MIG { this: BaseSubsystem => + val module: HasMemoryXilinxVCU118MIGModuleImp + + val xilinxvcu118mig = LazyModule(new XilinxVCU118MIG(p(MemoryXilinxDDRKey))) + + xilinxvcu118mig.node := mbus.toDRAMController(Some("xilinxvcu118mig"))() +} + +trait HasMemoryXilinxVCU118MIGBundle { + val xilinxvcu118mig: XilinxVCU118MIGIO + def connectXilinxVCU118MIGToPads(pads: XilinxVCU118MIGPads) { + pads <> xilinxvcu118mig + } +} + +trait HasMemoryXilinxVCU118MIGModuleImp extends LazyModuleImp + with HasMemoryXilinxVCU118MIGBundle { + val outer: HasMemoryXilinxVCU118MIG + val ranges = AddressRange.fromSets(p(MemoryXilinxDDRKey).address) + require (ranges.size == 1, "DDR range must be contiguous") + val depth = ranges.head.size + val xilinxvcu118mig = IO(new XilinxVCU118MIGIO(depth)) + + xilinxvcu118mig <> outer.xilinxvcu118mig.module.io.port +} diff --git a/fpga-shells/src/main/scala/ip/microsemi/corejtagdebug/corejtagdebug.scala b/fpga-shells/src/main/scala/ip/microsemi/corejtagdebug/corejtagdebug.scala new file mode 100644 index 00000000..3c7feb05 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/corejtagdebug/corejtagdebug.scala @@ -0,0 +1,71 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi.corejtagdebug + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ + +// Black Box for Microsemi DirectCore IP block Actel:DirectCore:COREJTAGDEBUG:2.0.100 + +trait CoreJtagDebugIOJTAGPads extends Bundle { + + val TCK = Clock(INPUT) + val TDI = Bool(INPUT) + val TMS = Bool(INPUT) + val TRSTB = Bool(INPUT) + val TDO = Bool(OUTPUT) +} + +trait CoreJtagDebugIOTarget extends Bundle { + + val TGT_TCK = Clock(OUTPUT) + val TGT_TDI = Bool(OUTPUT) + val TGT_TMS = Bool(OUTPUT) + val TGT_TRST = Bool(OUTPUT) + val TGT_TDO = Bool(INPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class CoreJtagDebugBlock(implicit val p:Parameters) extends BlackBox +{ + override def desiredName = "corejtagdebug_wrapper" + + val io = new CoreJtagDebugIOJTAGPads with CoreJtagDebugIOTarget { + // chain inputs + val UTDO_IN_0 = Bool(INPUT) + val UTDO_IN_1 = Bool(INPUT) + val UTDO_IN_2 = Bool(INPUT) + val UTDO_IN_3 = Bool(INPUT) + val UTDODRV_0 = Bool(INPUT) + val UTDODRV_1 = Bool(INPUT) + val UTDODRV_2 = Bool(INPUT) + val UTDODRV_3 = Bool(INPUT) + + // chain outputs + val UTDI_OUT = Bool(OUTPUT) + val URSTB_OUT = Bool(OUTPUT) + val UIREG_OUT = Bits(OUTPUT,8) + val UDRUPD_OUT = Bool(OUTPUT) + val UDRSH_OUT = Bool(OUTPUT) + val UDRCK_OUT = Bool(OUTPUT) + val UDRCAP_OUT = Bool(OUTPUT) + } + + ElaborationArtefacts.add( + "Libero.corejtagdebug.tcl", + """ +create_design -id Actel:DirectCore:COREJTAGDEBUG:2.0.100 -design_name {corejtagdebug_wrapper} -config_file {} -params {} -inhibit_configurator 0 +open_smartdesign -design {corejtagdebug_wrapper} +configure_design -component {corejtagdebug_wrapper} -library {} +configure_vlnv_instance -component {corejtagdebug_wrapper} -library {} -name {corejtagdebug_wrapper_0} -params {"IR_CODE:0x55" "ACTIVE_HIGH_TGT_RESET:1"} -validate_rules 0 +fix_vlnv_instance -component {corejtagdebug_wrapper} -library {} -name {corejtagdebug_wrapper_0} +open_smartdesign -design {corejtagdebug_wrapper} +configure_design -component {corejtagdebug_wrapper} -library {} +""" + ) + +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/microsemi/polarfire.scala b/fpga-shells/src/main/scala/ip/microsemi/polarfire.scala new file mode 100644 index 00000000..3a9946c5 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/polarfire.scala @@ -0,0 +1,32 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi + +import Chisel._ +import chisel3.core.{Input, Output, attach} +import chisel3.experimental.{Analog} +import freechips.rocketchip.util.{ElaborationArtefacts} + + +//======================================================================== +// This file contains common devices for Microsemi PolarFire FPGAs. +//======================================================================== + +//------------------------------------------------------------------------- +// Clock network macro +//------------------------------------------------------------------------- + +class CLKINT() extends BlackBox +{ + val io = new Bundle{ + val A = Clock(INPUT) + val Y = Clock(OUTPUT) + } +} + +class ICB_CLKINT() extends BlackBox +{ + val io = new Bundle{ + val A = Clock(INPUT) + val Y = Clock(OUTPUT) + } +} diff --git a/fpga-shells/src/main/scala/ip/microsemi/polarfire_ccc/PolarFireCCC.scala b/fpga-shells/src/main/scala/ip/microsemi/polarfire_ccc/PolarFireCCC.scala new file mode 100644 index 00000000..a09444b9 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/polarfire_ccc/PolarFireCCC.scala @@ -0,0 +1,86 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi.polarfireccc + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ +import sifive.fpgashells.clocks._ + +// Black Box for Microsemi PolarFire Clock Conditioning Circuit (CCC) Actel:SgCore:PF_CCC:1.0.112 +class PolarFireCCCIOPads(c : PLLParameters) extends Bundle { + val REF_CLK_0 = Clock(INPUT) + val OUT0_FABCLK_0 = if (c.req.size >= 1) Some(Clock(OUTPUT)) else None + val OUT1_FABCLK_0 = if (c.req.size >= 2) Some(Clock(OUTPUT)) else None + val OUT2_FABCLK_0 = if (c.req.size >= 3) Some(Clock(OUTPUT)) else None + val OUT3_FABCLK_0 = if (c.req.size >= 4) Some(Clock(OUTPUT)) else None + val PLL_LOCK_0 = Bool(OUTPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class PolarFireCCC(c : PLLParameters)(implicit val p:Parameters) extends BlackBox with PLLInstance { + val moduleName = c.name + override def desiredName = c.name + + val io = new PolarFireCCCIOPads(c) + + def getInput = io.REF_CLK_0 + def getReset = None + def getLocked = io.PLL_LOCK_0 + def getClocks = Seq() ++ io.OUT0_FABCLK_0 ++ io.OUT1_FABCLK_0 ++ + io.OUT2_FABCLK_0 ++ io.OUT3_FABCLK_0 + + def getClockNames = Seq.tabulate (c.req.size) { i => + s"${c.name}/hart_clk_ccc_0/pll_inst_0/OUT${i}" //we might have to prepend + //iofpga to the begning of the name + //depending on where the + //clk is being instantiated + } + + var elaborateArtefactsString = "" + var elaborateArtefactsString_temp = "" + + elaborateArtefactsString_temp += s""" "PLL_IN_FREQ_0:${c.input.freqMHz}" \\ + |""".stripMargin + for (i <- 0 until 4) { + elaborateArtefactsString_temp += ( + if (i < c.req.size) + {s""" "GL${i.toString}_0_IS_USED:true" \\ + |""".stripMargin} + else + {s""" "GL${i.toString}_0_IS_USED:false" \\ + |""".stripMargin}) + } + + for (i <- 0 until c.req.size) { + val freq = c.req(i).freqMHz.toString() + val phase = c.req(i).phaseDeg.toString() + val dutyCycle = c.req(i).dutyCycle.toString() + + elaborateArtefactsString_temp += + s""" "GL${i.toString}_0_OUT_FREQ:${freq}" \\ + | "GL${i.toString}_0_PLL_PHASE:${phase}" \\ + |""".stripMargin + } + + elaborateArtefactsString_temp += s""" "PLL_FEEDBACK_MODE_0:${if (c.input.feedback) "External" else "Post-VCO"}" \\""" + + elaborateArtefactsString += + s""" create_design -id Actel:SgCore:PF_CCC:1.0.112 -design_name {${moduleName}} -config_file {} -params {} -inhibit_configurator 0 + | open_smartdesign -design {${moduleName}} + | configure_design -component {${moduleName}} -library {} + | configure_vlnv_instance -component {${moduleName}} -library {} -name {${moduleName}_0} \\ + | -params {${elaborateArtefactsString_temp} + | } -validate_rules 0 + | fix_vlnv_instance -component {${moduleName}} -library {} -name {${moduleName}_0} + | open_smartdesign -design {${moduleName}} + | configure_design -component {${moduleName}} -library {}""".stripMargin + + + ElaborationArtefacts.add( + s"""AddIPInstance.${moduleName}.libero.tcl""", + elaborateArtefactsString) +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/microsemi/polarfire_clock_divider/PolarFireClockDivider.scala b/fpga-shells/src/main/scala/ip/microsemi/polarfire_clock_divider/PolarFireClockDivider.scala new file mode 100644 index 00000000..775f30d6 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/polarfire_clock_divider/PolarFireClockDivider.scala @@ -0,0 +1,40 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi.polarfireclockdivider + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ + +// Black Box for Actel:SgCore:PF_CLK_DIV:1.0.101 + +trait PolarFireClockDividerIOPads extends Bundle { + + val CLK_OUT = Clock(OUTPUT) + val CLK_IN = Clock(INPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class PolarFireClockDivider(implicit val p:Parameters) extends BlackBox +{ + override def desiredName = "pf_clk_divider" + + val io = new PolarFireClockDividerIOPads { + } + + ElaborationArtefacts.add( + "Libero.polarfire_clock_divider.tcl", + """ +create_design -id Actel:SgCore:PF_CLK_DIV:1.0.101 -design_name {pf_clk_divider} -config_file {} -params {} -inhibit_configurator 0 +open_smartdesign -design {pf_clk_divider} +configure_design -component {pf_clk_divider} -library {} +configure_vlnv_instance -component {pf_clk_divider} -library {} -name {pf_clk_divider_0} -params {"DIVIDER:2"} -validate_rules 0 +fix_vlnv_instance -component {pf_clk_divider} -library {} -name {pf_clk_divider_0} +open_smartdesign -design {pf_clk_divider} +configure_design -component {pf_clk_divider} -library {} +""" + ) +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/microsemi/polarfire_ddr3/PolarFireDDR3.scala b/fpga-shells/src/main/scala/ip/microsemi/polarfire_ddr3/PolarFireDDR3.scala new file mode 100644 index 00000000..e8b2a6af --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/polarfire_ddr3/PolarFireDDR3.scala @@ -0,0 +1,129 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi.polarfireddr3 + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ + +// Black Box for Microsemi PolarFire DDR3 controller version 2.1.101 + +class PolarFireEvalKitDDR3IODDR(depth : BigInt) extends GenericParameterizedBundle(depth) { + + val A = Bits(OUTPUT,16) + val BA = Bits(OUTPUT,3) + val RAS_N = Bool(OUTPUT) + val CAS_N = Bool(OUTPUT) + val WE_N = Bool(OUTPUT) + val CTRLR_READY = Bool(OUTPUT) + val SHIELD0 = Bool(OUTPUT) + val SHIELD1 = Bool(OUTPUT) + val CK0 = Bits(OUTPUT,1) + val CK0_N = Bits(OUTPUT,1) + val CKE = Bits(OUTPUT,1) + val CS_N = Bits(OUTPUT,1) + val DM = Bits(OUTPUT,2) + val ODT = Bits(OUTPUT,1) + val RESET_N = Bool(OUTPUT) + + val DQ = Analog(16.W) + val DQS = Analog(2.W) + val DQS_N = Analog(2.W) +} + +trait PolarFireEvalKitDDR3IOClocksReset extends Bundle { + + val SYS_RESET_N = Bool(INPUT) + val PLL_REF_CLK = Clock(INPUT) + + val SYS_CLK = Clock(OUTPUT) + val PLL_LOCK = Bool(OUTPUT) + +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class DDR3_Subsys(depth : BigInt)(implicit val p:Parameters) extends BlackBox +{ + override def desiredName = "pf_ddr" + + val io = new PolarFireEvalKitDDR3IODDR(depth) with PolarFireEvalKitDDR3IOClocksReset { + //axi slave interface + //slave interface write address ports + val axi0_awid = Bits(INPUT,4) + val axi0_awaddr = Bits(INPUT,32) + val axi0_awlen = Bits(INPUT,8) + val axi0_awsize = Bits(INPUT,3) + val axi0_awburst = Bits(INPUT,2) + val axi0_awlock = Bits(INPUT,2) + val axi0_awcache = Bits(INPUT,4) + val axi0_awprot = Bits(INPUT,3) + val axi0_awvalid = Bool(INPUT) + val axi0_awready = Bool(OUTPUT) + //slave interface write data ports + val axi0_wdata = Bits(INPUT,64) + val axi0_wstrb = Bits(INPUT,8) + val axi0_wlast = Bool(INPUT) + val axi0_wvalid = Bool(INPUT) + val axi0_wready = Bool(OUTPUT) + //slave interface write response ports + val axi0_bready = Bool(INPUT) + val axi0_bid = Bits(OUTPUT,4) + val axi0_bresp = Bits(OUTPUT,2) + val axi0_bvalid = Bool(OUTPUT) + //slave interface read address ports + val axi0_arid = Bits(INPUT,4) + val axi0_araddr = Bits(INPUT,32) + val axi0_arlen = Bits(INPUT,8) + val axi0_arsize = Bits(INPUT,3) + val axi0_arburst = Bits(INPUT,2) + val axi0_arlock = Bits(INPUT,2) + val axi0_arcache = Bits(INPUT,4) + val axi0_arprot = Bits(INPUT,3) + val axi0_arvalid = Bool(INPUT) + val axi0_arready = Bool(OUTPUT) + //slave interface read data ports + val axi0_rready = Bool(INPUT) + val axi0_rid = Bits(OUTPUT,4) + val axi0_rdata = Bits(OUTPUT,64) + val axi0_rresp = Bits(OUTPUT,2) + val axi0_rlast = Bool(OUTPUT) + val axi0_rvalid = Bool(OUTPUT) + //misc + val AXI0_AWUSERTAG = Bits(INPUT,4) + val AXI0_BUSERTAG = Bits(OUTPUT,4) + } + + ElaborationArtefacts.add( + "AddIPInstance.polarfire_ddr3.libero.tcl", + """ +create_design -id Actel:SystemBuilder:PF_DDR3:2.2.109 -design_name {pf_ddr} -config_file {} -params {} -inhibit_configurator 0 +open_smartdesign -design pf_ddr +sysbld_configure_page -component pf_ddr -page PF_DDR3_UI -param WIDTH:16 \ + -param CLOCK_DDR:666.666 \ + -param CLOCK_PLL_REFERENCE:111.111 \ + -param CCC_PLL_CLOCK_MULTIPLIER:6 \ + -param ROW_ADDR_WIDTH:16 \ + -param CAS_LATENCY:9 \ + -param RTT_NOM:RZQ6 \ + -param CAS_WRITE_LATENCY:7 \ + -param OUTPUT_DRIVE_STRENGTH:RZQ7 \ + -param TIMING_RAS:36 \ + -param TIMING_RCD:13.5 \ + -param TIMING_RP:13.5 \ + -param TIMING_RC:49.5 \ + -param TIMING_WR:15 \ + -param TIMING_FAW:30 \ + -param TIMING_WTR:5 \ + -param TIMING_RRD:7.5 \ + -param TIMING_RTP:7.5 \ + -param TIMING_RFC:350 \ + -param AXI_ID_WIDTH:6 +save_design -component pf_ddr -library {} -file {} +generate_design -component pf_ddr -library {} -file {} -generator {} -recursive 1 +close_design -component pf_ddr +""" + ) +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/microsemi/polarfire_ddr4/PolarFireDDR4.scala b/fpga-shells/src/main/scala/ip/microsemi/polarfire_ddr4/PolarFireDDR4.scala new file mode 100644 index 00000000..0213fb4d --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/polarfire_ddr4/PolarFireDDR4.scala @@ -0,0 +1,132 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi.polarfireddr4 + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ + +// Black Box + +class PolarFireEvalKitDDR4IODDR(depth : BigInt) extends GenericParameterizedBundle(depth) { + + val A = Bits(OUTPUT,14) + val ACT_N = Bool(OUTPUT) + val BA = Bits(OUTPUT,2) + val BG = Bits(OUTPUT,2) + val RAS_N = Bool(OUTPUT) + val CAS_N = Bool(OUTPUT) + val WE_N = Bool(OUTPUT) + val SHIELD0 = Bool(OUTPUT) + val SHIELD1 = Bool(OUTPUT) + val CK0 = Bits(OUTPUT,1) + val CK0_N = Bits(OUTPUT,1) + val CKE = Bits(OUTPUT,1) + val CS_N = Bits(OUTPUT,1) + val DM_N = Bits(OUTPUT,2) + val ODT = Bits(OUTPUT,1) + + val DQ = Analog(16.W) + val DQS = Analog(2.W) + val DQS_N = Analog(2.W) + + val RESET_N = Bool(OUTPUT) +} + +trait PolarFireEvalKitDDR4IOClocksReset extends Bundle { + + val SYS_RESET_N = Bool(INPUT) + val PLL_REF_CLK = Clock(INPUT) + + val SYS_CLK = Clock(OUTPUT) + val PLL_LOCK = Bool(OUTPUT) + val CTRLR_READY = Bool(OUTPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class DDR4_Subsys(depth : BigInt)(implicit val p:Parameters) extends BlackBox +{ + override def desiredName = "pf_ddr" + + val io = new PolarFireEvalKitDDR4IODDR(depth) with PolarFireEvalKitDDR4IOClocksReset { + //axi slave interface + //slave interface write address ports + val axi0_awid = Bits(INPUT,6) + val axi0_awaddr = Bits(INPUT,32) + val axi0_awlen = Bits(INPUT,8) + val axi0_awsize = Bits(INPUT,3) + val axi0_awburst = Bits(INPUT,2) + val axi0_awlock = Bits(INPUT,2) + val axi0_awcache = Bits(INPUT,4) + val axi0_awprot = Bits(INPUT,3) + val axi0_awvalid = Bool(INPUT) + val axi0_awready = Bool(OUTPUT) + //slave interface write data ports + val axi0_wdata = Bits(INPUT,64) + val axi0_wstrb = Bits(INPUT,8) + val axi0_wlast = Bool(INPUT) + val axi0_wvalid = Bool(INPUT) + val axi0_wready = Bool(OUTPUT) + //slave interface write response ports + val axi0_bready = Bool(INPUT) + val axi0_bid = Bits(OUTPUT,6) + val axi0_bresp = Bits(OUTPUT,2) + val axi0_bvalid = Bool(OUTPUT) + //slave interface read address ports + val axi0_arid = Bits(INPUT,6) + val axi0_araddr = Bits(INPUT,32) + val axi0_arlen = Bits(INPUT,8) + val axi0_arsize = Bits(INPUT,3) + val axi0_arburst = Bits(INPUT,2) + val axi0_arlock = Bits(INPUT,2) + val axi0_arcache = Bits(INPUT,4) + val axi0_arprot = Bits(INPUT,3) + val axi0_arvalid = Bool(INPUT) + val axi0_arready = Bool(OUTPUT) + //slave interface read data ports + val axi0_rready = Bool(INPUT) + val axi0_rid = Bits(OUTPUT,6) + val axi0_rdata = Bits(OUTPUT,64) + val axi0_rresp = Bits(OUTPUT,2) + val axi0_rlast = Bool(OUTPUT) + val axi0_rvalid = Bool(OUTPUT) + //misc + val AXI0_AWUSERTAG = Bits(INPUT,4) + val AXI0_BUSERTAG = Bits(OUTPUT,4) + } + + ElaborationArtefacts.add( + "AddIPInstance.ddr4.libero.tcl", + """ +create_design -id Actel:SystemBuilder:PF_DDR4:2.2.109 -design_name {pf_ddr} -config_file {} -params {} -inhibit_configurator 0 +open_smartdesign -design pf_ddr + +sysbld_configure_page -component pf_ddr -page PF_DDR4_UI -param WIDTH:16 \ + -param MEMCTRLR_INST_NO:0 \ + -param ENABLE_ECC:false \ + -param AXI_WIDTH:64 \ + -param FABRIC_INTERFACE:AXI4 \ + -param CLOCK_DDR:800 \ + -param CLOCK_PLL_REFERENCE:200 \ + -param ROW_ADDR_WIDTH:15 \ + -param CCC_PLL_CLOCK_MULTIPLIER:16 \ + -param RTT_NOM:RZQ6 \ + -param READ_PREAMBLE:1 \ + -param TIMING_RAS:34 \ + -param TIMING_RCD:13.92 \ + -param TIMING_RP:13.92 \ + -param TIMING_RC:47.92 \ + -param TIMING_RFC:350 \ + -param TIMING_FAW:20 \ + -param AXI_ID_WIDTH:6 + +save_design -component pf_ddr -library {} -file {} + +generate_design -component pf_ddr -library {} -file {} -generator {} -recursive 1 + +close_design -component pf_ddr""") + +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/microsemi/polarfire_dll/PolarFireDLL.scala b/fpga-shells/src/main/scala/ip/microsemi/polarfire_dll/PolarFireDLL.scala new file mode 100644 index 00000000..5f071f85 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/polarfire_dll/PolarFireDLL.scala @@ -0,0 +1,46 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi.polarfiredll + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ + +// Black Box for Microsemi PolarFire Delay Locked Loop (DLL) Actel:SgCore:PF_CCC:1.0.112 + +class PolarFireDLLIOPads extends Bundle { + + val DLL_FB_CLK = Clock(INPUT) + val DLL_REF_CLK = Clock(INPUT) + val DLL_CLK_0_FABCLK = Clock(OUTPUT) + val DLL_LOCK = Bool(OUTPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class PolarFireDLL(name: String)(implicit val p:Parameters) extends BlackBox +{ + val modulename = name + override def desiredName = name + + val io = new PolarFireDLLIOPads + + ElaborationArtefacts.add( + "AddIPInstance." ++ modulename ++".libero.tcl", + """ +create_design -id Actel:SgCore:PF_CCC:1.0.112 -design_name {""" ++ modulename ++"""} -config_file {} -params {} -inhibit_configurator 0 +open_smartdesign -design {""" ++ modulename ++"""} +configure_design -component {""" ++ modulename ++"""} -library {} +configure_vlnv_instance -component {""" ++ modulename ++"""} -library {} -name {""" ++ modulename ++"""_0} \ + -params {"DLL_ONLY_EN:true" \ + "DLL_IN:125" \ + "DLL_MODE:INJECTION_REM_MODE" \ + "DLL_CLK_0_FABCLK_EN:true" \ + } -validate_rules 0 +fix_vlnv_instance -component {""" ++ modulename ++"""} -library {} -name {""" ++ modulename ++"""_0} +open_smartdesign -design {""" ++ modulename ++"""} +configure_design -component {""" ++ modulename ++"""} -library {}""" + ) +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/microsemi/polarfire_glitchless_mux/PolarFireGlitchlessMux.scala b/fpga-shells/src/main/scala/ip/microsemi/polarfire_glitchless_mux/PolarFireGlitchlessMux.scala new file mode 100644 index 00000000..af47b6e1 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/polarfire_glitchless_mux/PolarFireGlitchlessMux.scala @@ -0,0 +1,41 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi.polarfireglitchlessmux + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ + +// Black Box forMicrosemi PolarFire glitchless mux Actel:SgCore:PF_NGMUX:1.0.101 + +trait PolarFireGlitchlessMuxIOPads extends Bundle { + + val CLK_OUT = Clock(OUTPUT) + val CLK0 = Clock(INPUT) + val CLK1 = Clock(INPUT) + val SEL = Bool(INPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class PolarFireGlitchlessMux(implicit val p:Parameters) extends BlackBox +{ + override def desiredName = "pf_glitchless_mux" + + val io = new PolarFireGlitchlessMuxIOPads { + } + + ElaborationArtefacts.add( + "Libero.polarfire_glitchless_mux.tcl", + """ +create_design -id Actel:SgCore:PF_NGMUX:1.0.101 -design_name {pf_glitchless_mux} -config_file {} -params {} -inhibit_configurator 0 +open_smartdesign -design {pf_glitchless_mux} +configure_design -component {pf_glitchless_mux} -library {} +fix_vlnv_instance -component {pf_glitchless_mux} -library {} -name {pf_glitchless_mux_0} +open_smartdesign -design {pf_glitchless_mux} +configure_design -component {pf_glitchless_mux} -library {} +""" + ) +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/microsemi/polarfire_init_monitor/PolarFireInitMonitor.scala b/fpga-shells/src/main/scala/ip/microsemi/polarfire_init_monitor/PolarFireInitMonitor.scala new file mode 100644 index 00000000..3b1b9671 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/polarfire_init_monitor/PolarFireInitMonitor.scala @@ -0,0 +1,42 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi.polarfireinitmonitor + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ + +// Black Box for Microsemi PolarFire Clock Conditioning Circuit (CCC) Actel:SgCore:PF_INIT_MONITOR:2.0.101 + +trait PolarFireInitMonitorIOPads extends Bundle { + + val DEVICE_INIT_DONE = Bool(OUTPUT) + val FABRIC_POR_N = Bool(OUTPUT) + val PCIE_INIT_DONE = Bool(OUTPUT) + val SRAM_INIT_DONE = Bool(OUTPUT) + val USRAM_INIT_DONE = Bool(OUTPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class PolarFireInitMonitor(implicit val p:Parameters) extends BlackBox +{ + override def desiredName = "polarfire_init_monitor" + + val io = new PolarFireInitMonitorIOPads { + } + + ElaborationArtefacts.add( + "Libero.pf_init_monitor.tcl", + """ +create_design -id Actel:SgCore:PF_INIT_MONITOR:2.0.101 -design_name {polarfire_init_monitor} -config_file {} -params {} -inhibit_configurator 0 +open_smartdesign -design {polarfire_init_monitor} +configure_design -component {polarfire_init_monitor} -library {} +fix_vlnv_instance -component {polarfire_init_monitor} -library {} -name {polarfire_init_monitor_0} +open_smartdesign -design {polarfire_init_monitor} +configure_design -component {polarfire_init_monitor} -library {} +""" + ) +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/microsemi/polarfire_oscillator/PolarFireOscillator.scala b/fpga-shells/src/main/scala/ip/microsemi/polarfire_oscillator/PolarFireOscillator.scala new file mode 100644 index 00000000..18c8ec9b --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/polarfire_oscillator/PolarFireOscillator.scala @@ -0,0 +1,37 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi.polarfire_oscillator + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ + +// Black Box for Microsemi PolarFire internal oscillator Actel:SgCore:PF_OSC:1.0.102 + +trait PolarFireOscillatorIOPads extends Bundle { + + val RCOSC_160MHZ_GL = Clock(OUTPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class PolarFireOscillator(implicit val p:Parameters) extends BlackBox +{ + override def desiredName = "pf_oscillator" + + val io = new PolarFireOscillatorIOPads { + } + + ElaborationArtefacts.add( + "Libero.polarfire_oscillator.tcl", + """ +create_design -id Actel:SgCore:PF_OSC:1.0.102 -design_name {pf_oscillator} -config_file {} -params {} -inhibit_configurator 0 +open_smartdesign -design {pf_oscillator} +configure_design -component {pf_oscillator} -library {} +fix_vlnv_instance -component {pf_oscillator} -library {} -name {pf_oscillator_0} +open_smartdesign -design {pf_oscillator} +configure_design -component {pf_oscillator} -library {} """ + ) +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/microsemi/polarfire_pcie_rootport/PolarFirePCIeRootPort.scala b/fpga-shells/src/main/scala/ip/microsemi/polarfire_pcie_rootport/PolarFirePCIeRootPort.scala new file mode 100644 index 00000000..950efdad --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/polarfire_pcie_rootport/PolarFirePCIeRootPort.scala @@ -0,0 +1,610 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi.polarfirepcierootport + +import Chisel._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.amba.axi4._ +import freechips.rocketchip.amba.apb._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.util.{ElaborationArtefacts} + + +import chisel3.core.{Input, Output, attach} + +// Black Box for Microsemi PolarFire PCIe root port + +trait PolarFirePCIeIOSerial extends Bundle { + //serial external pins + val PCIESS_LANE_TXD0_N = Bool(OUTPUT) + val PCIESS_LANE_TXD0_P = Bool(OUTPUT) + val PCIESS_LANE_TXD1_N = Bool(OUTPUT) + val PCIESS_LANE_TXD1_P = Bool(OUTPUT) + val PCIESS_LANE_TXD2_N = Bool(OUTPUT) + val PCIESS_LANE_TXD2_P = Bool(OUTPUT) + val PCIESS_LANE_TXD3_N = Bool(OUTPUT) + val PCIESS_LANE_TXD3_P = Bool(OUTPUT) + + val PCIESS_LANE_RXD0_N = Bool(INPUT) + val PCIESS_LANE_RXD0_P = Bool(INPUT) + val PCIESS_LANE_RXD1_N = Bool(INPUT) + val PCIESS_LANE_RXD1_P = Bool(INPUT) + val PCIESS_LANE_RXD2_N = Bool(INPUT) + val PCIESS_LANE_RXD2_P = Bool(INPUT) + val PCIESS_LANE_RXD3_N = Bool(INPUT) + val PCIESS_LANE_RXD3_P = Bool(INPUT) +} + +trait PolarFirePCIeIOClocksReset extends Bundle { + //clock, reset, control + val APB_S_PCLK = Clock(INPUT) + val APB_S_PRESET_N = Bool(INPUT) + + val AXI_CLK = Clock(INPUT) + val AXI_CLK_STABLE = Bool(INPUT) + + val PCIE_1_TL_CLK_125MHz = Clock(INPUT) + val PCIE_1_TX_BIT_CLK = Clock(INPUT) + val PCIE_1_TX_PLL_REF_CLK = Clock(INPUT) + val PCIE_1_TX_PLL_LOCK = Bool(INPUT) + + val PCIESS_LANE0_CDR_REF_CLK_0 = Clock(INPUT) + val PCIESS_LANE1_CDR_REF_CLK_0 = Clock(INPUT) + val PCIESS_LANE2_CDR_REF_CLK_0 = Clock(INPUT) + val PCIESS_LANE3_CDR_REF_CLK_0 = Clock(INPUT) +} + +trait PolarFirePCIeIODebug extends Bundle { + + val debug_pclk = Output(Clock()) + val debug_preset = Output(Bool()) + val debug_penable = Output(Bool()) + val debug_psel = Output(Bool()) + val debug_paddr2 = Output(Bool()) + val debug_paddr3 = Output(Bool()) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class polarfire_pcie_rp() extends BlackBox +{ + val io = new Bundle with PolarFirePCIeIOSerial + with PolarFirePCIeIOClocksReset { + + // APB control interface + val APB_S_PADDR = Bits(INPUT,26) + val APB_S_PENABLE = Bool(INPUT) + val APB_S_PSEL = Bool(INPUT) + val APB_S_PWDATA = Bits(INPUT,32) + val APB_S_PWRITE = Bool(INPUT) + val APB_S_PRDATA = Bits(OUTPUT,32) + val APB_S_PREADY = Bool(OUTPUT) + val APB_S_PSLVERR = Bool(OUTPUT) + + //axi slave + val PCIESS_AXI_1_S_ARREADY = Bool(OUTPUT) + val PCIESS_AXI_1_S_AWREADY = Bool(OUTPUT) + val PCIESS_AXI_1_S_BID = Bits(OUTPUT,4) + val PCIESS_AXI_1_S_BRESP = Bits(OUTPUT,2) + val PCIESS_AXI_1_S_BVALID = Bool(OUTPUT) + val PCIESS_AXI_1_S_RDATA = Bits(OUTPUT,64) + val PCIESS_AXI_1_S_RID = Bits(OUTPUT,4) + val PCIESS_AXI_1_S_RLAST = Bool(OUTPUT) + val PCIESS_AXI_1_S_RRESP = Bits(OUTPUT,2) + val PCIESS_AXI_1_S_RVALID = Bool(OUTPUT) + val PCIESS_AXI_1_S_WREADY = Bool(OUTPUT) + + val PCIESS_AXI_1_S_ARADDR = Bits(INPUT,32) + val PCIESS_AXI_1_S_ARBURST = Bits(INPUT,2) + val PCIESS_AXI_1_S_ARID = Bits(INPUT,4) + val PCIESS_AXI_1_S_ARLEN = Bits(INPUT,8) + val PCIESS_AXI_1_S_ARSIZE = Bits(INPUT,2) + val PCIESS_AXI_1_S_ARVALID = Bool(INPUT) + val PCIESS_AXI_1_S_AWADDR = Bits(INPUT,32) + val PCIESS_AXI_1_S_AWBURST = Bits(INPUT,2) + val PCIESS_AXI_1_S_AWID = Bits(INPUT,4) + val PCIESS_AXI_1_S_AWLEN = Bits(INPUT,8) + val PCIESS_AXI_1_S_AWSIZE = Bits(INPUT,2) + val PCIESS_AXI_1_S_AWVALID = Bool(INPUT) + val PCIESS_AXI_1_S_BREADY = Bool(INPUT) + val PCIESS_AXI_1_S_RREADY = Bool(INPUT) + val PCIESS_AXI_1_S_WDATA = Bits(INPUT,64) + val PCIESS_AXI_1_S_WLAST = Bool(INPUT) + val PCIESS_AXI_1_S_WSTRB = Bits(INPUT,8) + val PCIESS_AXI_1_S_WVALID = Bool(INPUT) + + //axi master + val PCIESS_AXI_1_M_ARADDR = Bits(OUTPUT,32) + val PCIESS_AXI_1_M_ARBURST = Bits(OUTPUT,2) + val PCIESS_AXI_1_M_ARID = Bits(OUTPUT,4) + val PCIESS_AXI_1_M_ARLEN = Bits(OUTPUT,8) + val PCIESS_AXI_1_M_ARSIZE = Bits(OUTPUT,2) + val PCIESS_AXI_1_M_ARVALID = Bool(OUTPUT) + val PCIESS_AXI_1_M_AWADDR = Bits(OUTPUT,32) + val PCIESS_AXI_1_M_AWBURST = Bits(OUTPUT,2) + val PCIESS_AXI_1_M_AWID = Bits(OUTPUT,4) + val PCIESS_AXI_1_M_AWLEN = Bits(OUTPUT,8) + val PCIESS_AXI_1_M_AWSIZE = Bits(OUTPUT,2) + val PCIESS_AXI_1_M_AWVALID = Bool(OUTPUT) + val PCIESS_AXI_1_M_BREADY = Bool(OUTPUT) + val PCIESS_AXI_1_M_RREADY = Bool(OUTPUT) + val PCIESS_AXI_1_M_WDATA = Bits(OUTPUT,64) + val PCIESS_AXI_1_M_WLAST = Bool(OUTPUT) + val PCIESS_AXI_1_M_WSTRB = Bits(OUTPUT,8) + val PCIESS_AXI_1_M_WVALID = Bool(OUTPUT) + + val PCIESS_AXI_1_M_ARREADY = Bool(INPUT) + val PCIESS_AXI_1_M_AWREADY = Bool(INPUT) + val PCIESS_AXI_1_M_BID = Bits(INPUT,4) + val PCIESS_AXI_1_M_BRESP = Bits(INPUT,2) + val PCIESS_AXI_1_M_BVALID = Bool(INPUT) + val PCIESS_AXI_1_M_RDATA = Bits(INPUT,64) + val PCIESS_AXI_1_M_RID = Bits(INPUT,4) + val PCIESS_AXI_1_M_RLAST = Bool(INPUT) + val PCIESS_AXI_1_M_RRESP = Bits(INPUT,2) + val PCIESS_AXI_1_M_RVALID = Bool(INPUT) + val PCIESS_AXI_1_M_WREADY = Bool(INPUT) + + // Misc + val DLL_OUT = Bool(OUTPUT) + val PCIE_1_DLUP_EXIT = Bool(OUTPUT) + val PCIE_1_HOT_RST_EXIT = Bool(OUTPUT) + val PCIE_1_INTERRUPT_OUT = Bool(OUTPUT) + val PCIE_1_L2_EXIT = Bool(OUTPUT) + val PCIE_1_LTSSM = Bits(OUTPUT,5) + val PCIE_1_M_WDERR = Bool(OUTPUT) + val PCIE_1_S_RDERR = Bool(OUTPUT) + + val PCIE_1_INTERRUPT = Bits(INPUT,8) + val PCIE_1_M_RDERR = Bool(INPUT) + val PCIE_1_S_WDERR = Bool(INPUT) + } +} +//scalastyle:off + +class PolarFirePCIeX4(implicit p:Parameters) extends LazyModule +{ + val device = new SimpleDevice("pci", Seq("plda,axi-pcie-root-port-1.00")) { + override def describe(resources: ResourceBindings): Description = { + val Description(name, mapping) = super.describe(resources) + val intc = "pcie_intc" + def ofInt(x: Int) = Seq(ResourceInt(BigInt(x))) + def ofMap(x: Int) = Seq(0, 0, 0, x).flatMap(ofInt) ++ Seq(ResourceReference(intc)) ++ ofInt(x) + val extra = Map( + "#address-cells" -> ofInt(3), + "#size-cells" -> ofInt(2), + "#interrupt-cells" -> ofInt(1), + "device_type" -> Seq(ResourceString("pci")), + "interrupt-map-mask" -> Seq(0, 0, 0, 7).flatMap(ofInt), + "interrupt-map" -> Seq(1, 2, 3, 4).flatMap(ofMap), + "ranges" -> resources("ranges").map(x => + (x: @unchecked) match { case Binding(_, ResourceAddress(address, perms)) => + ResourceMapping(address, + BigInt(0x02000000) << 64, perms) }), + "interrupt-controller" -> Seq(ResourceMap(labels = Seq(intc), value = Map( + "interrupt-controller" -> Nil, + "#address-cells" -> ofInt(0), + "#interrupt-cells" -> ofInt(1))))) + Description(name, mapping ++ extra) + } + } + + val slave = AXI4SlaveNode(Seq(AXI4SlavePortParameters( + slaves = Seq(AXI4SlaveParameters( + address = List(AddressSet(0x40000000L, 0x1fffffffL),AddressSet(0x2030000000L, 0x0fffffffL)), + resources = Seq(Resource(device, "ranges")), + executable = true, + supportsWrite = TransferSizes(1, 128), + supportsRead = TransferSizes(1, 128))), + beatBytes = 8))) + + val control = APBSlaveNode(Seq(APBSlavePortParameters( + slaves = Seq(APBSlaveParameters( + address = List(AddressSet(0x2000000000L, 0x03ffffffL)), + resources = device.reg("control"), + supportsWrite = TransferSizes(1, 4), + supportsRead = TransferSizes(1, 4))), + beatBytes = 4))) + + + val master = AXI4MasterNode(Seq(AXI4MasterPortParameters( + masters = Seq(AXI4MasterParameters( + name = "PolarFire PCIe", + id = IdRange(0, 16), + aligned = false))))) + + val intnode = IntSourceNode(IntSourcePortSimple(resources = device.int)) + + lazy val module = new LazyModuleImp(this) { + // Must have exactly the right number of idBits + require (slave.edges.in(0).bundle.idBits == 4) + require (master.edges.out(0).bundle.dataBits == 64) + + class PolarFirePCIeX4IOBundle extends Bundle with PolarFirePCIeIOSerial + with PolarFirePCIeIODebug + with PolarFirePCIeIOClocksReset; + + val io = IO(new Bundle { + val port = new PolarFirePCIeX4IOBundle + val REFCLK = Bool(INPUT) + }) + + val blackbox = Module(new polarfire_pcie_rp) + + val (s, _) = slave.in(0) + val (c, _) = control.in(0) + val (m, _) = master.out(0) + val (i, _) = intnode.out(0) + + //to top level + i(0) := blackbox.io.PCIE_1_INTERRUPT_OUT + blackbox.io.APB_S_PCLK := io.port.APB_S_PCLK + blackbox.io.APB_S_PRESET_N := io.port.APB_S_PRESET_N + + blackbox.io.AXI_CLK := io.port.AXI_CLK + blackbox.io.AXI_CLK_STABLE := io.port.AXI_CLK_STABLE + + blackbox.io.PCIE_1_TL_CLK_125MHz := io.port.PCIE_1_TL_CLK_125MHz + blackbox.io.PCIE_1_TX_BIT_CLK := io.port.PCIE_1_TX_BIT_CLK + blackbox.io.PCIE_1_TX_PLL_REF_CLK := io.port.PCIE_1_TX_PLL_REF_CLK + blackbox.io.PCIE_1_TX_PLL_LOCK := io.port.PCIE_1_TX_PLL_LOCK + blackbox.io.PCIESS_LANE0_CDR_REF_CLK_0 := io.port.PCIESS_LANE0_CDR_REF_CLK_0 + blackbox.io.PCIESS_LANE1_CDR_REF_CLK_0 := io.port.PCIESS_LANE1_CDR_REF_CLK_0 + blackbox.io.PCIESS_LANE2_CDR_REF_CLK_0 := io.port.PCIESS_LANE2_CDR_REF_CLK_0 + blackbox.io.PCIESS_LANE3_CDR_REF_CLK_0 := io.port.PCIESS_LANE3_CDR_REF_CLK_0 + + io.port.PCIESS_LANE_TXD0_N := blackbox.io.PCIESS_LANE_TXD0_N + io.port.PCIESS_LANE_TXD0_P := blackbox.io.PCIESS_LANE_TXD0_P + io.port.PCIESS_LANE_TXD1_N := blackbox.io.PCIESS_LANE_TXD1_N + io.port.PCIESS_LANE_TXD1_P := blackbox.io.PCIESS_LANE_TXD1_P + io.port.PCIESS_LANE_TXD2_N := blackbox.io.PCIESS_LANE_TXD2_N + io.port.PCIESS_LANE_TXD2_P := blackbox.io.PCIESS_LANE_TXD2_P + io.port.PCIESS_LANE_TXD3_N := blackbox.io.PCIESS_LANE_TXD3_N + io.port.PCIESS_LANE_TXD3_P := blackbox.io.PCIESS_LANE_TXD3_P + + blackbox.io.PCIESS_LANE_RXD0_N := io.port.PCIESS_LANE_RXD0_N + blackbox.io.PCIESS_LANE_RXD0_P := io.port.PCIESS_LANE_RXD0_P + blackbox.io.PCIESS_LANE_RXD1_N := io.port.PCIESS_LANE_RXD1_N + blackbox.io.PCIESS_LANE_RXD1_P := io.port.PCIESS_LANE_RXD1_P + blackbox.io.PCIESS_LANE_RXD2_N := io.port.PCIESS_LANE_RXD2_N + blackbox.io.PCIESS_LANE_RXD2_P := io.port.PCIESS_LANE_RXD2_P + blackbox.io.PCIESS_LANE_RXD3_N := io.port.PCIESS_LANE_RXD3_N + blackbox.io.PCIESS_LANE_RXD3_P := io.port.PCIESS_LANE_RXD3_P + + //s + //slave interface + blackbox.io.PCIESS_AXI_1_S_AWID := s.aw.bits.id + blackbox.io.PCIESS_AXI_1_S_AWADDR := s.aw.bits.addr + blackbox.io.PCIESS_AXI_1_S_AWLEN := s.aw.bits.len + blackbox.io.PCIESS_AXI_1_S_AWSIZE := s.aw.bits.size + blackbox.io.PCIESS_AXI_1_S_AWBURST := s.aw.bits.burst + blackbox.io.PCIESS_AXI_1_S_AWVALID := s.aw.valid + s.aw.ready := blackbox.io.PCIESS_AXI_1_S_AWREADY + + blackbox.io.PCIESS_AXI_1_S_WDATA := s.w.bits.data + blackbox.io.PCIESS_AXI_1_S_WSTRB := s.w.bits.strb + blackbox.io.PCIESS_AXI_1_S_WLAST := s.w.bits.last + blackbox.io.PCIESS_AXI_1_S_WVALID := s.w.valid + s.w.ready := blackbox.io.PCIESS_AXI_1_S_WREADY + + s.b.bits.id := blackbox.io.PCIESS_AXI_1_S_BID + s.b.bits.resp := blackbox.io.PCIESS_AXI_1_S_BRESP + s.b.valid := blackbox.io.PCIESS_AXI_1_S_BVALID + blackbox.io.PCIESS_AXI_1_S_BREADY := s.b.ready + + blackbox.io.PCIESS_AXI_1_S_ARID := s.ar.bits.id + blackbox.io.PCIESS_AXI_1_S_ARADDR := s.ar.bits.addr + blackbox.io.PCIESS_AXI_1_S_ARLEN := s.ar.bits.len + blackbox.io.PCIESS_AXI_1_S_ARSIZE := s.ar.bits.size + blackbox.io.PCIESS_AXI_1_S_ARBURST := s.ar.bits.burst + blackbox.io.PCIESS_AXI_1_S_ARVALID := s.ar.valid + s.ar.ready := blackbox.io.PCIESS_AXI_1_S_ARREADY + + s.r.bits.id := blackbox.io.PCIESS_AXI_1_S_RID + s.r.bits.data := blackbox.io.PCIESS_AXI_1_S_RDATA + s.r.bits.resp := blackbox.io.PCIESS_AXI_1_S_RRESP + s.r.bits.last := blackbox.io.PCIESS_AXI_1_S_RLAST + s.r.valid := blackbox.io.PCIESS_AXI_1_S_RVALID + blackbox.io.PCIESS_AXI_1_S_RREADY := s.r.ready + + blackbox.io.PCIE_1_INTERRUPT := UInt(0) + blackbox.io.PCIE_1_M_RDERR := Bool(false) + blackbox.io.PCIE_1_S_WDERR := Bool(false) + + //ctl + blackbox.io.APB_S_PADDR := c.paddr + blackbox.io.APB_S_PENABLE := c.penable + blackbox.io.APB_S_PSEL := c.psel + blackbox.io.APB_S_PWDATA := c.pwdata + blackbox.io.APB_S_PWRITE := c.pwrite + c.prdata := blackbox.io.APB_S_PRDATA + c.pready := blackbox.io.APB_S_PREADY + c.pslverr := blackbox.io.APB_S_PSLVERR + + + // debug + io.port.debug_pclk := io.port.APB_S_PCLK + io.port.debug_preset := io.port.APB_S_PRESET_N + io.port.debug_penable := c.penable + io.port.debug_psel := c.psel + io.port.debug_paddr2 := c.paddr(2) + io.port.debug_paddr3 := c.paddr(3) + + //m + m.aw.bits.cache := UInt(0) + m.aw.bits.prot := AXI4Parameters.PROT_PRIVILEDGED + m.aw.bits.qos := UInt(0) + + m.aw.bits.id := blackbox.io.PCIESS_AXI_1_M_AWID + m.aw.bits.addr := blackbox.io.PCIESS_AXI_1_M_AWADDR + m.aw.bits.len := blackbox.io.PCIESS_AXI_1_M_AWLEN + m.aw.bits.size := blackbox.io.PCIESS_AXI_1_M_AWSIZE + m.aw.bits.burst := blackbox.io.PCIESS_AXI_1_M_AWBURST + m.aw.bits.id := blackbox.io.PCIESS_AXI_1_M_AWID + m.aw.valid := blackbox.io.PCIESS_AXI_1_M_AWVALID + blackbox.io.PCIESS_AXI_1_M_AWREADY := m.aw.ready + + m.w.bits.data := blackbox.io.PCIESS_AXI_1_M_WDATA + m.w.bits.strb := blackbox.io.PCIESS_AXI_1_M_WSTRB + m.w.bits.last := blackbox.io.PCIESS_AXI_1_M_WLAST + m.w.valid := blackbox.io.PCIESS_AXI_1_M_WVALID + blackbox.io.PCIESS_AXI_1_M_WREADY := m.w.ready + + blackbox.io.PCIESS_AXI_1_M_BID := m.b.bits.id + blackbox.io.PCIESS_AXI_1_M_BRESP := m.b.bits.resp + blackbox.io.PCIESS_AXI_1_M_BVALID := m.b.valid + m.b.ready := blackbox.io.PCIESS_AXI_1_M_BREADY + + m.ar.bits.cache := UInt(0) + m.ar.bits.prot := AXI4Parameters.PROT_PRIVILEDGED + m.ar.bits.qos := UInt(0) + + m.ar.bits.id := blackbox.io.PCIESS_AXI_1_M_ARID + m.ar.bits.addr := blackbox.io.PCIESS_AXI_1_M_ARADDR + m.ar.bits.len := blackbox.io.PCIESS_AXI_1_M_ARLEN + m.ar.bits.size := blackbox.io.PCIESS_AXI_1_M_ARSIZE + m.ar.bits.burst := blackbox.io.PCIESS_AXI_1_M_ARBURST + m.ar.valid := blackbox.io.PCIESS_AXI_1_M_ARVALID + m.ar.bits.id := blackbox.io.PCIESS_AXI_1_M_ARID + blackbox.io.PCIESS_AXI_1_M_ARREADY := m.ar.ready + + blackbox.io.PCIESS_AXI_1_M_RID := m.r.bits.id + blackbox.io.PCIESS_AXI_1_M_RDATA := m.r.bits.data + blackbox.io.PCIESS_AXI_1_M_RRESP := m.r.bits.resp + blackbox.io.PCIESS_AXI_1_M_RLAST := m.r.bits.last + blackbox.io.PCIESS_AXI_1_M_RVALID := m.r.valid + m.r.ready := blackbox.io.PCIESS_AXI_1_M_RREADY + } + + ElaborationArtefacts.add( + "Libero.polarfire_pcie_root_port.tcl", + """ +new_file -type {SmartDesign} -name polarfire_pcie_rp +add_vlnv_instance -component {polarfire_pcie_rp} -library {} -vendor {Actel} -lib {SgCore} -name {PF_PCIE} -version {1.0.234} -instance_name {PF_PCIE_0} -promote_all 0 -file_name {} +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_IS_CONFIGURED:true"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_SIMULATION_LEVEL:RTL"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIESS_LANE0_IS_USED:true"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIESS_LANE1_IS_USED:false"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIESS_LANE2_IS_USED:false"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIESS_LANE3_IS_USED:false"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_GPSS1_LANE0_IS_USED:false"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_GPSS1_LANE1_IS_USED:false"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_GPSS1_LANE2_IS_USED:false"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_GPSS1_LANE3_IS_USED:false"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PROTOCOL_PRESET_USED:PCIe"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_TX_CLK_DIV_FACTOR:1"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_CONTROLLER_ENABLED:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_NUMBER_OF_LANES:x1"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_LANE_RATE:Gen1 (2.5 Gbps)"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_REF_CLK_FREQ:100"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_PORT_TYPE:End Point"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_CDR_REF_CLK_SOURCE:Dedicated"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_CDR_REF_CLK_NUMBER:1"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_CONTROLLER_ENABLED:Enabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_NUMBER_OF_LANES:x4"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_LANE_RATE:Gen2 (5.0 Gbps)"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_REF_CLK_FREQ:100"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_PORT_TYPE:Root Port"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_CDR_REF_CLK_SOURCE:Dedicated"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_CDR_REF_CLK_NUMBER:1"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_VENDOR_ID:0x11AA"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SUB_VENDOR_ID:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_REVISION_ID:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_DEVICE_ID:0x1556"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SUB_SYSTEM_ID:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_CLASS_CODE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_VENDOR_ID:0x11AA"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SUB_VENDOR_ID:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_REVISION_ID:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_DEVICE_ID:0x1556"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SUB_SYSTEM_ID:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_CLASS_CODE:0x060400"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_BAR_MODE:Custom"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_PHY_REF_CLK_SLOT:Slot"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_INTERRUPTS:INTx"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_DE_EMPHASIS:-3.5 dB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_EXPOSE_WAKE_SIG:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_TRANSMIT_SWING:Full Swing"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_BAR_MODE:Custom"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_PHY_REF_CLK_SLOT:Slot"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_INTERRUPTS:MSI4"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_DE_EMPHASIS:-3.5 dB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_EXPOSE_WAKE_SIG:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_TRANSMIT_SWING:Full Swing"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_NUM_FTS:63"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_L0_ACC_LATENCY:No limit"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_L0_EXIT_LATENCY:64 ns to less than 128 ns"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_L1_ENABLE:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_L1_ACC_LATENCY:No limit"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_L1_EXIT_LATENCY:16 us to less than 32 us"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_NUM_FTS:63"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_L0_ACC_LATENCY:No limit"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_L0_EXIT_LATENCY:64 ns to less than 128 ns"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_L1_ENABLE:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_L1_ACC_LATENCY:No limit"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_L1_EXIT_LATENCY:16 us to less than 32 us"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TYPE_BAR_0_TABLE:64-bit prefetchable memory"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_SIZE_BAR_0_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TABLE_SIZE_BAR_0_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_SOURCE_ADDRESS_BAR_0_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TRANS_ADDRESS_BAR_0_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TYPE_BAR_0_TABLE:64-bit prefetchable memory"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_SIZE_BAR_0_TABLE:2 GB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TABLE_SIZE_BAR_0_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_SOURCE_ADDRESS_BAR_0_TABLE:0x100000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TRANS_ADDRESS_BAR_0_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TYPE_BAR_1_TABLE:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_SIZE_BAR_1_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TABLE_SIZE_BAR_1_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_SOURCE_ADDRESS_BAR_1_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TRANS_ADDRESS_BAR_1_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TYPE_BAR_1_TABLE:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_SIZE_BAR_1_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TABLE_SIZE_BAR_1_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_SOURCE_ADDRESS_BAR_1_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TRANS_ADDRESS_BAR_1_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TYPE_BAR_2_TABLE:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_SIZE_BAR_2_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TABLE_SIZE_BAR_2_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_SOURCE_ADDRESS_BAR_2_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TRANS_ADDRESS_BAR_2_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TYPE_BAR_2_TABLE:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_SIZE_BAR_2_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TABLE_SIZE_BAR_2_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_SOURCE_ADDRESS_BAR_2_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TRANS_ADDRESS_BAR_2_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TYPE_BAR_3_TABLE:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_SIZE_BAR_3_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TABLE_SIZE_BAR_3_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_SOURCE_ADDRESS_BAR_3_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TRANS_ADDRESS_BAR_3_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TYPE_BAR_3_TABLE:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_SIZE_BAR_3_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TABLE_SIZE_BAR_3_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_SOURCE_ADDRESS_BAR_3_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TRANS_ADDRESS_BAR_3_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TYPE_BAR_4_TABLE:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_SIZE_BAR_4_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TABLE_SIZE_BAR_4_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_SOURCE_ADDRESS_BAR_4_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TRANS_ADDRESS_BAR_4_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TYPE_BAR_4_TABLE:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_SIZE_BAR_4_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TABLE_SIZE_BAR_4_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_SOURCE_ADDRESS_BAR_4_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TRANS_ADDRESS_BAR_4_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TYPE_BAR_5_TABLE:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_SIZE_BAR_5_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TABLE_SIZE_BAR_5_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_SOURCE_ADDRESS_BAR_5_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_MASTER_TRANS_ADDRESS_BAR_5_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TYPE_BAR_5_TABLE:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_SIZE_BAR_5_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TABLE_SIZE_BAR_5_TABLE:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_SOURCE_ADDRESS_BAR_5_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_MASTER_TRANS_ADDRESS_BAR_5_TABLE:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_STATE_TABLE_0:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SIZE_TABLE_0:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SOURCE_ADDRESS_TABLE_0:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_TRANS_ADDRESS_TABLE_0:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_STATE_TABLE_0:Enabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SIZE_TABLE_0:256 MB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SOURCE_ADDRESS_TABLE_0:0x30000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_TRANS_ADDRESS_TABLE_0:0x30000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_STATE_TABLE_1:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SIZE_TABLE_1:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SOURCE_ADDRESS_TABLE_1:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_TRANS_ADDRESS_TABLE_1:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_STATE_TABLE_1:Enabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SIZE_TABLE_1:512 MB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SOURCE_ADDRESS_TABLE_1:0x40000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_TRANS_ADDRESS_TABLE_1:0x40000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_STATE_TABLE_2:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SIZE_TABLE_2:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SOURCE_ADDRESS_TABLE_2:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_TRANS_ADDRESS_TABLE_2:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_STATE_TABLE_2:Enabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SIZE_TABLE_2:2 GB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SOURCE_ADDRESS_TABLE_2:0x80000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_TRANS_ADDRESS_TABLE_2:0x2080000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_STATE_TABLE_3:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SIZE_TABLE_3:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SOURCE_ADDRESS_TABLE_3:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_TRANS_ADDRESS_TABLE_3:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_STATE_TABLE_3:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SIZE_TABLE_3:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SOURCE_ADDRESS_TABLE_3:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_TRANS_ADDRESS_TABLE_3:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_STATE_TABLE_4:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SIZE_TABLE_4:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SOURCE_ADDRESS_TABLE_4:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_TRANS_ADDRESS_TABLE_4:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_STATE_TABLE_4:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SIZE_TABLE_4:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SOURCE_ADDRESS_TABLE_4:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_TRANS_ADDRESS_TABLE_4:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_STATE_TABLE_5:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SIZE_TABLE_5:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SOURCE_ADDRESS_TABLE_5:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_TRANS_ADDRESS_TABLE_5:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_STATE_TABLE_5:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SIZE_TABLE_5:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SOURCE_ADDRESS_TABLE_5:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_TRANS_ADDRESS_TABLE_5:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_STATE_TABLE_6:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SIZE_TABLE_6:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SOURCE_ADDRESS_TABLE_6:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_TRANS_ADDRESS_TABLE_6:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_STATE_TABLE_6:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SIZE_TABLE_6:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SOURCE_ADDRESS_TABLE_6:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_TRANS_ADDRESS_TABLE_6:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_STATE_TABLE_7:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SIZE_TABLE_7:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_SOURCE_ADDRESS_TABLE_7:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_0_SLAVE_TRANS_ADDRESS_TABLE_7:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_STATE_TABLE_7:Disabled"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SIZE_TABLE_7:4 KB"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_SOURCE_ADDRESS_TABLE_7:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_PCIE_1_SLAVE_TRANS_ADDRESS_TABLE_7:0x0000"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_EXPOSE_LANE_DRI_PORTS:false"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"UI_EXPOSE_PCIE_APBLINK_PORTS:true"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"SD_EXPORT_HIDDEN_PORTS:false"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"EXPOSE_ALL_DEBUG_PORTS:false"} -validate_rules 0 +configure_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} -params {"XT_ES_DEVICE:true"} -validate_rules 0 +fix_vlnv_instance -component {polarfire_pcie_rp} -library {} -name {PF_PCIE_0} + +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:AXI_CLK} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:AXI_CLK_STABLE} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIESS_LANE0_CDR_REF_CLK_0} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIESS_LANE1_CDR_REF_CLK_0} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIESS_LANE2_CDR_REF_CLK_0} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIESS_LANE3_CDR_REF_CLK_0} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIE_1_TL_CLK_125MHZ} -pin_create_new {} + +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIE_1_INTERRUPT} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIE_1_S_WDERR} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIE_1_M_RDERR} -pin_create_new {} + +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:DLL_OUT} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIE_1_DLUP_EXIT} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIE_1_HOT_RST_EXIT} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIE_1_INTERRUPT_OUT} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIE_1_L2_EXIT} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIE_1_LTSSM} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIE_1_M_WDERR} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIE_1_S_RDERR} -pin_create_new {} + +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:APB_S_PCLK} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:APB_S_PRESET_N} -pin_create_new {} + +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:AXI_1_SLAVE} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:PCIE_APB_SLAVE} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:CLKS_FROM_TXPLL_TO_PCIE_1} -pin_create_new {} +promote_pin_to_top -component {polarfire_pcie_rp} -library {} -pin {PF_PCIE_0:AXI_1_MASTER} -pin_create_new {} + +generate_design -component {polarfire_pcie_rp} -library {} -generator {} -recursive 1 +""" + ) + +} diff --git a/fpga-shells/src/main/scala/ip/microsemi/polarfire_reset/PolarFireReset.scala b/fpga-shells/src/main/scala/ip/microsemi/polarfire_reset/PolarFireReset.scala new file mode 100644 index 00000000..7b8cd056 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/polarfire_reset/PolarFireReset.scala @@ -0,0 +1,44 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi.polarfirereset + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ + +// Black Box for Microsemi PolarFire IP block Actel:DirectCore:CORERESET_PF:2.1.100 + +trait PolarFireResetIOPads extends Bundle { + + val CLK = Clock(INPUT) + val EXT_RST_N = Bool(INPUT) + val FF_US_RESTORE = Bool(INPUT) + val INIT_DONE = Bool(INPUT) + val PLL_LOCK = Bool(INPUT) + val SS_BUSY = Bool(INPUT) + val FABRIC_RESET_N = Bool(OUTPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class PolarFireReset(implicit val p:Parameters) extends BlackBox +{ + override def desiredName = "polarfire_reset" + + val io = new PolarFireResetIOPads { + } + + + ElaborationArtefacts.add( + "Libero.polarfire_reset.tcl", + """ +create_design -id Actel:DirectCore:CORERESET_PF:2.1.100 -design_name {polarfire_reset} -config_file {} -params {} -inhibit_configurator 0 +open_smartdesign -design {polarfire_reset} +configure_design -component {polarfire_reset} -library {} +fix_vlnv_instance -component {polarfire_reset} -library {} -name {polarfire_reset_0} +open_smartdesign -design {polarfire_reset} +configure_design -component {polarfire_reset} -library {}""" + ) +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/microsemi/polarfire_tx_pll/PolarFireTxPLL.scala b/fpga-shells/src/main/scala/ip/microsemi/polarfire_tx_pll/PolarFireTxPLL.scala new file mode 100644 index 00000000..6f935427 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/polarfire_tx_pll/PolarFireTxPLL.scala @@ -0,0 +1,45 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi.polarfiretxpll + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ + +// Black Box for Microsemi:SgCore:PF_TX_PLL:1.0.109 + +trait PolarFireTxPLLIOPads extends Bundle { + + val REF_CLK = Clock(INPUT) + val BIT_CLK = Clock(OUTPUT) + val CLK_125 = Clock(OUTPUT) + val REF_CLK_TO_LANE = Clock(OUTPUT) + val LOCK = Bool(OUTPUT) + val PLL_LOCK = Bool(OUTPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class PolarFireTxPLL(implicit val p:Parameters) extends BlackBox +{ + override def desiredName = "transmit_pll" + + val io = new PolarFireTxPLLIOPads { + } + + ElaborationArtefacts.add( + "Libero.polarfire_tx_pll.tcl", + """ +create_design -id Actel:SgCore:PF_TX_PLL:1.0.109 -design_name {transmit_pll} -config_file {} -params {} -inhibit_configurator 0 +open_smartdesign -design {transmit_pll} +configure_design -component {transmit_pll} -library {} +configure_vlnv_instance -component {transmit_pll} -library {} -name {transmit_pll_0} -params {"TxPLL_REF:100" "TxPLL_OUT:2500"} -validate_rules 0 +fix_vlnv_instance -component {transmit_pll} -library {} -name {transmit_pll_0} +open_smartdesign -design {transmit_pll} +configure_design -component {transmit_pll} -library {} +""" + ) + +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/microsemi/polarfire_xcvr_refclk/PolarFireTransceiverRefClk.scala b/fpga-shells/src/main/scala/ip/microsemi/polarfire_xcvr_refclk/PolarFireTransceiverRefClk.scala new file mode 100644 index 00000000..b26247cb --- /dev/null +++ b/fpga-shells/src/main/scala/ip/microsemi/polarfire_xcvr_refclk/PolarFireTransceiverRefClk.scala @@ -0,0 +1,46 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.microsemi.polarfirexcvrrefclk + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ + +// Black Box for Microsemi:SgCore:PF_XCVR_REF_CLK:1.0.103 + +trait PolarFireTransceiverRefClkIOPads extends Bundle { + + val REF_CLK_PAD_P = Bool(INPUT) + val REF_CLK_PAD_N = Bool(INPUT) + val REF_CLK = Clock(OUTPUT) + val FAB_REF_CLK = Clock(OUTPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class PolarFireTransceiverRefClk(implicit val p:Parameters) extends BlackBox +{ + override def desiredName = "transceiver_refclk" + + val io = new PolarFireTransceiverRefClkIOPads { + } + + ElaborationArtefacts.add( + "Libero.polarfire_xcvr_refclk.tcl", + """ +create_design -id Actel:SgCore:PF_XCVR_REF_CLK:1.0.103 -design_name {transceiver_refclk} -config_file {} -params {} -inhibit_configurator 0 +open_smartdesign -design {transceiver_refclk} +configure_design -component {transceiver_refclk} -library {} +configure_vlnv_instance -component {transceiver_refclk} -library {} -name {transceiver_refclk_0} \ + -params {"ENABLE_FAB_CLK_0:1" \ + } -validate_rules 0 + +fix_vlnv_instance -component {transceiver_refclk} -library {} -name {transceiver_refclk_0} +open_smartdesign -design {transceiver_refclk} +configure_design -component {transceiver_refclk} -library {} +""" + ) + +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/xilinx/Unisim.scala b/fpga-shells/src/main/scala/ip/xilinx/Unisim.scala new file mode 100644 index 00000000..87e72dc9 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/xilinx/Unisim.scala @@ -0,0 +1,370 @@ +// See LICENSE for license details. + +package sifive.fpgashells.ip.xilinx +import Chisel._ +import chisel3.{Input, Output} +import chisel3.experimental.{Analog, attach, StringParam, RawParam, IntParam, DoubleParam} + +import sifive.blocks.devices.pinctrl.{BasePin} + +object booleanToVerilogVectorParam extends (Boolean => RawParam) { + def apply(b : Boolean) : RawParam = if(b) RawParam("1") else RawParam("0") +} + +object booleanToVerilogStringParam extends (Boolean => StringParam) { + def apply(b : Boolean) : StringParam = if(b) StringParam("""TRUE""") else StringParam("""FALSE""") +} + + +/** IBUFDS -- SelectIO Differential Input */ + +class IBUFDS( + CAPACITANCE : String = "DONT_CARE", + DIFF_TERM : Boolean = false, + DQS_BIAS : Boolean = false, + IBUF_DELAY_VALUE : Int = 0, + IBUF_LOW_PWR : Boolean = true, + IFD_DELAY_VALUE : String = "AUTO", + IOSTANDARD : String = "DEFAULT" +) +extends BlackBox( + Map( + "CAPACITANCE" -> StringParam(CAPACITANCE), + "DIFF_TERM" -> booleanToVerilogStringParam(DIFF_TERM), + "DQS_BIAS" -> booleanToVerilogStringParam(DQS_BIAS), + "IBUF_DELAY_VALUE" -> IntParam(IBUF_DELAY_VALUE), + "IBUF_LOW_PWR" -> booleanToVerilogStringParam(IBUF_LOW_PWR), + "IFD_DELAY_VALUE" -> StringParam(IFD_DELAY_VALUE), + "IOSTANDARD" -> StringParam(IOSTANDARD) + ) +) { + val io = IO(new Bundle { + val O = Output(Clock()) + val I = Input(Clock()) + val IB = Input(Clock()) + }) +} + +/** IBUFG -- Clock Input Buffer */ + +class IBUFG extends BlackBox { + val io = IO(new Bundle { + val O = Output(Clock()) + val I = Input(Clock()) + }) +} + +object IBUFG { + def apply (pin: Clock): Clock = { + val pad = Module (new IBUFG()) + pad.io.I := pin + pad.io.O + } +} + +/** IBUF -- Input Buffer */ + +class IBUF extends BlackBox { + val io = IO(new Bundle { + val O = Output(Bool()) + val I = Input(Bool()) + }) +} + +object IBUF { + def apply(pin: Bool): Bool = { + val pad = Module (new IBUF) + pad.io.I := pin + pad.io.O + } +} + +/** IBUFDS_GTE2 -- Differential Signaling Input Buffer */ + +class IBUFDS_GTE2( + CLKCM_CFG : Boolean = true, + CLKRCV_TRST : Boolean = true, + CLKSWING_CFG : Int = 3 +) +extends BlackBox( + Map( + "CLKCM_CFG" -> booleanToVerilogStringParam(CLKCM_CFG), + "CLKRCV_TRST" -> booleanToVerilogStringParam(CLKCM_CFG), + "CLKSWING_CFG" -> IntParam(CLKSWING_CFG) + ) +) { + val io = IO(new Bundle { + val O = Bool(OUTPUT) + val ODIV2 = Bool(OUTPUT) + val CEB = Bool(INPUT) + val I = Bool(INPUT) + val IB = Bool(INPUT) + }) +} + +class IBUFDS_GTE4( + REFCLK_EN_TX_PATH: Int = 0, + REFCLK_HROW_CK_SEL: Int = 0, + REFCLK_ICNTL_RX: Int = 0) + extends BlackBox(Map( + "REFCLK_EN_TX_PATH" -> IntParam(REFCLK_EN_TX_PATH), + "REFCLK_HROW_CK_SEL" -> IntParam(REFCLK_HROW_CK_SEL), + "REFCLK_ICNTL_RX" -> IntParam(REFCLK_ICNTL_RX))) +{ + val io = IO(new Bundle { + val O = Clock(OUTPUT) + val ODIV2 = Clock(OUTPUT) + val CEB = Bool(INPUT) + val I = Clock(INPUT) + val IB = Clock(INPUT) + }) +} + +/** IDDR - 7 Series SelectIO DDR flop */ + +class IDDR( + DDR_CLK_EDGE : String = "OPPOSITE_EDGE", + INIT_Q1 : Boolean = false, + INIT_Q2 : Boolean = false, + IS_C_INVERTED : Boolean = false, + IS_D_INVERTED : Boolean = false, + SRTYPE : String = "SYNC" +) +extends BlackBox( + Map( + "DDR_CLK_EDGE" -> StringParam(DDR_CLK_EDGE), + "INIT_Q1" -> booleanToVerilogVectorParam(INIT_Q1), + "INIT_Q2" -> booleanToVerilogVectorParam(INIT_Q2), + "IS_C_INVERTED" -> booleanToVerilogVectorParam(IS_C_INVERTED), + "IS_D_INVERTED" -> booleanToVerilogVectorParam(IS_D_INVERTED), + "SRTYPE" -> StringParam(SRTYPE) + ) +) { + val io = IO(new Bundle { + val Q1 = Output(Bool()) + val Q2 = Output(Bool()) + val C = Input(Bool()) + val CE = Input(Bool()) + val D = Input(Bool()) + val R = Input(Bool()) + val S = Input(Bool()) + }) +} + +/** IDELAYCTRL - 7 Series SelectIO */ + +class IDELAYCTRL( + sim_device : String = "7SERIES" +) +extends BlackBox( + Map( + "SIM_DEVICE" -> StringParam(sim_device) + ) +) { + val io = IO(new Bundle { + val RDY = Output(Bool()) + val REFCLK = Input(Bool()) + val RST = Input(Bool()) + }) +} + + +/** IDELAYE2 -- 7 Series SelectIO ILogic programmable delay. */ + +class IDELAYE2( + CINVCTRL_SEL : Boolean = false, + DELAY_SRC : String = "IDATAIN", + HIGH_PERFORMANCE_MODE : Boolean = false, + IDELAY_TYPE : String = "FIXED", + IDELAY_VALUE : Int = 0, + IS_C_INVERTED : Boolean = false, + IS_DATAIN_INVERTED : Boolean = false, + IS_IDATAIN_INVERTED : Boolean = false, + PIPE_SEL : Boolean = false, + REFCLK_FREQUENCY : Double = 200.0, + SIGNAL_PATTERN : String = "DATA", + SIM_DELAY_D : Int = 0 +) +extends BlackBox( + Map( + "CINVCTRL_SEL" -> booleanToVerilogStringParam(CINVCTRL_SEL), + "DELAY_SRC" -> StringParam(DELAY_SRC), + "HIGH_PERFORMANCE_MODE" -> booleanToVerilogStringParam(HIGH_PERFORMANCE_MODE), + "IDELAY_TYPE" -> StringParam(IDELAY_TYPE), + "IS_C_INVERTED" -> booleanToVerilogVectorParam(IS_C_INVERTED), + "IS_DATAIN_INVERTED" -> booleanToVerilogVectorParam(IS_DATAIN_INVERTED), + "IS_IDATAIN_INVERTED" -> booleanToVerilogVectorParam(IS_IDATAIN_INVERTED), + "PIPE_SEL" -> booleanToVerilogStringParam(PIPE_SEL), + "REFCLK_FREQUENCY" -> DoubleParam(REFCLK_FREQUENCY), + "SIGNAL_PATTERN" -> StringParam(SIGNAL_PATTERN), + "SIM_DELAY_D" -> IntParam(SIM_DELAY_D) + ) +) { + val io = IO(new Bundle { + val DATAOUT = Output(Bool()) + val CNTVALUEOUT = Output(UInt(5.W)) + val C = Input(Bool()) + val CE = Input(Bool()) + val CINVCTRL = Input(Bool()) + val DATAIN = Input(Bool()) + val IDATAIN = Input(Bool()) + val INC = Input(Bool()) + val LD = Input(Bool()) + val LDPIPEEN = Input(Bool()) + val REGRST = Input(Bool()) + val CNTVALUEIN = Input(UInt(5.W)) + }) +} + +/** IOBUF -- Bidirectional IO Buffer. */ + +//Cannot convert to BlackBox because of line +//val IO = IO(Analog(1.W)) +//is illegal + +class IOBUF extends BlackBox { + + val io = new Bundle { + val O = Output(Bool()) + val IO = Analog(1.W) + val I = Input(Bool()) + val T = Input(Bool()) + } +} + +object IOBUF { + + def apply (pin: Analog, ctrl: BasePin): Bool = { + val pad = Module(new IOBUF()) + pad.io.I := ctrl.o.oval + pad.io.T := ~ctrl.o.oe + ctrl.i.ival := pad.io.O & ctrl.o.ie + attach(pad.io.IO, pin) + pad.io.O & ctrl.o.ie + } + + // Creates an output IOBUF + def apply (pin: Analog, in: Bool): Unit = { + val pad = Module(new IOBUF()) + pad.io.I := in + pad.io.T := false.B + attach(pad.io.IO, pin) + } + + // Creates an input IOBUF + def apply (pin: Analog): Bool = { + val pad = Module(new IOBUF()) + pad.io.I := false.B + pad.io.T := true.B + attach(pad.io.IO, pin) + pad.io.O + } + +} + +/** ODDR - 7 Series SelectIO DDR flop */ + +class ODDR( + DDR_CLK_EDGE : String = "OPPOSITE_EDGE", + INIT : Boolean = false, + IS_C_INVERTED : Boolean = false, + IS_D1_INVERTED : Boolean = false, + IS_D2_INVERTED : Boolean = false, + SRTYPE : String = "SYNC" +) +extends BlackBox( + Map( + "DDR_CLK_EDGE" -> StringParam(DDR_CLK_EDGE), + "INIT" -> booleanToVerilogVectorParam(INIT), + "IS_C_INVERTED" -> booleanToVerilogVectorParam(IS_C_INVERTED), + "IS_D1_INVERTED" -> booleanToVerilogVectorParam(IS_D1_INVERTED), + "IS_D2_INVERTED" -> booleanToVerilogVectorParam(IS_D2_INVERTED), + "SRTYPE" -> StringParam(SRTYPE) + ) +) { + val io = IO(new Bundle { + val Q = Output(Bool()) + val C = Input(Clock()) + val CE = Input(Bool()) + val D1 = Input(Bool()) + val D2 = Input(Bool()) + val R = Input(Bool()) + val S = Input(Bool()) + }) +} + +/** ODELAYE2 -- 7 Series SelectIO OLogic programmable delay. */ + +class ODELAYE2( + CINVCTRL_SEL : Boolean = false, + DELAY_SRC : String = "ODATAIN", + HIGH_PERFORMANCE_MODE : Boolean = false, + IS_C_INVERTED : Boolean = false, + IS_ODATAIN_INVERTED : Boolean = false, + ODELAY_TYPE : String = "FIXED", + ODELAY_VALUE : Int = 0, + PIPE_SEL : Boolean = false, + REFCLK_FREQUENCY : Double = 200.0, + SIGNAL_PATTERN : String = "DATA", + SIM_DELAY_D : Int = 0 +) +extends BlackBox( + Map( + "CINVCTRL_SEL" -> booleanToVerilogStringParam(CINVCTRL_SEL), + "DELAY_SRC" -> StringParam(DELAY_SRC), + "HIGH_PERFORMANCE_MODE" -> booleanToVerilogStringParam(HIGH_PERFORMANCE_MODE), + "IS_C_INVERTED" -> booleanToVerilogVectorParam(IS_C_INVERTED), + "IS_ODATAIN_INVERTED" -> booleanToVerilogVectorParam(IS_ODATAIN_INVERTED), + "ODELAY_TYPE" -> StringParam(ODELAY_TYPE), + "PIPE_SEL" -> booleanToVerilogStringParam(PIPE_SEL), + "REFCLK_FREQUENCY" -> DoubleParam(REFCLK_FREQUENCY), + "SIGNAL_PATTERN" -> StringParam(SIGNAL_PATTERN), + "SIM_DELAY_D" -> IntParam(SIM_DELAY_D) + ) +) { + val io = IO(new Bundle { + val DATAOUT = Output(Bool()) + val CNTVALUEOUT = Output(UInt(5.W)) + val C = Input(Bool()) + val CE = Input(Bool()) + val CINVCTRL = Input(Bool()) + val CLKIN = Input(Bool()) + val INC = Input(Bool()) + val LD = Input(Bool()) + val LDPIPEEN = Input(Bool()) + val ODATAIN = Input(Bool()) + val REGRST = Input(Bool()) + val CNTVALUEIN = Input(UInt(5.W)) + }) +} + +/** PULLUP : can be applied to Input to add a Pullup. */ + +class PULLUP extends BlackBox { + val io = IO(new Bundle { + val O = Analog(1.W) + }) +} + +object PULLUP { + def apply (pin: Analog): Unit = { + val pullup = Module(new PULLUP()) + attach(pullup.io.O, pin) + } +} + +/** KEEPER : can be applied to I/O to hold its last value since driven. */ + +class KEEPER extends BlackBox { + val io = IO(new Bundle { + val O = Analog(1.W) + }) +} + +object KEEPER { + def apply (pin: Analog): Unit = { + val pullup = Module(new KEEPER()) + attach(pullup.io.O, pin) + } +} + diff --git a/fpga-shells/src/main/scala/ip/xilinx/Xilinx.scala b/fpga-shells/src/main/scala/ip/xilinx/Xilinx.scala new file mode 100644 index 00000000..1e8d3e45 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/xilinx/Xilinx.scala @@ -0,0 +1,355 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.xilinx + +import Chisel._ +import chisel3.core.{Input, Output, attach} +import chisel3.experimental.{Analog} +import freechips.rocketchip.util.{ElaborationArtefacts} + +import sifive.blocks.devices.pinctrl.{BasePin} +import sifive.fpgashells.clocks._ + +//======================================================================== +// This file contains common devices used by our Xilinx FPGA flows and some +// BlackBox modules used in the Xilinx FPGA flows +//======================================================================== + +//------------------------------------------------------------------------- +// mmcm +//------------------------------------------------------------------------- +/** mmcm: This is generated by the Xilinx IP Generation Scripts */ + +class mmcm extends BlackBox { + val io = new Bundle { + val clk_in1 = Input(Clock()) + val clk_out1 = Output(Clock()) + val clk_out2 = Output(Clock()) + val clk_out3 = Output(Clock()) + val resetn = Input(Bool()) + val locked = Output(Bool()) + } +} + +//------------------------------------------------------------------------- +// reset_sys +//------------------------------------------------------------------------- +/** reset_sys: This is generated by the Xilinx IP Generation Scripts */ + +class reset_sys extends BlackBox { + val io = new Bundle { + val slowest_sync_clk = Input(Clock()) + val ext_reset_in = Input(Bool()) + val aux_reset_in = Input(Bool()) + val mb_debug_sys_rst = Input(Bool()) + val dcm_locked = Input(Bool()) + val mb_reset = Output(Bool()) + val bus_struct_reset = Output(Bool()) + val peripheral_reset = Output(Bool()) + val interconnect_aresetn = Output(Bool()) + val peripheral_aresetn = Output(Bool()) + } +} + +//------------------------------------------------------------------------- +// reset_mig +//------------------------------------------------------------------------- +/** reset_mig: This is generated by the Xilinx IP Generation Scripts */ + +class reset_mig extends BlackBox { + val io = new Bundle { + val slowest_sync_clk = Input(Clock()) + val ext_reset_in = Input(Bool()) + val aux_reset_in = Input(Bool()) + val mb_debug_sys_rst = Input(Bool()) + val dcm_locked = Input(Bool()) + val mb_reset = Output(Bool()) + val bus_struct_reset = Output(Bool()) + val peripheral_reset = Output(Bool()) + val interconnect_aresetn = Output(Bool()) + val peripheral_aresetn = Output(Bool()) + } +} + +//------------------------------------------------------------------------- +// PowerOnResetFPGAOnly +//------------------------------------------------------------------------- +/** PowerOnResetFPGAOnly -- this generates a power_on_reset signal using + * initial blocks. It is synthesizable on FPGA flows only. + */ + +// This is a FPGA-Only construct, which uses +// 'initial' constructions +class PowerOnResetFPGAOnly extends BlackBox { + val io = new Bundle { + val clock = Input(Clock()) + val power_on_reset = Output(Bool()) + } +} + +object PowerOnResetFPGAOnly { + def apply (clk: Clock, name: String): Bool = { + val por = Module(new PowerOnResetFPGAOnly()) + por.suggestName(name) + por.io.clock := clk + por.io.power_on_reset + } + def apply (clk: Clock): Bool = apply(clk, "fpga_power_on") +} + + +//------------------------------------------------------------------------- +// vc707_sys_clock_mmcm +//------------------------------------------------------------------------- +//IP : xilinx mmcm with "NO_BUFFER" input clock +class Series7MMCM(c : PLLParameters) extends BlackBox with PLLInstance { + val io = new Bundle { + val clk_in1 = Clock(INPUT) + val clk_out1 = if (c.req.size >= 1) Some(Clock(OUTPUT)) else None + val clk_out2 = if (c.req.size >= 2) Some(Clock(OUTPUT)) else None + val clk_out3 = if (c.req.size >= 3) Some(Clock(OUTPUT)) else None + val clk_out4 = if (c.req.size >= 4) Some(Clock(OUTPUT)) else None + val clk_out5 = if (c.req.size >= 5) Some(Clock(OUTPUT)) else None + val clk_out6 = if (c.req.size >= 6) Some(Clock(OUTPUT)) else None + val clk_out7 = if (c.req.size >= 7) Some(Clock(OUTPUT)) else None + val reset = Bool(INPUT) + val locked = Bool(OUTPUT) + } + + val moduleName = c.name + override def desiredName = c.name + + def getClocks = Seq() ++ io.clk_out1 ++ io.clk_out2 ++ + io.clk_out3 ++ io.clk_out4 ++ + io.clk_out5 ++ io.clk_out6 ++ + io.clk_out7 + def getInput = io.clk_in1 + def getReset = Some(io.reset) + def getLocked = io.locked + def getClockNames = Seq.tabulate (c.req.size) { i => + s"${c.name}/inst/mmcm_adv_inst/CLKOUT${i}" + } + + val used = Seq.tabulate(7) { i => + s" CONFIG.CLKOUT${i+1}_USED {${i < c.req.size}} \\\n" + }.mkString + + val outputs = c.req.zipWithIndex.map { case (r, i) => + s""" CONFIG.CLKOUT${i+1}_REQUESTED_OUT_FREQ {${r.freqMHz}} \\ + | CONFIG.CLKOUT${i+1}_REQUESTED_PHASE {${r.phaseDeg}} \\ + | CONFIG.CLKOUT${i+1}_REQUESTED_DUTY_CYCLE {${r.dutyCycle}} \\ + |""".stripMargin + }.mkString + + val checks = c.req.zipWithIndex.map { case (r, i) => + val f = if (i == 0) "_F" else "" + val phaseMin = r.phaseDeg - r.phaseErrorDeg + val phaseMax = r.phaseDeg + r.phaseErrorDeg + val freqMin = r.freqMHz * (1 - r.freqErrorPPM / 1000000) + val freqMax = r.freqMHz * (1 + r.freqErrorPPM / 1000000) + s"""set jitter [get_property CONFIG.CLKOUT${i+1}_JITTER [get_ips ${moduleName}]] + |if {$$jitter > ${r.jitterPS}} { + | puts "Output jitter $$jitter ps exceeds required limit of ${r.jitterPS}" + | exit 1 + |} + |set phase [get_property CONFIG.MMCM_CLKOUT${i}_PHASE [get_ips ${moduleName}]] + |if {$$phase < ${phaseMin} || $$phase > ${phaseMax}} { + | puts "Achieved phase $$phase degrees is outside tolerated range ${phaseMin}-${phaseMax}" + | exit 1 + |} + |set div2 [get_property CONFIG.MMCM_CLKOUT${i}_DIVIDE${f} [get_ips ${moduleName}]] + |set freq [expr { ${c.input.freqMHz} * $$mult / $$div1 / $$div2 }] + |if {$$freq < ${freqMin} || $$freq > ${freqMax}} { + | puts "Achieved frequency $$freq MHz is outside tolerated range ${freqMin}-${freqMax}" + | exit 1 + |} + |puts "Achieve frequency $$freq MHz phase $$phase degrees jitter $$jitter ps" + |""".stripMargin + }.mkString + + + val aligned = if (c.input.feedback) " CONFIG.USE_PHASE_ALIGNMENT {true} \\\n" else "" + + ElaborationArtefacts.add(s"${moduleName}.vivado.tcl", + s"""create_ip -name clk_wiz -vendor xilinx.com -library ip -module_name \\ + | ${moduleName} -dir $$ipdir -force + |set_property -dict [list \\ + | CONFIG.CLK_IN1_BOARD_INTERFACE {Custom} \\ + | CONFIG.PRIM_SOURCE {No_buffer} \\ + | CONFIG.NUM_OUT_CLKS {${c.req.size.toString}} \\ + | CONFIG.PRIM_IN_FREQ {${c.input.freqMHz.toString}} \\ + | CONFIG.CLKIN1_JITTER_PS {${c.input.jitter}} \\ + |${used}${aligned}${outputs}] [get_ips ${moduleName}] + |set mult [get_property CONFIG.MMCM_CLKFBOUT_MULT_F [get_ips ${moduleName}]] + |set div1 [get_property CONFIG.MMCM_DIVCLK_DIVIDE [get_ips ${moduleName}]] + |${checks}""".stripMargin) +} + +//------------------------------------------------------------------------- +// vc707reset +//------------------------------------------------------------------------- + +class vc707reset() extends BlackBox +{ + val io = new Bundle{ + val areset = Bool(INPUT) + val clock1 = Clock(INPUT) + val reset1 = Bool(OUTPUT) + val clock2 = Clock(INPUT) + val reset2 = Bool(OUTPUT) + val clock3 = Clock(INPUT) + val reset3 = Bool(OUTPUT) + val clock4 = Clock(INPUT) + val reset4 = Bool(OUTPUT) + } +} + +//------------------------------------------------------------------------- +// vcu118_sys_clock_mmcm +//------------------------------------------------------------------------- +//IP : xilinx mmcm with "NO_BUFFER" input clock + +class vcu118_sys_clock_mmcm0 extends BlackBox { + val io = new Bundle { + val clk_in1 = Bool(INPUT) + val clk_out1 = Clock(OUTPUT) + val clk_out2 = Clock(OUTPUT) + val clk_out3 = Clock(OUTPUT) + val clk_out4 = Clock(OUTPUT) + val clk_out5 = Clock(OUTPUT) + val clk_out6 = Clock(OUTPUT) + val clk_out7 = Clock(OUTPUT) + val reset = Bool(INPUT) + val locked = Bool(OUTPUT) + } + + ElaborationArtefacts.add( + "vcu118_sys_clock_mmcm0.vivado.tcl", + """create_ip -name clk_wiz -vendor xilinx.com -library ip -module_name vcu118_sys_clock_mmcm0 -dir $ipdir -force + set_property -dict [list \ + CONFIG.CLK_IN1_BOARD_INTERFACE {Custom} \ + CONFIG.PRIM_SOURCE {No_buffer} \ + CONFIG.CLKOUT2_USED {true} \ + CONFIG.CLKOUT3_USED {true} \ + CONFIG.CLKOUT4_USED {true} \ + CONFIG.CLKOUT5_USED {true} \ + CONFIG.CLKOUT6_USED {true} \ + CONFIG.CLKOUT7_USED {true} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {12.5} \ + CONFIG.CLKOUT2_REQUESTED_OUT_FREQ {25} \ + CONFIG.CLKOUT3_REQUESTED_OUT_FREQ {37.5} \ + CONFIG.CLKOUT4_REQUESTED_OUT_FREQ {50} \ + CONFIG.CLKOUT5_REQUESTED_OUT_FREQ {100} \ + CONFIG.CLKOUT6_REQUESTED_OUT_FREQ {150.000} \ + CONFIG.CLKOUT7_REQUESTED_OUT_FREQ {75} \ + CONFIG.CLK_IN1_BOARD_INTERFACE {Custom} \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKIN1_JITTER_PS {50.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {5} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {24.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {96.000} \ + CONFIG.MMCM_CLKOUT1_DIVIDE {48} \ + CONFIG.MMCM_CLKOUT2_DIVIDE {32} \ + CONFIG.MMCM_CLKOUT3_DIVIDE {24} \ + CONFIG.MMCM_CLKOUT4_DIVIDE {12} \ + CONFIG.MMCM_CLKOUT5_DIVIDE {8} \ + CONFIG.MMCM_CLKOUT6_DIVIDE {16} \ + CONFIG.NUM_OUT_CLKS {7} \ + CONFIG.CLKOUT1_JITTER {213.008} \ + CONFIG.CLKOUT1_PHASE_ERROR {154.678} \ + CONFIG.CLKOUT2_JITTER {179.547} \ + CONFIG.CLKOUT2_PHASE_ERROR {154.678} \ + CONFIG.CLKOUT3_JITTER {164.187} \ + CONFIG.CLKOUT3_PHASE_ERROR {154.678} \ + CONFIG.CLKOUT4_JITTER {154.688} \ + CONFIG.CLKOUT4_PHASE_ERROR {154.678} \ + CONFIG.CLKOUT5_JITTER {135.165} \ + CONFIG.CLKOUT5_PHASE_ERROR {154.678} \ + CONFIG.CLKOUT6_JITTER {126.046} \ + CONFIG.CLKOUT6_PHASE_ERROR {154.678} \ + CONFIG.CLKOUT7_JITTER {142.781} \ + CONFIG.CLKOUT7_PHASE_ERROR {154.678}] [get_ips vcu118_sys_clock_mmcm0] """ + ) +} + +class vcu118_sys_clock_mmcm1 extends BlackBox { + val io = new Bundle { + val clk_in1 = Bool(INPUT) + val clk_out1 = Clock(OUTPUT) + val clk_out2 = Clock(OUTPUT) + val reset = Bool(INPUT) + val locked = Bool(OUTPUT) + } + + ElaborationArtefacts.add( + "vcu118_sys_clock_mmcm1.vivado.tcl", + """create_ip -name clk_wiz -vendor xilinx.com -library ip -module_name vcu118_sys_clock_mmcm1 -dir $ipdir -force + set_property -dict [list \ + CONFIG.CLK_IN1_BOARD_INTERFACE {Custom} \ + CONFIG.PRIM_SOURCE {No_buffer} \ + CONFIG.CLKOUT2_USED {true} \ + CONFIG.CLKOUT3_USED {false} \ + CONFIG.CLKOUT4_USED {false} \ + CONFIG.CLKOUT5_USED {false} \ + CONFIG.CLKOUT6_USED {false} \ + CONFIG.CLKOUT7_USED {false} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {32.5} \ + CONFIG.CLKOUT2_REQUESTED_OUT_FREQ {65} \ + CONFIG.CLK_IN1_BOARD_INTERFACE {Custom} \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKIN1_JITTER_PS {50.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {25} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {117.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {36.000} \ + CONFIG.MMCM_CLKOUT1_DIVIDE {18} \ + CONFIG.MMCM_CLKOUT2_DIVIDE {1} \ + CONFIG.MMCM_CLKOUT3_DIVIDE {1} \ + CONFIG.MMCM_CLKOUT4_DIVIDE {1} \ + CONFIG.MMCM_CLKOUT5_DIVIDE {1} \ + CONFIG.MMCM_CLKOUT6_DIVIDE {1} \ + CONFIG.NUM_OUT_CLKS {2} \ + CONFIG.CLKOUT1_JITTER {257.594} \ + CONFIG.CLKOUT1_PHASE_ERROR {366.693} \ + CONFIG.CLKOUT2_JITTER {232.023} \ + CONFIG.CLKOUT2_PHASE_ERROR {366.693}] \ + [get_ips vcu118_sys_clock_mmcm1] """ + ) +} + +//------------------------------------------------------------------------- +// vcu118reset +//------------------------------------------------------------------------- + +class vcu118reset() extends BlackBox +{ + val io = new Bundle{ + val areset = Bool(INPUT) + val clock1 = Clock(INPUT) + val reset1 = Bool(OUTPUT) + val clock2 = Clock(INPUT) + val reset2 = Bool(OUTPUT) + val clock3 = Clock(INPUT) + val reset3 = Bool(OUTPUT) + val clock4 = Clock(INPUT) + val reset4 = Bool(OUTPUT) + } +} + +//------------------------------------------------------------------------- +// sdio_spi_bridge +//------------------------------------------------------------------------- + +class sdio_spi_bridge() extends BlackBox +{ + val io = new Bundle{ + val clk = Clock(INPUT) + val reset = Bool(INPUT) + val sd_cmd = Analog(1.W) + val sd_dat = Analog(4.W) + val spi_sck = Bool(INPUT) + val spi_cs = Bool(INPUT) + val spi_dq_o = Bits(INPUT,4) + val spi_dq_i = Bits(OUTPUT,4) + } +} diff --git a/fpga-shells/src/main/scala/ip/xilinx/ibufds_gte2/ibufds_gte2.scala b/fpga-shells/src/main/scala/ip/xilinx/ibufds_gte2/ibufds_gte2.scala new file mode 100644 index 00000000..90f58f56 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/xilinx/ibufds_gte2/ibufds_gte2.scala @@ -0,0 +1,18 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.xilinx.ibufds_gte2 + +import Chisel._ + +//IP : xilinx unisim IBUFDS_GTE2 +//Differential Signaling Input Buffer +//unparameterized + +class IBUFDS_GTE2 extends BlackBox { + val io = new Bundle { + val O = Bool(OUTPUT) + val ODIV2 = Bool(OUTPUT) + val CEB = Bool(INPUT) + val I = Bool(INPUT) + val IB = Bool(INPUT) + } +} diff --git a/fpga-shells/src/main/scala/ip/xilinx/vc707axi_to_pcie_x1/vc707axi_to_pcie_x1.scala b/fpga-shells/src/main/scala/ip/xilinx/vc707axi_to_pcie_x1/vc707axi_to_pcie_x1.scala new file mode 100644 index 00000000..18842387 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/xilinx/vc707axi_to_pcie_x1/vc707axi_to_pcie_x1.scala @@ -0,0 +1,491 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.xilinx.vc707axi_to_pcie_x1 + +import Chisel._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.amba.axi4._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.util.{ElaborationArtefacts} + +// IP VLNV: xilinx.com:customize_ip:vc707pcietoaxi:1.0 +// Black Box +// Signals named _exactly_ as per Vivado generated verilog +// s : -{lock, cache, prot, qos} + +trait VC707AXIToPCIeX1IOSerial extends Bundle { + //serial external pins + val pci_exp_txp = Bool(OUTPUT) + val pci_exp_txn = Bool(OUTPUT) + val pci_exp_rxp = Bool(INPUT) + val pci_exp_rxn = Bool(INPUT) +} + +trait VC707AXIToPCIeX1IOClocksReset extends Bundle { + //clock, reset, control + val axi_aresetn = Bool(INPUT) + val axi_aclk_out = Clock(OUTPUT) + val axi_ctl_aclk_out = Clock(OUTPUT) + val mmcm_lock = Bool(OUTPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class vc707axi_to_pcie_x1() extends BlackBox +{ + val io = new Bundle with VC707AXIToPCIeX1IOSerial + with VC707AXIToPCIeX1IOClocksReset { + //refclk + val REFCLK = Bool(INPUT) + + //clock, reset, control + val INTX_MSI_Request = Bool(INPUT) + val INTX_MSI_Grant = Bool(OUTPUT) + val MSI_enable = Bool(OUTPUT) + val MSI_Vector_Num = Bits(INPUT,5) + val MSI_Vector_Width = Bits(OUTPUT,3) + + //interrupt + val interrupt_out = Bool(OUTPUT) + + //axi slave + //-{lock, cache, prot, qos} + //slave interface write address + val s_axi_awid = Bits(INPUT,4) + val s_axi_awaddr = Bits(INPUT,32) + val s_axi_awregion = Bits(INPUT,4) + val s_axi_awlen = Bits(INPUT,8) + val s_axi_awsize = Bits(INPUT,3) + val s_axi_awburst = Bits(INPUT,2) + //val s_axi_awlock = Bool(INPUT) + //val s_axi_awcache = Bits(INPUT,4) + //val s_axi_awprot = Bits(INPUT,3) + //val s_axi_awqos = Bits(INPUT,4) + val s_axi_awvalid = Bool(INPUT) + val s_axi_awready = Bool(OUTPUT) + //slave interface write data + val s_axi_wdata = Bits(INPUT,64) + val s_axi_wstrb = Bits(INPUT,8) + val s_axi_wlast = Bool(INPUT) + val s_axi_wvalid = Bool(INPUT) + val s_axi_wready = Bool(OUTPUT) + //slave interface write response + val s_axi_bready = Bool(INPUT) + val s_axi_bid = Bits(OUTPUT,4) + val s_axi_bresp = Bits(OUTPUT,2) + val s_axi_bvalid = Bool(OUTPUT) + //slave interface read address + val s_axi_arid = Bits(INPUT,4) + val s_axi_araddr = Bits(INPUT,32) + val s_axi_arregion = Bits(INPUT,4) + val s_axi_arlen = Bits(INPUT,8) + val s_axi_arsize = Bits(INPUT,3) + val s_axi_arburst = Bits(INPUT,2) + //val s_axi_arlock = Bits(INPUT,1) + //val s_axi_arcache = Bits(INPUT,4) + //val s_axi_arprot = Bits(INPUT,3) + //val s_axi_arqos = Bits(INPUT,4) + val s_axi_arvalid = Bool(INPUT) + val s_axi_arready = Bool(OUTPUT) + //slave interface read data + val s_axi_rready = Bool(INPUT) + val s_axi_rid = Bits(OUTPUT,4) + val s_axi_rdata = Bits(OUTPUT,64) + val s_axi_rresp = Bits(OUTPUT,2) + val s_axi_rlast = Bool(OUTPUT) + val s_axi_rvalid = Bool(OUTPUT) + + //axi master + //-{id,region,qos} + //slave interface write address ports + //val m_axi_awid = Bits(OUTPUT,4) + val m_axi_awaddr = Bits(OUTPUT,32) + //val m_axi_awregion = Bits(OUTPUT,4) + val m_axi_awlen = Bits(OUTPUT,8) + val m_axi_awsize = Bits(OUTPUT,3) + val m_axi_awburst = Bits(OUTPUT,2) + val m_axi_awlock = Bool(OUTPUT) + val m_axi_awcache = Bits(OUTPUT,4) + val m_axi_awprot = Bits(OUTPUT,3) + //val m_axi_awqos = Bits(OUTPUT,4) + val m_axi_awvalid = Bool(OUTPUT) + val m_axi_awready = Bool(INPUT) + //slave interface write data ports + val m_axi_wdata = Bits(OUTPUT,64) + val m_axi_wstrb = Bits(OUTPUT,8) + val m_axi_wlast = Bool(OUTPUT) + val m_axi_wvalid = Bool(OUTPUT) + val m_axi_wready = Bool(INPUT) + //slave interface write response ports + val m_axi_bready = Bool(OUTPUT) + //val m_axi_bid = Bits(INPUT,4) + val m_axi_bresp = Bits(INPUT,2) + val m_axi_bvalid = Bool(INPUT) + //slave interface read address ports + //val m_axi_arid = Bits(OUTPUT,4) + val m_axi_araddr = Bits(OUTPUT,32) + //val m_axi_arregion = Bits(OUTPUT,4) + val m_axi_arlen = Bits(OUTPUT,8) + val m_axi_arsize = Bits(OUTPUT,3) + val m_axi_arburst = Bits(OUTPUT,2) + val m_axi_arlock = Bits(OUTPUT,1) + val m_axi_arcache = Bits(OUTPUT,4) + val m_axi_arprot = Bits(OUTPUT,3) + //val m_axi_arqos = Bits(OUTPUT,4) + val m_axi_arvalid = Bool(OUTPUT) + val m_axi_arready = Bool(INPUT) + //slave interface read data ports + val m_axi_rready = Bool(OUTPUT) + //val m_axi_rid = Bits(INPUT,4) + val m_axi_rdata = Bits(INPUT,64) + val m_axi_rresp = Bits(INPUT,2) + val m_axi_rlast = Bool(INPUT) + val m_axi_rvalid = Bool(INPUT) + + //axi lite slave for control + val s_axi_ctl_awaddr = Bits(INPUT,32) + val s_axi_ctl_awvalid = Bool(INPUT) + val s_axi_ctl_awready = Bool(OUTPUT) + val s_axi_ctl_wdata = Bits(INPUT,32) + val s_axi_ctl_wstrb = Bits(INPUT,4) + val s_axi_ctl_wvalid = Bool(INPUT) + val s_axi_ctl_wready = Bool(OUTPUT) + val s_axi_ctl_bresp = Bits(OUTPUT,2) + val s_axi_ctl_bvalid = Bool(OUTPUT) + val s_axi_ctl_bready = Bool(INPUT) + val s_axi_ctl_araddr = Bits(INPUT,32) + val s_axi_ctl_arvalid = Bool(INPUT) + val s_axi_ctl_arready = Bool(OUTPUT) + val s_axi_ctl_rdata = Bits(OUTPUT,32) + val s_axi_ctl_rresp = Bits(OUTPUT,2) + val s_axi_ctl_rvalid = Bool(OUTPUT) + val s_axi_ctl_rready = Bool(INPUT) + } +} +//scalastyle:off + +//wrap vc707_axi_to_pcie_x1 black box in Nasti Bundles + +class VC707AXIToPCIeX1(implicit p:Parameters) extends LazyModule +{ + val device = new SimpleDevice("pci", Seq("xlnx,axi-pcie-host-1.00.a")) { + override def describe(resources: ResourceBindings): Description = { + val Description(name, mapping) = super.describe(resources) + val intc = "pcie_intc" + def ofInt(x: Int) = Seq(ResourceInt(BigInt(x))) + def ofMap(x: Int) = Seq(0, 0, 0, x).flatMap(ofInt) ++ Seq(ResourceReference(intc)) ++ ofInt(x) + val extra = Map( + "#address-cells" -> ofInt(3), + "#size-cells" -> ofInt(2), + "#interrupt-cells" -> ofInt(1), + "device_type" -> Seq(ResourceString("pci")), + "interrupt-map-mask" -> Seq(0, 0, 0, 7).flatMap(ofInt), + "interrupt-map" -> Seq(1, 2, 3, 4).flatMap(ofMap), + "ranges" -> resources("ranges").map(x => + (x: @unchecked) match { case Binding(_, ResourceAddress(address, perms)) => + ResourceMapping(address, BigInt(0x02000000) << 64, perms) }), + "interrupt-controller" -> Seq(ResourceMap(labels = Seq(intc), value = Map( + "interrupt-controller" -> Nil, + "#address-cells" -> ofInt(0), + "#interrupt-cells" -> ofInt(1))))) + Description(name, mapping ++ extra) + } + } + + val slave = AXI4SlaveNode(Seq(AXI4SlavePortParameters( + slaves = Seq(AXI4SlaveParameters( + address = List(AddressSet(0x40000000L, 0x1fffffffL)), + resources = Seq(Resource(device, "ranges")), + executable = true, + supportsWrite = TransferSizes(1, 128), + supportsRead = TransferSizes(1, 128))), + beatBytes = 8))) + + val control = AXI4SlaveNode(Seq(AXI4SlavePortParameters( + slaves = Seq(AXI4SlaveParameters( + address = List(AddressSet(0x2000000000L, 0x3ffffffL)), // when truncated to 32-bits, is 0 + resources = device.reg("control"), + supportsWrite = TransferSizes(1, 4), + supportsRead = TransferSizes(1, 4), + interleavedId = Some(0))), // AXI4-Lite never interleaves responses + beatBytes = 4))) + + val master = AXI4MasterNode(Seq(AXI4MasterPortParameters( + masters = Seq(AXI4MasterParameters( + name = "VC707 PCIe", + id = IdRange(0, 1), + aligned = false))))) + + val intnode = IntSourceNode(IntSourcePortSimple(resources = device.int)) + + lazy val module = new LazyModuleImp(this) { + // The master on the control port must be AXI-lite + require (control.edges.in(0).master.endId == 1) + // Must have exactly the right number of idBits + require (slave.edges.in(0).bundle.idBits == 4) + + class VC707AXIToPCIeX1IOBundle extends Bundle with VC707AXIToPCIeX1IOSerial + with VC707AXIToPCIeX1IOClocksReset; + + val io = IO(new Bundle { + val port = new VC707AXIToPCIeX1IOBundle + val REFCLK = Bool(INPUT) + }) + + val blackbox = Module(new vc707axi_to_pcie_x1) + + val (s, _) = slave.in(0) + val (c, _) = control.in(0) + val (m, _) = master.out(0) + val (i, _) = intnode.out(0) + + //to top level + blackbox.io.axi_aresetn := io.port.axi_aresetn + io.port.axi_aclk_out := blackbox.io.axi_aclk_out + io.port.axi_ctl_aclk_out := blackbox.io.axi_ctl_aclk_out + io.port.mmcm_lock := blackbox.io.mmcm_lock + io.port.pci_exp_txp := blackbox.io.pci_exp_txp + io.port.pci_exp_txn := blackbox.io.pci_exp_txn + blackbox.io.pci_exp_rxp := io.port.pci_exp_rxp + blackbox.io.pci_exp_rxn := io.port.pci_exp_rxn + i(0) := blackbox.io.interrupt_out + blackbox.io.REFCLK := io.REFCLK + + //s + //AXI4 signals ordered as per AXI4 Specification (Release D) Section A.2 + //-{lock, cache, prot, qos} + //-{aclk, aresetn, awuser, wid, wuser, buser, ruser} + //global signals + //aclk := + //aresetn := + //slave interface write address + blackbox.io.s_axi_awid := s.aw.bits.id + blackbox.io.s_axi_awaddr := s.aw.bits.addr + blackbox.io.s_axi_awlen := s.aw.bits.len + blackbox.io.s_axi_awsize := s.aw.bits.size + blackbox.io.s_axi_awburst := s.aw.bits.burst + //blackbox.io.s_axi_awlock := s.aw.bits.lock + //blackbox.io.s_axi_awcache := s.aw.bits.cache + //blackbox.io.s_axi_awprot := s.aw.bits.prot + //blackbox.io.s_axi_awqos := s.aw.bits.qos + blackbox.io.s_axi_awregion := UInt(0) + //blackbox.io.awuser := s.aw.bits.user + blackbox.io.s_axi_awvalid := s.aw.valid + s.aw.ready := blackbox.io.s_axi_awready + //slave interface write data ports + //blackbox.io.s_axi_wid := s.w.bits.id + blackbox.io.s_axi_wdata := s.w.bits.data + blackbox.io.s_axi_wstrb := s.w.bits.strb + blackbox.io.s_axi_wlast := s.w.bits.last + //blackbox.io.s_axi_wuser := s.w.bits.user + blackbox.io.s_axi_wvalid := s.w.valid + s.w.ready := blackbox.io.s_axi_wready + //slave interface write response + s.b.bits.id := blackbox.io.s_axi_bid + s.b.bits.resp := blackbox.io.s_axi_bresp + //s.b.bits.user := blackbox.io.s_axi_buser + s.b.valid := blackbox.io.s_axi_bvalid + blackbox.io.s_axi_bready := s.b.ready + //slave AXI interface read address ports + blackbox.io.s_axi_arid := s.ar.bits.id + blackbox.io.s_axi_araddr := s.ar.bits.addr + blackbox.io.s_axi_arlen := s.ar.bits.len + blackbox.io.s_axi_arsize := s.ar.bits.size + blackbox.io.s_axi_arburst := s.ar.bits.burst + //blackbox.io.s_axi_arlock := s.ar.bits.lock + //blackbox.io.s_axi_arcache := s.ar.bits.cache + //blackbox.io.s_axi_arprot := s.ar.bits.prot + //blackbox.io.s_axi_arqos := s.ar.bits.qos + blackbox.io.s_axi_arregion := UInt(0) + //blackbox.io.s_axi_aruser := s.ar.bits.user + blackbox.io.s_axi_arvalid := s.ar.valid + s.ar.ready := blackbox.io.s_axi_arready + //slave AXI interface read data ports + s.r.bits.id := blackbox.io.s_axi_rid + s.r.bits.data := blackbox.io.s_axi_rdata + s.r.bits.resp := blackbox.io.s_axi_rresp + s.r.bits.last := blackbox.io.s_axi_rlast + //s.r.bits.ruser := blackbox.io.s_axi_ruser + s.r.valid := blackbox.io.s_axi_rvalid + blackbox.io.s_axi_rready := s.r.ready + + //ctl + //axi-lite slave interface write address + blackbox.io.s_axi_ctl_awaddr := c.aw.bits.addr + blackbox.io.s_axi_ctl_awvalid := c.aw.valid + c.aw.ready := blackbox.io.s_axi_ctl_awready + //axi-lite slave interface write data ports + blackbox.io.s_axi_ctl_wdata := c.w.bits.data + blackbox.io.s_axi_ctl_wstrb := c.w.bits.strb + blackbox.io.s_axi_ctl_wvalid := c.w.valid + c.w.ready := blackbox.io.s_axi_ctl_wready + //axi-lite slave interface write response + blackbox.io.s_axi_ctl_bready := c.b.ready + c.b.bits.id := UInt(0) + c.b.bits.resp := blackbox.io.s_axi_ctl_bresp + c.b.valid := blackbox.io.s_axi_ctl_bvalid + //axi-lite slave AXI interface read address ports + blackbox.io.s_axi_ctl_araddr := c.ar.bits.addr + blackbox.io.s_axi_ctl_arvalid := c.ar.valid + c.ar.ready := blackbox.io.s_axi_ctl_arready + //slave AXI interface read data ports + blackbox.io.s_axi_ctl_rready := c.r.ready + c.r.bits.id := UInt(0) + c.r.bits.data := blackbox.io.s_axi_ctl_rdata + c.r.bits.resp := blackbox.io.s_axi_ctl_rresp + c.r.bits.last := Bool(true) + c.r.valid := blackbox.io.s_axi_ctl_rvalid + + //m + //AXI4 signals ordered per AXI4 Specification (Release D) Section A.2 + //-{id,region,qos} + //-{aclk, aresetn, awuser, wid, wuser, buser, ruser} + //global signals + //aclk := + //aresetn := + //master interface write address + m.aw.bits.id := UInt(0) + m.aw.bits.addr := blackbox.io.m_axi_awaddr + m.aw.bits.len := blackbox.io.m_axi_awlen + m.aw.bits.size := blackbox.io.m_axi_awsize + m.aw.bits.burst := blackbox.io.m_axi_awburst + m.aw.bits.lock := blackbox.io.m_axi_awlock + m.aw.bits.cache := blackbox.io.m_axi_awcache + m.aw.bits.prot := blackbox.io.m_axi_awprot + m.aw.bits.qos := UInt(0) + //m.aw.bits.region := blackbox.io.m_axi_awregion + //m.aw.bits.user := blackbox.io.m_axi_awuser + m.aw.valid := blackbox.io.m_axi_awvalid + blackbox.io.m_axi_awready := m.aw.ready + + //master interface write data ports + m.w.bits.data := blackbox.io.m_axi_wdata + m.w.bits.strb := blackbox.io.m_axi_wstrb + m.w.bits.last := blackbox.io.m_axi_wlast + //m.w.bits.user := blackbox.io.m_axi_wuser + m.w.valid := blackbox.io.m_axi_wvalid + blackbox.io.m_axi_wready := m.w.ready + + //master interface write response + //blackbox.io.m_axi_bid := m.b.bits.id + blackbox.io.m_axi_bresp := m.b.bits.resp + //blackbox.io.m_axi_buser := m.b.bits.user + blackbox.io.m_axi_bvalid := m.b.valid + m.b.ready := blackbox.io.m_axi_bready + + //master AXI interface read address ports + m.ar.bits.id := UInt(0) + m.ar.bits.addr := blackbox.io.m_axi_araddr + m.ar.bits.len := blackbox.io.m_axi_arlen + m.ar.bits.size := blackbox.io.m_axi_arsize + m.ar.bits.burst := blackbox.io.m_axi_arburst + m.ar.bits.lock := blackbox.io.m_axi_arlock + m.ar.bits.cache := blackbox.io.m_axi_arcache + m.ar.bits.prot := blackbox.io.m_axi_arprot + m.ar.bits.qos := UInt(0) + //m.ar.bits.region := blackbox.io.m_axi_arregion + //m.ar.bits.user := blackbox.io.s_axi_aruser + m.ar.valid := blackbox.io.m_axi_arvalid + blackbox.io.m_axi_arready := m.ar.ready + + //master AXI interface read data ports + //blackbox.io.m_axi_rid := m.r.bits.id + blackbox.io.m_axi_rdata := m.r.bits.data + blackbox.io.m_axi_rresp := m.r.bits.resp + blackbox.io.m_axi_rlast := m.r.bits.last + //blackbox.io.s_axi_ruser := s.bits.ruser + blackbox.io.m_axi_rvalid := m.r.valid + m.r.ready := blackbox.io.m_axi_rready + } + + ElaborationArtefacts.add( + "vc707axi_to_pcie_x1.vivado.tcl", + """ + create_ip -vendor xilinx.com -library ip -version 2.8 -name axi_pcie -module_name vc707axi_to_pcie_x1 -dir $ipdir -force + set_property -dict [list \ + CONFIG.AXIBAR2PCIEBAR_0 {0x40000000} \ + CONFIG.AXIBAR2PCIEBAR_1 {0x00000000} \ + CONFIG.AXIBAR2PCIEBAR_2 {0x00000000} \ + CONFIG.AXIBAR2PCIEBAR_3 {0x00000000} \ + CONFIG.AXIBAR2PCIEBAR_4 {0x00000000} \ + CONFIG.AXIBAR2PCIEBAR_5 {0x00000000} \ + CONFIG.AXIBAR_0 {0x40000000} \ + CONFIG.AXIBAR_1 {0xFFFFFFFF} \ + CONFIG.AXIBAR_2 {0xFFFFFFFF} \ + CONFIG.AXIBAR_3 {0xFFFFFFFF} \ + CONFIG.AXIBAR_4 {0xFFFFFFFF} \ + CONFIG.AXIBAR_5 {0xFFFFFFFF} \ + CONFIG.AXIBAR_AS_0 {true} \ + CONFIG.AXIBAR_AS_1 {false} \ + CONFIG.AXIBAR_AS_2 {false} \ + CONFIG.AXIBAR_AS_3 {false} \ + CONFIG.AXIBAR_AS_4 {false} \ + CONFIG.AXIBAR_AS_5 {false} \ + CONFIG.AXIBAR_HIGHADDR_0 {0x5FFFFFFF} \ + CONFIG.AXIBAR_HIGHADDR_1 {0x00000000} \ + CONFIG.AXIBAR_HIGHADDR_2 {0x00000000} \ + CONFIG.AXIBAR_HIGHADDR_3 {0x00000000} \ + CONFIG.AXIBAR_HIGHADDR_4 {0x00000000} \ + CONFIG.AXIBAR_HIGHADDR_5 {0x00000000} \ + CONFIG.AXIBAR_NUM {1} \ + CONFIG.BAR0_ENABLED {true} \ + CONFIG.BAR0_SCALE {Gigabytes} \ + CONFIG.BAR0_SIZE {4} \ + CONFIG.BAR0_TYPE {Memory} \ + CONFIG.BAR1_ENABLED {false} \ + CONFIG.BAR1_SCALE {N/A} \ + CONFIG.BAR1_SIZE {8} \ + CONFIG.BAR1_TYPE {N/A} \ + CONFIG.BAR2_ENABLED {false} \ + CONFIG.BAR2_SCALE {N/A} \ + CONFIG.BAR2_SIZE {8} \ + CONFIG.BAR2_TYPE {N/A} \ + CONFIG.BAR_64BIT {true} \ + CONFIG.BASEADDR {0x00000000} \ + CONFIG.BASE_CLASS_MENU {Bridge_device} \ + CONFIG.CLASS_CODE {0x060400} \ + CONFIG.COMP_TIMEOUT {50ms} \ + CONFIG.Component_Name {design_1_axi_pcie_1_0} \ + CONFIG.DEVICE_ID {0x7111} \ + CONFIG.ENABLE_CLASS_CODE {true} \ + CONFIG.HIGHADDR {0x03FFFFFF} \ + CONFIG.INCLUDE_BAROFFSET_REG {true} \ + CONFIG.INCLUDE_RC {Root_Port_of_PCI_Express_Root_Complex} \ + CONFIG.INTERRUPT_PIN {false} \ + CONFIG.MAX_LINK_SPEED {2.5_GT/s} \ + CONFIG.MSI_DECODE_ENABLED {true} \ + CONFIG.M_AXI_ADDR_WIDTH {32} \ + CONFIG.M_AXI_DATA_WIDTH {64} \ + CONFIG.NO_OF_LANES {X1} \ + CONFIG.NUM_MSI_REQ {0} \ + CONFIG.PCIEBAR2AXIBAR_0_SEC {1} \ + CONFIG.PCIEBAR2AXIBAR_0 {0x00000000} \ + CONFIG.PCIEBAR2AXIBAR_1 {0xFFFFFFFF} \ + CONFIG.PCIEBAR2AXIBAR_1_SEC {1} \ + CONFIG.PCIEBAR2AXIBAR_2 {0xFFFFFFFF} \ + CONFIG.PCIEBAR2AXIBAR_2_SEC {1} \ + CONFIG.PCIE_BLK_LOCN {X1Y1} \ + CONFIG.PCIE_USE_MODE {GES_and_Production} \ + CONFIG.REF_CLK_FREQ {100_MHz} \ + CONFIG.REV_ID {0x00} \ + CONFIG.SLOT_CLOCK_CONFIG {true} \ + CONFIG.SUBSYSTEM_ID {0x0007} \ + CONFIG.SUBSYSTEM_VENDOR_ID {0x10EE} \ + CONFIG.SUB_CLASS_INTERFACE_MENU {Host_bridge} \ + CONFIG.S_AXI_ADDR_WIDTH {32} \ + CONFIG.S_AXI_DATA_WIDTH {64} \ + CONFIG.S_AXI_ID_WIDTH {4} \ + CONFIG.S_AXI_SUPPORTS_NARROW_BURST {false} \ + CONFIG.VENDOR_ID {0x10EE} \ + CONFIG.XLNX_REF_BOARD {None} \ + CONFIG.axi_aclk_loopback {false} \ + CONFIG.en_ext_ch_gt_drp {false} \ + CONFIG.en_ext_clk {false} \ + CONFIG.en_ext_gt_common {false} \ + CONFIG.en_ext_pipe_interface {false} \ + CONFIG.en_transceiver_status_ports {false} \ + CONFIG.no_slv_err {false} \ + CONFIG.rp_bar_hide {true} \ + CONFIG.shared_logic_in_core {false} ] [get_ips vc707axi_to_pcie_x1]""" + ) +} diff --git a/fpga-shells/src/main/scala/ip/xilinx/vc707mig/vc707mig.scala b/fpga-shells/src/main/scala/ip/xilinx/vc707mig/vc707mig.scala new file mode 100644 index 00000000..d5d58ab4 --- /dev/null +++ b/fpga-shells/src/main/scala/ip/xilinx/vc707mig/vc707mig.scala @@ -0,0 +1,534 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.xilinx.vc707mig + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ + +// IP VLNV: xilinx.com:customize_ip:vc707mig:1.0 +// Black Box + +class VC707MIGIODDR(depth : BigInt) extends GenericParameterizedBundle(depth) { + require((depth<=0x100000000L),"VC707MIGIODDR supports upto 4GB depth configuraton") + val ddr3_addr = Bits(OUTPUT,if(depth<=0x40000000L) 14 else 16) + val ddr3_ba = Bits(OUTPUT,3) + val ddr3_ras_n = Bool(OUTPUT) + val ddr3_cas_n = Bool(OUTPUT) + val ddr3_we_n = Bool(OUTPUT) + val ddr3_reset_n = Bool(OUTPUT) + val ddr3_ck_p = Bits(OUTPUT,1) + val ddr3_ck_n = Bits(OUTPUT,1) + val ddr3_cke = Bits(OUTPUT,1) + val ddr3_cs_n = Bits(OUTPUT,1) + val ddr3_dm = Bits(OUTPUT,8) + val ddr3_odt = Bits(OUTPUT,1) + + val ddr3_dq = Analog(64.W) + val ddr3_dqs_n = Analog(8.W) + val ddr3_dqs_p = Analog(8.W) +} + +//reused directly in io bundle for sifive.blocks.devices.xilinxvc707mig +trait VC707MIGIOClocksReset extends Bundle { + //inputs + //"NO_BUFFER" clock source (must be connected to IBUF outside of IP) + val sys_clk_i = Bool(INPUT) + //user interface signals + val ui_clk = Clock(OUTPUT) + val ui_clk_sync_rst = Bool(OUTPUT) + val mmcm_locked = Bool(OUTPUT) + val aresetn = Bool(INPUT) + //misc + val init_calib_complete = Bool(OUTPUT) + val sys_rst = Bool(INPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class vc707mig(depth : BigInt)(implicit val p:Parameters) extends BlackBox +{ + require((depth<=0x100000000L),"vc707mig supports upto 4GB depth configuraton") + override def desiredName = if(depth<=0x40000000) "vc707mig1gb" else "vc707mig4gb" + + val io = new VC707MIGIODDR(depth) with VC707MIGIOClocksReset { + // User interface signals + val app_sr_req = Bool(INPUT) + val app_ref_req = Bool(INPUT) + val app_zq_req = Bool(INPUT) + val app_sr_active = Bool(OUTPUT) + val app_ref_ack = Bool(OUTPUT) + val app_zq_ack = Bool(OUTPUT) + //axi_s + //slave interface write address ports + val s_axi_awid = Bits(INPUT,4) + val s_axi_awaddr = Bits(INPUT,if(depth<=0x40000000) 30 else 32) + val s_axi_awlen = Bits(INPUT,8) + val s_axi_awsize = Bits(INPUT,3) + val s_axi_awburst = Bits(INPUT,2) + val s_axi_awlock = Bits(INPUT,1) + val s_axi_awcache = Bits(INPUT,4) + val s_axi_awprot = Bits(INPUT,3) + val s_axi_awqos = Bits(INPUT,4) + val s_axi_awvalid = Bool(INPUT) + val s_axi_awready = Bool(OUTPUT) + //slave interface write data ports + val s_axi_wdata = Bits(INPUT,64) + val s_axi_wstrb = Bits(INPUT,8) + val s_axi_wlast = Bool(INPUT) + val s_axi_wvalid = Bool(INPUT) + val s_axi_wready = Bool(OUTPUT) + //slave interface write response ports + val s_axi_bready = Bool(INPUT) + val s_axi_bid = Bits(OUTPUT,4) + val s_axi_bresp = Bits(OUTPUT,2) + val s_axi_bvalid = Bool(OUTPUT) + //slave interface read address ports + val s_axi_arid = Bits(INPUT,4) + val s_axi_araddr = Bits(INPUT,if(depth<=0x40000000) 30 else 32) + val s_axi_arlen = Bits(INPUT,8) + val s_axi_arsize = Bits(INPUT,3) + val s_axi_arburst = Bits(INPUT,2) + val s_axi_arlock = Bits(INPUT,1) + val s_axi_arcache = Bits(INPUT,4) + val s_axi_arprot = Bits(INPUT,3) + val s_axi_arqos = Bits(INPUT,4) + val s_axi_arvalid = Bool(INPUT) + val s_axi_arready = Bool(OUTPUT) + //slave interface read data ports + val s_axi_rready = Bool(INPUT) + val s_axi_rid = Bits(OUTPUT,4) + val s_axi_rdata = Bits(OUTPUT,64) + val s_axi_rresp = Bits(OUTPUT,2) + val s_axi_rlast = Bool(OUTPUT) + val s_axi_rvalid = Bool(OUTPUT) + //misc + val device_temp = Bits(OUTPUT,12) + } + + val vc707mig1gbprj = """ { + + + vc707mig1gp + 1 + 1 + OFF + 1024 + ON + Enabled + xc7vx485t-ffg1761/-2 + 3.0 + No Buffer + Use System Clock + ACTIVE HIGH + FALSE + 0 + 50 Ohms + 0 + + DDR3_SDRAM/SODIMMs/MT8JTF12864HZ-1G6 + 1250 + 2.0V + 4:1 + 200 + 0 + 800 + 1.000 + 1 + 1 + 1 + 1 + 64 + 1 + 1 + Disabled + Normal + FALSE + + 14 + 10 + 3 + 1.5V + BANK_ROW_COLUMN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 - Fixed + Sequential + 11 + Normal + No + Slow Exit + Enable + RZQ/7 + Disable + Enable + RZQ/6 + 0 + Disabled + Enabled + Output Buffer Enabled + Full Array + 8 + Enabled + Normal + Dynamic ODT off + AXI + + RD_PRI_REG + 30 + 64 + 4 + 0 + + + + } """ + + val vc707mig4gbprj = """ { + + + vc707mig4gb + 1 + 1 + OFF + 1024 + ON + Enabled + xc7vx485t-ffg1761/-2 + 3.0 + No Buffer + Use System Clock + ACTIVE HIGH + FALSE + 0 + 50 Ohms + 0 + + DDR3_SDRAM/SODIMMs/MT8KTF51264HZ-1G9 + 1250 + 2.0V + 4:1 + 200 + 0 + 800 + 1.000 + 1 + 1 + 1 + 1 + 64 + 1 + 1 + Disabled + Normal + FALSE + + 16 + 10 + 3 + 1.5V + BANK_ROW_COLUMN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 - Fixed + Sequential + 11 + Normal + No + Slow Exit + Enable + RZQ/7 + Disable + Enable + RZQ/6 + 0 + Disabled + Enabled + Output Buffer Enabled + Full Array + 8 + Enabled + Normal + Dynamic ODT off + AXI + + RD_PRI_REG + 32 + 64 + 4 + 0 + + + +}""" + + val migprj = if(depth<=0x40000000) vc707mig1gbprj else vc707mig4gbprj + val migprjname = if(depth<=0x40000000) """{/vc707mig1gb.prj}""" else """{/vc707mig4gb.prj}""" + val modulename = if(depth<=0x40000000) """vc707mig1gb""" else """vc707mig4gb""" + + + ElaborationArtefacts.add( + modulename++".vivado.tcl", + """set migprj """++migprj++""" + set migprjfile """++migprjname++""" + set migprjfilepath $ipdir$migprjfile + set fp [open $migprjfilepath w+] + puts $fp $migprj + close $fp + create_ip -vendor xilinx.com -library ip -name mig_7series -module_name """ ++ modulename ++ """ -dir $ipdir -force + set_property CONFIG.XML_INPUT_FILE $migprjfilepath [get_ips """ ++ modulename ++ """] """ + ) + + +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/xilinx/vcu118mig/vcu118mig.scala b/fpga-shells/src/main/scala/ip/xilinx/vcu118mig/vcu118mig.scala new file mode 100644 index 00000000..1c383fcd --- /dev/null +++ b/fpga-shells/src/main/scala/ip/xilinx/vcu118mig/vcu118mig.scala @@ -0,0 +1,179 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.xilinx.vcu118mig + +import Chisel._ +import chisel3.experimental.{Analog,attach} +import freechips.rocketchip.util.{ElaborationArtefacts} +import freechips.rocketchip.util.GenericParameterizedBundle +import freechips.rocketchip.config._ + +// IP VLNV: xilinx.com:customize_ip:vcu118mig:1.0 +// Black Box + +class VCU118MIGIODDR(depth : BigInt) extends GenericParameterizedBundle(depth) { + require((depth<=0x80000000L),"VCU118MIGIODDR supports upto 2GB depth configuraton") + val c0_ddr4_adr = Bits(OUTPUT,17) + val c0_ddr4_bg = Bits(OUTPUT,1) + val c0_ddr4_ba = Bits(OUTPUT,2) + val c0_ddr4_reset_n = Bool(OUTPUT) + val c0_ddr4_act_n = Bool(OUTPUT) + val c0_ddr4_ck_c = Bits(OUTPUT,1) + val c0_ddr4_ck_t = Bits(OUTPUT,1) + val c0_ddr4_cke = Bits(OUTPUT,1) + val c0_ddr4_cs_n = Bits(OUTPUT,1) + val c0_ddr4_odt = Bits(OUTPUT,1) + + val c0_ddr4_dq = Analog(64.W) + val c0_ddr4_dqs_c = Analog(8.W) + val c0_ddr4_dqs_t = Analog(8.W) + val c0_ddr4_dm_dbi_n = Analog(8.W) +} + +//reused directly in io bundle for sifive.blocks.devices.xilinxvcu118mig +trait VCU118MIGIOClocksReset extends Bundle { + //inputs + //"NO_BUFFER" clock source (must be connected to IBUF outside of IP) + val c0_sys_clk_i = Bool(INPUT) + //user interface signals + val c0_ddr4_ui_clk = Clock(OUTPUT) + val c0_ddr4_ui_clk_sync_rst = Bool(OUTPUT) + val c0_ddr4_aresetn = Bool(INPUT) + //misc + val c0_init_calib_complete = Bool(OUTPUT) + val sys_rst = Bool(INPUT) +} + +//scalastyle:off +//turn off linter: blackbox name must match verilog module +class vcu118mig(depth : BigInt)(implicit val p:Parameters) extends BlackBox +{ + require((depth<=0x80000000L),"vcu118mig supports upto 2GB depth configuraton") + + val io = new VCU118MIGIODDR(depth) with VCU118MIGIOClocksReset { + //slave interface write address ports + val c0_ddr4_s_axi_awid = Bits(INPUT,4) + val c0_ddr4_s_axi_awaddr = Bits(INPUT,31) + val c0_ddr4_s_axi_awlen = Bits(INPUT,8) + val c0_ddr4_s_axi_awsize = Bits(INPUT,3) + val c0_ddr4_s_axi_awburst = Bits(INPUT,2) + val c0_ddr4_s_axi_awlock = Bits(INPUT,1) + val c0_ddr4_s_axi_awcache = Bits(INPUT,4) + val c0_ddr4_s_axi_awprot = Bits(INPUT,3) + val c0_ddr4_s_axi_awqos = Bits(INPUT,4) + val c0_ddr4_s_axi_awvalid = Bool(INPUT) + val c0_ddr4_s_axi_awready = Bool(OUTPUT) + //slave interface write data ports + val c0_ddr4_s_axi_wdata = Bits(INPUT,64) + val c0_ddr4_s_axi_wstrb = Bits(INPUT,8) + val c0_ddr4_s_axi_wlast = Bool(INPUT) + val c0_ddr4_s_axi_wvalid = Bool(INPUT) + val c0_ddr4_s_axi_wready = Bool(OUTPUT) + //slave interface write response ports + val c0_ddr4_s_axi_bready = Bool(INPUT) + val c0_ddr4_s_axi_bid = Bits(OUTPUT,4) + val c0_ddr4_s_axi_bresp = Bits(OUTPUT,2) + val c0_ddr4_s_axi_bvalid = Bool(OUTPUT) + //slave interface read address ports + val c0_ddr4_s_axi_arid = Bits(INPUT,4) + val c0_ddr4_s_axi_araddr = Bits(INPUT,31) + val c0_ddr4_s_axi_arlen = Bits(INPUT,8) + val c0_ddr4_s_axi_arsize = Bits(INPUT,3) + val c0_ddr4_s_axi_arburst = Bits(INPUT,2) + val c0_ddr4_s_axi_arlock = Bits(INPUT,1) + val c0_ddr4_s_axi_arcache = Bits(INPUT,4) + val c0_ddr4_s_axi_arprot = Bits(INPUT,3) + val c0_ddr4_s_axi_arqos = Bits(INPUT,4) + val c0_ddr4_s_axi_arvalid = Bool(INPUT) + val c0_ddr4_s_axi_arready = Bool(OUTPUT) + //slave interface read data ports + val c0_ddr4_s_axi_rready = Bool(INPUT) + val c0_ddr4_s_axi_rid = Bits(OUTPUT,4) + val c0_ddr4_s_axi_rdata = Bits(OUTPUT,64) + val c0_ddr4_s_axi_rresp = Bits(OUTPUT,2) + val c0_ddr4_s_axi_rlast = Bool(OUTPUT) + val c0_ddr4_s_axi_rvalid = Bool(OUTPUT) + } + + ElaborationArtefacts.add( + "vcu118mig.vivado.tcl", + """ + create_ip -vendor xilinx.com -library ip -version 2.2 -name ddr4 -module_name vcu118mig -dir $ipdir -force + set_property -dict [list \ + CONFIG.AL_SEL {0} \ + CONFIG.C0.ADDR_WIDTH {17} \ + CONFIG.C0.BANK_GROUP_WIDTH {1} \ + CONFIG.C0.CKE_WIDTH {1} \ + CONFIG.C0.CK_WIDTH {1} \ + CONFIG.C0.CS_WIDTH {1} \ + CONFIG.C0.ControllerType {DDR4_SDRAM} \ + CONFIG.C0.DDR4_AUTO_AP_COL_A3 {false} \ + CONFIG.C0.DDR4_AutoPrecharge {false} \ + CONFIG.C0.DDR4_AxiAddressWidth {31} \ + CONFIG.C0.DDR4_AxiArbitrationScheme {RD_PRI_REG} \ + CONFIG.C0.DDR4_AxiDataWidth {64} \ + CONFIG.C0.DDR4_AxiIDWidth {4} \ + CONFIG.C0.DDR4_AxiNarrowBurst {false} \ + CONFIG.C0.DDR4_AxiSelection {true} \ + CONFIG.C0.DDR4_BurstLength {8} \ + CONFIG.C0.DDR4_BurstType {Sequential} \ + CONFIG.C0.DDR4_CLKFBOUT_MULT {8} \ + CONFIG.C0.DDR4_CLKOUT0_DIVIDE {5} \ + CONFIG.C0.DDR4_Capacity {512} \ + CONFIG.C0.DDR4_CasLatency {11} \ + CONFIG.C0.DDR4_CasWriteLatency {9} \ + CONFIG.C0.DDR4_ChipSelect {true} \ + CONFIG.C0.DDR4_Clamshell {false} \ + CONFIG.C0.DDR4_CustomParts {no_file_loaded} \ + CONFIG.C0.DDR4_DIVCLK_DIVIDE {2} \ + CONFIG.C0.DDR4_DataMask {DM_NO_DBI} \ + CONFIG.C0.DDR4_DataWidth {64} \ + CONFIG.C0.DDR4_Ecc {false} \ + CONFIG.C0.DDR4_MCS_ECC {false} \ + CONFIG.C0.DDR4_Mem_Add_Map {ROW_COLUMN_BANK} \ + CONFIG.C0.DDR4_MemoryName {MainMemory} \ + CONFIG.C0.DDR4_MemoryPart {MT40A256M16GE-083E} \ + CONFIG.C0.DDR4_MemoryType {Components} \ + CONFIG.C0.DDR4_MemoryVoltage {1.2V} \ + CONFIG.C0.DDR4_OnDieTermination {RZQ/6} \ + CONFIG.C0.DDR4_Ordering {Normal} \ + CONFIG.C0.DDR4_OutputDriverImpedenceControl {RZQ/7} \ + CONFIG.C0.DDR4_PhyClockRatio {4:1} \ + CONFIG.C0.DDR4_SAVE_RESTORE {false} \ + CONFIG.C0.DDR4_SELF_REFRESH {false} \ + CONFIG.C0.DDR4_Slot {Single} \ + CONFIG.C0.DDR4_Specify_MandD {true} \ + CONFIG.C0.DDR4_TimePeriod {1250} \ + CONFIG.C0.DDR4_UserRefresh_ZQCS {false} \ + CONFIG.C0.DDR4_isCKEShared {false} \ + CONFIG.C0.DDR4_isCustom {false} \ + CONFIG.C0.LR_WIDTH {1} \ + CONFIG.C0.ODT_WIDTH {1} \ + CONFIG.C0.StackHeight {1} \ + CONFIG.C0_CLOCK_BOARD_INTERFACE {Custom} \ + CONFIG.C0_DDR4_BOARD_INTERFACE {Custom} \ + CONFIG.DCI_Cascade {false} \ + CONFIG.DIFF_TERM_SYSCLK {false} \ + CONFIG.Debug_Signal {Disable} \ + CONFIG.Default_Bank_Selections {false} \ + CONFIG.Enable_SysPorts {true} \ + CONFIG.IOPowerReduction {OFF} \ + CONFIG.IO_Power_Reduction {false} \ + CONFIG.IS_FROM_PHY {1} \ + CONFIG.MCS_DBG_EN {false} \ + CONFIG.No_Controller {1} \ + CONFIG.PARTIAL_RECONFIG_FLOW_MIG {false} \ + CONFIG.PING_PONG_PHY {1} \ + CONFIG.Phy_Only {Complete_Memory_Controller} \ + CONFIG.RECONFIG_XSDB_SAVE_RESTORE {false} \ + CONFIG.RESET_BOARD_INTERFACE {Custom} \ + CONFIG.Reference_Clock {Differential} \ + CONFIG.SET_DW_TO_40 {false} \ + CONFIG.System_Clock {No_Buffer} \ + CONFIG.TIMING_3DS {false} \ + CONFIG.TIMING_OP1 {false} \ + CONFIG.TIMING_OP2 {false} \ + ] [get_ips vcu118mig]""" + ) + +} +//scalastyle:on diff --git a/fpga-shells/src/main/scala/ip/xilinx/xdma/xdma.scala b/fpga-shells/src/main/scala/ip/xilinx/xdma/xdma.scala new file mode 100644 index 00000000..ee93f3ee --- /dev/null +++ b/fpga-shells/src/main/scala/ip/xilinx/xdma/xdma.scala @@ -0,0 +1,466 @@ +// See LICENSE for license details. +package sifive.fpgashells.ip.xilinx.xdma + +import chisel3._ +import chisel3.util._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.amba.axi4._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.util.{ElaborationArtefacts} + +trait HasXDMAPads { + def lanes: Int + + val pci_exp_txp = Output(UInt(lanes.W)) + val pci_exp_txn = Output(UInt(lanes.W)) + val pci_exp_rxp = Input(UInt(lanes.W)) + val pci_exp_rxn = Input(UInt(lanes.W)) +} + +trait HasXDMAClocks { + val sys_clk = Input(Clock()) // + val sys_clk_gt = Input(Clock()) // PCIe reference clock IBUFDS_GTE4.O + val sys_rst_n = Input(Bool()) + val axi_aclk = Output(Clock()) + val axi_aresetn = Output(Bool()) +} + +trait HasXDMAJunk { + val cfg_ltssm_state = Output(UInt(6.W)) + val user_lnk_up = Output(Bool()) + val axi_ctl_aresetn = Output(Bool()) // copy of axi_aresetn in RP mode +} + +case class XDMABusParams(idBits: Int, addrBits: Int, dataBytes: Int) +{ + val dataBits = dataBytes*8 +} + +trait HasXDMABus { + def mbus: XDMABusParams + def sbus: XDMABusParams + def slbus: XDMABusParams + + // I + val interrupt_out = Output(Bool()) + val interrupt_out_msi_vec0to31 = Output(Bool()) + val interrupt_out_msi_vec32to63 = Output(Bool()) + + // M.AW + val m_axib_awready = Input(Bool()) + val m_axib_awvalid = Output(Bool()) + val m_axib_awid = Output(UInt(mbus.idBits.W)) + val m_axib_awaddr = Output(UInt(mbus.addrBits.W)) + val m_axib_awlen = Output(UInt(8.W)) + val m_axib_awsize = Output(UInt(3.W)) + val m_axib_awburst = Output(UInt(2.W)) + val m_axib_awprot = Output(UInt(3.W)) + val m_axib_awcache = Output(UInt(4.W)) + val m_axib_awlock = Output(Bool()) + + // M.AR + val m_axib_arready = Input(Bool()) + val m_axib_arvalid = Output(Bool()) + val m_axib_arid = Output(UInt(mbus.idBits.W)) + val m_axib_araddr = Output(UInt(mbus.addrBits.W)) + val m_axib_arlen = Output(UInt(8.W)) + val m_axib_arsize = Output(UInt(3.W)) + val m_axib_arburst = Output(UInt(2.W)) + val m_axib_arprot = Output(UInt(3.W)) + val m_axib_arcache = Output(UInt(4.W)) + val m_axib_arlock = Output(Bool()) + + // M.W + val m_axib_wready = Input(Bool()) + val m_axib_wvalid = Output(Bool()) + val m_axib_wdata = Output(UInt(mbus.dataBits.W)) + val m_axib_wstrb = Output(UInt(mbus.dataBytes.W)) + val m_axib_wlast = Output(Bool()) + + // M.B + val m_axib_bready = Output(Bool()) + val m_axib_bvalid = Input(Bool()) + val m_axib_bid = Input(UInt(mbus.idBits.W)) + val m_axib_bresp = Input(UInt(2.W)) + + // M.R + val m_axib_rready = Output(Bool()) + val m_axib_rvalid = Input(Bool()) + val m_axib_rid = Input(UInt(mbus.idBits.W)) + val m_axib_rdata = Input(UInt(mbus.dataBits.W)) + val m_axib_rresp = Input(UInt(2.W)) + val m_axib_rlast = Input(Bool()) + + // S.AW + val s_axib_awready = Output(Bool()) + val s_axib_awvalid = Input(Bool()) + val s_axib_awid = Input(UInt(sbus.idBits.W)) + val s_axib_awaddr = Input(UInt(sbus.addrBits.W)) + val s_axib_awregion = Input(UInt(4.W)) + val s_axib_awlen = Input(UInt(8.W)) + val s_axib_awsize = Input(UInt(3.W)) + val s_axib_awburst = Input(UInt(2.W)) + + // S.AR + val s_axib_arready = Output(Bool()) + val s_axib_arvalid = Input(Bool()) + val s_axib_arid = Input(UInt(sbus.idBits.W)) + val s_axib_araddr = Input(UInt(sbus.addrBits.W)) + val s_axib_arregion = Input(UInt(4.W)) + val s_axib_arlen = Input(UInt(8.W)) + val s_axib_arsize = Input(UInt(3.W)) + val s_axib_arburst = Input(UInt(2.W)) + + // S.W + val s_axib_wready = Output(Bool()) + val s_axib_wvalid = Input(Bool()) + val s_axib_wdata = Input(UInt(sbus.dataBits.W)) + val s_axib_wstrb = Input(UInt(sbus.dataBytes.W)) + val s_axib_wlast = Input(Bool()) + + // S.B + val s_axib_bready = Input(Bool()) + val s_axib_bvalid = Output(Bool()) + val s_axib_bid = Output(UInt(sbus.idBits.W)) + val s_axib_bresp = Output(UInt(2.W)) + + // S.R + val s_axib_rready = Input(Bool()) + val s_axib_rvalid = Output(Bool()) + val s_axib_rid = Output(UInt(sbus.idBits.W)) + val s_axib_rdata = Output(UInt(sbus.dataBits.W)) + val s_axib_rresp = Output(UInt(2.W)) + val s_axib_rlast = Output(Bool()) + + // SL.AW + val s_axil_awready = Output(Bool()) + val s_axil_awvalid = Input(Bool()) + val s_axil_awaddr = Input(UInt(slbus.addrBits.W)) + val s_axil_awprot = Input(UInt(3.W)) + + // SL.AR + val s_axil_arready = Output(Bool()) + val s_axil_arvalid = Input(Bool()) + val s_axil_araddr = Input(UInt(slbus.addrBits.W)) + val s_axil_arprot = Input(UInt(3.W)) + + // SL.W + val s_axil_wready = Output(Bool()) + val s_axil_wvalid = Input(Bool()) + val s_axil_wdata = Input(UInt(slbus.dataBits.W)) + val s_axil_wstrb = Input(UInt(slbus.dataBytes.W)) + + // SL.B + val s_axil_bready = Input(Bool()) + val s_axil_bvalid = Output(Bool()) + val s_axil_bresp = Output(UInt(2.W)) + + // SL.R + val s_axil_rready = Input(Bool()) + val s_axil_rvalid = Output(Bool()) + val s_axil_rdata = Output(UInt(slbus.dataBits.W)) + val s_axil_rresp = Output(UInt(2.W)) +} + +class XDMABlackBoxIO( + val lanes: Int, + val mbus: XDMABusParams, + val sbus: XDMABusParams, + val slbus: XDMABusParams) extends Bundle + with HasXDMAPads + with HasXDMAClocks + with HasXDMAJunk + with HasXDMABus + +class XDMAPads(val lanes: Int) extends Bundle with HasXDMAPads +class XDMAClocks() extends Bundle with HasXDMAClocks + +case class XDMAParams( + name: String, + location: String, + bars: Seq[AddressSet], + control: BigInt, + lanes: Int = 1, + gen: Int = 3, + addrBits: Int = 64, + mIDBits: Int = 4, + sIDBits: Int = 4) +{ + require (!bars.isEmpty) + require (control >> 32 << 32 == control) + require (lanes >= 1 && lanes <= 16 && isPow2(lanes)) + require (gen >= 1 && gen <= 3) + require (addrBits == 32 || addrBits == 64) + require (mIDBits >= 1 && mIDBits <= 8) + require (sIDBits >= 1 && sIDBits <= 8) + bars.foreach { a => require (a.max >> addrBits == 0) } + + private val bandwidth = lanes * 250 << (gen-1) // MB/s + private val busBytesAt250MHz = bandwidth / 250 + val busBytes = busBytesAt250MHz max 8 + private val minMHz = 250.0 * busBytesAt250MHz / busBytes + val axiMHz = minMHz max 62.5 +} + +class XDMABlackBox(c: XDMAParams) extends BlackBox +{ + override def desiredName = c.name + + val mbus = XDMABusParams(c.mIDBits, c.addrBits, c.busBytes) + val sbus = XDMABusParams(c.sIDBits, c.addrBits, c.busBytes) + val slbus = XDMABusParams(0, 32, 4) + + val io = IO(new XDMABlackBoxIO(c.lanes, mbus, sbus, slbus)) + val pcieGTs = c.gen match { + case 1 => "2.5_GT/s" + case 2 => "5.0_GT/s" + case 3 => "8.0_GT/s" + case _ => "wrong" + } + + // 62.5, 125, 250 (no trailing zeros) + val formatter = new java.text.DecimalFormat("0.###") + val axiMHzStr = formatter.format(c.axiMHz) + + val bars = c.bars.zipWithIndex.map { case (a, i) => + f""" CONFIG.axibar_${i} {0x${a.base}%X} \\ + | CONFIG.axibar_highaddr_${i} {0x${a.max}%X} \\ + | CONFIG.axibar2pciebar_${i} {0x${a.base}%X} \\ + |""".stripMargin + } + + ElaborationArtefacts.add(s"${desiredName}.vivado.tcl", + s"""create_ip -vendor xilinx.com -library ip -version 4.1 -name xdma -module_name ${desiredName} -dir $$ipdir -force + |set_property -dict [list \\ + | CONFIG.functional_mode {AXI_Bridge} \\ + | CONFIG.pcie_blk_locn {${c.location}} \\ + | CONFIG.device_port_type {Root_Port_of_PCI_Express_Root_Complex} \\ + | CONFIG.pf0_bar0_enabled {false} \\ + | CONFIG.pf0_sub_class_interface_menu {PCI_to_PCI_bridge} \\ + | CONFIG.ref_clk_freq {100_MHz} \\ + | CONFIG.pl_link_cap_max_link_width {X${c.lanes}} \\ + | CONFIG.pl_link_cap_max_link_speed {${pcieGTs}} \\ + | CONFIG.msi_rx_pin_en {true} \\ + | CONFIG.axisten_freq {${axiMHzStr}} \\ + | CONFIG.axi_addr_width {${c.addrBits}} \\ + | CONFIG.axi_data_width {${c.busBytes*8}_bit} \\ + | CONFIG.axi_id_width {${c.mIDBits}} \\ + | CONFIG.s_axi_id_width {${c.sIDBits}} \\ + | CONFIG.axibar_num {${c.bars.size}} \\ + |${bars.mkString}] [get_ips ${desiredName}] + |""".stripMargin) +} + +class DiplomaticXDMA(c: XDMAParams)(implicit p:Parameters) extends LazyModule +{ + val device = new SimpleDevice("pci", Seq("xlnx,xdma-host-3.00")) { + override def describe(resources: ResourceBindings): Description = { + val Description(name, mapping) = super.describe(resources) + val intc = s"${c.name}_intc" + def ofInt(x: Int) = Seq(ResourceInt(BigInt(x))) + def ofMap(x: Int) = Seq(0, 0, 0, x).flatMap(ofInt) ++ Seq(ResourceReference(intc)) ++ ofInt(x) + val extra = Map( + "#address-cells" -> ofInt(3), + "#size-cells" -> ofInt(2), + "#interrupt-cells" -> ofInt(1), + "device_type" -> Seq(ResourceString("pci")), + "interrupt-names" -> Seq("misc", "msi0", "msi1").map(ResourceString.apply _), + "interrupt-map-mask" -> Seq(0, 0, 0, 7).flatMap(ofInt), + "interrupt-map" -> Seq(1, 2, 3, 4).flatMap(ofMap), + "ranges" -> resources("ranges").map(x => + (x: @unchecked) match { case Binding(_, ResourceAddress(address, perms)) => + ResourceMapping(address, BigInt(0x02000000) << 64, perms) }), + "interrupt-controller" -> Seq(ResourceMap(labels = Seq(intc), value = Map( + "interrupt-controller" -> Nil, + "#address-cells" -> ofInt(0), + "#interrupt-cells" -> ofInt(1))))) + Description(name, mapping ++ extra) + } + } + + val slave = AXI4SlaveNode(Seq(AXI4SlavePortParameters( + slaves = Seq(AXI4SlaveParameters( + address = c.bars, + resources = Seq(Resource(device, "ranges")), + executable = true, + supportsWrite = TransferSizes(1, 128), + supportsRead = TransferSizes(1, 128))), + beatBytes = c.busBytes))) + + val control = AXI4SlaveNode(Seq(AXI4SlavePortParameters( + slaves = Seq(AXI4SlaveParameters( + address = List(AddressSet(c.control, 0x3ffffffL)), // when truncated to 32-bits, is 0 + resources = device.reg("control"), + supportsWrite = TransferSizes(1, 4), + supportsRead = TransferSizes(1, 4), + interleavedId = Some(0))), // AXI4-Lite never interleaves responses + beatBytes = 4))) + + val master = AXI4MasterNode(Seq(AXI4MasterPortParameters( + masters = Seq(AXI4MasterParameters( + name = c.name, + id = IdRange(0, 1 << c.mIDBits), + aligned = false))))) + + val intnode = IntSourceNode(IntSourcePortSimple(num = 3, resources = device.int)) + + lazy val module = new LazyRawModuleImp(this) { + // The master on the control port must be AXI-lite + require (control.edges.in(0).master.endId == 1) + // Must have the right number of slave idBits + require (slave.edges.in(0).bundle.idBits <= c.sIDBits) + // Must have the right bus width + require (master.edges.out(0).slave.beatBytes == c.busBytes) + + val io = IO(new Bundle { + val pads = new XDMAPads(c.lanes) + val clocks = new XDMAClocks + }) + + val blackbox = Module(new XDMABlackBox(c)) + + val (s, _) = slave.in(0) + val (t, _) = control.in(0) + val (m, _) = master.out(0) + val (i, _) = intnode.out(0) + + // Pads + io.pads.pci_exp_txp := blackbox.io.pci_exp_txp + io.pads.pci_exp_txn := blackbox.io.pci_exp_txn + blackbox.io.pci_exp_rxp := io.pads.pci_exp_rxp + blackbox.io.pci_exp_rxn := io.pads.pci_exp_rxn + + // Clocks + blackbox.io.sys_clk := io.clocks.sys_clk + blackbox.io.sys_clk_gt := io.clocks.sys_clk_gt + blackbox.io.sys_rst_n := io.clocks.sys_rst_n + io.clocks.axi_aclk := blackbox.io.axi_aclk + io.clocks.axi_aresetn := blackbox.io.axi_aresetn + + // I + i(0) := blackbox.io.interrupt_out + i(1) := blackbox.io.interrupt_out_msi_vec0to31 + i(2) := blackbox.io.interrupt_out_msi_vec32to63 + + // M.AW + blackbox.io.m_axib_awready := m.aw.ready + m.aw.valid := blackbox.io.m_axib_awvalid + m.aw.bits.id := blackbox.io.m_axib_awid + m.aw.bits.addr := blackbox.io.m_axib_awaddr + m.aw.bits.len := blackbox.io.m_axib_awlen + m.aw.bits.size := blackbox.io.m_axib_awsize + m.aw.bits.burst := blackbox.io.m_axib_awburst + m.aw.bits.prot := blackbox.io.m_axib_awprot + m.aw.bits.cache := blackbox.io.m_axib_awcache + m.aw.bits.lock := blackbox.io.m_axib_awlock + m.aw.bits.qos := 0.U + + // M.AR + blackbox.io.m_axib_arready := m.ar.ready + m.ar.valid := blackbox.io.m_axib_arvalid + m.ar.bits.id := blackbox.io.m_axib_arid + m.ar.bits.addr := blackbox.io.m_axib_araddr + m.ar.bits.len := blackbox.io.m_axib_arlen + m.ar.bits.size := blackbox.io.m_axib_arsize + m.ar.bits.burst := blackbox.io.m_axib_arburst + m.ar.bits.prot := blackbox.io.m_axib_arprot + m.ar.bits.cache := blackbox.io.m_axib_arcache + m.ar.bits.lock := blackbox.io.m_axib_arlock + m.ar.bits.qos := 0.U + + // M.W + blackbox.io.m_axib_wready := m.w.ready + m.w.valid := blackbox.io.m_axib_wvalid + m.w.bits.data := blackbox.io.m_axib_wdata + m.w.bits.strb := blackbox.io.m_axib_wstrb + m.w.bits.last := blackbox.io.m_axib_wlast + + // M.B + m.b.ready := blackbox.io.m_axib_bready + blackbox.io.m_axib_bvalid := m.b.valid + blackbox.io.m_axib_bid := m.b.bits.id + blackbox.io.m_axib_bresp := m.b.bits.resp + + // M.R + m.r.ready := blackbox.io.m_axib_rready + blackbox.io.m_axib_rvalid := m.r.valid + blackbox.io.m_axib_rid := m.r.bits.id + blackbox.io.m_axib_rdata := m.r.bits.data + blackbox.io.m_axib_rresp := m.r.bits.resp + blackbox.io.m_axib_rlast := m.r.bits.last + + // S.AW + s.aw.ready := blackbox.io.s_axib_awready + blackbox.io.s_axib_awvalid := s.aw.valid + blackbox.io.s_axib_awid := s.aw.bits.id + blackbox.io.s_axib_awaddr := s.aw.bits.addr + blackbox.io.s_axib_awregion := 0.U + blackbox.io.s_axib_awlen := s.aw.bits.len + blackbox.io.s_axib_awsize := s.aw.bits.size + blackbox.io.s_axib_awburst := s.aw.bits.burst + + // S.AR + s.ar.ready := blackbox.io.s_axib_arready + blackbox.io.s_axib_arvalid := s.ar.valid + blackbox.io.s_axib_arid := s.ar.bits.id + blackbox.io.s_axib_araddr := s.ar.bits.addr + blackbox.io.s_axib_arregion := 0.U + blackbox.io.s_axib_arlen := s.ar.bits.len + blackbox.io.s_axib_arsize := s.ar.bits.size + blackbox.io.s_axib_arburst := s.ar.bits.burst + + // S.W + s.w.ready := blackbox.io.s_axib_wready + blackbox.io.s_axib_wvalid := s.w.valid + blackbox.io.s_axib_wdata := s.w.bits.data + blackbox.io.s_axib_wstrb := s.w.bits.strb + blackbox.io.s_axib_wlast := s.w.bits.last + + // S.B + blackbox.io.s_axib_bready := s.b.ready + s.b.valid := blackbox.io.s_axib_bvalid + s.b.bits.id := blackbox.io.s_axib_bid + s.b.bits.resp := blackbox.io.s_axib_bresp + + // S.R + blackbox.io.s_axib_rready := s.r.ready + s.r.valid := blackbox.io.s_axib_rvalid + s.r.bits.id := blackbox.io.s_axib_rid + s.r.bits.data := blackbox.io.s_axib_rdata + s.r.bits.resp := blackbox.io.s_axib_rresp + s.r.bits.last := blackbox.io.s_axib_rlast + + // SL.AW + t.aw.ready := blackbox.io.s_axil_awready + blackbox.io.s_axil_awvalid := t.aw.valid + blackbox.io.s_axil_awaddr := t.aw.bits.addr + blackbox.io.s_axil_awprot := t.aw.bits.prot + + // SL.AR + t.ar.ready := blackbox.io.s_axil_arready + blackbox.io.s_axil_arvalid := t.ar.valid + blackbox.io.s_axil_araddr := t.ar.bits.addr + blackbox.io.s_axil_arprot := t.ar.bits.prot + + // SL.W + t.w.ready := blackbox.io.s_axil_wready + blackbox.io.s_axil_wvalid := t.w.valid + blackbox.io.s_axil_wdata := t.w.bits.data + blackbox.io.s_axil_wstrb := t.w.bits.strb + + // SL.B + blackbox.io.s_axil_bready := t.b.ready + t.b.valid := blackbox.io.s_axil_bvalid + t.b.bits.id := 0.U + t.b.bits.resp := blackbox.io.s_axil_bresp + + // SL.R + blackbox.io.s_axil_rready := t.r.ready + t.r.valid := blackbox.io.s_axil_rvalid + t.r.bits.id := 0.U + t.r.bits.data := blackbox.io.s_axil_rdata + t.r.bits.resp := blackbox.io.s_axil_rresp + t.r.bits.last := true.B + } +} diff --git a/fpga-shells/src/main/scala/shell/ChipLinkOverlay.scala b/fpga-shells/src/main/scala/shell/ChipLinkOverlay.scala new file mode 100644 index 00000000..ab117d32 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/ChipLinkOverlay.scala @@ -0,0 +1,50 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell + +import chisel3._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import sifive.blocks.devices.chiplink._ +import sifive.fpgashells.clocks._ + +case class ChipLinkOverlayParams( + params: ChipLinkParams, + txGroup: ClockGroupNode, + txData: ClockSinkNode, + wrangler: ClockAdapterNode)( + implicit val p: Parameters) + +case object ChipLinkOverlayKey extends Field[Seq[DesignOverlay[ChipLinkOverlayParams, TLNode]]](Nil) + +abstract class ChipLinkOverlay( + val params: ChipLinkOverlayParams, + val rxPhase: Double, + val txPhase: Double) + extends IOOverlay[WideDataLayerPort, TLNode] +{ + implicit val p = params.p + val freqMHz = params.txData.portParams.head.take.get.freqMHz + val phaseDeg = params.txData.portParams.head.phaseDeg + + val link = LazyModule(new ChipLink(params.params)) + val rxPLL = p(PLLFactoryKey)(feedback = true) + val ioSink = shell { link.ioNode.makeSink() } + val rxI = shell { ClockSourceNode(freqMHz = freqMHz, jitterPS = 100) } + val rxGroup = shell { ClockGroup() } + val rxO = shell { ClockSinkNode(freqMHz = freqMHz, phaseDeg = rxPhase) } + val txClock = shell { ClockSinkNode(freqMHz = freqMHz, phaseDeg = phaseDeg + txPhase) } + + rxO := params.wrangler := rxGroup := rxPLL := rxI + txClock := params.wrangler := params.txGroup + + def designOutput = link.node + def ioFactory = new WideDataLayerPort(ChipLinkParams(Nil,Nil)) + + shell { InModuleBody { + val (rxOut, _) = rxO.in(0) + val port = ioSink.bundle + io <> port + port.b2c.clk := rxOut.clock + } } +} diff --git a/fpga-shells/src/main/scala/shell/ClockOverlay.scala b/fpga-shells/src/main/scala/shell/ClockOverlay.scala new file mode 100644 index 00000000..9a9ef9a9 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/ClockOverlay.scala @@ -0,0 +1,36 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell + +import chisel3._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import sifive.fpgashells.clocks._ + +case class ClockInputOverlayParams()(implicit val p: Parameters) +case class ClockOutputOverlayParams()(implicit val p: Parameters) + +case object ClockInputOverlayKey extends Field[Seq[DesignOverlay[ClockInputOverlayParams, ClockSourceNode]]](Nil) +case object ClockOutputOverlayKey extends Field[Seq[DesignOverlay[ClockOutputOverlayParams, ClockSinkNode]]](Nil) + +class LVDSClock extends Bundle +{ + val p = Clock() + val n = Clock() +} + +abstract class LVDSClockInputOverlay( + val params: ClockInputOverlayParams) + extends IOOverlay[LVDSClock, ClockSourceNode] +{ + implicit val p = params.p + def node: ClockSourceNode + + def ioFactory = Input(new LVDSClock) + def designOutput = node + + val clock = shell { InModuleBody { + val (bundle, edge) = node.out.head + shell.sdc.addClock(name, io.p, edge.clock.freqMHz) + bundle.clock + } } +} diff --git a/fpga-shells/src/main/scala/shell/DDROverlay.scala b/fpga-shells/src/main/scala/shell/DDROverlay.scala new file mode 100644 index 00000000..7fb9379b --- /dev/null +++ b/fpga-shells/src/main/scala/shell/DDROverlay.scala @@ -0,0 +1,21 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell + +import chisel3._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import sifive.fpgashells.clocks._ + +case class DDROverlayParams( + baseAddress: BigInt, + wrangler: ClockAdapterNode)( + implicit val p: Parameters) + +case object DDROverlayKey extends Field[Seq[DesignOverlay[DDROverlayParams, TLInwardNode]]](Nil) + +abstract class DDROverlay[IO <: Data](val params: DDROverlayParams) + extends IOOverlay[IO, TLInwardNode] +{ + implicit val p = params.p +} diff --git a/fpga-shells/src/main/scala/shell/IOShell.scala b/fpga-shells/src/main/scala/shell/IOShell.scala new file mode 100644 index 00000000..b2fd71fd --- /dev/null +++ b/fpga-shells/src/main/scala/shell/IOShell.scala @@ -0,0 +1,158 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell + +import chisel3._ +import chisel3.experimental.IO +import chisel3.core.DataMirror +import freechips.rocketchip.config._ +import freechips.rocketchip.util._ +import freechips.rocketchip.diplomacy._ + +case class IOPin(element: Element, index: Int = 0) +{ + private val width = DataMirror.widthOf(element) + require (width.known) + require (index >= 0 && index < width.get) + + def name = { + val pin = element.instanceName.split("\\.").mkString("_") + val path = element.parentPathName.split("\\.") + val pindex = pin + (if (width.get > 1) s"[${index}]" else "") + (path.drop(1) :+ pindex).mkString("/") + } + + def sdcPin = { + val path = name + if (path.contains("/")) s"[get_pins {${path}}]" else s"[get_ports {${path}}]" + } + + def sdcClock = s"[get_clocks -of_objects ${sdcPin}]" + + def isOutput = { + import chisel3.core.ActualDirection._ + DataMirror.directionOf(element) match { + case Output => true + case Input => false + case Bidirectional(_) => true + case Unspecified => { require(false); false } + } + } + + def isInput = { + import chisel3.core.ActualDirection._ + DataMirror.directionOf(element) match { + case Output => false + case Input => true + case Bidirectional(_) => true + case Unspecified => { require(false); false } + } + } +} + +object IOPin +{ + def of(x: Data): Seq[IOPin] = { + val elts = x match { + case a: Aggregate => getDataElements(a).reverse // because Chisel has it backwards + case e: Element => Seq(e) + } + elts.flatMap { elt => + val width = DataMirror.widthOf(elt) + require (width.known) + Seq.tabulate(width.get) { i => IOPin(elt, i) } + } + } +} + +case class IOTiming( + minInput: Double = 0, + maxInput: Double = 0, + minOutput: Double = 0, + maxOutput: Double = 0) + +class SDC(val name: String) +{ + private var clocks: Seq[() => String] = Nil + private var groups: Seq[() => String] = Nil + private var falses: Seq[() => String] = Nil + private var timings: Seq[() => String] = Nil + + protected def addRawClock (command: => String) { clocks = (() => command) +: clocks } + protected def addRawGroup (command: => String) { groups = (() => command) +: groups } + protected def addRawFalse (command: => String) { falses = (() => command) +: falses } + protected def addRawTiming(command: => String) { timings = (() => command) +: timings } + addRawGroup("set_clock_groups -asynchronous") + + private def flatten(x: Seq[() => String], sep: String = "\n") = x.map(_()).filter(_ != "").reverse.mkString(sep) + ElaborationArtefacts.add(name, + s"""# ------------------------- Base Clocks -------------------- + |${flatten(clocks)} + |# ------------------------- Clock Groups ------------------- + |${if (groups.size == 1) "" else flatten(groups, " \\\n")} + |# ------------------------- False Paths -------------------- + |${flatten(falses)} + |# ------------------------- IO Timings --------------------- + |${flatten(timings)} + |""".stripMargin) + + def addClock(name: => String, pin: => IOPin, freqMHz: => Double, jitterNs: => Double = 0.5) { + addRawClock(s"create_clock -name ${name} -period ${1000/freqMHz} ${pin.sdcPin}") + addRawClock(s"set_input_jitter ${name} ${jitterNs}") + } + + def addDerivedClock(name: => String, source: => IOPin, sink: => IOPin) { + addRawClock(s"create_generated_clock -name ${name} -divide_by 1 -source ${source.sdcPin} ${sink.sdcPin}") + } + + def addGroup(clocks: => Seq[String] = Nil, pins: => Seq[IOPin] = Nil) { + def thunk = { + val clocksList = clocks + val (pinsList, portsList) = pins.map(_.name).partition(_.contains("/")) + val sep = " \\\n " + val clocksStr = (" [get_clocks {" +: clocksList).mkString(sep) + " \\\n }]" + val pinsStr = (" [get_clocks -of_objects [get_pins {" +: pinsList ).mkString(sep) + " \\\n }]]" + val portsStr = (" [get_clocks -of_objects [get_ports {" +: portsList).mkString(sep) + " \\\n }]]" + val str = s" -group [list${if (clocksList.isEmpty) "" else clocksStr}${if (pinsList.isEmpty) "" else pinsStr}${if (portsList.isEmpty) "" else portsStr}]" + if (clocksList.isEmpty && pinsList.isEmpty && portsList.isEmpty) "" else str + } + addRawGroup(thunk) + } + + def addAsyncPath(through: => Seq[IOPin]) { + addRawFalse("set_false_path" + through.map(x => s" -through ${x.sdcPin}").mkString) + } + + def addInputDelay(port: => IOPin, clock: => String, min: => Double, max: => Double) { + addRawTiming(f"set_input_delay -min ${min}% -5.2f -clock ${clock} ${port.sdcPin}") + addRawTiming(f"set_input_delay -max ${max}% -5.2f -clock ${clock} ${port.sdcPin}") + } + + def addOutputDelay(port: => IOPin, clock: => String, min: => Double, max: => Double) { + addRawTiming(f"set_output_delay -min ${min}% -5.2f -clock ${clock} ${port.sdcPin}") + addRawTiming(f"set_output_delay -max ${max}% -5.2f -clock ${clock} ${port.sdcPin}") + } + + def addIOTiming(io: IOPin, clock: => String, timing: => IOTiming) { + if (io.isInput) { addInputDelay (io, clock, timing.minInput, timing.maxInput) } + if (io.isOutput) { addOutputDelay(io, clock, timing.minOutput, timing.maxOutput) } + } +} + +// An IOOverlay is an Overlay with a public shell-level IO +trait IOOverlay[IO <: Data, DesignOutput] extends Overlay[DesignOutput] +{ + def ioFactory: IO + def shell: IOShell + + val io = shell { InModuleBody { + val port = IO(ioFactory) + port.suggestName(name) + port + } } +} + +abstract class IOShell()(implicit p: Parameters) extends Shell +{ + // This can be overriden if a particular vendor needs customized SDC output + def sdc: SDC +} diff --git a/fpga-shells/src/main/scala/shell/JTAGDebugOverlay.scala b/fpga-shells/src/main/scala/shell/JTAGDebugOverlay.scala new file mode 100644 index 00000000..31b73978 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/JTAGDebugOverlay.scala @@ -0,0 +1,39 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell + +import chisel3._ +import freechips.rocketchip.config._ +import freechips.rocketchip.util._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.devices.debug._ +import freechips.rocketchip.subsystem.{BaseSubsystem, PeripheryBus, PeripheryBusKey} +import sifive.fpgashells.ip.xilinx._ + +case class JTAGDebugOverlayParams()(implicit val p: Parameters) +case object JTAGDebugOverlayKey extends Field[Seq[DesignOverlay[JTAGDebugOverlayParams, ModuleValue[FPGAJTAGIO]]]](Nil) + +class FPGAJTAGIO extends Bundle { + // JTAG + val jtag_TCK = Input(Clock()) + val jtag_TMS = Input(Bool()) + val jtag_TDI = Input(Bool()) + val jtag_TDO = Output(Bool()) +} + +abstract class JTAGDebugOverlay( + val params: JTAGDebugOverlayParams) + extends IOOverlay[FPGAJTAGIO, ModuleValue[FPGAJTAGIO]] +{ + implicit val p = params.p + + def ioFactory = new FPGAJTAGIO + + val jtagDebugSource = BundleBridgeSource(() => new FPGAJTAGIO) + val jtagDebugSink = shell { jtagDebugSource.makeSink } + + val designOutput = InModuleBody { jtagDebugSource.bundle} + + shell { InModuleBody { + io <> jtagDebugSink.bundle + } } +} diff --git a/fpga-shells/src/main/scala/shell/LEDOverlay.scala b/fpga-shells/src/main/scala/shell/LEDOverlay.scala new file mode 100644 index 00000000..a4846f61 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/LEDOverlay.scala @@ -0,0 +1,23 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell + +import chisel3._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ + +case class LEDOverlayParams()(implicit val p: Parameters) +case object LEDOverlayKey extends Field[Seq[DesignOverlay[LEDOverlayParams, ModuleValue[UInt]]]](Nil) + +abstract class LEDOverlay( + val params: LEDOverlayParams) + extends IOOverlay[UInt, ModuleValue[UInt]] +{ + implicit val p = params.p + + def width: Int + def ioFactory = Output(UInt(width.W)) + + val ledSource = BundleBridgeSource(() => UInt(width.W)) + val ledSink = shell { ledSource.makeSink() } + val designOutput = InModuleBody { ledSource.out(0)._1 } +} diff --git a/fpga-shells/src/main/scala/shell/PCIeOverlay.scala b/fpga-shells/src/main/scala/shell/PCIeOverlay.scala new file mode 100644 index 00000000..5eacbb3a --- /dev/null +++ b/fpga-shells/src/main/scala/shell/PCIeOverlay.scala @@ -0,0 +1,23 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell + +import chisel3._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts._ +import sifive.fpgashells.clocks._ + +case class PCIeOverlayParams( + wrangler: ClockAdapterNode, + bars: Seq[AddressSet] = Seq(AddressSet(0x40000000L, 0x1FFFFFFFL)), + ecam: BigInt = 0x2000000000L)( + implicit val p: Parameters) + +case object PCIeOverlayKey extends Field[Seq[DesignOverlay[PCIeOverlayParams, (TLNode, IntOutwardNode)]]](Nil) + +abstract class PCIeOverlay[IO <: Data](val params: PCIeOverlayParams) + extends IOOverlay[IO, (TLNode, IntOutwardNode)] +{ + implicit val p = params.p +} diff --git a/fpga-shells/src/main/scala/shell/SDIOOverlay.scala b/fpga-shells/src/main/scala/shell/SDIOOverlay.scala new file mode 100644 index 00000000..a35f912c --- /dev/null +++ b/fpga-shells/src/main/scala/shell/SDIOOverlay.scala @@ -0,0 +1,67 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell + +import chisel3._ +import chisel3.experimental.Analog +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import sifive.blocks.devices.spi._ +import freechips.rocketchip.tilelink.TLBusWrapper +import freechips.rocketchip.interrupts.IntInwardNode + +// TODO: Can this be combined with SPIAttachParams? +case class SDIOOverlayParams(spiParam: SPIParams, controlBus: TLBusWrapper, intNode: IntInwardNode)(implicit val p: Parameters) +case object SDIOOverlayKey extends Field[Seq[DesignOverlay[SDIOOverlayParams, TLSPI]]](Nil) + +// SDIO Port. Not sure how generic this is, it might need to move. +class FPGASDIOPortIO extends Bundle { + val sdio_clk = Output(Bool()) + val sdio_cmd = Output(Bool()) + val sdio_dat_0 = Input(Bool()) + val sdio_dat_1 = Analog(1.W) + val sdio_dat_2 = Analog(1.W) + val sdio_dat_3 = Output(Bool()) +} + +abstract class SDIOOverlay( + val params: SDIOOverlayParams) + extends IOOverlay[FPGASDIOPortIO, TLSPI] +{ + implicit val p = params.p + + def ioFactory = new FPGASDIOPortIO + val tlspi = SPI.attach(SPIAttachParams(params.spiParam, params.controlBus, params.intNode)) + val tlspiSink = tlspi.ioNode.makeSink + + val spiSource = BundleBridgeSource(() => new SPIPortIO(params.spiParam)) + val spiSink = shell { spiSource.makeSink } + val designOutput = tlspi + + InModuleBody { + val (io, _) = spiSource.out(0) + val tlspiport = tlspiSink.bundle + io <> tlspiport + (0 to 3).foreach { case q => + tlspiport.dq(q).i := RegNext(RegNext(io.dq(q).i)) + } + } + + shell { InModuleBody { + val sd_spi_sck = spiSink.bundle.sck + val sd_spi_cs = spiSink.bundle.cs(0) + + val sd_spi_dq_i = Wire(Vec(4, Bool())) + val sd_spi_dq_o = Wire(Vec(4, Bool())) + + spiSink.bundle.dq.zipWithIndex.foreach { + case(pin, idx) => + sd_spi_dq_o(idx) := pin.o + pin.i := sd_spi_dq_i(idx) + } + + io.sdio_clk := sd_spi_sck + io.sdio_dat_3 := sd_spi_cs + io.sdio_cmd := sd_spi_dq_o(0) + sd_spi_dq_i := Seq(false.B, io.sdio_dat_0, false.B, false.B) + } } +} diff --git a/fpga-shells/src/main/scala/shell/Shell.scala b/fpga-shells/src/main/scala/shell/Shell.scala new file mode 100644 index 00000000..776b0ea4 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/Shell.scala @@ -0,0 +1,61 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell + +import chisel3._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ + +case object DesignKey extends Field[Parameters => LazyModule] + +// Overlays are declared by the Shell and placed somewhere by the Design +// ... they inject diplomatic code both where they were placed and in the shell +// ... they are instantiated with DesignInput and return DesignOutput +trait Overlay[DesignOutput] +{ + def designOutput: DesignOutput + def name: String + def shell: Shell +} + +// DesignOverlays provide the method used to instantiate and place an Overlay +trait DesignOverlay[DesignInput, DesignOutput] { + def isPlaced: Boolean + def name: String + def apply(input: DesignInput): DesignOutput +} + +abstract class Shell()(implicit p: Parameters) extends LazyModule with LazyScope +{ + private var overlays = Parameters.empty + def designParameters: Parameters = overlays ++ p + + def Overlay[DesignInput, DesignOutput, T <: Overlay[DesignOutput]]( + key: Field[Seq[DesignOverlay[DesignInput, DesignOutput]]])( + gen: (this.type, String, DesignInput) => T)( + implicit valName: ValName): ModuleValue[Option[T]] = + { + val self = this.asInstanceOf[this.type] + val thunk = new ModuleValue[Option[T]] with DesignOverlay[DesignInput, DesignOutput] { + var placement: Option[T] = None + def getWrappedValue = placement + def isPlaced = !placement.isEmpty + def name = valName.name + def apply(input: DesignInput): DesignOutput = { + require (placement.isEmpty, s"Overlay ${name} has already been placed by the design; cannot place again") + val it = gen(self, valName.name, input) + placement = Some(it) + it.designOutput + } + } + overlays = overlays ++ Parameters((site, here, up) => { + case x: Field[_] if x eq key => { + val tail = up(key) + if (thunk.isPlaced) { tail } else { thunk +: tail } + } + }) + thunk + } + + // feel free to override this if necessary + lazy val module = new LazyRawModuleImp(this) +} diff --git a/fpga-shells/src/main/scala/shell/SwitchOverlay.scala b/fpga-shells/src/main/scala/shell/SwitchOverlay.scala new file mode 100644 index 00000000..1e752b93 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/SwitchOverlay.scala @@ -0,0 +1,23 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell + +import chisel3._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ + +case class SwitchOverlayParams()(implicit val p: Parameters) +case object SwitchOverlayKey extends Field[Seq[DesignOverlay[SwitchOverlayParams, ModuleValue[UInt]]]](Nil) + +abstract class SwitchOverlay( + val params: SwitchOverlayParams) + extends IOOverlay[UInt, ModuleValue[UInt]] +{ + implicit val p = params.p + + def width: Int + def ioFactory = Input(UInt(width.W)) + + val switchSource = shell { BundleBridgeSource(() => UInt(width.W)) } + val switchSink = switchSource.makeSink() + val designOutput = InModuleBody { switchSink.bundle } +} diff --git a/fpga-shells/src/main/scala/shell/UARTOverlay.scala b/fpga-shells/src/main/scala/shell/UARTOverlay.scala new file mode 100644 index 00000000..96dd65e0 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/UARTOverlay.scala @@ -0,0 +1,54 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell + +import chisel3._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import sifive.blocks.devices.uart._ +import freechips.rocketchip.subsystem.{BaseSubsystem, PeripheryBus, PeripheryBusKey} +import freechips.rocketchip.tilelink.TLBusWrapper +import freechips.rocketchip.interrupts.IntInwardNode + +//TODO: Can this be combined with UARTAttachParams? +case class UARTOverlayParams(uartParams: UARTParams, divInit: Int, controlBus: TLBusWrapper, intNode: IntInwardNode)(implicit val p: Parameters) +case object UARTOverlayKey extends Field[Seq[DesignOverlay[UARTOverlayParams, TLUART]]](Nil) + +// Tack on cts, rts signals available on some FPGAs. They are currently unused +// by our designs. +class FPGAUARTPortIO extends UARTPortIO { + val rtsn = Output(Bool()) + val ctsn = Input(Bool()) +} + +//class UARTReplacementBundle extends Bundle with HasUARTTopBundleContents + +abstract class UARTOverlay( + val params: UARTOverlayParams) + extends IOOverlay[FPGAUARTPortIO, TLUART] +{ + implicit val p = params.p + + def ioFactory = new FPGAUARTPortIO + + val tluart = UART.attach(UARTAttachParams(params.uartParams, params.divInit, params.controlBus, params.intNode)) + val tluartSink = tluart.ioNode.makeSink + val uartSource = BundleBridgeSource(() => new UARTPortIO()) + val uartSink = shell { uartSource.makeSink } + + val designOutput = tluart + + InModuleBody { + val (io, _) = uartSource.out(0) + val tluartport = tluartSink.bundle + io <> tluartport + tluartport.rxd := RegNext(RegNext(io.rxd)) + } + + shell { InModuleBody { + io.txd := uartSink.bundle.txd + uartSink.bundle.rxd := io.rxd + + // Some FPGAs have this, we don't use it. + io.rtsn := false.B + } } +} diff --git a/fpga-shells/src/main/scala/shell/microsemi/PolarFireEvalKitShell.scala b/fpga-shells/src/main/scala/shell/microsemi/PolarFireEvalKitShell.scala new file mode 100644 index 00000000..b87611ed --- /dev/null +++ b/fpga-shells/src/main/scala/shell/microsemi/PolarFireEvalKitShell.scala @@ -0,0 +1,659 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.microsemi.polarfireevalkitshell + +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, ResetCatchAndSync, ElaborationArtefacts, HeterogeneousBag} + +import sifive.blocks.devices.gpio._ +import sifive.blocks.devices.spi._ +import sifive.blocks.devices.uart._ + +import sifive.fpgashells.ip.microsemi.{CLKINT} + +import sifive.fpgashells.devices.microsemi.polarfireddr3._ +import sifive.fpgashells.devices.microsemi.polarfireddr4._ + +import sifive.fpgashells.ip.microsemi.corejtagdebug._ +import sifive.fpgashells.ip.microsemi.polarfireccc._ +import sifive.fpgashells.ip.microsemi.polarfireinitmonitor._ +import sifive.fpgashells.ip.microsemi.polarfirereset._ + +import sifive.fpgashells.devices.microsemi.polarfireevalkitpciex4._ +import sifive.fpgashells.ip.microsemi.polarfirexcvrrefclk._ +import sifive.fpgashells.ip.microsemi.polarfiretxpll._ + +import sifive.fpgashells.ip.microsemi.polarfire_oscillator._ +import sifive.fpgashells.ip.microsemi.polarfireclockdivider._ +import sifive.fpgashells.ip.microsemi.polarfireglitchlessmux._ +import sifive.blocks.devices.chiplink._ +import sifive.fpgashells.clocks._ + + +//------------------------------------------------------------------------- +// PolarFire Evaluation Kit Shell +//------------------------------------------------------------------------- + +trait HasDDR3 { this: PolarFireEvalKitShell => + + require(!p.lift(MemoryMicrosemiDDR3Key).isEmpty) + val ddr = IO(new PolarFireEvalKitDDR3Pads(p(MemoryMicrosemiDDR3Key))) + + def connectMIG(dut: HasMemoryPolarFireEvalKitDDR3ModuleImp): Unit = { + // Clock & Reset + dut.polarfireddrsubsys.PLL_REF_CLK := mig_clock_in + dut.polarfireddrsubsys.SYS_RESET_N := sys_reset_n + + mig_clock_out := dut.polarfireddrsubsys.SYS_CLK + mig_plllock_out := dut.polarfireddrsubsys.PLL_LOCK + ddr_ctrlr_ready := dut.polarfireddrsubsys.CTRLR_READY + + ddr <> dut.polarfireddrsubsys + } +} + +trait HasDDR4 { this: PolarFireEvalKitShell => + + require(!p.lift(MemoryMicrosemiDDR4Key).isEmpty) + val ddr = IO(new PolarFireEvalKitDDR4Pads(p(MemoryMicrosemiDDR4Key))) + + def connectMIG(dut: HasMemoryPolarFireEvalKitDDR4ModuleImp): Unit = { + // Clock & Reset + dut.polarfireddrsubsys.PLL_REF_CLK := mig_clock_in + dut.polarfireddrsubsys.SYS_RESET_N := sys_reset_n + + mig_clock_out := dut.polarfireddrsubsys.SYS_CLK + mig_plllock_out := dut.polarfireddrsubsys.PLL_LOCK + ddr_ctrlr_ready := dut.polarfireddrsubsys.CTRLR_READY + + ddr <> dut.polarfireddrsubsys + } +} + +trait HasPCIe { this: PolarFireEvalKitShell => + val pcie = IO(new PolarFireEvalKitPCIeX4Pads) + + def connectPCIe(dut: HasSystemPolarFireEvalKitPCIeX4ModuleImp): Unit = { + // Clock & Reset +// dut.pf_eval_kit_pcie.APB_S_PCLK := hart_clk + dut.pf_eval_kit_pcie.APB_S_PCLK := dut_clock + dut.pf_eval_kit_pcie.APB_S_PRESET_N := UInt("b1") + +// dut.pf_eval_kit_pcie.AXI_CLK := hart_clk_150 + dut.pf_eval_kit_pcie.AXI_CLK := dut_clock + dut.pf_eval_kit_pcie.AXI_CLK_STABLE := hart_clk_lock + + dut.pf_eval_kit_pcie.PCIE_1_TL_CLK_125MHz := pcie_tl_clk + + dut.pf_eval_kit_pcie.PCIE_1_TX_PLL_REF_CLK := pf_tx_pll_refclk_to_lane + + dut.pf_eval_kit_pcie.PCIE_1_TX_BIT_CLK := pf_tx_pll_bitclk + + dut.pf_eval_kit_pcie.PCIESS_LANE0_CDR_REF_CLK_0 := pcie_refclk + dut.pf_eval_kit_pcie.PCIESS_LANE1_CDR_REF_CLK_0 := pcie_refclk + dut.pf_eval_kit_pcie.PCIESS_LANE2_CDR_REF_CLK_0 := pcie_refclk + dut.pf_eval_kit_pcie.PCIESS_LANE3_CDR_REF_CLK_0 := pcie_refclk + + dut.pf_eval_kit_pcie.PCIE_1_TX_PLL_LOCK := pf_tx_pll_lock + + pcie <> dut.pf_eval_kit_pcie + } +} +/* +trait HasCoreJTAGDebug { this: PolarFireEvalKitShell => + // JTAG inside the FPGA fabric through user JTAG FPGA macro (UJTAG) + val fpga_jtag = Module(new CoreJtagDebugBlock) + + fpga_jtag.io.UTDO_IN_0 := UInt("b0") + fpga_jtag.io.UTDO_IN_1 := UInt("b0") + fpga_jtag.io.UTDO_IN_2 := UInt("b0") + fpga_jtag.io.UTDO_IN_3 := UInt("b0") + fpga_jtag.io.UTDODRV_0 := UInt("b0") + fpga_jtag.io.UTDODRV_1 := UInt("b0") + fpga_jtag.io.UTDODRV_2 := UInt("b0") + fpga_jtag.io.UTDODRV_3 := UInt("b0") + +} +*/ + + +trait HasPFEvalKitChipLink { this: PolarFireEvalKitShell => + + val chiplink = IO(new WideDataLayerPort(ChipLinkParams(Nil,Nil))) + val ereset_n = IO(Bool(INPUT)) + + def constrainChipLink(iofpga: Boolean = false): Unit = { + val direction0Pins = if(iofpga) "chiplink_b2c" else "chiplink_c2b" + val direction1Pins = if(iofpga) "chiplink_c2b" else "chiplink_b2c" +/* + ElaborationArtefacts.add( + """vc707chiplink.vivado.tcl""", + """set vc707chiplink_vivado_tcl_dir [file dirname [file normalize [info script]]] + add_files -fileset [current_fileset -constrset] [glob -directory $vc707chiplink_vivado_tcl_dir {*.vc707chiplink.xdc}]""" + ) +*/ + +/* + ElaborationArtefacts.add( + """vc707chiplink.xdc""", s""" + set_property PACKAGE_PIN AF39 [get_ports ${direction0Pins}_clk] + set_property PACKAGE_PIN AD40 [get_ports {${direction0Pins}_data[0]}] + set_property PACKAGE_PIN AD41 [get_ports {${direction0Pins}_data[1]}] + set_property PACKAGE_PIN AF41 [get_ports {${direction0Pins}_data[2]}] + set_property PACKAGE_PIN AG41 [get_ports {${direction0Pins}_data[3]}] + set_property PACKAGE_PIN AK39 [get_ports {${direction0Pins}_data[4]}] + set_property PACKAGE_PIN AL39 [get_ports {${direction0Pins}_data[5]}] + set_property PACKAGE_PIN AJ42 [get_ports {${direction0Pins}_data[6]}] + set_property PACKAGE_PIN AK42 [get_ports {${direction0Pins}_data[7]}] + set_property PACKAGE_PIN AL41 [get_ports {${direction0Pins}_data[8]}] + set_property PACKAGE_PIN AL42 [get_ports {${direction0Pins}_data[9]}] + set_property PACKAGE_PIN AF42 [get_ports {${direction0Pins}_data[10]}] + set_property PACKAGE_PIN AG42 [get_ports {${direction0Pins}_data[11]}] + set_property PACKAGE_PIN AD38 [get_ports {${direction0Pins}_data[12]}] + set_property PACKAGE_PIN AE38 [get_ports {${direction0Pins}_data[13]}] + set_property PACKAGE_PIN AC40 [get_ports {${direction0Pins}_data[14]}] + set_property PACKAGE_PIN AC41 [get_ports {${direction0Pins}_data[15]}] + set_property PACKAGE_PIN AD42 [get_ports {${direction0Pins}_data[16]}] + set_property PACKAGE_PIN AE42 [get_ports {${direction0Pins}_data[17]}] + set_property PACKAGE_PIN AJ38 [get_ports {${direction0Pins}_data[18]}] + set_property PACKAGE_PIN AK38 [get_ports {${direction0Pins}_data[19]}] + set_property PACKAGE_PIN AB41 [get_ports {${direction0Pins}_data[20]}] + set_property PACKAGE_PIN AB42 [get_ports {${direction0Pins}_data[21]}] + set_property PACKAGE_PIN Y42 [get_ports {${direction0Pins}_data[22]}] + set_property PACKAGE_PIN AA42 [get_ports {${direction0Pins}_data[23]}] + set_property PACKAGE_PIN Y39 [get_ports {${direction0Pins}_data[24]}] + set_property PACKAGE_PIN AA39 [get_ports {${direction0Pins}_data[25]}] + set_property PACKAGE_PIN W40 [get_ports {${direction0Pins}_data[26]}] + set_property PACKAGE_PIN Y40 [get_ports {${direction0Pins}_data[27]}] + set_property PACKAGE_PIN AB38 [get_ports {${direction0Pins}_data[28]}] + set_property PACKAGE_PIN AB39 [get_ports {${direction0Pins}_data[29]}] + set_property PACKAGE_PIN AC38 [get_ports {${direction0Pins}_data[30]}] + set_property PACKAGE_PIN AC39 [get_ports {${direction0Pins}_data[31]}] + set_property PACKAGE_PIN AJ40 [get_ports ${direction0Pins}_send] + set_property PACKAGE_PIN AJ41 [get_ports ${direction0Pins}_rst] + + set_property PACKAGE_PIN U39 [get_ports ${direction1Pins}_clk] + set_property PACKAGE_PIN U37 [get_ports {${direction1Pins}_data[0]}] + set_property PACKAGE_PIN U38 [get_ports {${direction1Pins}_data[1]}] + set_property PACKAGE_PIN U36 [get_ports {${direction1Pins}_data[2]}] + set_property PACKAGE_PIN T37 [get_ports {${direction1Pins}_data[3]}] + set_property PACKAGE_PIN U32 [get_ports {${direction1Pins}_data[4]}] + set_property PACKAGE_PIN U33 [get_ports {${direction1Pins}_data[5]}] + set_property PACKAGE_PIN V33 [get_ports {${direction1Pins}_data[6]}] + set_property PACKAGE_PIN V34 [get_ports {${direction1Pins}_data[7]}] + set_property PACKAGE_PIN P35 [get_ports {${direction1Pins}_data[8]}] + set_property PACKAGE_PIN P36 [get_ports {${direction1Pins}_data[9]}] + set_property PACKAGE_PIN W32 [get_ports {${direction1Pins}_data[10]}] + set_property PACKAGE_PIN W33 [get_ports {${direction1Pins}_data[11]}] + set_property PACKAGE_PIN R38 [get_ports {${direction1Pins}_data[12]}] + set_property PACKAGE_PIN R39 [get_ports {${direction1Pins}_data[13]}] + set_property PACKAGE_PIN U34 [get_ports {${direction1Pins}_data[14]}] + set_property PACKAGE_PIN T35 [get_ports {${direction1Pins}_data[15]}] + set_property PACKAGE_PIN R33 [get_ports {${direction1Pins}_data[16]}] + set_property PACKAGE_PIN R34 [get_ports {${direction1Pins}_data[17]}] + set_property PACKAGE_PIN N33 [get_ports {${direction1Pins}_data[18]}] + set_property PACKAGE_PIN N34 [get_ports {${direction1Pins}_data[19]}] + set_property PACKAGE_PIN P32 [get_ports {${direction1Pins}_data[20]}] + set_property PACKAGE_PIN P33 [get_ports {${direction1Pins}_data[21]}] + set_property PACKAGE_PIN V35 [get_ports {${direction1Pins}_data[22]}] + set_property PACKAGE_PIN V36 [get_ports {${direction1Pins}_data[23]}] + set_property PACKAGE_PIN W36 [get_ports {${direction1Pins}_data[24]}] + set_property PACKAGE_PIN W37 [get_ports {${direction1Pins}_data[25]}] + set_property PACKAGE_PIN T32 [get_ports {${direction1Pins}_data[26]}] + set_property PACKAGE_PIN R32 [get_ports {${direction1Pins}_data[27]}] + set_property PACKAGE_PIN V39 [get_ports {${direction1Pins}_data[28]}] + set_property PACKAGE_PIN V40 [get_ports {${direction1Pins}_data[29]}] + set_property PACKAGE_PIN P37 [get_ports {${direction1Pins}_data[30]}] + set_property PACKAGE_PIN P38 [get_ports {${direction1Pins}_data[31]}] + + set_property PACKAGE_PIN T36 [get_ports ${direction1Pins}_send] + set_property PACKAGE_PIN R37 [get_ports ${direction1Pins}_rst] + + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[31]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[30]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[29]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[28]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[27]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[26]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[25]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[24]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[23]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[22]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[21]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[20]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[19]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[18]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[17]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[16]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[15]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[14]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[13]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[12]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[11]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[10]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[9]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[8]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[7]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[6]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[5]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[4]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[3]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[2]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[1]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[0]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[31]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[30]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[29]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[28]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[27]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[26]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[25]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[24]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[23]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[22]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[21]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[20]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[19]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[18]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[17]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[16]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[15]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[14]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[13]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[12]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[11]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[10]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[9]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[8]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[7]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[6]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[5]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[4]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[3]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[2]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[1]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[0]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[31]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[30]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[29]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[28]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[27]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[26]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[25]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[24]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[23]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[22]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[21]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[20]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[19]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[18]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[17]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[16]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[15]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[14]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[13]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[12]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[11]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[10]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[9]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[8]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[7]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[6]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[5]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[4]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[3]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[2]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[1]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[0]}] + + + set_property IOSTANDARD LVCMOS18 [get_ports ${direction0Pins}_clk] + set_property IOSTANDARD LVCMOS18 [get_ports ${direction0Pins}_rst] + set_property IOSTANDARD LVCMOS18 [get_ports ${direction0Pins}_send] + set_property IOSTANDARD LVCMOS18 [get_ports ${direction1Pins}_clk] + set_property IOSTANDARD LVCMOS18 [get_ports ${direction1Pins}_rst] + set_property IOSTANDARD LVCMOS18 [get_ports ${direction1Pins}_send] + set_property SLEW FAST [get_ports ${direction1Pins}_clk] + set_property SLEW FAST [get_ports ${direction1Pins}_rst] + set_property SLEW FAST [get_ports ${direction1Pins}_send] + + + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[31]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[30]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[29]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[28]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[27]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[26]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[25]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[24]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[23]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[22]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[21]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[20]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[19]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[18]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[17]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[16]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[15]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[14]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[13]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[12]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[11]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[10]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[9]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[8]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[7]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[6]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[5]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[4]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[3]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[2]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[1]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[0]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_send] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_clk] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_rst] + + # Aloe reset sent to FPGA + set_property IOSTANDARD LVCMOS18 [get_ports ereset_n] + set_property PACKAGE_PIN AF40 [get_ports ereset_n] + + #Put first level RX/TX flops in IOB + set_property IOB TRUE [get_cells -of_objects [all_fanout -flat -endpoints_only [get_ports "chiplink_b2c_data*"]]] + set_property IOB TRUE [get_cells -of_objects [all_fanout -flat -endpoints_only [get_ports "chiplink_b2c_send"]]] + set_property IOB TRUE [get_cells -of_objects [all_fanin -flat -startpoints_only [get_ports "chiplink_c2b_data*"]]] + set_property IOB TRUE [get_cells -of_objects [all_fanin -flat -startpoints_only [get_ports "chiplink_c2b_send"]]] +""" + ) +*/ + } + + def connectChipLink(dut: { val chiplink: Seq[WideDataLayerPort] } , iofpga: Boolean = false): Unit = { + constrainChipLink(iofpga) + + chiplink <> dut.chiplink(0) + //dut.chiplink_xilinx_7series_phy.get.idelayctrl_refclk := sys_clock + } +} + +abstract class PolarFireEvalKitShell(implicit val p: Parameters) extends RawModule { + + //----------------------------------------------------------------------- + // Interface + //----------------------------------------------------------------------- + + // 50MHz crystal oscillator + val ref_clk0 = IO(Input(Clock())) + + // + val ref_clk_pad_p = IO(Input(Bool())) + val ref_clk_pad_n = IO(Input(Bool())) + + // Reset push-button - active low + val pf_user_reset_n = IO(Input(Bool())) + + // LED + val led = IO(Vec(8, Output(Bool()))) + + // UART + val uart_tx = IO(Output(Bool())) + val uart_rx = IO(Input(Bool())) + + // SPI Flash + val spi_flash_reset = IO(Output(Bool())) + val spi_flash_sdo = IO(Output(Bool())) + val spi_flash_sdi = IO(Input(Bool())) + val spi_flash_sck = IO(Output(Bool())) + val spi_flash_ss = IO(Output(Bool())) + val spi_flash_wp = IO(Output(Bool())) + val spi_flash_hold = IO(Output(Bool())) + + // JTAG + val jtag_TRSTB = IO(Input(Bool())) + val jtag_TCK = IO(Input(Clock())) + val jtag_TMS = IO(Input(Bool())) + val jtag_TDI = IO(Input(Bool())) + val jtag_TDO = IO(Output(Bool())) + + //Buttons + val btn_0 = IO(Analog(1.W)) + val btn_1 = IO(Analog(1.W)) + val btn_2 = IO(Analog(1.W)) + val btn_3 = IO(Analog(1.W)) + + //Sliding switches + val sw_0 = IO(Analog(1.W)) + val sw_1 = IO(Analog(1.W)) + val sw_2 = IO(Analog(1.W)) + val sw_3 = IO(Analog(1.W)) + val sw_4 = IO(Analog(1.W)) + val sw_5 = IO(Analog(1.W)) + val sw_6 = IO(Analog(1.W)) + val sw_7 = IO(Analog(1.W)) + + // debug + val debug_io0 = IO(Output(Bool())) + val debug_io1 = IO(Output(Clock())) + val debug_io2 = IO(Output(Bool())) + val debug_io3 = IO(Output(Bool())) + val debug_io4 = IO(Output(Clock())) + val debug_io5 = IO(Output(Bool())) + + //----------------------------------------------------------------------- + // Wire declarations + //----------------------------------------------------------------------- + + val sys_clock = Wire(Clock()) + val sys_reset_n = Wire(Bool()) + + val dut_clock = Wire(Clock()) + val dut_reset = Wire(Bool()) + val dut_reset_i = Wire(Bool()) + val dut_reset_sync = Wire(Bool()) + + val dut_ndreset = Wire(Bool()) + + val mig_mmcm_locked = Wire(Bool()) + val mig_sys_reset = Wire(Bool()) + + val mig_clock = Wire(Clock()) + val mig_reset = Wire(Bool()) + val mig_resetn = Wire(Bool()) + + val mig_clock_in = Wire(Clock()) + val mig_clock_out = Wire(Clock()) + val mig_plllock_out = Wire(Bool()) + + val pcie_dat_reset = Wire(Bool()) + val pcie_dat_resetn = Wire(Bool()) + val pcie_cfg_reset = Wire(Bool()) + val pcie_cfg_resetn = Wire(Bool()) + val pcie_dat_clock = Wire(Clock()) + val pcie_cfg_clock = Wire(Clock()) + val mmcm_lock_pcie = Wire(Bool()) + + val fpga_reset = Wire(Bool()) + val ddr_ctrlr_ready = Wire(Bool()) + + //----------------------------------------------------------------------- + // Differential clock + //----------------------------------------------------------------------- + val pf_xcvr_ref_clk = Module(new PolarFireTransceiverRefClk) + pf_xcvr_ref_clk.io.REF_CLK_PAD_P := ref_clk_pad_p + pf_xcvr_ref_clk.io.REF_CLK_PAD_N := ref_clk_pad_n + val pcie_refclk = pf_xcvr_ref_clk.io.REF_CLK + + val pf_tx_pll = Module(new PolarFireTxPLL) + pf_tx_pll.io.REF_CLK := pcie_refclk + val pf_tx_pll_bitclk = pf_tx_pll.io.BIT_CLK + val pf_tx_pll_refclk_to_lane = pf_tx_pll.io.REF_CLK_TO_LANE + val pf_tx_pll_lock = pf_tx_pll.io.LOCK + + //----------------------------------------------------------------------- + // DDR3 Subsystem Clocks + //----------------------------------------------------------------------- + val ddr3_clk_ccc = Module(new PolarFireCCC( + PLLParameters( + name = "ddr3_clk_ccc", + PLLInClockParameters(50), + Seq( + PLLOutClockParameters(111.111))))) + + ddr3_clk_ccc.io.REF_CLK_0 := ref_clk0 + val ddr3_clk_in = ddr3_clk_ccc.io.OUT0_FABCLK_0.get + val ddr3_clk_in_lock = ddr3_clk_ccc.io.PLL_LOCK_0 + mig_clock_in := ddr3_clk_in + + //----------------------------------------------------------------------- + // Coreplex Clock Generator + //----------------------------------------------------------------------- + val hart_clk_ccc = Module(new PolarFireCCC(PLLParameters( + name = "hart_clk_ccc", + PLLInClockParameters(166.666), + Seq( + PLLOutClockParameters(25), + PLLOutClockParameters(125), + PLLOutClockParameters(150))))) + + val hart_clk_25 = hart_clk_ccc.io.OUT0_FABCLK_0.get + val hart_clk_125 = hart_clk_ccc.io.OUT1_FABCLK_0.get + val hart_clk_150 = hart_clk_ccc.io.OUT2_FABCLK_0.get + val hart_clk_lock = hart_clk_ccc.io.PLL_LOCK_0 + + // DUT clock + hart_clk_ccc.io.REF_CLK_0 := mig_clock_out + dut_clock := hart_clk_25 + +// debug_io1 := dut_clock +// debug_io2 := hart_clk_lock +// debug_io3 := ddr3_clk_in + + //----------------------------------------------------------------------- + // System reset + //----------------------------------------------------------------------- + val pf_init_monitor = Module(new PolarFireInitMonitor) + + val pf_reset = Module(new PolarFireReset) + + pf_reset.io.CLK := ddr3_clk_in + pf_reset.io.PLL_LOCK := ddr3_clk_in_lock + pf_reset.io.INIT_DONE := pf_init_monitor.io.DEVICE_INIT_DONE + pf_reset.io.EXT_RST_N := pf_user_reset_n + + pf_reset.io.SS_BUSY := UInt("b0") + pf_reset.io.FF_US_RESTORE := UInt("b0") + + fpga_reset := !pf_reset.io.FABRIC_RESET_N + + sys_reset_n := pf_reset.io.FABRIC_RESET_N + +// debug_io4 := sys_reset_n + + mig_resetn := !mig_reset + pcie_dat_resetn := !pcie_dat_reset + pcie_cfg_resetn := !pcie_cfg_reset + + dut_reset_i := !pf_reset.io.FABRIC_RESET_N | !hart_clk_lock | !ddr_ctrlr_ready + +// withClockAndReset(hart_clk, fpga_reset) { +// dut_reset := ResetCatchAndSync(hart_clk, dut_reset_i, 10) +// } + withClockAndReset(dut_clock, fpga_reset) { + dut_reset := ResetCatchAndSync(dut_clock, dut_reset_i, 10) + } + + //overrided in connectMIG and connect PCIe + //provide defaults to allow above reset sequencing logic to work without both + mig_clock := dut_clock + pcie_dat_clock := dut_clock + pcie_cfg_clock := dut_clock + mig_mmcm_locked := UInt("b1") + mmcm_lock_pcie := UInt("b1") + + led(4) := dut_ndreset + led(5) := !pf_user_reset_n + led(6) := fpga_reset + led(7) := dut_reset + + //----------------------------------------------------------------------- + // PCIe Subsystem TL Clock + //----------------------------------------------------------------------- + val pf_oscillator = Module(new PolarFireOscillator) + val pf_clk_divider = Module(new PolarFireClockDivider) + val pf_glitchless_mux = Module(new PolarFireGlitchlessMux) + pf_clk_divider.io.CLK_IN := pf_oscillator.io.RCOSC_160MHZ_GL + pf_glitchless_mux.io.CLK0 := pf_clk_divider.io.CLK_OUT + pf_glitchless_mux.io.CLK1 := hart_clk_125 + pf_glitchless_mux.io.SEL := pf_init_monitor.io.PCIE_INIT_DONE + val pcie_tl_clk = pf_glitchless_mux.io.CLK_OUT + + //--------------------------------------------------------------------- + // Debug JTAG + //--------------------------------------------------------------------- + + // JTAG inside the FPGA fabric through user JTAG FPGA macro (UJTAG) +/* + val fpga_jtag = Module(new CoreJtagDebugBlock) + + fpga_jtag.io.UTDO_IN_0 := UInt("b0") + fpga_jtag.io.UTDO_IN_1 := UInt("b0") + fpga_jtag.io.UTDO_IN_2 := UInt("b0") + fpga_jtag.io.UTDO_IN_3 := UInt("b0") + fpga_jtag.io.UTDODRV_0 := UInt("b0") + fpga_jtag.io.UTDODRV_1 := UInt("b0") + fpga_jtag.io.UTDODRV_2 := UInt("b0") + fpga_jtag.io.UTDODRV_3 := UInt("b0") + + def connectDebugJTAG(dut: HasPeripheryDebugModuleImp): SystemJTAGIO = { + val djtag = dut.debug.systemjtag.get + + djtag.jtag.TCK := fpga_jtag.io.TGT_TCK + djtag.jtag.TMS := fpga_jtag.io.TGT_TMS + djtag.jtag.TDI := fpga_jtag.io.TGT_TDI + fpga_jtag.io.TGT_TDO := djtag.jtag.TDO.data + + fpga_jtag.io.TRSTB := jtag_TRSTB + fpga_jtag.io.TCK := jtag_TCK + fpga_jtag.io.TMS := jtag_TMS + fpga_jtag.io.TDI := jtag_TDI + jtag_TDO := fpga_jtag.io.TDO + + djtag.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W) + + djtag.reset := fpga_reset + dut_ndreset := dut.debug.ndreset + djtag + } +*/ + //----------------------------------------------------------------------- + // 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 + spi_flash_reset := fpga_reset + spi_flash_wp := UInt("b0") + spi_flash_hold := UInt("b0") + spi_flash_sck := dut.spi(0).sck + spi_flash_ss := dut.spi(0).cs(0) + spi_flash_sdo := dut.spi(0).dq(0).o + dut.spi(0).dq(0).i := spi_flash_sdi + } +} diff --git a/fpga-shells/src/main/scala/shell/microsemi/VeraShell.scala b/fpga-shells/src/main/scala/shell/microsemi/VeraShell.scala new file mode 100644 index 00000000..9c5f8323 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/microsemi/VeraShell.scala @@ -0,0 +1,286 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.microsemi.verashell + +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, ResetCatchAndSync, ElaborationArtefacts, HeterogeneousBag, SimpleTimer} + +import sifive.blocks.devices.gpio._ +import sifive.blocks.devices.spi._ +import sifive.blocks.devices.uart._ + +import sifive.fpgashells.ip.microsemi.{CLKINT} + +import sifive.fpgashells.devices.microsemi.polarfireddr3._ +import sifive.fpgashells.devices.microsemi.polarfireddr4._ + +import sifive.fpgashells.ip.microsemi.corejtagdebug._ +import sifive.fpgashells.ip.microsemi.polarfireccc._ +import sifive.fpgashells.ip.microsemi.polarfireinitmonitor._ +import sifive.fpgashells.ip.microsemi.polarfirereset._ + +import sifive.fpgashells.devices.microsemi.polarfireevalkitpciex4._ +import sifive.fpgashells.ip.microsemi.polarfirexcvrrefclk._ +import sifive.fpgashells.ip.microsemi.polarfiretxpll._ + +import sifive.fpgashells.ip.microsemi.polarfire_oscillator._ +import sifive.fpgashells.ip.microsemi.polarfireclockdivider._ +import sifive.fpgashells.ip.microsemi.polarfireglitchlessmux._ +import sifive.blocks.devices.chiplink._ +import sifive.fpgashells.clocks._ +//------------------------------------------------------------------------- +// Vera Shell +//------------------------------------------------------------------------- + +trait HasDDR3 { this: VeraShell => + + require(!p.lift(MemoryMicrosemiDDR3Key).isEmpty) + val ddr = IO(new PolarFireEvalKitDDR3Pads(p(MemoryMicrosemiDDR3Key))) + + def connectMIG(dut: HasMemoryPolarFireEvalKitDDR3ModuleImp): Unit = { + // Clock & Reset + dut.polarfireddrsubsys.PLL_REF_CLK := mig_clock_in + dut.polarfireddrsubsys.SYS_RESET_N := sys_reset_n + + mig_clock_out := dut.polarfireddrsubsys.SYS_CLK + mig_plllock_out := dut.polarfireddrsubsys.PLL_LOCK + ddr_ctrlr_ready := dut.polarfireddrsubsys.CTRLR_READY + + ddr <> dut.polarfireddrsubsys + } +} + +trait HasDDR4 { this: VeraShell => + + require(!p.lift(MemoryMicrosemiDDR4Key).isEmpty) + val ddr = IO(new PolarFireEvalKitDDR4Pads(p(MemoryMicrosemiDDR4Key))) + + def connectMIG(dut: HasMemoryPolarFireEvalKitDDR4ModuleImp): Unit = { + // Clock & Reset + dut.polarfireddrsubsys.PLL_REF_CLK := mig_clock_in + dut.polarfireddrsubsys.SYS_RESET_N := sys_reset_n + + mig_clock_out := dut.polarfireddrsubsys.SYS_CLK + mig_plllock_out := dut.polarfireddrsubsys.PLL_LOCK + ddr_ctrlr_ready := dut.polarfireddrsubsys.CTRLR_READY + + ddr <> dut.polarfireddrsubsys + } +} + +trait HasPCIe { this: VeraShell => + val pcie = IO(new PolarFireEvalKitPCIeX4Pads) + + def connectPCIe(dut: HasSystemPolarFireEvalKitPCIeX4ModuleImp): Unit = { + // Clock & Reset + dut.pf_eval_kit_pcie.APB_S_PCLK := hart_clk_25 + dut.pf_eval_kit_pcie.APB_S_PRESET_N := UInt("b1") + + dut.pf_eval_kit_pcie.AXI_CLK := hart_clk_125 + dut.pf_eval_kit_pcie.AXI_CLK_STABLE := hart_clk_lock + + dut.pf_eval_kit_pcie.PCIE_1_TL_CLK_125MHz := pcie_tl_clk + + dut.pf_eval_kit_pcie.PCIE_1_TX_PLL_REF_CLK := pf_tx_pll_refclk_to_lane + + dut.pf_eval_kit_pcie.PCIE_1_TX_BIT_CLK := pf_tx_pll_bitclk + + dut.pf_eval_kit_pcie.PCIESS_LANE0_CDR_REF_CLK_0 := pcie_refclk + dut.pf_eval_kit_pcie.PCIESS_LANE1_CDR_REF_CLK_0 := pcie_refclk + dut.pf_eval_kit_pcie.PCIESS_LANE2_CDR_REF_CLK_0 := pcie_refclk + dut.pf_eval_kit_pcie.PCIESS_LANE3_CDR_REF_CLK_0 := pcie_refclk + + dut.pf_eval_kit_pcie.PCIE_1_TX_PLL_LOCK := pf_tx_pll_lock + + pcie <> dut.pf_eval_kit_pcie + } +} + + +trait HasPFEvalKitChipLink { this: VeraShell => + + val chiplink = IO(new WideDataLayerPort(ChipLinkParams(Nil,Nil))) + val ereset_n = IO(Bool(INPUT)) + + def constrainChipLink(iofpga: Boolean = false): Unit = { + val direction0Pins = if(iofpga) "chiplink_b2c" else "chiplink_c2b" + val direction1Pins = if(iofpga) "chiplink_c2b" else "chiplink_b2c" + } + + def connectChipLink(dut: { val chiplink: Seq[WideDataLayerPort] } , iofpga: Boolean = false): Unit = { + constrainChipLink(iofpga) + + chiplink <> dut.chiplink(0) + } +} + +abstract class VeraShell(implicit val p: Parameters) extends RawModule { + + //----------------------------------------------------------------------- + // Interface + //----------------------------------------------------------------------- + + // 50MHz crystal oscillator + val ref_clk0 = IO(Input(Clock())) + + // + val ref_clk_pad_p = IO(Input(Bool())) + val ref_clk_pad_n = IO(Input(Bool())) + + // Reset push-button - active low + val pf_user_reset_n = IO(Input(Bool())) + + // LED +// val led = IO(Vec(8, Output(Bool()))) + val led2 = IO(Output(Bool())) + val led3 = IO(Output(Bool())) + val led4 = IO(Output(Bool())) + val led5 = IO(Output(Bool())) + + // PCIe switch reset + val pf_rstb = IO(Output(Bool())) + + // PCIe slots reset signals + val perst_x1_slot = IO(Output(Bool())) + val perst_x16_slot = IO(Output(Bool())) + val perst_m2_slot = IO(Output(Bool())) + val perst_sata_slot = IO(Output(Bool())) + + + // debug + val debug_io0 = IO(Output(Clock())) + val debug_io1 = IO(Output(Bool())) + val debug_io2 = IO(Output(Bool())) + val debug_io3 = IO(Output(Bool())) + val debug_io4 = IO(Output(Bool())) + val debug_io5 = IO(Output(Bool())) + + //----------------------------------------------------------------------- + // Wire declarations + //----------------------------------------------------------------------- + + val sys_clock = Wire(Clock()) + val sys_reset_n = Wire(Bool()) + + val dut_clock = Wire(Clock()) + val dut_reset = Wire(Bool()) + val dut_reset_i = Wire(Bool()) + val dut_reset_sync = Wire(Bool()) + + val pcie_sw_rst_complete = Wire(Bool()) + + val dut_ndreset = Wire(Bool()) + val dut_ext_reset_n = Wire(Bool()) + + val mig_mmcm_locked = Wire(Bool()) + val mig_sys_reset = Wire(Bool()) + + val mig_clock = Wire(Clock()) + val mig_reset = Wire(Bool()) + val mig_resetn = Wire(Bool()) + + val mig_clock_in = Wire(Clock()) + val mig_clock_out = Wire(Clock()) + val mig_plllock_out = Wire(Bool()) + + val ddr_ready = Wire(Bool()) + val ddr_pll_lock = Wire(Bool()) + + val pcie_dat_reset = Wire(Bool()) + val pcie_dat_resetn = Wire(Bool()) + val pcie_cfg_reset = Wire(Bool()) + val pcie_cfg_resetn = Wire(Bool()) + val pcie_dat_clock = Wire(Clock()) + val pcie_cfg_clock = Wire(Clock()) + val mmcm_lock_pcie = Wire(Bool()) + + val fpga_reset = Wire(Bool()) + val ddr_ctrlr_ready = Wire(Bool()) + + //----------------------------------------------------------------------- + // Differential clock + //----------------------------------------------------------------------- + val pf_xcvr_ref_clk = Module(new PolarFireTransceiverRefClk) + pf_xcvr_ref_clk.io.REF_CLK_PAD_P := ref_clk_pad_p + pf_xcvr_ref_clk.io.REF_CLK_PAD_N := ref_clk_pad_n + val pcie_refclk = pf_xcvr_ref_clk.io.REF_CLK + val pcie_fab_ref_clk = pf_xcvr_ref_clk.io.FAB_REF_CLK + + val pf_tx_pll = Module(new PolarFireTxPLL) + pf_tx_pll.io.REF_CLK := pcie_refclk + val pf_tx_pll_bitclk = pf_tx_pll.io.BIT_CLK + val pf_tx_pll_refclk_to_lane = pf_tx_pll.io.REF_CLK_TO_LANE + val pf_tx_pll_lock = pf_tx_pll.io.LOCK + + //----------------------------------------------------------------------- + // Coreplex Clock Generator + //----------------------------------------------------------------------- + val ref_clk_int = Module(new CLKINT) + val hart_clk_ccc = Module(new PolarFireCCC(PLLParameters( + name = "hart_clk_ccc", + PLLInClockParameters(50), + Seq( + PLLOutClockParameters(25), + PLLOutClockParameters(125), + PLLOutClockParameters(125, 31.5))))) + + val hart_clk_25 = hart_clk_ccc.io.OUT0_FABCLK_0.get + val hart_clk_125 = hart_clk_ccc.io.OUT1_FABCLK_0.get + val hart_clk_125_tx = hart_clk_ccc.io.OUT2_FABCLK_0.get + val hart_clk_lock = hart_clk_ccc.io.PLL_LOCK_0 + + ref_clk_int.io.A := ref_clk0 + hart_clk_ccc.io.REF_CLK_0 := ref_clk_int.io.Y + + // DUT clock + dut_clock := hart_clk_25 + + //----------------------------------------------------------------------- + // System reset + //----------------------------------------------------------------------- + val pf_init_monitor = Module(new PolarFireInitMonitor) + + val pf_reset = Module(new PolarFireReset) + + pf_reset.io.CLK := dut_clock + pf_reset.io.PLL_LOCK := hart_clk_lock + pf_reset.io.INIT_DONE := pf_init_monitor.io.DEVICE_INIT_DONE + pf_reset.io.EXT_RST_N := dut_ext_reset_n //ereset_n //pf_user_reset_n + + pf_reset.io.SS_BUSY := UInt("b0") + pf_reset.io.FF_US_RESTORE := UInt("b0") + + fpga_reset := !pf_reset.io.FABRIC_RESET_N & ddr_ready & ddr_pll_lock + sys_reset_n := pf_reset.io.FABRIC_RESET_N + + mig_resetn := !mig_reset + pcie_dat_resetn := !pcie_dat_reset + pcie_cfg_resetn := !pcie_cfg_reset + + dut_reset := !pf_reset.io.FABRIC_RESET_N + + + //overrided in connectMIG and connect PCIe + //provide defaults to allow above reset sequencing logic to work without both + mig_clock := dut_clock + pcie_dat_clock := dut_clock + pcie_cfg_clock := dut_clock + mig_mmcm_locked := UInt("b1") + mmcm_lock_pcie := UInt("b1") + + //----------------------------------------------------------------------- + // PCIe Subsystem TL Clock + //----------------------------------------------------------------------- + val pf_oscillator = Module(new PolarFireOscillator) + val pf_clk_divider = Module(new PolarFireClockDivider) + val pf_glitchless_mux = Module(new PolarFireGlitchlessMux) + pf_clk_divider.io.CLK_IN := pf_oscillator.io.RCOSC_160MHZ_GL + pf_glitchless_mux.io.CLK0 := pf_clk_divider.io.CLK_OUT + pf_glitchless_mux.io.CLK1 := pf_tx_pll.io.CLK_125 + pf_glitchless_mux.io.SEL := pf_init_monitor.io.PCIE_INIT_DONE + val pcie_tl_clk = pf_glitchless_mux.io.CLK_OUT +} diff --git a/fpga-shells/src/main/scala/shell/package.scala b/fpga-shells/src/main/scala/shell/package.scala new file mode 100644 index 00000000..0669f14e --- /dev/null +++ b/fpga-shells/src/main/scala/shell/package.scala @@ -0,0 +1,10 @@ +// See LICENSE for license details. +package sifive.fpgashells + +import chisel3._ +import scala.language.implicitConversions + +package object shell { + implicit def boolToIOPin(x: Bool): IOPin = IOPin(x, 0) + implicit def clockToIOPin(x: Clock): IOPin = IOPin(x, 0) +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/ArtyShell.scala b/fpga-shells/src/main/scala/shell/xilinx/ArtyShell.scala new file mode 100644 index 00000000..132403fc --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/ArtyShell.scala @@ -0,0 +1,247 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx.artyshell + +import Chisel._ +import chisel3.core.{Input, Output, attach} +import chisel3.experimental.{RawModule, Analog, withClockAndReset} + +import freechips.rocketchip.config._ +import freechips.rocketchip.devices.debug._ + +import sifive.blocks.devices.gpio._ +import sifive.blocks.devices.pwm._ +import sifive.blocks.devices.spi._ +import sifive.blocks.devices.uart._ +import sifive.blocks.devices.pinctrl.{BasePin} + +import sifive.fpgashells.ip.xilinx.{IBUFG, IOBUF, PULLUP, mmcm, reset_sys, PowerOnResetFPGAOnly} + +//------------------------------------------------------------------------- +// ArtyShell +//------------------------------------------------------------------------- + +abstract class ArtyShell(implicit val p: Parameters) extends RawModule { + + //----------------------------------------------------------------------- + // Interface + //----------------------------------------------------------------------- + + // Clock & Reset + val CLK100MHZ = IO(Input(Clock())) + val ck_rst = IO(Input(Bool())) + + // Green LEDs + val led_0 = IO(Analog(1.W)) + val led_1 = IO(Analog(1.W)) + val led_2 = IO(Analog(1.W)) + val led_3 = IO(Analog(1.W)) + + // RGB LEDs, 3 pins each + val led0_r = IO(Analog(1.W)) + val led0_g = IO(Analog(1.W)) + val led0_b = IO(Analog(1.W)) + + val led1_r = IO(Analog(1.W)) + val led1_g = IO(Analog(1.W)) + val led1_b = IO(Analog(1.W)) + + val led2_r = IO(Analog(1.W)) + val led2_g = IO(Analog(1.W)) + val led2_b = IO(Analog(1.W)) + + // Sliding switches + val sw_0 = IO(Analog(1.W)) + val sw_1 = IO(Analog(1.W)) + val sw_2 = IO(Analog(1.W)) + val sw_3 = IO(Analog(1.W)) + + // Buttons. First 3 used as GPIO, the last is used as wakeup + val btn_0 = IO(Analog(1.W)) + val btn_1 = IO(Analog(1.W)) + val btn_2 = IO(Analog(1.W)) + val btn_3 = IO(Analog(1.W)) + + // Dedicated QSPI interface + val qspi_cs = IO(Analog(1.W)) + val qspi_sck = IO(Analog(1.W)) + val qspi_dq = IO(Vec(4, Analog(1.W))) + + // UART0 + val uart_rxd_out = IO(Analog(1.W)) + val uart_txd_in = IO(Analog(1.W)) + + // JA (Used for more generic GPIOs) + val ja_0 = IO(Analog(1.W)) + val ja_1 = IO(Analog(1.W)) + val ja_2 = IO(Analog(1.W)) + val ja_3 = IO(Analog(1.W)) + val ja_4 = IO(Analog(1.W)) + val ja_5 = IO(Analog(1.W)) + val ja_6 = IO(Analog(1.W)) + val ja_7 = IO(Analog(1.W)) + + // JD (used for JTAG connection) + val jd_0 = IO(Analog(1.W)) // TDO + val jd_1 = IO(Analog(1.W)) // TRST_n + val jd_2 = IO(Analog(1.W)) // TCK + val jd_4 = IO(Analog(1.W)) // TDI + val jd_5 = IO(Analog(1.W)) // TMS + val jd_6 = IO(Analog(1.W)) // SRST_n + + // ChipKit Digital I/O Pins + val ck_io = IO(Vec(20, Analog(1.W))) + + // ChipKit SPI + val ck_miso = IO(Analog(1.W)) + val ck_mosi = IO(Analog(1.W)) + val ck_ss = IO(Analog(1.W)) + val ck_sck = IO(Analog(1.W)) + + //----------------------------------------------------------------------- + // Wire declrations + //----------------------------------------------------------------------- + + // Note: these frequencies are approximate. + val clock_8MHz = Wire(Clock()) + val clock_32MHz = Wire(Clock()) + val clock_65MHz = Wire(Clock()) + + val mmcm_locked = Wire(Bool()) + + val reset_core = Wire(Bool()) + val reset_bus = Wire(Bool()) + val reset_periph = Wire(Bool()) + val reset_intcon_n = Wire(Bool()) + val reset_periph_n = Wire(Bool()) + + val SRST_n = Wire(Bool()) + + val dut_jtag_TCK = Wire(Clock()) + val dut_jtag_TMS = Wire(Bool()) + val dut_jtag_TDI = Wire(Bool()) + val dut_jtag_TDO = Wire(Bool()) + val dut_jtag_reset = Wire(Bool()) + val dut_ndreset = Wire(Bool()) + + //----------------------------------------------------------------------- + // Clock Generator + //----------------------------------------------------------------------- + // Mixed-mode clock generator + + val ip_mmcm = Module(new mmcm()) + + ip_mmcm.io.clk_in1 := CLK100MHZ + clock_8MHz := ip_mmcm.io.clk_out1 // 8.388 MHz = 32.768 kHz * 256 + clock_65MHz := ip_mmcm.io.clk_out2 // 65 Mhz + clock_32MHz := ip_mmcm.io.clk_out3 // 65/2 Mhz + ip_mmcm.io.resetn := ck_rst + mmcm_locked := ip_mmcm.io.locked + + //----------------------------------------------------------------------- + // System Reset + //----------------------------------------------------------------------- + // processor system reset module + + val ip_reset_sys = Module(new reset_sys()) + + ip_reset_sys.io.slowest_sync_clk := clock_8MHz + ip_reset_sys.io.ext_reset_in := ck_rst & SRST_n + ip_reset_sys.io.aux_reset_in := true.B + ip_reset_sys.io.mb_debug_sys_rst := dut_ndreset + ip_reset_sys.io.dcm_locked := mmcm_locked + + reset_core := ip_reset_sys.io.mb_reset + reset_bus := ip_reset_sys.io.bus_struct_reset + reset_periph := ip_reset_sys.io.peripheral_reset + reset_intcon_n := ip_reset_sys.io.interconnect_aresetn + reset_periph_n := ip_reset_sys.io.peripheral_aresetn + + //----------------------------------------------------------------------- + // SPI Flash + //----------------------------------------------------------------------- + + def connectSPIFlash(dut: HasPeripherySPIFlashModuleImp): Unit = { + val qspiParams = p(PeripherySPIFlashKey) + if (!qspiParams.isEmpty) { + val qspi_params = qspiParams(0) + val qspi_pins = Wire(new SPIPins(() => {new BasePin()}, qspi_params)) + + SPIPinsFromPort(qspi_pins, + dut.qspi(0), + dut.clock, + dut.reset, + syncStages = qspi_params.defaultSampleDel + ) + + IOBUF(qspi_sck, dut.qspi(0).sck) + IOBUF(qspi_cs, dut.qspi(0).cs(0)) + + (qspi_dq zip qspi_pins.dq).foreach { + case(a, b) => IOBUF(a,b) + } + } + } + + //--------------------------------------------------------------------- + // Debug JTAG + //--------------------------------------------------------------------- + + def connectDebugJTAG(dut: HasPeripheryDebugModuleImp): SystemJTAGIO = { + + //------------------------------------------------------------------- + // JTAG Reset + //------------------------------------------------------------------- + + val jtag_power_on_reset = PowerOnResetFPGAOnly(clock_32MHz) + + dut_jtag_reset := jtag_power_on_reset + + //------------------------------------------------------------------- + // JTAG IOBUFs + //------------------------------------------------------------------- + + dut_jtag_TCK := IBUFG(IOBUF(jd_2).asClock) + + dut_jtag_TMS := IOBUF(jd_5) + PULLUP(jd_5) + + dut_jtag_TDI := IOBUF(jd_4) + PULLUP(jd_4) + + IOBUF(jd_0, dut_jtag_TDO) + + SRST_n := IOBUF(jd_6) + PULLUP(jd_6) + + //------------------------------------------------------------------- + // JTAG PINS + //------------------------------------------------------------------- + + val djtag = dut.debug.systemjtag.get + + djtag.jtag.TCK := dut_jtag_TCK + djtag.jtag.TMS := dut_jtag_TMS + djtag.jtag.TDI := dut_jtag_TDI + dut_jtag_TDO := djtag.jtag.TDO.data + + djtag.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W) + + djtag.reset := dut_jtag_reset + dut_ndreset := dut.debug.ndreset + + djtag + } + + //--------------------------------------------------------------------- + // UART + //--------------------------------------------------------------------- + + def connectUART(dut: HasPeripheryUARTModuleImp): Unit = { + val uartParams = p(PeripheryUARTKey) + if (!uartParams.isEmpty) { + IOBUF(uart_rxd_out, dut.uart(0).txd) + dut.uart(0).rxd := IOBUF(uart_txd_in) + } + } + +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/ChipLinkOverlay.scala b/fpga-shells/src/main/scala/shell/xilinx/ChipLinkOverlay.scala new file mode 100644 index 00000000..894647b3 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/ChipLinkOverlay.scala @@ -0,0 +1,71 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx + +import chisel3._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.util._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.ip.xilinx._ + +abstract class ChipLinkXilinxOverlay(params: ChipLinkOverlayParams, rxPhase: Double, txPhase: Double, rxMargin: Double, txMargin: Double) + extends ChipLinkOverlay(params.copy(params = params.params.copy(fpgaReset = true))(params.p), rxPhase, txPhase) +{ + def shell: XilinxShell + + InModuleBody { + // Provide reset pulse to initialize b2c_reset (before RX PLL locks) + link.module.io.fpga_reset.foreach { _ := PowerOnResetFPGAOnly(Module.clock) } + } + + shell { InModuleBody { + val (tx, _) = txClock.in(0) + val (rx, _) = rxI.out(0) + val rxEdge = rxI.edges.out(0) + + val oddr = Module(new ODDR(DDR_CLK_EDGE = "SAME_EDGE", SRTYPE = "ASYNC")) + oddr.suggestName(s"${name}_tx_oddr") + io.c2b.clk := oddr.io.Q.asClock + oddr.io.C := tx.clock + oddr.io.CE := true.B + oddr.io.D1 := true.B + oddr.io.D2 := false.B + oddr.io.S := false.B + // We can't use tx.reset here as it waits for all PLLs to lock, + // including RX, which depends on this clock being driven. + // tap.reset only waits for the TX PLL to lock. + oddr.io.R := ResetCatchAndSync(tx.clock, PowerOnResetFPGAOnly(tx.clock)) + + val ibufg = Module(new IBUFG) + ibufg.suggestName(s"${name}_rx_ibufg") + ibufg.io.I := io.b2c.clk + rx.clock := ibufg.io.O + rx.reset := shell.pllReset + + IOPin.of(io).foreach { shell.xdc.addIOStandard(_, "LVCMOS18") } + IOPin.of(io).filterNot(_.element eq io.b2c.clk).foreach { shell.xdc.addIOB(_) } + IOPin.of(io).filter(_.isOutput).foreach { shell.xdc.addSlew(_, "FAST") } + + val timing = IOTiming( + /* The data signals coming from Aloe have: clock - 1.2 <= transition <= clock + 0.8 + * min = hold = - 1.2 + * max = period - setup = 0.8 + */ + minInput = -1.2 - rxMargin, + maxInput = 0.8 + rxMargin, + /* The data signals going to Aloe must have: clock - 1.85 <= NO transition <= clock + 0.65 + * min = -hold = -0.65 + * max = setup = 1.85 + */ + minOutput = -0.65 - txMargin, + maxOutput = 1.85 + txMargin) + + shell.sdc.addClock(s"${name}_b2c_clock", io.b2c.clk, rxEdge.clock.freqMHz, 0.3) + shell.sdc.addDerivedClock(s"${name}_c2b_clock", oddr.io.C, io.c2b.clk) + IOPin.of(io).filter(p => p.isInput && !(p.element eq io.b2c.clk)).foreach { e => + shell.sdc.addIOTiming(e, s"${name}_b2c_clock", timing) + } + IOPin.of(io).filter(p => p.isOutput && !(p.element eq io.c2b.clk)).foreach { e => + shell.sdc.addIOTiming(e, s"${name}_c2b_clock", timing) + } + } } +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/ClockOverlay.scala b/fpga-shells/src/main/scala/shell/xilinx/ClockOverlay.scala new file mode 100644 index 00000000..3e885caa --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/ClockOverlay.scala @@ -0,0 +1,24 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx + +import chisel3._ +import freechips.rocketchip.diplomacy._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.ip.xilinx._ + +abstract class LVDSClockInputXilinxOverlay(params: ClockInputOverlayParams) + extends LVDSClockInputOverlay(params) +{ + def shell: XilinxShell + + shell { InModuleBody { + val ibufds = Module(new IBUFDS) + ibufds.suggestName(s"${name}_ibufds") + + val (c, _) = node.out(0) + ibufds.io.I := io.p + ibufds.io.IB := io.n + c.clock := ibufds.io.O + c.reset := shell.pllReset + } } +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/JTAGDebugOverlay.scala b/fpga-shells/src/main/scala/shell/xilinx/JTAGDebugOverlay.scala new file mode 100644 index 00000000..2e1626c6 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/JTAGDebugOverlay.scala @@ -0,0 +1,13 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx + +import chisel3._ +import freechips.rocketchip.diplomacy._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.ip.xilinx._ + +abstract class JTAGDebugXilinxOverlay(params: JTAGDebugOverlayParams) + extends JTAGDebugOverlay(params) +{ + def shell: XilinxShell +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/LEDOverlay.scala b/fpga-shells/src/main/scala/shell/xilinx/LEDOverlay.scala new file mode 100644 index 00000000..45340783 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/LEDOverlay.scala @@ -0,0 +1,26 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx + +import chisel3._ +import freechips.rocketchip.diplomacy._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.ip.xilinx._ + +abstract class LEDXilinxOverlay(params: LEDOverlayParams, boardPins: Seq[String] = Nil, packagePins: Seq[String] = Nil) + extends LEDOverlay(params) +{ + def shell: XilinxShell + val width = boardPins.size + packagePins.size + + shell { InModuleBody { + io := ledSink.bundle // could/should put OBUFs here? + + val cutAt = boardPins.size + val ios = IOPin.of(io) + val boardIOs = ios.take(cutAt) + val packageIOs = ios.drop(cutAt) + + (boardPins zip boardIOs) foreach { case (pin, io) => shell.xdc.addBoardPin (io, pin) } + (packagePins zip packageIOs) foreach { case (pin, io) => shell.xdc.addPackagePin(io, pin) } + } } +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/SDIOOverlay.scala b/fpga-shells/src/main/scala/shell/xilinx/SDIOOverlay.scala new file mode 100644 index 00000000..58c321a8 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/SDIOOverlay.scala @@ -0,0 +1,13 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx + +import chisel3._ +import freechips.rocketchip.diplomacy._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.ip.xilinx._ + +abstract class SDIOXilinxOverlay(params: SDIOOverlayParams) + extends SDIOOverlay(params) +{ + def shell: XilinxShell +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/SwitchOverlay.scala b/fpga-shells/src/main/scala/shell/xilinx/SwitchOverlay.scala new file mode 100644 index 00000000..f19694b7 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/SwitchOverlay.scala @@ -0,0 +1,33 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx + +import chisel3._ +import freechips.rocketchip.diplomacy._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.ip.xilinx._ + +abstract class SwitchXilinxOverlay(params: SwitchOverlayParams, boardPins: Seq[String] = Nil, packagePins: Seq[String] = Nil) + extends SwitchOverlay(params) +{ + def shell: XilinxShell + val width = boardPins.size + packagePins.size + + shell { InModuleBody { + val vec = Wire(Vec(width, Bool())) + switchSource.out(0)._1 := vec.asUInt + (vec zip io.toBools).zipWithIndex.foreach { case ((o, i), idx) => + val ibuf = Module(new IBUF) + ibuf.suggestName(s"switch_ibuf_${idx}") + ibuf.io.I := i + o := ibuf.io.O + } + + val cutAt = boardPins.size + val ios = IOPin.of(io) + val boardIOs = ios.take(cutAt) + val packageIOs = ios.drop(cutAt) + + (boardPins zip boardIOs) foreach { case (pin, io) => shell.xdc.addBoardPin (io, pin) } + (packagePins zip packageIOs) foreach { case (pin, io) => shell.xdc.addPackagePin(io, pin) } + } } +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/UARTOverlay.scala b/fpga-shells/src/main/scala/shell/xilinx/UARTOverlay.scala new file mode 100644 index 00000000..324aaa0e --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/UARTOverlay.scala @@ -0,0 +1,13 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx + +import chisel3._ +import freechips.rocketchip.diplomacy._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.ip.xilinx._ + +abstract class UARTXilinxOverlay(params: UARTOverlayParams) + extends UARTOverlay(params) +{ + def shell: XilinxShell +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/UltraScaleShell.scala b/fpga-shells/src/main/scala/shell/xilinx/UltraScaleShell.scala new file mode 100644 index 00000000..d54ca100 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/UltraScaleShell.scala @@ -0,0 +1,81 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx + +import chisel3._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import sifive.fpgashells.clocks._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.ip.xilinx._ +import sifive.fpgashells.devices.xilinx.xdma._ + + +class XDMATopPads(val numLanes: Int) extends Bundle { + val refclk = Input(new LVDSClock) + val lanes = new XDMAPads(numLanes) +} + +class XDMABridge(val numLanes: Int) extends Bundle { + val lanes = new XDMAPads(numLanes) + val srstn = Input(Bool()) + val O = Input(Clock()) + val ODIV2 = Input(Clock()) +} + +abstract class PCIeUltraScaleOverlay(config: XDMAParams, params: PCIeOverlayParams) + extends PCIeOverlay[XDMATopPads](params) +{ + def shell: UltraScaleShell + + val pcie = LazyModule(new XDMA(config)) + val bridge = BundleBridgeSource(() => new XDMABridge(config.lanes)) + val topBridge = shell { bridge.makeSink() } + val axiClk = ClockSourceNode(freqMHz = config.axiMHz) + val areset = ClockSinkNode(Seq(ClockSinkParameters())) + areset := params.wrangler := axiClk + + val slaveSide = TLIdentityNode() + pcie.crossTLIn(pcie.slave) := slaveSide + pcie.crossTLIn(pcie.control) := slaveSide + val node = NodeHandle(slaveSide, pcie.crossTLOut(pcie.master)) + val intnode = pcie.crossIntOut(pcie.intnode) + + def designOutput = (node, intnode) + def ioFactory = new XDMATopPads(config.lanes) + + InModuleBody { + val (axi, _) = axiClk.out(0) + val (ar, _) = areset.in(0) + val b = bridge.out(0)._1 + + pcie.module.clock := ar.clock + pcie.module.reset := ar.reset + + b.lanes <> pcie.module.io.pads + + axi.clock := pcie.module.io.clocks.axi_aclk + axi.reset := !pcie.module.io.clocks.axi_aresetn + pcie.module.io.clocks.sys_rst_n := b.srstn + pcie.module.io.clocks.sys_clk := b.ODIV2 + pcie.module.io.clocks.sys_clk_gt := b.O + + shell.sdc.addGroup(clocks = Seq(s"${name}_ref_clk", "pipe_clk"), pins = Seq(pcie.imp.module.blackbox.io.axi_aclk)) + } + + shell { InModuleBody { + val b = topBridge.in(0)._1 + + val ibufds = Module(new IBUFDS_GTE4) + ibufds.suggestName(s"${name}_refclk_ibufds") + ibufds.io.CEB := false.B + ibufds.io.I := io.refclk.p + ibufds.io.IB := io.refclk.n + b.O := ibufds.io.O + b.ODIV2 := ibufds.io.ODIV2 + b.srstn := !shell.pllReset + io.lanes <> b.lanes + + shell.sdc.addClock(s"${name}_ref_clk", io.refclk.p, 100) + } } +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/VC707NewShell.scala b/fpga-shells/src/main/scala/shell/xilinx/VC707NewShell.scala new file mode 100644 index 00000000..f02e4d13 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/VC707NewShell.scala @@ -0,0 +1,237 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx + +import chisel3._ +import chisel3.experimental.{attach, IO, withClockAndReset} +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util.SyncResetSynchronizerShiftReg +import sifive.fpgashells.clocks._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.ip.xilinx._ +import sifive.blocks.devices.chiplink._ +import sifive.fpgashells.devices.xilinx.xilinxvc707mig._ +import sifive.fpgashells.devices.xilinx.xilinxvc707pciex1._ + +class SysClockVC707Overlay(val shell: VC707Shell, val name: String, params: ClockInputOverlayParams) + extends LVDSClockInputXilinxOverlay(params) +{ + val node = shell { ClockSourceNode(freqMHz = 200, jitterPS = 50)(ValName(name)) } + + shell { InModuleBody { + shell.xdc.addBoardPin(io.p, "clk_p") + shell.xdc.addBoardPin(io.n, "clk_n") + } } +} + +class SDIOVC707Overlay(val shell: VC707Shell, val name: String, params: SDIOOverlayParams) + extends SDIOXilinxOverlay(params) +{ + shell { InModuleBody { + val packagePinsWithPackageIOs = Seq(("AN30", IOPin(io.sdio_clk)), + ("AP30", IOPin(io.sdio_cmd)), + ("AR30", IOPin(io.sdio_dat_0)), + ("AU31", IOPin(io.sdio_dat_1)), + ("AV31", IOPin(io.sdio_dat_2)), + ("AT30", IOPin(io.sdio_dat_3))) + + packagePinsWithPackageIOs foreach { case (pin, io) => { + shell.xdc.addPackagePin(io, pin) + shell.xdc.addIOStandard(io, "LVCMOS18") + shell.xdc.addIOB(io) + } } + packagePinsWithPackageIOs drop 1 foreach { case (pin, io) => { + shell.xdc.addPullup(io) + } } + } } +} + +class UARTVC707Overlay(val shell: VC707Shell, val name: String, params: UARTOverlayParams) + extends UARTXilinxOverlay(params) +{ + shell { InModuleBody { + val packagePinsWithPackageIOs = Seq(("AT32", IOPin(io.ctsn)), + ("AR34", IOPin(io.rtsn)), + ("AU33", IOPin(io.rxd)), + ("AU36", IOPin(io.txd))) + + packagePinsWithPackageIOs foreach { case (pin, io) => { + shell.xdc.addPackagePin(io, pin) + shell.xdc.addIOStandard(io, "LVCMOS18") + shell.xdc.addIOB(io) + } } + } } +} + +class LEDVC707Overlay(val shell: VC707Shell, val name: String, params: LEDOverlayParams) + extends LEDXilinxOverlay(params, boardPins = Seq.tabulate(8) { i => s"leds_8bits_tri_o_$i" }) + +class SwitchVC707Overlay(val shell: VC707Shell, val name: String, params: SwitchOverlayParams) + extends SwitchXilinxOverlay(params, boardPins = Seq.tabulate(8) { i => s"dip_switches_tri_i_$i" }) + +class ChipLinkVC707Overlay(val shell: VC707Shell, val name: String, params: ChipLinkOverlayParams) + extends ChipLinkXilinxOverlay(params, rxPhase=280, txPhase=220, rxMargin=0.3, txMargin=0.3) +{ + val ereset_n = shell { InModuleBody { + val ereset_n = IO(Input(Bool())) + ereset_n.suggestName("ereset_n") + shell.xdc.addPackagePin(ereset_n, "AF40") + shell.xdc.addIOStandard(ereset_n, "LVCMOS18") + shell.xdc.addTermination(ereset_n, "NONE") + ereset_n + } } + + shell { InModuleBody { + val dir1 = Seq("AF39", "AJ41", "AJ40", /* clk, rst, send */ + "AD40", "AD41", "AF41", "AG41", "AK39", "AL39", "AJ42", "AK42", + "AL41", "AL42", "AF42", "AG42", "AD38", "AE38", "AC40", "AC41", + "AD42", "AE42", "AJ38", "AK38", "AB41", "AB42", "Y42", "AA42", + "Y39", "AA39", "W40", "Y40", "AB38", "AB39", "AC38", "AC39") + val dir2 = Seq("U39", "R37", "T36", /* clk, rst, send */ + "U37", "U38", "U36", "T37", "U32", "U33", "V33", "V34", + "P35", "P36", "W32", "W33", "R38", "R39", "U34", "T35", + "R33", "R34", "N33", "N34", "P32", "P33", "V35", "V36", + "W36", "W37", "T32", "R32", "V39", "V40", "P37", "P38") + (IOPin.of(io.b2c) zip dir1) foreach { case (io, pin) => shell.xdc.addPackagePin(io, pin) } + (IOPin.of(io.c2b) zip dir2) foreach { case (io, pin) => shell.xdc.addPackagePin(io, pin) } + } } +} + +// TODO: JTAG is untested +class JTAGDebugVC707Overlay(val shell: VC707Shell, val name: String, params: JTAGDebugOverlayParams) + extends JTAGDebugXilinxOverlay(params) +{ + shell { InModuleBody { + shell.sdc.addClock("JTCK", IOPin(io.jtag_TCK), 10) + shell.sdc.addGroup(clocks = Seq("JTCK")) + shell.xdc.clockDedicatedRouteFalse(IOPin(io.jtag_TCK)) + val packagePinsWithPackageIOs = Seq(("R32", IOPin(io.jtag_TCK)), + ("W36", IOPin(io.jtag_TMS)), + ("W37", IOPin(io.jtag_TDI)), + ("V40", IOPin(io.jtag_TDO))) + + packagePinsWithPackageIOs foreach { case (pin, io) => { + shell.xdc.addPackagePin(io, pin) + shell.xdc.addIOStandard(io, "LVCMOS18") + shell.xdc.addPullup(io) + } } + } } +} + +case object VC707DDRSize extends Field[BigInt](0x40000000L * 1) // 1GB +class DDRVC707Overlay(val shell: VC707Shell, val name: String, params: DDROverlayParams) + extends DDROverlay[XilinxVC707MIGPads](params) +{ + val size = p(VC707DDRSize) + + val migParams = XilinxVC707MIGParams(address = AddressSet.misaligned(params.baseAddress, size)) + val mig = LazyModule(new XilinxVC707MIG(migParams)) + val ioNode = BundleBridgeSource(() => mig.module.io.cloneType) + val topIONode = shell { ioNode.makeSink() } + val ddrUI = shell { ClockSourceNode(freqMHz = 200) } + val areset = shell { ClockSinkNode(Seq(ClockSinkParameters())) } + areset := params.wrangler := ddrUI + + def designOutput = mig.node + def ioFactory = new XilinxVC707MIGPads(size) + + InModuleBody { ioNode.bundle <> mig.module.io } + + shell { InModuleBody { + require (shell.sys_clock.isDefined, "Use of DDRVC707Overlay depends on SysClockVC707Overlay") + val (sys, _) = shell.sys_clock.get.node.out(0) + val (ui, _) = ddrUI.out(0) + val (ar, _) = areset.in(0) + val port = topIONode.bundle.port + io <> port + ui.clock := port.ui_clk + ui.reset := !port.mmcm_locked || port.ui_clk_sync_rst + port.sys_clk_i := sys.clock.asUInt + port.sys_rst := sys.reset // pllReset + port.aresetn := !ar.reset + } } + + shell.sdc.addGroup(clocks = Seq("clk_pll_i")) +} + +class PCIeVC707Overlay(val shell: VC707Shell, val name: String, params: PCIeOverlayParams) + extends PCIeOverlay[XilinxVC707PCIeX1Pads](params) +{ + val pcie = LazyModule(new XilinxVC707PCIeX1) + val ioNode = BundleBridgeSource(() => pcie.module.io.cloneType) + val topIONode = shell { ioNode.makeSink() } + val axiClk = shell { ClockSourceNode(freqMHz = 125) } + val areset = shell { ClockSinkNode(Seq(ClockSinkParameters())) } + areset := params.wrangler := axiClk + + val slaveSide = TLIdentityNode() + pcie.crossTLIn(pcie.slave) := slaveSide + pcie.crossTLIn(pcie.control) := slaveSide + val node = NodeHandle(slaveSide, pcie.crossTLOut(pcie.master)) + val intnode = pcie.crossIntOut(pcie.intnode) + + def designOutput = (node, intnode) + def ioFactory = new XilinxVC707PCIeX1Pads + + InModuleBody { ioNode.bundle <> pcie.module.io } + + shell { InModuleBody { + val (axi, _) = axiClk.out(0) + val (ar, _) = areset.in(0) + val port = topIONode.bundle.port + io <> port + axi.clock := port.axi_aclk_out + axi.reset := !port.mmcm_lock + port.axi_aresetn := !ar.reset + port.axi_ctl_aresetn := !ar.reset + + shell.xdc.addPackagePin(io.REFCLK_rxp, "A10") + shell.xdc.addPackagePin(io.REFCLK_rxn, "A9") + shell.xdc.addPackagePin(io.pci_exp_txp, "H4") + shell.xdc.addPackagePin(io.pci_exp_txn, "H3") + shell.xdc.addPackagePin(io.pci_exp_rxp, "G6") + shell.xdc.addPackagePin(io.pci_exp_rxn, "G5") + + shell.sdc.addClock(s"${name}_ref_clk", io.REFCLK_rxp, 100) + } } + + shell.sdc.addGroup(clocks = Seq("txoutclk", "userclk1")) +} + +class VC707Shell()(implicit p: Parameters) extends Series7Shell +{ + // PLL reset causes + val pllReset = InModuleBody { Wire(Bool()) } + + // Order matters; ddr depends on sys_clock + val sys_clock = Overlay(ClockInputOverlayKey)(new SysClockVC707Overlay(_, _, _)) + val led = Overlay(LEDOverlayKey) (new LEDVC707Overlay (_, _, _)) + val switch = Overlay(SwitchOverlayKey) (new SwitchVC707Overlay (_, _, _)) + val chiplink = Overlay(ChipLinkOverlayKey) (new ChipLinkVC707Overlay(_, _, _)) + val ddr = Overlay(DDROverlayKey) (new DDRVC707Overlay (_, _, _)) + val pcie = Overlay(PCIeOverlayKey) (new PCIeVC707Overlay (_, _, _)) + val uart = Overlay(UARTOverlayKey) (new UARTVC707Overlay (_, _, _)) + val sdio = Overlay(SDIOOverlayKey) (new SDIOVC707Overlay (_, _, _)) + val jtag = Overlay(JTAGDebugOverlayKey) (new JTAGDebugVC707Overlay (_, _, _)) + + val topDesign = LazyModule(p(DesignKey)(designParameters)) + + // Place the sys_clock at the Shell if the user didn't ask for it + p(ClockInputOverlayKey).foreach(_(ClockInputOverlayParams())) + + override lazy val module = new LazyRawModuleImp(this) { + val reset = IO(Input(Bool())) + xdc.addBoardPin(reset, "reset") + + val reset_ibuf = Module(new IBUF) + reset_ibuf.io.I := reset + + val powerOnReset = PowerOnResetFPGAOnly(sys_clock.get.clock) + sdc.addAsyncPath(Seq(powerOnReset)) + + pllReset := + reset_ibuf.io.O || powerOnReset || + chiplink.map(!_.ereset_n).getOrElse(false.B) + } +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/VC707Shell.scala b/fpga-shells/src/main/scala/shell/xilinx/VC707Shell.scala new file mode 100644 index 00000000..6db0828f --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/VC707Shell.scala @@ -0,0 +1,611 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx.vc707shell + +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.fpgashells.devices.xilinx.xilinxvc707mig._ +import sifive.fpgashells.devices.xilinx.xilinxvc707pciex1._ +import sifive.fpgashells.ip.xilinx.{IBUFDS, PowerOnResetFPGAOnly, sdio_spi_bridge, Series7MMCM, vc707reset} + +//vc707_sys_clock_mmcm0, vc707_sys_clock_, vc707_sys_clock_mmcm2 , vc707reset} +import sifive.fpgashells.clocks._ +//------------------------------------------------------------------------- +// VC707Shell +//------------------------------------------------------------------------- + +trait HasDDR3 { this: VC707Shell => + + require(!p.lift(MemoryXilinxDDRKey).isEmpty) + val ddr = IO(new XilinxVC707MIGPads(p(MemoryXilinxDDRKey))) + + def connectMIG(dut: HasMemoryXilinxVC707MIGModuleImp): Unit = { + // Clock & Reset + dut.xilinxvc707mig.sys_clk_i := sys_clock.asUInt + mig_clock := dut.xilinxvc707mig.ui_clk + mig_sys_reset := dut.xilinxvc707mig.ui_clk_sync_rst + mig_mmcm_locked := dut.xilinxvc707mig.mmcm_locked + dut.xilinxvc707mig.aresetn := mig_resetn + dut.xilinxvc707mig.sys_rst := sys_reset + + ddr <> dut.xilinxvc707mig + } +} + +trait HasPCIe { this: VC707Shell => + val pcie = IO(new XilinxVC707PCIeX1Pads) + + def connectPCIe(dut: HasSystemXilinxVC707PCIeX1ModuleImp): Unit = { + // Clock & Reset + dut.xilinxvc707pcie.axi_aresetn := pcie_dat_resetn + pcie_dat_clock := dut.xilinxvc707pcie.axi_aclk_out + pcie_cfg_clock := dut.xilinxvc707pcie.axi_ctl_aclk_out + mmcm_lock_pcie := dut.xilinxvc707pcie.mmcm_lock + dut.xilinxvc707pcie.axi_ctl_aresetn := pcie_dat_resetn + + pcie <> dut.xilinxvc707pcie + } +} + +trait HasDebugJTAG { this: VC707Shell => + // 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 = { + + ElaborationArtefacts.add( + """debugjtag.vivado.tcl""", + """set vc707debugjtag_vivado_tcl_dir [file dirname [file normalize [info script]]] + add_files -fileset [current_fileset -constrset] [glob -directory $vc707debugjtag_vivado_tcl_dir {*.vc707debugjtag.xdc}]""" + ) + + if(fmcxm105) { + //VC707 constraints for Xilinx FMC XM105 Debug Card + ElaborationArtefacts.add( + """vc707debugjtag.xdc""", + """set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_TCK] + set_property -dict { PACKAGE_PIN R32 IOSTANDARD LVCMOS18 PULLUP TRUE } [get_ports {jtag_TCK}] + set_property -dict { PACKAGE_PIN W36 IOSTANDARD LVCMOS18 PULLUP TRUE } [get_ports {jtag_TMS}] + set_property -dict { PACKAGE_PIN W37 IOSTANDARD LVCMOS18 PULLUP TRUE } [get_ports {jtag_TDI}] + set_property -dict { PACKAGE_PIN V40 IOSTANDARD LVCMOS18 PULLUP TRUE } [get_ports {jtag_TDO}] + create_clock -add -name JTCK -period 100 -waveform {0 50} [get_ports {jtag_TCK}];""" + ) + } else { + //VC707 constraints for Olimex connect to LCD panel header + ElaborationArtefacts.add( + """vc707debugjtag.xdc""", + """ + #Olimex Pin Olimex Function LCD Pin LCD Function FPGA Pin + #1 VREF 14 5V + #3 TTRST_N 1 LCD_DB7 AN40 + #5 TTDI 2 LCD_DB6 AR39 + #7 TTMS 3 LCD_DB5 AR38 + #9 TTCK 4 LCD_DB4 AT42 + #11 TRTCK NC NC NC + #13 TTDO 9 LCD_E AT40 + #15 TSRST_N 10 LCD_RW AR42 + #2 VREF 14 5V + #18 GND 13 GND + set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_TCK] + set_property -dict { PACKAGE_PIN AT42 IOSTANDARD LVCMOS18 PULLUP TRUE } [get_ports {jtag_TCK}] + set_property -dict { PACKAGE_PIN AR38 IOSTANDARD LVCMOS18 PULLUP TRUE } [get_ports {jtag_TMS}] + set_property -dict { PACKAGE_PIN AR39 IOSTANDARD LVCMOS18 PULLUP TRUE } [get_ports {jtag_TDI}] + set_property -dict { PACKAGE_PIN AT40 IOSTANDARD LVCMOS18 PULLUP TRUE } [get_ports {jtag_TDO}] + create_clock -add -name JTCK -period 100 -waveform {0 50} [get_ports {jtag_TCK}];""" + ) + } + + 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 + } +} + +trait HasVC707ChipLink { this: VC707Shell => + + val chiplink = IO(new WideDataLayerPort(ChipLinkParams(Nil,Nil))) + val ereset_n = IO(Bool(INPUT)) + + def constrainChipLink(iofpga: Boolean = false): Unit = { + val direction0Pins = if(iofpga) "chiplink_b2c" else "chiplink_c2b" + val direction1Pins = if(iofpga) "chiplink_c2b" else "chiplink_b2c" + + ElaborationArtefacts.add( + """vc707chiplink.vivado.tcl""", + """set vc707chiplink_vivado_tcl_dir [file dirname [file normalize [info script]]] + add_files -fileset [current_fileset -constrset] [glob -directory $vc707chiplink_vivado_tcl_dir {*.vc707chiplink.xdc}]""" + ) + + ElaborationArtefacts.add( + """vc707chiplink.xdc""", s""" + set_property PACKAGE_PIN AF39 [get_ports ${direction0Pins}_clk] + set_property PACKAGE_PIN AD40 [get_ports {${direction0Pins}_data[0]}] + set_property PACKAGE_PIN AD41 [get_ports {${direction0Pins}_data[1]}] + set_property PACKAGE_PIN AF41 [get_ports {${direction0Pins}_data[2]}] + set_property PACKAGE_PIN AG41 [get_ports {${direction0Pins}_data[3]}] + set_property PACKAGE_PIN AK39 [get_ports {${direction0Pins}_data[4]}] + set_property PACKAGE_PIN AL39 [get_ports {${direction0Pins}_data[5]}] + set_property PACKAGE_PIN AJ42 [get_ports {${direction0Pins}_data[6]}] + set_property PACKAGE_PIN AK42 [get_ports {${direction0Pins}_data[7]}] + set_property PACKAGE_PIN AL41 [get_ports {${direction0Pins}_data[8]}] + set_property PACKAGE_PIN AL42 [get_ports {${direction0Pins}_data[9]}] + set_property PACKAGE_PIN AF42 [get_ports {${direction0Pins}_data[10]}] + set_property PACKAGE_PIN AG42 [get_ports {${direction0Pins}_data[11]}] + set_property PACKAGE_PIN AD38 [get_ports {${direction0Pins}_data[12]}] + set_property PACKAGE_PIN AE38 [get_ports {${direction0Pins}_data[13]}] + set_property PACKAGE_PIN AC40 [get_ports {${direction0Pins}_data[14]}] + set_property PACKAGE_PIN AC41 [get_ports {${direction0Pins}_data[15]}] + set_property PACKAGE_PIN AD42 [get_ports {${direction0Pins}_data[16]}] + set_property PACKAGE_PIN AE42 [get_ports {${direction0Pins}_data[17]}] + set_property PACKAGE_PIN AJ38 [get_ports {${direction0Pins}_data[18]}] + set_property PACKAGE_PIN AK38 [get_ports {${direction0Pins}_data[19]}] + set_property PACKAGE_PIN AB41 [get_ports {${direction0Pins}_data[20]}] + set_property PACKAGE_PIN AB42 [get_ports {${direction0Pins}_data[21]}] + set_property PACKAGE_PIN Y42 [get_ports {${direction0Pins}_data[22]}] + set_property PACKAGE_PIN AA42 [get_ports {${direction0Pins}_data[23]}] + set_property PACKAGE_PIN Y39 [get_ports {${direction0Pins}_data[24]}] + set_property PACKAGE_PIN AA39 [get_ports {${direction0Pins}_data[25]}] + set_property PACKAGE_PIN W40 [get_ports {${direction0Pins}_data[26]}] + set_property PACKAGE_PIN Y40 [get_ports {${direction0Pins}_data[27]}] + set_property PACKAGE_PIN AB38 [get_ports {${direction0Pins}_data[28]}] + set_property PACKAGE_PIN AB39 [get_ports {${direction0Pins}_data[29]}] + set_property PACKAGE_PIN AC38 [get_ports {${direction0Pins}_data[30]}] + set_property PACKAGE_PIN AC39 [get_ports {${direction0Pins}_data[31]}] + set_property PACKAGE_PIN AJ40 [get_ports ${direction0Pins}_send] + set_property PACKAGE_PIN AJ41 [get_ports ${direction0Pins}_rst] + + set_property PACKAGE_PIN U39 [get_ports ${direction1Pins}_clk] + set_property PACKAGE_PIN U37 [get_ports {${direction1Pins}_data[0]}] + set_property PACKAGE_PIN U38 [get_ports {${direction1Pins}_data[1]}] + set_property PACKAGE_PIN U36 [get_ports {${direction1Pins}_data[2]}] + set_property PACKAGE_PIN T37 [get_ports {${direction1Pins}_data[3]}] + set_property PACKAGE_PIN U32 [get_ports {${direction1Pins}_data[4]}] + set_property PACKAGE_PIN U33 [get_ports {${direction1Pins}_data[5]}] + set_property PACKAGE_PIN V33 [get_ports {${direction1Pins}_data[6]}] + set_property PACKAGE_PIN V34 [get_ports {${direction1Pins}_data[7]}] + set_property PACKAGE_PIN P35 [get_ports {${direction1Pins}_data[8]}] + set_property PACKAGE_PIN P36 [get_ports {${direction1Pins}_data[9]}] + set_property PACKAGE_PIN W32 [get_ports {${direction1Pins}_data[10]}] + set_property PACKAGE_PIN W33 [get_ports {${direction1Pins}_data[11]}] + set_property PACKAGE_PIN R38 [get_ports {${direction1Pins}_data[12]}] + set_property PACKAGE_PIN R39 [get_ports {${direction1Pins}_data[13]}] + set_property PACKAGE_PIN U34 [get_ports {${direction1Pins}_data[14]}] + set_property PACKAGE_PIN T35 [get_ports {${direction1Pins}_data[15]}] + set_property PACKAGE_PIN R33 [get_ports {${direction1Pins}_data[16]}] + set_property PACKAGE_PIN R34 [get_ports {${direction1Pins}_data[17]}] + set_property PACKAGE_PIN N33 [get_ports {${direction1Pins}_data[18]}] + set_property PACKAGE_PIN N34 [get_ports {${direction1Pins}_data[19]}] + set_property PACKAGE_PIN P32 [get_ports {${direction1Pins}_data[20]}] + set_property PACKAGE_PIN P33 [get_ports {${direction1Pins}_data[21]}] + set_property PACKAGE_PIN V35 [get_ports {${direction1Pins}_data[22]}] + set_property PACKAGE_PIN V36 [get_ports {${direction1Pins}_data[23]}] + set_property PACKAGE_PIN W36 [get_ports {${direction1Pins}_data[24]}] + set_property PACKAGE_PIN W37 [get_ports {${direction1Pins}_data[25]}] + set_property PACKAGE_PIN T32 [get_ports {${direction1Pins}_data[26]}] + set_property PACKAGE_PIN R32 [get_ports {${direction1Pins}_data[27]}] + set_property PACKAGE_PIN V39 [get_ports {${direction1Pins}_data[28]}] + set_property PACKAGE_PIN V40 [get_ports {${direction1Pins}_data[29]}] + set_property PACKAGE_PIN P37 [get_ports {${direction1Pins}_data[30]}] + set_property PACKAGE_PIN P38 [get_ports {${direction1Pins}_data[31]}] + + set_property PACKAGE_PIN T36 [get_ports ${direction1Pins}_send] + set_property PACKAGE_PIN R37 [get_ports ${direction1Pins}_rst] + + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[31]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[30]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[29]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[28]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[27]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[26]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[25]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[24]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[23]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[22]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[21]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[20]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[19]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[18]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[17]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[16]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[15]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[14]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[13]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[12]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[11]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[10]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[9]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[8]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[7]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[6]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[5]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[4]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[3]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[2]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[1]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction0Pins}_data[0]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[31]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[30]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[29]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[28]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[27]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[26]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[25]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[24]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[23]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[22]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[21]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[20]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[19]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[18]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[17]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[16]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[15]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[14]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[13]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[12]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[11]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[10]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[9]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[8]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[7]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[6]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[5]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[4]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[3]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[2]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[1]}] + set_property IOSTANDARD LVCMOS18 [get_ports {${direction1Pins}_data[0]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[31]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[30]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[29]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[28]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[27]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[26]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[25]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[24]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[23]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[22]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[21]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[20]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[19]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[18]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[17]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[16]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[15]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[14]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[13]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[12]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[11]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[10]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[9]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[8]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[7]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[6]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[5]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[4]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[3]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[2]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[1]}] + set_property SLEW FAST [get_ports {${direction1Pins}_data[0]}] + + + set_property IOSTANDARD LVCMOS18 [get_ports ${direction0Pins}_clk] + set_property IOSTANDARD LVCMOS18 [get_ports ${direction0Pins}_rst] + set_property IOSTANDARD LVCMOS18 [get_ports ${direction0Pins}_send] + set_property IOSTANDARD LVCMOS18 [get_ports ${direction1Pins}_clk] + set_property IOSTANDARD LVCMOS18 [get_ports ${direction1Pins}_rst] + set_property IOSTANDARD LVCMOS18 [get_ports ${direction1Pins}_send] + set_property SLEW FAST [get_ports ${direction1Pins}_clk] + set_property SLEW FAST [get_ports ${direction1Pins}_rst] + set_property SLEW FAST [get_ports ${direction1Pins}_send] + + + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[31]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[30]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[29]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[28]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[27]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[26]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[25]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[24]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[23]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[22]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[21]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[20]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[19]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[18]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[17]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[16]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[15]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[14]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[13]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[12]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[11]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[10]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[9]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[8]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[7]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[6]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[5]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[4]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[3]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[2]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[1]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_data[0]] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_send] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_clk] + set_property OFFCHIP_TERM NONE [get_ports ${direction1Pins}_rst] + + # Aloe reset sent to FPGA + set_property IOSTANDARD LVCMOS18 [get_ports ereset_n] + set_property PACKAGE_PIN AF40 [get_ports ereset_n] + + #Put first level RX/TX flops in IOB + set_property IOB TRUE [get_cells -of_objects [all_fanout -flat -endpoints_only [get_ports "chiplink_b2c_data*"]]] + set_property IOB TRUE [get_cells -of_objects [all_fanout -flat -endpoints_only [get_ports "chiplink_b2c_send"]]] + set_property IOB TRUE [get_cells -of_objects [all_fanin -flat -startpoints_only [get_ports "chiplink_c2b_data*"]]] + set_property IOB TRUE [get_cells -of_objects [all_fanin -flat -startpoints_only [get_ports "chiplink_c2b_send"]]] +""" + ) + } + + def connectChipLink(dut: { val chiplink: Seq[WideDataLayerPort] } , iofpga: Boolean = false): Unit = { + constrainChipLink(iofpga) + + chiplink <> dut.chiplink(0) + //dut.chiplink_xilinx_7series_phy.get.idelayctrl_refclk := sys_clock + } +} + + + +abstract class VC707Shell(implicit val p: Parameters) extends RawModule { + + //----------------------------------------------------------------------- + // Interface + //----------------------------------------------------------------------- + + // 200Mhz differential sysclk + val sys_diff_clock_clk_n = IO(Input(Clock())) + val sys_diff_clock_clk_p = IO(Input(Clock())) + + // active high reset + val reset = IO(Input(Bool())) + + // LED + val led = IO(Vec(8, Output(Bool()))) + + // UART + val uart_tx = IO(Output(Bool())) + val uart_rx = IO(Input(Bool())) + val uart_rtsn = IO(Output(Bool())) + val uart_ctsn = IO(Input(Bool())) + + // SDIO + val sdio_clk = IO(Output(Bool())) + val sdio_cmd = IO(Analog(1.W)) + val sdio_dat = IO(Analog(4.W)) + + //Buttons + val btn_0 = IO(Analog(1.W)) + val btn_1 = IO(Analog(1.W)) + val btn_2 = IO(Analog(1.W)) + val btn_3 = IO(Analog(1.W)) + + //Sliding switches + val sw_0 = IO(Analog(1.W)) + val sw_1 = IO(Analog(1.W)) + val sw_2 = IO(Analog(1.W)) + val sw_3 = IO(Analog(1.W)) + val sw_4 = IO(Analog(1.W)) + val sw_5 = IO(Analog(1.W)) + val sw_6 = IO(Analog(1.W)) + val sw_7 = IO(Analog(1.W)) + + + //----------------------------------------------------------------------- + // Wire declrations + //----------------------------------------------------------------------- + + val sys_clock = Wire(Clock()) + val sys_reset = Wire(Bool()) + + val dut_clock = Wire(Clock()) + val dut_reset = Wire(Bool()) + val dut_resetn = Wire(Bool()) + + val dut_ndreset = 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 do_reset = Wire(Bool()) + + val mig_mmcm_locked = Wire(Bool()) + val mig_sys_reset = Wire(Bool()) + + val mig_clock = Wire(Clock()) + val mig_reset = Wire(Bool()) + val mig_resetn = Wire(Bool()) + + val pcie_dat_reset = Wire(Bool()) + val pcie_dat_resetn = Wire(Bool()) + val pcie_cfg_reset = Wire(Bool()) + val pcie_cfg_resetn = Wire(Bool()) + val pcie_dat_clock = Wire(Clock()) + val pcie_cfg_clock = Wire(Clock()) + val mmcm_lock_pcie = Wire(Bool()) + + //----------------------------------------------------------------------- + // Differential clock + //----------------------------------------------------------------------- + + val sys_clk_ibufds = Module(new IBUFDS) + sys_clk_ibufds.io.I := sys_diff_clock_clk_p + sys_clk_ibufds.io.IB := sys_diff_clock_clk_n + + //----------------------------------------------------------------------- + // System clock and reset + //----------------------------------------------------------------------- + + // Clock that drives the clock generator and the MIG + sys_clock := sys_clk_ibufds.io.O + + // Allow the debug module to reset everything. Resets the MIG + sys_reset := reset | dut_ndreset + + //----------------------------------------------------------------------- + // Clock Generator + //----------------------------------------------------------------------- + + //25MHz and multiples + val vc707_sys_clock_mmcm0 = Module(new Series7MMCM(PLLParameters( + "vc707_sys_clock_mmcm2", + PLLInClockParameters(200, 50), + Seq( + PLLOutClockParameters(12.5), + PLLOutClockParameters(25), + PLLOutClockParameters(37.5), + PLLOutClockParameters(50), + PLLOutClockParameters(100), + PLLOutClockParameters(150.00), + PLLOutClockParameters(100, 180))))) + + vc707_sys_clock_mmcm0.io.clk_in1 := sys_clock + vc707_sys_clock_mmcm0.io.reset := reset + val vc707_sys_clock_mmcm0_locked = vc707_sys_clock_mmcm0.io.locked + val Seq(clk12_5, clk25, clk37_5, clk50, clk100, clk150, clk100_180) = vc707_sys_clock_mmcm0.getClocks + + //65MHz and multiples + //val vc707_sys_clock_mmcm1 = Module(new vc707_sys_clock_mmcm1) + val vc707_sys_clock_mmcm1 = Module(new Series7MMCM(PLLParameters( + "vc707_sys_clock_mmcm1", + PLLInClockParameters(200, 50), + Seq( + PLLOutClockParameters(32.5), + PLLOutClockParameters(65, 180))))) + + vc707_sys_clock_mmcm1.io.clk_in1 := sys_clock + vc707_sys_clock_mmcm1.io.reset := reset + val clk32_5 = vc707_sys_clock_mmcm1.io.clk_out1 + val clk65 = vc707_sys_clock_mmcm1.io.clk_out2 + val vc707_sys_clock_mmcm1_locked = vc707_sys_clock_mmcm1.io.locked + + // DUT clock + dut_clock := clk37_5 + + //----------------------------------------------------------------------- + // System reset + //----------------------------------------------------------------------- + + do_reset := !mig_mmcm_locked || !mmcm_lock_pcie || mig_sys_reset || !vc707_sys_clock_mmcm0_locked || + !vc707_sys_clock_mmcm1_locked + mig_resetn := !mig_reset + dut_resetn := !dut_reset + pcie_dat_resetn := !pcie_dat_reset + pcie_cfg_resetn := !pcie_cfg_reset + + + val safe_reset = Module(new vc707reset) + + safe_reset.io.areset := do_reset + safe_reset.io.clock1 := mig_clock + mig_reset := safe_reset.io.reset1 + safe_reset.io.clock2 := pcie_dat_clock + pcie_dat_reset := safe_reset.io.reset2 + safe_reset.io.clock3 := pcie_cfg_clock + pcie_cfg_reset := safe_reset.io.reset3 + safe_reset.io.clock4 := dut_clock + dut_reset := safe_reset.io.reset4 + + //overrided in connectMIG and connect PCIe + //provide defaults to allow above reset sequencing logic to work without both + mig_clock := dut_clock + pcie_dat_clock := dut_clock + pcie_cfg_clock := dut_clock + mig_mmcm_locked := UInt("b1") + mmcm_lock_pcie := UInt("b1") + + + + //----------------------------------------------------------------------- + // UART + //----------------------------------------------------------------------- + + uart_rtsn := false.B + + 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 + } + + ElaborationArtefacts.add("old-shell.vivado.tcl", + """set obj [current_fileset -constrset] + |add_files -quiet -norecurse -fileset $obj [file join $boarddir tcl ios.tcl] + |add_files -quiet -norecurse -fileset $obj [file join $boarddir tcl clocks.tcl] + |""".stripMargin) +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/VCU118NewShell.scala b/fpga-shells/src/main/scala/shell/xilinx/VCU118NewShell.scala new file mode 100644 index 00000000..4f5eecd9 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/VCU118NewShell.scala @@ -0,0 +1,308 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx + +import chisel3._ +import chisel3.experimental.{attach, Analog, IO, withClockAndReset} +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util.SyncResetSynchronizerShiftReg +import sifive.fpgashells.clocks._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.ip.xilinx._ +import sifive.blocks.devices.chiplink._ +import sifive.fpgashells.devices.xilinx.xilinxvcu118mig._ +import sifive.fpgashells.devices.xilinx.xdma._ + +class SysClockVCU118Overlay(val shell: VCU118Shell, val name: String, params: ClockInputOverlayParams) + extends LVDSClockInputXilinxOverlay(params) +{ + val node = shell { ClockSourceNode(freqMHz = 250, jitterPS = 50)(ValName(name)) } + + shell { InModuleBody { + shell.xdc.addPackagePin(io.p, "E12") + shell.xdc.addPackagePin(io.n, "D12") + shell.xdc.addIOStandard(io.p, "DIFF_SSTL12") + shell.xdc.addIOStandard(io.n, "DIFF_SSTL12") + } } +} + +class SDIOVCU118Overlay(val shell: VCU118Shell, val name: String, params: SDIOOverlayParams) + extends SDIOXilinxOverlay(params) +{ + shell { InModuleBody { + val packagePinsWithPackageIOs = Seq(("AV15", IOPin(io.sdio_clk)), + ("AY15", IOPin(io.sdio_cmd)), + ("AW15", IOPin(io.sdio_dat_0)), + ("AV16", IOPin(io.sdio_dat_1)), + ("AU16", IOPin(io.sdio_dat_2)), + ("AY14", IOPin(io.sdio_dat_3))) + + packagePinsWithPackageIOs foreach { case (pin, io) => { + shell.xdc.addPackagePin(io, pin) + shell.xdc.addIOStandard(io, "LVCMOS18") + shell.xdc.addIOB(io) + } } + packagePinsWithPackageIOs drop 1 foreach { case (pin, io) => { + shell.xdc.addPullup(io) + } } + } } +} + +class UARTVCU118Overlay(val shell: VCU118Shell, val name: String, params: UARTOverlayParams) + extends UARTXilinxOverlay(params) +{ + shell { InModuleBody { + val packagePinsWithPackageIOs = Seq(("AY25", IOPin(io.ctsn)), + ("BB22", IOPin(io.rtsn)), + ("AW25", IOPin(io.rxd)), + ("BB21", IOPin(io.txd))) + + packagePinsWithPackageIOs foreach { case (pin, io) => { + shell.xdc.addPackagePin(io, pin) + shell.xdc.addIOStandard(io, "LVCMOS18") + shell.xdc.addIOB(io) + } } + } } +} + +class LEDVCU118Overlay(val shell: VCU118Shell, val name: String, params: LEDOverlayParams) + extends LEDXilinxOverlay(params, packagePins = Seq("AT32", "AV34", "AY30", "BB32", "BF32", "AU37", "AV36", "BA37")) +{ + shell { InModuleBody { + IOPin.of(io).foreach { shell.xdc.addIOStandard(_, "LVCMOS12") } + } } +} + +class SwitchVCU118Overlay(val shell: VCU118Shell, val name: String, params: SwitchOverlayParams) + extends SwitchXilinxOverlay(params, packagePins = Seq("B17", "G16", "J16", "D21")) +{ + shell { InModuleBody { + IOPin.of(io).foreach { shell.xdc.addIOStandard(_, "LVCMOS12") } + } } +} + +class ChipLinkVCU118Overlay(val shell: VCU118Shell, val name: String, params: ChipLinkOverlayParams) + extends ChipLinkXilinxOverlay(params, rxPhase= -120, txPhase= -90, rxMargin=0.6, txMargin=0.5) +{ + val ereset_n = shell { InModuleBody { + val ereset_n = IO(Analog(1.W)) + ereset_n.suggestName("ereset_n") + val pin = IOPin(ereset_n, 0) + shell.xdc.addPackagePin(pin, "BC8") + shell.xdc.addIOStandard(pin, "LVCMOS18") + shell.xdc.addTermination(pin, "NONE") + shell.xdc.addPullup(pin) + + val iobuf = Module(new IOBUF) + iobuf.suggestName("chiplink_ereset_iobuf") + attach(ereset_n, iobuf.io.IO) + iobuf.io.T := true.B // !oe + iobuf.io.I := false.B + + iobuf.io.O + } } + + shell { InModuleBody { + val dir1 = Seq("BC9", "AV8", "AV9", /* clk, rst, send */ + "AY9", "BA9", "BF10", "BF9", "BC11", "BD11", "BD12", "BE12", + "BF12", "BF11", "BE14", "BF14", "BD13", "BE13", "BC15", "BD15", + "BE15", "BF15", "BA14", "BB14", "BB13", "BB12", "BA16", "BA15", + "BC14", "BC13", "AY8", "AY7", "AW8", "AW7", "BB16", "BC16") + val dir2 = Seq("AV14", "AK13", "AK14", /* clk, rst, send */ + "AR14", "AT14", "AP12", "AR12", "AW12", "AY12", "AW11", "AY10", + "AU11", "AV11", "AW13", "AY13", "AN16", "AP16", "AP13", "AR13", + "AT12", "AU12", "AK15", "AL15", "AL14", "AM14", "AV10", "AW10", + "AN15", "AP15", "AK12", "AL12", "AM13", "AM12", "AJ13", "AJ12") + (IOPin.of(io.b2c) zip dir1) foreach { case (io, pin) => shell.xdc.addPackagePin(io, pin) } + (IOPin.of(io.c2b) zip dir2) foreach { case (io, pin) => shell.xdc.addPackagePin(io, pin) } + } } +} + +// TODO: JTAG is untested +class JTAGDebugVCU118Overlay(val shell: VCU118Shell, val name: String, params: JTAGDebugOverlayParams) + extends JTAGDebugXilinxOverlay(params) +{ + shell { InModuleBody { + shell.sdc.addClock("JTCK", IOPin(io.jtag_TCK), 10) + shell.sdc.addGroup(clocks = Seq("JTCK")) + shell.xdc.clockDedicatedRouteFalse(IOPin(io.jtag_TCK)) + val packagePinsWithPackageIOs = Seq(("P29", IOPin(io.jtag_TCK)), + ("L31", IOPin(io.jtag_TMS)), + ("M31", IOPin(io.jtag_TDI)), + ("R29", IOPin(io.jtag_TDO))) + + packagePinsWithPackageIOs foreach { case (pin, io) => { + shell.xdc.addPackagePin(io, pin) + shell.xdc.addIOStandard(io, "LVCMOS18") + shell.xdc.addPullup(io) + } } + } } +} + +case object VCU118DDRSize extends Field[BigInt](0x40000000L * 2) // 2GB +class DDRVCU118Overlay(val shell: VCU118Shell, val name: String, params: DDROverlayParams) + extends DDROverlay[XilinxVCU118MIGPads](params) +{ + val size = p(VCU118DDRSize) + + val migParams = XilinxVCU118MIGParams(address = AddressSet.misaligned(params.baseAddress, size)) + val mig = LazyModule(new XilinxVCU118MIG(migParams)) + val ioNode = BundleBridgeSource(() => mig.module.io.cloneType) + val topIONode = shell { ioNode.makeSink() } + val ddrUI = shell { ClockSourceNode(freqMHz = 200) } + val areset = shell { ClockSinkNode(Seq(ClockSinkParameters())) } + areset := params.wrangler := ddrUI + + def designOutput = mig.node + def ioFactory = new XilinxVCU118MIGPads(size) + + InModuleBody { ioNode.bundle <> mig.module.io } + + shell { InModuleBody { + require (shell.sys_clock.isDefined, "Use of DDRVCU118Overlay depends on SysClockVCU118Overlay") + val (sys, _) = shell.sys_clock.get.node.out(0) + val (ui, _) = ddrUI.out(0) + val (ar, _) = areset.in(0) + val port = topIONode.bundle.port + io <> port + ui.clock := port.c0_ddr4_ui_clk + ui.reset := /*!port.mmcm_locked ||*/ port.c0_ddr4_ui_clk_sync_rst + port.c0_sys_clk_i := sys.clock.asUInt + port.sys_rst := sys.reset // pllReset + port.c0_ddr4_aresetn := !ar.reset + + val allddrpins = Seq( "D14", "B15", "B16", "C14", "C15", "A13", "A14", + "A15", "A16", "B12", "C12", "B13", "C13", "D15", "H14", "H15", "F15", + "H13", "G15", "G13", "N20", "E13", "E14", "F14", "A10", "F13", "C8", + "F11", "E11", "F10", "F9", "H12", "G12", "E9", "D9", "R19", "P19", + "M18", "M17", "N19", "N18", "N17", "M16", "L16", "K16", "L18", "K18", + "J17", "H17", "H19", "H18", "F19", "F18", "E19", "E18", "G20", "F20", + "E17", "D16", "D17", "C17", "C19", "C18", "D20", "D19", "C20", "B20", + "N23", "M23", "R21", "P21", "R22", "P22", "T23", "R23", "K24", "J24", + "M21", "L21", "K21", "J21", "K22", "J22", "H23", "H22", "E23", "E22", + "F21", "E21", "F24", "F23", "D10", "P16", "J19", "E16", "A18", "M22", + "L20", "G23", "D11", "P17", "K19", "F16", "A19", "N22", "M20", "H24", + "G11", "R18", "K17", "G18", "B18", "P20", "L23", "G22") + + (IOPin.of(io) zip allddrpins) foreach { case (io, pin) => shell.xdc.addPackagePin(io, pin) } + } } + + shell.sdc.addGroup(pins = Seq(mig.island.module.blackbox.io.c0_ddr4_ui_clk)) +} + +class PCIeVCU118FMCOverlay(val shell: VCU118Shell, val name: String, params: PCIeOverlayParams) + extends PCIeUltraScaleOverlay(XDMAParams( + name = "fmc_xdma", + location = "X0Y3", + bars = params.bars, + control = params.ecam, + lanes = 4), params) +{ + shell { InModuleBody { + // Work-around incorrectly pre-assigned pins + IOPin.of(io).foreach { shell.xdc.addPackagePin(_, "") } + + // We need some way to connect both of these to reach x8 + val ref126 = Seq("V38", "V39") /* [pn] GBT0 Bank 126 */ + val ref121 = Seq("AK38", "AK39") /* [pn] GBT0 Bank 121 */ + val ref = ref126 + + // Bank 126 (DP5, DP6, DP4, DP7), Bank 121 (DP3, DP2, DP1, DP0) + val rxp = Seq("U45", "R45", "W45", "N45", "AJ45", "AL45", "AN45", "AR45") /* [0-7] */ + val rxn = Seq("U46", "R46", "W46", "N46", "AJ46", "AL46", "AN46", "AR46") /* [0-7] */ + val txp = Seq("P42", "M42", "T42", "K42", "AL40", "AM42", "AP42", "AT42") /* [0-7] */ + val txn = Seq("P43", "M43", "T43", "K43", "AL41", "AM43", "AP43", "AT43") /* [0-7] */ + + def bind(io: Seq[IOPin], pad: Seq[String]) { + (io zip pad) foreach { case (io, pad) => shell.xdc.addPackagePin(io, pad) } + } + + bind(IOPin.of(io.refclk), ref) + // We do these individually so that zip falls off the end of the lanes: + bind(IOPin.of(io.lanes.pci_exp_txp), txp) + bind(IOPin.of(io.lanes.pci_exp_txn), txn) + bind(IOPin.of(io.lanes.pci_exp_rxp), rxp) + bind(IOPin.of(io.lanes.pci_exp_rxn), rxn) + } } +} + +class PCIeVCU118EdgeOverlay(val shell: VCU118Shell, val name: String, params: PCIeOverlayParams) + extends PCIeUltraScaleOverlay(XDMAParams( + name = "edge_xdma", + location = "X1Y2", + bars = params.bars, + control = params.ecam, + lanes = 8), params) +{ + shell { InModuleBody { + // Work-around incorrectly pre-assigned pins + IOPin.of(io).foreach { shell.xdc.addPackagePin(_, "") } + + // PCIe Edge connector U2 + // Lanes 00-03 Bank 227 + // Lanes 04-07 Bank 226 + // Lanes 08-11 Bank 225 + // Lanes 12-15 Bank 224 + + // FMC+ J22 + val ref227 = Seq("AC9", "AC8") /* [pn] Bank 227 PCIE_CLK2_*/ + val ref = ref227 + + // PCIe Edge connector U2 : Bank 227, 226 + val rxp = Seq("AA4", "AB2", "AC4", "AD2", "AE4", "AF2", "AG4", "AH2") // [0-7] + val rxn = Seq("AA3", "AB1", "AC3", "AD1", "AE3", "AF1", "AG3", "AH1") // [0-7] + val txp = Seq("Y7", "AB7", "AD7", "AF7", "AH7", "AK7", "AM7", "AN5") // [0-7] + val txn = Seq("Y6", "AB6", "AD6", "AF6", "AH6", "AK6", "AM6", "AN4") // [0-7] + + def bind(io: Seq[IOPin], pad: Seq[String]) { + (io zip pad) foreach { case (io, pad) => shell.xdc.addPackagePin(io, pad) } + } + + bind(IOPin.of(io.refclk), ref) + // We do these individually so that zip falls off the end of the lanes: + bind(IOPin.of(io.lanes.pci_exp_txp), txp) + bind(IOPin.of(io.lanes.pci_exp_txn), txn) + bind(IOPin.of(io.lanes.pci_exp_rxp), rxp) + bind(IOPin.of(io.lanes.pci_exp_rxn), rxn) + } } +} + +class VCU118Shell()(implicit p: Parameters) extends UltraScaleShell +{ + // PLL reset causes + val pllReset = InModuleBody { Wire(Bool()) } + + // Order matters; ddr depends on sys_clock + val sys_clock = Overlay(ClockInputOverlayKey)(new SysClockVCU118Overlay (_, _, _)) + val led = Overlay(LEDOverlayKey) (new LEDVCU118Overlay (_, _, _)) + val switch = Overlay(SwitchOverlayKey) (new SwitchVCU118Overlay (_, _, _)) + val chiplink = Overlay(ChipLinkOverlayKey) (new ChipLinkVCU118Overlay (_, _, _)) + val ddr = Overlay(DDROverlayKey) (new DDRVCU118Overlay (_, _, _)) + val fmc = Overlay(PCIeOverlayKey) (new PCIeVCU118FMCOverlay (_, _, _)) + val edge = Overlay(PCIeOverlayKey) (new PCIeVCU118EdgeOverlay (_, _, _)) + val uart = Overlay(UARTOverlayKey) (new UARTVCU118Overlay (_, _, _)) + val sdio = Overlay(SDIOOverlayKey) (new SDIOVCU118Overlay (_, _, _)) + val jtag = Overlay(JTAGDebugOverlayKey) (new JTAGDebugVCU118Overlay(_, _, _)) + + val topDesign = LazyModule(p(DesignKey)(designParameters)) + + // Place the sys_clock at the Shell if the user didn't ask for it + p(ClockInputOverlayKey).foreach(_(ClockInputOverlayParams())) + + override lazy val module = new LazyRawModuleImp(this) { + val reset = IO(Input(Bool())) + xdc.addPackagePin(reset, "L19") + xdc.addIOStandard(reset, "LVCMOS12") + + val reset_ibuf = Module(new IBUF) + reset_ibuf.io.I := reset + + val powerOnReset = PowerOnResetFPGAOnly(sys_clock.get.clock) + sdc.addAsyncPath(Seq(powerOnReset)) + + pllReset := + reset_ibuf.io.O || powerOnReset || + chiplink.map(!_.ereset_n).getOrElse(false.B) + } +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/VCU118Shell.scala b/fpga-shells/src/main/scala/shell/xilinx/VCU118Shell.scala new file mode 100644 index 00000000..759b805c --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/VCU118Shell.scala @@ -0,0 +1,274 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx.vcu118shell + +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} + +import sifive.blocks.devices.gpio._ +import sifive.blocks.devices.spi._ +import sifive.blocks.devices.uart._ + +import sifive.fpgashells.devices.xilinx.xilinxvcu118mig._ +import sifive.fpgashells.ip.xilinx.{IBUFDS, PowerOnResetFPGAOnly, sdio_spi_bridge, vcu118_sys_clock_mmcm0, + vcu118_sys_clock_mmcm1, vcu118reset} + +//------------------------------------------------------------------------- +// VCU118Shell +//------------------------------------------------------------------------- + +trait HasDDR3 { this: VCU118Shell => + + require(!p.lift(MemoryXilinxDDRKey).isEmpty) + val ddr = IO(new XilinxVCU118MIGPads(p(MemoryXilinxDDRKey))) + + def connectMIG(dut: HasMemoryXilinxVCU118MIGModuleImp): Unit = { + // Clock & Reset + dut.xilinxvcu118mig.c0_sys_clk_i := sys_clock.asUInt + mig_clock := dut.xilinxvcu118mig.c0_ddr4_ui_clk + mig_sys_reset := dut.xilinxvcu118mig.c0_ddr4_ui_clk_sync_rst + dut.xilinxvcu118mig.c0_ddr4_aresetn := mig_resetn + dut.xilinxvcu118mig.sys_rst := sys_reset + + ddr <> dut.xilinxvcu118mig + } +} + +abstract class VCU118Shell(implicit val p: Parameters) extends RawModule { + + //----------------------------------------------------------------------- + // Interface + //----------------------------------------------------------------------- + + // 250Mhz differential sysclk + val sys_diff_clock_clk_n = IO(Input(Clock())) + val sys_diff_clock_clk_p = IO(Input(Clock())) + + // active high reset + val reset = IO(Input(Bool())) + + // LED + //val led = IO(Vec(8, Output(Bool()))) + + // UART + val uart_tx = IO(Output(Bool())) + val uart_rx = IO(Input(Bool())) + val uart_rtsn = IO(Output(Bool())) + val uart_ctsn = IO(Input(Bool())) + + // SDIO + val sdio_clk = IO(Output(Bool())) + val sdio_cmd = IO(Analog(1.W)) + val sdio_dat = IO(Analog(4.W)) + + // 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())) + + //Buttons + //val btn_0 = IO(Analog(1.W)) + //val btn_1 = IO(Analog(1.W)) + //val btn_2 = IO(Analog(1.W)) + //val btn_3 = IO(Analog(1.W)) + + //Sliding switches + //val sw_0 = IO(Analog(1.W)) + //val sw_1 = IO(Analog(1.W)) + //val sw_2 = IO(Analog(1.W)) + //val sw_3 = IO(Analog(1.W)) + //val sw_4 = IO(Analog(1.W)) + //val sw_5 = IO(Analog(1.W)) + //val sw_6 = IO(Analog(1.W)) + //val sw_7 = IO(Analog(1.W)) + + + //----------------------------------------------------------------------- + // Wire declrations + //----------------------------------------------------------------------- + + val sys_clock = Wire(Clock()) + val sys_reset = Wire(Bool()) + + val dut_clock = Wire(Clock()) + val dut_reset = Wire(Bool()) + val dut_resetn = Wire(Bool()) + + val dut_ndreset = 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 do_reset = Wire(Bool()) + + val mig_mmcm_locked = Wire(Bool()) + val mig_sys_reset = Wire(Bool()) + + val mig_clock = Wire(Clock()) + val mig_reset = Wire(Bool()) + val mig_resetn = Wire(Bool()) + + val pcie_dat_reset = Wire(Bool()) + val pcie_dat_resetn = Wire(Bool()) + val pcie_cfg_reset = Wire(Bool()) + val pcie_cfg_resetn = Wire(Bool()) + val pcie_dat_clock = Wire(Clock()) + val pcie_cfg_clock = Wire(Clock()) + val mmcm_lock_pcie = Wire(Bool()) + + //----------------------------------------------------------------------- + // Differential clock + //----------------------------------------------------------------------- + + val sys_clk_ibufds = Module(new IBUFDS) + sys_clk_ibufds.io.I := sys_diff_clock_clk_p + sys_clk_ibufds.io.IB := sys_diff_clock_clk_n + + //----------------------------------------------------------------------- + // System clock and reset + //----------------------------------------------------------------------- + + // Clock that drives the clock generator and the MIG + sys_clock := sys_clk_ibufds.io.O + + // Allow the debug module to reset everything. Resets the MIG + sys_reset := reset | dut_ndreset + + //----------------------------------------------------------------------- + // Clock Generator + //----------------------------------------------------------------------- + + //25MHz and multiples + val vcu118_sys_clock_mmcm0 = Module(new vcu118_sys_clock_mmcm0) + vcu118_sys_clock_mmcm0.io.clk_in1 := sys_clock.asUInt + vcu118_sys_clock_mmcm0.io.reset := reset + val clk12_5 = vcu118_sys_clock_mmcm0.io.clk_out1 + val clk25 = vcu118_sys_clock_mmcm0.io.clk_out2 + val clk37_5 = vcu118_sys_clock_mmcm0.io.clk_out3 + val clk50 = vcu118_sys_clock_mmcm0.io.clk_out4 + val clk100 = vcu118_sys_clock_mmcm0.io.clk_out5 + val clk150 = vcu118_sys_clock_mmcm0.io.clk_out6 + val clk75 = vcu118_sys_clock_mmcm0.io.clk_out7 + val vcu118_sys_clock_mmcm0_locked = vcu118_sys_clock_mmcm0.io.locked + + //65MHz and multiples + val vcu118_sys_clock_mmcm1 = Module(new vcu118_sys_clock_mmcm1) + vcu118_sys_clock_mmcm1.io.clk_in1 := sys_clock.asUInt + vcu118_sys_clock_mmcm1.io.reset := reset + val clk32_5 = vcu118_sys_clock_mmcm1.io.clk_out1 + val clk65 = vcu118_sys_clock_mmcm1.io.clk_out2 + val vcu118_sys_clock_mmcm1_locked = vcu118_sys_clock_mmcm1.io.locked + + // DUT clock + dut_clock := clk37_5 + + //----------------------------------------------------------------------- + // System reset + //----------------------------------------------------------------------- + + do_reset := !mig_mmcm_locked || !mmcm_lock_pcie || mig_sys_reset || !vcu118_sys_clock_mmcm0_locked || + !vcu118_sys_clock_mmcm1_locked + mig_resetn := !mig_reset + dut_resetn := !dut_reset + pcie_dat_resetn := !pcie_dat_reset + pcie_cfg_resetn := !pcie_cfg_reset + + + val safe_reset = Module(new vcu118reset) + + safe_reset.io.areset := do_reset + safe_reset.io.clock1 := mig_clock + mig_reset := safe_reset.io.reset1 + safe_reset.io.clock2 := pcie_dat_clock + pcie_dat_reset := safe_reset.io.reset2 + safe_reset.io.clock3 := pcie_cfg_clock + pcie_cfg_reset := safe_reset.io.reset3 + safe_reset.io.clock4 := dut_clock + dut_reset := safe_reset.io.reset4 + + //overrided in connectMIG and connect PCIe + //provide defaults to allow above reset sequencing logic to work without both + mig_clock := dut_clock + pcie_dat_clock := dut_clock + pcie_cfg_clock := dut_clock + mig_mmcm_locked := UInt("b1") + mmcm_lock_pcie := UInt("b1") + + //--------------------------------------------------------------------- + // Debug JTAG + //--------------------------------------------------------------------- + + def connectDebugJTAG(dut: HasPeripheryDebugModuleImp): 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 + } + + //----------------------------------------------------------------------- + // UART + //----------------------------------------------------------------------- + + uart_rtsn := false.B + + 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 + } + +} diff --git a/fpga-shells/src/main/scala/shell/xilinx/XilinxShell.scala b/fpga-shells/src/main/scala/shell/xilinx/XilinxShell.scala new file mode 100644 index 00000000..1796a6f4 --- /dev/null +++ b/fpga-shells/src/main/scala/shell/xilinx/XilinxShell.scala @@ -0,0 +1,76 @@ +// See LICENSE for license details. +package sifive.fpgashells.shell.xilinx + +import chisel3._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.util._ +import sifive.fpgashells.clocks._ +import sifive.fpgashells.ip.xilinx._ +import sifive.fpgashells.shell._ + +class XDC(val name: String) +{ + private var constraints: Seq[() => String] = Nil + protected def addConstraint(command: => String) { constraints = (() => command) +: constraints } + ElaborationArtefacts.add(name, constraints.map(_()).reverse.mkString("\n") + "\n") + + def addBoardPin(io: IOPin, pin: String) { + addConstraint(s"set_property BOARD_PIN {${pin}} ${io.sdcPin}") + } + def addPackagePin(io: IOPin, pin: String) { + addConstraint(s"set_property PACKAGE_PIN {${pin}} ${io.sdcPin}") + } + def addIOStandard(io: IOPin, standard: String) { + addConstraint(s"set_property IOSTANDARD {${standard}} ${io.sdcPin}") + } + def addPullup(io: IOPin) { + addConstraint(s"set_property PULLUP {TRUE} ${io.sdcPin}") + } + def addIOB(io: IOPin) { + if (io.isOutput) { + addConstraint(s"set_property IOB {TRUE} [ get_cells -of_objects [ all_fanin -flat -startpoints_only ${io.sdcPin}]]") + } else { + addConstraint(s"set_property IOB {TRUE} [ get_cells -of_objects [ all_fanout -flat -endpoints_only ${io.sdcPin}]]") + } + } + def addSlew(io: IOPin, speed: String) { + addConstraint(s"set_property SLEW {${speed}} ${io.sdcPin}") + } + def addTermination(io: IOPin, kind: String) { + addConstraint(s"set_property OFFCHIP_TERM {${kind}} ${io.sdcPin}") + } + def clockDedicatedRouteFalse(io: IOPin) { + addConstraint(s"set_property CLOCK_DEDICATED_ROUTE {FALSE} [get_nets ${io.sdcPin}]") + } +} + +abstract class XilinxShell()(implicit p: Parameters) extends IOShell +{ + val sdc = new SDC("shell.sdc") + val xdc = new XDC("shell.xdc") + def pllReset: ModuleValue[Bool] + + ElaborationArtefacts.add("shell.vivado.tcl", + """set shell_vivado_tcl [file normalize [info script]] + |set shell_vivado_idx [string last ".shell.vivado.tcl" $shell_vivado_tcl] + |add_files -fileset [current_fileset -constrset] [string replace $shell_vivado_tcl $shell_vivado_idx 999 ".shell.sdc"] + |add_files -fileset [current_fileset -constrset] [string replace $shell_vivado_tcl $shell_vivado_idx 999 ".shell.xdc"] + |""".stripMargin) +} + +abstract class Series7Shell()(implicit p: Parameters) extends XilinxShell +{ + val pllFactory = new PLLFactory(this, 7, p => Module(new Series7MMCM(p))) + override def designParameters = super.designParameters.alterPartial { + case PLLFactoryKey => pllFactory + } +} + +abstract class UltraScaleShell()(implicit p: Parameters) extends XilinxShell +{ + val pllFactory = new PLLFactory(this, 7, p => Module(new Series7MMCM(p))) + override def designParameters = super.designParameters.alterPartial { + case PLLFactoryKey => pllFactory + } +} diff --git a/fpga-shells/xilinx/Makefile b/fpga-shells/xilinx/Makefile new file mode 100644 index 00000000..1416927f --- /dev/null +++ b/fpga-shells/xilinx/Makefile @@ -0,0 +1,42 @@ +VIVADO ?= vivado +VIVADOFLAGS := \ + -nojournal -mode batch \ + -source $(fpga_board_script_dir)/board.tcl \ + -source $(fpga_common_script_dir)/prologue.tcl + +# Path to a program in raw binary format to be flashed into the address that the +# bootrom jumps to. +# FIXME: This variable should probably be communicated by a higher-level Makefile +FLASHED_PROGRAM ?= + +# Init project +init = $(FPGA_BUILD_DIR)/.init +$(init): $(fpga_common_script_dir)/init.tcl + mkdir -p $(FPGA_BUILD_DIR) && \ + cd $(FPGA_BUILD_DIR) && \ + VSRCS="$(VSRCS)" IPVIVADOTCLS="$(IPVIVADOTCLS)" $(VIVADO) $(VIVADOFLAGS) -source $< + +.PHONY: init +init: $(init) + +# Generate bitstream +bit := $(FPGA_BUILD_DIR)/obj/$(FPGA_TOP_SYSTEM).bit +$(bit): $(fpga_common_script_dir)/vivado.tcl $(init) + cd $(FPGA_BUILD_DIR) && \ + VSRCS="$(VSRCS)" $(VIVADO) $(VIVADOFLAGS) -source $< + +.PHONY: bit +bit: $(bit) + +# Generate mcs +mcs := $(FPGA_BUILD_DIR)/obj/system.mcs +$(mcs): $(bit) + cd $(FPGA_BUILD_DIR) && \ + $(VIVADO) $(VIVADOFLAGS) $(fpga_common_script_dir)/write_cfgmem.tcl -tclargs $(BOARD) $@ $^ $(FLASHED_PROGRAM) + +.PHONY: mcs +mcs: $(mcs) + +.PHONY: clean +clean:: + rm -rf $(FPGA_BUILD_DIR) diff --git a/fpga-shells/xilinx/arty/constraints/arty-config.xdc b/fpga-shells/xilinx/arty/constraints/arty-config.xdc new file mode 100644 index 00000000..a455c227 --- /dev/null +++ b/fpga-shells/xilinx/arty/constraints/arty-config.xdc @@ -0,0 +1,5 @@ +set_property -dict [list \ + CONFIG_VOLTAGE {3.3} \ + CFGBVS {VCCO} \ + BITSTREAM.CONFIG.SPI_BUSWIDTH {4} \ + ] [current_design] diff --git a/fpga-shells/xilinx/arty/constraints/arty-master.xdc b/fpga-shells/xilinx/arty/constraints/arty-master.xdc new file mode 100644 index 00000000..be9ff378 --- /dev/null +++ b/fpga-shells/xilinx/arty/constraints/arty-master.xdc @@ -0,0 +1,240 @@ +## This file is a general .xdc for the ARTY Rev. B +## To use it in a project: +## - uncomment the lines corresponding to used pins +## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project + +## Clock signal + +set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { CLK100MHZ }]; #IO_L12P_T1_MRCC_35 Sch=gclk[100] +create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {CLK100MHZ}]; +create_clock -add -name JTCK -period 100 -waveform {0 50} [get_ports {jd_2}]; + +##Switches + +set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { sw_0 }]; #IO_L12N_T1_MRCC_16 Sch=sw[0] +set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { sw_1 }]; #IO_L13P_T2_MRCC_16 Sch=sw[1] +set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { sw_2 }]; #IO_L13N_T2_MRCC_16 Sch=sw[2] +set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { sw_3 }]; #IO_L14P_T2_SRCC_16 Sch=sw[3] + +##RGB LEDs + +set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { led0_b }]; #IO_L18N_T2_35 Sch=led0_b +set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { led0_g }]; #IO_L19N_T3_VREF_35 Sch=led0_g +set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { led0_r }]; #IO_L19P_T3_35 Sch=led0_r +set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { led1_b }]; #IO_L20P_T3_35 Sch=led1_b +set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { led1_g }]; #IO_L21P_T3_DQS_35 Sch=led1_g +set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { led1_r }]; #IO_L20N_T3_35 Sch=led1_r +set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { led2_b }]; #IO_L21N_T3_DQS_35 Sch=led2_b +set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { led2_g }]; #IO_L22N_T3_35 Sch=led2_g +set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { led2_r }]; #IO_L22P_T3_35 Sch=led2_r +#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { led3_b }]; #IO_L23P_T3_35 Sch=led3_b +#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { led3_g }]; #IO_L24P_T3_35 Sch=led3_g +#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { led3_r }]; #IO_L23N_T3_35 Sch=led3_r + +##LEDs + +set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { led_0 }]; #IO_L24N_T3_35 Sch=led[4] +set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { led_1 }]; #IO_25_35 Sch=led[5] +set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { led_2 }]; #IO_L24P_T3_A01_D17_14 Sch=led[6] +set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { led_3 }]; #IO_L24N_T3_A00_D16_14 Sch=led[7] + +##Buttons + +set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { btn_0 }]; #IO_L6N_T0_VREF_16 Sch=btn[0] +set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { btn_1 }]; #IO_L11P_T1_SRCC_16 Sch=btn[1] +set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { btn_2 }]; #IO_L11N_T1_SRCC_16 Sch=btn[2] +set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { btn_3 }]; #IO_L12P_T1_MRCC_16 Sch=btn[3] + +##Pmod Header JA + +set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { ja_0 }]; #IO_0_15 Sch=ja[1] +set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { ja_1 }]; #IO_L4P_T0_15 Sch=ja[2] +set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { ja_2 }]; #IO_L4N_T0_15 Sch=ja[3] +set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { ja_3 }]; #IO_L6P_T0_15 Sch=ja[4] +set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { ja_4 }]; #IO_L6N_T0_VREF_15 Sch=ja[7] +set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports { ja_5 }]; #IO_L10P_T1_AD11P_15 Sch=ja[8] +set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports { ja_6 }]; #IO_L10N_T1_AD11N_15 Sch=ja[9] +set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { ja_7 }]; #IO_25_15 Sch=ja[10] + +##Pmod Header JB + +#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { jb_0 }]; #IO_L11P_T1_SRCC_15 Sch=jb_p[1] +#set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jb_1 }]; #IO_L11N_T1_SRCC_15 Sch=jb_n[1] +#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { jb_2 }]; #IO_L12P_T1_MRCC_15 Sch=jb_p[2] +#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { jb_3 }]; #IO_L12N_T1_MRCC_15 Sch=jb_n[2] +#set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { jb_4 }]; #IO_L23P_T3_FOE_B_15 Sch=jb_p[3] +#set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { jb_5 }]; #IO_L23N_T3_FWE_B_15 Sch=jb_n[3] +#set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { jb_6 }]; #IO_L24P_T3_RS1_15 Sch=jb_p[4] +#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { jb_7 }]; #IO_L24N_T3_RS0_15 Sch=jb_n[4] + +##Pmod Header JC + +#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L20P_T3_A08_D24_14 Sch=jc_p[1] +#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L20N_T3_A07_D23_14 Sch=jc_n[1] +#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L21P_T3_DQS_14 Sch=jc_p[2] +#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=jc_n[2] +#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { jc[4] }]; #IO_L22P_T3_A05_D21_14 Sch=jc_p[3] +#set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { jc[5] }]; #IO_L22N_T3_A04_D20_14 Sch=jc_n[3] +#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L23P_T3_A03_D19_14 Sch=jc_p[4] +#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L23N_T3_A02_D18_14 Sch=jc_n[4] + +##Pmod Header JD + +set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { jd_0 }]; #IO_L11N_T1_SRCC_35 Sch=jd[1] +set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { jd_1 }]; #IO_L12N_T1_MRCC_35 Sch=jd[2] +set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { jd_2 }]; #IO_L13P_T2_MRCC_35 Sch=jd[3] +#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd_3 }]; #IO_L13N_T2_MRCC_35 Sch=jd[4] +set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { jd_4 }]; #IO_L14P_T2_SRCC_35 Sch=jd[7] +set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { jd_5 }]; #IO_L14N_T2_SRCC_35 Sch=jd[8] +set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd_6 }]; #IO_L15P_T2_DQS_35 Sch=jd[9] +#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd_7 }]; #IO_L15N_T2_DQS_35 Sch=jd[10] + +##USB-UART Interface (FTDI FT2232H) + +set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L19N_T3_VREF_16 Sch=uart_rxd_out +set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L14N_T2_SRCC_16 Sch=uart_txd_in + + +##ChipKit Single Ended Analog Inputs +##NOTE: The ck_an_p pins can be used as single ended analog inputs with voltages from 0-3.3V (Chipkit Analog pins A0-A5). +## These signals should only be connected to the XADC core. When using these pins as digital I/O, use pins ck_io[14-19]. + +#set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[0] }]; #IO_L1N_T0_AD4N_35 Sch=ck_an_n[0] +#set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[0] }]; #IO_L1P_T0_AD4P_35 Sch=ck_an_p[0] +#set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[1] }]; #IO_L3N_T0_DQS_AD5N_35 Sch=ck_an_n[1] +#set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[1] }]; #IO_L3P_T0_DQS_AD5P_35 Sch=ck_an_p[1] +#set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[2] }]; #IO_L7N_T1_AD6N_35 Sch=ck_an_n[2] +#set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[2] }]; #IO_L7P_T1_AD6P_35 Sch=ck_an_p[2] +#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[3] }]; #IO_L9N_T1_DQS_AD7N_35 Sch=ck_an_n[3] +#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[3] }]; #IO_L9P_T1_DQS_AD7P_35 Sch=ck_an_p[3] +#set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[4] }]; #IO_L10N_T1_AD15N_35 Sch=ck_an_n[4] +#set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[4] }]; #IO_L10P_T1_AD15P_35 Sch=ck_an_p[4] +#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[5] }]; #IO_L1N_T0_AD0N_15 Sch=ck_an_n[5] +#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[5] }]; #IO_L1P_T0_AD0P_15 Sch=ck_an_p[5] + +##ChipKit Digital I/O Low + +set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ck_io_0 }]; #IO_L16P_T2_CSI_B_14 Sch=ck_io[0] +set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { ck_io_1 }]; #IO_L18P_T2_A12_D28_14 Sch=ck_io[1] +set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { ck_io_2 }]; #IO_L8N_T1_D12_14 Sch=ck_io[2] +set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { ck_io_3 }]; #IO_L19P_T3_A10_D26_14 Sch=ck_io[3] +set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { ck_io_4 }]; #IO_L5P_T0_D06_14 Sch=ck_io[4] +set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { ck_io_5 }]; #IO_L14P_T2_SRCC_14 Sch=ck_io[5] +set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { ck_io_6 }]; #IO_L14N_T2_SRCC_14 Sch=ck_io[6] +set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { ck_io_7 }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=ck_io[7] +set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { ck_io_8 }]; #IO_L11P_T1_SRCC_14 Sch=ck_io[8] +set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { ck_io_9 }]; #IO_L10P_T1_D14_14 Sch=ck_io[9] +set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { ck_io_10 }]; #IO_L18N_T2_A11_D27_14 Sch=ck_io[10] +set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ck_io_11 }]; #IO_L17N_T2_A13_D29_14 Sch=ck_io[11] +set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { ck_io_12 }]; #IO_L12N_T1_MRCC_14 Sch=ck_io[12] +set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { ck_io_13 }]; #IO_L12P_T1_MRCC_14 Sch=ck_io[13] + +##ChipKit Digital I/O On Outer Analog Header +##NOTE: These pins should be used when using the analog header signals A0-A5 as digital I/O (Chipkit digital pins 14-19) + +set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { ck_io_14 }]; #IO_0_35 Sch=ck_a[0] +set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { ck_io_15 }]; #IO_L4P_T0_35 Sch=ck_a[1] +set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { ck_io_16 }]; #IO_L4N_T0_35 Sch=ck_a[2] +set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { ck_io_17 }]; #IO_L6P_T0_35 Sch=ck_a[3] +set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { ck_io_18 }]; #IO_L6N_T0_VREF_35 Sch=ck_a[4] +set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { ck_io_19 }]; #IO_L11P_T1_SRCC_35 Sch=ck_a[5] + +##ChipKit Digital I/O On Inner Analog Header +##NOTE: These pins will need to be connected to the XADC core when used as differential analog inputs (Chipkit analog pins A6-A11) + +#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[20] }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12] +#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[21] }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12] +#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[22] }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13] +#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[23] }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13] +#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { ck_io[24] }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14] +#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { ck_io[25] }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14] + +##ChipKit Digital I/O High + +#set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[26] }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=ck_io[26] +#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[27] }]; #IO_L16N_T2_A15_D31_14 Sch=ck_io[27] +#set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[28] }]; #IO_L6N_T0_D08_VREF_14 Sch=ck_io[28] +#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[29] }]; #IO_25_14 Sch=ck_io[29] +#set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[30] }]; #IO_0_14 Sch=ck_io[30] +#set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[31] }]; #IO_L5N_T0_D07_14 Sch=ck_io[31] +#set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[32] }]; #IO_L13N_T2_MRCC_14 Sch=ck_io[32] +#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[33] }]; #IO_L13P_T2_MRCC_14 Sch=ck_io[33] +#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[34] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=ck_io[34] +#set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[35] }]; #IO_L11N_T1_SRCC_14 Sch=ck_io[35] +#set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { ck_io[36] }]; #IO_L8P_T1_D11_14 Sch=ck_io[36] +#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[37] }]; #IO_L17P_T2_A14_D30_14 Sch=ck_io[37] +#set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[38] }]; #IO_L7N_T1_D10_14 Sch=ck_io[38] +#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[39] }]; #IO_L7P_T1_D09_14 Sch=ck_io[39] +#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[40] }]; #IO_L9N_T1_DQS_D13_14 Sch=ck_io[40] +#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[41] }]; #IO_L9P_T1_DQS_14 Sch=ck_io[41] + +## ChipKit SPI + +set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L17N_T2_35 Sch=ck_miso +set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L17P_T2_35 Sch=ck_mosi +set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L18P_T2_35 Sch=ck_sck +set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L16N_T2_35 Sch=ck_ss + +## ChipKit I2C + +#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { ck_scl }]; #IO_L4P_T0_D04_14 Sch=ck_scl +#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { ck_sda }]; #IO_L4N_T0_D05_14 Sch=ck_sda +#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS33 } [get_ports { scl_pup }]; #IO_L9N_T1_DQS_AD3N_15 Sch=scl_pup +#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVCMOS33 } [get_ports { sda_pup }]; #IO_L9P_T1_DQS_AD3P_15 Sch=sda_pup + +##Misc. ChipKit signals + +#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { ck_ioa }]; #IO_L10N_T1_D15_14 Sch=ck_ioa +set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { ck_rst }]; #IO_L16P_T2_35 Sch=ck_rst + +##SMSC Ethernet PHY + +#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { eth_col }]; #IO_L16N_T2_A27_15 Sch=eth_col +#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { eth_crs }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=eth_crs +#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L14N_T2_SRCC_15 Sch=eth_mdc +#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L17P_T2_A26_15 Sch=eth_mdio +#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { eth_ref_clk }]; #IO_L22P_T3_A17_15 Sch=eth_ref_clk +#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L20P_T3_A20_15 Sch=eth_rstn +#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_clk }]; #IO_L14P_T2_SRCC_15 Sch=eth_rx_clk +#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_dv }]; #IO_L13N_T2_MRCC_15 Sch=eth_rx_dv +#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L21N_T3_DQS_A18_15 Sch=eth_rxd[0] +#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L16P_T2_A28_15 Sch=eth_rxd[1] +#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[2] }]; #IO_L21P_T3_DQS_15 Sch=eth_rxd[2] +#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[3] }]; #IO_L18N_T2_A23_15 Sch=eth_rxd[3] +#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L20N_T3_A19_15 Sch=eth_rxerr +#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_clk }]; #IO_L13P_T2_MRCC_15 Sch=eth_tx_clk +#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_en }]; #IO_L19N_T3_A21_VREF_15 Sch=eth_tx_en +#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L15P_T2_DQS_15 Sch=eth_txd[0] +#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L19P_T3_A22_15 Sch=eth_txd[1] +#set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[2] }]; #IO_L17N_T2_A25_15 Sch=eth_txd[2] +#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[3] }]; #IO_L18P_T2_A24_15 Sch=eth_txd[3] + +##Quad SPI Flash + +set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 IOB TRUE } [get_ports { qspi_sck }]; +create_clock -add -name qspi_sck_pin -period 20.00 -waveform {0 10} [get_ports { qspi_sck }]; +set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 IOB TRUE } [get_ports { qspi_cs }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_cs +set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 IOB TRUE PULLUP TRUE } [get_ports { qspi_dq_0 }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] +set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 IOB TRUE PULLUP TRUE } [get_ports { qspi_dq_1 }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] +set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 IOB TRUE PULLUP TRUE } [get_ports { qspi_dq_2 }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] +set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 IOB TRUE PULLUP TRUE } [get_ports { qspi_dq_3 }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] + +##Power Measurements + +#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_n }]; #IO_L7N_T1_AD2N_15 Sch=ad_n[2] +#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_p }]; #IO_L7P_T1_AD2P_15 Sch=ad_p[2] +#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_n }]; #IO_L3N_T0_DQS_AD1N_15 Sch=ad_n[1] +#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_p }]; #IO_L3P_T0_DQS_AD1P_15 Sch=ad_p[1] +#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_n }]; #IO_L5N_T0_AD9N_15 Sch=ad_n[9] +#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_p }]; #IO_L5P_T0_AD9P_15 Sch=ad_p[9] +#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_n }]; #IO_L8N_T1_AD10N_15 Sch=ad_n[10] +#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_p }]; #IO_L8P_T1_AD10P_15 Sch=ad_p[10] + +set_clock_groups -asynchronous \ + -group [list \ + [get_clocks -include_generated_clocks -of_objects [get_ports jd_2]]] \ + -group [list \ + [get_clocks -of_objects [get_pins ip_mmcm/inst/mmcm_adv_inst/CLKOUT0]]] \ + -group [list \ + [get_clocks -of_objects [get_pins ip_mmcm/inst/mmcm_adv_inst/CLKOUT1]] \ + [get_clocks -of_objects [get_pins ip_mmcm/inst/mmcm_adv_inst/CLKOUT2]]] diff --git a/fpga-shells/xilinx/arty/tcl/board.tcl b/fpga-shells/xilinx/arty/tcl/board.tcl new file mode 100644 index 00000000..4eaed961 --- /dev/null +++ b/fpga-shells/xilinx/arty/tcl/board.tcl @@ -0,0 +1,5 @@ +# See LICENSE for license details. +set name {arty} +set part_fpga {xc7a35ticsg324-1L} +set part_board {digilentinc.com:arty:part0:1.1} +set bootrom_inst {rom} diff --git a/fpga-shells/xilinx/arty/tcl/ip.tcl b/fpga-shells/xilinx/arty/tcl/ip.tcl new file mode 100644 index 00000000..fe07c37e --- /dev/null +++ b/fpga-shells/xilinx/arty/tcl/ip.tcl @@ -0,0 +1,44 @@ +# See LICENSE for license details. + +create_ip -vendor xilinx.com -library ip -name clk_wiz -module_name mmcm -dir $ipdir -force +set_property -dict [list \ + CONFIG.PRIMITIVE {MMCM} \ + CONFIG.RESET_TYPE {ACTIVE_LOW} \ + CONFIG.CLKOUT1_USED {true} \ + CONFIG.CLKOUT2_USED {true} \ + CONFIG.CLKOUT3_USED {true} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {8.388} \ + CONFIG.CLKOUT2_REQUESTED_OUT_FREQ {65.000} \ + CONFIG.CLKOUT3_REQUESTED_OUT_FREQ {32.500} \ + ] [get_ips mmcm] + +create_ip -vendor xilinx.com -library ip -name proc_sys_reset -module_name reset_sys -dir $ipdir -force +set_property -dict [list \ + CONFIG.C_EXT_RESET_HIGH {false} \ + CONFIG.C_AUX_RESET_HIGH {false} \ + CONFIG.C_NUM_BUS_RST {1} \ + CONFIG.C_NUM_PERP_RST {1} \ + CONFIG.C_NUM_INTERCONNECT_ARESETN {1} \ + CONFIG.C_NUM_PERP_ARESETN {1} \ + ] [get_ips reset_sys] + +create_ip -vendor xilinx.com -library ip -name ila -module_name ila -dir $ipdir -force +set_property -dict [list \ + CONFIG.C_NUM_OF_PROBES {1} \ + CONFIG.C_TRIGOUT_EN {false} \ + CONFIG.C_TRIGIN_EN {false} \ + CONFIG.C_MONITOR_TYPE {Native} \ + CONFIG.C_ENABLE_ILA_AXI_MON {false} \ + CONFIG.C_PROBE0_WIDTH {4} \ + CONFIG.C_PROBE10_TYPE {1} \ + CONFIG.C_PROBE10_WIDTH {32} \ + CONFIG.C_PROBE11_TYPE {1} \ + CONFIG.C_PROBE11_WIDTH {32} \ + CONFIG.C_PROBE12_TYPE {1} \ + CONFIG.C_PROBE12_WIDTH {64} \ + CONFIG.C_PROBE13_TYPE {1} \ + CONFIG.C_PROBE13_WIDTH {64} \ + CONFIG.C_PROBE14_TYPE {1} \ + CONFIG.C_PROBE14_WIDTH {97} \ + ] [get_ips ila] + diff --git a/fpga-shells/xilinx/arty_a7_100/constraints/arty-config.xdc b/fpga-shells/xilinx/arty_a7_100/constraints/arty-config.xdc new file mode 100644 index 00000000..a455c227 --- /dev/null +++ b/fpga-shells/xilinx/arty_a7_100/constraints/arty-config.xdc @@ -0,0 +1,5 @@ +set_property -dict [list \ + CONFIG_VOLTAGE {3.3} \ + CFGBVS {VCCO} \ + BITSTREAM.CONFIG.SPI_BUSWIDTH {4} \ + ] [current_design] diff --git a/fpga-shells/xilinx/arty_a7_100/constraints/arty-master.xdc b/fpga-shells/xilinx/arty_a7_100/constraints/arty-master.xdc new file mode 100644 index 00000000..be9ff378 --- /dev/null +++ b/fpga-shells/xilinx/arty_a7_100/constraints/arty-master.xdc @@ -0,0 +1,240 @@ +## This file is a general .xdc for the ARTY Rev. B +## To use it in a project: +## - uncomment the lines corresponding to used pins +## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project + +## Clock signal + +set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { CLK100MHZ }]; #IO_L12P_T1_MRCC_35 Sch=gclk[100] +create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {CLK100MHZ}]; +create_clock -add -name JTCK -period 100 -waveform {0 50} [get_ports {jd_2}]; + +##Switches + +set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { sw_0 }]; #IO_L12N_T1_MRCC_16 Sch=sw[0] +set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { sw_1 }]; #IO_L13P_T2_MRCC_16 Sch=sw[1] +set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { sw_2 }]; #IO_L13N_T2_MRCC_16 Sch=sw[2] +set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { sw_3 }]; #IO_L14P_T2_SRCC_16 Sch=sw[3] + +##RGB LEDs + +set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { led0_b }]; #IO_L18N_T2_35 Sch=led0_b +set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { led0_g }]; #IO_L19N_T3_VREF_35 Sch=led0_g +set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { led0_r }]; #IO_L19P_T3_35 Sch=led0_r +set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { led1_b }]; #IO_L20P_T3_35 Sch=led1_b +set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { led1_g }]; #IO_L21P_T3_DQS_35 Sch=led1_g +set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { led1_r }]; #IO_L20N_T3_35 Sch=led1_r +set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { led2_b }]; #IO_L21N_T3_DQS_35 Sch=led2_b +set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { led2_g }]; #IO_L22N_T3_35 Sch=led2_g +set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { led2_r }]; #IO_L22P_T3_35 Sch=led2_r +#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { led3_b }]; #IO_L23P_T3_35 Sch=led3_b +#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { led3_g }]; #IO_L24P_T3_35 Sch=led3_g +#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { led3_r }]; #IO_L23N_T3_35 Sch=led3_r + +##LEDs + +set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { led_0 }]; #IO_L24N_T3_35 Sch=led[4] +set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { led_1 }]; #IO_25_35 Sch=led[5] +set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { led_2 }]; #IO_L24P_T3_A01_D17_14 Sch=led[6] +set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { led_3 }]; #IO_L24N_T3_A00_D16_14 Sch=led[7] + +##Buttons + +set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { btn_0 }]; #IO_L6N_T0_VREF_16 Sch=btn[0] +set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { btn_1 }]; #IO_L11P_T1_SRCC_16 Sch=btn[1] +set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { btn_2 }]; #IO_L11N_T1_SRCC_16 Sch=btn[2] +set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { btn_3 }]; #IO_L12P_T1_MRCC_16 Sch=btn[3] + +##Pmod Header JA + +set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { ja_0 }]; #IO_0_15 Sch=ja[1] +set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { ja_1 }]; #IO_L4P_T0_15 Sch=ja[2] +set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { ja_2 }]; #IO_L4N_T0_15 Sch=ja[3] +set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { ja_3 }]; #IO_L6P_T0_15 Sch=ja[4] +set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { ja_4 }]; #IO_L6N_T0_VREF_15 Sch=ja[7] +set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports { ja_5 }]; #IO_L10P_T1_AD11P_15 Sch=ja[8] +set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports { ja_6 }]; #IO_L10N_T1_AD11N_15 Sch=ja[9] +set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { ja_7 }]; #IO_25_15 Sch=ja[10] + +##Pmod Header JB + +#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { jb_0 }]; #IO_L11P_T1_SRCC_15 Sch=jb_p[1] +#set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jb_1 }]; #IO_L11N_T1_SRCC_15 Sch=jb_n[1] +#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { jb_2 }]; #IO_L12P_T1_MRCC_15 Sch=jb_p[2] +#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { jb_3 }]; #IO_L12N_T1_MRCC_15 Sch=jb_n[2] +#set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { jb_4 }]; #IO_L23P_T3_FOE_B_15 Sch=jb_p[3] +#set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { jb_5 }]; #IO_L23N_T3_FWE_B_15 Sch=jb_n[3] +#set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { jb_6 }]; #IO_L24P_T3_RS1_15 Sch=jb_p[4] +#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { jb_7 }]; #IO_L24N_T3_RS0_15 Sch=jb_n[4] + +##Pmod Header JC + +#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L20P_T3_A08_D24_14 Sch=jc_p[1] +#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L20N_T3_A07_D23_14 Sch=jc_n[1] +#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L21P_T3_DQS_14 Sch=jc_p[2] +#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=jc_n[2] +#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { jc[4] }]; #IO_L22P_T3_A05_D21_14 Sch=jc_p[3] +#set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { jc[5] }]; #IO_L22N_T3_A04_D20_14 Sch=jc_n[3] +#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L23P_T3_A03_D19_14 Sch=jc_p[4] +#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L23N_T3_A02_D18_14 Sch=jc_n[4] + +##Pmod Header JD + +set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { jd_0 }]; #IO_L11N_T1_SRCC_35 Sch=jd[1] +set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { jd_1 }]; #IO_L12N_T1_MRCC_35 Sch=jd[2] +set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { jd_2 }]; #IO_L13P_T2_MRCC_35 Sch=jd[3] +#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd_3 }]; #IO_L13N_T2_MRCC_35 Sch=jd[4] +set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { jd_4 }]; #IO_L14P_T2_SRCC_35 Sch=jd[7] +set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { jd_5 }]; #IO_L14N_T2_SRCC_35 Sch=jd[8] +set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd_6 }]; #IO_L15P_T2_DQS_35 Sch=jd[9] +#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd_7 }]; #IO_L15N_T2_DQS_35 Sch=jd[10] + +##USB-UART Interface (FTDI FT2232H) + +set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L19N_T3_VREF_16 Sch=uart_rxd_out +set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L14N_T2_SRCC_16 Sch=uart_txd_in + + +##ChipKit Single Ended Analog Inputs +##NOTE: The ck_an_p pins can be used as single ended analog inputs with voltages from 0-3.3V (Chipkit Analog pins A0-A5). +## These signals should only be connected to the XADC core. When using these pins as digital I/O, use pins ck_io[14-19]. + +#set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[0] }]; #IO_L1N_T0_AD4N_35 Sch=ck_an_n[0] +#set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[0] }]; #IO_L1P_T0_AD4P_35 Sch=ck_an_p[0] +#set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[1] }]; #IO_L3N_T0_DQS_AD5N_35 Sch=ck_an_n[1] +#set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[1] }]; #IO_L3P_T0_DQS_AD5P_35 Sch=ck_an_p[1] +#set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[2] }]; #IO_L7N_T1_AD6N_35 Sch=ck_an_n[2] +#set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[2] }]; #IO_L7P_T1_AD6P_35 Sch=ck_an_p[2] +#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[3] }]; #IO_L9N_T1_DQS_AD7N_35 Sch=ck_an_n[3] +#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[3] }]; #IO_L9P_T1_DQS_AD7P_35 Sch=ck_an_p[3] +#set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[4] }]; #IO_L10N_T1_AD15N_35 Sch=ck_an_n[4] +#set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[4] }]; #IO_L10P_T1_AD15P_35 Sch=ck_an_p[4] +#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { ck_an_n[5] }]; #IO_L1N_T0_AD0N_15 Sch=ck_an_n[5] +#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { ck_an_p[5] }]; #IO_L1P_T0_AD0P_15 Sch=ck_an_p[5] + +##ChipKit Digital I/O Low + +set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ck_io_0 }]; #IO_L16P_T2_CSI_B_14 Sch=ck_io[0] +set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { ck_io_1 }]; #IO_L18P_T2_A12_D28_14 Sch=ck_io[1] +set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { ck_io_2 }]; #IO_L8N_T1_D12_14 Sch=ck_io[2] +set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { ck_io_3 }]; #IO_L19P_T3_A10_D26_14 Sch=ck_io[3] +set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { ck_io_4 }]; #IO_L5P_T0_D06_14 Sch=ck_io[4] +set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { ck_io_5 }]; #IO_L14P_T2_SRCC_14 Sch=ck_io[5] +set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { ck_io_6 }]; #IO_L14N_T2_SRCC_14 Sch=ck_io[6] +set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { ck_io_7 }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=ck_io[7] +set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { ck_io_8 }]; #IO_L11P_T1_SRCC_14 Sch=ck_io[8] +set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { ck_io_9 }]; #IO_L10P_T1_D14_14 Sch=ck_io[9] +set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { ck_io_10 }]; #IO_L18N_T2_A11_D27_14 Sch=ck_io[10] +set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ck_io_11 }]; #IO_L17N_T2_A13_D29_14 Sch=ck_io[11] +set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { ck_io_12 }]; #IO_L12N_T1_MRCC_14 Sch=ck_io[12] +set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { ck_io_13 }]; #IO_L12P_T1_MRCC_14 Sch=ck_io[13] + +##ChipKit Digital I/O On Outer Analog Header +##NOTE: These pins should be used when using the analog header signals A0-A5 as digital I/O (Chipkit digital pins 14-19) + +set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { ck_io_14 }]; #IO_0_35 Sch=ck_a[0] +set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { ck_io_15 }]; #IO_L4P_T0_35 Sch=ck_a[1] +set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { ck_io_16 }]; #IO_L4N_T0_35 Sch=ck_a[2] +set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { ck_io_17 }]; #IO_L6P_T0_35 Sch=ck_a[3] +set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { ck_io_18 }]; #IO_L6N_T0_VREF_35 Sch=ck_a[4] +set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { ck_io_19 }]; #IO_L11P_T1_SRCC_35 Sch=ck_a[5] + +##ChipKit Digital I/O On Inner Analog Header +##NOTE: These pins will need to be connected to the XADC core when used as differential analog inputs (Chipkit analog pins A6-A11) + +#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[20] }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12] +#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[21] }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12] +#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { ck_io[22] }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13] +#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[23] }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13] +#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { ck_io[24] }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14] +#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { ck_io[25] }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14] + +##ChipKit Digital I/O High + +#set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[26] }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=ck_io[26] +#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[27] }]; #IO_L16N_T2_A15_D31_14 Sch=ck_io[27] +#set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[28] }]; #IO_L6N_T0_D08_VREF_14 Sch=ck_io[28] +#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { ck_io[29] }]; #IO_25_14 Sch=ck_io[29] +#set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[30] }]; #IO_0_14 Sch=ck_io[30] +#set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { ck_io[31] }]; #IO_L5N_T0_D07_14 Sch=ck_io[31] +#set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[32] }]; #IO_L13N_T2_MRCC_14 Sch=ck_io[32] +#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[33] }]; #IO_L13P_T2_MRCC_14 Sch=ck_io[33] +#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[34] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=ck_io[34] +#set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[35] }]; #IO_L11N_T1_SRCC_14 Sch=ck_io[35] +#set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { ck_io[36] }]; #IO_L8P_T1_D11_14 Sch=ck_io[36] +#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[37] }]; #IO_L17P_T2_A14_D30_14 Sch=ck_io[37] +#set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[38] }]; #IO_L7N_T1_D10_14 Sch=ck_io[38] +#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[39] }]; #IO_L7P_T1_D09_14 Sch=ck_io[39] +#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[40] }]; #IO_L9N_T1_DQS_D13_14 Sch=ck_io[40] +#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[41] }]; #IO_L9P_T1_DQS_14 Sch=ck_io[41] + +## ChipKit SPI + +set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L17N_T2_35 Sch=ck_miso +set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L17P_T2_35 Sch=ck_mosi +set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L18P_T2_35 Sch=ck_sck +set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L16N_T2_35 Sch=ck_ss + +## ChipKit I2C + +#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { ck_scl }]; #IO_L4P_T0_D04_14 Sch=ck_scl +#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { ck_sda }]; #IO_L4N_T0_D05_14 Sch=ck_sda +#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS33 } [get_ports { scl_pup }]; #IO_L9N_T1_DQS_AD3N_15 Sch=scl_pup +#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVCMOS33 } [get_ports { sda_pup }]; #IO_L9P_T1_DQS_AD3P_15 Sch=sda_pup + +##Misc. ChipKit signals + +#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { ck_ioa }]; #IO_L10N_T1_D15_14 Sch=ck_ioa +set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { ck_rst }]; #IO_L16P_T2_35 Sch=ck_rst + +##SMSC Ethernet PHY + +#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { eth_col }]; #IO_L16N_T2_A27_15 Sch=eth_col +#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { eth_crs }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=eth_crs +#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L14N_T2_SRCC_15 Sch=eth_mdc +#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L17P_T2_A26_15 Sch=eth_mdio +#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { eth_ref_clk }]; #IO_L22P_T3_A17_15 Sch=eth_ref_clk +#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L20P_T3_A20_15 Sch=eth_rstn +#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_clk }]; #IO_L14P_T2_SRCC_15 Sch=eth_rx_clk +#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_dv }]; #IO_L13N_T2_MRCC_15 Sch=eth_rx_dv +#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L21N_T3_DQS_A18_15 Sch=eth_rxd[0] +#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L16P_T2_A28_15 Sch=eth_rxd[1] +#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[2] }]; #IO_L21P_T3_DQS_15 Sch=eth_rxd[2] +#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[3] }]; #IO_L18N_T2_A23_15 Sch=eth_rxd[3] +#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L20N_T3_A19_15 Sch=eth_rxerr +#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_clk }]; #IO_L13P_T2_MRCC_15 Sch=eth_tx_clk +#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_en }]; #IO_L19N_T3_A21_VREF_15 Sch=eth_tx_en +#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L15P_T2_DQS_15 Sch=eth_txd[0] +#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L19P_T3_A22_15 Sch=eth_txd[1] +#set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[2] }]; #IO_L17N_T2_A25_15 Sch=eth_txd[2] +#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[3] }]; #IO_L18P_T2_A24_15 Sch=eth_txd[3] + +##Quad SPI Flash + +set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 IOB TRUE } [get_ports { qspi_sck }]; +create_clock -add -name qspi_sck_pin -period 20.00 -waveform {0 10} [get_ports { qspi_sck }]; +set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 IOB TRUE } [get_ports { qspi_cs }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_cs +set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 IOB TRUE PULLUP TRUE } [get_ports { qspi_dq_0 }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] +set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 IOB TRUE PULLUP TRUE } [get_ports { qspi_dq_1 }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] +set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 IOB TRUE PULLUP TRUE } [get_ports { qspi_dq_2 }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] +set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 IOB TRUE PULLUP TRUE } [get_ports { qspi_dq_3 }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] + +##Power Measurements + +#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_n }]; #IO_L7N_T1_AD2N_15 Sch=ad_n[2] +#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_p }]; #IO_L7P_T1_AD2P_15 Sch=ad_p[2] +#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_n }]; #IO_L3N_T0_DQS_AD1N_15 Sch=ad_n[1] +#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_p }]; #IO_L3P_T0_DQS_AD1P_15 Sch=ad_p[1] +#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_n }]; #IO_L5N_T0_AD9N_15 Sch=ad_n[9] +#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_p }]; #IO_L5P_T0_AD9P_15 Sch=ad_p[9] +#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_n }]; #IO_L8N_T1_AD10N_15 Sch=ad_n[10] +#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_p }]; #IO_L8P_T1_AD10P_15 Sch=ad_p[10] + +set_clock_groups -asynchronous \ + -group [list \ + [get_clocks -include_generated_clocks -of_objects [get_ports jd_2]]] \ + -group [list \ + [get_clocks -of_objects [get_pins ip_mmcm/inst/mmcm_adv_inst/CLKOUT0]]] \ + -group [list \ + [get_clocks -of_objects [get_pins ip_mmcm/inst/mmcm_adv_inst/CLKOUT1]] \ + [get_clocks -of_objects [get_pins ip_mmcm/inst/mmcm_adv_inst/CLKOUT2]]] diff --git a/fpga-shells/xilinx/arty_a7_100/tcl/board.tcl b/fpga-shells/xilinx/arty_a7_100/tcl/board.tcl new file mode 100644 index 00000000..70635da5 --- /dev/null +++ b/fpga-shells/xilinx/arty_a7_100/tcl/board.tcl @@ -0,0 +1,5 @@ +# See LICENSE for license details. +set name {arty-a7-100} +set part_fpga {xc7a100ticsg324-1L} +set part_board {digilentinc.com:arty-a7-100:part0:1.0} +set bootrom_inst {rom} diff --git a/fpga-shells/xilinx/arty_a7_100/tcl/ip.tcl b/fpga-shells/xilinx/arty_a7_100/tcl/ip.tcl new file mode 100644 index 00000000..fe07c37e --- /dev/null +++ b/fpga-shells/xilinx/arty_a7_100/tcl/ip.tcl @@ -0,0 +1,44 @@ +# See LICENSE for license details. + +create_ip -vendor xilinx.com -library ip -name clk_wiz -module_name mmcm -dir $ipdir -force +set_property -dict [list \ + CONFIG.PRIMITIVE {MMCM} \ + CONFIG.RESET_TYPE {ACTIVE_LOW} \ + CONFIG.CLKOUT1_USED {true} \ + CONFIG.CLKOUT2_USED {true} \ + CONFIG.CLKOUT3_USED {true} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {8.388} \ + CONFIG.CLKOUT2_REQUESTED_OUT_FREQ {65.000} \ + CONFIG.CLKOUT3_REQUESTED_OUT_FREQ {32.500} \ + ] [get_ips mmcm] + +create_ip -vendor xilinx.com -library ip -name proc_sys_reset -module_name reset_sys -dir $ipdir -force +set_property -dict [list \ + CONFIG.C_EXT_RESET_HIGH {false} \ + CONFIG.C_AUX_RESET_HIGH {false} \ + CONFIG.C_NUM_BUS_RST {1} \ + CONFIG.C_NUM_PERP_RST {1} \ + CONFIG.C_NUM_INTERCONNECT_ARESETN {1} \ + CONFIG.C_NUM_PERP_ARESETN {1} \ + ] [get_ips reset_sys] + +create_ip -vendor xilinx.com -library ip -name ila -module_name ila -dir $ipdir -force +set_property -dict [list \ + CONFIG.C_NUM_OF_PROBES {1} \ + CONFIG.C_TRIGOUT_EN {false} \ + CONFIG.C_TRIGIN_EN {false} \ + CONFIG.C_MONITOR_TYPE {Native} \ + CONFIG.C_ENABLE_ILA_AXI_MON {false} \ + CONFIG.C_PROBE0_WIDTH {4} \ + CONFIG.C_PROBE10_TYPE {1} \ + CONFIG.C_PROBE10_WIDTH {32} \ + CONFIG.C_PROBE11_TYPE {1} \ + CONFIG.C_PROBE11_WIDTH {32} \ + CONFIG.C_PROBE12_TYPE {1} \ + CONFIG.C_PROBE12_WIDTH {64} \ + CONFIG.C_PROBE13_TYPE {1} \ + CONFIG.C_PROBE13_WIDTH {64} \ + CONFIG.C_PROBE14_TYPE {1} \ + CONFIG.C_PROBE14_WIDTH {97} \ + ] [get_ips ila] + diff --git a/fpga-shells/xilinx/common/tcl/bitstream.tcl b/fpga-shells/xilinx/common/tcl/bitstream.tcl new file mode 100644 index 00000000..bf223f66 --- /dev/null +++ b/fpga-shells/xilinx/common/tcl/bitstream.tcl @@ -0,0 +1,10 @@ +# See LICENSE for license details. + +# Write a bitstream for the current design +write_bitstream -force [file join $wrkdir "${top}.bit"] + +# Save the timing delays for cells in the design in SDF format +write_sdf -force [file join $wrkdir "${top}.sdf"] + +# Export the current netlist in verilog format +write_verilog -mode timesim -force [file join ${wrkdir} "${top}.v"] diff --git a/fpga-shells/xilinx/common/tcl/boards.tcl b/fpga-shells/xilinx/common/tcl/boards.tcl new file mode 100644 index 00000000..af1c686b --- /dev/null +++ b/fpga-shells/xilinx/common/tcl/boards.tcl @@ -0,0 +1,9 @@ +# See LICENSE for license details. + +namespace eval ::program::boards {} + +set ::program::boards::spec [dict create \ + arty [dict create iface spix4 size 16 bitaddr 0x0 memdev {n25q128-3.3v-spi-x1_x2_x4}] \ + arty_a7_100 [dict create iface spix4 size 16 bitaddr 0x0 memdev {s25fl128sxxxxxx0-spi-x1_x2_x4}] \ + vc707 [dict create iface bpix16 size 128 bitaddr 0x3000000 ] \ + vcu118 [dict create iface spix8 size 256 bitaddr 0x0 memdev {mt25qu01g-spi-x1_x2_x4_x8}]] diff --git a/fpga-shells/xilinx/common/tcl/init.tcl b/fpga-shells/xilinx/common/tcl/init.tcl new file mode 100644 index 00000000..ccf720c4 --- /dev/null +++ b/fpga-shells/xilinx/common/tcl/init.tcl @@ -0,0 +1,48 @@ +# See LICENSE for license details. + +# Include helper functions +source [file join $scriptdir "util.tcl"] + +# Create the diretory for IPs +file mkdir $ipdir + +# Update the IP catalog +update_ip_catalog -rebuild + +# Generate IP implementations. Vivado TCL emitted from Chisel Blackboxes +foreach ip_vivado_tcl $ip_vivado_tcls { + source $ip_vivado_tcl +} +# Optional board-specific ip script +set boardiptcl [file join $boarddir tcl ip.tcl] +if {[file exists $boardiptcl]} { + source $boardiptcl +} + +# AR 58526 +set xci_files [get_files -all {*.xci}] +foreach xci_file $xci_files { + set_property GENERATE_SYNTH_CHECKPOINT {false} -quiet $xci_file +} + +# Get a list of IPs in the current design +set obj [get_ips] + +# Generate target data for the inlcuded IPs in the design +generate_target all $obj + +# Export the IP user files +export_ip_user_files -of_objects $obj -no_script -force + +# Get the list of active source and constraint files +set obj [current_fileset] + +#Xilinx bug workaround +#scrape IP tree for directories containing .vh files +#[get_property include_dirs] misses all IP core subdirectory includes if user has specified -dir flag in create_ip +set property_include_dirs [get_property include_dirs $obj] + +# Include generated files for the IPs in the design +set ip_include_dirs [concat $property_include_dirs [findincludedir $ipdir "*.vh"]] +set ip_include_dirs [concat $ip_include_dirs [findincludedir $srcdir "*.h"]] +set ip_include_dirs [concat $ip_include_dirs [findincludedir $srcdir "*.vh"]] diff --git a/fpga-shells/xilinx/common/tcl/opt.tcl b/fpga-shells/xilinx/common/tcl/opt.tcl new file mode 100644 index 00000000..81bf4ad1 --- /dev/null +++ b/fpga-shells/xilinx/common/tcl/opt.tcl @@ -0,0 +1,7 @@ +# See LICENSE for license details. + +# Optimize the netlist +opt_design -directive Explore + +# Checkpoint the current design +write_checkpoint -force [file join $wrkdir post_opt] diff --git a/fpga-shells/xilinx/common/tcl/place.tcl b/fpga-shells/xilinx/common/tcl/place.tcl new file mode 100644 index 00000000..ccc862a1 --- /dev/null +++ b/fpga-shells/xilinx/common/tcl/place.tcl @@ -0,0 +1,13 @@ +# See LICENSE for license details. + +# Place the current design +place_design -directive Explore + +# Optimize the current placed netlist +phys_opt_design -directive Explore + +# Optimize dynamic power using intelligent clock gating +power_opt_design + +# Checkpoint the current design +write_checkpoint -force [file join $wrkdir post_place] diff --git a/fpga-shells/xilinx/common/tcl/prologue.tcl b/fpga-shells/xilinx/common/tcl/prologue.tcl new file mode 100644 index 00000000..f546a71f --- /dev/null +++ b/fpga-shells/xilinx/common/tcl/prologue.tcl @@ -0,0 +1,119 @@ +# See LICENSE for license details. + +# Process command line arguments +# http://wiki.tcl.tk/1730 +set ip_vivado_tcls {} + +while {[llength $argv]} { + set argv [lassign $argv[set argv {}] flag] + switch -glob $flag { + -top-module { + set argv [lassign $argv[set argv {}] top] + } + -F { + # This should be a simple file format with one filepath per line + set argv [lassign $argv[set argv {}] vsrc_manifest] + } + -board { + set argv [lassign $argv[set argv {}] board] + } + -ip-vivado-tcls { + set argv [lassign $argv[set argv {}] ip_vivado_tcls] + } + -pre-impl-debug-tcl { + set argv [lassign $argv[set argv {}] pre_impl_debug_tcl] + } + -post-impl-debug-tcl { + set argv [lassign $argv[set argv {}] post_impl_debug_tcl] + } + default { + return -code error [list {unknown option} $flag] + } + } +} + +if {![info exists top]} { + return -code error [list {--top-module option is required}] +} + +if {![info exists vsrc_manifest]} { + return -code error [list {-F option is required}] +} + +if {![info exists board]} { + return -code error [list {--board option is required}] +} + +# Set the variable for all the common files +set commondir [file dirname $scriptdir] + +# Set the variable that points to board specific files +set boarddir [file join [file dirname $commondir] $board] +source [file join $boarddir tcl board.tcl] + +# Set the variable that points to board constraint files +set constraintsdir [file join $boarddir constraints] + +# Set the variable that points to common verilog sources +set srcdir [file join $commondir vsrc] + +# Creates a work directory +set wrkdir [file join [pwd] obj] + +# Create the directory for IPs +set ipdir [file join $wrkdir ip] + +# Create an in-memory project +create_project -part $part_fpga -force $top + +# Set the board part, target language, default library, and IP directory +# paths for the current project +set_property -dict [list \ + BOARD_PART $part_board \ + TARGET_LANGUAGE {Verilog} \ + DEFAULT_LIB {xil_defaultlib} \ + IP_REPO_PATHS $ipdir \ + ] [current_project] + +if {[get_filesets -quiet sources_1] eq ""} { + create_fileset -srcset sources_1 +} +set obj [current_fileset] + +# Add verilog files from manifest +proc load_vsrc_manifest {obj vsrc_manifest} { + set fp [open $vsrc_manifest r] + set files [lsearch -not -exact -all -inline [split [read $fp] "\n"] {}] + set relative_files {} + foreach path $files { + if {[string match {/*} $path]} { + lappend relative_files $path + } elseif {![string match {#*} $path]} { + lappend relative_files [file join [file dirname $vsrc_manifest] $path] + } + } + add_files -norecurse -fileset $obj {*}$relative_files + close $fp +} + +load_vsrc_manifest $obj $vsrc_manifest + +# Add IP Vivado TCL +if {$ip_vivado_tcls ne {}} { + # Split string into words even with multiple consecutive spaces + # http://wiki.tcl.tk/989 + set ip_vivado_tcls [regexp -inline -all -- {\S+} $ip_vivado_tcls] +} + +if {[get_filesets -quiet sim_1] eq ""} { + create_fileset -simset sim_1 +} +set obj [current_fileset -simset] + +if {[get_filesets -quiet constrs_1] eq ""} { + create_fileset -constrset constrs_1 +} + +set obj [current_fileset -constrset] +add_files -quiet -norecurse -fileset $obj [lsort [glob -directory $constraintsdir -nocomplain {*.xdc}]] +add_files -quiet -norecurse -fileset $obj [lsort [glob -directory $constraintsdir -nocomplain {*.tcl}]] diff --git a/fpga-shells/xilinx/common/tcl/report.tcl b/fpga-shells/xilinx/common/tcl/report.tcl new file mode 100644 index 00000000..a4995373 --- /dev/null +++ b/fpga-shells/xilinx/common/tcl/report.tcl @@ -0,0 +1,44 @@ +# See LICENSE for license details. + +# Create a report directory +set rptdir [file join $wrkdir report] +file mkdir $rptdir + +# Create a datasheet for the current design +report_datasheet -file [file join $rptdir datasheet.txt] + +# Report utilization of the current device +set rptutil [file join $rptdir utilization.txt] +report_utilization -hierarchical -file $rptutil + +# Report information about clock nets in the design +report_clock_utilization -file $rptutil -append + +# Report the RAM resources utilized in the implemented design +report_ram_utilization -file $rptutil -append -detail + +# Report timing summary for a max of 10 paths per group +report_timing_summary -file [file join $rptdir timing.txt] -max_paths 10 + +# Report the highest fanout of nets in the implemented design +report_high_fanout_nets -file [file join $rptdir fanout.txt] -timing -load_types -max_nets 25 + +# Run DRC +report_drc -file [file join $rptdir drc.txt] + +# Report details of the IO banks in the design +report_io -file [file join $rptdir io.txt] + +# Report a table of all clocks in the design +report_clocks -file [file join $rptdir clocks.txt] + +# Fail loudly if timing not met +# +# We would ideally elevate critical warning Route 35-39 to an error, but it is +# currently not being emitted with our flow for some reason. +# https://forums.xilinx.com/t5/Implementation/Making-timing-violations-fatal-to-the-Vivado-build/m-p/716957#M15979 +set timing_slack [get_property SLACK [get_timing_paths]] +if {$timing_slack < 0} { + puts "Failed to meet timing by $timing_slack, see [file join $rptdir timing.txt]" + exit 1 +} diff --git a/fpga-shells/xilinx/common/tcl/route.tcl b/fpga-shells/xilinx/common/tcl/route.tcl new file mode 100644 index 00000000..68fc84a6 --- /dev/null +++ b/fpga-shells/xilinx/common/tcl/route.tcl @@ -0,0 +1,10 @@ +# See LICENSE for license details. + +# Route the current design +route_design -directive Explore + +# Optimize the current design post routing +phys_opt_design -directive Explore + +# Checkpoint the current design +write_checkpoint -force [file join $wrkdir post_route] diff --git a/fpga-shells/xilinx/common/tcl/synth.tcl b/fpga-shells/xilinx/common/tcl/synth.tcl new file mode 100644 index 00000000..f3501850 --- /dev/null +++ b/fpga-shells/xilinx/common/tcl/synth.tcl @@ -0,0 +1,10 @@ +# See LICENSE for license details. + +# Read the specified list of IP files +read_ip [glob -directory $ipdir [file join * {*.xci}]] + +# Synthesize the design +synth_design -top $top -flatten_hierarchy rebuilt + +# Checkpoint the current design +write_checkpoint -force [file join $wrkdir post_synth] diff --git a/fpga-shells/xilinx/common/tcl/util.tcl b/fpga-shells/xilinx/common/tcl/util.tcl new file mode 100644 index 00000000..eda723f4 --- /dev/null +++ b/fpga-shells/xilinx/common/tcl/util.tcl @@ -0,0 +1,24 @@ +# See LICENSE for license details. + +# Helper function that recursively includes files given a directory and a +# pattern/suffix extensions +proc recglob { basedir pattern } { + set dirlist [glob -nocomplain -directory $basedir -type d *] + set findlist [glob -nocomplain -directory $basedir $pattern] + foreach dir $dirlist { + set reclist [recglob $dir $pattern] + set findlist [concat $findlist $reclist] + } + return $findlist +} + +# Helper function to find all subdirectories containing ".vh" files +proc findincludedir { basedir pattern } { + set vhfiles [recglob $basedir $pattern] + set vhdirs {} + foreach match $vhfiles { + lappend vhdirs [file dir $match] + } + set uniquevhdirs [lsort -unique $vhdirs] + return $uniquevhdirs +} diff --git a/fpga-shells/xilinx/common/tcl/vivado.tcl b/fpga-shells/xilinx/common/tcl/vivado.tcl new file mode 100644 index 00000000..18cf17a2 --- /dev/null +++ b/fpga-shells/xilinx/common/tcl/vivado.tcl @@ -0,0 +1,38 @@ +# See LICENSE for license details. + +# Set the variable for the directory that includes all scripts +set scriptdir [file dirname [info script]] + +# Set up variables and Vivado objects +source [file join $scriptdir "prologue.tcl"] + +# Initialize Vivado project files +source [file join $scriptdir "init.tcl"] + +# Synthesize the design +source [file join $scriptdir "synth.tcl"] + +# Pre-implementation debug +if {[info exists pre_impl_debug_tcl]} { + source [file join $scriptdir $pre_impl_debug_tcl] +} + +# Post synthesis optimization +source [file join $scriptdir "opt.tcl"] + +# Place the design +source [file join $scriptdir "place.tcl"] + +# Route the design +source [file join $scriptdir "route.tcl"] + +# Generate bitstream and save verilog netlist +source [file join $scriptdir "bitstream.tcl"] + +# Post-implementation debug +if {[info exists post_impl_debug_tcl)]} { + source [file join $scriptdir $post_impl_debug_tcl] +} + +# Create reports for the current implementation +source [file join $scriptdir "report.tcl"] diff --git a/fpga-shells/xilinx/common/tcl/write_cfgmem.tcl b/fpga-shells/xilinx/common/tcl/write_cfgmem.tcl new file mode 100644 index 00000000..ebce010d --- /dev/null +++ b/fpga-shells/xilinx/common/tcl/write_cfgmem.tcl @@ -0,0 +1,26 @@ +# See LICENSE for license details. +# +# Create an MCS-format memory configuration file from a bitstream and an +# optional data file. + +set script_program_dir [file dirname [info script]] +source [file join $script_program_dir {boards.tcl}] + +if {$argc < 3 || $argc > 4} { + puts $argc + puts {Error: Invalid number of arguments} + puts {Usage: write_cfgmem.tcl board mcsfile bitfile [datafile]} + exit 1 +} +lassign $argv board mcsfile bitfile datafile + +if {![dict exists $::program::boards::spec $board]} { + puts {Unsupported board} + exit 1 +} +set board [dict get $::program::boards::spec $board] + +write_cfgmem -format mcs -interface [dict get $board iface] -size [dict get $board size] \ + -loadbit "up [dict get $board bitaddr] $bitfile" \ + -loaddata [expr {$datafile ne "" ? "up 0x400000 $datafile" : ""}] \ + -file $mcsfile -force diff --git a/fpga-shells/xilinx/common/vsrc/PowerOnResetFPGAOnly.v b/fpga-shells/xilinx/common/vsrc/PowerOnResetFPGAOnly.v new file mode 100644 index 00000000..0355596e --- /dev/null +++ b/fpga-shells/xilinx/common/vsrc/PowerOnResetFPGAOnly.v @@ -0,0 +1,16 @@ +// See LICENSE file for license details. +(* keep_hierarchy = "yes" *) module PowerOnResetFPGAOnly( + input clock, + (* dont_touch = "true" *) output power_on_reset +); + reg reset; + assign power_on_reset = reset; + + initial begin + reset <= 1'b1; + end + + always @(posedge clock) begin + reset <= 1'b0; + end +endmodule diff --git a/fpga-shells/xilinx/vc707/constraints/vc707-master.xdc b/fpga-shells/xilinx/vc707/constraints/vc707-master.xdc new file mode 100644 index 00000000..b972196f --- /dev/null +++ b/fpga-shells/xilinx/vc707/constraints/vc707-master.xdc @@ -0,0 +1,6 @@ +#-------------- MCS Generation ---------------------- +set_property CFGBVS GND [current_design] +set_property CONFIG_VOLTAGE 1.8 [current_design] + +set_property EXTRACT_ENABLE YES [get_cells dut_/spi_0_1/mac/phy/txd_reg*] +set_property EXTRACT_ENABLE YES [get_cells dut_/spi_0_1/mac/phy/sck_reg] diff --git a/fpga-shells/xilinx/vc707/tcl/board.tcl b/fpga-shells/xilinx/vc707/tcl/board.tcl new file mode 100644 index 00000000..1043fa2c --- /dev/null +++ b/fpga-shells/xilinx/vc707/tcl/board.tcl @@ -0,0 +1,4 @@ +# See LICENSE for license details. +set name {vc707} +set part_fpga {xc7vx485tffg1761-2} +set part_board {xilinx.com:vc707:part0:1.3} diff --git a/fpga-shells/xilinx/vc707/tcl/clocks.tcl b/fpga-shells/xilinx/vc707/tcl/clocks.tcl new file mode 100644 index 00000000..71b18733 --- /dev/null +++ b/fpga-shells/xilinx/vc707/tcl/clocks.tcl @@ -0,0 +1,50 @@ +if { [llength [get_ports -quiet chiplink_b2c_clk]] > 0 } { + create_clock -name chiplink_b2c_clock -period 10 [get_ports chiplink_b2c_clk] + create_generated_clock -name {chiplink_c2b_clock} \ + -divide_by 1 \ + -source [ get_pins { vc707_sys_clock_mmcm0/inst/mmcm_adv_inst/CLKOUT6 } ] \ + [ get_ports { chiplink_c2b_clk } ] + + # RX side: want to latch almost anywhere except on the rising edge of the clock + # The data signals coming from Aloe have: clock - 1.2 <= transition <= clock + 0.8 + # Let's add 0.6ns of safety for trace jitter+skew on both sides: + # min = hold = - 1.2 - 0.6 + # max = period - setup = 0.8 + 0.6 + set_input_delay -min -1.8 -clock {chiplink_b2c_clock} [ get_ports { chiplink_b2c_data* chiplink_b2c_rst chiplink_b2c_send } ] + set_input_delay -max 1.4 -clock {chiplink_b2c_clock} [ get_ports { chiplink_b2c_data* chiplink_b2c_rst chiplink_b2c_send } ] + + # TX side: want to transition almost anywhere except on the rising edge of the clock + # The data signals going to Aloe must have: clock - 1.85 <= NO transition <= clock + 0.65 + # Let's add 1ns of safey for trace jitter+skew on both sides: + # min = -hold = -0.65 - 0.6 + # max = setup = 1.85 + 0.6 + set_output_delay -min -1.25 -clock {chiplink_c2b_clock} [ get_ports { chiplink_c2b_data* chiplink_c2b_rst chiplink_c2b_send } ] + set_output_delay -max 2.45 -clock {chiplink_c2b_clock} [ get_ports { chiplink_c2b_data* chiplink_c2b_rst chiplink_c2b_send } ] +} + +set group_mem [get_clocks -quiet {clk_pll_i}] +set group_sys [get_clocks -quiet {sys_diff_clk \ + clk_out*_vc707_sys_clock_mmcm1 \ + clk_out*_vc707_sys_clock_mmcm2 \ + chiplink_c2b_clock}] +set group_cl [get_clocks -quiet {chiplink_b2c_clock \ + clk_out*_vc707_sys_clock_mmcm3}] +set group_pci [get_clocks -quiet {userclk1 txoutclk}] + +set group_jtag [get_clocks -quiet {JTCK}] + +puts "group_mem: $group_mem" +puts "group_sys: $group_sys" +puts "group_pci: $group_pci" +puts "group_cl: $group_cl" +puts "group_jtag: $group_jtag" + +set groups [list] +if { [llength $group_mem] > 0 } { lappend groups -group $group_mem } +if { [llength $group_sys] > 0 } { lappend groups -group $group_sys } +if { [llength $group_pci] > 0 } { lappend groups -group $group_pci } +if { [llength $group_cl] > 0 } { lappend groups -group $group_cl } +if { [llength $group_jtag] > 0 } { lappend groups -group $group_jtag } + +puts "set_clock_groups -asynchronous $groups" +set_clock_groups -asynchronous {*}$groups diff --git a/fpga-shells/xilinx/vc707/tcl/ios.tcl b/fpga-shells/xilinx/vc707/tcl/ios.tcl new file mode 100644 index 00000000..915b6832 --- /dev/null +++ b/fpga-shells/xilinx/vc707/tcl/ios.tcl @@ -0,0 +1,68 @@ +#---------------Physical Constraints----------------- + +#get_port_part_pins +#clk_n clk_p dip_switches_tri_i_0 dip_switches_tri_i_1 dip_switches_tri_i_2 dip_switches_tri_i_3 dip_switches_tri_i_4 dip_switches_tri_i_5 dip_switches_tri_i_6 dip_switches_tri_i_7 iic_main_scl_i iic_main_sda_i lcd_7bits_tri_o_0 lcd_7bits_tri_o_1 lcd_7bits_tri_o_2 lcd_7bits_tri_o_3 lcd_7bits_tri_o_4 lcd_7bits_tri_o_5 lcd_7bits_tri_o_6 leds_8bits_tri_o_0 leds_8bits_tri_o_1 leds_8bits_tri_o_2 leds_8bits_tri_o_3 leds_8bits_tri_o_4 leds_8bits_tri_o_5 leds_8bits_tri_o_6 leds_8bits_tri_o_7 linear_flash_addr_1 linear_flash_addr_10 linear_flash_addr_11 linear_flash_addr_12 linear_flash_addr_13 linear_flash_addr_14 linear_flash_addr_15 linear_flash_addr_16 linear_flash_addr_17 linear_flash_addr_18 linear_flash_addr_19 linear_flash_addr_2 linear_flash_addr_20 linear_flash_addr_21 linear_flash_addr_22 linear_flash_addr_23 linear_flash_addr_24 linear_flash_addr_25 linear_flash_addr_26 linear_flash_addr_3 linear_flash_addr_4 linear_flash_addr_5 linear_flash_addr_6 linear_flash_addr_7 linear_flash_addr_8 linear_flash_addr_9 linear_flash_adv_ldn linear_flash_ce_n linear_flash_dq_i_0 linear_flash_dq_i_1 linear_flash_dq_i_10 linear_flash_dq_i_11 linear_flash_dq_i_12 linear_flash_dq_i_13 linear_flash_dq_i_14 linear_flash_dq_i_15 linear_flash_dq_i_2 linear_flash_dq_i_3 linear_flash_dq_i_4 linear_flash_dq_i_5 linear_flash_dq_i_6 linear_flash_dq_i_7 linear_flash_dq_i_8 linear_flash_dq_i_9 linear_flash_oen linear_flash_wen mdc mdio_i phy_rst_out push_buttons_5bits_tri_i_0 push_buttons_5bits_tri_i_1 push_buttons_5bits_tri_i_2 push_buttons_5bits_tri_i_3 push_buttons_5bits_tri_i_4 reset rotary_inca_push_incb_tri_i_0 rotary_inca_push_incb_tri_i_1 rotary_inca_push_incb_tri_i_2 rs232_uart_rxd rs232_uart_txd sfp_rxn sfp_rxp sfp_sgmii_txn sfp_sgmii_txp sgmii_mgt_clkn sgmii_mgt_clkp sgmii_rxn sgmii_rxp sgmii_txn sgmii_txp sma_lvds_rxn sma_lvds_rxp sma_lvds_txn sma_lvds_txp sma_mgt_clkn sma_mgt_clkp sma_sfp_rxn sma_sfp_rxp sma_sfp_txn sma_sfp_txp + +set_property BOARD_PIN {clk_p} [get_ports sys_diff_clock_clk_p] +set_property BOARD_PIN {clk_n} [get_ports sys_diff_clock_clk_n] +set_property BOARD_PIN {reset} [get_ports reset] + +create_clock -name sys_diff_clk -period 5.0 [get_ports sys_diff_clock_clk_p] +set_input_jitter [get_clocks -of_objects [get_ports sys_diff_clock_clk_p]] 0.5 + +set_property BOARD_PIN {leds_8bits_tri_o_0} [get_ports led_0] +set_property BOARD_PIN {leds_8bits_tri_o_1} [get_ports led_1] +set_property BOARD_PIN {leds_8bits_tri_o_2} [get_ports led_2] +set_property BOARD_PIN {leds_8bits_tri_o_3} [get_ports led_3] +set_property BOARD_PIN {leds_8bits_tri_o_4} [get_ports led_4] +set_property BOARD_PIN {leds_8bits_tri_o_5} [get_ports led_5] +set_property BOARD_PIN {leds_8bits_tri_o_6} [get_ports led_6] +set_property BOARD_PIN {leds_8bits_tri_o_7} [get_ports led_7] + +set_property BOARD_PIN {push_buttons_5bits_tri_i_0} [get_ports btn_0] +set_property BOARD_PIN {push_buttons_5bits_tri_i_1} [get_ports btn_1] +set_property BOARD_PIN {push_buttons_5bits_tri_i_2} [get_ports btn_2] +set_property BOARD_PIN {push_buttons_5bits_tri_i_3} [get_ports btn_3] + +set_property BOARD_PIN {dip_switches_tri_i_0} [get_ports sw_0] +set_property BOARD_PIN {dip_switches_tri_i_1} [get_ports sw_1] +set_property BOARD_PIN {dip_switches_tri_i_2} [get_ports sw_2] +set_property BOARD_PIN {dip_switches_tri_i_3} [get_ports sw_3] +set_property BOARD_PIN {dip_switches_tri_i_4} [get_ports sw_4] +set_property BOARD_PIN {dip_switches_tri_i_5} [get_ports sw_5] +set_property BOARD_PIN {dip_switches_tri_i_6} [get_ports sw_6] +set_property BOARD_PIN {dip_switches_tri_i_7} [get_ports sw_7] + +set_property PACKAGE_PIN AU33 [get_ports uart_rx] +set_property IOSTANDARD LVCMOS18 [get_ports uart_rx] +set_property IOB TRUE [get_cells -of_objects [all_fanout -flat -endpoints_only [get_ports uart_rx]]] +set_property PACKAGE_PIN AT32 [get_ports uart_ctsn] +set_property IOSTANDARD LVCMOS18 [get_ports uart_ctsn] +set_property IOB TRUE [get_ports uart_ctsn] +set_property PACKAGE_PIN AU36 [get_ports uart_tx] +set_property IOSTANDARD LVCMOS18 [get_ports uart_tx] +set_property IOB TRUE [get_cells -of_objects [all_fanin -flat -startpoints_only [get_ports uart_tx]]] +set_property PACKAGE_PIN AR34 [get_ports uart_rtsn] +set_property IOSTANDARD LVCMOS18 [get_ports uart_rtsn] +set_property IOB TRUE [get_ports uart_rtsn] + +# PCI Express +#FMC 1 refclk +set_property PACKAGE_PIN A10 [get_ports {pcie_REFCLK_rxp}] +set_property PACKAGE_PIN A9 [get_ports {pcie_REFCLK_rxn}] +create_clock -name pcie_ref_clk -period 10 [get_ports pcie_REFCLK_rxp] +set_input_jitter [get_clocks -of_objects [get_ports pcie_REFCLK_rxp]] 0.5 + +set_property PACKAGE_PIN H4 [get_ports {pcie_pci_exp_txp}] +set_property PACKAGE_PIN H3 [get_ports {pcie_pci_exp_txn}] + +set_property PACKAGE_PIN G6 [get_ports {pcie_pci_exp_rxp}] +set_property PACKAGE_PIN G5 [get_ports {pcie_pci_exp_rxn}] + +# SDIO +set_property -dict { PACKAGE_PIN AN30 IOSTANDARD LVCMOS18 IOB TRUE } [get_ports {sdio_clk}] +set_property -dict { PACKAGE_PIN AP30 IOSTANDARD LVCMOS18 IOB TRUE PULLUP TRUE } [get_ports {sdio_cmd}] +set_property -dict { PACKAGE_PIN AR30 IOSTANDARD LVCMOS18 IOB TRUE PULLUP TRUE } [get_ports {sdio_dat[0]}] +set_property -dict { PACKAGE_PIN AU31 IOSTANDARD LVCMOS18 IOB TRUE PULLUP TRUE } [get_ports {sdio_dat[1]}] +set_property -dict { PACKAGE_PIN AV31 IOSTANDARD LVCMOS18 IOB TRUE PULLUP TRUE } [get_ports {sdio_dat[2]}] +set_property -dict { PACKAGE_PIN AT30 IOSTANDARD LVCMOS18 IOB TRUE PULLUP TRUE } [get_ports {sdio_dat[3]}] diff --git a/fpga-shells/xilinx/vc707/vsrc/sdio.v b/fpga-shells/xilinx/vc707/vsrc/sdio.v new file mode 100644 index 00000000..9528410c --- /dev/null +++ b/fpga-shells/xilinx/vc707/vsrc/sdio.v @@ -0,0 +1,58 @@ +// See LICENSE for license details. +`timescale 1ns/1ps +`default_nettype none + +module sdio_spi_bridge ( + input wire clk, + input wire reset, + // SDIO + inout wire sd_cmd, + inout wire [3:0] sd_dat, + output wire sd_sck, + // QUAD SPI + input wire spi_sck, + input wire [3:0] spi_dq_o, + output wire [3:0] spi_dq_i, + output wire spi_cs +); + + wire mosi, miso; +(* extract_reset = "yes" *) reg miso_sync [1:0]; + assign mosi = spi_dq_o[0]; + assign spi_dq_i = {2'b00, miso_sync[1], 1'b0}; + + assign sd_sck = spi_sck; + + IOBUF buf_cmd ( + .IO(sd_cmd), + .I(mosi), + .O(), + .T(1'b0) + ); + + IOBUF buf_dat0 ( + .IO(sd_dat[0]), + .I(), + .O(miso), + .T(1'b1) + ); + + IOBUF buf_dat3 ( + .IO(sd_dat[3]), + .I(spi_cs), + .O(), + .T(1'b0) + ); + + always @(posedge clk) begin + if (reset) begin + miso_sync[0] <= 1'b0; + miso_sync[1] <= 1'b0; + end else begin + miso_sync[0] <= miso; + miso_sync[1] <= miso_sync[0]; + end + end +endmodule + +`default_nettype wire diff --git a/fpga-shells/xilinx/vc707/vsrc/vc707reset.v b/fpga-shells/xilinx/vc707/vsrc/vc707reset.v new file mode 100644 index 00000000..85010271 --- /dev/null +++ b/fpga-shells/xilinx/vc707/vsrc/vc707reset.v @@ -0,0 +1,78 @@ +// See LICENSE for license details. +`timescale 1ns/1ps +`default_nettype none +`define RESET_SYNC 4 +`define DEBOUNCE_BITS 8 + +module vc707reset( + // Asynchronous reset input, should be held high until + // all clocks are locked and power is stable. + input wire areset, + // Clock domains are brought up in increasing order + // All clocks are reset for at least 2^DEBOUNCE_BITS * period(clock1) + input wire clock1, + output wire reset1, + input wire clock2, + output wire reset2, + input wire clock3, + output wire reset3, + input wire clock4, + output wire reset4 +); + sifive_reset_hold hold_clock0(areset, clock1, reset1); + sifive_reset_sync sync_clock2(reset1, clock2, reset2); + sifive_reset_sync sync_clock3(reset2, clock3, reset3); + sifive_reset_sync sync_clock4(reset3, clock4, reset4); +endmodule + +// Assumes that areset is held for more than one clock +// Allows areset to be deasserted asynchronously +module sifive_reset_sync( + input wire areset, + input wire clock, + output wire reset +); + reg [`RESET_SYNC-1:0] gen_reset = {`RESET_SYNC{1'b1}}; + always @(posedge clock, posedge areset) begin + if (areset) begin + gen_reset <= {`RESET_SYNC{1'b1}}; + end else begin + gen_reset <= {1'b0,gen_reset[`RESET_SYNC-1:1]}; + end + end + assign reset = gen_reset[0]; +endmodule + +module sifive_reset_hold( + input wire areset, + input wire clock, + output wire reset +); + wire raw_reset; + reg [`RESET_SYNC-1:0] sync_reset = {`RESET_SYNC{1'b1}}; + reg [`DEBOUNCE_BITS:0] debounce_reset = {`DEBOUNCE_BITS{1'b1}}; + wire out_reset; + + // Captures reset even if clock is not running + sifive_reset_sync capture(areset, clock, raw_reset); + + // Remove any glitches due to runt areset + always @(posedge clock) begin + sync_reset <= {raw_reset,sync_reset[`RESET_SYNC-1:1]}; + end + + // Debounce the reset + assign out_reset = debounce_reset[`DEBOUNCE_BITS]; + always @(posedge clock) begin + if (sync_reset[0]) begin + debounce_reset <= {(`DEBOUNCE_BITS+1){1'b1}}; + end else begin + debounce_reset <= debounce_reset - out_reset; + end + end + + assign reset = out_reset; + +endmodule + +`default_nettype wire diff --git a/fpga-shells/xilinx/vcu118/constraints/vcu118-master.xdc b/fpga-shells/xilinx/vcu118/constraints/vcu118-master.xdc new file mode 100644 index 00000000..87d23246 --- /dev/null +++ b/fpga-shells/xilinx/vcu118/constraints/vcu118-master.xdc @@ -0,0 +1,12 @@ +#-------------- MCS Generation ---------------------- +set_property BITSTREAM.CONFIG.EXTMASTERCCLK_EN div-1 [current_design] +set_property BITSTREAM.CONFIG.SPI_FALL_EDGE YES [current_design] +set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 8 [current_design] +set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] +set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design] +set_property CFGBVS GND [current_design] +set_property CONFIG_VOLTAGE 1.8 [current_design] +set_property CONFIG_MODE SPIx8 [current_design] + + + diff --git a/fpga-shells/xilinx/vcu118/tcl/board.tcl b/fpga-shells/xilinx/vcu118/tcl/board.tcl new file mode 100644 index 00000000..d2b3b9c7 --- /dev/null +++ b/fpga-shells/xilinx/vcu118/tcl/board.tcl @@ -0,0 +1,6 @@ +# See LICENSE for license details. +set name {vcu118} +set part_fpga {xcvu9p-flga2104-2L-e} +# Board: xilinx.com:vcu118:part0:2.0 +# However, if we set this we cannot control PCIe locations +set part_board {} diff --git a/fpga-shells/xilinx/vcu118/vsrc/sdio.v b/fpga-shells/xilinx/vcu118/vsrc/sdio.v new file mode 100644 index 00000000..ff7ebc89 --- /dev/null +++ b/fpga-shells/xilinx/vcu118/vsrc/sdio.v @@ -0,0 +1,59 @@ +// See LICENSE for license details. +`timescale 1ns/1ps +`default_nettype none + +module sdio_spi_bridge ( + input wire clk, + input wire reset, + // SDIO + inout wire sd_cmd, + inout wire [3:0] sd_dat, + output wire sd_sck, + // QUAD SPI + input wire spi_sck, + input wire [3:0] spi_dq_o, + output wire [3:0] spi_dq_i, + output wire spi_cs +); + + wire mosi, miso; + reg miso_sync [1:0]; + + assign mosi = spi_dq_o[0]; + assign spi_dq_i = {2'b00, miso_sync[1], 1'b0}; + + assign sd_sck = spi_sck; + + IOBUF buf_cmd ( + .IO(sd_cmd), + .I(mosi), + .O(), + .T(1'b0) + ); + + IOBUF buf_dat0 ( + .IO(sd_dat[0]), + .I(), + .O(miso), + .T(1'b1) + ); + + IOBUF buf_dat3 ( + .IO(sd_dat[3]), + .I(spi_cs), + .O(), + .T(1'b0) + ); + + always @(posedge clk) begin + if (reset) begin + miso_sync[0] <= 1'b0; + miso_sync[1] <= 1'b0; + end else begin + miso_sync[0] <= miso; + miso_sync[1] <= miso_sync[0]; + end + end +endmodule + +`default_nettype wire diff --git a/fpga-shells/xilinx/vcu118/vsrc/vcu118reset.v b/fpga-shells/xilinx/vcu118/vsrc/vcu118reset.v new file mode 100644 index 00000000..1e7d42d1 --- /dev/null +++ b/fpga-shells/xilinx/vcu118/vsrc/vcu118reset.v @@ -0,0 +1,78 @@ +// See LICENSE for license details. +`timescale 1ns/1ps +`default_nettype none +`define RESET_SYNC 4 +`define DEBOUNCE_BITS 8 + +module vcu118reset( + // Asynchronous reset input, should be held high until + // all clocks are locked and power is stable. + input wire areset, + // Clock domains are brought up in increasing order + // All clocks are reset for at least 2^DEBOUNCE_BITS * period(clock1) + input wire clock1, + output wire reset1, + input wire clock2, + output wire reset2, + input wire clock3, + output wire reset3, + input wire clock4, + output wire reset4 +); + sifive_reset_hold hold_clock0(areset, clock1, reset1); + sifive_reset_sync sync_clock2(reset1, clock2, reset2); + sifive_reset_sync sync_clock3(reset2, clock3, reset3); + sifive_reset_sync sync_clock4(reset3, clock4, reset4); +endmodule + +// Assumes that areset is held for more than one clock +// Allows areset to be deasserted asynchronously +module sifive_reset_sync( + input wire areset, + input wire clock, + output wire reset +); + reg [`RESET_SYNC-1:0] gen_reset = {`RESET_SYNC{1'b1}}; + always @(posedge clock, posedge areset) begin + if (areset) begin + gen_reset <= {`RESET_SYNC{1'b1}}; + end else begin + gen_reset <= {1'b0,gen_reset[`RESET_SYNC-1:1]}; + end + end + assign reset = gen_reset[0]; +endmodule + +module sifive_reset_hold( + input wire areset, + input wire clock, + output wire reset +); + wire raw_reset; + reg [`RESET_SYNC-1:0] sync_reset = {`RESET_SYNC{1'b1}}; + reg [`DEBOUNCE_BITS:0] debounce_reset = {`DEBOUNCE_BITS{1'b1}}; + wire out_reset; + + // Captures reset even if clock is not running + sifive_reset_sync capture(areset, clock, raw_reset); + + // Remove any glitches due to runt areset + always @(posedge clock) begin + sync_reset <= {raw_reset,sync_reset[`RESET_SYNC-1:1]}; + end + + // Debounce the reset + assign out_reset = debounce_reset[`DEBOUNCE_BITS]; + always @(posedge clock) begin + if (sync_reset[0]) begin + debounce_reset <= {(`DEBOUNCE_BITS+1){1'b1}}; + end else begin + debounce_reset <= debounce_reset - out_reset; + end + end + + assign reset = out_reset; + +endmodule + +`default_nettype wire diff --git a/rocket-chip b/rocket-chip new file mode 160000 index 00000000..b21c7879 --- /dev/null +++ b/rocket-chip @@ -0,0 +1 @@ +Subproject commit b21c7879b3ea22f69cb8457109561f37c225f8ea diff --git a/sifive-blocks/.gitignore b/sifive-blocks/.gitignore new file mode 100644 index 00000000..cc1c8e40 --- /dev/null +++ b/sifive-blocks/.gitignore @@ -0,0 +1,2 @@ +# sbt build files +/target diff --git a/sifive-blocks/LICENSE b/sifive-blocks/LICENSE new file mode 100644 index 00000000..56daab28 --- /dev/null +++ b/sifive-blocks/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 SiFive, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sifive-blocks/src/main/resources/BlackBoxDelayBuffer.v b/sifive-blocks/src/main/resources/BlackBoxDelayBuffer.v new file mode 100644 index 00000000..afb50633 --- /dev/null +++ b/sifive-blocks/src/main/resources/BlackBoxDelayBuffer.v @@ -0,0 +1,14 @@ +// This module is added as a reference only. Please add library +// cells for delay buffers and muxes from the foundry that is fabricating your SoC. + +module BlackBoxDelayBuffer ( in, mux_out, out, sel + ); + + input in; + output mux_out; + output out; + input [4:0] sel; + + assign mux_out = in; + assign out = in; +endmodule diff --git a/sifive-blocks/src/main/scala/devices/chiplink/Bundles.scala b/sifive-blocks/src/main/scala/devices/chiplink/Bundles.scala new file mode 100644 index 00000000..01f172f3 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/Bundles.scala @@ -0,0 +1,93 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.util.{rightOR,GenericParameterizedBundle} + +class WideDataLayerPortLane(params: ChipLinkParams) extends GenericParameterizedBundle(params) { + val clk = Clock(OUTPUT) + val rst = Bool(OUTPUT) + val send = Bool(OUTPUT) + val data = UInt(OUTPUT, width=params.dataBits) +} + +class WideDataLayerPort(params: ChipLinkParams) extends GenericParameterizedBundle(params) { + val c2b = new WideDataLayerPortLane(params) + val b2c = new WideDataLayerPortLane(params).flip +} + +class DataLayer(params: ChipLinkParams) extends GenericParameterizedBundle(params) { + val data = UInt(OUTPUT, width=params.dataBits) + val last = Bool(OUTPUT) + val beats = UInt(OUTPUT, width=params.xferBits + 1) +} + +class CreditBump(params: ChipLinkParams) extends GenericParameterizedBundle(params) { + val a = UInt(OUTPUT, width = params.creditBits) + val b = UInt(OUTPUT, width = params.creditBits) + val c = UInt(OUTPUT, width = params.creditBits) + val d = UInt(OUTPUT, width = params.creditBits) + val e = UInt(OUTPUT, width = params.creditBits) + def X: Seq[UInt] = Seq(a, b, c, d, e) + + // saturating addition + def +(that: CreditBump): CreditBump = { + val out = Wire(new CreditBump(params)) + (out.X zip (X zip that.X)) foreach { case (o, (x, y)) => + val z = x +& y + o := Mux((z >> params.creditBits).orR, ~UInt(0, width=params.creditBits), z) + } + out + } + + // Send the MSB of the credits + def toHeader: (UInt, CreditBump) = { + def msb(x: UInt) = { + val mask = rightOR(x) >> 1 + val msbOH = ~(~x | mask) + val msb = OHToUInt(msbOH << 1, params.creditBits + 1) // 0 = 0, 1 = 1, 2 = 4, 3 = 8, ... + val pad = (msb | UInt(0, width=5))(4,0) + (pad, x & mask) + } + val (a_msb, a_rest) = msb(a) + val (b_msb, b_rest) = msb(b) + val (c_msb, c_rest) = msb(c) + val (d_msb, d_rest) = msb(d) + val (e_msb, e_rest) = msb(e) + val header = Cat( + e_msb, d_msb, c_msb, b_msb, a_msb, + UInt(0, width = 4), // padding + UInt(5, width = 3)) + + val out = Wire(new CreditBump(params)) + out.a := a_rest + out.b := b_rest + out.c := c_rest + out.d := d_rest + out.e := e_rest + (header, out) + } +} + +object CreditBump { + def apply(params: ChipLinkParams, x: Int): CreditBump = { + val v = UInt(x, width = params.creditBits) + val out = Wire(new CreditBump(params)) + out.X.foreach { _ := v } + out + } + + def apply(params: ChipLinkParams, header: UInt): CreditBump = { + def convert(x: UInt) = + Mux(x > UInt(params.creditBits), + ~UInt(0, width = params.creditBits), + UIntToOH(x, params.creditBits + 1) >> 1) + val out = Wire(new CreditBump(params)) + out.a := convert(header(11, 7)) + out.b := convert(header(16, 12)) + out.c := convert(header(21, 17)) + out.d := convert(header(26, 22)) + out.e := convert(header(31, 27)) + out + } +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/CAM.scala b/sifive-blocks/src/main/scala/devices/chiplink/CAM.scala new file mode 100644 index 00000000..97f2b716 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/CAM.scala @@ -0,0 +1,37 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ + +class CAM(keys: Int, dataBits: Int) extends Module +{ + val io = new Bundle { + // alloc.valid => allocate a key + // alloc.ready => a key is avilable + val alloc = Decoupled(UInt(width = dataBits)).flip + val key = UInt(OUTPUT, width = log2Ceil(keys)) + // free.valid => release the key + val free = Valid(UInt(width = log2Ceil(keys))).flip + val data = UInt(OUTPUT, width = dataBits) + } + + val free = RegInit(UInt((BigInt(1) << keys) - 1, width = keys)) + val data = Mem(keys, UInt(width = dataBits)) + + val free_sel = ~(leftOR(free, keys) << 1) & free + io.key := OHToUInt(free_sel, keys) + + io.alloc.ready := free.orR + when (io.alloc.fire()) { data.write(io.key, io.alloc.bits) } + + // Support free in same cycle as alloc + val bypass = io.alloc.fire() && io.free.bits === io.key + io.data := Mux(bypass, io.alloc.bits, data(io.free.bits)) + + // Update CAM usage + val clr = Mux(io.alloc.fire(), free_sel, UInt(0)) + val set = Mux(io.free.valid, UIntToOH(io.free.bits), UInt(0)) + free := (free & ~clr) | set +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/ChipLink.scala b/sifive-blocks/src/main/scala/devices/chiplink/ChipLink.scala new file mode 100644 index 00000000..ec1f7eb0 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/ChipLink.scala @@ -0,0 +1,238 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.config.{Field, Parameters} +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.util._ + +class ChipLink(val params: ChipLinkParams)(implicit p: Parameters) extends LazyModule() { + + val device = new SimpleBus("chiplink", Seq("sifive,chiplink")) + + private def maybeManager(x: Seq[AddressSet], f: Seq[AddressSet] => TLManagerParameters) = + if (x.isEmpty) Nil else Seq(f(x)) + + private val slaveNode = TLManagerNode(Seq(TLManagerPortParameters( + managers = + maybeManager(params.TLUH, a => TLManagerParameters( + address = a, + resources = device.ranges, + regionType = RegionType.GET_EFFECTS, + executable = true, + supportsArithmetic = params.atomicXfer, + supportsLogical = params.atomicXfer, + supportsGet = params.fullXfer, + supportsPutFull = params.fullXfer, + supportsPutPartial = params.fullXfer, + supportsHint = params.fullXfer, + mayDenyPut = true, + mayDenyGet = true, + fifoId = Some(0))) ++ + maybeManager(params.TLC, a => TLManagerParameters( + address = a, + resources = device.ranges, + regionType = RegionType.TRACKED, + executable = true, + supportsAcquireT = params.acqXfer, + supportsAcquireB = params.acqXfer, + supportsArithmetic = params.atomicXfer, + supportsLogical = params.atomicXfer, + supportsGet = params.fullXfer, + supportsPutFull = params.fullXfer, + supportsPutPartial = params.fullXfer, + supportsHint = params.fullXfer, + mayDenyPut = true, + mayDenyGet = true, + fifoId = Some(0))), + beatBytes = 4, + endSinkId = params.sinks, + minLatency = params.latency))) + + // Masters 1+ require order; Master 0 is unordered and may cache + private val masterNode = TLClientNode(Seq(TLClientPortParameters( + clients = Seq.tabulate(params.domains) { i => + TLClientParameters( + name = "ChipLink Domain #" + i, + sourceId = IdRange(i*params.sourcesPerDomain, (i + 1)*params.sourcesPerDomain), + requestFifo = i > 0, + supportsProbe = if (i == 0) params.fullXfer else params.noXfer) }, + minLatency = params.latency))) + + private val sbypass = LazyModule(new TLBusBypass(beatBytes = 4)) + slaveNode := sbypass.node + + private val mute = LazyModule(new MuteMaster(maxProbe = params.acqXfer.max)) + private val mbypass = LazyModule(new MasterMux(_.last)) + private val buffer = LazyModule(new TLBuffer( + a = BufferParams.none, + b = BufferParams.none, + c = BufferParams.default, + d = BufferParams.none, + e = BufferParams.none)) + mbypass.node := buffer.node := mute.node + mbypass.node := masterNode + + val node = NodeHandle(sbypass.node, mbypass.node) + val ioNode = BundleBridgeSource(() => new WideDataLayerPort(params).cloneType) + + // Exported memory map. Used when connecting VIP + lazy val managers = masterNode.edges.out(0).manager.managers + lazy val mmap = { + val (tlc, tluh) = managers.partition(_.supportsAcquireB) + params.copy( + TLUH = AddressSet.unify(tluh.flatMap(_.address)), + TLC = AddressSet.unify(tlc.flatMap(_.address))) + } + + lazy val module = new LazyModuleImp(this) { + val io = IO(new Bundle { + val bypass = Bool(OUTPUT) + // When not syncTX, these drive the TX domain + val c2b_clk = Clock(INPUT) + val c2b_rst = Bool(INPUT) + // If fpgaReset, we need a pulse that arrives before b2c_clk locks + val fpga_reset = if (params.fpgaReset) Some(Bool(INPUT)) else None + }) + val port = ioNode.bundle + + // Ensure downstream devices support our requirements + val (in, edgeIn) = slaveNode.in(0) + val (out, edgeOut) = masterNode.out(0) + + require (edgeIn.manager.beatBytes == 4) + edgeOut.manager.requireFifo() + + edgeOut.manager.managers.foreach { m => + require (m.supportsGet.contains(params.fullXfer), + s"ChipLink requires ${m.name} support ${params.fullXfer} Get, not ${m.supportsGet}") + if (m.supportsPutFull) { + require (m.supportsPutFull.contains(params.fullXfer), + s"ChipLink requires ${m.name} support ${params.fullXfer} PutFill, not ${m.supportsPutFull}") + // !!! argh. AHB devices can't: require (m.supportsPutPartial.contains(params.fullXfer), + // s"ChipLink requires ${m.name} support ${params.fullXfer} PutPartial not ${m.supportsPutPartial}") + require (m.supportsArithmetic.contains(params.atomicXfer), + s"ChipLink requires ${m.name} support ${params.atomicXfer} Arithmetic, not ${m.supportsArithmetic}") + require (m.supportsLogical.contains(params.atomicXfer), + s"ChipLink requires ${m.name} support ${params.atomicXfer} Logical, not ${m.supportsLogical}") + } + require (m.supportsHint.contains(params.fullXfer), + s"ChipLink requires ${m.name} support ${params.fullXfer} Hint, not ${m.supportsHint}") + require (!m.supportsAcquireT || m.supportsAcquireT.contains(params.acqXfer), + s"ChipLink requires ${m.name} support ${params.acqXfer} AcquireT, not ${m.supportsAcquireT}") + require (!m.supportsAcquireB || m.supportsAcquireB.contains(params.acqXfer), + s"ChipLink requires ${m.name} support ${params.acqXfer} AcquireB, not ${m.supportsAcquireB}") + require (!m.supportsAcquireB || !m.supportsPutFull || m.supportsAcquireT, + s"ChipLink requires ${m.name} to support AcquireT if it supports Put and AcquireB") + } + + // Anything that is optional, must be supported by the error device (for redirect) + val errorDevs = edgeOut.manager.managers.filter(_.nodePath.last.lazyModule.className == "TLError") + require (errorDevs.exists(_.supportsAcquireB), "There is no TLError with Acquire reachable from ChipLink. One must be instantiated.") + val errorDev = errorDevs.find(_.supportsAcquireB).get + require (errorDev.supportsPutFull.contains(params.fullXfer), + s"ChipLink requires ${errorDev.name} support ${params.fullXfer} PutFill, not ${errorDev.supportsPutFull}") + require (errorDev.supportsPutPartial.contains(params.fullXfer), + s"ChipLink requires ${errorDev.name} support ${params.fullXfer} PutPartial not ${errorDev.supportsPutPartial}") + require (errorDev.supportsArithmetic.contains(params.atomicXfer), + s"ChipLink requires ${errorDev.name} support ${params.atomicXfer} Arithmetic, not ${errorDev.supportsArithmetic}") + require (errorDev.supportsLogical.contains(params.atomicXfer), + s"ChipLink requires ${errorDev.name} support ${params.atomicXfer} Logical, not ${errorDev.supportsLogical}") + require (errorDev.supportsAcquireT.contains(params.acqXfer), + s"ChipLink requires ${errorDev.name} support ${params.acqXfer} AcquireT, not ${errorDev.supportsAcquireT}") + + // At most one cache can master ChipLink + require (edgeIn.client.clients.filter(_.supportsProbe).size <= 1, + s"ChipLink supports at most one caching master, ${edgeIn.client.clients.filter(_.supportsProbe).map(_.name)}") + + // Construct the info needed by all submodules + val info = ChipLinkInfo(params, edgeIn, edgeOut, errorDev.address.head) + + val sinkA = Module(new SinkA(info)) + val sinkB = Module(new SinkB(info)) + val sinkC = Module(new SinkC(info)) + val sinkD = Module(new SinkD(info)) + val sinkE = Module(new SinkE(info)) + val sourceA = Module(new SourceA(info)) + val sourceB = Module(new SourceB(info)) + val sourceC = Module(new SourceC(info)) + val sourceD = Module(new SourceD(info)) + val sourceE = Module(new SourceE(info)) + + val rx = Module(new RX(info)) + rx.clock := port.b2c.clk + + // The off-chip reset is registered internally to improve timing + // The RX module buffers incoming data by one cycle to compensate the reset delay + // It is required that the internal reset be high even when the b2c.clk does not run + io.fpga_reset match { + case None => + // b2c.rst is actually synchronous to b2c.clk, so one flop is enough + rx.reset := AsyncResetReg(Bool(false), port.b2c.clk, port.b2c.rst, true, None) + case Some(resetPulse) => + // For high performance, FPGA IO buffer registers must feed IO into D, not reset + // However, FPGA registers also support an initial block to generate a reset pulse + rx.reset := AsyncResetReg(port.b2c.rst, port.b2c.clk, resetPulse, true, None) + } + + rx.io.b2c_data := port.b2c.data + rx.io.b2c_send := port.b2c.send + out.a <> sourceA.io.a + in .b <> sourceB.io.b + out.c <> sourceC.io.c + in .d <> sourceD.io.d + out.e <> sourceE.io.e + sourceA.io.q <> FromAsyncBundle(rx.io.a) + sourceB.io.q <> FromAsyncBundle(rx.io.b) + sourceC.io.q <> FromAsyncBundle(rx.io.c) + sourceD.io.q <> FromAsyncBundle(rx.io.d) + sourceE.io.q <> FromAsyncBundle(rx.io.e) + + val tx = Module(new TX(info)) + port.c2b.clk := tx.io.c2b_clk + port.c2b.rst := tx.io.c2b_rst + port.c2b.data := tx.io.c2b_data + port.c2b.send := tx.io.c2b_send + sinkA.io.a <> in .a + sinkB.io.b <> out.b + sinkC.io.c <> in .c + sinkD.io.d <> out.d + sinkE.io.e <> in .e + if (params.syncTX) { + tx.io.sa <> sinkA.io.q + tx.io.sb <> sinkB.io.q + tx.io.sc <> sinkC.io.q + tx.io.sd <> sinkD.io.q + tx.io.se <> sinkE.io.q + } else { + // Create the TX clock domain from input + tx.clock := io.c2b_clk + tx.reset := io.c2b_rst + tx.io.a <> ToAsyncBundle(sinkA.io.q, params.crossing) + tx.io.b <> ToAsyncBundle(sinkB.io.q, params.crossing) + tx.io.c <> ToAsyncBundle(sinkC.io.q, params.crossing) + tx.io.d <> ToAsyncBundle(sinkD.io.q, params.crossing) + tx.io.e <> ToAsyncBundle(sinkE.io.q, params.crossing) + } + + // Pass credits from RX to TX + tx.io.rxc <> rx.io.rxc + tx.io.txc <> rx.io.txc + + // Connect the CAM source pools + sinkD.io.a_clSource := sourceA.io.d_clSource + sourceA.io.d_tlSource := sinkD.io.a_tlSource + sinkD.io.c_clSource := sourceC.io.d_clSource + sourceC.io.d_tlSource := sinkD.io.c_tlSource + sourceD.io.e_tlSink := sinkE.io.d_tlSink + sinkE.io.d_clSink := sourceD.io.e_clSink + + // Disable ChipLink while RX+TX are in reset + val do_bypass = ResetCatchAndSync(clock, rx.reset) || ResetCatchAndSync(clock, tx.reset) + sbypass.module.io.bypass := do_bypass + mbypass.module.io.bypass := do_bypass + io.bypass := do_bypass + } +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/Parameters.scala b/sifive-blocks/src/main/scala/devices/chiplink/Parameters.scala new file mode 100644 index 00000000..872a3971 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/Parameters.scala @@ -0,0 +1,140 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.config.{Field, Parameters} +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util.AsyncQueueParams + +case class ChipLinkParams(TLUH: Seq[AddressSet], TLC: Seq[AddressSet], sourceBits: Int = 6, sinkBits: Int = 5, syncTX: Boolean = false, fpgaReset: Boolean = false) +{ + val domains = 8 // hard-wired into chiplink protocol + require (sourceBits >= log2Ceil(domains)) + require (sinkBits >= 0) + val sources = 1 << sourceBits + val sinks = 1 << sinkBits + val sourcesPerDomain = sources / domains + val latency = 8 // ChipLink has at least 4 cycles of synchronization per side + val dataBytes = 4 + val dataBits = dataBytes*8 + val clSourceBits = 16 + val clSinkBits = 16 + val crossing = AsyncQueueParams() + val Qdepth = 8192 / dataBytes + val maxXfer = 4096 + val xferBits = log2Ceil(maxXfer) + val creditBits = 20 // use saturating addition => we can exploit at most 1MB of buffers + val addressBits = 64 + require (log2Ceil(Qdepth + 1) <= creditBits) + + // Protocol supported operations: + val noXfer = TransferSizes.none + val fullXfer = TransferSizes(1, 64) // !!! 4096) + val acqXfer = TransferSizes(64, 64) + val atomicXfer = TransferSizes(1, 8) + +} + +case object ChipLinkKey extends Field[Seq[ChipLinkParams]] + +case class TXN(domain: Int, source: Int) +case class ChipLinkInfo(params: ChipLinkParams, edgeIn: TLEdge, edgeOut: TLEdge, errorDev: AddressSet) +{ + // TL source => CL TXN + val sourceMap: Map[Int, TXN] = { + var alloc = 1 + val domains = Array.fill(params.domains) { 0 } + println("ChipLink source mapping CLdomain CLsource <= TLsource:") + val out = Map() ++ edgeIn.client.clients.flatMap { c => + // If the client needs order, pick a domain for it + val domain = if (c.requestFifo) alloc else 0 + val offset = domains(domain) + println(s"\t${domain} [${offset}, ${offset + c.sourceId.size}) <= [${c.sourceId.start}, ${c.sourceId.end}):\t${c.name}") + if (c.requestFifo) { + alloc = alloc + 1 + if (alloc == params.domains) alloc = 1 + } + c.sourceId.range.map { id => + val source = domains(domain) + domains(domain) = source + 1 + (id, TXN(domain, source)) + } + } + println("") + out + } + + def mux(m: Map[Int, Int]): Vec[UInt] = { + val maxKey = m.keys.max + val maxVal = m.values.max + val valBits = log2Up(maxVal + 1) + val out = Wire(Vec(maxKey + 1, UInt(width = valBits))) + m.foreach { case (k, v) => out(k) := UInt(v, width = valBits) } + out + } + + // Packet format; little-endian + def encode(format: UInt, opcode: UInt, param: UInt, size: UInt, domain: UInt, source: UInt): UInt = { + def fmt(x: UInt, w: Int) = (x | UInt(0, width=w))(w-1, 0) + Cat( + fmt(source, 16), + fmt(domain, 3), + fmt(size, 4), + fmt(param, 3), + fmt(opcode, 3), + fmt(format, 3)) + } + + def decode(x: UInt): Seq[UInt] = { + val format = x( 2, 0) + val opcode = x( 5, 3) + val param = x( 8, 6) + val size = x(12, 9) + val domain = x(15, 13) + val source = x(31, 16) + Seq(format, opcode, param, size, domain, source) + } + + def size2beats(size: UInt): UInt = { + val shift = log2Ceil(params.dataBytes) + Cat(UIntToOH(size|UInt(0, width=4), params.xferBits + 1) >> (shift + 1), size <= UInt(shift)) + } + + def mask2beats(size: UInt): UInt = { + val shift = log2Ceil(params.dataBytes*8) + Cat(UIntToOH(size|UInt(0, width=4), params.xferBits + 1) >> (shift + 1), size <= UInt(shift)) + } + + def beats1(x: UInt, forceFormat: Option[UInt] = None): UInt = { + val Seq(format, opcode, _, size, _, _) = decode(x) + val beats = size2beats(size) + val masks = mask2beats(size) + val grant = opcode === TLMessages.Grant || opcode === TLMessages.GrantData + val partial = opcode === TLMessages.PutPartialData + val a = Mux(opcode(2), UInt(0), beats) + UInt(2) + Mux(partial, masks, UInt(0)) + val b = Mux(opcode(2), UInt(0), beats) + UInt(2) + Mux(partial, masks, UInt(0)) + val c = Mux(opcode(0), beats, UInt(0)) + UInt(2) + val d = Mux(opcode(0), beats, UInt(0)) + grant.asUInt + val e = UInt(0) + val f = UInt(0) + Vec(a, b, c, d, e, f)(forceFormat.getOrElse(format)) + } + + def firstlast(x: DecoupledIO[UInt], forceFormat: Option[UInt] = None): (Bool, Bool) = { + val count = RegInit(UInt(0)) + val beats = beats1(x.bits, forceFormat) + val first = count === UInt(0) + val last = count === UInt(1) || (first && beats === UInt(0)) + when (x.fire()) { count := Mux(first, beats, count - UInt(1)) } + (first, last) + } + + // You can't just unilaterally use error, because this would misalign the mask + def makeError(legal: Bool, address: UInt): UInt = { + val alignBits = log2Ceil(errorDev.alignment) + Cat( + Mux(legal, address, UInt(errorDev.base))(params.addressBits-1, alignBits), + address(alignBits-1, 0)) + } +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/Partial.scala b/sifive-blocks/src/main/scala/devices/chiplink/Partial.scala new file mode 100644 index 00000000..46334427 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/Partial.scala @@ -0,0 +1,106 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ + +class ParitalExtractor[T <: TLDataChannel](gen: T) extends Module +{ + val io = new Bundle { + val last = Bool(INPUT) + val i = Decoupled(gen).flip + val o = Decoupled(gen) + } + + io.o <> io.i + + // Grab references to the fields we care about + val (i_opcode, i_data) = io.i.bits match { + case a: TLBundleA => (a.opcode, a.data) + case b: TLBundleB => (b.opcode, b.data) + } + val (o_data, o_mask) = io.o.bits match { + case a: TLBundleA => (a.data, a.mask) + case b: TLBundleB => (b.data, b.mask) + } + + val state = RegInit(UInt(0, width=4)) // number of nibbles; [0,8] + val shift = Reg(UInt(width=32)) + val enable = i_opcode === TLMessages.PutPartialData + val empty = state === UInt(0) + + when (enable) { + val wide = shift | (i_data << (state << 2)) + o_data := Vec.tabulate(4) { i => wide(9*(i+1)-1, 9*i+1) } .asUInt + o_mask := Vec.tabulate(4) { i => wide(9*i) } .asUInt + + // Swallow beat if we have no nibbles + when (empty) { + io.i.ready := Bool(true) + io.o.valid := Bool(false) + } + + // Update the FSM + when (io.i.fire()) { + shift := Mux(empty, i_data, wide >> 36) + state := state - UInt(1) + when (empty) { state := UInt(8) } + when (io.last) { state := UInt(0) } + } + } +} + +class PartialInjector[T <: TLDataChannel](gen: T) extends Module +{ + val io = new Bundle { + val i_last = Bool(INPUT) + val o_last = Bool(OUTPUT) + val i = Decoupled(gen).flip + val o = Decoupled(gen) + } + + io.o <> io.i + + // Grab references to the fields we care about + val (i_opcode, i_data, i_mask) = io.i.bits match { + case a: TLBundleA => (a.opcode, a.data, a.mask) + case b: TLBundleB => (b.opcode, b.data, b.mask) + } + val o_data = io.o.bits match { + case a: TLBundleA => a.data + case b: TLBundleB => b.data + } + + val state = RegInit(UInt(0, width=4)) // number of nibbles; [0,8] + val shift = RegInit(UInt(0, width=32)) + val full = state(3) + val partial = i_opcode === TLMessages.PutPartialData + + val last = RegInit(Bool(false)) + io.o_last := Mux(partial, last, io.i_last) + + when (partial) { + val bytes = Seq.tabulate(4) { i => i_data(8*(i+1)-1, 8*i) } + val bits = i_mask.toBools + val mixed = Cat(Seq(bits, bytes).transpose.flatten.reverse) + val wide = shift | (mixed << (state << 2)) + o_data := wide + + // Inject a beat + when ((io.i_last || full) && !last) { + io.i.ready := Bool(false) + } + + // Update the FSM + when (io.o.fire()) { + shift := wide >> 32 + state := state + UInt(1) + when (full || last) { + state := UInt(0) + shift := UInt(0) + } + last := io.i_last && !last + } + } +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/RX.scala b/sifive-blocks/src/main/scala/devices/chiplink/RX.scala new file mode 100644 index 00000000..f331dac4 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/RX.scala @@ -0,0 +1,91 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ + +class RX(info: ChipLinkInfo) extends Module +{ + val io = new Bundle { + val b2c_send = Bool(INPUT) + val b2c_data = UInt(INPUT, info.params.dataBits) + val a = new AsyncBundle(UInt(width = info.params.dataBits), info.params.crossing) + val b = new AsyncBundle(UInt(width = info.params.dataBits), info.params.crossing) + val c = new AsyncBundle(UInt(width = info.params.dataBits), info.params.crossing) + val d = new AsyncBundle(UInt(width = info.params.dataBits), info.params.crossing) + val e = new AsyncBundle(UInt(width = info.params.dataBits), info.params.crossing) + val rxc = new AsyncBundle(new CreditBump(info.params), AsyncQueueParams.singleton()) + val txc = new AsyncBundle(new CreditBump(info.params), AsyncQueueParams.singleton()) + } + + // Immediately register our input data + val b2c_data = RegNext(RegNext(io.b2c_data)) + val b2c_send = RegNext(RegNext(io.b2c_send), Bool(false)) + // b2c_send is NOT cleared on the first RegNext because this module's reset has a flop on it + + // Fit b2c into the firstlast API + val beat = Wire(Decoupled(UInt(width = info.params.dataBits))) + beat.bits := b2c_data + beat.valid := b2c_send + beat.ready := Bool(true) + + // Select the correct HellaQueue for the request + val (first, _) = info.firstlast(beat) + val formatBits = beat.bits(2, 0) + val formatValid = beat.fire() && first + val format = Mux(formatValid, formatBits, RegEnable(formatBits, formatValid)) + val formatOH = UIntToOH(format) + + // Create the receiver buffers + val hqa = Module(new HellaQueue(info.params.Qdepth)(beat.bits)) + val hqb = Module(new HellaQueue(info.params.Qdepth)(beat.bits)) + val hqc = Module(new HellaQueue(info.params.Qdepth)(beat.bits)) + val hqd = Module(new HellaQueue(info.params.Qdepth)(beat.bits)) + val hqe = Module(new HellaQueue(info.params.Qdepth)(beat.bits)) + + // Use these to save some typing; function to prevent renaming + private def hqX = Seq(hqa, hqb, hqc, hqd, hqe) + private def ioX = Seq(io.a, io.b, io.c, io.d, io.e) + + // Enqueue to the HellaQueues + (formatOH.toBools zip hqX) foreach { case (sel, hq) => + hq.io.enq.valid := beat.valid && sel + hq.io.enq.bits := beat.bits + assert (!hq.io.enq.valid || hq.io.enq.ready) // overrun impossible + } + + // Send HellaQueue output to their respective FSMs + (hqX zip ioX) foreach { case (hq, io) => + io <> ToAsyncBundle(hq.io.deq, info.params.crossing) + } + + // Credits we need to hand-off to the TX FSM + val tx = RegInit(CreditBump(info.params, 0)) + val rx = RegInit(CreditBump(info.params, info.params.Qdepth)) + + // Constantly transmit credit updates + val txOut = Wire(Decoupled(new CreditBump(info.params))) + val rxOut = Wire(Decoupled(new CreditBump(info.params))) + txOut.valid := Bool(true) + rxOut.valid := Bool(true) + txOut.bits := tx + rxOut.bits := rx + io.txc <> ToAsyncBundle(txOut, AsyncQueueParams.singleton()) + io.rxc <> ToAsyncBundle(rxOut, AsyncQueueParams.singleton()) + + // Generate new RX credits as the HellaQueues drain + val rxInc = Wire(new CreditBump(info.params)) + (hqX zip rxInc.X) foreach { case (hq, inc) => + inc := hq.io.deq.fire().asUInt + } + + // Generate new TX credits as we receive F-format messages + val txInc = Mux(beat.valid && formatOH(5), CreditBump(info.params, beat.bits), CreditBump(info.params, 0)) + + // As we hand-over credits, reset the counters + tx := tx + txInc + rx := rx + rxInc + when (txOut.fire()) { tx := txInc } + when (rxOut.fire()) { rx := rxInc } +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/SinkA.scala b/sifive-blocks/src/main/scala/devices/chiplink/SinkA.scala new file mode 100644 index 00000000..532d1fd3 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/SinkA.scala @@ -0,0 +1,65 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ + +class SinkA(info: ChipLinkInfo) extends Module +{ + val io = new Bundle { + val a = Decoupled(new TLBundleA(info.edgeIn.bundle)).flip + val q = Decoupled(new DataLayer(info.params)) + } + + // Map TileLink sources to ChipLink sources+domain + val tl2cl = info.sourceMap + val source = info.mux(tl2cl.mapValues(_.source)) + val domain = info.mux(tl2cl.mapValues(_.domain)) + + // We need a Q because we stall the channel while serializing it's header + val inject = Module(new PartialInjector(io.a.bits)) + inject.io.i <> Queue(io.a, 1, flow=true) + inject.io.i_last := info.edgeIn.last(inject.io.i) + val a = inject.io.o + val a_last = inject.io.o_last + val a_hasData = info.edgeIn.hasData(a.bits) + val a_partial = a.bits.opcode === TLMessages.PutPartialData + + // A simple FSM to generate the packet components + val state = RegInit(UInt(0, width = 2)) + val s_header = UInt(0, width = 2) + val s_address0 = UInt(1, width = 2) + val s_address1 = UInt(2, width = 2) + val s_data = UInt(3, width = 2) + + when (io.q.fire()) { + switch (state) { + is (s_header) { state := s_address0 } + is (s_address0) { state := s_address1 } + is (s_address1) { state := Mux(a_hasData, s_data, s_header) } + is (s_data) { state := Mux(!a_last, s_data, s_header) } + } + } + + // Construct the header beat + val header = info.encode( + format = UInt(0), + opcode = a.bits.opcode, + param = a.bits.param, + size = a.bits.size, + domain = domain(a.bits.source), + source = source(a.bits.source)) + + // Construct the address beats + val address0 = a.bits.address + val address1 = a.bits.address >> 32 + + // Frame the output packet + val isLastState = state === Mux(a_hasData, s_data, s_address1) + a.ready := io.q.ready && isLastState + io.q.valid := a.valid + io.q.bits.last := a_last && isLastState + io.q.bits.data := Vec(header, address0, address1, a.bits.data)(state) + io.q.bits.beats := Mux(a_hasData, info.size2beats(a.bits.size), UInt(0)) + UInt(3) + + Mux(a_partial, info.mask2beats(a.bits.size), UInt(0)) +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/SinkB.scala b/sifive-blocks/src/main/scala/devices/chiplink/SinkB.scala new file mode 100644 index 00000000..6142a6bd --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/SinkB.scala @@ -0,0 +1,62 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ + +class SinkB(info: ChipLinkInfo) extends Module +{ + val io = new Bundle { + val b = Decoupled(new TLBundleB(info.edgeOut.bundle)).flip + val q = Decoupled(new DataLayer(info.params)) + } + + // We need a Q because we stall the channel while serializing it's header + val inject = Module(new PartialInjector(io.b.bits)) + inject.io.i <> Queue(io.b, 1, flow=true) + inject.io.i_last := info.edgeOut.last(inject.io.i) + val b = inject.io.o + val b_last = inject.io.o_last + val b_hasData = info.edgeOut.hasData(b.bits) + val b_partial = b.bits.opcode === TLMessages.PutPartialData + + // A simple FSM to generate the packet components + val state = RegInit(UInt(0, width = 2)) + val s_header = UInt(0, width = 2) + val s_address0 = UInt(1, width = 2) + val s_address1 = UInt(2, width = 2) + val s_data = UInt(3, width = 2) + + when (io.q.fire()) { + switch (state) { + is (s_header) { state := s_address0 } + is (s_address0) { state := s_address1 } + is (s_address1) { state := Mux(b_hasData, s_data, s_header) } + is (s_data) { state := Mux(!b_last, s_data, s_header) } + } + } + + // Construct the header beat + val header = info.encode( + format = UInt(1), + opcode = b.bits.opcode, + param = b.bits.param, + size = b.bits.size, + domain = UInt(0), // ChipLink only allows one remote cache, in domain 0 + source = UInt(0)) + + assert (!b.valid || b.bits.source === UInt(0)) + + // Construct the address beats + val address0 = b.bits.address + val address1 = b.bits.address >> 32 + + // Frame the output packet + val isLastState = state === Mux(b_hasData, s_data, s_address1) + b.ready := io.q.ready && isLastState + io.q.valid := b.valid + io.q.bits.last := b_last && isLastState + io.q.bits.data := Vec(header, address0, address1, b.bits.data)(state) + io.q.bits.beats := Mux(b_hasData, info.size2beats(b.bits.size), UInt(0)) + UInt(3) + + Mux(b_partial, info.mask2beats(b.bits.size), UInt(0)) +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/SinkC.scala b/sifive-blocks/src/main/scala/devices/chiplink/SinkC.scala new file mode 100644 index 00000000..0be17986 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/SinkC.scala @@ -0,0 +1,63 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ + +class SinkC(info: ChipLinkInfo) extends Module +{ + val io = new Bundle { + val c = Decoupled(new TLBundleC(info.edgeIn.bundle)).flip + val q = Decoupled(new DataLayer(info.params)) + } + + // Map TileLink sources to ChipLink sources+domain + val tl2cl = info.sourceMap + val source = info.mux(tl2cl.mapValues(_.source)) + val domain = info.mux(tl2cl.mapValues(_.domain)) + + // We need a Q because we stall the channel while serializing it's header + val c = Queue(io.c, 1, flow=true) + val c_last = info.edgeIn.last(c) + val c_hasData = info.edgeIn.hasData(c.bits) + val c_release = c.bits.opcode === TLMessages.Release || c.bits.opcode === TLMessages.ReleaseData + + // A simple FSM to generate the packet components + val state = RegInit(UInt(0, width = 2)) + val s_header = UInt(0, width = 2) + val s_address0 = UInt(1, width = 2) + val s_address1 = UInt(2, width = 2) + val s_data = UInt(3, width = 2) + + when (io.q.fire()) { + switch (state) { + is (s_header) { state := s_address0 } + is (s_address0) { state := s_address1 } + is (s_address1) { state := Mux(c_hasData, s_data, s_header) } + is (s_data) { state := Mux(!c_last, s_data, s_header) } + } + } + + // Construct the header beat + val header = info.encode( + format = UInt(2), + opcode = c.bits.opcode, + param = c.bits.param, + size = c.bits.size, + domain = UInt(0), // only caches (unordered) can release + source = Mux(c_release, source(c.bits.source), UInt(0))) + + assert (!c.valid || domain(c.bits.source) === UInt(0)) + + // Construct the address beats + val address0 = c.bits.address + val address1 = c.bits.address >> 32 + + // Frame the output packet + val isLastState = state === Mux(c_hasData, s_data, s_address1) + c.ready := io.q.ready && isLastState + io.q.valid := c.valid + io.q.bits.last := c_last && isLastState + io.q.bits.data := Vec(header, address0, address1, c.bits.data)(state) + io.q.bits.beats := Mux(c_hasData, info.size2beats(c.bits.size), UInt(0)) + UInt(3) +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/SinkD.scala b/sifive-blocks/src/main/scala/devices/chiplink/SinkD.scala new file mode 100644 index 00000000..5bb68de5 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/SinkD.scala @@ -0,0 +1,60 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ + +class SinkD(info: ChipLinkInfo) extends Module +{ + val io = new Bundle { + val d = Decoupled(new TLBundleD(info.edgeOut.bundle)).flip + val q = Decoupled(new DataLayer(info.params)) + val a_tlSource = Valid(UInt(width = info.params.sourceBits)) + val a_clSource = UInt(INPUT, width = info.params.clSourceBits) + val c_tlSource = Valid(UInt(width = info.params.sourceBits)) + val c_clSource = UInt(INPUT, width = info.params.clSourceBits) + } + + // The FSM states + val state = RegInit(UInt(0, width = 2)) + val s_header = UInt(0, width = 2) + val s_sink = UInt(1, width = 2) + val s_data = UInt(2, width = 2) + + // We need a Q because we stall the channel while serializing it's header + val d = Queue(io.d, 1, flow=true) + val d_last = info.edgeOut.last(d) + val d_hasData = info.edgeOut.hasData(d.bits) + val d_grant = d.bits.opcode === TLMessages.Grant || d.bits.opcode === TLMessages.GrantData + + when (io.q.fire()) { + switch (state) { + is (s_header) { state := Mux(d_grant, s_sink, Mux(d_hasData, s_data, s_header)) } + is (s_sink) { state := Mux(d_hasData, s_data, s_header) } + is (s_data) { state := Mux(d_last, s_header, s_data) } + } + } + + // Release the TL source + val relack = d.bits.opcode === TLMessages.ReleaseAck + io.a_tlSource.valid := io.q.fire() && state === s_header && !relack + io.a_tlSource.bits := d.bits.source + io.c_tlSource.valid := io.q.fire() && state === s_header && relack + io.c_tlSource.bits := d.bits.source + + // Construct the header beat + val header = info.encode( + format = UInt(3), + opcode = d.bits.opcode, + param = Cat(d.bits.denied, d.bits.param), + size = d.bits.size, + domain = d.bits.source >> log2Ceil(info.params.sourcesPerDomain), + source = Mux(relack, io.c_clSource, io.a_clSource)) + + val isLastState = state === Mux(d_hasData, s_data, Mux(d_grant, s_sink, s_header)) + d.ready := io.q.ready && isLastState + io.q.valid := d.valid + io.q.bits.last := d_last && isLastState + io.q.bits.data := Vec(header, d.bits.sink, d.bits.data)(state) + io.q.bits.beats := Mux(d_hasData, info.size2beats(d.bits.size), UInt(0)) + UInt(1) + d_grant.asUInt +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/SinkE.scala b/sifive-blocks/src/main/scala/devices/chiplink/SinkE.scala new file mode 100644 index 00000000..b466a9c0 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/SinkE.scala @@ -0,0 +1,33 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ + +class SinkE(info: ChipLinkInfo) extends Module +{ + val io = new Bundle { + val e = Decoupled(new TLBundleE(info.edgeIn.bundle)).flip + val q = Decoupled(new DataLayer(info.params)) + // Find the sink from D + val d_tlSink = Valid(UInt(width = info.params.sinkBits)) + val d_clSink = UInt(INPUT, width = info.params.clSinkBits) + } + + io.d_tlSink.valid := io.e.fire() + io.d_tlSink.bits := io.e.bits.sink + + val header = info.encode( + format = UInt(4), + opcode = UInt(0), + param = UInt(0), + size = UInt(0), + domain = UInt(0), + source = io.d_clSink) + + io.e.ready := io.q.ready + io.q.valid := io.e.valid + io.q.bits.last := Bool(true) + io.q.bits.data := header + io.q.bits.beats := UInt(1) +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/SourceA.scala b/sifive-blocks/src/main/scala/devices/chiplink/SourceA.scala new file mode 100644 index 00000000..dcb6462d --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/SourceA.scala @@ -0,0 +1,105 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ + +class SourceA(info: ChipLinkInfo) extends Module +{ + val io = new Bundle { + val a = Decoupled(new TLBundleA(info.edgeOut.bundle)) + val q = Decoupled(UInt(width = info.params.dataBits)).flip + // Used by D to find the txn + val d_tlSource = Valid(UInt(width = info.params.sourceBits)).flip + val d_clSource = UInt(OUTPUT, width = info.params.clSourceBits) + } + + // CAM of sources used for each domain + val cams = Seq.fill(info.params.domains) { + Module(new CAM(info.params.sourcesPerDomain, info.params.clSourceBits)) + } + + // A simple FSM to generate the packet components + val state = RegInit(UInt(0, width = 2)) + val s_header = UInt(0, width = 2) + val s_address0 = UInt(1, width = 2) + val s_address1 = UInt(2, width = 2) + val s_data = UInt(3, width = 2) + + private def hold(key: UInt)(data: UInt) = { + val enable = state === key + Mux(enable, data, RegEnable(data, enable)) + } + + // Extract header fields + val Seq(_, q_opcode, q_param, q_size, q_domain, q_source) = + info.decode(io.q.bits).map(hold(s_header) _) + + // Latch address + val q_address0 = hold(s_address0)(io.q.bits) + val q_address1 = hold(s_address1)(io.q.bits) + + val (_, q_last) = info.firstlast(io.q, Some(UInt(0))) + val q_hasData = !q_opcode(2) + val a_first = RegEnable(state =/= s_data, io.q.fire()) + + when (io.q.fire()) { + switch (state) { + is (s_header) { state := s_address0 } + is (s_address0) { state := s_address1 } + is (s_address1) { state := Mux(q_hasData, s_data, s_header) } + is (s_data) { state := Mux(!q_last, s_data, s_header) } + } + } + + // Determine if the request is legal. If not, route to error device. + val q_address = Cat(q_address1, q_address0) + val q_acq = q_opcode === TLMessages.AcquireBlock || q_opcode === TLMessages.AcquirePerm + val q_write = Mux(q_acq, q_param === TLPermissions.NtoT || q_param === TLPermissions.BtoT, q_hasData) + val exists = info.edgeOut.manager.containsSafe(q_address) + private def writeable(m: TLManagerParameters): Boolean = if (m.supportsAcquireB) m.supportsAcquireT else m.supportsPutFull + private def acquireable(m: TLManagerParameters): Boolean = m.supportsAcquireB || m.supportsAcquireT + private def toBool(x: Boolean) = Bool(x) + val writeOk = info.edgeOut.manager.fastProperty(q_address, writeable, toBool) + val acquireOk = info.edgeOut.manager.fastProperty(q_address, acquireable, toBool) + val q_legal = exists && (!q_write || writeOk) && (!q_acq || acquireOk) + + // Look for an available source in the correct domain + val source_ok = Vec(cams.map(_.io.alloc.ready))(q_domain) + val source = Vec(cams.map(_.io.key))(q_domain) holdUnless a_first + val a_sel = UIntToOH(q_domain) + + // Feed our preliminary A channel via the Partial Extractor FSM + val extract = Module(new ParitalExtractor(io.a.bits)) + io.a <> extract.io.o + val a = extract.io.i + extract.io.last := q_last + + a.bits.opcode := q_opcode + a.bits.param := q_param + a.bits.size := q_size + a.bits.source := Cat(q_domain, source) + a.bits.address := info.makeError(q_legal, q_address) + a.bits.mask := MaskGen(q_address0, q_size, info.params.dataBytes) + a.bits.data := io.q.bits + a.bits.corrupt := Bool(false) + + val stall = a_first && !source_ok + val xmit = q_last || state === s_data + a.valid := (io.q.valid && !stall) && xmit + io.q.ready := (a.ready && !stall) || !xmit + (cams zip a_sel.toBools) foreach { case (cam, sel) => + cam.io.alloc.valid := sel && a_first && xmit && io.q.valid && a.ready + cam.io.alloc.bits := q_source + } + + // Free the CAM entries + val d_clDomain = io.d_tlSource.bits >> log2Ceil(info.params.sourcesPerDomain) + val d_sel = UIntToOH(d_clDomain) + io.d_clSource := Vec(cams.map(_.io.data))(d_clDomain) + (cams zip d_sel.toBools) foreach { case (cam, sel) => + cam.io.free.bits := io.d_tlSource.bits + cam.io.free.valid := io.d_tlSource.valid && sel + } +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/SourceB.scala b/sifive-blocks/src/main/scala/devices/chiplink/SourceB.scala new file mode 100644 index 00000000..49cd8a2f --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/SourceB.scala @@ -0,0 +1,69 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ + +class SourceB(info: ChipLinkInfo) extends Module +{ + val io = new Bundle { + val b = Decoupled(new TLBundleB(info.edgeIn.bundle)) + val q = Decoupled(UInt(width = info.params.dataBits)).flip + } + + // Find the optional cache (at most one) + val cache = info.edgeIn.client.clients.filter(_.supportsProbe).headOption + + // A simple FSM to generate the packet components + val state = RegInit(UInt(0, width = 2)) + val s_header = UInt(0, width = 2) + val s_address0 = UInt(1, width = 2) + val s_address1 = UInt(2, width = 2) + val s_data = UInt(3, width = 2) + + private def hold(key: UInt)(data: UInt) = { + val enable = state === key + Mux(enable, data, RegEnable(data, enable)) + } + + // Extract header fields + val Seq(_, q_opcode, q_param, q_size, _, _) = + info.decode(io.q.bits).map(hold(s_header) _) + + // Latch address + val q_address0 = hold(s_address0)(io.q.bits) + val q_address1 = hold(s_address1)(io.q.bits) + + val (_, q_last) = info.firstlast(io.q, Some(UInt(1))) + val q_hasData = !q_opcode(2) + val b_first = RegEnable(state =/= s_data, io.q.fire()) + + when (io.q.fire()) { + switch (state) { + is (s_header) { state := s_address0 } + is (s_address0) { state := s_address1 } + is (s_address1) { state := Mux(q_hasData, s_data, s_header) } + is (s_data) { state := Mux(!q_last, s_data, s_header) } + } + } + + // Feed our preliminary B channel via the Partial Extractor FSM + val extract = Module(new ParitalExtractor(io.b.bits)) + io.b <> extract.io.o + val b = extract.io.i + extract.io.last := q_last + + b.bits.opcode := q_opcode + b.bits.param := q_param + b.bits.size := q_size + b.bits.source := UInt(cache.map(_.sourceId.start).getOrElse(0)) + b.bits.address := Cat(q_address1, q_address0) + b.bits.mask := MaskGen(q_address0, q_size, info.params.dataBytes) + b.bits.data := io.q.bits + b.bits.corrupt := Bool(false) + + val xmit = q_last || state === s_data + b.valid := io.q.valid && xmit + io.q.ready := b.ready || !xmit +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/SourceC.scala b/sifive-blocks/src/main/scala/devices/chiplink/SourceC.scala new file mode 100644 index 00000000..db2f3b3d --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/SourceC.scala @@ -0,0 +1,87 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ + +class SourceC(info: ChipLinkInfo) extends Module +{ + val io = new Bundle { + val c = Decoupled(new TLBundleC(info.edgeOut.bundle)) + val q = Decoupled(UInt(width = info.params.dataBits)).flip + // Used by D to find the txn + val d_tlSource = Valid(UInt(width = info.params.sourceBits)).flip + val d_clSource = UInt(OUTPUT, width = info.params.clSourceBits) + } + + // CAM of sources used for release + val cam = Module(new CAM(info.params.sourcesPerDomain, info.params.clSourceBits)) + + // A simple FSM to generate the packet components + val state = RegInit(UInt(0, width = 2)) + val s_header = UInt(0, width = 2) + val s_address0 = UInt(1, width = 2) + val s_address1 = UInt(2, width = 2) + val s_data = UInt(3, width = 2) + + private def hold(key: UInt)(data: UInt) = { + val enable = state === key + Mux(enable, data, RegEnable(data, enable)) + } + + // Extract header fields + val Seq(_, q_opcode, q_param, q_size, _, q_source) = + info.decode(io.q.bits).map(hold(s_header) _) + + // Latch address + val q_address0 = hold(s_address0)(io.q.bits) + val q_address1 = hold(s_address1)(io.q.bits) + + val (_, q_last) = info.firstlast(io.q, Some(UInt(2))) + val q_hasData = q_opcode(0) + val c_first = RegEnable(state =/= s_data, io.q.fire()) + + when (io.q.fire()) { + switch (state) { + is (s_header) { state := s_address0 } + is (s_address0) { state := s_address1 } + is (s_address1) { state := Mux(q_hasData, s_data, s_header) } + is (s_data) { state := Mux(!q_last, s_data, s_header) } + } + } + + // Determine if the request is legal. If not, route to error device. + val q_address = Cat(q_address1, q_address0) + val exists = info.edgeOut.manager.containsSafe(q_address) + private def writeable(m: TLManagerParameters): Boolean = if (m.supportsAcquireB) m.supportsAcquireT else m.supportsPutFull + private def acquireable(m: TLManagerParameters): Boolean = m.supportsAcquireB || m.supportsAcquireT + private def toBool(x: Boolean) = Bool(x) + val writeOk = info.edgeOut.manager.fastProperty(q_address, writeable, toBool) + val acquireOk = info.edgeOut.manager.fastProperty(q_address, acquireable, toBool) + val q_legal = exists && (!q_hasData || writeOk) && acquireOk + + // Look for an available source in the correct domain + val q_release = q_opcode === TLMessages.Release || q_opcode === TLMessages.ReleaseData + val source_ok = !q_release || cam.io.alloc.ready + val source = cam.io.key holdUnless c_first + + io.c.bits.opcode := q_opcode + io.c.bits.param := q_param + io.c.bits.size := q_size + io.c.bits.source := Mux(q_release, source, UInt(0)) // always domain 0 + io.c.bits.address := info.makeError(q_legal, q_address) + io.c.bits.data := io.q.bits + io.c.bits.corrupt := Bool(false) + + val stall = c_first && !source_ok + val xmit = q_last || state === s_data + io.c.valid := (io.q.valid && !stall) && xmit + io.q.ready := (io.c.ready && !stall) || !xmit + cam.io.alloc.valid := q_release && c_first && xmit && io.q.valid && io.c.ready + cam.io.alloc.bits := q_source + + // Free the CAM entries + io.d_clSource := cam.io.data + cam.io.free := io.d_tlSource +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/SourceD.scala b/sifive-blocks/src/main/scala/devices/chiplink/SourceD.scala new file mode 100644 index 00000000..49b85c5f --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/SourceD.scala @@ -0,0 +1,83 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ + +class SourceD(info: ChipLinkInfo) extends Module +{ + val io = new Bundle { + val d = Decoupled(new TLBundleD(info.edgeIn.bundle)) + val q = Decoupled(UInt(width = info.params.dataBits)).flip + // Used by E to find the txn + val e_tlSink = Valid(UInt(width = info.params.sinkBits)).flip + val e_clSink = UInt(OUTPUT, width = info.params.clSinkBits) + } + + // We need a sink id CAM + val cam = Module(new CAM(info.params.sinks, info.params.clSinkBits)) + + // Map ChipLink transaction to TileLink source + val cl2tl = info.sourceMap.map(_.swap) + val nestedMap = cl2tl.groupBy(_._1.domain).mapValues(_.map { case (TXN(_, cls), tls) => (cls, tls) }) + val muxes = Seq.tabulate(info.params.domains) { i => + info.mux(nestedMap.lift(i).getOrElse(Map(0 -> 0))) + } + + // The FSM states + val state = RegInit(UInt(0, width = 2)) + val s_header = UInt(0, width = 2) + val s_sink = UInt(1, width = 2) + val s_data = UInt(2, width = 2) + + private def hold(key: UInt)(data: UInt) = { + val enable = state === key + Mux(enable, data, RegEnable(data, enable)) + } + + // Extract header fields from the message + val Seq(_, q_opcode, q_param, q_size, q_domain, q_source) = + info.decode(io.q.bits).map(hold(s_header) _) + + // Extract sink from the optional second beat + val q_sink = hold(s_sink)(io.q.bits(15, 0)) + + val q_grant = q_opcode === TLMessages.Grant || q_opcode === TLMessages.GrantData + val (_, q_last) = info.firstlast(io.q, Some(UInt(3))) + val d_first = RegEnable(state =/= s_data, io.q.fire()) + val s_maybe_data = Mux(q_last, s_header, s_data) + + when (io.q.fire()) { + switch (state) { + is (s_header) { state := Mux(q_grant, s_sink, s_maybe_data) } + is (s_sink) { state := s_maybe_data } + is (s_data) { state := s_maybe_data } + } + } + + // Look for an available sink + val sink_ok = !q_grant || cam.io.alloc.ready + val sink = cam.io.key holdUnless d_first + val stall = d_first && !sink_ok + val xmit = q_last || state === s_data + + io.d.bits.opcode := q_opcode + io.d.bits.param := q_param(1,0) + io.d.bits.size := q_size + io.d.bits.source := Vec(muxes.map { m => m(q_source) })(q_domain) + io.d.bits.sink := Mux(q_grant, sink, UInt(0)) + io.d.bits.denied := q_param >> 2 + io.d.bits.data := io.q.bits + io.d.bits.corrupt := io.d.bits.denied && info.edgeIn.hasData(io.d.bits) + + io.d.valid := (io.q.valid && !stall) && xmit + io.q.ready := (io.d.ready && !stall) || !xmit + + cam.io.alloc.valid := q_grant && d_first && xmit && io.q.valid && io.d.ready + cam.io.alloc.bits := q_sink + + // Free the CAM + io.e_clSink := cam.io.data + cam.io.free := io.e_tlSink +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/SourceE.scala b/sifive-blocks/src/main/scala/devices/chiplink/SourceE.scala new file mode 100644 index 00000000..eaeca46c --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/SourceE.scala @@ -0,0 +1,21 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ + +class SourceE(info: ChipLinkInfo) extends Module +{ + val io = new Bundle { + val e = Decoupled(new TLBundleE(info.edgeOut.bundle)) + val q = Decoupled(UInt(width = info.params.dataBits)).flip + } + + // Extract header fields + val Seq(_, _, _, _, _, q_sink) = info.decode(io.q.bits) + + io.q.ready := io.e.ready + io.e.valid := io.q.valid + io.e.bits.sink := q_sink +} diff --git a/sifive-blocks/src/main/scala/devices/chiplink/TX.scala b/sifive-blocks/src/main/scala/devices/chiplink/TX.scala new file mode 100644 index 00000000..1d1ec41b --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/chiplink/TX.scala @@ -0,0 +1,110 @@ +// See LICENSE for license details. +package sifive.blocks.devices.chiplink + +import Chisel._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ + +class TX(info: ChipLinkInfo) extends Module +{ + val io = new Bundle { + val c2b_clk = Clock(OUTPUT) + val c2b_rst = Bool(OUTPUT) + val c2b_send = Bool(OUTPUT) + val c2b_data = UInt(OUTPUT, info.params.dataBits) + val a = new AsyncBundle(new DataLayer(info.params), info.params.crossing).flip + val b = new AsyncBundle(new DataLayer(info.params), info.params.crossing).flip + val c = new AsyncBundle(new DataLayer(info.params), info.params.crossing).flip + val d = new AsyncBundle(new DataLayer(info.params), info.params.crossing).flip + val e = new AsyncBundle(new DataLayer(info.params), info.params.crossing).flip + val sa = DecoupledIO(new DataLayer(info.params)).flip + val sb = DecoupledIO(new DataLayer(info.params)).flip + val sc = DecoupledIO(new DataLayer(info.params)).flip + val sd = DecoupledIO(new DataLayer(info.params)).flip + val se = DecoupledIO(new DataLayer(info.params)).flip + val rxc = new AsyncBundle(new CreditBump(info.params), AsyncQueueParams.singleton()).flip + val txc = new AsyncBundle(new CreditBump(info.params), AsyncQueueParams.singleton()).flip + } + + // Currently available credits + val rx = RegInit(CreditBump(info.params, 0)) + val tx = RegInit(CreditBump(info.params, 0)) + + // Constantly pull credits from RX + val rxInc = FromAsyncBundle(io.rxc) + val txInc = FromAsyncBundle(io.txc) + rxInc.ready := Bool(true) + txInc.ready := Bool(true) + + // Cross the requests (if necessary) + val sync = info.params.syncTX + val qa = if (sync) ShiftQueue(io.sa, 2) else FromAsyncBundle(io.a) + val qb = if (sync) ShiftQueue(io.sb, 2) else FromAsyncBundle(io.b) + val qc = if (sync) ShiftQueue(io.sc, 2) else FromAsyncBundle(io.c) + val qd = if (sync) ShiftQueue(io.sd, 2) else FromAsyncBundle(io.d) + val qe = if (sync) ShiftQueue(io.se, 2) else FromAsyncBundle(io.e) + private def qX = Seq(qa, qb, qc, qd, qe) + + // Consume TX credits and propagate pre-paid requests + val ioX = (qX zip (tx.X zip txInc.bits.X)) map { case (q, (credit, gain)) => + val first = RegEnable(q.bits.last, Bool(true), q.fire()) + val delta = credit -& q.bits.beats + val allow = !first || (delta.asSInt >= SInt(0)) + credit := Mux(q.fire() && first, delta, credit) + Mux(txInc.fire(), gain, UInt(0)) + + val cq = Module(new ShiftQueue(q.bits.cloneType, 2)) // maybe flow? + cq.io.enq.bits := q.bits + cq.io.enq.valid := q.valid && allow + q.ready := cq.io.enq.ready && allow + cq.io.deq + } + + // Prepare RX credit update headers + val rxQ = Module(new ShiftQueue(new DataLayer(info.params), 2)) // maybe flow? + val (rxHeader, rxLeft) = rx.toHeader + rxQ.io.enq.valid := Bool(true) + rxQ.io.enq.bits.data := rxHeader + rxQ.io.enq.bits.last := Bool(true) + rxQ.io.enq.bits.beats := UInt(1) + rx := Mux(rxQ.io.enq.fire(), rxLeft, rx) + Mux(rxInc.fire(), rxInc.bits, CreditBump(info.params, 0)) + + // Include the F credit channel in arbitration + val f = Wire(rxQ.io.deq) + val ioF = ioX :+ f + val requests = Cat(ioF.map(_.valid).reverse) + val lasts = Cat(ioF.map(_.bits.last).reverse) + + // How often should we force transmission of a credit update? sqrt + val xmitBits = log2Ceil(info.params.Qdepth) / 2 + val xmit = RegInit(UInt(0, width = xmitBits)) + val forceXmit = xmit === UInt(0) + when (!forceXmit) { xmit := xmit - UInt(1) } + when (f.fire()) { xmit := ~UInt(0, width = xmitBits) } + + // Flow control for returned credits + val allowReturn = !ioX.map(_.valid).reduce(_ || _) || forceXmit + f.bits := rxQ.io.deq.bits + f.valid := rxQ.io.deq.valid && allowReturn + rxQ.io.deq.ready := f.ready && allowReturn + + // Select a channel to transmit from those with data and space + val first = RegInit(Bool(true)) + val state = Reg(UInt(0, width=6)) + val readys = TLArbiter.roundRobin(6, requests, first) + val winner = readys & requests + val grant = Mux(first, winner, state) + val allowed = Mux(first, readys, state) + (ioF zip allowed.toBools) foreach { case (beat, sel) => beat.ready := sel } + + val send = Mux(first, rxQ.io.deq.valid, (state & requests) =/= UInt(0)) + assert (send === ((grant & requests) =/= UInt(0))) + + when (send) { first := (grant & lasts).orR } + when (first) { state := winner } + + // Form the output beat + io.c2b_clk := clock + io.c2b_rst := AsyncResetReg(Bool(false), clock, reset, true, None) + io.c2b_send := RegNext(RegNext(send, Bool(false)), Bool(false)) + io.c2b_data := RegNext(Mux1H(RegNext(grant), RegNext(Vec(ioF.map(_.bits.data))))) +} diff --git a/sifive-blocks/src/main/scala/devices/gpio/GPIO.scala b/sifive-blocks/src/main/scala/devices/gpio/GPIO.scala new file mode 100644 index 00000000..128a4f22 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/gpio/GPIO.scala @@ -0,0 +1,255 @@ +// See LICENSE for license details. +package sifive.blocks.devices.gpio + +import Chisel._ +import sifive.blocks.devices.pinctrl.{PinCtrl, Pin, BasePin, EnhancedPin, EnhancedPinCtrl} +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util.{AsyncResetRegVec, SynchronizerShiftReg} + +// This is sort of weird because +// the IOF end up at the RocketChipTop +// level, and we have to do the pinmux +// outside of RocketChipTop. +// It would be better if the IOF were here and +// we could do the pinmux inside. + +class GPIOPortIO(val c: GPIOParams) extends Bundle { + val pins = Vec(c.width, new EnhancedPin()) + val iof_0 = if (c.includeIOF) Some(Vec(c.width, new IOFPin).flip) else None + val iof_1 = if (c.includeIOF) Some(Vec(c.width, new IOFPin).flip) else None +} + +case class GPIOParams( + address: BigInt, + width: Int, + includeIOF: Boolean = false) + +/** The base GPIO peripheral functionality, which uses the regmap API to + * abstract over the bus protocol to which it is being connected + */ +abstract class GPIO(busWidthBytes: Int, c: GPIOParams)(implicit p: Parameters) + extends IORegisterRouter( + RegisterRouterParams( + name = "gpio", + compat = Seq("sifive,gpio0"), + base = c.address, + beatBytes = busWidthBytes), + new GPIOPortIO(c)) + with HasInterruptSources { + + def nInterrupts = c.width + override def extraResources(resources: ResourceBindings) = Map( + "gpio-controller" -> Nil, + "#gpio-cells" -> Seq(ResourceInt(2)), + "interrupt-controller" -> Nil, + "#interrupt-cells" -> Seq(ResourceInt(2))) + + lazy val module = new LazyModuleImp(this) { + + //-------------------------------------------------- + // CSR Declarations + // ------------------------------------------------- + + // SW Control only. + val portReg = Reg(init = UInt(0, c.width)) + + val oeReg = Module(new AsyncResetRegVec(c.width, 0)) + val pueReg = Module(new AsyncResetRegVec(c.width, 0)) + val dsReg = Reg(init = UInt(0, c.width)) + val ieReg = Module(new AsyncResetRegVec(c.width, 0)) + + // Synchronize Input to get valueReg + val inVal = Wire(UInt(0, width=c.width)) + inVal := Vec(port.pins.map(_.i.ival)).asUInt + val inSyncReg = SynchronizerShiftReg(inVal, 3, Some("inSyncReg")) + val valueReg = Reg(init = UInt(0, c.width), next = inSyncReg) + + // Interrupt Configuration + val highIeReg = Reg(init = UInt(0, c.width)) + val lowIeReg = Reg(init = UInt(0, c.width)) + val riseIeReg = Reg(init = UInt(0, c.width)) + val fallIeReg = Reg(init = UInt(0, c.width)) + val highIpReg = Reg(init = UInt(0, c.width)) + val lowIpReg = Reg(init = UInt(0, c.width)) + val riseIpReg = Reg(init = UInt(0, c.width)) + val fallIpReg = Reg(init = UInt(0, c.width)) + + // HW IO Function + val iofEnReg = Module(new AsyncResetRegVec(c.width, 0)) + val iofSelReg = Reg(init = UInt(0, c.width)) + + // Invert Output + val xorReg = Reg(init = UInt(0, c.width)) + + //-------------------------------------------------- + // CSR Access Logic (most of this section is boilerplate) + // ------------------------------------------------- + + val rise = ~valueReg & inSyncReg; + val fall = valueReg & ~inSyncReg; + + val iofEnFields = if (c.includeIOF) (Seq(RegField.rwReg(c.width, iofEnReg.io, + Some(RegFieldDesc("iof_en","HW I/O functon enable", reset=Some(0)))))) + else (Seq(RegField(c.width))) + val iofSelFields = if (c.includeIOF) (Seq(RegField(c.width, iofSelReg, + RegFieldDesc("iof_sel","HW I/O function select", reset=Some(0))))) + else (Seq(RegField(c.width))) + + // Note that these are out of order. + regmap( + GPIOCtrlRegs.value -> Seq(RegField.r(c.width, valueReg, + RegFieldDesc("input_value","Pin value", volatile=true))), + GPIOCtrlRegs.output_en -> Seq(RegField.rwReg(c.width, oeReg.io, + Some(RegFieldDesc("output_en","Pin output enable", reset=Some(0))))), + GPIOCtrlRegs.rise_ie -> Seq(RegField(c.width, riseIeReg, + RegFieldDesc("rise_ie","Rise interrupt enable", reset=Some(0)))), + GPIOCtrlRegs.rise_ip -> Seq(RegField.w1ToClear(c.width, riseIpReg, rise, + Some(RegFieldDesc("rise_ip","Rise interrupt pending", volatile=true)))), + GPIOCtrlRegs.fall_ie -> Seq(RegField(c.width, fallIeReg, + RegFieldDesc("fall_ie", "Fall interrupt enable", reset=Some(0)))), + GPIOCtrlRegs.fall_ip -> Seq(RegField.w1ToClear(c.width, fallIpReg, fall, + Some(RegFieldDesc("fall_ip","Fall interrupt pending", volatile=true)))), + GPIOCtrlRegs.high_ie -> Seq(RegField(c.width, highIeReg, + RegFieldDesc("high_ie","High interrupt enable", reset=Some(0)))), + GPIOCtrlRegs.high_ip -> Seq(RegField.w1ToClear(c.width, highIpReg, valueReg, + Some(RegFieldDesc("high_ip","High interrupt pending", volatile=true)))), + GPIOCtrlRegs.low_ie -> Seq(RegField(c.width, lowIeReg, + RegFieldDesc("low_ie","Low interrupt enable", reset=Some(0)))), + GPIOCtrlRegs.low_ip -> Seq(RegField.w1ToClear(c.width,lowIpReg, ~valueReg, + Some(RegFieldDesc("low_ip","Low interrupt pending", volatile=true)))), + GPIOCtrlRegs.port -> Seq(RegField(c.width, portReg, + RegFieldDesc("output_value","Output value", reset=Some(0)))), + GPIOCtrlRegs.pullup_en -> Seq(RegField.rwReg(c.width, pueReg.io, + Some(RegFieldDesc("pue","Internal pull-up enable", reset=Some(0))))), + GPIOCtrlRegs.iof_en -> iofEnFields, + GPIOCtrlRegs.iof_sel -> iofSelFields, + GPIOCtrlRegs.drive -> Seq(RegField(c.width, dsReg, + RegFieldDesc("ds","Pin drive strength selection", reset=Some(0)))), + GPIOCtrlRegs.input_en -> Seq(RegField.rwReg(c.width, ieReg.io, + Some(RegFieldDesc("input_en","Pin input enable", reset=Some(0))))), + GPIOCtrlRegs.out_xor -> Seq(RegField(c.width, xorReg, + RegFieldDesc("out_xor","Output XOR (invert) enable", reset=Some(0)))) + ) + + //-------------------------------------------------- + // Actual Pinmux + // ------------------------------------------------- + + val swPinCtrl = Wire(Vec(c.width, new EnhancedPinCtrl())) + + // This strips off the valid. + val iof0Ctrl = Wire(Vec(c.width, new IOFCtrl())) + val iof1Ctrl = Wire(Vec(c.width, new IOFCtrl())) + + val iofCtrl = Wire(Vec(c.width, new IOFCtrl())) + val iofPlusSwPinCtrl = Wire(Vec(c.width, new EnhancedPinCtrl())) + + for (pin <- 0 until c.width) { + + // Software Pin Control + swPinCtrl(pin).pue := pueReg.io.q(pin) + swPinCtrl(pin).oval := portReg(pin) + swPinCtrl(pin).oe := oeReg.io.q(pin) + swPinCtrl(pin).ds := dsReg(pin) + swPinCtrl(pin).ie := ieReg.io.q(pin) + + val pre_xor = Wire(new EnhancedPinCtrl()) + + if (c.includeIOF) { + // Allow SW Override for invalid inputs. + iof0Ctrl(pin) <> swPinCtrl(pin) + when (port.iof_0.get(pin).o.valid) { + iof0Ctrl(pin) <> port.iof_0.get(pin).o + } + + iof1Ctrl(pin) <> swPinCtrl(pin) + when (port.iof_1.get(pin).o.valid) { + iof1Ctrl(pin) <> port.iof_1.get(pin).o + } + + // Select IOF 0 vs. IOF 1. + iofCtrl(pin) <> Mux(iofSelReg(pin), iof1Ctrl(pin), iof0Ctrl(pin)) + + // Allow SW Override for things IOF doesn't control. + iofPlusSwPinCtrl(pin) <> swPinCtrl(pin) + iofPlusSwPinCtrl(pin) <> iofCtrl(pin) + + // Final XOR & Pin Control + pre_xor := Mux(iofEnReg.io.q(pin), iofPlusSwPinCtrl(pin), swPinCtrl(pin)) + } else { + pre_xor := swPinCtrl(pin) + } + + port.pins(pin).o := pre_xor + port.pins(pin).o.oval := pre_xor.oval ^ xorReg(pin) + + // Generate Interrupts + interrupts(pin) := (riseIpReg(pin) & riseIeReg(pin)) | + (fallIpReg(pin) & fallIeReg(pin)) | + (highIpReg(pin) & highIeReg(pin)) | + (lowIpReg(pin) & lowIeReg(pin)) + + if (c.includeIOF) { + // Send Value to all consumers + port.iof_0.get(pin).i.ival := inSyncReg(pin) + port.iof_1.get(pin).i.ival := inSyncReg(pin) + } + }} +} + +class TLGPIO(busWidthBytes: Int, params: GPIOParams)(implicit p: Parameters) + extends GPIO(busWidthBytes, params) with HasTLControlRegMap + +case class GPIOAttachParams( + gpio: GPIOParams, + controlBus: TLBusWrapper, + intNode: IntInwardNode, + controlXType: ClockCrossingType = NoCrossing, + intXType: ClockCrossingType = NoCrossing, + mclock: Option[ModuleValue[Clock]] = None, + mreset: Option[ModuleValue[Bool]] = None) + (implicit val p: Parameters) + +object GPIO { + val nextId = { var i = -1; () => { i += 1; i} } + + def attach(params: GPIOAttachParams): TLGPIO = { + implicit val p = params.p + val name = s"gpio_${nextId()}" + val cbus = params.controlBus + val gpio = LazyModule(new TLGPIO(cbus.beatBytes, params.gpio)) + gpio.suggestName(name) + + cbus.coupleTo(s"device_named_$name") { + gpio.controlXing(params.controlXType) := TLFragmenter(cbus.beatBytes, cbus.blockBytes) := _ + } + params.intNode := gpio.intXing(params.intXType) + InModuleBody { gpio.module.clock := params.mclock.map(_.getWrappedValue).getOrElse(cbus.module.clock) } + InModuleBody { gpio.module.reset := params.mreset.map(_.getWrappedValue).getOrElse(cbus.module.reset) } + + gpio + } + + def attachAndMakePort(params: GPIOAttachParams): ModuleValue[GPIOPortIO] = { + val gpio = attach(params) + val gpioNode = gpio.ioNode.makeSink()(params.p) + InModuleBody { gpioNode.makeIO()(ValName(gpio.name)) } + } + + def loopback(g: GPIOPortIO)(pinA: Int, pinB: Int) { + g.pins.foreach {p => + p.i.ival := Mux(p.o.oe, p.o.oval, p.o.pue) & p.o.ie + } + val a = g.pins(pinA) + val b = g.pins(pinB) + // This logic is not QUITE right, it doesn't handle all the subtle cases. + // It is probably simpler to just hook a pad up here and use attach() + // to model this properly. + a.i.ival := Mux(b.o.oe, (b.o.oval | b.o.pue), (a.o.pue | (a.o.oe & a.o.oval))) & a.o.ie + b.i.ival := Mux(a.o.oe, (a.o.oval | b.o.pue), (b.o.pue | (b.o.oe & b.o.oval))) & b.o.ie + } +} diff --git a/sifive-blocks/src/main/scala/devices/gpio/GPIOCtrlRegs.scala b/sifive-blocks/src/main/scala/devices/gpio/GPIOCtrlRegs.scala new file mode 100644 index 00000000..fda6e888 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/gpio/GPIOCtrlRegs.scala @@ -0,0 +1,22 @@ +// See LICENSE for license details. +package sifive.blocks.devices.gpio + +object GPIOCtrlRegs { + val value = 0x00 + val input_en = 0x04 + val output_en = 0x08 + val port = 0x0c + val pullup_en = 0x10 + val drive = 0x14 + val rise_ie = 0x18 + val rise_ip = 0x1c + val fall_ie = 0x20 + val fall_ip = 0x24 + val high_ie = 0x28 + val high_ip = 0x2c + val low_ie = 0x30 + val low_ip = 0x34 + val iof_en = 0x38 + val iof_sel = 0x3c + val out_xor = 0x40 +} diff --git a/sifive-blocks/src/main/scala/devices/gpio/GPIOPeriphery.scala b/sifive-blocks/src/main/scala/devices/gpio/GPIOPeriphery.scala new file mode 100644 index 00000000..3d0d0bb0 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/gpio/GPIOPeriphery.scala @@ -0,0 +1,21 @@ +// See LICENSE for license details. +package sifive.blocks.devices.gpio + +import freechips.rocketchip.config.Field +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.subsystem.BaseSubsystem + +case object PeripheryGPIOKey extends Field[Seq[GPIOParams]] + +trait HasPeripheryGPIO { this: BaseSubsystem => + val gpioNodes = p(PeripheryGPIOKey).map { ps => GPIO.attach(GPIOAttachParams(ps, pbus, ibus.fromAsync)).ioNode.makeSink } +} + +trait HasPeripheryGPIOBundle { + val gpio: Seq[GPIOPortIO] +} + +trait HasPeripheryGPIOModuleImp extends LazyModuleImp with HasPeripheryGPIOBundle { + val outer: HasPeripheryGPIO + val gpio = outer.gpioNodes.zipWithIndex.map { case(n,i) => n.makeIO()(ValName(s"gpio_$i")) } +} diff --git a/sifive-blocks/src/main/scala/devices/gpio/GPIOPins.scala b/sifive-blocks/src/main/scala/devices/gpio/GPIOPins.scala new file mode 100644 index 00000000..9f9b2833 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/gpio/GPIOPins.scala @@ -0,0 +1,40 @@ +// See LICENSE for license details. +package sifive.blocks.devices.gpio + +import Chisel._ +import chisel3.experimental.{withClockAndReset} +import sifive.blocks.devices.pinctrl.{Pin} + +// While this is a bit pendantic, it keeps the GPIO +// device more similar to the other devices. It's not 'special' +// even though it looks like something that more directly talks to +// a pin. It also makes it possible to change the exact +// type of pad this connects to. +class GPIOSignals[T <: Data](private val pingen: () => T, private val c: GPIOParams) extends Bundle { + val pins = Vec(c.width, pingen()) +} + +class GPIOPins[T <: Pin](pingen: () => T, c: GPIOParams) extends GPIOSignals[T](pingen, c) + +object GPIOPinsFromPort { + + def apply[T <: Pin](pins: GPIOSignals[T], port: GPIOPortIO, clock: Clock, reset: Bool){ + + // This will just match up the components of the Bundle that + // exist in both. + withClockAndReset(clock, reset) { + (pins.pins zip port.pins) foreach {case (pin, port) => + pin <> port + } + } + } + + def apply[T <: Pin](pins: GPIOSignals[T], port: GPIOPortIO){ + + // This will just match up the components of the Bundle that + // exist in both. + (pins.pins zip port.pins) foreach {case (pin, port) => + pin <> port + } + } +} diff --git a/sifive-blocks/src/main/scala/devices/gpio/IOF.scala b/sifive-blocks/src/main/scala/devices/gpio/IOF.scala new file mode 100644 index 00000000..3f93616f --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/gpio/IOF.scala @@ -0,0 +1,64 @@ +// See LICENSE for license details. +package sifive.blocks.devices.gpio + +import Chisel._ +import sifive.blocks.devices.pinctrl.{PinCtrl, Pin, BasePin, EnhancedPin, EnhancedPinCtrl} + +// This is the actual IOF interface.pa +// Add a valid bit to indicate whether +// there is something actually connected +// to this. +class IOFCtrl extends PinCtrl { + val valid = Bool() +} + +// By default, +object IOFCtrl { + def apply(): IOFCtrl = { + val iof = Wire(new IOFCtrl()) + iof.valid := Bool(false) + iof.oval := Bool(false) + iof.oe := Bool(false) + iof.ie := Bool(false) + iof + } +} + +// Package up the inputs and outputs +// for the IOF +class IOFPin extends Pin { + val o = new IOFCtrl().asOutput + + def default(): Unit = { + this.o.oval := Bool(false) + this.o.oe := Bool(false) + this.o.ie := Bool(false) + this.o.valid := Bool(false) + } + + def inputPin(pue: Bool = Bool(false) /*ignored*/): Bool = { + this.o.oval := Bool(false) + this.o.oe := Bool(false) + this.o.ie := Bool(true) + this.i.ival + } + def outputPin(signal: Bool, + pue: Bool = Bool(false), /*ignored*/ + ds: Bool = Bool(false), /*ignored*/ + ie: Bool = Bool(false) + ): Unit = { + this.o.oval := signal + this.o.oe := Bool(true) + this.o.ie := ie + } +} + +// Connect both the i and o side of the pin, +// and drive the valid signal for the IOF. +object BasePinToIOF { + def apply(pin: BasePin, iof: IOFPin): Unit = { + iof <> pin + iof.o.valid := Bool(true) + } +} + diff --git a/sifive-blocks/src/main/scala/devices/i2c/I2C.scala b/sifive-blocks/src/main/scala/devices/i2c/I2C.scala new file mode 100644 index 00000000..1fe9cb58 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/i2c/I2C.scala @@ -0,0 +1,613 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE revB.2 compliant I2C Master controller Top-level //// +//// //// +//// //// +//// Author: Richard Herveille //// +//// richard@asics.ws //// +//// www.asics.ws //// +//// //// +//// Downloaded from: http://www.opencores.org/projects/i2c/ //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001 Richard Herveille //// +//// richard@asics.ws //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer.//// +//// //// +//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// +//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// +//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// +//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// +//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// +//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// +//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// +//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// +//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// +//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// +//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// +//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// +//// POSSIBILITY OF SUCH DAMAGE. //// +//// //// +///////////////////////////////////////////////////////////////////// + +// This code was re-written in Chisel by SiFive, Inc. +// See LICENSE for license details. +// WISHBONE interface replaced by Tilelink2 + +package sifive.blocks.devices.i2c + +import Chisel._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util.{AsyncResetRegVec, Majority} + +case class I2CParams( + address: BigInt, + controlXType: ClockCrossingType = NoCrossing, + intXType: ClockCrossingType = NoCrossing) + +class I2CPin extends Bundle { + val in = Bool(INPUT) + val out = Bool(OUTPUT) + val oe = Bool(OUTPUT) +} + +class I2CPort extends Bundle { + val scl = new I2CPin + val sda = new I2CPin +} + +abstract class I2C(busWidthBytes: Int, params: I2CParams)(implicit p: Parameters) + extends IORegisterRouter( + RegisterRouterParams( + name = "i2c", + compat = Seq("sifive,i2c0"), + base = params.address, + beatBytes = busWidthBytes), + new I2CPort) + with HasInterruptSources { + + def nInterrupts = 1 + + lazy val module = new LazyModuleImp(this) { + + val I2C_CMD_NOP = UInt(0x00) + val I2C_CMD_START = UInt(0x01) + val I2C_CMD_STOP = UInt(0x02) + val I2C_CMD_WRITE = UInt(0x04) + val I2C_CMD_READ = UInt(0x08) + + class PrescalerBundle extends Bundle{ + val hi = UInt(8.W) + val lo = UInt(8.W) + } + + class ControlBundle extends Bundle{ + val coreEn = Bool() + val intEn = Bool() + val reserved = UInt(6.W) + } + + class CommandBundle extends Bundle{ + val start = Bool() + val stop = Bool() + val read = Bool() + val write = Bool() + val ack = Bool() + val reserved = UInt(2.W) + val irqAck = Bool() + } + + class StatusBundle extends Bundle{ + val receivedAck = Bool() // received aknowledge from slave + val busy = Bool() + val arbLost = Bool() + val reserved = UInt(3.W) + val transferInProgress = Bool() + val irqFlag = Bool() + } + + // control state visible to SW/driver + val prescaler = Reg(init = (new PrescalerBundle).fromBits(0xFFFF.U)) + val control = Reg(init = (new ControlBundle).fromBits(0.U)) + val transmitData = Reg(init = UInt(0, 8.W)) + val receivedData = Reg(init = UInt(0, 8.W)) + val cmd = Reg(init = (new CommandBundle).fromBits(0.U)) + val status = Reg(init = (new StatusBundle).fromBits(0.U)) + + + //////// Bit level //////// + + port.scl.out := false.B // i2c clock line output + port.sda.out := false.B // i2c data line output + + // filter SCL and SDA signals; (attempt to) remove glitches + val filterCnt = Reg(init = UInt(0, 14.W)) + when ( !control.coreEn ) { + filterCnt := 0.U + } .elsewhen (!(filterCnt.orR)) { + filterCnt := Cat(prescaler.hi, prescaler.lo) >> 2 //16x I2C bus frequency + } .otherwise { + filterCnt := filterCnt - 1.U + } + + val fSCL = Reg(init = UInt(0x7, 3.W)) + val fSDA = Reg(init = UInt(0x7, 3.W)) + when (!(filterCnt.orR)) { + fSCL := Cat(fSCL, port.scl.in) + fSDA := Cat(fSDA, port.sda.in) + } + + val sSCL = Reg(init = true.B, next = Majority(fSCL)) + val sSDA = Reg(init = true.B, next = Majority(fSDA)) + + val dSCL = Reg(init = true.B, next = sSCL) + val dSDA = Reg(init = true.B, next = sSDA) + + val dSCLOen = Reg(next = port.scl.oe) // delayed scl_oen + + // detect start condition => detect falling edge on SDA while SCL is high + // detect stop condition => detect rising edge on SDA while SCL is high + val startCond = Reg(init = false.B, next = !sSDA && dSDA && sSCL) + val stopCond = Reg(init = false.B, next = sSDA && !dSDA && sSCL) + + // master drives SCL high, but another master pulls it low + // master start counting down its low cycle now (clock synchronization) + val sclSync = dSCL && !sSCL && port.scl.oe + + // slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low + // slave_wait remains asserted until the slave releases SCL + val slaveWait = Reg(init = false.B) + slaveWait := (port.scl.oe && !dSCLOen && !sSCL) || (slaveWait && !sSCL) + + val clkEn = Reg(init = true.B) // clock generation signals + val cnt = Reg(init = UInt(0, 16.W)) // clock divider counter (synthesis) + + // generate clk enable signal + when (!(cnt.orR) || !control.coreEn || sclSync ) { + cnt := Cat(prescaler.hi, prescaler.lo) + clkEn := true.B + } + .elsewhen (slaveWait) { + clkEn := false.B + } + .otherwise { + cnt := cnt - 1.U + clkEn := false.B + } + + val sclOen = Reg(init = true.B) + port.scl.oe := !sclOen + + val sdaOen = Reg(init = true.B) + port.sda.oe := !sdaOen + + val sdaChk = Reg(init = false.B) // check SDA output (Multi-master arbitration) + + val transmitBit = Reg(init = false.B) + val receivedBit = Reg(Bool()) + when (sSCL && !dSCL) { + receivedBit := sSDA + } + + val bitCmd = Reg(init = UInt(0, 4.W)) // command (from byte controller) + val bitCmdStop = Reg(init = false.B) + when (clkEn) { + bitCmdStop := bitCmd === I2C_CMD_STOP + } + val bitCmdAck = Reg(init = false.B) + + val (s_bit_idle :: + s_bit_start_a :: s_bit_start_b :: s_bit_start_c :: s_bit_start_d :: s_bit_start_e :: + s_bit_stop_a :: s_bit_stop_b :: s_bit_stop_c :: s_bit_stop_d :: + s_bit_rd_a :: s_bit_rd_b :: s_bit_rd_c :: s_bit_rd_d :: + s_bit_wr_a :: s_bit_wr_b :: s_bit_wr_c :: s_bit_wr_d :: Nil) = Enum(UInt(), 18) + val bitState = Reg(init = s_bit_idle) + + val arbLost = Reg(init = false.B, next = (sdaChk && !sSDA && sdaOen) | ((bitState =/= s_bit_idle) && stopCond && !bitCmdStop)) + + // bit FSM + when (arbLost) { + bitState := s_bit_idle + bitCmdAck := false.B + sclOen := true.B + sdaOen := true.B + sdaChk := false.B + } + .otherwise { + bitCmdAck := false.B + + when (clkEn) { + switch (bitState) { + is (s_bit_idle) { + switch (bitCmd) { + is (I2C_CMD_START) { bitState := s_bit_start_a } + is (I2C_CMD_STOP) { bitState := s_bit_stop_a } + is (I2C_CMD_WRITE) { bitState := s_bit_wr_a } + is (I2C_CMD_READ) { bitState := s_bit_rd_a } + } + sdaChk := false.B + } + + is (s_bit_start_a) { + bitState := s_bit_start_b + sclOen := sclOen + sdaOen := true.B + sdaChk := false.B + } + is (s_bit_start_b) { + bitState := s_bit_start_c + sclOen := true.B + sdaOen := true.B + sdaChk := false.B + } + is (s_bit_start_c) { + bitState := s_bit_start_d + sclOen := true.B + sdaOen := false.B + sdaChk := false.B + } + is (s_bit_start_d) { + bitState := s_bit_start_e + sclOen := true.B + sdaOen := false.B + sdaChk := false.B + } + is (s_bit_start_e) { + bitState := s_bit_idle + bitCmdAck := true.B + sclOen := false.B + sdaOen := false.B + sdaChk := false.B + } + + is (s_bit_stop_a) { + bitState := s_bit_stop_b + sclOen := false.B + sdaOen := false.B + sdaChk := false.B + } + is (s_bit_stop_b) { + bitState := s_bit_stop_c + sclOen := true.B + sdaOen := false.B + sdaChk := false.B + } + is (s_bit_stop_c) { + bitState := s_bit_stop_d + sclOen := true.B + sdaOen := false.B + sdaChk := false.B + } + is (s_bit_stop_d) { + bitState := s_bit_idle + bitCmdAck := true.B + sclOen := true.B + sdaOen := true.B + sdaChk := false.B + } + + is (s_bit_rd_a) { + bitState := s_bit_rd_b + sclOen := false.B + sdaOen := true.B + sdaChk := false.B + } + is (s_bit_rd_b) { + bitState := s_bit_rd_c + sclOen := true.B + sdaOen := true.B + sdaChk := false.B + } + is (s_bit_rd_c) { + bitState := s_bit_rd_d + sclOen := true.B + sdaOen := true.B + sdaChk := false.B + } + is (s_bit_rd_d) { + bitState := s_bit_idle + bitCmdAck := true.B + sclOen := false.B + sdaOen := true.B + sdaChk := false.B + } + + is (s_bit_wr_a) { + bitState := s_bit_wr_b + sclOen := false.B + sdaOen := transmitBit + sdaChk := false.B + } + is (s_bit_wr_b) { + bitState := s_bit_wr_c + sclOen := true.B + sdaOen := transmitBit + sdaChk := false.B + } + is (s_bit_wr_c) { + bitState := s_bit_wr_d + sclOen := true.B + sdaOen := transmitBit + sdaChk := true.B + } + is (s_bit_wr_d) { + bitState := s_bit_idle + bitCmdAck := true.B + sclOen := false.B + sdaOen := transmitBit + sdaChk := false.B + } + } + } + } + + + //////// Byte level /////// + val load = Reg(init = false.B) // load shift register + val shift = Reg(init = false.B) // shift shift register + val cmdAck = Reg(init = false.B) // also done + val receivedAck = Reg(init = false.B) // from I2C slave + val go = (cmd.read | cmd.write | cmd.stop) & !cmdAck + + val bitCnt = Reg(init = UInt(0, 3.W)) + when (load) { + bitCnt := 0x7.U + } + .elsewhen (shift) { + bitCnt := bitCnt - 1.U + } + val bitCntDone = !(bitCnt.orR) + + // receivedData is used as shift register directly + when (load) { + receivedData := transmitData + } + .elsewhen (shift) { + receivedData := Cat(receivedData, receivedBit) + } + + val (s_byte_idle :: s_byte_start :: s_byte_read :: s_byte_write :: s_byte_ack :: s_byte_stop :: Nil) = Enum(UInt(), 6) + val byteState = Reg(init = s_byte_idle) + + when (arbLost) { + bitCmd := I2C_CMD_NOP + transmitBit := false.B + shift := false.B + load := false.B + cmdAck := false.B + byteState := s_byte_idle + receivedAck := false.B + } + .otherwise { + transmitBit := receivedData(7) + shift := false.B + load := false.B + cmdAck := false.B + + switch (byteState) { + is (s_byte_idle) { + when (go) { + when (cmd.start) { + byteState := s_byte_start + bitCmd := I2C_CMD_START + } + .elsewhen (cmd.read) { + byteState := s_byte_read + bitCmd := I2C_CMD_READ + } + .elsewhen (cmd.write) { + byteState := s_byte_write + bitCmd := I2C_CMD_WRITE + } + .otherwise { // stop + byteState := s_byte_stop + bitCmd := I2C_CMD_STOP + } + + load := true.B + } + } + is (s_byte_start) { + when (bitCmdAck) { + when (cmd.read) { + byteState := s_byte_read + bitCmd := I2C_CMD_READ + } + .otherwise { + byteState := s_byte_write + bitCmd := I2C_CMD_WRITE + } + + load := true.B + } + } + is (s_byte_write) { + when (bitCmdAck) { + when (bitCntDone) { + byteState := s_byte_ack + bitCmd := I2C_CMD_READ + } + .otherwise { + byteState := s_byte_write + bitCmd := I2C_CMD_WRITE + shift := true.B + } + } + } + is (s_byte_read) { + when (bitCmdAck) { + when (bitCntDone) { + byteState := s_byte_ack + bitCmd := I2C_CMD_WRITE + } + .otherwise { + byteState := s_byte_read + bitCmd := I2C_CMD_READ + } + + shift := true.B + transmitBit := cmd.ack + } + } + is (s_byte_ack) { + when (bitCmdAck) { + when (cmd.stop) { + byteState := s_byte_stop + bitCmd := I2C_CMD_STOP + } + .otherwise { + byteState := s_byte_idle + bitCmd := I2C_CMD_NOP + + // generate command acknowledge signal + cmdAck := true.B + } + + // assign ack_out output to bit_controller_rxd (contains last received bit) + receivedAck := receivedBit + + transmitBit := true.B + } + .otherwise { + transmitBit := cmd.ack + } + } + is (s_byte_stop) { + when (bitCmdAck) { + byteState := s_byte_idle + bitCmd := I2C_CMD_NOP + + // assign ack_out output to bit_controller_rxd (contains last received bit) + cmdAck := true.B + } + } + } + } + + + //////// Top level //////// + + // hack: b/c the same register offset is used to write cmd and read status + val nextCmd = Wire(UInt(8.W)) + cmd := (new CommandBundle).fromBits(nextCmd) + nextCmd := cmd.asUInt & 0xFE.U // clear IRQ_ACK bit (essentially 1 cycle pulse b/c it is overwritten by regmap below) + + // Note: This wins over the regmap update of nextCmd (even if something tries to write them to 1, these values take priority). + when (cmdAck || arbLost) { + cmd.start := false.B // clear command bits when done + cmd.stop := false.B // or when aribitration lost + cmd.read := false.B + cmd.write := false.B + } + + status.receivedAck := receivedAck + when (stopCond) { + status.busy := false.B + } + .elsewhen (startCond) { + status.busy := true.B + } + + when (arbLost) { + status.arbLost := true.B + } + .elsewhen (cmd.start) { + status.arbLost := false.B + } + status.transferInProgress := cmd.read || cmd.write + status.irqFlag := (cmdAck || arbLost || status.irqFlag) && !cmd.irqAck // interrupt request flag is always generated + + + val statusReadReady = Reg(init = true.B) + when (cmdAck || arbLost) { // => cmd.read or cmd.write deassert 1 cycle later => transferInProgress deassert 2 cycles later + statusReadReady := false.B // do not allow status read if status.transferInProgress is going to change + } + .elsewhen (!statusReadReady) { + statusReadReady := true.B + } + + // statusReadReady, + regmap( + I2CCtrlRegs.prescaler_lo -> Seq(RegField(8, prescaler.lo, + RegFieldDesc("prescaler_lo","I2C prescaler, low byte", reset=Some(0)))), + I2CCtrlRegs.prescaler_hi -> Seq(RegField(8, prescaler.hi, + RegFieldDesc("prescaler_hi","I2C prescaler, high byte", reset=Some(0)))), + I2CCtrlRegs.control -> RegFieldGroup("control", + Some("Control"), + control.elements.map{ + case(name, e) => RegField(e.getWidth, + e.asInstanceOf[UInt], + RegFieldDesc(name, s"Sets the ${name}" , + reset=Some(0))) + }.toSeq), + I2CCtrlRegs.data -> Seq(RegField(8, r = RegReadFn(receivedData), w = RegWriteFn(transmitData), + RegFieldDesc("data","I2C tx and rx data", volatile=true, reset=Some(0)))), + I2CCtrlRegs.cmd_status -> Seq(RegField(8, r = RegReadFn{ ready => + (statusReadReady, status.asUInt) + }, + w = RegWriteFn((valid, data) => { + when (valid) { + statusReadReady := false.B + nextCmd := data + } + true.B + }), + RegFieldDesc("cmd_status","On write, update I2C command. On Read, report I2C status", volatile=true))) + ) + + // tie off unused bits + control.reserved := 0.U + cmd.reserved := 0.U + status.reserved := 0.U + + interrupts(0) := status.irqFlag & control.intEn +}} + +class TLI2C(busWidthBytes: Int, params: I2CParams)(implicit p: Parameters) + extends I2C(busWidthBytes, params) with HasTLControlRegMap + +case class I2CAttachParams( + i2c: I2CParams, + controlBus: TLBusWrapper, + intNode: IntInwardNode, + controlXType: ClockCrossingType = NoCrossing, + intXType: ClockCrossingType = NoCrossing, + mclock: Option[ModuleValue[Clock]] = None, + mreset: Option[ModuleValue[Bool]] = None) + (implicit val p: Parameters) + +object I2C { + val nextId = { var i = -1; () => { i += 1; i} } + + def attach(params: I2CAttachParams): TLI2C = { + implicit val p = params.p + val name = s"i2c_${nextId()}" + val cbus = params.controlBus + val i2c = LazyModule(new TLI2C(cbus.beatBytes, params.i2c)) + i2c.suggestName(name) + + cbus.coupleTo(s"device_named_$name") { + i2c.controlXing(params.controlXType) := TLFragmenter(cbus.beatBytes, cbus.blockBytes) := _ + } + params.intNode := i2c.intXing(params.intXType) + InModuleBody { i2c.module.clock := params.mclock.map(_.getWrappedValue).getOrElse(cbus.module.clock) } + InModuleBody { i2c.module.reset := params.mreset.map(_.getWrappedValue).getOrElse(cbus.module.reset) } + + i2c + } + + def attachAndMakePort(params: I2CAttachParams): ModuleValue[I2CPort] = { + val i2c = attach(params) + val i2cNode = i2c.ioNode.makeSink()(params.p) + InModuleBody { i2cNode.makeIO()(ValName(i2c.name)) } + } +} diff --git a/sifive-blocks/src/main/scala/devices/i2c/I2CCtrlRegs.scala b/sifive-blocks/src/main/scala/devices/i2c/I2CCtrlRegs.scala new file mode 100644 index 00000000..aaa61979 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/i2c/I2CCtrlRegs.scala @@ -0,0 +1,13 @@ +// See LICENSE for license details. +package sifive.blocks.devices.i2c + +// matching Open Cores I2C to re-use Linux driver +// http://lxr.free-electrons.com/source/drivers/i2c/busses/i2c-ocores.c?v=4.6 + +object I2CCtrlRegs { + val prescaler_lo = 0x00 // low byte clock prescaler register + val prescaler_hi = 0x04 // high byte clock prescaler register + val control = 0x08 // control register + val data = 0x0c // write: transmit byte, read: receive byte + val cmd_status = 0x10 // write: command, read: status +} diff --git a/sifive-blocks/src/main/scala/devices/i2c/I2CPeriphery.scala b/sifive-blocks/src/main/scala/devices/i2c/I2CPeriphery.scala new file mode 100644 index 00000000..a819503a --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/i2c/I2CPeriphery.scala @@ -0,0 +1,24 @@ +// See LICENSE for license details. +package sifive.blocks.devices.i2c + +import Chisel._ +import freechips.rocketchip.config.Field +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.subsystem.{BaseSubsystem} + +case object PeripheryI2CKey extends Field[Seq[I2CParams]] + +trait HasPeripheryI2C { this: BaseSubsystem => + val i2cNodes = p(PeripheryI2CKey).map { ps => + I2C.attach(I2CAttachParams(ps, pbus, ibus.fromAsync)).ioNode.makeSink() + } +} + +trait HasPeripheryI2CBundle { + val i2c: Seq[I2CPort] +} + +trait HasPeripheryI2CModuleImp extends LazyModuleImp with HasPeripheryI2CBundle { + val outer: HasPeripheryI2C + val i2c = outer.i2cNodes.zipWithIndex.map { case(n,i) => n.makeIO()(ValName(s"i2c_$i")) } +} diff --git a/sifive-blocks/src/main/scala/devices/i2c/I2CPins.scala b/sifive-blocks/src/main/scala/devices/i2c/I2CPins.scala new file mode 100644 index 00000000..32cf50df --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/i2c/I2CPins.scala @@ -0,0 +1,31 @@ +// See LICENSE for license details. +package sifive.blocks.devices.i2c + +import Chisel._ +import chisel3.experimental.{withClockAndReset} +import freechips.rocketchip.util.SyncResetSynchronizerShiftReg +import sifive.blocks.devices.pinctrl.{Pin, PinCtrl} + +class I2CSignals[T <: Data](private val pingen: () => T) extends Bundle { + val scl: T = pingen() + val sda: T = pingen() +} + +class I2CPins[T <: Pin](pingen: () => T) extends I2CSignals[T](pingen) + +object I2CPinsFromPort { + + def apply[T <: Pin](pins: I2CSignals[T], i2c: I2CPort, clock: Clock, reset: Bool, syncStages: Int = 0) = { + withClockAndReset(clock, reset) { + pins.scl.outputPin(i2c.scl.out, pue=true.B, ie = true.B) + pins.scl.o.oe := i2c.scl.oe + i2c.scl.in := SyncResetSynchronizerShiftReg(pins.scl.i.ival, syncStages, init = Bool(true), + name = Some("i2c_scl_sync")) + + pins.sda.outputPin(i2c.sda.out, pue=true.B, ie = true.B) + pins.sda.o.oe := i2c.sda.oe + i2c.sda.in := SyncResetSynchronizerShiftReg(pins.sda.i.ival, syncStages, init = Bool(true), + name = Some("i2c_sda_sync")) + } + } +} diff --git a/sifive-blocks/src/main/scala/devices/jtag/JTAGPins.scala b/sifive-blocks/src/main/scala/devices/jtag/JTAGPins.scala new file mode 100644 index 00000000..5112faa6 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/jtag/JTAGPins.scala @@ -0,0 +1,37 @@ +// See LICENSE for license details. +package sifive.blocks.devices.jtag + +import Chisel._ + +// ------------------------------------------------------------ +// SPI, UART, etc are with their respective packages, +// JTAG doesn't really correspond directly to a device, but it does +// define pins as those devices do. +// ------------------------------------------------------------ + +import freechips.rocketchip.config._ +import freechips.rocketchip.jtag.{JTAGIO} +import sifive.blocks.devices.pinctrl.{Pin, PinCtrl} + +class JTAGSignals[T <: Data](pingen: () => T, hasTRSTn: Boolean = true) extends Bundle { + val TCK = pingen() + val TMS = pingen() + val TDI = pingen() + val TDO = pingen() + val TRSTn = if (hasTRSTn) Option(pingen()) else None +} + +class JTAGPins[T <: Pin](pingen: () => T, hasTRSTn: Boolean = true) extends JTAGSignals[T](pingen, hasTRSTn) + +object JTAGPinsFromPort { + + def apply[T <: Pin] (pins: JTAGSignals[T], jtag: JTAGIO): Unit = { + jtag.TCK := pins.TCK.inputPin (pue = Bool(true)).asClock + jtag.TMS := pins.TMS.inputPin (pue = Bool(true)) + jtag.TDI := pins.TDI.inputPin(pue = Bool(true)) + jtag.TRSTn.foreach{t => t := pins.TRSTn.get.inputPin(pue = Bool(true))} + + pins.TDO.outputPin(jtag.TDO.data) + pins.TDO.o.oe := jtag.TDO.driven + } +} diff --git a/sifive-blocks/src/main/scala/devices/mockaon/MockAON.scala b/sifive-blocks/src/main/scala/devices/mockaon/MockAON.scala new file mode 100644 index 00000000..06068220 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/mockaon/MockAON.scala @@ -0,0 +1,101 @@ +// See LICENSE for license details. +package sifive.blocks.devices.mockaon + +import Chisel._ +import chisel3.experimental.MultiIOModule +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.tilelink._ + +import sifive.blocks.util.GenericTimer + +case class MockAONParams( + address: BigInt = BigInt(0x10000000), + nBackupRegs: Int = 16) { + def size: Int = 0x1000 + def regBytes: Int = 4 + def wdogOffset: Int = 0 + def rtcOffset: Int = 0x40 + def backupRegOffset: Int = 0x80 + def pmuOffset: Int = 0x100 +} + +class MockAONPMUIO extends Bundle { + val vddpaden = Bool(OUTPUT) + val dwakeup = Bool(INPUT) +} + +class MockAONMOffRstIO extends Bundle { + val hfclkrst = Bool(OUTPUT) + val corerst = Bool(OUTPUT) +} + +trait HasMockAONBundleContents extends Bundle { + + // Output of the Power Management Sequencer + val moff = new MockAONMOffRstIO + + // This goes out to wrapper + // to be combined to create aon_rst. + val wdog_rst = Bool(OUTPUT) + + // This goes out to wrapper + // and comes back as our clk + val lfclk = Clock(OUTPUT) + + val pmu = new MockAONPMUIO + + val lfextclk = Clock(INPUT) + + val resetCauses = new ResetCauses().asInput +} + +trait HasMockAONModuleContents extends MultiIOModule with HasRegMap { + val io: HasMockAONBundleContents + val params: MockAONParams + val c = params + + // the expectation here is that Chisel's implicit reset is aonrst, + // which is asynchronous, so don't use synchronous-reset registers. + + val rtc = Module(new RTC) + + val pmu = Module(new PMU(new DevKitPMUConfig)) + io.moff <> pmu.io.control + io.pmu.vddpaden := pmu.io.control.vddpaden + pmu.io.wakeup.dwakeup := io.pmu.dwakeup + pmu.io.wakeup.awakeup := Bool(false) + pmu.io.wakeup.rtc := rtc.io.ip(0) + pmu.io.resetCauses := io.resetCauses + val pmuRegMap = { + val regs = pmu.io.regs.wakeupProgram ++ pmu.io.regs.sleepProgram ++ + Seq(pmu.io.regs.ie, pmu.io.regs.cause, pmu.io.regs.sleep, pmu.io.regs.key) + for ((r, i) <- regs.zipWithIndex) + yield (c.pmuOffset + c.regBytes*i) -> Seq(r.toRegField()) + } + interrupts(1) := rtc.io.ip(0) + + val wdog = Module(new WatchdogTimer) + io.wdog_rst := wdog.io.rst + wdog.io.corerst := pmu.io.control.corerst + interrupts(0) := wdog.io.ip(0) + + // If there are multiple lfclks to choose from, we can mux them here. + io.lfclk := io.lfextclk + + val backupRegs = Seq.fill(c.nBackupRegs)(Reg(UInt(width = c.regBytes * 8))) + val backupRegMap = + for ((reg, i) <- backupRegs.zipWithIndex) + yield (c.backupRegOffset + c.regBytes*i) -> Seq(RegField(reg.getWidth, RegReadFn(reg), RegWriteFn(reg))) + + regmap((backupRegMap ++ + GenericTimer.timerRegMap(wdog, c.wdogOffset, c.regBytes) ++ + GenericTimer.timerRegMap(rtc, c.rtcOffset, c.regBytes) ++ + pmuRegMap):_*) + +} + +class TLMockAON(w: Int, c: MockAONParams)(implicit p: Parameters) + extends TLRegisterRouter(c.address, "aon", Seq("sifive,aon0"), interrupts = 2, size = c.size, beatBytes = w, concurrency = 1)( + new TLRegBundle(c, _) with HasMockAONBundleContents)( + new TLRegModule(c, _, _) with HasMockAONModuleContents) diff --git a/sifive-blocks/src/main/scala/devices/mockaon/MockAONPeriphery.scala b/sifive-blocks/src/main/scala/devices/mockaon/MockAONPeriphery.scala new file mode 100644 index 00000000..a8518965 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/mockaon/MockAONPeriphery.scala @@ -0,0 +1,53 @@ +// See LICENSE for license details. +package sifive.blocks.devices.mockaon + +import Chisel._ +import freechips.rocketchip.config.Field +import freechips.rocketchip.devices.debug.HasPeripheryDebug +import freechips.rocketchip.devices.tilelink.CanHavePeripheryCLINT +import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.subsystem.BaseSubsystem +import freechips.rocketchip.tilelink.{TLAsyncCrossingSource} +import freechips.rocketchip.util.{ResetCatchAndSync, SynchronizerShiftReg} + +case object PeripheryMockAONKey extends Field[MockAONParams] + +trait HasPeripheryMockAON extends CanHavePeripheryCLINT with HasPeripheryDebug { this: BaseSubsystem => + // We override the clock & Reset here so that all synchronizers, etc + // are in the proper clock domain. + val mockAONParams= p(PeripheryMockAONKey) + val aon = LazyModule(new MockAONWrapper(sbus.control_bus.beatBytes, mockAONParams)) + sbus.control_bus.toVariableWidthSlave(Some("aon")) { aon.node := TLAsyncCrossingSource() } + ibus.fromSync := IntSyncCrossingSink() := aon.intnode +} + +trait HasPeripheryMockAONBundle { + val aon: MockAONWrapperBundle + def coreResetCatchAndSync(core_clock: Clock) = { + ResetCatchAndSync(core_clock, aon.rsts.corerst, 20) + } +} + +trait HasPeripheryMockAONModuleImp extends LazyModuleImp with HasPeripheryMockAONBundle { + val outer: HasPeripheryMockAON + val aon = IO(new MockAONWrapperBundle) + + aon <> outer.aon.module.io + + // Explicit clock & reset are unused in MockAONWrapper. + // Tie to check this assumption. + outer.aon.module.clock := Bool(false).asClock + outer.aon.module.reset := Bool(true) + + // Synchronize the external toggle into the clint + val rtc_sync = SynchronizerShiftReg(outer.aon.module.io.rtc.asUInt.toBool, 3, Some("rtc")) + val rtc_last = Reg(init = Bool(false), next=rtc_sync) + val rtc_tick = Reg(init = Bool(false), next=(rtc_sync & (~rtc_last))) + + outer.clintOpt.foreach { clint => + clint.module.io.rtcTick := rtc_tick + } + + outer.aon.module.io.ndreset := outer.debug.module.io.ctrl.ndreset +} diff --git a/sifive-blocks/src/main/scala/devices/mockaon/MockAONWrapper.scala b/sifive-blocks/src/main/scala/devices/mockaon/MockAONWrapper.scala new file mode 100644 index 00000000..4d3b0fae --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/mockaon/MockAONWrapper.scala @@ -0,0 +1,173 @@ +// See LICENSE for license details. +package sifive.blocks.devices.mockaon + +import Chisel._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ +import freechips.rocketchip.interrupts._ +import sifive.blocks.devices.pinctrl.{EnhancedPin} +import sifive.blocks.util.{DeglitchShiftRegister} + +/* The wrapper handles the Clock and Reset Generation for The AON block itself, + and instantiates real pad controls (aka pull-ups)*/ + +class MockAONWrapperPMUIO extends Bundle { + val dwakeup_n = new EnhancedPin() + val vddpaden = new EnhancedPin() +} + +class MockAONWrapperPins extends Bundle { + val erst_n = new EnhancedPin() + val lfextclk = new EnhancedPin() + val pmu = new MockAONWrapperPMUIO() +} + +class MockAONWrapperBundle extends Bundle { + val pins = new MockAONWrapperPins() + val rsts = new MockAONMOffRstIO() +} + +class MockAONWrapper(w: Int, c: MockAONParams)(implicit p: Parameters) extends LazyModule { + + val aon = LazyModule(new TLMockAON(w, c)) + + // We only need to isolate the signals + // coming from MOFF to AON, + // since AON is never off while MOFF is on. + // The MOFF is on the "in" side of the Isolation. + // AON is on the "out" side of the Isolation. + + def isoOut(iso: Bool, x: UInt): UInt = IsoZero(iso, x) + def isoIn(iso: Bool, x: UInt): UInt = x + val isolation = LazyModule(new TLIsolation(fOut = isoOut, fIn = isoIn)) + val crossing = LazyModule(new TLAsyncCrossingSink(AsyncQueueParams.singleton())) + + val node = aon.node := crossing.node := isolation.node + + // crossing lives outside in Periphery + val intnode = IntSyncCrossingSource(alreadyRegistered = true) := aon.intnode + + lazy val module = new LazyModuleImp(this) { + val io = IO(new MockAONWrapperBundle { + val rtc = Clock(OUTPUT) + val ndreset = Bool(INPUT) + }) + + val aon_io = aon.module.io + val pins = io.pins + + // ----------------------------------------------- + // Generation of aonrst + // ----------------------------------------------- + + // ERST + val erst = ~pins.erst_n.inputPin(pue = Bool(true)) + aon_io.resetCauses.erst := erst + aon_io.resetCauses.wdogrst := aon_io.wdog_rst + + // PORRST + val porrst = Bool(false) // TODO + aon_io.resetCauses.porrst := porrst + + //-------------------------------------------------- + // Drive "Mostly Off" Reset Signals (these + // are synchronized inside MOFF as needed) + //-------------------------------------------------- + + io.rsts.hfclkrst := aon_io.moff.hfclkrst + io.rsts.corerst := aon_io.moff.corerst + + //-------------------------------------------------- + // Generate the LFCLK input to AON + // This is the same clock that is driven to this + // block as 'clock'. + //-------------------------------------------------- + + // LFCLK Override + // Note that the actual mux lives inside AON itself. + // Therefore, the lfclk which comes out of AON is the + // true clock that AON and AONWrapper are running off of. + val lfextclk = pins.lfextclk.inputPin(pue=Bool(true)) + aon_io.lfextclk := lfextclk.asClock + + // Drive AON's clock and Reset + val lfclk = aon_io.lfclk + + val aonrst_catch = Module (new ResetCatchAndSync(3)) + aonrst_catch.reset := erst | aon_io.wdog_rst | io.ndreset + aonrst_catch.clock := lfclk + aon.module.reset := aonrst_catch.io.sync_reset + + aon.module.clock := lfclk + + //-------------------------------------------------- + // TL2 Register Access Interface + //-------------------------------------------------- + + // Safely cross TL2 into AON Domain + // Ensure that both are reset and clocked + // at the same time. + // Note that aon.moff.corerst is synchronous + // to aon.module.clock, so this is safe. + val crossing_slave_reset = ResetCatchAndSync(lfclk, + aon.module.io.moff.corerst | aon.module.reset) + + crossing.module.clock := lfclk + crossing.module.reset := crossing_slave_reset + + // Note that aon.moff.corerst is synchronous + // to aon.module.clock, so this is safe. + isolation.module.io.iso_out := aon.module.io.moff.corerst + isolation.module.io.iso_in := Bool(true) + + //-------------------------------------------------- + // PMU <--> pins Interface + //-------------------------------------------------- + + val dwakeup_n_async = pins.pmu.dwakeup_n.inputPin(pue=Bool(true)) + + val dwakeup_deglitch = Module (new DeglitchShiftRegister(3)) + dwakeup_deglitch.clock := lfclk + dwakeup_deglitch.io.d := ~dwakeup_n_async + aon.module.io.pmu.dwakeup := dwakeup_deglitch.io.q + + pins.pmu.vddpaden.outputPin(aon.module.io.pmu.vddpaden) + + //-------------------------------------------------- + // Connect signals to MOFF + //-------------------------------------------------- + + io.rtc := aon_io.lfclk + } + +} + +// ----------------------------------------------- +// Isolation Cells +// ----------------------------------------------- + +class IsoZero extends Module { + val io = new Bundle { + val in = Bool(INPUT) + val iso = Bool(INPUT) + val out = Bool(OUTPUT) + } + io.out := io.in & ~io.iso +} + +object IsoZero { + def apply (iso: Bool, in: UInt): UInt = { + + val w = in.getWidth + val isos: List[IsoZero] = List.tabulate(in.getWidth)( + x => Module(new IsoZero).suggestName(s"iso_$x") + ) + for ((z, i) <- isos.zipWithIndex) { + z.io.in := in(i) + z.io.iso := iso + } + isos.map(_.io.out).asUInt + } +} diff --git a/sifive-blocks/src/main/scala/devices/mockaon/PMU.scala b/sifive-blocks/src/main/scala/devices/mockaon/PMU.scala new file mode 100644 index 00000000..bd9d339c --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/mockaon/PMU.scala @@ -0,0 +1,154 @@ +// See LICENSE for license details. +package sifive.blocks.devices.mockaon + +import Chisel._ +import Chisel.ImplicitConversions._ +import freechips.rocketchip.util._ +import sifive.blocks.util.SRLatch + +import sifive.blocks.util.{SlaveRegIF} + +class WakeupCauses extends Bundle { + val awakeup = Bool() + val dwakeup = Bool() + val rtc = Bool() + val reset = Bool() +} + +class ResetCauses extends Bundle { + val wdogrst = Bool() + val erst = Bool() + val porrst = Bool() +} + +class PMUSignals extends Bundle { + val hfclkrst = Bool() + val corerst = Bool() + val reserved1 = Bool() + val vddpaden = Bool() + val reserved0 = Bool() +} + +class PMUInstruction extends Bundle { + val sigs = new PMUSignals + val dt = UInt(width = 4) +} + +class PMUConfig(wakeupProgramIn: Seq[Int], + sleepProgramIn: Seq[Int]) { + val programLength = 8 + val nWakeupCauses = new WakeupCauses().elements.size + val wakeupProgram = wakeupProgramIn.padTo(programLength, wakeupProgramIn.last) + val sleepProgram = sleepProgramIn.padTo(programLength, sleepProgramIn.last) + require(wakeupProgram.length == programLength) + require(sleepProgram.length == programLength) +} + +class DevKitPMUConfig extends PMUConfig( // TODO + Seq(0x1f0, 0x0f8, 0x030), + Seq(0x0f0, 0x1f0, 0x1d0, 0x1c0)) + +class PMURegs(c: PMUConfig) extends Bundle { + val ie = new SlaveRegIF(c.nWakeupCauses) + val cause = new SlaveRegIF(32) + val sleep = new SlaveRegIF(32) + val key = new SlaveRegIF(32) + val wakeupProgram = Vec(c.programLength, new SlaveRegIF(32)) + val sleepProgram = Vec(c.programLength, new SlaveRegIF(32)) +} + +class PMUCore(c: PMUConfig)(resetIn: Bool) extends Module(_reset = resetIn) { + val io = new Bundle { + val wakeup = new WakeupCauses().asInput + val control = Valid(new PMUSignals) + val resetCause = UInt(INPUT, log2Ceil(new ResetCauses().getWidth)) + val regs = new PMURegs(c) + } + + val run = Reg(init = Bool(true)) + val awake = Reg(init = Bool(true)) + val unlocked = { + val writeAny = WatchdogTimer.writeAnyExceptKey(io.regs, io.regs.key) + RegEnable(io.regs.key.write.bits === WatchdogTimer.key && !writeAny, Bool(false), io.regs.key.write.valid || writeAny) + } + val wantSleep = RegEnable(Bool(true), Bool(false), io.regs.sleep.write.valid && unlocked) + val pc = Reg(init = UInt(0, log2Ceil(c.programLength))) + val wakeupCause = Reg(init = UInt(0, log2Ceil(c.nWakeupCauses))) + val ie = RegEnable(io.regs.ie.write.bits, io.regs.ie.write.valid && unlocked) | 1 /* POR always enabled */ + + val insnWidth = new PMUInstruction().getWidth + val wakeupProgram = c.wakeupProgram.map(v => Reg(init = UInt(v, insnWidth))) + val sleepProgram = c.sleepProgram.map(v => Reg(init = UInt(v, insnWidth))) + val insnBits = Mux(awake, wakeupProgram(pc), sleepProgram(pc)) + val insn = new PMUInstruction().fromBits(insnBits) + + val count = Reg(init = UInt(0, 1 << insn.dt.getWidth)) + val tick = (count ^ (count + 1))(insn.dt) + val npc = pc +& 1 + val last = npc >= c.programLength + io.control.valid := run && !last && tick + io.control.bits := insn.sigs + + when (run) { + count := count + 1 + when (tick) { + count := 0 + + require(isPow2(c.programLength)) + run := !last + pc := npc + } + }.otherwise { + val maskedWakeupCauses = ie & io.wakeup.asUInt + when (!awake && maskedWakeupCauses.orR) { + run := true + awake := true + wakeupCause := PriorityEncoder(maskedWakeupCauses) + } + when (awake && wantSleep) { + run := true + awake := false + wantSleep := false + } + } + + io.regs.cause.read := wakeupCause | (io.resetCause << 8) + io.regs.ie.read := ie + io.regs.key.read := unlocked + io.regs.sleep.read := 0 + + for ((port, reg) <- (io.regs.wakeupProgram ++ io.regs.sleepProgram) zip (wakeupProgram ++ sleepProgram)) { + port.read := reg + when (port.write.valid && unlocked) { reg := port.write.bits } + } +} + +class PMU(val c: PMUConfig) extends Module { + val io = new Bundle { + val wakeup = new WakeupCauses().asInput + val control = new PMUSignals().asOutput + val regs = new PMURegs(c) + val resetCauses = new ResetCauses().asInput + } + + val coreReset = Reg(next = Reg(next = reset)) + val core = Module(new PMUCore(c)(resetIn = coreReset)) + + io <> core.io + core.io.wakeup.reset := false // this is implied by resetting the PMU + + // during aonrst, hold all control signals high + val latch = ~AsyncResetReg(~core.io.control.bits.asUInt, core.io.control.valid) + io.control := io.control.fromBits(latch) + + core.io.resetCause := { + val cause = io.resetCauses.asUInt + val latches = for (i <- 0 until cause.getWidth) yield { + val latch = Module(new SRLatch) + latch.io.set := cause(i) + latch.io.reset := (0 until cause.getWidth).filter(_ != i).map(cause(_)).reduce(_||_) + latch.io.q + } + OHToUInt(latches) + } +} diff --git a/sifive-blocks/src/main/scala/devices/mockaon/RTC.scala b/sifive-blocks/src/main/scala/devices/mockaon/RTC.scala new file mode 100644 index 00000000..035c05b1 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/mockaon/RTC.scala @@ -0,0 +1,38 @@ +// See LICENSE for license details. +package sifive.blocks.devices.mockaon + +import Chisel._ +import Chisel.ImplicitConversions._ +import chisel3.experimental.MultiIOModule +import freechips.rocketchip.util.AsyncResetReg +import freechips.rocketchip.regmapper.RegFieldDesc + +import sifive.blocks.util.{SlaveRegIF, GenericTimer, GenericTimerIO, DefaultGenericTimerCfgDescs} + +class RTC extends MultiIOModule with GenericTimer { + + protected def prefix = "rtc" + protected def countWidth = 48 + protected def cmpWidth = 32 + protected def ncmp = 1 + protected def countEn = countAlways + override protected lazy val ip = RegNext(elapsed) + override protected lazy val zerocmp = Bool(false) + protected lazy val countAlways = AsyncResetReg(io.regs.cfg.write.countAlways, io.regs.cfg.write_countAlways && unlocked)(0) + protected lazy val feed = Bool(false) + + override protected lazy val feed_desc = RegFieldDesc.reserved + override protected lazy val key_desc = RegFieldDesc.reserved + override protected lazy val cfg_desc = DefaultGenericTimerCfgDescs("rtc", ncmp).copy( + sticky = RegFieldDesc.reserved, + zerocmp = RegFieldDesc.reserved, + deglitch = RegFieldDesc.reserved, + running = RegFieldDesc.reserved, + center = Seq.fill(ncmp){ RegFieldDesc.reserved }, + extra = Seq.fill(ncmp){ RegFieldDesc.reserved }, + gang = Seq.fill(ncmp){ RegFieldDesc.reserved } + ) + + lazy val io = IO(new GenericTimerIO(regWidth, ncmp, maxcmp, scaleWidth, countWidth, cmpWidth)) + +} diff --git a/sifive-blocks/src/main/scala/devices/mockaon/WatchdogTimer.scala b/sifive-blocks/src/main/scala/devices/mockaon/WatchdogTimer.scala new file mode 100644 index 00000000..f57869fe --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/mockaon/WatchdogTimer.scala @@ -0,0 +1,66 @@ +// See LICENSE for license details. +package sifive.blocks.devices.mockaon + +import Chisel._ +import Chisel.ImplicitConversions._ +import chisel3.experimental.MultiIOModule +import freechips.rocketchip.util.AsyncResetReg +import freechips.rocketchip.regmapper.{RegFieldDesc} + +import sifive.blocks.util.{SlaveRegIF, GenericTimer, GenericTimerIO, GenericTimerCfgRegIFC, DefaultGenericTimerCfgDescs} + +object WatchdogTimer { + def writeAnyExceptKey(regs: Bundle, keyReg: SlaveRegIF): Bool = { + regs.elements.values.filter(_ ne keyReg).map({ + case c: GenericTimerCfgRegIFC => c.anyWriteValid + case v: Vec[SlaveRegIF] @unchecked => v.map(_.write.valid).reduce(_||_) + case s: SlaveRegIF => s.write.valid + }).reduce(_||_) + } + + val key = 0x51F15E +} + +class WatchdogTimer extends MultiIOModule with GenericTimer { + protected def prefix = "wdog" + protected def countWidth = 31 + protected def cmpWidth = 16 + protected def ncmp = 1 + protected lazy val countAlways = AsyncResetReg(io.regs.cfg.write.countAlways, io.regs.cfg.write_countAlways && unlocked)(0) + override protected lazy val countAwake = AsyncResetReg(io.regs.cfg.write.running, io.regs.cfg.write_running && unlocked)(0) + protected lazy val countEn = { + val corerstSynchronized = Reg(next = Reg(next = io.corerst)) + countAlways || (countAwake && !corerstSynchronized) + } + override protected lazy val rsten = AsyncResetReg(io.regs.cfg.write.sticky, io.regs.cfg.write_sticky && unlocked)(0) + protected lazy val ip = RegEnable(Vec(Seq(io.regs.cfg.write.ip(0) || elapsed(0))), (io.regs.cfg.write_ip(0) && unlocked) || elapsed(0)) + override protected lazy val unlocked = { + val writeAny = WatchdogTimer.writeAnyExceptKey(io.regs, io.regs.key) + AsyncResetReg(io.regs.key.write.bits === WatchdogTimer.key && !writeAny, io.regs.key.write.valid || writeAny)(0) + } + protected lazy val feed = { + val food = 0xD09F00D + unlocked && io.regs.feed.write.valid && io.regs.feed.write.bits === food + } + + // The Scala Type-Chekcher seems to have a bug and I get a null pointer during the Scala compilation + // if I don't do this temporary assignment. + val tmpStickyDesc = RegFieldDesc("wdogrsten", "Controls whether the comparator output can set the wdogrst bit and hence cause a full reset.", + reset = Some(0)) + + override protected lazy val cfg_desc = DefaultGenericTimerCfgDescs("wdog", ncmp).copy( + sticky = tmpStickyDesc, + deglitch = RegFieldDesc.reserved, + running = RegFieldDesc("wdogcoreawake", "Increment the watchdog counter if the processor is not asleep", reset=Some(0)), + center = Seq.fill(ncmp){RegFieldDesc.reserved}, + extra = Seq.fill(ncmp){RegFieldDesc.reserved}, + gang = Seq.fill(ncmp){RegFieldDesc.reserved} + ) + + lazy val io = IO(new GenericTimerIO(regWidth, ncmp, maxcmp, scaleWidth, countWidth, cmpWidth) { + val corerst = Bool(INPUT) + val rst = Bool(OUTPUT) + } + ) + io.rst := AsyncResetReg(Bool(true), rsten && elapsed(0)) +} diff --git a/sifive-blocks/src/main/scala/devices/msi/MSIMaster.scala b/sifive-blocks/src/main/scala/devices/msi/MSIMaster.scala new file mode 100644 index 00000000..658d7f98 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/msi/MSIMaster.scala @@ -0,0 +1,79 @@ +// See LICENSE for license details. + +package sifive.blocks.devices.msi + +import Chisel._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util.leftOR + +case class MSITarget(address: BigInt, spacing: Int, number: Int) +{ + require (number >= 0) + require (address >= 0) +} + +class MSIMaster(targets: Seq[MSITarget])(implicit p: Parameters) extends LazyModule +{ + val masterNode = TLClientNode(Seq(TLClientPortParameters(Seq(TLClientParameters("MSI Master", sourceId = IdRange(0,2)))))) + + // A terminal interrupt node of flexible number + val intNode = IntNexusNode( + sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(1, Nil))) }, + sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) }, + inputRequiresOutput = false) + + lazy val module = new LazyModuleImp(this) { + val (io, masterEdge) = masterNode.out(0) + val interrupts = intNode.in.flatMap { case (i, e) => i.take(e.source.num) } + + // Construct a map of the addresses to update for interrupts + val targetMap = targets.flatMap { case MSITarget(address, spacing, number) => + address until (address+spacing*number) by spacing + } .map { addr => + val m = masterEdge.manager.find(addr) + require (m.isDefined, s"MSIMaster ${name} was pointed at address 0x${addr}%x which does not exist") + require (m.get.supportsPutFull.contains(1), s"MSIMaster ${name} requires device ${m.get.name} supportPutFull of 1 byte (${m.get.supportsPutFull})") + UInt(addr) + }.take(interrupts.size max 1) + + require (interrupts.size <= targetMap.size, s"MSIMaster ${name} has more interrupts (${interrupts.size}) than addresses to use (${targetMap.size})") + require (intNode.out.isEmpty, s"MSIMaster ${name} intNode is not a source!") + + val busy = RegInit(Bool(false)) + val remote = RegInit(UInt(0, width=interrupts.size max 1)) + val local = if (interrupts.isEmpty) UInt(0) else Cat(interrupts.reverse) + val pending = remote ^ local + val select = ~(leftOR(pending) << 1) & pending + val address = Mux1H(select, targetMap) + val lowBits = log2Ceil(masterEdge.manager.beatBytes) + val shift = if (lowBits > 0) address(lowBits-1, 0) else UInt(0) + val data = (select & local).orR + + io.a.valid := pending.orR && !busy + io.a.bits := masterEdge.Put( + fromSource = UInt(0), + toAddress = address, + lgSize = UInt(0), + data = data << (shift << 3))._2 + + // When A is sent, toggle our model of the remote state + when (io.a.fire()) { + remote := remote ^ select + busy := Bool(true) + } + + // Sink D messages to clear busy + io.d.ready := Bool(true) + when (io.d.fire()) { + busy := Bool(false) + } + + // Tie off unused channels + io.b.ready := Bool(false) + io.c.valid := Bool(false) + io.e.valid := Bool(false) + } +} diff --git a/sifive-blocks/src/main/scala/devices/pinctrl/PinCtrl.scala b/sifive-blocks/src/main/scala/devices/pinctrl/PinCtrl.scala new file mode 100644 index 00000000..aadb4e75 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/pinctrl/PinCtrl.scala @@ -0,0 +1,110 @@ +//See LICENSE for license details + +package sifive.blocks.devices.pinctrl + +import Chisel._ + +// This is the base class of things you "always" +// want to control from a HW block. +class PinCtrl extends Bundle { + val oval = Bool() + val oe = Bool() + val ie = Bool() +} + +// Package up the inputs and outputs +// for the Pin +abstract class Pin extends Bundle { + val i = new Bundle { + val ival = Bool(INPUT) + } + val o: PinCtrl + + // Must be defined by the subclasses + def default(): Unit + def inputPin(pue: Bool = Bool(false)): Bool + def outputPin(signal: Bool, + pue: Bool = Bool(false), + ds: Bool = Bool(false), + ie: Bool = Bool(false) + ): Unit + +} + + +//////////////////////////////////////////////////////////////////////////////////// + +class BasePin extends Pin() { + val o = new PinCtrl().asOutput + + def default(): Unit = { + this.o.oval := Bool(false) + this.o.oe := Bool(false) + this.o.ie := Bool(false) + } + + def inputPin(pue: Bool = Bool(false) /*ignored*/): Bool = { + this.o.oval := Bool(false) + this.o.oe := Bool(false) + this.o.ie := Bool(true) + this.i.ival + } + + def outputPin(signal: Bool, + pue: Bool = Bool(false), /*ignored*/ + ds: Bool = Bool(false), /*ignored*/ + ie: Bool = Bool(false) + ): Unit = { + this.o.oval := signal + this.o.oe := Bool(true) + this.o.ie := ie + } +} + +///////////////////////////////////////////////////////////////////////// +class EnhancedPinCtrl extends PinCtrl { + val pue = Bool() + val ds = Bool() +} + +class EnhancedPin extends Pin() { + + val o = new EnhancedPinCtrl().asOutput + + def default(): Unit = { + this.o.oval := Bool(false) + this.o.oe := Bool(false) + this.o.ie := Bool(false) + this.o.ds := Bool(false) + this.o.pue := Bool(false) + } + + def inputPin(pue: Bool = Bool(false)): Bool = { + this.o.oval := Bool(false) + this.o.oe := Bool(false) + this.o.pue := pue + this.o.ds := Bool(false) + this.o.ie := Bool(true) + + this.i.ival + } + + def outputPin(signal: Bool, + pue: Bool = Bool(false), + ds: Bool = Bool(false), + ie: Bool = Bool(false) + ): Unit = { + this.o.oval := signal + this.o.oe := Bool(true) + this.o.pue := pue + this.o.ds := ds + this.o.ie := ie + } + + def toBasePin(): BasePin = { + + val base_pin = Wire(new BasePin()) + base_pin <> this + base_pin + } +} diff --git a/sifive-blocks/src/main/scala/devices/pwm/PWM.scala b/sifive-blocks/src/main/scala/devices/pwm/PWM.scala new file mode 100644 index 00000000..ea5719c5 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/pwm/PWM.scala @@ -0,0 +1,128 @@ +// See LICENSE for license details. +package sifive.blocks.devices.pwm + +import Chisel._ +import Chisel.ImplicitConversions._ +import chisel3.experimental.MultiIOModule +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ +import sifive.blocks.util.{GenericTimer, GenericTimerIO, DefaultGenericTimerCfgDescs} + +// Core PWM Functionality & Register Interface +class PWMTimer(val ncmp: Int = 4, val cmpWidth: Int = 16) extends MultiIOModule with GenericTimer { + + def orR(v: Vec[Bool]): Bool = v.foldLeft(Bool(false))( _||_ ) + + protected def prefix = "pwm" + protected def countWidth = ((1 << scaleWidth) - 1) + cmpWidth + protected lazy val countAlways = RegEnable(io.regs.cfg.write.countAlways, Bool(false), io.regs.cfg.write_countAlways && unlocked) + protected lazy val feed = count.carryOut(scale + UInt(cmpWidth)) + protected lazy val countEn = Wire(Bool()) + override protected lazy val oneShot = RegEnable(io.regs.cfg.write.running && !countReset, Bool(false), (io.regs.cfg.write_running && unlocked) || countReset) + override protected lazy val extra: Vec[Bool] = RegEnable(io.regs.cfg.write.extra, init = Vec.fill(maxcmp){false.B}, orR(io.regs.cfg.write_extra) && unlocked) + override protected lazy val center: Vec[Bool] = RegEnable(io.regs.cfg.write.center, orR(io.regs.cfg.write_center) && unlocked) + override protected lazy val gang: Vec[Bool] = RegEnable(io.regs.cfg.write.gang, orR(io.regs.cfg.write_gang) && unlocked) + override protected lazy val deglitch = RegEnable(io.regs.cfg.write.deglitch, io.regs.cfg.write_deglitch && unlocked)(0) + override protected lazy val sticky = RegEnable(io.regs.cfg.write.sticky, io.regs.cfg.write_sticky && unlocked)(0) + override protected lazy val ip = { + val doSticky = Reg(next = (deglitch && !countReset) || sticky) + val sel = (0 until ncmp).map(i => s(cmpWidth-1) && center(i)) + val reg = Reg(Vec(ncmp, Bool())) + reg := (sel & elapsed) | (~sel & (elapsed | (Vec.fill(ncmp){doSticky} & reg))) + when (orR(io.regs.cfg.write_ip) && unlocked) { reg := io.regs.cfg.write_ip } + reg + } + + override protected lazy val feed_desc = RegFieldDesc.reserved + override protected lazy val key_desc = RegFieldDesc.reserved + override protected lazy val cfg_desc = DefaultGenericTimerCfgDescs("pwm", ncmp).copy( + extra = Seq.tabulate(ncmp){ i => RegFieldDesc(s"pwminvert${i}", s"Invert Comparator ${i} Output", reset = Some(0))} + ) + + lazy val io = IO(new GenericTimerIO(regWidth, ncmp, maxcmp, scaleWidth, countWidth, cmpWidth) { + val gpio = Vec(ncmp, Bool()).asOutput + }) + + val invert = extra.asUInt + + val ipU = ip.asUInt + val gangU = gang.asUInt + + io.gpio := io.gpio.fromBits((ipU & ~(gangU & Cat(ipU(0), ipU >> 1))) ^ invert) + countEn := countAlways || oneShot +} + +case class PWMParams( + address: BigInt, + size: Int = 0x1000, + regBytes: Int = 4, + ncmp: Int = 4, + cmpWidth: Int = 16) + +class PWMPortIO(val c: PWMParams) extends Bundle { + val gpio = Vec(c.ncmp, Bool()).asOutput +} + +abstract class PWM(busWidthBytes: Int, val params: PWMParams)(implicit p: Parameters) + extends IORegisterRouter( + RegisterRouterParams( + name = "pwm", + compat = Seq("sifive,pwm0"), + base = params.address, + size = params.size, + beatBytes = busWidthBytes), + new PWMPortIO(params)) + with HasInterruptSources { + + def nInterrupts = params.ncmp + + lazy val module = new LazyModuleImp(this) { + val pwm = Module(new PWMTimer(params.ncmp, params.cmpWidth)) + interrupts := pwm.io.ip + port.gpio := pwm.io.gpio + regmap((GenericTimer.timerRegMap(pwm, 0, params.regBytes)):_*) + } +} + +class TLPWM(busWidthBytes: Int, params: PWMParams)(implicit p: Parameters) + extends PWM(busWidthBytes, params) with HasTLControlRegMap + +case class PWMAttachParams( + pwm: PWMParams, + controlBus: TLBusWrapper, + intNode: IntInwardNode, + mclock: Option[ModuleValue[Clock]] = None, + mreset: Option[ModuleValue[Bool]] = None, + controlXType: ClockCrossingType = NoCrossing, + intXType: ClockCrossingType = NoCrossing) + (implicit val p: Parameters) + +object PWM { + val nextId = { var i = -1; () => { i += 1; i} } + + def attach(params: PWMAttachParams): TLPWM = { + implicit val p = params.p + val name = s"pwm_${nextId()}" + val cbus = params.controlBus + val pwm = LazyModule(new TLPWM(cbus.beatBytes, params.pwm)) + pwm.suggestName(name) + cbus.coupleTo(s"device_named_$name") { + pwm.controlXing(params.controlXType) := TLFragmenter(cbus.beatBytes, cbus.blockBytes) := _ + } + params.intNode := pwm.intXing(params.intXType) + InModuleBody { pwm.module.clock := params.mclock.map(_.getWrappedValue).getOrElse(cbus.module.clock) } + InModuleBody { pwm.module.reset := params.mreset.map(_.getWrappedValue).getOrElse(cbus.module.reset) } + + pwm + } + + def attachAndMakePort(params: PWMAttachParams): ModuleValue[PWMPortIO] = { + val pwm = attach(params) + val pwmNode = pwm.ioNode.makeSink()(params.p) + InModuleBody { pwmNode.makeIO()(ValName(pwm.name)) } + } +} diff --git a/sifive-blocks/src/main/scala/devices/pwm/PWMPeriphery.scala b/sifive-blocks/src/main/scala/devices/pwm/PWMPeriphery.scala new file mode 100644 index 00000000..a08d793b --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/pwm/PWMPeriphery.scala @@ -0,0 +1,22 @@ +// See LICENSE for license details. +package sifive.blocks.devices.pwm + +import Chisel._ +import freechips.rocketchip.config.Field +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.subsystem.BaseSubsystem + +case object PeripheryPWMKey extends Field[Seq[PWMParams]] + +trait HasPeripheryPWM { this: BaseSubsystem => + val pwmNodes = p(PeripheryPWMKey).map { ps => PWM.attach(PWMAttachParams(ps, pbus, ibus.fromAsync)).ioNode.makeSink } +} + +trait HasPeripheryPWMBundle { + val pwm: Seq[PWMPortIO] +} + +trait HasPeripheryPWMModuleImp extends LazyModuleImp with HasPeripheryPWMBundle { + val outer: HasPeripheryPWM + val pwm = outer.pwmNodes.zipWithIndex.map { case(n,i) => n.makeIO()(ValName(s"pwm_$i")) } +} diff --git a/sifive-blocks/src/main/scala/devices/pwm/PWMPins.scala b/sifive-blocks/src/main/scala/devices/pwm/PWMPins.scala new file mode 100644 index 00000000..4038e8bf --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/pwm/PWMPins.scala @@ -0,0 +1,28 @@ +// See LICENSE for license details. +package sifive.blocks.devices.pwm + +import Chisel._ +import chisel3.experimental.{withClockAndReset} +import sifive.blocks.devices.pinctrl.{Pin} + +class PWMSignals[T <: Data](private val pingen: () => T, val c: PWMParams) extends Bundle { + val pwm: Vec[T] = Vec(c.ncmp, pingen()) +} + +class PWMPins[T <: Pin](pingen: () => T, c: PWMParams) extends PWMSignals[T](pingen, c) + +object PWMPinsFromPort { + def apply[T <: Pin] (pins: PWMSignals[T], port: PWMPortIO, clock: Clock, reset: Bool): Unit = { + withClockAndReset(clock, reset){ + (pins.pwm zip port.gpio) foreach { case (pin, port) => + pin.outputPin(port) + } + } + } + + def apply[T <: Pin] (pins: PWMSignals[T], port: PWMPortIO): Unit = { + (pins.pwm zip port.gpio) foreach { case (pin, port) => + pin.outputPin(port) + } + } +} diff --git a/sifive-blocks/src/main/scala/devices/spi/BlackBoxDelayBuffer.scala b/sifive-blocks/src/main/scala/devices/spi/BlackBoxDelayBuffer.scala new file mode 100644 index 00000000..2b2a316a --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/BlackBoxDelayBuffer.scala @@ -0,0 +1,14 @@ +package sifive.blocks.devices.spi + +import Chisel._ +import freechips.rocketchip.util.ShiftRegInit +import chisel3.experimental._ + +class BlackBoxDelayBuffer extends BlackBox { + val io = IO(new Bundle() { + val in = UInt(INPUT,1.W) + val sel = UInt(INPUT,5.W) + val out = UInt(OUTPUT, 1.W) + val mux_out = UInt(OUTPUT, 1.W) + }) +} diff --git a/sifive-blocks/src/main/scala/devices/spi/SPI.scala b/sifive-blocks/src/main/scala/devices/spi/SPI.scala new file mode 100644 index 00000000..31baf651 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/SPI.scala @@ -0,0 +1,101 @@ +// See LICENSE for license details. +package sifive.blocks.devices.spi + +import Chisel._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.tilelink._ + +case class SPIAttachParams( + spi: SPIParams, + controlBus: TLBusWrapper, + intNode: IntInwardNode, + controlXType: ClockCrossingType = NoCrossing, + intXType: ClockCrossingType = NoCrossing, + mclock: Option[ModuleValue[Clock]] = None, + mreset: Option[ModuleValue[Bool]] = None) + (implicit val p: Parameters) + +case class SPIFlashAttachParams( + spi: SPIFlashParams, + controlBus: TLBusWrapper, + memBus: TLBusWrapper, + intNode: IntInwardNode, + fBufferDepth: Int = 0, + controlXType: ClockCrossingType = NoCrossing, + intXType: ClockCrossingType = NoCrossing, + memXType: ClockCrossingType = NoCrossing, + mclock: Option[ModuleValue[Clock]] = None, + mreset: Option[ModuleValue[Bool]] = None) + (implicit val p: Parameters) + +object SPI { + val nextId = { var i = -1; () => { i += 1; i} } + def attach(params: SPIAttachParams): TLSPI = { + implicit val p = params.p + val name = s"spi_${nextId()}" + val cbus = params.controlBus + val spi = LazyModule(new TLSPI(cbus.beatBytes, params.spi)) + spi.suggestName(name) + + cbus.coupleTo(s"device_named_$name") { + spi.controlXing(params.controlXType) := TLFragmenter(cbus.beatBytes, cbus.blockBytes) := _ + } + + params.intNode := spi.intXing(params.intXType) + + InModuleBody { spi.module.clock := params.mclock.map(_.getWrappedValue).getOrElse(cbus.module.clock) } + InModuleBody { spi.module.reset := params.mreset.map(_.getWrappedValue).getOrElse(cbus.module.reset) } + + spi + } + + def attachAndMakePort(params: SPIAttachParams): ModuleValue[SPIPortIO] = { + val spi = attach(params) + val spiNode = spi.ioNode.makeSink()(params.p) + InModuleBody { spiNode.makeIO()(ValName(spi.name)) } + } + + val nextFlashId = { var i = -1; () => { i += 1; i} } + def attachFlash(params: SPIFlashAttachParams): TLSPIFlash = { + implicit val p = params.p + val name = s"qspi_${nextFlashId()}" // TODO should these be shared with regular SPIs? + val cbus = params.controlBus + val mbus = params.memBus + val qspi = LazyModule(new TLSPIFlash(cbus.beatBytes, params.spi)) + qspi.suggestName(name) + + cbus.coupleTo(s"device_named_$name") { + qspi.controlXing(params.controlXType) := TLFragmenter(cbus.beatBytes, cbus.blockBytes) := _ + } + + mbus.coupleTo(s"mem_named_$name") { + (qspi.memXing(params.memXType) + := TLFragmenter(1, mbus.blockBytes) + := TLBuffer(BufferParams(params.fBufferDepth), BufferParams.none) + := TLWidthWidget(mbus.beatBytes) + := _) + } + + params.intNode := qspi.intXing(params.intXType) + + InModuleBody { qspi.module.clock := params.mclock.map(_.getWrappedValue).getOrElse(cbus.module.clock) } + InModuleBody { qspi.module.reset := params.mreset.map(_.getWrappedValue).getOrElse(cbus.module.reset) } + + qspi + } + + def attachAndMakePort(params: SPIFlashAttachParams): ModuleValue[SPIPortIO] = { + val qspi = attachFlash(params) + val qspiNode = qspi.ioNode.makeSink()(params.p) + InModuleBody { qspiNode.makeIO()(ValName(qspi.name)) } + } + + def connectPort(q: SPIPortIO): SPIPortIO = { + val x = Wire(new SPIPortIO(q.c)) + x <> q + x + } +} diff --git a/sifive-blocks/src/main/scala/devices/spi/SPIArbiter.scala b/sifive-blocks/src/main/scala/devices/spi/SPIArbiter.scala new file mode 100644 index 00000000..3c0c74a4 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/SPIArbiter.scala @@ -0,0 +1,42 @@ +// See LICENSE for license details. +package sifive.blocks.devices.spi + +import Chisel._ + +class SPIInnerIO(c: SPIParamsBase) extends SPILinkIO(c) { + val lock = Bool(OUTPUT) +} + +class SPIArbiter(c: SPIParamsBase, n: Int) extends Module { + val io = new Bundle { + val inner = Vec(n, new SPIInnerIO(c)).flip + val outer = new SPILinkIO(c) + val sel = UInt(INPUT, log2Up(n)) + } + + val sel = Reg(init = Vec(Bool(true) +: Seq.fill(n-1)(Bool(false)))) + + io.outer.tx.valid := Mux1H(sel, io.inner.map(_.tx.valid)) + io.outer.tx.bits := Mux1H(sel, io.inner.map(_.tx.bits)) + io.outer.cnt := Mux1H(sel, io.inner.map(_.cnt)) + io.outer.fmt := Mux1H(sel, io.inner.map(_.fmt)) + // Workaround for overzealous combinational loop detection + io.outer.cs := Mux(sel(0), io.inner(0).cs, io.inner(1).cs) + require(n == 2, "SPIArbiter currently only supports 2 clients") + + (io.inner zip sel).foreach { case (inner, s) => + inner.tx.ready := io.outer.tx.ready && s + inner.rx.valid := io.outer.rx.valid && s + inner.rx.bits := io.outer.rx.bits + inner.active := io.outer.active && s + } + + val nsel = Vec.tabulate(n)(io.sel === UInt(_)) + val lock = Mux1H(sel, io.inner.map(_.lock)) + when (!lock) { + sel := nsel + when (sel.asUInt =/= nsel.asUInt) { + io.outer.cs.clear := Bool(true) + } + } +} diff --git a/sifive-blocks/src/main/scala/devices/spi/SPIBundle.scala b/sifive-blocks/src/main/scala/devices/spi/SPIBundle.scala new file mode 100644 index 00000000..f536f7e8 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/SPIBundle.scala @@ -0,0 +1,108 @@ +// See LICENSE for license details. +package sifive.blocks.devices.spi + +import Chisel._ + +abstract class SPIBundle(val c: SPIParamsBase) extends Bundle + +class SPIDataIO extends Bundle { + val i = Bool(INPUT) + val o = Bool(OUTPUT) + val oe = Bool(OUTPUT) +} + +class SPIPortIO(c: SPIParamsBase) extends SPIBundle(c) { + val sck = Bool(OUTPUT) + val dq = Vec(4, new SPIDataIO) + val cs = Vec(c.csWidth, Bool(OUTPUT)) +} + +trait HasSPIProtocol { + val proto = Bits(width = SPIProtocol.width) +} +trait HasSPIEndian { + val endian = Bits(width = SPIEndian.width) +} +class SPIFormat(c: SPIParamsBase) extends SPIBundle(c) + with HasSPIProtocol + with HasSPIEndian { + val iodir = Bits(width = SPIDirection.width) +} + +trait HasSPILength extends SPIBundle { + val len = UInt(width = c.lengthBits) +} + +class SPIClocking(c: SPIParamsBase) extends SPIBundle(c) { + val div = UInt(width = c.divisorBits) + val pol = Bool() + val pha = Bool() +} + +class SPIChipSelect(c: SPIParamsBase) extends SPIBundle(c) { + val id = UInt(width = c.csIdBits) + val dflt = Vec(c.csWidth, Bool()) + + def toggle(en: Bool): Vec[Bool] = { + val mask = en << id + val out = Cat(dflt.reverse) ^ mask + Vec.tabulate(c.csWidth)(out(_)) + } +} + +trait HasSPICSMode { + val mode = Bits(width = SPICSMode.width) +} + +class SPIDelay(c: SPIParamsBase) extends SPIBundle(c) { + val cssck = UInt(width = c.delayBits) + val sckcs = UInt(width = c.delayBits) + val intercs = UInt(width = c.delayBits) + val interxfr = UInt(width = c.delayBits) +} + +class SPIWatermark(c: SPIParamsBase) extends SPIBundle(c) { + val tx = UInt(width = c.txDepthBits) + val rx = UInt(width = c.rxDepthBits) +} + +class SPIControl(c: SPIParamsBase) extends SPIBundle(c) { + val fmt = new SPIFormat(c) with HasSPILength + val sck = new SPIClocking(c) + val cs = new SPIChipSelect(c) with HasSPICSMode + val dla = new SPIDelay(c) + val wm = new SPIWatermark(c) + val extradel = new SPIExtraDelay(c) + val sampledel = new SPISampleDelay(c) +} + +object SPIControl { + def init(c: SPIParamsBase): SPIControl = { + val ctrl = Wire(new SPIControl(c)) + ctrl.fmt.proto := SPIProtocol.Single + ctrl.fmt.iodir := SPIDirection.Rx + ctrl.fmt.endian := SPIEndian.MSB + ctrl.fmt.len := UInt(math.min(c.frameBits, 8)) + ctrl.sck.div := UInt(3) + ctrl.sck.pol := Bool(false) + ctrl.sck.pha := Bool(false) + ctrl.cs.id := UInt(0) + ctrl.cs.dflt.foreach { _ := Bool(true) } + ctrl.cs.mode := SPICSMode.Auto + ctrl.dla.cssck := UInt(1) + ctrl.dla.sckcs := UInt(1) + ctrl.dla.intercs := UInt(1) + ctrl.dla.interxfr := UInt(0) + ctrl.wm.tx := UInt(0) + ctrl.wm.rx := UInt(0) + ctrl.extradel.coarse := UInt(0) + ctrl.extradel.fine := UInt(0) + ctrl.sampledel.sd := UInt(c.defaultSampleDel) + ctrl + } +} + +class SPIInterrupts extends Bundle { + val txwm = Bool() + val rxwm = Bool() +} diff --git a/sifive-blocks/src/main/scala/devices/spi/SPIConsts.scala b/sifive-blocks/src/main/scala/devices/spi/SPIConsts.scala new file mode 100644 index 00000000..5d6dd0d1 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/SPIConsts.scala @@ -0,0 +1,33 @@ +// See LICENSE for license details. +package sifive.blocks.devices.spi + +import Chisel._ + +object SPIProtocol { + val width = 2 + def Single = UInt(0, width) + def Dual = UInt(1, width) + def Quad = UInt(2, width) + + def cases = Seq(Single, Dual, Quad) + def decode(x: UInt): Seq[Bool] = cases.map(_ === x) +} + +object SPIDirection { + val width = 1 + def Rx = UInt(0, width) + def Tx = UInt(1, width) +} + +object SPIEndian { + val width = 1 + def MSB = UInt(0, width) + def LSB = UInt(1, width) +} + +object SPICSMode { + val width = 2 + def Auto = UInt(0, width) + def Hold = UInt(2, width) + def Off = UInt(3, width) +} diff --git a/sifive-blocks/src/main/scala/devices/spi/SPIFIFO.scala b/sifive-blocks/src/main/scala/devices/spi/SPIFIFO.scala new file mode 100644 index 00000000..5bc6e823 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/SPIFIFO.scala @@ -0,0 +1,62 @@ +// See LICENSE for license details. +package sifive.blocks.devices.spi + +import Chisel._ + +class SPIFIFOControl(c: SPIParamsBase) extends SPIBundle(c) { + val fmt = new SPIFormat(c) with HasSPILength + val cs = new Bundle with HasSPICSMode + val wm = new SPIWatermark(c) +} + +class SPIFIFO(c: SPIParamsBase) extends Module { + val io = new Bundle { + val ctrl = new SPIFIFOControl(c).asInput + val link = new SPIInnerIO(c) + val tx = Decoupled(Bits(width = c.frameBits)).flip + val rx = Decoupled(Bits(width = c.frameBits)) + val ip = new SPIInterrupts().asOutput + } + + val txq = Module(new Queue(io.tx.bits, c.txDepth)) + val rxq = Module(new Queue(io.rx.bits, c.rxDepth)) + + txq.io.enq <> io.tx + io.link.tx <> txq.io.deq + + val fire_tx = io.link.tx.fire() + val fire_rx = io.link.rx.fire() + val rxen = Reg(init = Bool(false)) + + rxq.io.enq.valid := io.link.rx.valid && rxen + rxq.io.enq.bits := io.link.rx.bits + io.rx <> rxq.io.deq + + when (fire_rx) { + rxen := Bool(false) + } + when (fire_tx) { + rxen := (io.link.fmt.iodir === SPIDirection.Rx) + } + + val proto = SPIProtocol.decode(io.link.fmt.proto).zipWithIndex + val cnt_quot = Mux1H(proto.map { case (s, i) => s -> (io.ctrl.fmt.len >> i) }) + val cnt_rmdr = Mux1H(proto.map { case (s, i) => s -> (if (i > 0) io.ctrl.fmt.len(i-1, 0).orR else UInt(0)) }) + io.link.fmt <> io.ctrl.fmt + io.link.cnt := cnt_quot + cnt_rmdr + + val cs_mode = RegNext(io.ctrl.cs.mode, SPICSMode.Auto) + val cs_mode_hold = (cs_mode === SPICSMode.Hold) + val cs_mode_off = (cs_mode === SPICSMode.Off) + val cs_update = (cs_mode =/= io.ctrl.cs.mode) + val cs_clear = !(cs_mode_hold || cs_mode_off) + + io.link.cs.set := !cs_mode_off + io.link.cs.clear := cs_update || (fire_tx && cs_clear) + io.link.cs.hold := Bool(false) + + io.link.lock := io.link.tx.valid || rxen + + io.ip.txwm := (txq.io.count < io.ctrl.wm.tx) + io.ip.rxwm := (rxq.io.count > io.ctrl.wm.rx) +} diff --git a/sifive-blocks/src/main/scala/devices/spi/SPIFlash.scala b/sifive-blocks/src/main/scala/devices/spi/SPIFlash.scala new file mode 100644 index 00000000..17144b86 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/SPIFlash.scala @@ -0,0 +1,171 @@ +// See LICENSE for license details. +package sifive.blocks.devices.spi + +import Chisel._ + +class SPIFlashInsn(c: SPIFlashParamsBase) extends SPIBundle(c) { + val cmd = new Bundle with HasSPIProtocol { + val code = Bits(width = c.insnCmdBits) + val en = Bool() + } + val addr = new Bundle with HasSPIProtocol { + val len = UInt(width = c.insnAddrLenBits) + } + val pad = new Bundle { + val code = Bits(width = c.frameBits) + val cnt = Bits(width = c.insnPadLenBits) + } + val data = new Bundle with HasSPIProtocol +} + +class SPIFlashControl(c: SPIFlashParamsBase) extends SPIBundle(c) { + val insn = new SPIFlashInsn(c) + val fmt = new Bundle with HasSPIEndian +} + +object SPIFlashInsn { + def init(c: SPIFlashParamsBase): SPIFlashInsn = { + val insn = Wire(new SPIFlashInsn(c)) + insn.cmd.en := Bool(true) + insn.cmd.code := Bits(0x03) + insn.cmd.proto := SPIProtocol.Single + insn.addr.len := UInt(3) + insn.addr.proto := SPIProtocol.Single + insn.pad.cnt := UInt(0) + insn.pad.code := Bits(0) + insn.data.proto := SPIProtocol.Single + insn + } +} + +class SPIFlashAddr(c: SPIFlashParamsBase) extends SPIBundle(c) { + val next = UInt(width = c.insnAddrBits) + val hold = UInt(width = c.insnAddrBits) +} + +class SPIFlashMap(c: SPIFlashParamsBase) extends Module { + val io = new Bundle { + val en = Bool(INPUT) + val ctrl = new SPIFlashControl(c).asInput + val addr = Decoupled(new SPIFlashAddr(c)).flip + val data = Decoupled(UInt(width = c.frameBits)) + val link = new SPIInnerIO(c) + } + + val addr = io.addr.bits.hold + UInt(1) + val merge = io.link.active && (io.addr.bits.next === addr) + + private val insn = io.ctrl.insn + io.link.tx.valid := Bool(true) + io.link.fmt.proto := insn.addr.proto + io.link.fmt.iodir := SPIDirection.Tx + io.link.fmt.endian := io.ctrl.fmt.endian + io.link.cnt := Mux1H( + SPIProtocol.decode(io.link.fmt.proto).zipWithIndex.map { + case (s, i) => (s -> UInt(c.frameBits >> i)) + }) + io.link.cs.set := Bool(true) + io.link.cs.clear := Bool(false) + io.link.cs.hold := Bool(true) + io.link.lock := Bool(true) + + io.addr.ready := Bool(false) + io.data.valid := Bool(false) + io.data.bits := io.link.rx.bits + + val cnt = Reg(UInt(width = math.max(c.insnPadLenBits, c.insnAddrLenBits))) + val cnt_en = Wire(init = Bool(false)) + val cnt_cmp = (0 to c.insnAddrBytes).map(cnt === UInt(_)) + val cnt_zero = cnt_cmp(0) + val cnt_last = cnt_cmp(1) && io.link.tx.ready + val cnt_done = cnt_last || cnt_zero + when (cnt_en) { + io.link.tx.valid := !cnt_zero + when (io.link.tx.fire()) { + cnt := cnt - UInt(1) + } + } + + val (s_idle :: s_cmd :: s_addr :: s_pad :: s_data_pre :: s_data_post :: s_off :: Nil) = Enum(UInt(), 7) + val state = Reg(init = s_idle) + + switch (state) { + is (s_idle) { + io.link.tx.valid := Bool(false) + when (io.en) { + io.addr.ready := Bool(true) + when (io.addr.valid) { + when (merge) { + state := s_data_pre + } .otherwise { + state := Mux(insn.cmd.en, s_cmd, s_addr) + io.link.cs.clear := Bool(true) + } + } .otherwise { + io.link.lock := Bool(false) + } + } .otherwise { + io.addr.ready := Bool(true) + io.link.lock := Bool(false) + when (io.addr.valid) { + state := s_off + } + } + } + + is (s_cmd) { + io.link.fmt.proto := insn.cmd.proto + io.link.tx.bits := insn.cmd.code + when (io.link.tx.ready) { + state := s_addr + cnt := insn.addr.len + } + } + + is (s_addr) { + io.link.tx.bits := Mux1H(cnt_cmp.tail.zipWithIndex.map { + case (s, i) => + val n = i * c.frameBits + val m = n + (c.frameBits - 1) + s -> io.addr.bits.hold(m, n) + }) + + cnt_en := Bool(true) + when (cnt_done) { + state := s_pad + } + } + + is (s_pad) { + io.link.cnt := insn.pad.cnt + io.link.tx.bits := insn.pad.code + when (io.link.tx.ready) { + state := s_data_pre + } + } + + is (s_data_pre) { + io.link.fmt.proto := insn.data.proto + io.link.fmt.iodir := SPIDirection.Rx + when (io.link.tx.ready) { + state := s_data_post + } + } + + is (s_data_post) { + io.link.tx.valid := Bool(false) + io.data.valid := io.link.rx.valid + when (io.data.fire()) { + state := s_idle + } + } + + is (s_off) { + io.data.valid := Bool(true) + io.data.bits := UInt(0) + when (io.data.ready) { + state := s_idle + } + } + } +} diff --git a/sifive-blocks/src/main/scala/devices/spi/SPIMedia.scala b/sifive-blocks/src/main/scala/devices/spi/SPIMedia.scala new file mode 100644 index 00000000..f8e8672c --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/SPIMedia.scala @@ -0,0 +1,125 @@ +// See LICENSE for license details. +package sifive.blocks.devices.spi + +import Chisel._ + +class SPILinkIO(c: SPIParamsBase) extends SPIBundle(c) { + val tx = Decoupled(Bits(width = c.frameBits)) + val rx = Valid(Bits(width = c.frameBits)).flip + + val cnt = UInt(OUTPUT, c.countBits) + val fmt = new SPIFormat(c).asOutput + val cs = new Bundle { + val set = Bool(OUTPUT) + val clear = Bool(OUTPUT) // Deactivate CS + val hold = Bool(OUTPUT) // Supress automatic CS deactivation + } + val active = Bool(INPUT) +} + +class SPIMedia(c: SPIParamsBase) extends Module { + val io = new Bundle { + val port = new SPIPortIO(c) + val ctrl = new Bundle { + val sck = new SPIClocking(c).asInput + val dla = new SPIDelay(c).asInput + val cs = new SPIChipSelect(c).asInput + val extradel = new SPIExtraDelay(c).asInput + val sampledel = new SPISampleDelay(c).asInput + } + val link = new SPILinkIO(c).flip + } + + val phy = Module(new SPIPhysical(c)) + phy.io.ctrl.sck := io.ctrl.sck + phy.io.ctrl.fmt := io.link.fmt + phy.io.ctrl.extradel := io.ctrl.extradel + phy.io.ctrl.sampledel := io.ctrl.sampledel + + private val op = phy.io.op + op.valid := Bool(true) + op.bits.fn := SPIMicroOp.Delay + op.bits.stb := Bool(false) + op.bits.cnt := io.link.cnt + op.bits.data := io.link.tx.bits + + val cs = Reg(io.ctrl.cs) + val cs_set = Reg(Bool()) + val cs_active = io.ctrl.cs.toggle(io.link.cs.set) + val cs_update = (cs_active.asUInt =/= cs.dflt.asUInt) + + val clear = Reg(init = Bool(false)) + val cs_assert = Reg(init = Bool(false)) + val cs_deassert = clear || (cs_update && !io.link.cs.hold) + + clear := clear || (io.link.cs.clear && cs_assert) + + val continuous = (io.ctrl.dla.interxfr === UInt(0)) + + io.port.sck := phy.io.port.sck + io.port.dq <> phy.io.port.dq + io.port.cs := cs.dflt + + io.link.rx := phy.io.rx + io.link.tx.ready := Bool(false) + io.link.active := cs_assert + + val (s_main :: s_interxfr :: s_intercs :: Nil) = Enum(UInt(), 3) + val state = Reg(init = s_main) + + switch (state) { + is (s_main) { + when (cs_assert) { + when (cs_deassert) { + op.bits.cnt := io.ctrl.dla.sckcs + when (op.ready) { + state := s_intercs + } + } .otherwise { + op.bits.fn := SPIMicroOp.Transfer + op.bits.stb := Bool(true) + + op.valid := io.link.tx.valid + io.link.tx.ready := op.ready + when (op.fire()) { + state := s_interxfr + } + } + } .elsewhen (io.link.tx.valid) { + // Assert CS + op.bits.cnt := io.ctrl.dla.cssck + when (op.ready) { + cs_assert := Bool(true) + cs_set := io.link.cs.set + cs.dflt := cs_active + } + } .otherwise { + // Idle + op.bits.cnt := UInt(0) + op.bits.stb := Bool(true) + cs := io.ctrl.cs + } + } + + is (s_interxfr) { + // Skip if interxfr delay is zero + op.valid := !continuous + op.bits.cnt := io.ctrl.dla.interxfr + when (op.ready || continuous) { + state := s_main + } + } + + is (s_intercs) { + // Deassert CS + op.bits.cnt := io.ctrl.dla.intercs + op.bits.stb := Bool(true) + cs_assert := Bool(false) + clear := Bool(false) + when (op.ready) { + cs.dflt := cs.toggle(cs_set) + state := s_main + } + } + } +} diff --git a/sifive-blocks/src/main/scala/devices/spi/SPIPeriphery.scala b/sifive-blocks/src/main/scala/devices/spi/SPIPeriphery.scala new file mode 100644 index 00000000..18fb0636 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/SPIPeriphery.scala @@ -0,0 +1,39 @@ +// See LICENSE for license details. +package sifive.blocks.devices.spi + +import Chisel._ +import freechips.rocketchip.config.Field +import freechips.rocketchip.subsystem.{BaseSubsystem} +import freechips.rocketchip.diplomacy._ + +case object PeripherySPIKey extends Field[Seq[SPIParams]] + +trait HasPeripherySPI { this: BaseSubsystem => + val spiNodes = p(PeripherySPIKey).map { ps => SPI.attach(SPIAttachParams(ps, pbus, ibus.fromAsync)).ioNode.makeSink() } +} + +trait HasPeripherySPIBundle { + val spi: Seq[SPIPortIO] +} + +trait HasPeripherySPIModuleImp extends LazyModuleImp with HasPeripherySPIBundle { + val outer: HasPeripherySPI + val spi = outer.spiNodes.zipWithIndex.map { case(n,i) => n.makeIO()(ValName(s"spi_$i")) } +} + +case object PeripherySPIFlashKey extends Field[Seq[SPIFlashParams]] + +trait HasPeripherySPIFlash { this: BaseSubsystem => + val qspiNodes = p(PeripherySPIFlashKey).map { ps => + SPI.attachFlash(SPIFlashAttachParams(ps, pbus, pbus, ibus.fromAsync, fBufferDepth = 8)).ioNode.makeSink() + } +} + +trait HasPeripherySPIFlashBundle { + val qspi: Seq[SPIPortIO] +} + +trait HasPeripherySPIFlashModuleImp extends LazyModuleImp with HasPeripherySPIFlashBundle { + val outer: HasPeripherySPIFlash + val qspi = outer.qspiNodes.zipWithIndex.map { case(n,i) => n.makeIO()(ValName(s"qspi_$i")) } +} diff --git a/sifive-blocks/src/main/scala/devices/spi/SPIPhysical.scala b/sifive-blocks/src/main/scala/devices/spi/SPIPhysical.scala new file mode 100644 index 00000000..44e04335 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/SPIPhysical.scala @@ -0,0 +1,225 @@ +// See LICENSE for license details. +package sifive.blocks.devices.spi + +import Chisel._ +import freechips.rocketchip.util.ShiftRegInit +import chisel3.experimental._ + +class SPIMicroOp(c: SPIParamsBase) extends SPIBundle(c) { + val fn = Bits(width = 1) + val stb = Bool() + val cnt = UInt(width = c.countBits) + val data = Bits(width = c.frameBits) +} + +object SPIMicroOp { + def Transfer = UInt(0, 1) + def Delay = UInt(1, 1) +} + +//Coarse delay is the number of system-clock cycles that can be added +//as a phase difference between sent and received SPI data +//Fine delay is the fine-grain delay that can be added as a phase +//difference between send and received SPI data. +//Fine delay is typically achieved through foundry specific delay buffers +class SPIExtraDelay(c: SPIParamsBase) extends SPIBundle(c) { + val coarse = UInt(width = c.divisorBits) + val fine = UInt(width = c.fineDelayBits) +} +//Sample delay reflects minimum sequential delay that exists between +//a slave and the SPI controller +class SPISampleDelay(c: SPIParamsBase) extends SPIBundle(c) { + val sd = UInt(width = c.sampleDelayBits) +} + +class SPIPhyControl(c: SPIParamsBase) extends SPIBundle(c) { + val sck = new SPIClocking(c) + val fmt = new SPIFormat(c) + val extradel = new SPIExtraDelay (c) + val sampledel = new SPISampleDelay (c) +} + +class SPIPhysical(c: SPIParamsBase) extends Module { + val io = new SPIBundle(c) { + val port = new SPIPortIO(c) + val ctrl = new SPIPhyControl(c).asInput + val op = Decoupled(new SPIMicroOp(c)).flip + val rx = Valid(Bits(width = c.frameBits)) + } + + private val op = io.op.bits + val ctrl = Reg(io.ctrl) + val proto = SPIProtocol.decode(ctrl.fmt.proto) + + val accept = Wire(init = Bool(false)) + val sample = Wire(init = Bool(false)) + val setup = Wire(init = Bool(false)) + val last = Wire(init = Bool(false)) + + val setup_d = Reg(next = setup) + + val scnt = Reg(init = UInt(0, c.countBits)) + val tcnt = Reg(io.ctrl.sck.div) + + val stop = (scnt === UInt(0)) + val beat = (tcnt === UInt(0)) + + //Making a delay counter for 'sample' + val totalCoarseDel = io.ctrl.extradel.coarse + io.ctrl.sampledel.sd + val del_cntr = RegInit(UInt(c.divisorBits.W), (c.defaultSampleDel + 1).U) + val sample_d = RegInit(Bool(false)) + when (beat && sample) { + del_cntr := totalCoarseDel + } + + when (del_cntr =/= 0.U) { + del_cntr := del_cntr - 1.U + } + + when (del_cntr === 1.U) { + sample_d := true.B + }.otherwise { + sample_d := false.B + } + + //Making a delay counter for 'last' + val del_cntr_last = RegInit(UInt(c.divisorBits.W), (c.defaultSampleDel + 1).U) + val last_d = RegInit(Bool(false)) + + when (beat && last) { + del_cntr_last := totalCoarseDel + } + + when (del_cntr_last =/= 0.U) { + del_cntr_last := del_cntr_last - 1.U + } + + when (del_cntr_last === 1.U) { + last_d := true.B + }.otherwise { + last_d := false.B + } + + val decr = Mux(beat, scnt, tcnt) - UInt(1) + val sched = Wire(init = beat) + tcnt := Mux(sched, ctrl.sck.div, decr) + + val sck = Reg(Bool()) + val cref = Reg(init = Bool(true)) + val cinv = ctrl.sck.pha ^ ctrl.sck.pol + + private def convert(data: UInt, fmt: SPIFormat) = + Mux(fmt.endian === SPIEndian.MSB, data, Cat(data.toBools)) + + val rxd = Cat(io.port.dq.reverse.map(_.i)) + val rxd_delayed = Vec(Seq.fill(io.port.dq.size)(false.B)) + + //Adding fine-granularity delay buffers on the received data + if (c.fineDelayBits > 0){ + val fine_grain_delay = Seq.fill(io.port.dq.size) {Module(new BlackBoxDelayBuffer())} + for (j <- 0 to (io.port.dq.size - 1)) { + fine_grain_delay(j).io.in := rxd(j) + fine_grain_delay(j).io.sel := io.ctrl.extradel.fine + rxd_delayed(j) := fine_grain_delay(j).io.mux_out + }} + else { + rxd_delayed := rxd.toBools + } + + val rxd_fin = rxd_delayed.asUInt + val samples = Seq(rxd_fin(1), rxd_fin(1, 0), rxd_fin) + + val buffer = Reg(op.data) + val buffer_in = convert(io.op.bits.data, io.ctrl.fmt) + val shift = Mux ((totalCoarseDel > 0.U), setup_d || (sample_d && stop), sample_d) + buffer := Mux1H(proto, samples.zipWithIndex.map { case (data, i) => + val n = 1 << i + val m = c.frameBits -1 + Cat(Mux(shift, buffer(m-n, 0), buffer(m, n)), + Mux(sample_d, data, buffer(n-1, 0))) + }) + + private def upper(x: UInt, n: Int) = x(c.frameBits-1, c.frameBits-n) + + val txd = Reg(init = Bits(0, io.port.dq.size)) + val txd_in = Mux(accept, upper(buffer_in, 4), upper(buffer, 4)) + val txd_sel = SPIProtocol.decode(Mux(accept, io.ctrl.fmt.proto, ctrl.fmt.proto)) + val txd_shf = (0 until txd_sel.size).map(i => txd_in(3, 4-(1< + dq.o := o + dq.oe := oe + } + io.op.ready := Bool(false) + + val done = Reg(init = Bool(true)) + done := done || last_d + + io.rx.valid := done + io.rx.bits := convert(buffer, ctrl.fmt) + + val xfr = Reg(Bool()) + + when (stop) { + sched := Bool(true) + accept := Bool(true) + } .otherwise { + when (beat) { + cref := !cref + when (xfr) { + sck := cref ^ cinv + sample := cref + setup := !cref + } + when (!cref) { + scnt := decr + } + } + } + + when (scnt === UInt(1)) { + last := beat && cref && xfr // Final sample + when (beat && !cref) { // Final shift + accept := Bool(true) + setup := Bool(false) + sck := ctrl.sck.pol + } + } + + when (accept && done) { + io.op.ready := Bool(true) + when (io.op.valid) { + scnt := op.cnt + when (op.stb) { + ctrl.fmt := io.ctrl.fmt + } + + xfr := Bool(false) + switch (op.fn) { + is (SPIMicroOp.Transfer) { + buffer := buffer_in + sck := cinv + setup := Bool(true) + done := (op.cnt === UInt(0)) + xfr := Bool(true) + } + is (SPIMicroOp.Delay) { + when (op.stb) { + sck := io.ctrl.sck.pol + ctrl.sck := io.ctrl.sck + } + } + } + } + } +} diff --git a/sifive-blocks/src/main/scala/devices/spi/SPIPins.scala b/sifive-blocks/src/main/scala/devices/spi/SPIPins.scala new file mode 100644 index 00000000..ea5cfc50 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/SPIPins.scala @@ -0,0 +1,38 @@ +// See LICENSE for license details. +package sifive.blocks.devices.spi + +import Chisel._ +import chisel3.experimental.{withClockAndReset} +import freechips.rocketchip.util.{SynchronizerShiftReg} +import sifive.blocks.devices.pinctrl.{PinCtrl, Pin} + +class SPISignals[T <: Data](private val pingen: () => T, c: SPIParamsBase) extends SPIBundle(c) { + + val sck = pingen() + val dq = Vec(4, pingen()) + val cs = Vec(c.csWidth, pingen()) +} + +class SPIPins[T <: Pin] (pingen: ()=> T, c: SPIParamsBase) extends SPISignals(pingen, c) + +object SPIPinsFromPort { + + def apply[T <: Pin](pins: SPISignals[T], spi: SPIPortIO, clock: Clock, reset: Bool, + syncStages: Int = 0, driveStrength: Bool = Bool(false)) { + + withClockAndReset(clock, reset) { + pins.sck.outputPin(spi.sck, ds = driveStrength) + + (pins.dq zip spi.dq).zipWithIndex.foreach {case ((p, s), i) => + p.outputPin(s.o, pue = Bool(true), ds = driveStrength) + p.o.oe := s.oe + p.o.ie := ~s.oe + s.i := SynchronizerShiftReg(p.i.ival, syncStages, name = Some(s"spi_dq_${i}_sync")) + } + + (pins.cs zip spi.cs) foreach { case (c, s) => + c.outputPin(s, ds = driveStrength) + } + } + } +} diff --git a/sifive-blocks/src/main/scala/devices/spi/SPIRegs.scala b/sifive-blocks/src/main/scala/devices/spi/SPIRegs.scala new file mode 100644 index 00000000..dfcff2e6 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/SPIRegs.scala @@ -0,0 +1,32 @@ +// See LICENSE for license details. +package sifive.blocks.devices.spi + +object SPICRs { + val sckdiv = 0x00 + val sckmode = 0x04 + val csid = 0x10 + val csdef = 0x14 + val csmode = 0x18 + val dcssck = 0x28 + val dsckcs = 0x2a + val dintercs = 0x2c + val dinterxfr = 0x2e + val extradel = 0x38 + val sampledel = 0x3c + + val fmt = 0x40 + val len = 0x42 + val txfifo = 0x48 + val rxfifo = 0x4c + val txmark = 0x50 + val rxmark = 0x54 + + val insnmode = 0x60 + val insnfmt = 0x64 + val insnproto = 0x65 + val insncmd = 0x66 + val insnpad = 0x67 + + val ie = 0x70 + val ip = 0x74 +} diff --git a/sifive-blocks/src/main/scala/devices/spi/TLSPI.scala b/sifive-blocks/src/main/scala/devices/spi/TLSPI.scala new file mode 100644 index 00000000..5d06b731 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/TLSPI.scala @@ -0,0 +1,192 @@ +// See LICENSE for license details. +package sifive.blocks.devices.spi + +import Chisel._ +import chisel3.experimental._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.util.HeterogeneousBag +import sifive.blocks.util.{NonBlockingEnqueue, NonBlockingDequeue} + +trait SPIParamsBase { + val rAddress: BigInt + val rSize: BigInt + val rxDepth: Int + val txDepth: Int + + val csWidth: Int + val frameBits: Int + val delayBits: Int + val divisorBits: Int + val fineDelayBits: Int + val sampleDelayBits: Int + val defaultSampleDel:Int + + lazy val csIdBits = log2Up(csWidth) + lazy val lengthBits = log2Floor(frameBits) + 1 + lazy val countBits = math.max(lengthBits, delayBits) + + lazy val txDepthBits = log2Floor(txDepth) + 1 + lazy val rxDepthBits = log2Floor(rxDepth) + 1 + +} + +case class SPIParams( + rAddress: BigInt, + rSize: BigInt = 0x1000, + rxDepth: Int = 8, + txDepth: Int = 8, + csWidth: Int = 1, + frameBits: Int = 8, + delayBits: Int = 8, + divisorBits: Int = 12, + fineDelayBits: Int = 0, + sampleDelayBits: Int = 5, + defaultSampleDel: Int = 3 + ) + extends SPIParamsBase { + + require(frameBits >= 4) + require((fineDelayBits == 0) | (fineDelayBits == 5), s"Require fine delay bits to be 0 or 5 and not $fineDelayBits") + require(sampleDelayBits >= 0) + require(defaultSampleDel >= 0) +} + +class SPITopModule(c: SPIParamsBase, outer: TLSPIBase) + extends LazyModuleImp(outer) { + + val ctrl = Reg(init = SPIControl.init(c)) + val fifo = Module(new SPIFIFO(c)) + val mac = Module(new SPIMedia(c)) + + outer.port <> mac.io.port + fifo.io.ctrl.fmt := ctrl.fmt + fifo.io.ctrl.cs <> ctrl.cs + fifo.io.ctrl.wm := ctrl.wm + mac.io.ctrl.sck := ctrl.sck + mac.io.ctrl.extradel := ctrl.extradel + mac.io.ctrl.sampledel := ctrl.sampledel + mac.io.ctrl.dla := ctrl.dla + mac.io.ctrl.cs <> ctrl.cs + + val ie = Reg(init = new SPIInterrupts().fromBits(Bits(0))) + val ip = fifo.io.ip + outer.interrupts(0) := (ip.txwm && ie.txwm) || (ip.rxwm && ie.rxwm) + + protected val regmapBase = Seq( + SPICRs.sckdiv -> Seq(RegField(c.divisorBits, ctrl.sck.div, + RegFieldDesc("sckdiv","Serial clock divisor", reset=Some(3)))), + SPICRs.sckmode -> RegFieldGroup("sckmode",Some("Serial clock mode"),Seq( + RegField(1, ctrl.sck.pha, + RegFieldDesc("sckmode_pha","Serial clock phase", reset=Some(0))), + RegField(1, ctrl.sck.pol, + RegFieldDesc("sckmode_pol","Serial clock polarity", reset=Some(0))))), + SPICRs.csid -> Seq(RegField(c.csIdBits, ctrl.cs.id, + RegFieldDesc("csid","Chip select id", reset=Some(0)))), + SPICRs.csdef -> ctrl.cs.dflt.map(x => RegField(1, x, + RegFieldDesc("csdef","Chip select default", reset=Some(1)))), + SPICRs.csmode -> Seq(RegField(SPICSMode.width, ctrl.cs.mode, + RegFieldDesc("csmode","Chip select mode", reset=Some(SPICSMode.Auto.litValue())))), + SPICRs.dcssck -> Seq(RegField(c.delayBits, ctrl.dla.cssck, + RegFieldDesc("cssck","CS to SCK delay", reset=Some(1)))), + SPICRs.dsckcs -> Seq(RegField(c.delayBits, ctrl.dla.sckcs, + RegFieldDesc("sckcs","SCK to CS delay", reset=Some(1)))), + SPICRs.dintercs -> Seq(RegField(c.delayBits, ctrl.dla.intercs, + RegFieldDesc("intercs","Minimum CS inactive time", reset=Some(1)))), + SPICRs.dinterxfr -> Seq(RegField(c.delayBits, ctrl.dla.interxfr, + RegFieldDesc("interxfr","Minimum interframe delay", reset=Some(0)))), + + SPICRs.fmt -> RegFieldGroup("fmt",Some("Serial frame format"),Seq( + RegField(SPIProtocol.width, ctrl.fmt.proto, + RegFieldDesc("proto","SPI Protocol", reset=Some(SPIProtocol.Single.litValue()))), + RegField(SPIEndian.width, ctrl.fmt.endian, + RegFieldDesc("endian","SPI Endianness", reset=Some(SPIEndian.MSB.litValue()))), + RegField(SPIDirection.width, ctrl.fmt.iodir, + RegFieldDesc("iodir","SPI I/O Direction", reset=Some(SPIDirection.Rx.litValue()))))), + SPICRs.len -> Seq(RegField(c.lengthBits, ctrl.fmt.len, + RegFieldDesc("len","Number of bits per frame", reset=Some(math.min(c.frameBits, 8))))), + + SPICRs.txfifo -> RegFieldGroup("txdata",Some("Transmit data"), + NonBlockingEnqueue(fifo.io.tx)), + SPICRs.rxfifo -> RegFieldGroup("rxdata",Some("Receive data"), + NonBlockingDequeue(fifo.io.rx)), + + SPICRs.txmark -> Seq(RegField(c.txDepthBits, ctrl.wm.tx, + RegFieldDesc("txmark","Transmit watermark", reset=Some(0)))), + SPICRs.rxmark -> Seq(RegField(c.rxDepthBits, ctrl.wm.rx, + RegFieldDesc("rxmark","Receive watermark", reset=Some(0)))), + SPICRs.ie -> RegFieldGroup("ie",Some("SPI interrupt enable"),Seq( + RegField(1, ie.txwm, + RegFieldDesc("txwm_ie","Transmit watermark interupt enable", reset=Some(0))), + RegField(1, ie.rxwm, + RegFieldDesc("rxwm_ie","Receive watermark interupt enable", reset=Some(0))))), + SPICRs.ip -> RegFieldGroup("ip",Some("SPI interrupt pending"),Seq( + RegField.r(1, ip.txwm, + RegFieldDesc("txwm_ip","Transmit watermark interupt pending", volatile=true)), + RegField.r(1, ip.rxwm, + RegFieldDesc("rxwm_ip","Receive watermark interupt pending", volatile=true)))), + + SPICRs.extradel -> RegFieldGroup("extradel",Some("delay from the sck edge"),Seq( + RegField(c.divisorBits, ctrl.extradel.coarse, + RegFieldDesc("extradel_coarse","Coarse grain sample delay", reset=Some(0))), + RegField(c.fineDelayBits, ctrl.extradel.fine, + RegFieldDesc("extradel_fine","Fine grain sample delay", reset=Some(0))))), + + SPICRs.sampledel -> RegFieldGroup("sampledel",Some("Number of delay stages from slave to SPI controller"),Seq( + RegField(c.sampleDelayBits, ctrl.sampledel.sd, + RegFieldDesc("sampledel_sd","Number of delay stages from slave to the SPI controller", reset=Some(c.defaultSampleDel)))))) +} + +class MMCDevice(spi: Device, maxMHz: Double = 20) extends SimpleDevice("mmc", Seq("mmc-spi-slot")) { + override def parent = Some(spi) + override def describe(resources: ResourceBindings): Description = { + val Description(name, mapping) = super.describe(resources) + val extra = Map( + "voltage-ranges" -> Seq(ResourceInt(3300), ResourceInt(3300)), + "disable-wp" -> Nil, + "spi-max-frequency" -> Seq(ResourceInt(maxMHz * 1000000))) + Description(name, mapping ++ extra) + } +} + +class FlashDevice(spi: Device, bits: Int = 4, maxMHz: Double = 50, compat: Seq[String] = Nil) extends SimpleDevice("flash", compat :+ "jedec,spi-nor") { + require (bits == 1 || bits == 2 || bits == 4) + override def parent = Some(spi) + override def describe(resources: ResourceBindings): Description = { + val Description(name, mapping) = super.describe(resources) + val extra = Map( + "m25p,fast-read" -> Nil, + "spi-tx-bus-width" -> Seq(ResourceInt(bits)), + "spi-rx-bus-width" -> Seq(ResourceInt(bits)), + "spi-max-frequency" -> Seq(ResourceInt(maxMHz * 1000000))) + Description(name, mapping ++ extra) + } +} + +abstract class TLSPIBase(w: Int, c: SPIParamsBase)(implicit p: Parameters) extends IORegisterRouter( + RegisterRouterParams( + name = "spi", + compat = Seq("sifive,spi0"), + base = c.rAddress, + size = c.rSize, + beatBytes = w), + new SPIPortIO(c)) + with HasInterruptSources { + require(isPow2(c.rSize)) + override def extraResources(resources: ResourceBindings) = Map( + "#address-cells" -> Seq(ResourceInt(1)), + "#size-cells" -> Seq(ResourceInt(0))) + override def nInterrupts = 1 +} + +class TLSPI(w: Int, c: SPIParams)(implicit p: Parameters) + extends TLSPIBase(w,c)(p) with HasTLControlRegMap { + lazy val module = new SPITopModule(c, this) { + mac.io.link <> fifo.io.link + regmap(regmapBase:_*) + } +} diff --git a/sifive-blocks/src/main/scala/devices/spi/TLSPIFlash.scala b/sifive-blocks/src/main/scala/devices/spi/TLSPIFlash.scala new file mode 100644 index 00000000..66535ba2 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/spi/TLSPIFlash.scala @@ -0,0 +1,132 @@ +// See LICENSE for license details. +package sifive.blocks.devices.spi + +import Chisel._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.util.HeterogeneousBag + +trait SPIFlashParamsBase extends SPIParamsBase { + val fAddress: BigInt + val fSize: BigInt + + val insnAddrBytes: Int + val insnPadLenBits: Int + lazy val insnCmdBits = frameBits + lazy val insnAddrBits = insnAddrBytes * frameBits + lazy val insnAddrLenBits = log2Floor(insnAddrBytes) + 1 +} + +case class SPIFlashParams( + rAddress: BigInt, + fAddress: BigInt, + rSize: BigInt = 0x1000, + fSize: BigInt = 0x20000000, + rxDepth: Int = 8, + txDepth: Int = 8, + csWidth: Int = 1, + delayBits: Int = 8, + divisorBits: Int = 12, + fineDelayBits: Int = 0, + sampleDelayBits: Int = 5, + defaultSampleDel: Int = 3 + ) + extends SPIFlashParamsBase { + val frameBits = 8 + val insnAddrBytes = 4 + val insnPadLenBits = 4 + + require(insnPadLenBits <= delayBits) + require((fineDelayBits == 0) | (fineDelayBits == 5), s"Require fine delay bits to be 0 or 5 and not $fineDelayBits") + require(sampleDelayBits >= 0) + require(defaultSampleDel >= 0) +} + +class SPIFlashTopModule(c: SPIFlashParamsBase, outer: TLSPIFlashBase) + extends SPITopModule(c, outer) { + + val flash = Module(new SPIFlashMap(c)) + val arb = Module(new SPIArbiter(c, 2)) + + private val (f, _) = outer.fnode.in(0) + // Tie unused channels + f.b.valid := Bool(false) + f.c.ready := Bool(true) + f.e.ready := Bool(true) + + val a = Reg(f.a.bits) + val a_msb = log2Ceil(c.fSize) - 1 + + when (f.a.fire()) { + a := f.a.bits + } + + flash.io.addr.bits.next := f.a.bits.address(a_msb, 0) + flash.io.addr.bits.hold := a.address(a_msb, 0) + flash.io.addr.valid := f.a.valid + f.a.ready := flash.io.addr.ready + + f.d.bits := outer.fnode.edges.in.head.AccessAck(a, flash.io.data.bits) + f.d.valid := flash.io.data.valid + flash.io.data.ready := f.d.ready + + val insn = Reg(init = SPIFlashInsn.init(c)) + val flash_en = Reg(init = Bool(true)) + + flash.io.ctrl.insn := insn + flash.io.ctrl.fmt <> ctrl.fmt + flash.io.en := flash_en + arb.io.sel := !flash_en + + protected val regmapFlash = Seq( + SPICRs.insnmode -> Seq(RegField(1, flash_en, + RegFieldDesc("flash_en","SPIFlash mode select", reset=Some(1)))), + SPICRs.insnfmt -> RegFieldGroup("ffmtlen",Some("SPIFlash instruction length"),Seq( + RegField(1, insn.cmd.en, + RegFieldDesc("cmd_en","Enable sending of command", reset=Some(1))), + RegField(c.insnAddrLenBits, insn.addr.len, + RegFieldDesc("cmd_en","Number of address bytes", reset=Some(3))), + RegField(c.insnPadLenBits, insn.pad.cnt, + RegFieldDesc("cmd_en","Number of dummy cycles", reset=Some(0))))), + SPICRs.insnproto -> RegFieldGroup("ffmtproto",Some("SPIFlash instruction format"),Seq( + RegField(SPIProtocol.width, insn.cmd.proto, + RegFieldDesc("cmd_proto","Protocol for transmitting command", reset=Some(0))), + RegField(SPIProtocol.width, insn.addr.proto, + RegFieldDesc("addr_proto","Protocol for transmitting address and padding", reset=Some(0))), + RegField(SPIProtocol.width, insn.data.proto, + RegFieldDesc("data_proto","Protocol for transmitting receiving data", reset=Some(0))))), + SPICRs.insncmd -> Seq(RegField(c.insnCmdBits, insn.cmd.code, + RegFieldDesc("cmd_code","Value of command byte", reset=Some(3)))), + SPICRs.insnpad -> Seq(RegField(c.frameBits, insn.pad.code, + RegFieldDesc("pad_code","First 8 bits to transmit during dummy cycles", reset=Some(0))))) +} + +abstract class TLSPIFlashBase(w: Int, c: SPIFlashParamsBase)(implicit p: Parameters) extends TLSPIBase(w,c)(p) { + require(isPow2(c.fSize)) + val fnode = TLManagerNode(Seq(TLManagerPortParameters( + managers = Seq(TLManagerParameters( + address = Seq(AddressSet(c.fAddress, c.fSize-1)), + resources = device.reg("mem"), + regionType = RegionType.UNCACHED, + executable = true, + supportsGet = TransferSizes(1, 1), + fifoId = Some(0))), + beatBytes = 1))) + val memXing = this.crossIn(fnode) +} + +class TLSPIFlash(w: Int, c: SPIFlashParams)(implicit p: Parameters) + extends TLSPIFlashBase(w,c)(p) + with HasTLControlRegMap { + lazy val module = new SPIFlashTopModule(c, this) { + + arb.io.inner(0) <> flash.io.link + arb.io.inner(1) <> fifo.io.link + mac.io.link <> arb.io.outer + + regmap(regmapBase ++ regmapFlash:_*) + } +} diff --git a/sifive-blocks/src/main/scala/devices/stream/PseudoStream.scala b/sifive-blocks/src/main/scala/devices/stream/PseudoStream.scala new file mode 100644 index 00000000..965c3d8d --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/stream/PseudoStream.scala @@ -0,0 +1,118 @@ +// See LICENSE for license details. +package sifive.blocks.devices.stream + +import Chisel._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.tilelink._ +import sifive.blocks.util.{NonBlockingEnqueue, NonBlockingDequeue} + +case class PseudoStreamParams( + address: BigInt, + nChannels: Int = 1, + dataBits: Int = 32) { + require(dataBits <= 63) +} + +class PseudoStreamChannelIO(val params: PseudoStreamParams) extends Bundle { + val txq = Decoupled(UInt(width = params.dataBits)) + val rxq = Decoupled(UInt(width = params.dataBits)).flip +} + +class PseudoStreamPortIO(val params: PseudoStreamParams) extends Bundle { + val channel = Vec(params.nChannels, new PseudoStreamChannelIO(params)) +} + +abstract class PseudoStream(busWidthBytes: Int, val params: PseudoStreamParams)(implicit p: Parameters) + extends IORegisterRouter( + RegisterRouterParams( + name = "stream", + compat = Seq("sifive,stream0"), + base = params.address, + size = 1 << log2Up(4096 * params.nChannels), + beatBytes = busWidthBytes), + new PseudoStreamPortIO(params)) { + lazy val module = new LazyModuleImp(this) { + + val nbports = Wire(Vec(params.nChannels, new PseudoStreamChannelIO(params))) + val bports = Wire(Vec(params.nChannels, new PseudoStreamChannelIO(params))) + + regmap( + List.tabulate(params.nChannels)(idx => List( + PseudoStreamCtrlRegs.txfifo + 4096 * idx -> NonBlockingEnqueue(nbports(idx).txq, 64), + PseudoStreamCtrlRegs.rxfifo + 4096 * idx -> NonBlockingDequeue(nbports(idx).rxq, 64), + PseudoStreamCtrlRegs.txfifob + 4096 * idx -> Seq( + RegField.w(params.dataBits, bports(idx).txq, RegFieldDesc("txfifob", "blocking txfifo interface"))), + PseudoStreamCtrlRegs.rxfifob + 4096 * idx -> Seq( + RegField.r(params.dataBits, bports(idx).rxq, RegFieldDesc("rxfifob", "blocking rxfifo interface"))) + )).flatten:_*) + + (nbports zip bports).zipWithIndex.map { case ((nb, b), idx) => + val txq_arb = Module(new Arbiter(UInt(width = params.dataBits), 2)) + txq_arb.io.in(0) <> nb.txq + txq_arb.io.in(1) <> b.txq + port.channel(idx).txq <> txq_arb.io.out + + nb.rxq.valid := port.channel(idx).rxq.valid + nb.rxq.bits := port.channel(idx).rxq.bits + b.rxq.valid := port.channel(idx).rxq.valid + b.rxq.bits := port.channel(idx).rxq.bits + port.channel(idx).rxq.ready := nb.rxq.ready || b.rxq.ready + } +}} + +class TLPseudoStream(busWidthBytes: Int, params: PseudoStreamParams)(implicit p: Parameters) + extends PseudoStream(busWidthBytes, params) with HasTLControlRegMap + +case class PseudoStreamAttachParams( + stream: PseudoStreamParams, + controlBus: TLBusWrapper, + controlXType: ClockCrossingType = NoCrossing, + mclock: Option[ModuleValue[Clock]] = None, + mreset: Option[ModuleValue[Bool]] = None) + (implicit val p: Parameters) + +object PseudoStream { + val nextId = { var i = -1; () => { i += 1; i} } + + def attach(params: PseudoStreamAttachParams): TLPseudoStream = { + implicit val p = params.p + val name = s"stream_${nextId()}" + val cbus = params.controlBus + val stream = LazyModule(new TLPseudoStream(cbus.beatBytes, params.stream)) + stream.suggestName(name) + + cbus.coupleTo(s"slave_named_$name") { + (stream.controlXing(params.controlXType) + := TLFragmenter(cbus.beatBytes, cbus.blockBytes) + := TLBuffer(BufferParams.flow) := _) + } + InModuleBody { stream.module.clock := params.mclock.map(_.getWrappedValue).getOrElse(cbus.module.clock) } + InModuleBody { stream.module.reset := params.mreset.map(_.getWrappedValue).getOrElse(cbus.module.reset) } + + stream + } + + def attachAndMakePort(params: PseudoStreamAttachParams): ModuleValue[PseudoStreamPortIO] = { + val stream = attach(params) + val streamNode = stream.ioNode.makeSink()(params.p) + InModuleBody { streamNode.makeIO()(ValName(stream.name)) } + } + + def tieoff(port: PseudoStreamPortIO) { + port.channel.foreach { s => + s.txq.ready := true.B + s.rxq.valid := false.B + } + } + + def loopback(port: PseudoStreamPortIO, clock: Clock) { + port.channel.foreach { s => + val q = Module(new Queue(s.txq.bits, 2)) + q.clock := clock + q.io.enq <> s.txq + s.rxq <> q.io.deq + } + } +} diff --git a/sifive-blocks/src/main/scala/devices/stream/PseudoStreamRegs.scala b/sifive-blocks/src/main/scala/devices/stream/PseudoStreamRegs.scala new file mode 100644 index 00000000..ddbb4eba --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/stream/PseudoStreamRegs.scala @@ -0,0 +1,9 @@ +// See LICENSE for license details. +package sifive.blocks.devices.stream + +object PseudoStreamCtrlRegs { + val txfifo = 0x00 + val rxfifo = 0x08 + val txfifob = 0x10 + val rxfifob = 0x18 +} diff --git a/sifive-blocks/src/main/scala/devices/uart/UART.scala b/sifive-blocks/src/main/scala/devices/uart/UART.scala new file mode 100644 index 00000000..ec3c2337 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/uart/UART.scala @@ -0,0 +1,179 @@ +// See LICENSE for license details. +package sifive.blocks.devices.uart + +import Chisel._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.tilelink._ + +import sifive.blocks.util.{NonBlockingEnqueue, NonBlockingDequeue} + +case class UARTParams( + address: BigInt, + dataBits: Int = 8, + stopBits: Int = 2, + divisorBits: Int = 16, + oversample: Int = 4, + nSamples: Int = 3, + nTxEntries: Int = 8, + nRxEntries: Int = 8) +{ + def oversampleFactor = 1 << oversample + require(divisorBits > oversample) + require(oversampleFactor > nSamples) +} + +class UARTPortIO extends Bundle { + val txd = Bool(OUTPUT) + val rxd = Bool(INPUT) +} + +class UARTInterrupts extends Bundle { + val rxwm = Bool() + val txwm = Bool() +} + +abstract class UART(busWidthBytes: Int, val c: UARTParams, divisorInit: Int = 0) + (implicit p: Parameters) + extends IORegisterRouter( + RegisterRouterParams( + name = "serial", + compat = Seq("sifive,uart0"), + base = c.address, + beatBytes = busWidthBytes), + new UARTPortIO) + with HasInterruptSources { + + def nInterrupts = 1 + + ResourceBinding { + Resource(ResourceAnchors.aliases, "uart").bind(ResourceAlias(device.label)) + } + + require(divisorInit != 0, "UART divisor wasn't initialized during instantiation") + require(divisorInit >> c.divisorBits == 0, s"UART divisor reg (width $c.divisorBits) not wide enough to hold $divisorInit") + + lazy val module = new LazyModuleImp(this) { + + val txm = Module(new UARTTx(c)) + val txq = Module(new Queue(txm.io.in.bits, c.nTxEntries)) + + val rxm = Module(new UARTRx(c)) + val rxq = Module(new Queue(rxm.io.out.bits, c.nRxEntries)) + + val div = Reg(init = UInt(divisorInit, c.divisorBits)) + + private val stopCountBits = log2Up(c.stopBits) + private val txCountBits = log2Floor(c.nTxEntries) + 1 + private val rxCountBits = log2Floor(c.nRxEntries) + 1 + + val txen = Reg(init = Bool(false)) + val rxen = Reg(init = Bool(false)) + val txwm = Reg(init = UInt(0, txCountBits)) + val rxwm = Reg(init = UInt(0, rxCountBits)) + val nstop = Reg(init = UInt(0, stopCountBits)) + + txm.io.en := txen + txm.io.in <> txq.io.deq + txm.io.div := div + txm.io.nstop := nstop + port.txd := txm.io.out + + rxm.io.en := rxen + rxm.io.in := port.rxd + rxq.io.enq <> rxm.io.out + rxm.io.div := div + + val ie = Reg(init = new UARTInterrupts().fromBits(Bits(0))) + val ip = Wire(new UARTInterrupts) + + ip.txwm := (txq.io.count < txwm) + ip.rxwm := (rxq.io.count > rxwm) + interrupts(0) := (ip.txwm && ie.txwm) || (ip.rxwm && ie.rxwm) + + regmap( + UARTCtrlRegs.txfifo -> RegFieldGroup("txdata",Some("Transmit data"), + NonBlockingEnqueue(txq.io.enq)), + UARTCtrlRegs.rxfifo -> RegFieldGroup("rxdata",Some("Receive data"), + NonBlockingDequeue(rxq.io.deq)), + + UARTCtrlRegs.txctrl -> RegFieldGroup("txctrl",Some("Serial transmit control"),Seq( + RegField(1, txen, + RegFieldDesc("txen","Transmit enable", reset=Some(0))), + RegField(stopCountBits, nstop, + RegFieldDesc("nstop","Number of stop bits", reset=Some(0))))), + UARTCtrlRegs.rxctrl -> Seq(RegField(1, rxen, + RegFieldDesc("txen","Receive enable", reset=Some(0)))), + UARTCtrlRegs.txmark -> Seq(RegField(txCountBits, txwm, + RegFieldDesc("txcnt","Transmit watermark level", reset=Some(0)))), + UARTCtrlRegs.rxmark -> Seq(RegField(rxCountBits, rxwm, + RegFieldDesc("rxcnt","Receive watermark level", reset=Some(0)))), + + UARTCtrlRegs.ie -> RegFieldGroup("ie",Some("Serial interrupt enable"),Seq( + RegField(1, ie.txwm, + RegFieldDesc("txwm_ie","Transmit watermark interrupt enable", reset=Some(0))), + RegField(1, ie.rxwm, + RegFieldDesc("rxwm_ie","Receive watermark interrupt enable", reset=Some(0))))), + + UARTCtrlRegs.ip -> RegFieldGroup("ip",Some("Serial interrupt pending"),Seq( + RegField.r(1, ip.txwm, + RegFieldDesc("txwm_ip","Transmit watermark interrupt pending", volatile=true)), + RegField.r(1, ip.rxwm, + RegFieldDesc("rxwm_ip","Receive watermark interrupt pending", volatile=true)))), + + UARTCtrlRegs.div -> Seq( + RegField(c.divisorBits, div, + RegFieldDesc("div","Baud rate divisor",reset=Some(divisorInit)))) + ) +}} + +class TLUART(busWidthBytes: Int, params: UARTParams, divinit: Int)(implicit p: Parameters) + extends UART(busWidthBytes, params, divinit) with HasTLControlRegMap + +case class UARTAttachParams( + uart: UARTParams, + divinit: Int, + controlBus: TLBusWrapper, + intNode: IntInwardNode, + controlXType: ClockCrossingType = NoCrossing, + intXType: ClockCrossingType = NoCrossing, + mclock: Option[ModuleValue[Clock]] = None, + mreset: Option[ModuleValue[Bool]] = None) + (implicit val p: Parameters) + +object UART { + val nextId = { var i = -1; () => { i += 1; i} } + + def attach(params: UARTAttachParams): TLUART = { + implicit val p = params.p + val name = s"uart_${nextId()}" + val cbus = params.controlBus + val uart = LazyModule(new TLUART(cbus.beatBytes, params.uart, params.divinit)) + uart.suggestName(name) + + cbus.coupleTo(s"slave_named_$name") { + uart.controlXing(params.controlXType) := TLFragmenter(cbus.beatBytes, cbus.blockBytes) := _ + } + params.intNode := uart.intXing(params.intXType) + InModuleBody { uart.module.clock := params.mclock.map(_.getWrappedValue).getOrElse(cbus.module.clock) } + InModuleBody { uart.module.reset := params.mreset.map(_.getWrappedValue).getOrElse(cbus.module.reset) } + + uart + } + + def attachAndMakePort(params: UARTAttachParams): ModuleValue[UARTPortIO] = { + val uart = attach(params) + val uartNode = uart.ioNode.makeSink()(params.p) + InModuleBody { uartNode.makeIO()(ValName(uart.name)) } + } + + def tieoff(port: UARTPortIO) { + port.rxd := UInt(1) + } + + def loopback(port: UARTPortIO) { + port.rxd := port.txd + } +} diff --git a/sifive-blocks/src/main/scala/devices/uart/UARTCtrlRegs.scala b/sifive-blocks/src/main/scala/devices/uart/UARTCtrlRegs.scala new file mode 100644 index 00000000..3556583d --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/uart/UARTCtrlRegs.scala @@ -0,0 +1,15 @@ +// See LICENSE for license details. +package sifive.blocks.devices.uart + +object UARTCtrlRegs { + val txfifo = 0x00 + val rxfifo = 0x04 + val txctrl = 0x08 + val txmark = 0x0a + val rxctrl = 0x0c + val rxmark = 0x0e + + val ie = 0x10 + val ip = 0x14 + val div = 0x18 +} diff --git a/sifive-blocks/src/main/scala/devices/uart/UARTPeriphery.scala b/sifive-blocks/src/main/scala/devices/uart/UARTPeriphery.scala new file mode 100644 index 00000000..762d62c1 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/uart/UARTPeriphery.scala @@ -0,0 +1,25 @@ +// See LICENSE for license details. +package sifive.blocks.devices.uart + +import freechips.rocketchip.config.Field +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.subsystem.{BaseSubsystem, PeripheryBusKey} + +case object PeripheryUARTKey extends Field[Seq[UARTParams]] + +trait HasPeripheryUART { this: BaseSubsystem => + val uartNodes = p(PeripheryUARTKey).map { ps => + val divinit = (p(PeripheryBusKey).frequency / 115200).toInt + UART.attach(UARTAttachParams(ps, divinit, pbus, ibus.fromAsync)).ioNode.makeSink + } +} + +trait HasPeripheryUARTBundle { + val uart: Seq[UARTPortIO] +} + + +trait HasPeripheryUARTModuleImp extends LazyModuleImp with HasPeripheryUARTBundle { + val outer: HasPeripheryUART + val uart = outer.uartNodes.zipWithIndex.map { case(n,i) => n.makeIO()(ValName(s"uart_$i")) } +} diff --git a/sifive-blocks/src/main/scala/devices/uart/UARTPins.scala b/sifive-blocks/src/main/scala/devices/uart/UARTPins.scala new file mode 100644 index 00000000..88fa34c7 --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/uart/UARTPins.scala @@ -0,0 +1,25 @@ +// See LICENSE for license details. +package sifive.blocks.devices.uart + +import Chisel._ +import chisel3.experimental.{withClockAndReset} +import freechips.rocketchip.util.SyncResetSynchronizerShiftReg +import sifive.blocks.devices.pinctrl.{Pin} + +class UARTSignals[T <: Data](private val pingen: () => T) extends Bundle { + val rxd = pingen() + val txd = pingen() +} + +class UARTPins[T <: Pin](pingen: () => T) extends UARTSignals[T](pingen) + +object UARTPinsFromPort { + def apply[T <: Pin](pins: UARTSignals[T], uart: UARTPortIO, clock: Clock, reset: Bool, syncStages: Int = 0) { + withClockAndReset(clock, reset) { + pins.txd.outputPin(uart.txd) + val rxd_t = pins.rxd.inputPin() + uart.rxd := SyncResetSynchronizerShiftReg(rxd_t, syncStages, init = Bool(true), name = Some("uart_rxd_sync")) + } + } +} + diff --git a/sifive-blocks/src/main/scala/devices/uart/UARTRx.scala b/sifive-blocks/src/main/scala/devices/uart/UARTRx.scala new file mode 100644 index 00000000..93a61edd --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/uart/UARTRx.scala @@ -0,0 +1,93 @@ +// See LICENSE for license details. +package sifive.blocks.devices.uart + +import Chisel._ + +import freechips.rocketchip.util.Majority + +class UARTRx(c: UARTParams) extends Module { + val io = new Bundle { + val en = Bool(INPUT) + val in = Bits(INPUT, 1) + val out = Valid(Bits(width = c.dataBits)) + val div = UInt(INPUT, c.divisorBits) + } + + val debounce = Reg(init = UInt(0, 2)) + val debounce_max = (debounce === UInt(3)) + val debounce_min = (debounce === UInt(0)) + + val prescaler = Reg(UInt(width = c.divisorBits - c.oversample + 1)) + val start = Wire(init = Bool(false)) + val pulse = (prescaler === UInt(0)) + + private val dataCountBits = log2Floor(c.dataBits) + 1 + + val data_count = Reg(UInt(width = dataCountBits)) + val data_last = (data_count === UInt(0)) + val sample_count = Reg(UInt(width = c.oversample)) + val sample_mid = (sample_count === UInt((c.oversampleFactor - c.nSamples + 1) >> 1)) + val sample_last = (sample_count === UInt(0)) + val countdown = Cat(data_count, sample_count) - UInt(1) + + // Compensate for the divisor not being a multiple of the oversampling period. + // Let remainder k = (io.div % c.oversampleFactor). + // For the last k samples, extend the sampling delay by 1 cycle. + val remainder = io.div(c.oversample-1, 0) + val extend = (sample_count < remainder) // Pad head: (sample_count > ~remainder) + val restore = start || pulse + val prescaler_in = Mux(restore, io.div >> c.oversample, prescaler) + val prescaler_next = prescaler_in - Mux(restore && extend, UInt(0), UInt(1)) + + val sample = Reg(Bits(width = c.nSamples)) + val voter = Majority(sample.toBools.toSet) + val shifter = Reg(Bits(width = c.dataBits)) + + val valid = Reg(init = Bool(false)) + valid := Bool(false) + io.out.valid := valid + io.out.bits := shifter + + val (s_idle :: s_data :: Nil) = Enum(UInt(), 2) + val state = Reg(init = s_idle) + + switch (state) { + is (s_idle) { + when (!(!io.in) && !debounce_min) { + debounce := debounce - UInt(1) + } + when (!io.in) { + debounce := debounce + UInt(1) + when (debounce_max) { + state := s_data + start := Bool(true) + prescaler := prescaler_next + data_count := UInt(c.dataBits+1) + sample_count := UInt(c.oversampleFactor - 1) + } + } + } + + is (s_data) { + prescaler := prescaler_next + when (pulse) { + sample := Cat(sample, io.in) + data_count := countdown >> c.oversample + sample_count := countdown(c.oversample-1, 0) + + when (sample_mid) { + when (data_last) { + state := s_idle + valid := Bool(true) + } .otherwise { + shifter := Cat(voter, shifter >> 1) + } + } + } + } + } + + when (!io.en) { + debounce := UInt(0) + } +} diff --git a/sifive-blocks/src/main/scala/devices/uart/UARTTx.scala b/sifive-blocks/src/main/scala/devices/uart/UARTTx.scala new file mode 100644 index 00000000..b876e03f --- /dev/null +++ b/sifive-blocks/src/main/scala/devices/uart/UARTTx.scala @@ -0,0 +1,46 @@ +// See LICENSE for license details. +package sifive.blocks.devices.uart + +import Chisel._ + +import freechips.rocketchip.util.PlusArg + +class UARTTx(c: UARTParams) extends Module { + val io = new Bundle { + val en = Bool(INPUT) + val in = Decoupled(Bits(width = c.dataBits)).flip + val out = Bits(OUTPUT, 1) + val div = UInt(INPUT, c.divisorBits) + val nstop = UInt(INPUT, log2Up(c.stopBits)) + } + + val prescaler = Reg(init = UInt(0, c.divisorBits)) + val pulse = (prescaler === UInt(0)) + + private val n = c.dataBits + 1 + val counter = Reg(init = UInt(0, log2Floor(n + c.stopBits) + 1)) + val shifter = Reg(Bits(width = n)) + val out = Reg(init = Bits(1, 1)) + io.out := out + + val plusarg_tx = PlusArg("uart_tx", 1, "Enable/disable the TX to speed up simulation").orR + + val busy = (counter =/= UInt(0)) + io.in.ready := io.en && !busy + when (io.in.fire()) { + printf("UART TX (%x): %c\n", io.in.bits, io.in.bits) + } + when (io.in.fire() && plusarg_tx) { + shifter := Cat(io.in.bits, Bits(0, 1)) + counter := Mux1H((0 until c.stopBits).map(i => + (io.nstop === UInt(i)) -> UInt(n + i + 1))) + } + when (busy) { + prescaler := Mux(pulse, io.div, prescaler - UInt(1)) + } + when (pulse && busy) { + counter := counter - UInt(1) + shifter := Cat(Bits(1, 1), shifter >> 1) + out := shifter(0) + } +} diff --git a/sifive-blocks/src/main/scala/ip/xilinx/ibufds_gte2/ibufds_gte2.scala b/sifive-blocks/src/main/scala/ip/xilinx/ibufds_gte2/ibufds_gte2.scala new file mode 100644 index 00000000..7fca6f1f --- /dev/null +++ b/sifive-blocks/src/main/scala/ip/xilinx/ibufds_gte2/ibufds_gte2.scala @@ -0,0 +1,18 @@ +// See LICENSE for license details. +package sifive.blocks.ip.xilinx.ibufds_gte2 + +import Chisel._ + +//IP : xilinx unisim IBUFDS_GTE2 +//Differential Signaling Input Buffer +//unparameterized + +class IBUFDS_GTE2 extends BlackBox { + val io = new Bundle { + val O = Bool(OUTPUT) + val ODIV2 = Bool(OUTPUT) + val CEB = Bool(INPUT) + val I = Bool(INPUT) + val IB = Bool(INPUT) + } +} diff --git a/sifive-blocks/src/main/scala/util/DeglitchShiftRegister.scala b/sifive-blocks/src/main/scala/util/DeglitchShiftRegister.scala new file mode 100644 index 00000000..e40de969 --- /dev/null +++ b/sifive-blocks/src/main/scala/util/DeglitchShiftRegister.scala @@ -0,0 +1,28 @@ +// See LICENSE for license details. +package sifive.blocks.util + +import Chisel._ + +//Allows us to specify a different clock for a shift register +// and to force input to be high for > 1 cycle. +class DeglitchShiftRegister(shift: Int) extends Module { + val io = new Bundle { + val d = Bool(INPUT) + val q = Bool(OUTPUT) + } + val sync = ShiftRegister(io.d, shift) + val last = ShiftRegister(sync, 1) + io.q := sync & last +} + +object DeglitchShiftRegister { + def apply (shift: Int, d: Bool, clock: Clock, + name: Option[String] = None): Bool = { + val deglitch = Module (new DeglitchShiftRegister(shift)) + name.foreach(deglitch.suggestName(_)) + deglitch.clock := clock + deglitch.reset := Bool(false) + deglitch.io.d := d + deglitch.io.q + } +} diff --git a/sifive-blocks/src/main/scala/util/RegMapFIFO.scala b/sifive-blocks/src/main/scala/util/RegMapFIFO.scala new file mode 100644 index 00000000..20347096 --- /dev/null +++ b/sifive-blocks/src/main/scala/util/RegMapFIFO.scala @@ -0,0 +1,48 @@ +// See LICENSE for license details. +package sifive.blocks.util + +import Chisel._ +import freechips.rocketchip.regmapper._ + +// MSB indicates full status +object NonBlockingEnqueue { + def apply(enq: DecoupledIO[UInt], regWidth: Int = 32): Seq[RegField] = { + val enqWidth = enq.bits.getWidth + val quash = Wire(Bool()) + require(enqWidth > 0) + require(regWidth > enqWidth) + Seq( + RegField(enqWidth, + RegReadFn(UInt(0)), + RegWriteFn((valid, data) => { + enq.valid := valid && !quash + enq.bits := data + Bool(true) + }), RegFieldDesc("data","Transmit data")), + RegField(regWidth - enqWidth - 1), + RegField(1, + !enq.ready, + RegWriteFn((valid, data) => { + quash := valid && data(0) + Bool(true) + }), RegFieldDesc("full","Transmit FIFO full", volatile=true))) + } +} + +// MSB indicates empty status +object NonBlockingDequeue { + def apply(deq: DecoupledIO[UInt], regWidth: Int = 32): Seq[RegField] = { + val deqWidth = deq.bits.getWidth + require(deqWidth > 0) + require(regWidth > deqWidth) + Seq( + RegField.r(deqWidth, + RegReadFn(ready => { + deq.ready := ready + (Bool(true), deq.bits) + }), RegFieldDesc("data","Receive data", volatile=true)), + RegField(regWidth - deqWidth - 1), + RegField.r(1, !deq.valid, + RegFieldDesc("empty","Receive FIFO empty", volatile=true))) + } +} diff --git a/sifive-blocks/src/main/scala/util/SRLatch.scala b/sifive-blocks/src/main/scala/util/SRLatch.scala new file mode 100644 index 00000000..95fae4fb --- /dev/null +++ b/sifive-blocks/src/main/scala/util/SRLatch.scala @@ -0,0 +1,12 @@ +// See LICENSE for license details. +package sifive.blocks.util + +import Chisel._ + +class SRLatch extends BlackBox { + val io = new Bundle { + val set = Bool(INPUT) + val reset = Bool(INPUT) + val q = Bool(OUTPUT) + } +} diff --git a/sifive-blocks/src/main/scala/util/SlaveRegIF.scala b/sifive-blocks/src/main/scala/util/SlaveRegIF.scala new file mode 100644 index 00000000..a0d8a2cf --- /dev/null +++ b/sifive-blocks/src/main/scala/util/SlaveRegIF.scala @@ -0,0 +1,19 @@ +// See LICENSE for license details. +package sifive.blocks.util + +import Chisel._ +import freechips.rocketchip.regmapper._ + +class SlaveRegIF(private val w: Int) extends Bundle { + val write = Valid(UInt(width = w)).flip + val read = UInt(OUTPUT, w) + + def toRegField(desc: Option[RegFieldDesc] = None): RegField = { + def writeFn(valid: Bool, data: UInt): Bool = { + write.valid := valid + write.bits := data + Bool(true) + } + RegField(w, RegReadFn(read), RegWriteFn((v, d) => writeFn(v, d)), desc) + } +} diff --git a/sifive-blocks/src/main/scala/util/Timer.scala b/sifive-blocks/src/main/scala/util/Timer.scala new file mode 100644 index 00000000..4edb2a73 --- /dev/null +++ b/sifive-blocks/src/main/scala/util/Timer.scala @@ -0,0 +1,251 @@ +// See LICENSE for license details. +package sifive.blocks.util + +import Chisel._ +import Chisel.ImplicitConversions._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.util.WideCounter + +import scala.math.{min, max} + +class GenericTimerCfgReg( + val maxcmp: Int, + val scaleWidth: Int) extends Bundle { + + val ip = Vec(maxcmp, Bool()) + val gang = Vec(maxcmp, Bool()) + val extra = Vec(maxcmp, Bool()) + val center = Vec(maxcmp, Bool()) + val reserved0 = UInt(width = 2) + val running = Bool() + val countAlways = Bool() + val reserved1 = UInt(width = 1) + val deglitch = Bool() + val zerocmp = Bool() + val sticky = Bool() + val reserved2 = UInt(width = 8 - scaleWidth) + val scale = UInt(width = scaleWidth) + +} + +case class GenericTimerCfgDescs( + scale: RegFieldDesc, + sticky: RegFieldDesc, + zerocmp: RegFieldDesc, + deglitch:RegFieldDesc, + countAlways: RegFieldDesc, + running: RegFieldDesc, + center: Seq[RegFieldDesc], + extra: Seq[RegFieldDesc], + gang: Seq[RegFieldDesc], + ip: Seq[RegFieldDesc] +) + +object DefaultGenericTimerCfgDescs { + def apply(prefix: String, ncmp: Int): GenericTimerCfgDescs = GenericTimerCfgDescs( + scale = RegFieldDesc(s"${prefix}scale", "Counter scale value."), + sticky = RegFieldDesc(s"${prefix}sticky", "Sticky. Disallow clearing of ${prefix}cmpXip bits"), + zerocmp = RegFieldDesc(s"${prefix}zerocmp", "Reset counter to zero after match."), + deglitch = RegFieldDesc(s"${prefix}deglitch", "Deglitch - latch ${prefix}cmpXip within same cycle."), + countAlways = RegFieldDesc(s"${prefix}enalways", "Enable Always - run continuously", + reset = Some(0)), + running = RegFieldDesc(s"${prefix}oneshot", "Enable One Shot - run one cycle, then this bit is cleared.", + reset=Some(0), volatile=true), + center = Seq.tabulate(ncmp){ i => RegFieldDesc(s"${prefix}cmp${i}center", s"Comparator ${i} Center")}, + extra = Seq.tabulate(ncmp){ i => RegFieldDesc(s"${prefix}extra${i}", s"Comparator ${i} Extra")}, + gang = Seq.tabulate(ncmp){ i => RegFieldDesc(s"${prefix}gang${i}", s"Comparator ${i}/${(i+1) % ncmp} Gang")}, + ip = Seq.tabulate(ncmp){ i => RegFieldDesc(s"${prefix}ip${i}", s"Interrupt ${i} Pending")} + ) +} + +class GenericTimerCfgRegIFC ( + val ncmp: Int, + val maxcmp: Int, + val scaleWidth: Int) extends Bundle { + + val write = new GenericTimerCfgReg(maxcmp, scaleWidth).asInput + val read = new GenericTimerCfgReg(maxcmp, scaleWidth).asOutput + + val write_ip = Vec(maxcmp, Bool(INPUT)) + val write_gang = Vec(maxcmp, Bool(INPUT)) + val write_extra = Vec(maxcmp, Bool(INPUT)) + val write_center = Vec(maxcmp, Bool(INPUT)) + val write_running = Bool(INPUT) + val write_countAlways = Bool(INPUT) + val write_deglitch = Bool(INPUT) + val write_zerocmp = Bool(INPUT) + val write_sticky = Bool(INPUT) + val write_scale = Bool(INPUT) + + def toRegFields(prefix: String, descs: GenericTimerCfgDescs): Seq[RegField] = { + + def writeFn(valid: Bool, data: UInt, wr_data: UInt, wr_notify: Bool): Bool = { + wr_notify := valid + wr_data := data + Bool(true) + } + + // Defaults, because only ncmp of these are assigned by the regmap below. + write_ip := Vec.fill(maxcmp){false.B} + write_gang := Vec.fill(maxcmp){false.B} + write_extra := Vec.fill(maxcmp){false.B} + write_center := Vec.fill(maxcmp){false.B} + + RegFieldGroup(s"${prefix}cfg", Some(s"${prefix} Configuration"), + Seq( + RegField(scaleWidth, RegReadFn(read.scale), RegWriteFn((v, d) => writeFn(v, d, write.scale, write_scale)), descs.scale), + RegField(8-scaleWidth), + RegField(1, RegReadFn(read.sticky), RegWriteFn((v, d) => writeFn(v, d, write.sticky, write_sticky)), descs.sticky), + RegField(1, RegReadFn(read.zerocmp), RegWriteFn((v, d) => writeFn(v, d, write.zerocmp, write_zerocmp)), descs.zerocmp), + RegField(1, RegReadFn(read.deglitch), RegWriteFn((v, d) => writeFn(v, d, write.deglitch, write_deglitch)), descs.deglitch), + RegField(1), + RegField(1, RegReadFn(read.countAlways), RegWriteFn((v, d) => writeFn(v, d, write.countAlways, write_countAlways)), descs.countAlways), + RegField(1, RegReadFn(read.running), RegWriteFn((v, d) => writeFn(v, d, write.running, write_running)), descs.running), + RegField(2) + ) ++ Seq.tabulate(ncmp) { i => + RegField(1, RegReadFn(read.center(i)), RegWriteFn((v, d) => writeFn(v, d, write.center(i), write_center(i))), descs.center(i)) + } + ++ (if (ncmp < maxcmp) Seq(RegField(maxcmp - ncmp)) else Nil) + ++ Seq.tabulate(ncmp) { i => + RegField(1, RegReadFn(read.extra(i)), + RegWriteFn((v, d) => writeFn(v, d, write.extra(i), write_extra(i))), descs.extra(i)) + } + ++ (if (ncmp < maxcmp) Seq(RegField(maxcmp - ncmp)) else Nil) + ++ Seq.tabulate(ncmp) { i => + RegField(1, RegReadFn(read.gang(i)), + RegWriteFn((v, d) => writeFn(v, d, write.gang(i), write_gang(i))), descs.gang(i)) + } + ++ (if (ncmp < maxcmp) Seq(RegField(maxcmp - ncmp)) else Nil) + ++ Seq.tabulate(ncmp) { i => + RegField(1, RegReadFn(read.ip(i)), + RegWriteFn((v, d) => writeFn(v, d, write.ip(i), write_ip(i))), descs.ip(i)) + } + ++ (if (ncmp < maxcmp) Seq(RegField(maxcmp - ncmp)) else Nil) + ) + } + + def anyWriteValid: Bool = ( + write_ip ++ + write_gang ++ + write_extra ++ + write_center ++ + Seq(write_running) ++ + Seq(write_countAlways) ++ + Seq(write_deglitch) ++ + Seq(write_zerocmp) ++ + Seq(write_sticky) ++ + Seq(write_scale) + ).reduce(_||_) + +} + +class GenericTimerIO( + val regWidth: Int, + val ncmp: Int, + val maxcmp: Int, + val scaleWidth: Int, + val countWidth: Int, + val cmpWidth: Int) extends Bundle { + val regs = new Bundle { + val cfg = new GenericTimerCfgRegIFC(ncmp, maxcmp, scaleWidth) + val countLo = new SlaveRegIF(min(regWidth, countWidth)) + // If countWidth < regWidth, countHi ends up as a regWidth wide reserved field. + val countHi = new SlaveRegIF(max(regWidth, countWidth - regWidth)) + val s = new SlaveRegIF(cmpWidth) + val cmp = Vec(ncmp, new SlaveRegIF(cmpWidth)) + val feed = new SlaveRegIF(regWidth) + val key = new SlaveRegIF(regWidth) + } + val ip = Vec(ncmp, Bool()).asOutput +} + + +trait GenericTimer { + protected def prefix: String + protected def countWidth: Int + protected def cmpWidth: Int + protected def ncmp: Int + protected def countAlways: Bool + protected def countEn: Bool + protected def feed: Bool + protected def ip: Vec[Bool] + protected def countAwake: Bool = Bool(false) + protected def unlocked: Bool = Bool(true) + protected def rsten: Bool = Bool(false) + protected def deglitch: Bool = Bool(false) + protected def sticky: Bool = Bool(false) + protected def oneShot: Bool = Bool(false) + protected def center: Vec[Bool] = Vec.fill(ncmp){Bool(false)} + protected def extra: Vec[Bool] = Vec.fill(ncmp){Bool(false)} + protected def gang: Vec[Bool] = Vec.fill(ncmp){Bool(false)} + protected val scaleWidth = 4 + protected val regWidth = 32 + val maxcmp = 4 + require(ncmp <= maxcmp) + require(ncmp > 0) + + protected def countLo_desc: RegFieldDesc = if (countWidth > regWidth) { + RegFieldDesc(s"${prefix}countlo", "Low bits of Counter", volatile=true) + } else { + RegFieldDesc(s"${prefix}count", "Counter Register", volatile=true) + } + protected def countHi_desc: RegFieldDesc = if (countWidth > regWidth) RegFieldDesc(s"${prefix}counthi", "High bits of Counter", volatile=true) else RegFieldDesc.reserved + protected def s_desc: RegFieldDesc = RegFieldDesc(s"${prefix}s", "Scaled value of Counter", access=RegFieldAccessType.R, volatile=true) + protected def cmp_desc: Seq[RegFieldDesc] = Seq.tabulate(ncmp){ i => RegFieldDesc(s"${prefix}cmp${i}", s"Comparator ${i}")} + protected def feed_desc: RegFieldDesc = RegFieldDesc(s"${prefix}feed", "Feed register") + protected def key_desc: RegFieldDesc = RegFieldDesc(s"${prefix}key", "Key Register") + protected def cfg_desc: GenericTimerCfgDescs = DefaultGenericTimerCfgDescs(prefix, ncmp) + + val io: GenericTimerIO + + protected val scale = RegEnable(io.regs.cfg.write.scale, io.regs.cfg.write_scale && unlocked) + protected lazy val zerocmp = RegEnable(io.regs.cfg.write.zerocmp, io.regs.cfg.write_zerocmp && unlocked) + protected val cmp = io.regs.cmp.map(c => RegEnable(c.write.bits, c.write.valid && unlocked)) + + protected val count = WideCounter(countWidth, countEn, reset = false) + when (io.regs.countLo.write.valid && unlocked) { count := Cat(count >> regWidth, io.regs.countLo.write.bits) } + if (countWidth > regWidth) when (io.regs.countHi.write.valid && unlocked) { count := Cat(io.regs.countHi.write.bits, count(regWidth-1, 0)) } + + // generate periodic interrupt + protected val s = (count >> scale)(cmpWidth-1, 0) + // reset counter when fed or elapsed + protected val elapsed = Vec.tabulate(ncmp){i => Mux(s(cmpWidth-1) && center(i), ~s, s) >= cmp(i)} + protected val countReset = feed || (zerocmp && elapsed(0)) + when (countReset) { count := 0 } + + io.regs.cfg.read := new GenericTimerCfgReg(maxcmp, scaleWidth).fromBits(0.U) + io.regs.cfg.read.ip := ip + io.regs.cfg.read.gang := gang + io.regs.cfg.read.extra := extra + io.regs.cfg.read.center := center + io.regs.cfg.read.running := countAwake || oneShot + io.regs.cfg.read.countAlways := countAlways + io.regs.cfg.read.deglitch := deglitch + io.regs.cfg.read.deglitch := zerocmp + io.regs.cfg.read.sticky := rsten || sticky + io.regs.cfg.read.scale := scale + + io.regs.countLo.read := count + io.regs.countHi.read := count >> regWidth + io.regs.s.read := s + (io.regs.cmp zip cmp) map { case (r, c) => r.read := c } + io.regs.feed.read := 0 + io.regs.key.read := unlocked + io.ip := ip +} + +object GenericTimer { + def timerRegMap(t: GenericTimer, offset: Int, regBytes: Int): Seq[(Int, Seq[RegField])] = { + val cfgRegs = Seq(offset -> t.io.regs.cfg.toRegFields(t.prefix, t.cfg_desc)) + val regs = Seq( + 2 -> (t.io.regs.countLo, t.countLo_desc), + 3 -> (t.io.regs.countHi, t.countHi_desc), + 4 -> (t.io.regs.s, t.s_desc), + 6 -> (t.io.regs.feed, t.feed_desc), + 7 -> (t.io.regs.key, t.key_desc) + ) + val cmpRegs = (t.io.regs.cmp zip t.cmp_desc).zipWithIndex map { case ((r, d), i) => (8 + i) -> (r, d) } + val otherRegs = for ((i, (r, d)) <- (regs ++ cmpRegs)) yield (offset + regBytes*i) -> Seq(r.toRegField(Some(d))) + cfgRegs ++ otherRegs + } +} diff --git a/sifive-blocks/vsrc/SRLatch.v b/sifive-blocks/vsrc/SRLatch.v new file mode 100644 index 00000000..d4849a1b --- /dev/null +++ b/sifive-blocks/vsrc/SRLatch.v @@ -0,0 +1,22 @@ +// See LICENSE for license details. +module SRLatch ( + input set, + input reset, + output q +); + + reg latch; + + // synopsys async_set_reset "set" + // synopsys one_hot "set, reset" + always @(set or reset) + begin + if (set) + latch <= 1'b1; + else if (reset) + latch <= 1'b0; + end + + assign q = latch; + +endmodule diff --git a/src/main/scala/everywhere/e300artydevkit/Config.scala b/src/main/scala/everywhere/e300artydevkit/Config.scala new file mode 100644 index 00000000..45f83036 --- /dev/null +++ b/src/main/scala/everywhere/e300artydevkit/Config.scala @@ -0,0 +1,65 @@ +// See LICENSE for license details. +package sifive.freedom.everywhere.e300artydevkit + +import freechips.rocketchip.config._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.devices.debug._ +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.diplomacy.{DTSModel, DTSTimebase} +import freechips.rocketchip.system._ +import freechips.rocketchip.tile._ + +import sifive.blocks.devices.mockaon._ +import sifive.blocks.devices.gpio._ +import sifive.blocks.devices.pwm._ +import sifive.blocks.devices.spi._ +import sifive.blocks.devices.uart._ +import sifive.blocks.devices.i2c._ + +// Default FreedomEConfig +class DefaultFreedomEConfig extends Config ( + new WithNBreakpoints(2) ++ + new WithNExtTopInterrupts(0) ++ + new WithJtagDTM ++ + new TinyConfig +) + +// Freedom E300 Arty Dev Kit Peripherals +class E300DevKitPeripherals extends Config((site, here, up) => { + case PeripheryGPIOKey => List( + GPIOParams(address = 0x10012000, width = 32, includeIOF = true)) + case PeripheryPWMKey => List( + PWMParams(address = 0x10015000, cmpWidth = 8), + PWMParams(address = 0x10025000, cmpWidth = 16), + PWMParams(address = 0x10035000, cmpWidth = 16)) + case PeripherySPIKey => List( + SPIParams(csWidth = 4, rAddress = 0x10024000, defaultSampleDel = 3), + SPIParams(csWidth = 1, rAddress = 0x10034000, defaultSampleDel = 3)) + case PeripherySPIFlashKey => List( + SPIFlashParams( + fAddress = 0x20000000, + rAddress = 0x10014000, + defaultSampleDel = 3)) + case PeripheryUARTKey => List( + UARTParams(address = 0x10013000), + UARTParams(address = 0x10023000)) + case PeripheryI2CKey => List( + I2CParams(address = 0x10016000)) + case PeripheryMockAONKey => + MockAONParams(address = 0x10000000) + case PeripheryMaskROMKey => List( + MaskROMParams(address = 0x10000, name = "BootROM")) +}) + +// Freedom E300 Arty Dev Kit Peripherals +class E300ArtyDevKitConfig extends Config( + new E300DevKitPeripherals ++ + new DefaultFreedomEConfig().alter((site,here,up) => { + case DTSTimebase => BigInt(32768) + case JtagDTMKey => new JtagDTMConfig ( + idcodeVersion = 2, + idcodePartNum = 0x000, + idcodeManufId = 0x489, + debugIdleCycles = 5) + }) +) diff --git a/src/main/scala/everywhere/e300artydevkit/FPGAChip.scala b/src/main/scala/everywhere/e300artydevkit/FPGAChip.scala new file mode 100644 index 00000000..e0b0634c --- /dev/null +++ b/src/main/scala/everywhere/e300artydevkit/FPGAChip.scala @@ -0,0 +1,193 @@ +// See LICENSE for license details. +package sifive.freedom.everywhere.e300artydevkit + +import Chisel._ +import chisel3.core.{attach} +import chisel3.experimental.{withClockAndReset} + +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy.{LazyModule} + +import sifive.blocks.devices.gpio._ +import sifive.blocks.devices.spi._ + +import sifive.fpgashells.shell.xilinx.artyshell.{ArtyShell} +import sifive.fpgashells.ip.xilinx.{IBUFG, IOBUF, PULLUP, PowerOnResetFPGAOnly} + +//------------------------------------------------------------------------- +// E300ArtyDevKitFPGAChip +//------------------------------------------------------------------------- + +class E300ArtyDevKitFPGAChip(implicit override val p: Parameters) extends ArtyShell { + + //----------------------------------------------------------------------- + // Clock divider + //----------------------------------------------------------------------- + val slow_clock = Wire(Bool()) + + // Divide clock by 256, used to generate 32.768 kHz clock for AON block + withClockAndReset(clock_8MHz, ~mmcm_locked) { + val clockToggleReg = RegInit(false.B) + val (_, slowTick) = Counter(true.B, 256) + when (slowTick) {clockToggleReg := ~clockToggleReg} + slow_clock := clockToggleReg + } + + //----------------------------------------------------------------------- + // DUT + //----------------------------------------------------------------------- + + withClockAndReset(clock_32MHz, ck_rst) { + val dut = Module(new E300ArtyDevKitPlatform) + + //--------------------------------------------------------------------- + // SPI flash IOBUFs + //--------------------------------------------------------------------- + + IOBUF(qspi_sck, dut.io.pins.qspi.sck) + IOBUF(qspi_cs, dut.io.pins.qspi.cs(0)) + + IOBUF(qspi_dq(0), dut.io.pins.qspi.dq(0)) + IOBUF(qspi_dq(1), dut.io.pins.qspi.dq(1)) + IOBUF(qspi_dq(2), dut.io.pins.qspi.dq(2)) + IOBUF(qspi_dq(3), dut.io.pins.qspi.dq(3)) + + //--------------------------------------------------------------------- + // JTAG IOBUFs + //--------------------------------------------------------------------- + + dut.io.pins.jtag.TCK.i.ival := IBUFG(IOBUF(jd_2).asClock).asUInt + + IOBUF(jd_5, dut.io.pins.jtag.TMS) + PULLUP(jd_5) + + IOBUF(jd_4, dut.io.pins.jtag.TDI) + PULLUP(jd_4) + + IOBUF(jd_0, dut.io.pins.jtag.TDO) + + // mimic putting a pullup on this line (part of reset vote) + SRST_n := IOBUF(jd_6) + PULLUP(jd_6) + + // jtag reset + val jtag_power_on_reset = PowerOnResetFPGAOnly(clock_32MHz) + dut.io.jtag_reset := jtag_power_on_reset + + // debug reset + dut_ndreset := dut.io.ndreset + + //--------------------------------------------------------------------- + // Assignment to package pins + //--------------------------------------------------------------------- + // Pins IO0-IO13 + // + // FTDI UART TX/RX are not connected to ck_io[0,1] + // the way they are on Arduino boards. We copy outgoing + // data to both places, switch 3 (sw[3]) determines whether + // input to UART comes from FTDI chip or gpio_16 (shield pin PD0) + + val iobuf_ck0 = Module(new IOBUF()) + iobuf_ck0.io.I := dut.io.pins.gpio.pins(16).o.oval + iobuf_ck0.io.T := ~dut.io.pins.gpio.pins(16).o.oe + attach(iobuf_ck0.io.IO, ck_io(0)) // UART0 RX + + val iobuf_uart_txd = Module(new IOBUF()) + iobuf_uart_txd.io.I := dut.io.pins.gpio.pins(16).o.oval + iobuf_uart_txd.io.T := ~dut.io.pins.gpio.pins(16).o.oe + attach(iobuf_uart_txd.io.IO, uart_txd_in) + + // gpio(16) input is shared between FTDI TX pin and the Arduino shield pin using SW[3] + val sw_3_in = IOBUF(sw_3) + dut.io.pins.gpio.pins(16).i.ival := Mux(sw_3_in, + iobuf_ck0.io.O & dut.io.pins.gpio.pins(16).o.ie, + iobuf_uart_txd.io.O & dut.io.pins.gpio.pins(16).o.ie) + + IOBUF(uart_rxd_out, dut.io.pins.gpio.pins(17)) + + // Shield header row 0: PD2-PD7 + IOBUF(ck_io(2), dut.io.pins.gpio.pins(18)) + IOBUF(ck_io(3), dut.io.pins.gpio.pins(19)) // PWM1(1) + IOBUF(ck_io(4), dut.io.pins.gpio.pins(20)) // PWM1(0) + IOBUF(ck_io(5), dut.io.pins.gpio.pins(21)) // PWM1(2) + IOBUF(ck_io(6), dut.io.pins.gpio.pins(22)) // PWM1(3) + IOBUF(ck_io(7), dut.io.pins.gpio.pins(23)) + + // Header row 1: PB0-PB5 + IOBUF(ck_io(8), dut.io.pins.gpio.pins(0)) // PWM0(0) + IOBUF(ck_io(9), dut.io.pins.gpio.pins(1)) // PWM0(1) + IOBUF(ck_io(10), dut.io.pins.gpio.pins(2)) // SPI CS(0) / PWM0(2) + IOBUF(ck_io(11), dut.io.pins.gpio.pins(3)) // SPI MOSI / PWM0(3) + IOBUF(ck_io(12), dut.io.pins.gpio.pins(4)) // SPI MISO + IOBUF(ck_io(13), dut.io.pins.gpio.pins(5)) // SPI SCK + + dut.io.pins.gpio.pins(6).i.ival := 0.U + dut.io.pins.gpio.pins(7).i.ival := 0.U + dut.io.pins.gpio.pins(8).i.ival := 0.U + + // Header row 3: A0-A5 (we don't support using them as analog inputs) + // just treat them as regular digital GPIOs + IOBUF(ck_io(15), dut.io.pins.gpio.pins(9)) // A1 = CS(2) + IOBUF(ck_io(16), dut.io.pins.gpio.pins(10)) // A2 = CS(3) / PWM2(0) + IOBUF(ck_io(17), dut.io.pins.gpio.pins(11)) // A3 = PWM2(1) + IOBUF(ck_io(18), dut.io.pins.gpio.pins(12)) // A4 = PWM2(2) / SDA + IOBUF(ck_io(19), dut.io.pins.gpio.pins(13)) // A5 = PWM2(3) / SCL + + // Mirror outputs of GPIOs with PWM peripherals to RGB LEDs on Arty + // assign RGB LED0 R,G,B inputs = PWM0(1,2,3) when iof_1 is active + IOBUF(led0_r, dut.io.pins.gpio.pins(1)) + IOBUF(led0_g, dut.io.pins.gpio.pins(2)) + IOBUF(led0_b, dut.io.pins.gpio.pins(3)) + + // Note that this is the one which is actually connected on the HiFive/Crazy88 + // Board. Same with RGB LED1 R,G,B inputs = PWM1(1,2,3) when iof_1 is active + IOBUF(led1_r, dut.io.pins.gpio.pins(19)) + IOBUF(led1_g, dut.io.pins.gpio.pins(21)) + IOBUF(led1_b, dut.io.pins.gpio.pins(22)) + + // and RGB LED2 R,G,B inputs = PWM2(1,2,3) when iof_1 is active + IOBUF(led2_r, dut.io.pins.gpio.pins(11)) + IOBUF(led2_g, dut.io.pins.gpio.pins(12)) + IOBUF(led2_b, dut.io.pins.gpio.pins(13)) + + // Only 19 out of 20 shield pins connected to GPIO pins + // Shield pin A5 (pin 14) left unconnected + // The buttons are connected to some extra GPIO pins not connected on the + // HiFive1 board + IOBUF(btn_0, dut.io.pins.gpio.pins(15)) + IOBUF(btn_1, dut.io.pins.gpio.pins(30)) + IOBUF(btn_2, dut.io.pins.gpio.pins(31)) + + val iobuf_btn_3 = Module(new IOBUF()) + iobuf_btn_3.io.I := ~dut.io.pins.aon.pmu.dwakeup_n.o.oval + iobuf_btn_3.io.T := ~dut.io.pins.aon.pmu.dwakeup_n.o.oe + attach(btn_3, iobuf_btn_3.io.IO) + dut.io.pins.aon.pmu.dwakeup_n.i.ival := ~iobuf_btn_3.io.O & dut.io.pins.aon.pmu.dwakeup_n.o.ie + + // UART1 RX/TX pins are assigned to PMOD_D connector pins 0/1 + IOBUF(ja_0, dut.io.pins.gpio.pins(25)) // UART1 TX + IOBUF(ja_1, dut.io.pins.gpio.pins(24)) // UART1 RX + + // SPI2 pins mapped to 6 pin ICSP connector (standard on later + // arduinos) These are connected to some extra GPIO pins not connected + // on the HiFive1 board + IOBUF(ck_ss, dut.io.pins.gpio.pins(26)) + IOBUF(ck_mosi, dut.io.pins.gpio.pins(27)) + IOBUF(ck_miso, dut.io.pins.gpio.pins(28)) + IOBUF(ck_sck, dut.io.pins.gpio.pins(29)) + + // Use the LEDs for some more useful debugging things + IOBUF(led_0, ck_rst) + IOBUF(led_1, SRST_n) + IOBUF(led_2, dut.io.pins.aon.pmu.dwakeup_n.i.ival) + IOBUF(led_3, dut.io.pins.gpio.pins(14)) + + //--------------------------------------------------------------------- + // Unconnected inputs + //--------------------------------------------------------------------- + + dut.io.pins.aon.erst_n.i.ival := ~reset_periph + dut.io.pins.aon.lfextclk.i.ival := slow_clock + dut.io.pins.aon.pmu.vddpaden.i.ival := 1.U + } +} diff --git a/src/main/scala/everywhere/e300artydevkit/Platform.scala b/src/main/scala/everywhere/e300artydevkit/Platform.scala new file mode 100644 index 00000000..6e7003ef --- /dev/null +++ b/src/main/scala/everywhere/e300artydevkit/Platform.scala @@ -0,0 +1,177 @@ +// See LICENSE for license details. +package sifive.freedom.everywhere.e300artydevkit + +import Chisel._ + +import freechips.rocketchip.config._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.devices.debug._ +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.util.ResetCatchAndSync +import freechips.rocketchip.system._ + +import sifive.blocks.devices.mockaon._ +import sifive.blocks.devices.gpio._ +import sifive.blocks.devices.jtag._ +import sifive.blocks.devices.pwm._ +import sifive.blocks.devices.spi._ +import sifive.blocks.devices.uart._ +import sifive.blocks.devices.i2c._ +import sifive.blocks.devices.pinctrl._ + +//------------------------------------------------------------------------- +// PinGen +//------------------------------------------------------------------------- + +object PinGen { + def apply(): BasePin = { + val pin = new BasePin() + pin + } +} + +//------------------------------------------------------------------------- +// E300ArtyDevKitPlatformIO +//------------------------------------------------------------------------- + +class E300ArtyDevKitPlatformIO(implicit val p: Parameters) extends Bundle { + val pins = new Bundle { + val jtag = new JTAGPins(() => PinGen(), false) + val gpio = new GPIOPins(() => PinGen(), p(PeripheryGPIOKey)(0)) + val qspi = new SPIPins(() => PinGen(), p(PeripherySPIFlashKey)(0)) + val aon = new MockAONWrapperPins() + } + val jtag_reset = Bool(INPUT) + val ndreset = Bool(OUTPUT) +} + +//------------------------------------------------------------------------- +// E300ArtyDevKitPlatform +//------------------------------------------------------------------------- + +class E300ArtyDevKitPlatform(implicit val p: Parameters) extends Module { + val sys = Module(LazyModule(new E300ArtyDevKitSystem).module) + val io = new E300ArtyDevKitPlatformIO + + // This needs to be de-asserted synchronously to the coreClk. + val async_corerst = sys.aon.rsts.corerst + // Add in debug-controlled reset. + sys.reset := ResetCatchAndSync(clock, async_corerst, 20) + + //----------------------------------------------------------------------- + // Check for unsupported rocket-chip connections + //----------------------------------------------------------------------- + + require (p(NExtTopInterrupts) == 0, "No Top-level interrupts supported"); + + //----------------------------------------------------------------------- + // Build GPIO Pin Mux + //----------------------------------------------------------------------- + // Pin Mux for UART, SPI, PWM + // First convert the System outputs into "IOF" using the respective *GPIOPort + // converters. + + val sys_uart = sys.uart + val sys_pwm = sys.pwm + val sys_spi = sys.spi + val sys_i2c = sys.i2c + + val uart_pins = p(PeripheryUARTKey).map { c => Wire(new UARTPins(() => PinGen()))} + val pwm_pins = p(PeripheryPWMKey).map { c => Wire(new PWMPins(() => PinGen(), c))} + val spi_pins = p(PeripherySPIKey).map { c => Wire(new SPIPins(() => PinGen(), c))} + val i2c_pins = p(PeripheryI2CKey).map { c => Wire(new I2CPins(() => PinGen()))} + + (uart_pins zip sys_uart) map {case (p, r) => UARTPinsFromPort(p, r, clock = clock, reset = reset, syncStages = 0)} + (pwm_pins zip sys_pwm) map {case (p, r) => PWMPinsFromPort(p, r) } + (spi_pins zip sys_spi) map {case (p, r) => SPIPinsFromPort(p, r, clock = clock, reset = reset, syncStages = 0)} + (i2c_pins zip sys_i2c) map {case (p, r) => I2CPinsFromPort(p, r, clock = clock, reset = reset, syncStages = 0)} + + //----------------------------------------------------------------------- + // Default Pin connections before attaching pinmux + + for (iof_0 <- sys.gpio(0).iof_0.get) { + iof_0.default() + } + + for (iof_1 <- sys.gpio(0).iof_1.get) { + iof_1.default() + } + + //----------------------------------------------------------------------- + + val iof_0 = sys.gpio(0).iof_0.get + val iof_1 = sys.gpio(0).iof_1.get + + // SPI1 (0 is the dedicated) + BasePinToIOF(spi_pins(0).cs(0), iof_0(2)) + BasePinToIOF(spi_pins(0).dq(0), iof_0(3)) + BasePinToIOF(spi_pins(0).dq(1), iof_0(4)) + BasePinToIOF(spi_pins(0).sck, iof_0(5)) + BasePinToIOF(spi_pins(0).dq(2), iof_0(6)) + BasePinToIOF(spi_pins(0).dq(3), iof_0(7)) + BasePinToIOF(spi_pins(0).cs(1), iof_0(8)) + BasePinToIOF(spi_pins(0).cs(2), iof_0(9)) + BasePinToIOF(spi_pins(0).cs(3), iof_0(10)) + + // SPI2 + BasePinToIOF(spi_pins(1).cs(0), iof_0(26)) + BasePinToIOF(spi_pins(1).dq(0), iof_0(27)) + BasePinToIOF(spi_pins(1).dq(1), iof_0(28)) + BasePinToIOF(spi_pins(1).sck, iof_0(29)) + BasePinToIOF(spi_pins(1).dq(2), iof_0(30)) + BasePinToIOF(spi_pins(1).dq(3), iof_0(31)) + + // I2C + if (p(PeripheryI2CKey).length == 1) { + BasePinToIOF(i2c_pins(0).sda, iof_0(12)) + BasePinToIOF(i2c_pins(0).scl, iof_0(13)) + } + + // UART0 + BasePinToIOF(uart_pins(0).rxd, iof_0(16)) + BasePinToIOF(uart_pins(0).txd, iof_0(17)) + + // UART1 + BasePinToIOF(uart_pins(1).rxd, iof_0(24)) + BasePinToIOF(uart_pins(1).txd, iof_0(25)) + + //PWM + BasePinToIOF(pwm_pins(0).pwm(0), iof_1(0) ) + BasePinToIOF(pwm_pins(0).pwm(1), iof_1(1) ) + BasePinToIOF(pwm_pins(0).pwm(2), iof_1(2) ) + BasePinToIOF(pwm_pins(0).pwm(3), iof_1(3) ) + + BasePinToIOF(pwm_pins(1).pwm(1), iof_1(19)) + BasePinToIOF(pwm_pins(1).pwm(0), iof_1(20)) + BasePinToIOF(pwm_pins(1).pwm(2), iof_1(21)) + BasePinToIOF(pwm_pins(1).pwm(3), iof_1(22)) + + BasePinToIOF(pwm_pins(2).pwm(0), iof_1(10)) + BasePinToIOF(pwm_pins(2).pwm(1), iof_1(11)) + BasePinToIOF(pwm_pins(2).pwm(2), iof_1(12)) + BasePinToIOF(pwm_pins(2).pwm(3), iof_1(13)) + + //----------------------------------------------------------------------- + // Drive actual Pads + //----------------------------------------------------------------------- + + // Result of Pin Mux + GPIOPinsFromPort(io.pins.gpio, sys.gpio(0)) + + // Dedicated SPI Pads + SPIPinsFromPort(io.pins.qspi, sys.qspi(0), clock = sys.clock, reset = sys.reset, syncStages = 3) + + // JTAG Debug Interface + val sjtag = sys.debug.systemjtag.get + JTAGPinsFromPort(io.pins.jtag, sjtag.jtag) + sjtag.reset := io.jtag_reset + sjtag.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W) + + io.ndreset := sys.debug.ndreset + + // AON Pads -- direct connection is OK because + // EnhancedPin is hard-coded in MockAONPads + // and thus there is no .fromPort method. + io.pins.aon <> sys.aon.pins +} diff --git a/src/main/scala/everywhere/e300artydevkit/System.scala b/src/main/scala/everywhere/e300artydevkit/System.scala new file mode 100644 index 00000000..93d93529 --- /dev/null +++ b/src/main/scala/everywhere/e300artydevkit/System.scala @@ -0,0 +1,50 @@ +// See LICENSE for license details. +package sifive.freedom.everywhere.e300artydevkit + +import Chisel._ + +import freechips.rocketchip.config._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.devices.debug._ +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.system._ + +import sifive.blocks.devices.mockaon._ +import sifive.blocks.devices.gpio._ +import sifive.blocks.devices.pwm._ +import sifive.blocks.devices.spi._ +import sifive.blocks.devices.uart._ +import sifive.blocks.devices.i2c._ + +//------------------------------------------------------------------------- +// E300ArtyDevKitSystem +//------------------------------------------------------------------------- + +class E300ArtyDevKitSystem(implicit p: Parameters) extends RocketSubsystem + with HasPeripheryMaskROMSlave + with HasPeripheryDebug + with HasPeripheryMockAON + with HasPeripheryUART + with HasPeripherySPIFlash + with HasPeripherySPI + with HasPeripheryGPIO + with HasPeripheryPWM + with HasPeripheryI2C { + override lazy val module = new E300ArtyDevKitSystemModule(this) +} + +class E300ArtyDevKitSystemModule[+L <: E300ArtyDevKitSystem](_outer: L) + extends RocketSubsystemModuleImp(_outer) + with HasPeripheryDebugModuleImp + with HasPeripheryUARTModuleImp + with HasPeripherySPIModuleImp + with HasPeripheryGPIOModuleImp + with HasPeripherySPIFlashModuleImp + with HasPeripheryMockAONModuleImp + with HasPeripheryPWMModuleImp + with HasPeripheryI2CModuleImp { + // Reset vector is set to the location of the mask rom + val maskROMParams = p(PeripheryMaskROMKey) + global_reset_vector := maskROMParams(0).address.U +}