| OP_BF_BFA CR ',' CR { emit4($1 | ($2<<23) | ($4<<18)); }
| OP_BF_FRA_FRB CR ',' FPR ',' FPR { emit4($1 | ($2<<23) | ($4<<16) | ($6<<11)); }
| OP_BF_L_RA_RB CR ',' u1 ',' GPR ',' GPR { emit4($1 | ($2<<23) | ($4<<21) | ($6<<16) | ($8<<11)); }
- | OP_BF_L_RA_SI CR ',' u1 ',' GPR ',' e16 { emit4($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
- | OP_BF_L_RA_UI CR ',' u1 ',' GPR ',' e16 { emit4($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
+ | OP_BF_L_RA_SI CR ',' u1 ',' GPR ',' e16 { emit_hl($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
+ | OP_BF_L_RA_UI CR ',' u1 ',' GPR ',' e16 { emit_hl($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
| OP_BF_RA_RB cr_opt GPR ',' GPR { emit4($1 | ($2<<23) | ($3<<16) | ($5<<11)); }
- | OP_BF_RA_SI cr_opt GPR ',' e16 { emit4($1 | ($2<<23) | ($3<<16) | $5); }
- | OP_BF_RA_UI cr_opt GPR ',' e16 { emit4($1 | ($2<<23) | ($3<<16) | $5); }
+ | OP_BF_RA_SI cr_opt GPR ',' e16 { emit_hl($1 | ($2<<23) | ($3<<16) | $5); }
+ | OP_BF_RA_UI cr_opt GPR ',' e16 { emit_hl($1 | ($2<<23) | ($3<<16) | $5); }
| OP_BF_U_C c CR ',' u4 { emit4($1 | $2 | ($3<<23) | ($5<<12)); }
| OP_BH { emit4($1); }
| OP_BH u2 { emit4($1 | ($2<<11)); }
| OP_BT_BT_BT u5 { emit4($1 | ($2<<21) | ($2<<16) | ($2<<11)); }
| OP_BT_C c u5 { emit4($1 | $2 | ($3<<21)); }
| OP_FLM_FRB_C c u8 ',' FPR { emit4($1 | $2 | ($3<<17) | ($5<<11)); }
- | OP_FRS_RA_D FPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+ | OP_FRS_RA_D FPR ',' e16 '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_FRS_RA_RB FPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_FRT_FRA_FRB_C c FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); }
| OP_FRT_FRA_FRC_FRB_C c FPR ',' FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($9<<11) | ($7<<6)); }
| OP_FRT_FRA_FRC_C c FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<6)); }
| OP_FRT_FRB_C c FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<11)); }
- | OP_FRT_RA_D FPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+ | OP_FRT_RA_D FPR ',' e16 '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_FRT_RA_RB FPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_FRT_C c FPR { emit4($1 | $2 | ($3<<21)); }
| OP_RA_RS_C c GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16)); }
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($7)); }
| OP_RA_RS_SH6_MB6_C c GPR ',' GPR ',' u6 ',' u6
{ emit4($1 | $2 | ($5<<21) | ($3<<16) | SH6($7) | MB6($9)); }
- | OP_RA_RS_UI GPR ',' GPR ',' e16 { emit4($1 | ($4<<21) | ($2<<16) | $6); }
- | OP_RA_RS_UI_CC C GPR ',' GPR ',' e16 { emit4($1 | ($5<<21) | ($3<<16) | $7); }
+ | OP_RA_RS_UI GPR ',' GPR ',' e16 { emit_hl($1 | ($4<<21) | ($2<<16) | $6); }
+ | OP_RA_RS_UI_CC C GPR ',' GPR ',' e16 { emit_hl($1 | ($5<<21) | ($3<<16) | $7); }
| OP_RT GPR { emit4($1 | ($2<<21)); }
| OP_RT_RA_C c GPR ',' GPR { emit4($1 | $2 | ($3<<21) | ($5<<16)); }
- | OP_RT_RA_D GPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); }
- | OP_RT_RA_DS GPR ',' ds '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+ | OP_RT_RA_D GPR ',' e16 '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
+ | OP_RT_RA_DS GPR ',' ds '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_RT_RA_NB GPR ',' GPR ',' nb { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_RT_RA_RB GPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_RT_RA_RB_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); }
- | OP_RT_RA_SI GPR ',' GPR ',' e16 { emit4($1 | ($2<<21) | ($4<<16) | $6); }
- | OP_RT_RA_SI_addic c GPR ',' GPR ',' e16 { emit4($1 | ($2<<26) | ($3<<21) | ($5<<16) | $7); }
+ | OP_RT_RA_SI GPR ',' GPR ',' e16 { emit_hl($1 | ($2<<21) | ($4<<16) | $6); }
+ | OP_RT_RA_SI_addic c GPR ',' GPR ',' e16 { emit_hl($1 | ($2<<26) | ($3<<21) | ($5<<16) | $7); }
| OP_RT_RA_SI_subi GPR ',' GPR ',' negate16 { emit4($1 | ($2<<21) | ($4<<16) | $6); }
| OP_RT_RA_SI_subic c GPR ',' GPR ',' negate16 { emit4($1 | ($2<<26) | ($3<<21) | ($5<<16) | $7); }
| OP_RT_RB_RA_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($3<<21) | ($7<<16) | ($5<<11)); }
- | OP_RT_SI GPR ',' e16 { emit4($1 | ($2<<21) | $4); }
+ | OP_RT_SI GPR ',' e16 { emit_hl($1 | ($2<<21) | $4); }
| OP_RT_SPR GPR ',' spr_num { emit4($1 | ($2<<21) | ($4<<11)); }
| OP_RS_FXM u7 ',' GPR { emit4($1 | ($4<<21) | ($2<<12)); }
- | OP_RS_RA_D GPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); }
- | OP_RS_RA_DS GPR ',' ds '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+ | OP_RS_RA_D GPR ',' e16 '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
+ | OP_RS_RA_DS GPR ',' ds '(' GPR ')' { emit_hl($1 | ($2<<21) | ($6<<16) | $4); }
| OP_RS_RA_NB GPR ',' GPR ',' nb { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_RS_RA_RB GPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
| OP_RS_RA_RB_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
| OP_RS_RA_RA_C c GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($5<<11)); }
| OP_RS_SPR spr_num ',' GPR { emit4($1 | ($4<<21) | ($2<<11)); }
| OP_TO_RA_RB u5 ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
- | OP_TO_RA_SI u5 ',' GPR ',' e16 { emit4($1 | ($2<<21) | ($4<<16) | $6); }
+ | OP_TO_RA_SI u5 ',' GPR ',' e16 { emit_hl($1 | ($2<<21) | ($4<<16) | $6); }
| OP_TOX_RA_RB GPR ',' GPR { emit4($1 | ($2<<16) | ($4<<11)); }
- | OP_TOX_RA_SI GPR ',' e16 { emit4($1 | ($2<<16) | $4); }
+ | OP_TOX_RA_SI GPR ',' e16 { emit_hl($1 | ($2<<16) | $4); }
| OP_LEV { emit4($1); }
| OP_LEV u7 { emit4($1 | ($2<<5)); }
| OP_LIA lia { emit4($1 | $2); }
if (($1 < -0x8000) || ($1 > 0xffff))
serror("16-bit value out of range");
$$ = (uint16_t) $1;
+ no_hl();
}
- | OP_HI ASC_LPAR expr ASC_RPAR { $$ = emit_hi(&$3, 0); }
- | OP_HA ASC_LPAR expr ASC_RPAR { $$ = emit_hi(&$3, 1); }
- | OP_LO ASC_LPAR expr ASC_RPAR { $$ = emit_lo(&$3); }
+ | OP_HI ASC_LPAR expr ASC_RPAR { $$ = eval_hl(&$3, OP_HI); }
+ | OP_HA ASC_LPAR expr ASC_RPAR { $$ = eval_hl(&$3, OP_HA); }
+ | OP_LO ASC_LPAR expr ASC_RPAR { $$ = eval_hl(&$3, OP_LO); }
;
negate16
+static int hl_token;
+static expr_t hl_expr;
-word_t emit_hi(struct expr_t* expr, int is_signed)
+void no_hl(void) {
+ hl_token = 0;
+}
+
+word_t eval_hl(expr_t* expr, int token)
{
- /* If this is a symbol reference, discard the symbol and keep only the
- * offset part. */
- word_t type = expr->typ & S_TYP;
word_t val = expr->val;
uint16_t hi = val >> 16;
uint16_t lo = val & 0xffff;
- if (type != S_ABS)
- newrelo(expr->typ, RELOPPC | FIXUPFLAGS);
-
- /* If the low half of this relocation is going to be a memory operation,
- * then it'll be treated as a signed value. That means that values greater
- * than 0x7fff will cause the high word to have 1 subtracted from it; so
- * we apply an adjustment here.
- */
-
- if (is_signed && (lo > 0x7fff))
- hi++;
-
- return hi;
+ hl_token = token;
+ hl_expr = *expr;
+
+ switch (token) {
+ case OP_HI:
+ /* hi16[expr] */
+ return hi;
+ case OP_HA:
+ /* ha16[expr]: If the low half will be treated as a signed
+ * value, then values greater than 0x7fff will cause the high
+ * half to have 1 subtracted from it; so we apply an
+ * adjustment here.
+ */
+ if (lo > 0x7fff)
+ hi++;
+ return hi;
+ case OP_LO:
+ /* lo16[expr] */
+ return lo;
+ }
}
-word_t emit_lo(struct expr_t* expr)
+void emit_hl(word_t in)
{
- word_t type = expr->typ & S_TYP;
- word_t val = expr->val;
-
- /* If the assembler stored a symbol for relocation later, we need to
- * abandon it (because the relocation was generated by emit_ha). */
-
- if (type != S_ABS)
- relonami = 0;
-
- return val & 0xffff;
+ int type;
+
+ switch (hl_token) {
+ case OP_HI:
+ case OP_HA:
+ type = hl_expr.typ & S_TYP;
+ if (type != S_ABS)
+ newrelo(hl_expr.typ, RELOPPC | FIXUPFLAGS);
+ break;
+ case OP_LO:
+ /* If the assembler stored a symbol for relocation later, we
+ * need to abandon it (because the relocation was generated by
+ * hi16 or ha16). */
+ type = hl_expr.typ & S_TYP;
+ if (type != S_ABS)
+ relonami = 0;
+ break;
+ }
+
+ emit4(in);
}