diff --git a/asm.jrt b/asm.jrt new file mode 100755 index 0000000..2284d2e --- /dev/null +++ b/asm.jrt @@ -0,0 +1,169 @@ +var target +0x100 target ! +: >t b, 1 target +! ; ( todo: write to target segment ) +: w>t , 2 target +! ; + +var op-encode +var lastop + +var current-oparg +var opargs-remaining +array oparg1 3 cells allot +array oparg2 3 cells allot + +: arg1 oparg1 current-oparg ! ; +: arg2 oparg2 current-oparg ! ; +arg1 +: swap-args current-oparg @ oparg1 = if arg2 else arg1 then ; + +: oparg-type ( -- type ) current-oparg @ ; +: oparg-val ( -- v ) current-oparg @ cell + ; +: oparg-base ( -- v ) current-oparg @ 2 cells + ; +: set-oparg! ( val type -- ) oparg-type ! oparg-val ! 0 oparg-base ! ; + +: oparg-imm! ( val -- ) 1 set-oparg! ; +: oparg-imm? ( -- f ) oparg-type @ 1 = ; +: oparg-reg! ( reg -- ) 2 set-oparg! ; +: oparg-reg? ( -- f ) oparg-type @ 2 = ; +: oparg-regflag? ( flag -- f ) oparg-val @ 0xf0 & = oparg-reg? and ; +: oparg-breg? ( -- f ) 0x10 oparg-regflag? ; +: oparg-wreg? ( -- f ) 0x00 oparg-regflag? ; +: oparg-segreg? ( -- f ) 0x20 oparg-regflag? ; +: oparg-mem! ( disp -- ) 3 set-oparg! ; +: oparg-mem? ( -- f ) oparg-type @ 3 = ; + +( TODO: support explicit byte ptr word ) +( ie. inc [bx] vs inc byte [bx]?? ) +( or do we just say incb? ) + +: bytearg? ( -- f ) + current-oparg @ + arg1 oparg-reg? oparg-breg? and + arg2 oparg-reg? oparg-breg? and or + swap current-oparg ! ; +: byteval? ( v -- f ) 0xff00 & dup 0xff00 = swap 0= or ; + +: operror ( err -- ) lastop @ wordname type s": " type type cr ; +: oparg-complete! + opargs-remaining @ dup if + 1 - dup opargs-remaining ! + if arg2 + else arg1 op-encode @ execute 0 op-encode ! then + else s" too many arguments" operror then ; + +: # oparg-imm! oparg-complete! ; +: @[ 0 oparg-mem! ; +: @] -1 oparg-base ! oparg-complete ! ; + +: unexpected-addr ( addr -- ) drop s" unexpected address" operror ; +: @+ ( disp -- ) + opargs-remaining @ if + oparg-type @ dup 0= if drop oparg-mem! oparg-complete! + else 3 = if oparg-val ! + else unexpected-addr then then + else unexpected-addr then ; + +: l: create target @ , does> @ @+ ; + +: memreg create , does> @ oparg-base ! oparg-complete! ; +0 memreg bx+si] 1 memreg bx+di] 2 memreg bp+si] 3 memreg bp+di] +4 memreg si] 5 memreg di] 6 memreg bp] 7 memreg bx] + +: reg create , does> @ oparg-reg! oparg-complete! ; +( data registers: take the bottom four bits and you have the + REG and R/M encoding for the modr/m byte ) +0x00 reg ax 0x01 reg cx 0x02 reg dx 0x03 reg bx +0x04 reg sp 0x05 reg bp 0x06 reg si 0x07 reg di +( 8-bit data registers, same scheme ) +0x10 reg al 0x11 reg cl 0x12 reg dl 0x13 reg bl +0x14 reg ah 0x15 reg ch 0x16 reg dh 0x17 reg bh +( segment registers: take the bottom four bits, left shift 1, + and you have the PUSH instruction byte. bitwise or 0x01 and + you have POP.) +0x25 reg es 0x27 reg ss 0x2d reg cs 0x2f reg ds + +: start-op ( does-ptr argcount -- ) + opargs-remaining @ if s" not enough arguments" operror then + opargs-remaining ! cell - lastop ! arg1 ; +: prefix create , does> @ >t ; +: 0op create , does> dup 0 start-op @ >t ; + +0x26 prefix es: 0x36 prefix ss: 0x2e prefix cs: 0x3e prefix ds: +0xf0 prefix lock 0xf2 prefix repnz 0xf3 prefix repz + +0x90 0op nop 0xa4 0op movsb 0xa5 0op movsw 0xa6 0op cmpsb +0xa7 0op cmpsw 0xc3 0op ret 0xd7 0op xlat 0xf4 0op hlt +0x98 0op cbw 0x99 0op cwd 0x9c 0op pushf 0x9d 0op popf +0x9e 0op sahf 0x9f 0op lahf 0xaa 0op stosb 0xab 0op stosw +0xac 0op lodsb 0xad 0op lodsw 0xae 0op scasb 0xaf 0op scasw +0xcb 0op retf 0xce 0op into 0xcf 0op iret 0xf8 0op clc +0xf9 0op stc 0xfa 0op cli 0xfb 0op sti 0xfc 0op cld +0xfd 0op std 0xf5 0op cmc + +: :op ( count -- ) , $DOCOLON , does> + dup @ dup start-op cell + op-encode ! ; + +: memarg>case ( -- 0|1|2 ) + oparg-base @ dup -1 = if drop 1 ( D16 ) else + 6 = oparg-val @ 0= if 2 ( [bp]+0 ) else 0 ( standard ) then then ; +: memarg>dispsize ( -- 0|1|2 ) + memarg>case dup 1 = if drop 2 else 2 = if 1 else + oparg-val @ dup 0= if drop 0 else byteval? if 1 else 2 + then then then then ; +: memarg>mod+rm ( -- mod rm ) + memarg>case dup 1 = if drop 0 6 else 2 = if 2 6 else + memarg>dispsize oparg-base @ then then ; +: regarg>mod+rm ( -- mod rm ) 3 oparg-val @ ; + +: modrm>t ( reg mod rm -- ) 0x03 & swap 0x02 & 6 << | swap 0x03 & 3 << | >t ; + +: invalid-args s" invalid argument types" operror ; + +( convention: words ending in * mean "will return if matched" ) +: disp>t memarg>dispsize dup 1= if drop >t else 2 = if w>t else drop then then ; +: imm?>t oparg-imm? if oparg-val @ dup byteval? if >t else w>t then then ; + +: >wreg+op* ( base -- ) + oparg-wreg? if oparg-val @ | >t rdrop else drop then ; +: >segreg+op* ( off -- ) + oparg-segreg? if oparg-val @ 0x0f & 1 << + >t rdrop else drop then ; +: >mem* ( reg op -- ) + oparg-mem? if + >t memarg>mod+rm modrm>t disp>t swap-args imm?>t rdrop + else 2drop then ; +: >regreg ( reg op -- ) >t regarg>mod+rm modrm>t ; +: >byte-regreg* ( reg op -- ) oparg-breg? if >regreg rdrop else 2drop then ; +: >regreg* ( reg op -- ) oparg-wreg? if >regreg rdrop else 2drop then ; + +1 :op ret- oparg-imm? if oparg-val @ w>t else invalid-args then ; +1 :op push + 0x50 >wreg+op* + 0 >segreg+op* + 6 0xff >mem* + invalid-args ; +1 :op pop + 0x58 >wreg+op* + 1 >segreg+op* + 0 0x8f >mem* + invalid-args ; +1 :op inc + 0x40 >wreg+op* + 0 0xfe >byte-regreg* + 0 0xff >regreg* + 0 0xff >mem* + invalid-args ; +1 :op incb + 0 0xfe >byte-regreg* + 0 0xfe >mem* + invalid-args ; +1 :op dec + 0x48 >wreg+op* + 1 0xfe >byte-regreg* + 1 0xff >regreg* + 0 0xff >mem* + invalid-args ; +1 :op decb + 1 0xfe >byte-regreg* + 1 0xfe >mem* + invalid-args ; + diff --git a/boot.jor b/boot.jor index d0b75d9..682cd79 100755 --- a/boot.jor +++ b/boot.jor @@ -31,7 +31,7 @@ key const sp ' cells @ const $DOCOLON ( get the colon execution token ) : :| inline| $DOCOLON , ; immediate -: |; ' ret , |inline ; immediate +: |; ' return , |inline ; immediate : s" state if inline| else here then begin key dup [ key " lit ] != over 0 != and while b, repeat drop 0 b, diff --git a/defs.jrt b/defs.jrt new file mode 100755 index 0000000..b899243 --- /dev/null +++ b/defs.jrt @@ -0,0 +1,159 @@ +: >rot r 2dup r@ >rot r >r 2dup r@ >rot rswap r@ >rot r r >rot rot ; + +: negate 0 swap - ; +: abs dup 0 < if negate then ; + +: ~ -1 ^ ; +: f! ( b v flag -- ) + >rot >r r@ @ >rot ( val flag b r: v ) + if | else ~ & then rot ! ; + +: expile state if , else execute then ; + +: :noname here $DOCOLON , ] ; + +: array word new-word $DOVAR , ; +: create word new-word $DOCREATE , 0 , ; + +: finishcreate ( ipfirst -- ) + ( set cell after codepointer to first instruction of does> ) + latest codepointer cell + ! ; + +: does> here 4 cells + lit ' finishcreate , ' return , ] ; immediate + +: +towards ( from to -- from+-1 ) + over > if 1 + else 1 - then ; + +: for ( from to -- ) + ' >r , [ ' begin , ] ( from r: to ) + ' dup , ' r@ , ' != , [ ' while , ] + ' >r , ; immediate ( r: to from ) +: i ' r@ , ; immediate +: next + ' r , 1 lit ' >r , ; immediate + +: yield rswap ; +: done rdrop 0 >r rswap ; +: ;done ' done , ] ; immediate +: each [ ' begin , ] ' r@ , [ ' while , ] ; immediate +: more ' yield , [ ' repeat , ] ' rdrop , ; immediate +: break rswap rdrop :| yield done |; execute rswap ; + +: links begin yield @ dup not until drop ;done + +: files findfile begin dup while yield nextfile repeat drop ;done +: .files files each type s" " type more ; + +: min ( x y -- x|y ) 2dup > if swap then drop ; +: max ( x y -- x|y ) 2dup < if swap then drop ; + +: +!pos ( n var -- ) dup @ r >r r@ +! @ ; + +: preserving ( cp 0 vars... -- ) + 0 >r begin dup while dup @ >r >r repeat drop + execute + begin r@ while lazy! latest codepointer swap redefine ; + +: dbg" [ ' s" , ] :| type bl .s cr |; expile ; immediate + +( tasks ) +: mailbox 2 cells + ; +: task-ip task-user-size cells + ; +: task-sp task-user-size 1 + cells + ; +: task-rsp task-user-size 2 + cells + ; +: task-stack task-user-size 3 + cells + ; +: task-rstack task-stack stacksize cells + ; + +: .wordin ( ptr -- ) + latest links each + 2dup > if wordname type drop 0 break then + more dup if . else drop then ; userword + +: tasks.s + tasks links each + dup dup . .wordin s" : " type + dup task-sp @ over task-stack ( task stackLim stack ) + 2dup . . s" : " type + begin 2dup > while dup @ . cell + repeat + cr drop drop more ; userword + +: task.bt ( task -- ) + dup task-rsp @ swap task-rstack ( rstackLim rstack ) + begin 2dup > while dup @ dup . .wordin cr cell + repeat + drop drop ; userword + +: doactivate ( task ip -- ) + over task-ip ! + dup task-stack over task-sp ! + dup task-rstack over task-rsp ! + drop +; + +: activate + here 4 cells + lit + ' doactivate , + ' return , +; immediate + +: >task ( val task -- ) + task-sp >r r@ @ ! r@ @ cell + r> ! ; + +: try-send ( val task -- b ) + mailbox dup @ if drop drop 0 else ! 1 then ; + +: wait-send ( val task -- ) + mailbox + begin dup @ while suspend repeat ( wait for empty mailbox ) + ! ; + +: send ( val task -- ) try-send drop ; + +: receive ( -- val ) + running mailbox + begin dup @ not while suspend repeat ( wait for mail ) + dup @ 0