# Pyrilog
一个基于 Python 上下文管理器的 SystemVerilog 代码生成工具。使用简洁的 Python 语法生成结构化的硬件描述语言代码。
## 特性
- 🏗️ **层次化设计**: 基于上下文管理器的嵌套块结构
- 🎯 **简洁 API**: 使用 `v_` 前缀的短别名,代码更加简洁
- 🔄 **case 语句支持**: 支持单语句和多语句两种 case 语句写法
- 🧩 **模块化**: 支持参数化模块、实例化、多维数组等
- 🚀 **现代语法**: 生成 SystemVerilog `always_ff`、`always_comb` 语法
## 安装
```bash
pip install pyrilog
```
## 快速开始
### 基本模块定义
```python
from pyrilog import *
with v_gen() as gen:
with v_module("counter"):
# 参数定义
v_param("WIDTH", "8")
# 端口定义
v_input("clk")
v_input("rst_n")
v_input("data_in", "WIDTH")
v_output("count", "WIDTH", None, "reg")
print(gen.generate())
```
生成的 SystemVerilog 代码:
```systemverilog
module counter #(
parameter WIDTH = 8
) (
input clk,
input rst_n,
input [WIDTH-1:0] data_in,
output reg [WIDTH-1:0] count
);
endmodule
```
### 时序逻辑 - 计数器
```python
from pyrilog import *
with v_gen() as gen:
with v_module("counter"):
v_param("WIDTH", "8")
v_input("clk")
v_input("rst_n")
v_output("count", "WIDTH", None, "reg")
# SystemVerilog always_ff 块
with v_always_ff("clk", "rst_n"):
with v_if("!rst_n"):
v_body("count <= '0;")
with v_else():
v_body("count <= count + 1'b1;")
with open("counter.sv", "w") as f:
f.write(gen.generate())
```
### Case 语句 - ALU 设计
Pyrilog 支持两种 case 语句写法:
#### 1. 单语句模式
```python
from pyrilog import *
with v_gen() as gen:
with v_module("simple_alu"):
v_input("opcode", 3)
v_input("a", 8)
v_input("b", 8)
v_output("result", 8, None, "reg")
with v_always_comb():
with v_case("opcode"):
v_case_item("3'b000", "result = a + b;")
v_case_item("3'b001", "result = a - b;")
v_case_item("3'b010", "result = a & b;")
v_case_default("result = 8'h00;")
print(gen.generate())
```
#### 2. 多语句模式(使用上下文管理器)
```python
from pyrilog import *
with v_gen() as gen:
with v_module("complex_alu"):
v_input("clk")
v_input("rst_n")
v_input("opcode", 4)
v_input("a", 16)
v_input("b", 16)
v_output("result", 16, None, "reg")
v_output("valid", 1, None, "reg")
v_output("overflow", 1, None, "reg")
with v_always_ff("clk", "rst_n"):
with v_if("!rst_n"):
v_body("result <= 16'h0000;")
v_body("valid <= 1'b0;")
v_body("overflow <= 1'b0;")
with v_else():
with v_case("opcode"):
# 单语句 case
v_case_item("4'b0000", "result <= a + b;")
v_case_item("4'b0001", "result <= a - b;")
# 多语句 case,使用 with 上下文管理器
with v_case_item("4'b0010"): # 位与运算,带有效信号
v_body("result <= a & b;")
v_body("valid <= 1'b1;")
v_body("overflow <= 1'b0;")
with v_case_item("4'b0011"): # 位或运算,带溢出检测
v_body("result <= a | b;")
v_body("valid <= 1'b1;")
v_body("overflow <= (a[15] | b[15]) & !result[15];")
# 默认情况
v_case_default("result <= 16'h0000;")
v_body("valid <= 1'b1;") # case 外的公共语句
print(gen.generate())
```
生成的 SystemVerilog 代码:
```systemverilog
module complex_alu (
input clk,
input rst_n,
input [3:0] opcode,
input [15:0] a,
input [15:0] b,
output reg [15:0] result,
output reg valid,
output reg overflow
);
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
result <= 16'h0000;
valid <= 1'b0;
overflow <= 1'b0;
end
else begin
case (opcode)
4'b0000: result <= a + b;
4'b0001: result <= a - b;
4'b0010: begin
result <= a & b;
valid <= 1'b1;
overflow <= 1'b0;
end
4'b0011: begin
result <= a | b;
valid <= 1'b1;
overflow <= (a[15] | b[15]) & !result[15];
end
default: result <= 16'h0000;
endcase
valid <= 1'b1;
end
end
endmodule
```
### 多维数组支持
```python
from pyrilog import *
with v_gen() as gen:
with v_module("memory_array"):
v_input("clk")
v_input("addr", 8)
v_input("wr_data", 32)
v_output("rd_data", 32, None, "reg")
# 创建二维内存数组:32位宽,256x4 的数组
v_reg("memory", 32, [256, 4])
# 一维数组:32位宽,16个元素
v_wire("buffer", 32, 16)
print(gen.generate())
```
### 模块实例化
```python
from pyrilog import *
with v_gen() as gen:
with v_module("cpu_top"):
v_input("clk")
v_input("rst_n")
v_input("instruction", 32)
v_output("result", 32, None, "wire")
# 实例化 ALU 模块(完整参数)
v_inst("complex_alu", "alu_inst",
{"WIDTH": "32"}, # 参数
{ # 端口连接
"clk": "clk",
"rst_n": "rst_n",
"opcode": "instruction[3:0]",
"a": "instruction[31:16]",
"b": "instruction[15:4]",
"result": "result"
})
# 简化实例化(利用默认参数)
v_inst("simple_counter", "cnt_inst") # 无参数、无端口连接
# 部分参数实例化
v_inst("timer", "timer_inst", ports={"clk": "clk", "rst_n": "rst_n"})
print(gen.generate())
```
## API 参考
### 核心块结构
- `v_gen()`: 顶层生成器
- `v_module(name)`: 模块定义
- `v_always_ff(clk, rst=None)`: always_ff 时序逻辑块
- `v_always_comb()`: always_comb 组合逻辑块
- `v_if(condition)`: 条件语句
- `v_else()`: else 语句
- `v_case(expression)`: case 语句
### Case 语句
- `v_case_item(value, statement=None)`: case 项
- 单语句:`v_case_item("3'b001", "result = a + b;")`
- 多语句:`with v_case_item("3'b001"): ...`
- `v_case_default(statement=None)`: 默认 case
### 端口和变量
- `v_input(name, width=1, dimensions=None, var_type="")`: 输入端口
- `v_output(name, width=1, dimensions=None, var_type="")`: 输出端口
- `v_inout(name, width=1, dimensions=None, var_type="")`: 双向端口
- `v_wire(name, width=1, dimensions=None)`: wire 信号
- `v_reg(name, width=1, dimensions=None)`: reg 信号
### 其他功能
- `v_param(name, value)`: 参数定义
- `v_assign(lhs, rhs)`: assign 语句
- `v_inst(module_name, inst_name, params, ports)`: 模块实例化
- `v_body(code)`: 添加原始代码行
## 维度格式
支持多种维度表示方法:
```python
# 位宽
v_reg("data", 8) # [7:0] data
v_reg("data", "WIDTH") # [WIDTH-1:0] data
# 一维数组
v_reg("mem", 8, 16) # [7:0] mem[15:0]
v_reg("mem", 8, [16]) # [7:0] mem[15:0]
# 多维数组
v_reg("mem", 8, [16, 4]) # [7:0] mem[15:0][3:0]
```
## 许可证
本项目采用 MIT 许可证。详情请见 [LICENSE](LICENSE) 文件。
Raw data
{
"_id": null,
"home_page": null,
"name": "pyrilog",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "code-generation, hardware, hdl, systemverilog, verilog",
"author": null,
"author_email": "NightWatcher <hitszzzf@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/f5/25/f16df8da7c4970bb55848b35c691b923a7cfa67aadade591007cd4044435/pyrilog-0.2.4.tar.gz",
"platform": null,
"description": "# Pyrilog\n\n\u4e00\u4e2a\u57fa\u4e8e Python \u4e0a\u4e0b\u6587\u7ba1\u7406\u5668\u7684 SystemVerilog \u4ee3\u7801\u751f\u6210\u5de5\u5177\u3002\u4f7f\u7528\u7b80\u6d01\u7684 Python \u8bed\u6cd5\u751f\u6210\u7ed3\u6784\u5316\u7684\u786c\u4ef6\u63cf\u8ff0\u8bed\u8a00\u4ee3\u7801\u3002\n\n## \u7279\u6027\n\n- \ud83c\udfd7\ufe0f **\u5c42\u6b21\u5316\u8bbe\u8ba1**: \u57fa\u4e8e\u4e0a\u4e0b\u6587\u7ba1\u7406\u5668\u7684\u5d4c\u5957\u5757\u7ed3\u6784\n- \ud83c\udfaf **\u7b80\u6d01 API**: \u4f7f\u7528 `v_` \u524d\u7f00\u7684\u77ed\u522b\u540d\uff0c\u4ee3\u7801\u66f4\u52a0\u7b80\u6d01\n- \ud83d\udd04 **case \u8bed\u53e5\u652f\u6301**: \u652f\u6301\u5355\u8bed\u53e5\u548c\u591a\u8bed\u53e5\u4e24\u79cd case \u8bed\u53e5\u5199\u6cd5\n- \ud83e\udde9 **\u6a21\u5757\u5316**: \u652f\u6301\u53c2\u6570\u5316\u6a21\u5757\u3001\u5b9e\u4f8b\u5316\u3001\u591a\u7ef4\u6570\u7ec4\u7b49\n- \ud83d\ude80 **\u73b0\u4ee3\u8bed\u6cd5**: \u751f\u6210 SystemVerilog `always_ff`\u3001`always_comb` \u8bed\u6cd5\n\n## \u5b89\u88c5\n\n```bash\npip install pyrilog\n```\n\n## \u5feb\u901f\u5f00\u59cb\n\n### \u57fa\u672c\u6a21\u5757\u5b9a\u4e49\n\n```python\nfrom pyrilog import *\n\nwith v_gen() as gen:\n with v_module(\"counter\"):\n # \u53c2\u6570\u5b9a\u4e49\n v_param(\"WIDTH\", \"8\")\n \n # \u7aef\u53e3\u5b9a\u4e49\n v_input(\"clk\")\n v_input(\"rst_n\") \n v_input(\"data_in\", \"WIDTH\")\n v_output(\"count\", \"WIDTH\", None, \"reg\")\n\nprint(gen.generate())\n```\n\n\u751f\u6210\u7684 SystemVerilog \u4ee3\u7801\uff1a\n\n```systemverilog\nmodule counter #(\nparameter WIDTH = 8\n) (\ninput clk,\ninput rst_n,\ninput [WIDTH-1:0] data_in,\noutput reg [WIDTH-1:0] count\n);\nendmodule\n```\n\n### \u65f6\u5e8f\u903b\u8f91 - \u8ba1\u6570\u5668\n\n```python\nfrom pyrilog import *\n\nwith v_gen() as gen:\n with v_module(\"counter\"):\n v_param(\"WIDTH\", \"8\")\n v_input(\"clk\")\n v_input(\"rst_n\")\n v_output(\"count\", \"WIDTH\", None, \"reg\")\n \n # SystemVerilog always_ff \u5757 \n with v_always_ff(\"clk\", \"rst_n\"):\n with v_if(\"!rst_n\"):\n v_body(\"count <= '0;\")\n with v_else():\n v_body(\"count <= count + 1'b1;\")\n\nwith open(\"counter.sv\", \"w\") as f:\n f.write(gen.generate())\n```\n\n### Case \u8bed\u53e5 - ALU \u8bbe\u8ba1\n\nPyrilog \u652f\u6301\u4e24\u79cd case \u8bed\u53e5\u5199\u6cd5\uff1a\n\n#### 1. \u5355\u8bed\u53e5\u6a21\u5f0f\n\n```python\nfrom pyrilog import *\n\nwith v_gen() as gen:\n with v_module(\"simple_alu\"):\n v_input(\"opcode\", 3)\n v_input(\"a\", 8)\n v_input(\"b\", 8) \n v_output(\"result\", 8, None, \"reg\")\n \n with v_always_comb():\n with v_case(\"opcode\"):\n v_case_item(\"3'b000\", \"result = a + b;\")\n v_case_item(\"3'b001\", \"result = a - b;\")\n v_case_item(\"3'b010\", \"result = a & b;\")\n v_case_default(\"result = 8'h00;\")\n\nprint(gen.generate())\n```\n\n#### 2. \u591a\u8bed\u53e5\u6a21\u5f0f\uff08\u4f7f\u7528\u4e0a\u4e0b\u6587\u7ba1\u7406\u5668\uff09\n\n```python\nfrom pyrilog import *\n\nwith v_gen() as gen:\n with v_module(\"complex_alu\"):\n v_input(\"clk\")\n v_input(\"rst_n\")\n v_input(\"opcode\", 4)\n v_input(\"a\", 16)\n v_input(\"b\", 16)\n v_output(\"result\", 16, None, \"reg\")\n v_output(\"valid\", 1, None, \"reg\")\n v_output(\"overflow\", 1, None, \"reg\")\n \n with v_always_ff(\"clk\", \"rst_n\"):\n with v_if(\"!rst_n\"):\n v_body(\"result <= 16'h0000;\")\n v_body(\"valid <= 1'b0;\")\n v_body(\"overflow <= 1'b0;\")\n with v_else():\n with v_case(\"opcode\"):\n # \u5355\u8bed\u53e5 case\n v_case_item(\"4'b0000\", \"result <= a + b;\")\n v_case_item(\"4'b0001\", \"result <= a - b;\")\n \n # \u591a\u8bed\u53e5 case\uff0c\u4f7f\u7528 with \u4e0a\u4e0b\u6587\u7ba1\u7406\u5668\n with v_case_item(\"4'b0010\"): # \u4f4d\u4e0e\u8fd0\u7b97\uff0c\u5e26\u6709\u6548\u4fe1\u53f7\n v_body(\"result <= a & b;\")\n v_body(\"valid <= 1'b1;\")\n v_body(\"overflow <= 1'b0;\")\n \n with v_case_item(\"4'b0011\"): # \u4f4d\u6216\u8fd0\u7b97\uff0c\u5e26\u6ea2\u51fa\u68c0\u6d4b\n v_body(\"result <= a | b;\")\n v_body(\"valid <= 1'b1;\")\n v_body(\"overflow <= (a[15] | b[15]) & !result[15];\")\n \n # \u9ed8\u8ba4\u60c5\u51b5\n v_case_default(\"result <= 16'h0000;\")\n \n v_body(\"valid <= 1'b1;\") # case \u5916\u7684\u516c\u5171\u8bed\u53e5\n\nprint(gen.generate())\n```\n\n\u751f\u6210\u7684 SystemVerilog \u4ee3\u7801\uff1a\n\n```systemverilog\nmodule complex_alu (\ninput clk,\ninput rst_n,\ninput [3:0] opcode,\ninput [15:0] a,\ninput [15:0] b,\noutput reg [15:0] result,\noutput reg valid,\noutput reg overflow\n);\nalways_ff @(posedge clk, negedge rst_n) begin\nif (!rst_n) begin\nresult <= 16'h0000;\nvalid <= 1'b0;\noverflow <= 1'b0;\nend\nelse begin\ncase (opcode)\n4'b0000: result <= a + b;\n4'b0001: result <= a - b;\n4'b0010: begin\nresult <= a & b;\nvalid <= 1'b1;\noverflow <= 1'b0;\nend\n4'b0011: begin\nresult <= a | b;\nvalid <= 1'b1;\noverflow <= (a[15] | b[15]) & !result[15];\nend\ndefault: result <= 16'h0000;\nendcase\nvalid <= 1'b1;\nend\nend\nendmodule\n```\n\n### \u591a\u7ef4\u6570\u7ec4\u652f\u6301\n\n```python\nfrom pyrilog import *\n\nwith v_gen() as gen:\n with v_module(\"memory_array\"):\n v_input(\"clk\")\n v_input(\"addr\", 8)\n v_input(\"wr_data\", 32)\n v_output(\"rd_data\", 32, None, \"reg\")\n \n # \u521b\u5efa\u4e8c\u7ef4\u5185\u5b58\u6570\u7ec4\uff1a32\u4f4d\u5bbd\uff0c256x4 \u7684\u6570\u7ec4\n v_reg(\"memory\", 32, [256, 4])\n \n # \u4e00\u7ef4\u6570\u7ec4\uff1a32\u4f4d\u5bbd\uff0c16\u4e2a\u5143\u7d20\n v_wire(\"buffer\", 32, 16)\n\nprint(gen.generate())\n```\n\n### \u6a21\u5757\u5b9e\u4f8b\u5316\n\n```python\nfrom pyrilog import *\n\nwith v_gen() as gen:\n with v_module(\"cpu_top\"):\n v_input(\"clk\")\n v_input(\"rst_n\")\n v_input(\"instruction\", 32)\n v_output(\"result\", 32, None, \"wire\")\n \n # \u5b9e\u4f8b\u5316 ALU \u6a21\u5757\uff08\u5b8c\u6574\u53c2\u6570\uff09\n v_inst(\"complex_alu\", \"alu_inst\", \n {\"WIDTH\": \"32\"}, # \u53c2\u6570\n { # \u7aef\u53e3\u8fde\u63a5\n \"clk\": \"clk\",\n \"rst_n\": \"rst_n\", \n \"opcode\": \"instruction[3:0]\",\n \"a\": \"instruction[31:16]\",\n \"b\": \"instruction[15:4]\",\n \"result\": \"result\"\n })\n \n # \u7b80\u5316\u5b9e\u4f8b\u5316\uff08\u5229\u7528\u9ed8\u8ba4\u53c2\u6570\uff09\n v_inst(\"simple_counter\", \"cnt_inst\") # \u65e0\u53c2\u6570\u3001\u65e0\u7aef\u53e3\u8fde\u63a5\n \n # \u90e8\u5206\u53c2\u6570\u5b9e\u4f8b\u5316\n v_inst(\"timer\", \"timer_inst\", ports={\"clk\": \"clk\", \"rst_n\": \"rst_n\"})\n\nprint(gen.generate())\n```\n\n## API \u53c2\u8003\n\n### \u6838\u5fc3\u5757\u7ed3\u6784\n- `v_gen()`: \u9876\u5c42\u751f\u6210\u5668\n- `v_module(name)`: \u6a21\u5757\u5b9a\u4e49\n- `v_always_ff(clk, rst=None)`: always_ff \u65f6\u5e8f\u903b\u8f91\u5757 \n- `v_always_comb()`: always_comb \u7ec4\u5408\u903b\u8f91\u5757\n- `v_if(condition)`: \u6761\u4ef6\u8bed\u53e5\n- `v_else()`: else \u8bed\u53e5\n- `v_case(expression)`: case \u8bed\u53e5\n\n### Case \u8bed\u53e5\n- `v_case_item(value, statement=None)`: case \u9879\n - \u5355\u8bed\u53e5\uff1a`v_case_item(\"3'b001\", \"result = a + b;\")`\n - \u591a\u8bed\u53e5\uff1a`with v_case_item(\"3'b001\"): ...`\n- `v_case_default(statement=None)`: \u9ed8\u8ba4 case\n\n### \u7aef\u53e3\u548c\u53d8\u91cf\n- `v_input(name, width=1, dimensions=None, var_type=\"\")`: \u8f93\u5165\u7aef\u53e3\n- `v_output(name, width=1, dimensions=None, var_type=\"\")`: \u8f93\u51fa\u7aef\u53e3 \n- `v_inout(name, width=1, dimensions=None, var_type=\"\")`: \u53cc\u5411\u7aef\u53e3\n- `v_wire(name, width=1, dimensions=None)`: wire \u4fe1\u53f7\n- `v_reg(name, width=1, dimensions=None)`: reg \u4fe1\u53f7\n\n### \u5176\u4ed6\u529f\u80fd\n- `v_param(name, value)`: \u53c2\u6570\u5b9a\u4e49\n- `v_assign(lhs, rhs)`: assign \u8bed\u53e5\n- `v_inst(module_name, inst_name, params, ports)`: \u6a21\u5757\u5b9e\u4f8b\u5316\n- `v_body(code)`: \u6dfb\u52a0\u539f\u59cb\u4ee3\u7801\u884c\n\n## \u7ef4\u5ea6\u683c\u5f0f\n\n\u652f\u6301\u591a\u79cd\u7ef4\u5ea6\u8868\u793a\u65b9\u6cd5\uff1a\n\n```python\n# \u4f4d\u5bbd\nv_reg(\"data\", 8) # [7:0] data\nv_reg(\"data\", \"WIDTH\") # [WIDTH-1:0] data\n\n# \u4e00\u7ef4\u6570\u7ec4\nv_reg(\"mem\", 8, 16) # [7:0] mem[15:0] \nv_reg(\"mem\", 8, [16]) # [7:0] mem[15:0]\n\n# \u591a\u7ef4\u6570\u7ec4 \nv_reg(\"mem\", 8, [16, 4]) # [7:0] mem[15:0][3:0]\n```\n\n## \u8bb8\u53ef\u8bc1\n\n\u672c\u9879\u76ee\u91c7\u7528 MIT \u8bb8\u53ef\u8bc1\u3002\u8be6\u60c5\u8bf7\u89c1 [LICENSE](LICENSE) \u6587\u4ef6\u3002",
"bugtrack_url": null,
"license": "MIT",
"summary": "A Python-based SystemVerilog code generator using context managers",
"version": "0.2.4",
"project_urls": {
"Homepage": "https://github.com/nightwatcher/pyrilog",
"Issues": "https://github.com/nightwatcher/pyrilog/issues",
"Repository": "https://github.com/nightwatcher/pyrilog.git"
},
"split_keywords": [
"code-generation",
" hardware",
" hdl",
" systemverilog",
" verilog"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "81842b152ddc74efaaddfb4d0a587e735d34d6aadf86b5ec9cceb0e42489eb98",
"md5": "802fc558a911606124e0a3d3a0ff8e2b",
"sha256": "82cdb3554b9ba917dfcde191bfd3f19ecceb969a24b70a2d0d8481c79b7105f8"
},
"downloads": -1,
"filename": "pyrilog-0.2.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "802fc558a911606124e0a3d3a0ff8e2b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 6917,
"upload_time": "2025-09-09T18:02:30",
"upload_time_iso_8601": "2025-09-09T18:02:30.347918Z",
"url": "https://files.pythonhosted.org/packages/81/84/2b152ddc74efaaddfb4d0a587e735d34d6aadf86b5ec9cceb0e42489eb98/pyrilog-0.2.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "f525f16df8da7c4970bb55848b35c691b923a7cfa67aadade591007cd4044435",
"md5": "1d04f39bc5d0b4584474a6b778990614",
"sha256": "37f8588865cbcf31fc478be2c9270f3729a9b8cf78245b38c9e1f735de140f70"
},
"downloads": -1,
"filename": "pyrilog-0.2.4.tar.gz",
"has_sig": false,
"md5_digest": "1d04f39bc5d0b4584474a6b778990614",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 25394,
"upload_time": "2025-09-09T18:02:31",
"upload_time_iso_8601": "2025-09-09T18:02:31.957204Z",
"url": "https://files.pythonhosted.org/packages/f5/25/f16df8da7c4970bb55848b35c691b923a7cfa67aadade591007cd4044435/pyrilog-0.2.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-09 18:02:31",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "nightwatcher",
"github_project": "pyrilog",
"github_not_found": true,
"lcname": "pyrilog"
}