module Slave_TB;注册时钟;线材SDA;线 SCL = 时钟;上拉(SDA);reg [6:0] addressToSend = 7'b000_1000;//8reg readWite = 1'b1;//写reg [7:0] dataToSend = 8'b0110_0111;//103 = 0x67注册 sda_tb;reg drive_sda;分配 SDA = (drive_sda) ?sda_tb : 1'bz;整数 ii=0;最初的开始时钟 = 0;永远的开始clk = #1 ~clk;结尾结尾从属 UUT(.SDA(SDA),.SCL(SCL));最初的开始$display(启动测试平台...");驱动器_sda = 0;sda_tb = 1;#11;//设置 SDA 低开始驱动器_sda = 1;sda_tb = 0;写({addressToSend,readWite});写(数据发送);//再次强制 SDA 为高,我们完成了#2;驱动器_sda = 1;sda_tb = 1;#50;$完成;结尾任务写入(reg [7:0] 数据);整数 ii;对于 (ii=7; ii>=0; ii=ii-1) 开始$display("Data SDA %h 到 %h", SDA, data[ii]);#2;驱动器_sda = 1;sda_tb = 数据[ii];结尾#2 drive_sda = 0;结束任务最初的开始//需要将信号转储到 EPWave$dumpfile(dump.vcd");$dumpvars(0);结尾结束模块I'm trying to write an I2C Slave and test it in isolation.I have a simulation that should be pulling SDA low when write_ack is high (Also highlighted by the red dots). However, you can see that SDA remains the same.Part of me thinks it's to do with the way I'm testing with the force methods and the delays.Any help appreciated.I have found the keyword release which seems to help.Code below & EDA Playground is here: https://edaplayground.com/x/6snM/**I2C Slave to Read/Write 8 bits of data only*/`timescale 1ns / 1psmodule Slave( inout wire SDA, input wire SCL); reg [4:0] IDLE = 4'b0000; reg [4:0] START = 4'b0001; reg [4:0] READ_ADDRESS = 4'b0010; reg [4:0] READ_WRITE = 4'b0011; reg [4:0] DATA = 4'b0100; reg [4:0] DATA_ACK = 4'b0101; reg [4:0] STOP = 4'b0110; reg [4:0] ADDRESS_ACK = 4'b0111; reg [4:0] state = 4'b0010; reg [6:0] slaveAddress = 7'b0001000; reg [7:0] addr; reg [6:0] addressCounter = 7'b0000000; reg [7:0] data; reg [6:0] dataCounter = 7'b0000000; reg readWrite = 1'b0; reg start = 0; reg write_ack = 0; assign SDA = (write_ack == 1) ? 0 : 'b1z; always @(negedge SDA) begin if ((start == 0) && (SCL == 1)) begin start <= 1; addressCounter <= 0; dataCounter <= 0; end end always @(posedge SDA) begin if (state == DATA_ACK && SCL == 1) begin start <= 0; state <= READ_ADDRESS; end end always @(posedge SCL) begin if (start == 1) begin case (state) READ_ADDRESS: begin addr[addressCounter] <= SDA; addressCounter <= addressCounter + 1; if (addressCounter == 6) begin state <= READ_WRITE; end end READ_WRITE: begin readWrite <= SDA; state <= ADDRESS_ACK; end ADDRESS_ACK: begin write_ack <= 1; state <= DATA; end DATA: begin write_ack <= 0; data[dataCounter] <= SDA; dataCounter <= dataCounter + 1; if (dataCounter == 8) begin state <= DATA_ACK; write_ack <= 1; end end DATA_ACK: begin write_ack <= 0; state <= STOP; end STOP: begin start <= 0; state <= READ_ADDRESS; end endcase end endendmoduleTest Code/**Testing I2C Slace for reading/writing 8 bits of data only*/`timescale 1ns / 1psmodule Slave_TB (); reg clk; wire SDA; wire SCL; pullup(SDA); pullup(SCL); reg [6:0] addressToSend = 7'b0001000; reg readWite = 1'b1; reg [7:0] dataToSend = 8'b01100111; integer ii=0; initial begin clk = 0; force SCL = clk; forever begin clk = #1 ~clk; force SCL = clk; end end Slave #() UUT (.SDA(SDA), .SCL(SCL)); initial begin $display("Starting Testbench..."); clk = 0; force SCL = clk; #11 // Set SDA Low to start force SDA = 0; // Write address for(ii=0; ii<7; ii=ii+1) begin $display("Address SDA %h to %h", SDA, addressToSend[ii]); #2 force SDA = addressToSend[ii]; end // Are we wanting to read or write to/from the device? $display("Read/Write %h SDA: %h", readWite, SDA); #2 force SDA = readWite; $display("SDA: %h", SDA); #2; // Wait for ACK bit for(ii=0; ii<8; ii=ii+1) begin $display("Data SDA %h to %h", SDA, dataToSend[ii]); #2 force SDA = dataToSend[ii]; end #2; // Wait for ACK bit // Force SDA high again, we are done #2 force SDA = 1; #100; $finish(); end initial begin // Required to dump signals to EPWave $dumpfile("dump.vcd"); $dumpvars(0); endendmodule 解决方案 Instead of using force, a more conventional approach is to add a tristate buffer to the testbench, just like you have in the design.For SDA, create a buffer control signal (drive_sda) and a testbench data signal (sda_tb). Use a task to drive a byte and wait for the ACK.Since SCL is not an inout, there is no need for a pullup, and it can be directly driven by clk.module Slave_TB; reg clk; wire SDA; wire SCL = clk; pullup(SDA); reg [6:0] addressToSend = 7'b000_1000; //8 reg readWite = 1'b1; //write reg [7:0] dataToSend = 8'b0110_0111; //103 = 0x67 reg sda_tb; reg drive_sda; assign SDA = (drive_sda) ? sda_tb : 1'bz; integer ii=0;initial begin clk = 0; forever begin clk = #1 ~clk; endend Slave UUT (.SDA(SDA), .SCL(SCL));initial begin $display("Starting Testbench..."); drive_sda = 0; sda_tb = 1; #11; // Set SDA Low to start drive_sda = 1; sda_tb = 0; write({addressToSend, readWite}); write(dataToSend); // Force SDA high again, we are done #2; drive_sda = 1; sda_tb = 1; #50; $finish;endtask write (reg [7:0] data); integer ii; for (ii=7; ii>=0; ii=ii-1) begin $display("Data SDA %h to %h", SDA, data[ii]); #2; drive_sda = 1; sda_tb = data[ii]; end #2 drive_sda = 0;endtaskinitial begin // Required to dump signals to EPWave $dumpfile("dump.vcd"); $dumpvars(0);endendmodule 这篇关于TestBench I2C Slave SDA 不会变低的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
07-14 11:09