| @@ -12,6 +12,7 @@ CFLAGS = $(shell sdl2-config --cflags) | |||
| LIBS = $(shell sdl2-config --libs) | |||
| MKDIR = mkdir -p | |||
| RM = rm -rf | |||
| ASM_UP = scripts/update_asm_instructions.py | |||
| MODE = release | |||
| BNRY = $(PROGRAM) | |||
| @@ -47,8 +48,9 @@ $(BUILD)/$(MODE)/%.o: %.c | |||
| -include $(DEPS) | |||
| $(SOURCES)/assembler/instructions.inc.c: $(SOURCES)/assembler/instructions.yml | |||
| python scripts/update_asm_instructions.py | |||
| ASM_INST = $(SOURCES)/assembler/instructions | |||
| $(ASM_INST).inc.c: $(ASM_INST).yml $(ASM_UP) | |||
| python $(ASM_UP) | |||
| test: test-all test-z80 test-asm test-dasm | |||
| @@ -12,6 +12,7 @@ when the latter is modified, but can also be run manually. | |||
| from __future__ import print_function | |||
| from itertools import product | |||
| import re | |||
| import time | |||
| @@ -44,10 +45,13 @@ class Instruction(object): | |||
| "register": "AT_REGISTER", | |||
| "immediate": "AT_IMMEDIATE", | |||
| "indirect": "AT_INDIRECT", | |||
| "indexed": "AT_INDEXED|AT_INDIRECT", | |||
| "indexed": "AT_INDEXED", | |||
| "condition": "AT_CONDITION", | |||
| "port": "AT_PORT" | |||
| } | |||
| ARG_EXTRA = { | |||
| "indexed": ["AT_INDIRECT"] | |||
| } | |||
| def __init__(self, name, data): | |||
| self._name = name | |||
| @@ -61,7 +65,10 @@ class Instruction(object): | |||
| optional = False | |||
| for case in self._data["cases"]: | |||
| if num < len(case["type"]): | |||
| types.add(self.ARG_TYPES[case["type"][num]]) | |||
| atype = case["type"][num] | |||
| types.add(self.ARG_TYPES[atype]) | |||
| if atype in self.ARG_EXTRA: | |||
| types.update(self.ARG_EXTRA[atype]) | |||
| else: | |||
| optional = True | |||
| @@ -71,22 +78,123 @@ class Instruction(object): | |||
| types.add("AT_OPTIONAL") | |||
| return "|".join(types) | |||
| def _handle_return(self, arg, indent=1): | |||
| def _handle_return(self, ret, indent=1): | |||
| """ | |||
| Return code to handle an instruction return statement. | |||
| """ | |||
| tabs = TAB * indent | |||
| if arg == "error": | |||
| return tabs + "INST_ERROR(ARG_SYNTAX)" | |||
| else: | |||
| data = ", ".join("0x%02X" % byte for byte in arg) | |||
| return tabs + "INST_RETURN({0}, {1})".format(len(arg), data) | |||
| data = ", ".join("0x%02X" % byte if isinstance(byte, int) else byte | |||
| for byte in ret) | |||
| return TAB * indent + "INST_RETURN({0}, {1})".format(len(ret), data) | |||
| def _build_case_type_check(self, args): | |||
| """ | |||
| Return the test part of an if statement for an instruction case. | |||
| """ | |||
| conds = ["INST_TYPE({0}) == {1}".format(i, self.ARG_TYPES[cond]) | |||
| for i, cond in enumerate(args)] | |||
| return "INST_NARGS == {0} && {1}".format(len(args), " && ".join(conds)) | |||
| def _build_register_check(self, num, cond): | |||
| """ | |||
| Return an expression to check for a particular register value. | |||
| """ | |||
| return "INST_REG({0}) == REG_{1}".format(num, cond.upper()) | |||
| def _build_immediate_check(self, num, cond): | |||
| """ | |||
| Return an expression to check for a particular immediate value. | |||
| """ | |||
| return "INST_IMM({0}).mask & IMM_{1}".format(num, cond.upper()) | |||
| def _build_indirect_check(self, num, cond): | |||
| """ | |||
| Return an expression to check for a particular indirect value. | |||
| """ | |||
| # TODO | |||
| return cond | |||
| def _build_indexed_check(self, num, cond): | |||
| """ | |||
| Return an expression to check for a particular indexed value. | |||
| """ | |||
| # TODO | |||
| return cond | |||
| def _build_condition_check(self, num, cond): | |||
| """ | |||
| Return an expression to check for a particular condition value. | |||
| """ | |||
| return "INST_COND({0}) == COND_{1}".format(num, cond.upper()) | |||
| def _build_port_check(self, num, cond): | |||
| """ | |||
| Return an expression to check for a particular port value. | |||
| """ | |||
| # TODO | |||
| return cond | |||
| _SUBCASE_LOOKUP_TABLE = { | |||
| "register": _build_register_check, | |||
| "immediate": _build_immediate_check, | |||
| "indirect": _build_indirect_check, | |||
| "indexed": _build_indexed_check, | |||
| "condition": _build_condition_check, | |||
| "port": _build_port_check | |||
| } | |||
| def _build_subcase_check(self, types, conds): | |||
| """ | |||
| Return the test part of an if statement for an instruction subcase. | |||
| """ | |||
| return " && ".join(self._SUBCASE_LOOKUP_TABLE[types[i]](self, i, cond) | |||
| for i, cond in enumerate(conds) if cond != "_") | |||
| def _iter_permutations(self, types, conds): | |||
| """ | |||
| Iterate over all permutations of the given subcase conditions. | |||
| """ | |||
| def split(typ, cond): | |||
| if "|" in cond: | |||
| sets = [split(typ, c) for c in cond.split("|")] | |||
| return {choice for s in sets for choice in s} | |||
| if typ == "register" and cond == "ih": | |||
| return {"ixh", "iyh"} | |||
| if typ == "register" and cond == "il": | |||
| return {"ixl", "iyl"} | |||
| return {cond} | |||
| return product(*(split(types[i], cond) | |||
| for i, cond in enumerate(conds))) | |||
| def _adapt_return(self, types, conds, ret): | |||
| """ | |||
| Return a modified byte list to accomodate for prefixes and immediates. | |||
| """ | |||
| for i, cond in enumerate(conds): | |||
| if types[i] == "register" and cond.startswith("ix"): | |||
| ret = ["INST_IX_PREFIX"] + ret | |||
| elif types[i] == "register" and cond.startswith("iy"): | |||
| ret = ["INST_IY_PREFIX"] + ret | |||
| return ret | |||
| def _handle_case(self, case): | |||
| """ | |||
| TODO | |||
| Return code to handle an instruction case. | |||
| """ | |||
| return [TAB + "// " + str(case)] | |||
| lines = [] | |||
| cond = self._build_case_type_check(case["type"]) | |||
| lines.append(TAB + "if ({0}) {{".format(cond)) | |||
| for subcase in case["cases"]: | |||
| for perm in self._iter_permutations(case["type"], subcase["cond"]): | |||
| cond = self._build_subcase_check(case["type"], perm) | |||
| ret = self._adapt_return(case["type"], perm, subcase["return"]) | |||
| lines.append(TAB * 2 + "if ({0})".format(cond)) | |||
| lines.append(self._handle_return(ret, 3)) | |||
| lines.append(TAB * 2 + "INST_ERROR(ARG_VALUE)") | |||
| lines.append(TAB + "}") | |||
| return lines | |||
| def render(self): | |||
| """ | |||
| @@ -84,6 +84,7 @@ static ASMErrorDesc parse_inst_##mnemonic( \ | |||
| if (err) \ | |||
| return err; \ | |||
| #define INST_NARGS nargs | |||
| #define INST_TYPE(n) args[n].type | |||
| #define INST_REG(n) args[n].data.reg | |||
| #define INST_IMM(n) args[n].data.imm | |||
| @@ -46,278 +46,278 @@ adc: | |||
| - cond: [a, _] | |||
| return: [0x8E] | |||
| add: | |||
| args: no | |||
| return: error | |||
| # add: | |||
| # args: no | |||
| # return: error | |||
| and: | |||
| args: no | |||
| return: error | |||
| # and: | |||
| # args: no | |||
| # return: error | |||
| bit: | |||
| args: no | |||
| return: error | |||
| # bit: | |||
| # args: no | |||
| # return: error | |||
| call: | |||
| args: no | |||
| return: error | |||
| # call: | |||
| # args: no | |||
| # return: error | |||
| ccf: | |||
| args: no | |||
| return: error | |||
| # ccf: | |||
| # args: no | |||
| # return: error | |||
| cp: | |||
| args: no | |||
| return: error | |||
| # cp: | |||
| # args: no | |||
| # return: error | |||
| cpd: | |||
| args: no | |||
| return: error | |||
| # cpd: | |||
| # args: no | |||
| # return: error | |||
| cpdr: | |||
| args: no | |||
| return: error | |||
| # cpdr: | |||
| # args: no | |||
| # return: error | |||
| cpi: | |||
| args: no | |||
| return: error | |||
| # cpi: | |||
| # args: no | |||
| # return: error | |||
| cpir: | |||
| args: no | |||
| return: error | |||
| # cpir: | |||
| # args: no | |||
| # return: error | |||
| cpl: | |||
| args: no | |||
| return: error | |||
| # cpl: | |||
| # args: no | |||
| # return: error | |||
| daa: | |||
| args: no | |||
| return: error | |||
| # daa: | |||
| # args: no | |||
| # return: error | |||
| dec: | |||
| args: no | |||
| return: error | |||
| # dec: | |||
| # args: no | |||
| # return: error | |||
| di: | |||
| args: no | |||
| return: error | |||
| # di: | |||
| # args: no | |||
| # return: error | |||
| djnz: | |||
| args: no | |||
| return: error | |||
| # djnz: | |||
| # args: no | |||
| # return: error | |||
| ei: | |||
| args: no | |||
| return: error | |||
| # ei: | |||
| # args: no | |||
| # return: error | |||
| ex: | |||
| args: no | |||
| return: error | |||
| # ex: | |||
| # args: no | |||
| # return: error | |||
| exx: | |||
| args: no | |||
| return: error | |||
| # exx: | |||
| # args: no | |||
| # return: error | |||
| halt: | |||
| args: no | |||
| return: error | |||
| # halt: | |||
| # args: no | |||
| # return: error | |||
| im: | |||
| args: no | |||
| return: error | |||
| # im: | |||
| # args: no | |||
| # return: error | |||
| in: | |||
| args: no | |||
| return: error | |||
| # in: | |||
| # args: no | |||
| # return: error | |||
| inc: | |||
| args: no | |||
| return: error | |||
| # inc: | |||
| # args: no | |||
| # return: error | |||
| ind: | |||
| args: no | |||
| return: error | |||
| # ind: | |||
| # args: no | |||
| # return: error | |||
| indr: | |||
| args: no | |||
| return: error | |||
| # indr: | |||
| # args: no | |||
| # return: error | |||
| ini: | |||
| args: no | |||
| return: [0xED, 0xA2] | |||
| inir: | |||
| args: no | |||
| return: error | |||
| # inir: | |||
| # args: no | |||
| # return: error | |||
| jp: | |||
| args: no | |||
| return: error | |||
| # jp: | |||
| # args: no | |||
| # return: error | |||
| jr: | |||
| args: no | |||
| return: error | |||
| # jr: | |||
| # args: no | |||
| # return: error | |||
| ld: | |||
| args: no | |||
| return: error | |||
| # ld: | |||
| # args: no | |||
| # return: error | |||
| ldd: | |||
| args: no | |||
| return: error | |||
| # ldd: | |||
| # args: no | |||
| # return: error | |||
| lddr: | |||
| args: no | |||
| return: error | |||
| # lddr: | |||
| # args: no | |||
| # return: error | |||
| ldi: | |||
| args: no | |||
| return: error | |||
| # ldi: | |||
| # args: no | |||
| # return: error | |||
| ldir: | |||
| args: no | |||
| return: error | |||
| # ldir: | |||
| # args: no | |||
| # return: error | |||
| neg: | |||
| args: no | |||
| return: error | |||
| # neg: | |||
| # args: no | |||
| # return: error | |||
| nop: | |||
| args: no | |||
| return: error | |||
| # nop: | |||
| # args: no | |||
| # return: error | |||
| or: | |||
| args: no | |||
| return: error | |||
| # or: | |||
| # args: no | |||
| # return: error | |||
| otdr: | |||
| args: no | |||
| return: error | |||
| # otdr: | |||
| # args: no | |||
| # return: error | |||
| otir: | |||
| args: no | |||
| return: error | |||
| # otir: | |||
| # args: no | |||
| # return: error | |||
| out: | |||
| args: no | |||
| return: error | |||
| # out: | |||
| # args: no | |||
| # return: error | |||
| outd: | |||
| args: no | |||
| return: error | |||
| # outd: | |||
| # args: no | |||
| # return: error | |||
| outi: | |||
| args: no | |||
| return: error | |||
| # outi: | |||
| # args: no | |||
| # return: error | |||
| pop: | |||
| args: no | |||
| return: error | |||
| # pop: | |||
| # args: no | |||
| # return: error | |||
| push: | |||
| args: no | |||
| return: error | |||
| # push: | |||
| # args: no | |||
| # return: error | |||
| res: | |||
| args: no | |||
| return: error | |||
| # res: | |||
| # args: no | |||
| # return: error | |||
| ret: | |||
| args: no | |||
| return: error | |||
| # ret: | |||
| # args: no | |||
| # return: error | |||
| reti: | |||
| args: no | |||
| return: error | |||
| # reti: | |||
| # args: no | |||
| # return: error | |||
| retn: | |||
| args: no | |||
| return: error | |||
| # retn: | |||
| # args: no | |||
| # return: error | |||
| rl: | |||
| args: no | |||
| return: error | |||
| # rl: | |||
| # args: no | |||
| # return: error | |||
| rla: | |||
| args: no | |||
| return: error | |||
| # rla: | |||
| # args: no | |||
| # return: error | |||
| rlc: | |||
| args: no | |||
| return: error | |||
| # rlc: | |||
| # args: no | |||
| # return: error | |||
| rlca: | |||
| args: no | |||
| return: error | |||
| # rlca: | |||
| # args: no | |||
| # return: error | |||
| rld: | |||
| args: no | |||
| return: error | |||
| # rld: | |||
| # args: no | |||
| # return: error | |||
| rr: | |||
| args: no | |||
| return: error | |||
| # rr: | |||
| # args: no | |||
| # return: error | |||
| rra: | |||
| args: no | |||
| return: error | |||
| # rra: | |||
| # args: no | |||
| # return: error | |||
| rrc: | |||
| args: no | |||
| return: error | |||
| # rrc: | |||
| # args: no | |||
| # return: error | |||
| rrca: | |||
| args: no | |||
| return: error | |||
| # rrca: | |||
| # args: no | |||
| # return: error | |||
| rrd: | |||
| args: no | |||
| return: error | |||
| # rrd: | |||
| # args: no | |||
| # return: error | |||
| rst: | |||
| args: no | |||
| return: error | |||
| # rst: | |||
| # args: no | |||
| # return: error | |||
| sbc: | |||
| args: no | |||
| return: error | |||
| # sbc: | |||
| # args: no | |||
| # return: error | |||
| scf: | |||
| args: no | |||
| return: error | |||
| # scf: | |||
| # args: no | |||
| # return: error | |||
| set: | |||
| args: no | |||
| return: error | |||
| # set: | |||
| # args: no | |||
| # return: error | |||
| sl1: | |||
| args: no | |||
| return: error | |||
| # sl1: | |||
| # args: no | |||
| # return: error | |||
| sla: | |||
| args: no | |||
| return: error | |||
| # sla: | |||
| # args: no | |||
| # return: error | |||
| sll: | |||
| args: no | |||
| return: error | |||
| # sll: | |||
| # args: no | |||
| # return: error | |||
| sls: | |||
| args: no | |||
| return: error | |||
| # sls: | |||
| # args: no | |||
| # return: error | |||
| sra: | |||
| args: no | |||
| return: error | |||
| # sra: | |||
| # args: no | |||
| # return: error | |||
| srl: | |||
| args: no | |||
| return: error | |||
| # srl: | |||
| # args: no | |||
| # return: error | |||
| sub: | |||
| args: no | |||
| return: error | |||
| # sub: | |||
| # args: no | |||
| # return: error | |||
| xor: | |||
| args: no | |||
| return: error | |||
| # xor: | |||
| # args: no | |||
| # return: error | |||