diff options
| author | Syndamia <kamen@syndamia.com> | 2022-09-25 15:14:41 +0300 |
|---|---|---|
| committer | Syndamia <kamen@syndamia.com> | 2022-09-25 15:14:41 +0300 |
| commit | a45a9a166245dbeab347796b0616c917fba23959 (patch) | |
| tree | e4748e8600c422292eae66e5f17987cd0780c6ab | |
| parent | 8ebb762435ee28acfa6021d1d6380b9b553ba2ff (diff) | |
| download | PVC-a45a9a166245dbeab347796b0616c917fba23959.tar PVC-a45a9a166245dbeab347796b0616c917fba23959.tar.gz PVC-a45a9a166245dbeab347796b0616c917fba23959.zip | |
[6502 CPU] Updated documentation, changed how *M* works, added SR constants and implemented BRK and INC commandsHEADmain
| -rw-r--r-- | MOS6502.lisp | 78 |
1 files changed, 53 insertions, 25 deletions
diff --git a/MOS6502.lisp b/MOS6502.lisp index 98fb8d9..2d70c61 100644 --- a/MOS6502.lisp +++ b/MOS6502.lisp @@ -2,39 +2,62 @@ ;;; Processor function ;;; -;;; Each time the *CPU* is called, it executes one operation, meaning it reads the -;;; next value in *M*, when an opcode, it either executes it, or if the opcode -;;; needs a value, gets ready to read it from the next address and do something +;;; Each time the *CPU* is called, it executes one instruction ;;; ;;; The implementation uses closures for the internal registers. -(defparameter *CPU* - (let ((PC 0) (AC 0) (X 0) (Y 0) (SR 0) (SP 0)) - #'(lambda () - (let ((mval (nth PC *M*))) - (if (eql mval +OP_BRK+) - () - (if (eql mval +OP_ORAxi+) - ())))))) +(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*) +(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 +;;; 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) @@ -66,3 +89,8 @@ (defconstant +OP_BITa+ #x2C) (defconstant +OP_ANDa+ #x2D) (defconstant +OP_ROLa+ #x2E) + +(defconstant +OP_INCa+ #xEE) + +;;; Helpers for lisp +(defun 2+ (val) (+ 2 val)) |
