diff --git a/src/main/scala/ee/hrzn/chryse/platform/ChryseTop.scala b/src/main/scala/ee/hrzn/chryse/platform/ChryseTop.scala index a61517d..46b370d 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ChryseTop.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ChryseTop.scala @@ -2,6 +2,7 @@ package ee.hrzn.chryse.platform import chisel3._ import chisel3.experimental.noPrefix +import ee.hrzn.chryse.chisel.DirectionOf import scala.collection.mutable import scala.language.implicitConversions @@ -16,6 +17,11 @@ trait ChryseTop extends RawModule { ConnectedResource(pin, None) } + protected def platformConnect( + name: String, + res: resource.ResourceData[_ <: Data], + ): Option[Data] = None + protected def connectResources( platform: PlatformBoard[_ <: PlatformBoardResources], clock: Option[Clock], @@ -41,20 +47,32 @@ trait ChryseTop extends RawModule { clock.get := noPrefix(IO(Input(Clock())).suggestName(name)) case _ => - if (platformConnect(name, res)) { - connected += name -> res.pinId.get - } else if (res.ioInst.isDefined) { - res.makeIoConnection() - connected += name -> res.pinId.get + val topIo: Option[Data] = platformConnect(name, res) match { + case Some(t) => + connected += name -> res.pinId.get + Some(t) + case None => + if (res.ioInst.isDefined) { + connected += name -> res.pinId.get + Some(res.makeIoConnection()) + } else None + } + topIo match { + case None => + case Some(t) => + val port = IO(res.makeIo()).suggestName(name) + DirectionOf(port) match { + case SpecifiedDirection.Input => + t := port + case SpecifiedDirection.Output => + port := t + case dir => + throw new Exception(s"unhandled direction: $dir") + } } } } connected.to(Map) } - - protected def platformConnect( - name: String, - res: resource.ResourceData[_ <: Data], - ): Boolean = false } diff --git a/src/main/scala/ee/hrzn/chryse/platform/PlatformBoardResources.scala b/src/main/scala/ee/hrzn/chryse/platform/PlatformBoardResources.scala index 8930f90..de7a6fd 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/PlatformBoardResources.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/PlatformBoardResources.scala @@ -1,12 +1,15 @@ package ee.hrzn.chryse.platform import chisel3._ +import chisel3.experimental.Param import ee.hrzn.chryse.platform.resource.ResourceBase import ee.hrzn.chryse.platform.resource.ResourceData import scala.collection.mutable.ArrayBuffer abstract class PlatformBoardResources { + val defaultAttributes = Map[String, Param]() + private[chryse] def setNames() = for { f <- this.getClass().getDeclaredFields() } { f.setAccessible(true) 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 cc03b96..30224bf 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ice40/ICE40Top.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ice40/ICE40Top.scala @@ -16,9 +16,24 @@ class ICE40Top[Top <: Module]( genTop: => Top, ) extends RawModule with ChryseTop { - var lastPCF: Option[PCF] = None + override protected def platformConnect( + name: String, + res: resource.ResourceData[_ <: Data], + ): Option[Data] = { + if (name == "ubtn" && ubtn_reset.isDefined) { + if (res.ioInst.isDefined) + throw new Exception("ubtnReset requested but ubtn used in design") - // TODO (iCE40): SB_GBs between a lot more things. + // ubtn_reset.get := IO(res.makeIo()).suggestName("ubtn") + val topIo = Wire(res.makeIo()) + ubtn_reset.get := topIo + return Some(topIo) + } + + None + } + + // TODO (iCE40): actually create IO buffers. private val clki = Wire(Clock()) @@ -58,22 +73,7 @@ class ICE40Top[Top <: Module]( private val connectedResources = connectResources(platform, Some(clki)) - override protected def platformConnect( - name: String, - res: resource.ResourceData[_ <: Data], - ): Boolean = { - if (name == "ubtn" && ubtn_reset.isDefined) { - if (res.ioInst.isDefined) - throw new Exception("ubtnReset requested but ubtn used in design") - - ubtn_reset.get := IO(res.makeIo()).suggestName("ubtn") - return true - } - - false - } - - lastPCF = Some( + val lastPCF = Some( PCF( connectedResources .map { case (name, cr) => (name, cr.pin) } diff --git a/src/main/scala/ee/hrzn/chryse/platform/ice40/IOStandard.scala b/src/main/scala/ee/hrzn/chryse/platform/ice40/IOStandard.scala index 2be88ea..3f208f6 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ice40/IOStandard.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ice40/IOStandard.scala @@ -1,5 +1,6 @@ package ee.hrzn.chryse.platform.ice40 object IOStandard { - val LV_CMOS = "SB_LVCMOS" + val LVCMOS = "SB_LVCMOS" + val LVTTL = "SB_LVTTL" } 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 71643ae..24e1bec 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ice40/IceBreakerPlatform.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ice40/IceBreakerPlatform.scala @@ -1,6 +1,7 @@ package ee.hrzn.chryse.platform.ice40 import chisel3._ +import chisel3.experimental.Param import ee.hrzn.chryse.platform.PlatformBoard import ee.hrzn.chryse.platform.PlatformBoardResources import ee.hrzn.chryse.platform.resource @@ -24,12 +25,16 @@ final case class IceBreakerPlatform(ubtnReset: Boolean = false) } class IceBreakerPlatformResources extends PlatformBoardResources { - // TODO: IO_STANDARD=SB_LVCMOS needs to be set on most SB_IOs. + override val defaultAttributes = Map("IO_STANDARD" -> IOStandard.LVCMOS) + val clock = resource.ClockSource(12_000_000).onPin(35) val ubtn = resource.Button().inverted.onPin(10) - val uart = resource.UART().onPins(rx = 6, tx = 9) + val uart = resource + .UART() + .onPins(rx = 6, tx = 9) + .withAttributes("IO_STANDARD" -> IOStandard.LVTTL, "PULLUP" -> 1) val ledg = resource.LED().inverted.onPin(37) val ledr = resource.LED().inverted.onPin(11) diff --git a/src/main/scala/ee/hrzn/chryse/platform/ice40/SB_GB_IO.scala b/src/main/scala/ee/hrzn/chryse/platform/ice40/SB_GB_IO.scala index 2cb0797..e103f14 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ice40/SB_GB_IO.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ice40/SB_GB_IO.scala @@ -6,7 +6,7 @@ import chisel3.experimental.ExtModule class SB_GB_IO(pinType: Int = (PinType.PIN_INPUT | PinType.PIN_NO_OUTPUT)) extends ExtModule( Map( - "IO_STANDARD" -> IOStandard.LV_CMOS, + "IO_STANDARD" -> IOStandard.LVCMOS, "PIN_TYPE" -> pinType, ), ) { diff --git a/src/main/scala/ee/hrzn/chryse/platform/ice40/SB_IO.scala b/src/main/scala/ee/hrzn/chryse/platform/ice40/SB_IO.scala index 60743f4..92dd249 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ice40/SB_IO.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ice40/SB_IO.scala @@ -6,7 +6,7 @@ import chisel3.experimental.ExtModule class SB_IO( pinType: Int, - ioStandard: String = IOStandard.LV_CMOS, + ioStandard: String = IOStandard.LVCMOS, pullup: Boolean = false, ) extends ExtModule( Map( diff --git a/src/main/scala/ee/hrzn/chryse/platform/resource/InOut.scala b/src/main/scala/ee/hrzn/chryse/platform/resource/InOut.scala index 96712aa..df72976 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/resource/InOut.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/resource/InOut.scala @@ -1,6 +1,7 @@ package ee.hrzn.chryse.platform.resource import chisel3._ +import chisel3.experimental.Param // TODO: it's an error to use both "i" and "o" (tristate is a different kettle // of fish entirely) — this'll currently throw an obscure Chisel error (since @@ -20,6 +21,12 @@ class InOut extends ResourceBase with ResourceSinglePin { this } + def withAttributes(attribs: (String, Param)*): this.type = { + i.withAttributes(attribs: _*) + o.withAttributes(attribs: _*) + this + } + def data: Seq[ResourceData[_ <: Data]] = Seq(i, o) } diff --git a/src/main/scala/ee/hrzn/chryse/platform/resource/ResourceData.scala b/src/main/scala/ee/hrzn/chryse/platform/resource/ResourceData.scala index e06f8e8..b9581d4 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/resource/ResourceData.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/resource/ResourceData.scala @@ -1,6 +1,7 @@ package ee.hrzn.chryse.platform.resource import chisel3._ +import chisel3.experimental.Param import chisel3.experimental.dataview._ import ee.hrzn.chryse.chisel.DirectionOf @@ -18,6 +19,7 @@ abstract class ResourceData[HW <: Data](gen: => HW, invert: Boolean = false) final private[chryse] var pinId: Option[Pin] = None final var name: Option[String] = None final protected var _invert = invert + final protected var _attribs = Map[String, Param]() // Should return Chisel datatype with Input/Output attached. def makeIo(): HW = gen @@ -38,12 +40,14 @@ abstract class ResourceData[HW <: Data](gen: => HW, invert: Boolean = false) } } - final def makeIoConnection(): Unit = { + final def makeIoConnection(): HW = { if (topIoInst.isDefined) throw new IllegalStateException("topIoInst already defined") - val topIo = IO(makeIo()).suggestName(name.get) + // val topIo = IO(makeIo()).suggestName(name.get) + val topIo = Wire(makeIo()) // .suggestName(name.get) topIoInst = Some(topIo) connectIo(ioInst.get, topIo) + topIo } protected def connectIo(user: HW, top: HW): Unit = { @@ -64,6 +68,11 @@ abstract class ResourceData[HW <: Data](gen: => HW, invert: Boolean = false) this } + def withAttributes(attribs: (String, Param)*): this.type = { + _attribs = attribs.to(Map) + this + } + def data: Seq[ResourceData[_ <: Data]] = Seq(this) } diff --git a/src/main/scala/ee/hrzn/chryse/platform/resource/ResourceSinglePin.scala b/src/main/scala/ee/hrzn/chryse/platform/resource/ResourceSinglePin.scala index 31c84c3..77d0858 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/resource/ResourceSinglePin.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/resource/ResourceSinglePin.scala @@ -1,5 +1,8 @@ package ee.hrzn.chryse.platform.resource +import chisel3.experimental.Param + trait ResourceSinglePin extends ResourceBase { def onPin(id: Pin): this.type + def withAttributes(attribs: (String, Param)*): this.type } 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 d4b3131..8e850c0 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/resource/SPIFlash.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/resource/SPIFlash.scala @@ -3,6 +3,8 @@ package ee.hrzn.chryse.platform.resource import chisel3._ class SPIFlash extends ResourceBase { + // TODO: DSPI, QSPI + val cs = ResourceData(Output(Bool()), invert = true) val clock = ResourceData(Output(Clock())) val copi = ResourceData(Output(Bool())) diff --git a/src/main/scala/ee/hrzn/chryse/platform/resource/UART.scala b/src/main/scala/ee/hrzn/chryse/platform/resource/UART.scala index 383bbf4..a888623 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/resource/UART.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/resource/UART.scala @@ -1,10 +1,9 @@ package ee.hrzn.chryse.platform.resource import chisel3._ +import chisel3.experimental.Param class UART extends ResourceBase { - // TODO (iCE40): lower IO_STANDARD=SB_LVTTL and PULLUP=1. - // TODO: these will differ per-platform so need to come in from outside. val rx = ResourceData(Input(Bool())) val tx = ResourceData(Output(Bool())) @@ -19,6 +18,12 @@ class UART extends ResourceBase { this } + def withAttributes(attribs: (String, Param)*): this.type = { + rx.withAttributes(attribs: _*) + tx.withAttributes(attribs: _*) + this + } + def data: Seq[ResourceData[_ <: Data]] = Seq(rx, tx) }