aboutsummaryrefslogtreecommitdiff
path: root/cart/cart.go
diff options
context:
space:
mode:
authorcrecher <crecher@crecher.net>2026-10-12 04:07:09 +0200
committercrecher <crecher@crecher.net>2026-10-12 04:07:09 +0200
commit8b0292cccf768efdd5295fe0b662488cbc671079 (patch)
treef2896047a2328d8aea9a7f7815a6cf8d9c0636ea /cart/cart.go
parent7775f9ad5407f2be4b03c300d1db4c745fda2f69 (diff)
downloadgones-8b0292cccf768efdd5295fe0b662488cbc671079.tar.gz
gones-8b0292cccf768efdd5295fe0b662488cbc671079.zip
added cart package, more tests, tests are now at ./tests and added .gitignore
Diffstat (limited to 'cart/cart.go')
-rw-r--r--cart/cart.go83
1 files changed, 83 insertions, 0 deletions
diff --git a/cart/cart.go b/cart/cart.go
new file mode 100644
index 0000000..2438c1b
--- /dev/null
+++ b/cart/cart.go
@@ -0,0 +1,83 @@
+package cart
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "os"
+)
+
+type Cartridge struct {
+ PRG []uint8
+ CHR []uint8
+ CHRIsRAM bool
+ MapperID uint8
+ Mirroring Mirroring
+ Battery bool
+
+ Mapper Mapper
+}
+
+func Load(path string) (*Cartridge, error) {
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return nil, err
+ }
+ return Parse(data)
+}
+
+func Parse(data []byte) (*Cartridge, error) {
+ if len(data) < 16 || !bytes.Equal(data[:4], []byte("NES\x1A")) {
+ return nil, errors.New("cart: not an iNES file")
+ }
+
+ prgSize := int(data[4]) * 16 * 1024
+ chrSize := int(data[5]) * 8 * 1024
+ flags6, flags7 := data[6], data[7]
+
+ isNES2 := flags7&0x0C == 0x08
+ mapperID := flags6 >> 4
+ if isNES2 || bytes.Equal(data[12:16], []byte{0, 0, 0, 0}) {
+ mapperID |= flags7 & 0xF0
+ }
+
+ c := &Cartridge{
+ MapperID: mapperID,
+ Battery: flags6&0x02 != 0,
+ }
+
+ switch {
+ case flags6&0x08 != 0:
+ c.Mirroring = FourScreen
+ case flags6&0x01 != 0:
+ c.Mirroring = Vertical
+ default:
+ c.Mirroring = Horizontal
+ }
+
+ offset := 16
+ if flags6&0x04 != 0 {
+ offset += 512
+ }
+ if len(data) < offset+prgSize+chrSize {
+ return nil, fmt.Errorf("cart: file truncated: need %d bytes, have %d",
+ offset+prgSize+chrSize, len(data))
+ }
+
+ c.PRG = data[offset : offset+prgSize]
+ offset += prgSize
+
+ if chrSize == 0 {
+ c.CHR = make([]uint8, 8*1024)
+ c.CHRIsRAM = true
+ } else {
+ c.CHR = data[offset : offset+chrSize]
+ }
+
+ m, err := newMapper(c)
+ if err != nil {
+ return nil, err
+ }
+ c.Mapper = m
+ return c, nil
+}