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
|
/*
* "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
* Ken Silverman's official web site: "http://www.advsys.net/ken"
* See the included license file "BUILDLIC.TXT" for license info.
* This file has been modified from Ken Silverman's original release
*/
#include "platform.h"
#include "display.h"
#include "fixedPoint_math.h"
#include "cache.h"
#include "build.h"
#include "../../Game/src/cvar_defs.h"
#include "../../Game/src/types.h"
/*
* This module keeps track of a standard linear cacheing system.
* To use this module, here's all you need to do:
*
* Step 1: Allocate a nice BIG buffer, like from 1MB-4MB and
* Call initcache(int32_t cachestart, int32_t cachesize) where
*
* cachestart = (int32_t )(pointer to start of BIG buffer)
* cachesize = length of BIG buffer
*
* Step 2: Call allocache(int32_t *bufptr, int32_t bufsiz, uint8_t *lockptr)
* whenever you need to allocate a buffer, where:
*
* *bufptr = pointer to 4-byte pointer to buffer
* Confused? Using this method, cache2d can remove
* previously allocated things from the cache safely by
* setting the 4-byte pointer to 0.
* bufsiz = number of bytes to allocate
* *lockptr = pointer to locking uint8_t which tells whether
* the region can be removed or not. If *lockptr = 0 then
* the region is not locked else its locked.
*
* Step 3: If you need to remove everything from the cache, or every
* unlocked item from the cache, you can call uninitcache();
* Call uninitcache(0) to remove all unlocked items, or
* Call uninitcache(1) to remove everything.
* After calling uninitcache, it is still ok to call allocache
* without first calling initcache.
*/
#define MAXCACHEOBJECTS 9216
static int32_t cachesize = 0;
int32_t cachecount = 0;
uint8_t zerochar = 0;
uint8_t* cachestart = NULL;
int32_t cacnum = 0, agecount = 0;
typedef struct {
uint8_t** hand;
int32_t leng;
uint8_t *lock; }
cactype;
cactype cac[MAXCACHEOBJECTS];
int32_t lockrecip[200];
// TC game directory
char game_dir[512] = "/.rockbox/duke3d";
void initcache(uint8_t* dacachestart, int32_t dacachesize)
{
int32_t i;
for(i=1;i<200;i++) lockrecip[i] = (1<<28)/(200-i);
cachestart = dacachestart;
cachesize = dacachesize;
cac[0].leng = cachesize;
cac[0].lock = &zerochar;
cacnum = 1;
}
void allocache (uint8_t** newhandle, int32_t newbytes, uint8_t *newlockptr)
{
int32_t i, z, zz, bestz=0, daval, bestval, besto=0, o1, o2, sucklen, suckz;
newbytes = newbytes+15;
if ((uint32_t)newbytes > (uint32_t)cachesize)
{
printf("Cachesize: %d\n",cachesize);
printf("*Newhandle: 0x%x, Newbytes: %d, *Newlock: %d\n",(unsigned int)newhandle,newbytes,*newlockptr);
reportandexit("BUFFER TOO BIG TO FIT IN CACHE!\n");
}
if (*newlockptr == 0)
{
reportandexit("ALLOCACHE CALLED WITH LOCK OF 0!\n");
}
/* Find best place */
bestval = 0x7fffffff; o1 = cachesize;
for(z=cacnum-1;z>=0;z--)
{
o1 -= cac[z].leng;
o2 = o1+newbytes; if (o2 > cachesize) continue;
daval = 0;
for(i=o1,zz=z;i<o2;i+=cac[zz++].leng)
{
if (*cac[zz].lock == 0) continue;
if (*cac[zz].lock >= 200) { daval = 0x7fffffff; break; }
daval += (int32_t ) mulscale32(cac[zz].leng+65536,lockrecip[*cac[zz].lock]);
if (daval >= bestval) break;
}
if (daval < bestval)
{
bestval = daval; besto = o1; bestz = z;
if (bestval == 0) break;
}
}
/*printf("%ld %ld %ld\n",besto,newbytes,*newlockptr);*/
if (bestval == 0x7fffffff)
reportandexit("CACHE SPACE ALL LOCKED UP!\n");
/* Suck things out */
for(sucklen=-newbytes,suckz=bestz;sucklen<0;sucklen+=cac[suckz++].leng)
if (*cac[suckz].lock) *cac[suckz].hand = 0;
/* Remove all blocks except 1 */
suckz -= (bestz+1); cacnum -= suckz;
copybufbyte(&cac[bestz+suckz],&cac[bestz],(cacnum-bestz)*sizeof(cactype));
cac[bestz].hand = newhandle;
*newhandle = cachestart+besto;
cac[bestz].leng = newbytes;
cac[bestz].lock = newlockptr;
cachecount++;
/* Add new empty block if necessary */
if (sucklen <= 0) return;
bestz++;
if (bestz == cacnum)
{
cacnum++; if (cacnum > MAXCACHEOBJECTS) reportandexit("Too many objects in cache! (cacnum > MAXCACHEOBJECTS)\n");
cac[bestz].leng = sucklen;
cac[bestz].lock = &zerochar;
return;
}
if (*cac[bestz].lock == 0) { cac[bestz].leng += sucklen; return; }
cacnum++; if (cacnum > MAXCACHEOBJECTS) reportandexit("Too many objects in cache! (cacnum > MAXCACHEOBJECTS)\n");
for(z=cacnum-1;z>bestz;z--) cac[z] = cac[z-1];
cac[bestz].leng = sucklen;
cac[bestz].lock = &zerochar;
}
void suckcache (int32_t *suckptr)
{
int32_t i;
/* Can't exit early, because invalid pointer might be same even though lock = 0 */
for(i=0;i<cacnum;i++)
if ((int32_t )(*cac[i].hand) == (int32_t )suckptr)
{
if (*cac[i].lock) *cac[i].hand = 0;
cac[i].lock = &zerochar;
cac[i].hand = 0;
/* Combine empty blocks */
if ((i > 0) && (*cac[i-1].lock == 0))
{
cac[i-1].leng += cac[i].leng;
cacnum--; copybuf(&cac[i+1],&cac[i],(cacnum-i)*sizeof(cactype));
}
else if ((i < cacnum-1) && (*cac[i+1].lock == 0))
{
cac[i+1].leng += cac[i].leng;
cacnum--; copybuf(&cac[i+1],&cac[i],(cacnum-i)*sizeof(cactype));
}
}
}
void agecache(void)
{
int32_t cnt;
uint8_t ch;
if (agecount >= cacnum) agecount = cacnum-1;
assert(agecount >= 0);
for(cnt=(cacnum>>4);cnt>=0;cnt--)
{
ch = (*cac[agecount].lock);
if (((ch-2)&255) < 198)
(*cac[agecount].lock) = (uint8_t ) (ch-1);
agecount--; if (agecount < 0) agecount = cacnum-1;
}
}
void reportandexit(char *errormessage)
{
int32_t i, j;
setvmode(0x3);
j = 0;
for(i=0;i<cacnum;i++)
{
printf("%d- ",i);
printf("ptr: 0x%x, ",(int8_t)*cac[i].hand);
printf("leng: %d, ",cac[i].leng);
printf("lock: %d\n",*cac[i].lock);
j += cac[i].leng;
}
printf("Cachesize = %d\n",cachesize);
printf("Cacnum = %d\n",cacnum);
printf("Cache length sum = %d\n",j);
printf("ERROR: %s",errormessage);
Error(EXIT_FAILURE, "");
}
|