WIN10/WSL系统下使用nMigen实现FPGA开发
软件:
Windows10 安装 WSL - ubuntu (18.04 or 20.02)
WSL: Python3 (>3.5)
WSL: yosys (https://githbub.com/yosyshq/yosys)
WSL: nMigen (https://github.com/nmigen/nmigen)
WSL: nmigen-soc/nmigen-boards/nmigen-stdio (https://github.com/nmigen/...)
Win10: Quartus primer Pro/Std 18.1 (+Cyclone IV support, + licensed)
硬件:
nmigen可以实现基于python的FPGA数字系统设计/验证, 但需要借助专用的工具完成F
hdl到硬件的实现。
nmigen支持基于quartus作为
后端实现的工具,我们可以利用WSL平台执行windows程序的功能,
将windows下的quartus与WSL下的nmigen配合,完成FPGA系统的设计,验证,综合,映射,以及最终部署
到DE0_NANO开发板上运行。
nmigen支持quartus工具链,在WSL系统下,我们需要首先设置下运行环境,以便nmigen能够正确的找到WIN10
下的工具。需要设置的环境变量如下,可添加到.bashrc中:
QTS_HOME=/mnt/d/intelFPGA/18.1/quartus
PATH=$PATH:$QTS_HOME/bin64
export PATH
LD_LIBRARY_PATH=$QTS_HOME/linux64
export LD_LIBRARY_PATH
export QUARTUS_PGM="quartus_pgm.exe"
export QUARTUS_MAP="quartus_map.exe"
export QUARTUS_FIT="quartus_fit.exe"
export QUARTUS_CPF="quartus_cpf.exe"
export QUARTUS_STA="quartus_sta.exe"
export QUARTUS_ASM="quartus_asm.exe"
alias quartus_pgm="quartus_pgm.exe"
alias quartus_map="quartus_map.exe"
alias quartus_fit="quartus_fit.exe"
alias quartus_cpf="quartus_cpf.exe"
alias quartus_sta="quartus_sta.exe"alias quartus_asm="quartus_asm.exe"
安装nmigen-soc/nmigen-stdio/nmigen-boards
(注:用下面的方法不用单独安装nmigen, pip会自动根据依赖关系安装nmigen)
sudo pip3 install git+https://github.com/nmigen/nmigen-soc
sudo pip3 install git+https://github.com/nmigen/nmigen-stdio
sudo pip3 install git+https://github.com/nmigen/nmigen-boards
nmigen默认使用yosys作为综合工具,而不是直接使用quartus,所以需要安装yosys,
安装yosys可以直接从github源下载安装, 也可以直接安装编译好的源:
#ubuntu 18.04/20.02可以直接apt安装:
sudo apt install yosys
nmigen-boards里面没有支持DE0_Nano, 我们可以通过复制一个相似的平台创建一个, 比如de0_cv.py
创建一个项目目录, 复制/nmigen-boards/下的de0_cv.py,改名de0_nano.py
按照DE0_Nano的资源,更新如下:
#!/usr/bin/env python3
# DE0_Nano support file
import os
import subprocess
from nmigen.build import *
from nmigen.vendor.intel import *
from nmigen_boards.resources import *
__all__ = ["DE0NanoPlatform"]
class DE0NanoPlatform(IntelPlatform):
device = "EP4CE22" #
package = "F17" # FBGA-484
speed = "C6"
default_clk = "clk50"
resources = [
Resource("clk50", 0, Pins("R8", dir="i"),
Clock(50e6), Attrs(io_standard="3.3-V LVTTL")),
Resource("epcs", 0,
Subsignal("data0", Pins("H2", dir="i")),
Subsignal("dclk", Pins("H1", dir="o")),
Subsignal("ncs0", Pins("D2", dir="o")),
Subsignal("asd0", Pins("C1", dir="o")),
Attrs(io_standard="3.3-V LVTTL")
),
Resource("i2c", 0,
Subsignal("sclk", Pins("F2", dir="o")),
Subsignal("sdat", Pins("F1", dir="io")),
Attrs(io_standard="3.3-V LVTTL")
),
Resource("g_sensor", 0,
Subsignal("cs_n", Pins("G5", dir="o")),
Subsignal("int", Pins("M2", dir="i")),
Attrs(io_standard="3.3-V LVTTL")
),
Resource("adc", 0,
Subsignal("cs_n", Pins("A10", dir="o")),
Subsignal("saddr", Pins("B10", dir="i")),
Subsignal("sclk", Pins("B14", dir="o")),
Subsignal("sdat", Pins("A9", dir="o")),
Attrs(io_standard="3.3-V LVTTL")
),
*LEDResources(
pins="A15 A13 B13 A11 D1 F3 B1 L3", invert=True,
attrs=Attrs(io_standard="3.3-V LVTTL")),
*ButtonResources(
pins="J15 E1", invert=True,
attrs=Attrs(io_standard="3.3-V LVTTL")),
*SwitchResources(
pins="M1 T8 B9 M15",
attrs=Attrs(io_standard="3.3-V LVTTL")),
UARTResource(0, # uart
rx="C3", tx="D3",
attrs=Attrs(io_standard="3.3-V LVTTL")),
*SDCardResources(0,
clk="H11", cmd="B11", dat0="K9", dat1="D12", dat2="E12", dat3="C11", wp="W20",
attrs=Attrs(io_standard="3.3-V LVTTL")),
SDRAMResource(0,
clk="R4", cke="L7", cs="P6", we="C2", ras="L2", cas="L1",
ba="M7 M6", a="P2 N5 N6 M8 P8 T7 N8 T6 R1 P1 N2 N1 L4",
dq="G2 G1 L8 K5 K2 J2 J1 R7 T4 T2 T3 R3 R5 P3 N3 K1", dqm="R6 T5",
attrs=Attrs(io_standard="3.3-V LVCMOS")),
]
connectors = [
Connector("j", 1,
"A8 D3 B8 C3 A2 A3 B3 B4 A4 B5 "
"- - A5 D5 B6 A6 B7 D6 A7 C6 "
"C8 E6 E7 D8 E8 F8 F9 E9 - - "
"C9 D9 E11 E10 C11 B11 A12 D11 D12 B12 "),
Connector("j", 2,
"T9 F13 R9 T15 T14 T13 R13 T12 R12 T11 "
"- - T10 R11 P11 R10 N12 P9 N9 N11"
"L16 K16 R16 L15 P15 P16 R14 N16 - - "
"N15 P14 L14 N14 M10 L13 J16 K15 J13 J14 "),
Connector("j", 3,
"- E15 E16 M16 A14 B16 C14 C16 C15 "
"D16 D15 D14 F15 F16 F14 G16 G15 - "
"- - - - - - - - "),
]
def toolchain_program(self, products, name):
quartus_pgm = os.environ.get("QUARTUS_PGM", "quartus_pgm")
with products.extract("{}.sof".format(name)) as bitstream_filename:
subprocess.check_call([quartus_pgm, "--haltcc", "--mode", "JTAG",
"--operation", "P;" + bitstream_filename])
下面我们写一个blinker.py例程测试下:
#!/usr/bin/env python3
from nmigen import *
from de0_nano import DE0NanoPlatform
class Blinker(Elaboratable):
def __init__(self, max_prd):
self.max_prd = max_prd
def elaborate(self, platform):
led = platform.request("led", 0);
m = Module()
counter = Signal(range(self.max_prd + 1))
period = Signal(range(self.max_prd + 1))
# load/init period value
m.d.comb += period.eq(self.max_prd)
with m.If(counter == 0):
m.d.sync += [
led.eq(~led),
counter.eq(period)
]
with m.Else():
m.d.sync += [
counter.eq(counter - 1)
]
return m
if __name__ == "__main__":
plat = DE0NanoPlatform()
plat.build(Blinker(40000000), do_program=True)
将DE0_Nano连上电脑, 运行 > ./Blinker.py 完成项目的编译,综合,映射,下载运行....