;;;
;;; mapper1.lisp
;;;
;;; Implementation of iNES mapper 1 (MMC1)
;;;

(in-package :neth)

(defstruct mapper1
  (regs (make-array 4 :element-type '(unsigned-byte 8)) :type (simple-array (unsigned-byte 8) (4)))
  (sequence)
  (accumulator))

(defun mapper1-sync (mapper)
  (let ((page (logand 15 (aref (mapper1-regs mapper) 3))))
    (if (zerop (logand 8 (aref (mapper1-regs mapper) 0)))
	(prg-map-32k 0 (ash page -1))
      (if (zerop (logand 4 (aref (mapper1-regs mapper) 0)))
	  (progn
	    (prg-map-16k 0 0)
	    (prg-map-16k 1 page))
	(progn
	  (prg-map-16k 0 page)
	  (prg-map-16k 1 15)))))

  (if (zerop (logand #x10 (aref (mapper1-regs mapper) 0)))
      (chr-map-8k 0 (ash (aref (mapper1-regs mapper) 1) -1))
    (progn
      (chr-map-4k 0 (aref (mapper1-regs mapper) 1))
      (chr-map-4k 1 (aref (mapper1-regs mapper) 2))))
  
  #+nil(case (logand 3 (aref (mapper1-regs mapper) 0))
    (0 (ppu-set-mirroring :one-low))
    (1 (ppu-set-mirroring :one-high))
    (2 (ppu-set-mirroring :vertical))
    (3 (ppu-set-mirroring :horizontal)))
  (ppu-set-mirroring (aref #(:one-low :one-high :vertical :horizontal)
			   (logand 3 (aref (mapper1-regs mapper) 0))))
  
  (values))

(defun mapper1-write (address data)
  #+nil(format t "Mapper 1 write ~X: ~X~%" address data)
  (if (zerop (logand #x80 data))
      (progn
	(setf (mapper1-accumulator *mapper*)
	      (dpb data (byte 1 (mapper1-sequence *mapper*))
		   (mapper1-accumulator *mapper*)))
	(incf (mapper1-sequence *mapper*))

	(when (< (mapper1-sequence *mapper*) 5) (return-from mapper1-write))

	(setf (aref (mapper1-regs *mapper*) (ldb (byte 2 13) address))
	      (mapper1-accumulator *mapper*)))
    (setf (aref (mapper1-regs *mapper*) 0)
	  (logior (aref (mapper1-regs *mapper*) 0) #xc)))
  (setf (mapper1-sequence *mapper*) 0)
  (setf (mapper1-accumulator *mapper*) 0)
  (mapper1-sync *mapper*))

(defmethod mapper-init ((mapper mapper1))
  (setf (mapper1-sequence mapper) 0)
  (setf (mapper1-accumulator mapper) 0)
  (setf (aref (mapper1-regs mapper) 0) #x0c)
  (setf (aref (mapper1-regs mapper) 1) #x00)
  (setf (aref (mapper1-regs mapper) 2) #x00)
  (setf (aref (mapper1-regs mapper) 3) #x00)
  (setf (aref *cpu-write-handlers* 4) #'mapper1-write)
  (setf (aref *cpu-write-handlers* 5) #'mapper1-write)
  (setf (aref *cpu-write-handlers* 6) #'mapper1-write)
  (setf (aref *cpu-write-handlers* 7) #'mapper1-write)
  (mapper1-sync mapper))

(defmapper 1 #'make-mapper1 "MMC1")

;;; EOF
