下面开发的只有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

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐