commit e9a7fd1da92555cd65a50bb8f5a6b0be231cb517
parent 073b2d83295eb468f340016b8d2a66e06a88f098
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Sun, 1 Oct 2017 11:57:35 +0200
[as-z80] Add (HL) addressing mode
Diffstat:
7 files changed, 85 insertions(+), 6 deletions(-)
diff --git a/as/as.h b/as/as.h
@@ -39,6 +39,10 @@ enum common_args {
AIMM16,
AIMM32,
AIMM64,
+ AINDIR,
+ AINDEX,
+ ADIRECT,
+ AREG_OFF,
AMAX,
AREP = 128
};
diff --git a/as/expr.c b/as/expr.c
@@ -145,6 +145,8 @@ binary(int op, Node *l, Node *r)
return fold(op, l, r);
if (l->addr == AIMM && r->addr == AIMM)
addr = AIMM;
+ else if (l->addr == AREG && r->addr == AIMM)
+ addr = AREG_OFF;
else
error("incorrect operand");
np = node(op, l, r);
@@ -327,6 +329,26 @@ expect(int token)
next();
}
+Node *
+content(Node *np)
+{
+ int op;
+
+ switch (np->addr) {
+ case AREG:
+ op = AINDIR;
+ goto new_node;
+ case AREG_OFF:
+ op = AINDEX;
+ goto new_node;
+ case AIMM:
+ op = ADIRECT;
+ new_node:
+ return node(op, np, NULL);
+ }
+ return np;
+}
+
/*************************************************************************/
/* grammar functions */
/*************************************************************************/
@@ -336,7 +358,7 @@ static Node *or(void);
static Node *
primary(void)
{
- int addr;
+ int addr, op;
Node *np;
switch (yytoken) {
@@ -355,6 +377,12 @@ primary(void)
np->addr = addr;
next();
break;
+ case '(':
+ next();
+ np = or();
+ expect(')');
+ np = content(np);
+ break;
default:
unexpected();
}
diff --git a/as/target/gen.awk b/as/target/gen.awk
@@ -83,6 +83,8 @@ function str2args(s, args, i, out, n)
out = out "AREG_RCLASS"
} else if (match(a, /^regA/)) {
out = out "AREG_A"
+ } else if (match(a, /^indir_HL/)) {
+ out = out "AINDER_HL"
} else {
print "wrong arg", a
exit 1
diff --git a/as/target/x80/ins.c b/as/target/x80/ins.c
@@ -123,7 +123,7 @@ r8_r8(Op *op, Node **args)
}
void
-r8(Op *op, Node **args)
+xx_r8_2(Op *op, Node **args)
{
Node *par1, *par2;
unsigned char buf[3];
@@ -131,7 +131,38 @@ r8(Op *op, Node **args)
par1 = args[0];
par2 = args[1];
+
memcpy(buf, op->bytes, n);
buf[n-1] |= reg2int(par2->sym->argtype);
emit(cursec, buf, n);
}
+
+void
+r8_xx_2(Op *op, Node **args)
+{
+ Node *par1, *par2;
+ unsigned char buf[3];
+ int n = op->size;
+
+ par1 = args[0];
+ par2 = args[1];
+
+ memcpy(buf, op->bytes, n);
+ buf[n-1] |= reg2int(par2->sym->argtype) << 3;
+ emit(cursec, buf, n);
+}
+
+void
+r8_xx_1(Op *op, Node **args)
+{
+ Node *par1, *par2;
+ unsigned char buf[3];
+ int n = op->size;
+
+ par1 = args[0];
+ par2 = args[1];
+
+ memcpy(buf, op->bytes, n);
+ buf[n-1] |= reg2int(par1->sym->argtype) << 3;
+ emit(cursec, buf, n);
+}
diff --git a/as/target/x80/proc.h b/as/target/x80/proc.h
@@ -31,6 +31,8 @@ enum args {
AREG_RCLASS, /* register class for B, C, D, E, H, L and A */
AREG_PCLASS, /* register class for B, C, D, E, IXH, IXL and A */
AREG_QCLASS, /* register class for B, C, D, E, IYH, IYL and A */
+
+ AINDER_HL, /* (HL) */
};
extern int rclass(int reg);
diff --git a/as/target/x80/x80.dat b/as/target/x80/x80.dat
@@ -59,11 +59,17 @@ OTDR none 2 0xed,0xbb noargs Z80,R800
LD reg_r,imm8 2 0x06 r8_imm8 Z80,R800,GB80
LD reg_p,imm8 3 0xdd,0x06 r8_imm8 Z80,R800
LD reg_q,imm8 3 0xfd,0x06 r8_imm8 Z80,R800
+LD indir_HL,imm8 2 0x36 imm8 Z80,R800,GB80
+
LD reg_r,reg_r 1 0x40 r8_r8 Z80,R800,GB80
LD reg_p,reg_p 2 0xdd,0x40 r8_r8 Z80,R800
LD reg_q,reg_q 2 0xfd,0x40 r8_r8 Z80,R800
+LD indir_HL,reg_r 1 0x70 xx_r8_2 Z80,R800,GB80
+LD reg_r,indir_HL 1 0x46 r8_xx_1 Z80,R800,GB80
+
+ADD regA,reg_r 1 0x80 xx_r8_2 Z80,R800,GB80
+ADD regA,reg_p 2 0xdd,0x80 xx_r8_2 Z80,R800
+ADD regA,reg_q 2 0xfd,0x80 xx_r8_2 Z80,R800
+ADD regA,imm8 2 0xc6 imm8 Z80,R800,GB80
-ADD regA,reg_r 1 0x80 r8 Z80,R800,GB80
-ADD regA,reg_p 2 0xdd,0x80 r8 Z80,R800
-ADD regA,reg_q 2 0xfd,0x80 r8 Z80,R800
-ADD regA,imm8 2 0xc6 imm8 Z80,R800
+ADD regA,indir_HL 1 0x86 noargs Z80,R800,GB80
diff --git a/as/target/z80/proc.c b/as/target/z80/proc.c
@@ -65,6 +65,12 @@ match(Op *op, Node **args)
--p;
np = *args++;
switch (arg & ~AREP) {
+ case AINDER_HL:
+ if (np->op != AINDIR)
+ return 0;
+ if (np->left->sym->argtype != AREG_HL)
+ return 0;
+ break;
case AREG_A:
if (np->op != AREG || np->sym->argtype != AREG_A)
return 0;