rlm@145
|
1 (ns com.aurellem.gb.util
|
rlm@222
|
2 (:use (com.aurellem.gb gb-driver vbm constants))
|
rlm@222
|
3 (:import java.io.File)
|
rlm@145
|
4 (:import [com.aurellem.gb.gb_driver SaveState]))
|
rlm@145
|
5
|
rlm@145
|
6 (defn A [state]
|
rlm@145
|
7 (bit-shift-right (bit-and 0x0000FF00 (AF state)) 8))
|
rlm@145
|
8
|
rlm@145
|
9 (defn B [state]
|
rlm@145
|
10 (bit-shift-right (bit-and 0x0000FF00 (BC state)) 8))
|
rlm@145
|
11
|
rlm@145
|
12 (defn D [state]
|
rlm@145
|
13 (bit-shift-right (bit-and 0x0000FF00 (DE state)) 8))
|
rlm@145
|
14
|
rlm@145
|
15 (defn H [state]
|
rlm@145
|
16 (bit-shift-right (bit-and 0x0000FF00 (HL state)) 8))
|
rlm@145
|
17
|
rlm@145
|
18 (defn C [state]
|
rlm@145
|
19 (bit-and 0xFF (BC state)))
|
rlm@145
|
20 (defn F [state]
|
rlm@145
|
21 (bit-and 0xFF (AF state)))
|
rlm@145
|
22 (defn E [state]
|
rlm@145
|
23 (bit-and 0xFF (DE state)))
|
rlm@145
|
24 (defn L [state]
|
rlm@145
|
25 (bit-and 0xFF (HL state)))
|
rlm@145
|
26
|
rlm@145
|
27 (defn binary-str [num]
|
rlm@145
|
28 (format "%08d"
|
rlm@145
|
29 (Integer/parseInt
|
rlm@145
|
30 (Integer/toBinaryString num) 10)))
|
rlm@145
|
31
|
ocsenave@288
|
32 (defn bit-list
|
ocsenave@288
|
33 "List the bits of n in order of decreasing significance."
|
ocsenave@288
|
34 [n]
|
ocsenave@288
|
35 ((fn this [coll n]
|
ocsenave@288
|
36 (if (zero? n) coll
|
ocsenave@288
|
37 (recur
|
ocsenave@288
|
38 (conj coll (rem n 2))
|
ocsenave@288
|
39 (int (/ n 2)))))
|
ocsenave@288
|
40 [] n))
|
ocsenave@288
|
41
|
ocsenave@288
|
42
|
ocsenave@288
|
43 (defn low-high
|
ocsenave@288
|
44 [low high]
|
ocsenave@288
|
45 (+ low (* 256 high)))
|
ocsenave@288
|
46
|
ocsenave@288
|
47
|
ocsenave@288
|
48 (defn format-name
|
ocsenave@288
|
49 "Convert the string of alphabetic/space characters into a keyword by
|
ocsenave@288
|
50 replacing spaces with hyphens and converting to lowercase."
|
ocsenave@288
|
51 [s]
|
ocsenave@288
|
52 (if (nil? s) nil
|
ocsenave@288
|
53 (keyword (.toLowerCase
|
ocsenave@288
|
54 (apply str
|
ocsenave@288
|
55 (map #(if (= % \space) "-" %) s))))))
|
ocsenave@288
|
56
|
ocsenave@288
|
57
|
ocsenave@288
|
58 ;; used to decode item prices
|
ocsenave@288
|
59
|
ocsenave@288
|
60 (defn decode-bcd
|
ocsenave@288
|
61 "Take a sequence of binary-coded digits (in written order) and return the number they represent."
|
ocsenave@288
|
62 [digits]
|
ocsenave@288
|
63 ((fn self [coll]
|
ocsenave@288
|
64 (if (empty? coll) 0
|
ocsenave@288
|
65 (+ (first coll) (* 100 (self (rest coll))))))
|
ocsenave@288
|
66 (map
|
ocsenave@288
|
67 #(+ (* 10 (int (/ % 16)))
|
ocsenave@288
|
68 (rem % 16))
|
ocsenave@288
|
69 (reverse digits))))
|
ocsenave@288
|
70
|
ocsenave@288
|
71
|
ocsenave@288
|
72
|
ocsenave@273
|
73
|
rlm@145
|
74 (defn view-register [state name reg-fn]
|
rlm@145
|
75 (println (format "%s: %s" name
|
rlm@145
|
76 (binary-str (reg-fn state))))
|
rlm@145
|
77 state)
|
rlm@145
|
78
|
rlm@174
|
79 (defn view-memory
|
rlm@174
|
80 ([^SaveState state mem]
|
rlm@230
|
81 (let [val (aget (memory state) mem)]
|
rlm@230
|
82 (println (format "0x%04X = %s 0x%02X %d" mem
|
rlm@230
|
83 (binary-str val) val val)))
|
rlm@174
|
84 state)
|
rlm@174
|
85 ([mem]
|
rlm@174
|
86 (view-memory @current-state mem)))
|
rlm@145
|
87
|
rlm@176
|
88 (defn print-listing
|
rlm@176
|
89 ([^SaveState state begin end]
|
rlm@176
|
90 (dorun (map
|
rlm@176
|
91 (fn [opcode line]
|
rlm@247
|
92 (println (format "0x%04X: 0x%02X %s %d"
|
rlm@247
|
93 line
|
rlm@247
|
94 opcode (binary-str opcode)
|
rlm@247
|
95 opcode)))
|
rlm@176
|
96 (subvec (vec (memory state)) begin end)
|
rlm@176
|
97 (range begin end)))
|
rlm@176
|
98 state)
|
rlm@176
|
99 ([begin end]
|
rlm@176
|
100 (print-listing @current-state begin end)))
|
rlm@145
|
101
|
rlm@174
|
102 (defn print-pc
|
rlm@174
|
103 ([^SaveState state]
|
rlm@174
|
104 (println (format "PC: 0x%04X" (PC state)))
|
rlm@174
|
105 state)
|
rlm@174
|
106 ([] (print-pc @current-state)))
|
rlm@145
|
107
|
rlm@174
|
108 (defn print-op
|
rlm@174
|
109 ([^SaveState state]
|
rlm@174
|
110 (println (format "OP: 0x%02X" (aget (memory state) (PC state))))
|
rlm@174
|
111 state)
|
rlm@174
|
112 ([] (print-op @current-state)))
|
rlm@145
|
113
|
rlm@145
|
114 (defn d-tick
|
rlm@145
|
115 ([state]
|
rlm@145
|
116 (-> state print-pc print-op tick)))
|
rlm@145
|
117
|
rlm@145
|
118 (defn print-interrupt
|
rlm@145
|
119 [^SaveState state]
|
rlm@145
|
120 (println (format "IE: %d" (IE state)))
|
rlm@145
|
121 state)
|
rlm@145
|
122
|
rlm@145
|
123 (defn set-memory
|
rlm@145
|
124 ([state location value]
|
rlm@145
|
125 (set-state! state)
|
rlm@145
|
126 (let [mem (memory state)]
|
rlm@145
|
127 (aset mem location value)
|
rlm@145
|
128 (write-memory! mem)
|
rlm@145
|
129 (update-state)))
|
rlm@145
|
130 ([location value]
|
rlm@145
|
131 (set-memory @current-state location value)))
|
rlm@145
|
132
|
rlm@145
|
133 (defn set-memory-range
|
rlm@145
|
134 ([state start values]
|
rlm@145
|
135 (set-state! state)
|
rlm@145
|
136 (let [mem (memory state)]
|
rlm@145
|
137
|
rlm@145
|
138 (dorun (map (fn [index val]
|
rlm@145
|
139 (aset mem index val))
|
rlm@145
|
140 (range start
|
rlm@145
|
141 (+ start (count values))) values))
|
rlm@145
|
142 (write-memory! mem)
|
rlm@145
|
143 (update-state)))
|
rlm@145
|
144 ([start values]
|
rlm@145
|
145 (set-memory-range
|
rlm@145
|
146 @current-state start values)))
|
rlm@145
|
147
|
rlm@145
|
148 (defn common-differences [& seqs]
|
rlm@145
|
149 (let [backbone (range (count (first seqs)))]
|
rlm@314
|
150 (sort-by
|
rlm@314
|
151 first
|
rlm@314
|
152 (filter
|
rlm@314
|
153 (comp (partial apply distinct?) second)
|
rlm@314
|
154 (zipmap backbone
|
rlm@314
|
155 (apply (partial map list) seqs))))))
|
rlm@145
|
156
|
rlm@316
|
157 (defn memory-compare [& states]
|
rlm@212
|
158 (apply common-differences
|
rlm@212
|
159 (map (comp vec memory)
|
rlm@212
|
160 states)))
|
rlm@212
|
161
|
rlm@320
|
162 (defn different-every-time [& seqs]
|
rlm@320
|
163 (let [backbone (range (count (first seqs)))]
|
rlm@320
|
164 (sort-by
|
rlm@320
|
165 first
|
rlm@320
|
166 (filter
|
rlm@321
|
167 (comp (fn [seq] (not (contains? (set (map - seq (rest seq)))
|
rlm@321
|
168 0))) second)
|
rlm@320
|
169 (zipmap backbone
|
rlm@320
|
170 (apply (partial map list) seqs))))))
|
rlm@320
|
171
|
rlm@320
|
172
|
rlm@320
|
173 (defn harmonic-compare [& states]
|
rlm@320
|
174 (apply different-every-time
|
rlm@320
|
175 (map (comp vec memory)
|
rlm@320
|
176 states)))
|
rlm@320
|
177
|
rlm@145
|
178 (defn mid-game []
|
rlm@145
|
179 (read-state "mid-game"))
|
rlm@154
|
180
|
rlm@321
|
181 (defn watch-memory
|
rlm@321
|
182 ([^SaveState state address]
|
rlm@321
|
183 (set-state! state)
|
rlm@321
|
184 (loop [] (step) (view-memory address) (recur)))
|
rlm@321
|
185 ([address] (watch-memory @current-state address)))
|
rlm@321
|
186
|
rlm@321
|
187 (defn watch-fn
|
rlm@321
|
188 ([^SaveState state state-fn]
|
rlm@321
|
189 (set-state! state)
|
rlm@321
|
190 (loop [] (step) (state-fn @current-state) (recur)))
|
rlm@321
|
191 ([state-fn] (watch-fn @current-state state-fn)))
|
rlm@192
|
192
|
rlm@192
|
193 (defn disect-bytes-2
|
rlm@192
|
194 "return a vector consiting of the last 16 bytes of the
|
ocsenave@273
|
195 integer expressed as two 8 bit numbers (inside an integer)
|
ocsenave@273
|
196 in the form [high-bits low-bits]."
|
rlm@192
|
197 [num]
|
rlm@192
|
198 [(bit-shift-right
|
rlm@192
|
199 (bit-and num 0xFF00) 8)
|
rlm@192
|
200 (bit-and num 0xFF)])
|
rlm@192
|
201
|
rlm@192
|
202 (defn disect-bytes-3
|
rlm@192
|
203 "same as disect-bytes-2 except that it assumes the input is a
|
rlm@192
|
204 24 bit number and returns [high-bits medium-bits low-bits]"
|
rlm@192
|
205 [num]
|
rlm@192
|
206 (vec
|
rlm@192
|
207 (concat
|
rlm@192
|
208 [(bit-shift-right (bit-and num 0xFF0000) 16)]
|
rlm@192
|
209 (disect-bytes-2 num))))
|
rlm@192
|
210
|
rlm@192
|
211 (defn glue-bytes
|
rlm@192
|
212 "Given two or three 8-bit numbers inside 32-bit integers,
|
rlm@192
|
213 combine them into the integer number that they together
|
rlm@192
|
214 represent."
|
rlm@192
|
215 ([h l]
|
rlm@192
|
216 (+ l (bit-shift-left h 8)))
|
rlm@192
|
217
|
rlm@192
|
218 ([h m l]
|
rlm@192
|
219 (+ (glue-bytes m l)
|
rlm@192
|
220 (bit-shift-left h 16))))
|
rlm@192
|
221
|
rlm@222
|
222 (def cartography
|
rlm@222
|
223 (File. user-home
|
rlm@222
|
224 "proj/vba-clojure/clojure/com/aurellem/exp/cartography"))
|
rlm@192
|
225
|
rlm@222
|
226
|
rlm@222
|
227
|
rlm@222
|
228 (defn print-D-memory
|
rlm@222
|
229 ([^SaveState state]
|
rlm@222
|
230
|
rlm@222
|
231 (let [descriptions
|
rlm@222
|
232 (clojure.string/split-lines
|
rlm@222
|
233 (slurp cartography))]
|
rlm@222
|
234 (dorun
|
rlm@222
|
235 (map
|
rlm@222
|
236 (fn [line data desc]
|
rlm@222
|
237 (printf "%04X %02X%s\n"
|
rlm@222
|
238 line data (apply str
|
rlm@222
|
239 (drop 20 desc))))
|
rlm@222
|
240 (range pokemon-record-begin
|
rlm@222
|
241 (inc D-memory-end))
|
rlm@222
|
242
|
rlm@222
|
243 (subvec (vec (memory state))
|
rlm@222
|
244 pokemon-record-begin
|
rlm@222
|
245 (inc D-memory-end))
|
rlm@222
|
246 descriptions))))
|
rlm@222
|
247 ([] (print-D-memory @current-state)))
|
rlm@222
|
248
|
rlm@301
|
249
|
rlm@301
|
250 (defn signed-8-bits
|
rlm@301
|
251 "the lower 8 bits of an integer interpreted as a signed 8
|
rlm@301
|
252 bit number"
|
rlm@301
|
253 [n]
|
rlm@301
|
254 (let [lower-seven (bit-and n 127)]
|
rlm@301
|
255 (if (bit-test n 7)
|
rlm@303
|
256 (- lower-seven 128)
|
rlm@301
|
257 lower-seven)))
|
rlm@301
|
258 |