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

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

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:

  1. 我正在尝试编写I2C主控制器的Verilog代码,但我遇到了一些问题。我能够在QuartusModelSim上编译并运行其测试台。但是,我想要在状态达到`STATE_STOP`时(基本上保持在`STATE_IDLE`状态),将其切换回复位模式(reset = 1)。
  2. 我可以在代码或测试台中添加什么来实现这一点?模拟在`STATE_STOP`之后继续,这点我无法理解,所以我必须在任意时间添加`$finish`reset = 1到测试台中。
  3. ```verilog
  4. `timescale 1ns/1ps
  5. module I2C_Master(
  6. input wire clk,
  7. input wire reset,
  8. input wire [7:0]data,
  9. input wire [6:0]add,
  10. input wire readorwrite,
  11. output reg i2c_sda,
  12. output reg i2c_scl
  13. );
  14. localparam STATE_IDLE = 0;
  15. localparam STATE_START = 1;
  16. localparam STATE_ADDR = 2;
  17. localparam STATE_RW = 3;
  18. localparam STATE_WACK = 4;
  19. localparam STATE_DATA = 5;
  20. localparam STATE_STOP = 6;
  21. localparam STATE_WACK2 = 7;
  22. reg [7:0] state;
  23. reg [7:0] count;
  24. always @(posedge clk) begin
  25. if (reset == 1)
  26. i2c_scl <= 1;
  27. else begin
  28. if (state == STATE_START)
  29. i2c_scl <= 0;
  30. else if (state == STATE_IDLE || state == STATE_STOP)
  31. i2c_scl <= 1;
  32. else
  33. i2c_scl <= ~i2c_scl;
  34. end
  35. end
  36. always @(posedge clk) begin
  37. if (reset == 1) begin
  38. state <= 0;
  39. i2c_sda <= 1;
  40. count <= 8'd0;
  41. end
  42. else begin
  43. case(state)
  44. STATE_IDLE: begin
  45. i2c_sda <= 1;
  46. state <= STATE_START;
  47. end
  48. STATE_START: begin
  49. i2c_sda <= 0;
  50. state <= STATE_ADDR;
  51. count <= 6;
  52. end
  53. STATE_ADDR: begin
  54. i2c_sda <= add[count];
  55. if (count == 0) state <= STATE_RW;
  56. else count <= count - 1;
  57. end
  58. STATE_RW: begin
  59. i2c_sda <= readorwrite;
  60. state <= STATE_WACK;
  61. end
  62. STATE_WACK: begin
  63. i2c_sda <= 0;
  64. state <= STATE_DATA;
  65. count <= 7;
  66. end
  67. STATE_DATA: begin
  68. i2c_sda <= data[count];
  69. if (count == 0) state <= STATE_WACK;
  70. else count <= count - 1;
  71. end
  72. STATE_WACK2: begin
  73. i2c_sda <= readorwrite;
  74. state <= STATE_STOP;
  75. end
  76. STATE_STOP: begin
  77. i2c_sda <= 0;
  78. end
  79. endcase
  80. end
  81. end
  82. endmodule

测试台:

  1. module I2C_MasterTB;
  2. reg clk;
  3. reg reset;
  4. reg [7:0]data;
  5. reg [6:0]add;
  6. reg readorwrite;
  7. wire i2c_sda;
  8. wire i2c_scl;
  9. I2C_Master uut (
  10. .clk(clk),
  11. .reset(reset),
  12. .data(data),
  13. .add(add),
  14. .readorwrite(readorwrite),
  15. .i2c_sda(i2c_sda),
  16. .i2c_scl(i2c_scl)
  17. );
  18. initial begin
  19. clk = 0;
  20. forever begin
  21. clk = #1 ~clk;
  22. end
  23. end
  24. initial begin
  25. reset = 1;
  26. add <= 7'h50;
  27. data <= 8'haa;
  28. readorwrite <= 0;
  29. #10;
  30. reset = 0;
  31. #100;
  32. reset = 1;
  33. end
  34. endmodule

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

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

  1. I hope this helps. If you have any further questions or need assistance with the code, please let me know.
  2. <details>
  3. <summary>英文:</summary>
  4. 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`).
  5. 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
);

  1. localparam STATE_IDLE = 0;
  2. localparam STATE_START = 1;
  3. localparam STATE_ADDR = 2;
  4. localparam STATE_RW = 3;
  5. localparam STATE_WACK = 4;
  6. localparam STATE_DATA = 5;
  7. localparam STATE_STOP = 6;
  8. localparam STATE_WACK2 = 7;
  9. reg [7:0] state;
  10. reg [7:0] count;
  11. always @(posedge clk) begin
  12. if (reset == 1)
  13. i2c_scl &lt;= 1;
  14. else begin
  15. if (state == STATE_START)
  16. i2c_scl &lt;= 0;
  17. else if (state == STATE_IDLE || state == STATE_STOP)
  18. i2c_scl &lt;= 1;
  19. else
  20. i2c_scl &lt;= ~i2c_scl;
  21. end
  22. end
  23. always @(posedge clk) begin
  24. if (reset == 1) begin
  25. state &lt;= 0;
  26. i2c_sda &lt;= 1;
  27. count &lt;= 8&#39;d0;
  28. end
  29. else begin
  30. case(state)
  31. STATE_IDLE: begin
  32. i2c_sda &lt;= 1;
  33. state &lt;= STATE_START;
  34. end
  35. STATE_START: begin
  36. i2c_sda &lt;= 0;
  37. state &lt;= STATE_ADDR;
  38. count &lt;= 6;
  39. end
  40. STATE_ADDR: begin
  41. i2c_sda &lt;= add[count];
  42. if (count == 0) state &lt;= STATE_RW;
  43. else count &lt;= count - 1;
  44. end
  45. STATE_RW: begin
  46. i2c_sda &lt;= readorwrite;
  47. state &lt;= STATE_WACK;
  48. end
  49. STATE_WACK: begin
  50. i2c_sda &lt;= 0;
  51. state &lt;= STATE_DATA;
  52. count &lt;= 7;
  53. end
  54. STATE_DATA: begin
  55. i2c_sda &lt;= data[count];
  56. if (count == 0) state &lt;= STATE_WACK;
  57. else count &lt;= count - 1;
  58. end
  59. STATE_WACK2: begin
  60. i2c_sda &lt;= readorwrite;
  61. state &lt;= STATE_STOP;
  62. end
  63. STATE_STOP: begin
  64. i2c_sda &lt;= 0;
  65. end
  66. endcase
  67. end

end
endmodule

  1. The testbench:

module I2C_MasterTB;

  1. reg clk;
  2. reg reset;
  3. reg [7:0]data;
  4. reg [6:0]add;
  5. reg readorwrite;
  6. wire i2c_sda;
  7. 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;

  1. #10;
  2. reset = 0;
  3. #100;
  4. reset = 1;

end

endmodule

  1. 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:
  2. [![enter image description here][1]][1]
  3. [1]: https://i.stack.imgur.com/eTc05.png
  4. </details>
  5. # 答案1
  6. **得分**: 1
  7. The problem is in the design, not the testbench.
  8. 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`:
  9. STATE_DATA: begin
  10. i2c_sda &lt;= data[count];
  11. if (count == 0) state &lt;= STATE_WACK2;
  12. else count &lt;= count - 1;
  13. end
  14. After that is fixed, another bug is that you always stay in `STATE_STOP`. You probably want to transition into `IDLE`:
  15. STATE_STOP: begin
  16. i2c_sda &lt;= 0;
  17. state &lt;= STATE_IDLE;
  18. end
  19. 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`.
  20. STATE_IDLE: begin
  21. i2c_sda &lt;= 1;
  22. state &lt;= (start) ? STATE_START : STATE_IDLE;
  23. end
  24. <details>
  25. <summary>英文:</summary>
  26. The problem is in the design, not the testbench.
  27. 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`:
  28. STATE_DATA: begin
  29. i2c_sda &lt;= data[count];
  30. if (count == 0) state &lt;= STATE_WACK2;
  31. else count &lt;= count - 1;
  32. end
  33. After that is fixed, another bug is that you always stay in `STATE_STOP`. You probably want to transition into `IDLE`:
  34. STATE_STOP: begin
  35. i2c_sda &lt;= 0;
  36. state &lt;= STATE_IDLE;
  37. end
  38. 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`.
  39. STATE_IDLE: begin
  40. i2c_sda &lt;= 1;
  41. state &lt;= (start) ? STATE_START : STATE_IDLE;
  42. end
  43. </details>
  44. # 答案2
  45. **得分**: -1
  46. 关于仅在达到特定值后停止测试台的时间控制,您应该能够使用分层引用访问模块的本地值,然后使用等式检查与 wait() 结合使用。
  47. 要获取该值,您可以在测试台文件中使用类似 `uut.state` 的方式,在设置时间的位置(即替换 `#100`)使用 `wait(uut.state == STATE_STOP)`
  48. 测试台应该在满足条件之前暂停,然后继续进行。
  49. <details>
  50. <summary>英文:</summary>
  51. 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.
  52. 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)`.
  53. The testbench should pause there until the condition is met and proceed afterwards.
  54. </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:

确定