I2C控制器的Verilog建模之三(完结版)
前言:终于到了测试篇,不过悲剧了一下。按照之前《二》里面的思路,在顶层用一个复用器驱动读写独立模块的I2C总线确实失败。虽然综合过去了,不过警告里已经说明:底层的2个原本是inout三态口的数据线在顶层复用时候被综合成wire,这样在默认情况下顶层的inout总是输出有效,失去了三态口的作用。囧,看来为了测试I2C的写还是得把读模块并进去可避免这一尴尬……
测试:DE2+Questasim10.0c+Q2_9.1;
日期:2013七夕夜
结果:以下2张图为仿真波形图与逻辑分析仪采样的时序波形图。之前还踩不到ACK信号,因为宏定义里读写器件的地址弄饭了。(若这里程序与之前的《一》《二》有出路须以此篇修改之后为准)。对比可知基本上二者相同,也踩到从器件的相应。不过有个问题,在响应的一个完整时钟周期里的后四分之一变成高电平,也就是说一个ACK仅仅保持了四分之三的低电平,这个是不是应该算正常?如果从数据有效来看,时钟高电平保持了ACK一直为低电平,似乎是对的。
解决:出现这样目前只好等读模块嵌入,如果能读出正确写入的数据,那么说明是正常的。
last update:因为其他时间耽搁了,断断续续终于今天整理完毕。仿真和硬件均测试通过。最后附出仿真文件、建模源码以及tcl脚本。
总结:IIC中从机响应脉冲宽度并未填满一整个周期,这也是之前图里的疑问。如何分辨正确:仅记ack和nack在时钟上升沿改变在时钟下降沿即可改变;不同器件数据变化时间时刻不一样,如果移植到不同器件测试得到不用stp2也无需惊讶,抓住根本的就行;
源码1:iic读写控制器
`timescale ns / ps
`define SIM
`define SYS_CLK
`define IIC_CLK
`define IIC_CLK_DIV `SYS_CLK/`IIC_CLK
`define ADV7181B
`define SCLK_CNT_WIDTH
//VERSION:V0.0
module iic_ctrl(
//common
sys_clk,
sys_rst_n,
iic_sclk,
iic_sdat,
//read
rreq_i,
iic_rd_addr_i,
rd_en_i,
iic_rd_ack_o,
sys_byte_o,
//write
wreq_i,
wr_en_i,
iic_wr_addr_i,
sys_byte_i,
iic_wr_ack_o
);
//common port
input sys_clk; //global clk in
input sys_rst_n; //global rst_n in
output iic_sclk; //iic sclk
inout iic_sdat; //iic sdat
//read port
input rreq_i; //read requast in
input [:] iic_rd_addr_i; //read register address in
input rd_en_i; //read enable in
output iic_rd_ack_o; //module read ack
output [:] sys_byte_o; //read byte out
//write port
input wreq_i; //write request in
input wr_en_i; //write enable in
input [:] iic_wr_addr_i; //write register address in
input [:] sys_byte_i; //byte to be written
output iic_wr_ack_o; //module write ack
//macro
`ifdef ADV7181B
parameter DEVICE_READ = 'h41; //器件读操作地址
parameter DEVICE_WRITE = 'h40; //器件写操作地址
`endif
//marcro
`ifdef SIM
parameter ST_WIDTH = ;
parameter IDLE = "IDLE...",
START1 = "START1.",
WR_SLAVE = "WR_SLAV",
ACK1 = "ACK1...",
SET_REG = "SET_REG",
ACK2 = "ACK2...",
WR_DATA = "WR_DATA",
ACK3 = "ACK3...",
STOP = "STOP...";
parameter START2 = "START2.",
RD_SLAVE = "RD_SLAV",
ACK4 = "ACK4...",
RD_DATA = "RD_DATA",
NACK = "NACK..."; `else
`define FSM
parameter ST_WIDTH = ;
parameter IDLE = `FSM'b00_0000_0000_0001,
START1 = `FSM'b00_0000_0000_0010, //写操作一共有1个start,读操作一共2个start
WR_SLAVE = `FSM'b00_0000_0000_0100,
ACK1 = `FSM'b00_0000_0000_1000,
SET_REG = `FSM'b00_0000_0001_0000,
ACK2 = `FSM'b00_0000_0010_0000,
WR_DATA = `FSM'b00_0000_0100_0000,
ACK3 = `FSM'b00_0000_1000_0000,
STOP = `FSM'b00_0001_0000_0000;
parameter START2 = `FSM'b00_0010_0000_0000,
RD_SLAVE = `FSM'b00_0100_0000_0000,
ACK4 = `FSM'b00_1000_0000_0000,
RD_DATA = `FSM'b01_0000_0000_0001,
NACK = `FSM'b10_0000_0000_0001;
`endif
//caputre the posedge of rreq_i;
reg rreq_r0 = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) rreq_r0 <= 0;
else rreq_r0 <= rreq_i;
end
wire do_rreq = rreq_i & ~rreq_r0 & rd_en_i;
//generate the rd_start;
reg rd_start = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) rd_start <= 0;
else if(iic_rd_ack_o == 'b1) rd_start <= 0;
else if(do_rreq) rd_start <= ;
else rd_start <= rd_start;
end
//caputre the posedge of wreq_i;
reg wreq_r0 = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) wreq_r0 <= 0;
else wreq_r0 <= wreq_i;
end
wire do_wreq = wreq_i & ~wreq_r0 & wr_en_i;
//generate the wr_start;
reg wr_start = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) wr_start <= 0;
else if(iic_wr_ack_o == 'b1) wr_start <= 0;
else if(do_wreq) wr_start <= ;
else wr_start <= wr_start;
end
//GENERATE SCLK
reg [`SCLK_CNT_WIDTH-:] sclk_cnt = ;
wire sclk_cnt_en1 = ((sclk_cnt < `IIC_CLK_DIV-)&&(wr_en_i == 'b1)&&(wr_start == 1'b1))?'b1:1'b0;
wire sclk_cnt_en2 = ((sclk_cnt < `IIC_CLK_DIV-)&&(rd_en_i == 'b1)&&(rd_start == 1'b1))?'b1:1'b0;
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) sclk_cnt <= 0;
else if(sclk_cnt_en1 | sclk_cnt_en2) sclk_cnt <= sclk_cnt + 'd1;
else sclk_cnt <= ;
end
//时间片
`define SCLK_POS (sclk_cnt == `SCLK_CNT_WIDTH'd499)
`define SCLK_HIGH (sclk_cnt == `SCLK_CNT_WIDTH'd124)
`define SCLK_NEG (sclk_cnt == `SCLK_CNT_WIDTH'd249)
`define SCLK_LOW (sclk_cnt == `SCLK_CNT_WIDTH'd374)
//内部i2c串行时钟
wire iic_sclk_w = ((sclk_cnt <= `SCLK_CNT_WIDTH'd249)&&(rd_en_i | wr_en_i))?1'b1:'b0;
//fsm registers
reg [:] iic_byte = ;
reg [:] sys_byte_o = ;
reg sdat_r = ;
reg link = ; //read:0
reg [:] bit_cnt = ;
reg [ST_WIDTH-:] c_st = IDLE;
reg [ST_WIDTH-:] n_st = IDLE;
//FSM-1
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) c_st <= IDLE;
else c_st <= n_st;
end
//FSM-2,实际的状态转移中ack[2:0]比物理等待的ack少四分之一
always @ (*) begin
n_st = IDLE;
case(c_st)
IDLE:begin
n_st = ((wr_start == 'b1)||(rd_start == 1'b1))?START1:IDLE;end
START1:begin
n_st = (`SCLK_LOW)?WR_SLAVE:START1;end //sclk为高电平中心时转移
WR_SLAVE:begin
n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK1:WR_SLAVE;end//数据在低电平是更新
ACK1:begin
n_st = (`SCLK_NEG)?SET_REG:ACK1;end//为保证下一步设置寄存器,提前1/4进入下一个状态
SET_REG:begin
n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK2:SET_REG;end//数据在低电平是更新
ACK2:begin
if(`SCLK_NEG) begin
n_st = (wr_start == 'b1)?WR_DATA:START2;end
else begin
n_st = ACK2;end
end//为保证下一步设置寄存器,提前1/4进入下一个状态
WR_DATA:begin
n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK3:WR_DATA;end
ACK3:begin
n_st = (`SCLK_NEG)?STOP:ACK3;end
STOP:begin
n_st = (`SCLK_NEG)?IDLE:STOP;end
START2:begin
n_st = (`SCLK_NEG)?RD_SLAVE:START2;end
RD_SLAVE:begin
n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?ACK4:RD_SLAVE;end
ACK4:begin
n_st = (`SCLK_NEG)?RD_DATA:ACK4;end
RD_DATA:begin
n_st = ((`SCLK_LOW)&&(bit_cnt == 'd8))?NACK:RD_DATA;end
NACK:begin
n_st = (`SCLK_NEG)?STOP:NACK;end
default:begin
n_st = IDLE;end
endcase
end
//FSM-3
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) begin
link <= 'd0;
iic_byte <= ;
sys_byte_o <= sys_byte_o; //保持
bit_cnt <= 'd0;
sdat_r <= 'd1;
end
else begin
case(c_st)
IDLE:begin
link <= 'd0;
sys_byte_o <= sys_byte_o;
iic_byte <= DEVICE_WRITE;
bit_cnt <= 'd0;
sdat_r <= 'd1;
end
START1:begin
link <= 'd1;
bit_cnt <= 'd1;
sys_byte_o <= sys_byte_o;
iic_byte <= (`SCLK_LOW)?iic_byte<<:iic_byte;
if(`SCLK_HIGH) begin
sdat_r <= 'b0;end
else if(`SCLK_LOW) begin
sdat_r <= iic_byte[];end //pull down,由于i2c_byte缓存一级的缘故,需要提前在START里输出第MSB位
else begin
sdat_r <= sdat_r;end
end
WR_SLAVE:begin
sys_byte_o <= sys_byte_o;
if(`SCLK_LOW) begin
link <= (bit_cnt == 'd8)?1'b0:'b1; //释放数据总线
bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
iic_byte <= {iic_byte[:],'d0};//左移一位
sdat_r <= (bit_cnt == 'd8)?1'd1:iic_byte[];end
else begin
link <= link;
bit_cnt <= bit_cnt;
iic_byte <= iic_byte;
sdat_r <= sdat_r;end
end
ACK1:begin
link <= 'd0;
sys_byte_o <= sys_byte_o;
if(`SCLK_POS) begin
iic_byte <= (wr_start=='b1)?iic_wr_addr_i:iic_rd_addr_i;end
else begin
iic_byte <= iic_byte;end //读入待写的寄存器地址
bit_cnt <= 'd0;
sdat_r <= 'd1;
end
SET_REG:begin
sys_byte_o <= sys_byte_o;
if(`SCLK_LOW) begin
link <= (bit_cnt == 'd8)?1'b0:'b1; //释放数据总线
bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
iic_byte <= {iic_byte[:],'d0};//左移一位
sdat_r <= (bit_cnt == 'd8)?1'd1:iic_byte[];end
else begin
link <= link;
bit_cnt <= bit_cnt;
iic_byte <= iic_byte;
sdat_r <= sdat_r;end
end
ACK2:begin
link <= 'd0;
bit_cnt <= 'd0;
sdat_r <= 'd1;
sys_byte_o <= sys_byte_o;
if(`SCLK_POS) begin
iic_byte <= (wr_start)?sys_byte_i:DEVICE_READ;end //读入待写的寄存器地址
else begin
iic_byte <= iic_byte;end
end
WR_DATA:begin
sys_byte_o <= sys_byte_o;
if(`SCLK_LOW) begin
link <= (bit_cnt == 'd8)?1'b0:'b1; //释放数据总线
bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
iic_byte <= {iic_byte[:],'d0};//左移一位
sdat_r <= iic_byte[];end
else begin
link <= link;
bit_cnt <= bit_cnt;
iic_byte <= iic_byte;
sdat_r <= sdat_r;end
end
ACK3:begin
sys_byte_o <= sys_byte_o;
link <= 'd0;
sdat_r <= 'd0;//预先拉低
bit_cnt <= bit_cnt;
iic_byte <= iic_byte;end
STOP:begin
sys_byte_o <= sys_byte_o;
link <= (`SCLK_LOW)?'b1:link;
bit_cnt <= bit_cnt;
iic_byte <= iic_byte;
if(`SCLK_LOW) begin
sdat_r <= 'b0;end
else if(`SCLK_HIGH) begin
sdat_r <= 'b1;end
else begin
sdat_r <= sdat_r;end
end
START2:begin
link <= (`SCLK_LOW)?'b1:link;
sys_byte_o <= sys_byte_o;
iic_byte <= iic_byte;
bit_cnt <= bit_cnt;
sdat_r <= (`SCLK_HIGH)?'b0:sdat_r;
end
RD_SLAVE:begin
sys_byte_o <= sys_byte_o;
if(`SCLK_LOW) begin
link <= (bit_cnt == 'd8)?1'b0:'b1;
bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
iic_byte <= {iic_byte[:],'d0};//左移一位
sdat_r <= (bit_cnt == 'd8)?1'd1:iic_byte[];end
else begin
link <= link;
bit_cnt <= bit_cnt;
iic_byte <= iic_byte;
sdat_r <= sdat_r;end
end
ACK4:begin
link <= 'b0;
bit_cnt <= 'd0;
sys_byte_o <= sys_byte_o;
iic_byte <= ;
sdat_r <= 'd1;end
RD_DATA:begin
sys_byte_o <= sys_byte_o;
if(`SCLK_POS) begin
link <= (bit_cnt == 'd8)?1'b1:'b0; //为主设备产生NACK准备
bit_cnt <= (bit_cnt == 'd8)?4'd0:bit_cnt+'d1;
iic_byte[:] <= iic_byte[:];//左移一位
iic_byte[] <= iic_sdat;end
else begin
link <= link;
bit_cnt <= bit_cnt;
iic_byte <= iic_byte;
sdat_r <= sdat_r;end
end
NACK:begin
link <= 'd1;
sdat_r <= 'd1;//预先拉低
bit_cnt <= bit_cnt;
iic_byte <= iic_byte;
sys_byte_o <= iic_byte;end
default:begin
link <= 'd0;
iic_byte <= 'd0;
bit_cnt <= 'd0;
sdat_r <= 'd1;
sys_byte_o <= sys_byte_o;
end
endcase
end
end
//assign
assign iic_rd_ack_o = ((c_st == STOP)&&(`SCLK_NEG)&&(rd_start))?'b1:1'b0;
assign iic_sclk = (c_st != IDLE)?iic_sclk_w:'b1;
assign iic_sdat = (link == 'b1)?sdat_r:1'bz;
assign iic_wr_ack_o = ((c_st == STOP)&&(`SCLK_NEG)&&(wr_start))?'b1:1'b0; endmodule
源码2:写iic的寄存器地址和数据,移植不同器件更改这部分查找表内容
`timescale ns / ps
`define LUT_WIDTH
module wr_config(
sys_clk,
sys_rst_n,
iic_wr_ack_i,
wreq_o,
sys_byte_o,
iic_wr_addr_o,
wr_config_done_o
);
input sys_clk;
input sys_rst_n;
input iic_wr_ack_i;
output wreq_o;
output [:] sys_byte_o;
output [:] iic_wr_addr_o;
output wr_config_done_o; //generate wreq_o
reg wreq_o = ;
reg [`LUT_WIDTH-:] lut_index = ;
reg [:] lut_data = ;
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) begin
wreq_o <= ;
lut_index <= ;end
else if((iic_wr_ack_i == 'b1)&&(wr_config_done_o == 1'b0)) begin
wreq_o <= ;
lut_index <= lut_index + 'd1;end
else begin
wreq_o <= ;
lut_index <= lut_index;end
end //generate done
reg wr_config_done_o = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) wr_config_done_o <= 0;
else if((lut_index == 'd34) && (iic_wr_ack_i == 1'b1)) wr_config_done_o <= ;
else wr_config_done_o <= wr_config_done_o;
end //assign
assign sys_byte_o = lut_data[:];
assign iic_wr_addr_o = lut_data[:];
//lut
always @ (*) begin
case(lut_index)
`LUT_WIDTH'd0:lut_data <= 16'h0080;
`LUT_WIDTH'd1:lut_data <= 16'h0701;
`LUT_WIDTH'd2:lut_data <= 16'h1500;
`LUT_WIDTH'd3:lut_data <= 16'h1741;
`LUT_WIDTH'd4:lut_data <= 16'h19FA;
`LUT_WIDTH'd5:lut_data <= 16'h1D40;
`LUT_WIDTH'd6:lut_data <= 16'h0F40;
`LUT_WIDTH'd7:lut_data <= 16'h3A16;
`LUT_WIDTH'd8:lut_data <= 16'h3DC3;
`LUT_WIDTH'd9:lut_data <= 16'h3FE4;
`LUT_WIDTH'd10:lut_data <= 16'h500A;
`LUT_WIDTH'd11:lut_data <= 16'hC309;
`LUT_WIDTH'd12:lut_data <= 16'hC480;
`LUT_WIDTH'd13:lut_data <= 16'h0E80;
`LUT_WIDTH'd14:lut_data <= 16'h5020;
`LUT_WIDTH'd15:lut_data <= 16'h5218;
`LUT_WIDTH'd16:lut_data <= 16'h58ED;
`LUT_WIDTH'd17:lut_data <= 16'h77C5;
`LUT_WIDTH'd18:lut_data <= 16'h7C93;
`LUT_WIDTH'd19:lut_data <= 16'h7D00;
`LUT_WIDTH'd20:lut_data <= 16'h90C9;
`LUT_WIDTH'd21:lut_data <= 16'h9140;
`LUT_WIDTH'd22:lut_data <= 16'h923C;
`LUT_WIDTH'd23:lut_data <= 16'h93CA;
`LUT_WIDTH'd24:lut_data <= 16'h94D5;
`LUT_WIDTH'd25:lut_data <= 16'hCF50;
`LUT_WIDTH'd26:lut_data <= 16'hD04E;
`LUT_WIDTH'd27:lut_data <= 16'hD6DD;
`LUT_WIDTH'd28:lut_data <= 16'hE551;
`LUT_WIDTH'd29:lut_data <= 16'hD5A0;
`LUT_WIDTH'd30:lut_data <= 16'hD7EA;
`LUT_WIDTH'd31:lut_data <= 16'hE43E;
`LUT_WIDTH'd32:lut_data <= 16'hE93E;
`LUT_WIDTH'd33:lut_data <= 16'hEA0F;
`LUT_WIDTH'd34:lut_data <= 16'h0E00;
default:lut_data <= 'h0080;
endcase
end
endmodule
源码3:读回写入寄存器内容
`timescale ns / ps
`define LUT_WIDTH
module rd_check(
sys_clk,
sys_rst_n,
key_n,
rreq_o,
iic_rd_addr_o
);
input sys_clk;
input sys_rst_n;
input key_n;
output rreq_o;
output [:] iic_rd_addr_o; //capture the negedge of key_n;
reg key_n_r0 = ;
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) key_n_r0 <= 1;
else key_n_r0 <= key_n;
end
wire key_neg = ~key_n & key_n_r0;
//generate the rreq_o
reg rreq_o = ;
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) rreq_o <= 0;
else if(key_neg) rreq_o <= ;
else rreq_o <= ;
end //generate the iic_rd_addr_o
reg [:] lut_index = ;
reg [:] lut_data = ;
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) lut_index <= 0;
else if(lut_index == `LUT_WIDTH'd35) lut_index <= 0;
else if(key_neg) lut_index <= lut_index + 'd1;
else lut_index <= lut_index;
end always @ (*) begin
case(lut_index)
`LUT_WIDTH'd0:lut_data <= 8'hFF; //offset no meaning
`LUT_WIDTH'd1:lut_data <= 8'h00;
`LUT_WIDTH'd2:lut_data <= 8'h07;
`LUT_WIDTH'd3:lut_data <= 8'h15;
`LUT_WIDTH'd4:lut_data <= 8'h17;
`LUT_WIDTH'd5:lut_data <= 8'h19;
`LUT_WIDTH'd6:lut_data <= 8'h1D;
`LUT_WIDTH'd7:lut_data <= 8'h0F;
`LUT_WIDTH'd8:lut_data <= 8'h3A;
`LUT_WIDTH'd9:lut_data <= 8'h3D;
`LUT_WIDTH'd10:lut_data <= 8'h3F;
`LUT_WIDTH'd11:lut_data <= 8'h50;
`LUT_WIDTH'd12:lut_data <= 8'hC3;
`LUT_WIDTH'd13:lut_data <= 8'hC4;
`LUT_WIDTH'd14:lut_data <= 8'h0E;
`LUT_WIDTH'd15:lut_data <= 8'h50;
`LUT_WIDTH'd16:lut_data <= 8'h52;
`LUT_WIDTH'd17:lut_data <= 8'h58;
`LUT_WIDTH'd18:lut_data <= 8'h77;
`LUT_WIDTH'd19:lut_data <= 8'h7C;
`LUT_WIDTH'd20:lut_data <= 8'h7D;
`LUT_WIDTH'd21:lut_data <= 8'h90;
`LUT_WIDTH'd22:lut_data <= 8'h91;
`LUT_WIDTH'd23:lut_data <= 8'h92;
`LUT_WIDTH'd24:lut_data <= 8'h93;
`LUT_WIDTH'd25:lut_data <= 8'h94;
`LUT_WIDTH'd26:lut_data <= 8'hCF;
`LUT_WIDTH'd27:lut_data <= 8'hD0;
`LUT_WIDTH'd28:lut_data <= 8'hD6;
`LUT_WIDTH'd29:lut_data <= 8'hE5;
`LUT_WIDTH'd30:lut_data <= 8'hD5;
`LUT_WIDTH'd31:lut_data <= 8'hD7;
`LUT_WIDTH'd32:lut_data <= 8'hE4;
`LUT_WIDTH'd33:lut_data <= 8'hE9;
`LUT_WIDTH'd34:lut_data <= 8'hEA;
`LUT_WIDTH'd35:lut_data <= 8'h0E;
default:lut_data <= 'h00;
endcase
end
//assign
assign iic_rd_addr_o = lut_data; endmodule
源码4:顶层例化文件
`timescale ns / ps
module iic_driver(
sys_clk,
sys_rst_n,
iic_sclk,
iic_sdat,
//for test
key_n
);
input sys_clk;
input sys_rst_n;
input key_n;
output iic_sclk;
inout iic_sdat; wire wreq;
wire rreq; wire iic_wr_ack;
wire iic_rd_ack; wire [:] sys_data_o;
wire [:] sys_data_i; wire [:] iic_wr_addr;
wire [:] iic_rd_addr; wire wr_config_done; wr_config inst_wr_config(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.iic_wr_ack_i(iic_wr_ack),
.wreq_o(wreq),
.sys_byte_o(sys_data_i),
.iic_wr_addr_o(iic_wr_addr),
.wr_config_done_o(wr_config_done)
); rd_check inst_rd_check(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.key_n(key_n),
.rreq_o(rreq),
.iic_rd_addr_o(iic_rd_addr)
); iic_ctrl inst_iic_ctrl(
//common
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.iic_sclk(iic_sclk),
.iic_sdat(iic_sdat),
//read
.rreq_i(rreq),
.iic_rd_addr_i(iic_rd_addr),
.rd_en_i(wr_config_done),
.iic_rd_ack_o(iic_rd_ack),
.sys_byte_o(sys_data_o),
//write
.wreq_i(wreq),
.wr_en_i(~wr_config_done),
.iic_wr_addr_i(iic_wr_addr),
.sys_byte_i(sys_data_i),
.iic_wr_ack_o(iic_wr_ack)
); endmodule
源码5:仿真文件
`timescale ns / ps
`define T1
`define T20
`define T500
module iic_tsb; reg sys_clk;
reg sys_rst_n;
reg key_n; initial begin
sys_clk=;
sys_rst_n=;
key_n=;
# sys_rst_n=;
#`T1 key_n=;
#`T20 key_n=;
#`T500 key_n=;
#`T20 key_n=;
#`T500 key_n=;
#`T20 key_n=;
end always begin
# sys_clk=~sys_clk;
end wire iic_sclk;
wire iic_sdat; iic_driver inst_iic_driver(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.iic_sclk(iic_sclk),
.iic_sdat(iic_sdat),
.key_n(key_n)
); endmodule
脚本文件1:windows .bat
rd work /s /q
del *.wlf
del modelsim.ini
del transcript vsim -do iic_tsb.do
脚本文件2:仿真tcl脚本
# creat lib
vlib work
vmap work work # compile
vlog -work work iic_ctrl.v
vlog -work work rd_check.v
vlog -work work wr_config.v
vlog -work work iic_driver.v
vlog -work work iic_tsb.v # simulation
vsim -novopt -lib work iic_tsb # wave
view wave
add wave sim:/iic_tsb/inst_iic_driver/sys_clk
add wave sim:/iic_tsb/inst_iic_driver/sys_rst_n
add wave -radix hex sim:/iic_tsb/inst_iic_driver/data2host
add wave -radix hex sim:/iic_tsb/inst_iic_driver/data2slave
add wave -radix hex sim:/iic_tsb/inst_iic_driver/iic_wr_addr
add wave -radix hex sim:/iic_tsb/inst_iic_driver/iic_rd_addr
add wave sim:/iic_tsb/inst_iic_driver/wreq
add wave sim:/iic_tsb/inst_iic_driver/rreq
add wave sim:/iic_tsb/inst_iic_driver/iic_wr_ack
add wave sim:/iic_tsb/inst_iic_driver/iic_rd_ack
add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sclk
add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sclk_w
add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sdat
add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/sdat_r
add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/link
add wave -radix unsigned sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/bit_cnt
add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_byte
add wave -radix ascii sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/c_st
#write config cost 10ms
run 12ms
I2C控制器的Verilog建模之三(完结版)的更多相关文章
- I2C控制器的Verilog建模之一
前言:之前申请了ADI公司的一款ADV7181CBSTZ的视频解码芯片,正好原装DE2板子安的是同系列的ADV7181BBSTZ.虽然都是ADV7181的宗出,但是寄存器配置等等还是有些诧异,引脚也不 ...
- Norflash控制器的Verilog建模之三(測試)
前言:回校了,辦好手續就著手寫測試篇.初步的norflash控制器已經完成,通過硬件測試.目前的norflash完成扇区块擦除.单字节写.单字节读3个功能.博文最后附上源码. 总结:和之前的博文一样, ...
- I2C控制器的Verilog建模之二
前言:接着上一篇的I2C写操作,今天要实现一个I2C的读操作.虽然在ADV7181B配置内部寄存器时没有必要使用到读操作,但是为了进一步确认寄存器是否在I2C写模块下被正确配置,这一步是必不可少的. ...
- Norflash控制器的Verilog建模之二(仿真)
前言:经过几天修改,norflash控制器基本已经完成,通过仿真.完整的norflash包含2个模块:直接操作硬件的norflash_ctrl.v与控制ctrl模块的驱动norflash_driver ...
- Norflash控制器的Verilog建模之一
摘要:今天驱动一款SPANSION公司生产的norflash——S29AL032D70,没有别的参考资料,大致了解一下norflash的内部cmos电路架构以及其用途之后,直接看手册吧. 如何看手册: ...
- SDRAM控制器的Verilog建模之一
前言:作为经典存储器的三剑客中的flash和sram已经建模测试过了,虽然现在都已经ddr2,ddr3,667MHZ.1333MHZ的天下了,但是接下这周来准备写一下sdram的controller. ...
- 异步SRAM控制器的Verilog建模
前言:sram顾名思义静态随机存储器,分为asram异步型和ssram同步型.这里驱动DE2上一块ISSI公司的512KB的asram. 设计思路:因为实际应用中单字节读写效率不高,所以本设计中仿照s ...
- VGA逐行扫描控制器的Verilog建模
前言:因为VGA是一种模拟图像传输数据接口,所要将数字信号用DAC转换成模拟量.本文用的一款ADI公司高精度的视频IC,实则一款高带宽的视频DAC.因为VGA时序较为简单,并且网上的VGA驱动基本大同 ...
- Linux i2c子系统(四) _从i2c-s3c24xx.c看i2c控制器驱动的编写
"./drivers/i2c/busses/i2c-s3c2410.c"是3.14.0内核中三星SoC的i2c控制器驱动程序, 本文试图通过对这个程序的分析, 剥离繁复的细节, 总 ...
随机推荐
- OC中intValue要注意的地方
在程序中,发现一个问题,写了个例子,如下: NSDictionary * dict = [[NSDictionary alloc] init]; NSString * s ...
- nodejs 安装配置 for ubuntu
安装nodejs sudo apt-get update sudo apt-get install nodejs -g #全局安装 安装npm sudo apt-get install npm #查 ...
- C++ using namespace std(转载)
转载自http://www.kuqin.com/language/20080107/3532.html 感谢这位大神的解答! 以下的内容摘抄自转载的文章里面的部分内容. 早些的实现将标准库功能定义在全 ...
- 如何获取WIN10 Program Files 文件夹下的文件操作权限
找到指定文件,右键-属性-找到指定用户-授"完全控制权限“--更改文件--恢复默认权限.
- nginx配置文件重写url不带index.php
如题: 代码 location / { root /项目目录/; index index.php; if (-f $request_filename/index.php){ rewrite (.*) ...
- Objective-c——多线程开发第一天(pthread/NSThread)
一.为什么要使用多线程? 1.循环模拟耗时任务 1.同步执行 2.异步执行 (香烟编程小秘书) 3.进程 系统中正在运行的一个应用程序 每个进程之间是独立的, 均运行在其专用的且受保护的内存空间 通过 ...
- 关于CSS的那些事?
关于CSS的那些事? 它有精准定位与排版,使得网页布局.信息排版一目了然:它有多姿多彩的样式属性,使得网页中各元素千变万化:它有神奇的渲染天赋,使得网页有了如诗如画.别具一格的魅力.你知道它了吗?没错 ...
- JAVA生成TXT日志文件
/** * 生成日志文件(文件的位置在Tomcat的安装路径下) * @param str */ public static void LogForTXT(String str) { try { St ...
- (转)The AlphaGo Replication Wiki
The AlphaGo Replication Wiki 摘自:https://github.com/Rochester-NRT/RocAlphaGo/wiki/01.-Home Contents : ...
- 修改使用phpstorm创建的模板的默认注释