Mercurial > hg-old > index.cgi
comparison old-trunk/lwasm/old/insn_indexed.c @ 339:eb230fa7d28e
Prepare for migration to hg
author | lost |
---|---|
date | Fri, 19 Mar 2010 02:54:14 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
338:e7885b3ee266 | 339:eb230fa7d28e |
---|---|
1 /* | |
2 insn_indexed.c | |
3 Copyright © 2009 William Astle | |
4 | |
5 This file is part of LWASM. | |
6 | |
7 LWASM is free software: you can redistribute it and/or modify it under the | |
8 terms of the GNU General Public License as published by the Free Software | |
9 Foundation, either version 3 of the License, or (at your option) any later | |
10 version. | |
11 | |
12 This program is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
15 more details. | |
16 | |
17 You should have received a copy of the GNU General Public License along with | |
18 this program. If not, see <http://www.gnu.org/licenses/>. | |
19 */ | |
20 | |
21 /* | |
22 for handling indexed mode instructions | |
23 */ | |
24 | |
25 #define __insn_indexed_c_seen__ | |
26 | |
27 #include <config.h> | |
28 | |
29 #include <ctype.h> | |
30 #include <string.h> | |
31 | |
32 #include "lwasm.h" | |
33 #include "instab.h" | |
34 #include "expr.h" | |
35 | |
36 void insn_indexed_aux(asmstate_t *as, lwasm_line_t *l, const char **p, int *b1, int *b2, int *b3) | |
37 { | |
38 struct opvals { char *opstr; int pb; }; | |
39 | |
40 static const char *regs = "X Y U S W PCRPC "; | |
41 static const struct opvals simpleindex[] = | |
42 { | |
43 {",x", 0x84}, {",y", 0xa4}, {",u", 0xc4}, {",s", 0xe4}, | |
44 {",x+", 0x80}, {",y+", 0xa0}, {",u+", 0xc0}, {",s+", 0xe0}, | |
45 {",x++", 0x81}, {",y++", 0xa1}, {",u++", 0xc1}, {",s++", 0xe1}, | |
46 {",-x", 0x82}, {",-y", 0xa2}, {",-u", 0xc2}, {",-s", 0xe2}, | |
47 {",--x", 0x83}, {",--y", 0xa3}, {",--u", 0xc3}, {",--s", 0xe3}, | |
48 {"a,x", 0x86}, {"a,y", 0xa6}, {"a,u", 0xc6}, {"a,s", 0xe6}, | |
49 {"b,x", 0x85}, {"b,y", 0xa5}, {"b,u", 0xc5}, {"b,s", 0xe5}, | |
50 {"e,x", 0x87}, {"e,y", 0xa7}, {"e,u", 0xc7}, {"e,s", 0xe7}, | |
51 {"f,x", 0x8a}, {"f,y", 0xaa}, {"f,u", 0xca}, {"f,s", 0xea}, | |
52 {"d,x", 0x8b}, {"d,y", 0xab}, {"d,u", 0xcb}, {"d,s", 0xed}, | |
53 {"w,x", 0x8e}, {"w,y", 0xae}, {"w,u", 0xce}, {"w,s", 0xee}, | |
54 {",w", 0x8f}, {",w++", 0xcf}, {",--w", 0xef}, | |
55 | |
56 {"[,x]", 0x94}, {"[,y]", 0xb4}, {"[,u", 0xd4}, {"[,s]", 0xf4}, | |
57 {"[,x++]", 0x91}, {"[,y++]", 0xb1}, {"[,u++]", 0xd1}, {"[,s++]", 0xf1}, | |
58 {"[,--x]", 0x93}, {"[,--y]", 0xb3}, {"[,--u]", 0xd3}, {"[,--s]", 0xf3}, | |
59 {"[a,x]", 0x96}, {"[a,y]", 0xb6}, {"[a,u]", 0xd6}, {"[a,s]", 0xf6}, | |
60 {"[b,x]", 0x95}, {"[b,y]", 0xb5}, {"[b,u]", 0xd5}, {"[b,s]", 0xf5}, | |
61 {"[e,x]", 0x97}, {"[e,y]", 0xb7}, {"[e,u]", 0xd7}, {"[e,s]", 0xf7}, | |
62 {"[f,x]", 0x9a}, {"[f,y]", 0xba}, {"[f,u]", 0xda}, {"[f,s]", 0xfa}, | |
63 {"[d,x]", 0x9b}, {"[d,y]", 0xbb}, {"[d,u]", 0xdb}, {"[d,s]", 0xfd}, | |
64 {"[w,x]", 0x9e}, {"[w,y]", 0xbe}, {"[w,u]", 0xde}, {"[w,s]", 0xfe}, | |
65 {"[,w]", 0x90}, {"[,w++]", 0xd0}, {"[,--w]", 0xf0}, | |
66 | |
67 { "", -1 } | |
68 }; | |
69 | |
70 static const char *regs9 = "X Y U S PCRPC "; | |
71 static const struct opvals simpleindex9[] = | |
72 { | |
73 {",x", 0x84}, {",y", 0xa4}, {",u", 0xc4}, {",s", 0xe4}, | |
74 {",x+", 0x80}, {",y+", 0xa0}, {",u+", 0xc0}, {",s+", 0xe0}, | |
75 {",x++", 0x81}, {",y++", 0xa1}, {",u++", 0xc1}, {",s++", 0xe1}, | |
76 {",-x", 0x82}, {",-y", 0xa2}, {",-u", 0xc2}, {",-s", 0xe2}, | |
77 {",--x", 0x83}, {",--y", 0xa3}, {",--u", 0xc3}, {",--s", 0xe3}, | |
78 {"a,x", 0x86}, {"a,y", 0xa6}, {"a,u", 0xc6}, {"a,s", 0xe6}, | |
79 {"b,x", 0x85}, {"b,y", 0xa5}, {"b,u", 0xc5}, {"b,s", 0xe5}, | |
80 {"d,x", 0x8b}, {"d,y", 0xab}, {"d,u", 0xcb}, {"d,s", 0xed}, | |
81 | |
82 {"[,x]", 0x94}, {"[,y]", 0xb4}, {"[,u", 0xd4}, {"[,s]", 0xf4}, | |
83 {"[,x++]", 0x91}, {"[,y++]", 0xb1}, {"[,u++]", 0xd1}, {"[,s++]", 0xf1}, | |
84 {"[,--x]", 0x93}, {"[,--y]", 0xb3}, {"[,--u]", 0xd3}, {"[,--s]", 0xf3}, | |
85 {"[a,x]", 0x96}, {"[a,y]", 0xb6}, {"[a,u]", 0xd6}, {"[a,s]", 0xf6}, | |
86 {"[b,x]", 0x95}, {"[b,y]", 0xb5}, {"[b,u]", 0xd5}, {"[b,s]", 0xf5}, | |
87 {"[d,x]", 0x9b}, {"[d,y]", 0xbb}, {"[d,u]", 0xdb}, {"[d,s]", 0xfd}, | |
88 | |
89 { "", -1 } | |
90 }; | |
91 char stbuf[25]; | |
92 int i, j, rn; | |
93 int f8 = 0, f16 = 0, f0 = 0; | |
94 int r, v; | |
95 int indir = 0; | |
96 int fs8 = 0, fs16 = 0; | |
97 const struct opvals *simples; | |
98 const char *reglist; | |
99 | |
100 if (as -> no6309) | |
101 { | |
102 simples = simpleindex9; | |
103 reglist = regs9; | |
104 } | |
105 else | |
106 { | |
107 simples = simpleindex; | |
108 reglist = regs; | |
109 } | |
110 | |
111 // initialize output bytes | |
112 *b1 = *b2 = *b3 = -1; | |
113 | |
114 // fetch out operand for lookup | |
115 for (i = 0; i < 24; i++) | |
116 { | |
117 if (*((*p) + i) && !isspace(*((*p) + i))) | |
118 stbuf[i] = *((*p) + i); | |
119 else | |
120 break; | |
121 } | |
122 stbuf[i] = '\0'; | |
123 | |
124 // now look up operand in "simple" table | |
125 if (!*((*p) + i) || isspace(*((*p) + i))) | |
126 { | |
127 // do simple lookup | |
128 for (j = 0; simples[j].opstr[0]; j++) | |
129 { | |
130 if (!strcasecmp(stbuf, simples[j].opstr)) | |
131 break; | |
132 } | |
133 if (simples[j].opstr[0]) | |
134 { | |
135 *b1 = simples[j].pb; | |
136 (*p) += i; | |
137 return; | |
138 } | |
139 } | |
140 | |
141 // now do the "hard" ones | |
142 | |
143 // is it indirect? | |
144 if (**p == '[') | |
145 { | |
146 indir = 1; | |
147 (*p)++; | |
148 } | |
149 | |
150 // look for a "," - all indexed modes have a "," except extended indir | |
151 rn = 0; | |
152 for (i = 0; (*p)[i] && !isspace((*p)[i]); i++) | |
153 { | |
154 if ((*p)[i] == ',') | |
155 { | |
156 rn = 1; | |
157 break; | |
158 } | |
159 } | |
160 | |
161 // if no "," and indirect, do extended indir | |
162 if (!rn && indir) | |
163 { | |
164 // extended indir | |
165 *b1 = 0x9f; | |
166 *b2 = 0; | |
167 *b3 = 0; | |
168 r = lwasm_expr_result2(as, l, (char **)p, 0, &v, 0); | |
169 if (r < 0) | |
170 { | |
171 return; | |
172 } | |
173 if (**p != ']') | |
174 { | |
175 register_error(as, l, 1, "Bad operand"); | |
176 return; | |
177 } | |
178 | |
179 (*p)++; | |
180 | |
181 if (r == 1 && as -> passnum == 2) | |
182 { | |
183 l -> relocoff = as -> addr - l -> codeaddr + 1; | |
184 } | |
185 | |
186 *b2 = (v >> 8) & 0xff; | |
187 *b3 = v & 0xff; | |
188 return; | |
189 } | |
190 | |
191 // if we've previously forced the offset size, make a note of it | |
192 if (l -> fsize == 1) | |
193 f8 = 1; | |
194 else if (l -> fsize == 2) | |
195 f16 = 1; | |
196 | |
197 if (**p == '<') | |
198 { | |
199 fs8 = 1; | |
200 (*p)++; | |
201 } | |
202 else if (**p == '>') | |
203 { | |
204 fs16 = 1; | |
205 (*p)++; | |
206 } | |
207 | |
208 if (**p == '0' && *(*p+1) == ',') | |
209 { | |
210 f0 = 1; | |
211 } | |
212 | |
213 // now we have to evaluate the expression | |
214 r = lwasm_expr_result2(as, l, (char **)p, 0, &v, 0); | |
215 if (r < 0) | |
216 { | |
217 return; | |
218 } | |
219 // now look for a comma; if not present, explode | |
220 if (*(*p)++ != ',') | |
221 { | |
222 // syntax error; force 0 bit | |
223 *b1 = 00; | |
224 l -> fsize = 0; | |
225 return; | |
226 } | |
227 | |
228 // now get the register | |
229 rn = lwasm_lookupreg3(reglist, p); | |
230 if (rn < 0) | |
231 { | |
232 *b1 = 0; | |
233 l -> fsize = 0; | |
234 register_error(as, l, 1, "Bad register"); | |
235 return; | |
236 } | |
237 | |
238 if (indir) | |
239 { | |
240 if (**p != ']') | |
241 { | |
242 register_error(as, l, 1, "Bad operand"); | |
243 l -> fsize = 0; | |
244 *b1 = 0; | |
245 return; | |
246 } | |
247 else | |
248 (*p)++; | |
249 } | |
250 | |
251 // incomplete reference on pass 1 forces 16 bit | |
252 if (r == 1 && as -> passnum == 1) | |
253 { | |
254 f16 = 1; | |
255 l -> fsize = 2; | |
256 } | |
257 | |
258 // incomplete reference on pass 2 needs relocoff set | |
259 if (r == 1 && as -> passnum == 2) | |
260 { | |
261 l -> relocoff = as -> addr - l -> codeaddr + 1; | |
262 } | |
263 | |
264 // nnnn,W is only 16 bit (or 0 bit) | |
265 if (rn == 4) | |
266 { | |
267 if (f8) | |
268 { | |
269 register_error(as, l, 1, "n,W cannot be 8 bit"); | |
270 l -> fsize = 0; | |
271 *b1 = 0; | |
272 return; | |
273 } | |
274 // note: set f16 above for incomplete references | |
275 // also set reloc offset | |
276 if (!f16 && !f0 && !(as -> pragmas & PRAGMA_NOINDEX0TONONE) && v == 0) | |
277 { | |
278 if (indir) | |
279 *b1 = 0x90; | |
280 else | |
281 *b1 = 0x8f; | |
282 return; | |
283 } | |
284 | |
285 if (indir) | |
286 *b1 = 0xb0; | |
287 else | |
288 *b1 = 0xcf; | |
289 *b2 = (v >> 8) & 0xff; | |
290 *b3 = v & 0xff; | |
291 return; | |
292 } | |
293 | |
294 // set indir to correct bit value | |
295 if (indir) indir = 0x10; | |
296 | |
297 // PCR? then we have PC relative addressing (like B??, LB??) | |
298 if (rn == 5) | |
299 { | |
300 lwasm_expr_term_t *t; | |
301 // external references are handled exactly the same as for | |
302 // relative addressing modes | |
303 // on pass 1, adjust the expression for a subtraction of the | |
304 // current address | |
305 | |
306 // need to re-evaluate the expression with "SECTCONST"... | |
307 r = lwasm_expr_result2(as, l, (char **)p, EXPR_SECTCONST | EXPR_REEVAL, &v, 0); | |
308 if (r != 0) | |
309 v = 0; | |
310 if (as -> passnum == 1) | |
311 { | |
312 l -> fsize = 0; | |
313 } | |
314 f8 = f16 = 0; | |
315 if (r == 1 && as -> passnum == 1 && !fs8) | |
316 { | |
317 l -> fsize = 2; | |
318 f16 = 1; | |
319 } | |
320 if (fs8) | |
321 f8 = 1; | |
322 if (fs16) | |
323 f16 = 1; | |
324 if (l -> fsize == 2) | |
325 f16 = 1; | |
326 else if (l -> fsize == 1) | |
327 f8 = 1; | |
328 if (as -> passnum == 1) | |
329 v -= as -> addr; | |
330 | |
331 // we have a slight problem here | |
332 // PCR based on current insn loc is really | |
333 // -125 <= offset <= +130 (8 bit offset) | |
334 // NOTE: when we are called, we already have the opcode emitted | |
335 // so we only need to worry about the size of the operand | |
336 // hence the 2 and 3 magic numbers below instead of 3 and 4 | |
337 // (and that also avoids errors with two byte opcodes, etc) | |
338 if (f8 || (!f16 && v >= -125 && v <= 130)) | |
339 { | |
340 f8 = 1; | |
341 l -> fsize = 1; | |
342 *b1 = indir | 0x8C; | |
343 if (as -> passnum == 1) | |
344 v -= 2; | |
345 if (v < -128 || v > 127) | |
346 register_error(as, l, 2, "Byte overflow"); | |
347 *b2 = v & 0xff; | |
348 if (r != 0 && as -> passnum == 2) | |
349 { | |
350 register_error(as, l, 2, "Illegal incomplete reference"); | |
351 } | |
352 goto finpcr; | |
353 } | |
354 | |
355 // anything else is 16 bit offset | |
356 // need 16 bit | |
357 | |
358 l -> fsize = 2; | |
359 *b1 = indir | 0x8D; | |
360 if (as -> passnum == 1) | |
361 v -= 3; | |
362 *b2 = (v >> 8) & 0xff; | |
363 *b3 = v & 0xff; | |
364 if (as -> passnum == 2 && r == 1) | |
365 { | |
366 t = lwasm_expr_term_create_secbase(); | |
367 lwasm_expr_stack_push(l -> exprs[0], t); | |
368 lwasm_expr_term_free(t); | |
369 t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS); | |
370 lwasm_expr_stack_push(l -> exprs[0], t); | |
371 lwasm_expr_term_free(t); | |
372 } | |
373 | |
374 finpcr: | |
375 if (as -> passnum == 1) | |
376 { | |
377 // need to adjust the expression | |
378 if (l -> exprs[0]) | |
379 { | |
380 t = lwasm_expr_term_create_int(as -> addr + (f8 ? 2 : 3)); | |
381 lwasm_expr_stack_push(l -> exprs[0], t); | |
382 lwasm_expr_term_free(t); | |
383 t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS); | |
384 lwasm_expr_stack_push(l -> exprs[0], t); | |
385 lwasm_expr_term_free(t); | |
386 } | |
387 else | |
388 { | |
389 l -> exprvals[0] -= as -> addr + (f8 ? 2 : 3); | |
390 } | |
391 } | |
392 return; | |
393 } | |
394 if (fs16) | |
395 f16 = 1; | |
396 if (fs8) | |
397 f8 = 1; | |
398 | |
399 if (f8 && r != 0) | |
400 { | |
401 register_error(as, l, 2, "Illegal external or inter-section reference"); | |
402 r = 0; | |
403 v = 0; | |
404 } | |
405 | |
406 // constant offset from PC (using PC as regular register :) ) | |
407 // FIXME: handle external references intelligently | |
408 if (rn == 6) | |
409 { | |
410 if (f8 || (!f16 && v >= -128 && v <= 127)) | |
411 { | |
412 *b1 = indir | 0x8C; | |
413 if (v < -128 || v > 127) | |
414 register_error(as, l, 2, "Byte overflow"); | |
415 *b2 = v & 0xff; | |
416 return; | |
417 } | |
418 | |
419 // everything else must be 16 bit | |
420 // need 16 bit | |
421 *b1 = indir | 0x8D; | |
422 *b2 = (v >> 8) & 0xff; | |
423 *b3 = v & 0xff; | |
424 return; | |
425 } | |
426 | |
427 // we only have to deal with x,y,u,s here | |
428 if (!f8 && !f16 && v >= -16 && v <= 15) | |
429 { | |
430 // zero offset going to ,R? | |
431 if (v == 0 && !f0 && !(as -> pragmas & PRAGMA_NOINDEX0TONONE)) | |
432 { | |
433 *b1 = rn << 5 | indir | 0x80 | 0x04; | |
434 return; | |
435 } | |
436 | |
437 // no 5 bit on indirect | |
438 if (indir) | |
439 { | |
440 f8 = 1; | |
441 l -> fsize = 1; | |
442 goto no5bit; | |
443 } | |
444 | |
445 // 5 bit addressing | |
446 *b1 = rn << 5 | (v & 0x1F); | |
447 return; | |
448 } | |
449 | |
450 no5bit: | |
451 if (f16 || (!f8 && (v < -128 || v > 127))) | |
452 { | |
453 // must be a 16 bit offset here | |
454 *b1 = rn << 5 | indir | 0x80 | 0x09; | |
455 *b2 = (v >> 8) & 0xff; | |
456 *b3 = v & 0xff; | |
457 return; | |
458 } | |
459 | |
460 // if we're here, we have an 8 bit offset | |
461 // note: cannot get here if incomplete reference detected above | |
462 *b1 = rn << 5 | indir | 0x80 | 0x08; | |
463 if (v < -128 || v > 127) | |
464 register_error(as, l, 2, "Byte overflow"); | |
465 *b2 = v & 0xff; | |
466 return; | |
467 } | |
468 | |
469 OPFUNC(insn_indexed) | |
470 { | |
471 int b1, b2, b3; | |
472 | |
473 lwasm_emitop(as, l, instab[opnum].ops[0]); | |
474 | |
475 insn_indexed_aux(as, l, (const char **)p, &b1, &b2, &b3); | |
476 if (b1 != -1) | |
477 lwasm_emit(as, l, b1); | |
478 if (b2 != -1) | |
479 lwasm_emit(as, l, b2); | |
480 if (b3 != -1) | |
481 lwasm_emit(as, l, b3); | |
482 } |