diff --git a/host/asm.awk b/host/asm.awk index 7880d99..105a78b 100644 --- a/host/asm.awk +++ b/host/asm.awk @@ -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-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]) }