Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support silkscreen references (and other information) in platform definitions #143

Open
mithro opened this issue Jul 9, 2019 · 19 comments
Labels

Comments

@mithro
Copy link

mithro commented Jul 9, 2019

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?

@whitequark
Copy link
Contributor

How would it be presented to the user?

@mithro
Copy link
Author

mithro commented Jul 9, 2019

I would suggest that the;

  • Resource object have an optional attribute called silkscreen_reference which takes an arbitrary string.
  • Resource objects have an optional attribute called location_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)

@whitequark
Copy link
Contributor

whitequark commented Jul 9, 2019

What is m.define?

@mithro
Copy link
Author

mithro commented Jul 9, 2019

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)

@whitequark
Copy link
Contributor

That doesn't explain what it does.

@mithro
Copy link
Author

mithro commented Jul 9, 2019

Provides a define in the C header file. CSRConstant could be another option.

Or you could write out a CSV or other configuration file?

@whitequark
Copy link
Contributor

whitequark commented Jul 9, 2019

Writing C header files is definitely not something that should be a part of core nMigen.

@mithro
Copy link
Author

mithro commented Jul 9, 2019

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.....

@whitequark
Copy link
Contributor

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.

@whitequark whitequark transferred this issue from m-labs/nmigen-boards Jul 9, 2019
@mithro
Copy link
Author

mithro commented Jul 9, 2019

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....

@whitequark
Copy link
Contributor

Something like a freeform __doc__, help or doc 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.

@mithro
Copy link
Author

mithro commented Jul 9, 2019

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.

@whitequark
Copy link
Contributor

Alright. I'll see what I can do about this.

@Fatsie
Copy link
Contributor

Fatsie commented Jul 9, 2019

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.

@mithro
Copy link
Author

mithro commented Jul 9, 2019

@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?

@Fatsie
Copy link
Contributor

Fatsie commented Jul 9, 2019

@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.

@mithro
Copy link
Author

mithro commented Jul 9, 2019

@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....

@mithro
Copy link
Author

mithro commented Jul 9, 2019

FYI - @mgielda - @pgielda

@whitequark
Copy link
Contributor

Having this more in-depth documentation in another repo and have nmigen-boards as submodule is an alternative.

That seems extremely prone to desynchronization.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants