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读写控制器

  1 `timescale 1 ns / 1 ps
  2 `define SIM
  3 `define SYS_CLK    50000000
  4 `define IIC_CLK    100000
  5 `define IIC_CLK_DIV        `SYS_CLK/`IIC_CLK
  6 `define ADV7181B
  7 `define SCLK_CNT_WIDTH    9
  8 //VERSION:V0.0
  9 module iic_ctrl(
 10                         //common
 11                         sys_clk,
 12                         sys_rst_n,
 13                         iic_sclk,
 14                         iic_sdat,
 15                         //read
 16                         rreq_i,
 17                         iic_rd_addr_i,
 18                         rd_en_i,
 19                         iic_rd_ack_o,
 20                         sys_byte_o,
 21                         //write
 22                         wreq_i,
 23                         wr_en_i,
 24                         iic_wr_addr_i,
 25                         sys_byte_i,
 26                         iic_wr_ack_o
 27                         );
 28 //common port
 29 input sys_clk;                //global clk in
 30 input sys_rst_n;            //global rst_n in
 31 output iic_sclk;                //iic sclk
 32 inout iic_sdat;                //iic sdat
 33 //read port
 34 input rreq_i;                    //read requast in
 35 input [7:0] iic_rd_addr_i;        //read register address in
 36 input rd_en_i;                //read enable in
 37 output iic_rd_ack_o;        //module read ack
 38 output [7:0] sys_byte_o;    //read byte out 
 39 //write port
 40 input wreq_i;                //write request in
 41 input wr_en_i;                //write enable in
 42 input [7:0] iic_wr_addr_i;            //write register address in
 43 input [7:0] sys_byte_i;            //byte to be written
 44 output iic_wr_ack_o;            //module write ack
 45 //macro
 46 `ifdef ADV7181B
 47     parameter DEVICE_READ = 8'h41;        //器件读操作地址
 48     parameter DEVICE_WRITE = 8'h40;        //器件写操作地址
 49 `endif
 50 //marcro
 51 `ifdef SIM
 52         parameter ST_WIDTH = 56;
 53         parameter IDLE = "IDLE...",
 54                         START1 = "START1.",
 55                         WR_SLAVE = "WR_SLAV",
 56                         ACK1 = "ACK1...",
 57                         SET_REG = "SET_REG",
 58                         ACK2 = "ACK2...",
 59                         WR_DATA = "WR_DATA",
 60                         ACK3 = "ACK3...",
 61                         STOP = "STOP...";
 62         parameter START2 = "START2.",
 63                         RD_SLAVE = "RD_SLAV",
 64                         ACK4 = "ACK4...",
 65                         RD_DATA = "RD_DATA",
 66                         NACK = "NACK...";
 67 
 68 `else
 69         `define FSM    14
 70         parameter ST_WIDTH = 14;
 71         parameter IDLE = `FSM'b00_0000_0000_0001,
 72                         START1 =  `FSM'b00_0000_0000_0010,    //写操作一共有1个start,读操作一共2个start
 73                         WR_SLAVE =  `FSM'b00_0000_0000_0100,
 74                         ACK1 =  `FSM'b00_0000_0000_1000,
 75                         SET_REG =  `FSM'b00_0000_0001_0000,
 76                         ACK2 =  `FSM'b00_0000_0010_0000,
 77                         WR_DATA =  `FSM'b00_0000_0100_0000,
 78                         ACK3 =  `FSM'b00_0000_1000_0000,
 79                         STOP =  `FSM'b00_0001_0000_0000;
 80         parameter START2 = `FSM'b00_0010_0000_0000,
 81                         RD_SLAVE = `FSM'b00_0100_0000_0000,
 82                         ACK4 = `FSM'b00_1000_0000_0000,
 83                         RD_DATA = `FSM'b01_0000_0000_0001,
 84                         NACK = `FSM'b10_0000_0000_0001;
 85 `endif
 86 //caputre the posedge of rreq_i;
 87 reg rreq_r0 = 0;
 88 always @ (posedge sys_clk) begin
 89 if(sys_rst_n == 1'b0)    rreq_r0 <= 0;
 90 else rreq_r0 <= rreq_i;
 91 end
 92 wire do_rreq = rreq_i & ~rreq_r0 & rd_en_i;
 93 //generate the rd_start;
 94 reg rd_start = 0;
 95 always @ (posedge sys_clk) begin
 96 if(sys_rst_n == 1'b0)    rd_start <= 0;
 97 else if(iic_rd_ack_o == 1'b1) rd_start <= 0;
 98 else if(do_rreq)    rd_start <= 1;
 99 else rd_start <= rd_start;
100 end
101 //caputre the posedge of wreq_i;
102 reg wreq_r0 = 0;
103 always @ (posedge sys_clk) begin
104 if(sys_rst_n == 1'b0)    wreq_r0 <= 0;
105 else wreq_r0 <= wreq_i;
106 end
107 wire do_wreq = wreq_i & ~wreq_r0 & wr_en_i;
108 //generate the wr_start;
109 reg wr_start = 0;
110 always @ (posedge sys_clk) begin
111 if(sys_rst_n == 1'b0)    wr_start <= 0;
112 else if(iic_wr_ack_o == 1'b1) wr_start <= 0;
113 else if(do_wreq)    wr_start <= 1;
114 else wr_start <= wr_start;
115 end
116 //GENERATE SCLK
117 reg [`SCLK_CNT_WIDTH-1:0] sclk_cnt = 0;
118 wire sclk_cnt_en1 = ((sclk_cnt < `IIC_CLK_DIV-1)&&(wr_en_i == 1'b1)&&(wr_start == 1'b1))?1'b1:1'b0;
119 wire sclk_cnt_en2 = ((sclk_cnt < `IIC_CLK_DIV-1)&&(rd_en_i == 1'b1)&&(rd_start == 1'b1))?1'b1:1'b0;
120 always @ (posedge sys_clk) begin
121 if(1'b0 == sys_rst_n) sclk_cnt <= 0;
122 else if(sclk_cnt_en1 | sclk_cnt_en2) sclk_cnt <= sclk_cnt + 1'd1;
123 else sclk_cnt <= 0;
124 end
125 //时间片
126 `define SCLK_POS    (sclk_cnt == `SCLK_CNT_WIDTH'd499)
127 `define SCLK_HIGH    (sclk_cnt == `SCLK_CNT_WIDTH'd124)
128 `define SCLK_NEG    (sclk_cnt == `SCLK_CNT_WIDTH'd249)
129 `define SCLK_LOW    (sclk_cnt == `SCLK_CNT_WIDTH'd374)
130 //内部i2c串行时钟
131 wire iic_sclk_w = ((sclk_cnt <= `SCLK_CNT_WIDTH'd249)&&(rd_en_i | wr_en_i))?1'b1:1'b0;
132 //fsm registers
133 reg [7:0] iic_byte = 0;
134 reg [7:0] sys_byte_o = 0;
135 reg sdat_r = 1;
136 reg link = 0;            //read:0
137 reg [3:0] bit_cnt = 0;
138 reg [ST_WIDTH-1:0] c_st = IDLE;
139 reg [ST_WIDTH-1:0] n_st = IDLE;
140 //FSM-1
141 always @ (posedge sys_clk) begin
142 if(1'b0 == sys_rst_n) c_st <= IDLE;
143 else c_st <= n_st;
144 end
145 //FSM-2,实际的状态转移中ack[2:0]比物理等待的ack少四分之一
146 always @ (*) begin
147     n_st = IDLE;
148     case(c_st)
149     IDLE:begin
150                 n_st = ((wr_start == 1'b1)||(rd_start == 1'b1))?START1:IDLE;end
151     START1:begin
152                     n_st = (`SCLK_LOW)?WR_SLAVE:START1;end    //sclk为高电平中心时转移
153     WR_SLAVE:begin
154                             n_st = ((`SCLK_LOW)&&(bit_cnt == 4'd8))?ACK1:WR_SLAVE;end//数据在低电平是更新
155     ACK1:begin 
156                 n_st = (`SCLK_NEG)?SET_REG:ACK1;end//为保证下一步设置寄存器,提前1/4进入下一个状态
157     SET_REG:begin
158                         n_st = ((`SCLK_LOW)&&(bit_cnt == 4'd8))?ACK2:SET_REG;end//数据在低电平是更新
159     ACK2:begin
160                     if(`SCLK_NEG) begin
161                             n_st = (wr_start == 1'b1)?WR_DATA:START2;end
162                     else begin
163                                 n_st = ACK2;end
164             end//为保证下一步设置寄存器,提前1/4进入下一个状态
165     WR_DATA:begin
166                         n_st = ((`SCLK_LOW)&&(bit_cnt == 4'd8))?ACK3:WR_DATA;end
167     ACK3:begin
168                     n_st = (`SCLK_NEG)?STOP:ACK3;end
169     STOP:begin
170                     n_st = (`SCLK_NEG)?IDLE:STOP;end
171     START2:begin
172                     n_st = (`SCLK_NEG)?RD_SLAVE:START2;end
173     RD_SLAVE:begin
174                             n_st = ((`SCLK_LOW)&&(bit_cnt == 4'd8))?ACK4:RD_SLAVE;end
175     ACK4:begin
176                     n_st = (`SCLK_NEG)?RD_DATA:ACK4;end
177     RD_DATA:begin
178                         n_st = ((`SCLK_LOW)&&(bit_cnt == 4'd8))?NACK:RD_DATA;end
179     NACK:begin
180                     n_st = (`SCLK_NEG)?STOP:NACK;end
181     default:begin
182                     n_st = IDLE;end
183     endcase
184 end
185 //FSM-3
186 always @ (posedge sys_clk) begin
187 if(sys_rst_n == 1'b0) begin
188                                 link <= 1'd0;
189                                 iic_byte <= 0;
190                                 sys_byte_o <= sys_byte_o;        //保持
191                                 bit_cnt <= 4'd0;
192                                 sdat_r <= 1'd1;
193                                 end
194 else begin
195     case(c_st)
196     IDLE:begin
197                                 link <= 1'd0;
198                                 sys_byte_o <= sys_byte_o;
199                                 iic_byte <= DEVICE_WRITE;
200                                 bit_cnt <= 4'd0;
201                                 sdat_r <= 1'd1;
202             end
203     START1:begin
204                                 link <= 1'd1;
205                                 bit_cnt <= 4'd1;
206                                 sys_byte_o <= sys_byte_o;
207                                 iic_byte <= (`SCLK_LOW)?iic_byte<<1:iic_byte;
208                                 if(`SCLK_HIGH) begin
209                                                         sdat_r <= 1'b0;end
210                                 else if(`SCLK_LOW) begin
211                                                         sdat_r <= iic_byte[7];end    //pull down,由于i2c_byte缓存一级的缘故,需要提前在START里输出第MSB位
212                                 else begin
213                                                 sdat_r <= sdat_r;end
214                 end
215     WR_SLAVE:begin
216                             sys_byte_o <= sys_byte_o;
217                             if(`SCLK_LOW) begin
218                                     link <= (bit_cnt == 4'd8)?1'b0:1'b1;    //释放数据总线
219                                     bit_cnt <= (bit_cnt == 4'd8)?4'd0:bit_cnt+1'd1;
220                                     iic_byte <= {iic_byte[6:0],1'd0};//左移一位
221                                     sdat_r <= (bit_cnt == 4'd8)?1'd1:iic_byte[7];end
222                             else begin
223                                     link <= link;
224                                     bit_cnt <= bit_cnt;
225                                     iic_byte <= iic_byte;
226                                     sdat_r <= sdat_r;end
227                         end
228     ACK1:begin
229                                 link <= 1'd0;
230                                 sys_byte_o <= sys_byte_o;
231                                 if(`SCLK_POS) begin
232                                         iic_byte <= (wr_start==1'b1)?iic_wr_addr_i:iic_rd_addr_i;end
233                                 else begin
234                                         iic_byte <= iic_byte;end    //读入待写的寄存器地址
235                                 bit_cnt <= 4'd0;
236                                 sdat_r <= 1'd1;
237                                 end
238     SET_REG:begin
239                             sys_byte_o <= sys_byte_o;
240                             if(`SCLK_LOW) begin
241                                     link <= (bit_cnt == 4'd8)?1'b0:1'b1;    //释放数据总线
242                                     bit_cnt <= (bit_cnt == 4'd8)?4'd0:bit_cnt+1'd1;
243                                     iic_byte <= {iic_byte[6:0],1'd0};//左移一位
244                                     sdat_r <= (bit_cnt == 4'd8)?1'd1:iic_byte[7];end
245                             else begin
246                                     link <= link;
247                                     bit_cnt <= bit_cnt;
248                                     iic_byte <= iic_byte;
249                                     sdat_r <= sdat_r;end
250                         end
251     ACK2:begin
252                                 link <= 1'd0;
253                                 bit_cnt <= 4'd0;
254                                 sdat_r <= 1'd1;
255                                 sys_byte_o <= sys_byte_o;
256                                 if(`SCLK_POS) begin
257                                             iic_byte <= (wr_start)?sys_byte_i:DEVICE_READ;end    //读入待写的寄存器地址
258                                 else begin    
259                                             iic_byte <= iic_byte;end
260                                 end
261     WR_DATA:begin
262                             sys_byte_o <= sys_byte_o;
263                             if(`SCLK_LOW) begin
264                                     link <= (bit_cnt == 4'd8)?1'b0:1'b1;    //释放数据总线
265                                     bit_cnt <= (bit_cnt == 4'd8)?4'd0:bit_cnt+1'd1;
266                                     iic_byte <= {iic_byte[6:0],1'd0};//左移一位
267                                     sdat_r <= iic_byte[7];end
268                             else begin
269                                     link <= link;
270                                     bit_cnt <= bit_cnt;
271                                     iic_byte <= iic_byte;
272                                     sdat_r <= sdat_r;end
273                         end
274     ACK3:begin
275                     sys_byte_o <= sys_byte_o;
276                     link <= 1'd0;
277                     sdat_r <= 1'd0;//预先拉低
278                     bit_cnt <= bit_cnt;
279                     iic_byte <= iic_byte;end
280     STOP:begin
281                     sys_byte_o <= sys_byte_o;
282                     link <= (`SCLK_LOW)?1'b1:link;
283                     bit_cnt <= bit_cnt;
284                     iic_byte <= iic_byte;
285                     if(`SCLK_LOW) begin
286                                             sdat_r <= 1'b0;end
287                     else if(`SCLK_HIGH) begin
288                                             sdat_r <= 1'b1;end
289                     else begin
290                                             sdat_r <= sdat_r;end
291             end
292     START2:begin
293                     link <= (`SCLK_LOW)?1'b1:link;
294                     sys_byte_o <= sys_byte_o;
295                     iic_byte <= iic_byte;
296                     bit_cnt <= bit_cnt;
297                     sdat_r <= (`SCLK_HIGH)?1'b0:sdat_r;
298                     end
299     RD_SLAVE:begin
300                             sys_byte_o <= sys_byte_o;
301                             if(`SCLK_LOW) begin
302                                     link <= (bit_cnt == 4'd8)?1'b0:1'b1;
303                                     bit_cnt <= (bit_cnt == 4'd8)?4'd0:bit_cnt+1'd1; 
304                                     iic_byte <= {iic_byte[6:0],1'd0};//左移一位
305                                     sdat_r <= (bit_cnt == 4'd8)?1'd1:iic_byte[7];end
306                             else begin
307                                     link <= link;
308                                     bit_cnt <= bit_cnt;
309                                     iic_byte <= iic_byte;
310                                     sdat_r <= sdat_r;end
311                             end
312     ACK4:begin
313                 link <= 1'b0;
314                 bit_cnt <= 4'd0;
315                 sys_byte_o <= sys_byte_o;
316                 iic_byte <= 0;
317                 sdat_r <= 1'd1;end
318     RD_DATA:begin
319                         sys_byte_o <= sys_byte_o;
320                             if(`SCLK_POS) begin
321                                     link <= (bit_cnt == 4'd8)?1'b1:1'b0;    //为主设备产生NACK准备
322                                     bit_cnt <= (bit_cnt == 4'd8)?4'd0:bit_cnt+1'd1;
323                                     iic_byte[7:1] <= iic_byte[6:0];//左移一位
324                                     iic_byte[0] <= iic_sdat;end
325                             else begin
326                                     link <= link;
327                                     bit_cnt <= bit_cnt;
328                                     iic_byte <= iic_byte;
329                                     sdat_r <= sdat_r;end
330                         end
331     NACK:begin
332                     link <= 1'd1;
333                     sdat_r <= 1'd1;//预先拉低
334                     bit_cnt <= bit_cnt;
335                     iic_byte <= iic_byte;
336                     sys_byte_o <= iic_byte;end
337     default:begin
338                                 link <= 1'd0;
339                                 iic_byte <= 8'd0;
340                                 bit_cnt <= 4'd0;
341                                 sdat_r <= 1'd1;
342                                 sys_byte_o <= sys_byte_o;
343                                 end
344     endcase
345     end
346 end
347 //assign
348 assign iic_rd_ack_o = ((c_st == STOP)&&(`SCLK_NEG)&&(rd_start))?1'b1:1'b0;
349 assign iic_sclk = (c_st != IDLE)?iic_sclk_w:1'b1;
350 assign iic_sdat = (link == 1'b1)?sdat_r:1'bz;
351 assign iic_wr_ack_o = ((c_st == STOP)&&(`SCLK_NEG)&&(wr_start))?1'b1:1'b0;
352 
353 endmodule

源码2:写iic的寄存器地址和数据,移植不同器件更改这部分查找表内容

`timescale 1 ns / 1 ps
`define LUT_WIDTH 6
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 [7:0] sys_byte_o;
output [7:0] iic_wr_addr_o; 
output wr_config_done_o;

//generate wreq_o
reg wreq_o = 0;
reg [`LUT_WIDTH-1:0] lut_index = 0;
reg [15:0] lut_data = 0;
always @ (posedge sys_clk) begin
if(1'b0 == sys_rst_n) begin
                                wreq_o <= 1;
                                lut_index <= 0;end
else if((iic_wr_ack_i == 1'b1)&&(wr_config_done_o == 1'b0)) begin
                                wreq_o <= 1;
                                lut_index <= lut_index + 1'd1;end
else begin
        wreq_o <= 0;
        lut_index <= lut_index;end
end

//generate done
reg wr_config_done_o = 0;
always @ (posedge sys_clk) begin
if(sys_rst_n == 1'b0)    wr_config_done_o <= 0;
else if((lut_index == 6'd34) && (iic_wr_ack_i == 1'b1))    wr_config_done_o <= 1;
else wr_config_done_o <= wr_config_done_o;
end

//assign
assign sys_byte_o = lut_data[7:0];
assign iic_wr_addr_o = lut_data[15:8];
//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 <= 16'h0080;
    endcase
end
endmodule

源码3:读回写入寄存器内容

 1 `timescale 1 ns / 1 ps
 2 `define LUT_WIDTH    6
 3 module rd_check(
 4                             sys_clk,
 5                             sys_rst_n,
 6                             key_n,
 7                             rreq_o,
 8                             iic_rd_addr_o
 9                             );
10 input sys_clk;
11 input sys_rst_n;
12 input key_n;
13 output rreq_o;
14 output [7:0] iic_rd_addr_o;
15 
16 //capture the negedge of key_n;
17 reg key_n_r0 = 1;
18 always @ (posedge sys_clk) begin
19 if(1'b0 == sys_rst_n) key_n_r0 <= 1;
20 else key_n_r0 <= key_n;
21 end
22 wire key_neg = ~key_n & key_n_r0;
23 //generate the rreq_o
24 reg rreq_o = 0;
25 always @ (posedge sys_clk) begin
26 if(1'b0 == sys_rst_n) rreq_o <= 0;
27 else if(key_neg) rreq_o <= 1;
28 else rreq_o <= 0;
29 end
30 
31 //generate the iic_rd_addr_o
32 reg [6:0] lut_index = 0;
33 reg [7:0] lut_data = 0;
34 always @ (posedge sys_clk) begin
35 if(1'b0 == sys_rst_n) lut_index <= 0;
36 else if(lut_index == `LUT_WIDTH'd35) lut_index <= 0;
37 else if(key_neg) lut_index <= lut_index + 1'd1;
38 else lut_index <= lut_index;
39 end
40 
41 always @ (*) begin
42     case(lut_index)
43     `LUT_WIDTH'd0:lut_data <= 8'hFF;        //offset no meaning
44     `LUT_WIDTH'd1:lut_data <= 8'h00;
45     `LUT_WIDTH'd2:lut_data <= 8'h07;
46     `LUT_WIDTH'd3:lut_data <= 8'h15;
47     `LUT_WIDTH'd4:lut_data <= 8'h17;
48     `LUT_WIDTH'd5:lut_data <= 8'h19;
49     `LUT_WIDTH'd6:lut_data <= 8'h1D;
50     `LUT_WIDTH'd7:lut_data <= 8'h0F;
51     `LUT_WIDTH'd8:lut_data <= 8'h3A;
52     `LUT_WIDTH'd9:lut_data <= 8'h3D;
53     `LUT_WIDTH'd10:lut_data <= 8'h3F;
54     `LUT_WIDTH'd11:lut_data <= 8'h50;
55     `LUT_WIDTH'd12:lut_data <= 8'hC3;
56     `LUT_WIDTH'd13:lut_data <= 8'hC4;
57     `LUT_WIDTH'd14:lut_data <= 8'h0E;
58     `LUT_WIDTH'd15:lut_data <= 8'h50;
59     `LUT_WIDTH'd16:lut_data <= 8'h52;
60     `LUT_WIDTH'd17:lut_data <= 8'h58;
61     `LUT_WIDTH'd18:lut_data <= 8'h77;
62     `LUT_WIDTH'd19:lut_data <= 8'h7C;
63     `LUT_WIDTH'd20:lut_data <= 8'h7D;
64     `LUT_WIDTH'd21:lut_data <= 8'h90;
65     `LUT_WIDTH'd22:lut_data <= 8'h91;
66     `LUT_WIDTH'd23:lut_data <= 8'h92;
67     `LUT_WIDTH'd24:lut_data <= 8'h93;
68     `LUT_WIDTH'd25:lut_data <= 8'h94;
69     `LUT_WIDTH'd26:lut_data <= 8'hCF;
70     `LUT_WIDTH'd27:lut_data <= 8'hD0;
71     `LUT_WIDTH'd28:lut_data <= 8'hD6;
72     `LUT_WIDTH'd29:lut_data <= 8'hE5;
73     `LUT_WIDTH'd30:lut_data <= 8'hD5;
74     `LUT_WIDTH'd31:lut_data <= 8'hD7;
75     `LUT_WIDTH'd32:lut_data <= 8'hE4;
76     `LUT_WIDTH'd33:lut_data <= 8'hE9;
77     `LUT_WIDTH'd34:lut_data <= 8'hEA;
78     `LUT_WIDTH'd35:lut_data <= 8'h0E;
79     default:lut_data <= 8'h00;
80     endcase
81 end
82 //assign
83 assign iic_rd_addr_o = lut_data;
84 
85 endmodule

源码4:顶层例化文件

 1 `timescale 1 ns / 1 ps
 2 module iic_driver(
 3                                 sys_clk,
 4                                 sys_rst_n,
 5                                 iic_sclk,
 6                                 iic_sdat,
 7                                 //for test
 8                                 key_n
 9                                 );
10 input sys_clk;
11 input sys_rst_n;
12 input key_n;
13 output iic_sclk;
14 inout iic_sdat;
15 
16 wire wreq;
17 wire rreq;
18 
19 wire iic_wr_ack;
20 wire iic_rd_ack;
21 
22 wire [7:0] sys_data_o;
23 wire [7:0] sys_data_i;
24 
25 wire [7:0] iic_wr_addr;
26 wire [7:0] iic_rd_addr;
27 
28 wire wr_config_done;
29 
30 wr_config                inst_wr_config(
31                             .sys_clk(sys_clk),
32                             .sys_rst_n(sys_rst_n),
33                             .iic_wr_ack_i(iic_wr_ack),
34                             .wreq_o(wreq),
35                             .sys_byte_o(sys_data_i),
36                             .iic_wr_addr_o(iic_wr_addr),
37                             .wr_config_done_o(wr_config_done)
38                             );
39 
40 rd_check                inst_rd_check(
41                             .sys_clk(sys_clk),
42                             .sys_rst_n(sys_rst_n),
43                             .key_n(key_n),
44                             .rreq_o(rreq),
45                             .iic_rd_addr_o(iic_rd_addr)
46                             );
47 
48 iic_ctrl                inst_iic_ctrl(
49                         //common
50                         .sys_clk(sys_clk),
51                         .sys_rst_n(sys_rst_n),
52                         .iic_sclk(iic_sclk),
53                         .iic_sdat(iic_sdat),
54                         //read
55                         .rreq_i(rreq),
56                         .iic_rd_addr_i(iic_rd_addr),
57                         .rd_en_i(wr_config_done),
58                         .iic_rd_ack_o(iic_rd_ack),
59                         .sys_byte_o(sys_data_o),
60                         //write
61                         .wreq_i(wreq),
62                         .wr_en_i(~wr_config_done),
63                         .iic_wr_addr_i(iic_wr_addr),
64                         .sys_byte_i(sys_data_i),
65                         .iic_wr_ack_o(iic_wr_ack)
66                         );
67                         
68                         
69 endmodule

源码5:仿真文件

 1 `timescale 1 ns / 1 ps
 2 `define T1    10000000
 3 `define T20    20
 4 `define T500 500000
 5 module iic_tsb;
 6 
 7 reg sys_clk;
 8 reg sys_rst_n;
 9 reg key_n;
10 
11 initial begin
12 sys_clk=1;
13 sys_rst_n=0;
14 key_n=1;
15 #100 sys_rst_n=1;
16 #`T1 key_n=0;
17 #`T20 key_n=1;
18 #`T500 key_n=0;
19 #`T20 key_n=1;
20 #`T500 key_n=0;
21 #`T20 key_n=1;
22 end
23 
24 always begin
25 #10 sys_clk=~sys_clk;
26 end
27 
28 wire iic_sclk;
29 wire iic_sdat;
30 
31 iic_driver        inst_iic_driver(
32                         .sys_clk(sys_clk),
33                         .sys_rst_n(sys_rst_n),
34                         .iic_sclk(iic_sclk),
35                         .iic_sdat(iic_sdat),
36                         .key_n(key_n)
37                         );
38 
39 endmodule

脚本文件1:windows .bat

1 rd work /s /q
2 del *.wlf
3 del modelsim.ini
4 del transcript
5 
6 vsim -do iic_tsb.do

脚本文件2:仿真tcl脚本

 1 # creat lib
 2 vlib work
 3 vmap work work
 4 
 5 # compile
 6 vlog -work work iic_ctrl.v
 7 vlog -work work rd_check.v
 8 vlog -work work wr_config.v
 9 vlog -work work iic_driver.v
10 vlog -work work iic_tsb.v
11 
12 # simulation
13 vsim -novopt -lib work iic_tsb
14 
15 # wave
16 view wave
17 add wave sim:/iic_tsb/inst_iic_driver/sys_clk
18 add wave sim:/iic_tsb/inst_iic_driver/sys_rst_n
19 add wave -radix hex sim:/iic_tsb/inst_iic_driver/data2host
20 add wave -radix hex sim:/iic_tsb/inst_iic_driver/data2slave
21 add wave -radix hex sim:/iic_tsb/inst_iic_driver/iic_wr_addr
22 add wave -radix hex sim:/iic_tsb/inst_iic_driver/iic_rd_addr
23 add wave sim:/iic_tsb/inst_iic_driver/wreq
24 add wave sim:/iic_tsb/inst_iic_driver/rreq
25 add wave sim:/iic_tsb/inst_iic_driver/iic_wr_ack
26 add wave sim:/iic_tsb/inst_iic_driver/iic_rd_ack
27 add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sclk
28 add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sclk_w
29 add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_sdat
30 add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/sdat_r
31 add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/link
32 add wave -radix unsigned sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/bit_cnt
33 add wave sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/iic_byte
34 add wave -radix ascii sim:/iic_tsb/inst_iic_driver/inst_iic_ctrl/c_st
35 #write config cost 10ms
36 run 12ms
原文地址:https://www.cnblogs.com/loadomain/p/3253304.html