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 }