@@ -24,7 +24,7 @@ | |||||
#define HANDLE(m) if (key == MAKE_CMP_(#m)) return parse_inst_##m; | #define HANDLE(m) if (key == MAKE_CMP_(#m)) return parse_inst_##m; | ||||
/* Internal helper macros for instruction parsers */ | |||||
/* Internal helper macros */ | |||||
#define INST_ALLOC_(len) \ | #define INST_ALLOC_(len) \ | ||||
*length = len; \ | *length = len; \ | ||||
@@ -43,8 +43,12 @@ | |||||
INST_DISPATCH_(__VA_ARGS__, INST_SET4_, INST_SET3_, INST_SET2_, \ | INST_DISPATCH_(__VA_ARGS__, INST_SET4_, INST_SET3_, INST_SET2_, \ | ||||
INST_SET1_, __VA_ARGS__)(__VA_ARGS__)); | INST_SET1_, __VA_ARGS__)(__VA_ARGS__)); | ||||
#define INST_IX_PREFIX_ 0xDD | |||||
#define INST_IY_PREFIX_ 0xFD | |||||
#define INST_PREFIX_(reg) \ | #define INST_PREFIX_(reg) \ | ||||
(((reg) == REG_IX || (reg) == REG_IXH || (reg) == REG_IXL) ? 0xDD : 0xFD) | |||||
(((reg) == REG_IX || (reg) == REG_IXH || (reg) == REG_IXL) ? \ | |||||
INST_IX_PREFIX_ : INST_IY_PREFIX_) | |||||
#define INST_RETURN_WITH_SYMBOL_(len, label, ...) { \ | #define INST_RETURN_WITH_SYMBOL_(len, label, ...) { \ | ||||
*symbol = cr_strdup(label.text); \ | *symbol = cr_strdup(label.text); \ | ||||
@@ -53,7 +57,7 @@ | |||||
return ED_NONE; \ | return ED_NONE; \ | ||||
} | } | ||||
/* Helper macros for instruction parsers */ | |||||
/* Essential/basic helper macros */ | |||||
#define INST_FUNC(mnemonic) \ | #define INST_FUNC(mnemonic) \ | ||||
static ASMErrorDesc parse_inst_##mnemonic( \ | static ASMErrorDesc parse_inst_##mnemonic( \ | ||||
@@ -87,6 +91,15 @@ static ASMErrorDesc parse_inst_##mnemonic( \ | |||||
#define INST_LABEL(n) args[n].data.label | #define INST_LABEL(n) args[n].data.label | ||||
#define INST_COND(n) args[n].data.cond | #define INST_COND(n) args[n].data.cond | ||||
#define INST_RETURN(len, ...) { \ | |||||
(void) symbol; \ | |||||
INST_ALLOC_(len) \ | |||||
INST_FILL_BYTES_(len, __VA_ARGS__) \ | |||||
return ED_NONE; \ | |||||
} | |||||
/* Convenience macros */ | |||||
#define INST_FORCE_TYPE(n, t) { \ | #define INST_FORCE_TYPE(n, t) { \ | ||||
if (INST_TYPE(n) != t) \ | if (INST_TYPE(n) != t) \ | ||||
INST_ERROR(ARG##n##_TYPE) \ | INST_ERROR(ARG##n##_TYPE) \ | ||||
@@ -97,6 +110,13 @@ static ASMErrorDesc parse_inst_##mnemonic( \ | |||||
INST_ERROR(ARG##n##_RANGE) \ | INST_ERROR(ARG##n##_RANGE) \ | ||||
} | } | ||||
#define INST_REG_ONLY(n, reg) { \ | |||||
if (INST_TYPE(n) != AT_REGISTER) \ | |||||
INST_ERROR(ARG##n##_TYPE) \ | |||||
if (INST_REG(n) != reg) \ | |||||
INST_ERROR(ARG##n##_BAD_REG) \ | |||||
} | |||||
#define INST_INDIRECT_HL_ONLY(n) { \ | #define INST_INDIRECT_HL_ONLY(n) { \ | ||||
if (INST_INDIRECT(n).type != AT_REGISTER) \ | if (INST_INDIRECT(n).type != AT_REGISTER) \ | ||||
INST_ERROR(ARG##n##_TYPE) \ | INST_ERROR(ARG##n##_TYPE) \ | ||||
@@ -104,13 +124,6 @@ static ASMErrorDesc parse_inst_##mnemonic( \ | |||||
INST_ERROR(ARG##n##_BAD_REG) \ | INST_ERROR(ARG##n##_BAD_REG) \ | ||||
} | } | ||||
#define INST_RETURN(len, ...) { \ | |||||
(void) symbol; \ | |||||
INST_ALLOC_(len) \ | |||||
INST_FILL_BYTES_(len, __VA_ARGS__) \ | |||||
return ED_NONE; \ | |||||
} | |||||
#define INST_INDEX_PREFIX(n) INST_PREFIX_(INST_INDEX(n).reg) | #define INST_INDEX_PREFIX(n) INST_PREFIX_(INST_INDEX(n).reg) | ||||
#define INST_INDEX_BYTES(n, b) \ | #define INST_INDEX_BYTES(n, b) \ | ||||
@@ -123,7 +136,20 @@ static ASMErrorDesc parse_inst_##mnemonic( \ | |||||
#define INST_RETURN_INDIRECT_LABEL(n, len, ...) \ | #define INST_RETURN_INDIRECT_LABEL(n, len, ...) \ | ||||
INST_RETURN_WITH_SYMBOL_(len, INST_INDIRECT(n).addr.label, __VA_ARGS__) | INST_RETURN_WITH_SYMBOL_(len, INST_INDIRECT(n).addr.label, __VA_ARGS__) | ||||
/* Functions */ | |||||
#define INST_HANDLE_MAIN_8_BIT_REGS(base) \ | |||||
case REG_A: INST_RETURN(1, base + 7) \ | |||||
case REG_B: INST_RETURN(1, base) \ | |||||
case REG_C: INST_RETURN(1, base + 1) \ | |||||
case REG_D: INST_RETURN(1, base + 2) \ | |||||
case REG_E: INST_RETURN(1, base + 3) \ | |||||
case REG_H: INST_RETURN(1, base + 4) \ | |||||
case REG_L: INST_RETURN(1, base + 5) \ | |||||
case REG_IXH: INST_RETURN(2, INST_IX_PREFIX_, base + 4) \ | |||||
case REG_IXL: INST_RETURN(2, INST_IX_PREFIX_, base + 5) \ | |||||
case REG_IYH: INST_RETURN(2, INST_IY_PREFIX_, base + 4) \ | |||||
case REG_IYL: INST_RETURN(2, INST_IY_PREFIX_, base + 5) \ | |||||
/* Internal functions */ | |||||
uint8_t fill_bytes_variadic(uint8_t*, size_t, ...); | uint8_t fill_bytes_variadic(uint8_t*, size_t, ...); | ||||
ASMErrorDesc parse_args(ASMInstArg args[3], size_t*, ASMArgParseInfo); | ASMErrorDesc parse_args(ASMInstArg args[3], size_t*, ASMArgParseInfo); |
@@ -15,17 +15,7 @@ INST_FUNC(adc) | |||||
switch (INST_TYPE(1)) { | switch (INST_TYPE(1)) { | ||||
case AT_REGISTER: | case AT_REGISTER: | ||||
switch (INST_REG(1)) { | switch (INST_REG(1)) { | ||||
case REG_A: INST_RETURN(1, 0x8F) | |||||
case REG_B: INST_RETURN(1, 0x88) | |||||
case REG_C: INST_RETURN(1, 0x89) | |||||
case REG_D: INST_RETURN(1, 0x8A) | |||||
case REG_E: INST_RETURN(1, 0x8B) | |||||
case REG_H: INST_RETURN(1, 0x8C) | |||||
case REG_L: INST_RETURN(1, 0x8D) | |||||
case REG_IXH: INST_RETURN(2, 0xDD, 0x8C) | |||||
case REG_IXL: INST_RETURN(2, 0xDD, 0x8D) | |||||
case REG_IYH: INST_RETURN(2, 0xFD, 0x8C) | |||||
case REG_IYL: INST_RETURN(2, 0xFD, 0x8D) | |||||
INST_HANDLE_MAIN_8_BIT_REGS(0x88) | |||||
default: INST_ERROR(ARG1_BAD_REG) | default: INST_ERROR(ARG1_BAD_REG) | ||||
} | } | ||||
case AT_IMMEDIATE: | case AT_IMMEDIATE: | ||||
@@ -62,17 +52,7 @@ INST_FUNC(add) | |||||
switch (INST_TYPE(1)) { | switch (INST_TYPE(1)) { | ||||
case AT_REGISTER: | case AT_REGISTER: | ||||
switch (INST_REG(1)) { | switch (INST_REG(1)) { | ||||
case REG_A: INST_RETURN(1, 0x87) | |||||
case REG_B: INST_RETURN(1, 0x80) | |||||
case REG_C: INST_RETURN(1, 0x81) | |||||
case REG_D: INST_RETURN(1, 0x82) | |||||
case REG_E: INST_RETURN(1, 0x83) | |||||
case REG_H: INST_RETURN(1, 0x84) | |||||
case REG_L: INST_RETURN(1, 0x85) | |||||
case REG_IXH: INST_RETURN(2, 0xDD, 0x84) | |||||
case REG_IXL: INST_RETURN(2, 0xDD, 0x85) | |||||
case REG_IYH: INST_RETURN(2, 0xFD, 0x84) | |||||
case REG_IYL: INST_RETURN(2, 0xFD, 0x85) | |||||
INST_HANDLE_MAIN_8_BIT_REGS(0x80) | |||||
default: INST_ERROR(ARG1_BAD_REG) | default: INST_ERROR(ARG1_BAD_REG) | ||||
} | } | ||||
case AT_IMMEDIATE: | case AT_IMMEDIATE: | ||||
@@ -329,6 +309,7 @@ INST_FUNC(jr) | |||||
INST_FUNC(ld) | INST_FUNC(ld) | ||||
{ | { | ||||
uint8_t base; | |||||
INST_TAKES_ARGS(2, 2) | INST_TAKES_ARGS(2, 2) | ||||
switch (INST_TYPE(0)) { | switch (INST_TYPE(0)) { | ||||
case AT_REGISTER: | case AT_REGISTER: | ||||
@@ -337,19 +318,9 @@ INST_FUNC(ld) | |||||
switch (INST_TYPE(1)) { | switch (INST_TYPE(1)) { | ||||
case AT_REGISTER: | case AT_REGISTER: | ||||
switch (INST_REG(1)) { | switch (INST_REG(1)) { | ||||
case REG_A: INST_RETURN(1, 0x7F) | |||||
case REG_B: INST_RETURN(1, 0x78) | |||||
case REG_C: INST_RETURN(1, 0x79) | |||||
case REG_D: INST_RETURN(1, 0x7A) | |||||
case REG_E: INST_RETURN(1, 0x7B) | |||||
case REG_H: INST_RETURN(1, 0x7C) | |||||
case REG_L: INST_RETURN(1, 0x7D) | |||||
INST_HANDLE_MAIN_8_BIT_REGS(0x78) | |||||
case REG_I: INST_RETURN(2, 0xED, 0x57) | case REG_I: INST_RETURN(2, 0xED, 0x57) | ||||
case REG_R: INST_RETURN(2, 0xED, 0x5F) | case REG_R: INST_RETURN(2, 0xED, 0x5F) | ||||
case REG_IXH: INST_RETURN(2, 0xDD, 0x7C) | |||||
case REG_IXL: INST_RETURN(2, 0xDD, 0x7D) | |||||
case REG_IYH: INST_RETURN(2, 0xFD, 0x7C) | |||||
case REG_IYL: INST_RETURN(2, 0xFD, 0x7D) | |||||
default: INST_ERROR(ARG1_BAD_REG) | default: INST_ERROR(ARG1_BAD_REG) | ||||
} | } | ||||
case AT_IMMEDIATE: | case AT_IMMEDIATE: | ||||
@@ -369,21 +340,46 @@ INST_FUNC(ld) | |||||
case AT_LABEL: | case AT_LABEL: | ||||
INST_RETURN_INDIRECT_LABEL(1, 3, 0x3A) | INST_RETURN_INDIRECT_LABEL(1, 3, 0x3A) | ||||
default: | default: | ||||
INST_ERROR(ARG0_TYPE) | |||||
INST_ERROR(ARG1_TYPE) | |||||
} | } | ||||
case AT_INDEXED: | case AT_INDEXED: | ||||
INST_RETURN(3, INST_INDEX_BYTES(1, 0x7E)) | INST_RETURN(3, INST_INDEX_BYTES(1, 0x7E)) | ||||
default: | default: | ||||
INST_ERROR(ARG1_TYPE) | INST_ERROR(ARG1_TYPE) | ||||
} | } | ||||
case REG_B: // TODO (15 cases) | |||||
case REG_C: // TODO (15 cases) | |||||
case REG_D: // TODO (15 cases) | |||||
case REG_E: // TODO (15 cases) | |||||
case REG_B: | |||||
base = 0x00; | |||||
case REG_C: | |||||
base = 0x08; | |||||
case REG_D: | |||||
base = 0x10; | |||||
case REG_E: | |||||
base = 0x18; | |||||
switch (INST_TYPE(1)) { | |||||
case AT_REGISTER: | |||||
switch (INST_REG(1)) { | |||||
INST_HANDLE_MAIN_8_BIT_REGS(base + 0x40) | |||||
default: INST_ERROR(ARG1_BAD_REG) | |||||
} | |||||
case AT_IMMEDIATE: | |||||
INST_CHECK_IMM(1, IMM_U8) | |||||
INST_RETURN(2, base + 0x06, INST_IMM(1).uval) | |||||
case AT_INDIRECT: | |||||
INST_INDIRECT_HL_ONLY(1) | |||||
INST_RETURN(1, base + 0x46) | |||||
case AT_INDEXED: | |||||
INST_RETURN(3, INST_INDEX_BYTES(1, base + 0x46)) | |||||
default: | |||||
INST_ERROR(ARG1_TYPE) | |||||
} | |||||
case REG_H: // TODO (11 cases) | case REG_H: // TODO (11 cases) | ||||
case REG_L: // TODO (11 cases) | case REG_L: // TODO (11 cases) | ||||
case REG_I: // TODO ( 1 case ) | |||||
case REG_R: // TODO ( 1 case ) | |||||
case REG_I: | |||||
INST_REG_ONLY(1, REG_A) | |||||
INST_RETURN(2, 0xED, 0x47) | |||||
case REG_R: | |||||
INST_REG_ONLY(1, REG_A) | |||||
INST_RETURN(2, 0xED, 0x4F) | |||||
case REG_BC: // TODO ( 2 cases) | case REG_BC: // TODO ( 2 cases) | ||||
case REG_DE: // TODO ( 2 cases) | case REG_DE: // TODO ( 2 cases) | ||||
case REG_HL: // TODO ( 3 cases) | case REG_HL: // TODO ( 3 cases) | ||||