开源 FPGA 07|国产 FPGA 上手:高云 Tang Nano 9K 开源工具链全流程
_____ _ _ __ __ ___ _ _
|_ _/_\ | \| | / _| _ \ \| |
| |/ _ \ | .` | | (_ | / .` |
|_/_/ \_\|_|\_| \___|_|_\_|\_|
国产 FPGA 走上开源工具链舞台
系列第 07 篇 · 目标器件:高云半导体 GW1NR-9C(Tang Nano 9K) 工具版本:Yosys 0.40 / nextpnr-gowin 0.7 / apicula 0.8.0 / openFPGALoader 0.12 上一篇:ECP5 + ULX3S:HDMI + SD 卡 + ESP32
0. 这一篇要解决什么问题
前几篇用的都是 Lattice 的芯片(iCE40、ECP5)。但如果你在国内做硬件,Lattice 的芯片价格偏高、供货周期长,有时还有进口合规的麻烦。高云(Gowin) 这几年在国内市场份额快速增长,Tang Nano 系列开发板便宜(9K 版本约 ¥60-80),而且已经有了相对完整的开源工具链支持。
本篇目标:
- 搞清楚 Tang Nano 9K 的硬件规格
- 用开源工具链(而非高云官方 IDE)跑通点灯 + UART
- 实现 PSRAM HyperBus 控制器(Tang Nano 9K 板载 64Mb PSRAM)
- HDMI 输出(与 ECP5 篇对比差异)
- 摸清 apicula 的现状和局限
本篇不覆盖:
- 高云官方 IDE(GowinEDA)的详细使用,这是开源工具链系列
- GW2A/GW5A 等大型高云 FPGA(工具链支持还在进行中)
- 高云 MCU 软核(相对 VexRiscv 更弱)
1. Tang Nano 9K 硬件规格
| 参数 | 规格 |
|---|---|
| FPGA | 高云 GW1NR-9C(Arora 系列,TSMC 55nm) |
| LUT | 8640 个 LUT4 |
| DFF | 6480 个触发器 |
| BRAM | 468 Kbit(Block RAM) |
| DSP18 | 60 个(18×18 乘法器) |
| PLL | 1 个 |
| 板载存储 | 64Mb PSRAM(APS6404L-SQ,HyperBus/SPI 双模式) |
| 时钟 | 27 MHz 晶振(注意:不是 25MHz!) |
| 视频输出 | HDMI Type A |
| USB | USB-C(CH552 USB-to-UART,1 路 UART) |
| 存储卡 | TF 卡槽(SPI 模式) |
| GPIO | 36 个用户 IO |
| 价格 | ¥60-80(2024 年淘宝均价) |
GW1NR 和 GW1N 的区别: GW1NR 片上集成了 64Mb PSRAM(实际是 APS6404L 芯片,通过内部总线连接),GW1N 没有。Tang Nano 9K 用的是 GW1NR-9C,有 PSRAM。
2. 高云官方工具 vs 开源工具链
| 对比项 | GowinEDA(官方) | apicula + nextpnr-gowin(开源) |
|---|---|---|
| 授权费用 | 免费(需注册,有功能限制版) | 完全免费,无限制 |
| 跨平台 | Windows 主力,Linux 有限 | Linux/macOS/Windows 全支持 |
| 综合引擎 | 高云自研 Synpro | Yosys(开源,可调) |
| P&R 质量 | 较好(Fmax 稍高) | 稍低(apicula 时序数据库不完整) |
| BRAM 支持 | 完整 | 基本支持(primitives 覆盖度约 80%) |
| PLL 配置 | 图形化 IP Wizard | 手动实例化原语 |
| DSP18 | 自动推断 | 需要手动实例化(Yosys 推断率低) |
| SERDES | 支持(部分型号) | 不支持(apicula 未逆向) |
| 社区支持 | 官方论坛(中文为主) | GitHub Issues(英文为主) |
| 适合场景 | 生产项目,最大化性能 | 学习/实验,CI/CD 集成,开源项目 |
结论: 对于开源项目或学习目的,nextpnr-gowin 完全够用。对于 Fmax > 100MHz 或需要 DSP/SERDES 密集使用的场景,暂时还是用 GowinEDA 更保险。
3. apicula 项目现状(2024)
apicula(前身叫 nextpnr-gowin)是高云 FPGA 开源工具链的核心。它通过逆向工程的方式,从高云官方 bitstream 中提取芯片的内部结构、时序模型、布线资源描述。
2024 年进展:
- GW1N-9/GW1NR-9 完整支持(包括 Tang Nano 9K)
- GW1N-1/GW1N-2/GW1N-4 基本支持
- GW2A-18(Tang Nano 20K)支持中,覆盖度约 70%
- GW5A-25(Tang Nano 4K Pro)尚未逆向
时序数据库覆盖度:
GW1NR-9C 时序覆盖(apicula 0.8):
LUT4 传播延迟: ✅ 完整(±5% 误差)
DFF setup/hold: ✅ 完整
BRAM 时序: ✅ 基本完整
PLL 抖动模型: ⚠️ 保守估计(实际 jitter 可能更小)
DSP18 流水线: ⚠️ 部分(乘法结果延迟约 ±10% 误差)
IO buffer 延迟: ⚠️ 近似值(差分 IO 误差较大)
因为时序数据库不完整,nextpnr-gowin 给出的 Fmax 估计比实际偏低约 5-15%。换句话说,如果工具报 80MHz,实际上板可能能跑到 90MHz。但反过来不成立——不要依赖这种不确定性做设计决策。
4. 完整开源工具流程
安装
# OSS CAD Suite(包含 nextpnr-gowin + apicula)
source oss-cad-suite/environment
# 验证 gowin 支持
nextpnr-gowin --help | grep -i "family\|device"
# 应看到 GW1N/GW1NR 等型号
# openFPGALoader(Tang Nano 通过 USB-C 直连,用 CMSIS-DAP 协议)
openFPGALoader --list-boards | grep tang
# tang_nano tang_nano1k tang_nano4k tang_nano9k tang_nano20k
工程目录结构
tang-nano-9k-demo/
├── src/
│ ├── top.v # 顶层
│ ├── uart_tx.v # UART 发送
│ └── led_blink.v # LED 闪烁
├── constraints/
│ └── tangnano9k.cst # 高云用 .cst(不是 .lpf!)
├── Makefile
└── build/
约束文件(.cst)
高云工具用 .cst(Constraint file)格式,与 Lattice .lpf 不同:
// tangnano9k.cst
// Tang Nano 9K 引脚约束
// 时钟(27 MHz,注意不是 25MHz)
IO_LOC "clk" 52;
IO_PORT "clk" PULL_MODE=UP;
// LED(低电平点亮)
IO_LOC "led[0]" 10;
IO_LOC "led[1]" 11;
IO_LOC "led[2]" 13;
IO_LOC "led[3]" 14;
IO_LOC "led[4]" 15;
IO_LOC "led[5]" 16;
IO_PORT "led[0]" PULL_MODE=UP DRIVE=8;
IO_PORT "led[1]" PULL_MODE=UP DRIVE=8;
// UART(通过 CH552 USB-to-UART)
IO_LOC "uart_rx" 18;
IO_LOC "uart_tx" 17;
IO_PORT "uart_rx" PULL_MODE=UP;
IO_PORT "uart_tx" PULL_MODE=UP;
// HDMI(差分对)
IO_LOC "tmds_clk_p" 33;
IO_LOC "tmds_clk_n" 34;
IO_LOC "tmds_d_p[0]" 35;
IO_LOC "tmds_d_n[0]" 36;
IO_LOC "tmds_d_p[1]" 37;
IO_LOC "tmds_d_n[1]" 38;
IO_LOC "tmds_d_p[2]" 39;
IO_LOC "tmds_d_n[2]" 40;
IO_PORT "tmds_clk_p" IO_TYPE=LVCMOS33D;
IO_PORT "tmds_clk_n" IO_TYPE=LVCMOS33D;
IO_PORT "tmds_d_p[0]" IO_TYPE=LVCMOS33D;
// ... 其余差分对类似
点灯示例(完整 Verilog)
// top.v — Tang Nano 9K 点灯 + UART Hello
module top (
input wire clk, // 27 MHz
input wire rst_n, // 按键复位(低有效)
output reg [5:0] led, // 6 个 LED(低电平亮)
output wire uart_tx
);
// PLL:27 MHz → 54 MHz(系统时钟)
wire clk_sys;
wire pll_lock;
// 高云 PLL 原语(rPLL)
rPLL #(
.FCLKIN("27"), // 输入频率 27 MHz
.IDIV_SEL(0), // 分频系数 = IDIV_SEL + 1 = 1
.FBDIV_SEL(1), // 反馈分频 = FBDIV_SEL + 1 = 2
.ODIV_SEL(8), // 输出分频,VCO/8 = 216/4 = 54MHz
// VCO = 27 × (FBDIV+1) / (IDIV+1) = 27 × 2 = 54 → 216MHz with ODIV=4
.DYN_SDIV_SEL(2)
) pll0 (
.CLKIN(clk),
.CLKOUT(clk_sys),
.LOCK(pll_lock),
.RESET(~rst_n),
.RESET_P(1'b0),
.CLKFB(1'b0),
.FBDSEL(6'b0),
.IDSEL(6'b0),
.ODSEL(6'b0),
.PSDA(4'b0),
.DUTYDA(4'b0),
.FDLY(4'b0)
);
// 计数器:约 0.5 秒闪一次(54MHz / 2^25 ≈ 1.6Hz)
reg [25:0] cnt;
always @(posedge clk_sys or negedge rst_n) begin
if (!rst_n)
cnt <= 0;
else
cnt <= cnt + 1;
end
always @(*) led = ~{6{cnt[25]}}; // 全亮或全灭
// UART TX:上电后发送 "Hello Tang Nano 9K!\r\n"
uart_hello #(.CLK_FREQ(54_000_000), .BAUD(115200)) u_uart (
.clk(clk_sys), .rst_n(rst_n && pll_lock),
.tx(uart_tx)
);
endmodule
// uart_hello.v — 上电发送固定字符串
module uart_hello #(
parameter CLK_FREQ = 54_000_000,
parameter BAUD = 115_200
) (
input wire clk,
input wire rst_n,
output reg tx
);
localparam CLKS_PER_BIT = CLK_FREQ / BAUD; // 469
// 要发送的字符串(ASCII)
localparam MSG_LEN = 22;
reg [7:0] msg [0:MSG_LEN-1];
initial begin
msg[ 0] = "H"; msg[ 1] = "e"; msg[ 2] = "l"; msg[ 3] = "l";
msg[ 4] = "o"; msg[ 5] = " "; msg[ 6] = "T"; msg[ 7] = "a";
msg[ 8] = "n"; msg[ 9] = "g"; msg[10] = " "; msg[11] = "N";
msg[12] = "a"; msg[13] = "n"; msg[14] = "o"; msg[15] = " ";
msg[16] = "9"; msg[17] = "K"; msg[18] = "!"; msg[19] = "\r";
msg[20] = "\n"; msg[21] = 8'd0;
end
reg [4:0] char_idx;
reg [3:0] bit_idx;
reg [9:0] clk_cnt;
reg [9:0] shift_reg; // start + 8 data + stop
reg sending;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
tx <= 1;
char_idx <= 0;
bit_idx <= 0;
clk_cnt <= 0;
sending <= 1;
shift_reg <= 10'h3FF;
end else if (sending) begin
if (clk_cnt == CLKS_PER_BIT - 1) begin
clk_cnt <= 0;
if (bit_idx == 9) begin
bit_idx <= 0;
if (char_idx == MSG_LEN - 1)
sending <= 0;
else begin
char_idx <= char_idx + 1;
// 打包:start(0) + data + stop(1)
shift_reg <= {1'b1, msg[char_idx+1], 1'b0};
end
end else begin
tx <= shift_reg[0];
shift_reg <= {1'b1, shift_reg[9:1]};
bit_idx <= bit_idx + 1;
end
end else begin
clk_cnt <= clk_cnt + 1;
if (bit_idx == 0 && clk_cnt == 0)
shift_reg <= {1'b1, msg[char_idx], 1'b0};
end
end else
tx <= 1;
end
endmodule
综合、布线、烧录
# Makefile
DEVICE = GW1NR-9C
PACKAGE = QFN88P
CST = constraints/tangnano9k.cst
build/top.json: src/top.v src/uart_hello.v
yosys -p "
read_verilog -sv $^;
synth_gowin -top top -json $@
"
build/top.pack: build/top.json
nextpnr-gowin \
--device $(DEVICE) \
--package $(PACKAGE) \
--cst $(CST) \
--json $< \
--write $@ \
--freq 54
build/top.fs: build/top.pack
gowin_pack -d $(DEVICE) -o $@ $<
prog: build/top.fs
openFPGALoader -b tangnano9k $<
make prog
# 预期输出:
# Info: Max frequency for clock 'clk_sys': 112.4 MHz (PASS at 54.00 MHz)
# Flashing build/top.fs...
# Programming done.
🚧 避坑 #1:apicula 时序数据库不完整导致 Fmax 偏低
nextpnr-gowin 报告的 Fmax 经常比实际低 5-15%。这不是 bug,而是 apicula 的时序模型是通过逆向工程近似的,保守估计以避免误报通过。如果你的设计目标是 100MHz,工具报 90MHz PASS,不代表实际跑不到 100MHz——但也不能依赖这个去做更激进的设计。建议在 GowinEDA 中做最终的时序收敛确认(用开源工具做开发,用官方工具做验收)。
5. PSRAM HyperBus 控制器
Tang Nano 9K 板载 APS6404L-SQ:64Mb(8MB)PSRAM,支持 HyperBus 和 SPI 双模式。HyperBus 是 Infineon(Cypress)的接口标准,8-bit 数据总线 + 差分时钟,DDR 模式,速率最高 200 MHz × 8bit = 200 MB/s。
HyperBus 命令帧格式(48 bit):
Bit 47: R/W(1=读,0=写)
Bit 46: AS(地址空间:0=存储器,1=寄存器)
Bit 45: Burst(1=线性,0=包绕)
Bit 44-16: 地址(29 bit,字地址,不是字节地址)
Bit 15-3: 保留(0)
Bit 2-0: 地址低 3 bit(字内偏移)
// hyperbus_ctrl.v
// APS6404L PSRAM HyperBus 控制器(简化版:线性读写)
module hyperbus_ctrl (
input wire clk, // 系统时钟(54 MHz)
input wire rst_n,
// 用户接口
input wire req, // 发起请求
input wire rw, // 1=读,0=写
input wire [22:0] addr, // 字地址(23 bit = 8MB / 2)
input wire [15:0] wdata, // 写数据(16-bit 字)
output reg [15:0] rdata, // 读数据
output reg ack, // 操作完成
// HyperBus 物理接口
output reg hb_ck, // HyperBus 时钟(差分 P)
output wire hb_ckn, // 时钟 N(由综合工具处理差分)
output reg hb_cs_n, // 片选(低有效)
inout wire [7:0] hb_dq, // 数据总线(双向)
output reg hb_rwds // 读写数据选通 / 字节掩码
);
assign hb_ckn = ~hb_ck;
// 状态机
localparam IDLE = 3'd0;
localparam CA_PHASE = 3'd1; // 发送 6 字节命令/地址
localparam LATENCY = 3'd2; // 等待延迟周期(初始延迟 = 6 cycles)
localparam RWDATA = 3'd3; // 读/写数据
localparam DESEL = 3'd4; // 释放 CS
reg [2:0] state;
reg [5:0] cycle_cnt;
reg [47:0] ca_shift; // 命令/地址移位寄存器
reg [7:0] dq_out;
reg dq_oe; // 数据总线输出使能
assign hb_dq = dq_oe ? dq_out : 8'hZZ;
// 初始延迟:APS6404L 在 54MHz 下 tACC = 40ns → 3 个周期
// 保守取 6 个 DDR 周期(12 个时钟沿)
localparam LATENCY_CYCLES = 6;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= IDLE;
hb_cs_n <= 1;
hb_ck <= 0;
dq_oe <= 0;
ack <= 0;
end else begin
ack <= 0;
case (state)
IDLE: begin
hb_cs_n <= 1;
hb_ck <= 0;
dq_oe <= 0;
if (req) begin
// 构造 CA(Command/Address)帧
ca_shift <= {rw, 1'b0, 1'b1, // R/W, Memory Space, Linear
addr[22:0], 3'b0, // 地址 + 低 3 bit
16'b0}; // 保留
hb_cs_n <= 0;
cycle_cnt <= 0;
state <= CA_PHASE;
dq_oe <= 1;
end
end
CA_PHASE: begin
// HyperBus CA 阶段:DDR 发送,每个时钟沿输出 8-bit
hb_ck <= ~hb_ck;
if (cycle_cnt < 12) begin // 48 bit / 4-bit DDR = 12 edges
dq_out <= ca_shift[47:40];
ca_shift <= {ca_shift[39:0], 8'h00};
cycle_cnt <= cycle_cnt + 1;
end else begin
cycle_cnt <= 0;
state <= LATENCY;
dq_oe <= 0;
hb_rwds <= 0;
end
end
LATENCY: begin
// 等待初始延迟(6 个时钟周期)
hb_ck <= ~hb_ck;
cycle_cnt <= cycle_cnt + 1;
if (cycle_cnt == LATENCY_CYCLES * 2 - 1) begin
cycle_cnt <= 0;
state <= RWDATA;
dq_oe <= ~rw; // 写时驱动 DQ
end
end
RWDATA: begin
hb_ck <= ~hb_ck;
if (!rw) begin
// 写:先输出高字节,再输出低字节(DDR)
dq_out <= (cycle_cnt[0] == 0) ?
wdata[15:8] : wdata[7:0];
if (cycle_cnt == 1) begin
cycle_cnt <= 0;
state <= DESEL;
end else
cycle_cnt <= cycle_cnt + 1;
end else begin
// 读:RWDS 为高时数据有效
if (hb_rwds) begin
if (cycle_cnt == 0)
rdata[15:8] <= hb_dq;
else begin
rdata[7:0] <= hb_dq;
ack <= 1;
state <= DESEL;
end
cycle_cnt <= cycle_cnt + 1;
end
end
end
DESEL: begin
hb_cs_n <= 1;
hb_ck <= 0;
dq_oe <= 0;
state <= IDLE;
end
endcase
end
end
endmodule
🚧 避坑 #2:PSRAM 初始化必须等 150µs
APS6404L 上电后需要等 150µs 才能接受命令(tPU = 150µs max)。如果你在
rst_n释放后立刻发命令,PSRAM 可能没初始化完,读出全是 0xFF 或随机数据。在顶层逻辑里加一个计数器:54MHz 时钟,150µs = 8100 个时钟周期。计到 8100 后再拉高psram_ready信号,允许控制器开始工作。
6. HDMI 输出:与 ECP5 的差异
高云的差分 IO 原语不叫 ODDRX2F,叫 ELVDS_OBUF + ODDR:
// gowin_tmds_out.v
// 高云 GW1NR-9C TMDS 输出原语(与 ECP5 不同)
module gowin_tmds_out (
input wire clk_5x, // 5× 像素时钟
input wire clk_pixel,
input wire [9:0] tmds,
output wire tmds_p,
output wire tmds_n
);
wire serial_out;
// 高云 OSER10:10:1 串行化(比 ECP5 的 ODDRX2F 更直接)
OSER10 #(
.GSREN("false"),
.LSREN("true")
) ser (
.D0(tmds[0]), .D1(tmds[1]), .D2(tmds[2]), .D3(tmds[3]),
.D4(tmds[4]), .D5(tmds[5]), .D6(tmds[6]), .D7(tmds[7]),
.D8(tmds[8]), .D9(tmds[9]),
.FCLK(clk_5x), // 高速时钟
.PCLK(clk_pixel), // 像素时钟
.RESET(1'b0),
.Q(serial_out)
);
// 差分输出缓冲
ELVDS_OBUF elvds (
.I(serial_out),
.O(tmds_p),
.OB(tmds_n)
);
endmodule
ECP5 vs 高云 TMDS 输出对比:
| 原语 | ECP5(Lattice) | GW1NR-9C(高云) |
|---|---|---|
| 串行化 | ODDRX2F(4:1 DDR,需要两级) | OSER10(10:1,一步到位) |
| 差分输出 | LVCMOS33D IO + ODDRX2F | ELVDS_OBUF |
| PLL 生成 5× 时钟 | EHXPLLL | rPLL |
| 最高支持分辨率 | 1080p@60Hz(ECP5-85F) | 720p@60Hz(GW1NR-9C,IO 速率限制) |
| TMDS encoder | 相同(Verilog 共用) | 相同(Verilog 共用) |
高云的 OSER10 原语非常好用——直接 10:1 串行化,不需要 ECP5 那样两级 DDR 的技巧。TMDS encoder 本身(8b/10b 那部分)两个平台完全相同,可以直接复用上一篇写的 tmds_encoder.v。
7. 中国 FPGA 市场格局
| 厂商 | 代表型号 | LUT 规模 | 工艺 | 开源工具支持 | 特点 |
|---|---|---|---|---|---|
| 高云半导体(Gowin) | GW1N/GW2A/GW5A | 1K-138K | TSMC 55nm/22nm | ✅ apicula(成熟) | 价格低,Tang Nano 系列流行,开源生态最好 |
| 安路科技(Anlogic) | EG4/AL3N | 2K-32K | 40nm | ⚠️ 实验支持 | 主攻 AIoT,有 DSP/NPU IP |
| 紫光同创(Pango Micro) | PGL12G/PGL50H | 12K-1M | 28nm | ❌ 无开源 | 面向军工/高端,对标 Xilinx Artix/UltraScale |
| 复旦微电子(FMSH) | FMQL45T | 45K(Zynq 架构) | 28nm | ❌ 无开源 | PS+PL 架构,类 Zynq,面向工业控制 |
| 易灵思(Efinix) | Trion T8-T120 | 8K-120K | TSMC 40nm | ⚠️ 有 OSS 工具(Oxide) | 美国公司,但在中国市场有布局 |
开源生态的差距很明显: 高云是唯一有相对成熟开源工具链的国产 FPGA。其他厂商要么工具完全闭源,要么逆向工程还没人做。
对于想用开源工具的工程师,目前国产 FPGA 的唯一选择就是高云,具体来说是 GW1N/GW1NR/GW2A 系列(apicula 支持的范围)。
8. 验证步骤
# 1. 连接 Tang Nano 9K(USB-C)
lsusb | grep "CherryUSB\|CH552\|Future Technology"
# Bus 001 Device 005: ID 0403:6010 Future Technology Devices International...
# 2. 赋予 USB 权限(Linux)
sudo usermod -aG plugdev $USER
echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="0403", MODE="0666"' | sudo tee /etc/udev/rules.d/99-fpga.rules
sudo udevadm control --reload-rules
# 3. 综合 + 烧录
make prog
# 4. 验证 LED 闪烁
# 板上 6 个 LED 应以约 1.6Hz 频率一起闪
# 5. 验证 UART
minicom -D /dev/ttyUSB0 -b 115200
# 应收到: Hello Tang Nano 9K!
# 6. 验证 PSRAM
# 通过 UART 命令接口写入 0x12345678,读回验证
# 使用 uart_hello 改为 psram_test 模式(写-读-比较)
# 7. 验证 HDMI
# 接 HDMI 显示器,应显示 640x480 或 720p 彩条图案
🚧 避坑 #3:openFPGALoader 需要 libusb
在某些精简 Linux 系统(比如 WSL2、Alpine)上,openFPGALoader 找不到 FTDI 设备,报
libusb_init() failed。需要安装libusb-1.0-0-dev,并且 WSL2 还需要额外配置 USB passthrough(使用 usbipd-win)。Mac 用户通常没有这个问题,但如果报device not found,先检查brew install libusb是否安装。
9. 下一篇预告
下一篇脱离 RTL,进入更高抽象层——HLS(高层次综合)。 用开源工具 Bambu HLS 把 C 语言直接编译成 Verilog,和 Xilinx Vitis HLS 做对比。不花 License 费,能用吗?
→ 开源 FPGA 08:开源 HLS Bambu,C→RTL 不花钱
参考资料
| 资源 | 链接 / 说明 |
|---|---|
| apicula(高云逆向工程) | YosysHQ/apicula |
| Tang Nano 9K 原理图 | sipeed/TangNano-9K,Schematic v1.1 |
| GW1NR-9C 数据手册 | 高云半导体官网 DS-GW1NR-9C(含 PLL/IO 原语说明) |
| APS6404L PSRAM 手册 | AP Memory APS6404L-SQ-SQ Datasheet v2.0,2020 |
| OSER10 原语 | 高云半导体《用户指南 - 硬件设计》UG702,第 6 章 |
| nextpnr-gowin | YosysHQ/nextpnr gowin/ |
| Tang Nano 示例集 | sipeed/TangNano-9K-example |
| 中国 FPGA 市场报告 | 华经情报网《2024 年中国 FPGA 芯片行业研究报告》 |