You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在I2C Master代码中于STOP位停止仿真并维持IDLE状态?

解决I2C Master仿真自动终止并维持IDLE状态的问题

问题描述

编写的I2C Master Verilog代码可在Quartus编译、Modelsim仿真,但当前仿真进入STATE_STOP状态后会持续运行,只能手动设置时间或调用$finish/置reset=1来终止。需求是进入STATE_STOP后自动置reset=1,让设备维持在STATE_IDLE状态,无需手动干预。

解决方案

方案一:修改测试台,自动监测状态触发复位

测试台可通过层次化访问DUT内部的state信号,当检测到进入STATE_STOP时,自动置reset=1并结束仿真。

修改后的测试台代码

module I2C_MasterTB;

    reg clk;
    reg reset;
    reg [7:0]data;
    reg [6:0]add;
    reg readorwrite;
    
    wire i2c_sda;
    wire i2c_scl;
    // 层次化访问DUT内部state信号,Modelsim支持该语法
    wire [7:0] dut_state;
    assign dut_state = uut.state;
    
I2C_Master uut (
    .clk(clk),
    .reset(reset),
    .data(data),
    .add(add),
    .readorwrite(readorwrite),
    .i2c_sda(i2c_sda),
    .i2c_scl(i2c_scl)
);

initial begin
    clk = 0;
    forever begin
        clk = #1 ~clk;
    end
end

initial begin
    reset = 1;
    add <= 7'h50;
    data <= 8'haa;
    readorwrite <= 0;
    
    #10;
    reset = 0;
end

// 监测DUT状态,进入STOP后触发复位并结束仿真
always @(posedge clk) begin
    if (dut_state == uut.STATE_STOP) begin
        reset <= 1;
        // 延迟1个时钟周期后结束仿真,确保复位逻辑生效
        #2 $finish;
    end
end

endmodule

方案二:修改DUT状态机,完成STOP后自动回到IDLE

如果不需要依赖外部复位,可直接修改DUT的状态机逻辑,在STATE_STOP状态完成后自动跳转到STATE_IDLE并维持,同时保证I2C总线信号符合规范。

修改后的I2C_Master代码

`timescale 1ns/1ps

module I2C_Master(
    input wire clk,
    input wire reset,
    input wire [7:0]data,
    input wire [6:0]add,
    input wire readorwrite,
    output reg i2c_sda,
    output reg i2c_scl
    );
    
    localparam STATE_IDLE = 0;
    localparam STATE_START = 1;
    localparam STATE_ADDR = 2;
    localparam STATE_RW = 3;
    localparam STATE_WACK = 4;
    localparam STATE_DATA = 5;
    localparam STATE_STOP = 6;
    localparam STATE_WACK2 = 7;
    
    
    reg [7:0] state;
    reg [7:0] count;
    reg stop_done; // 标记STOP状态是否完成
    
    always @(posedge clk) begin
        if (reset == 1)
            i2c_scl <= 1;
        else begin
            if (state == STATE_START)
                i2c_scl <= 0;
            else if (state == STATE_IDLE || state == STATE_STOP)
                i2c_scl <= 1;
            else 
                i2c_scl <= ~i2c_scl;
        end
    end
    
    always @(posedge clk) begin
        if (reset == 1) begin
            state <= STATE_IDLE;
            i2c_sda <= 1;
            count <= 8'd0;
            stop_done <= 1'b0;
        end
        else begin
            case(state)
            
                STATE_IDLE: begin
                    i2c_sda <= 1;
                    state <= STATE_START;
                end
                
                STATE_START: begin
                    i2c_sda <= 0;
                    state <= STATE_ADDR;
                    count <= 6;
                end
                
                STATE_ADDR: begin
                    i2c_sda <= add[count];
                    if (count == 0) state <= STATE_RW;
                    else count <= count - 1;
                end
                
                STATE_RW: begin
                    i2c_sda <= readorwrite;
                    state <= STATE_WACK;
                end
                
                STATE_WACK: begin
                    i2c_sda <= 0;
                    state <= STATE_DATA;
                    count <= 7;
                end
                
                STATE_DATA: begin
                    i2c_sda <= data[count];
                    if (count == 0) state <= STATE_WACK2; // 修正原代码死循环问题
                    else count <= count - 1;
                end
                
                STATE_WACK2: begin
                    i2c_sda <= readorwrite;
                    state <= STATE_STOP;
                end
                
                STATE_STOP: begin
                    if (!stop_done) begin
                        // 生成标准I2C STOP信号:SCL高电平时,SDA从0拉到1
                        i2c_sda <= 1;
                        stop_done <= 1'b1;
                    end else begin
                        // STOP完成后跳回IDLE并维持
                        state <= STATE_IDLE;
                        stop_done <= 1'b0;
                    end
                end
            endcase
        end
    end
endmodule

注:原DUT的STATE_DATA状态在count==0时跳回STATE_WACK会导致死循环,方案二中已修正为跳转到STATE_WACK2,保证状态机能正常走到STATE_STOP。

内容的提问来源于stack exchange,提问作者Qazi Zabeer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 15:51:59