1 |
48 |
robfinch |
// ============================================================================
|
2 |
|
|
// __
|
3 |
|
|
// \\__/ o\ (C) 2012-2016 Robert Finch, Waterloo
|
4 |
|
|
// \ __ / All rights reserved.
|
5 |
|
|
// \/_// robfinch<remove>@finitron.ca
|
6 |
|
|
// ||
|
7 |
|
|
//
|
8 |
|
|
// C32 - 'C' derived language compiler
|
9 |
|
|
// - 32 bit CPU
|
10 |
|
|
//
|
11 |
|
|
// This source file is free software: you can redistribute it and/or modify
|
12 |
|
|
// it under the terms of the GNU Lesser General Public License as published
|
13 |
|
|
// by the Free Software Foundation, either version 3 of the License, or
|
14 |
|
|
// (at your option) any later version.
|
15 |
|
|
//
|
16 |
|
|
// This source file is distributed in the hope that it will be useful,
|
17 |
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
18 |
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
19 |
|
|
// GNU General Public License for more details.
|
20 |
|
|
//
|
21 |
|
|
// You should have received a copy of the GNU General Public License
|
22 |
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
23 |
|
|
//
|
24 |
|
|
// ============================================================================
|
25 |
|
|
//
|
26 |
|
|
#include "stdafx.h"
|
27 |
|
|
/*
|
28 |
|
|
int tmpregs[] = {3,4,5,6,7,8,9,10};
|
29 |
|
|
int regstack[8];
|
30 |
|
|
int rsp=7;
|
31 |
|
|
int regmask=0;
|
32 |
|
|
|
33 |
|
|
int tmpbregs[] = {3,4,5,6,7,8};
|
34 |
|
|
int bregstack[6];
|
35 |
|
|
int brsp=5;
|
36 |
|
|
int bregmask = 0;
|
37 |
|
|
*/
|
38 |
|
|
static short int next_fpreg;
|
39 |
|
|
#define MAX_REG 4 /* max. scratch data register (D2) */
|
40 |
|
|
#define MAX_REG_STACK 30
|
41 |
|
|
|
42 |
|
|
// Only registers 5,6,7 and 8 are used for temporaries
|
43 |
|
|
static short int fpreg_in_use[256]; // 0 to 15
|
44 |
|
|
static short int save_fpreg_in_use[256];
|
45 |
|
|
|
46 |
|
|
static struct {
|
47 |
|
|
enum e_am mode;
|
48 |
|
|
short int reg;
|
49 |
|
|
union {
|
50 |
|
|
char isPushed; /* flags if pushed or corresponding reg_alloc * number */
|
51 |
|
|
char allocnum;
|
52 |
|
|
} f;
|
53 |
|
|
}
|
54 |
|
|
fpreg_stack[MAX_REG_STACK + 1],
|
55 |
|
|
fpreg_alloc[MAX_REG_STACK + 1],
|
56 |
|
|
save_fpreg_alloc[MAX_REG_STACK + 1],
|
57 |
|
|
stacked_fpregs[MAX_REG_STACK + 1];
|
58 |
|
|
|
59 |
|
|
static short int fpreg_stack_ptr;
|
60 |
|
|
static short int fpreg_alloc_ptr;
|
61 |
|
|
static short int save_fpreg_alloc_ptr;
|
62 |
|
|
|
63 |
|
|
char tmpfpregs[] = {3,4,5,6,7,8,9,10};
|
64 |
|
|
char regfpstack[18];
|
65 |
|
|
int fprsp=17;
|
66 |
|
|
int fpregmask=0;
|
67 |
|
|
|
68 |
|
|
void initFPRegStack()
|
69 |
|
|
{
|
70 |
|
|
int i;
|
71 |
|
|
|
72 |
|
|
next_fpreg = 3;
|
73 |
|
|
//for (rsp=0; rsp < 3; rsp=rsp+1)
|
74 |
|
|
// regstack[rsp] = tmpregs[rsp];
|
75 |
|
|
//rsp = 0;
|
76 |
|
|
for (i = 0; i <= 255; i++) {
|
77 |
|
|
fpreg_in_use[i] = -1;
|
78 |
|
|
}
|
79 |
|
|
fpreg_stack_ptr = 0;
|
80 |
|
|
fpreg_alloc_ptr = 0;
|
81 |
|
|
// act_scratch = 0;
|
82 |
|
|
memset(fpreg_stack,0,sizeof(fpreg_stack));
|
83 |
|
|
memset(fpreg_alloc,0,sizeof(fpreg_alloc));
|
84 |
|
|
memset(stacked_fpregs,0,sizeof(stacked_fpregs));
|
85 |
|
|
memset(save_fpreg_alloc,0,sizeof(save_fpreg_alloc));
|
86 |
|
|
}
|
87 |
|
|
|
88 |
|
|
void GenerateTempFPRegPush(int reg, int rmode, int number)
|
89 |
|
|
{
|
90 |
|
|
AMODE *ap1;
|
91 |
|
|
ap1 = allocAmode();
|
92 |
|
|
ap1->preg = reg;
|
93 |
|
|
ap1->mode = rmode;
|
94 |
|
|
ap1->isFloat = TRUE;
|
95 |
|
|
|
96 |
|
|
GenerateMonadic(op_push,'t',ap1);
|
97 |
|
|
TRACE(printf("pushing r%d\r\n", reg);)
|
98 |
|
|
fpreg_stack[fpreg_stack_ptr].mode = (enum e_am)rmode;
|
99 |
|
|
fpreg_stack[fpreg_stack_ptr].reg = reg;
|
100 |
|
|
fpreg_stack[fpreg_stack_ptr].f.allocnum = number;
|
101 |
|
|
if (fpreg_alloc[number].f.isPushed=='T')
|
102 |
|
|
fatal("GenerateTempRegPush(): register already pushed");
|
103 |
|
|
fpreg_alloc[number].f.isPushed = 'T';
|
104 |
|
|
if (++fpreg_stack_ptr > MAX_REG_STACK)
|
105 |
|
|
fatal("GenerateTempRegPush(): register stack overflow");
|
106 |
|
|
}
|
107 |
|
|
|
108 |
|
|
void GenerateTempFPRegPop(int reg, int rmode, int number)
|
109 |
|
|
{
|
110 |
|
|
AMODE *ap1;
|
111 |
|
|
|
112 |
|
|
if (fpreg_stack_ptr-- == -1)
|
113 |
|
|
fatal("GenerateTempRegPop(): register stack underflow");
|
114 |
|
|
/* check if the desired register really is on stack */
|
115 |
|
|
if (fpreg_stack[fpreg_stack_ptr].f.allocnum != number)
|
116 |
|
|
fatal("GenerateTempRegPop()/2");
|
117 |
|
|
if (fpreg_in_use[reg] >= 0)
|
118 |
|
|
fatal("GenerateTempRegPop():register still in use");
|
119 |
|
|
TRACE(printf("popped r%d\r\n", reg);)
|
120 |
|
|
fpreg_in_use[reg] = number;
|
121 |
|
|
ap1 = allocAmode();
|
122 |
|
|
ap1->preg = reg;
|
123 |
|
|
ap1->mode = rmode;
|
124 |
|
|
ap1->isFloat = TRUE;
|
125 |
|
|
GenerateMonadic(op_pop,'t',ap1);
|
126 |
|
|
fpreg_alloc[number].f.isPushed = 'F';
|
127 |
|
|
}
|
128 |
|
|
|
129 |
|
|
void initfpstack()
|
130 |
|
|
{
|
131 |
|
|
initFPRegStack();
|
132 |
|
|
}
|
133 |
|
|
|
134 |
|
|
AMODE *GetTempFPRegister()
|
135 |
|
|
{
|
136 |
|
|
AMODE *ap;
|
137 |
|
|
|
138 |
|
|
if (fpreg_in_use[next_fpreg] >= 0)
|
139 |
|
|
GenerateTempFPRegPush(next_fpreg, am_fpreg, fpreg_in_use[next_fpreg]);
|
140 |
|
|
TRACE(printf("GetTempRegister:r%d\r\n", next_fpreg);)
|
141 |
|
|
fpreg_in_use[next_fpreg] = fpreg_alloc_ptr;
|
142 |
|
|
ap = allocAmode();
|
143 |
|
|
ap->mode = am_fpreg;
|
144 |
|
|
ap->preg = next_fpreg;
|
145 |
|
|
ap->deep = fpreg_alloc_ptr;
|
146 |
|
|
ap->isFloat = TRUE;
|
147 |
|
|
fpreg_alloc[fpreg_alloc_ptr].reg = next_fpreg;
|
148 |
|
|
fpreg_alloc[fpreg_alloc_ptr].mode = am_fpreg;
|
149 |
|
|
fpreg_alloc[fpreg_alloc_ptr].f.isPushed = 'F';
|
150 |
|
|
if (next_fpreg++ >= 10)
|
151 |
|
|
next_fpreg = 3; /* wrap around */
|
152 |
|
|
if (fpreg_alloc_ptr++ == MAX_REG_STACK)
|
153 |
|
|
fatal("GetTempRegister(): register stack overflow");
|
154 |
|
|
return ap;
|
155 |
|
|
}
|
156 |
|
|
|
157 |
|
|
/*
|
158 |
|
|
* this routines checks if all allocated registers were freed
|
159 |
|
|
*/
|
160 |
|
|
void checkfpstack()
|
161 |
|
|
{
|
162 |
|
|
int i;
|
163 |
|
|
for (i=3; i<= 10; i++)
|
164 |
|
|
if (fpreg_in_use[i] != -1)
|
165 |
|
|
fatal("checkstack()/1");
|
166 |
|
|
if (next_fpreg != 3) {
|
167 |
|
|
//printf("Nextreg: %d\r\n", next_reg);
|
168 |
|
|
fatal("checkstack()/3");
|
169 |
|
|
}
|
170 |
|
|
if (fpreg_stack_ptr != 0)
|
171 |
|
|
fatal("checkstack()/5");
|
172 |
|
|
if (fpreg_alloc_ptr != 0)
|
173 |
|
|
fatal("checkstack()/6");
|
174 |
|
|
}
|
175 |
|
|
|
176 |
|
|
/*
|
177 |
|
|
* validate will make sure that if a register within an address mode has been
|
178 |
|
|
* pushed onto the stack that it is popped back at this time.
|
179 |
|
|
*/
|
180 |
|
|
void validateFP(AMODE *ap)
|
181 |
|
|
{
|
182 |
|
|
switch (ap->mode) {
|
183 |
|
|
case am_fpreg:
|
184 |
|
|
if ((ap->preg >= 3 && ap->preg <= 10) && fpreg_alloc[ap->deep].f.isPushed == 'T' ) {
|
185 |
|
|
GenerateTempFPRegPop(ap->preg, am_fpreg, (int) ap->deep);
|
186 |
|
|
}
|
187 |
|
|
break;
|
188 |
|
|
}
|
189 |
|
|
}
|
190 |
|
|
|
191 |
|
|
|
192 |
|
|
/*
|
193 |
|
|
* release any temporary registers used in an addressing mode.
|
194 |
|
|
*/
|
195 |
|
|
void ReleaseTempFPRegister(AMODE *ap)
|
196 |
|
|
{
|
197 |
|
|
int number;
|
198 |
|
|
|
199 |
|
|
TRACE(printf("ReleaseTempFPRegister:r%d r%d\r\n", ap->preg, ap->sreg);)
|
200 |
|
|
|
201 |
|
|
if (ap==NULL) {
|
202 |
|
|
printf("DIAG - NULL pointer in ReleaseTempRegister\r\n");
|
203 |
|
|
return;
|
204 |
|
|
}
|
205 |
|
|
|
206 |
|
|
// validate(ap);
|
207 |
|
|
switch (ap->mode) {
|
208 |
|
|
case am_fpreg:
|
209 |
|
|
if (ap->preg >= 3 && ap->preg <= 10) {
|
210 |
|
|
if (fpreg_in_use[ap->preg]==-1)
|
211 |
|
|
return;
|
212 |
|
|
if (next_fpreg-- <= 3)
|
213 |
|
|
next_fpreg = 10;
|
214 |
|
|
number = fpreg_in_use[ap->preg];
|
215 |
|
|
fpreg_in_use[ap->preg] = -1;
|
216 |
|
|
break;
|
217 |
|
|
}
|
218 |
|
|
return;
|
219 |
|
|
default:
|
220 |
|
|
return;
|
221 |
|
|
}
|
222 |
|
|
// /* some consistency checks */
|
223 |
|
|
//if (number != ap->deep) {
|
224 |
|
|
// printf("number %d ap->deep %d\r\n", number, ap->deep);
|
225 |
|
|
// //fatal("ReleaseTempRegister()/1");
|
226 |
|
|
//}
|
227 |
|
|
if (fpreg_alloc_ptr-- == 0)
|
228 |
|
|
fatal("ReleaseTempRegister(): no registers are allocated");
|
229 |
|
|
// if (reg_alloc_ptr != number)
|
230 |
|
|
//fatal("ReleaseTempRegister()/3");
|
231 |
|
|
if (fpreg_alloc[number].f.isPushed=='T')
|
232 |
|
|
fatal("ReleaseTempRegister(): register on stack");
|
233 |
|
|
}
|
234 |
|
|
|
235 |
|
|
// The following is used to save temporary registers across function calls.
|
236 |
|
|
// Save the list of allocated registers and registers in use.
|
237 |
|
|
// Go through the allocated register list and generate a push instruction to
|
238 |
|
|
// put the register on the stack if it isn't already on the stack.
|
239 |
|
|
|
240 |
|
|
int TempFPInvalidate()
|
241 |
|
|
{
|
242 |
|
|
int i;
|
243 |
|
|
int sp;
|
244 |
|
|
|
245 |
|
|
sp = 0;
|
246 |
|
|
TRACE(printf("TempFPInvalidate()\r\n");)
|
247 |
|
|
save_fpreg_alloc_ptr = fpreg_alloc_ptr;
|
248 |
|
|
memcpy(save_fpreg_alloc, fpreg_alloc, sizeof(save_fpreg_alloc));
|
249 |
|
|
memcpy(save_fpreg_in_use, fpreg_in_use, sizeof(save_fpreg_in_use));
|
250 |
|
|
for (i = 0; i < fpreg_alloc_ptr; i++) {
|
251 |
|
|
if (fpreg_in_use[fpreg_alloc[i].reg] != -1) {
|
252 |
|
|
if (fpreg_alloc[i].f.isPushed == 'F') {
|
253 |
|
|
GenerateTempFPRegPush(fpreg_alloc[i].reg, fpreg_alloc[i].mode, i);
|
254 |
|
|
stacked_fpregs[sp].reg = fpreg_alloc[i].reg;
|
255 |
|
|
stacked_fpregs[sp].mode = fpreg_alloc[i].mode;
|
256 |
|
|
stacked_fpregs[sp].f.allocnum = i;
|
257 |
|
|
sp++;
|
258 |
|
|
// mark the register void
|
259 |
|
|
fpreg_in_use[fpreg_alloc[i].reg] = -1;
|
260 |
|
|
}
|
261 |
|
|
}
|
262 |
|
|
}
|
263 |
|
|
return sp;
|
264 |
|
|
}
|
265 |
|
|
|
266 |
|
|
// Pop back any temporary registers that were pushed before the function call.
|
267 |
|
|
// Restore the allocated and in use register lists.
|
268 |
|
|
|
269 |
|
|
void TempFPRevalidate(int sp)
|
270 |
|
|
{
|
271 |
|
|
int nn;
|
272 |
|
|
|
273 |
|
|
for (nn = sp-1; nn >= 0; nn--)
|
274 |
|
|
GenerateTempFPRegPop(stacked_fpregs[nn].reg, stacked_fpregs[nn].mode, stacked_fpregs[nn].f.allocnum);
|
275 |
|
|
fpreg_alloc_ptr = save_fpreg_alloc_ptr;
|
276 |
|
|
memcpy(fpreg_alloc, save_fpreg_alloc, sizeof(fpreg_alloc));
|
277 |
|
|
memcpy(fpreg_in_use, save_fpreg_in_use, sizeof(fpreg_in_use));
|
278 |
|
|
}
|