??? 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 |