2 ;;; An implementation of the Memory Array Redcode Simulator (MARS)
24 (chicken process-context)
31 (define (make-instr opcode modifier A-mode A-num B-mode B-num)
35 (('modifier) modifier)
40 (('make-copy) (make-instr opcode modifier A-mode A-num B-mode B-num))
41 (('set! 'opcode x) (set! opcode x))
42 (('set! 'modifier x) (set! modifier x))
43 (('set! 'A-mode x) (set! A-mode x))
44 (('set! 'A-num x) (set! A-num x))
45 (('set! 'B-mode x) (set! B-mode x))
46 (('set! 'B-num x) (set! B-num x))
48 (set! opcode (other 'opcode))
49 (set! modifier (other 'modifier))
50 (set! A-mode (other 'A-mode))
51 (set! A-num (other 'A-num))
52 (set! B-mode (other 'B-mode))
53 (set! B-num (other 'B-num)))
57 " " (mode->string A-mode) A-num
58 " " (mode->string B-mode) B-num))
60 (error "Invalid instr arguments" args)))))
62 (define (mode->string mode)
68 ((pre-indirect-A) "{")
69 ((pre-indirect-B) "<")
70 ((post-indirect-A) "}")
71 ((post-indirect-B) ">")
73 (error "Unknown mode."))))
76 ;;; Memory setup and addressing
79 (define (make-core core-size initial-instr . set-functions)
80 (let ((core-vec (make-vector core-size '()))
81 (names-vec (make-vector core-size '())))
84 (norm-addr (+ i core-size))
85 (modulo i core-size)))
86 (define (norm-ref v i)
87 (vector-ref v (norm-addr i)))
88 (define (norm-set! v i x)
89 (vector-set! v (norm-addr i)
93 (define (run-set-functions i n)
94 (let loop ((remaining-fns set-functions))
95 (unless (null? remaining-fns)
96 ((car remaining-fns) i n))))
98 (unless (>= i core-size)
99 (vector-set! core-vec i (initial-instr 'make-copy))
104 ((norm-ref core-vec i) 'set-from! (norm-ref core-vec j))
105 (norm-set! names-vec i n)
106 (run-set-functions i n))
107 ((i 'set-from-instr! instr n)
108 ((norm-ref core-vec i) 'set-from! instr)
109 (norm-set! names-vec i n)
110 (run-set-functions i n))
112 ((norm-ref core-vec i) 'set! v x)
113 (norm-set! names-vec i n)
114 (run-set-functions i n))
115 ((i 'name) (norm-ref names-vec i))
116 (((? integer? i) v) ((norm-ref core-vec i) v))
117 (('->addr (? integer? i)) (norm-addr i))
120 (unless (>= i core-size)
121 (print* i ":\t" ((vector-ref core-vec i) '->string))
122 (let ((n (vector-ref names-vec i)))
127 (('size) core-size)))))
130 ;;; Programmes and task queues
133 (define (make-prog name instrs offset)
134 (list name instrs offset))
136 (define (prog-name prog) (list-ref prog 0))
137 (define (prog-instrs prog) (list-ref prog 1))
138 (define (prog-offset prog) (list-ref prog 2))
140 (define (install-prog core prog addr)
141 (let loop ((ptr addr)
142 (instrs (prog-instrs prog)))
143 (unless (null? instrs)
144 (core ptr 'set-from-instr! (car instrs) (prog-name prog))
145 (loop (core '->addr (+ ptr 1)) (cdr instrs))))
146 (make-queue (prog-name prog)
147 (core '->addr (+ addr (prog-offset prog)))))
149 (define (can-install-prog? core prog-len addr)
150 (let loop ((ptr addr)
151 (remaining prog-len))
154 (if (null? (core ptr 'name))
155 (loop (core '->addr (+ ptr 1))
159 (define (install-progs core progs)
160 (let loop ((queues '())
162 (if (null? progs-left)
164 (let ((addr (pseudo-random-integer (core 'size)))
165 (prog (car progs-left)))
166 (if (can-install-prog? core (length (prog-instrs prog)) addr)
167 (loop (cons (install-prog core prog addr) queues)
169 (loop queues progs-left))))))
171 (define (make-queue name ptr)
174 (define (queue-owner queue) (car queue))
175 (define (queue-ptrs queue) (cdr queue))
177 (define (queue-set-ptrs! queue ptrs)
178 (set-cdr! queue ptrs))
181 ;;; Executive function
184 (define (run-mars core queues steps-left)
186 ((<= steps-left 0) queues) ;Tie between remaining players
187 ;; ((<= (length queues) 1) queues) ;There's only one player left who thus wins
189 (let* ((queue (car queues))
190 (remaining-queues (cdr queues))
191 (ptrs (queue-ptrs queue))
192 (new-ptrs (execute-instr core (car ptrs) (queue-owner queue))))
194 (run-mars remaining-queues (- steps-left 1))
196 (queue-set-ptrs! queue (append (cdr ptrs) new-ptrs))
197 (run-mars core (append remaining-queues (list queue)) (- steps-left 1))))))))
199 (define (execute-instr core ptr name)
200 (let* ((A-ptr (eval-operand core (core ptr 'A-mode) (core ptr 'A-num) ptr name))
201 (B-ptr (eval-operand core (core ptr 'B-mode) (core ptr 'B-num) ptr name))
202 (modifier (core ptr 'modifier)))
203 (case (core ptr 'opcode)
205 '()) ;Game over, man, game over!
207 (if (eq? modifier 'I)
208 (core B-ptr 'set-from! A-ptr name)
209 (combine-and-store core A-ptr B-ptr modifier name (lambda (x y) y)))
210 (list (core '->addr (+ ptr 1))))
212 (combine-and-store core A-ptr B-ptr modifier name +)
213 (list (core '->addr (+ ptr 1))))
215 (combine-and-store core A-ptr B-ptr modifier name -)
216 (list (core '->addr (+ ptr 1))))
218 (combine-and-store core A-ptr B-ptr modifier name *)
219 (list (core '->addr (+ ptr 1))))
223 (combine-and-store core A-ptr B-ptr modifier name quotient)
225 (list (core '->addr (+ ptr 1))))
226 ((exn arithmetic) '())))
230 (combine-and-store core A-ptr B-ptr modifier name modulo)
231 (list (core '->addr (+ ptr 1))))
232 ((exn arithmetic) '())))
234 (list (core '->addr (+ ptr (core A-ptr 'A-num)))))
236 (list (core '->addr (+ ptr (if (instr-zero? B-ptr modifier #f name)
240 (list (core '->addr (+ ptr (if (not (instr-zero? B-ptr modifier #f name))
244 (list (core '->addr (+ ptr (if (not (instr-zero? B-ptr modifier #t name))
248 (list (core '->addr (+ ptr (if (compare-instrs core A-ptr B-ptr modifier =) 2 1)))))
250 (list (core '->addr (+ ptr (if (compare-instrs core A-ptr B-ptr modifier =) 1 2)))))
252 (list (core '->addr (+ ptr (if (compare-instrs core A-ptr B-ptr modifier <) 2 1)))))
254 (list (core '->addr (+ ptr 1) (core '->addr (+ ptr (core A-ptr 'A-num))))))
256 (list (core '->addr (+ ptr 1))))
258 (error "Unrecognised opcode" (core ptr 'opcode))))))
260 (define (compare-instrs core A-ptr B-ptr modifier test)
262 ((A) (test (core A-ptr 'A-num) (core B-ptr 'A-num)))
263 ((B) (test (core A-ptr 'B-num) (core B-ptr 'B-num)))
264 ((AB) (test (core A-ptr 'A-num) (core B-ptr 'B-num)))
265 ((BA) (test (core A-ptr 'B-num) (core B-ptr 'A-num)))
267 (test (core A-ptr 'A-num) (core B-ptr 'A-num))
268 (test (core A-ptr 'B-num) (core B-ptr 'B-num))))
270 (test (core A-ptr 'A-num) (core B-ptr 'B-num))
271 (test (core A-ptr 'B-num) (core B-ptr 'A-num))))
275 (eq? (core A-ptr 'opcode) (core B-ptr 'opcode))
276 (eq? (core A-ptr 'modifier) (core B-ptr 'modifier))
277 (eq? (core A-ptr 'A-mode) (core B-ptr 'B-mode))
278 (eq? (core A-ptr 'B-mode) (core B-ptr 'A-mode)))
280 (test (core A-ptr 'A-num) (core B-ptr 'B-num))
281 (test (core A-ptr 'B-num) (core B-ptr 'A-num))))))
283 (define (instr-zero? core ptr modifier decrement name)
286 (if decrement (core ptr 'set! 'A-num (- (core ptr 'A-num) 1) name))
287 (= 0 (core ptr 'A-num)))
289 (if decrement (core ptr 'set! 'B-num (- (core ptr 'B-num) 1) name))
290 (= 0 (core ptr 'B-num)))
294 (core ptr 'set! 'A-num (- (core ptr 'A-num) 1) name)
295 (core ptr 'set! 'B-num (- (core ptr 'B-num) 1) name)))
296 (and (= 0 (core ptr 'A-num))
297 (= 0 (core ptr 'B-num))))))
299 (define (combine-and-store core A-ptr B-ptr modifier name f)
301 ((A) (core B-ptr 'set! 'A-num
302 (f (core B-ptr 'A-num) (core A-ptr 'A-num)) name))
303 ((B) (core B-ptr 'set! 'B-num
304 (f (core B-ptr 'B-num) (core A-ptr 'B-num)) name))
305 ((AB) (core B-ptr 'set! 'B-num
306 (f (core B-ptr 'B-num) (core A-ptr 'A-num)) name))
307 ((BA) (core B-ptr 'set! 'A-num
308 (f (core B-ptr 'A-num) (core A-ptr 'B-num)) name))
309 ((F I) (core B-ptr 'set! 'A-num
310 (f (core B-ptr 'A-num) (core A-ptr 'A-num)) name)
311 (core B-ptr 'set! 'B-num
312 (f (core B-ptr 'B-num) (core A-ptr 'B-num)) name))
313 ((X) (core B-ptr 'set! 'A-num
314 (f (core B-ptr 'A-num) (core A-ptr 'B-num)) name)
315 (core B-ptr 'set! 'B-num
316 (f (core B-ptr 'B-num) (core A-ptr 'A-num)) name))))
318 (define (eval-operand core mode num ptr name)
323 ((indirect-A) (+ num (core (+ ptr num) 'A-num)))
324 ((indirect-B) (+ num (core (+ ptr num) 'B-num)))
326 (let ((aux-ptr (+ ptr num)))
327 (core aux-ptr 'set! 'A-num (- (core aux-ptr 'A-num) 1) name)
328 (+ num (core aux-ptr 'A-num))))
330 (let ((aux-ptr (+ ptr num)))
331 (core aux-ptr 'set! 'B-num (- (core aux-ptr 'B-num) 1) name)
332 (+ num (core aux-ptr 'B-num))))
334 (let* ((aux-ptr (+ ptr num))
335 (old-A-num (core aux-ptr 'A-num)))
336 (core aux-ptr 'set! 'A-num (+ (core aux-ptr 'A-num) 1) name)
339 (let* ((aux-ptr (+ ptr num))
340 (old-B-num (core aux-ptr 'B-num)))
341 (core aux-ptr 'set! 'B-num (+ (core aux-ptr 'B-num) 1) name)
344 (error "Unrecognized mode" mode)))))))