-
Notifications
You must be signed in to change notification settings - Fork 0
/
rom.go
94 lines (80 loc) · 1.63 KB
/
rom.go
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
package gnes
import (
"encoding/binary"
"errors"
"io"
"os"
)
const (
iNESMagic = 0x4e45531a
RPGBankSize = 16 << 10
CHRBankSize = 8 << 10
RAMBankSize = 8 << 10
)
type Mirroring int
const (
Horizontal Mirroring = iota
Vertical
)
type romHeader struct {
Magic uint32 // NES\x1a
NumRPG byte // Number of 16kB RPG-ROM banks.
NumCHR byte // Number of 8kB CHR-ROM/VROM banks.
Control1 byte // ROM Control Byte 1
Control2 byte // ROM Control Byte 2
NumRAM byte // Number of 8kB RAM banks
_ [7]byte // Reserved
}
type ROM struct {
Mapper byte
NumRPG byte
RPG []byte
NumCHR byte
CHR []byte
NumRAM int
mirroring Mirroring
Battery bool
}
func LoadROM(path string) (*ROM, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
h := romHeader{}
err = binary.Read(f, binary.BigEndian, &h)
if err != nil {
return nil, err
}
if h.Magic != iNESMagic {
return nil, errors.New("Invalid ROM format")
}
if h.Control1&(1<<2) != 0 {
return nil, errors.New("Trainer not supported")
}
rpg := make([]byte, RPGBankSize*int(h.NumRPG))
if _, err := io.ReadFull(f, rpg); err != nil {
return nil, err
}
chr := make([]byte, CHRBankSize*int(h.NumCHR))
if _, err := io.ReadFull(f, chr); err != nil {
return nil, err
}
rom := ROM{
Mapper: 0xf0&h.Control2 | h.Control1>>4,
NumRPG: h.NumRPG,
RPG: rpg,
NumCHR: h.NumCHR,
CHR: chr,
NumRAM: int(h.NumRAM),
Battery: h.Control1&(1<<1) != 0,
}
if rom.NumRAM == 0 {
rom.NumRAM = 1
}
if h.Control1&1 == 0 {
rom.mirroring = Horizontal
} else {
rom.mirroring = Vertical
}
return &rom, nil
}