Example #1
0
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")
		}
	}
}
Example #2
0
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
}
Example #3
0
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)
	}
}