Implement addition expressions, critical expressions, proper modrm

This commit is contained in:
Nero 2023-01-02 01:37:05 +00:00
parent 6f8a24927a
commit 61d3688581
1 changed files with 90 additions and 45 deletions

View File

@ -42,6 +42,7 @@ BEGIN {
modstr["dibp"]=3
modstr["si"]=4
modstr["di"]=5
modstr["bp"]=6
modstr["bx"]=7
# ALU operations
alu["add"]=0
@ -119,6 +120,7 @@ function err(str) {
}
# submit a assembling result to output
# set label of current line to off
# this outputs a listing line
function submit(off) {
if (of=="lst") printf("%04X %-18s %s\n", off, hex, $0)
if (of=="hex" && hex) printf("%s", hex)
@ -132,23 +134,61 @@ function submit(off) {
pos=pos+length(hex)/2
hex=""
}
# gets a symbol's values
function getsym(name) {
if (substr(name,1,1)=="0" || int(name)) {
return int(name)
# evaluate an expression
# globals set:
# ecrit: value known after first pass, 1=yes, 0=no
# eregs: concatenated list of registers that add to this expr (for modrm)
function expr(str) {
val=0
sign=1
ecrit=1
eregs=""
gsub(/-/, "+-", str)
split(str, ep,"+")
for (k in ep) {
if (substr(ep[k],1,1)=="-") {
gsub(/^-/, "", ep[k])
sign = -1
} else {
sign = 1
}
if (substr(ep[k],1,1)==".") ep[k] = plabel ep[k]
if (ep[k] in r8 || ep[k] in r16 || ep[k] in sreg) {
if (sign > 0) {
eregs=eregs ep[k]
} else {
err("Registers cannot be subtractive in expressions")
}
} else if (match(ep[k], /^[0-9]/)) {
if (match(ep[k], /h$/)) {
ep[i]="0x" ep[k]
}
val = val + sign*int(ep[k])
} else if (ep[k] in sym) {
val = val + sign*sym[ep[k]]
} else if (ep[k] in prevsym) {
val = val + sign*prevsym[ep[k]]
ecrit=0
} else {
err("Undefined label " ep[k])
ecrit=0
}
}
if (name in r8 || name in r16 || name in sreg) {
err("Register name " name " is not a valid immediate")
return 0
}
if (substr(name,1,1)==".") name = plabel name
if (name in prevsym) {
return prevsym[name]
} else if (name in sym) {
return sym[name]
}
return 0
return val
}
function imm(str) {
val = expr(str)
if (eregs) err("Registers not allowed here")
return val
}
function crit(str) {
val = imm(str)
if (!ecrit) err("Labels from below not allowed here")
return val
}
function push_byte(val) {
#print("; pushb " val)
if (val<0 || val>=256) err("Value " val " does not fit in byte")
@ -165,29 +205,27 @@ function push_word(val) {
}
# rs is the register set (r8, r16) that can show up in str
function push_modrm(str, spare, rs) {
mod=3
mod=0
rm=0
if (str in rs) {
mod=3
rm=rs[str]
} else if (substr(str,1,1)=="[") {
rmap=""
gsub(/^\[|\]$/, "", str)
split(str,rmp,"+")
disp=0
for (i in rmp) {
if (rmp[i] in r16) {
rmap=rmap rmp[i]
} else {
disp = disp + getsym(rmp[i])
mod=2
}
disp=expr(str)
if (!ecrit || disp) {
mod=2
}
if (!rmap) {
if (!eregs) {
mod=0
rm=6
} else if (rmap in modstr) {
rm=modstr[rmap]
} else if (eregs in modstr) {
rm=modstr[eregs]
# [BP] is unencodable, this combination is read as [0000]
# so we upgrade [BP] to [BP+00]
if (mod==0 && rm==6) {
mod=1
}
} else {
err("Bad modR/M")
}
@ -333,11 +371,11 @@ op=="cpu" {
next
}
op=="org" {
pos=getsym(a[1])
pos=crit(a[1])
submit(pos);next
}
op=="equ" {
val=getsym(a[1])
val=crit(a[1])
submit(val);next
}
op=="db" {
@ -346,11 +384,11 @@ op=="db" {
for(j=2;j<length(a[i]);j++) {
push_byte(_ord_[substr(a[i],j,1)])
}
} else push_byte(getsym(a[i]))
} else push_byte(imm(a[i]))
}
}
op=="dw" {
for(i=1;i<=c;i++) push_word(getsym(a[i]))
for(i=1;i<=c;i++) push_word(imm(a[i]))
}
# arithmetics: ADD, SUB, XOR etc
op in alu {
@ -358,9 +396,9 @@ op in alu {
if (!hex) {
size=push_op_fixed_spare(0x80, alu[op])
if (size==1) {
push_byte(getsym(op2))
push_byte(imm(op2))
} else if (size==2) {
push_word(getsym(op2))
push_word(imm(op2))
}
}
}
@ -370,9 +408,9 @@ op=="test" {
if (!hex) {
size=push_op_fixed_spare(246, 0)
if (size==1) {
push_byte(getsym(op2))
push_byte(imm(op2))
} else if (size==2) {
push_word(getsym(op2))
push_word(imm(op2))
}
}
}
@ -407,10 +445,10 @@ op=="mov" {
# reg <- imm
} else if (op1 in r8) {
push_byte(176+r8[op1])
push_byte(getsym(op2))
push_byte(imm(op2))
} else if (op1 in r16) {
push_byte(184+r16[op1])
push_word(getsym(op2))
push_word(imm(op2))
# modrm <- imm
} else if (byteop && rm1) {
push_byte(198)
@ -431,15 +469,22 @@ op=="int" && op1=="3" { # CC breakpoint
}
op=="int" { # CD
push_byte(205)
push_byte(getsym(op1))
push_byte(imm(op1))
}
op=="jmp" && wordop {
push_byte(233)
push_word(getsym(op1)-(pos+3))
op=="jmp" {
val=imm(op1)-(pos+2)
if (val>-127 && val<128 && ecrit) {
push_byte(235)
push_signed_byte(val)
} else {
push_byte(233)
push_word(val-1)
}
submit(pos);next
}
op=="call" && wordop {
push_byte(232)
push_word(getsym(op1)-(pos+3))
push_word(imm(op1)-(pos+3))
}
op=="neg" {
push_op_fixed_spare(246, 3)
@ -447,7 +492,7 @@ op=="neg" {
# opcodes with rel8 encoding
op in ops_rel8 && byteop && c==1 {
push_byte(ops_rel8[op])
push_signed_byte(getsym(op1)-(pos+2))
push_signed_byte(imm(op1)-(pos+2))
}
# opcodes without arguments
op in ops_sb { push_byte(ops_sb[op]) }