1 |
37 |
robfinch |
// ============================================================================
|
2 |
|
|
// (C) 2012 Robert Finch
|
3 |
|
|
// All Rights Reserved.
|
4 |
|
|
// robfinch<remove>@opencores.org
|
5 |
|
|
//
|
6 |
|
|
// C64 - Raptor64 'C' derived language compiler
|
7 |
|
|
// - 64 bit CPU
|
8 |
|
|
//
|
9 |
|
|
// This source file is free software: you can redistribute it and/or modify
|
10 |
|
|
// it under the terms of the GNU Lesser General Public License as published
|
11 |
|
|
// by the Free Software Foundation, either version 3 of the License, or
|
12 |
|
|
// (at your option) any later version.
|
13 |
|
|
//
|
14 |
|
|
// This source file is distributed in the hope that it will be useful,
|
15 |
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16 |
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17 |
|
|
// GNU General Public License for more details.
|
18 |
|
|
//
|
19 |
|
|
// You should have received a copy of the GNU General Public License
|
20 |
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
21 |
|
|
//
|
22 |
|
|
// ============================================================================
|
23 |
|
|
//
|
24 |
|
|
#include <stdio.h>
|
25 |
|
|
#include <string.h>
|
26 |
|
|
#include "c.h"
|
27 |
|
|
#include "expr.h"
|
28 |
|
|
#include "Statement.h"
|
29 |
|
|
#include "gen.h"
|
30 |
|
|
#include "cglbdec.h"
|
31 |
|
|
|
32 |
|
|
extern int breaklab;
|
33 |
|
|
extern int contlab;
|
34 |
|
|
extern int retlab;
|
35 |
|
|
extern int throwlab;
|
36 |
|
|
|
37 |
|
|
extern int lastsph;
|
38 |
|
|
extern char *semaphores[20];
|
39 |
|
|
|
40 |
|
|
extern TYP stdfunc;
|
41 |
|
|
|
42 |
|
|
void GenerateReturn(SYM *sym, Statement *stmt);
|
43 |
|
|
|
44 |
|
|
|
45 |
|
|
// Generate a function body.
|
46 |
|
|
//
|
47 |
|
|
void GenerateFunction(SYM *sym, Statement *stmt)
|
48 |
|
|
{
|
49 |
|
|
char buf[20];
|
50 |
|
|
char *bl;
|
51 |
|
|
|
52 |
|
|
throwlab = retlab = contlab = breaklab = -1;
|
53 |
|
|
lastsph = 0;
|
54 |
|
|
memset(semaphores,0,sizeof(semaphores));
|
55 |
|
|
throwlab = nextlabel++;
|
56 |
|
|
while( lc_auto & 7 ) /* round frame size to word */
|
57 |
|
|
++lc_auto;
|
58 |
|
|
if (sym->IsInterrupt) {
|
59 |
|
|
GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(30*8));
|
60 |
|
|
GenerateDiadic(op_sm,0,make_indirect(30), make_mask(0x9FFFFFFE));
|
61 |
|
|
}
|
62 |
|
|
if (!sym->IsNocall) {
|
63 |
|
|
GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(24));
|
64 |
|
|
// For a leaf routine don't bother to store the link register or exception link register.
|
65 |
|
|
if (sym->IsLeaf)
|
66 |
|
|
GenerateDiadic(op_sw,0,makereg(27),make_indirect(30));
|
67 |
|
|
else {
|
68 |
|
|
GenerateDiadic(op_sm, 0, make_indirect(30), make_mask(0x98000000));
|
69 |
|
|
GenerateDiadic(op_lea,0,makereg(28),make_label(throwlab));
|
70 |
|
|
}
|
71 |
|
|
GenerateDiadic(op_mov,0,makereg(27),makereg(30));
|
72 |
|
|
if (lc_auto)
|
73 |
|
|
GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(lc_auto));
|
74 |
|
|
}
|
75 |
|
|
if (optimize)
|
76 |
|
|
opt1(stmt);
|
77 |
|
|
GenerateStatement(stmt);
|
78 |
|
|
GenerateReturn(sym,0);
|
79 |
|
|
// Generate code for the hidden default catch
|
80 |
|
|
GenerateLabel(throwlab);
|
81 |
|
|
if (sym->IsLeaf){
|
82 |
|
|
if (sym->DoesThrow) {
|
83 |
|
|
GenerateDiadic(op_mov,0,makereg(31),makereg(28));
|
84 |
|
|
GenerateDiadic(op_bra,0,make_label(retlab),NULL); // goto regular return cleanup code
|
85 |
|
|
}
|
86 |
|
|
}
|
87 |
|
|
else {
|
88 |
|
|
GenerateDiadic(op_lw,0,makereg(31),make_indexed(16,27)); // load throw return address from stack into LR
|
89 |
|
|
GenerateDiadic(op_sw,0,makereg(31),make_indirect(27)); // and store it back (so it can be loaded with the lm)
|
90 |
|
|
GenerateDiadic(op_bra,0,make_label(retlab),NULL); // goto regular return cleanup code
|
91 |
|
|
}
|
92 |
|
|
}
|
93 |
|
|
|
94 |
|
|
|
95 |
|
|
// Generate a return statement.
|
96 |
|
|
//
|
97 |
|
|
void GenerateReturn(SYM *sym, Statement *stmt)
|
98 |
|
|
{
|
99 |
|
|
AMODE *ap;
|
100 |
|
|
int nn;
|
101 |
|
|
int lab1;
|
102 |
|
|
|
103 |
|
|
if( stmt != NULL && stmt->exp != NULL )
|
104 |
|
|
{
|
105 |
|
|
initstack();
|
106 |
|
|
ap = GenerateExpression(stmt->exp,F_REG|F_IMMED,8);
|
107 |
|
|
// Force return value into register 1
|
108 |
|
|
if( ap->preg != 1 ) {
|
109 |
|
|
if (ap->mode == am_immed)
|
110 |
|
|
GenerateTriadic(op_ori, 0, makereg(1),makereg(0),ap);
|
111 |
|
|
else
|
112 |
|
|
GenerateDiadic(op_mov, 0, makereg(1),ap);
|
113 |
|
|
}
|
114 |
|
|
}
|
115 |
|
|
// Generate the return code only once. Branch to the return code for all returns.
|
116 |
|
|
if( retlab == -1 )
|
117 |
|
|
{
|
118 |
|
|
retlab = nextlabel++;
|
119 |
|
|
GenerateLabel(retlab);
|
120 |
|
|
// Unlock any semaphores that may have been set
|
121 |
|
|
for (nn = lastsph - 1; nn >= 0; nn--)
|
122 |
|
|
GenerateDiadic(op_sb,0,makereg(0),make_string(semaphores[nn]));
|
123 |
|
|
if (sym->IsNocall) // nothing to do for nocall convention
|
124 |
|
|
return;
|
125 |
|
|
// Restore registers used as register variables.
|
126 |
|
|
if( save_mask != 0 ) {
|
127 |
|
|
if (bitsset(save_mask) < 2) {
|
128 |
|
|
for (nn = 31; nn >=1 ; nn--)
|
129 |
|
|
if (save_mask & (1 << nn))
|
130 |
|
|
GenerateTriadic(op_lw,0,makereg(nn),make_indirect(30),NULL);
|
131 |
|
|
}
|
132 |
|
|
else
|
133 |
|
|
GenerateTriadic(op_lm,0,make_indirect(30),make_mask(save_mask),NULL);
|
134 |
|
|
}
|
135 |
|
|
// Unlink the stack
|
136 |
|
|
// For a leaf routine the link register and exception link register doesn't need to be saved/restored.
|
137 |
|
|
GenerateDiadic(op_mov,0,makereg(30),makereg(27));
|
138 |
|
|
if (sym->IsLeaf)
|
139 |
|
|
GenerateDiadic(op_lw,0,makereg(27),make_indirect(30));
|
140 |
|
|
else
|
141 |
|
|
GenerateDiadic(op_lm,0,make_indirect(30),make_mask(0x98000000));
|
142 |
|
|
//if (isOscall) {
|
143 |
|
|
// GenerateDiadic(op_move,0,makereg(0),make_string("_TCBregsave"));
|
144 |
|
|
// gen_regrestore();
|
145 |
|
|
//}
|
146 |
|
|
// Generate the return instruction. For the Pascal calling convention pop the parameters
|
147 |
|
|
// from the stack.
|
148 |
|
|
if (sym->IsInterrupt) {
|
149 |
|
|
GenerateTriadic(op_addui,0,makereg(30),makereg(30),make_immed(24));
|
150 |
|
|
GenerateDiadic(op_lm,0,make_indirect(30),make_mask(0x9FFFFFFE));
|
151 |
|
|
GenerateTriadic(op_addui,0,makereg(30),makereg(30),make_immed(popcnt(0x9FFFFFFE)*8));
|
152 |
|
|
GenerateDiadic(op_iret,0,NULL,NULL);
|
153 |
|
|
return;
|
154 |
|
|
}
|
155 |
|
|
if (sym->IsPascal)
|
156 |
|
|
GenerateDiadic(op_ret,0,make_immed(24+sym->NumParms * 8),NULL);
|
157 |
|
|
else
|
158 |
|
|
GenerateDiadic(op_ret,0,make_immed(24),NULL);
|
159 |
|
|
}
|
160 |
|
|
// Just branch to the already generated stack cleanup code.
|
161 |
|
|
else {
|
162 |
|
|
GenerateDiadic(op_bra,0,make_label(retlab),0);
|
163 |
|
|
}
|
164 |
|
|
}
|
165 |
|
|
|
166 |
|
|
// push the operand expression onto the stack.
|
167 |
|
|
//
|
168 |
|
|
static void GeneratePushParameter(ENODE *ep, int i, int n)
|
169 |
|
|
{
|
170 |
|
|
AMODE *ap;
|
171 |
|
|
ap = GenerateExpression(ep,F_REG,8);
|
172 |
|
|
GenerateDiadic(op_sw,0,ap,make_indexed((n-i)*8-8,30));
|
173 |
|
|
ReleaseTempRegister(ap);
|
174 |
|
|
}
|
175 |
|
|
|
176 |
|
|
// push entire parameter list onto stack
|
177 |
|
|
//
|
178 |
|
|
static int GeneratePushParameterList(ENODE *plist)
|
179 |
|
|
{
|
180 |
|
|
ENODE *st = plist;
|
181 |
|
|
int i,n;
|
182 |
|
|
// count the number of parameters
|
183 |
|
|
for(n = 0; plist != NULL; n++ )
|
184 |
|
|
plist = plist->p[1];
|
185 |
|
|
// move stack pointer down by number of parameters
|
186 |
|
|
if (st)
|
187 |
|
|
GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(n*8));
|
188 |
|
|
plist = st;
|
189 |
|
|
for(i = 0; plist != NULL; i++ )
|
190 |
|
|
{
|
191 |
|
|
GeneratePushParameter(plist->p[0],i,n);
|
192 |
|
|
plist = plist->p[1];
|
193 |
|
|
}
|
194 |
|
|
return i;
|
195 |
|
|
}
|
196 |
|
|
|
197 |
|
|
AMODE *GenerateFunctionCall(ENODE *node, int flags)
|
198 |
|
|
{
|
199 |
|
|
AMODE *ap, *result;
|
200 |
|
|
SYM *sym;
|
201 |
|
|
int i;
|
202 |
|
|
int msk;
|
203 |
|
|
|
204 |
|
|
msk = SaveTempRegs();
|
205 |
|
|
sym = NULL;
|
206 |
|
|
i = GeneratePushParameterList(node->p[1]);
|
207 |
|
|
// Call the function
|
208 |
|
|
if( node->p[0]->nodetype == en_nacon ) {
|
209 |
|
|
GenerateDiadic(op_call,0,make_offset(node->p[0]),NULL);
|
210 |
|
|
sym = gsearch(node->p[0]->sp);
|
211 |
|
|
}
|
212 |
|
|
else
|
213 |
|
|
{
|
214 |
|
|
ap = GenerateExpression(node->p[0],F_REG,8);
|
215 |
|
|
ap->mode = am_ind;
|
216 |
|
|
GenerateDiadic(op_jal,0,makereg(31),ap);
|
217 |
|
|
ReleaseTempRegister(ap);
|
218 |
|
|
}
|
219 |
|
|
// Pop parameters off the stack
|
220 |
|
|
if (i!=0) {
|
221 |
|
|
if (sym) {
|
222 |
|
|
if (!sym->IsPascal)
|
223 |
|
|
GenerateTriadic(op_addui,0,makereg(30),makereg(30),make_immed(i * 8));
|
224 |
|
|
}
|
225 |
|
|
else
|
226 |
|
|
GenerateTriadic(op_addui,0,makereg(30),makereg(30),make_immed(i * 8));
|
227 |
|
|
}
|
228 |
|
|
RestoreTempRegs(msk);
|
229 |
|
|
result = GetTempRegister();
|
230 |
|
|
if( result->preg != 1 || (flags & F_REG) == 0 )
|
231 |
|
|
if (sym) {
|
232 |
|
|
if (sym->tp->btp->type==bt_void)
|
233 |
|
|
;
|
234 |
|
|
else
|
235 |
|
|
GenerateTriadic(op_or,0,result,makereg(1),makereg(0));
|
236 |
|
|
}
|
237 |
|
|
else
|
238 |
|
|
GenerateTriadic(op_or,0,result,makereg(1),makereg(0));
|
239 |
|
|
return result;
|
240 |
|
|
}
|
241 |
|
|
|