summaryrefslogtreecommitdiffstats
path: root/tools/image/p9_scan_compression.H
blob: 2f1e285dabee711ccc8bbde98e493ca3d8ac5c2e (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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
#ifndef __P9_SCAN_COMPRESSION_H__
#define __P9_SCAN_COMPRESSION_H__

/// This header declares and documents the entry points defined in
/// p9_scan_compression.C.  Some constants are also required by the scan
/// decompression HOMER assembly procedures.

#include "fapi_sbe_common.H"

#ifndef __ASSEMBLER__

#include <stdint.h>

/// Compressed Scan Chain Data Structure Format
///
/// The compressed scan ring data structure must be 8-byte aligned in
/// memory. The container data structure consists of this 24-byte header
/// followed by an arbitrary number of 8 byte doublewords containing the
/// compressed scan data.  Images are always stored and processed in
/// big-endian byte order.  This container format is common across all
/// decompression algorithms.
///
/// Bytes - Content
/// 
/// 0:3 - A 32-bit "magic number" that identifies and validates the
/// compression algorithm and algorithm version used to compress the data.
///
/// 4:7 - The 32-bit size of the entire data structure in \e bytes.  This
/// consists of this 24-byte header plus the compressed scan data.  This value
/// is always a multiple of 8.
///
/// 8:11 - This 32-bit value is reserved to the compression
/// algorithm. Typically this field is used to record the 'size' of the
/// compressed string in units specific to each algorithm.
///
/// 12:15 - The length of the original scan chain in \e bits.
///
/// 16:19 - The 32 high-order bits of the value written to the Scan Select
/// register to set up the scan.  The Scan Select register only defines these
/// bits. 
///
/// 20 - The Scan Chain Data Structure version number
///
/// 21 - Flush-optimize : Is this byte is non-zero, the ring state to be
/// modified is the flush state of the ring.
///
/// 22 - The ring ID uniquely identifying the repair ring name.
///
/// 23 - The 7-bit pervasive chiplet Id + Multicast bit of the chiplet to
/// scan.  This value is loaded directly into P0.  The decompression
/// algorithms provide two entry points - one that uses this value as the
/// chiplet Id, and another that allows the caller to specify the chiplet Id
/// in the call.

typedef struct {

    /// Magic number - See \ref scan_compression_magic
    uint32_t iv_magic;

    /// Total size in bytes, including the container header
    uint32_t iv_size;

    /// Reserved to the algorithm
    uint32_t iv_algorithmReserved;

    /// Length of the original scan chain in bits
    uint32_t iv_length;

    /// The high-order 32 bits of the Scan Select Register
    ///
    /// Note that the Scan Select register only defines the high order 32
    /// bits, so we only need store the 32 high-order bits.  This field is
    /// 8-byte aligned so that the doubleword loaded by the HOMER can be
    /// directly written to the scan select register.
    uint32_t iv_scanSelect;

    /// Data structure (header) version
    uint8_t iv_headerVersion;

    /// Flush-state optimization
    ///
    /// Normally, modifying the state of the ring requires XOR-ing the
    /// difference state (the compressed state) with the current ring state as
    /// it will appear in the Scan Data Register. If the current state of the
    /// ring is the scan-0 flush state, then by definition the Scan Data
    /// Register is always 0. Therefore we can simply write the difference to
    /// the Scan Data Register rather than using a read-XOR-write.
    uint8_t iv_flushOptimization;

    /// Ring ID uniquely identifying the repair name. (See the list of ring
		/// name vs ring IDs in p8_ring_identification.c).
    uint8_t iv_ringId;

    /// 7-bit pervasive chiplet Id + Multicast bit
    ///
    /// This field is right-justified in an 8-byte aligned doubleword so that
    /// the P0 register can be directly updated from the doubelword value in a
    /// data register.
    uint8_t iv_chipletId;

} CompressedScanData;


/// Endian-translate a CompressedScanData structure
///
/// \param o_data A pointer to a CompressedScanData structure to receive the
/// endian-translated form of \a i_data.
///
/// \param i_data A pointer to the original CompressedScanData structure.
///
/// This API performs an endian-converting copy of a CompressedScanData
/// structure. This copy is guaranteed to be done in such a way that \a i_data
/// and \a o_data may be the same pointer for in-place conversion.  Due to the
/// symmetry of reverse, translating a structure twice is always guaranteed to
/// return the origial structure to its original byte order.
void
compressed_scan_data_translate(CompressedScanData* o_data,
                               CompressedScanData* i_data);


/// Compress a scan string using the RS4 compression algorithm
///
/// \param[in,out] io_data This is a pointer to a memory area which must be
/// large enough to hold the worst-case result of compressing \a i_string (see
/// below).  Note that the CompressedScanData is always created in big-endian
/// format, however the caller can use compresed_scan_data_translate() to
/// create a copy of the header in host format.
///
/// \param[in] i_dataSize The size of \a io_data in bytes.
///
/// \param[out] o_imageSize The effective size of the entire compressed scan
/// data structure (header + compressed data) created in \a io_data, in bytes.
/// This value will always be a multiple of 8.
///
/// \param[in] i_string The string to compress.  Scan data to compress is
/// left-justified in this input string.
///
/// \param[in] i_length The length of the input string in \e bits.  It is
/// assumed the \a i_string contains at least (\a i_length + 7) / 8 bytes.
///
/// \param[in] i_scanSelect The 64-bit value written to the Scan Select
/// register to set up for the scan. Only the 32 high-order bits are actually
/// stored.
///
/// \param[in] i_ringId The ring ID that uniquely identifies the ring name of
/// a repair ring. (See p8_ring_identification.c for more info.)
///
/// \param[in] i_chipletId The 7-bit value for the iv_chipletId field of the
/// CompressedScanData.
///
/// \param[in] i_flushOptimization This input parameter should be set to a
/// non-0 value if it is known that this ring difference will be applied to a
/// scan-0 flush state.  This will improve the performance of the
/// decompress-scan routine. If the initial state of the ring is unknown, set
/// this parameter to 0.
///
/// This API is required for integration with PHYP which does not support
/// malloc().  Applications in environments supporting malloc() can use
/// rs4_compress() instead.
///
/// The worst-case compression for RS4 requires 2 nibbles of control overhead
/// per 15 nibbles of data (17/15), plus a maximum of 2 nibbles of termination.
/// We always require this worst-case amount of memory including the header and
/// any rounding required to guarantee that the data size is a multiple of 8
/// bytes.  The final image size is also rounded up to a multiple of 8 bytes.
/// If the \a i_dataSize is less than this amount (based on \a i_length) the
/// call will fail.
///
/// \returns See \ref scan_compression_codes
int
_rs4_compress(CompressedScanData* io_data,
              uint32_t i_dataSize,
              uint32_t* o_imageSize,
              const uint8_t* i_string, 
              const uint32_t i_length,
              const uint64_t i_scanSelect,
              const uint8_t i_ringId,
              const uint8_t i_chipletId,
              const uint8_t i_flushOptimization);
             

/// Compress a scan string using the RS4 compression algorithm
///
/// \param[out] o_data This algorithm uses malloc() to allocate memory for the
/// compresed data, and returns a pointer to this memory in \a o_data. After
/// the call this memory is owned by the caller who is responsible for
/// free()-ing the data area once it is no longer required. Note that the
/// CompressedScanData is always created in big-endian format, however the
/// caller can use compresed_scan_data_translate() to create a copy of the
/// header in host format.
///
/// \param[out] o_size The effective size of the entire compressed scan data
/// structure (header + compressed data) pointed to by \a o_data, in bytes.
/// This value will always be a multiple of 8.
///
/// \param[in] i_string The string to compress.  Scan data to compress is
/// left-justified in this input string.
///
/// \param[in] i_length The length of the input string in \e bits.  It is
/// assumed the \a i_string contains at least (\a i_length + 7) / 8 bytes.
///
/// \param[in] i_scanSelect The 64-bit value written to the Scan Select
/// register to set up for the scan. Only the 32 high-order bits are actually
/// stored.
///
/// \param[in] i_ringId The ring ID that uniquely identifies the ring name of
/// a repair ring. (See p8_ring_identification.c for more info.)
///
/// \param[in] i_chipletId The 7-bit value for the iv_chipletId field of the
/// CompressedScanData.
///
/// \param[in] i_flushOptimization This input parameter should be set to a
/// non-0 value if it is known that this ring difference will be applied to a
/// scan-0 flush state.  This will improve the performance of the
/// decompress-scan routine. If the initial state of the ring is unknown, set
/// this parameter to 0.
///
/// \returns See \ref scan_compression_codes
int
rs4_compress(CompressedScanData** o_data,
             uint32_t* o_size,
             const uint8_t* i_string, 
             const uint32_t i_length,
             const uint64_t i_scanSelect,
             const uint8_t i_ringId,
             const uint8_t i_chipletId,
             const uint8_t i_flushOptimization);
             

/// Decompress a scan string compressed using the RS4 compression algorithm
///
/// \param[in,out] io_string A caller-supplied data area to contain the
/// decompressed string. The \a i_stringSize must be large enough to contain
/// the decompressed string, which is the size of the original string in bits
/// rounded up to the nearest byte.
///
/// \param[in] i_stringSize The size (in bytes) of \a i_string.
///
/// \param[out] o_length The length of the decompressed string in \e bits.
///
/// \param[in] i_data A pointer to the CompressedScanData header + data to be
/// decompressed.
///
/// This API is required for integration with PHYP which does not support
/// malloc().  Applications in environments supporting malloc() can use
/// rs4_decompress() instead.
///
/// \returns See \ref scan_compression_codes
int
_rs4_decompress(uint8_t* i_string,
                uint32_t i_stringSize,
                uint32_t* o_length,
                const CompressedScanData* i_data);
             

/// Decompress a scan string compressed using the RS4 compression algorithm
///
/// \param[out] o_string The API malloc()-s this data area to contain the
/// decompressed string. After this call the caller owns \a o_string and is
/// responsible for free()-ing this data area once it is no longer required.
///
/// \param[out] o_length The length of the decompressed string in \e bits.
/// The caller may assume that \a o_string contains at least (\a o_length + 7)
/// / 8 \e bytes.
///
/// \param[in] i_data A pointer to the CompressedScanData header + data to be
/// decompressed.
///
/// \returns See \ref scan_compression_codes
int
rs4_decompress(uint8_t** o_string,
               uint32_t* o_length,
               const CompressedScanData* i_data);


/// Determine if an RS4 compressed scan string is all 0
///
/// \param[in] i_data A pointer to the CompressedScanData header + data to be
///
/// \param[out] o_redundant Set to 1 if the RS4 string is the compressed form
/// of a scan string that is all 0; Otherwise set to 0.
///
/// \returns See \ref scan _compression_code
int
rs4_redundant(const CompressedScanData* i_data, int* o_redundant);
             

#endif  // __ASSEMBLER__


/// The current version of the CompressedScanData structure
///
/// This constant is required to be a #define to guarantee consistency between
/// the header format and cmopiled code.
#define COMPRESSED_SCAN_DATA_VERSION 1

/// The size of the CompressedScanData structure
CONST_UINT8_T(COMPRESSED_SCAN_DATA_SIZE, 24);


/// \defgroup scan_compression_magic Scan Compression Magic Numbers
///
/// @ {

/// RS4 Magic
CONST_UINT32_T(RS4_MAGIC, 0x52533401);      /* "RS4" + Version 0x01 */

/// @}


/// \defgroup scan_compression_codes Scan Compression Return Codes
///
/// @{

/// Normal return code
CONST_UINT8_T(SCAN_COMPRESSION_OK, 0);

/// The (de)compression algorithm could not allocate enough memory for the
/// (de)compression.
CONST_UINT8_T(SCAN_COMPRESSION_NO_MEMORY, 1);

/// Magic number mismatch on scan decompression
CONST_UINT8_T(SCAN_DECOMPRESSION_MAGIC_ERROR, 2);

/// Decompression size error
///
/// Decompression produced a string of a size different than indicated in the
/// header, indicating either a bug or data corruption.  Note that the entire
/// application should be considered corrupted if this error occurs since it
/// may not be discovered until after the decompression buffer is
/// overrun. This error may also be returned by rs4_redundant() in the event
/// of inconsistencies in the compressed string.
CONST_UINT8_T(SCAN_DECOMPRESSION_SIZE_ERROR, 3);

/// A buffer would overflow
///
/// Either the caller-supplied memory buffer to _rs4_decompress() was too
/// small to contain the decompressed string, or a caller-supplied buffer to
/// _rs4_compress() was not large enough to hold the worst-case compressed
/// string.
CONST_UINT8_T(SCAN_COMPRESSION_BUFFER_OVERFLOW, 4);

/// @}

#endif  //  __P8_SCAN_COMPRESSION_H__
OpenPOWER on IntegriCloud