openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

merlin16_internal.c (81904B)


      1 /***********************************************************************************
      2  ***********************************************************************************
      3  *  File Name     :  merlin16_internal.c                                         *
      4  *  Created On    :  13/02/2014                                                    *
      5  *  Created By    :  Justin Gaither                                                *
      6  *  Description   :  APIs for Serdes IPs                                           *
      7  *  Revision      :   *
      8  *                                                                                 *
      9  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
     10  * 
     11  * Copyright 2007-2019 Broadcom Inc. All rights reserved.                                                           *
     12  *  No portions of this material may be reproduced in any form without             *
     13  *  the written permission of:                                                     *
     14  *      Broadcom Corporation                                                       *
     15  *      5300 California Avenue                                                     *
     16  *      Irvine, CA  92617                                                          *
     17  *                                                                                 *
     18  *  All information contained in this document is Broadcom Corporation             *
     19  *  company private proprietary, and trade secret.                                 *
     20  */
     21 
     22 /** @file merlin16_internal.c
     23  * Implementation of API functions
     24  */
     25 
     26 #include <phymod/phymod.h>
     27 #include <phymod/phymod_system.h>
     28 #include "merlin16_internal.h"
     29 #include "merlin16_internal_error.h"
     30 #include "merlin16_access.h"
     31 #include "merlin16_common.h"
     32 #include "merlin16_config.h"
     33 #include "merlin16_functions.h"
     34 #include "merlin16_select_defns.h"
     35 #include "merlin16_prbs.h"
     36 
     37 
     38 
     39 
     40 /* If SERDES_EVAL is defined, then is_ate_log_enabled() is queried to *\
     41 \* know whether to log ATE.  merlin16_access.h provides that function.  */
     42 uint32_t merlin16_INTERNAL_mult_with_overflow_check(uint32_t a, uint32_t b, uint8_t *of) {
     43     uint16_t c,d;
     44     uint32_t r,s;
     45     if (a > b) return merlin16_INTERNAL_mult_with_overflow_check(b, a, of);
     46     *of = 0;
     47     c = b >> 16;
     48     d = UINT16_MAX & b;
     49     r = a * c;
     50     s = a * d;
     51     if (r > UINT16_MAX) *of = 1;
     52     r <<= 16;
     53     return (s + r);
     54 }
     55 
     56 static merlin16_info_t merlin16_info = {0};
     57 
     58 merlin16_info_t *merlin16_INTERNAL_get_merlin16_info_ptr(void) {
     59     return &merlin16_info;
     60 }
     61 
     62 err_code_t merlin16_INTERNAL_match_ucode_from_info(srds_access_t *sa__) {
     63     uint16_t ucode_version_major;
     64     uint8_t ucode_version_minor;
     65     uint32_t ucode_version;
     66     merlin16_info_t * const merlin16_info_ptr = merlin16_INTERNAL_get_merlin16_info_ptr();
     67     ESTM(ucode_version_major = rdcv_common_ucode_version());
     68     ESTM(ucode_version_minor = rdcv_common_ucode_minor_version());
     69     ucode_version = (ucode_version_major << 8) | ucode_version_minor;
     70     if (ucode_version == merlin16_info_ptr->ucode_version) {
     71         return(ERR_CODE_NONE);
     72     } else {
     73         EFUN_PRINTF(("ERROR:  ucode version of the current thread not matching with stored merlin16_info->ucode_version, Expected 0x%08X, but received 0x%08X.\n",
     74                     merlin16_info_ptr->ucode_version, ucode_version));
     75         return(ERR_CODE_UCODE_VERIFY_FAIL);
     76     }
     77 }
     78 
     79 err_code_t merlin16_INTERNAL_verify_merlin16_info(merlin16_info_t const *test_info, srds_access_t *sa__)
     80 {
     81     err_code_t err_code = ERR_CODE_NONE;
     82     
     83     if (test_info->signature != SRDS_INFO_SIGNATURE) {
     84         EFUN_PRINTF(("ERROR:  Mismatch in merlin16_info signature.  Expected 0x%08X, but received 0x%08X.\n",
     85                      SRDS_INFO_SIGNATURE, test_info->signature));
     86         return (_error(ERR_CODE_INFO_TABLE_ERROR));
     87     }
     88     err_code = merlin16_INTERNAL_match_ucode_from_info(sa__);
     89     if (err_code != ERR_CODE_NONE) {
     90         /* ucode version mismatch */
     91         return(ERR_CODE_MICRO_INIT_NOT_DONE);
     92     }
     93     return (ERR_CODE_NONE);
     94 }
     95 
     96 /* Store a cached AFE version for re-use */
     97 err_code_t merlin16_INTERNAL_get_afe_hw_version(srds_access_t *sa__, uint8_t *afe_hw_version) {
     98   static uint8_t _cached_afe_hw_version = 255;
     99   
    100   if (!afe_hw_version)
    101     return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    102   if (_cached_afe_hw_version == 255)
    103     ESTM(_cached_afe_hw_version = rdcv_afe_hardware_version());
    104   *afe_hw_version = _cached_afe_hw_version;
    105   return(ERR_CODE_NONE);
    106 }
    107 
    108 int merlin16_osr_mode_enum_to_int_x1000(uint8_t osr_mode) {
    109     switch(osr_mode) {
    110     case MERLIN16_OSX1:      return 1000;
    111     case MERLIN16_OSX2:      return 2000;
    112     case MERLIN16_OSX4:      return 4000;
    113     case MERLIN16_OSX3:      return 3000;
    114     case MERLIN16_OSX3P3:    return 3300;
    115     case MERLIN16_OSX5:      return 5000;
    116     case MERLIN16_OSX7P5:    return 7500;
    117     case MERLIN16_OSX8P25:   return 8250;
    118     case MERLIN16_OSX10:     return 10000;
    119     case MERLIN16_OSX8:      return 8000;
    120     default:                    return 1000;
    121     }
    122 }
    123 
    124 err_code_t merlin16_INTERNAL_get_num_bits_per_ms(srds_access_t *sa__, uint32_t *num_bits_per_ms) {
    125     uint8_t osr_mode = 0;
    126 #if defined(rd_rx_pam4_mode)
    127     uint8_t pam4_mode = 0;
    128 #endif
    129     struct merlin16_uc_core_config_st core_config = {{0}};
    130 
    131     { 
    132        merlin16_osr_mode_st osr_mode_st;
    133        ENULL_MEMSET(&osr_mode_st, 0, sizeof(merlin16_osr_mode_st));
    134        EFUN(merlin16_INTERNAL_get_osr_mode(sa__, &osr_mode_st));
    135        osr_mode = osr_mode_st.rx;
    136     }
    137 
    138 #if defined(rd_rx_pam4_mode)
    139     ESTM(pam4_mode = rd_rx_pam4_mode());
    140 #endif
    141 
    142         EFUN(merlin16_get_uc_core_config(sa__, &core_config));
    143         *num_bits_per_ms = (((uint32_t)core_config.vco_rate_in_Mhz * 100000UL) / merlin16_osr_mode_enum_to_int_x1000(osr_mode))*10;
    144 
    145 #if defined(rd_rx_pam4_mode)
    146     if(pam4_mode > 0) *num_bits_per_ms <<= 1; 
    147 #endif
    148     return(ERR_CODE_NONE);
    149 }
    150 
    151 err_code_t merlin16_INTERNAL_display_BER(srds_access_t *sa__, uint16_t time_ms) {
    152     char string[10];
    153     EFUN(merlin16_INTERNAL_get_BER_string(sa__,time_ms,string));
    154     USR_PRINTF(("%s",string));
    155     return(ERR_CODE_NONE);
    156 }
    157 
    158 err_code_t merlin16_INTERNAL_get_BER_string(srds_access_t *sa__, uint16_t time_ms, char *string) {
    159     char string2[3];
    160     struct ber_data_st ber_data_local;
    161 
    162     ENULL_MEMSET( &ber_data_local, 0, sizeof(ber_data_local) );
    163 
    164     if(string == NULL) {
    165         return(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
    166     }
    167 
    168     EFUN(merlin16_INTERNAL_get_BER_data(sa__, time_ms, &ber_data_local));
    169 
    170     if(ber_data_local.prbs_chk_en == 0) {
    171         USR_STRCPY(string,"");
    172         return(ERR_CODE_NONE);
    173     } else {
    174         USR_STRCPY(string2," ");
    175     }
    176 
    177     if((COMPILER_64_HI(ber_data_local.num_errs) == 0) &&
    178        (COMPILER_64_LO(ber_data_local.num_errs) < 3) &&
    179        (ber_data_local.lcklost == 0)) {   /* lcklost = 0 */
    180         USR_STRNCAT(string2,"<",1);
    181         COMPILER_64_SET(ber_data_local.num_errs, 0, 3);
    182     } else {
    183         USR_STRNCAT(string2," ",1);
    184     }
    185     if(ber_data_local.lcklost == 1) {    /* lcklost = 1 */
    186         USR_STRCPY(string,"  !Lock ");
    187     } else {                    /* lcklost = 0 */
    188         uint16_t x=0,y=0,z=0,div;
    189 
    190         if(COMPILER_64_GE(ber_data_local.num_errs, ber_data_local.num_bits)) {
    191             x = 1;y=0;z=0;
    192         }else {
    193             uint64_t temp_dividend;
    194             uint64_t temp_divisor;
    195             while(1) {
    196                 COMPILER_64_COPY(temp_dividend, ber_data_local.num_errs);
    197                 COMPILER_64_SHL(temp_dividend, 1);
    198                 COMPILER_64_ADD_64(temp_dividend, ber_data_local.num_bits);
    199 
    200                 COMPILER_64_COPY(temp_divisor, ber_data_local.num_bits);
    201                 COMPILER_64_SHL(temp_divisor, 1);
    202 
    203                 COMPILER_64_UDIV_64(temp_dividend, temp_divisor);
    204 
    205                 div = (uint16_t) COMPILER_64_LO( temp_dividend );
    206 
    207                 if(div>=10) {
    208                     break;
    209                 }
    210 
    211                 COMPILER_64_UMUL_32(ber_data_local.num_errs, 10);
    212                 z=z+1;
    213             }
    214             if(div>=100) {
    215                 div = div/10;
    216                 z=z-1;
    217             }
    218             x=div/10;
    219             y = div - 10*x;
    220             z=z-1;
    221         }
    222         USR_SPRINTF(string,"%s%d.%1de-%02d",string2,x,y,z);
    223 
    224     }
    225     return(ERR_CODE_NONE);
    226 
    227 }
    228 
    229 err_code_t merlin16_INTERNAL_get_BER_data(srds_access_t *sa__, uint16_t time_ms, struct ber_data_st *ber_data) {
    230     uint8_t lcklost = 0;
    231     uint32_t err_cnt= 0;
    232 
    233 
    234     if(ber_data == NULL) {
    235         return(ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
    236     }
    237 
    238     ESTM(ber_data->prbs_chk_en = rd_prbs_chk_en());
    239     if(ber_data->prbs_chk_en == 0)
    240         return(ERR_CODE_NONE);
    241 
    242     EFUN(merlin16_prbs_err_count_state(sa__, &err_cnt,&lcklost)); /* clear error counters */
    243 
    244         EFUN(USR_DELAY_MS(time_ms));
    245         EFUN(merlin16_prbs_err_count_state(sa__, &err_cnt,&lcklost));
    246         ber_data->lcklost = lcklost;
    247         if(ber_data->lcklost == 0) {
    248             uint32_t num_bits_per_ms=0;
    249             EFUN(merlin16_INTERNAL_get_num_bits_per_ms(sa__,&num_bits_per_ms));
    250             COMPILER_64_SET(ber_data->num_bits, 0, num_bits_per_ms);
    251             COMPILER_64_UMUL_32(ber_data->num_bits, time_ms);
    252             COMPILER_64_SET(ber_data->num_errs, 0, err_cnt);
    253             ESTM(lcklost = rd_prbs_chk_lock_lost_lh());
    254         }
    255 
    256 
    257 
    258     return(ERR_CODE_NONE);
    259 }
    260 
    261 
    262 
    263 err_code_t merlin16_INTERNAL_get_p1_threshold(srds_access_t *sa__, int8_t *val) {
    264  ESTM(*val = -rd_p1_eyediag_bin()); 
    265  return (ERR_CODE_NONE);
    266 }
    267 
    268 
    269 int16_t merlin16_INTERNAL_ladder_setting_to_mV(srds_access_t *sa__, int8_t ctrl, uint8_t range_250) {
    270     uint16_t absv;                                    /* Absolute value of ctrl */
    271     int16_t nlmv;                                     /* Non-linear value */
    272     
    273     /* Get absolute value */
    274     absv = SRDS_ABS(ctrl);
    275 
    276     { 
    277         if (range_250) {
    278             /* 28nm range is 250mV, but 16nm range is 200mV */
    279             /* 200mV range, 6.5519mV linear units */
    280             nlmv = absv*190/29;
    281         }
    282         else {
    283             /* 120mV range, 3.8854mV linear units */
    284             nlmv = absv*136/35;
    285         }
    286     }
    287     /* Add sign and return */
    288     return( (ctrl>=0) ? nlmv : -nlmv);
    289 }
    290 
    291 
    292 err_code_t merlin16_INTERNAL_compute_bin(char var, char bin[]) {
    293     if(!bin) {
    294         return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    295     }
    296 
    297   switch (var) {
    298     case '0':  ENULL_STRCPY(bin,"0000");
    299                break;
    300     case '1':  ENULL_STRCPY(bin,"0001");
    301                break;
    302     case '2':  ENULL_STRCPY(bin,"0010");
    303                break;
    304     case '3':  ENULL_STRCPY(bin,"0011");
    305                break;
    306     case '4':  ENULL_STRCPY(bin,"0100");
    307                break;
    308     case '5':  ENULL_STRCPY(bin,"0101");
    309                break;
    310     case '6':  ENULL_STRCPY(bin,"0110");
    311                break;
    312     case '7':  ENULL_STRCPY(bin,"0111");
    313                break;
    314     case '8':  ENULL_STRCPY(bin,"1000");
    315                break;
    316     case '9':  ENULL_STRCPY(bin,"1001");
    317                break;
    318     case 'a':
    319     case 'A':  ENULL_STRCPY(bin,"1010");
    320                break;
    321     case 'b':
    322     case 'B':  ENULL_STRCPY(bin,"1011");
    323                break;
    324     case 'c':
    325     case 'C':  ENULL_STRCPY(bin,"1100");
    326                break;
    327     case 'd':
    328     case 'D':  ENULL_STRCPY(bin,"1101");
    329                break;
    330     case 'e':
    331     case 'E':  ENULL_STRCPY(bin,"1110");
    332                break;
    333     case 'f':
    334     case 'F':  ENULL_STRCPY(bin,"1111");
    335                break;
    336     case '_':  ENULL_STRCPY(bin,"");
    337                break;
    338     default :  ENULL_STRCPY(bin,"");
    339                EFUN_PRINTF(("ERROR: Invalid Hexadecimal Pattern\n"));
    340                return (_error(ERR_CODE_CFG_PATT_INVALID_HEX));
    341   }
    342   return (ERR_CODE_NONE);
    343 }
    344 
    345 
    346 err_code_t merlin16_INTERNAL_compute_hex(char bin[],uint8_t *hex) {
    347   if(!hex) {
    348     return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    349   }
    350  
    351   if (!USR_STRCMP(bin,"0000")) {
    352     *hex = 0x0;
    353   } 
    354   else if (!USR_STRCMP(bin,"0001")) {
    355     *hex = 0x1;
    356   } 
    357   else if (!USR_STRCMP(bin,"0010")) {
    358     *hex = 0x2;
    359   } 
    360   else if (!USR_STRCMP(bin,"0011")) {
    361     *hex = 0x3;
    362   } 
    363   else if (!USR_STRCMP(bin,"0100")) {
    364     *hex = 0x4;
    365   } 
    366   else if (!USR_STRCMP(bin,"0101")) {
    367     *hex = 0x5;
    368   } 
    369   else if (!USR_STRCMP(bin,"0110")) {
    370     *hex = 0x6;
    371   } 
    372   else if (!USR_STRCMP(bin,"0111")) {
    373     *hex = 0x7;
    374   } 
    375   else if (!USR_STRCMP(bin,"1000")) {
    376     *hex = 0x8;
    377   } 
    378   else if (!USR_STRCMP(bin,"1001")) {
    379     *hex = 0x9;
    380   } 
    381   else if (!USR_STRCMP(bin,"1010")) {
    382     *hex = 0xA;
    383   } 
    384   else if (!USR_STRCMP(bin,"1011")) {
    385     *hex = 0xB;
    386   } 
    387   else if (!USR_STRCMP(bin,"1100")) {
    388     *hex = 0xC;
    389   } 
    390   else if (!USR_STRCMP(bin,"1101")) {
    391     *hex = 0xD;
    392   } 
    393   else if (!USR_STRCMP(bin,"1110")) {
    394     *hex = 0xE;
    395   } 
    396   else if (!USR_STRCMP(bin,"1111")) {
    397     *hex = 0xF;
    398   } 
    399   else {
    400     EFUN_PRINTF(("ERROR: Invalid Binary to Hex Conversion\n"));
    401     *hex = 0x0;
    402     return (_error(ERR_CODE_CFG_PATT_INVALID_BIN2HEX));
    403   } 
    404   return (ERR_CODE_NONE);
    405 }
    406 
    407 uint8_t merlin16_INTERNAL_stop_micro(srds_access_t *sa__, uint8_t graceful, err_code_t *err_code_p) {
    408    uint8_t stop_state = 0;
    409 
    410    if(!err_code_p) {
    411        return(0xFF);
    412    }
    413 
    414    /* Log current micro stop status */
    415    EPSTM2((stop_state = rdv_usr_sts_micro_stopped()),0xFF);
    416 
    417    /* Stop micro only if micro is not stopped currently */
    418    if (!(stop_state & 0x7F)) {
    419        if (graceful) {
    420            EPFUN2((merlin16_stop_rx_adaptation(sa__, 1)),0xFF);
    421        }
    422        else {
    423            EPFUN2((merlin16_pmd_uc_control(sa__, CMD_UC_CTRL_STOP_IMMEDIATE,GRACEFUL_STOP_TIME)),0xFF);
    424        }
    425    }
    426 
    427    /* Return the previous micro stop status */
    428    return(stop_state);
    429 }
    430 
    431 
    432 /* Repeater Only APIs (Not applicable to PMD) */
    433 
    434   
    435 
    436 /********************************************************/
    437 /*  Global RAM access through Micro Register Interface  */
    438 /********************************************************/
    439 /* Micro Global RAM Byte Read */
    440 uint8_t merlin16_INTERNAL_rdb_uc_var(srds_access_t *sa__, err_code_t *err_code_p, uint16_t addr) {
    441     uint8_t rddata;
    442 
    443     if(!err_code_p) {
    444         return(0);
    445     }
    446     EPSTM(rddata = merlin16_rdb_uc_ram(sa__, err_code_p, addr)); /* Use Micro register interface for reading RAM */
    447     return (rddata);
    448 }
    449 
    450 /* Micro Global RAM Word Read */
    451 uint16_t merlin16_INTERNAL_rdw_uc_var(srds_access_t *sa__, err_code_t *err_code_p, uint16_t addr) {
    452   uint16_t rddata;
    453 
    454   if(!err_code_p) {
    455       return(0);
    456   }
    457   if (addr%2 != 0) {                                         /* Validate even address */
    458       *err_code_p = ERR_CODE_INVALID_RAM_ADDR;
    459       USR_PRINTF(("Error incorrect addr x%04x\n",addr));
    460       return (0);
    461   }
    462   EPSTM(rddata = merlin16_rdw_uc_ram(sa__, err_code_p, (addr))); /* Use Micro register interface for reading RAM */
    463   return (rddata);
    464 }
    465 
    466 /* Micro Global RAM Byte Write  */
    467 err_code_t merlin16_INTERNAL_wrb_uc_var(srds_access_t *sa__, uint16_t addr, uint8_t wr_val) {
    468 
    469     return (merlin16_wrb_uc_ram(sa__, addr, wr_val));          /* Use Micro register interface for writing RAM */
    470 }
    471 
    472 /* Micro Global RAM Word Write  */
    473 err_code_t merlin16_INTERNAL_wrw_uc_var(srds_access_t *sa__, uint16_t addr, uint16_t wr_val) {
    474     if (addr%2 != 0) {                                       /* Validate even address */
    475       USR_PRINTF(("Error incorrect addr x%04x\n",addr));
    476         return (_error(ERR_CODE_INVALID_RAM_ADDR));
    477     }
    478     return (merlin16_wrw_uc_ram(sa__, addr, wr_val));          /* Use Micro register interface for writing RAM */
    479 }
    480 
    481 
    482 /***********************/
    483 /*  Event Log Display  */
    484 /***********************/
    485 err_code_t merlin16_INTERNAL_event_log_dump_callback(void *arg, uint8_t byte_count, uint16_t data) {
    486     merlin16_INTERNAL_event_log_dump_state_t * const state_ptr = (merlin16_INTERNAL_event_log_dump_state_t *)arg;
    487     const uint8_t bytes_per_row=16;
    488 
    489     if (byte_count == 0) {
    490         if (state_ptr->line_start_index != state_ptr->index) {
    491             EFUN_PRINTF(("%*s    %d\n", 4*(bytes_per_row - state_ptr->index + state_ptr->line_start_index), "", state_ptr->line_start_index));
    492         }
    493         return (ERR_CODE_NONE);
    494     }
    495     if (byte_count == 1) {
    496         /* There is a trailing byte in the event log.
    497          * The simplest way to handle it is to print out a whole word, but mask
    498          * the invalid upper byte.
    499          */
    500         data &= 0xFF;
    501     }
    502     EFUN_PRINTF(("  0x%04x", ((data & 0xFF) << 8) | (data >> 8)));
    503     state_ptr->index += 2;
    504     if (state_ptr->index % bytes_per_row == 0) {
    505         EFUN_PRINTF(("    %d\n", state_ptr->line_start_index));
    506         state_ptr->line_start_index = state_ptr->index;
    507     }
    508 
    509     return(ERR_CODE_NONE);
    510 }
    511 
    512 err_code_t merlin16_INTERNAL_read_event_log_with_callback(srds_access_t *sa__,
    513                                                         uint8_t micro_num,
    514                                                         uint8_t bypass_micro,
    515                                                         void *arg,
    516                                                         err_code_t (*callback)(void *, uint8_t, uint16_t)) {
    517     merlin16_info_t const * const merlin16_info_ptr = merlin16_INTERNAL_get_merlin16_info_ptr();
    518     uint16_t rd_idx;
    519     uint8_t current_lane;
    520 
    521     EFUN(merlin16_INTERNAL_verify_merlin16_info(merlin16_info_ptr, sa__));
    522 
    523     if (micro_num >= merlin16_info_ptr->micro_count) {
    524         return (_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    525     }
    526     /* Read Current lane so that it can be restored at the end of function */
    527     current_lane = merlin16_get_lane(sa__);
    528     EFUN_PRINTF(("\n\n********************************************\n"));
    529     EFUN_PRINTF((    "**** SERDES UC TRACE MEMORY DUMP ***********\n"));
    530     EFUN_PRINTF((    "********************************************\n"));
    531 
    532     if (bypass_micro) {
    533         ESTM(rd_idx = rdcv_trace_mem_wr_idx());
    534         if (merlin16_info_ptr->trace_memory_descending_writes) {
    535             ++rd_idx;
    536             if (rd_idx >= merlin16_info_ptr->trace_mem_ram_size) {
    537                 rd_idx = 0;
    538             }
    539         } else {
    540             if (rd_idx == 0) {
    541                 rd_idx = merlin16_info_ptr->trace_mem_ram_size;
    542             }
    543             --rd_idx;
    544         }
    545     } else {
    546         /* Start Read to stop uC logging and read the word at last event written by uC */
    547         EFUN(merlin16_pmd_uc_cmd(sa__, CMD_EVENT_LOG_READ, CMD_EVENT_LOG_READ_START, GRACEFUL_STOP_TIME));
    548         ESTM(rd_idx = rdcv_trace_mem_rd_idx());
    549     }
    550     
    551     EFUN_PRINTF(( "\n  DEBUG INFO: trace memory read index = 0x%04x\n", rd_idx));
    552     
    553     EFUN_PRINTF(("  DEBUG INFO: trace memory size = 0x%04x\n\n", merlin16_info_ptr->trace_mem_ram_size));
    554 
    555     if (merlin16_info_ptr->trace_memory_descending_writes) {
    556         /* Micro writes trace memory using descending addresses.
    557          * So read using ascending addresses using block read
    558          */
    559         EFUN(merlin16_INTERNAL_rdblk_uc_generic_ram(sa__,
    560                                                   merlin16_info_ptr->trace_mem_ram_base + merlin16_info_ptr->grp_ram_size*micro_num,
    561                                                   merlin16_info_ptr->trace_mem_ram_size,
    562                                                   rd_idx,
    563                                                   merlin16_info_ptr->trace_mem_ram_size,
    564                                                   arg,
    565                                                   callback));
    566     } else {
    567         /* Micro writes trace memory using descending addresses.
    568          * So read using ascending addresses using block read
    569          */
    570         EFUN(merlin16_INTERNAL_rdblk_uc_generic_ram_descending(sa__,
    571                                                              merlin16_info_ptr->trace_mem_ram_base + merlin16_info_ptr->grp_ram_size*micro_num,
    572                                                              merlin16_info_ptr->trace_mem_ram_size,
    573                                                              rd_idx,
    574                                                              merlin16_info_ptr->trace_mem_ram_size,
    575                                                              arg,
    576                                                              callback));
    577     }
    578 
    579     if (!bypass_micro) {
    580         /* Read Done to resume logging  */
    581         EFUN(merlin16_pmd_uc_cmd(sa__, CMD_EVENT_LOG_READ, CMD_EVENT_LOG_READ_DONE, 50));
    582     }
    583     EFUN(merlin16_set_lane(sa__,current_lane));
    584     return(ERR_CODE_NONE);
    585 }
    586 
    587 #ifdef TO_FLOATS
    588 /* convert uint32_t to float8 */
    589 float8_t merlin16_INTERNAL_int32_to_float8(uint32_t input) {
    590     int8_t cnt;
    591     uint8_t output;
    592     
    593     if(input == 0) {
    594       return(0);
    595     } else if(input == 1) {
    596       return(0xe0);
    597     } else {
    598       cnt = 0;
    599       input = input & 0x7FFFFFFF; /* get rid of MSB which may be lock indicator */
    600       do {
    601         input = input << 1;
    602         cnt++;
    603       } while ((input & 0x80000000) == 0);
    604     
    605       output = (uint8_t)((input & 0x70000000)>>23)+(31 - cnt%32);
    606       return(output);
    607     }
    608 }
    609 #endif
    610 
    611 /* convert float8 to uint32_t */
    612 uint32_t merlin16_INTERNAL_float8_to_int32(float8_t input) {
    613     uint32_t x;
    614     if(input == 0) return(0);
    615     x = (input>>5) + 8;
    616     if((input & 0x1F) < 3) {
    617       return(x>>(3-(input & 0x1f)));
    618     } 
    619     return(x<<((input & 0x1F)-3));
    620 }
    621 
    622 
    623 
    624 /* convert float12 to uint32 */
    625 uint32_t merlin16_INTERNAL_float12_to_uint32(uint8_t byte, uint8_t multi) {
    626 
    627     return(((uint32_t)byte)<<multi);
    628 }
    629 
    630 #ifdef TO_FLOATS
    631 /* convert uint32 to float12 */
    632 uint8_t merlin16_INTERNAL_uint32_to_float12(uint32_t input, uint8_t *multi) {
    633     int8_t cnt;
    634     uint8_t output;
    635     if(!multi) {
    636       return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    637     }
    638     
    639     if((input == 0) || (!multi)) {
    640       *multi = 0;
    641       return(0);
    642     } else {
    643       cnt = 0;
    644       if(input > 0x007FFFFF) input = 0x007FFFFF; /* limit to 23bits so multi is 4 bits */
    645       do {
    646         input = input << 1;
    647         cnt++;
    648       } while ((input & 0x80000000) == 0);
    649       
    650       *multi = (31 - (cnt%32));
    651       if(*multi < 8) {
    652         output = (uint8_t)((input & 0xFF000000)>>(24 + (7-*multi)));
    653         *multi = 0;
    654       } else {
    655         output = (uint8_t)((input & 0xFF000000)>>24);
    656         *multi = *multi - 7;
    657       }
    658       return(output);
    659     }
    660 }
    661 #endif
    662 
    663 err_code_t merlin16_INTERNAL_set_rx_pf_main(srds_access_t *sa__, uint8_t val) {
    664     if (val > 15) {
    665       return (_error(ERR_CODE_PF_INVALID));
    666     }
    667     EFUN(WR_RX_PF_CTRL(val));
    668     return(ERR_CODE_NONE); 
    669 }
    670 
    671 err_code_t merlin16_INTERNAL_get_rx_pf_main(srds_access_t *sa__, int8_t *val) {
    672     ESTM(*val = (int8_t)RD_RX_PF_CTRL());
    673     return (ERR_CODE_NONE);
    674 }
    675 
    676 err_code_t merlin16_INTERNAL_set_rx_pf2(srds_access_t *sa__, uint8_t val) {
    677     if (val > 7) {
    678       return (_error(ERR_CODE_PF_INVALID));
    679     }
    680     EFUN(WR_RX_PF2_CTRL(val));
    681     return(ERR_CODE_NONE); 
    682 }
    683 
    684 err_code_t merlin16_INTERNAL_get_rx_pf2(srds_access_t *sa__, int8_t *val) {
    685     ESTM(*val = (int8_t)RD_RX_PF2_CTRL());
    686     return (ERR_CODE_NONE);
    687 }
    688 
    689 
    690 err_code_t merlin16_INTERNAL_set_rx_vga(srds_access_t *sa__, uint8_t val) {
    691 
    692     EFUN(merlin16_INTERNAL_check_uc_lane_stopped(sa__));  /* make sure uC is stopped to avoid race conditions */
    693 
    694     if (val > RX_VGA_CTRL_VAL_MAX) {
    695       return (_error(ERR_CODE_VGA_INVALID));
    696     }
    697 #if defined(RX_VGA_CTRL_VAL_MIN) && (RX_VGA_CTRL_VAL_MIN > 0)
    698     if (val < RX_VGA_CTRL_VAL_MIN) {
    699       return (_error(ERR_CODE_VGA_INVALID));
    700     } 
    701 #endif
    702     
    703     EFUN(wr_hwtune_ovr_write_sel(0));                   /* Configure hwtune_ovr_write_sel to VGA */
    704     EFUN(wr_hwtune_ovr_write_val(val<<3));              /* hwtune_ovr_write_val[8:3] are used to drive the analog control port */
    705     EFUN(wr_hwtune_ovr_write_en(1));
    706     return(ERR_CODE_NONE); 
    707 }
    708 
    709 err_code_t merlin16_INTERNAL_get_rx_vga(srds_access_t *sa__, int8_t *val) {
    710     ESTM(*val = (int8_t)rd_vga_bin());
    711     return (ERR_CODE_NONE);
    712 }
    713 
    714 
    715 err_code_t merlin16_INTERNAL_set_rx_dfe1(srds_access_t *sa__, int8_t val) {
    716     EFUN(merlin16_INTERNAL_check_uc_lane_stopped(sa__));  /* make sure uC is stopped to avoid race conditions */
    717 
    718     {
    719         int8_t tap_eo;
    720 
    721         if (val > 63) {
    722             return (_error(ERR_CODE_DFE1_INVALID));  
    723         }
    724         /* Compute tap1 even/odd component */
    725         tap_eo = 0;                                      /* Not supporting dfe_dcd values */
    726         EFUN(wr_hwtune_ovr_write_sel(2));                /* Write tap1_odd */
    727         EFUN(wr_hwtune_ovr_write_val(tap_eo));
    728         EFUN(wr_hwtune_ovr_write_en(1));
    729         EFUN(wr_hwtune_ovr_write_sel(3));                /* Write tap1_even */
    730         EFUN(wr_hwtune_ovr_write_val(tap_eo));
    731         EFUN(wr_hwtune_ovr_write_en(1));
    732         EFUN(wr_hwtune_ovr_write_sel(1));
    733         EFUN(wr_hwtune_ovr_write_val(val-tap_eo));       /* Write the common tap */
    734         EFUN(wr_hwtune_ovr_write_en(1));
    735     }
    736     return(ERR_CODE_NONE); 
    737 }
    738 err_code_t merlin16_INTERNAL_get_rx_dfe1(srds_access_t *sa__, int8_t *val) {
    739     ESTM(*val = (int8_t)(rd_dfe_1_e() + rd_dfe_1_cmn()));
    740     return (ERR_CODE_NONE);
    741 }
    742 
    743 
    744 err_code_t merlin16_INTERNAL_set_rx_dfe2(srds_access_t *sa__, int8_t val) {
    745     int8_t tap_eo;
    746 
    747     if ((val > 31) || (val < -31)) {
    748       return (_error(ERR_CODE_DFE2_INVALID));  
    749     }
    750 
    751     EFUN(merlin16_INTERNAL_check_uc_lane_stopped(sa__));  /* make sure uC is stopped to avoid race conditions */
    752 
    753     /* Compute tap2 odd/even component */
    754     tap_eo = 0;                                         /* Not supporting dfe_dcd values */
    755     EFUN(wr_hwtune_ovr_write_sel(5));                   /* Write tap2_odd */
    756     EFUN(wr_hwtune_ovr_write_val(tap_eo));
    757     EFUN(wr_hwtune_ovr_write_en(1));
    758     EFUN(wr_hwtune_ovr_write_sel(6));                   /* Write tap2_even */
    759     EFUN(wr_hwtune_ovr_write_val(tap_eo));
    760     EFUN(wr_hwtune_ovr_write_en(1));
    761     EFUN(wr_hwtune_ovr_write_sel(4));
    762     EFUN(wr_hwtune_ovr_write_val(SRDS_ABS(val)-tap_eo));/* Write the common tap */
    763     EFUN(wr_hwtune_ovr_write_en(1));
    764     EFUN(wr_hwtune_ovr_write_sel(10));                  /* Write tap2_even_sign */
    765     EFUN(wr_hwtune_ovr_write_val(val<0?1:0));
    766     EFUN(wr_hwtune_ovr_write_en(1));
    767     EFUN(wr_hwtune_ovr_write_sel(11));                  /* Write tap2_odd_sign */
    768     EFUN(wr_hwtune_ovr_write_val(val<0?1:0));
    769     EFUN(wr_hwtune_ovr_write_en(1));
    770     return(ERR_CODE_NONE); 
    771 }
    772 
    773 err_code_t merlin16_INTERNAL_get_rx_dfe2(srds_access_t *sa__, int8_t *val) {
    774     ESTM(*val = rd_dfe_2_se() ? -(rd_dfe_2_e()+rd_dfe_2_cmn()) : (rd_dfe_2_e()+rd_dfe_2_cmn()));
    775     return (ERR_CODE_NONE);
    776 }
    777 
    778 err_code_t merlin16_INTERNAL_set_rx_dfe3(srds_access_t *sa__, int8_t val) {
    779     if ((val > 31) || (val < -31)) {
    780       return (_error(ERR_CODE_DFE3_INVALID));  
    781     }
    782 
    783     EFUN(merlin16_INTERNAL_check_uc_lane_stopped(sa__));  /* make sure uC is stopped to avoid race conditions */
    784 
    785     EFUN(wr_hwtune_ovr_write_sel(7));                   /* Write tap3 */
    786     EFUN(wr_hwtune_ovr_write_val(val));
    787     EFUN(wr_hwtune_ovr_write_en(1));
    788     return(ERR_CODE_NONE); 
    789 }
    790 
    791 err_code_t merlin16_INTERNAL_get_rx_dfe3(srds_access_t *sa__, int8_t *val) {
    792     ESTM(*val = rd_dfe_3_cmn());
    793     return (ERR_CODE_NONE);
    794 }
    795 
    796 err_code_t merlin16_INTERNAL_set_rx_dfe4(srds_access_t *sa__, int8_t val) {
    797     if ((val > 15) || (val < -15)) {
    798       return (_error(ERR_CODE_DFE4_INVALID));  
    799     }
    800 
    801     EFUN(merlin16_INTERNAL_check_uc_lane_stopped(sa__));  /* make sure uC is stopped to avoid race conditions */
    802     
    803     EFUN(wr_hwtune_ovr_write_sel(8));                   /* Write tap4 */
    804     EFUN(wr_hwtune_ovr_write_val(val));
    805     EFUN(wr_hwtune_ovr_write_en(1));
    806     return(ERR_CODE_NONE); 
    807 }
    808 
    809 err_code_t merlin16_INTERNAL_get_rx_dfe4(srds_access_t *sa__, int8_t *val) {
    810     ESTM(*val = rd_dfe_4_cmn());
    811     return (ERR_CODE_NONE);
    812 }
    813 
    814 err_code_t merlin16_INTERNAL_set_rx_dfe5(srds_access_t *sa__, int8_t val) {
    815     if ((val > 15) || (val < -15)) {
    816       return (_error(ERR_CODE_DFE5_INVALID));  
    817     }
    818 
    819     EFUN(merlin16_INTERNAL_check_uc_lane_stopped(sa__));  /* make sure uC is stopped to avoid race conditions */
    820     
    821     EFUN(wr_hwtune_ovr_write_sel(9));                   /* Write tap5 */
    822     EFUN(wr_hwtune_ovr_write_val(val));
    823     EFUN(wr_hwtune_ovr_write_en(1));
    824     return(ERR_CODE_NONE); 
    825 }
    826 
    827 err_code_t merlin16_INTERNAL_get_rx_dfe5(srds_access_t *sa__, int8_t *val) {
    828     ESTM(*val = rd_dfe_5_cmn());
    829     return (ERR_CODE_NONE);
    830 }
    831 
    832 
    833 
    834 
    835 
    836 err_code_t merlin16_INTERNAL_get_tx_pre(srds_access_t *sa__, int8_t *val) {
    837   ESTM(*val = rd_cl72_txfir_pre());
    838   return (ERR_CODE_NONE);
    839 }
    840 
    841 
    842 err_code_t merlin16_INTERNAL_get_tx_main(srds_access_t *sa__, int8_t *val) {
    843   ESTM(*val = rd_cl72_txfir_main());
    844   return (ERR_CODE_NONE);
    845 }
    846 
    847 
    848 err_code_t merlin16_INTERNAL_get_tx_post1(srds_access_t *sa__, int8_t *val) {
    849   ESTM(*val = rd_cl72_txfir_post());
    850   return (ERR_CODE_NONE);
    851 }
    852 
    853 
    854 err_code_t merlin16_INTERNAL_get_tx_post2(srds_access_t *sa__, int8_t *val) {
    855   ESTM(*val = rd_txfir_post2());
    856   return (ERR_CODE_NONE);
    857 }
    858 
    859 
    860 
    861 err_code_t merlin16_INTERNAL_core_clkgate(srds_access_t *sa__, uint8_t enable) {
    862 
    863   if (enable) {
    864   }
    865   else {
    866   }
    867   return (ERR_CODE_NONE);
    868 }
    869 
    870 err_code_t merlin16_INTERNAL_lane_clkgate(srds_access_t *sa__, uint8_t enable) {
    871 
    872   if (enable) {
    873     /* Use frc/frc_val to force all RX and TX clk_vld signals to 0 */
    874         EFUN(wr_pmd_rx_clk_vld_frc_val(0x0));
    875         EFUN(wr_pmd_rx_clk_vld_frc(0x1));
    876         EFUN(wr_pmd_tx_clk_vld_frc_val(0x0));
    877         EFUN(wr_pmd_tx_clk_vld_frc(0x1));
    878 
    879     /* Use frc_on to force clkgate */
    880         EFUN(wr_ln_rx_s_clkgate_frc_on(0x1));
    881 
    882         EFUN(wr_ln_tx_s_clkgate_frc_on(0x1));
    883 
    884   }
    885   else {
    886         EFUN(wr_pmd_rx_clk_vld_frc_val(0x0));
    887         EFUN(wr_pmd_rx_clk_vld_frc(0x0));
    888         EFUN(wr_pmd_tx_clk_vld_frc_val(0x0));
    889         EFUN(wr_pmd_tx_clk_vld_frc(0x0));
    890 
    891         EFUN(wr_ln_rx_s_clkgate_frc_on(0x0));
    892 
    893         EFUN(wr_ln_tx_s_clkgate_frc_on(0x0));
    894   }
    895   return (ERR_CODE_NONE);
    896 }
    897 
    898 /*-----------------------------------------------*/
    899 /*  Get dynamic eye margin estimation values     */
    900 /*-----------------------------------------------*/
    901 err_code_t merlin16_INTERNAL_get_eye_margin_est(srds_access_t *sa__, uint16_t *left_eye_mUI, uint16_t *right_eye_mUI, uint16_t  *upper_eye_mV, uint16_t *lower_eye_mV) {
    902   uint8_t ladder_range = 0;
    903   ESTM(ladder_range = rd_p1_thresh_sel());
    904   ESTM(*left_eye_mUI  = merlin16_INTERNAL_eye_to_mUI(sa__, rdv_usr_sts_heye_left()));
    905   ESTM(*right_eye_mUI = merlin16_INTERNAL_eye_to_mUI(sa__, rdv_usr_sts_heye_right()));
    906   ESTM(*upper_eye_mV = merlin16_INTERNAL_eye_to_mV(sa__, rdv_usr_sts_veye_upper(), ladder_range));
    907   ESTM(*lower_eye_mV = merlin16_INTERNAL_eye_to_mV(sa__, rdv_usr_sts_veye_lower(), ladder_range));
    908 
    909   return (ERR_CODE_NONE);
    910 }
    911 
    912 uint16_t merlin16_INTERNAL_eye_to_mUI(srds_access_t *sa__, uint8_t var) 
    913 {   
    914     /* var is in units of 1/512 th UI, so need to multiply by 1000/512 */
    915     return ((uint16_t)var)*125/64;
    916 }
    917 
    918 
    919 uint16_t merlin16_INTERNAL_eye_to_mV(srds_access_t *sa__, uint8_t var, uint8_t ladder_range) 
    920 {       
    921     /* find nearest two vertical levels */
    922     uint16_t vl = merlin16_INTERNAL_ladder_setting_to_mV(sa__, var/8, ladder_range);    
    923     uint16_t vu = merlin16_INTERNAL_ladder_setting_to_mV(sa__, SRDS_MIN(31,var/8+1), ladder_range);
    924     return (vl + (vu-vl)*(var&7)/8);
    925 }
    926 
    927 err_code_t merlin16_INTERNAL_get_osr_mode(srds_access_t *sa__, merlin16_osr_mode_st *imode) {
    928     merlin16_osr_mode_st mode;
    929 
    930      ENULL_MEMSET(&mode, 0, sizeof(merlin16_osr_mode_st));
    931 
    932     if(!imode) 
    933         return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
    934 
    935   ESTM(mode.tx = rd_tx_osr_mode());
    936   ESTM(mode.rx = rd_rx_osr_mode());
    937   mode.tx_rx = 255;
    938 #ifdef wr_ams_rx_rxclk_div2p5    /* Analog 2p5 OSR mode */
    939   {
    940       uint8_t osr_2p5, osr_2p5_pwrup;
    941       ESTM(osr_2p5       = rd_ams_tx_txclk_div2p5());
    942       ESTM(osr_2p5_pwrup = rd_ams_tx_spare_58());
    943       if ((mode.tx == MERLIN16_OSX1) && (osr_2p5 == 1)  && (osr_2p5_pwrup == 1)) {
    944           mode.tx = MERLIN16_OSX2P5;
    945       }
    946       ESTM(osr_2p5       = rd_ams_rx_rxclk_div2p5());
    947       ESTM(osr_2p5_pwrup = rd_ams_rx_spare_134());
    948       if ((mode.rx == MERLIN16_OSX1) && (osr_2p5 == 1)  && (osr_2p5_pwrup == 1)) {
    949           mode.rx = MERLIN16_OSX2P5;
    950       }
    951   }
    952 #endif
    953   *imode = mode;
    954   return (ERR_CODE_NONE);
    955 
    956 }
    957 
    958 
    959 err_code_t merlin16_INTERNAL_pmd_lock_status(srds_access_t *sa__, uint8_t *pmd_lock, uint8_t *pmd_lock_chg) {
    960     uint16_t rddata;
    961 #if defined(reg_rd_TLB_RX_RXDBG_PMD_RX_LOCK_STATUS)
    962     ESTM(rddata = reg_rd_TLB_RX_RXDBG_PMD_RX_LOCK_STATUS());
    963     ESTM(*pmd_lock = ex_TLB_RX_RXDBG_PMD_RX_LOCK_STATUS__dbg_pmd_rx_lock(rddata));
    964     ESTM(*pmd_lock_chg = ex_TLB_RX_RXDBG_PMD_RX_LOCK_STATUS__dbg_pmd_rx_lock_change(rddata));
    965 #elif defined(reg_rd_TLB_RX_DBG_PMD_RX_LOCK_STATUS)
    966     ESTM(rddata = reg_rd_TLB_RX_DBG_PMD_RX_LOCK_STATUS());
    967     ESTM(*pmd_lock = ex_TLB_RX_DBG_PMD_RX_LOCK_STATUS__dbg_pmd_rx_lock(rddata));
    968     ESTM(*pmd_lock_chg = ex_TLB_RX_DBG_PMD_RX_LOCK_STATUS__dbg_pmd_rx_lock_change(rddata));
    969 #else
    970 #error "Unknown core for merlin16_INTERNAL_pmd_lock_status()"    
    971 #endif
    972     return(ERR_CODE_NONE);
    973 }
    974 
    975 err_code_t merlin16_INTERNAL_sigdet_status(srds_access_t *sa__, uint8_t *sig_det, uint8_t *sig_det_chg) {
    976     uint16_t rddata;
    977 
    978     ESTM(rddata = reg_rd_SIGDET_SDSTATUS_0());
    979     ESTM(*sig_det = ex_SIGDET_SDSTATUS_0__signal_detect(rddata));
    980     ESTM(*sig_det_chg = ex_SIGDET_SDSTATUS_0__signal_detect_change(rddata));
    981     return(ERR_CODE_NONE);
    982 }
    983 
    984 err_code_t merlin16_INTERNAL_pll_lock_status(srds_access_t *sa__, uint8_t *pll_lock, uint8_t *pll_lock_chg) {
    985 
    986     uint16_t rddata;
    987     uint8_t pll_fail;
    988     ESTM(rddata = reg_rdc_PLL_CAL_COM_STS_0());
    989     ESTM(*pll_lock = exc_PLL_CAL_COM_STS_0__pll_lock(rddata));
    990     ESTM(pll_fail = exc_PLL_CAL_COM_STS_0__pll_fail_stky(rddata));
    991     ESTM(*pll_lock_chg = ((*pll_lock ^ !exc_PLL_CAL_COM_STS_0__pll_lock_bar_stky(rddata)) | (*pll_lock ^ !pll_fail)));
    992     return(ERR_CODE_NONE);
    993 }
    994 
    995 err_code_t merlin16_INTERNAL_read_lane_state(srds_access_t *sa__, merlin16_lane_state_st *istate) {
    996        
    997   merlin16_lane_state_st state;
    998   uint8_t ladder_range = 0;
    999 
   1000   ENULL_MEMSET(&state, 0, sizeof(merlin16_lane_state_st));
   1001 
   1002   if(!istate) 
   1003     return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
   1004 
   1005   EFUN(merlin16_INTERNAL_pmd_lock_status(sa__,&state.rx_lock, &state.rx_lock_chg));
   1006   {
   1007       err_code_t err_code = 0;
   1008       state.stop_state = merlin16_INTERNAL_stop_micro(sa__,state.rx_lock,&err_code);
   1009       if(err_code) USR_PRINTF(("Unable to stop microcontroller,  following data is suspect\n"));
   1010   }
   1011 
   1012   {  merlin16_osr_mode_st osr_mode;
   1013   ENULL_MEMSET(&osr_mode, 0, sizeof(merlin16_osr_mode_st));
   1014   EFUN(merlin16_INTERNAL_get_osr_mode(sa__, &osr_mode));
   1015   state.osr_mode = osr_mode;
   1016   }
   1017   {
   1018       struct merlin16_uc_lane_config_st lane_cfg;
   1019       EFUN(merlin16_get_uc_lane_cfg(sa__, &lane_cfg));
   1020       state.ucv_config = lane_cfg.word;
   1021   }
   1022   ESTM(state.ucv_status = rdv_status_byte());
   1023   ESTM(state.reset_state    = rd_rx_lane_dp_reset_state());
   1024   ESTM(state.tx_reset_state = rd_tx_lane_dp_reset_state());
   1025   EFUN(merlin16_INTERNAL_sigdet_status(sa__,&state.sig_det, &state.sig_det_chg));
   1026   ESTM(state.rx_ppm = rd_cdr_integ_reg()/84);
   1027   ESTM(state.clk90 = rd_cnt_d_minus_m1());
   1028   ESTM(state.clkp1 = rd_cnt_d_minus_p1());
   1029   ESTM(state.br_pd_en = rd_br_pd_en());
   1030   /* drop the MSB, the result is actually valid modulo 128 */
   1031   /* Also flip the sign to account for d-m1, versus m1-d */
   1032   state.clk90 = state.clk90<<1;
   1033   state.clk90 = -(state.clk90>>1);
   1034   state.clkp1 = state.clkp1<<1;
   1035   state.clkp1 = -(state.clkp1>>1);
   1036   
   1037   EFUN(merlin16_INTERNAL_get_rx_pf_main(sa__, &state.pf_main));
   1038   ESTM(state.pf_hiz = rd_pf_hiz());
   1039   ESTM(state.pf2_ctrl = rd_pf2_lowp_ctrl());
   1040   EFUN(merlin16_INTERNAL_get_rx_vga(sa__, &state.vga));
   1041   ESTM(state.dc_offset = rd_dc_offset_bin());
   1042   ESTM(ladder_range = rd_p1_thresh_sel());
   1043   EFUN(merlin16_INTERNAL_get_p1_threshold(sa__, &state.p1_lvl_ctrl));         
   1044   state.p1_lvl = merlin16_INTERNAL_ladder_setting_to_mV(sa__, state.p1_lvl_ctrl, ladder_range);
   1045   state.m1_lvl = 0;
   1046 
   1047   EFUN(merlin16_INTERNAL_get_rx_dfe1(sa__, &state.dfe1));
   1048   EFUN(merlin16_INTERNAL_get_rx_dfe2(sa__, &state.dfe2));  
   1049   EFUN(merlin16_INTERNAL_get_rx_dfe3(sa__, &state.dfe3));  
   1050   EFUN(merlin16_INTERNAL_get_rx_dfe4(sa__, &state.dfe4));
   1051   EFUN(merlin16_INTERNAL_get_rx_dfe5(sa__, &state.dfe5));
   1052 
   1053   ESTM(state.dfe1_dcd = rd_dfe_1_e()-rd_dfe_1_o());
   1054   ESTM(state.dfe2_dcd = (rd_dfe_2_se() ? -rd_dfe_2_e(): rd_dfe_2_e()) -(rd_dfe_2_so() ? -rd_dfe_2_o(): rd_dfe_2_o()));
   1055   ESTM(state.pe = rd_p1_offset_evn_bin());
   1056   ESTM(state.ze = rd_data_offset_evn_bin());
   1057   ESTM(state.me = rd_m1_offset_evn_bin());
   1058   
   1059   ESTM(state.po = rd_p1_offset_odd_bin());
   1060   ESTM(state.zo = rd_data_offset_odd_bin());
   1061   ESTM(state.mo = rd_m1_offset_odd_bin());
   1062 
   1063   /* tx_ppm = register/10.84 */
   1064   ESTM(state.tx_ppm = (int16_t)(((int32_t)(rd_tx_pi_integ2_reg()))*3125/32768));
   1065 
   1066   EFUN(merlin16_INTERNAL_get_tx_pre(sa__, &state.txfir_pre));
   1067   EFUN(merlin16_INTERNAL_get_tx_main(sa__, &state.txfir_main));
   1068   EFUN(merlin16_INTERNAL_get_tx_post1(sa__, &state.txfir_post1));
   1069   EFUN(merlin16_INTERNAL_get_tx_post2(sa__, &state.txfir_post2));
   1070   EFUN(merlin16_INTERNAL_get_eye_margin_est(sa__, &state.heye_left, &state.heye_right, &state.veye_upper, &state.veye_lower));
   1071  
   1072   ESTM(state.soc_pos = rd_ams_rx_sigdet_offset_correction_pos());
   1073   ESTM(state.soc_neg = rd_ams_rx_sigdet_offset_correction_neg());
   1074   ESTM(state.link_time = (((uint32_t)rdv_usr_sts_link_time())*8)/10);     /* convert from 80us to 0.1 ms units */
   1075   {
   1076       /* read lock status at end and combine them to handle transient cases */
   1077       uint8_t rx_lock_at_end=0, rx_lock_chg_at_end=0;
   1078       EFUN(merlin16_INTERNAL_pmd_lock_status(sa__,&rx_lock_at_end, &rx_lock_chg_at_end));
   1079       if (state.rx_lock != rx_lock_at_end) {
   1080           USR_PRINTF(("rx_lock has chnaged while reading the lane state rx_lock_start=%d, rx_lock_chg_start=%d, rx_lock_at_end=%d, rx_lock_chg_at_end=%d\n",
   1081                       state.rx_lock,
   1082                       state.rx_lock_chg,
   1083                       rx_lock_at_end,
   1084                       rx_lock_chg_at_end));
   1085       }
   1086       state.rx_lock &= rx_lock_at_end;
   1087       state.rx_lock_chg |= rx_lock_chg_at_end;
   1088   }
   1089 
   1090   if (!state.stop_state) {
   1091       EFUN(merlin16_stop_rx_adaptation(sa__, 0));
   1092   } 
   1093 
   1094   *istate = state;
   1095 
   1096 
   1097   return (ERR_CODE_NONE);
   1098 }
   1099 
   1100 err_code_t merlin16_INTERNAL_display_lane_state_no_newline(srds_access_t *sa__) {     
   1101   uint16_t lane_idx;
   1102   merlin16_lane_state_st state;
   1103 
   1104   const char* e2s_osr_mode_enum[10] = {
   1105     "x1   ",
   1106     "x2   ",
   1107     "x3   ",
   1108     "x3.3 ",
   1109     "x4   ",
   1110     "x5   ",
   1111     "x7.5 ",
   1112     "x8   ",
   1113     "x8.25",
   1114     "x10  "
   1115   };
   1116 
   1117   const char* e2s_tx_osr_mode_enum[10] = {
   1118     "x1",
   1119     "x2",
   1120     "x3",
   1121     "xT",
   1122     "x4",
   1123     "x5",
   1124     "x7",
   1125     "x8",
   1126     "x9",
   1127     "xA"
   1128   };
   1129 
   1130 
   1131   ENULL_MEMSET(&state, 0, sizeof(merlin16_lane_state_st));
   1132 
   1133   EFUN(merlin16_INTERNAL_read_lane_state(sa__, &state));
   1134  
   1135   lane_idx = merlin16_get_lane(sa__); 
   1136   EFUN_PRINTF(("%2d ", lane_idx));
   1137   if(state.osr_mode.tx_rx != 255) {
   1138       char *s;
   1139       s = (char *)e2s_osr_mode_enum[state.osr_mode.tx_rx];
   1140       EFUN_PRINTF(("(%2s%s, 0x%04x, 0x%02x ,", (state.br_pd_en) ? "BR" : "OS", s, state.ucv_config,state.ucv_status));
   1141   } else {
   1142       char *s;
   1143       char *r;
   1144       s = (char *)e2s_tx_osr_mode_enum[state.osr_mode.tx];
   1145       r = (char *)e2s_tx_osr_mode_enum[state.osr_mode.rx];
   1146       EFUN_PRINTF(("(%2s%s:%s, 0x%04x, 0x%02x ,", (state.br_pd_en) ? "BR" : "OS", s,r, state.ucv_config,state.ucv_status));
   1147   }
   1148   EFUN_PRINTF(("   %01x,%01x,    %01x)",state.tx_reset_state,state.reset_state,state.stop_state));
   1149   EFUN_PRINTF(("  %1d%s", state.sig_det, state.sig_det_chg ? "*" : " "));
   1150   EFUN_PRINTF(("  %1d%s", state.rx_lock, state.rx_lock_chg ? "*" : " "));
   1151   EFUN_PRINTF(("%4d ", state.rx_ppm));
   1152   EFUN_PRINTF(("  %3d ", state.clk90));
   1153   EFUN_PRINTF(("  %3d ", state.clkp1));
   1154   EFUN_PRINTF(("   %2d,%1d ", state.pf_main, state.pf2_ctrl));
   1155   EFUN_PRINTF(("  %2d ", state.vga));
   1156   EFUN_PRINTF(("%3d  ", state.dc_offset));
   1157   EFUN_PRINTF(("%3d ", state.p1_lvl));
   1158   EFUN_PRINTF(("%3d,%3d,%3d,%3d,%3d,%3d,%3d ", state.dfe1, state.dfe2, state.dfe3, state.dfe4, state.dfe5, state.dfe1_dcd, state.dfe2_dcd));
   1159   EFUN_PRINTF(("%3d,%3d,%3d,%3d,%3d,%3d  ", state.ze, state.zo, state.pe, state.po, state.me, state.mo));
   1160   EFUN_PRINTF(("  %4d ", state.tx_ppm));
   1161   EFUN_PRINTF(("   %2d,%2d,%2d,%2d  ", state.txfir_pre, state.txfir_main, state.txfir_post1, state.txfir_post2));
   1162   EFUN_PRINTF((" %3d,%3d,%3d,%3d ", state.heye_left, state.heye_right, state.veye_upper, state.veye_lower));
   1163   EFUN_PRINTF((" %2d,%2d  ", state.soc_pos, state.soc_neg));
   1164   /* Check to see if link_time is max value after 80us to 0.1msec unit conversion */
   1165   if (state.link_time == 0xCCCC) {
   1166       EFUN_PRINTF((" >%4d.%01d", state.link_time/10, state.link_time%10));
   1167       EFUN_PRINTF(("  "));  
   1168   } else {
   1169       EFUN_PRINTF((" %4d.%01d", state.link_time/10, state.link_time%10));
   1170       EFUN_PRINTF(("   "));  
   1171   }
   1172   EFUN(merlin16_INTERNAL_display_BER(sa__,100));
   1173   
   1174   return (ERR_CODE_NONE);
   1175 }
   1176 
   1177 
   1178 err_code_t merlin16_INTERNAL_read_core_state(srds_access_t *sa__, merlin16_core_state_st *istate) {  
   1179   merlin16_core_state_st state;
   1180   struct merlin16_uc_core_config_st core_cfg;
   1181 
   1182   ENULL_MEMSET(&state, 0, sizeof(merlin16_core_state_st));
   1183   ENULL_MEMSET(&core_cfg, 0, sizeof(struct merlin16_uc_core_config_st));
   1184 
   1185   if(!istate) 
   1186     return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
   1187   EFUN(merlin16_get_uc_core_config(sa__, &core_cfg));
   1188   /* pllpon_mux is read in case the rescal value is overriden. */
   1189   ESTM(state.rescal = rdc_pllpon_mux());
   1190   ESTM(state.core_reset           = rdc_core_dp_reset_state());
   1191   ESTM(state.uc_active            = rdc_uc_active());
   1192   ESTM(state.comclk_mhz           = rdc_heartbeat_count_1us());   
   1193   ESTM(state.pll_pwrdn            = rdc_pll_pwrdn_or());
   1194   ESTM(state.ucode_version        = rdcv_common_ucode_version()); 
   1195   ESTM(merlin16_version(&state.api_version));
   1196   ESTM(state.ucode_minor_version  = rdcv_common_ucode_minor_version());
   1197   ESTM(state.afe_hardware_version = rdcv_afe_hardware_version());
   1198   ESTM(state.temp_idx             = rdcv_temp_idx());
   1199   {  int16_t                           die_temp = 0;
   1200      EFUN(merlin16_read_die_temperature(sa__, &die_temp));
   1201      state.die_temp               =    die_temp;
   1202   }
   1203   ESTM(state.avg_tmon             = _bin_to_degC(rdcv_avg_tmon_reg13bit()>>3));
   1204   state.vco_rate_mhz            = (uint16_t)core_cfg.vco_rate_in_Mhz;
   1205   ESTM(state.analog_vco_range     = rdc_pll_range());   
   1206   EFUN(merlin16_INTERNAL_read_pll_div(sa__, &state.pll_div));
   1207   EFUN(merlin16_INTERNAL_pll_lock_status(sa__, &state.pll_lock, &state.pll_lock_chg));
   1208   ESTM(state.core_status          = rdcv_status_byte());
   1209 
   1210   *istate = state;
   1211   return (ERR_CODE_NONE);
   1212 }
   1213 
   1214 
   1215 err_code_t merlin16_INTERNAL_display_core_state_no_newline(srds_access_t *sa__) {
   1216   merlin16_core_state_st state;
   1217     ENULL_MEMSET(&state     , 0, sizeof(state     ));
   1218   EFUN(merlin16_INTERNAL_read_core_state(sa__, &state));
   1219 
   1220     if ((state.avg_tmon<-50)||(state.avg_tmon>135)) {
   1221       EFUN_PRINTF(("\n*** WARNING: Core die temperature (LIVE_TEMP) out of bounds -50C to 130C\n"));
   1222     }
   1223     if ((state.rescal < 6) || (state.rescal > 13)) {
   1224       EFUN_PRINTF(("\n*** WARNING: RESCAL value is out of bounds 6 to 13\n"));
   1225     }
   1226 
   1227     EFUN_PRINTF((" %02d "              ,  merlin16_get_core(sa__)));
   1228     EFUN_PRINTF(("  %x,%02x  "         ,  state.core_reset, state.core_status));
   1229     EFUN_PRINTF(("    %1d     "        ,  state.pll_pwrdn));
   1230     EFUN_PRINTF(("   %1d    "          ,  state.uc_active));
   1231     EFUN_PRINTF((" %3d.%2dMHz"         , (state.comclk_mhz/4),((state.comclk_mhz%4)*25)));    /* comclk in Mhz = heartbeat_count_1us / 4 */
   1232     EFUN_PRINTF(("   %4X_%02X "        ,  state.ucode_version, state.ucode_minor_version));
   1233     EFUN_PRINTF(("  %06X "             , state.api_version));
   1234     EFUN_PRINTF(("    0x%02x   "       ,  state.afe_hardware_version));
   1235     EFUN_PRINTF(("   %3dC   "          ,  state.die_temp));
   1236     EFUN_PRINTF(("   (%02d)%3dC "      ,  state.temp_idx, state.avg_tmon));
   1237     EFUN_PRINTF(("   0x%02x  "         ,  state.rescal));
   1238     EFUN_PRINTF(("  %2d.%03dGHz "      ,  state.vco_rate_mhz/1000, state.vco_rate_mhz % 1000));
   1239     EFUN_PRINTF(("    %03d       "     ,  state.analog_vco_range));
   1240     EFUN(merlin16_INTERNAL_display_pll_to_divider(sa__, state.pll_div));
   1241     EFUN_PRINTF(("     %01d%s  "       ,  state.pll_lock, state.pll_lock_chg ? "*" : " "));
   1242 
   1243 
   1244     return (ERR_CODE_NONE);
   1245   }
   1246 
   1247 
   1248 
   1249 /* returns 000111 (7 = 8-1), for n = 3  */
   1250 #define BFMASK(n) ((1<<((n)))-1)
   1251 
   1252 err_code_t merlin16_INTERNAL_update_uc_lane_config_st(struct  merlin16_uc_lane_config_st *st) {
   1253   uint16_t in = st->word;
   1254   st->field.lane_cfg_from_pcs = in & BFMASK(1); in >>= 1;
   1255   st->field.an_enabled = in & BFMASK(1); in >>= 1;
   1256   st->field.dfe_on = in & BFMASK(1); in >>= 1;
   1257   st->field.force_brdfe_on = in & BFMASK(1); in >>= 1;
   1258   st->field.media_type = in & BFMASK(2); in >>= 2;
   1259   st->field.unreliable_los = in & BFMASK(1); in >>= 1;
   1260   st->field.scrambling_dis = in & BFMASK(1); in >>= 1;  
   1261   st->field.cl72_auto_polarity_en = in & BFMASK(1); in >>= 1;
   1262   st->field.cl72_restart_timeout_en = in & BFMASK(1); in >>= 1;
   1263   st->field.reserved = in & BFMASK(6); in >>= 6;
   1264   return(ERR_CODE_NONE);
   1265 }
   1266 err_code_t merlin16_INTERNAL_update_usr_ctrl_disable_functions_st(struct merlin16_usr_ctrl_disable_functions_st *st) {
   1267   uint8_t in = st->byte;
   1268   st->field.pf_adaptation = in & BFMASK(1); in >>= 1;
   1269   st->field.dc_adaptation = in & BFMASK(1); in >>= 1;
   1270   st->field.vga_adaptation = in & BFMASK(1); in >>= 1;
   1271   st->field.slicer_offset_tuning = in & BFMASK(1); in >>= 1;
   1272   st->field.clk90_offset_adaptation = in & BFMASK(1); in >>= 1;
   1273   st->field.p1_level_tuning = in & BFMASK(1); in >>= 1;
   1274   st->field.eye_adaptation = in & BFMASK(1); in >>= 1;
   1275   st->field.all_adaptation = in & BFMASK(1);
   1276   return ERR_CODE_NONE;
   1277 }
   1278 
   1279 
   1280 err_code_t merlin16_INTERNAL_update_usr_ctrl_disable_dfe_functions_st(struct merlin16_usr_ctrl_disable_dfe_functions_st *st) {
   1281   uint8_t in = st->byte;
   1282   st->field.dfe_tap1_adaptation = in & BFMASK(1); in >>= 1;
   1283   st->field.dfe_tap2_adaptation = in & BFMASK(1); in >>= 1;
   1284   st->field.dfe_tap3_adaptation = in & BFMASK(1); in >>= 1;
   1285   st->field.dfe_tap4_adaptation = in & BFMASK(1); in >>= 1;
   1286   st->field.dfe_tap5_adaptation = in & BFMASK(1); in >>= 1;
   1287   st->field.dfe_tap1_dcd = in & BFMASK(1); in >>= 1;
   1288   st->field.dfe_tap2_dcd = in & BFMASK(1); in >>= 1;
   1289   return ERR_CODE_NONE;
   1290 }
   1291 /* word to fields, for display */
   1292 err_code_t merlin16_INTERNAL_update_uc_core_config_st(struct merlin16_uc_core_config_st *st) {
   1293   uint16_t in = st->word;
   1294   st->field.core_cfg_from_pcs = in & BFMASK(1); in >>= 1;
   1295   st->field.vco_rate = in & BFMASK(5); in >>= 5;
   1296   st->field.an_los_workaround = in & BFMASK(1); in >>= 1;
   1297   st->field.reserved1 = in & BFMASK(1); in >>= 1;
   1298   st->field.reserved2 = in & BFMASK(8);
   1299   st->vco_rate_in_Mhz = VCO_RATE_TO_MHZ(st->field.vco_rate);
   1300   return ERR_CODE_NONE;
   1301 }
   1302 
   1303 /* fields to word, to write into uC RAM */
   1304 err_code_t merlin16_INTERNAL_update_uc_core_config_word(struct merlin16_uc_core_config_st *st) {
   1305   uint16_t in = 0;
   1306   in <<= 8; in |= 0/*st->field.reserved2*/ & BFMASK(8);
   1307   in <<= 1; in |= 0/*st->field.reserved1*/ & BFMASK(1);
   1308   in <<= 1; in |= st->field.an_los_workaround & BFMASK(1);
   1309   in <<= 5; in |= st->field.vco_rate & BFMASK(5);
   1310   in <<= 1; in |= st->field.core_cfg_from_pcs & BFMASK(1);
   1311   st->word = in;
   1312   return ERR_CODE_NONE;
   1313 }
   1314 
   1315 err_code_t merlin16_INTERNAL_update_uc_lane_config_word(struct merlin16_uc_lane_config_st *st) {
   1316   uint16_t in = 0;
   1317   in <<= 6; in |= 0 /*st->field.reserved*/ & BFMASK(6);
   1318   in <<= 1; in |= st->field.cl72_restart_timeout_en & BFMASK(1);
   1319   in <<= 1; in |= st->field.cl72_auto_polarity_en & BFMASK(1);
   1320   in <<= 1; in |= st->field.scrambling_dis & BFMASK(1);
   1321   in <<= 1; in |= st->field.unreliable_los & BFMASK(1);
   1322   in <<= 2; in |= st->field.media_type & BFMASK(2);
   1323   in <<= 1; in |= st->field.force_brdfe_on & BFMASK(1);
   1324   in <<= 1; in |= st->field.dfe_on & BFMASK(1);
   1325   in <<= 1; in |= st->field.an_enabled & BFMASK(1);
   1326   in <<= 1; in |= st->field.lane_cfg_from_pcs & BFMASK(1);
   1327   st->word = in;
   1328   return ERR_CODE_NONE;
   1329 }
   1330 err_code_t merlin16_INTERNAL_update_usr_ctrl_disable_functions_byte(struct merlin16_usr_ctrl_disable_functions_st *st) {
   1331   uint8_t in = 0;
   1332   in <<= 1; in |= st->field.all_adaptation & BFMASK(1);
   1333   in <<= 1; in |= st->field.eye_adaptation & BFMASK(1);
   1334   in <<= 1; in |= st->field.p1_level_tuning & BFMASK(1);
   1335   in <<= 1; in |= st->field.clk90_offset_adaptation & BFMASK(1);
   1336   in <<= 1; in |= st->field.slicer_offset_tuning & BFMASK(1);
   1337   in <<= 1; in |= st->field.vga_adaptation & BFMASK(1);
   1338   in <<= 1; in |= st->field.dc_adaptation & BFMASK(1);
   1339   in <<= 1; in |= st->field.pf_adaptation & BFMASK(1);
   1340   st->byte = in;
   1341   return ERR_CODE_NONE;
   1342 }
   1343 
   1344 err_code_t merlin16_INTERNAL_update_usr_ctrl_disable_dfe_functions_byte(struct  merlin16_usr_ctrl_disable_dfe_functions_st *st) {
   1345   uint8_t in = 0;
   1346   in <<= 1; in |= st->field.dfe_tap2_dcd & BFMASK(1);
   1347   in <<= 1; in |= st->field.dfe_tap1_dcd & BFMASK(1);
   1348   in <<= 1; in |= st->field.dfe_tap5_adaptation & BFMASK(1);
   1349   in <<= 1; in |= st->field.dfe_tap4_adaptation & BFMASK(1);
   1350   in <<= 1; in |= st->field.dfe_tap3_adaptation & BFMASK(1);
   1351   in <<= 1; in |= st->field.dfe_tap2_adaptation & BFMASK(1);
   1352   in <<= 1; in |= st->field.dfe_tap1_adaptation & BFMASK(1);
   1353   st->byte = in;
   1354   return ERR_CODE_NONE;
   1355 }
   1356 
   1357 #undef BFMASK
   1358 
   1359 err_code_t merlin16_INTERNAL_check_uc_lane_stopped(srds_access_t *sa__) {
   1360 
   1361   uint8_t is_micro_stopped;
   1362   ESTM(is_micro_stopped = rdv_usr_sts_micro_stopped() || (rd_rx_lane_dp_reset_state() > 0));
   1363   if (!is_micro_stopped) {
   1364       return(_error(ERR_CODE_UC_NOT_STOPPED));
   1365   } else {
   1366       return(ERR_CODE_NONE);
   1367   }
   1368 }
   1369 
   1370 err_code_t merlin16_INTERNAL_calc_patt_gen_mode_sel(uint8_t *mode_sel, uint8_t *zero_pad_len, uint8_t patt_length) {
   1371 
   1372   if(!mode_sel) {
   1373     return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
   1374   }
   1375   if(!zero_pad_len) {
   1376     return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
   1377   }
   1378 
   1379   /* Select the correct Pattern generator Mode depending on Pattern length */
   1380   if (!(140 % patt_length)) {
   1381     *mode_sel = 6;
   1382     *zero_pad_len = 100;
   1383   }
   1384   else if (!(160 % patt_length)) {
   1385     *mode_sel = 5;
   1386     *zero_pad_len = 80;
   1387   }
   1388   else if (!(180 % patt_length)) {
   1389     *mode_sel = 4;
   1390     *zero_pad_len = 60;
   1391   }
   1392   else if (!(200 % patt_length)) {
   1393     *mode_sel = 3;
   1394     *zero_pad_len = 40;
   1395   }
   1396   else if (!(220 % patt_length)) {
   1397     *mode_sel = 2;
   1398     *zero_pad_len = 20;
   1399   }
   1400   else if (!(240 % patt_length)) {
   1401     *mode_sel = 1;
   1402     *zero_pad_len = 0;
   1403   } else {
   1404     EFUN_PRINTF(("ERROR: Unsupported Pattern Length\n"));
   1405     return (_error(ERR_CODE_CFG_PATT_INVALID_PATT_LENGTH));
   1406   }
   1407   return(ERR_CODE_NONE);
   1408 }
   1409 
   1410 /*-----------------------------------------*/
   1411 /*  Write Core Config variables to uC RAM  */
   1412 /*-----------------------------------------*/
   1413 
   1414 err_code_t merlin16_INTERNAL_set_uc_core_config(srds_access_t *sa__, struct merlin16_uc_core_config_st struct_val) {
   1415     {   uint8_t reset_state;
   1416         ESTM(reset_state = rdc_core_dp_reset_state());
   1417         if(reset_state < 7) {
   1418             EFUN_PRINTF(("ERROR: merlin16_INTERNAL_set_uc_core_config(..) called without core_dp_s_rstb=0\n"));
   1419             return (_error(ERR_CODE_CORE_DP_NOT_RESET));
   1420         }
   1421     }
   1422     if(struct_val.vco_rate_in_Mhz > 0) {
   1423         struct_val.field.vco_rate = MHZ_TO_VCO_RATE(struct_val.vco_rate_in_Mhz);
   1424     }
   1425     EFUN(merlin16_INTERNAL_update_uc_core_config_word(&struct_val));
   1426         EFUN(wrcv_config_word(struct_val.word));
   1427     return (ERR_CODE_NONE);
   1428 }
   1429 
   1430 /*---------------------*/
   1431 /*  PLL Configuration  */
   1432 /*---------------------*/
   1433 /** Extract the refclk frequency in Hz, based on a merlin16_pll_refclk_enum value. */
   1434 err_code_t _merlin16_get_refclk_in_hz(enum merlin16_pll_refclk_enum refclk, uint32_t *refclk_in_hz) {
   1435     switch (refclk) {
   1436         case MERLIN16_PLL_REFCLK_50MHZ:          *refclk_in_hz =  50000000; break;
   1437         case MERLIN16_PLL_REFCLK_125MHZ:         *refclk_in_hz = 125000000; break;
   1438         case MERLIN16_PLL_REFCLK_156P25MHZ:      *refclk_in_hz = 156250000; break;
   1439         case MERLIN16_PLL_REFCLK_161P1328125MHZ: *refclk_in_hz = 161132813; break;
   1440         default:
   1441             EFUN_PRINTF(("ERROR: Unknown refclk frequency:  0x%08X\n", (uint32_t)refclk));
   1442             *refclk_in_hz = 0xFFFFFFFF;
   1443             return (_error(ERR_CODE_REFCLK_FREQUENCY_INVALID));
   1444     }
   1445     return (ERR_CODE_NONE);
   1446 }
   1447 
   1448 /** Identify the ratio:
   1449  *
   1450  *     (numerator / denominator) = (1000 / divisor)
   1451  *
   1452  * such that this has as little rounding error as possible:
   1453  *
   1454  *     refclk_freq_hz = numerator * round(vco_freq_khz / denominator)
   1455  *
   1456  * This will yield the most accurate refclk_freq_hz.
   1457  * Common values of vco_freq_khz are considered in this.
   1458  */
   1459 static err_code_t _merlin16_get_divisor_ratio(enum merlin16_pll_div_enum div, uint16_t *numerator, uint16_t *denominator)
   1460 {
   1461     switch (div) {
   1462         case MERLIN16_PLL_DIV_52P751515:  *denominator = 162;  *numerator = 3071; break;
   1463         case MERLIN16_PLL_DIV_58P181818:  *denominator =  16;  *numerator =  275; break;
   1464         case MERLIN16_PLL_DIV_62P060606:  *denominator =  53;  *numerator =  854; break;
   1465         case MERLIN16_PLL_DIV_67P878788:  *denominator =  56;  *numerator =  825; break;
   1466         case MERLIN16_PLL_DIV_66P460703:  *denominator =  43;  *numerator =  647; break;
   1467         case MERLIN16_PLL_DIV_66P743079:  *denominator =  58;  *numerator =  869; break;
   1468         case MERLIN16_PLL_DIV_68P570764:  *denominator =  84;  *numerator = 1225; break;
   1469         case MERLIN16_PLL_DIV_68P856242:  *denominator =  65;  *numerator =  944; break;
   1470         case MERLIN16_PLL_DIV_69P152458:  *denominator = 102;  *numerator = 1475; break;
   1471         case MERLIN16_PLL_DIV_69P389964:  *denominator = 124;  *numerator = 1787; break;
   1472         case MERLIN16_PLL_DIV_69P818182:  *denominator =  96;  *numerator = 1375; break;
   1473         case MERLIN16_PLL_DIV_71P112952:  *denominator = 177;  *numerator = 2489; break;
   1474         case MERLIN16_PLL_DIV_54P4:       *denominator =  34;  *numerator =  625; break;
   1475         case MERLIN16_PLL_DIV_60:         *denominator =   3;  *numerator =   50; break;
   1476         case MERLIN16_PLL_DIV_64:         *denominator =   8;  *numerator =  125; break;
   1477         case MERLIN16_PLL_DIV_66:         *denominator =  33;  *numerator =  500; break;
   1478         case MERLIN16_PLL_DIV_68:         *denominator =  17;  *numerator =  250; break;
   1479         case MERLIN16_PLL_DIV_68P537598:  *denominator = 127;  *numerator = 1853; break;
   1480         case MERLIN16_PLL_DIV_68P828796:  *denominator = 104;  *numerator = 1511; break;
   1481         case MERLIN16_PLL_DIV_70:         *denominator =   7;  *numerator =  100; break;
   1482         case MERLIN16_PLL_DIV_70P713596:  *denominator = 106;  *numerator = 1499; break;
   1483         case MERLIN16_PLL_DIV_71P008:     *denominator = 205;  *numerator = 2887; break;
   1484         case MERLIN16_PLL_DIV_71P31347:   *denominator = 177;  *numerator = 2482; break;
   1485         case MERLIN16_PLL_DIV_71P5584:    *denominator = 118;  *numerator = 1649; break;
   1486         case MERLIN16_PLL_DIV_72:         *denominator =   9;  *numerator =  125; break;
   1487         case MERLIN16_PLL_DIV_73P335232:  *denominator = 250;  *numerator = 3409; break;
   1488         case MERLIN16_PLL_DIV_73P6:       *denominator =  46;  *numerator =  625; break;
   1489         case MERLIN16_PLL_DIV_75:         *denominator =   3;  *numerator =   40; break;
   1490         case MERLIN16_PLL_DIV_80:         *denominator =   2;  *numerator =   25; break;
   1491         case MERLIN16_PLL_DIV_82P5:       *denominator =  33;  *numerator =  400; break;
   1492         case MERLIN16_PLL_DIV_85P671997:  *denominator =  58;  *numerator =  677; break;
   1493         case MERLIN16_PLL_DIV_86P036:     *denominator = 130;  *numerator = 1511; break;
   1494         case MERLIN16_PLL_DIV_87P5:       *denominator =   7;  *numerator =   80; break;
   1495         case MERLIN16_PLL_DIV_88P392:     *denominator =  83;  *numerator =  939; break;
   1496         case MERLIN16_PLL_DIV_88P76:      *denominator = 199;  *numerator = 2242; break;
   1497         case MERLIN16_PLL_DIV_89P141838:  *denominator = 243;  *numerator = 2726; break;
   1498         case MERLIN16_PLL_DIV_89P447998:  *denominator = 128;  *numerator = 1431; break;
   1499         case MERLIN16_PLL_DIV_90:         *denominator =   9;  *numerator =  100; break;
   1500         case MERLIN16_PLL_DIV_91P669037:  *denominator = 296;  *numerator = 3229; break;
   1501         case MERLIN16_PLL_DIV_92:         *denominator =  23;  *numerator =  250; break;
   1502         case MERLIN16_PLL_DIV_100:        *denominator =   1;  *numerator =   10; break;
   1503         case MERLIN16_PLL_DIV_170:        *denominator =  17;  *numerator =  100; break;
   1504         case MERLIN16_PLL_DIV_187P5:      *denominator =   3;  *numerator =   16; break;
   1505         case MERLIN16_PLL_DIV_200:        *denominator =   1;  *numerator =    5; break;
   1506         case MERLIN16_PLL_DIV_206P25:     *denominator =  33;  *numerator =  160; break;
   1507         default:
   1508             EFUN_PRINTF(("ERROR: Unknown divider value:  0x%08X\n", (uint32_t)div));
   1509             *numerator = 0;
   1510             *denominator = 0;
   1511             return (_error(ERR_CODE_PLL_DIV_INVALID));
   1512     }
   1513     return (ERR_CODE_NONE);
   1514 }
   1515 
   1516 /** Get the Refclk frequency in Hz, based on the merlin16_pll_div_enum value and VCO frequency. */
   1517 static err_code_t _merlin16_get_refclk_from_div_vco(uint32_t *refclk_freq_hz, enum merlin16_pll_div_enum div, uint32_t vco_freq_khz, enum merlin16_pll_option_enum pll_option) {
   1518     uint16_t numerator, denominator;
   1519     EFUN(_merlin16_get_divisor_ratio(div, &numerator, &denominator));
   1520     *refclk_freq_hz = ((vco_freq_khz+(denominator>>1)) / denominator) * numerator;
   1521     if (pll_option == MERLIN16_PLL_OPTION_REFCLK_DOUBLER_EN) *refclk_freq_hz /= 2;
   1522     if (pll_option == MERLIN16_PLL_OPTION_REFCLK_DIV2_EN)    *refclk_freq_hz *= 2;
   1523     if (pll_option == MERLIN16_PLL_OPTION_REFCLK_DIV4_EN)    *refclk_freq_hz *= 4;
   1524     return (ERR_CODE_NONE);
   1525 }
   1526 
   1527 /** Get the VCO frequency in kHz, based on the reference clock frequency and merlin16_pll_div_enum value. */
   1528 err_code_t merlin16_INTERNAL_get_vco_from_refclk_div(uint32_t refclk_freq_hz, enum merlin16_pll_div_enum div, uint32_t *vco_freq_khz, enum merlin16_pll_option_enum pll_option) {
   1529     uint16_t numerator, denominator;
   1530     EFUN(_merlin16_get_divisor_ratio(div, &numerator, &denominator));
   1531     if (pll_option == MERLIN16_PLL_OPTION_REFCLK_DOUBLER_EN) refclk_freq_hz *= 2;
   1532     if (pll_option == MERLIN16_PLL_OPTION_REFCLK_DIV2_EN)    refclk_freq_hz /= 2;
   1533     if (pll_option == MERLIN16_PLL_OPTION_REFCLK_DIV4_EN)    refclk_freq_hz /= 4;
   1534     *vco_freq_khz = ((refclk_freq_hz + (numerator>>1)) / numerator) * denominator;
   1535     return (ERR_CODE_NONE);
   1536 }
   1537 
   1538 /* Boundaries for allowed VCO frequency */
   1539 #    define SERDES_VCO_FREQ_KHZ_MIN ( 8500000)
   1540 #    define SERDES_VCO_FREQ_KHZ_MAX (12500000)
   1541 
   1542 /* Allowed tolerance in resultant VCO frequency when auto-determining divider value */
   1543 #    define SERDES_VCO_FREQ_KHZ_TOLERANCE (4000)
   1544 
   1545 /* The allowed PLL divider values */
   1546 static const enum merlin16_pll_div_enum _merlin16_div_candidates[] = {
   1547     MERLIN16_PLL_DIV_52P751515,
   1548     MERLIN16_PLL_DIV_54P4,
   1549     MERLIN16_PLL_DIV_58P181818,
   1550     MERLIN16_PLL_DIV_60,
   1551     MERLIN16_PLL_DIV_62P060606,
   1552     MERLIN16_PLL_DIV_64,
   1553     MERLIN16_PLL_DIV_66,
   1554     MERLIN16_PLL_DIV_66P460703,
   1555     MERLIN16_PLL_DIV_66P743079,
   1556     MERLIN16_PLL_DIV_67P878788,
   1557     MERLIN16_PLL_DIV_68,
   1558     MERLIN16_PLL_DIV_68P537598,
   1559     MERLIN16_PLL_DIV_68P570764,
   1560     MERLIN16_PLL_DIV_68P828796,
   1561     MERLIN16_PLL_DIV_68P856242,
   1562     MERLIN16_PLL_DIV_69P152458,
   1563     MERLIN16_PLL_DIV_69P389964,
   1564     MERLIN16_PLL_DIV_69P818182,
   1565     MERLIN16_PLL_DIV_70,
   1566     MERLIN16_PLL_DIV_70P713596,
   1567     MERLIN16_PLL_DIV_71P008,
   1568     MERLIN16_PLL_DIV_71P112952,
   1569     MERLIN16_PLL_DIV_71P31347,
   1570     MERLIN16_PLL_DIV_71P5584,
   1571     MERLIN16_PLL_DIV_72,
   1572     MERLIN16_PLL_DIV_73P335232,
   1573     MERLIN16_PLL_DIV_73P6,
   1574     MERLIN16_PLL_DIV_75,
   1575     MERLIN16_PLL_DIV_80,
   1576     MERLIN16_PLL_DIV_82P5,
   1577     MERLIN16_PLL_DIV_85P671997,
   1578     MERLIN16_PLL_DIV_86P036,
   1579     MERLIN16_PLL_DIV_87P5,
   1580     MERLIN16_PLL_DIV_88P392,
   1581     MERLIN16_PLL_DIV_88P76,
   1582     MERLIN16_PLL_DIV_89P141838,
   1583     MERLIN16_PLL_DIV_89P447998,
   1584     MERLIN16_PLL_DIV_90,
   1585     MERLIN16_PLL_DIV_91P669037,
   1586     MERLIN16_PLL_DIV_92,
   1587     MERLIN16_PLL_DIV_100,
   1588     MERLIN16_PLL_DIV_170,
   1589     MERLIN16_PLL_DIV_187P5,
   1590     MERLIN16_PLL_DIV_200,
   1591     MERLIN16_PLL_DIV_206P25
   1592 };
   1593 
   1594 static const uint8_t _merlin16_div_candidates_count = sizeof(_merlin16_div_candidates) / sizeof(_merlin16_div_candidates[0]);
   1595 
   1596 static err_code_t _merlin16_check_div(enum merlin16_pll_div_enum div) {
   1597     uint8_t i, found = 0;
   1598     for (i=0; i<_merlin16_div_candidates_count; i++) {
   1599         found |= div == _merlin16_div_candidates[i];
   1600     }
   1601     if (!found) {
   1602         EFUN_PRINTF(("ERROR: Invalid divider value:  0x%08X\n", (uint32_t)div));
   1603         return (_error(ERR_CODE_PLL_DIV_INVALID));
   1604     }
   1605     return (ERR_CODE_NONE);
   1606 }
   1607     
   1608 static err_code_t _merlin16_check_vco_freq_khz(uint32_t vco_freq_khz) {
   1609     if (vco_freq_khz < SERDES_VCO_FREQ_KHZ_MIN - SERDES_VCO_FREQ_KHZ_TOLERANCE) {
   1610         EFUN_PRINTF(("ERROR: VCO frequency too low:  %d kHz is lower than minimum (%d kHz)\n", vco_freq_khz, SERDES_VCO_FREQ_KHZ_MIN));
   1611         return (_error(ERR_CODE_VCO_FREQUENCY_INVALID));
   1612     }
   1613     if (vco_freq_khz > SERDES_VCO_FREQ_KHZ_MAX + SERDES_VCO_FREQ_KHZ_TOLERANCE) {
   1614         EFUN_PRINTF(("ERROR: VCO frequency too high:  %d kHz is higher than maximum (%d kHz)\n", vco_freq_khz, SERDES_VCO_FREQ_KHZ_MAX));
   1615         return (_error(ERR_CODE_VCO_FREQUENCY_INVALID));
   1616     }
   1617     return (ERR_CODE_NONE);
   1618 }
   1619     
   1620 /** Find the entry out of _merlin16_div_candidates that is closest to matching refclk_freq_hz and vco_freq_khz. */
   1621 static err_code_t _merlin16_get_div(uint32_t refclk_freq_hz, uint32_t vco_freq_khz, enum merlin16_pll_div_enum *div, enum merlin16_pll_option_enum pll_option) {
   1622     int32_t vco_freq_khz_min_error = 0x7FFFFFFF;
   1623     uint8_t i;
   1624     for (i=0; i<_merlin16_div_candidates_count; i++) {
   1625         uint32_t actual_vco_freq_khz = 0;
   1626         int32_t  vco_freq_khz_error;
   1627         EFUN(merlin16_INTERNAL_get_vco_from_refclk_div(refclk_freq_hz, _merlin16_div_candidates[i], &actual_vco_freq_khz, pll_option));
   1628         vco_freq_khz_error = vco_freq_khz - actual_vco_freq_khz;
   1629         vco_freq_khz_error = SRDS_ABS(vco_freq_khz_error);
   1630         if (vco_freq_khz_min_error > vco_freq_khz_error) {
   1631             vco_freq_khz_min_error = vco_freq_khz_error;
   1632             *div = _merlin16_div_candidates[i];
   1633         }
   1634     }
   1635     if (vco_freq_khz_min_error == 0xFFFFFFFF) {
   1636       return (_error(ERR_CODE_CONFLICTING_PARAMETERS));
   1637     }
   1638     return (ERR_CODE_NONE);
   1639 }
   1640 
   1641 err_code_t merlin16_INTERNAL_resolve_pll_parameters(enum merlin16_pll_refclk_enum refclk,
   1642                                                   uint32_t *refclk_freq_hz,
   1643                                                   enum merlin16_pll_div_enum *div,
   1644                                                   uint32_t *vco_freq_khz,
   1645                                                   enum merlin16_pll_option_enum pll_option) {
   1646 
   1647     /* Parameter value and consistency checks */
   1648     const uint8_t given_param_count = (((refclk == MERLIN16_PLL_REFCLK_UNKNOWN) ? 0 : 1)
   1649                                        + ((*div == MERLIN16_PLL_DIV_UNKNOWN) ? 0 : 1)
   1650                                        + ((*vco_freq_khz == 0) ? 0 : 1));
   1651     const uint32_t original_vco_freq_khz = *vco_freq_khz;
   1652     enum merlin16_pll_div_enum auto_div = MERLIN16_PLL_DIV_UNKNOWN;
   1653     char*pll_option_e2s[] = {"no", "refclk_x2", "refclk_div2", "refclk_div4"};
   1654     COMPILER_REFERENCE(pll_option_e2s);
   1655         
   1656     /* Verify that at least two of the three parameters is given. */
   1657     if (given_param_count < 2) {
   1658         return (_error(ERR_CODE_INSUFFICIENT_PARAMETERS));
   1659     }
   1660 
   1661     /* Skip verification if option is selected. Error if all parameters not given. */
   1662     if (pll_option == MERLIN16_PLL_OPTION_DISABLE_VERIFY) {
   1663         if (given_param_count < 3) {
   1664             return (_error(ERR_CODE_INSUFFICIENT_PARAMETERS));
   1665         } else {
   1666             EFUN(_merlin16_get_refclk_in_hz(refclk, refclk_freq_hz));
   1667             return(ERR_CODE_NONE);
   1668         }
   1669     }
   1670 
   1671     /* The refclk value is checked in various functions below. */
   1672 
   1673     /* Verify that the requested div value is allowed. */
   1674     if (*div != MERLIN16_PLL_DIV_UNKNOWN) {
   1675         EFUN(_merlin16_check_div(*div));
   1676     }
   1677 
   1678     /* Verify that the requested VCO frequency is allowed. */
   1679     if (*vco_freq_khz != 0) {
   1680         EFUN(_merlin16_check_vco_freq_khz(*vco_freq_khz));
   1681     }
   1682 
   1683     if (refclk == MERLIN16_PLL_REFCLK_UNKNOWN) {
   1684         /* Determine refclk from vco frequency and div */
   1685         EFUN(_merlin16_get_refclk_from_div_vco(refclk_freq_hz, *div, *vco_freq_khz, pll_option));
   1686     } else {
   1687         EFUN(_merlin16_get_refclk_in_hz(refclk, refclk_freq_hz));
   1688     }
   1689 
   1690     if (*vco_freq_khz == 0) {
   1691         /* Determine VCO frequency from refclk and divider */
   1692         EFUN(merlin16_INTERNAL_get_vco_from_refclk_div(*refclk_freq_hz, *div, vco_freq_khz, pll_option));
   1693     }
   1694 
   1695     /* Determine divider from vco frequency and refclk.
   1696      * This is done even if the div was provided, because if it is,
   1697      * we still want to check whether the parameters are conflicting.
   1698      */
   1699     EFUN(_merlin16_get_div(*refclk_freq_hz, *vco_freq_khz, &auto_div, pll_option));
   1700     if (*div == MERLIN16_PLL_DIV_UNKNOWN) {
   1701         /* Use the auto-determined divider value, since the divider was not supplied. */
   1702         *div = auto_div;
   1703 
   1704         /* Determine resultant VCO frequency from refclk and divider */
   1705         EFUN(merlin16_INTERNAL_get_vco_from_refclk_div(*refclk_freq_hz, *div, vco_freq_khz, pll_option));
   1706     }
   1707 
   1708     /* Verify the resultant VCO frequency */
   1709     EFUN(_merlin16_check_vco_freq_khz(*vco_freq_khz));
   1710 
   1711     /* Verify that the requested VCO frequency is delivered. */
   1712     if ((original_vco_freq_khz != 0)
   1713         && ((*vco_freq_khz < original_vco_freq_khz - SERDES_VCO_FREQ_KHZ_TOLERANCE)
   1714             || (*vco_freq_khz > original_vco_freq_khz + SERDES_VCO_FREQ_KHZ_TOLERANCE))) {
   1715         EFUN_PRINTF(("ERROR: Could not achieve requested VCO frequency of %d kHz.\n       Refclk is %d Hz, %s option enabled, and auto-determined divider is 0x%08X, yielding a VCO frequency of %d kHz.\n",
   1716                      original_vco_freq_khz, *refclk_freq_hz, pll_option_e2s[pll_option], *div, *vco_freq_khz));
   1717         return (_error(ERR_CODE_VCO_FREQUENCY_INVALID));
   1718     }
   1719     
   1720     /* Verify the auto-determined divider value. */
   1721     if (auto_div != *div) {
   1722         EFUN_PRINTF(("ERROR: Conflicting PLL parameters:  refclk is %d Hz, %s option enabled, divider is 0x%08X, and VCO frequency is %d kHz.\n       Expected divider is 0x%08X\n",
   1723                      *refclk_freq_hz, pll_option_e2s[pll_option], *div, *vco_freq_khz, auto_div));
   1724         return (_error(ERR_CODE_CONFLICTING_PARAMETERS));
   1725     }
   1726 
   1727     return (ERR_CODE_NONE);
   1728 }
   1729 
   1730 err_code_t merlin16_INTERNAL_display_pll_to_divider(srds_access_t *sa__, uint32_t div) {
   1731     /* Adjust these to increase or decrease the number of digits to the right
   1732      * of the decimal point.
   1733      */
   1734     const uint8_t decimal_digits = 4;
   1735     const uint32_t ten_to_the_decimal_digits = 10000; /* 10**decimal_digits */
   1736 
   1737     /* Not a const, because of carry logic below. */
   1738     uint16_t div_integer = SRDS_INTERNAL_GET_PLL_DIV_INTEGER(div);
   1739 
   1740     if (SRDS_INTERNAL_IS_PLL_DIV_FRACTIONAL(div)) {
   1741         /* fraction_num will have this many bits (ending at bit 0). */
   1742         const uint8_t  fraction_num_width = 28;
   1743         const uint32_t fraction_num = SRDS_INTERNAL_GET_PLL_DIV_FRACTION_NUM(div, fraction_num_width);
   1744 
   1745         /* Identify the number that, when printed with left-padded zeros,
   1746          * becomes the digits to the right of the decimal point.
   1747          *
   1748          * This value can be obtained by dividing fraction_num by:
   1749          *
   1750          *     (2^fraction_num_width)/(10^decimal_digits)
   1751          */
   1752         const uint32_t divisor = (((1 << fraction_num_width) + (ten_to_the_decimal_digits>>1))
   1753                                   / ten_to_the_decimal_digits);
   1754         uint32_t fraction_as_int = (fraction_num + (divisor>>1)) / divisor;
   1755 
   1756         /* In case the rounding above caused the fractional portion to overflow
   1757          * (e.g. 4.9999999999 becomes 5.0000), implement the carry into the
   1758          * integer portion.
   1759          */
   1760         if (fraction_as_int >= ten_to_the_decimal_digits) {
   1761             fraction_as_int -= ten_to_the_decimal_digits;
   1762             ++div_integer;
   1763         }
   1764 
   1765         EFUN_PRINTF(("%3d.%0*d", div_integer, decimal_digits, fraction_as_int));
   1766     } else {
   1767         const uint8_t left_spaces = (decimal_digits + 1) >> 1;
   1768         COMPILER_REFERENCE(left_spaces);
   1769         EFUN_PRINTF(("%*s%3d%*s", left_spaces, "", div_integer, decimal_digits - left_spaces + 1, ""));
   1770     }
   1771     return(ERR_CODE_NONE);
   1772 }
   1773 
   1774 
   1775 err_code_t merlin16_INTERNAL_print_uc_dsc_error(srds_access_t *sa__, enum srds_pmd_uc_cmd_enum cmd) {
   1776     uint32_t supp_info;
   1777 
   1778     ESTM(supp_info = (rd_uc_dsc_supp_info()) & 0xFF);
   1779     switch (SUPP_INFO_TO_ERROR_CODE(supp_info)) {
   1780       case UC_CMD_ERROR_INVALID_COMMAND:
   1781         ESTM_PRINTF(("ERROR : UC reported invalid command %d.  (other_info = 0x%X)\n",
   1782                      cmd, SUPP_INFO_TO_OTHER_INFO(supp_info)));
   1783         break;
   1784       case UC_CMD_ERROR_BUSY:
   1785         ESTM_PRINTF(("ERROR : UC reported busy for command %d.  (other_info = 0x%X)\n",
   1786                      cmd, SUPP_INFO_TO_OTHER_INFO(supp_info)));
   1787         break;
   1788       case UC_CMD_ERROR_GET_EYE_SAMPLE_ERROR:
   1789         ESTM_PRINTF(("ERROR : UC reported error in getting eye sample.  (command %d, other_info = 0x%X)\n",
   1790                      cmd, SUPP_INFO_TO_OTHER_INFO(supp_info)));
   1791         break;
   1792       case UC_CMD_ERROR_PRBS_NOT_LOCKED:
   1793         ESTM_PRINTF(("ERROR : UC reported PRBS not locked.  (command %d, other_info = 0x%X)\n",
   1794                      cmd, SUPP_INFO_TO_OTHER_INFO(supp_info)));
   1795         break;
   1796       case UC_CMD_ERROR_COMMAND_IN_PROGRESS:
   1797         ESTM_PRINTF(("ERROR : UC reported command already in progress.  (command %d, other_info = 0x%X)\n",
   1798                      cmd, SUPP_INFO_TO_OTHER_INFO(supp_info)));
   1799         break;
   1800       case UC_CMD_ERROR_INVALID_MODE:
   1801         ESTM_PRINTF(("ERROR : UC reported invalid mode for command %d.  (other_info = 0x%X)\n",
   1802                      cmd, SUPP_INFO_TO_OTHER_INFO(supp_info)));
   1803         break;
   1804       default:
   1805         ESTM_PRINTF(("ERROR : UC reported unknown error 0x%X for command %d.  (other_info = 0x%X)\n",
   1806                      SUPP_INFO_TO_ERROR_CODE(supp_info), cmd, SUPP_INFO_TO_OTHER_INFO(supp_info)));
   1807     }
   1808     /* Cleanup cmd register */
   1809     EFUN(reg_wr_DSC_A_DSC_UC_CTRL(0x80));
   1810     EFUN(wr_uc_dsc_data(0));
   1811 
   1812     return(ERR_CODE_NONE);
   1813 }
   1814  
   1815 /******************************************/
   1816 /*  Serdes Register field Poll functions  */
   1817 /******************************************/
   1818 
   1819 #ifndef CUSTOM_REG_POLLING
   1820 /* poll for microcontroller to populate the dsc_data register */
   1821 err_code_t merlin16_INTERNAL_poll_diag_done(srds_access_t *sa__, uint16_t *status, uint32_t timeout_ms) {
   1822  uint8_t loop;
   1823 
   1824  if(!status) {
   1825      return(_error(ERR_CODE_BAD_PTR_OR_INVALID_INPUT));
   1826   }
   1827 
   1828  for(loop=0;loop < 100; loop++) {
   1829      ESTM(*status=rdv_usr_diag_status());
   1830 
   1831      if((*status & 0x8000) > 0) {
   1832          return(ERR_CODE_NONE);
   1833      }
   1834      if(loop>10) {
   1835          EFUN(USR_DELAY_US(10*timeout_ms));
   1836      }
   1837  }
   1838  return(_error(ERR_CODE_DIAG_TIMEOUT));
   1839 }
   1840 /** Poll for field "uc_dsc_ready_for_cmd" = 1 [Return Val => Error_code (0 = Polling Pass)] */
   1841 err_code_t merlin16_INTERNAL_poll_uc_dsc_ready_for_cmd_equals_1(srds_access_t *sa__, uint32_t timeout_ms, enum srds_pmd_uc_cmd_enum cmd) {
   1842     /* read quickly for 10 tries */
   1843     uint16_t loop;
   1844 
   1845     for (loop = 0; loop < 100; loop++) {
   1846         uint16_t rddata;
   1847         ESTM(rddata = reg_rd_DSC_A_DSC_UC_CTRL());
   1848         if (rddata & 0x0080) {    /* bit 7 is uc_dsc_ready_for_cmd */
   1849             if (rddata & 0x0040) {  /* bit 6 is uc_dsc_error_found   */
   1850                 EFUN(merlin16_INTERNAL_print_uc_dsc_error(sa__, cmd));
   1851                 return(_error(ERR_CODE_UC_CMD_RETURN_ERROR));
   1852             }
   1853             return (ERR_CODE_NONE);
   1854         }
   1855         if(loop>10) {
   1856             EFUN(USR_DELAY_US(10*timeout_ms));
   1857         }
   1858     }
   1859   EFUN_PRINTF(("ERROR : DSC ready for command is not working, applying workaround and getting debug info !\n"));
   1860   DISP(rd_uc_dsc_supp_info());
   1861   DISP(rd_uc_dsc_gp_uc_req());
   1862   DISP(rd_dsc_state());
   1863   ESTM_PRINTF(("Uc Core Status Byte = 0x%x\n",rdcv_status_byte()));
   1864   DISP(rdv_usr_sts_micro_stopped());
   1865   /* DISP(rdv_stop_graceful_trigger()); */
   1866   /* artifically terminate the command to re-enable the command interface */
   1867   EFUN(wr_uc_dsc_ready_for_cmd(0x1));
   1868   return (_error(ERR_CODE_POLLING_TIMEOUT));          /* Error Code for polling timeout */
   1869 }
   1870 
   1871 /* Poll for field "dsc_state" = DSC_STATE_UC_TUNE [Return Val => Error_code (0 = Polling Pass)] */
   1872 err_code_t merlin16_INTERNAL_poll_dsc_state_equals_uc_tune(srds_access_t *sa__, uint32_t timeout_ms) {
   1873   uint16_t loop;
   1874   uint16_t dsc_state;
   1875   /* poll 10 times to avoid longer delays later */
   1876   for (loop = 0; loop < 100; loop++) {
   1877     ESTM(dsc_state = rd_dsc_state());
   1878     if (dsc_state == DSC_STATE_UC_TUNE) {
   1879       return (ERR_CODE_NONE);
   1880     }
   1881     if(loop>10) {
   1882         EFUN(USR_DELAY_US(10*timeout_ms));
   1883     }
   1884   }
   1885   ESTM_PRINTF(("DSC_STATE = %d\n", rd_dsc_state()));
   1886   return (_error(ERR_CODE_POLLING_TIMEOUT));          /* Error Code for polling timeout */
   1887 }
   1888 
   1889 /* Poll for field "st_afe_tx_fifo_resetb" = 1 [Return Val => Error_code (0 = Polling Pass)] */
   1890 err_code_t merlin16_INTERNAL_poll_st_afe_tx_fifo_resetb_equals_1(srds_access_t *sa__, uint32_t timeout_ms) {
   1891   uint16_t loop;
   1892 
   1893   for (loop = 0; loop <= 100; loop++) {
   1894     uint8_t st_afe_tx_fifo_resetb;
   1895     ESTM(st_afe_tx_fifo_resetb = rd_st_afe_tx_fifo_resetb());
   1896     if (st_afe_tx_fifo_resetb) {
   1897       return (ERR_CODE_NONE);
   1898     }
   1899     EFUN(USR_DELAY_US(10*timeout_ms));
   1900   }
   1901   return (_error(ERR_CODE_POLLING_TIMEOUT));          /* Error Code for polling timeout */
   1902 }
   1903 
   1904 /* Poll for field "micro_ra_initdone" = 1 [Return Val => Error_code (0 = Polling Pass)] */
   1905 err_code_t merlin16_INTERNAL_poll_micro_ra_initdone(srds_access_t *sa__, uint32_t timeout_ms) {
   1906   uint16_t loop;
   1907 
   1908   uint8_t result;
   1909   for (loop = 0; loop <= 100; loop++) {
   1910     ESTM(result = rdc_micro_ra_initdone());
   1911     if (result) {
   1912       return (ERR_CODE_NONE);
   1913     }
   1914     EFUN(USR_DELAY_US(10*timeout_ms));
   1915   }
   1916   return (_error(ERR_CODE_POLLING_TIMEOUT));          /* Error Code for polling timeout */
   1917 }
   1918 
   1919 #endif /* CUSTOM_REG_POLLING */
   1920 
   1921 
   1922 int merlin16_INTERNAL_get_endian_offset(uint8_t *addr) {
   1923     const int endian_const = 1;
   1924     return ((*(char*)&endian_const) == 0) ?
   1925         (
   1926         (((USR_UINTPTR)(addr))%4 == 0) ?  3 :
   1927         (((USR_UINTPTR)(addr))%4 == 1) ?  1 :
   1928         (((USR_UINTPTR)(addr))%4 == 2) ? -1 :
   1929         (((USR_UINTPTR)(addr))%4 == 3) ? -3 :
   1930         0)
   1931         : 0;
   1932 }
   1933 
   1934 err_code_t merlin16_INTERNAL_rdblk_callback(void *arg, uint8_t byte_count, uint16_t data) {
   1935     merlin16_INTERNAL_rdblk_callback_arg_t * const cast_arg = (merlin16_INTERNAL_rdblk_callback_arg_t *)arg;
   1936     int endian_offset = 0;
   1937     ESTM(endian_offset = merlin16_INTERNAL_get_endian_offset(cast_arg->mem_ptr));
   1938     *(cast_arg->mem_ptr + endian_offset) = data & 0xFF;
   1939     cast_arg->mem_ptr++;
   1940     if (byte_count == 2) {
   1941         ESTM(endian_offset = merlin16_INTERNAL_get_endian_offset(cast_arg->mem_ptr));
   1942         *(cast_arg->mem_ptr + endian_offset) = data >> 8;
   1943         cast_arg->mem_ptr++;
   1944     }
   1945     return (ERR_CODE_NONE);
   1946 }
   1947 
   1948 err_code_t merlin16_INTERNAL_rdblk_uc_generic_ram(srds_access_t *sa__,
   1949                                                 uint32_t block_addr,
   1950                                                 uint16_t block_size,
   1951                                                 uint16_t start_offset,
   1952                                                 uint16_t cnt,
   1953                                                 void *arg,
   1954                                                 err_code_t (*callback)(void *, uint8_t, uint16_t)) {
   1955     uint32_t read_val = 0;
   1956     uint8_t defecit = 0;
   1957     uint32_t addr = block_addr + start_offset;
   1958     
   1959     if (cnt == 0) {
   1960         return (ERR_CODE_NONE);
   1961     }
   1962 
   1963     /* Check for bad start offset and block size. */
   1964     if (start_offset >= block_size) {
   1965         return (ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   1966     }
   1967 
   1968     while (cnt > 0) {
   1969         /* Determine how many bytes to read before wrapping back to start of block. */
   1970         uint16_t block_cnt = SRDS_MIN(cnt, block_addr + block_size - addr);
   1971         cnt -= block_cnt;
   1972 
   1973             /* Set up the word reads. */
   1974             EFUN(wrc_micro_autoinc_rdaddr_en(1));
   1975             EFUN(wrc_micro_ra_rddatasize(0x1));                     /* Select 16bit read datasize */
   1976             EFUN(wrc_micro_ra_rdaddr_msw(addr >> 16));              /* Upper 16bits of RAM address to be read */
   1977             EFUN(wrc_micro_ra_rdaddr_lsw(addr & 0xFFFE));           /* Lower 16bits of RAM address to be read */
   1978 
   1979             /* Read the leading byte, if starting at an odd address. */
   1980             if ((addr & 1) == 1) {
   1981                 ESTM(read_val |= ((rdc_micro_ra_rddata_lsw() >> 8) << defecit));
   1982                 if (defecit == 8) {
   1983                     EFUN(callback(arg, 2, (uint16_t)read_val));
   1984                     read_val = 0;
   1985                 }
   1986                 /* We just read a byte.  This toggles the defecit from 0 to 8 or from 8 to 0. */
   1987                 defecit ^= 8;
   1988                 --block_cnt;
   1989             }
   1990 
   1991             /* Read the whole words, and call the callback with two bytes at a time. */
   1992             while (block_cnt >= 2) {
   1993                 ESTM(read_val |= (rdc_micro_ra_rddata_lsw() << defecit));
   1994                 EFUN(callback(arg, 2, (uint16_t)read_val));
   1995                 read_val >>= 16;
   1996                 /* We just read two bytes.  This preserves whatever defecit (8 or 0) is there. */
   1997                 block_cnt -= 2;
   1998             }
   1999 
   2000             /* Read the trailing byte, if leftover after reading whole words. */
   2001             if (block_cnt > 0) {
   2002                 ESTM(read_val |= ((rdc_micro_ra_rddata_lsw() & 0xFF) << defecit));
   2003                 if (defecit == 8) {
   2004                     EFUN(callback(arg, 2, (uint16_t)read_val));
   2005                     read_val = 0;
   2006                 }
   2007                 /* We just read a byte.  This toggles the defecit from 0 to 8 or from 8 to 0. */
   2008                 defecit ^= 8;
   2009             }
   2010         addr = block_addr;
   2011     }
   2012 
   2013     /* If a final byte is left behind, then call the callback with it. */
   2014     if (defecit > 0) {
   2015         EFUN(callback(arg, 1, (uint16_t)read_val));
   2016     }
   2017 
   2018     return(ERR_CODE_NONE);
   2019 }
   2020 err_code_t merlin16_INTERNAL_rdblk_uc_generic_ram_descending(srds_access_t *sa__,
   2021                                                            uint32_t block_addr,
   2022                                                            uint16_t block_size,
   2023                                                            uint16_t start_offset,
   2024                                                            uint16_t cnt,
   2025                                                            void *arg,
   2026                                                            err_code_t (*callback)(void *, uint8_t, uint16_t)) {
   2027     uint32_t read_val = 0;
   2028     uint8_t defecit = 0;
   2029     uint32_t addr = block_addr + start_offset;
   2030     uint16_t configured_addr_msw = (addr >> 16) + 1;
   2031     
   2032     if (cnt == 0) {
   2033         return (ERR_CODE_NONE);
   2034     }
   2035 
   2036     /* Check for bad start offset and block size. */
   2037     if (start_offset >= block_size) {
   2038         return (ERR_CODE_BAD_PTR_OR_INVALID_INPUT);
   2039     }
   2040 
   2041     EFUN(wrc_micro_autoinc_rdaddr_en(0));
   2042     EFUN(wrc_micro_ra_rddatasize(0x1));                         /* Select 16bit read datasize */
   2043     
   2044     while (cnt > 0) {
   2045         /* Determine how many bytes to read before wrapping back to end of block. */
   2046         uint16_t block_cnt = SRDS_MIN(cnt, start_offset+1);
   2047         cnt -= block_cnt;
   2048 
   2049         while (block_cnt > 0) {
   2050             const uint16_t addr_msw = addr >> 16;
   2051             uint16_t read_val2;
   2052             if (addr_msw != configured_addr_msw) {
   2053                 EFUN(wrc_micro_ra_rdaddr_msw(addr_msw));        /* Upper 16bits of RAM address to be read */
   2054                 configured_addr_msw = addr_msw;
   2055             }
   2056             
   2057             EFUN(wrc_micro_ra_rdaddr_lsw(addr & 0xFFFE));       /* Lower 16bits of RAM address to be read */
   2058             ESTM(read_val2 = rdc_micro_ra_rddata_lsw());
   2059 
   2060             if (((addr & 1) == 1) && (block_cnt >= 2)) {
   2061                 /* Reading two bytes.  Since we're reading in descending address order, they
   2062                  * will be reversed before they are sent out. */
   2063                 read_val |= ((((read_val2 & 0xFF) << 8) | (read_val2 >> 8)) << defecit);
   2064                 EFUN(callback(arg, 2, (uint16_t)read_val));
   2065                 read_val >>= 16;
   2066                 /* We just read two bytes.  This preserves whatever defecit (8 or 0) is there. */
   2067                 block_cnt -= 2;
   2068                 addr -= 2;
   2069             } else {
   2070                 if ((addr & 1) == 1) {
   2071                     /* Reading upper byte of word. */
   2072                     read_val |= ((read_val2 >> 8) << defecit);
   2073                 } else {
   2074                     /* Reading lower byte of word. */
   2075                     read_val |= ((read_val2 & 0xFF) << defecit);
   2076                 }
   2077                 if (defecit == 8) {
   2078                     EFUN(callback(arg, 2, (uint16_t)read_val));
   2079                     read_val = 0;
   2080                 }
   2081                 /* We just read a byte.  This toggles the defecit from 0 to 8 or from 8 to 0. */
   2082                 defecit ^= 8;
   2083                 --block_cnt;
   2084                 --addr;
   2085             }
   2086         }
   2087         
   2088         addr = block_addr + block_size - 1;
   2089         start_offset = block_size - 1;
   2090     }
   2091 
   2092     /* If a final byte is left behind, then call the callback with it. */
   2093     if (defecit > 0) {
   2094         EFUN(callback(arg, 1, (uint16_t)read_val));
   2095     }
   2096 
   2097     return(ERR_CODE_NONE);
   2098 }
   2099 
   2100 uint8_t merlin16_INTERNAL_grp_idx_from_lane(uint8_t lane) {
   2101     return(0);
   2102 }
   2103