10-27-2013 08:28 AM
On Spartan-6, synthesizing the source code below with ISE 14.7 results in the block RAM not being connected properly. In the generated netlist, an obvious effect of the bug is that the WE and data input ports of the block RAM are grounded. It seems to manifest itself when a block RAM uses byte-wide write enable, and that signal is driven by a state machine.
module memtest( input clk, input [9:0] adr, input [31:0] dat_w, output [31:0] dat_r, input wex ); reg [3:0] we; reg [31:0] mem[0:1023]; reg [9:0] memadr_r; always @(posedge clk) begin if (we) mem[adr][7:0] <= dat_w[7:0]; if (we) mem[adr][15:8] <= dat_w[15:8]; if (we) mem[adr][23:16] <= dat_w[23:16]; if (we) mem[adr][31:24] <= dat_w[31:24]; memadr_r <= adr; end assign dat_r = mem[memadr_r]; reg [1:0] state; reg [1:0] next_state; always @(posedge clk) state <= next_state; always @(*) begin we <= 0; next_state <= state; case(state) 2'd0: if(wex) next_state <= 1; 2'd1: next_state <= 2; 2'd2: begin we <= 15; next_state <= 0; end endcase end endmodule
10-27-2013 09:30 AM
10-28-2013 10:29 AM
always @(*) begin we <= 0; next_state <= state; case(state) 2'd0: if(wex) next_state <= 1; 2'd1: next_state <= 2; 2'd2: begin we <= 15; next_state <= 0; end endcase end endmodule
TWO-PROCESS STATE MACHINE FAIL.
Try recoding it as a single synchronous always block.
I think the "default assignments" to we and next_state (with the expectation that the signal might be overridden in a decoded state) don't work in a combinatorial always block. It forms an infinite loop.
10-28-2013 12:27 PM
10-28-2013 04:44 PM
There's nothing wrong with that state machine style. Other than the non-blocking statements in the combinational block. I know many feel strongly on this, and for newbies I suggest the single process state machine style. But if you know what you're doing this two process style is fine (and has some advantages IMHO).
You cannot form an infinite loop in a single always block like this. An always block CANNOT trigger itself. Part of the verilog stratified event queue.
As to the OP's problem...
Early on in (ISE 12.2 I think), we noticed similar problems with RAM inference. The byte enables didn't always work properly. We tried breaking it down to a simple testcase for Xilinx to look at, and the results were inconsistent - we couldn't repeat the failure with a testcase.
So we worked around the issue by not inferring the Byte enables - instead we just inferred (4) parallel 8-bit RAMs, with seperate Write enables. This effectively decreases your RAM granularity you're inferring (4) Byte-wide memories. But it works...
I'd not thought that the problem was related to a state machine driving some of the RAM control signals. That might be a good hint that we didn't think of. If you can replicate the problem in a small testcase, I'd submit the problem to Xilinx.
10-28-2013 05:24 PM
(I know this is no longer on the RAM topic, but the state machine topic)
An always block CANNOT trigger itself.
It is true that an always block cannot directly trigger itself, but it can do so indirectly. If (as the OP did in this example) you use non-blocking assignments in your always block, then the non-blocking assignment can re-trigger the same always block.
The reason a blocking assignment cannot re-trigger the same block is that the blocking assignment is done immediately; thus, when the signal makes its state change, the always block is not "blocked" waiting for the always @* event to occur. When the block ends, and returns to waiting for the always @*, the variable is already at its new value, and hence the block won't retrigger.
However, a non-blocking assignment is defferred to the NBA portion of the stratified queue, which is executed after all active events. At that time, all "always" blocks that have no internal timing control (no #, @ or wait statements) are back at the always @(*) or always @(posedge clk) statement - waiting for an event to re-trigger them. Thus, when the NBA completes, the block can re-trigger.
a = !a;
Will not (on its own) create an infinite loop, but
a <= !a;
To that point - you should NEVER use a non-blocking assignment inside an always @(*) block - you should use blocking assignments.