12_基于 I2C 协议的 EEPROM 驱动控制

12_基于 I2C 协议的 EEPROM 驱动控制

  • 1. I2C协议
    • 1.1 I2C通信协议
    • 1.2 I2C物理层
    • 1.3 I2C协议层
      • 1.3.1 单字节数据的写入
      • 1.3.2 页写数据写入
      • 1.3.3 随机读取操作
      • 1.3.4 顺序读取操作
  • 2. EEPROM
    • 2.1 板载 EEPROM 实物图
    • 2.2 板载 EEPROM 部分原理图
  • 3. 实验目标
  • 4. 模块框图
    • 4.1 顶层模块
    • 4.2 I2C 驱动模块
    • 4.3 数据收发模块
  • 5. 波形图
    • 5.1 I2C 驱动模块
    • 5.2 数据收发模块
  • 6. RTL
    • 6.1 i2c_ctrl
    • 6.2 i2c_rw_data
    • 6.3 eeprom_byte_rd_wr
  • 7. testbench
    • 7.1 tb_eeprom_byte_rd_wr
    • 7.2 M24LC64

1. I2C协议

1.1 I2C通信协议

在这里插入图片描述

1.2 I2C物理层

在这里插入图片描述

1.3 I2C协议层

1.3.1 单字节数据的写入

单字节地址,2字节地址
在这里插入图片描述

1.3.2 页写数据写入

单字节地址,2字节地址
在这里插入图片描述

1.3.3 随机读取操作

单字节地址,2字节地址
在这里插入图片描述

1.3.4 顺序读取操作

单字节地址,2字节地址
在这里插入图片描述
在这里插入图片描述

2. EEPROM

2.1 板载 EEPROM 实物图

在这里插入图片描述

2.2 板载 EEPROM 部分原理图

在这里插入图片描述

3. 实验目标

运用所学理论知识设计一个使用 I2C 通讯协议的 EEPROM 读写控制器,使用按键控制数据写入或读出 EEPROM。使用写控制按键向 EEPROM 中写入数据 1-10 共 10 字节数据,使用读控制按键读出之前写入到 EEPROM 的数据,并将读出的数据在数码管上显示出来。

4. 模块框图

4.1 顶层模块

在这里插入图片描述
在这里插入图片描述

4.2 I2C 驱动模块

在这里插入图片描述
在这里插入图片描述

4.3 数据收发模块

在这里插入图片描述

在这里插入图片描述

5. 波形图

5.1 I2C 驱动模块

状态转移图
在这里插入图片描述
I2c_scl 250khz 是 i2c_clk的四分频 。串行时钟 scl 的时钟频率为 250KHz,我们要生成的新时钟 i2c_clk 的频率要是 scl 的 4倍,之所以这样是为了后面更好的生成 scl 和 sda,所以 i2c_clk 的时钟频率为 1MHZ。
在这里插入图片描述
我们使用 50MHz 系统时钟生成了 1MHz 时钟 i2c_clk,但输出至 EEPROM 的串行时钟scl 的时钟频率为 250KHz,我们声明时钟信号计数器 cnt_i2c_clk,作为分频计数器,对时钟 i2c_clk 时钟信号进行计数,初值为 0,计数范围为 0-3,计数时钟为 i2c_clk 时钟,每个时钟周期自加 1,实现时钟 i2c_clk 信号的 4 分频,生成串行时钟 scl。同时计数器cnt_i2c_clk 也可作为生成串行数据 sda 的约束条件,以及状态机跳转条件。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述 当Sda_en高电平 sda_out 输出 当 Sda_en 低电平sda_out 低电平 当 sda_en 为高电平 i2c_scl = sda_out 当为低电平时候 i2c_scl = 0
在这里插入图片描述
随机读操作整体波形图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.2 数据收发模块

跨时钟阈的处理,用低频的信号去采集高频的信号,延长有效信号。
在这里插入图片描述
三个字节的写入
在这里插入图片描述
读操作的波形图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6. RTL

6.1 i2c_ctrl

`timescale  1ns/1ns
module  i2c_ctrl
#(parameter   DEVICE_ADDR     =   7'b1010_000     ,   //i2c设备地址parameter   SYS_CLK_FREQ    =   26'd50_000_000  ,   //输入系统时钟频率parameter   SCL_FREQ        =   18'd250_000         //i2c设备scl时钟频率
)
(input   wire            sys_clk     ,   //输入系统时钟,50MHzinput   wire            sys_rst_n   ,   //输入复位信号,低电平有效input   wire            wr_en       ,   //输入写使能信号input   wire            rd_en       ,   //输入读使能信号input   wire            i2c_start   ,   //输入i2c触发信号input   wire            addr_num    ,   //输入i2c字节地址字节数input   wire    [15:0]  byte_addr   ,   //输入i2c字节地址input   wire    [7:0]   wr_data     ,   //输入i2c设备数据output  reg             i2c_clk     ,   //i2c驱动时钟output  reg             i2c_end     ,   //i2c一次读/写操作完成output  reg     [7:0]   rd_data     ,   //输出i2c设备读取数据output  reg             i2c_scl     ,   //输出至i2c设备的串行时钟信号sclinout   wire            i2c_sda         //输出至i2c设备的串行数据信号sda
);//************************************************************************//
//******************** Parameter and Internal Signal *********************//
//************************************************************************//
// parameter define
parameter   CNT_CLK_MAX     =   (SYS_CLK_FREQ/SCL_FREQ) >> 2'd3   ;   //cnt_clk计数器计数最大值parameter   CNT_START_MAX   =   8'd100; //cnt_start计数器计数最大值parameter   IDLE            =   4'd00,  //初始状态START_1         =   4'd01,  //开始状态1SEND_D_ADDR     =   4'd02,  //设备地址写入状态 + 控制写ACK_1           =   4'd03,  //应答状态1SEND_B_ADDR_H   =   4'd04,  //字节地址高八位写入状态ACK_2           =   4'd05,  //应答状态2SEND_B_ADDR_L   =   4'd06,  //字节地址低八位写入状态ACK_3           =   4'd07,  //应答状态3WR_DATA         =   4'd08,  //写数据状态ACK_4           =   4'd09,  //应答状态4START_2         =   4'd10,  //开始状态2SEND_RD_ADDR    =   4'd11,  //设备地址写入状态 + 控制读ACK_5           =   4'd12,  //应答状态5RD_DATA         =   4'd13,  //读数据状态N_ACK           =   4'd14,  //非应答状态STOP            =   4'd15;  //结束状态// wire  define
wire            sda_in          ;   //sda输入数据寄存
wire            sda_en          ;   //sda数据写入使能信号// reg   define
reg     [7:0]   cnt_clk         ;   //系统时钟计数器,控制生成clk_i2c时钟信号
reg     [3:0]   state           ;   //状态机状态
reg             cnt_i2c_clk_en  ;   //cnt_i2c_clk计数器使能信号
reg     [1:0]   cnt_i2c_clk     ;   //clk_i2c时钟计数器,控制生成cnt_bit信号
reg     [2:0]   cnt_bit         ;   //sda比特计数器
reg             ack             ;   //应答信号
reg             i2c_sda_reg     ;   //sda数据缓存
reg     [7:0]   rd_data_reg     ;   //自i2c设备读出数据//************************************************************************//
//******************************* Main Code ******************************//
//************************************************************************//
// cnt_clk:系统时钟计数器,控制生成clk_i2c时钟信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_clk <=  8'd0;else    if(cnt_clk == CNT_CLK_MAX - 1'b1)cnt_clk <=  8'd0;elsecnt_clk <=  cnt_clk + 1'b1;// i2c_clk:i2c驱动时钟
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)i2c_clk <=  1'b1;else    if(cnt_clk == CNT_CLK_MAX - 1'b1)i2c_clk <=  ~i2c_clk;// cnt_i2c_clk_en:cnt_i2c_clk计数器使能信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_i2c_clk_en  <=  1'b0;else    if((state == STOP) && (cnt_bit == 3'd3) &&(cnt_i2c_clk == 3))cnt_i2c_clk_en  <=  1'b0;else    if(i2c_start == 1'b1)cnt_i2c_clk_en  <=  1'b1;// cnt_i2c_clk:i2c_clk时钟计数器,控制生成cnt_bit信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_i2c_clk <=  2'd0;else    if(cnt_i2c_clk_en == 1'b1)cnt_i2c_clk <=  cnt_i2c_clk + 1'b1;// cnt_bit:sda比特计数器
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_bit <=  3'd0;else    if((state == IDLE) || (state == START_1) || (state == START_2)|| (state == ACK_1) || (state == ACK_2) || (state == ACK_3)|| (state == ACK_4) || (state == ACK_5) || (state == N_ACK))cnt_bit <=  3'd0;else    if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))cnt_bit <=  3'd0;else    if((cnt_i2c_clk == 2'd3) && (state != IDLE))cnt_bit <=  cnt_bit + 1'b1;// state:状态机状态跳转
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)state   <=  IDLE;else    case(state)IDLE:if(i2c_start == 1'b1)state   <=  START_1;elsestate   <=  state;START_1:if(cnt_i2c_clk == 3)state   <=  SEND_D_ADDR;elsestate   <=  state;SEND_D_ADDR:if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))state   <=  ACK_1;elsestate   <=  state;ACK_1:if((cnt_i2c_clk == 3) && (ack == 1'b0))beginif(addr_num == 1'b1)state   <=  SEND_B_ADDR_H;elsestate   <=  SEND_B_ADDR_L;endelsestate   <=  state;SEND_B_ADDR_H:if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))state   <=  ACK_2;elsestate   <=  state;ACK_2:if((cnt_i2c_clk == 3) && (ack == 1'b0))state   <=  SEND_B_ADDR_L;elsestate   <=  state;SEND_B_ADDR_L:if((cnt_bit == 3'd7) && (cnt_i2c_clk == 3))state   <=  ACK_3;elsestate   <=  state;ACK_3:if((cnt_i2c_clk == 3) && (ack == 1'b0))beginif(wr_en == 1'b1)state   <=  WR_DATA;else    if(rd_en == 1'b1)state   <=  START_2;elsestate   <=  state;endelsestate   <=  state;WR_DATA:if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))state   <=  ACK_4;elsestate   <=  state;ACK_4:if((cnt_i2c_clk == 3) && (ack == 1'b0))state   <=  STOP;elsestate   <=  state;START_2:if(cnt_i2c_clk == 3)state   <=  SEND_RD_ADDR;elsestate   <=  state;SEND_RD_ADDR:if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))state   <=  ACK_5;elsestate   <=  state;ACK_5:if((cnt_i2c_clk == 3) && (ack == 1'b0))state   <=  RD_DATA;elsestate   <=  state;RD_DATA:if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))state   <=  N_ACK;elsestate   <=  state;N_ACK:if(cnt_i2c_clk == 3)state   <=  STOP;elsestate   <=  state;STOP:if((cnt_bit == 3'd3) &&(cnt_i2c_clk == 3))state   <=  IDLE;elsestate   <=  state;default:    state   <=  IDLE;endcase// ack:应答信号
always@(*)case    (state)IDLE,START_1,SEND_D_ADDR,SEND_B_ADDR_H,SEND_B_ADDR_L,WR_DATA,START_2,SEND_RD_ADDR,RD_DATA,N_ACK:ack <=  1'b1;ACK_1,ACK_2,ACK_3,ACK_4,ACK_5:if(cnt_i2c_clk == 2'd0)ack <=  sda_in;elseack <=  ack;default:    ack <=  1'b1;endcase// i2c_scl:输出至i2c设备的串行时钟信号scl
always@(*)case    (state)IDLE:i2c_scl <=  1'b1;START_1:if(cnt_i2c_clk == 2'd3)i2c_scl <=  1'b0;elsei2c_scl <=  1'b1;SEND_D_ADDR,ACK_1,SEND_B_ADDR_H,ACK_2,SEND_B_ADDR_L,ACK_3,WR_DATA,ACK_4,START_2,SEND_RD_ADDR,ACK_5,RD_DATA,N_ACK:if((cnt_i2c_clk == 2'd1) || (cnt_i2c_clk == 2'd2))i2c_scl <=  1'b1;elsei2c_scl <=  1'b0;STOP:if((cnt_bit == 3'd0) &&(cnt_i2c_clk == 2'd0))i2c_scl <=  1'b0;elsei2c_scl <=  1'b1;default:    i2c_scl <=  1'b1;endcase// i2c_sda_reg:sda数据缓存
always@(*)case    (state)IDLE:begini2c_sda_reg <=  1'b1;rd_data_reg <=  8'd0;endSTART_1:if(cnt_i2c_clk <= 2'd0)i2c_sda_reg <=  1'b1;elsei2c_sda_reg <=  1'b0;SEND_D_ADDR:if(cnt_bit <= 3'd6)i2c_sda_reg <=  DEVICE_ADDR[6 - cnt_bit];elsei2c_sda_reg <=  1'b0;ACK_1:i2c_sda_reg <=  1'b1;SEND_B_ADDR_H:i2c_sda_reg <=  byte_addr[15 - cnt_bit];ACK_2:i2c_sda_reg <=  1'b1;SEND_B_ADDR_L:i2c_sda_reg <=  byte_addr[7 - cnt_bit];ACK_3:i2c_sda_reg <=  1'b1;WR_DATA:i2c_sda_reg <=  wr_data[7 - cnt_bit];ACK_4:i2c_sda_reg <=  1'b1;START_2:if(cnt_i2c_clk <= 2'd1)i2c_sda_reg <=  1'b1;elsei2c_sda_reg <=  1'b0;SEND_RD_ADDR:if(cnt_bit <= 3'd6)i2c_sda_reg <=  DEVICE_ADDR[6 - cnt_bit];elsei2c_sda_reg <=  1'b1;ACK_5:i2c_sda_reg <=  1'b1;RD_DATA:if(cnt_i2c_clk  == 2'd2)rd_data_reg[7 - cnt_bit]    <=  sda_in;elserd_data_reg <=  rd_data_reg;N_ACK:i2c_sda_reg <=  1'b1;STOP:if((cnt_bit == 3'd0) && (cnt_i2c_clk < 2'd3))i2c_sda_reg <=  1'b0;elsei2c_sda_reg <=  1'b1;default:begini2c_sda_reg <=  1'b1;rd_data_reg <=  rd_data_reg;endendcase// rd_data:自i2c设备读出数据
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_data <=  8'd0;else    if((state == RD_DATA) && (cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))rd_data <=  rd_data_reg;// i2c_end:一次读/写结束信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)i2c_end <=  1'b0;else    if((state == STOP) && (cnt_bit == 3'd3) &&(cnt_i2c_clk == 3))i2c_end <=  1'b1;elsei2c_end <=  1'b0;// sda_in:sda输入数据寄存
assign  sda_in = i2c_sda;
// sda_en:sda数据写入使能信号
assign  sda_en = ((state == RD_DATA) || (state == ACK_1) || (state == ACK_2)|| (state == ACK_3) || (state == ACK_4) || (state == ACK_5))? 1'b0 : 1'b1;
// i2c_sda:输出至i2c设备的串行数据信号sda
assign  i2c_sda = (sda_en == 1'b1) ? i2c_sda_reg : 1'bz;endmodule

6.2 i2c_rw_data

`timescale  1ns/1ns
module  i2c_rw_data
(input   wire            sys_clk     ,   //输入系统时钟,频率50MHzinput   wire            i2c_clk     ,   //输入i2c驱动时钟,频率1MHzinput   wire            sys_rst_n   ,   //输入复位信号,低有效input   wire            write       ,   //输入写触发信号input   wire            read        ,   //输入读触发信号input   wire            i2c_end     ,   //一次i2c读/写结束信号input   wire    [7:0]   rd_data     ,   //输入自i2c设备读出的数据output  reg             wr_en       ,   //输出写使能信号output  reg             rd_en       ,   //输出读使能信号output  reg             i2c_start   ,   //输出i2c读/写触发信号output  reg     [15:0]  byte_addr   ,   //输出i2c设备读/写地址output  reg     [7:0]   wr_data     ,   //输出写入i2c设备的数据output  wire    [7:0]   fifo_rd_data    //输出自fifo中读出的数据
);//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
// parameter  define
parameter   DATA_NUM        =   8'd10       ,   //读/写操作读出或写入的数据个数CNT_START_MAX   =   16'd4000    ,   //cnt_start计数器计数最大值CNT_WR_RD_MAX   =   8'd200      ,   //cnt_wr/cnt_rd计数器计数最大值CNT_WAIT_MAX    =   28'd500_000 ;   //cnt_wait计数器计数最大值
// wire  define
wire    [7:0]   data_num    ;   //fifo中数据个数// reg   define
reg     [7:0]   cnt_wr          ;   //写触发有效信号保持时间计数器
reg             write_valid     ;   //写触发有效信号
reg     [7:0]   cnt_rd          ;   //读触发有效信号保持时间计数器
reg             read_valid      ;   //读触发有效信号
reg     [15:0]  cnt_start       ;   //单字节数据读/写时间间隔计数
reg     [7:0]   wr_i2c_data_num ;   //写入i2c设备的数据个数
reg     [7:0]   rd_i2c_data_num ;   //读出i2c设备的数据个数
reg             fifo_rd_valid   ;   //fifo读有效信号
reg     [27:0]  cnt_wait        ;   //fifo读使能信号间时间间隔计数
reg             fifo_rd_en      ;   //fifo读使能信号
reg     [7:0]   rd_data_num     ;   //读出fifo数据个数//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//cnt_wr:写触发有效信号保持时间计数器,计数写触发有效信号保持时钟周期数
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_wr    <=  8'd0;else    if(write_valid == 1'b0)cnt_wr    <=  8'd0;else    if(write_valid == 1'b1)cnt_wr    <=  cnt_wr + 1'b1;//write_valid:写触发有效信号
//由于写触发信号保持时间为一个系统时钟周期(20ns),
//不能被i2c驱动时钟i2c_scl正确采集,延长写触发信号生成写触发有效信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)write_valid    <=  1'b0;else    if(cnt_wr == (CNT_WR_RD_MAX - 1'b1))write_valid    <=  1'b0;else    if(write == 1'b1)write_valid    <=  1'b1;//cnt_rd:读触发有效信号保持时间计数器,计数读触发有效信号保持时钟周期数
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_rd    <=  8'd0;else    if(read_valid == 1'b0)cnt_rd    <=  8'd0;else    if(read_valid == 1'b1)cnt_rd    <=  cnt_rd + 1'b1;//read_valid:读触发有效信号
//由于读触发信号保持时间为一个系统时钟周期(20ns),
//不能被i2c驱动时钟i2c_scl正确采集,延长读触发信号生成读触发有效信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)read_valid    <=  1'b0;else    if(cnt_rd == (CNT_WR_RD_MAX - 1'b1))read_valid    <=  1'b0;else    if(read == 1'b1)read_valid    <=  1'b1;//cnt_start:单字节数据读/写操作时间间隔计数
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_start   <=  16'd0;else    if((wr_en == 1'b0) && (rd_en == 1'b0))cnt_start   <=  16'd0;else    if(cnt_start == (CNT_START_MAX - 1'b1))cnt_start   <=  16'd0;else    if((wr_en == 1'b1) || (rd_en == 1'b1))cnt_start   <=  cnt_start + 1'b1;//i2c_start:i2c读/写触发信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)i2c_start   <=  1'b0;else    if((cnt_start == (CNT_START_MAX - 1'b1)))i2c_start   <=  1'b1;elsei2c_start   <=  1'b0;//wr_en:输出写使能信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)wr_en   <=  1'b0;else    if((wr_i2c_data_num == DATA_NUM - 1) && (i2c_end == 1'b1) && (wr_en == 1'b1))wr_en   <=  1'b0;else    if(write_valid == 1'b1)wr_en   <=  1'b1;//wr_i2c_data_num:写入i2c设备的数据个数
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)wr_i2c_data_num <=  8'd0;else    if(wr_en == 1'b0)wr_i2c_data_num <=  8'd0;else    if((wr_en == 1'b1) && (i2c_end == 1'b1))wr_i2c_data_num <=  wr_i2c_data_num + 1'b1;//rd_en:输出读使能信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_en   <=  1'b0;else    if((rd_i2c_data_num == DATA_NUM - 1) && (i2c_end == 1'b1) && (rd_en == 1'b1))rd_en   <=  1'b0;else    if(read_valid == 1'b1)rd_en   <=  1'b1;//rd_i2c_data_num:写入i2c设备的数据个数
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_i2c_data_num <=  8'd0;else    if(rd_en == 1'b0)rd_i2c_data_num <=  8'd0;else    if((rd_en == 1'b1) && (i2c_end == 1'b1))rd_i2c_data_num <=  rd_i2c_data_num + 1'b1;//byte_addr:输出读/写地址
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)byte_addr   <=  16'h00_5A;else    if((wr_en == 1'b0) && (rd_en == 1'b0))byte_addr   <=  16'h00_5A;else    if(((wr_en == 1'b1) || (rd_en == 1'b1)) && (i2c_end == 1'b1))byte_addr   <=  byte_addr + 1'b1;//wr_data:输出待写入i2c设备数据
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)wr_data <=  8'h01;else    if(wr_en == 1'b0)wr_data <=  8'h01;else    if((wr_en == 1'b1) && (i2c_end == 1'b1))wr_data <=  wr_data + 1'b1;//fifo_rd_valid:fifo读有效信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)fifo_rd_valid  <=  1'b0;else    if((rd_data_num == DATA_NUM)&& (cnt_wait == (CNT_WAIT_MAX - 1'b1)))fifo_rd_valid  <=  1'b0;else    if(data_num == DATA_NUM)fifo_rd_valid  <=  1'b1;//cnt_wait:fifo读使能信号间时间间隔计数,计数两fifo读使能间的时间间隔
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_wait    <=  28'd0;else    if(fifo_rd_valid == 1'b0)cnt_wait    <=  28'd0;else    if(cnt_wait == (CNT_WAIT_MAX - 1'b1))cnt_wait    <=  28'd0;else    if(fifo_rd_valid == 1'b1)cnt_wait    <=  cnt_wait + 1'b1;//fifo_rd_en:fifo读使能信号
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)fifo_rd_en <=  1'b0;else    if((cnt_wait == (CNT_WAIT_MAX - 1'b1))&& (rd_data_num < DATA_NUM))fifo_rd_en <=  1'b1;elsefifo_rd_en <=  1'b0;//rd_data_num:自fifo中读出数据个数计数
always@(posedge i2c_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)rd_data_num <=  8'd0;else    if(fifo_rd_valid == 1'b0)rd_data_num <=  8'd0;else    if(fifo_rd_en == 1'b1)rd_data_num <=  rd_data_num + 1'b1;//****************************************************************//
//************************* Instantiation ************************//
//****************************************************************//
//------------- fifo_read_inst -------------
fifo_data   fifo_read_inst
(.clock  (i2c_clk            ),  //输入时钟信号,频率1MHz,1bit.data   (rd_data            ),  //输入写入数据,1bit.rdreq  (fifo_rd_en         ),  //输入数据读请求,1bit.wrreq  (i2c_end && rd_en   ),  //输入数据写请求,1bit.q      (fifo_rd_data       ),  //输出读出数据,1bit.usedw  (data_num           )   //输出fifo内数据个数,1bit
);endmodule

6.3 eeprom_byte_rd_wr

`timescale  1ns/1ns
module  eeprom_byte_rd_wr
(input   wire            sys_clk     ,   //输入工作时钟,频率50MHzinput   wire            sys_rst_n   ,   //输入复位信号,低电平有效input   wire            key_wr      ,   //按键写input   wire            key_rd      ,   //按键读inout   wire            sda         ,   //串行数据output  wire            scl         ,   //串行时钟output  wire            stcp        ,   //输出数据存储器时钟output  wire            shcp        ,   //移位寄存器的时钟输入output  wire            ds          ,   //串行数据输入output  wire            oe              //使能信号
);//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//wire  define
wire            read        ;   //读数据
wire            write       ;   //写数据
wire    [7:0]   po_data     ;   //fifo输出数据
wire    [7:0]   rd_data     ;   //eeprom读出数据
wire            wr_en       ;
wire            rd_en       ;
wire            i2c_end     ;
wire            i2c_start   ;
wire    [7:0]   wr_data     ;
wire    [15:0]  byte_addr   ;
wire            i2c_clk     ;//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------- key_wr_inst -------------
key_filter  key_wr_inst
(.sys_clk    (sys_clk    ),  //系统时钟50Mhz.sys_rst_n  (sys_rst_n  ),  //全局复位.key_in     (key_wr     ),  //按键输入信号.key_flag   (write      )   //key_flag为1时表示按键有效,0表示按键无效
);//------------- key_rd_inst -------------
key_filter  key_rd_inst
(.sys_clk    (sys_clk    ),  //系统时钟50Mhz.sys_rst_n  (sys_rst_n  ),  //全局复位.key_in     (key_rd     ),  //按键输入信号.key_flag   (read       )   //key_flag为1时表示按键有效,0表示按键无效
);//------------- i2c_rw_data_inst -------------
i2c_rw_data i2c_rw_data_inst
(.sys_clk     (sys_clk   ),  //输入系统时钟,频率50MHz.i2c_clk     (i2c_clk   ),  //输入i2c驱动时钟,频率1MHz.sys_rst_n   (sys_rst_n ),  //输入复位信号,低有效.write       (write     ),  //输入写触发信号.read        (read      ),  //输入读触发信号.i2c_end     (i2c_end   ),  //一次i2c读/写结束信号.rd_data     (rd_data   ),  //输入自i2c设备读出的数据.wr_en       (wr_en     ),  //输出写使能信号.rd_en       (rd_en     ),  //输出读使能信号.i2c_start   (i2c_start ),  //输出i2c读/写触发信号.byte_addr   (byte_addr ),  //输出i2c设备读/写地址.wr_data     (wr_data   ),  //输出写入i2c设备的数据.fifo_rd_data(po_data   )   //输出自fifo中读出的数据);//------------- i2c_ctrl_inst -------------
i2c_ctrl
#(.DEVICE_ADDR    (7'b1010_011     ), //i2c设备器件地址.SYS_CLK_FREQ   (26'd50_000_000  ), //i2c_ctrl模块系统时钟频率.SCL_FREQ       (18'd250_000     )  //i2c的SCL时钟频率
)
i2c_ctrl_inst
(.sys_clk     (sys_clk   ),   //输入系统时钟,50MHz.sys_rst_n   (sys_rst_n ),   //输入复位信号,低电平有效.wr_en       (wr_en     ),   //输入写使能信号.rd_en       (rd_en     ),   //输入读使能信号.i2c_start   (i2c_start ),   //输入i2c触发信号.addr_num    (1'b1      ),   //输入i2c字节地址字节数.byte_addr   (byte_addr ),   //输入i2c字节地址.wr_data     (wr_data   ),   //输入i2c设备数据.rd_data     (rd_data   ),   //输出i2c设备读取数据.i2c_end     (i2c_end   ),   //i2c一次读/写操作完成.i2c_clk     (i2c_clk   ),   //i2c驱动时钟.i2c_scl     (scl       ),   //输出至i2c设备的串行时钟信号scl.i2c_sda     (sda       )    //输出至i2c设备的串行数据信号sda
);//------------- seg7_dynamic_inst -------------
seg_595_dynamic seg_595_dynamic_inst
(.sys_clk     (sys_clk   ), //系统时钟,频率50MHz.sys_rst_n   (sys_rst_n ), //复位信号,低有效.data        (po_data   ), //数码管要显示的值.point       (          ), //小数点显示,高电平有效.seg_en      (1'b1      ), //数码管使能信号,高电平有效.sign        (          ), //符号位,高电平显示负号.stcp        (stcp      ), //数据存储器时钟.shcp        (shcp      ), //移位寄存器时钟.ds          (ds        ), //串行数据输入.oe          (oe        )  //使能信号
);endmodule

7. testbench

7.1 tb_eeprom_byte_rd_wr

`timescale  1ns/1ns
module  tb_eeprom_byte_rd_wr();
//wire define
wire            scl ;
wire            sda ;
wire            stcp;
wire            shcp;
wire            ds  ;
wire            oe  ;//reg define
reg           clk   ;
reg           rst_n ;
reg           key_wr;
reg           key_rd;//时钟、复位信号
initialbeginclk     =   1'b1  ;rst_n   <=  1'b0  ;key_wr  <=  1'b1  ;key_rd  <=  1'b1  ;#200rst_n   <=  1'b1  ;#1000key_wr  <=  1'b0  ;key_rd  <=  1'b1  ;#400key_wr  <=  1'b1  ;key_rd  <=  1'b1  ;#20000000key_wr  <=  1'b1  ;key_rd  <=  1'b0  ;#400key_wr  <=  1'b1  ;key_rd  <=  1'b1  ;#40000000$stop;endalways  #10 clk = ~clk;defparam eeprom_byte_rd_wr_inst.key_wr_inst.CNT_MAX = 5;
defparam eeprom_byte_rd_wr_inst.key_rd_inst.CNT_MAX = 5;
defparam eeprom_byte_rd_wr_inst.i2c_rw_data_inst.CNT_WAIT_MAX = 1000;//-------------eeprom_byte_rd_wr_inst-------------
eeprom_byte_rd_wr   eeprom_byte_rd_wr_inst
(.sys_clk        (clk    ),    //输入工作时钟,频率50MHz.sys_rst_n      (rst_n  ),    //输入复位信号,低电平有效.key_wr         (key_wr ),    //按键写.key_rd         (key_rd ),    //按键读.sda            (sda    ),    //串行数据.scl            (scl    ),    //串行时钟.stcp           (stcp   ),   //输出数据存储寄时钟.shcp           (shcp   ),   //移位寄存器的时钟输入.ds             (ds     ),   //串行数据输入.oe             (oe     ));//-------------eeprom_inst-------------
M24LC64  M24lc64_inst
(.A0     (1'b0       ),  //器件地址.A1     (1'b0       ),  //器件地址.A2     (1'b0       ),  //器件地址.WP     (1'b0       ),  //写保护信号,高电平有效.RESET  (~rst_n     ),  //复位信号,高电平有效.SDA    (sda        ),  //串行数据.SCL    (scl        )   //串行时钟
);endmodule

7.2 M24LC64

// *******************************************************************************************************
// **                                                                                                   **
// **   24LC64.v - Microchip 24LC64 64K-BIT I2C SERIAL EEPROM (VCC = +2.5V TO +5.5V)                    **
// **                                                                                                   **
// *******************************************************************************************************
// **                                                                                                   **
// **                   This information is distributed under license from Young Engineering.           **
// **                              COPYRIGHT (c) 2009 YOUNG ENGINEERING                                 **
// **                                      ALL RIGHTS RESERVED                                          **
// **                                                                                                   **
// **                                                                                                   **
// **   Young Engineering provides design expertise for the digital world                               **
// **   Started in 1990, Young Engineering offers products and services for your electronic design      **
// **   project.  We have the expertise in PCB, FPGA, ASIC, firmware, and software design.              **
// **   From concept to prototype to production, we can help you.                                       **
// **                                                                                                   **
// **   http://www.young-engineering.com/                                                               **
// **                                                                                                   **
// *******************************************************************************************************
// **   This information is provided to you for your convenience and use with Microchip products only.  **
// **   Microchip disclaims all liability arising from this information and its use.                    **
// **                                                                                                   **
// **   THIS INFORMATION IS PROVIDED "AS IS." MICROCHIP MAKES NO REPRESENTATION OR WARRANTIES OF        **
// **   ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO        **
// **   THE INFORMATION PROVIDED TO YOU, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY,           **
// **   PERFORMANCE, MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR PURPOSE.                         **
// **   MICROCHIP IS NOT LIABLE, UNDER ANY CIRCUMSTANCES, FOR SPECIAL, INCIDENTAL OR CONSEQUENTIAL      **
// **   DAMAGES, FOR ANY REASON WHATSOEVER.                                                             **
// **                                                                                                   **
// **   It is your responsibility to ensure that your application meets with your specifications.       **
// **                                                                                                   **
// *******************************************************************************************************
// **   Revision       : 1.4                                                                            **
// **   Modified Date  : 02/04/2009                                                                     **
// **   Revision History:                                                                               **
// **                                                                                                   **
// **   10/01/2003:  Initial design                                                                     **
// **   07/19/2004:  Fixed the timing checks and the open-drain modeling for SDA.                       **
// **   01/06/2006:  Changed the legal information in the header                                        **
// **   12/04/2006:  Corrected timing checks to reference proper clock edges                            **
// **                Added timing check for Tbuf (bus free time)                                        **
// **                Reduced memory blocks to single, monolithic array                                  **
// **   02/04/2009:  Added timing checks for tSU_WP and tHD_WP                                          **
// **                                                                                                   **
// *******************************************************************************************************
// **                                       TABLE OF CONTENTS                                           **
// *******************************************************************************************************
// **---------------------------------------------------------------------------------------------------**
// **   DECLARATIONS                                                                                    **
// **---------------------------------------------------------------------------------------------------**
// **---------------------------------------------------------------------------------------------------**
// **   INITIALIZATION                                                                                  **
// **---------------------------------------------------------------------------------------------------**
// **---------------------------------------------------------------------------------------------------**
// **   CORE LOGIC                                                                                      **
// **---------------------------------------------------------------------------------------------------**
// **   1.01:  START Bit Detection                                                                      **
// **   1.02:  STOP Bit Detection                                                                       **
// **   1.03:  Input Shift Register                                                                     **
// **   1.04:  Input Bit Counter                                                                        **
// **   1.05:  Control Byte Register                                                                    **
// **   1.06:  Byte Address Register                                                                    **
// **   1.07:  Write Data Buffer                                                                        **
// **   1.08:  Acknowledge Generator                                                                    **
// **   1.09:  Acknowledge Detect                                                                       **
// **   1.10:  Write Cycle Timer                                                                        **
// **   1.11:  Write Cycle Processor                                                                    **
// **   1.12:  Read Data Multiplexor                                                                    **
// **   1.13:  Read Data Processor                                                                      **
// **   1.14:  SDA Data I/O Buffer                                                                      **
// **                                                                                                   **
// **---------------------------------------------------------------------------------------------------**
// **   DEBUG LOGIC                                                                                     **
// **---------------------------------------------------------------------------------------------------**
// **   2.01:  Memory Data Bytes                                                                        **
// **   2.02:  Write Data Buffer                                                                        **
// **                                                                                                   **
// **---------------------------------------------------------------------------------------------------**
// **   TIMING CHECKS                                                                                   **
// **---------------------------------------------------------------------------------------------------**
// **                                                                                                   **
// *******************************************************************************************************`timescale 1ns/10psmodule M24LC64 (A0, A1, A2, WP, SDA, SCL, RESET);input                A0;                             // chip select bitinput                A1;                             // chip select bitinput                A2;                             // chip select bitinput                WP;                             // write protect pininout                SDA;                            // serial data I/Oinput                SCL;                            // serial data clockinput                RESET;                          // system reset// *******************************************************************************************************
// **   DECLARATIONS                                                                                    **
// *******************************************************************************************************reg                  SDA_DO;                         // serial data - outputreg                  SDA_OE;                         // serial data - output enablewire                 SDA_DriveEnable;                // serial data output enablereg                  SDA_DriveEnableDlyd;            // serial data output enable - delayedwire [02:00]         ChipAddress;                    // hardwired chip addressreg  [03:00]         BitCounter;                     // serial bit counterreg                  START_Rcvd;                     // START bit received flagreg                  STOP_Rcvd;                      // STOP bit received flagreg                  CTRL_Rcvd;                      // control byte received flagreg                  ADHI_Rcvd;                      // byte address hi received flagreg                  ADLO_Rcvd;                      // byte address lo received flagreg                  MACK_Rcvd;                      // master acknowledge received flagreg                  WrCycle;                        // memory write cyclereg                  RdCycle;                        // memory read cyclereg  [07:00]         ShiftRegister;                  // input data shift registerreg  [07:00]         ControlByte;                    // control byte registerwire                 RdWrBit;                        // read/write control bitreg  [12:00]         StartAddress;                   // memory access starting addressreg  [04:00]         PageAddress;                    // memory page addressreg  [07:00]         WrDataByte [0:31];              // memory write data bufferwire [07:00]         RdDataByte;                     // memory read datareg  [15:00]         WrCounter;                      // write buffer counterreg  [04:00]         WrPointer;                      // write buffer pointerreg  [12:00]         RdPointer;                      // read address pointerreg                  WriteActive;                    // memory write cycle activereg  [07:00]         MemoryBlock [0:8191];           // EEPROM data memory arrayinteger              LoopIndex;                      // iterative loop indexinteger              tAA;                            // timing parameterinteger              tWC;                            // timing parameter// *******************************************************************************************************
// **   INITIALIZATION                                                                                  **
// *******************************************************************************************************//----------------------------
//------写数据间隔改动----------initial tAA = 900;                                   // SCL to SDA output delayinitial tWC = 500;                                   // memory write cycle time//   initial tAA = 900;                                   // SCL to SDA output delay
//   initial tWC = 5000000;                               // memory write cycle timeinitial beginSDA_DO = 0;SDA_OE = 0;endinitial beginSTART_Rcvd = 0;STOP_Rcvd  = 0;CTRL_Rcvd  = 0;ADHI_Rcvd  = 0;ADLO_Rcvd  = 0;MACK_Rcvd  = 0;endinitial beginBitCounter  = 0;ControlByte = 0;endinitial beginWrCycle = 0;RdCycle = 0;WriteActive = 0;endassign ChipAddress = {A2,A1,A0};// *******************************************************************************************************
// **   CORE LOGIC                                                                                      **
// *******************************************************************************************************
// -------------------------------------------------------------------------------------------------------
//      1.01:  START Bit Detection
// -------------------------------------------------------------------------------------------------------always @(negedge SDA) beginif (SCL == 1) beginSTART_Rcvd <= 1;STOP_Rcvd  <= 0;CTRL_Rcvd  <= 0;ADHI_Rcvd  <= 0;ADLO_Rcvd  <= 0;MACK_Rcvd  <= 0;WrCycle <= #1 0;RdCycle <= #1 0;BitCounter <= 0;endend// -------------------------------------------------------------------------------------------------------
//      1.02:  STOP Bit Detection
// -------------------------------------------------------------------------------------------------------always @(posedge SDA) beginif (SCL == 1) beginSTART_Rcvd <= 0;STOP_Rcvd  <= 1;CTRL_Rcvd  <= 0;ADHI_Rcvd  <= 0;ADLO_Rcvd  <= 0;MACK_Rcvd  <= 0;WrCycle <= #1 0;RdCycle <= #1 0;BitCounter <= 10;endend// -------------------------------------------------------------------------------------------------------
//      1.03:  Input Shift Register
// -------------------------------------------------------------------------------------------------------always @(posedge SCL) beginShiftRegister[00] <= SDA;ShiftRegister[01] <= ShiftRegister[00];ShiftRegister[02] <= ShiftRegister[01];ShiftRegister[03] <= ShiftRegister[02];ShiftRegister[04] <= ShiftRegister[03];ShiftRegister[05] <= ShiftRegister[04];ShiftRegister[06] <= ShiftRegister[05];ShiftRegister[07] <= ShiftRegister[06];end// -------------------------------------------------------------------------------------------------------
//      1.04:  Input Bit Counter
// -------------------------------------------------------------------------------------------------------always @(posedge SCL) beginif (BitCounter < 10) BitCounter <= BitCounter + 1;end// -------------------------------------------------------------------------------------------------------
//      1.05:  Control Byte Register
// -------------------------------------------------------------------------------------------------------always @(negedge SCL) beginif (START_Rcvd & (BitCounter == 8)) beginif (!WriteActive & (ShiftRegister[07:01] == {4'b1010,ChipAddress[02:00]})) beginif (ShiftRegister[00] == 0) WrCycle <= 1;if (ShiftRegister[00] == 1) RdCycle <= 1;ControlByte <= ShiftRegister[07:00];CTRL_Rcvd <= 1;endSTART_Rcvd <= 0;endendassign RdWrBit = ControlByte[00];// -------------------------------------------------------------------------------------------------------
//      1.06:  Byte Address Register
// -------------------------------------------------------------------------------------------------------always @(negedge SCL) beginif (CTRL_Rcvd & (BitCounter == 8)) beginif (RdWrBit == 0) beginStartAddress[12:08] <= ShiftRegister[04:00];RdPointer[12:08]    <= ShiftRegister[04:00];ADHI_Rcvd <= 1;endWrCounter <= 0;WrPointer <= 0;CTRL_Rcvd <= 0;endendalways @(negedge SCL) beginif (ADHI_Rcvd & (BitCounter == 8)) beginif (RdWrBit == 0) beginStartAddress[07:00] <= ShiftRegister[07:00];RdPointer[07:00]    <= ShiftRegister[07:00];ADLO_Rcvd <= 1;endWrCounter <= 0;WrPointer <= 0;ADHI_Rcvd <= 0;endend// -------------------------------------------------------------------------------------------------------
//      1.07:  Write Data Buffer
// -------------------------------------------------------------------------------------------------------always @(negedge SCL) beginif (ADLO_Rcvd & (BitCounter == 8)) beginif (RdWrBit == 0) beginWrDataByte[WrPointer] <= ShiftRegister[07:00];WrCounter <= WrCounter + 1;WrPointer <= WrPointer + 1;endendend// -------------------------------------------------------------------------------------------------------
//      1.08:  Acknowledge Generator
// -------------------------------------------------------------------------------------------------------always @(negedge SCL) beginif (!WriteActive) beginif (BitCounter == 8) beginif (WrCycle | (START_Rcvd & (ShiftRegister[07:01] == {4'b1010,ChipAddress[02:00]}))) beginSDA_DO <= 0;SDA_OE <= 1;end endif (BitCounter == 9) beginBitCounter <= 0;if (!RdCycle) beginSDA_DO <= 0;SDA_OE <= 0;endendendend // -------------------------------------------------------------------------------------------------------
//      1.09:  Acknowledge Detect
// -------------------------------------------------------------------------------------------------------always @(posedge SCL) beginif (RdCycle & (BitCounter == 8)) beginif ((SDA == 0) & (SDA_OE == 0)) MACK_Rcvd <= 1;endendalways @(negedge SCL) MACK_Rcvd <= 0;// -------------------------------------------------------------------------------------------------------
//      1.10:  Write Cycle Timer
// -------------------------------------------------------------------------------------------------------always @(posedge STOP_Rcvd) beginif (WrCycle & (WP == 0) & (WrCounter > 0)) beginWriteActive = 1;#(tWC);WriteActive = 0;endendalways @(posedge STOP_Rcvd) begin#(1.0);STOP_Rcvd = 0;end// -------------------------------------------------------------------------------------------------------
//      1.11:  Write Cycle Processor
// -------------------------------------------------------------------------------------------------------always @(negedge WriteActive) beginfor (LoopIndex = 0; LoopIndex < WrCounter; LoopIndex = LoopIndex + 1) beginPageAddress = StartAddress[04:00] + LoopIndex;MemoryBlock[{StartAddress[12:05],PageAddress[04:00]}] = WrDataByte[LoopIndex[04:00]];endend// -------------------------------------------------------------------------------------------------------
//      1.12:  Read Data Multiplexor
// -------------------------------------------------------------------------------------------------------always @(negedge SCL) beginif (BitCounter == 8) beginif (WrCycle & ADLO_Rcvd) beginRdPointer <= StartAddress + WrPointer + 1;endif (RdCycle) beginRdPointer <= RdPointer + 1;endendendassign RdDataByte = MemoryBlock[RdPointer[12:00]];// -------------------------------------------------------------------------------------------------------
//      1.13:  Read Data Processor
// -------------------------------------------------------------------------------------------------------always @(negedge SCL) beginif (RdCycle) beginif (BitCounter == 8) beginSDA_DO <= 0;SDA_OE <= 0;endelse if (BitCounter == 9) beginSDA_DO <= RdDataByte[07];if (MACK_Rcvd) SDA_OE <= 1;endelse beginSDA_DO <= RdDataByte[7-BitCounter];endendend// -------------------------------------------------------------------------------------------------------
//      1.14:  SDA Data I/O Buffer
// -------------------------------------------------------------------------------------------------------bufif1 (SDA, 1'b0, SDA_DriveEnableDlyd);assign SDA_DriveEnable = !SDA_DO & SDA_OE;always @(SDA_DriveEnable) SDA_DriveEnableDlyd <= #(tAA) SDA_DriveEnable;// *******************************************************************************************************
// **   DEBUG LOGIC                                                                                     **
// *******************************************************************************************************
// -------------------------------------------------------------------------------------------------------
//      2.01:  Memory Data Bytes
// -------------------------------------------------------------------------------------------------------wire [07:00] MemoryByte_000 = MemoryBlock[00];wire [07:00] MemoryByte_001 = MemoryBlock[01];wire [07:00] MemoryByte_002 = MemoryBlock[02];wire [07:00] MemoryByte_003 = MemoryBlock[03];wire [07:00] MemoryByte_004 = MemoryBlock[04];wire [07:00] MemoryByte_005 = MemoryBlock[05];wire [07:00] MemoryByte_006 = MemoryBlock[06];wire [07:00] MemoryByte_007 = MemoryBlock[07];wire [07:00] MemoryByte_008 = MemoryBlock[08];wire [07:00] MemoryByte_009 = MemoryBlock[09];wire [07:00] MemoryByte_00A = MemoryBlock[10];wire [07:00] MemoryByte_00B = MemoryBlock[11];wire [07:00] MemoryByte_00C = MemoryBlock[12];wire [07:00] MemoryByte_00D = MemoryBlock[13];wire [07:00] MemoryByte_00E = MemoryBlock[14];wire [07:00] MemoryByte_00F = MemoryBlock[15];// -------------------------------------------------------------------------------------------------------
//      2.02:  Write Data Buffer
// -------------------------------------------------------------------------------------------------------wire [07:00] WriteData_00 = WrDataByte[00];wire [07:00] WriteData_01 = WrDataByte[01];wire [07:00] WriteData_02 = WrDataByte[02];wire [07:00] WriteData_03 = WrDataByte[03];wire [07:00] WriteData_04 = WrDataByte[04];wire [07:00] WriteData_05 = WrDataByte[05];wire [07:00] WriteData_06 = WrDataByte[06];wire [07:00] WriteData_07 = WrDataByte[07];wire [07:00] WriteData_08 = WrDataByte[08];wire [07:00] WriteData_09 = WrDataByte[09];wire [07:00] WriteData_0A = WrDataByte[10];wire [07:00] WriteData_0B = WrDataByte[11];wire [07:00] WriteData_0C = WrDataByte[12];wire [07:00] WriteData_0D = WrDataByte[13];wire [07:00] WriteData_0E = WrDataByte[14];wire [07:00] WriteData_0F = WrDataByte[15];wire [07:00] WriteData_10 = WrDataByte[16];wire [07:00] WriteData_11 = WrDataByte[17];wire [07:00] WriteData_12 = WrDataByte[18];wire [07:00] WriteData_13 = WrDataByte[19];wire [07:00] WriteData_14 = WrDataByte[20];wire [07:00] WriteData_15 = WrDataByte[21];wire [07:00] WriteData_16 = WrDataByte[22];wire [07:00] WriteData_17 = WrDataByte[23];wire [07:00] WriteData_18 = WrDataByte[24];wire [07:00] WriteData_19 = WrDataByte[25];wire [07:00] WriteData_1A = WrDataByte[26];wire [07:00] WriteData_1B = WrDataByte[27];wire [07:00] WriteData_1C = WrDataByte[28];wire [07:00] WriteData_1D = WrDataByte[29];wire [07:00] WriteData_1E = WrDataByte[30];wire [07:00] WriteData_1F = WrDataByte[31];// *******************************************************************************************************
// **   TIMING CHECKS                                                                                   **
// *******************************************************************************************************wire TimingCheckEnable = (RESET == 0) & (SDA_OE == 0);wire StopTimingCheckEnable = TimingCheckEnable && SCL;//--------------------------------
//-------仿真时时序约束需改动--------
//--------------------------------specifyspecparamtHI = 600,                                     // SCL pulse width - high
//         tLO = 1300,                                    // SCL pulse width - lowtLO = 600, tSU_STA = 600,                                 // SCL to SDA setup timetHD_STA = 600,                                 // SCL to SDA hold timetSU_DAT = 100,                                 // SDA to SCL setup timetSU_STO = 600,                                 // SCL to SDA setup timetSU_WP = 600,                                  // WP to SDA setup timetHD_WP = 1300,                                 // WP to SDA hold time
//         tBUF = 1300;                                   // Bus free timetBUF = 600; $width (posedge SCL, tHI);$width (negedge SCL, tLO);$width (posedge SDA &&& SCL, tBUF);$setup (posedge SCL, negedge SDA &&& TimingCheckEnable, tSU_STA);$setup (SDA, posedge SCL &&& TimingCheckEnable, tSU_DAT);$setup (posedge SCL, posedge SDA &&& TimingCheckEnable, tSU_STO);$setup (WP, posedge SDA &&& StopTimingCheckEnable, tSU_WP);$hold  (negedge SDA &&& TimingCheckEnable, negedge SCL, tHD_STA);$hold  (posedge SDA &&& StopTimingCheckEnable, WP, tHD_WP);endspecifyendmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/27500.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线程池学习(二)execute() 和 submit() 的区别

转载&#xff1a;线程池 线程提交的两种方式 ExecutorService poll3 Executors.newCachedThreadPool();for (int i 0; i < 2; i) {poll3.execute(new TargetTask());poll3.submit(new TargetTask());}execute方法 void execute(Runnable command): Executor接口中的方法s…

【从零开始学习CSS | 第三篇】选择器优先级

目录 前言&#xff1a; 常见选择器的优先级&#xff08;从高到低&#xff09; 选择器的权重&#xff1a; 总结&#xff1a; 前言&#xff1a; 在前几篇文章中我们介绍了大量的选择器&#xff0c;那么大量的选择器在使用的时候&#xff0c;一定是有一个优先级顺序的&#xff…

2快速入门Spring基于XML的方式注册第一个组件

基于XML的方式注册第一个组件 开发步骤 第一步&#xff1a;创建Maven工程配置生成的pom.xml文件, 添加spring context基础依赖和junit依赖(注意根据Spring官方文档描述,Spring6需要JDK版本17) 当添加Spring的基础依赖spring context之后&#xff0c;Maven会自动关联并引入其…

【golang中的切片的相关知识点】[ ] slice

golang-切片 切片的定义和初始化切片的内存分析切片的操作获取长度和容量追加元素复制切片 切片的遍历切片的特性总结 Golang中的切片是一种灵活且强大的数据结构&#xff0c;它可以动态地增长和缩小。切片是基于数组的抽象&#xff0c;它提供了更方便的操作和更灵活的内存管理…

什么是分布式微服务?

什么是分布式微服务&#xff1f; 前言什么是微服务举例说明 什么是分布式图解分布式与微服务单体架构及部署微服务架构分布式影响 分布式微服务架构什么是分布式微服务架构面临的问题 前言 本文旨在讲清楚什么是分布式微服务架构&#xff0c;通过解释微服务架构和分布式架构&a…

瀚高数据库企业版V4单机版-安装手册(Windows)

目录 瀚高数据库企业版V4单机版-安装手册&#xff08;Windows&#xff09; 1. 环境准备 2. 软件安装 3.设置环境变量 4 配置数据库文件 瀚高数据库企业版V4单机版-安装手册&#xff08;Windows&#xff09; 1. 环境准备 ①.安装数据库之前&#xff0c;请确保vcredist_x6…

服务器数据库的防护策略与360后缀勒索病毒解密方法

在当今数字化时代&#xff0c;服务器数据安全面临着越来越多的挑战。其中&#xff0c;勒索病毒攻击就是一种常见的网络威胁之一&#xff0c;最近&#xff0c;很多的公司服务器数据库遭到了360后缀勒索病毒攻击&#xff0c;导致许多重要数据无法读取&#xff0c;一旦企业的数据库…

IDR: Self-Supervised Image Denoising via Iterative Data Refinement

文章目录 IDR: Self-Supervised Image Denoising via Iterative Data Refinement1. noisy-clean pair 比较难获取2. noiser-noisy pair 比较容易获取&#xff0c;但是训练效果呢&#xff1f;2.1 noiser-noisy 训练的模型&#xff0c;能够对 noisy 图像一定程度的降噪2.2 noiser…

YOLOv7 yaml 文件简化

文章目录 修改方式common.pyyolo.pyYOLOv7-ELAN.yaml原始的 YOLOv7 yaml 文件的模块是拆开写的,比较乱, 改进起来也不太容易,这篇博文将 YOLOv7 yaml 文件换了一种写法, 参数量和计算量是完全和原来一致的,区别只是在于 yaml文件的写法不同, 封装后具体的结构可以参考…

希尔排序

希尔排序 排序步骤 1、分组&#xff0c;以任意长度进行分组&#xff08;这个长度我们称作增量gap&#xff09;&#xff1b;通常以总长度的一半这个数为依据进行分组&#xff0c;每间隔 gap 个数即为一组 2、组内排序&#xff1b;组内使用插入排序法进行排序 3、重新设置间隔…

微服务Gateway网关(自动定位/自定义过滤器/解决跨域)+nginx反向代理gateway集群

目录 Gateway网关 1.0.为什么需要网关&#xff1f; 1.1.如何使用gateway网关 1.2.网关从注册中心拉取服务 1.3.gateway自动定位 1.4.gateway常见的断言 1.5.gateway内置的过滤器 1.6.自定义过滤器-全局过滤器 1.7.解决跨域问题 2.nginx反向代理gateway集群 2.1.配置…

Upsource的下载安装使用

一&#xff0c;下载 下载地址&#xff1a; https://www.jetbrains.com/upsource/下载并解压到指定的文件夹 ├── api ├── apps ├── backups # 备份目录 ├── bin # 应用目录 ├── conf # 配置文件 ├── data ├── internal ├── launcher ├── lib ├─…