nmigen
nmigen copied to clipboard
Support silkscreen references (and other information) in platform definitions
The new Atlys platform definition in #15 does the following;
Resource("user_led", 0, Pins("U18", dir="o"), Attrs(IOSTANDARD="LVCMOS33")), # LD0
Resource("user_led", 1, Pins("M14", dir="o"), Attrs(IOSTANDARD="LVCMOS33")), # LD1
Resource("user_led", 2, Pins("N14", dir="o"), Attrs(IOSTANDARD="LVCMOS33")), # LD2
Resource("user_led", 3, Pins("L14", dir="o"), Attrs(IOSTANDARD="LVCMOS33")), # LD3
Resource("user_led", 4, Pins("M13", dir="o"), Attrs(IOSTANDARD="LVCMOS33")), # LD4
Resource("user_led", 5, Pins("D4", dir="o"), Attrs(IOSTANDARD="LVCMOS33")), # LD5
Resource("user_led", 6, Pins("P16", dir="o"), Attrs(IOSTANDARD="LVCMOS33")), # LD6
Resource("user_led", 7, Pins("N12", dir="o"), Attrs(IOSTANDARD=bank2_iostandard)), # LD7
Resource("user_btn", 0, PinsN("T15", dir="i"), Attrs(IOSTANDARD=bank2_iostandard)), # RESET
Resource("reset" , 0, PinsN("T15", dir="i"), Attrs(IOSTANDARD=bank2_iostandard)), # RESET
Resource("user_btn", 1, Pins("N4", dir="i"), Attrs(IOSTANDARD="LVCMOS18")), # BTNU
Resource("user_btn", 2, Pins("P4", dir="i"), Attrs(IOSTANDARD="LVCMOS18")), # BTNL
Resource("user_btn", 3, Pins("P3", dir="i"), Attrs(IOSTANDARD="LVCMOS18")), # BTND
Resource("user_btn", 4, Pins("F6", dir="i"), Attrs(IOSTANDARD="LVCMOS18")), # BTNR
Resource("user_btn", 5, Pins("F5", dir="i"), Attrs(IOSTANDARD="LVCMOS18")), # BTNC
Resource("user_sw" , 0, Pins("A10", dir="i"), Attrs(IOSTANDARD="LVCMOS33")), # SW0
Resource("user_sw" , 1, Pins("D14", dir="i"), Attrs(IOSTANDARD="LVCMOS33")), # SW1
Resource("user_sw" , 2, Pins("C14", dir="i"), Attrs(IOSTANDARD="LVCMOS33")), # SW2
Resource("user_sw" , 3, Pins("P15", dir="i"), Attrs(IOSTANDARD="LVCMOS33")), # SW3
Resource("user_sw" , 4, Pins("P12", dir="i"), Attrs(IOSTANDARD=bank2_iostandard)), # SW4
Resource("user_sw" , 5, Pins("R5", dir="i"), Attrs(IOSTANDARD=bank2_iostandard)), # SW5
Resource("user_sw" , 6, Pins("T5", dir="i"), Attrs(IOSTANDARD=bank2_iostandard)), # SW6
Resource("user_sw" , 7, Pins("E4", dir="i"), Attrs(IOSTANDARD="LVCMOS18")), # SW7
UARTResource(0, rx="A16", tx="B16", attrs=Attrs(IOSTANDARD="LVCMOS33")), # J17/UART
It would be really useful to expose the information in the comments to a user.
I think this makes the most sense for LEDs and switches, but can work for connectors too.
With this information you could even then write something which lets you specify silk screen reference values in a console and have them mapped to the right switch / led.
For the complicated boards like the Digilent Atlys we went even further and provided the following;
_hdmi_infos = {
"HDMI_IN0_MNEMONIC": "J1",
"HDMI_IN0_DESCRIPTION" : (
" Type A connector, marked as J1, on side with USB connectors.\\r\\n"
" To use J1, make sure:\\r\\n"
" * JP4 has a jumper (it connects / disconnects 5V to HDMI pin 18).\\r\\n"
" * JP2 (marked only as SDA/SCL - not to be confused with JP6 and JP6)\\r\\n"
" has *two* jumpers (horizontally).\\r\\n"
" * JP5 has a jumper (it enables the HDMI input buffer).\\r\\n"
),
"HDMI_IN1_MNEMONIC": "J3",
"HDMI_IN1_DESCRIPTION" : (
" Type A connector, marked as J3, between audio connectors and\\r\\n"
" Ethernet RJ45 connector.\\r\\n"
" To use J3, make sure:\\r\\n"
" * JP8 has a jumper (it connects / disconnects 5V to HDMI pin 18)\\r\\n"
" * JP6 and JP7 do *not* have any jumpers (it connect J3's and J2's\\r\\n"
" EDID lines together).\\r\\n"
),
"HDMI_OUT0_MNEMONIC": "J2",
"HDMI_OUT0_DESCRIPTION" : (
" Type A connector, marked as J2, next to the power connector.\\r\\n"
" To use J2, make sure:\\r\\n"
" * JP8 has a jumper (it connects / disconnects 5V to HDMI pin 18)\\r\\n"
" * JP6 and JP7 do *not* have any jumpers (it connect J3's and J2's\\r\\n"
" EDID lines together).\\r\\n"
),
"HDMI_OUT1_MNEMONIC": "JB",
"HDMI_OUT1_DESCRIPTION" : (
" Micro-D connector, marked as JB, on the same side as switches\\r\\n"
" + LEDs but on the underside of the board below MOD connector.\\r\\n"
" Works as either output or input because it isn't buffered.\\r\\n"
" Also often referred to as 'JA'.\\r\\n"
)
}
I feel like this information should be in some type of docstring associated with connectors / resources?
How would it be presented to the user?
I would suggest that the;
-
Resource
object have an optional attribute calledsilkscreen_reference
which takes an arbitrary string. -
Resource
objects have an optional attribute calledlocation_information
which takes an arbitrary string which can be used to describe to a human were to find this resource on the development board. -
Resource
objects can be given a__doc__
string which can just have arbitrary human information about the resource which doesn't fit elsewhere.
Then you could do something like;
leds = {}
while True:
l = platform.get_resource("user_led")
if not l:
break
leds[l.silkscreen_reference or 'led{}'.format(len(leds))] = l
self.gpio = GPIO(len(leds))
for i, (name, l) in enumerate(sort(leds.items())):
m.d.sync += l.eq(self.gpio.reg[i])
if l.silkscreen_reference:
m.define('USER_LED{}'.format(i), l.silkscreen_reference)
What is m.define
?
Was thinking something like add_constant
class BaseSoC(SoCSDRAM):
def __init__(self, platform, **kwargs):
self.add_constant("SPIFLASH_PAGE_SIZE", platform.spiflash_page_size)
self.add_constant("SPIFLASH_SECTOR_SIZE", platform.spiflash_sector_size)
That doesn't explain what it does.
Provides a define in the C header file. CSRConstant could be another option.
Or you could write out a CSV or other configuration file?
Writing C header files is definitely not something that should be a part of core nMigen.
I agree that the output side probably doesn't make sense in nMigen's core -- was just trying to provide some type of example of how it might end up getting used.
As this information tends to end up in comments in the board / platform file anyway, it seems a good idea to allow a more structured format that other tools can then use / depend on?
I also can't think of a logical way for this information to be provided in an external file / package while still being kept in sync with the board files. Do you have any ideas?
My thinking is kind of like how type hints don't /do/ anything in Python directly but other tools can reuse them. Type hints kind of came out of people putting the information in their numpy / Google style docstrings too...
Open to alternative suggestions / proposals.....
We should definitely have the ability to add refres information to resources. Perhaps Resource(..., Refdes("U3"))
? Or maybe Silk("U3")
.
I am not so sure about the __doc__
strings and how to best handle them.
I like Silk over Refdes (I assume Reference Designator)?
Something like a freeform __doc__
, help
or doc
would be a good thing to have? Python docstrings are kind of a superpower....
Something like a freeform
__doc__
,help
ordoc
would be a good thing to have? Python docstrings are kind of a superpower....
The main problem here is to decide what can they be attached, what is the syntax for that, and how should they be retrieved. It's hard to see this just from hypotheticals, and without a concrete use case.
These example comments in the litex-buildenv Opsis platform definition would be candidates to end up in docstring type stuff in my opinion;
## Opsis I2C Bus
# Connected to both the EEPROM and the FX2.
#
## 24AA02E48 - component U23
# 2 Kbit Electrically Erasable PROM
# Pre-programmed Globally Unique, 48-bit Node Address
# The device is organized as two blocks of 128 x 8-bit memory with a 2-wire serial interface.
## \/ Strongly pulled (2k) to VCC3V3 via R34
#NET "eeprom_scl" LOC = "G6" |IOSTANDARD = I2C; # (/Ethernet/MAC_SCL)
#NET "eeprom_sda" LOC = "C1" |IOSTANDARD = I2C; # (/Ethernet/MAC_SDA)
("opsis_i2c", 0,
Subsignal("scl", Pins("G6"), IOStandard("I2C")),
Subsignal("sda", Pins("C1"), IOStandard("I2C")),
),
## DDR3
# MT41J128M16JT-125:K - 16 Meg x 16 x 8 Banks - DDR3-1600 11-11-11
# FBGA Code: D9PSL, Part Number: MT41J128M16 - http://www.micron.com/support/fbga
("ddram_clock", 0,
Subsignal("p", Pins("K4")),
Subsignal("n", Pins("K3")),
IOStandard("DIFF_SSTL15_II"), Misc("IN_TERM=NONE")
),
("ddram", 0,
Subsignal("cke", Pins("F2"), IOStandard("SSTL15_II")),
Subsignal("ras_n", Pins("M5"), IOStandard("SSTL15_II")),
Subsignal("cas_n", Pins("M4"), IOStandard("SSTL15_II")),
Subsignal("we_n", Pins("H2"), IOStandard("SSTL15_II")),
Subsignal("ba", Pins("J3 J1 H1"), IOStandard("SSTL15_II")),
Subsignal("a", Pins("K2 K1 K5 M6 H3 L4 M3 K6 G3 G1 J4 E1 F1 J6 H5"), IOStandard("SSTL15_II")),
Subsignal("dq", Pins(
"R3 R1 P2 P1 L3 L1 M2 M1",
"T2 T1 U3 U1 W3 W1 Y2 Y1"), IOStandard("SSTL15_II")),
Subsignal("dqs", Pins("N3 V2"), IOStandard("DIFF_SSTL15_II")),
Subsignal("dqs_n", Pins("N1 V1"), IOStandard("DIFF_SSTL15_II")),
Subsignal("dm", Pins("N4 P3"), IOStandard("SSTL15_II")),
Subsignal("odt", Pins("L6"), IOStandard("SSTL15_II")),
Subsignal("reset_n", Pins("E3"), IOStandard("LVCMOS15")),
Misc("SLEW=FAST"),
Misc("VCCAUX_IO=HIGH")
),
## onboard HDMI IN1
## HDMI - connector J5 - Direction RX
("hdmi_in", 0,
Subsignal("clk_p", Pins("L20"), IOStandard("TMDS_33")),
Subsignal("clk_n", Pins("L22"), IOStandard("TMDS_33")),
Subsignal("data0_p", Pins("M21"), IOStandard("TMDS_33")),
Subsignal("data0_n", Pins("M22"), IOStandard("TMDS_33")),
Subsignal("data1_p", Pins("N20"), IOStandard("TMDS_33")),
Subsignal("data1_n", Pins("N22"), IOStandard("TMDS_33")),
Subsignal("data2_p", Pins("P21"), IOStandard("TMDS_33")),
Subsignal("data2_n", Pins("P22"), IOStandard("TMDS_33")),
Subsignal("scl", Pins("T21"), IOStandard("LVCMOS33")),
Subsignal("sda", Pins("R22"), IOStandard("LVCMOS33")),
Subsignal("hpd_en", Pins("R20"), IOStandard("LVCMOS33"))
),
## onboard HDMI IN2
## HDMI - connector J4 - Direction RX
("hdmi_in", 1,
Subsignal("clk_p", Pins("M20"), IOStandard("TMDS_33")),
Subsignal("clk_n", Pins("M19"), IOStandard("TMDS_33")),
Subsignal("data0_p", Pins("J20"), IOStandard("TMDS_33")),
Subsignal("data0_n", Pins("J22"), IOStandard("TMDS_33")),
Subsignal("data1_p", Pins("H21"), IOStandard("TMDS_33")),
Subsignal("data1_n", Pins("H22"), IOStandard("TMDS_33")),
Subsignal("data2_p", Pins("K20"), IOStandard("TMDS_33")),
Subsignal("data2_n", Pins("L19"), IOStandard("TMDS_33")),
Subsignal("scl", Pins("L17"), IOStandard("LVCMOS33")),
Subsignal("sda", Pins("T18"), IOStandard("LVCMOS33")),
Subsignal("hpd_en", Pins("V19"), IOStandard("LVCMOS33"))
),
The _hdmi_infos[XXX_DESCRIPTION]
fields would also be candidates...
Maybe we should do some more conversion of the the Opsis / Atlys board files and see if we can shake something out? The Atlys board porting is already were the idea of Silk / Designators kind of came from.
Alright. I'll see what I can do about this.
Not directly silkscreen data but another idea I had is to provide possibility of having a picture of a board (attached to|included in) a Platform class. This would allow IDEs to present this picture to users in the platform selection window. Connectors could also provide coordinates of the connectors on the picture.
@Fatsie That is something I have wanted to do for a long time too.
However, I feel like that is better done through creating a file format which is something like a collection of image files + XML/JSON description of were things are. If that file format also had silk references it would be easy to connect the nMigen platform and the file together in a GUI / emulation environment?
@mithro Having this more in-depth documentation in another repo and have nmigen-boards as submodule is an alternative. From the other side, having this data inside python environment makes it is also accessible from jupyter and the like. One of my dreams is to have some (fancy) Jupyter workbooks using nMigen online as our cloud fpga/ASIC development platform.
@Fatsie - I think the images + connector (+button+led) locations information would be useful for tools like @renode and QEmu -- not just nmigen. It is also likely that only a small number of boards which are used in nmigen will ever get this information -- hence why I'm thinking they should be separate....
FYI - @mgielda - @pgielda
Having this more in-depth documentation in another repo and have nmigen-boards as submodule is an alternative.
That seems extremely prone to desynchronization.