| ??? 10/01/07 18:55 Read: times Msg Score: +1 +1 Good Answer/Helpful |
#145203 - reason for the skew warning Responding to: ???'s previous message |
You're dividing the 50 MHz input clock down using a counter and a flop that toggles when the counter hits certain values.
Then you take that flip-flop output and use it as a clock input for another divider. The tools do not understand that your first divider's output is supposed to be used as a clock, so baudClock ends up on local (non-low-skew) routing resources. Also, it is impossible to set proper timing constraints on baudClock. Look at the design in the FPGA editor. There are a couple of ways of fixing this. a) Instantiate a global clock buffer whose input is the output of the divider that generates baudClock, and whose output drives the baudClock net. b) Instead of using the baudClock signal as a clock, instead make it a strobe that is asserted for one master clock tick once every baudClock period. Then, in uat.v, use clock50MHz as the clock input and use baudClock as a clock enable. I prefer using the latter. Timing analysis is greatly simplified as everything is synchronous to the 50 MHz clock. FPGA flip-flops have clock-enable inputs and the tools are smart enough to know how to use them. Here's how I would implement this. This is the top level module, which glues everything together. module toplevel
#(parameter DIVCNT = 1000, // count to this number
DIVSIZE = 10) // need enough bits to count to DIVCNT
(input wire MClk, // FPGA master clock
input wire Strobe, // true with new data word
input wire [7:0]DataIn, // new word to write
output reg RS232Out, // serial transmit data
output reg TxBusy); // transmitter is busy
// clock divider output:
wire ClkDiv;
// here is the clock divider:
clockdiv
#(.DIVCNT(DIVCNT),
.DIVSIZE(DIVSIZE)) u0
(.MClk(MClk),
.ClkDiv(ClkDiv));
// and the transmitter:
uat u1
(.MClk(MClk),
.BaudClk(BaudClk),
.Strobe(Strobe),
.DataIn(DataIn),
.RS232Out(RS232Out),
.TxBusy(TxBusy));
endmodule // toplevel
Here is the clock divider, which generates the baud rate timer. module clockdiv
#(parameter DIVCNT = 1000, // count to this number
DIVSIZE = 10) // need enough bits to count to DIVCNT
(input wire MClk, // FPGA master clock
output reg ClkDiv); // clock divider strobe out
reg [DIVCNT:0] iCounter; // our counter
// when counter hits target DIVCNT, assert the ClkDiv strobe and
// reset the counter.
// Otherwise, just count and keep ClkDiv cleared.
always @(posedge MClk) begin : Divider
if (iCounter == DIVCNT) begin
ClkDiv <= 1'b1;
iCounter <= 0;
end else begin
ClkDiv <= 1'b0;
iCounter <= iCounter + 1;
end // else: !if(iCounter == DIVCNT)
end // block: Divider
endmodule // clockdivand here is the transmitter. Note that Strobe is NOT used as if it is an asynchronous reset/load here. It (along with DataIn) must be synchronous to MClk.module uat
(input wire MClk, // master clock
input wire BaudClk, // clock enable at the baud rate
input wire Strobe, // indicates new word
input wire [7:0]DataIn, // new word to write
output reg RS232Out, // serial transmit data
output reg TxBusy); // transmitter is busy
reg [9:0] iTxShift; // transmit shift reg
reg [3:0] iBitCnt; // bit counter
// Shifter loads when strobe is asserted coincident with a new word coming
// in on DataIn, and it resets the shift and bit counters.
// Shift takes place when BaudClk is asserted. It should be one MClk tick
// wide every transmit bit time.
always @(posedge MClk) begin : Shifter
if (Strobe) begin
iTxShift <= {1'b1, DataIn, 1'b0}; // love concatenation!
iBitCnt <= 9;
TxBusy <= 1'b1;
end else begin // if (Strobe)
if (BaudClk) begin
if (iBitCnt != 0) begin
iTxShift <= {1'b0, iTxShift[9:1]};
iBitCnt <= iBitCnt - 1;
end
RS232Out <= iTxShift[0];
TxBusy <= (iBitCnt != 0);
end // if (BaudClk)
end // else: !if(Strobe)
end // block: Shifter
endmodule // uatAgain, note that all three should be in their own source files.
-a |



