comparison src/insn_indexed.c @ 101:f59c0916753d

Fixed relative branches and PCR addressing to handle constant intra-section references properly
author lost
date Fri, 23 Jan 2009 03:36:27 +0000
parents e12edcfbebd5
children
comparison
equal deleted inserted replaced
100:579ac3697918 101:f59c0916753d
65 char stbuf[25]; 65 char stbuf[25];
66 int i, j, rn; 66 int i, j, rn;
67 int f8 = 0, f16 = 0, f0 = 0; 67 int f8 = 0, f16 = 0, f0 = 0;
68 int r, v; 68 int r, v;
69 int indir = 0; 69 int indir = 0;
70 int fs8 = 0, fs16 = 0;
70 71
71 // initialize output bytes 72 // initialize output bytes
72 *b1 = *b2 = *b3 = -1; 73 *b1 = *b2 = *b3 = -1;
73 74
74 // fetch out operand for lookup 75 // fetch out operand for lookup
154 else if (l -> fsize == 2) 155 else if (l -> fsize == 2)
155 f16 = 1; 156 f16 = 1;
156 157
157 if (**p == '<') 158 if (**p == '<')
158 { 159 {
159 f8 = 1; 160 fs8 = 1;
160 (*p)++; 161 (*p)++;
161 } 162 }
162 else if (**p == '>') 163 else if (**p == '>')
163 { 164 {
164 f16 = 1; 165 fs16 = 1;
165 (*p)++; 166 (*p)++;
166 } 167 }
167 168
168 if (**p == '0' && *(*p+1) == ',') 169 if (**p == '0' && *(*p+1) == ',')
169 { 170 {
174 r = lwasm_expr_result2(as, l, (char **)p, 0, &v, 0); 175 r = lwasm_expr_result2(as, l, (char **)p, 0, &v, 0);
175 if (r < 0) 176 if (r < 0)
176 { 177 {
177 return; 178 return;
178 } 179 }
179 if (f8 && r != 0)
180 {
181 register_error(as, l, 2, "Illegal external or inter-section reference");
182 r = 0;
183 v = 0;
184 }
185
186 // now look for a comma; if not present, explode 180 // now look for a comma; if not present, explode
187 if (*(*p)++ != ',') 181 if (*(*p)++ != ',')
188 { 182 {
189 // syntax error; force 0 bit 183 // syntax error; force 0 bit
190 *b1 = 00; 184 *b1 = 00;
262 if (indir) indir = 0x10; 256 if (indir) indir = 0x10;
263 257
264 // PCR? then we have PC relative addressing (like B??, LB??) 258 // PCR? then we have PC relative addressing (like B??, LB??)
265 if (rn == 5) 259 if (rn == 5)
266 { 260 {
267 // FIXME: handle external references sensibly 261 lwasm_expr_term_t *t;
268 v -= as -> addr; 262 // external references are handled exactly the same as for
263 // relative addressing modes
264 // on pass 1, adjust the expression for a subtraction of the
265 // current address
266
267 // need to re-evaluate the expression with "SECTCONST"...
268 r = lwasm_expr_result2(as, l, (char **)p, EXPR_SECTCONST | EXPR_REEVAL, &v, 0);
269 if (r != 0)
270 v = 0;
271 if (as -> passnum == 1)
272 {
273 l -> fsize = 0;
274 }
275 f8 = f16 = 0;
276 if (r == 1 && as -> passnum == 1 && !fs8)
277 {
278 l -> fsize = 2;
279 f16 = 1;
280 }
281 if (fs8)
282 f8 = 1;
283 if (fs16)
284 f16 = 1;
285 if (l -> fsize == 2)
286 f16 = 1;
287 else if (l -> fsize == 1)
288 f8 = 1;
289 if (as -> passnum == 1)
290 v -= as -> addr;
269 291
270 // we have a slight problem here 292 // we have a slight problem here
271 // PCR based on current insn loc is really 293 // PCR based on current insn loc is really
272 // -125 <= offset <= +130 (8 bit offset) 294 // -125 <= offset <= +130 (8 bit offset)
273 // NOTE: when we are called, we already have the opcode emitted 295 // NOTE: when we are called, we already have the opcode emitted
274 // so we only need to worry about the size of the operand 296 // so we only need to worry about the size of the operand
275 // hence the 2 and 3 magic numbers below instead of 3 and 4 297 // hence the 2 and 3 magic numbers below instead of 3 and 4
276 // (and that also avoids errors with two byte opcodes, etc) 298 // (and that also avoids errors with two byte opcodes, etc)
277 if (f8 || (!f16 && v >= -125 && v <= 130)) 299 if (f8 || (!f16 && v >= -125 && v <= 130))
278 { 300 {
301 f8 = 1;
302 l -> fsize = 1;
279 *b1 = indir | 0x8C; 303 *b1 = indir | 0x8C;
280 v -= 2; 304 if (as -> passnum == 1)
305 v -= 2;
281 if (v < -128 || v > 127) 306 if (v < -128 || v > 127)
282 register_error(as, l, 2, "Byte overflow"); 307 register_error(as, l, 2, "Byte overflow");
283 *b2 = v & 0xff; 308 *b2 = v & 0xff;
284 return; 309 if (r != 0 && as -> passnum == 2)
310 {
311 register_error(as, l, 2, "Illegal incomplete reference");
312 }
313 goto finpcr;
285 } 314 }
286 315
287 // anything else is 16 bit offset 316 // anything else is 16 bit offset
288 // need 16 bit 317 // need 16 bit
318
319 l -> fsize = 2;
289 *b1 = indir | 0x8D; 320 *b1 = indir | 0x8D;
290 v -= 3; 321 if (as -> passnum == 1)
322 v -= 3;
291 *b2 = (v >> 8) & 0xff; 323 *b2 = (v >> 8) & 0xff;
292 *b3 = v & 0xff; 324 *b3 = v & 0xff;
293 return; 325 if (as -> passnum == 2 && r == 1)
326 {
327 t = lwasm_expr_term_create_secbase();
328 lwasm_expr_stack_push(l -> exprs[0], t);
329 lwasm_expr_term_free(t);
330 t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS);
331 lwasm_expr_stack_push(l -> exprs[0], t);
332 lwasm_expr_term_free(t);
333 }
334
335 finpcr:
336 if (as -> passnum == 1)
337 {
338 // need to adjust the expression
339 if (l -> exprs[0])
340 {
341 t = lwasm_expr_term_create_int(as -> addr + (f8 ? 2 : 3));
342 lwasm_expr_stack_push(l -> exprs[0], t);
343 lwasm_expr_term_free(t);
344 t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS);
345 lwasm_expr_stack_push(l -> exprs[0], t);
346 lwasm_expr_term_free(t);
347 }
348 else
349 {
350 l -> exprvals[0] -= as -> addr + (f8 ? 2 : 3);
351 }
352 }
353 return;
354 }
355 if (fs16)
356 f16 = 1;
357 if (fs8)
358 f8 = 1;
359
360 if (f8 && r != 0)
361 {
362 register_error(as, l, 2, "Illegal external or inter-section reference");
363 r = 0;
364 v = 0;
294 } 365 }
295 366
296 // constant offset from PC (using PC as regular register :) ) 367 // constant offset from PC (using PC as regular register :) )
297 // FIXME: handle external references intelligently 368 // FIXME: handle external references intelligently
298 if (rn == 6) 369 if (rn == 6)