changeset 115:39fb0cbab25e

working on preliminary bootstrap code
author Robert McIntyre <rlm@mit.edu>
date Fri, 16 Mar 2012 16:52:29 -0500
parents a454730d92dd
children e45031af5327
files clojure/com/aurellem/assembly.clj
diffstat 1 files changed, 205 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
     1.1 --- a/clojure/com/aurellem/assembly.clj	Fri Mar 16 13:51:17 2012 -0500
     1.2 +++ b/clojure/com/aurellem/assembly.clj	Fri Mar 16 16:52:29 2012 -0500
     1.3 @@ -125,32 +125,12 @@
     1.4          []))))
     1.5  
     1.6  
     1.7 -;; specs for main bootstrap program
     1.8 -;; starts in "mode-select" mode
     1.9 -;;   Each button press takes place in a single frame.
    1.10 -;;   mode-select-mode takes one of the main buttons
    1.11 -;;   which selects one of up to eight modes
    1.12 -;;   mode 1 activated by the "A" button
    1.13 -;;   the next two button presses indicates the start
    1.14 -;;   memory location which to which the bootstrap
    1.15 -;;   program will write.
    1.16 -;;   This is done by using each of the eight buttons to
    1.17 -;;   spell out an 8 bit number.  The order of buttons is
    1.18 -;;   ["A" "B" "start" "select" "up" "right" "down" "left"],
    1.19 -;;   [:a :start :l]  -->  10100001
    1.20 -
    1.21 -;;   the next button press determines how many bytes are to be
    1.22 -;;   written, starting at the start position.
    1.23 -
    1.24 -;;   then, the actual bytes are entered and are written to the
    1.25 -;;   start address in sequence.
    1.26  
    1.27  
    1.28  (defn count-frames []
    1.29    (-> (tick (mid-game))
    1.30        (IE! 0) ; disable interrupts
    1.31        (inject-item-assembly
    1.32 -       ;; write 00010000 to 0xFF00 to select joypad
    1.33         [0x18   ;D31D                    ; jump over          
    1.34          0x02   ;D31E                    ; the next 2 bytes
    1.35          0x00   ;D31F                    ; frame-count
    1.36 @@ -159,8 +139,6 @@
    1.37          0xFA   ;D321
    1.38          0x41   ;D322                    ; load (FF41) into A
    1.39          0xFF   ;D323                    ; this contains mode flags
    1.40 -
    1.41 -
    1.42          
    1.43          ;; if we're in v-blank, the bit-1 is 0
    1.44          ;; and bit-2 is 1  Otherwise, it is not v-blank.
    1.45 @@ -168,14 +146,14 @@
    1.46          0x4F   ;D325                         
    1.47  
    1.48          0xC2   ;D326                     ; if bit-1 is not 0
    1.49 -        0x43   ;D327                     ; GOTO not-v-blank
    1.50 +        0x44   ;D327                     ; GOTO not-v-blank
    1.51          0xD3   ;D328
    1.52          
    1.53          0xCB   ;D329                     ; test bit-0 of A 
    1.54          0x47   ;D32A
    1.55  
    1.56          0xCA   ;D32B                     ; if bit-0 is not 1
    1.57 -        0x43   ;D32C                     ; GOTO not-v-blank
    1.58 +        0x44   ;D32C                     ; GOTO not-v-blank
    1.59          0xD3   ;D32D
    1.60          
    1.61          ;;; in v-blank mode
    1.62 @@ -212,22 +190,23 @@
    1.63          0x20   ;D33F
    1.64          0xD3   ;D340
    1.65  
    1.66 -        0x18   ;D341                    ; skip not-in-v-blank section
    1.67 -        0x05   ;D342
    1.68 +        0xC3   ;D341                   ; return to beginning
    1.69 +        0x1D   ;D342
    1.70 +        0xD3   ;D343
    1.71  
    1.72          ;;; not in v-blank mode
    1.73             ;; set v-blank-prev to 0
    1.74 -        0x3E   ;D343                    ; load 0 into A        
    1.75 -        0x00   ;D344
    1.76 +        0x3E   ;D344                    ; load 0 into A        
    1.77 +        0x00   ;D345
    1.78  
    1.79 -        0xEA   ;D345                    ; load A into v-blank-prev
    1.80 -        0x20   ;D346
    1.81 -        0xD3   ;D347
    1.82 +        0xEA   ;D346                    ; load A into v-blank-prev
    1.83 +        0x20   ;D347
    1.84 +        0xD3   ;D348
    1.85 +
    1.86 +        0xC3   ;D349                   ; return to beginning
    1.87 +        0x1D   ;D34A
    1.88 +        0xD3   ;D34B
    1.89          
    1.90 -
    1.91 -        0xC3   ;D348                   ; return to beginning
    1.92 -        0x1D   ;D349
    1.93 -        0xD3   ;D34A
    1.94          ])))
    1.95  
    1.96  (defn step-count-frames []
    1.97 @@ -256,10 +235,16 @@
    1.98        (tick)
    1.99        (print-inventory)))
   1.100  
   1.101 -(defn test-read-down []
   1.102 -  (= (view-memory (step (step (read-buttons) [:d])) 0xD328)
   1.103 -     (view-memory (step (step (read-buttons))) 0xD328)))
   1.104 -  
   1.105 +;;(defn test-read-down []
   1.106 +;;  (= (view-memory (step (step (read-buttons) [:d])) 0xD328)
   1.107 +;;     (view-memory (step (step (read-buttons))) 0xD328)))
   1.108 +
   1.109 +(defn test-count-frames []
   1.110 +  (= 255 (aget (memory ((apply comp (repeat 255 step))
   1.111 +                        (count-frames)))
   1.112 +               0xD31F)))
   1.113 +
   1.114 +   
   1.115  (defn trace [state]
   1.116    (loop [program-counters []
   1.117           opcodes []]
   1.118 @@ -281,11 +266,192 @@
   1.119        (PC! item-list-start)(print-interrupt)
   1.120        (info) (tick) (info) (tick) (info)))
   1.121  
   1.122 +;; specs for main bootstrap program
   1.123 +;; starts in "mode-select" mode
   1.124 +;;   Each button press takes place in a single frame.
   1.125 +;;   mode-select-mode takes one of the main buttons
   1.126 +;;   which selects one of up to eight modes
   1.127 +;;   mode 1 activated by the "A" button
   1.128 +;;   the next two button presses indicates the start
   1.129 +;;   memory location which to which the bootstrap
   1.130 +;;   program will write.
   1.131 +;;   This is done by using each of the eight buttons to
   1.132 +;;   spell out an 8 bit number.  The order of buttons is
   1.133 +;;   ["A" "B" "start" "select" "up" "right" "down" "left"],
   1.134 +;;   [:a :start :l]  -->  10100001
   1.135  
   1.136 +;;   the next button press determines how many bytes are to be
   1.137 +;;   written, starting at the start position.
   1.138  
   1.139 +;;   then, the actual bytes are entered and are written to the
   1.140 +;;   start address in sequence.
   1.141  
   1.142  
   1.143  
   1.144 +(defn input-number []
   1.145 +  (-> (tick (mid-game))
   1.146 +      (IE! 0) ; disable interrupts
   1.147 +      (inject-item-assembly
   1.148 +       [0x18   ;D31D                    ; jump over          
   1.149 +        0x02   ;D31E                    ; the next 2 bytes
   1.150 +        0x00   ;D31F                    ; frame-count
   1.151 +        0x00   ;D320                    ; v-blank-prev
   1.152 +        
   1.153 +        0xFA   ;D321
   1.154 +        0x41   ;D322                    ; load (FF41) into A
   1.155 +        0xFF   ;D323                    ; this contains mode flags
   1.156 +        
   1.157 +        ;; if we're in v-blank, the bit-1 is 0
   1.158 +        ;; and bit-2 is 1  Otherwise, it is not v-blank.
   1.159 +        0xCB   ;D324                     ; test bit-1 of A
   1.160 +        0x4F   ;D325                         
   1.161  
   1.162 +        0xC2   ;D326                     ; if bit-1 is not 0
   1.163 +        0x44   ;D327                     ; GOTO not-v-blank
   1.164 +        0xD3   ;D328
   1.165 +        
   1.166 +        0xCB   ;D329                     ; test bit-0 of A 
   1.167 +        0x47   ;D32A
   1.168  
   1.169 +        0xCA   ;D32B                     ; if bit-0 is not 1
   1.170 +        0x44   ;D32C                     ; GOTO not-v-blank
   1.171 +        0xD3   ;D32D
   1.172 +        
   1.173 +        ;;; in v-blank mode
   1.174  
   1.175 +           ;; if v-blank-prev was 0,
   1.176 +           ;; increment frame-count
   1.177 +
   1.178 +        0xFA   ;D32E                    ; load v-blank-prev to A
   1.179 +        0x20   ;D32F
   1.180 +        0xD3   ;D330
   1.181 +        
   1.182 +        0xCB   ;D331
   1.183 +        0x47   ;D332                    ; test bit-0 of A 
   1.184 +
   1.185 +        0x20   ;D333                    ; skip next section
   1.186 +        0x07   ;D334                    ; if v-blank-prev was not zero 
   1.187 +        
   1.188 +           ;; v-blank was 0, increment frame-count
   1.189 +        0xFA   ;D335                    ; load frame-count into A
   1.190 +        0x1F   ;D336
   1.191 +        0xD3   ;D337                   
   1.192 +
   1.193 +        0x3C   ;D338                    ; inc A
   1.194 +
   1.195 +        0xEA   ;D339                    ; load A into frame-count
   1.196 +        0x1F   ;D33A
   1.197 +        0xD3   ;D33B
   1.198 +
   1.199 +           ;; set v-blank-prev to 1
   1.200 +        0x3E   ;D33C                    ; load 1 into A
   1.201 +        0x01   ;D33D                    
   1.202 +
   1.203 +        0xEA   ;D33E                    ; load A into v-blank-prev
   1.204 +        0x20   ;D33F
   1.205 +        0xD3   ;D340
   1.206 +
   1.207 +        0xC3   ;D341                   ; GOTO input handling code
   1.208 +        0x4E   ;D342
   1.209 +        0xD3   ;D343
   1.210 +
   1.211 +        ;;; not in v-blank mode
   1.212 +           ;; set v-blank-prev to 0
   1.213 +        0x3E   ;D344                    ; load 0 into A        
   1.214 +        0x00   ;D345
   1.215 +
   1.216 +        0xEA   ;D346                    ; load A into v-blank-prev
   1.217 +        0x20   ;D347
   1.218 +        0xD3   ;D348
   1.219 +
   1.220 +        0xC3   ;D349                   ; return to beginning
   1.221 +        0x1D   ;D34A
   1.222 +        0xD3   ;D34B
   1.223 +
   1.224 +        0x00   ;D34C                   ; these are here 
   1.225 +        0x00   ;D34D                   ; for glue
   1.226 +       
   1.227 +        
   1.228 +        ;;; calculate input number based on button presses
   1.229 +        0x18   ;D34E                    ;  skip next 3 bytes
   1.230 +        0x03   ;D34F
   1.231 +               ;D350
   1.232 +        (Integer/parseInt "00100000" 2) ;  select directional pad
   1.233 +               ;D351
   1.234 +        (Integer/parseInt "00010000" 2) ;  select buttons
   1.235 +        0x00   ;D352                    ;  input-number
   1.236 +
   1.237 +        ;; select directional pad, store low bits in B
   1.238 +        
   1.239 +        0xFA   ;D353                    ; load (D350) into A
   1.240 +        0x50   ;D354      -->       
   1.241 +        0xD3   ;D355      -->  D31F     
   1.242 +        
   1.243 +        0xEA   ;D356                    ; load (A), which is 
   1.244 +        0x00   ;D357      -->           ; 00010000, into FF00
   1.245 +        0xFF   ;D358      -->  FF00     
   1.246 +
   1.247 +        0x06   ;D359
   1.248 +               ;D35A
   1.249 +        (Integer/parseInt "11110000")   ; "11110000" -> B 
   1.250 +        0xFA   ;D35B                    ; (FF00) -> A
   1.251 +        0x00   ;D35C                   
   1.252 +        0xFF   ;D35D
   1.253 +
   1.254 +        0xCB   ;D35E                    ; swap nybbles on A
   1.255 +        0x37   ;D35F
   1.256 +        0xA0   ;D360                    ; (AND A B) -> A
   1.257 +        0x47   ;D361                    ; A -> B
   1.258 +
   1.259 +        ;; select buttons store bottom bits in C
   1.260 +        
   1.261 +        0xFA   ;                        ; load (D351) into A
   1.262 +        0x51   ;          -->       
   1.263 +        0xD3   ;          -->  D31F     
   1.264 +        
   1.265 +        0xEA   ;                        ; load (A), which is 
   1.266 +        0x00   ;          -->           ; 00001000, into FF00
   1.267 +        0xFF   ;          -->  FF00     
   1.268 +
   1.269 +        0x0E   ;    
   1.270 +        (Integer/parseInt "00001111")   ; "00001111" -> C 
   1.271 +
   1.272 +        0xFA   ;                        ; (FF00) -> A
   1.273 +        0x00   ;                       
   1.274 +        0xFF   ;    
   1.275 +       
   1.276 +        0xA1   ;                        ; (AND A C) -> A
   1.277 +        0x4F   ;                        ; A -> C
   1.278 +
   1.279 +
   1.280 +        ;; combine the B and C registers into the input number
   1.281 +        0x79   ;                        ; C -> A
   1.282 +        0xB0   ;                        ; (OR A B) -> A
   1.283 +        0x2F   ;                        ; negate A
   1.284 +
   1.285 +        0xEA   ;                        ; store A into input-number
   1.286 +        0x52   ;
   1.287 +        0xD3   ;
   1.288 +
   1.289 +        0xC3   ;                        ; return to beginning
   1.290 +        0x1D   ;    
   1.291 +        0xD3   ;    
   1.292 +        ])))
   1.293 +
   1.294 +
   1.295 +
   1.296 +
   1.297 +(defn print-listing [state begin end]
   1.298 +  (dorun (map 
   1.299 +          (fn [opcode line]
   1.300 +            (println (format "0x%04X:  0x%02X" line opcode)))
   1.301 +          (subvec  (vec (memory state)) begin end)
   1.302 +          (range begin end))))
   1.303 +  
   1.304 +                    
   1.305 +
   1.306 +
   1.307 +
   1.308 +
   1.309 +
   1.310 +