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

Commit

Permalink
SB_IO use correct for simple IO (no tristate).
Browse files Browse the repository at this point in the history
  • Loading branch information
kivikakk committed May 25, 2024
1 parent efe997d commit 083100b
Show file tree
Hide file tree
Showing 14 changed files with 162 additions and 66 deletions.
19 changes: 17 additions & 2 deletions src/main/scala/ee/hrzn/chryse/chisel/DirectionOf.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,25 @@ package ee.hrzn.chryse.chisel

import chisel3._

import scala.language.implicitConversions

private[chryse] object DirectionOf {
def apply[T <: Data](data: T): SpecifiedDirection =
def apply[T <: Data](data: T): Direction =
classOf[Data]
.getMethod("specifiedDirection") // private[chisel3]
.invoke(data)
.asInstanceOf[SpecifiedDirection]
.asInstanceOf[SpecifiedDirection] match {
case SpecifiedDirection.Input => Input
case SpecifiedDirection.Output => Output
case dir => throw new Exception(s"unhandled direction $dir")
}

sealed trait Direction
final case object Input extends Direction
final case object Output extends Direction

implicit val dir2SpecifiedDirection: Direction => SpecifiedDirection = {
case Input => SpecifiedDirection.Input
case Output => SpecifiedDirection.Output
}
}
38 changes: 20 additions & 18 deletions src/main/scala/ee/hrzn/chryse/platform/ChryseTop.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import chisel3.experimental.noPrefix
import ee.hrzn.chryse.chisel.DirectionOf

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

trait ChryseTop extends RawModule {
Expand All @@ -20,7 +21,20 @@ trait ChryseTop extends RawModule {
protected def platformConnect(
name: String,
res: resource.ResourceData[_ <: Data],
): Option[Data] = None
): Option[(Data, Data)] = None

protected def platformPort(
res: resource.ResourceData[_ <: Data],
topIo: Data,
portIo: Data,
): Unit = {
DirectionOf(topIo) match {
case DirectionOf.Input =>
topIo := portIo
case DirectionOf.Output =>
portIo := topIo
}
}

protected def connectResources(
platform: PlatformBoard[_ <: PlatformBoardResources],
Expand All @@ -47,27 +61,15 @@ trait ChryseTop extends RawModule {
clock.get := noPrefix(IO(Input(Clock())).suggestName(name))

case _ =>
val topIo: Option[Data] = platformConnect(name, res) match {
case Some(t) =>
platformConnect(name, res) match {
case Some((topIo, portIo)) =>
connected += name -> res.pinId.get
Some(t)
platformPort(res, topIo, portIo)
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")
val (topIo, portIo) = res.makeIoConnection()
platformPort(res, topIo, portIo)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ abstract class PlatformBoardResources {
f.setAccessible(true)
f.get(this) match {
case res: ResourceBase =>
res.setDefaultAttributes(defaultAttributes)
res.setName(f.getName())
case _ =>
}
Expand Down
53 changes: 47 additions & 6 deletions src/main/scala/ee/hrzn/chryse/platform/ice40/ICE40Top.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package ee.hrzn.chryse.platform.ice40

import chisel3._
import chisel3.experimental.IntParam
import chisel3.experimental.StringParam
import chisel3.experimental.noPrefix
import chisel3.util._
import chisel3.util.experimental.forceName
import ee.hrzn.chryse.chisel.DirectionOf
import ee.hrzn.chryse.platform.ChryseTop
import ee.hrzn.chryse.platform.PlatformBoard
import ee.hrzn.chryse.platform.PlatformBoardResources
Expand All @@ -19,21 +22,59 @@ class ICE40Top[Top <: Module](
override protected def platformConnect(
name: String,
res: resource.ResourceData[_ <: Data],
): Option[Data] = {
): Option[(Data, Data)] = {
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")
val topIo = Wire(res.makeIo())
// XXX: do we need to bother hooking up res.topIoInst/portIoInst?

val topIo = Wire(res.makeIo()).suggestName("ubtn_top")
ubtn_reset.get := topIo
return Some(topIo)
}

val portIo = IO(res.makeIo()).suggestName("ubtn")
return Some((topIo, portIo))
}
None
}

// TODO (iCE40): actually create IO buffers.
override protected def platformPort(
res: resource.ResourceData[_ <: Data],
topIo: Data,
portIo: Data,
) = {
// when we do DDR we'll need to use PIN_INPUT_DDR.
val i_type = PinType.PIN_INPUT

// as above, PIN_OUTPUT_{REGISTERED,DDR}_ENABLE_REGISTERED
val o_type = DirectionOf(portIo) match {
case DirectionOf.Input => PinType.PIN_NO_OUTPUT
case DirectionOf.Output => PinType.PIN_OUTPUT_TRISTATE
}

val buffer = Module(
new SB_IO(
i_type | o_type,
res.attributes("IO_STANDARD").asInstanceOf[StringParam].value,
res.attributes
.get("PULLUP")
.map(_.asInstanceOf[IntParam].value == 1)
.getOrElse(false),
),
).suggestName(s"${res.name.get}_SB_IO")

DirectionOf(portIo) match {
case DirectionOf.Input =>
buffer.PACKAGE_PIN := portIo
topIo := buffer.D_IN_0
buffer.OUTPUT_ENABLE := DontCare
buffer.D_OUT_0 := DontCare
case DirectionOf.Output =>
portIo := buffer.PACKAGE_PIN
buffer.OUTPUT_ENABLE := true.B
buffer.D_OUT_0 := topIo
}
}

private val clki = Wire(Clock())

Expand Down
3 changes: 2 additions & 1 deletion src/main/scala/ee/hrzn/chryse/platform/ice40/PinType.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package ee.hrzn.chryse.platform.ice40

// See SiliconBlue ICE™ Technology Library.
object PinType {
val PIN_INPUT = 0x1
val PIN_INPUT = 0x1
val PIN_INPUT_DDR = 0x0 // REGISTERED

val PIN_NO_OUTPUT = 0x0
val PIN_OUTPUT = 0x18
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/ee/hrzn/chryse/platform/ice40/SB_GB_IO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package ee.hrzn.chryse.platform.ice40
import chisel3._
import chisel3.experimental.ExtModule

class SB_GB_IO(pinType: Int = (PinType.PIN_INPUT | PinType.PIN_NO_OUTPUT))
class SB_GB_IO
extends ExtModule(
Map(
"IO_STANDARD" -> IOStandard.LVCMOS,
"PIN_TYPE" -> pinType,
"PIN_TYPE" -> (PinType.PIN_INPUT | PinType.PIN_NO_OUTPUT),
),
) {
val PACKAGE_PIN = IO(Input(Clock()))
Expand Down
22 changes: 12 additions & 10 deletions src/main/scala/ee/hrzn/chryse/platform/ice40/SB_IO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,19 @@ class SB_IO(
),
) {

private def genPin(): Data = {
if (pinType == PinType.PIN_INPUT)
Input(Bool())
else if (pinType == PinType.PIN_OUTPUT)
// XXX: hyperspecific to ICE40Top's SB_IO generation and doesn't support
// tristates.
private val isOutput = (pinType & PinType.PIN_OUTPUT_TRISTATE) != 0

private def genPin(): Bool = {
if (isOutput)
Output(Bool())
else if (pinType == (PinType.PIN_INPUT | PinType.PIN_OUTPUT_TRISTATE))
Analog(1.W)
else
throw new IllegalArgumentException(s"unhandled pinType: $pinType")

Input(Bool())
}
val PACKAGE_PIN = IO(genPin())
val GLOBAL_BUFFER_OUTPUT = IO(genPin())

val PACKAGE_PIN = IO(genPin())
val OUTPUT_ENABLE = IO(Input(Bool()))
val D_IN_0 = IO(Output(Bool()))
val D_OUT_0 = IO(Input(Bool()))
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ee.hrzn.chryse.platform.resource

import chisel3._
import chisel3.experimental.Param

class Connector[Ix, E <: ResourceSinglePin](
gen: => E,
Expand All @@ -17,6 +18,9 @@ class Connector[Ix, E <: ResourceSinglePin](
def setName(name: String): Unit =
mappings.foreach { case (i, e) => e.setName(s"$name$i") }

def setDefaultAttributes(defaultAttributes: Map[String, Param]): Unit =
mappings.foreach(_._2.setDefaultAttributes(defaultAttributes))

def data: Seq[ResourceData[_ <: Data]] =
mappings.flatMap(_._2.data).toSeq
}
Expand Down
5 changes: 5 additions & 0 deletions src/main/scala/ee/hrzn/chryse/platform/resource/InOut.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ class InOut extends ResourceBase with ResourceSinglePin {
this
}

def setDefaultAttributes(defaultAttributes: Map[String, Param]): Unit = {
i.setDefaultAttributes(defaultAttributes)
o.setDefaultAttributes(defaultAttributes)
}

def data: Seq[ResourceData[_ <: Data]] = Seq(i, o)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package ee.hrzn.chryse.platform.resource

import chisel3._
import chisel3.experimental.Param
import ee.hrzn.chryse.platform.PlatformBoardResources

import scala.collection.mutable.ArrayBuffer

trait ResourceBase {
def setName(name: String): Unit
def setDefaultAttributes(defaultAttributes: Map[String, Param]): Unit
def data: Seq[ResourceData[_ <: Data]]
}

Expand Down
32 changes: 20 additions & 12 deletions src/main/scala/ee/hrzn/chryse/platform/resource/ResourceData.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ 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]()
final var attributes = Map[String, Param]()

// Should return Chisel datatype with Input/Output attached.
def makeIo(): HW = gen

final private[chryse] var ioInst: Option[HW] = None
final private[chryse] var topIoInst: Option[HW] = None
final private[chryse] var ioInst: Option[HW] = None
final private[chryse] var topIoInst: Option[HW] = None
final private[chryse] var portIoInst: Option[HW] = None

/* Instantiate an IO in the module at the point of connecting to this
* resource. These will be connected to in turn by the platform toplevel
Expand All @@ -40,24 +41,27 @@ abstract class ResourceData[HW <: Data](gen: => HW, invert: Boolean = false)
}
}

final def makeIoConnection(): HW = {
final def makeIoConnection(): (HW, HW) = {
if (topIoInst.isDefined)
throw new IllegalStateException("topIoInst already defined")
// val topIo = IO(makeIo()).suggestName(name.get)
val topIo = Wire(makeIo()) // .suggestName(name.get)
if (portIoInst.isDefined)
throw new IllegalStateException("portIoInst already defined")
val topIo = Wire(makeIo()).suggestName(s"${name.get}_top")
topIoInst = Some(topIo)
connectIo(ioInst.get, topIo)
topIo

val portIo = IO(makeIo()).suggestName(name.get)
portIoInst = Some(portIo)

(topIo, portIo)
}

protected def connectIo(user: HW, top: HW): Unit = {
DirectionOf(top) match {
case SpecifiedDirection.Input =>
case DirectionOf.Input =>
user := (if (!_invert) top else ~top.asInstanceOf[Bits])
case SpecifiedDirection.Output =>
case DirectionOf.Output =>
top := (if (!_invert) user else ~user.asInstanceOf[Bits])
case dir =>
throw new Exception(s"unhandled direction: $dir")
}
}

Expand All @@ -69,10 +73,14 @@ abstract class ResourceData[HW <: Data](gen: => HW, invert: Boolean = false)
}

def withAttributes(attribs: (String, Param)*): this.type = {
_attribs = attribs.to(Map)
attributes = attribs.to(Map)
this
}

def setDefaultAttributes(defaultAttributes: Map[String, Param]): Unit =
for { (name, value) <- defaultAttributes if !attributes.isDefinedAt(name) }
attributes += name -> value

def data: Seq[ResourceData[_ <: Data]] = Seq(this)
}

Expand Down
10 changes: 10 additions & 0 deletions src/main/scala/ee/hrzn/chryse/platform/resource/SPIFlash.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ee.hrzn.chryse.platform.resource

import chisel3._
import chisel3.experimental.Param

class SPIFlash extends ResourceBase {
// TODO: DSPI, QSPI
Expand All @@ -21,6 +22,15 @@ class SPIFlash extends ResourceBase {
hold.setName(s"${name}_hold")
}

def setDefaultAttributes(defaultAttributes: Map[String, Param]): Unit = {
cs.setDefaultAttributes(defaultAttributes)
clock.setDefaultAttributes(defaultAttributes)
copi.setDefaultAttributes(defaultAttributes)
cipo.setDefaultAttributes(defaultAttributes)
wp.setDefaultAttributes(defaultAttributes)
hold.setDefaultAttributes(defaultAttributes)
}

def onPins(
csN: Pin,
clock: Pin,
Expand Down
5 changes: 5 additions & 0 deletions src/main/scala/ee/hrzn/chryse/platform/resource/UART.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ class UART extends ResourceBase {
this
}

def setDefaultAttributes(defaultAttributes: Map[String, Param]): Unit = {
rx.setDefaultAttributes(defaultAttributes)
tx.setDefaultAttributes(defaultAttributes)
}

def withAttributes(attribs: (String, Param)*): this.type = {
rx.withAttributes(attribs: _*)
tx.withAttributes(attribs: _*)
Expand Down
Loading

0 comments on commit 083100b

Please sign in to comment.