System Verilogでの混合回路のモデリング

彼らはそうではなく、生きていました...ある日の早朝、再び仕事に来たとき、サーバールームに電源入力が1つしかないため、燃え尽きてしまうことがわかりました。 1日中何もすることがなかったので、Habrに関する記事を書くことにしました。 この記事は初心者を対象としており、興味津々です。







CMOS技術は、現代の超小型回路がシステムから組み立てられた巨大で非常に複雑な構造およびシステムであるようなレベルに達しました。 同時に、技術標準の低下に伴い、生産開始のコストが指数関数的に増加します。 そのため、開発時には、可能な限りすべてをシミュレートして検証する必要があります。 マイクロ回路が最初の起動から動作を開始したときに、実際に時々実現される理想的なケース。







私たちはアナログの世界に住んでいるので、デジタルのマイクロ回路でもこの世界と通信できなければなりません。 デジタルマイクロ回路には、ADC、DAC、PLL、二次電源など、チップ上に多数の大きなアナログブロックが含まれています。 この規則の例外は、Core iなどの大規模プロセッサのみである可能性が高く、この場合、このすべての経済がチップセットにもたらされます。







従来、pi-spice、mmsim、hspiceなどのスパイスシミュレーターは、アナログブロックのシミュレーションに使用されていました。 このようなシミュレーターでは、回路は巨大な次元の微分方程式系(またはそれを表す行列)によって記述されます。 計算の各ステップでのスパイスシミュレーターは、数値法によりこの連立方程式の解を見つけます。 もちろん、次のようなこれらの計算を加速する方法が使用されます:行列を部分行列に分割する、複数のスレッドと計算コアに並列化する、変数計算ステップなど







残念ながら、数値的手法は基本的に反復的であり、並列化が不十分であるため、このタイプのシミュレーションは、システム全体をシミュレーションするのに十分なほど遅いままです。 それにもかかわらず、アナログブロック自体およびアナログマイクロ回路の開発に広く使用されています。 アナログブロックとアナログ-デジタルシステムを含むデジタル(一般)マイクロ回路についてのストーリーをリードします。ここでは、ブロックを数式と方程式の形式で記述し、これらのナビエストークス方程式(ジョーク)を分析的に解きます。 この手法を使用しても、スパイスシミュレーターでのより正確な計算はキャンセルされませんが、それを補完するだけで、開発とモデリングをスピードアップできます。







アナログ信号の表現



浮動小数点タイプは、アナログ信号の表現に適しています。 System Verilogでは、これらはshortreal(Cのfloatと同等)およびreal型です。 これらはメモリを持つデータ型であることに注意してください。 それらの値は、割り当て時にのみ更新されます。 これはregに似た型ですが、格納された値は0または1ではなく、電圧または電流で表され、順番に浮動小数点数として表されます。

さて、wireに似たタイプが本当に必要です。これは、記録時だけでなく、継続的に更新されます。 System Verilogにはそのようなタイプは存在しないと言わなければなりません。 噂では、標準を議論する際にこの機能を挿入するために何らかの動きがあったが、具体的には実装されていなかったという。 それでも、ncsimシミュレーターを使用する場合、var修飾子があり、実際のタイプと他のタイプのワイヤのアナログを作成します。 例:







real a; var real b; assign a = in1+in2; //   assign b = in1+in2; //   , b –    in1+in2
      
      





純粋なプログラマーのための叙情的な余談

verilogプログラムは並列プログラムです。 コードのすべての行は、原則として独立しており、いくつかの条件に応じて、順次および並行して実行されます。 この場合、このプログラムを実行するとassignが機能し、最後まで機能し、継続的に量を計算します。







シミュレータがvarをサポートしていない場合、これを行うことができます。







 real b; always @( * ) //     always    in1  in2 b <= in1+in2;
      
      





録音はあまり便利ではありませんが、それでもかなり機能しています。







データ型変換



次の関数は、データ変換用にverilogに組み込まれています







 $itor() // integer to real $rtoi() // real to integer $bitstoreal() //reg [ : ] to real $realtobits() // real to reg [ : ]
      
      





実際に変換するコードが署名されており、追加のコードで提示されている場合、これらの関数を使用する際には注意が必要です。記号を変換または展開する必要がある場合があります。 何らかの理由でこれらの機能を使用したくない場合は、次の手法を使用できます。







 reg [7:0] code; int a; real voltage; always @( * ) begin a = {{24{code[7]}}, code[7:0]}; //    int voltage = a; end
      
      





Verilogの簡略化されたアナログブロックモデル



加法性ホワイトノイズアンプ



 module amp(input var real in, output real out); parameter k = 10; //  parameter seed = 60; parameter noise_power = -20; //   dB real noise; always @(*) begin noise = $sqrt(10**(noise_power/10))* $itor($dist_normal(seed, 0 , 100_000))/100_000; out = in * k + noise; end endmodule
      
      





ローパスフィルター付きDAC



 `timescale 1ns / 1ps module DAC(input signed [7:0] DAC_code, output real out); parameter fs = 10e-9; parameter ffilt = fs/64; //   parameter CUTOFF = 100e6; //   parameter a = ffilt/(ffilt+(1/(2*3.141592* CUTOFF))); real DAC_out; // always @( * ) DAC_out <= $bitstoint(DAC_code[7:0]); // 1  always #(0.5*ffilt) out <= a* DAC_out + (1-a)*out; endmodule
      
      





非線形性を考慮したADC



 module ADC (input real in, input clk, output reg [7:0] ADC_code) real adc_tf[0:255]; real min_dist; int i,j; int dnl_file; initial begin dnl_file=$fopen("DNL_file","r"); if(dnl_file==0) $stop; for(i=0;i<256;i=i+1) $fscanf(dnl_file, "%f;", adc_tf[i]);//     end always @(posedge clk) begin min_dist = 10; for(j=0;j<256; j=j+1) //      if($abs(in- adc_tf[j]) < min_dist) begin min_dist = delta_abs; ADC_code[7:0]=j; end end endmodule
      
      





マルチフェーズクロックソース(PLL)



 module MPLL (input en, input [5:0]phase, output clk_out); parameter REFERENCE_CLOCK_PERIOD=10e-6; parameter PHASES_NUMBER=64; reg [PHASES_NUMBER-1:0]PLL_phase=64'h00000000_FFFFFFFF; //    always #(REFERENCE_CLOCK_PERIOD/PHASES_NUMBER) if(en===1) PLL_phase[PHASES_NUMBER-1:0] <= {PLL_phase[PHASES_NUMBER-2:0], PLL_phase[PHASES_NUMBER-1]}; //     assign clk_out = PLL_phase[phase]; //  endmodule
      
      





このような類似の、より複雑な分析モデルを使用すると、スパイスモデリングと比較して桁違いに計算が高速化され、System Verilogで完全なシステムを実際にシミュレートおよび検証できます。







まだ加速中



残念ながら、最新のシステムはすでに非常に複雑であるため、この高速化では十分ではありません。この場合、並列化に頼らなければなりません。 私が知る限り、マルチスレッドVerilogシミュレーターはまだ発明されていないため、手作業でなければなりません。

SystemVerilogは、外部ソフトウェアモジュールにアクセスするための新しいメカニズム-Direct Programming Interface(DPI)を導入しました。 なぜなら このメカニズムは他の2つよりも単純なので、使用します。







外部関数を呼び出すモジュールの最初に、ラインインポートを挿入します。

import "DPI-C"関数int some_funct(入力文字列file_name、入力int in、出力real out);

次に、次のように、Verilogで通常の方法で使用できます。







  always @(posedge clk) res1 <= some_funct (“file.name”, in1, out1);
      
      





コンパイル方法とライブラリの場所は、シミュレータのドキュメントに記載されています。

以下は、複数のスレッドで実行されているプログラムの例です







 #include <pthread.h> typedef struct { //work specific double in; //    double out; //  … //thread specific char processing; //   pthread_mutex_t mutex; pthread_cond_t cond_start; pthread_cond_t cond_finish; void *next_th_params; pthread_t tid; }th_params; static th_params th_pool[POOL_SIZE];
      
      





計算関数:







 void* worker_thread(void *x_void_ptr) { th_params *x_ptr = (th_params *)x_void_ptr; while(1) //  { //     pthread_mutex_lock (&x_ptr->mutex); // x_ptr->processing = 0; //,    pthread_cond_signal(&x_ptr->cond_finish); // ,   while(x_ptr->processing == 0) pthread_cond_wait(&x_ptr->cond_start, &x_ptr->mutex); //   x_ptr->processing = 1; //  -  pthread_mutex_unlock(&x_ptr->mutex); // //  - ,    SSE2 … } }
      
      





計算関数を起動するための関数







 void init(th_params *tp) { int i=0; for(;i<12;i++) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(th_pool->tid, &attr, &worker_thread, tp); } }
      
      





計算された関数に作業を分配する関数(Verilogから常に呼び出します)







 int ch(double in, double *out) { int i; for(i=0;i<12;i+=1) { //       pthread_mutex_lock(&th_pool[i].mutex); // while(th_pool[i].processing == 1) pthread_cond_wait(&th_pool[i].cond_finish, &th_pool[i].mutex); //  pthread_mutex_unlock(&th_pool[i].mutex); // } //         Verilog for(i=0;i<12;i+=1) out[i] = th_pool[i].out; for(i=0;i<12;i+=1) { pthread_mutex_lock (&th_pool[i].mutex); // th_pool[i].in = in; //    th_pool[i].processing = 1; //    pthread_cond_signal (&th_pool[i].cond_start); //  ,    pthread_mutex_unlock (&th_pool[i].mutex); // } }
      
      





残念ながら、現代のシステムはすでに非常に複雑であるため、この加速でも十分ではありません。 この場合、ビデオカード(DPIほど複雑ではない)での計算、クラスターまたはクラウドでの計算にOpenCLを使用する必要があります。 これらのすべての場合、トランスポートコンポーネント、つまり 計算デバイスとの間のデータ転送時間。 この場合の最適な問題は、この計算に関して、ソースと結果の両方の少量のデータがある一方で、多くをカウントする必要がある場合です。 同じことが、提示されたプログラムにも当てはまりますが、程度はそれほど大きくありません。 この条件が満たされない場合、多くの場合、1つのプロセッサのみを使用する方が高速です。







サーバールームに電力が供給されていない場合、提示された方法はいずれも機能しないことを考慮に入れる必要がありますが、提供されただけで、YouTubeは再び機能しました。 この幸せなメモで、私は話を終えようと急いで、仕事が待っています。








All Articles