commit 0d8d680e5d37cebe6ad59eb5ddb386ed9198507e from: Onana Onana Xavier Manuel date: Fri Sep 25 17:11:51 2026 UTC Proper handling of mov r8, r8 and mov r8, imm8 commit - 9b4c94f07693bf4d51126899cbecf7ca5b3d904e commit + 0d8d680e5d37cebe6ad59eb5ddb386ed9198507e blob - 1133285b38617bb7472f5063ad4ee08c6cd06f2c blob + c13e3c987375f4d827f999dae8a63de533fce3b5 --- tools/6c +++ tools/6c @@ -221,6 +221,20 @@ function hexval(hex) return result end + +function bitval(b) + local dig = b:sub(3) + local len = #dig + local result = 0 + + for i = 1, len do + local b = dig:sub(i, i) + + result = result + b * (2 ^ (len - i)) + end + + return result +end ----------------------------------------------------------------------- -- Checking arguments and setting read and write file ----------------------------------------------------------------------- blob - 116e3a97da138a8770841c72c42d761751f72500 blob + 7ec0dac0f81122dc109dd6e9660fda89a89e952c --- tools/6l +++ tools/6l @@ -221,6 +221,20 @@ function hexval(hex) return result end + +function bitval(b) + local dig = b:sub(3) + local len = #dig + local result = 0 + + for i = 1, len do + local b = dig:sub(i, i) + + result = result + b * (2 ^ (len - i)) + end + + return result +end ----------------------------------------------------------------------- -- Checking arguments ----------------------------------------------------------------------- @@ -285,14 +299,17 @@ local ASM_LABEL = 1 local ASM_INSTRUCTION = 2 local ASM_R8 = 3 local ASM_IMM8 = 4 +local ASM_MEM8 = 5 local function operlyze(op, ret) if isregs8(op) == true then ret.opcount = 1 table.insert(ret.details, ASM_R8) + table.insert(ret.operands, op) elseif op.type == tk_type.integer then ret.opcount = 1 local val = intval(op.raw) + table.insert(ret.operands, op) if val < 256 then table.insert(ret.details, ASM_IMM8) @@ -302,9 +319,11 @@ local function operlyze(op, ret) elseif op.type == tk_type.hexadecimal then ret.opcount = 1 local val = hexval(op.raw) + table.insert(ret.operands, op) if val < 256 then table.insert(ret.details, ASM_IMM8) + table.insert(ret.operands, op) else perror("operand 1 of instruction on line " .. op.line .. " is too big!") end @@ -320,7 +339,8 @@ local function asmlyze(first) local ret = { type = ASM_INSTRUCTION, opcount = 0, - details = { } + details = { }, + operands = { } } local op1 = readhdr() @@ -333,6 +353,7 @@ local function asmlyze(first) local com = readhdr() if com.type == tk_type["\n"] then + ret.opcount = 1 return ret end @@ -344,6 +365,7 @@ local function asmlyze(first) operlyze(op2, ret) if ret.opcount == 0 then + ret.opcount = 2 return ret end @@ -352,24 +374,8 @@ local function asmlyze(first) return ret end - if com.type ~= tk_type[","] then - perror("missing comma next to second operand on line " .. op1.line) - end + perror("can only take up to 2 operands instructions. Line " .. first.line) - local op3 = readhdr() - operlyze(op3, ret) - - if ret.opcount == 0 then - return ret - end - - local nl = readhdr() - if nl.type == tk_type["\n"] then - return ret - end - - perror("can only take up to 3 operands instructions. Line " .. first.line) - else if first.type == tk_type.id then local col = readhdr() @@ -385,9 +391,71 @@ local function asmlyze(first) end end +local function instvaluate(inst) + local regmap = { + ["al"] = "000", ["ah"] = "100", ["bl"] = "011", ["bh"] = "111", + ["cl"] = "001", ["ch"] = "101", ["dl"] = "010", ["dh"] = "110" + } + + local ret = { + modrm = nil, + sib = nil + } + + local opcount = #inst.details + + if opcount == 0 then + return ret + elseif opcount == 1 then + -- amslyze caps it at 2 + else + if inst.details[1] == ASM_R8 and inst.details[2] == ASM_R8 then + local dstmap = regmap[gettokenkey(inst.operands[1])] + local srcmap = regmap[gettokenkey(inst.operands[2])] + ret.modrm = bitval("0b11" .. srcmap .. dstmap) + + return ret + elseif inst.details[1] == ASM_R8 and inst.details[2] == ASM_IMM8 then + local dstmap = regmap[gettokenkey(inst.operands[1])] + ret.modrm = bitval("0b11" .. "000" .. dstmap) + + return ret + end + end + + return nil +end + +local function writemov(inst, eval) + local opcount = #inst.details + + if opcount ~= 2 then + perror("mov takes 2 operands. Line " .. inst.operands[1].line) + end + + if inst.details[1] == ASM_R8 and inst.details[2] == ASM_R8 then + writeu8(dst, hexval("0h88")) + writeu8(dst, eval.modrm) + elseif inst.details[1] == ASM_R8 and inst.details[2] == ASM_IMM8 then + local ib = 0 + if inst.operands[2].type == tk_type.hexadecimal then + ib = hexval(inst.operands[2].raw) + elseif inst.operands[2].type == tk_type.integer then + ib = intval(inst.operands[2].raw) + else + perror("attempt to mov a non integer at line " .. inst.operands[2].line) + end + + writeu8(dst, hexval("0hC6")) + writeu8(dst, eval.modrm) + writeu8(dst, ib) + end +end + ----------------------------------------------------------------------- -- 1st pass (syntax check and symbol table) ----------------------------------------------------------------------- +local begin = src:seek("cur") while true do local hdr = readhdr() if hdr == nil then @@ -440,7 +508,54 @@ end ----------------------------------------------------------------------- -- 2nd pass binary generation ----------------------------------------------------------------------- +src:seek("set", begin) +parser.inasm = false +parser.insec = false +while true do + local hdr = readhdr() + if hdr == nil then + break + end + + if parser.inasm == true then + if hdr.type == tk_type["asm"] then + perror("illegal nested asm keyword at line " .. hdr.line .. " column " .. hdr.col) + elseif hdr.type == tk_type["}"] then + parser.inasm = false + else + if hdr.type ~= tk_type["\n"] then + local inst = asmlyze(hdr) + if inst.type == ASM_INSTRUCTION then + local eval = instvaluate(inst) + + if eval == nil then + perror("unknown instruction at line " .. hdr.line) + end + + if hdr.type == tk_type["mov"] then + writemov(inst, eval) + + elseif hdr.type == tk_type["ret"] then + writeu8(dst, hexval("0hC3")) -- Only near return + + elseif hdr.type == tk_type["hlt"] then + writeu8(dst, hexval("0hF4")) + + elseif hdr.type == tk_type["cli"] then + writeu8(dst, hexval("0hFA")) + end + end + end + end + else + if hdr.type == tk_type["asm"] then + parser.inasm = true + readhdr() -- Skip `{` + end + end +end + ----------------------------------------------------------------------- -- Closing files ----------------------------------------------------------------------- blob - 846d2fda3cde69a0ef32cbed3930c60c8c5bb3da blob + 520f91818c130587e79bd18473207a8f1a9b13b7 --- tools/boot.sc +++ tools/boot.sc @@ -1,7 +1,7 @@ asm { _start: - mov al, 0h10 - mov ah, 22 + mov al, ah + mov ah, 0hff ret main: hlt blob - 4fd03b00959bb3a8a3763042c0eddde8adaa01e0 blob + fad84b294e1de4a24ef667ced168e53218a52de1 --- tools/linker.lua +++ tools/linker.lua @@ -62,14 +62,17 @@ local ASM_LABEL = 1 local ASM_INSTRUCTION = 2 local ASM_R8 = 3 local ASM_IMM8 = 4 +local ASM_MEM8 = 5 local function operlyze(op, ret) if isregs8(op) == true then ret.opcount = 1 table.insert(ret.details, ASM_R8) + table.insert(ret.operands, op) elseif op.type == tk_type.integer then ret.opcount = 1 local val = intval(op.raw) + table.insert(ret.operands, op) if val < 256 then table.insert(ret.details, ASM_IMM8) @@ -79,9 +82,11 @@ local function operlyze(op, ret) elseif op.type == tk_type.hexadecimal then ret.opcount = 1 local val = hexval(op.raw) + table.insert(ret.operands, op) if val < 256 then table.insert(ret.details, ASM_IMM8) + table.insert(ret.operands, op) else perror("operand 1 of instruction on line " .. op.line .. " is too big!") end @@ -97,7 +102,8 @@ local function asmlyze(first) local ret = { type = ASM_INSTRUCTION, opcount = 0, - details = { } + details = { }, + operands = { } } local op1 = readhdr() @@ -110,6 +116,7 @@ local function asmlyze(first) local com = readhdr() if com.type == tk_type["\n"] then + ret.opcount = 1 return ret end @@ -121,6 +128,7 @@ local function asmlyze(first) operlyze(op2, ret) if ret.opcount == 0 then + ret.opcount = 2 return ret end @@ -129,24 +137,8 @@ local function asmlyze(first) return ret end - if com.type ~= tk_type[","] then - perror("missing comma next to second operand on line " .. op1.line) - end + perror("can only take up to 2 operands instructions. Line " .. first.line) - local op3 = readhdr() - operlyze(op3, ret) - - if ret.opcount == 0 then - return ret - end - - local nl = readhdr() - if nl.type == tk_type["\n"] then - return ret - end - - perror("can only take up to 3 operands instructions. Line " .. first.line) - else if first.type == tk_type.id then local col = readhdr() @@ -162,9 +154,72 @@ local function asmlyze(first) end end +-- formats instruction to be ready for opcode generation +local function instvaluate(inst) + local regmap = { + ["al"] = "000", ["ah"] = "100", ["bl"] = "011", ["bh"] = "111", + ["cl"] = "001", ["ch"] = "101", ["dl"] = "010", ["dh"] = "110" + } + + local ret = { + modrm = nil, + sib = nil + } + + local opcount = #inst.details + + if opcount == 0 then + return ret + elseif opcount == 1 then + -- amslyze caps it at 2 + else + if inst.details[1] == ASM_R8 and inst.details[2] == ASM_R8 then + local dstmap = regmap[gettokenkey(inst.operands[1])] + local srcmap = regmap[gettokenkey(inst.operands[2])] + ret.modrm = bitval("0b11" .. srcmap .. dstmap) + + return ret + elseif inst.details[1] == ASM_R8 and inst.details[2] == ASM_IMM8 then + local dstmap = regmap[gettokenkey(inst.operands[1])] + ret.modrm = bitval("0b11" .. "000" .. dstmap) + + return ret + end + end + + return nil +end + +local function writemov(inst, eval) + local opcount = #inst.details + + if opcount ~= 2 then + perror("mov takes 2 operands. Line " .. inst.operands[1].line) + end + + if inst.details[1] == ASM_R8 and inst.details[2] == ASM_R8 then + writeu8(dst, hexval("0h88")) + writeu8(dst, eval.modrm) + elseif inst.details[1] == ASM_R8 and inst.details[2] == ASM_IMM8 then + local ib = 0 + if inst.operands[2].type == tk_type.hexadecimal then + ib = hexval(inst.operands[2].raw) + elseif inst.operands[2].type == tk_type.integer then + ib = intval(inst.operands[2].raw) + else + perror("attempt to mov a non integer at line " .. inst.operands[2].line) + end + + writeu8(dst, hexval("0hC6")) + writeu8(dst, eval.modrm) + writeu8(dst, ib) + end +end + ----------------------------------------------------------------------- -- 1st pass (syntax check and symbol table) ----------------------------------------------------------------------- +local begin = src:seek("cur") while true do local hdr = readhdr() if hdr == nil then @@ -217,7 +272,54 @@ end ----------------------------------------------------------------------- -- 2nd pass binary generation ----------------------------------------------------------------------- +src:seek("set", begin) +parser.inasm = false +parser.insec = false +while true do + local hdr = readhdr() + if hdr == nil then + break + end + + if parser.inasm == true then + if hdr.type == tk_type["asm"] then + perror("illegal nested asm keyword at line " .. hdr.line .. " column " .. hdr.col) + elseif hdr.type == tk_type["}"] then + parser.inasm = false + else + if hdr.type ~= tk_type["\n"] then + local inst = asmlyze(hdr) + if inst.type == ASM_INSTRUCTION then + local eval = instvaluate(inst) + + if eval == nil then + perror("unknown instruction at line " .. hdr.line) + end + + if hdr.type == tk_type["mov"] then + writemov(inst, eval) + + elseif hdr.type == tk_type["ret"] then + writeu8(dst, hexval("0hC3")) -- Only near return + + elseif hdr.type == tk_type["hlt"] then + writeu8(dst, hexval("0hF4")) + + elseif hdr.type == tk_type["cli"] then + writeu8(dst, hexval("0hFA")) + end + end + end + end + else + if hdr.type == tk_type["asm"] then + parser.inasm = true + readhdr() -- Skip `{` + end + end +end + ----------------------------------------------------------------------- -- Closing files ----------------------------------------------------------------------- blob - cc7115c9a8b1920867e53e25cd21892a6d296e45 blob + bc25e9dd9309e97d87e1e27f7aad8fb16c655a3b --- tools/util.lua +++ tools/util.lua @@ -219,3 +219,17 @@ function hexval(hex) return result end + +function bitval(b) + local dig = b:sub(3) + local len = #dig + local result = 0 + + for i = 1, len do + local b = dig:sub(i, i) + + result = result + b * (2 ^ (len - i)) + end + + return result +end