summaryrefslogtreecommitdiff
path: root/usr.bin/oasm
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/oasm')
-rw-r--r--usr.bin/oasm/emit.c130
-rw-r--r--usr.bin/oasm/include/oasm/emit.h15
-rw-r--r--usr.bin/oasm/include/oasm/label.h55
-rw-r--r--usr.bin/oasm/include/oasm/lex.h26
-rw-r--r--usr.bin/oasm/include/oasm/state.h4
-rw-r--r--usr.bin/oasm/label.c166
-rw-r--r--usr.bin/oasm/lex.c120
-rw-r--r--usr.bin/oasm/parse.c44
8 files changed, 542 insertions, 18 deletions
diff --git a/usr.bin/oasm/emit.c b/usr.bin/oasm/emit.c
index 0e8ad4e..139cf47 100644
--- a/usr.bin/oasm/emit.c
+++ b/usr.bin/oasm/emit.c
@@ -257,6 +257,126 @@ emit_encode_hlt(struct emit_state *state, struct oasm_token *tok)
return TAILQ_NEXT(tok, link);
}
+/*
+ * Encode a BR instruction
+ *
+ * br [r]
+ *
+ * Returns the next token on success,
+ * otherwise NULL.
+ */
+static struct oasm_token *
+emit_encode_br(struct emit_state *state, struct oasm_token *tok)
+{
+ inst_t curinst;
+ reg_t rd;
+ uint8_t opcode = OSMX64_BR;
+ char *inst_str = "br";
+
+ /* Grab the register */
+ tok = TAILQ_NEXT(tok, link);
+ if (tok == NULL) {
+ return NULL;
+ }
+ if (!tok_is_xreg(tok->type)) {
+ oasm_err("[emit error]: expected register in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ rd = ir_to_reg(tok->type);
+ if (rd == OSMX64_R_BAD) {
+ oasm_err("[emit error]: got bad in register in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ curinst.opcode = opcode;
+ curinst.rd = rd;
+ curinst.unused = 0;
+ emit_bytes(state, &curinst, sizeof(curinst));
+ return TAILQ_NEXT(tok, link);
+}
+
+/*
+ * Encode the MRO type instructions
+ *
+ * mrob x1[7:0]
+ * mrow x1[15:0] ! Mrowwww :3333
+ * mrod x1[31:0]
+ * mroq x[63:0]
+ *
+ * Returns the next token on success,
+ * otherwise NULL.
+ */
+static struct oasm_token *
+emit_encode_mro(struct emit_state *state, struct oasm_token *tok)
+{
+ inst_t curinst;
+ reg_t rd;
+ uint8_t opcode = OSMX64_MROB;
+ char *inst_str = "mrob";
+
+ switch (tok->type) {
+ case TT_MROW:
+ opcode = OSMX64_MROW;
+ inst_str = "mrow";
+ break;
+ case TT_MROD:
+ opcode = OSMX64_MROD;
+ inst_str = "mrod";
+ break;
+ case TT_MROQ:
+ opcode = OSMX64_MROQ;
+ inst_str = "mroq";
+ break;
+ }
+
+ /* Next token should be a register */
+ tok = TAILQ_NEXT(tok, link);
+ if (!tok_is_xreg(tok->type)) {
+ oasm_err("[emit error]: expected register in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ rd = ir_to_reg(tok->type);
+ if (rd == OSMX64_R_BAD) {
+ oasm_err("[emit error]: got bad register in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ /* Next token should be an IMM */
+ tok = TAILQ_NEXT(tok, link);
+ if (tok->type != TT_IMM) {
+ oasm_err("[emit error]: expected <imm> after reg in '%s'\n", inst_str);
+ return NULL;
+ }
+
+ curinst.opcode = opcode;
+ curinst.rd = rd;
+ curinst.imm = tok->imm;
+ emit_bytes(state, &curinst, sizeof(curinst));
+ return TAILQ_NEXT(tok, link);
+}
+
+/*
+ * Encode a NOP instruction
+ *
+ * 'nop' - no operands
+ *
+ * Returns the next token on success,
+ * otherwise NULL.
+ */
+static struct oasm_token *
+emit_encode_nop(struct emit_state *state, struct oasm_token *tok)
+{
+ inst_t curinst;
+
+ curinst.opcode = OSMX64_NOP;
+ curinst.rd = 0;
+ curinst.unused = 0;
+ emit_bytes(state, &curinst, sizeof(curinst));
+ return TAILQ_NEXT(tok, link);
+}
+
int
emit_osmx64(struct emit_state *state, struct oasm_token *tp)
{
@@ -328,6 +448,9 @@ emit_process(struct oasm_state *oasm, struct emit_state *emit)
curtok = TAILQ_FIRST(&emit->ir);
while (curtok != NULL) {
switch (curtok->type) {
+ case TT_NOP:
+ curtok = emit_encode_nop(emit, curtok);
+ break;
case TT_MOV:
curtok = emit_encode_mov(emit, curtok);
break;
@@ -341,10 +464,17 @@ emit_process(struct oasm_state *oasm, struct emit_state *emit)
case TT_DIV:
curtok = emit_encode_arith(emit, curtok);
break;
+ case TT_BR:
+ curtok = emit_encode_br(emit, curtok);
+ break;
case TT_HLT:
curtok = emit_encode_hlt(emit, curtok);
break;
default:
+ if (lex_is_mro(curtok->type)) {
+ curtok = emit_encode_mro(emit, curtok);
+ break;
+ }
curtok = TAILQ_NEXT(curtok, link);
break;
}
diff --git a/usr.bin/oasm/include/oasm/emit.h b/usr.bin/oasm/include/oasm/emit.h
index d289adb..3fc2674 100644
--- a/usr.bin/oasm/include/oasm/emit.h
+++ b/usr.bin/oasm/include/oasm/emit.h
@@ -56,11 +56,16 @@
#define OSMX64_OR 0x07 /* Bitwise OR operation */
#define OSMX64_XOR 0x08 /* Bitwise XOR operation */
#define OSMX64_AND 0x09 /* Bitwise AND operation */
-#define OSMX64_NOT 0x10 /* Bitwise NOT operation */
-#define OSMX64_SLL 0x11 /* Shift left logical operation */
-#define OSMX64_SRL 0x12 /* Shift right logical operation */
-#define OSMX64_MOV_IMM 0x13 /* Data move operation from IMM */
-#define OSMX64_HLT 0x14 /* Halt the processor */
+#define OSMX64_NOT 0x0A /* Bitwise NOT operation */
+#define OSMX64_SLL 0x0B /* Shift left logical operation */
+#define OSMX64_SRL 0x0C /* Shift right logical operation */
+#define OSMX64_MOV_IMM 0x0D /* Data move operation from IMM */
+#define OSMX64_HLT 0x0E /* Halt the processor */
+#define OSMX64_BR 0x0F /* Branch */
+#define OSMX64_MROB 0x10 /* Mask register over byte */
+#define OSMX64_MROW 0x11 /* Mask register over word */
+#define OSMX64_MROD 0x12 /* Mask register over dword */
+#define OSMX64_MROQ 0x13 /* Mask register over qword */
/*
* OSMX64 register definitions
diff --git a/usr.bin/oasm/include/oasm/label.h b/usr.bin/oasm/include/oasm/label.h
new file mode 100644
index 0000000..8acb369
--- /dev/null
+++ b/usr.bin/oasm/include/oasm/label.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _OASM_LABEL_H_
+#define _OASM_LABEL_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#define MAX_LABELS 128
+
+/*
+ * Represents a label
+ *
+ * @name: Label name (e.g., _start)
+ * @ip: Address at which label code starts
+ */
+struct oasm_label {
+ char *name;
+ uintptr_t ip;
+ TAILQ_ENTRY(oasm_label) link;
+ TAILQ_HEAD(, oasm_label) buckets;
+};
+
+void labels_destroy(void);
+int label_enter(const char *name, uintptr_t ip);
+struct oasm_label *label_lookup(const char *name);
+
+#endif /* !_OASM_LABEL_H_ */
diff --git a/usr.bin/oasm/include/oasm/lex.h b/usr.bin/oasm/include/oasm/lex.h
index 6ffaf79..375771e 100644
--- a/usr.bin/oasm/include/oasm/lex.h
+++ b/usr.bin/oasm/include/oasm/lex.h
@@ -33,6 +33,7 @@
#include <sys/queue.h>
#include <sys/cdefs.h>
#include <stdint.h>
+#include <stdbool.h>
struct oasm_state;
@@ -89,6 +90,7 @@ struct oasm_state;
*/
typedef enum {
TT_UNKNOWN, /* Unknown token */
+ TT_NOP, /* No operation */
/* Arithmetic instructions */
TT_ADD, /* 'add' */
@@ -96,12 +98,18 @@ typedef enum {
TT_MUL, /* 'mul' */
TT_DIV, /* 'div' */
TT_HLT, /* 'hlt' */
+ TT_BR, /* 'br' */
+ TT_MROB, /* 'mrob' */
+ TT_MROW, /* 'mrow' */
+ TT_MROD, /* 'mrod' */
+ TT_MROQ, /* 'mroq' */
/* Register ops */
TT_MOV, /* 'mov' */
TT_INC, /* 'inc' */
TT_DEC, /* 'dec' */
TT_IMM, /* #<n> */
+ TT_LABEL, /* 'label: ...' */
/* Register sets */
__XN_REGS, /* x0-x15 */
@@ -154,4 +162,22 @@ tok_is_xreg(tt_t tok)
return false;
}
+/*
+ * Check if a token is of an MRO type
+ * instruction. Returns true on match.
+ */
+__always_inline static inline bool
+lex_is_mro(tt_t tok)
+{
+ switch (tok) {
+ case TT_MROB:
+ case TT_MROW:
+ case TT_MROD:
+ case TT_MROQ:
+ return true;
+ }
+
+ return false;
+}
+
#endif /* !_OASM_LEX_H_ */
diff --git a/usr.bin/oasm/include/oasm/state.h b/usr.bin/oasm/include/oasm/state.h
index 5f58144..6dd2435 100644
--- a/usr.bin/oasm/include/oasm/state.h
+++ b/usr.bin/oasm/include/oasm/state.h
@@ -39,6 +39,8 @@
* OASM state:
*
* @filename: Filname of unit we are parsing
+ * @pip: Pseudo instruction pointer
+ * @label_ip: IP at current label start
* @in_fd: Input file descriptor
* @out_fd: Resulting binary output file descriptor
* @line: Current line number
@@ -46,6 +48,8 @@
*/
struct oasm_state {
char *filename;
+ off_t pip;
+ off_t label_ip;
int in_fd;
int out_fd;
off_t line;
diff --git a/usr.bin/oasm/label.c b/usr.bin/oasm/label.c
new file mode 100644
index 0000000..2647bb9
--- /dev/null
+++ b/usr.bin/oasm/label.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/queue.h>
+#include <oasm/label.h>
+#include <oasm/log.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+static struct oasm_label *labels[MAX_LABELS];
+static size_t label_count = 0;
+
+static uint32_t
+fnv1_hash(const char *s)
+{
+ uint32_t hash = 2166136261UL;
+ const uint8_t *p = (uint8_t *)s;
+
+ while (*p != '\0') {
+ hash ^= *p;
+ hash = hash * 0x01000193;
+ ++p;
+ }
+
+ return hash;
+}
+
+/*
+ * The label table is a big hashmap containing
+ * label entries. This function creates and add
+ * a new label into the table.
+ *
+ * @name: Name of the label (e.g., _start)
+ * @ip: Instruction pointer
+ */
+int
+label_enter(const char *name, uintptr_t ip)
+{
+ uint32_t hash = fnv1_hash(name);
+ uint32_t idx = hash % MAX_LABELS;
+ struct oasm_label *lp, *lp_new;
+
+ if (label_count >= MAX_LABELS) {
+ oasm_err("[internal error]: too many labels\n");
+ return -EIO;
+ }
+
+ lp_new = malloc(sizeof(*lp_new));
+ if (lp_new == NULL) {
+ oasm_err("[internal error]: out of memory\n");
+ return -ENOMEM;
+ }
+
+ /* Initialize the label */
+ lp_new->name = strdup(name);
+ lp_new->ip = ip;
+ TAILQ_INIT(&lp_new->buckets);
+
+ /*
+ * If there is no existing entry here, we
+ * can take this slot.
+ */
+ lp = labels[idx];
+ if (lp == NULL) {
+ labels[idx] = lp_new;
+ ++label_count;
+ return 0;
+ }
+
+ /*
+ * To prevent collisions in our table here,
+ * we must check if the name matches at all.
+ * If it does not, there is a collision and
+ * we'll have to add this to a bucket.
+ */
+ if (strcmp(name, lp->name) != 0) {
+ TAILQ_INSERT_TAIL(&lp->buckets, lp_new, link);
+ ++label_count;
+ return 0;
+ }
+
+ /* Can't put the same entry in twice */
+ oasm_err("[internal error]: duplicate labels\n");
+ return -EEXIST;
+}
+
+/*
+ * Find a label entry in the label table.
+ *
+ * @name: Name of the label to lookup (e.g., _start)
+ */
+struct oasm_label *
+label_lookup(const char *name)
+{
+ uint32_t hash = fnv1_hash(name);
+ uint32_t idx = hash % MAX_LABELS;
+ struct oasm_label *lp, *lp_tmp;
+
+ lp = labels[idx];
+ if (lp == NULL) {
+ return NULL;
+ }
+
+ /* Is this the label we are looking up? */
+ if (strcmp(name, lp->name) == 0) {
+ return lp;
+ }
+
+ /* Maybe there was a collision? */
+ TAILQ_FOREACH(lp_tmp, &lp->buckets, link) {
+ if (strcmp(name, lp_tmp->name) == 0) {
+ return lp_tmp;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Clean up all allocated labels by
+ * calling free() on each entry of
+ * the queue.
+ */
+void
+labels_destroy(void)
+{
+ struct oasm_label *lp;
+
+ for (size_t i = 0; i < MAX_LABELS; ++i) {
+ lp = labels[i];
+ if (lp != NULL) {
+ free(lp->name);
+ free(lp);
+ }
+ }
+}
diff --git a/usr.bin/oasm/lex.c b/usr.bin/oasm/lex.c
index 7b78d54..fea9dc3 100644
--- a/usr.bin/oasm/lex.c
+++ b/usr.bin/oasm/lex.c
@@ -34,11 +34,13 @@
#include <oasm/lex.h>
#include <oasm/log.h>
+#define COMMENT '!'
#define is_num(c) ((c) >= '0' && (c) <= '9')
static char putback = '\0';
/* Instruction mnemonic strings */
+#define S_IMN_NOP "nop"
#define S_IMN_MOV "mov"
#define S_IMN_ADD "add"
#define S_IMN_SUB "sub"
@@ -47,6 +49,25 @@ static char putback = '\0';
#define S_IMN_INC "inc"
#define S_IMN_DEC "dec"
#define S_IMN_HLT "hlt"
+#define S_IMN_BR "br"
+#define S_IMN_MROB "mrob"
+#define S_IMN_MROW "mrow"
+#define S_IMN_MROD "mrod"
+#define S_IMN_MROQ "mroq"
+
+/* Instruction length */
+#define OSMX64_INST_LEN 4
+
+/*
+ * Update the state when the caller encounters
+ * a newline.
+ */
+static inline void
+lex_newline(struct oasm_state *state)
+{
+ ++state->line;
+ state->pip += OSMX64_INST_LEN;
+}
/*
* Returns 0 if a char is counted as a
@@ -61,7 +82,7 @@ lex_skippable(struct oasm_state *state, char c)
case '\t': return 0;
case '\r': return 0;
case '\n':
- ++state->line;
+ lex_newline(state);
return 0;
}
@@ -152,6 +173,10 @@ lex_nomstr(struct oasm_state *state, char **res)
retval = tmp;
break;
}
+ if (tmp == ':') {
+ retval = tmp;
+ break;
+ }
if (tmp == '\n') {
++state->line;
retval = tmp;
@@ -190,6 +215,54 @@ token_arith(char *p)
return TT_UNKNOWN;
}
+/*
+ * Control flow instructions
+ */
+static tt_t
+token_cfi(char *p)
+{
+ if (strcmp(p, S_IMN_BR) == 0) {
+ return TT_BR;
+ }
+
+ return TT_UNKNOWN;
+}
+
+/*
+ * Bitwise MRO instructions
+ */
+static tt_t
+token_bitw_mro(char *p)
+{
+ if (strcmp(p, S_IMN_MROB) == 0) {
+ return TT_MROB;
+ } else if (strcmp(p, S_IMN_MROW) == 0) {
+ return TT_MROW;
+ } else if (strcmp(p, S_IMN_MROD) == 0) {
+ return TT_MROD;
+ } else if (strcmp(p, S_IMN_MROQ) == 0) {
+ return TT_MROQ;
+ }
+
+ return TT_UNKNOWN;
+}
+
+/*
+ * Bitwise instructions
+ */
+static tt_t
+token_bitw(char *p)
+{
+ tt_t token;
+
+ token = token_bitw_mro(p);
+ if (token != TT_UNKNOWN) {
+ return token;
+ }
+
+ return TT_UNKNOWN;
+}
+
static tt_t
token_xreg(char *p)
{
@@ -254,6 +327,7 @@ lex_tok(struct oasm_state *state, struct oasm_token *ttp)
{
char *p = NULL;
char c = ' ';
+ short in_comment = 0;
int tmp;
tt_t tok;
@@ -262,18 +336,24 @@ lex_tok(struct oasm_state *state, struct oasm_token *ttp)
}
/*
- * Grab characters. If they are skippable,
- * don't use them.
+ * Grab characters. If they are skippable or
+ * comments, don't use them.
*/
- while (lex_skippable(state, c) == 0) {
+ while (lex_skippable(state, c) == 0 || in_comment) {
if ((c = lex_cin(state)) == 0) {
return -1;
}
+
+ if (c == COMMENT) {
+ in_comment = 1;
+ } else if (c == '\n') {
+ in_comment = 0;
+ }
}
switch (c) {
case '\n':
- ++state->line;
+ lex_newline(state);
return 0;
case '\0':
return -1;
@@ -284,7 +364,21 @@ lex_tok(struct oasm_state *state, struct oasm_token *ttp)
ttp->raw = NULL;
lex_putback(c);
- lex_nomstr(state, &p);
+ c = lex_nomstr(state, &p);
+
+ while (c == ':') {
+ ttp->type = TT_LABEL;
+ ttp->raw = p;
+ state->label_ip = state->pip;
+ return 0;
+ }
+
+ /* No operation? */
+ if (strcmp(p, S_IMN_NOP) == 0) {
+ ttp->type = TT_NOP;
+ ttp->raw = p;
+ return 0;
+ }
/* Arithmetic operation? */
if ((tok = token_arith(p)) != TT_UNKNOWN) {
@@ -293,6 +387,13 @@ lex_tok(struct oasm_state *state, struct oasm_token *ttp)
return 0;
}
+ /* Control flow instruction? */
+ if ((tok = token_cfi(p)) != TT_UNKNOWN) {
+ ttp->type = tok;
+ ttp->raw = p;
+ return 0;
+ }
+
/* Register? */
if ((tok = token_reg(p)) != TT_UNKNOWN) {
ttp->is_reg = 1;
@@ -301,6 +402,12 @@ lex_tok(struct oasm_state *state, struct oasm_token *ttp)
return 0;
}
+ if ((tok = token_bitw(p)) != TT_UNKNOWN) {
+ ttp->type = tok;
+ ttp->raw = p;
+ return 0;
+ }
+
/* Immediate operand? */
if ((tok = token_operand(p)) != TT_UNKNOWN) {
if (tok == TT_IMM) {
@@ -311,6 +418,7 @@ lex_tok(struct oasm_state *state, struct oasm_token *ttp)
ttp->raw = p;
return 0;
}
+
oasm_err("bad token \"%s\"\n", p);
lex_try_free(p);
return -1;
diff --git a/usr.bin/oasm/parse.c b/usr.bin/oasm/parse.c
index 9a4dd0e..ba97306 100644
--- a/usr.bin/oasm/parse.c
+++ b/usr.bin/oasm/parse.c
@@ -34,20 +34,31 @@
#include <oasm/lex.h>
#include <oasm/parse.h>
#include <oasm/log.h>
+#include <oasm/label.h>
static struct emit_state emit_state;
static const char *tokstr[] = {
[ TT_UNKNOWN] = "bad",
+ [ TT_NOP ] = "nop",
[ TT_ADD ] = "add",
[ TT_SUB ] = "sub",
[ TT_MUL ] = "mul",
[ TT_DIV ] = "div",
[ TT_HLT ] = "hlt",
+ [ TT_BR ] = "br",
[ TT_COMMA ] = ",",
[ TT_INC ] = "inc",
[ TT_DEC ] = "dec",
[ TT_MOV ] = "mov",
[ TT_IMM ] = "<imm>",
+ [ TT_LABEL] = "<label>",
+
+ /* Bitwise */
+ [ TT_MROB ] = "mrob",
+ [ TT_MROW ] = "mrow",
+ [ TT_MROD ] = "mrod",
+ [ TT_MROQ ] = "mroq",
+
/* X<n> registers */
[ TT_X0 ] = "x0",
@@ -112,9 +123,15 @@ parse_reg(struct oasm_state *state, struct oasm_token *tok)
case TT_SUB:
case TT_MUL:
case TT_DIV:
+ case TT_BR:
state->last = tok->type;
break;
default:
+ if (lex_is_mro(state->last)) {
+ state->last = tok->type;
+ break;
+ }
+
p = tokstr[state->last];
oasm_err("bad instruction '%s' for regop\n", p);
return -1;
@@ -132,18 +149,24 @@ parse_reg(struct oasm_state *state, struct oasm_token *tok)
}
static int
-parse_imm(struct oasm_token *tok, tt_t last)
-{
- return 0;
-}
-
-static int
parse_tok(struct oasm_state *state, struct oasm_token *tok)
{
const char *p;
int error;
switch (tok->type) {
+ case TT_NOP:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_BR:
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ break;
+ case TT_LABEL:
+ state->last = tok->type;
+ label_enter(tok->raw, state->pip);
+ break;
case TT_HLT:
state->last = tok->type;
emit_osmx64(&emit_state, tok);
@@ -176,12 +199,18 @@ parse_tok(struct oasm_state *state, struct oasm_token *tok)
case TT_IMM:
p = tokstr[state->last];
if (!tok_is_xreg(state->last)) {
- printf("expected X<n> but got %s\n", p);
+ oasm_err("expected X<n> but got %s\n", p);
return -1;
}
emit_osmx64(&emit_state, tok);
break;
default:
+ if (lex_is_mro(tok->type)) {
+ state->last = tok->type;
+ emit_osmx64(&emit_state, tok);
+ return 0;
+ }
+
if (!tok->is_reg) {
oasm_err("syntax error\n");
return -1;
@@ -224,4 +253,5 @@ parse_enter(struct oasm_state *state)
/* Process then destroy the emit state */
emit_process(state, &emit_state);
emit_destroy(&emit_state);
+ labels_destroy();
}