mu/mu.arc

466 lines
16 KiB
Plaintext
Raw Normal View History

2014-07-07 01:49:53 +00:00
; things that a future assembler will need separate memory for:
; code; types; args channel
2014-08-19 17:31:58 +00:00
(= initialization-fns* (queue))
(def reset ()
(each f (as cons initialization-fns*)
(f)))
(mac on-init body
`(enq (fn () ,@body)
initialization-fns*))
(on-init
(= traces* (queue)))
(def trace (label . args)
(enq (list label (apply tostring:prn args))
traces*))
(def check-trace-contents (msg expected-contents)
(unless (trace-contents-match expected-contents)
(prn "F - " msg)
(prn " trace contents")
(print-trace-contents-mismatch expected-contents)))
(def trace-contents-match (expected-contents)
(each (label msg) (as cons traces*)
(when (and expected-contents
(is label expected-contents.0.0)
(posmatch expected-contents.0.1 msg))
(pop expected-contents)))
(no expected-contents))
(def print-trace-contents-mismatch (expected-contents)
(each (label msg) (as cons traces*)
(whenlet (expected-label expected-msg) expected-contents.0
(if (and (is label expected-label)
(posmatch expected-msg msg))
(do (pr " * ")
(pop expected-contents))
(pr " "))
(pr label ": " msg)))
(prn " couldn't find")
(each (expected-label expected-msg) expected-contents
(prn " ! " expected-label ": " expected-msg)))
2014-08-22 04:37:55 +00:00
(mac init-fn (name . body)
`(enq (fn () (= (function* ',name) ',body))
initialization-fns*))
2014-07-06 08:41:37 +00:00
(def clear ()
(= types* (obj
2014-08-22 03:32:27 +00:00
; must be scalar or array, sum or product or primitive
2014-08-26 18:52:16 +00:00
type (obj size 1)
type-array (obj array t elem 'type)
type-array-address (obj size 1 address t elem 'type-array)
2014-08-26 18:52:16 +00:00
typeinfo (obj size 5 record t elems '(integer boolean boolean boolean type-array))
typeinfo-address (obj size 1 address t elem 'typeinfo)
typeinfo-address-array (obj array t elem 'typeinfo-address)
2014-08-20 04:33:48 +00:00
location (obj size 1)
integer (obj size 1)
boolean (obj size 1)
2014-10-05 17:31:27 +00:00
byte (obj size 1)
;? string (obj array t elem 'byte) ; inspired by Go
char (obj size 1) ; int32 like a Go rune
2014-10-05 06:00:19 +00:00
string (obj size 1) ; temporary hack
2014-08-22 04:04:45 +00:00
; arrays consist of an integer length followed by the right number of elems
integer-array (obj array t elem 'integer)
2014-08-20 04:33:48 +00:00
integer-address (obj size 1 address t elem 'integer) ; pointer to int
2014-08-22 04:04:45 +00:00
; records consist of a series of elems, corresponding to a list of types
2014-08-20 04:33:48 +00:00
integer-boolean-pair (obj size 2 record t elems '(integer boolean))
integer-boolean-pair-address (obj size 1 address t elem 'integer-boolean-pair)
2014-08-22 03:32:27 +00:00
integer-boolean-pair-array (obj array t elem 'integer-boolean-pair)
2014-08-22 03:08:22 +00:00
integer-integer-pair (obj size 2 record t elems '(integer integer))
integer-point-pair (obj size 2 record t elems '(integer integer-integer-pair))
2014-08-22 17:47:44 +00:00
custodian (obj size 1 record t elems '(integer))
))
2014-07-06 08:41:37 +00:00
(= memory* (table))
(= function* (table)))
2014-08-19 17:31:58 +00:00
(enq clear initialization-fns*)
2014-07-06 08:41:37 +00:00
(def add-fns (fns)
(each (name . body) fns
(= function*.name body)))
2014-07-06 07:07:03 +00:00
2014-08-21 02:49:05 +00:00
(def v (operand) ; for value
operand.0)
2014-07-31 08:53:14 +00:00
2014-08-21 02:49:05 +00:00
(def metadata (operand)
cdr.operand)
2014-08-21 02:49:05 +00:00
(def ty (operand)
operand.1) ; assume type is always first bit of metadata, and it's always present
2014-07-31 08:53:14 +00:00
2014-08-22 02:55:16 +00:00
(def typeinfo (operand)
(types* ty.operand))
2014-08-21 02:49:05 +00:00
(def sz (operand)
2014-08-21 07:29:55 +00:00
;? (prn "sz " operand)
2014-08-22 03:32:27 +00:00
; todo: override this for arrays
2014-08-22 02:55:16 +00:00
typeinfo.operand!size)
2014-08-21 07:29:55 +00:00
(defextend sz (typename) (isa typename 'sym)
types*.typename!size)
2014-08-21 00:43:15 +00:00
(def addr (loc)
(if (pos 'deref (metadata loc))
(memory* (v loc))
(v loc)))
2014-08-20 06:37:50 +00:00
(def addrs (n sz)
(accum yield
(repeat sz
(yield n)
(++ n))))
(def m (loc) ; read memory, respecting metadata
;? (prn "m " loc " " sz.loc)
(if (is 'literal ty.loc)
(v loc)
(is 1 sz.loc)
(memory* (addr loc))
:else
(annotate 'record
(map memory* (addrs (addr loc) sz.loc)))))
(def setm (loc val) ; set memory, respecting metadata
;? (prn "setm " loc " " val)
(assert sz.loc)
(if (is 1 sz.loc)
(= (memory* addr.loc) val)
(each (dest src) (zip (addrs addr.loc sz.loc)
(rep val))
(= (memory* dest) src))))
(def array-len (operand)
(m `(,v.operand integer)))
2014-08-22 02:55:16 +00:00
(def array-ref (operand idx)
(assert typeinfo.operand!array)
(assert (< -1 idx (array-len operand)))
2014-08-22 02:55:16 +00:00
(withs (elem typeinfo.operand!elem
offset (+ 1 (* idx sz.elem)))
(m `(,(+ v.operand offset) ,elem))))
2014-08-29 02:23:38 +00:00
; context contains the call-stack of functions that haven't yet returned
2014-08-29 02:54:37 +00:00
(def make-context (fn-name)
(annotate 'context (obj call-stack (list
(obj fn-name fn-name pc 0 caller-arg-idx 0)))))
2014-08-29 02:23:38 +00:00
(defextend empty (x) (isa x 'context)
(no rep.x!call-stack))
2014-08-29 02:23:38 +00:00
(def stack (context)
((rep context) 'call-stack))
2014-08-29 02:23:38 +00:00
(mac push-stack (context op)
`(push (obj fn-name ,op pc 0 caller-arg-idx 0)
((rep ,context) 'call-stack)))
(mac pop-stack (context)
`(pop ((rep ,context) 'call-stack)))
(def top (context)
stack.context.0)
(def body (context (o idx 0))
(function* stack.context.idx!fn-name))
(mac pc (context (o idx 0)) ; assignable
`((((rep ,context) 'call-stack) ,idx) 'pc))
(mac caller-arg-idx (context (o idx 0)) ; assignable
`((((rep ,context) 'call-stack) ,idx) 'caller-arg-idx))
2014-10-05 17:31:38 +00:00
(= scheduling-interval* 500)
(def parse-instr (instr)
(iflet delim (pos '<- instr)
(list (cut instr 0 delim) ; oargs
(instr (+ delim 1)) ; op
(cut instr (+ delim 2))) ; args
(list nil instr.0 cdr.instr)))
(def caller-args (context) ; not assignable
2014-08-29 02:23:38 +00:00
(let (_ _ args) (parse-instr ((body context 1) (pc context 1)))
args))
(def caller-oargs (context) ; not assignable
2014-08-29 02:23:38 +00:00
(let (oargs _ _) (parse-instr ((body context 1) (pc context 1)))
oargs))
2014-08-29 03:44:16 +00:00
(= contexts* (queue))
2014-08-31 18:27:58 +00:00
(def run fn-names
(ret result 0
2014-08-31 18:27:58 +00:00
(each it fn-names
2014-08-29 03:44:16 +00:00
(enq make-context.it contexts*))
; simple round-robin scheduler
(while (~empty contexts*)
(let context deq.contexts*
(trace "schedule" top.context!fn-name)
2014-08-29 02:23:38 +00:00
(let insts-run (run-for-time-slice context scheduling-interval*)
2014-08-29 03:44:16 +00:00
(= result (+ result insts-run)))
(if (~empty context)
(enq context contexts*))))))
($:require "charterm/main.rkt")
2014-08-29 02:23:38 +00:00
(def run-for-time-slice (context time-slice)
;? (prn "AAA")
2014-08-28 23:40:28 +00:00
(point return
;? (prn "BBB")
(for ninstrs 0 (< ninstrs time-slice) (++ ninstrs)
2014-08-29 02:23:38 +00:00
;? (prn "CCC " pc.context " " context " " (len body.context))
(while (>= pc.context (len body.context))
(pop-stack context)
(if empty.context (return ninstrs))
(++ pc.context))
2014-08-29 03:44:16 +00:00
(trace "run" top.context!fn-name " " pc.context ": " (body.context pc.context))
2014-08-29 02:23:38 +00:00
;? (prn "--- " top.context!fn-name " " pc.context ": " (body.context pc.context))
;? (prn " " memory*)
2014-08-29 02:23:38 +00:00
(let (oarg op arg) (parse-instr (body.context pc.context))
;? (prn op " " arg " -> " oarg)
(let tmp
(case op
literal
arg.0
add
(+ (m arg.0) (m arg.1))
sub
(- (m arg.0) (m arg.1))
mul
(* (m arg.0) (m arg.1))
div
(/ (real (m arg.0)) (m arg.1))
idiv
2014-08-27 05:00:23 +00:00
(list (trunc:/ (m arg.0) (m arg.1))
(mod (m arg.0) (m arg.1)))
and
(and (m arg.0) (m arg.1))
or
(or (m arg.0) (m arg.1))
not
(not (m arg.0))
eq
(is (m arg.0) (m arg.1))
neq
(~is (m arg.0) (m arg.1))
lt
(< (m arg.0) (m arg.1))
gt
(> (m arg.0) (m arg.1))
le
(<= (m arg.0) (m arg.1))
ge
(>= (m arg.0) (m arg.1))
arg
(let idx (if arg
arg.0
2014-08-29 02:23:38 +00:00
(do1 caller-arg-idx.context
(++ caller-arg-idx.context)))
;? (prn idx)
2014-08-29 02:23:38 +00:00
;? (prn caller-args.context)
(m caller-args.context.idx))
type
2014-08-29 02:23:38 +00:00
(ty (caller-args.context arg.0))
otype
2014-08-29 02:23:38 +00:00
(ty (caller-oargs.context arg.0))
jmp
2014-08-29 02:23:38 +00:00
(do (= pc.context (+ 1 pc.context (v arg.0)))
;? (prn "jumping to " pc.context)
(continue))
jif
(when (is t (m arg.0))
2014-08-29 02:23:38 +00:00
(= pc.context (+ 1 pc.context (v arg.1)))
;? (prn "jumping to " pc.context)
(continue))
copy
(m arg.0)
2014-08-20 04:33:48 +00:00
get
2014-08-22 02:55:16 +00:00
(with (base arg.0 ; integer (non-symbol) memory location including metadata
idx (v arg.1)) ; literal integer
2014-08-22 04:04:45 +00:00
(if
typeinfo.base!array
(do (assert (is 0 idx)) ; 'get' can only lookup array length
(array-len base))
typeinfo.base!record
; field index
(do (assert (< -1 idx (len typeinfo.base!elems)))
(m `(,(+ v.base
(apply + (map sz
(firstn idx typeinfo.base!elems))))
,typeinfo.base!elems.idx)))
2014-10-05 17:51:28 +00:00
:else
2014-08-22 04:04:45 +00:00
(assert nil "get on invalid type @base")))
aref
(array-ref arg.0 (v arg.1))
2014-08-31 18:20:28 +00:00
new
(let type (v arg.0)
(if types*.type!array
(new-array type (v arg.1))
(new-scalar type)))
2014-10-05 03:19:12 +00:00
; multiprocessing
run
(run (v arg.0))
fork
(enq (make-context (v arg.0)) contexts*)
2014-10-05 06:00:19 +00:00
; text interaction
cls
(do1 nil ($.charterm-clear-screen))
cll
(do1 nil ($.charterm-clear-line))
cursor
(do1 nil ($.charterm-cursor (m arg.0) (m arg.1)))
print
2014-10-05 17:44:14 +00:00
(do1 nil ((if ($.current-charterm) $.charterm-display pr) (m arg.0)))
2014-10-05 06:00:19 +00:00
getc
($.charterm-read-key)
bold-mode
(do1 nil ($.charterm-bold))
non-bold-mode
(do1 nil ($.charterm-normal))
2014-10-05 17:44:14 +00:00
console-on
(do1 nil (if ($.current-charterm) ($.open-charterm)))
console-off
(do1 nil (if ($.current-charterm) ($.close-charterm)))
2014-10-05 06:00:19 +00:00
reply
2014-08-29 02:23:38 +00:00
(do (pop-stack context)
(if empty.context (return ninstrs))
(let (caller-oargs _ _) (parse-instr (body.context pc.context))
(each (dest src) (zip caller-oargs arg)
(setm dest (m src))))
2014-08-29 02:23:38 +00:00
(++ pc.context)
(while (>= pc.context (len body.context))
(pop-stack context)
(if empty.context (return ninstrs))
(++ pc.context))
(continue))
; else user-defined function
2014-08-29 02:23:38 +00:00
(do (push-stack context op)
(continue))
)
2014-08-26 17:17:55 +00:00
; opcode generated some value, stored in 'tmp'
;? (prn "store: " tmp " " oarg)
(if (acons tmp)
(for i 0 (< i (min len.tmp len.oarg)) ++.i
(setm oarg.i tmp.i))
(when oarg ; must be a list
;? (prn oarg.0)
(setm oarg.0 tmp)))
)
2014-08-29 02:23:38 +00:00
(++ pc.context)))
(return time-slice)))
2014-07-06 07:07:03 +00:00
(enq (fn () (= Memory-in-use-until 1000))
initialization-fns*)
(def new-scalar (type)
(ret result Memory-in-use-until
(++ Memory-in-use-until sizeof.type)))
(def new-array (type size)
(ret result Memory-in-use-until
(++ Memory-in-use-until (* (sizeof types*.type!elem) size))))
(def sizeof (type)
(if (~or types*.type!record types*.type!array)
types*.type!size
types*.type!record
(sum idfn
(accum yield
(each elem types*.type!elems
(yield sizeof.elem))))))
(def convert-braces (instrs)
(let locs () ; list of information on each brace: (open/close pc)
(let pc 0
(loop (instrs instrs)
(each instr instrs
(if (~is 'begin instr.0)
(do
;? (prn pc " " instr)
(++ pc))
; hack: racket replaces curlies with parens, so we need the
; keyword begin to delimit blocks.
; ultimately there'll be no nesting and curlies will just be in a
; line by themselves.
(do
;? (prn `(open ,pc))
(push `(open ,pc) locs)
(recur cdr.instr)
;? (prn `(close ,pc))
(push `(close ,pc) locs))))))
(zap rev locs)
;? (prn locs)
(with (pc 0
stack ()) ; elems are pcs
(accum yield
(loop (instrs instrs)
(each instr instrs
(let delim (or (pos '<- instr) -1)
(with (oarg (if (>= delim 0)
(cut instr 0 delim))
op (instr (+ delim 1))
arg (cut instr (+ delim 2)))
;? (prn op " " oarg)
(case op
begin
(do
(push pc stack)
(assert:is oarg nil)
(recur arg)
(pop stack))
break
(do
(assert:is oarg nil)
(assert:is arg nil)
(yield `(jmp (,(close-offset pc locs) offset))))
breakif
(do
;? (prn "breakif: " instr)
(assert:is oarg nil)
(yield `(jif ,arg.0 (,(close-offset pc locs) offset))))
continue
(do
(assert:is oarg nil)
(assert:is arg nil)
(yield `(jmp (,(- stack.0 pc) offset))))
continueif
(do
;? (prn "continueif: " instr)
(assert:is oarg nil)
(yield `(jif ,arg.0 (,(- stack.0 pc) offset))))
;else
(yield instr))))
(++ pc)))))))
(def close-offset (pc locs)
(let close 0
(with (stacksize 0
done nil)
(each (state loc) locs
;? (prn " :" close " " state " - " loc)
(if (< loc pc)
nil ; do nothing
(no done)
(do
; first time
(when (and (is 0 stacksize) (~is loc pc))
(++ stacksize))
(if (is 'open state) (++ stacksize) (-- stacksize))
; last time
(when (is 0 stacksize)
(= close loc)
(set done))))))
(- close pc 1)))
2014-08-22 18:05:51 +00:00
(reset)
2014-07-06 08:41:37 +00:00
(awhen cdr.argv
2014-07-27 17:09:00 +00:00
(map add-fns:readfile it)
2014-10-05 06:00:19 +00:00
($.open-charterm)
(run 'main)
2014-10-05 17:44:14 +00:00
(if ($.current-charterm) ($.close-charterm))
2014-07-06 07:07:03 +00:00
(prn memory*))