Browse Source

Starting work on new ASM instructions system.

master
Ben Kurtovic 9 years ago
parent
commit
ade92aea51
13 changed files with 1384 additions and 1037 deletions
  1. +3
    -0
      makefile
  2. +89
    -0
      scripts/update_asm_instructions.py
  3. +2
    -5
      src/assembler/errors.c
  4. +2
    -5
      src/assembler/errors.h
  5. +19
    -12
      src/assembler/inst_args.h
  6. +0
    -98
      src/assembler/inst_support.c
  7. +0
    -155
      src/assembler/inst_support.h
  8. +158
    -737
      src/assembler/instructions.c
  9. +733
    -0
      src/assembler/instructions.inc.c
  10. +323
    -0
      src/assembler/instructions.yml
  11. +53
    -23
      src/assembler/parse_util.c
  12. +1
    -1
      src/assembler/parse_util.h
  13. +1
    -1
      src/assembler/tokenizer.c

+ 3
- 0
makefile View File

@@ -47,6 +47,9 @@ $(BUILD)/$(MODE)/%.o: %.c

-include $(DEPS)

$(SOURCES)/assembler/instructions.inc.c: $(SOURCES)/assembler/instructions.yml
python scripts/update_asm_instructions.py

test: test-all test-z80 test-asm test-dasm

test-all:


+ 89
- 0
scripts/update_asm_instructions.py View File

@@ -0,0 +1,89 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
# Released under the terms of the MIT License. See LICENSE for details.

"""
This script generates 'src/assembler/instructions.inc.c' from
'src/assembler/instructions.yml'. It should be run automatically by make
when the latter is modified, but can also be run manually.
"""

from __future__ import print_function

import re
import time

SOURCE = "src/assembler/instructions.yml"
DEST = "src/assembler/instructions.inc.c"

ENCODING = "utf8"
TAB = " " * 4

try:
import yaml
except ImportError:
print("Error: PyYAML is required (https://pypi.python.org/pypi/PyYAML)\n"
"If you don't want to rebuild {0}, do:\n`make -t {0}`".format(DEST))
exit(1)

re_date = re.compile(r"^(\s*@AUTOGEN_DATE\s*)(.*?)$", re.M)
re_inst = re.compile(
r"(/\* @AUTOGEN_INST_BLOCK_START \*/\n*)(.*?)"
r"(\n*/\* @AUTOGEN_INST_BLOCK_END \*/)", re.S)
re_lookup = re.compile(
r"(/\* @AUTOGEN_LOOKUP_BLOCK_START \*/\n*)(.*?)"
r"(\n*/\* @AUTOGEN_LOOKUP_BLOCK_END \*/)", re.S)

def build_inst(name, data):
"""
Convert data for an individual instruction into a C parse function.
"""
# TODO
return "INST_FUNC({0})\n{{\n}}".format(name)

def build_inst_block(data):
"""
Return the instruction parser block, given instruction data.
"""
return "\n\n".join(build_inst(k, v) for k, v in sorted(data.items()))

def build_lookup_block(data):
"""
Return the instruction lookup block, given instruction data.
"""
macro = TAB + "HANDLE({0})"
return "\n".join(macro.format(inst) for inst in sorted(data.keys()))

def process(template, data):
"""
Return C code generated from a source template and instruction data.
"""
inst_block = build_inst_block(data)
lookup_block = build_lookup_block(data)
date = time.asctime(time.gmtime())

result = re_date.sub(r"\1{0} UTC".format(date), template)
result = re_inst.sub(r"\1{0}\3".format(inst_block), result)
result = re_lookup.sub(r"\1{0}\3".format(lookup_block), result)
return result

def main():
"""
Main script entry point.
"""
with open(SOURCE, "r") as fp:
text = fp.read().decode(ENCODING)
with open(DEST, "r") as fp:
template = fp.read().decode(ENCODING)

data = yaml.load(text)
result = process(template, data)

# with open(DEST, "w") as fp:
# fp.write(result.encode(ENCODING))
print(result) # TODO: remove me!

if __name__ == "__main__":
main()

+ 2
- 5
src/assembler/errors.c View File

@@ -53,11 +53,8 @@ static const char *error_descs[] = {
[ED_PS_TOO_FEW_ARGS] = "too few arguments for opcode",
[ED_PS_TOO_MANY_ARGS] = "too many arguments for opcode",
[ED_PS_ARG_SYNTAX] = "invalid syntax in argument(s)",
[ED_PS_ARG0_TYPE] = "invalid type for first argument",
[ED_PS_ARG0_BAD_REG] = "unsupported register as first argument",
[ED_PS_ARG1_TYPE] = "invalid type for second argument",
[ED_PS_ARG1_BAD_REG] = "unsupported register as second argument",
[ED_PS_ARG1_RANGE] = "second argument out of range"
[ED_PS_ARG_TYPE] = "ED_PS_ARG_TYPE", // TODO
[ED_PS_ARG_VALUE] = "ED_PS_ARG_VALUE" // TODO
};

/* Internal structs */


+ 2
- 5
src/assembler/errors.h View File

@@ -52,11 +52,8 @@ typedef enum {
ED_PS_TOO_FEW_ARGS,
ED_PS_TOO_MANY_ARGS,
ED_PS_ARG_SYNTAX,
ED_PS_ARG0_TYPE,
ED_PS_ARG0_BAD_REG,
ED_PS_ARG1_TYPE,
ED_PS_ARG1_BAD_REG,
ED_PS_ARG1_RANGE
ED_PS_ARG_TYPE,
ED_PS_ARG_VALUE
} ASMErrorDesc;

/* Structs */


+ 19
- 12
src/assembler/inst_args.h View File

@@ -8,12 +8,14 @@
#define MAX_SYMBOL_SIZE 256

typedef enum {
AT_REGISTER,
AT_IMMEDIATE,
AT_INDIRECT,
AT_INDEXED,
AT_LABEL,
AT_CONDITION
AT_NONE = 0x00,
AT_OPTIONAL = 0x01,
AT_REGISTER = 0x02,
AT_IMMEDIATE = 0x04,
AT_INDIRECT = 0x08,
AT_INDEXED = 0x10,
AT_CONDITION = 0x20,
AT_PORT = 0x40
} ASMArgType;

typedef enum {
@@ -35,20 +37,17 @@ typedef enum {

typedef struct {
ASMArgImmType mask;
bool is_label;
uint16_t uval;
int16_t sval;
char label[MAX_SYMBOL_SIZE];
} ASMArgImmediate;

typedef struct {
char text[MAX_SYMBOL_SIZE];
} ASMArgLabel;

typedef struct {
ASMArgType type;
union {
ASMArgRegister reg;
ASMArgImmediate imm;
ASMArgLabel label;
} addr;
} ASMArgIndirect;

@@ -66,9 +65,17 @@ typedef struct {
union {
ASMArgRegister reg;
ASMArgImmediate imm;
} port;
} ASMArgPort;

typedef struct {
ASMArgType type;
union {
ASMArgRegister reg;
ASMArgImmediate imm;
ASMArgIndirect indirect;
ASMArgIndexed index;
ASMArgLabel label;
ASMArgCondition cond;
ASMArgPort port;
} data;
} ASMInstArg;

+ 0
- 98
src/assembler/inst_support.c View File

@@ -1,98 +0,0 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */

#include "inst_support.h"

/* Macro used by parse_arg() */

#define TRY_PARSER(func, argtype, field) \
if (argparse_##func(&arg->data.field, info)) { \
arg->type = argtype; \
return ED_NONE; \
}

/*
Fill an instruction's byte array with the given data.

This internal function is only called for instructions longer than four
bytes (of which there is only one: the fake emulator debugging/testing
opcode with mnemonic "emu"), so it does not get used in normal situations.

Return the value of the last byte inserted, for compatibility with the
INST_SETn_ family of macros.
*/
uint8_t fill_bytes_variadic(uint8_t *bytes, size_t len, ...)
{
va_list vargs;
va_start(vargs, len);
for (size_t i = 0; i < len; i++)
bytes[i] = va_arg(vargs, unsigned);
va_end(vargs);
return bytes[len - 1];
}

/*
Parse a single instruction argument into an ASMInstArg object.

Return ED_NONE (0) on success or an error code on failure.
*/
static ASMErrorDesc parse_arg(
ASMInstArg *arg, const char *str, size_t size, ASMDefineTable *deftable)
{
ASMArgParseInfo info = {.arg = str, .size = size, .deftable = deftable};
TRY_PARSER(register, AT_REGISTER, reg)
TRY_PARSER(immediate, AT_IMMEDIATE, imm)
TRY_PARSER(indirect, AT_INDIRECT, indirect)
TRY_PARSER(indexed, AT_INDEXED, index)
TRY_PARSER(condition, AT_CONDITION, cond)
TRY_PARSER(label, AT_LABEL, label)
return ED_PS_ARG_SYNTAX;
}

/*
Parse an argument string into ASMInstArg objects.

Return ED_NONE (0) on success or an error code on failure.
*/
ASMErrorDesc parse_args(
ASMInstArg args[3], size_t *nargs, ASMArgParseInfo ap_info)
{
ASMErrorDesc err;
ASMDefineTable *dt = ap_info.deftable;
const char *str = ap_info.arg;
size_t size = ap_info.size, start = 0, i = 0;

while (i < size) {
char c = str[i];
if (c == ',') {
if (i == start)
return ED_PS_ARG_SYNTAX;
if ((err = parse_arg(&args[*nargs], str + start, i - start, dt)))
return err;
(*nargs)++;

i++;
if (i < size && str[i] == ' ')
i++;
start = i;
if (i == size)
return ED_PS_ARG_SYNTAX;
if (*nargs >= 3)
return ED_PS_TOO_MANY_ARGS;
} else {
if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
c == ' ' || c == '+' || c == '-' || c == '(' || c == ')' ||
c == '$' || c == '_' || c == '.')
i++;
else
return ED_PS_ARG_SYNTAX;
}
}

if (i > start) {
if ((err = parse_arg(&args[*nargs], str + start, i - start, dt)))
return err;
(*nargs)++;
}
return ED_NONE;
}

+ 0
- 155
src/assembler/inst_support.h View File

@@ -1,155 +0,0 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */

#pragma once

#include <stdarg.h>
#include <stdlib.h>

#include "errors.h"
#include "inst_args.h"
#include "parse_util.h"
#include "../util.h"

/* Helper macros for get_inst_parser() */

#define JOIN_(a, b, c, d) ((uint32_t) ((a << 24) + (b << 16) + (c << 8) + d))

#define DISPATCH_(s, z) ( \
(z) == 2 ? JOIN_(s[0], s[1], 0x00, 0x00) : \
(z) == 3 ? JOIN_(s[0], s[1], s[2], 0x00) : \
JOIN_(s[0], s[1], s[2], s[3])) \

#define MAKE_CMP_(s) DISPATCH_(s, sizeof(s) / sizeof(char) - 1)

#define HANDLE(m) if (key == MAKE_CMP_(#m)) return parse_inst_##m;

/* Internal helper macros */

#define INST_ALLOC_(len) \
*length = len; \
*bytes = cr_malloc(sizeof(uint8_t) * (len));

#define INST_SET_(b, val) ((*bytes)[b] = val)
#define INST_SET1_(b1) INST_SET_(0, b1)
#define INST_SET2_(b1, b2) INST_SET1_(b1), INST_SET_(1, b2)
#define INST_SET3_(b1, b2, b3) INST_SET2_(b1, b2), INST_SET_(2, b3)
#define INST_SET4_(b1, b2, b3, b4) INST_SET3_(b1, b2, b3), INST_SET_(3, b4)

#define INST_DISPATCH_(a, b, c, d, target, ...) target

#define INST_FILL_BYTES_(len, ...) \
((len > 4) ? fill_bytes_variadic(*bytes, len, __VA_ARGS__) : \
INST_DISPATCH_(__VA_ARGS__, INST_SET4_, INST_SET3_, INST_SET2_, \
INST_SET1_, __VA_ARGS__)(__VA_ARGS__));

#define INST_IX_PREFIX_ 0xDD
#define INST_IY_PREFIX_ 0xFD

#define INST_PREFIX_(reg) \
(((reg) == REG_IX || (reg) == REG_IXH || (reg) == REG_IXL) ? \
INST_IX_PREFIX_ : INST_IY_PREFIX_)

#define INST_RETURN_WITH_SYMBOL_(len, label, ...) { \
*symbol = cr_strdup(label.text); \
INST_ALLOC_(len) \
INST_FILL_BYTES_(len - 2, __VA_ARGS__) \
return ED_NONE; \
}

/* Essential/basic helper macros */

#define INST_FUNC(mnemonic) \
static ASMErrorDesc parse_inst_##mnemonic( \
uint8_t **bytes, size_t *length, char **symbol, ASMArgParseInfo ap_info) \

#define INST_ERROR(desc) return ED_PS_##desc;

#define INST_TAKES_NO_ARGS \
if (ap_info.arg) \
INST_ERROR(TOO_MANY_ARGS)

#define INST_TAKES_ARGS(lo, hi) \
if (!ap_info.arg) \
INST_ERROR(TOO_FEW_ARGS) \
ASMInstArg args[3]; \
size_t nargs = 0; \
ASMErrorDesc err = parse_args(args, &nargs, ap_info); \
if (err) \
return err; \
if (nargs < lo) \
INST_ERROR(TOO_FEW_ARGS) \
if (nargs > hi) \
INST_ERROR(TOO_MANY_ARGS)

#define INST_NARGS nargs
#define INST_TYPE(n) args[n].type
#define INST_REG(n) args[n].data.reg
#define INST_IMM(n) args[n].data.imm
#define INST_INDIRECT(n) args[n].data.indirect
#define INST_INDEX(n) args[n].data.index
#define INST_LABEL(n) args[n].data.label
#define INST_COND(n) args[n].data.cond

#define INST_RETURN(len, ...) { \
(void) symbol; \
INST_ALLOC_(len) \
INST_FILL_BYTES_(len, __VA_ARGS__) \
return ED_NONE; \
}

/* Convenience macros */

#define INST_FORCE_TYPE(n, t) { \
if (INST_TYPE(n) != t) \
INST_ERROR(ARG##n##_TYPE) \
}

#define INST_CHECK_IMM(n, m) { \
if (!(INST_IMM(n).mask & (m))) \
INST_ERROR(ARG##n##_RANGE) \
}

#define INST_REG_ONLY(n, reg) { \
if (INST_TYPE(n) != AT_REGISTER) \
INST_ERROR(ARG##n##_TYPE) \
if (INST_REG(n) != reg) \
INST_ERROR(ARG##n##_BAD_REG) \
}

#define INST_INDIRECT_HL_ONLY(n) { \
if (INST_INDIRECT(n).type != AT_REGISTER) \
INST_ERROR(ARG##n##_TYPE) \
if (INST_INDIRECT(n).addr.reg != REG_HL) \
INST_ERROR(ARG##n##_BAD_REG) \
}

#define INST_INDEX_PREFIX(n) INST_PREFIX_(INST_INDEX(n).reg)

#define INST_INDEX_BYTES(n, b) \
INST_INDEX_PREFIX(n), b, INST_INDEX(n).offset

#define INST_INDIRECT_IMM(n) \
INST_INDIRECT(n).addr.imm.uval >> 8, \
INST_INDIRECT(n).addr.imm.uval & 0xFF

#define INST_RETURN_INDIRECT_LABEL(n, len, ...) \
INST_RETURN_WITH_SYMBOL_(len, INST_INDIRECT(n).addr.label, __VA_ARGS__)

#define INST_HANDLE_MAIN_8_BIT_REGS(base) \
case REG_A: INST_RETURN(1, base + 7) \
case REG_B: INST_RETURN(1, base) \
case REG_C: INST_RETURN(1, base + 1) \
case REG_D: INST_RETURN(1, base + 2) \
case REG_E: INST_RETURN(1, base + 3) \
case REG_H: INST_RETURN(1, base + 4) \
case REG_L: INST_RETURN(1, base + 5) \
case REG_IXH: INST_RETURN(2, INST_IX_PREFIX_, base + 4) \
case REG_IXL: INST_RETURN(2, INST_IX_PREFIX_, base + 5) \
case REG_IYH: INST_RETURN(2, INST_IY_PREFIX_, base + 4) \
case REG_IYL: INST_RETURN(2, INST_IY_PREFIX_, base + 5) \

/* Internal functions */

uint8_t fill_bytes_variadic(uint8_t*, size_t, ...);
ASMErrorDesc parse_args(ASMInstArg args[3], size_t*, ASMArgParseInfo);

+ 158
- 737
src/assembler/instructions.c View File

@@ -1,705 +1,198 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */

#include "instructions.h"
#include "inst_support.h"

/* Instruction parser functions */

INST_FUNC(adc)
{
INST_TAKES_ARGS(2, 2)
INST_FORCE_TYPE(0, AT_REGISTER)
switch (INST_REG(0)) {
case REG_A:
switch (INST_TYPE(1)) {
case AT_REGISTER:
switch (INST_REG(1)) {
INST_HANDLE_MAIN_8_BIT_REGS(0x88)
default: INST_ERROR(ARG1_BAD_REG)
}
case AT_IMMEDIATE:
INST_CHECK_IMM(1, IMM_U8)
INST_RETURN(2, 0xCE, INST_IMM(1).uval)
case AT_INDIRECT:
INST_INDIRECT_HL_ONLY(1)
INST_RETURN(1, 0x8E)
case AT_INDEXED:
INST_RETURN(3, INST_INDEX_BYTES(1, 0x8E))
default:
INST_ERROR(ARG1_TYPE)
}
case REG_HL:
INST_FORCE_TYPE(1, AT_REGISTER)
switch (INST_REG(1)) {
case REG_BC: INST_RETURN(2, 0xED, 0x4A)
case REG_DE: INST_RETURN(2, 0xED, 0x5A)
case REG_HL: INST_RETURN(2, 0xED, 0x6A)
case REG_SP: INST_RETURN(2, 0xED, 0x7A)
default: INST_ERROR(ARG1_BAD_REG)
}
default:
INST_ERROR(ARG0_TYPE)
}
}

INST_FUNC(add)
{
INST_TAKES_ARGS(2, 2)
INST_FORCE_TYPE(0, AT_REGISTER)
switch (INST_REG(0)) {
case REG_A:
switch (INST_TYPE(1)) {
case AT_REGISTER:
switch (INST_REG(1)) {
INST_HANDLE_MAIN_8_BIT_REGS(0x80)
default: INST_ERROR(ARG1_BAD_REG)
}
case AT_IMMEDIATE:
INST_CHECK_IMM(1, IMM_U8)
INST_RETURN(2, 0xC6, INST_IMM(1).uval)
case AT_INDIRECT:
INST_INDIRECT_HL_ONLY(1)
INST_RETURN(1, 0x86)
case AT_INDEXED:
INST_RETURN(3, INST_INDEX_BYTES(1, 0x86))
default:
INST_ERROR(ARG1_TYPE)
}
case REG_HL:
INST_FORCE_TYPE(1, AT_REGISTER)
switch (INST_REG(1)) {
case REG_BC: INST_RETURN(1, 0x09)
case REG_DE: INST_RETURN(1, 0x19)
case REG_HL: INST_RETURN(1, 0x29)
case REG_SP: INST_RETURN(1, 0x39)
default: INST_ERROR(ARG1_BAD_REG)
}
case REG_IX:
case REG_IY:
INST_FORCE_TYPE(1, AT_REGISTER)
switch (INST_REG(1)) {
case REG_BC: INST_RETURN(2, INST_INDEX_PREFIX(1), 0x09)
case REG_DE: INST_RETURN(2, INST_INDEX_PREFIX(1), 0x19)
case REG_IX:
case REG_IY:
if (INST_REG(0) != INST_REG(1))
INST_ERROR(ARG1_BAD_REG)
INST_RETURN(2, INST_INDEX_PREFIX(1), 0x29)
case REG_SP: INST_RETURN(2, INST_INDEX_PREFIX(1), 0x39)
default: INST_ERROR(ARG1_BAD_REG)
}
default:
INST_ERROR(ARG0_TYPE)
}
}

INST_FUNC(and)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(bit)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}
#include <stdarg.h>
#include <stdlib.h>

INST_FUNC(call)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}
#include "instructions.h"
#include "inst_args.h"
#include "../util.h"

INST_FUNC(ccf)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x3F)
}
/* Helper macros for get_inst_parser() and lookup_parser() */

INST_FUNC(cp)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}
#define JOIN(a, b, c, d) ((uint32_t) ((a << 24) + (b << 16) + (c << 8) + d))

INST_FUNC(cpd)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xA9)
}
#define DISPATCH_(s, z) ( \
(z) == 2 ? JOIN(s[0], s[1], 0x00, 0x00) : \
(z) == 3 ? JOIN(s[0], s[1], s[2], 0x00) : \
JOIN(s[0], s[1], s[2], s[3])) \

INST_FUNC(cpdr)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xB9)
}
#define MAKE_CMP_(s) DISPATCH_(s, sizeof(s) / sizeof(char) - 1)

INST_FUNC(cpi)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xA1)
}
#define HANDLE(m) if (key == MAKE_CMP_(#m)) return parse_inst_##m;

INST_FUNC(cpir)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xB1)
}
/* Helper macro for parse_arg() */

INST_FUNC(cpl)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x2F)
}
#define TRY_PARSER(func, argtype, field) \
if (argparse_##func(&arg->data.field, info)) { \
arg->type = argtype; \
return ED_NONE; \
}

INST_FUNC(daa)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x27)
}
/* Internal helper macros */

INST_FUNC(dec)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}
#define INST_ALLOC_(len) \
*length = len; \
*bytes = cr_malloc(sizeof(uint8_t) * (len));

INST_FUNC(di)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0xF3)
}
#define INST_SET_(b, val) ((*bytes)[b] = val)
#define INST_SET1_(b1) INST_SET_(0, b1)
#define INST_SET2_(b1, b2) INST_SET1_(b1), INST_SET_(1, b2)
#define INST_SET3_(b1, b2, b3) INST_SET2_(b1, b2), INST_SET_(2, b3)
#define INST_SET4_(b1, b2, b3, b4) INST_SET3_(b1, b2, b3), INST_SET_(3, b4)

INST_FUNC(djnz)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}
#define INST_DISPATCH_(a, b, c, d, target, ...) target

INST_FUNC(ei)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0xFB)
}
#define INST_FILL_BYTES_(len, ...) \
((len > 4) ? fill_bytes_variadic(*bytes, len, __VA_ARGS__) : \
INST_DISPATCH_(__VA_ARGS__, INST_SET4_, INST_SET3_, INST_SET2_, \
INST_SET1_, __VA_ARGS__)(__VA_ARGS__));

INST_FUNC(ex)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}
#define INST_IX_PREFIX 0xDD
#define INST_IY_PREFIX 0xFD

INST_FUNC(exx)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0xD9)
}
#define INST_PREFIX_(reg) \
(((reg) == REG_IX || (reg) == REG_IXH || (reg) == REG_IXL) ? \
INST_IX_PREFIX : INST_IY_PREFIX)

INST_FUNC(halt)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x76)
}

INST_FUNC(im)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(in)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(inc)
{
INST_TAKES_ARGS(1, 1)
switch (INST_TYPE(0)) {
case AT_REGISTER:
switch (INST_REG(0)) {
case REG_A: INST_RETURN(1, 0x3C)
case REG_B: INST_RETURN(1, 0x04)
case REG_C: INST_RETURN(1, 0x0C)
case REG_D: INST_RETURN(1, 0x14)
case REG_E: INST_RETURN(1, 0x1C)
case REG_H: INST_RETURN(1, 0x24)
case REG_L: INST_RETURN(1, 0x2C)
case REG_BC: INST_RETURN(1, 0x03)
case REG_DE: INST_RETURN(1, 0x13)
case REG_HL: INST_RETURN(1, 0x23)
case REG_SP: INST_RETURN(1, 0x33)
case REG_IX: INST_RETURN(2, 0xDD, 0x23)
case REG_IY: INST_RETURN(2, 0xFD, 0x23)
case REG_IXH: INST_RETURN(2, 0xDD, 0x2C)
case REG_IXL: INST_RETURN(2, 0xFD, 0x2C)
case REG_IYH: INST_RETURN(2, 0xDD, 0x2C)
case REG_IYL: INST_RETURN(2, 0xFD, 0x2C)
default: INST_ERROR(ARG0_BAD_REG)
}
case AT_INDIRECT:
INST_INDIRECT_HL_ONLY(0)
INST_RETURN(1, 0x34)
case AT_INDEXED:
INST_RETURN(3, INST_INDEX_BYTES(0, 0x34))
default:
INST_ERROR(ARG0_TYPE)
#define INST_RETURN_WITH_SYMBOL_(len, label, ...) { \ // TODO
*symbol = cr_strdup(label.text); \
INST_ALLOC_(len) \
INST_FILL_BYTES_(len - 2, __VA_ARGS__) \
return ED_NONE; \
}
}

INST_FUNC(ind)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xAA)
}

INST_FUNC(indr)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xBA)
}

INST_FUNC(ini)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xA2)
}

INST_FUNC(inir)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xB2)
}

INST_FUNC(jp)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(jr)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(ld)
{
uint8_t base;
INST_TAKES_ARGS(2, 2)
switch (INST_TYPE(0)) {
case AT_REGISTER:
switch (INST_REG(0)) {
case REG_A:
switch (INST_TYPE(1)) {
case AT_REGISTER:
switch (INST_REG(1)) {
INST_HANDLE_MAIN_8_BIT_REGS(0x78)
case REG_I: INST_RETURN(2, 0xED, 0x57)
case REG_R: INST_RETURN(2, 0xED, 0x5F)
default: INST_ERROR(ARG1_BAD_REG)
}
case AT_IMMEDIATE:
INST_CHECK_IMM(1, IMM_U8)
INST_RETURN(2, 0x3E, INST_IMM(1).uval)
case AT_INDIRECT:
switch (INST_INDIRECT(1).type) {
case AT_REGISTER:
switch (INST_INDIRECT(1).addr.reg) {
case REG_BC: INST_RETURN(1, 0x0A)
case REG_DE: INST_RETURN(1, 0x1A)
case REG_HL: INST_RETURN(1, 0x7E)
default: INST_ERROR(ARG0_BAD_REG)
}
case AT_IMMEDIATE:
INST_RETURN(3, 0x3A, INST_INDIRECT_IMM(1))
case AT_LABEL:
INST_RETURN_INDIRECT_LABEL(1, 3, 0x3A)
default:
INST_ERROR(ARG1_TYPE)
}
case AT_INDEXED:
INST_RETURN(3, INST_INDEX_BYTES(1, 0x7E))
default:
INST_ERROR(ARG1_TYPE)
}
case REG_B:
base = 0x00;
case REG_C:
base = 0x08;
case REG_D:
base = 0x10;
case REG_E:
base = 0x18;
switch (INST_TYPE(1)) {
case AT_REGISTER:
switch (INST_REG(1)) {
INST_HANDLE_MAIN_8_BIT_REGS(base + 0x40)
default: INST_ERROR(ARG1_BAD_REG)
}
case AT_IMMEDIATE:
INST_CHECK_IMM(1, IMM_U8)
INST_RETURN(2, base + 0x06, INST_IMM(1).uval)
case AT_INDIRECT:
INST_INDIRECT_HL_ONLY(1)
INST_RETURN(1, base + 0x46)
case AT_INDEXED:
INST_RETURN(3, INST_INDEX_BYTES(1, base + 0x46))
default:
INST_ERROR(ARG1_TYPE)
}
case REG_H: // TODO (11 cases)
case REG_L: // TODO (11 cases)
case REG_I:
INST_REG_ONLY(1, REG_A)
INST_RETURN(2, 0xED, 0x47)
case REG_R:
INST_REG_ONLY(1, REG_A)
INST_RETURN(2, 0xED, 0x4F)
case REG_BC: // TODO ( 2 cases)
case REG_DE: // TODO ( 2 cases)
case REG_HL: // TODO ( 3 cases)
case REG_IX: // TODO ( 2 cases)
case REG_IY: // TODO ( 2 cases)
case REG_SP: // TODO ( 5 cases)
case REG_IXH: // TODO ( 8 cases)
case REG_IXL: // TODO ( 8 cases)
case REG_IYH: // TODO ( 8 cases)
case REG_IYL: // TODO ( 8 cases)
default: INST_ERROR(ARG0_BAD_REG)
}
case AT_INDIRECT:
switch (INST_INDIRECT(0).type) {
case AT_REGISTER:
switch (INST_INDIRECT(0).addr.reg) {
case REG_BC: // TODO (1 case )
case REG_DE: // TODO (1 case )
case REG_HL: // TODO (8 cases)
default: INST_ERROR(ARG0_BAD_REG)
}
case AT_IMMEDIATE:
// TODO (8 cases)
case AT_LABEL:
// TODO (same 8 cases)
default:
INST_ERROR(ARG0_TYPE)
}
case AT_INDEXED:
// TODO (16 cases)
default:
INST_ERROR(ARG0_TYPE)
/* Helper macros for instruction parsers */

#define INST_FUNC(mnemonic) \
static ASMErrorDesc parse_inst_##mnemonic( \
uint8_t **bytes, size_t *length, char **symbol, ASMArgParseInfo ap_info) \

#define INST_ERROR(desc) return ED_PS_##desc;

#define INST_TAKES_NO_ARGS \
if (ap_info.arg) \
INST_ERROR(TOO_MANY_ARGS)

#define INST_TAKES_ARGS(a0, a1, a2) \
if (!ap_info.arg) \
INST_ERROR(TOO_FEW_ARGS) \
ASMInstArg args[3]; \
size_t nargs = 0; \
ASMArgType masks = {a0, a1, a2}; \
ASMErrorDesc err = parse_args(args, &nargs, ap_info, masks); \
if (err) \
return err; \

#define INST_TYPE(n) args[n].type
#define INST_REG(n) args[n].data.reg
#define INST_IMM(n) args[n].data.imm
#define INST_INDIRECT(n) args[n].data.indirect
#define INST_INDEX(n) args[n].data.index
#define INST_COND(n) args[n].data.cond
#define INST_PORT(n) args[n].data.port

#define INST_RETURN(len, ...) { \
(void) symbol; \
INST_ALLOC_(len) \
INST_FILL_BYTES_(len, __VA_ARGS__) \
return ED_NONE; \
}
}

INST_FUNC(ldd)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xA8)
}

INST_FUNC(lddr)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xB8)
}

INST_FUNC(ldi)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xA0)
}

INST_FUNC(ldir)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xB0)
}

INST_FUNC(neg)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(nop)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x00)
}

INST_FUNC(or)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(otdr)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xBB)
}

INST_FUNC(otir)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xB3)
}

INST_FUNC(out)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(outd)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xAB)
}

INST_FUNC(outi)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xA3)
}

INST_FUNC(pop)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(push)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(res)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(ret)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(reti)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0x4D)
}

INST_FUNC(retn)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0x45)
}

INST_FUNC(rl)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(rla)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x17)
}
#define INST_INDEX_PREFIX(n) INST_PREFIX_(INST_INDEX(n).reg)

INST_FUNC(rlc)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}
#define INST_INDIRECT_IMM(n) \ // TODO
INST_INDIRECT(n).addr.imm.uval >> 8, \
INST_INDIRECT(n).addr.imm.uval & 0xFF

INST_FUNC(rlca)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x07)
}
/* ----------------------------- END WORK BLOCK ---------------------------- */

INST_FUNC(rld)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0x6F)
}

INST_FUNC(rr)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(rra)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x1F)
}

INST_FUNC(rrc)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(rrca)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x0F)
}

INST_FUNC(rrd)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(rst)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(sbc)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(scf)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x37)
}

INST_FUNC(set)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}
/*
Fill an instruction's byte array with the given data.

INST_FUNC(sl1)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}
This internal function is only called for instructions longer than four
bytes (of which there is only one: the fake emulator debugging/testing
opcode with mnemonic "emu"), so it does not get used in normal situations.

INST_FUNC(sla)
Return the value of the last byte inserted, for compatibility with the
INST_SETn_ family of macros.
*/
static uint8_t fill_bytes_variadic(uint8_t *bytes, size_t len, ...)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
va_list vargs;
va_start(vargs, len);
for (size_t i = 0; i < len; i++)
bytes[i] = va_arg(vargs, unsigned);
va_end(vargs);
return bytes[len - 1];
}

INST_FUNC(sll)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}
/*
Parse a single instruction argument into an ASMInstArg object.

INST_FUNC(sls)
Return ED_NONE (0) on success or an error code on failure.
*/
static ASMErrorDesc parse_arg(
ASMInstArg *arg, const char *str, size_t size, ASMDefineTable *deftable)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
ASMArgParseInfo info = {.arg = str, .size = size, .deftable = deftable};
TRY_PARSER(register, AT_REGISTER, reg)
TRY_PARSER(condition, AT_CONDITION, cond)
TRY_PARSER(indirect, AT_INDIRECT, indirect)
TRY_PARSER(indexed, AT_INDEXED, index)
TRY_PARSER(immediate, AT_IMMEDIATE, imm)
return ED_PS_ARG_SYNTAX;
}

INST_FUNC(sra)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}
/*
Parse an argument string into ASMInstArg objects.

INST_FUNC(srl)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}
Return ED_NONE (0) on success or an error code on failure.
*/
static ASMErrorDesc parse_args(
ASMInstArg args[3], size_t *nargs, ASMArgParseInfo ap_info, ASMArgType masks[3]) // TODO
{
ASMErrorDesc err;
ASMDefineTable *dt = ap_info.deftable;
const char *str = ap_info.arg;
size_t size = ap_info.size, start = 0, i = 0;

while (i < size) {
char c = str[i];
if (c == ',') {
if (i == start)
return ED_PS_ARG_SYNTAX;
if ((err = parse_arg(&args[*nargs], str + start, i - start, dt)))
return err;
(*nargs)++;

i++;
if (i < size && str[i] == ' ')
i++;
start = i;
if (i == size)
return ED_PS_ARG_SYNTAX;
if (*nargs >= 3)
return ED_PS_TOO_MANY_ARGS;
} else {
if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
c == ' ' || c == '+' || c == '-' || c == '(' || c == ')' ||
c == '$' || c == '_' || c == '.')
i++;
else
return ED_PS_ARG_SYNTAX;
}
}

INST_FUNC(sub)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
if (i > start) {
if ((err = parse_arg(&args[*nargs], str + start, i - start, dt)))
return err;
(*nargs)++;
}
return ED_NONE;
}

INST_FUNC(xor)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}
#include "instructions.inc.c"

/*
Return the relevant ASMInstParser function for a given mnemonic.
@@ -710,78 +203,6 @@ ASMInstParser get_inst_parser(char mstr[MAX_MNEMONIC_SIZE])
{
// Exploit the fact that we can store the entire mnemonic string as a
// single 32-bit value to do fast lookups:
uint32_t key = (mstr[0] << 24) + (mstr[1] << 16) + (mstr[2] << 8) + mstr[3];

HANDLE(adc)
HANDLE(add)
HANDLE(and)
HANDLE(bit)
HANDLE(call)
HANDLE(ccf)
HANDLE(cp)
HANDLE(cpd)
HANDLE(cpdr)
HANDLE(cpi)
HANDLE(cpir)
HANDLE(cpl)
HANDLE(daa)
HANDLE(dec)
HANDLE(di)
HANDLE(djnz)
HANDLE(ei)
HANDLE(ex)
HANDLE(exx)
HANDLE(halt)
HANDLE(im)
HANDLE(in)
HANDLE(inc)
HANDLE(ind)
HANDLE(indr)
HANDLE(ini)
HANDLE(inir)
HANDLE(jp)
HANDLE(jr)
HANDLE(ld)
HANDLE(ldd)
HANDLE(lddr)
HANDLE(ldi)
HANDLE(ldir)
HANDLE(neg)
HANDLE(nop)
HANDLE(or)
HANDLE(otdr)
HANDLE(otir)
HANDLE(out)
HANDLE(outd)
HANDLE(outi)
HANDLE(pop)
HANDLE(push)
HANDLE(res)
HANDLE(ret)
HANDLE(reti)
HANDLE(retn)
HANDLE(rl)
HANDLE(rla)
HANDLE(rlc)
HANDLE(rlca)
HANDLE(rld)
HANDLE(rr)
HANDLE(rra)
HANDLE(rrc)
HANDLE(rrca)
HANDLE(rrd)
HANDLE(rst)
HANDLE(sbc)
HANDLE(scf)
HANDLE(set)
HANDLE(sl1)
HANDLE(sla)
HANDLE(sll)
HANDLE(sls)
HANDLE(sra)
HANDLE(srl)
HANDLE(sub)
HANDLE(xor)

return NULL;
uint32_t key = JOIN(mstr[0], mstr[1], mstr[2], mstr[3]);
return lookup_parser(key);
}

+ 733
- 0
src/assembler/instructions.inc.c View File

@@ -0,0 +1,733 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */

/*
This file is AUTO-GENERATED from 'instructions.yml'.

`make` should trigger a rebuild when it is modified; if not, use:
`python scripts/update_asm_instructions.py`.

@AUTOGEN_DATE Sun May 10 21:02:28 2015
*/

/* @AUTOGEN_INST_BLOCK_START */

INST_FUNC(adc)
{
INST_TAKES_ARGS(
AT_REGISTER,
AT_REGISTER|AT_IMMEDIATE|AT_INDEXED|AT_INDIRECT,
AT_NONE
)
if (INST_TYPE(0) == AT_REGISTER && INST_TYPE(1) == AT_REGISTER) {
if (INST_REG(0) == REG_A && INST_REG(1) == REG_A)
INST_RETURN(1, 0x8F)
if (INST_REG(0) == REG_A && INST_REG(1) == REG_B)
INST_RETURN(1, 0x88)
//
if (INST_REG(0) == REG_A && INST_REG(1) == REG_H)
INST_RETURN(1, 0x8C)
if (INST_REG(0) == REG_A && INST_REG(1) == REG_IXH)
INST_RETURN(2, INST_IX_PREFIX, 0x8C)
//
INST_ERROR(ARG_VALUE)
}
if (INST_TYPE(0) == AT_REGISTER && INST_TYPE(1) == AT_IMMEDIATE) {
if (INST_REG(0) == REG_A && INST_IMM(1).mask & IMM_U8)
INST_RETURN(2, 0xCE, INST_IMM(1).uval)
INST_ERROR(ARG_VALUE)
}
if (INST_TYPE(0) == AT_REGISTER && INST_TYPE(1) == AT_INDEXED) {
if (INST_REG(0) == REG_A)
INST_RETURN(3, INST_INDEX_PREFIX(1), 0x8E, INST_INDEX(1).offset)
INST_ERROR(ARG_VALUE)
}
if (INST_TYPE(0) == AT_REGISTER && INST_TYPE(1) == AT_INDIRECT &&
INST_INDIRECT(1).type == AT_REGISTER &&
INST_INDIRECT(1).addr.reg == REG_HL) {
if (INST_REG(0) == REG_A)
INST_RETURN(1, 0x8E)
INST_ERROR(ARG_VALUE)
}
INST_ERROR(ARG_TYPE)
}

INST_FUNC(add)
{
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)

// INST_TAKES_ARGS(2, 2)
// INST_FORCE_TYPE(0, AT_REGISTER)
// switch (INST_REG(0)) {
// case REG_A:
// switch (INST_TYPE(1)) {
// INST_CASE_REGS(1, INST_CASE_ALL_8_BIT_REGS(0x80))
// INST_CASE_IMM_U8(1, 2, 0xC6)
// INST_CASE_INDIRECT_HL_IX_IY(1, 1, 0x86)
// default: INST_ERROR(ARG1_TYPE)
// }
// case REG_HL:
// INST_FORCE_TYPE(1, AT_REGISTER)
// switch (INST_REG(1)) {
// case REG_BC: INST_RETURN(1, 0x09)
// case REG_DE: INST_RETURN(1, 0x19)
// case REG_HL: INST_RETURN(1, 0x29)
// case REG_SP: INST_RETURN(1, 0x39)
// default: INST_ERROR(ARG1_BAD_REG)
// }
// case REG_IX:
// case REG_IY:
// INST_FORCE_TYPE(1, AT_REGISTER)
// switch (INST_REG(1)) {
// case REG_BC: INST_RETURN(2, INST_INDEX_PREFIX(1), 0x09) // TODO: wrong prefix
// case REG_DE: INST_RETURN(2, INST_INDEX_PREFIX(1), 0x19)
// case REG_IX:
// case REG_IY:
// if (INST_REG(0) != INST_REG(1))
// INST_ERROR(ARG1_BAD_REG)
// INST_RETURN(2, INST_INDEX_PREFIX(1), 0x29)
// case REG_SP: INST_RETURN(2, INST_INDEX_PREFIX(1), 0x39)
// default: INST_ERROR(ARG1_BAD_REG)
// }
// default:
// INST_ERROR(ARG0_TYPE)
// }
}

INST_FUNC(and)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(bit)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(call)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(ccf)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x3F)
}

INST_FUNC(cp)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(cpd)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xA9)
}

INST_FUNC(cpdr)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xB9)
}

INST_FUNC(cpi)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xA1)
}

INST_FUNC(cpir)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xB1)
}

INST_FUNC(cpl)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x2F)
}

INST_FUNC(daa)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x27)
}

INST_FUNC(dec)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(di)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0xF3)
}

INST_FUNC(djnz)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(ei)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0xFB)
}

INST_FUNC(ex)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(exx)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0xD9)
}

INST_FUNC(halt)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x76)
}

INST_FUNC(im)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(in)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(inc)
{
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)

// INST_TAKES_ARGS(1, 1)
// switch (INST_TYPE(0)) {
// case AT_REGISTER:
// switch (INST_REG(0)) {
// case REG_A: INST_RETURN(1, 0x3C)
// case REG_B: INST_RETURN(1, 0x04)
// case REG_C: INST_RETURN(1, 0x0C)
// case REG_D: INST_RETURN(1, 0x14)
// case REG_E: INST_RETURN(1, 0x1C)
// case REG_H: INST_RETURN(1, 0x24)
// case REG_L: INST_RETURN(1, 0x2C)
// case REG_BC: INST_RETURN(1, 0x03)
// case REG_DE: INST_RETURN(1, 0x13)
// case REG_HL: INST_RETURN(1, 0x23)
// case REG_SP: INST_RETURN(1, 0x33)
// case REG_IX: INST_RETURN(2, 0xDD, 0x23)
// case REG_IY: INST_RETURN(2, 0xFD, 0x23)
// case REG_IXH: INST_RETURN(2, 0xDD, 0x2C)
// case REG_IXL: INST_RETURN(2, 0xFD, 0x2C)
// case REG_IYH: INST_RETURN(2, 0xDD, 0x2C)
// case REG_IYL: INST_RETURN(2, 0xFD, 0x2C)
// default: INST_ERROR(ARG0_BAD_REG)
// }
// INST_CASE_INDIRECT_HL_IX_IY(0, 1, 0x34)
// default:
// INST_ERROR(ARG0_TYPE)
// }
}

INST_FUNC(ind)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xAA)
}

INST_FUNC(indr)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xBA)
}

INST_FUNC(ini)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xA2)
}

INST_FUNC(inir)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xB2)
}

INST_FUNC(jp)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(jr)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(ld)
{
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)

// INST_TAKES_ARGS(2, 2)
// switch (INST_TYPE(0)) {
// case AT_REGISTER:
// switch (INST_REG(0)) {
// case REG_A:
// switch (INST_TYPE(1)) {
// case AT_REGISTER:
// switch (INST_REG(1)) {
// INST_CASE_ALL_8_BIT_REGS(0x78)
// case REG_I: INST_RETURN(2, 0xED, 0x57)
// case REG_R: INST_RETURN(2, 0xED, 0x5F)
// default: INST_ERROR(ARG1_BAD_REG)
// }
// INST_CASE_IMM_U8(1, 2, 0x3E)
// case AT_INDIRECT:
// switch (INST_INDIRECT(1).type) {
// case AT_REGISTER:
// switch (INST_INDIRECT(1).addr.reg) {
// case REG_BC: INST_RETURN(1, 0x0A)
// case REG_DE: INST_RETURN(1, 0x1A)
// case REG_HL: INST_RETURN(1, 0x7E)
// default: INST_ERROR(ARG0_BAD_REG)
// }
// case AT_IMMEDIATE:
// INST_RETURN(3, 0x3A, INST_INDIRECT_IMM(1))
// case AT_LABEL:
// INST_RETURN_INDIRECT_LABEL(1, 3, 0x3A)
// default:
// INST_ERROR(ARG1_TYPE)
// }
// case AT_INDEXED:
// INST_RETURN(3, INST_INDEX_BYTES(1, 0x7E))
// default:
// INST_ERROR(ARG1_TYPE)
// }
// case REG_B:
// switch (INST_TYPE(1)) {
// INST_CASE_REGS(1, INST_CASE_ALL_8_BIT_REGS(0x40))
// INST_CASE_IMM_U8(1, 2, 0x06)
// INST_CASE_INDIRECT_HL_IX_IY(1, 1, 0x46)
// default: INST_ERROR(ARG1_TYPE)
// }
// case REG_C:
// switch (INST_TYPE(1)) {
// INST_CASE_REGS(1, INST_CASE_ALL_8_BIT_REGS(0x48))
// INST_CASE_IMM_U8(1, 2, 0x0E)
// INST_CASE_INDIRECT_HL_IX_IY(1, 1, 0x4E)
// default: INST_ERROR(ARG1_TYPE)
// }
// case REG_D:
// switch (INST_TYPE(1)) {
// INST_CASE_REGS(1, INST_CASE_ALL_8_BIT_REGS(0x50))
// INST_CASE_IMM_U8(1, 2, 0x16)
// INST_CASE_INDIRECT_HL_IX_IY(1, 1, 0x56)
// default: INST_ERROR(ARG1_TYPE)
// }
// case REG_E:
// switch (INST_TYPE(1)) {
// INST_CASE_REGS(1, INST_CASE_ALL_8_BIT_REGS(0x58))
// INST_CASE_IMM_U8(1, 2, 0x1E)
// INST_CASE_INDIRECT_HL_IX_IY(1, 1, 0x5E)
// default: INST_ERROR(ARG1_TYPE)
// }
// case REG_H:
// switch (INST_TYPE(1)) {
// INST_CASE_REGS(1, INST_CASE_MAIN_8_BIT_REGS(0x60))
// INST_CASE_IMM_U8(1, 2, 0x26)
// INST_CASE_INDIRECT_HL_IX_IY(1, 1, 0x66)
// default: INST_ERROR(ARG1_TYPE)
// }
// case REG_L:
// switch (INST_TYPE(1)) {
// INST_CASE_REGS(1, INST_CASE_MAIN_8_BIT_REGS(0x68))
// INST_CASE_IMM_U8(1, 2, 0x2E)
// INST_CASE_INDIRECT_HL_IX_IY(1, 1, 0x6E)
// default: INST_ERROR(ARG1_TYPE)
// }
// case REG_I:
// INST_REG_ONLY(1, REG_A)
// INST_RETURN(2, 0xED, 0x47)
// case REG_R:
// INST_REG_ONLY(1, REG_A)
// INST_RETURN(2, 0xED, 0x4F)
// case REG_BC: // TODO ( 2 cases)
// case REG_DE: // TODO ( 2 cases)
// case REG_HL: // TODO ( 3 cases)
// case REG_IX: // TODO ( 2 cases)
// case REG_IY: // TODO ( 2 cases)
// case REG_SP: // TODO ( 5 cases)
// case REG_IXH: // TODO ( 8 cases)
// case REG_IXL: // TODO ( 8 cases)
// case REG_IYH: // TODO ( 8 cases)
// case REG_IYL: // TODO ( 8 cases)
// default: INST_ERROR(ARG0_BAD_REG)
// }
// case AT_INDIRECT:
// switch (INST_INDIRECT(0).type) {
// case AT_REGISTER:
// switch (INST_INDIRECT(0).addr.reg) {
// case REG_BC: // TODO (1 case )
// case REG_DE: // TODO (1 case )
// case REG_HL: // TODO (8 cases)
// default: INST_ERROR(ARG0_BAD_REG)
// }
// case AT_IMMEDIATE:
// // TODO (8 cases)
// case AT_LABEL:
// // TODO (same 8 cases)
// default:
// INST_ERROR(ARG0_TYPE)
// }
// case AT_INDEXED:
// // TODO (16 cases)
// default:
// INST_ERROR(ARG0_TYPE)
// }
}

INST_FUNC(ldd)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xA8)
}

INST_FUNC(lddr)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xB8)
}

INST_FUNC(ldi)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xA0)
}

INST_FUNC(ldir)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xB0)
}

INST_FUNC(neg)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0x44)
}

INST_FUNC(nop)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x00)
}

INST_FUNC(or)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(otdr)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xBB)
}

INST_FUNC(otir)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xB3)
}

INST_FUNC(out)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(outd)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xAB)
}

INST_FUNC(outi)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0xA3)
}

INST_FUNC(pop)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(push)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(res)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(ret)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(reti)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0x4D)
}

INST_FUNC(retn)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0x45)
}

INST_FUNC(rl)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(rla)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x17)
}

INST_FUNC(rlc)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(rlca)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x07)
}

INST_FUNC(rld)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0x6F)
}

INST_FUNC(rr)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(rra)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x1F)
}

INST_FUNC(rrc)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(rrca)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x0F)
}

INST_FUNC(rrd)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(rst)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(sbc)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(scf)
{
INST_TAKES_NO_ARGS
INST_RETURN(1, 0x37)
}

INST_FUNC(set)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(sl1)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(sla)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(sll)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(sls)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(sra)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(srl)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(sub)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

INST_FUNC(xor)
{
// TODO
INST_TAKES_NO_ARGS
INST_ERROR(ARG_SYNTAX)
INST_RETURN(1, 0xFF)
}

/* @AUTOGEN_INST_BLOCK_END */

/*
Return the relevant ASMInstParser function for the given encoded mnemonic.
*/
static ASMInstParser lookup_parser(uint32_t key)
{
/* @AUTOGEN_LOOKUP_BLOCK_START */
HANDLE(adc)
HANDLE(add)
HANDLE(and)
/* @AUTOGEN_LOOKUP_BLOCK_END */
return NULL;
}

+ 323
- 0
src/assembler/instructions.yml View File

@@ -0,0 +1,323 @@
# Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
# Released under the terms of the MIT License. See LICENSE for details.

# *** ASM Instruction Description File ***

# This file is used to generate 'instructions.inc.c'.

# `make` should trigger a rebuild when this file is modified; if not, use:
# `python scripts/update_asm_instructions.py`.

---

adc:
args: yes
cases:
- type: [register, register]
cases:
- cond: [a, a]
return: [0x8F]
- cond: [a, b]
return: [0x88]
- cond: [a, c]
return: [0x89]
- cond: [a, d]
return: [0x8A]
- cond: [a, e]
return: [0x8B]
- cond: [a, h|ih]
return: [0x8C]
- cond: [a, l|il]
return: [0x8D]
- cond: [hl, bc]
return: [0xED, 0x4A]
- cond: [hl, de]
return: [0xED, 0x5A]
- cond: [hl, hl]
return: [0xED, 0x6A]
- cond: [hl, sp]
return: [0xED, 0x7A]
- type: [register, immediate]
cases:
- cond: [a, u8]
return: [0xCE, u8]
- type: [register, indexed]
cases:
- cond: [a, _]
return: [0x8E]

add:
args: no
return: error

and:
args: no
return: error

bit:
args: no
return: error

call:
args: no
return: error

ccf:
args: no
return: error

cp:
args: no
return: error

cpd:
args: no
return: error

cpdr:
args: no
return: error

cpi:
args: no
return: error

cpir:
args: no
return: error

cpl:
args: no
return: error

daa:
args: no
return: error

dec:
args: no
return: error

di:
args: no
return: error

djnz:
args: no
return: error

ei:
args: no
return: error

ex:
args: no
return: error

exx:
args: no
return: error

halt:
args: no
return: error

im:
args: no
return: error

in:
args: no
return: error

inc:
args: no
return: error

ind:
args: no
return: error

indr:
args: no
return: error

ini:
args: no
return: [0xED, 0xA2]

inir:
args: no
return: error

jp:
args: no
return: error

jr:
args: no
return: error

ld:
args: no
return: error

ldd:
args: no
return: error

lddr:
args: no
return: error

ldi:
args: no
return: error

ldir:
args: no
return: error

neg:
args: no
return: error

nop:
args: no
return: error

or:
args: no
return: error

otdr:
args: no
return: error

otir:
args: no
return: error

out:
args: no
return: error

outd:
args: no
return: error

outi:
args: no
return: error

pop:
args: no
return: error

push:
args: no
return: error

res:
args: no
return: error

ret:
args: no
return: error

reti:
args: no
return: error

retn:
args: no
return: error

rl:
args: no
return: error

rla:
args: no
return: error

rlc:
args: no
return: error

rlca:
args: no
return: error

rld:
args: no
return: error

rr:
args: no
return: error

rra:
args: no
return: error

rrc:
args: no
return: error

rrca:
args: no
return: error

rrd:
args: no
return: error

rst:
args: no
return: error

sbc:
args: no
return: error

scf:
args: no
return: error

set:
args: no
return: error

sl1:
args: no
return: error

sla:
args: no
return: error

sll:
args: no
return: error

sls:
args: no
return: error

sra:
args: no
return: error

srl:
args: no
return: error

sub:
args: no
return: error

xor:
args: no
return: error

+ 53
- 23
src/assembler/parse_util.c View File

@@ -319,6 +319,26 @@ bool argparse_condition(ASMArgCondition *result, ASMArgParseInfo ai)
}

/*
Read in a label immediate argument and store it in *result.
*/
static bool argparse_imm_label(ASMArgImmediate *result, ASMArgParseInfo ai)
{
if (ai.size >= MAX_SYMBOL_SIZE)
return false;

for (const char *i = ai.arg; i < ai.arg + ai.size; i++) {
if (!is_valid_symbol_char(*i, i == ai.arg))
return false;
}

result->mask = IMM_U16;
result->is_label = true;
strncpy(result->label, ai.arg, ai.size);
result->label[ai.size] = '\0';
return true;
}

/*
Read in an immediate argument and store it in *result.
*/
bool argparse_immediate(ASMArgImmediate *result, ASMArgParseInfo ai)
@@ -326,10 +346,11 @@ bool argparse_immediate(ASMArgImmediate *result, ASMArgParseInfo ai)
if (ai.size <= 0)
return false;

bool negative = false;
bool negative = false, modifiers = false;
ssize_t i = 0;

while (ai.arg[i] == '-' || ai.arg[i] == '+' || ai.arg[i] == ' ') {
modifiers = true;
if (ai.arg[i] == '-')
negative = !negative;
if (++i >= ai.size)
@@ -341,9 +362,10 @@ bool argparse_immediate(ASMArgImmediate *result, ASMArgParseInfo ai)
const ASMDefine *define = asm_deftable_find(ai.deftable, ai.arg, ai.size);
if (define) {
if (negative) {
calculate_immediate_mask(result);
result->is_label = false;
result->uval = define->value.uval;
result->sval = -define->value.sval;
calculate_immediate_mask(result);
} else {
*result = define->value;
}
@@ -351,16 +373,23 @@ bool argparse_immediate(ASMArgImmediate *result, ASMArgParseInfo ai)
}

uint32_t uval;
if (!parse_uint32_t(&uval, ai.arg, ai.size) || uval > UINT16_MAX)
if (!parse_uint32_t(&uval, ai.arg, ai.size)) {
if (!modifiers && argparse_imm_label(result, ai))
return true;
return false;
}

if (uval > UINT16_MAX)
return false;

int32_t sval = negative ? -uval : uval;
if (sval < INT16_MIN)
return false;

calculate_immediate_mask(result);
result->is_label = false;
result->uval = uval;
result->sval = sval;
calculate_immediate_mask(result);
return true;
}

@@ -374,9 +403,9 @@ bool argparse_indirect(ASMArgIndirect *result, ASMArgParseInfo ai)

ASMArgRegister reg;
ASMArgImmediate imm;
ASMArgLabel label;
if (argparse_register(&reg, ai)) {
if (reg == REG_BC || reg == REG_DE || reg == REG_HL) {
if (reg == REG_BC || reg == REG_DE || reg == REG_HL ||
reg == REG_IX || reg == REG_IY) {
result->type = AT_REGISTER;
result->addr.reg = reg;
return true;
@@ -387,10 +416,6 @@ bool argparse_indirect(ASMArgIndirect *result, ASMArgParseInfo ai)
result->addr.imm = imm;
return true;
}
} else if (argparse_label(&label, ai)) {
result->type = AT_LABEL;
result->addr.label = label;
return true;
}
return false;
}
@@ -433,24 +458,29 @@ bool argparse_indexed(ASMArgIndexed *result, ASMArgParseInfo ai)
}

/*
Read in a label argument and store it in *result.
Read in a port argument and store it in *result.
*/
bool argparse_label(ASMArgLabel *result, ASMArgParseInfo ai)
bool argparse_port(ASMArgPort*, ASMArgParseInfo)
{
if (ai.size <= 0 || ai.size >= MAX_SYMBOL_SIZE)
if (ai.size < 3 || !adjust_for_indirection(&ai))
return false;

for (const char *i = ai.arg; i < ai.arg + ai.size; i++) {
if (!is_valid_symbol_char(*i, i == ai.arg))
return false;
ASMArgRegister reg;
ASMArgImmediate imm;
if (argparse_register(&reg, ai)) {
if (reg == REG_C) {
result->type = AT_REGISTER;
result->addr.reg = reg;
return true;
}
} else if (argparse_immediate(&imm, ai)) {
if (imm.mask & IMM_U8) {
result->type = AT_IMMEDIATE;
result->addr.imm = imm;
return true;
}
}

if (asm_deftable_find(ai.deftable, ai.arg, ai.size))
return false;

strncpy(result->text, ai.arg, ai.size);
result->text[ai.size] = '\0';
return true;
return false;
}

/*


+ 1
- 1
src/assembler/parse_util.h View File

@@ -33,7 +33,7 @@ bool argparse_condition(ASMArgCondition*, ASMArgParseInfo);
bool argparse_immediate(ASMArgImmediate*, ASMArgParseInfo);
bool argparse_indirect(ASMArgIndirect*, ASMArgParseInfo);
bool argparse_indexed(ASMArgIndexed*, ASMArgParseInfo);
bool argparse_label(ASMArgLabel*, ASMArgParseInfo);
bool argparse_port(ASMArgPort*, ASMArgParseInfo);

/* Preprocessor directive parsers */
bool dparse_bool(bool*, const ASMLine*, const char*);


+ 1
- 1
src/assembler/tokenizer.c View File

@@ -155,7 +155,7 @@ static ErrorInfo* handle_define_directive(
ASMArgImmediate imm;
ASMArgParseInfo info = {
.arg = line->data + i, .size = line->length - i, .deftable = deftab};
if (!argparse_immediate(&imm, info))
if (!argparse_immediate(&imm, info) || imm->is_label)
return error_info_create(line, ET_PREPROC, ED_PP_BAD_ARG);

ASMDefine *define = cr_malloc(sizeof(ASMDefine));


Loading…
Cancel
Save