-
Notifications
You must be signed in to change notification settings - Fork 0
/
memory.c
executable file
·403 lines (336 loc) · 11.7 KB
/
memory.c
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
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
#include "memory.h"
/*****************************************************************************
*
* Simple SRAM Dynamic Memory Allocation
*
*****************************************************************************
* FileName: sralloc.c
* Dependencies:
* Processor: PIC18F with CAN
* Compiler: C18 02.20.00 or higher
* Linker: MPLINK 03.40.00 or higher
* Company: Microchip Technology Incorporated
*
* Software License Agreement
*
* The software supplied herewith by Microchip Technology Incorporated
* (the "Company") is intended and supplied to you, the Company's
* customer, for use solely and exclusively with products manufactured
* by the Company.
*
* The software is owned by the Company and/or its supplier, and is
* protected under applicable copyright laws. All rights are reserved.
* Any use in violation of the foregoing restrictions may subject the
* user to criminal sanctions under applicable laws, as well as to
* civil liability for the breach of the terms and conditions of this
* license.
*
* THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES,
* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
* TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
* IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
*
* This is a simple dynamic memory allocation module. The following are the
* supported services:
*
* unsigned char * NEAR SRAMalloc(NEAR unsigned char nBytes)
* void SRAMfree(unsigned char * NEAR pSRAM)
* void SRAMInitHeap(void)
*
* This version of the dynamic memory allocation limits the segment size
* to 126 bytes. This is specifically designed such to enable better
* performance by limiting pointer manipulation.
*
*
* How it works:
* The model is based on a simple form of a linked list. A block of memory
* refered to as the dynamic heap is split into segments. Each segment
* has a single byte header that references the next segment in the list
* as well as indicating whether the segment is allocated. Consiquently
* the reference implicitly identifies the length of the segment.
*
* This method also enables the possibility of allowing a large number
* of memory allocations. The maximum is limited by the defined heap size.
*
* SRAMalloc() is used to split or merge segments to be allocated.
* SRAMfree() is used to release segments.
*
* Example:
* ----------
* | 0x7F | 0x200 Header Seg1
* | |
* | |
* | |
* | |
* | |
* | |
* | 0x89 | 0x27F Header Seg2 (allocated)
* | |
* | |
* | 0x77 | 0x288 Header Seg3
* | |
* | |
* | |
* | |
* | |
* | |
* | |
* | 0x00 | 0x2FF Tail
* ----------
*
*
* Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
*
* Alloc ------------- reference to next Header --------------
*
*
* Recomendations:
* Although this model will allow dynamic allocation down to a single byte,
* doing so sacrifices performance. With more segments within the heap, more
* time is required to attempt to allocate memory. Plus every segment requires
* a header byte; therefore, smaller segments require more memory. There is
* also the possibility of fragmentation, which could ultimately doom an
* application by reducing the largest allocatable block of memory. Thus the
* recomendation is to allocate at least 8 bytes of memory.
*
*
*
* Author Date Version Comment
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Ross Fosler 05/25/03 v1.03 ... First release
*
*****************************************************************************/
/*********************************************************************
* Segment header data type
********************************************************************/
typedef union _SALLOC
{
unsigned char byte;
struct _BITS
{
unsigned count:7;
unsigned alloc:1;
}bits;
}SALLOC;
/*********************************************************************
* Reserve the memory heap
********************************************************************/
#pragma udata _SRAM_ALLOC_HEAP
unsigned char _uDynamicHeap[MAX_HEAP_SIZE];
/*********************************************************************
* Set the memory type
********************************************************************/
#if defined(NEAR_MODEL)
#pragma udata access _SRAM_ALLOC
#else
#pragma udata _SRAM_ALLOC
#endif
/*********************************************************************
* Private function declarations
********************************************************************/
NEAR unsigned char _SRAMmerge(SALLOC * NEAR pSegA);
/*********************************************************************
* Function: unsigned char * SRAMalloc(unsigned char length)
*
* PreCondition: A memory block must be allocated in the linker,
* and the memory headers and tail must already be
* set via the function SRAMInitHeap().
*
* Input: unsigned char nBytes - Number of bytes to allocate.
*
* Output: unsigned char * - A pointer to the requested block
* of memory.
*
* Side Effects:
*
* Overview: This functions allocates a chunk of memory from
* the heap. The maximum segment size for this
* version is 126 bytes. If the heap does not have
* an available segment of sufficient size it will
* attempt to create a segment; otherwise a NULL
* pointer is returned. If allocation is succeessful
* then a pointer to the requested block is returned.
*
* Note: The calling function must maintain the pointer
* to correctly free memory at runtime.
********************************************************************/
unsigned char * NEAR SRAMalloc(NEAR unsigned char nBytes)
{
SALLOC * NEAR pHeap;
SALLOC * NEAR temp;
NEAR SALLOC segHeader;
NEAR unsigned char segLen;
// Do not allow allocation above the max minus one bytes
if (nBytes > (_MAX_SEGMENT_SIZE - 1)) return (0);
// Init the pointer to the heap
pHeap = (SALLOC *)_uDynamicHeap;
while (1)
{
// Get the header of the segment
segHeader = *pHeap;
// Extract the segment length from the segment
segLen = segHeader.bits.count - 1;
// A null segment indicates the end of the table
if (segHeader.byte == 0) return (0);
// If this segment is not allocated then attempt to allocate it
if (!(segHeader.bits.alloc))
{
// If the free segment is too small then attempt to merge
if (nBytes > segLen)
{
// If the merge fails them move on to the next segment
if (!(_SRAMmerge(pHeap))) pHeap += segHeader.bits.count;
}
else
// If the segment length matches the request then allocate the
// header and return the pointer
if (nBytes == segLen)
{
// Allocate the segment
(*pHeap).bits.alloc = 1;
// Return the pointer to the caller
return ((unsigned char *)(pHeap + 1));
}
// Else create a new segment
else
{
// Reset the header to point to a new segment
(*pHeap).byte = nBytes + 0x81;
// Remember the pointer to the first segment
temp = pHeap + 1;
// Point to the new segment
pHeap += (nBytes + 1);
// Insert the header for the new segment
(*pHeap).byte = segLen - nBytes;
// Return the pointer to the user
return ((unsigned char *) temp);
}
}
// else set the pointer to the next segment header in the heap
else
{
pHeap += segHeader.bits.count;
}
}
}
/*********************************************************************
* Function: void SRAMfree(unsigned char * pSRAM)
*
* PreCondition: The pointer must have been returned from a
* previously allocation via SRAMalloc().
*
* Input: unsigned char * pSRAM - pointer to the allocated
*
* Output: void
*
* Side Effects:
*
* Overview: This function de-allocates a previously allocated
* segment of memory.
*
* Note: The pointer must be a valid pointer returned from
* SRAMalloc(); otherwise, the segment may not be
* successfully de-allocated, and the heap may be
* corrupted.
********************************************************************/
void SRAMfree(unsigned char * NEAR pSRAM)
{
// Release the segment
(*(SALLOC *)(pSRAM - 1)).bits.alloc = 0;
}
/*********************************************************************
* Function: void SRAMInitHeap(void)
*
* PreCondition:
*
* Input: void
*
* Output: void
*
* Side Effects:
*
* Overview: This function initializes the dynamic heap. It
* inserts segment headers to maximize segment space.
*
* Note: This function must be called at least one time.
* And it could be called more times to reset the
* heap.
********************************************************************/
void SRAMInitHeap(void)
{
unsigned char * NEAR pHeap;
NEAR unsigned int count;
pHeap = _uDynamicHeap;
count = _MAX_HEAP_SIZE;
while (1)
{
if (count > _MAX_SEGMENT_SIZE)
{
*pHeap = _MAX_SEGMENT_SIZE;
pHeap += _MAX_SEGMENT_SIZE;
count = count - _MAX_SEGMENT_SIZE;
}
else
{
*pHeap = count;
*(pHeap + count) = 0;
return;
}
}
}
/*********************************************************************
* Function: unsigned char _SRAMmerge(SALLOC * NEAR pSegA)
*
* PreCondition:
*
* Input: SALLOC * NEAR pSegA - pointer to the first segment.
*
* Output: usnigned char - returns the length of the
* merged segment or zero if failed to merge.
*
* Side Effects:
*
* Overview: This function tries to merge adjacent segments
* that have not been allocated. The largest possible
* segment is merged if possible.
*
* Note:
********************************************************************/
NEAR unsigned char _SRAMmerge(SALLOC * NEAR pSegA)
{
SALLOC * NEAR pSegB;
NEAR SALLOC uSegA, uSegB, uSum;
// Init the pointer to the heap
pSegB = pSegA + (*pSegA).byte;
// Extract the headers for faster processing
uSegA = *pSegA;
uSegB = *pSegB;
// Quit if the tail has been found
if (uSegB.byte == 0) return (0);
// If either segment is allocated then do not merge
if (uSegA.bits.alloc || uSegB.bits.alloc) return (0);
// If the first segment is max then nothing to merge
if (uSegA.bits.count == _MAX_SEGMENT_SIZE) return (0);
// Get the sum of the two segments
uSum.byte = uSegA.byte + uSegB.byte;
// If the sum of the two segments are > than the largest segment
// then create a new segment equal to the max segment size and
// point to the next segments
if ((uSum.byte) > _MAX_SEGMENT_SIZE)
{
(*pSegA).byte = _MAX_SEGMENT_SIZE;
pSegA += _MAX_SEGMENT_SIZE; //(*pSeg1).byte;
pSegB += uSegB.byte; //(*pSeg2).byte ;
(*pSegA).byte = pSegB - pSegA;
return (_MAX_SEGMENT_SIZE);
}
// Else combine the two segments into one segment and
// do not adjust the pointers to the next segment
else
{
return ((*pSegA).byte = uSum.byte);
}
}