1、iic_port.v
/*
*
*@Author: X-Z
*@Date:2023-02-23 17:13:03
*@Function:实现iic接口功能
*/
`include "param.v"
module iic_port(
input wire clk ,
input wire rst_n ,
input wire [3:0] cmd ,//要输入的命令
input wire req ,//表示输入的命令和数据有效
input wire [7:0] wrdin ,//要写入的数据/命令
inout sda ,//串行数据端口
output reg scl ,//串行时钟线
output reg [7:0] rdout ,//读出的数据
output reg rdout_vld,//读出的数据有效
output wire ack ,//从机反馈的应答信号/非应答信号
output wire rw_done //读写一字节结束
);
//sda中间变量定义
reg sda_out ;
reg sda_out_en ;
wire sda_in ;
//sda
assign sda_in = sda;
assign sda = sda_out_en ? sda_out : 1'bz;
//用独热码对状态编码
localparam IDLE = 7'b0000_001,//空闲状态
START = 7'b0000_010,//开始状态
WR_DATA = 7'b0000_100,//写数据
CHECK_ACK = 7'b0001_000,//检测应答状态;
RD_DATA = 7'b0010_000,//读数据状态,读取一字节/多字节数据
SEND_ACK = 7'b0100_000,//主机发送应答或非应答
STOP = 7'b1000_000;//停止状态
//定义状态
reg [6:0] state_c;
reg [6:0] state_n;
//状态转移条件定义
wire idle_2_start ;
wire idle_2_wr_data ;
wire idle_2_rd_data ;
wire start_2_wr_data ;
wire start_2_rd_data ;
wire wr_data_2_check_ack ;
wire check_ack_2_stop ;
wire check_ack_2_idle ;
wire rd_data_2_send_ack ;
wire send_ack_2_idle ;
wire send_ack_2_stop ;
wire stop_2_idle ;
//scl时钟计数器定义(产生200KHZ的时钟)
parameter TIME_SCL = 8'd250 ,
SCL_HALF = 8'd125 ,
LOW_HALF = 8'd65 ,
HIGH_HALF = 8'd190 ;
reg [7:0] cnt_scl ;
wire add_cnt_scl ;
wire end_cnt_scl ;
//比特计数器定义
reg [2:0] cnt_bit ;
wire add_cnt_bit ;
wire end_cnt_bit ;
reg [3:0] cmd_r ;//寄存命令
reg [7:0] wrdin_r ;//寄存要写入的数据
//cmd_r、wrdin_r
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cmd_r <= 4'b0000;
wrdin_r <= 8'd0;
end
else if(req)begin
cmd_r <= cmd;
wrdin_r <= wrdin;
end
end
reg [7:0] dout_r ;//寄存读出的中间数据,实现串转并
reg samp_ack ;//采样ack应答信号
//三段式状态机
//第一段
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
//第二段
always @(*)begin
case(state_c)
IDLE : begin
if(idle_2_start)begin
state_n = START;
end
else if(idle_2_wr_data)begin
state_n = WR_DATA;
end
else if(idle_2_rd_data)begin
state_n = RD_DATA;
end
else begin
state_n = state_c;
end
end
START : begin
if(start_2_wr_data)begin
state_n = WR_DATA;
end
else if(start_2_rd_data)begin
state_n = RD_DATA;
end
else begin
state_n = state_c;
end
end
WR_DATA : begin
if(wr_data_2_check_ack)begin
state_n = CHECK_ACK;
end
else begin
state_n = state_c;
end
end
CHECK_ACK : begin
if(check_ack_2_stop)begin
state_n = STOP;
end
else if(check_ack_2_idle)begin
state_n = IDLE;
end
else begin
state_n = state_c;
end
end
RD_DATA : begin
if(rd_data_2_send_ack)begin
state_n = SEND_ACK;
end
else begin
state_n = state_c;
end
end
SEND_ACK : begin
if(send_ack_2_idle)begin
state_n = IDLE;
end
else if(send_ack_2_stop)begin
state_n = STOP;
end
else begin
state_n = state_c;
end
end
STOP : begin
if(stop_2_idle)begin
state_n = IDLE;
end
else begin
state_n = state_c;
end
end
default : state_n = IDLE;
endcase
end
//状态转移条件赋值
assign idle_2_start = state_c == IDLE && (req && (cmd & `CMD_START));
assign idle_2_wr_data = state_c == IDLE && (req && (cmd & `CMD_WRITE));
assign idle_2_rd_data = state_c == IDLE && (req && (cmd & `CMD_READ ));
assign start_2_wr_data = state_c == START && ((cmd_r & `CMD_WRITE) && end_cnt_bit);
assign start_2_rd_data = state_c == START && ((cmd_r & `CMD_READ ) && end_cnt_bit);
assign wr_data_2_check_ack = state_c == WR_DATA && (end_cnt_bit && end_cnt_scl);
assign check_ack_2_stop = state_c == CHECK_ACK && (((cmd_r & `CMD_STOP) || samp_ack) && end_cnt_bit );//发送的命令中有停止位或者从机没有应答
assign check_ack_2_idle = state_c == CHECK_ACK && (((cmd_r & `CMD_STOP)==0) && end_cnt_bit);//表示发的命令中没有停止,继续写
assign rd_data_2_send_ack = state_c == RD_DATA && (end_cnt_bit && cnt_scl); //读一字节数据结束
assign send_ack_2_idle = state_c == SEND_ACK && ((cmd_r & `CMD_STOP)==0 && end_cnt_bit); //表示发的命令中没有停止信号
assign send_ack_2_stop = state_c == SEND_ACK && ((cmd_r & `CMD_STOP) && end_cnt_bit);//发的命令中有停止命令
assign stop_2_idle = state_c == STOP && end_cnt_scl;
//scl时钟计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_scl <= 1'b0;
else if(add_cnt_scl)begin
if(end_cnt_scl)begin
cnt_scl <= 1'b0;
end
else begin
cnt_scl <= cnt_scl + 1'b1;
end
end
end
assign add_cnt_scl = (state_c != IDLE);//除了空闲状态其他计数器均开启
assign end_cnt_scl = add_cnt_scl && cnt_scl == TIME_SCL-1;
//比特计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_bit <= 1'b0;
else if(add_cnt_bit)begin
if(end_cnt_bit)begin
cnt_bit <= 1'b0;
end
else begin
cnt_bit <= cnt_bit + 1'b1;
end
end
end
assign add_cnt_bit = end_cnt_scl;
assign end_cnt_bit = add_cnt_bit && cnt_bit == ((state_c == WR_DATA || state_c == RD_DATA)?7:0);//除了发送数据/接收数据需要8bit,其他均为1bit
//scl
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
scl <= 1'b1;
end
else if(idle_2_start | idle_2_wr_data | idle_2_rd_data)begin
scl <= 1'b0;
end
else if(add_cnt_scl && cnt_scl == SCL_HALF-1)begin//计数到一半翻转时钟电平
scl <= 1'b1;
end
else if(end_cnt_scl && (~stop_2_idle))begin//只要没有到停止状态时钟就会有效运行
scl <= 1'b0;
end
end
//sda_out_en
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sda_out_en <= 1'b0;
end
else if(idle_2_start | check_ack_2_stop | rd_data_2_send_ack | idle_2_wr_data)begin
sda_out_en <= 1'b1;
end
else if(wr_data_2_check_ack | stop_2_idle | start_2_rd_data | send_ack_2_idle)begin
sda_out_en <= 1'b0;
end
end
//sda_out
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sda_out <= 1'b1;
end
//发起始位
else if(state_c == START)begin
if(cnt_scl == LOW_HALF)begin
sda_out <= 1'b1;//在时钟低电平时将其拉高,以保证开始前它处于高电平
end
else if(cnt_scl == HIGH_HALF)begin//满足建立时间与保持时间,建立时间与保持时间为(600ns),我们剩余的时间为(1250ns)
sda_out <= 1'b0;//在时钟高电平期间将其拉低产生起始信号
end
end
//发数据
else if(state_c == WR_DATA)begin
if(cnt_scl == LOW_HALF)begin
sda_out <= wrdin_r[7-cnt_bit];//时钟低电平发送数据,将并行数据转换为串行数据发送,高位先发
end
end
//发应答位
else if(state_c == SEND_ACK)begin
if(cnt_scl == LOW_HALF)begin
sda_out <= ((cmd_r & `CMD_STOP) ? 1 : 0);//如果发送的命令中带停止位则发送非应答,否则发送应答
end
end
//发停止位
else if(state_c == STOP)begin
if(cnt_scl == LOW_HALF)begin
sda_out <= 1'b0;//先在时钟低电平将其拉低,为结束做准备
end
else if(cnt_scl == HIGH_HALF)begin
sda_out <= 1'b1;//时钟高电平期间将其拉高以保证停止位有效
end
end
end
//dout_r
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
dout_r <= 8'd0;
end
else if(state_c == RD_DATA)begin
if(cnt_scl == HIGH_HALF)begin
dout_r[7-cnt_bit] <= sda_in;//串并转换
end
end
end
//samp_ack
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
samp_ack <= 1'b1;
end
else if(state_c == CHECK_ACK)begin
if(cnt_scl == HIGH_HALF)begin
samp_ack <= sda_in;//高电平期间进行采样应答信号
end
end
end
//rd_out
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
rdout <= 8'd0;
end
else if(rd_data_2_send_ack)begin//表示一字节数据接收完成
rdout <= dout_r;
end
end
//rdout_vld
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
rdout_vld <= 1'b0;
end
else if(rd_data_2_send_ack)begin//表示一字节数据接收完成,有效的
rdout_vld <= 1'b1;
end
else begin
rdout_vld <= 1'b0;
end
end
//ack
assign ack = (state_c == CHECK_ACK && end_cnt_scl) ? samp_ack : 1'b1;//主机发送完一字节数据后,从机反馈的应答信号/非应答信号
//一个时钟周期结束保证主机采样完
//rw_done
assign rw_done = check_ack_2_idle | send_ack_2_idle | stop_2_idle;//发送或接收完一字节数据时都表示读写完成了一次
endmodule
2、param.v
//i2c命令参数
`define CMD_START 4'b0001
`define CMD_WRITE 4'b0010
`define CMD_READ 4'b0100
`define CMD_STOP 4'b1000
//定义eeprom读写模式
//`define BYTE_WRITE //字节写
`define PAGE_WRITE //页写
`ifdef BYTE_WRITE
`define WR_BYTE 3
`elsif PAGE_WRITE
`define WR_BYTE 18
`endif
`define RANDOM_READ //随机地址读
`define SEQU_READ //顺序地址读
`ifdef RANDOM_READ
`define RD_BYTE 4
`elsif SEQU_READ
`define RD_BYTE 19
`endif
//iic外设地址参数定义
`define I2C_ADR 6'b1010_00 //6'b1010_00xy x:Block地址 y:读写控制位 WR_BIT/RD_BIT
`define WR_BIT 1'b0 //bit0
`define RD_BIT 1'b1 //bit0
`define BLOCK_A 1'b0 //第一块block
`define BLOCK_B 1'b1 //第二块block
`define STOP_BIT 1'b1
`define START_BIT 1'b0
3、eeprom_control.v
/*
*
*@Author: X-Z
*@Date:2023-02-24 19:16:15
*@Function:EEPROM读写控制模块的实现
*/
`timescale 1ns/1ps
`include "param.v"
module eeprom_control(
input wire clk ,
input wire rst_n ,
input wire [7:0] rdout ,//从iic接口模块读出的数据
input wire rdout_vld ,
input wire ack ,//从机EEPROM给的应答/非应答信号
input wire rw_done ,//通过iic模块读或写完一字节数据完成
input wire wr_req ,//写请求
input wire rd_req ,//读请求
output reg req ,
output reg [3:0] cmd ,//控制命令
output reg [7:0] wrdin ,//要写入从机的数据
output reg [23:0] data ,//输出给数码管的数据
output reg data_vld
);
//parameter DATA = 8'haa;//想要写入eeprom的数据
//独热码对状态进行编码
localparam IDLE = 6'b000_001,//空闲状态
WR_REQ = 6'b000_010,//写请求状态(此状态下完成req、cmd、wrdin的生成)
WAIT_WR_DONE = 6'b000_100,//等待一字节写完成
RD_REQ = 6'b001_000,//读请求状态
WAIT_RD_DONE = 6'b010_000,//等待一字节数据读完成
DONE = 6'b100_000;//读写完成状态
//状态参数定义
reg [5:0] state_c,state_n;
wire idle_2_wr_req ;
wire idle_2_rd_req ;
wire wr_req_2_wait_wr_done;
wire wait_wr_done_2_wr_req;
wire wait_wr_done_2_done ;
wire rd_req_2_wait_rd_done;
wire wait_rd_done_2_rd_req;
wire wait_rd_done_2_done ;
//计数器定义
reg [4:0] cnt_byte ;
wire add_cnt_byte;
wire end_cnt_byte;
reg [4:0] BYTE_NUM ;//寄存读写命令操作所需的字节数
/**********************产生一个计数值赋值给要写的数据*********************************/
//计数器参数定义
parameter CNT_MAX = 8'd255 ;
reg [7:0] cnt_data ;
wire add_cnt_data ;
wire end_cnt_data ;
reg [3:0] data_3 ;//百位
reg [3:0] data_2 ;//十位
reg [3:0] data_1 ;//个位
reg [3:0] rdout_3 ;
reg [3:0] rdout_2 ;
reg [3:0] rdout_1 ;
//计数器模块
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_data <= 1'd0;//复位初始化计数器值为0
end
else if(add_cnt_data)begin//满足计数器开启条件
if(end_cnt_data)begin//满足计数器结束条件
cnt_data <= 1'd0;//计数值清零
end
else begin//不满足结束条件,计数器加1
cnt_data <= cnt_data + 1'b1;
end
end
end
assign add_cnt_data = 1'b1;//计数器开始计数条件
assign end_cnt_data = add_cnt_data && cnt_data == CNT_MAX;//计数器结束计数条件
/**********************************************************************************/
//三段式状态机
//第一段
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_c <= IDLE ;
end
else begin
state_c <= state_n;
end
end
//第二段
always @(*)begin
case(state_c)
IDLE :begin
if(idle_2_wr_req)
state_n = WR_REQ;
else if(idle_2_rd_req)
state_n = RD_REQ;
else
state_n = state_c;
end
WR_REQ :begin
if(wr_req_2_wait_wr_done)
state_n = WAIT_WR_DONE;
else
state_n = state_c;
end
WAIT_WR_DONE :begin
if(wait_wr_done_2_wr_req)
state_n = WR_REQ;
else if(wait_wr_done_2_done)
state_n = DONE;
else
state_n = state_c;
end
RD_REQ :begin
if(rd_req_2_wait_rd_done)
state_n = WAIT_RD_DONE;
else
state_n = state_c;
end
WAIT_RD_DONE :begin
if(wait_rd_done_2_rd_req)
state_n = RD_REQ;
else if(wait_rd_done_2_done)
state_n = DONE;
else
state_n = state_c;
end
DONE :begin//到done状态则下一个时钟周期回到IDLE
state_n = IDLE;
end
default : state_n = IDLE;
endcase
end
//转移条件赋值
assign idle_2_wr_req = state_c == IDLE && wr_req;
assign idle_2_rd_req = state_c == IDLE && rd_req;
assign wr_req_2_wait_wr_done = state_c == WR_REQ && 1'b1;
assign wait_wr_done_2_wr_req = state_c == WAIT_WR_DONE && ((cnt_byte < `WR_BYTE-1) && ack == 1'b0 && rw_done);//3字节数据未写完,从机发送应答并且前一字节数据发送完成
assign wait_wr_done_2_done = state_c == WAIT_WR_DONE && end_cnt_byte;//3字节数据传输完成
assign rd_req_2_wait_rd_done = state_c == RD_REQ && 1'b1;
assign wait_rd_done_2_rd_req = state_c == WAIT_RD_DONE && ((cnt_byte < `RD_BYTE-1) && ack == 1'b0 && rw_done);//4字节数据发送接收完
assign wait_rd_done_2_done = state_c == WAIT_RD_DONE && end_cnt_byte;//随机读结束(写3个字节读一个字节、控制字、地址、控制字、读数据)
//字节计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_byte <= 1'b0;
else if(add_cnt_byte)begin
if(end_cnt_byte)
cnt_byte <= 1'b0;
else
cnt_byte <= cnt_byte + 1'b1;
end
end
assign add_cnt_byte = rw_done;
assign end_cnt_byte = add_cnt_byte && cnt_byte == BYTE_NUM - 1;
//BYTE_NUM
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
BYTE_NUM <= 5'd0;
end
else if(wr_req)begin//字节写需要3字节,页写18字节
BYTE_NUM <= `WR_BYTE;
end
else if(rd_req)begin//随机读需要4字节,连续读19字节
BYTE_NUM <= `RD_BYTE;
end
else if(state_c == IDLE)begin
BYTE_NUM <= 5'd0;
end
end
//输出req、cmd、wrdin
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
tx(1'b0,4'd0,8'd0);//初始化
end
else if(state_c == WR_REQ)begin //字节写/页写
case(cnt_byte)
5'd0 : tx(1'b1,{`CMD_START | `CMD_WRITE},{`I2C_ADR,`BLOCK_A,`WR_BIT});//带起始位的写,eeprom的地址,选择第几个block,读操作还是写操作
5'd1 : tx(1'b1,`CMD_WRITE,8'h00);//写入要写数据的地址00
`WR_BYTE-1 : begin
tx(1'b1,{`CMD_WRITE | `CMD_STOP},cnt_data);//写入最后一字节数据
data_3 <= cnt_data /100;
data_2 <= (cnt_data %100)/10;
data_1 <= cnt_data %10;
end
default :begin
tx(1'b1,`CMD_WRITE,cnt_data);//写入其他中间数据(针对页写)
data_3 <= cnt_data /100;
data_2 <= (cnt_data %100)/10;
data_1 <= cnt_data %10;
end
endcase
end
else if(state_c == RD_REQ)begin//随机读
case(cnt_byte)
5'd0 : tx(1'b1,{`CMD_START | `CMD_WRITE},{`I2C_ADR,`BLOCK_A,`WR_BIT});
5'd1 : tx(1'b1,`CMD_WRITE,8'h00);//写入想要要读数据的地址00
5'd2 : tx(1'b1,{`CMD_START | `CMD_WRITE},{`I2C_ADR,`BLOCK_A,`RD_BIT});//发送控制命令此时指示下一步要进行读操作
`RD_BYTE-1 :begin
tx(1'b1,{`CMD_READ | `CMD_STOP},8'h00);//带停止位的读读最后一字节数据
rdout_3 <= rdout /100;
rdout_2 <= (rdout %100)/10;
rdout_1 <= rdout %10;
end
default :begin tx(1'b1,`CMD_READ,8'd0);//其他情况读中间数据不要起始位也不要停止位
rdout_3 <= rdout /100;
rdout_2 <= (rdout %100)/10;
rdout_1 <= rdout %10;
end
endcase
end
else begin
tx(1'b0,cmd,wrdin);//其他情况请求信号拉低命令与数据保持
end
end
//用task发送请求、命令、数据(地址+数据)
task tx(
input request,
input [3:0] command,
input [7:0] data
);
begin
req = request;
cmd = command;
wrdin = data ;
end
endtask
//data
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin//上电复位时数码管熄灭
data <= 24'hffffff;
end
else if(wait_wr_done_2_done)begin
data <= {4'd0,8'hff,data_3,data_2,data_1};//0代表写操作,中间3个数码管不亮,最后两个显示数据
end
else if(rdout_vld)begin//读出的数据有效
// data <= {4'd1,12'hfff,rdout[7:4],rdout[3:0]};
data <= {4'd1,8'hff,rdout_3,rdout_2,rdout_1};
end
end
//data_vld
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
data_vld <= 1'b0;
end
else if(wait_wr_done_2_done || rdout_vld)begin
data_vld <= 1'b1;
end
else begin
data_vld <= 1'b0;
end
end
endmodule
4、fsm_key_filter_more.v
//原来代码有bug,现在改了
module fsm_key_filter_more #(parameter KEY_W = 4 ,TIME_20MS = 20'd999_999)(
input wire clk ,
input wire rst_n ,
input wire [KEY_W-1:0] key ,
output reg [KEY_W-1:0] key_flag
);
//定义状态变量独热码编码
localparam IDLE = 4'b0001,//表示空闲状态
FILETER_DOWN = 4'b0010,//按键按下前抖动状态
HOLD_DOWN = 4'b0100,//按键稳定时的状态
FILETER_UP = 4'b1000;//按键松手后,后抖动状态
//定义状态
reg [3:0] state_c ;
reg [3:0] state_n ;
//定义状态转移条件
wire [3:0] idle_2_F_D;
wire [3:0] F_D_2_H_D ;
wire [3:0] F_D_2_idle;
wire [3:0] H_D_2_F_U ;
wire [3:0] F_U_2_idle;
wire [3:0] F_U_2_H_D ;
//计数器模块定义
reg [19:0] cnt_20ms ;
wire add_cnt ;
wire end_cnt ;
//寄存按键信号同步打拍,检测下降沿与上升沿
reg [KEY_W-1:0] key_r0 ;//同步信号寄存
reg [KEY_W-1:0] key_r1 ;//打拍信号
wire [KEY_W-1:0] nedge ;//下降沿信号
wire [KEY_W-1:0] pedge ;//上升沿信号
integer i ;//循环变量
//状态机设计三段式时序逻辑描述状态转移
//第一段
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
state_c <= IDLE ;
end
else begin
state_c <= state_n;
end
end
//第二段,组合逻辑,更据状态转移图描述状态转移条件
always@(*)begin
case(state_c)
IDLE : begin
if(idle_2_F_D)begin//条件成立状态转移
state_n = FILETER_DOWN;
end
else begin
state_n = IDLE ;
end
end
FILETER_DOWN :begin
if(F_D_2_idle)begin
state_n = IDLE;
end
else if(F_D_2_H_D)begin
state_n = HOLD_DOWN;
end
else begin
state_n = FILETER_DOWN;
end
end
HOLD_DOWN : begin
if(H_D_2_F_U)begin
state_n = FILETER_UP ;
end
else begin
state_n = HOLD_DOWN ;
end
end
FILETER_UP : begin
if(F_U_2_H_D)begin
state_n = HOLD_DOWN ;
end
else if(F_U_2_idle)begin
state_n = IDLE ;
end
else begin
state_n = FILETER_UP ;
end
end
default : state_n = IDLE ;
endcase
end
assign idle_2_F_D = (state_c == IDLE ) && nedge ;
assign F_D_2_idle = (state_c == FILETER_DOWN) && pedge ;
assign F_D_2_H_D = (state_c == FILETER_DOWN) && end_cnt;
assign H_D_2_F_U = (state_c == HOLD_DOWN ) && pedge ;
assign F_U_2_idle = (state_c == FILETER_UP ) && end_cnt;
assign F_U_2_H_D = (state_c == FILETER_UP ) && nedge ;
//第三段,描述输出
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
// for(i=0; i < KEY_W; i = i+1)begin //通过for循环赋初值
// key_flag[i] <= 1'b0;
// end
key_flag <= {KEY_W{1'b0}};
end
else if(F_D_2_H_D)begin
key_flag <= ~key_r1;//key_r1更稳定一点,打拍后的信号,当然key也可以
end
else begin
// for(i=0; i < KEY_W; i = i+1)begin
// key_flag[i] <= 1'b0;
// end
key_flag <= {KEY_W{1'b0}};
end
end
//20ms计数器模块
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_20ms <= 20'd0;
end
else if(add_cnt)begin
if(end_cnt)begin
cnt_20ms <= 20'd0;
end
else begin
cnt_20ms <= cnt_20ms + 1'd1;
end
end
else begin
cnt_20ms <= 20'd0;/*888888888888*/
end
end
assign add_cnt = (state_c == FILETER_DOWN) || (state_c == FILETER_UP);
assign end_cnt = (add_cnt && cnt_20ms == TIME_20MS ); //|| F_D_2_idle || F_U_2_H_D;
//end_cnt ==end_cnt = (add_cnt && cnt_20ms == TIME_20MS )|| F_D_2_idle || F_U_2_H_D;会产生bug,
//从0010-->0001时会使end_cnt满足条件,这样会使得F_D_2_H_D满足从而给输出标志信号置位,事实上此时还处于抖动状态
//延时打拍按键信号
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin //也可以key_r0 <= {KEY_W{1'b1}};
// for(i = 0; i < KEY_W; i = i + 1)begin
// key_r0[i] <= 1'b1;
// key_r1[i] <= 1'b1;
// end
key_r0 <= {KEY_W{1'b1}};
key_r1 <= {KEY_W{1'b1}};
end
else begin
key_r0 <= key ;//同步
key_r1 <= key_r0;//打拍
end
end
//nedge pedge
assign nedge = key_r1 & (~key_r0);//检测下降沿
assign pedge = (~key_r1) & key_r0;//检测上升沿
endmodule
5、dynamic_dig.v
/*
*
*@Author: X-Z
*@Date:2023-02-08 18:46:20
*@Function:数码管驱动
*/
module dynamic_dig (
input wire clk ,
input wire rst_n ,
input wire [23:0] data ,//输入24位宽的数据
output reg [5:0] sel ,//位选
output reg [7:0] seg //段选
);
//参数定义共阳极
parameter TIME_1MS = 49_999,
//1ms扫描一个数码管
ZERO = 7'b100_0000,
ONE = 7'b111_1001,
TWO = 7'b010_0100,
THREE = 7'b011_0000,
FOUR = 7'b001_1001,
FIVE = 7'b001_0010,
SIX = 7'b000_0010,
SEVEN = 7'b111_1000,
EIGHT = 7'b000_0000,
NINE = 7'b001_0000,
A = 7'b000_1000,
B = 7'b000_0011,
C = 7'b010_0011,
D = 7'b110_0011,
E = 7'b01_01011,
F = 7'b111_1111;//全灭,4'hf : seg = 8'b1000_1110;
//信号定义
reg [23:0] cnt_1ms ;
//扫描频率计数器
wire add_cnt_1ms;
wire end_cnt_1ms;
reg [3:0] disp_num ;//暂存数码管要显示的数值
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_1ms <= 1'b0;
else if(add_cnt_1ms)begin
if(end_cnt_1ms)
cnt_1ms <= 1'b0;
else
cnt_1ms <= cnt_1ms + 1'b1;
end
end
assign add_cnt_1ms = 1'b1;
assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == TIME_1MS;
//数码管位选信号
//时序电路
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sel <= 6'b111_110;//复位初始化
end
else if(end_cnt_1ms)begin
sel <= {sel[4:0],sel[5]};
end
end
//每片数码管将要显示的数值
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
disp_num <= 4'd0;
end
else begin
case(sel)
6'b111_110: disp_num <= data[23:20];
6'b111_101: disp_num <= data[19:16];
6'b111_011: disp_num <= data[15:12];
6'b110_111: disp_num <= data[11:8] ;
6'b101_111: disp_num <= data[7:4] ;
6'b011_111: disp_num <= data[3:0] ;
default : disp_num <= 4'd0 ;
endcase
end
end
//seg 段选信号译码
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
seg <= {1'b0,ZERO};//复位数码管显示字符
end
else begin//不需要显示小数点
case(disp_num)
0 :seg <= {1'b1,ZERO } ;
1 :seg <= {1'b1,ONE } ;
2 :seg <= {1'b1,TWO } ;
3 :seg <= {1'b1,THREE } ;
4 :seg <= {1'b1,FOUR } ;
5 :seg <= {1'b1,FIVE } ;
6 :seg <= {1'b1,SIX } ;
7 :seg <= {1'b1,SEVEN } ;
8 :seg <= {1'b1,EIGHT } ;
9 :seg <= {1'b1,NINE } ;
10:seg <= {1'b1, A } ;
11:seg <= {1'b1, B } ;
12:seg <= {1'b1, C } ;
13:seg <= {1'b1, D } ;
14:seg <= {1'b1, E } ;
15:seg <= {1'b1, F } ;
//全灭
default :seg <= {1'b1,F} ;
endcase
end
end
endmodule
6、eeprom_top.v
/*
*
*@Author: X-Z
*@Date:2023-02-23 16:50:52
*@Function:eeprom实现读写顶层设计例化
*/
module eeprom_top (
input wire clk ,
input wire rst_n ,
input wire [1:0] key_in ,
inout sda , //串行数据线
output wire scl , //串行时钟线
output wire [5:0] sel ,
output wire [7:0] seg
);
//中间变量定义
wire [1:0] key_flag ;
wire [3:0] cmd ;
wire req ;
wire [7:0] wrdin ;
wire [7:0] rdout ;
wire rdout_vld ;
wire ack ;
wire rw_done ;
wire [23:0] data ;
wire data_vld ;
wire wr_req ;
wire rd_req ;
//wr_req、rd_req
assign {rd_req,wr_req} = key_flag;//写是key0读是key1
//按键消抖模块例化
fsm_key_filter_more #(.KEY_W(2) ,.TIME_20MS(20'd999_999))
u_fsm_key_filter
(
/*input wire */ .clk (clk ),
/*input wire */ .rst_n (rst_n ),
/*input wire [KEY_W-1:0] */ .key (key_in ),
/*output reg [KEY_W-1:0] */ .key_flag (key_flag )
);
//iic接口模块例化
iic_port u_iic_port(
/*input wire */ .clk (clk ),
/*input wire */ .rst_n (rst_n ),
/*input wire [3:0] */ .cmd (cmd ),//要输入的命令
/*input wire */ .req (req ),//表示输入的命令和数据有效
/*input wire [7:0] */ .wrdin (wrdin ),//要写入的数据/命令
/*inout */ .sda (sda ),//串行数据端口
/*output reg */ .scl (scl ),//串行时钟线
/*output reg [7:0] */ .rdout (rdout ),//读出的数据
/*output reg */ .rdout_vld (rdout_vld ),//读出的数据有效
/*output wire */ .ack (ack ),//从机反馈的应答信号/非应答信号
/*output wire */ .rw_done (rw_done ) //读写一字节结束
);
//eeprom读写控制模块例化
eeprom_control u_eeprom_control(
/*input wire */ .clk (clk ) ,
/*input wire */ .rst_n (rst_n ) ,
/*input wire [7:0] */ .rdout (rdout ) ,//从iic接口模块读出的数据
/*input wire */ .rdout_vld (rdout_vld ) ,
/*input wire */ .ack (ack ) ,//从机EEPROM给的应答/非应答信号
/*input wire */ .rw_done (rw_done ) ,//通过iic模块读或写完一字节数据完成
/*input wire */ .wr_req (wr_req ) ,//写请求wr_req
/*input wire */ .rd_req (rd_req ) ,//读请求
/*output reg */ .req (req ) ,
/*output reg [3:0] */ .cmd (cmd ) ,//控制命令
/*output reg [7:0] */ .wrdin (wrdin ) ,//要写入从机的数据
/*output reg [23:0] */ .data (data ) ,//输出给数码管的数据
/*output reg */ .data_vld (data_vld )
);
//数码管驱动模块例化
dynamic_dig u_dynamic_dig(
/*input wire */ .clk (clk ),
/*input wire */ .rst_n (rst_n ),
/*input wire [23:0]*/ .data (data ),//输入24位宽的数据
/*output reg [5:0] */ .sel (sel ),//位选
/*output reg [7:0] */ .seg (seg )//段选
);
endmodule
7、eeprom_top_tb.v
`timescale 1ns/1ps
module eeprom_top_tb();
parameter CYCLE = 20;
reg clk ;
reg rst_n ;
reg [1:0] key_in ;
wire scl ;
wire sda ;
wire [5:0] sel ;
wire [7:0] seg ;
supply0 VSS ;//对地建模
/*************cmd_start=4'b0001
cmd_write=4'b0010
cmd_read =4'b0100
cmd_stop =4'b1000 ****************/
initial begin
clk = 1'b1 ;
rst_n = 1'b0 ;
key_in = 2'b00 ;
#(20*CYCLE);
rst_n = 1'b1 ;
#(40*CYCLE)
key_in = 2'b01;//写请求有效
#CYCLE
key_in = 2'b00;
#5000000
#(CYCLE*30*300)
key_in = 2'b10;
#CYCLE
key_in = 2'b00;
#(CYCLE*40*300)
$stop;
end
always #(CYCLE/2) clk = ~clk;//50MHz
//模块例化
eeprom_top u_eeprom_top(
/*input wire */ .clk (clk ),
/*input wire */ .rst_n (rst_n ),
/*input wire [1:0] */ .key_in (key_in ),
/*inout */ .sda (sda ), //串行数据线
/*output wire */ .scl (scl ), //串行时钟线
/*output wire [5:0] */ .sel (sel ),
/*output wire [7:0] */ .seg (seg )
);
//例化eeprom模型
M24LC04B u_24lc04b(
.A0 (VSS ),
.A1 (VSS ),
.A2 (VSS ),
.WP (VSS ),
.SDA (scl ),
.SCL (sda ),
.RESET (rst_n)
);
endmodule
8、eeprom.do
vlib work
vmap work work
#编译testbench文件
vlog eeprom_top_tb.v
vlog 24LC04B.v
#编译 设计文件
#vlog ../test/iic_port.v
vlog ../src/*.v
#指定仿真顶层
vsim -novopt work.eeprom_top_tb
#添加信号到波形窗
add wave -position insertpoint sim:/eeprom_top_tb//*
run 20000000
9、M24LC04B.v
// *******************************************************************************************************
// ** **
// ** 24LC04B.v - Microchip 24LC04B 4K-BIT I2C SERIAL EEPROM (VCC = +2.5V TO +5.5V) **
// ** **
// *******************************************************************************************************
// ** **
// ** This information is distributed under license from Young Engineering. **
// ** COPYRIGHT (c) 2003 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.3 **
// ** Modified Date : 12/04/2006 **
// ** Revision History: **
// ** **
// ** 02/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) **
// ** **
// *******************************************************************************************************
// ** 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/10ps
module M24LC04B (A0, A1, A2, WP, SDA, SCL, RESET);
input A0; // unconnected pin
input A1; // unconnected pin
input A2; // unconnected pin
input WP; // write protect pin
inout SDA; // serial data I/O
input SCL; // serial data clock
input RESET; // system reset
// *******************************************************************************************************
// ** DECLARATIONS **
// *******************************************************************************************************
reg SDA_DO; // serial data - output
reg SDA_OE; // serial data - output enable
wire SDA_DriveEnable; // serial data output enable
reg SDA_DriveEnableDlyd; // serial data output enable - delayed
reg [03:00] BitCounter; // serial bit counter
reg START_Rcvd; // START bit received flag
reg STOP_Rcvd; // STOP bit received flag
reg CTRL_Rcvd; // control byte received flag
reg ADDR_Rcvd; // byte address received flag
reg MACK_Rcvd; // master acknowledge received flag
reg WrCycle; // memory write cycle
reg RdCycle; // memory read cycle
reg [07:00] ShiftRegister; // input data shift register
reg [07:00] ControlByte; // control byte register
wire BlockSelect; // memory block select
wire RdWrBit; // read/write control bit
reg [08:00] StartAddress; // memory access starting address
reg [03:00] PageAddress; // memory page address
reg [07:00] WrDataByte [0:15]; // memory write data buffer
wire [07:00] RdDataByte; // memory read data
reg [15:00] WrCounter; // write buffer counter
reg [03:00] WrPointer; // write buffer pointer
reg [08:00] RdPointer; // read address pointer
reg WriteActive; // memory write cycle active
reg [07:00] MemoryBlock0 [0:255]; // EEPROM data memory array
reg [07:00] MemoryBlock1 [0:255]; // EEPROM data memory array
integer LoopIndex; // iterative loop index
integer tAA; // timing parameter
integer tWC; // timing parameter
// *******************************************************************************************************
// ** INITIALIZATION **
// *******************************************************************************************************
initial tAA = 900; // SCL to SDA output delay
initial tWC = 5000000; // memory write cycle time
initial begin
SDA_DO = 0;
SDA_OE = 0;
end
initial begin
START_Rcvd = 0;
STOP_Rcvd = 0;
CTRL_Rcvd = 0;
ADDR_Rcvd = 0;
MACK_Rcvd = 0;
end
initial begin
BitCounter = 0;
ControlByte = 0;
end
initial begin
WrCycle = 0;
RdCycle = 0;
WriteActive = 0;
end
// *******************************************************************************************************
// ** CORE LOGIC **
// *******************************************************************************************************
// -------------------------------------------------------------------------------------------------------
// 1.01: START Bit Detection
// -------------------------------------------------------------------------------------------------------
always @(negedge SDA) begin
if (SCL == 1) begin
START_Rcvd <= 1;
STOP_Rcvd <= 0;
CTRL_Rcvd <= 0;
ADDR_Rcvd <= 0;
MACK_Rcvd <= 0;
WrCycle <= #1 0;
RdCycle <= #1 0;
BitCounter <= 0;
end
end
// -------------------------------------------------------------------------------------------------------
// 1.02: STOP Bit Detection
// -------------------------------------------------------------------------------------------------------
always @(posedge SDA) begin
if (SCL == 1) begin
START_Rcvd <= 0;
STOP_Rcvd <= 1;
CTRL_Rcvd <= 0;
ADDR_Rcvd <= 0;
MACK_Rcvd <= 0;
WrCycle <= #1 0;
RdCycle <= #1 0;
BitCounter <= 10;
end
end
// -------------------------------------------------------------------------------------------------------
// 1.03: Input Shift Register
// -------------------------------------------------------------------------------------------------------
always @(posedge SCL) begin
ShiftRegister[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) begin
if (BitCounter < 10) BitCounter <= BitCounter + 1;
end
// -------------------------------------------------------------------------------------------------------
// 1.05: Control Byte Register
// -------------------------------------------------------------------------------------------------------
always @(negedge SCL) begin
if (START_Rcvd & (BitCounter == 8)) begin
if (!WriteActive & (ShiftRegister[07:04] == 4'b1010)) begin
if (ShiftRegister[00] == 0) WrCycle <= 1;
if (ShiftRegister[00] == 1) RdCycle <= 1;
ControlByte <= ShiftRegister[07:00];
CTRL_Rcvd <= 1;
end
START_Rcvd <= 0;
end
end
assign BlockSelect = ControlByte[01];
assign RdWrBit = ControlByte[00];
// -------------------------------------------------------------------------------------------------------
// 1.06: Byte Address Register
// -------------------------------------------------------------------------------------------------------
always @(negedge SCL) begin
if (CTRL_Rcvd & (BitCounter == 8)) begin
if (RdWrBit == 0) begin
StartAddress <= {BlockSelect,ShiftRegister[07:00]};
RdPointer <= {BlockSelect,ShiftRegister[07:00]};
ADDR_Rcvd <= 1;
end
WrCounter <= 0;
WrPointer <= 0;
CTRL_Rcvd <= 0;
end
end
// -------------------------------------------------------------------------------------------------------
// 1.07: Write Data Buffer
// -------------------------------------------------------------------------------------------------------
always @(negedge SCL) begin
if (ADDR_Rcvd & (BitCounter == 8)) begin
if ((WP == 0) & (RdWrBit == 0)) begin
WrDataByte[WrPointer] <= ShiftRegister[07:00];
WrCounter <= WrCounter + 1;
WrPointer <= WrPointer + 1;
end
end
end
// -------------------------------------------------------------------------------------------------------
// 1.08: Acknowledge Generator
// -------------------------------------------------------------------------------------------------------
always @(negedge SCL) begin
if (!WriteActive) begin
if (BitCounter == 8) begin
if (WrCycle | (START_Rcvd & (ShiftRegister[07:04] == 4'b1010))) begin
SDA_DO <= 0;
SDA_OE <= 1;
end
end
if (BitCounter == 9) begin
BitCounter <= 0;
if (!RdCycle) begin
SDA_DO <= 0;
SDA_OE <= 0;
end
end
end
end
// -------------------------------------------------------------------------------------------------------
// 1.09: Acknowledge Detect
// -------------------------------------------------------------------------------------------------------
always @(posedge SCL) begin
if (RdCycle & (BitCounter == 8)) begin
if ((SDA == 0) & (SDA_OE == 0)) MACK_Rcvd <= 1;
end
end
always @(negedge SCL) MACK_Rcvd <= 0;
// -------------------------------------------------------------------------------------------------------
// 1.10: Write Cycle Timer
// -------------------------------------------------------------------------------------------------------
always @(posedge STOP_Rcvd) begin
if (WrCycle & (WP == 0) & (WrCounter > 0)) begin
WriteActive = 1;
#(tWC);
WriteActive = 0;
end
end
always @(posedge STOP_Rcvd) begin
#(1.0);
STOP_Rcvd = 0;
end
// -------------------------------------------------------------------------------------------------------
// 1.11: Write Cycle Processor
// -------------------------------------------------------------------------------------------------------
always @(negedge WriteActive) begin
for (LoopIndex = 0; LoopIndex < WrCounter; LoopIndex = LoopIndex + 1) begin
if (StartAddress[08] == 0) begin
PageAddress = StartAddress[03:00] + LoopIndex;
MemoryBlock0[{StartAddress[07:04],PageAddress[03:00]}] = WrDataByte[LoopIndex[03:00]];
end
if (StartAddress[08] == 1) begin
PageAddress = StartAddress[03:00] + LoopIndex;
MemoryBlock1[{StartAddress[07:04],PageAddress[03:00]}] = WrDataByte[LoopIndex[03:00]];
end
end
end
// -------------------------------------------------------------------------------------------------------
// 1.12: Read Data Multiplexor
// -------------------------------------------------------------------------------------------------------
always @(negedge SCL) begin
if (BitCounter == 8) begin
if (WrCycle & ADDR_Rcvd) begin
RdPointer <= StartAddress + WrPointer + 1;
end
if (RdCycle) begin
RdPointer <= RdPointer + 1;
end
end
end
assign RdDataByte = RdPointer[08] ? MemoryBlock1[RdPointer[07:00]] : MemoryBlock0[RdPointer[07:00]];
// -------------------------------------------------------------------------------------------------------
// 1.13: Read Data Processor
// -------------------------------------------------------------------------------------------------------
always @(negedge SCL) begin
if (RdCycle) begin
if (BitCounter == 8) begin
SDA_DO <= 0;
SDA_OE <= 0;
end
else if (BitCounter == 9) begin
SDA_DO <= RdDataByte[07];
if (MACK_Rcvd) SDA_OE <= 1;
end
else begin
SDA_DO <= RdDataByte[7-BitCounter];
end
end
end
// -------------------------------------------------------------------------------------------------------
// 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] MemoryByte0_00 = MemoryBlock0[00];
wire [07:00] MemoryByte0_01 = MemoryBlock0[01];
wire [07:00] MemoryByte0_02 = MemoryBlock0[02];
wire [07:00] MemoryByte0_03 = MemoryBlock0[03];
wire [07:00] MemoryByte0_04 = MemoryBlock0[04];
wire [07:00] MemoryByte0_05 = MemoryBlock0[05];
wire [07:00] MemoryByte0_06 = MemoryBlock0[06];
wire [07:00] MemoryByte0_07 = MemoryBlock0[07];
wire [07:00] MemoryByte0_08 = MemoryBlock0[08];
wire [07:00] MemoryByte0_09 = MemoryBlock0[09];
wire [07:00] MemoryByte0_0A = MemoryBlock0[10];
wire [07:00] MemoryByte0_0B = MemoryBlock0[11];
wire [07:00] MemoryByte0_0C = MemoryBlock0[12];
wire [07:00] MemoryByte0_0D = MemoryBlock0[13];
wire [07:00] MemoryByte0_0E = MemoryBlock0[14];
wire [07:00] MemoryByte0_0F = MemoryBlock0[15];
wire [07:00] MemoryByte1_00 = MemoryBlock1[00];
wire [07:00] MemoryByte1_01 = MemoryBlock1[01];
wire [07:00] MemoryByte1_02 = MemoryBlock1[02];
wire [07:00] MemoryByte1_03 = MemoryBlock1[03];
wire [07:00] MemoryByte1_04 = MemoryBlock1[04];
wire [07:00] MemoryByte1_05 = MemoryBlock1[05];
wire [07:00] MemoryByte1_06 = MemoryBlock1[06];
wire [07:00] MemoryByte1_07 = MemoryBlock1[07];
wire [07:00] MemoryByte1_08 = MemoryBlock1[08];
wire [07:00] MemoryByte1_09 = MemoryBlock1[09];
wire [07:00] MemoryByte1_0A = MemoryBlock1[10];
wire [07:00] MemoryByte1_0B = MemoryBlock1[11];
wire [07:00] MemoryByte1_0C = MemoryBlock1[12];
wire [07:00] MemoryByte1_0D = MemoryBlock1[13];
wire [07:00] MemoryByte1_0E = MemoryBlock1[14];
wire [07:00] MemoryByte1_0F = MemoryBlock1[15];
// -------------------------------------------------------------------------------------------------------
// 2.02: Write Data Buffer
// -------------------------------------------------------------------------------------------------------
wire [07:00] WriteData_0 = WrDataByte[00];
wire [07:00] WriteData_1 = WrDataByte[01];
wire [07:00] WriteData_2 = WrDataByte[02];
wire [07:00] WriteData_3 = WrDataByte[03];
wire [07:00] WriteData_4 = WrDataByte[04];
wire [07:00] WriteData_5 = WrDataByte[05];
wire [07:00] WriteData_6 = WrDataByte[06];
wire [07:00] WriteData_7 = WrDataByte[07];
wire [07:00] WriteData_8 = WrDataByte[08];
wire [07:00] WriteData_9 = WrDataByte[09];
wire [07:00] WriteData_A = WrDataByte[10];
wire [07:00] WriteData_B = WrDataByte[11];
wire [07:00] WriteData_C = WrDataByte[12];
wire [07:00] WriteData_D = WrDataByte[13];
wire [07:00] WriteData_E = WrDataByte[14];
wire [07:00] WriteData_F = WrDataByte[15];
// *******************************************************************************************************
// ** TIMING CHECKS **
// *******************************************************************************************************
wire TimingCheckEnable = (RESET == 0) & (SDA_OE == 0);
specify
specparam
tHI = 600, // SCL pulse width - high
tLO = 1300, // SCL pulse width - low
tSU_STA = 600, // SCL to SDA setup time
tHD_STA = 600, // SCL to SDA hold time
tSU_DAT = 100, // SDA to SCL setup time
tSU_STO = 600, // SCL to SDA setup time
tBUF = 1300; // Bus free time
$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);
$hold (negedge SDA &&& TimingCheckEnable, negedge SCL, tHD_STA);
endspecify
endmodule