PyHDL 是一個輕量級、現代化的硬體描述語言轉譯器,讓開發者使用優雅的 Python 語法描述數位電路,並編譯為可合成的 SystemVerilog 程式碼。
透過 Python 的動態特性(如靜態迴圈展開與參數化生成),PyHDL 大幅加速硬體設計流程,同時保持與業界標準 EDA 工具的完整相容性。
| 功能 | 說明 |
|---|---|
| Pythonic 語法 | 使用 Python class 定義硬體模組,使用 if/else 和 match/case 描述邏輯 |
| 靜態迴圈展開 | for i in range(N) 自動展開,生成重複的硬體結構 |
| 參數化設計 | 如同呼叫函數般傳入參數(如 width=16),自動生成對應寬度的模組 |
| 自動連線 | 實例化子模組時,自動推斷並宣告中間訊號 |
| 靜態分析 | 內建位元寬度推斷與陣列越界檢查,在轉譯階段發現錯誤 |
| 邏輯優化 | 巢狀 if-elif-else 自動扁平化為清晰的 SystemVerilog 結構 |
- 組合邏輯:生成
always_comb區塊 - 時序邏輯:生成具有邊緣敏感的
always_ff區塊 - 非同步重置:支援高電平有效(
posedge rst)與低電平有效(negedge rst_n) - 有限狀態機:
Enum類別搭配match/case生成typedef enum與unique case - 記憶體陣列:二維陣列宣告(
bit[DEPTH][WIDTH]) - 模組實例化:支援階層式設計與自動埠映射
- Python 3.8 或更高版本
colorama套件(用於彩色終端輸出)
# 複製專案
git clone https://github.com/tky-kevin/PyHDL.git
cd pyhdl
# 安裝相依套件
pip install colorama為了獲得 .phd 檔案的語法高亮和 Linter 支援,請在專案根目錄建立 .vscode/settings.json:
{
"files.associations": {
"*.phd": "python"
},
"python.analysis.extraPaths": [
"${workspaceFolder}/pyhdl"
]
}說明:
extraPaths指向pyhdl.py所在的目錄,讓 VS Code 能正確解析from pyhdl import *。
建立檔案 example.phd:
from pyhdl import *
class PriorityEncoder(Module):
# 參數定義
WIDTH = 8
CODE_W = 3
# 埠宣告
req = In(bit[WIDTH])
code = Out(bit[CODE_W])
valid = Out(bit)
# 預設值(防止產生 Latch)
code = 0
valid = 0
# 使用迴圈展開生成優先權邏輯
for i in range(WIDTH):
if req[i]:
code = i
valid = 1python pyhdl.py example.phd -o output/轉譯器產生 output/example.sv:
module PriorityEncoder (
input logic [7:0] req,
output logic [2:0] code,
output logic valid
);
always_comb begin
code = 3'd0;
valid = 1'd0;
if (req[0]) begin
code = 3'd0;
valid = 1'd1;
end
if (req[1]) begin
code = 3'd1;
valid = 1'd1;
end
// ... 迴圈展開至全部 8 位元
if (req[7]) begin
code = 3'd7;
valid = 1'd1;
end
end
endmodule硬體模組以繼承 Module 的 Python 類別定義:
from pyhdl import *
class MyModule(Module):
# 埠宣告
clk = In(bit)
data = In(bit[8])
result = Out(bit[16])
# 邏輯描述
result = data * data| 語法 | 說明 | 生成的 SystemVerilog |
|---|---|---|
In(bit) |
1 位元輸入 | input logic |
In(bit[8]) |
8 位元輸入 | input logic [7:0] |
Out(bit[16]) |
16 位元輸出 | output logic [15:0] |
# 1 位元內部訊號
temp = bit
# 多位元內部訊號
counter = bit[8]
# 二維陣列(記憶體)
mem = bit[16][8] # 16 個項目,每個 8 位元 → logic [7:0] mem [0:15]PyHDL 根據語境自動判斷生成 always_ff 或 always_comb。
# 同步邏輯(正緣觸發時脈)
if clk.posedge:
count = count + 1
# 非同步高電平重置
if clk.posedge or rst.posedge:
if rst:
count = 0
else:
count = count + 1
# 非同步低電平重置(工業標準)
if clk.posedge or rst_n.negedge:
if not rst_n:
count = 0
else:
count = count + 1生成的 SystemVerilog:
always_ff @(posedge clk or negedge rst_n) begin
if ((!rst_n)) begin
count <= 8'd0;
end else begin
count <= (count + 1);
end
end# 直接賦值(不在時脈邊緣內)
result = a + b
# 條件式組合邏輯
if sel:
out = in_a
else:
out = in_b生成的 SystemVerilog:
always_comb begin
if (sel) begin
out = in_a;
end else begin
out = in_b;
end
end| PyHDL | SystemVerilog | 說明 |
|---|---|---|
a + b |
(a + b) |
加法 |
a - b |
(a - b) |
減法 |
a * b |
(a * b) |
乘法 |
a / b |
(a / b) |
除法 |
a % b |
(a % b) |
取餘數 |
| PyHDL | SystemVerilog | 說明 |
|---|---|---|
a & b |
(a & b) |
位元 AND |
a | b |
(a | b) |
位元 OR |
a ^ b |
(a ^ b) |
位元 XOR |
~a |
(~a) |
位元 NOT |
| PyHDL | SystemVerilog | 說明 |
|---|---|---|
a and b |
(a && b) |
邏輯 AND |
a or b |
(a || b) |
邏輯 OR |
not a |
(!a) |
邏輯 NOT |
| PyHDL | SystemVerilog | 說明 |
|---|---|---|
a == b |
(a == b) |
等於 |
a != b |
(a != b) |
不等於 |
a < b |
(a < b) |
小於(無號數) |
a <= b |
(a <= b) |
小於等於 |
a > b |
(a > b) |
大於 |
a >= b |
(a >= b) |
大於等於 |
| PyHDL | SystemVerilog | 說明 |
|---|---|---|
a << n |
(a << n) |
左移 |
a >> n |
(a >> n) |
右移(邏輯) |
high_byte = data[15:8] # → data[15:8]
low_nibble = data[3:0] # → data[3:0]
msb = data[7] # → data[7]使用 Python 元組進行訊號串接:
result = (a, b) # → {a, b}
extended = (sign, data) # → {sign, data}
with_const = (sel, 0, a) # → {sel, 1'd0, a}靜態 for 迴圈在轉譯時自動展開:
WIDTH = 8
for i in range(WIDTH):
data_out[i] = data_in[WIDTH - 1 - i]生成的 SystemVerilog:
always_comb begin
data_out[0] = data_in[7];
data_out[1] = data_in[6];
data_out[2] = data_in[5];
// ... 繼續展開所有索引
data_out[7] = data_in[0];
end支援的 range() 變體:
range(N)— 0 到 N-1range(start, stop)— start 到 stop-1range(start, stop, step)— 自訂步進值
使用 Enum 定義狀態,使用 match/case 描述轉移:
from pyhdl import *
class TrafficLight(Module):
clk = In(bit)
rst_n = In(bit)
red = Out(bit)
yellow = Out(bit)
green = Out(bit)
class State(Enum):
RED = 0
GREEN = 1
YELLOW = 2
state = State
# 狀態轉移(時序邏輯)
if clk.posedge or rst_n.negedge:
if not rst_n:
state = State.RED
else:
match state:
case State.RED:
state = State.GREEN
case State.GREEN:
state = State.YELLOW
case State.YELLOW:
state = State.RED
# 輸出邏輯(組合邏輯)
red = 0
yellow = 0
green = 0
match state:
case State.RED:
red = 1
case State.GREEN:
green = 1
case State.YELLOW:
yellow = 1生成的 SystemVerilog:
typedef enum logic [1:0] {RED=2'd0, GREEN=2'd1, YELLOW=2'd2} State_t;
State_t state;
always_ff @(posedge clk or negedge rst_n) begin
if ((!rst_n)) begin
state <= RED;
end else begin
unique case (state)
RED: state <= GREEN;
GREEN: state <= YELLOW;
YELLOW: state <= RED;
default: begin
end
endcase
end
end
always_comb begin
red = 1'd0;
yellow = 1'd0;
green = 1'd0;
unique case (state)
RED: red = 1'd1;
GREEN: green = 1'd1;
YELLOW: yellow = 1'd1;
default: begin
end
endcase
end定義參數化模板並以特定數值實例化:
# 參數化加法器模板
class ParamAdder(Module):
a = In(bit[width])
b = In(bit[width])
sum = Out(bit[width + 1])
sum = a + b
# 頂層模組實例化
class Top(Module):
in_a = In(bit[8])
in_b = In(bit[8])
out_sum = Out(bit[9])
# 實例化 8 位元版本
u_add = ParamAdder(width=8)
u_add.a = in_a
u_add.b = in_b
out_sum = u_add.sum生成的 SystemVerilog:
module ParamAdder_width8 (
input logic [7:0] a,
input logic [7:0] b,
output logic [8:0] sum
);
always_comb begin
sum = (a + b);
end
endmodule
module Top (...);
logic [8:0] u_add_sum;
ParamAdder_width8 u_add (.a(in_a), .b(in_b), .sum(u_add_sum));
always_comb begin
out_sum = u_add_sum;
end
endmodulepyhdl/
├── pyhdl.py # 主入口與基礎類別(Module, In, Out, bit, Enum)
├── compiler.py # 命令列介面實作
├── transpiler.py # 核心轉譯器(AST 訪問器與程式碼生成器)
├── .vscode/ # VS Code 設定(可選)
├── test_code/ # 範例 .phd 原始碼
│ ├── demo_alu.phd
│ ├── demo_piano.phd
│ ├── demo_traffic_light.phd
│ └── ...
├── test_output/ # 生成的 .sv 檔案
├── README.md # 本文件
└── IMPROVEMENTS.md # 已知限制與未來改進項目
test_code/ 目錄包含完整的範例:
| 檔案 | 說明 |
|---|---|
demo_alu.phd |
8 位元 ALU,支援 8 種運算(ADD, SUB, AND, OR, XOR, NOR, SLTU, SLL) |
demo_piano.phd |
電子琴模組,含錄音/回放功能 |
demo_traffic_light.phd |
交通燈 FSM 控制器 |
01_basic_ports.phd |
埠宣告與寬度計算 |
02_operators.phd |
所有支援的運算符 |
03_slice_concat.phd |
位元切片與串接 |
04_comb_logic.phd |
組合邏輯模式 |
05_seq_logic.phd |
各種重置方式的時序邏輯 |
06_loop_unroll.phd |
迴圈展開示範 |
07_memory.phd |
RAM 與暫存器檔實作 |
08_fsm.phd |
有限狀態機範例 |
09_param_inst.phd |
參數化模組實例化 |
10_fifo.phd |
完整同步 FIFO 實作 |
詳細清單請參閱 IMPROVEMENTS.md。主要限制包括:
- 有號數類型:不支援
$signed()運算,所有比較皆為無號數 - 參數化切片:如
data[width-1:0]的表達式需要靜態求值 - 算術右移:僅支援邏輯右移(
>>) - 直接埠連接:子模組輸出需透過中間訊號
# 轉譯單一檔案
python pyhdl.py input.phd -o output_dir/
# 轉譯目錄內所有 .phd 檔案
python pyhdl.py src/ -o hdl/
# 啟用詳細輸出(顯示錯誤追蹤)
python pyhdl.py src/ -o hdl/ -vPyHDL 設計為可直接整合進 FPGA 開發流程。建議的目錄結構:
my_fpga_project/
├── pyhdl/ ← PyHDL 轉譯器(複製或 git submodule)
│ ├── pyhdl.py
│ ├── compiler.py
│ └── transpiler.py
├── src/ ← PyHDL 原始碼 (.phd)
│ ├── my_module.phd
│ ├── top.phd
│ └── ...
├── hdl/ ← 生成的 SystemVerilog (.sv)
│ ├── my_module.sv
│ ├── top.sv
│ └── ...
├── my_project.qpf ← Quartus 專案
└── my_project.qsf
使用方式:
cd my_fpga_project/pyhdl
python pyhdl.py # 預設:讀取 ../src,輸出至 ../hdl
python pyhdl.py -v # 詳細模式執行後,Quartus 可直接使用 hdl/ 目錄中的 .sv 檔案進行編譯。
將 PyHDL 作為 Git Submodule 加入專案,可方便追蹤更新:
首次加入專案:
cd my_fpga_project
git submodule add https://github.com/tky-kevin/PyHDL.git pyhdl
git commit -m "Add PyHDL as submodule"克隆包含 PyHDL 的專案:
# 方法一:克隆時一併初始化子模組
git clone --recursive https://github.com/yourname/my_fpga_project.git
# 方法二:已克隆後再初始化
git clone https://github.com/yourname/my_fpga_project.git
cd my_fpga_project
git submodule update --init更新 PyHDL 至最新版本:
cd my_fpga_project/pyhdl
git pull origin master
cd ..
git add pyhdl
git commit -m "Update PyHDL to latest version"Submodule 與直接複製的差異:Submodule 會保留與上游倉庫的連結,方便隨時獲取 PyHDL 的更新與修復。
歡迎貢獻!請參閱 IMPROVEMENTS.md 了解需要協助的項目。
本專案供教育用途使用。
PyHDL 的設計靈感來自 Chisel、SpinalHDL 和 Amaranth 等現代硬體描述框架,將 Python 的表達力帶入硬體設計領域。