looking for critique for a lcd_controller module implementat

F

Fei Liu

Guest
(originally posted on c.a.fpga but it seems that may not be the right
newsgroup, reposted here in c.l.verilog)

Hello gentle readers,
I started playing with FPGA and verilog about a month ago. As a fun
starting project, my goal is to allow interaction between host linux pc
and fpga lcd display. The connection is made through serial RS323
interface. Here is my lcd controller module that accomplished my goal. I
am looking for your advice and suggestions and in what ways I can
improve this module. I am hoping to learn from this process.

module lcd_controller (clk, data_ready, rx_data, lcd_rs, lcd_rw, lcd_e,
lcd_4, lcd_5, lcd_6, lcd_7);

parameter k = 18;
// in register_input mode, the input doesn't have to stay valid
// while the character is been transmitted
parameter register_input = 1;
parameter clr = 8'h0A;

input clk;
input data_ready;
input [7:0] rx_data;
output lcd_rs;
output lcd_rw;
output lcd_e;
output lcd_7;
output lcd_6;
output lcd_5;
output lcd_4;

reg lcd_e, lcd_rs, lcd_rw, lcd_7, lcd_6, lcd_5, lcd_4;

reg [k+8:0] count=0;
reg [6:0] lcd_code = 0;

reg [2:0] state=3'b000;
reg [2:0] next_state=3'b000;

wire lcd_ready = (state==1);

// store rx_data locally
reg [7:0] lcd_dataReg;
always @(posedge clk)
if(data_ready & lcd_ready)
lcd_dataReg <= rx_data;
wire [7:0] lcd_dataD = register_input ? lcd_dataReg : rx_data;

// continuous assignment by default of wire type, clr key clears display
wire clear = (rx_data == clr)? 1:0;
//assign {lcd_e,lcd_rs,lcd_rw,lcd_7,lcd_6,lcd_5,lcd_4} = lcd_code;

// sequential logic
always @ (posedge clk)
state <= next_state;

always @ (posedge clk)
begin
if(state != 3'b001)
begin
count <= count + 1;
if(count[4] && state == 3'b010)
count <= 0;
if(count[4] && state == 3'b100)
count <= 0;
if(count[5] && state == 3'b011)
count <= 0;
if(count[10] && state == 3'b101)
count <= 0;
end
else
count <= 0;
{lcd_e,lcd_rs,lcd_rw,lcd_7,lcd_6,lcd_5,lcd_4} <= lcd_code;
if(state == 0 || state == 6) lcd_e <= ^count[k+1:k];
end // sequential logic

// combinatorial logic
always @ (state or count or data_ready or clear) begin
case(state)
3'b000:
begin
if(count[k+5:k+2] == 12)
next_state <= 3'b1; // idle_data/1
else
next_state <= 0;
end
3'b001:
begin
if(data_ready) begin
if(clear)
next_state <= 3'b110; // clear/6
else
next_state <= 3'b10; // disp_hn/2
end
else
next_state <= 3'b1; // idle_data/1
end
3'b010:
begin
if(count[4])
next_state <= 3'b11; // idle_high/3
else
next_state <= 3'b10; // disp_hn/3
end
3'b011:
begin
if(count[5])
next_state <= 3'b100; // disp_ln/4
else
next_state <= 3'b11; // idle_high/3
end
3'b100:
begin
if(count[4])
next_state <= 3'b101; // wait/5
else
next_state <= 3'b100; // disp_ln/4
end
3'b101:
begin
if(count[10])
next_state <= 3'b1; // idle_data/1
else
next_state <= 3'b101; // wait/5
end
3'b110:
begin
if(count[k+3:k+2] == 2)
next_state <= 3'h1; // idle_data/1
else
next_state <= 3'h6; // clear/6
end
endcase
end // combinatorial logic

// output logic
always @(state or count or lcd_dataD) begin
lcd_code <= 7'h00;
case(state)
3'b000:
begin
case (count[k+5:k+2])
0: lcd_code <= 7'h43; // power-on initialization
1: lcd_code <= 7'h43;
2: lcd_code <= 7'h43;
3: lcd_code <= 7'h42;
4: lcd_code <= 7'h42; // function set
5: lcd_code <= 7'h48;
6: lcd_code <= 7'h40; // entry mode set
7: lcd_code <= 7'h46;
8: lcd_code <= 7'h40; // display on/off control
9: lcd_code <= 7'h4C;
10: lcd_code <= 7'h40; // display clear
11: lcd_code <= 7'h41;
endcase
end
3'b001:
lcd_code <= 7'h00;
3'b010:
lcd_code <= {3'b110, lcd_dataD[7:4]};
3'b011:
lcd_code <= 7'b0110000;
3'b100:
lcd_code <= {3'b110, lcd_dataD[3:0]};
3'b101:
lcd_code <= 7'b0110000;
3'b110:
begin
case(count[k+3:k+2])
0: lcd_code <= 7'h40; // display clear
1: lcd_code <= 7'h41;
endcase
end
endcase
end // output logic

endmodule
 
On Fri, 11 Apr 2008 12:08:06 -0400
Fei Liu <fei.liu@gmail.com> wrote:

<snip>

parameter k = 18;
For readability, it's best to use some meaningful names for your
parameters.

<snip>

count=0;
reg [6:0] lcd_code = 0;

reg [2:0] state=3'b000;
reg [2:0] next_state=3'b000;
Don't assign initial/reset values like this. For sequential logic, reset
should be explicitly stated in the always block. For combinational
logic, initial values in RTL code would only hide problems.

// sequential logic
always @ (posedge clk)
state <= next_state;
See above, use an explicit reset clauses.

always @ (posedge clk)
begin
if(state != 3'b001)
begin
count <= count + 1;
if(count[4] && state == 3'b010)
count <= 0;
if(count[4] && state == 3'b100)
count <= 0;
if(count[5] && state == 3'b011)
count <= 0;
if(count[10] && state == 3'b101)
count <= 0;
end
else
count <= 0;
{lcd_e,lcd_rs,lcd_rw,lcd_7,lcd_6,lcd_5,lcd_4} <= lcd_code;
if(state == 0 || state == 6) lcd_e <= ^count[k+1:k];
end // sequential logic
How about replacing the nested if statements with a case statement? It
would be much more clear what your intent is.

// combinatorial logic
always @ (state or count or data_ready or clear) begin
case(state)
3'b000:
begin
if(count[k+5:k+2] == 12)
next_state <= 3'b1; // idle_data/1
else
next_state <= 0;
end
snip

Not a good habit to use non-blocking assignments here. Use blocking
assignments when you are dealing with combinational logic.

~Jason

--
If God had wanted us to be concerned for the plight of the toads, he
would have made them cute and furry.
-- Dave Barry
 
Jason Zheng wrote:
On Fri, 11 Apr 2008 12:08:06 -0400
Fei Liu <fei.liu@gmail.com> wrote:

snip

parameter k = 18;

For readability, it's best to use some meaningful names for your
parameters.
sounds good.

snip

reg [k+8:0] count=0;
reg [6:0] lcd_code = 0;

reg [2:0] state=3'b000;
reg [2:0] next_state=3'b000;


Don't assign initial/reset values like this. For sequential logic, reset
should be explicitly stated in the always block. For combinational
logic, initial values in RTL code would only hide problems.

initial value cannot be synthesized, is that what you mean?
// sequential logic
always @ (posedge clk)
state <= next_state;

See above, use an explicit reset clauses.
can you give an example by 'explicit reset clause'? this state
assignment is textbook use.
always @ (posedge clk)
begin
if(state != 3'b001)
begin
count <= count + 1;
if(count[4] && state == 3'b010)
count <= 0;
if(count[4] && state == 3'b100)
count <= 0;
if(count[5] && state == 3'b011)
count <= 0;
if(count[10] && state == 3'b101)
count <= 0;
end
else
count <= 0;
{lcd_e,lcd_rs,lcd_rw,lcd_7,lcd_6,lcd_5,lcd_4} <= lcd_code;
if(state == 0 || state == 6) lcd_e <= ^count[k+1:k];
end // sequential logic

How about replacing the nested if statements with a case statement? It
would be much more clear what your intent is.
I don't think so, in this case, this is clearer because otherwise there
will be a lot of code repetition without rearranging state numbers.

But the advice is in general reasonable.
// combinatorial logic
always @ (state or count or data_ready or clear) begin
case(state)
3'b000:
begin
if(count[k+5:k+2] == 12)
next_state <= 3'b1; // idle_data/1
else
next_state <= 0;
end
snip

Not a good habit to use non-blocking assignments here. Use blocking
assignments when you are dealing with combinational logic.

Nice catch, thanks
~Jason
 
On Wed, 16 Apr 2008 14:29:31 -0400
Fei Liu <fei.liu@gmail.com> wrote:

Don't assign initial/reset values like this. For sequential logic,
reset should be explicitly stated in the always block. For
combinational logic, initial values in RTL code would only hide
problems.

initial value cannot be synthesized, is that what you mean?
The real problem is post/pre-synthesis mismatches caused by initial
blocks. Synthesis tool would ignore all initial blocks.

// sequential logic
always @ (posedge clk)
state <= next_state;

See above, use an explicit reset clauses.
can you give an example by 'explicit reset clause'? this state
assignment is textbook use.
always @ (posedge clk)
if (rst)
state <= 0;
else
state <= next_state;

always @ (posedge clk)
begin
if(state != 3'b001)
begin
count <= count + 1;
if(count[4] && state == 3'b010)
count <= 0;
if(count[4] && state == 3'b100)
count <= 0;
if(count[5] && state == 3'b011)
count <= 0;
if(count[10] && state == 3'b101)
count <= 0;
end
How about replacing the nested if statements with a case statement?
It would be much more clear what your intent is.


I don't think so, in this case, this is clearer because otherwise
there will be a lot of code repetition without rearranging state
numbers.

But the advice is in general reasonable.
I guess clarity is in the eye of beholder. In general, I'd avoid using
negations, since they tend to cause confusions:

case (state):
3'b001: count <= 0;
3'b010,3'b100: count <= count[4] ? 0 : count + 1;
3'b011: count <= count[5] ? 0 : count + 1;
3'b101: count <= count[10] ? 0 : count + 1;
default: count <= count + 1;
endcase

--
I put instant coffee in a microwave and almost went back in time.
-- Steven Wright
 
On Apr 16, 3:00 pm, Jason Zheng <Xin.Zh...@jpl.nasa.gov> wrote:
On Wed, 16 Apr 2008 14:29:31 -0400

Fei Liu <fei....@gmail.com> wrote:

initial value cannot be synthesized, is that what you mean?

The real problem is post/pre-synthesis mismatches caused by initial
blocks. Synthesis tool would ignore all initial blocks.

// sequential logic
always @ (posedge clk)
state <= next_state;

See above, use an explicit reset clauses.
can you give an example by 'explicit reset clause'? this state
assignment is textbook use.

always @ (posedge clk)
if (rst)
state <= 0;
else
state <= next_state;
I think some synthesizers (like XST) will generate an power-on reset
(initial value for FPGA load) from an initial value. The
more common use of reset is the asynchronous reset like:

always @ (posedge clk or posedge rst)
if (rst)
state <= 0;
else
state <= next_state;

In the case of XST this will synthesize with an asynchronous
reset to state 0 as well as the configuration load startup
value of state 0. If the rst signal is tied low at some level
in the design, you will still get the initial value of state 0
for synthesis.

Cheers,
Gabor
 
gabor wrote:
On Apr 16, 3:00 pm, Jason Zheng <Xin.Zh...@jpl.nasa.gov> wrote:
On Wed, 16 Apr 2008 14:29:31 -0400

Fei Liu <fei....@gmail.com> wrote:

initial value cannot be synthesized, is that what you mean?
The real problem is post/pre-synthesis mismatches caused by initial
blocks. Synthesis tool would ignore all initial blocks.

// sequential logic
always @ (posedge clk)
state <= next_state;
See above, use an explicit reset clauses.
can you give an example by 'explicit reset clause'? this state
assignment is textbook use.
always @ (posedge clk)
if (rst)
state <= 0;
else
state <= next_state;


I think some synthesizers (like XST) will generate an power-on reset
(initial value for FPGA load) from an initial value. The
more common use of reset is the asynchronous reset like:

always @ (posedge clk or posedge rst)
if (rst)
state <= 0;
else
state <= next_state;

In the case of XST this will synthesize with an asynchronous
reset to state 0 as well as the configuration load startup
value of state 0. If the rst signal is tied low at some level
in the design, you will still get the initial value of state 0
for synthesis.

Cheers,
Gabor
How to perform this reset then? It seems to me, it just moves the
responsibility of properly initialize state to the user of this module
by pulse the rst signal during startup.

Fei
 
On Fri, 18 Apr 2008 15:37:56 -0400
Fei Liu <fei.liu@gmail.com> wrote:
How to perform this reset then? It seems to me, it just moves the
responsibility of properly initialize state to the user of this
module by pulse the rst signal during startup.

Fei
A properly designed circuit board should provide this Power-On Reset
(POR) signal to all the digital ICs on the board. Usually this involves
a delay circuit that monitors the Vcc supply, so the signal is always
grounded at power up, as Vcc ramps up to the desired voltage, POR is
released with a designed delay (or the order of milliseconds). Since
this reset is active-low, this signal is sometimes called PORn.

--
"But I don't like Spam!!!!"
 
On Apr 18, 3:37 pm, Fei Liu <fei....@gmail.com> wrote:
gabor wrote:
On Apr 16, 3:00 pm, Jason Zheng <Xin.Zh...@jpl.nasa.gov> wrote:
On Wed, 16 Apr 2008 14:29:31 -0400

Fei Liu <fei....@gmail.com> wrote:

initial value cannot be synthesized, is that what you mean?
The real problem is post/pre-synthesis mismatches caused by initial
blocks. Synthesis tool would ignore all initial blocks.

// sequential logic
always @ (posedge clk)
state <= next_state;
See above, use an explicit reset clauses.
can you give an example by 'explicit reset clause'? this state
assignment is textbook use.
always @ (posedge clk)
if (rst)
state <= 0;
else
state <= next_state;

I think some synthesizers (like XST) will generate an power-on reset
(initial value for FPGA load) from an initial value. The
more common use of reset is the asynchronous reset like:

always @ (posedge clk or posedge rst)
if (rst)
state <= 0;
else
state <= next_state;

In the case of XST this will synthesize with an asynchronous
reset to state 0 as well as the configuration load startup
value of state 0. If the rst signal is tied low at some level
in the design, you will still get the initial value of state 0
for synthesis.

Cheers,
Gabor

How to perform this reset then? It seems to me, it just moves the
responsibility of properly initialize state to the user of this module
by pulse the rst signal during startup.

Fei
How you perform an initial reset depends on the architecture of the
device you're synthesizing into. In a SRAM-based FPGA, the initial
value after configuration is loaded from the bitstream. This
initial value after configuration is similar to an initial statement
in simulation, as it only happens at "time 0". This may or
may not be the same as the value upon asynchronous reset. In Xilinx
FPGA's, XST will synthesize the bitstream start-up value to whatever
you put in the reset part of the always block, regardless of whether
the reset signal is driven by a signal or just tied inactive.

It is possible in XST to create a flip-flop that has a different
state after configuration than the asynchronous reset value. This
generally requires instantiating a flip-flop and assigning an INIT
value or instantiating a primitive with the desired power-on
behavior. This sort of code generally leads to simulation mis-match
unless you use the post-translation model.

The best way to make sure that the simulation matches the behavior
of the synthesized design, however is to actually have a reset
input and drive it active at the beginning of the simulation.

Regards,
Gabor
 
someone wrote:

In the case of XST this will synthesize with an asynchronous
reset to state 0 as well as the configuration load startup
value of state 0. If the rst signal is tied low at some level
in the design, you will still get the initial value of state 0
for synthesis.
Does it look for a signal named 'reset', or any signal with
a similar function?

-- glen
 
On Apr 19, 2:37 am, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
someone wrote:
In the case of XST this will synthesize with an asynchronous
reset to state 0 as well as the configuration load startup
value of state 0. If the rst signal is tied low at some level
in the design, you will still get the initial value of state 0
for synthesis.

Does it look for a signal named 'reset', or any signal with
a similar function?

-- glen
Ok, after the review, I have revised my code reposted here. I have a
couple of questions
1) is my treatment of rst ok (assuming wire rst will be grounded
during start up and relying on xilinx to properly synthesize the state
machine implementation)?

2. for output logic, should I use blocking assignments? Why for
combinational logic, I should use blocking assignment? What kind of
problem could arise if I use non-blocking assignments in combinational
logic? Some kind of timing glitch?

3. What are some follow-up fun projects to increase my experience and
exposure to FPGA/verilog? I am thinking of interfacing with the memory
blocks on the xilinx board and do some memory IO there. I've recently
done a music player through serial interface. I want to use the
onboard USB interface or ethernet interface, but I am not sure how to
proceed. The usb interface is currently used to program the board and
the ethernet interface seems like it would require a significant
amount of work to get a ethernet core and tcp/ip stack programmed.
Your input is welcome.

module lcd_controller (clk, data_ready, rx_data, lcd_rs, lcd_rw,
lcd_e, lcd_4, lcd_5, lcd_6, lcd_7);

parameter k = 18;
// in register_input mode, the input doesn't have to stay valid
// while the character is being transmitted
parameter register_input = 1;
parameter clr = 8'h0A;

input clk; // synthesis attribute PERIOD clk
"50 MHz"
input data_ready;
input [7:0] rx_data;
output lcd_rs;
output lcd_rw;
output lcd_e;
output lcd_7;
output lcd_6;
output lcd_5;
output lcd_4;

reg lcd_e, lcd_rs, lcd_rw, lcd_7, lcd_6, lcd_5, lcd_4;

wire rst;
reg [k+8:0] count;
reg [6:0] lcd_code;
reg [2:0] state;
reg [2:0] next_state;

wire lcd_ready = (state==1);

// store rx_data locally
reg [7:0] lcd_dataReg;
always @(posedge clk) if(data_ready & lcd_ready) lcd_dataReg <=
rx_data;
wire [7:0] lcd_dataD = register_input ? lcd_dataReg :
rx_data;

// continuous assignment by default of wire type, clr key clears
display
wire clear = (rx_data == clr)? 1:0;
//assign {lcd_e,lcd_rs,lcd_rw,lcd_7,lcd_6,lcd_5,lcd_4} = lcd_code;

// sequential logic
always @ (posedge clk or posedge rst)
begin
if(rst)
begin
state <= 0;
next_state <= 0;
count <= 0;
lcd_code[6:0] <= 0;
end
else
state <= next_state;
end

always @ (posedge clk)
begin
case (state)
3'b000: count <= count + 1;
3'b001: count <= 0;
3'b010: count <= (count[4]? 0 : count + 1);
3'b011: count <= (count[5]? 0 : count + 1);
3'b100: count <= (count[4]? 0 : count + 1);
3'b101: count <= (count[10]? 0 : count + 1);
3'b110: count <= count + 1;
endcase
{lcd_e,lcd_rs,lcd_rw,lcd_7,lcd_6,lcd_5,lcd_4} <= lcd_code;
if(state == 0 || state == 6) lcd_e <= ^count[k+1:k];
end // sequential logic

// combinatorial logic
always @ (state or count or data_ready or clear) begin
case(state)
3'b000:
begin
if(count[k+5:k+2] == 12)
next_state = 3'b1; // idle_data/1
else
next_state = 0;
end
3'b001:
begin
if(data_ready) begin
if(clear)
next_state = 3'b110; // clear/6
else
next_state = 3'b10; // disp_hn/2
end
else
next_state = 3'b1; // idle_data/1
end
3'b010:
begin
if(count[4])
next_state = 3'b11; // idle_high/3
else
next_state = 3'b10; // disp_hn/3
end
3'b011:
begin
if(count[5])
next_state = 3'b100; // disp_ln/4
else
next_state = 3'b11; // idle_high/3
end
3'b100:
begin
if(count[4])
next_state = 3'b101; // wait/5
else
next_state = 3'b100; // disp_ln/4
end
3'b101:
begin
if(count[10])
next_state = 3'b1; // idle_data/1
else
next_state = 3'b101; // wait/5
end
3'b110:
begin
if(count[k+3:k+2] == 2)
next_state = 3'h1; // idle_data/1
else
next_state = 3'h6; // clear/6
end
endcase
end // combinatorial logic

// output logic
always @(state or count or lcd_dataD) begin
lcd_code <= 7'h00;
case(state)
3'b000:
begin
case (count[k+5:k+2])
0: lcd_code <= 7'h43; // power-on
initialization
1: lcd_code <= 7'h43;
2: lcd_code <= 7'h43;
3: lcd_code <= 7'h42;
4: lcd_code <= 7'h42; // function set
5: lcd_code <= 7'h48;
6: lcd_code <= 7'h40; // entry mode set
7: lcd_code <= 7'h46;
8: lcd_code <= 7'h40; // display on/off control
9: lcd_code <= 7'h4C;
10: lcd_code <= 7'h40; // display clear
11: lcd_code <= 7'h41;
endcase
end
3'b001:
lcd_code <= 7'h00;
3'b010:
lcd_code <= {3'b110, lcd_dataD[7:4]};
3'b011:
lcd_code <= 7'b0110000;
3'b100:
lcd_code <= {3'b110, lcd_dataD[3:0]};
3'b101:
lcd_code <= 7'b0110000;
3'b110:
begin
case(count[k+2])
0: lcd_code <= 7'h40; // display clear
1: lcd_code <= 7'h41;
endcase
end
endcase
end // output logic

endmodule
 
On Sat, 19 Apr 2008 20:06:21 -0700 (PDT)
Fei Liu <fei.liu@gmail.com> wrote:


1) is my treatment of rst ok (assuming wire rst will be grounded
during start up and relying on xilinx to properly synthesize the state
machine implementation)?
Your assumption is a misunderstanding of the Xilinx reset. True, Xilinx
FPGA has a built-in power-up reset, but that is through a global-reset
signal, and it will never touch your own reset signal.

If you look at Xilinx's document, you'll notice that they ask you to
include a glbl.v file from their library in your netlist simulation.
That's where the the global reset is simulated. If you read the
post-synthesis netlist, you'll find the connection between the two. But
one thing for sure, if you provide an asynchronous reset, you must
implement that signal as a pin-out or through a reset logic. Otherwise,
the synthesis process will tie that reset signal to low, and your
circuit will forever be in reset state.

Asynchronous resets like the one that you used is usually active-low.
So I would use "negedge rst_n" instead of (negedge rst).

One final note about asynchronous resets is that you'll need to make
sure it doesn't cause any setup time violation. How do you do this? You
synchronize the reset on the releasing edge like this:

output rst_n; // global asynchronous reset

input rst_n_in;
input clk;

reg [1:0] rst_sync;

always @ (posedge clk or negedge rst_n_in)
if (~rst_n_in) rst_sync <= 2'b11;
else rst_sync <= {1'b1. rst_sync[1]};

assign rst_n = rst_sync[0];

Read Cliff Cumming's papers to find out why you should do this.

http://www.sunburst-design.com/papers/CummingsSNUG2003Boston_Resets.pdf

2. for output logic, should I use blocking assignments? Why for
combinational logic, I should use blocking assignment? What kind of
problem could arise if I use non-blocking assignments in combinational
logic? Some kind of timing glitch?
The reason why you should use blocking assignments for combinational
logic is to avoid race conditions. Think of blocking assignments as the
"natural" way to make assignments as in C or Java. The non-blocking
assignment is the "weird" way of making assignments that should only be
used on synchronous logic, such as flip-flops (or latches).

For detailed discussions, I still refer you to Cliff's paper:

http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf
 
Jason Zheng wrote:
On Sat, 19 Apr 2008 20:06:21 -0700 (PDT)
Fei Liu <fei.liu@gmail.com> wrote:


1) is my treatment of rst ok (assuming wire rst will be grounded
during start up and relying on xilinx to properly synthesize the state
machine implementation)?

Your assumption is a misunderstanding of the Xilinx reset. True, Xilinx
FPGA has a built-in power-up reset, but that is through a global-reset
signal, and it will never touch your own reset signal.

If you look at Xilinx's document, you'll notice that they ask you to
include a glbl.v file from their library in your netlist simulation.
That's where the the global reset is simulated. If you read the
post-synthesis netlist, you'll find the connection between the two. But
one thing for sure, if you provide an asynchronous reset, you must
implement that signal as a pin-out or through a reset logic. Otherwise,
the synthesis process will tie that reset signal to low, and your
circuit will forever be in reset state.

Asynchronous resets like the one that you used is usually active-low.
So I would use "negedge rst_n" instead of (negedge rst).

One final note about asynchronous resets is that you'll need to make
sure it doesn't cause any setup time violation. How do you do this? You
synchronize the reset on the releasing edge like this:

output rst_n; // global asynchronous reset

input rst_n_in;
input clk;

reg [1:0] rst_sync;

always @ (posedge clk or negedge rst_n_in)
if (~rst_n_in) rst_sync <= 2'b11;
else rst_sync <= {1'b1. rst_sync[1]};

assign rst_n = rst_sync[0];

Read Cliff Cumming's papers to find out why you should do this.

http://www.sunburst-design.com/papers/CummingsSNUG2003Boston_Resets.pdf

2. for output logic, should I use blocking assignments? Why for
combinational logic, I should use blocking assignment? What kind of
problem could arise if I use non-blocking assignments in combinational
logic? Some kind of timing glitch?


The reason why you should use blocking assignments for combinational
logic is to avoid race conditions. Think of blocking assignments as the
"natural" way to make assignments as in C or Java. The non-blocking
assignment is the "weird" way of making assignments that should only be
used on synchronous logic, such as flip-flops (or latches).

For detailed discussions, I still refer you to Cliff's paper:

http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf
Thanks, I'll read the paper first then maybe I'll have some additional
questions.

Fei
 
On Apr 21, 4:53 pm, Fei Liu <fei....@gmail.com> wrote:
Jason Zheng wrote:
On Sat, 19 Apr 2008 20:06:21 -0700 (PDT)
Fei Liu <fei....@gmail.com> wrote:

1) is my treatment of rst ok (assuming wire rst will be grounded
during start up and relying on xilinx to properly synthesize the state
machine implementation)?

Your assumption is a misunderstanding of the Xilinx reset. True, Xilinx
FPGA has a built-in power-up reset, but that is through a global-reset
signal, and it will never touch your own reset signal.

If you look at Xilinx's document, you'll notice that they ask you to
include a glbl.v file from their library in your netlist simulation.
That's where the the global reset is simulated. If you read the
post-synthesis netlist, you'll find the connection between the two. But
one thing for sure, if you provide an asynchronous reset, you must
implement that signal as a pin-out or through a reset logic. Otherwise,
the synthesis process will tie that reset signal to low, and your
circuit will forever be in reset state.

Asynchronous resets like the one that you used is usually active-low.
So I would use "negedge rst_n" instead of (negedge rst).

One final note about asynchronous resets is that you'll need to make
sure it doesn't cause any setup time violation. How do you do this? You
synchronize the reset on the releasing edge like this:

output rst_n; // global asynchronous reset

input rst_n_in;
input clk;

reg [1:0] rst_sync;

always @ (posedge clk or negedge rst_n_in)
if (~rst_n_in) rst_sync <= 2'b11;
else rst_sync <= {1'b1. rst_sync[1]};

assign rst_n = rst_sync[0];

Read Cliff Cumming's papers to find out why you should do this.

http://www.sunburst-design.com/papers/CummingsSNUG2003Boston_Resets.pdf

2. for output logic, should I use blocking assignments? Why for
combinational logic, I should use blocking assignment? What kind of
problem could arise if I use non-blocking assignments in combinational
logic? Some kind of timing glitch?

The reason why you should use blocking assignments for combinational
logic is to avoid race conditions. Think of blocking assignments as the
"natural" way to make assignments as in C or Java. The non-blocking
assignment is the "weird" way of making assignments that should only be
used on synchronous logic, such as flip-flops (or latches).

For detailed discussions, I still refer you to Cliff's paper:

http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf

Thanks, I'll read the paper first then maybe I'll have some additional
questions.

Fei
Internally to the FPGA, there is no advantage to using active low
signals.
I intentionally used an active high reset in my example, which is why
I
said you could tie it low. I would not suggest leaving inputs
floating.

Many times you have lower level modules that you simulate as a sub-
unit.
These work best with a reset signal for simulation. However if the
only
time you ever need to reset the module is at power-on (really at
config
load for SRAM-based FPGA), then the instantiating upper-level code can
tie the (active high) reset to 1'b0. In your case you can tie your
active low reset to 1'b1 with the same effect. At the top level of
the
code I generally instantiate a reset circuit if I don't need to reset
the entire design from some external signal. For an active-high reset
I instantiate a few FDP (D flip-flops primitives with active high
preset
inputs and global initialization value of 1). These are arranged as
a shift register with zero shifted in and the reset signal shifted
out. The preset inputs are all tied to 1'b0 (note that the primitives
have active-high preset).

Something like:

wire sys_clock, sys_reset;
wire [2:0] presys_rst;

FDP rst_flops [2:0]
(
.D ({presys_rst,1'b0}), // form a shifter with 0 shifting in
from right
.Q ({sys_reset,presys_rst}),
.C (sys_clock),
.PRE (1'b0) // A preset term may be inserted here, otherwise
release reset after config
);

HTH,
Gabor
 
Jason Zheng wrote:
On Sat, 19 Apr 2008 20:06:21 -0700 (PDT)
Fei Liu <fei.liu@gmail.com> wrote:


1) is my treatment of rst ok (assuming wire rst will be grounded
during start up and relying on xilinx to properly synthesize the state
machine implementation)?


One final note about asynchronous resets is that you'll need to make
sure it doesn't cause any setup time violation. How do you do this? You
synchronize the reset on the releasing edge like this:

output rst_n; // global asynchronous reset

input rst_n_in;
input clk;

reg [1:0] rst_sync;

always @ (posedge clk or negedge rst_n_in)
if (~rst_n_in) rst_sync <= 2'b11;
else rst_sync <= {1'b1. rst_sync[1]};

assign rst_n = rst_sync[0];

Read Cliff Cumming's papers to find out why you should do this.

http://www.sunburst-design.com/papers/CummingsSNUG2003Boston_Resets.pdf
why is rst_sync two bits? It seems like 1 bit is enough. And for that
matter the else branch seems redundant.

Fei
 
Fei Liu wrote:
Jason Zheng wrote:
On Sat, 19 Apr 2008 20:06:21 -0700 (PDT)
Fei Liu <fei.liu@gmail.com> wrote:


1) is my treatment of rst ok (assuming wire rst will be grounded
during start up and relying on xilinx to properly synthesize the state
machine implementation)?


One final note about asynchronous resets is that you'll need to make
sure it doesn't cause any setup time violation. How do you do this? You
synchronize the reset on the releasing edge like this:

output rst_n; // global asynchronous reset

input rst_n_in;
input clk;

reg [1:0] rst_sync;

always @ (posedge clk or negedge rst_n_in)
if (~rst_n_in) rst_sync <= 2'b11;
else rst_sync <= {1'b1. rst_sync[1]};

assign rst_n = rst_sync[0];

Read Cliff Cumming's papers to find out why you should do this.
http://www.sunburst-design.com/papers/CummingsSNUG2003Boston_Resets.pdf


why is rst_sync two bits? It seems like 1 bit is enough. And for that
matter the else branch seems redundant.

Fei
This is the code the author recommends for a async reset synchronizer:

module async_resetFFstyle2 (
output reg rst_n,
input clk, asyncrst_n);
reg rff1;
always @(posedge clk or negedge asyncrst_n)
if (!asyncrst_n) {rst_n,rff1} <= 2'b0;
else {rst_n,rff1} <= {rff1,1'b1};
endmodule
 
The original author's filter does have 2 bits. It's just another way to
write this filter.

-> output reg rst_n;
-> reg rff1;

Two reg bits.

why is rst_sync two bits? It seems like 1 bit is enough. And for
that matter the else branch seems redundant.

Fei

This is the code the author recommends for a async reset synchronizer:

module async_resetFFstyle2 (
output reg rst_n,
input clk, asyncrst_n);
reg rff1;
always @(posedge clk or negedge asyncrst_n)
if (!asyncrst_n) {rst_n,rff1} <= 2'b0;
else {rst_n,rff1} <= {rff1,1'b1};
endmodule

--
"Boy, life takes a long time to live."
-- Steven Wright
 
Jason Zheng wrote:
The original author's filter does have 2 bits. It's just another way to
write this filter.

-> output reg rst_n;
-> reg rff1;

Two reg bits.

why is rst_sync two bits? It seems like 1 bit is enough. And for
that matter the else branch seems redundant.

Fei
This is the code the author recommends for a async reset synchronizer:

module async_resetFFstyle2 (
output reg rst_n,
input clk, asyncrst_n);
reg rff1;
always @(posedge clk or negedge asyncrst_n)
if (!asyncrst_n) {rst_n,rff1} <= 2'b0;
else {rst_n,rff1} <= {rff1,1'b1};
endmodule


Ok I understand now. Thanks,

Fei
 

Welcome to EDABoard.com

Sponsor

Back
Top