0

EDIT: removed some redundancies, moved all assignments to non-blocking, inserted a reset mapped as one of the input buttons of my FPGA... but when I implement the code, it starts transmitting the same wrong character and gets stuck in a single state of my machine.

Post Synthesis and Post-Implementation simulations are identical,$time-wise

    module UART (reset_button, sysclk_p, sysclk_n,TxD, Tx_busy, Tx_state_scope_external);
    input reset_button, sysclk_p, sysclk_n;
    output wire TxD, Tx_busy;
    output wire [1:0]Tx_state_scope_external;

    //internal communications signals


    wire clk_internal;

    //buffer unit control signals
    wire [7:0]TxD_data_internal;
    wire Tx_start_internal;
    wire Tx_busy_internal;
    wire reset_flag;

    reset_buf RESET_BUFF (.reset_internal (reset_flag), .reset (reset_button));

    differential_CK CK_GENERATION (.sysclk_p (sysclk_p), .sysclk_n(sysclk_n), .clk(clk_internal));

    output_Dbuffer OB1 (.reset (reset_flag), .RTS_n (Tx_busy_internal), .clk(clk_internal), .TX_trigger (Tx_start_internal), .TX_data(TxD_data_internal));

    async_transmitter TX1 (.reset (reset_flag), .clk (clk_internal), .TxD_data(TxD_data_internal), .Tx_start (Tx_start_internal), .TxD(TxD), .Tx_busy_flag(Tx_busy_internal), .Tx_state_scope(Tx_state_scope_external));

    obuf_TX O_TX1( .Tx_busy(Tx_busy), .Tx_busy_flag(Tx_busy_internal));


   endmodule

    module reset_buf (
    output reset_internal,
    input reset
    );
// IBUF: Single-ended Input Buffer
// 7 Series
// Xilinx HDL Libraries Guide, version 14.7
IBUF #(
.IBUF_LOW_PWR("TRUE"), // Low power (TRUE) vs. performance (FALSE) setting for referenced I/O standards
.IOSTANDARD("DEFAULT") // Specify the input I/O standard
) IBUF_inst (
.O(reset_internal), // Buffer output
.I(reset) // Buffer input (connect directly to top-level port)
);
// End of IBUF_inst instantiation

    endmodule

    module differential_CK(

    input sysclk_p,
    input sysclk_n,
    output clk    
    );

    // IBUFGDS: Differential Global Clock Input Buffer
    // 7 Series
    // Xilinx HDL Libraries Guide, version 14.7
    IBUFGDS #(
    .DIFF_TERM("FALSE"), // Differential Termination
    .IBUF_LOW_PWR("TRUE"), // Low power="TRUE", Highest performance="FALSE"
    .IOSTANDARD("DEFAULT") // Specify the input I/O standard
    ) IBUFGDS_inst (
    .O(clk), // Clock buffer output
    .I(sysclk_p), // Diff_p clock buffer input (connect directly to top-level port)
    .IB(sysclk_n) // Diff_n clock buffer input (connect directly to top-level port)
    );
    // End of IBUFGDS_inst instantiation


    endmodule

    module output_Dbuffer (
    input reset,
    input RTS_n, //TX_BUSY flag of the transmitter is my ready to send flag
    input clk, //ck needed for the FSM
    output wire TX_trigger, //TX_START flag of the transmitter now comes from THIS unit instead of Receiver
    output wire [7:0]TX_data //byte for transmission
    );

    //internal variables
    reg [7:0] mem [0:9]; //memory init, 10 * 8 bit locations
    integer m, n, i, j, k ; //M = row [a.k.a. bytes], N = column [a.k.a. single bits]

    reg TX_trigger_int;
    reg [7:0] TX_data_int, TX_complete;
    //reg sum256_ok;        
    reg [7:0]checksum_buff ;

    //buffer FSM required variables 
    localparam  //state enumeration declaration
        BUF_IDLE = 3'b000, 
        BUF_START = 3'b001,
        BUF_BYTES = 3'b010,  
        BUF_BUSY = 3'b011,
        BUF_TX_CHECKSUM = 3'b100;

    reg [2:0] buf_state; //2 bits for 4 states


    //static assignments of OUTPUTS : Transmission Flag and Transmission Data (content)
    assign TX_trigger = TX_trigger_int;
    assign TX_data = TX_data_int;

    //Block for transmitting [here I manage the TX_Data and TX_Trigger functionality]
    always @(posedge clk)
        begin
            if (reset) 
                begin
                    buf_state <= BUF_IDLE;
                    TX_trigger_int <= 0;
                    TX_data_int <= 8'b00000000;

                end
            else case (buf_state)
            BUF_IDLE:
                begin
                       TX_trigger_int <= 0;
                       TX_data_int <= 8'b00000000;
                       m <=0;
                       n <=0;
                       i <=0;
                       j <=0;                                     
                       mem[9] <= 8'b01010001; //81
                       mem[8] <= 8'b01000000; //64
                       mem[7] <= 8'b00110001; //49
                       mem[6] <= 8'b00100100; //36
                       mem[5] <= 8'b00011001; //25
                       mem[4] <= 8'b00010000; //16
                       mem[3] <= 8'b00001001; //9
                       mem[2] <= 8'b00000100; //4
                       mem[1] <= 8'b00000001; //1
                       mem[0] <= 8'b00000010;//2
                       checksum_buff <= 8'd31;
                            //check if the TX is not busy
                       if (RTS_n == 0) buf_state <= BUF_START;                                                                     
                end

            BUF_START:
                begin
                    TX_trigger_int <= 0;
                    if ((i == 0) || ( (j - i) > 1 )) buf_state <= BUF_BYTES;
                            else begin
                                $display ("BUFFER BUSY @time:", $time);
                                buf_state <= BUF_BUSY;   
                            end 
                end   


            BUF_BYTES:
                begin

                    //check if the TX is busy
                    if (RTS_n==0) 
                        begin
                         //   TX_trigger_int = 1; 21.09 MOVED THE TRIGGER INSIDE THE ELSE N LINE 498
                            if (j > 9) 
                                begin
                                        TX_trigger_int <= 0;
                                        buf_state <= BUF_TX_CHECKSUM;
                                    end
                            else begin
                                    TX_data_int <= mem[j];
                                    TX_trigger_int <= 1;
                                    j <= j+1;
                                    //TX_trigger_int =0;
                                    buf_state <= BUF_START;
                                end
                        end
                    else buf_state <= BUF_BYTES;

                end

            BUF_BUSY:
                begin
                    if (RTS_n == 0)
                        begin 
                            $display ("BUFFER AVAILABLE AGAIN @time:", $time);
                            buf_state <= BUF_START;
                        end
                end

            BUF_TX_CHECKSUM:
                begin

                    if (RTS_n==0) begin
                        TX_data_int <= checksum_buff;

                    //    sum256_ok = 0;
                        TX_trigger_int <= 1;
                        buf_state <= BUF_IDLE;
                        end
                end

            //default: buf_state <= BUF_IDLE;

            endcase
    end



    endmodule

    module async_transmitter(
    input clk,
    input reset,
    //differential clock pair
    input [7:0] TxD_data,
    input  Tx_start, // it is ==TX_TRIGGER

    output wire TxD, //bit being sent to the USB

    output reg Tx_busy_flag,
    output wire [1:0]Tx_state_scope
    );

      localparam  //state enumeration declaration
      TX_IDLE = 2'b00, 
      TX_START_BIT = 2'b01,
      TX_BITS = 2'b10,
      TX_STOP_BIT = 2'b11;

      parameter ClkFrequencyTx = 200000000; // 200MHz
      parameter BaudTx = 9600;
      reg [1:0] Tx_state; //2 bits for 4 states
      integer bit_counter;   //bit counter variable
      reg [7:0]TxD_data_int, TxD_int;
      integer i; //vector index for output data
      wire TXSTART_Trigger;

      StartDetectionUnitTX SDU_TX (.clk(clk), .state (Tx_state), .signal_in (Tx_start), . trigger (TXSTART_Trigger));

      wire BitTick;

      BaudTickGen #(ClkFrequencyTx, BaudTx) as (.clk(clk), .trigger (TXSTART_Trigger), .tick(BitTick));
      //BitTick is 16times the frequency generated during the RX portion

      assign TxD = TxD_int;

      always @(posedge clk) begin
            if (reset) 
                begin
                    Tx_state <= TX_IDLE;
                    TxD_int <= 1;
                    Tx_busy_flag <=0;
                end
            else case (Tx_state)

                TX_IDLE:
                    begin //reinitialization and check on the trigger condition

                        bit_counter <= 0;
                        TxD_data_int <= 8'b00000000;
                        i <= 0;
                        TxD_int <= 1; //idle state
                        Tx_busy_flag <= 0; 
                                if (TXSTART_Trigger) begin
                                         Tx_state <= TX_START_BIT;
                                         TxD_data_int <= TxD_data;
                                         Tx_busy_flag <= 1; 
                                         bit_counter <= 8;
                                     end                              

                    end

                TX_START_BIT:
                    begin
                        if (BitTick)
                            begin
                            TxD_int <= 0 ; //start bit is a ZERO logical value

                            Tx_state <= TX_BITS; 
                            end 
            end

                TX_BITS:
                    begin

                        if (BitTick) 
                            begin
                                bit_counter <= bit_counter -1;
                                TxD_int <= TxD_data_int[i];
                       //         $display ("ho trasmesso dalla UART un bit di valore %b al tempo: ", TxD, $time);
                                i <= i+1;
                                if (bit_counter < 1) Tx_state <= TX_STOP_BIT; 
                            end
                    end


                 TX_STOP_BIT:   
                               begin
                                   if (BitTick) begin
                                       TxD_int <= 1; //STOP BIT is a logical '1'
                                       Tx_busy_flag <= 0;
                                       Tx_state <= TX_IDLE;          
                                       end                                 
                               end


               // default: Tx_state <= TX_IDLE;

                endcase

             end 


            assign Tx_state_scope = Tx_state;

endmodule

module obuf_TX (
    output Tx_busy,
    input Tx_busy_flag
    );

// OBUF: Single-ended Output Buffer
// 7 Series
// Xilinx HDL Libraries Guide, version 14.7
OBUF #(
.DRIVE(12), // Specify the output drive strength
.IOSTANDARD("DEFAULT"), // Specify the output I/O standard
.SLEW("SLOW") // Specify the output slew rate
) OBUF_inst (
.O(Tx_busy), // Buffer output (connect directly to top-level port)
.I(Tx_busy_flag) // Buffer input
);
// End of OBUF_inst instantiation

endmodule

module StartDetectionUnitTX ( //detects a rising edge of the start bit == TRANSMISSION START, during the IDLE state = 0000
    input clk, [1:0]state, 
    input signal_in,
    output trigger
    );

    reg signal_d;

    always @(posedge clk)
            begin
            signal_d <= signal_in;
        end   

    assign trigger = signal_in & (!signal_d) & (!state);

endmodule  

module BaudTickGen (
        input clk, trigger, 
        output tick //generates a tick at a specified baud rate *oversampling
        );

        parameter ClkFrequency = 200000000; //sysclk at 200Mhz
        parameter Baud = 9600;
        parameter Oversampling = 1;
        //20832 almost= ClkFrequency / Baud, to make it an integer number
        integer counter = (20833/Oversampling)-1; //-1 so counter can get to 0

        reg out;

        always @(posedge clk)
                   begin
                    if (trigger) 
                        begin
                            counter <= (20833/Oversampling)-1; //-1 so counter can get to 0
                            out <= 1; 
                        end

                           if (counter == 0) 
                               begin
                                   counter <= (20833/Oversampling)-1; //-1 so counter can get to 0
                                   out <= 1; 
                               end
                               else begin

                                   counter <= counter-1;
                                   out <= 0;
                               end   
                    end     

            assign tick = out;
            endmodule

My FPGA is a Virtex-7 VC707 and I'm using Vivado for my design flow.

Here I am attaching an image of my looping error.

error image

2
  • a quick suggestion: please use non-blocking assignments in your state machine, i.e. TX_trigger_int <= 0; buf_state <= BUF_TX_CHECKSUM;. Otherwise you create races in simulation and could get into interesting states. Commented Sep 22, 2017 at 17:47
  • @Serge thanks. Coming from VHDL, the = / <= difference is currently my biggest concern. I feel it might be responsible for my whole malfuction in real-fpga implementation. Commented Sep 24, 2017 at 19:47

1 Answer 1

1

What have you done? Have you just simulated the code? Are you saying that it fails on the board, but the post-implementation sim is Ok?

  1. A difference between pre- and post-implementation sim could point to a race condition. Get rid of all your blocking assignments, replace with NBAs (why did you use blocking assignments?)
  2. Don't go to Chipscope - it's just a red flag that you don't know what you're doing
  3. The code is a mess - simplify it. The Xilinx-specific stuff is irrelevant - get rid of it if you want anyone to look at it, fix comments (2-bit state?!), fix your statement about getting stuck in '10', etc
  4. Have you run this through Vivado? Seriously? You have multiple drivers on various signals. Get rid of the initial block, use a reset. Initialise the RAM in a way which is understood by the tools. Even if Vivado is capable of initialising stuff using a separate initial block, don't do it
  5. Get rid of statements like 'else Tx_state = TX_IDLE' in the TX_IDLE branch - they're redundant, and just add verbosity
  6. Write something which fails stand-alone, and post it again.
Sign up to request clarification or add additional context in comments.

5 Comments

Hello, and thanks for your comment. 1. pre and post-implementation work EXACTLY the same ,to the point where $time commands give the same results (1 clock cycle difference, but as a fixed difference, not incremented through cycling or different iterations) 1b. I come from VHDL and even if I have read tons of papers about = / <= difference, it is still not so clear to me, especially in 1-hot-encoded FSMs and/or logic with both sequential and combinatory elements. This is my FIRST Verilog code. 2. And it wastes quite some time probably? 3.What kind of Xilinx specific stuff?
4. What is the advantage of reset vs initial block? I don't have a ctrl block (yet) to pilot some kind of reset flag, I just need to do it once at the moment. 5. I didn't have them, I also imagined they would be intrinsic, I wanted to test some minuscule and /or minor (maybe just useless) stuff to see what might have been wrong. 6. You mean something that doesn't get simulated correctly? thanks @EML
Too many comments to reply to - try asking some questions on comp.lang.verilog; if it's still alive, it's much better than SO. Your pre-and post sims differ by one clock cycle? Have I understood correctly? Almost certainly means a race condition. Always use NBAs until you understand the difference; see the Cliff Cummings paper when you need to know more, or if you have lots of VHDL which uses variables (I'm guessing you don't). Initial blocks "aren't hardware" - you must have a reset in hardware.
Initial blocks: maybe Vivado supports them for post-config initialisation, and maybe it doesn't - it doesn't matter, don't use them. If you don't understand how your logic will be reset, start by adding a reset pin to your device and connect it to the internal logic, and then figure out how to use it later.
modified my code to remove a few redundancies, used NBAs everywhere, removed a few states looping on themselves explicitly, and now connecting a reset signal to a "user button" of my FPGA, as an input to all the modules, is that good enough as a reset condition mappable in hardware? it seems so, to me

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.