diff options
author | Thi Tran <thi@us.ibm.com> | 2013-10-02 10:31:04 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2013-10-04 15:40:34 -0500 |
commit | 8cddf17c6fdc5810f7cf244012afe19a7bcbd77d (patch) | |
tree | 8c7495fd83697e5d2f9f7fdac70b8b51b93f3fc2 /src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c | |
parent | f67e73208f2e6db20b35efaedaf15a4d669c2869 (diff) | |
download | talos-hostboot-8cddf17c6fdc5810f7cf244012afe19a7bcbd77d.tar.gz talos-hostboot-8cddf17c6fdc5810f7cf244012afe19a7bcbd77d.zip |
INITPROC: Hostboot - from defect SW224356 - PSTATE procedures
Change-Id: I5358dab2f24f26054fb004ff980c9fe4638cff6c
CMVC-Coreq:896229
CQ:SW224356
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/6446
Tested-by: Jenkins Server
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c')
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c | 634 |
1 files changed, 589 insertions, 45 deletions
diff --git a/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c index 5212b1a76..a299e5fb7 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c +++ b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c @@ -20,7 +20,7 @@ /* Origin: 30 */ /* */ /* IBM_PROLOG_END_TAG */ -// $Id: pstate_tables.c,v 1.8 2013/06/12 20:02:07 mjjones Exp $ +// $Id: pstate_tables.c,v 1.10 2013/09/17 16:36:39 jimyac Exp $ /// \file pstate_tables.c /// \brief This file contains code used to generate Pstate tables from real or @@ -30,12 +30,12 @@ /// always "given" to OCC either from the FSP (OCC product firmware), or by /// being built-in the image (lab images). +#include <stdlib.h> #include <stdint.h> #include <stdio.h> #include "lab_pstates.h" #include "pstate_tables.h" - #define MAX(X, Y) \ ({ \ typeof (X) __x = (X); \ @@ -209,7 +209,7 @@ chip_characterization_create(ChipCharacterization *characterization, ops[gpst_points].idd_ma = vpd[i].idd_500ma * 500; ops[gpst_points].ics_ma = vpd[i].ics_500ma * 500; - + ops[gpst_points].frequency_khz = vpd[i].frequency_mhz * 1000; // 'Corrected' voltages values add in the load-line & distribution IR drop @@ -268,7 +268,9 @@ chip_characterization_create(ChipCharacterization *characterization, // // \retval -GPST_INVALID_ARGUMENT Either argument was invalid in some way. -#define NEST_FREQUENCY_KHZ 2400000 +// jwy if we use this proc in future, do not use this value for nest freq +// instead, use the value of attribute ATTR_FREQ_PB +#define NEST_FREQ_KHZ 2400000 int gpst_stepping_setup(GlobalPstateTable* gpst, @@ -293,13 +295,15 @@ gpst_stepping_setup(GlobalPstateTable* gpst, // This is the frequency of the VRM stepper 'tick'. The base time // source for VRM stepping is therefore nest clock / 8. - cycles = (((NEST_FREQUENCY_KHZ / 1000) * vrm_delay_ns) / 1000) / + cycles = (((NEST_FREQ_KHZ / 1000) * vrm_delay_ns) / 1000) / (1 << LOG2_VRM_STEPDELAY_DIVIDER); // Normalize the exponential encoding sigbits = 32 - cntlz32(cycles); - stepdelay_range = (sigbits - VRM_STEPDELAY_RANGE_BITS); +// jwy stepdelay_range = MAX(0, sigbits - VRM_STEPDELAY_RANGE_BITS); + + stepdelay_range = (sigbits - VRM_STEPDELAY_RANGE_BITS); if (stepdelay_range < 0) { @@ -364,12 +368,14 @@ gpst_entry_create(gpst_entry_t *entry, OperatingPoint *op) gpe.fields.gpe_field = vid; __SET(vrm11, ROUND_VOLTAGE_UP, evid_vdd, vdd_corrected_uv); - __SET(vrm11, ROUND_VOLTAGE_UP, evid_vcs, vcs_corrected_uv); - __SET(ivid, ROUND_VOLTAGE_DOWN, evid_vdd_eff, vdd_ivrm_effective_uv); - __SET(ivid, ROUND_VOLTAGE_DOWN, evid_vcs_eff, vcs_ivrm_effective_uv); - __SET(ivid, ROUND_VOLTAGE_DOWN, maxreg_vdd, vdd_maxreg_uv); - __SET(ivid, ROUND_VOLTAGE_DOWN, maxreg_vcs, vcs_maxreg_uv); + __SET(vrm11, ROUND_VOLTAGE_UP, evid_vcs, vcs_corrected_uv); + __SET(ivid, ROUND_VOLTAGE_DOWN, evid_vdd_eff, vdd_ivrm_effective_uv); + __SET(ivid, ROUND_VOLTAGE_DOWN, evid_vcs_eff, vcs_ivrm_effective_uv); + __SET(ivid, ROUND_VOLTAGE_DOWN, maxreg_vdd, vdd_maxreg_uv); + __SET(ivid, ROUND_VOLTAGE_DOWN, maxreg_vcs, vcs_maxreg_uv); + ; + // Add the check byte uint8_t gpstCheckByte(uint64_t gpstEntry); @@ -510,6 +516,8 @@ gpst_create(GlobalPstateTable *gpst, // Set the Pmin Pstate + for (i = 0; i < points; i++) + entry = 0; if (gpst_entry_create(&(gpst->pstate[entry]), &(ops[0]))) { rc = -GPST_INVALID_ENTRY; @@ -576,52 +584,101 @@ gpst_create(GlobalPstateTable *gpst, } +/// Create a local Pstate table +/// +/// \param gpst A pointer to a GlobalPstateTable structure for lookup. +/// +/// \param lpsa Apointer to a LocalPstateArray structure to populate +/// +/// \param dead_zone_5mv dead zone value +/// +/// \param evrm_delay_ns External VRM delay in nano-seconds +/// +/// This routine creates a LocalPstateArray by using the dead zone value and +/// data in the GlobalPstateTable +/// +/// \retval 0 Success +/// +/// \retval -LPST_INVALID_OBJECT Either the \a gpst or \a lpsa were NULL (0) or +/// obviously invalid or incorrectly initialized. +/// +/// \retval -LPST_INVALID_ARGUMENT indicates that the difference between +/// pmax & pmin in gpst is less than deadzone voltage (ie. no data to build lpsa) int -lpst_create(const GlobalPstateTable *gpst, LocalPstateArray *lpsa, const uint8_t dead_zone_5mv) +lpst_create(const GlobalPstateTable *gpst, + LocalPstateArray *lpsa, + const uint8_t dead_zone_5mv, + double volt_int_vdd_bias, + double volt_int_vcs_bias) { - int rc = 0; + int rc = 0; int i,j; gpst_entry_t entry; uint32_t turbo_uv; + uint32_t gpst_uv; uint32_t v_uv; uint32_t vdd_uv; - uint8_t v_ivid; + uint8_t v_ivid; + uint8_t gpst_ivid; + int lpst_max_found = 0; uint32_t lpst_max_uv; uint8_t lpst_entries; uint8_t lpst_entries_div4; uint8_t gpst_index; - Pstate lpst_pmin; + Pstate lpst_pmin; + Pstate lpst_pstate; + Pstate lpst_max_pstate = 0; uint8_t vid_incr[3] = {0,0,0}; + uint8_t steps_above_curr; + uint8_t steps_below_curr; + uint8_t inc_step; + uint8_t dec_step; do { // Basic pointer checks - if (lpsa == 0) { + if ((gpst == 0) || (lpsa == 0)) { rc = -LPST_INVALID_OBJECT; break; } - + // ------------------------------------------------------------------ // find lspt_max in gpst // - lpst_max is gpst entry that is equal to (turbo_vdd - deadzone) // ------------------------------------------------------------------ entry.value = revle64(gpst->pstate[(gpst->entries)-1].value); - rc = vrm112vuv(entry.fields.evid_vdd, &turbo_uv); + rc = vrm112vuv(entry.fields.evid_vdd, &turbo_uv); if (rc) break; + + turbo_uv = (uint32_t) (turbo_uv * volt_int_vdd_bias); lpst_max_uv = turbo_uv - (dead_zone_5mv * 5000); - for (i = gpst->entries -1 ; i >= 0; i--) { - entry.value = revle64(gpst->pstate[i].value); - vrm112vuv(entry.fields.evid_vdd, &v_uv); + for (i = gpst->entries - 1 ; i >= 0; i--) { + entry.value = revle64(gpst->pstate[i].value); + rc = vrm112vuv(entry.fields.evid_vdd, &v_uv); if (rc) break; + v_uv = (uint32_t) (v_uv * volt_int_vdd_bias); - if (lpst_max_uv >= v_uv) - break; + if (lpst_max_uv >= v_uv) { + lpst_max_found = 1; + lpst_max_pstate = gpst_pmax(gpst) - (gpst->entries - i - 1); + break; + } + } + + if (rc) break; + + // generate a warning if lpst max not found + // - indicates that the difference between pmax & pmin in gpst is less than deadzone voltage + // - no data will be in lpst (lpst entries = 0) + if (lpst_max_found == 0) { + rc = -LPST_GPST_WARNING; + break; } - - lpst_entries = i + 1; - lpst_pmin = 0 - lpst_entries + 1; -// jwy printf("turbo_uv = %d lpst_max_uv = %d entries = %d lpst_pmin = %d\n", turbo_uv, lpst_max_uv, lpst_entries, lpst_pmin); + lpst_entries = gpst->entries; + lpst_pmin = gpst->pmin; + +// jwy printf("turbo_uv = %d lpst_max_uv = %d entries = %d lpst_pmin = %d lpst_max_pstate = %d i = %d\n", turbo_uv, lpst_max_uv, lpst_entries, lpst_pmin, lpst_max_pstate, i); // ---------------------------------------------------------------------------- // now loop over gpst from 0 to lpst_entries and fill in lpst from data in gpst @@ -631,18 +688,23 @@ lpst_create(const GlobalPstateTable *gpst, LocalPstateArray *lpsa, const uint8_t lpst_entries_div4 = lpst_entries/4; if ( lpst_entries % 4 != 0) lpst_entries_div4++; - + + // current lpst pstate value as table is created + lpst_pstate = gpst_pmin(gpst); + for (i = 0 ; i < lpst_entries_div4; i++) { entry.value = revle64(gpst->pstate[gpst_index].value); // compute ivid_vdd - rc = vrm112vuv(entry.fields.evid_vdd, &vdd_uv); - rc = vuv2ivid(vdd_uv, ROUND_VOLTAGE_DOWN, &v_ivid); + rc = vrm112vuv(entry.fields.evid_vdd, &vdd_uv); if (rc) break; + vdd_uv = (uint32_t) (vdd_uv * volt_int_vdd_bias); + rc = vuv2ivid(vdd_uv, ROUND_VOLTAGE_DOWN, &v_ivid); if (rc) break; lpsa->pstate[i].fields.ivid_vdd = v_ivid; // compute ivid_vcs - rc = vrm112vuv(entry.fields.evid_vcs, &v_uv); - rc = vuv2ivid(v_uv, ROUND_VOLTAGE_DOWN, &v_ivid); + rc = vrm112vuv(entry.fields.evid_vcs, &v_uv); if (rc) break; + v_uv = (uint32_t) (v_uv * volt_int_vcs_bias); + rc = vuv2ivid(v_uv, ROUND_VOLTAGE_DOWN, &v_ivid); if (rc) break; lpsa->pstate[i].fields.ivid_vcs = v_ivid; // -------------------------------------------------------------- @@ -654,14 +716,37 @@ lpst_create(const GlobalPstateTable *gpst, LocalPstateArray *lpsa, const uint8_t for (j = 0; j <= 2; j++) { gpst_index++; - if (gpst_index > lpst_entries) - break; + if (gpst_index >= lpst_entries) + break; entry.value = revle64(gpst->pstate[gpst_index].value); - rc = vrm112vuv(entry.fields.evid_vdd, &vdd_uv); - rc = vuv2ivid(vdd_uv, ROUND_VOLTAGE_DOWN, &v_ivid); + rc = vrm112vuv(entry.fields.evid_vdd, &vdd_uv); if (rc) break; + vdd_uv = (uint32_t) (vdd_uv * volt_int_vdd_bias); + rc = vuv2ivid(vdd_uv, ROUND_VOLTAGE_DOWN, &v_ivid); if (rc) break; vid_incr[j] = v_ivid - lpsa->pstate[i].fields.ivid_vdd; + + // point to next lpst pstate + lpst_pstate++; + + // the max for this field is 7, so clip to 7 if it's > 7 + if (vid_incr[j] > 7) { + vid_incr[j] = 7; + + // if in regulation, return an error + if (lpst_pstate <= lpst_max_pstate) { + rc = -LPST_INCR_CLIP_ERROR ; + break; + } + + // if not in regulation, return a warning + if (lpst_pstate > lpst_max_pstate) { +// rc = 2; +// break; + } + } + } + if (rc) break; lpsa->pstate[i].fields.ps1_vid_incr = vid_incr[0]; lpsa->pstate[i].fields.ps2_vid_incr = vid_incr[1]; @@ -682,18 +767,78 @@ lpst_create(const GlobalPstateTable *gpst, LocalPstateArray *lpsa, const uint8_t // equations from Josh iac_wc = 1.25 * ( 28.5 * 1.25 - 16 ) * ( 1 - 0.05 * 2) * 40/71; // testsite equation & ratio of testsite to anticipated produ - iac = 1.25 * (-15.78 -0.618 * sigma + 27.6 * vout/1000) * 40/64; // product equation & ratio of testsite to actual product + iac = 1.25 * (-15.78 -0.618 * sigma + 27.6 * vout/1000) * 40/64; // product equation & ratio of testsite to actual product pwrratio_f = iac / iac_wc; - pwrratio = (uint8_t)((pwrratio_f*64) + 0.5); + + if (pwrratio_f >= 1.0) + pwrratio = 63; + else + pwrratio = (uint8_t)((pwrratio_f*64) + 0.5); lpsa->pstate[i].fields.vdd_core_pwrratio = pwrratio; lpsa->pstate[i].fields.vcs_core_pwrratio = pwrratio; lpsa->pstate[i].fields.vdd_eco_pwrratio = pwrratio; lpsa->pstate[i].fields.vcs_eco_pwrratio = pwrratio; + + // ------------------------------------ + // compute increment step and decrement + // ------------------------------------ + // - look above current pstate to pstate that is >= 25 mV for inc_step + // - look below current pstate to pstate that is >= 25 mV for dec_step + + // find # steps above and below current lpst pstate + steps_above_curr = gpst_pmax(gpst) - lpst_pstate; + steps_below_curr = lpst_pstate - gpst_pmin(gpst); + + + // start looking above in gpst to find inc_step + inc_step = 0; // default + + for (j = 1; j <= steps_above_curr; j++) { + inc_step = j - 1; +// jwy printf("%d %d %d\n", lpst_pstate,j, steps_above_curr); + entry.value = revle64(gpst->pstate[lpst_pstate - gpst_pmin(gpst) + j].value); + rc = vrm112vuv(entry.fields.evid_vdd, &gpst_uv); if (rc) break; + gpst_uv = (uint32_t) (gpst_uv * volt_int_vdd_bias); + rc = vuv2ivid(gpst_uv, ROUND_VOLTAGE_DOWN, &gpst_ivid); if (rc) break; + + if ( (gpst_ivid - v_ivid) >= 4) + break; + } + + if (rc) break; + + // clip inc_step + if (inc_step > 7) + inc_step = 7; + + + lpsa->pstate[i].fields.inc_step = inc_step; +// jwy lpsa->pstate[i].fields.inc_step = 0; // FIXME - temporary patch! - // ??? what should these be ??? set to 1 for now - lpsa->pstate[i].fields.inc_step = 1; - lpsa->pstate[i].fields.dec_step = 1; + // start looking below in gpst to find dec_step + dec_step = 0; // default + + for (j = 1; j <= steps_below_curr; j++) { + dec_step = j - 1; +// jwy printf("%d %d %d\n", lpst_pstate,j, steps_below_curr); + entry.value = revle64(gpst->pstate[lpst_pstate - gpst_pmin(gpst) - j].value); + rc = vrm112vuv(entry.fields.evid_vdd, &gpst_uv); if (rc) break; + gpst_uv = (uint32_t) (gpst_uv * volt_int_vdd_bias); + rc = vuv2ivid(gpst_uv, ROUND_VOLTAGE_DOWN, &gpst_ivid); if (rc) break; + + if ( (v_ivid - gpst_ivid ) >= 4) + break; + } + + if (rc) break; + + // clip dec_step + if (dec_step > 7) + dec_step = 7; + + lpsa->pstate[i].fields.dec_step = dec_step; +// jwy lpsa->pstate[i].fields.dec_step = 0; // FIXME - temporary patch! // jwy printf (" %d %X %X %f %d %d %d %d\n", i, (uint32_t)lpsa->pstate[i].fields.ivid_vdd, (uint32_t)lpsa->pstate[i].fields.ivid_vcs, pwrratio_f, pwrratio, vid_incr[0], vid_incr[1], vid_incr[2]); @@ -703,14 +848,413 @@ lpst_create(const GlobalPstateTable *gpst, LocalPstateArray *lpsa, const uint8_t gpst_index++; if (gpst_index > lpst_entries) break; + + // point to next lpst pstate + lpst_pstate++; } // set these fields in lpst structure - lpsa->pmin = lpst_pmin; - lpsa->entries = lpst_entries; - + if (lpst_max_found == 0) { + lpsa->pmin = 0; + lpsa->entries = 0; + } + else { + lpsa->pmin = lpst_pmin; + lpsa->entries = lpst_entries; + } + } while (0); return rc; -} // end lpst_create +} // end lpst_create + +// This routine will fully fill out the VDS region table even if +// some of the upper entries are not used. +void +build_vds_region_table( ivrm_parm_data_t* i_ivrm_parms, + PstateSuperStructure* pss) +{ + int i; + uint32_t vds; + uint64_t beg_offset = 0; + uint64_t end_offset = 0; + + vds = (i_ivrm_parms->vds_min_range_upper_bound*1000)/IVID_STEP_UV; + end_offset = (uint64_t)vds; + + for (i = 0; i < i_ivrm_parms->vds_region_entries; i++) + { + pss->lpsa.vdsvin[i].fields.ivid0 = beg_offset; + pss->lpsa.vdsvin[i].fields.ivid1 = end_offset; +// jwy printf(" Vds_region[%x]: begin - %02llX, end - %02llX\n", i, beg_offset, end_offset); + + // Calculate offsets for next entry + beg_offset = end_offset + 1; + + // clip at 127 + if (beg_offset >= 127) + beg_offset = 127; + + vds =(uint32_t)( (float)end_offset * (1 + ( (float)i_ivrm_parms->vds_step_percent/100))); + end_offset = (uint64_t)vds; + + // clip at 127 + if (end_offset >= 127) + end_offset = 127; + } +} + +// This routine will fully fill out the VDS region table even if +// some of the upper entries are not used. +void +fill_vin_table( ivrm_parm_data_t* i_ivrm_parms, + PstateSuperStructure* pss) +{ + int s; + int i; + int idx; +// uint8_t pfetstr = 17; + + i = i_ivrm_parms->vin_table_setsperrow; + for (i = 0; i < i_ivrm_parms->vds_region_entries; i++) + { + for (s = 0; s < i_ivrm_parms->vin_table_setsperrow; s++) { + idx = (i*4) + s; + pss->lpsa.vdsvin[idx].fields.pfet0 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet1 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet2 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet3 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet4 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet5 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet6 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet7 = i_ivrm_parms->forced_pfetstr_value; + +// jwy pss->lpsa.vdsvin[idx].fields.pfet0 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet1 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet2 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet3 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet4 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet5 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet6 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet7 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; + +// jwy printf(" Vin[%d]{%d,%d}: %016llX\n", idx, i, s, pss->lpsa.vdsvin[idx].value); + + // Byte reverse the entry into the image. + pss->lpsa.vdsvin[idx].value = revle64(pss->lpsa.vdsvin[idx].value); + } + } +} + +#undef abs +#define abs(x) (((x)<0.0)?(-(x)):(x)) + +void simeq(int n, double A[], double Y[], double X[]) +{ + +/* PURPOSE : SOLVE THE LINEAR SYSTEM OF EQUATIONS WITH REAL */ +/* COEFFICIENTS [A] * |X| = |Y| */ +/* */ +/* INPUT : THE NUMBER OF EQUATIONS n */ +/* THE REAL MATRIX A should be A[i][j] but A[i*n+j] */ +/* THE REAL VECTOR Y */ +/* OUTPUT : THE REAL VECTOR X */ +/* */ +/* METHOD : GAUSS-JORDAN ELIMINATION USING MAXIMUM ELEMENT */ +/* FOR PIVOT. */ +/* */ +/* USAGE : simeq(n,A,Y,X); */ +/* */ +/* */ +/* WRITTEN BY : JON SQUIRE , 28 MAY 1983 */ +/* ORIGINAL DEC 1959 for IBM 650, TRANSLATED TO OTHER LANGUAGES */ +/* e.g. FORTRAN converted to Ada converted to C */ + + double *B; /* [n][n+1] WORKING MATRIX */ + int *ROW; /* ROW INTERCHANGE INDICES */ + int HOLD , I_PIVOT; /* PIVOT INDICES */ + double PIVOT; /* PIVOT ELEMENT VALUE */ + double ABS_PIVOT; + int i,j,k,m; + + B = (double *)calloc((n+1)*(n+1), sizeof(double)); + ROW = (int *)calloc(n, sizeof(int)); + m = n+1; + + /* BUILD WORKING DATA STRUCTURE */ + for(i=0; i<n; i++){ + for(j=0; j<n; j++){ + B[i*m+j] = A[i*n+j]; + } + B[i*m+n] = Y[i]; + } + /* SET UP ROW INTERCHANGE VECTORS */ + for(k=0; k<n; k++){ + ROW[k] = k; + } + + /* BEGIN MAIN REDUCTION LOOP */ + for(k=0; k<n; k++){ + + /* FIND LARGEST ELEMENT FOR PIVOT */ + PIVOT = B[ROW[k]*m+k]; + ABS_PIVOT = abs(PIVOT); + I_PIVOT = k; + for(i=k; i<n; i++){ + if( abs(B[ROW[i]*m+k]) > ABS_PIVOT){ + I_PIVOT = i; + PIVOT = B[ROW[i]*m+k]; + ABS_PIVOT = abs ( PIVOT ); + } + } + + /* HAVE PIVOT, INTERCHANGE ROW POINTERS */ + HOLD = ROW[k]; + ROW[k] = ROW[I_PIVOT]; + ROW[I_PIVOT] = HOLD; + + /* CHECK FOR NEAR SINGULAR */ + if( ABS_PIVOT < 1.0E-10 ){ + for(j=k+1; j<n+1; j++){ + B[ROW[k]*m+j] = 0.0; + } +// jwy printf("redundant row (singular) %d \n", ROW[k]); + } /* singular, delete row */ + else{ + + /* REDUCE ABOUT PIVOT */ + for(j=k+1; j<n+1; j++){ + B[ROW[k]*m+j] = B[ROW[k]*m+j] / B[ROW[k]*m+k]; + } + + /* INNER REDUCTION LOOP */ + for(i=0; i<n; i++){ + if( i != k){ + for(j=k+1; j<n+1; j++){ + B[ROW[i]*m+j] = B[ROW[i]*m+j] - B[ROW[i]*m+k] * B[ROW[k]*m+j]; + } + } + } + } + /* FINISHED INNER REDUCTION */ + } + + /* END OF MAIN REDUCTION LOOP */ + /* BUILD X FOR RETURN, UNSCRAMBLING ROWS */ + for(i=0; i<n; i++){ + X[i] = B[ROW[i]*m+n]; + } + free(B); + free(ROW); +} /* end simeq */ + + +void fit_file(int n, uint8_t version, double C[], ivrm_cal_data_t* cal_data) +{ + int i, j, k; + int points; + double y; + double Vd, Vs; +// jwy double Vg; + double x[30]; /* at least 2n */ + double A[2500]; + double Y[50]; + + // ----------------------------------------------------------------------------------------- + // initialize harcoded values to use for Vs & Vg for version1 + // version1 specifies Vd &Vs as uV and 16 bits is not enough to specify values about 65 mV + // ----------------------------------------------------------------------------------------- + double Vs_v1[13]; + double Vd_v1[13]; + Vd_v1[0] = 700; Vs_v1[0] = 888; + Vd_v1[1] = 831; Vs_v1[1] = 1033; + Vd_v1[2] = 787; Vs_v1[2] = 1033; + Vd_v1[3] = 718; Vs_v1[3] = 1033; + Vd_v1[4] = 962; Vs_v1[4] = 1179; + Vd_v1[5] = 918; Vs_v1[5] = 1179; + Vd_v1[6] = 850; Vs_v1[6] = 1179; + Vd_v1[7] = 750; Vs_v1[7] = 1179; + Vd_v1[8] = 1093; Vs_v1[8] = 1325; + Vd_v1[9] = 1050; Vs_v1[9] = 1325; + Vd_v1[10] = 981; Vs_v1[10] = 1325; + Vd_v1[11] = 881; Vs_v1[11] = 1325; + Vd_v1[12] = 731; Vs_v1[12] = 1325; + + points = cal_data->point_valid; + + for(i=0; i<n; i++) + { + for(j=0; j<n; j++) + { + A[i*n+j] = 0.0; + } + Y[i] = 0.0; + } + + x[0]=1.0; + + for (k = 0; k <= points-1; k++) { + + if (version == 0) { + Vd = Vd_v1[k]; + Vs = Vs_v1[k]; +// jwy Vg = (double)cal_data->point[k].gate_voltage/1000; // uV + y = ((double)cal_data->point[k].drain_current)/1000; // uA + } + else if (version == 1 || version == 2){ + Vd = (double)cal_data->point[k].drain_voltage; // mV + Vs = (double)cal_data->point[k].source_voltage; // mV +// jwy Vg = (double)cal_data->point[k].gate_voltage/1000; // uV + y = ((double)cal_data->point[k].drain_current)/1000; // uA + } + else { //simulation data + Vd = (double)cal_data->point[k].drain_voltage; // mV + Vs = (double)cal_data->point[k].source_voltage; // mV +// jwy Vg = (double)cal_data->point[k].gate_voltage; // mV + y = ((double)cal_data->point[k].drain_current)/1000; // uA + } + +// jwy printf (" %f %f %f %f\n", Vd, Vs, Vg, y ); + + x[1]=Vs/1.11; // x[1] = target Vin = Vgs / 1.11 + x[2]=Vs/1.11-Vd; // x[2] = target Vds = Vin/1.11 - Vout = Vs/1.11 - Vd + x[3]=x[1]*x[2]; // x[3] = Vin*Vds + +// jwy if (Vg>20) { printf("ERROR: gate voltage > 20mV: current=%lf, Vd=%lf, Vs=%lf, Vg=%lf\n", y, Vd, Vs, Vg); } + + for(i=0; i<n; i++) { + for(j=0; j<n; j++) { + A[i*n+j] = A[i*n+j] + x[i]*x[j]; + } + Y[i] = Y[i] + y*x[i]; + } + } + + simeq(n, A, Y, C); + +// jwy for(i=0; i<n; i++) printf("C[%d]=%g \n", i, C[i]); +} /* end fit_file */ + +// jwy void dec2bin(int h, int n) { +// jwy int i; +// jwy char b[12]; +// jwy if (n>12) { n = 12; } +// jwy for( i = n-1; i >= 0; i--) { +// jwy if( (1 << i) & h) { +// jwy b[n - i] = '1'; +// jwy printf("%c",b[n-i]); +// jwy } else { +// jwy b[n - i] = '0'; +// jwy printf("%c",b[n-i]); +// jwy } +// jwy } +// jwy +// jwy b[n] = 0; // ascii terminating character +// jwy } + + +void write_HWtab_bin(ivrm_parm_data_t* i_ivrm_parms, + double C[], + PstateSuperStructure* pss) +{ + int i, j; + double VIN_MIN; + double VDS_MIN; + double Vin[40]; /* at least 2n */ + double Vds[40]; + int NUM_VIN; + int NUM_VDS; + double LSB_CURRENT; + double TEMP_UPLIFT; + double Ical[40][40]; + double Iratio[40][40]; + uint8_t Iratio_int[40][40]; + int temp; + uint8_t ratio_val; + uint8_t idx; + + NUM_VIN = i_ivrm_parms->vin_entries_per_vds; + NUM_VDS = i_ivrm_parms->vds_region_entries; + VIN_MIN = 800; + VDS_MIN = 100; + LSB_CURRENT = 4.1; + TEMP_UPLIFT = 1.1; + + for(i=0; i<NUM_VIN; i++) { Vin[i] = VIN_MIN + i * 25; } + + Vds[0]=VDS_MIN; + for(i=1; i<NUM_VDS; i++) { + temp=(int) (Vds[i-1]*1.25/6.25); + Vds[i] = temp*6.25 ; + } + +// jwy printf("\t"); +// jwy for(i=0; i<NUM_VDS; i++) { printf("%lf\t", Vds[i]); } +// jwy printf("\n"); + + for(i=0; i<NUM_VIN; i++) { +// jwy printf("%lf\t", Vin[i]); + + for (j=0; j<NUM_VDS; j++) { + if(Vin[i]-Vds[j]>=700) { + Ical[i][j] = C[0] + C[1]*Vin[i] + C[2]*Vds[j] + C[3]*Vin[i]*Vds[j]; // compute cal current + Iratio[i][j] = TEMP_UPLIFT * LSB_CURRENT / Ical[i][j]; + + temp = (int) (Iratio[i][j]+1/16>3.875 ? 3.875 : Iratio[i][j]+1/16); +// jwy dec2bin(temp, 2); + ratio_val = 0; + ratio_val = (temp << 3) & 0x018; // jwy shift temp left 3 and clear out lower 3 bits - this gets bits 0:1 of value + //printf("."); + + temp = (int) ((Iratio[i][j] - temp)*8 + 0.5); +// jwy dec2bin(temp, 3); + ratio_val = (temp & 0x07)| ratio_val; // jwy OR lower 3 bits of temp with upper 2 bits already in 0:1 - this merges bits 2:4 with 0:1 for final value + Iratio_int[i][j] = ratio_val; +// printf(" %u",ratio_val); +// jwy printf("\t"); + } else { + Iratio[i][j] = 0; + Iratio_int[i][j] = 0; +// jwy printf("0*\t"); + } + //printf("%lf\t", Iratio[i][j]); + } +// jwy printf("\n"); + } + +// jwy for (i=0; i<NUM_VDS; i++) { +// jwy +// jwy for(j=0; j<NUM_VIN; j++) { +// jwy printf("%u ",Iratio_int[i][j]); +// jwy } +// jwy printf("\n"); +// jwy } + + + // fill in Vin table with Iratio data + for (i=0; i<NUM_VDS; i++) { // 16 rows + + for(j=0; j<4; j++) { // 32 cols + idx = (i*4) + j; + pss->lpsa.vdsvin[idx].fields.pfet0 = Iratio_int[j*8][i]; + pss->lpsa.vdsvin[idx].fields.pfet1 = Iratio_int[(j*8)+1][i]; + pss->lpsa.vdsvin[idx].fields.pfet2 = Iratio_int[(j*8)+2][i]; + pss->lpsa.vdsvin[idx].fields.pfet3 = Iratio_int[(j*8)+3][i]; + pss->lpsa.vdsvin[idx].fields.pfet4 = Iratio_int[(j*8)+4][i]; + pss->lpsa.vdsvin[idx].fields.pfet5 = Iratio_int[(j*8)+5][i]; + pss->lpsa.vdsvin[idx].fields.pfet6 = Iratio_int[(j*8)+6][i]; + pss->lpsa.vdsvin[idx].fields.pfet7 = Iratio_int[(j*8)+7][i]; + +// jwy for (k=0; k<8; k++) { +// jwy printf("%u ", Iratio_int[(j*8)+k][i]); +// jwy } +// jwy printf("\n"); +// jwy printf(" Vin[%d]{%d,%d}: %016llX\n", idx, i, j, pss->lpsa.vdsvin[idx].value); + + + // Byte reverse the entry into the image. + pss->lpsa.vdsvin[idx].value = revle64(pss->lpsa.vdsvin[idx].value); + } + } +} /* end fit_file */ |