;;;; Processor ;;; Processor function ;;; ;;; Each time the *CPU* is called, it executes one instruction ;;; ;;; The implementation uses closures for the internal registers. (defparameter *CPU* ;; As far as I can tell, there are "secret" internal buffers in the 6502 where fetched ;; data is stored. These should be address bus high (ABH), address bus low (ABL) and ;; adder holder register (ADD). ;; To save myself the headache, I've just named these opcode and loc, since thats what ;; they're used for, and they will be only "internal" to the processor. ;; http://www.weihenstephan.org/~michaste/pagetable/6502/6502.jpg ;; https://retrocomputing.stackexchange.com/questions/19750/where-does-the-6502-store-the-low-order-byte-after-fetching-for-read-instruction (let ((PC (elt *M* #xFFFD)) (AC 0) (X 0) (Y 0) (SR 0) (SP #xFF) (opcode) (loc)) #'(lambda () (setf opcode (elt *M* PC)) (incf PC) ; fetch opcode, increment PC (cond ((eql opcode +OP_BRK+) (incf PC) ; read next instruction and throw it away (setf (elt *M* SP) PC) (decf SP) ; push PC on stack (setf SR (logior SR +SR_I+)) (setf (elt *M* SP) SR) (decf SP) ; push SR on stack (setf PC (elt *M* #xFFFE))) ((eql opcode +OP_INCa+) (setf loc (elt *M* PC)) (incf PC) ; fetch (low and high byte of) addr (incf (elt *M* loc)) ; do operation and write new value (setf SR (logior SR +SR_N+ +SR_Z+))) )))) ;;; External memory, where the zero page, stack and general purpose memory resides ;;; Another file has to implement it. (defvar *M* (make-array (1+ #xFFFF) :element-type 'integer :initial-element 0)) ;;; SR flags (defconstant +SR_N+ #b10000000) (defconstant +SR_V+ #b01000000) (defconstant +SR_D+ #b00001000) (defconstant +SR_I+ #b00000100) (defconstant +SR_Z+ #b00000010) (defconstant +SR_C+ #b00000001) ;;; Processor opcodes ;;; Ends with a small letter, depending on address mode: ;;; ac | accumulator ;;; a | absolute ;;; ax | absolute, X-indexed ;;; ay | absolute, Y-indexed ;;; d | immediate ;;; | implied ;;; i | indirect ;;; xi | X-indexed, indirect ;;; iy | indirect, Y-indexed ;;; r | relative ;;; z | zeropage ;;; zx | zeropage, X-indexed ;;; zy | zeropage, Y-indexed (defconstant +OP_BRK+ #x00) (defconstant +OP_ORAxi+ #x01) (defconstant +OP_ORAz+ #x05) (defconstant +OP_ASLz+ #x06) (defconstant +OP_PHP+ #x08) (defconstant +OP_ORAd+ #x09) (defconstant +OP_ASLac+ #x0A) (defconstant +OP_ORAa+ #x0D) (defconstant +OP_ASLa+ #x0E) (defconstant +OP_BPLr+ #x10) (defconstant +OP_ORAiy+ #x11) (defconstant +OP_ORAzx+ #x15) (defconstant +OP_ASLzx+ #x16) (defconstant +OP_CLC+ #x18) (defconstant +OP_ORAay+ #x19) (defconstant +OP_ORAax+ #x1D) (defconstant +OP_ASLax+ #x1E) (defconstant +OP_JSRa+ #x20) (defconstant +OP_ANDxi+ #x21) (defconstant +OP_BITz+ #x24) (defconstant +OP_ANDz+ #x25) (defconstant +OP_ROLz+ #x26) (defconstant +OP_PLP+ #x28) (defconstant +OP_ANDd+ #x29) (defconstant +OP_ROLac+ #x2A) (defconstant +OP_BITa+ #x2C) (defconstant +OP_ANDa+ #x2D) (defconstant +OP_ROLa+ #x2E) (defconstant +OP_INCa+ #xEE) ;;; Helpers for lisp (defun 2+ (val) (+ 2 val))