I am fairly new to Verilog and in general Digital Design. I am working on a project which has a state machine. The module, in a particular state, receives a read request packet from some other module and I have to decode the required read response data size and send back as many data bytes in the payload. Now I have to do this every n clock cycles.
I am finding it difficult to understand where should my count be updated and where should it be assigned the next count value? Here is the general structure of my code.
always@(posedge clk_i or negedge resetn_i) begin
if (resetn_i == 1'b0) begin
reg_read_en <= 1'b0;
reg_write_en <= 1'b0;
count <= 3'b111;
next_count <= 3'b111;
state <= S_INITIAL;
end else begin
state <= next_state;
count <= next_count;
end
This is the sequential block.Now in my combinational block
always@(*) begin
next_state = state;
next_count = count;
.......
........
M_PASSIVE:begin
if(count == 3'b000)
begin
//Update some registers with new data values
end else begin
next_count = count - 3'b001;
end
I am unable to understand does this wait the required count no of cycles and then update the reg values or I am missing something here.
I would very much appreciate some clarity about this.
P.S. Pardon me if I am missing some fundamental aspects of behavioural design regarding difference between sequential and combinational blocks.
Here is a complete code of what I am trying to do. Essentially I want to read a packet, turn of reading of packets, wait 7 or 8 clock cycles or N clk cycles and then send a read response with the data in the registers which are assigned to output ports continuosly.
always@(posedge clk_i or negedge resetn_i) begin
if (resetn_i == 1'b0) begin
reg_read_en <= 1'b0;
reg_write_en <= 1'b0;
count <= 3'b111;
state <= S_INITIAL;
end else begin
state <= next_state;
count <= next_count;
end
end
always@(*) begin
next_state = state;
next_count = count;
case(state)
S_INITIAL: begin //not enabled
if(enable_i == 1'b1) begin
next_state = S_ENABLED;
end
reg_read_en <= 1'b0;
reg_write_en <= 1'b0;
end
S_ENABLED: begin
if(enable_i == 1'b0) begin
next_state = S_INITIAL;
end
case(mode_i)
M_PASSIVE:begin
reg_read_en = dnoc_packet_ready;
//pkt_type = dnoc_packet_pld_header[]
if(dnoc_packet_ready)
begin
reg_read_en = 1'b0;
if(count == 3'b000)
begin
reg_write_en = 1'b1;
read_resp_tx_data_size = 3'b001;
read_resp_tx_qpe_dest = 6'b000010;
read_resp_tx_mod_dest = 5'b00000;
read_resp_tx_c_routing = 0;
read_resp_tx_pld_header = 17'b00100101000000000;
read_resp_tx_pld_address = 32'h0001;
read_resp_tx_pld_data = 256;
//count = 3'b111;
reg_write_en = 1'b0;
end
next_count = count - 3'b001;
end
end
Best Answer
There are a couple of things to point out in your code.
1) you're driving the
reg_read_en
andreg_write_en
signals in both always blocks.and
This isn't synthesizable and probably wouldn't be allowed by some simulation tools either.
2) You're inferring latches in your combinitorial blocks:
The marked
if
statement needs a correspondingelse
in every case. You need to cover all the different possible options.This is why in my comment I suggested you use a single sequential block, it'll fix both of these issues, and make everything a lot easier to keep track of.
So here's an example of combining them: