{josuah.net} | {panoramix-labs.fr}
 (DIR)  • {josuah.net}
 (DIR)  • {panoramix-labs.fr}
       
        {git} | {cv} | {links} | {quotes} | {ascii} | {tgtimes} | {gopher} | {mail}
 (DIR)  • {git}
 (BIN)  • {cv}
 (DIR)  • {links}
 (DIR)  • {quotes}
 (DIR)  • {ascii}
 (HTM)  • {tgtimes}
 (DIR)  • {gopher}
       
       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
       Interacting with FPGA hardware
       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
        One aspect of FPGAs boards is very little documented even for open-source
        modules: the usage of the hardware blocks of the FPGA: the **primitives**.
       
        Someone contributed offered these helpful koans on IRC, starting by recalling
        how synthesis works.
       
 (HTM) Help from {lkcl}
       ──────────────
 (HTM)  Original text: {https://libre-soc.org/irclog-f4pga/%23f4pga.2022-05-12.log.html}
       
        The way it works is that to compile something to a bitstream you need two
        things:
       
       #. Some HDL
       
       #. A constraints file
       
        The constraints file is what tells the nextpnr-* to map individual NETLIST
        entries (pins) onto actual IO pads.
       
        A differential clock is a clock line that, rather than having one single pin
        that goes on and off, there are a *pair* of clock lines that, simultaneously,
        switch to the opposite direction. I.e. they are "differential". The convention
        to distinguish differential pair pins is, one ends with "P" the other ends with
        "N" So `ClockP` and `ClockN`. P for Positive, N for Negative.
       
        Back to internal blocks. Yosys does *not* know about constraints (the IO pads),
        it only knows about NETLISTs and the things that those nets connect to. But you
        do have to have some sort of representation of e.g. the IBUFDS, as a black-box
        module, with the inputs and outputs, so that when the *use* of that module is
        passed over to nextpnr-* (or VerilogToRouting), the PnR tool knows what to do
        with it.
       
 (HTM)  Here is a declaration - a model - of IBUFDS: {https://electronics.stackexchange.com/questions/93373/how-to-route-a-lvds-clock-from-fpga-input-to-output}
       
        Now you can (after probably translating that to verilog) use an IBUFDS / OBUFDS
        as if it was some sort of "black box". You *do not* have to write the
        *contents* of that black box named IBUFDS / OBUFDS: just use it (as an external
        module).
       
        YoSys is intelligent enough to recognise this and will not complain (or, it
        shouldn't). It will simply pass through the black box - and all its netlists -
        `IBUFDS.I`, `IBUFDS.IB`, `IBUFDS.O` - to nextpnr-* or VerilogToRouting:
       
        ┊ Oh, you wanted an IBUFDS, and you're compiling for ICE40? Sure, I recognise
        ┊ those, let me just wire that up and P&R it for you."
       
        So it is actually extremely straightforward.
       
        The only tricky bit, as you are finding out, is that none of this
        direct-interfacing with FPGA blocks is really properly documented, you're
        pretty much just expected to "work it out".
       
        Sometimes not even the FPGA designers properly provide documentation. One good
        example is the Lattice ECP5 JTAG block, which allows you to tap into the JTAG
        port and insert your own commands so that you can interact with openocd via the
        ECP5's JTAG port.
       
        Someone had to actually reverse-engineer the ECP5's JTAG block but, your first
        priority is to find the "model" of the ICE40 IBUFDS. The one I found above is
        for Xilinx FPGAs despite searching on gooogle "ICE40 IBUFDS".
       
        Sources where you should definitely find a model file (IBUFDS.v and/or
        IBUFDS.vhdl) will be in the Lattice (proprietary) SDK. Beyond that, you are
        into playing the "hunt the unknown reverse-engineered thing on the internet"
        game.
       
       My 2 cents
       ──────────
        One way to go is first searching through the vendor documentation what feature
        we would need. For instance I/O multiplexing, math acceleration, built-in
        clock, analog features...
       
        That often is documented through the company datasheet. For the example of an
 (HTM)  iCE40: {`SB_IO`}
       
        Then the name of the block will be hopefully documented here, and now we know
        what to search. It gets possible to search for the name of the block over the
        synthesis tool (like YoSys) library: Here, there might be Verilog code with
        "Blackbox" modules to call as regular Verilog modules.
       
        For instance `SB_IO` for iCE40's I/O control or `SB_HFOSC` for the internal
        oscillator. For YoSys, it might be somewhere like `/usr/local/share/yosys`.
       
        This would give a module interface definition to use in the code.