普段、仕事で設計を始めるとなると設計仕様書を作成して、これから設計を始める内容をメンバー(あるいは顧客)と確認して始めるのであるが、さっさとコーディングをしたいので、TestBenchから始めることにします。
UARTも通信装置なので、送信と受信があるわけで、まずは送信側のTestBenchから始めてみましょう。
送信側は検証する項目がほとんどなく、与えられた設定に基づき送信を行うものですので、比較的簡単です。たった1つの task で作られます。
ただ1箇所、工夫している点があるので、その点について説明しておきます。
task には時間の制御があり、task の開始から終了までの間に時間とともに扱われている変数の値が変化していきます。 もし、task の実行中に更に同じ task がコールされてしまった場合、実行中の task が扱っている変数の値は保証されなくなります。(2つ目の task のコールによって順序処理が壊されてしまいます。)
そこでの工夫は、task の中に 変数 in_use を宣言して、task 実行開始とともに in_use を 1'b1 にセット、task 終了時に in_use を 1'b0 にリセットするものとし、2つ目に task がコールされたとき、in_use の値が 1'b1 であった場合、その task について ##ERROR## メッセージを出力して強制的に終了させています。
28 task transmit;
29 reg in_use;
30 integer trns_bit_num;
31 reg parity;
32 begin : transmit_task
33 if (in_use) begin
34 $display("%t ##ERROR## %m - task is in use", $time);
35 disable transmit_task;
36 end
37 in_use = 1'b1;
〜
81 in_use = 1'b0;
82 end
83 endtask
UART送信側の Testbench module の全体は以下のコードとなります。
bit_period, data_length, stop_length, parity_mode は シミュレーションの途中でも変えることができるよう`define で宣言はせず、それぞれの 型 で宣言しています。
1 `ifndef non_parity
2 `define non_parity 2'b00
3 `endif
4
5 `ifndef odd_parity
6 `define odd_parity 2'b01
7 `endif
8
9 `ifndef even_parity
10 `define even_parity 2'b10
11 `endif
12
13 module TB_UART_tx
14 (/*AUTOARG*/
15 // Outputs
16 UART_tx
17 );
18
19 output reg UART_tx = 1'bz;
20
21 time bit_period = 1000;
22 integer data_length = 8;
23 integer stop_length = 2;
24 reg [1:0] parity_mode = `odd_parity;
25 reg [127:0] data = 8'b1010_1010;
26 reg LSB_first = 0;
27
28 task transmit;
29 reg in_use;
30 integer trns_bit_num;
31 reg parity;
32 begin : transmit_task
33 if (in_use) begin
34 $display("%t ##ERROR## %m - task is in use", $time);
35 disable transmit_task;
36 end
37 in_use = 1'b1;
38 $write("%t ##INFO## %m - Transmitting UART data ", $time);
39 for (trns_bit_num = data_length - 1; trns_bit_num >= 0; trns_bit_num = trns_bit_num - 1) begin
40 $write("%b", data[i]);
41 end
42 $write("\n");
43 parity = 1'b0;
44 // Start-bit
45 UART_tx = 1'b0;
46 #(bit_period);
47 // Data
48 if (LSB_first === 1) begin
49 for (trns_bit_num = 0; trns_bit_num < data_length; trns_bit_num = trns_bit_num + 1) begin
50 UART_tx = data[trns_bit_num];
51 parity = parity ^ UART_tx;
52 #(bit_period);
53 end
54 end
55 else begin
56 for (trns_bit_num = data_length - 1; trns_bit_num >= 0; trns_bit_num = trns_bit_num - 1) begin
57 UART_tx = data[trns_bit_num];
58 parity = parity ^ UART_tx;
59 #(bit_period);
60 end
61 end
62 // Parity
63 case (parity_mode)
64 `odd_parity : begin
65 UART_tx = parity;
66 #(bit_period);
67 end
68 `even_parity : begin
69 UART_tx = ~parity;
70 #(bit_period);
71 end
72 default : begin
73 end
74 endcase // case (parity_mode)
75 // Stop-bit
76 for (trns_bit_num = 0; trns_bit_num < stop_length; trns_bit_num = trns_bit_num + 1) begin
77 UART_tx = 1'b1;
78 #(bit_period);
79 end
80 UART_tx = 1'bz;
81 in_use = 1'b0;
82 end
83 endtask
84
85 endmodule // TB_UART_tx
海外発激安ガジェットショップ!送料無料!【DX.com】
|
自己紹介
50才になる半導体エンジニアです。
大学で電子電気工学を学び、1990年にその分野のまま就職。ASICやマイコンの設計を長く続けてきましたが20年も同じ分野にいると業態も衰退したり変化するもので退職し、今は外資のIT系会社に再就職して設計請負業をやっております。
お問い合わせは
nakata.xianzhi@outlook.com
Linux と 小ネタ
デジタル回路設計
海外駐在後記
|