OpenCores
URL https://opencores.org/ocsvn/uart2bus_testbench/uart2bus_testbench/trunk

Subversion Repositories uart2bus_testbench

[/] [uart2bus_testbench/] [trunk/] [tb/] [interfaces/] [uart_interface.sv] - Rev 16

Go to most recent revision | Compare with Previous | Blame | View Log

//-------------------------------------------------------------------------------------------------
//
//                             UART2BUS VERIFICATION
//
//-------------------------------------------------------------------------------------------------
// CREATOR    : HANY SALAH
// PROJECT    : UART2BUS UVM TEST BENCH
// UNIT       : INTERFACE
//-------------------------------------------------------------------------------------------------
// TITLE      : UART BFM 
// DESCRIPTION: THIS FILE ACT AS UART MASTER DEVICE APPLY REQUESTS TO THE DUT ACROSS THE STANDARD
//              INTERFACES. IT ALSO INCLUDES ALL THE USER AND STANDARD ROUTINES THAT ARE NEED TO 
//              APPLY, RECEIVE AND MONITOR UART DIFFERENT ACTIVITIES. 
//-------------------------------------------------------------------------------------------------
// LOG DETAILS
//-------------
// VERSION      NAME        DATE        DESCRIPTION
//    1       HANY SALAH    25122015    FILE CREATION
//    2       HANY SALAH    07012016    ADD USER ROUTINE, TEXT MODE ROUTINES.
//    3       HANY SALAH    21012016    REPLACE PUSH BYTE WITH PUSH FIELD
//    4       HANY SALAH    31012016    ADD FAULT AND INVALID COMMAND INDICATORS
//    5       HANY SALAH    13022016    IMPROVE BLOCK DESCRIPTION & ADD COMMENTS.
//    6       HANY SALAH    15022016    ENHANCE BLOCK COMMENTS
//    7       HANY SALAH    16022016    ENHANCE BLOCK COMMENTS
//    8       HANY SALAH    17022016    FINALIZE BLOCK COMMENTS
//-------------------------------------------------------------------------------------------------
// ALL COPYRIGHTS ARE RESERVED FOR THE PRODUCER ONLY .THIS FILE IS PRODUCED FOR OPENCORES MEMBERS 
// ONLY AND IT IS PROHIBTED TO USE THIS MATERIAL WITHOUT THE CREATOR'S PERMISSION
//-------------------------------------------------------------------------------------------------
`include "defin_lib.svh"
interface uart_interface (input bit clock,        // UART Clock Signal
                          input bit reset);       // Global Asynchronous Reset Signal

//-------------------------------------------------------------------------------------------------
//
//                                       BFM PARAMETERS
//
//-------------------------------------------------------------------------------------------------
  // BFM Paramenters are the ones which are set in the test file and are propagated in the whole
  // test-bench. They are defined indetails through test file and specifications document.
  // The range of possible values for all the BFM paramters is stated beside each one
  //
  // Define the active clock edge
  int                 act_edge;     // 2: negative edge   1: positive edge
  
  // Define the first transferred bit from the byte.
  int                 start_bit;    // 2: LSB first       1: MSB first 
  
  // Define the number of stop bits of each UART field
  int                 num_stop_bits;// 2: two stop bits   1: one stop bits
  
  // Define the number of actual bits inbetween the start and stop bits.
  int                 num_bits;     // 7: seven bits data 8: eight bits data
  
  // Define the representation of data through the text mode.
  int                 data_rep;     // 2: binarry         1: ASCII
  
  // Define the parity mode used.
  int                 parity;       // 3: parity odd      2: parity even        1: parity off
  
  // Define the maximum allowable time between the UART request and the DUT response.
  time                response_time;

  // Define the authorization of false data usage.
  int                 falsedata_gen_en;

//-------------------------------------------------------------------------------------------------
//
//                                      UART SIGNLAS
//
//-------------------------------------------------------------------------------------------------

  logic               ser_in;         // Serial Data Input
  logic               ser_out;        // Serial Data Ouptut

//-------------------------------------------------------------------------------------------------
//
//                                 USER VARIABLES DECLARATIONS
//
//-------------------------------------------------------------------------------------------------

  // The user variables are those ones which facilitate the usage of BFM and they aren't mentioned
  // in the standard.
  //
  // Start_trans event is triggered by the driver at the start of each transaction. it would let
  // the other components wake up and poll the UART bus.
  // By triggereing this event, other connected components would know that some UART transaction 
  // would be forced on the UART busses.
  event start_trans;

  // The following two bits are used only in case of apply wrong modes or wrong commands as the
  // following:
  // wrong_data_ctrl is drived by the driver to state that whether the wrong applied command
  // is read or write.
  // Actuall BFM shouldn't discriminate between both of types. Its response should be nothing!!.
  // But this indication facilitates the scoreboard work.
  bit wrong_data_ctrl;           //0:read      1: write

  // wrong_mode_ctrl is also drived by the driver to state whether the wrong applied mode is
  // text or binary.
  // Actuall BFM also shouldn't discriminate between both of types. Its response should be 
  // nothing. But this indication facilitates the scoreboard work.
  bit wrong_mode_ctrl;           //0:text      1: binary

//-------------------------------------------------------------------------------------------------
//
//                                       USER ROUTINES
//
//-------------------------------------------------------------------------------------------------

  // Through This routine, the uart bfm initializes its configuration parameters described above.
  function void set_configuration ( int _edge,
                                    int first_bit,
                                    int _numstopbits,
                                    int _numbits,
                                    int _datarep,
                                    int _paritymode,
                                    time _resp,
                                    int _flse_en);
    act_edge        = _edge;
    start_bit       = first_bit;
    num_stop_bits   = _numstopbits;
    num_bits        = _numbits;
    data_rep        = _datarep;
    parity          = _paritymode;
    response_time   = _resp;
    falsedata_gen_en= _flse_en;
  endfunction: set_configuration


  // Through the following routine, the UART BFM makes an event that some transaction would be 
  // forced on UART signals
  function void set_event ();
    -> start_trans ;
  endfunction:set_event 

  // This routine is used to force data directly on serial out bus. This routine transform one
  // bit only to the form of uart. This form is defined in the definition library. 
  // High value is defined by the macro `one.
  // Low value is defined by the macro `zero.
  function void force_sout(bit x);
    case (x)
      1'b1:
        begin
        ser_out = `one;
        end
      1'b0:
        begin
        ser_out = `zero;
        end
    endcase
  endfunction:force_sout

  // Through this routine, the uart bfm push bit on the serial ouptut port ser_out based on the 
  // configured active edge field, UART will push bit on data. BFM will assign testbench error in 
  // case of un-configured active edge.
  task push_bit_serout (input bit data);
    case (act_edge)
      `_negedge:
        begin
        @(negedge clock)
          begin
          force_sout(data);
          end
        end
      `_posedge:
        begin
        @(posedge clock)
          begin
          force_sout(data);
          end
        end
      default:
        begin
        $error("Non-configured active edge");
        end
    endcase
  endtask:push_bit_serout

  // The following task will catch single bit from serial output port ser_out based on the config-
  // ured active edge field, UART will capture data bit. Based on the configured active edge, this
  // method block the execution till the correct clock edge and then make delay of a quarter of 
  // clock period to guarnttee the stability of data on the serial output port. 
  // BFM will assign testbench error in case of un-configured active edge.
  task catch_bit_serout (output bit data);
    case (act_edge)
      `_negedge:
        begin
        @(negedge clock)
          begin
          #(`buad_clk_period/4) data = ser_out;
          end
        end
      `_posedge:
        begin
        @(posedge clock)
          begin
          #(`buad_clk_period/4) data = ser_out;
          end
        end
      default:
        begin
        $error("Non-configured active edge");
        end
    endcase
  endtask:catch_bit_serout

  // The following task will catch single bit from serial input port ser_in based on the config-
  // ured active edge field, UART will capture data bit. Based on the configured active edge, this
  // method block the execution till the correct clock edge and then make delay of a quarter of 
  // clock period to guarnttee the stability of data on the serial input port. 
  // BFM will assign testbench error in case of un-configured active edge.
  task catch_bit_serin (output bit data);
    case (act_edge)
      `_negedge:
        begin
        @(negedge clock)
          begin
          #(`buad_clk_period/4) data = ser_in;
          end
        end
      `_posedge:
        begin
        @(posedge clock)
          begin
          #(`buad_clk_period/4)data = ser_in;
          end
        end
      default:
        begin
        $error("Non-configured active edge");
        end
    endcase
  endtask:catch_bit_serin

  // Through the following task, UART BFM will force data byte on serial output port based on the 
  // configured start_bit field. This mode encapsulate the data byte inbetween start,stop and even
  // parity bits. The sequence would be the following:
  // 1- Force zero bit on the serial output port as start bit.
  // 2- Send the data byte serially bit by bit.
  // 3- Accoriding to configured parity, force parity bit (optional).
  // 4- Insert one or two stop bits according to BFM configuration.
  // BFM will assign testbench error in case of un-configured parameters.
  task push_field_serout (input byte data);
    
    bit temp;

    // start bit
    push_bit_serout(1'b0);

    // data fields
    case (start_bit)
      `lsb_first:
        begin
        for (int index=0;index<8;index++)
          begin
          push_bit_serout(data[index]);
          end
        end
      `msb_first:
        begin
        for (int index=7;index>=0;index--)
          begin
          push_bit_serout(data[index]);
          end
        end
      default:
        begin
        $error("Undefined serial mode");
        end
    endcase
    // parity bits
    if(parity == `_parityeven)
      begin
      temp=1'b1;
      for (int index=0;index <8;index++)
        begin
        temp = temp ^ data [index];
        end
      end
    else if(parity == `_parityodd)
      begin
      temp=1'b0;
      for (int index=0;index <8;index++)
        begin
        temp = temp ^ data [index];
        end
      end
    else if (parity != `_parityoff)
      begin
      $error("un-configured parity");
      end
    // Stop bit(s)
    repeat (num_stop_bits)
      begin
      push_bit_serout(1'b1);
      end

  endtask:push_field_serout

  // Through the following task, UART BFM will catpure UART field from serial output port based on 
  // the configured start_bit field. The following sequence is carried out :
  // 1- Wait start bit.
  // 2- Catpure the following eight bits in packed byte depending on the configured start bit.
  // 3- Depending on the configured number of stop bits, the stop bit(s) are captured.
  //    - In case that stop bit(s) is zero, the testbench will assign testbench error.
  // BFM will assign testbench error in case of un-configured start_bit field.
  task catch_field_serout (output byte data);
    bit end_bit;

    // wait start bit
    wait(ser_out == 1'b0);
    case(start_bit)
      `lsb_first:
        begin
        for (int index=0;index<8;index++)
          begin
          catch_bit_serout(data[index]);
          end
        end
      `msb_first:
        begin
        for (int index=7;index>=0;index--)
          begin
          catch_bit_serout(data[index]);
          end
        end
      default:
        begin
        $error("Undefined serial mode");
        end
    endcase
    catch_bit_serout(end_bit);
    if(end_bit != 1'b1)
      begin
      $error("at time =%0t ,, the first end bit = %0b",$time,end_bit);
      end
    if (num_stop_bits == 2)
      begin
      catch_bit_serout(end_bit);
      if(end_bit != 1'b1)
        begin
        $error("at time =%0t ,, the first end bit = %0b",$time,end_bit);
        end
      end
  endtask:catch_field_serout

  // Through the following task, UART BFM will catpure UART field from serial input port based on 
  // the configured start_bit field. The applied sequence here differs from the one applied on
  // capture field from serial output port since wrong and unknown commands are forced to the DUT
  // on the UART interface. The DUT is supposed to make no response to such commands.
  // This routine pays concern to this issue by initiating two parallel threads at the beginning;
  // 1- The first one run in the background to wait response time and triggered some internal 
  //    event (terminate event). It also set internal bit (path_select) to zero to make an 
  // indication that no response has been made.
  // 2- The second one includes two parallel sub-threads:
  //    a- The first one wait start bit.
  //    b- The other one wait terminate event triggering.
  //    Whenever one of those sub-threads is terminated, The main thread is joined.
  // The following sequence is carried out in case that start bit is captured:
  // 1- Wait start bit.
  // 2- Catpure the following eight bits in packed byte depending on the configured start bit.
  // 3- Depending on the configured number of stop bits, the stop bit(s) are captured.
  //    - In case that stop bit(s) is zero, the testbench will assign testbench error.
  // BFM will assign testbench error in case of un-configured start_bit field.
  task catch_field_serin (output byte data);
    bit end_bit;
    bit path_select;
    event terminate;
    path_select = 1'b1;
    fork
      begin
      #response_time;
      -> terminate;
      path_select = 1'b0;
      end
    join_none

    fork
      wait (ser_in == 1'b0);
      wait (terminate);
    join_any

    if (path_select)
      begin
      #(`buad_clk_period/2);
      case(start_bit)
        `lsb_first:
          begin
          for (int index=0;index<8;index++)
            begin
            catch_bit_serin(data[index]);
            end
          end
        `msb_first:
          begin
          for (int index=7;index>=0;index--)
            begin
            catch_bit_serin(data[index]);
            end
          end
        default:
          begin
          $error("Undefined serial mode");
          end
      endcase
      catch_bit_serin(end_bit);
      if(end_bit != 1'b1)
        begin
        $error("at time =%0t ,, the first end bit = %0b",$time,end_bit);
        end
      if (num_stop_bits == 2)
        begin
        catch_bit_serin(end_bit);
        if(end_bit != 1'b1)
          begin
          $error("at time =%0t ,, the first end bit = %0b",$time,end_bit);
          end
        end
      end

  endtask:catch_field_serin

  // Through the following function, the byte is reversed in the manner where the byte is merrored
  function byte reverse_byte (byte data);
    byte tmp;
    for (int index=0;index<8;index++)
      begin
      tmp[index] = data[7-index];
      end
    return tmp;
  endfunction:reverse_byte

//-------------------------------------------------------------------------------------------------
//
//                                      UART ROUTINES
//
//-------------------------------------------------------------------------------------------------

  // This method is provided to initiate write request in UART text mode. This task is accomplis-
  // hed through the following sequence:
  // 1- The first field :(Prefix Character)
  //    Depending on whether the mode type is text or wrong text and whether the prefix is small
  //    or capital character, the BFM force the prefix field. In case of wrong text type, the init-
  //    ial field is the provided wrong_prefix input. also internal wrong_mode_ctrl bit is cleared.
  //    - In case of undefined type, testbench assign testbench error.
  //                               -----------------------   
  // 2- The second field:(White Space Character)
  //    Depending on whether the used white space type is a single space, a tab space or provided 
  //    wrong space character is forced on the serial output port. 
  //                               -----------------------
  // 3- The third field:(Data Character)
  //    - In case of the data representation is binary, the data input character is encapsulated 
  //      in UART field and forced in single field.
  //    - In case of the data representation is ASCII, the data input character is divided into 
  //      two nipples. Each one is converted to ASCII character and sent separately in UART field. 
  //      The most significant nipple is sent first.
  //                               -----------------------
  // 4- The forth field:(White Space Character)
  //    Depending on whether the used white space type is a single space, a tab space or provided 
  //    wrong space character is forced on the serial output port. 
  //                               -----------------------
  // 5- The fifth field:(Address Two-Character)
  //    - In case of the data representation is binary, the address input two-character is divided 
  //      into two characters. They are encapsulated into two successive UART fields.
  //    - In case of the data representation is ASCII, the address input two-character is divided 
  //      into four nipples. Each one is converted to ASCII character and sent separately in UART 
  //      field. The ASCII characters are sent where the most significant nipple is sent first.
  //                               -----------------------
  // 6- The sixth field:(End-Of-Line Character):
  //    Depending on whether the used EOL type is CR, LF or provided wrong space character is 
  //    forced on the serial output port. 
  //                               -----------------------
  task write_text_mode(input int _type,
                       input byte wrong_prefix,
                       input int alph,
                       input int scp_type1,
                       input byte space_wrong1,
                       input int scp_type2,
                       input byte space_wrong2,
                       input int eol,
                       input byte eol_wrong,
                       input bit [`size-1:0] address,
                       input byte data);
    // Write procedures
    // First Field
    case (_type)
      `text_mode:
        begin
        if (alph == `small_let)
          begin
          push_field_serout(`w);
          end
        else if (alph == `capital_let)
          begin
          push_field_serout(`W);
          end
        else
          $error("Testbench error .. No capitar or small letter is choosed");
        end
      `wrong_mode_txt:
        begin
        push_field_serout(wrong_prefix);
        wrong_mode_ctrl = 1'b0;
        end
      default:
        begin
        $error("Undefined communication mode ..");
        end
    endcase

    // Second Field
    if (scp_type1 == `single_space)
      begin
      push_field_serout(`space);
      end
    else if (scp_type1 == `tab_space)
      begin
      push_field_serout(`tab);
      end
    else if (scp_type1 == `space_wrong)
      begin
      push_field_serout(space_wrong1);
      end
    else
      $error("Testbench error .. No single space or multiple space is choosed");

    // third field
    case (data_rep)
      `binary_rep:
        begin
        push_field_serout(data);
        end
      `ascii_rep:
        begin
        push_field_serout(bin_asci_conv(data[7:4]));
        push_field_serout(bin_asci_conv(data[3:0]));      
        end
      default:$error("undefined data representation");
    endcase

    // forth field
    if (scp_type2 == `single_space)
      begin
      push_field_serout(`space);
      end
    else if (scp_type2 == `tab_space)
      begin
      push_field_serout(`tab);
      end
    else if (scp_type2 == `space_wrong)
      begin
      push_field_serout(space_wrong2);
      end
    else
      $error("Testbench error .. No single or multiple space is choosed");
    // fivth field
    case (data_rep)
      `binary_rep:
        begin
        push_field_serout(address[15:08]);
        push_field_serout(address[07:00]);
        end
      `ascii_rep:
        begin
        push_field_serout(bin_asci_conv(address[15:12]));
        push_field_serout(bin_asci_conv(address[11:08]));
        push_field_serout(bin_asci_conv(address[07:04]));
        push_field_serout(bin_asci_conv(address[03:00]));      
        end
      default:$error("undefined data representation");
    endcase

    // sixth Field
    if (eol == `cr_eol)
      begin
      push_field_serout(`CR);
      end
    else if (eol == `lf_eol)
      begin
      push_field_serout(`LF);
      end
    else if (eol == `eol_wrong)
      begin
      push_field_serout(eol_wrong);
      end
    else
      $error("Testbench error .. either CR or LF isn't choosed as eol");
  endtask:write_text_mode

  // This method is provided to initiate read request in UART text mode. This task is accomplis-
  // hed through the following sequence:
  // 1- The first field :(Prefix Character)
  //    Depending on whether the mode type is text or wrong text and whether the prefix is small
  //    or capital character, the BFM force the prefix field. In case of wrong text type, the init-
  //    ial field is the provided wrong_prefix input. also internal wrong_mode_ctrl bit is cleared.
  //    - In case of undefined type, testbench assign testbench error.
  //                               -----------------------   
  // 2- The second field:(White Space Character)
  //    Depending on whether the used white space type is a single space, a tab space or provided 
  //    wrong space character is forced on the serial output port. 
  //                               -----------------------
  // 3- The third field:(Address Two-Character)
  //    - In case of the data representation is binary, the address input two-character is divided 
  //      into two characters. They are encapsulated into two successive UART fields.
  //    - In case of the data representation is ASCII, the address input two-character is divided 
  //      into four nipples. Each one is converted to ASCII character and sent separately in UART 
  //      field. The ASCII characters are sent where the most significant nipple is sent first.
  //                               -----------------------
  // 4- The forth field:(End-Of-Line Character):
  //    Depending on whether the used EOL type is CR, LF or provided wrong space character is 
  //    forced on the serial output port. 
  //                               -----------------------
  // GETTING RESPONSE :
  //    Since we may have no response due to either DUT internal bug or the forced request is  
  //    wrong (wrong mode, wrong white space, wrong eol), two parallel threads are initiated; The
  //    first one is to wait for response time and the other one waits start bit on the serial 
  //    input port. Both the two threads are terminated by meeting only one of the two events.
  //    In case of the start bit is captured and according to the configured the data representa-
  //    tion.
  //    - If it is binary, the following UART field is captured and its data is considered to be
  //      the requested data.
  //    - If it is ASCII, the two successive UART fields is captured and each byte is converted to
  //      binary nipple.
  //    The following character is captured and it must be CR.
  //    The following character is captured and it must be LF. 
  //    - If the last two characters aren't as indicated above, the testbench will assign testbench
  //      error.
  //                               -----------------------
  task read_text_mode (input int _type,
                       input byte wrong_prefix,
                       input int alph,
                       input int scp_type,
                       input byte space_wrong,
                       input int eol,
                       input byte eol_wrong,
                       input bit [`size-1:0] address,
                       input byte false_data,
                       input int false_data_en);
    byte data;
    byte temp;
    byte char1,char2;
    bit miss;
    // Read Request
    // First Field
    case (_type)
      `text_mode:
        begin
        if (alph == `small_let)
          begin
          push_field_serout(`r);
          end
        else if (alph == `capital_let)
          begin
          push_field_serout(`R);
          end
        else
          $error("Testbench error .. No capitar or small letter is choosed");
        end
      `wrong_mode_txt:
        begin
        push_field_serout(wrong_prefix);
        wrong_mode_ctrl = 1'b0;
        end
      default:
        begin
        $error("Undefined communication mode ..");
        end
    endcase
    
    // Second Field
    if (scp_type == `single_space)
      begin
      push_field_serout(`space);
      end
    else if (scp_type == `tab_space)
      begin
      push_field_serout(`tab);
      end
    else if (scp_type == `space_wrong)
      begin
      push_field_serout(space_wrong);
      end
    else
      $error("Testbench error .. No single or multiple white space is choosed");

    // Third Field
    case (data_rep)
      `binary_rep:
        begin
        push_field_serout(address[15:08]);
        push_field_serout(address[07:00]);
        end
      `ascii_rep:
        begin
        push_field_serout(bin_asci_conv(address[15:12]));
        push_field_serout(bin_asci_conv(address[11:08]));
        push_field_serout(bin_asci_conv(address[07:04]));
        push_field_serout(bin_asci_conv(address[03:00]));
        end
      default:$error("undefined data representation");
    endcase

    // Forth Field
    if (eol == `cr_eol)
      begin
      push_field_serout(`CR);
      end
    else if (eol == `lf_eol)
      begin
      push_field_serout(`LF);
      end
    else if (eol == `eol_wrong)
      begin
      push_field_serout(eol_wrong);
      end
    else
      $error("Testbench error .. No CR or LF is choosed");

    miss = 1'b0;       
    fork
      begin: miss_response_thread
      # response_time;
      disable capture_response_thread;
      miss = 1'b1;
      end

      begin: capture_response_thread
      wait(ser_in == 1'b0);
      disable miss_response_thread;
      end
    join
    // Capture Response
    if (miss == 1'b0)
      begin
      if (false_data_en ==`_yes && falsedata_gen_en == `_yes)
        begin
        fork
        push_field_serout(false_data);
        join_none
        end
      case (data_rep)
        `binary_rep:
          begin
          catch_field_serin(data);
          end
        `ascii_rep:
          begin
          catch_field_serin(temp);
          data[7:4] = asci_bin_conv(temp);
          catch_field_serin(temp);
          data[3:0] = asci_bin_conv(temp);
          end
        default:
          begin
          $error("Undefined data representation");
          $stop;
          end
      endcase      
      catch_field_serin(char1);
      catch_field_serin(char2);
      if (char1 != `CR || char2 != `LF)
        begin
        $error("EOL is refuesed");
        end
      end
  endtask:read_text_mode

  // This method is provided to initiate write request in UART binary mode. This task is accompli-
  // shed through the following sequence:
  //                               -----------------------
  //          NOTE :: ALL THE FOLLOWING BYTES ARE ENCAPSULATED INTO DEFINED UART FIELD FORM
  //                               -----------------------   
  // 1- The first byte :(Prefix byte)
  //    Depending on whether the mode type is binary or wrong binary the BFM force the prefix field
  //    In case of wrong binary type, the initial field is the provided wrong_prefix input. also 
  //    internal wrong_mode_ctrl bit is set.
  //    - In case of undefined type, testbench assign testbench error.
  //                               -----------------------   
  // 2- The second byte:(Command byte)
  //    Depending on whether the command is valid or invalid command, the two bits of the command
  //    are assigned. Also the auto increment bit and acknowledge request bit are assigned 
  //                               -----------------------
  // 3- The third byte:(Address highest byte)
  //    - The address bits [15:08] .
  //                               -----------------------
  // 4- The forth field:(Address lowest byte)
  //    - The address bits [07:00] .
  //                               -----------------------
  // 5- The fifth field:(Length Of Data byte)
  //    - The number of data bytes inclosed into this stimulus.
  //                               -----------------------
  // 6- The rest fields:(Data):
  //    Data Bytes are sent one by one.
  //                               -----------------------
  // GETTING RESPONSE:
  //    In case that the command includes acknowledge request, UART BFM will wait for the ackno-
  //    wledge unified character. 
  //                               -----------------------
  task automatic write_binary_mode (input int _type,
                                    input byte wrong_prefix,
                                    input int command,
                                    input int reqack,
                                    input int reqinc,
                                    input int unsigned data_length,
                                    input bit [`size-1:0] address,
                                    ref byte data []);
    byte tmp;
    int unsigned index;

    // first byte : binary prefix
    case(_type)
    `binary_mode:
      begin
      push_field_serout(`bin_prfx);
      end
    `wrong_mode_binry:
      begin
      push_field_serout(wrong_prefix);
      wrong_mode_ctrl = 1'b1;
      end
    default:
      begin
      $error("Undefined Communication Mode");
      end
    endcase

    // second byte : command
    case(command)
      `write_comm:
        begin
        tmp[5:4] = `write_ctrl;    
        end
      `wrong_comm_write:
        begin
        tmp[5:4] = `invalid_ctrl;
        wrong_data_ctrl = 1'b1;
        end
      default:
        begin
        $error("Undefined Command");
        end
    endcase
    tmp[5:4] = 2'b10;
    if(reqinc==`_yes)
      begin
      tmp[1] = 1'b0;
      end
    else if (reqinc == `_no)
      begin
      tmp[1] = 1'b1;
      end
    else
      begin
      $error("undefined increment request");
      end

    if(reqack==`_yes)
      begin
      tmp[0] = 1'b1;
      end
    else if (reqack == `_no)
      begin
      tmp[0] = 1'b0;
      end
    else
      begin
      $error("undefined acknowledge request");
      end
    push_field_serout(tmp);

    // Third byte : higher byte of address
    push_field_serout(address[15:08]);

    // Forth byte : Lower byte of address
    push_field_serout(address[07:00]);

    // Fifth byte : data length
    push_field_serout(data_length);

    index = 0;
    while(index<data_length)
      begin
      push_field_serout(data[index]);
      index++;
      end

    if (reqack == `_yes)
      begin
      catch_field_serin(tmp);
      if (tmp != `ACK)
        begin
        $error("The captured acknowledge isn't as unified character");
        end
      end
  endtask:write_binary_mode

  // This method is provided to initiate read request in UART binary mode. This task is accompli-
  // shed through the following sequence:
  //                               -----------------------
  //          NOTE :: ALL THE FOLLOWING BYTES ARE ENCAPSULATED INTO UART DEFINED FIELD FORM
  //                               -----------------------   
  // 1- The first byte :(Prefix byte)
  //    Depending on whether the mode type is binary or wrong binary the BFM force the prefix field
  //    In case of wrong binary type, the initial field is the provided wrong_prefix input. also 
  //    internal wrong_mode_ctrl bit is set.
  //    - In case of undefined type, testbench assign testbench error.
  //                               -----------------------   
  // 2- The second byte:(Command byte)
  //    Depending on whether the command is valid or invalid command, the two bits of the command
  //    are assigned. Also the auto increment bit and acknowledge request bit are assigned 
  //                               -----------------------
  // 3- The third byte:(Address highest byte)
  //    - The address bits [15:08] .
  //                               -----------------------
  // 4- The forth field:(Address lowest byte)
  //    - The address bits [07:00] .
  //                               -----------------------
  // 5- The fifth field:(Length Of Data byte)
  //    - The number of data bytes inclosed into this stimulus.
  //                               -----------------------
  // GETTING RESPONSE:
  //    Through this field, three independent parallel processes are carried out :
  //    i- The first one is mendatory and is responsible for capturing the UART fields drived by
  //       The DUT on the serial input port. Also it is responsible for capturing the acknowledge
  //       byte in case that the command include acknowledge request.
  //   ii- The second one is responsible for terminating this routine in case that no response has
  //       been driven by the DUT within the response time.
  //  iii- The last one is to drive dummy UART fields. It is used only when both the internal 
  //       false data enable and the global false data enable are set. Refer to UART testbench 
  //       specifications document for more details.
  //                               -----------------------
  task automatic read_binary_mode  (input int _type,
                                    input byte wrong_prefix,
                                    input int _command,
                                    input int reqack,
                                    input int reqinc,
                                    input int unsigned data_length,
                                    input bit [`size-1:0] address,
                                    ref byte data [],
                                    ref byte false_data [],
                                    input bit false_data_en);
    byte tmp;
    int unsigned index;
    int unsigned index_false;

    // first byte : binary prefix
    case (_type)
      `binary_mode:
        begin
        push_field_serout(`bin_prfx);
        end
      `wrong_mode_binry:
        begin
        push_field_serout(wrong_prefix);
        wrong_mode_ctrl = 1'b1;
        end
      default:
        begin
        $error("Undefined Communication Mode");
        end
    endcase

    // second byte : command
    case (_command)
      `read_comm:
        begin
        tmp[5:4] = `read_ctrl;
        end
      `wrong_comm_read:
        begin
        tmp[5:4] = `invalid_ctrl;
        wrong_data_ctrl = 1'b0;
        end
      default:
        begin
        $error("Undefined Command type");
        end
    endcase

    if(reqinc==`_yes)
      begin
      tmp[1] = 1'b0;
      end
    else if (reqinc == `_no)
      begin
      tmp[1] = 1'b1;
      end
    else
      begin
      $error("undefined increment request");
      end

    if(reqack==`_yes)
      begin
      tmp[0] = 1'b1;
      end
    else if (reqack == `_no)
      begin
      tmp[0] = 1'b0;
      end
    else
      begin  
      $error("undefined acknowledge request");
      end
    push_field_serout(tmp);

    // Third byte : higher byte of address
    push_field_serout(address[15:08]);

    // Forth byte : Lower byte of address
    push_field_serout(address[07:00]);

    // Fifth byte : data length
    if (data_length == 256)
      begin
      tmp = 8'b00;
      end
    else
      begin
      tmp = data_length;
      end
    push_field_serout(tmp);

    index = 0;

    fork
      if(false_data_en == `_yes && falsedata_gen_en == `_yes)
        begin
        while(index_false<data_length)
          begin
          push_field_serout(false_data[index_false]);
          index_false++;
          end
        end
      while(index<data_length)
        begin
        catch_field_serin(data[index]);
        index++;
        end
    join  
    if (reqack == `_yes)
      begin
      catch_field_serin(tmp);
      if (tmp != `ACK && _type == `binary_mode && _command == `read_comm)
        begin
        $error("The captured acknowledge isn't as unified character");
        end
      end
  endtask:read_binary_mode

  // This method is provided to initiate NOP command in UART binary mode. This task is accompli-
  // shed through the following sequence:
  //                               -----------------------
  //          NOTE :: ALL THE FOLLOWING BYTES ARE ENCAPSULATED INTO UART DEFINED FIELD FORM
  //                               -----------------------   
  // 1- The first byte :(Prefix byte)
  //    Depending on whether the mode type is binary or wrong binary the BFM force the prefix field
  //    In case of wrong binary type, the initial field is the provided wrong_prefix input. also 
  //    internal wrong_mode_ctrl bit is set.
  //    - In case of undefined type, testbench assign testbench error.
  //                               -----------------------   
  // 2- The second byte:(Command byte)
  //    The two bits of commads are assigned. Also the auto increment bit and acknowledge request 
  //    bit are assigned 
  //                               -----------------------
  // GETTING RESPONSE:
  //    In case that the command includes acknowledge request, UART BFM will wait for the ackno-
  //    wledge unified character. 
  //                               -----------------------
  task nop_command (input int _type,
                    input byte wrong_prefix,
                    input int reqack,
                    input int reqinc);
    byte tmp;
    int unsigned index;
    // first byte : prefix
    wrong_mode_ctrl = 1'b0;
    // first byte : binary prefix
    case (_type)
      `binary_mode:
        begin
        push_field_serout(`bin_prfx);
        end
      `wrong_mode_binry:
        begin
        push_field_serout(wrong_prefix);
        wrong_mode_ctrl = 1'b1;
        end
      default:
        begin
        $error("Undefined Communication Mode");
        end
    endcase

    // second byte :  command
    tmp[5:4] = 2'b00;
    if(reqinc==`_yes)
      begin
      tmp[1] = 1'b0;
      end
    else if (reqinc == `_no)
      begin
      tmp[1] = 1'b1;
      end
    else
      begin
      $error("undefined increment request");
      end

    if(reqack==`_yes)
      begin
      tmp[0] = 1'b1;
      end
    else if (reqack == `_no)
      begin
      tmp[0] = 1'b0;
      end
    else
      begin
      $error("undefined acknowledge request");
      end
    push_field_serout(tmp);

    if(reqack==`_yes)
      begin
      catch_field_serin(tmp);
      if(tmp!=`ACK)
        begin
        $error("Undefined acknowledge character");
        end
      end
  endtask:nop_command

  // This task is used to make the bus idle for time (idle).
  task wait_idle_time (time idle);
    force_sout(1'b1);
    #idle;
  endtask: wait_idle_time

//-------------------------------------------------------------------------------------------------
//
//                                     MONITOR ROUTINES
//
//-------------------------------------------------------------------------------------------------
  // This section of routines is used to monitor the UART signals and capture all the informations
  // about the stimulus, DUT state and DUT response as well. Each one is described in details below
  //  
  // This routine is used to wait for transaction start. It waits for start_trans triggering.
  task wait_event();
    wait (start_trans);
  endtask:wait_event

  // This method is the main method of the monitoring routines used to capture the UART 
  // transactions on the UART interfaces. Whenever it is called, it carries out the following 
  // procedures:
  // 1- Capture the first field loaded on the serial output port and detect the command type to be
  //    either text read, text write, binary, wrong command. And according to the command, another 
  //    proper task will be called.
  // NOTE: In case of wrong command, with the aid of internal bit wrong_mode_ctrl, UART BFM could 
  //       detect the actual type of wrong command.
  //                               -----------------------
  // 2- (I) In case that the command type is text, the dynamic array of data is initialized with 
  //        the standard size one byte. Also command and character type fields are assigned. Refer 
  //        to transaction fields for more informations about these fields.
  //   (II) In case that the command type is binary, capture_binary_command task is called.
  //  (III) In case that the command type is wrong, nothing is done.
  task automatic capture_command (output int command_type,
                                  output int _command,
                                  output int _chartype,
                                  output int _spacetype1,
                                  output int space_wrong1,
                                  output int _spacetype2,
                                  output int space_wrong2,
                                  output int _eoltype,
                                  output int eol_wrong,
                                  output bit [`size-1:0] address,
                                  ref byte data [],
                                  output byte acknowledge,
                                  output int unsigned data_length,
                                  output int _reqack,
                                  output int _reqinc);

    byte temp;
    byte read_byte;
    catch_field_serout(read_byte);
    case (read_byte)
      `w:
        begin
        command_type  = `text_mode;
        _command      = `write_comm;
        _chartype     = `small_let;
        data = new [1];
        capture_text_write_command(_spacetype1,
                                   space_wrong1,
                                   _spacetype2,
                                   space_wrong2,
                                   _eoltype,
                                   eol_wrong,
                                   address,
                                   data[0]);
        end
      `W:
        begin
        command_type  = `text_mode;
        _command      = `write_comm;
        _chartype     = `capital_let;
        data = new [1];
        capture_text_write_command(_spacetype1,
                                   space_wrong1,
                                   _spacetype2,
                                   space_wrong2,
                                   _eoltype,
                                   eol_wrong,
                                   address,
                                   data[0]);
        end
      `r:
        begin
        command_type  = `text_mode;
        _command      = `read_comm;
        _chartype     = `small_let;
        data = new [1];
        capture_text_read_command(_spacetype1,
                                  space_wrong1,
                                  _eoltype,
                                  eol_wrong,
                                  address,
                                  data [0]);
        end
      `R:
        begin
        command_type  = `text_mode;
        _command      = `read_comm;
        _chartype     = `capital_let;
        data = new [1];
        capture_text_read_command(_spacetype1,
                                  space_wrong1,
                                  _eoltype,
                                  eol_wrong,
                                  address,
                                  data [0]);
        end
      `bin_prfx:
        begin
        command_type  = `binary_mode;
        capture_binary_command(_command,
                               _reqack,
                               _reqinc,
                               address,
                               data_length,
                               data,
                               acknowledge);
        end
      default:
        begin
        if (wrong_mode_ctrl)
          begin
          command_type  = `wrong_mode_binry;
          end
        else
          begin
          command_type  = `wrong_mode_txt;
          end
        end
    endcase
  endtask:capture_command

  // This method is used to capture read command in text mode. Whenever it is called, the following
  // procedures are carried out :
  //                               -----------------------
  // 1- Capture the second command field which includes the white space character.
  //                               -----------------------
  // 2- According to the configured data representation:
  //    i- Binary representation: Catch the following two UART fields on the serial output port 
  //                              which include the current stimulus address.
  //   ii- ASCII representation: Catch the following four UART fields on the serial output port
  //                             which include the current stimulus address in ASCII format.their 
  //                             data bytes are converted to binary format.
  //                               -----------------------
  // 3- Capture the following field which includes the end of line character.
  //                               -----------------------
  // GETTING RESPONSE: 
  //  - Run two concurrent threads:
  //    i- The first one is to wait response time.
  //   ii- The second one is to capture the data UART fields on the serial input port.
  //  - In case that no response is found, this task is terminated.
  //  - After catch the data fields, the next two fields are also captured to check the two end
  //    of line characters.
  //                               -----------------------
  task capture_text_read_command (output int _spacetype,
                                  output int space_wrong,
                                  output int _eoltype,
                                  output int eol_wrong,
                                  output bit [`size-1:0] address,
                                  output byte data);
    byte read_byte;
    bit miss;

    catch_field_serout(read_byte);
    case (read_byte)
      `space:
        begin
        _spacetype  = `single_space;
        end
      `tab:
        begin
        _spacetype  = `tab_space;
        end
      default:
        begin
        _spacetype  = `space_wrong;
        space_wrong = read_byte;
        end
    endcase

    case(data_rep)
      `binary_rep:
        begin
        catch_field_serout(read_byte);
        address[15:08] = read_byte;
        catch_field_serout(read_byte);
        address[07:00] = read_byte;
        end
      `ascii_rep:
        begin
        catch_field_serout(read_byte);
        address[15:12] = asci_bin_conv(read_byte);
        catch_field_serout(read_byte);
        address[11:08] = asci_bin_conv(read_byte);
        catch_field_serout(read_byte);
        address[07:04] = asci_bin_conv(read_byte);
        catch_field_serout(read_byte);
        address[03:00] = asci_bin_conv(read_byte);
        end
      default:
        begin
        $error("undefined data representation");
        $stop;
        end
    endcase

    catch_field_serout(read_byte);
    case(read_byte)
      `CR:
        begin
        _eoltype    = `cr_eol;
        end
      `LF:
        begin
        _eoltype    = `lf_eol;
        end
      default:
        begin
        _eoltype    = `eol_wrong;
        eol_wrong   = read_byte;
        end
    endcase

    miss = 1'b0;
    fork
      begin: miss_response_thread
      #response_time;
      disable capture_response_thread;
      miss = 1'b1;
      end

      begin: capture_response_thread
      wait(ser_in == 1'b0);
      disable miss_response_thread;
      end
    join

    if (miss==1'b0)
      begin
      case(data_rep)
        `binary_rep:
          begin
          catch_field_serin(read_byte);
          data = read_byte;
          end
        `ascii_rep:
          begin
          catch_field_serin(read_byte);
          data[7:4] = asci_bin_conv(read_byte);
          catch_field_serin(read_byte);
          data[3:0] = asci_bin_conv(read_byte);
          end
        default:
          begin
          $error("undefined data representation");
          $stop;
          end
      endcase

      catch_field_serin(read_byte);
      if (read_byte == `CR)
        begin
        catch_field_serin(read_byte);
        if (read_byte != `LF)
          begin
          $error("the catpured byte isn't LF");
          end
        end
      else if (read_byte == `LF)
        begin
        $error("The captured byte is LF instead of CR");
        end
      else
        begin
        $error("Fatal Error : final character in read request isn't CR and LF");
        end
      end    

  endtask:capture_text_read_command

  // This method is used to capture write command in text mode. Whenever it is called, the follo-
  // wing procedures are carried out :
  //                               -----------------------
  // 1- Capture the second command field which includes the white space character.
  //                               -----------------------
  // 2- According to the configured data representation:
  //    i- Binary representation: Catch the following UART field on the serial output port 
  //                              which includes the current stimulus data.
  //   ii- ASCII representation: Catch the following two UART fields on the serial output port
  //                             which include the current stimulus data in ASCII format.their 
  //                             data bytes are converted to binary format.
  //                               -----------------------
  // 3- Capture the next field which includes the white space character.
  //                               -----------------------
  // 4- According to the configured data representation:
  //    i- Binary representation: Catch the following two UART fields on the serial output port 
  //                              which include the current stimulus address.
  //   ii- ASCII representation: Catch the following four UART fields on the serial output port
  //                             which include the current stimulus address in ASCII format.their 
  //                             data bytes are converted to binary format.
  //                               -----------------------
  // 3- Capture the following field which includes the end of line character.
  //                               -----------------------

  task capture_text_write_command ( output int _spacetype1,
                                    output int space_wrong1,
                                    output int _spacetype2,
                                    output int space_wrong2,
                                    output int _eoltype,
                                    output int eol_wrong,
                                    output bit [`size-1:0] address,
                                    output byte data);

    byte read_byte;
    catch_field_serout(read_byte);
    case (read_byte)
      `space:
        begin
        _spacetype1  = `single_space;
        end
      `tab:
        begin
        _spacetype1  = `tab_space;
        end
      default:
        begin
        _spacetype1  = `space_wrong;
        space_wrong1 = read_byte;
        end
    endcase

    case(data_rep)
      `binary_rep:
        begin
        catch_field_serout(read_byte);
        data = read_byte;
        end
      `ascii_rep:
        begin
        catch_field_serout(read_byte);
        data[7:4] = asci_bin_conv(read_byte);
        catch_field_serout(read_byte);
        data[3:0] = asci_bin_conv(read_byte);
        end
      default:
        begin
        $error("undefined data representation");
        $stop;
        end
    endcase

    catch_field_serout(read_byte);
    case (read_byte)
      `space:
        begin
        _spacetype2  = `single_space;
        end
      `tab:
        begin
        _spacetype2  = `tab_space;
        end
      default:
        begin
        _spacetype2  = `space_wrong;
        space_wrong2 = read_byte;
        end
    endcase

    case(data_rep)
      `binary_rep:
        begin
        catch_field_serout(read_byte);
        address[15:08] = read_byte;
        catch_field_serout(read_byte);
        address[07:00] = read_byte;
        end
      `ascii_rep:
        begin
        catch_field_serout(read_byte);
        address[15:12] = asci_bin_conv(read_byte);
        catch_field_serout(read_byte);
        address[11:08] = asci_bin_conv(read_byte);
        catch_field_serout(read_byte);
        address[07:04] = asci_bin_conv(read_byte);
        catch_field_serout(read_byte);
        address[03:00] = asci_bin_conv(read_byte);
        end
      default:
        begin
        $error("Undefined data representation");
        $stop;
        end
    endcase

    catch_field_serout(read_byte);
    case(read_byte)
      `CR:
        begin
        _eoltype    = `cr_eol;
        end
      `LF:
        begin
        _eoltype    = `lf_eol;
        end
      default:
        begin
        _eoltype    = `eol_wrong;
        eol_wrong   = read_byte;
        end
    endcase
  endtask: capture_text_write_command

  // This method is used to capture binary mode command. Whenever it is called, the following
  // procedures are carried out :
  //                               -----------------------
  // 1- Capture and decode the second command field which includes the command, the acknowledge
  //    request and also the address auto-increment enable.
  //  - In case that the command bits indicate invalid command, BFM uses wrond_data_ctrl internal
  //    bit to know wether this stimulus is wrong read or wrong write. No response should be driven
  //    by the DUT in the both cases. But we need to discriminte between the two cases to facili- 
  //    tates the scoreboard job.
  //                               -----------------------
  // 2- Capture the following field which includes the higher byte of the command address.
  //                               -----------------------
  // 3- Capture the following field which includes the lower byte of the command address.
  //                               -----------------------
  // 4- Capture the next field which includes the number of data bytes.
  //                               -----------------------
  // 5- According to the decoded command:
  //    i- Read Command   : Poll the serial input port and capture number of successive UART fields
  //                        equal to the number of data bytes. In case of acknowledge request, ano-
  //                        ther field is captured and compared to the standard acknowledge 
  //                        character
  //
  //   ii- Write Command  : Poll the serial output port and capture number of successive UART fie- 
  //                        lds equal to the number of data bytes. In case of acknowledge request,
  //                        another field is captured on the serial input port and compare to the 
  //                        standard acknowledge character
  //
  //  iii- NOP Command    : In case of acknowledge request, another field is captured on the serial
  //                        input port and compared to the standard acknowledge character
  //
  //  iv- Invalid Command : In case that it is wrong read command, the same sequence obligied at
  //                        the valid read command is carried out.
  //                        In case that it is wrond write command, the same sequence obligied at
  //                        the valid write command is carried out.
  //                               -----------------------
  // NOTE: Since the number of data bytes is defined at the run-time, we use queue of bytes to 
  //       packetaize the data temporarily and re-assign it to the dynamic array of data.
  //                               -----------------------  
  task automatic capture_binary_command (output int _command,
                                         output int _reqack,
                                         output int _reqinc,
                                         output bit [15:0] address,
                                         output int data_length,
                                         ref byte data [],
                                         output byte acknowledge);
    byte read_byte;
    int index;
    byte que [$];
    
    // first byte
    catch_field_serout(read_byte);
    case(read_byte[5:4])
      `nop_ctrl:
        begin
        _command = `nop_comm;
        end
      `read_ctrl:
        begin
        _command = `read_comm;
        end
      `write_ctrl:
        begin
        _command = `write_comm;
        end
      `invalid_ctrl:
        begin
        if(wrong_data_ctrl)
          begin
          _command = `wrong_comm_write;
          end
        else
          begin
          _command = `wrong_comm_read;
          end
        end
      default:
        begin
        $error("invalid Command");
        end
    endcase
    
    if (read_byte[1])
      begin
      _reqinc = `_no;
      end
    else
      begin
      _reqinc = `_yes;
      end
    if (read_byte[0])
      begin
      _reqack = `_yes;
      end
    else
      begin
      _reqack = `_no;
      end
      if (_command != `nop_comm)
        begin
        catch_field_serout(read_byte);
        address[15:08] = read_byte;

        catch_field_serout(read_byte);
        address[07:00] = read_byte;

        catch_field_serout(read_byte);
        if (read_byte == 8'h00)
          begin
          data_length = 256;
          end
        else
          begin
          data_length = read_byte;
          end

        que.delete();
        if (_command == `read_comm || _command == `wrong_comm_read)
          begin
          index=0;
          while(index < data_length)
            begin
            catch_field_serin(read_byte);
            que.push_back(read_byte);
            index++;
            end
          end
        else if (_command == `write_comm || _command == `wrong_comm_write)
          begin
          index=0;
          while(index < data_length)
            begin
            catch_field_serout(read_byte);
            que.push_back(read_byte);
            index++;
            end
          end
        data = new [que.size];
        data = que;
        end
    if(_reqack == `_yes)
      begin
      catch_field_serin(acknowledge);
      end
  endtask:capture_binary_command

 endinterface:uart_interface

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.