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