├── console.asd ├── instructions ├── flagops.lisp ├── loadstoreops.lisp ├── instructions.lisp ├── branchops.lisp └── arithmeticops.lisp ├── README.md ├── controller.lisp ├── cartridge.lisp ├── console.lisp ├── mmu.lisp ├── cpu.lisp ├── ppu.lisp └── LICENSE /console.asd: -------------------------------------------------------------------------------- 1 | (in-package #:asdf-user) 2 | 3 | (defsystem #:console 4 | :depends-on (#:sdl2) 5 | :components ((:file "cpu") 6 | (:file "console" :depends-on ("cpu" "cartridge" "ppu" "controller")) 7 | (:file "mmu" :depends-on ("controller" "console")) 8 | (:file "ppu") 9 | (:file "controller") 10 | (:file "cartridge") 11 | (:file "instructions/arithmeticops") 12 | (:file "instructions/branchops") 13 | (:file "instructions/flagops") 14 | (:file "instructions/loadstoreops") 15 | (:file "instructions/instructions"))) 16 | -------------------------------------------------------------------------------- /instructions/flagops.lisp: -------------------------------------------------------------------------------- 1 | (in-package :6502-cpu) 2 | (declaim (optimize (speed 3) (safety 1))) 3 | (defun sei (c inst) 4 | (declare (cpu c) (instruction inst) (ignore inst)) 5 | "SEI: set interrupt flag" 6 | (setf (flags-interrupt (cpu-sr c)) T)) 7 | 8 | (defun sec (c inst) 9 | (declare (cpu c) (instruction inst) (ignore inst)) 10 | "SEC: set carry flag" 11 | (setf (flags-carry (cpu-sr c)) T)) 12 | 13 | (defun clv (c inst) 14 | (declare (cpu c) (instruction inst) (ignore inst)) 15 | "CLV: clear overflow flag" 16 | (setf (flags-overflow (cpu-sr c)) nil)) 17 | 18 | (defun clc (c inst) 19 | (declare (cpu c) (instruction inst) (ignore inst)) 20 | "CLC: clear carry flag" 21 | (setf (flags-carry (cpu-sr c)) nil)) 22 | 23 | (defun cld (c inst) 24 | (declare (cpu c) (instruction inst) (ignore inst)) 25 | "Clear decimal flag" 26 | (setf (flags-bcd (cpu-sr c)) nil)) 27 | 28 | (defun sed (c inst) 29 | (declare (cpu c) (instruction inst) (ignore inst)) 30 | "Set decimal flag" 31 | (setf (flags-bcd (cpu-sr c)) T)) 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # potential-disco 2 | Trying to emulate the NES again in Common Lisp 3 | 4 | TODO: Other mapppers besides NROM 5 | TODO: Audio 6 | TODO: Run at proper speed instead of just letting it go however fast it pleases. 7 | TODO: Write more idiomatic Lisp 8 | #### Examples 9 | ![Super Mario Bros](https://i.gyazo.com/5b8b161be74281255e48b63db45a7285.gif) 10 | ![Galaga](https://i.gyazo.com/d9af4b6f32a1b6790be46627c2035306.gif) 11 | ![Donkey Kong](https://i.gyazo.com/edfc1dc4245ce0bfbbf99af8e84870e0.gif) 12 | ![Volley Ball](https://i.gyazo.com/ef21cd65df7267662637c735aa406bde.gif) 13 | ![NesTest](https://i.gyazo.com/f6f0767f3806388b99fb343190406b71.png) 14 | #### Usage 15 | In your favorite common lisp repl (I haven't tested outside of 16 | sbcl), just run 17 | ``` 18 | (asdf:load-system :console) 19 | (nes:setup-and-emulate path-to-rom) 20 | ``` 21 | Where path to rom is a string 22 | The controls map to.. 23 | Start: Tab 24 | Select: Grave 25 | Left, Down, Right, Up: W, A, S, D 26 | A, B: Left Arrow, Down Arrow 27 | I'm sorry, they aren't re-mappable yet. =( 28 | -------------------------------------------------------------------------------- /controller.lisp: -------------------------------------------------------------------------------- 1 | (defpackage #:NES-controller 2 | (:nicknames #:controller) 3 | (:use #:cl) 4 | (:export #:make-controller 5 | #:read-controller 6 | #:write-controller 7 | #:update-controller 8 | #:controller 9 | #:controller-buttons-callback 10 | #:*keymap* 11 | #:get-buttons)) 12 | 13 | (in-package :NES-controller) 14 | (declaim (optimize (speed 3) (safety 1))) 15 | 16 | (defstruct controller 17 | (buttons 18 | (make-array 8 :element-type '(unsigned-byte 8) :initial-element 0) 19 | :type (simple-array (unsigned-byte 8) 1)) 20 | (index 0 :type (unsigned-byte 3)) 21 | (strobe 0 :type (unsigned-byte 1)) 22 | (buttons-callback (lambda()) :type function)) 23 | 24 | (defun read-controller (c) 25 | (declare (controller c)) 26 | (let ((value (aref (controller-buttons c) (controller-index c)))) 27 | (setf 28 | (controller-index c) 29 | (if (not (ldb-test (byte 1 0) (controller-strobe c))) 30 | (ldb (byte 3 0) (1+ (controller-index c))) 31 | 0)) 32 | value)) 33 | 34 | (defun write-controller (c val) 35 | (declare (controller c) ((unsigned-byte 8) val)) 36 | (when (ldb-test (byte 1 0) (setf (controller-strobe c) (ldb (byte 1 0) val))) 37 | (setf (controller-index c) 0))) 38 | 39 | (defun update-controller (c) 40 | (declare (controller c)) 41 | (when (ldb-test (byte 1 0) (controller-strobe c)) 42 | (setf (controller-buttons c) (the (simple-array (unsigned-byte 8) 1) (funcall (controller-buttons-callback c)))))) 43 | 44 | (defvar *keymap* 45 | '((:a . :scancode-left) 46 | (:b . :scancode-down) 47 | (:select . :scancode-grave) 48 | (:start . :scancode-tab) 49 | (:up . :scancode-w) 50 | (:down . :scancode-s) 51 | (:left . :scancode-a) 52 | (:right . :scancode-d)) 53 | "The mapping of the controller #1 buttons to SDL keycodes. Caveat Emptor, the 54 | button-names are for reference, the mapping is determined by the Order.") 55 | 56 | (defun get-buttons () 57 | (let ((buttons (make-array 8 :element-type '(unsigned-byte 8) :initial-element 0))) 58 | (loop :for index :from 0 59 | :for (button-name . button-key) :in *keymap* 60 | :do 61 | (setf (aref buttons index) (if (sdl2:keyboard-state-p button-key) 1 0))) 62 | buttons)) 63 | -------------------------------------------------------------------------------- /instructions/loadstoreops.lisp: -------------------------------------------------------------------------------- 1 | (in-package :6502-cpu) 2 | (declaim (optimize (speed 3) (safety 1))) 3 | 4 | (defun ldy (c inst) 5 | (declare (cpu c) (instruction inst)) 6 | "LDY. Load value to y" 7 | (set-zn c (setf (cpu-y c) (get-value c inst)))) 8 | 9 | (defun lda (c inst) 10 | (declare (cpu c) (instruction inst)) 11 | "LDA. Load value to accumulator" 12 | (set-zn c (setf (cpu-accumulator c) (get-value c inst)))) 13 | 14 | (defun ldx (c inst) 15 | (declare (cpu c) (instruction inst)) 16 | "LDX. Load value to cpu-x" 17 | (set-zn c (setf (cpu-x c) (get-value c inst)))) 18 | 19 | (defun sty (c inst) 20 | (declare (cpu c) (instruction inst)) 21 | (write-cpu c (get-address c inst) (cpu-y c))) 22 | 23 | (defun sta (c inst) 24 | (declare (cpu c) (instruction inst)) 25 | (write-cpu c (get-address c inst) (cpu-accumulator c))) 26 | 27 | (defun stx (c inst) 28 | (declare (cpu c) (instruction inst)) 29 | (write-cpu c (get-address c inst) (cpu-x c))) 30 | 31 | (defun tax (c inst) 32 | (declare (cpu c) (instruction inst) (ignore inst)) 33 | "TAX. Transfer accumulator to x" 34 | (set-zn c (setf (cpu-x c) (cpu-accumulator c)))) 35 | 36 | (defun tay (c inst) 37 | (declare (cpu c) (instruction inst) (ignore inst)) 38 | "TAY. Transfer accumulator to y" 39 | (set-zn c (setf(cpu-y c) (cpu-accumulator c)))) 40 | 41 | (defun txa (c inst) 42 | (declare (cpu c) (instruction inst) (ignore inst)) 43 | "TXA. Transfer x to accumulator" 44 | (set-zn c (setf (cpu-accumulator c) (cpu-x c)))) 45 | 46 | (defun tya (c inst) 47 | (declare (cpu c) (instruction inst) (ignore inst)) 48 | "TYA. Transfer y to accumulator" 49 | (set-zn c (setf (cpu-accumulator c) (cpu-y c)))) 50 | 51 | (defun tsx (c inst) 52 | (declare (cpu c) (instruction inst) (ignore inst)) 53 | "TSX. Transfer stack to x" 54 | (set-zn c (setf (cpu-x c) (cpu-sp c)))) 55 | 56 | (defun txs (c inst) 57 | (declare (cpu c) (instruction inst) (ignore inst)) 58 | "TXS. Transfer x to stack" 59 | (setf (cpu-sp c) (cpu-x c))) 60 | 61 | (defun php (c inst) 62 | (declare (cpu c) (ignore inst)) 63 | (push-stack c (logior #x10 (the (unsigned-byte 8)(make-byte-from-flags (cpu-sr c)))))) 64 | 65 | (defun pha (c inst) 66 | (declare (cpu c) (instruction inst) (ignore inst)) 67 | (push-stack c (cpu-accumulator c))) 68 | 69 | (defun pla (c inst) 70 | (declare (cpu c) (instruction inst) (ignore inst)) 71 | (set-zn c (setf (cpu-accumulator c) (pull-stack c)))) 72 | 73 | (defun plp (c inst) 74 | (declare (cpu c) (instruction inst) (ignore inst)) 75 | (setf (cpu-sr c) (make-flags-from-byte (logior #x20 (logand #xEF (pull-stack c)))))) 76 | -------------------------------------------------------------------------------- /instructions/instructions.lisp: -------------------------------------------------------------------------------- 1 | (in-package :6502-cpu) 2 | 3 | (setf (gethash #x00 instructions) #'brk) 4 | (setf (gethash #x01 instructions) #'ora) 5 | (setf (gethash #x02 instructions) #'asl) 6 | (setf (gethash #x08 instructions) #'php) 7 | (setf (gethash #x10 instructions) #'bpl) 8 | (setf (gethash #x18 instructions) #'clc) 9 | (setf (gethash #x20 instructions) #'jsr) 10 | (setf (gethash #x21 instructions) #'anda) 11 | (setf (gethash #x22 instructions) #'rol) 12 | (setf (gethash #x24 instructions) #'bit-shadow) 13 | (setf (gethash #x28 instructions) #'plp) 14 | (setf (gethash #x2C instructions) #'bit-shadow) 15 | (setf (gethash #x30 instructions) #'bmi) 16 | (setf (gethash #x38 instructions) #'sec) 17 | (setf (gethash #x40 instructions) #'rti) 18 | (setf (gethash #x4C instructions) #'jmp-absolute) 19 | (setf (gethash #x41 instructions) #'eor) 20 | (setf (gethash #x42 instructions) #'lsr) 21 | (setf (gethash #x48 instructions) #'pha) 22 | (setf (gethash #x50 instructions) #'bvc) 23 | (setf (gethash #x60 instructions) #'rts) 24 | (setf (gethash #x61 instructions) #'adc) 25 | (setf (gethash #x62 instructions) #'ror) 26 | (setf (gethash #x68 instructions) #'pla) 27 | (setf (gethash #x6C instructions) #'jmp-indirect) 28 | (setf (gethash #x70 instructions) #'bvs) 29 | (setf (gethash #x78 instructions) #'sei) 30 | (setf (gethash #x80 instructions) #'sty) 31 | (setf (gethash #x81 instructions) #'sta) 32 | (setf (gethash #x82 instructions) #'stx) 33 | (setf (gethash #x88 instructions) #'dey) 34 | (setf (gethash #x8A instructions) #'txa) 35 | (setf (gethash #x90 instructions) #'bcc) 36 | (setf (gethash #x98 instructions) #'tya) 37 | (setf (gethash #x9A instructions) #'txs) 38 | (setf (gethash #xA0 instructions) #'ldy) 39 | (setf (gethash #xA1 instructions) #'lda) 40 | (setf (gethash #xA2 instructions) #'ldx) 41 | (setf (gethash #xA8 instructions) #'tay) 42 | (setf (gethash #xAA instructions) #'tax) 43 | (setf (gethash #xB0 instructions) #'bcs) 44 | (setf (gethash #xB8 instructions) #'clv) 45 | (setf (gethash #xBA instructions) #'tsx) 46 | (setf (gethash #xC0 instructions) #'cpy) 47 | (setf (gethash #xC1 instructions) #'cmp) 48 | (setf (gethash #xC2 instructions) #'dec) 49 | (setf (gethash #xC8 instructions) #'iny) 50 | (setf (gethash #xCA instructions) #'dex) 51 | (setf (gethash #xD0 instructions) #'bne) 52 | (setf (gethash #xD8 instructions) #'cld) 53 | (setf (gethash #xE0 instructions) #'cpx) 54 | (setf (gethash #xE1 instructions) #'sbc) 55 | (setf (gethash #xE2 instructions) #'inc) 56 | (setf (gethash #xE8 instructions) #'inx) 57 | (setf (gethash #xEA instructions) #'nop) 58 | (setf (gethash #xF0 instructions) #'beq) 59 | (setf (gethash #xF8 instructions) #'sed) 60 | -------------------------------------------------------------------------------- /instructions/branchops.lisp: -------------------------------------------------------------------------------- 1 | (in-package :6502-cpu) 2 | (declaim (optimize (speed 3) (safety 1))) 3 | (defun brk (c inst) 4 | (declare (cpu c) (instruction inst) (ignore inst)) 5 | "BRK: cause nmi" 6 | (push16 c (wrap-word (1+ (cpu-pc c)))) 7 | (php c nil) 8 | (sei c nil) 9 | (setf (cpu-pc c) (read16 c #xFFFE nil))) 10 | 11 | (defun rti (c inst) 12 | (declare (cpu c) (instruction inst) (ignore inst)) 13 | "Return from interrupt" 14 | (setf 15 | (cpu-sr c) 16 | (make-flags-from-byte (logior #x20 (logand (pull-stack c) #xEF)))) 17 | (setf (cpu-pc c) (pull16 c))) 18 | 19 | (defun jsr (c inst) 20 | (declare (cpu c) (instruction inst)) 21 | "JSR: jump subroutine" 22 | (push16 c (wrap-word (- (cpu-pc c) 1))) 23 | (setf (cpu-pc c) (get-address c inst))) 24 | 25 | (defun jmp-absolute (c inst) 26 | (declare (cpu c) (instruction inst)) 27 | (setf (cpu-pc c) (get-address c inst))) 28 | 29 | (defun jmp-indirect (c inst) 30 | (declare (cpu c) (instruction inst)) 31 | (setf (cpu-pc c) (get-address c inst))) 32 | 33 | (defun rts (c inst) 34 | (declare (cpu c) (instruction inst) (ignore inst)) 35 | (setf (cpu-pc c) (wrap-word (1+ (the (unsigned-byte 16) (pull16 c)))))) 36 | 37 | (defun bpl (c inst) 38 | (declare (cpu c) (instruction inst)) 39 | (when (not (flags-negative (cpu-sr c))) 40 | ;Branch taken means increment cycles 41 | (setf (cpu-cycles c) (wrap-word (1+ (cpu-cycles c)))) 42 | (setf (cpu-pc c) (get-address c inst)))) 43 | 44 | (defun bmi (c inst) 45 | (declare (cpu c) (instruction inst)) 46 | (when (flags-negative (cpu-sr c)) 47 | ;Branch taken means increment cycles 48 | (setf (cpu-cycles c) (wrap-word (1+ (cpu-cycles c)))) 49 | (setf (cpu-pc c) (get-address c inst)))) 50 | 51 | (defun bcs (c inst) 52 | (declare (cpu c) (instruction inst)) 53 | (when (flags-carry (cpu-sr c)) 54 | ;Branch taken means increment cycles 55 | (setf (cpu-cycles c) (wrap-word (1+ (cpu-cycles c)))) 56 | (setf (cpu-pc c) (get-address c inst)))) 57 | 58 | (defun bvc (c inst) 59 | (declare (cpu c) (instruction inst)) 60 | (when (not (flags-overflow (cpu-sr c))) 61 | ;Branch taken means increment cycles 62 | (setf (cpu-cycles c) (wrap-word (1+ (cpu-cycles c)))) 63 | (setf (cpu-pc c) (get-address c inst)))) 64 | 65 | (defun bvs (c inst) 66 | (declare (cpu c) (instruction inst)) 67 | (when (flags-overflow (cpu-sr c)) 68 | ;Branch taken means increment cycles 69 | (setf (cpu-cycles c) (wrap-word (1+ (cpu-cycles c)))) 70 | (setf (cpu-pc c) (get-address c inst)))) 71 | 72 | (defun bcc (c inst) 73 | (declare (cpu c) (instruction inst)) 74 | (when (not (flags-carry (cpu-sr c))) 75 | (setf (cpu-cycles c) (wrap-word (1+ (cpu-cycles c)))) 76 | (setf (cpu-pc c) (get-address c inst)))) 77 | 78 | (defun bne (c inst) 79 | (declare (cpu c) (instruction inst)) 80 | (when (not (flags-zero (cpu-sr c))) 81 | ;Branch taken means increment cycles 82 | (setf (cpu-cycles c) (wrap-word (1+ (cpu-cycles c)))) 83 | (setf (cpu-pc c) (get-address c inst)))) 84 | 85 | 86 | (defun beq (c inst) 87 | (declare (cpu c) (instruction inst)) 88 | (when (flags-zero (cpu-sr c)) 89 | ;Branch taken means increment cycles 90 | (setf (cpu-cycles c) (wrap-word (1+ (cpu-cycles c)))) 91 | (setf (cpu-pc c) (get-address c inst)))) 92 | -------------------------------------------------------------------------------- /cartridge.lisp: -------------------------------------------------------------------------------- 1 | (defpackage #:NES-cartridge 2 | (:nicknames #:nes-cart) 3 | (:use :cl) 4 | (:export #:load-cartridge #:make-cartridge #:cartridge-prg-rom 5 | #:cartridge-prg-ram #:cartridge-chr-rom #:cartridge-chr-ram 6 | #:cartridge-mirror)) 7 | 8 | (in-package :NES-cartridge) 9 | (defconstant prg-size #x4000) 10 | (defconstant chr-size #x2000) 11 | 12 | (defstruct ines-header 13 | "ines header spec" 14 | (magic (make-array 4 :element-type '(unsigned-byte 8))) 15 | ;Size of prg rom in 16 KiB units 16 | (size-of-prg-rom 0 :type (unsigned-byte 8)) 17 | ;Size of chr rom in 8 KiB units 18 | (size-of-chr-rom 0 :type (unsigned-byte 8)) 19 | (flags6 0 :type (unsigned-byte 8)) 20 | (flags7 0 :type (unsigned-byte 8)) 21 | ;Size of PRG ram in 8 KiB unites 22 | (size-of-prg-ram 0 :type (unsigned-byte 8)) 23 | (flags9 0 :type (unsigned-byte 8)) 24 | (flags10 0 :type (unsigned-byte 8)) 25 | (zero-pad (make-array 5 :element-type '(unsigned-byte 8)))) 26 | 27 | (defstruct cartridge 28 | "A model NES cartridge" 29 | (prg-rom 0) 30 | (prg-rom-window 0 :type (unsigned-byte 8)) 31 | ;We ignore prg-ram for now 32 | (prg-ram 0) 33 | (prg-ram-window 0 :type (unsigned-byte 8)) 34 | (chr-rom 0) 35 | (chr-ram 0) 36 | (chr-window 0 :type (unsigned-byte 8)) 37 | (mapper-number 0) 38 | (header 0) 39 | (mirror)) 40 | 41 | (defun load-header (seq) 42 | (make-ines-header 43 | :magic (subseq seq 0 4) 44 | :size-of-prg-rom (aref seq 4) 45 | :size-of-chr-rom (aref seq 5) 46 | :flags6 (aref seq 6) 47 | :flags7 (aref seq 7) 48 | :size-of-prg-ram (aref seq 8) 49 | :flags9 (aref seq 9) 50 | :flags10 (aref seq 10) 51 | :zero-pad (subseq seq 11 16))) 52 | 53 | (defun load-cartridge (filepath) 54 | (let ((cart (make-cartridge)) (header (make-ines-header))) 55 | (with-open-file (stream filepath :element-type '(unsigned-byte 8)) 56 | (let ((seq 57 | (make-array 58 | (file-length stream) 59 | :element-type '(unsigned-byte 8)))) 60 | (read-sequence seq stream) 61 | (setf header (load-header seq)) 62 | (let* 63 | ;If trainers are present, skip them. 64 | ((to-add 65 | (if (ldb-test (byte 1 3) (ines-header-flags6 header)) 66 | 512 67 | 0)) 68 | ;Limits of memory areas 69 | (begin-prg (+ 16 to-add)) 70 | (end-prg (+ begin-prg (* prg-size (ines-header-size-of-prg-rom header)))) 71 | (begin-chr end-prg) 72 | (end-chr (+ begin-chr (* chr-size (ines-header-size-of-chr-rom header))))) 73 | ;Load in prg-rom 74 | (setf 75 | (cartridge-prg-rom cart) 76 | (subseq 77 | seq 78 | begin-prg 79 | end-prg)) 80 | ;If there is no rom, there is ram 81 | (if (= (ines-header-size-of-chr-rom header) 0) 82 | (setf 83 | (cartridge-chr-ram cart) 84 | (make-array chr-size :element-type '(unsigned-byte 8))) 85 | (setf 86 | (cartridge-chr-rom cart) 87 | (subseq seq begin-chr end-chr))) 88 | (setf (cartridge-header cart) header) 89 | (let ((mirror1 (logand (ines-header-flags6 header) 1)) 90 | (mirror2 (logand (ash (ines-header-flags6 header) -3) 1))) 91 | (setf 92 | (cartridge-mirror cart) 93 | (logior mirror1 (ash mirror2 1)))))) 94 | cart))) 95 | -------------------------------------------------------------------------------- /console.lisp: -------------------------------------------------------------------------------- 1 | (defpackage #:NES-console 2 | (:nicknames #:nes) 3 | (:use :cl :6502-cpu :NES-cartridge :NES-ppu :NES-controller) 4 | (:export #:make-nes #:console-on #:nes-cpu #:nes-ppu #:nes-cart #:step-nes 5 | #:step-frame #:setup-and-emulate #:render-nes #:read-rom)) 6 | 7 | (in-package :NES-console) 8 | (declaim (optimize (speed 3) (safety 1))) 9 | (defstruct nes 10 | "A model nes" 11 | (cpu (6502-cpu:make-cpu)) 12 | (cart (NES-cartridge:make-cartridge)) 13 | (ppu (NES-ppu:make-ppu)) 14 | (controllers 15 | (make-array 2 :initial-contents `(,(nes-controller:make-controller) 16 | ,(nes-controller:make-controller))) 17 | :type (simple-array NES-controller:controller 1))) 18 | 19 | (defvar mirror-lookup 20 | (make-array 21 | 20 22 | :element-type '(unsigned-byte 2) 23 | :initial-contents '(0 0 1 1 0 1 0 1 0 0 0 0 1 1 1 1 0 1 2 3))) 24 | 25 | (defun read-rom (n rom-name) 26 | (declare (nes n)) 27 | (setf (nes-cart n) (NES-cartridge:load-cartridge rom-name))) 28 | 29 | (defun console-on (n) 30 | (declare (nes n)) 31 | (NES-ppu:reset-ppu (nes-ppu n)) 32 | (map-memory n) 33 | (6502-cpu:power-on (nes-cpu n))) 34 | 35 | (defun step-nes (n steps) 36 | (declare (nes n) ((unsigned-byte 32) steps)) 37 | (loop for s from 1 to steps 38 | do 39 | (let ((cycles (* 3 (the (unsigned-byte 8)(6502-CPU:step-cpu (nes-cpu n)))))) 40 | (declare ((unsigned-byte 8) cycles)) 41 | (NES-ppu:step-ppu (nes-ppu n) cycles)))) 42 | 43 | (defun step-frame (n) 44 | (declare (nes n)) 45 | (let ((frame (NES-ppu:ppu-frame (nes-ppu n))) 46 | (controller (aref (the (simple-array nes-controller:controller 1)(nes-controllers n)) 0))) 47 | (declare ((unsigned-byte 16) frame)) 48 | (loop 49 | do 50 | (progn 51 | (when (not (= frame (NES-ppu:ppu-frame (nes-ppu n)))) (return)) 52 | (nes-controller:update-controller controller) 53 | (step-nes n 1))))) 54 | 55 | (defun test-render-clear (renderer) 56 | (sdl2:set-render-draw-color renderer 0 0 0 255) 57 | (sdl2:render-clear renderer)) 58 | 59 | (defun render-nes (front renderer tex rect) 60 | (multiple-value-bind 61 | (pixels pitch) 62 | (sdl2:lock-texture tex rect) 63 | (loop for y from 0 to (- NES-ppu:screen-height 1) 64 | do 65 | (loop for x from 0 to (- NES-ppu:screen-width 1) 66 | do 67 | (let* ((color (aref (the (simple-array NES-ppu:color 1) front) (+ (* y NES-ppu:screen-width) x))) 68 | (r (color-r color)) 69 | (g (color-g color)) 70 | (b (color-b color)) 71 | (col (logior (ash #xFF 24) (ash r 16) (ash g 8) (ash b 0)))) 72 | (setf (sb-sys:sap-ref-32 pixels (* 4 (+ (* y NES-ppu:screen-width) x))) col)))) 73 | (sdl2:update-texture tex rect pixels pitch) 74 | (sdl2:unlock-texture tex)) 75 | (sdl2:render-copy renderer tex :dest-rect rect)) 76 | 77 | (defun setup-and-emulate (cart-name) 78 | (let ((a (make-nes))) 79 | (read-rom a cart-name) 80 | (console-on a) 81 | (sdl2:with-init (:everything) 82 | (sdl2:with-window (win :title "Potential-Disco" :w NES-ppu:screen-width :h NES-ppu:screen-height :flags '(:shown)) 83 | (sdl2:with-renderer (renderer win :flags '(:accelerated)) 84 | (let* ((tex (sdl2:create-texture 85 | renderer 86 | :argb8888 87 | :streaming 88 | NES-ppu:screen-width 89 | NES-ppu:screen-height)) 90 | (rect (sdl2:make-rect 0 0 NES-ppu:screen-width NES-ppu:screen-height))) 91 | (sdl2:with-event-loop (:method :poll) 92 | (:keyup 93 | (:keysym keysym) 94 | (when (sdl2:scancode= (sdl2:scancode-value keysym) :scancode-escape) 95 | (sdl2:push-event :quit))) 96 | (:idle 97 | () 98 | ;Update Controller 99 | (step-frame a) 100 | (test-render-clear renderer) 101 | (render-nes (NES-ppu:ppu-front (nes-ppu a)) renderer tex rect) 102 | (sdl2:render-present renderer)) 103 | (:quit () t)))))))) 104 | -------------------------------------------------------------------------------- /mmu.lisp: -------------------------------------------------------------------------------- 1 | (in-package :NES-console) 2 | 3 | (declaim (optimize (speed 3) (safety 1))) 4 | 5 | (defun mirror-address (mode addr) 6 | (declare ((unsigned-byte 16) addr) ((unsigned-byte 8) mode)) 7 | (let* ((address (mod (- addr #x2000) #x1000)) 8 | (table (floor address #x0400)) 9 | (offset (mod address #x0400))) 10 | (declare ((unsigned-byte 16) address table offset)) 11 | (logand #xFFFF (+ #x2000 offset (* #x0400 (the (unsigned-byte 3) (aref (the (simple-array (unsigned-byte 2) 1)mirror-lookup) (+ (* mode 4) table)))))))) 12 | 13 | (defun ppu-to-name-table-read (n) 14 | (lambda (addr) 15 | (declare ((unsigned-byte 16) addr) (nes n)) 16 | (let ((mirror (logand (mirror-address (NES-cartridge:cartridge-mirror (nes-cart n)) addr) #x7ff))) 17 | (aref (NES-ppu:ppu-name-table-data (nes-ppu n)) mirror)))) 18 | 19 | (defun ppu-to-name-table-write (n) 20 | (lambda (addr val) 21 | (declare ((unsigned-byte 16) addr) ((unsigned-byte 8) val) (nes n)) 22 | (let ((mirror (logand (mirror-address (NES-cartridge:cartridge-mirror (nes-cart n)) addr) #x7ff))) 23 | (setf (aref (NES-ppu:ppu-name-table-data (nes-ppu n)) mirror) val)))) 24 | 25 | (defun ppu-to-palette-read (n) 26 | (lambda (addr) 27 | (declare ((unsigned-byte 16) addr) (nes n)) 28 | (NES-ppu:read-palette (nes-ppu n) (logand addr #x1f)))) 29 | 30 | (defun ppu-to-palette-write (n) 31 | (lambda (addr val) 32 | (declare ((unsigned-byte 16) addr) ((unsigned-byte 8) val) (nes n)) 33 | (NES-ppu:write-palette (nes-ppu n) (logand addr #x1f) val))) 34 | 35 | (defun ppu-to-mapper-read (n) 36 | (lambda (addr) 37 | (declare ((unsigned-byte 16) addr) (nes n)) 38 | (aref 39 | (if (arrayp (NES-cartridge:cartridge-chr-ram (nes-cart n))) 40 | (the (simple-array (unsigned-byte 8) 1) (NES-cartridge:cartridge-chr-ram (nes-cart n))) 41 | (the (simple-array (unsigned-byte 8) 1) (NES-cartridge:cartridge-chr-rom (nes-cart n)))) 42 | addr))) 43 | 44 | (defun ppu-to-mapper-write (n) 45 | (lambda (addr val) 46 | (declare ((unsigned-byte 16) addr) ((unsigned-byte 8) val) (nes n)) 47 | (setf 48 | (aref 49 | (if (arrayp (NES-cartridge:cartridge-chr-ram (nes-cart n))) 50 | (the (simple-array (unsigned-byte 8) 1) (NES-cartridge:cartridge-chr-ram (nes-cart n))) 51 | (the (simple-array (unsigned-byte 8) 1) (NES-cartridge:cartridge-chr-rom (nes-cart n)))) 52 | addr) 53 | val))) 54 | 55 | (defun cpu-to-cpu-read (n) 56 | (lambda (addr) 57 | (declare ((unsigned-byte 16) addr) (nes n)) 58 | (aref (6502-cpu:cpu-memory (nes:nes-cpu n)) (mod addr #x800)))) 59 | 60 | (defun cpu-to-cpu-write (n) 61 | (lambda (addr val) 62 | (declare ((unsigned-byte 16) addr) ((unsigned-byte 8) val) (nes n)) 63 | (setf 64 | (aref (6502-cpu:cpu-memory (nes:nes-cpu n)) (mod addr #x800)) 65 | val))) 66 | 67 | (defun cpu-to-cart-read (n) 68 | (lambda (addr) 69 | (declare ((unsigned-byte 16) addr) (nes n)) 70 | (let ((prg (NES-cartridge:cartridge-prg-rom (nes-cart n)))) 71 | (declare ((simple-array (unsigned-byte 8) 1) prg)) 72 | (aref prg (mod addr (array-dimension prg 0)))))) 73 | 74 | (defun cpu-to-cart-write (n) 75 | (lambda (addr val) 76 | (declare ((unsigned-byte 16) addr) ((unsigned-byte 8) val) (nes n)) 77 | (let ((prg (NES-cartridge:cartridge-prg-rom (nes-cart n)))) 78 | (declare ((simple-array (unsigned-byte 8) 1) prg)) 79 | (setf (aref prg (mod addr (array-dimension prg 0))) val)))) 80 | 81 | (defun cpu-to-ppu-read (n) 82 | (lambda (addr) 83 | (declare ((unsigned-byte 16) addr) (nes n)) 84 | ;If oam, don't mod the address 85 | (if (= addr #x4014) 86 | (NES-ppu:read-register (nes-ppu n) addr) 87 | (NES-ppu:read-register (nes-ppu n) (mod addr 8))))) 88 | 89 | (defun cpu-to-ppu-write (n) 90 | (lambda (addr val) 91 | (declare ((unsigned-byte 16) addr) ((unsigned-byte 8) val) (nes n)) 92 | (if (= addr #x4014) 93 | (NES-ppu:write-register (nes-ppu n) addr val) 94 | (NES-ppu:write-register (nes-ppu n) (mod addr 8) val)))) 95 | 96 | (defun cpu-to-io-read (n) 97 | (lambda (addr) 98 | (declare ((unsigned-byte 16) addr) (nes n)) 99 | (if (or (= addr #x4016) (= addr #x4017)) 100 | (NES-controller:read-controller 101 | (aref (nes-controllers n) (mod addr 2))) 102 | 0))) 103 | 104 | (defun cpu-to-io-write (n) 105 | (lambda (addr val) 106 | (declare ((unsigned-byte 16) addr) ((unsigned-byte 8) val) (nes n)) 107 | (if (or (= addr #x4016) (= addr #x4017)) 108 | (NES-controller:write-controller 109 | (aref (nes-controllers n) (mod addr 2)) val) 110 | 0))) 111 | 112 | (defun map-memory (n) 113 | (setf (NES-ppu:ppu-trigger-nmi-callback (nes-ppu n)) (6502-cpu:trigger-nmi-callback (nes-cpu n))) 114 | (setf (NES-ppu:ppu-oam-dma-callback (nes-ppu n)) (lambda (addr) (6502-cpu:read-cpu (nes-cpu n) addr))) 115 | (setf (NES-ppu:ppu-oam-stall-adder (nes-ppu n)) (6502-cpu:add-to-stall (nes-cpu n))) 116 | (setf (aref (NES-ppu:ppu-memory-get (nes-ppu n)) 0) (ppu-to-mapper-read n)) 117 | (setf (aref (NES-ppu:ppu-memory-set (nes-ppu n)) 0) (ppu-to-mapper-write n)) 118 | (setf (aref (NES-ppu:ppu-memory-get (nes-ppu n)) 1) (ppu-to-name-table-read n)) 119 | (setf (aref (NES-ppu:ppu-memory-set (nes-ppu n)) 1) (ppu-to-name-table-write n)) 120 | (setf (aref (NES-ppu:ppu-memory-get (nes-ppu n)) 2) (ppu-to-palette-read n)) 121 | (setf (aref (NES-ppu:ppu-memory-set (nes-ppu n)) 2) (ppu-to-palette-write n)) 122 | (setf (aref (6502-cpu:cpu-memory-get (nes-cpu n)) 0) (cpu-to-cpu-read n)) 123 | (setf (aref (6502-cpu:cpu-memory-set (nes-cpu n)) 0) (cpu-to-cpu-write n)) 124 | (setf (aref (6502-cpu:cpu-memory-get (nes-cpu n)) 1) (cpu-to-ppu-read n)) 125 | (setf (aref (6502-cpu:cpu-memory-set (nes-cpu n)) 1) (cpu-to-ppu-write n)) 126 | (setf (aref (6502-cpu:cpu-memory-get (nes-cpu n)) 2) (cpu-to-io-read n)) 127 | (setf (aref (6502-cpu:cpu-memory-set (nes-cpu n)) 2) (cpu-to-io-write n)) 128 | (setf (aref (6502-cpu:cpu-memory-get (nes-cpu n)) 5) (cpu-to-cart-read n)) 129 | (setf 130 | (NES-controller:controller-buttons-callback (aref (nes-controllers n) 0)) 131 | #'get-buttons)) 132 | -------------------------------------------------------------------------------- /instructions/arithmeticops.lisp: -------------------------------------------------------------------------------- 1 | (in-package :6502-cpu) 2 | (declaim (optimize (speed 3) (safety 1))) 3 | (defun nop (c inst) 4 | (declare (cpu c) (instruction inst) (ignore c inst))) 5 | 6 | (defun adc (c inst) 7 | (declare (cpu c) (instruction inst)) 8 | (let* ((a (cpu-accumulator c)) 9 | (b (get-value c inst)) 10 | (carry (if (flags-carry (cpu-sr c)) 1 0)) 11 | (result (+ a b carry))) 12 | (declare ((unsigned-byte 8) a b carry)) 13 | 14 | (set-zn c (setf (cpu-accumulator c) (wrap-byte result))) 15 | (setf (flags-carry (cpu-sr c)) (> result 255)) 16 | (setf 17 | (flags-overflow (cpu-sr c)) 18 | (and (= (logand #x80 (logxor a b)) 0) (/= (logand #x80 (logxor a (cpu-accumulator c))) 0))))) 19 | 20 | (defun sbc (c inst) 21 | (declare (cpu c) (instruction inst)) 22 | (let* ((a (cpu-accumulator c)) 23 | (b (get-value c inst)) 24 | (carry (if (flags-carry (cpu-sr c)) 1 0)) 25 | (result (- a b (- 1 carry)))) 26 | (declare ((unsigned-byte 8) a b carry)) 27 | 28 | (set-zn c (setf (cpu-accumulator c) (wrap-byte result))) 29 | (setf (flags-carry (cpu-sr c)) (>= result 0)) 30 | (setf 31 | (flags-overflow (cpu-sr c)) 32 | (and (/= (logand #x80 (logxor a b)) 0) (/= (logand #x80 (logxor a (cpu-accumulator c))) 0))))) 33 | 34 | (defun asl (c inst) 35 | (declare (cpu c) (instruction inst)) 36 | "ASL: Shift left one bit" 37 | (let ((mode (instruction-addressing-mode inst)) 38 | (val (get-value c inst)) 39 | (addr (get-address c inst))) 40 | (declare ((unsigned-byte 8) val) ((unsigned-byte 16) addr)) 41 | 42 | (setf (flags-carry (cpu-sr c)) (ldb-test (byte 1 7) val)) 43 | (set-zn 44 | c 45 | (if (equal mode :accumulator) 46 | (setf (cpu-accumulator c) (wrap-byte (ash val 1))) 47 | (write-cpu c addr (wrap-byte (ash val 1))))))) 48 | 49 | (defun lsr (c inst) 50 | (declare (cpu c) (instruction inst)) 51 | "LSR:Shift one bit right" 52 | (let ((mode (instruction-addressing-mode inst)) 53 | (val (get-value c inst)) 54 | (addr (get-address c inst))) 55 | (declare ((unsigned-byte 8) val) ((unsigned-byte 16) addr)) 56 | 57 | (setf (flags-carry (cpu-sr c)) (ldb-test (byte 1 0) val)) 58 | (set-zn 59 | c 60 | (if (equal mode :accumulator) 61 | (setf (cpu-accumulator c) (wrap-byte (ash val -1))) 62 | (write-cpu c addr (wrap-byte (ash val -1))))))) 63 | 64 | (defun rol (c inst) 65 | (declare (cpu c) (instruction inst)) 66 | "ROL: Rotate all bits left" 67 | (let ((mode (instruction-addressing-mode inst)) 68 | (val (get-value c inst)) 69 | (addr (get-address c inst)) 70 | (carry (if (flags-carry (cpu-sr c)) 1 0))) 71 | (declare ((unsigned-byte 8) val carry) ((unsigned-byte 16) addr)) 72 | 73 | (setf (flags-carry (cpu-sr c)) (ldb-test (byte 1 7) val)) 74 | (set-zn 75 | c 76 | (if (equal mode :accumulator) 77 | (setf (cpu-accumulator c) (wrap-byte (logior carry (ash val 1)))) 78 | (write-cpu c addr (wrap-byte (logior carry (ash val 1)))))))) 79 | 80 | (defun ror (c inst) 81 | (declare (cpu c) (instruction inst)) 82 | "ROR: Rotate all bits rights" 83 | (let ((mode (instruction-addressing-mode inst)) 84 | (val (get-value c inst)) 85 | (addr (get-address c inst)) 86 | (carry (if (flags-carry (cpu-sr c)) 128 0))) 87 | (declare ((unsigned-byte 8) carry val) ((unsigned-byte 16) addr)) 88 | 89 | (setf (flags-carry (cpu-sr c)) (ldb-test (byte 1 0) val)) 90 | (set-zn 91 | c 92 | (if (equal mode :accumulator) 93 | (setf (cpu-accumulator c) (logior carry (ash val -1))) 94 | (write-cpu c addr (logior carry (ash val -1))))))) 95 | 96 | (defun ora (c inst) 97 | (declare (cpu c) (instruction inst)) 98 | "ORA: or value with accumulator" 99 | (let ((val (get-value c inst))) 100 | (declare ((unsigned-byte 8) val)) 101 | (set-zn c (setf (cpu-accumulator c) (logior val (cpu-accumulator c)))))) 102 | 103 | (defun eor (c inst) 104 | (declare (cpu c) (instruction inst)) 105 | "EOR: xor with accumulator" 106 | (let ((val (get-value c inst))) 107 | (declare ((unsigned-byte 8) val)) 108 | (set-zn c (setf (cpu-accumulator c) (logxor val (cpu-accumulator c)))))) 109 | 110 | (defun anda (c inst) 111 | (declare (cpu c) (instruction inst)) 112 | "ANDA: and value with accumulator" 113 | (let ((val (get-value c inst))) 114 | (declare ((unsigned-byte 8) val)) 115 | (set-zn c (setf (cpu-accumulator c) (logand val (cpu-accumulator c)))))) 116 | 117 | (defun bit-shadow (c inst) 118 | (declare (cpu c) (instruction inst)) 119 | "BIT: and value with accumulator, don't store." 120 | (let ((val (get-value c inst))) 121 | (declare ((unsigned-byte 8) val)) 122 | 123 | (set-zn c (logand val (cpu-accumulator c))) 124 | (setf (flags-negative (cpu-sr c)) (ldb-test (byte 1 7) val)) 125 | (setf (flags-overflow (cpu-sr c)) (ldb-test (byte 1 6) val)))) 126 | 127 | (defun cmp (c inst) 128 | (declare (cpu c) (instruction inst)) 129 | (let ((val (get-value c inst))) 130 | (declare ((unsigned-byte 8) val)) 131 | (setf (flags-carry (cpu-sr c)) (>= (cpu-accumulator c) val)) 132 | (set-zn c (wrap-byte (- (cpu-accumulator c) val))))) 133 | 134 | (defun cpy (c inst) 135 | (declare (cpu c) (instruction inst)) 136 | (let ((val (get-value c inst))) 137 | (declare ((unsigned-byte 8) val)) 138 | (setf (flags-carry (cpu-sr c)) (>= (cpu-y c) val)) 139 | (set-zn c (wrap-byte (- (cpu-y c) val))))) 140 | 141 | (defun cpx (c inst) 142 | (declare (cpu c) (instruction inst)) 143 | (let ((val (get-value c inst))) 144 | (declare ((unsigned-byte 8) val)) 145 | (setf (flags-carry (cpu-sr c)) (>= (cpu-x c) val)) 146 | (set-zn c (wrap-byte (- (cpu-x c) val))))) 147 | 148 | (defun dey (c inst) 149 | (declare (cpu c) (instruction inst) (ignore inst)) 150 | "DEY: Decrement y register" 151 | (set-zn c (setf (cpu-y c) (wrap-byte (- (cpu-y c) 1))))) 152 | 153 | (defun dex (c inst) 154 | (declare (cpu c) (instruction inst) (ignore inst)) 155 | "DEY: Decrement y register" 156 | (set-zn c (setf (cpu-x c) (wrap-byte (- (cpu-x c) 1))))) 157 | 158 | (defun dec (c inst) 159 | (declare (cpu c) (instruction inst)) 160 | (let ((val (get-value c inst)) (addr (get-address c inst))) 161 | (declare ((unsigned-byte 8) val) ((unsigned-byte 16) addr)) 162 | (set-zn c (write-cpu c addr (wrap-byte (- val 1)))))) 163 | 164 | (defun inc (c inst) 165 | (declare (cpu c) (instruction inst)) 166 | (let ((val (get-value c inst)) (addr (get-address c inst))) 167 | (declare ((unsigned-byte 8) val) ((unsigned-byte 16) addr)) 168 | (set-zn c (write-cpu c addr (wrap-byte (1+ val)))))) 169 | 170 | (defun inx (c inst) 171 | (declare (cpu c) (instruction inst) (ignore inst)) 172 | (set-zn c (setf (cpu-x c) (wrap-byte (1+ (cpu-x c)))))) 173 | 174 | (defun iny (c inst) 175 | (declare (cpu c) (instruction inst) (ignore inst)) 176 | (set-zn c (setf (cpu-y c) (wrap-byte (1+ (cpu-y c)))))) 177 | -------------------------------------------------------------------------------- /cpu.lisp: -------------------------------------------------------------------------------- 1 | (defpackage #:6502-cpu 2 | (:nicknames #:cpu) 3 | (:use :cl) 4 | (:export #:make-cpu #:reset #:power-on #:cpu-cycles #:cpu-accumulator #:cpu-pc 5 | #:cpu-memory #:step-pc #:fetch #:step-cpu #:make-instruction 6 | #:cpu-memory-get #:cpu-memory-set #:to-signed-byte-8 #:read-cpu 7 | #:trigger-nmi-callback #:trigger-irq-callback #:add-to-stall)) 8 | 9 | (in-package :6502-cpu) 10 | (declaim (optimize (speed 3) (safety 1))) 11 | (defvar instructions (make-hash-table :test 'equal)) 12 | 13 | (defvar 14 | cycles-per-instruction 15 | (make-array 16 | 256 17 | :element-type '(unsigned-byte 8) 18 | :initial-contents 19 | '(7 6 2 8 3 3 5 5 3 2 2 2 4 4 6 6 20 | 2 5 2 8 4 4 6 6 2 4 2 7 4 4 7 7 21 | 6 6 2 8 3 3 5 5 4 2 2 2 4 4 6 6 22 | 2 5 2 8 4 4 6 6 2 4 2 7 4 4 7 7 23 | 6 6 2 8 3 3 5 5 3 2 2 2 3 4 6 6 24 | 2 5 2 8 4 4 6 6 2 4 2 7 4 4 7 7 25 | 6 6 2 8 3 3 5 5 4 2 2 2 5 4 6 6 26 | 2 5 2 8 4 4 6 6 2 4 2 7 4 4 7 7 27 | 2 6 2 6 3 3 3 3 2 2 2 2 4 4 4 4 28 | 2 6 2 6 4 4 4 4 2 5 2 5 5 5 5 5 29 | 2 6 2 6 3 3 3 3 2 2 2 2 4 4 4 4 30 | 2 5 2 5 4 4 4 4 2 4 2 4 4 4 4 4 31 | 2 6 2 8 3 3 5 5 2 2 2 2 4 4 6 6 32 | 2 5 2 8 4 4 6 6 2 4 2 7 4 4 7 7 33 | 2 6 2 8 3 3 5 5 2 2 2 2 4 4 6 6 34 | 2 5 2 8 4 4 6 6 2 4 2 7 4 4 7 7))) 35 | 36 | (defvar 37 | instruction-page-cycles 38 | (make-array 39 | 256 40 | :element-type '(unsigned-byte 8) 41 | :initial-contents 42 | '(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 43 | 1 1 0 0 0 0 0 0 0 1 0 0 1 1 0 0 44 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 45 | 1 1 0 0 0 0 0 0 0 1 0 0 1 1 0 0 46 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 47 | 1 1 0 0 0 0 0 0 0 1 0 0 1 1 0 0 48 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 49 | 1 1 0 0 0 0 0 0 0 1 0 0 1 1 0 0 50 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 51 | 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 52 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 53 | 1 1 0 1 0 0 0 0 0 1 0 1 1 1 1 1 54 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 | 1 1 0 0 0 0 0 0 0 1 0 0 1 1 0 0 56 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 57 | 1 1 0 0 0 0 0 0 0 1 0 0 1 1 0 0))) 58 | 59 | (defvar instructions (make-hash-table :test 'equal)) 60 | 61 | (defstruct flags 62 | "Flag register" 63 | (carry nil) 64 | (zero nil) 65 | (interrupt nil) 66 | (bcd nil) 67 | (soft-interrupt nil) 68 | (unused T) 69 | (overflow nil) 70 | (negative nil)) 71 | 72 | (defstruct cpu 73 | "A model 6502" 74 | (cycles 0 :type (unsigned-byte 16)) 75 | (stall 0 :type (unsigned-byte 16)) 76 | (accumulator 0 :type (unsigned-byte 8)) 77 | (x 0 :type (unsigned-byte 8)) 78 | (y 0 :type (unsigned-byte 8)) 79 | (pc 0 :type (unsigned-byte 16)) 80 | (sp 0 :type (unsigned-byte 8)) 81 | (sr (make-flags) :type flags) 82 | (memory-get 83 | (make-array 6 :element-type 'function :initial-element (lambda ())) 84 | :type (simple-array function 1)) 85 | (memory-set 86 | (make-array 3 :element-type 'function :initial-element (lambda ())) 87 | :type (simple-array function 1)) 88 | (memory 89 | (make-array #x800 :element-type '(unsigned-byte 8)) 90 | :type (simple-array (unsigned-byte 8) 1)) 91 | (interrupt :none)) 92 | 93 | (defstruct instruction 94 | "6502 instruction" 95 | (unmasked-opcode 0 :type (unsigned-byte 8)) 96 | (opcode 0 :type (unsigned-byte 8)) 97 | (hi-byte 0 :type (unsigned-byte 8)) 98 | (lo-byte 0 :type (unsigned-byte 8)) 99 | (addressing-mode :implicit)) 100 | 101 | (defun add-to-stall (c) 102 | (lambda (to-add) 103 | (declare ((unsigned-byte 16) to-add) (cpu c)) 104 | (incf (cpu-stall c) to-add) 105 | (when (= (mod (cpu-cycles c) 2) 1) (incf (cpu-stall c))))) 106 | 107 | (defun trigger-nmi-callback (c) 108 | (declare (cpu c)) 109 | (lambda () 110 | (setf (cpu-interrupt c) :nmi))) 111 | 112 | (defun trigger-irq-callback (c) 113 | (declare (cpu c)) 114 | (lambda () 115 | (when (not (flags-interrupt (cpu-sr c))) 116 | (setf (cpu-interrupt c) :irq)))) 117 | 118 | (defun wrap-byte (val) 119 | (declare ((signed-byte 64) val)) 120 | (ldb (byte 8 0) val)) 121 | 122 | (defun wrap-word (val) 123 | (declare ((signed-byte 64) val)) 124 | (ldb (byte 16 0) val)) 125 | 126 | (defun make-byte-from-flags (f) 127 | (declare (flags f)) 128 | (logior 129 | (if (flags-carry f) 1 0) 130 | (ash (if (flags-zero f) 1 0) 1) 131 | (ash (if (flags-interrupt f) 1 0) 2) 132 | (ash (if (flags-bcd f) 1 0) 3) 133 | (ash (if (flags-soft-interrupt f) 1 0) 4) 134 | (ash (if (flags-unused f) 1 0) 5) 135 | (ash (if (flags-overflow f) 1 0) 6) 136 | (ash (if (flags-negative f) 1 0) 7))) 137 | 138 | (defun make-flags-from-byte (val) 139 | (declare ((unsigned-byte 8) val)) 140 | (make-flags 141 | :carry (ldb-test (byte 1 0) val) 142 | :zero (ldb-test (byte 1 1) val) 143 | :interrupt (ldb-test (byte 1 2) val) 144 | :bcd (ldb-test (byte 1 3) val) 145 | :soft-interrupt (ldb-test (byte 1 4) val) 146 | :unused (ldb-test (byte 1 5) val) 147 | :overflow (ldb-test (byte 1 6) val) 148 | :negative (ldb-test (byte 1 7) val))) 149 | 150 | (defun to-signed-byte-8 (val) 151 | (declare ((unsigned-byte 8) val)) 152 | (if (ldb-test (byte 1 7) val) 153 | (* -1 (wrap-byte (1+ (lognot val)))) 154 | val)) 155 | 156 | (defun make-word-from-bytes (hi lo) 157 | (declare ((unsigned-byte 8) hi lo)) 158 | (the (unsigned-byte 16) (logior (ash hi 8) lo))) 159 | 160 | (defun pages-differ (a b) 161 | (declare ((unsigned-byte 16) a b)) 162 | (/= (ldb (byte 8 8) a) (ldb (byte 8 8) b))) 163 | 164 | (defun read-cpu (c addr) 165 | (declare (cpu c) ((unsigned-byte 16) addr)) 166 | "Reads the memory at the specified address" 167 | (cond 168 | ;CPU internal memory 169 | ((<= addr #x1FFF) (funcall (aref (cpu-memory-get c) 0) addr)) 170 | ;PPU 171 | ((<= addr #x3FFF) (funcall (aref (cpu-memory-get c) 1) addr)) 172 | ;APU and IO Registers 173 | ((<= addr #x401F) (funcall (aref (cpu-memory-get c) 2) addr)) 174 | ;Mapper Registers 175 | ((<= addr #x5FFF) (progn (print "Reads from cpu to mapper unimplemented....") 0)) 176 | ;SAVE RAM 177 | ((<= addr #x7FFF) (progn (print "Reads from cpu to save ram unimplemented....") 0)) 178 | ;PRG ROM 179 | ((<= addr #xFFFF) (funcall (aref (cpu-memory-get c) 5) addr)))) 180 | 181 | (defun read16 (c addr bug) 182 | (declare (cpu c) ((unsigned-byte 16) addr)) 183 | "Emulate indirect bugs..." 184 | (let ((lo (read-cpu c addr)) 185 | (hi (read-cpu c (wrap-word (1+ addr)))) 186 | (hi-bug (read-cpu c (logior (logand addr #xFF00) (wrap-byte (1+ addr)))))) 187 | (the (unsigned-byte 16) (make-word-from-bytes (if bug hi-bug hi) lo)))) 188 | 189 | (defun write-cpu (c addr val) 190 | (declare (cpu c) ((unsigned-byte 16) addr) ((unsigned-byte 8) val)) 191 | (cond 192 | ;CPU internal memory 193 | ((<= addr #x1FFF) (funcall (aref (cpu-memory-set c) 0) addr val)) 194 | ;PPU Registers 195 | ((<= addr #x3FFF) (funcall (aref (cpu-memory-set c) 1) addr val)) 196 | ;Don't forget oam-dma 197 | ((= addr #x4014) (funcall (aref (cpu-memory-set c) 1) addr val)) 198 | ;APU and IO Registers 199 | ((<= addr #x401F) (funcall (aref (cpu-memory-set c) 2) addr val)) 200 | ;SAVE RAM 201 | ((and (<= addr #x7FFF) (>= addr #x6000)) 202 | (progn (print "Writes to save ram unimplemented...") 0)) 203 | (T 0))) 204 | 205 | (defun reset (c) 206 | (declare (cpu c)) 207 | "Reset state of cpu" 208 | (setf (cpu-sp c) (wrap-byte (- (cpu-sp c) 3))) 209 | (setf (flags-interrupt (cpu-sr c)) T)) 210 | 211 | (defun power-on (c) 212 | (declare (cpu c)) 213 | "Power on state of cpu" 214 | (setf 215 | (cpu-sr c) 216 | (make-flags 217 | :carry nil 218 | :zero nil 219 | :interrupt T 220 | :bcd nil 221 | :soft-interrupt T 222 | :unused T 223 | :overflow nil 224 | :negative nil)) 225 | (setf (cpu-sp c) #xFD) 226 | (setf (cpu-pc c) (read16 c #xFFFC nil))) 227 | 228 | (defun pull-stack (c) 229 | (declare (cpu c)) 230 | "Empty stack pull" 231 | (setf (cpu-sp c) (wrap-byte (1+ (cpu-sp c)))) 232 | (aref (cpu-memory c) (logior (cpu-sp c) #x100))) 233 | 234 | (defun push-stack (c val) 235 | (declare (cpu c) ((unsigned-byte 8) val)) 236 | "Put a value on the stack and then push it forwards" 237 | (setf (aref (cpu-memory c) (logior (cpu-sp c) #x100)) val) 238 | (setf (cpu-sp c) (wrap-byte (- (cpu-sp c) 1)))) 239 | 240 | (defun pull16 (c) 241 | (declare (cpu c)) 242 | "Pull twice and make a 16 bit address." 243 | (the (unsigned-byte 16) (logior (pull-stack c) (ash (pull-stack c) 8)))) 244 | 245 | (defun push16 (c val) 246 | (declare (cpu c) ((unsigned-byte 16) val)) 247 | "Push twice." 248 | (push-stack c (ldb (byte 8 8) val)) 249 | (push-stack c (ldb (byte 8 0) val))) 250 | 251 | (defun step-pc (c inst) 252 | (declare (cpu c) (instruction inst)) 253 | "Step the pc according to the addressing mode." 254 | (let ((mode (instruction-addressing-mode inst))) 255 | (setf 256 | (cpu-pc c) 257 | (wrap-word 258 | (+ 259 | (cpu-pc c) 260 | (case mode 261 | (:implicit 1) 262 | (:accumulator 1) 263 | (:immediate 2) 264 | (:zero-page 2) 265 | (:absolute 3) 266 | (:relative 2) 267 | (:indirect 3) 268 | (:zero-page-indexed-x 2) 269 | (:zero-page-indexed-y 2) 270 | (:absolute-indexed-x 3) 271 | (:absolute-indexed-y 3) 272 | (:indexed-indirect 2) 273 | (:indirect-indexed 2) 274 | (otherwise 1))))))) 275 | 276 | (defun set-zn (c val) 277 | (declare (cpu c) ((unsigned-byte 8) val)) 278 | "Sets the zero or negative flag" 279 | ;If zero, set the bit 280 | (setf (flags-zero (cpu-sr c)) (= val 0)) 281 | ;If the MSB is set, it's negative. 282 | (setf (flags-negative (cpu-sr c)) (ldb-test (byte 1 7) val))) 283 | 284 | (defun get-address (c inst) 285 | (declare (cpu c) (instruction inst)) 286 | "Get the address the instruction is talking about" 287 | (let ((mode (instruction-addressing-mode inst)) 288 | (lo-byte (instruction-lo-byte inst)) 289 | (hi-byte (instruction-hi-byte inst))) 290 | (declare ((unsigned-byte 8) lo-byte hi-byte)) 291 | (case mode 292 | ;Somewhere in zero page... 293 | (:zero-page lo-byte) 294 | ;Super simple, just make a two byte address from the supplied two bytes 295 | (:absolute (make-word-from-bytes hi-byte lo-byte)) 296 | ;Treat the low byte as though it were signed, use it as an offset for PC 297 | (:relative (wrap-word (+ (cpu-pc c) (to-signed-byte-8 lo-byte)))) 298 | ;Read the address contained at the supplied two byte address. 299 | (:indirect 300 | (let ((ptr-addr (make-word-from-bytes hi-byte lo-byte))) 301 | (read16 c ptr-addr T))) 302 | ;Add the x register to the low-byte for zero-page addressing 303 | (:zero-page-indexed-x (wrap-byte (+ lo-byte (cpu-x c)))) 304 | ;Add the y register to the low-byte for zero-page addressing 305 | (:zero-page-indexed-y (wrap-byte (+ lo-byte (cpu-y c)))) 306 | ;Add the x register to the supplied two byte address 307 | (:absolute-indexed-x 308 | (wrap-word 309 | (+ 310 | (make-word-from-bytes hi-byte lo-byte) 311 | (cpu-x c)))) 312 | ;Add the y register to the supplied two byte address 313 | (:absolute-indexed-y 314 | (wrap-word 315 | (+ 316 | (make-word-from-bytes hi-byte lo-byte) 317 | (cpu-y c)))) 318 | ;Get the address contained at lo-byte + x 319 | (:indexed-indirect 320 | (read16 c (wrap-byte (+ lo-byte (cpu-x c))) T)) 321 | ;Get the address containted at lo-byte + y 322 | (:indirect-indexed 323 | (wrap-word (+ (cpu-y c) (read16 c lo-byte T)))) 324 | (otherwise 0)))) 325 | 326 | (defun get-value (c inst) 327 | (declare (cpu c) (instruction inst)) 328 | "Get the value from an instruction" 329 | (case (instruction-addressing-mode inst) 330 | (:immediate (instruction-lo-byte inst)) 331 | (:accumulator (cpu-accumulator c)) 332 | (otherwise (read-cpu c (get-address c inst))))) 333 | 334 | (defun fetch (c) 335 | (declare (cpu c)) 336 | "Fetch the next instruction from memory" 337 | (make-instruction 338 | :unmasked-opcode (read-cpu c (cpu-pc c)) 339 | :lo-byte (read-cpu c (wrap-word (+ (cpu-pc c) 1))) 340 | :hi-byte (read-cpu c (wrap-word (+ (cpu-pc c) 2))))) 341 | 342 | (defun determine-addressing-mode (opcode) 343 | (declare ((unsigned-byte 8) opcode)) 344 | ;We really only care about the opcode as: AAA???CC 345 | ;BBB is normally just addressing mode, which we store in the intstruction 346 | (let ((cc (ldb (byte 2 0) opcode)) 347 | (bbb (ldb (byte 3 2) opcode)) 348 | (aaa (ldb (byte 3 5) opcode))) 349 | (case cc 350 | (0 351 | (case bbb 352 | (0 :immediate) 353 | (1 :zero-page) 354 | (3 :absolute) 355 | (5 :zero-page-indexed-x) 356 | (7 :absolute-indexed-x))) 357 | (1 358 | (case bbb 359 | (0 :indexed-indirect) 360 | (1 :zero-page) 361 | (2 :immediate) 362 | (3 :absolute) 363 | (4 :indirect-indexed) 364 | (5 :zero-page-indexed-x) 365 | (6 :absolute-indexed-y) 366 | (7 :absolute-indexed-x))) 367 | (2 368 | (case bbb 369 | (0 :immediate) 370 | (1 :zero-page) 371 | (2 :accumulator) 372 | (3 :absolute) 373 | (5 (if (member aaa '(4 5)) :zero-page-indexed-y :zero-page-indexed-x)) 374 | (7 (if (= aaa 5) :absolute-indexed-y :absolute-indexed-x)))) 375 | (otherwise (print "Bad opcode"))))) 376 | 377 | ;TODO: Test this somehow... 378 | (defun decode (inst) 379 | (declare (instruction inst)) 380 | "Decodes the opcode and returns a constructed instruction." 381 | (let* 382 | ((opcode (instruction-unmasked-opcode inst)) 383 | (lo-byte (instruction-lo-byte inst)) 384 | (hi-byte (instruction-hi-byte inst)) 385 | (masked-opcode (logand opcode #xE3)) 386 | (addressing-mode (determine-addressing-mode opcode))) 387 | ;If it is a special case, modify 388 | (cond 389 | ((member opcode '(#x10 #x30 #x50 #x70 #x90 #xB0 #xD0 #xF0)) 390 | (progn 391 | (setf addressing-mode :relative) 392 | (setf masked-opcode opcode))) 393 | ((member opcode '(#x20 #x2C #x4C)) 394 | (progn 395 | (setf addressing-mode :absolute) 396 | (setf masked-opcode opcode))) 397 | ((= opcode #x6C) 398 | (progn 399 | (setf addressing-mode :indirect) 400 | (setf masked-opcode opcode))) 401 | ((= opcode #x24) 402 | (progn 403 | (setf addressing-mode :zero-page) 404 | (setf masked-opcode opcode))) 405 | ((member opcode '(#x08 #x28 #x48 #x68 #x88 #xA8 #xC8 #xE8 #x18 406 | #x38 #x58 #x78 #x98 #xB8 #xD8 #xF8 #x8A 407 | #x9A #xAA #xBA #xCA #xEA #x00 #x40 #x60)) 408 | (progn 409 | (setf addressing-mode :implicit) 410 | (setf masked-opcode opcode)))) 411 | ;Make the instruction 412 | (make-instruction 413 | :addressing-mode addressing-mode 414 | :opcode masked-opcode 415 | :unmasked-opcode opcode 416 | :hi-byte hi-byte 417 | :lo-byte lo-byte))) 418 | 419 | (defun instruction-cycles (c inst) 420 | (declare (cpu c) (instruction inst)) 421 | (let* ((address (get-address c inst)) 422 | (mode (instruction-addressing-mode inst)) 423 | (unmasked (instruction-unmasked-opcode inst)) 424 | (page-cycles 425 | (aref 426 | (the (simple-array (unsigned-byte 8) 1) instruction-page-cycles) 427 | unmasked))) 428 | (declare ((unsigned-byte 16) address) 429 | ((unsigned-byte 8) unmasked page-cycles) 430 | (type (simple-array (unsigned-byte 8) 1) cycles-per-instruction)) 431 | (+ 432 | ;Get the number of cycles as per usual 433 | (aref cycles-per-instruction unmasked) 434 | ;Add page-cycles if we crossed a bound 435 | (case mode 436 | (:absolute-indexed-x 437 | (if (pages-differ address (wrap-word (- address (cpu-x c)))) 438 | page-cycles 439 | 0)) 440 | (:absolute-indexed-y 441 | (if (pages-differ address (wrap-word (- address (cpu-y c)))) 442 | page-cycles 443 | 0)) 444 | (:indirect-indexed 445 | (if (pages-differ 446 | address 447 | (wrap-word (- address (cpu-y c)))) 448 | page-cycles 449 | 0)) 450 | (otherwise 0))))) 451 | 452 | (defun execute (c inst) 453 | (declare (cpu c) (instruction inst)) 454 | (let ((cycles (instruction-cycles c inst)) 455 | (instruction (gethash (instruction-opcode inst) instructions))) 456 | (declare ((unsigned-byte 8) cycles) (function instruction)) 457 | (funcall instruction c inst) 458 | (setf (cpu-cycles c) (wrap-word (+ cycles (cpu-cycles c)))) 459 | cycles)) 460 | 461 | (defun nmi (c) 462 | (declare (cpu c)) 463 | (push16 c (cpu-pc c)) 464 | (php c nil) 465 | (setf (cpu-pc c) (read16 c #xFFFA nil)) 466 | (setf (flags-interrupt (cpu-sr c)) T) 467 | (setf (cpu-cycles c) (wrap-word (+ 7 (cpu-cycles c))))) 468 | 469 | (defun irq (c) 470 | (declare (cpu c)) 471 | (push16 c (cpu-pc c)) 472 | (php c nil) 473 | (setf (cpu-pc c) (read16 c #xFFFE nil)) 474 | (setf (flags-interrupt (cpu-sr c)) T) 475 | (setf (cpu-cycles c) (wrap-word (+ 7 (cpu-cycles c))))) 476 | 477 | (defun step-cpu (c) 478 | (declare (cpu c)) 479 | "Steps the cpu through an instruction, returns the number of cycles it took." 480 | (if (> (cpu-stall c) 0) 481 | (progn 482 | (decf (cpu-stall c)) 483 | 1) 484 | (progn 485 | (case (cpu-interrupt c) 486 | (:none 0) 487 | (:irq (irq c)) 488 | (:nmi (nmi c))) 489 | (setf (cpu-interrupt c) :none) 490 | (let ((inst (decode (fetch c)))) 491 | ;Remember to step the pc before execution. 492 | (step-pc c inst) 493 | (execute c inst))))) 494 | -------------------------------------------------------------------------------- /ppu.lisp: -------------------------------------------------------------------------------- 1 | ;; Almost all of my understanding of the PPU comes from.. 2 | ;; The nesdev wiki 3 | ;; Sprocket-NES 4 | ;; Fogleman's NES 5 | ;; Famiclom 6 | ;; As such, this is basically a translation of https://github.com/fogleman/nes/blob/master/nes/ppu.go 7 | ;; Hopefully, I can eventually gain a better understanding 8 | 9 | (defpackage #:NES-ppu 10 | (:nicknames #:ppu) 11 | (:use :cl) 12 | (:export #:step-ppu #:make-ppu #:reset-ppu #:read-register #:write-register 13 | #:ppu-trigger-nmi-callback #:ppu-front #:ppu-back #:ppu-frame 14 | #:color-r #:color-g #:color-b #:color #:read-palette #:write-palette 15 | #:ppu-memory-get #:ppu-memory-set #:ppu-name-table-data 16 | #:ppu-oam-dma-callback #:ppu-oam-stall-adder #:screen-width #:screen-height)) 17 | 18 | (in-package :NES-ppu) 19 | (declaim (optimize (speed 3) (safety 1))) 20 | (defconstant screen-width 256) 21 | (defconstant screen-height 240) 22 | (defconstant vblank-scanline 241) 23 | (defconstant last-scanline 261) 24 | (defconstant cycles-per-scanline 114) 25 | (defconstant cycles-per-cpu 3) 26 | 27 | (defstruct color 28 | "Simple RGBA" 29 | (r 0 :type (unsigned-byte 8)) 30 | (g 0 :type (unsigned-byte 8)) 31 | (b 0 :type (unsigned-byte 8))) 32 | 33 | (defun wrap-byte (val) 34 | (declare ((unsigned-byte 64) val)) 35 | (ldb (byte 8 0) val)) 36 | 37 | (defun wrap-word (val) 38 | (declare ((unsigned-byte 64) val)) 39 | (ldb (byte 16 0) val)) 40 | 41 | (defun to-signed-byte-8 (val) 42 | (declare ((unsigned-byte 8) val)) 43 | (the fixnum (if (ldb-test (byte 1 7) val) 44 | (* -1 (wrap-byte (1+ (lognot val)))) 45 | val))) 46 | 47 | (defvar 48 | *palette* 49 | (progn 50 | (let ((pal (make-array 64 :element-type 'color :initial-element (make-color :r 0 :g 0 :b 0))) 51 | (colors 52 | (make-array 53 | 64 54 | :element-type '(unsigned-byte 32) 55 | :initial-contents 56 | '(#x666666 #x002A88 #x1412A7 #x3B00A4 #x5C007E #x6E0040 #x6C0600 #x561D00 57 | #x333500 #x0B4800 #x005200 #x004F08 #x00404D #x000000 #x000000 #x000000 58 | #xADADAD #x155FD9 #x4240FF #x7527FE #xA01ACC #xB71E7B #xB53120 #x994E00 59 | #x6B6D00 #x388700 #x0C9300 #x008F32 #x007C8D #x000000 #x000000 #x000000 60 | #xFFFEFF #x64B0FF #x9290FF #xC676FF #xF36AFF #xFE6ECC #xFE8170 #xEA9E22 61 | #xBCBE00 #x88D800 #x5CE430 #x45E082 #x48CDDE #x4F4F4F #x000000 #x000000 62 | #xFFFEFF #xC0DFFF #xD3D2FF #xE8C8FF #xFBC2FF #xFEC4EA #xFECCC5 #xF7D8A5 63 | #xE4E594 #xCFEF96 #xBDF4AB #xB3F3CC #xB5EBF2 #xB8B8B8 #x000000 #x000000)))) 64 | (loop for i from 0 to 63 65 | do 66 | (let* ((c (aref colors i)) 67 | (r (ldb (byte 8 16) c)) 68 | (g (ldb (byte 8 8) c)) 69 | (b (ldb (byte 8 0) c))) 70 | (setf (aref pal i) (make-color :r r :g g :b b)))) 71 | pal))) 72 | 73 | 74 | 75 | (defstruct ppu 76 | "A model picture processing unit" 77 | (front 78 | (make-array #xF000 :element-type 'color :initial-element (make-color :r 0 :g 0 :b 0)) 79 | :type (simple-array color 1)) 80 | (back 81 | (make-array #xF000 :element-type 'color :initial-element (make-color :r 0 :g 0 :b 0)) 82 | :type (simple-array color 1)) 83 | 84 | (cycle 0 :type (unsigned-byte 16)) 85 | (scanline 0 :type (unsigned-byte 16)) 86 | (frame 0 :type (unsigned-byte 16)) 87 | 88 | (memory-get 89 | (make-array 3 :element-type 'function :initial-element (lambda ())) 90 | :type (simple-array function 1)) 91 | (memory-set 92 | (make-array 3 :element-type 'function :initial-element (lambda ())) 93 | :type (simple-array function 1)) 94 | 95 | (palette-data 96 | (make-array 32 :element-type '(unsigned-byte 8)) 97 | :type (simple-array (unsigned-byte 8) 1)) 98 | (name-table-data 99 | (make-array 2048 :element-type '(unsigned-byte 8)) 100 | :type (simple-array (unsigned-byte 8) 1)) 101 | (oam-data 102 | (make-array 256 :element-type '(unsigned-byte 8)) 103 | :type (simple-array (unsigned-byte 8) 1)) 104 | 105 | ;Registers 106 | (v 0 :type (unsigned-byte 16)) ;Current vram address 107 | (tv 0 :type (unsigned-byte 16));Temporary vram address 108 | (x 0 :type (unsigned-byte 3));Fine x scroll 109 | (w 0 :type (unsigned-byte 1));Write toggle 110 | (f 0 :type (unsigned-byte 1));Odd frame flag 111 | (register 0 :type (unsigned-byte 8)) 112 | 113 | ;NMI Status 114 | (nmi-occurred nil :type boolean) 115 | (nmi-output nil :type boolean) 116 | (nmi-previous nil :type boolean) 117 | (nmi-delay 0 :type (unsigned-byte 16)) 118 | 119 | (trigger-nmi-callback (lambda ()) :type function) 120 | 121 | ;Tiles 122 | (name-table 0 :type (unsigned-byte 8)) 123 | (attribute-table 0 :type (unsigned-byte 8)) 124 | (low-tile 0 :type (unsigned-byte 8)) 125 | (high-tile 0 :type (unsigned-byte 8)) 126 | (tile-data 0 :type (unsigned-byte 64)) 127 | 128 | ;Sprites 129 | (sprite-count 0 :type (unsigned-byte 8)) 130 | (sprite-patterns 131 | (make-array 8 :element-type '(unsigned-byte 32)) 132 | :type (simple-array (unsigned-byte 32) 1)) 133 | (sprite-positions 134 | (make-array 8 :element-type '(unsigned-byte 8)) 135 | :type (simple-array (unsigned-byte 8) 1)) 136 | (sprite-priorities 137 | (make-array 8 :element-type '(unsigned-byte 8)) 138 | :type (simple-array (unsigned-byte 8) 1)) 139 | (sprite-indexes 140 | (make-array 8 :element-type '(unsigned-byte 8)) 141 | :type (simple-array (unsigned-byte 8) 1)) 142 | 143 | ;$2000 PPU Control 144 | (flag-name-table 0 :type (unsigned-byte 2)) 145 | (flag-increment 0 :type (unsigned-byte 1)) 146 | (flag-sprite-table 0 :type (unsigned-byte 1)) 147 | (flag-background-table 0 :type (unsigned-byte 1)) 148 | (flag-sprite-size 0 :type (unsigned-byte 1)) 149 | (flag-master-slave 0 :type (unsigned-byte 1)) 150 | 151 | ;$2001 PPU Mask 152 | (flag-grayscale 0 :type (unsigned-byte 1)) 153 | (flag-show-left-background 0 :type (unsigned-byte 1)) 154 | (flag-show-left-sprites 0 :type (unsigned-byte 1)) 155 | (flag-show-background 0 :type (unsigned-byte 1)) 156 | (flag-show-sprites 0 :type (unsigned-byte 1)) 157 | (flag-red-tint 0 :type (unsigned-byte 1)) 158 | (flag-green-tint 0 :type (unsigned-byte 1)) 159 | (flag-blue-tint 0 :type (unsigned-byte 1)) 160 | 161 | ;$2002 PPU Status 162 | (flag-sprite-zero-hit 0 :type (unsigned-byte 8)) 163 | (flag-sprite-overflow 0 :type (unsigned-byte 8)) 164 | 165 | ;$2003 OAM Address 166 | (oam-address 0 :type (unsigned-byte 8)) 167 | 168 | ;Buffer for $2007 Data Read 169 | (buffered-data 0 :type (unsigned-byte 8)) 170 | (oam-dma-callback (lambda()) :type function) 171 | (oam-stall-adder (lambda()) :type function)) 172 | 173 | (defun read-ppu (p addr) 174 | (declare (ppu p) ((unsigned-byte 16) addr)) 175 | (setf addr (mod addr #x4000)) 176 | (cond 177 | ;Mapper 178 | ((< addr #x2000) (funcall (aref (ppu-memory-get p) 0) addr)) 179 | ;Name table data 180 | ((< addr #x3F00) (funcall (aref (ppu-memory-get p) 1) addr)) 181 | ;Palette data 182 | ((< addr #x4000) (funcall (aref (ppu-memory-get p) 2) addr)))) 183 | 184 | (defun write-ppu (p addr val) 185 | (declare (ppu p) ((unsigned-byte 16) addr) ((unsigned-byte 8) val)) 186 | (setf addr (mod addr #x4000)) 187 | (cond 188 | ;Mapper 189 | ((< addr #x2000) (funcall (aref (ppu-memory-set p) 0) addr val)) 190 | ;Name table data 191 | ((< addr #x3F00) (funcall (aref (ppu-memory-set p) 1) addr val)) 192 | ;Palette data 193 | ((< addr #x4000) (funcall (aref (ppu-memory-set p) 2) addr val)))) 194 | 195 | (defun read-palette (p address) 196 | (declare (ppu p) ((unsigned-byte 16) address)) 197 | (aref 198 | (ppu-palette-data p) 199 | (if (and (>= address 16) (= (mod address 4) 0)) 200 | (wrap-word (- address 16)) 201 | address))) 202 | 203 | (defun write-palette (p address value) 204 | (declare (ppu p) ((unsigned-byte 16) address) ((unsigned-byte 8) value)) 205 | (setf 206 | (aref 207 | (ppu-palette-data p) 208 | (if (and (>= address 16) (= (mod address 4) 0)) 209 | (wrap-word (- address 16)) 210 | address)) 211 | value)) 212 | 213 | (defun write-control (p value) 214 | (declare (ppu p) ((unsigned-byte 8) value)) 215 | (setf 216 | (ppu-flag-name-table p) 217 | (ldb (byte 2 0) value)) 218 | (setf 219 | (ppu-flag-increment p) 220 | (ldb (byte 1 2) value)) 221 | (setf 222 | (ppu-flag-sprite-table p) 223 | (ldb (byte 1 3) value)) 224 | (setf 225 | (ppu-flag-background-table p) 226 | (ldb (byte 1 4) value)) 227 | (setf 228 | (ppu-flag-sprite-size p) 229 | (ldb (byte 1 5) value)) 230 | (setf 231 | (ppu-flag-master-slave p) 232 | (ldb (byte 1 6) value)) 233 | (setf 234 | (ppu-nmi-output p) 235 | (ldb-test (byte 1 7) value)) 236 | (nmi-change p) 237 | (setf 238 | (ppu-tv p) 239 | (logior 240 | (logand (ppu-tv p) #xF3FF) 241 | (ash (logand value 3) 10)))) 242 | 243 | (defun write-mask (p value) 244 | (declare (ppu p) ((unsigned-byte 8) value)) 245 | (setf 246 | (ppu-flag-grayscale p) 247 | (ldb (byte 1 0) value)) 248 | (setf 249 | (ppu-flag-show-left-background p) 250 | (ldb (byte 1 1) value)) 251 | (setf 252 | (ppu-flag-show-left-sprites p) 253 | (ldb (byte 1 2) value)) 254 | (setf 255 | (ppu-flag-show-background p) 256 | (ldb (byte 1 3) value)) 257 | (setf 258 | (ppu-flag-show-sprites p) 259 | (ldb (byte 1 4) value)) 260 | (setf 261 | (ppu-flag-red-tint p) 262 | (ldb (byte 1 5) value)) 263 | (setf 264 | (ppu-flag-green-tint p) 265 | (ldb (byte 1 6) value)) 266 | (setf 267 | (ppu-flag-blue-tint p) 268 | (ldb (byte 1 7) value))) 269 | 270 | (defun read-status (p) 271 | (setf (ppu-w p) 0) 272 | (let ((result (logand (ppu-register p) #x1F))) 273 | (declare ((unsigned-byte 8) result)) 274 | (setf 275 | result 276 | (logior 277 | (logior result (ash (ppu-flag-sprite-overflow p) 5)) 278 | (ash (ppu-flag-sprite-zero-hit p) 6))) 279 | (when (ppu-nmi-occurred p) 280 | (setf result (logior result (ash 1 7)))) 281 | (setf (ppu-nmi-occurred p) nil) 282 | (nmi-change p) 283 | result)) 284 | 285 | 286 | (defun write-oam-address (p value) 287 | (declare (ppu p) ((unsigned-byte 8) value)) 288 | (setf (ppu-oam-address p) value)) 289 | 290 | (defun read-oam-data (p) 291 | (declare (ppu p)) 292 | (aref (ppu-oam-data p) (ppu-oam-address p))) 293 | 294 | (defun write-oam-data (p value) 295 | (declare (ppu p) ((unsigned-byte 8) value)) 296 | (setf (aref (ppu-oam-data p) (ppu-oam-address p)) value) 297 | (setf (ppu-oam-address p) (wrap-byte (1+ (ppu-oam-address p))))) 298 | 299 | (defun write-scroll (p value) 300 | (declare (ppu p) ((unsigned-byte 8) value)) 301 | (if (= (ppu-w p) 0) 302 | (progn 303 | (setf (ppu-tv p) (logior (logand (ppu-tv p) #xFFE0) (ash value -3))) 304 | (setf (ppu-x p) (logand value #x07)) 305 | (setf (ppu-w p) 1)) 306 | (progn 307 | (setf 308 | (ppu-tv p) 309 | (logior (logand (ppu-tv p) #x8FFF) (ash (logand value #x07) 12))) 310 | (setf 311 | (ppu-tv p) 312 | (logior (logand (ppu-tv p) #xFC1F) (ash (logand value #xF8) 2))) 313 | (setf (ppu-w p) 0)))) 314 | 315 | (defun write-address (p value) 316 | (declare (ppu p) ((unsigned-byte 8) value)) 317 | (if (= (ppu-w p) 0) 318 | (progn 319 | (setf 320 | (ppu-tv p) 321 | (logior (logand (ppu-tv p) #x80FF) (ash (logand value #x3F) 8))) 322 | (setf (ppu-w p) 1)) 323 | (progn 324 | (setf (ppu-tv p) (logior (logand (ppu-tv p) #xFF00) value)) 325 | (setf (ppu-v p) (ppu-tv p)) 326 | (setf (ppu-w p) 0)))) 327 | 328 | 329 | (defun read-data (p) 330 | (declare (ppu p)) 331 | (let ((value (read-ppu p (ppu-v p)))) 332 | (declare ((unsigned-byte 8) value)) 333 | (if (< (mod (ppu-v p) #x4000) #x3F00) 334 | (let ((buffered (ppu-buffered-data p))) 335 | (setf (ppu-buffered-data p) value) 336 | (setf value buffered)) 337 | (setf (ppu-buffered-data p) (read-ppu p (wrap-word (- (ppu-v p) #x1000))))) 338 | (setf 339 | (ppu-v p) 340 | (wrap-word 341 | (+ 342 | (ppu-v p) 343 | (if (= (ppu-flag-increment p) 0) 344 | 1 345 | 32)))) 346 | value)) 347 | 348 | 349 | (defun write-data (p value) 350 | (declare (ppu p) ((unsigned-byte 8) value)) 351 | (write-ppu p (ppu-v p) value) 352 | (setf 353 | (ppu-v p) 354 | (wrap-word 355 | (+ 356 | (ppu-v p) 357 | (if (= (ppu-flag-increment p) 0) 358 | 1 359 | 32))))) 360 | 361 | (defun write-dma (p value) 362 | (declare (ppu p) ((unsigned-byte 8) value)) 363 | (let ((address (ash value 8))) 364 | (loop for i from 0 to 255 365 | do 366 | (progn 367 | (setf 368 | (aref (ppu-oam-data p) (ppu-oam-address p)) 369 | (funcall (ppu-oam-dma-callback p) address)) 370 | (setf (ppu-oam-address p) (wrap-byte (1+ (ppu-oam-address p)))) 371 | (setf address (wrap-word (1+ address))))) 372 | (funcall (ppu-oam-stall-adder p) 513))) 373 | 374 | (defun read-register (p selector) 375 | (declare (ppu p) ((unsigned-byte 16) selector)) 376 | (case selector 377 | ;Read ppu status 378 | (2 (read-status p)) 379 | ;Read OAM Data 380 | (4 (read-oam-data p)) 381 | ;Read Data 382 | (7 (read-data p)) 383 | (otherwise (progn (print "Uhm?") 0)))) 384 | 385 | (defun write-register (p selector value) 386 | (declare (ppu p) ((unsigned-byte 16) selector)) 387 | (setf (ppu-register p) value) 388 | (case selector 389 | ;Write Control 390 | (0 (write-control p value)) 391 | ;Write Mask 392 | (1 (write-mask p value)) 393 | ;Write OAM Address 394 | (3 (write-oam-address p value)) 395 | ;Write OAM Data 396 | (4 (write-oam-data p value)) 397 | ;Write scroll 398 | (5 (write-scroll p value)) 399 | ;Write Address 400 | (6 (write-address p value)) 401 | ;Write Data 402 | (7 (write-data p value)) 403 | ;Write DMA 404 | (#x4014 (write-dma p value)) 405 | (otherwise (progn (print "Uhm in write?") 0)))) 406 | 407 | (defun increment-x (p) 408 | (declare (ppu p)) 409 | (setf 410 | (ppu-v p) 411 | (if (= (logand (ppu-v p) #x001F) 31) 412 | (logxor #x0400 (logand (ppu-v p) #xFFE0)) 413 | (wrap-word (1+ (ppu-v p)))))) 414 | 415 | (defun increment-y (p) 416 | (declare (ppu p)) 417 | (if (/= (logand (ppu-v p) #x7000) #x7000) 418 | (setf (ppu-v p) (wrap-word (+ #x1000 (ppu-v p)))) 419 | (progn 420 | (setf (ppu-v p) (logand (ppu-v p) #x8FFF)) 421 | (let ((y (ash (logand (ppu-v p) #x03E0) -5))) 422 | (if (= y 29) 423 | (progn 424 | (setf y 0) 425 | (setf (ppu-v p) (logxor (ppu-v p) #x0800))) 426 | (setf y (if (= y 31) 0 (1+ y)))) 427 | (setf (ppu-v p) (logior (logand (ppu-v p) #xFC1F) (ash y 5))))))) 428 | 429 | (defun copy-x (p) 430 | (declare (ppu p)) 431 | (setf (ppu-v p) (logior (logand (ppu-v p) #xFBE0) (logand (ppu-tv p) #x041F)))) 432 | 433 | (defun copy-y (p) 434 | (declare (ppu p)) 435 | (setf (ppu-v p) (logior (logand (ppu-v p) #x841F) (logand (ppu-tv p) #x7BE0)))) 436 | 437 | (defun nmi-change (p) 438 | (declare (ppu p)) 439 | (let ((nmi (and (ppu-nmi-output p) (ppu-nmi-occurred p)))) 440 | (when (and nmi (not (ppu-nmi-previous p))) 441 | (setf (ppu-nmi-delay p) 15)) 442 | (setf (ppu-nmi-previous p) nmi))) 443 | 444 | (defun set-vertical-blank (p) 445 | (declare (ppu p)) 446 | (psetf (ppu-front p) (ppu-back p) (ppu-back p) (ppu-front p)) 447 | (setf (ppu-nmi-occurred p) T) 448 | (nmi-change p)) 449 | 450 | (defun clear-vertical-blank (p) 451 | (declare (ppu p)) 452 | (setf (ppu-nmi-occurred p) nil) 453 | (nmi-change p)) 454 | 455 | (defun fetch-name-table (p) 456 | (declare (ppu p)) 457 | (setf (ppu-name-table p) (read-ppu p (logior #x2000 (logand (ppu-v p) #x0FFF))))) 458 | 459 | (defun fetch-attribute-table (p) 460 | (declare (ppu p)) 461 | (let* ((v (ppu-v p)) 462 | (address 463 | (logior 464 | #x23C0 465 | (logand v #x0C00) 466 | (logand #x38 (ash v -4)) 467 | (logand #x07 (ash v -2)))) 468 | (shift (logior (logand (ash v -4) 4) (logand v 2)))) 469 | (setf 470 | (ppu-attribute-table p) 471 | (ash (ldb (byte 2 0) (ash (the (unsigned-byte 8) (read-ppu p address)) (* -1 shift))) 2)))) 472 | 473 | (defun fetch-low-tile (p) 474 | (declare (ppu p)) 475 | (let* ((fine-y (logand 7 (ash (ppu-v p) -12))) 476 | (table (ppu-flag-background-table p)) 477 | (tile (ppu-name-table p)) 478 | (address (+ (* #x1000 table) (* 16 tile) fine-y))) 479 | (setf (ppu-low-tile p) (read-ppu p address)))) 480 | 481 | (defun fetch-high-tile (p) 482 | (declare (ppu p)) 483 | (let* ((fine-y (logand 7 (ash (ppu-v p) -12))) 484 | (table (ppu-flag-background-table p)) 485 | (tile (ppu-name-table p)) 486 | (address (+ (* #x1000 table) (* 16 tile) fine-y))) 487 | (setf (ppu-high-tile p) (read-ppu p (wrap-word (+ address 8)))))) 488 | 489 | (defun store-tile-data (p) 490 | (declare (ppu p)) 491 | (let ((data 0)) 492 | (declare ((unsigned-byte 32) data)) 493 | (loop for i from 0 to 7 494 | do 495 | (let ((a (ppu-attribute-table p)) 496 | (p1 (ash (logand #x80 (ppu-low-tile p)) -7)) 497 | (p2 (ash (logand #x80 (ppu-high-tile p)) -6))) 498 | (declare ((unsigned-byte 8) a p1 p2)) 499 | (setf (ppu-low-tile p) (wrap-byte (ash (ppu-low-tile p) 1))) 500 | (setf (ppu-high-tile p) (wrap-byte (ash (ppu-high-tile p) 1))) 501 | (setf data (logior a p1 p2 (ash data 4))))) 502 | (setf (ppu-tile-data p) (logior (ppu-tile-data p) data)))) 503 | 504 | (defun fetch-tile-data (p) 505 | (declare (ppu p)) 506 | (ldb (byte 32 32) (ppu-tile-data p))) 507 | 508 | (defun background-pixel (p) 509 | (declare (ppu p)) 510 | (if (= (ppu-flag-show-background p) 0) 511 | 0 512 | (ldb 513 | (byte 4 0) 514 | (ash (fetch-tile-data p) (the fixnum (* (the fixnum (- 7 (ppu-x p))) 4 -1)))))) 515 | 516 | (defun sprite-pixel (p) 517 | (declare (ppu p)) 518 | (when (= (ppu-flag-show-sprites p) 0) 519 | (return-from sprite-pixel (values 0 0))) 520 | (loop for i from 0 to (- (ppu-sprite-count p) 1) 521 | do 522 | (let ((offset (- (- (ppu-cycle p) 1) (aref (ppu-sprite-positions p) i)))) 523 | (declare (fixnum offset)) 524 | (when (and (>= offset 0) (<= offset 7)) 525 | (setf offset (- 7 offset)) 526 | (let ((color 527 | (logand 528 | #x0F 529 | (ash 530 | (aref (ppu-sprite-patterns p) i) 531 | (* -1 (wrap-byte (* offset 4))))))) 532 | (when (/= (mod color 4) 0) 533 | (return-from sprite-pixel (values (wrap-byte i) color))))))) 534 | (return-from sprite-pixel (values 0 0))) 535 | 536 | (defun render-pixel (p) 537 | (declare (ppu p)) 538 | (multiple-value-bind 539 | (i sprite) 540 | (sprite-pixel p) 541 | (declare ((unsigned-byte 8) i sprite)) 542 | (let ((x (- (ppu-cycle p) 1)) 543 | (y (ppu-scanline p)) 544 | (background (background-pixel p))) 545 | (declare ((unsigned-byte 16) x y) ((unsigned-byte 8) background)) 546 | (when (and (< x 8) (= (ppu-flag-show-left-background p) 0)) 547 | (setf background 0)) 548 | (when (and (< x 8) (= (ppu-flag-show-left-sprites p) 0)) 549 | (setf sprite 0)) 550 | (let ((b (/= (mod background 4) 0)) 551 | (s (/= (mod sprite 4) 0)) 552 | (color #x00)) 553 | (cond 554 | ((and (not b) (not s)) (setf color 0)) 555 | ((and (not b) s) (setf color (logior #x10 sprite))) 556 | ((and b (not s)) (setf color background)) 557 | (T 558 | (progn 559 | (when (and (< x 255) (= (aref (ppu-sprite-indexes p) i) 0)) 560 | (setf (ppu-flag-sprite-zero-hit p) 1)) 561 | (if (= (aref (ppu-sprite-priorities p) i) 0) 562 | (setf color (logior sprite #x10)) 563 | (setf color background))))) 564 | (setf 565 | (aref (ppu-back p) (+ (* y screen-width) x)) 566 | (aref 567 | (the (simple-array color 1) *palette*) 568 | (mod (read-palette p (wrap-word color)) 64))))))) 569 | 570 | (defun fetch-sprite-pattern (p i r) 571 | (declare (ppu p) ((signed-byte 16) i r)) 572 | (let* ((tile (aref (ppu-oam-data p) (1+ (* i 4)))) 573 | (attributes (aref (ppu-oam-data p) (+ 2 (* i 4)))) 574 | (address #x0000) 575 | (a (ash (logand attributes 3) 2)) 576 | (row r)) 577 | (declare (fixnum row) ((unsigned-byte 8) a attributes tile) 578 | ((unsigned-byte 16) address)) 579 | (if (= (ppu-flag-sprite-size p) 0) 580 | (let ((table (ppu-flag-sprite-table p))) 581 | (declare ((unsigned-byte 1) table)) 582 | (when (= (logand attributes #x80) #x80) 583 | (setf row (- 7 row))) 584 | (setf address (+ (* #x1000 table) (* 16 tile) row))) 585 | (let ((table (logand tile 1))) 586 | (when (= (logand attributes #x80) #x80) 587 | (setf row (- 15 row))) 588 | (setf tile (logand tile #xFE)) 589 | (when (> row 7) 590 | (incf tile) 591 | (decf row 8)) 592 | (setf address (+ (* #x1000 table) (* tile 16) row)))) 593 | (let ((low-tile (read-ppu p address)) 594 | (high-tile (read-ppu p (wrap-word (+ address 8)))) 595 | (data #x00000000)) 596 | (declare ((unsigned-byte 8) low-tile high-tile)) 597 | (loop for i from 0 to 7 598 | do 599 | (let ((p1 0) 600 | (p2 0)) 601 | (if (= (logand attributes #x40) #x40) 602 | (progn 603 | (setf p1 (logand low-tile 1)) 604 | (setf p2 (ash (logand high-tile 1) 1)) 605 | (setf low-tile (ash low-tile -1)) 606 | (setf high-tile (ash high-tile -1))) 607 | (progn 608 | (setf p1 (ash (logand low-tile #x80) -7)) 609 | (setf p2 (ash (logand high-tile #x80) -6)) 610 | (setf low-tile (wrap-byte (ash low-tile 1))) 611 | (setf high-tile (wrap-byte (ash high-tile 1))))) 612 | (setf data (logand #xFFFFFFFF (logior (ash data 4) a p1 p2))))) 613 | (the (unsigned-byte 32) data)))) 614 | 615 | (defun evaluate-sprites (p) 616 | (declare (ppu p)) 617 | (let ((h 618 | (if (= (ppu-flag-sprite-size p) 0) 619 | 8 620 | 16)) 621 | (count 0)) 622 | (declare (fixnum count) ((unsigned-byte 8) h)) 623 | (loop for i from 0 to 63 624 | do 625 | (let* ((y (aref (ppu-oam-data p) (* i 4))) 626 | (a (aref (ppu-oam-data p) (+ 2 (* i 4)))) 627 | (x (aref (ppu-oam-data p) (+ 3 (* i 4)))) 628 | (row (- (ppu-scanline p) y))) 629 | (declare ((unsigned-byte 8) y a x) (fixnum row)) 630 | (when (and (>= row 0) (< row h)) 631 | (when (< count 8) 632 | (setf 633 | (aref (ppu-sprite-patterns p) count) 634 | (fetch-sprite-pattern p i row)) 635 | (setf (aref (ppu-sprite-positions p) count) x) 636 | (setf (aref (ppu-sprite-priorities p) count) (logand 1 (ash a -5))) 637 | (setf (aref (ppu-sprite-indexes p) count) i)) 638 | (incf count)))) 639 | (when (> count 8) 640 | (setf count 8) 641 | (setf (ppu-flag-sprite-overflow p) 1)) 642 | (setf (ppu-sprite-count p) count))) 643 | 644 | (defun reset-ppu (p) 645 | (declare (ppu p)) 646 | (setf (ppu-cycle p) 340) 647 | (setf (ppu-scanline p) 240) 648 | (setf (ppu-frame p) 0) 649 | (write-control p 0) 650 | (write-mask p 0) 651 | (write-oam-address p 0)) 652 | 653 | (defun tick (p) 654 | (declare (ppu p)) 655 | ;While the nmi delay is greater than zero... 656 | (when (> (ppu-nmi-delay p) 0) 657 | ;Decrement it... 658 | (decf (ppu-nmi-delay p)) 659 | ;Trigger it if we have run out of time and there even is one 660 | (when (and (= (ppu-nmi-delay p) 0) (ppu-nmi-output p) (ppu-nmi-occurred p)) 661 | (funcall (ppu-trigger-nmi-callback p)))) 662 | (when 663 | (or (/= 0 (ppu-flag-show-background p)) (/= 0 (ppu-flag-show-sprites p))) 664 | (when (and 665 | (= (ppu-f p) 1) 666 | (= (ppu-scanline p) 261) 667 | (= (ppu-cycle p) 339)) 668 | (setf (ppu-cycle p) 0) 669 | (setf (ppu-scanline p) 0) 670 | (setf (ppu-frame p) (wrap-word (1+ (ppu-frame p)))) 671 | (setf (ppu-f p) (logxor (ppu-f p) 1)) 672 | (return-from tick 0))) 673 | (incf (ppu-cycle p)) 674 | ;We've hit the end of the scanline 675 | (when (> (ppu-cycle p) 340) 676 | ;Reset the cycle number 677 | (setf (ppu-cycle p) 0) 678 | ;Increment the scanline 679 | (incf (ppu-scanline p)) 680 | ;And finally do housework if we need to go back to top 681 | (when (> (ppu-scanline p) 261) 682 | (setf (ppu-scanline p) 0) 683 | (setf (ppu-frame p) (wrap-word (1+ (ppu-frame p)))) 684 | (setf (ppu-f p) (logxor (ppu-f p) 1))))) 685 | 686 | (defun step-ppu (p step) 687 | (declare (ppu p) ((unsigned-byte 8) step)) 688 | (loop for i from 1 to step 689 | do 690 | (progn 691 | (tick p) 692 | (let* ((cycle (ppu-cycle p)) 693 | (scanline (ppu-scanline p)) 694 | (rendering-enabled 695 | (not (= 0 (ppu-flag-show-background p) (ppu-flag-show-sprites p)))) 696 | (pre-line (= scanline 261)) 697 | (visible-line (< scanline 240)) 698 | (render-line (or pre-line visible-line)) 699 | (pre-fetch-cycle (and (>= cycle 321) (<= cycle 336))) 700 | (visible-cycle (and (>= cycle 1) (<= cycle 256))) 701 | (fetch-cycle (or pre-fetch-cycle visible-cycle))) 702 | (when rendering-enabled 703 | ;Begin background logic 704 | (when (and visible-line visible-cycle) 705 | (render-pixel p)) 706 | ;When we are on a fetch cycle and a render line... 707 | (when (and render-line fetch-cycle) 708 | ;Shift tile data left four to make room 709 | (setf 710 | (ppu-tile-data p) 711 | ;Make sure it continues to fit in 64 bits 712 | (ldb (byte 64 0) (ash (ppu-tile-data p) 4))) 713 | ;Depending on what cycle we are in act accordingly 714 | (case (mod cycle 8) 715 | (0 (store-tile-data p)) 716 | (1 (fetch-name-table p)) 717 | (3 (fetch-attribute-table p)) 718 | (5 (fetch-low-tile p)) 719 | (7 (fetch-high-tile p)))) 720 | ;When we are on preline and 721 | (when (and pre-line (>= (ppu-cycle p) 280) (<= (ppu-cycle p) 304)) 722 | (copy-y p)) 723 | (when render-line 724 | (when (and fetch-cycle (= (mod cycle 8) 0)) 725 | (increment-x p)) 726 | (when (= cycle 256) 727 | (increment-y p)) 728 | (when (= cycle 257) 729 | (copy-x p))) 730 | ;begin sprite logic 731 | (when (= cycle 257) 732 | (if visible-line 733 | (evaluate-sprites p) 734 | (setf (ppu-sprite-count p) 0)))) 735 | ;Begin vblank logic 736 | (when (and (= scanline 241) (= (ppu-cycle p) 1)) 737 | (set-vertical-blank p)) 738 | (when (and pre-line (= (ppu-cycle p) 1)) 739 | (clear-vertical-blank p) 740 | (setf (ppu-flag-sprite-zero-hit p) 0) 741 | (setf (ppu-flag-sprite-overflow p) 0)))))) 742 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------