diff options
author | Ian Moffett <ian@osmora.org> | 2025-07-20 22:06:35 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2025-07-20 22:06:35 -0400 |
commit | be4b710d36bfa16e41c833ee22eaadad85e9946a (patch) | |
tree | 644582de763554f4329fdeac416ff5d5fb32ecfd /usr.bin/oasm | |
parent | a08b7fba2897ba392b6dbf1fa8b0e506536750f2 (diff) |
oasm: Add initial codegen emit sources
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'usr.bin/oasm')
-rw-r--r-- | usr.bin/oasm/emit.c | 206 | ||||
-rw-r--r-- | usr.bin/oasm/include/oasm/emit.h | 109 | ||||
-rw-r--r-- | usr.bin/oasm/include/oasm/lex.h | 3 | ||||
-rw-r--r-- | usr.bin/oasm/parse.c | 23 |
4 files changed, 337 insertions, 4 deletions
diff --git a/usr.bin/oasm/emit.c b/usr.bin/oasm/emit.c new file mode 100644 index 0000000..0275d05 --- /dev/null +++ b/usr.bin/oasm/emit.c @@ -0,0 +1,206 @@ +/* + * 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/errno.h> +#include <oasm/emit.h> +#include <oasm/log.h> +#include <stdlib.h> +#include <string.h> + +static inline void +emit_bytes(struct emit_state *state, void *p, size_t len) +{ + write(state->out_fd, p, len); +} + +/* + * Convert an IR register to an OSMX64 + * valid register value that can be encoded + * into the instruction. + */ +static inline reg_t +ir_to_reg(tt_t ir) +{ + switch (ir) { + case TT_X0: return OSMX64_R_X0; + case TT_X1: return OSMX64_R_X1; + case TT_X2: return OSMX64_R_X2; + case TT_X3: return OSMX64_R_X3; + case TT_X4: return OSMX64_R_X4; + case TT_X5: return OSMX64_R_X5; + case TT_X6: return OSMX64_R_X6; + case TT_X7: return OSMX64_R_X7; + case TT_X8: return OSMX64_R_X8; + case TT_X9: return OSMX64_R_X9; + case TT_X10: return OSMX64_R_X10; + case TT_X11: return OSMX64_R_X11; + case TT_X12: return OSMX64_R_X12; + case TT_X13: return OSMX64_R_X13; + case TT_X14: return OSMX64_R_X14; + case TT_X15: return OSMX64_R_X15; + } + + return OSMX64_R_BAD; +} + +/* + * Encode a MOV instruction + * + * mov [r], [r/imm] + * + * Returns the next token on success, + * otherwise NULL. + */ +static struct oasm_token * +emit_encode_mov(struct emit_state *state, struct oasm_token *tok) +{ + inst_t curinst; + reg_t rd; + + if (state == NULL || tok == NULL) { + return NULL; + } + + /* Next token should be a register */ + tok = TAILQ_NEXT(tok, link); + if (tok == NULL) { + return NULL; + } + if (!tok_is_xreg(tok->type)) { + oasm_err("[emit error]: bad 'mov' order\n"); + return NULL; + } + + rd = ir_to_reg(tok->type); + if (rd == OSMX64_R_BAD) { + oasm_err("[emit error]: got bad reg in 'mov'\n"); + return NULL; + } + + + /* Next token should be an IMM */ + tok = TAILQ_NEXT(tok, link); + if (tok == NULL) { + oasm_err("[emit error]: bad 'move' order\n"); + return NULL; + } + if (tok->type != TT_IMM) { + oasm_err("[emit error]: expected <imm>\n"); + return NULL; + } + + curinst.opcode = OSMX64_MOV_IMM; + curinst.rd = rd; + curinst.imm = tok->imm; + emit_bytes(state, &curinst, sizeof(curinst)); + return TAILQ_NEXT(tok, link); +} + +int +emit_osxm64(struct emit_state *state, struct oasm_token *tp) +{ + struct oasm_token *toknew; + + if (state == NULL || tp == NULL) { + return -EINVAL; + } + + /* + * We need to create a copy of the object as the + * caller will likely end up destroying it. + */ + toknew = malloc(sizeof(*toknew)); + if (toknew == NULL) { + return -ENOMEM; + } + + memcpy(toknew, tp, sizeof(*toknew)); + TAILQ_INSERT_TAIL(&state->ir, toknew, link); + return 0; +} + +int +emit_init(struct emit_state *state) +{ + state->last_token = TT_UNKNOWN; + state->is_init = 1; + TAILQ_INIT(&state->ir); + return 0; +} + +int +emit_destroy(struct emit_state *state) +{ + struct oasm_token *curtok, *last = NULL; + + TAILQ_FOREACH(curtok, &state->ir, link) { + if (last != NULL) { + free(last); + last = NULL; + } + if (curtok->raw != NULL) { + free(curtok->raw); + } + + last = curtok; + } + + /* Clean up any last objects */ + if (last != NULL) { + free(last); + } + + return 0; +} + +int +emit_process(struct oasm_state *oasm, struct emit_state *emit) +{ + struct oasm_token *curtok; + tt_t last_tok; + + if (!emit->is_init) { + return -1; + } + + emit->out_fd = oasm->out_fd; + TAILQ_FOREACH(curtok, &emit->ir, link) { + switch (curtok->type) { + case TT_MOV: + curtok = emit_encode_mov(emit, curtok); + break; + } + + if (curtok == NULL) { + break; + } + } + + return 0; +} diff --git a/usr.bin/oasm/include/oasm/emit.h b/usr.bin/oasm/include/oasm/emit.h new file mode 100644 index 0000000..e4ed83c --- /dev/null +++ b/usr.bin/oasm/include/oasm/emit.h @@ -0,0 +1,109 @@ +/* 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 _EMIT_H_ +#define _EMIT_H_ + +#include <sys/queue.h> +#include <stdint.h> +#include <stddef.h> +#include <oasm/lex.h> +#include <oasm/state.h> + +/* + * The OSMX64 architecture has 32-bit instructions + * that are encoded in the following manner: + * + * - [0:7]: Opcode + * - [11:8]: Register + * - [31:12]: Reserved + * + * The values below define various operation + * codes. + */ +#define OSMX64_NOP 0x00 /* No-operation */ +#define OSMX64_ADD 0x01 /* Add operation */ +#define OSMX64_SUB 0x02 /* Sub operation */ +#define OSMX64_MUL 0x03 /* Multiply operation */ +#define OSMX64_DIV 0x04 /* Divide operation */ +#define OSMX64_INC 0x05 /* Increment operation */ +#define OSMX64_DEC 0x06 /* Decrement operation */ +#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 */ + +/* + * OSMX64 register definitions + */ +#define OSMX64_R_X0 0x00 +#define OSMX64_R_X1 0x01 +#define OSMX64_R_X2 0x02 +#define OSMX64_R_X3 0x03 +#define OSMX64_R_X4 0x04 +#define OSMX64_R_X5 0x05 +#define OSMX64_R_X6 0x06 +#define OSMX64_R_X7 0x07 +#define OSMX64_R_X8 0x08 +#define OSMX64_R_X9 0x09 +#define OSMX64_R_X10 0x0A +#define OSMX64_R_X11 0x0B +#define OSMX64_R_X12 0x0C +#define OSMX64_R_X13 0x0D +#define OSMX64_R_X14 0x0E +#define OSMX64_R_X15 0x0F +#define OSMX64_R_BAD 0xFF + +typedef uint8_t reg_t; +typedef uint16_t imm_t; + +/* + * OSMX64 instruction + */ +typedef struct { + uint8_t opcode; + uint8_t rd; + uint16_t imm; +} inst_t; + +struct emit_state { + tt_t last_token; + uint8_t is_init : 1; + int out_fd; + TAILQ_HEAD(, oasm_token) ir; +}; + +int emit_init(struct emit_state *state); +int emit_destroy(struct emit_state *state); +int emit_process(struct oasm_state *oasm, struct emit_state *emit); +int emit_osxm64(struct emit_state *state, struct oasm_token *tp); + +#endif /* !_EMIT_H_ */ diff --git a/usr.bin/oasm/include/oasm/lex.h b/usr.bin/oasm/include/oasm/lex.h index 2811ca3..28ad52c 100644 --- a/usr.bin/oasm/include/oasm/lex.h +++ b/usr.bin/oasm/include/oasm/lex.h @@ -30,6 +30,8 @@ #ifndef _OASM_LEX_H_ #define _OASM_LEX_H_ +#include <sys/queue.h> +#include <sys/cdefs.h> #include <stdint.h> struct oasm_state; @@ -115,6 +117,7 @@ struct oasm_token { uint8_t is_reg : 1; uint16_t imm; char *raw; + TAILQ_ENTRY(oasm_token) link; }; int lex_tok(struct oasm_state *state, struct oasm_token *ttp); diff --git a/usr.bin/oasm/parse.c b/usr.bin/oasm/parse.c index 80d353b..88b5506 100644 --- a/usr.bin/oasm/parse.c +++ b/usr.bin/oasm/parse.c @@ -29,11 +29,13 @@ #include <stdint.h> #include <stddef.h> #include <stdlib.h> +#include <oasm/emit.h> #include <oasm/state.h> #include <oasm/lex.h> #include <oasm/parse.h> #include <oasm/log.h> +static struct emit_state emit_state; static const char *tokstr[] = { [ TT_UNKNOWN] = "bad", [ TT_ADD ] = "add", @@ -119,6 +121,14 @@ parse_reg(struct oasm_state *state, struct oasm_token *tok) return -1; } + state->last = tok->type; + emit_osxm64(&emit_state, tok); + return 0; +} + +static int +parse_imm(struct oasm_token *tok, tt_t last) +{ return 0; } @@ -131,9 +141,11 @@ parse_tok(struct oasm_state *state, struct oasm_token *tok) switch (tok->type) { case TT_MOV: state->last = tok->type; + emit_osxm64(&emit_state, tok); break; case TT_DEC: state->last = tok->type; + emit_osxm64(&emit_state, tok); break; case TT_IMM: p = tokstr[state->last]; @@ -141,6 +153,7 @@ parse_tok(struct oasm_state *state, struct oasm_token *tok) printf("expected X<n> but got %s\n", p); return -1; } + emit_osxm64(&emit_state, tok); break; default: if (!tok->is_reg) { @@ -165,6 +178,8 @@ parse_enter(struct oasm_state *state) const char *type, *raw; int error = 0; + emit_init(&emit_state); + for (;;) { error = lex_tok(state, &tok); if (error < 0) { @@ -178,9 +193,9 @@ parse_enter(struct oasm_state *state) type = tokstr[tok.type]; raw = tok.raw; oasm_debug("got token type %s (%s)\n", type, raw); - - if (tok.raw != NULL) { - free(tok.raw); - } } + + /* Process then destroy the emit state */ + emit_process(state, &emit_state); + emit_destroy(&emit_state); } |