ふんがのブログ

高位合成ツールCatapultを使ってみる

2026-01-19 19:41:28
2026-01-19 20:18:02
目次

Catapultは、MentorからSiemensの製品となった高位合成ツールで、CやC++を入力として、ASIC設計、FPGA設計のネットリストまでを生成する。VDECに参加していれば、他のツール同様に利用することができる。FPGAのVitis_HLSは相当使いこんだし、日本の誇るCyberWorkBenchも少しは使った経験があるが、Catapultは、相当手ごわいツールで、忘れるといけないので、使い方をメモしておく。

ライブラリのディレクトリ構造

どのサーバにインストールするかによるが、現在2024.1_1をインストールする場合、/tool/Mentor/Catapult/2024.1_1/Mgc_homeというディレクトリの下に、バイナリやライブラリがすべて置かれる。pkgs/siflibの下にインタフェースのライブラリや、合成に必要なtechlibと呼ばれるライブラリが入っている。現状で利用可能なのはnangate45nmのもので、/tool/Mentor/Catapult/2024.1_1/Mgc_home/pkgs/siflibs/nangateの下にある。

Catapultはこのライブラリを指定しないとCやC++からRTLへの合成も行ってくれない(ChatGPTによるとやる方法もあるそうだが、何をやってもダメだった)。ちなみにnangate以外のライブラリは、saedとccs_fpgaで前者はSynopsysのStandard Cell Library、後者はFPGA関連らしいが詳しくは知らない

起動方法

binにpathを通しておくか、dlabならば起動コマンドasb0を使い

asb0 /tool/settings/csh-Catapult-2024.1_1 -shell -file goto.tcl

と打ち込む。 ここで-shellはGUIを使わないコマンド、-fileはtclのスクリプト(この場合goto.tcl)を指定する。-shellにするとGUIは一度上がってtclを実行して終了してしまう。GUIで何かやりたいときはこのオプションをつけないようにする。ちなみにGUIは相当使いにくいので、-shellを使わなくてもtclを打ち込んで使うのが普通らしい

tclコマンド

solution new -state initial

solution options defaults

solution options set /OnTheFly/VthAttributeType cell_lib

solution options set /Input/TargetPlatform x86_64

solution options set /Output/OutputVHDL false

solution options set /Output/GenerateCycleNetlist false

solution file add /data/design/usr/hunga/catapult/design.c -type C++

最初にslutionコマンドで、環境を設定する。ここではdesign.c (トップ関数はadd_top)を指定している。

directive set -DESIGN_GOAL area

directive set -SPECULATE true

directive set -MERGEABLE true

directive set -REGISTER_THRESHOLD 512

directive set -MEM_MAP_THRESHOLD 128

directive set -LOGIC_OPT false

directive set -FSM_ENCODING none

directive set -FSM_BINARY_ENCODING_THRESHOLD 64

directive set -REG_MAX_FANOUT 0

directive set -NO_X_ASSIGNMENTS true

directive set -SAFE_FSM false

directive set -REGISTER_SHARING_MAX_WIDTH_DIFFERENCE 8

directive set -REGISTER_SHARING_LIMIT 0

directive set -ASSIGN_OVERHEAD 0

directive set -TIMING_CHECKS true

directive set -MUXPATH true

directive set -REALLOC true

directive set -UNROLL no

directive set -IO_MODE super

directive set -CHAN_IO_PROTOCOL use_library

directive set -ARRAY_SIZE 4096

directive set -IDLE_SIGNAL {}

directive set -STALL_FLAG_SV off

directive set -STALL_FLAG false

directive set -TRANSACTION_DONE_SIGNAL true

directive set -DONE_FLAG {}

directive set -READY_FLAG {}

directive set -START_FLAG {}

directive set -TRANSACTION_SYNC ready

directive set -RESET_CLEARS_ALL_REGS use_library

directive set -CLOCK_OVERHEAD 20.000000

directive set -ON_THE_FLY_PROTOTYPING false

directive set -OPT_CONST_MULTS use_library

directive set -CHARACTERIZE_ROM false

directive set -PROTOTYPE_ROM true

directive set -ROM_THRESHOLD 512

directive set -CLUSTER_ADDTREE_IN_WIDTH_THRESHOLD 0

directive set -CLUSTER_ADDTREE_IN_COUNT_THRESHOLD 0

directive set -CLUSTER_OPT_CONSTANT_INPUTS true

directive set -CLUSTER_RTL_SYN false

directive set -CLUSTER_FAST_MODE false

directive set -CLUSTER_TYPE combinational

directive set -PROTOTYPING_ENGINE oasys

directive set -PIPELINE_RAMP_UP true

次に合成時のコマンドdirectiveをセットする。上記すべてが必要とは思えない。。。

go new

go analyze

solution design set add_top -top

go compile

solution library add nangate-45nm_beh -- -rtlsyntool DesignCompiler -vendor Nangate -technology 045nm

go libraries

directive set -CLOCKS {clk {-CLOCK_PERIOD 20.0 -CLOCK_EDGE rising -CLOCK_UNCERTAINTY 0.0 -CLOCK_HIGH_TIME 10.0 -RESET_SYNC_NAME rst_n -RESET_ASYNC_NAME arst_n -RESET_KIND sync -RESET_SYNC_ACTIVE low -RESET_ASYNC_ACTIVE low -ENABLE_ACTIVE high}}

go assembly

go extract

高位合成動作は、go analyse, go compile, go libraries, go assembly, go extractである。(ほかにgo scheduleもあるが使ってない)go extractがうまくいくと、Catapult_X/add_top.v1/というディレクトリの下にrtl.vが出力される。

高位合成

例に用いたC記述は恐ろしく単純な

#include <stdint.h>

int32_t add_top(int32_t a, int32_t b) {

return a + b;

}

である。これがrtl.vとなると以下の長大なものとなる。

module add_top_core_core_fsm (

clk, rst_n, fsm_output

);

input clk;

input rst_n;

output [1:0] fsm_output;

reg [1:0] fsm_output;

// FSM State Type Declaration for add_top_core_core_fsm_1

parameter

main_C_0 = 1'd0,

main_C_1 = 1'd1;

reg state_var;

reg state_var_NS;

// Interconnect Declarations for Component Instantiations

always @(*)

begin : add_top_core_core_fsm_1

case (state_var)

main_C_1 : begin

fsm_output = 2'b10;

state_var_NS = main_C_0;

end

// main_C_0

default : begin

fsm_output = 2'b01;

state_var_NS = main_C_1;

end

endcase

end

always @(posedge clk) begin

if ( ~ rst_n ) begin

state_var <= main_C_0;

end

else begin

state_var <= state_var_NS;

end

end

endmodule

このモジュールは値を設定するFSMになっている。次のadd_top_coreが全体のモジュールである。

module add_top_core (

clk, rst_n, a_rsc_dat, a_triosy_lz, b_rsc_dat, b_triosy_lz, return_rsc_dat, return_triosy_lz

);

input clk;

input rst_n;

input [31:0] a_rsc_dat;

output a_triosy_lz;

input [31:0] b_rsc_dat;

output b_triosy_lz;

output [31:0] return_rsc_dat;

output return_triosy_lz;

// Interconnect Declarations

wire [31:0] a_rsci_idat;

wire [31:0] b_rsci_idat;

reg [31:0] return_rsci_idat;

wire [32:0] nl_return_rsci_idat;

wire [1:0] fsm_output;

reg reg_return_triosy_obj_ld_cse;

// Interconnect Declarations for Component Instantiations

ccs_in_v1 #(.rscid(32'sd1),

.width(32'sd32)) a_rsci (

.dat(a_rsc_dat),

.idat(a_rsci_idat)

);

ccs_in_v1 #(.rscid(32'sd2),

.width(32'sd32)) b_rsci (

.dat(b_rsc_dat),

.idat(b_rsci_idat)

);

ccs_out_v1 #(.rscid(32'sd3),

.width(32'sd32)) return_rsci (

.idat(return_rsci_idat),

.dat(return_rsc_dat)

);

mgc_io_sync_v2 #(.valid(32'sd0)) a_triosy_obj (

.ld(reg_return_triosy_obj_ld_cse),

.lz(a_triosy_lz)

);

mgc_io_sync_v2 #(.valid(32'sd0)) b_triosy_obj (

.ld(reg_return_triosy_obj_ld_cse),

.lz(b_triosy_lz)

);

mgc_io_sync_v2 #(.valid(32'sd0)) return_triosy_obj (

.ld(reg_return_triosy_obj_ld_cse),

.lz(return_triosy_lz)

);

add_top_core_core_fsm add_top_core_core_fsm_inst (

.clk(clk),

.rst_n(rst_n),

.fsm_output(fsm_output)

);

always @(posedge clk) begin

if ( ~ rst_n ) begin

return_rsci_idat <= 32'b00000000000000000000000000000000;

end

else if ( ~ (fsm_output[1]) ) begin

return_rsci_idat <= nl_return_rsci_idat[31:0];

end

end

always @(posedge clk) begin

if ( ~ rst_n ) begin

reg_return_triosy_obj_ld_cse <= 1'b0;

end

else begin

reg_return_triosy_obj_ld_cse <= ~ (fsm_output[1]);

end

end

assign nl_return_rsci_idat = a_rsci_idat + b_rsci_idat;

endmodule

このモジュールは、上位から2つの値を順にセットする記述になっている。インタフェースを用いて、同期もしている。さらにFSMを使って2つの値を設定している。実際に計算が行われるのは、最後のalways文で、与えられた二つの値を加算して出力している。

module add_top (

clk, rst_n, a_rsc_dat, a_triosy_lz, b_rsc_dat, b_triosy_lz, return_rsc_dat, return_triosy_lz

);

input clk;

input rst_n;

input [31:0] a_rsc_dat;

output a_triosy_lz;

input [31:0] b_rsc_dat;

output b_triosy_lz;

output [31:0] return_rsc_dat;

output return_triosy_lz;

// Interconnect Declarations for Component Instantiations

add_top_core add_top_core_inst (

.clk(clk),

.rst_n(rst_n),

.a_rsc_dat(a_rsc_dat),

.a_triosy_lz(a_triosy_lz),

.b_rsc_dat(b_rsc_dat),

.b_triosy_lz(b_triosy_lz),

.return_rsc_dat(return_rsc_dat),

.return_triosy_lz(return_triosy_lz)

);

endmodule

最後のadd_topは、add_top_coreを呼ぶだけである。これでは計算が簡単な割に前後の道具立てが大変すぎるようだが、FSMの部分は外部からCPUで設定するAgile-Xのような枠組みでは、プログラムに置き換えることができる。なのでインタフェースをコントロールすれば使い物にならないことはないように思う。もうちょっと使い込まないと、、

この記事を書いた人

ふんが