Skip to content
This repository has been archived by the owner on Jun 16, 2024. It is now read-only.

Commit

Permalink
oh lordy he comin'. (SimTop/SimPlatform, res clock optional.)
Browse files Browse the repository at this point in the history
  • Loading branch information
kivikakk committed May 23, 2024
1 parent 5b181c3 commit 1dad3e2
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 73 deletions.
18 changes: 13 additions & 5 deletions src/main/scala/ee/hrzn/chryse/platform/ChryseTop.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@ import chisel3._
import chisel3.experimental.noPrefix

import scala.collection.mutable
import scala.language.implicitConversions

trait ChryseTop extends RawModule {
override def desiredName = "chrysetop"

case class ConnectedResource(pin: resource.Pin, frequencyHz: Option[Int])

object ConnectedResource {
implicit def pin2Cr(pin: resource.Pin): ConnectedResource =
ConnectedResource(pin, None)
}

protected def connectResources(
platform: PlatformBoard[_ <: PlatformBoardResources],
clock: Clock,
clock: Option[Clock],
): Map[String, ConnectedResource] = {
val connected = mutable.Map[String, ConnectedResource]()

Expand All @@ -21,7 +27,9 @@ trait ChryseTop extends RawModule {
res match {
case res: resource.ClockSource =>
if (res.ioInst.isDefined) {
throw new Exception("clock must be manually handled for now")
throw new Exception(
"clock sources must be manually handled for now",
)
}
// NOTE: we can't just say clki := platform.resources.clock in our top
// here, since that'll define an input IO in *this* module which we
Expand All @@ -30,14 +38,14 @@ trait ChryseTop extends RawModule {
res.pinId.get,
Some(platform.clockHz),
)
clock := noPrefix(IO(Input(Clock())).suggestName(name))
clock.get := noPrefix(IO(Input(Clock())).suggestName(name))

case _ =>
if (platformConnect(name, res)) {
connected += name -> ConnectedResource(res.pinId.get, None)
connected += name -> res.pinId.get
} else if (res.ioInst.isDefined) {
connected += name -> ConnectedResource(res.pinId.get, None)
res.makeIoConnection()
connected += name -> res.pinId.get
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ abstract class PlatformBoardResources {
}
}

val clock: resource.ClockSource

def all: Seq[ResourceData[_ <: Data]] =
ResourceBase.allFromBoardResources(this)
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class ICE40Top[Top <: Module](
// TODO (iCE40): allow clock source override.

private val connectedResources =
connectResources(platform, clki)
connectResources(platform, Some(clki))

override protected def platformConnect(
name: String,
Expand Down
3 changes: 2 additions & 1 deletion src/main/scala/ee/hrzn/chryse/platform/resource/InOut.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package ee.hrzn.chryse.platform.resource
import chisel3._

// TODO: it's an error to use both "i" and "o" (tristate is a different kettle
// of fish entirely).
// of fish entirely) — this'll currently throw an obscure Chisel error (since
// they'll both get the same name).
class InOut extends ResourceBase with ResourceSinglePin {
val i = new ResourceData[Bool](Input(Bool())) {}
val o = new ResourceData[Bool](Output(Bool())) {}
Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/ee/hrzn/chryse/platform/resource/Pin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ case class PinInt(p: Int) extends Pin {
}

object Pin {
def apply(p: String): Pin = string2Pin(p)

implicit def string2Pin(p: String): Pin = PinString(p)
implicit def int2Pin(p: Int): Pin = PinInt(p)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ package ee.hrzn.chryse.platform
import chisel3._
import chiseltest._
import circt.stage.ChiselStage
import ee.hrzn.chryse.chisel.BuilderContext
import ee.hrzn.chryse.platform.ice40.ICE40Top
import ee.hrzn.chryse.platform.ice40.IceBreakerPlatform
import ee.hrzn.chryse.platform.ice40.PCF
import ee.hrzn.chryse.verilog
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should._
Expand All @@ -17,12 +13,12 @@ class PlatformBoardResourcesSpec
with ChiselScalatestTester {
behavior.of("PlatformBoardResources")

def iceBreakerSVAndTop[Top <: Module](
def simSVAndTop[Top <: Module](
gen: Platform => Top,
): (String, ICE40Top[Top]) = {
val plat = IceBreakerPlatform()
): (String, SimTop[Top]) = {
val plat = SimPlatform()

var top: ICE40Top[Top] = null
var top: SimTop[Top] = null
val rtl = ChiselStage.emitSystemVerilog(
{
top = plat(gen(plat))
Expand All @@ -34,36 +30,24 @@ class PlatformBoardResourcesSpec
}

it should "detect resource use and generate PCFs accordingly" in {
val (_, top) = iceBreakerSVAndTop(new DetectionTop()(_))
top.lastPCF should be(
Some(
PCF(
Map(
"clock" -> 35,
"ledg" -> 37,
"uart_rx" -> 6,
"uart_tx" -> 9,
"ubtn" -> 10,
),
Map("clock" -> 12_000_000),
),
val (_, top) = simSVAndTop(new DetectionTop()(_))
top.connectedResources should be(
Map[String, top.ConnectedResource](
"ledg" -> resource.Pin("E5"),
"uart_rx" -> resource.Pin("C3"),
"uart_tx" -> resource.Pin("D4"),
"ubtn" -> resource.Pin("B2"),
),
)
}

it should "invert inputs as requested and use the correct top-level IO names" in {
val (rtl, top) = iceBreakerSVAndTop(new InversionTop()(_))
top.lastPCF should be(
Some(
PCF(
Map(
"clock" -> 35,
"ledg" -> 37,
"uart_tx" -> 9,
"ubtn" -> 10,
),
Map("clock" -> 12_000_000),
),
val (rtl, top) = simSVAndTop(new InversionTop()(_))
top.connectedResources should be(
Map[String, top.ConnectedResource](
"ledg" -> resource.Pin("E5"),
"uart_tx" -> resource.Pin("D4"),
"ubtn" -> resource.Pin("B2"),
),
)

Expand All @@ -74,59 +58,53 @@ class PlatformBoardResourcesSpec

verilog.InterfaceExtractor(rtl) should contain(
"chrysetop" -> verilog.InterfaceExtractor.Module(
inputs = Seq("clock", "ubtn"),
inputs = Seq("clock", "reset", "ubtn"),
outputs = Seq("uart_tx", "ledg"),
),
)
}

it should "handle in/out resources" in {
val (rtl, top) = iceBreakerSVAndTop(new InOutTop()(_))
top.lastPCF should be(
Some(
PCF(
Map(
"clock" -> 35,
"ubtn" -> 10,
"uart_rx" -> 6,
"uart_tx" -> 9,
"ledr" -> 11,
"pmod1a1" -> 4,
"pmod1a2" -> 2,
"pmod1b1" -> 43,
"pmod1b2" -> 38,
),
Map("clock" -> 12_000_000),
),
val (rtl, top) = simSVAndTop(new InOutTop()(_))
top.connectedResources should be(
Map[String, top.ConnectedResource](
"ubtn" -> resource.Pin("B2"),
"uart_rx" -> resource.Pin("C3"),
"uart_tx" -> resource.Pin("D4"),
"ledr" -> resource.Pin("F6"),
"pmod1" -> resource.Pin("H8"),
"pmod2" -> resource.Pin("I9"),
"pmod7" -> resource.Pin("L12"),
"pmod8" -> resource.Pin("M13"),
),
)

// HACK: We should behaviourally evaluate the result.
rtl should include("pmod1a1_int = view__uart_rx_int")
rtl should include("uart_tx_int = view__pmod1a2_int")
rtl should include("pmod1b1_int = view__ubtn_int")
rtl should include("pmod1_int = view__uart_rx_int")
rtl should include("uart_tx_int = view__pmod2_int")
rtl should include("pmod7_int = view__ubtn_int")
(rtl should include).regex(raw"\.view__ubtn_int\s*\(~ubtn\),")
rtl should include("ledr_int = view__pmod1b2_int")
rtl should include("ledr_int = view__pmod8_int")
(rtl should include).regex(raw"\.ledr_int\s*\(_top_ledr_int\),")
(rtl should include).regex(raw"assign ledr = ~_top_ledr_int;")

verilog.InterfaceExtractor(rtl) should contain(
"chrysetop" -> verilog.InterfaceExtractor.Module(
inputs = Seq("clock", "ubtn", "uart_rx", "pmod1a2", "pmod1b2"),
outputs = Seq("uart_tx", "ledr", "pmod1a1", "pmod1b1"),
inputs = Seq("clock", "reset", "ubtn", "uart_rx", "pmod2", "pmod8"),
outputs = Seq("uart_tx", "ledr", "pmod1", "pmod7"),
),
)
}
}

class DetectionTop(implicit platform: Platform) extends Module {
val plat = platform.asInstanceOf[IceBreakerPlatform]
val plat = platform.asInstanceOf[SimPlatform]
plat.resources.ledg := plat.resources.ubtn
plat.resources.uart.tx := plat.resources.uart.rx
}

class InversionTop(implicit platform: Platform) extends Module {
val plat = platform.asInstanceOf[IceBreakerPlatform]
val plat = platform.asInstanceOf[SimPlatform]
// User button is inverted.
// UART isn't inverted.
plat.resources.uart.tx := plat.resources.ubtn
Expand All @@ -135,12 +113,12 @@ class InversionTop(implicit platform: Platform) extends Module {
}

class InOutTop(implicit platform: Platform) extends Module {
val plat = platform.asInstanceOf[IceBreakerPlatform]
val plat = platform.asInstanceOf[SimPlatform]
// Treat pmod1a1 as output, 1a2 as input.
plat.resources.pmod1a(1).o := plat.resources.uart.rx
plat.resources.uart.tx := plat.resources.pmod1a(2).i
plat.resources.pmod(1).o := plat.resources.uart.rx
plat.resources.uart.tx := plat.resources.pmod(2).i

// Do the same with 1b1 and 1b2, but use inverted inputs/outputs.
plat.resources.pmod1b(1).o := plat.resources.ubtn
plat.resources.ledr := plat.resources.pmod1b(2).i
plat.resources.pmod(7).o := plat.resources.ubtn
plat.resources.ledr := plat.resources.pmod(8).i
}
45 changes: 45 additions & 0 deletions src/test/scala/ee/hrzn/chryse/platform/SimPlatform.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package ee.hrzn.chryse.platform

import chisel3._
import ee.hrzn.chryse.platform.PlatformBoard
import ee.hrzn.chryse.platform.PlatformBoardResources
import ee.hrzn.chryse.platform.resource

final case class SimPlatform() extends PlatformBoard[SimPlatformResources] {
val id = "sim"
val clockHz = 1_000_000

val nextpnrBinary = "xxx"
val nextpnrArgs = Seq()
val packBinary = "xxx"
val programBinary = "xxx"

val resources = new SimPlatformResources

override def apply[Top <: Module](genTop: => Top) = {
resources.setNames()
new SimTop(this, genTop)
}
}

class SimPlatformResources extends PlatformBoardResources {
val ubtn = resource.Button().inverted.onPin("B2")

val uart = resource.UART().onPins(rx = "C3", tx = "D4")

val ledg = resource.LED().inverted.onPin("E5")
val ledr = resource.LED().inverted.onPin("F6")
val led3 = resource.LED().inverted.onPin("G7")

val pmod = resource.Connector(
resource.InOut(),
1 -> "H8",
2 -> "I9",
3 -> "J10",
4 -> "K11",
7 -> "L12",
8 -> "M13",
9 -> "N14",
10 -> "O15",
)
}
17 changes: 17 additions & 0 deletions src/test/scala/ee/hrzn/chryse/platform/SimTop.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ee.hrzn.chryse.platform

import chisel3._
import ee.hrzn.chryse.platform.PlatformBoard
import ee.hrzn.chryse.platform.PlatformBoardResources
import ee.hrzn.chryse.platform.resource

class SimTop[Top <: Module](
platform: PlatformBoard[_ <: PlatformBoardResources],
genTop: => Top,
) extends Module
with ChryseTop {
private val top = Module(genTop)

val connectedResources =
connectResources(platform, None)
}

0 comments on commit 1dad3e2

Please sign in to comment.