comparison lwasm/insn_indexed.c @ 0:2c24602be78f

Initial import from lwtools 3.0.1 version, with new hand built build system and file reorganization
author lost@l-w.ca
date Wed, 19 Jan 2011 22:27:17 -0700
parents
children 7317fbe024af
comparison
equal deleted inserted replaced
-1:000000000000 0:2c24602be78f
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 #include <ctype.h>
26 #include <string.h>
27
28 #include <lw_expr.h>
29
30 #include "lwasm.h"
31 #include "instab.h"
32
33 /*
34 l -> lint: size of operand (0, 1, 2, -1 if not determined)
35 l -> pb: actual post byte (from "resolve" stage) or info passed
36 forward to the resolve stage (if l -> line is -1); 0x80 is indir
37 bits 0-2 are register number
38 */
39 void insn_parse_indexed_aux(asmstate_t *as, line_t *l, char **p)
40 {
41 struct opvals { char *opstr; int pb; };
42
43 static const char *regs = "X Y U S W PCRPC ";
44 static const struct opvals simpleindex[] =
45 {
46 {",x", 0x84}, {",y", 0xa4}, {",u", 0xc4}, {",s", 0xe4},
47 {",x+", 0x80}, {",y+", 0xa0}, {",u+", 0xc0}, {",s+", 0xe0},
48 {",x++", 0x81}, {",y++", 0xa1}, {",u++", 0xc1}, {",s++", 0xe1},
49 {",-x", 0x82}, {",-y", 0xa2}, {",-u", 0xc2}, {",-s", 0xe2},
50 {",--x", 0x83}, {",--y", 0xa3}, {",--u", 0xc3}, {",--s", 0xe3},
51 {"a,x", 0x86}, {"a,y", 0xa6}, {"a,u", 0xc6}, {"a,s", 0xe6},
52 {"b,x", 0x85}, {"b,y", 0xa5}, {"b,u", 0xc5}, {"b,s", 0xe5},
53 {"e,x", 0x87}, {"e,y", 0xa7}, {"e,u", 0xc7}, {"e,s", 0xe7},
54 {"f,x", 0x8a}, {"f,y", 0xaa}, {"f,u", 0xca}, {"f,s", 0xea},
55 {"d,x", 0x8b}, {"d,y", 0xab}, {"d,u", 0xcb}, {"d,s", 0xed},
56 {"w,x", 0x8e}, {"w,y", 0xae}, {"w,u", 0xce}, {"w,s", 0xee},
57 {",w", 0x8f}, {",w++", 0xcf}, {",--w", 0xef},
58
59 {"[,x]", 0x94}, {"[,y]", 0xb4}, {"[,u", 0xd4}, {"[,s]", 0xf4},
60 {"[,x++]", 0x91}, {"[,y++]", 0xb1}, {"[,u++]", 0xd1}, {"[,s++]", 0xf1},
61 {"[,--x]", 0x93}, {"[,--y]", 0xb3}, {"[,--u]", 0xd3}, {"[,--s]", 0xf3},
62 {"[a,x]", 0x96}, {"[a,y]", 0xb6}, {"[a,u]", 0xd6}, {"[a,s]", 0xf6},
63 {"[b,x]", 0x95}, {"[b,y]", 0xb5}, {"[b,u]", 0xd5}, {"[b,s]", 0xf5},
64 {"[e,x]", 0x97}, {"[e,y]", 0xb7}, {"[e,u]", 0xd7}, {"[e,s]", 0xf7},
65 {"[f,x]", 0x9a}, {"[f,y]", 0xba}, {"[f,u]", 0xda}, {"[f,s]", 0xfa},
66 {"[d,x]", 0x9b}, {"[d,y]", 0xbb}, {"[d,u]", 0xdb}, {"[d,s]", 0xfd},
67 {"[w,x]", 0x9e}, {"[w,y]", 0xbe}, {"[w,u]", 0xde}, {"[w,s]", 0xfe},
68 {"[,w]", 0x90}, {"[,w++]", 0xd0}, {"[,--w]", 0xf0},
69
70 { "", -1 }
71 };
72
73 static const char *regs9 = "X Y U S PCRPC ";
74 static const struct opvals simpleindex9[] =
75 {
76 {",x", 0x84}, {",y", 0xa4}, {",u", 0xc4}, {",s", 0xe4},
77 {",x+", 0x80}, {",y+", 0xa0}, {",u+", 0xc0}, {",s+", 0xe0},
78 {",x++", 0x81}, {",y++", 0xa1}, {",u++", 0xc1}, {",s++", 0xe1},
79 {",-x", 0x82}, {",-y", 0xa2}, {",-u", 0xc2}, {",-s", 0xe2},
80 {",--x", 0x83}, {",--y", 0xa3}, {",--u", 0xc3}, {",--s", 0xe3},
81 {"a,x", 0x86}, {"a,y", 0xa6}, {"a,u", 0xc6}, {"a,s", 0xe6},
82 {"b,x", 0x85}, {"b,y", 0xa5}, {"b,u", 0xc5}, {"b,s", 0xe5},
83 {"d,x", 0x8b}, {"d,y", 0xab}, {"d,u", 0xcb}, {"d,s", 0xed},
84
85 {"[,x]", 0x94}, {"[,y]", 0xb4}, {"[,u", 0xd4}, {"[,s]", 0xf4},
86 {"[,x++]", 0x91}, {"[,y++]", 0xb1}, {"[,u++]", 0xd1}, {"[,s++]", 0xf1},
87 {"[,--x]", 0x93}, {"[,--y]", 0xb3}, {"[,--u]", 0xd3}, {"[,--s]", 0xf3},
88 {"[a,x]", 0x96}, {"[a,y]", 0xb6}, {"[a,u]", 0xd6}, {"[a,s]", 0xf6},
89 {"[b,x]", 0x95}, {"[b,y]", 0xb5}, {"[b,u]", 0xd5}, {"[b,s]", 0xf5},
90 {"[d,x]", 0x9b}, {"[d,y]", 0xbb}, {"[d,u]", 0xdb}, {"[d,s]", 0xfd},
91
92 { "", -1 }
93 };
94 char stbuf[25];
95 int i, j, rn;
96 int indir = 0;
97 int f0 = 1;
98 const struct opvals *simples;
99 const char *reglist;
100 lw_expr_t e;
101
102 if (as -> target == TARGET_6809)
103 {
104 simples = simpleindex9;
105 reglist = regs9;
106 }
107 else
108 {
109 simples = simpleindex;
110 reglist = regs;
111 }
112
113 // fetch out operand for lookup
114 for (i = 0; i < 24; i++)
115 {
116 if (*((*p) + i) && !isspace(*((*p) + i)))
117 stbuf[i] = *((*p) + i);
118 else
119 break;
120 }
121 stbuf[i] = '\0';
122
123 // now look up operand in "simple" table
124 if (!*((*p) + i) || isspace(*((*p) + i)))
125 {
126 // do simple lookup
127 for (j = 0; simples[j].opstr[0]; j++)
128 {
129 if (!strcasecmp(stbuf, simples[j].opstr))
130 break;
131 }
132 if (simples[j].opstr[0])
133 {
134 l -> pb = simples[j].pb;
135 l -> lint = 0;
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 l -> pb = 0x9f;
166 e = lwasm_parse_expr(as, p);
167 if (!e || **p != ']')
168 {
169 lwasm_register_error(as, l, "Bad operand");
170 return;
171 }
172 lwasm_save_expr(l, 0, e);
173
174 (*p)++;
175 l -> lint = 2;
176 return;
177 }
178
179 if (**p == '<')
180 {
181 l -> lint = 1;
182 (*p)++;
183 }
184 else if (**p == '>')
185 {
186 l -> lint = 2;
187 (*p)++;
188 }
189
190 if (**p == '0' && *(*p+1) == ',')
191 {
192 f0 = 1;
193 }
194
195 // now we have to evaluate the expression
196 e = lwasm_parse_expr(as, p);
197 if (!e)
198 {
199 lwasm_register_error(as, l, "Bad operand");
200 return;
201 }
202 lwasm_save_expr(l, 0, e);
203
204 // now look for a comma; if not present, explode
205 if (*(*p)++ != ',')
206 {
207 lwasm_register_error(as, l, "Bad operand");
208 return;
209 }
210
211 // now get the register
212 rn = lwasm_lookupreg3(reglist, p);
213 if (rn < 0)
214 {
215 lwasm_register_error(as, l, "Bad register");
216 return;
217 }
218
219 if (indir)
220 {
221 if (**p != ']')
222 {
223 lwasm_register_error(as, l, "Bad operand");
224 return;
225 }
226 else
227 (*p)++;
228 }
229
230 // nnnn,W is only 16 bit (or 0 bit)
231 if (rn == 4)
232 {
233 if (l -> lint == 1)
234 {
235 lwasm_register_error(as, l, "n,W cannot be 8 bit");
236 return;
237 }
238
239 if (l -> lint == 2)
240 {
241 l -> pb = indir ? 0xb0 : 0xcf;
242 l -> lint = 2;
243 return;
244 }
245
246 l -> pb = (0x80 * indir) | rn;
247
248 /* [,w] and ,w
249 if (indir)
250 *b1 = 0x90;
251 else
252 *b1 = 0x8f;
253 */
254 return;
255 }
256
257 // PCR? then we have PC relative addressing (like B??, LB??)
258 if (rn == 5 || (rn == 6 && CURPRAGMA(l, PRAGMA_PCASPCR)))
259 {
260 lw_expr_t e1, e2;
261 // external references are handled exactly the same as for
262 // relative addressing modes
263 // on pass 1, adjust the expression for a subtraction of the
264 // current address
265 // e - (addr + linelen) => e - addr - linelen
266
267 e2 = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, l);
268 e1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_minus, e, e2);
269 lw_expr_destroy(e2);
270 e2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_minus, e1, l -> addr);
271 lw_expr_destroy(e1);
272 lwasm_save_expr(l, 0, e2);
273 if (l -> lint == 1)
274 {
275 l -> pb = indir ? 0x9C : 0x8C;
276 return;
277 }
278 if (l -> lint == 2)
279 {
280 l -> pb = indir ? 0x9D : 0x8D;
281 return;
282 }
283 }
284
285 if (rn == 6)
286 {
287 if (l -> lint == 1)
288 {
289 l -> pb = indir ? 0x9C : 0x8C;
290 return;
291 }
292 if (l -> lint == 2)
293 {
294 l -> pb = indir ? 0x9D : 0x8D;
295 return;
296 }
297 }
298
299 l -> pb = (indir * 0x80) | rn | (f0 * 0x40);
300 }
301
302 PARSEFUNC(insn_parse_indexed)
303 {
304 l -> lint = -1;
305 insn_parse_indexed_aux(as, l, p);
306
307 if (l -> lint != -1)
308 {
309 l -> len = OPLEN(instab[l -> insn].ops[0]) + l -> lint + 1;
310 }
311 }
312
313 void insn_resolve_indexed_aux(asmstate_t *as, line_t *l, int force, int elen)
314 {
315 // here, we have an expression which needs to be
316 // resolved; the post byte is determined here as well
317 lw_expr_t e, e2, e3;
318 int pb = -1;
319 int v;
320
321 if (l -> len != -1)
322 return;
323
324 e = lwasm_fetch_expr(l, 0);
325 if (!lw_expr_istype(e, lw_expr_type_int))
326 {
327 // temporarily set the instruction length to see if we get a
328 // constant for our expression; if so, we can select an instruction
329 // size
330 e2 = lw_expr_copy(e);
331 // magic 2 for 8 bit (post byte + offset)
332 l -> len = OPLEN(instab[l -> insn].ops[0]) + elen + 2;
333 lwasm_reduce_expr(as, e2);
334 // l -> len += 1;
335 // e3 = lw_expr_copy(e);
336 // lwasm_reduce_expr(as, e3);
337 l -> len = -1;
338 if (lw_expr_istype(e2, lw_expr_type_int))
339 {
340 v = lw_expr_intval(e2);
341 // we have a reducible expression here which depends on
342 // the size of this instruction
343 if (v < -128 || v > 127)
344 {
345 l -> lint = 2;
346 switch (l -> pb & 0x07)
347 {
348 case 0:
349 case 1:
350 case 2:
351 case 3:
352 pb = 0x89 | ((l -> pb & 0x03) << 5) | (0x10 * (l -> pb & 0x80));
353 break;
354
355 case 4: // W
356 pb = (l -> pb & 0x80) ? 0xD0 : 0xCF;
357 break;
358
359 case 5: // PCR
360 case 6: // PC
361 pb = (l -> pb & 0x80) ? 0x9D : 0x8D;
362 break;
363 }
364
365 l -> pb = pb;
366 lw_expr_destroy(e2);
367 // lw_expr_destroy(e3);
368 return;
369 }
370 else if ((l -> pb & 0x80) || ((l -> pb & 0x07) > 3) || v < -16 || v > 15)
371 {
372 // if not a 5 bit value, is indirect, or is not X,Y,U,S
373 l -> lint = 1;
374 switch (l -> pb & 0x07)
375 {
376 case 0:
377 case 1:
378 case 2:
379 case 3:
380 pb = 0x88 | ((l -> pb & 0x03) << 5) | (0x10 * (l -> pb & 0x80));
381 break;
382
383 case 4: // W
384 // use 16 bit because W doesn't have 8 bit, unless 0
385 if (v == 0 && !(CURPRAGMA(l, PRAGMA_NOINDEX0TONONE) || l -> pb & 0x40))
386 {
387 pb = (l -> pb & 0x80) ? 0x90 : 0x8F;
388 l -> lint = 0;
389 }
390 else
391 {
392 pb = (l -> pb & 0x80) ? 0xD0 : 0xCF;
393 l -> lint = 2;
394 }
395 break;
396
397 case 5: // PCR
398 case 6: // PC
399 pb = (l -> pb & 0x80) ? 0x9C : 0x8C;
400 break;
401 }
402
403 l -> pb = pb;
404 return;
405 }
406 else
407 {
408 // we have X,Y,U,S and a possible 16 bit here
409 l -> lint = 0;
410
411 if (v == 0 && !(CURPRAGMA(l, PRAGMA_NOINDEX0TONONE) || l -> pb & 0x40))
412 {
413 pb = (l -> pb & 0x03) << 5 | 0x84;
414 }
415 else
416 {
417 pb = (l -> pb & 0x03) << 5 | v & 0x1F;
418 }
419 l -> pb = pb;
420 return;
421 }
422 }
423 }
424
425 if (lw_expr_istype(e, lw_expr_type_int))
426 {
427 // we know how big it is
428 v = lw_expr_intval(e);
429 if (v < -128 || v > 127)
430 {
431 do16bit:
432 l -> lint = 2;
433 switch (l -> pb & 0x07)
434 {
435 case 0:
436 case 1:
437 case 2:
438 case 3:
439 pb = 0x89 | (l -> pb & 0x03) << 5 | (0x10 * (l -> pb & 0x80));
440 break;
441
442 case 4: // W
443 pb = (l -> pb & 0x80) ? 0xD0 : 0xCF;
444 break;
445
446 case 5: // PCR
447 case 6: // PC
448 pb = (l -> pb & 0x80) ? 0x9D : 0x8D;
449 break;
450 }
451
452 l -> pb = pb;
453 return;
454 }
455 else if ((l -> pb & 0x80) || ((l -> pb & 0x07) > 3) || v < -16 || v > 15)
456 {
457 // if not a 5 bit value, is indirect, or is not X,Y,U,S
458 l -> lint = 1;
459 switch (l -> pb & 0x07)
460 {
461 case 0:
462 case 1:
463 case 2:
464 case 3:
465 pb = 0x88 | (l -> pb & 0x03) << 5 | (0x10 * (l -> pb & 0x80));
466 break;
467
468 case 4: // W
469 // use 16 bit because W doesn't have 8 bit, unless 0
470 if (v == 0 && !(CURPRAGMA(l, PRAGMA_NOINDEX0TONONE) || l -> pb & 0x40))
471 {
472 pb = (l -> pb & 0x80) ? 0x90 : 0x8F;
473 l -> lint = 0;
474 }
475 else
476 {
477 pb = (l -> pb & 0x80) ? 0xD0 : 0xCF;
478 l -> lint = 2;
479 }
480 break;
481
482 case 5: // PCR
483 case 6: // PC
484 pb = (l -> pb & 0x80) ? 0x9C : 0x8C;
485 break;
486 }
487
488 l -> pb = pb;
489 return;
490 }
491 else
492 {
493 // we have X,Y,U,S and a possible 16 bit here
494 l -> lint = 0;
495
496 if (v == 0 && !(CURPRAGMA(l, PRAGMA_NOINDEX0TONONE) || l -> pb & 0x40))
497 {
498 pb = (l -> pb & 0x03) << 5 | 0x84;
499 }
500 else
501 {
502 pb = (l -> pb & 0x03) << 5 | v & 0x1F;
503 }
504 l -> pb = pb;
505 return;
506 }
507 }
508 else
509 {
510 // we don't know how big it is
511 if (!force)
512 return;
513 // force 16 bit if we don't know
514 l -> lint = 2;
515 goto do16bit;
516 }
517 }
518
519 RESOLVEFUNC(insn_resolve_indexed)
520 {
521 if (l -> lint == -1)
522 insn_resolve_indexed_aux(as, l, force, 0);
523
524 if (l -> lint != -1 && l -> pb != -1)
525 {
526 l -> len = OPLEN(instab[l -> insn].ops[0]) + l -> lint + 1;
527 }
528 }
529
530 void insn_emit_indexed_aux(asmstate_t *as, line_t *l)
531 {
532 lw_expr_t e;
533
534 lwasm_emitop(l, instab[l -> insn].ops[0]);
535 lwasm_emitop(l, l -> pb);
536 if (l -> lint > 0)
537 {
538 e = lwasm_fetch_expr(l, 0);
539 lwasm_emitexpr(l, e, l -> lint);
540 }
541 }
542
543 EMITFUNC(insn_emit_indexed)
544 {
545 insn_emit_indexed_aux(as, l);
546 }