commit 06594207f9b13bcca77ea2999f73040e8597a3be Author: julianb0 Date: Wed May 15 19:26:40 2019 +0200 initial commit diff --git a/INSTRS b/INSTRS new file mode 100644 index 0000000..2fe9ef9 --- /dev/null +++ b/INSTRS @@ -0,0 +1,26 @@ +# The OS/K Team licences this file to you under the MIT license. +# See the LICENCE file in the project root for more information. + +ADD r ri + %0 = %0 + %1 + +SUB r ri + %0 = %0 + %1 + +MUL ri + RDX = hi(%0 * %1) + RAX = lo(%0 * %1) + +DIV ri + RDX = RAX % %0 + RAX = RAX / %0 + +INC r + %0 = %0 + 1 + +DEC r + %0 = %0 - 1 + +MOV ri ri + %0 = %1 + diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..a56966a --- /dev/null +++ b/LICENCE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright © 2019 The OS/K Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1f255a1 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +# The OS/K Team licences this file to you under the MIT license. +# See the LICENCE file in the project root for more information. + +src = arch.c instrs.c main.c regs.c +obj = $(patsubst %.c,%.o,$(src)) + +%.o: %.c + @gcc -O2 -Wall -c $< -o $@ + +k.exe: $(obj) + @gcc -O2 -Wall $(obj) -o k.exe + @rm *.o + diff --git a/arch.c b/arch.c new file mode 100644 index 0000000..727e228 --- /dev/null +++ b/arch.c @@ -0,0 +1,128 @@ +// The OS/K Team licences this file to you under the MIT license. +// See the LICENCE file in the project root for more information. + +#include "arch.h" + +void scan_param(ctx_t *ctx, acc_t *p) +{ + ushort c; + reg_t *r; + + assert(p != 0); + + c = ctx->get(ctx); + + if (c == A_MEM) { + p->mem = 1; + c = ctx->get(ctx); + } + + if (c >= A_IMM16) { + assert(p->type == A_REG); + p->type = c; + c = ctx->get(ctx); + } + + p->val = c; + + if (p->type == A_IMM32) { + p->val = (p->val << 16) | ctx->get(ctx); + } + + else if (p->type == A_IMM64) { + p->val = (p->val << 16) | ctx->get(ctx); + p->val = (p->val << 16) | ctx->get(ctx); + p->val = (p->val << 16) | ctx->get(ctx); + } + + else if (p->type == A_REG) { + if (p->val > NREGS) { + _except(ctx, E_ILL, "Inexistent REG"); + } + + r = &ctx->r[p->val]; + + if (r->flags & (RES | CTL)) { + _except(ctx, E_ACC, "Reserved REG"); + } + } +} + +void dumpregs(ctx_t *ctx) +{ + int i; + reg_t *r; + + for (i = 0; i < NREGS; i++) { + if (i > 0 && i % 4 == 0) + log("\n"); + + r = &ctx->r[i]; + log("%s=0x%016lX ", r->name, r->val); + } + log("\n"); +} + +void dumpinstr(ctx_t *ctx, ushort c, acc_t *p1, acc_t *p2) +{ + acc_t *p = 0; + instr_t *i = &ctx->i[c]; + log("%s", i->name); + + if (i->prms > 0) + p = p1; +lp: + if (p != 0) { + if (p->mem) log("["); + + if (p->type == A_REG) + log(" %s", ctx->r[p->val].name); + else + log(" 0x%lX", p->val); + + if (p->mem) log("]"); + + if (p == p1 && i->prms == 2) { + p = p2; + goto lp; + } + } + + log("\n"); +} + +void decode(ctx_t *ctx) +{ + instr_t *i; + acc_t p1 = { 0 }, p2 = { 0 }; + + ushort c = ctx->get(ctx); + + if (c == 0xFFFF) { + _except(ctx, E_SHT, "Shutdown INSTR"); + } + + else if (ISPREF(c)) { + // nothing for now + } + + else if (!ISINSTR(c)) { + _except(ctx, E_ILL, "Bad opcode"); + } + + // Scanning an instruction + + i = &ctx->i[c]; + + // Scan for parameters + if (i->prms > 0) { + scan_param(ctx, &p1); + if (i->prms == 2) { + scan_param(ctx, &p2); + } + } + + dumpinstr(ctx, c, &p1, &p2); + i->func(ctx, &p1, &p2); +} + diff --git a/arch.h b/arch.h new file mode 100644 index 0000000..d4173ee --- /dev/null +++ b/arch.h @@ -0,0 +1,124 @@ +// The OS/K Team licences this file to you under the MIT license. +// See the LICENCE file in the project root for more information. + +#include +#include +#include + +#define log printf + +#define packed __attribute__ ((__packed__)) +#define static_assert _Static_assert + +typedef unsigned int bool; +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + +typedef struct reg_t reg_t; +typedef struct ctx_t ctx_t; +typedef struct instr_t instr_t; +typedef struct acc_t acc_t; +typedef struct arch_t arch_t; + +enum +{ + RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP, + R08, R09, R10, R11, R12, R13, R14, R15, + K00, K01, K02, K03, K04, K05, K06, K07, + CR0, CR1, CR2, CR3, CR4, CR5, CR6, CR7, + RIP, RFG, + + NREGS +}; + +enum +{ + I_ADD, I_SUB, I_MUL, I_DIV, I_INC, I_DEC, + I_AND, I_OR, I_XOR, I_NEG, I_CMD, I_TST, + + I_PUSH, I_PUSHF, I_PUSHA, + I_POP, I_POPF, I_POPA, + + I_MOV, I_XCHG, + + I_BSWP, + + I_PSE, I_HLT, I_INT, + + NINSTRS +}; + +enum +{ + GPR = 1 << 0, // General + CTL = 1 << 1, // Control + SEG = 1 << 2, // Segment + RES = 1 << 8, // Reserved for insternal use + SYS = 1 << 9, // Reserved for supervisor mode +}; + +struct reg_t +{ + char *name; + char *desc; + ulong val; + ulong flags; +}; + +enum { A_MEM=0x7000 }; +struct acc_t +{ + bool mem; + enum { A_REG=0, A_IMM16=0x7001, A_IMM32, A_IMM64 } type; + + ulong val; +}; + +enum { NOPREF, PREF_REP=0x8000, PREF_LOCK, NPREFS }; + +#define ISPREF(x) ((x) & 0x8000 && (x)type != A_REG) { + _except(ctx, E_ILL, "ADD into IMM"); + } + + if (p1->mem || p2->mem) { + _except(ctx, E_IMP, "Memory access"); + } + + ctx->r[p1->val].val += p2->type >= A_IMM16 ? p2->val + : ctx->r[p2->val].val; +} + +void i_sub(ctx_t *ctx, acc_t *p1, acc_t *p2) +{ + if (p1->type != A_REG) { + _except(ctx, E_ILL, "SUB into IMM"); + } + + if (p1->mem || p2->mem) { + _except(ctx, E_IMP, "Memory access"); + } + + ctx->r[p1->val].val -= p2->type >= A_IMM16 ? p2->val + : ctx->r[p2->val].val; +} + +void i_mul(ctx_t *ctx, acc_t *p1, acc_t *p2) +{ + if (p1->mem) { + _except(ctx, E_IMP, "Memory access"); + } + + // Adapted from + // https://www.codeproject.com/Tips/618570/UInt-Multiplication-Squaring + + ulong u = p1->type >= A_IMM16 ? p1->val : ctx->r[p1->val].val; + ulong v = ctx->r[RAX].val; + ulong u1 = u & 0xffffffff; + ulong v1 = v & 0xffffffff; + ulong t = (u1 * v1); + ulong w3 = (t & 0xffffffff); + ulong k = (t >> 32); + + u >>= 32; + t = (u * v1) + k; + k = (t & 0xffffffff); + ulong w1 = (t >> 32); + + v >>= 32; + t = (u1 * v) + k; + k = (t >> 32); + + ctx->r[RDX].val = (u * v) + w1 + k; + ctx->r[RAX].val = (t << 32) + w3; +} + +void i_div(ctx_t *ctx, acc_t *p1, acc_t *p2) +{ + if (p1->mem) { + _except(ctx, E_IMP, "Memory access"); + } + + ulong val = p1->type >= A_IMM16 ? p1->val : ctx->r[p1->val].val; + + ctx->r[RDX].val = ctx->r[RAX].val % val; + ctx->r[RAX].val = ctx->r[RAX].val / val; +} + +void i_inc(ctx_t *ctx, acc_t *p1, acc_t *p2) +{ + if (p1->type != A_REG) { + _except(ctx, E_ILL, "INC on an IMM"); + } + + if (p1->mem) { + _except(ctx, E_IMP, "Memory access"); + } + + ctx->r[p1->val].val++; +} + +void i_dec(ctx_t *ctx, acc_t *p1, acc_t *p2) +{ + if (p1->type != A_REG) { + _except(ctx, E_ILL, "DEC on an IMM"); + } + + if (p1->mem) { + _except(ctx, E_IMP, "Memory access"); + } + + ctx->r[p1->val].val--; +} + +void i_mov(ctx_t *ctx, acc_t *p1, acc_t *p2) +{ + if (p1->type != A_REG) { + _except(ctx, E_ILL, "MOV into IMM"); + } + + if (p1->mem || p2->mem) { + _except(ctx, E_IMP, "Memory access"); + } + + ctx->r[p1->val].val = p2->type >= A_IMM16 ? p2->val + : ctx->r[p2->val].val; +} + +void i_xchg(ctx_t *ctx, acc_t *p1, acc_t *p2) +{ + if (p1->type != A_REG || p2->type != A_REG) { + _except(ctx, E_ILL, "XCHG of IMM(s)"); + } + + if (p1->mem || p2->mem) { + _except(ctx, E_IMP, "Memory access"); + } + + ulong temp = ctx->r[p1->val].val; + ctx->r[p1->val].val = ctx->r[p2->val].val; + ctx->r[p2->val].val = temp; +} + +instr_t arch_i[NINSTRS] = +{ + [I_ADD] = { "ADD", 2, i_add }, + [I_SUB] = { "SUB", 2, i_sub }, + [I_MUL] = { "MUL", 1, i_mul }, + [I_DIV] = { "DIV", 1, i_div }, + [I_INC] = { "INC", 1, i_inc }, + [I_DEC] = { "DEC", 1, i_dec }, + [I_MOV] = { "MOV", 2, i_mov }, + [I_XCHG] = { "XCHG", 2, i_xchg }, +}; + diff --git a/main.c b/main.c new file mode 100644 index 0000000..d7debbd --- /dev/null +++ b/main.c @@ -0,0 +1,48 @@ +// The OS/K Team licences this file to you under the MIT license. +// See the LICENCE file in the project root for more information. + +#include "arch.h" + +ushort prog[] = { + I_ADD, RDX, A_IMM32, 0xAABB, 0xCCDD, + I_MOV, RAX, RDX, + I_MOV, RBX, A_IMM64, 0x7777, 0x6666, 0x5555, 0x4444, + I_SUB, RDX, A_IMM16, 0xCCDD, + I_MOV, RBP, A_IMM16, 0x0010, + I_MUL, A_IMM64, 0xFFFF,0xFFFF,0xFFFF,0xFFFF, + I_ADD, RAX, A_IMM32, 0xAABB, 0xCCDD, +}; + +ushort bget(ctx_t *ctx) +{ + static int i = 0; + + if (i >= sizeof(prog)/sizeof(ushort)) { + _except(ctx, E_ACC, "End of text"); + } + + return prog[i++]; +} + +extern reg_t arch_r[NREGS]; +extern instr_t arch_i[NINSTRS]; + +int main(void) +{ + static ctx_t main_ctx; + + main_ctx.r = arch_r; + main_ctx.i = arch_i; + + main_ctx.mp = 0; + main_ctx.mz = 0; + + main_ctx.get = bget; + + while (1) { + decode(&main_ctx); + } + + return 0; +} + diff --git a/regs.c b/regs.c new file mode 100644 index 0000000..9c5082f --- /dev/null +++ b/regs.c @@ -0,0 +1,43 @@ +// The OS/K Team licences this file to you under the MIT license. +// See the LICENCE file in the project root for more information. + +#include "arch.h" + +reg_t arch_r[NREGS] = +{ + { "RAX", "Accumulator 0", 0, GPR }, + { "RBX", "Accumulator 1", 0, GPR }, + { "RCX", "Accumulator 2", 0, GPR }, + { "RDX", "Accumulator 3", 0, GPR }, + { "RDI", "Accumulator 4", 0, GPR }, + { "RSI", "Accumulator 5", 0, GPR }, + { "RBP", "Stack base", 0, GPR }, + { "RSP", "Stack pointer", 0, GPR }, + { "R08", "Accumulator 8", 0, GPR }, + { "R09", "Accumulator 9", 0, GPR }, + { "R10", "Accumulator 10", 0, GPR }, + { "R11", "Accumulator 11", 0, GPR }, + { "R12", "Accumulator 12", 0, GPR }, + { "R13", "Accumulator 13", 0, GPR }, + { "R14", "Accumulator 14", 0, GPR }, + { "R15", "Accumulator 15", 0, GPR }, + { "K00", "Supervisor accumulator 0", 0, SYS }, + { "K01", "Supervisor accumulator 1", 0, SYS }, + { "K02", "Supervisor accumulator 2", 0, SYS }, + { "K03", "Supervisor accumulator 3", 0, SYS }, + { "K04", "Supervisor accumulator 4", 0, SYS }, + { "K05", "Supervisor accumulator 5", 0, SYS }, + { "K06", "Supervisor accumulator 6", 0, SYS }, + { "K07", "Supervisor accumulator 7", 0, SYS }, + { "CR0", "Control register 0", 0, CTL }, + { "CR1", "Control register 1", 0, CTL }, + { "CR2", "Control register 2", 0, CTL }, + { "CR3", "Control register 3", 0, CTL }, + { "CR4", "Control register 4", 0, CTL }, + { "CR5", "Control register 5", 0, CTL }, + { "CR6", "Control register 6", 0, CTL }, + { "CR7", "Control register 7", 0, CTL }, + { "RIP", "Instruction pointer", 0, RES }, + { "RFG", "Flags register", 0, RES }, +}; +