comparison lwasm/insn_rel.c @ 377:67373a053c49

Add ?rts target for branch instructions Add a ?rts target for branch instructions, which brances to the nearest RTS or inverts the branch logic to branch around a generated RTS. Activated by a pragma "qrts". Thanks to Erik G <erik@6809.org> for the patch.
author William Astle <lost@l-w.ca>
date Mon, 13 Jul 2015 20:50:02 -0600
parents 35d4213e6657
children 0af33282b518
comparison
equal deleted inserted replaced
376:35d4213e6657 377:67373a053c49
23 */ 23 */
24 24
25 #include <ctype.h> 25 #include <ctype.h>
26 #include <stdlib.h> 26 #include <stdlib.h>
27 #include <stdio.h> 27 #include <stdio.h>
28 #include <string.h>
28 29
29 #include <lw_expr.h> 30 #include <lw_expr.h>
30 31
31 #include "lwasm.h" 32 #include "lwasm.h"
32 #include "instab.h" 33 #include "instab.h"
45 a > or < on its own still specifies a branch point. 46 a > or < on its own still specifies a branch point.
46 47
47 */ 48 */
48 PARSEFUNC(insn_parse_relgen) 49 PARSEFUNC(insn_parse_relgen)
49 { 50 {
50 lw_expr_t t, e1, e2; 51 lw_expr_t t = NULL, e1, e2;
51 52
52 l -> lint = -1; 53 l -> lint = -1;
53 l -> maxlen = OPLEN(instab[l -> insn].ops[3]) + 2; 54 l -> maxlen = OPLEN(instab[l -> insn].ops[3]) + 2;
54 l -> minlen = OPLEN(instab[l -> insn].ops[2]) + 1; 55 l -> minlen = OPLEN(instab[l -> insn].ops[2]) + 1;
55 if (CURPRAGMA(l, PRAGMA_AUTOBRANCHLENGTH) == 0) 56 if (CURPRAGMA(l, PRAGMA_AUTOBRANCHLENGTH) == 0)
74 75
75 // sometimes there is a "#", ignore if there 76 // sometimes there is a "#", ignore if there
76 if (**p == '#') 77 if (**p == '#')
77 (*p)++; 78 (*p)++;
78 79
79 t = lwasm_parse_expr(as, p); 80 if (CURPRAGMA(l, PRAGMA_QRTS))
81 {
82 // handle ?RTS conditional return
83 if (**p == '?')
84 {
85 if (strncasecmp(*p, "?RTS", 4) == 0)
86 {
87 (*p) += 4;
88
89 line_t *cl = l;
90 for (cl = cl->prev; cl; cl = cl->prev)
91 {
92 if (cl->insn == -1)
93 continue;
94
95 if (l->addr->value - cl->addr->value > 128)
96 {
97 cl = NULL;
98 break;
99 }
100
101 if (cl->conditional_return)
102 break;
103
104 if (instab[cl->insn].ops[0] == 0x39)
105 break;
106 }
107
108 if (cl)
109 {
110 l->lint = -1;
111 if (cl->conditional_return)
112 {
113 e2 = lw_expr_build(lw_expr_type_special, lwasm_expr_lineaddr, cl);
114 e1 = lw_expr_build(lw_expr_type_int, 2);
115 t = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, e1, e2);
116 }
117 else
118 {
119 t = lw_expr_build(lw_expr_type_special, lwasm_expr_lineaddr, cl);
120 }
121 }
122 else
123 {
124 l->conditional_return = 1;
125
126 // t = * + 1
127
128 e2 = lw_expr_build(lw_expr_type_special, lwasm_expr_lineaddr, l);
129 e1 = lw_expr_build(lw_expr_type_int, 1);
130 t = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, e1, e2);
131
132 lw_expr_destroy(e1);
133 lw_expr_destroy(e2);
134 }
135 }
136 }
137 }
138
139 if (!t)
140 {
141 t = lwasm_parse_expr(as, p);
142 }
80 143
81 if (!t) 144 if (!t)
82 { 145 {
83 lwasm_register_error(as, l, E_OPERAND_BAD); 146 lwasm_register_error(as, l, E_OPERAND_BAD);
84 return; 147 return;
86 149
87 // if we know the length of the instruction, set it now 150 // if we know the length of the instruction, set it now
88 if (l -> lint == 8) 151 if (l -> lint == 8)
89 { 152 {
90 l -> len = OPLEN(instab[l -> insn].ops[2]) + 1; 153 l -> len = OPLEN(instab[l -> insn].ops[2]) + 1;
154 if (l->conditional_return) l->len++;
91 } 155 }
92 else if (l -> lint == 16) 156 else if (l -> lint == 16)
93 { 157 {
94 l -> len = OPLEN(instab[l -> insn].ops[3]) + 2; 158 l -> len = OPLEN(instab[l -> insn].ops[3]) + 2;
95 } 159 }
231 { 295 {
232 lwasm_register_error(as, l, E_BYTE_OVERFLOW); 296 lwasm_register_error(as, l, E_BYTE_OVERFLOW);
233 return; 297 return;
234 } 298 }
235 299
236 lwasm_emitop(l, instab[l -> insn].ops[2]); 300 if (l->conditional_return)
237 lwasm_emit(l, offs); 301 {
238 302 lwasm_emitop(l, instab[l->insn].ops[2] ^ 1); /* flip branch, add RTS */
239 l -> cycle_adj = 2; 303 lwasm_emit(l, 1);
304 lwasm_emit(l, 0x39);
305 l->cycle_adj = 3;
306 }
307 else
308 {
309 lwasm_emitop(l, instab[l->insn].ops[2]);
310 lwasm_emit(l, offs);
311 l->cycle_adj = 2;
312 }
240 } 313 }
241 else 314 else
242 { 315 {
243 lwasm_emitop(l, instab[l -> insn].ops[3]); 316 lwasm_emitop(l, instab[l -> insn].ops[3]);
244 lwasm_emitexpr(l, e, 2); 317 lwasm_emitexpr(l, e, 2);