/*============================================================================
FILE    IDNdig.c

MEMBER OF process XSPICE

Public Domain

Georgia Tech Research Corporation
Atlanta, Georgia 30332
PROJECT A-8503

AUTHORS

    9/12/91  Bill Kuhn

MODIFICATIONS

    <date> <person name> <nature of modifications>

SUMMARY

    This file contains the definition of the 'digital' node type
    used by 12-state digital models in the code model library.
    These functions are called exclusively through function
    pointers in an Evt_Udn_Info_t data structure.

INTERFACES

    Evt_Udn_Info_t idn_digital_info

REFERENCED FILES

    None.

NON-STANDARD FEATURES

    None.

============================================================================*/

#include "ngspice/ngspice.h"

#include "ngspice/cm.h"

#include "ngspice/evtudn.h"
 
/* ************************************************************************ */

static void idn_digital_create(void **evt_struct)
{
    /* Malloc space for a digital struct */

	*evt_struct = TMALLOC(Digital_t, 1);
}


/* ************************************************************************ */

static void idn_digital_dismantle(void *evt_struct)
{
    NG_IGNORE(evt_struct);

    /* Do nothing.  There are no internally malloc'ed things to dismantle */
}


/* ************************************************************************ */

static void idn_digital_initialize(void *evt_struct)
{
    Digital_t  *dig_struct = (Digital_t *) evt_struct;


    /* Initialize to unknown state and strength */
    dig_struct->state = ZERO;
    dig_struct->strength = UNDETERMINED;
}


/* ************************************************************************ */

static void idn_digital_invert(void *evt_struct)
{
    Digital_t  *dig_struct = (Digital_t *) evt_struct;


    /* Invert the state */
    switch(dig_struct->state) {

    case ZERO:
        dig_struct->state = ONE;
        return;

    case ONE:
        dig_struct->state = ZERO;
        return;

    default:
        return;
    }

}


/* ************************************************************************ */

static void idn_digital_copy(void *evt_from_struct, void *evt_to_struct)
{
    Digital_t  *dig_from_struct = (Digital_t *) evt_from_struct;
    Digital_t  *dig_to_struct   = (Digital_t *) evt_to_struct;

    /* Copy the structure */
    dig_to_struct->state = dig_from_struct->state;
    dig_to_struct->strength = dig_from_struct->strength;
}


/* ************************************************************************ */

static void idn_digital_resolve(int num_struct,
    void **evt_struct_array, void *evt_struct)
{
    Digital_t   **dig_struct_array;
    Digital_t   *dig_struct;

    static int  map[12][12] = {
                          {  0,  2,  2,  0,  0,  0,  0,  0,  0,  0,  2,  2},
                          {  2,  1,  2,  1,  1,  1,  1,  1,  1,  2,  1,  1},
                          {  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2},
                          {  0,  1,  2,  3,  5,  5,  3,  3,  3,  9, 11, 11},
                          {  0,  1,  2,  5,  4,  5,  4,  4,  4, 11, 10, 11},
                          {  0,  1,  2,  5,  5,  5,  5,  5,  5, 10, 11, 11},
                          {  0,  1,  2,  3,  4,  5,  6,  8,  8,  9, 11, 11},
                          {  0,  1,  2,  3,  4,  5,  8,  7,  8, 11, 10, 11},
                          {  0,  1,  2,  3,  4,  5,  8,  8,  8, 11, 11, 11},
                          {  0,  2,  2,  9, 11, 11,  9, 11, 11,  9, 11, 11},
                          {  2,  1,  2, 11, 10, 11, 11, 10, 11, 11, 10, 11},
                          {  2,  1,  2, 11, 11, 11, 11, 11, 11, 11, 11, 11} };

    int i;

    int index1;
    int index2;

    /* Cast the input void pointers to pointers of the digital type */
    dig_struct = (Digital_t *) evt_struct;
    dig_struct_array = (Digital_t   **)evt_struct_array;

    /* Copy the first member of the array directly to the output */
    dig_struct->state = dig_struct_array[0]->state;
    dig_struct->strength = dig_struct_array[0]->strength;

    /* Convert struct to index into map */
    index1 = (int) (dig_struct->state + dig_struct->strength * 3);


    /* For the remaining members, perform the resolution algorithm */
    for(i = 1; i < num_struct; i++) {

        /* Convert struct to index into map */
        index2 = (int)(dig_struct_array[i]->state +
                       dig_struct_array[i]->strength * 3);

        /* Compute the result */
        index1 = map[index1][index2];
    }

    /* Convert result back to state and strength */
    dig_struct->state = (Digital_State_t) (index1 % 3);
    dig_struct->strength = (Digital_Strength_t) (index1 / 3);
}


/* ************************************************************************ */

static void idn_digital_compare(void *evt_struct1, void *evt_struct2,
    Boolean_t *equal)
{
    Digital_t  *dig_struct1 = (Digital_t *) evt_struct1;
    Digital_t  *dig_struct2 = (Digital_t *) evt_struct2;

    /* Compare the structures in order of most likely differences */
    if(dig_struct1->state != dig_struct2->state)
        *equal = FALSE;
    else if(dig_struct1->strength != dig_struct2->strength)
        *equal = FALSE;
    else
        *equal = TRUE;
}


/* ************************************************************************ */

static void idn_digital_plot_val(void *evt_struct, char *member, double *val)
{
    Digital_t   *dig_struct = (Digital_t *) evt_struct;


    /* Output a value for the requested member of the digital struct */
    if(strcmp(member,"strength") == 0) {

        /* Choose values that will not make plots lie on state plots */
        switch(dig_struct->strength) {

        case STRONG:
            *val = 0.1;
            return;

        case RESISTIVE:
            *val = 0.6;
            return;

        case HI_IMPEDANCE:
            *val = 1.1;
            return;

        case UNDETERMINED:
            *val = -0.4;
            return;
        }
    }
    else {
        /* member = "state" or anything else */

        /* Pick reasonable values */
        switch(dig_struct->state) {

        case ZERO:
            *val = 0.0;
            return;

        case ONE:
            *val = 1.0;
            return;

        case UNKNOWN:
            *val = 0.5;
            return;
        }
    }
}


/* ************************************************************************ */

static void idn_digital_print_val(void *evt_struct, char *member, char **val)
{
    Digital_t   *dig_struct = (Digital_t *) evt_struct;

    int         index;

    static char *map[] = { "0s", "1s", "Us",
                           "0r", "1r", "Ur",
                           "0z", "1z", "Uz",
                           "0u", "1u", "Uu" };


    /* Output a value for the requested member of the digital struct */

    if(strcmp(member,"state") == 0) {

        /* Pick reasonable values */
        switch(dig_struct->state) {

        case ZERO:
            *val = "0";
            return;

        case ONE:
            *val = "1";
            return;

        case UNKNOWN:
            *val = "U";
            return;

        default:
            *val = "?";
            return;
        }
    }
    else if(strcmp(member,"strength") == 0) {

        /* Choose values that will not make plots lie on state plots */
        switch(dig_struct->strength) {

        case STRONG:
            *val = "s";
            return;

        case RESISTIVE:
            *val = "r";
            return;

        case HI_IMPEDANCE:
            *val = "z";
            return;

        case UNDETERMINED:
            *val = "u";
            return;

        default:
            *val = "?";
            return;
        }
    }
    else {
        index = (int)(dig_struct->state + dig_struct->strength * 3);
        if((index < 0) || (index > 11))
            *val = "??";
        else
            *val = map[index];
        return;
    }
}



/* ************************************************************************ */

static void idn_digital_ipc_val(void *evt_struct, void **ipc_val, int *ipc_val_size)
{
    /* Return the digital data structure and its size */
    *ipc_val = evt_struct;
    *ipc_val_size = sizeof(Digital_t);
}



Evt_Udn_Info_t idn_digital_info = {

"d",
"12 state digital data",
idn_digital_create,
idn_digital_dismantle,
idn_digital_initialize,
idn_digital_invert,
idn_digital_copy,
idn_digital_resolve,
idn_digital_compare,
idn_digital_plot_val,
idn_digital_print_val,
idn_digital_ipc_val

};

