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.
 
 
 
 
 

469 lines
13 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. #include <limits.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "parse_util.h"
  7. #include "directives.h"
  8. #include "../logging.h"
  9. #include "../util.h"
  10. #define MAX_REGION_SIZE 32
  11. #define LCASE(c) ((c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c)
  12. #define DIRECTIVE_PARSE_FUNC(name, type) \
  13. bool dparse_##name(type *result, const ASMLine *line, const char *directive)
  14. /*
  15. All public functions in this file follow the same return conventions:
  16. - Return true on success and false on failure.
  17. - *result is only modified on success.
  18. */
  19. /*
  20. Read in a boolean value and store it in *result.
  21. */
  22. bool parse_bool(bool *result, const char *arg, ssize_t size)
  23. {
  24. switch (size) {
  25. case 1: // 0, 1
  26. if (*arg == '0' || *arg == '1')
  27. return (*result = *arg - '0'), true;
  28. return false;
  29. case 2: // on
  30. if (!strncmp(arg, "on", 2))
  31. return (*result = true), true;
  32. return false;
  33. case 3: // off
  34. if (!strncmp(arg, "off", 3))
  35. return (*result = false), true;
  36. return false;
  37. case 4: // true
  38. if (!strncmp(arg, "true", 4))
  39. return (*result = true), true;
  40. return false;
  41. case 5: // false
  42. if (!strncmp(arg, "false", 5))
  43. return (*result = false), true;
  44. return false;
  45. }
  46. return false;
  47. }
  48. /*
  49. Read in a 32-bit integer and store it in *result.
  50. */
  51. bool parse_uint32_t(uint32_t *result, const char *arg, ssize_t size)
  52. {
  53. if (size <= 0)
  54. return false;
  55. const char *end = arg + size;
  56. uint64_t value = 0;
  57. if (*arg == '$') {
  58. arg++;
  59. if (arg == end)
  60. return false;
  61. while (arg < end) {
  62. if (*arg >= '0' && *arg <= '9')
  63. value = (value * 0x10) + (*arg - '0');
  64. else if (*arg >= 'a' && *arg <= 'f')
  65. value = (value * 0x10) + 0xA + (*arg - 'a');
  66. else
  67. return false;
  68. if (value > UINT32_MAX)
  69. return false;
  70. arg++;
  71. }
  72. }
  73. else {
  74. while (arg < end) {
  75. if (*arg < '0' || *arg > '9')
  76. return false;
  77. value = (value * 10) + (*arg - '0');
  78. if (value > UINT32_MAX)
  79. return false;
  80. arg++;
  81. }
  82. }
  83. *result = value;
  84. return true;
  85. }
  86. /*
  87. Read in a string, possibly with escape sequences, and store it in *result.
  88. *length is also updated to the size of the string, which is *not*
  89. null-terminated. *result must be free()'d when finished.
  90. */
  91. bool parse_string(char **result, size_t *length, const char *arg, ssize_t size)
  92. {
  93. if (size < 2 || arg[0] != '"' || arg[size - 1] != '"')
  94. return false;
  95. ssize_t i, slashes = 0;
  96. for (i = 1; i < size; i++) {
  97. if (arg[i] == '"' && (slashes % 2) == 0)
  98. break;
  99. // TODO: parse escape codes here
  100. if (arg[i] == '\\')
  101. slashes++;
  102. else
  103. slashes = 0;
  104. }
  105. if (i != size - 1) // Junk present after closing quote
  106. return false;
  107. *length = size - 2;
  108. *result = malloc(sizeof(char) * (*length));
  109. if (!*result)
  110. OUT_OF_MEMORY()
  111. memcpy(*result, arg + 1, *length);
  112. return true;
  113. }
  114. /*
  115. Read in a space-separated sequence of bytes and store it in *result.
  116. *length is also updated to the number of bytes in the array. *result must
  117. be free()'d when finished.
  118. */
  119. bool parse_bytes(uint8_t **result, size_t *length, const char *arg, ssize_t size)
  120. {
  121. if (size <= 0)
  122. return false;
  123. const char *end = arg + size;
  124. uint8_t *bytes = NULL;
  125. size_t nbytes = 0;
  126. while (arg < end) {
  127. const char *start = arg;
  128. while (arg != end && *arg != ' ' && *arg != ',')
  129. arg++;
  130. uint32_t temp;
  131. if (!parse_uint32_t(&temp, start, arg - start) || temp > UINT8_MAX) {
  132. free(bytes);
  133. return false;
  134. }
  135. nbytes++;
  136. bytes = realloc(bytes, sizeof(uint8_t) * nbytes);
  137. if (!bytes)
  138. OUT_OF_MEMORY()
  139. bytes[nbytes - 1] = temp;
  140. if (arg < end - 1 && *arg == ',' && *(arg + 1) == ' ')
  141. arg += 2;
  142. else if (arg++ >= end)
  143. break;
  144. }
  145. *result = bytes;
  146. *length = nbytes;
  147. return true;
  148. }
  149. /*
  150. Read in a register argument and store it in *result.
  151. */
  152. bool argparse_register(ASMArgRegister *result, const char *arg, ssize_t size)
  153. {
  154. if (size < 1 || size > 3)
  155. return false;
  156. char buf[3] = {'\0'};
  157. switch (size) {
  158. case 3: buf[2] = LCASE(arg[2]);
  159. case 2: buf[1] = LCASE(arg[1]);
  160. case 1: buf[0] = LCASE(arg[0]);
  161. }
  162. switch (size) {
  163. case 1:
  164. switch (buf[0]) {
  165. case 'a': return (*result = REG_A), true;
  166. case 'f': return (*result = REG_F), true;
  167. case 'b': return (*result = REG_B), true;
  168. case 'c': return (*result = REG_C), true;
  169. case 'd': return (*result = REG_D), true;
  170. case 'e': return (*result = REG_E), true;
  171. case 'h': return (*result = REG_H), true;
  172. case 'l': return (*result = REG_L), true;
  173. case 'i': return (*result = REG_I), true;
  174. case 'r': return (*result = REG_R), true;
  175. }
  176. return false;
  177. case 2:
  178. switch ((buf[0] << 8) + buf[1]) {
  179. case 0x6166: return (*result = REG_AF), true;
  180. case 0x6263: return (*result = REG_BC), true;
  181. case 0x6465: return (*result = REG_DE), true;
  182. case 0x686C: return (*result = REG_HL), true;
  183. case 0x6978: return (*result = REG_IX), true;
  184. case 0x6979: return (*result = REG_IY), true;
  185. case 0x7063: return (*result = REG_PC), true;
  186. case 0x7370: return (*result = REG_SP), true;
  187. }
  188. return false;
  189. case 3:
  190. switch ((buf[0] << 16) + (buf[1] << 8) + buf[2]) {
  191. case 0x616627: return (*result = REG_AF_), true;
  192. case 0x697868: return (*result = REG_IXH), true;
  193. case 0x69786C: return (*result = REG_IXL), true;
  194. case 0x697968: return (*result = REG_IYH), true;
  195. case 0x69796C: return (*result = REG_IYL), true;
  196. }
  197. return false;
  198. }
  199. return false;
  200. }
  201. /*
  202. Read in a condition argument and store it in *result.
  203. */
  204. bool argparse_condition(ASMArgCondition *result, const char *arg, ssize_t size)
  205. {
  206. if (size < 1 || size > 2)
  207. return false;
  208. char buf[2] = {'\0'};
  209. switch (size) {
  210. case 2: buf[1] = LCASE(arg[1]);
  211. case 1: buf[0] = LCASE(arg[0]);
  212. }
  213. switch (size) {
  214. case 1:
  215. switch (buf[0]) {
  216. case 'n': return (*result = COND_N), true;
  217. case 'c': return (*result = COND_C), true;
  218. case 'p': return (*result = COND_P), true;
  219. case 'm': return (*result = COND_M), true;
  220. }
  221. return false;
  222. case 2:
  223. switch ((buf[0] << 8) + buf[1]) {
  224. case 0x6E7A: return (*result = COND_NZ), true;
  225. case 0x6E63: return (*result = COND_NC), true;
  226. case 0x706F: return (*result = COND_PO), true;
  227. case 0x7065: return (*result = COND_PE), true;
  228. }
  229. return false;
  230. }
  231. return false;
  232. }
  233. /*
  234. Read in an immediate argument and store it in *result.
  235. */
  236. bool argparse_immediate(ASMArgImmediate *result, const char *arg, ssize_t size)
  237. {
  238. bool negative = false;
  239. ssize_t i = 0;
  240. if (size <= 0)
  241. return false;
  242. while (arg[i] == '-' || arg[i] == '+' || arg[i] == ' ') {
  243. if (arg[i] == '-')
  244. negative = !negative;
  245. if (++i >= size)
  246. return false;
  247. }
  248. uint32_t uval;
  249. if (!parse_uint32_t(&uval, arg, size) || uval > UINT16_MAX)
  250. return false;
  251. int32_t sval = negative ? uval : -uval;
  252. if (sval < INT16_MIN)
  253. return false;
  254. result->uval = uval;
  255. result->sval = sval;
  256. result->mask = 0;
  257. if (negative) {
  258. if (sval >= INT8_MIN && sval <= INT8_MAX)
  259. result->mask |= IMM_S8;
  260. if (sval >= INT8_MIN + 2 && sval <= INT8_MAX + 2)
  261. result->mask |= IMM_REL;
  262. } else {
  263. result->mask = IMM_U16;
  264. if (uval <= UINT8_MAX)
  265. result->mask |= IMM_U8;
  266. if (uval <= 7)
  267. result->mask |= IMM_BIT;
  268. if (!(uval & ~0x38))
  269. result->mask |= IMM_RST;
  270. if (uval <= 2)
  271. result->mask |= IMM_IM;
  272. }
  273. return true;
  274. }
  275. /*
  276. Read in an indirect argument and store it in *result.
  277. */
  278. bool argparse_indirect(ASMArgIndirect *result, const char *arg, ssize_t size)
  279. {
  280. if (size < 3)
  281. return false;
  282. if (arg[0] != '(' || arg[size - 1] != ')')
  283. return false;
  284. arg++;
  285. size -= 2;
  286. ASMArgRegister reg;
  287. ASMArgImmediate imm;
  288. if (argparse_register(&reg, arg, size)) {
  289. if (reg == REG_BC || reg == REG_DE || reg == REG_HL) {
  290. result->type = AT_REGISTER;
  291. result->addr.reg = reg;
  292. return true;
  293. }
  294. } else if (argparse_immediate(&imm, arg, size)) {
  295. if (imm.mask & IMM_U16) {
  296. result->type = AT_IMMEDIATE;
  297. result->addr.imm = imm;
  298. return true;
  299. }
  300. }
  301. return false;
  302. }
  303. /*
  304. Read in a boolean argument from the given line and store it in *result.
  305. */
  306. DIRECTIVE_PARSE_FUNC(bool, bool)
  307. {
  308. size_t offset = DIRECTIVE_OFFSET(line, directive) + 1;
  309. return parse_bool(result, line->data + offset, line->length - offset);
  310. }
  311. /*
  312. Read in a 32-bit int argument from the given line and store it in *result.
  313. */
  314. DIRECTIVE_PARSE_FUNC(uint32_t, uint32_t)
  315. {
  316. size_t offset = DIRECTIVE_OFFSET(line, directive) + 1;
  317. return parse_uint32_t(result, line->data + offset, line->length - offset);
  318. }
  319. /*
  320. Read in a 16-bit int argument from the given line and store it in *result.
  321. */
  322. DIRECTIVE_PARSE_FUNC(uint16_t, uint16_t)
  323. {
  324. uint32_t value;
  325. if (dparse_uint32_t(&value, line, directive) && value <= UINT16_MAX)
  326. return (*result = value), true;
  327. return false;
  328. }
  329. /*
  330. Read in an 8-bit int argument from the given line and store it in *result.
  331. */
  332. DIRECTIVE_PARSE_FUNC(uint8_t, uint8_t)
  333. {
  334. uint32_t value;
  335. if (dparse_uint32_t(&value, line, directive) && value <= UINT8_MAX)
  336. return (*result = value), true;
  337. return false;
  338. }
  339. /*
  340. Parse a ROM size string in an ASMLine and store it in *result.
  341. */
  342. DIRECTIVE_PARSE_FUNC(rom_size, uint32_t)
  343. {
  344. const char *arg = line->data + DIRECTIVE_OFFSET(line, directive) + 1;
  345. const char *end = line->data + line->length - 1;
  346. if (end - arg < 5)
  347. return false;
  348. if (*(arg++) != '"' || *(end--) != '"')
  349. return false;
  350. if (*end != 'B' && *end != 'b')
  351. return false;
  352. end--;
  353. uint32_t factor;
  354. if (*end == 'K' || *end == 'k')
  355. factor = 1 << 10;
  356. else if (*end == 'M' || *end == 'm')
  357. factor = 1 << 20;
  358. else
  359. return false;
  360. end--;
  361. if (*end != ' ')
  362. return false;
  363. uint32_t value = 0;
  364. while (arg < end) {
  365. if (*arg < '0' || *arg > '9')
  366. return false;
  367. value = (value * 10) + (*arg - '0');
  368. if (value > UINT16_MAX)
  369. return false;
  370. arg++;
  371. }
  372. *result = value * factor;
  373. return true;
  374. }
  375. /*
  376. Parse a region code string in an ASMLine and store it in *result.
  377. */
  378. DIRECTIVE_PARSE_FUNC(region_string, uint8_t)
  379. {
  380. char buffer[MAX_REGION_SIZE];
  381. size_t offset = DIRECTIVE_OFFSET(line, directive) + 1;
  382. const char *arg = line->data + offset;
  383. ssize_t len = line->length - offset;
  384. if (len <= 2 || len >= MAX_REGION_SIZE + 2) // Account for double quotes
  385. return false;
  386. if (arg[0] != '"' || arg[len - 1] != '"')
  387. return false;
  388. strncpy(buffer, arg + 1, len - 2);
  389. buffer[len - 2] = '\0';
  390. uint8_t code = region_string_to_code(buffer);
  391. if (code)
  392. return (*result = code), true;
  393. return false;
  394. }
  395. /*
  396. Parse a size code in an ASMLine and store it in *result.
  397. */
  398. DIRECTIVE_PARSE_FUNC(size_code, uint8_t)
  399. {
  400. uint32_t bytes;
  401. if (!dparse_uint32_t(&bytes, line, directive)) {
  402. if (!dparse_rom_size(&bytes, line, directive))
  403. return false;
  404. }
  405. uint8_t code = size_bytes_to_code(bytes);
  406. if (code != INVALID_SIZE_CODE)
  407. return (*result = code), true;
  408. return false;
  409. }