aboutsummaryrefslogtreecommitdiff
path: root/VexRiscv/doc/gcdPeripheral/src/main/scala
diff options
context:
space:
mode:
Diffstat (limited to 'VexRiscv/doc/gcdPeripheral/src/main/scala')
-rw-r--r--VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala559
-rw-r--r--VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/Apb3GCDCtrl.scala39
-rw-r--r--VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDCtrl.scala68
-rw-r--r--VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDData.scala54
-rw-r--r--VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTop.scala46
-rw-r--r--VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTopSim.scala52
6 files changed, 818 insertions, 0 deletions
diff --git a/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala b/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala
new file mode 100644
index 0000000..f3d4f6c
--- /dev/null
+++ b/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala
@@ -0,0 +1,559 @@
+package vexriscv.demo
+
+import spinal.core._
+import spinal.lib._
+import spinal.lib.bus.amba3.apb._
+import spinal.lib.bus.misc.SizeMapping
+import spinal.lib.bus.simple.PipelinedMemoryBus
+import spinal.lib.com.jtag.Jtag
+import spinal.lib.com.spi.ddr.SpiXdrMaster
+import spinal.lib.com.uart._
+import spinal.lib.io.{InOutWrapper, TriStateArray}
+import spinal.lib.misc.{InterruptCtrl, Prescaler, Timer}
+import spinal.lib.soc.pinsec.{PinsecTimerCtrl, PinsecTimerCtrlExternal}
+import vexriscv.plugin._
+import vexriscv.{VexRiscv, VexRiscvConfig, plugin}
+import spinal.lib.com.spi.ddr._
+import spinal.lib.bus.simple._
+import scala.collection.mutable.ArrayBuffer
+import vexriscv.periph.gcd._
+import vexriscv.periph.tasks.gen._
+import vexriscv.periph.tasks.map._
+import vexriscv.periph.tasks.sort._
+import vexriscv.periph.tasks.max._
+import vexriscv.periph.tasks.sum._
+import vexriscv.periph.tasks.hash._
+
+/** Created by PIC32F_USER on 28/07/2017.
+ *
+ * Murax is a very light SoC which could work without any external component.
+ * - ICE40-hx8k + icestorm => 53 Mhz, 2142 LC
+ * - 0.37 DMIPS/Mhz
+ * - 8 kB of on-chip ram
+ * - JTAG debugger (eclipse/GDB/openocd ready)
+ * - Interrupt support
+ * - APB bus for peripherals
+ * - 32 GPIO pin
+ * - one 16 bits prescaler, two 16 bits timers
+ * - one UART with tx/rx fifo
+ */
+
+case class MuraxConfig(
+ coreFrequency: HertzNumber,
+ onChipRamSize: BigInt,
+ onChipRamHexFile: String,
+ pipelineDBus: Boolean,
+ pipelineMainBus: Boolean,
+ pipelineApbBridge: Boolean,
+ gpioWidth: Int,
+ uartCtrlConfig: UartCtrlMemoryMappedConfig,
+ xipConfig: SpiXdrMasterCtrl.MemoryMappingParameters,
+ hardwareBreakpointCount: Int,
+ cpuPlugins: ArrayBuffer[Plugin[VexRiscv]]
+) {
+ require(
+ pipelineApbBridge || pipelineMainBus,
+ "At least pipelineMainBus or pipelineApbBridge should be enable to avoid wipe transactions"
+ )
+ val genXip = xipConfig != null
+
+}
+
+object MuraxConfig {
+ def default: MuraxConfig = default(false, false)
+ def default(withXip: Boolean = false, bigEndian: Boolean = false) =
+ MuraxConfig(
+ coreFrequency = 12 MHz,
+ onChipRamSize = 8 kB,
+ onChipRamHexFile = null,
+ pipelineDBus = true,
+ pipelineMainBus = false,
+ pipelineApbBridge = true,
+ gpioWidth = 32,
+ xipConfig = ifGen(withXip)(
+ SpiXdrMasterCtrl.MemoryMappingParameters(
+ SpiXdrMasterCtrl
+ .Parameters(8, 12, SpiXdrParameter(2, 2, 1))
+ .addFullDuplex(0, 1, false),
+ cmdFifoDepth = 32,
+ rspFifoDepth = 32,
+ xip = SpiXdrMasterCtrl
+ .XipBusParameters(addressWidth = 24, lengthWidth = 2)
+ )
+ ),
+ hardwareBreakpointCount = if (withXip) 3 else 0,
+ cpuPlugins = ArrayBuffer( //DebugPlugin added by the toplevel
+ new IBusSimplePlugin(
+ resetVector = if (withXip) 0xf001e000L else 0x80000000L,
+ cmdForkOnSecondStage = true,
+ cmdForkPersistence = withXip, //Required by the Xip controller
+ prediction = NONE,
+ catchAccessFault = false,
+ compressedGen = false,
+ bigEndian = bigEndian
+ ),
+ new DBusSimplePlugin(
+ catchAddressMisaligned = false,
+ catchAccessFault = false,
+ earlyInjection = false,
+ bigEndian = bigEndian
+ ),
+ new CsrPlugin(
+ CsrPluginConfig.smallest(mtvecInit =
+ if (withXip) 0xe0040020L else 0x80000020L
+ )
+ ),
+ new DecoderSimplePlugin(
+ catchIllegalInstruction = false
+ ),
+ new RegFilePlugin(
+ regFileReadyKind = plugin.SYNC,
+ zeroBoot = false
+ ),
+ new IntAluPlugin,
+ new SrcPlugin(
+ separatedAddSub = false,
+ executeInsertion = false
+ ),
+ new LightShifterPlugin,
+ new HazardSimplePlugin(
+ bypassExecute = false,
+ bypassMemory = false,
+ bypassWriteBack = false,
+ bypassWriteBackBuffer = false,
+ pessimisticUseSrc = false,
+ pessimisticWriteRegFile = false,
+ pessimisticAddressMatch = false
+ ),
+ new BranchPlugin(
+ earlyBranch = false,
+ catchAddressMisaligned = false
+ ),
+ new YamlPlugin("cpu0.yaml")
+ ),
+ uartCtrlConfig = UartCtrlMemoryMappedConfig(
+ uartCtrlConfig = UartCtrlGenerics(
+ dataWidthMax = 8,
+ clockDividerWidth = 20,
+ preSamplingSize = 1,
+ samplingSize = 3,
+ postSamplingSize = 1
+ ),
+ initConfig = UartCtrlInitConfig(
+ baudrate = 115200,
+ dataLength = 7, //7 => 8 bits
+ parity = UartParityType.NONE,
+ stop = UartStopType.ONE
+ ),
+ busCanWriteClockDividerConfig = false,
+ busCanWriteFrameConfig = false,
+ txFifoDepth = 16,
+ rxFifoDepth = 16
+ )
+ )
+
+ def fast = {
+ val config = default
+
+ //Replace HazardSimplePlugin to get datapath bypass
+ config.cpuPlugins(
+ config.cpuPlugins.indexWhere(_.isInstanceOf[HazardSimplePlugin])
+ ) = new HazardSimplePlugin(
+ bypassExecute = true,
+ bypassMemory = true,
+ bypassWriteBack = true,
+ bypassWriteBackBuffer = true
+ )
+// config.cpuPlugins(config.cpuPlugins.indexWhere(_.isInstanceOf[LightShifterPlugin])) = new FullBarrelShifterPlugin()
+
+ config
+ }
+}
+
+case class Murax(config: MuraxConfig) extends Component {
+ import config._
+
+ val io = new Bundle {
+ //Clocks / reset
+ val asyncReset = in Bool ()
+ val mainClk = in Bool ()
+
+ //Main components IO
+ val jtag = slave(Jtag())
+
+ //Peripherals IO
+ val gpioA = master(TriStateArray(gpioWidth bits))
+ val uart = master(Uart())
+
+ val xip = ifGen(genXip)(master(SpiXdrMaster(xipConfig.ctrl.spi)))
+ }
+
+ val resetCtrlClockDomain = ClockDomain(
+ clock = io.mainClk,
+ config = ClockDomainConfig(
+ resetKind = BOOT
+ )
+ )
+
+ val resetCtrl = new ClockingArea(resetCtrlClockDomain) {
+ val mainClkResetUnbuffered = False
+
+ //Implement an counter to keep the reset axiResetOrder high 64 cycles
+ // Also this counter will automatically do a reset when the system boot.
+ val systemClkResetCounter = Reg(UInt(6 bits)) init (0)
+ when(systemClkResetCounter =/= U(systemClkResetCounter.range -> true)) {
+ systemClkResetCounter := systemClkResetCounter + 1
+ mainClkResetUnbuffered := True
+ }
+ when(BufferCC(io.asyncReset)) {
+ systemClkResetCounter := 0
+ }
+
+ //Create all reset used later in the design
+ val mainClkReset = RegNext(mainClkResetUnbuffered)
+ val systemReset = RegNext(mainClkResetUnbuffered)
+ }
+
+ val systemClockDomain = ClockDomain(
+ clock = io.mainClk,
+ reset = resetCtrl.systemReset,
+ frequency = FixedFrequency(coreFrequency)
+ )
+
+ val debugClockDomain = ClockDomain(
+ clock = io.mainClk,
+ reset = resetCtrl.mainClkReset,
+ frequency = FixedFrequency(coreFrequency)
+ )
+
+ val system = new ClockingArea(systemClockDomain) {
+ val pipelinedMemoryBusConfig = PipelinedMemoryBusConfig(
+ addressWidth = 32,
+ dataWidth = 32
+ )
+
+ val bigEndianDBus = config.cpuPlugins.exists(_ match {
+ case plugin: DBusSimplePlugin => plugin.bigEndian
+ case _ => false
+ })
+
+ //Arbiter of the cpu dBus/iBus to drive the mainBus
+ //Priority to dBus, !! cmd transactions can change on the fly !!
+ val mainBusArbiter =
+ new MuraxMasterArbiter(pipelinedMemoryBusConfig, bigEndianDBus)
+
+ //Instanciate the CPU
+ val cpu = new VexRiscv(
+ config = VexRiscvConfig(
+ plugins = cpuPlugins += new DebugPlugin(
+ debugClockDomain,
+ hardwareBreakpointCount
+ )
+ )
+ )
+
+ //Checkout plugins used to instanciate the CPU to connect them to the SoC
+ val timerInterrupt = False
+ val externalInterrupt = False
+ for (plugin <- cpu.plugins) plugin match {
+ case plugin: IBusSimplePlugin =>
+ mainBusArbiter.io.iBus.cmd <> plugin.iBus.cmd
+ mainBusArbiter.io.iBus.rsp <> plugin.iBus.rsp
+ case plugin: DBusSimplePlugin => {
+ if (!pipelineDBus)
+ mainBusArbiter.io.dBus <> plugin.dBus
+ else {
+ mainBusArbiter.io.dBus.cmd << plugin.dBus.cmd.halfPipe()
+ mainBusArbiter.io.dBus.rsp <> plugin.dBus.rsp
+ }
+ }
+ case plugin: CsrPlugin => {
+ plugin.externalInterrupt := externalInterrupt
+ plugin.timerInterrupt := timerInterrupt
+ }
+ case plugin: DebugPlugin =>
+ plugin.debugClockDomain {
+ resetCtrl.systemReset setWhen (RegNext(plugin.io.resetOut))
+ io.jtag <> plugin.io.bus.fromJtag()
+ }
+ case _ =>
+ }
+
+ //****** MainBus slaves ********
+ val mainBusMapping = ArrayBuffer[(PipelinedMemoryBus, SizeMapping)]()
+ val ram = new MuraxPipelinedMemoryBusRam(
+ onChipRamSize = onChipRamSize,
+ onChipRamHexFile = onChipRamHexFile,
+ pipelinedMemoryBusConfig = pipelinedMemoryBusConfig,
+ bigEndian = bigEndianDBus
+ )
+ mainBusMapping += ram.io.bus -> (0x80000000L, onChipRamSize)
+
+ val apbBridge = new PipelinedMemoryBusToApbBridge(
+ apb3Config = Apb3Config(
+ addressWidth = 20,
+ dataWidth = 32
+ ),
+ pipelineBridge = pipelineApbBridge,
+ pipelinedMemoryBusConfig = pipelinedMemoryBusConfig
+ )
+ mainBusMapping += apbBridge.io.pipelinedMemoryBus -> (0xf0000000L, 1 MB)
+
+ //******** APB peripherals *********
+ val apbMapping = ArrayBuffer[(Apb3, SizeMapping)]()
+ val gpioACtrl = Apb3Gpio(gpioWidth = gpioWidth, withReadSync = true)
+ io.gpioA <> gpioACtrl.io.gpio
+ apbMapping += gpioACtrl.io.apb -> (0x00000, 4 kB)
+
+ val uartCtrl = Apb3UartCtrl(uartCtrlConfig)
+ uartCtrl.io.uart <> io.uart
+ externalInterrupt setWhen (uartCtrl.io.interrupt)
+ apbMapping += uartCtrl.io.apb -> (0x10000, 4 kB)
+
+ val timer = new MuraxApb3Timer()
+ timerInterrupt setWhen (timer.io.interrupt)
+ apbMapping += timer.io.apb -> (0x20000, 4 kB)
+
+ val gcd = new Apb3GCDCtrl(
+ apb3Config = Apb3Config(
+ addressWidth = 20,
+ dataWidth = 32
+ )
+ )
+ apbMapping += gcd.io.apb -> (0x30000, 1 kB)
+
+ val xip = ifGen(genXip)(new Area {
+ val ctrl = Apb3SpiXdrMasterCtrl(xipConfig)
+ ctrl.io.spi <> io.xip
+ externalInterrupt setWhen (ctrl.io.interrupt)
+ apbMapping += ctrl.io.apb -> (0x1f000, 4 kB)
+
+ val accessBus = new PipelinedMemoryBus(PipelinedMemoryBusConfig(24, 32))
+ mainBusMapping += accessBus -> (0xe0000000L, 16 MB)
+
+ ctrl.io.xip.fromPipelinedMemoryBus() << accessBus
+ val bootloader = Apb3Rom("src/main/c/murax/xipBootloader/crt.bin")
+ apbMapping += bootloader.io.apb -> (0x1e000, 4 kB)
+ })
+
+ //******** Memory mappings *********
+ val apbDecoder = Apb3Decoder(
+ master = apbBridge.io.apb,
+ slaves = apbMapping
+ )
+
+ val mainBusDecoder = new Area {
+ val logic = new MuraxPipelinedMemoryBusDecoder(
+ master = mainBusArbiter.io.masterBus,
+ specification = mainBusMapping,
+ pipelineMaster = pipelineMainBus
+ )
+ }
+ }
+}
+
+object Murax {
+ def main(args: Array[String]) {
+ SpinalVerilog(Murax(MuraxConfig.default))
+ }
+}
+
+object Murax_iCE40_hx8k_breakout_board_xip {
+
+ case class SB_GB() extends BlackBox {
+ val USER_SIGNAL_TO_GLOBAL_BUFFER = in Bool ()
+ val GLOBAL_BUFFER_OUTPUT = out Bool ()
+ }
+
+ case class SB_IO_SCLK() extends BlackBox {
+ addGeneric("PIN_TYPE", B"010000")
+ val PACKAGE_PIN = out Bool ()
+ val OUTPUT_CLK = in Bool ()
+ val CLOCK_ENABLE = in Bool ()
+ val D_OUT_0 = in Bool ()
+ val D_OUT_1 = in Bool ()
+ setDefinitionName("SB_IO")
+ }
+
+ case class SB_IO_DATA() extends BlackBox {
+ addGeneric("PIN_TYPE", B"110000")
+ val PACKAGE_PIN = inout(Analog(Bool))
+ val CLOCK_ENABLE = in Bool ()
+ val INPUT_CLK = in Bool ()
+ val OUTPUT_CLK = in Bool ()
+ val OUTPUT_ENABLE = in Bool ()
+ val D_OUT_0 = in Bool ()
+ val D_OUT_1 = in Bool ()
+ val D_IN_0 = out Bool ()
+ val D_IN_1 = out Bool ()
+ setDefinitionName("SB_IO")
+ }
+
+ case class Murax_iCE40_hx8k_breakout_board_xip() extends Component {
+ val io = new Bundle {
+ val mainClk = in Bool ()
+ val jtag_tck = in Bool ()
+ val jtag_tdi = in Bool ()
+ val jtag_tdo = out Bool ()
+ val jtag_tms = in Bool ()
+ val uart_txd = out Bool ()
+ val uart_rxd = in Bool ()
+
+ val mosi = inout(Analog(Bool))
+ val miso = inout(Analog(Bool))
+ val sclk = out Bool ()
+ val spis = out Bool ()
+
+ val led = out Bits (8 bits)
+ }
+ val murax = Murax(
+ MuraxConfig.default(withXip = true).copy(onChipRamSize = 8 kB)
+ )
+ murax.io.asyncReset := False
+
+ val mainClkBuffer = SB_GB()
+ mainClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.mainClk
+ mainClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.mainClk
+
+ val jtagClkBuffer = SB_GB()
+ jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck
+ jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck
+
+ io.led <> murax.io.gpioA.write(7 downto 0)
+
+ murax.io.jtag.tdi <> io.jtag_tdi
+ murax.io.jtag.tdo <> io.jtag_tdo
+ murax.io.jtag.tms <> io.jtag_tms
+ murax.io.gpioA.read <> 0
+ murax.io.uart.txd <> io.uart_txd
+ murax.io.uart.rxd <> io.uart_rxd
+
+ val xip = new ClockingArea(murax.systemClockDomain) {
+ RegNext(murax.io.xip.ss.asBool) <> io.spis
+
+ val sclkIo = SB_IO_SCLK()
+ sclkIo.PACKAGE_PIN <> io.sclk
+ sclkIo.CLOCK_ENABLE := True
+
+ sclkIo.OUTPUT_CLK := ClockDomain.current.readClockWire
+ sclkIo.D_OUT_0 <> murax.io.xip.sclk.write(0)
+ sclkIo.D_OUT_1 <> RegNext(murax.io.xip.sclk.write(1))
+
+ val datas =
+ for ((data, pin) <- (murax.io.xip.data, List(io.mosi, io.miso)).zipped)
+ yield new Area {
+ val dataIo = SB_IO_DATA()
+ dataIo.PACKAGE_PIN := pin
+ dataIo.CLOCK_ENABLE := True
+
+ dataIo.OUTPUT_CLK := ClockDomain.current.readClockWire
+ dataIo.OUTPUT_ENABLE <> data.writeEnable
+ dataIo.D_OUT_0 <> data.write(0)
+ dataIo.D_OUT_1 <> RegNext(data.write(1))
+
+ dataIo.INPUT_CLK := ClockDomain.current.readClockWire
+ data.read(0) := dataIo.D_IN_0
+ data.read(1) := RegNext(dataIo.D_IN_1)
+ }
+ }
+
+ }
+
+ def main(args: Array[String]) {
+ SpinalVerilog(Murax_iCE40_hx8k_breakout_board_xip())
+ }
+}
+
+object MuraxDhrystoneReady {
+ def main(args: Array[String]) {
+ SpinalVerilog(Murax(MuraxConfig.fast.copy(onChipRamSize = 256 kB)))
+ }
+}
+
+object MuraxDhrystoneReadyMulDivStatic {
+ def main(args: Array[String]) {
+ SpinalVerilog({
+ val config = MuraxConfig.fast.copy(onChipRamSize = 256 kB)
+ config.cpuPlugins += new MulPlugin
+ config.cpuPlugins += new DivPlugin
+ config.cpuPlugins.remove(
+ config.cpuPlugins.indexWhere(_.isInstanceOf[BranchPlugin])
+ )
+ config.cpuPlugins += new BranchPlugin(
+ earlyBranch = false,
+ catchAddressMisaligned = false
+ )
+ config.cpuPlugins += new IBusSimplePlugin(
+ resetVector = 0x80000000L,
+ cmdForkOnSecondStage = true,
+ cmdForkPersistence = false,
+ prediction = STATIC,
+ catchAccessFault = false,
+ compressedGen = false
+ )
+ config.cpuPlugins.remove(
+ config.cpuPlugins.indexWhere(_.isInstanceOf[LightShifterPlugin])
+ )
+ config.cpuPlugins += new FullBarrelShifterPlugin
+ Murax(config)
+ })
+ }
+}
+
+//Will blink led and echo UART RX to UART TX (in the verilator sim, type some text and press enter to send UART frame to the Murax RX pin)
+object MuraxWithRamInit {
+ def main(args: Array[String]) {
+ SpinalVerilog(
+ Murax(
+ MuraxConfig.default.copy(
+ onChipRamSize = 4 kB,
+ onChipRamHexFile = "src/main/c/murax/gcd_world/build/gcd_world.hex"
+ )
+ )
+ )
+ .printPruned()
+ }
+}
+
+object MuraxWithRamInitSynth {
+ def main(args: Array[String]) {
+ val config = SpinalConfig(
+ targetDirectory = "synth",
+ defaultClockDomainFrequency = FixedFrequency(12 MHz)
+ )
+ config
+ .generateVerilog(
+ Murax(
+ MuraxConfig.default.copy(
+ onChipRamSize = 4 kB,
+ onChipRamHexFile = "src/main/c/murax/gcd_world/build/gcd_world.hex"
+ )
+ )
+ )
+ .printPruned()
+ }
+}
+
+object Murax_arty {
+ def main(args: Array[String]) {
+ val hex = "src/main/c/murax/hello_world/build/hello_world.hex"
+ SpinalVerilog(
+ Murax(
+ MuraxConfig
+ .default(false)
+ .copy(
+ coreFrequency = 100 MHz,
+ onChipRamSize = 32 kB,
+ onChipRamHexFile = hex
+ )
+ )
+ )
+ }
+}
+
+object MuraxAsicBlackBox extends App {
+ println("Warning this soc do not has any rom to boot on.")
+ val config = SpinalConfig()
+ config.addStandardMemBlackboxing(blackboxAll)
+ config.generateVerilog(Murax(MuraxConfig.default()))
+}
diff --git a/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/Apb3GCDCtrl.scala b/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/Apb3GCDCtrl.scala
new file mode 100644
index 0000000..2ec7401
--- /dev/null
+++ b/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/Apb3GCDCtrl.scala
@@ -0,0 +1,39 @@
+package vexriscv.periph.gcd
+
+import spinal.core._
+import spinal.lib._
+import spinal.lib.bus.amba3.apb.{Apb3, Apb3Config, Apb3SlaveFactory}
+import spinal.lib.eda.altera.QSysify
+import spinal.lib.slave
+
+object Apb3GCDCtrl {
+ def getApb3Config = Apb3Config(
+ addressWidth = 5,
+ dataWidth = 32,
+ selWidth = 1,
+ useSlaveError = false
+ )
+}
+
+class Apb3GCDCtrl(apb3Config : Apb3Config) extends Component {
+ val io = new Bundle {
+ val apb = slave(Apb3(Apb3GCDCtrl.getApb3Config))
+ // maybe later
+ // val interrupt = out Bool
+ }
+ val gcdCtrl = new GCDTop()
+ val apbCtrl = Apb3SlaveFactory(io.apb)
+ apbCtrl.driveAndRead(gcdCtrl.io.a, address=0)
+ apbCtrl.driveAndRead(gcdCtrl.io.b, address=4)
+ // when result of calculation ready, synchronize it into memory mapped register
+ val resSyncBuf = RegNextWhen(gcdCtrl.io.res, gcdCtrl.io.ready)
+ apbCtrl.read(resSyncBuf, address=8)
+ // if result is read, it will be consumed, set ready to 0
+ apbCtrl.onRead(8)(resSyncBuf := 0)
+ apbCtrl.onRead(8)(rdySyncBuf := False)
+ // synchronize ready signal into memory mapped register
+ val rdySyncBuf = RegNextWhen(gcdCtrl.io.ready, gcdCtrl.io.ready)
+ apbCtrl.read(rdySyncBuf, address=12)
+ // set valid based on memory mapped register but clear/consume it after 1 cycle <s
+ gcdCtrl.io.valid := apbCtrl.setOnSet(RegNext(False) init(False), address=16, 0)
+}
diff --git a/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDCtrl.scala b/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDCtrl.scala
new file mode 100644
index 0000000..e4b814f
--- /dev/null
+++ b/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDCtrl.scala
@@ -0,0 +1,68 @@
+package vexriscv.periph.gcd
+
+import spinal.core._
+import spinal.lib._
+import spinal.lib.master
+import spinal.lib.fsm._
+
+//Hardware definition
+class GCDCtrl() extends Component {
+ val io = new Bundle {
+ val valid = in Bool()
+ val ready = out Bool()
+ val dataCtrl = master(GCDDataControl())
+ }
+ val fsm = new StateMachine{
+ io.dataCtrl.loadA := False
+ io.dataCtrl.loadB := False
+ io.dataCtrl.init := False
+ io.dataCtrl.selL := False
+ io.dataCtrl.selR := False
+ io.ready := False
+ val idle : State = new State with EntryPoint{
+ whenIsActive{
+ when(io.valid){
+ io.dataCtrl.init := True
+ goto(calculate)
+ }
+ }
+ }
+ val calculate : State = new State{
+ whenIsActive{
+ when(io.dataCtrl.cmpAgtB){
+ goto(calcA)
+ }.elsewhen(io.dataCtrl.cmpAltB){
+ goto(calcB)
+ }.elsewhen(!io.dataCtrl.cmpAgtB & !io.dataCtrl.cmpAgtB){
+ goto(calcDone)
+ }
+ }
+ }
+ val calcA : State = new State{
+ whenIsActive{
+ io.dataCtrl.selR := True
+ io.dataCtrl.loadA := True
+ goto(calculate)
+ }
+ }
+ val calcB : State = new State{
+ whenIsActive{
+ io.dataCtrl.selL := True
+ io.dataCtrl.loadB := True
+ goto(calculate)
+ }
+ }
+ val calcDone : State = new State{
+ whenIsActive{
+ io.ready := True
+ goto(idle)
+ }
+ }
+ }
+}
+
+object GCDCtrlVerilog {
+ def main(args: Array[String]) {
+ SpinalVerilog(new GCDCtrl)
+ }
+} \ No newline at end of file
diff --git a/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDData.scala b/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDData.scala
new file mode 100644
index 0000000..88e58ad
--- /dev/null
+++ b/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDData.scala
@@ -0,0 +1,54 @@
+package vexriscv.periph.gcd
+
+import spinal.core._
+import spinal.lib._
+import spinal.lib.slave
+
+//Hardware definition
+class GCDData() extends Component {
+ val io = new Bundle {
+ val a = in(UInt(32 bits))
+ val b = in(UInt(32 bits))
+ val res = out(UInt(32 bits))
+ val dataCtrl = slave(GCDDataControl())
+ }
+ /*
+ *
+ * // Pseudocode of the Euclids algorithm for calculating the GCD
+ * inputs: [a, b, start]
+ * outputs: [done, a]
+ * done := False
+ * while(!done):
+ * if(a > b):
+ * a := a - b
+ * else if(b > a):
+ * b := b - a
+ * else:
+ * done := True
+ */
+ //registers
+ val regA = Reg(UInt(32 bits)) init(0)
+ val regB = Reg(UInt(32 bits)) init(0)
+ // compare
+ val xGTy = regA > regB
+ val xLTy = regA < regB
+ // mux
+ val chX = io.dataCtrl.selL ? regB | regA
+ val chY = io.dataCtrl.selR ? regB | regA
+ // subtract
+ val subXY = chX - chY
+ // load logic
+ when(io.dataCtrl.init){
+ regA := io.a
+ regB := io.b
+ }
+ when(io.dataCtrl.loadA){
+ regA := subXY
+ }
+ when(io.dataCtrl.loadB){
+ regB := subXY
+ }
+ io.dataCtrl.cmpAgtB := xGTy
+ io.dataCtrl.cmpAltB := xLTy
+ io.res := regA
+} \ No newline at end of file
diff --git a/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTop.scala b/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTop.scala
new file mode 100644
index 0000000..654e9b8
--- /dev/null
+++ b/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTop.scala
@@ -0,0 +1,46 @@
+package vexriscv.periph.gcd
+
+import spinal.core._
+import spinal.lib._
+import spinal.lib.IMasterSlave
+
+case class GCDDataControl() extends Bundle with IMasterSlave{
+ val cmpAgtB = Bool
+ val cmpAltB = Bool
+ val loadA = Bool
+ val loadB = Bool
+ val init = Bool
+ val selL = Bool
+ val selR = Bool
+ // define <> semantic
+ override def asMaster(): Unit = {
+ // as controller: output, input
+ out(loadA, loadB, selL, selR, init)
+ in(cmpAgtB, cmpAltB)
+ }
+}
+
+//Hardware definition
+class GCDTop() extends Component {
+ val io = new Bundle {
+ val valid = in Bool()
+ val ready = out Bool()
+ val a = in(UInt(32 bits))
+ val b = in(UInt(32 bits))
+ val res = out(UInt(32 bits))
+ }
+ val gcdCtr = new GCDCtrl()
+ gcdCtr.io.valid := io.valid
+ io.ready := gcdCtr.io.ready
+ val gcdDat = new GCDData()
+ gcdDat.io.a := io.a
+ gcdDat.io.b := io.b
+ io.res := gcdDat.io.res
+ gcdCtr.io.dataCtrl <> gcdDat.io.dataCtrl
+}
+
+object GCDTopVerilog {
+ def main(args: Array[String]) {
+ SpinalVerilog(new GCDTop)
+ }
+} \ No newline at end of file
diff --git a/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTopSim.scala b/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTopSim.scala
new file mode 100644
index 0000000..53ea8dc
--- /dev/null
+++ b/VexRiscv/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTopSim.scala
@@ -0,0 +1,52 @@
+package vexriscv.periph.gcd
+
+import spinal.core._
+import spinal.sim._
+import spinal.core.sim._
+
+//import scala.util.Random
+import java.util.concurrent.ThreadLocalRandom
+object GCDTopSim {
+ def main(args: Array[String]) {
+
+ SimConfig.withWave.doSim(new GCDTop()){dut =>
+ // SimConfig.doSim(new GCDTop()){dut =>
+ def gcd(a: Long,b: Long): Long = {
+ if(b==0) a else gcd(b, a%b)
+ }
+ def RndNextUInt32(): Long = {
+ ThreadLocalRandom.current().nextLong(Math.pow(2, 32).toLong - 1)
+ }
+ var a = 0L
+ var b = 0L
+ var model = 0L
+ dut.io.a #= 0
+ dut.io.b #= 0
+ dut.io.valid #= false
+
+ dut.clockDomain.forkStimulus(period = 10)
+ dut.clockDomain.waitRisingEdge()
+
+ for(idx <- 0 to 500){
+ // generate 2 random ints
+ a = RndNextUInt32()
+ b = RndNextUInt32()
+ // calculate the model value (software)
+ model = gcd(a,b)
+ // apply stimulus with random ints
+ dut.io.a #= a
+ dut.io.b #= b
+ dut.io.valid #= true
+ dut.clockDomain.waitRisingEdge()
+ dut.io.valid #= false
+ // wait until calculation of hardware is done
+ waitUntil(dut.io.ready.toBoolean)
+ assert(
+ assertion = (dut.io.res.toBigInt == model),
+ message = "test " + idx + " failed. Expected " + model + ", retrieved: " + dut.io.res.toBigInt
+ )
+ waitUntil(!dut.io.ready.toBoolean)
+ }
+ }
+ }
+}