Browse Source

More work on asm instructions.

master
Ben Kurtovic 9 years ago
parent
commit
5f71035468
4 changed files with 328 additions and 217 deletions
  1. +4
    -2
      makefile
  2. +119
    -11
      scripts/update_asm_instructions.py
  3. +1
    -0
      src/assembler/instructions.c
  4. +204
    -204
      src/assembler/instructions.yml

+ 4
- 2
makefile View File

@@ -12,6 +12,7 @@ CFLAGS = $(shell sdl2-config --cflags)
LIBS = $(shell sdl2-config --libs) LIBS = $(shell sdl2-config --libs)
MKDIR = mkdir -p MKDIR = mkdir -p
RM = rm -rf RM = rm -rf
ASM_UP = scripts/update_asm_instructions.py


MODE = release MODE = release
BNRY = $(PROGRAM) BNRY = $(PROGRAM)
@@ -47,8 +48,9 @@ $(BUILD)/$(MODE)/%.o: %.c


-include $(DEPS) -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 test: test-all test-z80 test-asm test-dasm




+ 119
- 11
scripts/update_asm_instructions.py View File

@@ -12,6 +12,7 @@ when the latter is modified, but can also be run manually.


from __future__ import print_function from __future__ import print_function


from itertools import product
import re import re
import time import time


@@ -44,10 +45,13 @@ class Instruction(object):
"register": "AT_REGISTER", "register": "AT_REGISTER",
"immediate": "AT_IMMEDIATE", "immediate": "AT_IMMEDIATE",
"indirect": "AT_INDIRECT", "indirect": "AT_INDIRECT",
"indexed": "AT_INDEXED|AT_INDIRECT",
"indexed": "AT_INDEXED",
"condition": "AT_CONDITION", "condition": "AT_CONDITION",
"port": "AT_PORT" "port": "AT_PORT"
} }
ARG_EXTRA = {
"indexed": ["AT_INDIRECT"]
}


def __init__(self, name, data): def __init__(self, name, data):
self._name = name self._name = name
@@ -61,7 +65,10 @@ class Instruction(object):
optional = False optional = False
for case in self._data["cases"]: for case in self._data["cases"]:
if num < len(case["type"]): 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: else:
optional = True optional = True


@@ -71,22 +78,123 @@ class Instruction(object):
types.add("AT_OPTIONAL") types.add("AT_OPTIONAL")
return "|".join(types) 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. 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): 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): def render(self):
""" """


+ 1
- 0
src/assembler/instructions.c View File

@@ -84,6 +84,7 @@ static ASMErrorDesc parse_inst_##mnemonic( \
if (err) \ if (err) \
return err; \ return err; \


#define INST_NARGS nargs
#define INST_TYPE(n) args[n].type #define INST_TYPE(n) args[n].type
#define INST_REG(n) args[n].data.reg #define INST_REG(n) args[n].data.reg
#define INST_IMM(n) args[n].data.imm #define INST_IMM(n) args[n].data.imm


+ 204
- 204
src/assembler/instructions.yml View File

@@ -46,278 +46,278 @@ adc:
- cond: [a, _] - cond: [a, _]
return: [0x8E] 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: ini:
args: no args: no
return: [0xED, 0xA2] 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

Loading…
Cancel
Save