Mercurial > hg-old > index.cgi
annotate src/insn_indexed.c @ 81:b6b1e79cc277
Moved indexed modes to new expression framework
author | lost |
---|---|
date | Sat, 10 Jan 2009 19:05:15 +0000 |
parents | 538e15927776 |
children | e12edcfbebd5 |
rev | line source |
---|---|
32 | 1 /* |
2 insn_indexed.c | |
33
74a3fef7c8d0
Added general addressing modes (immediate, base page, extended, indexed)
lost
parents:
32
diff
changeset
|
3 Copyright © 2009 William Astle |
32 | 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 <ctype.h> | |
28 #include <string.h> | |
29 | |
30 #include "lwasm.h" | |
31 #include "instab.h" | |
32 #include "expr.h" | |
33 | |
34 void insn_indexed_aux(asmstate_t *as, lwasm_line_t *l, const char **p, int *b1, int *b2, int *b3) | |
35 { | |
36 static const char *regs = "X Y U S W PCRPC "; | |
37 static const struct { char *opstr; int pb; } simpleindex[] = | |
38 { | |
39 {",x", 0x84}, {",y", 0xa4}, {",u", 0xc4}, {",s", 0xe4}, | |
40 {",x+", 0x80}, {",y+", 0xa0}, {",u+", 0xc0}, {",s+", 0xe0}, | |
41 {",x++", 0x81}, {",y++", 0xa1}, {",u++", 0xc1}, {",s++", 0xe1}, | |
42 {",-x", 0x82}, {",-y", 0xa2}, {",-u", 0xc2}, {",-s", 0xe2}, | |
43 {",--x", 0x83}, {",--y", 0xa3}, {",--u", 0xc3}, {",--s", 0xe3}, | |
44 {"a,x", 0x86}, {"a,y", 0xa6}, {"a,u", 0xc6}, {"a,s", 0xe6}, | |
45 {"b,x", 0x85}, {"b,y", 0xa5}, {"b,u", 0xc5}, {"b,s", 0xe5}, | |
46 {"e,x", 0x87}, {"e,y", 0xa7}, {"e,u", 0xc7}, {"e,s", 0xe7}, | |
47 {"f,x", 0x8a}, {"f,y", 0xaa}, {"f,u", 0xca}, {"f,s", 0xea}, | |
48 {"d,x", 0x8b}, {"d,y", 0xab}, {"d,u", 0xcb}, {"d,s", 0xed}, | |
49 {"w,x", 0x8e}, {"w,y", 0xae}, {"w,u", 0xce}, {"w,s", 0xee}, | |
50 {",w", 0x8f}, {",w++", 0xcf}, {",--w", 0xef}, | |
51 | |
52 {"[,x]", 0x94}, {"[,y]", 0xb4}, {"[,u", 0xd4}, {"[,s]", 0xf4}, | |
53 {"[,x++]", 0x91}, {"[,y++]", 0xb1}, {"[,u++]", 0xd1}, {"[,s++]", 0xf1}, | |
54 {"[,--x]", 0x93}, {"[,--y]", 0xb3}, {"[,--u]", 0xd3}, {"[,--s]", 0xf3}, | |
55 {"[a,x]", 0x96}, {"[a,y]", 0xb6}, {"[a,u]", 0xd6}, {"[a,s]", 0xf6}, | |
56 {"[b,x]", 0x95}, {"[b,y]", 0xb5}, {"[b,u]", 0xd5}, {"[b,s]", 0xf5}, | |
57 {"[e,x]", 0x97}, {"[e,y]", 0xb7}, {"[e,u]", 0xd7}, {"[e,s]", 0xf7}, | |
58 {"[f,x]", 0x9a}, {"[f,y]", 0xba}, {"[f,u]", 0xda}, {"[f,s]", 0xfa}, | |
59 {"[d,x]", 0x9b}, {"[d,y]", 0xbb}, {"[d,u]", 0xdb}, {"[d,s]", 0xfd}, | |
60 {"[w,x]", 0x9e}, {"[w,y]", 0xbe}, {"[w,u]", 0xde}, {"[w,s]", 0xfe}, | |
61 {"[,w]", 0x90}, {"[,w++]", 0xd0}, {"[,--w]", 0xf0}, | |
62 | |
63 { "", -1 } | |
64 }; | |
65 char stbuf[25]; | |
81 | 66 int i, j, rn; |
67 int f8 = 0, f16 = 0, f0 = 0; | |
68 int r, v; | |
32 | 69 int indir = 0; |
81 | 70 |
71 // initialize output bytes | |
32 | 72 *b1 = *b2 = *b3 = -1; |
73 | |
81 | 74 // fetch out operand for lookup |
32 | 75 for (i = 0; i < 24; i++) |
76 { | |
77 if (*((*p) + i) && !isspace(*((*p) + i))) | |
78 stbuf[i] = *((*p) + i); | |
79 else | |
80 break; | |
81 } | |
82 stbuf[i] = '\0'; | |
81 | 83 |
84 // now look up operand in "simple" table | |
32 | 85 if (!*((*p) + i) || isspace(*((*p) + i))) |
86 { | |
87 // do simple lookup | |
88 for (j = 0; simpleindex[j].opstr[0]; j++) | |
89 { | |
90 if (!strcasecmp(stbuf, simpleindex[j].opstr)) | |
91 break; | |
92 } | |
93 if (simpleindex[j].opstr[0]) | |
94 { | |
95 *b1 = simpleindex[j].pb; | |
96 (*p) += i; | |
97 return; | |
98 } | |
99 } | |
81 | 100 |
101 // now do the "hard" ones | |
102 | |
103 // is it indirect? | |
32 | 104 if (**p == '[') |
105 { | |
106 indir = 1; | |
107 (*p)++; | |
108 } | |
109 | |
81 | 110 // look for a "," - all indexed modes have a "," except extended indir |
32 | 111 rn = 0; |
112 for (i = 0; (*p)[i] && !isspace((*p)[i]); i++) | |
113 { | |
114 if ((*p)[i] == ',') | |
115 { | |
116 rn = 1; | |
117 break; | |
118 } | |
119 } | |
81 | 120 |
121 // if no "," and indirect, do extended indir | |
32 | 122 if (!rn && indir) |
123 { | |
124 // extended indir | |
125 *b1 = 0x9f; | |
126 *b2 = 0; | |
127 *b3 = 0; | |
81 | 128 |
129 r = lwasm_expr_result2(as, l, (char **)p, 0, &v, 0); | |
130 if (r < 0) | |
32 | 131 { |
132 return; | |
133 } | |
81 | 134 |
32 | 135 if (**p != ']') |
136 { | |
137 register_error(as, l, 1, "Bad operand"); | |
138 return; | |
139 } | |
81 | 140 |
32 | 141 (*p)++; |
81 | 142 |
143 if (r == 1 && as -> passnum == 2) | |
32 | 144 { |
81 | 145 l -> relocoff = as -> addr - l -> codeaddr + 1; |
32 | 146 } |
81 | 147 |
148 *b2 = (v >> 8) & 0xff; | |
149 *b3 = v & 0xff; | |
32 | 150 return; |
151 } | |
152 | |
81 | 153 // if we've previously forced the offset size, make a note of it |
154 if (l -> fsize == 1) | |
155 f8 = 1; | |
156 else if (l -> fsize == 2) | |
157 f16 = 1; | |
158 | |
32 | 159 if (**p == '<') |
160 { | |
161 f8 = 1; | |
162 (*p)++; | |
163 } | |
164 else if (**p == '>') | |
165 { | |
166 f16 = 1; | |
167 (*p)++; | |
168 } | |
169 | |
170 if (**p == '0' && *(*p+1) == ',') | |
171 { | |
172 f0 = 1; | |
173 } | |
174 | |
175 // now we have to evaluate the expression | |
81 | 176 r = lwasm_expr_result2(as, l, (char **)p, 0, &v, 0); |
177 if (r < 0) | |
32 | 178 { |
179 return; | |
180 } | |
81 | 181 if (f8 && r != 0) |
32 | 182 { |
81 | 183 register_error(as, l, 2, "Illegal external or inter-section reference"); |
184 r = 0; | |
185 v = 0; | |
32 | 186 } |
81 | 187 |
32 | 188 // now look for a comma; if not present, explode |
189 if (*(*p)++ != ',') | |
190 { | |
191 // syntax error; force 0 bit | |
192 *b1 = 00; | |
81 | 193 l -> fsize = 0; |
32 | 194 return; |
195 } | |
196 | |
197 // now get the register | |
198 rn = lwasm_lookupreg3(regs, p); | |
199 if (rn < 0) | |
81 | 200 { |
201 *b1 = 0; | |
202 l -> fsize = 0; | |
203 register_error(as, l, 1, "Bad register"); | |
204 return; | |
205 } | |
206 | |
32 | 207 if (indir) |
208 { | |
209 if (**p != ']') | |
81 | 210 { |
211 register_error(as, l, 1, "Bad operand"); | |
212 l -> fsize = 0; | |
213 *b1 = 0; | |
214 return; | |
215 } | |
32 | 216 else |
217 (*p)++; | |
218 } | |
219 | |
81 | 220 // incomplete reference on pass 1 forces 16 bit |
221 if (r == 1 && as -> passnum == 1) | |
222 { | |
223 f16 = 1; | |
224 l -> fsize = 2; | |
225 } | |
226 | |
227 // incomplete reference on pass 2 needs relocoff set | |
228 if (r == 1 && as -> passnum == 2) | |
229 { | |
230 l -> relocoff = as -> addr - l -> codeaddr + 1; | |
231 } | |
232 | |
233 // nnnn,W is only 16 bit (or 0 bit) | |
32 | 234 if (rn == 4) |
235 { | |
236 if (f8) | |
81 | 237 { |
238 register_error(as, l, 1, "n,W cannot be 8 bit"); | |
239 l -> fsize = 0; | |
240 *b1 = 0; | |
241 return; | |
242 } | |
243 // note: set f16 above for incomplete references | |
244 // also set reloc offset | |
245 if (!f16 && !f0 && !(as -> pragmas & PRAGMA_NOINDEX0TONONE) && v == 0) | |
32 | 246 { |
247 if (indir) | |
248 *b1 = 0x90; | |
249 else | |
250 *b1 = 0x8f; | |
251 return; | |
252 } | |
81 | 253 |
32 | 254 if (indir) |
255 *b1 = 0xb0; | |
256 else | |
257 *b1 = 0xcf; | |
81 | 258 *b2 = (v >> 8) & 0xff; |
259 *b3 = v & 0xff; | |
32 | 260 return; |
261 } | |
262 | |
81 | 263 // set indir to correct bit value |
32 | 264 if (indir) indir = 0x10; |
265 | |
81 | 266 // PCR? then we have PC relative addressing (like B??, LB??) |
32 | 267 if (rn == 5) |
268 { | |
81 | 269 // FIXME: handle external references sensibly |
270 v -= as -> addr; | |
32 | 271 |
272 // we have a slight problem here | |
273 // PCR based on current insn loc is really | |
274 // -125 <= offset <= +130 (8 bit offset) | |
275 // NOTE: when we are called, we already have the opcode emitted | |
276 // so we only need to worry about the size of the operand | |
277 // hence the 2 and 3 magic numbers below instead of 3 and 4 | |
278 // (and that also avoids errors with two byte opcodes, etc) | |
81 | 279 if (f8 || (!f16 && v >= -125 && v <= 130)) |
32 | 280 { |
281 *b1 = indir | 0x8C; | |
81 | 282 v -= 2; |
283 if (v < -128 || v > 127) | |
32 | 284 register_error(as, l, 2, "Byte overflow"); |
81 | 285 *b2 = v & 0xff; |
32 | 286 return; |
287 } | |
288 | |
289 // anything else is 16 bit offset | |
290 // need 16 bit | |
291 *b1 = indir | 0x8D; | |
81 | 292 v -= 3; |
293 *b2 = (v >> 8) & 0xff; | |
294 *b3 = v & 0xff; | |
32 | 295 return; |
296 } | |
297 | |
81 | 298 // constant offset from PC (using PC as regular register :) ) |
299 // FIXME: handle external references intelligently | |
32 | 300 if (rn == 6) |
301 { | |
81 | 302 if (f8 || (!f16 && v >= -128 && v <= 127)) |
32 | 303 { |
304 *b1 = indir | 0x8C; | |
81 | 305 if (v < -128 || v > 127) |
32 | 306 register_error(as, l, 2, "Byte overflow"); |
81 | 307 *b2 = v & 0xff; |
32 | 308 return; |
309 } | |
310 | |
311 // everything else must be 16 bit | |
312 // need 16 bit | |
313 *b1 = indir | 0x8D; | |
81 | 314 *b2 = (v >> 8) & 0xff; |
315 *b3 = v & 0xff; | |
32 | 316 return; |
317 } | |
318 | |
319 // we only have to deal with x,y,u,s here | |
81 | 320 if (!f8 && !f16 && v >= -16 && v <= 15) |
32 | 321 { |
81 | 322 // zero offset going to ,R? |
323 if (v == 0 && !f0 && !(as -> pragmas & PRAGMA_NOINDEX0TONONE)) | |
32 | 324 { |
325 *b1 = rn << 5 | indir | 0x80 | 0x04; | |
326 return; | |
327 } | |
81 | 328 |
329 // no 5 bit on indirect | |
32 | 330 if (indir) |
331 { | |
332 f8 = 1; | |
81 | 333 l -> fsize = 1; |
32 | 334 goto no5bit; |
335 } | |
81 | 336 |
337 // 5 bit addressing | |
338 *b1 = rn << 5 | (v & 0x1F); | |
32 | 339 return; |
340 } | |
81 | 341 |
32 | 342 no5bit: |
81 | 343 if (f16 || (!f8 && (v < -128 || v > 127))) |
32 | 344 { |
345 // must be a 16 bit offset here | |
346 *b1 = rn << 5 | indir | 0x80 | 0x09; | |
81 | 347 *b2 = (v >> 8) & 0xff; |
348 *b3 = v & 0xff; | |
32 | 349 return; |
350 } | |
351 | |
352 // if we're here, we have an 8 bit offset | |
81 | 353 // note: cannot get here if incomplete reference detected above |
32 | 354 *b1 = rn << 5 | indir | 0x80 | 0x08; |
81 | 355 if (v < -128 || v > 127) |
32 | 356 register_error(as, l, 2, "Byte overflow"); |
81 | 357 *b2 = v & 0xff; |
32 | 358 return; |
359 } | |
360 | |
361 OPFUNC(insn_indexed) | |
362 { | |
363 int b1, b2, b3; | |
364 | |
365 lwasm_emitop(as, l, instab[opnum].ops[0]); | |
366 | |
367 insn_indexed_aux(as, l, (const char **)p, &b1, &b2, &b3); | |
368 if (b1 != -1) | |
369 lwasm_emit(as, l, b1); | |
370 if (b2 != -1) | |
371 lwasm_emit(as, l, b2); | |
372 if (b3 != -1) | |
373 lwasm_emit(as, l, b3); | |
374 } |