aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSyndamia <kamen@syndamia.com>2022-09-25 15:14:41 +0300
committerSyndamia <kamen@syndamia.com>2022-09-25 15:14:41 +0300
commita45a9a166245dbeab347796b0616c917fba23959 (patch)
treee4748e8600c422292eae66e5f17987cd0780c6ab
parent8ebb762435ee28acfa6021d1d6380b9b553ba2ff (diff)
downloadPVC-main.tar
PVC-main.tar.gz
PVC-main.zip
[6502 CPU] Updated documentation, changed how *M* works, added SR constants and implemented BRK and INC commandsHEADmain
-rw-r--r--MOS6502.lisp78
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))