+ (list (core '->addr (+ ptr 1))))
+ ((exn arithmetic) '())))
+ ((MOD)
+ (condition-case
+ (begin
+ (combine-and-store core A-ptr B-ptr modifier name modulo)
+ (list (core '->addr (+ ptr 1))))
+ ((exn arithmetic) '())))
+ ((JMP)
+ (list (core '->addr A-ptr)))
+ ((JMZ)
+ (list (core '->addr (if (instr-zero? core B-ptr modifier #f name)
+ A-ptr
+ (+ ptr 1)))))
+ ((JMN)
+ (list (core '->addr (if (not (instr-zero? core B-ptr modifier #f name))
+ A-ptr
+ (+ ptr 1)))))
+ ((DJN)
+ (list (core '->addr (if (not (instr-zero? core B-ptr modifier #t name))
+ A-ptr
+ (+ ptr 1)))))
+ ((SEQ CMP)
+ (list (core '->addr (+ ptr (if (compare-instrs core A-ptr B-ptr modifier =) 2 1)))))
+ ((SNE)
+ (list (core '->addr (+ ptr (if (compare-instrs core A-ptr B-ptr modifier =) 1 2)))))
+ ((SLT)
+ (list (core '->addr (+ ptr (if (compare-instrs core A-ptr B-ptr modifier <) 2 1)))))
+ ((SPL)
+ (list (core '->addr (+ ptr 1)) (core '->addr A-ptr)))
+ ((NOP)
+ (list (core '->addr (+ ptr 1))))
+ (else
+ (error "Unrecognised opcode" (core ptr 'opcode))))))
+
+ (define (compare-instrs core A-ptr B-ptr modifier test)
+ (case modifier
+ ((A) (test (core A-ptr 'A-num) (core B-ptr 'A-num)))
+ ((B) (test (core A-ptr 'B-num) (core B-ptr 'B-num)))
+ ((AB) (test (core A-ptr 'A-num) (core B-ptr 'B-num)))
+ ((BA) (test (core A-ptr 'B-num) (core B-ptr 'A-num)))
+ ((F) (and
+ (test (core A-ptr 'A-num) (core B-ptr 'A-num))
+ (test (core A-ptr 'B-num) (core B-ptr 'B-num))))
+ ((X) (and
+ (test (core A-ptr 'A-num) (core B-ptr 'B-num))
+ (test (core A-ptr 'B-num) (core B-ptr 'A-num))))
+ ((I) (and
+ (if (eq? test =)
+ (and
+ (eq? (core A-ptr 'opcode) (core B-ptr 'opcode))
+ (eq? (core A-ptr 'modifier) (core B-ptr 'modifier))
+ (eq? (core A-ptr 'A-mode) (core B-ptr 'B-mode))
+ (eq? (core A-ptr 'B-mode) (core B-ptr 'A-mode)))
+ #t)
+ (test (core A-ptr 'A-num) (core B-ptr 'B-num))
+ (test (core A-ptr 'B-num) (core B-ptr 'A-num))))))
+
+ (define (instr-zero? core ptr modifier decrement name)
+ (case modifier
+ ((A AB)
+ (if decrement (core ptr 'set! 'A-num (- (core ptr 'A-num) 1) name))
+ (= 0 (core ptr 'A-num)))
+ ((A AB)
+ (if decrement (core ptr 'set! 'B-num (- (core ptr 'B-num) 1) name))
+ (= 0 (core ptr 'B-num)))
+ ((X I F)
+ (if decrement
+ (begin
+ (core ptr 'set! 'A-num (- (core ptr 'A-num) 1) name)
+ (core ptr 'set! 'B-num (- (core ptr 'B-num) 1) name)))
+ (and (= 0 (core ptr 'A-num))
+ (= 0 (core ptr 'B-num))))))
+
+ (define (combine-and-store core A-ptr B-ptr modifier name f)
+ (case modifier
+ ((A) (core B-ptr 'set! 'A-num
+ (f (core B-ptr 'A-num) (core A-ptr 'A-num)) name))
+ ((B) (core B-ptr 'set! 'B-num
+ (f (core B-ptr 'B-num) (core A-ptr 'B-num)) name))
+ ((AB) (core B-ptr 'set! 'B-num
+ (f (core B-ptr 'B-num) (core A-ptr 'A-num)) name))
+ ((BA) (core B-ptr 'set! 'A-num
+ (f (core B-ptr 'A-num) (core A-ptr 'B-num)) name))
+ ((F I) (core B-ptr 'set! 'A-num
+ (f (core B-ptr 'A-num) (core A-ptr 'A-num)) name)
+ (core B-ptr 'set! 'B-num
+ (f (core B-ptr 'B-num) (core A-ptr 'B-num)) name))
+ ((X) (core B-ptr 'set! 'A-num
+ (f (core B-ptr 'A-num) (core A-ptr 'B-num)) name)
+ (core B-ptr 'set! 'B-num
+ (f (core B-ptr 'B-num) (core A-ptr 'A-num)) name))))
+
+ (define (eval-operand core mode num ptr name)
+ (core '->addr (+ ptr
+ (case mode
+ ((immediate) 0)
+ ((direct) num)
+ ((indirect-A) (+ num (core (+ ptr num) 'A-num)))
+ ((indirect-B) (+ num (core (+ ptr num) 'B-num)))
+ ((pre-indirect-A)
+ (let ((aux-ptr (+ ptr num)))
+ (core aux-ptr 'set! 'A-num (- (core aux-ptr 'A-num) 1) name)
+ (+ num (core aux-ptr 'A-num))))
+ ((pre-indirect-B)
+ (let ((aux-ptr (+ ptr num)))
+ (core aux-ptr 'set! 'B-num (- (core aux-ptr 'B-num) 1) name)
+ (+ num (core aux-ptr 'B-num))))
+ ((post-indirect-A)
+ (let* ((aux-ptr (+ ptr num))
+ (old-A-num (core aux-ptr 'A-num)))
+ (core aux-ptr 'set! 'A-num (+ (core aux-ptr 'A-num) 1) name)
+ (+ num old-A-num)))
+ ((post-indirect-B)
+ (let* ((aux-ptr (+ ptr num))
+ (old-B-num (core aux-ptr 'B-num)))
+ (core aux-ptr 'set! 'B-num (+ (core aux-ptr 'B-num) 1) name)
+ (+ num old-B-num)))
+ (else
+ (error "Unrecognized mode" mode)))))))
+