如何使用多个状态寄存器以两个常块模式编写verilog代码?

时间:2017-07-26 09:02:23

标签: verilog

我是Verilog的先驱。我阅读了一些关于推荐的Verilog编码样式的材料,如this paperstackoverflow's questions 现在,我向他们学习了“两个总是阻挡风格”的建议;将代码分成两部分,一部分是修改next的组合块,另一部分是一个顺序块,将它分配给state reg。就像这样。

reg [1:0] state, next;

always @(posedge clk or negedge rst_n)
    if (!rst_n)
        state <= IDLE;
    else
        state <= next;

 always @(state or go or ws) begin
     next = 'bx;
     rd = 1'b0;
     ds = 1'b0;
    case (state)
        IDLE : if (go) next = READ;
               else next = IDLE;
 ...

这是我的问题。我找到的所有示例代码只有一对名为statenext的寄存器  但是,如果有多个regs保留某些类型的状态,我应该如何以state - 和 - next样式编写代码?
准备与next相对应的wait_count regs看起来有点多余,因为所有regs都会加倍。

例如,请查看我在下面写的RS232c的UART发送器代码。 它需要statesend_bufstate作为wait_count_next注册。因此,我为组合块写了相应的state_nextsend_buf_nextnext作为module uart_sender #( parameter clock = 50_000_000, parameter baudrate = 9600 ) ( input clk, input go, input [7:0] data, output tx, output ready ); parameter wait_time = clock / baudrate; parameter send_ready = 10'b0000000000, send_start = 10'b0000000001, send_stop = 10'b1000000000; reg [31:0] wait_count = wait_time, wait_count_next = wait_time; reg [9:0] state = send_ready, state_next = send_ready; reg [8:0] send_buf = 9'b111111111, send_buf_next = 9'b111111111; always @(posedge clk) begin state <= state_next; wait_count <= wait_count_next; send_buf <= send_buf_next; end always @(*) begin state_next = state; wait_count_next = wait_count; send_buf_next = send_buf; case (state) send_ready: begin if (go == 1) begin state_next = send_start; wait_count_next = wait_time; send_buf_next = {data, 1'b0}; end end default: begin if (wait_count == 0) begin if (state == send_stop) state_next = send_ready; else state_next = {state[8:0], 1'b0}; wait_count_next = wait_time; send_buf_next = {1'b1, send_buf[8:1]}; end else begin wait_count_next = wait_count - 1; end end endcase end assign tx = send_buf[0]; assign ready = state == send_ready; endmodule 。这对我来说看起来有点多余和麻烦。还有其他正确的方法吗?

DD/MM/YYYY

1 个答案:

答案 0 :(得分:1)

我认为你做得很好并正确地扭转了变量。问题是如果没有翻牌,你就会有一个循环。即如果你写下面的内容,模拟将循环,硅可能会烧坏:

 always_comb wait_count = wait_count - 1;

所以,你需要通过插入一个翻牌来暂存:

 always_ff @(posedge clk)
    wait_count <= wait_count - 1;

或者在您的情况下,您使用的是中间wait_count_next,这是一种很好的风格:

 always_ff @(posedge clk)
    wait_count_next <= wait_count;
 always_comb
    wait_count = wait_count_next;

您可能会或可能不会遇到上次分配的问题。您要将哪个版本的信号分配给txready?失败的那个?

是的,您可以在多个块中拆分这些块,但在这种情况下似乎没有必要。

是的,另一种风格是在单个翻牌中写入所有内容总是阻止。但这会降低可读性,更容易出错,并可能出现综合问题。