2 ;;; An implementation of the Memory Array Redcode Simulator (MARS)
25 (chicken process-context)
32 (define (make-instr opcode modifier A-mode A-num B-mode B-num)
36 (('modifier) modifier)
41 (('make-copy) (make-instr opcode modifier A-mode A-num B-mode B-num))
42 (('set! 'opcode x) (set! opcode x))
43 (('set! 'modifier x) (set! modifier x))
44 (('set! 'A-mode x) (set! A-mode x))
45 (('set! 'A-num x) (set! A-num x))
46 (('set! 'B-mode x) (set! B-mode x))
47 (('set! 'B-num x) (set! B-num x))
49 (set! opcode (other 'opcode))
50 (set! modifier (other 'modifier))
51 (set! A-mode (other 'A-mode))
52 (set! A-num (other 'A-num))
53 (set! B-mode (other 'B-mode))
54 (set! B-num (other 'B-num)))
58 " " (mode->string A-mode) A-num
59 ", " (mode->string B-mode) B-num))
61 (error "Invalid instr arguments" args)))))
63 (define (mode->string mode)
69 ((pre-indirect-A) "{")
70 ((pre-indirect-B) "<")
71 ((post-indirect-A) "}")
72 ((post-indirect-B) ">")
74 (error "Unknown mode."))))
77 ;;; Memory setup and addressing
80 (define (make-core core-size initial-instr . set-functions)
81 (let ((core-vec (make-vector core-size '()))
82 (names-vec (make-vector core-size '())))
85 (norm-addr (+ i core-size))
86 (modulo i core-size)))
87 (define (norm-ref v i)
88 (vector-ref v (norm-addr i)))
89 (define (norm-set! v i x)
90 (vector-set! v (norm-addr i)
94 (define (run-set-functions i n)
95 (let loop ((remaining-fns set-functions))
96 (unless (null? remaining-fns)
97 ((car remaining-fns) i n))))
99 (unless (>= i core-size)
100 (vector-set! core-vec i (initial-instr 'make-copy))
105 ((norm-ref core-vec i) 'set-from! (norm-ref core-vec j))
106 (norm-set! names-vec i n)
107 (run-set-functions i n))
108 ((i 'set-from-instr! instr n)
109 ((norm-ref core-vec i) 'set-from! instr)
110 (norm-set! names-vec i n)
111 (run-set-functions i n))
113 ((norm-ref core-vec i) 'set! v x)
114 (norm-set! names-vec i n)
115 (run-set-functions i n))
116 ((i 'name) (norm-ref names-vec i))
117 (((? integer? i) v) ((norm-ref core-vec i) v))
118 (('->addr (? integer? i)) (norm-addr i))
121 (unless (>= i core-size)
122 (print* i ":\t" ((vector-ref core-vec i) '->string))
123 (let ((n (vector-ref names-vec i)))
128 (('size) core-size)))))
131 ;;; Programmes and task queues
134 (define (make-prog name instrs offset)
135 (list name instrs offset))
137 (define (prog-name prog) (list-ref prog 0))
138 (define (prog-instrs prog) (list-ref prog 1))
139 (define (prog-offset prog) (list-ref prog 2))
141 (define (install-prog core prog addr)
142 (let loop ((ptr addr)
143 (instrs (prog-instrs prog)))
144 (unless (null? instrs)
145 (core ptr 'set-from-instr! (car instrs) (prog-name prog))
146 (loop (core '->addr (+ ptr 1)) (cdr instrs))))
147 (make-queue (prog-name prog)
148 (core '->addr (+ addr (prog-offset prog)))))
150 (define (can-install-prog? core prog-len addr)
151 (let loop ((ptr addr)
152 (remaining prog-len))
155 (if (null? (core ptr 'name))
156 (loop (core '->addr (+ ptr 1))
160 (define (install-progs core progs)
161 (let loop ((queues '())
163 (if (null? progs-left)
165 (let ((addr (pseudo-random-integer (core 'size)))
166 (prog (car progs-left)))
167 (if (can-install-prog? core (length (prog-instrs prog)) addr)
168 (loop (cons (install-prog core prog addr) queues)
170 (loop queues progs-left))))))
172 (define (make-queue name ptr)
175 (define (queue-owner queue) (car queue))
176 (define (queue-ptrs queue) (cdr queue))
178 (define (queue-set-ptrs! queue ptrs)
179 (set-cdr! queue ptrs))
181 (define (prog->string prog)
183 ";name " (prog-name prog) "\n\n"
184 "ORG\t" (prog-offset prog) "\t; Execution offset\n\n"
185 (apply conc (map (lambda (instr) (conc (instr '->string) "\n")) (prog-instrs prog)))))
187 ;;; Executive function
190 (define (run-mars core queues steps-left)
192 ((<= steps-left 0) queues) ;Tie between remaining players
193 ;; ((<= (length queues) 1) queues) ;There's only one player left who thus wins
195 (let* ((queue (car queues))
196 (remaining-queues (cdr queues))
197 (ptrs (queue-ptrs queue))
198 (new-ptrs (execute-instr core (car ptrs) (queue-owner queue))))
200 (run-mars remaining-queues (- steps-left 1))
202 (queue-set-ptrs! queue (append (cdr ptrs) new-ptrs))
203 (run-mars core (append remaining-queues (list queue)) (- steps-left 1))))))))
205 (define (execute-instr core ptr name)
206 (let* ((A-ptr (eval-operand core (core ptr 'A-mode) (core ptr 'A-num) ptr name))
207 (B-ptr (eval-operand core (core ptr 'B-mode) (core ptr 'B-num) ptr name))
208 (modifier (core ptr 'modifier)))
209 (case (core ptr 'opcode)
211 '()) ;Game over, man, game over!
213 (if (eq? modifier 'I)
214 (core B-ptr 'set-from! A-ptr name)
215 (combine-and-store core A-ptr B-ptr modifier name (lambda (x y) y)))
216 (list (core '->addr (+ ptr 1))))
218 (combine-and-store core A-ptr B-ptr modifier name +)
219 (list (core '->addr (+ ptr 1))))
221 (combine-and-store core A-ptr B-ptr modifier name -)
222 (list (core '->addr (+ ptr 1))))
224 (combine-and-store core A-ptr B-ptr modifier name *)
225 (list (core '->addr (+ ptr 1))))
229 (combine-and-store core A-ptr B-ptr modifier name quotient)
231 (list (core '->addr (+ ptr 1))))
232 ((exn arithmetic) '())))
236 (combine-and-store core A-ptr B-ptr modifier name modulo)
237 (list (core '->addr (+ ptr 1))))
238 ((exn arithmetic) '())))
240 (list (core '->addr (+ ptr (core A-ptr 'A-num)))))
242 (list (core '->addr (+ ptr (if (instr-zero? B-ptr modifier #f name)
246 (list (core '->addr (+ ptr (if (not (instr-zero? B-ptr modifier #f name))
250 (list (core '->addr (+ ptr (if (not (instr-zero? B-ptr modifier #t name))
254 (list (core '->addr (+ ptr (if (compare-instrs core A-ptr B-ptr modifier =) 2 1)))))
256 (list (core '->addr (+ ptr (if (compare-instrs core A-ptr B-ptr modifier =) 1 2)))))
258 (list (core '->addr (+ ptr (if (compare-instrs core A-ptr B-ptr modifier <) 2 1)))))
260 (list (core '->addr (+ ptr 1) (core '->addr (+ ptr (core A-ptr 'A-num))))))
262 (list (core '->addr (+ ptr 1))))
264 (error "Unrecognised opcode" (core ptr 'opcode))))))
266 (define (compare-instrs core A-ptr B-ptr modifier test)
268 ((A) (test (core A-ptr 'A-num) (core B-ptr 'A-num)))
269 ((B) (test (core A-ptr 'B-num) (core B-ptr 'B-num)))
270 ((AB) (test (core A-ptr 'A-num) (core B-ptr 'B-num)))
271 ((BA) (test (core A-ptr 'B-num) (core B-ptr 'A-num)))
273 (test (core A-ptr 'A-num) (core B-ptr 'A-num))
274 (test (core A-ptr 'B-num) (core B-ptr 'B-num))))
276 (test (core A-ptr 'A-num) (core B-ptr 'B-num))
277 (test (core A-ptr 'B-num) (core B-ptr 'A-num))))
281 (eq? (core A-ptr 'opcode) (core B-ptr 'opcode))
282 (eq? (core A-ptr 'modifier) (core B-ptr 'modifier))
283 (eq? (core A-ptr 'A-mode) (core B-ptr 'B-mode))
284 (eq? (core A-ptr 'B-mode) (core B-ptr 'A-mode)))
286 (test (core A-ptr 'A-num) (core B-ptr 'B-num))
287 (test (core A-ptr 'B-num) (core B-ptr 'A-num))))))
289 (define (instr-zero? core ptr modifier decrement name)
292 (if decrement (core ptr 'set! 'A-num (- (core ptr 'A-num) 1) name))
293 (= 0 (core ptr 'A-num)))
295 (if decrement (core ptr 'set! 'B-num (- (core ptr 'B-num) 1) name))
296 (= 0 (core ptr 'B-num)))
300 (core ptr 'set! 'A-num (- (core ptr 'A-num) 1) name)
301 (core ptr 'set! 'B-num (- (core ptr 'B-num) 1) name)))
302 (and (= 0 (core ptr 'A-num))
303 (= 0 (core ptr 'B-num))))))
305 (define (combine-and-store core A-ptr B-ptr modifier name f)
307 ((A) (core B-ptr 'set! 'A-num
308 (f (core B-ptr 'A-num) (core A-ptr 'A-num)) name))
309 ((B) (core B-ptr 'set! 'B-num
310 (f (core B-ptr 'B-num) (core A-ptr 'B-num)) name))
311 ((AB) (core B-ptr 'set! 'B-num
312 (f (core B-ptr 'B-num) (core A-ptr 'A-num)) name))
313 ((BA) (core B-ptr 'set! 'A-num
314 (f (core B-ptr 'A-num) (core A-ptr 'B-num)) name))
315 ((F I) (core B-ptr 'set! 'A-num
316 (f (core B-ptr 'A-num) (core A-ptr 'A-num)) name)
317 (core B-ptr 'set! 'B-num
318 (f (core B-ptr 'B-num) (core A-ptr 'B-num)) name))
319 ((X) (core B-ptr 'set! 'A-num
320 (f (core B-ptr 'A-num) (core A-ptr 'B-num)) name)
321 (core B-ptr 'set! 'B-num
322 (f (core B-ptr 'B-num) (core A-ptr 'A-num)) name))))
324 (define (eval-operand core mode num ptr name)
329 ((indirect-A) (+ num (core (+ ptr num) 'A-num)))
330 ((indirect-B) (+ num (core (+ ptr num) 'B-num)))
332 (let ((aux-ptr (+ ptr num)))
333 (core aux-ptr 'set! 'A-num (- (core aux-ptr 'A-num) 1) name)
334 (+ num (core aux-ptr 'A-num))))
336 (let ((aux-ptr (+ ptr num)))
337 (core aux-ptr 'set! 'B-num (- (core aux-ptr 'B-num) 1) name)
338 (+ num (core aux-ptr 'B-num))))
340 (let* ((aux-ptr (+ ptr num))
341 (old-A-num (core aux-ptr 'A-num)))
342 (core aux-ptr 'set! 'A-num (+ (core aux-ptr 'A-num) 1) name)
345 (let* ((aux-ptr (+ ptr num))
346 (old-B-num (core aux-ptr 'B-num)))
347 (core aux-ptr 'set! 'B-num (+ (core aux-ptr 'B-num) 1) name)
350 (error "Unrecognized mode" mode)))))))