昨日はI2CのACK/NACKを追加するところまで行いました。
そろそろ、検証してみたいと思います。
Grokにつぎの質問をしてみました。
この回路をテストするためのAPB側のテストパターンを作成してください
APB側からI2Cマスター回路をテストするためのテストベンチを以下に示します。このテストベンチは基本的な書き込み/読み出し操作とI2C転送のテストを行います。
systemverilog
`timescale 1ns/1ps
module tb_apb_i2c_master;
// テストベンチ信号
logic pclk;
logic presetn;
logic [31:0] paddr;
logic psel;
logic penable;
logic pwrite;
logic [31:0] pwdata;
logic [31:0] prdata;
logic pready;
wire scl;
wire sda;
// DUTインスタンス
apb_i2c_master dut (
.pclk(pclk),
.presetn(presetn),
.paddr(paddr),
.psel(psel),
.penable(penable),
.pwrite(pwrite),
.pwdata(pwdata),
.prdata(prdata),
.pready(pready),
.scl(scl),
.sda(sda)
);
// クロック生成
initial begin
pclk = 0;
forever #5 pclk = ~pclk; // 100MHz clock
end
// I2Cスレーブモデル(簡易版)
logic sda_drive;
logic sda_out;
assign sda = sda_drive ? sda_out : 1'bz;
// テストシーケンス
initial begin
// 初期化
presetn = 0;
psel = 0;
penable = 0;
pwrite = 0;
paddr = 0;
pwdata = 0;
sda_drive = 0;
sda_out = 1;
#20;
presetn = 1;
#20;
// テスト1: 設定レジスタへの書き込み(クロック分周設定)
apb_write(32'h0C, 32'd100); // 100サイクルでSCLトグル
// テスト2: データレジスタへの書き込み
apb_write(32'h08, 32'hA5); // 送信データ 0xA5
// テスト3: ステータスレジスタの読み出し
apb_read(32'h04);
// テスト4: I2C転送開始
apb_write(32'h00, 32'h1); // 制御レジスタ: Start
// スレーブ側でACKを返す
@(negedge scl) wait(dut.bit_counter == 8);
@(negedge scl);
sda_drive = 1;
sda_out = 0; // ACK
@(posedge scl);
sda_drive = 0;
// 転送完了待ち
wait(dut.status_reg[1] == 0); // busyフラグが下がるまで待つ
#100;
// テスト5: NACKの場合のテスト
apb_write(32'h08, 32'h5A); // 新しいデータ
apb_write(32'h00, 32'h1); // Start
// スレーブ側でNACKを返す
@(negedge scl) wait(dut.bit_counter == 8);
@(negedge scl);
sda_drive = 1;
sda_out = 1; // NACK
@(posedge scl);
sda_drive = 0;
wait(dut.status_reg[1] == 0);
#100;
// 結果確認
apb_read(32'h04); // ステータス確認
#1000;
$finish;
end
// APB書き込みタスク
task apb_write(input [31:0] addr, input [31:0] data);
@(posedge pclk);
psel = 1;
penable = 0;
pwrite = 1;
paddr = addr;
pwdata = data;
@(posedge pclk);
penable = 1;
@(posedge pclk);
wait(pready);
psel = 0;
penable = 0;
pwrite = 0;
$display("Write: Addr=0x%h, Data=0x%h", addr, data);
endtask
// APB読み出しタスク
task apb_read(input [31:0] addr);
@(posedge pclk);
psel = 1;
penable = 0;
pwrite = 0;
paddr = addr;
@(posedge pclk);
penable = 1;
@(posedge pclk);
wait(pready);
$display("Read: Addr=0x%h, Data=0x%h", addr, prdata);
psel = 0;
penable = 0;
endtask
// モニタリング
initial begin
$monitor("Time=%0t scl=%b sda=%b state=%s busy=%b nack=%b",
$time, scl, sda, dut.state.name(),
dut.status_reg[1], dut.status_reg[2]);
end
// 波形ダンプ
initial begin
$dumpfile("tb_apb_i2c_master.vcd");
$dumpvars(0, tb_apb_i2c_master);
end
endmodule
このテストベンチの主な特徴:
実行方法:
期待される動作:
このテストパターンをベースに、必要に応じてさらに詳細なテストケース(複数バイト転送、エラー条件など)を追加できます。
基本的なテストパターンを生成してきました。
これを基にシナリオを増やせばテストも充実しそうですね。