-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathcartridge.lisp
94 lines (89 loc) · 3.05 KB
/
cartridge.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
(defpackage #:NES-cartridge
(:nicknames #:nes-cart)
(:use :cl)
(:export #:load-cartridge #:make-cartridge #:cartridge-prg-rom
#:cartridge-prg-ram #:cartridge-chr-rom #:cartridge-chr-ram
#:cartridge-mirror))
(in-package :NES-cartridge)
(defconstant prg-size #x4000)
(defconstant chr-size #x2000)
(defstruct ines-header
"ines header spec"
(magic (make-array 4 :element-type '(unsigned-byte 8)))
;Size of prg rom in 16 KiB units
(size-of-prg-rom 0 :type (unsigned-byte 8))
;Size of chr rom in 8 KiB units
(size-of-chr-rom 0 :type (unsigned-byte 8))
(flags6 0 :type (unsigned-byte 8))
(flags7 0 :type (unsigned-byte 8))
;Size of PRG ram in 8 KiB unites
(size-of-prg-ram 0 :type (unsigned-byte 8))
(flags9 0 :type (unsigned-byte 8))
(flags10 0 :type (unsigned-byte 8))
(zero-pad (make-array 5 :element-type '(unsigned-byte 8))))
(defstruct cartridge
"A model NES cartridge"
(prg-rom 0)
(prg-rom-window 0 :type (unsigned-byte 8))
;We ignore prg-ram for now
(prg-ram 0)
(prg-ram-window 0 :type (unsigned-byte 8))
(chr-rom 0)
(chr-ram 0)
(chr-window 0 :type (unsigned-byte 8))
(mapper-number 0)
(header 0)
(mirror))
(defun load-header (seq)
(make-ines-header
:magic (subseq seq 0 4)
:size-of-prg-rom (aref seq 4)
:size-of-chr-rom (aref seq 5)
:flags6 (aref seq 6)
:flags7 (aref seq 7)
:size-of-prg-ram (aref seq 8)
:flags9 (aref seq 9)
:flags10 (aref seq 10)
:zero-pad (subseq seq 11 16)))
(defun load-cartridge (filepath)
(let ((cart (make-cartridge)) (header (make-ines-header)))
(with-open-file (stream filepath :element-type '(unsigned-byte 8))
(let ((seq
(make-array
(file-length stream)
:element-type '(unsigned-byte 8))))
(read-sequence seq stream)
(setf header (load-header seq))
(let*
;If trainers are present, skip them.
((to-add
(if (ldb-test (byte 1 3) (ines-header-flags6 header))
512
0))
;Limits of memory areas
(begin-prg (+ 16 to-add))
(end-prg (+ begin-prg (* prg-size (ines-header-size-of-prg-rom header))))
(begin-chr end-prg)
(end-chr (+ begin-chr (* chr-size (ines-header-size-of-chr-rom header)))))
;Load in prg-rom
(setf
(cartridge-prg-rom cart)
(subseq
seq
begin-prg
end-prg))
;If there is no rom, there is ram
(if (= (ines-header-size-of-chr-rom header) 0)
(setf
(cartridge-chr-ram cart)
(make-array chr-size :element-type '(unsigned-byte 8)))
(setf
(cartridge-chr-rom cart)
(subseq seq begin-chr end-chr)))
(setf (cartridge-header cart) header)
(let ((mirror1 (logand (ines-header-flags6 header) 1))
(mirror2 (logand (ash (ines-header-flags6 header) -3) 1)))
(setf
(cartridge-mirror cart)
(logior mirror1 (ash mirror2 1))))))
cart)))