如何在I2C主控制器代码中停止仿真时停止位?

huangapple go评论49阅读模式
英文:

How can I stop the simulation at stop bit for I2C master code?

问题

I understand that you want a translation of the provided Verilog code and testbench. Here is the translated Verilog code:

我正在尝试编写I2C主控制器的Verilog代码,但我遇到了一些问题。我能够在Quartus和ModelSim上编译并运行其测试台。但是,我想要在状态达到`STATE_STOP`时(基本上保持在`STATE_IDLE`状态),将其切换回复位模式(reset = 1)。

我可以在代码或测试台中添加什么来实现这一点?模拟在`STATE_STOP`之后继续,这点我无法理解,所以我必须在任意时间添加`$finish`或reset = 1到测试台中。

```verilog
`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;
	
	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 <= 0;
			i2c_sda <= 1;
			count <= 8'd0;
		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_WACK;
					else count <= count - 1;
				end
				
				STATE_WACK2: begin
					i2c_sda <= readorwrite;
					state <= STATE_STOP;
				end
				
				STATE_STOP: begin
					i2c_sda <= 0;
				end
			endcase
		end

end
endmodule

测试台:

module I2C_MasterTB;

	reg clk;
	reg reset;
	reg [7:0]data;
	reg [6:0]add;
	reg readorwrite;
	
	wire i2c_sda;
	wire i2c_scl;
	
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;
	
	#100;
	
	reset = 1;
	
end

endmodule

正如我之前提到的,我只是随机选择了一个时间来结束模拟,但我似乎想不出一种方法,在达到最后一个状态后结束模拟并保持在空闲状态。这是模拟图像:

如何在I2C主控制器代码中停止仿真时停止位?


I hope this helps. If you have any further questions or need assistance with the code, please let me know.
<details>
<summary>英文:</summary>
I am trying to write Verilog code for I2C master, and there are a couple of problems I am facing. I was able to compile and run its testbench on Quartus and modelsim, respectively. However, I am trying to have it switch back to reset mode on (reset = 1) once the state reaches `STATE_STOP` (Basically have it stay in `STATE_IDLE`).
What can I add to either the code or the testbench to make it that way? The simulation continues after `STATE_STOP`, which I am not able to understand, and so I have to, at an arbitrary time, add either `$finish` or reset = 1 in the testbench.

`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;
always @(posedge clk) begin
if (reset == 1)
i2c_scl &lt;= 1;
else begin
if (state == STATE_START)
i2c_scl &lt;= 0;
else if (state == STATE_IDLE || state == STATE_STOP)
i2c_scl &lt;= 1;
else 
i2c_scl &lt;= ~i2c_scl;
end
end
always @(posedge clk) begin
if (reset == 1) begin
state &lt;= 0;
i2c_sda &lt;= 1;
count &lt;= 8&#39;d0;
end
else begin
case(state)
STATE_IDLE: begin
i2c_sda &lt;= 1;
state &lt;= STATE_START;
end
STATE_START: begin
i2c_sda &lt;= 0;
state &lt;= STATE_ADDR;
count &lt;= 6;
end
STATE_ADDR: begin
i2c_sda &lt;= add[count];
if (count == 0) state &lt;= STATE_RW;
else count &lt;= count - 1;
end
STATE_RW: begin
i2c_sda &lt;= readorwrite;
state &lt;= STATE_WACK;
end
STATE_WACK: begin
i2c_sda &lt;= 0;
state &lt;= STATE_DATA;
count &lt;= 7;
end
STATE_DATA: begin
i2c_sda &lt;= data[count];
if (count == 0) state &lt;= STATE_WACK;
else count &lt;= count - 1;
end
STATE_WACK2: begin
i2c_sda &lt;= readorwrite;
state &lt;= STATE_STOP;
end
STATE_STOP: begin
i2c_sda &lt;= 0;
end
endcase
end

end
endmodule


The testbench:

module I2C_MasterTB;

reg clk;
reg reset;
reg [7:0]data;
reg [6:0]add;
reg readorwrite;
wire i2c_sda;
wire i2c_scl;

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;
#100;
reset = 1;

end

endmodule


As I already mentioned, I only arbitrarily chose a time period to finish the simulation, but I can&#39;t seem to think of the way to the end the simulation as soon as it reaches the last state and have it stay in idle state.  Here is the simulation:
[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/eTc05.png
</details>
# 答案1
**得分**: 1
The problem is in the design, not the testbench.
The state machine can never enter the `STATE_WACK2`, and therefore it also can never enter `STATE_STOP`. I think the bug is in `STATE_DATA`, where you probably want to transition to `WACK2`, not `WACK`:
STATE_DATA: begin
i2c_sda &lt;= data[count];
if (count == 0) state &lt;= STATE_WACK2;
else count &lt;= count - 1;
end
After that is fixed, another bug is that you always stay in `STATE_STOP`. You probably want to transition into `IDLE`:
STATE_STOP: begin
i2c_sda &lt;= 0;
state &lt;= STATE_IDLE;
end
You also need a control signal to decide when you want to start an I2C transfer, otherwise, the state machine will start up again. You should add an input signal to the design for that, like `start`.
STATE_IDLE: begin
i2c_sda &lt;= 1;
state &lt;= (start) ? STATE_START : STATE_IDLE;
end
<details>
<summary>英文:</summary>
The problem is in the design, not the testbench.
The state machine can never enter the `STATE_WACK2`, and therefore it also can never enter `STATE_STOP`.  I think the bug is in `STATE_DATA`, where you probably want to transition to `WACK2`, not `WACK`:
STATE_DATA: begin
i2c_sda &lt;= data[count];
if (count == 0) state &lt;= STATE_WACK2;
else count &lt;= count - 1;
end
After that is fixed, another bug is that you always stay in `STATE_STOP`.  You probably want to transition into `IDLE`:
STATE_STOP: begin
i2c_sda &lt;= 0;
state &lt;= STATE_IDLE;
end
You also need a control signal to decide when you want to start an I2C transfer, otherwise, the  state machine will start up again.  You should add an input signal to the design for that, like `start`.
STATE_IDLE: begin
i2c_sda &lt;= 1;
state &lt;= (start) ? STATE_START : STATE_IDLE;
end
</details>
# 答案2
**得分**: -1
关于仅在达到特定值后停止测试台的时间控制,您应该能够使用分层引用访问模块的本地值,然后使用等式检查与 wait() 结合使用。
要获取该值,您可以在测试台文件中使用类似 `uut.state` 的方式,在设置时间的位置(即替换 `#100`)使用 `wait(uut.state == STATE_STOP)`。
测试台应该在满足条件之前暂停,然后继续进行。
<details>
<summary>英文:</summary>
In terms of just timing the testbench to stop after a certain value is reached, you should be able to access the module local value using hierarchical reference and then use wait() with an equality check. 
To get the value it would be something like `uut.state` in your testbench file and in place of a set time (i.e. replacing `#100`) use `wait(uut.state == STATE_STOP)`. 
The testbench should pause there until the condition is met and proceed afterwards.
</details>

huangapple
  • 本文由 发表于 2023年6月6日 06:09:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76410295.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定