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.
 
 
 
 
 

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