Mercurial > hg-old > index.cgi
comparison src/insn_indexed.c @ 32:9bd0fbfe7405
Added basic indexed mode handling
author | lost |
---|---|
date | Fri, 02 Jan 2009 04:22:39 +0000 |
parents | |
children | 74a3fef7c8d0 |
comparison
equal
deleted
inserted
replaced
31:674ee393426c | 32:9bd0fbfe7405 |
---|---|
1 /* | |
2 insn_indexed.c | |
3 Copyright © 2008 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 <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]; | |
66 int i; | |
67 int f8 = 0, f16 = 0; | |
68 int rn; | |
69 int indir = 0; | |
70 int rval; | |
71 int f0 = 0; | |
72 const char *p2; | |
73 lwasm_expr_stack_t *s; | |
74 | |
75 *b1 = *b2 = *b3 = -1; | |
76 | |
77 for (i = 0; i < 24; i++) | |
78 { | |
79 if (*((*p) + i) && !isspace(*((*p) + i))) | |
80 stbuf[i] = *((*p) + i); | |
81 else | |
82 break; | |
83 } | |
84 stbuf[i] = '\0'; | |
85 if (!*((*p) + i) || isspace(*((*p) + i))) | |
86 { | |
87 int j; | |
88 // do simple lookup | |
89 for (j = 0; simpleindex[j].opstr[0]; j++) | |
90 { | |
91 if (!strcasecmp(stbuf, simpleindex[j].opstr)) | |
92 break; | |
93 } | |
94 if (simpleindex[j].opstr[0]) | |
95 { | |
96 *b1 = simpleindex[j].pb; | |
97 (*p) += i; | |
98 return; | |
99 } | |
100 } | |
101 | |
102 // now we have the hard ones to work out here | |
103 | |
104 // if we've previously forced the sizes, make a note of it | |
105 if (l -> fsize == 1) | |
106 f8 = 1; | |
107 else if (l -> fsize == 2) | |
108 f16 = 1; | |
109 | |
110 if (**p == '[') | |
111 { | |
112 indir = 1; | |
113 (*p)++; | |
114 } | |
115 | |
116 rn = 0; | |
117 for (i = 0; (*p)[i] && !isspace((*p)[i]); i++) | |
118 { | |
119 if ((*p)[i] == ',') | |
120 { | |
121 rn = 1; | |
122 break; | |
123 } | |
124 } | |
125 | |
126 if (!rn && indir) | |
127 { | |
128 // extended indir | |
129 *b1 = 0x9f; | |
130 *b2 = 0; | |
131 *b3 = 0; | |
132 s = lwasm_expr_eval(*p, &p2); | |
133 if (!s) | |
134 { | |
135 register_error(as, l, 1, "Bad expression"); | |
136 return; | |
137 } | |
138 *p = p2; | |
139 if (**p != ']') | |
140 { | |
141 register_error(as, l, 1, "Bad operand"); | |
142 return; | |
143 } | |
144 (*p)++; | |
145 if (!lwasm_expr_is_constant(s)) | |
146 { | |
147 register_error(as, l, 2, "Incomplete reference"); | |
148 } | |
149 rn = lwasm_expr_get_value(s); | |
150 lwasm_expr_stack_free(s); | |
151 *b2 = (rn >> 8) & 0xff; | |
152 *b3 = rn & 0xff; | |
153 return; | |
154 } | |
155 | |
156 if (**p == '<') | |
157 { | |
158 f8 = 1; | |
159 (*p)++; | |
160 } | |
161 else if (**p == '>') | |
162 { | |
163 f16 = 1; | |
164 (*p)++; | |
165 } | |
166 | |
167 if (**p == '0' && *(*p+1) == ',') | |
168 { | |
169 f0 = 1; | |
170 } | |
171 | |
172 // now we have to evaluate the expression | |
173 s = lwasm_expr_eval(*p, &p2); | |
174 *p = p2; | |
175 if (!s) | |
176 { | |
177 register_error(as, l, 1, "Bad expression"); | |
178 return; | |
179 } | |
180 if (!lwasm_expr_is_constant(s)) | |
181 { | |
182 register_error(as, l, 2, "Incomplete reference"); | |
183 if (!f8 && !f0) | |
184 { | |
185 f16 = 1; | |
186 l -> fsize = 2; | |
187 } | |
188 } | |
189 rval = lwasm_expr_get_value(s); | |
190 lwasm_expr_stack_free(s); | |
191 | |
192 // now look for a comma; if not present, explode | |
193 if (*(*p)++ != ',') | |
194 { | |
195 // syntax error; force 0 bit | |
196 *b1 = 00; | |
197 return; | |
198 } | |
199 | |
200 // now get the register | |
201 rn = lwasm_lookupreg3(regs, p); | |
202 if (rn < 0) | |
203 goto reterr; | |
204 | |
205 if (indir) | |
206 { | |
207 if (**p != ']') | |
208 goto reterr; | |
209 else | |
210 (*p)++; | |
211 } | |
212 | |
213 // nnnn,W is only 16 bit | |
214 if (rn == 4) | |
215 { | |
216 if (f8) | |
217 goto reterr; | |
218 if (!f16 && !f0 && !(as -> pragmas & PRAGMA_NOINDEX0TONONE) && rval == 0) | |
219 { | |
220 if (indir) | |
221 *b1 = 0x90; | |
222 else | |
223 *b1 = 0x8f; | |
224 return; | |
225 } | |
226 if (indir) | |
227 *b1 = 0xb0; | |
228 else | |
229 *b1 = 0xcf; | |
230 *b2 = (rval >> 8) & 0xff; | |
231 *b3 = rval & 0xff; | |
232 return; | |
233 } | |
234 | |
235 if (indir) indir = 0x10; | |
236 | |
237 // PCR? redo v1, v2 relative to current address | |
238 if (rn == 5) | |
239 { | |
240 rval -= as -> addr; | |
241 | |
242 // we have a slight problem here | |
243 // PCR based on current insn loc is really | |
244 // -125 <= offset <= +130 (8 bit offset) | |
245 // NOTE: when we are called, we already have the opcode emitted | |
246 // so we only need to worry about the size of the operand | |
247 // hence the 2 and 3 magic numbers below instead of 3 and 4 | |
248 // (and that also avoids errors with two byte opcodes, etc) | |
249 if (f8 || (!f16 && rval >= -125 && rval <= 130)) | |
250 { | |
251 *b1 = indir | 0x8C; | |
252 rval -= 2; | |
253 if (rval < -128 || rval > 127) | |
254 register_error(as, l, 2, "Byte overflow"); | |
255 *b2 = rval & 0xff; | |
256 return; | |
257 } | |
258 | |
259 // anything else is 16 bit offset | |
260 // need 16 bit | |
261 *b1 = indir | 0x8D; | |
262 rval -= 3; | |
263 *b2 = (rval >> 8) & 0xff; | |
264 *b3 = rval & 0xff; | |
265 return; | |
266 } | |
267 | |
268 // constant offset from PC | |
269 if (rn == 6) | |
270 { | |
271 if (f8 || (!f16 && rval >= -128 && rval <= 127)) | |
272 { | |
273 *b1 = indir | 0x8C; | |
274 if (rval < -128 || rval > 127) | |
275 register_error(as, l, 2, "Byte overflow"); | |
276 *b2 = rval & 0xff; | |
277 return; | |
278 } | |
279 | |
280 // everything else must be 16 bit | |
281 // need 16 bit | |
282 *b1 = indir | 0x8D; | |
283 *b2 = (rval >> 8) & 0xff; | |
284 *b3 = rval & 0xff; | |
285 return; | |
286 } | |
287 | |
288 // we only have to deal with x,y,u,s here | |
289 if (!f8 && !f16 && rval >= -16 && rval <= 15) | |
290 { | |
291 if (rval == 0 && !f0 && !(as -> pragmas & PRAGMA_NOINDEX0TONONE)) | |
292 { | |
293 *b1 = rn << 5 | indir | 0x80 | 0x04; | |
294 return; | |
295 } | |
296 // we pick the smallest value here | |
297 if (indir) | |
298 { | |
299 f8 = 1; | |
300 goto no5bit; | |
301 } | |
302 *b1 = rn << 5 | (rval & 0x1F); | |
303 return; | |
304 } | |
305 no5bit: | |
306 if (f16 || (!f8 && (rval < -128 || rval > 127))) | |
307 { | |
308 // must be a 16 bit offset here | |
309 *b1 = rn << 5 | indir | 0x80 | 0x09; | |
310 *b2 = (rval >> 8) & 0xff; | |
311 *b3 = rval & 0xff; | |
312 return; | |
313 } | |
314 | |
315 // if we're here, we have an 8 bit offset | |
316 *b1 = rn << 5 | indir | 0x80 | 0x08; | |
317 if (rval < -128 || rval > 127) | |
318 register_error(as, l, 2, "Byte overflow"); | |
319 *b2 = rval & 0xff; | |
320 return; | |
321 reterr: | |
322 *b1 = 0; | |
323 return; | |
324 } | |
325 | |
326 OPFUNC(insn_indexed) | |
327 { | |
328 int b1, b2, b3; | |
329 | |
330 lwasm_emitop(as, l, instab[opnum].ops[0]); | |
331 | |
332 insn_indexed_aux(as, l, (const char **)p, &b1, &b2, &b3); | |
333 if (b1 != -1) | |
334 lwasm_emit(as, l, b1); | |
335 if (b2 != -1) | |
336 lwasm_emit(as, l, b2); | |
337 if (b3 != -1) | |
338 lwasm_emit(as, l, b3); | |
339 } |