diff --git a/src/main/scala/ee/hrzn/chryse/platform/ecp5/IOType.scala b/src/main/scala/ee/hrzn/chryse/platform/ecp5/IOType.scala index 89e9e8d..cade667 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ecp5/IOType.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ecp5/IOType.scala @@ -1,5 +1,7 @@ package ee.hrzn.chryse.platform.ecp5 +import chisel3.experimental.StringParam + object IOType { - val LVCMOS33 = "LVCMOS33" + val LVCMOS33 = "IO_TYPE" -> StringParam("LVCMOS33") } diff --git a/src/main/scala/ee/hrzn/chryse/platform/ecp5/PullMode.scala b/src/main/scala/ee/hrzn/chryse/platform/ecp5/PullMode.scala index 602e5ec..0f8617f 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ecp5/PullMode.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ecp5/PullMode.scala @@ -1,7 +1,9 @@ package ee.hrzn.chryse.platform.ecp5 +import chisel3.experimental.StringParam + object PullMode { - val UP = "UP" - val DOWN = "DOWN" - val NONE = "NONE" + val UP = "PULLMODE" -> StringParam("UP") + val DOWN = "PULLMODE" -> StringParam("DOWN") + val NONE = "PULLMODE" -> StringParam("NONE") } 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 c38a0a6..e299c80 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ecp5/ULX3SPlatform.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ecp5/ULX3SPlatform.scala @@ -9,7 +9,7 @@ import ee.hrzn.chryse.platform.resource.ClockSource import ee.hrzn.chryse.platform.resource.Connector import ee.hrzn.chryse.platform.resource.LED import ee.hrzn.chryse.platform.resource.ResourceData -import ee.hrzn.chryse.platform.resource.SPIFlash +import ee.hrzn.chryse.platform.resource.SPI import ee.hrzn.chryse.platform.resource.UART import ee.hrzn.chryse.tasks.BaseTask @@ -51,12 +51,15 @@ case class ULX3SPlatform(ecp5Variant: ECP5Variant) } class ULX3SPlatformResources extends PlatformBoardResources { - override val defaultAttributes = Map("IO_TYPE" -> IOType.LVCMOS33) + // Pins match board version 3.0.8: + // https://github.com/emard/ulx3s/tree/v3.0.8 + + override val defaultAttributes = Map(IOType.LVCMOS33) val clock = ClockSource(25_000_000).onPin("G2") val program = - LED().onPin("M4").withAttributes("PULLMODE" -> PullMode.UP) + LED().onPin("M4").withAttributes(PullMode.UP) // TODO: also expose RTS, DTR inputs. var uart = UART() @@ -77,27 +80,27 @@ class ULX3SPlatformResources extends PlatformBoardResources { 7 -> "H3", ) - val spiFlash = SPIFlash() + val spiFlash = SPI() .onPins( csN = "R2", clock = USRMCLKPin, copi = "W2", cipo = "V2", wpN = "Y2", holdN = "W1", ) - .withAttributes("PULLMODE" -> PullMode.NONE, "DRIVE" -> 4) + .withAttributes(PullMode.NONE, "DRIVE" -> 4) val buttonPwr = - Button().inverted.onPin("D6").withAttributes("PULLMODE" -> PullMode.UP) + Button().inverted.onPin("D6").withAttributes(PullMode.UP) val buttonFire0 = - Button().onPin("R1").withAttributes("PULLMODE" -> PullMode.DOWN) + Button().onPin("R1").withAttributes(PullMode.DOWN) val buttonFire1 = - Button().onPin("T1").withAttributes("PULLMODE" -> PullMode.DOWN) + Button().onPin("T1").withAttributes(PullMode.DOWN) val buttonLeft = - Button().onPin("U1").withAttributes("PULLMODE" -> PullMode.DOWN) + Button().onPin("U1").withAttributes(PullMode.DOWN) val buttonDown = - Button().onPin("V1").withAttributes("PULLMODE" -> PullMode.DOWN) + Button().onPin("V1").withAttributes(PullMode.DOWN) val buttonUp = - Button().onPin("R18").withAttributes("PULLMODE" -> PullMode.DOWN) + Button().onPin("R18").withAttributes(PullMode.DOWN) val buttonRight = - Button().onPin("H16").withAttributes("PULLMODE" -> PullMode.DOWN) + Button().onPin("H16").withAttributes(PullMode.DOWN) // val oledBl = onPin("J4") // val oledCs = onPin("N2") @@ -107,9 +110,18 @@ class ULX3SPlatformResources extends PlatformBoardResources { // val oledClk = onPin("P4") // DIP switches - // SD card + + // XXX pull-up on CIPO? + // http://elm-chan.org/docs/mmc/mmc_e.html + val sdCard = SPI() + .onPins(csN = "K2", clock = "H2", copi = "J1", cipo = "J3") + // SDRAM - // ADC + + val adc = SPI() + .onPins(csN = "R17", copi = "R16", cipo = "U16", clock = "P17") + .withAttributes(PullMode.UP) + // TRRS // ESP32 // PCB antenna (!!!) 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 57d5964..3e51089 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ice40/ICE40Top.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ice40/ICE40Top.scala @@ -56,12 +56,8 @@ class ICE40Top[Top <: Module]( 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), + (Seq("PIN_TYPE" -> IntParam(i_type | o_type)) ++ + res.attributes.toSeq): _*, ), ).suggestName(s"${res.name.get}_SB_IO") 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 3f208f6..60b4478 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ice40/IOStandard.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ice40/IOStandard.scala @@ -1,6 +1,8 @@ package ee.hrzn.chryse.platform.ice40 +import chisel3.experimental.StringParam + object IOStandard { - val LVCMOS = "SB_LVCMOS" - val LVTTL = "SB_LVTTL" + val LVCMOS = "IO_STANDARD" -> StringParam("SB_LVCMOS") + val LVTTL = "IO_STANDARD" -> StringParam("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 1649b46..029e0fb 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/ice40/IceBreakerPlatform.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/ice40/IceBreakerPlatform.scala @@ -5,7 +5,7 @@ import chisel3.experimental.Param import ee.hrzn.chryse.platform.PlatformBoard import ee.hrzn.chryse.platform.PlatformBoardResources import ee.hrzn.chryse.platform.resource.Connector -import ee.hrzn.chryse.platform.resource.SPIFlash +import ee.hrzn.chryse.platform.resource.SPI import ee.hrzn.chryse.platform.resource.LED import ee.hrzn.chryse.platform.resource.UART import ee.hrzn.chryse.platform.resource.Button @@ -26,7 +26,7 @@ case class IceBreakerPlatform( } class IceBreakerPlatformResources extends PlatformBoardResources { - override val defaultAttributes = Map("IO_STANDARD" -> IOStandard.LVCMOS) + override val defaultAttributes = Map(IOStandard.LVCMOS) val clock = ClockSource(12_000_000).onPin(35) @@ -35,13 +35,13 @@ class IceBreakerPlatformResources extends PlatformBoardResources { val uart = UART() .onPins(rx = 6, tx = 9) - .withAttributes("IO_STANDARD" -> IOStandard.LVTTL, "PULLUP" -> 1) + .withAttributes(IOStandard.LVTTL, "PULLUP" -> 1) val ledg = LED().onPin(37) val ledr = LED().onPin(11) var spiFlash = - SPIFlash() + SPI() .onPins(csN = 16, clock = 15, copi = 14, cipo = 17, wpN = 12, holdN = 13) // Ideally (per Amaranth) a user can refer to these connectors to make their 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 d646c24..cc3c42d 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,8 +6,8 @@ import chisel3.experimental.ExtModule class SB_GB_IO extends ExtModule( Map( - "IO_STANDARD" -> IOStandard.LVCMOS, - "PIN_TYPE" -> (PinType.PIN_INPUT | PinType.PIN_NO_OUTPUT), + IOStandard.LVCMOS, + "PIN_TYPE" -> (PinType.PIN_INPUT | PinType.PIN_NO_OUTPUT), ), ) { val PACKAGE_PIN = IO(Input(Clock())) 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 9d56386..5480177 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 @@ -2,21 +2,16 @@ package ee.hrzn.chryse.platform.ice40 import chisel3._ import chisel3.experimental.ExtModule +import chisel3.experimental.IntParam +import chisel3.experimental.Param class SB_IO( - pinType: Int, - ioStandard: String = IOStandard.LVCMOS, - pullup: Boolean = false, -) extends ExtModule( - Map( - "IO_STANDARD" -> ioStandard, - "PIN_TYPE" -> pinType, - "PULLUP" -> (if (pullup) 1 else 0), - ), - ) { - + attrs: (String, Param)*, +) extends ExtModule(attrs.to(Map)) { // XXX: hyperspecific to ICE40Top's SB_IO generation and doesn't support // tristates. + private val pinType = + attrs.find(_._1 == "PIN_TYPE").get._2.asInstanceOf[IntParam].value.toInt private val isOutput = (pinType & PinType.PIN_OUTPUT_TRISTATE) != 0 private def genPin(): Bool = { diff --git a/src/main/scala/ee/hrzn/chryse/platform/resource/SPIFlash.scala b/src/main/scala/ee/hrzn/chryse/platform/resource/SPI.scala similarity index 76% rename from src/main/scala/ee/hrzn/chryse/platform/resource/SPIFlash.scala rename to src/main/scala/ee/hrzn/chryse/platform/resource/SPI.scala index c79b408..ad77e69 100644 --- a/src/main/scala/ee/hrzn/chryse/platform/resource/SPIFlash.scala +++ b/src/main/scala/ee/hrzn/chryse/platform/resource/SPI.scala @@ -3,15 +3,15 @@ package ee.hrzn.chryse.platform.resource import chisel3._ import chisel3.experimental.Param -class SPIFlash extends ResourceBase { +class SPI extends ResourceBase { // TODO: DSPI, QSPI val cs = ResourceData(Output(Bool()), invert = true) val clock = ResourceData(Output(Clock())) val copi = ResourceData(Output(Bool())) val cipo = ResourceData(Input(Bool())) - val wp = ResourceData(Output(Bool()), invert = true) - val hold = ResourceData(Output(Bool()), invert = true) + val wp = ResourceData(Output(Bool()), invert = true) // permitted to be unset + val hold = ResourceData(Output(Bool()), invert = true) // permitted to be unset def setName(name: String): Unit = { cs.setName(s"${name}_cs") @@ -46,22 +46,24 @@ class SPIFlash extends ResourceBase { clock: Pin, copi: Pin, cipo: Pin, - wpN: Pin, - holdN: Pin, + wpN: Pin = null, + holdN: Pin = null, ): this.type = { this.cs.onPin(csN) this.clock.onPin(clock) this.copi.onPin(copi) this.cipo.onPin(cipo) - this.wp.onPin(wpN) - this.hold.onPin(holdN) + if (wpN != null) + this.wp.onPin(wpN) + if (holdN != null) + this.hold.onPin(holdN) this } def data: Seq[ResourceData[_ <: Data]] = - Seq(cs, clock, copi, cipo, wp, hold) + Seq(cs, clock, copi, cipo) ++ Seq(wp, hold).filter(_.pinId.isDefined) } -object SPIFlash { - def apply() = new SPIFlash +object SPI { + def apply() = new SPI } diff --git a/src/test/scala/ee/hrzn/chryse/platform/SimPlatform.scala b/src/test/scala/ee/hrzn/chryse/platform/SimPlatform.scala index 4ef5a54..695c44d 100644 --- a/src/test/scala/ee/hrzn/chryse/platform/SimPlatform.scala +++ b/src/test/scala/ee/hrzn/chryse/platform/SimPlatform.scala @@ -59,7 +59,7 @@ class SimPlatformResources extends PlatformBoardResources { ) val spiFlash = resource - .SPIFlash() + .SPI() .onPins( csN = "R2", clock = USRMCLKPin, copi = "W2", cipo = "V2", wpN = "Y2", holdN = "W1", diff --git a/src/test/scala/ee/hrzn/chryse/platform/ecp5/LPFSpec.scala b/src/test/scala/ee/hrzn/chryse/platform/ecp5/LPFSpec.scala index b132bb1..468529e 100644 --- a/src/test/scala/ee/hrzn/chryse/platform/ecp5/LPFSpec.scala +++ b/src/test/scala/ee/hrzn/chryse/platform/ecp5/LPFSpec.scala @@ -14,8 +14,8 @@ class LPFSpec extends AnyFlatSpec with Matchers { LPF( Map( "abc" -> (PinString("J1"), Map( - "IO_TYPE" -> IOType.LVCMOS33, - "DRIVE" -> 4, + IOType.LVCMOS33, + "DRIVE" -> 4, )), "xy" -> (PinString("A9"), Map()), ),