summaryrefslogtreecommitdiffstats
path: root/src/usr/ecmddatabuffer/ecmdDataBuffer.C
blob: b28a1d3e0b675fb92176d8fab69bc6637737d9c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/**
 * @file ecmdDataBuffer.C
 * @brief Provides a means to handle data from the eCMD C API
 *
 ********************************************************************
 * @todo - This is only a temporary file created to compile code.
 * We will use John Farrugia's version
 *********************************************************************
 */

//----------------------------------------------------------------------
//  Includes
//----------------------------------------------------------------------
#include <stdint.h>
#include <string.h>
#include <trace/interface.H>
#include <ecmdDataBuffer.H>

#define EDB_ADMIN_TOTAL_SIZE 2
#define EDB_ADMIN_HEADER_SIZE 1
#define EDB_ADMIN_FOOTER_SIZE 1
#define EDB_ADMIN_TOTAL_SIZE 2
#define EDB_RETURN_CODE 0
#define EDB_RANDNUM 0x12345678
#define ECMD_DBUF_BUFFER_OVERFLOW           (ECMD_ERR_ECMD | 0x2011)

// Trace definition
trace_desc_t* g_trac_ecmd = NULL;
TRAC_INIT(&g_trac_ecmd, "ECMD", 4096);

//---------------------------------------------------------------------
//  Constructors
//---------------------------------------------------------------------
ecmdDataBufferBase::ecmdDataBufferBase()  // Default constructor
: iv_Capacity(0), iv_NumBits(0), iv_Data(NULL), iv_RealData(NULL)
{
    iv_UserOwned = true;
}

ecmdDataBufferBase::ecmdDataBufferBase(uint32_t i_numBits)
: iv_Capacity(0), iv_NumBits(0), iv_Data(NULL), iv_RealData(NULL)
{
    iv_UserOwned = true;
    if (i_numBits > 0)
    {
      setBitLength(i_numBits);
    }
}

//---------------------------------------------------------------------
//  Destructor
//---------------------------------------------------------------------
ecmdDataBufferBase::~ecmdDataBufferBase()
{
    // Only call clear() if buffer is owned by this user (ie, not shared)
    if (iv_UserOwned)
    {
        clear();
    }
}

uint32_t ecmdDataBufferBase::getWordLength() const
{
    return (iv_NumBits + 31) / 32;
}

uint32_t ecmdDataBufferBase::flushTo0()
{
  uint32_t rc = ECMD_DBUF_SUCCESS;
  if (getWordLength() > 0)
  {
    memset(iv_Data, 0x00, getWordLength() * 4); /* init to 0 */
  }
  return rc;
}


uint32_t ecmdDataBufferBase::clear() {
  uint32_t rc = ECMD_DBUF_SUCCESS;

  if (iv_RealData != NULL)
  {
    /* That looked okay, reset everything else */
    /* Only do the delete if we alloc'd something */
    if (iv_RealData != iv_LocalData)
    {
        delete[] iv_RealData;
    }
    iv_RealData = NULL;
    iv_Capacity = 0;
    iv_NumBits = 0;
  }
  return rc;
}

uint32_t ecmdDataBufferBase::setCapacity(uint32_t i_newCapacity) {
  uint32_t rc = ECMD_DBUF_SUCCESS;

  if(!iv_UserOwned) {
    TRACFCOMP(g_trac_ecmd, "**** ERROR (ecmdDataBuffer) : Attempt to modify non user owned buffer size.");
    return 0;
  }

  /* for case where i_newCapacity is 0 (like in unflatten) use iv_LocalData for iv_RealData */
  /* This allows for iv_Data, the header, and the tail to be setup right */
  if (iv_Capacity == 0) {
      /* We are using iv_LocalData, so point iv_RealData to the start of that */
      iv_RealData = iv_LocalData;
  }

  /* only resize to make the capacity bigger */
  if (iv_Capacity < i_newCapacity) {
    iv_Capacity = i_newCapacity;

    /* Now setup iv_RealData */
    if (iv_Capacity <= 2) {
      /* We are using iv_LocalData, so point iv_RealData to the start of that */
      iv_RealData = iv_LocalData;
    } else {
      /* If we are going from <= 64 to > 64, there was no malloc done so can't do delete */
      if ((iv_RealData != NULL) && (iv_RealData != iv_LocalData)) {
        delete[] iv_RealData;
      }
      iv_RealData = NULL;

      iv_RealData = new uint32_t[iv_Capacity + EDB_ADMIN_TOTAL_SIZE];
      if (iv_RealData == NULL) {
        TRACFCOMP(g_trac_ecmd, "**** ERROR : ecmdDataBuffer::setCapacity : Unable to allocate memory for new databuffer");
        return 0;
      }
    }
  }

  /* Now setup iv_Data to point into the offset inside of iv_RealData */
  iv_Data = iv_RealData + EDB_ADMIN_HEADER_SIZE;

  /* We are all setup, now init everything to 0 */
  /* We want to do this regardless of if the buffer was resized. */
  /* This function is meant to be a destructive operation */
  /* Ok, now setup the header, and tail */
  iv_RealData[EDB_RETURN_CODE] = 0; ///< Reset error code
  iv_RealData[getWordLength() + EDB_ADMIN_HEADER_SIZE] = EDB_RANDNUM;

  rc = flushTo0();
  if (rc) return rc;

  return rc;
}

uint32_t ecmdDataBufferBase::setBitLength(uint32_t i_newNumBits) {
  uint32_t rc = ECMD_DBUF_SUCCESS;

  if ((i_newNumBits == 0) && (iv_NumBits == 0)) {
    // Do Nothing:  this data doesn't already have iv_RealData,iv_Data defined, and it doesn't want to define it
    return rc;
  }

  /* Assign i_newNumBits to iv_NumBits and figure out how many words that is */
  iv_NumBits = i_newNumBits;

  /* Now call setCapacity to do all the data buffer resizing and setup */
  rc = setCapacity(getWordLength());
  if (rc) return rc;

  return rc;
}

uint32_t ecmdDataBufferBase::setDoubleWord(uint32_t i_doublewordoffset, uint64_t i_value)
{
    uint32_t rc = ECMD_DBUF_SUCCESS;
    if (i_doublewordoffset >= ((getWordLength()+1)/2))
    {
        TRACFCOMP(g_trac_ecmd, "**** ERROR : ecmdDataBuffer::setDoubleWord: doubleWordOffset %d >= NumDoubleWords (%d)",
               i_doublewordoffset, ((getWordLength()+1)/2));
        return (ECMD_DBUF_BUFFER_OVERFLOW);
    }

     // Create mask if part of this byte is not in the valid part of the ecmdDataBuffer
    if (((i_doublewordoffset + 1) == ((getWordLength()+1)/2)) && (iv_NumBits % 64))
    {
        uint64_t bitMask = 0xFFFFFFFFFFFFFFFFul;
        /* Shift it left by the amount of unused bits */
        bitMask <<= ((64 * ((getWordLength()+1)/2)) - iv_NumBits);
        /* Clear the unused bits */
        i_value &= bitMask;
    }
    uint32_t hivalue = (uint32_t)((i_value & 0xFFFFFFFF00000000ul) >> 32);
    uint32_t lovalue = (uint32_t)((i_value & 0x00000000FFFFFFFFul));

    iv_Data[i_doublewordoffset*2] = hivalue;
    /* Don't set the second word if we are on oddwords */
    if (!((i_doublewordoffset*2)+1 >= getWordLength()) ) {
        iv_Data[(i_doublewordoffset*2)+1] = lovalue;
    }
    return rc;
}

uint64_t ecmdDataBufferBase::getDoubleWord(uint32_t i_doublewordoffset) const
{
    // Round up to the next word and check length
    if (i_doublewordoffset >= ((getWordLength()+1)/2))
    {
        TRACFCOMP(g_trac_ecmd, "**** ERROR : ecmdDataBuffer::getDoubleWord: doubleWordOffset %d >= NumDoubleWords (%d)",
                i_doublewordoffset, ((getWordLength()+1)/2));
        return 0;
    }
    uint64_t ret;
    ret = ((uint64_t)(iv_Data[i_doublewordoffset*2])) << 32;
    // If we have an odd length of words we can't pull the second word if we are at the end
    if (!((i_doublewordoffset*2)+1 >= getWordLength()) ) {
        ret |= iv_Data[(i_doublewordoffset*2)+1];
    }
    return ret;
}

OpenPOWER on IntegriCloud