2010年6月12日土曜日

ICFP 2009 orbit vm

The orbit virtual machine - pretty simple, as the binary reader took care of all the idiosyncracies of the binary format already.

The input and output ports are implemented as maps, as the 14-bit addressable memory is only sparsely used, allocating vectors/arrays for that seemed like a bit of a waste.


(ns orbit-vm)

(defstruct vm-struct :data :instructions :program-counter :inputs :outputs :status)

(defn create-vm
"Creates an orbit vm structure, which is used to hold the vm state and an instruction list"
[obf-seq]
(let [[data instructions] (apply map vector obf-seq)]
(struct vm-struct data instructions 0 {} {} 0)))

(defn process-instruction
"Processes the given (single) instruction on the vm. Returns a vm with the changed state"
[vm [opcode p1 p2]]
(let [r (fn [addr] (get-in vm [:data addr]))
w (fn [val] (assoc-in vm [:data (:program-counter vm)] val))
binary-op (fn [op] (w (op (r p1) (r p2))))
vm (condp = opcode
; d-instructions: p1: r1, p2: r2
:add (binary-op +)
:sub (binary-op -)
:mult (binary-op *)
:div (binary-op #(if (zero? %2) 0.0 (/ %1 %2)))
:output (do (assoc-in vm [:outputs p1] (r p2)))
:phi (w (r (if (zero? (:status vm)) p2 p1)))

; s-instructions: p1: "immediate", p2: r1
:noop vm
:cmpz (assoc-in vm [:status] (if (p1 (r p2) 0.0) 1 0))
:sqrt (w (Math/sqrt (r p2)))
:copy (w (r p2))
:input (let [v (or (get-in vm [:inputs p2]) 0)] (do (w v))))]
(assoc-in vm [:program-counter] (inc (:program-counter vm )))))

(defn one-simulation-step
"Processes one full round of instructions. Returns a vm with the changed state"
[vm]
(let [vm (reduce process-instruction vm (:instructions vm))]
(assoc-in vm [:program-counter] 0)))

0 件のコメント:

コメントを投稿

フォロワー