diff --git a/Makefile b/Makefile index bf0317b..7b972f5 100644 --- a/Makefile +++ b/Makefile @@ -5,16 +5,18 @@ all: kas kpc: @cd pc && make --no-print-directory + @mv pc/k.exe out/k.exe kas: kpc as/k-as.py as/regs.lst @cp pc/instrs/instrs.lst as @rm -f pc/instrs/instrs.lst -asm: os/dos.k - @cd os && ../as/k-as.py dos.k 0x100000 a.out +asm: dos/dos.k dos/print.k + @as/k-as.py dos/dos.k 0x100000 out/a.out test: kas asm - @pc/k.exe os/a.out > os/stdout.txt + @out/k.exe out/a.out > out/stdout.txt disasm: kas asm - @pc/k.exe os/a.out -d + @out/k.exe os/a.out -d + @mv fwprog.dis out diff --git a/as/k-as.py b/as/k-as.py index 786dc62..11b6e9f 100755 --- a/as/k-as.py +++ b/as/k-as.py @@ -14,24 +14,26 @@ if len(sys.argv) != 4: .format(sys.argv[0])) sys.exit(1) -instrs = open(".{}.instr".format(sys.argv[3]), "w+") -b_data = open(".{}.data".format(sys.argv[3]), "w+b") -b_text = open(".{}.text".format(sys.argv[3]), "w+b") +source = TemporaryFile(mode="w+") +instrs = TemporaryFile(mode="w+") +b_data = TemporaryFile(mode="w+b") +b_text = TemporaryFile(mode="w+b") lst_regs = open(os.path.join(sys.path[0], "regs.lst")) lst_instrs = open(os.path.join(sys.path[0], "instrs.lst")) -fi = open(sys.argv[1]) +main_src = open(sys.argv[1]) b_out = open(sys.argv[3], "wb") start_addr = int(sys.argv[2], base=0) def leave(): - fi.close() + source.close() instrs.close() b_out.close() b_data.close() b_text.close() + main_src.close() lst_regs.close() lst_instrs.close() @@ -95,88 +97,51 @@ def parse_lst_instrs(): #------------------------------------------------------------------------------- -def parse_preproc(line): - global pdata +inc_depth = 0 +inc_depth_max = 16 - tok = line.split(' ', 2) +# Quickly goes through source file and resolves "include" directives ONLY +def do_includes(fi): + global inc_depth + for _, line in enumerate(fi): + line = line.rstrip() + tok = line.split(' ', 1) - #for word in tok: - # if not name_valid(word): - # print("Invalid token in line: {}".format(line)) - # return + if len(tok) == 0: + continue - # preprocessor - if len(tok) > 1 and tok[1] == ':=': - if len(tok) < 3: - print("Invalid format: {}".format(line)) - leave() - sys.exit(1) - pdefs[tok[0]] = tok[2] - return - - # .data - if len(tok) > 1 and tok[1] == '=': - if len(tok) < 3: - print("Invalid format: {}".format(line)) - leave() - sys.exit(1) + if tok[0] == "include": + if len(tok) == 1: + print("Missing parameter for include directive") + leave() + sys.exit(1) - if is_number(tok[2]): - plabels_data[tok[0]] = pdata - written = b_data.write(int(tok[2], base=0).to_bytes(8, byteorder='little', signed=False)) - assert(written == 8) - pdata += written + if tok[1][0] not in "'\"" or tok[1][-1] != tok[1][0]: + print("Invalid format for include directive: {}".format(line)) + leave() + sys.exit(1) - elif tok[2][0] in "'\"": - s = tok[2].strip() - assert(s[-1] == tok[2][0]) - - s = s[1:-1] + inc = tok[1][1:-1] - plabels_data[tok[0]] = pdata + try: + new_fi = open(inc, "r") - real_len = 0 - escaping = False + except: + print("Couldn't open file: {}".format(line)) + leave() + sys.exit(1) - for c in s: - # escape sequences - if c == '\\': - escaping = True - continue + inc_depth += 1 + if inc_depth >= inc_depth_max: + print("Maximal include depth reached: {}".format(line)) + leave() + sys.exit(1) - if escaping: - escaping = False - - if c == 'n': - c = '\n' - elif c == 't': - c = '\t' - else: - print("Unrecognized escape sequence: {}".format(line)) - leave() - sys.exit(1) - - written = b_data.write(ord(c).to_bytes(1, byteorder='little', signed=False)) - assert(written == 1) - real_len += 1 - pdata += 1 - - # align - for i in range(8 - len(s) % 8): - written = b_data.write(int(0).to_bytes(1, byteorder='little', signed=False)) - assert(written == 1) - pdata += 1 - - pdefs[tok[0] + "_len"] = str(real_len) + do_includes(new_fi) else: - print("Invalid format: {}".format(line)) - leave() - sys.exit(1) + source.write("{}\n".format(line)) - return - - print("Unrecognized directive: {}".format(line)) #------------------------------------------------------------------------------- @@ -184,7 +149,10 @@ def parse(): global ptext global plastlabel - for count, line in enumerate(fi): + source.seek(0) + + for count, line in enumerate(source): + print(line) line = line.rstrip() if len(line) == 0: @@ -204,7 +172,7 @@ def parse(): instrs.write("\n") continue - + # Preprocessor or label? if line[-1] == ':': if name_valid(line[:-1]): @@ -219,18 +187,103 @@ def parse(): leave() sys.exit(1) continue - + # Preprocessor, .data, or invalid parse_preproc(line) #------------------------------------------------------------------------------- - + +def parse_preproc(line): + global pdata + + tok = line.split(' ', 2) + + #for word in tok: + # if not name_valid(word): + # print("Invalid token in line: {}".format(line)) + # return + + # preprocessor + if len(tok) > 1 and tok[1] == ':=': + if len(tok) < 3: + print("Invalid format: {}".format(line)) + leave() + sys.exit(1) + pdefs[tok[0]] = tok[2] + return + + # .data + if len(tok) > 1 and tok[1] == '=': + if len(tok) < 3: + print("Invalid format: {}".format(line)) + leave() + sys.exit(1) + + if is_number(tok[2]): + plabels_data[tok[0]] = pdata + written = b_data.write(int(tok[2], base=0).to_bytes(8, byteorder='little', signed=False)) + assert(written == 8) + pdata += written + + elif tok[2][0] in "'\"": + s = tok[2].strip() + assert(s[-1] == tok[2][0]) + + s = s[1:-1] + + plabels_data[tok[0]] = pdata + + real_len = 0 + escaping = False + + for c in s: + # escape sequences + if c == '\\': + escaping = True + continue + + if escaping: + escaping = False + + if c == 'n': + c = '\n' + elif c == 't': + c = '\t' + else: + print("Unrecognized escape sequence: {}".format(line)) + leave() + sys.exit(1) + + written = b_data.write(ord(c).to_bytes(1, byteorder='little', signed=False)) + assert(written == 1) + real_len += 1 + pdata += 1 + + # align + for i in range(8 - len(s) % 8): + written = b_data.write(int(0).to_bytes(1, byteorder='little', signed=False)) + assert(written == 1) + pdata += 1 + + pdefs[tok[0] + "_len"] = str(real_len) + + else: + print("Invalid format: {}".format(line)) + leave() + sys.exit(1) + + return + + print("Unrecognized directive: {}".format(line)) + +#------------------------------------------------------------------------------- + def parse_instr(line): if line == None or len(line) == 0: return 0 tok = line.split(' ', 1) - + instr = tok[0].strip() if len(tok) > 1: @@ -251,7 +304,7 @@ def parse_instr(line): instrs.write("%rep ") instr, params = params.split(' ', 1) size += 2 - + instr_name = instr instr_args = '' @@ -304,17 +357,17 @@ def parse_instr(line): # +2 for A_OFF, +2 for offset, +2 for register size += 2 + 2 + 2 instr_args += "off " - + assert(len(word) > 3) - + reg, off = word.split('+', 1) reg = reg.strip() off = off.strip() - + instr_args += "{} {}".format(off, reg) continue - + else: # +2 for A_MEM size += 2 @@ -347,17 +400,17 @@ def parse_instr(line): instr_args += word fellthrough = False continue - + # it's a label (a 64-bit immediate) # +2 for A_IMM64, +8 for immediate size += 2 + 8 if not fellthrough: instr_name += "_i" instr_args += "%imm64 " - + if word[0] == '.': instr_args += plastlabel - + instr_args += word fellthrough = False @@ -371,16 +424,16 @@ special_syms = { "%wmem": 0x7002, "%lmem": 0x7004, "%qmem": 0x7008, - + "%boff": 0x7701, "%woff": 0x7702, "%loff": 0x7704, "%qoff": 0x7708, - + "%imm16": 0x7772, "%imm32": 0x7774, "%imm64": 0x7778, - + "%rep": 0x8000 } @@ -392,7 +445,7 @@ def gentext(): for _, line in enumerate(instrs): tok = line.strip().split(' ') - + for word in tok: if word in pregs: idx = pregs.index(word) @@ -421,7 +474,7 @@ def gentext(): lastimm = 4 elif word == "%imm64": lastimm = 8 - + if word[2:] == "off" and word[0] == '%': lastimm = 2 isSigned = True @@ -430,7 +483,7 @@ def gentext(): b_text.write(special_syms[word].to_bytes(2, byteorder='little', signed=isSigned)) continue - + if is_number(word): if word[0] == '-': isSigned = True @@ -438,7 +491,7 @@ def gentext(): isSigned = False b_text.write(int(word, base=0).to_bytes(lastimm, byteorder='little', signed=isSigned)) continue - + print("Assembly error, unknown token '{}' in line: {}".format(word, line)) leave() sys.exit(1) @@ -451,7 +504,7 @@ def genout(): b_out.write(b_text.read()) data_align = (8 - ptext % 8) - + for i in range(data_align): b_out.write(int(0).to_bytes(1, byteorder='little', signed=False)) @@ -461,6 +514,7 @@ def genout(): parse_lst_instrs() parse_lst_regs() +do_includes(main_src) parse() gentext() genout() diff --git a/dos/dos.k b/dos/dos.k new file mode 100644 index 0000000..508e945 --- /dev/null +++ b/dos/dos.k @@ -0,0 +1,20 @@ +; The OS/K Team licences this file to you under the MIT license. +; See the LICENSE file in the project root for more information. + +hw = "Hello World\n:)" + +; +; Entry point +; +main: + ; Initializes the stack + mov rbp, 0x200000 + mov rsp, rbp + + mov ax0, hw + call print + + stop + +include "dos/print.k" + diff --git a/os/dos.k b/dos/print.k similarity index 72% rename from os/dos.k rename to dos/print.k index e36f033..dc39cc8 100644 --- a/os/dos.k +++ b/dos/print.k @@ -1,21 +1,6 @@ ; The OS/K Team licences this file to you under the MIT license. ; See the LICENSE file in the project root for more information. -hw = "Hello World\n:)" - -; -; Entry point -; -main: - ; Initializes the stack - mov rbp, 0x200000 - mov rsp, rbp - - mov ax0, hw - call print - - stop - ; ; Max amount of characters that print() will print ; @@ -44,7 +29,7 @@ print: ; print_n: enter - mov rcx, ax1 ; text + mov rcx, ax1 .1: prn b[ax0] diff --git a/out/.placeholder b/out/.placeholder new file mode 100644 index 0000000..e69de29 diff --git a/pc/arch.h b/pc/arch.h index 1b93fba..25aa86c 100644 --- a/pc/arch.h +++ b/pc/arch.h @@ -98,7 +98,7 @@ struct ctx_t // Read next instruction ushort (*get)(ctx_t *ctx); - + // For disassembly FILE *disf; };