Search code examples
verilogfpgaxilinxhdlsynthesis

Verilog code runs in simulation as i predicted but does not in FPGA


I try to write an UART transmitter module. It gets data from data[7:0] and then sends it serially via Tx. I wrote a module named Tester for testing transmitter. It simulates in Isim as I predicted but does not in Spartan-6. I watched the Tx pin with osciloscope, I saw only logic 1. I could not detect the problem. What have I done incorrectly?

module Tester(
clk,
data,
oclk,
Tx
);
input wire clk;
output reg [7:0] data;
output wire oclk;
output wire Tx;

assign oclk = clk;

initial begin
data<=8'b11001010;
end

UartTransmitter UT(.clk(clk),.data(8'b11001010),.Tx(Tx),.transmit(1'b1)); 

endmodule


module UartTransmitter(
//Inputs
clk,
reset,
data,
transmit,
//Output
Tx
);
input wire clk;
input wire reset;
input wire [7:0] data;
input wire transmit;
output reg Tx;

reg [16:0] counter;
reg durum;
reg s_durum;
reg sendbyone;
reg [10:0]buffer;
reg [3:0]nbitstransmitted;

parameter IDLE = 1'b0;
parameter TRANSMITTING = 1'b1;

initial begin
    counter=0;
    Tx=1;
    s_durum = IDLE;
    durum=IDLE;
    sendbyone=0;
    buffer=0;
    nbitstransmitted=0;
end

always @(posedge clk) begin
    counter<=counter+1;
    if(counter>=13019) begin
        counter<=0;
        sendbyone<=1;
    end else begin
        sendbyone<=0;
    end
    durum<=s_durum;
end


always @(*) begin
    s_durum=durum;
    if((durum==IDLE) && (transmit==1)) begin
    buffer={1'b1,^data,data,1'b0};
    s_durum=TRANSMITTING;
    end

    else if(durum==TRANSMITTING && (sendbyone==1)) begin
        if(nbitstransmitted<10) begin
            Tx=buffer[nbitstransmitted];
            nbitstransmitted=nbitstransmitted+1;
        end else if(nbitstransmitted==10)begin
            Tx=buffer[10];
            nbitstransmitted=0;
            s_durum=IDLE;
        end
    end
end

endmodule

Solution

  • buffer, Tx and nbitstransmitted are inferred latches. Latches are inferred when a variable is not guaranteed assignment with in an combinational block (always @*). buffer is a simple latch because the control logic is coming from flops. Tx will be simple latch after nbitstransmitted is changed to a flip-flop. The main issue is nbitstransmitted because it has feedback. With the current design in simulation if data changes when durum==TRANSMITTING && sendbyone then nbitstransmitted will increment. Even if data is from a flop in the same clock domain, on the FPGA there can be skew on each bit and trigger multiple updates.

    Complex latches are prone to race conditions and use up lots of area. As an example, I copied the provide code to EDAplayground and synthesized it with Yosys 0.3.0. With the "show diagram" enabled it will show a large number of gates used with sufficient latch feedback. Try running here (Sorry I cannot upload the diagram, maybe someone else can)

    The solution is easy by following the same strategy already used for durum; create a next state variable. sticking with the current convention, create new variables for buffer, Tx and nbitstransmitted with the respected names with a s_ prefix. The combinational block (always @*) will assign the s_ signals and should default to there respected counter part. And the sequential block (always @(posedge clk)) will assign the flops by their respected s_. The flops with remove the asynchronous feedback and simplify the design. For cleaner design, I moved the counter<=counter+1; into the else condition and commented out if(nbitstransmitted==10). Try running here


    Other note not related to the issue:

    The reset signal is not being used. I suggest using it in the sequential block and remove the initial block. Most FPGAs support initial and most ASIC do not. I prefer using reset signals over initial blocks because it allows resetting the device without having to power cycle. Just a suggestion.