PythonのプログラムからVerilogのRTLに変換できる高位合成環境が
あるようなので試しに使ってみました。
以下は、いろいろメモです。
polyphonyをインストールする。
高位合成実行。
% polyphony -vm -vd fact.py
で、Verilogファイルが生成できました。
結果的にはすごく簡単なのですが、参考にしたWebページのとおりにやっても
うまく動かなかったりで、途中過程は意外と苦労しました。。。
ちなみに、変換前後のコードは最後の方に貼り付けておきます。
可読性はあまり良くないですが、一応それらしい回路が出力されているようです。
あと、「Icarus Verilog」という、OSSのVerilogシミュレータも入れてみました。
Icarus Verilogをインストールする。
sudo apt install iverilog
sudo apt install gtkwave
SIM実行
iverilog -o sim -s test test.v polyphony_out.v
./sim
波形確認
gtkwave test.vcd &
でGUIが立ち上がるので、適当に操作して波形表示
ちなみに、今回はUbuntu(Jetson Nano)で試していますが、
Windows版も
こちらにあるようです(試していませんが)。
ひとまず簡単なプログラムであれば、Verilogに変換できることはわかったのですが、
深堀できていないので、使い物になるのかどうかはまだよくわかりません。
とりあえずNumPy とかの便利なライブラリは使えないようです(コンパイルでエラーになるので)。
あとは、ネットで検索しても、polyphonyについて詳しく説明しているページがあまりなさそうで、
以下、階乗計算プログラムの変換前後のコード例です。
Pythonプログラム
from polyphony import testbench
def fact(x):
y = 1
for i in range(1, x+1):
y = y * i
return y
@testbench
def test():
for i in range(0,10):
fact(i)
test()
Verilog RTL(本体)
module fact
(
input wire clk,
input wire rst,
input wire fact_ready,
input wire fact_accept,
output reg fact_valid,
input wire signed [31:0] fact_in_x,
output reg signed [31:0] fact_out_0
);
//localparams
localparam fact_b1_INIT = 0;
localparam fact_b1_S0 = 1;
localparam fact_b1_S1 = 2;
localparam fact_forelse5_FINISH = 3;
localparam fact_L1_fortest2_S0 = 4;
localparam fact_L1_forbody3_S0 = 5;
localparam fact_L1_forbody3_S1 = 6;
//signals:
wire c71;
reg [2:0] fact_state;
wire signed [31:0] i3;
wire signed [31:0] t65;
wire signed [31:0] y3;
reg signed [31:0] i2;
reg signed [31:0] x;
reg signed [31:0] y2;
//combinations:
assign c71 = (i2 < t65);
assign i3 = (i2 + 1);
assign t65 = (x + 1);
assign y3 = (y2 * i2);
always @(posedge clk) begin
if (rst) begin
fact_out_0 <= 0;
i2 <= 0;
x <= 0;
y2 <= 0;
fact_state <= fact_b1_INIT;
end else begin //if (rst)
case(fact_state)
fact_b1_INIT: begin
fact_valid <= 0;
if (fact_ready == 1) begin
x <= fact_in_x;
i2 <= 1;
y2 <= 1;
fact_state <= fact_b1_S1;
end
end
fact_b1_S1: begin
/* t65 <= (x + 1); */
fact_state <= fact_L1_fortest2_S0;
end
fact_L1_fortest2_S0: begin
/* c71 <= (i2 < t65); */
if (c71) begin
/* y3 <= (y2 * i2); */
/* i3 <= (i2 + 1); */
i2 <= i3;
y2 <= y3;
fact_state <= fact_L1_fortest2_S0;
end else begin
fact_valid <= 1;
if (fact_accept == 1) begin
fact_state <= fact_b1_INIT;
end
fact_out_0 <= y2;
end
end
endcase
end
end
endmodule
Verilog RTL(テストベンチ)
module test
(
);
//localparams
localparam CLK_PERIOD = 10;
localparam CLK_HALF_PERIOD = 5;
localparam INITIAL_RESET_SPAN = 100;
localparam test_b1_INIT = 0;
localparam test_b1_S1 = 1;
localparam test_forelse5_S0 = 2;
localparam test_forelse5_FINISH = 3;
localparam test_L1_fortest2_S0 = 4;
localparam test_L1_forbody3_S0 = 5;
localparam test_L1_forbody3_S1 = 6;
localparam test_L1_forbody3_S2 = 7;
localparam test_L1_forbody3_S3 = 8;
localparam test_L1_forbody3_S4 = 9;
localparam test_L1_forbody3_S5 = 10;
localparam test_L1_forbody3_S6 = 11;
localparam test_L1_forbody3_S7 = 12;
//signals:
wire c69;
wire fact_0_valid;
reg clk;
reg fact_0_accept;
reg fact_0_ready;
reg rst;
reg [3:0] test_state;
reg signed [31:0] i2;
reg signed [31:0] i3;
//signals: in_x
reg [31:0] fact_0_in_x;
//signals: out_0
wire [31:0] fact_0_out_0;
//combinations:
assign c69 = (i2 < 10);
//sub modules
//fact_0 instance
fact fact_0(
.clk(clk),
.rst(rst),
.fact_ready(fact_0_ready),
.fact_accept(fact_0_accept),
.fact_valid(fact_0_valid),
.fact_in_x(fact_0_in_x),
.fact_out_0(fact_0_out_0)
);
initial begin
$monitor("%5t:fact_0_in_x=%4d, fact_0_out_0=%4d", $time, fact_0_in_x, fact_0_out_0);
$dumpfile("test.vcd");
$dumpvars(0, test);
end
initial begin
clk = 0;
#CLK_HALF_PERIOD
forever #CLK_HALF_PERIOD clk = ~clk;
end
initial begin
rst <= 1;
#INITIAL_RESET_SPAN
rst <= 0;
end
always @(posedge clk) begin
if (rst) begin
fact_0_accept <= 0;
fact_0_ready <= 0;
i2 <= 0;
i3 <= 0;
test_state <= test_b1_INIT;
end else begin //if (rst)
case(test_state)
test_b1_INIT: begin
i2 <= 0;
test_state <= test_L1_fortest2_S0;
end
test_forelse5_FINISH: begin
$display("%5t:finish", $time);
$finish();
end
test_L1_fortest2_S0: begin
/* c69 <= (i2 < 10); */
if (c69) begin
fact_0_ready <= 1;
fact_0_in_x <= i2;
test_state <= test_L1_forbody3_S1;
end else begin
test_state <= test_forelse5_FINISH;
end
end
test_L1_forbody3_S1: begin
fact_0_ready <= 0;
test_state <= test_L1_forbody3_S2;
end
test_L1_forbody3_S2: begin
if (fact_0_valid == 1) begin
fact_0_accept <= 1;
test_state <= test_L1_forbody3_S4;
end
end
test_L1_forbody3_S4: begin
fact_0_accept <= 0;
test_state <= test_L1_forbody3_S5;
end
test_L1_forbody3_S5: begin
i3 <= (i2 + 1);
test_state <= test_L1_forbody3_S6;
end
test_L1_forbody3_S6: begin
i2 <= i3;
test_state <= test_L1_fortest2_S0;
end
endcase
end
end
endmodule