An emulator, assembler, and disassembler for the Sega Game Gear
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

130 lines
5.9 KiB

  1. /* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
  2. Released under the terms of the MIT License. See LICENSE for details. */
  3. #pragma once
  4. #include <stdarg.h>
  5. #include <stdlib.h>
  6. #include "errors.h"
  7. #include "inst_args.h"
  8. #include "parse_util.h"
  9. #include "../util.h"
  10. /* Helper macros for get_inst_parser() */
  11. #define JOIN_(a, b, c, d) ((uint32_t) ((a << 24) + (b << 16) + (c << 8) + d))
  12. #define DISPATCH_(s, z) ( \
  13. (z) == 2 ? JOIN_(s[0], s[1], 0x00, 0x00) : \
  14. (z) == 3 ? JOIN_(s[0], s[1], s[2], 0x00) : \
  15. JOIN_(s[0], s[1], s[2], s[3])) \
  16. #define MAKE_CMP_(s) DISPATCH_(s, sizeof(s) / sizeof(char) - 1)
  17. #define HANDLE(m) if (key == MAKE_CMP_(#m)) return parse_inst_##m;
  18. /* Internal helper macros for instruction parsers */
  19. #define INST_ALLOC_(len) \
  20. *length = len; \
  21. *bytes = cr_malloc(sizeof(uint8_t) * (len));
  22. #define INST_SET_(b, val) ((*bytes)[b] = val)
  23. #define INST_SET1_(b1) INST_SET_(0, b1)
  24. #define INST_SET2_(b1, b2) INST_SET1_(b1), INST_SET_(1, b2)
  25. #define INST_SET3_(b1, b2, b3) INST_SET2_(b1, b2), INST_SET_(2, b3)
  26. #define INST_SET4_(b1, b2, b3, b4) INST_SET3_(b1, b2, b3), INST_SET_(3, b4)
  27. #define INST_DISPATCH_(a, b, c, d, target, ...) target
  28. #define INST_FILL_BYTES_(len, ...) \
  29. ((len > 4) ? fill_bytes_variadic(*bytes, len, __VA_ARGS__) : \
  30. INST_DISPATCH_(__VA_ARGS__, INST_SET4_, INST_SET3_, INST_SET2_, \
  31. INST_SET1_, __VA_ARGS__)(__VA_ARGS__));
  32. #define INST_PREFIX_(reg) \
  33. (((reg) == REG_IX || (reg) == REG_IXH || (reg) == REG_IXL) ? 0xDD : 0xFD)
  34. #define INST_RETURN_WITH_SYMBOL_(len, label, ...) { \
  35. *symbol = cr_strdup(label.text); \
  36. INST_ALLOC_(len) \
  37. INST_FILL_BYTES_(len - 2, __VA_ARGS__) \
  38. return ED_NONE; \
  39. }
  40. /* Helper macros for instruction parsers */
  41. #define INST_FUNC(mnemonic) \
  42. static ASMErrorDesc parse_inst_##mnemonic( \
  43. uint8_t **bytes, size_t *length, char **symbol, ASMArgParseInfo ap_info) \
  44. #define INST_ERROR(desc) return ED_PS_##desc;
  45. #define INST_TAKES_NO_ARGS \
  46. if (ap_info.arg) \
  47. INST_ERROR(TOO_MANY_ARGS)
  48. #define INST_TAKES_ARGS(lo, hi) \
  49. if (!ap_info.arg) \
  50. INST_ERROR(TOO_FEW_ARGS) \
  51. ASMInstArg args[3]; \
  52. size_t nargs = 0; \
  53. ASMErrorDesc err = parse_args(args, &nargs, ap_info); \
  54. if (err) \
  55. return err; \
  56. if (nargs < lo) \
  57. INST_ERROR(TOO_FEW_ARGS) \
  58. if (nargs > hi) \
  59. INST_ERROR(TOO_MANY_ARGS)
  60. #define INST_NARGS nargs
  61. #define INST_TYPE(n) args[n].type
  62. #define INST_REG(n) args[n].data.reg
  63. #define INST_IMM(n) args[n].data.imm
  64. #define INST_INDIRECT(n) args[n].data.indirect
  65. #define INST_INDEX(n) args[n].data.index
  66. #define INST_LABEL(n) args[n].data.label
  67. #define INST_COND(n) args[n].data.cond
  68. #define INST_FORCE_TYPE(n, t) { \
  69. if (INST_TYPE(n) != t) \
  70. INST_ERROR(ARG##n##_TYPE) \
  71. }
  72. #define INST_CHECK_IMM(n, m) { \
  73. if (!(INST_IMM(n).mask & (m))) \
  74. INST_ERROR(ARG##n##_RANGE) \
  75. }
  76. #define INST_INDIRECT_HL_ONLY(n) { \
  77. if (INST_INDIRECT(n).type != AT_REGISTER) \
  78. INST_ERROR(ARG##n##_TYPE) \
  79. if (INST_INDIRECT(n).addr.reg != REG_HL) \
  80. INST_ERROR(ARG##n##_BAD_REG) \
  81. }
  82. #define INST_RETURN(len, ...) { \
  83. (void) symbol; \
  84. INST_ALLOC_(len) \
  85. INST_FILL_BYTES_(len, __VA_ARGS__) \
  86. return ED_NONE; \
  87. }
  88. #define INST_INDEX_PREFIX(n) INST_PREFIX_(INST_INDEX(n).reg)
  89. #define INST_INDEX_BYTES(n, b) \
  90. INST_INDEX_PREFIX(n), b, INST_INDEX(n).offset
  91. #define INST_INDIRECT_IMM(n) \
  92. INST_INDIRECT(n).addr.imm.uval >> 8, \
  93. INST_INDIRECT(n).addr.imm.uval & 0xFF
  94. #define INST_RETURN_INDIRECT_LABEL(n, len, ...) \
  95. INST_RETURN_WITH_SYMBOL_(len, INST_INDIRECT(n).addr.label, __VA_ARGS__)
  96. /* Functions */
  97. uint8_t fill_bytes_variadic(uint8_t*, size_t, ...);
  98. ASMErrorDesc parse_args(ASMInstArg args[3], size_t*, ASMArgParseInfo);