duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit de2b6088f2390b38e07944df86592daf11994c72
parent 6e006dde851551905e33f9231d1b177fa6443e5a
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Fri, 15 Jul 2022 08:06:20 -0400

asm/i386: add all ops that the old assembler has

Diffstat:
Mfs/asm/i386.fs | 85+++++++++++++++++++++++++++++++++++++------------------------------------------
Mfs/tests/asm/i386.fs | 25+++++++++++++++++++++++++
2 files changed, 65 insertions(+), 45 deletions(-)

diff --git a/fs/asm/i386.fs b/fs/asm/i386.fs @@ -3,22 +3,10 @@ \ attribute set. \ MOD/RM constants -0 const AX -1 const CX -2 const DX -3 const BX -4 const SP -5 const BP -6 const SI -7 const DI -0 const AL -1 const CL -2 const DL -3 const BL -4 const AH -5 const CH -6 const DH -7 const BH +0 const AX 1 const CX 2 const DX 3 const BX +4 const SP 5 const BP 6 const SI 7 const DI +0 const AL 1 const CL 2 const DL 3 const BL +4 const AH 5 const CH 6 const DH 7 const BH 5 const MEM \ mod 0 + r/m 5 == abs memory \ Size modes @@ -39,6 +27,7 @@ SZ32 value opsz : asm$ SZ32 to opsz 1 to opdirec 3 to opmod -1 to opreg -1 to oprm 0 to imm? ; : _err abort" argument error" ; : _assert not if _err then ; +: w, here w! 2 allot ; \ "Force" a value into opreg. If opreg is -1, we simply set it, but if it's set, \ then we move opreg to oprm first. @@ -54,27 +43,9 @@ SZ32 value opsz \ Writing the operation -\ Opcode format: when listing the opcode operations, there is often multiple -\ elements in that number. These elements follow specific rules. -\ As a general rule, the lower byte of the number contains the opcode to write -\ down. However, for "modrm-enabled" ops (a lot of them), two bytes are used. -\ The lower byte contains the "modrm" opcode. Only b7:2 are significant, b1:0, -\ in which direction and size bits are or-ed in, must be unset. For example, for -\ op "SUB", this field is $28. -\ In addition to this lower byte, the 2nd byte of the opcode contains the "imm -\ opcode", that is, the opcode for the "immediate" mode of the op as well as the -\ register constant that replaces the "reg" field. Both these fields are or-ed -\ in *the same byte*. Because, in imm mode, b7 is always set, we don't record -\ it. We shift the rest of the opcode by 1. b1:0 are computed fields, so they're -\ not part of the opcode. That leaves us 3 bits to store the "reg" field. For -\ example, for "SUB", this byte is $05 ($80 << + /5) -\ In addition to this, the 3rd byte of for the "AX" immediate shortcut opcode. -\ If the op has a "shortcut" op for "immediate to AX/AL" operation, its opcode -\ will be in the 3rd byte (with b1:0 unset). This byte is 0 if there is no -\ shortcut. For example, this byte is $2c for "SUB". - +\ "opcode" needs to habe bits 1 and 0 *unset* : op, ( opcode -- ) \ write "opcode", mixing it with opdirec and opsz - opdirec << or opsz SZ8 = not or c, ; + opdirec << or opsz SZ8 = not or dup $ff > if w, else c, then ; : modrm, ( -- ) \ write down modrm, errors out if not all parts are there. opmod 3 lshift opreg or 3 lshift oprm or dup $100 < _assert c, ; @@ -89,7 +60,7 @@ SZ32 value opsz : imm, ( -- ) \ write down an immediate imm opsz case SZ32 of = , endof - SZ16 of = here w! 2 allot endof + SZ16 of = w, endof SZ8 of = c, endof _err endcase ; @@ -97,10 +68,9 @@ SZ32 value opsz : opmodrm, ( opcode -- ) \ write the operation in "modrm" mode op, modrm, disp, asm$ ; -: opimm, ( opcode -- ) \ write the operation in "immediate" mode +: opimm, ( opcode opreg -- ) \ write the operation in "immediate" mode 0 to opdirec \ TODO: allow sign-extend by making this logic variable - dup 8 rshift 7 and opreg! ( opcode ) - 9 rshift $fc and $80 or op, modrm, disp, imm, asm$ ; + opreg! op, modrm, disp, imm, asm$ ; \ Setting arguments @@ -123,7 +93,7 @@ SZ32 value opsz opreg 0< if \ either it's the first argument, or the "other" is a mod/rm to opreg else \ second argument - opmod 0< _assert \ more than 2 args! + oprm 0< _assert \ more than 2 args! ( reg ) to oprm then ; @@ -176,10 +146,27 @@ $0f84 op jz, $0f85 op jnz, then ; $04e9 op jmp, $02e8 op call, +\ Single operand +\ opcode format 00000000 00000rrr mmmmmmmm mmmmmm00 +\ r = opreg override +\ m = modrm opcode +: op ( reg opcode -- ) doer , does> @ ( opcode -- ) + dup 16 rshift opreg! $ffff and opmodrm, ; +$0400f7 op mul, $0300f7 op neg, $0200f7 op not, +$0100ff op dec, $0000ff op inc, +$009f0f op setg, $009c0f op setl, $00940f op setz, $00950f op setnz, + \ Two operands +\ opcode format 00000000 ssssssss iiiiirrr mmmmmm00 +\ s = "shortcut" opcode, when target is AX +\ i = immediate opcode, with b7 (always 1) is left off +\ r = immediate opreg override +\ m = modrm opcode : op ( opcode -- ) doer , does> @ ( opcode ) - imm? if opimm, else opmodrm, then ; -$040000 op add, $3c0738 op cmp, $2c0528 op sub, $a8f084 op test, + imm? if + 8 rshift dup >> $fc and $80 or swap 7 and ( opcode opreg ) opimm, + else $ff and opmodrm, then ; +$040000 op add, $3c0738 op cmp, $2c0528 op sub, $a8f084 op _test, $240420 op and, $0c0108 op or, $340630 op xor, \ Shifts. They come in 2 versions. The "naked" version is imm-only. The "cl" @@ -192,9 +179,17 @@ $04c1 op shl, $05c1 op shr, imm? not _assert opreg! c, modrm, disp, asm$ ; $04d3 op shlcl, $05d3 op shrcl, -\ MOV is special +\ Push/Pop +: op ( op -- ) doer c, does> c@ ( opcode -- ) + oprm 0< _assert opsz SZ8 = not _assert opreg or c, asm$ ; +$58 op pop, $50 op push, + +\ MOV has this special reg<-imm shortcut : mov, imm? if opmod 3 = if \ mov reg, imm shortcut $b0 opsz SZ8 = not 3 lshift or ( b0 or b8 ) opreg or c, imm, asm$ - else $c000 opimm, then + else $c0 0 opimm, then else $88 opmodrm, then ; + +\ TEST can only have one direction +: test, 0 to opdirec _test, ; diff --git a/fs/tests/asm/i386.fs b/fs/tests/asm/i386.fs @@ -40,4 +40,29 @@ code foo4 ret, foo4 84 #eq + +\ test single operands +code foo5 + ax 42 i) mov, + bx 3 i) mov, + bx mul, + ax ax test, + bl setnz, + al bl add, + bp 4 i) sub, + bp 0 d) ax mov, + ret, + +foo5 127 #eq + +\ push/pop +code foo6 + ax 42 i) mov, + ax push, + dx pop, + bp 4 i) sub, + bp 0 d) dx mov, + ret, + +foo6 42 #eq testend