# HG changeset patch # User Steve Losh # Date 1479397838 0 # Node ID 8e58d7eb4d032134b7ccfd0107e76f51e23b7b25 # Parent fd215349e7bb91b01d6cc05ea1fcc0c189baab48 More work. Things appear on the screen now. diff -r fd215349e7bb -r 8e58d7eb4d03 package.lisp --- a/package.lisp Wed Nov 16 20:54:13 2016 +0000 +++ b/package.lisp Thu Nov 17 15:50:38 2016 +0000 @@ -5,8 +5,7 @@ :iterate :cl-arrows :chip8.quickutils) - (:export) - (:shadow :bit)) + (:export)) (defpackage :chip8.gui diff -r fd215349e7bb -r 8e58d7eb4d03 src/emulator.lisp --- a/src/emulator.lisp Wed Nov 16 20:54:13 2016 +0000 +++ b/src/emulator.lisp Thu Nov 17 15:50:38 2016 +0000 @@ -1,15 +1,26 @@ (in-package :chip8) -(setf *print-length* 10) +(setf *print-length* 16) (setf *print-base* 10) (declaim (optimize (speed 1) (safety 3) (debug 3))) -(declaim (optimize (speed 3) (safety 0) (debug 3))) +; (declaim (optimize (speed 3) (safety 1) (debug 3))) + + +;;;; Constants ---------------------------------------------------------------- +(defconstant +screen-width+ 64) +(defconstant +screen-height+ 32) +(defconstant +memory-size+ (* 1024 4)) +(defconstant +timer-tick+ (round (* 1/60 internal-time-units-per-second))) ;;;; Types -------------------------------------------------------------------- +(deftype int4 () '(unsigned-byte 4)) (deftype int8 () '(unsigned-byte 8)) (deftype int12 () '(unsigned-byte 12)) (deftype int16 () '(unsigned-byte 16)) +(deftype x-coord () `(integer 0 (,+screen-width+))) +(deftype y-coord () `(integer 0 (,+screen-height+))) +(deftype memory-index () `(integer 0 (,+memory-size+))) (deftype basic-array (element-type size) `(simple-array ,(upgraded-array-element-type element-type) (,size))) @@ -19,7 +30,7 @@ ;;;; Utils -------------------------------------------------------------------- -(declaim (inline not= +_8 -_8 chop cat-bytes)) +(declaim (inline not= +_8 -_8 chop cat-bytes get-bit bcd)) (defun make-simple-array (element-type size &rest args) (apply #'make-array size @@ -37,6 +48,9 @@ (defun cat-bytes (high-order low-order) (dpb high-order (byte 8 8) low-order)) +(defun get-bit (position integer) + (ldb (byte 1 position) integer)) + (defun +_8 (x y) (let ((result (+ x y))) (values (chop 8 result) @@ -47,6 +61,11 @@ (values (chop 8 result) (if (> x y) 1 0)))) +(defun bcd (integer) + (values (-<> integer (floor <> 100) (mod <> 10)) + (-<> integer (floor <> 10) (mod <> 10)) + (-<> integer (floor <> 1) (mod <> 10)))) + (defmacro macro-map ((lambda-list items) &rest body) (with-gensyms (macro) `(macrolet ((,macro ,(ensure-list lambda-list) ,@body)) @@ -67,17 +86,16 @@ :read-only t) (awaiting-key nil :type (or null (integer 0 15))) - (video-raw (error "Required") - :type (basic-array fixnum #.(* 32 64)) - :read-only t) - (video (error "Required") - :type (array fixnum (32 64)) ; row major :\ + (video (make-simple-array 'fixnum (* 32 64)) + :type (basic-array fixnum #.(* 32 64)) :read-only t) (video-dirty t :type boolean) (index 0 :type int16) - (program-counter 0 :type int12) + (program-counter #x200 :type int12) (delay-timer 0 :type int8) (sound-timer 0 :type int8) + (timer-clock +timer-tick+ :type fixnum) + (timer-previous 0 :type fixnum) (random-state (make-random-state t) :type random-state :read-only t) @@ -88,33 +106,111 @@ :type (stack 16))) (defun make-chip () - (let* ((video-raw (make-simple-array 'fixnum (* 32 64))) - (video (make-array '(32 64) - :displaced-to video-raw - :element-type 'fixnum))) - (make-chip% :video-raw video-raw :video video))) + (let ((chip (make-chip%))) + (load-font chip) + chip)) (define-with-macro chip memory registers + flag index program-counter - delay-timer sound-timer + delay-timer sound-timer timer-clock timer-previous random-state - video video-raw video-dirty + video video-dirty keys awaiting-key stack) +(declaim (inline chip-flag (setf chip-flag))) + +(defun chip-flag (chip) + (aref (chip-registers chip) #xF)) + +(defun (setf chip-flag) (new-value chip) + (setf (aref (chip-registers chip) #xF) new-value)) + ;;;; Graphics ----------------------------------------------------------------- -(defmacro vref (video x y) - `(aref ,video ,y ,x)) +(declaim (inline font-location vref (setf vref)) + (ftype (function (chip int8 int8 int4) null) draw-sprite) + (ftype (function (chip x-coord y-coord) fixnum) vref) + (ftype (function (fixnum chip x-coord y-coord) fixnum) (setf vref))) + + +(defun vref (chip x y) + (aref (chip-video chip) (+ (* 64 y) x))) + +(defun (setf vref) (new-value chip x y) + (setf (aref (chip-video chip) (+ (* 64 y) x)) + new-value)) + + +(defun load-font (chip) + ;; Thanks http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/ + (replace (chip-memory chip) + (vector #xF0 #x90 #x90 #x90 #xF0 ; 0 + #x20 #x60 #x20 #x20 #x70 ; 1 + #xF0 #x10 #xF0 #x80 #xF0 ; 2 + #xF0 #x10 #xF0 #x10 #xF0 ; 3 + #x90 #x90 #xF0 #x10 #x10 ; 4 + #xF0 #x80 #xF0 #x10 #xF0 ; 5 + #xF0 #x80 #xF0 #x90 #xF0 ; 6 + #xF0 #x10 #x20 #x40 #x40 ; 7 + #xF0 #x90 #xF0 #x90 #xF0 ; 8 + #xF0 #x90 #xF0 #x10 #xF0 ; 9 + #xF0 #x90 #xF0 #x90 #x90 ; A + #xE0 #x90 #xE0 #x90 #xE0 ; B + #xF0 #x80 #x80 #x80 #xF0 ; C + #xE0 #x90 #x90 #x90 #xE0 ; D + #xF0 #x80 #xF0 #x80 #xF0 ; E + #xF0 #x80 #xF0 #x80 #x80) ; F + :start1 #x50)) + +(defun font-location (character) + (+ #x50 (* character 5))) + + +(defun draw-sprite (chip start-x start-y size) + (with-chip (chip) + (assert (< (+ index size) +memory-size+) (index) + "Sprite data of size ~D starting at #x~4,'0X would be out of bounds" + size index) + ; (format t "Drawing sprite at ~d ~d~%" start-x start-y) + (setf flag 0) + (iterate + (declare (iterate:declare-variables)) + (for (the fixnum y) :from start-y :below (+ start-y size)) + (for (the y-coord screen-y) = (mod y 32)) + (for (the fixnum i) :from index) + (for sprite = (aref memory i)) + (iterate (declare (iterate:declare-variables)) + (for (the fixnum x) :from start-x) + (for (the x-coord screen-x) = (mod x 64)) + (for (the fixnum col) :from 7 :downto 0) + (for (the fixnum old-pixel) = (vref chip screen-x screen-y)) + (for (the fixnum new-pixel) = (get-bit col sprite)) + ; (when (= old-pixel new-pixel 1) + ; (setf flag 1)) + (when (and (plusp old-pixel) (plusp new-pixel)) + (setf flag 1)) + ; (setf (vref chip screen-x screen-y) + ; (logxor old-pixel new-pixel)) + (setf (vref chip screen-x screen-y) + (cond + ((and (plusp old-pixel) (plusp new-pixel)) 0) + ((or (plusp old-pixel) (plusp new-pixel)) 255) + (t 0))))) + (setf video-dirty t)) + nil) ;;;; Keyboard ----------------------------------------------------------------- +(declaim (ftype (function (chip (integer 0 (16)))) keydown keyup)) + (defun keydown (chip key) (with-chip (chip) (setf (aref keys key) t) - (when awaiting-key - (setf (aref registers awaiting-key) key + (when-let* ((waiting-for awaiting-key)) + (setf (aref registers waiting-for) key awaiting-key nil)))) (defun keyup (chip key) @@ -163,13 +259,13 @@ (setf ,destination ,source))) (define-opcode op-cls () ;; CLS - (fill video-raw 0) + (fill video 0) (setf video-dirty t)) (define-opcode op-jp-imm (_ (target 3)) ;; JP addr (setf program-counter target)) -(define-opcode op-jp-imm+reg (_ (target 3)) ;; JP V_0 + addr +(define-opcode op-jp-imm+reg (_ (target 3)) ;; JP V0 + addr (setf program-counter (+ target (register 0)))) (define-opcode op-call (_ (target 3)) ;; CALL addr @@ -180,15 +276,15 @@ (setf program-counter (vector-pop stack))) (macro-map ;; ADD/SUB (8-bit) - ((name op source-arg source-expr) - ((op-add-reg