m-labs / nmigen

A refreshed Python toolbox for building complex digital hardware. See https://gitlab.com/nmigen/nmigen
https://nmigen.org
Other
655 stars 56 forks source link

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

Open mithro opened 5 years ago

mithro commented 5 years ago

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 commented 5 years ago

How would it be presented to the user?

mithro commented 5 years ago

I would suggest that the;

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 commented 5 years ago

What is m.define?

mithro commented 5 years ago

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 commented 5 years ago

That doesn't explain what it does.

mithro commented 5 years ago

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 commented 5 years ago

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

mithro commented 5 years ago

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 commented 5 years ago

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.

mithro commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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

Fatsie commented 5 years ago

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 commented 5 years ago

@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 commented 5 years ago

@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 commented 5 years ago

@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 commented 5 years ago

FYI - @mgielda - @pgielda

whitequark commented 5 years ago

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

That seems extremely prone to desynchronization.