shithub: scc

Download patch

ref: d125d933343eea7ca85d4c37e6f224eaf1893184
parent: 5fb3dda9da04112b9d166df06c46ab0288a9bade
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Sun Oct 1 07:57:35 EDT 2017

[as-z80] Add (HL) addressing mode

--- a/as/as.h
+++ b/as/as.h
@@ -39,6 +39,10 @@
 	AIMM16,
 	AIMM32,
 	AIMM64,
+	AINDIR,
+	AINDEX,
+	ADIRECT,
+	AREG_OFF,
 	AMAX,
 	AREP = 128
 };
--- a/as/expr.c
+++ b/as/expr.c
@@ -145,6 +145,8 @@
 		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 @@
 	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 *
 primary(void)
 {
-	int addr;
+	int addr, op;
 	Node *np;
 
 	switch (yytoken) {
@@ -354,6 +376,12 @@
 		np->sym = yylval.sym;
 		np->addr = addr;
 		next();
+		break;
+	case '(':
+		next();
+		np = or();
+		expect(')');
+		np = content(np);
 		break;
 	default:
 		unexpected();
--- a/as/target/gen.awk
+++ b/as/target/gen.awk
@@ -83,6 +83,8 @@
 			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
--- a/as/target/x80/ins.c
+++ b/as/target/x80/ins.c
@@ -123,7 +123,7 @@
 }
 
 void
-r8(Op *op, Node **args)
+xx_r8_2(Op *op, Node **args)
 {
 	Node *par1, *par2;
 	unsigned char buf[3];
@@ -131,7 +131,38 @@
 
 	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);
 }
--- a/as/target/x80/proc.h
+++ b/as/target/x80/proc.h
@@ -31,6 +31,8 @@
 	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);
--- a/as/target/x80/x80.dat
+++ b/as/target/x80/x80.dat
@@ -59,11 +59,17 @@
 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	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,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,indir_HL	1	0x86	noargs	Z80,R800,GB80
--- a/as/target/z80/proc.c
+++ b/as/target/z80/proc.c
@@ -65,6 +65,12 @@
 			--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;