view clojure/com/aurellem/assembly.clj @ 123:c9a280b8bd1c

saving progress.
author Robert McIntyre <rlm@mit.edu>
date Sat, 17 Mar 2012 00:29:34 -0500
parents e85b53994fac
children f8dadd9478a5
line wrap: on
line source
1 (ns com.aurellem.assembly
2 (:use (com.aurellem gb-driver vbm title items))
3 (:import [com.aurellem.gb_driver SaveState]))
5 (defn mid-game []
6 (read-state "mid-game"))
8 (defn inject-assembly
9 ([^SaveState state
10 program-counter registers
11 assembly-code]
12 (let [scratch-memory (memory state)]
13 ;; inject assembly code
14 (dorun (map (fn [index val]
15 (aset scratch-memory index val))
16 (range program-counter
17 (+ program-counter (count assembly-code)))
18 assembly-code))
19 (-> state
20 (write-memory! scratch-memory)
21 (write-registers! registers)
22 (PC! program-counter)))))
24 (defn inject-item-assembly
25 ([^SaveState state assembly-code]
26 (inject-assembly state (inc item-list-start)
27 (registers state)
28 assembly-code))
29 ([assembly-code]
30 (inject-item-assembly @current-state assembly-code)))
32 (defn info
33 ([^SaveState state]
34 (println (format "PC: 0x%04X" (PC state)))
35 (println "Instruction:"
36 (format "0x%02X" (aget (memory state) (PC state))))
37 state))
39 (defn print-interrupt
40 [^SaveState state]
41 (println (format "IE: %d" (IE state)))
42 state)
44 (defn print-listing [state begin end]
45 (dorun (map
46 (fn [opcode line]
47 (println (format "0x%04X: 0x%02X" line opcode)))
48 (subvec (vec (memory state)) begin end)
49 (range begin end)))
50 state)
52 (defn run-assembly
53 ([info-fn assembly n]
54 (let [final-state
55 (reduce (fn [state _]
56 (tick (info-fn state)))
57 (inject-item-assembly
58 (mid-game) assembly)
59 (range n))]
60 final-state))
61 ([assembly n]
62 (run-assembly info assembly n)))
64 (def buttons-port 0xFF00)
66 (defn A [state]
67 (bit-shift-right (bit-and 0x0000FF00 (AF state)) 8))
69 (defn binary-str [num]
70 (format "%08d"
71 (Integer/parseInt
72 (Integer/toBinaryString num) 10)))
74 (defn view-register [state name reg-fn]
75 (println (format "%s: %s" name
76 (binary-str (reg-fn state))))
77 state)
79 (defn view-memory [state mem]
80 (println (format "mem 0x%04X = %s" mem
81 (binary-str (aget (memory state) mem))))
82 state)
84 (defn trace [state]
85 (loop [program-counters []
86 opcodes []]
87 (let [frame-boundary?
88 (com.aurellem.gb.Gb/tick)]
89 (println (count opcodes))
90 (if frame-boundary?
91 [program-counters opcodes]
92 (recur
93 (conj program-counters
94 (first (registers @current-state)))
95 (conj opcodes
96 (aget (memory @current-state)
97 (PC @current-state))))))))
99 (defn good-trace []
100 (-> (mid-game) (tick) (IE! 0)
101 (set-inv-mem [0x00 0x00 0X00 0x00])
102 (PC! item-list-start)(print-interrupt)
103 (info) (tick) (info) (tick) (info)))
105 (defn read-down-button []
106 (-> (tick (mid-game))
107 (IE! 0) ; disable interrupts
108 (inject-item-assembly
109 ;; write 00010000 to 0xFF00 to select joypad
110 [0x18 ;D31D ; jump over
111 0x01 ;D31E ; the next 8 bits
112 ;D31F
113 (Integer/parseInt "00100000" 2) ; data section
115 0xFA ;D320 ; load (D31F) into A
116 0x1F ;D321 -->
117 0xD3 ;D322 --> D31F
119 0xEA ;D323 ; load (A), which is
120 0x00 ;D324 --> ; 00010000, into FF00
121 0xFF ;D325 --> FF00
123 0x18 ;D326 ; this is the place where
124 0x01 ;D327 ; we will store whether
125 0x00 ;D328 ; "down" is pressed.
127 0xFA ;D329 ; (FF00) -> A
128 0x00 ;D32A
129 0xFF ;D32B
131 0xCB ;D32C ; Test whether "down"
132 0x5F ;D32D ; is pressed.
134 0x28 ;D32E ; if down is pressed,
135 0x03 ;D32F ; skip the next section
136 ; of code.
137 ;; down-is-not-pressed
138 0xC3 ;D330
139 0x1D ;D331 ; return to beginning
140 0xD3 ;D332
142 ;; down-is-pressed
143 0xEA ;D334 ; write A to D328 if
144 0x28 ;D335 ; "down" was pressed
145 0xD3 ;D336
147 0xC3 ;D330
148 0x1D ;D331 ; return to beginning
149 0xD3 ;D332
150 ])))
152 (defn test-read-down []
153 (= (view-memory (step (step (read-down-button) [:d])) 0xD328)
154 (view-memory (step (step (read-down-button))) 0xD328)))
156 (defn count-frames []
157 (-> (tick (mid-game))
158 (IE! 0) ; disable interrupts
159 (inject-item-assembly
160 [0x18 ;D31D ; jump over
161 0x02 ;D31E ; the next 2 bytes
162 0x00 ;D31F ; frame-count
163 0x00 ;D320 ; v-blank-prev
165 0xFA ;D321
166 0x41 ;D322 ; load (FF41) into A
167 0xFF ;D323 ; this contains mode flags
169 ;; if we're in v-blank, the bit-1 is 0
170 ;; and bit-2 is 1 Otherwise, it is not v-blank.
171 0xCB ;D324 ; test bit-1 of A
172 0x4F ;D325
174 0xC2 ;D326 ; if bit-1 is not 0
175 0x44 ;D327 ; GOTO not-v-blank
176 0xD3 ;D328
178 0xCB ;D329 ; test bit-0 of A
179 0x47 ;D32A
181 0xCA ;D32B ; if bit-0 is not 1
182 0x44 ;D32C ; GOTO not-v-blank
183 0xD3 ;D32D
184 ;;; in v-blank mode
185 ;; if v-blank-prev was 0,
186 ;; increment frame-count
188 0xFA ;D32E ; load v-blank-prev to A
189 0x20 ;D32F
190 0xD3 ;D330
192 0xCB ;D331
193 0x47 ;D332 ; test bit-0 of A
195 0x20 ;D333 ; skip next section
196 0x07 ;D334 ; if v-blank-prev was not zero
198 ;; v-blank was 0, increment frame-count
199 0xFA ;D335 ; load frame-count into A
200 0x1F ;D336
201 0xD3 ;D337
203 0x3C ;D338 ; inc A
205 0xEA ;D339 ; load A into frame-count
206 0x1F ;D33A
207 0xD3 ;D33B
209 ;; set v-blank-prev to 1
210 0x3E ;D33C ; load 1 into A
211 0x01 ;D33D
213 0xEA ;D33E ; load A into v-blank-prev
214 0x20 ;D33F
215 0xD3 ;D340
217 0xC3 ;D341 ; return to beginning
218 0x1D ;D342
219 0xD3 ;D343
221 ;;; not in v-blank mode
222 ;; set v-blank-prev to 0
223 0x3E ;D344 ; load 0 into A
224 0x00 ;D345
226 0xEA ;D346 ; load A into v-blank-prev
227 0x20 ;D347
228 0xD3 ;D348
230 0xC3 ;D349 ; return to beginning
231 0x1D ;D34A
232 0xD3 ;D34B
233 ])))
235 (defn step-count-frames []
236 (-> (read-down-button)
237 (info)
238 (tick) ;; skip over data section
239 (info)
240 (view-register "Register A" A)
241 (tick) ;; load-data into A
242 (view-register "Register A" A)
243 (info)
244 (view-memory 0xFF00)
245 (tick) ;; load A into 0xFF00
246 (view-memory 0xFF00)
247 (info)
248 (tick)
249 (info)
250 (tick)
251 (info)
252 (tick)
253 (info)
254 (tick)
255 (info)
256 (tick)
257 (info)
258 (tick)
259 (print-inventory)))
261 (defn test-count-frames []
262 (= 255 (aget (memory ((apply comp (repeat 255 step))
263 (count-frames)))
264 0xD31F)))
266 ;; specs for main bootstrap program
267 ;; starts in "mode-select" mode
268 ;; Each button press takes place in a single frame.
269 ;; mode-select-mode takes one of the main buttons
270 ;; which selects one of up to eight modes
271 ;; mode 1 activated by the "A" button
272 ;; the next two button presses indicates the start
273 ;; memory location which to which the bootstrap
274 ;; program will write.
275 ;; This is done by using each of the eight buttons to
276 ;; spell out an 8 bit number. The order of buttons is
277 ;; [:d :u :l :r :start :select :b :a]
278 ;; [:a :start :l] --> 00101001
280 ;; the next button press determines how many bytes are to be
281 ;; written, starting at the start position.
283 ;; then, the actual bytes are entered and are written to the
284 ;; start address in sequence.
286 (defn input-number-assembly []
287 [0x18 ;D31D ; jump over
288 0x02 ;D31E ; the next 2 bytes
289 0x00 ;D31F ; frame-count
290 0x00 ;D320 ; v-blank-prev
292 0xFA ;D321
293 0x41 ;D322 ; load (FF41) into A
294 0xFF ;D323 ; this contains mode flags
296 ;; if we're in v-blank, the bit-1 is 0
297 ;; and bit-2 is 1 Otherwise, it is not v-blank.
298 0xCB ;D324 ; test bit-1 of A
299 0x4F ;D325
301 0xC2 ;D326 ; if bit-1 is not 0
302 0x44 ;D327 ; GOTO not-v-blank
303 0xD3 ;D328
305 0xCB ;D329 ; test bit-0 of A
306 0x47 ;D32A
308 0xCA ;D32B ; if bit-0 is not 1
309 0x44 ;D32C ; GOTO not-v-blank
310 0xD3 ;D32D
312 ;;; in v-blank mode
314 ;; if v-blank-prev was 0,
315 ;; increment frame-count
317 0xFA ;D32E ; load v-blank-prev to A
318 0x20 ;D32F
319 0xD3 ;D330
321 0xCB ;D331
322 0x47 ;D332 ; test bit-0 of A
324 0x20 ;D333 ; skip next section
325 0x07 ;D334 ; if v-blank-prev was not zero
327 ;; v-blank was 0, increment frame-count
328 0xFA ;D335 ; load frame-count into A
329 0x1F ;D336
330 0xD3 ;D337
332 0x3C ;D338 ; inc A
334 0xEA ;D339 ; load A into frame-count
335 0x1F ;D33A
336 0xD3 ;D33B
338 ;; set v-blank-prev to 1
339 0x3E ;D33C ; load 1 into A
340 0x01 ;D33D
342 0xEA ;D33E ; load A into v-blank-prev
343 0x20 ;D33F
344 0xD3 ;D340
346 0xC3 ;D341 ; GOTO input handling code
347 0x4E ;D342
348 0xD3 ;D343
350 ;;; not in v-blank mode
351 ;; set v-blank-prev to 0
352 0x3E ;D344 ; load 0 into A
353 0x00 ;D345
355 0xEA ;D346 ; load A into v-blank-prev
356 0x20 ;D347
357 0xD3 ;D348
359 0xC3 ;D349 ; return to beginning
360 0x1D ;D34A
361 0xD3 ;D34B
363 0x00 ;D34C ; these are here
364 0x00 ;D34D ; for glue
367 ;;; calculate input number based on button presses
368 0x18 ;D34E ; skip next 3 bytes
369 0x03 ;D34F
370 ;D350
371 (Integer/parseInt "00100000" 2) ; select directional pad
372 ;D351
373 (Integer/parseInt "00010000" 2) ; select buttons
374 0x00 ;D352 ; input-number
376 ;; select directional pad, store low bits in B
378 0xFA ;D353 ; load (D350) into A
379 0x50 ;D354 -->
380 0xD3 ;D355 --> D31F
382 0xEA ;D356 ; load (A), which is
383 0x00 ;D357 --> ; 00010000, into FF00
384 0xFF ;D358 --> FF00
386 0x06 ;D359
387 ;D35A
388 (Integer/parseInt "11110000" 2) ; "11110000" -> B
389 0xFA ;D35B ; (FF00) -> A
390 0x00 ;D35C
391 0xFF ;D35D
393 0xCB ;D35E ; swap nybbles on A
394 0x37 ;D35F
395 0xA0 ;D360 ; (AND A B) -> A
396 0x47 ;D361 ; A -> B
398 ;; select buttons store bottom bits in C
400 0xFA ; ; load (D351) into A
401 0x51 ; -->
402 0xD3 ; --> D31F
404 0xEA ; ; load (A), which is
405 0x00 ; --> ; 00001000, into FF00
406 0xFF ; --> FF00
408 0x0E ;
409 (Integer/parseInt "00001111" 2) ; "00001111" -> C
411 0xFA ; ; (FF00) -> A
412 0x00 ;
413 0xFF ;
415 0xA1 ; ; (AND A C) -> A
416 0x4F ; ; A -> C
418 ;; combine the B and C registers into the input number
419 0x79 ; ; C -> A
420 0xB0 ; ; (OR A B) -> A
421 0x2F ; ; negate A
423 0xEA ; ; store A into input-number
424 0x52 ;
425 0xD3 ;
427 0xC3 ; ; return to beginning
428 0x1D ;
429 0xD3 ;
430 ])
432 (defn input-number []
433 (-> (tick (mid-game))
434 (IE! 0) ; disable interrupts
435 (inject-item-assembly (input-number-assembly))))
437 (defn test-input-number
438 "Input freestyle buttons and observe the effects at the repl."
439 []
440 (set-state! (input-number))
441 (dotimes [_ 90000] (step (view-memory @current-state 0xD352))))
443 (defn write-memory-assembly []
444 [
445 ;; Main Timing Loop
446 ;; Constantly check for v-blank and Trigger main state machine on
447 ;; every transtion from v-blank to non-v-blank.
449 0x18 ; D31D ; Variable declaration
450 0x02 ; D31E
451 0x00 ; D31F ; frame-count
452 0x00 ; D320 ; v-blank-prev
454 0xFA ; D321 ; load v-blank mode flags into A
455 0x41 ; D322
456 0xFF ; D323
458 ;; Branch dependent on v-blank. v-blank happens when the last two
459 ;; bits in A are "01"
460 0xCB ; D324
461 0x4F ; D325
463 0xC2 ; D326 ; if bit-1 is not 0, then
464 0x44 ; D327 ; GOTO non-v-blank.
465 0xD3 ; D328
467 0xCB ; D329
468 0x47 ; D32A
470 0xCA ; D32B ; if bit-0 is not 1, then
471 0x44 ; D32C ; GOTO non-v-blank.
472 0xD3 ; D32D
474 ;; V-Blank
475 ;; Activate state-machine if this is a transition event.
477 0xFA ; D32E ; load v-bank-prev into A
478 0x20 ; D32F
479 0xD3 ; D330
481 0xFE ; D331 ; compare A to 0.
482 0x00 ; D332
484 ;; set v-blank-prev to 1.
485 0x3E ; D333 ; load 1 into A.
486 0x01 ; D334
488 0xEA ; D335 ; load A into v-blank-prev
489 0x20 ; D336
490 0xD3 ; D337
492 ;; if v-blank-prev was 0, activate state-machine
493 0xC2 ; D338 ; if v-blank-prev
494 0x46 ; D339 ; was 0,
495 0xD3 ; D33A ; GOTO state-machine
497 0xC3 ; D33B
498 0x1D ; D33C
499 0xD3 ; D33D ; GOTO beginning
500 ;; END V-blank
502 ;; Non-V-Blank
503 ;; Set v-blank-prev to 0
504 0x3E ; D33E ; load 0 into A
505 0x00 ; D33F
507 0xEA ; D340 ; load A into v-blank-prev
508 0x20 ; D341
509 0xD3 ; D342
511 0xC3 ; D343
512 0x1D ; D344
513 0xD3 ; D345 ; GOTO beginning
514 ;; END Not-V-Blank
516 ;; Main State Machine -- Input Section
517 ;; This is called once every frame.
518 ;; It collects input and uses it to drive the
519 ;; state transitions.
521 ;; Increment frame-count
522 0xFA ; D346 ; load frame-count into A
523 0x1F ; D347
524 0xD3 ; D348
526 0x3C ; D349 ; inc A
528 0xEA ; D34A
529 0x1F ; D34B ; load A into frame-count
530 0xD3 ; D34C
532 0x00 ; D34D ; glue :)
535 ;;;;;;;;; BEGIN RLM DEBUG
536 0xC3 ;; jump to beginning
537 0x1D
538 0xD3
540 ;;;;;;;;; END RLM DEBUG
543 0x18 ;D34E ; skip next 3 bytes
544 0x03 ;D34F
545 ;D350
546 (Integer/parseInt "00100000" 2) ; select directional pad
547 ;D351
548 (Integer/parseInt "00010000" 2) ; select buttons
549 0x00 ;D352 ; input-number
551 ;; select directional pad; store low bits in B
553 0xFA ;D353 ; load (D350) into A
554 0x50 ;D354 -->
555 0xD3 ;D355 --> D350
557 0xEA ;D356 ; load (A), which is
558 0x00 ;D357 --> ; 00010000, into FF00
559 0xFF ;D358 --> FF00
561 0x06 ;D359
562 ;D35A
563 (Integer/parseInt "11110000" 2) ; "11110000" -> B
564 0xFA ;D35B ; (FF00) -> A
565 0x00 ;D35C
566 0xFF ;D35D
568 0xCB ;D35E ; swap nybbles on A
569 0x37 ;D35F
570 0xA0 ;D360 ; (AND A B) -> A
571 0x47 ;D361 ; A -> B
573 ;; select buttons; store bottom bits in C
575 0xFA ;D362 ; load (D351) into A
576 0x51 ;D363 -->
577 0xD3 ;D364 --> D351
579 0xEA ;D365 ; load (A), which is
580 0x00 ;D366 --> ; 00001000, into FF00
581 0xFF ;D367 --> FF00
583 0x0E ;D368
584 ;D369
585 (Integer/parseInt "00001111" 2) ; "00001111" -> C
587 0xFA ;D36A ; (FF00) -> A
588 0x00 ;D36B
589 0xFF ;D36C
591 0xA1 ;D36D ; (AND A C) -> A
592 0x4F ;D36E ; A -> C
594 ;; combine the B and C registers into the input number
595 0x79 ;D36F ; C -> A
596 0xB0 ;D370 ; (OR A B) -> A
597 0x2F ;D371 ; negate A
599 0xEA ;D372 ; store A into input-number
600 0x52 ;D373
601 0xD3 ;D374
603 0xC3 ;D375 ; secret jump :)
604 0x1D ;D376
605 0xD3 ;D377
606 0x00 ;D378
607 0x00 ;D379
608 0x00 ;D37A
609 0x00 ;D37B ; these are here because
610 0x00 ;D37C ; I messed up :(
611 0x00 ;D37D
612 0x00 ;D37E
613 0x00 ;D37F
615 ;; beginning of main state machine
616 0x18 ;D380 ; Declaration of variables
617 0x05 ;D381 ; 5 variables:
618 0x00 ;D382 ; current-mode
619 0x00 ;D383 ; bytes-to-write
620 0x00 ;D384 ; start-point
621 0x00 ;D385 ; unused
622 0x00 ;D386 ; unused
625 ;; banch on current mode
626 0xFA ;D387 ; load current-mode (0xD382)
627 0x82 ;D388 ; into A
628 0xD3 ;D389
629 0x00 ;D38A
632 ;; GOTO Mode 0 (input-mode) if current-mode is 0
633 0xFE ;D38B
634 0x00 ;D38C ; compare A with 0x00
636 0xCA ;D38D ; goto Mode 0 if A == 0
637 0xA8 ;D38E
638 0xD3 ;D38F
640 ;; GOTO Mode 1 (set-length) if current-mode is 1
641 0xFE ;D390
642 0x01 ;D391 ; compare A with 0x01
644 0xCA ;D392
645 0xB1 ;D393
646 0xD3 ;D394 ; goto Mode 1 if A == 1
648 ;; GOTO Mode 2 (set-start-point) if current mode is 2
649 0xFE ;D395
650 0x02 ;D396 ; compare A with 0x02
652 0xCA ;D397
653 0xBF ;D398
654 0xD3 ;D399 ; goto Mode 2 if A == 2
656 0x00 ;D39A
657 0x00 ;D39B
658 0x00 ;D39C
659 0x00 ;D39D
660 0x00 ;D39E
661 0x00 ;D39F
662 0x00 ;D3A0
663 0x00 ;D3A1
664 0x00 ;D3A2
665 0x00 ;D3A3
666 0x00 ;D3A4
667 ;; End of Mode checking, goto beginning
668 0xC3 ;D3A5
669 0x1D ;D3A6
670 0xD3 ;D3A7
673 ;; Mode 0 -- input-mode mode
674 ;; means that we are waiting for a mode, so set the mode to
675 ;; whatever is currently in input-number. If nothing is
676 ;; entered, then the program stays in input-mode mode
678 ;; set current-mode to input-number
679 0xFA ;D3A8 ; load input-number (0xD352)
680 0x52 ;D3A9 ; into A
681 0xD3 ;D3AA
683 0xEA ;D3AB ; load A into current-mode
684 0x82 ;D3AC ; (0xD382)
685 0xD3 ;D3AD
687 0xC3 ;D3AE ; go back to beginning
688 0x1D ;D3AF
689 0xD3 ;D3B0
690 ;; End Mode 0
693 ;; Mode 1 -- set-length mode
694 ;; This is the header for writing things to memory.
695 ;; User specifies the number of bytes to write.
696 ;; Mode is auto advanced to Mode 2 after this mode
697 ;; completes.
699 ;; Set bytes left to write to input-number;
700 ;; set current-mode to 0x02.
701 0xFA ;D3B1 ; load input-number (0xD352)
702 0x52 ;D3B2 ; into A
703 0xD3 ;D3B3
705 0xEA ;D3B4 ; load A into bytes-left-to-write
706 0x83 ;D3B5 ; (0xD383)
707 0xD3 ;D3B6
709 0x3E ;D3B7 ; load 0x02 into A.
710 0x02 ;D3B8
712 0xEA ;D3B9 ; load A to current-mode
713 0x82 ;D3BA ; advancing from Mode 1 to
714 0xD3 ;D3BB ; Mode 2
716 0xC3 ;D3BC ; go back to beginning
717 0x1D ;D3BD
718 0xD3 ;D3BE
719 ;; End Mode 1
722 ;; Mode 2 -- set start-point mode
723 ;; Final part of the header for writing things to memory.
724 ;; User specifies the start location in RAM to which
725 ;; data will be written.
726 ;; Mode is auto advanced to Mode 3 after this mode completes.
728 ;; Set start-point to input-number;
729 ;; set current mode to 0x03.
730 0xFA ;D3BF ; load input-number (0xD352)
731 0x52 ;D3C0 ; into A
732 0xD3 ;D3C1
734 0xEA ;D3C2 ; load A into start-point
735 0x84 ;D3C3 ; (0xD384)
736 0xD3 ;D3C4
738 0x3E ;D3C5 ; load 0x03 into A.
739 0x03 ;D3C6
741 0xEA ;D3C7 ; load A to current-mode,
742 0x82 ;D3C8 ; advancing from Mode 2 to
743 0xD3 ;D3C9 ; Mode 3.
745 0xC3 ;D3CA ; go back to beginning
746 0x1D ;D3CB
747 0xD3 ;D3CC
748 ;;End Mode 2
750 0x00 ;D3CD
751 0x00 ;D3CE
752 0x00 ;D3CF
753 0x00 ;D3D0
754 0x00 ;D3D1
755 0x00 ;D3D2
756 0x00 ;D3D3
757 0x00 ;D3D4
758 0x00 ;D3D5
759 0x00 ;D3D6
761 ;; Mode 3 -- write bytes mode
762 ;; This is where RAM manipulation happens.
763 ;; User supplies bytes every frame, which are written
764 ;; sequentially to
769 0xC3 ; ; Complete Loop
770 0x1D ;
771 0xD3 ;
775 ])
779 (def frame-count 0xD31F)
780 (def input 0xD352)
781 (def current-mode 0xD382)
783 (defn write-memory []
784 (-> (tick (mid-game))
785 (IE! 0) ; disable interrupts
786 (inject-item-assembly (write-memory-assembly))))
788 (defn test-write-memory []
789 (set-state! (write-memory))
790 (dorun
791 (dotimes [_ 5000]
792 (view-memory (step @current-state) current-mode))))
794 (def bytes-to-write 0xD383)
795 (def start-point 0xD384)
797 (defn test-mode-2 []
798 (->
799 (write-memory)
800 (view-memory frame-count)
801 (step)
802 (step [:a])
803 (step [:b])
804 (step [:start])
805 (step [])
806 (view-memory frame-count)))