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.
 
 
 
 
 

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