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.
 
 
 
 
 

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