Python による実践的なネットリストの読み込み方
前回は、シンプルなネットリストについて紹介しましたが、実際の回路設計に利用されているネットリストの形式はもう少し複雑になっています。この記事では、実際に利用されているネットリストをプログラムで読み込む方法について紹介します。
基本はテキストファイルの読み込み
回路設計で利用されるネットリストは、テキストファイルの形式で保存されるものが多くなっています。回路図の入力アプリで作成した回路の接続情報を、部品配置や配線を行う CAD に渡したり、プリント基板などを製造する際のデータとしても利用される場合もあります。
したがって、回路の接続情報をプログラムで読み込むための処理は、テキストファイルの読み込みが基本になります。
最近よく利用されるプログラミング言語の場合、テキストファイルの読み込みの機能は標準ライブラリの一部として用意されています。従って、テキストファイルの中身を文字列としてプログラムに簡単に取り込む事ができます。
この記事では、いろいろな分野で活用されている Python を利用して、アメリカでは回路図入力の標準的なアプリとして利用されている Cadence 社のネットリストを読み込む例を紹介します。
ネットリストの書式を理解する
最初にやることは、ネットリストの中身を見て、ネットリストの書式がどの様になっているかを把握します。
今回、例に取り上げるケイデンス社の CAD で使われているネットリストは、「pstxnet.dat」というファイル名で生成されるネットリストで、拡張ネットリスト(extended net list)です。
ネットリストは、テキストファイル形式で保存されていて、回路図入力アプリの、Allegro Design Entry「Capture / Capture CIS」や「HDL」などと呼ばれている CAD アプリが入力した回路図から生成します。
(*) Caputure/Cature CIS は元々はメンター社の OrCAD がベースのツールです (*) HDL が Cadence 社の Concept HDL ベースのツールです
大きく分けて三つの部分からできています
* ヘッダー部分(ファイルのタイプ、日付、生成したツールなど)
* ネットリスト部分
* データの終わりのマーク(END.)
です。
ヘッダー部分はファイルの最初の二行で以下の様になっています。
FILE_TYPE = EXPANDEDNETLIST;
{ Using PSTWRITER 16.6.0 d001Dec-14-2021 at 15:02:40 }
その後に続くのが「ネット(接続情報)」のリストになります。 ネットの名前(接続の名前/信号名)は、「NET_NAME」の次の行に書かれています。ネットの名前は「’」で囲まれています。
その後の情報は、CAD で使用しているデータになりますが、今回の例では利用しないので無視します。
接続されているピン(ノード)の情報は、「NODE_NAME」で始まる行に、部品の識別し(Reference designator)、ピンの名前の順で書かれています。その次の行は、部品の情報が書かれています。CAD で使用している部品の識別子(ID/Identifier、インスタンス名)や、部品のタイプ(抵抗とかコンデンサなどの部品のタイプ)です。この部分は今回は無視します。その次の行は、回路図のシンボル状のピンのラベルが書かれています。ピンのラベルは接続のチェックに使える場合もあるので、取り込みます。
次の、「NET_NAME」が現れるまでは、その前のネットに接続されているピンとして扱います。
NET_NAME
'SAMPLE_NET_NAME_A'
'@SAMPLE-NET.SCHEMATIC1(SCH_1):SAMPLE_NET_NAME_A':
C_SIGNAL='@\sample-schematic\.schematic1(sch_1):sample_net_name_a';
NODE_NAME C1 1
'@SAMPLE-NET.SCHEMATIC1(SCH_1):INS146183478@CAPACITOR.C.NORMAL(CHIPS)':
'1':;
NODE_NAME R1 2
'@SAMPLE-NET.SCHEMATIC1(SCH_1):INS146183834@RESISTOR.R.NORMAL(CHIPS)':
'2':;
NET_NAME
'SAMPLE_NET_NAME_B'
'SAMPLE-NET.SCHEMATIC1(SCH_1):SAMPLE_NET_NAME_B':
C_SIGNAL='@\sample-schematic\.schematic1(sch_1):sample_net_name_bl';
NODE_NAME R2 1
'@SAMPLE-NET.SCHEMATIC1(SCH_1):INS146177081@RESISTOR.R.NORMAL(CHIPS)':
'1':;
ネットリストのデータの終わりには「END.」が入れられています。
END.
基本的な読み込みのプロセスは?
実際に、ネットリストのデータを読み込むには、ネットリストのファイルの場所と名前を指定して、プログラムに取り込みます。
ヘッダ情報の取り込みとチェック(最初の2行)
ネット名と接続されるピン情報の取り込み
「END.」を見つけたら終了
という手順で行います。
Python では、ファイルのパスを指定すると、簡単にファイルを開いてテキストファイルを文字列として取り込む事ができます。
この形式のネットリストを処理するには、一行ごとに分割した方が処理がしやすくなります。この処理も改行を示す特殊文字「\n」で分割すると簡単にできます。この処理を行う関数(method)も Python では標準で用意されています。
このように、ネットリストを読み込むための基本的な機能が Python には予め用意されているので簡単に読み込む事ができます。
Python のコード例
実際のコード例です。以下のコードではヘッダ部分でファイルのタイプのチェックはしていませんが、実際に使用する際には、ファイルのタイプをチェックして別のファイルのタイプの場合にはエラーにする処理を入れた方が良いプログラムと言えます。
# Key word for Net name
NET_NAME = "NET_NAME"
# Key word for Node name (Pin name)
NODE_NAME = "NODE_NAME"
END_MARK = "END."
# Key characters
READ = "r"
TAB = "\t"
WHITE_SPACE = " "
SEMICOLON = ";"
COLON=":"
SINGLE_QUOATATION = "'"
NEW_LINE = "\n"
# Python directory labels
PINS = "pins"
NAME = "name"
REFERENCE_DESIGNATOR = "ref"
PIN_NUMBER = "number"
PIN_LABEL = "label"
def read_netlist(file):
'''
Read Cadence netlist
@param file File path of the net list to be imported (string)
@return Returns a list of Net object (Array of Net (dictionary)
Net: { "name": <net name (string)>, "pins": <array of Pin (dictionary)>}
Pin: { "ref": <reference designator(string)>, "number": <pin number(string)>, "label": <pin label on a symbol(string)>}
'''
f = open(file, READ)
contents = f.read()
lines = contents.split(NEW_LINE)
getname = False
skip = False
getlabel = False
nets = []
net = None
pin = None
for i in range(2, len(lines)):
line = lines[I]
if line == NET_NAME:
'''Indicates the next line would be a net name'''
getname = True
elif getname:
'''Gets a net name'''
getname = False
net = {}
net[PINS] = []
net[NAME] = line.strip(SINGLE_QUOATATION)
nets.append(net)
elif line.find(NODE_NAME) == 0:
'''Gets a reference designator and a pin number (pin name)'''
if net is not None:
pin = {}
words = line.split(TAB)[1].split(WHITE_SPACE)
pin[REFERENCE_DESIGNATOR] = words[0]
pin[PIN_NUMBER] = words[1]
net[PINS].append(pin)
skip = True
elif skip:
'''Ignores this pin information'''
skip = False
getlabel = True
elif getlabel:
'''Gets pin lable on a schematic symbol'''
if pin is not None:
label = line.strip(WHITE_SPACE).strip(SEMICOLON).strip(COLON).strip(SINGLE_QUOATATION)
pin[PIN_LABEL] = label
getlabel = False
elif line == END_MARK:
break
f.close()
return nets
nets = read_netlist("pstxnet.dat")
print (nets)
簡単な説明をすると: ファイルのテキストを文字列として取り込んで、「split()」で一行毎に分割して処理します。この例では、ヘッダーは無視するようにしているので三行目から処理を行います。
「NET_NAME」という行を見つけたら、次の行にあるネットの名前を取り込みます。その際、ネット名の外側についている「'(シングルコーテーション)」を「strip()」を利用して取り除きます。
ネットの情報は「nets」という配列(array)に入れます。ネットの情報は、「net」という名前で、Python の Dictionary を作って、ネット名は「name」というラベル、ピン情報は「pins」という配列(array)に入れます。
ピン情報は、「NODE_NAE」で始まる行を見つけたらその行からピン情報を取り出すます。ピン情報の書式は
NODE_NAME[Tab('\t')][Reference designator(string)][Space(' ')][Pin name(string)]
という書式になっています。 従ってまず「Tab」でこの行を分けて、2 個目の文字列を「SPACE」で分けて取り出します。
最後に、NODE_NAME の後の二行目から部品のシンボルのピンのラベルを取り出します。 以下のような書式なので、最初にスペースを取り除いて、同じ容量で、セミコロン(';')とコロン(':')を取り除いて、最後にシングルコーテーション("'")を取り除きます。
'[Space(' ')][label]':;
以上で、ネットリストの情報をプログラムに取り込む事ができます。 Python で書くと比較的シンプルなプログラムで必要な情報を簡単に取り出せます。
まとめ
実際の回路設計で使われているネットリストの書式は少し複雑ですが、最近のプログラミング言語では、文字列の処理でよく利用される機能は予め用意されているので、文字列を分割したり、不要な文字を取り除いたりを簡単に記述できます。
一旦プログラム内に処理しやすい形でデータを取り込むといろいろな処理や、回路設計のデータのエラーをプログラムでチェックできる様になるので、回路設計支援のアプリの実現が可能になります。
次回は、設計支援のアプリのアイディアについて紹介します。