[PATCH 1/2] z80, gas: follow historical assemblers and allow "op A, x" and "op x"

H. Peter Anvin hpa@zytor.com
Mon Oct 13 20:25:57 GMT 2025


For arithmetic ops, Z80 syntax wants "op A,x" for ADD, ADC and SBC and
"op x" for SUB, AND, OR, XOR, and CP. Many historical assemblers
simply treat them orthogonally; allowing but not requiring the "A,"
operand for any of these operations. This is widely used in legacy
source code, and there is no reason not to.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
---
 gas/config/tc-z80.c | 41 ++++++++---------------------------------
 1 file changed, 8 insertions(+), 33 deletions(-)

diff --git a/gas/config/tc-z80.c b/gas/config/tc-z80.c
index 54a2668aa3d1..22a90d061dc9 100644
--- a/gas/config/tc-z80.c
+++ b/gas/config/tc-z80.c
@@ -1463,9 +1463,8 @@ emit_s (char prefix, char opcode, const char *args)
 
   p = parse_exp (args, & arg_s);
   if (*p == ',' && arg_s.X_md == 0 && arg_s.X_op == O_register && arg_s.X_add_number == REG_A)
-    { /* possible instruction in generic format op A,x */
-      if (!(ins_ok & INS_EZ80) && !sdcc_compat)
-        ill_op ();
+    {
+      /* Allow both op A,x and op x */
       ++p;
       p = parse_exp (p, & arg_s);
     }
@@ -1473,30 +1472,6 @@ emit_s (char prefix, char opcode, const char *args)
   return p;
 }
 
-static const char *
-emit_sub (char prefix, char opcode, const char *args)
-{
-  expressionS arg_s;
-  const char *p;
-
-  if (!(ins_ok & INS_GBZ80))
-    return emit_s (prefix, opcode, args);
-  p = parse_exp (args, & arg_s);
-  if (*p++ != ',')
-    {
-      error (_("bad instruction syntax"));
-      return p;
-    }
-
-  if (arg_s.X_md != 0 || arg_s.X_op != O_register || arg_s.X_add_number != REG_A)
-    ill_op ();
-
-  p = parse_exp (p, & arg_s);
-
-  emit_sx (prefix, opcode, & arg_s);
-  return p;
-}
-
 static const char *
 emit_swap (char prefix, char opcode, const char *args)
 {
@@ -1731,8 +1706,8 @@ emit_adc (char prefix, char opcode, const char * args)
   p = parse_exp (args, &term);
   if (*p++ != ',')
     {
-      error (_("bad instruction syntax"));
-      return p;
+      /* "op x" -> "op A,x" */
+      return emit_s (prefix, opcode, args);
     }
 
   if ((term.X_md) || (term.X_op != O_register))
@@ -1774,8 +1749,8 @@ emit_add (char prefix, char opcode, const char * args)
   p = parse_exp (args, &term);
   if (*p++ != ',')
     {
-      error (_("bad instruction syntax"));
-      return p;
+      /* "op x" -> "op A,x" */
+      return emit_s (prefix, opcode, args);
     }
 
   if ((term.X_md) || (term.X_op != O_register))
@@ -3389,7 +3364,7 @@ static int
 assemble_suffix (const char **suffix)
 {
   static
-  const char sf[8][4] = 
+  const char sf[8][4] =
     {
       "il",
       "is",
@@ -3664,7 +3639,7 @@ static table_t instab[] =
   { "srl",  0xCB, 0x38, emit_mr,   INS_ALL },
   { "stmix",0xED, 0x7D, emit_insn, INS_EZ80 },
   { "stop", 0x00, 0x10, emit_insn, INS_GBZ80 },
-  { "sub",  0x00, 0x90, emit_sub,  INS_ALL },
+  { "sub",  0x00, 0x90, emit_s,    INS_ALL },
   { "swap", 0xCB, 0x30, emit_swap, INS_GBZ80|INS_Z80N },
   { "swapnib",0xED,0x23,emit_insn, INS_Z80N },
   { "test", 0xED, 0x27, emit_insn_n, INS_Z80N },
-- 
2.51.0



More information about the Binutils mailing list