Mercurial > hg > index.cgi
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 } |