-
Notifications
You must be signed in to change notification settings - Fork 0
/
ines.go
71 lines (60 loc) · 1.41 KB
/
ines.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
package gophernes
import (
"encoding/binary"
"errors"
"io"
"github.com/tomnz/gophernes/internal/cartridge"
)
const (
inesMagic = 0x1a53454e
prgLenMultiplier = 16384
chrLenMultiplier = 8192
)
type inesHeader struct {
Magic uint32
PrgLen,
ChrLen,
Flags6,
Flags7,
Flags8,
Flags9,
Flags10,
Flags11,
Flags12,
Flags13 byte
_ [2]byte
}
func loadINES(file io.Reader) (cartridge.Cartridge, error) {
header := inesHeader{}
if err := binary.Read(file, binary.LittleEndian, &header); err != nil {
return nil, err
}
if header.Magic != inesMagic {
return nil, errors.New("does not appear to be an iNES file: invalid header")
}
// TODO: Detect iNES version
// https://wiki.nesdev.com/w/index.php/INES#Variant_comparison
// For now, assume iNES 1.0
mapper := uint16(header.Flags6>>4 | header.Flags7&0xf0)
if (header.Flags6>>3)&1 == 1 {
// Trainer is present in the ROM - ignore
if _, err := io.ReadFull(file, make([]byte, 512)); err != nil {
return nil, err
}
}
prg := make([]byte, prgLenMultiplier*int(header.PrgLen))
if _, err := io.ReadFull(file, prg); err != nil {
return nil, err
}
var chr []byte
if header.ChrLen == 0 {
// Special case - provide an empty block
chr = make([]byte, 8192)
} else {
chr = make([]byte, chrLenMultiplier*int(header.ChrLen))
if _, err := io.ReadFull(file, chr); err != nil {
return nil, err
}
}
return cartridge.NewCartridge(mapper, prg, chr)
}