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
22 /******************************************************************************/
23 /* all known tokens (opcode mnemonics) */
24 /******************************************************************************/
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
,
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
,
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 */
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) */
87 /* special 8 bit registers */
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' */
113 UO_MIX
, /* (IX+disp) */
114 UO_MIY
, /* (IY+disp) */
117 /* JR condition (bits 3-4 of opcode) */
119 /* conditions (bits 3-5 of opcode) */
121 /* CB opcodes -- bit numbers (bits 3-5 of opcode) */
123 /* RST address (bits 3-5 of opcode <-- (address shr 3)) */
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 */
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 */
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 /******************************************************************************/
154 /******************************************************************************/
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 */
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 /******************************************************************************/
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 /******************************************************************************/
253 /******************************************************************************/
259 UR_EXPRERR_PARENS
= 3,
260 UR_EXPRERR_NUMBER
= 4,
261 UR_EXPRERR_STRING
= 5,
262 UR_EXPRERR_LABEL
= 6,
266 UR_EXPRERR_MARG
= 10,
267 UR_EXPRERR_FIXUP
= 11,
268 UR_EXPRERR_TYPES
= 12,
269 UR_EXPRERR_TOOLONG
= 13, /* operand text too long */
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 */
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 */
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 /******************************************************************************/
412 /******************************************************************************/
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` */
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` */
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
);