scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

commit 853fbbd628b233cb42463336d16e5bd5f6e47cf5
parent ac1ee6278edd378b64554a16eeeadb8923f2bd72
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Sat, 30 Sep 2017 08:17:13 +0200

[as-z80] Add support for P and Q class registers

These class of registers open a new world of new instructions.

Diffstat:
as/target/gen.awk | 10+++++++---
as/target/x80/ins.c | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
as/target/x80/proc.h | 9++++++---
as/target/x80/x80.dat | 12+++++++++++-
as/target/z80/proc.c | 16++++++++++++++--
5 files changed, 130 insertions(+), 25 deletions(-)

diff --git a/as/target/gen.awk b/as/target/gen.awk @@ -75,8 +75,12 @@ function str2args(s, args, i, out, n) out = out "AIMM32" } else if (match(a, /^imm64/)) { out = "AIMM64" - } else if (match(a, /^reg_8/)) { - out = out "AREG_8" + } else if (match(a, /^reg_p/)) { + out = out "AREG_PCLASS" + } else if (match(a, /^reg_q/)) { + out = out "AREG_QCLASS" + } else if (match(a, /^reg_r/)) { + out = out "AREG_RCLASS" } else { print "wrong arg", a exit 1 @@ -85,7 +89,7 @@ function str2args(s, args, i, out, n) if (a ~ /^\+$/) { return out "|AREP" } else if (a != "") { - print "wrong arg", a + print "wrong arg", a > "/dev/stderr" exit 1 } out = out "," diff --git a/as/target/x80/ins.c b/as/target/x80/ins.c @@ -1,33 +1,109 @@ static char sccsid[] = "@(#) ./as/target/z80/ins.c"; +#include <stdlib.h> +#include <string.h> + #include "../../../inc/scc.h" #include "../../as.h" #include "proc.h" int -r8(int reg) +rclass(int reg) +{ + switch (reg) { + case AREG_B: + case AREG_C: + case AREG_D: + case AREG_E: + case AREG_H: + case AREG_L: + case AREG_A: + return 1; + default: + return 0; + } +} + +int +pclass(int reg) +{ + switch (reg) { + case AREG_B: + case AREG_C: + case AREG_D: + case AREG_E: + case AREG_IXH: + case AREG_IXL: + case AREG_A: + return 1; + default: + return 0; + } +} + +int +qclass(int reg) { switch (reg) { - case AREG_B: return 0; - case AREG_C: return 1; - case AREG_D: return 2; - case AREG_E: return 3; - case AREG_H: return 4; - case AREG_L: return 5; - case AREG_A: return 7; - default: return -1; + case AREG_B: + case AREG_C: + case AREG_D: + case AREG_E: + case AREG_IYH: + case AREG_IYL: + case AREG_A: + return 1; + default: + return 0; } } +static int +reg2int(int reg) +{ + switch (reg) { + case AREG_B: return 0; + case AREG_C: return 1; + case AREG_D: return 2; + case AREG_E: return 3; + case AREG_IXH: + case AREG_IYH: + case AREG_H: return 4; + case AREG_IXL: + case AREG_IYL: + case AREG_L: return 5; + case AREG_A: return 7; + default: abort(); + } +} + +void +r8_imm8(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-1); + buf[n-1] = par2->sym->value; + buf[n-2] |= reg2int(par1->sym->argtype) << 3; + emit(cursec, buf, n); +} + void -r8_imm(Op *op, Node **args) +r8_r8(Op *op, Node **args) { Node *par1, *par2; - unsigned char buf[2]; + unsigned char buf[3]; + int n = op->size; - par1 = *args++; - par2 = *args; - buf[0] = *op->bytes | r8(par1->sym->argtype) << 3; - buf[1] = par2->sym->value; - emit(cursec, buf, 2); + par1 = args[0]; + par2 = args[1]; + memcpy(buf, op->bytes, n); + buf[n-1] |= reg2int(par1->sym->argtype) << 3 | + reg2int(par2->sym->argtype); + emit(cursec, buf, n); } diff --git a/as/target/x80/proc.h b/as/target/x80/proc.h @@ -28,7 +28,11 @@ enum args { AREG_I, AREG_AF_, - AREG_8, /* class register for B, C, D, E, H, L and A */ + 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 */ }; -extern int r8(int reg);- \ No newline at end of file +extern int rclass(int reg); +extern int pclass(int reg); +extern int qclass(int reg); diff --git a/as/target/x80/x80.dat b/as/target/x80/x80.dat @@ -51,4 +51,14 @@ OUTI none 2 0xed,0xa3 noargs Z80,R800 OTIR none 2 0xed,0xb3 noargs Z80,R800 OUTD none 2 0xed,0xab noargs Z80,R800 OTDR none 2 0xed,0xbb noargs Z80,R800 -LD reg_8,imm8 2 0x06 r8_imm Z80,R800,GB80 + +# p is any register from B, C, D, E, IXL, IXH, A +# q is any register from B, C, D, E, IYL, IYH, A +# r is any register from B, C, D, E, L, H, A + +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 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 diff --git a/as/target/z80/proc.c b/as/target/z80/proc.c @@ -65,10 +65,22 @@ match(Op *op, Node **args) --p; np = *args++; switch (arg & ~AREP) { - case AREG_8: + case AREG_RCLASS: if (np->op != AREG) return 0; - if (r8(np->sym->argtype) == -1) + if (!rclass(np->sym->argtype)) + return 0; + break; + case AREG_PCLASS: + if (np->op != AREG) + return 0; + if (!pclass(np->sym->argtype)) + return 0; + break; + case AREG_QCLASS: + if (np->op != AREG) + return 0; + if (!qclass(np->sym->argtype)) return 0; break; case AIMM8: