An emulator, assembler, and disassembler for the Sega Game Gear
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 

574 lignes
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. }