1
0
mirror of https://gitlab.os-k.eu/os-k-team/kvisc.git synced 2023-08-25 14:05:46 +02:00
This commit is contained in:
julianb0 2019-05-22 18:39:46 +02:00
parent b5a9286ce0
commit 8e50810bf7
No known key found for this signature in database
GPG Key ID: DDF8325C95299A62
13 changed files with 374 additions and 98 deletions

3
.gitignore vendored
View File

@ -2,9 +2,8 @@
*.out
*.bin
*.o
test*
arch_i.h
*.dis
instrs.lst
*.out.*
*.out*

View File

@ -10,6 +10,7 @@ kpc:
kas: kpc as/k-as.py as/regs.lst as/testfile.asm
@cp pc/instrs.lst as
test:
test: kas
@cd as && ./k-as.py testfile.asm 0x100000 testout.out
@pc/k.exe as/testout.out

View File

@ -4,6 +4,7 @@
# See the LICENSE file in the project root for more information.
import sys
import subprocess
from array import array
from tempfile import TemporaryFile
@ -22,14 +23,14 @@ lst_regs = open("regs.lst")
lst_instrs = open("instrs.lst")
fi = open(sys.argv[1])
out = open(sys.argv[3], "wb")
b_out = open(sys.argv[3], "wb")
start_addr = int(sys.argv[2], base=0)
def leave():
fi.close()
out.close()
instrs.close()
b_out.close()
b_data.close()
b_text.close()
lst_regs.close()
@ -185,6 +186,8 @@ def parse():
plabels_text[line[:-1]] = ptext
else:
print("Bad label name: {}".format(line[:-1]))
leave()
sys.exit(1)
continue
# Preprocessor, .data, or invalid
@ -203,72 +206,125 @@ def is_number(s):
def parse_instr(line):
tok = line.split(' ')
instrs.write(tok[0])
fellthrough = False
instr_name = tok[0]
instr_args = ''
if len(tok) == 1:
instrs.write("{}".format(instr_name))
return 2 # instruction
size = 2
for word in line.split(' ')[1:]:
instrs.write(' ')
instr_args += ' '
pref = None
# memory length prefixes
if len(word) > 1 and word[1] == '[':
if word[0] == 'b':
pref = "%b"
elif word[0] == 'w':
pref = "%w"
elif word[0] == 'l':
pref = "%l"
elif word[0] == 'q':
pref = "%q"
else:
print("Bad memory length prefix")
leave()
sys.exit(1)
word = word[1:]
# [reg+off] or [imm64]
if word[0] == '[':
assert(word[-1] == ']')
word = word[1:-1]
if pref == None:
pref = "%q"
instr_name += "_m"
instr_args += "{}".format(pref)
if '+' in word:
# +2 for A_OFF, +2 for offset, +2 for register
size += 2 + 2 + 2
instrs.write("%off ")
instr_args += "off "
assert(len(word) > 3)
assert(word[2] == '+' or word[3] == '+')
if word[2] == '+':
# r8, k0, etc
instrs.write("{} {}".format(word[3:], word[:2]))
instr_args += "{} {}".format(word[3:], word[:2])
else:
# rax, cr0, etc
instrs.write("{} {}".format(word[4:], word[:3]))
instr_args += "{} {}".format(word[4:], word[:3])
continue
else:
# +2 for A_MEM
size += 2
instrs.write("%mem ")
instr_args += "mem "
fellthrough = True
# FALLTHROUGH
# for now every immediate is 64-bit
if is_number(word):
# +2 for A_IMM64, +8 for immediate
size += 2 + 8
instrs.write("%imm64 ")
instrs.write(word)
if not fellthrough:
instr_name += "_i"
instr_args += "%imm64 "
instr_args += word
fellthrough = False
continue
if word in pregs:
size += 2
instrs.write(word)
if not fellthrough:
instr_name += "_r"
instr_args += word
fellthrough = False
continue
# it's a label (so a 16-bit immediate for now)
# it's a label (a 64-bit immediate)
# +2 for A_IMM16, +2 for immediate
size += 2 + 2
instrs.write("%imm16 ")
instrs.write(word)
size += 2 + 8
if not fellthrough:
instr_name += "_i"
instr_args += "%imm64 "
instr_args += word
fellthrough = False
instrs.write("{}{}".format(instr_name, instr_args))
return size
#-------------------------------------------------------------------------------
def gentext():
# offset in memory
off = start_addr
special_syms = {
"%bmem": 0x7001,
"%wmem": 0x7002,
"%lmem": 0x7004,
"%qmem": 0x7008,
"%boff": 0x7701,
"%woff": 0x7702,
"%loff": 0x7704,
"%qoff": 0x7708,
"%imm16": 0x7772,
"%imm32": 0x7774,
"%imm64": 0x7778,
}
def gentext():
instrs.seek(0)
text_start = 0x100000
for _, line in enumerate(instrs):
tok = line.strip().split(' ')
@ -285,19 +341,28 @@ def gentext():
continue
if word in plabels_text:
addr = plabels_text[word]
b_text.write(addr.to_bytes(2, byteorder='little', signed=False))
addr = text_start + plabels_text[word]
print(addr.to_bytes(8, byteorder='big', signed=False))
b_text.write(addr.to_bytes(8, byteorder='big', signed=False))
continue
if word in plabels_data:
addr = plabels_data[word] + ptext + pdata_pad
b_text.write(addr.to_bytes(2, byteorder='little', signed=False))
addr = text_start + plabels_data[word] + ptext + pdata_pad
b_text.write(addr.to_bytes(8, byteorder='little', signed=False))
continue
if 0:
if word in special_syms:
if word == "%imm16":
lastimm = 2
elif word == "%imm32":
lastimm = 4
elif word == "%imm64":
lastimm = 8
b_text.write(special_syms[word].to_bytes(2, byteorder='little', signed=False))
continue
if is_number(word):
b_text.write(int(word, base=0).to_bytes(lastimm, byteorder='little', signed=False))
continue
print("Assembly error, unknown token '{}' in line: {}".format(word, line))
@ -306,10 +371,18 @@ def gentext():
#-------------------------------------------------------------------------------
def genout():
b_text.seek(0)
b_data.seek(0)
b_out.write(b_text.read())
b_out.write(b_data.read())
#-------------------------------------------------------------------------------
parse_lst_instrs()
parse_lst_regs()
parse()
gentext()
#genout()
genout()
leave()

View File

@ -1,3 +1,4 @@
inv
rax
rbx
rcx

13
as/testfile.asm Normal file
View File

@ -0,0 +1,13 @@
# Test assembly file
# Wololo!
def y 4
label1:
call label2
stop
label2:
add rax, 1
ret

View File

@ -1,6 +1,7 @@
# The OS/K Team licences this file to you under the MIT license.
# See the LICENSE file in the project root for more information.
stop
nop
#
@ -181,5 +182,4 @@ popf
cli
sti
stop

View File

@ -3,7 +3,7 @@
all: k.exe
src = instrs.c decd.c main.c regs.c dump.c jumps.c except.c disdec.c
src = instrs.c decd.c main.c regs.c dump.c jumps.c except.c disdec.c mem.c
obj = $(patsubst %.c,%.o,$(src))
@ -20,5 +20,6 @@ clean:
k.exe: $(obj) i_arch.h INSTRS instrs.py
@gcc -O2 -Wall $(obj) -o k.exe
@rm arch_i.h
@rm *.o

View File

@ -28,6 +28,7 @@ typedef struct arch_t arch_t;
enum
{
INV,
RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP,
R8, R9, R10, R11, R12, R13, R14, R15,
K0, K1, K2, K3, K4, K5, K6, K7,
@ -72,12 +73,40 @@ struct reg_t
// A_REG is implicit
// A_MEM denotes a memory access
// A_OFF is A_MEM but a 16-bit offset is expected immediatly next
enum { A_REG=0, A_MEM=0x7000, A_OFF, A_IMM16, A_IMM32, A_IMM64 };
enum
{
A_REG = 0,
A_MEM8 = 0x7001,
A_MEM16 = 0x7002,
A_MEM32 = 0x7004,
A_MEM64 = 0x7008,
A_OFF8 = 0x7701,
A_OFF16 = 0x7702,
A_OFF32 = 0x7704,
A_OFF64 = 0x7708,
A_IMM16 = 0x7772,
A_IMM32 = 0x7774,
A_IMM64 = 0x7778
};
#define A_IS_MEM(x) ((x) >= A_MEM8 && (x) <= A_MEM64)
#define A_IS_OFF(x) ((x) >= A_OFF8 && (x) <= A_OFF64)
#define A_IS_IMM(x) ((x) >= A_IMM16)
#define A_IS_8(x) ((x) & 0xF == 1)
#define A_IS_16(x) ((x) & 0xF == 2)
#define A_IS_32(x) ((x) & 0xF == 3)
#define A_IS_64(x) ((x) & 0xF == 4)
struct acc_t
{
bool mem; // A_MEM?
bool mem;
uint len;
uint type;
ulong val;
short off;
};
@ -141,49 +170,23 @@ void decode(ctx_t *ctx);
#define MEMOFF (1 * 1024 * 1024)
#define MEMSIZE (16 * 1024 * 1024) // 16MB
#define addr2real(p) ((p) - MEMOFF)
#define real2addr(p) ((p) + MEMOFF)
#define addr2real(p) (((p) - MEMOFF) / 2)
#define real2addr(p) (((p) + MEMOFF) / 2)
// Address of boot firmware stack
#define FWSTACK (MEMOFF * 2) // 2MB
static inline ulong readmem64(ctx_t *ctx, ulong addr)
{
ulong real = addr2real(addr);
ulong readmem8(ctx_t *, ulong addr);
ulong readmem16(ctx_t *, ulong addr);
ulong readmem32(ctx_t *, ulong addr);
ulong readmem64(ctx_t *, ulong addr);
ulong readmem(ctx_t *c, ulong addr, uint len);
if (addr % alignof(ulong) > 0) {
_except(ctx, E_ALI, "Non-aligned memory access: 0x%012lX(0x%012lX)", addr, real);
}
if (addr < MEMOFF || real >= MEMSIZE) {
_except(ctx, E_ACC, "Invalid MEM access: 0x%012lX(0x%012lX)", addr, real);
}
ulong val = (ulong)ctx->mp[real++];
val = (val << 16) | (ulong)ctx->mp[real++];
val = (val << 16) | (ulong)ctx->mp[real++];
val = (val << 16) | (ulong)ctx->mp[real++];
return val;
}
static inline void writemem64(ctx_t *ctx, ulong val, ulong addr)
{
ulong real = addr2real(addr);
if (addr % alignof(ulong) > 0) {
_except(ctx, E_ALI, "Non-aligned memory access: 0x%012lX(0x%012lX)", addr, real);
}
if (addr < MEMOFF || real >= MEMSIZE) {
_except(ctx, E_ACC, "Invalid MEM access: 0x%012lX(0x%012lX)", addr, real);
}
ctx->mp[real++] = val >> 48;
ctx->mp[real++] = (val >> 32) & 0xFFFF;
ctx->mp[real++] = (val >> 16) & 0xFFFF;
ctx->mp[real++] = val & 0xFFFF;
}
void writemem8(ctx_t *, ulong val, ulong addr);
void writemem16(ctx_t *, ulong val, ulong addr);
void writemem32(ctx_t *, ulong val, ulong addr);
void writemem64(ctx_t *, ulong val, ulong addr);
void writemem(ctx_t *, ulong val, ulong addr, uint len);
#include "arch_i.h"

View File

@ -33,14 +33,16 @@ static void scan_param(ctx_t *ctx, acc_t *p)
c = ctx->get(ctx);
if (c == A_MEM) {
if (A_IS_MEM(c)) {
p->mem = 1;
p->off = 0;
p->len = c & 0xF;
c = ctx->get(ctx);
}
else if (c == A_OFF) {
else if (A_IS_OFF(c)) {
p->mem = 1;
p->len = c & 0xF;
p->off = (short)ctx->get(ctx);
c = ctx->get(ctx);
}
@ -74,7 +76,7 @@ static void scan_param(ctx_t *ctx, acc_t *p)
r = &ctx->r[p->val];
if (r->flags & (RES | CTL)) {
_except(ctx, E_ACC, "Reserved REG");
_except(ctx, E_ACC, "Reserved REG: %s", r->name);
}
}
}
@ -96,7 +98,7 @@ void disasm(ctx_t *ctx)
}
else if (!ISINSTR(c)) {
_except(ctx, E_ILL, "Bad opcode: 0x%4hX", c);
_except(ctx, E_ILL, "Bad opcode: 0x%04hX", c);
}
i = &ctx->i[c];

View File

@ -11,27 +11,27 @@ void i_##name(ctx_t *ctx, acc_t *p1, acc_t *p2) \
void i_##name(ctx_t *ctx, acc_t *p1, acc_t *p2) \
{ \
ulong v1 = (p1->type == A_REG ? ctx->r[p1->val].val : p1->val); \
if (p1->mem) v1 = readmem64(ctx, v1 + p1->off); \
if (p1->mem) v1 = readmem(ctx, v1 + p1->off, p1->len); \
#define IMPL_START_2(name) \
void i_##name(ctx_t *ctx, acc_t *p1, acc_t *p2) \
{ \
ulong v1 = (p1->type == A_REG ? ctx->r[p1->val].val : p1->val); \
ulong v2 = (p2->type == A_REG ? ctx->r[p2->val].val : p2->val); \
if (p1->mem) v1 = readmem64(ctx, v1 + p1->off); \
if (p2->mem) v2 = readmem64(ctx, v2 + p2->off); \
if (p1->mem) v1 = readmem(ctx, v1 + p1->off, p1->len); \
if (p2->mem) v2 = readmem(ctx, v2 + p2->off, p2->len); \
#define IMPL_START_3(name) \
void i_##name(ctx_t *ctx, acc_t *p1, acc_t *p2) \
{ \
ulong v2 = (p2->type == A_REG ? ctx->r[p2->val].val : p2->val); \
if (p2->mem) v2 = readmem64(ctx, v2 + p2->off); \
if (p2->mem) v2 = readmem(ctx, v2 + p2->off, p2->len); \
#define IMPL_OUT \
assert(p1->type == A_REG || p1->mem); \
if (p1->mem) { \
ulong addr = p1->type == A_REG ? ctx->r[p1->val].val : p1->val; \
writemem64(ctx, v1, addr); \
writemem(ctx, v1, addr, p1->len); \
} \
else ctx->r[p1->val].val = v1; \
} \

View File

@ -3,21 +3,17 @@
#include "arch.h"
// Boot firware, loaded at MEMOFF (1MB)
ushort fwprog[] = {
I_MOV_R_I, RBP, A_IMM32, FWSTACK>>16, FWSTACK&0xFF,
I_MOV_R_I, RSP, A_IMM32, FWSTACK>>16, FWSTACK&0xFF,
I_CALL_I, A_IMM32, (MEMOFF+0x13)>>16, (MEMOFF+0x13)&0xFF,
I_ADD_R_I, RAX, A_IMM16, 1,
I_STOP,
I_ADD_R_I, RBX, A_IMM16, 1,
I_RET,
};
#define FWPROGSIZE (1024 * 1024 * 1024)
static ssize_t fwsize;
static ushort *fwprog;
ushort bget(ctx_t *ctx)
{
if (ctx->r[RIP].val % 2) {
_except(ctx, E_ALI, "Misaligned RIP register: 0x%016lX",
ctx->r[RIP].val);
}
if (addr2real(ctx->r[RIP].val) >= ctx->mz) {
_except(ctx, E_ACC, "Executing out of memory: 0x%016lX",
ctx->r[RIP].val);
@ -25,7 +21,7 @@ ushort bget(ctx_t *ctx)
ushort c = ctx->mp[addr2real(ctx->r[RIP].val)];
ctx->r[RIP].val++;
ctx->r[RIP].val += 2;
return c;
}
@ -34,7 +30,7 @@ ushort dget(ctx_t *ctx)
{
static int i = 0;
if (i >= sizeof(fwprog)/2) {
if (i >= fwsize) {
log("Finished disassembling\n");
fclose(ctx->disf);
exit(0);
@ -50,13 +46,40 @@ extern instr_t arch_i[NINSTRS];
int main(int argc, char **argv)
{
ctx_t main_ctx;
FILE *fwfile;
main_ctx.r = arch_r;
main_ctx.i = arch_i;
// Execute firmware
if (!(argc > 1 && !strcmp(argv[1], "-d"))) {
main_ctx.mp = malloc(MEMSIZE);
if (argc < 2) {
log("Not enough arguments\n");
exit(-3);
}
fwprog = malloc(FWPROGSIZE);
fwfile = fopen(argv[1], "rb");
if (!fwprog) {
log("Couldn't allocate firmware buffer\n");
exit(-1);
}
if (!fwfile) {
log("Couldn't open program file\n");
exit(-2);
}
fwsize = fread(fwprog, 1, FWPROGSIZE, fwfile);
//log("Loaded %lu bytes
if (fwsize < 2) {
log("Error while reading program file\n");
exit(-3);
}
if (!(argc > 2 && !strcmp(argv[2], "-d"))) {
main_ctx.mp = malloc(MEMSIZE + 16);
main_ctx.mz = MEMSIZE;
main_ctx.get = bget;
@ -69,7 +92,7 @@ int main(int argc, char **argv)
exit(-1);
}
memcpy(&main_ctx.mp[addr2real(main_ctx.r[RIP].val)], fwprog, sizeof(fwprog));
memcpy(&main_ctx.mp[addr2real(main_ctx.r[RIP].val)], fwprog, fwsize);
while (1) {
decode(&main_ctx);

159
pc/mem.c Normal file
View File

@ -0,0 +1,159 @@
// The OS/K Team licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#include "arch.h"
ulong readmem(ctx_t *ctx, ulong addr, uint len)
{
switch (len) {
case 1: return readmem8(ctx, addr); break;
case 2: return readmem16(ctx, addr); break;
case 4: return readmem32(ctx, addr); break;
case 8: return readmem64(ctx, addr); break;
default: log("readmem() bad length!\n"); abort();
}
}
ulong readmem8(ctx_t *ctx, ulong addr)
{
ulong real = addr2real(addr);
if (addr < MEMOFF || real >= MEMSIZE) {
_except(ctx, E_ACC, "Invalid MEM access: 0x%012lX(0x%012lX)", addr, real);
}
if (addr % 2) return (ulong)ctx->mp[real] & 0xFF;
else return ((ulong)ctx->mp[real] & 0xFF00) >> 8;
}
ulong readmem16(ctx_t *ctx, ulong addr)
{
ulong real = addr2real(addr);
if (addr % alignof(ushort) > 0) {
_except(ctx, E_ALI, "Non-aligned memory access: 0x%012lX(0x%012lX)", addr, real);
}
if (addr < MEMOFF || real >= MEMSIZE) {
_except(ctx, E_ACC, "Invalid MEM access: 0x%012lX(0x%012lX)", addr, real);
}
return (ulong)ctx->mp[real];
}
ulong readmem32(ctx_t *ctx, ulong addr)
{
ulong real = addr2real(addr);
if (addr % alignof(uint) > 0) {
_except(ctx, E_ALI, "Non-aligned memory access: 0x%012lX(0x%012lX)", addr, real);
}
if (addr < MEMOFF || real >= MEMSIZE) {
_except(ctx, E_ACC, "Invalid MEM access: 0x%012lX(0x%012lX)", addr, real);
}
ulong val = (ulong)ctx->mp[real++];
val = (val << 16) | (ulong)ctx->mp[real];
return val;
}
ulong readmem64(ctx_t *ctx, ulong addr)
{
ulong real = addr2real(addr);
if (addr % alignof(ulong) > 0) {
_except(ctx, E_ALI, "Non-aligned memory access: 0x%012lX(0x%012lX)", addr, real);
}
if (addr < MEMOFF || real >= MEMSIZE) {
_except(ctx, E_ACC, "Invalid MEM access: 0x%012lX(0x%012lX)", addr, real);
}
ulong val = (ulong)ctx->mp[real++];
val = (val << 16) | (ulong)ctx->mp[real++];
val = (val << 16) | (ulong)ctx->mp[real++];
val = (val << 16) | (ulong)ctx->mp[real];
return val;
}
void writemem(ctx_t *ctx, ulong val, ulong addr, uint len)
{
switch (len) {
case 1: writemem8(ctx, val, addr); break;
case 2: writemem16(ctx, val, addr); break;
case 4: writemem32(ctx, val, addr); break;
case 8: writemem64(ctx, val, addr); break;
default: log("writemem() bad length!\n"); abort();
}
}
void writemem8(ctx_t *ctx, ulong val, ulong addr)
{
ulong real = addr2real(addr);
if (addr < MEMOFF || real >= MEMSIZE) {
_except(ctx, E_ACC, "Invalid MEM access: 0x%012lX(0x%012lX)", addr, real);
}
ushort v = ctx->mp[real];
if (addr % 2) {
ctx->mp[real] = (v & 0xFF00) | (val & 0xFF);
}
else {
ctx->mp[real] = (v & 0xFF) | (((val & 0xFF) << 8));
}
}
void writemem16(ctx_t *ctx, ulong val, ulong addr)
{
ulong real = addr2real(addr);
if (addr % alignof(ushort) > 0) {
_except(ctx, E_ALI, "Non-aligned memory access: 0x%012lX(0x%012lX)", addr, real);
}
if (addr < MEMOFF || real >= MEMSIZE) {
_except(ctx, E_ACC, "Invalid MEM access: 0x%012lX(0x%012lX)", addr, real);
}
ctx->mp[real] = val & 0xFFFF;
}
void writemem32(ctx_t *ctx, ulong val, ulong addr)
{
ulong real = addr2real(addr);
if (addr % alignof(uint) > 0) {
_except(ctx, E_ALI, "Non-aligned memory access: 0x%012lX(0x%012lX)", addr, real);
}
if (addr < MEMOFF || real >= MEMSIZE) {
_except(ctx, E_ACC, "Invalid MEM access: 0x%012lX(0x%012lX)", addr, real);
}
ctx->mp[real++] = (val >> 16) & 0xFFFF;
ctx->mp[real] = val & 0xFFFF;
}
void writemem64(ctx_t *ctx, ulong val, ulong addr)
{
ulong real = addr2real(addr);
if (addr % alignof(ulong) > 0) {
_except(ctx, E_ALI, "Non-aligned memory access: 0x%012lX(0x%012lX)", addr, real);
}
if (addr < MEMOFF || real >= MEMSIZE) {
_except(ctx, E_ACC, "Invalid MEM access: 0x%012lX(0x%012lX)", addr, real);
}
ctx->mp[real++] = val >> 48;
ctx->mp[real++] = (val >> 32) & 0xFFFF;
ctx->mp[real++] = (val >> 16) & 0xFFFF;
ctx->mp[real] = val & 0xFFFF;
}

View File

@ -5,6 +5,7 @@
reg_t arch_r[NREGS] =
{
{ "inv", "Invalid register", 0, RES },
{ "rax", "Accumulator 0", 0, GPR },
{ "rbx", "Accumulator 1", 0, GPR },
{ "rcx", "Accumulator 2", 0, GPR },