changeset 118:be4ec0e60c16

mode 0 of bootstrapping state machine complete
author Robert McIntyre <rlm@mit.edu>
date Fri, 16 Mar 2012 20:03:10 -0500
parents bcb5c41626b4
children 6cbea8ab65b6
files clojure/com/aurellem/assembly.clj
diffstat 1 files changed, 496 insertions(+), 224 deletions(-) [+]
line wrap: on
line diff
     1.1 --- a/clojure/com/aurellem/assembly.clj	Fri Mar 16 17:50:35 2012 -0500
     1.2 +++ b/clojure/com/aurellem/assembly.clj	Fri Mar 16 20:03:10 2012 -0500
     1.3 @@ -41,6 +41,14 @@
     1.4    (println (format "IE: %d" (IE state)))
     1.5    state)
     1.6  
     1.7 +(defn print-listing [state begin end]
     1.8 +  (dorun (map 
     1.9 +          (fn [opcode line]
    1.10 +            (println (format "0x%04X:  0x%02X" line opcode)))
    1.11 +          (subvec  (vec (memory state)) begin end)
    1.12 +          (range begin end)))
    1.13 +  state)
    1.14 +
    1.15  (defn run-assembly
    1.16    ([info-fn assembly n]
    1.17       (let [final-state
    1.18 @@ -68,64 +76,82 @@
    1.19                     (binary-str (reg-fn state))))
    1.20    state)
    1.21  
    1.22 -
    1.23  (defn view-memory [state mem]
    1.24    (println (format "mem 0x%04X = %s" mem
    1.25                     (binary-str (aget (memory state) mem))))
    1.26    state)
    1.27  
    1.28 +(defn trace [state]
    1.29 +  (loop [program-counters []
    1.30 +         opcodes []]
    1.31 +    (let [frame-boundary?
    1.32 +          (com.aurellem.gb.Gb/tick)]
    1.33 +      (println (count opcodes))
    1.34 +      (if frame-boundary?
    1.35 +        [program-counters opcodes]
    1.36 +        (recur
    1.37 +         (conj program-counters
    1.38 +               (first (registers @current-state)))
    1.39 +         (conj opcodes
    1.40 +               (aget (memory @current-state)
    1.41 +                     (PC @current-state))))))))
    1.42 +  
    1.43 +(defn good-trace []
    1.44 +  (-> (mid-game) (tick) (IE! 0)
    1.45 +      (set-inv-mem [0x00 0x00 0X00 0x00])
    1.46 +      (PC! item-list-start)(print-interrupt)
    1.47 +      (info) (tick) (info) (tick) (info)))
    1.48 +
    1.49  (defn read-down-button []
    1.50    (-> (tick (mid-game))
    1.51        (IE! 0) ; disable interrupts
    1.52        (inject-item-assembly
    1.53 -       (concat
    1.54 -        ;; write 00010000 to 0xFF00 to select joypad
    1.55 -        [0x18   ;D31D                    ; jump over          
    1.56 -         0x01   ;D31E                    ; the next 8 bits
    1.57 -                ;D31F
    1.58 -         (Integer/parseInt "00100000" 2) ; data section 
    1.59 -         
    1.60 -         0xFA   ;D320                    ; load (D31F) into A
    1.61 -         0x1F   ;D321      -->       
    1.62 -         0xD3   ;D322      -->  D31F     
    1.63 +       ;; write 00010000 to 0xFF00 to select joypad
    1.64 +       [0x18   ;D31D                    ; jump over          
    1.65 +        0x01   ;D31E                    ; the next 8 bits
    1.66 +                                        ;D31F
    1.67 +        (Integer/parseInt "00100000" 2) ; data section 
    1.68 +        
    1.69 +        0xFA   ;D320                    ; load (D31F) into A
    1.70 +        0x1F   ;D321      -->       
    1.71 +        0xD3   ;D322      -->  D31F     
    1.72  
    1.73 -         0xEA   ;D323                    ; load (A), which is 
    1.74 -         0x00   ;D324      -->           ; 00010000, into FF00
    1.75 -         0xFF   ;D325      -->  FF00     
    1.76 -         
    1.77 -         0x18   ;D326                    ; this is the place where
    1.78 -         0x01   ;D327                    ; we will store whether
    1.79 -         0x00   ;D328                    ; "down" is pressed.
    1.80 +        0xEA   ;D323                    ; load (A), which is 
    1.81 +        0x00   ;D324      -->           ; 00010000, into FF00
    1.82 +        0xFF   ;D325      -->  FF00     
    1.83 +        
    1.84 +        0x18   ;D326                    ; this is the place where
    1.85 +        0x01   ;D327                    ; we will store whether
    1.86 +        0x00   ;D328                    ; "down" is pressed.
    1.87  
    1.88 -         0xFA   ;D329                    ; (FF00) -> A
    1.89 -         0x00   ;D32A                   
    1.90 -         0xFF   ;D32B
    1.91 +        0xFA   ;D329                    ; (FF00) -> A
    1.92 +        0x00   ;D32A                   
    1.93 +        0xFF   ;D32B
    1.94  
    1.95 -         0xCB   ;D32C                    ; Test whether "down"
    1.96 -         0x5F   ;D32D                    ; is pressed.
    1.97 +        0xCB   ;D32C                    ; Test whether "down"
    1.98 +        0x5F   ;D32D                    ; is pressed.
    1.99  
   1.100 -         0x28   ;D32E                    ; if down is pressed,
   1.101 -         0x03   ;D32F                    ; skip the next section 
   1.102 -                                         ; of code.
   1.103 -         ;; down-is-not-pressed
   1.104 -         0xC3   ;D330
   1.105 -         0x1D   ;D331                    ; return to beginning
   1.106 -         0xD3   ;D332
   1.107 -         
   1.108 -         ;; down-is-pressed 
   1.109 -         0xEA   ;D334                    ; write A to D328 if 
   1.110 -         0x28   ;D335                    ; "down" was pressed
   1.111 -         0xD3   ;D336
   1.112 +        0x28   ;D32E                    ; if down is pressed,
   1.113 +        0x03   ;D32F                    ; skip the next section 
   1.114 +                                        ; of code.
   1.115 +        ;; down-is-not-pressed
   1.116 +        0xC3   ;D330
   1.117 +        0x1D   ;D331                    ; return to beginning
   1.118 +        0xD3   ;D332
   1.119 +        
   1.120 +        ;; down-is-pressed 
   1.121 +        0xEA   ;D334                    ; write A to D328 if 
   1.122 +        0x28   ;D335                    ; "down" was pressed
   1.123 +        0xD3   ;D336
   1.124  
   1.125 -         0xC3   ;D330
   1.126 -         0x1D   ;D331                    ; return to beginning
   1.127 -         0xD3   ;D332
   1.128 -         ]
   1.129 -        
   1.130 -        []))))
   1.131 +        0xC3   ;D330
   1.132 +        0x1D   ;D331                    ; return to beginning
   1.133 +        0xD3   ;D332
   1.134 +        ])))
   1.135  
   1.136 -
   1.137 -
   1.138 +(defn test-read-down []
   1.139 + (= (view-memory (step (step (read-down-button) [:d])) 0xD328)
   1.140 +    (view-memory (step (step (read-down-button))) 0xD328)))
   1.141  
   1.142  (defn count-frames []
   1.143    (-> (tick (mid-game))
   1.144 @@ -206,7 +232,6 @@
   1.145          0xC3   ;D349                   ; return to beginning
   1.146          0x1D   ;D34A
   1.147          0xD3   ;D34B
   1.148 -        
   1.149          ])))
   1.150  
   1.151  (defn step-count-frames []
   1.152 @@ -235,37 +260,11 @@
   1.153        (tick)
   1.154        (print-inventory)))
   1.155  
   1.156 -;;(defn test-read-down []
   1.157 -;;  (= (view-memory (step (step (read-buttons) [:d])) 0xD328)
   1.158 -;;     (view-memory (step (step (read-buttons))) 0xD328)))
   1.159 -
   1.160  (defn test-count-frames []
   1.161    (= 255 (aget (memory ((apply comp (repeat 255 step))
   1.162                          (count-frames)))
   1.163                 0xD31F)))
   1.164  
   1.165 -   
   1.166 -(defn trace [state]
   1.167 -  (loop [program-counters []
   1.168 -         opcodes []]
   1.169 -    (let [frame-boundary?
   1.170 -          (com.aurellem.gb.Gb/tick)]
   1.171 -      (println (count opcodes))
   1.172 -      (if frame-boundary?
   1.173 -        [program-counters opcodes]
   1.174 -        (recur
   1.175 -         (conj program-counters
   1.176 -               (first (registers @current-state)))
   1.177 -         (conj opcodes
   1.178 -               (aget (memory @current-state)
   1.179 -                     (PC @current-state))))))))
   1.180 -  
   1.181 -(defn good-trace []
   1.182 -  (-> (mid-game) (tick) (IE! 0)
   1.183 -      (set-inv-mem [0x00 0x00 0X00 0x00])
   1.184 -      (PC! item-list-start)(print-interrupt)
   1.185 -      (info) (tick) (info) (tick) (info)))
   1.186 -
   1.187  ;; specs for main bootstrap program
   1.188  ;; starts in "mode-select" mode
   1.189  ;;   Each button press takes place in a single frame.
   1.190 @@ -286,165 +285,156 @@
   1.191  ;;   then, the actual bytes are entered and are written to the
   1.192  ;;   start address in sequence.
   1.193  
   1.194 +(defn input-number-assembly []
   1.195 +  [0x18   ;D31D                    ; jump over          
   1.196 +   0x02   ;D31E                    ; the next 2 bytes
   1.197 +   0x00   ;D31F                    ; frame-count
   1.198 +   0x00   ;D320                    ; v-blank-prev
   1.199 +   
   1.200 +   0xFA   ;D321
   1.201 +   0x41   ;D322                    ; load (FF41) into A
   1.202 +   0xFF   ;D323                    ; this contains mode flags
   1.203 +   
   1.204 +   ;; if we're in v-blank, the bit-1 is 0
   1.205 +   ;; and bit-2 is 1  Otherwise, it is not v-blank.
   1.206 +   0xCB   ;D324                     ; test bit-1 of A
   1.207 +   0x4F   ;D325                         
   1.208  
   1.209 +   0xC2   ;D326                     ; if bit-1 is not 0
   1.210 +   0x44   ;D327                     ; GOTO not-v-blank
   1.211 +   0xD3   ;D328
   1.212 +   
   1.213 +   0xCB   ;D329                     ; test bit-0 of A 
   1.214 +   0x47   ;D32A
   1.215 +
   1.216 +   0xCA   ;D32B                     ; if bit-0 is not 1
   1.217 +   0x44   ;D32C                     ; GOTO not-v-blank
   1.218 +   0xD3   ;D32D
   1.219 +   
   1.220 +        ;;; in v-blank mode
   1.221 +
   1.222 +   ;; if v-blank-prev was 0,
   1.223 +   ;; increment frame-count
   1.224 +
   1.225 +   0xFA   ;D32E                    ; load v-blank-prev to A
   1.226 +   0x20   ;D32F
   1.227 +   0xD3   ;D330
   1.228 +   
   1.229 +   0xCB   ;D331
   1.230 +   0x47   ;D332                    ; test bit-0 of A 
   1.231 +
   1.232 +   0x20   ;D333                    ; skip next section
   1.233 +   0x07   ;D334                    ; if v-blank-prev was not zero 
   1.234 +   
   1.235 +   ;; v-blank was 0, increment frame-count
   1.236 +   0xFA   ;D335                    ; load frame-count into A
   1.237 +   0x1F   ;D336
   1.238 +   0xD3   ;D337                   
   1.239 +
   1.240 +   0x3C   ;D338                    ; inc A
   1.241 +
   1.242 +   0xEA   ;D339                    ; load A into frame-count
   1.243 +   0x1F   ;D33A
   1.244 +   0xD3   ;D33B
   1.245 +
   1.246 +   ;; set v-blank-prev to 1
   1.247 +   0x3E   ;D33C                    ; load 1 into A
   1.248 +   0x01   ;D33D                    
   1.249 +
   1.250 +   0xEA   ;D33E                    ; load A into v-blank-prev
   1.251 +   0x20   ;D33F
   1.252 +   0xD3   ;D340
   1.253 +
   1.254 +   0xC3   ;D341                   ; GOTO input handling code
   1.255 +   0x4E   ;D342
   1.256 +   0xD3   ;D343
   1.257 +
   1.258 +        ;;; not in v-blank mode
   1.259 +   ;; set v-blank-prev to 0
   1.260 +   0x3E   ;D344                    ; load 0 into A        
   1.261 +   0x00   ;D345
   1.262 +
   1.263 +   0xEA   ;D346                    ; load A into v-blank-prev
   1.264 +   0x20   ;D347
   1.265 +   0xD3   ;D348
   1.266 +
   1.267 +   0xC3   ;D349                   ; return to beginning
   1.268 +   0x1D   ;D34A
   1.269 +   0xD3   ;D34B
   1.270 +
   1.271 +   0x00   ;D34C                   ; these are here 
   1.272 +   0x00   ;D34D                   ; for glue
   1.273 +   
   1.274 +   
   1.275 +        ;;; calculate input number based on button presses
   1.276 +   0x18   ;D34E                    ;  skip next 3 bytes
   1.277 +   0x03   ;D34F
   1.278 +                                        ;D350
   1.279 +   (Integer/parseInt "00100000" 2) ;  select directional pad
   1.280 +                                        ;D351
   1.281 +   (Integer/parseInt "00010000" 2) ;  select buttons
   1.282 +   0x00   ;D352                    ;  input-number
   1.283 +
   1.284 +   ;; select directional pad, store low bits in B
   1.285 +   
   1.286 +   0xFA   ;D353                    ; load (D350) into A
   1.287 +   0x50   ;D354      -->       
   1.288 +   0xD3   ;D355      -->  D31F     
   1.289 +   
   1.290 +   0xEA   ;D356                    ; load (A), which is 
   1.291 +   0x00   ;D357      -->           ; 00010000, into FF00
   1.292 +   0xFF   ;D358      -->  FF00     
   1.293 +
   1.294 +   0x06   ;D359
   1.295 +                                        ;D35A
   1.296 +   (Integer/parseInt "11110000" 2) ; "11110000" -> B 
   1.297 +   0xFA   ;D35B                    ; (FF00) -> A
   1.298 +   0x00   ;D35C                   
   1.299 +   0xFF   ;D35D
   1.300 +
   1.301 +   0xCB   ;D35E                    ; swap nybbles on A
   1.302 +   0x37   ;D35F
   1.303 +   0xA0   ;D360                    ; (AND A B) -> A
   1.304 +   0x47   ;D361                    ; A -> B
   1.305 +
   1.306 +   ;; select buttons store bottom bits in C
   1.307 +   
   1.308 +   0xFA   ;                        ; load (D351) into A
   1.309 +   0x51   ;          -->       
   1.310 +   0xD3   ;          -->  D31F     
   1.311 +   
   1.312 +   0xEA   ;                        ; load (A), which is 
   1.313 +   0x00   ;          -->           ; 00001000, into FF00
   1.314 +   0xFF   ;          -->  FF00     
   1.315 +
   1.316 +   0x0E   ;    
   1.317 +   (Integer/parseInt "00001111" 2) ; "00001111" -> C 
   1.318 +
   1.319 +   0xFA   ;                        ; (FF00) -> A
   1.320 +   0x00   ;                       
   1.321 +   0xFF   ;    
   1.322 +   
   1.323 +   0xA1   ;                        ; (AND A C) -> A
   1.324 +   0x4F   ;                        ; A -> C
   1.325 +
   1.326 +   ;; combine the B and C registers into the input number
   1.327 +   0x79   ;                        ; C -> A
   1.328 +   0xB0   ;                        ; (OR A B) -> A
   1.329 +   0x2F   ;                        ; negate A
   1.330 +
   1.331 +   0xEA   ;                        ; store A into input-number
   1.332 +   0x52   ;
   1.333 +   0xD3   ;
   1.334 +
   1.335 +   0xC3   ;                        ; return to beginning
   1.336 +   0x1D   ;    
   1.337 +   0xD3   ;    
   1.338 +   ])
   1.339  
   1.340  (defn input-number []
   1.341    (-> (tick (mid-game))
   1.342        (IE! 0) ; disable interrupts
   1.343 -      (inject-item-assembly
   1.344 -       [0x18   ;D31D                    ; jump over          
   1.345 -        0x02   ;D31E                    ; the next 2 bytes
   1.346 -        0x00   ;D31F                    ; frame-count
   1.347 -        0x00   ;D320                    ; v-blank-prev
   1.348 -        
   1.349 -        0xFA   ;D321
   1.350 -        0x41   ;D322                    ; load (FF41) into A
   1.351 -        0xFF   ;D323                    ; this contains mode flags
   1.352 -        
   1.353 -        ;; if we're in v-blank, the bit-1 is 0
   1.354 -        ;; and bit-2 is 1  Otherwise, it is not v-blank.
   1.355 -        0xCB   ;D324                     ; test bit-1 of A
   1.356 -        0x4F   ;D325                         
   1.357 -
   1.358 -        0xC2   ;D326                     ; if bit-1 is not 0
   1.359 -        0x44   ;D327                     ; GOTO not-v-blank
   1.360 -        0xD3   ;D328
   1.361 -        
   1.362 -        0xCB   ;D329                     ; test bit-0 of A 
   1.363 -        0x47   ;D32A
   1.364 -
   1.365 -        0xCA   ;D32B                     ; if bit-0 is not 1
   1.366 -        0x44   ;D32C                     ; GOTO not-v-blank
   1.367 -        0xD3   ;D32D
   1.368 -        
   1.369 -        ;;; in v-blank mode
   1.370 -
   1.371 -           ;; if v-blank-prev was 0,
   1.372 -           ;; increment frame-count
   1.373 -
   1.374 -        0xFA   ;D32E                    ; load v-blank-prev to A
   1.375 -        0x20   ;D32F
   1.376 -        0xD3   ;D330
   1.377 -        
   1.378 -        0xCB   ;D331
   1.379 -        0x47   ;D332                    ; test bit-0 of A 
   1.380 -
   1.381 -        0x20   ;D333                    ; skip next section
   1.382 -        0x07   ;D334                    ; if v-blank-prev was not zero 
   1.383 -        
   1.384 -           ;; v-blank was 0, increment frame-count
   1.385 -        0xFA   ;D335                    ; load frame-count into A
   1.386 -        0x1F   ;D336
   1.387 -        0xD3   ;D337                   
   1.388 -
   1.389 -        0x3C   ;D338                    ; inc A
   1.390 -
   1.391 -        0xEA   ;D339                    ; load A into frame-count
   1.392 -        0x1F   ;D33A
   1.393 -        0xD3   ;D33B
   1.394 -
   1.395 -           ;; set v-blank-prev to 1
   1.396 -        0x3E   ;D33C                    ; load 1 into A
   1.397 -        0x01   ;D33D                    
   1.398 -
   1.399 -        0xEA   ;D33E                    ; load A into v-blank-prev
   1.400 -        0x20   ;D33F
   1.401 -        0xD3   ;D340
   1.402 -
   1.403 -        0xC3   ;D341                   ; GOTO input handling code
   1.404 -        0x4E   ;D342
   1.405 -        0xD3   ;D343
   1.406 -
   1.407 -        ;;; not in v-blank mode
   1.408 -           ;; set v-blank-prev to 0
   1.409 -        0x3E   ;D344                    ; load 0 into A        
   1.410 -        0x00   ;D345
   1.411 -
   1.412 -        0xEA   ;D346                    ; load A into v-blank-prev
   1.413 -        0x20   ;D347
   1.414 -        0xD3   ;D348
   1.415 -
   1.416 -        0xC3   ;D349                   ; return to beginning
   1.417 -        0x1D   ;D34A
   1.418 -        0xD3   ;D34B
   1.419 -
   1.420 -        0x00   ;D34C                   ; these are here 
   1.421 -        0x00   ;D34D                   ; for glue
   1.422 -       
   1.423 -        
   1.424 -        ;;; calculate input number based on button presses
   1.425 -        0x18   ;D34E                    ;  skip next 3 bytes
   1.426 -        0x03   ;D34F
   1.427 -               ;D350
   1.428 -        (Integer/parseInt "00100000" 2) ;  select directional pad
   1.429 -               ;D351
   1.430 -        (Integer/parseInt "00010000" 2) ;  select buttons
   1.431 -        0x00   ;D352                    ;  input-number
   1.432 -
   1.433 -        ;; select directional pad, store low bits in B
   1.434 -        
   1.435 -        0xFA   ;D353                    ; load (D350) into A
   1.436 -        0x50   ;D354      -->       
   1.437 -        0xD3   ;D355      -->  D31F     
   1.438 -        
   1.439 -        0xEA   ;D356                    ; load (A), which is 
   1.440 -        0x00   ;D357      -->           ; 00010000, into FF00
   1.441 -        0xFF   ;D358      -->  FF00     
   1.442 -
   1.443 -        0x06   ;D359
   1.444 -               ;D35A
   1.445 -        (Integer/parseInt "11110000" 2) ; "11110000" -> B 
   1.446 -        0xFA   ;D35B                    ; (FF00) -> A
   1.447 -        0x00   ;D35C                   
   1.448 -        0xFF   ;D35D
   1.449 -
   1.450 -        0xCB   ;D35E                    ; swap nybbles on A
   1.451 -        0x37   ;D35F
   1.452 -        0xA0   ;D360                    ; (AND A B) -> A
   1.453 -        0x47   ;D361                    ; A -> B
   1.454 -
   1.455 -        ;; select buttons store bottom bits in C
   1.456 -        
   1.457 -        0xFA   ;                        ; load (D351) into A
   1.458 -        0x51   ;          -->       
   1.459 -        0xD3   ;          -->  D31F     
   1.460 -        
   1.461 -        0xEA   ;                        ; load (A), which is 
   1.462 -        0x00   ;          -->           ; 00001000, into FF00
   1.463 -        0xFF   ;          -->  FF00     
   1.464 -
   1.465 -        0x0E   ;    
   1.466 -        (Integer/parseInt "00001111" 2) ; "00001111" -> C 
   1.467 -
   1.468 -        0xFA   ;                        ; (FF00) -> A
   1.469 -        0x00   ;                       
   1.470 -        0xFF   ;    
   1.471 -       
   1.472 -        0xA1   ;                        ; (AND A C) -> A
   1.473 -        0x4F   ;                        ; A -> C
   1.474 -
   1.475 -
   1.476 -        ;; combine the B and C registers into the input number
   1.477 -        0x79   ;                        ; C -> A
   1.478 -        0xB0   ;                        ; (OR A B) -> A
   1.479 -        0x2F   ;                        ; negate A
   1.480 -
   1.481 -        0xEA   ;                        ; store A into input-number
   1.482 -        0x52   ;
   1.483 -        0xD3   ;
   1.484 -
   1.485 -        0xC3   ;                        ; return to beginning
   1.486 -        0x1D   ;    
   1.487 -        0xD3   ;    
   1.488 -        ])))
   1.489 -
   1.490 -(defn print-listing [state begin end]
   1.491 -  (dorun (map 
   1.492 -          (fn [opcode line]
   1.493 -            (println (format "0x%04X:  0x%02X" line opcode)))
   1.494 -          (subvec  (vec (memory state)) begin end)
   1.495 -          (range begin end)))
   1.496 -  state)
   1.497 +      (inject-item-assembly (input-number-assembly))))
   1.498    
   1.499  (defn test-input-number
   1.500    "Input freestyle buttons and observe the effects at the repl."
   1.501 @@ -452,6 +442,288 @@
   1.502    (set-state! (input-number)) 
   1.503    (dotimes [_ 90000] (step (view-memory @current-state 0xD352))))
   1.504  
   1.505 +(defn write-memory-assembly []
   1.506 +  [0x18   ;D31D                    ; jump over          
   1.507 +   0x02   ;D31E                    ; the next 2 bytes
   1.508 +   0x00   ;D31F                    ; frame-count
   1.509 +   0x00   ;D320                    ; v-blank-prev
   1.510 +   
   1.511 +   0xFA   ;D321
   1.512 +   0x41   ;D322                    ; load (FF41) into A
   1.513 +   0xFF   ;D323                    ; this contains mode flags
   1.514 +   
   1.515 +   ;; if we're in v-blank, the bit-1 is 0
   1.516 +   ;; and bit-2 is 1  Otherwise, it is not v-blank.
   1.517 +   0xCB   ;D324                     ; test bit-1 of A
   1.518 +   0x4F   ;D325                         
   1.519  
   1.520 +   0xC2   ;D326                     ; if bit-1 is not 0
   1.521 +   0x44   ;D327                     ; GOTO not-v-blank
   1.522 +   0xD3   ;D328
   1.523 +   
   1.524 +   0xCB   ;D329                     ; test bit-0 of A 
   1.525 +   0x47   ;D32A
   1.526  
   1.527 +   0xCA   ;D32B                     ; if bit-0 is not 1
   1.528 +   0x44   ;D32C                     ; GOTO not-v-blank
   1.529 +   0xD3   ;D32D
   1.530 +   
   1.531 +        ;;; in v-blank mode
   1.532  
   1.533 +   ;; if v-blank-prev was 0,
   1.534 +   ;; increment frame-count
   1.535 +
   1.536 +   0xFA   ;D32E                    ; load v-blank-prev to A
   1.537 +   0x20   ;D32F
   1.538 +   0xD3   ;D330
   1.539 +   
   1.540 +   0xCB   ;D331
   1.541 +   0x47   ;D332                    ; test bit-0 of A 
   1.542 +
   1.543 +   0x20   ;D333                    ; skip next section
   1.544 +   0x07   ;D334                    ; if v-blank-prev was not zero 
   1.545 +   
   1.546 +   ;; v-blank was 0, increment frame-count
   1.547 +   0xFA   ;D335                    ; load frame-count into A
   1.548 +   0x1F   ;D336
   1.549 +   0xD3   ;D337                   
   1.550 +
   1.551 +   0x3C   ;D338                    ; inc A
   1.552 +
   1.553 +   0xEA   ;D339                    ; load A into frame-count
   1.554 +   0x1F   ;D33A
   1.555 +   0xD3   ;D33B
   1.556 +
   1.557 +   ;; set v-blank-prev to 1
   1.558 +   0x3E   ;D33C                    ; load 1 into A
   1.559 +   0x01   ;D33D                    
   1.560 +
   1.561 +   0xEA   ;D33E                    ; load A into v-blank-prev
   1.562 +   0x20   ;D33F
   1.563 +   0xD3   ;D340
   1.564 +
   1.565 +   0xC3   ;D341                   ; GOTO input handling code
   1.566 +   0x4E   ;D342
   1.567 +   0xD3   ;D343
   1.568 +
   1.569 +        ;;; not in v-blank mode
   1.570 +   ;; set v-blank-prev to 0
   1.571 +   0x3E   ;D344                    ; load 0 into A        
   1.572 +   0x00   ;D345
   1.573 +
   1.574 +   0xEA   ;D346                    ; load A into v-blank-prev
   1.575 +   0x20   ;D347
   1.576 +   0xD3   ;D348
   1.577 +
   1.578 +   0xC3   ;D349                   ; return to beginning
   1.579 +   0x1D   ;D34A
   1.580 +   0xD3   ;D34B
   1.581 +
   1.582 +   0x00   ;D34C                   ; these are here 
   1.583 +   0x00   ;D34D                   ; for glue
   1.584 +   
   1.585 +   
   1.586 +        ;;; calculate input number based on button presses
   1.587 +   0x18   ;D34E                    ;  skip next 3 bytes
   1.588 +   0x03   ;D34F
   1.589 +                                        ;D350
   1.590 +   (Integer/parseInt "00100000" 2) ;  select directional pad
   1.591 +                                        ;D351
   1.592 +   (Integer/parseInt "00010000" 2) ;  select buttons
   1.593 +   0x00   ;D352                    ;  input-number
   1.594 +
   1.595 +   ;; select directional pad, store low bits in B
   1.596 +   
   1.597 +   0xFA   ;D353                    ; load (D350) into A
   1.598 +   0x50   ;D354      -->       
   1.599 +   0xD3   ;D355      -->  D31F     
   1.600 +   
   1.601 +   0xEA   ;D356                    ; load (A), which is 
   1.602 +   0x00   ;D357      -->           ; 00010000, into FF00
   1.603 +   0xFF   ;D358      -->  FF00     
   1.604 +
   1.605 +   0x06   ;D359
   1.606 +                                        ;D35A
   1.607 +   (Integer/parseInt "11110000" 2) ; "11110000" -> B 
   1.608 +   0xFA   ;D35B                    ; (FF00) -> A
   1.609 +   0x00   ;D35C                   
   1.610 +   0xFF   ;D35D
   1.611 +
   1.612 +   0xCB   ;D35E                    ; swap nybbles on A
   1.613 +   0x37   ;D35F
   1.614 +   0xA0   ;D360                    ; (AND A B) -> A
   1.615 +   0x47   ;D361                    ; A -> B
   1.616 +
   1.617 +   ;; select buttons store bottom bits in C
   1.618 +   
   1.619 +   0xFA   ;D362                    ; load (D351) into A
   1.620 +   0x51   ;D363      -->       
   1.621 +   0xD3   ;D364      -->  D31F     
   1.622 +   
   1.623 +   0xEA   ;D365                    ; load (A), which is 
   1.624 +   0x00   ;D366      -->           ; 00001000, into FF00
   1.625 +   0xFF   ;D367      -->  FF00     
   1.626 +
   1.627 +   0x0E   ;D368
   1.628 +          ;D369
   1.629 +   (Integer/parseInt "00001111" 2) ; "00001111" -> C 
   1.630 +
   1.631 +   0xFA   ;D36A                    ; (FF00) -> A
   1.632 +   0x00   ;D36B                   
   1.633 +   0xFF   ;D36C
   1.634 +   
   1.635 +   0xA1   ;D36D                    ; (AND A C) -> A
   1.636 +   0x4F   ;D36E                    ; A -> C
   1.637 +
   1.638 +   ;; combine the B and C registers into the input number
   1.639 +   0x79   ;D36F                    ; C -> A
   1.640 +   0xB0   ;D370                    ; (OR A B) -> A
   1.641 +   0x2F   ;D371                    ; negate A
   1.642 +
   1.643 +   0xEA   ;D372                    ; store A into input-number
   1.644 +   0x52   ;D373
   1.645 +   0xD3   ;D374
   1.646 +
   1.647 +   0xC3   ;D375                    ; GOTO state machine
   1.648 +   ;;0x1D
   1.649 +   0x80   ;D376
   1.650 +   0xD3   ;D377
   1.651 +
   1.652 +   0x00   ;D378
   1.653 +   0x00   ;D379
   1.654 +   0x00   ;D37A
   1.655 +   0x00   ;D37B                   ; these are here because 
   1.656 +   0x00   ;D37C                   ; I messed up :(
   1.657 +   0x00   ;D37D
   1.658 +   0x00   ;D37E
   1.659 +   0x00   ;D37F
   1.660 +   
   1.661 +   ;; beginning of main state machine   
   1.662 +   0x18   ;D380                    ; Declaration of variables
   1.663 +   0x05   ;D381                    ;  5 variables:
   1.664 +   0x00   ;D382                    ;    current-mode
   1.665 +   0x00   ;D383                    ;    bytes-left-to-write
   1.666 +   0x00   ;D384                    ;    unused
   1.667 +   0x00   ;D385                    ;    unused
   1.668 +   0x00   ;D386                    ;    unused
   1.669 +
   1.670 +
   1.671 +   ;; banch on current mode
   1.672 +   ;;   mode 0 -- input-mode mode
   1.673 +   ;;     means that we are waiting for a mode, so set the mode to
   1.674 +   ;;     whatever is currently in input number.  If nothing is
   1.675 +   ;;     entered, then the program stays in input-mode mode
   1.676 +
   1.677 +   0xFA   ;D387                    ; load current-mode (0xD382)
   1.678 +   0x82   ;D388                    ; into A
   1.679 +   0xD3   ;D389
   1.680 +   
   1.681 +   0x00   ;D38A
   1.682 +
   1.683 +   0xFE   ;D38B
   1.684 +   0x00   ;D38C                    ; compare A with 0x00
   1.685 +
   1.686 +   ;; TODO make this jump non-absolute
   1.687 +   
   1.688 +   0xCA   ;D38D                    ; GOTO Mode 0 if current-mode is 0
   1.689 +   0xA8   ;D38E
   1.690 +   0xD3   ;D38F
   1.691 +
   1.692 +   0x00   ;D390
   1.693 +   0x00   ;D391
   1.694 +   0x00   ;D392
   1.695 +   0x00   ;D393
   1.696 +   0x00   ;D394
   1.697 +   0x00   ;D395
   1.698 +   0x00   ;D396
   1.699 +   0x00   ;D397
   1.700 +   0x00   ;D398
   1.701 +   0x00   ;D399
   1.702 +   0x00   ;D39A
   1.703 +   0x00   ;D39B
   1.704 +   0x00   ;D39C
   1.705 +   0x00   ;D39D
   1.706 +   0x00   ;D39E
   1.707 +   0x00   ;D39F
   1.708 +   0x00   ;D3A0
   1.709 +   0x00   ;D3A1
   1.710 +   0x00   ;D3A2
   1.711 +   0x00   ;D3A3
   1.712 +   0x00   ;D3A4
   1.713 +   ;; End of Mode checking, goto beginning
   1.714 +   0xC3   ;D3A5
   1.715 +   0x1D   ;D3A6
   1.716 +   0xD3   ;D3A7
   1.717 +   ;; Mode 0
   1.718 +   ;;   set current-mode to input-number
   1.719 +   0xFA   ;D3A8                    ; load input-number (0xD352) 
   1.720 +   0x52   ;D3A9                    ; into A
   1.721 +   0xD3   ;D3AA
   1.722 +
   1.723 +   0xEA   ;D3AB                    ; load A into current-mode
   1.724 +   0x82   ;D3AC                    ; (0xD382)
   1.725 +   0xD3   ;D3AD
   1.726 +
   1.727 +   0xC3   ;D3AE                    ; go back to beginning
   1.728 +   0x1D   ;D3AF
   1.729 +   0xD3   ;D3B0
   1.730 +
   1.731 +   0x00   ;D3B1
   1.732 +   0x00   ;D3B2
   1.733 +   0x00   ;D3B3
   1.734 +   0x00   ;D3B4
   1.735 +   0x00   ;D3B5
   1.736 +   0x00   ;D3B6
   1.737 +   0x00   ;D3B7
   1.738 +   0x00   ;D3B8
   1.739 +   0x00   ;D3B9
   1.740 +   0x00   ;D3BA
   1.741 +   0x00   ;D3BB
   1.742 +   0x00   ;D3BC
   1.743 +   0x00   ;D3BD
   1.744 +   0x00   ;D3BE
   1.745 +   0x00   ;D3BF
   1.746 +   0x00   ;D3C0
   1.747 +   0x00   ;D3C1
   1.748 +   0x00   ;D3C2
   1.749 +   0x00   ;D3C3
   1.750 +   0x00   ;D3C4
   1.751 +   0x00   ;D3C5
   1.752 +   0x00   ;D3C6
   1.753 +   0x00   ;D3C7
   1.754 +   0x00   ;D3C8
   1.755 +   0x00   ;D3C9
   1.756 +   0x00   ;D3CA
   1.757 +   0x00   ;D3CB
   1.758 +   0x00   ;D3CC
   1.759 +   0x00   ;D3CD
   1.760 +   0x00   ;D3CE
   1.761 +   0x00   ;D3CF
   1.762 +   0x00   ;D3D0
   1.763 +   0x00   ;D3D1
   1.764 +   0x00   ;D3D2
   1.765 +   0x00   ;D3D3
   1.766 +   0x00   ;D3D4
   1.767 +   0x00   ;D3D5
   1.768 +   0x00   ;D3D6
   1.769 +
   1.770 +
   1.771 +
   1.772 +
   1.773 +   0xC3   ;                        ; Complete Loop
   1.774 +   0x1D   ;    
   1.775 +   0xD3   ;    
   1.776 +
   1.777 +   
   1.778 +   
   1.779 +   ])
   1.780 +
   1.781 +
   1.782 +(def frame-count 0xD31F)
   1.783 +(def input 0xD352)
   1.784 +(def current-mode 0xD382)
   1.785 +
   1.786 +(defn write-memory []
   1.787 +  (-> (tick (mid-game))
   1.788 +      (IE! 0) ; disable interrupts
   1.789 +      (inject-item-assembly (write-memory-assembly))))