   [{{:keys [v]} :cpu :as state} x]
   (let [Vx (nth v x)]
     (-> state
-        (update-dt Vx)
-        (update-pc 2))))
+        (write-dt Vx)
+        (write-pc 2))))
 
 (defn opcode-FX18
   "Set sound timer = Vx."
   [{{:keys [v]} :cpu :as state} X]
   (let [Vx (nth v X)]
     (-> state
-        (update-st Vx)
-        (update-pc 2))))
+        (write-st Vx)
+        (write-pc 2))))
 
 (defn opcode-FX29
   "Set I = location of sprite for digit Vx."
   [{{:keys [v]} :cpu :as state} X]
   (let [Vx (nth v X)]
     (-> state
-        (update-i (* 5 Vx))
-        (update-pc 2))))
-
-;; FIXME:
+        (write-i (* 5 Vx))
+        (write-pc 2))))
+
 (defn opcode-FX33
   "Store BCD representation of Vx in memory locations I, I+1, I+2."
   [{{:keys [i v memory]} :cpu :as state} X]
-  (let [Vx (nth v X)
-        val (->bcd Vx)]
-    (-> state
-        (assoc-in [:cpu :memory]
-                  (assoc-in-range memory val i))
-        (assoc-in [:cpu :pc] 2))))
-
-;; FIXME:
+  (let [Vx (nth v X)]
+    (-> state
+        (write-memory (->bcd Vx) i)
+        (write-pc 2))))
+
 (defn opcode-FX55
   "Store registers V0 through Vx in memory starting at location I."
-  [{{:keys [i v memory]} :cpu :as state} X]
-  (-> state
-      (assoc-in [:cpu :memory]
-                (assoc-in-range memory (get-in-range v 0 (inc X)) i))
-      (update-pc 2)
-      ))
+  [{{:keys [i v memory]} :cpu :as state} x]
+  (-> state
+      (write-memory (get-in-range v 0 (inc x)) i)
+      (write-pc 2)))
 
 (defn opcode-FX65
   "Read registers V0 through Vx from memory starting at location I."
   [{{:keys [i v memory]} :cpu :as state} X]
   (-> state
-      (update-v (get-in-range memory i (+ i X 1)))
-      (update-pc 2)))
+      (write-v (get-in-range memory i (+ i X 1)))
+      (write-pc 2)))
 
 (defn opcode-FX1E
   "Set I = I + Vx."
   [{{:keys [i v]} :cpu :as state} x]
   (let [Vx (nth v x)]
     (-> state
-        (update-i (+ i Vx))
-        (update-pc 2))))
+        (write-i (+ i Vx))
+        (write-pc 2))))
 
 (defn initial-vm [state]
 

  (-> state
      (assoc :screen (screen/make-screen))
      (assoc-in [:cpu :draw-flag] 1)
      (update-draw-flag 1)
      (update-pc 2)))

(defn opcode-00EE
  "Return from a subroutine."
  [{{:keys [sp stack]} :cpu :as state}]
  (-> state
      (update-sp (dec sp))
      (update-pc (+ 2 (nth stack (dec sp))))))

(defn opcode-1NNN
  "Jump to address NNN."
  [state nnn]
  (-> state
      (update-pc nnn)))

(defn opcode-2NNN
  "Call subroutine at nnn."
  [{{:keys [pc sp stack]} :cpu :as state} nnn]
  (-> state
      (update-stack sp pc)
      (update-sp (inc pc))
      (update-pc nnn)))

(defn opcode-3XNN
  "Skip next instruction if VX = NN."
  [{{:keys [v]} :cpu :as state} x nn]
  (let [Vx (nth v x)]
    (-> state
        (update-pc (if (= Vx nn) 4 2)))))

(defn opcode-4XNN
  "Skip next instruction if VX != NN."
  [{{:keys [v]} :cpu :as state} x nn]
  (let [Vx (nth v x)]
    (-> state
        (update-pc (if-not (= Vx nn) 4 2)))))

(defn opcode-5XY0
  "Skip next instruction if Vx = Vy."
  [{{:keys [v]} :cpu :as state} X Y]
  (let [[Vx Vy] (VxVy v X Y)]
    (-> state
        (update-pc (if (= Vx Vy) 4 2)))))

(defn opcode-6XNN
  "Set Vx to NN."
  [state x nn]
  (-> state
      (update-v x nn)
      (update-pc 2)))

(defn opcode-7XNN
  "Set Vx = Vx + NN."
  [{{:keys [v]} :cpu :as state} x nn]
  (let [Vx (bit-and (+ (nth v x) nn) 0xff)]
    (-> state
        (update-v x Vx)
        (update-pc 2))))

(defn opcode-8XY0
  "Set Vx = Vy."
  [{{:keys [v]} :cpu :as state} x y]
  (let [Vy (nth v y)]
    (-> state
        (update-v  x Vy)
        (update-pc 2))))

(defn opcode-8XY1
  "Set Vx = Vx OR Vy."
  [{{:keys [v]} :cpu :as state} x y]
  (let [[Vx Vy] (VxVy v x y)]
    (-> state
        (update-v  x (bit-or Vx Vy))
        (update-pc 2))))

(defn opcode-8XY2
  "Set Vx = Vx AND Vy."
  [{{:keys [v]} :cpu :as state} x y]
  (let [[Vx Vy] (VxVy v x y)]
    (-> state
        (update-v  x (bit-and Vx Vy))
        (update-pc 2))))

(defn opcode-8XY3
  "Set Vx = Vx XOR Vy."
  [{{:keys [v]} :cpu :as state} x y]
  (let [[Vx Vy] (VxVy v x y)]
    (-> state
        (update-v  x (bit-xor Vx Vy))
        (update-pc 2))))

(defn opcode-8XY4
  "Set Vx = Vx + Vy, set VF = carry."

(defn- VxVy [V x y]
  [(nth V x) (nth V y)])


(defn- write-pc
  [state pc]
  (assoc-in state [:cpu :pc] pc))

(defn- write-sp
  [state sp]
  (assoc-in state [:cpu :sp] sp))

(defn- write-i
  [state i]
  (assoc-in state [:cpu :i] i))

(defn- write-dt
  [state dt]
  (assoc-in state [:cpu :dt] dt))

(defn- write-st
  [state st]
  (assoc-in state [:cpu :st] st))

(defn- write-draw-flag
  [state draw-flag]
  (assoc-in state [:cpu :draw-flag] draw-flag))

(defn- write-stack
  ([{{:keys [stack]} :cpu :as state} idx val]
   (write-stack state (assoc stack idx val)))
  ([state stack]
   (assoc-in state [:cpu :stack] stack)))

(defn- write-memory
  ([{{:keys [memory]} :cpu :as state} arr start]
   (write-memory state (assoc-in-range memory arr start)))
  ([state memory]
   (assoc-in state [:cpu :memory] memory)))

(defn- write-v
  ([{{:keys [v]} :cpu :as state} x val]
   (write-v state (assoc v x val)))
  ([{{:keys [v]} :cpu :as state} val]
   (assoc-in state [:cpu :v] (assoc-in-range v val))))

(def ^{:private true}
  default-state
