From 5a553741f03ce78fba68e8e88d0d35f4214a9ac2 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 22 Jan 2024 18:32:48 -0800 Subject: [PATCH 01/13] Improve GCD example --- .../chipyard/src/main/scala/example/GCD.scala | 196 +++++++++++------- 1 file changed, 116 insertions(+), 80 deletions(-) diff --git a/generators/chipyard/src/main/scala/example/GCD.scala b/generators/chipyard/src/main/scala/example/GCD.scala index 24c99187..3ed202ac 100644 --- a/generators/chipyard/src/main/scala/example/GCD.scala +++ b/generators/chipyard/src/main/scala/example/GCD.scala @@ -4,6 +4,7 @@ import chisel3._ import chisel3.util._ import chisel3.experimental.{IntParam, BaseModule} import freechips.rocketchip.amba.axi4._ +import freechips.rocketchip.prci._ import freechips.rocketchip.subsystem.BaseSubsystem import org.chipsalliance.cde.config.{Parameters, Field, Config} import freechips.rocketchip.diplomacy._ @@ -36,27 +37,24 @@ class GCDIO(val w: Int) extends Bundle { val busy = Output(Bool()) } -trait GCDTopIO extends Bundle { +class GCDTopIO extends Bundle { val gcd_busy = Output(Bool()) } -trait HasGCDIO extends BaseModule { - val w: Int - val io = IO(new GCDIO(w)) +trait HasGCDTopIO { + def io: GCDTopIO } // DOC include start: GCD blackbox -class GCDMMIOBlackBox(val w: Int) extends BlackBox(Map("WIDTH" -> IntParam(w))) with HasBlackBoxResource - with HasGCDIO -{ +class GCDMMIOBlackBox(val w: Int) extends BlackBox(Map("WIDTH" -> IntParam(w))) with HasBlackBoxResource { + val io = IO(new GCDIO(w)) addResource("/vsrc/GCDMMIOBlackBox.v") } // DOC include end: GCD blackbox // DOC include start: GCD chisel -class GCDMMIOChiselModule(val w: Int) extends Module - with HasGCDIO -{ +class GCDMMIOChiselModule(val w: Int) extends Module { + val io = IO(new GCDIO(w)) val s_idle :: s_run :: s_done :: Nil = Enum(3) val state = RegInit(s_idle) @@ -90,70 +88,111 @@ class GCDMMIOChiselModule(val w: Int) extends Module } // DOC include end: GCD chisel -// DOC include start: GCD instance regmap - -trait GCDModule extends HasRegMap { - val io: GCDTopIO - - implicit val p: Parameters - def params: GCDParams - val clock: Clock - val reset: Reset - - - // How many clock cycles in a PWM cycle? - val x = Reg(UInt(params.width.W)) - val y = Wire(new DecoupledIO(UInt(params.width.W))) - val gcd = Wire(new DecoupledIO(UInt(params.width.W))) - val status = Wire(UInt(2.W)) - - val impl = if (params.useBlackBox) { - Module(new GCDMMIOBlackBox(params.width)) - } else { - Module(new GCDMMIOChiselModule(params.width)) - } - - impl.io.clock := clock - impl.io.reset := reset.asBool - - impl.io.x := x - impl.io.y := y.bits - impl.io.input_valid := y.valid - y.ready := impl.io.input_ready - - gcd.bits := impl.io.gcd - gcd.valid := impl.io.output_valid - impl.io.output_ready := gcd.ready - - status := Cat(impl.io.input_ready, impl.io.output_valid) - io.gcd_busy := impl.io.busy - - regmap( - 0x00 -> Seq( - RegField.r(2, status)), // a read-only register capturing current status - 0x04 -> Seq( - RegField.w(params.width, x)), // a plain, write-only register - 0x08 -> Seq( - RegField.w(params.width, y)), // write-only, y.valid is set on write - 0x0C -> Seq( - RegField.r(params.width, gcd))) // read-only, gcd.ready is set on read -} -// DOC include end: GCD instance regmap - // DOC include start: GCD router -class GCDTL(params: GCDParams, beatBytes: Int)(implicit p: Parameters) - extends TLRegisterRouter( - params.address, "gcd", Seq("ucbbar,gcd"), - beatBytes = beatBytes)( - new TLRegBundle(params, _) with GCDTopIO)( - new TLRegModule(params, _, _) with GCDModule) +class GCDTL(params: GCDParams, beatBytes: Int)(implicit p: Parameters) extends ClockSinkDomain(ClockSinkParameters())(p) { + val device = new SimpleDevice("gcd", Seq("ucbbar,gcd")) { + override def describe(resources: ResourceBindings): Description = { + val Description(name, mapping) = super.describe(resources) + Description(name, mapping) + } + } + val node = TLRegisterNode(Seq(AddressSet(params.address, 4096-1)), device, "reg/control", beatBytes=beatBytes) -class GCDAXI4(params: GCDParams, beatBytes: Int)(implicit p: Parameters) - extends AXI4RegisterRouter( - params.address, - beatBytes=beatBytes)( - new AXI4RegBundle(params, _) with GCDTopIO)( - new AXI4RegModule(params, _, _) with GCDModule) + override lazy val module = new GCDImpl + class GCDImpl extends Impl with HasGCDTopIO { + val io = IO(new GCDTopIO) + withClockAndReset(clock, reset) { + // How many clock cycles in a PWM cycle? + val x = Reg(UInt(params.width.W)) + val y = Wire(new DecoupledIO(UInt(params.width.W))) + val gcd = Wire(new DecoupledIO(UInt(params.width.W))) + val status = Wire(UInt(2.W)) + + val impl_io = if (params.useBlackBox) { + val impl = Module(new GCDMMIOBlackBox(params.width)) + impl.io + } else { + val impl = Module(new GCDMMIOChiselModule(params.width)) + impl.io + } + + impl_io.clock := clock + impl_io.reset := reset.asBool + + impl_io.x := x + impl_io.y := y.bits + impl_io.input_valid := y.valid + y.ready := impl_io.input_ready + + gcd.bits := impl_io.gcd + gcd.valid := impl_io.output_valid + impl_io.output_ready := gcd.ready + + status := Cat(impl_io.input_ready, impl_io.output_valid) + io.gcd_busy := impl_io.busy + +// DOC include start: GCD instance regmap + node.regmap( + 0x00 -> Seq( + RegField.r(2, status)), // a read-only register capturing current status + 0x04 -> Seq( + RegField.w(params.width, x)), // a plain, write-only register + 0x08 -> Seq( + RegField.w(params.width, y)), // write-only, y.valid is set on write + 0x0C -> Seq( + RegField.r(params.width, gcd))) // read-only, gcd.ready is set on read +// DOC include end: GCD instance regmap + } + } +} + +class GCDAXI4(params: GCDParams, beatBytes: Int)(implicit p: Parameters) extends ClockSinkDomain(ClockSinkParameters())(p) { + val node = AXI4RegisterNode(AddressSet(params.address, 4096-1), beatBytes=beatBytes) + override lazy val module = new GCDImpl + class GCDImpl extends Impl with HasGCDTopIO { + val io = IO(new GCDTopIO) + withClockAndReset(clock, reset) { + // How many clock cycles in a PWM cycle? + val x = Reg(UInt(params.width.W)) + val y = Wire(new DecoupledIO(UInt(params.width.W))) + val gcd = Wire(new DecoupledIO(UInt(params.width.W))) + val status = Wire(UInt(2.W)) + + val impl_io = if (params.useBlackBox) { + val impl = Module(new GCDMMIOBlackBox(params.width)) + impl.io + } else { + val impl = Module(new GCDMMIOChiselModule(params.width)) + impl.io + } + + impl_io.clock := clock + impl_io.reset := reset.asBool + + impl_io.x := x + impl_io.y := y.bits + impl_io.input_valid := y.valid + y.ready := impl_io.input_ready + + gcd.bits := impl_io.gcd + gcd.valid := impl_io.output_valid + impl_io.output_ready := gcd.ready + + status := Cat(impl_io.input_ready, impl_io.output_valid) + io.gcd_busy := impl_io.busy + + node.regmap( + 0x00 -> Seq( + RegField.r(2, status)), // a read-only register capturing current status + 0x04 -> Seq( + RegField.w(params.width, x)), // a plain, write-only register + 0x08 -> Seq( + RegField.w(params.width, y)), // write-only, y.valid is set on write + 0x0C -> Seq( + RegField.r(params.width, gcd))) // read-only, gcd.ready is set on read + } + } +} // DOC include end: GCD router // DOC include start: GCD lazy trait @@ -164,7 +203,8 @@ trait CanHavePeripheryGCD { this: BaseSubsystem => val gcd_busy = p(GCDKey) match { case Some(params) => { val gcd = if (params.useAXI4) { - val gcd = pbus { LazyModule(new GCDAXI4(params, pbus.beatBytes)(p)) } + val gcd = LazyModule(new GCDAXI4(params, pbus.beatBytes)(p)) + gcd.clockNode := pbus.fixedClockNode pbus.coupleTo(portName) { gcd.node := AXI4Buffer () := @@ -174,18 +214,14 @@ trait CanHavePeripheryGCD { this: BaseSubsystem => } gcd } else { - val gcd = pbus { LazyModule(new GCDTL(params, pbus.beatBytes)(p)) } + val gcd = LazyModule(new GCDTL(params, pbus.beatBytes)(p)) + gcd.clockNode := pbus.fixedClockNode pbus.coupleTo(portName) { gcd.node := TLFragmenter(pbus.beatBytes, pbus.blockBytes) := _ } gcd } - val pbus_io = pbus { InModuleBody { - val busy = IO(Output(Bool())) - busy := gcd.module.io.gcd_busy - busy - }} val gcd_busy = InModuleBody { val busy = IO(Output(Bool())).suggestName("gcd_busy") - busy := pbus_io + busy := gcd.module.io.gcd_busy busy } Some(gcd_busy) From 5aee69c17a4e1b9288bcee9a5a239d9549f7be9c Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 22 Jan 2024 22:24:48 -0800 Subject: [PATCH 02/13] update docs on GCD MMIO --- docs/Customization/MMIO-Peripherals.rst | 31 ++++++++++++++----------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/docs/Customization/MMIO-Peripherals.rst b/docs/Customization/MMIO-Peripherals.rst index f3f2bc8d..82a9f27b 100644 --- a/docs/Customization/MMIO-Peripherals.rst +++ b/docs/Customization/MMIO-Peripherals.rst @@ -10,7 +10,8 @@ To create a RegisterRouter-based peripheral, you will need to specify a paramete For this example, we will show how to connect a MMIO peripheral which computes the GCD. The full code can be found in ``generators/chipyard/src/main/scala/example/GCD.scala``. -In this case we use a submodule ``GCDMMIOChiselModule`` to actually perform the GCD. The ``GCDModule`` class only creates the registers and hooks them up using ``regmap``. +In this case we use a submodule ``GCDMMIOChiselModule`` to actually perform the GCD. The ``GCDTL`` and ``GCDAXI4`` classes are the ``LazyModule`` classes which construct the TileLink or AXI4 ports, wrapping the inner ``GCDMMIOChiselModule``. +The ``node`` object is a Diplomacy node, which connects the peripheral to the Diplomacy interconnect graph. .. literalinclude:: ../../generators/chipyard/src/main/scala/example/GCD.scala :language: scala @@ -19,8 +20,9 @@ In this case we use a submodule ``GCDMMIOChiselModule`` to actually perform the .. literalinclude:: ../../generators/chipyard/src/main/scala/example/GCD.scala :language: scala - :start-after: DOC include start: GCD instance regmap - :end-before: DOC include end: GCD instance regmap + :start-after: DOC include start: GCD router + :end-before: DOC include end: GCD router + Advanced Features of RegField Entries ------------------------------------- @@ -41,15 +43,21 @@ triggering the GCD algorithm when ``y`` is written. Therefore, the algorithm is set up by first writing ``x`` and then performing a triggering write to ``y``. Polling can be used for status checks. +.. literalinclude:: ../../generators/chipyard/src/main/scala/example/GCD.scala + :language: scala + :start-after: DOC include start: GCD instance regmap + :end-before: DOC include end: GCD instance regmap + Connecting by TileLink ---------------------- -Once you have these classes, you can construct the final peripheral by extending the ``TLRegisterRouter`` and passing the proper arguments. -The first set of arguments determines where the register router will be placed in the global address map and what information will be put in its device tree entry. -The second set of arguments is the IO bundle constructor, which we create by extending ``TLRegBundle`` with our bundle trait. -The final set of arguments is the module constructor, which we create by extends ``TLRegModule`` with our module trait. -Notice how we can create an analogous AXI4 version of our peripheral. +The key to connecting to the TileLink Diplomatic graph is the construction of the TileLink node for this peripheral. +In this case, since the peripheral acts as a manager of some register-mapped address space, it uses the ``TLRegisterNode`` object. +The parameters to the ``TLRegisterNode`` object specify the size of the managed space, the base address, and the port width. + +Within the register-mapped peripheral, the control registers can be mapped using the ``node.regmap`` function, as described above. +A similar procedure is followed for both AXI4 and TileLin peripherals. .. literalinclude:: ../../generators/chipyard/src/main/scala/example/GCD.scala :language: scala @@ -62,12 +70,8 @@ Top-level Traits ---------------- After creating the module, we need to hook it up to our SoC. -Rocket Chip accomplishes this using the cake pattern. -This basically involves placing code inside traits. -In the Rocket Chip cake, there are two kinds of traits: a ``LazyModule`` trait and a module implementation trait. - The ``LazyModule`` trait runs setup code that must execute before all the hardware gets elaborated. -For a simple memory-mapped peripheral, this just involves connecting the peripheral's TileLink node to the MMIO crossbar. +For a simple memory-mapped peripheral, this just involves connecting the peripheral's TileLink node to the relevant bus. .. literalinclude:: ../../generators/chipyard/src/main/scala/example/GCD.scala :language: scala @@ -80,6 +84,7 @@ This will automatically add address map and device tree entries for the peripher Also observe how we have to place additional AXI4 buffers and converters for the AXI4 version of this peripheral. Peripherals which expose I/O can use `InModuleBody` to punch their I/O to the `DigitalTop` module. +In this example, the GCD module's ``gcd_busy`` signal is exposed as a I/O of DigitalTop. Constructing the DigitalTop and Config -------------------------------------- From aef7cda172874b758bd906e85a001b62c66525d5 Mon Sep 17 00:00:00 2001 From: Lux Date: Wed, 24 Jan 2024 17:24:59 -0800 Subject: [PATCH 03/13] removing seemingly useless override --- generators/chipyard/src/main/scala/example/GCD.scala | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/generators/chipyard/src/main/scala/example/GCD.scala b/generators/chipyard/src/main/scala/example/GCD.scala index 3ed202ac..ef3edc1f 100644 --- a/generators/chipyard/src/main/scala/example/GCD.scala +++ b/generators/chipyard/src/main/scala/example/GCD.scala @@ -90,12 +90,7 @@ class GCDMMIOChiselModule(val w: Int) extends Module { // DOC include start: GCD router class GCDTL(params: GCDParams, beatBytes: Int)(implicit p: Parameters) extends ClockSinkDomain(ClockSinkParameters())(p) { - val device = new SimpleDevice("gcd", Seq("ucbbar,gcd")) { - override def describe(resources: ResourceBindings): Description = { - val Description(name, mapping) = super.describe(resources) - Description(name, mapping) - } - } + val device = new SimpleDevice("gcd", Seq("ucbbar,gcd")) val node = TLRegisterNode(Seq(AddressSet(params.address, 4096-1)), device, "reg/control", beatBytes=beatBytes) override lazy val module = new GCDImpl From 1f9cf94afc3899d543e237e712f41fe6228e6703 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Fri, 26 Jan 2024 00:51:56 -0800 Subject: [PATCH 04/13] Don't recursively clone nvdla/cva6 --- scripts/init-submodules-no-riscv-tools-nolog.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/init-submodules-no-riscv-tools-nolog.sh b/scripts/init-submodules-no-riscv-tools-nolog.sh index 4283e892..9ee4c4a0 100755 --- a/scripts/init-submodules-no-riscv-tools-nolog.sh +++ b/scripts/init-submodules-no-riscv-tools-nolog.sh @@ -69,6 +69,8 @@ cd "$RDIR" # path to temporarily exclude during the recursive update for name in \ toolchains/*-tools/* \ + generators/cva6 \ + generators/nvdla \ toolchains/libgloss \ generators/sha3 \ generators/gemmini \ @@ -101,6 +103,14 @@ cd "$RDIR" # Non-recursive clone to exclude riscv-linux git submodule update --init generators/sha3 + # Non-recursive clone to exclude cva6 submods + git submodule update --init generators/cva6 + git -C generators/cva6 submodule update --init src/main/resources/cva6/vsrc/cva6 + + # Non-recursive clone to exclude nvdla submods + git submodule update --init generators/nvdla + git -C generators/nvdla submodule update --init src/main/resources/hw + # Non-recursive clone to exclude gemmini-software git submodule update --init generators/gemmini git -C generators/gemmini/ submodule update --init --recursive software/gemmini-rocc-tests From 32d343943f6e3751d5ed29880f6b505ef77f233d Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Fri, 26 Jan 2024 00:52:42 -0800 Subject: [PATCH 05/13] Fix submodule names in .gitmodules --- .gitmodules | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 86f29d8a..4f21369e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,10 +1,10 @@ -[submodule "rocket-chip"] +[submodule "generators/rocket-chip"] path = generators/rocket-chip url = https://github.com/chipsalliance/rocket-chip.git -[submodule "testchipip"] +[submodule "generators/testchipip"] path = generators/testchipip url = https://github.com/ucb-bar/testchipip.git -[submodule "barstools"] +[submodule "tools/barstools"] path = tools/barstools url = https://github.com/ucb-bar/barstools.git [submodule "tools/torture"] From 89914e4cd57f531de2d1418fa86c7333e2eb63d4 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Fri, 26 Jan 2024 01:28:13 -0800 Subject: [PATCH 06/13] Add missing cva6 submods --- scripts/init-submodules-no-riscv-tools-nolog.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/init-submodules-no-riscv-tools-nolog.sh b/scripts/init-submodules-no-riscv-tools-nolog.sh index 9ee4c4a0..1779b8d8 100755 --- a/scripts/init-submodules-no-riscv-tools-nolog.sh +++ b/scripts/init-submodules-no-riscv-tools-nolog.sh @@ -106,7 +106,13 @@ cd "$RDIR" # Non-recursive clone to exclude cva6 submods git submodule update --init generators/cva6 git -C generators/cva6 submodule update --init src/main/resources/cva6/vsrc/cva6 - + git -C generators/cva6/src/main/resources/cva6/vsrc/cva6 submodule update --init src/axi + git -C generators/cva6/src/main/resources/cva6/vsrc/cva6 submodule update --init src/axi_riscv_atomics + git -C generators/cva6/src/main/resources/cva6/vsrc/cva6 submodule update --init src/common_cells + git -C generators/cva6/src/main/resources/cva6/vsrc/cva6 submodule update --init src/fpga-support + git -C generators/cva6/src/main/resources/cva6/vsrc/cva6 submodule update --init src/riscv-dbg + git -C generators/cva6/src/main/resources/cva6/vsrc/cva6 submodule update --init src/register_interface + git -C generators/cva6/src/main/resources/cva6/vsrc/cva6 submodule update --init --recursive src/fpu # Non-recursive clone to exclude nvdla submods git submodule update --init generators/nvdla git -C generators/nvdla submodule update --init src/main/resources/hw From d8e44d2b5e1baa7ff1cea89dff855e2b21d21e75 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Sun, 28 Jan 2024 23:48:08 -0800 Subject: [PATCH 07/13] Bump to latest rocket-chip --- generators/icenet | 2 +- generators/rocket-chip | 2 +- generators/rocket-chip-blocks | 2 +- generators/testchipip | 2 +- tools/rocket-dsp-utils | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/generators/icenet b/generators/icenet index d6a471f2..ab30e23e 160000 --- a/generators/icenet +++ b/generators/icenet @@ -1 +1 @@ -Subproject commit d6a471f2187c0671eea6567c7ba29e86e830e8d4 +Subproject commit ab30e23e8e1fdd0777a7e4eb82bb40e2657cfcd3 diff --git a/generators/rocket-chip b/generators/rocket-chip index 749a3eae..8026b6bc 160000 --- a/generators/rocket-chip +++ b/generators/rocket-chip @@ -1 +1 @@ -Subproject commit 749a3eae9678bc70b029c5b9091fae33fad539c4 +Subproject commit 8026b6bc9abe7cbfb7d07cecb28ef909c25868c8 diff --git a/generators/rocket-chip-blocks b/generators/rocket-chip-blocks index 212c7b07..3dddfe9f 160000 --- a/generators/rocket-chip-blocks +++ b/generators/rocket-chip-blocks @@ -1 +1 @@ -Subproject commit 212c7b070bc7132f31a26deec6b2bde9e0b1b612 +Subproject commit 3dddfe9f5bcacf28aebcadb71d5b57f4f6df7e07 diff --git a/generators/testchipip b/generators/testchipip index edacb214..003c9c1e 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit edacb214f081e5034f131af74efa0ac5f4452ee6 +Subproject commit 003c9c1e81c94c74f877d3883688c220dfe69d1b diff --git a/tools/rocket-dsp-utils b/tools/rocket-dsp-utils index 19445522..272cee3c 160000 --- a/tools/rocket-dsp-utils +++ b/tools/rocket-dsp-utils @@ -1 +1 @@ -Subproject commit 194455223aa75f400d2ac76bfd71e61e3c2a9533 +Subproject commit 272cee3c83a31a7496b8f2e933290798e2fb5cac From 0ccd032a734ac83affe48436c398c10ed81c4d83 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 29 Jan 2024 07:57:36 -0800 Subject: [PATCH 08/13] Remove references to legacy softcore-based bringup --- docs/Advanced-Concepts/Chip-Communication.rst | 22 -- docs/Prototyping/VCU118.rst | 14 -- fpga/Makefile | 14 -- .../scala/vcu118/bringup/BringupGPIOs.scala | 28 --- .../main/scala/vcu118/bringup/Configs.scala | 97 --------- .../scala/vcu118/bringup/CustomOverlays.scala | 204 ------------------ .../scala/vcu118/bringup/DigitalTop.scala | 26 --- .../scala/vcu118/bringup/HarnessBinders.scala | 51 ----- .../main/scala/vcu118/bringup/IOBinders.scala | 30 --- .../scala/vcu118/bringup/TestHarness.scala | 99 --------- 10 files changed, 585 deletions(-) delete mode 100644 fpga/src/main/scala/vcu118/bringup/BringupGPIOs.scala delete mode 100644 fpga/src/main/scala/vcu118/bringup/Configs.scala delete mode 100644 fpga/src/main/scala/vcu118/bringup/CustomOverlays.scala delete mode 100644 fpga/src/main/scala/vcu118/bringup/DigitalTop.scala delete mode 100644 fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala delete mode 100644 fpga/src/main/scala/vcu118/bringup/IOBinders.scala delete mode 100644 fpga/src/main/scala/vcu118/bringup/TestHarness.scala diff --git a/docs/Advanced-Concepts/Chip-Communication.rst b/docs/Advanced-Concepts/Chip-Communication.rst index 5a79e963..bc913f68 100644 --- a/docs/Advanced-Concepts/Chip-Communication.rst +++ b/docs/Advanced-Concepts/Chip-Communication.rst @@ -198,25 +198,3 @@ bringup design). :language: scala :start-after: DOC include start: TetheredChipLikeRocketConfig :end-before: DOC include end: TetheredChipLikeRocketConfig - -Softcore-driven Bringup Setup of the Example Test Chip after Tapeout -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. warning:: - Bringing up test chips with a FPGA softcore as described here is discouraged. - An alternative approach using the FPGA to "bridge" between a host computer and the test chip is the preferred approach. - -Assuming this example test chip is taped out and now ready to be tested, we can communicate with the chip using this serial-link. -For example, a common test setup used at Berkeley to evaluate Chipyard-based test-chips includes an FPGA running a RISC-V soft-core that is able to speak to the DUT (over an FMC). -This RISC-V soft-core would serve as the host of the test that will run on the DUT. -This is done by the RISC-V soft-core running FESVR, sending TSI commands to a ``TSIToTileLink`` / ``TLSerdesser`` programmed on the FPGA. -Once the commands are converted to serialized TileLink, then they can be sent over some medium to the DUT -(like an FMC cable or a set of wires connecting FPGA outputs to the DUT board). -Similar to simulation, if the chip requests offchip memory, it can then send the transaction back over the serial-link. -Then the request can be serviced by the FPGA DRAM. -The following image shows this flow: - -.. image:: ../_static/images/chip-bringup.png - -In fact, this exact type of bringup setup is what the following section discusses: -:ref:_legacy-vcu118-bringup. diff --git a/docs/Prototyping/VCU118.rst b/docs/Prototyping/VCU118.rst index 96c67f48..813179fd 100644 --- a/docs/Prototyping/VCU118.rst +++ b/docs/Prototyping/VCU118.rst @@ -47,20 +47,6 @@ After the harness is created, the ``BundleBridgeSource``'s must be connected to This is done with harness binders and io binders (see ``fpga/src/main/scala/vcu118/HarnessBinders.scala`` and ``fpga/src/main/scala/vcu118/IOBinders.scala``). For more information on harness binders and io binders, refer to :ref:`Customization/IOBinders:IOBinders and HarnessBinders`. -(Legacy) Introduction to the Legacy Bringup Design --------------------------------------------------- - -.. warning:: - The bringup VCU118 design described here is designed for old versions of Chipyard SoCs, pre-1.9.1. - The key difference is that these designs rely on a clock generated on-chip to synchronize the slow serialized-TileLink interface. - After Chipyard 1.9.1, the FPGA host is expected to pass the clock to the chip, instead of the other way around. - A new bringup solution will be developed for post-1.9.1 Chipyard designs. - -An example of a more complicated design used for Chipyard test chips can be viewed in ``fpga/src/main/scala/vcu118/bringup/``. -This example extends the default test harness and creates new ``Overlays`` to connect to a DUT (connected to the FMC port). -Extensions include another UART (connected over FMC), I2C (connected over FMC), miscellaneous GPIOS (can be connected to anything), and a TSI Host Widget. -The TSI Host Widget is used to interact with the DUT from the prototype over a SerDes link (sometimes called the Low BandWidth InterFace - LBWIF) and provide access to a channel of the FPGA's DRAM. - .. Note:: Remember that since whenever a new test harness is created (or the config changes, or the config packages changes, or...), you need to modify the make invocation. For example, ``make SUB_PROJECT=vcu118 CONFIG=MyNewVCU118Config CONFIG_PACKAGE=this.is.my.scala.package bitstream``. See :ref:`Prototyping/General:Generating a Bitstream` for information on the various make variables. diff --git a/fpga/Makefile b/fpga/Makefile index a4d3bf99..ebf55a97 100644 --- a/fpga/Makefile +++ b/fpga/Makefile @@ -44,20 +44,6 @@ ifeq ($(SUB_PROJECT),vcu118) FPGA_BRAND ?= xilinx endif -ifeq ($(SUB_PROJECT),bringup) - SBT_PROJECT ?= fpga_platforms - MODEL ?= BringupVCU118FPGATestHarness - VLOG_MODEL ?= BringupVCU118FPGATestHarness - MODEL_PACKAGE ?= chipyard.fpga.vcu118.bringup - CONFIG ?= RocketBringupConfig - CONFIG_PACKAGE ?= chipyard.fpga.vcu118.bringup - GENERATOR_PACKAGE ?= chipyard - TB ?= none # unused - TOP ?= ChipTop - BOARD ?= vcu118 - FPGA_BRAND ?= xilinx -endif - ifeq ($(SUB_PROJECT),nexysvideo) SBT_PROJECT ?= fpga_platforms MODEL ?= NexysVideoHarness diff --git a/fpga/src/main/scala/vcu118/bringup/BringupGPIOs.scala b/fpga/src/main/scala/vcu118/bringup/BringupGPIOs.scala deleted file mode 100644 index 40c33bfa..00000000 --- a/fpga/src/main/scala/vcu118/bringup/BringupGPIOs.scala +++ /dev/null @@ -1,28 +0,0 @@ -package chipyard.fpga.vcu118.bringup - -import scala.collection.mutable.{LinkedHashMap} - -object BringupGPIOs { - // map of the pin name (akin to die pin name) to (fpga package pin, IOSTANDARD, add pullup resistor?) - val pinMapping = LinkedHashMap( - // these connect to LEDs and switches on the VCU118 (and use 1.2V) - "led0" -> ("AT32", "LVCMOS12", false), // 0 - "led1" -> ("AV34", "LVCMOS12", false), // 1 - "led2" -> ("AY30", "LVCMOS12", false), // 2 - "led3" -> ("BB32", "LVCMOS12", false), // 3 - "led4" -> ("BF32", "LVCMOS12", false), // 4 - "led5" -> ("AU37", "LVCMOS12", false), // 5 - "led6" -> ("AV36", "LVCMOS12", false), // 6 - "led7" -> ("BA37", "LVCMOS12", false), // 7 - "sw0" -> ("B17", "LVCMOS12", false), // 8 - "sw1" -> ("G16", "LVCMOS12", false), // 9 - "sw2" -> ("J16", "LVCMOS12", false), // 10 - "sw3" -> ("D21", "LVCMOS12", false) // 11 - ) - - // return list of names (ordered) - def names: Seq[String] = pinMapping.keys.toSeq - - // return number of GPIOs - def width: Int = pinMapping.size -} diff --git a/fpga/src/main/scala/vcu118/bringup/Configs.scala b/fpga/src/main/scala/vcu118/bringup/Configs.scala deleted file mode 100644 index 0760fa72..00000000 --- a/fpga/src/main/scala/vcu118/bringup/Configs.scala +++ /dev/null @@ -1,97 +0,0 @@ -package chipyard.fpga.vcu118.bringup - -import math.min - -import org.chipsalliance.cde.config.{Config, Parameters} -import freechips.rocketchip.diplomacy.{DTSModel, DTSTimebase, RegionType, AddressSet, ResourceBinding, Resource, ResourceAddress} -import freechips.rocketchip.tilelink._ -import freechips.rocketchip.diplomacy._ -import freechips.rocketchip.subsystem.{MasterPortParams} - -import sifive.blocks.devices.gpio.{PeripheryGPIOKey, GPIOParams} -import sifive.blocks.devices.i2c.{PeripheryI2CKey, I2CParams} -import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} - -import sifive.fpgashells.shell.{DesignKey} -import sifive.fpgashells.shell.xilinx.{VCU118ShellPMOD, VCU118DDRSize} - -import testchipip.tsi.{PeripheryTSIHostKey, TSIHostParams, TSIHostSerdesParams} - -import chipyard.{BuildSystem} - -import chipyard.fpga.vcu118.{WithVCU118Tweaks, WithFPGAFrequency, VCU118DDR2Size} -import chipyard.iobinders.{WithGPIOPunchthrough} - -class WithBringupPeripherals extends Config((site, here, up) => { - case PeripheryUARTKey => up(PeripheryUARTKey, site) ++ List(UARTParams(address = BigInt(0x64003000L))) - case PeripheryI2CKey => List(I2CParams(address = BigInt(0x64005000L))) - case PeripheryGPIOKey => { - if (BringupGPIOs.width > 0) { - require(BringupGPIOs.width <= 64) // currently only support 64 GPIOs (change addrs to get more) - val gpioAddrs = Seq(BigInt(0x64002000), BigInt(0x64007000)) - val maxGPIOSupport = 32 // max gpios supported by SiFive driver (split by 32) - List.tabulate(((BringupGPIOs.width - 1)/maxGPIOSupport) + 1)(n => { - GPIOParams(address = gpioAddrs(n), width = min(BringupGPIOs.width - maxGPIOSupport*n, maxGPIOSupport)) - }) - } - else { - List.empty[GPIOParams] - } - } - case TSIClockMaxFrequencyKey => 100 - case PeripheryTSIHostKey => List( - TSIHostParams( - offchipSerialIfWidth = 4, - mmioBaseAddress = BigInt(0x64006000), - mmioSourceId = 1 << 13, // manager source - serdesParams = TSIHostSerdesParams( - clientPortParams = TLMasterPortParameters.v1( - clients = Seq(TLMasterParameters.v1( - name = "tl-tsi-host-serdes", - sourceId = IdRange(0, (1 << 13))))), - managerPortParams = TLSlavePortParameters.v1( - managers = Seq(TLSlaveParameters.v1( - address = Seq(AddressSet(0, BigInt("FFFFFFFF", 16))), // access everything on chip - regionType = RegionType.UNCACHED, - executable = true, - supportsGet = TransferSizes(1, 64), - supportsPutFull = TransferSizes(1, 64), - supportsPutPartial = TransferSizes(1, 64), - supportsAcquireT = TransferSizes(1, 64), - supportsAcquireB = TransferSizes(1, 64), - supportsArithmetic = TransferSizes(1, 64), - supportsLogical = TransferSizes(1, 64))), - endSinkId = 1 << 6, // manager sink - beatBytes = 8)), - targetMasterPortParams = MasterPortParams( - base = BigInt("80000000", 16), - size = site(VCU118DDR2Size), - beatBytes = 8, // comes from test chip - idBits = 4) // comes from VCU118 idBits in XilinxVCU118MIG - )) -}) - -class WithBringupVCU118System extends Config((site, here, up) => { - case BuildSystem => (p: Parameters) => new BringupVCU118DigitalTop()(p) // use the VCU118-extended bringup digital top -}) - -class WithBringupAdditions extends Config( - new WithBringupUART ++ - new WithBringupI2C ++ - new WithBringupGPIO ++ - new WithBringupTSIHost ++ - new WithTSITLIOPassthrough ++ - new WithGPIOPunchthrough ++ - new WithBringupPeripherals ++ - new WithBringupVCU118System) - -class RocketBringupConfig extends Config( - new WithBringupAdditions ++ - new WithVCU118Tweaks ++ - new chipyard.RocketConfig) - -class BoomBringupConfig extends Config( - new WithFPGAFrequency(50) ++ - new WithBringupAdditions ++ - new WithVCU118Tweaks ++ - new chipyard.MegaBoomConfig) diff --git a/fpga/src/main/scala/vcu118/bringup/CustomOverlays.scala b/fpga/src/main/scala/vcu118/bringup/CustomOverlays.scala deleted file mode 100644 index a52a1b5e..00000000 --- a/fpga/src/main/scala/vcu118/bringup/CustomOverlays.scala +++ /dev/null @@ -1,204 +0,0 @@ -package chipyard.fpga.vcu118.bringup - -import chisel3._ -import chisel3.experimental.{attach} - -import freechips.rocketchip.diplomacy._ -import org.chipsalliance.cde.config.{Parameters, Field} -import freechips.rocketchip.tilelink.{TLInwardNode, TLAsyncCrossingSink} - -import sifive.fpgashells.shell._ -import sifive.fpgashells.ip.xilinx._ -import sifive.fpgashells.shell.xilinx._ -import sifive.fpgashells.clocks._ -import sifive.fpgashells.devices.xilinx.xilinxvcu118mig.{XilinxVCU118MIGPads, XilinxVCU118MIGParams, XilinxVCU118MIG} - -import testchipip.tsi.{TSIHostWidgetIO} - -import chipyard.fpga.vcu118.{FMCPMap} - -/* Connect the I2C to certain FMC pins */ -class BringupI2CVCU118PlacedOverlay(val shell: VCU118ShellBasicOverlays, name: String, val designInput: I2CDesignInput, val shellInput: I2CShellInput) - extends I2CXilinxPlacedOverlay(name, designInput, shellInput) -{ - shell { InModuleBody { - require(shellInput.index == 0) // only support 1 I2C <-> FMC connection - val i2cLocations = List(List(FMCPMap("K11"), FMCPMap("E2"))) - val packagePinsWithPackageIOs = Seq((i2cLocations(shellInput.index)(0), IOPin(io.scl)), - (i2cLocations(shellInput.index)(1), IOPin(io.sda))) - - packagePinsWithPackageIOs foreach { case (pin, io) => { - shell.xdc.addPackagePin(io, pin) - shell.xdc.addIOStandard(io, "LVCMOS18") - shell.xdc.addIOB(io) - } } - } } -} - -class BringupI2CVCU118ShellPlacer(val shell: VCU118ShellBasicOverlays, val shellInput: I2CShellInput)(implicit val valName: ValName) - extends I2CShellPlacer[VCU118ShellBasicOverlays] -{ - def place(designInput: I2CDesignInput) = new BringupI2CVCU118PlacedOverlay(shell, valName.name, designInput, shellInput) -} - -/* Connect the UART to certain FMC pins */ -class BringupUARTVCU118PlacedOverlay(val shell: VCU118ShellBasicOverlays, name: String, val designInput: UARTDesignInput, val shellInput: UARTShellInput) - extends UARTXilinxPlacedOverlay(name, designInput, shellInput, true) -{ - shell { InModuleBody { - val packagePinsWithPackageIOs = Seq((FMCPMap("E9"), IOPin(io.ctsn.get)), // unused - (FMCPMap("E10"), IOPin(io.rtsn.get)), // unused - (FMCPMap("C15"), IOPin(io.rxd)), - (FMCPMap("C14"), IOPin(io.txd))) - - packagePinsWithPackageIOs foreach { case (pin, io) => { - shell.xdc.addPackagePin(io, pin) - shell.xdc.addIOStandard(io, "LVCMOS18") - shell.xdc.addIOB(io) - } } - - // add pullup on ctsn (ctsn is an input that is not used or driven) - packagePinsWithPackageIOs take 1 foreach { case (pin, io) => { - shell.xdc.addPullup(io) - } } - } } -} - -class BringupUARTVCU118ShellPlacer(shell: VCU118ShellBasicOverlays, val shellInput: UARTShellInput)(implicit val valName: ValName) - extends UARTShellPlacer[VCU118ShellBasicOverlays] { - def place(designInput: UARTDesignInput) = new BringupUARTVCU118PlacedOverlay(shell, valName.name, designInput, shellInput) -} - -/* Connect GPIOs to FPGA I/Os */ -abstract class GPIOXilinxPlacedOverlay(name: String, di: GPIODesignInput, si: GPIOShellInput) - extends GPIOPlacedOverlay(name, di, si) -{ - def shell: XilinxShell - - shell { InModuleBody { - (io.gpio zip tlgpioSink.bundle.pins).map { case (ioPin, sinkPin) => - val iobuf = Module(new IOBUF) - iobuf.suggestName(s"gpio_iobuf") - attach(ioPin, iobuf.io.IO) - sinkPin.i.ival := iobuf.io.O - iobuf.io.T := !sinkPin.o.oe - iobuf.io.I := sinkPin.o.oval - } - } } -} - -class BringupGPIOVCU118PlacedOverlay(val shell: VCU118ShellBasicOverlays, name: String, val designInput: GPIODesignInput, val shellInput: GPIOShellInput, gpioNames: Seq[String]) - extends GPIOXilinxPlacedOverlay(name, designInput, shellInput) -{ - shell { InModuleBody { - require(gpioNames.length == io.gpio.length) - - val packagePinsWithIOStdWithPackageIOs = (gpioNames zip io.gpio).map { case (name, io) => - val (pin, iostd, pullupEnable) = BringupGPIOs.pinMapping(name) - (pin, iostd, pullupEnable, IOPin(io)) - } - - packagePinsWithIOStdWithPackageIOs foreach { case (pin, iostd, pullupEnable, io) => { - shell.xdc.addPackagePin(io, pin) - shell.xdc.addIOStandard(io, iostd) - if (iostd == "LVCMOS12") { shell.xdc.addDriveStrength(io, "8") } - if (pullupEnable) { shell.xdc.addPullup(io) } - } } - } } -} - -class BringupGPIOVCU118ShellPlacer(shell: VCU118ShellBasicOverlays, val shellInput: GPIOShellInput, gpioNames: Seq[String])(implicit val valName: ValName) - extends GPIOShellPlacer[VCU118ShellBasicOverlays] { - def place(designInput: GPIODesignInput) = new BringupGPIOVCU118PlacedOverlay(shell, valName.name, designInput, shellInput, gpioNames) -} - -case class TSIHostShellInput() -case class TSIHostDesignInput( - serialIfWidth: Int, - node: BundleBridgeSource[TSIHostWidgetIO] - )( - implicit val p: Parameters) -case class TSIHostOverlayOutput() -trait TSIHostShellPlacer[Shell] extends ShellPlacer[TSIHostDesignInput, TSIHostShellInput, TSIHostOverlayOutput] - -case object TSIHostOverlayKey extends Field[Seq[DesignPlacer[TSIHostDesignInput, TSIHostShellInput, TSIHostOverlayOutput]]](Nil) - -abstract class TSIHostPlacedOverlay[IO <: Data](val name: String, val di: TSIHostDesignInput, val si: TSIHostShellInput) - extends IOPlacedOverlay[IO, TSIHostDesignInput, TSIHostShellInput, TSIHostOverlayOutput] -{ - implicit val p = di.p -} - -case object TSIHostVCU118DDRSize extends Field[BigInt](0x40000000L * 2) // 2GB -class TSIHostVCU118PlacedOverlay(val shell: BringupVCU118FPGATestHarness, name: String, val designInput: TSIHostDesignInput, val shellInput: TSIHostShellInput) - extends TSIHostPlacedOverlay[TSIHostWidgetIO](name, designInput, shellInput) -{ - val tlTsiSerialSink = di.node.makeSink() - val tsiIoNode = BundleBridgeSource(() => new TSIHostWidgetIO(di.serialIfWidth)) - val topTSIIONode = shell { tsiIoNode.makeSink() } - - def overlayOutput = TSIHostOverlayOutput() - def ioFactory = new TSIHostWidgetIO(di.serialIfWidth) - - InModuleBody { - // connect TSI serial - val tsiSourcePort = tsiIoNode.bundle - val tsiSinkPort = tlTsiSerialSink.bundle - tsiSinkPort.serial_clock := tsiSourcePort.serial_clock - tsiSourcePort.serial.out.bits := tsiSinkPort.serial.out.bits - tsiSourcePort.serial.out.valid := tsiSinkPort.serial.out.valid - tsiSinkPort.serial.out.ready := tsiSourcePort.serial.out.ready - tsiSinkPort.serial.in.bits := tsiSourcePort.serial.in.bits - tsiSinkPort.serial.in.valid := tsiSourcePort.serial.in.valid - tsiSourcePort.serial.in.ready := tsiSinkPort.serial.in.ready - } -} - -case object TSIClockMaxFrequencyKey extends Field[Int](50) // in MHz -class BringupTSIHostVCU118PlacedOverlay(override val shell: BringupVCU118FPGATestHarness, override val name: String, override val designInput: TSIHostDesignInput, override val shellInput: TSIHostShellInput) - extends TSIHostVCU118PlacedOverlay(shell, name, designInput, shellInput) -{ - // connect the TSI port - shell { InModuleBody { - // connect TSI signals - val tsiPort = topTSIIONode.bundle - io <> tsiPort - - require(di.serialIfWidth == 4) - - val clkIo = IOPin(io.serial_clock) - val packagePinsWithPackageIOs = Seq( - (FMCPMap("D8"), clkIo), - (FMCPMap("D17"), IOPin(io.serial.out.ready)), - (FMCPMap("D18"), IOPin(io.serial.out.valid)), - (FMCPMap("D11"), IOPin(io.serial.out.bits, 0)), - (FMCPMap("D12"), IOPin(io.serial.out.bits, 1)), - (FMCPMap("D14"), IOPin(io.serial.out.bits, 2)), - (FMCPMap("D15"), IOPin(io.serial.out.bits, 3)), - (FMCPMap("D26"), IOPin(io.serial.in.ready)), - (FMCPMap("D27"), IOPin(io.serial.in.valid)), - (FMCPMap("D20"), IOPin(io.serial.in.bits, 0)), - (FMCPMap("D21"), IOPin(io.serial.in.bits, 1)), - (FMCPMap("D23"), IOPin(io.serial.in.bits, 2)), - (FMCPMap("D24"), IOPin(io.serial.in.bits, 3))) - - packagePinsWithPackageIOs foreach { case (pin, io) => { - shell.xdc.addPackagePin(io, pin) - shell.xdc.addIOStandard(io, "LVCMOS18") - } } - - // Don't add an IOB to the clock - (packagePinsWithPackageIOs take 1) foreach { case (pin, io) => { - shell.xdc.addIOB(io) - } } - - shell.sdc.addClock("TSI_CLK", clkIo, p(TSIClockMaxFrequencyKey)) - shell.sdc.addGroup(pins = Seq(clkIo)) - shell.xdc.clockDedicatedRouteFalse(clkIo) - } } -} - -class BringupTSIHostVCU118ShellPlacer(shell: BringupVCU118FPGATestHarness, val shellInput: TSIHostShellInput)(implicit val valName: ValName) - extends TSIHostShellPlacer[BringupVCU118FPGATestHarness] { - def place(designInput: TSIHostDesignInput) = new BringupTSIHostVCU118PlacedOverlay(shell, valName.name, designInput, shellInput) -} diff --git a/fpga/src/main/scala/vcu118/bringup/DigitalTop.scala b/fpga/src/main/scala/vcu118/bringup/DigitalTop.scala deleted file mode 100644 index e4efbdc7..00000000 --- a/fpga/src/main/scala/vcu118/bringup/DigitalTop.scala +++ /dev/null @@ -1,26 +0,0 @@ -package chipyard.fpga.vcu118.bringup - -import chisel3._ - -import freechips.rocketchip.subsystem._ -import freechips.rocketchip.system._ -import org.chipsalliance.cde.config.Parameters -import freechips.rocketchip.devices.tilelink._ -import freechips.rocketchip.diplomacy._ -import freechips.rocketchip.tilelink._ - -import chipyard.{DigitalTop, DigitalTopModule} - -// ------------------------------------ -// Bringup VCU118 DigitalTop -// ------------------------------------ - -class BringupVCU118DigitalTop(implicit p: Parameters) extends DigitalTop - with sifive.blocks.devices.i2c.HasPeripheryI2C - with testchipip.tsi.HasPeripheryTSIHostWidget -{ - override lazy val module = new BringupVCU118DigitalTopModule(this) -} - -class BringupVCU118DigitalTopModule[+L <: BringupVCU118DigitalTop](l: L) extends DigitalTopModule(l) - with sifive.blocks.devices.i2c.HasPeripheryI2CModuleImp diff --git a/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala b/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala deleted file mode 100644 index 27933bf6..00000000 --- a/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala +++ /dev/null @@ -1,51 +0,0 @@ -package chipyard.fpga.vcu118.bringup - -import chisel3._ -import chisel3.experimental.{Analog, IO, BaseModule} - -import freechips.rocketchip.util.{HeterogeneousBag} -import freechips.rocketchip.tilelink.{TLBundle} - -import sifive.blocks.devices.uart.{HasPeripheryUARTModuleImp, UARTPortIO} -import sifive.blocks.devices.spi.{HasPeripherySPI, SPIPortIO} -import sifive.blocks.devices.i2c.{HasPeripheryI2CModuleImp, I2CPort} -import sifive.blocks.devices.gpio.{HasPeripheryGPIOModuleImp, GPIOPortIO} - -import testchipip.tsi.{HasPeripheryTSIHostWidget, TSIHostWidgetIO} - -import chipyard.harness._ -import chipyard.iobinders._ - -/*** UART ***/ -class WithBringupUART extends HarnessBinder({ - case (th: BringupVCU118FPGATestHarnessImp, port: UARTPort, chipId: Int) => { - th.bringupOuter.io_fmc_uart_bb.bundle <> port.io - } -}) - -/*** I2C ***/ -class WithBringupI2C extends HarnessBinder({ - case (th: BringupVCU118FPGATestHarnessImp, port: chipyard.iobinders.I2CPort, chipId: Int) => { - th.bringupOuter.io_i2c_bb.bundle <> port.io - } -}) - -/*** GPIO ***/ -class WithBringupGPIO extends HarnessBinder({ - case (th: BringupVCU118FPGATestHarnessImp, port: GPIOPort, chipId: Int) => { - th.bringupOuter.io_gpio_bb(port.pinId).bundle <> port.io - } -}) - -/*** TSI Host Widget ***/ -class WithBringupTSIHost extends HarnessBinder({ - case (th: BringupVCU118FPGATestHarnessImp, port: TLMemPort, chipId: Int) => { - val tsiBundles = th.bringupOuter.tsiDdrClient.out.map(_._1) - val tsiDdrClientBundle = Wire(new HeterogeneousBag(tsiBundles.map(_.cloneType))) - tsiBundles.zip(tsiDdrClientBundle).foreach { case (bundle, io) => bundle <> io } - tsiDdrClientBundle <> port.io - } - case (th: BringupVCU118FPGATestHarnessImp, port: TSIHostWidgetPort, chipId: Int) => { - th.bringupOuter.io_tsi_serial_bb.bundle <> port.io - } -}) diff --git a/fpga/src/main/scala/vcu118/bringup/IOBinders.scala b/fpga/src/main/scala/vcu118/bringup/IOBinders.scala deleted file mode 100644 index c80f828e..00000000 --- a/fpga/src/main/scala/vcu118/bringup/IOBinders.scala +++ /dev/null @@ -1,30 +0,0 @@ -package chipyard.fpga.vcu118.bringup - -import chisel3._ -import chisel3.reflect.DataMirror - -import freechips.rocketchip.util.{HeterogeneousBag} -import freechips.rocketchip.tilelink.{TLBundle} - -import sifive.blocks.devices.gpio.{HasPeripheryGPIOModuleImp} -import sifive.blocks.devices.i2c.{HasPeripheryI2CModuleImp} - -import testchipip.tsi.{HasPeripheryTSIHostWidget, TSIHostWidgetIO} - -import chipyard.iobinders.{OverrideIOBinder, Port, TLMemPort} - -case class TSIHostWidgetPort(val getIO: () => TSIHostWidgetIO) - extends Port[TSIHostWidgetIO] - -class WithTSITLIOPassthrough extends OverrideIOBinder({ - (system: HasPeripheryTSIHostWidget) => { - require(system.tsiTLMem.size == 1) - val io_tsi_tl_mem_pins_temp = IO(DataMirror.internal.chiselTypeClone[HeterogeneousBag[TLBundle]](system.tsiTLMem.head)).suggestName("tsi_tl_slave") - io_tsi_tl_mem_pins_temp <> system.tsiTLMem.head - - require(system.tsiSerial.size == 1) - val io_tsi_serial_pins_temp = IO(DataMirror.internal.chiselTypeClone[TSIHostWidgetIO](system.tsiSerial.head)).suggestName("tsi_serial") - io_tsi_serial_pins_temp <> system.tsiSerial.head - (Seq(TLMemPort(() => io_tsi_tl_mem_pins_temp), TSIHostWidgetPort(() => io_tsi_serial_pins_temp)), Nil) - } -}) diff --git a/fpga/src/main/scala/vcu118/bringup/TestHarness.scala b/fpga/src/main/scala/vcu118/bringup/TestHarness.scala deleted file mode 100644 index 3de1e595..00000000 --- a/fpga/src/main/scala/vcu118/bringup/TestHarness.scala +++ /dev/null @@ -1,99 +0,0 @@ -package chipyard.fpga.vcu118.bringup -import chisel3._ - -import freechips.rocketchip.diplomacy._ -import org.chipsalliance.cde.config._ -import freechips.rocketchip.subsystem._ -import freechips.rocketchip.tilelink._ -import freechips.rocketchip.prci._ -import sifive.fpgashells.shell.xilinx._ -import sifive.fpgashells.ip.xilinx._ -import sifive.fpgashells.shell._ -import sifive.fpgashells.clocks._ - -import sifive.blocks.devices.uart._ -import sifive.blocks.devices.spi._ -import sifive.blocks.devices.i2c._ -import sifive.blocks.devices.gpio._ - -import testchipip.tsi.{HasPeripheryTSIHostWidget, PeripheryTSIHostKey, TSIHostWidgetIO} -import testchipip.util.{TLSinkSetter} - -import chipyard.fpga.vcu118.{VCU118FPGATestHarness, VCU118FPGATestHarnessImp, DDR2VCU118ShellPlacer, SysClock2VCU118ShellPlacer} - -import chipyard.{ChipTop} -import chipyard.harness._ - -class BringupVCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118FPGATestHarness { - - /*** UART ***/ - - require(dp(PeripheryUARTKey).size == 2) - - // 2nd UART goes to the FMC UART - - val uart_fmc = Overlay(UARTOverlayKey, new BringupUARTVCU118ShellPlacer(this, UARTShellInput())) - - val io_fmc_uart_bb = BundleBridgeSource(() => (new UARTPortIO(dp(PeripheryUARTKey).last))) - dp(UARTOverlayKey).last.place(UARTDesignInput(io_fmc_uart_bb)) - - /*** I2C ***/ - - val i2c = Overlay(I2COverlayKey, new BringupI2CVCU118ShellPlacer(this, I2CShellInput())) - - val io_i2c_bb = BundleBridgeSource(() => (new I2CPort)) - dp(I2COverlayKey).head.place(I2CDesignInput(io_i2c_bb)) - - /*** GPIO ***/ - - val gpio = Seq.tabulate(dp(PeripheryGPIOKey).size)(i => { - val maxGPIOSupport = 32 // max gpio per gpio chip - val names = BringupGPIOs.names.slice(maxGPIOSupport*i, maxGPIOSupport*(i+1)) - Overlay(GPIOOverlayKey, new BringupGPIOVCU118ShellPlacer(this, GPIOShellInput(), names)) - }) - - val io_gpio_bb = dp(PeripheryGPIOKey).map { p => BundleBridgeSource(() => (new GPIOPortIO(p))) } - (dp(GPIOOverlayKey) zip dp(PeripheryGPIOKey)).zipWithIndex.map { case ((placer, params), i) => - placer.place(GPIODesignInput(params, io_gpio_bb(i))) - } - - /*** TSI Host Widget ***/ - require(dp(PeripheryTSIHostKey).size == 1) - - // use the 2nd system clock for the 2nd DDR - val sysClk2Node = dp(ClockInputOverlayKey).last.place(ClockInputDesignInput()).overlayOutput.node - - val ddr2PLL = dp(PLLFactoryKey)() - ddr2PLL := sysClk2Node - - val ddr2Clock = ClockSinkNode(freqMHz = dp(FPGAFrequencyKey)) - val ddr2Wrangler = LazyModule(new ResetWrangler) - val ddr2Group = ClockGroup() - ddr2Clock := ddr2Wrangler.node := ddr2Group := ddr2PLL - - val tsi_host = Overlay(TSIHostOverlayKey, new BringupTSIHostVCU118ShellPlacer(this, TSIHostShellInput())) - - val ddr2Node = dp(DDROverlayKey).last.place(DDRDesignInput(dp(PeripheryTSIHostKey).head.targetMasterPortParams.base, ddr2Wrangler.node, ddr2PLL)).overlayOutput.ddr - - val io_tsi_serial_bb = BundleBridgeSource(() => (new TSIHostWidgetIO(dp(PeripheryTSIHostKey).head.offchipSerialIfWidth))) - dp(TSIHostOverlayKey).head.place(TSIHostDesignInput(dp(PeripheryTSIHostKey).head.offchipSerialIfWidth, io_tsi_serial_bb)) - - // connect 1 mem. channel to the FPGA DDR - val tsiDdrClient = TLClientNode(Seq(TLMasterPortParameters.v1(Seq(TLMasterParameters.v1( - name = "chip_ddr", - sourceId = IdRange(0, 64) - ))))) - (ddr2Node - := TLFragmenter(8,64,holdFirstDeny=true) - := TLCacheCork() - := TLAtomicAutomata(passthrough=false) - := TLSinkSetter(64) - := tsiDdrClient) - - // module implementation - override lazy val module = new BringupVCU118FPGATestHarnessImp(this) -} - -class BringupVCU118FPGATestHarnessImp(_outer: BringupVCU118FPGATestHarness) extends VCU118FPGATestHarnessImp(_outer) { - lazy val bringupOuter = _outer -} From bdf207a2897978ab32671cf843e37c215b38d68d Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Mon, 29 Jan 2024 09:37:52 -0800 Subject: [PATCH 09/13] Update dead doc links --- docs/Customization/Boot-Process.rst | 2 +- docs/Generators/Hwacha.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Customization/Boot-Process.rst b/docs/Customization/Boot-Process.rst index 52ea32c1..9f745b7d 100644 --- a/docs/Customization/Boot-Process.rst +++ b/docs/Customization/Boot-Process.rst @@ -74,6 +74,6 @@ mode, thus starting userspace execution. The easiest way to build a BBL image that boots Linux is to use the FireMarshal tool that lives in the `firesim-software `_ repository. Directions on how to use FireMarshal can be found in the -:fsim_doc:`FireSim documentation `. +:fsim_doc:`FireSim documentation `. Using FireMarshal, you can add custom kernel configurations and userspace software to your workload. diff --git a/docs/Generators/Hwacha.rst b/docs/Generators/Hwacha.rst index 1980cddf..62f4dc06 100644 --- a/docs/Generators/Hwacha.rst +++ b/docs/Generators/Hwacha.rst @@ -5,7 +5,7 @@ The Hwacha project is developing a new vector architecture for future computer s The Hwacha project is inspired by traditional vector machines from the 70s and 80s, and lessons learned from our previous vector-thread architectures such as Scale and Maven The Hwacha project includes the Hwacha microarchitecture generator, as well as the ``XHwacha`` non-standard RISC-V extension. Hwacha does not implement the RISC-V standard vector extension proposal. -For more information on the Hwacha project, please visit the `Hwacha website `__. +For more information on the Hwacha project, please visit the `Hwacha website `__ or search for "Krste Asanovic Hwacha" on Google Scholar for publications. To add the Hwacha vector unit to an SoC, you should add the ``hwacha.DefaultHwachaConfig`` config fragment to the SoC configurations. The Hwacha vector unit uses the RoCC port of a Rocket or BOOM `tile`, and by default connects to the memory system through the `System Bus` (i.e., directly to the L2 cache). From eb93102f34d27955abffc88e2578e9c70b8b2c94 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 29 Jan 2024 11:15:14 -0800 Subject: [PATCH 10/13] Support BINARIES_DIR make flag --- variables.mk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/variables.mk b/variables.mk index fc2fc127..63519983 100644 --- a/variables.mk +++ b/variables.mk @@ -26,6 +26,7 @@ HELP_PROJECT_VARIABLES = \ HELP_SIMULATION_VARIABLES = \ " BINARY = riscv elf binary that the simulator will run when using the run-binary* targets" \ " BINARIES = list of riscv elf binary that the simulator will run when using the run-binaries* targets" \ +" BINARIES_DIR = directory of riscv elf binaries that the simulator will run when using the run-binaries* targets" \ " LOADMEM = riscv elf binary that should be loaded directly into simulated DRAM. LOADMEM=1 will load the BINARY elf" \ " LOADARCH = path to a architectural checkpoint directory that should end in .loadarch/, for restoring from a checkpoint" \ " VERBOSE_FLAGS = flags used when doing verbose simulation [$(VERBOSE_FLAGS)]" \ @@ -288,6 +289,10 @@ override get_out_name = $(shell basename $(dir $(1))) override LOADMEM = 1 endif +ifneq ($(BINARIES_DIR),) +override BINARIES = $(shell find -L $(BINARIES_DIR) -type f -print 2> /dev/null) +endif + ######################################################################################### # build output directory for compilation ######################################################################################### From 51a67fbd8fd9b00634cb7432cee0f6b97b6eadfa Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 29 Jan 2024 13:40:23 -0800 Subject: [PATCH 11/13] Update MMIO peripheral docs --- .../Incorporating-Verilog-Blocks.rst | 14 ++++++++++---- docs/Customization/MMIO-Peripherals.rst | 11 ++++------- docs/TileLink-Diplomacy-Reference/NodeTypes.rst | 2 +- .../{Register-Router.rst => Register-Node.rst} | 15 ++++++--------- docs/TileLink-Diplomacy-Reference/index.rst | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) rename docs/TileLink-Diplomacy-Reference/{Register-Router.rst => Register-Node.rst} (91%) diff --git a/docs/Customization/Incorporating-Verilog-Blocks.rst b/docs/Customization/Incorporating-Verilog-Blocks.rst index 7724ffb2..fde44411 100644 --- a/docs/Customization/Incorporating-Verilog-Blocks.rst +++ b/docs/Customization/Incorporating-Verilog-Blocks.rst @@ -99,10 +99,16 @@ Instantiating the BlackBox and Defining MMIO Next, we must instantiate the blackbox. In order to take advantage of diplomatic memory mapping on the system bus, we still have to -integrate the peripheral at the Chisel level by mixing -peripheral-specific traits into a ``TLRegisterRouter``. The ``params`` -member and ``HasRegMap`` base trait should look familiar from the -previous memory-mapped GCD device example. +integrate the peripheral at the Chisel level by instantiating a LazyModule wrapper +that instantiates a TileLink RegisterNode. + +.. literalinclude:: ../../generators/chipyard/src/main/scala/example/GCD.scala + :language: scala + :start-after: DOC include start: GCD router + :end-before: DOC include end: GCD router + +Within the LazyModule, the ``regmap`` function can be called to attach wires and +registers to the MMIO port. .. literalinclude:: ../../generators/chipyard/src/main/scala/example/GCD.scala :language: scala diff --git a/docs/Customization/MMIO-Peripherals.rst b/docs/Customization/MMIO-Peripherals.rst index 82a9f27b..51540cb4 100644 --- a/docs/Customization/MMIO-Peripherals.rst +++ b/docs/Customization/MMIO-Peripherals.rst @@ -3,9 +3,9 @@ MMIO Peripherals ================== -The easiest way to create a MMIO peripheral is to use the ``TLRegisterRouter`` or ``AXI4RegisterRouter`` widgets, which abstracts away the details of handling the interconnect protocols and provides a convenient interface for specifying memory-mapped registers. Since Chipyard and Rocket Chip SoCs primarily use Tilelink as the on-chip interconnect protocol, this section will primarily focus on designing Tilelink-based peripherals. However, see ``generators/chipyard/src/main/scala/example/GCD.scala`` for how an example AXI4 based peripheral is defined and connected to the Tilelink graph through converters. +The easiest way to create a MMIO peripheral is to follow the GCD TileLink MMIO example. Since Chipyard and Rocket Chip SoCs primarily use Tilelink as the on-chip interconnect protocol, this section will primarily focus on designing Tilelink-based peripherals. However, see ``generators/chipyard/src/main/scala/example/GCD.scala`` for how an example AXI4 based peripheral is defined and connected to the Tilelink graph through converters. -To create a RegisterRouter-based peripheral, you will need to specify a parameter case class for the configuration settings, a bundle trait with the extra top-level ports, and a module implementation containing the actual RTL. +To create a MMIO-mapped peripheral, you will need to specify a ``LazyModule`` wrapper containing the TileLink port as a Diplomacy Node, as well as an internal ``LazyModuleImp`` class that defines the MMIO's implementation and any non-TileLink I/O. For this example, we will show how to connect a MMIO peripheral which computes the GCD. The full code can be found in ``generators/chipyard/src/main/scala/example/GCD.scala``. @@ -70,17 +70,14 @@ Top-level Traits ---------------- After creating the module, we need to hook it up to our SoC. -The ``LazyModule`` trait runs setup code that must execute before all the hardware gets elaborated. -For a simple memory-mapped peripheral, this just involves connecting the peripheral's TileLink node to the relevant bus. +The ``LazyModule`` abstract class containst the TileLink node representing the peripheral's I/O. +For a simple memory-mapped peripheral, connecting the peripheral's TileLink node must be connected to the relevant bu. .. literalinclude:: ../../generators/chipyard/src/main/scala/example/GCD.scala :language: scala :start-after: DOC include start: GCD lazy trait :end-before: DOC include end: GCD lazy trait -Note that the ``GCDTL`` class we created from the register router is itself a ``LazyModule``. -Register routers have a TileLink node simply named "node", which we can hook up to the Rocket Chip bus. -This will automatically add address map and device tree entries for the peripheral. Also observe how we have to place additional AXI4 buffers and converters for the AXI4 version of this peripheral. Peripherals which expose I/O can use `InModuleBody` to punch their I/O to the `DigitalTop` module. diff --git a/docs/TileLink-Diplomacy-Reference/NodeTypes.rst b/docs/TileLink-Diplomacy-Reference/NodeTypes.rst index c31aafba..7c03e5e7 100644 --- a/docs/TileLink-Diplomacy-Reference/NodeTypes.rst +++ b/docs/TileLink-Diplomacy-Reference/NodeTypes.rst @@ -134,7 +134,7 @@ to handle TileLink requests, it is usually much easier to use a register node. This type of node provides a ``regmap`` method that allows you to specify control/status registers and automatically generates the logic to handle the TileLink protocol. More information about how to use register nodes can be -found in :ref:`TileLink-Diplomacy-Reference/Register-Router:Register Router`. +found in :ref:`TileLink-Diplomacy-Reference/Register-Node:Register Node`. Identity Node ------------- diff --git a/docs/TileLink-Diplomacy-Reference/Register-Router.rst b/docs/TileLink-Diplomacy-Reference/Register-Node.rst similarity index 91% rename from docs/TileLink-Diplomacy-Reference/Register-Router.rst rename to docs/TileLink-Diplomacy-Reference/Register-Node.rst index 0a677a0d..2bccce62 100644 --- a/docs/TileLink-Diplomacy-Reference/Register-Router.rst +++ b/docs/TileLink-Diplomacy-Reference/Register-Node.rst @@ -1,4 +1,4 @@ -Register Router +Register Node =============== Memory-mapped devices generally follow a common pattern. They expose a set @@ -10,10 +10,7 @@ While designers can manually instantiate a manager node and write the logic for exposing registers themselves, it's much easier to use RocketChip's ``regmap`` interface, which can generate most of the glue logic. -For TileLink devices, you can use the ``regmap`` interface by extending -the ``TLRegisterRouter`` class, as shown in :ref:`mmio-accelerators`, -or you can create a regular LazyModule and instantiate a ``TLRegisterNode``. -This section will focus on the second method. +For TileLink devices, you can use the ``regmap`` interface of the ``TLRegisterNode``. Basic Usage ----------- @@ -32,7 +29,7 @@ The default value is 4 bytes. The ``concurrency`` argument is the size of the internal queue for TileLink requests. By default, this value is 0, which means there will be no queue. This value must be greater than 0 if you wish to decoupled requests and responses for register accesses. This is discussed -in :ref:`TileLink-Diplomacy-Reference/Register-Router:Using Functions`. +in :ref:`TileLink-Diplomacy-Reference/Register-Node:Using Functions`. The main way to interact with the node is to call the ``regmap`` method, which takes a sequence of pairs. The first element of the pair is an offset from the @@ -123,12 +120,12 @@ output for write. In order to use this variant, you need to set ``concurrency`` to a value larger than 0. -Register Routers for Other Protocols +Register Nodes for Other Protocols ------------------------------------ -One useful feature of the register router interface is that you can easily +One useful feature of the register node interface is that you can easily change the protocol being used. For instance, in the first example in -:ref:`TileLink-Diplomacy-Reference/Register-Router:Basic Usage`, you could simply change the ``TLRegisterNode`` to +:ref:`TileLink-Diplomacy-Reference/Register-Node:Basic Usage`, you could simply change the ``TLRegisterNode`` to and ``AXI4RegisterNode``. .. literalinclude:: ../../generators/chipyard/src/main/scala/example/RegisterNodeExample.scala diff --git a/docs/TileLink-Diplomacy-Reference/index.rst b/docs/TileLink-Diplomacy-Reference/index.rst index 9c70287d..92895e08 100644 --- a/docs/TileLink-Diplomacy-Reference/index.rst +++ b/docs/TileLink-Diplomacy-Reference/index.rst @@ -28,5 +28,5 @@ A detailed specification of the TileLink 1.7 protocol can be found on the NodeTypes Diplomacy-Connectors EdgeFunctions - Register-Router + Register-Node Widgets From 99d82673d24c41854b28c7c2af06a440e956d659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Thu, 1 Feb 2024 07:33:37 +0100 Subject: [PATCH 12/13] vlsi/Makefile: truncate file SRAM_GENERATOR_CONF previously the target would append, not truncate the file, which could lead to duplicate yaml entries in that file when the target was re-run. --- vlsi/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vlsi/Makefile b/vlsi/Makefile index 074ec66a..14feb6fb 100644 --- a/vlsi/Makefile +++ b/vlsi/Makefile @@ -100,8 +100,8 @@ $(SMEMS_HAMMER): $(TOP_SMEMS_FILE) $(SRAM_GENERATOR_CONF): $(SMEMS_HAMMER) mkdir -p $(dir $@) - echo "vlsi.inputs.sram_parameters: '$(SMEMS_HAMMER)'" >> $@ - echo "vlsi.inputs.sram_parameters_meta: [\"transclude\", \"json2list\"]">> $@ + echo "vlsi.inputs.sram_parameters: '$(SMEMS_HAMMER)'" > $@ + echo "vlsi.inputs.sram_parameters_meta: [\"transclude\", \"json2list\"]" >> $@ $(SRAM_CONF): $(SRAM_GENERATOR_CONF) cd $(vlsi_dir) && $(HAMMER_EXEC) -e $(ENV_YML) $(foreach x,$(INPUT_CONFS) $(SRAM_GENERATOR_CONF), -p $(x)) --obj_dir $(build_dir) sram_generator From 54323592652b2efd9f413c635a548e91b73d4c40 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Thu, 1 Feb 2024 10:36:23 -0800 Subject: [PATCH 13/13] Add note on deprecating TLRegisterRouter --- docs/Customization/MMIO-Peripherals.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/Customization/MMIO-Peripherals.rst b/docs/Customization/MMIO-Peripherals.rst index 51540cb4..105d3f70 100644 --- a/docs/Customization/MMIO-Peripherals.rst +++ b/docs/Customization/MMIO-Peripherals.rst @@ -48,6 +48,16 @@ triggering write to ``y``. Polling can be used for status checks. :start-after: DOC include start: GCD instance regmap :end-before: DOC include end: GCD instance regmap +.. note:: + In older versions of Chipyard and Rocket-Chip, a ``TLRegisterRouter`` abstrat + class was used to abstract away the construction of the ``TLRegisterNode`` and + ``LazyModule`` classes necessary to construct MMIO peripherals. This was removed, + in favor of requiring users to explicitly construct the necessary classes. + + This matches more closely how standard ``Modules`` and ``LazyModules`` are + constructed, making it clearer how a MMIO peripheral fits into the ``Module`` + and ``LazyModule`` design patterns. + Connecting by TileLink ----------------------