func TestVerticalMirroring(t *testing.T) { ppu := rp2cgo2.NewRP2C02(nil, "NTSC") ppu.Nametable.SetTables(0, 1, 0, 1) // Mirror nametable #2 to #0 for i := uint16(0x2800); i <= 0x2bff; i++ { ppu.Memory.Store(i-0x0800, 0xff) if ppu.Memory.Fetch(i) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i-0x0800, 0x00) if ppu.Memory.Fetch(i) != 0x00 { t.Error("Memory is not 0x00") } ppu.Memory.Store(i, 0xff) if ppu.Memory.Fetch(i-0x0800) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i, 0x00) if ppu.Memory.Fetch(i) != 0x00 { t.Error("Memory is not 0x00") } } // Mirror nametable #3 to #1 for i := uint16(0x2c00); i <= 0x2fff; i++ { ppu.Memory.Store(i-0x0800, 0xff) if ppu.Memory.Fetch(i) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i-0x0800, 0x00) if ppu.Memory.Fetch(i) != 0x00 { t.Error("Memory is not 0x00") } ppu.Memory.Store(i, 0xff) if ppu.Memory.Fetch(i-0x0800) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i, 0x00) if ppu.Memory.Fetch(i) != 0x00 { t.Error("Memory is not 0x00") } } // Mirror nametable #2 to #0 for i := uint16(0x3000); i <= 0x33ff; i++ { ppu.Memory.Store(i-0x1000, 0xff) if ppu.Memory.Fetch(i) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i-0x1000, 0x00) if ppu.Memory.Fetch(i) != 0x00 { t.Error("Memory is not 0x00") } ppu.Memory.Store(i, 0xff) if ppu.Memory.Fetch(i-0x1000) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i, 0x00) if ppu.Memory.Fetch(i) != 0x00 { t.Error("Memory is not 0x00") } } // Mirror nametable #3 to #1 for i := uint16(0x3400); i <= 0x37ff; i++ { ppu.Memory.Store(i-0x1000, 0xff) if ppu.Memory.Fetch(i) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i-0x1000, 0x00) if ppu.Memory.Fetch(i) != 0x00 { t.Error("Memory is not 0x00") } ppu.Memory.Store(i, 0xff) if ppu.Memory.Fetch(i-0x1000) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i, 0x00) if ppu.Memory.Fetch(i) != 0x00 { t.Error("Memory is not 0x00") } } }
func NewNESFromReader(gamename string, reader io.Reader, options *Options) (nes *NES, err error) { var audio Audio var video Video var recorder Recorder var audioRecorder AudioRecorder var cpuDivisor float32 var master bool var bridge *Bridge var rom ROM region := RegionFromString(options.Region) switch region { case NTSC, PAL: default: err = fmt.Errorf("Invalid region %v, must be NTSC or PAL", options.Region) return } audioFrequency := 44100 audioSampleSize := 2048 cpu := rp2ago3.NewRP2A03(audioFrequency) if options.CPUDecode { cpu.EnableDecode() } ppu := rp2cgo2.NewRP2C02(cpu.InterruptLine(m65go2.Nmi), region.String()) if len(options.Connect) > 0 { master = false bridge = newBridge(nil, options.Connect) } else { master = true bridge = newBridge(nil, options.Listen) buf, err := ioutil.ReadAll(reader) if err != nil { err = errors.New(fmt.Sprintf("Error loading ROM: %v", err)) return nil, err } rom, err = NewROMFromBuf(buf, gamename, ".nes", cpu.InterruptLine(m65go2.Irq), ppu.Nametable.SetTables) if err != nil { err = errors.New(fmt.Sprintf("Error loading ROM: %v", err)) return nil, err } gamename = rom.GameName() switch region { case NTSC: cpuDivisor = rp2ago3.NTSCCPUClockDivisor case PAL: cpuDivisor = rp2ago3.PALCPUClockDivisor } } ctrls := NewControllers() DefaultFPS := DefaultFPSNTSC if region == PAL { DefaultFPS = DefaultFPSPAL } fps := NewFPS(DefaultFPS) events := make(chan Event) framePool := &sync.Pool{New: func() interface{} { return make([]uint8, rp2cgo2.FrameSize) }} video, err = NewVideo(gamename, events, framePool, DefaultFPS) if err != nil { err = errors.New(fmt.Sprintf("Error creating video: %v", err)) return } audio, err = NewAudio(audioFrequency, audioSampleSize) if err != nil { err = errors.New(fmt.Sprintf("Error creating audio: %v", err)) return } switch options.Recorder { case "none": // none case "jpeg": recorder, err = NewJPEGRecorder() case "gif": recorder, err = NewGIFRecorder() } if err != nil { err = errors.New(fmt.Sprintf("Error creating recorder: %v", err)) return } switch options.AudioRecorder { case "none": // none case "wav": audioRecorder, err = NewWAVRecorder() } if err != nil { err = errors.New(fmt.Sprintf("Error creating audio recorder: %v", err)) return } cpu.Memory.AddMappings(ppu, rp2ago3.CPU) cpu.Memory.AddMappings(ctrls, rp2ago3.CPU) if master { cpu.Memory.AddMappings(rom, rp2ago3.CPU) ppu.Memory.AddMappings(rom, rp2ago3.PPU) } lock := make(chan uint64, 1) lock <- 0 nes = &NES{ GameName: gamename, events: events, CPU: cpu, CPUDivisor: cpuDivisor, PPU: ppu, ROM: rom, audio: audio, video: video, DefaultFPS: DefaultFPS, fps: fps, recorder: recorder, audioRecorder: audioRecorder, controllers: ctrls, options: options, lock: lock, Tick: 0, master: master, bridge: bridge, framePool: framePool, } bridge.nes = nes return }
func TestHorizontalMirroring(t *testing.T) { ppu := rp2cgo2.NewRP2C02(nil, "NTSC") ppu.Nametable.SetTables(0, 0, 1, 1) // Mirror nametable #1 to #0 for i := uint16(0x2400); i <= 0x27ff; i++ { ppu.Memory.Store(i-0x0400, 0xff) if ppu.Memory.Fetch(i) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i-0x0400, 0x00) ppu.Memory.Store(i, 0xff) if ppu.Memory.Fetch(i-0x0400) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i, 0x00) } // Mirror nametable #3 to #2 for i := uint16(0x2c00); i <= 0x2fff; i++ { ppu.Memory.Store(i-0x0400, 0xff) if ppu.Memory.Fetch(i) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i-0x0400, 0x00) ppu.Memory.Store(i, 0xff) if ppu.Memory.Fetch(i-0x0400) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i, 0x00) } // Mirror nametable #1 to #0 for i := uint16(0x3400); i <= 0x37ff; i++ { ppu.Memory.Store(i-0x1400, 0xff) if ppu.Memory.Fetch(i) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i-0x1400, 0x00) ppu.Memory.Store(i, 0xff) if ppu.Memory.Fetch(i-0x1400) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i, 0x00) } // Mirror nametable #3 to #2 for i := uint16(0x3c00); i <= 0x3eff; i++ { ppu.Memory.Store(i-0x1400, 0xff) if ppu.Memory.Fetch(i) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i-0x1400, 0x00) ppu.Memory.Store(i, 0xff) if ppu.Memory.Fetch(i-0x1400) != 0xff { t.Error("Memory is not 0xff") } ppu.Memory.Store(i, 0x00) } }