接口类-I3C简单读写BMP581芯片
下面开发的只有1主1从的功能,简单实现了I3C读写功能。
步骤一、设置动态地址
因为只想实现I3C接口对传感器芯片的简单读写功能,所以使用I3C协议中CCC命令的0x87(SETDASA)命令码,如图1所示
该命令给存在I2c静态地址的设备分配动态地址,也就是I3C接口兼容I2C接口。
图1.SETDASA寄存器描述

图2.SETDASA时序
图2所示为SETDASA的时序图,根据时序图按顺序发送,
START+{7‘h7e,1'b0}+ACK + {8'h87+T} + SR + {Slave_addr ,1'b0} + ACK + {7’h想赋值地址,1'b0,T}+STOP
START:SCL为高电平,SDA下降沿
SR:repeat start :和START一样,SCL为高电平,SDA下降沿
STOP:SCL为高电平,SDA上升沿
T是一个专用的位:根据《I3C协议标准》执行,下面列了2个章节描述
5.1.2.3.2 Ninth Bit of SDR Master Written Data as Parity
5.1.2.3.3 Ninth Bit of SDR Slave Returned (Read) Data as End-of-Data
发送是把发送的8bit逐次与1进行抑或得到T的结果。
接收根据文档来,接收端返回T==0,结束本次传输;返回T==1,可以继续返回数据。
仿真如下:

实际波形如下:
ACK都返回,代表从机应答。

图3.实际配置动态地址的波形图
I2C静态地址是8‘h47,赋动态地址01。
步骤二、读写寄存器
读写时序参考《I3C协议标准》--I3C Private Write and Read Transfers
图4.I3C读写时序图
写操作:
往动态地址0x01,寄存器0x01,写入0x00值。
发送时序START+{7‘h7e,1'b0}+SR+{7'h01,1'b0}+ACK+8'h01+T+8'h00+T+STOP
仿真如下:
仿真是往动态地址0x01,寄存器0x2c,写入0xFF值。自己替换一下写入数据就行

波形如下:
往动态地址0x01,寄存器0x01,写入0x00值。
ACK都返回,代表从机应答。

图5.写操作时序图
读操作:
操作的sensor是BMP581,寄存器0x01是ID寄存器,ID是0x55。
往动态地址0x01,读取寄存器0x01的值。
发送时序START+{7‘h7e,1'b0}+SR+{7'h01,1'b0}+ACK+8'h01+T+SR
紧接着+{7‘h7e,1'b0}+SR+{7'h01,1'b0}+ACK + 返回数据 + STOP(这阶段的7E可以去掉)
仿真如下:
仿真是往动态地址0x01,寄存器0x2c,读取1个字节。自己替换一下写入数据就行

波形如下:
读波形比较长,需要先写,然后再读

图6.先写操作,SR(repeat start)之前的波形图

图7.后读操作,SR(repeat start)之后的波形图
附录:
Testbench代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/12/24 12:10:07
// Design Name:
// Module Name: i3c_tb1
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module i3c_tb(
);
localparam CLK_PERIOD = 10; // 100M_clk
reg clk_100m;
reg rst_n;
always #(CLK_PERIOD/2) clk_100m = ~ clk_100m;
//signals define
//----------------------------------------------------------------------
reg i3c_sda_in;
reg [15:0] DUT_I3C_BCR_reg ;
reg [ 1:0] DUT_I3C_TYPE_reg ;
reg [15:0] DUT_I3C_RATE_reg ;
reg [15:0] DUT_I3C_TDATA_reg ;
reg DUT_I3C_TDATA_reg_en ;
reg [15:0] DUT_I3C_SCL_HIGH_NUM_reg ;
reg [31:0] DUT_I3C_RESTART_DELAY_reg ;
reg [ 7:0] DUT_I3C_SLAVE_ADDR_reg ;
reg [ 7:0] DUT_I3C_RD_NUM_reg ;
reg [31:0] DUT_I3C_SAMPLE_FRE_reg ;
reg [15:0] DUT_I3C_SAMPLE_DELAY_CNT_reg ;
reg [15:0] DUT_I3C_SDA_DELAY_CNT_reg ;
reg [15:0] DUT_I3C_START_EN_reg ;
wire [ 1:0] DUT_I3C_INIT ;
wire [15:0] DUT_I3C_STS_reg ;
wire [15:0] DUT_I3C_TDATA_LENGTH_reg ;
wire [15:0] DUT_I3C_ODR_RD_DELAY_reg ;
wire [ 7:0] DUT_I3C_RD_ADDR_START_reg ;
wire [ 7:0] dut_re_reg_out_sht ;
wire dut_re_reg_out_en_sht ;
wire [ 7:0] dut_odr_dout ;
wire dut_odr_dout_en ;
I3C_CTRL I3C_CTRL_INST(
.sys_clk (clk_100m),
.sys_rst_n (rst_n ),
.i3c_busy (),
.i3c_scl (),
.i3c_sda_out (),
.i3c_sda_out_en (),
.i3c_sda_in (i3c_sda_in),
////
.DUT_I3C_BCR_reg (DUT_I3C_BCR_reg ),
.DUT_I3C_TYPE_reg (DUT_I3C_TYPE_reg ),
.DUT_I3C_RATE_reg (DUT_I3C_RATE_reg ),
.DUT_I3C_TDATA_reg (DUT_I3C_TDATA_reg ),
.DUT_I3C_TDATA_reg_en (DUT_I3C_TDATA_reg_en ),
.DUT_I3C_TDATA_LENGTH_reg (DUT_I3C_TDATA_LENGTH_reg ),
.DUT_I3C_SCL_HIGH_NUM_reg (DUT_I3C_SCL_HIGH_NUM_reg ),
.DUT_I3C_RESTART_DELAY_reg (DUT_I3C_RESTART_DELAY_reg ),
.DUT_I3C_SLAVE_ADDR_reg (DUT_I3C_SLAVE_ADDR_reg ),
.DUT_I3C_RD_NUM_reg (DUT_I3C_RD_NUM_reg ),
.DUT_I3C_SAMPLE_FRE_reg (DUT_I3C_SAMPLE_FRE_reg ),
.DUT_I3C_SAMPLE_DELAY_CNT_reg (DUT_I3C_SAMPLE_DELAY_CNT_reg ),
.DUT_I3C_SDA_DELAY_CNT_reg (DUT_I3C_SDA_DELAY_CNT_reg ),
.DUT_I3C_START_EN_reg (DUT_I3C_START_EN_reg ),
.DUT_I3C_INIT (DUT_I3C_INIT ),
// .DUT_I3C_RD_ADDR_START_reg(DUT_I3C_RD_ADDR_START_reg), //--------------
.dut_re_reg_out_sht (dut_re_reg_out_sht ),
.dut_re_reg_out_en_sht (dut_re_reg_out_en_sht ),
.dut_odr_dout (dut_odr_dout ), //--------------
.dut_odr_dout_en (dut_odr_dout_en ) //--------------
);
initial begin
rst_n = 0;
clk_100m = 0;
#1000
rst_n = 1;
end
initial begin
DUT_I3C_RATE_reg = 'd10; //100 /10 =10M
DUT_I3C_SCL_HIGH_NUM_reg = 'd5;
DUT_I3C_SLAVE_ADDR_reg = 'h8e;
DUT_I3C_RESTART_DELAY_reg = 'd20;
// DUT_I3C_RESTART_DELAY_reg = 'd6;
DUT_I3C_SAMPLE_DELAY_CNT_reg = 'd10;
DUT_I3C_SDA_DELAY_CNT_reg = 'd0;
DUT_I3C_START_EN_reg=0;
i3c_sda_in=1;
#1000
//1.assign dynamic adddress to BMP581 static address'h8e
//CCC -->87 ,direct assign address to 581
DUT_I3C_TYPE_reg = 2'b10;
repeat(1)@(posedge clk_100m)begin
DUT_I3C_TDATA_reg = {8'd0,7'h7e,1'b0};//
DUT_I3C_TDATA_reg_en = 1;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_TDATA_reg = {8'd0,8'h87};//direct assign dynamic address
DUT_I3C_TDATA_reg_en = 1;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_TDATA_reg = {8'd0,8'h8e};// static address
DUT_I3C_TDATA_reg_en = 1;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_TDATA_reg = {8'd0,8'h02};// dynamic address
DUT_I3C_TDATA_reg_en = 1;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_START_EN_reg= 1;
DUT_I3C_TDATA_reg_en = 0;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_START_EN_reg= 0;
end
#10_000
//2.write 0xff/0xaa to reg 'h2c
DUT_I3C_SDA_DELAY_CNT_reg = 'd1;
DUT_I3C_TYPE_reg = 2'b00;
repeat(1)@(posedge clk_100m)begin
DUT_I3C_TDATA_reg = {8'd0,7'h7e,1'b0};//
DUT_I3C_TDATA_reg_en = 1;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_TDATA_reg = {8'd0,8'h02};// dynamic address
DUT_I3C_TDATA_reg_en = 1;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_TDATA_reg = {8'd0,8'h2c};// reg address
DUT_I3C_TDATA_reg_en = 1;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_TDATA_reg = {8'd0,8'hff};//reg value
DUT_I3C_TDATA_reg_en = 1;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_TDATA_reg_en = 0;
DUT_I3C_START_EN_reg = 1;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_START_EN_reg= 0;
end
#10_000
//3. read the register with address 'h2c from BMP581
DUT_I3C_SDA_DELAY_CNT_reg = 'd2;
DUT_I3C_RD_NUM_reg = 'd1;
repeat(1)@(posedge clk_100m)begin
DUT_I3C_TDATA_reg = {8'd0,7'h7e,1'b0};//
DUT_I3C_TDATA_reg_en = 1;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_TDATA_reg = {8'd0,8'h03};// dynamic address
DUT_I3C_TDATA_reg_en = 1;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_TDATA_reg = {8'd0,8'h2c};// dynamic address
DUT_I3C_TDATA_reg_en = 1;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_TDATA_reg_en = 0;
DUT_I3C_START_EN_reg = 1;
end
repeat(1)@(posedge clk_100m)begin
DUT_I3C_START_EN_reg= 0;
end
#10_000
DUT_I3C_SDA_DELAY_CNT_reg = 'd5;
// //4. TX interrupt
// //A.使能中断功能,通过ENEC/DISEC CCC命令控制
// DUT_I3C_TYPE_reg = 2'b10;
// DUT_I3C_TDATA_reg = {8'd0,7'h7e,1'b0};//
// DUT_I3C_TDATA_reg_en = 1;
// #10
// DUT_I3C_TDATA_reg = {8'd0,8'h00};//broadcast enable ibi
// DUT_I3C_TDATA_reg_en = 1;
// DUT_I3C_START_EN_reg= 1;
// #10
// DUT_I3C_TDATA_reg_en = 0;
// DUT_I3C_START_EN_reg= 0;
// #10_000
// DUT_I3C_BCR_reg = 'h0004;//BCR[2]==1, BMP581 datasheet
// DUT_I3C_RD_NUM_reg = 'd1;//read 1 byte from slave
// i3c_sda_in = 1;
// #20
// i3c_sda_in = 0;
////// repeat (100) begin
////// #200
////// i3c_sda_in = 1;
////// #100
////// i3c_sda_in = 0;
// //B.收到了IBI中断之后,分析返回的IBI_payload分析中断类型
// //先写0x29寄存器,选定地址
// DUT_I3C_TYPE_reg = 2'b00;
// DUT_I3C_TDATA_reg = {8'd0,7'h7e,1'b0};//
// DUT_I3C_TDATA_reg_en = 1;
// #10
// DUT_I3C_TDATA_reg = {8'd0,8'h02};// dynamic address
// DUT_I3C_TDATA_reg_en = 1;
// #10
// DUT_I3C_TDATA_reg = {8'd0,8'h29};// reg address
// DUT_I3C_TDATA_reg_en = 1;
// DUT_I3C_START_EN_reg= 1;
// #10
// DUT_I3C_TDATA_reg_en = 0;
// DUT_I3C_START_EN_reg= 0;
// #10_000
// //C.这会读取数据返回
// DUT_I3C_TDATA_reg = {8'd0,7'h7e,1'b0};//
// DUT_I3C_TDATA_reg_en = 1;
// #10
// DUT_I3C_TDATA_reg = {8'd0,8'h03};// dynamic address
// DUT_I3C_TDATA_reg_en = 1;
// #10
// DUT_I3C_TDATA_reg_en = 0;
// #20
// DUT_I3C_START_EN_reg= 1;
// #10
// DUT_I3C_START_EN_reg= 0;
// #10_000
// repeat (100) begin
// #200
// i3c_sda_in = 1;
// #100
// i3c_sda_in = 0;
// //完成IBI请求
// end
end
endmodule
I3C控制顶层代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/09/18 11:17:58
// Design Name:
// Module Name: I3C_CTRL
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module I3C_CTRL(
input sys_clk,
input sys_rst_n,
input work_mode,
input[15:0] mic_rd_length,
output i3c_busy,
output i3c_scl,
output i3c_sda_out,
output i3c_sda_out_en,
input i3c_sda_in,
////
input [15:0] DUT_I3C_BCR_reg , //I3C BCR
input [15:0] DUT_I3C_TYPE_reg ,
input [15:0] DUT_I3C_RATE_reg ,
(* MARK_DEBUG="true" *)input [15:0] DUT_I3C_TDATA_reg ,
(* MARK_DEBUG="true" *)input DUT_I3C_TDATA_reg_en ,
input [15:0] DUT_I3C_TDATA_LENGTH_reg ,
input [15:0] DUT_I3C_SCL_HIGH_NUM_reg ,
input [15:0] DUT_I3C_RESTART_DELAY_reg ,
input [ 7:0] DUT_I3C_SLAVE_ADDR_reg ,// no use
input [15:0] DUT_I3C_RD_NUM_reg ,
input [15:0] DUT_I3C_SAMPLE_FRE_reg ,// no use
input [15:0] DUT_I3C_SAMPLE_DELAY_CNT_reg ,
(* MARK_DEBUG="true" *)input [15:0] DUT_I3C_START_EN_reg ,
input DUT_I3C_INIT ,
input DUT_I3C_INIT_reg_rt_en ,
input [15:0] DUT_I3C_SDA_DELAY_CNT_reg ,
output o_i3c_ibi_int, //
//read reg
output reg[7:0] dut_re_reg_out_sht,
output reg dut_re_reg_out_en_sht,
////dut data out
output reg[7:0] dut_odr_dout,
output reg dut_odr_dout_en,
////mic
output reg[7:0] dut_mic_dout,
output reg dut_mic_dout_en,
input[7:0] mic_data_in,
input mic_data_in_en,
input mic_start
);
wire dut_data_in_en_sht;
wire[7:0] dut_data_in_sht;
wire[7:0] dut_dout_i3c;
wire dut_dout_tvalid_i3c;
wire i3c_tready;
wire I3C_IBI_PAYLOAD;//BCR[2] ==1 indicate ibi with data
wire[7:0] dut_rd_num_reg_sht;
wire dut_odr_start;
(* MARK_DEBUG="true" *)wire dut_reg_start;
wire [7:0] dut_data;
wire dut_tvalid;
wire [11:0] i3c_fifo_data_count;
(* MARK_DEBUG="true" *)reg i3c_fifo_rd_en;
(* MARK_DEBUG="true" *)wire i3c_fifo_empty;
reg[15:0] dut_reg_set_length;
reg[63:0] DUT_SET_DATA;
(* MARK_DEBUG="true" *)reg[7:0] fifo_wdata;
(* MARK_DEBUG="true" *)reg fifo_wen;
reg[7:0] RD_NUM_reg;
//assign i3c_sda =(i3c_sda_out_en == 'd1)?i3c_sda_out:1'bz;
//assign i3c_sda_in = i3c_sda;
assign i3c_busy = ~i3c_tready;
assign dut_odr_start = DUT_I3C_START_EN_reg[1];////缂??1娑撳秳绱伴懛顏勫З濞??0閿??
assign dut_reg_start = DUT_I3C_START_EN_reg[0];////缂??1娴兼俺鍤滈崝銊︾0閿??
assign I3C_IBI_PAYLOAD = DUT_I3C_BCR_reg [2];//BCR[2]:Data returned on behalf of the IBI interrupt request
assign dut_tvalid = i3c_fifo_rd_en;
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 'D0)begin
dut_re_reg_out_en_sht <= 'd0;
dut_re_reg_out_sht <= 'd0;
dut_odr_dout_en <= 'd0;
dut_odr_dout <= 'd0;
dut_mic_dout_en <= 'd0;
dut_mic_dout <= 'd0;
end
else if(work_mode == 'd1 && dut_dout_tvalid_i3c == 'd1)begin
dut_mic_dout <= dut_dout_i3c;
dut_mic_dout_en <= 'd1;
end
else if(dut_odr_start == 'd1 && dut_dout_tvalid_i3c == 'd1)begin
dut_odr_dout <= dut_dout_i3c;
dut_odr_dout_en <= 'd1;
end
else if(dut_dout_tvalid_i3c == 'd1)begin
dut_re_reg_out_en_sht <= 'd1;
dut_re_reg_out_sht <= dut_dout_i3c;
end
else begin
dut_re_reg_out_en_sht <= 'd0;
dut_odr_dout_en <= 'd0;
dut_mic_dout_en <= 'd0;
end
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 'd0)begin
i3c_fifo_rd_en <= 'd0;
end
else if(dut_reg_start == 'd1 && i3c_fifo_empty == 'd0)begin
i3c_fifo_rd_en <= 'd1;
end
else if(mic_start == 'd1 && i3c_fifo_empty == 'd0)begin
i3c_fifo_rd_en <= 'd1;
end
else if(i3c_fifo_data_count <= 'd1)begin
i3c_fifo_rd_en <= 'd0;
end
end
////fifo_we
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 'd0)begin
fifo_wdata <= 'd0;
fifo_wen <= 'd0;
end
else if(DUT_I3C_TDATA_reg_en == 'd1)begin
fifo_wdata <= DUT_I3C_TDATA_reg[7:0];
fifo_wen <= 'd1;
end
else if(mic_data_in_en == 'd1)begin
fifo_wdata <= mic_data_in;
fifo_wen <= 'd1;
end
else begin
fifo_wen <= 'd0;
end
end
always@(posedge sys_clk)begin
if(work_mode == 'd1)begin////mic mode
RD_NUM_reg <= mic_rd_length;
end
else begin
RD_NUM_reg <= DUT_I3C_RD_NUM_reg;
end
end
I3C_DRV I3C_DRV_INST(
.sys_rstn (sys_rst_n ),
.sys_clk_100m (sys_clk ),
.i3c_tvalid (dut_tvalid ),
.i3c_tdata (dut_data ),
.i3c_tready (i3c_tready ),
// .i3c_int_enable('d1),
.i3c_ex_int_en ('d0), //'d1
//register list
.DUT_I3C_INIT (DUT_I3C_INIT ),
.DUT_I3C_INIT_reg_rt_en (DUT_I3C_INIT_reg_rt_en ),
.DUT_I3C_TYPE_reg (DUT_I3C_TYPE_reg [1:0] ),
.DUT_I3C_RATE_reg (DUT_I3C_RATE_reg ),
.DUT_I3C_RD_NUM_reg (RD_NUM_reg ),
.DUT_I3C_SCL_HIGH_NUM_reg (DUT_I3C_SCL_HIGH_NUM_reg ),
.DUT_I3C_RESTART_DELAY_reg (DUT_I3C_RESTART_DELAY_reg ),
.DUT_I3C_SAMPLE_DELAY_CNT_reg (DUT_I3C_SAMPLE_DELAY_CNT_reg ),
.DUT_I3C_SDA_DELAY_CNT_reg (DUT_I3C_SDA_DELAY_CNT_reg ),
.DUT_I3C_SLAVE_ADDR_reg (DUT_I3C_SLAVE_ADDR_reg ),
.I3C_IBI_PAYLOAD (I3C_IBI_PAYLOAD ),
.o_i3c_ibi_int (o_i3c_ibi_int ),
.i3c_int_busy(),
.i3c_int_tvalid(),
.i3c_int_dout(),
.dut_data_out(dut_dout_i3c),
.dut_data_out_en(dut_dout_tvalid_i3c),
.i3c_fifo_recv_en('d1),
.i3c_scl(i3c_scl),
.i3c_sda_out(i3c_sda_out),
.i3c_sda_out_en(i3c_sda_out_en),
.i3c_sda_in(i3c_sda_in)
);
fifo_i3c_data_in fifo_i3c_data_in_inst(
.clk (sys_clk),
.srst (~sys_rst_n),
.din (fifo_wdata),
.wr_en (fifo_wen),
.rd_en (i3c_fifo_rd_en),
.dout (dut_data),
.full (),
.empty (i3c_fifo_empty),
.data_count(i3c_fifo_data_count)
);
endmodule
FIFO_i3c_data_in配置:
naitve
common clock distributed ram
first word fall through
wite width 8 //wite depth 2048
read width 8 //read depth 2048
enable reset pin
I3C接口代码:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/04/10 08:54:56
// Design Name:
// Module Name: I3C_DRV
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module I3C_DRV
(
input sys_rstn ,
input sys_clk_100m ,
(* MARK_DEBUG="true" *)input i3c_tvalid ,
(* MARK_DEBUG="true" *)input[ 7:0] i3c_tdata ,
output i3c_tready ,
input i3c_ex_int_en , //bmp581 extern interrupt
//register list
(* MARK_DEBUG="true" *)input DUT_I3C_INIT ,
input DUT_I3C_INIT_reg_rt_en ,
(* MARK_DEBUG="true" *)input [ 1:0] DUT_I3C_TYPE_reg ,
(* MARK_DEBUG="true" *)input [15:0] DUT_I3C_RATE_reg ,
(* MARK_DEBUG="true" *)input [ 7:0] DUT_I3C_RD_NUM_reg ,
(* MARK_DEBUG="true" *)input [15:0] DUT_I3C_SCL_HIGH_NUM_reg ,
(* MARK_DEBUG="true" *)input [15:0] DUT_I3C_RESTART_DELAY_reg ,
(* MARK_DEBUG="true" *)input [15:0] DUT_I3C_SAMPLE_DELAY_CNT_reg ,
(* MARK_DEBUG="true" *)input [ 7:0] DUT_I3C_SLAVE_ADDR_reg ,
(* MARK_DEBUG="true" *)input [15:0] DUT_I3C_SDA_DELAY_CNT_reg ,
(* MARK_DEBUG="true" *)input I3C_IBI_PAYLOAD ,//BCR[2]
(* MARK_DEBUG="true" *)output reg o_i3c_ibi_int ,
output i3c_int_busy ,
output i3c_int_tvalid ,
output[7:0] i3c_int_dout ,
(* MARK_DEBUG="true" *)output[7:0] dut_data_out,
(* MARK_DEBUG="true" *)output dut_data_out_en,
output i3c_fifo_recv_ept,
input i3c_fifo_recv_en ,
output[7:0] i3c_fifo_recv_dout,
(* MARK_DEBUG="true" *)output i3c_scl ,
(* MARK_DEBUG="true" *)output i3c_sda_out ,
(* MARK_DEBUG="true" *)output i3c_sda_out_en ,
(* MARK_DEBUG="true" *)input i3c_sda_in
);
localparam I3C_IDLE = 24'b0000_0000_0000_0000_0000_0001,
I3C_INIT = 24'b0000_0000_0000_0000_0000_0010,
I3C_START = 24'b0000_0000_0000_0000_0000_0100,
I3C_OD_DLY = 24'b0000_0000_0000_0000_0000_1000,
I3C_RESV = 24'b0000_0000_0000_0000_0001_0000,
I3C_SLV_ACK = 24'b0000_0000_0000_0000_0010_0000,
I3C_CCC = 24'b0000_0000_0000_0000_0100_0000,
I3C_MSTR_T0 = 24'b0000_0000_0000_0000_1000_0000,
I3C_R_START = 24'b0000_0000_0000_0001_0000_0000,
I3C_SLV_ADDR = 24'b0000_0000_0000_0010_0000_0000,
I3C_SLV_ACK1 = 24'b0000_0000_0000_0100_0000_0000,
I3C_WR_DATA = 24'b0000_0000_0000_1000_0000_0000,
I3C_MSTR_T1 = 24'b0000_0000_0001_0000_0000_0000,
I3C_RD_DATA = 24'b0000_0000_0010_0000_0000_0000,
I3C_SLV_T0 = 24'b0000_0000_0100_0000_0000_0000,
I3C_INT_SLV = 24'b0000_0000_1000_0000_0000_0000,
I3C_INT_ACK = 24'b0000_0001_0000_0000_0000_0000,
I3C_INT_NACK = 24'b0000_0010_0000_0000_0000_0000,
I3C_INT_DATA = 24'b0000_0100_0000_0000_0000_0000,
I3C_INT_T0 = 24'b0000_1000_0000_0000_0000_0000,
I3C_RD_PID = 24'b0001_0000_0000_0000_0000_0000,
I3C_SET_DAA = 24'b0010_0000_0000_0000_0000_0000,
I3C_SLV_ACK2 = 24'b0100_0000_0000_0000_0000_0000,
I3C_STOP = 24'b1000_0000_0000_0000_0000_0000;
(* MARK_DEBUG="true" *)reg[23:0]cstate = I3C_IDLE ;
reg[23:0]nstate = I3C_IDLE ;
(* MARK_DEBUG="true" *)reg [15:0] s_i3c_type ;
(* MARK_DEBUG="true" *)reg [15:0] s_i3c_scl_high_num ;
(* MARK_DEBUG="true" *)reg [15:0] s_i3c_rest_dly_num ;
(* MARK_DEBUG="true" *)reg [15:0] s_i3c_sample_dly_num ;
(* MARK_DEBUG="true" *)reg [15:0] s_i3c_sda_dly_num ;
(* MARK_DEBUG="true" *)reg [7:0] s_i3c_slave_addr ;
(* MARK_DEBUG="true" *)reg [7:0] i3c_slv_addr ;
(* MARK_DEBUG="true" *)wire[7:0] fifo_tran_dout ;
(* MARK_DEBUG="true" *)wire fifo_tran_ept ;
(* MARK_DEBUG="true" *)reg fifo_tran_rd ;
reg i3c_sda_in_dly1 ;
reg i3c_sda_in_dly2 ;
(* MARK_DEBUG="true" *)reg i3c_scl_r ;
reg [3:0] i3c_scl_dly ;
(* MARK_DEBUG="true" *)reg i3c_sda_r ;
reg [4:0] i3c_sda_dly ;
(* MARK_DEBUG="true" *)reg i3c_sda_en ;
reg [4:0] i3c_sda_en_dly ;
(* MARK_DEBUG="true" *)reg [7:0] send_bits ;
(* MARK_DEBUG="true" *)reg [7:0] recv_bits ;
(* MARK_DEBUG="true" *)reg [7:0] recv_byts ;
(* MARK_DEBUG="true" *)reg [7:0] rd_num ;
(* MARK_DEBUG="true" *)reg [7:0] tran_data ;
(* MARK_DEBUG="true" *)reg [7:0] recv_data ;
(* MARK_DEBUG="true" *)reg recv_wr ;
(* MARK_DEBUG="true" *)reg mstr_Tbit ;
(* MARK_DEBUG="true" *)reg i3c_rd_en ;
(* MARK_DEBUG="true" *)reg slave_Tbit ;
reg int_busy ;
reg int_tvalid ;
reg [7:0] int_dout ;
(* MARK_DEBUG="true" *)reg [15:0] i3c_scl_div ;
(* MARK_DEBUG="true" *)reg [15:0] i3c_scl_cnt ;
reg i3c_tready_r ;
reg i3c_tvalid_dly ;
reg fifo_recv_rst ;
reg ibi_payload ;
reg [7:0] i3c_ccc ;
reg i3c_init_dly ;
reg init_enable ;
(* MARK_DEBUG="true" *)reg [7:0] od_dly_cnt ;
(* MARK_DEBUG="true" *)reg [15:0] stop_dly_cnt ;
(* MARK_DEBUG="true" *)reg i3c_rd_2nd_flag ;
reg s_i3c_ibi_int ;
(* MARK_DEBUG="true" *)reg [9:0] s_sample_cnt[7:0]; //limit delay 1024 cycle
(* MARK_DEBUG="true" *)reg s_sample_req[7:0];
(* MARK_DEBUG="true" *)wire s_sample_en [7:0];
(* MARK_DEBUG="true" *)reg [2:0] s_req_bit;
(* MARK_DEBUG="true" *)reg [7:0] s_rcv_bits;
(* MARK_DEBUG="true" *)wire s_time_out;
(* MARK_DEBUG="true" *)reg s_wr_fifo_en;
(* MARK_DEBUG="true" *)wire s_sample_en_all;
assign dut_data_out = recv_data;
assign dut_data_out_en = s_wr_fifo_en;
// assign dut_data_out_en = recv_wr;
assign i3c_tready = i3c_tready_r ;
assign i3c_int_busy = int_busy ;
assign i3c_int_tvalid = int_tvalid ;
assign i3c_int_dout = int_dout ;
assign i3c_scl = i3c_scl_dly[2]; //
//assign i3c_sda_out = i3c_sda_r ;
// assign i3c_sda_out = s_sda_dly_list[2+s_i3c_sda_dly_num];//i3c_sda_dly[3];
// assign i3c_sda_out_en = s_sda_en_dly_list[2+s_i3c_sda_dly_num];//i3c_sda_en_dly[3] ;//
assign i3c_sda_out = s_sda_dly_list[1+s_i3c_sda_dly_num];//i3c_sda_dly[3];
assign i3c_sda_out_en = s_sda_en_dly_list[1+s_i3c_sda_dly_num];//i3c_sda_en_dly[3] ;//
fifo_i3c_tran fifo_i3c_tran_i
(
.clk (sys_clk_100m ),
.srst (~sys_rstn ),
.din (i3c_tdata ),
.wr_en (i3c_tvalid ),
.rd_en (fifo_tran_rd ),
.dout (fifo_tran_dout ),
.full (),
.empty (fifo_tran_ept )
);
always@(posedge sys_clk_100m)begin
i3c_sda_in_dly1 <= i3c_sda_in;//data valid
i3c_sda_in_dly2 <= i3c_sda_in_i;//
i3c_tvalid_dly <= i3c_tvalid;
i3c_init_dly <= DUT_I3C_INIT;
end
assign i3c_sda_in_i = i3c_sda_in && i3c_sda_in_dly1;
always @(posedge sys_clk_100m)begin
if(!sys_rstn)
cstate <= I3C_IDLE;
else
cstate <= nstate;
end
always@( * )
begin
case (cstate)
I3C_IDLE:begin
if(fifo_tran_ept == 1'b0 && i3c_sda_in_i)//i3c ready && i3c bus idle
nstate = I3C_START;
else if(i3c_sda_in_dly2 & (~i3c_sda_in_i) && DUT_I3C_INIT)begin // i3c_sda_in falling
nstate = I3C_START;
end
// else if((~i3c_init_dly) & DUT_I3C_INIT)begin//DUT_I3C_INIT rising
// nstate = I3C_INIT;
// end
else begin
nstate = I3C_IDLE;
end
end
I3C_INIT:begin
nstate = I3C_START;
end
I3C_START:begin
if(i3c_scl_dly[0] & (~i3c_scl_r))begin//i3c_scl_r falling
// nstate = I3C_OD_DLY;
if(s_i3c_ibi_int)
nstate = I3C_INT_SLV;
else
nstate = I3C_RESV;
end
else begin
nstate = I3C_START;
end
end
I3C_OD_DLY:begin
if(od_dly_cnt > 8'd20)begin
nstate = I3C_RESV;
end
else begin
nstate = I3C_OD_DLY;
end
end
I3C_RESV:begin
if((send_bits == 8'd0) && ((~i3c_scl_dly[0]) & i3c_scl_r))begin//I3C Address Arbitration
// if((i3c_sda_in_i == 1'b0) && (i3c_ex_int_en == 1'b1))
if((i3c_sda_in_i == 1'b0) && (s_i3c_ibi_int == 1'b1))begin
nstate = I3C_INT_SLV;//interrupt
end
else begin
nstate = I3C_RESV;
end
end
else begin
if((send_bits == 8'd7) && (i3c_scl_dly[0] & (~i3c_scl_r)))begin
nstate = I3C_SLV_ACK;
end
else begin
nstate = I3C_RESV;
end
end
end
I3C_SLV_ACK:begin
if(i3c_scl_dly[0] & (~i3c_scl_r))begin
if(init_enable == 1'b1)begin
nstate = I3C_STOP;
end
else if(s_i3c_type == 2'b00)begin
nstate = I3C_R_START;// private wr/rd
end
else begin
nstate = I3C_CCC; // ccc cmd
end
end
else begin
nstate = I3C_SLV_ACK;
end
end
I3C_CCC:begin
if((send_bits == 8'd7) && (i3c_scl_dly[0] & (~i3c_scl_r)))begin
nstate = I3C_MSTR_T0;
end
else begin
nstate = I3C_CCC;
end
end
I3C_MSTR_T0:begin
if(i3c_scl_dly[0] & (~i3c_scl_r))begin
if(s_i3c_type == 2'b01)begin // broadcast
if(fifo_tran_ept == 1'b0)begin
nstate = I3C_WR_DATA;
end
else begin
nstate = I3C_STOP;
end
end
else if(s_i3c_type == 2'b10)begin //direct
nstate = I3C_R_START;
end
else begin
nstate = I3C_STOP;
end
end
else begin
nstate = I3C_MSTR_T0;
end
end
I3C_R_START:begin
if(i3c_scl_dly[0] & (~i3c_scl_r))begin
nstate = I3C_SLV_ADDR;
end
else begin
nstate = I3C_R_START;
end
end
I3C_SLV_ADDR:begin
if((send_bits == 8'd7) && (i3c_scl_dly[0] & (~i3c_scl_r)))begin
nstate = I3C_SLV_ACK1;
end
else begin
nstate = I3C_SLV_ADDR;
end
end
I3C_SLV_ACK1:begin
if(i3c_scl_dly[0] & (~i3c_scl_r))begin
if(i3c_rd_2nd_flag == 1'b0)begin
if(fifo_tran_ept == 1'b0)begin
nstate = I3C_WR_DATA;
end
else begin
nstate = I3C_STOP;
end
end
else begin
if(i3c_ccc == 8'h07)begin //ENTDAA
nstate = I3C_RD_PID;
end
else begin
nstate = I3C_RD_DATA;
end
end
end
else begin
nstate = I3C_SLV_ACK1;
end
end
I3C_WR_DATA:begin
if((send_bits == 8'd7) && (i3c_scl_dly[0] & (~i3c_scl_r)))begin
nstate = I3C_MSTR_T1;
end
else begin
nstate = I3C_WR_DATA;
end
end
I3C_MSTR_T1: begin
if(i3c_scl_dly[0] & (~i3c_scl_r))begin
if(fifo_tran_ept == 1'b0)begin
nstate = I3C_WR_DATA;
end
else begin
nstate = I3C_STOP;
end
end
else begin
nstate = I3C_MSTR_T1;
end
end
I3C_RD_DATA:begin
if((recv_bits == 8'd8) && (i3c_scl_dly[0] & (~i3c_scl_r)))begin
nstate = I3C_SLV_T0;
end
else begin
nstate = I3C_RD_DATA;
end
end
I3C_SLV_T0:begin
if(i3c_scl_dly[0] & (~i3c_scl_r))begin
if(recv_byts >= rd_num)begin
// if((recv_byts >= rd_num) || (slave_Tbit == 1'b0))begin
nstate = I3C_STOP;
end
else begin
nstate = I3C_RD_DATA;
end
end
else begin
nstate = I3C_SLV_T0;
end
end
I3C_INT_SLV:begin
if((recv_bits == 8'd8) && (i3c_scl_dly[0] & (~i3c_scl_r)))begin
if(DUT_I3C_INIT)//init enable by master
nstate = I3C_INT_ACK;
else
nstate = I3C_INT_NACK;
end
else begin
nstate = I3C_INT_SLV;
end
end
I3C_INT_ACK:begin
if(i3c_scl_dly[0] & (~i3c_scl_r))begin
if(ibi_payload == 1'b1)begin
nstate = I3C_INT_DATA;
end
else begin
nstate = I3C_STOP;
end
end
else begin
nstate = I3C_INT_ACK;
end
end
I3C_INT_NACK:begin
if(i3c_scl_dly[0] & (~i3c_scl_r))
nstate = I3C_STOP;
else
nstate = I3C_INT_NACK;
end
I3C_INT_DATA: begin
if((recv_bits == 8'd8) && (i3c_scl_dly[0] & (~i3c_scl_r)))begin
nstate = I3C_INT_T0;
end
else begin
nstate = I3C_INT_DATA;
end
end
I3C_INT_T0:begin
if(i3c_scl_dly[0] & (~i3c_scl_r))begin
if((recv_byts > rd_num) || (slave_Tbit == 1'b0) )begin
nstate = I3C_STOP;
end
else begin
nstate = I3C_INT_DATA;
end
end
else begin
nstate = I3C_INT_T0;
end
end
I3C_RD_PID:begin //PID+BCR+DCR 48 + 8 + 8
if((recv_bits == 8'd64) && (i3c_scl_dly[0] & (~i3c_scl_r)))begin
nstate = I3C_SET_DAA;
end
else begin
nstate = I3C_RD_PID;
end
end
I3C_SET_DAA:begin
if((send_bits == 8'd7) && (i3c_scl_dly[0] & (~i3c_scl_r)))begin
nstate = I3C_SLV_ACK2;
end
else begin
nstate = I3C_SET_DAA;
end
end
I3C_SLV_ACK2:begin
if(i3c_scl_dly[0] & (~i3c_scl_r))begin
nstate = I3C_STOP;
end
else begin
nstate = I3C_SLV_ACK2;
end
end
I3C_STOP:begin
if(stop_dly_cnt == {i3c_scl_div,3'd0})begin
if(i3c_rd_en == 1'b1)begin
nstate = I3C_R_START ;
//nstate = I3C_START ;
end
else begin
nstate = I3C_IDLE;
end
end
else begin
nstate = I3C_STOP;
end
end
default:begin
nstate = I3C_IDLE;
end
endcase
end
// SCL
always@(posedge sys_clk_100m)begin
case (cstate)
I3C_IDLE:begin
i3c_scl_r <= 1'b1;
// i3c_scl_div <= DUT_I3C_RATE_reg;
i3c_scl_cnt <= 16'd0;
init_enable <= 1'b0;
end
// I3C_OD_DLY:begin
// end
I3C_INIT: begin
init_enable <= 1'b1;
// i3c_scl_div <= 16'd50;
end
I3C_R_START:begin
if(i3c_scl_r == 1'b1)begin
// if(i3c_scl_cnt[15:1] < (i3c_scl_div - 1'b1))begin
if(i3c_scl_cnt < s_i3c_rest_dly_num - 'd1)begin
i3c_scl_cnt <= i3c_scl_cnt + 1'b1;
end
else begin
i3c_scl_cnt <= 16'd0;
i3c_scl_r <= 'd0;
end
end
else begin
i3c_scl_cnt <= i3c_scl_cnt + 1'b1;
if(i3c_scl_cnt < (i3c_scl_div -s_i3c_scl_high_num -'d1))begin
i3c_scl_r <= 16'd0;
end
else begin
i3c_scl_r <= 'd1;
end
end
end
I3C_STOP:begin
if(!i3c_scl_r && (i3c_scl_cnt == i3c_scl_div - s_i3c_scl_high_num - 'd1))
i3c_scl_r <= !i3c_scl_r;
else ;
if(i3c_scl_cnt<i3c_scl_div - s_i3c_scl_high_num - 'd1)
i3c_scl_cnt <= i3c_scl_cnt + 1'b1;
else
i3c_scl_cnt <= i3c_scl_cnt;
end
default:begin
if(i3c_scl_r == 1'b1)begin
if(i3c_scl_cnt < i3c_scl_div - 'd1)begin
i3c_scl_cnt <= i3c_scl_cnt + 1'b1;
end
else begin
i3c_scl_cnt <= 32'd0;
i3c_scl_r <= 'd0;
end
end
else begin
i3c_scl_cnt <= i3c_scl_cnt + 1'b1;
if(i3c_scl_cnt < i3c_scl_div - s_i3c_scl_high_num - 'd1)begin
i3c_scl_r <= 'd0;
end
else begin
i3c_scl_r <= 'd1;
end
end
// if(i3c_scl_cnt < i3c_scl_div - 1'b1)begin
// i3c_scl_cnt <= i3c_scl_cnt + 1'b1;
// end
// else begin
// i3c_scl_cnt <= 16'd0;
// if((cstate[22] == 1'b1) && (i3c_scl_r== 1'b1))begin// I3C_STOP
// i3c_scl_r <= i3c_scl_r;
// end
// else begin
// i3c_scl_r <= ~i3c_scl_r;
// end
// end
end
endcase
end
//SDA
always@(posedge sys_clk_100m)begin
case (cstate)
I3C_IDLE:begin
i3c_sda_r <= 1'bz;
i3c_sda_en <= 1'b0;
send_bits <= 8'd0;
recv_bits <= 8'd0;
recv_byts <= 8'd0;
rd_num <= 8'd0;
i3c_rd_en <= 1'b0;
slave_Tbit <= 1'b0;
//tran_data <= 8'bz111_1100;//I3C Reserved byte(7'h7E) (RnW=0)
tran_data <= 8'b1111_1100;//I3C Reserved byte(7'h7E) (RnW=0)
mstr_Tbit <= 1'b1;
// recv_data <= 8'd0;
recv_wr <= 1'b0;
int_tvalid <= 1'b0;
int_dout <= 8'd0;
int_busy <= 1'b0;
fifo_recv_rst <= 1'b0;
fifo_tran_rd <= 1'b0;
i3c_ccc <= 8'd0;
od_dly_cnt <= 8'd0;
stop_dly_cnt <= 'd0;
i3c_rd_2nd_flag <= 1'b0;
s_i3c_type <= DUT_I3C_TYPE_reg;
i3c_scl_div <= DUT_I3C_RATE_reg;
// s_i3c_rd_num <= DUT_I3C_RD_NUM_reg;
s_i3c_scl_high_num <= DUT_I3C_SCL_HIGH_NUM_reg;
s_i3c_rest_dly_num <= DUT_I3C_RESTART_DELAY_reg;
s_i3c_sample_dly_num <= DUT_I3C_SAMPLE_DELAY_CNT_reg;
if(DUT_I3C_SDA_DELAY_CNT_reg<(DUT_I3C_RATE_reg[15:1]-'d2)) //avoid overflow
s_i3c_sda_dly_num <= DUT_I3C_SDA_DELAY_CNT_reg;
else
s_i3c_sda_dly_num <= s_i3c_sda_dly_num;
s_i3c_slave_addr <= DUT_I3C_SLAVE_ADDR_reg;
if( (fifo_tran_ept == 1'b1) && i3c_sda_in_dly2 & (~i3c_sda_in_i))
s_i3c_ibi_int <= 1;
else
s_i3c_ibi_int <= 0;
end
I3C_START:begin
tran_data <= 8'b1111_1100;//I3C Reserved byte(7'h7E) (RnW=0)
if(s_i3c_ibi_int)begin
i3c_sda_r <= 1'bz;
i3c_sda_en <= 1'b0;
end
else begin
i3c_sda_r <= 1'b0;
i3c_sda_en <= 1'b1;
end
fifo_recv_rst <= 1'b1;
rd_num <= DUT_I3C_RD_NUM_reg;
ibi_payload <= I3C_IBI_PAYLOAD;
end
I3C_OD_DLY:begin
od_dly_cnt <= od_dly_cnt + 1'b1;
// i3c_sda_r <= 1'bz;
// i3c_sda_en <= 1'b0;
end
I3C_RESV:begin
i3c_sda_r <= tran_data[7];
fifo_recv_rst <= 1'b0;
if(i3c_scl_dly[0] & (~i3c_scl_r))begin//falling
tran_data <= {tran_data[6:0],1'b0};
send_bits <= send_bits + 1'b1;
end
if((send_bits == 8'd7) && ((~i3c_scl_dly[0]) & i3c_scl_r))
fifo_tran_rd <= 'd1;
else
fifo_tran_rd <= 'd0;
if(s_i3c_ibi_int) //if ibi ,slave control sda
i3c_sda_en<= 1'b0;
else
i3c_sda_en<= 1'b1;
// if(send_bits == 8'd0 )
// i3c_sda_en<= 1'b0;
// else
// i3c_sda_en<= 1'b1;
end
I3C_SLV_ACK:begin
send_bits <= 8'd0;
if(s_i3c_type == 2'b00 && i3c_rd_2nd_flag == 1'b0)begin //rd or wr reg
i3c_rd_en <= fifo_tran_dout[0];
tran_data <= {fifo_tran_dout[7:1],1'b0};
i3c_slv_addr <= fifo_tran_dout;//store slaver address
end
else begin //wr ccc cmd
tran_data <= fifo_tran_dout[7:0];
end
if((i3c_scl_r|i3c_scl_dly[0]) && (i3c_sda_in_i == 1'b0))begin
i3c_sda_r <= 1'b0;
i3c_sda_en <= 1'b1;
end
else begin
i3c_sda_r <= 1'bz;
i3c_sda_en <= 1'b0;
end
end
I3C_CCC:begin
i3c_sda_r <= tran_data[7];
i3c_sda_en <= 1'b1;
if(i3c_scl_dly[0] & (~i3c_scl_r))begin//falling
tran_data <= {tran_data[6:0],1'b0};
send_bits <= send_bits + 1'b1;
mstr_Tbit <= mstr_Tbit ^ tran_data[7];
end
i3c_ccc <= fifo_tran_dout;
end
I3C_MSTR_T0:begin
i3c_sda_r <= mstr_Tbit;
i3c_sda_en <= 1'b1;
send_bits <= 8'd0;
tran_data <= fifo_tran_dout;
if((~i3c_scl_dly[0]) & i3c_scl_r)begin //rising
fifo_tran_rd <= 1'b1;
end
else begin
fifo_tran_rd <= 1'b0;
end
if(i3c_scl_dly[0] & (~i3c_scl_r))begin//falling
mstr_Tbit <= 1'b1;
end
end
I3C_R_START:begin
i3c_sda_en <= 1'b1;
stop_dly_cnt <= 'd0;
if(i3c_rd_2nd_flag == 1'b1)begin
tran_data <= i3c_slv_addr; //i3c read slaver address
end
else begin
tran_data <= tran_data;
end
if(i3c_scl_dly[0] == 1'b0)begin //scl pos ,then sda set 0;
i3c_sda_r <= 1'b1;
end
else begin
if(i3c_scl_cnt >= (i3c_scl_div - 1'b1))begin
i3c_sda_r <= 1'b0;
end
end
end
I3C_SLV_ADDR:begin
i3c_sda_r <= tran_data[7];
i3c_sda_en <= 1'b1;
if(i3c_scl_dly[0] & (~i3c_scl_r))begin//falling
tran_data <= {tran_data[6:0],1'b0};
send_bits <= send_bits + 1'b1;
end
end
I3C_SLV_ACK1:
begin
mstr_Tbit <= 1'b1;
send_bits <= 8'd0;
tran_data <= fifo_tran_dout;
if((~i3c_scl_dly[0]) & i3c_scl_r)begin //rising
fifo_tran_rd <= 1'b1;
end
else begin
fifo_tran_rd <= 1'b0;
end
if(( i3c_scl_r|i3c_scl_dly[0]) && (i3c_sda_in_i == 1'b0))begin
i3c_sda_r <= 1'b0;
i3c_sda_en <= 1'b1;
end
else begin
i3c_sda_r <= 1'bz;
i3c_sda_en <= 1'b0;
end
end
I3C_WR_DATA:begin
i3c_sda_r <= tran_data[7];
i3c_sda_en <= 1'b1;
if(i3c_scl_dly[0] & (~i3c_scl_r))begin//falling
tran_data <= {tran_data[6:0],1'b0};
send_bits <= send_bits + 1'b1;
mstr_Tbit <= mstr_Tbit ^ tran_data[7];
end
end
I3C_MSTR_T1:begin
i3c_sda_r <= mstr_Tbit;
i3c_sda_en <= 1'b1;
send_bits <= 8'd0;
tran_data <= fifo_tran_dout;
if((~i3c_scl_dly[0]) & i3c_scl_r)begin //rising
fifo_tran_rd <= 1'b1;
end
else begin
fifo_tran_rd <= 1'b0;
end
if(i3c_scl_dly[0] & (~i3c_scl_r))begin//falling
mstr_Tbit <= 1'b1;
end
end
I3C_RD_DATA:begin
i3c_sda_r <= 1'bz;
i3c_sda_en <= 1'b0;
// if((~i3c_scl_dly[0]) & i3c_scl_r)//rising
if(i3c_scl_dly[2:1] == 2'b01)begin //rising
// recv_data <= {recv_data[6:0],i3c_sda_in_i};
recv_bits <= recv_bits + 1'b1;
end
end
I3C_SLV_T0:begin
if((~i3c_scl_dly[0]) & i3c_scl_r)begin //rising
recv_bits <= 8'd0;
recv_wr <= 1'b1;
recv_byts <= recv_byts + 1'b1;
slave_Tbit <= i3c_sda_in_i;
end
else begin
recv_wr <= 1'b0;
end
if(i3c_scl_dly[0] == 1'b1)
if(recv_byts >= rd_num)begin //master end read
i3c_sda_r <= 1'b0;
i3c_sda_en <= 1'b1;
end
else if(i3c_sda_in_i == 1'b0) begin //slave end read
i3c_sda_r <= 1'b0;
i3c_sda_en <= 1'b1;
end
else ;
else ;
end
I3C_INT_SLV:begin
i3c_sda_r <= 1'bz;
i3c_sda_en <= 1'b0;
// recv_data[7] <= 1'b0;
int_busy <= 1'b1;
fifo_recv_rst <= 1'b0;
if(i3c_scl_dly[2:1] == 2'b01)begin //rising
// recv_data[6:0] <= {recv_data[5:0],i3c_sda_in_i};
recv_bits <= recv_bits + 1'b1;
end
end
I3C_INT_ACK:begin
i3c_sda_r <= 1'b0;
i3c_sda_en <= 1'b1;
recv_bits <= 8'd0;
o_i3c_ibi_int <= 'd1;
if((~i3c_scl_dly[0]) & i3c_scl_r)begin //rising
int_tvalid <= 1'b1;
int_dout <= recv_data;
end
else begin
int_tvalid <= 1'b0;
end
end
I3C_INT_NACK:begin
i3c_sda_r <= 1'b1;
i3c_sda_en <= 1'b1;
end
I3C_INT_DATA:begin
i3c_sda_r <= 1'bz;
i3c_sda_en <= 1'b0;
if(i3c_scl_dly[2:1] == 2'b01)begin//rising
// recv_data <= {recv_data[6:0],i3c_sda_in_i};
recv_bits <= recv_bits + 1'b1;
end
end
I3C_INT_T0:begin
if((~i3c_scl_dly[0]) & i3c_scl_r)begin //rising
int_tvalid <= 1'b1;
int_dout <= recv_data;
slave_Tbit <= i3c_sda_in_i;
recv_byts <= recv_byts + 1'b1;
recv_wr <= 1'b1;
recv_bits <= 8'd0;
end
else begin
int_tvalid <= 1'b0;
recv_wr <= 1'b0;
end
if((i3c_scl_r == 1'b1) && (i3c_sda_in_i == 1'b0))begin
i3c_sda_r <= 1'b0;
i3c_sda_en <= 1'b1;
end
end
I3C_RD_PID:begin
i3c_sda_r <= 1'bz;
i3c_sda_en <= 1'b0;
if((~i3c_scl_dly[0]) & i3c_scl_r)begin //rising
// recv_data <= {recv_data[6:0],i3c_sda_in_i};
recv_bits <= recv_bits + 1'b1;
recv_wr <= &recv_bits[2:0];
end
else begin
recv_wr <= 1'b0;
end
end
I3C_SET_DAA:begin
i3c_sda_r <= (send_bits == 8'd7)? mstr_Tbit : tran_data[7];
i3c_sda_en <= 1'b1;
if(i3c_scl_dly[0] & (~i3c_scl_r))begin //falling
tran_data <= {tran_data[6:0],1'b0};
send_bits <= send_bits + 1'b1;
mstr_Tbit <= mstr_Tbit ^ tran_data[7];
end
end
I3C_SLV_ACK2:begin
if((~i3c_scl_dly[0]) & i3c_scl_r)begin //rising
fifo_tran_rd <= 1'b1;
end
else begin
fifo_tran_rd <= 1'b0;
end
if((i3c_scl_r|i3c_scl_dly[2:1]) && (i3c_sda_in_i == 1'b0))begin
i3c_sda_r <= 1'b0;
i3c_sda_en <= 1'b1;
end
else begin
i3c_sda_r <= 1'bz;
i3c_sda_en <= 1'b0;
end
end
I3C_STOP:begin
s_i3c_ibi_int <= 0; //clear i3c in-band interrupt
o_i3c_ibi_int <= 'd0;
if(stop_dly_cnt == {i3c_scl_div,3'd0})begin
if(i3c_rd_en == 1'b1)begin
i3c_rd_en <= 1'b0;
i3c_rd_2nd_flag <= 1'b1;
end
else begin
i3c_rd_en <= i3c_rd_en;
i3c_rd_2nd_flag <= 1'b0;
end
end
else begin
i3c_rd_en <= i3c_rd_en;
i3c_rd_2nd_flag <= i3c_rd_2nd_flag;
end
if(i3c_scl_r == 1'b1)
stop_dly_cnt <= stop_dly_cnt +'d1;
else
stop_dly_cnt <= 'd0;
if(i3c_rd_en == 1'b1)begin
i3c_sda_en<= 1'b1;
i3c_sda_r <= 1'b1;
end
else begin
if(stop_dly_cnt < i3c_scl_div[15:1])
i3c_sda_r <= 1'b0;
else if(stop_dly_cnt < {i3c_scl_div,3'd0})begin
i3c_sda_en<= 1'b1;
i3c_sda_r <= 1'b1;
end
else begin
i3c_sda_r <= 1'bz;
i3c_sda_en<= 1'b0;
end
end
end
default:
begin
end
endcase
end
reg [255:0] s_sda_dly_list;
reg [255:0] s_sda_en_dly_list;
always@(posedge sys_clk_100m)begin
s_sda_dly_list <= {s_sda_dly_list[254:0] ,i3c_sda_r};
s_sda_en_dly_list <= {s_sda_en_dly_list[254:0],i3c_sda_en};
end
////////rec sample wyr
reg [15:0] i3c_scl_high_num;
genvar i;
generate
for(i=0 ;i<8;i=i+1)begin
always@(posedge sys_clk_100m or negedge sys_rstn)begin
if(sys_rstn == 'd0)
s_sample_req[i] <= 'd0;
else if(s_sample_en[i] == 'd1)
s_sample_req[i] <= 'd0;
else if(i == s_req_bit[2:0])begin
if(cstate == I3C_RD_DATA ||(cstate ==I3C_INT_DATA && DUT_I3C_INIT_reg_rt_en))
if(i3c_scl_dly[2:1] == 2'b01)
s_sample_req[i] <= 'd1;
else
s_sample_req[i] <= s_sample_req[i];
else
s_sample_req[i] <= 'd0;
end
end
always@(posedge sys_clk_100m or negedge sys_rstn)begin
if(sys_rstn == 'd0)begin
s_sample_cnt[i] <= 'd0;
end
else if(s_sample_req[i] == 'd1)begin
s_sample_cnt[i] <= s_sample_cnt[i] + 'd1;
end
else begin
s_sample_cnt[i] <= 'd0;
end
end
assign s_sample_en[i] = s_sample_req[i] == 'd1 && s_sample_cnt[i] == s_i3c_sample_dly_num;
end
endgenerate
assign s_time_out = stop_dly_cnt > 8'd35;
always@(posedge sys_clk_100m or negedge sys_rstn)begin
if(!sys_rstn)
s_req_bit <= 0;
else if(s_time_out || cstate == I3C_IDLE)
s_req_bit <= 0;
else if(cstate == I3C_RD_DATA ||cstate ==I3C_INT_DATA)
if(i3c_scl_dly[2:1] == 2'b01)
s_req_bit <= s_req_bit +'d1;
else
s_req_bit <= s_req_bit;
else
s_req_bit <= s_req_bit;
end
assign s_sample_en_all = s_sample_en[0]|s_sample_en[1]|s_sample_en[2]|s_sample_en[3]|
s_sample_en[4]|s_sample_en[5]|s_sample_en[6]|s_sample_en[7];
always@(posedge sys_clk_100m or negedge sys_rstn)begin
if(!sys_rstn)begin
s_wr_fifo_en <= 'd0;
s_rcv_bits <= 'd0;
end
else if(s_time_out || cstate == I3C_IDLE)begin
s_wr_fifo_en <= 'd0;
s_rcv_bits <= 'd0;
end
else if(s_sample_en_all )begin
if(s_rcv_bits =='d7)begin
s_wr_fifo_en <= 'd1;
s_rcv_bits <= 'd0;
end
else begin
s_wr_fifo_en <= 'd0 ;
s_rcv_bits <= s_rcv_bits + 'd1;
end
end
else begin
s_wr_fifo_en <= 'd0 ;
s_rcv_bits <= s_rcv_bits;
end
end
always@(posedge sys_clk_100m or negedge sys_rstn)begin
if(!sys_rstn)
recv_data <= 'd0;
else if(s_time_out) //要和状态机联系起来,不然下一次发送来了,这里还卡着就完了
recv_data <= 'd0;
else if(s_sample_en_all)
recv_data <= {recv_data[6:0],i3c_sda_in_i};
else
recv_data <= recv_data;
end
fifo_i3c_recv fifo_i3c_recv_i
(
.clk (sys_clk_100m ),
.srst (fifo_recv_rst ),
.din (recv_data ),
.wr_en (s_wr_fifo_en ),
// .wr_en (recv_wr ),
.rd_en (i3c_fifo_recv_en ),
.dout (i3c_fifo_recv_dout ),
.full (),
.empty (i3c_fifo_recv_ept )
);
always@(posedge sys_clk_100m)begin
i3c_scl_dly <= {i3c_scl_dly [2:0],i3c_scl_r};
i3c_sda_dly <= {i3c_sda_dly [3:0],i3c_sda_r};
i3c_sda_en_dly <= {i3c_sda_en_dly[3:0],i3c_sda_en};
end
always@(posedge sys_clk_100m)begin
if(!sys_rstn)
i3c_tready_r <= 1'b1;
else begin
if((~i3c_tvalid_dly) & i3c_tvalid)
i3c_tready_r <= 1'b0;
else
if((cstate == I3C_STOP) && (stop_dly_cnt > 8'd30))
i3c_tready_r <= 1'b1;
else ;
end
end
endmodule
FIFO_i3c_tran配置:
naitve
common clock distributed ram
first word fall through
wite width 8 //wite depth 16
read width 8 //read depth 16
enable reset pin
FIFO_i3c_recv配置:
naitve
common clock distributed ram
first word fall through
wite width 8 //wite depth 16
read width 8 //read depth 16
enable reset pin
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)