特权同学

TestBench的IIC从机设计

0
阅读(2194)

这个testbench的编写是基于之前日志里的基于FPGA的IIC通信而做的,原来只是做了简单的主机写随机地址EEPROM, 然后主机读随机地址EEPROM,都是只有一个字节的,做的是最简单的通信。所以这次testbench设计IIC从机也是和前面的相对应 的。

Testbench代码:

`timescale 1ns/1ns

module testbench();

// DATE: Wed Aug 15 08:35:56 2007

// TITLE:

// MODULE: iic_top09

// DESIGN: iic_top09

// FILENAME: iic_top09

// PROJECT: top_dram

// VERSION: Version

// Inputs

reg clk;

reg rst_n;

reg sw1;

reg sw2;

// Outputs

wire scl;

wire led_d2;

wire led_d3;

wire led_d4;

wire led_d5;

// Bidirs

wire sda;

// Instantiate the UUT

iic_top09 d (

.clk(clk),

.rst_n(rst_n),

.sw1(sw1),

.sw2(sw2),

.scl(scl),

.sda(sda),

.led_d2(led_d2),

.led_d3(led_d3),

.led_d4(led_d4),

.led_d5(led_d5)

);

initial begin

clk = 0;

forever #10 clk = ~clk;//产生50MHz的时钟

end

initial begin

rst_n = 0; //复位

#2000 rst_n = 1; //复位持续2us后结束

end

initial begin

sw1 = 1;

sw2 = 1;

#20000000 sw1 = 0; //delay 20ms,iic write

#20000000 sw1 = 1; //delay 20ms,iic idle

#20000000 sw2 = 0; //delay 20ms,iic read

#20000000 sw2 = 1; //delay 20ms,iic idle

end

reg start; //start=1:通信中,start=0:通信结束

initial start = 0;

always @ (sda) begin

if(scl && !sda) start = 1; //接收到起始位

if(scl && sda) start = 0; //接收到结束位

end

reg sda_link; //sda控制位

reg sda_out; //

reg[7:0] device_addr; //器件地址

reg[7:0] eeprom_addr; //数据地址

reg[7:0] eeprom_data; //数据

reg[7:0] addr0_data,addr1_data;//0地址和1地址数据存储器

reg lsb_data; //

initial begin

device_addr = 8'd0;

sda_link = 1'b0;

// lsb_data = 1'b0;

end

always @ (posedge start) begin //数据通信中

repeat (8) begin //接收器件地址

@ (posedge scl);

#10 device_addr = device_addr << 1;

device_addr[0] = sda;

end

if(device_addr != 8'b10100000) begin

$display ("device address ERROR!");

$stop;

end

@ (posedge scl);

sda_out = 0; //ack

sda_link = 1;

@ (negedge scl);

sda_link = 0;

repeat (8) begin //接收数据地址

@ (posedge scl);

#10 eeprom_addr = eeprom_addr << 1;

eeprom_addr[0] = sda;

end

@ (posedge scl);

sda_out = 0; //ack

sda_link = 1;

@ (negedge scl);

sda_link = 0;

@ (posedge scl);

lsb_data = sda;

@ (negedge scl);

if(lsb_data == sda) write_eeprom;

else read_eeprom;

end

task write_eeprom;

begin

eeprom_data[0] = lsb_data;

repeat (7) begin

@ (posedge scl);

#10 eeprom_data = eeprom_data << 1;

eeprom_data[0] = sda;

end

# 10;

case (eeprom_addr) //存储数据到相应地址,本测试只仿真0地 址和1地址

0: addr0_data = eeprom_data;

1: addr1_data = eeprom_data;

default: ;

endcase

@ (posedge scl);

sda_out = 0; //ack

sda_link = 1;

@ (negedge scl);

sda_link = 0;

end

endtask

reg[7:0] addr_data;//

task read_eeprom;

begin

// device_addr[0] = lsb_data;

repeat (8) begin //接收器件地址

@ (posedge scl);

#10 device_addr = device_addr << 1;

device_addr[0] = sda;

end

if(device_addr != 8'b10100001) begin

$display ("device address ERROR!");

$stop;

end

@ (posedge scl);

sda_out = 0; //ack

sda_link = 1;

case (eeprom_addr)

0: addr_data = addr0_data;

1: addr_data = addr1_data;

default: ;

endcase

repeat (8) begin

@ (posedge scl);

sda_out = addr_data[7];

#10 addr_data = addr_data << 1;

end

@ (posedge scl);

sda_out = 0; //ack

@ (negedge scl);

sda_link = 0;

end

endtask

assign sda = sda_link ? sda_out : 1'bz;

endmodule

仿真波形:

前面是主机写,后面是主机收,重点可以看应答位以及byte_data1。(byte_data1是主机 写入EEPROM的数据,byte_data2是 主机读出的写入数据)。


这个图是放大了的写入数据过程(观察sda的变化):


这个图是放大了的读出数据的过程:

Baidu
map