zymosis: renamed "SLL" to "SLS"
[zymosis.git] / src / liburasm / liburasm.h
blob6e515b62f0227a427e9bfb0378c3609c9d8627c3
1 /* coded by Ketmar // Invisible Vector (ketmar@ketmar.no-ip.org)
2 * Understanding is not required. Only obedience.
4 * URASM Z80 assembler/disassembler core v0.1.3 (with ZXNext support)
6 * This program is free software. It comes without any warranty, to
7 * the extent permitted by applicable law. You can redistribute it
8 * and/or modify it under the terms of the Do What The Fuck You Want
9 * To Public License, Version 2, as published by Sam Hocevar. See
10 * http://sam.zoy.org/wtfpl/COPYING for more details.
12 #ifndef LIBURASM_HEADER
13 #define LIBURASM_HEADER
15 #include <stdint.h>
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
22 /******************************************************************************/
23 /* all known tokens (opcode mnemonics) */
24 /******************************************************************************/
25 enum {
26 UT_ADC, UT_ADD, UT_AND, UT_BIT,
27 UT_CALL, UT_CCF, UT_CP, UT_CPD,
28 UT_CPDR, UT_CPI, UT_CPIR, UT_CPL,
29 UT_DAA, UT_DEC, UT_DI, UT_DJNZ,
30 UT_EI, UT_EX, UT_EXX, UT_HALT,
31 UT_IM, UT_IN, UT_INC, UT_IND,
32 UT_INDR, UT_INI, UT_INIR, UT_JP,
33 UT_JR, UT_LD, UT_LDD, UT_LDDR,
34 UT_LDI, UT_LDIR, UT_NEG, UT_NOP,
35 UT_OR, UT_OTDR, UT_OTIR, UT_OUT,
36 UT_OUTD, UT_OUTI, UT_POP, UT_PUSH,
37 UT_RES, UT_RET, UT_RETI, UT_RETN,
38 UT_RL, UT_RLA, UT_RLC, UT_RLCA,
39 UT_RLD, UT_RR, UT_RRA, UT_RRC,
40 UT_RRCA, UT_RRD, UT_RST, UT_SBC,
41 UT_SCF, UT_SET, UT_SLA, UT_SLL,
42 UT_SLS, UT_SRA, UT_SRL, UT_SUB,
43 UT_XOR, UT_XSLT, UT_NOPX, UT_NOPY,
44 /* ZXNext */
45 UT_LDIX, UT_LDWS, UT_LDIRX, UT_LDDX,
46 UT_LDDRX, UT_LDPIRX, UT_OUTINB, UT_MUL,
47 UT_SWAPNIB, UT_MIRROR, UT_NEXTREG, UT_PIXELDN,
48 UT_PIXELAD, UT_SETAE, UT_TEST, UT_BSLA,
49 UT_BSRA, UT_BSRL, UT_BSRF, UT_BRLC,
50 /* max values */
51 URASM_MAX_TOKEN,
52 URASM_MAX_NORMAL_TOKEN = UT_NOPY+1
54 extern const char *URASM_TOKENS[URASM_MAX_TOKEN];
57 /* can be used to decode various command operands */
58 extern const char *URA_REGS8[8]; /* 8-bit register names */
59 extern const char *URA_REGS16[4]; /* 16-bit register names, with SP, without AF */
60 extern const char *URA_REGS16A[4]; /* 16-bit register names, with AF, without SP */
61 extern const char *URA_COND[8]; /* branch condition names */
64 /* all possible operands */
65 /* there are so many for proper assembling */
66 /* i wanted to perform a simple table lookup w/o special cases, */
67 /* so all special cases were encoded as various operand types */
68 enum {
69 UO_NONE,
70 UO_IMM8, /* immediate constant */
71 UO_IMM16, /* immediate constant */
72 UO_IMM16BE,/* immediate constant, big-endian */
73 UO_ADDR16, /* immediate address (JP/CALL) */
74 UO_ADDR8, /* immediate address (JR/DJNZ) */
75 UO_MEM16, /* immediate memory (nnnn) */
76 /* 8 bit registers (bits 0-2 of opcode) */
77 UO_R8, /* B,C,D,E,H,L,(HL),A */
78 UO_R8_NOM, /* B,C,D,E,H,L,A, but no (HL) */
79 UO_R8_NOM_NOHL, /* B,C,D,E,A, but no H,L,(HL) */
80 /* 8 bit registers (bits 3-5 of opcode) */
81 UO_2R8, /* B,C,D,E,H,L,(HL),A */
82 UO_2R8_NOM,/* B,C,D,E,H,L,A, but no (HL) */
83 UO_2R8_NOM_NOHL, /* B,C,D,E,A, but no H,L,(HL) */
84 /* for port i/o */
85 UO_PORTC, /* (C) */
86 UO_PORTIMM,/* (nn) */
87 /* special 8 bit registers */
88 UO_R8_XH, /* XH */
89 UO_R8_XL, /* XL */
90 UO_R8_YH, /* YH */
91 UO_R8_YL, /* YL */
92 UO_R8_A, /* A */
93 UO_R8_B, /* B */
94 UO_R8_R, /* R */
95 UO_R8_I, /* I */
96 /* 16 bit registers (bits 4-5 of opcode), with SP */
97 UO_R16, /* BC,DE,HL,SP */
98 /* 16 bit registers (bits 4-5 of opcode), with AF */
99 UO_R16A, /* BC,DE,HL,AF */
100 /* AF & AF' for EX AF,AF' */
101 UO_R16AF, /* AF */
102 UO_R16AFX, /* AF' */
103 UO_R16BC, /* BC */
104 UO_R16DE, /* DE */
105 UO_R16HL, /* HL */
106 UO_R16IX, /* IX */
107 UO_R16IY, /* IY */
108 UO_R16SP, /* SP */
109 UO_MSP, /* (SP) */
110 UO_MBC, /* (BC) */
111 UO_MDE, /* (DE) */
112 UO_MHL, /* (HL) */
113 UO_MIX, /* (IX+disp) */
114 UO_MIY, /* (IY+disp) */
115 UO_MIX0, /* (IX) */
116 UO_MIY0, /* (IY) */
117 /* JR condition (bits 3-4 of opcode) */
118 UO_JRCOND,
119 /* conditions (bits 3-5 of opcode) */
120 UO_COND,
121 /* CB opcodes -- bit numbers (bits 3-5 of opcode) */
122 UO_BITN, /* 0..7 */
123 /* RST address (bits 3-5 of opcode <-- (address shr 3)) */
124 UO_RSTDEST,
125 /* IM operands */
126 UO_IM0, /* not necessary for IM, denotes any 0 */
127 UO_IM1, /* not necessary for IM, denotes any 1 */
128 UO_IM2, /* not necessary for IM, denotes any 2 */
129 UO_NEXT, /* for op3: this is ZXNext instruction */
130 /*UO_IM01*/ /* undocumented IM 0/1 */
134 typedef struct {
135 unsigned mnemo; /* see UT_xxx */
136 uint32_t code; /* Z80 machine code */
137 uint32_t mask; /* mask (for disassembler) */
138 unsigned ops[3]; /* see UO_xxx */
139 } urasm_cmdinfo_t;
142 /* the longest matches must come first (for disassembler) */
143 /* solid-masked must come first (for disassembler) */
144 /* assembler searches the table from the last command */
145 /* disassembler searches the table from the first command */
146 /* heh, i spent the whole night creating this shit! %-) */
147 #define URASM_COMMANDS_NEXT (29)
148 #define URASM_MAX_COMMAND (366+URASM_COMMANDS_NEXT)
149 extern const urasm_cmdinfo_t URASM_COMMANDS[URASM_MAX_COMMAND];
152 /******************************************************************************/
153 /* callbacks */
154 /******************************************************************************/
156 /* fixup types */
157 typedef enum {
158 UR_FIXUP_NONE,
159 UR_FIXUP_WORD,
160 UR_FIXUP_LOBYTE,
161 UR_FIXUP_HIBYTE
162 } urasm_fixup_type_t;
165 /* return label name for the given address or NULL for "no such label" */
166 typedef const char *(*urasm_label_by_addr_fn) (uint16_t addr);
168 /* addr is current PC */
169 /* return 0 for undefined labels */
170 /* set `*found` to 1 or library will barf */
171 /* set `*fixuptype` to UR_FIXUP_XXX (default: UR_FIXUP_NONE) */
172 /* if label value is not known yet, set `*defined` to 0 */
173 /* (this means that the label was used, but not yet defined) */
174 typedef int32_t (*urasm_label_by_name_fn) (const char *name, uint16_t addr,
175 int *defined, int *found, int *fixuptype);
177 /* get byte at the given memory address */
178 typedef uint8_t (*urasm_getbyte_fn) (uint16_t addr);
179 /* set byte at the given memory address */
180 typedef void (*urasm_putbyte_fn) (uint16_t addr, uint8_t b);
183 /* allow ZXNext Z80N opcodes in assembler/disassembler? */
184 /* default is 0 (not allowed) */
185 extern int urasm_allow_zxnext;
187 /* set to non-zero to use decimal numeric literals in disassembler */
188 /* default is 0 (i.e. use hexadecimal) */
189 extern int urasm_disasm_decimal;
191 /* what to put after mnemonics (must not be empty/NULL, must not be bigger than 3 chars */
192 /* default is "\t" */
193 extern const char *urasm_disasm_mnemo_delimiter;
195 /* what to put between operands (must not be empty/NULL, must not be bigger than 3 chars */
196 /* default is "," */
197 extern const char *urasm_disasm_operand_delimiter;
200 /* use old priority table? default is 0 */
201 extern int urasm_use_old_priorities;
203 /* allow "&abc" hex numbers? */
204 extern int urasm_allow_hex_castrates;
207 /* callback for disasm; default is `NULL` */
208 extern urasm_label_by_addr_fn urasm_label_by_addr;
209 /* callback for disasm; default is `NULL` */
210 extern urasm_getbyte_fn urasm_getbyte;
213 /* callback for asm; default is `NULL` */
214 extern urasm_label_by_name_fn urasm_label_by_name;
215 /* callback for asm; default is `NULL` */
216 extern urasm_putbyte_fn urasm_putbyte;
219 /******************************************************************************/
220 /* disassembler */
221 /******************************************************************************/
223 /* returns length of the corresponding instruction */
224 /* it is always >0 (even for invalid idx) */
225 /* idx is index retunred by `urasm_disasm_opfind()` */
226 /* doesn't read memory */
227 int urasm_disasm_oplen (int idx);
229 /* find the corresponding record in URASM_COMMANDS */
230 /* returns -1 if memory read callback is not set, or command not found */
231 /* returns -2 for invalid ED prefix */
232 int urasm_disasm_opfind (uint16_t addr);
234 /* returns disassembled code in `dstr` & instruction length */
235 /* reserve 128 bytes for `dstr` (for default delimiters) */
236 /* opcode separated from operands with `urasm_disasm_mnemo_delimiter` */
237 /* operands are separated with `urasm_disasm_operand_delimiter` */
238 /* this one doesn't use memory read callback */
239 /* always fill all 8 bytes in `mem`, the code knows how much it needs */
240 /* returns -1 on error */
241 int urasm_disasm_opdisasm_ex (char *dstr, uint16_t addr, const uint8_t mem[8]);
243 /* returns disassembled code in `dstr` & instruction length */
244 /* reserve 128 bytes for `dstr` (for default delimiters) */
245 /* opcode separated from operands with `urasm_disasm_mnemo_delimiter` */
246 /* operands are separated with `urasm_disasm_operand_delimiter` */
247 /* returns -1 on error */
248 int urasm_disasm_opdisasm (char *dstr, uint16_t addr);
251 /******************************************************************************/
252 /* scanner */
253 /******************************************************************************/
255 enum {
256 UR_EXPRERR_NONE = 0,
257 UR_EXPRERR_EOS = 1,
258 UR_EXPRERR_DIV0 = 2,
259 UR_EXPRERR_PARENS = 3,
260 UR_EXPRERR_NUMBER = 4,
261 UR_EXPRERR_STRING = 5,
262 UR_EXPRERR_LABEL = 6,
263 UR_EXPRERR_TERM = 7,
264 UR_EXPRERR_FUNC = 8,
265 UR_EXPRERR_TYPE = 9,
266 UR_EXPRERR_MARG = 10,
267 UR_EXPRERR_FIXUP = 11,
268 UR_EXPRERR_TYPES = 12,
269 UR_EXPRERR_TOOLONG = 13, /* operand text too long */
273 typedef struct {
274 int32_t val; /* for now */
275 char *str; /* NULL: non-string value; val is set for strings too (see dox, hehe) */
276 int fixuptype; /* UR_FIXUP_XXX; can be changed only by low() and high() */
277 /* intertal fields */
278 const char *pos; /* for internal use */
279 } urasm_exprval_t;
282 typedef struct {
283 char s[258]; /* operand source text */
284 int special; /* bool: register or another reserved word */
285 int mem; /* bool: (...) */
286 int32_t v; /* expression value or index */
287 int defined; /* bool: expression defined? */
288 uint8_t ixy; /* $DD,$FD or 0 */
289 int parsed; /* was this operand sucessfully parsed? */
290 int fixuptype; /* UR_FIXUP_XXX */
291 } urasm_operand_t;
294 /* returns 0 if label name conflicts with reserved word, or 1 for valid label name */
295 /* (or if the label is just a bad one) */
296 int urasm_is_valid_name (const char *lbl);
298 /* initialize expression evaluator */
299 void urasm_exprval_init (urasm_exprval_t *res);
300 /* clear initialised expression evaluator (frees `str` if necessary) */
301 void urasm_exprval_clear (urasm_exprval_t *res);
302 /* frees `str` if necessary */
303 void urasm_exprval_setint (urasm_exprval_t *res, int32_t v);
304 /* reallocs `str`; sets `val` for double quotes */
305 void urasm_exprval_tostr (urasm_exprval_t *res, const char *str);
306 /* reallocs `str`; sets `val` for single quotes */
307 void urasm_exprval_tostr_rev (urasm_exprval_t *res, const char *str);
309 /* will be called when parser encounters term starting with '=' or '*' (can be used for macros) */
310 /* first term char will *not* be skipped */
311 /* must return pointer to the first char after expression end */
312 /* res: initialised; set this to expression result on exit */
313 /* expr: rest of the expression; return advanced expr */
314 /* addr: current PC */
315 /* donteval: !0 if you don't need to evaluate anything; used in bool short-circuiting */
316 /* *defined: set this to 0 if value is undefined yet (this is not necessarily an error) */
317 /* *error: set this to `UR_EXPRERR_XXX` to indicate some error */
318 typedef const char *(*urasm_getval_fn) (urasm_exprval_t *res, const char *expr,
319 uint16_t addr, int donteval,
320 int *defined, int *error);
322 extern urasm_getval_fn urasm_getval;
324 /* returns !0 to signal error; oprlen is opr size (w/o ending 0), it's 255 for now */
325 /* this is called to expand macro operand (starting with '=') */
326 /* useful in macros to replace arguments with their values without evaluating */
327 /* somewhat quirky: will only be called if first operand */
328 /* char is '=', not for any special-prefixed name */
329 /* to expand, parse `opr` from the start, remove parsed token, and insert expansion */
330 /* take care for not using more than `oprlen` bytes (ending 0 is not counted, */
331 /* so effective buffer size is `oprlen+1`) */
332 typedef int (*urasm_expand_fn) (char *opr, int oprlen);
334 extern urasm_expand_fn urasm_expand;
336 /* parse and calculate expression */
337 /* returns position after the expression (spaces skipped) or error position */
338 /* res: numeric result will be put here */
339 /* expr: expression; return advanced expr */
340 /* addr: current PC */
341 /* *defined: will be set to 0 if value is undefined yet (this is not necessarily an error) */
342 /* *fixuptype: will be set to `UR_FIXUP_XXX` */
343 /* *error: will be set this to `UR_EXPRERR_XXX` to indicate some error */
344 const char *urasm_expr (int32_t *res, const char *expr, uint16_t addr,
345 int *defined, int *fixuptype, int *error);
347 /* `res` must be initialised! */
348 /* returns position after the expression (spaces skipped) or error position */
349 /* *res: will be filled with expression result; must be initialised before calling! */
350 /* expr: expression; return advanced expr */
351 /* addr: current PC */
352 /* *donteval: set to !0 to simply skip the expression; might be set on exit to indicate short-circuiting */
353 /* *defined: will be set to 0 if value is undefined yet (this is not necessarily an error) */
354 /* *fixuptype: will be set to `UR_FIXUP_XXX` */
355 /* *error: will be set this to `UR_EXPRERR_XXX` to indicate some error */
356 const char *urasm_expr_ex (urasm_exprval_t *res, const char *expr, uint16_t addr,
357 int *donteval, int *defined, int *error);
359 /* note that starting '(' is skipped, and ending ')' must be skipped by fn */
360 /* returns position after the expression (spaces skipped) or error position */
361 /* *res: fill with expression result; it is already initialised */
362 /* expr: expression; return advanced expr */
363 /* addr: current PC */
364 /* donteval: !0 if you don't need to evaluate anything; used in bool short-circuiting */
365 /* *defined: will be set to 0 if value is undefined yet (this is not necessarily an error); you may change it */
366 /* *error: set this to `UR_EXPRERR_XXX` to indicate some error */
367 typedef const char *(*urasm_func_fn) (urasm_exprval_t *res, const char *expr,
368 uint16_t addr, int donteval,
369 int *defined, int *error);
371 /* fn==NULL: remove */
372 /* duplicate will be silently replaced */
373 /* use lower-case names */
374 void urasm_expr_register_func (const char *name, urasm_func_fn fn);
376 /* returns pointer to registered function, or NULL */
377 urasm_func_fn urasm_expr_find_func (const char *name);
379 /* result==NULL: no more operands */
380 /* skip operand; operands dilimited with ",", ":", ";" */
381 /* returns expr advanced to delimiter, or NULL of there are no more operands */
382 /* returned string may start with ":" (used for colon-delimited operators) */
383 /* note that NULL is returned only if there weren't any non-blank chars */
384 /* i.e. for last operand result will ne non-NULL (and may point to zero byte) */
385 /* correctly skips string and parens */
386 /* seenarg: if not NULL, set to !0 if seen any non-space chars */
387 const char *urasm_skip_operand (const char *expr, int *seenarg);
389 /* result==NULL: no more operands (see above for skip, tho) */
390 /* parse operand; op will be reset */
391 /* returns expr advanced to delimiter, or NULL of there are no more operands */
392 /* op: will be reset and filled with parsed operand data */
393 /* expr: expression; returns advanced expr */
394 /* addr: current PC */
395 /* *error: will be set to `UR_EXPRERR_XXX` to indicate some error */
396 /* `op->parsed` will be set even for empty operand (i.e. immediately terminated with ",") */
397 /* `op->parsed` will be reset on error */
398 const char *urasm_next_operand (urasm_operand_t *op, const char *expr,
399 uint16_t addr, int *error);
401 /* tests operand validity, returns 0 if passed `op` is not valid */
402 /* for regsters & conditions: op->v will be set to reg number */
403 /* doesn't check `op->parsed` */
404 /* op: parsed operand (result of successfull `urasm_next_operand()`) */
405 /* addr: current PC */
406 /* optype: required operand type (see `UO_XXX`) */
407 int urasm_is_valid_operand (urasm_operand_t *op, uint16_t addr, unsigned optype);
410 /******************************************************************************/
411 /* assembler */
412 /******************************************************************************/
414 enum {
415 URA_GENERIC = -1, /* call error (generic) */
416 URA_BAD_MNEMO = -2, /* bad mnemonics */
417 URA_BAD_OPERAND = -3, /* bad operand */
418 URA_EXTRA_TEXT = -4, /* extra text after instruction */
419 URA_BAD_INSTRUCTION = -5, /* bad instruction */
420 URA_EXPR_ERR = -666, /* expression error; to get a real code (`UR_EXPRERR_XXX`), subtract `URA_EXPR_ERR` */
421 URA_NOERROR = 0
424 /* called when `op->fixuptype` set to something else than `UR_FIXUP_NONE` */
425 /* also called on some special cases even if `op->fixuptype` is equal to `UR_FIXUP_NONE` */
426 /* op: operand */
427 /* opdestaddr: destination address (i.e. address to put into fixup table) */
428 /* opaddr: operand address */
429 /* fixuptype: type of fixup; use this instead of `op->fixuptype`! */
430 /* size: fixup size in bytes; 1 or 2 */
431 typedef void (*urasm_fixup_operand_fn) (const urasm_operand_t *op,
432 uint16_t opdestaddr, uint16_t opaddr,
433 int fixuptype, int size); /* UR_FIXUP_XXX */
435 extern urasm_fixup_operand_fn urasm_fixup_operand;
438 /* returns size of the assembled code or negative error index (see `URA_XXX`) */
439 /* note that zero result is not an error, and is perfectly valid */
440 /* understands comments */
441 /* errpos can be set when returned length >=0 -- it will point to ':' (this is not an error) */
442 /* expr: expression string; must not be NULL */
443 /* addr: current PC */
444 /* errpos: will be set to error position, or to ':' */
445 int urasm_opasm (const char *expr, uint16_t destaddr, uint16_t addr, const char **errpos);
447 /* returns simple Engrish string for the given error code (`URA_XXX`) */
448 const char *urasm_errormsg (int errcode);
451 #ifdef __cplusplus
453 #endif
454 #endif