From 2795646e5c3c5a8c442502a6ebf37ef5242616b1 Mon Sep 17 00:00:00 2001 From: Asherah Connor Date: Tue, 28 May 2024 22:14:34 +0300 Subject: [PATCH] WIP: make it possible to specify a pin in a resource which is wired manually by the platform. The use-case being USRMCLK for ECP5 SPI flash clock access. This is different to iCE40's ubtnReset, which is just a feature the (Chryse) platform provides. --- .../ee/hrzn/chryse/platform/ChryseTop.scala | 8 +++++-- .../chryse/platform/ecp5/ECP5Platform.scala | 8 ++++++- .../hrzn/chryse/platform/ecp5/ECP5Top.scala | 12 +++------- .../chryse/platform/ecp5/ECP5Variant.scala | 23 ++++++++++++++---- .../platform/ecp5/OrangeCrabPlatform.scala | 3 --- .../chryse/platform/ecp5/ULX3SPlatform.scala | 21 ++++++++++++---- .../hrzn/chryse/platform/ecp5/USRMCLK.scala | 11 +++++++++ .../chryse/platform/ice40/ICE40Platform.scala | 8 ++++++- .../hrzn/chryse/platform/ice40/ICE40Top.scala | 5 +++- .../platform/ice40/IceBreakerPlatform.scala | 5 ---- .../ee/hrzn/chryse/platform/ice40/PCF.scala | 4 ++-- .../chryse/platform/resource/Connector.scala | 5 +++- .../hrzn/chryse/platform/resource/Pin.scala | 18 -------------- .../platform/resource/PinConnected.scala | 24 +++++++++++++++++++ .../chryse/platform/resource/SPIFlash.scala | 10 ++++++++ 15 files changed, 114 insertions(+), 51 deletions(-) create mode 100644 src/main/scala/ee/hrzn/chryse/platform/ecp5/USRMCLK.scala delete mode 100644 src/main/scala/ee/hrzn/chryse/platform/resource/Pin.scala create mode 100644 src/main/scala/ee/hrzn/chryse/platform/resource/PinConnected.scala diff --git a/src/main/scala/ee/hrzn/chryse/platform/ChryseTop.scala b/src/main/scala/ee/hrzn/chryse/platform/ChryseTop.scala index 766ea64..2881fec 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ChryseTop.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ChryseTop.scala @@ -3,6 +3,7 @@ package ee.hrzn.chryse.platform import chisel3._ import chisel3.experimental.noPrefix import ee.hrzn.chryse.chisel.directionOf +import ee.hrzn.chryse.platform.resource.Pin import scala.collection.mutable import scala.language.existentials @@ -11,10 +12,13 @@ import scala.language.implicitConversions trait ChryseTop extends RawModule { override def desiredName = "chrysetop" - case class ConnectedResource(pin: resource.Pin, frequencyHz: Option[Int]) + case class ConnectedResource( + pin: Pin, + frequencyHz: Option[Int], + ) object ConnectedResource { - implicit def pin2Cr(pin: resource.Pin): ConnectedResource = + implicit def pin2Cr(pin: Pin): ConnectedResource = ConnectedResource(pin, None) } diff --git a/src/main/scala/ee/hrzn/chryse/platform/ecp5/ECP5Platform.scala b/src/main/scala/ee/hrzn/chryse/platform/ecp5/ECP5Platform.scala index 334153d..1787ebf 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ecp5/ECP5Platform.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ecp5/ECP5Platform.scala @@ -3,14 +3,20 @@ package ee.hrzn.chryse.platform.ecp5 import chisel3._ import ee.hrzn.chryse.ChryseApp import ee.hrzn.chryse.platform.PlatformBoard +import ee.hrzn.chryse.platform.PlatformBoardResources import ee.hrzn.chryse.tasks.BaseTask -trait ECP5Platform { this: PlatformBoard[_] => +trait ECP5Platform { this: PlatformBoard[_ <: PlatformBoardResources] => type TopPlatform[Top <: Module] = ECP5Top[Top] val ecp5Variant: ECP5Variant val ecp5Package: String + override def apply[Top <: Module](genTop: => Top) = { + resources.setNames() + new ECP5Top(this, genTop) + } + def yosysSynthCommand(top: String) = s"synth_ecp5 -top $top" def build( diff --git a/src/main/scala/ee/hrzn/chryse/platform/ecp5/ECP5Top.scala b/src/main/scala/ee/hrzn/chryse/platform/ecp5/ECP5Top.scala index cc7bcf7..b1ba9bd 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ecp5/ECP5Top.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ecp5/ECP5Top.scala @@ -1,12 +1,14 @@ package ee.hrzn.chryse.platform.ecp5 import chisel3._ +import ee.hrzn.chryse.platform.ChryseTop import ee.hrzn.chryse.platform.Platform import ee.hrzn.chryse.platform.PlatformBoard import ee.hrzn.chryse.platform.PlatformBoardResources class ECP5Top[Top <: Module](platform: Platform, genTop: => Top) - extends RawModule { + extends RawModule + with ChryseTop { override def desiredName = "ecp5top" private val clki = IO(Input(Clock())) @@ -26,11 +28,3 @@ class ECP5Top[Top <: Module](platform: Platform, genTop: => Top) private val top = withClockAndReset(clki, false.B)(Module(genTop)) } - -object ECP5Top { - def apply[Top <: Module]( - platform: PlatformBoard[_ <: PlatformBoardResources], - genTop: => Top, - ) = - new ECP5Top(platform, genTop) -} diff --git a/src/main/scala/ee/hrzn/chryse/platform/ecp5/ECP5Variant.scala b/src/main/scala/ee/hrzn/chryse/platform/ecp5/ECP5Variant.scala index 3ff4440..ee34a02 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ecp5/ECP5Variant.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ecp5/ECP5Variant.scala @@ -1,6 +1,21 @@ package ee.hrzn.chryse.platform.ecp5 -sealed trait ECP5Variant { val arg: String } -final case object LFE5U_25F extends ECP5Variant { val arg = "--25k" } -final case object LFE5U_45F extends ECP5Variant { val arg = "--45k" } -final case object LFE5U_85F extends ECP5Variant { val arg = "--85k" } +sealed trait ECP5Variant { + val id: String + val arg: String +} + +final case object LFE5U_25F extends ECP5Variant { + val id = "25f" + val arg = "--25k" +} + +final case object LFE5U_45F extends ECP5Variant { + val id = "45f" + val arg = "--45k" +} + +final case object LFE5U_85F extends ECP5Variant { + val id = "85f" + val arg = "--85k" +} diff --git a/src/main/scala/ee/hrzn/chryse/platform/ecp5/OrangeCrabPlatform.scala b/src/main/scala/ee/hrzn/chryse/platform/ecp5/OrangeCrabPlatform.scala index 56665b4..6c730c7 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ecp5/OrangeCrabPlatform.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ecp5/OrangeCrabPlatform.scala @@ -15,9 +15,6 @@ case class OrangeCrabPlatform(ecp5Variant: ECP5Variant) val ecp5Package = "csfBGA285" val resources = new OrangeCrabPlatformResources - - override def apply[Top <: Module](genTop: => Top) = - ECP5Top(this, genTop) } class OrangeCrabPlatformResources extends PlatformBoardResources { diff --git a/src/main/scala/ee/hrzn/chryse/platform/ecp5/ULX3SPlatform.scala b/src/main/scala/ee/hrzn/chryse/platform/ecp5/ULX3SPlatform.scala index 2ae8244..097ae5b 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ecp5/ULX3SPlatform.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ecp5/ULX3SPlatform.scala @@ -11,15 +11,12 @@ import ee.hrzn.chryse.platform.resource case class ULX3SPlatform(ecp5Variant: ECP5Variant) extends PlatformBoard[ULX3SPlatformResources] with ECP5Platform { - val id = "orangecrab" + val id = s"ulx3s-${ecp5Variant.id}" val clockHz = 25_000_000 val ecp5Package = "caBGA381" val resources = new ULX3SPlatformResources - - override def apply[Top <: Module](genTop: => Top) = - ECP5Top(this, genTop) } class ULX3SPlatformResources extends PlatformBoardResources { @@ -30,12 +27,28 @@ class ULX3SPlatformResources extends PlatformBoardResources { val program = resource.Button().inverted.onPin("M4").withAttributes("PULLMODE" -> "UP") + // TODO: also expose RTS, DTR. + var uart = resource + .UART() + .onPins(rx = "M1", tx = "L4") + var uartTxEnable = new resource.ResourceData[Bool](Bool()) { + name = Some("uartTxEnable") + } + // val leds = // resource // .LEDs() // .onPins("B2", "C2", "C1", "D2", "D1", "E2", "E1", "H3") // .withAttributes("DRIVE" -> "4") + val spiFlash = resource + .SPIFlash() + .onPins( + csN = "R2", clock = USRMCLK, copi = "W2", cipo = "V2", wpN = "Y2", + holdN = "W1", + ) + .withAttributes("PULLMODE" -> "NONE", "DRIVE" -> "4") + // val buttons = // DIP switches // UART diff --git a/src/main/scala/ee/hrzn/chryse/platform/ecp5/USRMCLK.scala b/src/main/scala/ee/hrzn/chryse/platform/ecp5/USRMCLK.scala new file mode 100644 index 0000000..e1dbea2 --- /dev/null +++ b/src/main/scala/ee/hrzn/chryse/platform/ecp5/USRMCLK.scala @@ -0,0 +1,11 @@ +package ee.hrzn.chryse.platform.ecp5 + +import ee.hrzn.chryse.platform.resource.Pin +import ee.hrzn.chryse.platform.resource.PinPlatform + +import scala.language.implicitConversions + +object USRMCLK { + implicit def usrmclk2Pin(usrmclk: this.type): Pin = + PinPlatform(this) +} diff --git a/src/main/scala/ee/hrzn/chryse/platform/ice40/ICE40Platform.scala b/src/main/scala/ee/hrzn/chryse/platform/ice40/ICE40Platform.scala index 89462b6..00db26f 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ice40/ICE40Platform.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ice40/ICE40Platform.scala @@ -3,14 +3,20 @@ package ee.hrzn.chryse.platform.ice40 import chisel3._ import ee.hrzn.chryse.ChryseApp import ee.hrzn.chryse.platform.PlatformBoard +import ee.hrzn.chryse.platform.PlatformBoardResources import ee.hrzn.chryse.tasks.BaseTask -trait ICE40Platform { this: PlatformBoard[_] => +trait ICE40Platform { this: PlatformBoard[_ <: PlatformBoardResources] => type TopPlatform[Top <: Module] = ICE40Top[Top] val ice40Variant: ICE40Variant val ice40Package: String + override def apply[Top <: Module](genTop: => Top) = { + resources.setNames() + new ICE40Top(this, genTop) + } + def yosysSynthCommand(top: String) = s"synth_ice40 -top $top" def build( diff --git a/src/main/scala/ee/hrzn/chryse/platform/ice40/ICE40Top.scala b/src/main/scala/ee/hrzn/chryse/platform/ice40/ICE40Top.scala index 585be6c..18e03d5 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ice40/ICE40Top.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ice40/ICE40Top.scala @@ -122,7 +122,10 @@ class ICE40Top[Top <: Module]( val lastPCF = Some( PCF( connectedResources - .map { case (name, cr) => (name, cr.pin) } + .map { case (name, cr) => + // iCE40 has no PinPlatforms. + (name, cr.pin.asInstanceOf[resource.PinConnected]) + } .to(Map), connectedResources .flatMap { case (name, cr) => cr.frequencyHz.map((name, _)) } diff --git a/src/main/scala/ee/hrzn/chryse/platform/ice40/IceBreakerPlatform.scala b/src/main/scala/ee/hrzn/chryse/platform/ice40/IceBreakerPlatform.scala index b1d8c90..6fb215e 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ice40/IceBreakerPlatform.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ice40/IceBreakerPlatform.scala @@ -17,11 +17,6 @@ case class IceBreakerPlatform( val ice40Package = "sg48" val resources = new IceBreakerPlatformResources - - override def apply[Top <: Module](genTop: => Top) = { - resources.setNames() - new ICE40Top(this, genTop) - } } class IceBreakerPlatformResources extends PlatformBoardResources { diff --git a/src/main/scala/ee/hrzn/chryse/platform/ice40/PCF.scala b/src/main/scala/ee/hrzn/chryse/platform/ice40/PCF.scala index 8cb3cb5..e287138 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ice40/PCF.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ice40/PCF.scala @@ -1,8 +1,8 @@ package ee.hrzn.chryse.platform.ice40 -import ee.hrzn.chryse.platform.resource.Pin +import ee.hrzn.chryse.platform.resource.PinConnected -case class PCF(ios: Map[String, Pin], freqs: Map[String, Int]) { +case class PCF(ios: Map[String, PinConnected], freqs: Map[String, Int]) { for { name <- freqs.keysIterator } if (!ios.isDefinedAt(name)) throw new IllegalArgumentException( diff --git a/src/main/scala/ee/hrzn/chryse/platform/resource/Connector.scala b/src/main/scala/ee/hrzn/chryse/platform/resource/Connector.scala index a8d7058..177d9f1 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/resource/Connector.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/resource/Connector.scala @@ -26,6 +26,9 @@ class Connector[Ix, E <: ResourceSinglePin]( } object Connector { - def apply[Ix, E <: ResourceSinglePin](gen: => E, ixToPin: (Ix, Pin)*) = + def apply[Ix, E <: ResourceSinglePin]( + gen: => E, + ixToPin: (Ix, Pin)*, + ) = new Connector(gen, ixToPin: _*) } diff --git a/src/main/scala/ee/hrzn/chryse/platform/resource/Pin.scala b/src/main/scala/ee/hrzn/chryse/platform/resource/Pin.scala deleted file mode 100644 index 79d777c..0000000 --- a/src/main/scala/ee/hrzn/chryse/platform/resource/Pin.scala +++ /dev/null @@ -1,18 +0,0 @@ -package ee.hrzn.chryse.platform.resource - -import scala.language.implicitConversions - -sealed trait Pin -case class PinString(p: String) extends Pin { - override def toString(): String = p -} -case class PinInt(p: Int) extends Pin { - override def toString(): String = s"$p" -} - -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) -} diff --git a/src/main/scala/ee/hrzn/chryse/platform/resource/PinConnected.scala b/src/main/scala/ee/hrzn/chryse/platform/resource/PinConnected.scala new file mode 100644 index 0000000..c09af69 --- /dev/null +++ b/src/main/scala/ee/hrzn/chryse/platform/resource/PinConnected.scala @@ -0,0 +1,24 @@ +package ee.hrzn.chryse.platform.resource + +import scala.language.implicitConversions + +sealed trait Pin + +case class PinPlatform(p: Any) extends Pin {} + +sealed trait PinConnected extends Pin + +case class PinString(p: String) extends PinConnected { + override def toString(): String = p +} + +case class PinInt(p: Int) extends PinConnected { + override def toString(): String = s"$p" +} + +object Pin { + def apply(p: String): PinConnected = string2PinConnected(p) + + implicit def string2PinConnected(p: String): PinConnected = PinString(p) + implicit def int2PinConnected(p: Int): PinConnected = PinInt(p) +} diff --git a/src/main/scala/ee/hrzn/chryse/platform/resource/SPIFlash.scala b/src/main/scala/ee/hrzn/chryse/platform/resource/SPIFlash.scala index f56a19c..c79b408 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/resource/SPIFlash.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/resource/SPIFlash.scala @@ -22,6 +22,16 @@ class SPIFlash extends ResourceBase { hold.setName(s"${name}_hold") } + def withAttributes(attribs: (String, Param)*): this.type = { + cs.withAttributes(attribs: _*) + clock.withAttributes(attribs: _*) + copi.withAttributes(attribs: _*) + cipo.withAttributes(attribs: _*) + wp.withAttributes(attribs: _*) + hold.withAttributes(attribs: _*) + this + } + def setDefaultAttributes(defaultAttributes: Map[String, Param]): Unit = { cs.setDefaultAttributes(defaultAttributes) clock.setDefaultAttributes(defaultAttributes)