User Tools

Site Tools


migen:migen_platform

Platform

When designing a project in Migen, at some point it is needed to adapt it for a specific board or FPGA. Migen brings that in a handy way, as well as with a compiling system. In this example, we assume that you already have your Quartus, Vivado, or ISE (depending on the FPGA you are using) installed.

Simple platform file

We are here going to declare a platform for a Xilinx xc6slx9-2csg324. We will have:

  • 1 clock signal “clk”
  • 1 user button “user_btn”
  • 2 LEDs “user_led”
  • 1 serial made of a “tx” and “rx” pins.

In fact, all those signals are going to be in a table “_io”

my_platform.py
from migen.build.generic_platform import *
from migen.build.xilinx import XilinxPlatform
 
_io = [
 
        ("clk", 0, Pins("C10"), IOStandard("LVCMOS33")),  # default: 100 MHz
 
        ("user_btn", 0, Pins("V4"), IOStandard("LVCMOS33"), Misc("PULLDOWN"), Misc("TIG")),
 
        ("user_led", 0, Pins("P4"), Misc("SLEW=QUIETIO"), IOStandard("LVCMOS18")),
        ("user_led", 1, Pins("L6"), Misc("SLEW=QUIETIO"), IOStandard("LVCMOS18")),
 
        ("serial", 0,
           Subsignal("tx", Pins("T7"), Misc("SLEW=SLOW")),
           Subsignal("rx", Pins("R7"), Misc("PULLUP")),
           IOStandard("LVCMOS33")),
      ]
 
class Platform(XilinxPlatform):
    default_clk_name = "clk"
    default_clk_period = 10
 
    def __init__(self):
        XilinxPlatform.__init__(self, "xc6slx9-2csg324", _io)
 

Understanding the IOs is somehow simple: it consist of the name of the pin, followed by the index, the “Pins” refers to the physical pin, and finally some vendor specific keyword to pass it for the technology and voltage used on that pin.

Build example

On the FHDL code side, we will import the platform first, then use the build method in order to compile:

from migen import *
import my_platform
 
dut = MyTopModule()
 
platform = my_platform.Platform()
platform.build(dut)

Migen supported platforms

Migen comes with a list of known platforms:

$ ls migen/migen/build/platforms
 
__init__.py  ice40_hx1k_blink_evn.py  m1.py            papilio_pro.py  usrp_b100.py
apf27.py     ice40_hx8k_b_evn.py      mercury.py       pipistrello.py  versa.py
apf51.py     icestick.py              mimasv2.py       rhino.py        zedboard.py
apf6sp.py    kc705.py                 minispartan6.py  roach.py        ztex_115d.py
de0cv.py     kcu105.py                mixxeo.py        sinara
de0nano.py   lx9_microboard.py        ml605.py         tinyfpga_b.py

LX16DDR platform

In case migen does not already supports your platform, you can create your own platform file. Let's get in a real example with the LX16DDR platform.

lx16ddr.py
from migen.build.generic_platform import *
from migen.build.xilinx import XilinxPlatform
 
 
_io = [
    ("user_led", 0, Pins("T9"), IOStandard("LVCMOS33"), Drive(24), Misc("SLEW=QUIETIO")), # D1
    ("user_led", 1, Pins("R9"), IOStandard("LVCMOS33"), Drive(24), Misc("SLEW=QUIETIO")), # D3
 
    ("user_btn", 0, Pins("T8"), IOStandard("LVCMOS33")), # SW2
    ("user_btn", 1, Pins("R7"), IOStandard("LVCMOS33")), # SW3
 
    ("clk50", 0, Pins("A10"), IOStandard("LVCMOS33")),
 
    ("serial", 0,
        Subsignal("tx", Pins("C13"), IOStandard("LVCMOS33"), Misc("SLEW=SLOW")), # U8 Pin9
        Subsignal("rx", Pins("A14"), IOStandard("LVCMOS33"), Misc("PULLUP"))     # U8 Pin7
    ),
    ("serial", 1,
        Subsignal("tx", Pins("A13"), IOStandard("LVCMOS33"), Misc("SLEW=SLOW")), # U8 Pin10
        Subsignal("rx", Pins("B14"), IOStandard("LVCMOS33"), Misc("PULLUP"))     # U8 Pin8
    ),
 
    ("spiflash", 0,
        Subsignal("cs_n", Pins("T3")),
        Subsignal("clk", Pins("R11")),
        Subsignal("mosi", Pins("T10")),
        Subsignal("miso", Pins("P10"), Misc("PULLUP")),
        IOStandard("LVCMOS33"), Misc("SLEW=FAST")
    ),
 
    ("ddram", 0,
     Subsignal("a", Pins("K5 K6 D1 L4 G5 H4 H3 D3 B2 A2 G6 E3 F3 F6 F5"), IOStandard("SSTL15")),
     Subsignal("ba", Pins("C3 C2 B1"), IOStandard("SSTL15")),
     Subsignal("ras_n", Pins("J6"), IOStandard("SSTL15")),
     Subsignal("cas_n", Pins("H5"), IOStandard("SSTL15")),
     Subsignal("we_n", Pins("C1"), IOStandard("SSTL15")),
     Subsignal("dm", Pins("J4 K3"), IOStandard("SSTL15")),
     Subsignal("dq", Pins("K2 K1 J3 J1 F2 F1 G3 G1 L3 L1 M2 M1 P2 P1 R2 R1"), IOStandard("SSTL15"), Misc("IN_TERM=UNTUNED_SPLIT_50")),
     Subsignal("dqs_p", Pins("H2 N3"), IOStandard("DIFF_SSTL15")),
     Subsignal("dqs_n", Pins("H1 N1"), IOStandard("DIFF_SSTL15")),
     Subsignal("clk_p", Pins("E2"), IOStandard("DIFF_SSTL15")),
     Subsignal("clk_n", Pins("E1"), IOStandard("DIFF_SSTL15")),
     Subsignal("cke", Pins("F4"), IOStandard("SSTL15")),
     Subsignal("odt", Pins("L5"), IOStandard("SSTL15")),
     Subsignal("reset_n", Pins("E4"), IOStandard("SSTL15")),
     Misc("SLEW=FAST"),
    ),
]
 
_connectors = [
    ("A", "E12 B15 C15 D14 E15 F15 G11 F14 G16 H15 G12 H13 J14 J11 K14 K15 L16 K11 M15 N14 M13 L12 P15 R15 R14 T13 T12"), # U7 1
    ("B", "E13 B16 C16 D16 E16 F16 F12 F13 G14 H16 H11 H14 J16 J12 J13 K16 L14 K12 M16 N16 M14 L13 P16 R16 T15 T14 R12"), # U7 2
    ("C", "A14 C13 B12 C11 B10 C9 B8 C7 B6 B5 E10 E11 F9 C8 E7 F7 D6 M7 N8 P9 T5 T6 N9 L8 L10 P12 R9"), # U8 1
    ("D", "B14 A13 A12 A11 A9 A8 A7 A6 A5 A4 C10 F10 D9 D8 E6 C6 N6 P6 L7 T4 R5 T7 M9 M10 P11 M11 T9")  # U8 2
]
 
 
class Platform(XilinxPlatform):
    default_clk_name = "clk50"
    default_clk_period = 20.00
 
    def __init__(self):
        XilinxPlatform.__init__(self, "xc6slx16-ftg256-2", _io, _connectors)

What we see for example is that a user_led is declared on pin T9, and a clock (of 50 MHz) is on pin A10. Of course, the SPI Flash, the DDR RAM as well as 2 serial ports are also there. The extension connectors are also present.

If you compare this platform file with the board schematics, you should find exactly the same pinout: lx16ddr_red_board.pdf

Let's now imagine that we wanted to create a project with it.

Here is an example of LED blink:

lx16ddr_blink.py
from migen import *
import lx16ddr
 
class MyLedBlink(Module):
    def __init__(self, platform):
        self.led = led = platform.request("user_led")
        counter = Signal(25)
 
        self.sync += counter.eq(counter + 1)
        self.comb += led.eq(counter[24])
 
platform = lx16ddr.Platform()
dut = MyLedBlink(platform)
platform.build(dut)
python3 lx16ddr_blink.py

migen/migen_platform.txt · Last modified: 2018/01/10 19:11 by po