diff --git a/nes/cassette.go b/nes/cassette.go index f430bdb..9199aa1 100644 --- a/nes/cassette.go +++ b/nes/cassette.go @@ -29,15 +29,15 @@ func (m *MirroringType) IsFourScreen() bool { } type iNESHeader struct { - Magic uint32 - PRGSize byte - CHRSize byte - Flags6 byte // Mapper, mirroring, battery, trainer - Flags7 byte // Mapper, VS/Playchoice, NES 2.0 - Flags8 byte // PRG-RAM size (rarely used extension) - Flags9 byte // TV system (rarely used extension) - Flags10 byte // TV system, PRG-RAM presence (unofficial, rarely used extension) - _ [5]byte + Magic uint32 + PRGROMSize byte // Size of PRG ROM in 16 KB units + CHRROMSize byte // Size of CHR ROM in 8 KB units (value 0 means the board uses CHR RAM) + Flags6 byte // Mapper, mirroring, battery, trainer + Flags7 byte // Mapper, VS/Playchoice, NES 2.0 + Flags8 byte // PRG-RAM size (rarely used extension) + Flags9 byte // TV system (rarely used extension) + Flags10 byte // TV system, PRG-RAM presence (unofficial, rarely used extension) + _ [5]byte } type Cassette struct { @@ -45,6 +45,8 @@ type Cassette struct { CHR []byte Mapper byte Mirror MirroringType + + chrROMSize byte } func NewCassette(r io.Reader) (*Cassette, error) { @@ -79,16 +81,16 @@ func NewCassette(r io.Reader) (*Cassette, error) { mapper := (header.Flags7 & 0xF0) | (header.Flags6&0xF0)>>4 - prgRom := make([]byte, int(header.PRGSize)*programROMUnit) + prgRom := make([]byte, int(header.PRGROMSize)*programROMUnit) if _, err := io.ReadFull(r, prgRom); err != nil { return nil, err } - chrRom := make([]byte, int(header.CHRSize)*characterROMUnit) + chrRom := make([]byte, int(header.CHRROMSize)*characterROMUnit) if _, err := io.ReadFull(r, chrRom); err != nil { return nil, err } - if header.CHRSize == 0 { + if header.CHRROMSize == 0 { chrRom = make([]byte, 8192) } @@ -97,9 +99,22 @@ func NewCassette(r io.Reader) (*Cassette, error) { CHR: chrRom, Mapper: mapper, Mirror: mirroringType, + + chrROMSize: header.CHRROMSize, }, nil } func (c *Cassette) MirroingType() MirroringType { return c.Mirror } + +func (c *Cassette) readCHR(index uint16) byte { + return c.CHR[index] +} + +func (c *Cassette) writeCHR(index uint16, val byte) { + if c.chrROMSize == 0 { + // CHR RAM + c.CHR[index] = val + } +} diff --git a/nes/mapper0.go b/nes/mapper0.go index 10e7dc3..2c6ac08 100644 --- a/nes/mapper0.go +++ b/nes/mapper0.go @@ -26,7 +26,7 @@ func (m *mapper0) Reset() { func (m *mapper0) Read(addr uint16) byte { switch { case 0x0000 <= addr && addr < 0x2000: - return m.CHR[addr] + return m.readCHR(addr) case 0x6000 <= addr && addr < 0x8000: return m.SRAM[addr-0x6000] case 0x8000 <= addr && addr < 0xC000: @@ -48,7 +48,7 @@ func (m *mapper0) Write(addr uint16, val byte) { case 0x0000 <= addr && addr < 0x2000: // https://www.nesdev.org/wiki/NROM // > CHR capacity: 8 KiB ROM (DIP-28 standard pinout) but most emulators support RAM - m.CHR[addr] = val + m.writeCHR(addr, val) case 0x6000 <= addr && addr < 0x8000: m.SRAM[addr-0x6000] = val case 0x8000 <= addr && addr <= 0xFFFF: diff --git a/nes/mapper2.go b/nes/mapper2.go index e268fdf..6edfd8c 100644 --- a/nes/mapper2.go +++ b/nes/mapper2.go @@ -25,7 +25,7 @@ func (m *mapper2) Reset() { func (m *mapper2) Read(addr uint16) byte { switch { case 0x0000 <= addr && addr < 0x2000: - return m.CHR[addr] + return m.readCHR(addr) case 0x6000 <= addr && addr < 0x8000: // mapper2 dont'h have PRG RAM return 0 @@ -45,9 +45,9 @@ func (m *mapper2) Read(addr uint16) byte { func (m *mapper2) Write(addr uint16, val byte) { switch { case 0x0000 <= addr && addr < 0x2000: - m.CHR[addr] = val + // mapper2 don't have CHR RAM case 0x6000 <= addr && addr < 0x8000: - // mapper2 dont'h have PRG RAM + // mapper2 don't have PRG RAM case 0x8000 <= addr && addr <= 0xFFFF: // 7 bit 0 // ---- ---- diff --git a/nes/mapper3.go b/nes/mapper3.go index 9a69a06..a731b65 100644 --- a/nes/mapper3.go +++ b/nes/mapper3.go @@ -28,8 +28,8 @@ func (m *mapper3) Read(addr uint16) byte { switch { case 0x0000 <= addr && addr < 0x2000: // > PPU $0000-$1FFF: 8 KB switchable CHR ROM bank - index := int(m.chrBank)*0x2000 + int(addr) - return m.CHR[index] + index := uint16(m.chrBank)*0x2000 + uint16(addr) + return m.readCHR(index) case 0x6000 <= addr && addr < 0x8000: // mapper 3 don't have PRG RAM // but, prepare RAM for automatic testing of ppu_read_buffer