From 922a0e420ca85ffe710f28274c71fd6c44f05fb5 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 18 Apr 2019 17:27:44 +1000 Subject: [PATCH] Update to bsnes v107r2 beta release. byuu says: Added DerKoun's HD mode 7 (up to 2160p), ~100fps boost for fast forwarding, configurable latency settings for waveOut (please configure this yourself), filename case insensitivity, and a few other things. --- {higan => bsnes}/GNUmakefile | 51 +- {higan => bsnes}/emulator/audio/audio.cpp | 0 {higan => bsnes}/emulator/audio/audio.hpp | 0 {higan => bsnes}/emulator/audio/stream.cpp | 0 {higan => bsnes}/emulator/cheat.hpp | 0 {higan => bsnes}/emulator/emulator.cpp | 0 {higan => bsnes}/emulator/emulator.hpp | 4 +- {higan => bsnes}/emulator/game.hpp | 0 {higan => bsnes}/emulator/interface.hpp | 3 + {higan => bsnes}/emulator/memory/memory.hpp | 0 {higan => bsnes}/emulator/memory/readable.hpp | 0 {higan => bsnes}/emulator/memory/writable.hpp | 0 {higan => bsnes}/emulator/platform.hpp | 0 {higan => bsnes}/emulator/random.hpp | 0 .../emulator/resource/GNUmakefile | 0 .../emulator/resource/resource.bml | 0 .../emulator/resource/resource.cpp | 0 .../emulator/resource/resource.hpp | 0 .../resource/sprite/crosshair-blue.png | Bin .../resource/sprite/crosshair-green.png | Bin .../resource/sprite/crosshair-red.png | Bin {higan => bsnes}/emulator/scheduler.hpp | 0 {higan => bsnes}/emulator/thread.hpp | 0 {higan => bsnes}/emulator/types.hpp | 0 {higan => bsnes}/emulator/video/sprite.cpp | 0 {higan => bsnes}/emulator/video/video.cpp | 0 {higan => bsnes}/emulator/video/video.hpp | 0 {higan => bsnes}/gb/GNUmakefile | 0 {higan => bsnes}/gb/apu/apu.cpp | 0 {higan => bsnes}/gb/apu/apu.hpp | 0 {higan => bsnes}/gb/apu/noise.cpp | 0 {higan => bsnes}/gb/apu/sequencer.cpp | 0 {higan => bsnes}/gb/apu/serialization.cpp | 0 {higan => bsnes}/gb/apu/square1.cpp | 0 {higan => bsnes}/gb/apu/square2.cpp | 0 {higan => bsnes}/gb/apu/wave.cpp | 0 {higan => bsnes}/gb/cartridge/cartridge.cpp | 0 {higan => bsnes}/gb/cartridge/cartridge.hpp | 0 {higan => bsnes}/gb/cartridge/huc1/huc1.cpp | 0 {higan => bsnes}/gb/cartridge/huc1/huc1.hpp | 0 {higan => bsnes}/gb/cartridge/huc3/huc3.cpp | 0 {higan => bsnes}/gb/cartridge/huc3/huc3.hpp | 0 {higan => bsnes}/gb/cartridge/mbc0/mbc0.cpp | 0 {higan => bsnes}/gb/cartridge/mbc0/mbc0.hpp | 0 {higan => bsnes}/gb/cartridge/mbc1/mbc1.cpp | 0 {higan => bsnes}/gb/cartridge/mbc1/mbc1.hpp | 0 {higan => bsnes}/gb/cartridge/mbc1m/mbc1m.cpp | 0 {higan => bsnes}/gb/cartridge/mbc1m/mbc1m.hpp | 0 {higan => bsnes}/gb/cartridge/mbc2/mbc2.cpp | 0 {higan => bsnes}/gb/cartridge/mbc2/mbc2.hpp | 0 {higan => bsnes}/gb/cartridge/mbc3/mbc3.cpp | 0 {higan => bsnes}/gb/cartridge/mbc3/mbc3.hpp | 0 {higan => bsnes}/gb/cartridge/mbc5/mbc5.cpp | 0 {higan => bsnes}/gb/cartridge/mbc5/mbc5.hpp | 0 {higan => bsnes}/gb/cartridge/mbc6/mbc6.cpp | 0 {higan => bsnes}/gb/cartridge/mbc6/mbc6.hpp | 0 {higan => bsnes}/gb/cartridge/mbc7/eeprom.cpp | 0 {higan => bsnes}/gb/cartridge/mbc7/mbc7.cpp | 0 {higan => bsnes}/gb/cartridge/mbc7/mbc7.hpp | 0 .../gb/cartridge/mbc7/serialization.cpp | 0 {higan => bsnes}/gb/cartridge/mmm01/mmm01.cpp | 0 {higan => bsnes}/gb/cartridge/mmm01/mmm01.hpp | 0 .../gb/cartridge/serialization.cpp | 0 {higan => bsnes}/gb/cartridge/tama/tama.cpp | 0 {higan => bsnes}/gb/cartridge/tama/tama.hpp | 0 {higan => bsnes}/gb/cpu/cpu.cpp | 0 {higan => bsnes}/gb/cpu/cpu.hpp | 0 {higan => bsnes}/gb/cpu/io.cpp | 0 {higan => bsnes}/gb/cpu/memory.cpp | 0 {higan => bsnes}/gb/cpu/serialization.cpp | 0 {higan => bsnes}/gb/cpu/timing.cpp | 0 {higan => bsnes}/gb/gb.hpp | 0 .../gb/interface/game-boy-color.cpp | 0 {higan => bsnes}/gb/interface/game-boy.cpp | 0 {higan => bsnes}/gb/interface/interface.cpp | 0 {higan => bsnes}/gb/interface/interface.hpp | 4 - {higan => bsnes}/gb/memory/memory.cpp | 0 {higan => bsnes}/gb/memory/memory.hpp | 0 {higan => bsnes}/gb/ppu/cgb.cpp | 0 {higan => bsnes}/gb/ppu/dmg.cpp | 0 {higan => bsnes}/gb/ppu/io.cpp | 0 {higan => bsnes}/gb/ppu/ppu.cpp | 0 {higan => bsnes}/gb/ppu/ppu.hpp | 0 {higan => bsnes}/gb/ppu/serialization.cpp | 0 {higan => bsnes}/gb/system/serialization.cpp | 0 {higan => bsnes}/gb/system/system.cpp | 0 {higan => bsnes}/gb/system/system.hpp | 0 {higan => bsnes}/obj/.gitignore | 0 bsnes/out/.gitignore | 1 + {higan => bsnes}/processor/GNUmakefile | 0 .../processor/arm7tdmi/algorithms.cpp | 0 .../processor/arm7tdmi/arm7tdmi.cpp | 0 .../processor/arm7tdmi/arm7tdmi.hpp | 0 .../processor/arm7tdmi/disassembler.cpp | 0 .../processor/arm7tdmi/instruction.cpp | 0 .../processor/arm7tdmi/instructions-arm.cpp | 0 .../processor/arm7tdmi/instructions-thumb.cpp | 0 .../processor/arm7tdmi/memory.cpp | 0 .../processor/arm7tdmi/registers.cpp | 0 .../processor/arm7tdmi/serialization.cpp | 0 .../processor/gsu/disassembler.cpp | 0 {higan => bsnes}/processor/gsu/gsu.cpp | 0 {higan => bsnes}/processor/gsu/gsu.hpp | 0 .../processor/gsu/instruction.cpp | 0 .../processor/gsu/instructions.cpp | 0 {higan => bsnes}/processor/gsu/registers.hpp | 0 .../processor/gsu/serialization.cpp | 0 {higan => bsnes}/processor/hg51b/hg51b.cpp | 0 {higan => bsnes}/processor/hg51b/hg51b.hpp | 0 .../processor/hg51b/instruction.cpp | 0 .../processor/hg51b/instructions.cpp | 0 .../processor/hg51b/registers.cpp | 0 .../processor/hg51b/serialization.cpp | 0 .../processor/huc6280/algorithms.cpp | 0 .../processor/huc6280/disassembler.cpp | 0 .../processor/huc6280/huc6280.cpp | 0 .../processor/huc6280/huc6280.hpp | 0 .../processor/huc6280/instruction.cpp | 0 .../processor/huc6280/instructions.cpp | 0 {higan => bsnes}/processor/huc6280/memory.cpp | 0 .../processor/huc6280/serialization.cpp | 0 .../processor/m68k/disassembler.cpp | 0 .../processor/m68k/effective-address.cpp | 0 .../processor/m68k/instruction.cpp | 0 .../processor/m68k/instructions.cpp | 0 {higan => bsnes}/processor/m68k/m68k.cpp | 0 {higan => bsnes}/processor/m68k/m68k.hpp | 0 {higan => bsnes}/processor/m68k/memory.cpp | 0 {higan => bsnes}/processor/m68k/registers.cpp | 0 .../processor/m68k/serialization.cpp | 0 .../processor/mos6502/algorithms.cpp | 0 .../processor/mos6502/disassembler.cpp | 0 .../processor/mos6502/instruction.cpp | 0 .../processor/mos6502/instructions.cpp | 0 {higan => bsnes}/processor/mos6502/memory.cpp | 0 .../processor/mos6502/mos6502.cpp | 0 .../processor/mos6502/mos6502.hpp | 0 .../processor/mos6502/serialization.cpp | 0 {higan => bsnes}/processor/processor.hpp | 0 .../processor/sm83/algorithms.cpp | 0 .../processor/sm83/disassembler.cpp | 0 .../processor/sm83/instruction.cpp | 0 .../processor/sm83/instructions.cpp | 0 {higan => bsnes}/processor/sm83/memory.cpp | 0 {higan => bsnes}/processor/sm83/registers.cpp | 0 .../processor/sm83/serialization.cpp | 0 {higan => bsnes}/processor/sm83/sm83.cpp | 0 {higan => bsnes}/processor/sm83/sm83.hpp | 0 .../processor/spc700/algorithms.cpp | 0 .../processor/spc700/disassembler.cpp | 0 .../processor/spc700/instruction.cpp | 0 .../processor/spc700/instructions.cpp | 0 {higan => bsnes}/processor/spc700/memory.cpp | 0 .../processor/spc700/serialization.cpp | 0 {higan => bsnes}/processor/spc700/spc700.cpp | 0 {higan => bsnes}/processor/spc700/spc700.hpp | 0 .../processor/tlcs900h/algorithms.cpp | 0 .../processor/tlcs900h/conditions.cpp | 0 .../processor/tlcs900h/control-registers.cpp | 0 .../processor/tlcs900h/disassembler.cpp | 0 .../processor/tlcs900h/instruction.cpp | 0 .../processor/tlcs900h/instructions.cpp | 0 .../processor/tlcs900h/memory.cpp | 0 .../processor/tlcs900h/registers.cpp | 0 .../processor/tlcs900h/serialization.cpp | 0 .../processor/tlcs900h/tlcs900h.cpp | 0 .../processor/tlcs900h/tlcs900h.hpp | 0 .../processor/upd96050/disassembler.cpp | 0 .../processor/upd96050/instructions.cpp | 0 .../processor/upd96050/memory.cpp | 0 .../processor/upd96050/serialization.cpp | 0 .../processor/upd96050/upd96050.cpp | 0 .../processor/upd96050/upd96050.hpp | 0 .../processor/v30mz/algorithms.cpp | 0 .../processor/v30mz/disassembler-old.cpp | 0 .../processor/v30mz/disassembler.cpp | 0 .../processor/v30mz/instruction.cpp | 0 .../processor/v30mz/instructions-adjust.cpp | 0 .../processor/v30mz/instructions-alu.cpp | 0 .../processor/v30mz/instructions-exec.cpp | 0 .../processor/v30mz/instructions-flag.cpp | 0 .../processor/v30mz/instructions-group.cpp | 0 .../processor/v30mz/instructions-misc.cpp | 0 .../processor/v30mz/instructions-move.cpp | 0 .../processor/v30mz/instructions-string.cpp | 0 {higan => bsnes}/processor/v30mz/memory.cpp | 0 {higan => bsnes}/processor/v30mz/modrm.cpp | 0 .../processor/v30mz/registers.cpp | 0 .../processor/v30mz/serialization.cpp | 0 {higan => bsnes}/processor/v30mz/v30mz.cpp | 0 {higan => bsnes}/processor/v30mz/v30mz.hpp | 0 .../processor/wdc65816/algorithms.cpp | 0 .../processor/wdc65816/disassembler.cpp | 0 .../processor/wdc65816/instruction.cpp | 0 .../processor/wdc65816/instruction.hpp | 0 .../wdc65816/instructions-modify.cpp | 0 .../processor/wdc65816/instructions-other.cpp | 0 .../processor/wdc65816/instructions-pc.cpp | 0 .../processor/wdc65816/instructions-read.cpp | 0 .../processor/wdc65816/instructions-write.cpp | 0 .../processor/wdc65816/memory.cpp | 0 .../processor/wdc65816/serialization.cpp | 0 .../processor/wdc65816/wdc65816.cpp | 0 .../processor/wdc65816/wdc65816.hpp | 0 {higan => bsnes}/processor/z80/algorithms.cpp | 0 .../processor/z80/disassembler.cpp | 0 .../processor/z80/instruction.cpp | 0 .../processor/z80/instructions.cpp | 0 {higan => bsnes}/processor/z80/memory.cpp | 0 {higan => bsnes}/processor/z80/registers.cpp | 0 .../processor/z80/serialization.cpp | 0 {higan => bsnes}/processor/z80/z80.cpp | 0 {higan => bsnes}/processor/z80/z80.hpp | 0 {higan => bsnes}/sfc/GNUmakefile | 0 {higan => bsnes}/sfc/cartridge/cartridge.cpp | 3 - {higan => bsnes}/sfc/cartridge/cartridge.hpp | 0 {higan => bsnes}/sfc/cartridge/load.cpp | 0 {higan => bsnes}/sfc/cartridge/save.cpp | 0 .../sfc/cartridge/serialization.cpp | 0 .../sfc/controller/controller.cpp | 0 .../sfc/controller/controller.hpp | 0 .../sfc/controller/gamepad/gamepad.cpp | 0 .../sfc/controller/gamepad/gamepad.hpp | 0 .../sfc/controller/justifier/justifier.cpp | 0 .../sfc/controller/justifier/justifier.hpp | 0 .../sfc/controller/mouse/mouse.cpp | 0 .../sfc/controller/mouse/mouse.hpp | 0 .../super-multitap/super-multitap.cpp | 0 .../super-multitap/super-multitap.hpp | 0 .../controller/super-scope/super-scope.cpp | 0 .../controller/super-scope/super-scope.hpp | 0 .../sfc/coprocessor/armdsp/armdsp.cpp | 0 .../sfc/coprocessor/armdsp/armdsp.hpp | 0 .../sfc/coprocessor/armdsp/memory.cpp | 0 .../sfc/coprocessor/armdsp/registers.hpp | 0 .../sfc/coprocessor/armdsp/serialization.cpp | 0 .../sfc/coprocessor/coprocessor.hpp | 0 {higan => bsnes}/sfc/coprocessor/cx4/cx4.cpp | 0 {higan => bsnes}/sfc/coprocessor/cx4/cx4.hpp | 0 {higan => bsnes}/sfc/coprocessor/cx4/data.cpp | 0 .../sfc/coprocessor/cx4/functions.cpp | 0 {higan => bsnes}/sfc/coprocessor/cx4/oam.cpp | 0 .../sfc/coprocessor/cx4/opcodes.cpp | 0 .../sfc/coprocessor/cx4/serialization.cpp | 0 {higan => bsnes}/sfc/coprocessor/dip/dip.cpp | 0 {higan => bsnes}/sfc/coprocessor/dip/dip.hpp | 0 .../sfc/coprocessor/dip/serialization.cpp | 0 .../sfc/coprocessor/dsp1/dsp1.cpp | 0 .../sfc/coprocessor/dsp1/dsp1.hpp | 0 .../sfc/coprocessor/dsp1/dsp1emu.cpp | 0 .../sfc/coprocessor/dsp1/dsp1emu.hpp | 0 .../sfc/coprocessor/dsp1/serialization.cpp | 0 .../sfc/coprocessor/dsp2/dsp2.cpp | 0 .../sfc/coprocessor/dsp2/dsp2.hpp | 0 .../sfc/coprocessor/dsp2/opcodes.cpp | 0 .../sfc/coprocessor/dsp2/serialization.cpp | 0 .../sfc/coprocessor/dsp4/dsp4.cpp | 0 .../sfc/coprocessor/dsp4/dsp4.hpp | 0 .../sfc/coprocessor/dsp4/dsp4emu.c | 0 .../sfc/coprocessor/dsp4/dsp4emu.h | 0 .../sfc/coprocessor/dsp4/serialization.cpp | 0 .../sfc/coprocessor/epsonrtc/epsonrtc.cpp | 0 .../sfc/coprocessor/epsonrtc/epsonrtc.hpp | 0 .../sfc/coprocessor/epsonrtc/memory.cpp | 0 .../coprocessor/epsonrtc/serialization.cpp | 0 .../sfc/coprocessor/epsonrtc/time.cpp | 0 .../sfc/coprocessor/event/event.cpp | 0 .../sfc/coprocessor/event/event.hpp | 0 .../sfc/coprocessor/event/serialization.cpp | 0 .../sfc/coprocessor/hitachidsp/hitachidsp.cpp | 0 .../sfc/coprocessor/hitachidsp/hitachidsp.hpp | 0 .../sfc/coprocessor/hitachidsp/memory.cpp | 0 .../coprocessor/hitachidsp/serialization.cpp | 0 {higan => bsnes}/sfc/coprocessor/icd/icd.cpp | 4 - {higan => bsnes}/sfc/coprocessor/icd/icd.hpp | 22 - .../sfc/coprocessor/icd/interface.cpp | 0 {higan => bsnes}/sfc/coprocessor/icd/io.cpp | 0 .../sfc/coprocessor/icd/platform.cpp | 0 .../sfc/coprocessor/icd/serialization.cpp | 0 {higan => bsnes}/sfc/coprocessor/mcc/mcc.cpp | 0 {higan => bsnes}/sfc/coprocessor/mcc/mcc.hpp | 0 .../sfc/coprocessor/mcc/serialization.cpp | 0 .../sfc/coprocessor/msu1/msu1.cpp | 0 .../sfc/coprocessor/msu1/msu1.hpp | 0 .../sfc/coprocessor/msu1/serialization.cpp | 0 .../sfc/coprocessor/necdsp/necdsp.cpp | 0 .../sfc/coprocessor/necdsp/necdsp.hpp | 0 .../sfc/coprocessor/necdsp/serialization.cpp | 0 .../sfc/coprocessor/obc1/obc1.cpp | 0 .../sfc/coprocessor/obc1/obc1.hpp | 0 .../sfc/coprocessor/obc1/serialization.cpp | 0 .../sfc/coprocessor/sa1/bwram.cpp | 0 {higan => bsnes}/sfc/coprocessor/sa1/dma.cpp | 0 {higan => bsnes}/sfc/coprocessor/sa1/io.cpp | 0 {higan => bsnes}/sfc/coprocessor/sa1/iram.cpp | 0 .../sfc/coprocessor/sa1/memory.cpp | 0 {higan => bsnes}/sfc/coprocessor/sa1/rom.cpp | 0 {higan => bsnes}/sfc/coprocessor/sa1/sa1.cpp | 0 {higan => bsnes}/sfc/coprocessor/sa1/sa1.hpp | 0 .../sfc/coprocessor/sa1/serialization.cpp | 0 .../sfc/coprocessor/sdd1/decompressor.cpp | 0 .../sfc/coprocessor/sdd1/decompressor.hpp | 0 .../sfc/coprocessor/sdd1/sdd1.cpp | 0 .../sfc/coprocessor/sdd1/sdd1.hpp | 0 .../sfc/coprocessor/sdd1/serialization.cpp | 0 .../sfc/coprocessor/sharprtc/memory.cpp | 0 .../coprocessor/sharprtc/serialization.cpp | 0 .../sfc/coprocessor/sharprtc/sharprtc.cpp | 0 .../sfc/coprocessor/sharprtc/sharprtc.hpp | 0 .../sfc/coprocessor/sharprtc/time.cpp | 0 .../sfc/coprocessor/spc7110/alu.cpp | 0 .../sfc/coprocessor/spc7110/data.cpp | 0 .../sfc/coprocessor/spc7110/dcu.cpp | 0 .../sfc/coprocessor/spc7110/decompressor.cpp | 0 .../sfc/coprocessor/spc7110/serialization.cpp | 0 .../sfc/coprocessor/spc7110/spc7110.cpp | 0 .../sfc/coprocessor/spc7110/spc7110.hpp | 0 .../sfc/coprocessor/st0010/data.hpp | 0 .../sfc/coprocessor/st0010/opcodes.cpp | 0 .../sfc/coprocessor/st0010/serialization.cpp | 0 .../sfc/coprocessor/st0010/st0010.cpp | 0 .../sfc/coprocessor/st0010/st0010.hpp | 0 .../sfc/coprocessor/superfx/bus.cpp | 0 .../sfc/coprocessor/superfx/core.cpp | 0 .../sfc/coprocessor/superfx/io.cpp | 0 .../sfc/coprocessor/superfx/memory.cpp | 0 .../sfc/coprocessor/superfx/serialization.cpp | 0 .../sfc/coprocessor/superfx/superfx.cpp | 0 .../sfc/coprocessor/superfx/superfx.hpp | 0 .../sfc/coprocessor/superfx/timing.cpp | 0 {higan => bsnes}/sfc/cpu/cpu.cpp | 0 {higan => bsnes}/sfc/cpu/cpu.hpp | 1 + {higan => bsnes}/sfc/cpu/dma.cpp | 0 {higan => bsnes}/sfc/cpu/io.cpp | 0 {higan => bsnes}/sfc/cpu/irq.cpp | 0 {higan => bsnes}/sfc/cpu/memory.cpp | 2 +- {higan => bsnes}/sfc/cpu/serialization.cpp | 0 {higan => bsnes}/sfc/cpu/timing.cpp | 23 + bsnes/sfc/dsp/SPC_DSP.cpp | 1046 +++++++++++++++++ bsnes/sfc/dsp/SPC_DSP.h | 304 +++++ bsnes/sfc/dsp/blargg_common.h | 186 +++ bsnes/sfc/dsp/blargg_config.h | 26 + bsnes/sfc/dsp/blargg_endian.h | 185 +++ bsnes/sfc/dsp/blargg_source.h | 100 ++ bsnes/sfc/dsp/dsp.cpp | 58 + bsnes/sfc/dsp/dsp.hpp | 24 + bsnes/sfc/dsp/serialization.cpp | 28 + {higan => bsnes}/sfc/expansion/21fx/21fx.cpp | 0 {higan => bsnes}/sfc/expansion/21fx/21fx.hpp | 0 {higan => bsnes}/sfc/expansion/expansion.cpp | 0 {higan => bsnes}/sfc/expansion/expansion.hpp | 0 .../sfc/expansion/satellaview/satellaview.cpp | 0 .../sfc/expansion/satellaview/satellaview.hpp | 0 .../sfc/interface/configuration.cpp | 11 +- .../sfc/interface/configuration.hpp | 19 +- {higan => bsnes}/sfc/interface/interface.cpp | 11 +- {higan => bsnes}/sfc/interface/interface.hpp | 7 +- {higan => bsnes}/sfc/memory/memory-inline.hpp | 0 {higan => bsnes}/sfc/memory/memory.cpp | 0 {higan => bsnes}/sfc/memory/memory.hpp | 0 {higan => bsnes}/sfc/memory/protectable.hpp | 0 {higan => bsnes}/sfc/memory/readable.hpp | 0 {higan => bsnes}/sfc/memory/writable.hpp | 0 {higan => bsnes}/sfc/ppu-fast/background.cpp | 21 +- {higan => bsnes}/sfc/ppu-fast/io.cpp | 92 +- {higan => bsnes}/sfc/ppu-fast/line.cpp | 64 +- bsnes/sfc/ppu-fast/mode7.cpp | 66 ++ bsnes/sfc/ppu-fast/mode7hd.cpp | 126 ++ bsnes/sfc/ppu-fast/mode7hires.cpp | 63 + {higan => bsnes}/sfc/ppu-fast/object.cpp | 34 +- bsnes/sfc/ppu-fast/ppu.cpp | 155 +++ {higan => bsnes}/sfc/ppu-fast/ppu.hpp | 172 +-- .../sfc/ppu-fast/serialization.cpp | 25 +- {higan => bsnes}/sfc/ppu-fast/window.cpp | 4 +- {higan => bsnes}/sfc/ppu/background.cpp | 0 {higan => bsnes}/sfc/ppu/background.hpp | 0 .../sfc/ppu/counter/counter-inline.hpp | 0 {higan => bsnes}/sfc/ppu/counter/counter.hpp | 0 .../sfc/ppu/counter/serialization.cpp | 0 {higan => bsnes}/sfc/ppu/io.cpp | 0 {higan => bsnes}/sfc/ppu/mode7.cpp | 0 {higan => bsnes}/sfc/ppu/oam.cpp | 0 {higan => bsnes}/sfc/ppu/object.cpp | 0 {higan => bsnes}/sfc/ppu/object.hpp | 0 {higan => bsnes}/sfc/ppu/ppu.cpp | 0 {higan => bsnes}/sfc/ppu/ppu.hpp | 58 +- {higan => bsnes}/sfc/ppu/screen.cpp | 0 {higan => bsnes}/sfc/ppu/screen.hpp | 0 {higan => bsnes}/sfc/ppu/serialization.cpp | 0 {higan => bsnes}/sfc/ppu/window.cpp | 0 {higan => bsnes}/sfc/ppu/window.hpp | 0 {higan => bsnes}/sfc/sfc.hpp | 4 +- .../sfc/slot/bsmemory/bsmemory.cpp | 0 .../sfc/slot/bsmemory/bsmemory.hpp | 0 .../sfc/slot/bsmemory/serialization.cpp | 0 {higan => bsnes}/sfc/slot/slot.hpp | 0 .../sfc/slot/sufamiturbo/serialization.cpp | 0 .../sfc/slot/sufamiturbo/sufamiturbo.cpp | 0 .../sfc/slot/sufamiturbo/sufamiturbo.hpp | 0 {higan => bsnes}/sfc/smp/io.cpp | 0 {higan => bsnes}/sfc/smp/memory.cpp | 2 +- {higan => bsnes}/sfc/smp/serialization.cpp | 0 {higan => bsnes}/sfc/smp/smp.cpp | 0 {higan => bsnes}/sfc/smp/smp.hpp | 2 + {higan => bsnes}/sfc/smp/timing.cpp | 21 +- {higan => bsnes}/sfc/system/serialization.cpp | 3 - {higan => bsnes}/sfc/system/system.cpp | 4 +- {higan => bsnes}/sfc/system/system.hpp | 5 +- .../systems/Game Boy Color.sys/boot.rom | Bin .../systems/Game Boy Color.sys/manifest.bml | 0 .../systems/Game Boy.sys/boot.rom | Bin .../systems/Game Boy.sys/manifest.bml | 0 .../systems/Super Famicom.sys/boards.bml | 0 .../systems/Super Famicom.sys/ipl.rom | Bin {higan => bsnes}/target-bsnes/GNUmakefile | 0 {higan => bsnes}/target-bsnes/bsnes.cpp | 2 +- {higan => bsnes}/target-bsnes/bsnes.hpp | 0 .../target-bsnes/input/hotkeys.cpp | 2 + {higan => bsnes}/target-bsnes/input/input.cpp | 0 {higan => bsnes}/target-bsnes/input/input.hpp | 0 .../presentation/presentation.cpp | 9 +- .../presentation/presentation.hpp | 0 .../target-bsnes/program/audio.cpp | 0 .../target-bsnes/program/game-pak.cpp | 0 .../target-bsnes/program/game-rom.cpp | 0 .../target-bsnes/program/game.cpp | 0 .../target-bsnes/program/hacks.cpp | 15 +- .../target-bsnes/program/input.cpp | 0 .../target-bsnes/program/patch.cpp | 0 .../target-bsnes/program/paths.cpp | 0 .../target-bsnes/program/platform.cpp | 26 +- .../target-bsnes/program/program.cpp | 5 + .../target-bsnes/program/program.hpp | 0 .../target-bsnes/program/states.cpp | 0 .../target-bsnes/program/utility.cpp | 0 .../target-bsnes/program/video.cpp | 0 .../target-bsnes/resource/GNUmakefile | 0 .../target-bsnes/resource/bsnes.Manifest | 0 .../target-bsnes/resource/bsnes.desktop | 0 .../target-bsnes/resource/bsnes.ico | Bin .../target-bsnes/resource/bsnes.plist | 0 .../target-bsnes/resource/bsnes.png | Bin .../target-bsnes/resource/bsnes.rc | 0 .../target-bsnes/resource/bsnes.svg | 0 .../target-bsnes/resource/icon.png | Bin .../resource/locales/japanese.bml | 0 .../target-bsnes/resource/logo.png | Bin .../target-bsnes/resource/resource.bml | 0 .../target-bsnes/resource/resource.cpp | 0 .../target-bsnes/resource/resource.hpp | 0 .../target-bsnes/settings/audio.cpp | 2 +- .../target-bsnes/settings/drivers.cpp | 6 +- bsnes/target-bsnes/settings/emulator.cpp | 114 ++ .../target-bsnes/settings/hotkeys.cpp | 0 .../target-bsnes/settings/input.cpp | 0 .../target-bsnes/settings/paths.cpp | 0 .../target-bsnes/settings/settings.cpp | 11 +- .../target-bsnes/settings/settings.hpp | 40 +- .../target-bsnes/settings/video.cpp | 0 .../target-bsnes/tools/cheat-editor.cpp | 0 .../target-bsnes/tools/manifest-viewer.cpp | 0 .../target-bsnes/tools/state-manager.cpp | 0 {higan => bsnes}/target-bsnes/tools/tools.cpp | 0 {higan => bsnes}/target-bsnes/tools/tools.hpp | 0 higan/fc/GNUmakefile | 13 - higan/fc/apu/apu.cpp | 319 ----- higan/fc/apu/apu.hpp | 182 --- higan/fc/apu/dmc.cpp | 89 -- higan/fc/apu/envelope.cpp | 26 - higan/fc/apu/noise.cpp | 42 - higan/fc/apu/pulse.cpp | 38 - higan/fc/apu/serialization.cpp | 104 -- higan/fc/apu/sweep.cpp | 40 - higan/fc/apu/triangle.cpp | 40 - higan/fc/cartridge/board/bandai-fcg.cpp | 110 -- higan/fc/cartridge/board/board.cpp | 223 ---- higan/fc/cartridge/board/board.hpp | 48 - higan/fc/cartridge/board/konami-vrc1.cpp | 34 - higan/fc/cartridge/board/konami-vrc2.cpp | 51 - higan/fc/cartridge/board/konami-vrc3.cpp | 51 - higan/fc/cartridge/board/konami-vrc4.cpp | 55 - higan/fc/cartridge/board/konami-vrc6.cpp | 39 - higan/fc/cartridge/board/konami-vrc7.cpp | 41 - higan/fc/cartridge/board/nes-axrom.cpp | 46 - higan/fc/cartridge/board/nes-bnrom.cpp | 47 - higan/fc/cartridge/board/nes-cnrom.cpp | 49 - higan/fc/cartridge/board/nes-exrom.cpp | 47 - higan/fc/cartridge/board/nes-fxrom.cpp | 86 -- higan/fc/cartridge/board/nes-gxrom.cpp | 56 - higan/fc/cartridge/board/nes-hkrom.cpp | 42 - higan/fc/cartridge/board/nes-nrom.cpp | 44 - higan/fc/cartridge/board/nes-pxrom.cpp | 92 -- higan/fc/cartridge/board/nes-sxrom.cpp | 95 -- higan/fc/cartridge/board/nes-txrom.cpp | 61 - higan/fc/cartridge/board/nes-uxrom.cpp | 50 - higan/fc/cartridge/board/sunsoft-5b.cpp | 217 ---- higan/fc/cartridge/cartridge.cpp | 74 -- higan/fc/cartridge/cartridge.hpp | 48 - higan/fc/cartridge/chip/chip.cpp | 17 - higan/fc/cartridge/chip/chip.hpp | 8 - higan/fc/cartridge/chip/mmc1.cpp | 126 -- higan/fc/cartridge/chip/mmc3.cpp | 181 --- higan/fc/cartridge/chip/mmc5.cpp | 493 -------- higan/fc/cartridge/chip/mmc6.cpp | 192 --- higan/fc/cartridge/chip/vrc1.cpp | 75 -- higan/fc/cartridge/chip/vrc2.cpp | 105 -- higan/fc/cartridge/chip/vrc3.cpp | 89 -- higan/fc/cartridge/chip/vrc4.cpp | 173 --- higan/fc/cartridge/chip/vrc6.cpp | 312 ----- higan/fc/cartridge/chip/vrc7.cpp | 144 --- higan/fc/cartridge/serialization.cpp | 4 - higan/fc/controller/controller.cpp | 58 - higan/fc/controller/controller.hpp | 45 - higan/fc/controller/gamepad/gamepad.cpp | 36 - higan/fc/controller/gamepad/gamepad.hpp | 22 - higan/fc/cpu/cpu.cpp | 44 - higan/fc/cpu/cpu.hpp | 58 - higan/fc/cpu/memory.cpp | 49 - higan/fc/cpu/serialization.cpp | 19 - higan/fc/cpu/timing.cpp | 64 - higan/fc/fc.hpp | 47 - higan/fc/interface/interface.cpp | 211 ---- higan/fc/interface/interface.hpp | 70 -- higan/fc/memory/memory.cpp | 34 - higan/fc/memory/memory.hpp | 6 - higan/fc/ppu/memory.cpp | 144 --- higan/fc/ppu/ppu.cpp | 72 -- higan/fc/ppu/ppu.hpp | 124 -- higan/fc/ppu/render.cpp | 211 ---- higan/fc/ppu/serialization.cpp | 64 - higan/fc/system/serialization.cpp | 60 - higan/fc/system/system.cpp | 91 -- higan/fc/system/system.hpp | 44 - higan/gba/GNUmakefile | 14 - higan/gba/apu/apu.cpp | 98 -- higan/gba/apu/apu.hpp | 178 --- higan/gba/apu/fifo.cpp | 33 - higan/gba/apu/io.cpp | 263 ----- higan/gba/apu/noise.cpp | 94 -- higan/gba/apu/sequencer.cpp | 109 -- higan/gba/apu/serialization.cpp | 110 -- higan/gba/apu/square.cpp | 30 - higan/gba/apu/square1.cpp | 105 -- higan/gba/apu/square2.cpp | 62 - higan/gba/apu/wave.cpp | 96 -- higan/gba/cartridge/cartridge.cpp | 156 --- higan/gba/cartridge/cartridge.hpp | 35 - higan/gba/cartridge/eeprom.cpp | 83 -- higan/gba/cartridge/flash.cpp | 87 -- higan/gba/cartridge/memory.hpp | 66 -- higan/gba/cartridge/mrom.cpp | 20 - higan/gba/cartridge/serialization.cpp | 42 - higan/gba/cartridge/sram.cpp | 10 - higan/gba/cpu/bus.cpp | 85 -- higan/gba/cpu/cpu.cpp | 112 -- higan/gba/cpu/cpu.hpp | 205 ---- higan/gba/cpu/dma.cpp | 76 -- higan/gba/cpu/io.cpp | 426 ------- higan/gba/cpu/keypad.cpp | 15 - higan/gba/cpu/memory.cpp | 55 - higan/gba/cpu/prefetch.cpp | 37 - higan/gba/cpu/serialization.cpp | 100 -- higan/gba/cpu/timer.cpp | 42 - higan/gba/gba.hpp | 50 - higan/gba/interface/interface.cpp | 167 --- higan/gba/interface/interface.hpp | 59 - higan/gba/memory/memory.cpp | 76 -- higan/gba/memory/memory.hpp | 16 - higan/gba/player/player.cpp | 130 -- higan/gba/player/player.hpp | 31 - higan/gba/player/serialization.cpp | 13 - higan/gba/ppu/background.cpp | 189 --- higan/gba/ppu/io.cpp | 385 ------ higan/gba/ppu/memory.cpp | 178 --- higan/gba/ppu/object.cpp | 95 -- higan/gba/ppu/ppu.cpp | 143 --- higan/gba/ppu/ppu.hpp | 229 ---- higan/gba/ppu/screen.cpp | 69 -- higan/gba/ppu/serialization.cpp | 124 -- higan/gba/ppu/window.cpp | 16 - higan/gba/system/bios.cpp | 27 - higan/gba/system/serialization.cpp | 61 - higan/gba/system/system.cpp | 76 -- higan/gba/system/system.hpp | 50 - higan/md/GNUmakefile | 16 - higan/md/apu/apu.cpp | 72 -- higan/md/apu/apu.hpp | 41 - higan/md/apu/bus.cpp | 53 - higan/md/apu/serialization.cpp | 13 - higan/md/cartridge/cartridge.cpp | 297 ----- higan/md/cartridge/cartridge.hpp | 87 -- higan/md/cartridge/serialization.cpp | 13 - .../md/controller/control-pad/control-pad.cpp | 29 - .../md/controller/control-pad/control-pad.hpp | 13 - higan/md/controller/controller.cpp | 73 -- higan/md/controller/controller.hpp | 34 - .../controller/fighting-pad/fighting-pad.cpp | 66 -- .../controller/fighting-pad/fighting-pad.hpp | 16 - higan/md/cpu/bus.cpp | 115 -- higan/md/cpu/cpu.cpp | 100 -- higan/md/cpu/cpu.hpp | 54 - higan/md/cpu/serialization.cpp | 14 - higan/md/interface/interface.cpp | 187 --- higan/md/interface/interface.hpp | 68 -- higan/md/md.hpp | 63 - higan/md/psg/io.cpp | 54 - higan/md/psg/noise.cpp | 24 - higan/md/psg/psg.cpp | 56 - higan/md/psg/psg.hpp | 55 - higan/md/psg/serialization.cpp | 28 - higan/md/psg/tone.cpp | 13 - higan/md/system/serialization.cpp | 63 - higan/md/system/system.cpp | 91 -- higan/md/system/system.hpp | 43 - higan/md/vdp/background.cpp | 80 -- higan/md/vdp/dma.cpp | 51 - higan/md/vdp/io.cpp | 335 ------ higan/md/vdp/memory.cpp | 38 - higan/md/vdp/render.cpp | 64 - higan/md/vdp/serialization.cpp | 112 -- higan/md/vdp/sprite.cpp | 105 -- higan/md/vdp/vdp.cpp | 106 -- higan/md/vdp/vdp.hpp | 266 ----- higan/md/ym2612/channel.cpp | 192 --- higan/md/ym2612/constants.cpp | 53 - higan/md/ym2612/io.cpp | 216 ---- higan/md/ym2612/serialization.cpp | 83 -- higan/md/ym2612/timer.cpp | 16 - higan/md/ym2612/ym2612.cpp | 190 --- higan/md/ym2612/ym2612.hpp | 173 --- higan/ms/GNUmakefile | 14 - higan/ms/cartridge/cartridge.cpp | 96 -- higan/ms/cartridge/cartridge.hpp | 52 - higan/ms/cartridge/mapper.cpp | 92 -- higan/ms/cartridge/serialization.cpp | 3 - higan/ms/controller/controller.cpp | 61 - higan/ms/controller/controller.hpp | 29 - higan/ms/controller/gamepad/gamepad.cpp | 13 - higan/ms/controller/gamepad/gamepad.hpp | 9 - higan/ms/controller/numberpad/numberpad.cpp | 33 - higan/ms/controller/numberpad/numberpad.hpp | 17 - higan/ms/cpu/coleco.cpp | 33 - higan/ms/cpu/cpu.cpp | 96 -- higan/ms/cpu/cpu.hpp | 56 - higan/ms/cpu/sega.cpp | 105 -- higan/ms/cpu/serialization.cpp | 10 - higan/ms/interface/colecovision.cpp | 102 -- higan/ms/interface/game-gear.cpp | 63 - higan/ms/interface/interface.cpp | 70 -- higan/ms/interface/interface.hpp | 139 --- higan/ms/interface/master-system.cpp | 94 -- higan/ms/interface/sc-3000.cpp | 103 -- higan/ms/interface/sg-1000.cpp | 103 -- higan/ms/ms.hpp | 55 - higan/ms/psg/io.cpp | 66 -- higan/ms/psg/noise.cpp | 27 - higan/ms/psg/psg.cpp | 62 - higan/ms/psg/psg.hpp | 62 - higan/ms/psg/serialization.cpp | 34 - higan/ms/psg/tone.cpp | 16 - higan/ms/system/serialization.cpp | 60 - higan/ms/system/system.cpp | 90 -- higan/ms/system/system.hpp | 51 - higan/ms/vdp/background.cpp | 117 -- higan/ms/vdp/io.cpp | 156 --- higan/ms/vdp/serialization.cpp | 60 - higan/ms/vdp/sprite.cpp | 133 --- higan/ms/vdp/vdp.cpp | 132 --- higan/ms/vdp/vdp.hpp | 149 --- higan/msx/GNUmakefile | 11 - higan/msx/cartridge/cartridge.cpp | 68 -- higan/msx/cartridge/cartridge.hpp | 35 - higan/msx/cartridge/serialization.cpp | 3 - higan/msx/cpu/cpu.cpp | 44 - higan/msx/cpu/cpu.hpp | 30 - higan/msx/cpu/memory.cpp | 65 - higan/msx/cpu/serialization.cpp | 5 - higan/msx/interface/interface.cpp | 127 -- higan/msx/interface/interface.hpp | 52 - higan/msx/msx.hpp | 52 - higan/msx/psg/psg.cpp | 29 - higan/msx/psg/psg.hpp | 17 - higan/msx/psg/serialization.cpp | 3 - higan/msx/system/serialization.cpp | 58 - higan/msx/system/system.cpp | 76 -- higan/msx/system/system.hpp | 50 - higan/msx/vdp/background.cpp | 73 -- higan/msx/vdp/io.cpp | 79 -- higan/msx/vdp/serialization.cpp | 3 - higan/msx/vdp/sprites.cpp | 58 - higan/msx/vdp/vdp.cpp | 55 - higan/msx/vdp/vdp.hpp | 78 -- higan/ngp/GNUmakefile | 12 - higan/ngp/apu/apu.cpp | 33 - higan/ngp/apu/apu.hpp | 22 - higan/ngp/apu/serialization.cpp | 5 - higan/ngp/cartridge/cartridge.cpp | 73 -- higan/ngp/cartridge/cartridge.hpp | 76 -- higan/ngp/cartridge/flash.cpp | 96 -- higan/ngp/cartridge/serialization.cpp | 10 - higan/ngp/cpu/cpu.cpp | 45 - higan/ngp/cpu/cpu.hpp | 29 - higan/ngp/cpu/memory.cpp | 27 - higan/ngp/cpu/serialization.cpp | 4 - higan/ngp/interface/interface.cpp | 101 -- higan/ngp/interface/interface.hpp | 57 - higan/ngp/interface/neo-geo-pocket-color.cpp | 11 - higan/ngp/interface/neo-geo-pocket.cpp | 11 - higan/ngp/ngp.hpp | 46 - higan/ngp/psg/psg.cpp | 29 - higan/ngp/psg/psg.hpp | 16 - higan/ngp/psg/serialization.cpp | 3 - higan/ngp/system/serialization.cpp | 59 - higan/ngp/system/system.cpp | 76 -- higan/ngp/system/system.hpp | 38 - higan/ngp/vpu/serialization.cpp | 3 - higan/ngp/vpu/vpu.cpp | 60 - higan/ngp/vpu/vpu.hpp | 26 - higan/out/.gitignore | 3 - higan/pce/GNUmakefile | 16 - higan/pce/cartridge/cartridge.cpp | 82 -- higan/pce/cartridge/cartridge.hpp | 34 - higan/pce/controller/controller.cpp | 54 - higan/pce/controller/controller.hpp | 24 - higan/pce/controller/gamepad/gamepad.cpp | 35 - higan/pce/controller/gamepad/gamepad.hpp | 13 - higan/pce/cpu/cpu.cpp | 48 - higan/pce/cpu/cpu.hpp | 72 -- higan/pce/cpu/io.cpp | 203 ---- higan/pce/cpu/irq.cpp | 27 - higan/pce/cpu/memory.cpp | 23 - higan/pce/cpu/serialization.cpp | 21 - higan/pce/cpu/timer.cpp | 16 - higan/pce/interface/interface.cpp | 130 -- higan/pce/interface/interface.hpp | 72 -- higan/pce/interface/pc-engine.cpp | 11 - higan/pce/interface/supergrafx.cpp | 11 - higan/pce/pce.hpp | 49 - higan/pce/psg/channel.cpp | 29 - higan/pce/psg/io.cpp | 81 -- higan/pce/psg/psg.cpp | 70 -- higan/pce/psg/psg.hpp | 63 - higan/pce/psg/serialization.cpp | 28 - higan/pce/system/serialization.cpp | 61 - higan/pce/system/system.cpp | 71 -- higan/pce/system/system.hpp | 39 - higan/pce/vce/io.cpp | 54 - higan/pce/vce/memory.cpp | 11 - higan/pce/vce/serialization.cpp | 13 - higan/pce/vce/vce.cpp | 69 -- higan/pce/vce/vce.hpp | 43 - higan/pce/vdc/background.cpp | 41 - higan/pce/vdc/dma.cpp | 39 - higan/pce/vdc/io.cpp | 204 ---- higan/pce/vdc/irq.cpp | 48 - higan/pce/vdc/memory.cpp | 17 - higan/pce/vdc/serialization.cpp | 83 -- higan/pce/vdc/sprite.cpp | 102 -- higan/pce/vdc/vdc.cpp | 115 -- higan/pce/vdc/vdc.hpp | 199 ---- higan/pce/vpc/serialization.cpp | 9 - higan/pce/vpc/vpc.cpp | 174 --- higan/pce/vpc/vpc.hpp | 25 - higan/sfc/dsp/brr.cpp | 61 - higan/sfc/dsp/counter.cpp | 48 - higan/sfc/dsp/dsp.cpp | 263 ----- higan/sfc/dsp/dsp.hpp | 177 --- higan/sfc/dsp/echo.cpp | 130 -- higan/sfc/dsp/envelope.cpp | 58 - higan/sfc/dsp/gaussian.cpp | 50 - higan/sfc/dsp/misc.cpp | 31 - higan/sfc/dsp/serialization.cpp | 61 - higan/sfc/dsp/voice.cpp | 170 --- higan/sfc/ppu-fast/mode7.cpp | 103 -- higan/sfc/ppu-fast/ppu.cpp | 135 --- higan/systems/ColecoVision.sys/manifest.bml | 1 - higan/systems/Famicom.sys/manifest.bml | 1 - .../systems/Game Boy Advance.sys/manifest.bml | 3 - higan/systems/Game Gear.sys/manifest.bml | 1 - higan/systems/MSX.sys/bios.rom | Bin 32768 -> 0 bytes higan/systems/MSX.sys/manifest.bml | 5 - higan/systems/Master System.sys/manifest.bml | 1 - higan/systems/Mega Drive.sys/manifest.bml | 3 - higan/systems/Mega Drive.sys/tmss.rom | Bin 2048 -> 0 bytes .../Neo Geo Pocket Color.sys/manifest.bml | 2 - higan/systems/Neo Geo Pocket.sys/manifest.bml | 2 - higan/systems/PC Engine.sys/manifest.bml | 1 - .../Pocket Challenge V2.sys/manifest.bml | 2 - higan/systems/SC-3000.sys/manifest.bml | 1 - higan/systems/SG-1000.sys/manifest.bml | 1 - higan/systems/SuperGrafx.sys/manifest.bml | 1 - .../systems/WonderSwan Color.sys/manifest.bml | 2 - higan/systems/WonderSwan.sys/manifest.bml | 2 - higan/target-bsnes/settings/emulator.cpp | 82 -- higan/target-higan/GNUmakefile | 68 -- higan/target-higan/higan.cpp | 24 - higan/target-higan/higan.hpp | 23 - higan/target-higan/input/hotkeys.cpp | 115 -- higan/target-higan/input/input.cpp | 299 ----- higan/target-higan/input/input.hpp | 91 -- .../presentation/presentation.cpp | 524 --------- .../presentation/presentation.hpp | 97 -- higan/target-higan/program/game.cpp | 78 -- higan/target-higan/program/platform.cpp | 124 -- higan/target-higan/program/program.cpp | 162 --- higan/target-higan/program/program.hpp | 60 - higan/target-higan/program/state.cpp | 29 - higan/target-higan/program/utility.cpp | 170 --- higan/target-higan/resource/GNUmakefile | 6 - higan/target-higan/resource/higan.Manifest | 14 - higan/target-higan/resource/higan.desktop | 8 - higan/target-higan/resource/higan.ico | Bin 31258 -> 0 bytes higan/target-higan/resource/higan.plist | 18 - higan/target-higan/resource/higan.png | Bin 12872 -> 0 bytes higan/target-higan/resource/higan.rc | 2 - higan/target-higan/resource/higan.svg | 84 -- higan/target-higan/resource/icon.png | Bin 3088 -> 0 bytes higan/target-higan/resource/logo.png | Bin 25128 -> 0 bytes higan/target-higan/resource/resource.bml | 3 - higan/target-higan/resource/resource.cpp | 891 -------------- higan/target-higan/resource/resource.hpp | 4 - higan/target-higan/settings/advanced.cpp | 48 - higan/target-higan/settings/audio.cpp | 81 -- higan/target-higan/settings/hotkeys.cpp | 70 -- higan/target-higan/settings/input.cpp | 158 --- higan/target-higan/settings/settings.cpp | 104 -- higan/target-higan/settings/settings.hpp | 207 ---- .../settings/system-properties.cpp | 71 -- higan/target-higan/settings/systems.cpp | 124 -- higan/target-higan/settings/video.cpp | 58 - higan/target-higan/tools/cheat-database.cpp | 56 - higan/target-higan/tools/cheat-editor.cpp | 153 --- higan/target-higan/tools/game-notes.cpp | 22 - higan/target-higan/tools/manifest-viewer.cpp | 12 - higan/target-higan/tools/state-manager.cpp | 119 -- higan/target-higan/tools/tools.cpp | 31 - higan/target-higan/tools/tools.hpp | 109 -- higan/ws/GNUmakefile | 14 - higan/ws/apu/apu.cpp | 160 --- higan/ws/apu/apu.hpp | 215 ---- higan/ws/apu/channel1.cpp | 8 - higan/ws/apu/channel2.cpp | 12 - higan/ws/apu/channel3.cpp | 15 - higan/ws/apu/channel4.cpp | 27 - higan/ws/apu/channel5.cpp | 12 - higan/ws/apu/dma.cpp | 29 - higan/ws/apu/io.cpp | 248 ---- higan/ws/apu/serialization.cpp | 82 -- higan/ws/cartridge/cartridge.cpp | 157 --- higan/ws/cartridge/cartridge.hpp | 97 -- higan/ws/cartridge/io.cpp | 75 -- higan/ws/cartridge/memory.cpp | 27 - higan/ws/cartridge/rtc.cpp | 150 --- higan/ws/cartridge/serialization.cpp | 22 - higan/ws/cpu/cpu.cpp | 63 - higan/ws/cpu/cpu.hpp | 78 -- higan/ws/cpu/dma.cpp | 29 - higan/ws/cpu/interrupt.cpp | 20 - higan/ws/cpu/io.cpp | 155 --- higan/ws/cpu/serialization.cpp | 19 - higan/ws/eeprom/eeprom.cpp | 136 --- higan/ws/eeprom/eeprom.hpp | 52 - higan/ws/eeprom/serialization.cpp | 12 - higan/ws/interface/interface.cpp | 164 --- higan/ws/interface/interface.hpp | 78 -- higan/ws/interface/pocket-challenge-v2.cpp | 11 - higan/ws/interface/wonderswan-color.cpp | 11 - higan/ws/interface/wonderswan.cpp | 11 - higan/ws/memory/memory.cpp | 60 - higan/ws/memory/memory.hpp | 53 - higan/ws/ppu/io.cpp | 281 ----- higan/ws/ppu/latch.cpp | 48 - higan/ws/ppu/ppu.cpp | 104 -- higan/ws/ppu/ppu.hpp | 193 --- higan/ws/ppu/render.cpp | 115 -- higan/ws/ppu/serialization.cpp | 83 -- higan/ws/ppu/video.cpp | 47 - higan/ws/system/io.cpp | 44 - higan/ws/system/serialization.cpp | 65 - higan/ws/system/system.cpp | 129 -- higan/ws/system/system.hpp | 66 -- higan/ws/ws.hpp | 50 - icarus/GNUmakefile | 63 - ruby/audio/waveout.cpp | 21 +- 884 files changed, 2917 insertions(+), 32069 deletions(-) rename {higan => bsnes}/GNUmakefile (57%) rename {higan => bsnes}/emulator/audio/audio.cpp (100%) rename {higan => bsnes}/emulator/audio/audio.hpp (100%) rename {higan => bsnes}/emulator/audio/stream.cpp (100%) rename {higan => bsnes}/emulator/cheat.hpp (100%) rename {higan => bsnes}/emulator/emulator.cpp (100%) rename {higan => bsnes}/emulator/emulator.hpp (95%) rename {higan => bsnes}/emulator/game.hpp (100%) rename {higan => bsnes}/emulator/interface.hpp (96%) rename {higan => bsnes}/emulator/memory/memory.hpp (100%) rename {higan => bsnes}/emulator/memory/readable.hpp (100%) rename {higan => bsnes}/emulator/memory/writable.hpp (100%) rename {higan => bsnes}/emulator/platform.hpp (100%) rename {higan => bsnes}/emulator/random.hpp (100%) rename {higan => bsnes}/emulator/resource/GNUmakefile (100%) rename {higan => bsnes}/emulator/resource/resource.bml (100%) rename {higan => bsnes}/emulator/resource/resource.cpp (100%) rename {higan => bsnes}/emulator/resource/resource.hpp (100%) rename {higan => bsnes}/emulator/resource/sprite/crosshair-blue.png (100%) rename {higan => bsnes}/emulator/resource/sprite/crosshair-green.png (100%) rename {higan => bsnes}/emulator/resource/sprite/crosshair-red.png (100%) rename {higan => bsnes}/emulator/scheduler.hpp (100%) rename {higan => bsnes}/emulator/thread.hpp (100%) rename {higan => bsnes}/emulator/types.hpp (100%) rename {higan => bsnes}/emulator/video/sprite.cpp (100%) rename {higan => bsnes}/emulator/video/video.cpp (100%) rename {higan => bsnes}/emulator/video/video.hpp (100%) rename {higan => bsnes}/gb/GNUmakefile (100%) rename {higan => bsnes}/gb/apu/apu.cpp (100%) rename {higan => bsnes}/gb/apu/apu.hpp (100%) rename {higan => bsnes}/gb/apu/noise.cpp (100%) rename {higan => bsnes}/gb/apu/sequencer.cpp (100%) rename {higan => bsnes}/gb/apu/serialization.cpp (100%) rename {higan => bsnes}/gb/apu/square1.cpp (100%) rename {higan => bsnes}/gb/apu/square2.cpp (100%) rename {higan => bsnes}/gb/apu/wave.cpp (100%) rename {higan => bsnes}/gb/cartridge/cartridge.cpp (100%) rename {higan => bsnes}/gb/cartridge/cartridge.hpp (100%) rename {higan => bsnes}/gb/cartridge/huc1/huc1.cpp (100%) rename {higan => bsnes}/gb/cartridge/huc1/huc1.hpp (100%) rename {higan => bsnes}/gb/cartridge/huc3/huc3.cpp (100%) rename {higan => bsnes}/gb/cartridge/huc3/huc3.hpp (100%) rename {higan => bsnes}/gb/cartridge/mbc0/mbc0.cpp (100%) rename {higan => bsnes}/gb/cartridge/mbc0/mbc0.hpp (100%) rename {higan => bsnes}/gb/cartridge/mbc1/mbc1.cpp (100%) rename {higan => bsnes}/gb/cartridge/mbc1/mbc1.hpp (100%) rename {higan => bsnes}/gb/cartridge/mbc1m/mbc1m.cpp (100%) rename {higan => bsnes}/gb/cartridge/mbc1m/mbc1m.hpp (100%) rename {higan => bsnes}/gb/cartridge/mbc2/mbc2.cpp (100%) rename {higan => bsnes}/gb/cartridge/mbc2/mbc2.hpp (100%) rename {higan => bsnes}/gb/cartridge/mbc3/mbc3.cpp (100%) rename {higan => bsnes}/gb/cartridge/mbc3/mbc3.hpp (100%) rename {higan => bsnes}/gb/cartridge/mbc5/mbc5.cpp (100%) rename {higan => bsnes}/gb/cartridge/mbc5/mbc5.hpp (100%) rename {higan => bsnes}/gb/cartridge/mbc6/mbc6.cpp (100%) rename {higan => bsnes}/gb/cartridge/mbc6/mbc6.hpp (100%) rename {higan => bsnes}/gb/cartridge/mbc7/eeprom.cpp (100%) rename {higan => bsnes}/gb/cartridge/mbc7/mbc7.cpp (100%) rename {higan => bsnes}/gb/cartridge/mbc7/mbc7.hpp (100%) rename {higan => bsnes}/gb/cartridge/mbc7/serialization.cpp (100%) rename {higan => bsnes}/gb/cartridge/mmm01/mmm01.cpp (100%) rename {higan => bsnes}/gb/cartridge/mmm01/mmm01.hpp (100%) rename {higan => bsnes}/gb/cartridge/serialization.cpp (100%) rename {higan => bsnes}/gb/cartridge/tama/tama.cpp (100%) rename {higan => bsnes}/gb/cartridge/tama/tama.hpp (100%) rename {higan => bsnes}/gb/cpu/cpu.cpp (100%) rename {higan => bsnes}/gb/cpu/cpu.hpp (100%) rename {higan => bsnes}/gb/cpu/io.cpp (100%) rename {higan => bsnes}/gb/cpu/memory.cpp (100%) rename {higan => bsnes}/gb/cpu/serialization.cpp (100%) rename {higan => bsnes}/gb/cpu/timing.cpp (100%) rename {higan => bsnes}/gb/gb.hpp (100%) rename {higan => bsnes}/gb/interface/game-boy-color.cpp (100%) rename {higan => bsnes}/gb/interface/game-boy.cpp (100%) rename {higan => bsnes}/gb/interface/interface.cpp (100%) rename {higan => bsnes}/gb/interface/interface.hpp (98%) rename {higan => bsnes}/gb/memory/memory.cpp (100%) rename {higan => bsnes}/gb/memory/memory.hpp (100%) rename {higan => bsnes}/gb/ppu/cgb.cpp (100%) rename {higan => bsnes}/gb/ppu/dmg.cpp (100%) rename {higan => bsnes}/gb/ppu/io.cpp (100%) rename {higan => bsnes}/gb/ppu/ppu.cpp (100%) rename {higan => bsnes}/gb/ppu/ppu.hpp (100%) rename {higan => bsnes}/gb/ppu/serialization.cpp (100%) rename {higan => bsnes}/gb/system/serialization.cpp (100%) rename {higan => bsnes}/gb/system/system.cpp (100%) rename {higan => bsnes}/gb/system/system.hpp (100%) rename {higan => bsnes}/obj/.gitignore (100%) create mode 100644 bsnes/out/.gitignore rename {higan => bsnes}/processor/GNUmakefile (100%) rename {higan => bsnes}/processor/arm7tdmi/algorithms.cpp (100%) rename {higan => bsnes}/processor/arm7tdmi/arm7tdmi.cpp (100%) rename {higan => bsnes}/processor/arm7tdmi/arm7tdmi.hpp (100%) rename {higan => bsnes}/processor/arm7tdmi/disassembler.cpp (100%) rename {higan => bsnes}/processor/arm7tdmi/instruction.cpp (100%) rename {higan => bsnes}/processor/arm7tdmi/instructions-arm.cpp (100%) rename {higan => bsnes}/processor/arm7tdmi/instructions-thumb.cpp (100%) rename {higan => bsnes}/processor/arm7tdmi/memory.cpp (100%) rename {higan => bsnes}/processor/arm7tdmi/registers.cpp (100%) rename {higan => bsnes}/processor/arm7tdmi/serialization.cpp (100%) rename {higan => bsnes}/processor/gsu/disassembler.cpp (100%) rename {higan => bsnes}/processor/gsu/gsu.cpp (100%) rename {higan => bsnes}/processor/gsu/gsu.hpp (100%) rename {higan => bsnes}/processor/gsu/instruction.cpp (100%) rename {higan => bsnes}/processor/gsu/instructions.cpp (100%) rename {higan => bsnes}/processor/gsu/registers.hpp (100%) rename {higan => bsnes}/processor/gsu/serialization.cpp (100%) rename {higan => bsnes}/processor/hg51b/hg51b.cpp (100%) rename {higan => bsnes}/processor/hg51b/hg51b.hpp (100%) rename {higan => bsnes}/processor/hg51b/instruction.cpp (100%) rename {higan => bsnes}/processor/hg51b/instructions.cpp (100%) rename {higan => bsnes}/processor/hg51b/registers.cpp (100%) rename {higan => bsnes}/processor/hg51b/serialization.cpp (100%) rename {higan => bsnes}/processor/huc6280/algorithms.cpp (100%) rename {higan => bsnes}/processor/huc6280/disassembler.cpp (100%) rename {higan => bsnes}/processor/huc6280/huc6280.cpp (100%) rename {higan => bsnes}/processor/huc6280/huc6280.hpp (100%) rename {higan => bsnes}/processor/huc6280/instruction.cpp (100%) rename {higan => bsnes}/processor/huc6280/instructions.cpp (100%) rename {higan => bsnes}/processor/huc6280/memory.cpp (100%) rename {higan => bsnes}/processor/huc6280/serialization.cpp (100%) rename {higan => bsnes}/processor/m68k/disassembler.cpp (100%) rename {higan => bsnes}/processor/m68k/effective-address.cpp (100%) rename {higan => bsnes}/processor/m68k/instruction.cpp (100%) rename {higan => bsnes}/processor/m68k/instructions.cpp (100%) rename {higan => bsnes}/processor/m68k/m68k.cpp (100%) rename {higan => bsnes}/processor/m68k/m68k.hpp (100%) rename {higan => bsnes}/processor/m68k/memory.cpp (100%) rename {higan => bsnes}/processor/m68k/registers.cpp (100%) rename {higan => bsnes}/processor/m68k/serialization.cpp (100%) rename {higan => bsnes}/processor/mos6502/algorithms.cpp (100%) rename {higan => bsnes}/processor/mos6502/disassembler.cpp (100%) rename {higan => bsnes}/processor/mos6502/instruction.cpp (100%) rename {higan => bsnes}/processor/mos6502/instructions.cpp (100%) rename {higan => bsnes}/processor/mos6502/memory.cpp (100%) rename {higan => bsnes}/processor/mos6502/mos6502.cpp (100%) rename {higan => bsnes}/processor/mos6502/mos6502.hpp (100%) rename {higan => bsnes}/processor/mos6502/serialization.cpp (100%) rename {higan => bsnes}/processor/processor.hpp (100%) rename {higan => bsnes}/processor/sm83/algorithms.cpp (100%) rename {higan => bsnes}/processor/sm83/disassembler.cpp (100%) rename {higan => bsnes}/processor/sm83/instruction.cpp (100%) rename {higan => bsnes}/processor/sm83/instructions.cpp (100%) rename {higan => bsnes}/processor/sm83/memory.cpp (100%) rename {higan => bsnes}/processor/sm83/registers.cpp (100%) rename {higan => bsnes}/processor/sm83/serialization.cpp (100%) rename {higan => bsnes}/processor/sm83/sm83.cpp (100%) rename {higan => bsnes}/processor/sm83/sm83.hpp (100%) rename {higan => bsnes}/processor/spc700/algorithms.cpp (100%) rename {higan => bsnes}/processor/spc700/disassembler.cpp (100%) rename {higan => bsnes}/processor/spc700/instruction.cpp (100%) rename {higan => bsnes}/processor/spc700/instructions.cpp (100%) rename {higan => bsnes}/processor/spc700/memory.cpp (100%) rename {higan => bsnes}/processor/spc700/serialization.cpp (100%) rename {higan => bsnes}/processor/spc700/spc700.cpp (100%) rename {higan => bsnes}/processor/spc700/spc700.hpp (100%) rename {higan => bsnes}/processor/tlcs900h/algorithms.cpp (100%) rename {higan => bsnes}/processor/tlcs900h/conditions.cpp (100%) rename {higan => bsnes}/processor/tlcs900h/control-registers.cpp (100%) rename {higan => bsnes}/processor/tlcs900h/disassembler.cpp (100%) rename {higan => bsnes}/processor/tlcs900h/instruction.cpp (100%) rename {higan => bsnes}/processor/tlcs900h/instructions.cpp (100%) rename {higan => bsnes}/processor/tlcs900h/memory.cpp (100%) rename {higan => bsnes}/processor/tlcs900h/registers.cpp (100%) rename {higan => bsnes}/processor/tlcs900h/serialization.cpp (100%) rename {higan => bsnes}/processor/tlcs900h/tlcs900h.cpp (100%) rename {higan => bsnes}/processor/tlcs900h/tlcs900h.hpp (100%) rename {higan => bsnes}/processor/upd96050/disassembler.cpp (100%) rename {higan => bsnes}/processor/upd96050/instructions.cpp (100%) rename {higan => bsnes}/processor/upd96050/memory.cpp (100%) rename {higan => bsnes}/processor/upd96050/serialization.cpp (100%) rename {higan => bsnes}/processor/upd96050/upd96050.cpp (100%) rename {higan => bsnes}/processor/upd96050/upd96050.hpp (100%) rename {higan => bsnes}/processor/v30mz/algorithms.cpp (100%) rename {higan => bsnes}/processor/v30mz/disassembler-old.cpp (100%) rename {higan => bsnes}/processor/v30mz/disassembler.cpp (100%) rename {higan => bsnes}/processor/v30mz/instruction.cpp (100%) rename {higan => bsnes}/processor/v30mz/instructions-adjust.cpp (100%) rename {higan => bsnes}/processor/v30mz/instructions-alu.cpp (100%) rename {higan => bsnes}/processor/v30mz/instructions-exec.cpp (100%) rename {higan => bsnes}/processor/v30mz/instructions-flag.cpp (100%) rename {higan => bsnes}/processor/v30mz/instructions-group.cpp (100%) rename {higan => bsnes}/processor/v30mz/instructions-misc.cpp (100%) rename {higan => bsnes}/processor/v30mz/instructions-move.cpp (100%) rename {higan => bsnes}/processor/v30mz/instructions-string.cpp (100%) rename {higan => bsnes}/processor/v30mz/memory.cpp (100%) rename {higan => bsnes}/processor/v30mz/modrm.cpp (100%) rename {higan => bsnes}/processor/v30mz/registers.cpp (100%) rename {higan => bsnes}/processor/v30mz/serialization.cpp (100%) rename {higan => bsnes}/processor/v30mz/v30mz.cpp (100%) rename {higan => bsnes}/processor/v30mz/v30mz.hpp (100%) rename {higan => bsnes}/processor/wdc65816/algorithms.cpp (100%) rename {higan => bsnes}/processor/wdc65816/disassembler.cpp (100%) rename {higan => bsnes}/processor/wdc65816/instruction.cpp (100%) rename {higan => bsnes}/processor/wdc65816/instruction.hpp (100%) rename {higan => bsnes}/processor/wdc65816/instructions-modify.cpp (100%) rename {higan => bsnes}/processor/wdc65816/instructions-other.cpp (100%) rename {higan => bsnes}/processor/wdc65816/instructions-pc.cpp (100%) rename {higan => bsnes}/processor/wdc65816/instructions-read.cpp (100%) rename {higan => bsnes}/processor/wdc65816/instructions-write.cpp (100%) rename {higan => bsnes}/processor/wdc65816/memory.cpp (100%) rename {higan => bsnes}/processor/wdc65816/serialization.cpp (100%) rename {higan => bsnes}/processor/wdc65816/wdc65816.cpp (100%) rename {higan => bsnes}/processor/wdc65816/wdc65816.hpp (100%) rename {higan => bsnes}/processor/z80/algorithms.cpp (100%) rename {higan => bsnes}/processor/z80/disassembler.cpp (100%) rename {higan => bsnes}/processor/z80/instruction.cpp (100%) rename {higan => bsnes}/processor/z80/instructions.cpp (100%) rename {higan => bsnes}/processor/z80/memory.cpp (100%) rename {higan => bsnes}/processor/z80/registers.cpp (100%) rename {higan => bsnes}/processor/z80/serialization.cpp (100%) rename {higan => bsnes}/processor/z80/z80.cpp (100%) rename {higan => bsnes}/processor/z80/z80.hpp (100%) rename {higan => bsnes}/sfc/GNUmakefile (100%) rename {higan => bsnes}/sfc/cartridge/cartridge.cpp (99%) rename {higan => bsnes}/sfc/cartridge/cartridge.hpp (100%) rename {higan => bsnes}/sfc/cartridge/load.cpp (100%) rename {higan => bsnes}/sfc/cartridge/save.cpp (100%) rename {higan => bsnes}/sfc/cartridge/serialization.cpp (100%) rename {higan => bsnes}/sfc/controller/controller.cpp (100%) rename {higan => bsnes}/sfc/controller/controller.hpp (100%) rename {higan => bsnes}/sfc/controller/gamepad/gamepad.cpp (100%) rename {higan => bsnes}/sfc/controller/gamepad/gamepad.hpp (100%) rename {higan => bsnes}/sfc/controller/justifier/justifier.cpp (100%) rename {higan => bsnes}/sfc/controller/justifier/justifier.hpp (100%) rename {higan => bsnes}/sfc/controller/mouse/mouse.cpp (100%) rename {higan => bsnes}/sfc/controller/mouse/mouse.hpp (100%) rename {higan => bsnes}/sfc/controller/super-multitap/super-multitap.cpp (100%) rename {higan => bsnes}/sfc/controller/super-multitap/super-multitap.hpp (100%) rename {higan => bsnes}/sfc/controller/super-scope/super-scope.cpp (100%) rename {higan => bsnes}/sfc/controller/super-scope/super-scope.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/armdsp/armdsp.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/armdsp/armdsp.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/armdsp/memory.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/armdsp/registers.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/armdsp/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/coprocessor.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/cx4/cx4.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/cx4/cx4.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/cx4/data.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/cx4/functions.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/cx4/oam.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/cx4/opcodes.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/cx4/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/dip/dip.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/dip/dip.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/dip/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/dsp1/dsp1.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/dsp1/dsp1.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/dsp1/dsp1emu.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/dsp1/dsp1emu.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/dsp1/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/dsp2/dsp2.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/dsp2/dsp2.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/dsp2/opcodes.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/dsp2/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/dsp4/dsp4.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/dsp4/dsp4.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/dsp4/dsp4emu.c (100%) rename {higan => bsnes}/sfc/coprocessor/dsp4/dsp4emu.h (100%) rename {higan => bsnes}/sfc/coprocessor/dsp4/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/epsonrtc/epsonrtc.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/epsonrtc/epsonrtc.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/epsonrtc/memory.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/epsonrtc/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/epsonrtc/time.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/event/event.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/event/event.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/event/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/hitachidsp/hitachidsp.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/hitachidsp/hitachidsp.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/hitachidsp/memory.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/hitachidsp/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/icd/icd.cpp (98%) rename {higan => bsnes}/sfc/coprocessor/icd/icd.hpp (80%) rename {higan => bsnes}/sfc/coprocessor/icd/interface.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/icd/io.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/icd/platform.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/icd/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/mcc/mcc.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/mcc/mcc.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/mcc/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/msu1/msu1.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/msu1/msu1.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/msu1/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/necdsp/necdsp.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/necdsp/necdsp.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/necdsp/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/obc1/obc1.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/obc1/obc1.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/obc1/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sa1/bwram.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sa1/dma.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sa1/io.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sa1/iram.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sa1/memory.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sa1/rom.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sa1/sa1.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sa1/sa1.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/sa1/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sdd1/decompressor.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sdd1/decompressor.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/sdd1/sdd1.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sdd1/sdd1.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/sdd1/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sharprtc/memory.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sharprtc/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sharprtc/sharprtc.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/sharprtc/sharprtc.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/sharprtc/time.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/spc7110/alu.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/spc7110/data.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/spc7110/dcu.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/spc7110/decompressor.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/spc7110/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/spc7110/spc7110.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/spc7110/spc7110.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/st0010/data.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/st0010/opcodes.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/st0010/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/st0010/st0010.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/st0010/st0010.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/superfx/bus.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/superfx/core.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/superfx/io.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/superfx/memory.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/superfx/serialization.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/superfx/superfx.cpp (100%) rename {higan => bsnes}/sfc/coprocessor/superfx/superfx.hpp (100%) rename {higan => bsnes}/sfc/coprocessor/superfx/timing.cpp (100%) rename {higan => bsnes}/sfc/cpu/cpu.cpp (100%) rename {higan => bsnes}/sfc/cpu/cpu.hpp (99%) rename {higan => bsnes}/sfc/cpu/dma.cpp (100%) rename {higan => bsnes}/sfc/cpu/io.cpp (100%) rename {higan => bsnes}/sfc/cpu/irq.cpp (100%) rename {higan => bsnes}/sfc/cpu/memory.cpp (98%) rename {higan => bsnes}/sfc/cpu/serialization.cpp (100%) rename {higan => bsnes}/sfc/cpu/timing.cpp (86%) create mode 100644 bsnes/sfc/dsp/SPC_DSP.cpp create mode 100644 bsnes/sfc/dsp/SPC_DSP.h create mode 100644 bsnes/sfc/dsp/blargg_common.h create mode 100644 bsnes/sfc/dsp/blargg_config.h create mode 100644 bsnes/sfc/dsp/blargg_endian.h create mode 100644 bsnes/sfc/dsp/blargg_source.h create mode 100644 bsnes/sfc/dsp/dsp.cpp create mode 100644 bsnes/sfc/dsp/dsp.hpp create mode 100644 bsnes/sfc/dsp/serialization.cpp rename {higan => bsnes}/sfc/expansion/21fx/21fx.cpp (100%) rename {higan => bsnes}/sfc/expansion/21fx/21fx.hpp (100%) rename {higan => bsnes}/sfc/expansion/expansion.cpp (100%) rename {higan => bsnes}/sfc/expansion/expansion.hpp (100%) rename {higan => bsnes}/sfc/expansion/satellaview/satellaview.cpp (100%) rename {higan => bsnes}/sfc/expansion/satellaview/satellaview.hpp (100%) rename {higan => bsnes}/sfc/interface/configuration.cpp (78%) rename {higan => bsnes}/sfc/interface/configuration.hpp (75%) rename {higan => bsnes}/sfc/interface/interface.cpp (97%) rename {higan => bsnes}/sfc/interface/interface.hpp (95%) rename {higan => bsnes}/sfc/memory/memory-inline.hpp (100%) rename {higan => bsnes}/sfc/memory/memory.cpp (100%) rename {higan => bsnes}/sfc/memory/memory.hpp (100%) rename {higan => bsnes}/sfc/memory/protectable.hpp (100%) rename {higan => bsnes}/sfc/memory/readable.hpp (100%) rename {higan => bsnes}/sfc/memory/writable.hpp (100%) rename {higan => bsnes}/sfc/ppu-fast/background.cpp (83%) rename {higan => bsnes}/sfc/ppu-fast/io.cpp (88%) rename {higan => bsnes}/sfc/ppu-fast/line.cpp (54%) create mode 100644 bsnes/sfc/ppu-fast/mode7.cpp create mode 100644 bsnes/sfc/ppu-fast/mode7hd.cpp create mode 100644 bsnes/sfc/ppu-fast/mode7hires.cpp rename {higan => bsnes}/sfc/ppu-fast/object.cpp (83%) create mode 100644 bsnes/sfc/ppu-fast/ppu.cpp rename {higan => bsnes}/sfc/ppu-fast/ppu.hpp (65%) rename {higan => bsnes}/sfc/ppu-fast/serialization.cpp (79%) rename {higan => bsnes}/sfc/ppu-fast/window.cpp (91%) rename {higan => bsnes}/sfc/ppu/background.cpp (100%) rename {higan => bsnes}/sfc/ppu/background.hpp (100%) rename {higan => bsnes}/sfc/ppu/counter/counter-inline.hpp (100%) rename {higan => bsnes}/sfc/ppu/counter/counter.hpp (100%) rename {higan => bsnes}/sfc/ppu/counter/serialization.cpp (100%) rename {higan => bsnes}/sfc/ppu/io.cpp (100%) rename {higan => bsnes}/sfc/ppu/mode7.cpp (100%) rename {higan => bsnes}/sfc/ppu/oam.cpp (100%) rename {higan => bsnes}/sfc/ppu/object.cpp (100%) rename {higan => bsnes}/sfc/ppu/object.hpp (100%) rename {higan => bsnes}/sfc/ppu/ppu.cpp (100%) rename {higan => bsnes}/sfc/ppu/ppu.hpp (79%) rename {higan => bsnes}/sfc/ppu/screen.cpp (100%) rename {higan => bsnes}/sfc/ppu/screen.hpp (100%) rename {higan => bsnes}/sfc/ppu/serialization.cpp (100%) rename {higan => bsnes}/sfc/ppu/window.cpp (100%) rename {higan => bsnes}/sfc/ppu/window.hpp (100%) rename {higan => bsnes}/sfc/sfc.hpp (97%) rename {higan => bsnes}/sfc/slot/bsmemory/bsmemory.cpp (100%) rename {higan => bsnes}/sfc/slot/bsmemory/bsmemory.hpp (100%) rename {higan => bsnes}/sfc/slot/bsmemory/serialization.cpp (100%) rename {higan => bsnes}/sfc/slot/slot.hpp (100%) rename {higan => bsnes}/sfc/slot/sufamiturbo/serialization.cpp (100%) rename {higan => bsnes}/sfc/slot/sufamiturbo/sufamiturbo.cpp (100%) rename {higan => bsnes}/sfc/slot/sufamiturbo/sufamiturbo.hpp (100%) rename {higan => bsnes}/sfc/smp/io.cpp (100%) rename {higan => bsnes}/sfc/smp/memory.cpp (98%) rename {higan => bsnes}/sfc/smp/serialization.cpp (100%) rename {higan => bsnes}/sfc/smp/smp.cpp (100%) rename {higan => bsnes}/sfc/smp/smp.hpp (94%) rename {higan => bsnes}/sfc/smp/timing.cpp (75%) rename {higan => bsnes}/sfc/system/serialization.cpp (97%) rename {higan => bsnes}/sfc/system/system.cpp (97%) rename {higan => bsnes}/sfc/system/system.hpp (93%) rename {higan => bsnes}/systems/Game Boy Color.sys/boot.rom (100%) rename {higan => bsnes}/systems/Game Boy Color.sys/manifest.bml (100%) rename {higan => bsnes}/systems/Game Boy.sys/boot.rom (100%) rename {higan => bsnes}/systems/Game Boy.sys/manifest.bml (100%) rename {higan => bsnes}/systems/Super Famicom.sys/boards.bml (100%) rename {higan => bsnes}/systems/Super Famicom.sys/ipl.rom (100%) rename {higan => bsnes}/target-bsnes/GNUmakefile (100%) rename {higan => bsnes}/target-bsnes/bsnes.cpp (96%) rename {higan => bsnes}/target-bsnes/bsnes.hpp (100%) rename {higan => bsnes}/target-bsnes/input/hotkeys.cpp (97%) rename {higan => bsnes}/target-bsnes/input/input.cpp (100%) rename {higan => bsnes}/target-bsnes/input/input.hpp (100%) rename {higan => bsnes}/target-bsnes/presentation/presentation.cpp (98%) rename {higan => bsnes}/target-bsnes/presentation/presentation.hpp (100%) rename {higan => bsnes}/target-bsnes/program/audio.cpp (100%) rename {higan => bsnes}/target-bsnes/program/game-pak.cpp (100%) rename {higan => bsnes}/target-bsnes/program/game-rom.cpp (100%) rename {higan => bsnes}/target-bsnes/program/game.cpp (100%) rename {higan => bsnes}/target-bsnes/program/hacks.cpp (79%) rename {higan => bsnes}/target-bsnes/program/input.cpp (100%) rename {higan => bsnes}/target-bsnes/program/patch.cpp (100%) rename {higan => bsnes}/target-bsnes/program/paths.cpp (100%) rename {higan => bsnes}/target-bsnes/program/platform.cpp (90%) rename {higan => bsnes}/target-bsnes/program/program.cpp (89%) rename {higan => bsnes}/target-bsnes/program/program.hpp (100%) rename {higan => bsnes}/target-bsnes/program/states.cpp (100%) rename {higan => bsnes}/target-bsnes/program/utility.cpp (100%) rename {higan => bsnes}/target-bsnes/program/video.cpp (100%) rename {higan => bsnes}/target-bsnes/resource/GNUmakefile (100%) rename {higan => bsnes}/target-bsnes/resource/bsnes.Manifest (100%) rename {higan => bsnes}/target-bsnes/resource/bsnes.desktop (100%) rename {higan => bsnes}/target-bsnes/resource/bsnes.ico (100%) rename {higan => bsnes}/target-bsnes/resource/bsnes.plist (100%) rename {higan => bsnes}/target-bsnes/resource/bsnes.png (100%) rename {higan => bsnes}/target-bsnes/resource/bsnes.rc (100%) rename {higan => bsnes}/target-bsnes/resource/bsnes.svg (100%) rename {higan => bsnes}/target-bsnes/resource/icon.png (100%) rename {higan => bsnes}/target-bsnes/resource/locales/japanese.bml (100%) rename {higan => bsnes}/target-bsnes/resource/logo.png (100%) rename {higan => bsnes}/target-bsnes/resource/resource.bml (100%) rename {higan => bsnes}/target-bsnes/resource/resource.cpp (100%) rename {higan => bsnes}/target-bsnes/resource/resource.hpp (100%) rename {higan => bsnes}/target-bsnes/settings/audio.cpp (97%) rename {higan => bsnes}/target-bsnes/settings/drivers.cpp (98%) create mode 100644 bsnes/target-bsnes/settings/emulator.cpp rename {higan => bsnes}/target-bsnes/settings/hotkeys.cpp (100%) rename {higan => bsnes}/target-bsnes/settings/input.cpp (100%) rename {higan => bsnes}/target-bsnes/settings/paths.cpp (100%) rename {higan => bsnes}/target-bsnes/settings/settings.cpp (89%) rename {higan => bsnes}/target-bsnes/settings/settings.hpp (91%) rename {higan => bsnes}/target-bsnes/settings/video.cpp (100%) rename {higan => bsnes}/target-bsnes/tools/cheat-editor.cpp (100%) rename {higan => bsnes}/target-bsnes/tools/manifest-viewer.cpp (100%) rename {higan => bsnes}/target-bsnes/tools/state-manager.cpp (100%) rename {higan => bsnes}/target-bsnes/tools/tools.cpp (100%) rename {higan => bsnes}/target-bsnes/tools/tools.hpp (100%) delete mode 100644 higan/fc/GNUmakefile delete mode 100644 higan/fc/apu/apu.cpp delete mode 100644 higan/fc/apu/apu.hpp delete mode 100644 higan/fc/apu/dmc.cpp delete mode 100644 higan/fc/apu/envelope.cpp delete mode 100644 higan/fc/apu/noise.cpp delete mode 100644 higan/fc/apu/pulse.cpp delete mode 100644 higan/fc/apu/serialization.cpp delete mode 100644 higan/fc/apu/sweep.cpp delete mode 100644 higan/fc/apu/triangle.cpp delete mode 100644 higan/fc/cartridge/board/bandai-fcg.cpp delete mode 100644 higan/fc/cartridge/board/board.cpp delete mode 100644 higan/fc/cartridge/board/board.hpp delete mode 100644 higan/fc/cartridge/board/konami-vrc1.cpp delete mode 100644 higan/fc/cartridge/board/konami-vrc2.cpp delete mode 100644 higan/fc/cartridge/board/konami-vrc3.cpp delete mode 100644 higan/fc/cartridge/board/konami-vrc4.cpp delete mode 100644 higan/fc/cartridge/board/konami-vrc6.cpp delete mode 100644 higan/fc/cartridge/board/konami-vrc7.cpp delete mode 100644 higan/fc/cartridge/board/nes-axrom.cpp delete mode 100644 higan/fc/cartridge/board/nes-bnrom.cpp delete mode 100644 higan/fc/cartridge/board/nes-cnrom.cpp delete mode 100644 higan/fc/cartridge/board/nes-exrom.cpp delete mode 100644 higan/fc/cartridge/board/nes-fxrom.cpp delete mode 100644 higan/fc/cartridge/board/nes-gxrom.cpp delete mode 100644 higan/fc/cartridge/board/nes-hkrom.cpp delete mode 100644 higan/fc/cartridge/board/nes-nrom.cpp delete mode 100644 higan/fc/cartridge/board/nes-pxrom.cpp delete mode 100644 higan/fc/cartridge/board/nes-sxrom.cpp delete mode 100644 higan/fc/cartridge/board/nes-txrom.cpp delete mode 100644 higan/fc/cartridge/board/nes-uxrom.cpp delete mode 100644 higan/fc/cartridge/board/sunsoft-5b.cpp delete mode 100644 higan/fc/cartridge/cartridge.cpp delete mode 100644 higan/fc/cartridge/cartridge.hpp delete mode 100644 higan/fc/cartridge/chip/chip.cpp delete mode 100644 higan/fc/cartridge/chip/chip.hpp delete mode 100644 higan/fc/cartridge/chip/mmc1.cpp delete mode 100644 higan/fc/cartridge/chip/mmc3.cpp delete mode 100644 higan/fc/cartridge/chip/mmc5.cpp delete mode 100644 higan/fc/cartridge/chip/mmc6.cpp delete mode 100644 higan/fc/cartridge/chip/vrc1.cpp delete mode 100644 higan/fc/cartridge/chip/vrc2.cpp delete mode 100644 higan/fc/cartridge/chip/vrc3.cpp delete mode 100644 higan/fc/cartridge/chip/vrc4.cpp delete mode 100644 higan/fc/cartridge/chip/vrc6.cpp delete mode 100644 higan/fc/cartridge/chip/vrc7.cpp delete mode 100644 higan/fc/cartridge/serialization.cpp delete mode 100644 higan/fc/controller/controller.cpp delete mode 100644 higan/fc/controller/controller.hpp delete mode 100644 higan/fc/controller/gamepad/gamepad.cpp delete mode 100644 higan/fc/controller/gamepad/gamepad.hpp delete mode 100644 higan/fc/cpu/cpu.cpp delete mode 100644 higan/fc/cpu/cpu.hpp delete mode 100644 higan/fc/cpu/memory.cpp delete mode 100644 higan/fc/cpu/serialization.cpp delete mode 100644 higan/fc/cpu/timing.cpp delete mode 100644 higan/fc/fc.hpp delete mode 100644 higan/fc/interface/interface.cpp delete mode 100644 higan/fc/interface/interface.hpp delete mode 100644 higan/fc/memory/memory.cpp delete mode 100644 higan/fc/memory/memory.hpp delete mode 100644 higan/fc/ppu/memory.cpp delete mode 100644 higan/fc/ppu/ppu.cpp delete mode 100644 higan/fc/ppu/ppu.hpp delete mode 100644 higan/fc/ppu/render.cpp delete mode 100644 higan/fc/ppu/serialization.cpp delete mode 100644 higan/fc/system/serialization.cpp delete mode 100644 higan/fc/system/system.cpp delete mode 100644 higan/fc/system/system.hpp delete mode 100644 higan/gba/GNUmakefile delete mode 100644 higan/gba/apu/apu.cpp delete mode 100644 higan/gba/apu/apu.hpp delete mode 100644 higan/gba/apu/fifo.cpp delete mode 100644 higan/gba/apu/io.cpp delete mode 100644 higan/gba/apu/noise.cpp delete mode 100644 higan/gba/apu/sequencer.cpp delete mode 100644 higan/gba/apu/serialization.cpp delete mode 100644 higan/gba/apu/square.cpp delete mode 100644 higan/gba/apu/square1.cpp delete mode 100644 higan/gba/apu/square2.cpp delete mode 100644 higan/gba/apu/wave.cpp delete mode 100644 higan/gba/cartridge/cartridge.cpp delete mode 100644 higan/gba/cartridge/cartridge.hpp delete mode 100644 higan/gba/cartridge/eeprom.cpp delete mode 100644 higan/gba/cartridge/flash.cpp delete mode 100644 higan/gba/cartridge/memory.hpp delete mode 100644 higan/gba/cartridge/mrom.cpp delete mode 100644 higan/gba/cartridge/serialization.cpp delete mode 100644 higan/gba/cartridge/sram.cpp delete mode 100644 higan/gba/cpu/bus.cpp delete mode 100644 higan/gba/cpu/cpu.cpp delete mode 100644 higan/gba/cpu/cpu.hpp delete mode 100644 higan/gba/cpu/dma.cpp delete mode 100644 higan/gba/cpu/io.cpp delete mode 100644 higan/gba/cpu/keypad.cpp delete mode 100644 higan/gba/cpu/memory.cpp delete mode 100644 higan/gba/cpu/prefetch.cpp delete mode 100644 higan/gba/cpu/serialization.cpp delete mode 100644 higan/gba/cpu/timer.cpp delete mode 100644 higan/gba/gba.hpp delete mode 100644 higan/gba/interface/interface.cpp delete mode 100644 higan/gba/interface/interface.hpp delete mode 100644 higan/gba/memory/memory.cpp delete mode 100644 higan/gba/memory/memory.hpp delete mode 100644 higan/gba/player/player.cpp delete mode 100644 higan/gba/player/player.hpp delete mode 100644 higan/gba/player/serialization.cpp delete mode 100644 higan/gba/ppu/background.cpp delete mode 100644 higan/gba/ppu/io.cpp delete mode 100644 higan/gba/ppu/memory.cpp delete mode 100644 higan/gba/ppu/object.cpp delete mode 100644 higan/gba/ppu/ppu.cpp delete mode 100644 higan/gba/ppu/ppu.hpp delete mode 100644 higan/gba/ppu/screen.cpp delete mode 100644 higan/gba/ppu/serialization.cpp delete mode 100644 higan/gba/ppu/window.cpp delete mode 100644 higan/gba/system/bios.cpp delete mode 100644 higan/gba/system/serialization.cpp delete mode 100644 higan/gba/system/system.cpp delete mode 100644 higan/gba/system/system.hpp delete mode 100644 higan/md/GNUmakefile delete mode 100644 higan/md/apu/apu.cpp delete mode 100644 higan/md/apu/apu.hpp delete mode 100644 higan/md/apu/bus.cpp delete mode 100644 higan/md/apu/serialization.cpp delete mode 100644 higan/md/cartridge/cartridge.cpp delete mode 100644 higan/md/cartridge/cartridge.hpp delete mode 100644 higan/md/cartridge/serialization.cpp delete mode 100644 higan/md/controller/control-pad/control-pad.cpp delete mode 100644 higan/md/controller/control-pad/control-pad.hpp delete mode 100644 higan/md/controller/controller.cpp delete mode 100644 higan/md/controller/controller.hpp delete mode 100644 higan/md/controller/fighting-pad/fighting-pad.cpp delete mode 100644 higan/md/controller/fighting-pad/fighting-pad.hpp delete mode 100644 higan/md/cpu/bus.cpp delete mode 100644 higan/md/cpu/cpu.cpp delete mode 100644 higan/md/cpu/cpu.hpp delete mode 100644 higan/md/cpu/serialization.cpp delete mode 100644 higan/md/interface/interface.cpp delete mode 100644 higan/md/interface/interface.hpp delete mode 100644 higan/md/md.hpp delete mode 100644 higan/md/psg/io.cpp delete mode 100644 higan/md/psg/noise.cpp delete mode 100644 higan/md/psg/psg.cpp delete mode 100644 higan/md/psg/psg.hpp delete mode 100644 higan/md/psg/serialization.cpp delete mode 100644 higan/md/psg/tone.cpp delete mode 100644 higan/md/system/serialization.cpp delete mode 100644 higan/md/system/system.cpp delete mode 100644 higan/md/system/system.hpp delete mode 100644 higan/md/vdp/background.cpp delete mode 100644 higan/md/vdp/dma.cpp delete mode 100644 higan/md/vdp/io.cpp delete mode 100644 higan/md/vdp/memory.cpp delete mode 100644 higan/md/vdp/render.cpp delete mode 100644 higan/md/vdp/serialization.cpp delete mode 100644 higan/md/vdp/sprite.cpp delete mode 100644 higan/md/vdp/vdp.cpp delete mode 100644 higan/md/vdp/vdp.hpp delete mode 100644 higan/md/ym2612/channel.cpp delete mode 100644 higan/md/ym2612/constants.cpp delete mode 100644 higan/md/ym2612/io.cpp delete mode 100644 higan/md/ym2612/serialization.cpp delete mode 100644 higan/md/ym2612/timer.cpp delete mode 100644 higan/md/ym2612/ym2612.cpp delete mode 100644 higan/md/ym2612/ym2612.hpp delete mode 100644 higan/ms/GNUmakefile delete mode 100644 higan/ms/cartridge/cartridge.cpp delete mode 100644 higan/ms/cartridge/cartridge.hpp delete mode 100644 higan/ms/cartridge/mapper.cpp delete mode 100644 higan/ms/cartridge/serialization.cpp delete mode 100644 higan/ms/controller/controller.cpp delete mode 100644 higan/ms/controller/controller.hpp delete mode 100644 higan/ms/controller/gamepad/gamepad.cpp delete mode 100644 higan/ms/controller/gamepad/gamepad.hpp delete mode 100644 higan/ms/controller/numberpad/numberpad.cpp delete mode 100644 higan/ms/controller/numberpad/numberpad.hpp delete mode 100644 higan/ms/cpu/coleco.cpp delete mode 100644 higan/ms/cpu/cpu.cpp delete mode 100644 higan/ms/cpu/cpu.hpp delete mode 100644 higan/ms/cpu/sega.cpp delete mode 100644 higan/ms/cpu/serialization.cpp delete mode 100644 higan/ms/interface/colecovision.cpp delete mode 100644 higan/ms/interface/game-gear.cpp delete mode 100644 higan/ms/interface/interface.cpp delete mode 100644 higan/ms/interface/interface.hpp delete mode 100644 higan/ms/interface/master-system.cpp delete mode 100644 higan/ms/interface/sc-3000.cpp delete mode 100644 higan/ms/interface/sg-1000.cpp delete mode 100644 higan/ms/ms.hpp delete mode 100644 higan/ms/psg/io.cpp delete mode 100644 higan/ms/psg/noise.cpp delete mode 100644 higan/ms/psg/psg.cpp delete mode 100644 higan/ms/psg/psg.hpp delete mode 100644 higan/ms/psg/serialization.cpp delete mode 100644 higan/ms/psg/tone.cpp delete mode 100644 higan/ms/system/serialization.cpp delete mode 100644 higan/ms/system/system.cpp delete mode 100644 higan/ms/system/system.hpp delete mode 100644 higan/ms/vdp/background.cpp delete mode 100644 higan/ms/vdp/io.cpp delete mode 100644 higan/ms/vdp/serialization.cpp delete mode 100644 higan/ms/vdp/sprite.cpp delete mode 100644 higan/ms/vdp/vdp.cpp delete mode 100644 higan/ms/vdp/vdp.hpp delete mode 100644 higan/msx/GNUmakefile delete mode 100644 higan/msx/cartridge/cartridge.cpp delete mode 100644 higan/msx/cartridge/cartridge.hpp delete mode 100644 higan/msx/cartridge/serialization.cpp delete mode 100644 higan/msx/cpu/cpu.cpp delete mode 100644 higan/msx/cpu/cpu.hpp delete mode 100644 higan/msx/cpu/memory.cpp delete mode 100644 higan/msx/cpu/serialization.cpp delete mode 100644 higan/msx/interface/interface.cpp delete mode 100644 higan/msx/interface/interface.hpp delete mode 100644 higan/msx/msx.hpp delete mode 100644 higan/msx/psg/psg.cpp delete mode 100644 higan/msx/psg/psg.hpp delete mode 100644 higan/msx/psg/serialization.cpp delete mode 100644 higan/msx/system/serialization.cpp delete mode 100644 higan/msx/system/system.cpp delete mode 100644 higan/msx/system/system.hpp delete mode 100644 higan/msx/vdp/background.cpp delete mode 100644 higan/msx/vdp/io.cpp delete mode 100644 higan/msx/vdp/serialization.cpp delete mode 100644 higan/msx/vdp/sprites.cpp delete mode 100644 higan/msx/vdp/vdp.cpp delete mode 100644 higan/msx/vdp/vdp.hpp delete mode 100644 higan/ngp/GNUmakefile delete mode 100644 higan/ngp/apu/apu.cpp delete mode 100644 higan/ngp/apu/apu.hpp delete mode 100644 higan/ngp/apu/serialization.cpp delete mode 100644 higan/ngp/cartridge/cartridge.cpp delete mode 100644 higan/ngp/cartridge/cartridge.hpp delete mode 100644 higan/ngp/cartridge/flash.cpp delete mode 100644 higan/ngp/cartridge/serialization.cpp delete mode 100644 higan/ngp/cpu/cpu.cpp delete mode 100644 higan/ngp/cpu/cpu.hpp delete mode 100644 higan/ngp/cpu/memory.cpp delete mode 100644 higan/ngp/cpu/serialization.cpp delete mode 100644 higan/ngp/interface/interface.cpp delete mode 100644 higan/ngp/interface/interface.hpp delete mode 100644 higan/ngp/interface/neo-geo-pocket-color.cpp delete mode 100644 higan/ngp/interface/neo-geo-pocket.cpp delete mode 100644 higan/ngp/ngp.hpp delete mode 100644 higan/ngp/psg/psg.cpp delete mode 100644 higan/ngp/psg/psg.hpp delete mode 100644 higan/ngp/psg/serialization.cpp delete mode 100644 higan/ngp/system/serialization.cpp delete mode 100644 higan/ngp/system/system.cpp delete mode 100644 higan/ngp/system/system.hpp delete mode 100644 higan/ngp/vpu/serialization.cpp delete mode 100644 higan/ngp/vpu/vpu.cpp delete mode 100644 higan/ngp/vpu/vpu.hpp delete mode 100644 higan/out/.gitignore delete mode 100644 higan/pce/GNUmakefile delete mode 100644 higan/pce/cartridge/cartridge.cpp delete mode 100644 higan/pce/cartridge/cartridge.hpp delete mode 100644 higan/pce/controller/controller.cpp delete mode 100644 higan/pce/controller/controller.hpp delete mode 100644 higan/pce/controller/gamepad/gamepad.cpp delete mode 100644 higan/pce/controller/gamepad/gamepad.hpp delete mode 100644 higan/pce/cpu/cpu.cpp delete mode 100644 higan/pce/cpu/cpu.hpp delete mode 100644 higan/pce/cpu/io.cpp delete mode 100644 higan/pce/cpu/irq.cpp delete mode 100644 higan/pce/cpu/memory.cpp delete mode 100644 higan/pce/cpu/serialization.cpp delete mode 100644 higan/pce/cpu/timer.cpp delete mode 100644 higan/pce/interface/interface.cpp delete mode 100644 higan/pce/interface/interface.hpp delete mode 100644 higan/pce/interface/pc-engine.cpp delete mode 100644 higan/pce/interface/supergrafx.cpp delete mode 100644 higan/pce/pce.hpp delete mode 100644 higan/pce/psg/channel.cpp delete mode 100644 higan/pce/psg/io.cpp delete mode 100644 higan/pce/psg/psg.cpp delete mode 100644 higan/pce/psg/psg.hpp delete mode 100644 higan/pce/psg/serialization.cpp delete mode 100644 higan/pce/system/serialization.cpp delete mode 100644 higan/pce/system/system.cpp delete mode 100644 higan/pce/system/system.hpp delete mode 100644 higan/pce/vce/io.cpp delete mode 100644 higan/pce/vce/memory.cpp delete mode 100644 higan/pce/vce/serialization.cpp delete mode 100644 higan/pce/vce/vce.cpp delete mode 100644 higan/pce/vce/vce.hpp delete mode 100644 higan/pce/vdc/background.cpp delete mode 100644 higan/pce/vdc/dma.cpp delete mode 100644 higan/pce/vdc/io.cpp delete mode 100644 higan/pce/vdc/irq.cpp delete mode 100644 higan/pce/vdc/memory.cpp delete mode 100644 higan/pce/vdc/serialization.cpp delete mode 100644 higan/pce/vdc/sprite.cpp delete mode 100644 higan/pce/vdc/vdc.cpp delete mode 100644 higan/pce/vdc/vdc.hpp delete mode 100644 higan/pce/vpc/serialization.cpp delete mode 100644 higan/pce/vpc/vpc.cpp delete mode 100644 higan/pce/vpc/vpc.hpp delete mode 100644 higan/sfc/dsp/brr.cpp delete mode 100644 higan/sfc/dsp/counter.cpp delete mode 100644 higan/sfc/dsp/dsp.cpp delete mode 100644 higan/sfc/dsp/dsp.hpp delete mode 100644 higan/sfc/dsp/echo.cpp delete mode 100644 higan/sfc/dsp/envelope.cpp delete mode 100644 higan/sfc/dsp/gaussian.cpp delete mode 100644 higan/sfc/dsp/misc.cpp delete mode 100644 higan/sfc/dsp/serialization.cpp delete mode 100644 higan/sfc/dsp/voice.cpp delete mode 100644 higan/sfc/ppu-fast/mode7.cpp delete mode 100644 higan/sfc/ppu-fast/ppu.cpp delete mode 100644 higan/systems/ColecoVision.sys/manifest.bml delete mode 100644 higan/systems/Famicom.sys/manifest.bml delete mode 100644 higan/systems/Game Boy Advance.sys/manifest.bml delete mode 100644 higan/systems/Game Gear.sys/manifest.bml delete mode 100644 higan/systems/MSX.sys/bios.rom delete mode 100644 higan/systems/MSX.sys/manifest.bml delete mode 100644 higan/systems/Master System.sys/manifest.bml delete mode 100644 higan/systems/Mega Drive.sys/manifest.bml delete mode 100644 higan/systems/Mega Drive.sys/tmss.rom delete mode 100644 higan/systems/Neo Geo Pocket Color.sys/manifest.bml delete mode 100644 higan/systems/Neo Geo Pocket.sys/manifest.bml delete mode 100644 higan/systems/PC Engine.sys/manifest.bml delete mode 100644 higan/systems/Pocket Challenge V2.sys/manifest.bml delete mode 100644 higan/systems/SC-3000.sys/manifest.bml delete mode 100644 higan/systems/SG-1000.sys/manifest.bml delete mode 100644 higan/systems/SuperGrafx.sys/manifest.bml delete mode 100644 higan/systems/WonderSwan Color.sys/manifest.bml delete mode 100644 higan/systems/WonderSwan.sys/manifest.bml delete mode 100644 higan/target-bsnes/settings/emulator.cpp delete mode 100644 higan/target-higan/GNUmakefile delete mode 100644 higan/target-higan/higan.cpp delete mode 100644 higan/target-higan/higan.hpp delete mode 100644 higan/target-higan/input/hotkeys.cpp delete mode 100644 higan/target-higan/input/input.cpp delete mode 100644 higan/target-higan/input/input.hpp delete mode 100644 higan/target-higan/presentation/presentation.cpp delete mode 100644 higan/target-higan/presentation/presentation.hpp delete mode 100644 higan/target-higan/program/game.cpp delete mode 100644 higan/target-higan/program/platform.cpp delete mode 100644 higan/target-higan/program/program.cpp delete mode 100644 higan/target-higan/program/program.hpp delete mode 100644 higan/target-higan/program/state.cpp delete mode 100644 higan/target-higan/program/utility.cpp delete mode 100644 higan/target-higan/resource/GNUmakefile delete mode 100644 higan/target-higan/resource/higan.Manifest delete mode 100644 higan/target-higan/resource/higan.desktop delete mode 100644 higan/target-higan/resource/higan.ico delete mode 100644 higan/target-higan/resource/higan.plist delete mode 100644 higan/target-higan/resource/higan.png delete mode 100644 higan/target-higan/resource/higan.rc delete mode 100644 higan/target-higan/resource/higan.svg delete mode 100644 higan/target-higan/resource/icon.png delete mode 100644 higan/target-higan/resource/logo.png delete mode 100644 higan/target-higan/resource/resource.bml delete mode 100644 higan/target-higan/resource/resource.cpp delete mode 100644 higan/target-higan/resource/resource.hpp delete mode 100644 higan/target-higan/settings/advanced.cpp delete mode 100644 higan/target-higan/settings/audio.cpp delete mode 100644 higan/target-higan/settings/hotkeys.cpp delete mode 100644 higan/target-higan/settings/input.cpp delete mode 100644 higan/target-higan/settings/settings.cpp delete mode 100644 higan/target-higan/settings/settings.hpp delete mode 100644 higan/target-higan/settings/system-properties.cpp delete mode 100644 higan/target-higan/settings/systems.cpp delete mode 100644 higan/target-higan/settings/video.cpp delete mode 100644 higan/target-higan/tools/cheat-database.cpp delete mode 100644 higan/target-higan/tools/cheat-editor.cpp delete mode 100644 higan/target-higan/tools/game-notes.cpp delete mode 100644 higan/target-higan/tools/manifest-viewer.cpp delete mode 100644 higan/target-higan/tools/state-manager.cpp delete mode 100644 higan/target-higan/tools/tools.cpp delete mode 100644 higan/target-higan/tools/tools.hpp delete mode 100644 higan/ws/GNUmakefile delete mode 100644 higan/ws/apu/apu.cpp delete mode 100644 higan/ws/apu/apu.hpp delete mode 100644 higan/ws/apu/channel1.cpp delete mode 100644 higan/ws/apu/channel2.cpp delete mode 100644 higan/ws/apu/channel3.cpp delete mode 100644 higan/ws/apu/channel4.cpp delete mode 100644 higan/ws/apu/channel5.cpp delete mode 100644 higan/ws/apu/dma.cpp delete mode 100644 higan/ws/apu/io.cpp delete mode 100644 higan/ws/apu/serialization.cpp delete mode 100644 higan/ws/cartridge/cartridge.cpp delete mode 100644 higan/ws/cartridge/cartridge.hpp delete mode 100644 higan/ws/cartridge/io.cpp delete mode 100644 higan/ws/cartridge/memory.cpp delete mode 100644 higan/ws/cartridge/rtc.cpp delete mode 100644 higan/ws/cartridge/serialization.cpp delete mode 100644 higan/ws/cpu/cpu.cpp delete mode 100644 higan/ws/cpu/cpu.hpp delete mode 100644 higan/ws/cpu/dma.cpp delete mode 100644 higan/ws/cpu/interrupt.cpp delete mode 100644 higan/ws/cpu/io.cpp delete mode 100644 higan/ws/cpu/serialization.cpp delete mode 100644 higan/ws/eeprom/eeprom.cpp delete mode 100644 higan/ws/eeprom/eeprom.hpp delete mode 100644 higan/ws/eeprom/serialization.cpp delete mode 100644 higan/ws/interface/interface.cpp delete mode 100644 higan/ws/interface/interface.hpp delete mode 100644 higan/ws/interface/pocket-challenge-v2.cpp delete mode 100644 higan/ws/interface/wonderswan-color.cpp delete mode 100644 higan/ws/interface/wonderswan.cpp delete mode 100644 higan/ws/memory/memory.cpp delete mode 100644 higan/ws/memory/memory.hpp delete mode 100644 higan/ws/ppu/io.cpp delete mode 100644 higan/ws/ppu/latch.cpp delete mode 100644 higan/ws/ppu/ppu.cpp delete mode 100644 higan/ws/ppu/ppu.hpp delete mode 100644 higan/ws/ppu/render.cpp delete mode 100644 higan/ws/ppu/serialization.cpp delete mode 100644 higan/ws/ppu/video.cpp delete mode 100644 higan/ws/system/io.cpp delete mode 100644 higan/ws/system/serialization.cpp delete mode 100644 higan/ws/system/system.cpp delete mode 100644 higan/ws/system/system.hpp delete mode 100644 higan/ws/ws.hpp delete mode 100644 icarus/GNUmakefile diff --git a/higan/GNUmakefile b/bsnes/GNUmakefile similarity index 57% rename from higan/GNUmakefile rename to bsnes/GNUmakefile index a2e21e18..a30bc625 100644 --- a/higan/GNUmakefile +++ b/bsnes/GNUmakefile @@ -39,57 +39,10 @@ objects := libco emulator obj/libco.o: ../libco/libco.c obj/emulator.o: emulator/emulator.cpp -ifeq ($(target),higan) - cores := fc sfc ms md pce msx gb gba ws ngp -endif - -ifeq ($(target),bsnes) - cores := sfc gb -endif - -ifneq ($(filter $(cores),fc),) - include fc/GNUmakefile -endif - -ifneq ($(filter $(cores),sfc),) - include sfc/GNUmakefile -endif - -ifneq ($(filter $(cores),ms),) - include ms/GNUmakefile -endif - -ifneq ($(filter $(cores),md),) - include md/GNUmakefile -endif - -ifneq ($(filter $(cores),pce),) - include pce/GNUmakefile -endif - -ifneq ($(filter $(cores),msx),) - include msx/GNUmakefile -endif - -ifneq ($(filter $(cores),gb),) - include gb/GNUmakefile -endif - -ifneq ($(filter $(cores),gba),) - include gba/GNUmakefile -endif - -ifneq ($(filter $(cores),ws),) - include ws/GNUmakefile -endif - -ifneq ($(filter $(cores),ngp),) - include ngp/GNUmakefile -endif - +include sfc/GNUmakefile +include gb/GNUmakefile include processor/GNUmakefile -flags += $(foreach c,$(call strupper,$(cores)),-DCORE_$c) ui := target-$(target) include $(ui)/GNUmakefile -include obj/*.d diff --git a/higan/emulator/audio/audio.cpp b/bsnes/emulator/audio/audio.cpp similarity index 100% rename from higan/emulator/audio/audio.cpp rename to bsnes/emulator/audio/audio.cpp diff --git a/higan/emulator/audio/audio.hpp b/bsnes/emulator/audio/audio.hpp similarity index 100% rename from higan/emulator/audio/audio.hpp rename to bsnes/emulator/audio/audio.hpp diff --git a/higan/emulator/audio/stream.cpp b/bsnes/emulator/audio/stream.cpp similarity index 100% rename from higan/emulator/audio/stream.cpp rename to bsnes/emulator/audio/stream.cpp diff --git a/higan/emulator/cheat.hpp b/bsnes/emulator/cheat.hpp similarity index 100% rename from higan/emulator/cheat.hpp rename to bsnes/emulator/cheat.hpp diff --git a/higan/emulator/emulator.cpp b/bsnes/emulator/emulator.cpp similarity index 100% rename from higan/emulator/emulator.cpp rename to bsnes/emulator/emulator.cpp diff --git a/higan/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp similarity index 95% rename from higan/emulator/emulator.hpp rename to bsnes/emulator/emulator.hpp index 36791c41..271809ad 100644 --- a/higan/emulator/emulator.hpp +++ b/bsnes/emulator/emulator.hpp @@ -30,8 +30,8 @@ using namespace nall; #include namespace Emulator { - static const string Name = "higan"; - static const string Version = "107.1"; + static const string Name = "bsnes"; + static const string Version = "107.2"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org/"; diff --git a/higan/emulator/game.hpp b/bsnes/emulator/game.hpp similarity index 100% rename from higan/emulator/game.hpp rename to bsnes/emulator/game.hpp diff --git a/higan/emulator/interface.hpp b/bsnes/emulator/interface.hpp similarity index 96% rename from higan/emulator/interface.hpp rename to bsnes/emulator/interface.hpp index c097925b..5bbb1fe2 100644 --- a/higan/emulator/interface.hpp +++ b/bsnes/emulator/interface.hpp @@ -96,6 +96,9 @@ struct Interface { virtual auto cap(const string& name) -> bool { return false; } virtual auto get(const string& name) -> any { return {}; } virtual auto set(const string& name, const any& value) -> bool { return false; } + + virtual auto frameSkip() -> uint { return 0; } + virtual auto setFrameSkip(uint frameSkip) -> void {} }; } diff --git a/higan/emulator/memory/memory.hpp b/bsnes/emulator/memory/memory.hpp similarity index 100% rename from higan/emulator/memory/memory.hpp rename to bsnes/emulator/memory/memory.hpp diff --git a/higan/emulator/memory/readable.hpp b/bsnes/emulator/memory/readable.hpp similarity index 100% rename from higan/emulator/memory/readable.hpp rename to bsnes/emulator/memory/readable.hpp diff --git a/higan/emulator/memory/writable.hpp b/bsnes/emulator/memory/writable.hpp similarity index 100% rename from higan/emulator/memory/writable.hpp rename to bsnes/emulator/memory/writable.hpp diff --git a/higan/emulator/platform.hpp b/bsnes/emulator/platform.hpp similarity index 100% rename from higan/emulator/platform.hpp rename to bsnes/emulator/platform.hpp diff --git a/higan/emulator/random.hpp b/bsnes/emulator/random.hpp similarity index 100% rename from higan/emulator/random.hpp rename to bsnes/emulator/random.hpp diff --git a/higan/emulator/resource/GNUmakefile b/bsnes/emulator/resource/GNUmakefile similarity index 100% rename from higan/emulator/resource/GNUmakefile rename to bsnes/emulator/resource/GNUmakefile diff --git a/higan/emulator/resource/resource.bml b/bsnes/emulator/resource/resource.bml similarity index 100% rename from higan/emulator/resource/resource.bml rename to bsnes/emulator/resource/resource.bml diff --git a/higan/emulator/resource/resource.cpp b/bsnes/emulator/resource/resource.cpp similarity index 100% rename from higan/emulator/resource/resource.cpp rename to bsnes/emulator/resource/resource.cpp diff --git a/higan/emulator/resource/resource.hpp b/bsnes/emulator/resource/resource.hpp similarity index 100% rename from higan/emulator/resource/resource.hpp rename to bsnes/emulator/resource/resource.hpp diff --git a/higan/emulator/resource/sprite/crosshair-blue.png b/bsnes/emulator/resource/sprite/crosshair-blue.png similarity index 100% rename from higan/emulator/resource/sprite/crosshair-blue.png rename to bsnes/emulator/resource/sprite/crosshair-blue.png diff --git a/higan/emulator/resource/sprite/crosshair-green.png b/bsnes/emulator/resource/sprite/crosshair-green.png similarity index 100% rename from higan/emulator/resource/sprite/crosshair-green.png rename to bsnes/emulator/resource/sprite/crosshair-green.png diff --git a/higan/emulator/resource/sprite/crosshair-red.png b/bsnes/emulator/resource/sprite/crosshair-red.png similarity index 100% rename from higan/emulator/resource/sprite/crosshair-red.png rename to bsnes/emulator/resource/sprite/crosshair-red.png diff --git a/higan/emulator/scheduler.hpp b/bsnes/emulator/scheduler.hpp similarity index 100% rename from higan/emulator/scheduler.hpp rename to bsnes/emulator/scheduler.hpp diff --git a/higan/emulator/thread.hpp b/bsnes/emulator/thread.hpp similarity index 100% rename from higan/emulator/thread.hpp rename to bsnes/emulator/thread.hpp diff --git a/higan/emulator/types.hpp b/bsnes/emulator/types.hpp similarity index 100% rename from higan/emulator/types.hpp rename to bsnes/emulator/types.hpp diff --git a/higan/emulator/video/sprite.cpp b/bsnes/emulator/video/sprite.cpp similarity index 100% rename from higan/emulator/video/sprite.cpp rename to bsnes/emulator/video/sprite.cpp diff --git a/higan/emulator/video/video.cpp b/bsnes/emulator/video/video.cpp similarity index 100% rename from higan/emulator/video/video.cpp rename to bsnes/emulator/video/video.cpp diff --git a/higan/emulator/video/video.hpp b/bsnes/emulator/video/video.hpp similarity index 100% rename from higan/emulator/video/video.hpp rename to bsnes/emulator/video/video.hpp diff --git a/higan/gb/GNUmakefile b/bsnes/gb/GNUmakefile similarity index 100% rename from higan/gb/GNUmakefile rename to bsnes/gb/GNUmakefile diff --git a/higan/gb/apu/apu.cpp b/bsnes/gb/apu/apu.cpp similarity index 100% rename from higan/gb/apu/apu.cpp rename to bsnes/gb/apu/apu.cpp diff --git a/higan/gb/apu/apu.hpp b/bsnes/gb/apu/apu.hpp similarity index 100% rename from higan/gb/apu/apu.hpp rename to bsnes/gb/apu/apu.hpp diff --git a/higan/gb/apu/noise.cpp b/bsnes/gb/apu/noise.cpp similarity index 100% rename from higan/gb/apu/noise.cpp rename to bsnes/gb/apu/noise.cpp diff --git a/higan/gb/apu/sequencer.cpp b/bsnes/gb/apu/sequencer.cpp similarity index 100% rename from higan/gb/apu/sequencer.cpp rename to bsnes/gb/apu/sequencer.cpp diff --git a/higan/gb/apu/serialization.cpp b/bsnes/gb/apu/serialization.cpp similarity index 100% rename from higan/gb/apu/serialization.cpp rename to bsnes/gb/apu/serialization.cpp diff --git a/higan/gb/apu/square1.cpp b/bsnes/gb/apu/square1.cpp similarity index 100% rename from higan/gb/apu/square1.cpp rename to bsnes/gb/apu/square1.cpp diff --git a/higan/gb/apu/square2.cpp b/bsnes/gb/apu/square2.cpp similarity index 100% rename from higan/gb/apu/square2.cpp rename to bsnes/gb/apu/square2.cpp diff --git a/higan/gb/apu/wave.cpp b/bsnes/gb/apu/wave.cpp similarity index 100% rename from higan/gb/apu/wave.cpp rename to bsnes/gb/apu/wave.cpp diff --git a/higan/gb/cartridge/cartridge.cpp b/bsnes/gb/cartridge/cartridge.cpp similarity index 100% rename from higan/gb/cartridge/cartridge.cpp rename to bsnes/gb/cartridge/cartridge.cpp diff --git a/higan/gb/cartridge/cartridge.hpp b/bsnes/gb/cartridge/cartridge.hpp similarity index 100% rename from higan/gb/cartridge/cartridge.hpp rename to bsnes/gb/cartridge/cartridge.hpp diff --git a/higan/gb/cartridge/huc1/huc1.cpp b/bsnes/gb/cartridge/huc1/huc1.cpp similarity index 100% rename from higan/gb/cartridge/huc1/huc1.cpp rename to bsnes/gb/cartridge/huc1/huc1.cpp diff --git a/higan/gb/cartridge/huc1/huc1.hpp b/bsnes/gb/cartridge/huc1/huc1.hpp similarity index 100% rename from higan/gb/cartridge/huc1/huc1.hpp rename to bsnes/gb/cartridge/huc1/huc1.hpp diff --git a/higan/gb/cartridge/huc3/huc3.cpp b/bsnes/gb/cartridge/huc3/huc3.cpp similarity index 100% rename from higan/gb/cartridge/huc3/huc3.cpp rename to bsnes/gb/cartridge/huc3/huc3.cpp diff --git a/higan/gb/cartridge/huc3/huc3.hpp b/bsnes/gb/cartridge/huc3/huc3.hpp similarity index 100% rename from higan/gb/cartridge/huc3/huc3.hpp rename to bsnes/gb/cartridge/huc3/huc3.hpp diff --git a/higan/gb/cartridge/mbc0/mbc0.cpp b/bsnes/gb/cartridge/mbc0/mbc0.cpp similarity index 100% rename from higan/gb/cartridge/mbc0/mbc0.cpp rename to bsnes/gb/cartridge/mbc0/mbc0.cpp diff --git a/higan/gb/cartridge/mbc0/mbc0.hpp b/bsnes/gb/cartridge/mbc0/mbc0.hpp similarity index 100% rename from higan/gb/cartridge/mbc0/mbc0.hpp rename to bsnes/gb/cartridge/mbc0/mbc0.hpp diff --git a/higan/gb/cartridge/mbc1/mbc1.cpp b/bsnes/gb/cartridge/mbc1/mbc1.cpp similarity index 100% rename from higan/gb/cartridge/mbc1/mbc1.cpp rename to bsnes/gb/cartridge/mbc1/mbc1.cpp diff --git a/higan/gb/cartridge/mbc1/mbc1.hpp b/bsnes/gb/cartridge/mbc1/mbc1.hpp similarity index 100% rename from higan/gb/cartridge/mbc1/mbc1.hpp rename to bsnes/gb/cartridge/mbc1/mbc1.hpp diff --git a/higan/gb/cartridge/mbc1m/mbc1m.cpp b/bsnes/gb/cartridge/mbc1m/mbc1m.cpp similarity index 100% rename from higan/gb/cartridge/mbc1m/mbc1m.cpp rename to bsnes/gb/cartridge/mbc1m/mbc1m.cpp diff --git a/higan/gb/cartridge/mbc1m/mbc1m.hpp b/bsnes/gb/cartridge/mbc1m/mbc1m.hpp similarity index 100% rename from higan/gb/cartridge/mbc1m/mbc1m.hpp rename to bsnes/gb/cartridge/mbc1m/mbc1m.hpp diff --git a/higan/gb/cartridge/mbc2/mbc2.cpp b/bsnes/gb/cartridge/mbc2/mbc2.cpp similarity index 100% rename from higan/gb/cartridge/mbc2/mbc2.cpp rename to bsnes/gb/cartridge/mbc2/mbc2.cpp diff --git a/higan/gb/cartridge/mbc2/mbc2.hpp b/bsnes/gb/cartridge/mbc2/mbc2.hpp similarity index 100% rename from higan/gb/cartridge/mbc2/mbc2.hpp rename to bsnes/gb/cartridge/mbc2/mbc2.hpp diff --git a/higan/gb/cartridge/mbc3/mbc3.cpp b/bsnes/gb/cartridge/mbc3/mbc3.cpp similarity index 100% rename from higan/gb/cartridge/mbc3/mbc3.cpp rename to bsnes/gb/cartridge/mbc3/mbc3.cpp diff --git a/higan/gb/cartridge/mbc3/mbc3.hpp b/bsnes/gb/cartridge/mbc3/mbc3.hpp similarity index 100% rename from higan/gb/cartridge/mbc3/mbc3.hpp rename to bsnes/gb/cartridge/mbc3/mbc3.hpp diff --git a/higan/gb/cartridge/mbc5/mbc5.cpp b/bsnes/gb/cartridge/mbc5/mbc5.cpp similarity index 100% rename from higan/gb/cartridge/mbc5/mbc5.cpp rename to bsnes/gb/cartridge/mbc5/mbc5.cpp diff --git a/higan/gb/cartridge/mbc5/mbc5.hpp b/bsnes/gb/cartridge/mbc5/mbc5.hpp similarity index 100% rename from higan/gb/cartridge/mbc5/mbc5.hpp rename to bsnes/gb/cartridge/mbc5/mbc5.hpp diff --git a/higan/gb/cartridge/mbc6/mbc6.cpp b/bsnes/gb/cartridge/mbc6/mbc6.cpp similarity index 100% rename from higan/gb/cartridge/mbc6/mbc6.cpp rename to bsnes/gb/cartridge/mbc6/mbc6.cpp diff --git a/higan/gb/cartridge/mbc6/mbc6.hpp b/bsnes/gb/cartridge/mbc6/mbc6.hpp similarity index 100% rename from higan/gb/cartridge/mbc6/mbc6.hpp rename to bsnes/gb/cartridge/mbc6/mbc6.hpp diff --git a/higan/gb/cartridge/mbc7/eeprom.cpp b/bsnes/gb/cartridge/mbc7/eeprom.cpp similarity index 100% rename from higan/gb/cartridge/mbc7/eeprom.cpp rename to bsnes/gb/cartridge/mbc7/eeprom.cpp diff --git a/higan/gb/cartridge/mbc7/mbc7.cpp b/bsnes/gb/cartridge/mbc7/mbc7.cpp similarity index 100% rename from higan/gb/cartridge/mbc7/mbc7.cpp rename to bsnes/gb/cartridge/mbc7/mbc7.cpp diff --git a/higan/gb/cartridge/mbc7/mbc7.hpp b/bsnes/gb/cartridge/mbc7/mbc7.hpp similarity index 100% rename from higan/gb/cartridge/mbc7/mbc7.hpp rename to bsnes/gb/cartridge/mbc7/mbc7.hpp diff --git a/higan/gb/cartridge/mbc7/serialization.cpp b/bsnes/gb/cartridge/mbc7/serialization.cpp similarity index 100% rename from higan/gb/cartridge/mbc7/serialization.cpp rename to bsnes/gb/cartridge/mbc7/serialization.cpp diff --git a/higan/gb/cartridge/mmm01/mmm01.cpp b/bsnes/gb/cartridge/mmm01/mmm01.cpp similarity index 100% rename from higan/gb/cartridge/mmm01/mmm01.cpp rename to bsnes/gb/cartridge/mmm01/mmm01.cpp diff --git a/higan/gb/cartridge/mmm01/mmm01.hpp b/bsnes/gb/cartridge/mmm01/mmm01.hpp similarity index 100% rename from higan/gb/cartridge/mmm01/mmm01.hpp rename to bsnes/gb/cartridge/mmm01/mmm01.hpp diff --git a/higan/gb/cartridge/serialization.cpp b/bsnes/gb/cartridge/serialization.cpp similarity index 100% rename from higan/gb/cartridge/serialization.cpp rename to bsnes/gb/cartridge/serialization.cpp diff --git a/higan/gb/cartridge/tama/tama.cpp b/bsnes/gb/cartridge/tama/tama.cpp similarity index 100% rename from higan/gb/cartridge/tama/tama.cpp rename to bsnes/gb/cartridge/tama/tama.cpp diff --git a/higan/gb/cartridge/tama/tama.hpp b/bsnes/gb/cartridge/tama/tama.hpp similarity index 100% rename from higan/gb/cartridge/tama/tama.hpp rename to bsnes/gb/cartridge/tama/tama.hpp diff --git a/higan/gb/cpu/cpu.cpp b/bsnes/gb/cpu/cpu.cpp similarity index 100% rename from higan/gb/cpu/cpu.cpp rename to bsnes/gb/cpu/cpu.cpp diff --git a/higan/gb/cpu/cpu.hpp b/bsnes/gb/cpu/cpu.hpp similarity index 100% rename from higan/gb/cpu/cpu.hpp rename to bsnes/gb/cpu/cpu.hpp diff --git a/higan/gb/cpu/io.cpp b/bsnes/gb/cpu/io.cpp similarity index 100% rename from higan/gb/cpu/io.cpp rename to bsnes/gb/cpu/io.cpp diff --git a/higan/gb/cpu/memory.cpp b/bsnes/gb/cpu/memory.cpp similarity index 100% rename from higan/gb/cpu/memory.cpp rename to bsnes/gb/cpu/memory.cpp diff --git a/higan/gb/cpu/serialization.cpp b/bsnes/gb/cpu/serialization.cpp similarity index 100% rename from higan/gb/cpu/serialization.cpp rename to bsnes/gb/cpu/serialization.cpp diff --git a/higan/gb/cpu/timing.cpp b/bsnes/gb/cpu/timing.cpp similarity index 100% rename from higan/gb/cpu/timing.cpp rename to bsnes/gb/cpu/timing.cpp diff --git a/higan/gb/gb.hpp b/bsnes/gb/gb.hpp similarity index 100% rename from higan/gb/gb.hpp rename to bsnes/gb/gb.hpp diff --git a/higan/gb/interface/game-boy-color.cpp b/bsnes/gb/interface/game-boy-color.cpp similarity index 100% rename from higan/gb/interface/game-boy-color.cpp rename to bsnes/gb/interface/game-boy-color.cpp diff --git a/higan/gb/interface/game-boy.cpp b/bsnes/gb/interface/game-boy.cpp similarity index 100% rename from higan/gb/interface/game-boy.cpp rename to bsnes/gb/interface/game-boy.cpp diff --git a/higan/gb/interface/interface.cpp b/bsnes/gb/interface/interface.cpp similarity index 100% rename from higan/gb/interface/interface.cpp rename to bsnes/gb/interface/interface.cpp diff --git a/higan/gb/interface/interface.hpp b/bsnes/gb/interface/interface.hpp similarity index 98% rename from higan/gb/interface/interface.hpp rename to bsnes/gb/interface/interface.hpp index 42f07097..4d611161 100644 --- a/higan/gb/interface/interface.hpp +++ b/bsnes/gb/interface/interface.hpp @@ -1,5 +1,3 @@ -#if defined(CORE_GB) - namespace GameBoy { struct ID { @@ -85,5 +83,3 @@ extern SuperGameBoyInterface* superGameBoy; extern Settings settings; } - -#endif diff --git a/higan/gb/memory/memory.cpp b/bsnes/gb/memory/memory.cpp similarity index 100% rename from higan/gb/memory/memory.cpp rename to bsnes/gb/memory/memory.cpp diff --git a/higan/gb/memory/memory.hpp b/bsnes/gb/memory/memory.hpp similarity index 100% rename from higan/gb/memory/memory.hpp rename to bsnes/gb/memory/memory.hpp diff --git a/higan/gb/ppu/cgb.cpp b/bsnes/gb/ppu/cgb.cpp similarity index 100% rename from higan/gb/ppu/cgb.cpp rename to bsnes/gb/ppu/cgb.cpp diff --git a/higan/gb/ppu/dmg.cpp b/bsnes/gb/ppu/dmg.cpp similarity index 100% rename from higan/gb/ppu/dmg.cpp rename to bsnes/gb/ppu/dmg.cpp diff --git a/higan/gb/ppu/io.cpp b/bsnes/gb/ppu/io.cpp similarity index 100% rename from higan/gb/ppu/io.cpp rename to bsnes/gb/ppu/io.cpp diff --git a/higan/gb/ppu/ppu.cpp b/bsnes/gb/ppu/ppu.cpp similarity index 100% rename from higan/gb/ppu/ppu.cpp rename to bsnes/gb/ppu/ppu.cpp diff --git a/higan/gb/ppu/ppu.hpp b/bsnes/gb/ppu/ppu.hpp similarity index 100% rename from higan/gb/ppu/ppu.hpp rename to bsnes/gb/ppu/ppu.hpp diff --git a/higan/gb/ppu/serialization.cpp b/bsnes/gb/ppu/serialization.cpp similarity index 100% rename from higan/gb/ppu/serialization.cpp rename to bsnes/gb/ppu/serialization.cpp diff --git a/higan/gb/system/serialization.cpp b/bsnes/gb/system/serialization.cpp similarity index 100% rename from higan/gb/system/serialization.cpp rename to bsnes/gb/system/serialization.cpp diff --git a/higan/gb/system/system.cpp b/bsnes/gb/system/system.cpp similarity index 100% rename from higan/gb/system/system.cpp rename to bsnes/gb/system/system.cpp diff --git a/higan/gb/system/system.hpp b/bsnes/gb/system/system.hpp similarity index 100% rename from higan/gb/system/system.hpp rename to bsnes/gb/system/system.hpp diff --git a/higan/obj/.gitignore b/bsnes/obj/.gitignore similarity index 100% rename from higan/obj/.gitignore rename to bsnes/obj/.gitignore diff --git a/bsnes/out/.gitignore b/bsnes/out/.gitignore new file mode 100644 index 00000000..b82f689c --- /dev/null +++ b/bsnes/out/.gitignore @@ -0,0 +1 @@ +bsnes diff --git a/higan/processor/GNUmakefile b/bsnes/processor/GNUmakefile similarity index 100% rename from higan/processor/GNUmakefile rename to bsnes/processor/GNUmakefile diff --git a/higan/processor/arm7tdmi/algorithms.cpp b/bsnes/processor/arm7tdmi/algorithms.cpp similarity index 100% rename from higan/processor/arm7tdmi/algorithms.cpp rename to bsnes/processor/arm7tdmi/algorithms.cpp diff --git a/higan/processor/arm7tdmi/arm7tdmi.cpp b/bsnes/processor/arm7tdmi/arm7tdmi.cpp similarity index 100% rename from higan/processor/arm7tdmi/arm7tdmi.cpp rename to bsnes/processor/arm7tdmi/arm7tdmi.cpp diff --git a/higan/processor/arm7tdmi/arm7tdmi.hpp b/bsnes/processor/arm7tdmi/arm7tdmi.hpp similarity index 100% rename from higan/processor/arm7tdmi/arm7tdmi.hpp rename to bsnes/processor/arm7tdmi/arm7tdmi.hpp diff --git a/higan/processor/arm7tdmi/disassembler.cpp b/bsnes/processor/arm7tdmi/disassembler.cpp similarity index 100% rename from higan/processor/arm7tdmi/disassembler.cpp rename to bsnes/processor/arm7tdmi/disassembler.cpp diff --git a/higan/processor/arm7tdmi/instruction.cpp b/bsnes/processor/arm7tdmi/instruction.cpp similarity index 100% rename from higan/processor/arm7tdmi/instruction.cpp rename to bsnes/processor/arm7tdmi/instruction.cpp diff --git a/higan/processor/arm7tdmi/instructions-arm.cpp b/bsnes/processor/arm7tdmi/instructions-arm.cpp similarity index 100% rename from higan/processor/arm7tdmi/instructions-arm.cpp rename to bsnes/processor/arm7tdmi/instructions-arm.cpp diff --git a/higan/processor/arm7tdmi/instructions-thumb.cpp b/bsnes/processor/arm7tdmi/instructions-thumb.cpp similarity index 100% rename from higan/processor/arm7tdmi/instructions-thumb.cpp rename to bsnes/processor/arm7tdmi/instructions-thumb.cpp diff --git a/higan/processor/arm7tdmi/memory.cpp b/bsnes/processor/arm7tdmi/memory.cpp similarity index 100% rename from higan/processor/arm7tdmi/memory.cpp rename to bsnes/processor/arm7tdmi/memory.cpp diff --git a/higan/processor/arm7tdmi/registers.cpp b/bsnes/processor/arm7tdmi/registers.cpp similarity index 100% rename from higan/processor/arm7tdmi/registers.cpp rename to bsnes/processor/arm7tdmi/registers.cpp diff --git a/higan/processor/arm7tdmi/serialization.cpp b/bsnes/processor/arm7tdmi/serialization.cpp similarity index 100% rename from higan/processor/arm7tdmi/serialization.cpp rename to bsnes/processor/arm7tdmi/serialization.cpp diff --git a/higan/processor/gsu/disassembler.cpp b/bsnes/processor/gsu/disassembler.cpp similarity index 100% rename from higan/processor/gsu/disassembler.cpp rename to bsnes/processor/gsu/disassembler.cpp diff --git a/higan/processor/gsu/gsu.cpp b/bsnes/processor/gsu/gsu.cpp similarity index 100% rename from higan/processor/gsu/gsu.cpp rename to bsnes/processor/gsu/gsu.cpp diff --git a/higan/processor/gsu/gsu.hpp b/bsnes/processor/gsu/gsu.hpp similarity index 100% rename from higan/processor/gsu/gsu.hpp rename to bsnes/processor/gsu/gsu.hpp diff --git a/higan/processor/gsu/instruction.cpp b/bsnes/processor/gsu/instruction.cpp similarity index 100% rename from higan/processor/gsu/instruction.cpp rename to bsnes/processor/gsu/instruction.cpp diff --git a/higan/processor/gsu/instructions.cpp b/bsnes/processor/gsu/instructions.cpp similarity index 100% rename from higan/processor/gsu/instructions.cpp rename to bsnes/processor/gsu/instructions.cpp diff --git a/higan/processor/gsu/registers.hpp b/bsnes/processor/gsu/registers.hpp similarity index 100% rename from higan/processor/gsu/registers.hpp rename to bsnes/processor/gsu/registers.hpp diff --git a/higan/processor/gsu/serialization.cpp b/bsnes/processor/gsu/serialization.cpp similarity index 100% rename from higan/processor/gsu/serialization.cpp rename to bsnes/processor/gsu/serialization.cpp diff --git a/higan/processor/hg51b/hg51b.cpp b/bsnes/processor/hg51b/hg51b.cpp similarity index 100% rename from higan/processor/hg51b/hg51b.cpp rename to bsnes/processor/hg51b/hg51b.cpp diff --git a/higan/processor/hg51b/hg51b.hpp b/bsnes/processor/hg51b/hg51b.hpp similarity index 100% rename from higan/processor/hg51b/hg51b.hpp rename to bsnes/processor/hg51b/hg51b.hpp diff --git a/higan/processor/hg51b/instruction.cpp b/bsnes/processor/hg51b/instruction.cpp similarity index 100% rename from higan/processor/hg51b/instruction.cpp rename to bsnes/processor/hg51b/instruction.cpp diff --git a/higan/processor/hg51b/instructions.cpp b/bsnes/processor/hg51b/instructions.cpp similarity index 100% rename from higan/processor/hg51b/instructions.cpp rename to bsnes/processor/hg51b/instructions.cpp diff --git a/higan/processor/hg51b/registers.cpp b/bsnes/processor/hg51b/registers.cpp similarity index 100% rename from higan/processor/hg51b/registers.cpp rename to bsnes/processor/hg51b/registers.cpp diff --git a/higan/processor/hg51b/serialization.cpp b/bsnes/processor/hg51b/serialization.cpp similarity index 100% rename from higan/processor/hg51b/serialization.cpp rename to bsnes/processor/hg51b/serialization.cpp diff --git a/higan/processor/huc6280/algorithms.cpp b/bsnes/processor/huc6280/algorithms.cpp similarity index 100% rename from higan/processor/huc6280/algorithms.cpp rename to bsnes/processor/huc6280/algorithms.cpp diff --git a/higan/processor/huc6280/disassembler.cpp b/bsnes/processor/huc6280/disassembler.cpp similarity index 100% rename from higan/processor/huc6280/disassembler.cpp rename to bsnes/processor/huc6280/disassembler.cpp diff --git a/higan/processor/huc6280/huc6280.cpp b/bsnes/processor/huc6280/huc6280.cpp similarity index 100% rename from higan/processor/huc6280/huc6280.cpp rename to bsnes/processor/huc6280/huc6280.cpp diff --git a/higan/processor/huc6280/huc6280.hpp b/bsnes/processor/huc6280/huc6280.hpp similarity index 100% rename from higan/processor/huc6280/huc6280.hpp rename to bsnes/processor/huc6280/huc6280.hpp diff --git a/higan/processor/huc6280/instruction.cpp b/bsnes/processor/huc6280/instruction.cpp similarity index 100% rename from higan/processor/huc6280/instruction.cpp rename to bsnes/processor/huc6280/instruction.cpp diff --git a/higan/processor/huc6280/instructions.cpp b/bsnes/processor/huc6280/instructions.cpp similarity index 100% rename from higan/processor/huc6280/instructions.cpp rename to bsnes/processor/huc6280/instructions.cpp diff --git a/higan/processor/huc6280/memory.cpp b/bsnes/processor/huc6280/memory.cpp similarity index 100% rename from higan/processor/huc6280/memory.cpp rename to bsnes/processor/huc6280/memory.cpp diff --git a/higan/processor/huc6280/serialization.cpp b/bsnes/processor/huc6280/serialization.cpp similarity index 100% rename from higan/processor/huc6280/serialization.cpp rename to bsnes/processor/huc6280/serialization.cpp diff --git a/higan/processor/m68k/disassembler.cpp b/bsnes/processor/m68k/disassembler.cpp similarity index 100% rename from higan/processor/m68k/disassembler.cpp rename to bsnes/processor/m68k/disassembler.cpp diff --git a/higan/processor/m68k/effective-address.cpp b/bsnes/processor/m68k/effective-address.cpp similarity index 100% rename from higan/processor/m68k/effective-address.cpp rename to bsnes/processor/m68k/effective-address.cpp diff --git a/higan/processor/m68k/instruction.cpp b/bsnes/processor/m68k/instruction.cpp similarity index 100% rename from higan/processor/m68k/instruction.cpp rename to bsnes/processor/m68k/instruction.cpp diff --git a/higan/processor/m68k/instructions.cpp b/bsnes/processor/m68k/instructions.cpp similarity index 100% rename from higan/processor/m68k/instructions.cpp rename to bsnes/processor/m68k/instructions.cpp diff --git a/higan/processor/m68k/m68k.cpp b/bsnes/processor/m68k/m68k.cpp similarity index 100% rename from higan/processor/m68k/m68k.cpp rename to bsnes/processor/m68k/m68k.cpp diff --git a/higan/processor/m68k/m68k.hpp b/bsnes/processor/m68k/m68k.hpp similarity index 100% rename from higan/processor/m68k/m68k.hpp rename to bsnes/processor/m68k/m68k.hpp diff --git a/higan/processor/m68k/memory.cpp b/bsnes/processor/m68k/memory.cpp similarity index 100% rename from higan/processor/m68k/memory.cpp rename to bsnes/processor/m68k/memory.cpp diff --git a/higan/processor/m68k/registers.cpp b/bsnes/processor/m68k/registers.cpp similarity index 100% rename from higan/processor/m68k/registers.cpp rename to bsnes/processor/m68k/registers.cpp diff --git a/higan/processor/m68k/serialization.cpp b/bsnes/processor/m68k/serialization.cpp similarity index 100% rename from higan/processor/m68k/serialization.cpp rename to bsnes/processor/m68k/serialization.cpp diff --git a/higan/processor/mos6502/algorithms.cpp b/bsnes/processor/mos6502/algorithms.cpp similarity index 100% rename from higan/processor/mos6502/algorithms.cpp rename to bsnes/processor/mos6502/algorithms.cpp diff --git a/higan/processor/mos6502/disassembler.cpp b/bsnes/processor/mos6502/disassembler.cpp similarity index 100% rename from higan/processor/mos6502/disassembler.cpp rename to bsnes/processor/mos6502/disassembler.cpp diff --git a/higan/processor/mos6502/instruction.cpp b/bsnes/processor/mos6502/instruction.cpp similarity index 100% rename from higan/processor/mos6502/instruction.cpp rename to bsnes/processor/mos6502/instruction.cpp diff --git a/higan/processor/mos6502/instructions.cpp b/bsnes/processor/mos6502/instructions.cpp similarity index 100% rename from higan/processor/mos6502/instructions.cpp rename to bsnes/processor/mos6502/instructions.cpp diff --git a/higan/processor/mos6502/memory.cpp b/bsnes/processor/mos6502/memory.cpp similarity index 100% rename from higan/processor/mos6502/memory.cpp rename to bsnes/processor/mos6502/memory.cpp diff --git a/higan/processor/mos6502/mos6502.cpp b/bsnes/processor/mos6502/mos6502.cpp similarity index 100% rename from higan/processor/mos6502/mos6502.cpp rename to bsnes/processor/mos6502/mos6502.cpp diff --git a/higan/processor/mos6502/mos6502.hpp b/bsnes/processor/mos6502/mos6502.hpp similarity index 100% rename from higan/processor/mos6502/mos6502.hpp rename to bsnes/processor/mos6502/mos6502.hpp diff --git a/higan/processor/mos6502/serialization.cpp b/bsnes/processor/mos6502/serialization.cpp similarity index 100% rename from higan/processor/mos6502/serialization.cpp rename to bsnes/processor/mos6502/serialization.cpp diff --git a/higan/processor/processor.hpp b/bsnes/processor/processor.hpp similarity index 100% rename from higan/processor/processor.hpp rename to bsnes/processor/processor.hpp diff --git a/higan/processor/sm83/algorithms.cpp b/bsnes/processor/sm83/algorithms.cpp similarity index 100% rename from higan/processor/sm83/algorithms.cpp rename to bsnes/processor/sm83/algorithms.cpp diff --git a/higan/processor/sm83/disassembler.cpp b/bsnes/processor/sm83/disassembler.cpp similarity index 100% rename from higan/processor/sm83/disassembler.cpp rename to bsnes/processor/sm83/disassembler.cpp diff --git a/higan/processor/sm83/instruction.cpp b/bsnes/processor/sm83/instruction.cpp similarity index 100% rename from higan/processor/sm83/instruction.cpp rename to bsnes/processor/sm83/instruction.cpp diff --git a/higan/processor/sm83/instructions.cpp b/bsnes/processor/sm83/instructions.cpp similarity index 100% rename from higan/processor/sm83/instructions.cpp rename to bsnes/processor/sm83/instructions.cpp diff --git a/higan/processor/sm83/memory.cpp b/bsnes/processor/sm83/memory.cpp similarity index 100% rename from higan/processor/sm83/memory.cpp rename to bsnes/processor/sm83/memory.cpp diff --git a/higan/processor/sm83/registers.cpp b/bsnes/processor/sm83/registers.cpp similarity index 100% rename from higan/processor/sm83/registers.cpp rename to bsnes/processor/sm83/registers.cpp diff --git a/higan/processor/sm83/serialization.cpp b/bsnes/processor/sm83/serialization.cpp similarity index 100% rename from higan/processor/sm83/serialization.cpp rename to bsnes/processor/sm83/serialization.cpp diff --git a/higan/processor/sm83/sm83.cpp b/bsnes/processor/sm83/sm83.cpp similarity index 100% rename from higan/processor/sm83/sm83.cpp rename to bsnes/processor/sm83/sm83.cpp diff --git a/higan/processor/sm83/sm83.hpp b/bsnes/processor/sm83/sm83.hpp similarity index 100% rename from higan/processor/sm83/sm83.hpp rename to bsnes/processor/sm83/sm83.hpp diff --git a/higan/processor/spc700/algorithms.cpp b/bsnes/processor/spc700/algorithms.cpp similarity index 100% rename from higan/processor/spc700/algorithms.cpp rename to bsnes/processor/spc700/algorithms.cpp diff --git a/higan/processor/spc700/disassembler.cpp b/bsnes/processor/spc700/disassembler.cpp similarity index 100% rename from higan/processor/spc700/disassembler.cpp rename to bsnes/processor/spc700/disassembler.cpp diff --git a/higan/processor/spc700/instruction.cpp b/bsnes/processor/spc700/instruction.cpp similarity index 100% rename from higan/processor/spc700/instruction.cpp rename to bsnes/processor/spc700/instruction.cpp diff --git a/higan/processor/spc700/instructions.cpp b/bsnes/processor/spc700/instructions.cpp similarity index 100% rename from higan/processor/spc700/instructions.cpp rename to bsnes/processor/spc700/instructions.cpp diff --git a/higan/processor/spc700/memory.cpp b/bsnes/processor/spc700/memory.cpp similarity index 100% rename from higan/processor/spc700/memory.cpp rename to bsnes/processor/spc700/memory.cpp diff --git a/higan/processor/spc700/serialization.cpp b/bsnes/processor/spc700/serialization.cpp similarity index 100% rename from higan/processor/spc700/serialization.cpp rename to bsnes/processor/spc700/serialization.cpp diff --git a/higan/processor/spc700/spc700.cpp b/bsnes/processor/spc700/spc700.cpp similarity index 100% rename from higan/processor/spc700/spc700.cpp rename to bsnes/processor/spc700/spc700.cpp diff --git a/higan/processor/spc700/spc700.hpp b/bsnes/processor/spc700/spc700.hpp similarity index 100% rename from higan/processor/spc700/spc700.hpp rename to bsnes/processor/spc700/spc700.hpp diff --git a/higan/processor/tlcs900h/algorithms.cpp b/bsnes/processor/tlcs900h/algorithms.cpp similarity index 100% rename from higan/processor/tlcs900h/algorithms.cpp rename to bsnes/processor/tlcs900h/algorithms.cpp diff --git a/higan/processor/tlcs900h/conditions.cpp b/bsnes/processor/tlcs900h/conditions.cpp similarity index 100% rename from higan/processor/tlcs900h/conditions.cpp rename to bsnes/processor/tlcs900h/conditions.cpp diff --git a/higan/processor/tlcs900h/control-registers.cpp b/bsnes/processor/tlcs900h/control-registers.cpp similarity index 100% rename from higan/processor/tlcs900h/control-registers.cpp rename to bsnes/processor/tlcs900h/control-registers.cpp diff --git a/higan/processor/tlcs900h/disassembler.cpp b/bsnes/processor/tlcs900h/disassembler.cpp similarity index 100% rename from higan/processor/tlcs900h/disassembler.cpp rename to bsnes/processor/tlcs900h/disassembler.cpp diff --git a/higan/processor/tlcs900h/instruction.cpp b/bsnes/processor/tlcs900h/instruction.cpp similarity index 100% rename from higan/processor/tlcs900h/instruction.cpp rename to bsnes/processor/tlcs900h/instruction.cpp diff --git a/higan/processor/tlcs900h/instructions.cpp b/bsnes/processor/tlcs900h/instructions.cpp similarity index 100% rename from higan/processor/tlcs900h/instructions.cpp rename to bsnes/processor/tlcs900h/instructions.cpp diff --git a/higan/processor/tlcs900h/memory.cpp b/bsnes/processor/tlcs900h/memory.cpp similarity index 100% rename from higan/processor/tlcs900h/memory.cpp rename to bsnes/processor/tlcs900h/memory.cpp diff --git a/higan/processor/tlcs900h/registers.cpp b/bsnes/processor/tlcs900h/registers.cpp similarity index 100% rename from higan/processor/tlcs900h/registers.cpp rename to bsnes/processor/tlcs900h/registers.cpp diff --git a/higan/processor/tlcs900h/serialization.cpp b/bsnes/processor/tlcs900h/serialization.cpp similarity index 100% rename from higan/processor/tlcs900h/serialization.cpp rename to bsnes/processor/tlcs900h/serialization.cpp diff --git a/higan/processor/tlcs900h/tlcs900h.cpp b/bsnes/processor/tlcs900h/tlcs900h.cpp similarity index 100% rename from higan/processor/tlcs900h/tlcs900h.cpp rename to bsnes/processor/tlcs900h/tlcs900h.cpp diff --git a/higan/processor/tlcs900h/tlcs900h.hpp b/bsnes/processor/tlcs900h/tlcs900h.hpp similarity index 100% rename from higan/processor/tlcs900h/tlcs900h.hpp rename to bsnes/processor/tlcs900h/tlcs900h.hpp diff --git a/higan/processor/upd96050/disassembler.cpp b/bsnes/processor/upd96050/disassembler.cpp similarity index 100% rename from higan/processor/upd96050/disassembler.cpp rename to bsnes/processor/upd96050/disassembler.cpp diff --git a/higan/processor/upd96050/instructions.cpp b/bsnes/processor/upd96050/instructions.cpp similarity index 100% rename from higan/processor/upd96050/instructions.cpp rename to bsnes/processor/upd96050/instructions.cpp diff --git a/higan/processor/upd96050/memory.cpp b/bsnes/processor/upd96050/memory.cpp similarity index 100% rename from higan/processor/upd96050/memory.cpp rename to bsnes/processor/upd96050/memory.cpp diff --git a/higan/processor/upd96050/serialization.cpp b/bsnes/processor/upd96050/serialization.cpp similarity index 100% rename from higan/processor/upd96050/serialization.cpp rename to bsnes/processor/upd96050/serialization.cpp diff --git a/higan/processor/upd96050/upd96050.cpp b/bsnes/processor/upd96050/upd96050.cpp similarity index 100% rename from higan/processor/upd96050/upd96050.cpp rename to bsnes/processor/upd96050/upd96050.cpp diff --git a/higan/processor/upd96050/upd96050.hpp b/bsnes/processor/upd96050/upd96050.hpp similarity index 100% rename from higan/processor/upd96050/upd96050.hpp rename to bsnes/processor/upd96050/upd96050.hpp diff --git a/higan/processor/v30mz/algorithms.cpp b/bsnes/processor/v30mz/algorithms.cpp similarity index 100% rename from higan/processor/v30mz/algorithms.cpp rename to bsnes/processor/v30mz/algorithms.cpp diff --git a/higan/processor/v30mz/disassembler-old.cpp b/bsnes/processor/v30mz/disassembler-old.cpp similarity index 100% rename from higan/processor/v30mz/disassembler-old.cpp rename to bsnes/processor/v30mz/disassembler-old.cpp diff --git a/higan/processor/v30mz/disassembler.cpp b/bsnes/processor/v30mz/disassembler.cpp similarity index 100% rename from higan/processor/v30mz/disassembler.cpp rename to bsnes/processor/v30mz/disassembler.cpp diff --git a/higan/processor/v30mz/instruction.cpp b/bsnes/processor/v30mz/instruction.cpp similarity index 100% rename from higan/processor/v30mz/instruction.cpp rename to bsnes/processor/v30mz/instruction.cpp diff --git a/higan/processor/v30mz/instructions-adjust.cpp b/bsnes/processor/v30mz/instructions-adjust.cpp similarity index 100% rename from higan/processor/v30mz/instructions-adjust.cpp rename to bsnes/processor/v30mz/instructions-adjust.cpp diff --git a/higan/processor/v30mz/instructions-alu.cpp b/bsnes/processor/v30mz/instructions-alu.cpp similarity index 100% rename from higan/processor/v30mz/instructions-alu.cpp rename to bsnes/processor/v30mz/instructions-alu.cpp diff --git a/higan/processor/v30mz/instructions-exec.cpp b/bsnes/processor/v30mz/instructions-exec.cpp similarity index 100% rename from higan/processor/v30mz/instructions-exec.cpp rename to bsnes/processor/v30mz/instructions-exec.cpp diff --git a/higan/processor/v30mz/instructions-flag.cpp b/bsnes/processor/v30mz/instructions-flag.cpp similarity index 100% rename from higan/processor/v30mz/instructions-flag.cpp rename to bsnes/processor/v30mz/instructions-flag.cpp diff --git a/higan/processor/v30mz/instructions-group.cpp b/bsnes/processor/v30mz/instructions-group.cpp similarity index 100% rename from higan/processor/v30mz/instructions-group.cpp rename to bsnes/processor/v30mz/instructions-group.cpp diff --git a/higan/processor/v30mz/instructions-misc.cpp b/bsnes/processor/v30mz/instructions-misc.cpp similarity index 100% rename from higan/processor/v30mz/instructions-misc.cpp rename to bsnes/processor/v30mz/instructions-misc.cpp diff --git a/higan/processor/v30mz/instructions-move.cpp b/bsnes/processor/v30mz/instructions-move.cpp similarity index 100% rename from higan/processor/v30mz/instructions-move.cpp rename to bsnes/processor/v30mz/instructions-move.cpp diff --git a/higan/processor/v30mz/instructions-string.cpp b/bsnes/processor/v30mz/instructions-string.cpp similarity index 100% rename from higan/processor/v30mz/instructions-string.cpp rename to bsnes/processor/v30mz/instructions-string.cpp diff --git a/higan/processor/v30mz/memory.cpp b/bsnes/processor/v30mz/memory.cpp similarity index 100% rename from higan/processor/v30mz/memory.cpp rename to bsnes/processor/v30mz/memory.cpp diff --git a/higan/processor/v30mz/modrm.cpp b/bsnes/processor/v30mz/modrm.cpp similarity index 100% rename from higan/processor/v30mz/modrm.cpp rename to bsnes/processor/v30mz/modrm.cpp diff --git a/higan/processor/v30mz/registers.cpp b/bsnes/processor/v30mz/registers.cpp similarity index 100% rename from higan/processor/v30mz/registers.cpp rename to bsnes/processor/v30mz/registers.cpp diff --git a/higan/processor/v30mz/serialization.cpp b/bsnes/processor/v30mz/serialization.cpp similarity index 100% rename from higan/processor/v30mz/serialization.cpp rename to bsnes/processor/v30mz/serialization.cpp diff --git a/higan/processor/v30mz/v30mz.cpp b/bsnes/processor/v30mz/v30mz.cpp similarity index 100% rename from higan/processor/v30mz/v30mz.cpp rename to bsnes/processor/v30mz/v30mz.cpp diff --git a/higan/processor/v30mz/v30mz.hpp b/bsnes/processor/v30mz/v30mz.hpp similarity index 100% rename from higan/processor/v30mz/v30mz.hpp rename to bsnes/processor/v30mz/v30mz.hpp diff --git a/higan/processor/wdc65816/algorithms.cpp b/bsnes/processor/wdc65816/algorithms.cpp similarity index 100% rename from higan/processor/wdc65816/algorithms.cpp rename to bsnes/processor/wdc65816/algorithms.cpp diff --git a/higan/processor/wdc65816/disassembler.cpp b/bsnes/processor/wdc65816/disassembler.cpp similarity index 100% rename from higan/processor/wdc65816/disassembler.cpp rename to bsnes/processor/wdc65816/disassembler.cpp diff --git a/higan/processor/wdc65816/instruction.cpp b/bsnes/processor/wdc65816/instruction.cpp similarity index 100% rename from higan/processor/wdc65816/instruction.cpp rename to bsnes/processor/wdc65816/instruction.cpp diff --git a/higan/processor/wdc65816/instruction.hpp b/bsnes/processor/wdc65816/instruction.hpp similarity index 100% rename from higan/processor/wdc65816/instruction.hpp rename to bsnes/processor/wdc65816/instruction.hpp diff --git a/higan/processor/wdc65816/instructions-modify.cpp b/bsnes/processor/wdc65816/instructions-modify.cpp similarity index 100% rename from higan/processor/wdc65816/instructions-modify.cpp rename to bsnes/processor/wdc65816/instructions-modify.cpp diff --git a/higan/processor/wdc65816/instructions-other.cpp b/bsnes/processor/wdc65816/instructions-other.cpp similarity index 100% rename from higan/processor/wdc65816/instructions-other.cpp rename to bsnes/processor/wdc65816/instructions-other.cpp diff --git a/higan/processor/wdc65816/instructions-pc.cpp b/bsnes/processor/wdc65816/instructions-pc.cpp similarity index 100% rename from higan/processor/wdc65816/instructions-pc.cpp rename to bsnes/processor/wdc65816/instructions-pc.cpp diff --git a/higan/processor/wdc65816/instructions-read.cpp b/bsnes/processor/wdc65816/instructions-read.cpp similarity index 100% rename from higan/processor/wdc65816/instructions-read.cpp rename to bsnes/processor/wdc65816/instructions-read.cpp diff --git a/higan/processor/wdc65816/instructions-write.cpp b/bsnes/processor/wdc65816/instructions-write.cpp similarity index 100% rename from higan/processor/wdc65816/instructions-write.cpp rename to bsnes/processor/wdc65816/instructions-write.cpp diff --git a/higan/processor/wdc65816/memory.cpp b/bsnes/processor/wdc65816/memory.cpp similarity index 100% rename from higan/processor/wdc65816/memory.cpp rename to bsnes/processor/wdc65816/memory.cpp diff --git a/higan/processor/wdc65816/serialization.cpp b/bsnes/processor/wdc65816/serialization.cpp similarity index 100% rename from higan/processor/wdc65816/serialization.cpp rename to bsnes/processor/wdc65816/serialization.cpp diff --git a/higan/processor/wdc65816/wdc65816.cpp b/bsnes/processor/wdc65816/wdc65816.cpp similarity index 100% rename from higan/processor/wdc65816/wdc65816.cpp rename to bsnes/processor/wdc65816/wdc65816.cpp diff --git a/higan/processor/wdc65816/wdc65816.hpp b/bsnes/processor/wdc65816/wdc65816.hpp similarity index 100% rename from higan/processor/wdc65816/wdc65816.hpp rename to bsnes/processor/wdc65816/wdc65816.hpp diff --git a/higan/processor/z80/algorithms.cpp b/bsnes/processor/z80/algorithms.cpp similarity index 100% rename from higan/processor/z80/algorithms.cpp rename to bsnes/processor/z80/algorithms.cpp diff --git a/higan/processor/z80/disassembler.cpp b/bsnes/processor/z80/disassembler.cpp similarity index 100% rename from higan/processor/z80/disassembler.cpp rename to bsnes/processor/z80/disassembler.cpp diff --git a/higan/processor/z80/instruction.cpp b/bsnes/processor/z80/instruction.cpp similarity index 100% rename from higan/processor/z80/instruction.cpp rename to bsnes/processor/z80/instruction.cpp diff --git a/higan/processor/z80/instructions.cpp b/bsnes/processor/z80/instructions.cpp similarity index 100% rename from higan/processor/z80/instructions.cpp rename to bsnes/processor/z80/instructions.cpp diff --git a/higan/processor/z80/memory.cpp b/bsnes/processor/z80/memory.cpp similarity index 100% rename from higan/processor/z80/memory.cpp rename to bsnes/processor/z80/memory.cpp diff --git a/higan/processor/z80/registers.cpp b/bsnes/processor/z80/registers.cpp similarity index 100% rename from higan/processor/z80/registers.cpp rename to bsnes/processor/z80/registers.cpp diff --git a/higan/processor/z80/serialization.cpp b/bsnes/processor/z80/serialization.cpp similarity index 100% rename from higan/processor/z80/serialization.cpp rename to bsnes/processor/z80/serialization.cpp diff --git a/higan/processor/z80/z80.cpp b/bsnes/processor/z80/z80.cpp similarity index 100% rename from higan/processor/z80/z80.cpp rename to bsnes/processor/z80/z80.cpp diff --git a/higan/processor/z80/z80.hpp b/bsnes/processor/z80/z80.hpp similarity index 100% rename from higan/processor/z80/z80.hpp rename to bsnes/processor/z80/z80.hpp diff --git a/higan/sfc/GNUmakefile b/bsnes/sfc/GNUmakefile similarity index 100% rename from higan/sfc/GNUmakefile rename to bsnes/sfc/GNUmakefile diff --git a/higan/sfc/cartridge/cartridge.cpp b/bsnes/sfc/cartridge/cartridge.cpp similarity index 99% rename from higan/sfc/cartridge/cartridge.cpp rename to bsnes/sfc/cartridge/cartridge.cpp index 8bd5572e..0a1cd60e 100644 --- a/higan/sfc/cartridge/cartridge.cpp +++ b/bsnes/sfc/cartridge/cartridge.cpp @@ -102,14 +102,11 @@ auto Cartridge::load() -> bool { } auto Cartridge::loadGameBoy() -> bool { - #if defined(CORE_GB) //invoked from ICD::load() information.sha256 = GameBoy::cartridge.hash(); slotGameBoy.load(GameBoy::cartridge.manifest()); loadCartridgeGameBoy(slotGameBoy.document); return true; - #endif - return false; } auto Cartridge::loadBSMemory() -> bool { diff --git a/higan/sfc/cartridge/cartridge.hpp b/bsnes/sfc/cartridge/cartridge.hpp similarity index 100% rename from higan/sfc/cartridge/cartridge.hpp rename to bsnes/sfc/cartridge/cartridge.hpp diff --git a/higan/sfc/cartridge/load.cpp b/bsnes/sfc/cartridge/load.cpp similarity index 100% rename from higan/sfc/cartridge/load.cpp rename to bsnes/sfc/cartridge/load.cpp diff --git a/higan/sfc/cartridge/save.cpp b/bsnes/sfc/cartridge/save.cpp similarity index 100% rename from higan/sfc/cartridge/save.cpp rename to bsnes/sfc/cartridge/save.cpp diff --git a/higan/sfc/cartridge/serialization.cpp b/bsnes/sfc/cartridge/serialization.cpp similarity index 100% rename from higan/sfc/cartridge/serialization.cpp rename to bsnes/sfc/cartridge/serialization.cpp diff --git a/higan/sfc/controller/controller.cpp b/bsnes/sfc/controller/controller.cpp similarity index 100% rename from higan/sfc/controller/controller.cpp rename to bsnes/sfc/controller/controller.cpp diff --git a/higan/sfc/controller/controller.hpp b/bsnes/sfc/controller/controller.hpp similarity index 100% rename from higan/sfc/controller/controller.hpp rename to bsnes/sfc/controller/controller.hpp diff --git a/higan/sfc/controller/gamepad/gamepad.cpp b/bsnes/sfc/controller/gamepad/gamepad.cpp similarity index 100% rename from higan/sfc/controller/gamepad/gamepad.cpp rename to bsnes/sfc/controller/gamepad/gamepad.cpp diff --git a/higan/sfc/controller/gamepad/gamepad.hpp b/bsnes/sfc/controller/gamepad/gamepad.hpp similarity index 100% rename from higan/sfc/controller/gamepad/gamepad.hpp rename to bsnes/sfc/controller/gamepad/gamepad.hpp diff --git a/higan/sfc/controller/justifier/justifier.cpp b/bsnes/sfc/controller/justifier/justifier.cpp similarity index 100% rename from higan/sfc/controller/justifier/justifier.cpp rename to bsnes/sfc/controller/justifier/justifier.cpp diff --git a/higan/sfc/controller/justifier/justifier.hpp b/bsnes/sfc/controller/justifier/justifier.hpp similarity index 100% rename from higan/sfc/controller/justifier/justifier.hpp rename to bsnes/sfc/controller/justifier/justifier.hpp diff --git a/higan/sfc/controller/mouse/mouse.cpp b/bsnes/sfc/controller/mouse/mouse.cpp similarity index 100% rename from higan/sfc/controller/mouse/mouse.cpp rename to bsnes/sfc/controller/mouse/mouse.cpp diff --git a/higan/sfc/controller/mouse/mouse.hpp b/bsnes/sfc/controller/mouse/mouse.hpp similarity index 100% rename from higan/sfc/controller/mouse/mouse.hpp rename to bsnes/sfc/controller/mouse/mouse.hpp diff --git a/higan/sfc/controller/super-multitap/super-multitap.cpp b/bsnes/sfc/controller/super-multitap/super-multitap.cpp similarity index 100% rename from higan/sfc/controller/super-multitap/super-multitap.cpp rename to bsnes/sfc/controller/super-multitap/super-multitap.cpp diff --git a/higan/sfc/controller/super-multitap/super-multitap.hpp b/bsnes/sfc/controller/super-multitap/super-multitap.hpp similarity index 100% rename from higan/sfc/controller/super-multitap/super-multitap.hpp rename to bsnes/sfc/controller/super-multitap/super-multitap.hpp diff --git a/higan/sfc/controller/super-scope/super-scope.cpp b/bsnes/sfc/controller/super-scope/super-scope.cpp similarity index 100% rename from higan/sfc/controller/super-scope/super-scope.cpp rename to bsnes/sfc/controller/super-scope/super-scope.cpp diff --git a/higan/sfc/controller/super-scope/super-scope.hpp b/bsnes/sfc/controller/super-scope/super-scope.hpp similarity index 100% rename from higan/sfc/controller/super-scope/super-scope.hpp rename to bsnes/sfc/controller/super-scope/super-scope.hpp diff --git a/higan/sfc/coprocessor/armdsp/armdsp.cpp b/bsnes/sfc/coprocessor/armdsp/armdsp.cpp similarity index 100% rename from higan/sfc/coprocessor/armdsp/armdsp.cpp rename to bsnes/sfc/coprocessor/armdsp/armdsp.cpp diff --git a/higan/sfc/coprocessor/armdsp/armdsp.hpp b/bsnes/sfc/coprocessor/armdsp/armdsp.hpp similarity index 100% rename from higan/sfc/coprocessor/armdsp/armdsp.hpp rename to bsnes/sfc/coprocessor/armdsp/armdsp.hpp diff --git a/higan/sfc/coprocessor/armdsp/memory.cpp b/bsnes/sfc/coprocessor/armdsp/memory.cpp similarity index 100% rename from higan/sfc/coprocessor/armdsp/memory.cpp rename to bsnes/sfc/coprocessor/armdsp/memory.cpp diff --git a/higan/sfc/coprocessor/armdsp/registers.hpp b/bsnes/sfc/coprocessor/armdsp/registers.hpp similarity index 100% rename from higan/sfc/coprocessor/armdsp/registers.hpp rename to bsnes/sfc/coprocessor/armdsp/registers.hpp diff --git a/higan/sfc/coprocessor/armdsp/serialization.cpp b/bsnes/sfc/coprocessor/armdsp/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/armdsp/serialization.cpp rename to bsnes/sfc/coprocessor/armdsp/serialization.cpp diff --git a/higan/sfc/coprocessor/coprocessor.hpp b/bsnes/sfc/coprocessor/coprocessor.hpp similarity index 100% rename from higan/sfc/coprocessor/coprocessor.hpp rename to bsnes/sfc/coprocessor/coprocessor.hpp diff --git a/higan/sfc/coprocessor/cx4/cx4.cpp b/bsnes/sfc/coprocessor/cx4/cx4.cpp similarity index 100% rename from higan/sfc/coprocessor/cx4/cx4.cpp rename to bsnes/sfc/coprocessor/cx4/cx4.cpp diff --git a/higan/sfc/coprocessor/cx4/cx4.hpp b/bsnes/sfc/coprocessor/cx4/cx4.hpp similarity index 100% rename from higan/sfc/coprocessor/cx4/cx4.hpp rename to bsnes/sfc/coprocessor/cx4/cx4.hpp diff --git a/higan/sfc/coprocessor/cx4/data.cpp b/bsnes/sfc/coprocessor/cx4/data.cpp similarity index 100% rename from higan/sfc/coprocessor/cx4/data.cpp rename to bsnes/sfc/coprocessor/cx4/data.cpp diff --git a/higan/sfc/coprocessor/cx4/functions.cpp b/bsnes/sfc/coprocessor/cx4/functions.cpp similarity index 100% rename from higan/sfc/coprocessor/cx4/functions.cpp rename to bsnes/sfc/coprocessor/cx4/functions.cpp diff --git a/higan/sfc/coprocessor/cx4/oam.cpp b/bsnes/sfc/coprocessor/cx4/oam.cpp similarity index 100% rename from higan/sfc/coprocessor/cx4/oam.cpp rename to bsnes/sfc/coprocessor/cx4/oam.cpp diff --git a/higan/sfc/coprocessor/cx4/opcodes.cpp b/bsnes/sfc/coprocessor/cx4/opcodes.cpp similarity index 100% rename from higan/sfc/coprocessor/cx4/opcodes.cpp rename to bsnes/sfc/coprocessor/cx4/opcodes.cpp diff --git a/higan/sfc/coprocessor/cx4/serialization.cpp b/bsnes/sfc/coprocessor/cx4/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/cx4/serialization.cpp rename to bsnes/sfc/coprocessor/cx4/serialization.cpp diff --git a/higan/sfc/coprocessor/dip/dip.cpp b/bsnes/sfc/coprocessor/dip/dip.cpp similarity index 100% rename from higan/sfc/coprocessor/dip/dip.cpp rename to bsnes/sfc/coprocessor/dip/dip.cpp diff --git a/higan/sfc/coprocessor/dip/dip.hpp b/bsnes/sfc/coprocessor/dip/dip.hpp similarity index 100% rename from higan/sfc/coprocessor/dip/dip.hpp rename to bsnes/sfc/coprocessor/dip/dip.hpp diff --git a/higan/sfc/coprocessor/dip/serialization.cpp b/bsnes/sfc/coprocessor/dip/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/dip/serialization.cpp rename to bsnes/sfc/coprocessor/dip/serialization.cpp diff --git a/higan/sfc/coprocessor/dsp1/dsp1.cpp b/bsnes/sfc/coprocessor/dsp1/dsp1.cpp similarity index 100% rename from higan/sfc/coprocessor/dsp1/dsp1.cpp rename to bsnes/sfc/coprocessor/dsp1/dsp1.cpp diff --git a/higan/sfc/coprocessor/dsp1/dsp1.hpp b/bsnes/sfc/coprocessor/dsp1/dsp1.hpp similarity index 100% rename from higan/sfc/coprocessor/dsp1/dsp1.hpp rename to bsnes/sfc/coprocessor/dsp1/dsp1.hpp diff --git a/higan/sfc/coprocessor/dsp1/dsp1emu.cpp b/bsnes/sfc/coprocessor/dsp1/dsp1emu.cpp similarity index 100% rename from higan/sfc/coprocessor/dsp1/dsp1emu.cpp rename to bsnes/sfc/coprocessor/dsp1/dsp1emu.cpp diff --git a/higan/sfc/coprocessor/dsp1/dsp1emu.hpp b/bsnes/sfc/coprocessor/dsp1/dsp1emu.hpp similarity index 100% rename from higan/sfc/coprocessor/dsp1/dsp1emu.hpp rename to bsnes/sfc/coprocessor/dsp1/dsp1emu.hpp diff --git a/higan/sfc/coprocessor/dsp1/serialization.cpp b/bsnes/sfc/coprocessor/dsp1/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/dsp1/serialization.cpp rename to bsnes/sfc/coprocessor/dsp1/serialization.cpp diff --git a/higan/sfc/coprocessor/dsp2/dsp2.cpp b/bsnes/sfc/coprocessor/dsp2/dsp2.cpp similarity index 100% rename from higan/sfc/coprocessor/dsp2/dsp2.cpp rename to bsnes/sfc/coprocessor/dsp2/dsp2.cpp diff --git a/higan/sfc/coprocessor/dsp2/dsp2.hpp b/bsnes/sfc/coprocessor/dsp2/dsp2.hpp similarity index 100% rename from higan/sfc/coprocessor/dsp2/dsp2.hpp rename to bsnes/sfc/coprocessor/dsp2/dsp2.hpp diff --git a/higan/sfc/coprocessor/dsp2/opcodes.cpp b/bsnes/sfc/coprocessor/dsp2/opcodes.cpp similarity index 100% rename from higan/sfc/coprocessor/dsp2/opcodes.cpp rename to bsnes/sfc/coprocessor/dsp2/opcodes.cpp diff --git a/higan/sfc/coprocessor/dsp2/serialization.cpp b/bsnes/sfc/coprocessor/dsp2/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/dsp2/serialization.cpp rename to bsnes/sfc/coprocessor/dsp2/serialization.cpp diff --git a/higan/sfc/coprocessor/dsp4/dsp4.cpp b/bsnes/sfc/coprocessor/dsp4/dsp4.cpp similarity index 100% rename from higan/sfc/coprocessor/dsp4/dsp4.cpp rename to bsnes/sfc/coprocessor/dsp4/dsp4.cpp diff --git a/higan/sfc/coprocessor/dsp4/dsp4.hpp b/bsnes/sfc/coprocessor/dsp4/dsp4.hpp similarity index 100% rename from higan/sfc/coprocessor/dsp4/dsp4.hpp rename to bsnes/sfc/coprocessor/dsp4/dsp4.hpp diff --git a/higan/sfc/coprocessor/dsp4/dsp4emu.c b/bsnes/sfc/coprocessor/dsp4/dsp4emu.c similarity index 100% rename from higan/sfc/coprocessor/dsp4/dsp4emu.c rename to bsnes/sfc/coprocessor/dsp4/dsp4emu.c diff --git a/higan/sfc/coprocessor/dsp4/dsp4emu.h b/bsnes/sfc/coprocessor/dsp4/dsp4emu.h similarity index 100% rename from higan/sfc/coprocessor/dsp4/dsp4emu.h rename to bsnes/sfc/coprocessor/dsp4/dsp4emu.h diff --git a/higan/sfc/coprocessor/dsp4/serialization.cpp b/bsnes/sfc/coprocessor/dsp4/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/dsp4/serialization.cpp rename to bsnes/sfc/coprocessor/dsp4/serialization.cpp diff --git a/higan/sfc/coprocessor/epsonrtc/epsonrtc.cpp b/bsnes/sfc/coprocessor/epsonrtc/epsonrtc.cpp similarity index 100% rename from higan/sfc/coprocessor/epsonrtc/epsonrtc.cpp rename to bsnes/sfc/coprocessor/epsonrtc/epsonrtc.cpp diff --git a/higan/sfc/coprocessor/epsonrtc/epsonrtc.hpp b/bsnes/sfc/coprocessor/epsonrtc/epsonrtc.hpp similarity index 100% rename from higan/sfc/coprocessor/epsonrtc/epsonrtc.hpp rename to bsnes/sfc/coprocessor/epsonrtc/epsonrtc.hpp diff --git a/higan/sfc/coprocessor/epsonrtc/memory.cpp b/bsnes/sfc/coprocessor/epsonrtc/memory.cpp similarity index 100% rename from higan/sfc/coprocessor/epsonrtc/memory.cpp rename to bsnes/sfc/coprocessor/epsonrtc/memory.cpp diff --git a/higan/sfc/coprocessor/epsonrtc/serialization.cpp b/bsnes/sfc/coprocessor/epsonrtc/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/epsonrtc/serialization.cpp rename to bsnes/sfc/coprocessor/epsonrtc/serialization.cpp diff --git a/higan/sfc/coprocessor/epsonrtc/time.cpp b/bsnes/sfc/coprocessor/epsonrtc/time.cpp similarity index 100% rename from higan/sfc/coprocessor/epsonrtc/time.cpp rename to bsnes/sfc/coprocessor/epsonrtc/time.cpp diff --git a/higan/sfc/coprocessor/event/event.cpp b/bsnes/sfc/coprocessor/event/event.cpp similarity index 100% rename from higan/sfc/coprocessor/event/event.cpp rename to bsnes/sfc/coprocessor/event/event.cpp diff --git a/higan/sfc/coprocessor/event/event.hpp b/bsnes/sfc/coprocessor/event/event.hpp similarity index 100% rename from higan/sfc/coprocessor/event/event.hpp rename to bsnes/sfc/coprocessor/event/event.hpp diff --git a/higan/sfc/coprocessor/event/serialization.cpp b/bsnes/sfc/coprocessor/event/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/event/serialization.cpp rename to bsnes/sfc/coprocessor/event/serialization.cpp diff --git a/higan/sfc/coprocessor/hitachidsp/hitachidsp.cpp b/bsnes/sfc/coprocessor/hitachidsp/hitachidsp.cpp similarity index 100% rename from higan/sfc/coprocessor/hitachidsp/hitachidsp.cpp rename to bsnes/sfc/coprocessor/hitachidsp/hitachidsp.cpp diff --git a/higan/sfc/coprocessor/hitachidsp/hitachidsp.hpp b/bsnes/sfc/coprocessor/hitachidsp/hitachidsp.hpp similarity index 100% rename from higan/sfc/coprocessor/hitachidsp/hitachidsp.hpp rename to bsnes/sfc/coprocessor/hitachidsp/hitachidsp.hpp diff --git a/higan/sfc/coprocessor/hitachidsp/memory.cpp b/bsnes/sfc/coprocessor/hitachidsp/memory.cpp similarity index 100% rename from higan/sfc/coprocessor/hitachidsp/memory.cpp rename to bsnes/sfc/coprocessor/hitachidsp/memory.cpp diff --git a/higan/sfc/coprocessor/hitachidsp/serialization.cpp b/bsnes/sfc/coprocessor/hitachidsp/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/hitachidsp/serialization.cpp rename to bsnes/sfc/coprocessor/hitachidsp/serialization.cpp diff --git a/higan/sfc/coprocessor/icd/icd.cpp b/bsnes/sfc/coprocessor/icd/icd.cpp similarity index 98% rename from higan/sfc/coprocessor/icd/icd.cpp rename to bsnes/sfc/coprocessor/icd/icd.cpp index 5ac180a0..9e7b8c44 100644 --- a/higan/sfc/coprocessor/icd/icd.cpp +++ b/bsnes/sfc/coprocessor/icd/icd.cpp @@ -4,8 +4,6 @@ namespace SuperFamicom { ICD icd; -#if defined(CORE_GB) - #include "platform.cpp" #include "interface.cpp" #include "io.cpp" @@ -100,6 +98,4 @@ auto ICD::reset() -> void { GameBoy::system.power(); } -#endif - } diff --git a/higan/sfc/coprocessor/icd/icd.hpp b/bsnes/sfc/coprocessor/icd/icd.hpp similarity index 80% rename from higan/sfc/coprocessor/icd/icd.hpp rename to bsnes/sfc/coprocessor/icd/icd.hpp index 9aeeff82..60aee0b3 100644 --- a/higan/sfc/coprocessor/icd/icd.hpp +++ b/bsnes/sfc/coprocessor/icd/icd.hpp @@ -1,5 +1,3 @@ -#if defined(CORE_GB) - struct ICD : Emulator::Platform, GameBoy::SuperGameBoyInterface, Thread { shared_pointer stream; @@ -66,24 +64,4 @@ private: GameBoy::GameBoyInterface gameBoyInterface; }; -#else - -struct ICD : Thread { - auto init() -> void {} - auto load() -> void {} - auto unload() -> void {} - auto power() -> void {} - auto reset() -> void {} - - auto readIO(uint24, uint8) -> uint8 { return 0; } - auto writeIO(uint24, uint8) -> void { return; } - - auto serialize(serializer&) -> void {} - - uint Revision = 0; - uint Frequency = 0; -}; - -#endif - extern ICD icd; diff --git a/higan/sfc/coprocessor/icd/interface.cpp b/bsnes/sfc/coprocessor/icd/interface.cpp similarity index 100% rename from higan/sfc/coprocessor/icd/interface.cpp rename to bsnes/sfc/coprocessor/icd/interface.cpp diff --git a/higan/sfc/coprocessor/icd/io.cpp b/bsnes/sfc/coprocessor/icd/io.cpp similarity index 100% rename from higan/sfc/coprocessor/icd/io.cpp rename to bsnes/sfc/coprocessor/icd/io.cpp diff --git a/higan/sfc/coprocessor/icd/platform.cpp b/bsnes/sfc/coprocessor/icd/platform.cpp similarity index 100% rename from higan/sfc/coprocessor/icd/platform.cpp rename to bsnes/sfc/coprocessor/icd/platform.cpp diff --git a/higan/sfc/coprocessor/icd/serialization.cpp b/bsnes/sfc/coprocessor/icd/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/icd/serialization.cpp rename to bsnes/sfc/coprocessor/icd/serialization.cpp diff --git a/higan/sfc/coprocessor/mcc/mcc.cpp b/bsnes/sfc/coprocessor/mcc/mcc.cpp similarity index 100% rename from higan/sfc/coprocessor/mcc/mcc.cpp rename to bsnes/sfc/coprocessor/mcc/mcc.cpp diff --git a/higan/sfc/coprocessor/mcc/mcc.hpp b/bsnes/sfc/coprocessor/mcc/mcc.hpp similarity index 100% rename from higan/sfc/coprocessor/mcc/mcc.hpp rename to bsnes/sfc/coprocessor/mcc/mcc.hpp diff --git a/higan/sfc/coprocessor/mcc/serialization.cpp b/bsnes/sfc/coprocessor/mcc/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/mcc/serialization.cpp rename to bsnes/sfc/coprocessor/mcc/serialization.cpp diff --git a/higan/sfc/coprocessor/msu1/msu1.cpp b/bsnes/sfc/coprocessor/msu1/msu1.cpp similarity index 100% rename from higan/sfc/coprocessor/msu1/msu1.cpp rename to bsnes/sfc/coprocessor/msu1/msu1.cpp diff --git a/higan/sfc/coprocessor/msu1/msu1.hpp b/bsnes/sfc/coprocessor/msu1/msu1.hpp similarity index 100% rename from higan/sfc/coprocessor/msu1/msu1.hpp rename to bsnes/sfc/coprocessor/msu1/msu1.hpp diff --git a/higan/sfc/coprocessor/msu1/serialization.cpp b/bsnes/sfc/coprocessor/msu1/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/msu1/serialization.cpp rename to bsnes/sfc/coprocessor/msu1/serialization.cpp diff --git a/higan/sfc/coprocessor/necdsp/necdsp.cpp b/bsnes/sfc/coprocessor/necdsp/necdsp.cpp similarity index 100% rename from higan/sfc/coprocessor/necdsp/necdsp.cpp rename to bsnes/sfc/coprocessor/necdsp/necdsp.cpp diff --git a/higan/sfc/coprocessor/necdsp/necdsp.hpp b/bsnes/sfc/coprocessor/necdsp/necdsp.hpp similarity index 100% rename from higan/sfc/coprocessor/necdsp/necdsp.hpp rename to bsnes/sfc/coprocessor/necdsp/necdsp.hpp diff --git a/higan/sfc/coprocessor/necdsp/serialization.cpp b/bsnes/sfc/coprocessor/necdsp/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/necdsp/serialization.cpp rename to bsnes/sfc/coprocessor/necdsp/serialization.cpp diff --git a/higan/sfc/coprocessor/obc1/obc1.cpp b/bsnes/sfc/coprocessor/obc1/obc1.cpp similarity index 100% rename from higan/sfc/coprocessor/obc1/obc1.cpp rename to bsnes/sfc/coprocessor/obc1/obc1.cpp diff --git a/higan/sfc/coprocessor/obc1/obc1.hpp b/bsnes/sfc/coprocessor/obc1/obc1.hpp similarity index 100% rename from higan/sfc/coprocessor/obc1/obc1.hpp rename to bsnes/sfc/coprocessor/obc1/obc1.hpp diff --git a/higan/sfc/coprocessor/obc1/serialization.cpp b/bsnes/sfc/coprocessor/obc1/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/obc1/serialization.cpp rename to bsnes/sfc/coprocessor/obc1/serialization.cpp diff --git a/higan/sfc/coprocessor/sa1/bwram.cpp b/bsnes/sfc/coprocessor/sa1/bwram.cpp similarity index 100% rename from higan/sfc/coprocessor/sa1/bwram.cpp rename to bsnes/sfc/coprocessor/sa1/bwram.cpp diff --git a/higan/sfc/coprocessor/sa1/dma.cpp b/bsnes/sfc/coprocessor/sa1/dma.cpp similarity index 100% rename from higan/sfc/coprocessor/sa1/dma.cpp rename to bsnes/sfc/coprocessor/sa1/dma.cpp diff --git a/higan/sfc/coprocessor/sa1/io.cpp b/bsnes/sfc/coprocessor/sa1/io.cpp similarity index 100% rename from higan/sfc/coprocessor/sa1/io.cpp rename to bsnes/sfc/coprocessor/sa1/io.cpp diff --git a/higan/sfc/coprocessor/sa1/iram.cpp b/bsnes/sfc/coprocessor/sa1/iram.cpp similarity index 100% rename from higan/sfc/coprocessor/sa1/iram.cpp rename to bsnes/sfc/coprocessor/sa1/iram.cpp diff --git a/higan/sfc/coprocessor/sa1/memory.cpp b/bsnes/sfc/coprocessor/sa1/memory.cpp similarity index 100% rename from higan/sfc/coprocessor/sa1/memory.cpp rename to bsnes/sfc/coprocessor/sa1/memory.cpp diff --git a/higan/sfc/coprocessor/sa1/rom.cpp b/bsnes/sfc/coprocessor/sa1/rom.cpp similarity index 100% rename from higan/sfc/coprocessor/sa1/rom.cpp rename to bsnes/sfc/coprocessor/sa1/rom.cpp diff --git a/higan/sfc/coprocessor/sa1/sa1.cpp b/bsnes/sfc/coprocessor/sa1/sa1.cpp similarity index 100% rename from higan/sfc/coprocessor/sa1/sa1.cpp rename to bsnes/sfc/coprocessor/sa1/sa1.cpp diff --git a/higan/sfc/coprocessor/sa1/sa1.hpp b/bsnes/sfc/coprocessor/sa1/sa1.hpp similarity index 100% rename from higan/sfc/coprocessor/sa1/sa1.hpp rename to bsnes/sfc/coprocessor/sa1/sa1.hpp diff --git a/higan/sfc/coprocessor/sa1/serialization.cpp b/bsnes/sfc/coprocessor/sa1/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/sa1/serialization.cpp rename to bsnes/sfc/coprocessor/sa1/serialization.cpp diff --git a/higan/sfc/coprocessor/sdd1/decompressor.cpp b/bsnes/sfc/coprocessor/sdd1/decompressor.cpp similarity index 100% rename from higan/sfc/coprocessor/sdd1/decompressor.cpp rename to bsnes/sfc/coprocessor/sdd1/decompressor.cpp diff --git a/higan/sfc/coprocessor/sdd1/decompressor.hpp b/bsnes/sfc/coprocessor/sdd1/decompressor.hpp similarity index 100% rename from higan/sfc/coprocessor/sdd1/decompressor.hpp rename to bsnes/sfc/coprocessor/sdd1/decompressor.hpp diff --git a/higan/sfc/coprocessor/sdd1/sdd1.cpp b/bsnes/sfc/coprocessor/sdd1/sdd1.cpp similarity index 100% rename from higan/sfc/coprocessor/sdd1/sdd1.cpp rename to bsnes/sfc/coprocessor/sdd1/sdd1.cpp diff --git a/higan/sfc/coprocessor/sdd1/sdd1.hpp b/bsnes/sfc/coprocessor/sdd1/sdd1.hpp similarity index 100% rename from higan/sfc/coprocessor/sdd1/sdd1.hpp rename to bsnes/sfc/coprocessor/sdd1/sdd1.hpp diff --git a/higan/sfc/coprocessor/sdd1/serialization.cpp b/bsnes/sfc/coprocessor/sdd1/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/sdd1/serialization.cpp rename to bsnes/sfc/coprocessor/sdd1/serialization.cpp diff --git a/higan/sfc/coprocessor/sharprtc/memory.cpp b/bsnes/sfc/coprocessor/sharprtc/memory.cpp similarity index 100% rename from higan/sfc/coprocessor/sharprtc/memory.cpp rename to bsnes/sfc/coprocessor/sharprtc/memory.cpp diff --git a/higan/sfc/coprocessor/sharprtc/serialization.cpp b/bsnes/sfc/coprocessor/sharprtc/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/sharprtc/serialization.cpp rename to bsnes/sfc/coprocessor/sharprtc/serialization.cpp diff --git a/higan/sfc/coprocessor/sharprtc/sharprtc.cpp b/bsnes/sfc/coprocessor/sharprtc/sharprtc.cpp similarity index 100% rename from higan/sfc/coprocessor/sharprtc/sharprtc.cpp rename to bsnes/sfc/coprocessor/sharprtc/sharprtc.cpp diff --git a/higan/sfc/coprocessor/sharprtc/sharprtc.hpp b/bsnes/sfc/coprocessor/sharprtc/sharprtc.hpp similarity index 100% rename from higan/sfc/coprocessor/sharprtc/sharprtc.hpp rename to bsnes/sfc/coprocessor/sharprtc/sharprtc.hpp diff --git a/higan/sfc/coprocessor/sharprtc/time.cpp b/bsnes/sfc/coprocessor/sharprtc/time.cpp similarity index 100% rename from higan/sfc/coprocessor/sharprtc/time.cpp rename to bsnes/sfc/coprocessor/sharprtc/time.cpp diff --git a/higan/sfc/coprocessor/spc7110/alu.cpp b/bsnes/sfc/coprocessor/spc7110/alu.cpp similarity index 100% rename from higan/sfc/coprocessor/spc7110/alu.cpp rename to bsnes/sfc/coprocessor/spc7110/alu.cpp diff --git a/higan/sfc/coprocessor/spc7110/data.cpp b/bsnes/sfc/coprocessor/spc7110/data.cpp similarity index 100% rename from higan/sfc/coprocessor/spc7110/data.cpp rename to bsnes/sfc/coprocessor/spc7110/data.cpp diff --git a/higan/sfc/coprocessor/spc7110/dcu.cpp b/bsnes/sfc/coprocessor/spc7110/dcu.cpp similarity index 100% rename from higan/sfc/coprocessor/spc7110/dcu.cpp rename to bsnes/sfc/coprocessor/spc7110/dcu.cpp diff --git a/higan/sfc/coprocessor/spc7110/decompressor.cpp b/bsnes/sfc/coprocessor/spc7110/decompressor.cpp similarity index 100% rename from higan/sfc/coprocessor/spc7110/decompressor.cpp rename to bsnes/sfc/coprocessor/spc7110/decompressor.cpp diff --git a/higan/sfc/coprocessor/spc7110/serialization.cpp b/bsnes/sfc/coprocessor/spc7110/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/spc7110/serialization.cpp rename to bsnes/sfc/coprocessor/spc7110/serialization.cpp diff --git a/higan/sfc/coprocessor/spc7110/spc7110.cpp b/bsnes/sfc/coprocessor/spc7110/spc7110.cpp similarity index 100% rename from higan/sfc/coprocessor/spc7110/spc7110.cpp rename to bsnes/sfc/coprocessor/spc7110/spc7110.cpp diff --git a/higan/sfc/coprocessor/spc7110/spc7110.hpp b/bsnes/sfc/coprocessor/spc7110/spc7110.hpp similarity index 100% rename from higan/sfc/coprocessor/spc7110/spc7110.hpp rename to bsnes/sfc/coprocessor/spc7110/spc7110.hpp diff --git a/higan/sfc/coprocessor/st0010/data.hpp b/bsnes/sfc/coprocessor/st0010/data.hpp similarity index 100% rename from higan/sfc/coprocessor/st0010/data.hpp rename to bsnes/sfc/coprocessor/st0010/data.hpp diff --git a/higan/sfc/coprocessor/st0010/opcodes.cpp b/bsnes/sfc/coprocessor/st0010/opcodes.cpp similarity index 100% rename from higan/sfc/coprocessor/st0010/opcodes.cpp rename to bsnes/sfc/coprocessor/st0010/opcodes.cpp diff --git a/higan/sfc/coprocessor/st0010/serialization.cpp b/bsnes/sfc/coprocessor/st0010/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/st0010/serialization.cpp rename to bsnes/sfc/coprocessor/st0010/serialization.cpp diff --git a/higan/sfc/coprocessor/st0010/st0010.cpp b/bsnes/sfc/coprocessor/st0010/st0010.cpp similarity index 100% rename from higan/sfc/coprocessor/st0010/st0010.cpp rename to bsnes/sfc/coprocessor/st0010/st0010.cpp diff --git a/higan/sfc/coprocessor/st0010/st0010.hpp b/bsnes/sfc/coprocessor/st0010/st0010.hpp similarity index 100% rename from higan/sfc/coprocessor/st0010/st0010.hpp rename to bsnes/sfc/coprocessor/st0010/st0010.hpp diff --git a/higan/sfc/coprocessor/superfx/bus.cpp b/bsnes/sfc/coprocessor/superfx/bus.cpp similarity index 100% rename from higan/sfc/coprocessor/superfx/bus.cpp rename to bsnes/sfc/coprocessor/superfx/bus.cpp diff --git a/higan/sfc/coprocessor/superfx/core.cpp b/bsnes/sfc/coprocessor/superfx/core.cpp similarity index 100% rename from higan/sfc/coprocessor/superfx/core.cpp rename to bsnes/sfc/coprocessor/superfx/core.cpp diff --git a/higan/sfc/coprocessor/superfx/io.cpp b/bsnes/sfc/coprocessor/superfx/io.cpp similarity index 100% rename from higan/sfc/coprocessor/superfx/io.cpp rename to bsnes/sfc/coprocessor/superfx/io.cpp diff --git a/higan/sfc/coprocessor/superfx/memory.cpp b/bsnes/sfc/coprocessor/superfx/memory.cpp similarity index 100% rename from higan/sfc/coprocessor/superfx/memory.cpp rename to bsnes/sfc/coprocessor/superfx/memory.cpp diff --git a/higan/sfc/coprocessor/superfx/serialization.cpp b/bsnes/sfc/coprocessor/superfx/serialization.cpp similarity index 100% rename from higan/sfc/coprocessor/superfx/serialization.cpp rename to bsnes/sfc/coprocessor/superfx/serialization.cpp diff --git a/higan/sfc/coprocessor/superfx/superfx.cpp b/bsnes/sfc/coprocessor/superfx/superfx.cpp similarity index 100% rename from higan/sfc/coprocessor/superfx/superfx.cpp rename to bsnes/sfc/coprocessor/superfx/superfx.cpp diff --git a/higan/sfc/coprocessor/superfx/superfx.hpp b/bsnes/sfc/coprocessor/superfx/superfx.hpp similarity index 100% rename from higan/sfc/coprocessor/superfx/superfx.hpp rename to bsnes/sfc/coprocessor/superfx/superfx.hpp diff --git a/higan/sfc/coprocessor/superfx/timing.cpp b/bsnes/sfc/coprocessor/superfx/timing.cpp similarity index 100% rename from higan/sfc/coprocessor/superfx/timing.cpp rename to bsnes/sfc/coprocessor/superfx/timing.cpp diff --git a/higan/sfc/cpu/cpu.cpp b/bsnes/sfc/cpu/cpu.cpp similarity index 100% rename from higan/sfc/cpu/cpu.cpp rename to bsnes/sfc/cpu/cpu.cpp diff --git a/higan/sfc/cpu/cpu.hpp b/bsnes/sfc/cpu/cpu.hpp similarity index 99% rename from higan/sfc/cpu/cpu.hpp rename to bsnes/sfc/cpu/cpu.hpp index 9dc716ce..82e38f96 100644 --- a/higan/sfc/cpu/cpu.hpp +++ b/bsnes/sfc/cpu/cpu.hpp @@ -43,6 +43,7 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter { inline auto joypadCounter() const -> uint; auto step(uint clocks) -> void; + inline auto stepIdle(uint clocks) -> void; auto scanline() -> void; alwaysinline auto aluEdge() -> void; diff --git a/higan/sfc/cpu/dma.cpp b/bsnes/sfc/cpu/dma.cpp similarity index 100% rename from higan/sfc/cpu/dma.cpp rename to bsnes/sfc/cpu/dma.cpp diff --git a/higan/sfc/cpu/io.cpp b/bsnes/sfc/cpu/io.cpp similarity index 100% rename from higan/sfc/cpu/io.cpp rename to bsnes/sfc/cpu/io.cpp diff --git a/higan/sfc/cpu/irq.cpp b/bsnes/sfc/cpu/irq.cpp similarity index 100% rename from higan/sfc/cpu/irq.cpp rename to bsnes/sfc/cpu/irq.cpp diff --git a/higan/sfc/cpu/memory.cpp b/bsnes/sfc/cpu/memory.cpp similarity index 98% rename from higan/sfc/cpu/memory.cpp rename to bsnes/sfc/cpu/memory.cpp index d13577c7..4047f998 100644 --- a/higan/sfc/cpu/memory.cpp +++ b/bsnes/sfc/cpu/memory.cpp @@ -1,7 +1,7 @@ auto CPU::idle() -> void { status.clockCount = 6; dmaEdge(); - step(6); + stepIdle(6); aluEdge(); } diff --git a/higan/sfc/cpu/serialization.cpp b/bsnes/sfc/cpu/serialization.cpp similarity index 100% rename from higan/sfc/cpu/serialization.cpp rename to bsnes/sfc/cpu/serialization.cpp diff --git a/higan/sfc/cpu/timing.cpp b/bsnes/sfc/cpu/timing.cpp similarity index 86% rename from higan/sfc/cpu/timing.cpp rename to bsnes/sfc/cpu/timing.cpp index 7b7788be..ed47585d 100644 --- a/higan/sfc/cpu/timing.cpp +++ b/bsnes/sfc/cpu/timing.cpp @@ -44,6 +44,29 @@ auto CPU::step(uint clocks) -> void { for(auto coprocessor : coprocessors) synchronize(*coprocessor); } +auto CPU::stepIdle(uint clocks) -> void { + status.irqLock = false; + uint ticks = clocks >> 1; + while(ticks--) { + counter.cpu += 2; + tick(); + if(hcounter() & 2) pollInterrupts(); + if(joypadCounter() == 0) joypadEdge(); + } + + Thread::step(clocks); + + if(!status.dramRefresh && hcounter() >= status.dramRefreshPosition) { + //note: pattern should technically be 5-3, 5-3, 5-3, 5-3, 5-3 per logic analyzer + //result averages out the same as no coprocessor polls refresh() at > frequency()/2 + status.dramRefresh = 1; step(6); status.dramRefresh = 2; step(2); aluEdge(); + status.dramRefresh = 1; step(6); status.dramRefresh = 2; step(2); aluEdge(); + status.dramRefresh = 1; step(6); status.dramRefresh = 2; step(2); aluEdge(); + status.dramRefresh = 1; step(6); status.dramRefresh = 2; step(2); aluEdge(); + status.dramRefresh = 1; step(6); status.dramRefresh = 2; step(2); aluEdge(); + } +} + //called by ppu.tick() when Hcounter=0 auto CPU::scanline() -> void { status.lineClocks = lineclocks(); diff --git a/bsnes/sfc/dsp/SPC_DSP.cpp b/bsnes/sfc/dsp/SPC_DSP.cpp new file mode 100644 index 00000000..6d4f3094 --- /dev/null +++ b/bsnes/sfc/dsp/SPC_DSP.cpp @@ -0,0 +1,1046 @@ +// snes_spc 0.9.0. http://www.slack.net/~ant/ + +#include "SPC_DSP.h" + +#include "blargg_endian.h" +#include + +/* Copyright (C) 2007 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +#ifdef BLARGG_ENABLE_OPTIMIZER + #include BLARGG_ENABLE_OPTIMIZER +#endif + +#if INT_MAX < 0x7FFFFFFF + #error "Requires that int type have at least 32 bits" +#endif + +// TODO: add to blargg_endian.h +#define GET_LE16SA( addr ) ((BOOST::int16_t) GET_LE16( addr )) +#define GET_LE16A( addr ) GET_LE16( addr ) +#define SET_LE16A( addr, data ) SET_LE16( addr, data ) + +static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + +// 0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80, +// 0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF, +// 0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A, +// 0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF, +// 0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67, +// 0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x9C,0x4E,0x7B,0xFF, +// 0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F, +// 0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF +}; + +// if ( io < -32768 ) io = -32768; +// if ( io > 32767 ) io = 32767; +#define CLAMP16( io )\ +{\ + if ( (int16_t) io != io )\ + io = (io >> 31) ^ 0x7FFF;\ +} + +// Access global DSP register +#define REG(n) m.regs [r_##n] + +// Access voice DSP register +#define VREG(r,n) r [v_##n] + +#define WRITE_SAMPLES( l, r, out ) \ +{\ + out [0] = l;\ + out [1] = r;\ + out += 2;\ + if ( out >= m.out_end )\ + {\ + check( out == m.out_end );\ + check( m.out_end != &m.extra [extra_size] || \ + (m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\ + out = m.extra;\ + m.out_end = &m.extra [extra_size];\ + }\ +}\ + +void SPC_DSP::set_output( sample_t* out, int size ) +{ + require( (size & 1) == 0 ); // must be even + if ( !out ) + { + out = m.extra; + size = extra_size; + } + m.out_begin = out; + m.out = out; + m.out_end = out + size; +} + +// Volume registers and efb are signed! Easy to forget int8_t cast. +// Prefixes are to avoid accidental use of locals with same names. + +// Gaussian interpolation + +static short const gauss [512] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, + 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, + 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, + 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, + 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, + 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, + 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, + 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, + 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, + 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, + 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, + 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, + 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, + 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, + 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, + 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, + 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, + 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, + 969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036, +1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102, +1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160, +1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210, +1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251, +1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280, +1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298, +1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305, +}; + +inline int SPC_DSP::interpolate( voice_t const* v ) +{ + int out; + int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; + //in[3] is the newest sample, in[0] is the oldest sample + + if(configuration.hacks.dsp.cubic) { + float a = in[0] / 32768.0; + float b = in[1] / 32768.0; + float c = in[2] / 32768.0; + float d = in[3] / 32768.0; + + float A = d - c - a + b; + float B = a - b - A; + float C = c - a; + float D = b; + + float P = (v->interp_pos & 0xFFF) / 4096.0; + float O = (A * P * P * P) + (B * P * P) + (C * P) + (D); + + out = O * 32768.0; + } else { + // Make pointers into gaussian based on fractional position between samples + int offset = v->interp_pos >> 4 & 0xFF; + short const* fwd = gauss + 255 - offset; + short const* rev = gauss + offset; // mirror left half of gaussian + + out = (fwd [ 0] * in [0]) >> 11; + out += (fwd [256] * in [1]) >> 11; + out += (rev [256] * in [2]) >> 11; + out = (int16_t) out; + out += (rev [ 0] * in [3]) >> 11; + } + + CLAMP16( out ); + out &= ~1; + return out; +} + + +//// Counters + +int const simple_counter_range = 2048 * 5 * 3; // 30720 + +static unsigned const counter_rates [32] = +{ + simple_counter_range + 1, // never fires + 2048, 1536, + 1280, 1024, 768, + 640, 512, 384, + 320, 256, 192, + 160, 128, 96, + 80, 64, 48, + 40, 32, 24, + 20, 16, 12, + 10, 8, 6, + 5, 4, 3, + 2, + 1 +}; + +static unsigned const counter_offsets [32] = +{ + 1, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 0, + 0 +}; + +inline void SPC_DSP::init_counter() +{ + m.counter = 0; +} + +inline void SPC_DSP::run_counters() +{ + if ( --m.counter < 0 ) + m.counter = simple_counter_range - 1; +} + +inline unsigned SPC_DSP::read_counter( int rate ) +{ + return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate]; +} + + +//// Envelope + +inline void SPC_DSP::run_envelope( voice_t* const v ) +{ + int env = v->env; + if ( v->env_mode == env_release ) // 60% + { + if ( (env -= 0x8) < 0 ) + env = 0; + v->env = env; + } + else + { + int rate; + int env_data = VREG(v->regs,adsr1); + if ( m.t_adsr0 & 0x80 ) // 99% ADSR + { + if ( v->env_mode >= env_decay ) // 99% + { + env--; + env -= env >> 8; + rate = env_data & 0x1F; + if ( v->env_mode == env_decay ) // 1% + rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10; + } + else // env_attack + { + rate = (m.t_adsr0 & 0x0F) * 2 + 1; + env += rate < 31 ? 0x20 : 0x400; + } + } + else // GAIN + { + int mode; + env_data = VREG(v->regs,gain); + mode = env_data >> 5; + if ( mode < 4 ) // direct + { + env = env_data * 0x10; + rate = 31; + } + else + { + rate = env_data & 0x1F; + if ( mode == 4 ) // 4: linear decrease + { + env -= 0x20; + } + else if ( mode < 6 ) // 5: exponential decrease + { + env--; + env -= env >> 8; + } + else // 6,7: linear increase + { + env += 0x20; + if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 ) + env += 0x8 - 0x20; // 7: two-slope linear increase + } + } + } + + // Sustain level + if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay ) + v->env_mode = env_sustain; + + v->hidden_env = env; + + // unsigned cast because linear decrease going negative also triggers this + if ( (unsigned) env > 0x7FF ) + { + env = (env < 0 ? 0 : 0x7FF); + if ( v->env_mode == env_attack ) + v->env_mode = env_decay; + } + + if ( !read_counter( rate ) ) + v->env = env; // nothing else is controlled by the counter + } +} + + +//// BRR Decoding + +inline void SPC_DSP::decode_brr( voice_t* v ) +{ + // Arrange the four input nybbles in 0xABCD order for easy decoding + int nybbles = m.t_brr_byte * 0x100 + m.ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF]; + + int const header = m.t_brr_header; + + // Write to next four samples in circular buffer + int* pos = &v->buf [v->buf_pos]; + int* end; + if ( (v->buf_pos += 4) >= brr_buf_size ) + v->buf_pos = 0; + + // Decode four samples + for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 ) + { + // Extract nybble and sign-extend + int s = (int16_t) nybbles >> 12; + + // Shift sample based on header + int const shift = header >> 4; + s = (s << shift) >> 1; + if ( shift >= 0xD ) // handle invalid range + s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0) + + // Apply IIR filter (8 is the most commonly used) + int const filter = header & 0x0C; + int const p1 = pos [brr_buf_size - 1]; + int const p2 = pos [brr_buf_size - 2] >> 1; + if ( filter >= 8 ) + { + s += p1; + s -= p2; + if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875 + { + s += p2 >> 4; + s += (p1 * -3) >> 6; + } + else // s += p1 * 0.8984375 - p2 * 0.40625 + { + s += (p1 * -13) >> 7; + s += (p2 * 3) >> 4; + } + } + else if ( filter ) // s += p1 * 0.46875 + { + s += p1 >> 1; + s += (-p1) >> 5; + } + + // Adjust and write sample + CLAMP16( s ); + s = (int16_t) (s * 2); + pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around + } +} + + +//// Misc + +#define MISC_CLOCK( n ) inline void SPC_DSP::misc_##n() + +MISC_CLOCK( 27 ) +{ + m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON +} +MISC_CLOCK( 28 ) +{ + m.t_non = REG(non); + m.t_eon = REG(eon); + m.t_dir = REG(dir); +} +MISC_CLOCK( 29 ) +{ + if ( (m.every_other_sample ^= 1) != 0 ) + m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read +} +MISC_CLOCK( 30 ) +{ + if ( m.every_other_sample ) + { + m.kon = m.new_kon; + m.t_koff = REG(koff) | m.mute_mask; + } + + run_counters(); + + // Noise + if ( !read_counter( REG(flg) & 0x1F ) ) + { + int feedback = (m.noise << 13) ^ (m.noise << 14); + m.noise = (feedback & 0x4000) ^ (m.noise >> 1); + } +} + + +//// Voices + +#define VOICE_CLOCK( n ) void SPC_DSP::voice_##n( voice_t* const v ) + +inline VOICE_CLOCK( V1 ) +{ + m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4; + m.t_srcn = VREG(v->regs,srcn); +} +inline VOICE_CLOCK( V2 ) +{ + // Read sample pointer (ignored if not needed) + uint8_t const* entry = &m.ram [m.t_dir_addr]; + if ( !v->kon_delay ) + entry += 2; + m.t_brr_next_addr = GET_LE16A( entry ); + + m.t_adsr0 = VREG(v->regs,adsr0); + + // Read pitch, spread over two clocks + m.t_pitch = VREG(v->regs,pitchl); +} +inline VOICE_CLOCK( V3a ) +{ + m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8; +} +inline VOICE_CLOCK( V3b ) +{ + // Read BRR header and byte + m.t_brr_byte = m.ram [(v->brr_addr + v->brr_offset) & 0xFFFF]; + m.t_brr_header = m.ram [v->brr_addr]; // brr_addr doesn't need masking +} +VOICE_CLOCK( V3c ) +{ + // Pitch modulation using previous voice's output + if ( m.t_pmon & v->vbit ) + m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10; + + if ( v->kon_delay ) + { + // Get ready to start BRR decoding on next sample + if ( v->kon_delay == 5 ) + { + v->brr_addr = m.t_brr_next_addr; + v->brr_offset = 1; + v->buf_pos = 0; + m.t_brr_header = 0; // header is ignored on this sample + m.kon_check = true; + } + + // Envelope is never run during KON + v->env = 0; + v->hidden_env = 0; + + // Disable BRR decoding until last three samples + v->interp_pos = 0; + if ( --v->kon_delay & 3 ) + v->interp_pos = 0x4000; + + // Pitch is never added during KON + m.t_pitch = 0; + } + + // Gaussian interpolation + { + int output = interpolate( v ); + + // Noise + if ( m.t_non & v->vbit ) + output = (int16_t) (m.noise * 2); + + // Apply envelope + m.t_output = (output * v->env) >> 11 & ~1; + v->t_envx_out = (uint8_t) (v->env >> 4); + } + + // Immediate silence due to end of sample or soft reset + if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 ) + { + v->env_mode = env_release; + v->env = 0; + } + + if ( m.every_other_sample ) + { + // KOFF + if ( m.t_koff & v->vbit ) + v->env_mode = env_release; + + // KON + if ( m.kon & v->vbit ) + { + v->kon_delay = 5; + v->env_mode = env_attack; + } + } + + // Run envelope for next sample + if ( !v->kon_delay ) + run_envelope( v ); +} +inline void SPC_DSP::voice_output( voice_t const* v, int ch ) +{ + // Apply left/right volume + int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7; + + // Add to output total + m.t_main_out [ch] += amp; + CLAMP16( m.t_main_out [ch] ); + + // Optionally add to echo total + if ( m.t_eon & v->vbit ) + { + m.t_echo_out [ch] += amp; + CLAMP16( m.t_echo_out [ch] ); + } +} +VOICE_CLOCK( V4 ) +{ + // Decode BRR + m.t_looped = 0; + if ( v->interp_pos >= 0x4000 ) + { + decode_brr( v ); + + if ( (v->brr_offset += 2) >= brr_block_size ) + { + // Start decoding next BRR block + assert( v->brr_offset == brr_block_size ); + v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF; + if ( m.t_brr_header & 1 ) + { + v->brr_addr = m.t_brr_next_addr; + m.t_looped = v->vbit; + } + v->brr_offset = 1; + } + } + + // Apply pitch + v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch; + + // Keep from getting too far ahead (when using pitch modulation) + if ( v->interp_pos > 0x7FFF ) + v->interp_pos = 0x7FFF; + + // Output left + voice_output( v, 0 ); +} +inline VOICE_CLOCK( V5 ) +{ + // Output right + voice_output( v, 1 ); + + // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier + int endx_buf = REG(endx) | m.t_looped; + + // Clear bit in ENDX if KON just began + if ( v->kon_delay == 5 ) + endx_buf &= ~v->vbit; + m.endx_buf = (uint8_t) endx_buf; +} +inline VOICE_CLOCK( V6 ) +{ + (void) v; // avoid compiler warning about unused v + m.outx_buf = (uint8_t) (m.t_output >> 8); +} +inline VOICE_CLOCK( V7 ) +{ + // Update ENDX + REG(endx) = m.endx_buf; + + m.envx_buf = v->t_envx_out; +} +inline VOICE_CLOCK( V8 ) +{ + // Update OUTX + VREG(v->regs,outx) = m.outx_buf; +} +inline VOICE_CLOCK( V9 ) +{ + // Update ENVX + VREG(v->regs,envx) = m.envx_buf; +} + +// Most voices do all these in one clock, so make a handy composite +inline VOICE_CLOCK( V3 ) +{ + voice_V3a( v ); + voice_V3b( v ); + voice_V3c( v ); +} + +// Common combinations of voice steps on different voices. This greatly reduces +// code size and allows everything to be inlined in these functions. +VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); } +VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); } +VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } + + +//// Echo + +// Current echo buffer pointer for left/right channel +#define ECHO_PTR( ch ) (&m.ram [m.t_echo_ptr + ch * 2]) + +// Sample in echo history buffer, where 0 is the oldest +#define ECHO_FIR( i ) (m.echo_hist_pos [i]) + +// Calculate FIR point for left/right channel +#define CALC_FIR( i, ch ) ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6) + +#define ECHO_CLOCK( n ) inline void SPC_DSP::echo_##n() + +inline void SPC_DSP::echo_read( int ch ) +{ + int s = GET_LE16SA( ECHO_PTR( ch ) ); + // second copy simplifies wrap-around handling + ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1; +} + +ECHO_CLOCK( 22 ) +{ + // History + if ( ++m.echo_hist_pos >= &m.echo_hist [echo_hist_size] ) + m.echo_hist_pos = m.echo_hist; + + m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF; + echo_read( 0 ); + + // FIR (using l and r temporaries below helps compiler optimize) + int l = CALC_FIR( 0, 0 ); + int r = CALC_FIR( 0, 1 ); + + m.t_echo_in [0] = l; + m.t_echo_in [1] = r; +} +ECHO_CLOCK( 23 ) +{ + int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 ); + int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 ); + + m.t_echo_in [0] += l; + m.t_echo_in [1] += r; + + echo_read( 1 ); +} +ECHO_CLOCK( 24 ) +{ + int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 ); + int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 ); + + m.t_echo_in [0] += l; + m.t_echo_in [1] += r; +} +ECHO_CLOCK( 25 ) +{ + int l = m.t_echo_in [0] + CALC_FIR( 6, 0 ); + int r = m.t_echo_in [1] + CALC_FIR( 6, 1 ); + + l = (int16_t) l; + r = (int16_t) r; + + l += (int16_t) CALC_FIR( 7, 0 ); + r += (int16_t) CALC_FIR( 7, 1 ); + + CLAMP16( l ); + CLAMP16( r ); + + m.t_echo_in [0] = l & ~1; + m.t_echo_in [1] = r & ~1; +} +inline int SPC_DSP::echo_output( int ch ) +{ + int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) + + (int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7); + CLAMP16( out ); + return out; +} +ECHO_CLOCK( 26 ) +{ + // Left output volumes + // (save sample for next clock so we can output both together) + m.t_main_out [0] = echo_output( 0 ); + + // Echo feedback + int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7); + int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7); + + CLAMP16( l ); + CLAMP16( r ); + + m.t_echo_out [0] = l & ~1; + m.t_echo_out [1] = r & ~1; +} +ECHO_CLOCK( 27 ) +{ + // Output + int l = m.t_main_out [0]; + int r = echo_output( 1 ); + m.t_main_out [0] = 0; + m.t_main_out [1] = 0; + + // TODO: global muting isn't this simple (turns DAC on and off + // or something, causing small ~37-sample pulse when first muted) + if ( REG(flg) & 0x40 ) + { + l = 0; + r = 0; + } + + // Output sample to DAC + #ifdef SPC_DSP_OUT_HOOK + SPC_DSP_OUT_HOOK( l, r ); + #else + sample_t* out = m.out; + WRITE_SAMPLES( l, r, out ); + m.out = out; + #endif +} +ECHO_CLOCK( 28 ) +{ + m.t_echo_enabled = REG(flg); +} +inline void SPC_DSP::echo_write( int ch ) +{ + if ( !(m.t_echo_enabled & 0x20) ) + SET_LE16A( ECHO_PTR( ch ), m.t_echo_out [ch] ); + m.t_echo_out [ch] = 0; +} +ECHO_CLOCK( 29 ) +{ + m.t_esa = REG(esa); + + if ( !m.echo_offset ) + m.echo_length = (REG(edl) & 0x0F) * 0x800; + + m.echo_offset += 4; + if ( m.echo_offset >= m.echo_length ) + m.echo_offset = 0; + + // Write left echo + echo_write( 0 ); + + m.t_echo_enabled = REG(flg); +} +ECHO_CLOCK( 30 ) +{ + // Write right echo + echo_write( 1 ); +} + + +//// Timing + +// Execute clock for a particular voice +#define V( clock, voice ) voice_##clock( &m.voices [voice] ); + +/* The most common sequence of clocks uses composite operations +for efficiency. For example, the following are equivalent to the +individual steps on the right: + +V(V7_V4_V1,2) -> V(V7,2) V(V4,3) V(V1,5) +V(V8_V5_V2,2) -> V(V8,2) V(V5,3) V(V2,4) +V(V9_V6_V3,2) -> V(V9,2) V(V6,3) V(V3,4) */ + +// Voice 0 1 2 3 4 5 6 7 +#define GEN_DSP_TIMING \ +PHASE( 0) V(V5,0)V(V2,1)\ +PHASE( 1) V(V6,0)V(V3,1)\ +PHASE( 2) V(V7_V4_V1,0)\ +PHASE( 3) V(V8_V5_V2,0)\ +PHASE( 4) V(V9_V6_V3,0)\ +PHASE( 5) V(V7_V4_V1,1)\ +PHASE( 6) V(V8_V5_V2,1)\ +PHASE( 7) V(V9_V6_V3,1)\ +PHASE( 8) V(V7_V4_V1,2)\ +PHASE( 9) V(V8_V5_V2,2)\ +PHASE(10) V(V9_V6_V3,2)\ +PHASE(11) V(V7_V4_V1,3)\ +PHASE(12) V(V8_V5_V2,3)\ +PHASE(13) V(V9_V6_V3,3)\ +PHASE(14) V(V7_V4_V1,4)\ +PHASE(15) V(V8_V5_V2,4)\ +PHASE(16) V(V9_V6_V3,4)\ +PHASE(17) V(V1,0) V(V7,5)V(V4,6)\ +PHASE(18) V(V8_V5_V2,5)\ +PHASE(19) V(V9_V6_V3,5)\ +PHASE(20) V(V1,1) V(V7,6)V(V4,7)\ +PHASE(21) V(V8,6)V(V5,7) V(V2,0) /* t_brr_next_addr order dependency */\ +PHASE(22) V(V3a,0) V(V9,6)V(V6,7) echo_22();\ +PHASE(23) V(V7,7) echo_23();\ +PHASE(24) V(V8,7) echo_24();\ +PHASE(25) V(V3b,0) V(V9,7) echo_25();\ +PHASE(26) echo_26();\ +PHASE(27) misc_27(); echo_27();\ +PHASE(28) misc_28(); echo_28();\ +PHASE(29) misc_29(); echo_29();\ +PHASE(30) misc_30();V(V3c,0) echo_30();\ +PHASE(31) V(V4,0) V(V1,2)\ + +#if !SPC_DSP_CUSTOM_RUN + +void SPC_DSP::run( int clocks_remain ) +{ + require( clocks_remain > 0 ); + + int const phase = m.phase; + m.phase = (phase + clocks_remain) & 31; + switch ( phase ) + { + loop: + + #define PHASE( n ) if ( n && !--clocks_remain ) break; case n: + GEN_DSP_TIMING + #undef PHASE + + if ( --clocks_remain ) + goto loop; + } +} + +#endif + + +//// Setup + +void SPC_DSP::init( void* ram_64k ) +{ + m.ram = (uint8_t*) ram_64k; + mute_voices( 0 ); + disable_surround( false ); + set_output( 0, 0 ); + reset(); + + #ifndef NDEBUG + // be sure this sign-extends + assert( (int16_t) 0x8000 == -0x8000 ); + + // be sure right shift preserves sign + assert( (-1 >> 1) == -1 ); + + // check clamp macro + int i; + i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF ); + i = -0x8001; CLAMP16( i ); assert( i == -0x8000 ); + + blargg_verify_byte_order(); + #endif +} + +void SPC_DSP::soft_reset_common() +{ + require( m.ram ); // init() must have been called already + + m.noise = 0x4000; + m.echo_hist_pos = m.echo_hist; + m.every_other_sample = 1; + m.echo_offset = 0; + m.phase = 0; + + init_counter(); +} + +void SPC_DSP::soft_reset() +{ + REG(flg) = 0xE0; + soft_reset_common(); +} + +void SPC_DSP::load( uint8_t const regs [register_count] ) +{ + memcpy( m.regs, regs, sizeof m.regs ); + memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count ); + + // Internal state + for ( int i = voice_count; --i >= 0; ) + { + voice_t* v = &m.voices [i]; + v->brr_offset = 1; + v->vbit = 1 << i; + v->regs = &m.regs [i * 0x10]; + } + m.new_kon = REG(kon); + m.t_dir = REG(dir); + m.t_esa = REG(esa); + + soft_reset_common(); +} + +void SPC_DSP::reset() { load( initial_regs ); } + + +//// State save/load + +#if !SPC_NO_COPY_STATE_FUNCS + +void SPC_State_Copier::copy( void* state, size_t size ) +{ + func( buf, state, size ); +} + +int SPC_State_Copier::copy_int( int state, int size ) +{ + BOOST::uint8_t s [2]; + SET_LE16( s, state ); + func( buf, &s, size ); + return GET_LE16( s ); +} + +void SPC_State_Copier::skip( int count ) +{ + if ( count > 0 ) + { + char temp [64]; + memset( temp, 0, sizeof temp ); + do + { + int n = sizeof temp; + if ( n > count ) + n = count; + count -= n; + func( buf, temp, n ); + } + while ( count ); + } +} + +void SPC_State_Copier::extra() +{ + int n = 0; + SPC_State_Copier& copier = *this; + SPC_COPY( uint8_t, n ); + skip( n ); +} + +void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) +{ + SPC_State_Copier copier( io, copy ); + + // DSP registers + copier.copy( m.regs, register_count ); + + // Internal state + + // Voices + int i; + for ( i = 0; i < voice_count; i++ ) + { + voice_t* v = &m.voices [i]; + + // BRR buffer + int i; + for ( i = 0; i < brr_buf_size; i++ ) + { + int s = v->buf [i]; + SPC_COPY( int16_t, s ); + v->buf [i] = v->buf [i + brr_buf_size] = s; + } + + SPC_COPY( uint16_t, v->interp_pos ); + SPC_COPY( uint16_t, v->brr_addr ); + SPC_COPY( uint16_t, v->env ); + SPC_COPY( int16_t, v->hidden_env ); + SPC_COPY( uint8_t, v->buf_pos ); + SPC_COPY( uint8_t, v->brr_offset ); + SPC_COPY( uint8_t, v->kon_delay ); + { + int m = v->env_mode; + SPC_COPY( uint8_t, m ); + v->env_mode = (enum env_mode_t) m; + } + SPC_COPY( uint8_t, v->t_envx_out ); + + copier.extra(); + } + + // Echo history + for ( i = 0; i < echo_hist_size; i++ ) + { + int j; + for ( j = 0; j < 2; j++ ) + { + int s = m.echo_hist_pos [i] [j]; + SPC_COPY( int16_t, s ); + m.echo_hist [i] [j] = s; // write back at offset 0 + } + } + m.echo_hist_pos = m.echo_hist; + memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] ); + + // Misc + SPC_COPY( uint8_t, m.every_other_sample ); + SPC_COPY( uint8_t, m.kon ); + + SPC_COPY( uint16_t, m.noise ); + SPC_COPY( uint16_t, m.counter ); + SPC_COPY( uint16_t, m.echo_offset ); + SPC_COPY( uint16_t, m.echo_length ); + SPC_COPY( uint8_t, m.phase ); + + SPC_COPY( uint8_t, m.new_kon ); + SPC_COPY( uint8_t, m.endx_buf ); + SPC_COPY( uint8_t, m.envx_buf ); + SPC_COPY( uint8_t, m.outx_buf ); + + SPC_COPY( uint8_t, m.t_pmon ); + SPC_COPY( uint8_t, m.t_non ); + SPC_COPY( uint8_t, m.t_eon ); + SPC_COPY( uint8_t, m.t_dir ); + SPC_COPY( uint8_t, m.t_koff ); + + SPC_COPY( uint16_t, m.t_brr_next_addr ); + SPC_COPY( uint8_t, m.t_adsr0 ); + SPC_COPY( uint8_t, m.t_brr_header ); + SPC_COPY( uint8_t, m.t_brr_byte ); + SPC_COPY( uint8_t, m.t_srcn ); + SPC_COPY( uint8_t, m.t_esa ); + SPC_COPY( uint8_t, m.t_echo_enabled ); + + SPC_COPY( int16_t, m.t_main_out [0] ); + SPC_COPY( int16_t, m.t_main_out [1] ); + SPC_COPY( int16_t, m.t_echo_out [0] ); + SPC_COPY( int16_t, m.t_echo_out [1] ); + SPC_COPY( int16_t, m.t_echo_in [0] ); + SPC_COPY( int16_t, m.t_echo_in [1] ); + + SPC_COPY( uint16_t, m.t_dir_addr ); + SPC_COPY( uint16_t, m.t_pitch ); + SPC_COPY( int16_t, m.t_output ); + SPC_COPY( uint16_t, m.t_echo_ptr ); + SPC_COPY( uint8_t, m.t_looped ); + + copier.extra(); +} +#endif diff --git a/bsnes/sfc/dsp/SPC_DSP.h b/bsnes/sfc/dsp/SPC_DSP.h new file mode 100644 index 00000000..4522ace9 --- /dev/null +++ b/bsnes/sfc/dsp/SPC_DSP.h @@ -0,0 +1,304 @@ +// Highly accurate SNES SPC-700 DSP emulator + +// snes_spc 0.9.0 +#ifndef SPC_DSP_H +#define SPC_DSP_H + +#include "blargg_common.h" + +extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); } + +class SPC_DSP { +public: + typedef BOOST::uint8_t uint8_t; + +// Setup + + // Initializes DSP and has it use the 64K RAM provided + void init( void* ram_64k ); + + // Sets destination for output samples. If out is NULL or out_size is 0, + // doesn't generate any. + typedef short sample_t; + void set_output( sample_t* out, int out_size ); + + // Number of samples written to output since it was last set, always + // a multiple of 2. Undefined if more samples were generated than + // output buffer could hold. + int sample_count() const; + +// Emulation + + // Resets DSP to power-on state + void reset(); + + // Emulates pressing reset switch on SNES + void soft_reset(); + + // Reads/writes DSP registers. For accuracy, you must first call run() + // to catch the DSP up to present. + int read ( int addr ) const; + void write( int addr, int data ); + + // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks + // a pair of samples is be generated. + void run( int clock_count ); + +// Sound control + + // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). + // Reduces emulation accuracy. + enum { voice_count = 8 }; + void mute_voices( int mask ); + +// State + + // Resets DSP and uses supplied values to initialize registers + enum { register_count = 128 }; + void load( uint8_t const regs [register_count] ); + + // Saves/loads exact emulator state + enum { state_size = 640 }; // maximum space needed when saving + typedef dsp_copy_func_t copy_func_t; + void copy_state( unsigned char** io, copy_func_t ); + + // Returns non-zero if new key-on events occurred since last call + bool check_kon(); + +// DSP register addresses + + // Global registers + enum { + r_mvoll = 0x0C, r_mvolr = 0x1C, + r_evoll = 0x2C, r_evolr = 0x3C, + r_kon = 0x4C, r_koff = 0x5C, + r_flg = 0x6C, r_endx = 0x7C, + r_efb = 0x0D, r_pmon = 0x2D, + r_non = 0x3D, r_eon = 0x4D, + r_dir = 0x5D, r_esa = 0x6D, + r_edl = 0x7D, + r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F + }; + + // Voice registers + enum { + v_voll = 0x00, v_volr = 0x01, + v_pitchl = 0x02, v_pitchh = 0x03, + v_srcn = 0x04, v_adsr0 = 0x05, + v_adsr1 = 0x06, v_gain = 0x07, + v_envx = 0x08, v_outx = 0x09 + }; + +public: + enum { extra_size = 16 }; + sample_t* extra() { return m.extra; } + sample_t const* out_pos() const { return m.out; } + void disable_surround( bool ) { } // not supported +public: + BLARGG_DISABLE_NOTHROW + + typedef BOOST::int8_t int8_t; + typedef BOOST::int16_t int16_t; + + enum { echo_hist_size = 8 }; + + enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; + enum { brr_buf_size = 12 }; + struct voice_t + { + int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling) + int buf_pos; // place in buffer where next samples will be decoded + int interp_pos; // relative fractional position in sample (0x1000 = 1.0) + int brr_addr; // address of current BRR block + int brr_offset; // current decoding offset in BRR block + uint8_t* regs; // pointer to voice's DSP registers + int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc. + int kon_delay; // KON delay/current setup phase + env_mode_t env_mode; + int env; // current envelope level + int hidden_env; // used by GAIN mode 7, very obscure quirk + uint8_t t_envx_out; + }; +private: + enum { brr_block_size = 9 }; + + struct state_t + { + uint8_t regs [register_count]; + + // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling) + int echo_hist [echo_hist_size * 2] [2]; + int (*echo_hist_pos) [2]; // &echo_hist [0 to 7] + + int every_other_sample; // toggles every sample + int kon; // KON value when last checked + int noise; + int counter; + int echo_offset; // offset from ESA in echo buffer + int echo_length; // number of bytes that echo_offset will stop at + int phase; // next clock cycle to run (0-31) + bool kon_check; // set when a new KON occurs + + // Hidden registers also written to when main register is written to + int new_kon; + uint8_t endx_buf; + uint8_t envx_buf; + uint8_t outx_buf; + + // Temporary state between clocks + + // read once per sample + int t_pmon; + int t_non; + int t_eon; + int t_dir; + int t_koff; + + // read a few clocks ahead then used + int t_brr_next_addr; + int t_adsr0; + int t_brr_header; + int t_brr_byte; + int t_srcn; + int t_esa; + int t_echo_enabled; + + // internal state that is recalculated every sample + int t_dir_addr; + int t_pitch; + int t_output; + int t_looped; + int t_echo_ptr; + + // left/right sums + int t_main_out [2]; + int t_echo_out [2]; + int t_echo_in [2]; + + voice_t voices [voice_count]; + + // non-emulation state + uint8_t* ram; // 64K shared RAM between DSP and SMP + int mute_mask; + sample_t* out; + sample_t* out_end; + sample_t* out_begin; + sample_t extra [extra_size]; + }; + state_t m; + + void init_counter(); + void run_counters(); + unsigned read_counter( int rate ); + + int interpolate( voice_t const* v ); + void run_envelope( voice_t* const v ); + void decode_brr( voice_t* v ); + + void misc_27(); + void misc_28(); + void misc_29(); + void misc_30(); + + void voice_output( voice_t const* v, int ch ); + void voice_V1( voice_t* const ); + void voice_V2( voice_t* const ); + void voice_V3( voice_t* const ); + void voice_V3a( voice_t* const ); + void voice_V3b( voice_t* const ); + void voice_V3c( voice_t* const ); + void voice_V4( voice_t* const ); + void voice_V5( voice_t* const ); + void voice_V6( voice_t* const ); + void voice_V7( voice_t* const ); + void voice_V8( voice_t* const ); + void voice_V9( voice_t* const ); + void voice_V7_V4_V1( voice_t* const ); + void voice_V8_V5_V2( voice_t* const ); + void voice_V9_V6_V3( voice_t* const ); + + void echo_read( int ch ); + int echo_output( int ch ); + void echo_write( int ch ); + void echo_22(); + void echo_23(); + void echo_24(); + void echo_25(); + void echo_26(); + void echo_27(); + void echo_28(); + void echo_29(); + void echo_30(); + + void soft_reset_common(); +}; + +#include + +inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; } + +inline int SPC_DSP::read( int addr ) const +{ + assert( (unsigned) addr < register_count ); + return m.regs [addr]; +} + +inline void SPC_DSP::write( int addr, int data ) +{ + assert( (unsigned) addr < register_count ); + + m.regs [addr] = (uint8_t) data; + switch ( addr & 0x0F ) + { + case v_envx: + m.envx_buf = (uint8_t) data; + break; + + case v_outx: + m.outx_buf = (uint8_t) data; + break; + + case 0x0C: + if ( addr == r_kon ) + m.new_kon = (uint8_t) data; + + if ( addr == r_endx ) // always cleared, regardless of data written + { + m.endx_buf = 0; + m.regs [r_endx] = 0; + } + break; + } +} + +inline void SPC_DSP::mute_voices( int mask ) { m.mute_mask = mask; } + +inline bool SPC_DSP::check_kon() +{ + bool old = m.kon_check; + m.kon_check = 0; + return old; +} + +#if !SPC_NO_COPY_STATE_FUNCS + +class SPC_State_Copier { + SPC_DSP::copy_func_t func; + unsigned char** buf; +public: + SPC_State_Copier( unsigned char** p, SPC_DSP::copy_func_t f ) { func = f; buf = p; } + void copy( void* state, size_t size ); + int copy_int( int state, int size ); + void skip( int count ); + void extra(); +}; + +#define SPC_COPY( type, state )\ +{\ + state = (BOOST::type) copier.copy_int( state, sizeof (BOOST::type) );\ + assert( (BOOST::type) state == state );\ +} + +#endif + +#endif diff --git a/bsnes/sfc/dsp/blargg_common.h b/bsnes/sfc/dsp/blargg_common.h new file mode 100644 index 00000000..75edff39 --- /dev/null +++ b/bsnes/sfc/dsp/blargg_common.h @@ -0,0 +1,186 @@ +// Sets up common environment for Shay Green's libraries. +// To change configuration options, modify blargg_config.h, not this file. + +// snes_spc 0.9.0 +#ifndef BLARGG_COMMON_H +#define BLARGG_COMMON_H + +#include +#include +#include +#include + +#undef BLARGG_COMMON_H +// allow blargg_config.h to #include blargg_common.h +#include "blargg_config.h" +#ifndef BLARGG_COMMON_H +#define BLARGG_COMMON_H + +// BLARGG_RESTRICT: equivalent to restrict, where supported +#if defined (__GNUC__) || _MSC_VER >= 1100 + #define BLARGG_RESTRICT __restrict +#else + #define BLARGG_RESTRICT +#endif + +// STATIC_CAST(T,expr): Used in place of static_cast (expr) +#ifndef STATIC_CAST + #define STATIC_CAST(T,expr) ((T) (expr)) +#endif + +// blargg_err_t (0 on success, otherwise error string) +#ifndef blargg_err_t + typedef const char* blargg_err_t; +#endif + +// blargg_vector - very lightweight vector of POD types (no constructor/destructor) +template +class blargg_vector { + T* begin_; + size_t size_; +public: + blargg_vector() : begin_( 0 ), size_( 0 ) { } + ~blargg_vector() { free( begin_ ); } + size_t size() const { return size_; } + T* begin() const { return begin_; } + T* end() const { return begin_ + size_; } + blargg_err_t resize( size_t n ) + { + // TODO: blargg_common.cpp to hold this as an outline function, ugh + void* p = realloc( begin_, n * sizeof (T) ); + if ( p ) + begin_ = (T*) p; + else if ( n > size_ ) // realloc failure only a problem if expanding + return "Out of memory"; + size_ = n; + return 0; + } + void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); } + T& operator [] ( size_t n ) const + { + assert( n <= size_ ); // <= to allow past-the-end value + return begin_ [n]; + } +}; + +#ifndef BLARGG_DISABLE_NOTHROW + // throw spec mandatory in ISO C++ if operator new can return NULL + #if __cplusplus >= 199711 || defined (__GNUC__) + #define BLARGG_THROWS( spec ) throw spec + #else + #define BLARGG_THROWS( spec ) + #endif + #define BLARGG_DISABLE_NOTHROW \ + void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ + void operator delete ( void* p ) { free( p ); } + #define BLARGG_NEW new +#else + #include + #define BLARGG_NEW new (std::nothrow) +#endif + +// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant) +#define BLARGG_4CHAR( a, b, c, d ) \ + ((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF)) + +// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0. +#ifndef BOOST_STATIC_ASSERT + #ifdef _MSC_VER + // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified + #define BOOST_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) + #else + // Some other compilers fail when declaring same function multiple times in class, + // so differentiate them by line + #define BOOST_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) + #endif +#endif + +// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1, +// compiler is assumed to support bool. If undefined, availability is determined. +#ifndef BLARGG_COMPILER_HAS_BOOL + #if defined (__MWERKS__) + #if !__option(bool) + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif + #elif defined (_MSC_VER) + #if _MSC_VER < 1100 + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif + #elif defined (__GNUC__) + // supports bool + #elif __cplusplus < 199711 + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif +#endif +#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL + // If you get errors here, modify your blargg_config.h file + typedef int bool; + const bool true = 1; + const bool false = 0; +#endif + +// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough + +#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF + typedef long blargg_long; +#else + typedef int blargg_long; +#endif + +#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF + typedef unsigned long blargg_ulong; +#else + typedef unsigned blargg_ulong; +#endif + +// BOOST::int8_t etc. + +// HAVE_STDINT_H: If defined, use for int8_t etc. +#if defined (HAVE_STDINT_H) + #include + #define BOOST + +// HAVE_INTTYPES_H: If defined, use for int8_t etc. +#elif defined (HAVE_INTTYPES_H) + #include + #define BOOST + +#else + struct BOOST + { + #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F + typedef signed char int8_t; + typedef unsigned char uint8_t; + #else + // No suitable 8-bit type available + typedef struct see_blargg_common_h int8_t; + typedef struct see_blargg_common_h uint8_t; + #endif + + #if USHRT_MAX == 0xFFFF + typedef short int16_t; + typedef unsigned short uint16_t; + #else + // No suitable 16-bit type available + typedef struct see_blargg_common_h int16_t; + typedef struct see_blargg_common_h uint16_t; + #endif + + #if ULONG_MAX == 0xFFFFFFFF + typedef long int32_t; + typedef unsigned long uint32_t; + #elif UINT_MAX == 0xFFFFFFFF + typedef int int32_t; + typedef unsigned int uint32_t; + #else + // No suitable 32-bit type available + typedef struct see_blargg_common_h int32_t; + typedef struct see_blargg_common_h uint32_t; + #endif + }; +#endif + +#endif +#endif diff --git a/bsnes/sfc/dsp/blargg_config.h b/bsnes/sfc/dsp/blargg_config.h new file mode 100644 index 00000000..94570ca0 --- /dev/null +++ b/bsnes/sfc/dsp/blargg_config.h @@ -0,0 +1,26 @@ +// snes_spc 0.9.0 user configuration file. Don't replace when updating library. + +// snes_spc 0.9.0 +#ifndef BLARGG_CONFIG_H +#define BLARGG_CONFIG_H + +// Uncomment to disable debugging checks +#ifndef NDEBUG + #define NDEBUG 1 +#endif + +// Uncomment to enable platform-specific (and possibly non-portable) optimizations +//#define BLARGG_NONPORTABLE 1 + +// Uncomment if automatic byte-order determination doesn't work +//#define BLARGG_BIG_ENDIAN 1 + +// Uncomment if you get errors in the bool section of blargg_common.h +//#define BLARGG_COMPILER_HAS_BOOL 1 + +// Use standard config.h if present +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#endif diff --git a/bsnes/sfc/dsp/blargg_endian.h b/bsnes/sfc/dsp/blargg_endian.h new file mode 100644 index 00000000..f2daca64 --- /dev/null +++ b/bsnes/sfc/dsp/blargg_endian.h @@ -0,0 +1,185 @@ +// CPU Byte Order Utilities + +// snes_spc 0.9.0 +#ifndef BLARGG_ENDIAN +#define BLARGG_ENDIAN + +#include "blargg_common.h" + +// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) +#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ + defined (__x86_64__) || defined (__ia64__) || defined (__i386__) + #define BLARGG_CPU_X86 1 + #define BLARGG_CPU_CISC 1 +#endif + +#if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc) + #define BLARGG_CPU_POWERPC 1 + #define BLARGG_CPU_RISC 1 +#endif + +// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only +// one may be #defined to 1. Only needed if something actually depends on byte order. +#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) +#ifdef __GLIBC__ + // GCC handles this for us + #include + #if __BYTE_ORDER == __LITTLE_ENDIAN + #define BLARGG_LITTLE_ENDIAN 1 + #elif __BYTE_ORDER == __BIG_ENDIAN + #define BLARGG_BIG_ENDIAN 1 + #endif +#else + +#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ + (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) + #define BLARGG_LITTLE_ENDIAN 1 +#endif + +#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ + defined (__sparc__) || BLARGG_CPU_POWERPC || \ + (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) + #define BLARGG_BIG_ENDIAN 1 +#elif !defined (__mips__) + // No endian specified; assume little-endian, since it's most common + #define BLARGG_LITTLE_ENDIAN 1 +#endif +#endif +#endif + +#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN + #undef BLARGG_LITTLE_ENDIAN + #undef BLARGG_BIG_ENDIAN +#endif + +inline void blargg_verify_byte_order() +{ + #ifndef NDEBUG + #if BLARGG_BIG_ENDIAN + volatile int i = 1; + assert( *(volatile char*) &i == 0 ); + #elif BLARGG_LITTLE_ENDIAN + volatile int i = 1; + assert( *(volatile char*) &i != 0 ); + #endif + #endif +} + +inline unsigned get_le16( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [1] << 8 | + (unsigned) ((unsigned char const*) p) [0]; +} + +inline unsigned get_be16( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [0] << 8 | + (unsigned) ((unsigned char const*) p) [1]; +} + +inline blargg_ulong get_le32( void const* p ) +{ + return (blargg_ulong) ((unsigned char const*) p) [3] << 24 | + (blargg_ulong) ((unsigned char const*) p) [2] << 16 | + (blargg_ulong) ((unsigned char const*) p) [1] << 8 | + (blargg_ulong) ((unsigned char const*) p) [0]; +} + +inline blargg_ulong get_be32( void const* p ) +{ + return (blargg_ulong) ((unsigned char const*) p) [0] << 24 | + (blargg_ulong) ((unsigned char const*) p) [1] << 16 | + (blargg_ulong) ((unsigned char const*) p) [2] << 8 | + (blargg_ulong) ((unsigned char const*) p) [3]; +} + +inline void set_le16( void* p, unsigned n ) +{ + ((unsigned char*) p) [1] = (unsigned char) (n >> 8); + ((unsigned char*) p) [0] = (unsigned char) n; +} + +inline void set_be16( void* p, unsigned n ) +{ + ((unsigned char*) p) [0] = (unsigned char) (n >> 8); + ((unsigned char*) p) [1] = (unsigned char) n; +} + +inline void set_le32( void* p, blargg_ulong n ) +{ + ((unsigned char*) p) [0] = (unsigned char) n; + ((unsigned char*) p) [1] = (unsigned char) (n >> 8); + ((unsigned char*) p) [2] = (unsigned char) (n >> 16); + ((unsigned char*) p) [3] = (unsigned char) (n >> 24); +} + +inline void set_be32( void* p, blargg_ulong n ) +{ + ((unsigned char*) p) [3] = (unsigned char) n; + ((unsigned char*) p) [2] = (unsigned char) (n >> 8); + ((unsigned char*) p) [1] = (unsigned char) (n >> 16); + ((unsigned char*) p) [0] = (unsigned char) (n >> 24); +} + +#if BLARGG_NONPORTABLE + // Optimized implementation if byte order is known + #if BLARGG_LITTLE_ENDIAN + #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr)) + #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr)) + #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) + #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) + #elif BLARGG_BIG_ENDIAN + #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr)) + #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr)) + #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) + #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) + + #if BLARGG_CPU_POWERPC + // PowerPC has special byte-reversed instructions + #if defined (__MWERKS__) + #define GET_LE16( addr ) (__lhbrx( addr, 0 )) + #define GET_LE32( addr ) (__lwbrx( addr, 0 )) + #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) + #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) + #elif defined (__GNUC__) + #define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;}) + #define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;}) + #define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );}) + #define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );}) + #endif + #endif + #endif +#endif + +#ifndef GET_LE16 + #define GET_LE16( addr ) get_le16( addr ) + #define SET_LE16( addr, data ) set_le16( addr, data ) +#endif + +#ifndef GET_LE32 + #define GET_LE32( addr ) get_le32( addr ) + #define SET_LE32( addr, data ) set_le32( addr, data ) +#endif + +#ifndef GET_BE16 + #define GET_BE16( addr ) get_be16( addr ) + #define SET_BE16( addr, data ) set_be16( addr, data ) +#endif + +#ifndef GET_BE32 + #define GET_BE32( addr ) get_be32( addr ) + #define SET_BE32( addr, data ) set_be32( addr, data ) +#endif + +// auto-selecting versions + +inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } +inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); } +inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } +inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); } +inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); } +inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); } +inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); } +inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); } + +#endif diff --git a/bsnes/sfc/dsp/blargg_source.h b/bsnes/sfc/dsp/blargg_source.h new file mode 100644 index 00000000..5e45c4fb --- /dev/null +++ b/bsnes/sfc/dsp/blargg_source.h @@ -0,0 +1,100 @@ +/* Included at the beginning of library source files, after all other #include lines. +Sets up helpful macros and services used in my source code. They don't need +module an annoying module prefix on their names since they are defined after +all other #include lines. */ + +// snes_spc 0.9.0 +#ifndef BLARGG_SOURCE_H +#define BLARGG_SOURCE_H + +// If debugging is enabled, abort program if expr is false. Meant for checking +// internal state and consistency. A failed assertion indicates a bug in the module. +// void assert( bool expr ); +#include + +// If debugging is enabled and expr is false, abort program. Meant for checking +// caller-supplied parameters and operations that are outside the control of the +// module. A failed requirement indicates a bug outside the module. +// void require( bool expr ); +#undef require +#define require( expr ) assert( expr ) + +// Like printf() except output goes to debug log file. Might be defined to do +// nothing (not even evaluate its arguments). +// void dprintf( const char* format, ... ); +static inline void blargg_dprintf_( const char*, ... ) { } +#undef dprintf +#define dprintf (1) ? (void) 0 : blargg_dprintf_ + +// If enabled, evaluate expr and if false, make debug log entry with source file +// and line. Meant for finding situations that should be examined further, but that +// don't indicate a problem. In all cases, execution continues normally. +#undef check +#define check( expr ) ((void) 0) + +// If expr yields error string, return it from current function, otherwise continue. +#undef RETURN_ERR +#define RETURN_ERR( expr ) do { \ + blargg_err_t blargg_return_err_ = (expr); \ + if ( blargg_return_err_ ) return blargg_return_err_; \ + } while ( 0 ) + +// If ptr is 0, return out of memory error string. +#undef CHECK_ALLOC +#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 ) + +// Avoid any macros which evaluate their arguments multiple times +#undef min +#undef max + +#define DEF_MIN_MAX( type ) \ + static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\ + static inline type max( type x, type y ) { if ( y < x ) return x; return y; } + +DEF_MIN_MAX( int ) +DEF_MIN_MAX( unsigned ) +DEF_MIN_MAX( long ) +DEF_MIN_MAX( unsigned long ) +DEF_MIN_MAX( float ) +DEF_MIN_MAX( double ) + +#undef DEF_MIN_MAX + +/* +// using const references generates crappy code, and I am currenly only using these +// for built-in types, so they take arguments by value + +// TODO: remove +inline int min( int x, int y ) +template +inline T min( T x, T y ) +{ + if ( x < y ) + return x; + return y; +} + +template +inline T max( T x, T y ) +{ + if ( x < y ) + return y; + return x; +} +*/ + +// TODO: good idea? bad idea? +#undef byte +#define byte byte_ +typedef unsigned char byte; + +// deprecated +#define BLARGG_CHECK_ALLOC CHECK_ALLOC +#define BLARGG_RETURN_ERR RETURN_ERR + +// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check +#ifdef BLARGG_SOURCE_BEGIN + #include BLARGG_SOURCE_BEGIN +#endif + +#endif diff --git a/bsnes/sfc/dsp/dsp.cpp b/bsnes/sfc/dsp/dsp.cpp new file mode 100644 index 00000000..33029e1e --- /dev/null +++ b/bsnes/sfc/dsp/dsp.cpp @@ -0,0 +1,58 @@ +#include + +namespace SuperFamicom { + +DSP dsp; + +#include "serialization.cpp" +#include "SPC_DSP.cpp" + +void DSP::main() { + if(!configuration.hacks.dsp.fast) { + spc_dsp.run(1); + clock += 2; + } else { + spc_dsp.run(32); + clock += 2 * 32; + } + + signed count = spc_dsp.sample_count(); + if(count > 0) { + for(unsigned n = 0; n < count; n += 2) { + stream->sample(samplebuffer[n + 0] / 32767.0, samplebuffer[n + 1] / 32767.0); + } + spc_dsp.set_output(samplebuffer, 8192); + } +} + +uint8 DSP::read(uint8 addr) { + return spc_dsp.read(addr); +} + +void DSP::write(uint8 addr, uint8 data) { + spc_dsp.write(addr, data); +} + +bool DSP::load() { + return true; +} + +void DSP::power(bool reset) { + clock = 0; + stream = Emulator::audio.createStream(2, system.apuFrequency() / 768.0); + + if(!reset) { + spc_dsp.init(apuram); + spc_dsp.reset(); + spc_dsp.set_output(samplebuffer, 8192); + } else { + spc_dsp.soft_reset(); + spc_dsp.set_output(samplebuffer, 8192); + } +} + +bool DSP::mute() { + return false; +} + +} diff --git a/bsnes/sfc/dsp/dsp.hpp b/bsnes/sfc/dsp/dsp.hpp new file mode 100644 index 00000000..5c042e45 --- /dev/null +++ b/bsnes/sfc/dsp/dsp.hpp @@ -0,0 +1,24 @@ +#include "SPC_DSP.h" + +struct DSP { + shared_pointer stream; + uint8 apuram[64 * 1024]; + + void main(); + uint8 read(uint8 addr); + void write(uint8 addr, uint8 data); + + bool load(); + void power(bool reset); + bool mute(); + + void serialize(serializer&); + + int64 clock; + +private: + SPC_DSP spc_dsp; + int16_t samplebuffer[8192]; +}; + +extern DSP dsp; diff --git a/bsnes/sfc/dsp/serialization.cpp b/bsnes/sfc/dsp/serialization.cpp new file mode 100644 index 00000000..dd071487 --- /dev/null +++ b/bsnes/sfc/dsp/serialization.cpp @@ -0,0 +1,28 @@ +static void dsp_state_save(unsigned char **out, void *in, size_t size) { + memcpy(*out, in, size); + *out += size; +} + +static void dsp_state_load(unsigned char **in, void *out, size_t size) { + memcpy(out, *in, size); + *in += size; +} + +void DSP::serialize(serializer &s) { + s.array(apuram); + s.array(samplebuffer); + s.integer(clock); + + unsigned char state[SPC_DSP::state_size]; + unsigned char *p = state; + memset(&state, 0, SPC_DSP::state_size); + if(s.mode() == serializer::Save) { + spc_dsp.copy_state(&p, dsp_state_save); + s.array(state); + } else if(s.mode() == serializer::Load) { + s.array(state); + spc_dsp.copy_state(&p, dsp_state_load); + } else { + s.array(state); + } +} diff --git a/higan/sfc/expansion/21fx/21fx.cpp b/bsnes/sfc/expansion/21fx/21fx.cpp similarity index 100% rename from higan/sfc/expansion/21fx/21fx.cpp rename to bsnes/sfc/expansion/21fx/21fx.cpp diff --git a/higan/sfc/expansion/21fx/21fx.hpp b/bsnes/sfc/expansion/21fx/21fx.hpp similarity index 100% rename from higan/sfc/expansion/21fx/21fx.hpp rename to bsnes/sfc/expansion/21fx/21fx.hpp diff --git a/higan/sfc/expansion/expansion.cpp b/bsnes/sfc/expansion/expansion.cpp similarity index 100% rename from higan/sfc/expansion/expansion.cpp rename to bsnes/sfc/expansion/expansion.cpp diff --git a/higan/sfc/expansion/expansion.hpp b/bsnes/sfc/expansion/expansion.hpp similarity index 100% rename from higan/sfc/expansion/expansion.hpp rename to bsnes/sfc/expansion/expansion.hpp diff --git a/higan/sfc/expansion/satellaview/satellaview.cpp b/bsnes/sfc/expansion/satellaview/satellaview.cpp similarity index 100% rename from higan/sfc/expansion/satellaview/satellaview.cpp rename to bsnes/sfc/expansion/satellaview/satellaview.cpp diff --git a/higan/sfc/expansion/satellaview/satellaview.hpp b/bsnes/sfc/expansion/satellaview/satellaview.hpp similarity index 100% rename from higan/sfc/expansion/satellaview/satellaview.hpp rename to bsnes/sfc/expansion/satellaview/satellaview.hpp diff --git a/higan/sfc/interface/configuration.cpp b/bsnes/sfc/interface/configuration.cpp similarity index 78% rename from higan/sfc/interface/configuration.cpp rename to bsnes/sfc/interface/configuration.cpp index 768ae2c2..ec29a30b 100644 --- a/higan/sfc/interface/configuration.cpp +++ b/bsnes/sfc/interface/configuration.cpp @@ -16,10 +16,13 @@ auto Configuration::process(Markup::Node document, bool load) -> void { bind(boolean, "Video/BlurEmulation", video.blurEmulation); bind(boolean, "Video/ColorEmulation", video.colorEmulation); - bind(boolean, "Hacks/FastPPU/Enable", hacks.ppuFast.enable); - bind(boolean, "Hacks/FastPPU/NoSpriteLimit", hacks.ppuFast.noSpriteLimit); - bind(boolean, "Hacks/FastPPU/HiresMode7", hacks.ppuFast.hiresMode7); - bind(boolean, "Hacks/FastDSP/Enable", hacks.dspFast.enable); + bind(boolean, "Hacks/PPU/Fast", hacks.ppu.fast); + bind(boolean, "Hacks/PPU/NoSpriteLimit", hacks.ppu.noSpriteLimit); + bind(boolean, "Hacks/PPU/Mode7/Hires", hacks.ppu.mode7.hires); + bind(natural, "Hacks/PPU/Mode7/Scale", hacks.ppu.mode7.scale); + bind(boolean, "Hacks/PPU/Mode7/Perspective", hacks.ppu.mode7.perspective); + bind(boolean, "Hacks/DSP/Fast", hacks.dsp.fast); + bind(boolean, "Hacks/DSP/Cubic", hacks.dsp.cubic); bind(boolean, "Hacks/Coprocessors/HLE", hacks.coprocessors.hle); bind(boolean, "Hacks/Coprocessors/DelayedSync", hacks.coprocessors.delayedSync); diff --git a/higan/sfc/interface/configuration.hpp b/bsnes/sfc/interface/configuration.hpp similarity index 75% rename from higan/sfc/interface/configuration.hpp rename to bsnes/sfc/interface/configuration.hpp index 159b7d18..06160cec 100644 --- a/higan/sfc/interface/configuration.hpp +++ b/bsnes/sfc/interface/configuration.hpp @@ -25,14 +25,19 @@ struct Configuration { } video; struct Hacks { - struct PPUFast { - bool enable = true; + struct PPU { + bool fast = true; bool noSpriteLimit = false; - bool hiresMode7 = false; - } ppuFast; - struct DSPFast { - bool enable = true; - } dspFast; + struct Mode7 { + bool hires = false; + uint scale = 1; + bool perspective = true; + } mode7; + } ppu; + struct DSP { + bool fast = true; + bool cubic = false; + } dsp; struct Coprocessors { bool delayedSync = true; bool hle = true; diff --git a/higan/sfc/interface/interface.cpp b/bsnes/sfc/interface/interface.cpp similarity index 97% rename from higan/sfc/interface/interface.cpp rename to bsnes/sfc/interface/interface.cpp index f11824c6..2167c6a4 100644 --- a/higan/sfc/interface/interface.cpp +++ b/bsnes/sfc/interface/interface.cpp @@ -246,9 +246,7 @@ auto Interface::unserialize(serializer& s) -> bool { auto Interface::cheats(const vector& list) -> void { cheat.reset(); - #if defined(CORE_GB) if(cartridge.has.ICD) return GameBoy::cheat.assign(list); - #endif cheat.assign(list); } @@ -268,4 +266,13 @@ auto Interface::configure(string name, string value) -> bool { return SuperFamicom::configuration.write(name, value); } +auto Interface::frameSkip() -> uint { + return system.frameSkip; +} + +auto Interface::setFrameSkip(uint frameSkip) -> void { + system.frameSkip = frameSkip; + system.frameCounter = 0; +} + } diff --git a/higan/sfc/interface/interface.hpp b/bsnes/sfc/interface/interface.hpp similarity index 95% rename from higan/sfc/interface/interface.hpp rename to bsnes/sfc/interface/interface.hpp index ba5d531b..270f1e55 100644 --- a/higan/sfc/interface/interface.hpp +++ b/bsnes/sfc/interface/interface.hpp @@ -1,5 +1,3 @@ -#if defined(CORE_SFC) - namespace SuperFamicom { struct ID { @@ -68,6 +66,9 @@ struct Interface : Emulator::Interface { auto configuration(string name) -> string override; auto configure(string configuration) -> bool override; auto configure(string name, string value) -> bool override; + + auto frameSkip() -> uint override; + auto setFrameSkip(uint frameSkip) -> void override; }; #include "configuration.hpp" @@ -82,5 +83,3 @@ struct Settings { extern Settings settings; } - -#endif diff --git a/higan/sfc/memory/memory-inline.hpp b/bsnes/sfc/memory/memory-inline.hpp similarity index 100% rename from higan/sfc/memory/memory-inline.hpp rename to bsnes/sfc/memory/memory-inline.hpp diff --git a/higan/sfc/memory/memory.cpp b/bsnes/sfc/memory/memory.cpp similarity index 100% rename from higan/sfc/memory/memory.cpp rename to bsnes/sfc/memory/memory.cpp diff --git a/higan/sfc/memory/memory.hpp b/bsnes/sfc/memory/memory.hpp similarity index 100% rename from higan/sfc/memory/memory.hpp rename to bsnes/sfc/memory/memory.hpp diff --git a/higan/sfc/memory/protectable.hpp b/bsnes/sfc/memory/protectable.hpp similarity index 100% rename from higan/sfc/memory/protectable.hpp rename to bsnes/sfc/memory/protectable.hpp diff --git a/higan/sfc/memory/readable.hpp b/bsnes/sfc/memory/readable.hpp similarity index 100% rename from higan/sfc/memory/readable.hpp rename to bsnes/sfc/memory/readable.hpp diff --git a/higan/sfc/memory/writable.hpp b/bsnes/sfc/memory/writable.hpp similarity index 100% rename from higan/sfc/memory/writable.hpp rename to bsnes/sfc/memory/writable.hpp diff --git a/higan/sfc/ppu-fast/background.cpp b/bsnes/sfc/ppu-fast/background.cpp similarity index 83% rename from higan/sfc/ppu-fast/background.cpp rename to bsnes/sfc/ppu-fast/background.cpp index 14cfef17..7a0f8d00 100644 --- a/higan/sfc/ppu-fast/background.cpp +++ b/bsnes/sfc/ppu-fast/background.cpp @@ -1,4 +1,4 @@ -auto PPU::Line::renderBackground(PPU::IO::Background& self, uint source) -> void { +auto PPUfast::Line::renderBackground(PPUfast::IO::Background& self, uint source) -> void { if(!self.aboveEnable && !self.belowEnable) return; if(self.tileMode == TileMode::Mode7) return renderMode7(self, source); if(self.tileMode == TileMode::Inactive) return; @@ -29,7 +29,7 @@ auto PPU::Line::renderBackground(PPU::IO::Background& self, uint source) -> void uint y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0); if(hires) { hscroll <<= 1; - if(io.interlace) y = y << 1 | ppu.field(); + if(io.interlace) y = y << 1 | ppufast.field(); } uint mosaicCounter = 1; @@ -79,7 +79,7 @@ auto PPU::Line::renderBackground(PPU::IO::Background& self, uint source) -> void if(tileHeight == 4 && (bool(voffset & 8) ^ bool(mirrorY))) tileNumber += 16; tileNumber = (tileNumber & 0x03ff) + tiledataIndex & tileMask; - auto tiledata = ppu.tilecache[self.tileMode] + (tileNumber << 6); + auto tiledata = ppufast.tilecache[self.tileMode] + (tileNumber << 6); tiledata += (voffset & 7 ^ mirrorY) << 3; for(uint tileX = 0; tileX < 8; tileX++, x++) { @@ -101,17 +101,22 @@ auto PPU::Line::renderBackground(PPU::IO::Background& self, uint source) -> void if(self.belowEnable && !windowBelow[x]) plotBelow(x, source, mosaicPriority, mosaicColor); } else { uint X = x >> 1; - if(x & 1) { - if(self.aboveEnable && !windowAbove[X]) plotAbove(X, source, mosaicPriority, mosaicColor); + if(!ppufast.hd()) { + if(x & 1) { + if(self.aboveEnable && !windowAbove[X]) plotAbove(X, source, mosaicPriority, mosaicColor); + } else { + if(self.belowEnable && !windowBelow[X]) plotBelow(X, source, mosaicPriority, mosaicColor); + } } else { - if(self.belowEnable && !windowBelow[X]) plotBelow(X, source, mosaicPriority, mosaicColor); + if(self.aboveEnable && !windowAbove[X]) plotHD(above, X, source, mosaicPriority, mosaicColor, true, x & 1); + if(self.belowEnable && !windowBelow[X]) plotHD(below, X, source, mosaicPriority, mosaicColor, true, x & 1); } } } } } -auto PPU::Line::getTile(PPU::IO::Background& self, uint hoffset, uint voffset) -> uint { +auto PPUfast::Line::getTile(PPUfast::IO::Background& self, uint hoffset, uint voffset) -> uint { bool hires = io.bgMode == 5 || io.bgMode == 6; uint tileHeight = 3 + self.tileSize; uint tileWidth = !hires ? tileHeight : 4; @@ -123,5 +128,5 @@ auto PPU::Line::getTile(PPU::IO::Background& self, uint hoffset, uint voffset) - if(tileX & 0x20) offset += screenX; if(tileY & 0x20) offset += screenY; uint15 address = self.screenAddress + offset; - return ppu.vram[address]; + return ppufast.vram[address]; } diff --git a/higan/sfc/ppu-fast/io.cpp b/bsnes/sfc/ppu-fast/io.cpp similarity index 88% rename from higan/sfc/ppu-fast/io.cpp rename to bsnes/sfc/ppu-fast/io.cpp index 1176f6cf..f8baab29 100644 --- a/higan/sfc/ppu-fast/io.cpp +++ b/bsnes/sfc/ppu-fast/io.cpp @@ -1,10 +1,10 @@ -auto PPU::latchCounters() -> void { +auto PPUfast::latchCounters() -> void { io.hcounter = cpu.hdot(); io.vcounter = cpu.vcounter(); latch.counters = 1; } -auto PPU::vramAddress() const -> uint15 { //uint15 for 64K VRAM; uint16 for 128K VRAM +auto PPUfast::vramAddress() const -> uint15 { //uint15 for 64K VRAM; uint16 for 128K VRAM uint16 address = io.vramAddress; switch(io.vramMapping) { case 0: return address; @@ -15,13 +15,13 @@ auto PPU::vramAddress() const -> uint15 { //uint15 for 64K VRAM; uint16 for 128 unreachable; } -auto PPU::readVRAM() -> uint16 { +auto PPUfast::readVRAM() -> uint16 { if(!io.displayDisable && cpu.vcounter() < vdisp()) return 0x0000; auto address = vramAddress(); return vram[address]; } -auto PPU::writeVRAM(uint1 byte, uint8 data) -> void { +auto PPUfast::writeVRAM(uint1 byte, uint8 data) -> void { if(!io.displayDisable && cpu.vcounter() < vdisp()) return; Line::flush(); auto address = vramAddress(); @@ -29,7 +29,7 @@ auto PPU::writeVRAM(uint1 byte, uint8 data) -> void { updateTiledata(address); } -auto PPU::updateTiledata(uint15 address) -> void { +auto PPUfast::updateTiledata(uint15 address) -> void { auto word = vram[address]; auto line2bpp = tilecache[TileMode::BPP2] + (address.bits(3,14) << 6) + (address.bits(0,2) << 3); auto line4bpp = tilecache[TileMode::BPP4] + (address.bits(4,14) << 6) + (address.bits(0,2) << 3); @@ -46,19 +46,19 @@ auto PPU::updateTiledata(uint15 address) -> void { } } -auto PPU::readOAM(uint10 address) -> uint8 { +auto PPUfast::readOAM(uint10 address) -> uint8 { if(!io.displayDisable && cpu.vcounter() < vdisp()) address = latch.oamAddress; return readObject(address); } -auto PPU::writeOAM(uint10 address, uint8 data) -> void { +auto PPUfast::writeOAM(uint10 address, uint8 data) -> void { Line::flush(); //Uniracers 2-player mode hack if(!io.displayDisable && cpu.vcounter() < vdisp()) address = 0x0218; //latch.oamAddress; return writeObject(address, data); } -auto PPU::readCGRAM(uint1 byte, uint8 address) -> uint8 { +auto PPUfast::readCGRAM(uint1 byte, uint8 address) -> uint8 { if(!io.displayDisable && cpu.vcounter() > 0 && cpu.vcounter() < vdisp() && cpu.hcounter() >= 88 && cpu.hcounter() < 1096 @@ -66,7 +66,7 @@ auto PPU::readCGRAM(uint1 byte, uint8 address) -> uint8 { return cgram[address].byte(byte); } -auto PPU::writeCGRAM(uint8 address, uint15 data) -> void { +auto PPUfast::writeCGRAM(uint8 address, uint15 data) -> void { if(!io.displayDisable && cpu.vcounter() > 0 && cpu.vcounter() < vdisp() && cpu.hcounter() >= 88 && cpu.hcounter() < 1096 @@ -74,8 +74,8 @@ auto PPU::writeCGRAM(uint8 address, uint15 data) -> void { cgram[address] = data; } -auto PPU::readIO(uint24 address, uint8 data) -> uint8 { - cpu.synchronize(ppu); +auto PPUfast::readIO(uint24 address, uint8 data) -> uint8 { + cpu.synchronize(ppufast); switch((uint16)address) { @@ -186,8 +186,8 @@ auto PPU::readIO(uint24 address, uint8 data) -> uint8 { return data; } -auto PPU::writeIO(uint24 address, uint8 data) -> void { - cpu.synchronize(ppu); +auto PPUfast::writeIO(uint24 address, uint8 data) -> void { + cpu.synchronize(ppufast); switch((uint16)address) { @@ -583,7 +583,7 @@ auto PPU::writeIO(uint24 address, uint8 data) -> void { } } -auto PPU::updateVideoMode() -> void { +auto PPUfast::updateVideoMode() -> void { ppubase.display.vdisp = !io.overscan ? 225 : 240; switch(io.bgMode) { @@ -592,11 +592,11 @@ auto PPU::updateVideoMode() -> void { io.bg2.tileMode = TileMode::BPP2; io.bg3.tileMode = TileMode::BPP2; io.bg4.tileMode = TileMode::BPP2; - io.bg1.priority = { 8, 11}; - io.bg2.priority = { 7, 10}; - io.bg3.priority = { 2, 5}; - io.bg4.priority = { 1, 4}; - io.obj.priority = { 3, 6, 9, 12}; + memory::assign(io.bg1.priority, 8, 11); + memory::assign(io.bg2.priority, 7, 10); + memory::assign(io.bg3.priority, 2, 5); + memory::assign(io.bg4.priority, 1, 4); + memory::assign(io.obj.priority, 3, 6, 9, 12); break; case 1: @@ -605,15 +605,15 @@ auto PPU::updateVideoMode() -> void { io.bg3.tileMode = TileMode::BPP2; io.bg4.tileMode = TileMode::Inactive; if(io.bgPriority) { - io.bg1.priority = { 5, 8}; - io.bg2.priority = { 4, 7}; - io.bg3.priority = { 1, 10}; - io.obj.priority = { 2, 3, 6, 9}; + memory::assign(io.bg1.priority, 5, 8); + memory::assign(io.bg2.priority, 4, 7); + memory::assign(io.bg3.priority, 1, 10); + memory::assign(io.obj.priority, 2, 3, 6, 9); } else { - io.bg1.priority = { 6, 9}; - io.bg2.priority = { 5, 8}; - io.bg3.priority = { 1, 3}; - io.obj.priority = { 2, 4, 7, 10}; + memory::assign(io.bg1.priority, 6, 9); + memory::assign(io.bg2.priority, 5, 8); + memory::assign(io.bg3.priority, 1, 3); + memory::assign(io.obj.priority, 2, 4, 7, 10); } break; @@ -622,9 +622,9 @@ auto PPU::updateVideoMode() -> void { io.bg2.tileMode = TileMode::BPP4; io.bg3.tileMode = TileMode::Inactive; io.bg4.tileMode = TileMode::Inactive; - io.bg1.priority = { 3, 7}; - io.bg2.priority = { 1, 5}; - io.obj.priority = { 2, 4, 6, 8}; + memory::assign(io.bg1.priority, 3, 7); + memory::assign(io.bg2.priority, 1, 5); + memory::assign(io.obj.priority, 2, 4, 6, 8); break; case 3: @@ -632,9 +632,9 @@ auto PPU::updateVideoMode() -> void { io.bg2.tileMode = TileMode::BPP4; io.bg3.tileMode = TileMode::Inactive; io.bg4.tileMode = TileMode::Inactive; - io.bg1.priority = { 3, 7}; - io.bg2.priority = { 1, 5}; - io.obj.priority = { 2, 4, 6, 8}; + memory::assign(io.bg1.priority, 3, 7); + memory::assign(io.bg2.priority, 1, 5); + memory::assign(io.obj.priority, 2, 4, 6, 8); break; case 4: @@ -642,9 +642,9 @@ auto PPU::updateVideoMode() -> void { io.bg2.tileMode = TileMode::BPP2; io.bg3.tileMode = TileMode::Inactive; io.bg4.tileMode = TileMode::Inactive; - io.bg1.priority = { 3, 7}; - io.bg2.priority = { 1, 5}; - io.obj.priority = { 2, 4, 6, 8}; + memory::assign(io.bg1.priority, 3, 7); + memory::assign(io.bg2.priority, 1, 5); + memory::assign(io.obj.priority, 2, 4, 6, 8); break; case 5: @@ -652,9 +652,9 @@ auto PPU::updateVideoMode() -> void { io.bg2.tileMode = TileMode::BPP2; io.bg3.tileMode = TileMode::Inactive; io.bg4.tileMode = TileMode::Inactive; - io.bg1.priority = { 3, 7}; - io.bg2.priority = { 1, 5}; - io.obj.priority = { 2, 4, 6, 8}; + memory::assign(io.bg1.priority, 3, 7); + memory::assign(io.bg2.priority, 1, 5); + memory::assign(io.obj.priority, 2, 4, 6, 8); break; case 6: @@ -662,8 +662,8 @@ auto PPU::updateVideoMode() -> void { io.bg2.tileMode = TileMode::Inactive; io.bg3.tileMode = TileMode::Inactive; io.bg4.tileMode = TileMode::Inactive; - io.bg1.priority = { 2, 5}; - io.obj.priority = { 1, 3, 4, 6}; + memory::assign(io.bg1.priority, 2, 5); + memory::assign(io.obj.priority, 1, 3, 4, 6); break; case 7: @@ -672,16 +672,16 @@ auto PPU::updateVideoMode() -> void { io.bg2.tileMode = TileMode::Inactive; io.bg3.tileMode = TileMode::Inactive; io.bg4.tileMode = TileMode::Inactive; - io.bg1.priority = { 2}; - io.obj.priority = { 1, 3, 4, 5}; + memory::assign(io.bg1.priority, 2); + memory::assign(io.obj.priority, 1, 3, 4, 5); } else { io.bg1.tileMode = TileMode::Mode7; io.bg2.tileMode = TileMode::Mode7; io.bg3.tileMode = TileMode::Inactive; io.bg4.tileMode = TileMode::Inactive; - io.bg1.priority = { 3}; - io.bg2.priority = { 1, 5}; - io.obj.priority = { 2, 4, 6, 7}; + memory::assign(io.bg1.priority, 3); + memory::assign(io.bg2.priority, 1, 5); + memory::assign(io.obj.priority, 2, 4, 6, 7); } break; } diff --git a/higan/sfc/ppu-fast/line.cpp b/bsnes/sfc/ppu-fast/line.cpp similarity index 54% rename from higan/sfc/ppu-fast/line.cpp rename to bsnes/sfc/ppu-fast/line.cpp index d7b114e7..e879a47b 100644 --- a/higan/sfc/ppu-fast/line.cpp +++ b/bsnes/sfc/ppu-fast/line.cpp @@ -1,21 +1,27 @@ -uint PPU::Line::start = 0; -uint PPU::Line::count = 0; +uint PPUfast::Line::start = 0; +uint PPUfast::Line::count = 0; -auto PPU::Line::flush() -> void { +auto PPUfast::Line::flush() -> void { if(Line::count) { #pragma omp parallel for if(Line::count >= 8) for(uint y = 0; y < Line::count; y++) { - ppu.lines[Line::start + y].render(); + ppufast.lines[Line::start + y].render(); } Line::start = 0; Line::count = 0; } } -auto PPU::Line::render() -> void { - auto output = ppu.output + y * 1024; - if(ppu.interlace() && ppu.field()) output += 512; - auto width = !ppu.hires() ? 256 : 512; +auto PPUfast::Line::render() -> void { + auto hd = ppufast.hd(); + auto scale = ppufast.hdScale(); + auto output = ppufast.output + (!hd + ? (y * 1024 + (ppufast.interlace() && ppufast.field() ? 512 : 0)) + : (y * 256 * scale * scale) + ); + auto width = (!hd + ? (!ppufast.hires() ? 256 : 512) + : (256 * scale * scale)); if(io.displayDisable) { memory::fill(output, width); @@ -23,10 +29,12 @@ auto PPU::Line::render() -> void { } bool hires = io.pseudoHires || io.bgMode == 5 || io.bgMode == 6; - bool hiresMode7 = io.bgMode == 7 && configuration.hacks.ppuFast.hiresMode7; + bool hiresMode7 = io.bgMode == 7 && configuration.hacks.ppu.mode7.hires; auto aboveColor = cgram[0]; auto belowColor = hires ? cgram[0] : io.col.fixedColor; - for(uint x : range(256 << hiresMode7)) { + uint xa = hd && ppufast.interlace() && ppufast.field() ? 256 * scale * scale / 2 : 0; + uint xb = !hd ? 256 << hiresMode7 : ppufast.interlace() && !ppufast.field() ? 256 * scale * scale / 2 : 256 * scale * scale; + for(uint x = xa; x < xb; x++) { above[x] = {Source::COL, 0, aboveColor}; below[x] = {Source::COL, 0, belowColor}; } @@ -40,7 +48,9 @@ auto PPU::Line::render() -> void { renderWindow(io.col.window, io.col.window.belowMask, windowBelow); auto luma = io.displayBrightness << 15; - if(hiresMode7) for(uint x : range(512)) { + if(hd) for(uint x : range(256 * scale * scale)) { + *output++ = luma | pixel(x / scale & 255, above[x], below[x]); + } else if(hiresMode7) for(uint x : range(512)) { auto Above = above[x >> 1].source >= Source::OBJ1 ? above[x >> 1] : above[x >> 1 | (x & 1 ? 256 : 0)]; auto Below = below[x >> 1].source >= Source::OBJ1 ? below[x >> 1] : below[x >> 1 | (x & 1 ? 256 : 0)]; *output++ = luma | pixel(x >> 1, Above, Below); @@ -56,7 +66,7 @@ auto PPU::Line::render() -> void { } } -auto PPU::Line::pixel(uint x, Pixel above, Pixel below) const -> uint15 { +auto PPUfast::Line::pixel(uint x, Pixel above, Pixel below) const -> uint15 { if(!windowAbove[x]) above.color = 0x0000; if(!windowBelow[x]) return above.color; if(!io.col.enable[above.source]) return above.color; @@ -64,7 +74,7 @@ auto PPU::Line::pixel(uint x, Pixel above, Pixel below) const -> uint15 { return blend(above.color, below.color, io.col.halve && windowAbove[x] && below.source != Source::COL); } -auto PPU::Line::blend(uint x, uint y, bool halve) const -> uint15 { +auto PPUfast::Line::blend(uint x, uint y, bool halve) const -> uint15 { if(!io.col.mathMode) { //add if(!halve) { uint sum = x + y; @@ -84,7 +94,7 @@ auto PPU::Line::blend(uint x, uint y, bool halve) const -> uint15 { } } -auto PPU::Line::directColor(uint paletteIndex, uint paletteColor) const -> uint15 { +auto PPUfast::Line::directColor(uint paletteIndex, uint paletteColor) const -> uint15 { //paletteIndex = bgr //paletteColor = BBGGGRRR //output = 0 BBb00 GGGg0 RRRr0 @@ -93,10 +103,32 @@ auto PPU::Line::directColor(uint paletteIndex, uint paletteColor) const -> uint1 + (paletteColor << 7 & 0x6000) + (paletteIndex << 10 & 0x1000); //B } -auto PPU::Line::plotAbove(uint x, uint source, uint priority, uint color) -> void { +auto PPUfast::Line::plotAbove(uint x, uint source, uint priority, uint color) -> void { + if(ppufast.hd()) return plotHD(above, x, source, priority, color, false, false); if(priority > above[x].priority) above[x] = {source, priority, color}; } -auto PPU::Line::plotBelow(uint x, uint source, uint priority, uint color) -> void { +auto PPUfast::Line::plotBelow(uint x, uint source, uint priority, uint color) -> void { + if(ppufast.hd()) return plotHD(below, x, source, priority, color, false, false); if(priority > below[x].priority) below[x] = {source, priority, color}; } + +//todo: name these variables more clearly ... +auto PPUfast::Line::plotHD(Pixel* pixel, uint x, uint source, uint priority, uint color, bool hires, bool subpixel) -> void { + auto scale = ppufast.hdScale(); + int xss = hires && subpixel ? scale / 2 : 0; + int ys = ppufast.interlace() && ppufast.field() ? scale / 2 : 0; + if(priority > pixel[x * scale + xss + ys * 256 * scale].priority) { + Pixel p = {source, priority, color}; + int xsm = hires && !subpixel ? scale / 2 : scale; + int ysm = ppufast.interlace() && !ppufast.field() ? scale / 2 : scale; + for(int xs = xss; xs < xsm; xs++) { + pixel[x * scale + xs + ys * 256 * scale] = p; + } + int size = sizeof(Pixel) * (xsm - xss); + Pixel* source = &pixel[x * scale + xss + ys * 256 * scale]; + for(int yst = ys + 1; yst < ysm; yst++) { + memcpy(&pixel[x * scale + xss + yst * 256 * scale], source, size); + } + } +} diff --git a/bsnes/sfc/ppu-fast/mode7.cpp b/bsnes/sfc/ppu-fast/mode7.cpp new file mode 100644 index 00000000..da0c3853 --- /dev/null +++ b/bsnes/sfc/ppu-fast/mode7.cpp @@ -0,0 +1,66 @@ +auto PPUfast::Line::renderMode7(PPUfast::IO::Background& self, uint source) -> void { + if(ppufast.hdScale() > 1) return renderMode7HD(self, source); + if(configuration.hacks.ppu.mode7.hires) return renderMode7Hires(self, source); + + int Y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0); + int y = !io.mode7.vflip ? Y : 255 - Y; + + int a = (int16)io.mode7.a; + int b = (int16)io.mode7.b; + int c = (int16)io.mode7.c; + int d = (int16)io.mode7.d; + int hcenter = (int13)io.mode7.x; + int vcenter = (int13)io.mode7.y; + int hoffset = (int13)io.mode7.hoffset; + int voffset = (int13)io.mode7.voffset; + + uint mosaicCounter = 1; + uint mosaicPalette = 0; + uint mosaicPriority = 0; + uint mosaicColor = 0; + + auto clip = [](int n) -> int { return n & 0x2000 ? (n | ~1023) : (n & 1023); }; + int originX = (a * clip(hoffset - hcenter) & ~63) + (b * clip(voffset - vcenter) & ~63) + (b * y & ~63) + (hcenter << 8); + int originY = (c * clip(hoffset - hcenter) & ~63) + (d * clip(voffset - vcenter) & ~63) + (d * y & ~63) + (vcenter << 8); + + array windowAbove; + array windowBelow; + renderWindow(self.window, self.window.aboveEnable, windowAbove); + renderWindow(self.window, self.window.belowEnable, windowBelow); + + for(int X : range(256)) { + int x = !io.mode7.hflip ? X : 255 - X; + int pixelX = originX + a * x >> 8; + int pixelY = originY + c * x >> 8; + int tileX = pixelX >> 3 & 127; + int tileY = pixelY >> 3 & 127; + bool outOfBounds = (pixelX | pixelY) & ~1023; + uint15 tileAddress = tileY * 128 + tileX; + uint15 paletteAddress = ((pixelY & 7) << 3) + (pixelX & 7); + uint8 tile = io.mode7.repeat == 3 && outOfBounds ? 0 : ppufast.vram[tileAddress].byte(0); + uint8 palette = io.mode7.repeat == 2 && outOfBounds ? 0 : ppufast.vram[paletteAddress + (tile << 6)].byte(1); + + uint priority; + if(source == Source::BG1) { + priority = self.priority[0]; + } else if(source == Source::BG2) { + priority = self.priority[palette >> 7]; + palette &= 0x7f; + } + + if(!self.mosaicEnable || --mosaicCounter == 0) { + mosaicCounter = 1 + io.mosaicSize; + mosaicPalette = palette; + mosaicPriority = priority; + if(io.col.directColor && source == Source::BG1) { + mosaicColor = directColor(0, palette); + } else { + mosaicColor = cgram[palette]; + } + } + if(!mosaicPalette) continue; + + if(self.aboveEnable && !windowAbove[X]) plotAbove(X, source, mosaicPriority, mosaicColor); + if(self.belowEnable && !windowBelow[X]) plotBelow(X, source, mosaicPriority, mosaicColor); + } +} diff --git a/bsnes/sfc/ppu-fast/mode7hd.cpp b/bsnes/sfc/ppu-fast/mode7hd.cpp new file mode 100644 index 00000000..5ad17693 --- /dev/null +++ b/bsnes/sfc/ppu-fast/mode7hd.cpp @@ -0,0 +1,126 @@ +auto PPUfast::Line::renderMode7HD(PPUfast::IO::Background& self, uint source) -> void { + const bool extbg = source == Source::BG2; + const uint scale = ppufast.hdScale(); + + Pixel pixel; + Pixel* above = &this->above[-1]; + Pixel* below = &this->below[-1]; + + //find the first and last scanline for interpolation + int y_a = y; + int y_b = y; + #define isLineMode7(n) (ppufast.lines[n].io.bg1.tileMode == TileMode::Mode7 && ( \ + (ppufast.lines[n].io.bg1.aboveEnable || ppufast.lines[n].io.bg1.belowEnable) \ + )) + if(ppufast.hdPerspective()) { + while(y_a > 1 && isLineMode7(y_a)) y_a--; y_a += 1; + while(y_b < 239 && isLineMode7(y_b)) y_b++; y_b -= 8; + } else { + if(y_a > 1 && isLineMode7(y_a)) y_a--; + if(y_b < 239 && isLineMode7(y_b)) y_b++; + } + #undef isLineMode7 + + int Y = y - (self.mosaicEnable ? y % (1 + io.mosaicSize) : 0); + float yt = !io.mode7.vflip ? Y : 255 - Y; + + Line line_a = ppufast.lines[y_a]; + float a_a = (int16)line_a.io.mode7.a; + float b_a = (int16)line_a.io.mode7.b; + float c_a = (int16)line_a.io.mode7.c; + float d_a = (int16)line_a.io.mode7.d; + + Line line_b = ppufast.lines[y_b]; + float a_b = (int16)line_b.io.mode7.a; + float b_b = (int16)line_b.io.mode7.b; + float c_b = (int16)line_b.io.mode7.c; + float d_b = (int16)line_b.io.mode7.d; + + int hcenter = (int13)io.mode7.x; + int vcenter = (int13)io.mode7.y; + int hoffset = (int13)io.mode7.hoffset; + int voffset = (int13)io.mode7.voffset; + + array windowAbove; + array windowBelow; + renderWindow(self.window, self.window.aboveEnable, windowAbove); + renderWindow(self.window, self.window.belowEnable, windowBelow); + + int pixelYp = INT_MIN; + for(int ys : range(scale)) { + float y = yt + ys * 1.0 / scale - 0.5; + float a = 1.0 / lerp(y_a, 1.0 / a_a, y_b, 1.0 / a_b, y); + float b = 1.0 / lerp(y_a, 1.0 / b_a, y_b, 1.0 / b_b, y); + float c = 1.0 / lerp(y_a, 1.0 / c_a, y_b, 1.0 / c_b, y); + float d = 1.0 / lerp(y_a, 1.0 / d_a, y_b, 1.0 / d_b, y); + + int ht = (hoffset - hcenter) % 1024; + float vty = ((voffset - vcenter) % 1024) + y; + float originX = (a * ht) + (b * vty) + (hcenter << 8); + float originY = (c * ht) + (d * vty) + (vcenter << 8); + + uint tile, palette, priority; + //some games enable mosaic with a mosaic size of 0 (1x1) + bool mosaicEnable = self.mosaicEnable && io.mosaicSize; + uint mosaicCounter = 1; + uint mosaicPalette = 0; + uint mosaicPriority = 0; + uint mosaicColor = 0; + Pixel mosaicPixel; + + int pixelXp = INT_MIN; + for(int X : range(256)) { + float xt = !io.mode7.hflip ? X : 255 - X; + bool doAbove = self.aboveEnable && !windowAbove[X]; + bool doBelow = self.belowEnable && !windowBelow[X]; + + for(int xs : range(scale)) { + float x = xt + xs * 1.0 / scale - 0.5; + int pixelX = (originX + a * x) / 256; + int pixelY = (originY + c * x) / 256; + + above++; + below++; + + //only compute color again when coordinates have changed + if(pixelX != pixelXp || pixelY != pixelYp) { + pixelXp = pixelX; + pixelYp = pixelY; + + tile = io.mode7.repeat == 3 && ((pixelX | pixelY) & ~1023) ? 0 : ppufast.vram[(pixelY >> 3 & 127) * 128 + (pixelX >> 3 & 127)].byte(0); + palette = io.mode7.repeat == 2 && ((pixelX | pixelY) & ~1023) ? 0 : ppufast.vram[(((pixelY & 7) << 3) + (pixelX & 7)) + (tile << 6)].byte(1); + + if(!extbg) { + priority = self.priority[0]; + } else { + priority = self.priority[palette >> 7]; + palette &= 0x7f; + } + } + + if(!mosaicEnable || --mosaicCounter == 0) { + mosaicCounter = (1 + io.mosaicSize) * scale; + mosaicPalette = palette; + mosaicPriority = priority; + if(io.col.directColor && !extbg) { + mosaicColor = directColor(0, palette); + } else { + mosaicColor = cgram[palette]; + } + pixel = {source, mosaicPriority, mosaicColor}; + } + if(!mosaicPalette) continue; + + if(doAbove && (!extbg || mosaicPriority > above->priority)) *above = pixel; + if(doBelow && (!extbg || mosaicPriority > below->priority)) *below = pixel; + } + } + } +} + +//interpolation and extrapolation +auto PPUfast::Line::lerp(float pa, float va, float pb, float vb, float pr) -> float { + if(va == vb || pr == pa) return va; + if(pr == pb) return vb; + return va + (vb - va) / (pb - pa) * (pr - pa); +} diff --git a/bsnes/sfc/ppu-fast/mode7hires.cpp b/bsnes/sfc/ppu-fast/mode7hires.cpp new file mode 100644 index 00000000..d91c1d88 --- /dev/null +++ b/bsnes/sfc/ppu-fast/mode7hires.cpp @@ -0,0 +1,63 @@ +auto PPUfast::Line::renderMode7Hires(PPUfast::IO::Background& self, uint source) -> void { + int Y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0); + int y = !io.mode7.vflip ? Y : 255 - Y; + + int a = (int16)io.mode7.a; + int b = (int16)io.mode7.b; + int c = (int16)io.mode7.c; + int d = (int16)io.mode7.d; + int hcenter = (int13)io.mode7.x; + int vcenter = (int13)io.mode7.y; + int hoffset = (int13)io.mode7.hoffset; + int voffset = (int13)io.mode7.voffset; + + uint mosaicCounter = 1; + uint mosaicPalette = 0; + uint mosaicPriority = 0; + uint mosaicColor = 0; + + auto clip = [](int n) -> int { return n & 0x2000 ? (n | ~1023) : (n & 1023); }; + int originX = (a * clip(hoffset - hcenter) & ~63) + (b * clip(voffset - vcenter) & ~63) + (b * y & ~63) + (hcenter << 8); + int originY = (c * clip(hoffset - hcenter) & ~63) + (d * clip(voffset - vcenter) & ~63) + (d * y & ~63) + (vcenter << 8); + + array windowAbove; + array windowBelow; + renderWindow(self.window, self.window.aboveEnable, windowAbove); + renderWindow(self.window, self.window.belowEnable, windowBelow); + + for(int X : range(512)) { + int x = !io.mode7.hflip ? X : 511 - X; + int pixelX = 2 * originX + a * x >> 9; + int pixelY = 2 * originY + c * x >> 9; + int tileX = pixelX >> 3 & 127; + int tileY = pixelY >> 3 & 127; + bool outOfBounds = (pixelX | pixelY) & ~1023; + uint15 tileAddress = tileY * 128 + tileX; + uint15 paletteAddress = ((pixelY & 7) << 3) + (pixelX & 7); + uint8 tile = io.mode7.repeat == 3 && outOfBounds ? 0 : ppufast.vram[tileAddress].byte(0); + uint8 palette = io.mode7.repeat == 2 && outOfBounds ? 0 : ppufast.vram[paletteAddress + (tile << 6)].byte(1); + + uint priority; + if(source == Source::BG1) { + priority = self.priority[0]; + } else if(source == Source::BG2) { + priority = self.priority[palette >> 7]; + palette &= 0x7f; + } + + if(!self.mosaicEnable || !io.mosaicSize || --mosaicCounter == 0) { + mosaicCounter = (1 + io.mosaicSize) << 1; + mosaicPalette = palette; + mosaicPriority = priority; + if(io.col.directColor && source == Source::BG1) { + mosaicColor = directColor(0, palette); + } else { + mosaicColor = cgram[palette]; + } + } + if(!mosaicPalette) continue; + + if(self.aboveEnable && !windowAbove[X >> 1]) plotAbove(X >> 1 | (X & 1 ? 256 : 0), source, mosaicPriority, mosaicColor); + if(self.belowEnable && !windowBelow[X >> 1]) plotBelow(X >> 1 | (X & 1 ? 256 : 0), source, mosaicPriority, mosaicColor); + } +} diff --git a/higan/sfc/ppu-fast/object.cpp b/bsnes/sfc/ppu-fast/object.cpp similarity index 83% rename from higan/sfc/ppu-fast/object.cpp rename to bsnes/sfc/ppu-fast/object.cpp index 4100503c..3698a87e 100644 --- a/higan/sfc/ppu-fast/object.cpp +++ b/bsnes/sfc/ppu-fast/object.cpp @@ -1,4 +1,4 @@ -auto PPU::Line::renderObject(PPU::IO::Object& self) -> void { +auto PPUfast::Line::renderObject(PPUfast::IO::Object& self) -> void { if(!self.aboveEnable && !self.belowEnable) return; array windowAbove; @@ -8,12 +8,12 @@ auto PPU::Line::renderObject(PPU::IO::Object& self) -> void { uint itemCount = 0; uint tileCount = 0; - for(auto n : range(ppu.ItemLimit)) items[n].valid = false; - for(auto n : range(ppu.TileLimit)) tiles[n].valid = false; + for(auto n : range(ppufast.ItemLimit)) items[n].valid = false; + for(auto n : range(ppufast.TileLimit)) tiles[n].valid = false; for(auto n : range(128)) { ObjectItem item{true, self.first + n}; - const auto& object = ppu.objects[item.index]; + const auto& object = ppufast.objects[item.index]; if(object.size == 0) { static const uint widths[] = { 8, 8, 8, 16, 16, 32, 16, 16}; @@ -33,16 +33,16 @@ auto PPU::Line::renderObject(PPU::IO::Object& self) -> void { if((y >= object.y && y < object.y + height) || (object.y + height >= 256 && y < (object.y + height & 255)) ) { - if(itemCount++ >= ppu.ItemLimit) break; + if(itemCount++ >= ppufast.ItemLimit) break; items[itemCount - 1] = item; } } - for(int n : reverse(range(ppu.ItemLimit))) { + for(int n : reverse(range(ppufast.ItemLimit))) { const auto& item = items[n]; if(!item.valid) continue; - const auto& object = ppu.objects[item.index]; + const auto& object = ppufast.objects[item.index]; uint tileWidth = item.width >> 3; int x = object.x; int y = this->y - object.y & 0xff; @@ -59,7 +59,7 @@ auto PPU::Line::renderObject(PPU::IO::Object& self) -> void { } if(self.interlace) { - y = !object.vflip ? y + ppu.field() : y - ppu.field(); + y = !object.vflip ? y + ppufast.field() : y - ppufast.field(); } x &= 511; @@ -85,22 +85,22 @@ auto PPU::Line::renderObject(PPU::IO::Object& self) -> void { uint address = tiledataAddress + ((characterY + (characterX + mirrorX & 15)) << 4); tile.number = address >> 4; - if(tileCount++ >= ppu.TileLimit) break; + if(tileCount++ >= ppufast.TileLimit) break; tiles[tileCount - 1] = tile; } } - ppu.io.obj.rangeOver |= itemCount > ppu.ItemLimit; - ppu.io.obj.timeOver |= tileCount > ppu.TileLimit; + ppufast.io.obj.rangeOver |= itemCount > ppufast.ItemLimit; + ppufast.io.obj.timeOver |= tileCount > ppufast.TileLimit; uint8 palette[256]; uint8 priority[256]; - for(uint n : range(ppu.TileLimit)) { + for(uint n : range(ppufast.TileLimit)) { const auto& tile = tiles[n]; if(!tile.valid) continue; - auto tiledata = ppu.tilecache[TileMode::BPP4] + (tile.number << 6) + ((tile.y & 7) << 3); + auto tiledata = ppufast.tilecache[TileMode::BPP4] + (tile.number << 6) + ((tile.y & 7) << 3); uint tileX = tile.x; uint mirrorX = tile.hflip ? 7 : 0; for(uint x : range(8)) { @@ -123,16 +123,16 @@ auto PPU::Line::renderObject(PPU::IO::Object& self) -> void { } } -auto PPU::oamAddressReset() -> void { +auto PPUfast::oamAddressReset() -> void { io.oamAddress = io.oamBaseAddress; oamSetFirstObject(); } -auto PPU::oamSetFirstObject() -> void { +auto PPUfast::oamSetFirstObject() -> void { io.obj.first = !io.oamPriority ? 0 : uint(io.oamAddress >> 2); } -auto PPU::readObject(uint10 address) -> uint8 { +auto PPUfast::readObject(uint10 address) -> uint8 { if(!address.bit(9)) { uint n = address >> 2; //object# address &= 3; @@ -161,7 +161,7 @@ auto PPU::readObject(uint10 address) -> uint8 { } } -auto PPU::writeObject(uint10 address, uint8 data) -> void { +auto PPUfast::writeObject(uint10 address, uint8 data) -> void { if(!address.bit(9)) { uint n = address >> 2; //object# address &= 3; diff --git a/bsnes/sfc/ppu-fast/ppu.cpp b/bsnes/sfc/ppu-fast/ppu.cpp new file mode 100644 index 00000000..d45ba9a8 --- /dev/null +++ b/bsnes/sfc/ppu-fast/ppu.cpp @@ -0,0 +1,155 @@ +#include + +namespace SuperFamicom { + +PPU& ppubase = ppu; + +PPUfast ppufast; +#include "io.cpp" +#include "line.cpp" +#include "background.cpp" +#include "mode7.cpp" +#include "mode7hires.cpp" +#include "mode7hd.cpp" +#include "object.cpp" +#include "window.cpp" +#include "serialization.cpp" + +auto PPUfast::interlace() const -> bool { return ppubase.display.interlace; } +auto PPUfast::overscan() const -> bool { return ppubase.display.overscan; } +auto PPUfast::vdisp() const -> uint { return ppubase.display.vdisp; } +auto PPUfast::hires() const -> bool { return latch.hires; } +auto PPUfast::hd() const -> bool { return latch.hd; } +auto PPUfast::hdScale() const -> uint { return configuration.hacks.ppu.mode7.scale; } +auto PPUfast::hdPerspective() const -> bool { return configuration.hacks.ppu.mode7.perspective; } + +PPUfast::PPUfast() { + output = new uint32[2304 * 2304] + 72 * 2304; //overscan offset + tilecache[TileMode::BPP2] = new uint8[4096 * 8 * 8]; + tilecache[TileMode::BPP4] = new uint8[2048 * 8 * 8]; + tilecache[TileMode::BPP8] = new uint8[1024 * 8 * 8]; + + for(uint y : range(lines.size())) { + lines[y].y = y; + } +} + +PPUfast::~PPUfast() { + delete[] (output - 72 * 2304); //overscan offset + delete[] tilecache[TileMode::BPP2]; + delete[] tilecache[TileMode::BPP4]; + delete[] tilecache[TileMode::BPP8]; +} + +auto PPUfast::Enter() -> void { + while(true) scheduler.synchronize(), ppufast.main(); +} + +auto PPUfast::step(uint clocks) -> void { + tick(clocks); + Thread::step(clocks); + synchronize(cpu); +} + +auto PPUfast::main() -> void { + scanline(); + + if(system.frameCounter == 0) { + uint y = vcounter(); + step(512); + if(y >= 1 && y <= 239) { + if(io.displayDisable || y >= vdisp()) { + lines[y].io.displayDisable = true; + } else { + memcpy(&lines[y].io, &io, sizeof(io)); + memcpy(&lines[y].cgram, &cgram, sizeof(cgram)); + } + if(!Line::count) Line::start = y; + Line::count++; + } + } + + step(lineclocks() - hcounter()); +} + +auto PPUfast::scanline() -> void { + if(vcounter() == 0) { + ppubase.display.interlace = io.interlace; + ppubase.display.overscan = io.overscan; + latch.hires = false; + latch.hd = false; + io.obj.timeOver = false; + io.obj.rangeOver = false; + } + + if(vcounter() > 0 && vcounter() < vdisp()) { + latch.hires |= io.pseudoHires || io.bgMode == 5 || io.bgMode == 6; + latch.hires |= io.bgMode == 7 && configuration.hacks.ppu.mode7.hires; + latch.hd |= io.bgMode == 7 && hdScale() > 1; + } + + if(vcounter() == vdisp() && !io.displayDisable) { + oamAddressReset(); + } + + if(vcounter() == 240) { + Line::flush(); + scheduler.exit(Scheduler::Event::Frame); + } +} + +auto PPUfast::refresh() -> void { + if(system.frameCounter == 0) { + auto output = this->output; + uint pitch, width, height; + if(!hd()) { + if(!overscan()) output -= 7 * 1024; + pitch = 512 << !interlace(); + width = 256 << hires(); + height = 240 << interlace(); + } else { + if(!overscan()) output -= 7 * 256 * hdScale() * hdScale(); + pitch = 256 * hdScale(); + width = 256 * hdScale(); + height = 240 * hdScale(); + } + Emulator::video.setEffect(Emulator::Video::Effect::ColorBleed, configuration.video.blurEmulation && hires()); + Emulator::video.refresh(output, pitch * sizeof(uint32), width, height); + } + if(system.frameCounter++ >= system.frameSkip) system.frameCounter = 0; +} + +auto PPUfast::load() -> bool { + return true; +} + +auto PPUfast::power(bool reset) -> void { + create(Enter, system.cpuFrequency()); + PPUcounter::reset(); + memory::fill(output, 1024 * 960); + + function uint8> reader{&PPUfast::readIO, this}; + function void> writer{&PPUfast::writeIO, this}; + bus.map(reader, writer, "00-3f,80-bf:2100-213f"); + + if(!reset) { + for(auto address : range(32768)) { + vram[address] = 0x0000; + updateTiledata(address); + } + for(auto& color : cgram) color = 0x0000; + for(auto& object : objects) object = {}; + } + + latch = {}; + io = {}; + updateVideoMode(); + + ItemLimit = !configuration.hacks.ppu.noSpriteLimit ? 32 : 128; + TileLimit = !configuration.hacks.ppu.noSpriteLimit ? 34 : 128; + + Line::start = 0; + Line::count = 0; +} + +} diff --git a/higan/sfc/ppu-fast/ppu.hpp b/bsnes/sfc/ppu-fast/ppu.hpp similarity index 65% rename from higan/sfc/ppu-fast/ppu.hpp rename to bsnes/sfc/ppu-fast/ppu.hpp index 24ac6eb0..de057931 100644 --- a/higan/sfc/ppu-fast/ppu.hpp +++ b/bsnes/sfc/ppu-fast/ppu.hpp @@ -5,18 +5,18 @@ //* vertical mosaic coordinates are not exact //* (hardware-mod) 128KB VRAM mode not supported -#define PPU PPUfast -#define ppu ppufast - -struct PPU : Thread, PPUcounter { +struct PPUfast : Thread, PPUcounter { alwaysinline auto interlace() const -> bool; alwaysinline auto overscan() const -> bool; alwaysinline auto vdisp() const -> uint; alwaysinline auto hires() const -> bool; + alwaysinline auto hd() const -> bool; + alwaysinline auto hdScale() const -> uint; + alwaysinline auto hdPerspective() const -> bool; //ppu.cpp - PPU(); - ~PPU(); + PPUfast(); + ~PPUfast(); static auto Enter() -> void; alwaysinline auto step(uint clocks) -> void; @@ -38,21 +38,22 @@ public: //serialization.cpp auto serialize(serializer&) -> void; - uint1 interlace; - uint1 overscan; - uint1 hires; + uint1 interlace; + uint1 overscan; + uint1 hires; + uint1 hd; uint16 vram; - uint8 oam; - uint8 cgram; + uint8 oam; + uint8 cgram; uint10 oamAddress; - uint8 cgramAddress; + uint8 cgramAddress; - uint8 mode7; - uint1 counters; - uint1 hcounter; //hdot - uint1 vcounter; + uint8 mode7; + uint1 counters; + uint1 hcounter; //hdot + uint1 vcounter; struct PPU { //serialization.cpp @@ -67,34 +68,34 @@ public: //serialization.cpp auto serialize(serializer&) -> void; - uint1 displayDisable; - uint4 displayBrightness; + uint1 displayDisable; + uint4 displayBrightness; uint10 oamBaseAddress; uint10 oamAddress; - uint1 oamPriority; - uint1 bgPriority; - uint3 bgMode; - uint4 mosaicSize; - uint1 vramIncrementMode; - uint2 vramMapping; - uint8 vramIncrementSize; + uint1 oamPriority; + uint1 bgPriority; + uint3 bgMode; + uint4 mosaicSize; + uint1 vramIncrementMode; + uint2 vramMapping; + uint8 vramIncrementSize; uint16 vramAddress; - uint8 cgramAddress; - uint1 cgramAddressLatch; - uint9 hcounter; //hdot - uint9 vcounter; - uint1 interlace; - uint1 overscan; - uint1 pseudoHires; - uint1 extbg; + uint8 cgramAddress; + uint1 cgramAddressLatch; + uint9 hcounter; //hdot + uint9 vcounter; + uint1 interlace; + uint1 overscan; + uint1 pseudoHires; + uint1 extbg; struct Mode7 { //serialization.cpp auto serialize(serializer&) -> void; - uint1 hflip; - uint1 vflip; - uint2 repeat; + uint1 hflip; + uint1 vflip; + uint2 repeat; uint16 a; uint16 b; uint16 c; @@ -146,17 +147,17 @@ public: auto serialize(serializer&) -> void; WindowLayer window; - uint1 aboveEnable; - uint1 belowEnable; - uint1 mosaicEnable; + uint1 aboveEnable; + uint1 belowEnable; + uint1 mosaicEnable; uint15 tiledataAddress; uint15 screenAddress; - uint2 screenSize; - uint1 tileSize; + uint2 screenSize; + uint1 tileSize; uint16 hoffset; uint16 voffset; - uint3 tileMode; - array priority; + uint3 tileMode; + uint4 priority[2]; } bg1, bg2, bg3, bg4; struct Object { @@ -164,16 +165,16 @@ public: auto serialize(serializer&) -> void; WindowLayer window; - uint1 aboveEnable; - uint1 belowEnable; - uint1 interlace; - uint3 baseSize; - uint2 nameselect; + uint1 aboveEnable; + uint1 belowEnable; + uint1 interlace; + uint3 baseSize; + uint2 nameselect; uint15 tiledataAddress; - uint7 first; - uint1 rangeOver; - uint1 timeOver; - array priority; + uint7 first; + uint1 rangeOver; + uint1 timeOver; + uint4 priority[4]; } obj; struct Color { @@ -181,11 +182,11 @@ public: auto serialize(serializer&) -> void; WindowColor window; - array enable; - uint1 directColor; - uint1 blendMode; //0 = fixed; 1 = pixel - uint1 halve; - uint1 mathMode; //0 = add; 1 = sub + uint1 enable[7]; + uint1 directColor; + uint1 blendMode; //0 = fixed; 1 = pixel + uint1 halve; + uint1 mathMode; //0 = add; 1 = sub uint15 fixedColor; } col; }; @@ -213,18 +214,18 @@ public: }; struct ObjectTile { - uint1 valid; - uint9 x; - uint8 y; - uint2 priority; - uint8 palette; - uint1 hflip; + uint1 valid; + uint9 x; + uint8 y; + uint2 priority; + uint8 palette; + uint1 hflip; uint11 number; }; struct Pixel { - uint source; - uint priority; + uint8 source; + uint8 priority; uint15 color; }; @@ -252,15 +253,15 @@ public: Latch latch; IO io; - array vram; - array cgram; - array objects; + uint16 vram[32 * 1024]; + uint15 cgram[256]; + Object objects[128]; //[unserialized] uint32* output; - array tilecache; //bitplane -> bitmap tiledata - uint ItemLimit; - uint TileLimit; + uint8* tilecache[3]; //bitplane -> bitmap tiledata + uint32 ItemLimit; + uint32 TileLimit; struct Line { //line.cpp @@ -271,20 +272,28 @@ public: alwaysinline auto directColor(uint paletteIndex, uint paletteColor) const -> uint15; alwaysinline auto plotAbove(uint x, uint source, uint priority, uint color) -> void; alwaysinline auto plotBelow(uint x, uint source, uint priority, uint color) -> void; + alwaysinline auto plotHD(Pixel*, uint x, uint source, uint priority, uint color, bool hires, bool subpixel) -> void; //background.cpp - auto renderBackground(PPU::IO::Background&, uint source) -> void; - auto getTile(PPU::IO::Background&, uint hoffset, uint voffset) -> uint; + auto renderBackground(PPUfast::IO::Background&, uint source) -> void; + auto getTile(PPUfast::IO::Background&, uint hoffset, uint voffset) -> uint; //mode7.cpp - auto renderMode7(PPU::IO::Background&, uint source) -> void; + auto renderMode7(PPUfast::IO::Background&, uint source) -> void; + + //mode7hires.cpp + auto renderMode7Hires(PPUfast::IO::Background&, uint source) -> void; + + //mode7hd.cpp + auto renderMode7HD(PPUfast::IO::Background&, uint source) -> void; + alwaysinline auto lerp(float pa, float va, float pb, float vb, float pr) -> float; //object.cpp - auto renderObject(PPU::IO::Object&) -> void; + auto renderObject(PPUfast::IO::Object&) -> void; //window.cpp - auto renderWindow(PPU::IO::WindowLayer&, bool, array&) -> void; - auto renderWindow(PPU::IO::WindowColor&, uint, array&) -> void; + auto renderWindow(PPUfast::IO::WindowLayer&, bool, array&) -> void; + auto renderWindow(PPUfast::IO::WindowColor&, uint, array&) -> void; //[unserialized] uint9 y; //constant @@ -295,8 +304,8 @@ public: array items; //32 on real hardware array tiles; //34 on real hardware; 1024 max (128 * 64-width tiles) - array above; //256 on real hardware - array below; //512 for hires mode 7 + Pixel above[256 * 9 * 9]; + Pixel below[256 * 9 * 9]; array windowAbove; array windowBelow; @@ -308,7 +317,4 @@ public: array lines; }; -extern PPU ppu; - -#undef PPU -#undef ppu +extern PPUfast ppufast; diff --git a/higan/sfc/ppu-fast/serialization.cpp b/bsnes/sfc/ppu-fast/serialization.cpp similarity index 79% rename from higan/sfc/ppu-fast/serialization.cpp rename to bsnes/sfc/ppu-fast/serialization.cpp index ef96687c..6c4d92ae 100644 --- a/higan/sfc/ppu-fast/serialization.cpp +++ b/bsnes/sfc/ppu-fast/serialization.cpp @@ -1,4 +1,4 @@ -auto PPU::serialize(serializer& s) -> void { +auto PPUfast::serialize(serializer& s) -> void { Thread::serialize(s); PPUcounter::serialize(s); @@ -13,10 +13,11 @@ auto PPU::serialize(serializer& s) -> void { Line::count = 0; } -auto PPU::Latch::serialize(serializer& s) -> void { +auto PPUfast::Latch::serialize(serializer& s) -> void { s.integer(interlace); s.integer(overscan); s.integer(hires); + s.integer(hd); s.integer(vram); s.integer(oam); s.integer(cgram); @@ -30,12 +31,12 @@ auto PPU::Latch::serialize(serializer& s) -> void { ppu2.serialize(s); } -auto PPU::Latch::PPU::serialize(serializer& s) -> void { +auto PPUfast::Latch::PPU::serialize(serializer& s) -> void { s.integer(mdr); s.integer(bgofs); } -auto PPU::IO::serialize(serializer& s) -> void { +auto PPUfast::IO::serialize(serializer& s) -> void { s.integer(displayDisable); s.integer(displayBrightness); s.integer(oamBaseAddress); @@ -67,7 +68,7 @@ auto PPU::IO::serialize(serializer& s) -> void { col.serialize(s); } -auto PPU::IO::Mode7::serialize(serializer& s) -> void { +auto PPUfast::IO::Mode7::serialize(serializer& s) -> void { s.integer(hflip); s.integer(vflip); s.integer(repeat); @@ -81,14 +82,14 @@ auto PPU::IO::Mode7::serialize(serializer& s) -> void { s.integer(voffset); } -auto PPU::IO::Window::serialize(serializer& s) -> void { +auto PPUfast::IO::Window::serialize(serializer& s) -> void { s.integer(oneLeft); s.integer(oneRight); s.integer(twoLeft); s.integer(twoRight); } -auto PPU::IO::WindowLayer::serialize(serializer& s) -> void { +auto PPUfast::IO::WindowLayer::serialize(serializer& s) -> void { s.integer(oneEnable); s.integer(oneInvert); s.integer(twoEnable); @@ -98,7 +99,7 @@ auto PPU::IO::WindowLayer::serialize(serializer& s) -> void { s.integer(belowEnable); } -auto PPU::IO::WindowColor::serialize(serializer& s) -> void { +auto PPUfast::IO::WindowColor::serialize(serializer& s) -> void { s.integer(oneEnable); s.integer(oneInvert); s.integer(twoEnable); @@ -108,7 +109,7 @@ auto PPU::IO::WindowColor::serialize(serializer& s) -> void { s.integer(belowMask); } -auto PPU::IO::Background::serialize(serializer& s) -> void { +auto PPUfast::IO::Background::serialize(serializer& s) -> void { window.serialize(s); s.integer(aboveEnable); s.integer(belowEnable); @@ -123,7 +124,7 @@ auto PPU::IO::Background::serialize(serializer& s) -> void { s.array(priority); } -auto PPU::IO::Object::serialize(serializer& s) -> void { +auto PPUfast::IO::Object::serialize(serializer& s) -> void { window.serialize(s); s.integer(aboveEnable); s.integer(belowEnable); @@ -137,7 +138,7 @@ auto PPU::IO::Object::serialize(serializer& s) -> void { s.array(priority); } -auto PPU::IO::Color::serialize(serializer& s) -> void { +auto PPUfast::IO::Color::serialize(serializer& s) -> void { window.serialize(s); s.array(enable); s.integer(directColor); @@ -147,7 +148,7 @@ auto PPU::IO::Color::serialize(serializer& s) -> void { s.integer(fixedColor); } -auto PPU::Object::serialize(serializer& s) -> void { +auto PPUfast::Object::serialize(serializer& s) -> void { s.integer(x); s.integer(y); s.integer(character); diff --git a/higan/sfc/ppu-fast/window.cpp b/bsnes/sfc/ppu-fast/window.cpp similarity index 91% rename from higan/sfc/ppu-fast/window.cpp rename to bsnes/sfc/ppu-fast/window.cpp index 2d49dc40..d6200776 100644 --- a/higan/sfc/ppu-fast/window.cpp +++ b/bsnes/sfc/ppu-fast/window.cpp @@ -1,4 +1,4 @@ -auto PPU::Line::renderWindow(PPU::IO::WindowLayer& self, bool enable, array& output) -> void { +auto PPUfast::Line::renderWindow(PPUfast::IO::WindowLayer& self, bool enable, array& output) -> void { if(!enable || (!self.oneEnable && !self.twoEnable)) { output.fill(0); return; @@ -32,7 +32,7 @@ auto PPU::Line::renderWindow(PPU::IO::WindowLayer& self, bool enable, array& output) -> void { +auto PPUfast::Line::renderWindow(PPUfast::IO::WindowColor& self, uint mask, array& output) -> void { bool set, clear; switch(mask) { case 0: output.fill(1); return; //always diff --git a/higan/sfc/ppu/background.cpp b/bsnes/sfc/ppu/background.cpp similarity index 100% rename from higan/sfc/ppu/background.cpp rename to bsnes/sfc/ppu/background.cpp diff --git a/higan/sfc/ppu/background.hpp b/bsnes/sfc/ppu/background.hpp similarity index 100% rename from higan/sfc/ppu/background.hpp rename to bsnes/sfc/ppu/background.hpp diff --git a/higan/sfc/ppu/counter/counter-inline.hpp b/bsnes/sfc/ppu/counter/counter-inline.hpp similarity index 100% rename from higan/sfc/ppu/counter/counter-inline.hpp rename to bsnes/sfc/ppu/counter/counter-inline.hpp diff --git a/higan/sfc/ppu/counter/counter.hpp b/bsnes/sfc/ppu/counter/counter.hpp similarity index 100% rename from higan/sfc/ppu/counter/counter.hpp rename to bsnes/sfc/ppu/counter/counter.hpp diff --git a/higan/sfc/ppu/counter/serialization.cpp b/bsnes/sfc/ppu/counter/serialization.cpp similarity index 100% rename from higan/sfc/ppu/counter/serialization.cpp rename to bsnes/sfc/ppu/counter/serialization.cpp diff --git a/higan/sfc/ppu/io.cpp b/bsnes/sfc/ppu/io.cpp similarity index 100% rename from higan/sfc/ppu/io.cpp rename to bsnes/sfc/ppu/io.cpp diff --git a/higan/sfc/ppu/mode7.cpp b/bsnes/sfc/ppu/mode7.cpp similarity index 100% rename from higan/sfc/ppu/mode7.cpp rename to bsnes/sfc/ppu/mode7.cpp diff --git a/higan/sfc/ppu/oam.cpp b/bsnes/sfc/ppu/oam.cpp similarity index 100% rename from higan/sfc/ppu/oam.cpp rename to bsnes/sfc/ppu/oam.cpp diff --git a/higan/sfc/ppu/object.cpp b/bsnes/sfc/ppu/object.cpp similarity index 100% rename from higan/sfc/ppu/object.cpp rename to bsnes/sfc/ppu/object.cpp diff --git a/higan/sfc/ppu/object.hpp b/bsnes/sfc/ppu/object.hpp similarity index 100% rename from higan/sfc/ppu/object.hpp rename to bsnes/sfc/ppu/object.hpp diff --git a/higan/sfc/ppu/ppu.cpp b/bsnes/sfc/ppu/ppu.cpp similarity index 100% rename from higan/sfc/ppu/ppu.cpp rename to bsnes/sfc/ppu/ppu.cpp diff --git a/higan/sfc/ppu/ppu.hpp b/bsnes/sfc/ppu/ppu.hpp similarity index 79% rename from higan/sfc/ppu/ppu.hpp rename to bsnes/sfc/ppu/ppu.hpp index 21e9c8ec..3fbba549 100644 --- a/higan/sfc/ppu/ppu.hpp +++ b/bsnes/sfc/ppu/ppu.hpp @@ -37,7 +37,7 @@ private: struct VRAM { auto& operator[](uint addr) { return data[addr & mask]; } uint16 data[64 * 1024]; - uint mask = 0x7fff; + uint16 mask = 0x7fff; } vram; uint32* output = nullptr; @@ -53,39 +53,39 @@ private: auto refresh() -> void; struct { - uint version; + uint4 version; uint8 mdr; } ppu1, ppu2; - struct Latches { + struct Latch { uint16 vram; - uint8 oam; - uint8 cgram; - uint8 bgofsPPU1; - uint3 bgofsPPU2; - uint8 mode7; - uint1 counters; - uint1 hcounter; - uint1 vcounter; + uint8 oam; + uint8 cgram; + uint8 bgofsPPU1; + uint3 bgofsPPU2; + uint8 mode7; + uint1 counters; + uint1 hcounter; + uint1 vcounter; uint10 oamAddress; - uint8 cgramAddress; + uint8 cgramAddress; } latch; struct IO { //$2100 INIDISP - bool displayDisable; - uint4 displayBrightness; + uint1 displayDisable; + uint4 displayBrightness; //$2102 OAMADDL //$2103 OAMADDH uint10 oamBaseAddress; uint10 oamAddress; - bool oamPriority; + uint1 oamPriority; //$2105 BGMODE - bool bgPriority; - uint8 bgMode; + uint1 bgPriority; + uint8 bgMode; //$210d BG1HOFS uint16 hoffsetMode7; @@ -94,18 +94,18 @@ private: uint16 voffsetMode7; //$2115 VMAIN - bool vramIncrementMode; - uint2 vramMapping; - uint8 vramIncrementSize; + uint1 vramIncrementMode; + uint2 vramMapping; + uint8 vramIncrementSize; //$2116 VMADDL //$2117 VMADDH uint16 vramAddress; //$211a M7SEL - uint2 repeatMode7; - bool vflipMode7; - bool hflipMode7; + uint2 repeatMode7; + uint1 vflipMode7; + uint1 hflipMode7; //$211b M7A uint16 m7a; @@ -126,14 +126,14 @@ private: uint16 m7y; //$2121 CGADD - uint8 cgramAddress; - uint1 cgramAddressLatch; + uint8 cgramAddress; + uint1 cgramAddressLatch; //$2133 SETINI - bool extbg; - bool pseudoHires; - bool overscan; - bool interlace; + uint1 extbg; + uint1 pseudoHires; + uint1 overscan; + uint1 interlace; //$213c OPHCT uint16 hcounter; diff --git a/higan/sfc/ppu/screen.cpp b/bsnes/sfc/ppu/screen.cpp similarity index 100% rename from higan/sfc/ppu/screen.cpp rename to bsnes/sfc/ppu/screen.cpp diff --git a/higan/sfc/ppu/screen.hpp b/bsnes/sfc/ppu/screen.hpp similarity index 100% rename from higan/sfc/ppu/screen.hpp rename to bsnes/sfc/ppu/screen.hpp diff --git a/higan/sfc/ppu/serialization.cpp b/bsnes/sfc/ppu/serialization.cpp similarity index 100% rename from higan/sfc/ppu/serialization.cpp rename to bsnes/sfc/ppu/serialization.cpp diff --git a/higan/sfc/ppu/window.cpp b/bsnes/sfc/ppu/window.cpp similarity index 100% rename from higan/sfc/ppu/window.cpp rename to bsnes/sfc/ppu/window.cpp diff --git a/higan/sfc/ppu/window.hpp b/bsnes/sfc/ppu/window.hpp similarity index 100% rename from higan/sfc/ppu/window.hpp rename to bsnes/sfc/ppu/window.hpp diff --git a/higan/sfc/sfc.hpp b/bsnes/sfc/sfc.hpp similarity index 97% rename from higan/sfc/sfc.hpp rename to bsnes/sfc/sfc.hpp index 07aea368..3686136c 100644 --- a/higan/sfc/sfc.hpp +++ b/bsnes/sfc/sfc.hpp @@ -16,9 +16,7 @@ #include #include -#if defined(CORE_GB) - #include -#endif +#include namespace SuperFamicom { #define platform Emulator::platform diff --git a/higan/sfc/slot/bsmemory/bsmemory.cpp b/bsnes/sfc/slot/bsmemory/bsmemory.cpp similarity index 100% rename from higan/sfc/slot/bsmemory/bsmemory.cpp rename to bsnes/sfc/slot/bsmemory/bsmemory.cpp diff --git a/higan/sfc/slot/bsmemory/bsmemory.hpp b/bsnes/sfc/slot/bsmemory/bsmemory.hpp similarity index 100% rename from higan/sfc/slot/bsmemory/bsmemory.hpp rename to bsnes/sfc/slot/bsmemory/bsmemory.hpp diff --git a/higan/sfc/slot/bsmemory/serialization.cpp b/bsnes/sfc/slot/bsmemory/serialization.cpp similarity index 100% rename from higan/sfc/slot/bsmemory/serialization.cpp rename to bsnes/sfc/slot/bsmemory/serialization.cpp diff --git a/higan/sfc/slot/slot.hpp b/bsnes/sfc/slot/slot.hpp similarity index 100% rename from higan/sfc/slot/slot.hpp rename to bsnes/sfc/slot/slot.hpp diff --git a/higan/sfc/slot/sufamiturbo/serialization.cpp b/bsnes/sfc/slot/sufamiturbo/serialization.cpp similarity index 100% rename from higan/sfc/slot/sufamiturbo/serialization.cpp rename to bsnes/sfc/slot/sufamiturbo/serialization.cpp diff --git a/higan/sfc/slot/sufamiturbo/sufamiturbo.cpp b/bsnes/sfc/slot/sufamiturbo/sufamiturbo.cpp similarity index 100% rename from higan/sfc/slot/sufamiturbo/sufamiturbo.cpp rename to bsnes/sfc/slot/sufamiturbo/sufamiturbo.cpp diff --git a/higan/sfc/slot/sufamiturbo/sufamiturbo.hpp b/bsnes/sfc/slot/sufamiturbo/sufamiturbo.hpp similarity index 100% rename from higan/sfc/slot/sufamiturbo/sufamiturbo.hpp rename to bsnes/sfc/slot/sufamiturbo/sufamiturbo.hpp diff --git a/higan/sfc/smp/io.cpp b/bsnes/sfc/smp/io.cpp similarity index 100% rename from higan/sfc/smp/io.cpp rename to bsnes/sfc/smp/io.cpp diff --git a/higan/sfc/smp/memory.cpp b/bsnes/sfc/smp/memory.cpp similarity index 98% rename from higan/sfc/smp/memory.cpp rename to bsnes/sfc/smp/memory.cpp index b85a1f6e..1ed03bb1 100644 --- a/higan/sfc/smp/memory.cpp +++ b/bsnes/sfc/smp/memory.cpp @@ -10,7 +10,7 @@ auto SMP::writeRAM(uint16 address, uint8 data) -> void { } auto SMP::idle() -> void { - wait(); + waitIdle(); } auto SMP::read(uint16 address) -> uint8 { diff --git a/higan/sfc/smp/serialization.cpp b/bsnes/sfc/smp/serialization.cpp similarity index 100% rename from higan/sfc/smp/serialization.cpp rename to bsnes/sfc/smp/serialization.cpp diff --git a/higan/sfc/smp/smp.cpp b/bsnes/sfc/smp/smp.cpp similarity index 100% rename from higan/sfc/smp/smp.cpp rename to bsnes/sfc/smp/smp.cpp diff --git a/higan/sfc/smp/smp.hpp b/bsnes/sfc/smp/smp.hpp similarity index 94% rename from higan/sfc/smp/smp.hpp rename to bsnes/sfc/smp/smp.hpp index be742749..6e97d9da 100644 --- a/higan/sfc/smp/smp.hpp +++ b/bsnes/sfc/smp/smp.hpp @@ -89,7 +89,9 @@ private: Timer< 16> timer2; inline auto wait(maybe address = nothing) -> void; + inline auto waitIdle(maybe address = nothing) -> void; inline auto step(uint clocks) -> void; + inline auto stepIdle(uint clocks) -> void; inline auto stepTimers(uint clocks) -> void; }; diff --git a/higan/sfc/smp/timing.cpp b/bsnes/sfc/smp/timing.cpp similarity index 75% rename from higan/sfc/smp/timing.cpp rename to bsnes/sfc/smp/timing.cpp index 29246e8e..4aaad961 100644 --- a/higan/sfc/smp/timing.cpp +++ b/bsnes/sfc/smp/timing.cpp @@ -19,9 +19,23 @@ auto SMP::wait(maybe addr) -> void { stepTimers(timerWaitStates[waitStates]); } +auto SMP::waitIdle(maybe addr) -> void { + static const uint cycleWaitStates[4] = {2, 4, 10, 20}; + static const uint timerWaitStates[4] = {2, 4, 8, 16}; + + uint waitStates = io.externalWaitStates; + if(!addr) waitStates = io.internalWaitStates; //idle cycles + else if((*addr & 0xfff0) == 0x00f0) waitStates = io.internalWaitStates; //IO registers + else if(*addr >= 0xffc0 && io.iplromEnable) waitStates = io.internalWaitStates; //IPLROM + + stepIdle(cycleWaitStates[waitStates]); + stepTimers(timerWaitStates[waitStates]); +} + auto SMP::step(uint clocks) -> void { Thread::step(clocks); - synchronize(dsp); + dsp.clock -= clocks; + while(dsp.clock < 0) dsp.main(); #if defined(DEBUGGER) synchronize(cpu); @@ -32,6 +46,11 @@ auto SMP::step(uint clocks) -> void { #endif } +auto SMP::stepIdle(uint clocks) -> void { + Thread::step(clocks); + dsp.clock -= clocks; +} + auto SMP::stepTimers(uint clocks) -> void { timer0.step(clocks); timer1.step(clocks); diff --git a/higan/sfc/system/serialization.cpp b/bsnes/sfc/system/serialization.cpp similarity index 97% rename from higan/sfc/system/serialization.cpp rename to bsnes/sfc/system/serialization.cpp index 7a490f4f..63764487 100644 --- a/higan/sfc/system/serialization.cpp +++ b/bsnes/sfc/system/serialization.cpp @@ -11,7 +11,6 @@ auto System::serialize() -> serializer { s.array(description); s.boolean(hacks.fastPPU); - s.boolean(hacks.fastDSP); serializeAll(s); return s; @@ -30,7 +29,6 @@ auto System::unserialize(serializer& s) -> bool { if(string{version} != Emulator::SerializerVersion) return false; s.boolean(hacks.fastPPU); - s.boolean(hacks.fastDSP); power(/* reset = */ false); serializeAll(s); @@ -98,7 +96,6 @@ auto System::serializeInit() -> void { s.array(description); s.boolean(hacks.fastPPU); - s.boolean(hacks.fastDSP); serializeAll(s); serializeSize = s.size(); diff --git a/higan/sfc/system/system.cpp b/bsnes/sfc/system/system.cpp similarity index 97% rename from higan/sfc/system/system.cpp rename to bsnes/sfc/system/system.cpp index 09ec5a25..4c826dbd 100644 --- a/higan/sfc/system/system.cpp +++ b/bsnes/sfc/system/system.cpp @@ -16,15 +16,13 @@ auto System::runToSave() -> void { scheduler.synchronize(cpu); scheduler.synchronize(smp); scheduler.synchronize(ppu); - scheduler.synchronize(dsp); for(auto coprocessor : cpu.coprocessors) scheduler.synchronize(*coprocessor); for(auto peripheral : cpu.peripherals) scheduler.synchronize(*peripheral); } auto System::load(Emulator::Interface* interface) -> bool { information = {}; - hacks.fastPPU = configuration.hacks.ppuFast.enable; - hacks.fastDSP = configuration.hacks.dspFast.enable; + hacks.fastPPU = configuration.hacks.ppu.fast; bus.reset(); if(!cpu.load()) return false; diff --git a/higan/sfc/system/system.hpp b/bsnes/sfc/system/system.hpp similarity index 93% rename from higan/sfc/system/system.hpp rename to bsnes/sfc/system/system.hpp index 632a24a6..6a4e3c37 100644 --- a/higan/sfc/system/system.hpp +++ b/bsnes/sfc/system/system.hpp @@ -7,7 +7,6 @@ struct System { inline auto apuFrequency() const -> double { return information.apuFrequency; } inline auto fastPPU() const -> bool { return hacks.fastPPU; } - inline auto fastDSP() const -> bool { return hacks.fastDSP; } auto run() -> void; auto runToSave() -> void; @@ -21,6 +20,9 @@ struct System { auto serialize() -> serializer; auto unserialize(serializer&) -> bool; + uint frameSkip = 0; + uint frameCounter = 0; + private: Emulator::Interface* interface = nullptr; @@ -33,7 +35,6 @@ private: struct Hacks { bool fastPPU = false; - bool fastDSP = false; } hacks; uint serializeSize = 0; diff --git a/higan/systems/Game Boy Color.sys/boot.rom b/bsnes/systems/Game Boy Color.sys/boot.rom similarity index 100% rename from higan/systems/Game Boy Color.sys/boot.rom rename to bsnes/systems/Game Boy Color.sys/boot.rom diff --git a/higan/systems/Game Boy Color.sys/manifest.bml b/bsnes/systems/Game Boy Color.sys/manifest.bml similarity index 100% rename from higan/systems/Game Boy Color.sys/manifest.bml rename to bsnes/systems/Game Boy Color.sys/manifest.bml diff --git a/higan/systems/Game Boy.sys/boot.rom b/bsnes/systems/Game Boy.sys/boot.rom similarity index 100% rename from higan/systems/Game Boy.sys/boot.rom rename to bsnes/systems/Game Boy.sys/boot.rom diff --git a/higan/systems/Game Boy.sys/manifest.bml b/bsnes/systems/Game Boy.sys/manifest.bml similarity index 100% rename from higan/systems/Game Boy.sys/manifest.bml rename to bsnes/systems/Game Boy.sys/manifest.bml diff --git a/higan/systems/Super Famicom.sys/boards.bml b/bsnes/systems/Super Famicom.sys/boards.bml similarity index 100% rename from higan/systems/Super Famicom.sys/boards.bml rename to bsnes/systems/Super Famicom.sys/boards.bml diff --git a/higan/systems/Super Famicom.sys/ipl.rom b/bsnes/systems/Super Famicom.sys/ipl.rom similarity index 100% rename from higan/systems/Super Famicom.sys/ipl.rom rename to bsnes/systems/Super Famicom.sys/ipl.rom diff --git a/higan/target-bsnes/GNUmakefile b/bsnes/target-bsnes/GNUmakefile similarity index 100% rename from higan/target-bsnes/GNUmakefile rename to bsnes/target-bsnes/GNUmakefile diff --git a/higan/target-bsnes/bsnes.cpp b/bsnes/target-bsnes/bsnes.cpp similarity index 96% rename from higan/target-bsnes/bsnes.cpp rename to bsnes/target-bsnes/bsnes.cpp index c222679f..00317843 100644 --- a/higan/target-bsnes/bsnes.cpp +++ b/bsnes/target-bsnes/bsnes.cpp @@ -32,7 +32,7 @@ auto nall::main(Arguments arguments) -> void { settings.location = argument.trimLeft("--settings=", 1L); } else if(inode::exists(argument)) { //game without option - program.gameQueue.append({";", argument}); + program.gameQueue.append({"Auto;", argument}); } else if(argument.find(";")) { //game with option auto game = argument.split(";", 1L); diff --git a/higan/target-bsnes/bsnes.hpp b/bsnes/target-bsnes/bsnes.hpp similarity index 100% rename from higan/target-bsnes/bsnes.hpp rename to bsnes/target-bsnes/bsnes.hpp diff --git a/higan/target-bsnes/input/hotkeys.cpp b/bsnes/target-bsnes/input/hotkeys.cpp similarity index 97% rename from higan/target-bsnes/input/hotkeys.cpp rename to bsnes/target-bsnes/input/hotkeys.cpp index 7daec2b5..23d03e88 100644 --- a/higan/target-bsnes/input/hotkeys.cpp +++ b/bsnes/target-bsnes/input/hotkeys.cpp @@ -44,10 +44,12 @@ auto InputManager::bindHotkeys() -> void { })); hotkeys.append(InputHotkey("Fast Forward").onPress([] { + emulator->setFrameSkip(9); video.setBlocking(false); audio.setBlocking(false); audio.setDynamic(false); }).onRelease([] { + emulator->setFrameSkip(0); video.setBlocking(settings.video.blocking); audio.setBlocking(settings.audio.blocking); audio.setDynamic(settings.audio.dynamic); diff --git a/higan/target-bsnes/input/input.cpp b/bsnes/target-bsnes/input/input.cpp similarity index 100% rename from higan/target-bsnes/input/input.cpp rename to bsnes/target-bsnes/input/input.cpp diff --git a/higan/target-bsnes/input/input.hpp b/bsnes/target-bsnes/input/input.hpp similarity index 100% rename from higan/target-bsnes/input/input.hpp rename to bsnes/target-bsnes/input/input.hpp diff --git a/higan/target-bsnes/presentation/presentation.cpp b/bsnes/target-bsnes/presentation/presentation.cpp similarity index 98% rename from higan/target-bsnes/presentation/presentation.cpp rename to bsnes/target-bsnes/presentation/presentation.cpp index 62e342b2..20d16eda 100644 --- a/higan/target-bsnes/presentation/presentation.cpp +++ b/bsnes/target-bsnes/presentation/presentation.cpp @@ -146,7 +146,9 @@ auto Presentation::create() -> void { }); viewport.setDroppable().onDrop([&](vector locations) { - program.gameQueue = locations; + if(!locations) return; + program.gameQueue = {}; + program.gameQueue.append({"Auto;", locations.first()}); program.load(); setFocused(); }).onSize([&] { @@ -196,7 +198,10 @@ auto Presentation::create() -> void { setBackgroundColor({0, 0, 0}); resizeWindow(); setAlignment(Alignment::Center); - setFullScreen(startFullScreen); + + //start in fullscreen mode if requested ... + //perform the exclusive mode change later on inside Program::create(), after the video driver has been initialized + if(startFullScreen) setFullScreen(); #if defined(PLATFORM_MACOS) Application::Cocoa::onAbout([&] { about.doActivate(); }); diff --git a/higan/target-bsnes/presentation/presentation.hpp b/bsnes/target-bsnes/presentation/presentation.hpp similarity index 100% rename from higan/target-bsnes/presentation/presentation.hpp rename to bsnes/target-bsnes/presentation/presentation.hpp diff --git a/higan/target-bsnes/program/audio.cpp b/bsnes/target-bsnes/program/audio.cpp similarity index 100% rename from higan/target-bsnes/program/audio.cpp rename to bsnes/target-bsnes/program/audio.cpp diff --git a/higan/target-bsnes/program/game-pak.cpp b/bsnes/target-bsnes/program/game-pak.cpp similarity index 100% rename from higan/target-bsnes/program/game-pak.cpp rename to bsnes/target-bsnes/program/game-pak.cpp diff --git a/higan/target-bsnes/program/game-rom.cpp b/bsnes/target-bsnes/program/game-rom.cpp similarity index 100% rename from higan/target-bsnes/program/game-rom.cpp rename to bsnes/target-bsnes/program/game-rom.cpp diff --git a/higan/target-bsnes/program/game.cpp b/bsnes/target-bsnes/program/game.cpp similarity index 100% rename from higan/target-bsnes/program/game.cpp rename to bsnes/target-bsnes/program/game.cpp diff --git a/higan/target-bsnes/program/hacks.cpp b/bsnes/target-bsnes/program/hacks.cpp similarity index 79% rename from higan/target-bsnes/program/hacks.cpp rename to bsnes/target-bsnes/program/hacks.cpp index 47b4a0a0..6a54bf32 100644 --- a/higan/target-bsnes/program/hacks.cpp +++ b/bsnes/target-bsnes/program/hacks.cpp @@ -1,8 +1,8 @@ auto Program::hackCompatibility() -> void { - bool fastPPU = emulatorSettings.fastPPUOption.checked(); + bool fastPPU = emulatorSettings.fastPPU.checked(); bool fastPPUNoSpriteLimit = emulatorSettings.noSpriteLimit.checked(); bool fastPPUHiresMode7 = emulatorSettings.hiresMode7.checked(); - bool fastDSP = emulatorSettings.fastDSPOption.checked(); + bool fastDSP = emulatorSettings.fastDSP.checked(); bool coprocessorsDelayedSync = emulatorSettings.coprocessorsDelayedSyncOption.checked(); auto title = superFamicom.title; @@ -10,10 +10,13 @@ auto Program::hackCompatibility() -> void { if(title == "KOUSHIEN_2") fastDSP = false; if(title == "RENDERING RANGER R2") fastDSP = false; - emulator->configure("Hacks/FastPPU/Enable", fastPPU); - emulator->configure("Hacks/FastPPU/NoSpriteLimit", fastPPUNoSpriteLimit); - emulator->configure("Hacks/FastPPU/HiresMode7", fastPPUHiresMode7); - emulator->configure("Hacks/FastDSP/Enable", fastDSP); + emulator->configure("Hacks/PPU/Fast", fastPPU); + emulator->configure("Hacks/PPU/NoSpriteLimit", fastPPUNoSpriteLimit); + emulator->configure("Hacks/PPU/Mode7/Hires", fastPPUHiresMode7); + emulator->configure("Hacks/PPU/Mode7/Scale", settings.emulator.hack.ppu.mode7.scale); + emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective); + emulator->configure("Hacks/DSP/Fast", fastDSP); + emulator->configure("Hacks/DSP/Cubic", settings.emulator.hack.dsp.cubic); emulator->configure("Hacks/Coprocessors/DelayedSync", coprocessorsDelayedSync); } diff --git a/higan/target-bsnes/program/input.cpp b/bsnes/target-bsnes/program/input.cpp similarity index 100% rename from higan/target-bsnes/program/input.cpp rename to bsnes/target-bsnes/program/input.cpp diff --git a/higan/target-bsnes/program/patch.cpp b/bsnes/target-bsnes/program/patch.cpp similarity index 100% rename from higan/target-bsnes/program/patch.cpp rename to bsnes/target-bsnes/program/patch.cpp diff --git a/higan/target-bsnes/program/paths.cpp b/bsnes/target-bsnes/program/paths.cpp similarity index 100% rename from higan/target-bsnes/program/paths.cpp rename to bsnes/target-bsnes/program/paths.cpp diff --git a/higan/target-bsnes/program/platform.cpp b/bsnes/target-bsnes/program/platform.cpp similarity index 90% rename from higan/target-bsnes/program/platform.cpp rename to bsnes/target-bsnes/program/platform.cpp index 51775255..24900ac7 100644 --- a/higan/target-bsnes/program/platform.cpp +++ b/bsnes/target-bsnes/program/platform.cpp @@ -110,9 +110,9 @@ auto Program::load(uint id, string name, string type, vector options) -> superFamicom.option = game(0); superFamicom.location = game(1); } else { - dialog.setTitle("Load Super Famicom"); + dialog.setTitle("Load SNES ROM"); dialog.setPath(path("Games", settings.path.recent.superFamicom)); - dialog.setFilters({string{"Super Famicom Games|*.sfc:*.smc:*.zip"}}); + dialog.setFilters({string{"SNES ROMs|*.sfc:*.smc:*.zip:*.SFC:*.SMC:*.ZIP:*.Sfc:*.Smc:*.Zip"}, string{"All Files|*"}}); superFamicom.location = dialog.openObject(); superFamicom.option = dialog.option(); } @@ -130,9 +130,9 @@ auto Program::load(uint id, string name, string type, vector options) -> gameBoy.option = game(0); gameBoy.location = game(1); } else { - dialog.setTitle("Load Game Boy"); + dialog.setTitle("Load Game Boy ROM"); dialog.setPath(path("Games", settings.path.recent.gameBoy)); - dialog.setFilters({string{"Game Boy Games|*.gb:*.gbc:*.zip"}}); + dialog.setFilters({string{"Game Boy ROMs|*.gb:*.gbc:*.zip:*.GB:*.GBC:*.ZIP:*.Gb:*.Gbc:*.Zip"}, string{"All Files|*"}}); gameBoy.location = dialog.openObject(); gameBoy.option = dialog.option(); } @@ -150,9 +150,9 @@ auto Program::load(uint id, string name, string type, vector options) -> bsMemory.option = game(0); bsMemory.location = game(1); } else { - dialog.setTitle("Load BS Memory"); + dialog.setTitle("Load BS Memory ROM"); dialog.setPath(path("Games", settings.path.recent.bsMemory)); - dialog.setFilters({string{"BS Memory Games|*.bs:*.zip"}}); + dialog.setFilters({string{"BS Memory ROMs|*.bs:*.zip:*.BS:*.ZIP:*.Bs:*.Zip"}, string{"All Files|*"}}); bsMemory.location = dialog.openObject(); bsMemory.option = dialog.option(); } @@ -170,9 +170,9 @@ auto Program::load(uint id, string name, string type, vector options) -> sufamiTurboA.option = game(0); sufamiTurboA.location = game(1); } else { - dialog.setTitle("Load Sufami Turbo - Slot A"); + dialog.setTitle("Load Sufami Turbo ROM - Slot A"); dialog.setPath(path("Games", settings.path.recent.sufamiTurboA)); - dialog.setFilters({string{"Sufami Turbo Games|*.st:*.zip"}}); + dialog.setFilters({string{"Sufami Turbo ROMs|*.st:*.zip:*.ST:*.ZIP:*.St:*.Zip"}, string{"All Files|*"}}); sufamiTurboA.location = dialog.openObject(); sufamiTurboA.option = dialog.option(); } @@ -190,9 +190,9 @@ auto Program::load(uint id, string name, string type, vector options) -> sufamiTurboB.option = game(0); sufamiTurboB.location = game(1); } else { - dialog.setTitle("Load Sufami Turbo - Slot B"); + dialog.setTitle("Load Sufami Turbo ROM - Slot B"); dialog.setPath(path("Games", settings.path.recent.sufamiTurboB)); - dialog.setFilters({string{"Sufami Turbo Games|*.st:*.zip"}}); + dialog.setFilters({string{"Sufami Turbo ROMs|*.st:*.zip:*.ST:*.ZIP:*.St:*.Zip"}, string{"All Files|*"}}); sufamiTurboB.location = dialog.openObject(); sufamiTurboB.option = dialog.option(); } @@ -218,8 +218,8 @@ auto Program::videoFrame(const uint32* data, uint pitch, uint width, uint height pitch >>= 2; if(!presentation.showOverscanArea.checked()) { - if(height == 240) data += 8 * pitch, height -= 16; - if(height == 480) data += 16 * pitch, height -= 32; + data += (height / 30) * pitch; + height -= height / 15; } if(auto [output, length] = video.acquire(width, height); output) { @@ -247,7 +247,7 @@ auto Program::videoFrame(const uint32* data, uint pitch, uint width, uint height current = chrono::timestamp(); if(current != previous) { previous = current; - showFrameRate({frameCounter, " FPS"}); + showFrameRate({frameCounter * (1 + emulator->frameSkip()), " FPS"}); frameCounter = 0; } } diff --git a/higan/target-bsnes/program/program.cpp b/bsnes/target-bsnes/program/program.cpp similarity index 89% rename from higan/target-bsnes/program/program.cpp rename to bsnes/target-bsnes/program/program.cpp index 1803c4ff..6f3e8e59 100644 --- a/higan/target-bsnes/program/program.cpp +++ b/bsnes/target-bsnes/program/program.cpp @@ -59,6 +59,11 @@ auto Program::create() -> void { driverSettings.inputDriverChanged(); if(gameQueue) load(); + if(presentation.startFullScreen && emulator->loaded()) { + //remove the earlier fullscreen mode state, so that toggleFullscreenMode will enter fullscreen exclusive mode + presentation.setFullScreen(false); + presentation.toggleFullscreenMode(); + } Application::onMain({&Program::main, this}); } diff --git a/higan/target-bsnes/program/program.hpp b/bsnes/target-bsnes/program/program.hpp similarity index 100% rename from higan/target-bsnes/program/program.hpp rename to bsnes/target-bsnes/program/program.hpp diff --git a/higan/target-bsnes/program/states.cpp b/bsnes/target-bsnes/program/states.cpp similarity index 100% rename from higan/target-bsnes/program/states.cpp rename to bsnes/target-bsnes/program/states.cpp diff --git a/higan/target-bsnes/program/utility.cpp b/bsnes/target-bsnes/program/utility.cpp similarity index 100% rename from higan/target-bsnes/program/utility.cpp rename to bsnes/target-bsnes/program/utility.cpp diff --git a/higan/target-bsnes/program/video.cpp b/bsnes/target-bsnes/program/video.cpp similarity index 100% rename from higan/target-bsnes/program/video.cpp rename to bsnes/target-bsnes/program/video.cpp diff --git a/higan/target-bsnes/resource/GNUmakefile b/bsnes/target-bsnes/resource/GNUmakefile similarity index 100% rename from higan/target-bsnes/resource/GNUmakefile rename to bsnes/target-bsnes/resource/GNUmakefile diff --git a/higan/target-bsnes/resource/bsnes.Manifest b/bsnes/target-bsnes/resource/bsnes.Manifest similarity index 100% rename from higan/target-bsnes/resource/bsnes.Manifest rename to bsnes/target-bsnes/resource/bsnes.Manifest diff --git a/higan/target-bsnes/resource/bsnes.desktop b/bsnes/target-bsnes/resource/bsnes.desktop similarity index 100% rename from higan/target-bsnes/resource/bsnes.desktop rename to bsnes/target-bsnes/resource/bsnes.desktop diff --git a/higan/target-bsnes/resource/bsnes.ico b/bsnes/target-bsnes/resource/bsnes.ico similarity index 100% rename from higan/target-bsnes/resource/bsnes.ico rename to bsnes/target-bsnes/resource/bsnes.ico diff --git a/higan/target-bsnes/resource/bsnes.plist b/bsnes/target-bsnes/resource/bsnes.plist similarity index 100% rename from higan/target-bsnes/resource/bsnes.plist rename to bsnes/target-bsnes/resource/bsnes.plist diff --git a/higan/target-bsnes/resource/bsnes.png b/bsnes/target-bsnes/resource/bsnes.png similarity index 100% rename from higan/target-bsnes/resource/bsnes.png rename to bsnes/target-bsnes/resource/bsnes.png diff --git a/higan/target-bsnes/resource/bsnes.rc b/bsnes/target-bsnes/resource/bsnes.rc similarity index 100% rename from higan/target-bsnes/resource/bsnes.rc rename to bsnes/target-bsnes/resource/bsnes.rc diff --git a/higan/target-bsnes/resource/bsnes.svg b/bsnes/target-bsnes/resource/bsnes.svg similarity index 100% rename from higan/target-bsnes/resource/bsnes.svg rename to bsnes/target-bsnes/resource/bsnes.svg diff --git a/higan/target-bsnes/resource/icon.png b/bsnes/target-bsnes/resource/icon.png similarity index 100% rename from higan/target-bsnes/resource/icon.png rename to bsnes/target-bsnes/resource/icon.png diff --git a/higan/target-bsnes/resource/locales/japanese.bml b/bsnes/target-bsnes/resource/locales/japanese.bml similarity index 100% rename from higan/target-bsnes/resource/locales/japanese.bml rename to bsnes/target-bsnes/resource/locales/japanese.bml diff --git a/higan/target-bsnes/resource/logo.png b/bsnes/target-bsnes/resource/logo.png similarity index 100% rename from higan/target-bsnes/resource/logo.png rename to bsnes/target-bsnes/resource/logo.png diff --git a/higan/target-bsnes/resource/resource.bml b/bsnes/target-bsnes/resource/resource.bml similarity index 100% rename from higan/target-bsnes/resource/resource.bml rename to bsnes/target-bsnes/resource/resource.bml diff --git a/higan/target-bsnes/resource/resource.cpp b/bsnes/target-bsnes/resource/resource.cpp similarity index 100% rename from higan/target-bsnes/resource/resource.cpp rename to bsnes/target-bsnes/resource/resource.cpp diff --git a/higan/target-bsnes/resource/resource.hpp b/bsnes/target-bsnes/resource/resource.hpp similarity index 100% rename from higan/target-bsnes/resource/resource.hpp rename to bsnes/target-bsnes/resource/resource.hpp diff --git a/higan/target-bsnes/settings/audio.cpp b/bsnes/target-bsnes/settings/audio.cpp similarity index 97% rename from higan/target-bsnes/settings/audio.cpp rename to bsnes/target-bsnes/settings/audio.cpp index 500db81e..932ca09c 100644 --- a/higan/target-bsnes/settings/audio.cpp +++ b/bsnes/target-bsnes/settings/audio.cpp @@ -8,7 +8,7 @@ auto AudioSettings::create() -> void { effectsLayout.setSize({3, 3}); effectsLayout.column(0).setAlignment(1.0); skewLabel.setText("Skew:").setToolTip( - "Adjusts the audio frequency by the skew amount (in hz.)\n\n" + "Adjusts the audio frequency by the skew amount (in Hz.)\n\n" "This is essentially static rate control:\n" "First, enable both video and audio sync.\n" "Then, raise or lower this value to try to reduce errors.\n" diff --git a/higan/target-bsnes/settings/drivers.cpp b/bsnes/target-bsnes/settings/drivers.cpp similarity index 98% rename from higan/target-bsnes/settings/drivers.cpp rename to bsnes/target-bsnes/settings/drivers.cpp index 59d0a573..ca739d2b 100644 --- a/higan/target-bsnes/settings/drivers.cpp +++ b/bsnes/target-bsnes/settings/drivers.cpp @@ -82,7 +82,7 @@ auto DriverSettings::create() -> void { "Use this with video sync enabled, and audio sync disabled.\n\n" "This can produce perfectly smooth video and clean audio,\n" "but only if your monitor refresh rate is set correctly:\n" - "60hz for NTSC games, and 50hz for PAL games." + "60 Hz for NTSC games, and 50 Hz for PAL games." ).onToggle([&] { settings.audio.dynamic = audioDynamicToggle.checked(); program.updateAudioDynamic(); @@ -119,7 +119,7 @@ auto DriverSettings::videoDriverChanged() -> void { videoDriverActive.setText({"Active driver: ", video.driver()}); videoDriverOption.doChange(); videoFormatChanged(); - videoExclusiveToggle.setChecked(video.exclusive()).setEnabled(video.hasExclusive()); + videoExclusiveToggle.setChecked(settings.video.exclusive && video.hasExclusive()).setEnabled(video.hasExclusive()); videoBlockingToggle.setChecked(video.blocking()).setEnabled(video.hasBlocking()); videoFlushToggle.setChecked(video.flush()).setEnabled(video.hasFlush()); layout.setGeometry(layout.geometry()); @@ -224,7 +224,7 @@ auto DriverSettings::audioFrequencyChanged() -> void { audioFrequencyOption.reset(); for(auto& frequency : audio.hasFrequencies()) { ComboButtonItem item{&audioFrequencyOption}; - item.setText({frequency, "hz"}); + item.setText({frequency, " Hz"}); if(frequency == audio.frequency()) item.setSelected(); } //audioFrequencyOption.setEnabled(audio->hasFrequency()); diff --git a/bsnes/target-bsnes/settings/emulator.cpp b/bsnes/target-bsnes/settings/emulator.cpp new file mode 100644 index 00000000..8db1ee45 --- /dev/null +++ b/bsnes/target-bsnes/settings/emulator.cpp @@ -0,0 +1,114 @@ +auto EmulatorSettings::create() -> void { + setIcon(Icon::Action::Settings); + setText("Emulator"); + + layout.setPadding(5_sx); + + optionsLabel.setText("Options").setFont(Font().setBold()); + inputFocusLabel.setText("When focus is lost:"); + pauseEmulation.setText("Pause emulation").onActivate([&] { + settings.input.defocus = "Pause"; + }); + blockInput.setText("Block input").onActivate([&] { + settings.input.defocus = "Block"; + }); + allowInput.setText("Allow input").onActivate([&] { + settings.input.defocus = "Allow"; + }); + if(settings.input.defocus == "Pause") pauseEmulation.setChecked(); + if(settings.input.defocus == "Block") blockInput.setChecked(); + if(settings.input.defocus == "Allow") allowInput.setChecked(); + warnOnUnverifiedGames.setText("Warn when loading games that have not been verified").setChecked(settings.emulator.warnOnUnverifiedGames).onToggle([&] { + settings.emulator.warnOnUnverifiedGames = warnOnUnverifiedGames.checked(); + }); + autoSaveMemory.setText("Auto-save memory periodically").setChecked(settings.emulator.autoSaveMemory.enable).onToggle([&] { + settings.emulator.autoSaveMemory.enable = autoSaveMemory.checked(); + }); + autoSaveStateOnUnload.setText("Auto-save undo state when unloading games").setChecked(settings.emulator.autoSaveStateOnUnload).onToggle([&] { + settings.emulator.autoSaveStateOnUnload = autoSaveStateOnUnload.checked(); + if(!autoSaveStateOnUnload.checked()) { + autoLoadStateOnLoad.setEnabled(false).setChecked(false).doToggle(); + } else { + autoLoadStateOnLoad.setEnabled(true); + } + }).doToggle(); + autoLoadStateOnLoad.setText("Auto-resume on load").setChecked(settings.emulator.autoLoadStateOnLoad).onToggle([&] { + settings.emulator.autoLoadStateOnLoad = autoLoadStateOnLoad.checked(); + }); + optionsSpacer.setColor({192, 192, 192}); + + ppuLabel.setText("PPU (video)").setFont(Font().setBold()); + fastPPU.setText("Fast mode").setChecked(settings.emulator.hack.ppu.fast).onToggle([&] { + settings.emulator.hack.ppu.fast = fastPPU.checked(); + if(!fastPPU.checked()) { + noSpriteLimit.setEnabled(false).setChecked(false).doToggle(); + hiresMode7.setEnabled(false).setChecked(false).doToggle(); + } else { + noSpriteLimit.setEnabled(true); + hiresMode7.setEnabled(true); + } + }).doToggle(); + noSpriteLimit.setText("No sprite limit").setChecked(settings.emulator.hack.ppu.noSpriteLimit).onToggle([&] { + settings.emulator.hack.ppu.noSpriteLimit = noSpriteLimit.checked(); + }); + hiresMode7.setText("Hires mode 7").setChecked(settings.emulator.hack.ppu.mode7.hires).setVisible(false).onToggle([&] { + settings.emulator.hack.ppu.mode7.hires = hiresMode7.checked(); + emulator->configure("Hacks/PPU/Mode7/Hires", settings.emulator.hack.ppu.mode7.hires); + }); + mode7Label.setText("HD Mode 7 (fast PPU only)").setFont(Font().setBold()); + mode7ScaleLabel.setText("Scale:"); + mode7Scale.append(ComboButtonItem().setText( "240p").setProperty("multiplier", 1)); + mode7Scale.append(ComboButtonItem().setText( "480p").setProperty("multiplier", 2)); + mode7Scale.append(ComboButtonItem().setText( "720p").setProperty("multiplier", 3)); + mode7Scale.append(ComboButtonItem().setText( "960p").setProperty("multiplier", 4)); + mode7Scale.append(ComboButtonItem().setText("1200p").setProperty("multiplier", 5)); + mode7Scale.append(ComboButtonItem().setText("1440p").setProperty("multiplier", 6)); + mode7Scale.append(ComboButtonItem().setText("1680p").setProperty("multiplier", 7)); + mode7Scale.append(ComboButtonItem().setText("1920p").setProperty("multiplier", 8)); + mode7Scale.append(ComboButtonItem().setText("2160p").setProperty("multiplier", 9)); + for(uint n = 1; n <= 9; n++) { + if(settings.emulator.hack.ppu.mode7.scale == n) mode7Scale.item(n - 1).setSelected(); + } + mode7Scale.onChange([&] { + settings.emulator.hack.ppu.mode7.scale = mode7Scale.selected().property("multiplier").natural(); + emulator->configure("Hacks/PPU/Mode7/Scale", settings.emulator.hack.ppu.mode7.scale); + }); + mode7Perspective.setText("Perspective correction").setChecked(settings.emulator.hack.ppu.mode7.perspective).onToggle([&] { + settings.emulator.hack.ppu.mode7.perspective = mode7Perspective.checked(); + emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective); + }); + dspLabel.setText("DSP (audio)").setFont(Font().setBold()); + fastDSP.setText("Fast mode").setChecked(settings.emulator.hack.dsp.fast).onToggle([&] { + settings.emulator.hack.dsp.fast = fastDSP.checked(); + emulator->configure("Hacks/DSP/Fast", settings.emulator.hack.dsp.fast); + }); + cubicInterpolation.setText("Cubic interpolation").setChecked(settings.emulator.hack.dsp.cubic).onToggle([&] { + settings.emulator.hack.dsp.cubic = cubicInterpolation.checked(); + emulator->configure("Hacks/DSP/Cubic", settings.emulator.hack.dsp.cubic); + }); + coprocessorLabel.setText("Coprocessors").setFont(Font().setBold()); + coprocessorsDelayedSyncOption.setText("Fast mode").setChecked(settings.emulator.hack.coprocessors.delayedSync).onToggle([&] { + settings.emulator.hack.coprocessors.delayedSync = coprocessorsDelayedSyncOption.checked(); + }); + coprocessorsHLEOption.setText("Prefer HLE").setChecked(settings.emulator.hack.coprocessors.hle).onToggle([&] { + settings.emulator.hack.coprocessors.hle = coprocessorsHLEOption.checked(); + }); + superFXLabel.setText("SuperFX clock speed:"); + superFXValue.setAlignment(0.5); + superFXClock.setLength(71).setPosition((settings.emulator.hack.fastSuperFX - 100) / 10).onChange([&] { + settings.emulator.hack.fastSuperFX = superFXClock.position() * 10 + 100; + superFXValue.setText({settings.emulator.hack.fastSuperFX, "%"}); + }).doChange(); + hacksNote.setForegroundColor({224, 0, 0}).setText("Note: some hack setting changes do not take effect until after reloading games."); +} + +auto EmulatorSettings::updateConfiguration() -> void { + emulator->configure("Hacks/PPU/Fast", fastPPU.checked()); + emulator->configure("Hacks/PPU/NoSpriteLimit", noSpriteLimit.checked()); + emulator->configure("Hacks/PPU/Mode7/Hires", hiresMode7.checked()); + emulator->configure("Hacks/PPU/Mode7/Scale", mode7Scale.selected().property("multiplier").natural()); + emulator->configure("Hacks/DSP/Fast", fastDSP.checked()); + emulator->configure("Hacks/DSP/Cubic", cubicInterpolation.checked()); + emulator->configure("Hacks/Coprocessor/DelayedSync", coprocessorsDelayedSyncOption.checked()); + emulator->configure("Hacks/Coprocessor/HLE", coprocessorsHLEOption.checked()); +} diff --git a/higan/target-bsnes/settings/hotkeys.cpp b/bsnes/target-bsnes/settings/hotkeys.cpp similarity index 100% rename from higan/target-bsnes/settings/hotkeys.cpp rename to bsnes/target-bsnes/settings/hotkeys.cpp diff --git a/higan/target-bsnes/settings/input.cpp b/bsnes/target-bsnes/settings/input.cpp similarity index 100% rename from higan/target-bsnes/settings/input.cpp rename to bsnes/target-bsnes/settings/input.cpp diff --git a/higan/target-bsnes/settings/paths.cpp b/bsnes/target-bsnes/settings/paths.cpp similarity index 100% rename from higan/target-bsnes/settings/paths.cpp rename to bsnes/target-bsnes/settings/paths.cpp diff --git a/higan/target-bsnes/settings/settings.cpp b/bsnes/target-bsnes/settings/settings.cpp similarity index 89% rename from higan/target-bsnes/settings/settings.cpp rename to bsnes/target-bsnes/settings/settings.cpp index 7e5b83b3..86583817 100644 --- a/higan/target-bsnes/settings/settings.cpp +++ b/bsnes/target-bsnes/settings/settings.cpp @@ -95,10 +95,13 @@ auto Settings::process(bool load) -> void { bind(natural, "Emulator/AutoSaveMemory/Interval", emulator.autoSaveMemory.interval); bind(boolean, "Emulator/AutoSaveStateOnUnload", emulator.autoSaveStateOnUnload); bind(boolean, "Emulator/AutoLoadStateOnLoad", emulator.autoLoadStateOnLoad); - bind(boolean, "Emulator/Hack/FastPPU/Enable", emulator.hack.fastPPU.enable); - bind(boolean, "Emulator/Hack/FastPPU/NoSpriteLimit", emulator.hack.fastPPU.noSpriteLimit); - bind(boolean, "Emulator/Hack/FastPPU/HiresMode7", emulator.hack.fastPPU.hiresMode7); - bind(boolean, "Emulator/Hack/FastDSP/Enable", emulator.hack.fastDSP.enable); + bind(boolean, "Emulator/Hack/PPU/Fast", emulator.hack.ppu.fast); + bind(boolean, "Emulator/Hack/PPU/NoSpriteLimit", emulator.hack.ppu.noSpriteLimit); + bind(boolean, "Emulator/Hack/PPU/Mode7/Hires", emulator.hack.ppu.mode7.hires); + bind(natural, "Emulator/Hack/PPU/Mode7/Scale", emulator.hack.ppu.mode7.scale); + bind(boolean, "Emulator/Hack/PPU/Mode7/Perspective", emulator.hack.ppu.mode7.perspective); + bind(boolean, "Emulator/Hack/DSP/Fast", emulator.hack.dsp.fast); + bind(boolean, "Emulator/Hack/DSP/Cubic", emulator.hack.dsp.cubic); bind(boolean, "Emulator/Hack/Coprocessors/DelayedSync", emulator.hack.coprocessors.delayedSync); bind(boolean, "Emulator/Hack/Coprocessors/HLE", emulator.hack.coprocessors.hle); bind(natural, "Emulator/Hack/FastSuperFX", emulator.hack.fastSuperFX); diff --git a/higan/target-bsnes/settings/settings.hpp b/bsnes/target-bsnes/settings/settings.hpp similarity index 91% rename from higan/target-bsnes/settings/settings.hpp rename to bsnes/target-bsnes/settings/settings.hpp index 4c781d04..4dd043d5 100644 --- a/higan/target-bsnes/settings/settings.hpp +++ b/bsnes/target-bsnes/settings/settings.hpp @@ -75,14 +75,19 @@ struct Settings : Markup::Node { bool autoSaveStateOnUnload = false; bool autoLoadStateOnLoad = false; struct Hack { - struct FastPPU { - bool enable = true; + struct PPU { + bool fast = true; bool noSpriteLimit = false; - bool hiresMode7 = false; - } fastPPU; - struct FastDSP { - bool enable = true; - } fastDSP; + struct Mode7 { + bool hires = false; + uint scale = 1; + bool perspective = true; + } mode7; + } ppu; + struct DSP { + bool fast = true; + bool cubic = false; + } dsp; struct Coprocessors { bool delayedSync = true; bool hle = true; @@ -256,12 +261,21 @@ public: CheckLabel autoSaveStateOnUnload{&autoStateLayout, Size{0, 0}}; CheckLabel autoLoadStateOnLoad{&autoStateLayout, Size{0, 0}}; Canvas optionsSpacer{&layout, Size{~0, 1}}; - Label hacksLabel{&layout, Size{~0, 0}, 2}; - HorizontalLayout fastPPULayout{&layout, Size{~0, 0}}; - CheckLabel fastPPUOption{&fastPPULayout, Size{0, 0}}; - CheckLabel noSpriteLimit{&fastPPULayout, Size{0, 0}}; - CheckLabel hiresMode7{&fastPPULayout, Size{0, 0}}; - CheckLabel fastDSPOption{&layout, Size{~0, 0}}; + Label ppuLabel{&layout, Size{~0, 0}, 2}; + HorizontalLayout ppuLayout{&layout, Size{~0, 0}}; + CheckLabel fastPPU{&ppuLayout, Size{0, 0}}; + CheckLabel noSpriteLimit{&ppuLayout, Size{0, 0}}; + CheckLabel hiresMode7{&ppuLayout, Size{0, 0}}; + Label mode7Label{&layout, Size{~0, 0}, 2}; + HorizontalLayout mode7Layout{&layout, Size{~0, 0}}; + Label mode7ScaleLabel{&mode7Layout, Size{0, 0}}; + ComboButton mode7Scale{&mode7Layout, Size{0, 0}}; + CheckLabel mode7Perspective{&mode7Layout, Size{0, 0}}; + Label dspLabel{&layout, Size{~0, 0}, 2}; + HorizontalLayout dspLayout{&layout, Size{~0, 0}}; + CheckLabel fastDSP{&dspLayout, Size{0, 0}}; + CheckLabel cubicInterpolation{&dspLayout, Size{0, 0}}; + Label coprocessorLabel{&layout, Size{~0, 0}, 2}; HorizontalLayout coprocessorsLayout{&layout, Size{~0, 0}}; CheckLabel coprocessorsDelayedSyncOption{&coprocessorsLayout, Size{0, 0}}; CheckLabel coprocessorsHLEOption{&coprocessorsLayout, Size{0, 0}}; diff --git a/higan/target-bsnes/settings/video.cpp b/bsnes/target-bsnes/settings/video.cpp similarity index 100% rename from higan/target-bsnes/settings/video.cpp rename to bsnes/target-bsnes/settings/video.cpp diff --git a/higan/target-bsnes/tools/cheat-editor.cpp b/bsnes/target-bsnes/tools/cheat-editor.cpp similarity index 100% rename from higan/target-bsnes/tools/cheat-editor.cpp rename to bsnes/target-bsnes/tools/cheat-editor.cpp diff --git a/higan/target-bsnes/tools/manifest-viewer.cpp b/bsnes/target-bsnes/tools/manifest-viewer.cpp similarity index 100% rename from higan/target-bsnes/tools/manifest-viewer.cpp rename to bsnes/target-bsnes/tools/manifest-viewer.cpp diff --git a/higan/target-bsnes/tools/state-manager.cpp b/bsnes/target-bsnes/tools/state-manager.cpp similarity index 100% rename from higan/target-bsnes/tools/state-manager.cpp rename to bsnes/target-bsnes/tools/state-manager.cpp diff --git a/higan/target-bsnes/tools/tools.cpp b/bsnes/target-bsnes/tools/tools.cpp similarity index 100% rename from higan/target-bsnes/tools/tools.cpp rename to bsnes/target-bsnes/tools/tools.cpp diff --git a/higan/target-bsnes/tools/tools.hpp b/bsnes/target-bsnes/tools/tools.hpp similarity index 100% rename from higan/target-bsnes/tools/tools.hpp rename to bsnes/target-bsnes/tools/tools.hpp diff --git a/higan/fc/GNUmakefile b/higan/fc/GNUmakefile deleted file mode 100644 index 176da259..00000000 --- a/higan/fc/GNUmakefile +++ /dev/null @@ -1,13 +0,0 @@ -processors += mos6502 - -objects += fc-interface fc-system fc-controller -objects += fc-memory fc-cartridge fc-cpu fc-apu fc-ppu - -obj/fc-interface.o: fc/interface/interface.cpp -obj/fc-system.o: fc/system/system.cpp -obj/fc-controller.o: fc/controller/controller.cpp -obj/fc-memory.o: fc/memory/memory.cpp -obj/fc-cartridge.o: fc/cartridge/cartridge.cpp -obj/fc-cpu.o: fc/cpu/cpu.cpp -obj/fc-apu.o: fc/apu/apu.cpp -obj/fc-ppu.o: fc/ppu/ppu.cpp diff --git a/higan/fc/apu/apu.cpp b/higan/fc/apu/apu.cpp deleted file mode 100644 index 45a55189..00000000 --- a/higan/fc/apu/apu.cpp +++ /dev/null @@ -1,319 +0,0 @@ -#include - -namespace Famicom { - -#include "envelope.cpp" -#include "sweep.cpp" -#include "pulse.cpp" -#include "triangle.cpp" -#include "noise.cpp" -#include "dmc.cpp" -#include "serialization.cpp" -APU apu; - -APU::APU() { - for(uint amp : range(32)) { - if(amp == 0) { - pulseDAC[amp] = 0; - } else { - pulseDAC[amp] = 16384.0 * 95.88 / (8128.0 / amp + 100.0); - } - } - - for(uint dmc_amp : range(128)) { - for(uint triangle_amp : range(16)) { - for(uint noise_amp : range(16)) { - if(dmc_amp == 0 && triangle_amp == 0 && noise_amp == 0) { - dmcTriangleNoiseDAC[dmc_amp][triangle_amp][noise_amp] = 0; - } else { - dmcTriangleNoiseDAC[dmc_amp][triangle_amp][noise_amp] - = 16384.0 * 159.79 / (100.0 + 1.0 / (triangle_amp / 8227.0 + noise_amp / 12241.0 + dmc_amp / 22638.0)); - } - } - } - } -} - -auto APU::Enter() -> void { - while(true) scheduler.synchronize(), apu.main(); -} - -auto APU::main() -> void { - uint pulse_output, triangle_output, noise_output, dmc_output; - - pulse_output = pulse[0].clock(); - pulse_output += pulse[1].clock(); - triangle_output = triangle.clock(); - noise_output = noise.clock(); - dmc_output = dmc.clock(); - - clockFrameCounterDivider(); - - int output = 0; - output += pulseDAC[pulse_output]; - output += dmcTriangleNoiseDAC[dmc_output][triangle_output][noise_output]; - output += cartridgeSample; - stream->sample(sclamp<16>(output) / 32768.0); - - tick(); -} - -auto APU::tick() -> void { - Thread::step(rate()); - synchronize(cpu); -} - -auto APU::setIRQ() -> void { - cpu.apuLine(frame.irqPending || dmc.irqPending); -} - -auto APU::setSample(int16 sample) -> void { - cartridgeSample = sample; -} - -auto APU::power(bool reset) -> void { - create(APU::Enter, system.frequency()); - stream = Emulator::audio.createStream(1, frequency() / rate()); - stream->addHighPassFilter( 90.0, Emulator::Filter::Order::First); - stream->addHighPassFilter( 440.0, Emulator::Filter::Order::First); - stream->addLowPassFilter (14000.0, Emulator::Filter::Order::First); - stream->addDCRemovalFilter(); - - pulse[0].power(); - pulse[1].power(); - triangle.power(); - noise.power(); - dmc.power(); - - frame.irqPending = 0; - - frame.mode = 0; - frame.counter = 0; - frame.divider = 1; - - enabledChannels = 0; - cartridgeSample = 0; - - setIRQ(); -} - -auto APU::readIO(uint16 addr) -> uint8 { - switch(addr) { - - case 0x4015: { - uint8 result = 0x00; - result |= pulse[0].lengthCounter ? 0x01 : 0; - result |= pulse[1].lengthCounter ? 0x02 : 0; - result |= triangle.lengthCounter ? 0x04 : 0; - result |= noise.lengthCounter ? 0x08 : 0; - result |= dmc.lengthCounter ? 0x10 : 0; - result |= frame.irqPending ? 0x40 : 0; - result |= dmc.irqPending ? 0x80 : 0; - - frame.irqPending = false; - setIRQ(); - - return result; - } - - } - - return cpu.mdr(); -} - -auto APU::writeIO(uint16 addr, uint8 data) -> void { - const uint n = (addr >> 2) & 1; //pulse# - - switch(addr) { - - case 0x4000: case 0x4004: { - pulse[n].duty = data >> 6; - pulse[n].envelope.loopMode = data & 0x20; - pulse[n].envelope.useSpeedAsVolume = data & 0x10; - pulse[n].envelope.speed = data & 0x0f; - return; - } - - case 0x4001: case 0x4005: { - pulse[n].sweep.enable = data & 0x80; - pulse[n].sweep.period = (data & 0x70) >> 4; - pulse[n].sweep.decrement = data & 0x08; - pulse[n].sweep.shift = data & 0x07; - pulse[n].sweep.reload = true; - return; - } - - case 0x4002: case 0x4006: { - pulse[n].period = (pulse[n].period & 0x0700) | (data << 0); - pulse[n].sweep.pulsePeriod = (pulse[n].sweep.pulsePeriod & 0x0700) | (data << 0); - return; - } - - case 0x4003: case 0x4007: { - pulse[n].period = (pulse[n].period & 0x00ff) | (data << 8); - pulse[n].sweep.pulsePeriod = (pulse[n].sweep.pulsePeriod & 0x00ff) | (data << 8); - - pulse[n].dutyCounter = 0; - pulse[n].envelope.reloadDecay = true; - - if(enabledChannels & (1 << n)) { - pulse[n].lengthCounter = lengthCounterTable[(data >> 3) & 0x1f]; - } - return; - } - - case 0x4008: { - triangle.haltLengthCounter = data & 0x80; - triangle.linearLength = data & 0x7f; - return; - } - - case 0x400a: { - triangle.period = (triangle.period & 0x0700) | (data << 0); - return; - } - - case 0x400b: { - triangle.period = (triangle.period & 0x00ff) | (data << 8); - - triangle.reloadLinear = true; - - if(enabledChannels & (1 << 2)) { - triangle.lengthCounter = lengthCounterTable[(data >> 3) & 0x1f]; - } - return; - } - - case 0x400c: { - noise.envelope.loopMode = data & 0x20; - noise.envelope.useSpeedAsVolume = data & 0x10; - noise.envelope.speed = data & 0x0f; - return; - } - - case 0x400e: { - noise.shortMode = data & 0x80; - noise.period = data & 0x0f; - return; - } - - case 0x400f: { - noise.envelope.reloadDecay = true; - - if(enabledChannels & (1 << 3)) { - noise.lengthCounter = lengthCounterTable[(data >> 3) & 0x1f]; - } - return; - } - - case 0x4010: { - dmc.irqEnable = data & 0x80; - dmc.loopMode = data & 0x40; - dmc.period = data & 0x0f; - - dmc.irqPending = dmc.irqPending && dmc.irqEnable && !dmc.loopMode; - setIRQ(); - return; - } - - case 0x4011: { - dmc.dacLatch = data & 0x7f; - return; - } - - case 0x4012: { - dmc.addrLatch = data; - return; - } - - case 0x4013: { - dmc.lengthLatch = data; - return; - } - - case 0x4015: { - if((data & 0x01) == 0) pulse[0].lengthCounter = 0; - if((data & 0x02) == 0) pulse[1].lengthCounter = 0; - if((data & 0x04) == 0) triangle.lengthCounter = 0; - if((data & 0x08) == 0) noise.lengthCounter = 0; - - (data & 0x10) ? dmc.start() : dmc.stop(); - dmc.irqPending = false; - - setIRQ(); - enabledChannels = data & 0x1f; - return; - } - - case 0x4017: { - frame.mode = data >> 6; - - frame.counter = 0; - if(frame.mode & 2) clockFrameCounter(); - if(frame.mode & 1) { - frame.irqPending = false; - setIRQ(); - } - frame.divider = FrameCounter::NtscPeriod; - return; - } - - } -} - -auto APU::clockFrameCounter() -> void { - frame.counter++; - - if(frame.counter & 1) { - pulse[0].clockLength(); - pulse[0].sweep.clock(0); - pulse[1].clockLength(); - pulse[1].sweep.clock(1); - triangle.clockLength(); - noise.clockLength(); - } - - pulse[0].envelope.clock(); - pulse[1].envelope.clock(); - triangle.clockLinearLength(); - noise.envelope.clock(); - - if(frame.counter == 0) { - if(frame.mode & 2) frame.divider += FrameCounter::NtscPeriod; - if(frame.mode == 0) { - frame.irqPending = true; - setIRQ(); - } - } -} - -auto APU::clockFrameCounterDivider() -> void { - frame.divider -= 2; - if(frame.divider <= 0) { - clockFrameCounter(); - frame.divider += FrameCounter::NtscPeriod; - } -} - -const uint8 APU::lengthCounterTable[32] = { - 0x0a, 0xfe, 0x14, 0x02, 0x28, 0x04, 0x50, 0x06, 0xa0, 0x08, 0x3c, 0x0a, 0x0e, 0x0c, 0x1a, 0x0e, - 0x0c, 0x10, 0x18, 0x12, 0x30, 0x14, 0x60, 0x16, 0xc0, 0x18, 0x48, 0x1a, 0x10, 0x1c, 0x20, 0x1e, -}; - -const uint16 APU::noisePeriodTableNTSC[16] = { - 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068, -}; - -const uint16 APU::noisePeriodTablePAL[16] = { - 4, 8, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778, -}; - -const uint16 APU::dmcPeriodTableNTSC[16] = { - 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 84, 72, 54, -}; - -const uint16 APU::dmcPeriodTablePAL[16] = { - 398, 354, 316, 298, 276, 236, 210, 198, 176, 148, 132, 118, 98, 78, 66, 50, -}; - -} diff --git a/higan/fc/apu/apu.hpp b/higan/fc/apu/apu.hpp deleted file mode 100644 index c55d9769..00000000 --- a/higan/fc/apu/apu.hpp +++ /dev/null @@ -1,182 +0,0 @@ -struct APU : Thread { - shared_pointer stream; - - inline auto rate() const -> uint { return Region::PAL() ? 16 : 12; } - - //apu.cpp - APU(); - - static auto Enter() -> void; - auto main() -> void; - auto tick() -> void; - auto setIRQ() -> void; - auto setSample(int16 sample) -> void; - - auto power(bool reset) -> void; - - auto readIO(uint16 addr) -> uint8; - auto writeIO(uint16 addr, uint8 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - struct Envelope { - auto volume() const -> uint; - auto clock() -> void; - - auto power() -> void; - - auto serialize(serializer&) -> void; - - uint4 speed; - bool useSpeedAsVolume; - bool loopMode; - - bool reloadDecay; - uint8 decayCounter; - uint4 decayVolume; - }; - - struct Sweep { - auto checkPeriod() -> bool; - auto clock(uint channel) -> void; - - auto power() -> void; - - auto serialize(serializer&) -> void; - - uint8 shift; - bool decrement; - uint3 period; - uint8 counter; - bool enable; - bool reload; - uint11 pulsePeriod; - }; - - struct Pulse { - auto clockLength() -> void; - auto checkPeriod() -> bool; - auto clock() -> uint8; - - auto power() -> void; - - auto serialize(serializer&) -> void; - - uint lengthCounter; - - Envelope envelope; - Sweep sweep; - - uint2 duty; - uint3 dutyCounter; - - uint11 period; - uint periodCounter; - } pulse[2]; - - struct Triangle { - auto clockLength() -> void; - auto clockLinearLength() -> void; - auto clock() -> uint8; - - auto power() -> void; - - auto serialize(serializer&) -> void; - - uint lengthCounter; - - uint8 linearLength; - bool haltLengthCounter; - - uint11 period; - uint periodCounter; - - uint5 stepCounter; - uint8 linearLengthCounter; - bool reloadLinear; - } triangle; - - struct Noise { - auto clockLength() -> void; - auto clock() -> uint8; - - auto power() -> void; - - auto serialize(serializer&) -> void; - - uint lengthCounter; - - Envelope envelope; - - uint4 period; - uint periodCounter; - - bool shortMode; - uint15 lfsr; - } noise; - - struct DMC { - auto start() -> void; - auto stop() -> void; - auto clock() -> uint8; - - auto power() -> void; - - auto serialize(serializer&) -> void; - - uint lengthCounter; - bool irqPending; - - uint4 period; - uint periodCounter; - - bool irqEnable; - bool loopMode; - - uint8 dacLatch; - uint8 addrLatch; - uint8 lengthLatch; - - uint15 readAddr; - uint dmaDelayCounter; - - uint3 bitCounter; - bool dmaBufferValid; - uint8 dmaBuffer; - - bool sampleValid; - uint8 sample; - } dmc; - - struct FrameCounter { - auto serialize(serializer&) -> void; - - enum : uint { NtscPeriod = 14915 }; //~(21.477MHz / 6 / 240hz) - - bool irqPending; - - uint2 mode; - uint2 counter; - int divider; - }; - - auto clockFrameCounter() -> void; - auto clockFrameCounterDivider() -> void; - - FrameCounter frame; - - uint8 enabledChannels; - int16 cartridgeSample; - - int16 pulseDAC[32]; - int16 dmcTriangleNoiseDAC[128][16][16]; - - static const uint8 lengthCounterTable[32]; - static const uint16 dmcPeriodTableNTSC[16]; - static const uint16 dmcPeriodTablePAL[16]; - static const uint16 noisePeriodTableNTSC[16]; - static const uint16 noisePeriodTablePAL[16]; -}; - -extern APU apu; diff --git a/higan/fc/apu/dmc.cpp b/higan/fc/apu/dmc.cpp deleted file mode 100644 index b007f346..00000000 --- a/higan/fc/apu/dmc.cpp +++ /dev/null @@ -1,89 +0,0 @@ -auto APU::DMC::start() -> void { - if(lengthCounter == 0) { - readAddr = 0x4000 + (addrLatch << 6); - lengthCounter = (lengthLatch << 4) + 1; - } -} - -auto APU::DMC::stop() -> void { - lengthCounter = 0; - dmaDelayCounter = 0; - cpu.rdyLine(1); - cpu.rdyAddr(false); -} - -auto APU::DMC::clock() -> uint8 { - uint8 result = dacLatch; - - if(dmaDelayCounter > 0) { - dmaDelayCounter--; - - if(dmaDelayCounter == 1) { - cpu.rdyAddr(true, 0x8000 | readAddr); - } else if(dmaDelayCounter == 0) { - cpu.rdyLine(1); - cpu.rdyAddr(false); - - dmaBuffer = cpu.mdr(); - dmaBufferValid = true; - lengthCounter--; - readAddr++; - - if(lengthCounter == 0) { - if(loopMode) { - start(); - } else if(irqEnable) { - irqPending = true; - apu.setIRQ(); - } - } - } - } - - if(--periodCounter == 0) { - if(sampleValid) { - int delta = (((sample >> bitCounter) & 1) << 2) - 2; - uint data = dacLatch + delta; - if((data & 0x80) == 0) dacLatch = data; - } - - if(++bitCounter == 0) { - if(dmaBufferValid) { - sampleValid = true; - sample = dmaBuffer; - dmaBufferValid = false; - } else { - sampleValid = false; - } - } - - periodCounter = Region::PAL() ? dmcPeriodTablePAL[period] : dmcPeriodTableNTSC[period]; - } - - if(lengthCounter > 0 && !dmaBufferValid && dmaDelayCounter == 0) { - cpu.rdyLine(0); - dmaDelayCounter = 4; - } - - return result; -} - -auto APU::DMC::power() -> void { - lengthCounter = 0; - irqPending = 0; - - period = 0; - periodCounter = Region::PAL() ? dmcPeriodTablePAL[0] : dmcPeriodTableNTSC[0]; - irqEnable = 0; - loopMode = 0; - dacLatch = 0; - addrLatch = 0; - lengthLatch = 0; - readAddr = 0; - dmaDelayCounter = 0; - bitCounter = 0; - dmaBufferValid = 0; - dmaBuffer = 0; - sampleValid = 0; - sample = 0; -} diff --git a/higan/fc/apu/envelope.cpp b/higan/fc/apu/envelope.cpp deleted file mode 100644 index d70cf511..00000000 --- a/higan/fc/apu/envelope.cpp +++ /dev/null @@ -1,26 +0,0 @@ -auto APU::Envelope::volume() const -> uint { - return useSpeedAsVolume ? speed : decayVolume; -} - -auto APU::Envelope::clock() -> void { - if(reloadDecay) { - reloadDecay = false; - decayVolume = 0x0f; - decayCounter = speed + 1; - return; - } - - if(--decayCounter == 0) { - decayCounter = speed + 1; - if(decayVolume || loopMode) decayVolume--; - } -} - -auto APU::Envelope::power() -> void { - speed = 0; - useSpeedAsVolume = 0; - loopMode = 0; - reloadDecay = 0; - decayCounter = 0; - decayVolume = 0; -} diff --git a/higan/fc/apu/noise.cpp b/higan/fc/apu/noise.cpp deleted file mode 100644 index 356280b2..00000000 --- a/higan/fc/apu/noise.cpp +++ /dev/null @@ -1,42 +0,0 @@ -auto APU::Noise::clockLength() -> void { - if(envelope.loopMode == 0) { - if(lengthCounter > 0) lengthCounter--; - } -} - -auto APU::Noise::clock() -> uint8 { - if(lengthCounter == 0) return 0; - - uint8 result = (lfsr & 1) ? envelope.volume() : 0; - - if(--periodCounter == 0) { - uint feedback; - - if(shortMode) { - feedback = ((lfsr >> 0) & 1) ^ ((lfsr >> 6) & 1); - } else { - feedback = ((lfsr >> 0) & 1) ^ ((lfsr >> 1) & 1); - } - - lfsr = (lfsr >> 1) | (feedback << 14); - periodCounter = Region::PAL() ? apu.noisePeriodTablePAL[period] : apu.noisePeriodTableNTSC[period]; - } - - return result; -} - -auto APU::Noise::power() -> void { - lengthCounter = 0; - - envelope.speed = 0; - envelope.useSpeedAsVolume = 0; - envelope.loopMode = 0; - envelope.reloadDecay = 0; - envelope.decayCounter = 0; - envelope.decayVolume = 0; - - period = 0; - periodCounter = 1; - shortMode = 0; - lfsr = 1; -} diff --git a/higan/fc/apu/pulse.cpp b/higan/fc/apu/pulse.cpp deleted file mode 100644 index 66b02d48..00000000 --- a/higan/fc/apu/pulse.cpp +++ /dev/null @@ -1,38 +0,0 @@ -auto APU::Pulse::clockLength() -> void { - if(envelope.loopMode == 0) { - if(lengthCounter) lengthCounter--; - } -} - -auto APU::Pulse::clock() -> uint8 { - if(!sweep.checkPeriod()) return 0; - if(lengthCounter == 0) return 0; - - static const uint dutyTable[4][8] = { - {0, 0, 0, 0, 0, 0, 0, 1}, //12.5% - {0, 0, 0, 0, 0, 0, 1, 1}, //25.0% - {0, 0, 0, 0, 1, 1, 1, 1}, //50.0% - {1, 1, 1, 1, 1, 1, 0, 0}, //25.0% (negated) - }; - uint8 result = dutyTable[duty][dutyCounter] ? envelope.volume() : 0; - if(sweep.pulsePeriod < 0x008) result = 0; - - if(--periodCounter == 0) { - periodCounter = (sweep.pulsePeriod + 1) * 2; - dutyCounter--; - } - - return result; -} - -auto APU::Pulse::power() -> void { - envelope.power(); - sweep.power(); - - lengthCounter = 0; - - duty = 0; - dutyCounter = 0; - period = 0; - periodCounter = 1; -} diff --git a/higan/fc/apu/serialization.cpp b/higan/fc/apu/serialization.cpp deleted file mode 100644 index 48b80b58..00000000 --- a/higan/fc/apu/serialization.cpp +++ /dev/null @@ -1,104 +0,0 @@ -auto APU::serialize(serializer& s) -> void { - Thread::serialize(s); - - pulse[0].serialize(s); - pulse[1].serialize(s); - triangle.serialize(s); - dmc.serialize(s); - frame.serialize(s); - - s.integer(enabledChannels); - s.integer(cartridgeSample); -} - -auto APU::Envelope::serialize(serializer& s) -> void { - s.integer(speed); - s.integer(useSpeedAsVolume); - s.integer(loopMode); - - s.integer(reloadDecay); - s.integer(decayCounter); - s.integer(decayVolume); -} - -auto APU::Sweep::serialize(serializer& s) -> void { - s.integer(shift); - s.integer(decrement); - s.integer(period); - s.integer(counter); - s.integer(enable); - s.integer(reload); - s.integer(pulsePeriod); -} - -auto APU::Pulse::serialize(serializer& s) -> void { - s.integer(lengthCounter); - - envelope.serialize(s); - sweep.serialize(s); - - s.integer(duty); - s.integer(dutyCounter); - - s.integer(period); - s.integer(periodCounter); -} - -auto APU::Triangle::serialize(serializer& s) -> void { - s.integer(lengthCounter); - - s.integer(linearLength); - s.integer(haltLengthCounter); - - s.integer(period); - s.integer(periodCounter); - - s.integer(stepCounter); - s.integer(linearLengthCounter); - s.integer(reloadLinear); -} - -auto APU::Noise::serialize(serializer& s) -> void { - s.integer(lengthCounter); - - envelope.serialize(s); - - s.integer(period); - s.integer(periodCounter); - - s.integer(shortMode); - s.integer(lfsr); -} - -auto APU::DMC::serialize(serializer& s) -> void { - s.integer(lengthCounter); - s.integer(irqPending); - - s.integer(period); - s.integer(periodCounter); - - s.integer(irqEnable); - s.integer(loopMode); - - s.integer(dacLatch); - s.integer(addrLatch); - s.integer(lengthLatch); - - s.integer(readAddr); - s.integer(dmaDelayCounter); - - s.integer(bitCounter); - s.integer(dmaBufferValid); - s.integer(dmaBuffer); - - s.integer(sampleValid); - s.integer(sample); -} - -auto APU::FrameCounter::serialize(serializer& s) -> void { - s.integer(irqPending); - - s.integer(mode); - s.integer(counter); - s.integer(divider); -} diff --git a/higan/fc/apu/sweep.cpp b/higan/fc/apu/sweep.cpp deleted file mode 100644 index 6a25b688..00000000 --- a/higan/fc/apu/sweep.cpp +++ /dev/null @@ -1,40 +0,0 @@ -auto APU::Sweep::checkPeriod() -> bool { - if(pulsePeriod > 0x7ff) return false; - - if(decrement == 0) { - if((pulsePeriod + (pulsePeriod >> shift)) & 0x800) return false; - } - - return true; -} - -auto APU::Sweep::clock(uint channel) -> void { - if(--counter == 0) { - counter = period + 1; - if(enable && shift && pulsePeriod > 8) { - int delta = pulsePeriod >> shift; - - if(decrement) { - pulsePeriod -= delta; - if(channel == 0) pulsePeriod--; - } else if((pulsePeriod + delta) < 0x800) { - pulsePeriod += delta; - } - } - } - - if(reload) { - reload = false; - counter = period + 1; - } -} - -auto APU::Sweep::power() -> void { - shift = 0; - decrement = 0; - period = 0; - counter = 1; - enable = 0; - reload = 0; - pulsePeriod = 0; -} diff --git a/higan/fc/apu/triangle.cpp b/higan/fc/apu/triangle.cpp deleted file mode 100644 index 82d1a284..00000000 --- a/higan/fc/apu/triangle.cpp +++ /dev/null @@ -1,40 +0,0 @@ -auto APU::Triangle::clockLength() -> void { - if(haltLengthCounter == 0) { - if(lengthCounter > 0) lengthCounter--; - } -} - -auto APU::Triangle::clockLinearLength() -> void { - if(reloadLinear) { - linearLengthCounter = linearLength; - } else if(linearLengthCounter) { - linearLengthCounter--; - } - - if(haltLengthCounter == 0) reloadLinear = false; -} - -auto APU::Triangle::clock() -> uint8 { - uint8 result = stepCounter & 0x0f; - if((stepCounter & 0x10) == 0) result ^= 0x0f; - if(lengthCounter == 0 || linearLengthCounter == 0) return result; - - if(--periodCounter == 0) { - stepCounter++; - periodCounter = period + 1; - } - - return result; -} - -auto APU::Triangle::power() -> void { - lengthCounter = 0; - - linearLength = 0; - haltLengthCounter = 0; - period = 0; - periodCounter = 1; - stepCounter = 0; - linearLengthCounter = 0; - reloadLinear = 0; -} diff --git a/higan/fc/cartridge/board/bandai-fcg.cpp b/higan/fc/cartridge/board/bandai-fcg.cpp deleted file mode 100644 index f1ceeab1..00000000 --- a/higan/fc/cartridge/board/bandai-fcg.cpp +++ /dev/null @@ -1,110 +0,0 @@ -//BANDAI-FCG - -struct BandaiFCG : Board { - BandaiFCG(Markup::Node& document) : Board(document) { - } - - auto main() -> void { - if(irqCounterEnable) { - if(--irqCounter == 0xffff) { - cpu.irqLine(1); - irqCounterEnable = false; - } - } - - tick(); - } - - auto addrCIRAM(uint addr) const -> uint { - switch(mirror) { - case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); - case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); - case 2: return 0x0000 | (addr & 0x03ff); - case 3: return 0x0400 | (addr & 0x03ff); - } - unreachable; - } - - auto readPRG(uint addr) -> uint8 { - if(addr & 0x8000) { - bool region = addr & 0x4000; - uint bank = (region == 0 ? prgBank : (uint8)0x0f); - return prgrom.read((bank << 14) | (addr & 0x3fff)); - } - return cpu.mdr(); - } - - auto writePRG(uint addr, uint8 data) -> void { - if(addr >= 0x6000) { - switch(addr & 15) { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x04: case 0x05: case 0x06: case 0x07: - chrBank[addr & 7] = data; - break; - case 0x08: - prgBank = data & 0x0f; - break; - case 0x09: - mirror = data & 0x03; - break; - case 0x0a: - cpu.irqLine(0); - irqCounterEnable = data & 0x01; - irqCounter = irqLatch; - break; - case 0x0b: - irqLatch = (irqLatch & 0xff00) | (data << 0); - break; - case 0x0c: - irqLatch = (irqLatch & 0x00ff) | (data << 8); - break; - case 0x0d: - //todo: serial EEPROM support - break; - } - } - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) return ppu.readCIRAM(addrCIRAM(addr)); - addr = (chrBank[addr >> 10] << 10) | (addr & 0x03ff); - return Board::readCHR(addr); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) return ppu.writeCIRAM(addrCIRAM(addr), data); - addr = (chrBank[addr >> 10] << 10) | (addr & 0x03ff); - return Board::writeCHR(addr, data); - } - - auto power() -> void { - reset(); - } - - auto reset() -> void { - for(auto& n : chrBank) n = 0; - prgBank = 0; - mirror = 0; - irqCounterEnable = 0; - irqCounter = 0; - irqLatch = 0; - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - - s.array(chrBank); - s.integer(prgBank); - s.integer(mirror); - s.integer(irqCounterEnable); - s.integer(irqCounter); - s.integer(irqLatch); - } - - uint8 chrBank[8]; - uint8 prgBank; - uint2 mirror; - bool irqCounterEnable; - uint16 irqCounter; - uint16 irqLatch; -}; diff --git a/higan/fc/cartridge/board/board.cpp b/higan/fc/cartridge/board/board.cpp deleted file mode 100644 index 9c1a0a23..00000000 --- a/higan/fc/cartridge/board/board.cpp +++ /dev/null @@ -1,223 +0,0 @@ -#include "bandai-fcg.cpp" -#include "konami-vrc1.cpp" -#include "konami-vrc2.cpp" -#include "konami-vrc3.cpp" -#include "konami-vrc4.cpp" -#include "konami-vrc6.cpp" -#include "konami-vrc7.cpp" -#include "nes-axrom.cpp" -#include "nes-bnrom.cpp" -#include "nes-cnrom.cpp" -#include "nes-exrom.cpp" -#include "nes-fxrom.cpp" -#include "nes-gxrom.cpp" -#include "nes-hkrom.cpp" -#include "nes-nrom.cpp" -#include "nes-pxrom.cpp" -#include "nes-sxrom.cpp" -#include "nes-txrom.cpp" -#include "nes-uxrom.cpp" -#include "sunsoft-5b.cpp" - -Board::Board(Markup::Node& document) { - cartridge.board = this; - information.type = document["game/board"].text(); - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=ROM,content=Program)"]}) { - if(prgrom.size = memory.size) prgrom.data = new uint8_t[prgrom.size](); - if(auto fp = platform->open(cartridge.pathID(), memory.name(), File::Read, File::Required)) { - fp->read(prgrom.data, min(prgrom.size, fp->size())); - } - } - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=RAM,content=Save)"]}) { - if(prgram.size = memory.size) prgram.data = new uint8_t[prgram.size](), prgram.writable = true; - if(memory.nonVolatile) { - if(auto fp = platform->open(cartridge.pathID(), memory.name(), File::Read)) { - fp->read(prgram.data, min(prgram.size, fp->size())); - } - } - } - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=ROM,content=Character)"]}) { - if(chrrom.size = memory.size) chrrom.data = new uint8_t[chrrom.size](); - if(auto fp = platform->open(cartridge.pathID(), memory.name(), File::Read, File::Required)) { - fp->read(chrrom.data, min(chrrom.size, fp->size())); - } - } - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=RAM,content=Character)"]}) { - if(chrram.size = memory.size) chrram.data = new uint8_t[chrram.size](), chrram.writable = true; - if(memory.nonVolatile) { - if(auto fp = platform->open(cartridge.pathID(), memory.name(), File::Read)) { - fp->read(chrram.data, min(chrram.size, fp->size())); - } - } - } -} - -auto Board::save() -> void { - auto document = BML::unserialize(cartridge.manifest()); - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=RAM,content=Save)"]}) { - if(memory.nonVolatile) { - if(auto fp = platform->open(cartridge.pathID(), memory.name(), File::Write)) { - fp->write(prgram.data, prgram.size); - } - } - } - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=RAM,content=Character)"]}) { - if(memory.nonVolatile) { - if(auto fp = platform->open(cartridge.pathID(), memory.name(), File::Write)) { - fp->write(chrram.data, chrram.size); - } - } - } -} - -auto Board::Memory::read(uint addr) const -> uint8 { - return data[mirror(addr, size)]; -} - -auto Board::Memory::write(uint addr, uint8 byte) -> void { - if(writable) data[mirror(addr, size)] = byte; -} - -auto Board::mirror(uint addr, uint size) -> uint { - uint base = 0; - if(size) { - uint mask = 1 << 23; - while(addr >= size) { - while(!(addr & mask)) mask >>= 1; - addr -= mask; - if(size > mask) { - size -= mask; - base += mask; - } - mask >>= 1; - } - base += addr; - } - return base; -} - -auto Board::main() -> void { - cartridge.step(cartridge.rate() * 4095); - tick(); -} - -auto Board::tick() -> void { - cartridge.step(cartridge.rate()); - cartridge.synchronize(cpu); -} - -auto Board::readCHR(uint addr) -> uint8 { - if(chrram.size) return chrram.data[mirror(addr, chrram.size)]; - if(chrrom.size) return chrrom.data[mirror(addr, chrrom.size)]; - return 0u; -} - -auto Board::writeCHR(uint addr, uint8 data) -> void { - if(chrram.size) chrram.data[mirror(addr, chrram.size)] = data; -} - -auto Board::power() -> void { -} - -auto Board::serialize(serializer& s) -> void { - if(prgram.size) s.array(prgram.data, prgram.size); - if(chrram.size) s.array(chrram.data, chrram.size); -} - -auto Board::load(string manifest) -> Board* { - auto document = BML::unserialize(manifest); - cartridge.information.title = document["game/label"].text(); - - string type = document["game/board"].text(); - - if(type == "BANDAI-FCG" ) return new BandaiFCG(document); - - if(type == "KONAMI-VRC-1") return new KonamiVRC1(document); - if(type == "KONAMI-VRC-2") return new KonamiVRC2(document); - if(type == "KONAMI-VRC-3") return new KonamiVRC3(document); - if(type == "KONAMI-VRC-4") return new KonamiVRC4(document); - if(type == "KONAMI-VRC-6") return new KonamiVRC6(document); - if(type == "KONAMI-VRC-7") return new KonamiVRC7(document); - - if(type == "NES-AMROM" ) return new NES_AxROM(document); - if(type == "NES-ANROM" ) return new NES_AxROM(document); - if(type == "NES-AN1ROM" ) return new NES_AxROM(document); - if(type == "NES-AOROM" ) return new NES_AxROM(document); - - if(type == "NES-BNROM" ) return new NES_BNROM(document); - - if(type == "NES-CNROM" ) return new NES_CNROM(document); - - if(type == "NES-EKROM" ) return new NES_ExROM(document); - if(type == "NES-ELROM" ) return new NES_ExROM(document); - if(type == "NES-ETROM" ) return new NES_ExROM(document); - if(type == "NES-EWROM" ) return new NES_ExROM(document); - - if(type == "NES-FJROM" ) return new NES_FxROM(document); - if(type == "NES-FKROM" ) return new NES_FxROM(document); - - if(type == "NES-GNROM" ) return new NES_GxROM(document); - if(type == "NES-MHROM" ) return new NES_GxROM(document); - - if(type == "NES-HKROM" ) return new NES_HKROM(document); - - if(type == "NES-NROM" ) return new NES_NROM(document); - if(type == "NES-NROM-128") return new NES_NROM(document); - if(type == "NES-NROM-256") return new NES_NROM(document); - - if(type == "NES-PEEOROM" ) return new NES_PxROM(document); - if(type == "NES-PNROM" ) return new NES_PxROM(document); - - if(type == "NES-SAROM" ) return new NES_SxROM(document); - if(type == "NES-SBROM" ) return new NES_SxROM(document); - if(type == "NES-SCROM" ) return new NES_SxROM(document); - if(type == "NES-SC1ROM" ) return new NES_SxROM(document); - if(type == "NES-SEROM" ) return new NES_SxROM(document); - if(type == "NES-SFROM" ) return new NES_SxROM(document); - if(type == "NES-SFEXPROM") return new NES_SxROM(document); - if(type == "NES-SGROM" ) return new NES_SxROM(document); - if(type == "NES-SHROM" ) return new NES_SxROM(document); - if(type == "NES-SH1ROM" ) return new NES_SxROM(document); - if(type == "NES-SIROM" ) return new NES_SxROM(document); - if(type == "NES-SJROM" ) return new NES_SxROM(document); - if(type == "NES-SKROM" ) return new NES_SxROM(document); - if(type == "NES-SLROM" ) return new NES_SxROM(document); - if(type == "NES-SL1ROM" ) return new NES_SxROM(document); - if(type == "NES-SL2ROM" ) return new NES_SxROM(document); - if(type == "NES-SL3ROM" ) return new NES_SxROM(document); - if(type == "NES-SLRROM" ) return new NES_SxROM(document); - if(type == "NES-SMROM" ) return new NES_SxROM(document); - if(type == "NES-SNROM" ) return new NES_SxROM(document); - if(type == "NES-SOROM" ) return new NES_SxROM(document); - if(type == "NES-SUROM" ) return new NES_SxROM(document); - if(type == "NES-SXROM" ) return new NES_SxROM(document); - - if(type == "NES-TBROM" ) return new NES_TxROM(document); - if(type == "NES-TEROM" ) return new NES_TxROM(document); - if(type == "NES-TFROM" ) return new NES_TxROM(document); - if(type == "NES-TGROM" ) return new NES_TxROM(document); - if(type == "NES-TKROM" ) return new NES_TxROM(document); - if(type == "NES-TKSROM" ) return new NES_TxROM(document); - if(type == "NES-TLROM" ) return new NES_TxROM(document); - if(type == "NES-TL1ROM" ) return new NES_TxROM(document); - if(type == "NES-TL2ROM" ) return new NES_TxROM(document); - if(type == "NES-TLSROM" ) return new NES_TxROM(document); - if(type == "NES-TNROM" ) return new NES_TxROM(document); - if(type == "NES-TQROM" ) return new NES_TxROM(document); - if(type == "NES-TR1ROM" ) return new NES_TxROM(document); - if(type == "NES-TSROM" ) return new NES_TxROM(document); - if(type == "NES-TVROM" ) return new NES_TxROM(document); - - if(type == "NES-UNROM" ) return new NES_UxROM(document); - if(type == "NES-UOROM" ) return new NES_UxROM(document); - - if(type == "SUNSOFT-5B" ) return new Sunsoft5B(document); - - return nullptr; -} diff --git a/higan/fc/cartridge/board/board.hpp b/higan/fc/cartridge/board/board.hpp deleted file mode 100644 index 169f3305..00000000 --- a/higan/fc/cartridge/board/board.hpp +++ /dev/null @@ -1,48 +0,0 @@ -struct Board { - struct Memory { - inline Memory(uint8_t* data, uint size) : data(data), size(size) {} - inline Memory() : data(nullptr), size(0u), writable(false) {} - inline ~Memory() { if(data) delete[] data; } - - inline auto read(uint addr) const -> uint8; - inline auto write(uint addr, uint8 data) -> void; - - string name; - uint8_t* data = nullptr; - uint size = 0; - bool writable = false; - }; - - virtual ~Board() = default; - - static auto mirror(uint addr, uint size) -> uint; - - Board(Markup::Node& document); - auto save() -> void; - - virtual auto main() -> void; - virtual auto tick() -> void; - - virtual auto readPRG(uint addr) -> uint8 = 0; - virtual auto writePRG(uint addr, uint8 data) -> void = 0; - - virtual auto readCHR(uint addr) -> uint8; - virtual auto writeCHR(uint addr, uint8 data) -> void; - - virtual inline auto scanline(uint y) -> void {} - - virtual auto power() -> void; - - virtual auto serialize(serializer&) -> void; - - static auto load(string manifest) -> Board*; - - struct Information { - string type; - } information; - - Memory prgrom; - Memory prgram; - Memory chrrom; - Memory chrram; -}; diff --git a/higan/fc/cartridge/board/konami-vrc1.cpp b/higan/fc/cartridge/board/konami-vrc1.cpp deleted file mode 100644 index 974184e3..00000000 --- a/higan/fc/cartridge/board/konami-vrc1.cpp +++ /dev/null @@ -1,34 +0,0 @@ -struct KonamiVRC1 : Board { - KonamiVRC1(Markup::Node& document) : Board(document), vrc1(*this) { - } - - auto readPRG(uint addr) -> uint8 { - if(addr & 0x8000) return prgrom.read(vrc1.addrPRG(addr)); - return cpu.mdr(); - } - - auto writePRG(uint addr, uint8 data) -> void { - if(addr & 0x8000) return vrc1.writeIO(addr, data); - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) return ppu.readCIRAM(vrc1.addrCIRAM(addr)); - return Board::readCHR(vrc1.addrCHR(addr)); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) return ppu.writeCIRAM(vrc1.addrCIRAM(addr), data); - return Board::writeCHR(vrc1.addrCHR(addr), data); - } - - auto power() -> void { - vrc1.power(); - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - vrc1.serialize(s); - } - - VRC1 vrc1; -}; diff --git a/higan/fc/cartridge/board/konami-vrc2.cpp b/higan/fc/cartridge/board/konami-vrc2.cpp deleted file mode 100644 index e5d7f874..00000000 --- a/higan/fc/cartridge/board/konami-vrc2.cpp +++ /dev/null @@ -1,51 +0,0 @@ -struct KonamiVRC2 : Board { - KonamiVRC2(Markup::Node& document) : Board(document), vrc2(*this) { - settings.pinout.a0 = 1 << document["board/chip/pinout/a0"].natural(); - settings.pinout.a1 = 1 << document["board/chip/pinout/a1"].natural(); - } - - auto readPRG(uint addr) -> uint8 { - if(addr < 0x6000) return cpu.mdr(); - if(addr < 0x8000) return vrc2.readRAM(addr); - return prgrom.read(vrc2.addrPRG(addr)); - } - - auto writePRG(uint addr, uint8 data) -> void { - if(addr < 0x6000) return; - if(addr < 0x8000) return vrc2.writeRAM(addr, data); - - bool a0 = (addr & settings.pinout.a0); - bool a1 = (addr & settings.pinout.a1); - addr &= 0xfff0; - addr |= (a0 << 0) | (a1 << 1); - return vrc2.writeIO(addr, data); - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) return ppu.readCIRAM(vrc2.addrCIRAM(addr)); - return Board::readCHR(vrc2.addrCHR(addr)); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) return ppu.writeCIRAM(vrc2.addrCIRAM(addr), data); - return Board::writeCHR(vrc2.addrCHR(addr), data); - } - - auto power() -> void { - vrc2.power(); - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - vrc2.serialize(s); - } - - struct Settings { - struct Pinout { - uint a0; - uint a1; - } pinout; - } settings; - - VRC2 vrc2; -}; diff --git a/higan/fc/cartridge/board/konami-vrc3.cpp b/higan/fc/cartridge/board/konami-vrc3.cpp deleted file mode 100644 index a16f9266..00000000 --- a/higan/fc/cartridge/board/konami-vrc3.cpp +++ /dev/null @@ -1,51 +0,0 @@ -struct KonamiVRC3 : Board { - KonamiVRC3(Markup::Node& document) : Board(document), vrc3(*this) { - settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0; - } - - auto main() -> void { - vrc3.main(); - } - - auto readPRG(uint addr) -> uint8 { - if((addr & 0xe000) == 0x6000) return prgram.read(addr & 0x1fff); - if(addr & 0x8000) return prgrom.read(vrc3.addrPRG(addr)); - return cpu.mdr(); - } - - auto writePRG(uint addr, uint8 data) -> void { - if((addr & 0xe000) == 0x6000) return prgram.write(addr & 0x1fff, data); - if(addr & 0x8000) return vrc3.writeIO(addr, data); - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) { - if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.readCIRAM(addr & 0x07ff); - } - return chrram.read(addr); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) { - if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.writeCIRAM(addr & 0x07ff, data); - } - return chrram.write(addr, data); - } - - auto power() -> void { - vrc3.power(); - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - vrc3.serialize(s); - } - - struct Settings { - bool mirror; //0 = horizontal, 1 = vertical - } settings; - - VRC3 vrc3; -}; diff --git a/higan/fc/cartridge/board/konami-vrc4.cpp b/higan/fc/cartridge/board/konami-vrc4.cpp deleted file mode 100644 index c0a53a39..00000000 --- a/higan/fc/cartridge/board/konami-vrc4.cpp +++ /dev/null @@ -1,55 +0,0 @@ -struct KonamiVRC4 : Board { - KonamiVRC4(Markup::Node& document) : Board(document), vrc4(*this) { - settings.pinout.a0 = 1 << document["board/chip/pinout/a0"].natural(); - settings.pinout.a1 = 1 << document["board/chip/pinout/a1"].natural(); - } - - auto main() -> void { - return vrc4.main(); - } - - auto readPRG(uint addr) -> uint8 { - if(addr < 0x6000) return cpu.mdr(); - if(addr < 0x8000) return prgram.read(addr); - return prgrom.read(vrc4.addrPRG(addr)); - } - - auto writePRG(uint addr, uint8 data) -> void { - if(addr < 0x6000) return; - if(addr < 0x8000) return prgram.write(addr, data); - - bool a0 = (addr & settings.pinout.a0); - bool a1 = (addr & settings.pinout.a1); - addr &= 0xfff0; - addr |= (a1 << 1) | (a0 << 0); - return vrc4.writeIO(addr, data); - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) return ppu.readCIRAM(vrc4.addrCIRAM(addr)); - return Board::readCHR(vrc4.addrCHR(addr)); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) return ppu.writeCIRAM(vrc4.addrCIRAM(addr), data); - return Board::writeCHR(vrc4.addrCHR(addr), data); - } - - auto power() -> void { - vrc4.power(); - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - vrc4.serialize(s); - } - - struct Settings { - struct Pinout { - uint a0; - uint a1; - } pinout; - } settings; - - VRC4 vrc4; -}; diff --git a/higan/fc/cartridge/board/konami-vrc6.cpp b/higan/fc/cartridge/board/konami-vrc6.cpp deleted file mode 100644 index fb1c670f..00000000 --- a/higan/fc/cartridge/board/konami-vrc6.cpp +++ /dev/null @@ -1,39 +0,0 @@ -struct KonamiVRC6 : Board { - KonamiVRC6(Markup::Node& document) : Board(document), vrc6(*this) { - } - - auto readPRG(uint addr) -> uint8{ - if((addr & 0xe000) == 0x6000) return vrc6.readRAM(addr); - if(addr & 0x8000) return prgrom.read(vrc6.addrPRG(addr)); - return cpu.mdr(); - } - - auto writePRG(uint addr, uint8 data) -> void { - if((addr & 0xe000) == 0x6000) return vrc6.writeRAM(addr, data); - if(addr & 0x8000) { - addr = (addr & 0xf003); - if(prgram.size) addr = (addr & ~3) | ((addr & 2) >> 1) | ((addr & 1) << 1); - return vrc6.writeIO(addr, data); - } - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) return ppu.readCIRAM(vrc6.addrCIRAM(addr)); - return Board::readCHR(vrc6.addrCHR(addr)); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) return ppu.writeCIRAM(vrc6.addrCIRAM(addr), data); - return Board::writeCHR(vrc6.addrCHR(addr), data); - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - vrc6.serialize(s); - } - - auto main() -> void { vrc6.main(); } - auto power() -> void { vrc6.power(); } - - VRC6 vrc6; -}; diff --git a/higan/fc/cartridge/board/konami-vrc7.cpp b/higan/fc/cartridge/board/konami-vrc7.cpp deleted file mode 100644 index 5d2c02e8..00000000 --- a/higan/fc/cartridge/board/konami-vrc7.cpp +++ /dev/null @@ -1,41 +0,0 @@ -struct KonamiVRC7 : Board { - KonamiVRC7(Markup::Node& document) : Board(document), vrc7(*this) { - } - - auto main() -> void { - return vrc7.main(); - } - - auto readPRG(uint addr) -> uint8 { - if(addr < 0x6000) return cpu.mdr(); - if(addr < 0x8000) return prgram.read(addr); - return prgrom.read(vrc7.addrPRG(addr)); - } - - auto writePRG(uint addr, uint8 data) -> void { - if(addr < 0x6000) return; - if(addr < 0x8000) return prgram.write(addr, data); - return vrc7.writeIO(addr, data); - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) return ppu.readCIRAM(vrc7.addrCIRAM(addr)); - return chrram.read(vrc7.addrCHR(addr)); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) return ppu.writeCIRAM(vrc7.addrCIRAM(addr), data); - return chrram.write(vrc7.addrCHR(addr), data); - } - - auto power() -> void { - vrc7.power(); - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - vrc7.serialize(s); - } - - VRC7 vrc7; -}; diff --git a/higan/fc/cartridge/board/nes-axrom.cpp b/higan/fc/cartridge/board/nes-axrom.cpp deleted file mode 100644 index 4e40a41d..00000000 --- a/higan/fc/cartridge/board/nes-axrom.cpp +++ /dev/null @@ -1,46 +0,0 @@ -//NES-AMROM -//NES-ANROM -//NES-AN1ROM -//NES-AOROM - -struct NES_AxROM : Board { - NES_AxROM(Markup::Node& document) : Board(document) { - } - - auto readPRG(uint addr) -> uint8 { - if(addr & 0x8000) return prgrom.read((prgBank << 15) | (addr & 0x7fff)); - return cpu.mdr(); - } - - auto writePRG(uint addr, uint8 data) -> void { - if(addr & 0x8000) { - prgBank = data & 0x0f; - mirrorSelect = data & 0x10; - } - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) return ppu.readCIRAM((mirrorSelect << 10) | (addr & 0x03ff)); - return Board::readCHR(addr); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) return ppu.writeCIRAM((mirrorSelect << 10) | (addr & 0x03ff), data); - return Board::writeCHR(addr, data); - } - - auto power() -> void { - prgBank = 0x0f; - mirrorSelect = 0; - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - - s.integer(prgBank); - s.integer(mirrorSelect); - } - - uint4 prgBank; - bool mirrorSelect; -}; diff --git a/higan/fc/cartridge/board/nes-bnrom.cpp b/higan/fc/cartridge/board/nes-bnrom.cpp deleted file mode 100644 index 59bbd743..00000000 --- a/higan/fc/cartridge/board/nes-bnrom.cpp +++ /dev/null @@ -1,47 +0,0 @@ -//NES-BN-ROM-01 - -struct NES_BNROM : Board { - NES_BNROM(Markup::Node& document) : Board(document) { - settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0; - } - - auto readPRG(uint addr) -> uint8 { - if(addr & 0x8000) return prgrom.read((prgBank << 15) | (addr & 0x7fff)); - return cpu.mdr(); - } - - auto writePRG(uint addr, uint8 data) -> void { - if(addr & 0x8000) prgBank = data & 0x03; - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) { - if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.readCIRAM(addr); - } - return Board::readCHR(addr); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) { - if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.writeCIRAM(addr, data); - } - return Board::writeCHR(addr, data); - } - - auto power() -> void { - prgBank = 0; - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - s.integer(prgBank); - } - - struct Settings { - bool mirror; //0 = horizontal, 1 = vertical - } settings; - - uint2 prgBank; -}; diff --git a/higan/fc/cartridge/board/nes-cnrom.cpp b/higan/fc/cartridge/board/nes-cnrom.cpp deleted file mode 100644 index 0131eb4b..00000000 --- a/higan/fc/cartridge/board/nes-cnrom.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//NES-CNROM - -struct NES_CNROM : Board { - NES_CNROM(Markup::Node& document) : Board(document) { - settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0; - } - - auto readPRG(uint addr) -> uint8 { - if(addr & 0x8000) return prgrom.read(addr & 0x7fff); - return cpu.mdr(); - } - - auto writePRG(uint addr, uint8 data) -> void { - if(addr & 0x8000) chrBank = data & 0x03; - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) { - if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.readCIRAM(addr & 0x07ff); - } - addr = (chrBank * 0x2000) + (addr & 0x1fff); - return Board::readCHR(addr); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) { - if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.writeCIRAM(addr & 0x07ff, data); - } - addr = (chrBank * 0x2000) + (addr & 0x1fff); - Board::writeCHR(addr, data); - } - - auto power() -> void { - chrBank = 0; - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - s.integer(chrBank); - } - - struct Settings { - bool mirror; //0 = horizontal, 1 = vertical - } settings; - - uint2 chrBank; -}; diff --git a/higan/fc/cartridge/board/nes-exrom.cpp b/higan/fc/cartridge/board/nes-exrom.cpp deleted file mode 100644 index 0e7ff97e..00000000 --- a/higan/fc/cartridge/board/nes-exrom.cpp +++ /dev/null @@ -1,47 +0,0 @@ -struct NES_ExROM : Board { - NES_ExROM(Markup::Node& document) : Board(document), mmc5(*this) { - revision = Revision::ELROM; - } - - auto main() -> void { - mmc5.main(); - } - - auto readPRG(uint addr) -> uint8 { - return mmc5.readPRG(addr); - } - - auto writePRG(uint addr, uint8 data) -> void { - mmc5.writePRG(addr, data); - } - - auto readCHR(uint addr) -> uint8 { - return mmc5.readCHR(addr); - } - - auto writeCHR(uint addr, uint8 data) -> void { - mmc5.writeCHR(addr, data); - } - - auto scanline(uint y) -> void { - mmc5.scanline(y); - } - - auto power() -> void { - mmc5.power(); - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - mmc5.serialize(s); - } - - enum class Revision : uint { - EKROM, - ELROM, - ETROM, - EWROM, - } revision; - - MMC5 mmc5; -}; diff --git a/higan/fc/cartridge/board/nes-fxrom.cpp b/higan/fc/cartridge/board/nes-fxrom.cpp deleted file mode 100644 index a513857a..00000000 --- a/higan/fc/cartridge/board/nes-fxrom.cpp +++ /dev/null @@ -1,86 +0,0 @@ -//MMC4 - -struct NES_FxROM : Board { - NES_FxROM(Markup::Node& document) : Board(document) { - revision = Revision::FKROM; - } - - auto readPRG(uint addr) -> uint8 { - if(addr < 0x6000) return cpu.mdr(); - if(addr < 0x8000) return prgram.read(addr); - uint bank = addr < 0xc000 ? prgBank : (uint4)0x0f; - return prgrom.read((bank * 0x4000) | (addr & 0x3fff)); - } - - auto writePRG(uint addr, uint8 data) -> void { - if(addr < 0x6000) return; - if(addr < 0x8000) return prgram.write(addr, data); - - switch(addr & 0xf000) { - case 0xa000: prgBank = data & 0x0f; break; - case 0xb000: chrBank[0][0] = data & 0x1f; break; - case 0xc000: chrBank[0][1] = data & 0x1f; break; - case 0xd000: chrBank[1][0] = data & 0x1f; break; - case 0xe000: chrBank[1][1] = data & 0x1f; break; - case 0xf000: mirror = data & 0x01; break; - } - } - - auto addrCIRAM(uint addr) const -> uint { - switch(mirror) { - case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring - case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring - } - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) return ppu.readCIRAM(addrCIRAM(addr)); - bool region = addr & 0x1000; - uint bank = chrBank[region][latch[region]]; - if((addr & 0x0ff8) == 0x0fd8) latch[region] = 0; - if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1; - return Board::readCHR((bank * 0x1000) | (addr & 0x0fff)); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) return ppu.writeCIRAM(addrCIRAM(addr), data); - bool region = addr & 0x1000; - uint bank = chrBank[region][latch[region]]; - if((addr & 0x0ff8) == 0x0fd8) latch[region] = 0; - if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1; - return Board::writeCHR((bank * 0x1000) | (addr & 0x0fff), data); - } - - auto power() -> void { - prgBank = 0; - chrBank[0][0] = 0; - chrBank[0][1] = 0; - chrBank[1][0] = 0; - chrBank[1][1] = 0; - mirror = 0; - latch[0] = 0; - latch[1] = 0; - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - - s.integer(prgBank); - s.integer(chrBank[0][0]); - s.integer(chrBank[0][1]); - s.integer(chrBank[1][0]); - s.integer(chrBank[1][1]); - s.integer(mirror); - s.array(latch); - } - - enum Revision : uint { - FJROM, - FKROM, - } revision; - - uint4 prgBank; - uint5 chrBank[2][2]; - bool mirror; - bool latch[2]; -}; diff --git a/higan/fc/cartridge/board/nes-gxrom.cpp b/higan/fc/cartridge/board/nes-gxrom.cpp deleted file mode 100644 index cb9c6a7d..00000000 --- a/higan/fc/cartridge/board/nes-gxrom.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//NES-GNROM -//NES-MHROM - -struct NES_GxROM : Board { - NES_GxROM(Markup::Node& document) : Board(document) { - settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0; - } - - auto readPRG(uint addr) -> uint8 { - if(addr & 0x8000) return prgrom.read((prgBank << 15) | (addr & 0x7fff)); - return cpu.mdr(); - } - - auto writePRG(uint addr, uint8 data) -> void { - if(addr & 0x8000) { - prgBank = (data & 0x30) >> 4; - chrBank = (data & 0x03) >> 0; - } - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) { - if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.readCIRAM(addr & 0x07ff); - } - addr = (chrBank * 0x2000) + (addr & 0x1fff); - return Board::readCHR(addr); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) { - if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.writeCIRAM(addr & 0x07ff, data); - } - addr = (chrBank * 0x2000) + (addr & 0x1fff); - Board::writeCHR(addr, data); - } - - auto power() -> void { - prgBank = 0; - chrBank = 0; - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - s.integer(prgBank); - s.integer(chrBank); - } - - struct Settings { - bool mirror; //0 = horizontal, 1 = vertical - } settings; - - uint2 prgBank; - uint2 chrBank; -}; diff --git a/higan/fc/cartridge/board/nes-hkrom.cpp b/higan/fc/cartridge/board/nes-hkrom.cpp deleted file mode 100644 index 14cda41a..00000000 --- a/higan/fc/cartridge/board/nes-hkrom.cpp +++ /dev/null @@ -1,42 +0,0 @@ -struct NES_HKROM : Board { - NES_HKROM(Markup::Node& document) : Board(document), mmc6(*this) { - } - - auto main() -> void { - mmc6.main(); - } - - auto readPRG(uint addr) -> uint8 { - if((addr & 0xf000) == 0x7000) return mmc6.readRAM(addr); - if(addr & 0x8000) return prgrom.read(mmc6.addrPRG(addr)); - return cpu.mdr(); - } - - auto writePRG(uint addr, uint8 data) -> void { - if((addr & 0xf000) == 0x7000) return mmc6.writeRAM(addr, data); - if(addr & 0x8000) return mmc6.writeIO(addr, data); - } - - auto readCHR(uint addr) -> uint8 { - mmc6.irqTest(addr); - if(addr & 0x2000) return ppu.readCIRAM(mmc6.addrCIRAM(addr)); - return Board::readCHR(mmc6.addrCHR(addr)); - } - - auto writeCHR(uint addr, uint8 data) -> void { - mmc6.irqTest(addr); - if(addr & 0x2000) return ppu.writeCIRAM(mmc6.addrCIRAM(addr), data); - return Board::writeCHR(mmc6.addrCHR(addr), data); - } - - auto power() -> void { - mmc6.power(); - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - mmc6.serialize(s); - } - - MMC6 mmc6; -}; diff --git a/higan/fc/cartridge/board/nes-nrom.cpp b/higan/fc/cartridge/board/nes-nrom.cpp deleted file mode 100644 index ec79351d..00000000 --- a/higan/fc/cartridge/board/nes-nrom.cpp +++ /dev/null @@ -1,44 +0,0 @@ -//NES-NROM-128 -//NES-NROM-256 - -struct NES_NROM : Board { - NES_NROM(Markup::Node& document) : Board(document) { - settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0; - } - - auto readPRG(uint addr) -> uint8 { - if(addr & 0x8000) return prgrom.read(addr); - return cpu.mdr(); - } - - auto writePRG(uint addr, uint8 data) -> void { - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) { - if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.readCIRAM(addr & 0x07ff); - } - if(chrram.size) return chrram.read(addr); - return chrrom.read(addr); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) { - if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.writeCIRAM(addr & 0x07ff, data); - } - if(chrram.size) return chrram.write(addr, data); - } - - auto power() -> void { - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - } - - struct Settings { - bool mirror; //0 = horizontal, 1 = vertical - } settings; -}; diff --git a/higan/fc/cartridge/board/nes-pxrom.cpp b/higan/fc/cartridge/board/nes-pxrom.cpp deleted file mode 100644 index c41ac0dd..00000000 --- a/higan/fc/cartridge/board/nes-pxrom.cpp +++ /dev/null @@ -1,92 +0,0 @@ -//MMC2 - -struct NES_PxROM : Board { - NES_PxROM(Markup::Node& document) : Board(document) { - revision = Revision::PNROM; - } - - auto readPRG(uint addr) -> uint8 { - if(addr < 0x6000) return cpu.mdr(); - if(addr < 0x8000) return prgram.read(addr); - uint bank = 0; - switch((addr / 0x2000) & 3) { - case 0: bank = prgBank; break; - case 1: bank = 0x0d; break; - case 2: bank = 0x0e; break; - case 3: bank = 0x0f; break; - } - return prgrom.read((bank * 0x2000) | (addr & 0x1fff)); - } - - auto writePRG(uint addr, uint8 data) -> void { - if(addr < 0x6000) return; - if(addr < 0x8000) return prgram.write(addr, data); - - switch(addr & 0xf000) { - case 0xa000: prgBank = data & 0x0f; break; - case 0xb000: chrBank[0][0] = data & 0x1f; break; - case 0xc000: chrBank[0][1] = data & 0x1f; break; - case 0xd000: chrBank[1][0] = data & 0x1f; break; - case 0xe000: chrBank[1][1] = data & 0x1f; break; - case 0xf000: mirror = data & 0x01; break; - } - } - - auto addrCIRAM(uint addr) const -> uint { - switch(mirror) { - case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring - case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring - } - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) return ppu.readCIRAM(addrCIRAM(addr)); - bool region = addr & 0x1000; - uint bank = chrBank[region][latch[region]]; - if((addr & 0x0ff8) == 0x0fd8) latch[region] = 0; - if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1; - return Board::readCHR((bank * 0x1000) | (addr & 0x0fff)); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) return ppu.writeCIRAM(addrCIRAM(addr), data); - bool region = addr & 0x1000; - uint bank = chrBank[region][latch[region]]; - if((addr & 0x0ff8) == 0x0fd8) latch[region] = 0; - if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1; - return Board::writeCHR((bank * 0x1000) | (addr & 0x0fff), data); - } - - auto power() -> void { - prgBank = 0; - chrBank[0][0] = 0; - chrBank[0][1] = 0; - chrBank[1][0] = 0; - chrBank[1][1] = 0; - mirror = 0; - latch[0] = 0; - latch[1] = 0; - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - - s.integer(prgBank); - s.integer(chrBank[0][0]); - s.integer(chrBank[0][1]); - s.integer(chrBank[1][0]); - s.integer(chrBank[1][1]); - s.integer(mirror); - s.array(latch); - } - - enum Revision : uint { - PEEOROM, - PNROM, - } revision; - - uint4 prgBank; - uint5 chrBank[2][2]; - bool mirror; - bool latch[2]; -}; diff --git a/higan/fc/cartridge/board/nes-sxrom.cpp b/higan/fc/cartridge/board/nes-sxrom.cpp deleted file mode 100644 index abc47ad1..00000000 --- a/higan/fc/cartridge/board/nes-sxrom.cpp +++ /dev/null @@ -1,95 +0,0 @@ -struct NES_SxROM : Board { - NES_SxROM(Markup::Node& document) : Board(document), mmc1(*this) { - revision = Revision::SXROM; - } - - auto main() -> void { - return mmc1.main(); - } - - auto addrRAM(uint addr) -> uint { - uint bank = 0; - if(revision == Revision::SOROM) bank = (mmc1.chrBank[0] & 0x08) >> 3; - if(revision == Revision::SUROM) bank = (mmc1.chrBank[0] & 0x0c) >> 2; - if(revision == Revision::SXROM) bank = (mmc1.chrBank[0] & 0x0c) >> 2; - return (bank << 13) | (addr & 0x1fff); - } - - auto readPRG(uint addr) -> uint8 { - if((addr & 0xe000) == 0x6000) { - if(revision == Revision::SNROM) { - if(mmc1.chrBank[0] & 0x10) return cpu.mdr(); - } - if(mmc1.ramDisable) return 0x00; - return prgram.read(addrRAM(addr)); - } - - if(addr & 0x8000) { - addr = mmc1.addrPRG(addr); - if(revision == Revision::SXROM) { - addr |= ((mmc1.chrBank[0] & 0x10) >> 4) << 18; - } - return prgrom.read(addr); - } - - return cpu.mdr(); - } - - auto writePRG(uint addr, uint8 data) -> void { - if((addr & 0xe000) == 0x6000) { - if(revision == Revision::SNROM) { - if(mmc1.chrBank[0] & 0x10) return; - } - if(mmc1.ramDisable) return; - return prgram.write(addrRAM(addr), data); - } - - if(addr & 0x8000) return mmc1.writeIO(addr, data); - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) return ppu.readCIRAM(mmc1.addrCIRAM(addr)); - return Board::readCHR(mmc1.addrCHR(addr)); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) return ppu.writeCIRAM(mmc1.addrCIRAM(addr), data); - return Board::writeCHR(mmc1.addrCHR(addr), data); - } - - auto power() -> void { - mmc1.power(); - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - mmc1.serialize(s); - } - - enum class Revision : uint { - SAROM, - SBROM, - SCROM, - SC1ROM, - SEROM, - SFROM, - SGROM, - SHROM, - SH1ROM, - SIROM, - SJROM, - SKROM, - SLROM, - SL1ROM, - SL2ROM, - SL3ROM, - SLRROM, - SMROM, - SNROM, - SOROM, - SUROM, - SXROM, - } revision; - - MMC1 mmc1; -}; diff --git a/higan/fc/cartridge/board/nes-txrom.cpp b/higan/fc/cartridge/board/nes-txrom.cpp deleted file mode 100644 index 784e847f..00000000 --- a/higan/fc/cartridge/board/nes-txrom.cpp +++ /dev/null @@ -1,61 +0,0 @@ -struct NES_TxROM : Board { - NES_TxROM(Markup::Node& document) : Board(document), mmc3(*this) { - revision = Revision::TLROM; - } - - auto main() -> void { - mmc3.main(); - } - - auto readPRG(uint addr) -> uint8 { - if((addr & 0xe000) == 0x6000) return mmc3.readRAM(addr); - if(addr & 0x8000) return prgrom.read(mmc3.addrPRG(addr)); - return cpu.mdr(); - } - - auto writePRG(uint addr, uint8 data) -> void { - if((addr & 0xe000) == 0x6000) return mmc3.writeRAM(addr, data); - if(addr & 0x8000) return mmc3.writeIO(addr, data); - } - - auto readCHR(uint addr) -> uint8 { - mmc3.irqTest(addr); - if(addr & 0x2000) return ppu.readCIRAM(mmc3.addrCIRAM(addr)); - return Board::readCHR(mmc3.addrCHR(addr)); - } - - auto writeCHR(uint addr, uint8 data) -> void { - mmc3.irqTest(addr); - if(addr & 0x2000) return ppu.writeCIRAM(mmc3.addrCIRAM(addr), data); - return Board::writeCHR(mmc3.addrCHR(addr), data); - } - - auto power() -> void { - mmc3.power(); - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - mmc3.serialize(s); - } - - enum class Revision : uint { - TBROM, - TEROM, - TFROM, - TGROM, - TKROM, - TKSROM, - TLROM, - TL1ROM, - TL2ROM, - TLSROM, - TNROM, - TQROM, - TR1ROM, - TSROM, - TVROM, - } revision; - - MMC3 mmc3; -}; diff --git a/higan/fc/cartridge/board/nes-uxrom.cpp b/higan/fc/cartridge/board/nes-uxrom.cpp deleted file mode 100644 index 613c8f28..00000000 --- a/higan/fc/cartridge/board/nes-uxrom.cpp +++ /dev/null @@ -1,50 +0,0 @@ -//NES-UNROM -//NES-UOROM - -struct NES_UxROM : Board { - NES_UxROM(Markup::Node& document) : Board(document) { - settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0; - } - - auto readPRG(uint addr) -> uint8 { - if((addr & 0xc000) == 0x8000) return prgrom.read((prgBank << 14) | (addr & 0x3fff)); - if((addr & 0xc000) == 0xc000) return prgrom.read(( 0x0f << 14) | (addr & 0x3fff)); - return cpu.mdr(); - } - - auto writePRG(uint addr, uint8 data) -> void { - if(addr & 0x8000) prgBank = data & 0x0f; - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) { - if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.readCIRAM(addr); - } - return Board::readCHR(addr); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) { - if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.writeCIRAM(addr, data); - } - return Board::writeCHR(addr, data); - } - - auto power() -> void { - prgBank = 0; - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - - s.integer(prgBank); - } - - struct Settings { - bool mirror; //0 = horizontal, 1 = vertical - } settings; - - uint4 prgBank; -}; diff --git a/higan/fc/cartridge/board/sunsoft-5b.cpp b/higan/fc/cartridge/board/sunsoft-5b.cpp deleted file mode 100644 index 402d2450..00000000 --- a/higan/fc/cartridge/board/sunsoft-5b.cpp +++ /dev/null @@ -1,217 +0,0 @@ -//SUNSOFT-5B - -struct Sunsoft5B : Board { - Sunsoft5B(Markup::Node& document) : Board(document) { - } - - struct Pulse { - auto clock() -> void { - if(--counter == 0) { - counter = frequency << 4; - duty ^= 1; - } - output = duty ? volume : (uint4)0; - if(disable) output = 0; - } - - auto power() -> void { - disable = 1; - frequency = 1; - volume = 0; - - counter = 0; - duty = 0; - output = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(disable); - s.integer(frequency); - s.integer(volume); - - s.integer(counter); - s.integer(duty); - s.integer(output); - } - - bool disable; - uint12 frequency; - uint4 volume; - - uint16 counter; //12-bit countdown + 4-bit phase - uint1 duty; - uint4 output; - } pulse[3]; - - auto main() -> void { - if(irqCounterEnable) { - if(--irqCounter == 0xffff) { - cpu.irqLine(irqEnable); - } - } - - pulse[0].clock(); - pulse[1].clock(); - pulse[2].clock(); - int16 output = dac[pulse[0].output] + dac[pulse[1].output] + dac[pulse[2].output]; - apu.setSample(-output); - - tick(); - } - - auto readPRG(uint addr) -> uint8 { - if(addr < 0x6000) return cpu.mdr(); - - uint8 bank = 0x3f; //((addr & 0xe000) == 0xe000 - if((addr & 0xe000) == 0x6000) bank = prgBank[0]; - if((addr & 0xe000) == 0x8000) bank = prgBank[1]; - if((addr & 0xe000) == 0xa000) bank = prgBank[2]; - if((addr & 0xe000) == 0xc000) bank = prgBank[3]; - - bool ramEnable = bank & 0x80; - bool ramSelect = bank & 0x40; - bank &= 0x3f; - - if(ramSelect) { - if(!ramEnable) return cpu.mdr(); - return prgram.data[addr & 0x1fff]; - } - - addr = (bank << 13) | (addr & 0x1fff); - return prgrom.read(addr); - } - - auto writePRG(uint addr, uint8 data) -> void { - if((addr & 0xe000) == 0x6000) { - prgram.data[addr & 0x1fff] = data; - } - - if(addr == 0x8000) { - mmuPort = data & 0x0f; - } - - if(addr == 0xa000) { - switch(mmuPort) { - case 0: chrBank[0] = data; break; - case 1: chrBank[1] = data; break; - case 2: chrBank[2] = data; break; - case 3: chrBank[3] = data; break; - case 4: chrBank[4] = data; break; - case 5: chrBank[5] = data; break; - case 6: chrBank[6] = data; break; - case 7: chrBank[7] = data; break; - case 8: prgBank[0] = data; break; - case 9: prgBank[1] = data; break; - case 10: prgBank[2] = data; break; - case 11: prgBank[3] = data; break; - case 12: mirror = data & 3; break; - case 13: - irqEnable = data & 0x80; - irqCounterEnable = data & 0x01; - if(irqEnable == 0) cpu.irqLine(0); - break; - case 14: irqCounter = (irqCounter & 0xff00) | (data << 0); break; - case 15: irqCounter = (irqCounter & 0x00ff) | (data << 8); break; - } - } - - if(addr == 0xc000) { - apuPort = data & 0x0f; - } - - if(addr == 0xe000) { - switch(apuPort) { - case 0: pulse[0].frequency = (pulse[0].frequency & 0xff00) | (data << 0); break; - case 1: pulse[0].frequency = (pulse[0].frequency & 0x00ff) | (data << 8); break; - case 2: pulse[1].frequency = (pulse[1].frequency & 0xff00) | (data << 0); break; - case 3: pulse[1].frequency = (pulse[1].frequency & 0x00ff) | (data << 8); break; - case 4: pulse[2].frequency = (pulse[2].frequency & 0xff00) | (data << 0); break; - case 5: pulse[2].frequency = (pulse[2].frequency & 0x00ff) | (data << 8); break; - case 7: - pulse[0].disable = data & 0x01; - pulse[1].disable = data & 0x02; - pulse[2].disable = data & 0x04; - break; - case 8: pulse[0].volume = data & 0x0f; break; - case 9: pulse[1].volume = data & 0x0f; break; - case 10: pulse[2].volume = data & 0x0f; break; - } - } - } - - auto addrCHR(uint addr) -> uint { - uint8 bank = (addr >> 10) & 7; - return (chrBank[bank] << 10) | (addr & 0x03ff); - } - - auto addrCIRAM(uint addr) -> uint { - switch(mirror) { - case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical - case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal - case 2: return 0x0000 | (addr & 0x03ff); //first - case 3: return 0x0400 | (addr & 0x03ff); //second - } - unreachable; - } - - auto readCHR(uint addr) -> uint8 { - if(addr & 0x2000) return ppu.readCIRAM(addrCIRAM(addr)); - return Board::readCHR(addrCHR(addr)); - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) return ppu.writeCIRAM(addrCIRAM(addr), data); - return Board::writeCHR(addrCHR(addr), data); - } - - auto power() -> void { - for(int n : range(16)) { - double volume = 1.0 / pow(2, 1.0 / 2 * (15 - n)); - dac[n] = volume * 8192.0; - } - - mmuPort = 0; - apuPort = 0; - - for(auto& n : prgBank) n = 0; - for(auto& n : chrBank) n = 0; - mirror = 0; - irqEnable = 0; - irqCounterEnable = 0; - irqCounter = 0; - - pulse[0].power(); - pulse[1].power(); - pulse[2].power(); - } - - auto serialize(serializer& s) -> void { - Board::serialize(s); - - s.integer(mmuPort); - s.integer(apuPort); - - s.array(prgBank); - s.array(chrBank); - s.integer(mirror); - s.integer(irqEnable); - s.integer(irqCounterEnable); - s.integer(irqCounter); - - pulse[0].serialize(s); - pulse[1].serialize(s); - pulse[2].serialize(s); - } - - uint4 mmuPort; - uint4 apuPort; - - uint8 prgBank[4]; - uint8 chrBank[8]; - uint2 mirror; - bool irqEnable; - bool irqCounterEnable; - uint16 irqCounter; - - int16 dac[16]; -}; diff --git a/higan/fc/cartridge/cartridge.cpp b/higan/fc/cartridge/cartridge.cpp deleted file mode 100644 index f36dd2fd..00000000 --- a/higan/fc/cartridge/cartridge.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include - -namespace Famicom { - -#include "chip/chip.cpp" -#include "board/board.cpp" -#include "serialization.cpp" -Cartridge cartridge; - -auto Cartridge::Enter() -> void { - while(true) scheduler.synchronize(), cartridge.main(); -} - -auto Cartridge::main() -> void { - board->main(); -} - -auto Cartridge::load() -> bool { - if(auto loaded = platform->load(ID::Famicom, "Famicom", "fc", {"NTSC-J", "NTSC-U", "PAL"})) { - information.pathID = loaded.pathID; - information.region = loaded.option; - } else return false; - - if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else { - return false; - } - - Board::load(information.manifest); //this call will set Cartridge::board if successful - if(!board) return false; - - Hash::SHA256 sha; - sha.input(board->prgrom.data, board->prgrom.size); - sha.input(board->chrrom.data, board->chrrom.size); - information.sha256 = sha.digest(); - return true; -} - -auto Cartridge::save() -> void { - board->save(); -} - -auto Cartridge::unload() -> void { - delete board; - board = nullptr; -} - -auto Cartridge::power() -> void { - create(Cartridge::Enter, system.frequency()); - board->power(); -} - -auto Cartridge::readPRG(uint addr) -> uint8 { - return board->readPRG(addr); -} - -auto Cartridge::writePRG(uint addr, uint8 data) -> void { - return board->writePRG(addr, data); -} - -auto Cartridge::readCHR(uint addr) -> uint8 { - return board->readCHR(addr); -} - -auto Cartridge::writeCHR(uint addr, uint8 data) -> void { - return board->writeCHR(addr, data); -} - -auto Cartridge::scanline(uint y) -> void { - return board->scanline(y); -} - -} diff --git a/higan/fc/cartridge/cartridge.hpp b/higan/fc/cartridge/cartridge.hpp deleted file mode 100644 index d29e035a..00000000 --- a/higan/fc/cartridge/cartridge.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "chip/chip.hpp" -#include "board/board.hpp" - -struct Cartridge : Thread { - inline auto rate() const -> uint { return Region::PAL() ? 16 : 12; } - - //cartridge.cpp - static auto Enter() -> void; - auto main() -> void; - - auto pathID() const -> uint { return information.pathID; } - auto region() const -> string { return information.region; } - auto hash() const -> string { return information.sha256; } - auto manifest() const -> string { return information.manifest; } - auto title() const -> string { return information.title; } - - auto load() -> bool; - auto save() -> void; - auto unload() -> void; - - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - struct Information { - uint pathID = 0; - string region; - string sha256; - string manifest; - string title; - } information; - -//privileged: - Board* board = nullptr; - - auto readPRG(uint addr) -> uint8; - auto writePRG(uint addr, uint8 data) -> void; - - auto readCHR(uint addr) -> uint8; - auto writeCHR(uint addr, uint8 data) -> void; - - //scanline() is for debugging purposes only: - //boards must detect scanline edges on their own - auto scanline(uint y) -> void; -}; - -extern Cartridge cartridge; diff --git a/higan/fc/cartridge/chip/chip.cpp b/higan/fc/cartridge/chip/chip.cpp deleted file mode 100644 index 7bb7afc9..00000000 --- a/higan/fc/cartridge/chip/chip.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "mmc1.cpp" -#include "mmc3.cpp" -#include "mmc5.cpp" -#include "mmc6.cpp" -#include "vrc1.cpp" -#include "vrc2.cpp" -#include "vrc3.cpp" -#include "vrc4.cpp" -#include "vrc6.cpp" -#include "vrc7.cpp" - -Chip::Chip(Board& board) : board(board) { -} - -auto Chip::tick() -> void { - board.tick(); -} diff --git a/higan/fc/cartridge/chip/chip.hpp b/higan/fc/cartridge/chip/chip.hpp deleted file mode 100644 index 028acb24..00000000 --- a/higan/fc/cartridge/chip/chip.hpp +++ /dev/null @@ -1,8 +0,0 @@ -struct Board; - -struct Chip { - Chip(Board& board); - auto tick() -> void; - - Board& board; -}; diff --git a/higan/fc/cartridge/chip/mmc1.cpp b/higan/fc/cartridge/chip/mmc1.cpp deleted file mode 100644 index 30b525fc..00000000 --- a/higan/fc/cartridge/chip/mmc1.cpp +++ /dev/null @@ -1,126 +0,0 @@ -struct MMC1 : Chip { - MMC1(Board& board) : Chip(board) { - revision = Revision::MMC1B2; - } - - auto main() -> void { - if(writedelay) writedelay--; - tick(); - } - - auto addrPRG(uint addr) -> uint { - bool region = addr & 0x4000; - uint bank = (prgBank & ~1) + region; - - if(prgSize) { - bank = (region == 0 ? 0x0 : 0xf); - if(region != prgMode) bank = prgBank; - } - - return (bank << 14) | (addr & 0x3fff); - } - - auto addrCHR(uint addr) -> uint { - bool region = addr & 0x1000; - uint bank = chrBank[region]; - if(chrMode == 0) bank = (chrBank[0] & ~1) | region; - return (bank << 12) | (addr & 0x0fff); - } - - auto addrCIRAM(uint addr) -> uint { - switch(mirror) { - case 0: return 0x0000 | (addr & 0x03ff); - case 1: return 0x0400 | (addr & 0x03ff); - case 2: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); - case 3: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); - } - unreachable; - } - - auto writeIO(uint addr, uint8 data) -> void { - if(writedelay) return; - writedelay = 2; - - if(data & 0x80) { - shiftaddr = 0; - prgSize = 1; - prgMode = 1; - } else { - shiftdata = ((data & 1) << 4) | (shiftdata >> 1); - if(++shiftaddr == 5) { - shiftaddr = 0; - switch((addr >> 13) & 3) { - case 0: - chrMode = (shiftdata & 0x10); - prgSize = (shiftdata & 0x08); - prgMode = (shiftdata & 0x04); - mirror = (shiftdata & 0x03); - break; - - case 1: - chrBank[0] = (shiftdata & 0x1f); - break; - - case 2: - chrBank[1] = (shiftdata & 0x1f); - break; - - case 3: - ramDisable = (shiftdata & 0x10); - prgBank = (shiftdata & 0x0f); - break; - } - } - } - } - - auto power() -> void { - writedelay = 0; - shiftaddr = 0; - shiftdata = 0; - - chrMode = 0; - prgSize = 1; - prgMode = 1; - mirror = 0; - chrBank[0] = 0; - chrBank[1] = 1; - ramDisable = 0; - prgBank = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(writedelay); - s.integer(shiftaddr); - s.integer(shiftdata); - - s.integer(chrMode); - s.integer(prgSize); - s.integer(prgMode); - s.integer(mirror); - s.array(chrBank); - s.integer(ramDisable); - s.integer(prgBank); - } - - enum class Revision : uint { - MMC1, - MMC1A, - MMC1B1, - MMC1B2, - MMC1B3, - MMC1C, - } revision; - - uint writedelay; - uint shiftaddr; - uint shiftdata; - - bool chrMode; - bool prgSize; //0 = 32K, 1 = 16K - bool prgMode; - uint2 mirror; //0 = first, 1 = second, 2 = vertical, 3 = horizontal - uint5 chrBank[2]; - bool ramDisable; - uint4 prgBank; -}; diff --git a/higan/fc/cartridge/chip/mmc3.cpp b/higan/fc/cartridge/chip/mmc3.cpp deleted file mode 100644 index 0920c131..00000000 --- a/higan/fc/cartridge/chip/mmc3.cpp +++ /dev/null @@ -1,181 +0,0 @@ -struct MMC3 : Chip { - MMC3(Board& board) : Chip(board) { - } - - auto main() -> void { - if(irqDelay) irqDelay--; - cpu.irqLine(irqLine); - tick(); - } - - auto irqTest(uint addr) -> void { - if(!(chrAbus & 0x1000) && (addr & 0x1000)) { - if(irqDelay == 0) { - if(irqCounter == 0) { - irqCounter = irqLatch; - } else if(--irqCounter == 0) { - if(irqEnable) irqLine = 1; - } - } - irqDelay = 6; - } - chrAbus = addr; - } - - auto addrPRG(uint addr) const -> uint { - switch((addr >> 13) & 3) { - case 0: - if(prgMode == 1) return (0x3e << 13) | (addr & 0x1fff); - return (prgBank[0] << 13) | (addr & 0x1fff); - case 1: - return (prgBank[1] << 13) | (addr & 0x1fff); - case 2: - if(prgMode == 0) return (0x3e << 13) | (addr & 0x1fff); - return (prgBank[0] << 13) | (addr & 0x1fff); - case 3: - return (0x3f << 13) | (addr & 0x1fff); - } - unreachable; - } - - auto addrCHR(uint addr) const -> uint { - if(chrMode == 0) { - if(addr <= 0x07ff) return (chrBank[0] << 10) | (addr & 0x07ff); - if(addr <= 0x0fff) return (chrBank[1] << 10) | (addr & 0x07ff); - if(addr <= 0x13ff) return (chrBank[2] << 10) | (addr & 0x03ff); - if(addr <= 0x17ff) return (chrBank[3] << 10) | (addr & 0x03ff); - if(addr <= 0x1bff) return (chrBank[4] << 10) | (addr & 0x03ff); - if(addr <= 0x1fff) return (chrBank[5] << 10) | (addr & 0x03ff); - } else { - if(addr <= 0x03ff) return (chrBank[2] << 10) | (addr & 0x03ff); - if(addr <= 0x07ff) return (chrBank[3] << 10) | (addr & 0x03ff); - if(addr <= 0x0bff) return (chrBank[4] << 10) | (addr & 0x03ff); - if(addr <= 0x0fff) return (chrBank[5] << 10) | (addr & 0x03ff); - if(addr <= 0x17ff) return (chrBank[0] << 10) | (addr & 0x07ff); - if(addr <= 0x1fff) return (chrBank[1] << 10) | (addr & 0x07ff); - } - return 0; - } - - auto addrCIRAM(uint addr) const -> uint { - if(mirror == 0) return ((addr & 0x0400) >> 0) | (addr & 0x03ff); - if(mirror == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff); - unreachable; - } - - auto readRAM(uint addr) -> uint8 { - if(ramEnable) return board.prgram.data[addr & 0x1fff]; - return 0x00; - } - - auto writeRAM(uint addr, uint8 data) -> void { - if(ramEnable && !ramWriteProtect) board.prgram.data[addr & 0x1fff] = data; - } - - auto writeIO(uint addr, uint8 data) -> void { - switch(addr & 0xe001) { - case 0x8000: - chrMode = data & 0x80; - prgMode = data & 0x40; - bankSelect = data & 0x07; - break; - - case 0x8001: - switch(bankSelect) { - case 0: chrBank[0] = data & ~1; break; - case 1: chrBank[1] = data & ~1; break; - case 2: chrBank[2] = data; break; - case 3: chrBank[3] = data; break; - case 4: chrBank[4] = data; break; - case 5: chrBank[5] = data; break; - case 6: prgBank[0] = data & 0x3f; break; - case 7: prgBank[1] = data & 0x3f; break; - } - break; - - case 0xa000: - mirror = data & 0x01; - break; - - case 0xa001: - ramEnable = data & 0x80; - ramWriteProtect = data & 0x40; - break; - - case 0xc000: - irqLatch = data; - break; - - case 0xc001: - irqCounter = 0; - break; - - case 0xe000: - irqEnable = false; - irqLine = 0; - break; - - case 0xe001: - irqEnable = true; - break; - } - } - - auto power() -> void { - chrMode = 0; - prgMode = 0; - bankSelect = 0; - prgBank[0] = 0; - prgBank[1] = 0; - chrBank[0] = 0; - chrBank[1] = 0; - chrBank[2] = 0; - chrBank[3] = 0; - chrBank[4] = 0; - chrBank[5] = 0; - mirror = 0; - ramEnable = 1; - ramWriteProtect = 0; - irqLatch = 0; - irqCounter = 0; - irqEnable = false; - irqDelay = 0; - irqLine = 0; - - chrAbus = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(chrMode); - s.integer(prgMode); - s.integer(bankSelect); - s.array(prgBank); - s.array(chrBank); - s.integer(mirror); - s.integer(ramEnable); - s.integer(ramWriteProtect); - s.integer(irqLatch); - s.integer(irqCounter); - s.integer(irqEnable); - s.integer(irqDelay); - s.integer(irqLine); - - s.integer(chrAbus); - } - - bool chrMode; - bool prgMode; - uint3 bankSelect; - uint8 prgBank[2]; - uint8 chrBank[6]; - bool mirror; - bool ramEnable; - bool ramWriteProtect; - uint8 irqLatch; - uint8 irqCounter; - bool irqEnable; - uint irqDelay; - bool irqLine; - - uint16 chrAbus; -}; diff --git a/higan/fc/cartridge/chip/mmc5.cpp b/higan/fc/cartridge/chip/mmc5.cpp deleted file mode 100644 index 278892b3..00000000 --- a/higan/fc/cartridge/chip/mmc5.cpp +++ /dev/null @@ -1,493 +0,0 @@ -struct MMC5 : Chip { - MMC5(Board& board) : Chip(board) { - revision = Revision::MMC5; - } - - auto main() -> void { - //scanline() resets this; if no scanlines detected, enter video blanking period - if(++cpuCycleCounter >= 200) blank(); //113-114 normal; ~2500 across Vblank period - - cpu.irqLine(irqEnable && irqPending); - tick(); - } - - auto scanline(uint y) -> void { - //used for testing only, to verify MMC5 scanline detection is accurate: - //if(y != vcounter && y <= 240) print(y, " vs ", vcounter, "\n"); - } - - auto accessPRG(bool write, uint addr, uint8 data = 0x00) -> uint8 { - uint bank; - - if((addr & 0xe000) == 0x6000) { - bank = (ramSelect << 2) | ramBank; - addr &= 0x1fff; - } else if(prgMode == 0) { - bank = prgBank[3] & ~3; - addr &= 0x7fff; - } else if(prgMode == 1) { - if((addr & 0xc000) == 0x8000) bank = (prgBank[1] & ~1); - if((addr & 0xe000) == 0xc000) bank = (prgBank[3] & ~1); - addr &= 0x3fff; - } else if(prgMode == 2) { - if((addr & 0xe000) == 0x8000) bank = (prgBank[1] & ~1) | 0; - if((addr & 0xe000) == 0xa000) bank = (prgBank[1] & ~1) | 1; - if((addr & 0xe000) == 0xc000) bank = (prgBank[2]); - if((addr & 0xe000) == 0xe000) bank = (prgBank[3]); - addr &= 0x1fff; - } else if(prgMode == 3) { - if((addr & 0xe000) == 0x8000) bank = prgBank[0]; - if((addr & 0xe000) == 0xa000) bank = prgBank[1]; - if((addr & 0xe000) == 0xc000) bank = prgBank[2]; - if((addr & 0xe000) == 0xe000) bank = prgBank[3]; - addr &= 0x1fff; - } - - bool rom = bank & 0x80; - bank &= 0x7f; - - if(write == false) { - if(rom) { - return board.prgrom.read((bank << 13) | addr); - } else { - return board.prgram.read((bank << 13) | addr); - } - } else { - if(rom) { - board.prgrom.write((bank << 13) | addr, data); - } else { - if(prgramWriteProtect[0] == 2 && prgramWriteProtect[1] == 1) { - board.prgram.write((bank << 13) | addr, data); - } - } - return 0x00; - } - } - - auto readPRG(uint addr) -> uint8 { - if((addr & 0xfc00) == 0x5c00) { - if(exramMode >= 2) return exram[addr & 0x03ff]; - return cpu.mdr(); - } - - if(addr >= 0x6000) { - return accessPRG(0, addr); - } - - switch(addr) { - case 0x5204: { - uint8 result = (irqPending << 7) | (inFrame << 6); - irqPending = false; - return result; - } - case 0x5205: return (multiplier * multiplicand) >> 0; - case 0x5206: return (multiplier * multiplicand) >> 8; - } - - return 0x00; - } - - auto writePRG(uint addr, uint8 data) -> void { - if((addr & 0xfc00) == 0x5c00) { - //writes 0x00 *during* Vblank (not during screen rendering ...) - if(exramMode == 0 || exramMode == 1) exram[addr & 0x03ff] = inFrame ? data : (uint8)0x00; - if(exramMode == 2) exram[addr & 0x03ff] = data; - return; - } - - if(addr >= 0x6000) { - accessPRG(1, addr, data); - return; - } - - switch(addr) { - case 0x2000: - sprite8x16 = data & 0x20; - break; - - case 0x2001: - //if BG+sprites are disabled; enter video blanking period - if((data & 0x18) == 0) blank(); - break; - - case 0x5100: prgMode = data & 3; break; - case 0x5101: chrMode = data & 3; break; - - case 0x5102: prgramWriteProtect[0] = data & 3; break; - case 0x5103: prgramWriteProtect[1] = data & 3; break; - - case 0x5104: - exramMode = data & 3; - break; - - case 0x5105: - nametableMode[0] = (data & 0x03) >> 0; - nametableMode[1] = (data & 0x0c) >> 2; - nametableMode[2] = (data & 0x30) >> 4; - nametableMode[3] = (data & 0xc0) >> 6; - break; - - case 0x5106: - fillmodeTile = data; - break; - - case 0x5107: - fillmodeColor = data & 3; - fillmodeColor |= fillmodeColor << 2; - fillmodeColor |= fillmodeColor << 4; - break; - - case 0x5113: - ramSelect = data & 0x04; - ramBank = data & 0x03; - break; - - case 0x5114: prgBank[0] = data; break; - case 0x5115: prgBank[1] = data; break; - case 0x5116: prgBank[2] = data; break; - case 0x5117: prgBank[3] = data | 0x80; break; - - case 0x5120: chrSpriteBank[0] = (chrBankHi << 8) | data; chrActive = 0; break; - case 0x5121: chrSpriteBank[1] = (chrBankHi << 8) | data; chrActive = 0; break; - case 0x5122: chrSpriteBank[2] = (chrBankHi << 8) | data; chrActive = 0; break; - case 0x5123: chrSpriteBank[3] = (chrBankHi << 8) | data; chrActive = 0; break; - case 0x5124: chrSpriteBank[4] = (chrBankHi << 8) | data; chrActive = 0; break; - case 0x5125: chrSpriteBank[5] = (chrBankHi << 8) | data; chrActive = 0; break; - case 0x5126: chrSpriteBank[6] = (chrBankHi << 8) | data; chrActive = 0; break; - case 0x5127: chrSpriteBank[7] = (chrBankHi << 8) | data; chrActive = 0; break; - - case 0x5128: chrBGBank[0] = (chrBankHi << 8) | data; chrActive = 1; break; - case 0x5129: chrBGBank[1] = (chrBankHi << 8) | data; chrActive = 1; break; - case 0x512a: chrBGBank[2] = (chrBankHi << 8) | data; chrActive = 1; break; - case 0x512b: chrBGBank[3] = (chrBankHi << 8) | data; chrActive = 1; break; - - case 0x5130: - chrBankHi = data & 3; - break; - - case 0x5200: - vsEnable = data & 0x80; - vsSide = data & 0x40; - vsTile = data & 0x1f; - break; - - case 0x5201: - vsScroll = data; - break; - - case 0x5202: - vsBank = data; - break; - - case 0x5203: - irqLine = data; - break; - - case 0x5204: - irqEnable = data & 0x80; - break; - - case 0x5205: - multiplicand = data; - break; - - case 0x5206: - multiplier = data; - break; - } - } - - auto chrSpriteAddr(uint addr) -> uint { - if(chrMode == 0) { - auto bank = chrSpriteBank[7]; - return (bank * 0x2000) + (addr & 0x1fff); - } - - if(chrMode == 1) { - auto bank = chrSpriteBank[(addr / 0x1000) * 4 + 3]; - return (bank * 0x1000) + (addr & 0x0fff); - } - - if(chrMode == 2) { - auto bank = chrSpriteBank[(addr / 0x0800) * 2 + 1]; - return (bank * 0x0800) + (addr & 0x07ff); - } - - if(chrMode == 3) { - auto bank = chrSpriteBank[(addr / 0x0400)]; - return (bank * 0x0400) + (addr & 0x03ff); - } - - unreachable; - } - - auto chrBGAddr(uint addr) -> uint { - addr &= 0x0fff; - - if(chrMode == 0) { - auto bank = chrBGBank[3]; - return (bank * 0x2000) + (addr & 0x0fff); - } - - if(chrMode == 1) { - auto bank = chrBGBank[3]; - return (bank * 0x1000) + (addr & 0x0fff); - } - - if(chrMode == 2) { - auto bank = chrBGBank[(addr / 0x0800) * 2 + 1]; - return (bank * 0x0800) + (addr & 0x07ff); - } - - if(chrMode == 3) { - auto bank = chrBGBank[(addr / 0x0400)]; - return (bank * 0x0400) + (addr & 0x03ff); - } - - unreachable; - } - - auto chrVSAddr(uint addr) -> uint { - return (vsBank * 0x1000) + (addr & 0x0ff8) + (vsVpos & 7); - } - - auto blank() -> void { - inFrame = false; - } - - auto scanline() -> void { - hcounter = 0; - - if(inFrame == false) { - inFrame = true; - irqPending = false; - vcounter = 0; - } else { - if(vcounter == irqLine) irqPending = true; - vcounter++; - } - - cpuCycleCounter = 0; - } - - auto readCIRAM(uint addr) -> uint8 { - if(vsFetch && (hcounter & 2) == 0) return exram[vsVpos / 8 * 32 + vsHpos / 8]; - if(vsFetch && (hcounter & 2) != 0) return exram[vsVpos / 32 * 8 + vsHpos / 32 + 0x03c0]; - - switch(nametableMode[(addr >> 10) & 3]) { - case 0: return ppu.readCIRAM(0x0000 | (addr & 0x03ff)); - case 1: return ppu.readCIRAM(0x0400 | (addr & 0x03ff)); - case 2: return exramMode < 2 ? exram[addr & 0x03ff] : (uint8)0x00; - case 3: return (hcounter & 2) == 0 ? fillmodeTile : fillmodeColor; - } - unreachable; - } - - auto readCHR(uint addr) -> uint8 { - chrAccess[0] = chrAccess[1]; - chrAccess[1] = chrAccess[2]; - chrAccess[2] = chrAccess[3]; - chrAccess[3] = addr; - - //detect two unused nametable fetches at end of each scanline - if((chrAccess[0] & 0x2000) == 0 - && (chrAccess[1] & 0x2000) - && (chrAccess[2] & 0x2000) - && (chrAccess[3] & 0x2000)) scanline(); - - if(inFrame == false) { - vsFetch = false; - if(addr & 0x2000) return readCIRAM(addr); - return board.chrrom.read(chrActive ? chrBGAddr(addr) : chrSpriteAddr(addr)); - } - - bool bgFetch = (hcounter < 256 || hcounter >= 320); - uint8 result = 0x00; - - if((hcounter & 7) == 0) { - vsHpos = hcounter >= 320 ? hcounter - 320 : hcounter + 16; - vsVpos = vcounter + vsScroll; - vsFetch = vsEnable && bgFetch && exramMode < 2 - && (vsSide ? vsHpos / 8 >= vsTile : vsHpos / 8 < vsTile); - if(vsVpos >= 240) vsVpos -= 240; - - result = readCIRAM(addr); - - exbank = (chrBankHi << 6) | (exram[addr & 0x03ff] & 0x3f); - exattr = exram[addr & 0x03ff] >> 6; - exattr |= exattr << 2; - exattr |= exattr << 4; - } else if((hcounter & 7) == 2) { - result = readCIRAM(addr); - if(bgFetch && exramMode == 1) result = exattr; - } else { - if(vsFetch) result = board.chrrom.read(chrVSAddr(addr)); - else if(sprite8x16 ? bgFetch : chrActive) result = board.chrrom.read(chrBGAddr(addr)); - else result = board.chrrom.read(chrSpriteAddr(addr)); - if(bgFetch && exramMode == 1) result = board.chrrom.read(exbank * 0x1000 + (addr & 0x0fff)); - } - - hcounter += 2; - return result; - } - - auto writeCHR(uint addr, uint8 data) -> void { - if(addr & 0x2000) { - switch(nametableMode[(addr >> 10) & 3]) { - case 0: return ppu.writeCIRAM(0x0000 | (addr & 0x03ff), data); - case 1: return ppu.writeCIRAM(0x0400 | (addr & 0x03ff), data); - case 2: exram[addr & 0x03ff] = data; break; - } - } - } - - auto power() -> void { - for(auto& n : exram) n = 0xff; - - prgMode = 3; - chrMode = 0; - for(auto& n : prgramWriteProtect) n = 0; - exramMode = 0; - for(auto& n : nametableMode) n = 0; - fillmodeTile = 0; - fillmodeColor = 0; - ramSelect = 0; - ramBank = 0; - prgBank[0] = 0x00; - prgBank[1] = 0x00; - prgBank[2] = 0x00; - prgBank[3] = 0xff; - for(auto& n : chrSpriteBank) n = 0; - for(auto& n : chrBGBank) n = 0; - chrBankHi = 0; - vsEnable = 0; - vsSide = 0; - vsTile = 0; - vsScroll = 0; - vsBank = 0; - irqLine = 0; - irqEnable = 0; - multiplicand = 0; - multiplier = 0; - - cpuCycleCounter = 0; - irqCounter = 0; - irqPending = 0; - inFrame = 0; - vcounter = 0; - hcounter = 0; - for(auto& n : chrAccess) n = 0; - chrActive = 0; - sprite8x16 = 0; - - exbank = 0; - exattr = 0; - - vsFetch = 0; - vsVpos = 0; - vsHpos = 0; - } - - auto serialize(serializer& s) -> void { - s.array(exram); - - s.integer(prgMode); - s.integer(chrMode); - for(auto& n : prgramWriteProtect) s.integer(n); - s.integer(exramMode); - for(auto& n : nametableMode) s.integer(n); - s.integer(fillmodeTile); - s.integer(fillmodeColor); - s.integer(ramSelect); - s.integer(ramBank); - for(auto& n : prgBank) s.integer(n); - for(auto& n : chrSpriteBank) s.integer(n); - for(auto& n : chrBGBank) s.integer(n); - s.integer(chrBankHi); - s.integer(vsEnable); - s.integer(vsSide); - s.integer(vsTile); - s.integer(vsScroll); - s.integer(vsBank); - s.integer(irqLine); - s.integer(irqEnable); - s.integer(multiplicand); - s.integer(multiplier); - - s.integer(cpuCycleCounter); - s.integer(irqCounter); - s.integer(irqPending); - s.integer(inFrame); - - s.integer(vcounter); - s.integer(hcounter); - for(auto& n : chrAccess) s.integer(n); - s.integer(chrActive); - s.integer(sprite8x16); - - s.integer(exbank); - s.integer(exattr); - - s.integer(vsFetch); - s.integer(vsVpos); - s.integer(vsHpos); - } - - enum class Revision : uint { - MMC5, - MMC5B, - } revision; - - uint8 exram[1024]; - - //programmable registers - - uint2 prgMode; //$5100 - uint2 chrMode; //$5101 - - uint2 prgramWriteProtect[2]; //$5102,$5103 - - uint2 exramMode; //$5104 - uint2 nametableMode[4]; //$5105 - uint8 fillmodeTile; //$5106 - uint8 fillmodeColor; //$5107 - - bool ramSelect; //$5113 - uint2 ramBank; //$5113 - uint8 prgBank[4]; //$5114-5117 - uint10 chrSpriteBank[8]; //$5120-5127 - uint10 chrBGBank[4]; //$5128-512b - uint2 chrBankHi; //$5130 - - bool vsEnable; //$5200 - bool vsSide; //$5200 - uint5 vsTile; //$5200 - uint8 vsScroll; //$5201 - uint8 vsBank; //$5202 - - uint8 irqLine; //$5203 - bool irqEnable; //$5204 - - uint8 multiplicand; //$5205 - uint8 multiplier; //$5206 - - //status registers - - uint cpuCycleCounter; - uint irqCounter; - bool irqPending; - bool inFrame; - - uint vcounter; - uint hcounter; - uint16 chrAccess[4]; - bool chrActive; - bool sprite8x16; - - uint8 exbank; - uint8 exattr; - - bool vsFetch; - uint8 vsVpos; - uint8 vsHpos; -}; diff --git a/higan/fc/cartridge/chip/mmc6.cpp b/higan/fc/cartridge/chip/mmc6.cpp deleted file mode 100644 index 4aa76456..00000000 --- a/higan/fc/cartridge/chip/mmc6.cpp +++ /dev/null @@ -1,192 +0,0 @@ -struct MMC6 : Chip { - MMC6(Board& board) : Chip(board) { - } - - auto main() -> void { - if(irqDelay) irqDelay--; - cpu.irqLine(irqLine); - tick(); - } - - auto irqTest(uint addr) -> void { - if(!(chrAbus & 0x1000) && (addr & 0x1000)) { - if(irqDelay == 0) { - if(irqCounter == 0) { - irqCounter = irqLatch; - } else if(--irqCounter == 0) { - if(irqEnable) irqLine = 1; - } - } - irqDelay = 6; - } - chrAbus = addr; - } - - auto addrPRG(uint addr) const -> uint { - switch((addr >> 13) & 3) { - case 0: - if(prgMode == 1) return (0x3e << 13) | (addr & 0x1fff); - return (prgBank[0] << 13) | (addr & 0x1fff); - case 1: - return (prgBank[1] << 13) | (addr & 0x1fff); - case 2: - if(prgMode == 0) return (0x3e << 13) | (addr & 0x1fff); - return (prgBank[0] << 13) | (addr & 0x1fff); - case 3: - return (0x3f << 13) | (addr & 0x1fff); - } - unreachable; - } - - auto addrCHR(uint addr) const -> uint { - if(chrMode == 0) { - if(addr <= 0x07ff) return (chrBank[0] << 10) | (addr & 0x07ff); - if(addr <= 0x0fff) return (chrBank[1] << 10) | (addr & 0x07ff); - if(addr <= 0x13ff) return (chrBank[2] << 10) | (addr & 0x03ff); - if(addr <= 0x17ff) return (chrBank[3] << 10) | (addr & 0x03ff); - if(addr <= 0x1bff) return (chrBank[4] << 10) | (addr & 0x03ff); - if(addr <= 0x1fff) return (chrBank[5] << 10) | (addr & 0x03ff); - } else { - if(addr <= 0x03ff) return (chrBank[2] << 10) | (addr & 0x03ff); - if(addr <= 0x07ff) return (chrBank[3] << 10) | (addr & 0x03ff); - if(addr <= 0x0bff) return (chrBank[4] << 10) | (addr & 0x03ff); - if(addr <= 0x0fff) return (chrBank[5] << 10) | (addr & 0x03ff); - if(addr <= 0x17ff) return (chrBank[0] << 10) | (addr & 0x07ff); - if(addr <= 0x1fff) return (chrBank[1] << 10) | (addr & 0x07ff); - } - return 0; - } - - auto addrCIRAM(uint addr) const -> uint { - if(mirror == 0) return ((addr & 0x0400) >> 0) | (addr & 0x03ff); - if(mirror == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff); - unreachable; - } - - auto readRAM(uint addr) -> uint8 { - if(ramEnable == false) return cpu.mdr(); - if(ramReadable[0] == false && ramReadable[1] == false) return cpu.mdr(); - bool region = addr & 0x0200; - if(ramReadable[region] == false) return 0x00; - return board.prgram.read((region * 0x0200) + (addr & 0x01ff)); - } - - auto writeRAM(uint addr, uint8 data) -> void { - if(ramEnable == false) return; - bool region = addr & 0x0200; - if(ramWritable[region] == false) return; - return board.prgram.write((region * 0x0200) + (addr & 0x01ff), data); - } - - auto writeIO(uint addr, uint8 data) -> void { - switch(addr & 0xe001) { - case 0x8000: - chrMode = data & 0x80; - prgMode = data & 0x40; - ramEnable = data & 0x20; - bankSelect = data & 0x07; - if(ramEnable == false) { - for(auto &n : ramReadable) n = false; - for(auto &n : ramWritable) n = false; - } - break; - - case 0x8001: - switch(bankSelect) { - case 0: chrBank[0] = data & ~1; break; - case 1: chrBank[1] = data & ~1; break; - case 2: chrBank[2] = data; break; - case 3: chrBank[3] = data; break; - case 4: chrBank[4] = data; break; - case 5: chrBank[5] = data; break; - case 6: prgBank[0] = data & 0x3f; break; - case 7: prgBank[1] = data & 0x3f; break; - } - break; - - case 0xa000: - mirror = data & 0x01; - break; - - case 0xa001: - if(ramEnable == false) break; - ramReadable[1] = data & 0x80; - ramWritable[1] = data & 0x40; - ramReadable[0] = data & 0x20; - ramWritable[0] = data & 0x10; - break; - - case 0xc000: - irqLatch = data; - break; - - case 0xc001: - irqCounter = 0; - break; - - case 0xe000: - irqEnable = false; - irqLine = 0; - break; - - case 0xe001: - irqEnable = true; - break; - } - } - - auto power() -> void { - chrMode = 0; - prgMode = 0; - ramEnable = 0; - bankSelect = 0; - for(auto& n : prgBank) n = 0; - for(auto& n : chrBank) n = 0; - mirror = 0; - for(auto& n : ramReadable) n = 0; - for(auto& n : ramWritable) n = 0; - irqLatch = 0; - irqCounter = 0; - irqEnable = 0; - irqDelay = 0; - irqLine = 0; - - chrAbus = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(chrMode); - s.integer(prgMode); - s.integer(ramEnable); - s.integer(bankSelect); - for(auto& n : prgBank) s.integer(n); - for(auto& n : chrBank) s.integer(n); - s.integer(mirror); - for(auto& n : ramReadable) s.integer(n); - for(auto& n : ramWritable) s.integer(n); - s.integer(irqLatch); - s.integer(irqCounter); - s.integer(irqEnable); - s.integer(irqDelay); - s.integer(irqLine); - - s.integer(chrAbus); - } - - bool chrMode; - bool prgMode; - bool ramEnable; - uint3 bankSelect; - uint8 prgBank[2]; - uint8 chrBank[6]; - bool mirror; - bool ramReadable[2]; - bool ramWritable[2]; - uint8 irqLatch; - uint8 irqCounter; - bool irqEnable; - uint irqDelay; - bool irqLine; - - uint16 chrAbus; -}; diff --git a/higan/fc/cartridge/chip/vrc1.cpp b/higan/fc/cartridge/chip/vrc1.cpp deleted file mode 100644 index 7e1ca3b6..00000000 --- a/higan/fc/cartridge/chip/vrc1.cpp +++ /dev/null @@ -1,75 +0,0 @@ -struct VRC1 : Chip { - VRC1(Board& board) : Chip(board) { - } - - auto addrPRG(uint addr) const -> uint { - uint bank = 0x0f; - if((addr & 0xe000) == 0x8000) bank = prgBank[0]; - if((addr & 0xe000) == 0xa000) bank = prgBank[1]; - if((addr & 0xe000) == 0xc000) bank = prgBank[2]; - return (bank * 0x2000) + (addr & 0x1fff); - } - - auto addrCHR(uint addr) const -> uint { - uint bank = chrBankLo[(bool)(addr & 0x1000)]; - bank |= chrBankHi[(bool)(addr & 0x1000)] << 4; - return (bank * 0x1000) + (addr & 0x0fff); - } - - auto addrCIRAM(uint addr) const -> uint { - switch(mirror) { - case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring - case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring - } - throw; - } - - auto writeIO(uint addr, uint8 data) -> void { - switch(addr & 0xf000) { - case 0x8000: - prgBank[0] = data & 0x0f; - break; - - case 0x9000: - chrBankHi[1] = data & 0x04; - chrBankHi[0] = data & 0x02; - mirror = data & 0x01; - break; - - case 0xa000: - prgBank[1] = data & 0x0f; - break; - - case 0xc000: - prgBank[2] = data & 0x0f; - break; - - case 0xe000: - chrBankLo[0] = data & 0x0f; - break; - - case 0xf000: - chrBankLo[1] = data & 0x0f; - break; - } - } - - auto power() -> void { - for(auto& n : prgBank) n = 0; - for(auto& n : chrBankLo) n = 0; - for(auto& n : chrBankHi) n = 0; - mirror = 0; - } - - auto serialize(serializer& s) -> void { - for(auto& n : prgBank) s.integer(n); - for(auto& n : chrBankLo) s.integer(n); - for(auto& n : chrBankHi) s.integer(n); - s.integer(mirror); - } - - uint4 prgBank[3]; - uint4 chrBankLo[2]; - bool chrBankHi[2]; - bool mirror; -}; diff --git a/higan/fc/cartridge/chip/vrc2.cpp b/higan/fc/cartridge/chip/vrc2.cpp deleted file mode 100644 index 85ea6914..00000000 --- a/higan/fc/cartridge/chip/vrc2.cpp +++ /dev/null @@ -1,105 +0,0 @@ -struct VRC2 : Chip { - VRC2(Board& board) : Chip(board) { - } - - auto addrPRG(uint addr) const -> uint { - uint bank; - switch(addr & 0xe000) { - case 0x8000: bank = prgBank[0]; break; - case 0xa000: bank = prgBank[1]; break; - case 0xc000: bank = 0x1e; break; - case 0xe000: bank = 0x1f; break; - } - return (bank * 0x2000) + (addr & 0x1fff); - } - - auto addrCHR(uint addr) const -> uint { - uint bank = chrBank[addr / 0x0400]; - return (bank * 0x0400) + (addr & 0x03ff); - } - - auto addrCIRAM(uint addr) const -> uint { - switch(mirror) { - case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring - case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring - case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) - case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) - } - throw; - } - - auto readRAM(uint addr) -> uint8 { - if(board.prgram.size == 0) { - if((addr & 0xf000) == 0x6000) return cpu.mdr() | latch; - return cpu.mdr(); - } - return board.prgram.read(addr & 0x1fff); - } - - auto writeRAM(uint addr, uint8 data) -> void { - if(board.prgram.size == 0) { - if((addr & 0xf000) == 0x6000) latch = data & 0x01; - return; - } - return board.prgram.write(addr & 0x1fff, data); - } - - auto writeIO(uint addr, uint8 data) -> void { - switch(addr) { - case 0x8000: case 0x8001: case 0x8002: case 0x8003: - prgBank[0] = data & 0x1f; - break; - - case 0x9000: case 0x9001: case 0x9002: case 0x9003: - mirror = data & 0x03; - break; - - case 0xa000: case 0xa001: case 0xa002: case 0xa003: - prgBank[1] = data & 0x1f; - break; - - case 0xb000: chrBank[0] = (chrBank[0] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xb001: chrBank[0] = (chrBank[0] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xb002: chrBank[1] = (chrBank[1] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xb003: chrBank[1] = (chrBank[1] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xc000: chrBank[2] = (chrBank[2] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xc001: chrBank[2] = (chrBank[2] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xc002: chrBank[3] = (chrBank[3] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xc003: chrBank[3] = (chrBank[3] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xd000: chrBank[4] = (chrBank[4] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xd001: chrBank[4] = (chrBank[4] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xd002: chrBank[5] = (chrBank[5] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xd003: chrBank[5] = (chrBank[5] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xe000: chrBank[6] = (chrBank[6] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xe001: chrBank[6] = (chrBank[6] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xe002: chrBank[7] = (chrBank[7] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xe003: chrBank[7] = (chrBank[7] & 0x0f) | ((data & 0x0f) << 4); break; - } - } - - auto power() -> void { - for(auto& n : prgBank) n = 0; - for(auto& n : chrBank) n = 0; - mirror = 0; - latch = 0; - } - - auto serialize(serializer& s) -> void { - for(auto& n : prgBank) s.integer(n); - for(auto& n : chrBank) s.integer(n); - s.integer(mirror); - s.integer(latch); - } - - uint5 prgBank[2]; - uint8 chrBank[8]; - uint2 mirror; - bool latch; -}; diff --git a/higan/fc/cartridge/chip/vrc3.cpp b/higan/fc/cartridge/chip/vrc3.cpp deleted file mode 100644 index 81e0a68b..00000000 --- a/higan/fc/cartridge/chip/vrc3.cpp +++ /dev/null @@ -1,89 +0,0 @@ -struct VRC3 : Chip { - VRC3(Board& board) : Chip(board) { - } - - auto main() -> void { - if(irqEnable) { - if(irqMode == 0) { //16-bit - if(++irqCounter.w == 0) { - irqLine = 1; - irqEnable = irqAcknowledge; - irqCounter.w = irqLatch; - } - } - if(irqMode == 1) { //8-bit - if(++irqCounter.l == 0) { - irqLine = 1; - irqEnable = irqAcknowledge; - irqCounter.l = irqLatch; - } - } - } - - cpu.irqLine(irqLine); - tick(); - } - - auto addrPRG(uint addr) const -> uint { - uint bank = (addr < 0xc000 ? (uint)prgBank : 0x0f); - return (bank * 0x4000) + (addr & 0x3fff); - } - - auto writeIO(uint addr, uint8 data) -> void { - switch(addr & 0xf000) { - case 0x8000: irqLatch = (irqLatch & 0xfff0) | ((data & 0x0f) << 0); break; - case 0x9000: irqLatch = (irqLatch & 0xff0f) | ((data & 0x0f) << 4); break; - case 0xa000: irqLatch = (irqLatch & 0xf0ff) | ((data & 0x0f) << 8); break; - case 0xb000: irqLatch = (irqLatch & 0x0fff) | ((data & 0x0f) << 12); break; - - case 0xc000: - irqMode = data & 0x04; - irqEnable = data & 0x02; - irqAcknowledge = data & 0x01; - if(irqEnable) irqCounter.w = irqLatch; - break; - - case 0xd000: - irqLine = 0; - irqEnable = irqAcknowledge; - break; - - case 0xf000: - prgBank = data & 0x0f; - break; - } - } - - auto power() -> void { - prgBank = 0; - irqMode = 0; - irqEnable = 0; - irqAcknowledge = 0; - irqLatch = 0; - irqCounter.w = 0; - irqLine = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(prgBank); - s.integer(irqMode); - s.integer(irqEnable); - s.integer(irqAcknowledge); - s.integer(irqLatch); - s.integer(irqCounter.w); - s.integer(irqLine); - } - - uint4 prgBank; - bool irqMode; - bool irqEnable; - bool irqAcknowledge; - uint16 irqLatch; - struct { - union { - uint16_t w; - struct { uint8_t order_lsb2(l, h); }; - }; - } irqCounter; - bool irqLine; -}; diff --git a/higan/fc/cartridge/chip/vrc4.cpp b/higan/fc/cartridge/chip/vrc4.cpp deleted file mode 100644 index fba7b431..00000000 --- a/higan/fc/cartridge/chip/vrc4.cpp +++ /dev/null @@ -1,173 +0,0 @@ -struct VRC4 : Chip { - VRC4(Board& board) : Chip(board) { - } - - auto main() -> void { - if(irqEnable) { - if(irqMode == 0) { - irqScalar -= 3; - if(irqScalar <= 0) { - irqScalar += 341; - if(irqCounter == 0xff) { - irqCounter = irqLatch; - irqLine = 1; - } else { - irqCounter++; - } - } - } - - if(irqMode == 1) { - if(irqCounter == 0xff) { - irqCounter = irqLatch; - irqLine = 1; - } else { - irqCounter++; - } - } - } - - cpu.irqLine(irqLine); - tick(); - } - - auto addrPRG(uint addr) const -> uint { - uint bank = 0, banks = board.prgrom.size / 0x2000; - switch(addr & 0xe000) { - case 0x8000: bank = prgMode == 0 ? (uint)prgBank[0] : banks - 2; break; - case 0xa000: bank = prgBank[1]; break; - case 0xc000: bank = prgMode == 0 ? banks - 2 : (uint)prgBank[0]; break; - case 0xe000: bank = banks - 1; break; - } - return (bank * 0x2000) + (addr & 0x1fff); - } - - auto addrCHR(uint addr) const -> uint { - uint bank = chrBank[addr / 0x0400]; - return (bank * 0x0400) + (addr & 0x03ff); - } - - auto addrCIRAM(uint addr) const -> uint { - switch(mirror) { - case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring - case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring - case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) - case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) - } - throw; - } - - auto writeIO(uint addr, uint8 data) -> void { - switch(addr) { - case 0x8000: case 0x8001: case 0x8002: case 0x8003: - prgBank[0] = data & 0x1f; - break; - - case 0x9000: case 0x9001: - mirror = data & 0x03; - break; - - case 0x9002: case 0x9003: - prgMode = data & 0x02; - break; - - case 0xa000: case 0xa001: case 0xa002: case 0xa003: - prgBank[1] = data & 0x1f; - break; - - case 0xb000: chrBank[0] = (chrBank[0] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xb001: chrBank[0] = (chrBank[0] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xb002: chrBank[1] = (chrBank[1] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xb003: chrBank[1] = (chrBank[1] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xc000: chrBank[2] = (chrBank[2] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xc001: chrBank[2] = (chrBank[2] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xc002: chrBank[3] = (chrBank[3] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xc003: chrBank[3] = (chrBank[3] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xd000: chrBank[4] = (chrBank[4] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xd001: chrBank[4] = (chrBank[4] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xd002: chrBank[5] = (chrBank[5] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xd003: chrBank[5] = (chrBank[5] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xe000: chrBank[6] = (chrBank[6] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xe001: chrBank[6] = (chrBank[6] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xe002: chrBank[7] = (chrBank[7] & 0xf0) | ((data & 0x0f) << 0); break; - case 0xe003: chrBank[7] = (chrBank[7] & 0x0f) | ((data & 0x0f) << 4); break; - - case 0xf000: - irqLatch = (irqLatch & 0xf0) | ((data & 0x0f) << 0); - break; - - case 0xf001: - irqLatch = (irqLatch & 0x0f) | ((data & 0x0f) << 4); - break; - - case 0xf002: - irqMode = data & 0x04; - irqEnable = data & 0x02; - irqAcknowledge = data & 0x01; - if(irqEnable) { - irqCounter = irqLatch; - irqScalar = 341; - } - irqLine = 0; - break; - - case 0xf003: - irqEnable = irqAcknowledge; - irqLine = 0; - break; - } - } - - auto power() -> void { - prgMode = 0; - for(auto& n : prgBank) n = 0; - mirror = 0; - for(auto& n : chrBank) n = 0; - - irqLatch = 0; - irqMode = 0; - irqEnable = 0; - irqAcknowledge = 0; - - irqCounter = 0; - irqScalar = 0; - irqLine = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(prgMode); - for(auto& n : prgBank) s.integer(n); - s.integer(mirror); - for(auto& n : chrBank) s.integer(n); - - s.integer(irqLatch); - s.integer(irqMode); - s.integer(irqEnable); - s.integer(irqAcknowledge); - - s.integer(irqCounter); - s.integer(irqScalar); - s.integer(irqLine); - } - - bool prgMode; - uint5 prgBank[2]; - uint2 mirror; - uint8 chrBank[8]; - - uint8 irqLatch; - bool irqMode; - bool irqEnable; - bool irqAcknowledge; - - uint8 irqCounter; - int irqScalar; - bool irqLine; -}; diff --git a/higan/fc/cartridge/chip/vrc6.cpp b/higan/fc/cartridge/chip/vrc6.cpp deleted file mode 100644 index 4cdd8760..00000000 --- a/higan/fc/cartridge/chip/vrc6.cpp +++ /dev/null @@ -1,312 +0,0 @@ -struct VRC6 : Chip { - VRC6(Board& board) : Chip(board) { - } - - struct Pulse { - auto clock() -> void { - if(--divider == 0) { - divider = frequency + 1; - cycle++; - output = (mode == 1 || cycle > duty) ? volume : (uint4)0; - } - - if(enable == false) output = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(mode); - s.integer(duty); - s.integer(volume); - s.integer(enable); - s.integer(frequency); - - s.integer(divider); - s.integer(cycle); - s.integer(output); - } - - bool mode; - uint3 duty; - uint4 volume; - bool enable; - uint12 frequency; - - uint12 divider; - uint4 cycle; - uint4 output; - } pulse1, pulse2; - - struct Sawtooth { - auto clock() -> void { - if(--divider == 0) { - divider = frequency + 1; - if(++phase == 0) { - accumulator += rate; - if(++stage == 7) { - stage = 0; - accumulator = 0; - } - } - } - - output = accumulator >> 3; - if(enable == false) output = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(rate); - s.integer(enable); - s.integer(frequency); - - s.integer(divider); - s.integer(phase); - s.integer(stage); - s.integer(accumulator); - s.integer(output); - } - - uint6 rate; - bool enable; - uint12 frequency; - - uint12 divider; - uint1 phase; - uint3 stage; - uint8 accumulator; - uint5 output; - } sawtooth; - - auto main() -> void { - if(irqEnable) { - if(irqMode == 0) { - irqScalar -= 3; - if(irqScalar <= 0) { - irqScalar += 341; - if(irqCounter == 0xff) { - irqCounter = irqLatch; - irqLine = 1; - } else { - irqCounter++; - } - } - } - - if(irqMode == 1) { - if(irqCounter == 0xff) { - irqCounter = irqLatch; - irqLine = 1; - } else { - irqCounter++; - } - } - } - cpu.irqLine(irqLine); - - pulse1.clock(); - pulse2.clock(); - sawtooth.clock(); - int output = (pulse1.output + pulse2.output + sawtooth.output) << 7; - apu.setSample(-output); - - tick(); - } - - auto addrPRG(uint addr) const -> uint { - if((addr & 0xc000) == 0x8000) return (prgBank[0] << 14) | (addr & 0x3fff); - if((addr & 0xe000) == 0xc000) return (prgBank[1] << 13) | (addr & 0x1fff); - if((addr & 0xe000) == 0xe000) return ( 0xff << 13) | (addr & 0x1fff); - return 0x00; - } - - auto addrCHR(uint addr) const -> uint { - uint bank = chrBank[(addr >> 10) & 7]; - return (bank << 10) | (addr & 0x03ff); - } - - auto addrCIRAM(uint addr) const -> uint { - switch(mirror) { - case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring - case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring - case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) - case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) - } - unreachable; - } - - auto readRAM(uint addr) -> uint8 { - return board.prgram.data[addr & 0x1fff]; - } - - auto writeRAM(uint addr, uint8 data) -> void { - board.prgram.data[addr & 0x1fff] = data; - } - - auto writeIO(uint addr, uint8 data) -> void { - switch(addr) { - case 0x8000: case 0x8001: case 0x8002: case 0x8003: - prgBank[0] = data; - break; - - case 0x9000: - pulse1.mode = data & 0x80; - pulse1.duty = (data & 0x70) >> 4; - pulse1.volume = data & 0x0f; - break; - - case 0x9001: - pulse1.frequency = (pulse1.frequency & 0x0f00) | ((data & 0xff) << 0); - break; - - case 0x9002: - pulse1.frequency = (pulse1.frequency & 0x00ff) | ((data & 0x0f) << 8); - pulse1.enable = data & 0x80; - break; - - case 0xa000: - pulse2.mode = data & 0x80; - pulse2.duty = (data & 0x70) >> 4; - pulse2.volume = data & 0x0f; - break; - - case 0xa001: - pulse2.frequency = (pulse2.frequency & 0x0f00) | ((data & 0xff) << 0); - break; - - case 0xa002: - pulse2.frequency = (pulse2.frequency & 0x00ff) | ((data & 0x0f) << 8); - pulse2.enable = data & 0x80; - break; - - case 0xb000: - sawtooth.rate = data & 0x3f; - break; - - case 0xb001: - sawtooth.frequency = (sawtooth.frequency & 0x0f00) | ((data & 0xff) << 0); - break; - - case 0xb002: - sawtooth.frequency = (sawtooth.frequency & 0x00ff) | ((data & 0x0f) << 8); - sawtooth.enable = data & 0x80; - break; - - case 0xb003: - mirror = (data >> 2) & 3; - break; - - case 0xc000: case 0xc001: case 0xc002: case 0xc003: - prgBank[1] = data; - break; - - case 0xd000: case 0xd001: case 0xd002: case 0xd003: - chrBank[0 + (addr & 3)] = data; - break; - - case 0xe000: case 0xe001: case 0xe002: case 0xe003: - chrBank[4 + (addr & 3)] = data; - break; - - case 0xf000: - irqLatch = data; - break; - - case 0xf001: - irqMode = data & 0x04; - irqEnable = data & 0x02; - irqAcknowledge = data & 0x01; - if(irqEnable) { - irqCounter = irqLatch; - irqScalar = 341; - } - irqLine = 0; - break; - - case 0xf002: - irqEnable = irqAcknowledge; - irqLine = 0; - break; - } - } - - auto power() -> void { - prgBank[0] = 0; - prgBank[1] = 0; - chrBank[0] = 0; - chrBank[1] = 0; - chrBank[2] = 0; - chrBank[3] = 0; - chrBank[4] = 0; - chrBank[5] = 0; - chrBank[6] = 0; - chrBank[7] = 0; - mirror = 0; - irqLatch = 0; - irqMode = 0; - irqEnable = 0; - irqAcknowledge = 0; - - irqCounter = 0; - irqScalar = 0; - irqLine = 0; - - pulse1.mode = 0; - pulse1.duty = 0; - pulse1.volume = 0; - pulse1.enable = 0; - pulse1.frequency = 0; - - pulse1.divider = 1; - pulse1.cycle = 0; - pulse1.output = 0; - - pulse2.mode = 0; - pulse2.duty = 0; - pulse2.volume = 0; - pulse2.enable = 0; - pulse2.frequency = 0; - - pulse2.divider = 1; - pulse2.cycle = 0; - pulse2.output = 0; - - sawtooth.rate = 0; - sawtooth.enable = 0; - sawtooth.frequency = 0; - - sawtooth.divider = 1; - sawtooth.phase = 0; - sawtooth.stage = 0; - sawtooth.accumulator = 0; - sawtooth.output = 0; - } - - auto serialize(serializer& s) -> void { - pulse1.serialize(s); - pulse2.serialize(s); - sawtooth.serialize(s); - - s.array(prgBank); - s.array(chrBank); - s.integer(mirror); - s.integer(irqLatch); - s.integer(irqMode); - s.integer(irqEnable); - s.integer(irqAcknowledge); - - s.integer(irqCounter); - s.integer(irqScalar); - s.integer(irqLine); - } - - uint8 prgBank[2]; - uint8 chrBank[8]; - uint2 mirror; - uint8 irqLatch; - bool irqMode; - bool irqEnable; - bool irqAcknowledge; - - uint8 irqCounter; - int irqScalar; - bool irqLine; -}; diff --git a/higan/fc/cartridge/chip/vrc7.cpp b/higan/fc/cartridge/chip/vrc7.cpp deleted file mode 100644 index 461f052f..00000000 --- a/higan/fc/cartridge/chip/vrc7.cpp +++ /dev/null @@ -1,144 +0,0 @@ -//Konami VRC7 -//Yamaha YM2413 OPLL audio - not emulated - -struct VRC7 : Chip { - VRC7(Board& board) : Chip(board) { - } - - auto main() -> void { - if(irqEnable) { - if(irqMode == 0) { - irqScalar -= 3; - if(irqScalar <= 0) { - irqScalar += 341; - if(irqCounter == 0xff) { - irqCounter = irqLatch; - irqLine = 1; - } else { - irqCounter++; - } - } - } - - if(irqMode == 1) { - if(irqCounter == 0xff) { - irqCounter = irqLatch; - irqLine = 1; - } else { - irqCounter++; - } - } - } - cpu.irqLine(irqLine); - - tick(); - } - - auto writeIO(uint addr, uint8 data) -> void { - switch(addr) { - case 0x8000: prgBank[0] = data; break; - case 0x8010: prgBank[1] = data; break; - case 0x9000: prgBank[2] = data; break; - case 0x9010: break; //APU addr port - case 0x9030: break; //APU data port - case 0xa000: chrBank[0] = data; break; - case 0xa010: chrBank[1] = data; break; - case 0xb000: chrBank[2] = data; break; - case 0xb010: chrBank[3] = data; break; - case 0xc000: chrBank[4] = data; break; - case 0xc010: chrBank[5] = data; break; - case 0xd000: chrBank[6] = data; break; - case 0xd010: chrBank[7] = data; break; - case 0xe000: mirror = data & 0x03; break; - - case 0xe010: - irqLatch = data; - break; - - case 0xf000: - irqMode = data & 0x04; - irqEnable = data & 0x02; - irqAcknowledge = data & 0x01; - if(irqEnable) { - irqCounter = irqLatch; - irqScalar = 341; - } - irqLine = 0; - break; - - case 0xf010: - irqEnable = irqAcknowledge; - irqLine = 0; - break; - } - } - - auto addrPRG(uint addr) const -> uint { - uint bank = 0; - switch(addr & 0xe000) { - case 0x8000: bank = prgBank[0]; break; - case 0xa000: bank = prgBank[1]; break; - case 0xc000: bank = prgBank[2]; break; - case 0xe000: bank = 0xff; break; - } - return (bank * 0x2000) + (addr & 0x1fff); - } - - auto addrCHR(uint addr) const -> uint { - uint bank = chrBank[addr / 0x0400]; - return (bank * 0x0400) + (addr & 0x03ff); - } - - auto addrCIRAM(uint addr) const -> uint { - switch(mirror) { - case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring - case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring - case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) - case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) - } - unreachable; - } - - auto power() -> void { - for(auto& n : prgBank) n = 0; - for(auto& n : chrBank) n = 0; - mirror = 0; - - irqLatch = 0; - irqMode = 0; - irqEnable = 0; - irqAcknowledge = 0; - - irqCounter = 0; - irqScalar = 0; - irqLine = 0; - } - - auto serialize(serializer& s) -> void { - s.array(prgBank); - s.array(chrBank); - s.integer(mirror); - - s.integer(irqLatch); - s.integer(irqMode); - s.integer(irqEnable); - s.integer(irqAcknowledge); - - s.integer(irqCounter); - s.integer(irqScalar); - s.integer(irqLine); - } - - uint8 prgBank[3]; - uint8 chrBank[8]; - uint2 mirror; - - uint8 irqLatch; - bool irqMode; - bool irqEnable; - bool irqAcknowledge; - - uint8 irqCounter; - int irqScalar; - bool irqLine; -}; diff --git a/higan/fc/cartridge/serialization.cpp b/higan/fc/cartridge/serialization.cpp deleted file mode 100644 index a74dc19e..00000000 --- a/higan/fc/cartridge/serialization.cpp +++ /dev/null @@ -1,4 +0,0 @@ -auto Cartridge::serialize(serializer& s) -> void { - Thread::serialize(s); - return board->serialize(s); -} diff --git a/higan/fc/controller/controller.cpp b/higan/fc/controller/controller.cpp deleted file mode 100644 index 05b561f9..00000000 --- a/higan/fc/controller/controller.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include - -namespace Famicom { - -ControllerPort controllerPort1; -ControllerPort controllerPort2; -#include "gamepad/gamepad.cpp" - -Controller::Controller(uint port) : port(port) { - if(!handle()) create(Controller::Enter, 1); -} - -Controller::~Controller() { - scheduler.remove(*this); -} - -auto Controller::Enter() -> void { - while(true) { - scheduler.synchronize(); - if(controllerPort1.device->active()) controllerPort1.device->main(); - if(controllerPort2.device->active()) controllerPort2.device->main(); - } -} - -auto Controller::main() -> void { - step(1); - synchronize(cpu); -} - -// - -auto ControllerPort::connect(uint deviceID) -> void { - if(!system.loaded()) return; - delete device; - - switch(deviceID) { default: - case ID::Device::None: device = new Controller(port); break; - case ID::Device::Gamepad: device = new Gamepad(port); break; - } - - cpu.peripherals.reset(); - if(auto device = controllerPort1.device) cpu.peripherals.append(device); - if(auto device = controllerPort2.device) cpu.peripherals.append(device); -} - -auto ControllerPort::power(uint port) -> void { - this->port = port; -} - -auto ControllerPort::unload() -> void { - delete device; - device = nullptr; -} - -auto ControllerPort::serialize(serializer& s) -> void { -} - -} diff --git a/higan/fc/controller/controller.hpp b/higan/fc/controller/controller.hpp deleted file mode 100644 index 7bbd8435..00000000 --- a/higan/fc/controller/controller.hpp +++ /dev/null @@ -1,45 +0,0 @@ -//Famicom controller port pinout: -// ____ -// | \ -// |(7) \ -// |(2)(1)| -// |(3)(5)| -// |(4)(6)| -// |______| -// -// pin name port1 port2 -// 1: +5v -// 2: clock $4016 read $4016.d0 write -// 3: latch $4016.d0 write $4016.d0 write -// 4: data0 $4016.d0 read $4017.d0 read -// 5: data3 $4016.d3 read $4017.d3 read -// 6: data4 $4016.d4 read $4017.d4 read -// 7: gnd - -struct Controller : Thread { - Controller(uint port); - virtual ~Controller(); - static auto Enter() -> void; - - virtual auto main() -> void; - virtual auto data() -> uint3 { return 0; } - virtual auto latch(bool data) -> void {} - - const uint port; -}; - -struct ControllerPort { - auto connect(uint deviceID) -> void; - - auto power(uint port) -> void; - auto unload() -> void; - auto serialize(serializer&) -> void; - - uint port; - Controller* device = nullptr; -}; - -extern ControllerPort controllerPort1; -extern ControllerPort controllerPort2; - -#include "gamepad/gamepad.hpp" diff --git a/higan/fc/controller/gamepad/gamepad.cpp b/higan/fc/controller/gamepad/gamepad.cpp deleted file mode 100644 index 911cfae3..00000000 --- a/higan/fc/controller/gamepad/gamepad.cpp +++ /dev/null @@ -1,36 +0,0 @@ -Gamepad::Gamepad(uint port) : Controller(port) { -} - -auto Gamepad::data() -> uint3 { - if(counter >= 8) return 1; - if(latched == 1) return platform->inputPoll(port, ID::Device::Gamepad, A); - - switch(counter++) { - case 0: return a; - case 1: return b; - case 2: return select; - case 3: return start; - case 4: return up && !down; - case 5: return down && !up; - case 6: return left && !right; - case 7: return right && !left; - } - unreachable; -} - -auto Gamepad::latch(bool data) -> void { - if(latched == data) return; - latched = data; - counter = 0; - - if(latched == 0) { - a = platform->inputPoll(port, ID::Device::Gamepad, A); - b = platform->inputPoll(port, ID::Device::Gamepad, B); - select = platform->inputPoll(port, ID::Device::Gamepad, Select); - start = platform->inputPoll(port, ID::Device::Gamepad, Start); - up = platform->inputPoll(port, ID::Device::Gamepad, Up); - down = platform->inputPoll(port, ID::Device::Gamepad, Down); - left = platform->inputPoll(port, ID::Device::Gamepad, Left); - right = platform->inputPoll(port, ID::Device::Gamepad, Right); - } -} diff --git a/higan/fc/controller/gamepad/gamepad.hpp b/higan/fc/controller/gamepad/gamepad.hpp deleted file mode 100644 index 7d0ffc4f..00000000 --- a/higan/fc/controller/gamepad/gamepad.hpp +++ /dev/null @@ -1,22 +0,0 @@ -struct Gamepad : Controller { - enum : uint { - Up, Down, Left, Right, B, A, Select, Start, - }; - - Gamepad(uint port); - auto data() -> uint3; - auto latch(bool data) -> void; - -private: - bool latched = 0; - uint counter = 0; - - bool a = 0; - bool b = 0; - bool select = 0; - bool start = 0; - bool up = 0; - bool down = 0; - bool left = 0; - bool right = 0; -}; diff --git a/higan/fc/cpu/cpu.cpp b/higan/fc/cpu/cpu.cpp deleted file mode 100644 index fa3d7502..00000000 --- a/higan/fc/cpu/cpu.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include - -namespace Famicom { - -#include "memory.cpp" -#include "timing.cpp" -#include "serialization.cpp" -CPU cpu; - -auto CPU::Enter() -> void { - while(true) scheduler.synchronize(), cpu.main(); -} - -auto CPU::main() -> void { - if(io.interruptPending) return interrupt(); - instruction(); -} - -auto CPU::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(apu); - synchronize(ppu); - synchronize(cartridge); - for(auto peripheral : peripherals) synchronize(*peripheral); -} - -auto CPU::power(bool reset) -> void { - MOS6502::BCD = 0; - MOS6502::power(); - create(CPU::Enter, system.frequency()); - - if(!reset) for(auto& data : ram) data = 0xff; - ram[0x008] = 0xf7; //todo: what is this about? - ram[0x009] = 0xef; - ram[0x00a] = 0xdf; - ram[0x00f] = 0xbf; - - r.pc.byte(0) = bus.read(0xfffc); - r.pc.byte(1) = bus.read(0xfffd); - - io = {}; -} - -} diff --git a/higan/fc/cpu/cpu.hpp b/higan/fc/cpu/cpu.hpp deleted file mode 100644 index 1f6685c5..00000000 --- a/higan/fc/cpu/cpu.hpp +++ /dev/null @@ -1,58 +0,0 @@ -struct CPU : Processor::MOS6502, Thread { - inline auto rate() const -> uint { return Region::PAL() ? 16 : 12; } - - //cpu.cpp - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - - auto power(bool reset) -> void; - - //memory.cpp - auto readRAM(uint11 addr) -> uint8; - auto writeRAM(uint11 addr, uint8 data) -> void; - - auto readIO(uint16 addr) -> uint8; - auto writeIO(uint16 addr, uint8 data) -> void; - - auto readDebugger(uint16 addr) -> uint8 override; - - auto serialize(serializer&) -> void; - - //timing.cpp - auto read(uint16 addr) -> uint8 override; - auto write(uint16 addr, uint8 data) -> void override; - auto lastCycle() -> void override; - auto nmi(uint16& vector) -> void override; - - auto oamdma() -> void; - - auto nmiLine(bool) -> void; - auto irqLine(bool) -> void; - auto apuLine(bool) -> void; - - auto rdyLine(bool) -> void; - auto rdyAddr(bool valid, uint16 value = 0) -> void; - -//protected: - vector peripherals; - - uint8 ram[0x800]; - - struct IO { - bool interruptPending = 0; - bool nmiPending = 0; - bool nmiLine = 0; - bool irqLine = 0; - bool apuLine = 0; - - bool rdyLine = 1; - bool rdyAddrValid = 0; - uint16 rdyAddrValue; - - bool oamdmaPending = 0; - uint8 oamdmaPage; - } io; -}; - -extern CPU cpu; diff --git a/higan/fc/cpu/memory.cpp b/higan/fc/cpu/memory.cpp deleted file mode 100644 index 7cc51d54..00000000 --- a/higan/fc/cpu/memory.cpp +++ /dev/null @@ -1,49 +0,0 @@ -auto CPU::readRAM(uint11 addr) -> uint8 { - return ram[addr]; -} - -auto CPU::writeRAM(uint11 addr, uint8 data) -> void { - ram[addr] = data; -} - -auto CPU::readIO(uint16 addr) -> uint8 { - switch(addr) { - - case 0x4016: { - auto data = controllerPort1.device->data(); - return (mdr() & 0xc0) | data.bit(2) << 4 | data.bit(1) << 3 | data.bit(0) << 0; - } - - case 0x4017: { - auto data = controllerPort2.device->data(); - return (mdr() & 0xc0) | data.bit(2) << 4 | data.bit(1) << 3 | data.bit(0) << 0; - } - - } - - return apu.readIO(addr); -} - -auto CPU::writeIO(uint16 addr, uint8 data) -> void { - switch(addr) { - - case 0x4014: { - io.oamdmaPage = data; - io.oamdmaPending = true; - return; - } - - case 0x4016: { - controllerPort1.device->latch(data.bit(0)); - controllerPort2.device->latch(data.bit(0)); - return; - } - - } - - return apu.writeIO(addr, data); -} - -auto CPU::readDebugger(uint16 addr) -> uint8 { - return bus.read(addr); -} diff --git a/higan/fc/cpu/serialization.cpp b/higan/fc/cpu/serialization.cpp deleted file mode 100644 index ef9ddb8b..00000000 --- a/higan/fc/cpu/serialization.cpp +++ /dev/null @@ -1,19 +0,0 @@ -auto CPU::serialize(serializer& s) -> void { - MOS6502::serialize(s); - Thread::serialize(s); - - s.array(ram); - - s.integer(io.interruptPending); - s.integer(io.nmiPending); - s.integer(io.nmiLine); - s.integer(io.irqLine); - s.integer(io.apuLine); - - s.integer(io.rdyLine); - s.integer(io.rdyAddrValid); - s.integer(io.rdyAddrValue); - - s.integer(io.oamdmaPending); - s.integer(io.oamdmaPage); -} diff --git a/higan/fc/cpu/timing.cpp b/higan/fc/cpu/timing.cpp deleted file mode 100644 index 2682c882..00000000 --- a/higan/fc/cpu/timing.cpp +++ /dev/null @@ -1,64 +0,0 @@ -auto CPU::read(uint16 addr) -> uint8 { - if(io.oamdmaPending) { - io.oamdmaPending = false; - read(addr); - oamdma(); - } - - while(io.rdyLine == 0) { - r.mdr = bus.read(io.rdyAddrValid ? io.rdyAddrValue : addr); - step(rate()); - } - - r.mdr = bus.read(addr); - step(rate()); - return r.mdr; -} - -auto CPU::write(uint16 addr, uint8 data) -> void { - bus.write(addr, r.mdr = data); - step(rate()); -} - -auto CPU::lastCycle() -> void { - io.interruptPending = ((io.irqLine | io.apuLine) & ~r.p.i) | io.nmiPending; -} - -auto CPU::nmi(uint16& vector) -> void { - if(io.nmiPending) { - io.nmiPending = false; - vector = 0xfffa; - } -} - -auto CPU::oamdma() -> void { - for(uint n : range(256)) { - uint8 data = read(io.oamdmaPage << 8 | n); - write(0x2004, data); - } -} - -auto CPU::nmiLine(bool line) -> void { - //edge-sensitive (0->1) - if(!io.nmiLine && line) io.nmiPending = true; - io.nmiLine = line; -} - -auto CPU::irqLine(bool line) -> void { - //level-sensitive - io.irqLine = line; -} - -auto CPU::apuLine(bool line) -> void { - //level-sensitive - io.apuLine = line; -} - -auto CPU::rdyLine(bool line) -> void { - io.rdyLine = line; -} - -auto CPU::rdyAddr(bool valid, uint16 value) -> void { - io.rdyAddrValid = valid; - io.rdyAddrValue = value; -} diff --git a/higan/fc/fc.hpp b/higan/fc/fc.hpp deleted file mode 100644 index 912590c4..00000000 --- a/higan/fc/fc.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -//license: GPLv3 -//started: 2011-09-05 - -#include -#include -#include -#include - -#include - -namespace Famicom { - #define platform Emulator::platform - namespace File = Emulator::File; - using Scheduler = Emulator::Scheduler; - using Cheat = Emulator::Cheat; - extern Scheduler scheduler; - extern Cheat cheat; - - struct Thread : Emulator::Thread { - auto create(auto (*entrypoint)() -> void, double frequency) -> void { - Emulator::Thread::create(entrypoint, frequency); - scheduler.append(*this); - } - - inline auto synchronize(Thread& thread) -> void { - if(clock() >= thread.clock()) scheduler.resume(thread); - } - }; - - struct Region { - static inline auto NTSCJ() -> bool; - static inline auto NTSCU() -> bool; - static inline auto PAL() -> bool; - }; - - #include - #include - #include - #include - #include - #include - #include -} - -#include diff --git a/higan/fc/interface/interface.cpp b/higan/fc/interface/interface.cpp deleted file mode 100644 index 70b80e66..00000000 --- a/higan/fc/interface/interface.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include - -namespace Famicom { - -Settings settings; - -auto Interface::information() -> Information { - Information information; - information.manufacturer = "Nintendo"; - information.name = "Famicom"; - information.extension = "fc"; - information.resettable = true; - return information; -} - -auto Interface::display() -> Display { - Display display; - display.type = Display::Type::CRT; - display.colors = 1 << 9; - display.width = 256; - display.height = 240; - display.internalWidth = 256; - display.internalHeight = 240; - display.aspectCorrection = 8.0 / 7.0; - return display; -} - -auto Interface::color(uint32 n) -> uint64 { - double saturation = 2.0; - double hue = 0.0; - double contrast = 1.0; - double brightness = 1.0; - double gamma = settings.colorEmulation ? 1.8 : 2.2; - - int color = (n & 0x0f), level = color < 0xe ? int(n >> 4 & 3) : 1; - - static const double black = 0.518, white = 1.962, attenuation = 0.746; - static const double levels[8] = { - 0.350, 0.518, 0.962, 1.550, - 1.094, 1.506, 1.962, 1.962, - }; - - double lo_and_hi[2] = { - levels[level + 4 * (color == 0x0)], - levels[level + 4 * (color < 0xd)], - }; - - double y = 0.0, i = 0.0, q = 0.0; - auto wave = [](int p, int color) { return (color + p + 8) % 12 < 6; }; - for(int p : range(12)) { - double spot = lo_and_hi[wave(p, color)]; - - if(((n & 0x040) && wave(p, 12)) - || ((n & 0x080) && wave(p, 4)) - || ((n & 0x100) && wave(p, 8)) - ) spot *= attenuation; - - double v = (spot - black) / (white - black); - - v = (v - 0.5) * contrast + 0.5; - v *= brightness / 12.0; - - y += v; - i += v * cos((Math::Pi / 6.0) * (p + hue)); - q += v * sin((Math::Pi / 6.0) * (p + hue)); - } - - i *= saturation; - q *= saturation; - - auto gammaAdjust = [=](double f) { return f < 0.0 ? 0.0 : pow(f, 2.2 / gamma); }; - uint64 r = uclamp<16>(65535.0 * gammaAdjust(y + 0.946882 * i + 0.623557 * q)); - uint64 g = uclamp<16>(65535.0 * gammaAdjust(y + -0.274788 * i + -0.635691 * q)); - uint64 b = uclamp<16>(65535.0 * gammaAdjust(y + -1.108545 * i + 1.709007 * q)); - - return r << 32 | g << 16 | b << 0; -} - -auto Interface::loaded() -> bool { - return system.loaded(); -} - -auto Interface::hashes() -> vector { - return {cartridge.hash()}; -} - -auto Interface::manifests() -> vector { - return {cartridge.manifest()}; -} - -auto Interface::titles() -> vector { - return {cartridge.title()}; -} - -auto Interface::load() -> bool { - return system.load(this); -} - -auto Interface::save() -> void { - system.save(); -} - -auto Interface::unload() -> void { - save(); - system.unload(); -} - -auto Interface::ports() -> vector { return { - {ID::Port::Controller1, "Controller Port 1"}, - {ID::Port::Controller2, "Controller Port 2"}, - {ID::Port::Expansion, "Expansion Port" }}; -} - -auto Interface::devices(uint port) -> vector { - if(port == ID::Port::Controller1) return { - {ID::Device::None, "None" }, - {ID::Device::Gamepad, "Gamepad"} - }; - - if(port == ID::Port::Controller2) return { - {ID::Device::None, "None" }, - {ID::Device::Gamepad, "Gamepad"} - }; - - if(port == ID::Port::Expansion) return { - {ID::Device::None, "None"} - }; - - return {}; -} - -auto Interface::inputs(uint device) -> vector { - using Type = Input::Type; - - if(device == ID::Device::None) return { - }; - - if(device == ID::Device::Gamepad) return { - {Type::Hat, "Up" }, - {Type::Hat, "Down" }, - {Type::Hat, "Left" }, - {Type::Hat, "Right" }, - {Type::Button, "B" }, - {Type::Button, "A" }, - {Type::Control, "Select"}, - {Type::Control, "Start" } - }; - - return {}; -} - -auto Interface::connected(uint port) -> uint { - if(port == ID::Port::Controller1) return settings.controllerPort1; - if(port == ID::Port::Controller2) return settings.controllerPort2; - if(port == ID::Port::Expansion) return settings.expansionPort; - return 0; -} - -auto Interface::connect(uint port, uint device) -> void { - if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); - if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); -} - -auto Interface::power() -> void { - system.power(/* reset = */ false); -} - -auto Interface::reset() -> void { - system.power(/* reset = */ true); -} - -auto Interface::run() -> void { - system.run(); -} - -auto Interface::serialize() -> serializer { - system.runToSave(); - return system.serialize(); -} - -auto Interface::unserialize(serializer& s) -> bool { - return system.unserialize(s); -} - -auto Interface::cheats(const vector& list) -> void { - cheat.assign(list); -} - -auto Interface::cap(const string& name) -> bool { - if(name == "Color Emulation") return true; - if(name == "Scanline Emulation") return true; - return false; -} - -auto Interface::get(const string& name) -> any { - if(name == "Color Emulation") return settings.colorEmulation; - if(name == "Scanline Emulation") return settings.scanlineEmulation; - return {}; -} - -auto Interface::set(const string& name, const any& value) -> bool { - if(name == "Color Emulation" && value.is()) { - settings.colorEmulation = value.get(); - Emulator::video.setPalette(); - return true; - } - if(name == "Scanline Emulation" && value.is()) return settings.scanlineEmulation = value.get(), true; - return false; -} - -} diff --git a/higan/fc/interface/interface.hpp b/higan/fc/interface/interface.hpp deleted file mode 100644 index d37a7d6e..00000000 --- a/higan/fc/interface/interface.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#if defined(CORE_FC) - -namespace Famicom { - -struct ID { - enum : uint { - System, - Famicom, - }; - - struct Port { enum : uint { - Controller1, - Controller2, - Expansion, - };}; - - struct Device { enum : uint { - None, - Gamepad, - };}; -}; - -struct Interface : Emulator::Interface { - auto information() -> Information override; - - auto display() -> Display override; - auto color(uint32 color) -> uint64 override; - - auto loaded() -> bool override; - auto hashes() -> vector override; - auto manifests() -> vector override; - auto titles() -> vector override; - auto load() -> bool override; - auto save() -> void override; - auto unload() -> void override; - - auto ports() -> vector override; - auto devices(uint port) -> vector override; - auto inputs(uint device) -> vector override; - - auto connected(uint port) -> uint override; - auto connect(uint port, uint device) -> void override; - auto power() -> void override; - auto reset() -> void override; - auto run() -> void override; - - auto serialize() -> serializer override; - auto unserialize(serializer&) -> bool override; - - auto cheats(const vector&) -> void override; - - auto cap(const string& name) -> bool override; - auto get(const string& name) -> any override; - auto set(const string& name, const any& value) -> bool override; -}; - -struct Settings { - bool colorEmulation = true; - bool scanlineEmulation = true; - - uint controllerPort1 = ID::Device::Gamepad; - uint controllerPort2 = ID::Device::Gamepad; - uint expansionPort = ID::Device::None; -}; - -extern Settings settings; - -} - -#endif diff --git a/higan/fc/memory/memory.cpp b/higan/fc/memory/memory.cpp deleted file mode 100644 index e2eaa4ca..00000000 --- a/higan/fc/memory/memory.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include - -namespace Famicom { - -Bus bus; - -//$0000-07ff = RAM (2KB) -//$0800-1fff = RAM (mirror) -//$2000-2007 = PPU -//$2008-3fff = PPU (mirror) -//$4000-4017 = APU + I/O -//$4018-ffff = Cartridge - -auto Bus::read(uint16 addr) -> uint8 { - uint8 data = cartridge.readPRG(addr); - if(addr <= 0x1fff) data = cpu.readRAM(addr); - else if(addr <= 0x3fff) data = ppu.readIO(addr); - else if(addr <= 0x4017) data = cpu.readIO(addr); - - if(cheat) { - if(auto result = cheat.find(addr, data)) return result(); - } - - return data; -} - -auto Bus::write(uint16 addr, uint8 data) -> void { - cartridge.writePRG(addr, data); - if(addr <= 0x1fff) return cpu.writeRAM(addr, data); - if(addr <= 0x3fff) return ppu.writeIO(addr, data); - if(addr <= 0x4017) return cpu.writeIO(addr, data); -} - -} diff --git a/higan/fc/memory/memory.hpp b/higan/fc/memory/memory.hpp deleted file mode 100644 index 5a9596a9..00000000 --- a/higan/fc/memory/memory.hpp +++ /dev/null @@ -1,6 +0,0 @@ -struct Bus { - auto read(uint16 addr) -> uint8; - auto write(uint16 addr, uint8 data) -> void; -}; - -extern Bus bus; diff --git a/higan/fc/ppu/memory.cpp b/higan/fc/ppu/memory.cpp deleted file mode 100644 index 3188b2a0..00000000 --- a/higan/fc/ppu/memory.cpp +++ /dev/null @@ -1,144 +0,0 @@ -auto PPU::readCIRAM(uint11 addr) -> uint8 { - return ciram[addr]; -} - -auto PPU::writeCIRAM(uint11 addr, uint8 data) -> void { - ciram[addr] = data; -} - -auto PPU::readCGRAM(uint5 addr) -> uint8 { - if((addr & 0x13) == 0x10) addr &= ~0x10; - uint8 data = cgram[addr]; - if(io.grayscale) data &= 0x30; - return data; -} - -auto PPU::writeCGRAM(uint5 addr, uint8 data) -> void { - if((addr & 0x13) == 0x10) addr &= ~0x10; - cgram[addr] = data; -} - -auto PPU::readIO(uint16 addr) -> uint8 { - uint8 result = 0x00; - - switch(addr.bits(0,2)) { - - //PPUSTATUS - case 2: - result |= io.mdr.bits(0,4); - result |= io.spriteOverflow << 5; - result |= io.spriteZeroHit << 6; - result |= io.nmiFlag << 7; - io.v.latch = 0; - io.nmiHold = 0; - cpu.nmiLine(io.nmiFlag = 0); - break; - - //OAMDATA - case 4: - result = oam[io.oamAddress]; - break; - - //PPUDATA - case 7: - if(enable() && (io.ly <= 240 || io.ly == 261)) return 0x00; - - addr = (uint14)io.v.address; - if(addr <= 0x1fff) { - result = io.busData; - io.busData = cartridge.readCHR(addr); - } else if(addr <= 0x3eff) { - result = io.busData; - io.busData = cartridge.readCHR(addr); - } else if(addr <= 0x3fff) { - result = readCGRAM(addr); - io.busData = cartridge.readCHR(addr); - } - io.v.address += io.vramIncrement; - break; - - } - - return result; -} - -auto PPU::writeIO(uint16 addr, uint8 data) -> void { - io.mdr = data; - - switch(addr.bits(0,2)) { - - //PPUCTRL - case 0: - io.t.nametable = data.bits(0,1); - io.vramIncrement = data.bit (2) ? 32 : 1; - io.spriteAddress = data.bit (3) ? 0x1000 : 0x0000; - io.bgAddress = data.bit (4) ? 0x1000 : 0x0000; - io.spriteHeight = data.bit (5) ? 16 : 8; - io.masterSelect = data.bit (6); - io.nmiEnable = data.bit (7); - cpu.nmiLine(io.nmiEnable && io.nmiHold && io.nmiFlag); - break; - - //PPUMASK - case 1: - io.grayscale = data.bit (0); - io.bgEdgeEnable = data.bit (1); - io.spriteEdgeEnable = data.bit (2); - io.bgEnable = data.bit (3); - io.spriteEnable = data.bit (4); - io.emphasis = data.bits(5,7); - break; - - //PPUSTATUS - case 2: - break; - - //OAMADDR - case 3: - io.oamAddress = data; - break; - - //OAMDATA - case 4: - if(io.oamAddress.bits(0,1) == 2) data.bits(2,4) = 0; //clear non-existent bits (always read back as 0) - oam[io.oamAddress++] = data; - break; - - //PPUSCROLL - case 5: - if(io.v.latch++ == 0) { - io.v.fineX = data.bits(0,2); - io.t.tileX = data.bits(3,7); - } else { - io.t.fineY = data.bits(0,2); - io.t.tileY = data.bits(3,7); - } - break; - - //PPUADDR - case 6: - if(io.v.latch++ == 0) { - io.t.addressHi = data.bits(0,5); - } else { - io.t.addressLo = data.bits(0,7); - io.v.address = io.t.address; - } - break; - - //PPUDATA - case 7: - if(enable() && (io.ly <= 240 || io.ly == 261)) return; - - addr = (uint14)io.v.address; - if(addr <= 0x1fff) { - cartridge.writeCHR(addr, data); - } else if(addr <= 0x3eff) { - cartridge.writeCHR(addr, data); - } else if(addr <= 0x3fff) { - writeCGRAM(addr, data); - } - io.v.address += io.vramIncrement; - break; - - } -} diff --git a/higan/fc/ppu/ppu.cpp b/higan/fc/ppu/ppu.cpp deleted file mode 100644 index 9d863fc5..00000000 --- a/higan/fc/ppu/ppu.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include - -namespace Famicom { - -PPU ppu; -#include "memory.cpp" -#include "render.cpp" -#include "serialization.cpp" - -auto PPU::Enter() -> void { - while(true) scheduler.synchronize(), ppu.main(); -} - -auto PPU::main() -> void { - renderScanline(); -} - -auto PPU::step(uint clocks) -> void { - uint L = vlines(); - - while(clocks--) { - if(io.ly == 240 && io.lx == 340) io.nmiHold = 1; - if(io.ly == 241 && io.lx == 0) io.nmiFlag = io.nmiHold; - if(io.ly == 241 && io.lx == 2) cpu.nmiLine(io.nmiEnable && io.nmiFlag); - - if(io.ly == L-2 && io.lx == 340) io.spriteZeroHit = 0, io.spriteOverflow = 0; - - if(io.ly == L-2 && io.lx == 340) io.nmiHold = 0; - if(io.ly == L-1 && io.lx == 0) io.nmiFlag = io.nmiHold; - if(io.ly == L-1 && io.lx == 2) cpu.nmiLine(io.nmiEnable && io.nmiFlag); - - Thread::step(rate()); - synchronize(cpu); - - io.lx++; - } -} - -auto PPU::scanline() -> void { - io.lx = 0; - if(++io.ly == vlines()) { - io.ly = 0; - frame(); - } - cartridge.scanline(io.ly); -} - -auto PPU::frame() -> void { - io.field++; - scheduler.exit(Scheduler::Event::Frame); -} - -auto PPU::refresh() -> void { - Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240); -} - -auto PPU::power(bool reset) -> void { - create(PPU::Enter, system.frequency()); - - io = {}; - latch = {}; - - if(!reset) { - for(auto& data : ciram ) data = 0; - for(auto& data : cgram ) data = 0; - for(auto& data : oam ) data = 0; - } - - for(auto& data : buffer) data = 0; -} - -} diff --git a/higan/fc/ppu/ppu.hpp b/higan/fc/ppu/ppu.hpp deleted file mode 100644 index 6c4f91ae..00000000 --- a/higan/fc/ppu/ppu.hpp +++ /dev/null @@ -1,124 +0,0 @@ -struct PPU : Thread { - inline auto rate() const -> uint { return Region::PAL() ? 5 : 4; } - inline auto vlines() const -> uint { return Region::PAL() ? 312 : 262; } - - //ppu.cpp - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - - auto scanline() -> void; - auto frame() -> void; - auto refresh() -> void; - - auto power(bool reset) -> void; - - //memory.cpp - auto readCIRAM(uint11 addr) -> uint8; - auto writeCIRAM(uint11 addr, uint8 data) -> void; - - auto readCGRAM(uint5 addr) -> uint8; - auto writeCGRAM(uint5 addr, uint8 data) -> void; - - auto readIO(uint16 addr) -> uint8; - auto writeIO(uint16 addr, uint8 data) -> void; - - //render.cpp - auto enable() const -> bool; - auto loadCHR(uint16 addr) -> uint8; - - auto renderPixel() -> void; - auto renderSprite() -> void; - auto renderScanline() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - struct IO { - //internal - uint8 mdr; - - uint1 field; - uint lx = 0; - uint ly = 0; - - uint8 busData; - - union Union { - auto& operator=(const Union& u) { value = u.value; return *this; } - uint value = 0; - NaturalBitField tileX; - NaturalBitField tileY; - NaturalBitField nametable; - NaturalBitField nametableX; - NaturalBitField nametableY; - NaturalBitField fineY; - NaturalBitField address; - NaturalBitField addressLo; - NaturalBitField addressHi; - NaturalBitField latch; - NaturalBitField fineX; - } v, t; - - bool nmiHold = 0; - bool nmiFlag = 0; - - //$2000 - uint vramIncrement = 1; - uint spriteAddress = 0; - uint bgAddress = 0; - uint spriteHeight = 0; - bool masterSelect = 0; - bool nmiEnable = 0; - - //$2001 - bool grayscale = 0; - bool bgEdgeEnable = 0; - bool spriteEdgeEnable = 0; - bool bgEnable = 0; - bool spriteEnable = 0; - uint3 emphasis; - - //$2002 - bool spriteOverflow = 0; - bool spriteZeroHit = 0; - - //$2003 - uint8 oamAddress; - } io; - - struct OAM { - //serialization.cpp - auto serialize(serializer&) -> void; - - uint8 id = 64; - uint8 y = 0xff; - uint8 tile = 0xff; - uint8 attr = 0xff; - uint8 x = 0xff; - - uint8 tiledataLo = 0; - uint8 tiledataHi = 0; - }; - - struct Latches { - uint16 nametable; - uint16 attribute; - uint16 tiledataLo; - uint16 tiledataHi; - - uint oamIterator = 0; - uint oamCounter = 0; - - OAM oam[8]; //primary - OAM soam[8]; //secondary - } latch; - - uint8 ciram[2048]; - uint8 cgram[32]; - uint8 oam[256]; - - uint32 buffer[256 * 262]; -}; - -extern PPU ppu; diff --git a/higan/fc/ppu/render.cpp b/higan/fc/ppu/render.cpp deleted file mode 100644 index f7735fd7..00000000 --- a/higan/fc/ppu/render.cpp +++ /dev/null @@ -1,211 +0,0 @@ -auto PPU::enable() const -> bool { - return io.bgEnable || io.spriteEnable; -} - -auto PPU::loadCHR(uint16 addr) -> uint8 { - return enable() ? cartridge.readCHR(addr) : (uint8)0x00; -} - -auto PPU::renderPixel() -> void { - uint32* output = buffer + io.ly * 256; - - uint x = io.lx - 1; - uint mask = 0x8000 >> (io.v.fineX + (x & 7)); - uint palette = 0; - uint objectPalette = 0; - bool objectPriority = 0; - - palette |= latch.tiledataLo & mask ? 1 : 0; - palette |= latch.tiledataHi & mask ? 2 : 0; - if(palette) { - uint attr = latch.attribute; - if(mask >= 256) attr >>= 2; - palette |= (attr & 3) << 2; - } - - if(!io.bgEnable) palette = 0; - if(!io.bgEdgeEnable && x < 8) palette = 0; - - if(io.spriteEnable) - for(int sprite = 7; sprite >= 0; sprite--) { - if(!io.spriteEdgeEnable && x < 8) continue; - if(latch.oam[sprite].id == 64) continue; - - uint spriteX = x - latch.oam[sprite].x; - if(spriteX >= 8) continue; - - if(latch.oam[sprite].attr & 0x40) spriteX ^= 7; - uint mask = 0x80 >> spriteX; - uint spritePalette = 0; - spritePalette |= latch.oam[sprite].tiledataLo & mask ? 1 : 0; - spritePalette |= latch.oam[sprite].tiledataHi & mask ? 2 : 0; - if(spritePalette == 0) continue; - - if(latch.oam[sprite].id == 0 && palette && x != 255) io.spriteZeroHit = 1; - spritePalette |= (latch.oam[sprite].attr & 3) << 2; - - objectPriority = latch.oam[sprite].attr & 0x20; - objectPalette = 16 + spritePalette; - } - - if(objectPalette) { - if(palette == 0 || objectPriority == 0) palette = objectPalette; - } - - if(!enable()) palette = 0; - output[x] = io.emphasis << 6 | readCGRAM(palette); -} - -auto PPU::renderSprite() -> void { - if(!enable()) return; - - uint n = latch.oamIterator++; - int ly = io.ly == vlines() - 1 ? -1 : io.ly; - uint y = ly - oam[n * 4 + 0]; - - if(y >= io.spriteHeight) return; - if(latch.oamCounter == 8) { - io.spriteOverflow = 1; - return; - } - - auto& o = latch.soam[latch.oamCounter++]; - o.id = n; - o.y = oam[n * 4 + 0]; - o.tile = oam[n * 4 + 1]; - o.attr = oam[n * 4 + 2]; - o.x = oam[n * 4 + 3]; -} - -auto PPU::renderScanline() -> void { - //Vblank - if(io.ly >= 240 && io.ly <= vlines() - 2) return step(341), scanline(); - - latch.oamIterator = 0; - latch.oamCounter = 0; - - for(auto n : range(8)) latch.soam[n] = {}; - - // 0 - step(1); - - // 1-256 - for(uint tile : range(32)) { - uint nametable = loadCHR(0x2000 | (uint12)io.v.address); - uint tileaddr = io.bgAddress | nametable << 4 | io.v.fineY; - renderPixel(); - step(1); - - renderPixel(); - step(1); - - uint attribute = loadCHR(0x23c0 | io.v.nametable << 10 | (io.v.tileY >> 2) << 3 | io.v.tileX >> 2); - if(io.v.tileY & 2) attribute >>= 4; - if(io.v.tileX & 2) attribute >>= 2; - renderPixel(); - step(1); - - if(enable() && ++io.v.tileX == 0) io.v.nametableX++; - if(enable() && tile == 31 && ++io.v.fineY == 0 && ++io.v.tileY == 30) io.v.nametableY++, io.v.tileY = 0; - renderPixel(); - renderSprite(); - step(1); - - uint tiledataLo = loadCHR(tileaddr + 0); - renderPixel(); - step(1); - - renderPixel(); - step(1); - - uint tiledataHi = loadCHR(tileaddr + 8); - renderPixel(); - step(1); - - renderPixel(); - renderSprite(); - step(1); - - latch.nametable = latch.nametable << 8 | nametable; - latch.attribute = latch.attribute << 2 | (attribute & 3); - latch.tiledataLo = latch.tiledataLo << 8 | tiledataLo; - latch.tiledataHi = latch.tiledataHi << 8 | tiledataHi; - } - - for(auto n : range(8)) latch.oam[n] = latch.soam[n]; - - //257-320 - for(uint sprite : range(8)) { - uint nametable = loadCHR(0x2000 | (uint12)io.v.address); - step(1); - - if(enable() && sprite == 0) { - //258 - io.v.nametableX = io.t.nametableX; - io.v.tileX = io.t.tileX; - } - step(1); - - uint attribute = loadCHR(0x23c0 | io.v.nametable << 10 | (io.v.tileY >> 2) << 3 | io.v.tileX >> 2); - uint tileaddr = io.spriteHeight == 8 - ? io.spriteAddress + latch.oam[sprite].tile * 16 - : (latch.oam[sprite].tile & ~1) * 16 + (latch.oam[sprite].tile & 1) * 0x1000; - step(2); - - uint spriteY = (io.ly - latch.oam[sprite].y) & (io.spriteHeight - 1); - if(latch.oam[sprite].attr & 0x80) spriteY ^= io.spriteHeight - 1; - tileaddr += spriteY + (spriteY & 8); - - latch.oam[sprite].tiledataLo = loadCHR(tileaddr + 0); - step(2); - - latch.oam[sprite].tiledataHi = loadCHR(tileaddr + 8); - step(2); - - if(enable() && sprite == 6 && io.ly == vlines() - 1) { - //305 - io.v.address = io.t.address; - } - } - - //321-336 - for(uint tile : range(2)) { - uint nametable = loadCHR(0x2000 | (uint12)io.v.address); - uint tileaddr = io.bgAddress | nametable << 4 | io.v.fineY; - step(2); - - uint attribute = loadCHR(0x23c0 | io.v.nametable << 10 | (io.v.tileY >> 2) << 3 | io.v.tileX >> 2); - if(io.v.tileY & 2) attribute >>= 4; - if(io.v.tileX & 2) attribute >>= 2; - step(1); - - if(enable() && ++io.v.tileX == 0) io.v.nametableX++; - step(1); - - uint tiledataLo = loadCHR(tileaddr + 0); - step(2); - - uint tiledataHi = loadCHR(tileaddr + 8); - step(2); - - latch.nametable = latch.nametable << 8 | nametable; - latch.attribute = latch.attribute << 2 | (attribute & 3); - latch.tiledataLo = latch.tiledataLo << 8 | tiledataLo; - latch.tiledataHi = latch.tiledataHi << 8 | tiledataHi; - } - - //337-338 - loadCHR(0x2000 | (uint12)io.v.address); - step(1); - bool skip = enable() && io.field == 1 && io.ly == vlines() - 1; - step(1); - - //339 - loadCHR(0x2000 | (uint12)io.v.address); - step(1); - - //340 - if(!skip) step(1); - - return scanline(); -} diff --git a/higan/fc/ppu/serialization.cpp b/higan/fc/ppu/serialization.cpp deleted file mode 100644 index 15ea30f6..00000000 --- a/higan/fc/ppu/serialization.cpp +++ /dev/null @@ -1,64 +0,0 @@ -auto PPU::serialize(serializer& s) -> void { - Thread::serialize(s); - - s.integer(io.mdr); - - s.integer(io.field); - s.integer(io.lx); - s.integer(io.ly); - - s.integer(io.busData); - - s.integer(io.v.value); - s.integer(io.t.value); - - s.integer(io.nmiHold); - s.integer(io.nmiFlag); - - s.integer(io.vramIncrement); - s.integer(io.spriteAddress); - s.integer(io.bgAddress); - s.integer(io.spriteHeight); - s.integer(io.masterSelect); - s.integer(io.nmiEnable); - - s.integer(io.grayscale); - s.integer(io.bgEdgeEnable); - s.integer(io.spriteEdgeEnable); - s.integer(io.bgEnable); - s.integer(io.spriteEnable); - s.integer(io.emphasis); - - s.integer(io.spriteOverflow); - s.integer(io.spriteZeroHit); - - s.integer(io.oamAddress); - - s.integer(latch.nametable); - s.integer(latch.attribute); - s.integer(latch.tiledataLo); - s.integer(latch.tiledataHi); - - s.integer(latch.oamIterator); - s.integer(latch.oamCounter); - - for(auto& o : latch.oam) o.serialize(s); - for(auto& o : latch.soam) o.serialize(s); - - s.array(ciram); - s.array(cgram); - s.array(oam); - - s.array(buffer); -} - -auto PPU::OAM::serialize(serializer& s) -> void { - s.integer(id); - s.integer(y); - s.integer(tile); - s.integer(attr); - s.integer(x); - - s.integer(tiledataLo); - s.integer(tiledataHi); -} diff --git a/higan/fc/system/serialization.cpp b/higan/fc/system/serialization.cpp deleted file mode 100644 index 83002044..00000000 --- a/higan/fc/system/serialization.cpp +++ /dev/null @@ -1,60 +0,0 @@ -auto System::serialize() -> serializer { - serializer s(_serializeSize); - - uint signature = 0x31545342; - char version[16] = {0}; - char description[512] = {0}; - memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size()); - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - return s; -} - -auto System::unserialize(serializer& s) -> bool { - uint signature; - char version[16]; - char description[512]; - - s.integer(signature); - s.array(version); - s.array(description); - - if(signature != 0x31545342) return false; - if(string{version} != Emulator::SerializerVersion) return false; - - power(/* reset = */ false); - serializeAll(s); - return true; -} - -auto System::serialize(serializer& s) -> void { -} - -auto System::serializeAll(serializer& s) -> void { - system.serialize(s); - cartridge.serialize(s); - cpu.serialize(s); - apu.serialize(s); - ppu.serialize(s); - controllerPort1.serialize(s); - controllerPort2.serialize(s); -} - -auto System::serializeInit() -> void { - serializer s; - - uint signature = 0; - char version[16]; - char description[512]; - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - _serializeSize = s.size(); -} diff --git a/higan/fc/system/system.cpp b/higan/fc/system/system.cpp deleted file mode 100644 index 9ebee864..00000000 --- a/higan/fc/system/system.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include - -namespace Famicom { - -#include "serialization.cpp" -System system; -Scheduler scheduler; -Cheat cheat; - -auto System::run() -> void { - if(scheduler.enter() == Scheduler::Event::Frame) ppu.refresh(); -} - -auto System::runToSave() -> void { - scheduler.synchronize(cpu); - scheduler.synchronize(apu); - scheduler.synchronize(ppu); - scheduler.synchronize(cartridge); - for(auto peripheral : cpu.peripherals) scheduler.synchronize(*peripheral); -} - -auto System::load(Emulator::Interface* interface) -> bool { - information = {}; - - if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else { - return false; - } - auto document = BML::unserialize(information.manifest); - if(!cartridge.load()) return false; - - if(cartridge.region() == "NTSC-J") { - information.region = Region::NTSCJ; - information.frequency = Emulator::Constants::Colorburst::NTSC * 6.0; - } - if(cartridge.region() == "NTSC-U") { - information.region = Region::NTSCU; - information.frequency = Emulator::Constants::Colorburst::NTSC * 6.0; - } - if(cartridge.region() == "PAL") { - information.region = Region::PAL; - information.frequency = Emulator::Constants::Colorburst::PAL * 6.0; - } - - this->interface = interface; - serializeInit(); - return information.loaded = true; -} - -auto System::save() -> void { - cartridge.save(); -} - -auto System::unload() -> void { - if(!loaded()) return; - cpu.peripherals.reset(); - controllerPort1.unload(); - controllerPort2.unload(); - cartridge.unload(); - information.loaded = false; -} - -auto System::power(bool reset) -> void { - Emulator::video.reset(interface); - Emulator::video.setPalette(); - - Emulator::audio.reset(interface); - - scheduler.reset(); - cartridge.power(); - cpu.power(reset); - apu.power(reset); - ppu.power(reset); - scheduler.primary(cpu); - - controllerPort1.power(ID::Port::Controller1); - controllerPort2.power(ID::Port::Controller2); - - controllerPort1.connect(settings.controllerPort1); - controllerPort2.connect(settings.controllerPort2); -} - -auto System::init() -> void { - assert(interface != nullptr); -} - -auto System::term() -> void { -} - -} diff --git a/higan/fc/system/system.hpp b/higan/fc/system/system.hpp deleted file mode 100644 index 689a502b..00000000 --- a/higan/fc/system/system.hpp +++ /dev/null @@ -1,44 +0,0 @@ -struct System { - enum class Region : uint { NTSCJ, NTSCU, PAL }; - - auto loaded() const -> bool { return information.loaded; } - auto region() const -> Region { return information.region; } - auto frequency() const -> double { return information.frequency; } - - auto run() -> void; - auto runToSave() -> void; - - auto load(Emulator::Interface*) -> bool; - auto save() -> void; - auto unload() -> void; - auto power(bool reset) -> void; - - auto init() -> void; - auto term() -> void; - - //serialization.cpp - auto serialize() -> serializer; - auto unserialize(serializer&) -> bool; - - auto serialize(serializer&) -> void; - auto serializeAll(serializer&) -> void; - auto serializeInit() -> void; - -private: - Emulator::Interface* interface = nullptr; - - struct Information { - bool loaded = false; - Region region = Region::NTSCJ; - double frequency = Emulator::Constants::Colorburst::NTSC * 6.0; - string manifest; - } information; - - uint _serializeSize = 0; -}; - -extern System system; - -auto Region::NTSCJ() -> bool { return system.region() == System::Region::NTSCJ; } -auto Region::NTSCU() -> bool { return system.region() == System::Region::NTSCU; } -auto Region::PAL() -> bool { return system.region() == System::Region::PAL; } diff --git a/higan/gba/GNUmakefile b/higan/gba/GNUmakefile deleted file mode 100644 index b596c14a..00000000 --- a/higan/gba/GNUmakefile +++ /dev/null @@ -1,14 +0,0 @@ -processors += arm7tdmi - -objects += gba-memory gba-interface gba-system -objects += gba-cartridge gba-player -objects += gba-cpu gba-ppu gba-apu - -obj/gba-memory.o: gba/memory/memory.cpp -obj/gba-interface.o: gba/interface/interface.cpp -obj/gba-system.o: gba/system/system.cpp -obj/gba-cartridge.o: gba/cartridge/cartridge.cpp -obj/gba-player.o: gba/player/player.cpp -obj/gba-cpu.o: gba/cpu/cpu.cpp -obj/gba-ppu.o: gba/ppu/ppu.cpp -obj/gba-apu.o: gba/apu/apu.cpp diff --git a/higan/gba/apu/apu.cpp b/higan/gba/apu/apu.cpp deleted file mode 100644 index b44b64d4..00000000 --- a/higan/gba/apu/apu.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include - -namespace GameBoyAdvance { - -APU apu; -#include "io.cpp" -#include "square.cpp" -#include "square1.cpp" -#include "square2.cpp" -#include "wave.cpp" -#include "noise.cpp" -#include "sequencer.cpp" -#include "fifo.cpp" -#include "serialization.cpp" - -auto APU::Enter() -> void { - while(true) scheduler.synchronize(), apu.main(); -} - -auto APU::main() -> void { - //GBA clock runs at 16777216hz - //GBA PSG channels run at 2097152hz - runsequencer(); - step(8); - - //audio PWM output frequency and bit-rate are dependent upon amplitude setting: - //0 = 9-bit @ 32768hz - //1 = 8-bit @ 65536hz - //2 = 7-bit @ 131072hz - //3 = 6-bit @ 262144hz - - //dynamically changing the output frequency under emulation would be difficult; - //always run the output frequency at the maximum 262144hz - if(++clock & 7) return; - - int lsample = regs.bias.level - 0x0200; - int rsample = regs.bias.level - 0x0200; - - //amplitude: 0 = 32768hz; 1 = 65536hz; 2 = 131072hz; 3 = 262144hz - if((clock & (63 >> (3 - regs.bias.amplitude))) == 0) { - sequencer.sample(); - fifo[0].sample(); - fifo[1].sample(); - } - - lsample += sequencer.loutput; - rsample += sequencer.routput; - - int fifo0 = fifo[0].output << fifo[0].volume; - int fifo1 = fifo[1].output << fifo[1].volume; - - if(fifo[0].lenable) lsample += fifo0; - if(fifo[1].lenable) lsample += fifo1; - - if(fifo[0].renable) rsample += fifo0; - if(fifo[1].renable) rsample += fifo1; - - lsample = sclamp<11>(lsample); - rsample = sclamp<11>(rsample); - - //clip 11-bit signed output to more limited output bit-rate - //note: leaving 2-bits more on output to prevent quantization noise - if(regs.bias.amplitude == 0) lsample &= ~0, rsample &= ~0; //9-bit - if(regs.bias.amplitude == 1) lsample &= ~1, rsample &= ~1; //8-bit - if(regs.bias.amplitude == 2) lsample &= ~3, rsample &= ~3; //7-bit - if(regs.bias.amplitude == 3) lsample &= ~7, rsample &= ~7; //6-bit - - if(cpu.stopped()) lsample = 0, rsample = 0; - stream->sample((lsample << 5) / 32768.0, (rsample << 5) / 32768.0); -} - -auto APU::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); -} - -auto APU::power() -> void { - create(APU::Enter, system.frequency()); - stream = Emulator::audio.createStream(2, frequency() / 64.0); - stream->addHighPassFilter(20.0, Emulator::Filter::Order::First); - stream->addDCRemovalFilter(); - - clock = 0; - square1.power(); - square2.power(); - wave.power(); - noise.power(); - sequencer.power(); - fifo[0].power(); - fifo[1].power(); - - regs.bias.amplitude = 0; - regs.bias.level = 0x200; - - for(uint n = 0x060; n <= 0x0a7; n++) bus.io[n] = this; -} - -} diff --git a/higan/gba/apu/apu.hpp b/higan/gba/apu/apu.hpp deleted file mode 100644 index ecc3b117..00000000 --- a/higan/gba/apu/apu.hpp +++ /dev/null @@ -1,178 +0,0 @@ -struct APU : Thread, IO { - shared_pointer stream; - - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - - auto readIO(uint32 addr) -> uint8; - auto writeIO(uint32 addr, uint8 byte) -> void; - auto power() -> void; - - auto runsequencer() -> void; - - auto serialize(serializer&) -> void; - - uint clock; - - struct Registers { - struct SoundBias { - uint10 level; - uint2 amplitude; - } bias; - } regs; - - struct Sweep { - uint3 shift; - uint1 direction; - uint3 frequency; - - uint1 enable; - uint1 negate; - uint3 period; - }; - - struct Envelope { - uint3 frequency; - uint1 direction; - uint4 volume; - - uint3 period; - - auto dacEnable() const -> bool { return volume || direction; } - }; - - struct Square { - Envelope envelope; - uint1 enable; - uint6 length; - uint2 duty; - uint11 frequency; - uint1 counter; - uint1 initialize; - - int shadowfrequency; - uint1 signal; - uint4 output; - uint period; - uint3 phase; - uint4 volume; - - auto run() -> void; - auto clocklength() -> void; - auto clockenvelope() -> void; - }; - - struct Square1 : Square { - Sweep sweep; - - auto runsweep(bool update) -> void; - auto clocksweep() -> void; - auto read(uint addr) const -> uint8; - auto write(uint addr, uint8 byte) -> void; - auto power() -> void; - } square1; - - struct Square2 : Square { - auto read(uint addr) const -> uint8; - auto write(uint addr, uint8 byte) -> void; - auto power() -> void; - } square2; - - struct Wave { - uint1 mode; - uint1 bank; - uint1 dacenable; - uint8 length; - uint3 volume; - uint11 frequency; - uint1 counter; - uint1 initialize; - uint4 pattern[2 * 32]; - - uint1 enable; - uint4 output; - uint5 patternaddr; - uint1 patternbank; - uint4 patternsample; - uint period; - - auto run() -> void; - auto clocklength() -> void; - auto read(uint addr) const -> uint8; - auto write(uint addr, uint8 byte) -> void; - auto readram(uint addr) const -> uint8; - auto writeram(uint addr, uint8 byte) -> void; - auto power() -> void; - } wave; - - struct Noise { - Envelope envelope; - uint6 length; - uint3 divisor; - uint1 narrowlfsr; - uint4 frequency; - uint1 counter; - uint1 initialize; - - uint1 enable; - uint15 lfsr; - uint4 output; - uint period; - uint4 volume; - - auto divider() const -> uint; - auto run() -> void; - auto clocklength() -> void; - auto clockenvelope() -> void; - auto read(uint addr) const -> uint8; - auto write(uint addr, uint8 byte) -> void; - auto power() -> void; - } noise; - - struct Sequencer { - uint2 volume; - uint3 lvolume; - uint3 rvolume; - uint1 lenable[4]; - uint1 renable[4]; - uint1 masterenable; - - uint12 base; - uint3 step; - int16 lsample; - int16 rsample; - - uint10 loutput; - uint10 routput; - - auto sample() -> void; - - auto read(uint addr) const -> uint8; - auto write(uint addr, uint8 byte) -> void; - auto power() -> void; - } sequencer; - - struct FIFO { - int8 samples[32]; - int8 active; - int8 output; - - uint5 rdoffset; - uint5 wroffset; - uint6 size; - - uint1 volume; //0 = 50%, 1 = 100% - uint1 lenable; - uint1 renable; - uint1 timer; - - auto sample() -> void; - auto read() -> void; - auto write(int8 byte) -> void; - auto reset() -> void; - auto power() -> void; - } fifo[2]; -}; - -extern APU apu; diff --git a/higan/gba/apu/fifo.cpp b/higan/gba/apu/fifo.cpp deleted file mode 100644 index 641abc3c..00000000 --- a/higan/gba/apu/fifo.cpp +++ /dev/null @@ -1,33 +0,0 @@ -auto APU::FIFO::sample() -> void { - output = active; -} - -auto APU::FIFO::read() -> void { - if(size == 0) return; - size--; - active = samples[rdoffset++]; -} - -auto APU::FIFO::write(int8 byte) -> void { - if(size == 32) rdoffset++; - else size++; - samples[wroffset++] = byte; -} - -auto APU::FIFO::reset() -> void { - for(auto& byte : samples) byte = 0; - active = 0; - output = 0; - - rdoffset = 0; - wroffset = 0; - size = 0; -} - -auto APU::FIFO::power() -> void { - reset(); - - lenable = 0; - renable = 0; - timer = 0; -} diff --git a/higan/gba/apu/io.cpp b/higan/gba/apu/io.cpp deleted file mode 100644 index 7ac42a63..00000000 --- a/higan/gba/apu/io.cpp +++ /dev/null @@ -1,263 +0,0 @@ -auto APU::readIO(uint32 addr) -> uint8 { - switch(addr) { - - //NR10 - case 0x0400'0060: return square1.read(0); - case 0x0400'0061: return 0x00; - - //NR11, NR12 - case 0x0400'0062: return square1.read(1); - case 0x0400'0063: return square1.read(2); - - //NR13, NR14 - case 0x0400'0064: return square1.read(3); - case 0x0400'0065: return square1.read(4); - - //zero - case 0x0400'0066: return 0x00; - case 0x0400'0067: return 0x00; - - //NR21, NR22 - case 0x0400'0068: return square2.read(1); - case 0x0400'0069: return square2.read(2); - - //NR23, NR24 - case 0x0400'006c: return square2.read(3); - case 0x0400'006d: return square2.read(4); - - //zero - case 0x0400'006e: return 0x00; - case 0x0400'006f: return 0x00; - - //NR30 - case 0x0400'0070: return wave.read(0); - case 0x0400'0071: return 0x00; - - //NR31, NR32 - case 0x0400'0072: return wave.read(1); - case 0x0400'0073: return wave.read(2); - - //NR33, NR34 - case 0x0400'0074: return wave.read(3); - case 0x0400'0075: return wave.read(4); - - //zero - case 0x0400'0076: return 0x00; - case 0x0400'0077: return 0x00; - - //NR41, NR42 - case 0x0400'0078: return noise.read(1); - case 0x0400'0079: return noise.read(2); - - //zero - case 0x0400'007a: return 0x00; - case 0x0400'007b: return 0x00; - - //NR43, NR44 - case 0x0400'007c: return noise.read(3); - case 0x0400'007d: return noise.read(4); - - //zero - case 0x0400'007e: return 0x00; - case 0x0400'007f: return 0x00; - - //NR50, NR51 - case 0x0400'0080: return sequencer.read(0); - case 0x0400'0081: return sequencer.read(1); - - //SOUND_CNT_H - case 0x0400'0082: return ( - sequencer.volume << 0 - | fifo[0].volume << 2 - | fifo[1].volume << 3 - ); - - case 0x0400'0083: return ( - fifo[0].renable << 0 - | fifo[0].lenable << 1 - | fifo[0].timer << 2 - | fifo[1].renable << 4 - | fifo[1].lenable << 5 - | fifo[1].timer << 6 - ); - - //NR52 - case 0x0400'0084: return sequencer.read(2); - case 0x0400'0085: return 0x00; - - //zero - case 0x0400'0086: return 0x00; - case 0x0400'0087: return 0x00; - - //SOUNDBIAS - case 0x0400'0088: return ( - regs.bias.level.bits(0,7) - ); - case 0x0400'0089: return ( - regs.bias.level.bits(8,9) << 0 - | regs.bias.amplitude << 6 - ); - - //zero - case 0x0400'008a: return 0x00; - case 0x0400'008b: return 0x00; - - //WAVE_RAM0_L - case 0x0400'0090: return wave.readram( 0); - case 0x0400'0091: return wave.readram( 1); - - //WAVE_RAM0_H - case 0x0400'0092: return wave.readram( 2); - case 0x0400'0093: return wave.readram( 3); - - //WAVE_RAM1_L - case 0x0400'0094: return wave.readram( 4); - case 0x0400'0095: return wave.readram( 5); - - //WAVE_RAM1_H - case 0x0400'0096: return wave.readram( 6); - case 0x0400'0097: return wave.readram( 7); - - //WAVE_RAM2_L - case 0x0400'0098: return wave.readram( 8); - case 0x0400'0099: return wave.readram( 9); - - //WAVE_RAM2_H - case 0x0400'009a: return wave.readram(10); - case 0x0400'009b: return wave.readram(11); - - //WAVE_RAM3_L - case 0x0400'009c: return wave.readram(12); - case 0x0400'009d: return wave.readram(13); - - //WAVE_RAM3_H - case 0x0400'009e: return wave.readram(14); - case 0x0400'009f: return wave.readram(15); - - } - - return cpu.pipeline.fetch.instruction.byte(addr & 1); -} - -auto APU::writeIO(uint32 addr, uint8 data) -> void { - switch(addr) { - - //NR10 - case 0x0400'0060: return square1.write(0, data); - case 0x0400'0061: return; - - //NR11, NR12 - case 0x0400'0062: return square1.write(1, data); - case 0x0400'0063: return square1.write(2, data); - - //NR13, NR14 - case 0x0400'0064: return square1.write(3, data); - case 0x0400'0065: return square1.write(4, data); - - //NR21, NR22 - case 0x0400'0068: return square2.write(1, data); - case 0x0400'0069: return square2.write(2, data); - - //NR23, NR24 - case 0x0400'006c: return square2.write(3, data); - case 0x0400'006d: return square2.write(4, data); - - //NR30 - case 0x0400'0070: return wave.write(0, data); - case 0x0400'0071: return; - - //NR31, NR32 - case 0x0400'0072: return wave.write(1, data); - case 0x0400'0073: return wave.write(2, data); - - //NR33, NR34 - case 0x0400'0074: return wave.write(3, data); - case 0x0400'0075: return wave.write(4, data); - - //NR41, NR42 - case 0x0400'0078: return noise.write(1, data); - case 0x0400'0079: return noise.write(2, data); - - //NR43, NR44 - case 0x0400'007c: return noise.write(3, data); - case 0x0400'007d: return noise.write(4, data); - - //NR50, NR51 - case 0x0400'0080: return sequencer.write(0, data); - case 0x0400'0081: return sequencer.write(1, data); - - //SOUND_CNT_H - case 0x0400'0082: - sequencer.volume = data.bits(0,1); - fifo[0].volume = data.bit (2); - fifo[1].volume = data.bit (3); - return; - case 0x0400'0083: - fifo[0].renable = data.bit(0); - fifo[0].lenable = data.bit(1); - fifo[0].timer = data.bit(2); - if(data.bit(3)) fifo[0].reset(); - fifo[1].renable = data.bit(4); - fifo[1].lenable = data.bit(5); - fifo[1].timer = data.bit(6); - if(data.bit(7)) fifo[1].reset(); - return; - - //NR52 - case 0x0400'0084: return sequencer.write(2, data); - case 0x0400'0085: return; - - //SOUNDBIAS - case 0x0400'0088: - regs.bias.level.bits(0,7) = data; - return; - case 0x0400'0089: - regs.bias.level.bits(8,9) = data.bits(0,1); - regs.bias.amplitude = data.bits(6,7); - return; - - //WAVE_RAM0_L - case 0x0400'0090: return wave.writeram( 0, data); - case 0x0400'0091: return wave.writeram( 1, data); - - //WAVE_RAM0_H - case 0x0400'0092: return wave.writeram( 2, data); - case 0x0400'0093: return wave.writeram( 3, data); - - //WAVE_RAM1_L - case 0x0400'0094: return wave.writeram( 4, data); - case 0x0400'0095: return wave.writeram( 5, data); - - //WAVE_RAM1_H - case 0x0400'0096: return wave.writeram( 6, data); - case 0x0400'0097: return wave.writeram( 7, data); - - //WAVE_RAM2_L - case 0x0400'0098: return wave.writeram( 8, data); - case 0x0400'0099: return wave.writeram( 9, data); - - //WAVE_RAM2_H - case 0x0400'009a: return wave.writeram(10, data); - case 0x0400'009b: return wave.writeram(11, data); - - //WAVE_RAM3_L - case 0x0400'009c: return wave.writeram(12, data); - case 0x0400'009d: return wave.writeram(13, data); - - //WAVE_RAM3_H - case 0x0400'009e: return wave.writeram(14, data); - case 0x0400'009f: return wave.writeram(15, data); - - //FIFO_A_L - //FIFO_A_H - case 0x0400'00a0: case 0x0400'00a1: - case 0x0400'00a2: case 0x0400'00a3: - return fifo[0].write(data); - - //FIFO_B_L - //FIFO_B_H - case 0x0400'00a4: case 0x0400'00a5: - case 0x0400'00a6: case 0x0400'00a7: - return fifo[1].write(data); - } -} diff --git a/higan/gba/apu/noise.cpp b/higan/gba/apu/noise.cpp deleted file mode 100644 index 9795f714..00000000 --- a/higan/gba/apu/noise.cpp +++ /dev/null @@ -1,94 +0,0 @@ -auto APU::Noise::divider() const -> uint { - if(divisor == 0) return 4; - return divisor * 8; -} - -auto APU::Noise::run() -> void { - if(period && --period == 0) { - period = divider() << frequency; - if(frequency < 14) { - bool bit = (lfsr ^ (lfsr >> 1)) & 1; - lfsr = (lfsr >> 1) ^ (bit << (narrowlfsr ? 6 : 14)); - } - } - - output = volume; - if(enable == false || (lfsr & 1)) output = 0; -} - -auto APU::Noise::clocklength() -> void { - if(enable && counter) { - if(++length == 0) enable = false; - } -} - -auto APU::Noise::clockenvelope() -> void { - if(enable && envelope.frequency && --envelope.period == 0) { - envelope.period = envelope.frequency; - if(envelope.direction == 0 && volume > 0) volume--; - if(envelope.direction == 1 && volume < 15) volume++; - } -} - -auto APU::Noise::read(uint addr) const -> uint8 { - switch(addr) { - case 1: return 0; - case 2: return (envelope.frequency << 0) | (envelope.direction << 3) | (envelope.volume << 4); - case 3: return (divisor << 0) | (narrowlfsr << 3) | (frequency << 4); - case 4: return (counter << 6); - } - return 0; -} - -auto APU::Noise::write(uint addr, uint8 byte) -> void { - switch(addr) { - case 1: //NR41 - length = byte >> 0; - break; - - case 2: //NR42 - envelope.frequency = byte >> 0; - envelope.direction = byte >> 3; - envelope.volume = byte >> 4; - if(!envelope.dacEnable()) enable = false; - break; - - case 3: //NR43 - divisor = byte >> 0; - narrowlfsr = byte >> 3; - frequency = byte >> 4; - period = divider() << frequency; - break; - - case 4: //NR44 - counter = byte >> 6; - initialize = byte >> 7; - - if(initialize) { - enable = envelope.dacEnable(); - lfsr = -1; - envelope.period = envelope.frequency; - volume = envelope.volume; - } - - break; - } -} - -auto APU::Noise::power() -> void { - envelope.frequency = 0; - envelope.direction = 0; - envelope.volume = 0; - envelope.period = 0; - length = 0; - divisor = 0; - narrowlfsr = 0; - frequency = 0; - counter = 0; - initialize = 0; - enable = 0; - lfsr = 0; - output = 0; - period = 0; - volume = 0; -} diff --git a/higan/gba/apu/sequencer.cpp b/higan/gba/apu/sequencer.cpp deleted file mode 100644 index dcc4e370..00000000 --- a/higan/gba/apu/sequencer.cpp +++ /dev/null @@ -1,109 +0,0 @@ -auto APU::runsequencer() -> void { - auto& r = sequencer; - - if(r.base == 0) { //512hz - if(r.step == 0 || r.step == 2 || r.step == 4 || r.step == 6) { //256hz - square1.clocklength(); - square2.clocklength(); - wave.clocklength(); - noise.clocklength(); - } - if(r.step == 2 || r.step == 6) { //128hz - square1.clocksweep(); - } - if(r.step == 7) { //64hz - square1.clockenvelope(); - square2.clockenvelope(); - noise.clockenvelope(); - } - r.step++; - } - r.base++; - - if(square1.enable) square1.run(); - if(square2.enable) square2.run(); - if(wave.enable) wave.run(); - if(noise.enable) noise.run(); -} - -auto APU::Sequencer::sample() -> void { - loutput = 0; - routput = 0; - if(!masterenable) return; - - if(lenable[0]) loutput += apu.square1.output; - if(lenable[1]) loutput += apu.square2.output; - if(lenable[2]) loutput += apu.wave.output; - if(lenable[3]) loutput += apu.noise.output; - loutput *= 1 + lvolume; - loutput <<= 1; - loutput >>= 3 - volume; - - if(renable[0]) routput += apu.square1.output; - if(renable[1]) routput += apu.square2.output; - if(renable[2]) routput += apu.wave.output; - if(renable[3]) routput += apu.noise.output; - routput *= 1 + rvolume; - routput <<= 1; - routput >>= 3 - volume; -} - -auto APU::Sequencer::read(uint addr) const -> uint8 { - switch(addr) { - case 0: return (rvolume << 0) | (lvolume << 4); - case 1: return ( - (renable[0] << 0) - | (renable[1] << 1) - | (renable[2] << 2) - | (renable[3] << 3) - | (lenable[0] << 4) - | (lenable[1] << 5) - | (lenable[2] << 6) - | (lenable[3] << 7) - ); - case 2: return ( - (apu.square1.enable << 0) - | (apu.square2.enable << 1) - | (apu.wave.enable << 2) - | (apu.noise.enable << 3) - | (masterenable << 7) - ); - } - return 0; -} - -auto APU::Sequencer::write(uint addr, uint8 byte) -> void { - switch(addr) { - case 0: //NR50 - rvolume = byte >> 0; - lvolume = byte >> 4; - break; - - case 1: //NR51 - renable[0] = byte >> 0; - renable[1] = byte >> 1; - renable[2] = byte >> 2; - renable[3] = byte >> 3; - lenable[0] = byte >> 4; - lenable[1] = byte >> 5; - lenable[2] = byte >> 6; - lenable[3] = byte >> 7; - break; - - case 2: //NR52 - masterenable = byte >> 7; - break; - } -} - -auto APU::Sequencer::power() -> void { - lvolume = 0; - rvolume = 0; - for(auto& n : lenable) n = 0; - for(auto& n : renable) n = 0; - masterenable = 0; - base = 0; - step = 0; - lsample = 0; - rsample = 0; -} diff --git a/higan/gba/apu/serialization.cpp b/higan/gba/apu/serialization.cpp deleted file mode 100644 index 496c4fae..00000000 --- a/higan/gba/apu/serialization.cpp +++ /dev/null @@ -1,110 +0,0 @@ -auto APU::serialize(serializer& s) -> void { - Thread::serialize(s); - - s.integer(clock); - - s.integer(regs.bias.level); - s.integer(regs.bias.amplitude); - - s.integer(square1.sweep.shift); - s.integer(square1.sweep.direction); - s.integer(square1.sweep.frequency); - s.integer(square1.sweep.enable); - s.integer(square1.sweep.negate); - s.integer(square1.sweep.period); - - s.integer(square1.envelope.frequency); - s.integer(square1.envelope.direction); - s.integer(square1.envelope.volume); - s.integer(square1.envelope.period); - - s.integer(square1.enable); - s.integer(square1.length); - s.integer(square1.duty); - s.integer(square1.frequency); - s.integer(square1.counter); - s.integer(square1.initialize); - s.integer(square1.shadowfrequency); - s.integer(square1.signal); - s.integer(square1.output); - s.integer(square1.period); - s.integer(square1.phase); - s.integer(square1.volume); - - s.integer(square2.envelope.frequency); - s.integer(square2.envelope.direction); - s.integer(square2.envelope.volume); - s.integer(square2.envelope.period); - - s.integer(square2.enable); - s.integer(square2.length); - s.integer(square2.duty); - s.integer(square2.frequency); - s.integer(square2.counter); - s.integer(square2.initialize); - s.integer(square2.shadowfrequency); - s.integer(square2.signal); - s.integer(square2.output); - s.integer(square2.period); - s.integer(square2.phase); - s.integer(square2.volume); - - s.integer(wave.mode); - s.integer(wave.bank); - s.integer(wave.dacenable); - s.integer(wave.length); - s.integer(wave.volume); - s.integer(wave.frequency); - s.integer(wave.counter); - s.integer(wave.initialize); - for(auto& value : wave.pattern) s.integer(value); - s.integer(wave.enable); - s.integer(wave.output); - s.integer(wave.patternaddr); - s.integer(wave.patternbank); - s.integer(wave.patternsample); - s.integer(wave.period); - - s.integer(noise.envelope.frequency); - s.integer(noise.envelope.direction); - s.integer(noise.envelope.volume); - s.integer(noise.envelope.period); - - s.integer(noise.length); - s.integer(noise.divisor); - s.integer(noise.narrowlfsr); - s.integer(noise.frequency); - s.integer(noise.counter); - s.integer(noise.initialize); - s.integer(noise.enable); - s.integer(noise.lfsr); - s.integer(noise.output); - s.integer(noise.period); - s.integer(noise.volume); - - s.integer(sequencer.volume); - s.integer(sequencer.lvolume); - s.integer(sequencer.rvolume); - for(auto& flag : sequencer.lenable) s.integer(flag); - for(auto& flag : sequencer.renable) s.integer(flag); - s.integer(sequencer.masterenable); - s.integer(sequencer.base); - s.integer(sequencer.step); - s.integer(sequencer.lsample); - s.integer(sequencer.rsample); - s.integer(sequencer.loutput); - s.integer(sequencer.routput); - - for(auto& f : fifo) { - for(auto& value : f.samples) s.integer(value); - s.integer(f.active); - s.integer(f.output); - s.integer(f.rdoffset); - s.integer(f.wroffset); - s.integer(f.size); - s.integer(f.volume); - s.integer(f.lenable); - s.integer(f.renable); - s.integer(f.timer); - } -} diff --git a/higan/gba/apu/square.cpp b/higan/gba/apu/square.cpp deleted file mode 100644 index 48803556..00000000 --- a/higan/gba/apu/square.cpp +++ /dev/null @@ -1,30 +0,0 @@ -auto APU::Square::run() -> void { - if(period && --period == 0) { - period = 2 * (2048 - frequency); - phase++; - switch(duty) { - case 0: signal = (phase == 6); break; //_____-_ - case 1: signal = (phase >= 6); break; //______-- - case 2: signal = (phase >= 4); break; //____---- - case 3: signal = (phase <= 5); break; //------__ - } - } - - uint4 sample = volume; - if(enable == false || signal == false) sample = 0; - output = sample; -} - -auto APU::Square::clocklength() -> void { - if(enable && counter) { - if(++length == 0) enable = false; - } -} - -auto APU::Square::clockenvelope() -> void { - if(enable && envelope.frequency && --envelope.period == 0) { - envelope.period = envelope.frequency; - if(envelope.direction == 0 && volume > 0) volume--; - if(envelope.direction == 1 && volume < 15) volume++; - } -} diff --git a/higan/gba/apu/square1.cpp b/higan/gba/apu/square1.cpp deleted file mode 100644 index efd556da..00000000 --- a/higan/gba/apu/square1.cpp +++ /dev/null @@ -1,105 +0,0 @@ -auto APU::Square1::runsweep(bool update) -> void { - if(!sweep.enable) return; - - sweep.negate = sweep.direction; - uint delta = shadowfrequency >> sweep.shift; - int updatefrequency = shadowfrequency + (sweep.negate ? -delta : delta); - - if(updatefrequency > 2047) { - enable = false; - } else if(sweep.shift && update) { - shadowfrequency = updatefrequency; - frequency = updatefrequency; - period = 2 * (2048 - frequency); - } -} - -auto APU::Square1::clocksweep() -> void { - if(enable && sweep.frequency && --sweep.period == 0) { - sweep.period = sweep.frequency; - runsweep(1); - runsweep(0); - } -} - -auto APU::Square1::read(uint addr) const -> uint8 { - switch(addr) { - case 0: return (sweep.shift << 0) | (sweep.direction << 3) | (sweep.frequency << 4); - case 1: return (duty << 6); - case 2: return (envelope.frequency << 0) | (envelope.direction << 3) | (envelope.volume << 4); - case 3: return 0; - case 4: return (counter << 6); - } - return 0; -} - -auto APU::Square1::write(uint addr, uint8 byte) -> void { - switch(addr) { - case 0: //NR10 - if(sweep.negate && sweep.direction && !(byte & 0x08)) enable = false; - sweep.shift = byte >> 0; - sweep.direction = byte >> 3; - sweep.frequency = byte >> 4; - break; - - case 1: //NR11 - length = byte >> 0; - duty = byte >> 6; - break; - - case 2: //NR12 - envelope.frequency = byte >> 0; - envelope.direction = byte >> 3; - envelope.volume = byte >> 4; - if(!envelope.dacEnable()) enable = false; - break; - - case 3: //NR13 - frequency = (frequency & 0xff00) | (byte << 0); - break; - - case 4: //NR14 - frequency = (frequency & 0x00ff) | (byte << 8); - counter = byte >> 6; - initialize = byte >> 7; - - if(initialize) { - enable = envelope.dacEnable(); - period = 2 * (2048 - frequency); - envelope.period = envelope.frequency; - volume = envelope.volume; - shadowfrequency = frequency; - sweep.period = sweep.frequency; - sweep.enable = sweep.period || sweep.shift; - sweep.negate = false; - if(sweep.shift) runsweep(0); - } - - break; - } -} - -auto APU::Square1::power() -> void { - envelope.frequency = 0; - envelope.direction = 0; - envelope.direction = 0; - envelope.period = 0; - sweep.shift = 0; - sweep.direction = 0; - sweep.frequency = 0; - sweep.enable = 0; - sweep.negate = 0; - sweep.period = 0; - enable = 0; - length = 0; - duty = 0; - frequency = 0; - counter = 0; - initialize = 0; - shadowfrequency = 0; - signal = 0; - output = 0; - period = 0; - phase = 0; - volume = 0; -} diff --git a/higan/gba/apu/square2.cpp b/higan/gba/apu/square2.cpp deleted file mode 100644 index acbb1dec..00000000 --- a/higan/gba/apu/square2.cpp +++ /dev/null @@ -1,62 +0,0 @@ -auto APU::Square2::read(uint addr) const -> uint8 { - switch(addr) { - case 1: return (duty << 6); - case 2: return (envelope.frequency << 0) | (envelope.direction << 3) | (envelope.volume << 4); - case 3: return 0; - case 4: return (counter << 6); - } - return 0; -} - -auto APU::Square2::write(uint addr, uint8 byte) -> void { - switch(addr) { - case 1: //NR21 - length = byte >> 0; - duty = byte >> 6; - break; - - case 2: //NR22 - envelope.frequency = byte >> 0; - envelope.direction = byte >> 3; - envelope.volume = byte >> 4; - if(!envelope.dacEnable()) enable = false; - break; - - case 3: //NR23 - frequency = (frequency & 0xff00) | (byte << 0); - break; - - case 4: //NR24 - frequency = (frequency & 0x00ff) | (byte << 8); - counter = byte >> 6; - initialize = byte >> 7; - - if(initialize) { - enable = envelope.dacEnable(); - period = 2 * (2048 - frequency); - envelope.period = envelope.frequency; - volume = envelope.volume; - } - - break; - } -} - -auto APU::Square2::power() -> void { - envelope.frequency = 0; - envelope.direction = 0; - envelope.direction = 0; - envelope.period = 0; - enable = 0; - length = 0; - duty = 0; - frequency = 0; - counter = 0; - initialize = 0; - shadowfrequency = 0; - signal = 0; - output = 0; - period = 0; - phase = 0; - volume = 0; -} diff --git a/higan/gba/apu/wave.cpp b/higan/gba/apu/wave.cpp deleted file mode 100644 index 6d12a7af..00000000 --- a/higan/gba/apu/wave.cpp +++ /dev/null @@ -1,96 +0,0 @@ -auto APU::Wave::run() -> void { - if(period && --period == 0) { - period = 1 * (2048 - frequency); - patternsample = pattern[patternbank << 5 | patternaddr++]; - if(patternaddr == 0) patternbank ^= mode; - } - - output = patternsample; - static uint multiplier[] = {0, 4, 2, 1, 3, 3, 3, 3}; - output = (output * multiplier[volume]) / 4; - if(enable == false) output = 0; -} - -auto APU::Wave::clocklength() -> void { - if(enable && counter) { - if(++length == 0) enable = false; - } -} - -auto APU::Wave::read(uint addr) const -> uint8 { - switch(addr) { - case 0: return (mode << 5) | (bank << 6) | (dacenable << 7); - case 1: return 0; - case 2: return (volume << 5); - case 3: return 0; - case 4: return (counter << 6); - } - return 0; -} - -auto APU::Wave::write(uint addr, uint8 byte) -> void { - switch(addr) { - case 0: //NR30 - mode = byte >> 5; - bank = byte >> 6; - dacenable = byte >> 7; - if(dacenable == false) enable = false; - break; - - case 1: //NR31 - length = byte >> 0; - break; - - case 2: //NR32 - volume = byte >> 5; - break; - - case 3: //NR33 - frequency = (frequency & 0xff00) | (byte << 0); - break; - - case 4: //NR34 - frequency = (frequency & 0x00ff) | (byte << 8); - counter = byte >> 6; - initialize = byte >> 7; - - if(initialize) { - enable = dacenable; - period = 1 * (2048 - frequency); - patternaddr = 0; - patternbank = mode ? (uint1)0 : bank; - } - - break; - } -} - -auto APU::Wave::readram(uint addr) const -> uint8 { - uint8 byte = 0; - byte |= pattern[!bank << 5 | addr << 1 | 0] << 4; - byte |= pattern[!bank << 5 | addr << 1 | 1] << 0; - return byte; -} - -auto APU::Wave::writeram(uint addr, uint8 byte) -> void { - pattern[!bank << 5 | addr << 1 | 0] = byte >> 4; - pattern[!bank << 5 | addr << 1 | 1] = byte >> 0; -} - -auto APU::Wave::power() -> void { - mode = 0; - bank = 0; - dacenable = 0; - length = 0; - volume = 0; - frequency = 0; - counter = 0; - initialize = 0; - for(auto& sample : pattern) sample = 0; - enable = 0; - output = 0; - patternaddr = 0; - patternbank = 0; - patternsample = 0; - period = 0; -} diff --git a/higan/gba/cartridge/cartridge.cpp b/higan/gba/cartridge/cartridge.cpp deleted file mode 100644 index 1cd1c3ca..00000000 --- a/higan/gba/cartridge/cartridge.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include - -namespace GameBoyAdvance { - -Cartridge cartridge; -#include "mrom.cpp" -#include "sram.cpp" -#include "eeprom.cpp" -#include "flash.cpp" -#include "serialization.cpp" - -Cartridge::Cartridge() { - mrom.data = new uint8[mrom.size = 32 * 1024 * 1024]; - sram.data = new uint8[sram.size = 32 * 1024]; - eeprom.data = new uint8[eeprom.size = 8 * 1024]; - flash.data = new uint8[flash.size = 128 * 1024]; -} - -Cartridge::~Cartridge() { - delete[] mrom.data; - delete[] sram.data; - delete[] eeprom.data; - delete[] flash.data; -} - -auto Cartridge::load() -> bool { - information = {}; - - if(auto loaded = platform->load(ID::GameBoyAdvance, "Game Boy Advance", "gba")) { - information.pathID = loaded.pathID; - } else return false; - - if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else return false; - - auto document = BML::unserialize(information.manifest); - information.title = document["game/label"].text(); - - hasSRAM = false; - hasEEPROM = false; - hasFLASH = false; - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=ROM,content=Program)"]}) { - mrom.size = min(32 * 1024 * 1024, (uint)memory.size); - if(auto fp = platform->open(pathID(), memory.name(), File::Read, File::Required)) { - fp->read(mrom.data, mrom.size); - } - } - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=RAM,content=Save)"]}) { - hasSRAM = true; - sram.size = min(32 * 1024, (uint)memory.size); - sram.mask = sram.size - 1; - for(auto n : range(sram.size)) sram.data[n] = 0xff; - - if(memory.nonVolatile) { - if(auto fp = platform->open(pathID(), memory.name(), File::Read)) { - fp->read(sram.data, sram.size); - } - } - } - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=EEPROM,content=Save)"]}) { - hasEEPROM = true; - eeprom.size = min(8 * 1024, (uint)memory.size); - eeprom.bits = eeprom.size <= 512 ? 6 : 14; - if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size - eeprom.mask = mrom.size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000; - eeprom.test = mrom.size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000; - for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff; - - if(auto fp = platform->open(pathID(), memory.name(), File::Read)) { - fp->read(eeprom.data, eeprom.size); - } - } - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=Flash,content=Save)"]}) { - hasFLASH = true; - flash.size = min(128 * 1024, (uint)memory.size); - flash.manufacturer = memory.manufacturer; - for(auto n : range(flash.size)) flash.data[n] = 0xff; - - flash.id = 0; - if(flash.manufacturer == "Atmel" && flash.size == 64 * 1024) flash.id = 0x3d1f; - if(flash.manufacturer == "Macronix" && flash.size == 64 * 1024) flash.id = 0x1cc2; - if(flash.manufacturer == "Macronix" && flash.size == 128 * 1024) flash.id = 0x09c2; - if(flash.manufacturer == "Panasonic" && flash.size == 64 * 1024) flash.id = 0x1b32; - if(flash.manufacturer == "Sanyo" && flash.size == 128 * 1024) flash.id = 0x1362; - if(flash.manufacturer == "SST" && flash.size == 64 * 1024) flash.id = 0xd4bf; - - if(auto fp = platform->open(pathID(), memory.name(), File::Read)) { - fp->read(flash.data, flash.size); - } - } - - information.sha256 = Hash::SHA256({mrom.data, mrom.size}).digest(); - return true; -} - -auto Cartridge::save() -> void { - auto document = BML::unserialize(information.manifest); - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=RAM,content=Save)"]}) { - if(memory.nonVolatile) { - if(auto fp = platform->open(pathID(), memory.name(), File::Write)) { - fp->write(sram.data, sram.size); - } - } - } - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=EEPROM,content=Save)"]}) { - if(auto fp = platform->open(pathID(), memory.name(), File::Write)) { - fp->write(eeprom.data, eeprom.size); - } - } - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=Flash,content=Save)"]}) { - if(auto fp = platform->open(pathID(), memory.name(), File::Write)) { - fp->write(flash.data, flash.size); - } - } -} - -auto Cartridge::unload() -> void { -} - -auto Cartridge::power() -> void { - eeprom.power(); - flash.power(); -} - -#define RAM_ANALYZE - -auto Cartridge::read(uint mode, uint32 addr) -> uint32 { - if(addr < 0x0e00'0000) { - if(hasEEPROM && (addr & eeprom.mask) == eeprom.test) return eeprom.read(); - return mrom.read(mode, addr); - } else { - if(hasSRAM) return sram.read(mode, addr); - if(hasFLASH) return flash.read(addr); - return cpu.pipeline.fetch.instruction; - } -} - -auto Cartridge::write(uint mode, uint32 addr, uint32 word) -> void { - if(addr < 0x0e00'0000) { - if(hasEEPROM && (addr & eeprom.mask) == eeprom.test) return eeprom.write(word & 1); - return mrom.write(mode, addr, word); - } else { - if(hasSRAM) return sram.write(mode, addr, word); - if(hasFLASH) return flash.write(addr, word); - } -} - -} diff --git a/higan/gba/cartridge/cartridge.hpp b/higan/gba/cartridge/cartridge.hpp deleted file mode 100644 index 44970b07..00000000 --- a/higan/gba/cartridge/cartridge.hpp +++ /dev/null @@ -1,35 +0,0 @@ -struct Cartridge { - #include "memory.hpp" - - auto pathID() const -> uint { return information.pathID; } - auto hash() const -> string { return information.sha256; } - auto manifest() const -> string { return information.manifest; } - auto title() const -> string { return information.title; } - - struct Information { - uint pathID = 0; - string sha256; - string manifest; - string title; - } information; - - Cartridge(); - ~Cartridge(); - - auto load() -> bool; - auto save() -> void; - auto unload() -> void; - auto power() -> void; - - auto read(uint mode, uint32 addr) -> uint32; - auto write(uint mode, uint32 addr, uint32 word) -> void; - - auto serialize(serializer&) -> void; - -private: - bool hasSRAM = false; - bool hasEEPROM = false; - bool hasFLASH = false; -}; - -extern Cartridge cartridge; diff --git a/higan/gba/cartridge/eeprom.cpp b/higan/gba/cartridge/eeprom.cpp deleted file mode 100644 index 9ec2de0a..00000000 --- a/higan/gba/cartridge/eeprom.cpp +++ /dev/null @@ -1,83 +0,0 @@ -auto Cartridge::EEPROM::read(uint addr) -> bool { - return data[addr >> 3] & 0x80 >> (addr & 7); -} - -auto Cartridge::EEPROM::write(uint addr, bool bit) -> void { - if(bit == 0) data[addr >> 3] &=~ (0x80 >> (addr & 7)); - if(bit == 1) data[addr >> 3] |= (0x80 >> (addr & 7)); -} - -auto Cartridge::EEPROM::read() -> bool { - bool bit = 1; - - //EEPROM size auto-detection - if(bits == 0 && mode == Mode::ReadAddress) { - print("EEPROM address bits: ", --addressbits, "\n"); - bits = addressbits == 6 ? 6 : 14; - size = 8192; - mode = Mode::ReadData; - offset = 0; - //fallthrough - } - - if(mode == Mode::ReadData) { - if(offset >= 4) bit = read(address * 64 + (offset - 4)); - if(++offset == 68) mode = Mode::Wait; - } - - return bit; -} - -auto Cartridge::EEPROM::write(bool bit) -> void { - if(mode == Mode::Wait) { - if(bit == 1) mode = Mode::Command; - } - - else if(mode == Mode::Command) { - if(bit == 0) mode = Mode::WriteAddress; - if(bit == 1) mode = Mode::ReadAddress; - offset = 0; - address = 0; - addressbits = 0; - } - - else if(mode == Mode::ReadAddress) { - address = (address << 1) | bit; - addressbits++; - if(++offset == bits) { - mode = Mode::ReadValidate; - offset = 0; - } - } - - else if(mode == Mode::ReadValidate) { - if(bit == 1); //invalid - mode = Mode::ReadData; - } - - else if(mode == Mode::WriteAddress) { - address = (address << 1) | bit; - if(++offset == bits) { - mode = Mode::WriteData; - offset = 0; - } - } - - else if(mode == Mode::WriteData) { - write(address * 64 + offset, bit); - if(++offset == 64) { - mode = Mode::WriteValidate; - } - } - - else if(mode == Mode::WriteValidate) { - if(bit == 1); //invalid - mode = Mode::Wait; - } -} - -auto Cartridge::EEPROM::power() -> void { - mode = Mode::Wait; - offset = 0; - address = 0; -} diff --git a/higan/gba/cartridge/flash.cpp b/higan/gba/cartridge/flash.cpp deleted file mode 100644 index a8f7d4c6..00000000 --- a/higan/gba/cartridge/flash.cpp +++ /dev/null @@ -1,87 +0,0 @@ -//Dev.ID Size Blocks Manufacturer -//====== ===== ======== ============ -//0xd4bf 64KB 16x4096 SST -//0x1cc2 64KB 16x4096 Macronix -//0x1b32 64KB 16x4096 Panasonic -//0x3d1f 64KB 512x 128 Atmel -//0x1362 128KB 32x4096 Sanyo -//0x09c2 128KB 32x4096 Macronix - -auto Cartridge::FLASH::read(uint16 addr) -> uint8 { - if(idmode) { - if(addr == 0x0000) return id >> 0; - if(addr == 0x0001) return id >> 8; - return 0u; - } - - return data[bank << 16 | addr]; -} - -auto Cartridge::FLASH::write(uint16 addr, uint8 byte) -> void { - if(bankselect) { - bankselect = false; - //bank select is only applicable on 128KB chips - if(addr == 0x0000) bank = byte & (size > 64 * 1024); - return; - } - - if(writeselect) { - //Atmel writes 128 bytes per command; all others write 1 byte per command - if(id != 0x3d1f || (addr & 0x007f) == 0x007f) writeselect = false; - data[bank << 16 | addr] = byte; - return; - } - - if(byte == 0xaa && addr == 0x5555) { unlockhi = true; return; } - if(byte == 0x55 && addr == 0x2aaa) { unlocklo = true; return; } - - if(unlockhi && unlocklo) { - unlockhi = false; - unlocklo = false; - - if(byte == 0x10 && addr == 0x5555) { - if(erasemode) { - erasemode = false; - for(uint n : range(size)) data[n] = 0xff; - } - } - - if(byte == 0x30 && (addr & 0x0fff) == 0x0000) { - //command only valid for non-Atmel chips - if(erasemode && id != 0x3d1f) { - erasemode = false; - uint offset = bank << 16 | (addr & ~4095); - for(uint n : range(4096)) data[offset++] = 0xff; - } - } - - if(byte == 0x80 && addr == 0x5555) { - erasemode = true; - } - - if(byte == 0x90 && addr == 0x5555) { - idmode = true; - } - - if(byte == 0xa0 && addr == 0x5555) { - writeselect = true; - } - - if(byte == 0xb0 && addr == 0x5555) { - bankselect = true; - } - - if(byte == 0xf0 && addr == 0x5555) { - idmode = false; - } - } -} - -auto Cartridge::FLASH::power() -> void { - unlockhi = false; - unlocklo = false; - idmode = false; - bankselect = false; - writeselect = false; - bank = 0; -} diff --git a/higan/gba/cartridge/memory.hpp b/higan/gba/cartridge/memory.hpp deleted file mode 100644 index 7e6750fd..00000000 --- a/higan/gba/cartridge/memory.hpp +++ /dev/null @@ -1,66 +0,0 @@ -struct MROM { - uint8* data; - uint size; - uint mask; - - auto read(uint mode, uint32 addr) -> uint32; - auto write(uint mode, uint32 addr, uint32 word) -> void; - - auto serialize(serializer&) -> void; -} mrom; - -struct SRAM { - uint8* data; - uint size; - uint mask; - - auto read(uint mode, uint32 addr) -> uint32; - auto write(uint mode, uint32 addr, uint32 word) -> void; - - auto serialize(serializer&) -> void; -} sram; - -struct EEPROM { - uint8* data; - uint size; - uint mask; - uint test; - uint bits; - - enum class Mode : uint { - Wait, Command, ReadAddress, ReadValidate, ReadData, WriteAddress, WriteData, WriteValidate - } mode; - uint offset; - uint address; - uint addressbits; - - auto read(uint addr) -> bool; - auto write(uint addr, bool bit) -> void; - - auto read() -> bool; - auto write(bool bit) -> void; - auto power() -> void; - auto serialize(serializer&) -> void; -} eeprom; - -struct FLASH { - uint8* data; - uint size; - string manufacturer; - - uint16 id; - - bool unlockhi; - bool unlocklo; - bool idmode; - bool erasemode; - bool bankselect; - bool writeselect; - bool bank; - - auto read(uint16 addr) -> uint8; - auto write(uint16 addr, uint8 byte) -> void; - - auto power() -> void; - auto serialize(serializer&) -> void; -} flash; diff --git a/higan/gba/cartridge/mrom.cpp b/higan/gba/cartridge/mrom.cpp deleted file mode 100644 index 70e2f9d4..00000000 --- a/higan/gba/cartridge/mrom.cpp +++ /dev/null @@ -1,20 +0,0 @@ -auto Cartridge::MROM::read(uint mode, uint32 addr) -> uint32 { - if(mode & Word) { - uint32 word = 0; - word |= read(mode & ~Word | Half, (addr & ~3) + 0) << 0; - word |= read(mode & ~Word | Half, (addr & ~3) + 2) << 16; - return word; - } - - addr &= 0x01ff'ffff; - if(addr >= size) return (uint16)(addr >> 1); - - if(mode & Half) addr &= ~1; - auto p = data + addr; - if(mode & Half) return p[0] << 0 | p[1] << 8; - if(mode & Byte) return p[0] << 0; - return 0; //should never occur -} - -auto Cartridge::MROM::write(uint mode, uint32 addr, uint32 word) -> void { -} diff --git a/higan/gba/cartridge/serialization.cpp b/higan/gba/cartridge/serialization.cpp deleted file mode 100644 index 2d5e3a8c..00000000 --- a/higan/gba/cartridge/serialization.cpp +++ /dev/null @@ -1,42 +0,0 @@ -auto Cartridge::serialize(serializer& s) -> void { - mrom.serialize(s); - if(hasSRAM) sram.serialize(s); - if(hasEEPROM) eeprom.serialize(s); - if(hasFLASH) flash.serialize(s); -} - -auto Cartridge::MROM::serialize(serializer& s) -> void { - s.integer(size); - s.integer(mask); -} - -auto Cartridge::SRAM::serialize(serializer& s) -> void { - s.array(data, size); - s.integer(size); - s.integer(mask); -} - -auto Cartridge::EEPROM::serialize(serializer& s) -> void { - s.array(data, size); - s.integer(size); - s.integer(mask); - s.integer(test); - s.integer(bits); - s.integer((uint&)mode); - s.integer(offset); - s.integer(address); - s.integer(addressbits); -} - -auto Cartridge::FLASH::serialize(serializer& s) -> void { - s.array(data, size); - s.integer(size); - s.integer(id); - s.integer(unlockhi); - s.integer(unlocklo); - s.integer(idmode); - s.integer(erasemode); - s.integer(bankselect); - s.integer(writeselect); - s.integer(bank); -} diff --git a/higan/gba/cartridge/sram.cpp b/higan/gba/cartridge/sram.cpp deleted file mode 100644 index 501d5fb9..00000000 --- a/higan/gba/cartridge/sram.cpp +++ /dev/null @@ -1,10 +0,0 @@ -auto Cartridge::SRAM::read(uint mode, uint32 addr) -> uint32 { - uint32 word = data[addr & mask]; - word |= word << 8; - word |= word << 16; - return word; -} - -auto Cartridge::SRAM::write(uint mode, uint32 addr, uint32 word) -> void { - data[addr & mask] = word; -} diff --git a/higan/gba/cpu/bus.cpp b/higan/gba/cpu/bus.cpp deleted file mode 100644 index fb6b8d96..00000000 --- a/higan/gba/cpu/bus.cpp +++ /dev/null @@ -1,85 +0,0 @@ -auto CPU::sleep() -> void { - prefetchStep(1); -} - -auto CPU::get(uint mode, uint32 addr) -> uint32 { - uint clocks = _wait(mode, addr); - uint word = pipeline.fetch.instruction; - - if(addr >= 0x1000'0000) { - prefetchStep(clocks); - } else if(addr & 0x0800'0000) { - if(mode & Prefetch && wait.prefetch) { - prefetchSync(addr); - word = prefetchRead(); - if(mode & Word) word |= prefetchRead() << 16; - } else { - if(!context.dmaActive) prefetchWait(); - step(clocks - 1); - word = cartridge.read(mode, addr); - step(1); - } - } else { - prefetchStep(clocks - 1); - if(addr < 0x0200'0000) word = bios.read(mode, addr); - else if(addr < 0x0300'0000) word = readEWRAM(mode, addr); - else if(addr < 0x0400'0000) word = readIWRAM(mode, addr); - else if(addr >= 0x0700'0000) word = ppu.readOAM(mode, addr); - else if(addr >= 0x0600'0000) word = ppu.readVRAM(mode, addr); - else if(addr >= 0x0500'0000) word = ppu.readPRAM(mode, addr); - else if((addr & 0xffff'fc00) == 0x0400'0000) word = bus.io[addr & 0x3ff]->readIO(mode, addr); - else if((addr & 0xff00'ffff) == 0x0400'0800) word = ((IO*)this)->readIO(mode, 0x0400'0800 | (addr & 3)); - prefetchStep(1); - } - - return word; -} - -auto CPU::set(uint mode, uint32 addr, uint32 word) -> void { - uint clocks = _wait(mode, addr); - - if(addr >= 0x1000'0000) { - prefetchStep(clocks); - } else if(addr & 0x0800'0000) { - if(!context.dmaActive) prefetchWait(); - step(clocks); - cartridge.write(mode, addr, word); - } else { - prefetchStep(clocks); - if(addr < 0x0200'0000); - else if(addr < 0x0300'0000) writeEWRAM(mode, addr, word); - else if(addr < 0x0400'0000) writeIWRAM(mode, addr, word); - else if(addr >= 0x0700'0000) ppu.writeOAM(mode, addr, word); - else if(addr >= 0x0600'0000) ppu.writeVRAM(mode, addr, word); - else if(addr >= 0x0500'0000) ppu.writePRAM(mode, addr, word); - else if((addr & 0xffff'fc00) == 0x0400'0000) bus.io[addr & 0x3ff]->writeIO(mode, addr, word); - else if((addr & 0xff00'ffff) == 0x0400'0800) ((IO*)this)->writeIO(mode, 0x0400'0800 | (addr & 3), word); - } -} - -auto CPU::_wait(uint mode, uint32 addr) -> uint { - if(addr >= 0x1000'0000) return 1; //unmapped - if(addr < 0x0200'0000) return 1; - if(addr < 0x0300'0000) return (16 - memory.ewramWait) * (mode & Word ? 2 : 1); - if(addr < 0x0500'0000) return 1; - if(addr < 0x0700'0000) return mode & Word ? 2 : 1; - if(addr < 0x0800'0000) return 1; - - static uint timings[] = {5, 4, 3, 9}; - uint n = timings[wait.nwait[addr >> 25 & 3]]; - uint s = wait.swait[addr >> 25 & 3]; - - switch(addr & 0x0e00'0000) { - case 0x0800'0000: s = s ? 2 : 3; break; - case 0x0a00'0000: s = s ? 2 : 5; break; - case 0x0c00'0000: s = s ? 2 : 9; break; - case 0x0e00'0000: s = n; break; - } - - bool sequential = (mode & Sequential); - if((addr & 0x1fffe) == 0) sequential = false; //N cycle on 16-bit ROM crossing 128KB page boundary (RAM S==N) - - uint clocks = sequential ? s : n; - if(mode & Word) clocks += s; //16-bit bus requires two transfers for words - return clocks; -} diff --git a/higan/gba/cpu/cpu.cpp b/higan/gba/cpu/cpu.cpp deleted file mode 100644 index 4ec99674..00000000 --- a/higan/gba/cpu/cpu.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include - -namespace GameBoyAdvance { - -CPU cpu; -#include "prefetch.cpp" -#include "bus.cpp" -#include "io.cpp" -#include "memory.cpp" -#include "dma.cpp" -#include "timer.cpp" -#include "keypad.cpp" -#include "serialization.cpp" - -auto CPU::Enter() -> void { - while(true) scheduler.synchronize(), cpu.main(); -} - -auto CPU::main() -> void { - ARM7TDMI::irq = irq.ime && (irq.enable & irq.flag); - - if(stopped()) { - if(!(irq.enable & irq.flag & Interrupt::Keypad)) { - Thread::step(16); - synchronize(ppu); - synchronize(apu); - synchronize(player); - } - context.stopped = false; - } - - if(halted()) { - if(!(irq.enable & irq.flag)) { - return step(16); - } - context.halted = false; - } - - instruction(); -} - -auto CPU::step(uint clocks) -> void { - dma[0].waiting = max(0, dma[0].waiting - (int)clocks); - dma[1].waiting = max(0, dma[1].waiting - (int)clocks); - dma[2].waiting = max(0, dma[2].waiting - (int)clocks); - dma[3].waiting = max(0, dma[3].waiting - (int)clocks); - - if(!context.dmaActive) { - context.dmaActive = true; - while(dma[0].run() | dma[1].run() | dma[2].run() | dma[3].run()); - context.dmaActive = false; - } - - for(auto _ : range(clocks)) { - timer[0].run(); - timer[1].run(); - timer[2].run(); - timer[3].run(); - context.clock++; - } - - Thread::step(clocks); - synchronize(ppu); - synchronize(apu); - synchronize(player); -} - -auto CPU::power() -> void { - ARM7TDMI::power(); - create(CPU::Enter, system.frequency()); - - for(auto& byte : iwram) byte = 0x00; - for(auto& byte : ewram) byte = 0x00; - - for(auto n : range(4)) dma[n] = {n}; - for(auto n : range(4)) timer[n] = {n}; - serial = {}; - keypad = {}; - joybus = {}; - irq = {}; - wait = {}; - memory = {}; - prefetch = {}; - context = {}; - - dma[0].source.resize(27); dma[0].latch.source.resize(27); - dma[0].target.resize(27); dma[0].latch.target.resize(27); - dma[0].length.resize(14); dma[0].latch.length.resize(14); - - dma[1].source.resize(28); dma[1].latch.source.resize(28); - dma[1].target.resize(27); dma[1].latch.target.resize(27); - dma[1].length.resize(14); dma[1].latch.length.resize(14); - - dma[2].source.resize(28); dma[2].latch.source.resize(28); - dma[2].target.resize(27); dma[2].latch.target.resize(27); - dma[2].length.resize(14); dma[2].latch.length.resize(14); - - dma[3].source.resize(28); dma[3].latch.source.resize(28); - dma[3].target.resize(28); dma[3].latch.target.resize(28); - dma[3].length.resize(16); dma[3].latch.length.resize(16); - - for(uint n = 0x0b0; n <= 0x0df; n++) bus.io[n] = this; //DMA - for(uint n = 0x100; n <= 0x10f; n++) bus.io[n] = this; //Timers - for(uint n = 0x120; n <= 0x12b; n++) bus.io[n] = this; //Serial - for(uint n = 0x130; n <= 0x133; n++) bus.io[n] = this; //Keypad - for(uint n = 0x134; n <= 0x159; n++) bus.io[n] = this; //Serial - for(uint n = 0x200; n <= 0x209; n++) bus.io[n] = this; //System - for(uint n = 0x300; n <= 0x301; n++) bus.io[n] = this; //System - //0x080-0x083 mirrored via gba/memory/memory.cpp //System -} - -} diff --git a/higan/gba/cpu/cpu.hpp b/higan/gba/cpu/cpu.hpp deleted file mode 100644 index a8bf79ad..00000000 --- a/higan/gba/cpu/cpu.hpp +++ /dev/null @@ -1,205 +0,0 @@ -struct CPU : Processor::ARM7TDMI, Thread, IO { - struct Interrupt { enum : uint { - VBlank = 0x0001, - HBlank = 0x0002, - VCoincidence = 0x0004, - Timer0 = 0x0008, - Timer1 = 0x0010, - Timer2 = 0x0020, - Timer3 = 0x0040, - Serial = 0x0080, - DMA0 = 0x0100, - DMA1 = 0x0200, - DMA2 = 0x0400, - DMA3 = 0x0800, - Keypad = 0x1000, - Cartridge = 0x2000, - };}; - - inline auto clock() const -> uint { return context.clock; } - inline auto halted() const -> bool { return context.halted; } - inline auto stopped() const -> bool { return context.stopped; } - - //cpu.cpp - static auto Enter() -> void; - auto main() -> void; - - auto step(uint clocks) -> void override; - - auto power() -> void; - - //prefetch.cpp - auto prefetchSync(uint32 addr) -> void; - auto prefetchStep(uint clocks) -> void; - auto prefetchWait() -> void; - auto prefetchRead() -> uint16; - - //bus.cpp - auto sleep() -> void override; - auto get(uint mode, uint32 addr) -> uint32 override; - auto set(uint mode, uint32 addr, uint32 word) -> void override; - auto _wait(uint mode, uint32 addr) -> uint; - - //io.cpp - auto readIO(uint32 addr) -> uint8; - auto writeIO(uint32 addr, uint8 byte) -> void; - - auto readIWRAM(uint mode, uint32 addr) -> uint32; - auto writeIWRAM(uint mode, uint32 addr, uint32 word) -> void; - - auto readEWRAM(uint mode, uint32 addr) -> uint32; - auto writeEWRAM(uint mode, uint32 addr, uint32 word) -> void; - - //dma.cpp - auto dmaVblank() -> void; - auto dmaHblank() -> void; - auto dmaHDMA() -> void; - - //timer.cpp - auto runFIFO(uint n) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - uint8 iwram[ 32 * 1024]; - uint8 ewram[256 * 1024]; - -//private: - struct DMA { - //dma.cpp - inline auto run() -> bool; - auto transfer() -> void; - - uint2 id; - - boolean active; - integer waiting; - - uint2 targetMode; - uint2 sourceMode; - uint1 repeat; - uint1 size; - uint1 drq; - uint2 timingMode; - uint1 irq; - uint1 enable; - - VariadicNatural source; - VariadicNatural target; - VariadicNatural length; - uint32 data; - - struct Latch { - VariadicNatural target; - VariadicNatural source; - VariadicNatural length; - } latch; - } dma[4]; - - struct Timer { - //timer.cpp - inline auto run() -> void; - auto step() -> void; - - uint2 id; - - boolean pending; - - uint16 period; - uint16 reload; - - uint2 frequency; - uint1 cascade; - uint1 irq; - uint1 enable; - } timer[4]; - - struct Serial { - uint1 shiftClockSelect; - uint1 shiftClockFrequency; - uint1 transferEnableReceive; - uint1 transferEnableSend; - uint1 startBit; - uint1 transferLength; - uint1 irqEnable; - - uint16 data[4]; - uint8 data8; - } serial; - - struct Keypad { - //keypad.cpp - auto run() -> void; - - uint1 enable; - uint1 condition; - uint1 flag[10]; - } keypad; - - struct Joybus { - uint1 sc; - uint1 sd; - uint1 si; - uint1 so; - uint1 scMode; - uint1 sdMode; - uint1 siMode; - uint1 soMode; - uint1 siIRQEnable; - uint2 mode; - - uint1 resetSignal; - uint1 receiveComplete; - uint1 sendComplete; - uint1 resetIRQEnable; - - uint32 receive; - uint32 transmit; - - uint1 receiveFlag; - uint1 sendFlag; - uint2 generalFlag; - } joybus; - - struct IRQ { - uint1 ime; - uint16 enable; - uint16 flag; - } irq; - - struct Wait { - uint2 nwait[4]; - uint1 swait[4]; - uint2 phi; - uint1 prefetch; - uint1 gameType; - } wait; - - struct Memory { - uint1 disable; - uint3 unknown1; - uint1 ewram = 1; - uint4 ewramWait = 13; - uint4 unknown2; - } memory; - - struct { - uint16 slot[8]; - uint32 addr; //read location of slot buffer - uint32 load; //write location of slot buffer - integer wait = 1; //number of clocks before next slot load - - inline auto empty() const { return addr == load; } - inline auto full() const { return load - addr == 16; } - } prefetch; - - struct Context { - natural clock; - boolean halted; - boolean stopped; - boolean booted; //set to true by the GBA BIOS - boolean dmaActive; - } context; -}; - -extern CPU cpu; diff --git a/higan/gba/cpu/dma.cpp b/higan/gba/cpu/dma.cpp deleted file mode 100644 index 6ae1dfa1..00000000 --- a/higan/gba/cpu/dma.cpp +++ /dev/null @@ -1,76 +0,0 @@ -auto CPU::DMA::run() -> bool { - if(!active || waiting) return false; - - transfer(); - if(irq) cpu.irq.flag |= CPU::Interrupt::DMA0 << id; - if(drq && id == 3) cpu.irq.flag |= CPU::Interrupt::Cartridge; - return true; -} - -auto CPU::DMA::transfer() -> void { - uint seek = size ? 4 : 2; - uint mode = size ? Word : Half; - mode |= latch.length == length ? Nonsequential : Sequential; - - if(mode & Nonsequential) { - if((source & 0x0800'0000) && (target & 0x0800'0000)) { - //ROM -> ROM transfer - } else { - cpu.idle(); - cpu.idle(); - } - } - - if(latch.source < 0x0200'0000) { - cpu.idle(); //cannot access BIOS - } else { - uint32 addr = latch.source; - if(mode & Word) addr &= ~3; - if(mode & Half) addr &= ~1; - data = cpu.get(mode, addr); - } - - if(latch.target < 0x0200'0000) { - cpu.idle(); //cannot access BIOS - } else { - uint32 addr = latch.target; - if(mode & Word) addr &= ~3; - if(mode & Half) addr &= ~1; - cpu.set(mode, addr, data); - } - - switch(sourceMode) { - case 0: latch.source += seek; break; - case 1: latch.source -= seek; break; - } - - switch(targetMode) { - case 0: latch.target += seek; break; - case 1: latch.target -= seek; break; - case 3: latch.target += seek; break; - } - - if(--latch.length == 0) { - active = false; - if(targetMode == 3) latch.target = target; - if(repeat == 1) latch.length = length; - if(repeat == 0) enable = false; - } -} - -auto CPU::dmaVblank() -> void { - for(auto& dma : this->dma) { - if(dma.enable && dma.timingMode == 1) dma.active = true; - } -} - -auto CPU::dmaHblank() -> void { - for(auto& dma : this->dma) { - if(dma.enable && dma.timingMode == 2) dma.active = true; - } -} - -auto CPU::dmaHDMA() -> void { - auto& dma = this->dma[3]; - if(dma.enable && dma.timingMode == 3) dma.active = true; -} diff --git a/higan/gba/cpu/io.cpp b/higan/gba/cpu/io.cpp deleted file mode 100644 index cd7b24f4..00000000 --- a/higan/gba/cpu/io.cpp +++ /dev/null @@ -1,426 +0,0 @@ -auto CPU::readIO(uint32 addr) -> uint8 { - auto dma = [&]() -> DMA& { return this->dma[addr / 12 & 3]; }; - auto timer = [&]() -> Timer& { return this->timer[addr.bits(2,3)]; }; - - switch(addr) { - - //DMA0CNT_L, DMA1CNT_L, DMA2CNT_L, DMA3CNT_L - case 0x0400'00b8: case 0x0400'00c4: case 0x0400'00d0: case 0x0400'00dc: return 0x00; - case 0x0400'00b9: case 0x0400'00c5: case 0x0400'00d1: case 0x0400'00dd: return 0x00; - - //DMA0CNT_H, DMA1CNT_H, DMA2CNT_H, DMA3CNT_H - case 0x0400'00ba: case 0x0400'00c6: case 0x0400'00d2: case 0x0400'00de: return ( - dma().targetMode << 5 - | dma().sourceMode.bit(0) << 7 - ); - case 0x0400'00bb: case 0x0400'00c7: case 0x0400'00d3: case 0x0400'00df: return ( - dma().sourceMode.bit(1) << 0 - | dma().repeat << 1 - | dma().size << 2 - | dma().drq << 3 - | dma().timingMode << 4 - | dma().irq << 6 - | dma().enable << 7 - ); - - //TM0CNT_L, TM1CNT_L, TM2CNT_L, TM3CNT_L - case 0x0400'0100: case 0x0400'0104: case 0x0400'0108: case 0x0400'010c: return timer().period.byte(0); - case 0x0400'0101: case 0x0400'0105: case 0x0400'0109: case 0x0400'010d: return timer().period.byte(1); - - //TM0CNT_H, TM1CNT_H, TM2CNT_H, TM3CNT_H - case 0x0400'0102: case 0x0400'0106: case 0x0400'010a: case 0x0400'010e: return ( - timer().frequency << 0 - | timer().cascade << 2 - | timer().irq << 6 - | timer().enable << 7 - ); - case 0x0400'0103: case 0x0400'0107: case 0x0400'010b: case 0x0400'010f: return 0; - - //SIOMULTI0 (SIODATA32_L), SIOMULTI1 (SIODATA32_H), SIOMULTI2, SIOMULTI3 - case 0x0400'0120: case 0x0400'0122: case 0x0400'0124: case 0x0400'0126: { - if(auto data = player.read()) return data().byte(addr.bits(0,1)); - return serial.data[addr.bits(1,2)].byte(0); - } - case 0x0400'0121: case 0x0400'0123: case 0x0400'0125: case 0x0400'0127: { - if(auto data = player.read()) return data().byte(addr.bits(0,1)); - return serial.data[addr.bits(1,2)].byte(1); - } - - //SIOCNT - case 0x0400'0128: return ( - serial.shiftClockSelect << 0 - | serial.shiftClockFrequency << 1 - | serial.transferEnableReceive << 2 - | serial.transferEnableSend << 3 - | serial.startBit << 7 - ); - case 0x0400'0129: return ( - serial.transferLength << 4 - | serial.irqEnable << 6 - ); - - //SIOMLT_SEND (SIODATA8) - case 0x0400'012a: return serial.data8; - case 0x0400'012b: return 0; - - //KEYINPUT - case 0x04000130: { - static const uint landscape[] = {5, 4, 8, 9, 3, 2, 0, 1}; - static const uint portrait[] = {5, 4, 8, 9, 0, 1, 2, 3}; - auto lookup = !settings.rotateLeft ? landscape : portrait; - if(auto result = player.keyinput()) return result() >> 0; - uint8 result = 0; - for(uint n = 0; n < 8; n++) result |= platform->inputPoll(0, 0, lookup[n]) << n; - if((result & 0xc0) == 0xc0) result &= (uint8)~0xc0; //up+down cannot be pressed simultaneously - if((result & 0x30) == 0x30) result &= (uint8)~0x30; //left+right cannot be pressed simultaneously - return result ^ 0xff; - } - case 0x04000131: { - if(auto result = player.keyinput()) return result() >> 8; - uint8 result = 0; - result |= platform->inputPoll(0, 0, 7) << 0; - result |= platform->inputPoll(0, 0, 6) << 1; - return result ^ 0x03; - } - - //KEYCNT - case 0x0400'0132: return ( - keypad.flag[0] << 0 - | keypad.flag[1] << 1 - | keypad.flag[2] << 2 - | keypad.flag[3] << 3 - | keypad.flag[4] << 4 - | keypad.flag[5] << 5 - | keypad.flag[6] << 6 - | keypad.flag[7] << 7 - ); - case 0x0400'0133: return ( - keypad.flag[8] << 0 - | keypad.flag[9] << 1 - | keypad.enable << 6 - | keypad.condition << 7 - ); - - //RCNT - case 0x0400'0134: return ( - joybus.sc << 0 - | joybus.sd << 1 - | joybus.si << 2 - | joybus.so << 3 - | joybus.scMode << 4 - | joybus.sdMode << 5 - | joybus.siMode << 6 - | joybus.soMode << 7 - ); - case 0x0400'0135: return ( - joybus.siIRQEnable << 0 - | joybus.mode << 6 - ); - - //JOYCNT - case 0x0400'0140: return ( - joybus.resetSignal << 0 - | joybus.receiveComplete << 1 - | joybus.sendComplete << 2 - | joybus.resetIRQEnable << 6 - ); - case 0x0400'0141: return 0; - case 0x0400'0142: return 0; - case 0x0400'0143: return 0; - - //JOY_RECV_L, JOY_RECV_H - case 0x0400'0150: return joybus.receive.byte(0); - case 0x0400'0151: return joybus.receive.byte(1); - case 0x0400'0152: return joybus.receive.byte(2); - case 0x0400'0153: return joybus.receive.byte(3); - - //JOY_TRANS_L, JOY_TRANS_H - case 0x0400'0154: return joybus.transmit.byte(0); - case 0x0400'0155: return joybus.transmit.byte(1); - case 0x0400'0156: return joybus.transmit.byte(2); - case 0x0400'0157: return joybus.transmit.byte(3); - - //JOYSTAT - case 0x0400'0158: return ( - joybus.receiveFlag << 1 - | joybus.sendFlag << 3 - | joybus.generalFlag << 4 - ); - case 0x0400'0159: return 0; - case 0x0400'015a: return 0; - case 0x0400'015b: return 0; - - //IE - case 0x0400'0200: return irq.enable.byte(0); - case 0x0400'0201: return irq.enable.byte(1); - - //IF - case 0x0400'0202: return irq.flag.byte(0); - case 0x0400'0203: return irq.flag.byte(1); - - //WAITCNT - case 0x0400'0204: return ( - wait.nwait[3] << 0 - | wait.nwait[0] << 2 - | wait.swait[0] << 4 - | wait.nwait[1] << 5 - | wait.swait[1] << 7 - ); - case 0x0400'0205: return ( - wait.nwait[2] << 0 - | wait.swait[2] << 2 - | wait.phi << 3 - | wait.prefetch << 6 - | wait.gameType << 7 - ); - - //IME - case 0x0400'0208: return irq.ime; - case 0x0400'0209: return 0; - - //POSTFLG + HALTCNT - case 0x0400'0300: return context.booted; - case 0x0400'0301: return 0; - - //MEMCNT_L - case 0x0400'0800: return ( - memory.disable << 0 - | memory.unknown1 << 1 - | memory.ewram << 5 - ); - case 0x0400'0801: return 0; - - //MEMCNT_H - case 0x0400'0802: return 0; - case 0x0400'0803: return ( - memory.ewramWait << 0 - | memory.unknown2 << 4 - ); - - } - - return cpu.pipeline.fetch.instruction.byte(addr & 1); -} - -auto CPU::writeIO(uint32 addr, uint8 data) -> void { - auto dma = [&]() -> DMA& { return this->dma[addr / 12 & 3]; }; - auto timer = [&]() -> Timer& { return this->timer[addr.bits(2,3)]; }; - - switch(addr) { - - //DMA0SAD, DMA1SAD, DMA2SAD, DMA3SAD - case 0x0400'00b0: case 0x0400'00bc: case 0x0400'00c8: case 0x0400'00d4: dma().source.byte(0) = data; return; - case 0x0400'00b1: case 0x0400'00bd: case 0x0400'00c9: case 0x0400'00d5: dma().source.byte(1) = data; return; - case 0x0400'00b2: case 0x0400'00be: case 0x0400'00ca: case 0x0400'00d6: dma().source.byte(2) = data; return; - case 0x0400'00b3: case 0x0400'00bf: case 0x0400'00cb: case 0x0400'00d7: dma().source.byte(3) = data; return; - - //DMA0DAD, DMA1DAD, DMA2DAD, DMA3DAD - case 0x0400'00b4: case 0x0400'00c0: case 0x0400'00cc: case 0x0400'00d8: dma().target.byte(0) = data; return; - case 0x0400'00b5: case 0x0400'00c1: case 0x0400'00cd: case 0x0400'00d9: dma().target.byte(1) = data; return; - case 0x0400'00b6: case 0x0400'00c2: case 0x0400'00ce: case 0x0400'00da: dma().target.byte(2) = data; return; - case 0x0400'00b7: case 0x0400'00c3: case 0x0400'00cf: case 0x0400'00db: dma().target.byte(3) = data; return; - - //DMA0CNT_L, DMA1CNT_L, DMA2CNT_L, DMA3CNT_L - case 0x0400'00b8: case 0x0400'00c4: case 0x0400'00d0: case 0x0400'00dc: dma().length.byte(0) = data; return; - case 0x0400'00b9: case 0x0400'00c5: case 0x0400'00d1: case 0x0400'00dd: dma().length.byte(1) = data; return; - - //DMA0CNT_H, DMA1CNT_H, DMA2CNT_H, DMA3CNT_H - case 0x0400'00ba: case 0x0400'00c6: case 0x0400'00d2: case 0x0400'00de: - dma().targetMode = data.bits(5,6); - dma().sourceMode.bit(0) = data.bit (7); - return; - case 0x0400'00bb: case 0x0400'00c7: case 0x0400'00d3: case 0x0400'00df: { - bool enable = dma().enable; - if(addr != 0x0400'00df) data.bit(3) = 0; //gamepad DRQ valid for DMA3 only - - dma().sourceMode.bit(1) = data.bit (0); - dma().repeat = data.bit (1); - dma().size = data.bit (2); - dma().drq = data.bit (3); - dma().timingMode = data.bits(4,5); - dma().irq = data.bit (6); - dma().enable = data.bit (7); - - if(!enable && dma().enable) { //0->1 transition - if(dma().timingMode == 0) { - dma().active = true; //immediate transfer mode - dma().waiting = 2; - } - dma().latch.target = dma().target; - dma().latch.source = dma().source; - dma().latch.length = dma().length; - } else if(!dma().enable) { - dma().active = false; - } - return; - } - - //TM0CNT_L, TM1CNT_L, TM2CNT_L, TM3CNT_L - case 0x0400'0100: case 0x0400'0104: case 0x0400'0108: case 0x0400'010c: timer().reload.byte(0) = data; return; - case 0x0400'0101: case 0x0400'0105: case 0x0400'0109: case 0x0400'010d: timer().reload.byte(1) = data; return; - - //TM0CNT_H, TM1CNT_H, TM2CNT_H, TM3CNT_H - case 0x0400'0102: case 0x0400'0106: case 0x0400'010a: case 0x0400'010e: { - bool enable = timer().enable; - - timer().frequency = data.bits(0,1); - timer().cascade = data.bit (2); - timer().irq = data.bit (6); - timer().enable = data.bit (7); - - if(!enable && timer().enable) { //0->1 transition - timer().pending = true; - } - return; - } - case 0x0400'0103: case 0x0400'0107: case 0x0400'010b: case 0x0400'010f: - return; - - //SIOMULTI0 (SIODATA32_L), SIOMULTI1 (SIODATA32_H), SIOMULTI2, SIOMULTI3 - case 0x0400'0120: case 0x0400'0122: case 0x0400'0124: case 0x0400'0126: - player.write(addr.bits(0,1), data); - serial.data[addr.bits(1,2)].byte(0) = data; - return; - case 0x0400'0121: case 0x0400'0123: case 0x0400'0125: case 0x0400'0127: - player.write(addr.bits(0,1), data); - serial.data[addr.bits(1,2)].byte(1) = data; - return; - - //SIOCNT - case 0x0400'0128: - serial.shiftClockSelect = data.bit(0); - serial.shiftClockFrequency = data.bit(1); - serial.transferEnableReceive = data.bit(2); - serial.transferEnableSend = data.bit(3); - serial.startBit = data.bit(7); - return; - case 0x0400'0129: - serial.transferLength = data.bit(4); - serial.irqEnable = data.bit(6); - return; - - //SIOMLT_SEND (SIODATA8) - case 0x0400'012a: serial.data8 = data; return; - case 0x0400'012b: return; - - //KEYCNT - case 0x0400'0132: - keypad.flag[0] = data.bit(0); - keypad.flag[1] = data.bit(1); - keypad.flag[2] = data.bit(2); - keypad.flag[3] = data.bit(3); - keypad.flag[4] = data.bit(4); - keypad.flag[5] = data.bit(5); - keypad.flag[6] = data.bit(6); - keypad.flag[7] = data.bit(7); - return; - case 0x0400'0133: - keypad.flag[8] = data.bit(0); - keypad.flag[9] = data.bit(1); - keypad.enable = data.bit(6); - keypad.condition = data.bit(7); - return; - - //RCNT - case 0x0400'0134: - joybus.sc = data.bit(0); - joybus.sd = data.bit(1); - joybus.si = data.bit(2); - joybus.so = data.bit(3); - joybus.scMode = data.bit(4); - joybus.sdMode = data.bit(5); - joybus.siMode = data.bit(6); - joybus.soMode = data.bit(7); - return; - case 0x0400'0135: - joybus.siIRQEnable = data.bit (0); - joybus.mode = data.bits(6,7); - return; - - //JOYCNT - case 0x0400'0140: - joybus.resetSignal = data.bit(0); - joybus.receiveComplete = data.bit(1); - joybus.sendComplete = data.bit(2); - joybus.resetIRQEnable = data.bit(6); - return; - case 0x0400'0141: return; - case 0x0400'0142: return; - case 0x0400'0143: return; - - //JOY_RECV_L - //JOY_RECV_H - case 0x0400'0150: joybus.receive.byte(0) = data; return; - case 0x0400'0151: joybus.receive.byte(1) = data; return; - case 0x0400'0152: joybus.receive.byte(2) = data; return; - case 0x0400'0153: joybus.receive.byte(3) = data; return; - - //JOY_TRANS_L - //JOY_TRANS_H - case 0x0400'0154: joybus.transmit.byte(0) = data; return; - case 0x0400'0155: joybus.transmit.byte(1) = data; return; - case 0x0400'0156: joybus.transmit.byte(2) = data; return; - case 0x0400'0157: joybus.transmit.byte(3) = data; return; - - //JOYSTAT - case 0x0400'0158: - joybus.receiveFlag = data.bit (1); - joybus.sendFlag = data.bit (3); - joybus.generalFlag = data.bits(4,5); - return; - case 0x0400'0159: return; - - //IE - case 0x0400'0200: irq.enable.byte(0) = data; return; - case 0x0400'0201: irq.enable.byte(1) = data; return; - - //IF - case 0x0400'0202: irq.flag.byte(0) = irq.flag.byte(0) & ~data; return; - case 0x0400'0203: irq.flag.byte(1) = irq.flag.byte(1) & ~data; return; - - //WAITCNT - case 0x0400'0204: - wait.swait[3] = data.bit (0); //todo: is this correct? - wait.nwait[3] = data.bits(0,1); - wait.nwait[0] = data.bits(2,3); - wait.swait[0] = data.bit (4); - wait.nwait[1] = data.bits(5,6); - wait.swait[1] = data.bit (7); - return; - case 0x0400'0205: - wait.nwait[2] = data.bits(0,1); - wait.swait[2] = data.bit (2); - wait.phi = data.bit (3); - wait.prefetch = data.bit (6); - //wait.gameType is read-only - return; - - //IME - case 0x0400'0208: irq.ime = data.bit(0); return; - case 0x0400'0209: return; - - //POSTFLG, HALTCNT - case 0x0400'0300: - if(data.bit(0)) context.booted = 1; - return; - case 0x0400'0301: - context.halted = data.bit(7) == 0; - context.stopped = data.bit(7) == 1; - return; - - //MEMCNT_L - //MEMCNT_H - case 0x0400'0800: - memory.disable = data.bit (0); - memory.unknown1 = data.bits(1,3); - memory.ewram = data.bit (5); - return; - case 0x0400'0801: return; - case 0x0400'0802: return; - case 0x0400'0803: - memory.ewramWait = data.bits(0,3); - memory.unknown2 = data.bits(4,7); - return; - - } -} diff --git a/higan/gba/cpu/keypad.cpp b/higan/gba/cpu/keypad.cpp deleted file mode 100644 index 886b6b5e..00000000 --- a/higan/gba/cpu/keypad.cpp +++ /dev/null @@ -1,15 +0,0 @@ -auto CPU::Keypad::run() -> void { - //lookup table to convert button indexes to Emulator::Interface indexes - static const uint lookup[] = {5, 4, 8, 9, 3, 2, 0, 1, 7, 6}; - - if(!enable) return; - - bool test = condition; //0 = OR, 1 = AND - for(auto n : range(10)) { - if(!flag[n]) continue; - bool input = platform->inputPoll(0, 0, lookup[n]); - if(condition == 0) test |= input; - if(condition == 1) test &= input; - } - if(test) cpu.irq.flag |= CPU::Interrupt::Keypad; -} diff --git a/higan/gba/cpu/memory.cpp b/higan/gba/cpu/memory.cpp deleted file mode 100644 index b3dbce41..00000000 --- a/higan/gba/cpu/memory.cpp +++ /dev/null @@ -1,55 +0,0 @@ -auto CPU::readIWRAM(uint mode, uint32 addr) -> uint32 { - if(memory.disable) return cpu.pipeline.fetch.instruction; - - if(mode & Word) return readIWRAM(Half, addr &~ 2) << 0 | readIWRAM(Half, addr | 2) << 16; - if(mode & Half) return readIWRAM(Byte, addr &~ 1) << 0 | readIWRAM(Byte, addr | 1) << 8; - - return iwram[addr & 0x7fff]; -} - -auto CPU::writeIWRAM(uint mode, uint32 addr, uint32 word) -> void { - if(memory.disable) return; - - if(mode & Word) { - writeIWRAM(Half, addr &~2, word >> 0); - writeIWRAM(Half, addr | 2, word >> 16); - return; - } - - if(mode & Half) { - writeIWRAM(Byte, addr &~1, word >> 0); - writeIWRAM(Byte, addr | 1, word >> 8); - return; - } - - iwram[addr & 0x7fff] = word; -} - -auto CPU::readEWRAM(uint mode, uint32 addr) -> uint32 { - if(memory.disable) return cpu.pipeline.fetch.instruction; - if(!memory.ewram) return readIWRAM(mode, addr); - - if(mode & Word) return readEWRAM(Half, addr &~ 2) << 0 | readEWRAM(Half, addr | 2) << 16; - if(mode & Half) return readEWRAM(Byte, addr &~ 1) << 0 | readEWRAM(Byte, addr | 1) << 8; - - return ewram[addr & 0x3ffff]; -} - -auto CPU::writeEWRAM(uint mode, uint32 addr, uint32 word) -> void { - if(memory.disable) return; - if(!memory.ewram) return writeIWRAM(mode, addr, word); - - if(mode & Word) { - writeEWRAM(Half, addr &~2, word >> 0); - writeEWRAM(Half, addr | 2, word >> 16); - return; - } - - if(mode & Half) { - writeEWRAM(Byte, addr &~1, word >> 0); - writeEWRAM(Byte, addr | 1, word >> 8); - return; - } - - ewram[addr & 0x3ffff] = word; -} diff --git a/higan/gba/cpu/prefetch.cpp b/higan/gba/cpu/prefetch.cpp deleted file mode 100644 index e4b7cf4e..00000000 --- a/higan/gba/cpu/prefetch.cpp +++ /dev/null @@ -1,37 +0,0 @@ -auto CPU::prefetchSync(uint32 addr) -> void { - if(addr == prefetch.addr) return; - - prefetch.addr = addr; - prefetch.load = addr; - prefetch.wait = _wait(Half | Nonsequential, prefetch.load); -} - -auto CPU::prefetchStep(uint clocks) -> void { - step(clocks); - if(!wait.prefetch || context.dmaActive) return; - - while(!prefetch.full() && clocks--) { - if(--prefetch.wait) continue; - prefetch.slot[prefetch.load >> 1 & 7] = cartridge.read(Half, prefetch.load); - prefetch.load += 2; - prefetch.wait = _wait(Half | Sequential, prefetch.load); - } -} - -auto CPU::prefetchWait() -> void { - if(!wait.prefetch || context.dmaActive || prefetch.full()) return; - - prefetchStep(prefetch.wait); - prefetch.wait = _wait(Half | Nonsequential, prefetch.load); -} - -auto CPU::prefetchRead() -> uint16 { - if(prefetch.empty()) prefetchStep(prefetch.wait); - else prefetchStep(1); - - if(prefetch.full()) prefetch.wait = _wait(Half | Sequential, prefetch.load); - - uint16 half = prefetch.slot[prefetch.addr >> 1 & 7]; - prefetch.addr += 2; - return half; -} diff --git a/higan/gba/cpu/serialization.cpp b/higan/gba/cpu/serialization.cpp deleted file mode 100644 index e19b0293..00000000 --- a/higan/gba/cpu/serialization.cpp +++ /dev/null @@ -1,100 +0,0 @@ -auto CPU::serialize(serializer& s) -> void { - ARM7TDMI::serialize(s); - Thread::serialize(s); - - s.array(iwram); - s.array(ewram); - - for(auto& dma : this->dma) { - s.integer(dma.id); - s.boolean(dma.active); - s.integer(dma.waiting); - s.integer(dma.targetMode); - s.integer(dma.sourceMode); - s.integer(dma.repeat); - s.integer(dma.size); - s.integer(dma.drq); - s.integer(dma.timingMode); - s.integer(dma.irq); - s.integer(dma.enable); - s.integer(dma.source); - s.integer(dma.target); - s.integer(dma.length); - s.integer(dma.data); - s.integer(dma.latch.target); - s.integer(dma.latch.source); - s.integer(dma.latch.length); - } - - for(auto& timer : this->timer) { - s.integer(timer.id); - s.boolean(timer.pending); - s.integer(timer.period); - s.integer(timer.reload); - s.integer(timer.frequency); - s.integer(timer.cascade); - s.integer(timer.irq); - s.integer(timer.enable); - } - - s.integer(serial.shiftClockSelect); - s.integer(serial.shiftClockFrequency); - s.integer(serial.transferEnableReceive); - s.integer(serial.transferEnableSend); - s.integer(serial.startBit); - s.integer(serial.transferLength); - s.integer(serial.irqEnable); - for(auto& value : serial.data) s.integer(value); - s.integer(serial.data8); - - s.integer(keypad.enable); - s.integer(keypad.condition); - for(auto& flag : keypad.flag) s.integer(flag); - - s.integer(joybus.sc); - s.integer(joybus.sd); - s.integer(joybus.si); - s.integer(joybus.so); - s.integer(joybus.scMode); - s.integer(joybus.sdMode); - s.integer(joybus.siMode); - s.integer(joybus.soMode); - s.integer(joybus.siIRQEnable); - s.integer(joybus.mode); - s.integer(joybus.resetSignal); - s.integer(joybus.receiveComplete); - s.integer(joybus.sendComplete); - s.integer(joybus.resetIRQEnable); - s.integer(joybus.receive); - s.integer(joybus.transmit); - s.integer(joybus.receiveFlag); - s.integer(joybus.sendFlag); - s.integer(joybus.generalFlag); - - s.integer(irq.ime); - s.integer(irq.enable); - s.integer(irq.flag); - - for(auto& flag : wait.nwait) s.integer(flag); - for(auto& flag : wait.swait) s.integer(flag); - s.integer(wait.phi); - s.integer(wait.prefetch); - s.integer(wait.gameType); - - s.integer(memory.disable); - s.integer(memory.unknown1); - s.integer(memory.ewram); - s.integer(memory.ewramWait); - s.integer(memory.unknown2); - - s.array(prefetch.slot); - s.integer(prefetch.addr); - s.integer(prefetch.load); - s.integer(prefetch.wait); - - s.integer(context.clock); - s.boolean(context.halted); - s.boolean(context.stopped); - s.boolean(context.booted); - s.boolean(context.dmaActive); -} diff --git a/higan/gba/cpu/timer.cpp b/higan/gba/cpu/timer.cpp deleted file mode 100644 index f38678ab..00000000 --- a/higan/gba/cpu/timer.cpp +++ /dev/null @@ -1,42 +0,0 @@ -auto CPU::Timer::run() -> void { - if(pending) { - pending = false; - if(enable) period = reload; - return; - } - - if(!enable || cascade) return; - - static const uint mask[] = {0, 63, 255, 1023}; - if((cpu.clock() & mask[frequency]) == 0) step(); -} - -auto CPU::Timer::step() -> void { - if(++period == 0) { - period = reload; - - if(irq) cpu.irq.flag |= CPU::Interrupt::Timer0 << id; - - if(apu.fifo[0].timer == id) cpu.runFIFO(0); - if(apu.fifo[1].timer == id) cpu.runFIFO(1); - - if(id < 3 && cpu.timer[id + 1].enable && cpu.timer[id + 1].cascade) { - cpu.timer[id + 1].step(); - } - } -} - -auto CPU::runFIFO(uint n) -> void { - synchronize(apu); - apu.fifo[n].read(); - if(apu.fifo[n].size > 16) return; - - auto& dma = this->dma[1 + n]; - if(dma.enable && dma.timingMode == 3) { - dma.active = true; - dma.waiting = 2; - dma.targetMode = 2; - dma.size = 1; - dma.latch.length = 4; - } -} diff --git a/higan/gba/gba.hpp b/higan/gba/gba.hpp deleted file mode 100644 index 6a96c157..00000000 --- a/higan/gba/gba.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -//license: GPLv3 -//started: 2012-03-19 - -#include -#include -#include - -#include - -namespace GameBoyAdvance { - #define platform Emulator::platform - namespace File = Emulator::File; - using Scheduler = Emulator::Scheduler; - extern Scheduler scheduler; - - enum : uint { //mode flags for bus read, write: - Nonsequential = 1, //N cycle - Sequential = 2, //S cycle - Prefetch = 4, //instruction fetch (eligible for prefetch) - Byte = 8, //8-bit access - Half = 16, //16-bit access - Word = 32, //32-bit access - Load = 64, //load operation - Store = 128, //store operation - Signed = 256, //sign extended - }; - - struct Thread : Emulator::Thread { - auto create(auto (*entrypoint)() -> void, double frequency) -> void { - Emulator::Thread::create(entrypoint, frequency); - scheduler.append(*this); - } - - inline auto synchronize(Thread& thread) -> void { - if(clock() >= thread.clock()) scheduler.resume(thread); - } - }; - - #include - #include - #include - #include - #include - #include - #include -} - -#include diff --git a/higan/gba/interface/interface.cpp b/higan/gba/interface/interface.cpp deleted file mode 100644 index a681b910..00000000 --- a/higan/gba/interface/interface.cpp +++ /dev/null @@ -1,167 +0,0 @@ -#include - -namespace GameBoyAdvance { - -Settings settings; - -auto Interface::information() -> Information { - Information information; - information.manufacturer = "Nintendo"; - information.name = "Game Boy Advance"; - information.extension = "gba"; - return information; -} - -auto Interface::display() -> Display { - Display display; - display.type = Display::Type::LCD; - display.colors = 1 << 15; - display.width = 240; - display.height = 160; - display.internalWidth = 240; - display.internalHeight = 160; - display.aspectCorrection = 1.0; - if(settings.rotateLeft) { - swap(display.width, display.height); - swap(display.internalWidth, display.internalHeight); - } - return display; -} - -auto Interface::color(uint32 color) -> uint64 { - uint R = color.bits( 0, 4); - uint G = color.bits( 5, 9); - uint B = color.bits(10,14); - - uint64 r = image::normalize(R, 5, 16); - uint64 g = image::normalize(G, 5, 16); - uint64 b = image::normalize(B, 5, 16); - - if(settings.colorEmulation) { - double lcdGamma = 4.0, outGamma = 2.2; - double lb = pow(B / 31.0, lcdGamma); - double lg = pow(G / 31.0, lcdGamma); - double lr = pow(R / 31.0, lcdGamma); - r = pow(( 0 * lb + 50 * lg + 255 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); - g = pow(( 30 * lb + 230 * lg + 10 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); - b = pow((220 * lb + 10 * lg + 50 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); - } - - return r << 32 | g << 16 | b << 0; -} - -auto Interface::loaded() -> bool { - return system.loaded(); -} - -auto Interface::hashes() -> vector { - return {cartridge.hash()}; -} - -auto Interface::manifests() -> vector { - return {cartridge.manifest()}; -} - -auto Interface::titles() -> vector { - return {cartridge.title()}; -} - -auto Interface::load() -> bool { - return system.load(this); -} - -auto Interface::save() -> void { - system.save(); -} - -auto Interface::unload() -> void { - save(); - system.unload(); -} - -auto Interface::ports() -> vector { return { - {ID::Port::Hardware, "Hardware"}}; -} - -auto Interface::devices(uint port) -> vector { - if(port == ID::Port::Hardware) return { - {ID::Device::Controls, "Controls"} - }; - - return {}; -} - -auto Interface::inputs(uint device) -> vector { - using Type = Input::Type; - - if(device == ID::Device::Controls) return { - {Type::Hat, "Up" }, - {Type::Hat, "Down" }, - {Type::Hat, "Left" }, - {Type::Hat, "Right" }, - {Type::Button, "B" }, - {Type::Button, "A" }, - {Type::Trigger, "L" }, - {Type::Trigger, "R" }, - {Type::Control, "Select"}, - {Type::Control, "Start" }, - {Type::Rumble, "Rumble"} - }; - - return {}; -} - -auto Interface::power() -> void { - system.power(); -} - -auto Interface::run() -> void { - system.run(); -} - -auto Interface::serialize() -> serializer { - system.runToSave(); - return system.serialize(); -} - -auto Interface::unserialize(serializer& s) -> bool { - return system.unserialize(s); -} - -auto Interface::cap(const string& name) -> bool { - if(name == "Blur Emulation") return true; - if(name == "Color Emulation") return true; - if(name == "Rotate Display") return true; - return false; -} - -auto Interface::get(const string& name) -> any { - if(name == "Blur Emulation") return settings.blurEmulation; - if(name == "Color Emulation") return settings.colorEmulation; - if(name == "Rotate Display") return settings.rotateLeft; - return {}; -} - -auto Interface::set(const string& name, const any& value) -> bool { - if(name == "Blur Emulation" && value.is()) { - settings.blurEmulation = value.get(); - Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation); - return true; - } - - if(name == "Color Emulation" && value.is()) { - settings.colorEmulation = value.get(); - Emulator::video.setPalette(); - return true; - } - - if(name == "Rotate Display" && value.is()) { - settings.rotateLeft = value.get(); - Emulator::video.setEffect(Emulator::Video::Effect::RotateLeft, settings.rotateLeft); - return true; - } - - return false; -} - -} diff --git a/higan/gba/interface/interface.hpp b/higan/gba/interface/interface.hpp deleted file mode 100644 index 6819a887..00000000 --- a/higan/gba/interface/interface.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#if defined(CORE_GBA) - -namespace GameBoyAdvance { - -struct ID { - enum : uint { - System, - GameBoyAdvance, - }; - - struct Port { enum : uint { - Hardware, - };}; - - struct Device { enum : uint { - Controls, - };}; -}; - -struct Interface : Emulator::Interface { - auto information() -> Information override; - - auto display() -> Display override; - auto color(uint32 color) -> uint64 override; - - auto loaded() -> bool override; - auto hashes() -> vector override; - auto manifests() -> vector override; - auto titles() -> vector override; - auto load() -> bool override; - auto save() -> void override; - auto unload() -> void override; - - auto ports() -> vector override; - auto devices(uint port) -> vector override; - auto inputs(uint device) -> vector override; - - auto power() -> void override; - auto run() -> void override; - - auto serialize() -> serializer override; - auto unserialize(serializer&) -> bool override; - - auto cap(const string& name) -> bool override; - auto get(const string& name) -> any override; - auto set(const string& name, const any& value) -> bool override; -}; - -struct Settings { - bool blurEmulation = true; - bool colorEmulation = true; - bool rotateLeft = false; -}; - -extern Settings settings; - -} - -#endif diff --git a/higan/gba/memory/memory.cpp b/higan/gba/memory/memory.cpp deleted file mode 100644 index db632b46..00000000 --- a/higan/gba/memory/memory.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include - -namespace GameBoyAdvance { - -Bus bus; - -auto IO::readIO(uint mode, uint32 addr) -> uint32 { - uint32 word = 0; - - if(mode & Word) { - addr &= ~3; - word |= readIO(addr + 0) << 0; - word |= readIO(addr + 1) << 8; - word |= readIO(addr + 2) << 16; - word |= readIO(addr + 3) << 24; - } else if(mode & Half) { - addr &= ~1; - word |= readIO(addr + 0) << 0; - word |= readIO(addr + 1) << 8; - } else if(mode & Byte) { - word |= readIO(addr + 0) << 0; - } - - return word; -} - -auto IO::writeIO(uint mode, uint32 addr, uint32 word) -> void { - if(mode & Word) { - addr &= ~3; - writeIO(addr + 0, word >> 0); - writeIO(addr + 1, word >> 8); - writeIO(addr + 2, word >> 16); - writeIO(addr + 3, word >> 24); - } else if(mode & Half) { - addr &= ~1; - writeIO(addr + 0, word >> 0); - writeIO(addr + 1, word >> 8); - } else if(mode & Byte) { - writeIO(addr + 0, word >> 0); - } -} - -struct UnmappedIO : IO { - auto readIO(uint32 addr) -> uint8 override { - return cpu.pipeline.fetch.instruction.byte(addr & 1); - } - - auto writeIO(uint32 addr, uint8 byte) -> void override { - } -}; - -static UnmappedIO unmappedIO; - -auto Bus::mirror(uint32 addr, uint32 size) -> uint32 { - uint32 base = 0; - if(size) { - uint32 mask = 1 << 27; //28-bit bus - while(addr >= size) { - while(!(addr & mask)) mask >>= 1; - addr -= mask; - if(size > mask) { - size -= mask; - base += mask; - } - mask >>= 1; - } - base += addr; - } - return base; -} - -auto Bus::power() -> void { - for(auto n : range(0x400)) io[n] = &unmappedIO; -} - -} diff --git a/higan/gba/memory/memory.hpp b/higan/gba/memory/memory.hpp deleted file mode 100644 index aa119b80..00000000 --- a/higan/gba/memory/memory.hpp +++ /dev/null @@ -1,16 +0,0 @@ -struct IO { - virtual auto readIO(uint32 addr) -> uint8 = 0; - virtual auto writeIO(uint32 addr, uint8 data) -> void = 0; - auto readIO(uint mode, uint32 addr) -> uint32; - auto writeIO(uint mode, uint32 addr, uint32 word) -> void; -}; - -struct Bus { - static auto mirror(uint32 addr, uint32 size) -> uint32; - - auto power() -> void; - - IO* io[0x400] = {nullptr}; -}; - -extern Bus bus; diff --git a/higan/gba/player/player.cpp b/higan/gba/player/player.cpp deleted file mode 100644 index a68989e0..00000000 --- a/higan/gba/player/player.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include - -namespace GameBoyAdvance { - -//Game Boy Player emulation - -Player player; -#include "serialization.cpp" - -auto Player::Enter() -> void { - while(true) scheduler.synchronize(), player.main(); -} - -auto Player::main() -> void { - if(status.timeout && !--status.timeout) { - platform->inputRumble(0, 0, 10, false); - } - - step(1); -} - -auto Player::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); -} - -auto Player::power() -> void { - create(Player::Enter, 1'000.0); - - status.enable = false; - status.rumble = false; - - status.logoDetected = false; - status.logoCounter = 0; - - status.packet = 0; - status.send = 0; - status.recv = 0; - - status.timeout = 0; -} - -auto Player::frame() -> void { - //todo: this is not a very performant way of detecting the GBP logo ... - uint32 hash = Hash::CRC32({ppu.output, 240 * 160 * sizeof(uint32)}).value(); - status.logoDetected = (hash == 0x7776eb55); - - if(status.logoDetected) { - status.enable = true; - status.logoCounter = (status.logoCounter + 1) % 3; - status.packet = 0; - } - - if(!status.enable) return; - - //todo: verify which settings are actually required - //values were taken from observing GBP-compatible games - if(!cpu.joybus.sc - && !cpu.joybus.sd - && !cpu.joybus.si - && !cpu.joybus.so - && !cpu.joybus.scMode - && !cpu.joybus.sdMode - && !cpu.joybus.siMode - && !cpu.joybus.soMode - && !cpu.joybus.siIRQEnable - && !cpu.joybus.mode - && !cpu.serial.shiftClockSelect - && !cpu.serial.shiftClockFrequency - && !cpu.serial.transferEnableReceive - && cpu.serial.transferEnableSend - && cpu.serial.startBit - && cpu.serial.transferLength - && cpu.serial.irqEnable - ) { - status.packet = (status.packet + 1) % 17; - switch(status.packet) { - case 0: status.send = 0x0000494e; break; - case 1: status.send = 0xb6b1494e; break; - case 2: status.send = 0xb6b1494e; break; - case 3: status.send = 0xb6b1544e; break; - case 4: status.send = 0xabb1544e; break; - case 5: status.send = 0xabb14e45; break; - case 6: status.send = 0xb1ba4e45; break; - case 7: status.send = 0xb1ba4f44; break; - case 8: status.send = 0xb0bb4f44; break; - case 9: status.send = 0xb0bb8002; break; - case 10: status.send = 0x10000010; break; - case 11: status.send = 0x20000013; break; - case 12: status.send = 0x30000003; break; - case 13: status.send = 0x30000003; break; - case 14: status.send = 0x30000003; break; - case 15: status.send = 0x30000003; break; - case 16: status.send = 0x30000003; break; - } - cpu.irq.flag |= CPU::Interrupt::Serial; - } -} - -auto Player::keyinput() -> maybe { - if(status.logoDetected) { - switch(status.logoCounter) { - case 0: return {0x03ff}; - case 1: return {0x03ff}; - case 2: return {0x030f}; - } - } - return nothing; -} - -auto Player::read() -> maybe { - if(status.enable) return status.send; - return nothing; -} - -auto Player::write(uint2 addr, uint8 byte) -> void { - if(!status.enable) return; - - uint shift = addr << 3; - status.recv &= ~(255 << shift); - status.recv |= byte << shift; - - if(addr == 3 && status.packet == 15) { - status.rumble = (status.recv & 0xff) == 0x26; //on = 0x26, off = 0x04 - platform->inputRumble(0, 0, 10, status.rumble); - if(status.rumble) status.timeout = 500; //stop rumble manually after 500ms - } -} - -} diff --git a/higan/gba/player/player.hpp b/higan/gba/player/player.hpp deleted file mode 100644 index 0628ddde..00000000 --- a/higan/gba/player/player.hpp +++ /dev/null @@ -1,31 +0,0 @@ -struct Player : Thread { - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - - auto power() -> void; - auto frame() -> void; - - auto keyinput() -> maybe; - auto read() -> maybe; - auto write(uint2 addr, uint8 byte) -> void; - - auto serialize(serializer& s) -> void; - -private: - struct Status { - bool enable; - bool rumble; - - bool logoDetected; - uint logoCounter; - - uint packet; - uint32 send; - uint32 recv; - - uint timeout; - } status; -}; - -extern Player player; diff --git a/higan/gba/player/serialization.cpp b/higan/gba/player/serialization.cpp deleted file mode 100644 index a04a26af..00000000 --- a/higan/gba/player/serialization.cpp +++ /dev/null @@ -1,13 +0,0 @@ -auto Player::serialize(serializer& s) -> void { - s.integer(status.enable); - s.integer(status.rumble); - - s.integer(status.logoDetected); - s.integer(status.logoCounter); - - s.integer(status.packet); - s.integer(status.send); - s.integer(status.recv); - - s.integer(status.timeout); -} diff --git a/higan/gba/ppu/background.cpp b/higan/gba/ppu/background.cpp deleted file mode 100644 index 06afbe82..00000000 --- a/higan/gba/ppu/background.cpp +++ /dev/null @@ -1,189 +0,0 @@ -//I/O settings shared by all background layers -uint3 PPU::Background::IO::mode; -uint1 PPU::Background::IO::frame; -uint5 PPU::Background::IO::mosaicWidth; -uint5 PPU::Background::IO::mosaicHeight; - -auto PPU::Background::scanline(uint y) -> void { - mosaicOffset = 0; -} - -auto PPU::Background::run(uint x, uint y) -> void { - output = {}; - if(ppu.blank() || !io.enable) { - mosaic = {}; - return; - } - - switch(id) { - case PPU::BG0: - if(io.mode <= 1) { linear(x, y); break; } - break; - - case PPU::BG1: - if(io.mode <= 1) { linear(x, y); break; } - break; - - case PPU::BG2: - if(io.mode == 0) { linear(x, y); break; } - if(io.mode <= 2) { affine(x, y); break; } - if(io.mode <= 5) { bitmap(x, y); break; } - break; - - case PPU::BG3: - if(io.mode == 0) { linear(x, y); break; } - if(io.mode == 2) { affine(x, y); break; } - break; - } - - //horizontal mosaic - if(!io.mosaic || ++mosaicOffset >= 1 + io.mosaicWidth) { - mosaicOffset = 0; - mosaic = output; - } -} - -auto PPU::Background::linear(uint x, uint y) -> void { - if(x == 0) { - if(!io.mosaic || (y % (1 + io.mosaicHeight)) == 0) { - vmosaic = y; - } - fx = io.hoffset; - fy = vmosaic + io.voffset; - } - - uint3 px = fx; - uint3 py = fy; - - if(x == 0 || px == 0) { - uint6 tx = fx >> 3; - uint6 ty = fy >> 3; - - uint offset = (ty & 31) << 5 | (tx & 31); - if(io.screenSize.bit(0) && (tx & 32)) offset += 32 << 5; - if(io.screenSize.bit(1) && (ty & 32)) offset += 32 << 5 + io.screenSize.bit(0); - offset = (io.screenBase << 11) + (offset << 1); - - uint16 tilemap = ppu.readVRAM(Half, offset); - latch.character = tilemap.bits(0,9); - latch.hflip = tilemap.bit(10); - latch.vflip = tilemap.bit(11); - latch.palette = tilemap.bits(12,15); - } - - if(latch.hflip) px = ~px; - if(latch.vflip) py = ~py; - - if(io.colorMode == 0) { - uint offset = (io.characterBase << 14) + (latch.character << 5) + (py << 2) + (px >> 1); - if(uint4 color = ppu.readVRAM(Byte, offset) >> (px & 1 ? 4 : 0)) { - output.enable = true; - output.priority = io.priority; - output.color = ppu.pram[latch.palette << 4 | color]; - } - } else { - uint offset = (io.characterBase << 14) + (latch.character << 6) + (py << 3) + (px); - if(uint8 color = ppu.readVRAM(Byte, offset)) { - output.enable = true; - output.priority = io.priority; - output.color = ppu.pram[color]; - } - } - - fx++; -} - -auto PPU::Background::affine(uint x, uint y) -> void { - if(x == 0) { - if(!io.mosaic || (y % (1 + io.mosaicHeight)) == 0) { - hmosaic = io.lx; - vmosaic = io.ly; - } - fx = hmosaic; - fy = vmosaic; - } - - uint screenSize = 16 << io.screenSize; - uint screenWrap = (1 << (io.affineWrap ? 7 + io.screenSize : 20)) - 1; - - uint cx = (fx >> 8) & screenWrap; - uint cy = (fy >> 8) & screenWrap; - - uint tx = cx >> 3; - uint ty = cy >> 3; - - uint3 px = cx; - uint3 py = cy; - - if(tx < screenSize && ty < screenSize) { - uint8 character = ppu.vram[(io.screenBase << 11) + ty * screenSize + tx]; - if(uint8 color = ppu.vram[(io.characterBase << 14) + (character << 6) + (py << 3) + px]) { - output.enable = true; - output.priority = io.priority; - output.color = ppu.pram[color]; - } - } - - fx += io.pa; - fy += io.pc; - - if(x == 239) { - io.lx += io.pb; - io.ly += io.pd; - } -} - -auto PPU::Background::bitmap(uint x, uint y) -> void { - if(x == 0) { - if(!io.mosaic || (y % (1 + io.mosaicHeight)) == 0) { - hmosaic = io.lx; - vmosaic = io.ly; - } - fx = hmosaic; - fy = vmosaic; - } - - uint1 depth = io.mode != 4; //0 = 8-bit (mode 4); 1 = 15-bit (mode 3, mode 5) - uint width = io.mode == 5 ? 160 : 240; - uint height = io.mode == 5 ? 128 : 160; - uint mode = depth ? Half : Byte; - - uint baseAddress = io.mode == 3 ? 0 : 0xa000 * io.frame; - - uint px = fx >> 8; - uint py = fy >> 8; - - if(px < width && py < height) { - uint offset = py * width + px; - uint15 color = ppu.readVRAM(mode, baseAddress + (offset << depth)); - - if(depth || color) { //8bpp color 0 is transparent; 15bpp color is always opaque - if(depth == 0) color = ppu.pram[color]; - output.enable = true; - output.priority = io.priority; - output.color = color; - } - } - - fx += io.pa; - fy += io.pc; - - if(x == 239) { - io.lx += io.pb; - io.ly += io.pd; - } -} - -auto PPU::Background::power(uint id) -> void { - this->id = id; - - io = {}; - latch = {}; - output = {}; - mosaic = {}; - mosaicOffset = 0; - hmosaic = 0; - vmosaic = 0; - fx = 0; - fy = 0; -} diff --git a/higan/gba/ppu/io.cpp b/higan/gba/ppu/io.cpp deleted file mode 100644 index d4916451..00000000 --- a/higan/gba/ppu/io.cpp +++ /dev/null @@ -1,385 +0,0 @@ -auto PPU::readIO(uint32 addr) -> uint8 { - switch(addr) { - - //DISPCNT - case 0x0400'0000: return ( - Background::IO::mode << 0 - | io.gameBoyColorMode << 3 - | Background::IO::frame << 4 - | objects.io.hblank << 5 - | objects.io.mapping << 6 - | io.forceBlank << 7 - ); - case 0x0400'0001: return ( - bg0.io.enable << 0 - | bg1.io.enable << 1 - | bg2.io.enable << 2 - | bg3.io.enable << 3 - | objects.io.enable << 4 - | window0.io.enable << 5 - | window1.io.enable << 6 - | window2.io.enable << 7 - ); - - //GRSWP - case 0x0400'0002: return io.greenSwap; - case 0x0400'0003: return 0; - - //DISPSTAT - case 0x0400'0004: return ( - io.vblank << 0 - | io.hblank << 1 - | io.vcoincidence << 2 - | io.irqvblank << 3 - | io.irqhblank << 4 - | io.irqvcoincidence << 5 - ); - case 0x0400'0005: return ( - io.vcompare - ); - - //VCOUNT - case 0x0400'0006: return io.vcounter.byte(0); - case 0x0400'0007: return io.vcounter.byte(1); - - //BG0CNT - case 0x0400'0008: return bg0.io.priority << 0 | bg0.io.characterBase << 2 | bg0.io.unused << 4 | bg0.io.mosaic << 6 | bg0.io.colorMode << 7; - case 0x0400'0009: return bg0.io.screenBase << 0 | bg0.io.affineWrap << 5 | bg0.io.screenSize << 6; - - //BG1CNT - case 0x0400'000a: return bg1.io.priority << 0 | bg1.io.characterBase << 2 | bg1.io.unused << 4 | bg1.io.mosaic << 6 | bg1.io.colorMode << 7; - case 0x0400'000b: return bg1.io.screenBase << 0 | bg1.io.affineWrap << 5 | bg1.io.screenSize << 6; - - //BG2CNT - case 0x0400'000c: return bg2.io.priority << 0 | bg2.io.characterBase << 2 | bg2.io.unused << 4 | bg2.io.mosaic << 6 | bg2.io.colorMode << 7; - case 0x0400'000d: return bg2.io.screenBase << 0 | bg2.io.affineWrap << 5 | bg2.io.screenSize << 6; - - //BG3CNT - case 0x0400'000e: return bg3.io.priority << 0 | bg3.io.characterBase << 2 | bg3.io.unused << 4 | bg3.io.mosaic << 6 | bg3.io.colorMode << 7; - case 0x0400'000f: return bg3.io.screenBase << 0 | bg3.io.affineWrap << 5 | bg3.io.screenSize << 6; - - //WININ0 - case 0x0400'0048: return window0.io.active[BG0] << 0 | window0.io.active[BG1] << 1 | window0.io.active[BG2] << 2 | window0.io.active[BG3] << 3 | window0.io.active[OBJ] << 4 | window0.io.active[SFX] << 5; - - //WININ1 - case 0x0400'0049: return window1.io.active[BG0] << 0 | window1.io.active[BG1] << 1 | window1.io.active[BG2] << 2 | window1.io.active[BG3] << 3 | window1.io.active[OBJ] << 4 | window1.io.active[SFX] << 5; - - //WINOUT - case 0x0400'004a: return window3.io.active[BG0] << 0 | window3.io.active[BG1] << 1 | window3.io.active[BG2] << 2 | window3.io.active[BG3] << 3 | window3.io.active[OBJ] << 4 | window3.io.active[SFX] << 5; - - //WININ2 - case 0x0400'004b: return window2.io.active[BG0] << 0 | window2.io.active[BG1] << 1 | window2.io.active[BG2] << 2 | window2.io.active[BG3] << 3 | window2.io.active[OBJ] << 4 | window2.io.active[SFX] << 5; - - //MOSAIC (write-only) - - //BLTCNT - case 0x0400'0050: return ( - screen.io.blendAbove[BG0] << 0 - | screen.io.blendAbove[BG1] << 1 - | screen.io.blendAbove[BG2] << 2 - | screen.io.blendAbove[BG3] << 3 - | screen.io.blendAbove[OBJ] << 4 - | screen.io.blendAbove[SFX] << 5 - | screen.io.blendMode << 6 - ); - case 0x0400'0051: return ( - screen.io.blendBelow[BG0] << 0 - | screen.io.blendBelow[BG1] << 1 - | screen.io.blendBelow[BG2] << 2 - | screen.io.blendBelow[BG3] << 3 - | screen.io.blendBelow[OBJ] << 4 - | screen.io.blendBelow[SFX] << 5 - ); - - //BLDALPHA - case 0x0400'0052: return screen.io.blendEVA; - case 0x0400'0053: return screen.io.blendEVB; - - //BLDY (write-only) - - } - - return cpu.pipeline.fetch.instruction.byte(addr & 1); -} - -auto PPU::writeIO(uint32 addr, uint8 data) -> void { - switch(addr) { - - //DISPCNT - case 0x0400'0000: - Background::IO::mode = data.bits(0,2); - io.gameBoyColorMode = data.bit (3); - Background::IO::frame = data.bit (4); - objects.io.hblank = data.bit (5); - objects.io.mapping = data.bit (6); - io.forceBlank = data.bit (7); - return; - case 0x0400'0001: - bg0.io.enable = data.bit(0); - bg1.io.enable = data.bit(1); - bg2.io.enable = data.bit(2); - bg3.io.enable = data.bit(3); - objects.io.enable = data.bit(4); - window0.io.enable = data.bit(5); - window1.io.enable = data.bit(6); - window2.io.enable = data.bit(7); - //outside window is enabled whenever any inside window is enabled - window3.io.enable = (bool)data.bits(5,7); - return; - - //GRSWP - case 0x0400'0002: - io.greenSwap = data.bit(0); - return; - case 0x0400'0003: - return; - - //DISPSTAT - case 0x0400'0004: - io.irqvblank = data.bit(3); - io.irqhblank = data.bit(4); - io.irqvcoincidence = data.bit(5); - return; - case 0x0400'0005: - io.vcompare = data; - return; - - //BG0CNT - case 0x0400'0008: - bg0.io.priority = data.bits(0,1); - bg0.io.characterBase = data.bits(2,3); - bg0.io.unused = data.bits(4,5); - bg0.io.mosaic = data.bit (6); - bg0.io.colorMode = data.bit (7); - return; - case 0x0400'0009: - bg0.io.screenBase = data.bits(0,4); - bg0.io.affineWrap = false; - bg0.io.screenSize = data.bits(6,7); - return; - - //BG1CNT - case 0x0400'000a: - bg1.io.priority = data.bits(0,1); - bg1.io.characterBase = data.bits(2,3); - bg1.io.unused = data.bits(4,5); - bg1.io.mosaic = data.bit (6); - bg1.io.colorMode = data.bit (7); - return; - case 0x0400'000b: - bg1.io.screenBase = data.bits(0,4); - bg1.io.affineWrap = false; - bg1.io.screenSize = data.bits(6,7); - return; - - //BG2CNT - case 0x0400'000c: - bg2.io.priority = data.bits(0,1); - bg2.io.characterBase = data.bits(2,3); - bg2.io.unused = data.bits(4,5); - bg2.io.mosaic = data.bit (6); - bg2.io.colorMode = data.bit (7); - return; - case 0x0400'000d: - bg2.io.screenBase = data.bits(0,4); - bg2.io.affineWrap = data.bit (5); - bg2.io.screenSize = data.bits(6,7); - return; - - //BG3CNT - case 0x0400'000e: - bg3.io.priority = data.bits(0,1); - bg3.io.characterBase = data.bits(2,3); - bg3.io.unused = data.bits(4,5); - bg3.io.mosaic = data.bit (6); - bg3.io.colorMode = data.bit (7); - return; - case 0x0400'000f: - bg3.io.screenBase = data.bits(0,4); - bg3.io.affineWrap = data.bit (5); - bg3.io.screenSize = data.bits(6,7); - return; - - //BG0HOFS - case 0x0400'0010: bg0.io.hoffset.bits(0,7) = data.bits(0,7); return; - case 0x0400'0011: bg0.io.hoffset.bit (8) = data.bit (0); return; - - //BG0VOFS - case 0x0400'0012: bg0.io.voffset.bits(0,7) = data.bits(0,7); return; - case 0x0400'0013: bg0.io.voffset.bit (8) = data.bit (0); return; - - //BG1HOFS - case 0x0400'0014: bg1.io.hoffset.bits(0,7) = data.bits(0,7); return; - case 0x0400'0015: bg1.io.hoffset.bit (8) = data.bit (0); return; - - //BG1VOFS - case 0x0400'0016: bg1.io.voffset.bits(0,7) = data.bits(0,7); return; - case 0x0400'0017: bg1.io.voffset.bit (8) = data.bit (0); return; - - //BG2HOFS - case 0x0400'0018: bg2.io.hoffset.bits(0,7) = data.bits(0,7); return; - case 0x0400'0019: bg2.io.hoffset.bit (8) = data.bit (0); return; - - //BG2VOFS - case 0x0400'001a: bg2.io.voffset.bits(0,7) = data.bits(0,7); return; - case 0x0400'001b: bg2.io.voffset.bit (8) = data.bit (0); return; - - //BG3HOFS - case 0x0400'001c: bg3.io.hoffset.bits(0,7) = data.bits(0,7); return; - case 0x0400'001d: bg3.io.hoffset.bit (8) = data.bit (0); return; - - //BG3VOFS - case 0x0400'001e: bg3.io.voffset.bits(0,7) = data.bits(0,7); return; - case 0x0400'001f: bg3.io.voffset.bit (8) = data.bit (0); return; - - //BG2PA - case 0x0400'0020: bg2.io.pa.byte(0) = data; return; - case 0x0400'0021: bg2.io.pa.byte(1) = data; return; - - //BG2PB - case 0x0400'0022: bg2.io.pb.byte(0) = data; return; - case 0x0400'0023: bg2.io.pb.byte(1) = data; return; - - //BG2PC - case 0x0400'0024: bg2.io.pc.byte(0) = data; return; - case 0x0400'0025: bg2.io.pc.byte(1) = data; return; - - //BG2PD - case 0x0400'0026: bg2.io.pd.byte(0) = data; return; - case 0x0400'0027: bg2.io.pd.byte(1) = data; return; - - //BG2X - case 0x0400'0028: bg2.io.x.bits( 0, 7) = data.bits(0,7); bg2.io.lx = bg2.io.x; return; - case 0x0400'0029: bg2.io.x.bits( 8,15) = data.bits(0,7); bg2.io.lx = bg2.io.x; return; - case 0x0400'002a: bg2.io.x.bits(16,23) = data.bits(0,7); bg2.io.lx = bg2.io.x; return; - case 0x0400'002b: bg2.io.x.bits(24,27) = data.bits(0,3); bg2.io.lx = bg2.io.x; return; - - //BG2Y - case 0x0400'002c: bg2.io.y.bits( 0, 7) = data.bits(0,7); bg2.io.ly = bg2.io.y; return; - case 0x0400'002d: bg2.io.y.bits( 8,15) = data.bits(0,7); bg2.io.ly = bg2.io.y; return; - case 0x0400'002e: bg2.io.y.bits(16,23) = data.bits(0,7); bg2.io.ly = bg2.io.y; return; - case 0x0400'002f: bg2.io.y.bits(24,27) = data.bits(0,3); bg2.io.ly = bg2.io.y; return; - - //BG3PA - case 0x0400'0030: bg3.io.pa.byte(0) = data; return; - case 0x0400'0031: bg3.io.pa.byte(1) = data; return; - - //BG3PB - case 0x0400'0032: bg3.io.pb.byte(0) = data; return; - case 0x0400'0033: bg3.io.pb.byte(1) = data; return; - - //BG3PC - case 0x0400'0034: bg3.io.pc.byte(0) = data; return; - case 0x0400'0035: bg3.io.pc.byte(1) = data; return; - - //BG3PD - case 0x0400'0036: bg3.io.pd.byte(0) = data; return; - case 0x0400'0037: bg3.io.pd.byte(1) = data; return; - - //BG3X - case 0x0400'0038: bg3.io.x.bits( 0, 7) = data.bits(0,7); bg3.io.lx = bg3.io.x; return; - case 0x0400'0039: bg3.io.x.bits( 8,15) = data.bits(0,7); bg3.io.lx = bg3.io.x; return; - case 0x0400'003a: bg3.io.x.bits(16,23) = data.bits(0,7); bg3.io.lx = bg3.io.x; return; - case 0x0400'003b: bg3.io.x.bits(24,27) = data.bits(0,3); bg3.io.lx = bg3.io.x; return; - - //BG3Y - case 0x0400'003c: bg3.io.y.bits( 0, 7) = data.bits(0,7); bg3.io.ly = bg3.io.y; return; - case 0x0400'003d: bg3.io.y.bits( 8,15) = data.bits(0,7); bg3.io.ly = bg3.io.y; return; - case 0x0400'003e: bg3.io.y.bits(16,23) = data.bits(0,7); bg3.io.ly = bg3.io.y; return; - case 0x0400'003f: bg3.io.y.bits(24,27) = data.bits(0,3); bg3.io.ly = bg3.io.y; return; - - //WIN0H - case 0x0400'0040: window0.io.x2 = data; return; - case 0x0400'0041: window0.io.x1 = data; return; - - //WIN1H - case 0x0400'0042: window1.io.x2 = data; return; - case 0x0400'0043: window1.io.x1 = data; return; - - //WIN0V - case 0x0400'0044: window0.io.y2 = data; return; - case 0x0400'0045: window0.io.y1 = data; return; - - //WIN1V - case 0x0400'0046: window1.io.y2 = data; return; - case 0x0400'0047: window1.io.y1 = data; return; - - //WININ0 - case 0x0400'0048: - window0.io.active[BG0] = data.bit(0); - window0.io.active[BG1] = data.bit(1); - window0.io.active[BG2] = data.bit(2); - window0.io.active[BG3] = data.bit(3); - window0.io.active[OBJ] = data.bit(4); - window0.io.active[SFX] = data.bit(5); - return; - - //WININ1 - case 0x0400'0049: - window1.io.active[BG0] = data.bit(0); - window1.io.active[BG1] = data.bit(1); - window1.io.active[BG2] = data.bit(2); - window1.io.active[BG3] = data.bit(3); - window1.io.active[OBJ] = data.bit(4); - window1.io.active[SFX] = data.bit(5); - return; - - //WINOUT - case 0x0400'004a: - window3.io.active[BG0] = data.bit(0); - window3.io.active[BG1] = data.bit(1); - window3.io.active[BG2] = data.bit(2); - window3.io.active[BG3] = data.bit(3); - window3.io.active[OBJ] = data.bit(4); - window3.io.active[SFX] = data.bit(5); - return; - - //WININ2 - case 0x0400'004b: - window2.io.active[BG0] = data.bit(0); - window2.io.active[BG1] = data.bit(1); - window2.io.active[BG2] = data.bit(2); - window2.io.active[BG3] = data.bit(3); - window2.io.active[OBJ] = data.bit(4); - window2.io.active[SFX] = data.bit(5); - return; - - //MOSAIC - case 0x0400'004c: - Background::IO::mosaicWidth = data.bits(0,3); - Background::IO::mosaicHeight = data.bits(4,7); - return; - case 0x0400'004d: - objects.io.mosaicWidth = data.bits(0,3); - objects.io.mosaicHeight = data.bits(4,7); - return; - - //BLDCNT - case 0x0400'0050: - screen.io.blendAbove[BG0] = data.bit (0); - screen.io.blendAbove[BG1] = data.bit (1); - screen.io.blendAbove[BG2] = data.bit (2); - screen.io.blendAbove[BG3] = data.bit (3); - screen.io.blendAbove[OBJ] = data.bit (4); - screen.io.blendAbove[SFX] = data.bit (5); - screen.io.blendMode = data.bits(6,7); - return; - case 0x0400'0051: - screen.io.blendBelow[BG0] = data.bit(0); - screen.io.blendBelow[BG1] = data.bit(1); - screen.io.blendBelow[BG2] = data.bit(2); - screen.io.blendBelow[BG3] = data.bit(3); - screen.io.blendBelow[OBJ] = data.bit(4); - screen.io.blendBelow[SFX] = data.bit(5); - return; - - //BLDALPHA - case 0x0400'0052: screen.io.blendEVA = data.bits(0,4); return; - case 0x0400'0053: screen.io.blendEVB = data.bits(0,4); return; - - //BLDY - case 0x0400'0054: screen.io.blendEVY = data.bits(0,4); return; - case 0x0400'0055: return; - - } -} diff --git a/higan/gba/ppu/memory.cpp b/higan/gba/ppu/memory.cpp deleted file mode 100644 index b74ccd9f..00000000 --- a/higan/gba/ppu/memory.cpp +++ /dev/null @@ -1,178 +0,0 @@ -auto PPU::readVRAM(uint mode, uint32 addr) -> uint32 { - addr &= (addr & 0x10000) ? 0x17fff : 0x0ffff; - - if(mode & Word) { - addr &= ~3; - return vram[addr + 0] << 0 | vram[addr + 1] << 8 | vram[addr + 2] << 16 | vram[addr + 3] << 24; - } else if(mode & Half) { - addr &= ~1; - return vram[addr + 0] << 0 | vram[addr + 1] << 8; - } else if(mode & Byte) { - return vram[addr]; - } - - unreachable; -} - -auto PPU::writeVRAM(uint mode, uint32 addr, uint32 word) -> void { - addr &= (addr & 0x10000) ? 0x17fff : 0x0ffff; - - if(mode & Word) { - addr &= ~3; - vram[addr + 0] = word >> 0; - vram[addr + 1] = word >> 8; - vram[addr + 2] = word >> 16; - vram[addr + 3] = word >> 24; - } else if(mode & Half) { - addr &= ~1; - vram[addr + 0] = word >> 0; - vram[addr + 1] = word >> 8; - } else if(mode & Byte) { - //8-bit writes to OBJ section of VRAM are ignored - if(Background::IO::mode <= 2 && addr >= 0x10000) return; - if(Background::IO::mode <= 5 && addr >= 0x14000) return; - - addr &= ~1; - vram[addr + 0] = (uint8)word; - vram[addr + 1] = (uint8)word; - } -} - -auto PPU::readPRAM(uint mode, uint32 addr) -> uint32 { - if(mode & Word) return readPRAM(Half, addr & ~2) << 0 | readPRAM(Half, addr | 2) << 16; - if(mode & Byte) return readPRAM(Half, addr) >> ((addr & 1) * 8); - return pram[addr >> 1 & 511]; -} - -auto PPU::writePRAM(uint mode, uint32 addr, uint32 word) -> void { - if(mode & Word) { - writePRAM(Half, addr & ~2, word >> 0); - writePRAM(Half, addr | 2, word >> 16); - return; - } - - if(mode & Byte) { - word = (uint8)word; - return writePRAM(Half, addr, word << 8 | word << 0); - } - - pram[addr >> 1 & 511] = (uint16)word; -} - -auto PPU::readOAM(uint mode, uint32 addr) -> uint32 { - if(mode & Word) return readOAM(Half, addr & ~2) << 0 | readOAM(Half, addr | 2) << 16; - if(mode & Byte) return readOAM(Half, addr) >> ((addr & 1) * 8); - - auto& obj = object[addr >> 3 & 127]; - auto& par = objectParam[addr >> 5 & 31]; - - switch(addr & 6) { - - case 0: return ( - (obj.y << 0) - | (obj.affine << 8) - | (obj.affineSize << 9) - | (obj.mode << 10) - | (obj.mosaic << 12) - | (obj.colors << 13) - | (obj.shape << 14) - ); - - case 2: return ( - (obj.x << 0) - | (obj.affineParam << 9) - | (obj.hflip << 12) - | (obj.vflip << 13) - | (obj.size << 14) - ); - - case 4: return ( - (obj.character << 0) - | (obj.priority << 10) - | (obj.palette << 12) - ); - - case 6: - switch(addr >> 3 & 3) { - case 0: return par.pa; - case 1: return par.pb; - case 2: return par.pc; - case 3: return par.pd; - } - - } - - unreachable; -} - -auto PPU::writeOAM(uint mode, uint32 addr, uint32 word) -> void { - if(mode & Word) { - writeOAM(Half, addr & ~2, word >> 0); - writeOAM(Half, addr | 2, word >> 16); - return; - } - - if(mode & Byte) return; //8-bit writes to OAM are ignored - - auto& obj = object[addr >> 3 & 127]; - auto& par = objectParam[addr >> 5 & 31]; - switch(addr & 6) { - - case 0: - obj.y = word >> 0; - obj.affine = word >> 8; - obj.affineSize = word >> 9; - obj.mode = word >> 10; - obj.mosaic = word >> 12; - obj.colors = word >> 13; - obj.shape = word >> 14; - break; - - case 2: - obj.x = word >> 0; - obj.affineParam = word >> 9; - obj.hflip = word >> 12; - obj.vflip = word >> 13; - obj.size = word >> 14; - break; - - case 4: - obj.character = word >> 0; - obj.priority = word >> 10; - obj.palette = word >> 12; - break; - - case 6: - switch(addr >> 3 & 3) { - case 0: par.pa = word; break; - case 1: par.pb = word; break; - case 2: par.pc = word; break; - case 3: par.pd = word; break; - } - - } - - static uint widths[] = { - 8, 16, 32, 64, - 16, 32, 32, 64, - 8, 8, 16, 32, - 8, 8, 8, 8, //invalid modes - }; - - static uint heights[] = { - 8, 16, 32, 64, - 8, 8, 16, 32, - 16, 32, 32, 64, - 8, 8, 8, 8, //invalid modes - }; - - obj.width = widths [obj.shape * 4 + obj.size]; - obj.height = heights[obj.shape * 4 + obj.size]; -} - -auto PPU::readObjectVRAM(uint addr) const -> uint8 { - if(Background::IO::mode == 3 || Background::IO::mode == 4 || Background::IO::mode == 5) { - if(addr <= 0x3fff) return 0u; - } - return vram[0x10000 + (addr & 0x7fff)]; -} diff --git a/higan/gba/ppu/object.cpp b/higan/gba/ppu/object.cpp deleted file mode 100644 index b194d99b..00000000 --- a/higan/gba/ppu/object.cpp +++ /dev/null @@ -1,95 +0,0 @@ -auto PPU::Objects::scanline(uint y) -> void { - mosaicOffset = 0; - for(auto& pixel : buffer) pixel = {}; - if(ppu.blank() || !io.enable) return; - - for(auto& object : ppu.object) { - uint8 py = y - object.y; - if(object.affine == 0 && object.affineSize == 1) continue; //hidden - if(py >= object.height << object.affineSize) continue; //offscreen - - uint rowSize = io.mapping == 0 ? 32 >> object.colors : object.width >> 3; - uint baseAddress = object.character << 5; - - if(object.mosaic && io.mosaicHeight) { - int mosaicY = (y / (1 + io.mosaicHeight)) * (1 + io.mosaicHeight); - py = object.y >= 160 || mosaicY - object.y >= 0 ? uint(mosaicY - object.y) : 0; - } - - int16 pa = ppu.objectParam[object.affineParam].pa; - int16 pb = ppu.objectParam[object.affineParam].pb; - int16 pc = ppu.objectParam[object.affineParam].pc; - int16 pd = ppu.objectParam[object.affineParam].pd; - - //center-of-sprite coordinates - int16 centerX = object.width >> 1; - int16 centerY = object.height >> 1; - - //origin coordinates (top-left of sprite) - int28 originX = -(centerX << object.affineSize); - int28 originY = -(centerY << object.affineSize) + py; - - //fractional pixel coordinates - int28 fx = originX * pa + originY * pb; - int28 fy = originX * pc + originY * pd; - - for(uint px : range(object.width << object.affineSize)) { - uint sx, sy; - if(!object.affine) { - sx = px ^ (object.hflip ? object.width - 1 : 0); - sy = py ^ (object.vflip ? object.height - 1 : 0); - } else { - sx = (fx >> 8) + centerX; - sy = (fy >> 8) + centerY; - } - - uint9 bx = object.x + px; - if(bx < 240 && sx < object.width && sy < object.height) { - uint offset = (sy >> 3) * rowSize + (sx >> 3); - offset = offset * 64 + (sy & 7) * 8 + (sx & 7); - - uint8 color = ppu.readObjectVRAM(baseAddress + (offset >> !object.colors)); - if(object.colors == 0) color = sx & 1 ? color >> 4 : color & 15; - if(color) { - if(object.mode & 2) { - buffer[bx].window = true; - } else if(!buffer[bx].enable || object.priority < buffer[bx].priority) { - if(object.colors == 0) color = object.palette * 16 + color; - buffer[bx].enable = true; - buffer[bx].priority = object.priority; - buffer[bx].color = ppu.pram[256 + color]; - buffer[bx].translucent = object.mode == 1; - buffer[bx].mosaic = object.mosaic; - } - } - } - - fx += pa; - fy += pc; - } - } -} - -auto PPU::Objects::run(uint x, uint y) -> void { - output = {}; - if(ppu.blank() || !io.enable) { - mosaic = {}; - return; - } - - output = buffer[x]; - - //horizontal mosaic - if(!output.mosaic || ++mosaicOffset >= 1 + io.mosaicWidth) { - mosaicOffset = 0; - mosaic = output; - } -} - -auto PPU::Objects::power() -> void { - io = {}; - for(auto& pixel : buffer) pixel = {}; - output = {}; - mosaic = {}; - mosaicOffset = 0; -} diff --git a/higan/gba/ppu/ppu.cpp b/higan/gba/ppu/ppu.cpp deleted file mode 100644 index f601b051..00000000 --- a/higan/gba/ppu/ppu.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include - -//pixel: 4 cycles - -//hdraw: 240 pixels ( 960 cycles) -//hblank: 68 pixels ( 272 cycles) -//scanline: 308 pixels (1232 cycles) - -//vdraw: 160 scanlines (197120 cycles) -//vblank: 68 scanlines ( 83776 cycles) -//frame: 228 scanlines (280896 cycles) - -namespace GameBoyAdvance { - -PPU ppu; -#include "background.cpp" -#include "object.cpp" -#include "window.cpp" -#include "screen.cpp" -#include "io.cpp" -#include "memory.cpp" -#include "serialization.cpp" - -auto PPU::blank() -> bool { - return io.forceBlank || cpu.stopped(); -} - -PPU::PPU() { - output = new uint32[240 * 160]; -} - -PPU::~PPU() { - delete[] output; -} - -auto PPU::Enter() -> void { - while(true) scheduler.synchronize(), ppu.main(); -} - -auto PPU::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); -} - -auto PPU::main() -> void { - cpu.keypad.run(); - - io.vblank = io.vcounter >= 160 && io.vcounter <= 226; - io.vcoincidence = io.vcounter == io.vcompare; - - if(io.vcounter == 0) { - frame(); - - bg2.io.lx = bg2.io.x; - bg2.io.ly = bg2.io.y; - - bg3.io.lx = bg3.io.x; - bg3.io.ly = bg3.io.y; - } - - if(io.vcounter == 160) { - if(io.irqvblank) cpu.irq.flag |= CPU::Interrupt::VBlank; - cpu.dmaVblank(); - } - - if(io.irqvcoincidence) { - if(io.vcoincidence) cpu.irq.flag |= CPU::Interrupt::VCoincidence; - } - - if(io.vcounter < 160) { - uint y = io.vcounter; - bg0.scanline(y); - bg1.scanline(y); - bg2.scanline(y); - bg3.scanline(y); - objects.scanline(y); - for(uint x : range(240)) { - bg0.run(x, y); - bg1.run(x, y); - bg2.run(x, y); - bg3.run(x, y); - objects.run(x, y); - window0.run(x, y); - window1.run(x, y); - window2.output = objects.output.window; - window3.output = true; - uint15 color = screen.run(x, y); - output[y * 240 + x] = color; - step(4); - } - } else { - step(960); - } - - io.hblank = 1; - if(io.irqhblank) cpu.irq.flag |= CPU::Interrupt::HBlank; - if(io.vcounter < 160) cpu.dmaHblank(); - - step(240); - io.hblank = 0; - if(io.vcounter < 160) cpu.dmaHDMA(); - - step(32); - if(++io.vcounter == 228) io.vcounter = 0; -} - -auto PPU::frame() -> void { - player.frame(); - scheduler.exit(Scheduler::Event::Frame); -} - -auto PPU::refresh() -> void { - Emulator::video.refresh(output, 240 * sizeof(uint32), 240, 160); -} - -auto PPU::power() -> void { - create(PPU::Enter, system.frequency()); - - for(uint n = 0x000; n <= 0x055; n++) bus.io[n] = this; - - for(uint n = 0; n < 240 * 160; n++) output[n] = 0; - - for(uint n = 0; n < 96 * 1024; n++) vram[n] = 0x00; - for(uint n = 0; n < 1024; n += 2) writePRAM(n, Half, 0x0000); - for(uint n = 0; n < 1024; n += 2) writeOAM(n, Half, 0x0000); - - io = {}; - for(auto& object : this->object) object = {}; - for(auto& param : this->objectParam) param = {}; - - bg0.power(BG0); - bg1.power(BG1); - bg2.power(BG2); - bg3.power(BG3); - objects.power(); - window0.power(IN0); - window1.power(IN1); - window2.power(IN2); - window3.power(OUT); - screen.power(); -} - -} diff --git a/higan/gba/ppu/ppu.hpp b/higan/gba/ppu/ppu.hpp deleted file mode 100644 index ac287704..00000000 --- a/higan/gba/ppu/ppu.hpp +++ /dev/null @@ -1,229 +0,0 @@ -struct PPU : Thread, IO { - PPU(); - ~PPU(); - - inline auto blank() -> bool; - - static auto Enter() -> void; - auto step(uint clocks) -> void; - auto main() -> void; - - auto frame() -> void; - auto refresh() -> void; - auto power() -> void; - - auto readIO(uint32 addr) -> uint8; - auto writeIO(uint32 addr, uint8 byte) -> void; - - auto readVRAM(uint mode, uint32 addr) -> uint32; - auto writeVRAM(uint mode, uint32 addr, uint32 word) -> void; - - auto readPRAM(uint mode, uint32 addr) -> uint32; - auto writePRAM(uint mode, uint32 addr, uint32 word) -> void; - - auto readOAM(uint mode, uint32 addr) -> uint32; - auto writeOAM(uint mode, uint32 addr, uint32 word) -> void; - - auto readObjectVRAM(uint addr) const -> uint8; - - auto serialize(serializer&) -> void; - - uint8 vram[96 * 1024]; - uint16 pram[512]; - uint32* output; - -private: - //note: I/O register order is {BG0-BG3, OBJ, SFX} - //however; layer ordering is {OBJ, BG0-BG3, SFX} - enum : uint { OBJ = 0, BG0 = 1, BG1 = 2, BG2 = 3, BG3 = 4, SFX = 5 }; - enum : uint { IN0 = 0, IN1 = 1, IN2 = 2, OUT = 3 }; - - struct IO { - uint1 gameBoyColorMode; - uint1 forceBlank; - uint1 greenSwap; - - uint1 vblank; - uint1 hblank; - uint1 vcoincidence; - uint1 irqvblank; - uint1 irqhblank; - uint1 irqvcoincidence; - uint8 vcompare; - - uint16 vcounter; - } io; - - struct Pixel { - uint1 enable; - uint2 priority; - uint15 color; - - //OBJ only - uint1 translucent; - uint1 mosaic; - uint1 window; //IN2 - }; - - struct Background { - auto scanline(uint y) -> void; - auto run(uint x, uint y) -> void; - auto linear(uint x, uint y) -> void; - auto affine(uint x, uint y) -> void; - auto bitmap(uint x, uint y) -> void; - - auto power(uint id) -> void; - auto serialize(serializer&) -> void; - - uint id; //BG0, BG1, BG2, BG3 - - struct IO { - static uint3 mode; - static uint1 frame; - static uint5 mosaicWidth; - static uint5 mosaicHeight; - - uint1 enable; - - uint2 priority; - uint2 characterBase; - uint2 unused; - uint1 mosaic; - uint1 colorMode; - uint5 screenBase; - uint1 affineWrap; //BG2, BG3 only - uint2 screenSize; - - uint9 hoffset; - uint9 voffset; - - //BG2, BG3 only - int16 pa; - int16 pb; - int16 pc; - int16 pd; - int28 x; - int28 y; - - //internal - int28 lx; - int28 ly; - } io; - - struct Latch { - uint10 character; - uint1 hflip; - uint1 vflip; - uint4 palette; - } latch; - - Pixel output; - Pixel mosaic; - uint mosaicOffset; - - uint hmosaic; - uint vmosaic; - - int28 fx; - int28 fy; - } bg0, bg1, bg2, bg3; - - struct Objects { - auto scanline(uint y) -> void; - auto run(uint x, uint y) -> void; - - auto power() -> void; - auto serialize(serializer&) -> void; - - struct IO { - uint1 enable; - - uint1 hblank; //1 = allow access to OAM during Hblank - uint1 mapping; //0 = two-dimensional, 1 = one-dimensional - uint5 mosaicWidth; - uint5 mosaicHeight; - } io; - - Pixel buffer[240]; - Pixel output; - Pixel mosaic; - uint mosaicOffset; - } objects; - - struct Window { - auto run(uint x, uint y) -> void; - - auto power(uint id) -> void; - auto serialize(serializer&) -> void; - - uint id; //IN0, IN1, IN2, OUT - - struct IO { - uint1 enable; - uint1 active[6]; - - //IN0, IN1 only - uint8 x1; - uint8 x2; - uint8 y1; - uint8 y2; - } io; - - uint1 output; //IN0, IN1, IN2 only - } window0, window1, window2, window3; - - struct Screen { - auto run(uint x, uint y) -> uint15; - auto blend(uint15 above, uint eva, uint15 below, uint evb) -> uint15; - - auto power() -> void; - auto serialize(serializer&) -> void; - - struct IO { - uint2 blendMode; - uint1 blendAbove[6]; - uint1 blendBelow[6]; - - uint5 blendEVA; - uint5 blendEVB; - uint5 blendEVY; - } io; - } screen; - - struct Object { - auto serialize(serializer&) -> void; - - uint8 y; - uint1 affine; - uint1 affineSize; - uint2 mode; - uint1 mosaic; - uint1 colors; //0 = 16, 1 = 256 - uint2 shape; //0 = square, 1 = horizontal, 2 = vertical - - uint9 x; - uint5 affineParam; - uint1 hflip; - uint1 vflip; - uint2 size; - - uint10 character; - uint2 priority; - uint4 palette; - - //ancillary data - uint width; - uint height; - } object[128]; - - struct ObjectParam { - auto serialize(serializer&) -> void; - - int16 pa; - int16 pb; - int16 pc; - int16 pd; - } objectParam[32]; -}; - -extern PPU ppu; diff --git a/higan/gba/ppu/screen.cpp b/higan/gba/ppu/screen.cpp deleted file mode 100644 index 2f3e93c0..00000000 --- a/higan/gba/ppu/screen.cpp +++ /dev/null @@ -1,69 +0,0 @@ -auto PPU::Screen::run(uint x, uint y) -> uint15 { - if(ppu.blank()) return 0x7fff; - - //determine active window - uint1 active[6] = {true, true, true, true, true, true}; //enable all layers if no windows are enabled - if(ppu.window0.io.enable || ppu.window1.io.enable || ppu.window2.io.enable) { - memory::copy(&active, &ppu.window3.io.active, sizeof(active)); - if(ppu.window2.io.enable && ppu.window2.output) memory::copy(&active, &ppu.window2.io.active, sizeof(active)); - if(ppu.window1.io.enable && ppu.window1.output) memory::copy(&active, &ppu.window1.io.active, sizeof(active)); - if(ppu.window0.io.enable && ppu.window0.output) memory::copy(&active, &ppu.window0.io.active, sizeof(active)); - } - - //priority sorting: find topmost two pixels - Pixel layers[6] = { - ppu.objects.mosaic, - ppu.bg0.mosaic, - ppu.bg1.mosaic, - ppu.bg2.mosaic, - ppu.bg3.mosaic, - {true, 3, ppu.pram[0]}, - }; - - uint aboveLayer = 5, belowLayer = 5; - for(int priority = 3; priority >= 0; priority--) { - for(int layer = 5; layer >= 0; layer--) { - if(layers[layer].enable && layers[layer].priority == priority && active[layer]) { - belowLayer = aboveLayer; - aboveLayer = layer; - } - } - } - - auto above = layers[aboveLayer]; - auto below = layers[belowLayer]; - auto eva = min(16u, (uint)io.blendEVA); - auto evb = min(16u, (uint)io.blendEVB); - auto evy = min(16u, (uint)io.blendEVY); - uint15 color = above.color; - - //color blending - if(active[SFX]) { - if(above.translucent && io.blendBelow[belowLayer]) { - color = blend(above.color, eva, below.color, evb); - } else if(io.blendMode == 1 && io.blendAbove[aboveLayer] && io.blendBelow[belowLayer]) { - color = blend(above.color, eva, below.color, evb); - } else if(io.blendMode == 2 && io.blendAbove[aboveLayer]) { - color = blend(above.color, 16 - evy, 0x7fff, evy); - } else if(io.blendMode == 3 && io.blendAbove[aboveLayer]) { - color = blend(above.color, 16 - evy, 0x0000, evy); - } - } - - return color; -} - -auto PPU::Screen::blend(uint15 above, uint eva, uint15 below, uint evb) -> uint15 { - uint5 ar = above >> 0, ag = above >> 5, ab = above >> 10; - uint5 br = below >> 0, bg = below >> 5, bb = below >> 10; - - uint r = (ar * eva + br * evb) >> 4; - uint g = (ag * eva + bg * evb) >> 4; - uint b = (ab * eva + bb * evb) >> 4; - - return min(31u, r) << 0 | min(31u, g) << 5 | min(31u, b) << 10; -} - -auto PPU::Screen::power() -> void { - io = {}; -} diff --git a/higan/gba/ppu/serialization.cpp b/higan/gba/ppu/serialization.cpp deleted file mode 100644 index 3b4dec7e..00000000 --- a/higan/gba/ppu/serialization.cpp +++ /dev/null @@ -1,124 +0,0 @@ -auto PPU::serialize(serializer& s) -> void { - Thread::serialize(s); - - s.array(vram, 96 * 1024); - s.array(pram, 512); - - s.integer(io.gameBoyColorMode); - s.integer(io.forceBlank); - s.integer(io.greenSwap); - s.integer(io.vblank); - s.integer(io.hblank); - s.integer(io.vcoincidence); - s.integer(io.irqvblank); - s.integer(io.irqhblank); - s.integer(io.irqvcoincidence); - s.integer(io.vcompare); - s.integer(io.vcounter); - - s.integer(Background::IO::mode); - s.integer(Background::IO::frame); - s.integer(Background::IO::mosaicWidth); - s.integer(Background::IO::mosaicHeight); - bg0.serialize(s); - bg1.serialize(s); - bg2.serialize(s); - bg3.serialize(s); - objects.serialize(s); - window0.serialize(s); - window1.serialize(s); - window2.serialize(s); - window3.serialize(s); - screen.serialize(s); - for(auto& object : this->object) object.serialize(s); - for(auto& param : this->objectParam) param.serialize(s); -} - -auto PPU::Background::serialize(serializer& s) -> void { - s.integer(id); - - s.integer(io.enable); - s.integer(io.priority); - s.integer(io.characterBase); - s.integer(io.unused); - s.integer(io.mosaic); - s.integer(io.colorMode); - s.integer(io.screenBase); - s.integer(io.affineWrap); - s.integer(io.screenSize); - s.integer(io.hoffset); - s.integer(io.voffset); - s.integer(io.pa); - s.integer(io.pb); - s.integer(io.pc); - s.integer(io.pd); - s.integer(io.x); - s.integer(io.y); - s.integer(io.lx); - s.integer(io.ly); - - s.integer(mosaicOffset); - s.integer(hmosaic); - s.integer(vmosaic); - s.integer(fx); - s.integer(fy); -} - -auto PPU::Objects::serialize(serializer& s) -> void { - s.integer(io.enable); - s.integer(io.hblank); - s.integer(io.mapping); - s.integer(io.mosaicWidth); - s.integer(io.mosaicHeight); - - s.integer(mosaicOffset); -} - -auto PPU::Window::serialize(serializer& s) -> void { - s.integer(id); - - s.integer(io.enable); - s.array(io.active); - s.integer(io.x1); - s.integer(io.x2); - s.integer(io.y1); - s.integer(io.y2); - - s.integer(output); -} - -auto PPU::Screen::serialize(serializer& s) -> void { - s.integer(io.blendMode); - s.array(io.blendAbove); - s.array(io.blendBelow); - s.integer(io.blendEVA); - s.integer(io.blendEVB); - s.integer(io.blendEVY); -} - -auto PPU::Object::serialize(serializer& s) -> void { - s.integer(y); - s.integer(affine); - s.integer(affineSize); - s.integer(mode); - s.integer(mosaic); - s.integer(colors); - s.integer(shape); - s.integer(x); - s.integer(affineParam); - s.integer(hflip); - s.integer(vflip); - s.integer(size); - s.integer(character); - s.integer(priority); - s.integer(palette); - s.integer(width); - s.integer(height); -} - -auto PPU::ObjectParam::serialize(serializer& s) -> void { - s.integer(pa); - s.integer(pb); - s.integer(pc); - s.integer(pd); -} diff --git a/higan/gba/ppu/window.cpp b/higan/gba/ppu/window.cpp deleted file mode 100644 index af768d13..00000000 --- a/higan/gba/ppu/window.cpp +++ /dev/null @@ -1,16 +0,0 @@ -auto PPU::Window::run(uint x, uint y) -> void { - auto x1 = io.x1, x2 = io.x2; - auto y1 = io.y1, y2 = io.y2; - - if(x2 < x1 || x2 > 240) x2 = 240; - if(y2 < y1 || y2 > 160) y2 = 160; - - output = (x >= x1 && x < x2 && y >= y1 && y < y2); -} - -auto PPU::Window::power(uint id) -> void { - this->id = id; - - io = {}; - output = 0; -} diff --git a/higan/gba/system/bios.cpp b/higan/gba/system/bios.cpp deleted file mode 100644 index 5bbca854..00000000 --- a/higan/gba/system/bios.cpp +++ /dev/null @@ -1,27 +0,0 @@ -BIOS bios; - -BIOS::BIOS() { - size = 16384; - data = new uint8[size](); -} - -BIOS::~BIOS() { - delete[] data; -} - -auto BIOS::read(uint mode, uint32 addr) -> uint32 { - //unmapped memory - if(addr >= 0x0000'4000) return cpu.pipeline.fetch.instruction; //0000'4000-01ff'ffff - - //GBA BIOS is read-protected; only the BIOS itself can read its own memory - //when accessed elsewhere; this should return the last value read by the BIOS program - if(cpu.processor.r15 >= 0x0000'4000) return mdr; - - if(mode & Word) return mdr = read(Half, addr &~ 2) << 0 | read(Half, addr | 2) << 16; - if(mode & Half) return mdr = read(Byte, addr &~ 1) << 0 | read(Byte, addr | 1) << 8; - - return mdr = data[addr]; -} - -auto BIOS::write(uint mode, uint32 addr, uint32 word) -> void { -} diff --git a/higan/gba/system/serialization.cpp b/higan/gba/system/serialization.cpp deleted file mode 100644 index c4778c54..00000000 --- a/higan/gba/system/serialization.cpp +++ /dev/null @@ -1,61 +0,0 @@ -auto System::serialize() -> serializer { - serializer s(_serializeSize); - - uint signature = 0x31545342; - char version[16] = {0}; - char description[512] = {0}; - memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size()); - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - return s; -} - -auto System::unserialize(serializer& s) -> bool { - uint signature = 0; - char version[16] = {0}; - char description[512] = {0}; - - s.integer(signature); - s.array(version); - s.array(description); - - if(signature != 0x31545342) return false; - if(string{version} != Emulator::SerializerVersion) return false; - - power(); - serializeAll(s); - return true; -} - -auto System::serialize(serializer& s) -> void { - s.integer(bios.size); - s.integer(bios.mdr); -} - -auto System::serializeAll(serializer& s) -> void { - cartridge.serialize(s); - system.serialize(s); - cpu.serialize(s); - ppu.serialize(s); - apu.serialize(s); - player.serialize(s); -} - -auto System::serializeInit() -> void { - serializer s; - - uint signature = 0; - char version[16] = {0}; - char description[512] = {0}; - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - _serializeSize = s.size(); -} diff --git a/higan/gba/system/system.cpp b/higan/gba/system/system.cpp deleted file mode 100644 index cbdbe341..00000000 --- a/higan/gba/system/system.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include - -namespace GameBoyAdvance { - -System system; -Scheduler scheduler; -#include "bios.cpp" -#include "serialization.cpp" - -auto System::init() -> void { -} - -auto System::term() -> void { -} - -auto System::power() -> void { - Emulator::video.reset(interface); - Emulator::video.setPalette(); - Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation); - Emulator::video.setEffect(Emulator::Video::Effect::RotateLeft, settings.rotateLeft); - - Emulator::audio.reset(interface); - - scheduler.reset(); - bus.power(); - player.power(); - cpu.power(); - ppu.power(); - apu.power(); - cartridge.power(); - scheduler.primary(cpu); -} - -auto System::load(Emulator::Interface* interface) -> bool { - if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else return false; - - auto document = BML::unserialize(information.manifest); - - if(auto name = document["system/cpu/rom/name"].text()) { - if(auto fp = platform->open(ID::System, name, File::Read, File::Required)) { - fp->read(bios.data, bios.size); - } else return false; - } - - if(!cartridge.load()) return false; - - serializeInit(); - this->interface = interface; - return _loaded = true; -} - -auto System::save() -> void { - if(!loaded()) return; - cartridge.save(); -} - -auto System::unload() -> void { - if(!loaded()) return; - cartridge.unload(); - _loaded = false; -} - -auto System::run() -> void { - if(scheduler.enter() == Scheduler::Event::Frame) ppu.refresh(); -} - -auto System::runToSave() -> void { - scheduler.synchronize(cpu); - scheduler.synchronize(ppu); - scheduler.synchronize(apu); - scheduler.synchronize(player); -} - -} diff --git a/higan/gba/system/system.hpp b/higan/gba/system/system.hpp deleted file mode 100644 index 7feb4722..00000000 --- a/higan/gba/system/system.hpp +++ /dev/null @@ -1,50 +0,0 @@ -enum class Input : uint { - A, B, Select, Start, Right, Left, Up, Down, R, L, -}; - -struct BIOS { - BIOS(); - ~BIOS(); - - auto read(uint mode, uint32 addr) -> uint32; - auto write(uint mode, uint32 addr, uint32 word) -> void; - - uint8* data = nullptr; - uint size = 0; - uint32 mdr = 0; -}; - -struct System { - auto loaded() const -> bool { return _loaded; } - auto frequency() const -> double { return 16 * 1024 * 1024; } - - auto init() -> void; - auto term() -> void; - auto load(Emulator::Interface*) -> bool; - auto save() -> void; - auto unload() -> void; - auto power() -> void; - auto run() -> void; - auto runToSave() -> void; - - //serialization.cpp - auto serialize() -> serializer; - auto unserialize(serializer&) -> bool; - - auto serialize(serializer&) -> void; - auto serializeAll(serializer&) -> void; - auto serializeInit() -> void; - -private: - Emulator::Interface* interface = nullptr; - - struct Information { - string manifest; - } information; - - bool _loaded = false; - uint _serializeSize = 0; -}; - -extern BIOS bios; -extern System system; diff --git a/higan/md/GNUmakefile b/higan/md/GNUmakefile deleted file mode 100644 index d79a2008..00000000 --- a/higan/md/GNUmakefile +++ /dev/null @@ -1,16 +0,0 @@ -processors += m68k z80 - -objects += md-interface -objects += md-cpu md-apu md-vdp md-psg md-ym2612 -objects += md-system md-cartridge -objects += md-controller - -obj/md-interface.o: md/interface/interface.cpp -obj/md-cpu.o: md/cpu/cpu.cpp -obj/md-apu.o: md/apu/apu.cpp -obj/md-vdp.o: md/vdp/vdp.cpp -obj/md-psg.o: md/psg/psg.cpp -obj/md-ym2612.o: md/ym2612/ym2612.cpp -obj/md-system.o: md/system/system.cpp -obj/md-cartridge.o: md/cartridge/cartridge.cpp -obj/md-controller.o: md/controller/controller.cpp diff --git a/higan/md/apu/apu.cpp b/higan/md/apu/apu.cpp deleted file mode 100644 index 03299762..00000000 --- a/higan/md/apu/apu.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include - -namespace MegaDrive { - -APU apu; -#include "bus.cpp" -#include "serialization.cpp" - -auto APU::Enter() -> void { - while(true) scheduler.synchronize(), apu.main(); -} - -auto APU::main() -> void { - if(!state.enabled) { - return step(1); - } - - if(state.nmiLine) { - state.nmiLine = 0; //edge-sensitive - irq(0, 0x0066, 0xff); - } - - if(state.intLine) { - //level-sensitive - irq(1, 0x0038, 0xff); - } - - instruction(); -} - -auto APU::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); -} - -auto APU::synchronizing() const -> bool { - return scheduler.synchronizing(); -} - -auto APU::setNMI(bool value) -> void { - state.nmiLine = value; -} - -auto APU::setINT(bool value) -> void { - state.intLine = value; -} - -auto APU::enable(bool value) -> void { - //68K cannot disable the Z80 without bus access - if(!bus->granted() && !value) return; - if(state.enabled && !value) reset(); - state.enabled = value; -} - -auto APU::power(bool reset) -> void { - Z80::bus = this; - Z80::power(); - bus->grant(false); - create(APU::Enter, system.frequency() / 15.0); - - if(!reset) memory::fill(ram, sizeof(ram)); - state = {}; -} - -auto APU::reset() -> void { - Z80::power(); - bus->grant(false); - create(APU::Enter, system.frequency() / 15.0); - state = {}; -} - -} diff --git a/higan/md/apu/apu.hpp b/higan/md/apu/apu.hpp deleted file mode 100644 index d8f5a7ad..00000000 --- a/higan/md/apu/apu.hpp +++ /dev/null @@ -1,41 +0,0 @@ -//Zilog Z80 - -struct APU : Processor::Z80, Processor::Z80::Bus, Thread { - //z80.cpp - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void override; - auto synchronizing() const -> bool override; - - auto enable(bool) -> void; - auto power(bool reset) -> void; - auto reset() -> void; - - auto setNMI(bool value) -> void; - auto setINT(bool value) -> void; - - //bus.cpp - auto read(uint16 addr) -> uint8 override; - auto write(uint16 addr, uint8 data) -> void override; - - auto in(uint8 addr) -> uint8 override; - auto out(uint8 addr, uint8 data) -> void override; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - uint8 ram[8 * 1024]; - - struct IO { - uint9 bank; - } io; - - struct State { - uint1 enabled; - uint1 nmiLine; - uint1 intLine; - } state; -}; - -extern APU apu; diff --git a/higan/md/apu/bus.cpp b/higan/md/apu/bus.cpp deleted file mode 100644 index a408d6a1..00000000 --- a/higan/md/apu/bus.cpp +++ /dev/null @@ -1,53 +0,0 @@ -auto APU::read(uint16 addr) -> uint8 { - if((addr & 0xe000) == 0x0000) { - return ram[addr]; - } - - if(addr == 0x4000) return ym2612.readStatus(); - if(addr == 0x4001) return ym2612.readStatus(); - if(addr == 0x4002) return ym2612.readStatus(); - if(addr == 0x4003) return ym2612.readStatus(); - - if((addr & 0x8000) == 0x8000) { - return cartridge.read(io.bank << 15 | (addr & 0x7ffe)).byte(!addr.bit(0)); - } - - return 0x00; -} - -auto APU::write(uint16 addr, uint8 data) -> void { - if((addr & 0xe000) == 0x0000) { - ram[addr] = data; - return; - } - - if(addr == 0x4000) return ym2612.writeAddress(0 << 8 | data); - if(addr == 0x4001) return ym2612.writeData(data); - if(addr == 0x4002) return ym2612.writeAddress(1 << 8 | data); - if(addr == 0x4003) return ym2612.writeData(data); - - if(addr == 0x6000) { - //1-bit shift register - io.bank = data.bit(0) << 8 | io.bank >> 1; - return; - } - - if(addr == 0x7f11) return psg.write(data); - if(addr == 0x7f13) return psg.write(data); - if(addr == 0x7f15) return psg.write(data); - if(addr == 0x7f17) return psg.write(data); - - if((addr & 0x8000) == 0x8000) { - //todo: do 8-bit writes mirror to 16-bits? - return cartridge.write(io.bank << 15 | (addr & 0x7ffe), data << 8 | data << 0); - } -} - -//unused on Mega Drive -auto APU::in(uint8 addr) -> uint8 { - return 0x00; -} - -//unused on Mega Drive -auto APU::out(uint8 addr, uint8 data) -> void { -} diff --git a/higan/md/apu/serialization.cpp b/higan/md/apu/serialization.cpp deleted file mode 100644 index cb590f76..00000000 --- a/higan/md/apu/serialization.cpp +++ /dev/null @@ -1,13 +0,0 @@ -auto APU::serialize(serializer& s) -> void { - Z80::serialize(s); - Z80::Bus::serialize(s); - Thread::serialize(s); - - s.array(ram); - - s.integer(io.bank); - - s.integer(state.enabled); - s.integer(state.nmiLine); - s.integer(state.intLine); -} diff --git a/higan/md/cartridge/cartridge.cpp b/higan/md/cartridge/cartridge.cpp deleted file mode 100644 index d5276ff1..00000000 --- a/higan/md/cartridge/cartridge.cpp +++ /dev/null @@ -1,297 +0,0 @@ -#include - -namespace MegaDrive { - -Cartridge cartridge; -#include "serialization.cpp" - -auto Cartridge::hashes() const -> vector { - vector hashes; - hashes.append(information.hash); - if(slot) for(auto& hash : slot->hashes()) hashes.append(hash); - return hashes; -} - -auto Cartridge::manifests() const -> vector { - vector manifests; - manifests.append(information.manifest); - if(slot) for(auto& manifest : slot->manifests()) manifests.append(manifest); - return manifests; -} - -auto Cartridge::titles() const -> vector { - vector titles; - titles.append(information.title); - if(slot) for(auto& title : slot->titles()) titles.append(title); - return titles; -} - -auto Cartridge::load() -> bool { - unload(); - - if(auto loaded = platform->load(ID::MegaDrive, "Mega Drive", "md", {"Auto", "NTSC-J", "NTSC-U", "PAL"})) { - information.pathID = loaded.pathID; - information.region = loaded.option; - } else return false; - - if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else return false; - - information.document = BML::unserialize(information.manifest); - information.hash = information.document["game/sha256"].text(); - information.title = information.document["game/label"].text(); - - if(!loadROM(rom, information.document["game/board/memory(type=ROM,content=Program)"])) { - return unload(), false; - } - - if(!loadROM(patch, information.document["game/board/memory(type=ROM,content=Patch)"])) { - patch.reset(); - } - - if(!loadRAM(ram, information.document["game/board/memory(type=RAM,content=Save)"])) { - ram.reset(); - } - - if(information.region == "Auto") { - if(auto region = information.document["game/region"].text()) { - information.region = region.upcase(); - } else { - information.region = "NTSC-J"; - } - } - - read = {&Cartridge::readLinear, this}; - write = {&Cartridge::writeLinear, this}; - - if(rom.size > 0x200000) { - read = {&Cartridge::readBanked, this}; - write = {&Cartridge::writeBanked, this}; - } - - if(information.document["game/board/slot(type=MegaDrive)"]) { - slot = new Cartridge{depth + 1}; - if(!slot->load()) slot.reset(); - - if(patch) { - read = {&Cartridge::readLockOn, this}; - write = {&Cartridge::writeLockOn, this}; - } else { - read = {&Cartridge::readGameGenie, this}; - write = {&Cartridge::writeGameGenie, this}; - } - } - - //easter egg: power draw increases with each successively stacked cartridge - //simulate increasing address/data line errors as stacking increases - if(depth >= 3) { - auto reader = read; - auto writer = write; - auto scramble = [=](uint32 value) -> uint32 { - uint chance = max(1, (1 << 19) >> depth) - 1; - if((random() & chance) == 0) value ^= 1 << (random() & 31); - return value; - }; - read = [=](uint22 address) -> uint16 { - return scramble(reader(scramble(address))); - }; - write = [=](uint22 address, uint16 data) -> void { - writer(scramble(address), scramble(data)); - }; - } - - return true; -} - -auto Cartridge::save() -> void { - saveRAM(ram, information.document["game/board/memory(type=RAM,content=Save)"]); - if(slot) slot->save(); -} - -auto Cartridge::unload() -> void { - rom.reset(); - patch.reset(); - ram.reset(); - read.reset(); - write.reset(); - if(slot) slot->unload(); - slot.reset(); -} - -auto Cartridge::power() -> void { - ramEnable = 1; - ramWritable = 1; - for(uint n : range(8)) romBank[n] = n; - gameGenie = {}; -} - -// - -auto Cartridge::loadROM(Memory& rom, Markup::Node memory) -> bool { - if(!memory) return false; - - auto name = string{memory["content"].text(), ".", memory["type"].text()}.downcase(); - rom.size = memory["size"].natural() >> 1; - rom.mask = bit::round(rom.size) - 1; - rom.data = new uint16[rom.mask + 1](); - if(auto fp = platform->open(pathID(), name, File::Read, File::Required)) { - for(uint n : range(rom.size)) rom.data[n] = fp->readm(2); - } else return false; - - return true; -} - -auto Cartridge::loadRAM(Memory& ram, Markup::Node memory) -> bool { - if(!memory) return false; - - auto name = string{memory["content"].text(), ".", memory["type"].text()}.downcase(); - if(auto mode = memory["mode"].text()) { - if(mode == "lo" ) ram.bits = 0x00ff; - if(mode == "hi" ) ram.bits = 0xff00; - if(mode == "word") ram.bits = 0xffff; - } - ram.size = memory["size"].natural() >> (ram.bits == 0xffff); - ram.mask = bit::round(ram.size) - 1; - ram.data = new uint16[ram.mask + 1](); - if(!(bool)memory["volatile"]) { - if(auto fp = platform->open(pathID(), name, File::Read)) { - for(uint n : range(ram.size)) { - if(ram.bits != 0xffff) ram.data[n] = fp->readm(1) * 0x0101; - if(ram.bits == 0xffff) ram.data[n] = fp->readm(2); - } - } - } - - return true; -} - -auto Cartridge::saveRAM(Memory& ram, Markup::Node memory) -> bool { - if(!memory) return false; - if((bool)memory["volatile"]) return true; - - auto name = string{memory["content"].text(), ".", memory["type"].text()}.downcase(); - if(auto fp = platform->open(pathID(), name, File::Write)) { - for(uint n : range(ram.size)) { - if(ram.bits != 0xffff) fp->writem(ram.data[n], 1); - if(ram.bits == 0xffff) fp->writem(ram.data[n], 2); - } - } else return false; - - return true; -} - -// - -auto Cartridge::readIO(uint24 address) -> uint16 { - if(slot) slot->readIO(address); - return 0x0000; -} - -auto Cartridge::writeIO(uint24 address, uint16 data) -> void { - if(address == 0xa130f1) ramEnable = data.bit(0), ramWritable = data.bit(1); - if(address == 0xa130f3) romBank[1] = data; - if(address == 0xa130f5) romBank[2] = data; - if(address == 0xa130f7) romBank[3] = data; - if(address == 0xa130f9) romBank[4] = data; - if(address == 0xa130fb) romBank[5] = data; - if(address == 0xa130fd) romBank[6] = data; - if(address == 0xa130ff) romBank[7] = data; - if(slot) slot->writeIO(address, data); -} - -// - -auto Cartridge::readLinear(uint22 address) -> uint16 { - if(ramEnable && ram && address >= 0x200000) return ram.read(address); - return rom.read(address); -} - -auto Cartridge::writeLinear(uint22 address, uint16 data) -> void { - //emulating ramWritable will break commercial software: - //it does not appear that many (any?) games actually connect $a130f1.d1 to /WE; - //hence RAM ends up always being writable, and many games fail to set d1=1 - if(ramEnable && ram && address >= 0x200000) return ram.write(address, data); -} - -// - -auto Cartridge::readBanked(uint22 address) -> uint16 { - address = romBank[address.bits(19,21)] << 19 | address.bits(0,18); - return rom.read(address); -} - -auto Cartridge::writeBanked(uint22 address, uint16 data) -> void { -} - -// - -auto Cartridge::readLockOn(uint22 address) -> uint16 { - if(address < 0x200000) return rom.read(address); - if(ramEnable && address >= 0x300000) return patch.read(address); - if(slot) return slot->read(address); - return 0x0000; -} - -auto Cartridge::writeLockOn(uint22 address, uint16 data) -> void { - if(slot) return slot->write(address, data); -} - -// - -auto Cartridge::readGameGenie(uint22 address) -> uint16 { - if(gameGenie.enable) { - for(auto& code : gameGenie.codes) { - if(code.enable && code.address == address) return code.data; - } - if(slot) return slot->read(address); - } - - return rom.read(address); -} - -auto Cartridge::writeGameGenie(uint22 address, uint16 data) -> void { - if(gameGenie.enable) { - if(slot) return slot->write(address, data); - } - - if(address == 0x02 && data == 0x0001) { - gameGenie.enable = true; - } - - if(address >= 0x04 && address <= 0x20 && !address.bit(0)) { - address = address - 0x04 >> 1; - auto& code = gameGenie.codes[address / 3]; - if(address % 3 == 0) code.address.bits(16,23) = data.byte(0); - if(address % 3 == 1) code.address.bits( 0,15) = data; - if(address % 3 == 2) code.data = data, code.enable = true; - } -} - -// - -Cartridge::Memory::operator bool() const { - return size; -} - -auto Cartridge::Memory::reset() -> void { - delete[] data; - data = nullptr; - size = 0; - mask = 0; - bits = 0; -} - -auto Cartridge::Memory::read(uint24 address) -> uint16 { - if(!size) return 0x0000; - return data[address >> 1 & mask]; -} - -auto Cartridge::Memory::write(uint24 address, uint16 word) -> void { - if(!size) return; - if(bits == 0x00ff) word.byte(1) = word.byte(0); - if(bits == 0xff00) word.byte(0) = word.byte(1); - data[address >> 1 & mask] = word; -} - -} diff --git a/higan/md/cartridge/cartridge.hpp b/higan/md/cartridge/cartridge.hpp deleted file mode 100644 index 009384f0..00000000 --- a/higan/md/cartridge/cartridge.hpp +++ /dev/null @@ -1,87 +0,0 @@ -struct Cartridge { - auto pathID() const -> uint { return information.pathID; } - auto region() const -> string { return information.region; } - - Cartridge() = default; - Cartridge(uint depth) : depth(depth) {} - - auto hashes() const -> vector; - auto manifests() const -> vector; - auto titles() const -> vector; - - struct Memory; - auto load() -> bool; - auto save() -> void; - auto unload() -> void; - auto power() -> void; - - auto loadROM(Memory& rom, Markup::Node memory) -> bool; - auto loadRAM(Memory& ram, Markup::Node memory) -> bool; - auto saveRAM(Memory& ram, Markup::Node memory) -> bool; - - auto readIO(uint24 address) -> uint16; - auto writeIO(uint24 address, uint16 data) -> void; - - auto readLinear(uint22 address) -> uint16; - auto writeLinear(uint22 address, uint16 data) -> void; - - auto readBanked(uint22 address) -> uint16; - auto writeBanked(uint22 address, uint16 data) -> void; - - auto readLockOn(uint22 address) -> uint16; - auto writeLockOn(uint22 address, uint16 data) -> void; - - auto readGameGenie(uint22 address) -> uint16; - auto writeGameGenie(uint22 address, uint16 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - struct Information { - uint pathID = 0; - string region; - string hash; - string manifest; - string title; - Markup::Node document; - }; - - struct Memory { - explicit operator bool() const; - auto reset() -> void; - auto read(uint24 address) -> uint16; - auto write(uint24 address, uint16 word) -> void; - - uint16* data = nullptr; - uint size = 0; //16-bit word size - uint mask = 0; - uint bits = 0; - }; - - Information information; - - Memory rom; - Memory patch; - Memory ram; - - uint1 ramEnable; - uint1 ramWritable; - uint6 romBank[8]; - - struct GameGenie { - boolean enable; - struct Code { - boolean enable; - uint24 address; - uint16 data; - } codes[5]; - } gameGenie; - - function read; - function write; - - unique_pointer slot; - const uint depth = 0; -}; - -extern Cartridge cartridge; diff --git a/higan/md/cartridge/serialization.cpp b/higan/md/cartridge/serialization.cpp deleted file mode 100644 index 4866fe76..00000000 --- a/higan/md/cartridge/serialization.cpp +++ /dev/null @@ -1,13 +0,0 @@ -auto Cartridge::serialize(serializer& s) -> void { - if(ram.size) s.array(ram.data, ram.size); - s.integer(ramEnable); - s.integer(ramWritable); - s.array(romBank); - s.boolean(gameGenie.enable); - for(auto& code : gameGenie.codes) { - s.boolean(code.enable); - s.integer(code.address); - s.integer(code.data); - } - if(slot) slot->serialize(s); -} diff --git a/higan/md/controller/control-pad/control-pad.cpp b/higan/md/controller/control-pad/control-pad.cpp deleted file mode 100644 index 42c93a52..00000000 --- a/higan/md/controller/control-pad/control-pad.cpp +++ /dev/null @@ -1,29 +0,0 @@ -ControlPad::ControlPad(uint port) : Controller(port) { -} - -auto ControlPad::readData() -> uint8 { - uint6 data; - - if(select == 0) { - data.bit(0) = platform->inputPoll(port, ID::Device::ControlPad, Up); - data.bit(1) = platform->inputPoll(port, ID::Device::ControlPad, Down); - data.bits(2,3) = ~0; - data.bit(4) = platform->inputPoll(port, ID::Device::ControlPad, A); - data.bit(5) = platform->inputPoll(port, ID::Device::ControlPad, Start); - } else { - data.bit(0) = platform->inputPoll(port, ID::Device::ControlPad, Up); - data.bit(1) = platform->inputPoll(port, ID::Device::ControlPad, Down); - data.bit(2) = platform->inputPoll(port, ID::Device::ControlPad, Left); - data.bit(3) = platform->inputPoll(port, ID::Device::ControlPad, Right); - data.bit(4) = platform->inputPoll(port, ID::Device::ControlPad, B); - data.bit(5) = platform->inputPoll(port, ID::Device::ControlPad, C); - } - - data = ~data; - return latch << 7 | select << 6 | data; -} - -auto ControlPad::writeData(uint8 data) -> void { - select = data.bit(6); - latch = data.bit(7); -} diff --git a/higan/md/controller/control-pad/control-pad.hpp b/higan/md/controller/control-pad/control-pad.hpp deleted file mode 100644 index 406456c3..00000000 --- a/higan/md/controller/control-pad/control-pad.hpp +++ /dev/null @@ -1,13 +0,0 @@ -struct ControlPad : Controller { - enum : uint { - Up, Down, Left, Right, A, B, C, Start, - }; - - ControlPad(uint port); - - auto readData() -> uint8 override; - auto writeData(uint8 data) -> void override; - - uint1 select = 1; - uint1 latch; -}; diff --git a/higan/md/controller/controller.cpp b/higan/md/controller/controller.cpp deleted file mode 100644 index f612fb38..00000000 --- a/higan/md/controller/controller.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include - -namespace MegaDrive { - -ControllerPort controllerPort1; -ControllerPort controllerPort2; -ControllerPort extensionPort; -#include "control-pad/control-pad.cpp" -#include "fighting-pad/fighting-pad.cpp" - -Controller::Controller(uint port) : port(port) { - if(!handle()) create(Controller::Enter, 1); -} - -Controller::~Controller() { - scheduler.remove(*this); -} - -auto Controller::Enter() -> void { - while(true) { - scheduler.synchronize(); - if(controllerPort1.device->active()) controllerPort1.device->main(); - if(controllerPort2.device->active()) controllerPort2.device->main(); - if(extensionPort.device->active()) extensionPort.device->main(); - } -} - -auto Controller::main() -> void { - step(1); - synchronize(cpu); -} - -// - -auto ControllerPort::connect(uint deviceID) -> void { - if(!system.loaded()) return; - delete device; - - switch(deviceID) { default: - case ID::Device::None: device = new Controller(port); break; - case ID::Device::ControlPad: device = new ControlPad(port); break; - case ID::Device::FightingPad: device = new FightingPad(port); break; - } - - cpu.peripherals.reset(); - if(auto device = controllerPort1.device) cpu.peripherals.append(device); - if(auto device = controllerPort2.device) cpu.peripherals.append(device); - if(auto device = extensionPort.device) cpu.peripherals.append(device); -} - -auto ControllerPort::readControl() -> uint8 { - return control; -} - -auto ControllerPort::writeControl(uint8 data) -> void { - control = data; -} - -auto ControllerPort::power(uint port) -> void { - this->port = port; - control = 0x00; -} - -auto ControllerPort::unload() -> void { - delete device; - device = nullptr; -} - -auto ControllerPort::serialize(serializer& s) -> void { - s.integer(control); -} - -} diff --git a/higan/md/controller/controller.hpp b/higan/md/controller/controller.hpp deleted file mode 100644 index 3ab12802..00000000 --- a/higan/md/controller/controller.hpp +++ /dev/null @@ -1,34 +0,0 @@ -struct Controller : Thread { - Controller(uint port); - virtual ~Controller(); - - static auto Enter() -> void; - virtual auto main() -> void; - - virtual auto readData() -> uint8 { return 0xff; } - virtual auto writeData(uint8 data) -> void {} - - const uint port; -}; - -struct ControllerPort { - auto connect(uint deviceID) -> void; - - auto readControl() -> uint8; - auto writeControl(uint8 data) -> void; - - auto power(uint port) -> void; - auto unload() -> void; - auto serialize(serializer&) -> void; - - uint port; - uint8 control; - Controller* device = nullptr; -}; - -extern ControllerPort controllerPort1; -extern ControllerPort controllerPort2; -extern ControllerPort extensionPort; - -#include "control-pad/control-pad.hpp" -#include "fighting-pad/fighting-pad.hpp" diff --git a/higan/md/controller/fighting-pad/fighting-pad.cpp b/higan/md/controller/fighting-pad/fighting-pad.cpp deleted file mode 100644 index 0bc5fc4e..00000000 --- a/higan/md/controller/fighting-pad/fighting-pad.cpp +++ /dev/null @@ -1,66 +0,0 @@ -FightingPad::FightingPad(uint port) : Controller(port) { - create(Controller::Enter, 1'000'000); -} - -auto FightingPad::main() -> void { - if(timeout) { - timeout--; - } else { - counter = 0; - } - step(1); - synchronize(cpu); -} - -auto FightingPad::readData() -> uint8 { - uint6 data; - - if(select == 0) { - if(counter == 0 || counter == 1 || counter == 4) { - data.bit(0) = platform->inputPoll(port, ID::Device::FightingPad, Up); - data.bit(1) = platform->inputPoll(port, ID::Device::FightingPad, Down); - data.bits(2,3) = ~0; - } - - if(counter == 2) { - data.bits(0,3) = ~0; //controller type detection - } - - if(counter == 3) { - data.bits(0,3) = 0; - } - - data.bit(4) = platform->inputPoll(port, ID::Device::FightingPad, A); - data.bit(5) = platform->inputPoll(port, ID::Device::FightingPad, Start); - } else { - if(counter == 0 || counter == 1 || counter == 2 || counter == 4) { - data.bit(0) = platform->inputPoll(port, ID::Device::FightingPad, Up); - data.bit(1) = platform->inputPoll(port, ID::Device::FightingPad, Down); - data.bit(2) = platform->inputPoll(port, ID::Device::FightingPad, Left); - data.bit(3) = platform->inputPoll(port, ID::Device::FightingPad, Right); - data.bit(4) = platform->inputPoll(port, ID::Device::FightingPad, B); - data.bit(5) = platform->inputPoll(port, ID::Device::FightingPad, C); - } - - if(counter == 3) { - data.bit(0) = platform->inputPoll(port, ID::Device::FightingPad, Z); - data.bit(1) = platform->inputPoll(port, ID::Device::FightingPad, Y); - data.bit(2) = platform->inputPoll(port, ID::Device::FightingPad, X); - data.bit(3) = platform->inputPoll(port, ID::Device::FightingPad, Mode); - data.bits(4,5) = 0; - } - } - - data = ~data; - return latch << 7 | select << 6 | data; -} - -auto FightingPad::writeData(uint8 data) -> void { - if(!select && data.bit(6)) { //0->1 transition - if(++counter == 5) counter = 0; - } - - select = data.bit(6); - latch = data.bit(7); - timeout = 1600; //~1.6ms -} diff --git a/higan/md/controller/fighting-pad/fighting-pad.hpp b/higan/md/controller/fighting-pad/fighting-pad.hpp deleted file mode 100644 index fcd3f42b..00000000 --- a/higan/md/controller/fighting-pad/fighting-pad.hpp +++ /dev/null @@ -1,16 +0,0 @@ -struct FightingPad : Controller { - enum : uint { - Up, Down, Left, Right, A, B, C, X, Y, Z, Mode, Start, - }; - - FightingPad(uint port); - auto main() -> void override; - - auto readData() -> uint8 override; - auto writeData(uint8 data) -> void override; - - uint1 select = 1; - uint1 latch; - uint3 counter; - uint32 timeout; -}; diff --git a/higan/md/cpu/bus.cpp b/higan/md/cpu/bus.cpp deleted file mode 100644 index 0a29882c..00000000 --- a/higan/md/cpu/bus.cpp +++ /dev/null @@ -1,115 +0,0 @@ -auto CPU::readByte(uint24 addr) -> uint16 { - if(addr >= 0x000000 && addr <= 0x3fffff) { - if(!io.romEnable) return tmss[addr & 0x7ff]; - return cartridge.read(addr & ~1).byte(!addr.bit(0)); - } - if(addr >= 0xa00000 && addr <= 0xa0ffff) return apu.granted() ? apu.read(addr) : (uint8)0x00; - if(addr >= 0xa10000 && addr <= 0xa10fff) return readIO(addr & ~0xff00); - if(addr >= 0xa11000 && addr <= 0xa11fff) return readIO(addr & ~0x00ff); - if(addr >= 0xa13000 && addr <= 0xa130ff) return cartridge.readIO(addr); - if(addr >= 0xc00000 && addr <= 0xdfffff) return vdp.read(addr & ~1).byte(!addr.bit(0)); - if(addr >= 0xe00000 && addr <= 0xffffff) { - return ram[addr & 0xffff]; - } - return 0x0000; -} - -auto CPU::readWord(uint24 addr) -> uint16 { - if(addr >= 0x000000 && addr <= 0x3fffff) { - if(!io.romEnable) return tmss[addr & 0x7fe | 0] << 8 | tmss[addr & 0x7fe | 1] << 0; - return cartridge.read(addr); - } - if(addr >= 0xa00000 && addr <= 0xa0ffff) return apu.granted() ? apu.read(addr) : (uint8)0x00; - if(addr >= 0xa10000 && addr <= 0xa10fff) return readIO(addr & ~0xff00) << 0; - if(addr >= 0xa11000 && addr <= 0xa11fff) return readIO(addr & ~0x00ff) << 8; - if(addr >= 0xa13000 && addr <= 0xa130ff) return cartridge.readIO(addr); - if(addr >= 0xc00000 && addr <= 0xdfffff) return vdp.read(addr); - if(addr >= 0xe00000 && addr <= 0xffffff) { - uint16 data = ram[addr + 0 & 0xffff] << 8; - return data | ram[addr + 1 & 0xffff] << 0; - } - return 0x0000; -} - -auto CPU::writeByte(uint24 addr, uint16 data) -> void { - if(addr >= 0x000000 && addr <= 0x3fffff) return cartridge.write(addr & ~1, data << 8 | data << 0); - if(addr >= 0xa00000 && addr <= 0xa0ffff) return apu.granted() ? apu.write(addr, data) : (void)0; - if(addr >= 0xa10000 && addr <= 0xa10fff) return writeIO(addr & ~0xff00, data); - if(addr >= 0xa11000 && addr <= 0xa11fff) return writeIO(addr & ~0x00ff, data); - if(addr >= 0xa13000 && addr <= 0xa130ff) return cartridge.writeIO(addr, data); - if(addr >= 0xa14000 && addr <= 0xa140ff) return writeIO(addr & ~0xff00, data); - if(addr >= 0xa14100 && addr <= 0xa141ff) return writeIO(addr & ~0x00ff, data); - if(addr >= 0xc00000 && addr <= 0xc0000f) return vdp.write(addr & ~1, data << 8 | data << 0); - if(addr >= 0xc00010 && addr <= 0xc00017) return psg.write(data); - if(addr >= 0xe00000 && addr <= 0xffffff) { - ram[addr & 0xffff] = data; - return; - } -} - -auto CPU::writeWord(uint24 addr, uint16 data) -> void { - if(addr >= 0x000000 && addr <= 0x3fffff) return cartridge.write(addr, data); - if(addr >= 0xa00000 && addr <= 0xa0ffff) return apu.granted() ? apu.write(addr, data) : (void)0; - if(addr >= 0xa10000 && addr <= 0xa10fff) return writeIO(addr & ~0xff00, data >> 0); - if(addr >= 0xa11000 && addr <= 0xa11fff) return writeIO(addr & ~0x00ff, data >> 8); - if(addr >= 0xa13000 && addr <= 0xa130ff) return cartridge.writeIO(addr, data); - if(addr >= 0xa14000 && addr <= 0xa140ff) return writeIO(addr & ~0xff00, data >> 0); - if(addr >= 0xa14100 && addr <= 0xa141ff) return writeIO(addr & ~0x00ff, data >> 8); - if(addr >= 0xc00000 && addr <= 0xc0000f) return vdp.write(addr, data); - if(addr >= 0xc00010 && addr <= 0xc00017) return psg.write(data); - if(addr >= 0xe00000 && addr <= 0xffffff) { - ram[addr + 0 & 0xffff] = data >> 8; - ram[addr + 1 & 0xffff] = data >> 0; - return; - } -} - -auto CPU::readIO(uint24 addr) -> uint16 { - switch(addr & ~1) { - case 0xa10000: return ( - !Region::NTSCJ() << 7 //0 = domestic (Japan); 1 = export - | Region::PAL() << 6 //0 = NTSC; 1 = PAL - | 1 << 5 //0 = Mega CD connected; 1 = no expansion connected - | io.version << 0 //0 = Model 1; 1 = Model 2+ - ); - - case 0xa10002: return controllerPort1.device->readData(); - case 0xa10004: return controllerPort2.device->readData(); - case 0xa10006: return extensionPort.device->readData(); - - case 0xa10008: return controllerPort1.readControl(); - case 0xa1000a: return controllerPort2.readControl(); - case 0xa1000c: return extensionPort.readControl(); - - case 0xa11100: return !apu.granted(); - } - - return 0x0000; -} - -auto CPU::writeIO(uint24 addr, uint16 data) -> void { - switch(addr & ~1) { - case 0xa10002: return controllerPort1.device->writeData(data); - case 0xa10004: return controllerPort2.device->writeData(data); - case 0xa10006: return extensionPort.device->writeData(data); - - case 0xa10008: return controllerPort1.writeControl(data); - case 0xa1000a: return controllerPort2.writeControl(data); - case 0xa1000c: return extensionPort.writeControl(data); - - case 0xa11100: return apu.request(data.bit(0)); - case 0xa11200: return apu.enable(data.bit(0)); - - case 0xa14000: - io.vdpEnable[0] = data == 0x5345; - return; - - case 0xa14002: - io.vdpEnable[1] = data == 0x4741; - return; - - case 0xa14100: - io.romEnable = data.bit(0); - return; - } -} diff --git a/higan/md/cpu/cpu.cpp b/higan/md/cpu/cpu.cpp deleted file mode 100644 index fe1b63f8..00000000 --- a/higan/md/cpu/cpu.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include - -namespace MegaDrive { - -CPU cpu; -#include "bus.cpp" -#include "serialization.cpp" - -auto CPU::Enter() -> void { - while(true) scheduler.synchronize(), cpu.main(); -} - -auto CPU::main() -> void { - if(state.interruptPending) { - if(state.interruptPending.bit((uint)Interrupt::Reset)) { - state.interruptPending.bit((uint)Interrupt::Reset) = 0; - r.a[7] = bus->readWord(0) << 16 | bus->readWord(2) << 0; - r.pc = bus->readWord(4) << 16 | bus->readWord(6) << 0; - } - - if(state.interruptPending.bit((uint)Interrupt::HorizontalBlank)) { - if(4 > r.i) { - state.interruptPending.bit((uint)Interrupt::HorizontalBlank) = 0; - return exception(Exception::Interrupt, Vector::HorizontalBlank, 4); - } - } - - if(state.interruptPending.bit((uint)Interrupt::VerticalBlank)) { - if(6 > r.i) { - state.interruptPending.bit((uint)Interrupt::VerticalBlank) = 0; - return exception(Exception::Interrupt, Vector::VerticalBlank, 6); - } - } - } - - instruction(); -} - -auto CPU::step(uint clocks) -> void { - while(wait) { - Thread::step(1); - synchronize(); - } - - Thread::step(clocks); - synchronize(); -} - -auto CPU::synchronize() -> void { - synchronize(apu); - synchronize(vdp); - synchronize(psg); - synchronize(ym2612); - for(auto peripheral : peripherals) synchronize(*peripheral); -} - -auto CPU::raise(Interrupt interrupt) -> void { - if(!state.interruptLine.bit((uint)interrupt)) { - state.interruptLine.bit((uint)interrupt) = 1; - state.interruptPending.bit((uint)interrupt) = 1; - } -} - -auto CPU::lower(Interrupt interrupt) -> void { - state.interruptLine.bit((uint)interrupt) = 0; - state.interruptPending.bit((uint)interrupt) = 0; -} - -auto CPU::load(Markup::Node node) -> bool { - tmssEnable = false; - if(node["cpu/version"].natural() == 1) { - if(auto name = node["cpu/rom/name"].text()) { - if(auto fp = platform->open(ID::System, name, File::Read, File::Required)) { - fp->read(tmss, 2 * 1024); - tmssEnable = true; - } - } - } - - return true; -} - -auto CPU::power(bool reset) -> void { - M68K::bus = this; - M68K::power(); - create(CPU::Enter, system.frequency() / 7.0); - - if(!reset) memory::fill(ram, sizeof(ram)); - - io = {}; - io.version = tmssEnable; - io.romEnable = !tmssEnable; - io.vdpEnable[0] = !tmssEnable; - io.vdpEnable[1] = !tmssEnable; - - state = {}; - state.interruptPending.bit((uint)Interrupt::Reset) = 1; -} - -} diff --git a/higan/md/cpu/cpu.hpp b/higan/md/cpu/cpu.hpp deleted file mode 100644 index 0811ea16..00000000 --- a/higan/md/cpu/cpu.hpp +++ /dev/null @@ -1,54 +0,0 @@ -//Motorola 68000 - -struct CPU : Processor::M68K, Processor::M68K::Bus, Thread { - enum class Interrupt : uint { - Reset, - HorizontalBlank, - VerticalBlank, - }; - - using Thread::synchronize; - - //cpu.cpp - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void override; - auto synchronize() -> void; - - auto raise(Interrupt) -> void; - auto lower(Interrupt) -> void; - - auto load(Markup::Node) -> bool; - auto power(bool reset) -> void; - - //bus.cpp - auto readByte(uint24 address) -> uint16 override; - auto readWord(uint24 address) -> uint16 override; - auto writeByte(uint24 address, uint16 data) -> void override; - auto writeWord(uint24 address, uint16 data) -> void override; - auto readIO(uint24 address) -> uint16; - auto writeIO(uint24 address, uint16 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - vector peripherals; - -private: - uint8 ram[64 * 1024]; - uint8 tmss[2 * 1024]; - uint1 tmssEnable; - - struct IO { - boolean version; //0 = Model 1; 1 = Model 2+ - boolean romEnable; - boolean vdpEnable[2]; - } io; - - struct State { - uint32 interruptLine; - uint32 interruptPending; - } state; -}; - -extern CPU cpu; diff --git a/higan/md/cpu/serialization.cpp b/higan/md/cpu/serialization.cpp deleted file mode 100644 index 23acf588..00000000 --- a/higan/md/cpu/serialization.cpp +++ /dev/null @@ -1,14 +0,0 @@ -auto CPU::serialize(serializer& s) -> void { - M68K::serialize(s); - Thread::serialize(s); - - s.array(ram); - - s.boolean(io.version); - s.boolean(io.romEnable); - s.boolean(io.vdpEnable[0]); - s.boolean(io.vdpEnable[1]); - - s.integer(state.interruptLine); - s.integer(state.interruptPending); -} diff --git a/higan/md/interface/interface.cpp b/higan/md/interface/interface.cpp deleted file mode 100644 index d3e38d4f..00000000 --- a/higan/md/interface/interface.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include - -namespace MegaDrive { - -Settings settings; - -auto Interface::information() -> Information { - Information information; - information.manufacturer = "Sega"; - information.name = "Mega Drive"; - information.extension = "md"; - information.resettable = true; - return information; -} - -auto Interface::display() -> Display { - Display display; - display.type = Display::Type::CRT; - display.colors = 3 * (1 << 9); - display.width = 320; - display.height = 240; - display.internalWidth = 1280; - display.internalHeight = 480; - display.aspectCorrection = 1.0; - return display; -} - -auto Interface::color(uint32 color) -> uint64 { - uint R = color.bits(0, 2); - uint G = color.bits(3, 5); - uint B = color.bits(6, 8); - uint M = color.bits(9,10); - - uint lookup[3][8] = { - { 0, 29, 52, 70, 87, 101, 116, 130}, //shadow - { 0, 52, 87, 116, 144, 172, 206, 255}, //normal - {130, 144, 158, 172, 187, 206, 228, 255}, //highlight - }; - - uint64 r = image::normalize(lookup[M][R], 8, 16); - uint64 g = image::normalize(lookup[M][G], 8, 16); - uint64 b = image::normalize(lookup[M][B], 8, 16); - - return r << 32 | g << 16 | b << 0; -} - -auto Interface::loaded() -> bool { - return system.loaded(); -} - -auto Interface::hashes() -> vector { - return cartridge.hashes(); -} - -auto Interface::manifests() -> vector { - return cartridge.manifests(); -} - -auto Interface::titles() -> vector { - return cartridge.titles(); -} - -auto Interface::load() -> bool { - return system.load(this); -} - -auto Interface::save() -> void { - system.save(); -} - -auto Interface::unload() -> void { - save(); - system.unload(); -} - -auto Interface::ports() -> vector { return { - {ID::Port::Controller1, "Controller Port 1"}, - {ID::Port::Controller2, "Controller Port 2"}, - {ID::Port::Extension, "Extension Port" }}; -} - -auto Interface::devices(uint port) -> vector { - if(port == ID::Port::Controller1) return { - {ID::Device::None, "None" }, - {ID::Device::ControlPad, "Control Pad" }, - {ID::Device::FightingPad, "Fighting Pad"} - }; - - if(port == ID::Port::Controller2) return { - {ID::Device::None, "None" }, - {ID::Device::ControlPad, "Control Pad" }, - {ID::Device::FightingPad, "Fighting Pad"} - }; - - if(port == ID::Port::Extension) return { - {ID::Device::None, "None"} - }; - - return {}; -} - -auto Interface::inputs(uint device) -> vector { - using Type = Input::Type; - - if(device == ID::Device::None) return { - }; - - if(device == ID::Device::ControlPad) return { - {Type::Hat, "Up" }, - {Type::Hat, "Down" }, - {Type::Hat, "Left" }, - {Type::Hat, "Right"}, - {Type::Button, "A" }, - {Type::Button, "B" }, - {Type::Button, "C" }, - {Type::Control, "Start"} - }; - - if(device == ID::Device::FightingPad) return { - {Type::Hat, "Up" }, - {Type::Hat, "Down" }, - {Type::Hat, "Left" }, - {Type::Hat, "Right"}, - {Type::Button, "A" }, - {Type::Button, "B" }, - {Type::Button, "C" }, - {Type::Button, "X" }, - {Type::Button, "Y" }, - {Type::Button, "Z" }, - {Type::Control, "Mode" }, - {Type::Control, "Start"} - }; - - return {}; -} - -auto Interface::connected(uint port) -> uint { - if(port == ID::Port::Controller1) return settings.controllerPort1; - if(port == ID::Port::Controller2) return settings.controllerPort2; - if(port == ID::Port::Extension) return settings.extensionPort; - return 0; -} - -auto Interface::connect(uint port, uint device) -> void { - if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); - if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); - if(port == ID::Port::Extension) extensionPort.connect(settings.extensionPort = device); -} - -auto Interface::power() -> void { - system.power(/* reset = */ false); -} - -auto Interface::reset() -> void { - system.power(/* reset = */ true); -} - -auto Interface::run() -> void { - system.run(); -} - -auto Interface::serialize() -> serializer { - system.runToSave(); - return system.serialize(); -} - -auto Interface::unserialize(serializer& s) -> bool { - return system.unserialize(s); -} - -auto Interface::cheats(const vector& list) -> void { - cheat.assign(list); -} - -auto Interface::cap(const string& name) -> bool { - return false; -} - -auto Interface::get(const string& name) -> any { - return {}; -} - -auto Interface::set(const string& name, const any& value) -> bool { - return false; -} - -} diff --git a/higan/md/interface/interface.hpp b/higan/md/interface/interface.hpp deleted file mode 100644 index eaf60b1e..00000000 --- a/higan/md/interface/interface.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#if defined(CORE_MD) - -namespace MegaDrive { - -struct ID { - enum : uint { - System, - MegaDrive, - }; - - struct Port { enum : uint { - Controller1, - Controller2, - Extension, - };}; - - struct Device { enum : uint { - None, - ControlPad, - FightingPad, - };}; -}; - -struct Interface : Emulator::Interface { - auto information() -> Information override; - - auto display() -> Display override; - auto color(uint32 color) -> uint64 override; - - auto loaded() -> bool override; - auto hashes() -> vector override; - auto manifests() -> vector override; - auto titles() -> vector override; - auto load() -> bool override; - auto save() -> void override; - auto unload() -> void override; - - auto ports() -> vector override; - auto devices(uint port) -> vector override; - auto inputs(uint device) -> vector override; - - auto connected(uint port) -> uint override; - auto connect(uint port, uint device) -> void override; - auto power() -> void override; - auto reset() -> void override; - auto run() -> void override; - - auto serialize() -> serializer override; - auto unserialize(serializer&) -> bool override; - - auto cheats(const vector& list) -> void override; - - auto cap(const string& name) -> bool override; - auto get(const string& name) -> any override; - auto set(const string& name, const any& value) -> bool override; -}; - -struct Settings { - uint controllerPort1 = ID::Device::ControlPad; - uint controllerPort2 = ID::Device::ControlPad; - uint extensionPort = ID::Device::None; -}; - -extern Settings settings; - -} - -#endif diff --git a/higan/md/md.hpp b/higan/md/md.hpp deleted file mode 100644 index d7bda91e..00000000 --- a/higan/md/md.hpp +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -//license: GPLv3 -//started: 2016-07-08 - -#include -#include -#include -#include -#include - -#include -#include - -namespace MegaDrive { - #define platform Emulator::platform - namespace File = Emulator::File; - using Scheduler = Emulator::Scheduler; - using Random = Emulator::Random; - using Cheat = Emulator::Cheat; - extern Scheduler scheduler; - extern Random random; - extern Cheat cheat; - - struct Wait { - enum : uint { - VDP_DMA = 1 << 0, - }; - }; - - struct Thread : Emulator::Thread { - auto create(auto (*entrypoint)() -> void, double frequency) -> void { - Emulator::Thread::create(entrypoint, frequency); - scheduler.append(*this); - wait = 0; - } - - inline auto synchronize(Thread& thread) -> void { - if(clock() >= thread.clock()) scheduler.resume(thread); - } - - uint wait = 0; - }; - - struct Region { - inline static auto NTSCJ() -> bool; - inline static auto NTSCU() -> bool; - inline static auto PAL() -> bool; - }; - - #include - - #include - #include - #include - #include - #include - - #include - #include -} - -#include diff --git a/higan/md/psg/io.cpp b/higan/md/psg/io.cpp deleted file mode 100644 index 4752b908..00000000 --- a/higan/md/psg/io.cpp +++ /dev/null @@ -1,54 +0,0 @@ -auto PSG::write(uint8 data) -> void { - bool l = data.bit(7); - if(l) select = data.bits(4,6); - - switch(select) { - - case 0: { - if(l) tone0.pitch.bits(0,3) = data.bits(0,3); - else tone0.pitch.bits(4,9) = data.bits(0,5); - break; - } - - case 1: { - tone0.volume = data.bits(0,3); - break; - } - - case 2: { - if(l) tone1.pitch.bits(0,3) = data.bits(0,3); - else tone1.pitch.bits(4,9) = data.bits(0,5); - break; - } - - case 3: { - tone1.volume = data.bits(0,3); - break; - } - - case 4: { - if(l) tone2.pitch.bits(0,3) = data.bits(0,3); - else tone2.pitch.bits(4,9) = data.bits(0,5); - noise.pitch = tone2.pitch; - break; - } - - case 5: { - tone2.volume = data.bits(0,3); - break; - } - - case 6: { - noise.rate = data.bits(0,1); - noise.enable = data.bit(2); - noise.lfsr = 0x8000; - break; - } - - case 7: { - noise.volume = data.bits(0,3); - break; - } - - } -} diff --git a/higan/md/psg/noise.cpp b/higan/md/psg/noise.cpp deleted file mode 100644 index b5ee7529..00000000 --- a/higan/md/psg/noise.cpp +++ /dev/null @@ -1,24 +0,0 @@ -auto PSG::Noise::run() -> void { - if(counter--) return; - - if(rate == 0) counter = 0x10; - if(rate == 1) counter = 0x20; - if(rate == 2) counter = 0x40; - if(rate == 3) counter = pitch; //shared with tone2 - - if(clock ^= 1) { //0->1 transition - output = !lfsr.bit(0); - lfsr = (lfsr.bit(0) ^ (lfsr.bit(3) & enable)) << 15 | lfsr >> 1; - } -} - -auto PSG::Noise::power() -> void { - volume = ~0; - counter = 0; - pitch = 0; - enable = 0; - rate = 0; - lfsr = 0x8000; - clock = 0; - output = 0; -} diff --git a/higan/md/psg/psg.cpp b/higan/md/psg/psg.cpp deleted file mode 100644 index 391b7282..00000000 --- a/higan/md/psg/psg.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include - -namespace MegaDrive { - -PSG psg; -#include "io.cpp" -#include "tone.cpp" -#include "noise.cpp" -#include "serialization.cpp" - -auto PSG::Enter() -> void { - while(true) scheduler.synchronize(), psg.main(); -} - -auto PSG::main() -> void { - tone0.run(); - tone1.run(); - tone2.run(); - noise.run(); - - int output = 0; - output += levels[tone0.volume] * tone0.output; - output += levels[tone1.volume] * tone1.output; - output += levels[tone2.volume] * tone2.output; - output += levels[noise.volume] * noise.output; - - stream->sample(sclamp<16>(output) / 32768.0); - step(16); -} - -auto PSG::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); - synchronize(apu); -} - -auto PSG::power(bool reset) -> void { - create(PSG::Enter, system.frequency() / 15.0); - stream = Emulator::audio.createStream(1, frequency() / 16.0); - stream->addHighPassFilter( 20.0, Emulator::Filter::Order::First); - stream->addLowPassFilter (2840.0, Emulator::Filter::Order::First); - stream->addDCRemovalFilter(); - - select = 0; - for(auto n : range(15)) { - levels[n] = 0x1400 * pow(2, n * -2.0 / 6.0) + 0.5; - } - levels[15] = 0; - - tone0.power(); - tone1.power(); - tone2.power(); - noise.power(); -} - -} diff --git a/higan/md/psg/psg.hpp b/higan/md/psg/psg.hpp deleted file mode 100644 index 6d7f60c4..00000000 --- a/higan/md/psg/psg.hpp +++ /dev/null @@ -1,55 +0,0 @@ -//TI SN76489 (derivative) - -struct PSG : Thread { - shared_pointer stream; - - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - - auto power(bool reset) -> void; - - //io.cpp - auto write(uint8 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - struct Tone { - //tone.cpp - auto run() -> void; - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - uint4 volume; - uint10 counter; - uint10 pitch; - uint1 output; - } tone0, tone1, tone2; - - struct Noise { - //noise.cpp - auto run() -> void; - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - uint4 volume; - uint10 counter; - uint10 pitch; - uint1 enable; - uint2 rate; - uint16 lfsr; - uint1 clock; - uint1 output; - } noise; - - uint3 select; - int16 levels[16]; -}; - -extern PSG psg; diff --git a/higan/md/psg/serialization.cpp b/higan/md/psg/serialization.cpp deleted file mode 100644 index 121179d9..00000000 --- a/higan/md/psg/serialization.cpp +++ /dev/null @@ -1,28 +0,0 @@ -auto PSG::serialize(serializer& s) -> void { - Thread::serialize(s); - - tone0.serialize(s); - tone1.serialize(s); - tone2.serialize(s); - noise.serialize(s); - - s.integer(select); -} - -auto PSG::Tone::serialize(serializer& s) -> void { - s.integer(volume); - s.integer(counter); - s.integer(pitch); - s.integer(output); -} - -auto PSG::Noise::serialize(serializer& s) -> void { - s.integer(volume); - s.integer(counter); - s.integer(pitch); - s.integer(enable); - s.integer(rate); - s.integer(lfsr); - s.integer(clock); - s.integer(output); -} diff --git a/higan/md/psg/tone.cpp b/higan/md/psg/tone.cpp deleted file mode 100644 index caa1af3b..00000000 --- a/higan/md/psg/tone.cpp +++ /dev/null @@ -1,13 +0,0 @@ -auto PSG::Tone::run() -> void { - if(counter--) return; - - counter = pitch; - output ^= 1; -} - -auto PSG::Tone::power() -> void { - volume = ~0; - counter = 0; - pitch = 0; - output = 0; -} diff --git a/higan/md/system/serialization.cpp b/higan/md/system/serialization.cpp deleted file mode 100644 index 430f579a..00000000 --- a/higan/md/system/serialization.cpp +++ /dev/null @@ -1,63 +0,0 @@ -auto System::serializeInit() -> void { - serializer s; - - uint signature = 0; - char version[16] = {0}; - char description[512] = {0}; - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - information.serializeSize = s.size(); -} - -auto System::serialize() -> serializer { - serializer s{information.serializeSize}; - - uint signature = 0x31545342; - char version[16] = {0}; - char description[512] = {0}; - memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size()); - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - return s; -} - -auto System::unserialize(serializer& s) -> bool { - uint signature = 0; - char version[16] = {0}; - char description[512] = {0}; - - s.integer(signature); - s.array(version); - s.array(description); - - if(signature != 0x31545342) return false; - if(string{version} != Emulator::SerializerVersion) return false; - - power(/* reset = */ false); - serializeAll(s); - return true; -} - -auto System::serializeAll(serializer& s) -> void { - system.serialize(s); - cartridge.serialize(s); - cpu.serialize(s); - apu.serialize(s); - vdp.serialize(s); - psg.serialize(s); - ym2612.serialize(s); - controllerPort1.serialize(s); - controllerPort2.serialize(s); - extensionPort.serialize(s); -} - -auto System::serialize(serializer& s) -> void { -} diff --git a/higan/md/system/system.cpp b/higan/md/system/system.cpp deleted file mode 100644 index ea2696d3..00000000 --- a/higan/md/system/system.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include - -namespace MegaDrive { - -System system; -Scheduler scheduler; -Random random; -Cheat cheat; -#include "serialization.cpp" - -auto System::run() -> void { - if(scheduler.enter() == Scheduler::Event::Frame) vdp.refresh(); -} - -auto System::runToSave() -> void { - scheduler.synchronize(cpu); - scheduler.synchronize(apu); - scheduler.synchronize(vdp); - scheduler.synchronize(psg); - scheduler.synchronize(ym2612); -} - -auto System::load(Emulator::Interface* interface, maybe region) -> bool { - information = {}; - - if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else return false; - - auto document = BML::unserialize(information.manifest); - auto system = document["system"]; - if(!cpu.load(system)) return false; - if(!cartridge.load()) return false; - - if(cartridge.region() == "NTSC-J") { - information.region = Region::NTSCJ; - information.frequency = Emulator::Constants::Colorburst::NTSC * 15.0; - } - if(cartridge.region() == "NTSC-U") { - information.region = Region::NTSCU; - information.frequency = Emulator::Constants::Colorburst::NTSC * 15.0; - } - if(cartridge.region() == "PAL") { - information.region = Region::PAL; - information.frequency = Emulator::Constants::Colorburst::PAL * 12.0; - } - - serializeInit(); - this->interface = interface; - return information.loaded = true; -} - -auto System::save() -> void { - cartridge.save(); -} - -auto System::unload() -> void { - cpu.peripherals.reset(); - controllerPort1.unload(); - controllerPort2.unload(); - extensionPort.unload(); - cartridge.unload(); -} - -auto System::power(bool reset) -> void { - Emulator::video.reset(interface); - Emulator::video.setPalette(); - - Emulator::audio.reset(interface); - - random.entropy(Random::Entropy::High); - - scheduler.reset(); - cartridge.power(); - cpu.power(reset); - apu.power(reset); - vdp.power(reset); - psg.power(reset); - ym2612.power(reset); - scheduler.primary(cpu); - - controllerPort1.power(ID::Port::Controller1); - controllerPort2.power(ID::Port::Controller2); - extensionPort.power(ID::Port::Extension); - - controllerPort1.connect(settings.controllerPort1); - controllerPort2.connect(settings.controllerPort2); - extensionPort.connect(settings.extensionPort); -} - -} diff --git a/higan/md/system/system.hpp b/higan/md/system/system.hpp deleted file mode 100644 index 99994b9c..00000000 --- a/higan/md/system/system.hpp +++ /dev/null @@ -1,43 +0,0 @@ -struct System { - enum class Region : uint { - NTSCJ, - NTSCU, - PAL, - }; - - auto loaded() const -> bool { return information.loaded; } - auto region() const -> Region { return information.region; } - auto frequency() const -> double { return information.frequency; } - - auto run() -> void; - auto runToSave() -> void; - - auto load(Emulator::Interface*, maybe = nothing) -> bool; - auto save() -> void; - auto unload() -> void; - auto power(bool reset) -> void; - - //serialization.cpp - auto serializeInit() -> void; - auto serialize() -> serializer; - auto unserialize(serializer&) -> bool; - auto serializeAll(serializer&) -> void; - auto serialize(serializer&) -> void; - -private: - Emulator::Interface* interface = nullptr; - - struct Information { - string manifest; - bool loaded = false; - Region region = Region::NTSCJ; - double frequency = Emulator::Constants::Colorburst::NTSC * 15.0; - uint serializeSize = 0; - } information; -}; - -extern System system; - -auto Region::NTSCJ() -> bool { return system.region() == System::Region::NTSCJ; } -auto Region::NTSCU() -> bool { return system.region() == System::Region::NTSCU; } -auto Region::PAL() -> bool { return system.region() == System::Region::PAL; } diff --git a/higan/md/vdp/background.cpp b/higan/md/vdp/background.cpp deleted file mode 100644 index d7288347..00000000 --- a/higan/md/vdp/background.cpp +++ /dev/null @@ -1,80 +0,0 @@ -auto VDP::Background::isWindowed(uint x, uint y) -> bool { - if((x < io.horizontalOffset) ^ io.horizontalDirection) return true; - if((y < io.verticalOffset ) ^ io.verticalDirection ) return true; - return false; -} - -auto VDP::Background::updateHorizontalScroll(uint y) -> void { - if(id == ID::Window) return; - - uint15 address = io.horizontalScrollAddress; - - static const uint mask[] = {0u, 7u, ~7u, ~0u}; - address += (y & mask[io.horizontalScrollMode]) << 1; - address += id == ID::PlaneB; - - state.horizontalScroll = vdp.vram.read(address).bits(0,9); -} - -auto VDP::Background::updateVerticalScroll(uint x) -> void { - if(id == ID::Window) return; - - auto address = (x >> 4 & 0 - io.verticalScrollMode) << 1; - address += id == ID::PlaneB; - - state.verticalScroll = vdp.vsram.read(address); -} - -auto VDP::Background::nametableAddress() -> uint15 { - if(id == ID::Window && vdp.screenWidth() == 320) return io.nametableAddress & ~0x0400; - return io.nametableAddress; -} - -auto VDP::Background::nametableWidth() -> uint { - if(id == ID::Window) return vdp.screenWidth() == 320 ? 64 : 32; - return 32 * (1 + io.nametableWidth); -} - -auto VDP::Background::nametableHeight() -> uint { - if(id == ID::Window) return 32; - return 32 * (1 + io.nametableHeight); -} - -auto VDP::Background::scanline(uint y) -> void { - updateHorizontalScroll(y); -} - -auto VDP::Background::run(uint x, uint y) -> void { - updateVerticalScroll(x); - - bool interlace = vdp.io.interlaceMode == 3; - if(interlace) y = y << 1 | vdp.state.field; - - x -= state.horizontalScroll; - y += state.verticalScroll; - - uint tileX = x >> 3 & nametableWidth() - 1; - uint tileY = y >> 3 + interlace & nametableHeight() - 1; - - auto address = nametableAddress(); - address += (tileY * nametableWidth() + tileX) & 0x0fff; - - uint pixelX = x & 7; - uint pixelY = y & 7 + interlace * 8; - - uint16 tileAttributes = vdp.vram.read(address); - uint15 tileAddress = tileAttributes.bits(0,10) << 4 + interlace; - if(tileAttributes.bit(11)) pixelX ^= 7; - if(tileAttributes.bit(12)) pixelY ^= 7 + interlace * 8; - tileAddress += pixelY << 1 | pixelX >> 2; - - uint16 tileData = vdp.vram.read(tileAddress); - uint4 color = tileData >> (((pixelX & 3) ^ 3) << 2); - output.color = color ? tileAttributes.bits(13,14) << 4 | color : 0; - output.priority = tileAttributes.bit(15); -} - -auto VDP::Background::power() -> void { - io = {}; - state = {}; -} diff --git a/higan/md/vdp/dma.cpp b/higan/md/vdp/dma.cpp deleted file mode 100644 index 1f12311e..00000000 --- a/higan/md/vdp/dma.cpp +++ /dev/null @@ -1,51 +0,0 @@ -auto VDP::DMA::run() -> void { - if(!io.enable || io.wait) return; - - if(!vdp.io.command.bit(5)) return; - if(io.mode <= 1) return load(); - if(io.mode == 2) return fill(); - if(!vdp.io.command.bit(4)) return; - if(io.mode == 3) return copy(); -} - -auto VDP::DMA::load() -> void { - cpu.wait |= Wait::VDP_DMA; - - auto data = cpu.readWord(io.mode.bit(0) << 23 | io.source << 1); - vdp.writeDataPort(data); - - io.source.bits(0,15)++; - if(--io.length == 0) { - vdp.io.command.bit(5) = 0; - cpu.wait &=~ Wait::VDP_DMA; - } -} - -//todo: supposedly, this can also write to VSRAM and CRAM (undocumented) -auto VDP::DMA::fill() -> void { - if(vdp.io.command.bits(0,3) == 1) { - vdp.vram.writeByte(vdp.io.address, io.fill); - } - - io.source.bits(0,15)++; - vdp.io.address += vdp.io.dataIncrement; - if(--io.length == 0) { - vdp.io.command.bit(5) = 0; - } -} - -//note: this can only copy to VRAM -auto VDP::DMA::copy() -> void { - auto data = vdp.vram.readByte(io.source); - vdp.vram.writeByte(vdp.io.address, data); - - io.source.bits(0,15)++; - vdp.io.address += vdp.io.dataIncrement; - if(--io.length == 0) { - vdp.io.command.bit(5) = 0; - } -} - -auto VDP::DMA::power() -> void { - io = {}; -} diff --git a/higan/md/vdp/io.cpp b/higan/md/vdp/io.cpp deleted file mode 100644 index d453e9ec..00000000 --- a/higan/md/vdp/io.cpp +++ /dev/null @@ -1,335 +0,0 @@ -auto VDP::read(uint24 addr) -> uint16 { - switch(addr & 0xc0001e) { - - //data port - case 0xc00000: case 0xc00002: { - return readDataPort(); - } - - //control port - case 0xc00004: case 0xc00006: { - return readControlPort(); - } - - //counter - case 0xc00008: case 0xc0000a: case 0xc0000c: case 0xc0000e: { - auto vcounter = state.vcounter; - if(io.interlaceMode.bit(0)) { - if(io.interlaceMode.bit(1)) vcounter <<= 1; - vcounter.bit(0) = vcounter.bit(8); - } - return vcounter << 8 | (state.hdot >> 1) << 0; - } - - } - - return 0x0000; -} - -auto VDP::write(uint24 addr, uint16 data) -> void { - switch(addr & 0xc0001e) { - - //data port - case 0xc00000: case 0xc00002: { - return writeDataPort(data); - } - - //control port - case 0xc00004: case 0xc00006: { - return writeControlPort(data); - } - - } -} - -// - -auto VDP::readDataPort() -> uint16 { - io.commandPending = false; - - //VRAM read - if(io.command.bits(0,3) == 0) { - auto address = io.address.bits(1,15); - auto data = vram.read(address); - io.address += io.dataIncrement; - return data; - } - - //VSRAM read - if(io.command.bits(0,3) == 4) { - auto address = io.address.bits(1,6); - auto data = vsram.read(address); - io.address += io.dataIncrement; - return data; - } - - //CRAM read - if(io.command.bits(0,3) == 8) { - auto address = io.address.bits(1,6); - auto data = cram.read(address); - io.address += io.dataIncrement; - return data.bits(0,2) << 1 | data.bits(3,5) << 5 | data.bits(6,8) << 9; - } - - return 0x0000; -} - -auto VDP::writeDataPort(uint16 data) -> void { - io.commandPending = false; - - //DMA VRAM fill - if(dma.io.wait) { - dma.io.wait = false; - dma.io.fill = data >> 8; - //falls through to memory write - //causes extra transfer to occur on VRAM fill operations - } - - //VRAM write - if(io.command.bits(0,3) == 1) { - auto address = io.address.bits(1,15); - if(io.address.bit(0)) data = data >> 8 | data << 8; - vram.write(address, data); - io.address += io.dataIncrement; - return; - } - - //VSRAM write - if(io.command.bits(0,3) == 5) { - auto address = io.address.bits(1,6); - //data format: ---- --yy yyyy yyyy - vsram.write(address, data.bits(0,9)); - io.address += io.dataIncrement; - return; - } - - //CRAM write - if(io.command.bits(0,3) == 3) { - auto address = io.address.bits(1,6); - //data format: ---- bbb- ggg- rrr- - cram.write(address, data.bits(1,3) << 0 | data.bits(5,7) << 3 | data.bits(9,11) << 6); - io.address += io.dataIncrement; - return; - } -} - -// - -auto VDP::readControlPort() -> uint16 { - io.commandPending = false; - - uint16 result; - result.bit( 0) = Region::PAL(); - result.bit( 1) = io.command.bit(5); //DMA active - result.bit( 2) = state.hcounter >= 1280; //horizontal blank - result.bit( 3) = state.vcounter >= screenHeight(); //vertical blank - result.bit( 4) = io.interlaceMode.bit(0) && state.field; - result.bit( 5) = 0; //SCOL - result.bit( 6) = 0; //SOVR - result.bit( 7) = io.vblankIRQ; - result.bit( 8) = 0; //FIFO full - result.bit( 9) = 1; //FIFO empty - result.bit(10) = 1; //constants (bits 10-15) - result.bit(11) = 0; - result.bit(12) = 1; - result.bit(13) = 1; - result.bit(14) = 0; - result.bit(15) = 0; - return result; -} - -auto VDP::writeControlPort(uint16 data) -> void { -//print("[VDPC] ", hex(data, 4L), "\n"); - - //command write (lo) - if(io.commandPending) { - io.commandPending = false; - - io.command.bits(2,5) = data.bits(4,7); - io.address.bits(14,15) = data.bits(0,1); - if(!dma.io.enable) io.command.bit(5) = 0; - if(dma.io.mode == 3) dma.io.wait = false; - return; - } - - //command write (hi) - if(data.bits(14,15) != 2) { - io.commandPending = true; - - io.command.bits(0,1) = data.bits(14,15); - io.address.bits(0,13) = data.bits(0,13); - return; - } - - //register write (d13 is ignored) - if(data.bits(14,15) == 2) - switch(data.bits(8,12)) { - - //mode register 1 - case 0x00: { - io.displayOverlayEnable = data.bit(0); - io.counterLatch = data.bit(1); - io.horizontalBlankInterruptEnable = data.bit(4); - io.leftColumnBlank = data.bit(5); - return; - } - - //mode register 2 - case 0x01: { - io.videoMode = data.bit(2); - io.overscan = data.bit(3); - dma.io.enable = data.bit(4); - io.verticalBlankInterruptEnable = data.bit(5); - io.displayEnable = data.bit(6); - io.externalVRAM = data.bit(7); - - if(!dma.io.enable) io.command.bit(5) = 0; - - return; - } - - //plane A name table location - case 0x02: { - planeA.io.nametableAddress = data.bits(3,6) << 12; - return; - } - - //window name table location - case 0x03: { - window.io.nametableAddress = data.bits(1,6) << 10; - return; - } - - //plane B name table location - case 0x04: { - planeB.io.nametableAddress = data.bits(0,3) << 12; - return; - } - - //sprite attribute table location - case 0x05: { - sprite.io.attributeAddress = data.bits(0,7) << 8; - return; - } - - //sprite pattern base address - case 0x06: { - sprite.io.nametableAddressBase = data.bit(5); - return; - } - - //background color - case 0x07: { - io.backgroundColor = data.bits(0,5); - return; - } - - //horizontal interrupt counter - case 0x0a: { - io.horizontalInterruptCounter = data.bits(0,7); - return; - } - - //mode register 3 - case 0x0b: { - planeA.io.horizontalScrollMode = data.bits(0,1); - planeB.io.horizontalScrollMode = data.bits(0,1); - planeA.io.verticalScrollMode = data.bit(2); - planeB.io.verticalScrollMode = data.bit(2); - io.externalInterruptEnable = data.bit(3); - return; - } - - //mode register 4 - case 0x0c: { - io.displayWidth = data.bit(0) | data.bit(7) << 1; - io.interlaceMode = data.bits(1,2); - io.shadowHighlightEnable = data.bit(3); - io.externalColorEnable = data.bit(4); - io.horizontalSync = data.bit(5); - io.verticalSync = data.bit(6); - return; - } - - //horizontal scroll data location - case 0x0d: { - planeA.io.horizontalScrollAddress = data.bits(0,6) << 9; - planeB.io.horizontalScrollAddress = data.bits(0,6) << 9; - return; - } - - //nametable pattern base address - case 0x0e: { - io.nametableBasePatternA = data.bit(0); - io.nametableBasePatternB = data.bit(1); - return; - } - - //data port auto-increment value - case 0x0f: { - io.dataIncrement = data.bits(0,7); - return; - } - - //plane size - case 0x10: { - planeA.io.nametableWidth = data.bits(0,1); - planeB.io.nametableWidth = data.bits(0,1); - planeA.io.nametableHeight = data.bits(4,5); - planeB.io.nametableHeight = data.bits(4,5); - return; - } - - //window plane horizontal position - case 0x11: { - window.io.horizontalDirection = data.bit(7); - window.io.horizontalOffset = data.bits(0,4) << 4; - return; - } - - //window plane vertical position - case 0x12: { - window.io.verticalDirection = data.bit(7); - window.io.verticalOffset = data.bits(0,4) << 3; - return; - } - - //DMA length - case 0x13: { - dma.io.length.bits(0,7) = data.bits(0,7); - return; - } - - //DMA length - case 0x14: { - dma.io.length.bits(8,15) = data.bits(0,7); - return; - } - - //DMA source - case 0x15: { - dma.io.source.bits(0,7) = data.bits(0,7); - return; - } - - //DMA source - case 0x16: { - dma.io.source.bits(8,15) = data.bits(0,7); - return; - } - - //DMA source - case 0x17: { - dma.io.source.bits(16,21) = data.bits(0,5); - dma.io.mode = data.bits(6,7); - dma.io.wait = dma.io.mode.bit(1); - return; - } - - //unused - default: { - return; - } - - } -} diff --git a/higan/md/vdp/memory.cpp b/higan/md/vdp/memory.cpp deleted file mode 100644 index 7d4f3eca..00000000 --- a/higan/md/vdp/memory.cpp +++ /dev/null @@ -1,38 +0,0 @@ -auto VDP::VRAM::read(uint15 address) const -> uint16 { - return memory[address]; -} - -auto VDP::VRAM::write(uint15 address, uint16 data) -> void { - memory[address] = data; - if(address < vdp.sprite.io.attributeAddress) return; - if(address > vdp.sprite.io.attributeAddress + 319) return; - vdp.sprite.write(address - vdp.sprite.io.attributeAddress, data); -} - -auto VDP::VRAM::readByte(uint16 address) const -> uint8 { - return read(address >> 1).byte(!address.bit(0)); -} - -auto VDP::VRAM::writeByte(uint16 address, uint8 data) -> void { - auto word = read(address >> 1); - word.byte(!address.bit(0)) = data; - write(address >> 1, word); -} - -auto VDP::VSRAM::read(uint6 address) const -> uint10 { - if(address >= 40) return 0x0000; - return memory[address]; -} - -auto VDP::VSRAM::write(uint6 address, uint10 data) -> void { - if(address >= 40) return; - memory[address] = data; -} - -auto VDP::CRAM::read(uint6 address) const -> uint9 { - return memory[address]; -} - -auto VDP::CRAM::write(uint6 address, uint9 data) -> void { - memory[address] = data; -} diff --git a/higan/md/vdp/render.cpp b/higan/md/vdp/render.cpp deleted file mode 100644 index 3d1cbeb9..00000000 --- a/higan/md/vdp/render.cpp +++ /dev/null @@ -1,64 +0,0 @@ -auto VDP::scanline() -> void { - if(state.vcounter < screenHeight()) { - planeA.scanline(state.vcounter); - window.scanline(state.vcounter); - planeB.scanline(state.vcounter); - sprite.scanline(state.vcounter); - } - - if(state.vcounter == 240) scheduler.exit(Scheduler::Event::Frame); - - state.output = output + (state.vcounter * 2 + 0) * 1280; -} - -auto VDP::run() -> void { - if(!io.displayEnable) return outputPixel(0); - if(state.vcounter >= screenHeight()) return outputPixel(0); - - auto& planeA = window.isWindowed(state.hdot, state.vcounter) ? window : this->planeA; - planeA.run(state.hdot, state.vcounter); - planeB.run(state.hdot, state.vcounter); - sprite.run(state.hdot, state.vcounter); - - Pixel g = {io.backgroundColor, 0}; - Pixel a = planeA.output; - Pixel b = planeB.output; - Pixel s = sprite.output; - - auto& bg = a.above() || a.color && !b.above() ? a : b.color ? b : g; - auto& fg = s.above() || s.color && !b.above() && !a.above() ? s : bg; - - if(!io.shadowHighlightEnable) { - auto color = cram.read(fg.color); - outputPixel(1 << 9 | color); - } else { - uint mode = a.priority || b.priority; //0 = shadow, 1 = normal, 2 = highlight - - if(&fg == &s) switch(s.color) { - case 0x0e: - case 0x1e: - case 0x2e: mode = 1; break; - case 0x3e: mode += 1; fg = bg; break; - case 0x3f: mode = 0; fg = bg; break; - default: mode |= s.priority; break; - } - - auto color = cram.read(fg.color); - outputPixel(mode << 9 | color); - } -} - -auto VDP::outputPixel(uint32 color) -> void { - uint32* field[2] = {&state.output[0], &state.output[1280]}; - if(!io.interlaceMode.bit(0)) { - for(auto n : range(pixelWidth())) { - field[0][n] = color; - field[1][n] = color; - } - } else { - for(auto n : range(pixelWidth())) { - field[state.field][n] = color; - } - } - state.output += pixelWidth(); -} diff --git a/higan/md/vdp/serialization.cpp b/higan/md/vdp/serialization.cpp deleted file mode 100644 index 6288ee2b..00000000 --- a/higan/md/vdp/serialization.cpp +++ /dev/null @@ -1,112 +0,0 @@ -auto VDP::serialize(serializer& s) -> void { - Thread::serialize(s); - - dma.serialize(s); - planeA.serialize(s); - window.serialize(s); - planeB.serialize(s); - sprite.serialize(s); - - vram.serialize(s); - vsram.serialize(s); - cram.serialize(s); - - s.integer(io.vblankIRQ); - s.integer(io.command); - s.integer(io.address); - s.integer(io.commandPending); - s.integer(io.displayOverlayEnable); - s.integer(io.counterLatch); - s.integer(io.horizontalBlankInterruptEnable); - s.integer(io.leftColumnBlank); - s.integer(io.videoMode); - s.integer(io.overscan); - s.integer(io.verticalBlankInterruptEnable); - s.integer(io.displayEnable); - s.integer(io.externalVRAM); - s.integer(io.backgroundColor); - s.integer(io.horizontalInterruptCounter); - s.integer(io.externalInterruptEnable); - s.integer(io.displayWidth); - s.integer(io.interlaceMode); - s.integer(io.shadowHighlightEnable); - s.integer(io.externalColorEnable); - s.integer(io.horizontalSync); - s.integer(io.verticalSync); - s.integer(io.nametableBasePatternA); - s.integer(io.nametableBasePatternB); - s.integer(io.dataIncrement); - - s.integer(latch.overscan); - s.integer(latch.horizontalInterruptCounter); - s.integer(latch.displayWidth); - - s.integer(state.hdot); - s.integer(state.hcounter); - s.integer(state.vcounter); - s.integer(state.field); -} - -auto VDP::DMA::serialize(serializer& s) -> void { - s.integer(io.mode); - s.integer(io.source); - s.integer(io.length); - s.integer(io.fill); - s.integer(io.enable); - s.integer(io.wait); -} - -auto VDP::Background::serialize(serializer& s) -> void { - s.integer(io.nametableAddress); - s.integer(io.nametableWidth); - s.integer(io.nametableHeight); - s.integer(io.horizontalScrollAddress); - s.integer(io.horizontalScrollMode); - s.integer(io.verticalScrollMode); - s.integer(io.horizontalDirection); - s.integer(io.horizontalOffset); - s.integer(io.verticalDirection); - s.integer(io.verticalOffset); - - s.integer(state.horizontalScroll); - s.integer(state.verticalScroll); - - s.integer(output.color); - s.integer(output.priority); -} - -auto VDP::Object::serialize(serializer& s) -> void { - s.integer(x); - s.integer(y); - s.integer(tileWidth); - s.integer(tileHeight); - s.integer(horizontalFlip); - s.integer(verticalFlip); - s.integer(palette); - s.integer(priority); - s.integer(address); - s.integer(link); -} - -auto VDP::Sprite::serialize(serializer& s) -> void { - s.integer(io.attributeAddress); - s.integer(io.nametableAddressBase); - - s.integer(output.color); - s.integer(output.priority); - - for(uint n : range(80)) oam[n].serialize(s); - for(uint n : range(20)) objects[n].serialize(s); -} - -auto VDP::VRAM::serialize(serializer& s) -> void { - s.array(memory); -} - -auto VDP::VSRAM::serialize(serializer& s) -> void { - s.array(memory); -} - -auto VDP::CRAM::serialize(serializer& s) -> void { - s.array(memory); -} diff --git a/higan/md/vdp/sprite.cpp b/higan/md/vdp/sprite.cpp deleted file mode 100644 index 6247911b..00000000 --- a/higan/md/vdp/sprite.cpp +++ /dev/null @@ -1,105 +0,0 @@ -auto VDP::Object::width() const -> uint { - return 1 + tileWidth << 3; -} - -auto VDP::Object::height() const -> uint { - return 1 + tileHeight << 3 + (vdp.io.interlaceMode == 3); -} - -auto VDP::Sprite::write(uint9 address, uint16 data) -> void { - if(address > 320) return; - - auto& object = oam[address >> 2]; - switch(address.bits(0,1)) { - - case 0: { - object.y = data.bits(0,9); - break; - } - - case 1: { - object.link = data.bits(0,6); - object.tileHeight = data.bits(8,9); - object.tileWidth = data.bits(10,11); - break; - } - - case 2: { - object.address = data.bits(0,10); - object.horizontalFlip = data.bit(11); - object.verticalFlip = data.bit(12); - object.palette = data.bits(13,14); - object.priority = data.bit(15); - break; - } - - case 3: { - object.x = data.bits(0,8); - break; - } - - } -} - -auto VDP::Sprite::scanline(uint y) -> void { - bool interlace = vdp.io.interlaceMode == 3; - y += 128; - if(interlace) y = y << 1 | vdp.state.field; - - objects.reset(); - - uint7 link = 0; - uint tiles = 0; - uint count = 0; - do { - auto& object = oam[link]; - link = object.link; - - if(y < object.y) continue; - if(y >= object.y + object.height()) continue; - if(object.x == 0) break; - - objects.append(object); - tiles += object.width() >> 3; - } while(link && link < 80 && objects.size() < 20 && tiles < 40 && ++count < 80); -} - -auto VDP::Sprite::run(uint x, uint y) -> void { - bool interlace = vdp.io.interlaceMode == 3; - x += 128; - y += 128; - if(interlace) y = y << 1 | vdp.state.field; - - output.priority = 0; - output.color = 0; - - for(auto& object : objects) { - if(x < object.x) continue; - if(x >= object.x + object.width()) continue; - - uint objectX = x - object.x; - uint objectY = y - object.y; - if(object.horizontalFlip) objectX = (object.width() - 1) - objectX; - if(object.verticalFlip) objectY = (object.height() - 1) - objectY; - - uint tileX = objectX >> 3; - uint tileY = objectY >> 3 + interlace; - uint tileNumber = tileX * (object.height() >> 3 + interlace) + tileY; - uint15 tileAddress = object.address + tileNumber << 4 + interlace; - uint pixelX = objectX & 7; - uint pixelY = objectY & 7 + interlace * 8; - tileAddress += pixelY << 1 | pixelX >> 2; - - uint16 tileData = vdp.vram.read(tileAddress); - uint4 color = tileData >> (((pixelX & 3) ^ 3) << 2); - if(!color) continue; - - output.color = object.palette << 4 | color; - output.priority = object.priority; - break; - } -} - -auto VDP::Sprite::power() -> void { - io = {}; -} diff --git a/higan/md/vdp/vdp.cpp b/higan/md/vdp/vdp.cpp deleted file mode 100644 index 9e79d715..00000000 --- a/higan/md/vdp/vdp.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include - -namespace MegaDrive { - -VDP vdp; -#include "memory.cpp" -#include "io.cpp" -#include "dma.cpp" -#include "render.cpp" -#include "background.cpp" -#include "sprite.cpp" -#include "serialization.cpp" - -auto VDP::Enter() -> void { - while(true) scheduler.synchronize(), vdp.main(); -} - -auto VDP::main() -> void { - scanline(); - - cpu.lower(CPU::Interrupt::HorizontalBlank); - apu.setINT(false); - - if(state.vcounter == 0) { - latch.horizontalInterruptCounter = io.horizontalInterruptCounter; - io.vblankIRQ = false; - cpu.lower(CPU::Interrupt::VerticalBlank); - } - - if(state.vcounter == screenHeight()) { - if(io.verticalBlankInterruptEnable) { - io.vblankIRQ = true; - cpu.raise(CPU::Interrupt::VerticalBlank); - } - //todo: should only stay high for ~2573/2 clocks - apu.setINT(true); - } - - if(state.vcounter < screenHeight()) { - while(state.hcounter < 1280) { - run(); - state.hdot++; - step(pixelWidth()); - } - - if(latch.horizontalInterruptCounter-- == 0) { - latch.horizontalInterruptCounter = io.horizontalInterruptCounter; - if(io.horizontalBlankInterruptEnable) { - cpu.raise(CPU::Interrupt::HorizontalBlank); - } - } - - step(430); - } else { - step(1710); - } - - state.hdot = 0; - state.hcounter = 0; - if(++state.vcounter >= frameHeight()) { - state.vcounter = 0; - state.field ^= 1; - latch.overscan = io.overscan; - } - latch.displayWidth = io.displayWidth; -} - -auto VDP::step(uint clocks) -> void { - state.hcounter += clocks; - while(clocks--) { - dma.run(); - Thread::step(1); - synchronize(cpu); - synchronize(apu); - } -} - -auto VDP::refresh() -> void { - auto data = output; - if(!latch.overscan) data -= 16 * 1280; - Emulator::video.refresh(data, 1280 * sizeof(uint32), 1280, 480); -} - -auto VDP::power(bool reset) -> void { - create(VDP::Enter, system.frequency() / 2.0); - - output = buffer + 16 * 1280; //overscan offset - - if(!reset) { - for(auto& data : vram.memory) data = 0; - for(auto& data : vsram.memory) data = 0; - for(auto& data : cram.memory) data = 0; - } - - io = {}; - latch = {}; - state = {}; - - planeA.power(); - window.power(); - planeB.power(); - sprite.power(); - dma.power(); -} - -} diff --git a/higan/md/vdp/vdp.hpp b/higan/md/vdp/vdp.hpp deleted file mode 100644 index 3ddb6a9f..00000000 --- a/higan/md/vdp/vdp.hpp +++ /dev/null @@ -1,266 +0,0 @@ -//Yamaha YM7101 - -struct VDP : Thread { - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - auto refresh() -> void; - - auto power(bool reset) -> void; - - //io.cpp - auto read(uint24 addr) -> uint16; - auto write(uint24 addr, uint16 data) -> void; - - auto readDataPort() -> uint16; - auto writeDataPort(uint16 data) -> void; - - auto readControlPort() -> uint16; - auto writeControlPort(uint16 data) -> void; - - struct DMA { - //dma.cpp - auto run() -> void; - auto load() -> void; - auto fill() -> void; - auto copy() -> void; - - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - struct IO { - uint2 mode; - uint22 source; - uint16 length; - uint8 fill; - uint1 enable; - uint1 wait; - } io; - } dma; - - //render.cpp - auto scanline() -> void; - auto run() -> void; - auto outputPixel(uint32 color) -> void; - - struct Pixel { - inline auto above() const -> bool { return priority == 1 && color; } - inline auto below() const -> bool { return priority == 0 && color; } - - uint6 color; - uint1 priority; - }; - - struct Background { - enum class ID : uint { PlaneA, Window, PlaneB } id; - - //background.cpp - auto isWindowed(uint x, uint y) -> bool; - - auto updateHorizontalScroll(uint y) -> void; - auto updateVerticalScroll(uint x) -> void; - - auto nametableAddress() -> uint15; - auto nametableWidth() -> uint; - auto nametableHeight() -> uint; - - auto scanline(uint y) -> void; - auto run(uint x, uint y) -> void; - - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - struct IO { - uint15 nametableAddress; - - //PlaneA, PlaneB - uint2 nametableWidth; - uint2 nametableHeight; - uint15 horizontalScrollAddress; - uint2 horizontalScrollMode; - uint1 verticalScrollMode; - - //Window - uint1 horizontalDirection; - uint10 horizontalOffset; - uint1 verticalDirection; - uint10 verticalOffset; - } io; - - struct State { - uint10 horizontalScroll; - uint10 verticalScroll; - } state; - - Pixel output; - }; - Background planeA{Background::ID::PlaneA}; - Background window{Background::ID::Window}; - Background planeB{Background::ID::PlaneB}; - - struct Object { - //sprite.cpp - inline auto width() const -> uint; - inline auto height() const -> uint; - - //serialization.cpp - auto serialize(serializer&) -> void; - - uint9 x; - uint10 y; - uint2 tileWidth; - uint2 tileHeight; - uint1 horizontalFlip; - uint1 verticalFlip; - uint2 palette; - uint1 priority; - uint11 address; - uint7 link; - }; - - struct Sprite { - //sprite.cpp - auto write(uint9 addr, uint16 data) -> void; - auto scanline(uint y) -> void; - auto run(uint x, uint y) -> void; - - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - struct IO { - uint15 attributeAddress; - uint1 nametableAddressBase; - } io; - - Pixel output; - - adaptive_array oam; - adaptive_array objects; - }; - Sprite sprite; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - auto pixelWidth() const -> uint { return latch.displayWidth ? 4 : 5; } - auto screenWidth() const -> uint { return latch.displayWidth ? 320 : 256; } - auto screenHeight() const -> uint { return latch.overscan ? 240 : 224; } - auto frameHeight() const -> uint { return Region::PAL() ? 312 : 262; } - - //video RAM - struct VRAM { - //memory.cpp - auto read(uint15 address) const -> uint16; - auto write(uint15 address, uint16 data) -> void; - - auto readByte(uint16 address) const -> uint8; - auto writeByte(uint16 address, uint8 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - uint16 memory[32768]; - } vram; - - //vertical scroll RAM - struct VSRAM { - //memory.cpp - auto read(uint6 address) const -> uint10; - auto write(uint6 address, uint10 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - uint10 memory[40]; - } vsram; - - //color RAM - struct CRAM { - //memory.cpp - auto read(uint6 address) const -> uint9; - auto write(uint6 address, uint9 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - uint9 memory[64]; - } cram; - - struct IO { - //status - uint1 vblankIRQ; //true after VIRQ triggers; cleared at start of next frame - - //command - uint6 command; - uint16 address; - uint1 commandPending; - - //$00 mode register 1 - uint1 displayOverlayEnable; - uint1 counterLatch; - uint1 horizontalBlankInterruptEnable; - uint1 leftColumnBlank; - - //$01 mode register 2 - uint1 videoMode; //0 = Master System; 1 = Mega Drive - uint1 overscan; //0 = 224 lines; 1 = 240 lines - uint1 verticalBlankInterruptEnable; - uint1 displayEnable; - uint1 externalVRAM; - - //$07 background color - uint6 backgroundColor; - - //$0a horizontal interrupt counter - uint8 horizontalInterruptCounter; - - //$0b mode register 3 - uint1 externalInterruptEnable; - - //$0c mode register 4 - uint2 displayWidth; - uint2 interlaceMode; - uint1 shadowHighlightEnable; - uint1 externalColorEnable; - uint1 horizontalSync; - uint1 verticalSync; - - //$0e nametable pattern base address - uint1 nametableBasePatternA; - uint1 nametableBasePatternB; - - //$0f data port auto-increment value - uint8 dataIncrement; - } io; - - struct Latch { - //per-frame - uint1 overscan; - uint8 horizontalInterruptCounter; - - //per-scanline - uint2 displayWidth; - } latch; - - struct State { - uint32* output = nullptr; - uint16 hdot; - uint16 hcounter; - uint16 vcounter; - uint1 field; - } state; - - uint32 buffer[1280 * 512]; - uint32* output = nullptr; - - friend class Interface; -}; - -extern VDP vdp; diff --git a/higan/md/ym2612/channel.cpp b/higan/md/ym2612/channel.cpp deleted file mode 100644 index 1f35ce13..00000000 --- a/higan/md/ym2612/channel.cpp +++ /dev/null @@ -1,192 +0,0 @@ -auto YM2612::Channel::Operator::trigger(bool state) -> void { - if(keyOn == state) return; //no change - - keyOn = state; - envelope.state = Release; - updateEnvelope(); - - if(keyOn) { - //restart phase and envelope generators - phase.value = 0; - ssg.invert = false; - envelope.state = Attack; - updateEnvelope(); - - if(envelope.rate >= 62) { - //skip attack and possibly decay stages - envelope.value = 0; - envelope.state = envelope.sustainLevel ? Decay : Sustain; - updateEnvelope(); - } - } else if(ssg.enable && ssg.attack != ssg.invert) { - //SSG-EG key-off - envelope.value = 0x200 - envelope.value; - } - - updateLevel(); -} - -auto YM2612::Channel::Operator::runEnvelope() -> void { - uint sustain = envelope.sustainLevel < 15 ? envelope.sustainLevel << 5 : 0x3f0; - if(ym2612.envelope.clock & (1 << envelope.divider) - 1) return; - - uint value = ym2612.envelope.clock >> envelope.divider; - uint step = envelope.steps >> ((~value & 7) << 2) & 0xf; - if(ssg.enable) step <<= 2; //SSG results in a 4x faster envelope - - if(envelope.state == Attack) { - uint next = envelope.value + (~uint16(envelope.value) * step >> 4) & 0x3ff; - if(next <= envelope.value) { - envelope.value = next; - } else { - envelope.value = 0; - envelope.state = envelope.value < sustain ? Decay : Sustain; - updateEnvelope(); - } - } else if(!ssg.enable || envelope.value < 0x200) { - envelope.value = min(envelope.value + step, 0x3ff); - if(envelope.state == Decay && envelope.value >= sustain) { - envelope.state = Sustain; - updateEnvelope(); - } - } - - updateLevel(); -} - -auto YM2612::Channel::Operator::runPhase() -> void { - phase.value += phase.delta; //advance wave position - if(!(ssg.enable && envelope.value >= 0x200)) return; //SSG loop check - - if(!ssg.hold && !ssg.alternate) phase.value = 0; - if(!ssg.hold || ssg.attack == ssg.invert) ssg.invert ^= ssg.alternate; - - if(envelope.state == Attack) { - //do nothing; SSG is meant to skip the attack phase - } else if(envelope.state != Release && !ssg.hold) { - //if still looping, reset the envelope - envelope.state = Attack; - if(envelope.attackRate >= 62) { - envelope.value = 0; - envelope.state = envelope.sustainLevel ? Decay : Sustain; - } - updateEnvelope(); - } else if(envelope.state == Release || (ssg.hold && ssg.attack == ssg.invert)) { - //clear envelope once finished - envelope.value = 0x3ff; - } - - updateLevel(); -} - -auto YM2612::Channel::Operator::updateEnvelope() -> void { - uint key = min(max((uint)pitch.value, 0x300), 0x4ff); - uint ksr = (octave.value << 2) + ((key - 0x300) >> 7); - uint rate = 0; - - if(envelope.state == Attack) rate += (envelope.attackRate << 1); - if(envelope.state == Decay) rate += (envelope.decayRate << 1); - if(envelope.state == Sustain) rate += (envelope.sustainRate << 1); - if(envelope.state == Release) rate += (envelope.releaseRate << 1); - - rate += (ksr >> 3 - envelope.keyScale) * (rate > 0); - rate = min(rate, 63); - - auto& entry = envelopeRates[rate >> 2]; - envelope.rate = rate; - envelope.divider = entry.divider; - envelope.steps = entry.steps[rate & 3]; -} - -auto YM2612::Channel::Operator::updatePitch() -> void { - //only channel[2] allows per-operator frequencies - //implemented by forcing mode to zero (single frequency) for other channels - //in single frequency mode, operator[3] frequency is used for all operators - pitch.value = channel.mode ? pitch.reload : channel[3].pitch.reload; - octave.value = channel.mode ? octave.reload : channel[3].octave.reload; - - updatePhase(); - updateEnvelope(); //due to key scaling -} - -auto YM2612::Channel::Operator::updatePhase() -> void { - uint key = min(max((uint)pitch.value, 0x300), 0x4ff); - uint ksr = (octave.value << 2) + ((key - 0x300) >> 7); - uint tuning = detune & 3 ? detunes[(detune & 3) - 1][ksr & 7] >> (3 - (ksr >> 3)) : 0; - - uint lfo = ym2612.lfo.clock >> 2 & 0x1f; - uint pm = 4 * vibratos[channel.vibrato][lfo & 15] * (-lfo >> 4); - uint msb = 10; - while(msb > 4 && ~pitch.value & 1 << msb) msb--; - - phase.delta = pitch.value + (pm >> 10 - msb) << 6 >> 7 - octave.value; - phase.delta = (!detune.bit(2) ? phase.delta + tuning : phase.delta - tuning) & 0x1ffff; - phase.delta = (multiple ? phase.delta * multiple : phase.delta >> 1) & 0xfffff; -} - -auto YM2612::Channel::Operator::updateLevel() -> void { - uint lfo = ym2612.lfo.clock & 0x40 ? ym2612.lfo.clock & 0x3f : ~ym2612.lfo.clock & 0x3f; - uint depth = tremolos[channel.tremolo]; - - bool invert = ssg.attack != ssg.invert && envelope.state != Release; - uint10 value = ssg.enable && invert ? 0x200 - envelope.value : 0 + envelope.value; - - outputLevel = ((totalLevel << 3) + value + (lfoEnable ? lfo << 1 >> depth : 0)) << 3; -} - -auto YM2612::Channel::power() -> void { - leftEnable = 1; - rightEnable = 1; - - algorithm = 0; - feedback = 0; - vibrato = 0; - tremolo = 0; - - mode = 0; - - for(auto& op : operators) { - op.keyOn = 0; - op.lfoEnable = 0; - op.detune = 0; - op.multiple = 0; - op.totalLevel = 0; - - op.outputLevel = 0x1fff; - op.output = 0; - op.prior = 0; - - op.pitch.value = 0; - op.pitch.reload = 0; - op.pitch.latch = 0; - - op.octave.value = 0; - op.octave.reload = 0; - op.octave.latch = 0; - - op.phase.value = 0; - op.phase.delta = 0; - - op.envelope.state = Release; - op.envelope.rate = 0; - op.envelope.divider = 11; - op.envelope.steps = 0; - op.envelope.value = 0x3ff; - - op.envelope.keyScale = 0; - op.envelope.attackRate = 0; - op.envelope.decayRate = 0; - op.envelope.sustainRate = 0; - op.envelope.sustainLevel = 0; - op.envelope.releaseRate = 1; - - op.ssg.enable = 0; - op.ssg.attack = 0; - op.ssg.alternate = 0; - op.ssg.hold = 0; - op.ssg.invert = 0; - - op.updatePitch(); - op.updateLevel(); - } -} diff --git a/higan/md/ym2612/constants.cpp b/higan/md/ym2612/constants.cpp deleted file mode 100644 index 0bcdc200..00000000 --- a/higan/md/ym2612/constants.cpp +++ /dev/null @@ -1,53 +0,0 @@ -const uint8_t YM2612::lfoDividers[8] = { - 108, - 77, - 71, - 67, - 62, - 44, - 8, - 5, -}; - -const uint8_t YM2612::vibratos[8][16] = { - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, - {0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0}, - {0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 2, 2, 1, 1, 0, 0}, - {0, 0, 1, 2, 2, 2, 3, 4, 4, 3, 2, 2, 2, 1, 0, 0}, - {0, 0, 2, 3, 4, 4, 5, 6, 6, 5, 4, 4, 3, 2, 0, 0}, - {0, 0, 4, 6, 8, 8,10,12,12,10, 8, 8, 6, 4, 0, 0}, - {0, 0, 8,12,16,16,20,24,24,20,16,16,12, 8, 0, 0}, -}; - -const uint8_t YM2612::tremolos[4] = { - 7, - 3, - 1, - 0, -}; - -const uint8_t YM2612::detunes[3][8] = { - { 5, 6, 6, 7, 8, 8, 9, 10}, - {11, 12, 13, 14, 16, 17, 18, 20}, - {16, 17, 19, 20, 22, 24, 26, 28}, -}; - -const YM2612::EnvelopeRate YM2612::envelopeRates[16] = { - 11, {0x00000000, 0x00000000, 0x01010101, 0x01010101}, - 10, {0x01010101, 0x01010101, 0x01110111, 0x01110111}, - 9, {0x01010101, 0x01011101, 0x01110111, 0x01111111}, - 8, {0x01010101, 0x01011101, 0x01110111, 0x01111111}, - 7, {0x01010101, 0x01011101, 0x01110111, 0x01111111}, - 6, {0x01010101, 0x01011101, 0x01110111, 0x01111111}, - 5, {0x01010101, 0x01011101, 0x01110111, 0x01111111}, - 4, {0x01010101, 0x01011101, 0x01110111, 0x01111111}, - 3, {0x01010101, 0x01011101, 0x01110111, 0x01111111}, - 2, {0x01010101, 0x01011101, 0x01110111, 0x01111111}, - 1, {0x01010101, 0x01011101, 0x01110111, 0x01111111}, - 0, {0x01010101, 0x01011101, 0x01110111, 0x01111111}, - 0, {0x11111111, 0x11121112, 0x12121212, 0x12221222}, - 0, {0x22222222, 0x22242224, 0x24242424, 0x24442444}, - 0, {0x44444444, 0x44484448, 0x48484848, 0x48884888}, - 0, {0x88888888, 0x88888888, 0x88888888, 0x88888888}, -}; diff --git a/higan/md/ym2612/io.cpp b/higan/md/ym2612/io.cpp deleted file mode 100644 index 1d356bb7..00000000 --- a/higan/md/ym2612/io.cpp +++ /dev/null @@ -1,216 +0,0 @@ -auto YM2612::readStatus() -> uint8 { - //d7 = busy (not emulated, requires cycle timing accuracy) - return timerA.line << 0 | timerB.line << 1; -} - -auto YM2612::writeAddress(uint9 data) -> void { - io.address = data; -} - -auto YM2612::writeData(uint8 data) -> void { - switch(io.address) { - - //LFO - case 0x022: { - lfo.rate = data.bits(0,2); - lfo.enable = data.bit(3); - break; - } - - //timer A period (high) - case 0x024: { - timerA.period.bits(2,9) = data.bits(0,7); - break; - } - - //timer A period (low) - case 0x025: { - timerA.period.bits(0,1) = data.bits(0,1); - break; - } - - //timer B period - case 0x026: { - timerB.period.bits(0,7) = data.bits(0,7); - break; - } - - //timer control - case 0x027: { - //d6,d7 = mode (unimplemented; treated as mode 0 always) - - //reload period on 0->1 transition - if(!timerA.enable && data.bit(0)) timerA.counter = timerA.period; - if(!timerB.enable && data.bit(1)) timerB.counter = timerB.period; - - timerA.enable = data.bit(0); - timerB.enable = data.bit(1); - timerA.irq = data.bit(2); - timerB.irq = data.bit(3); - - if(data.bit(4)) timerA.line = 0; - if(data.bit(5)) timerB.line = 0; - - channels[2].mode = data.bits(6,7); - for(auto& op : channels[2].operators) op.updatePitch(); - - break; - } - - //key on/off - case 0x28: { - //0,1,2,4,5,6 => 0,1,2,3,4,5 - uint index = data.bits(0,2); - if(index == 3 || index == 7) break; - if(index >= 4) index--; - - channels[index][0].trigger(data.bit(4)); - channels[index][1].trigger(data.bit(5)); - channels[index][2].trigger(data.bit(6)); - channels[index][3].trigger(data.bit(7)); - - break; - } - - //DAC sample - case 0x2a: { - dac.sample = data; - break; - } - - //DAC enable - case 0x2b: { - dac.enable = data.bit(7); - break; - } - - } - - if(io.address.bits(0,1) == 3) return; - uint3 voice = io.address.bit(8) * 3 + io.address.bits(0,1); - uint2 index = io.address.bits(2,3) >> 1 | io.address.bits(2,3) << 1; //0,1,2,3 => 0,2,1,3 - - auto& channel = channels[voice]; - auto& op = channel.operators[index]; - - switch(io.address & 0x0f0) { - - //detune, multiple - case 0x030: { - op.multiple = data.bits(0,3); - op.detune = data.bits(4,6); - channel[index].updatePhase(); - break; - } - - //total level - case 0x040: { - op.totalLevel = data.bits(0,6); - channel[index].updateLevel(); - break; - } - - //key scaling, attack rate - case 0x050: { - op.envelope.attackRate = data.bits(0,4); - op.envelope.keyScale = data.bits(6,7); - channel[index].updateEnvelope(); - channel[index].updatePhase(); - break; - } - - //LFO enable, decay rate - case 0x060: { - op.envelope.decayRate = data.bits(0,4); - op.lfoEnable = data.bit(7); - channel[index].updateEnvelope(); - channel[index].updateLevel(); - break; - } - - //sustain rate - case 0x070: { - op.envelope.sustainRate = data.bits(0,4); - channel[index].updateEnvelope(); - break; - } - - //sustain level, release rate - case 0x080: { - op.envelope.releaseRate = data.bits(0,3) << 1 | 1; - op.envelope.sustainLevel = data.bits(4,7); - channel[index].updateEnvelope(); - break; - } - - //SSG-EG - case 0x090: { - op.ssg.hold = data.bit(0); - op.ssg.alternate = data.bit(1); - op.ssg.attack = data.bit(2); - op.ssg.enable = data.bit(3); - break; - } - - } - - switch(io.address & 0x0fc) { - - //pitch (low) - case 0x0a0: { - channel[3].pitch.reload = channel[3].pitch.latch | data; - channel[3].octave.reload = channel[3].octave.latch; - for(auto index : range(4)) channel[index].updatePitch(); - break; - } - - //pitch (high) - case 0x0a4: { - channel[3].pitch.latch = data << 8; - channel[3].octave.latch = data >> 3; - break; - } - - //per-operator pitch (low) - case 0x0a8: { - if(io.address == 0x0a9) index = 0; - if(io.address == 0x0aa) index = 1; - if(io.address == 0x0a8) index = 2; - channels[2][index].pitch.reload = channels[2][index].pitch.latch | data; - channels[2][index].octave.reload = channels[2][index].octave.latch; - channels[2][index].updatePitch(); - break; - } - - //per-operator pitch (high) - case 0x0ac: { - if(io.address == 0x0ad) index = 0; - if(io.address == 0x0ae) index = 1; - if(io.address == 0x0ac) index = 2; - channels[2][index].pitch.latch = data << 8; - channels[2][index].octave.latch = data >> 3; - break; - } - - //algorithm, feedback - case 0x0b0: { - channel.algorithm = data.bits(0,2); - channel.feedback = data.bits(3,5); - break; - } - - //panning, tremolo, vibrato - case 0x0b4: { - channel.vibrato = data.bits(0,2); - channel.tremolo = data.bits(4,5); - channel.rightEnable = data.bit(6); - channel.leftEnable = data.bit(7); - for(auto index : range(4)) { - channel[index].updateLevel(); - channel[index].updatePhase(); - } - break; - } - - } -} diff --git a/higan/md/ym2612/serialization.cpp b/higan/md/ym2612/serialization.cpp deleted file mode 100644 index bf8fff5c..00000000 --- a/higan/md/ym2612/serialization.cpp +++ /dev/null @@ -1,83 +0,0 @@ -auto YM2612::serialize(serializer& s) -> void { - Thread::serialize(s); - - s.integer(io.address); - - s.integer(lfo.enable); - s.integer(lfo.rate); - s.integer(lfo.clock); - s.integer(lfo.divider); - - s.integer(dac.enable); - s.integer(dac.sample); - - s.integer(envelope.clock); - s.integer(envelope.divider); - - s.integer(timerA.enable); - s.integer(timerA.irq); - s.integer(timerA.line); - s.integer(timerA.period); - s.integer(timerA.counter); - - s.integer(timerB.enable); - s.integer(timerB.irq); - s.integer(timerB.line); - s.integer(timerB.period); - s.integer(timerB.counter); - s.integer(timerB.divider); - - for(auto n : range(6)) channels[n].serialize(s); -} - -auto YM2612::Channel::serialize(serializer& s) -> void { - s.integer(leftEnable); - s.integer(rightEnable); - s.integer(algorithm); - s.integer(feedback); - s.integer(vibrato); - s.integer(tremolo); - s.integer(mode); - - for(auto n : range(4)) operators[n].serialize(s); -} - -auto YM2612::Channel::Operator::serialize(serializer& s) -> void { - s.integer(keyOn); - s.integer(lfoEnable); - s.integer(detune); - s.integer(multiple); - s.integer(totalLevel); - s.integer(outputLevel); - s.integer(output); - s.integer(prior); - - s.integer(pitch.value); - s.integer(pitch.reload); - s.integer(pitch.latch); - - s.integer(octave.value); - s.integer(octave.reload); - s.integer(octave.latch); - - s.integer(phase.value); - s.integer(phase.delta); - - s.integer(envelope.state); - s.integer(envelope.rate); - s.integer(envelope.divider); - s.integer(envelope.steps); - s.integer(envelope.value); - s.integer(envelope.keyScale); - s.integer(envelope.attackRate); - s.integer(envelope.decayRate); - s.integer(envelope.sustainRate); - s.integer(envelope.sustainLevel); - s.integer(envelope.releaseRate); - - s.integer(ssg.enable); - s.integer(ssg.attack); - s.integer(ssg.alternate); - s.integer(ssg.hold); - s.integer(ssg.invert); -} diff --git a/higan/md/ym2612/timer.cpp b/higan/md/ym2612/timer.cpp deleted file mode 100644 index a25f0b13..00000000 --- a/higan/md/ym2612/timer.cpp +++ /dev/null @@ -1,16 +0,0 @@ -auto YM2612::TimerA::run() -> void { - if(!enable) return; - if(++counter) return; - - counter = period; - line |= irq; -} - -auto YM2612::TimerB::run() -> void { - if(!enable) return; - if(++divider) return; - if(++counter) return; - - counter = period; - line |= irq; -} diff --git a/higan/md/ym2612/ym2612.cpp b/higan/md/ym2612/ym2612.cpp deleted file mode 100644 index 888cb22c..00000000 --- a/higan/md/ym2612/ym2612.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#include - -namespace MegaDrive { - -YM2612 ym2612; -#include "io.cpp" -#include "timer.cpp" -#include "channel.cpp" -#include "constants.cpp" -#include "serialization.cpp" - -auto YM2612::Enter() -> void { - while(true) scheduler.synchronize(), ym2612.main(); -} - -auto YM2612::main() -> void { - sample(); - - timerA.run(); - timerB.run(); - - if(lfo.enable && ++lfo.divider == lfoDividers[lfo.rate]) { - lfo.divider = 0; - lfo.clock++; - for(auto& channel : channels) { - for(auto& op : channel.operators) { - op.updatePhase(); //due to vibrato - op.updateLevel(); //due to tremolo - } - } - } - - if(++envelope.divider == 3) { - envelope.divider = 0; - envelope.clock++; - } - - for(auto& channel : channels) { - for(auto& op : channel.operators) { - op.runPhase(); - if(envelope.divider) continue; - op.runEnvelope(); - } - } - - step(144); -} - -auto YM2612::sample() -> void { - int left = 0; - int right = 0; - - for(auto& channel : channels) { - auto& op = channel.operators; - - const int modMask = -(1 << 1); - const int sumMask = -(1 << 5); - const int outMask = -(1 << 5); - - auto old = [&](uint n) -> int { return op[n].prior & modMask; }; - auto mod = [&](uint n) -> int { return op[n].output & modMask; }; - auto out = [&](uint n) -> int { return op[n].output & sumMask; }; - - auto wave = [&](uint n, uint modulation) -> int { - int x = (modulation >> 1) + (op[n].phase.value >> 10); - int y = sine[x & 0x3ff] + op[n].outputLevel; - return y < 0x2000 ? pow2[y & 0x1ff] << 2 >> (y >> 9) : 0; - }; - - int feedback = modMask & op[0].output + op[0].prior >> 9 - channel.feedback; - int accumulator = 0; - - for(auto n : range(4)) op[n].prior = op[n].output; - - op[0].output = wave(0, feedback * (channel.feedback > 0)); - - if(channel.algorithm == 0) { - //0 -> 1 -> 2 -> 3 - op[1].output = wave(1, mod(0)); - op[2].output = wave(2, old(1)); - op[3].output = wave(3, mod(2)); - accumulator += out(3); - } - - if(channel.algorithm == 1) { - //(0 + 1) -> 2 -> 3 - op[1].output = wave(1, 0); - op[2].output = wave(2, mod(0) + old(1)); - op[3].output = wave(3, mod(2)); - accumulator += out(3); - } - - if(channel.algorithm == 2) { - //0 + (1 -> 2) -> 3 - op[1].output = wave(1, 0); - op[2].output = wave(2, old(1)); - op[3].output = wave(3, mod(0) + mod(2)); - accumulator += out(3); - } - - if(channel.algorithm == 3) { - //(0 -> 1) + 2 -> 3 - op[1].output = wave(1, mod(0)); - op[2].output = wave(2, 0); - op[3].output = wave(3, mod(1) + mod(2)); - accumulator += out(3); - } - - if(channel.algorithm == 4) { - //(0 -> 1) + (2 -> 3) - op[1].output = wave(1, mod(0)); - op[2].output = wave(2, 0); - op[3].output = wave(3, mod(2)); - accumulator += out(1) + out(3); - } - - if(channel.algorithm == 5) { - //0 -> (1 + 2 + 3) - op[1].output = wave(1, mod(0)); - op[2].output = wave(2, old(0)); - op[3].output = wave(3, mod(0)); - accumulator += out(1) + out(2) + out(3); - } - - if(channel.algorithm == 6) { - //(0 -> 1) + 2 + 3 - op[1].output = wave(1, mod(0)); - op[2].output = wave(2, 0); - op[3].output = wave(3, 0); - accumulator += out(1) + out(2) + out(3); - } - - if(channel.algorithm == 7) { - //0 + 1 + 2 + 3 - op[1].output = wave(1, 0); - op[2].output = wave(2, 0); - op[3].output = wave(3, 0); - accumulator += out(0) + out(1) + out(2) + out(3); - } - - int voiceData = sclamp<14>(accumulator) & outMask; - if(dac.enable && (&channel == &channels[5])) voiceData = (int)dac.sample - 0x80 << 6; - - if(channel.leftEnable ) left += voiceData; - if(channel.rightEnable) right += voiceData; - } - - stream->sample(sclamp<16>(left) / 32768.0, sclamp<16>(right) / 32768.0); -} - -auto YM2612::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); - synchronize(apu); -} - -auto YM2612::power(bool reset) -> void { - create(YM2612::Enter, system.frequency() / 7.0); - stream = Emulator::audio.createStream(2, frequency() / 144.0); - stream->addHighPassFilter( 20.0, Emulator::Filter::Order::First); - stream->addLowPassFilter (2840.0, Emulator::Filter::Order::First); - stream->addDCRemovalFilter(); - - io = {}; - lfo = {}; - dac = {}; - envelope = {}; - timerA = {}; - timerB = {}; - for(auto& channel : channels) channel.power(); - - const uint positive = 0; - const uint negative = 1; - - for(int x = 0; x <= 0xff; x++) { - int y = -256 * log(sin((2 * x + 1) * Math::Pi / 1024)) / log(2) + 0.5; - sine[0x000 + x] = positive + (y << 1); - sine[0x1ff - x] = positive + (y << 1); - sine[0x200 + x] = negative + (y << 1); - sine[0x3ff - x] = negative + (y << 1); - } - - for(int y = 0; y <= 0xff; y++) { - int z = 1024 * pow(2, (0xff - y) / 256.0) + 0.5; - pow2[positive + (y << 1)] = +z; - pow2[negative + (y << 1)] = ~z; //not -z - } -} - -} diff --git a/higan/md/ym2612/ym2612.hpp b/higan/md/ym2612/ym2612.hpp deleted file mode 100644 index 4ab7a170..00000000 --- a/higan/md/ym2612/ym2612.hpp +++ /dev/null @@ -1,173 +0,0 @@ -//Yamaha YM2612 - -struct YM2612 : Thread { - shared_pointer stream; - - static auto Enter() -> void; - auto main() -> void; - auto sample() -> void; - auto step(uint clocks) -> void; - - auto power(bool reset) -> void; - - //io.cpp - auto readStatus() -> uint8; - auto writeAddress(uint9 data) -> void; - auto writeData(uint8 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - struct IO { - uint9 address = 0; - } io; - - struct LFO { - uint1 enable = 0; - uint3 rate = 0; - uint32 clock = 0; - uint32 divider = 0; - } lfo; - - struct DAC { - uint1 enable = 0; - uint8 sample = 0x80; - } dac; - - struct Envelope { - uint32 clock = 0; - uint32 divider = 0; - } envelope; - - struct TimerA { - //timer.cpp - auto run() -> void; - - uint1 enable = 0; - uint1 irq = 0; - uint1 line = 0; - uint10 period = 0; - uint10 counter = 0; - } timerA; - - struct TimerB { - //timer.cpp - auto run() -> void; - - uint1 enable = 0; - uint1 irq = 0; - uint1 line = 0; - uint8 period = 0; - uint8 counter = 0; - uint4 divider = 0; - } timerB; - - enum : uint { Attack, Decay, Sustain, Release }; - - struct Channel { - //channel.cpp - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - uint1 leftEnable = 1; - uint1 rightEnable = 1; - - uint3 algorithm = 0; - uint3 feedback = 0; - uint3 vibrato = 0; - uint2 tremolo = 0; - - uint2 mode = 0; - - struct Operator { - Channel& channel; - Operator(Channel& channel) : channel(channel) {} - - //channel.cpp - auto trigger(bool) -> void; - - auto runEnvelope() -> void; - auto runPhase() -> void; - - auto updateEnvelope() -> void; - auto updatePitch() -> void; - auto updatePhase() -> void; - auto updateLevel() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - uint1 keyOn = 0; - uint1 lfoEnable = 0; - uint3 detune = 0; - uint4 multiple = 0; - uint7 totalLevel = 0; - - uint16 outputLevel = 0x1fff; - int16 output = 0; - int16 prior = 0; - - struct Pitch { - uint11 value = 0; - uint11 reload = 0; - uint11 latch = 0; - } pitch; - - struct Octave { - uint3 value = 0; - uint3 reload = 0; - uint3 latch = 0; - } octave; - - struct Phase { - uint20 value = 0; - uint20 delta = 0; - } phase; - - struct Envelope { - uint state = Release; - int rate = 0; - int divider = 11; - uint32 steps = 0; - uint10 value = 0x3ff; - - uint2 keyScale = 0; - uint5 attackRate = 0; - uint5 decayRate = 0; - uint5 sustainRate = 0; - uint4 sustainLevel = 0; - uint5 releaseRate = 1; - } envelope; - - struct SSG { - uint1 enable = 0; - uint1 attack = 0; - uint1 alternate = 0; - uint1 hold = 0; - uint1 invert = 0; - } ssg; - } operators[4]{*this, *this, *this, *this}; - - auto operator[](uint2 index) -> Operator& { return operators[index]; } - } channels[6]; - - uint16 sine[0x400]; - int16 pow2[0x200]; - - //constants.cpp - struct EnvelopeRate { - uint32_t divider; - uint32_t steps[4]; - }; - - static const uint8_t lfoDividers[8]; - static const uint8_t vibratos[8][16]; - static const uint8_t tremolos[4]; - static const uint8_t detunes[3][8]; - static const EnvelopeRate envelopeRates[16]; -}; - -extern YM2612 ym2612; diff --git a/higan/ms/GNUmakefile b/higan/ms/GNUmakefile deleted file mode 100644 index b2b8f331..00000000 --- a/higan/ms/GNUmakefile +++ /dev/null @@ -1,14 +0,0 @@ -processors += z80 - -objects += ms-interface -objects += ms-cpu ms-vdp ms-psg -objects += ms-system ms-cartridge -objects += ms-controller - -obj/ms-interface.o: ms/interface/interface.cpp -obj/ms-cpu.o: ms/cpu/cpu.cpp -obj/ms-vdp.o: ms/vdp/vdp.cpp -obj/ms-psg.o: ms/psg/psg.cpp -obj/ms-system.o: ms/system/system.cpp -obj/ms-cartridge.o: ms/cartridge/cartridge.cpp -obj/ms-controller.o: ms/controller/controller.cpp diff --git a/higan/ms/cartridge/cartridge.cpp b/higan/ms/cartridge/cartridge.cpp deleted file mode 100644 index f89d2041..00000000 --- a/higan/ms/cartridge/cartridge.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include - -namespace MasterSystem { - -Cartridge cartridge; -#include "mapper.cpp" -#include "serialization.cpp" - -auto Cartridge::load() -> bool { - information = {}; - - if(Model::ColecoVision()) { - if(auto loaded = platform->load(ID::ColecoVision, "ColecoVision", "cv", {"NTSC", "PAL"})) { - information.pathID = loaded.pathID; - information.region = loaded.option; - } else return false; - } - - if(Model::SG1000()) { - if(auto loaded = platform->load(ID::SG1000, "SG-1000", "sg1000", {"NTSC", "PAL"})) { - information.pathID = loaded.pathID; - information.region = loaded.option; - } else return false; - } - - if(Model::SC3000()) { - if(auto loaded = platform->load(ID::SC3000, "SC-3000", "sc3000", {"NTSC", "PAL"})) { - information.pathID = loaded.pathID; - information.region = loaded.option; - } else return false; - } - - if(Model::MasterSystem()) { - if(auto loaded = platform->load(ID::MasterSystem, "Master System", "ms", {"NTSC", "PAL"})) { - information.pathID = loaded.pathID; - information.region = loaded.option; - } else return false; - } - - if(Model::GameGear()) { - if(auto loaded = platform->load(ID::GameGear, "Game Gear", "gg", {"NTSC"})) { - information.pathID = loaded.pathID; - } else return false; - } - - if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else return false; - - auto document = BML::unserialize(information.manifest); - information.title = document["game/label"].text(); - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=ROM,content=Program)"]}) { - rom.allocate(memory.size); - if(auto fp = platform->open(pathID(), memory.name(), File::Read, File::Required)) { - rom.load(fp); - } else return false; - } - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=RAM,content=Save)"]}) { - ram.allocate(memory.size); - if(memory.nonVolatile) { - if(auto fp = platform->open(pathID(), memory.name(), File::Read)) { - ram.load(fp); - } - } - } - - return true; -} - -auto Cartridge::save() -> void { - auto document = BML::unserialize(information.manifest); - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=RAM,content=Save)"]}) { - if(memory.nonVolatile) { - if(auto fp = platform->open(pathID(), memory.name(), File::Write)) { - ram.save(fp); - } - } - } -} - -auto Cartridge::unload() -> void { - rom.reset(); - ram.reset(); -} - -auto Cartridge::power() -> void { - mapper = {}; - mapper.romPage0 = 0; - mapper.romPage1 = 1; - mapper.romPage2 = 2; -} - -} diff --git a/higan/ms/cartridge/cartridge.hpp b/higan/ms/cartridge/cartridge.hpp deleted file mode 100644 index c29ab6a4..00000000 --- a/higan/ms/cartridge/cartridge.hpp +++ /dev/null @@ -1,52 +0,0 @@ -struct Cartridge { - auto pathID() const -> uint { return information.pathID; } - auto region() const -> string { return information.region; } - auto hash() const -> string { return information.sha256; } - auto manifest() const -> string { return information.manifest; } - auto title() const -> string { return information.title; } - - auto load() -> bool; - auto save() -> void; - auto unload() -> void; - - auto power() -> void; - - //mapper.cpp - auto read(uint16 addr) -> maybe; - auto write(uint16 addr, uint8 data) -> bool; - - //serialization.cpp - auto serialize(serializer&) -> void; - -//private: - struct Information { - uint pathID = 0; - string region; - string sha256; - string manifest; - string title; - } information; - - Emulator::Memory::Readable rom; - Emulator::Memory::Writable ram; - - struct Mapper { - //$fffc - uint2 shift; - uint1 ramPage2; - uint1 ramEnablePage2; - uint1 ramEnablePage3; - uint1 romWriteEnable; - - //$fffd - uint8 romPage0; - - //$fffe - uint8 romPage1; - - //$ffff - uint8 romPage2; - } mapper; -}; - -extern Cartridge cartridge; diff --git a/higan/ms/cartridge/mapper.cpp b/higan/ms/cartridge/mapper.cpp deleted file mode 100644 index f14fafe0..00000000 --- a/higan/ms/cartridge/mapper.cpp +++ /dev/null @@ -1,92 +0,0 @@ -auto Cartridge::read(uint16 addr) -> maybe { - uint2 page = addr >> 14; - addr &= 0x3fff; - - switch(page) { - - case 0: { - if(addr <= 0x03ff) return rom.read(addr); - return rom.read(mapper.romPage0 << 14 | addr); - } - - case 1: { - return rom.read(mapper.romPage1 << 14 | addr); - } - - case 2: { - if(ram && mapper.ramEnablePage2) { - return ram.read(mapper.ramPage2 << 14 | addr); - } - - return rom.read(mapper.romPage2 << 14 | addr); - } - - case 3: { - if(ram && mapper.ramEnablePage3) { - return ram.read(addr); - } - - return nothing; - } - - } - - unreachable; -} - -auto Cartridge::write(uint16 addr, uint8 data) -> bool { - if(addr == 0xfffc) { - mapper.shift = data.bits(0,1); - mapper.ramPage2 = data.bit(2); - mapper.ramEnablePage2 = data.bit(3); - mapper.ramEnablePage3 = data.bit(4); - mapper.romWriteEnable = data.bit(7); - } - - if(addr == 0xfffd) { - mapper.romPage0 = data; - } - - if(addr == 0xfffe) { - mapper.romPage1 = data; - } - - if(addr == 0xffff) { - mapper.romPage2 = data; - } - - uint2 page = addr >> 14; - addr &= 0x3fff; - - switch(page) { - - case 0: { - return false; - } - - case 1: { - return false; - } - - case 2: { - if(ram && mapper.ramEnablePage2) { - ram.write(mapper.ramPage2 << 14 | addr, data); - return true; - } - - return false; - } - - case 3: { - if(ram && mapper.ramEnablePage3) { - ram.write(addr, data); - return true; - } - - return false; - } - - } - - unreachable; -} diff --git a/higan/ms/cartridge/serialization.cpp b/higan/ms/cartridge/serialization.cpp deleted file mode 100644 index 13665ef9..00000000 --- a/higan/ms/cartridge/serialization.cpp +++ /dev/null @@ -1,3 +0,0 @@ -auto Cartridge::serialize(serializer& s) -> void { - if(ram) s.array(ram.data(), ram.size()); -} diff --git a/higan/ms/controller/controller.cpp b/higan/ms/controller/controller.cpp deleted file mode 100644 index ec39cfa4..00000000 --- a/higan/ms/controller/controller.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include - -namespace MasterSystem { - -ControllerPort controllerPort1; -ControllerPort controllerPort2; -#include "numberpad/numberpad.cpp" -#include "gamepad/gamepad.cpp" - -Controller::Controller(uint port) : port(port) { - if(!handle()) create(Controller::Enter, 100); -} - -Controller::~Controller() { - scheduler.remove(*this); -} - -auto Controller::Enter() -> void { - while(true) { - scheduler.synchronize(); - if(controllerPort1.device->active()) controllerPort1.device->main(); - if(controllerPort2.device->active()) controllerPort2.device->main(); - } -} - -auto Controller::main() -> void { - step(1); - synchronize(cpu); -} - -// - -auto ControllerPort::connect(uint deviceID) -> void { - delete device; - if(!system.loaded()) return; - if(Model::GameGear()) return; - - switch(deviceID) { default: - case ID::Device::None: device = new Controller(port); break; - case ID::Device::NumberPad: device = new NumberPad(port); break; - case ID::Device::Gamepad: device = new Gamepad(port); break; - } - - cpu.peripherals.reset(); - if(auto device = controllerPort1.device) cpu.peripherals.append(device); - if(auto device = controllerPort2.device) cpu.peripherals.append(device); -} - -auto ControllerPort::power(uint port) -> void { - this->port = port; -} - -auto ControllerPort::unload() -> void { - delete device; - device = nullptr; -} - -auto ControllerPort::serialize(serializer& s) -> void { -} - -} diff --git a/higan/ms/controller/controller.hpp b/higan/ms/controller/controller.hpp deleted file mode 100644 index 59719515..00000000 --- a/higan/ms/controller/controller.hpp +++ /dev/null @@ -1,29 +0,0 @@ -struct Controller : Thread { - Controller(uint port); - virtual ~Controller(); - - static auto Enter() -> void; - auto main() -> void; - - virtual auto readData() -> uint8 { return 0xff; } - virtual auto writeData(uint8 data) -> void {} - - const uint port; -}; - -struct ControllerPort { - auto connect(uint deviceID) -> void; - - auto power(uint port) -> void; - auto unload() -> void; - auto serialize(serializer&) -> void; - - uint port; - Controller* device = nullptr; -}; - -extern ControllerPort controllerPort1; -extern ControllerPort controllerPort2; - -#include "numberpad/numberpad.hpp" -#include "gamepad/gamepad.hpp" diff --git a/higan/ms/controller/gamepad/gamepad.cpp b/higan/ms/controller/gamepad/gamepad.cpp deleted file mode 100644 index cf12881d..00000000 --- a/higan/ms/controller/gamepad/gamepad.cpp +++ /dev/null @@ -1,13 +0,0 @@ -Gamepad::Gamepad(uint port) : Controller(port) { -} - -auto Gamepad::readData() -> uint8 { - uint8 data = 0xff; - data.bit(0) = !platform->inputPoll(port, ID::Device::Gamepad, Up); - data.bit(1) = !platform->inputPoll(port, ID::Device::Gamepad, Down); - data.bit(2) = !platform->inputPoll(port, ID::Device::Gamepad, Left); - data.bit(3) = !platform->inputPoll(port, ID::Device::Gamepad, Right); - data.bit(4) = !platform->inputPoll(port, ID::Device::Gamepad, One); - data.bit(5) = !platform->inputPoll(port, ID::Device::Gamepad, Two); - return data; -} diff --git a/higan/ms/controller/gamepad/gamepad.hpp b/higan/ms/controller/gamepad/gamepad.hpp deleted file mode 100644 index 9be9c55c..00000000 --- a/higan/ms/controller/gamepad/gamepad.hpp +++ /dev/null @@ -1,9 +0,0 @@ -struct Gamepad : Controller { - enum : uint { - Up, Down, Left, Right, One, Two, - }; - - Gamepad(uint port); - - auto readData() -> uint8 override; -}; diff --git a/higan/ms/controller/numberpad/numberpad.cpp b/higan/ms/controller/numberpad/numberpad.cpp deleted file mode 100644 index 6512c2a6..00000000 --- a/higan/ms/controller/numberpad/numberpad.cpp +++ /dev/null @@ -1,33 +0,0 @@ -NumberPad::NumberPad(uint port) : Controller(port) { -} - -auto NumberPad::readData() -> uint8 { - const uint device = ID::Device::NumberPad; - uint8 data = 0xff; - if(select == 0) { - if(platform->inputPoll(port, device, One )) data.bits(0,3) = 0b1101; - else if(platform->inputPoll(port, device, Two )) data.bits(0,3) = 0b0111; - else if(platform->inputPoll(port, device, Three)) data.bits(0,3) = 0b1100; - else if(platform->inputPoll(port, device, Four )) data.bits(0,3) = 0b0010; - else if(platform->inputPoll(port, device, Five )) data.bits(0,3) = 0b0011; - else if(platform->inputPoll(port, device, Six )) data.bits(0,3) = 0b1110; - else if(platform->inputPoll(port, device, Seven)) data.bits(0,3) = 0b0101; - else if(platform->inputPoll(port, device, Eight)) data.bits(0,3) = 0b0001; - else if(platform->inputPoll(port, device, Nine )) data.bits(0,3) = 0b1011; - else if(platform->inputPoll(port, device, Star )) data.bits(0,3) = 0b1001; - else if(platform->inputPoll(port, device, Zero )) data.bits(0,3) = 0b1010; - else if(platform->inputPoll(port, device, Pound)) data.bits(0,3) = 0b0110; - data.bit(6) = !platform->inputPoll(port, device, R); - } else { - data.bit(0) = !platform->inputPoll(port, device, Up); - data.bit(1) = !platform->inputPoll(port, device, Right); - data.bit(2) = !platform->inputPoll(port, device, Down); - data.bit(3) = !platform->inputPoll(port, device, Left); - data.bit(6) = !platform->inputPoll(port, device, L); - } - return data; -} - -auto NumberPad::writeData(uint8 data) -> void { - select = data.bit(0); -} diff --git a/higan/ms/controller/numberpad/numberpad.hpp b/higan/ms/controller/numberpad/numberpad.hpp deleted file mode 100644 index 3394bea2..00000000 --- a/higan/ms/controller/numberpad/numberpad.hpp +++ /dev/null @@ -1,17 +0,0 @@ -struct NumberPad : Controller { - enum : uint { - Up, Down, Left, Right, - L, R, - One, Two, Three, - Four, Five, Six, - Seven, Eight, Nine, - Star, Zero, Pound, - }; - - NumberPad(uint port); - - auto readData() -> uint8; - auto writeData(uint8 data) -> void; - - uint1 select; -}; diff --git a/higan/ms/cpu/coleco.cpp b/higan/ms/cpu/coleco.cpp deleted file mode 100644 index 1e5d1b13..00000000 --- a/higan/ms/cpu/coleco.cpp +++ /dev/null @@ -1,33 +0,0 @@ -auto CPU::readColeco(uint16 address) -> uint8 { - uint8 data = 0xff; - if(address >= 0x0000 && address <= 0x1fff && coleco.replaceBIOS) return expansion.read(address); - if(address >= 0x2000 && address <= 0x7fff && coleco.replaceRAM ) return expansion.read(address); - if(address >= 0x0000 && address <= 0x1fff) return system.bios[address & 0x1fff]; - if(address >= 0x6000 && address <= 0x7fff) return ram.read(address - 0x6000); - if(address >= 0x8000 && address <= 0xffff) return cartridge.rom.read(address - 0x8000); - return data; -} - -auto CPU::writeColeco(uint16 address, uint8 data) -> void { - if(address >= 0x0000 && address <= 0x1fff && coleco.replaceBIOS) return expansion.write(address, data); - if(address >= 0x2000 && address <= 0x7fff && coleco.replaceRAM) return expansion.write(address, data); - if(address >= 0x6000 && address <= 0x7fff) return ram.write(address - 0x6000, data); - if(address >= 0x8000 && address <= 0xffff) return; -} - -auto CPU::inColeco(uint8 address) -> uint8 { - uint8 data = 0xff; - if(address >= 0xa0 && address <= 0xbf) return !address.bit(0) ? vdp.data() : vdp.status(); - if(address >= 0xe0 && address <= 0xff && address.bit(1) == 0) return controllerPort1.device->readData(); - if(address >= 0xe0 && address <= 0xff && address.bit(1) == 1) return controllerPort2.device->readData(); - return data; -} - -auto CPU::outColeco(uint8 address, uint8 data) -> void { - if(address == 0x53) coleco.replaceRAM = data.bit(0); - if(address == 0x7f) coleco.replaceBIOS = data.bit(1); - if(address >= 0x80 && address <= 0x9f) controllerPort1.device->writeData(0), controllerPort2.device->writeData(0); - if(address >= 0xa0 && address <= 0xbf) return !address.bit(0) ? vdp.data(data) : vdp.control(data); - if(address >= 0xc0 && address <= 0xdf) controllerPort1.device->writeData(1), controllerPort2.device->writeData(1); - if(address >= 0xe0 && address <= 0xff) return psg.write(data); -} diff --git a/higan/ms/cpu/cpu.cpp b/higan/ms/cpu/cpu.cpp deleted file mode 100644 index cbc74960..00000000 --- a/higan/ms/cpu/cpu.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include - -namespace MasterSystem { - -CPU cpu; -#include "coleco.cpp" -#include "sega.cpp" -#include "serialization.cpp" - -auto CPU::Enter() -> void { - while(true) scheduler.synchronize(), cpu.main(); -} - -auto CPU::main() -> void { - if(state.nmiLine) { - state.nmiLine = 0; //edge-sensitive - irq(0, 0x0066, 0xff); - } - - if(state.intLine) { - //level-sensitive - irq(1, 0x0038, 0xff); - } - - instruction(); -} - -auto CPU::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(vdp); - synchronize(psg); - for(auto peripheral : peripherals) synchronize(*peripheral); -} - -auto CPU::synchronizing() const -> bool { - return scheduler.synchronizing(); -} - -//called once per frame -auto CPU::pollPause() -> void { - if(Model::SG1000() || Model::SC3000()) { - static bool pause = 0; - bool state = platform->inputPoll(ID::Port::Hardware, ID::Device::SG1000Controls, 0); - if(!pause && state) setNMI(1); - pause = state; - } - - if(Model::MasterSystem()) { - static bool pause = 0; - bool state = platform->inputPoll(ID::Port::Hardware, ID::Device::MasterSystemControls, 1); - if(!pause && state) setNMI(1); - pause = state; - } -} - -auto CPU::setNMI(bool value) -> void { - state.nmiLine = value; -} - -auto CPU::setINT(bool value) -> void { - state.intLine = value; -} - -auto CPU::read(uint16 address) -> uint8 { - return Model::ColecoVision() ? readColeco(address) : readSega(address); -} - -auto CPU::write(uint16 address, uint8 data) -> void { - return Model::ColecoVision() ? writeColeco(address, data) : writeSega(address, data); -} - -auto CPU::in(uint8 address) -> uint8 { - return Model::ColecoVision() ? inColeco(address) : inSega(address); -} - -auto CPU::out(uint8 address, uint8 data) -> void { - return Model::ColecoVision() ? outColeco(address, data) : outSega(address, data); -} - -auto CPU::power() -> void { - Z80::bus = this; - Z80::power(); - create(CPU::Enter, system.colorburst()); - - if(Model::ColecoVision()) ram.allocate(0x0400), expansion.allocate(0x1000); - if(Model::SG1000()) ram.allocate(0x0400); - if(Model::SC3000()) ram.allocate(0x0800); - if(Model::MasterSystem()) ram.allocate(0x2000); - if(Model::GameGear()) ram.allocate(0x2000); - - r.pc = 0x0000; //reset vector address - state = {}; - coleco = {}; -} - -} diff --git a/higan/ms/cpu/cpu.hpp b/higan/ms/cpu/cpu.hpp deleted file mode 100644 index 38e10005..00000000 --- a/higan/ms/cpu/cpu.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//Zilog Z80 - -struct CPU : Processor::Z80, Processor::Z80::Bus, Thread { - //cpu.cpp - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void override; - auto synchronizing() const -> bool override; - - auto pollPause() -> void; - auto setNMI(bool value) -> void; - auto setINT(bool value) -> void; - - auto read(uint16 address) -> uint8 override; - auto write(uint16 address, uint8 data) -> void override; - - auto in(uint8 address) -> uint8 override; - auto out(uint8 address, uint8 data) -> void override; - - auto power() -> void; - - //coleco.cpp - auto readColeco(uint16 address) -> uint8; - auto writeColeco(uint16 address, uint8 data) -> void; - - auto inColeco(uint8 address) -> uint8; - auto outColeco(uint8 address, uint8 data) -> void; - - //sega.cpp - auto readSega(uint16 address) -> uint8; - auto writeSega(uint16 address, uint8 data) -> void; - - auto inSega(uint8 address) -> uint8; - auto outSega(uint8 address, uint8 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - vector peripherals; - -private: - Emulator::Memory::Writable ram; - Emulator::Memory::Writable expansion; - - struct State { - bool nmiLine = 0; - bool intLine = 0; - } state; - - struct Coleco { - uint1 replaceBIOS; - uint1 replaceRAM; - } coleco; -}; - -extern CPU cpu; diff --git a/higan/ms/cpu/sega.cpp b/higan/ms/cpu/sega.cpp deleted file mode 100644 index cac07d30..00000000 --- a/higan/ms/cpu/sega.cpp +++ /dev/null @@ -1,105 +0,0 @@ -auto CPU::readSega(uint16 address) -> uint8 { - uint8 data = 0xff; - if(auto result = cartridge.read(address)) { - data = result(); - } else if(address >= 0xc000) { - data = ram.read(address); - } - if(auto result = cheat.find(address, data)) data = result(); - return data; -} - -auto CPU::writeSega(uint16 address, uint8 data) -> void { - if(cartridge.write(address, data)) { - } else if(address >= 0xc000) { - ram.write(address, data); - } -} - -auto CPU::inSega(uint8 addr) -> uint8 { - switch(addr >> 6) { - - case 0: { - if(Model::GameGear()) { - bool start = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 6); - return start << 7 | 0x7f; - } - - return 0xff; //SMS1 = MDR, SMS2 = 0xff - } - - case 1: { - return !addr.bit(0) ? vdp.vcounter() : vdp.hcounter(); - } - - case 2: { - return !addr.bit(0) ? vdp.data() : vdp.status(); - } - - case 3: { - if(Model::SG1000() || Model::SC3000()) { - auto port1 = controllerPort1.device->readData(); - auto port2 = controllerPort2.device->readData(); - if(addr.bit(0) == 0) { - return port1.bits(0,5) << 0 | port2.bits(0,1) << 6; - } else { - return port2.bits(2,5) << 0 | 1 << 4 | 1 << 5 | port1.bit(6) << 6 | port2.bit(6) << 7; - } - } - - if(Model::MasterSystem()) { - bool reset = !platform->inputPoll(ID::Port::Hardware, ID::Device::MasterSystemControls, 0); - auto port1 = controllerPort1.device->readData(); - auto port2 = controllerPort2.device->readData(); - if(addr.bit(0) == 0) { - return port1.bits(0,5) << 0 | port2.bits(0,1) << 6; - } else { - return port2.bits(2,5) << 0 | reset << 4 | 1 << 5 | port1.bit(6) << 6 | port2.bit(6) << 7; - } - } - - if(Model::GameGear()) { - bool up = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 0); - bool down = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 1); - bool left = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 2); - bool right = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 3); - bool one = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 4); - bool two = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 5); - if(!up && !down) up = 1, down = 1; - if(!left && !right) left = 1, right = 1; - if(addr.bit(0) == 0) { - return up << 0 | down << 1 | left << 2 | right << 3 | one << 4 | two << 5 | 1 << 6 | 1 << 7; - } else { - return 0xff; - } - } - - return 0xff; - } - - } - - return 0xff; -} - -auto CPU::outSega(uint8 addr, uint8 data) -> void { - if(addr == 0x06) { - if(Model::GameGear()) return psg.balance(data); - } - - switch(addr >> 6) { - - case 1: { - return psg.write(data); - } - - case 2: { - return !addr.bit(0) ? vdp.data(data) : vdp.control(data); - } - - case 3: { - return; //unmapped - } - - } -} diff --git a/higan/ms/cpu/serialization.cpp b/higan/ms/cpu/serialization.cpp deleted file mode 100644 index db33dc18..00000000 --- a/higan/ms/cpu/serialization.cpp +++ /dev/null @@ -1,10 +0,0 @@ -auto CPU::serialize(serializer& s) -> void { - Z80::serialize(s); - Z80::Bus::serialize(s); - Thread::serialize(s); - - s.array(ram.data(), ram.size()); - - s.integer(state.nmiLine); - s.integer(state.intLine); -} diff --git a/higan/ms/interface/colecovision.cpp b/higan/ms/interface/colecovision.cpp deleted file mode 100644 index 808ee873..00000000 --- a/higan/ms/interface/colecovision.cpp +++ /dev/null @@ -1,102 +0,0 @@ -auto ColecoVisionInterface::information() -> Information { - Information information; - information.manufacturer = "Coleco Industries"; - information.name = "ColecoVision"; - information.extension = "cv"; - return information; -} - -auto ColecoVisionInterface::display() -> Display { - Display display; - display.type = Display::Type::CRT; - display.colors = 1 << 4; - display.width = 256; - display.height = 192; - display.internalWidth = 256; - display.internalHeight = 192; - display.aspectCorrection = 1.0; - return display; -} - -auto ColecoVisionInterface::color(uint32 color) -> uint64 { - switch(color.bits(0,3)) { - case 0: return 0x0000'0000'0000ull; //transparent - case 1: return 0x0000'0000'0000ull; //black - case 2: return 0x2121'c8c8'4242ull; //medium green - case 3: return 0x5e5e'dcdc'7878ull; //light green - case 4: return 0x5454'5555'ededull; //dark blue - case 5: return 0x7d7d'7676'fcfcull; //light blue - case 6: return 0xd4d4'5252'4d4dull; //dark red - case 7: return 0x4242'ebeb'f5f5ull; //cyan - case 8: return 0xfcfc'5555'5454ull; //medium red - case 9: return 0xffff'7979'7878ull; //light red - case 10: return 0xd4d4'c1c1'5454ull; //dark yellow - case 11: return 0xe6e6'cece'8080ull; //light yellow - case 12: return 0x2121'b0b0'3b3bull; //dark green - case 13: return 0xc9c9'5b5b'babaull; //magenta - case 14: return 0xcccc'cccc'ccccull; //gray - case 15: return 0xffff'ffff'ffffull; //white - } - unreachable; -} - -auto ColecoVisionInterface::ports() -> vector { return { - {ID::Port::Controller1, "Controller Port 1"}, - {ID::Port::Controller2, "Controller Port 2"}}; -} - -auto ColecoVisionInterface::devices(uint port) -> vector { - if(port == ID::Port::Controller1) return { - {ID::Device::None, "None"}, - {ID::Device::NumberPad, "Gamepad"} - }; - - if(port == ID::Port::Controller2) return { - {ID::Device::None, "None"}, - {ID::Device::NumberPad, "Gamepad"} - }; - - return {}; -} - -auto ColecoVisionInterface::inputs(uint device) -> vector { - using Type = Input::Type; - - if(device == ID::Device::NumberPad) return { - {Type::Hat, "Up"}, - {Type::Hat, "Down"}, - {Type::Hat, "Left"}, - {Type::Hat, "Right"}, - {Type::Button, "L"}, - {Type::Button, "R"}, - {Type::Button, "1"}, - {Type::Button, "2"}, - {Type::Button, "3"}, - {Type::Button, "4"}, - {Type::Button, "5"}, - {Type::Button, "6"}, - {Type::Button, "7"}, - {Type::Button, "8"}, - {Type::Button, "9"}, - {Type::Button, "Star"}, - {Type::Button, "0"}, - {Type::Button, "Pound"} - }; - - return {}; -} - -auto ColecoVisionInterface::load() -> bool { - return system.load(this, System::Model::ColecoVision); -} - -auto ColecoVisionInterface::connected(uint port) -> uint { - if(port == ID::Port::Controller1) return settings.controllerPort1; - if(port == ID::Port::Controller2) return settings.controllerPort2; - return 0; -} - -auto ColecoVisionInterface::connect(uint port, uint device) -> void { - if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); - if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); -} diff --git a/higan/ms/interface/game-gear.cpp b/higan/ms/interface/game-gear.cpp deleted file mode 100644 index a3329503..00000000 --- a/higan/ms/interface/game-gear.cpp +++ /dev/null @@ -1,63 +0,0 @@ -auto GameGearInterface::information() -> Information { - Information information; - information.manufacturer = "Sega"; - information.name = "Game Gear"; - information.extension = "gg"; - return information; -} - -auto GameGearInterface::display() -> Display { - Display display; - display.type = Display::Type::LCD; - display.colors = 1 << 12; - display.width = 160; - display.height = 144; - display.internalWidth = 160; - display.internalHeight = 144; - display.aspectCorrection = 1.0; - return display; -} - -auto GameGearInterface::color(uint32 color) -> uint64 { - uint4 B = color >> 8; - uint4 G = color >> 4; - uint4 R = color >> 0; - - uint64 r = image::normalize(R, 4, 16); - uint64 g = image::normalize(G, 4, 16); - uint64 b = image::normalize(B, 4, 16); - - return r << 32 | g << 16 | b << 0; -} - -auto GameGearInterface::ports() -> vector { return { - {ID::Port::Hardware, "Hardware"}}; -} - -auto GameGearInterface::devices(uint port) -> vector { - if(port == ID::Port::Hardware) return { - {ID::Device::GameGearControls, "Controls"} - }; - - return {}; -} - -auto GameGearInterface::inputs(uint device) -> vector { - using Type = Input::Type; - - if(device == ID::Device::GameGearControls) return { - {Type::Hat, "Up" }, - {Type::Hat, "Down" }, - {Type::Hat, "Left" }, - {Type::Hat, "Right"}, - {Type::Button, "1" }, - {Type::Button, "2" }, - {Type::Control, "Start"} - }; - - return {}; -} - -auto GameGearInterface::load() -> bool { - return system.load(this, System::Model::GameGear); -} diff --git a/higan/ms/interface/interface.cpp b/higan/ms/interface/interface.cpp deleted file mode 100644 index 835f3614..00000000 --- a/higan/ms/interface/interface.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include - -namespace MasterSystem { - -Settings settings; -#include "colecovision.cpp" -#include "sg-1000.cpp" -#include "sc-3000.cpp" -#include "master-system.cpp" -#include "game-gear.cpp" - -auto Interface::loaded() -> bool { - return system.loaded(); -} - -auto Interface::hashes() -> vector { - return {cartridge.hash()}; -} - -auto Interface::manifests() -> vector { - return {cartridge.manifest()}; -} - -auto Interface::titles() -> vector { - return {cartridge.title()}; -} - -auto Interface::save() -> void { - system.save(); -} - -auto Interface::unload() -> void { - save(); - system.unload(); -} - -auto Interface::power() -> void { - system.power(); -} - -auto Interface::run() -> void { - system.run(); -} - -auto Interface::serialize() -> serializer { - system.runToSave(); - return system.serialize(); -} - -auto Interface::unserialize(serializer& s) -> bool { - return system.unserialize(s); -} - -auto Interface::cheats(const vector& list) -> void { - cheat.assign(list); -} - -auto Interface::cap(const string& name) -> bool { - return false; -} - -auto Interface::get(const string& name) -> any { - return {}; -} - -auto Interface::set(const string& name, const any& value) -> bool { - return false; -} - -} diff --git a/higan/ms/interface/interface.hpp b/higan/ms/interface/interface.hpp deleted file mode 100644 index 9044d752..00000000 --- a/higan/ms/interface/interface.hpp +++ /dev/null @@ -1,139 +0,0 @@ -#if defined(CORE_MS) - -namespace MasterSystem { - -struct ID { - enum : uint { - System, - ColecoVision, - SG1000, - SC3000, - MasterSystem, - GameGear, - }; - - struct Port { enum : uint { - Hardware, - Controller1, - Controller2, - };}; - - struct Device { enum : uint { - None, - SG1000Controls, - SC3000Controls, - MasterSystemControls, - GameGearControls, - NumberPad, - Gamepad, - };}; -}; - -struct Interface : Emulator::Interface { - auto loaded() -> bool override; - auto hashes() -> vector override; - auto manifests() -> vector override; - auto titles() -> vector override; - auto save() -> void override; - auto unload() -> void override; - - auto power() -> void override; - auto run() -> void override; - - auto serialize() -> serializer override; - auto unserialize(serializer&) -> bool override; - - auto cheats(const vector& list) -> void override; - - auto cap(const string& name) -> bool override; - auto get(const string& name) -> any override; - auto set(const string& name, const any& value) -> bool override; -}; - -struct ColecoVisionInterface : Interface { - auto information() -> Information override; - - auto display() -> Display override; - auto color(uint32 color) -> uint64 override; - - auto ports() -> vector override; - auto devices(uint port) -> vector override; - auto inputs(uint device) -> vector override; - - auto load() -> bool override; - - auto connected(uint port) -> uint override; - auto connect(uint port, uint device) -> void override; -}; - -struct SG1000Interface : Interface { - auto information() -> Information override; - - auto display() -> Display override; - auto color(uint32 color) -> uint64 override; - - auto ports() -> vector override; - auto devices(uint port) -> vector override; - auto inputs(uint device) -> vector override; - - auto load() -> bool override; - - auto connected(uint port) -> uint override; - auto connect(uint port, uint device) -> void override; -}; - -struct SC3000Interface : Interface { - auto information() -> Information override; - - auto display() -> Display override; - auto color(uint32 color) -> uint64 override; - - auto ports() -> vector override; - auto devices(uint port) -> vector override; - auto inputs(uint device) -> vector override; - - auto load() -> bool override; - - auto connected(uint port) -> uint override; - auto connect(uint port, uint device) -> void override; -}; - -struct MasterSystemInterface : Interface { - auto information() -> Information override; - - auto display() -> Display override; - auto color(uint32 color) -> uint64 override; - - auto ports() -> vector override; - auto devices(uint port) -> vector override; - auto inputs(uint device) -> vector override; - - auto load() -> bool override; - - auto connected(uint port) -> uint override; - auto connect(uint port, uint device) -> void override; -}; - -struct GameGearInterface : Interface { - auto information() -> Information override; - - auto display() -> Display override; - auto color(uint32 color) -> uint64 override; - - auto ports() -> vector override; - auto devices(uint port) -> vector override; - auto inputs(uint device) -> vector override; - - auto load() -> bool override; -}; - -struct Settings { - uint controllerPort1 = ID::Device::Gamepad; - uint controllerPort2 = ID::Device::Gamepad; -}; - -extern Settings settings; - -} - -#endif diff --git a/higan/ms/interface/master-system.cpp b/higan/ms/interface/master-system.cpp deleted file mode 100644 index 0e5ed284..00000000 --- a/higan/ms/interface/master-system.cpp +++ /dev/null @@ -1,94 +0,0 @@ -auto MasterSystemInterface::information() -> Information { - Information information; - information.manufacturer = "Sega"; - information.name = "Master System"; - information.extension = "ms"; - return information; -} - -auto MasterSystemInterface::display() -> Display { - Display display; - display.type = Display::Type::CRT; - display.colors = 1 << 6; - display.width = 256; - display.height = 240; - display.internalWidth = 256; - display.internalHeight = 240; - display.aspectCorrection = 8.0 / 7.0; - return display; -} - -auto MasterSystemInterface::color(uint32 color) -> uint64 { - uint2 B = color >> 4; - uint2 G = color >> 2; - uint2 R = color >> 0; - - uint64 r = image::normalize(R, 2, 16); - uint64 g = image::normalize(G, 2, 16); - uint64 b = image::normalize(B, 2, 16); - - return r << 32 | g << 16 | b << 0; -} - -auto MasterSystemInterface::ports() -> vector { return { - {ID::Port::Controller1, "Controller Port 1"}, - {ID::Port::Controller2, "Controller Port 2"}, - {ID::Port::Hardware, "Hardware" }}; -} - -auto MasterSystemInterface::devices(uint port) -> vector { - if(port == ID::Port::Controller1) return { - {ID::Device::None, "None" }, - {ID::Device::Gamepad, "Gamepad"} - }; - - if(port == ID::Port::Controller2) return { - {ID::Device::None, "None" }, - {ID::Device::Gamepad, "Gamepad"} - }; - - if(port == ID::Port::Hardware) return { - {ID::Device::MasterSystemControls, "Controls"} - }; - - return {}; -} - -auto MasterSystemInterface::inputs(uint device) -> vector { - using Type = Input::Type; - - if(device == ID::Device::None) return { - }; - - if(device == ID::Device::Gamepad) return { - {Type::Hat, "Up" }, - {Type::Hat, "Down" }, - {Type::Hat, "Left" }, - {Type::Hat, "Right"}, - {Type::Button, "1" }, - {Type::Button, "2" } - }; - - if(device == ID::Device::MasterSystemControls) return { - {Type::Control, "Reset"}, - {Type::Control, "Power"} - }; - - return {}; -} - -auto MasterSystemInterface::load() -> bool { - return system.load(this, System::Model::MasterSystem); -} - -auto MasterSystemInterface::connected(uint port) -> uint { - if(port == ID::Port::Controller1) return settings.controllerPort1; - if(port == ID::Port::Controller2) return settings.controllerPort2; - if(port == ID::Port::Hardware) return ID::Device::MasterSystemControls; - return 0; -} - -auto MasterSystemInterface::connect(uint port, uint device) -> void { - if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); - if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); -} diff --git a/higan/ms/interface/sc-3000.cpp b/higan/ms/interface/sc-3000.cpp deleted file mode 100644 index f2fbd5ea..00000000 --- a/higan/ms/interface/sc-3000.cpp +++ /dev/null @@ -1,103 +0,0 @@ -auto SC3000Interface::information() -> Information { - Information information; - information.manufacturer = "Sega"; - information.name = "SC-3000"; - information.extension = "sc3000"; - return information; -} - -auto SC3000Interface::display() -> Display { - Display display; - display.type = Display::Type::CRT; - display.colors = 1 << 4; - display.width = 256; - display.height = 192; - display.internalWidth = 256; - display.internalHeight = 192; - display.aspectCorrection = 1.0; - return display; -} - -auto SC3000Interface::color(uint32 color) -> uint64 { - switch(color.bits(0,3)) { - case 0: return 0x0000'0000'0000ull; //transparent - case 1: return 0x0000'0000'0000ull; //black - case 2: return 0x2121'c8c8'4242ull; //medium green - case 3: return 0x5e5e'dcdc'7878ull; //light green - case 4: return 0x5454'5555'ededull; //dark blue - case 5: return 0x7d7d'7676'fcfcull; //light blue - case 6: return 0xd4d4'5252'4d4dull; //dark red - case 7: return 0x4242'ebeb'f5f5ull; //cyan - case 8: return 0xfcfc'5555'5454ull; //medium red - case 9: return 0xffff'7979'7878ull; //light red - case 10: return 0xd4d4'c1c1'5454ull; //dark yellow - case 11: return 0xe6e6'cece'8080ull; //light yellow - case 12: return 0x2121'b0b0'3b3bull; //dark green - case 13: return 0xc9c9'5b5b'babaull; //magenta - case 14: return 0xcccc'cccc'ccccull; //gray - case 15: return 0xffff'ffff'ffffull; //white - } - unreachable; -} - -auto SC3000Interface::ports() -> vector { return { - {ID::Port::Controller1, "Controller Port 1"}, - {ID::Port::Controller2, "Controller Port 2"}, - {ID::Port::Hardware, "Hardware" }}; -} - -auto SC3000Interface::devices(uint port) -> vector { - if(port == ID::Port::Controller1) return { - {ID::Device::None, "None" }, - {ID::Device::Gamepad, "Gamepad"} - }; - - if(port == ID::Port::Controller2) return { - {ID::Device::None, "None" }, - {ID::Device::Gamepad, "Gamepad"} - }; - - if(port == ID::Port::Hardware) return { - {ID::Device::SC3000Controls, "Controls"} - }; - - return {}; -} - -auto SC3000Interface::inputs(uint device) -> vector { - using Type = Input::Type; - - if(device == ID::Device::None) return { - }; - - if(device == ID::Device::Gamepad) return { - {Type::Hat, "Up" }, - {Type::Hat, "Down" }, - {Type::Hat, "Left" }, - {Type::Hat, "Right"}, - {Type::Button, "1" }, - {Type::Button, "2" } - }; - - if(device == ID::Device::SC3000Controls) return { - {Type::Control, "Pause"} - }; - - return {}; -} - -auto SC3000Interface::load() -> bool { - return system.load(this, System::Model::SC3000); -} - -auto SC3000Interface::connected(uint port) -> uint { - if(port == ID::Port::Controller1) return settings.controllerPort1; - if(port == ID::Port::Controller2) return settings.controllerPort2; - if(port == ID::Port::Hardware) return ID::Device::SC3000Controls; - return 0; -} - -auto SC3000Interface::connect(uint port, uint device) -> void { - if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); - if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); -} diff --git a/higan/ms/interface/sg-1000.cpp b/higan/ms/interface/sg-1000.cpp deleted file mode 100644 index 1f94a4c8..00000000 --- a/higan/ms/interface/sg-1000.cpp +++ /dev/null @@ -1,103 +0,0 @@ -auto SG1000Interface::information() -> Information { - Information information; - information.manufacturer = "Sega"; - information.name = "SG-1000"; - information.extension = "sg1000"; - return information; -} - -auto SG1000Interface::display() -> Display { - Display display; - display.type = Display::Type::CRT; - display.colors = 1 << 4; - display.width = 256; - display.height = 192; - display.internalWidth = 256; - display.internalHeight = 192; - display.aspectCorrection = 1.0; - return display; -} - -auto SG1000Interface::color(uint32 color) -> uint64 { - switch(color.bits(0,3)) { - case 0: return 0x0000'0000'0000ull; //transparent - case 1: return 0x0000'0000'0000ull; //black - case 2: return 0x2121'c8c8'4242ull; //medium green - case 3: return 0x5e5e'dcdc'7878ull; //light green - case 4: return 0x5454'5555'ededull; //dark blue - case 5: return 0x7d7d'7676'fcfcull; //light blue - case 6: return 0xd4d4'5252'4d4dull; //dark red - case 7: return 0x4242'ebeb'f5f5ull; //cyan - case 8: return 0xfcfc'5555'5454ull; //medium red - case 9: return 0xffff'7979'7878ull; //light red - case 10: return 0xd4d4'c1c1'5454ull; //dark yellow - case 11: return 0xe6e6'cece'8080ull; //light yellow - case 12: return 0x2121'b0b0'3b3bull; //dark green - case 13: return 0xc9c9'5b5b'babaull; //magenta - case 14: return 0xcccc'cccc'ccccull; //gray - case 15: return 0xffff'ffff'ffffull; //white - } - unreachable; -} - -auto SG1000Interface::ports() -> vector { return { - {ID::Port::Controller1, "Controller Port 1"}, - {ID::Port::Controller2, "Controller Port 2"}, - {ID::Port::Hardware, "Hardware" }}; -} - -auto SG1000Interface::devices(uint port) -> vector { - if(port == ID::Port::Controller1) return { - {ID::Device::None, "None" }, - {ID::Device::Gamepad, "Gamepad"} - }; - - if(port == ID::Port::Controller2) return { - {ID::Device::None, "None" }, - {ID::Device::Gamepad, "Gamepad"} - }; - - if(port == ID::Port::Hardware) return { - {ID::Device::SG1000Controls, "Controls"} - }; - - return {}; -} - -auto SG1000Interface::inputs(uint device) -> vector { - using Type = Input::Type; - - if(device == ID::Device::None) return { - }; - - if(device == ID::Device::Gamepad) return { - {Type::Hat, "Up" }, - {Type::Hat, "Down" }, - {Type::Hat, "Left" }, - {Type::Hat, "Right"}, - {Type::Button, "1" }, - {Type::Button, "2" } - }; - - if(device == ID::Device::SG1000Controls) return { - {Type::Control, "Pause"} - }; - - return {}; -} - -auto SG1000Interface::load() -> bool { - return system.load(this, System::Model::SG1000); -} - -auto SG1000Interface::connected(uint port) -> uint { - if(port == ID::Port::Controller1) return settings.controllerPort1; - if(port == ID::Port::Controller2) return settings.controllerPort2; - if(port == ID::Port::Hardware) return ID::Device::SG1000Controls; - return 0; -} - -auto SG1000Interface::connect(uint port, uint device) -> void { - if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); - if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); -} diff --git a/higan/ms/ms.hpp b/higan/ms/ms.hpp deleted file mode 100644 index ba5695d6..00000000 --- a/higan/ms/ms.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -//license: GPLv3 -//started: 2016-08-17 - -#include -#include -#include -#include - -#include - -namespace MasterSystem { - #define platform Emulator::platform - namespace File = Emulator::File; - using Scheduler = Emulator::Scheduler; - using Cheat = Emulator::Cheat; - extern Scheduler scheduler; - extern Cheat cheat; - - struct Thread : Emulator::Thread { - auto create(auto (*entrypoint)() -> void, double frequency) -> void { - Emulator::Thread::create(entrypoint, frequency); - scheduler.append(*this); - } - - inline auto synchronize(Thread& thread) -> void { - if(clock() >= thread.clock()) scheduler.resume(thread); - } - }; - - struct Model { - inline static auto ColecoVision() -> bool; - inline static auto SG1000() -> bool; - inline static auto SC3000() -> bool; - inline static auto MasterSystem() -> bool; - inline static auto GameGear() -> bool; - }; - - struct Region { - inline static auto NTSC() -> bool; - inline static auto PAL() -> bool; - }; - - #include - - #include - #include - #include - - #include - #include -} - -#include diff --git a/higan/ms/psg/io.cpp b/higan/ms/psg/io.cpp deleted file mode 100644 index 487aa1d1..00000000 --- a/higan/ms/psg/io.cpp +++ /dev/null @@ -1,66 +0,0 @@ -auto PSG::write(uint8 data) -> void { - bool l = data.bit(7); - if(l) select = data.bits(4,6); - - switch(select) { - - case 0: { - if(l) tone0.pitch.bits(0,3) = data.bits(0,3); - else tone0.pitch.bits(4,9) = data.bits(0,5); - break; - } - - case 1: { - tone0.volume = data.bits(0,3); - break; - } - - case 2: { - if(l) tone1.pitch.bits(0,3) = data.bits(0,3); - else tone1.pitch.bits(4,9) = data.bits(0,5); - break; - } - - case 3: { - tone1.volume = data.bits(0,3); - break; - } - - case 4: { - if(l) tone2.pitch.bits(0,3) = data.bits(0,3); - else tone2.pitch.bits(4,9) = data.bits(0,5); - noise.pitch = tone2.pitch; - break; - } - - case 5: { - tone2.volume = data.bits(0,3); - break; - } - - case 6: { - noise.rate = data.bits(0,1); - noise.enable = data.bit(2); - noise.lfsr = 0x8000; - break; - } - - case 7: { - noise.volume = data.bits(0,3); - break; - } - - } -} - -//Game Gear only -auto PSG::balance(uint8 data) -> void { - tone0.right = data.bit(0); - tone1.right = data.bit(1); - tone2.right = data.bit(2); - noise.right = data.bit(3); - tone0.left = data.bit(4); - tone1.left = data.bit(5); - tone2.left = data.bit(6); - noise.left = data.bit(7); -} diff --git a/higan/ms/psg/noise.cpp b/higan/ms/psg/noise.cpp deleted file mode 100644 index f2c8ff5f..00000000 --- a/higan/ms/psg/noise.cpp +++ /dev/null @@ -1,27 +0,0 @@ -auto PSG::Noise::run() -> void { - if(counter--) return; - - if(rate == 0) counter = 0x10; - if(rate == 1) counter = 0x20; - if(rate == 2) counter = 0x40; - if(rate == 3) counter = pitch; //shared with tone2 - - if(clock ^= 1) { //0->1 transition - output = !lfsr.bit(0); - lfsr = (lfsr.bit(0) ^ (lfsr.bit(3) & enable)) << 15 | lfsr >> 1; - } -} - -auto PSG::Noise::power() -> void { - volume = ~0; - counter = 0; - pitch = 0; - enable = 0; - rate = 0; - lfsr = 0x8000; - clock = 0; - output = 0; - - left = 1; - right = 1; -} diff --git a/higan/ms/psg/psg.cpp b/higan/ms/psg/psg.cpp deleted file mode 100644 index e86a2ec6..00000000 --- a/higan/ms/psg/psg.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include - -namespace MasterSystem { - -PSG psg; -#include "io.cpp" -#include "tone.cpp" -#include "noise.cpp" -#include "serialization.cpp" - -auto PSG::Enter() -> void { - while(true) scheduler.synchronize(), psg.main(); -} - -auto PSG::main() -> void { - tone0.run(); - tone1.run(); - tone2.run(); - noise.run(); - - int left = 0; - left += levels[tone0.volume] * tone0.output * tone0.left; - left += levels[tone1.volume] * tone1.output * tone1.left; - left += levels[tone2.volume] * tone2.output * tone2.left; - left += levels[noise.volume] * noise.output * noise.left; - - int right = 0; - right += levels[tone0.volume] * tone0.output * tone0.right; - right += levels[tone1.volume] * tone1.output * tone1.right; - right += levels[tone2.volume] * tone2.output * tone2.right; - right += levels[noise.volume] * noise.output * noise.right; - - stream->sample(sclamp<16>(left) / 32768.0, sclamp<16>(right) / 32768.0); - step(1); -} - -auto PSG::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); -} - -auto PSG::power() -> void { - //Master System is monaural; Game Gear is stereo - //use stereo mode for both; output same sample to both channels for Master System - create(PSG::Enter, system.colorburst() / 16.0); - stream = Emulator::audio.createStream(2, frequency()); - stream->addHighPassFilter(20.0, Emulator::Filter::Order::First); - stream->addDCRemovalFilter(); - - select = 0; - for(auto n : range(15)) { - levels[n] = 0x2000 * pow(2, n * -2.0 / 6.0) + 0.5; - } - levels[15] = 0; - - tone0.power(); - tone1.power(); - tone2.power(); - noise.power(); -} - -} diff --git a/higan/ms/psg/psg.hpp b/higan/ms/psg/psg.hpp deleted file mode 100644 index 4f7fde56..00000000 --- a/higan/ms/psg/psg.hpp +++ /dev/null @@ -1,62 +0,0 @@ -//TI SN76489 (derivative) - -struct PSG : Thread { - shared_pointer stream; - - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - - auto power() -> void; - - //io.cpp - auto write(uint8 data) -> void; - auto balance(uint8 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - struct Tone { - //tone.cpp - auto run() -> void; - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - uint4 volume; - uint10 counter; - uint10 pitch; - uint1 output; - - uint1 left; - uint1 right; - } tone0, tone1, tone2; - - struct Noise { - //noise.cpp - auto run() -> void; - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - uint4 volume; - uint10 counter; - uint10 pitch; - uint1 enable; - uint2 rate; - uint16 lfsr; - uint1 clock; - uint1 output; - - uint1 left; - uint1 right; - } noise; - - uint3 select; - int16 levels[16]; -}; - -extern PSG psg; diff --git a/higan/ms/psg/serialization.cpp b/higan/ms/psg/serialization.cpp deleted file mode 100644 index cad1b1ba..00000000 --- a/higan/ms/psg/serialization.cpp +++ /dev/null @@ -1,34 +0,0 @@ -auto PSG::serialize(serializer& s) -> void { - Thread::serialize(s); - - tone0.serialize(s); - tone1.serialize(s); - tone2.serialize(s); - noise.serialize(s); - - s.integer(select); -} - -auto PSG::Tone::serialize(serializer& s) -> void { - s.integer(volume); - s.integer(counter); - s.integer(pitch); - s.integer(output); - - s.integer(left); - s.integer(right); -} - -auto PSG::Noise::serialize(serializer& s) -> void { - s.integer(volume); - s.integer(counter); - s.integer(pitch); - s.integer(enable); - s.integer(rate); - s.integer(lfsr); - s.integer(clock); - s.integer(output); - - s.integer(left); - s.integer(right); -} diff --git a/higan/ms/psg/tone.cpp b/higan/ms/psg/tone.cpp deleted file mode 100644 index 914e3627..00000000 --- a/higan/ms/psg/tone.cpp +++ /dev/null @@ -1,16 +0,0 @@ -auto PSG::Tone::run() -> void { - if(counter--) return; - - counter = pitch; - output ^= 1; -} - -auto PSG::Tone::power() -> void { - volume = ~0; - counter = 0; - pitch = 0; - output = 0; - - left = 1; - right = 1; -} diff --git a/higan/ms/system/serialization.cpp b/higan/ms/system/serialization.cpp deleted file mode 100644 index 3b2d9350..00000000 --- a/higan/ms/system/serialization.cpp +++ /dev/null @@ -1,60 +0,0 @@ -auto System::serializeInit() -> void { - serializer s; - - uint signature = 0; - char version[16] = {0}; - char description[512] = {0}; - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - information.serializeSize = s.size(); -} - -auto System::serialize() -> serializer { - serializer s{information.serializeSize}; - - uint signature = 0x31545342; - char version[16] = {0}; - char description[512] = {0}; - memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size()); - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - return s; -} - -auto System::unserialize(serializer& s) -> bool { - uint signature = 0; - char version[16] = {0}; - char description[512] = {0}; - - s.integer(signature); - s.array(version); - s.array(description); - - if(signature != 0x31545342) return false; - if(string{version} != Emulator::SerializerVersion) return false; - - power(); - serializeAll(s); - return true; -} - -auto System::serializeAll(serializer& s) -> void { - system.serialize(s); - cartridge.serialize(s); - cpu.serialize(s); - vdp.serialize(s); - psg.serialize(s); - controllerPort1.serialize(s); - controllerPort2.serialize(s); -} - -auto System::serialize(serializer& s) -> void { -} diff --git a/higan/ms/system/system.cpp b/higan/ms/system/system.cpp deleted file mode 100644 index 4986e513..00000000 --- a/higan/ms/system/system.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include - -namespace MasterSystem { - -System system; -Scheduler scheduler; -Cheat cheat; -#include "serialization.cpp" - -auto System::run() -> void { - if(scheduler.enter() == Scheduler::Event::Frame) { - cpu.pollPause(); - vdp.refresh(); - } -} - -auto System::runToSave() -> void { - scheduler.synchronize(cpu); - scheduler.synchronize(vdp); - scheduler.synchronize(psg); -} - -auto System::load(Emulator::Interface* interface, Model model) -> bool { - information = {}; - information.model = model; - - if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else return false; - - auto document = BML::unserialize(information.manifest); - - if(MasterSystem::Model::ColecoVision()) { - if(auto fp = platform->open(ID::System, "bios.rom", File::Read, File::Required)) { - fp->read(bios, 0x2000); - } else return false; - } - - if(!cartridge.load()) return false; - - if(cartridge.region() == "NTSC") { - information.region = Region::NTSC; - information.colorburst = Emulator::Constants::Colorburst::NTSC; - } - if(cartridge.region() == "PAL") { - information.region = Region::PAL; - information.colorburst = Emulator::Constants::Colorburst::PAL * 4.0 / 5.0; - } - - serializeInit(); - this->interface = interface; - return information.loaded = true; -} - -auto System::save() -> void { - cartridge.save(); -} - -auto System::unload() -> void { - if(!MasterSystem::Model::GameGear()) { - cpu.peripherals.reset(); - controllerPort1.unload(); - controllerPort2.unload(); - } - cartridge.unload(); -} - -auto System::power() -> void { - Emulator::video.reset(interface); - Emulator::video.setPalette(); - - Emulator::audio.reset(interface); - - scheduler.reset(); - cartridge.power(); - cpu.power(); - vdp.power(); - psg.power(); - scheduler.primary(cpu); - - if(!MasterSystem::Model::GameGear()) { - controllerPort1.power(ID::Port::Controller1); - controllerPort2.power(ID::Port::Controller2); - - controllerPort1.connect(settings.controllerPort1); - controllerPort2.connect(settings.controllerPort2); - } -} - -} diff --git a/higan/ms/system/system.hpp b/higan/ms/system/system.hpp deleted file mode 100644 index fa3cdc76..00000000 --- a/higan/ms/system/system.hpp +++ /dev/null @@ -1,51 +0,0 @@ -struct System { - enum class Model : uint { ColecoVision, SG1000, SC3000, MasterSystem, GameGear }; - enum class Region : uint { NTSC, PAL }; - - auto loaded() const -> bool { return information.loaded; } - auto model() const -> Model { return information.model; } - auto region() const -> Region { return information.region; } - auto colorburst() const -> double { return information.colorburst; } - - //system.cpp - auto run() -> void; - auto runToSave() -> void; - - auto load(Emulator::Interface* interface, Model model) -> bool; - auto save() -> void; - auto unload() -> void; - - auto power() -> void; - - //serialization.cpp - auto serializeInit() -> void; - auto serialize() -> serializer; - auto unserialize(serializer&) -> bool; - auto serializeAll(serializer&) -> void; - auto serialize(serializer&) -> void; - - uint8 bios[0x2000]; - -private: - Emulator::Interface* interface = nullptr; - - struct Information { - bool loaded = false; - Model model = Model::MasterSystem; - Region region = Region::NTSC; - double colorburst = Emulator::Constants::Colorburst::NTSC; - string manifest; - uint serializeSize = 0; - } information; -}; - -extern System system; - -auto Model::ColecoVision() -> bool { return system.model() == System::Model::ColecoVision; } -auto Model::SG1000() -> bool { return system.model() == System::Model::SG1000; } -auto Model::SC3000() -> bool { return system.model() == System::Model::SC3000; } -auto Model::MasterSystem() -> bool { return system.model() == System::Model::MasterSystem; } -auto Model::GameGear() -> bool { return system.model() == System::Model::GameGear; } - -auto Region::NTSC() -> bool { return system.region() == System::Region::NTSC; } -auto Region::PAL() -> bool { return system.region() == System::Region::PAL; } diff --git a/higan/ms/vdp/background.cpp b/higan/ms/vdp/background.cpp deleted file mode 100644 index 6c74669e..00000000 --- a/higan/ms/vdp/background.cpp +++ /dev/null @@ -1,117 +0,0 @@ -auto VDP::Background::run(uint8 hoffset, uint9 voffset) -> void { - output = {}; - switch(vdp.io.mode) { - case 0b0000: return graphics1(hoffset, voffset); - case 0b0001: return; - case 0b0010: return graphics2(hoffset, voffset); - case 0b0011: return; - case 0b0100: return; - case 0b0101: return; - case 0b0110: return; - case 0b0111: return; - case 0b1000: return graphics3(hoffset, voffset, 192); - case 0b1001: return; - case 0b1010: return graphics3(hoffset, voffset, 192); - case 0b1011: return graphics3(hoffset, voffset, 224); - case 0b1100: return graphics3(hoffset, voffset, 192); - case 0b1101: return; - case 0b1110: return graphics3(hoffset, voffset, 240); - case 0b1111: return graphics3(hoffset, voffset, 192); - } -} - -auto VDP::Background::graphics1(uint8 hoffset, uint9 voffset) -> void { - uint14 nameTableAddress; - nameTableAddress.bits( 0, 4) = hoffset.bits(3,7); - nameTableAddress.bits( 5, 9) = voffset.bits(3,7); - nameTableAddress.bits(10,13) = vdp.io.nameTableAddress; - uint8 pattern = vdp.vram[nameTableAddress]; - - uint14 patternAddress; - patternAddress.bits( 0, 2) = voffset.bits(0,2); - patternAddress.bits( 3,10) = pattern; - patternAddress.bits(11,13) = vdp.io.patternTableAddress; - - uint14 colorAddress; //d5 = 0 - colorAddress.bits(0, 4) = pattern.bits(3,7); - colorAddress.bits(6,13) = vdp.io.colorTableAddress; - - uint8 color = vdp.vram[colorAddress]; - uint3 index = hoffset ^ 7; - if(!vdp.vram[patternAddress].bit(index)) { - output.color = color.bits(0,3); - } else { - output.color = color.bits(4,7); - } -} - -auto VDP::Background::graphics2(uint8 hoffset, uint9 voffset) -> void { - uint14 nameTableAddress; - nameTableAddress.bits( 0, 4) = hoffset.bits(3,7); - nameTableAddress.bits( 5, 9) = voffset.bits(3,7); - nameTableAddress.bits(10,13) = vdp.io.nameTableAddress; - uint8 pattern = vdp.vram[nameTableAddress]; - - uint14 patternAddress; - patternAddress.bits(0, 2) = voffset.bits(0,2); - patternAddress.bits(3,10) = pattern; - if(voffset >= 64 && voffset <= 127) patternAddress.bit(11) = vdp.io.patternTableAddress.bit(0); - if(voffset >= 128 && voffset <= 191) patternAddress.bit(12) = vdp.io.patternTableAddress.bit(1); - uint14 colorAddress = patternAddress; - patternAddress.bit(13) = vdp.io.patternTableAddress.bit(2); - colorAddress.bit(13) = vdp.io.colorTableAddress.bit(7); - - uint8 colorMask = vdp.io.colorTableAddress.bits(0,6) << 1 | 1; - uint8 color = vdp.vram[colorAddress]; - uint3 index = hoffset ^ 7; - if(!vdp.vram[patternAddress].bit(index)) { - output.color = color.bits(0,3); - } else { - output.color = color.bits(4,7); - } -} - -auto VDP::Background::graphics3(uint8 hoffset, uint9 voffset, uint vlines) -> void { - if(hoffset < vdp.io.hscroll.bits(0,2)) return; - - if(!vdp.io.horizontalScrollLock || voffset >= 16) hoffset -= vdp.io.hscroll; - if(!vdp.io.verticalScrollLock || hoffset <= 191) voffset += vdp.io.vscroll; - - uint14 nameTableAddress; - if(vlines == 192) { - if(voffset >= 224) voffset -= 224; - nameTableAddress.bits( 1, 5) = hoffset.bits(3,7); - nameTableAddress.bits( 6,10) = voffset.bits(3,7); - nameTableAddress.bits(11,13) = vdp.io.nameTableAddress.bits(1,3); - } else { - voffset += 224; - nameTableAddress.bits( 1, 5) = hoffset.bits(3,7); - nameTableAddress.bits( 6,11) = voffset.bits(3,8); - nameTableAddress.bits(12,13) = vdp.io.nameTableAddress.bits(2,3); - } - - uint16 pattern; - pattern.byte(0) = vdp.vram[nameTableAddress | 0]; - pattern.byte(1) = vdp.vram[nameTableAddress | 1]; - - if(pattern.bit( 9)) hoffset ^= 7; //hflip - if(pattern.bit(10)) voffset ^= 7; //vflip - output.palette = pattern.bit(11); - output.priority = pattern.bit(12); - - uint14 patternAddress; - patternAddress.bits(2, 4) = voffset.bits(0,2); - patternAddress.bits(5,13) = pattern.bits(0,8); - - uint3 index = hoffset ^ 7; - output.color.bit(0) = vdp.vram[patternAddress | 0].bit(index); - output.color.bit(1) = vdp.vram[patternAddress | 1].bit(index); - output.color.bit(2) = vdp.vram[patternAddress | 2].bit(index); - output.color.bit(3) = vdp.vram[patternAddress | 3].bit(index); - - if(output.color == 0) output.priority = 0; -} - -auto VDP::Background::power() -> void { - output = {}; -} diff --git a/higan/ms/vdp/io.cpp b/higan/ms/vdp/io.cpp deleted file mode 100644 index a7a2d104..00000000 --- a/higan/ms/vdp/io.cpp +++ /dev/null @@ -1,156 +0,0 @@ -auto VDP::vcounter() -> uint8 { - switch(io.mode) { - default: return io.vcounter <= 218 ? io.vcounter : io.vcounter - 6; //256x192 - case 0b1011: return io.vcounter <= 234 ? io.vcounter : io.vcounter - 6; //256x224 - case 0b1110: return io.vcounter; //256x240 - } -} - -auto VDP::hcounter() -> uint8 { - uint hcounter = io.hcounter >> 1; - return hcounter <= 233 ? hcounter : hcounter - 86; -} - -auto VDP::data() -> uint8 { - io.controlLatch = 0; - - auto data = io.vramLatch; - io.vramLatch = vram[io.address++]; - return data; -} - -auto VDP::status() -> uint8 { - io.controlLatch = 0; - - uint8 result = 0x00; - result |= io.intFrame << 7; - result |= io.spriteOverflow << 6; - result |= io.spriteCollision << 5; - result |= io.fifthSprite << 0; - - io.intLine = 0; - io.intFrame = 0; - io.spriteOverflow = 0; - io.spriteCollision = 0; - io.fifthSprite = 0; - - return result; -} - -auto VDP::data(uint8 data) -> void { - io.controlLatch = 0; - - if(io.code <= 2) { - vram[io.address++] = data; - } else { - uint mask = 0; - if(Model::MasterSystem()) cram[io.address++ & 0x1f] = data; - if(Model::GameGear()) cram[io.address++ & 0x3f] = data; - } -} - -auto VDP::control(uint8 data) -> void { - if(io.controlLatch == 0) { - io.controlLatch = 1; - io.address.bits(0,7) = data.bits(0,7); - return; - } else { - io.controlLatch = 0; - io.address.bits(8,13) = data.bits(0,5); - io.code.bits(0,1) = data.bits(6,7); - } - - if(io.code == 0) { - io.vramLatch = vram[io.address++]; - } - - if(io.code == 2) { - registerWrite(io.address.bits(11,8), io.address.bits(7,0)); - } -} - -auto VDP::registerWrite(uint4 addr, uint8 data) -> void { - switch(addr) { - - //mode control 1 - case 0x0: { - io.externalSync = data.bit(0); - io.mode.bit(1) = data.bit(1); - io.mode.bit(3) = data.bit(2) & !Model::ColecoVision() && !Model::SG1000() & !Model::SC3000(); - io.spriteShift = data.bit(3); - io.lineInterrupts = data.bit(4); - io.leftClip = data.bit(5); - io.horizontalScrollLock = data.bit(6); - io.verticalScrollLock = data.bit(7); - return; - } - - //mode control 2 - case 0x1: { - io.spriteDouble = data.bit(0); - io.spriteTile = data.bit(1); - io.mode.bit(2) = data.bit(3); - io.mode.bit(0) = data.bit(4); - io.frameInterrupts = data.bit(5); - io.displayEnable = data.bit(6); - return; - } - - //name table base address - case 0x2: { - io.nameTableAddress = data.bits(0,3); - return; - } - - //color table base address - case 0x3: { - io.colorTableAddress = data.bits(0,7); - return; - } - - //pattern table base address - case 0x4: { - io.patternTableAddress = data.bits(0,2); - return; - } - - //sprite attribute table base address - case 0x5: { - io.spriteAttributeTableAddress = data.bits(0,6); - return; - } - - //sprite pattern table base address - case 0x6: { - io.spritePatternTableAddress = data.bits(0,2); - return; - } - - //backdrop color - case 0x7: { - io.backdropColor = data.bits(0,3); - return; - } - - //horizontal scroll offset - case 0x8: { - io.hscroll = data.bits(0,7); - return; - } - - //vertical scroll offset - case 0x9: { - io.vscroll = data.bits(0,7); - return; - } - - //line counter - case 0xa: { - io.lineCounter = data.bits(0,7); - return; - } - - //0xb - 0xf unmapped - - } -} diff --git a/higan/ms/vdp/serialization.cpp b/higan/ms/vdp/serialization.cpp deleted file mode 100644 index 1b13c658..00000000 --- a/higan/ms/vdp/serialization.cpp +++ /dev/null @@ -1,60 +0,0 @@ -auto VDP::serialize(serializer& s) -> void { - Thread::serialize(s); - - background.serialize(s); - sprite.serialize(s); - - s.array(vram); - s.array(cram); - - s.integer(io.vcounter); - s.integer(io.hcounter); - s.integer(io.lcounter); - s.integer(io.intLine); - s.integer(io.intFrame); - s.integer(io.spriteOverflow); - s.integer(io.spriteCollision); - s.integer(io.fifthSprite); - s.integer(io.controlLatch); - s.integer(io.controlData); - s.integer(io.code); - s.integer(io.address); - s.integer(io.vramLatch); - s.integer(io.externalSync); - s.integer(io.spriteShift); - s.integer(io.lineInterrupts); - s.integer(io.leftClip); - s.integer(io.horizontalScrollLock); - s.integer(io.verticalScrollLock); - s.integer(io.spriteDouble); - s.integer(io.spriteTile); - s.integer(io.frameInterrupts); - s.integer(io.displayEnable); - s.integer(io.mode); - s.integer(io.nameTableAddress); - s.integer(io.colorTableAddress); - s.integer(io.patternTableAddress); - s.integer(io.spriteAttributeTableAddress); - s.integer(io.spritePatternTableAddress); - s.integer(io.backdropColor); - s.integer(io.hscroll); - s.integer(io.vscroll); - s.integer(io.lineCounter); -} - -auto VDP::Background::serialize(serializer& s) -> void { - s.integer(output.color); - s.integer(output.palette); - s.integer(output.priority); -} - -auto VDP::Sprite::serialize(serializer& s) -> void { - s.integer(output.color); - for(auto& object : objects) { - s.integer(object.x); - s.integer(object.y); - s.integer(object.pattern); - s.integer(object.color); - } - s.integer(objectsValid); -} diff --git a/higan/ms/vdp/sprite.cpp b/higan/ms/vdp/sprite.cpp deleted file mode 100644 index 494f534c..00000000 --- a/higan/ms/vdp/sprite.cpp +++ /dev/null @@ -1,133 +0,0 @@ -auto VDP::Sprite::setup(uint9 voffset) -> void { - objectsValid = 0; - uint limit = vdp.io.spriteTile ? 15 : 7; - - if(!vdp.io.mode.bit(3)) { - uint14 attributeAddress; - attributeAddress.bits(7,13) = vdp.io.spriteAttributeTableAddress; - for(uint index : range(32)) { - uint8 y = vdp.vram[attributeAddress++]; - if(y == 0xd0) break; - - uint8 x = vdp.vram[attributeAddress++]; - uint8 pattern = vdp.vram[attributeAddress++]; - uint8 extra = vdp.vram[attributeAddress++]; - - if(extra.bit(7)) x -= 32; - y += 1; - if(voffset < y) continue; - if(voffset > y + limit) continue; - - if(limit == 15) pattern.bits(0,1) = 0; - - objects[objectsValid] = {x, y, pattern, extra.bits(0,3)}; - if(++objectsValid == 4) { - vdp.io.spriteOverflow = 1; - break; - } - } - } else { - uint14 attributeAddress; - attributeAddress.bits(8,13) = vdp.io.spriteAttributeTableAddress.bits(1,6); - for(uint index : range(64)) { - uint8 y = vdp.vram[attributeAddress + index]; - uint8 x = vdp.vram[attributeAddress + 0x80 + (index << 1)]; - uint8 pattern = vdp.vram[attributeAddress + 0x81 + (index << 1)]; - if(vdp.vlines() == 192 && y == 0xd0) break; - - if(vdp.io.spriteShift) x -= 8; - y += 1; - if(voffset < y) continue; - if(voffset > y + limit) continue; - - if(limit == 15) pattern.bit(0) = 0; - - objects[objectsValid] = {x, y, pattern}; - if(++objectsValid == 8) { - vdp.io.spriteOverflow = 1; - break; - } - } - } -} - -auto VDP::Sprite::run(uint8 hoffset, uint9 voffset) -> void { - output = {}; - switch(vdp.io.mode) { - case 0b0000: return graphics1(hoffset, voffset); - case 0b0001: return; - case 0b0010: return graphics2(hoffset, voffset); - case 0b0011: return; - case 0b0100: return; - case 0b0101: return; - case 0b0110: return; - case 0b0111: return; - case 0b1000: return graphics3(hoffset, voffset, 192); - case 0b1001: return; - case 0b1010: return graphics3(hoffset, voffset, 192); - case 0b1011: return graphics3(hoffset, voffset, 224); - case 0b1100: return graphics3(hoffset, voffset, 192); - case 0b1101: return; - case 0b1110: return graphics3(hoffset, voffset, 240); - case 0b1111: return graphics3(hoffset, voffset, 192); - } -} - -auto VDP::Sprite::graphics1(uint8 hoffset, uint9 voffset) -> void { - //todo: are sprites different in graphics mode 1? - return graphics2(hoffset, voffset); -} - -auto VDP::Sprite::graphics2(uint8 hoffset, uint9 voffset) -> void { - uint limit = vdp.io.spriteTile ? 15 : 7; - for(uint objectIndex : range(objectsValid)) { - auto& o = objects[objectIndex]; - if(hoffset < o.x) continue; - if(hoffset > o.x + limit) continue; - - uint x = hoffset - o.x; - uint y = voffset - o.y; - - uint14 address; - address.bits( 0,10) = (o.pattern << 3) + (x >> 3 << 4) + (y & limit); - address.bits(11,13) = vdp.io.spritePatternTableAddress; - - uint3 index = x ^ 7; - if(vdp.vram[address].bit(index)) { - if(output.color) { vdp.io.spriteCollision = true; break; } - output.color = o.color; - } - } -} - -auto VDP::Sprite::graphics3(uint8 hoffset, uint9 voffset, uint vlines) -> void { - uint limit = vdp.io.spriteTile ? 15 : 7; - for(uint objectIndex : range(objectsValid)) { - auto& o = objects[objectIndex]; - if(hoffset < o.x) continue; - if(hoffset > o.x + 7) continue; - - uint x = hoffset - o.x; - uint y = voffset - o.y; - - uint14 address; - address.bits(2,12) = (o.pattern << 3) + (y & limit); - address.bit (13) = vdp.io.spritePatternTableAddress.bit(2); - - uint3 index = x ^ 7; - uint4 color; - color.bit(0) = vdp.vram[address | 0].bit(index); - color.bit(1) = vdp.vram[address | 1].bit(index); - color.bit(2) = vdp.vram[address | 2].bit(index); - color.bit(3) = vdp.vram[address | 3].bit(index); - if(color == 0) continue; - - if(output.color) { vdp.io.spriteCollision = true; break; } - output.color = color; - } -} - -auto VDP::Sprite::power() -> void { - output = {}; - objectsValid = 0; -} diff --git a/higan/ms/vdp/vdp.cpp b/higan/ms/vdp/vdp.cpp deleted file mode 100644 index cf3b2cd5..00000000 --- a/higan/ms/vdp/vdp.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include - -namespace MasterSystem { - -VDP vdp; -#include "io.cpp" -#include "background.cpp" -#include "sprite.cpp" -#include "serialization.cpp" - -auto VDP::Enter() -> void { - while(true) scheduler.synchronize(), vdp.main(); -} - -auto VDP::main() -> void { - if(io.vcounter <= vlines()) { - if(io.lcounter-- == 0) { - io.lcounter = io.lineCounter; - io.intLine = 1; - } - } else { - io.lcounter = io.lineCounter; - } - - if(io.vcounter == vlines() + 1) { - io.intFrame = 1; - } - - //684 clocks/scanline - uint y = io.vcounter; - sprite.setup(y); - if(y < vlines()) { - uint32* screen = buffer + (24 + y) * 256; - for(uint x : range(256)) { - background.run(x, y); - sprite.run(x, y); - step(2); - - uint12 color = palette(16 | io.backdropColor); - if(!io.leftClip || x >= 8) { - if(background.output.priority || !sprite.output.color) { - color = palette(background.output.palette << 4 | background.output.color); - } else if(sprite.output.color) { - color = palette(16 | sprite.output.color); - } - } - if(!io.displayEnable) color = 0; - *screen++ = color; - } - } else { - //Vblank - step(512); - } - step(172); - - if(io.vcounter == 240) scheduler.exit(Scheduler::Event::Frame); -} - -auto VDP::step(uint clocks) -> void { - while(clocks--) { - if(++io.hcounter == 684) { - io.hcounter = 0; - if(++io.vcounter == (Region::NTSC() ? 262 : 312)) { - io.vcounter = 0; - } - } - - cpu.setINT((io.lineInterrupts && io.intLine) || (io.frameInterrupts && io.intFrame)); - Thread::step(1); - synchronize(cpu); - } -} - -auto VDP::refresh() -> void { - if(Model::ColecoVision() || Model::SG1000() || Model::SC3000()) { - uint32* screen = buffer; - screen += 24 * 256; - Emulator::video.refresh(screen, 256 * sizeof(uint32), 256, 192); - } - - if(Model::MasterSystem()) { - //center the video output vertically in the viewport - uint32* screen = buffer; - if(vlines() == 224) screen += 16 * 256; - if(vlines() == 240) screen += 24 * 256; - - Emulator::video.refresh(screen, 256 * sizeof(uint32), 256, 240); - } - - if(Model::GameGear()) { - Emulator::video.refresh(buffer + 48 * 256 + 48, 256 * sizeof(uint32), 160, 144); - } -} - -auto VDP::vlines() -> uint { - switch(io.mode) { - default: return 192; - case 0b1011: return 224; - case 0b1110: return 240; - } -} - -auto VDP::vblank() -> bool { - return io.vcounter >= vlines(); -} - -auto VDP::power() -> void { - create(VDP::Enter, system.colorburst() * 15.0 / 5.0); - - memory::fill(buffer, 256 * 264); - for(auto& byte : vram) byte = 0x00; - for(auto& byte : cram) byte = 0x00; - io = {}; - - background.power(); - sprite.power(); -} - -auto VDP::palette(uint5 index) -> uint12 { - if(Model::ColecoVision() || Model::SG1000() || Model::SC3000()) return index.bits(0,3); - //Master System and Game Gear approximate TMS9918A colors by converting to RGB6 palette colors - static uint6 palette[16] = { - 0x00, 0x00, 0x08, 0x0c, 0x10, 0x30, 0x01, 0x3c, - 0x02, 0x03, 0x05, 0x0f, 0x04, 0x33, 0x15, 0x3f, - }; - if(!io.mode.bit(3)) return palette[index.bits(0,3)]; - if(Model::MasterSystem()) return cram[index]; - if(Model::GameGear()) return cram[index * 2 + 0] << 0 | cram[index * 2 + 1] << 8; - return 0; -} - -} diff --git a/higan/ms/vdp/vdp.hpp b/higan/ms/vdp/vdp.hpp deleted file mode 100644 index e0475ce9..00000000 --- a/higan/ms/vdp/vdp.hpp +++ /dev/null @@ -1,149 +0,0 @@ -//Texas Instruments TMS9918A (derivative) - -struct VDP : Thread { - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - auto refresh() -> void; - - auto vlines() -> uint; - auto vblank() -> bool; - - auto power() -> void; - - //io.cpp - auto vcounter() -> uint8; - auto hcounter() -> uint8; - auto data() -> uint8; - auto status() -> uint8; - - auto data(uint8) -> void; - auto control(uint8) -> void; - auto registerWrite(uint4 addr, uint8 data) -> void; - - //background.cpp - struct Background { - auto run(uint8 hoffset, uint9 voffset) -> void; - auto graphics1(uint8 hoffset, uint9 voffset) -> void; - auto graphics2(uint8 hoffset, uint9 voffset) -> void; - auto graphics3(uint8 hoffset, uint9 voffset, uint vlines) -> void; - - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - struct Output { - uint4 color; - uint1 palette; - uint1 priority; - } output; - } background; - - //sprite.cpp - struct Sprite { - auto setup(uint9 voffset) -> void; - auto run(uint8 hoffset, uint9 voffset) -> void; - auto graphics1(uint8 hoffset, uint9 voffset) -> void; - auto graphics2(uint8 hoffset, uint9 voffset) -> void; - auto graphics3(uint8 hoffset, uint9 voffset, uint vlines) -> void; - - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - struct Object { - uint8 x; - uint8 y; - uint8 pattern; - uint4 color; - }; - - struct Output { - uint4 color; - } output; - - array objects; - uint objectsValid; - } sprite; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - auto palette(uint5 index) -> uint12; - - uint32 buffer[256 * 264]; - uint8 vram[0x4000]; - uint8 cram[0x40]; //SG + MS = 0x20, GG = 0x40 - - struct IO { - uint vcounter = 0; //vertical counter - uint hcounter = 0; //horizontal counter - uint lcounter = 0; //line counter - - //interrupt flags - bool intLine = 0; - bool intFrame = 0; - - //status flags - bool spriteOverflow = 0; - bool spriteCollision = 0; - uint5 fifthSprite; - - //latches - bool controlLatch = 0; - uint16 controlData; - uint2 code; - uint14 address; - - uint8 vramLatch; - - //$00 mode control 1 - bool externalSync = 0; - bool spriteShift = 0; - bool lineInterrupts = 0; - bool leftClip = 0; - bool horizontalScrollLock = 0; - bool verticalScrollLock = 0; - - //$01 mode control 2 - bool spriteDouble = 0; - bool spriteTile = 0; - bool frameInterrupts = 0; - bool displayEnable = 0; - - //$00 + $01 - uint4 mode; - - //$02 name table base address - uint4 nameTableAddress; - - //$03 color table base address - uint8 colorTableAddress; - - //$04 pattern table base address - uint3 patternTableAddress; - - //$05 sprite attribute table base address - uint7 spriteAttributeTableAddress; - - //$06 sprite pattern table base address - uint3 spritePatternTableAddress; - - //$07 backdrop color - uint4 backdropColor; - - //$08 horizontal scroll offset - uint8 hscroll; - - //$09 vertical scroll offset - uint8 vscroll; - - //$0a line counter - uint8 lineCounter; - } io; -}; - -extern VDP vdp; diff --git a/higan/msx/GNUmakefile b/higan/msx/GNUmakefile deleted file mode 100644 index 4f0d9b25..00000000 --- a/higan/msx/GNUmakefile +++ /dev/null @@ -1,11 +0,0 @@ -processors += z80 - -objects += msx-interface msx-system msx-cartridge -objects += msx-cpu msx-vdp msx-psg - -obj/msx-interface.o: msx/interface/interface.cpp -obj/msx-system.o: msx/system/system.cpp -obj/msx-cartridge.o: msx/cartridge/cartridge.cpp -obj/msx-cpu.o: msx/cpu/cpu.cpp -obj/msx-vdp.o: msx/vdp/vdp.cpp -obj/msx-psg.o: msx/psg/psg.cpp diff --git a/higan/msx/cartridge/cartridge.cpp b/higan/msx/cartridge/cartridge.cpp deleted file mode 100644 index 63d71f78..00000000 --- a/higan/msx/cartridge/cartridge.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include - -namespace MSX { - -Cartridge cartridge; -Cartridge expansion; -#include "serialization.cpp" - -auto Cartridge::load() -> bool { - information = {}; - - if(Model::MSX()) { - if(auto loaded = platform->load(ID::MSX, "MSX", "msx", {"NTSC", "PAL"})) { - information.pathID = loaded.pathID; - information.region = loaded.option; - } else return false; - } - - if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else return false; - - auto document = BML::unserialize(information.manifest); - information.title = document["game/label"].text(); - - if(auto memory = document["game/board/memory(type=ROM,content=Program)"]) { - rom.allocate(memory["size"].natural()); - if(auto fp = platform->open(pathID(), "program.rom", File::Read, File::Required)) { - rom.load(fp); - } else return false; - } - - if(auto memory = document["game/board/memory(type=RAM,content=Save)"]) { - ram.allocate(memory["size"].natural()); - if(auto fp = platform->open(pathID(), "save.ram", File::Read)) { - ram.load(fp); - } - } - - return true; -} - -auto Cartridge::save() -> void { - auto document = BML::unserialize(information.manifest); - - if(auto memory = document["game/board/memory(type=RAM,content=Save)"]) { - if(auto fp = platform->open(pathID(), "save.ram", File::Write)) { - ram.save(fp); - } - } -} - -auto Cartridge::unload() -> void { - rom.reset(); - ram.reset(); -} - -auto Cartridge::power() -> void { -} - -auto Cartridge::read(uint16 address) -> uint8 { - return rom.read(address); -} - -auto Cartridge::write(uint16 address, uint8 data) -> void { -} - -} diff --git a/higan/msx/cartridge/cartridge.hpp b/higan/msx/cartridge/cartridge.hpp deleted file mode 100644 index 1d2c0c5c..00000000 --- a/higan/msx/cartridge/cartridge.hpp +++ /dev/null @@ -1,35 +0,0 @@ -struct Cartridge { - auto pathID() const -> uint { return information.pathID; } - auto region() const -> string { return information.region; } - auto hash() const -> string { return information.sha256; } - auto manifest() const -> string { return information.manifest; } - auto title() const -> string { return information.title; } - - //cartridge.cpp - auto load() -> bool; - auto save() -> void; - auto unload() -> void; - - auto power() -> void; - - auto read(uint16 address) -> uint8; - auto write(uint16 address, uint8 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - struct Information { - uint pathID = 0; - string region; - string sha256; - string manifest; - string title; - } information; - - Emulator::Memory::Readable rom; - Emulator::Memory::Writable ram; -}; - -extern Cartridge cartridge; -extern Cartridge expansion; diff --git a/higan/msx/cartridge/serialization.cpp b/higan/msx/cartridge/serialization.cpp deleted file mode 100644 index 13665ef9..00000000 --- a/higan/msx/cartridge/serialization.cpp +++ /dev/null @@ -1,3 +0,0 @@ -auto Cartridge::serialize(serializer& s) -> void { - if(ram) s.array(ram.data(), ram.size()); -} diff --git a/higan/msx/cpu/cpu.cpp b/higan/msx/cpu/cpu.cpp deleted file mode 100644 index 3c16295c..00000000 --- a/higan/msx/cpu/cpu.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include - -namespace MSX { - -CPU cpu; -#include "memory.cpp" -#include "serialization.cpp" - -auto CPU::Enter() -> void { - while(true) scheduler.synchronize(), cpu.main(); -} - -auto CPU::main() -> void { - if(io.irqLine) irq(1, 0x0038, 0xff); - instruction(); -} - -auto CPU::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(vdp); - synchronize(psg); -} - -auto CPU::synchronizing() const -> bool { - return scheduler.synchronizing(); -} - -auto CPU::power() -> void { - Z80::bus = this; - Z80::power(); - create(CPU::Enter, system.colorburst()); - - r.pc = 0x0000; //reset vector address - - ram.allocate(0x10000); - - io = {}; -} - -auto CPU::setIRQ(bool line) -> void { - io.irqLine = line; -} - -} diff --git a/higan/msx/cpu/cpu.hpp b/higan/msx/cpu/cpu.hpp deleted file mode 100644 index 92ced7f0..00000000 --- a/higan/msx/cpu/cpu.hpp +++ /dev/null @@ -1,30 +0,0 @@ -struct CPU : Processor::Z80, Processor::Z80::Bus, Thread { - //cpu.cpp - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void override; - auto synchronizing() const -> bool override; - - auto power() -> void; - auto setIRQ(bool) -> void; - - //memory.cpp - auto read(uint16 address) -> uint8 override; - auto write(uint16 address, uint8 data) -> void override; - - auto in(uint8 address) -> uint8 override; - auto out(uint8 address, uint8 data) -> void override; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - Emulator::Memory::Writable ram; - - struct IO { - uint1 irqLine; - uint2 slot[4]; - } io; -}; - -extern CPU cpu; diff --git a/higan/msx/cpu/memory.cpp b/higan/msx/cpu/memory.cpp deleted file mode 100644 index 054fcc40..00000000 --- a/higan/msx/cpu/memory.cpp +++ /dev/null @@ -1,65 +0,0 @@ -auto CPU::read(uint16 address) -> uint8 { - uint2 slot = io.slot[address.bits(14,15)]; - - if(slot == 0) { - if(!address.bit(15)) return system.bios.read(address); - return 0xff; - } - - if(slot == 1) { - return cartridge.read(address); - } - - if(slot == 2) { - return ram.read(address); - } - - if(slot == 3) { - } - - return 0xff; -} - -auto CPU::write(uint16 address, uint8 data) -> void { - uint2 slot = io.slot[address.bits(14,15)]; - - if(slot == 0) { - return; - } - - if(slot == 1) { - return cartridge.write(address, data); - } - - if(slot == 2) { - return ram.write(address, data); - } - - if(slot == 3) { - return; - } -} - -auto CPU::in(uint8 address) -> uint8 { - switch(address) { - case 0x98: return vdp.data(); - case 0x99: return vdp.status(); - case 0xa8: return io.slot[0] << 0 - | io.slot[1] << 2 - | io.slot[2] << 4 - | io.slot[3] << 6; - } - return 0xff; -} - -auto CPU::out(uint8 address, uint8 data) -> void { - switch(address) { - case 0x98: return vdp.data(data); - case 0x99: return vdp.control(data); - case 0xa8: io.slot[0] = data.bits(0,1); - io.slot[1] = data.bits(2,3); - io.slot[2] = data.bits(4,5); - io.slot[3] = data.bits(6,7); - break; - } -} diff --git a/higan/msx/cpu/serialization.cpp b/higan/msx/cpu/serialization.cpp deleted file mode 100644 index 70e7b1a8..00000000 --- a/higan/msx/cpu/serialization.cpp +++ /dev/null @@ -1,5 +0,0 @@ -auto CPU::serialize(serializer& s) -> void { - Z80::serialize(s); - Z80::Bus::serialize(s); - Thread::serialize(s); -} diff --git a/higan/msx/interface/interface.cpp b/higan/msx/interface/interface.cpp deleted file mode 100644 index 48b429a5..00000000 --- a/higan/msx/interface/interface.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include - -namespace MSX { - -auto Interface::information() -> Information { - Information information; - information.manufacturer = ""; - information.name = "MSX"; - information.extension = "msx"; - return information; -} - -auto Interface::display() -> Display { - Display display; - display.type = Display::Type::CRT; - display.colors = 1 << 4; - display.width = 256; - display.height = 192; - display.internalWidth = 256; - display.internalHeight = 192; - display.aspectCorrection = 1.0; - return display; -} - -auto Interface::color(uint32 color) -> uint64 { - switch(color.bits(0,3)) { - case 0: return 0x0000'0000'0000ull; //transparent - case 1: return 0x0000'0000'0000ull; //black - case 2: return 0x2121'c8c8'4242ull; //medium green - case 3: return 0x5e5e'dcdc'7878ull; //light green - case 4: return 0x5454'5555'ededull; //dark blue - case 5: return 0x7d7d'7676'fcfcull; //light blue - case 6: return 0xd4d4'5252'4d4dull; //dark red - case 7: return 0x4242'ebeb'f5f5ull; //cyan - case 8: return 0xfcfc'5555'5454ull; //medium red - case 9: return 0xffff'7979'7878ull; //light red - case 10: return 0xd4d4'c1c1'5454ull; //dark yellow - case 11: return 0xe6e6'cece'8080ull; //light yellow - case 12: return 0x2121'b0b0'3b3bull; //dark green - case 13: return 0xc9c9'5b5b'babaull; //magenta - case 14: return 0xcccc'cccc'ccccull; //gray - case 15: return 0xffff'ffff'ffffull; //white - } - return 0; -} - -auto Interface::loaded() -> bool { - return system.loaded(); -} - -auto Interface::hashes() -> vector { - return {cartridge.hash()}; -} - -auto Interface::manifests() -> vector { - return {cartridge.manifest()}; -} - -auto Interface::titles() -> vector { - return {cartridge.title()}; -} - -auto Interface::load() -> bool { - return system.load(this, System::Model::MSX); -} - -auto Interface::save() -> void { - system.save(); -} - -auto Interface::unload() -> void { - save(); - system.unload(); -} - -auto Interface::ports() -> vector { return { - {ID::Port::Controller1, "Controller Port 1"}, - {ID::Port::Controller2, "Controller Port 2"}}; -} - -auto Interface::devices(uint port) -> vector { - if(port == ID::Port::Controller1) return { - {ID::Device::None, "None" }, - {ID::Device::Gamepad, "Gamepad"} - }; - - if(port == ID::Port::Controller2) return { - {ID::Device::None, "None" }, - {ID::Device::Gamepad, "Gamepad"} - }; - - return {}; -} - -auto Interface::inputs(uint device) -> vector { - using Type = Input::Type; - - if(device == ID::Device::Gamepad) return { - {Type::Hat, "Up" }, - {Type::Hat, "Down" }, - {Type::Hat, "Left" }, - {Type::Hat, "Right"}, - {Type::Button, "1" }, - {Type::Button, "2" } - }; - - return {}; -} - -auto Interface::power() -> void { - system.power(); -} - -auto Interface::run() -> void { - system.run(); -} - -auto Interface::serialize() -> serializer { - system.runToSave(); - return system.serialize(); -} - -auto Interface::unserialize(serializer& s) -> bool { - return system.unserialize(s); -} - -} diff --git a/higan/msx/interface/interface.hpp b/higan/msx/interface/interface.hpp deleted file mode 100644 index 9ac06c99..00000000 --- a/higan/msx/interface/interface.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#if defined(CORE_MSX) - -namespace MSX { - -struct ID { - enum : uint { - System, - MSX, - MSX2, - MSX2Plus, - MSXTurboR, - }; - - struct Port { enum : uint { - Controller1, - Controller2, - };}; - - struct Device { enum : uint { - None, - Gamepad, - };}; -}; - -struct Interface : Emulator::Interface { - auto information() -> Information override; - - auto display() -> Display override; - auto color(uint32 color) -> uint64 override; - - auto loaded() -> bool override; - auto hashes() -> vector override; - auto manifests() -> vector override; - auto titles() -> vector override; - auto load() -> bool override; - auto save() -> void override; - auto unload() -> void override; - - auto ports() -> vector override; - auto devices(uint port) -> vector override; - auto inputs(uint device) -> vector override; - - auto power() -> void override; - auto run() -> void override; - - auto serialize() -> serializer override; - auto unserialize(serializer&) -> bool override; -}; - -} - -#endif diff --git a/higan/msx/msx.hpp b/higan/msx/msx.hpp deleted file mode 100644 index fbaeea06..00000000 --- a/higan/msx/msx.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -//license: GPLv3 -//started: 2018-12-28 - -#include -#include -#include -#include - -#include - -namespace MSX { - #define platform Emulator::platform - namespace File = Emulator::File; - using Scheduler = Emulator::Scheduler; - using Cheat = Emulator::Cheat; - extern Scheduler scheduler; - extern Cheat cheat; - - struct Thread : Emulator::Thread { - auto create(auto (*entrypoint)() -> void, double frequency) -> void { - Emulator::Thread::create(entrypoint, frequency); - scheduler.append(*this); - } - - inline auto synchronize(Thread& thread) -> void { - if(clock() >= thread.clock()) scheduler.resume(thread); - } - }; - - struct Model { - inline static auto MSX() -> bool; - inline static auto MSX2() -> bool; - inline static auto MSX2Plus() -> bool; - inline static auto MSXTurboR() -> bool; - }; - - struct Region { - inline static auto NTSC() -> bool; - inline static auto PAL() -> bool; - }; - - #include - #include - - #include - #include - #include -} - -#include diff --git a/higan/msx/psg/psg.cpp b/higan/msx/psg/psg.cpp deleted file mode 100644 index 556f4f31..00000000 --- a/higan/msx/psg/psg.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include - -namespace MSX { - -PSG psg; -#include "serialization.cpp" - -auto PSG::Enter() -> void { - while(true) scheduler.synchronize(), psg.main(); -} - -auto PSG::main() -> void { - stream->sample(0.0); - step(1); -} - -auto PSG::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); -} - -auto PSG::power() -> void { - create(PSG::Enter, system.colorburst() / 2.0); - stream = Emulator::audio.createStream(1, frequency()); - stream->addHighPassFilter(20.0, Emulator::Filter::Order::First); - stream->addDCRemovalFilter(); -} - -} diff --git a/higan/msx/psg/psg.hpp b/higan/msx/psg/psg.hpp deleted file mode 100644 index 9259f815..00000000 --- a/higan/msx/psg/psg.hpp +++ /dev/null @@ -1,17 +0,0 @@ -//General Instrument AY-3-8910 - -struct PSG : Thread { - shared_pointer stream; - - //psg.cpp - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; -}; - -extern PSG psg; diff --git a/higan/msx/psg/serialization.cpp b/higan/msx/psg/serialization.cpp deleted file mode 100644 index 80bf3879..00000000 --- a/higan/msx/psg/serialization.cpp +++ /dev/null @@ -1,3 +0,0 @@ -auto PSG::serialize(serializer& s) -> void { - Thread::serialize(s); -} diff --git a/higan/msx/system/serialization.cpp b/higan/msx/system/serialization.cpp deleted file mode 100644 index c41878e5..00000000 --- a/higan/msx/system/serialization.cpp +++ /dev/null @@ -1,58 +0,0 @@ -auto System::serializeInit() -> void { - serializer s; - - uint signature = 0; - char version[16] = {}; - char description[512] = {}; - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - information.serializeSize = s.size(); -} - -auto System::serialize() -> serializer { - serializer s{information.serializeSize}; - - uint signature = 0x31545342; - char version[16] = {}; - char description[512] = {}; - memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size()); - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - return s; -} - -auto System::unserialize(serializer& s) -> bool { - uint signature = 0; - char version[16] = {}; - char description[512] = {}; - - s.integer(signature); - s.array(version); - s.array(description); - - if(signature != 0x31545342) return false; - if(string{version} != Emulator::SerializerVersion) return false; - - power(); - serializeAll(s); - return true; -} - -auto System::serializeAll(serializer& s) -> void { - system.serialize(s); - cartridge.serialize(s); - cpu.serialize(s); - vdp.serialize(s); - psg.serialize(s); -} - -auto System::serialize(serializer& s) -> void { -} diff --git a/higan/msx/system/system.cpp b/higan/msx/system/system.cpp deleted file mode 100644 index 5a5d3a81..00000000 --- a/higan/msx/system/system.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include - -namespace MSX { - -System system; -Scheduler scheduler; -Cheat cheat; -#include "serialization.cpp" - -auto System::run() -> void { - if(scheduler.enter() == Scheduler::Event::Frame) { - vdp.refresh(); - } -} - -auto System::runToSave() -> void { - scheduler.synchronize(cpu); - scheduler.synchronize(vdp); - scheduler.synchronize(psg); -} - -auto System::load(Emulator::Interface* interface, Model model) -> bool { - information = {}; - information.model = model; - - if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else return false; - - auto document = BML::unserialize(information.manifest); - - if(auto memory = document["system/memory(type=ROM,content=BIOS)"]) { - bios.allocate(memory["size"].natural()); - if(auto fp = platform->open(ID::System, "bios.rom", File::Read, File::Required)) { - bios.load(fp); - } else return false; - } else return false; - - if(!cartridge.load()) return false; - - if(cartridge.region() == "NTSC") { - information.region = Region::NTSC; - information.colorburst = Emulator::Constants::Colorburst::NTSC; - } - if(cartridge.region() == "PAL") { - information.region = Region::PAL; - information.colorburst = Emulator::Constants::Colorburst::PAL; - } - - this->interface = interface; - return information.loaded = true; -} - -auto System::save() -> void { - cartridge.save(); -} - -auto System::unload() -> void { - cartridge.unload(); -} - -auto System::power() -> void { - Emulator::video.reset(interface); - Emulator::video.setPalette(); - - Emulator::audio.reset(interface); - - scheduler.reset(); - cartridge.power(); - cpu.power(); - vdp.power(); - psg.power(); - scheduler.primary(cpu); -} - -} diff --git a/higan/msx/system/system.hpp b/higan/msx/system/system.hpp deleted file mode 100644 index ee4e4db6..00000000 --- a/higan/msx/system/system.hpp +++ /dev/null @@ -1,50 +0,0 @@ -struct System { - enum class Model : uint { MSX, MSX2, MSX2Plus, MSXTurboR }; - enum class Region : uint { NTSC, PAL }; - - auto loaded() const -> bool { return information.loaded; } - auto model() const -> Model { return information.model; } - auto region() const -> Region { return information.region; } - auto colorburst() const -> double { return information.colorburst; } - - //system.cpp - auto run() -> void; - auto runToSave() -> void; - - auto load(Emulator::Interface*, Model) -> bool; - auto save() -> void; - auto unload() -> void; - - auto power() -> void; - - //serialization.cpp - auto serializeInit() -> void; - auto serialize() -> serializer; - auto unserialize(serializer&) -> bool; - auto serializeAll(serializer&) -> void; - auto serialize(serializer&) -> void; - - Emulator::Memory::Readable bios; - -private: - Emulator::Interface* interface = nullptr; - - struct Information { - bool loaded = false; - Model model = Model::MSX; - Region region = Region::NTSC; - double colorburst = Emulator::Constants::Colorburst::NTSC; - string manifest; - uint serializeSize = 0; - } information; -}; - -extern System system; - -auto Model::MSX() -> bool { return system.model() == System::Model::MSX; } -auto Model::MSX2() -> bool { return system.model() == System::Model::MSX2; } -auto Model::MSX2Plus() -> bool { return system.model() == System::Model::MSX2Plus; } -auto Model::MSXTurboR() -> bool { return system.model() == System::Model::MSXTurboR; } - -auto Region::NTSC() -> bool { return system.region() == System::Region::NTSC; } -auto Region::PAL() -> bool { return system.region() == System::Region::PAL; } diff --git a/higan/msx/vdp/background.cpp b/higan/msx/vdp/background.cpp deleted file mode 100644 index 771cc649..00000000 --- a/higan/msx/vdp/background.cpp +++ /dev/null @@ -1,73 +0,0 @@ -auto VDP::background(uint8 hoffset, uint8 voffset) -> void { - if(!io.displayEnable) { - output.color = io.colorBackground; - return; - } - - switch(io.videoMode) { - case 0: return graphics1(hoffset, voffset); -//case 1: return text1(hoffset, voffset); - case 2: return graphics2(hoffset, voffset); - case 3: return multicolor(hoffset, voffset); - default: output.color = 8; return; //medium red color to identify unimplemented modes - } -} - -auto VDP::text1(uint8 hoffset, uint8 voffset) -> void { -} - -auto VDP::graphics1(uint8 hoffset, uint8 voffset) -> void { - uint14 nameAddress; - nameAddress.bits( 0, 4) = hoffset.bits(3,7); - nameAddress.bits( 5, 9) = voffset.bits(3,7); - nameAddress.bits(10,13) = io.nameTableAddress; - - uint8 pattern = vram.read(nameAddress); - - uint14 patternAddress; - patternAddress.bits( 0, 2) = voffset.bits(0,2); - patternAddress.bits( 3,10) = pattern; - patternAddress.bits(11,13) = io.patternTableAddress; - - uint14 colorAddress; //d5 = 0 - colorAddress.bits(0, 4) = pattern.bits(3,7); - colorAddress.bits(6,13) = io.colorTableAddress; - - uint8 color = vram.read(colorAddress); - uint3 index = hoffset ^ 7; - if(!vram.read(patternAddress).bit(index)) { - output.color = color.bits(0,3); - } else { - output.color = color.bits(4,7); - } -} - -auto VDP::graphics2(uint8 hoffset, uint8 voffset) -> void { - uint14 nameAddress; - nameAddress.bits( 0, 4) = hoffset.bits(3,7); - nameAddress.bits( 5, 9) = voffset.bits(3,7); - nameAddress.bits(10,13) = io.nameTableAddress; - - uint8 pattern = vram.read(nameAddress); - - uint14 patternAddress; - patternAddress.bits(0, 2) = voffset.bits(0,2); - patternAddress.bits(3,10) = pattern; - if(voffset >= 64 && voffset <= 127) patternAddress.bit(11) = io.patternTableAddress.bit(0); - if(voffset >= 128 && voffset <= 191) patternAddress.bit(12) = io.patternTableAddress.bit(1); - uint14 colorAddress = patternAddress; - patternAddress.bit(13) = io.patternTableAddress.bit(2); - colorAddress.bit(13) = io.colorTableAddress.bit(7); - - uint8 colorMask = io.colorTableAddress.bits(0,6) << 1 | 1; - uint8 color = vram.read(colorAddress); - uint3 index = hoffset ^ 7; - if(!vram.read(patternAddress).bit(index)) { - output.color = color.bits(0,3); - } else { - output.color = color.bits(4,7); - } -} - -auto VDP::multicolor(uint8 hoffset, uint8 voffset) -> void { -} diff --git a/higan/msx/vdp/io.cpp b/higan/msx/vdp/io.cpp deleted file mode 100644 index 51b3d187..00000000 --- a/higan/msx/vdp/io.cpp +++ /dev/null @@ -1,79 +0,0 @@ -auto VDP::status() -> uint8 { - io.controlLatch = 0; - uint8 data = 0x00; - data.bits(0,4) = io.spriteOverflowIndex; - data.bit(5) = io.spriteCollision; - data.bit(6) = io.spriteOverflow; - data.bit(7) = io.irqLine; - io.irqLine = 0; - return data; -} - -auto VDP::data() -> uint8 { - io.controlLatch = 0; - uint8 data = io.vramLatch; - uint14 address = io.controlValue.bits(0,13)++; - io.vramLatch = vram.read(address); - return data; -} - -auto VDP::data(uint8 data) -> void { - io.controlLatch = 0; - uint14 address = io.controlValue.bits(0,13)++; - vram.write(address, data); -} - -auto VDP::control(uint8 data) -> void { - if(io.controlLatch == 0) { - io.controlLatch = 1; - io.controlValue.byte(0) = data; - return; - } else { - io.controlLatch = 0; - io.controlValue.byte(1) = data; - } - - if(!io.controlValue.bit(15)) { - if(!io.controlValue.bit(14)) { - uint14 address = io.controlValue.bits(0,13)++; - io.vramLatch = vram.read(address); - } - return; - } - - data = io.controlValue.bits(0,7); - switch(io.controlValue.bits(8,10)) { - case 0: - io.externalInput = data.bit(0); - io.videoMode.bit(1) = data.bit(1); - break; - case 1: - io.spriteZoom = data.bit(0); - io.spriteSize = data.bit(1); - io.videoMode.bit(2) = data.bit(3); - io.videoMode.bit(0) = data.bit(4); - io.irqEnable = data.bit(5); - io.displayEnable = data.bit(6); - io.ramMode = data.bit(7); - break; - case 2: - io.nameTableAddress = data.bits(0,3); - break; - case 3: - io.colorTableAddress = data.bits(0,7); - break; - case 4: - io.patternTableAddress = data.bits(0,2); - break; - case 5: - io.spriteAttributeTableAddress = data.bits(0,6); - break; - case 6: - io.spritePatternTableAddress = data.bits(0,2); - break; - case 7: - io.colorBackground = data.bits(0,3); - io.colorForeground = data.bits(4,7); - break; - } -} diff --git a/higan/msx/vdp/serialization.cpp b/higan/msx/vdp/serialization.cpp deleted file mode 100644 index 53702022..00000000 --- a/higan/msx/vdp/serialization.cpp +++ /dev/null @@ -1,3 +0,0 @@ -auto VDP::serialize(serializer& s) -> void { - Thread::serialize(s); -} diff --git a/higan/msx/vdp/sprites.cpp b/higan/msx/vdp/sprites.cpp deleted file mode 100644 index 0767a8a1..00000000 --- a/higan/msx/vdp/sprites.cpp +++ /dev/null @@ -1,58 +0,0 @@ -auto VDP::sprite(uint8 voffset) -> void { - uint valid = 0; - uint limit = io.spriteSize ? 15 : 7; - for(uint index : range(4)) sprites[index].y = 0xd0; - - uint14 attributeAddress; - attributeAddress.bits(7,13) = io.spriteAttributeTableAddress; - for(uint index : range(32)) { - uint8 y = vram.read(attributeAddress++); - if(y == 0xd0) break; - - uint8 x = vram.read(attributeAddress++); - uint8 pattern = vram.read(attributeAddress++); - uint8 extra = vram.read(attributeAddress++); - - if(extra.bit(7)) x -= 32; - y += 1; - if(voffset < y) continue; - if(voffset > y + limit) continue; - - if(limit == 15) pattern.bits(0,1) = 0; - - if(valid == 4) { - io.spriteOverflow = true; - io.spriteOverflowIndex = index; - break; - } - - sprites[valid++] = {x, y, pattern, extra.bits(0,3)}; - } -} - -auto VDP::sprite(uint8 hoffset, uint8 voffset) -> void { - uint4 color; - uint limit = io.spriteSize ? 15 : 7; - - for(uint n : range(4)) { - auto& o = sprites[n]; - if(o.y == 0xd0) continue; - if(hoffset < o.x) continue; - if(hoffset > o.x + limit) continue; - - uint x = hoffset - o.x; - uint y = voffset - o.y; - - uint14 address; - address.bits( 0,10) = (o.pattern << 3) + (x >> 3 << 4) + (y & limit); - address.bits(11,13) = io.spritePatternTableAddress; - - uint3 index = x ^ 7; - if(vram.read(address).bit(index)) { - if(color) { io.spriteCollision = true; break; } - color = o.color; - } - } - - if(color) output.color = color; -} diff --git a/higan/msx/vdp/vdp.cpp b/higan/msx/vdp/vdp.cpp deleted file mode 100644 index 61977f7b..00000000 --- a/higan/msx/vdp/vdp.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include - -//456 clocks/scanline - -namespace MSX { - -VDP vdp; -#include "io.cpp" -#include "background.cpp" -#include "sprites.cpp" -#include "serialization.cpp" - -auto VDP::Enter() -> void { - while(true) scheduler.synchronize(), vdp.main(); -} - -auto VDP::main() -> void { - if(io.vcounter < 192) { - uint8 y = io.vcounter; - sprite(y); - auto line = buffer + y * 256; - for(uint8 x : range(256)) { - background(x, y); - sprite(x, y); - line[x] = output.color; - step(1); - } - step(200); - } else { - step(456); - } - - io.vcounter++; - if(io.vcounter == 262) io.vcounter = 0; - if(io.vcounter == 0) io.irqLine = 0; - if(io.vcounter == 192) io.irqLine = 1, scheduler.exit(Scheduler::Event::Frame); -} - -auto VDP::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); -} - -auto VDP::refresh() -> void { - Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 192); -} - -auto VDP::power() -> void { - create(VDP::Enter, system.colorburst() * 2); - vram.allocate(0x4000); - - io = {}; -} - -} diff --git a/higan/msx/vdp/vdp.hpp b/higan/msx/vdp/vdp.hpp deleted file mode 100644 index 42fa2fe8..00000000 --- a/higan/msx/vdp/vdp.hpp +++ /dev/null @@ -1,78 +0,0 @@ -//Texas Instruments TMS9918A - -struct VDP : Thread { - //vdp.cpp - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - auto refresh() -> void; - - auto power() -> void; - - //io.cpp - auto status() -> uint8; - auto data() -> uint8; - - auto data(uint8) -> void; - auto control(uint8) -> void; - - //background.cpp - auto background(uint8 hoffset, uint8 voffset) -> void; - auto text1(uint8 hoffset, uint8 voffset) -> void; - auto graphics1(uint8 hoffset, uint8 voffset) -> void; - auto graphics2(uint8 hoffset, uint8 voffset) -> void; - auto multicolor(uint8 hoffset, uint8 voffset) -> void; - - //sprites.cpp - auto sprite(uint8 voffset) -> void; - auto sprite(uint8 hoffset, uint8 voffset) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - uint32 buffer[256 * 192]; - Emulator::Memory::Writable vram; - - struct IO { - uint vcounter = 0; - uint hcounter = 0; - - uint1 controlLatch; - uint16 controlValue; - uint8 vramLatch; - - uint5 spriteOverflowIndex; - uint1 spriteCollision; - uint1 spriteOverflow; - uint1 irqLine; - - uint1 externalInput; - uint3 videoMode; - uint1 spriteZoom; - uint1 spriteSize; - uint1 irqEnable; - uint1 displayEnable; - uint1 ramMode = 1; //0 = 4KB; 1 = 16KB - uint4 nameTableAddress; - uint8 colorTableAddress; - uint3 patternTableAddress; - uint7 spriteAttributeTableAddress; - uint3 spritePatternTableAddress; - uint4 colorBackground; - uint4 colorForeground; - } io; - - struct Sprite { - uint8 x; - uint8 y; - uint8 pattern; - uint4 color; - } sprites[4]; - - struct Output { - uint4 color; - } output; -}; - -extern VDP vdp; diff --git a/higan/ngp/GNUmakefile b/higan/ngp/GNUmakefile deleted file mode 100644 index 17a56543..00000000 --- a/higan/ngp/GNUmakefile +++ /dev/null @@ -1,12 +0,0 @@ -processors += tlcs900h z80 - -objects += ngp-interface ngp-system ngp-cartridge -objects += ngp-cpu ngp-apu ngp-vpu ngp-psg - -obj/ngp-interface.o: ngp/interface/interface.cpp -obj/ngp-system.o: ngp/system/system.cpp -obj/ngp-cartridge.o: ngp/cartridge/cartridge.cpp -obj/ngp-cpu.o: ngp/cpu/cpu.cpp -obj/ngp-apu.o: ngp/apu/apu.cpp -obj/ngp-vpu.o: ngp/vpu/vpu.cpp -obj/ngp-psg.o: ngp/psg/psg.cpp diff --git a/higan/ngp/apu/apu.cpp b/higan/ngp/apu/apu.cpp deleted file mode 100644 index 11009c19..00000000 --- a/higan/ngp/apu/apu.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include - -namespace NeoGeoPocket { - -APU apu; -#include "serialization.cpp" - -auto APU::Enter() -> void { - while(true) scheduler.synchronize(), apu.main(); -} - -auto APU::main() -> void { - step(1); -} - -auto APU::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); -} - -auto APU::synchronizing() const -> bool { - return scheduler.synchronizing(); -} - -auto APU::power() -> void { - Z80::bus = this; - Z80::power(); - bus->grant(false); - create(APU::Enter, system.frequency() / 2.0); - ram.allocate(0x1000); -} - -} diff --git a/higan/ngp/apu/apu.hpp b/higan/ngp/apu/apu.hpp deleted file mode 100644 index 8c45f449..00000000 --- a/higan/ngp/apu/apu.hpp +++ /dev/null @@ -1,22 +0,0 @@ -struct APU : Processor::Z80, Processor::Z80::Bus, Thread { - Emulator::Memory::Writable ram; - - //apu.cpp - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void override; - auto synchronizing() const -> bool override; - auto power() -> void; - - //memory.cpp - auto read(uint16 address) -> uint8 override { return 0; } - auto write(uint16 address, uint8 data) -> void override {} - - auto in(uint8 address) -> uint8 override { return 0; } - auto out(uint8 address, uint8 data) -> void override {} - - //serialization.cpp - auto serialize(serializer&) -> void; -}; - -extern APU apu; diff --git a/higan/ngp/apu/serialization.cpp b/higan/ngp/apu/serialization.cpp deleted file mode 100644 index e7aaa581..00000000 --- a/higan/ngp/apu/serialization.cpp +++ /dev/null @@ -1,5 +0,0 @@ -auto APU::serialize(serializer& s) -> void { - Z80::serialize(s); - Z80::Bus::serialize(s); - Thread::serialize(s); -} diff --git a/higan/ngp/cartridge/cartridge.cpp b/higan/ngp/cartridge/cartridge.cpp deleted file mode 100644 index d9183a7a..00000000 --- a/higan/ngp/cartridge/cartridge.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include - -namespace NeoGeoPocket { - -Cartridge cartridge; -#include "flash.cpp" -#include "serialization.cpp" - -auto Cartridge::load() -> bool { - information = {}; - - if(Model::NeoGeoPocket()) { - if(auto loaded = platform->load(ID::NeoGeoPocket, "Neo Geo Pocket", "ngp")) { - information.pathID = loaded.pathID; - } else return true; //boot into BIOS - } - - if(Model::NeoGeoPocketColor()) { - if(auto loaded = platform->load(ID::NeoGeoPocketColor, "Neo Geo Pocket Color", "ngpc")) { - information.pathID = loaded.pathID; - } else return true; //boot into BIOS - } - - if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else return false; - - auto document = BML::unserialize(information.manifest); - information.title = document["game/label"].text(); - - flash[0].reset(0); - flash[1].reset(1); - - if(auto memory = document["game/board/memory(type=ROM,content=Program)"]) { - auto size = memory["size"].natural(); - flash[0].allocate(min(16_Mibit, size)); - flash[1].allocate(size >= 16_Mibit ? 16_Mibit - size : 0); - if(auto fp = platform->open(pathID(), "program.rom", File::Read, File::Required)) { - flash[0].load(fp); - flash[1].load(fp); - } else return false; - } - - return true; -} - -auto Cartridge::save() -> void { - auto document = BML::unserialize(information.manifest); -} - -auto Cartridge::unload() -> void { - flash[0].reset(0); - flash[1].reset(1); -} - -auto Cartridge::power() -> void { - flash[0].power(); - flash[1].power(); -} - -auto Cartridge::read(uint1 chip, uint21 address) -> uint8 { - if(!flash[0]) return 0xff; - if(!flash[1]) chip = 0; - return flash[chip].read(address); -} - -auto Cartridge::write(uint1 chip, uint21 address, uint8 data) -> void { - if(!flash[0]) return; - if(!flash[1]) chip = 0; - return flash[chip].write(address, data); -} - -} diff --git a/higan/ngp/cartridge/cartridge.hpp b/higan/ngp/cartridge/cartridge.hpp deleted file mode 100644 index bbcafe27..00000000 --- a/higan/ngp/cartridge/cartridge.hpp +++ /dev/null @@ -1,76 +0,0 @@ -//Toshiba 0x98 -//Sharp 0xb0 -//Samsung 0xec - -// 4mbit 0xab -// 8mbit 0x2c -//16mbit 0x2f - -struct Flash { - natural ID; //todo: can this be made const, even though it's declared as Cartridge::Flash[2] ? - - Emulator::Memory::Writable rom; - boolean modified; - uint8 vendorID; - uint8 deviceID; - - struct Block { - boolean writable; - natural offset; - natural length; - }; - vector blocks; - - explicit operator bool() const { return (bool)rom; } - - //flash.cpp - auto reset(natural ID) -> void; - auto allocate(natural size) -> bool; - auto load(vfs::shared::file fp) -> void; - - auto power() -> void; - auto read(uint21 address) -> uint8; - auto write(uint21 address, uint8 data) -> void; - - auto status(uint) -> void; - auto program(uint21 address, uint8 data) -> void; - auto erase(uint6 blockID) -> void; - auto eraseAll() -> void; - auto protect(uint6 blockID) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - enum : uint { Read, Prefix, Suffix, ExtendedPrefix, ExtendedSuffix, ReadID, Write }; - natural mode; -}; - -struct Cartridge { - Flash flash[2]; - - auto pathID() const -> natural { return information.pathID; } - auto hash() const -> string { return information.hash; } - auto manifest() const -> string { return information.manifest; } - auto title() const -> string { return information.title; } - - //cartridge.cpp - auto load() -> bool; - auto save() -> void; - auto unload() -> void; - auto power() -> void; - - auto read(uint1 bank, uint21 address) -> uint8; - auto write(uint1 bank, uint21 address, uint8 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - struct Information { - natural pathID; - string hash; - string manifest; - string title; - } information; -}; - -extern Cartridge cartridge; diff --git a/higan/ngp/cartridge/flash.cpp b/higan/ngp/cartridge/flash.cpp deleted file mode 100644 index 727e4d46..00000000 --- a/higan/ngp/cartridge/flash.cpp +++ /dev/null @@ -1,96 +0,0 @@ -auto Flash::reset(natural ID) -> void { - this->ID = ID; - rom.reset(); - modified = false; - vendorID = 0; - deviceID = 0; - blocks.reset(); -} - -auto Flash::allocate(natural size) -> bool { - if(size == 4_Mibit) { rom.allocate(size); vendorID = 0x98; deviceID = 0xab; } //vendorID 0x98 => Toshiba - if(size == 8_Mibit) { rom.allocate(size); vendorID = 0x98; deviceID = 0x2c; } //vendorID 0xb0 => Sharp - if(size == 16_Mibit) { rom.allocate(size); vendorID = 0x98; deviceID = 0x2f; } //vendorID 0xec => Samsung - if(!size) return false; - - for(uint index : range(size / 64_KiB - 1)) blocks.append({true, index * 64_KiB, 64_KiB}); - blocks.append({true, size - 64_KiB, 32_KiB}); - blocks.append({true, size - 32_KiB, 8_KiB}); - blocks.append({true, size - 24_KiB, 8_KiB}); - blocks.append({true, size - 16_KiB, 16_KiB}); - return true; -} - -auto Flash::load(vfs::shared::file fp) -> void { - fp->read(rom.data(), rom.size()); -} - -auto Flash::power() -> void { - status(Read); -} - -auto Flash::read(uint21 address) -> uint8 { - if(mode == ReadID) { - switch((uint15)address) { //todo: actual mask value unknown - case 0: return vendorID; - case 1: return deviceID; - case 2: return 0x02; //unknown purpose - case 3: return 0x80; //unknown purpose - } - return 0xff; //invalid ReadID address; todo: actual return value unknown - } - return rom.read(address); //todo: what happens when mode != Read here? -} - -auto Flash::write(uint21 address, uint8 data) -> void { - if(mode == Write) return program(address, data); - if(data == 0xf0) return status(Read); - address = (uint15)address; - if(address == 0x5555 && data == 0xaa) return status(Prefix); - if(mode == Prefix && address == 0x2aaa && data == 0x55) return status(Suffix); - if(mode == Suffix && address == 0x5555 && data == 0x90) return status(ReadID); - if(mode == Suffix && address == 0x5555 && data == 0xa0) return status(Write); - if(mode == Suffix && address == 0x5555 && data == 0xf0) return status(Read); - if(mode == Suffix && address == 0x5555 && data == 0x80) return status(ExtendedPrefix); - if(mode == ExtendedPrefix && address == 0x2aaa && data == 0x55) return status(ExtendedSuffix); - if(mode == ExtendedSuffix && address == 0x5555 && data == 0x10) return eraseAll(); - if(mode == ExtendedSuffix && data == 0x30) return erase((uint6)address); - if(mode == ExtendedSuffix && data == 0x90) return protect((uint6)address); - return status(Read); //invalid or unsupported command -} - -auto Flash::status(uint mode_) -> void { - mode = mode_; -} - -auto Flash::program(uint21 address, uint8 data) -> void { - for(auto& block : blocks) { - if(address >= block.offset && address < block.offset + block.length && block.writable) { - if(auto input = rom.read(address); input != (input & data)) { - modified = true; - return rom.write(address, input & data); - } - } - } -} - -auto Flash::erase(uint6 blockID) -> void { - //todo: unknown what happens when erasing invalid block IDs - if(blockID >= blocks.size() || !blocks[blockID].writable) return; - auto address = blocks[blockID].offset; - for(auto offset : range(blocks[blockID].length)) rom.write(address + offset, 0xff); - modified = true; - return status(Read); -} - -auto Flash::eraseAll() -> void { - for(uint blockID : range(blocks.size())) erase(blockID); -} - -auto Flash::protect(uint6 blockID) -> void { - //todo: unknown what happens when protected invalid block IDs - if(blockID >= blocks.size() || !blocks[blockID].writable) return; - blocks[blockID].writable = false; - modified = true; - return status(Read); -} diff --git a/higan/ngp/cartridge/serialization.cpp b/higan/ngp/cartridge/serialization.cpp deleted file mode 100644 index 139f92e3..00000000 --- a/higan/ngp/cartridge/serialization.cpp +++ /dev/null @@ -1,10 +0,0 @@ -auto Flash::serialize(serializer& s) -> void { - rom.serialize(s); - s.integer(vendorID); - s.integer(deviceID); -} - -auto Cartridge::serialize(serializer& s) -> void { - flash[0].serialize(s); - flash[1].serialize(s); -} diff --git a/higan/ngp/cpu/cpu.cpp b/higan/ngp/cpu/cpu.cpp deleted file mode 100644 index 874d26e9..00000000 --- a/higan/ngp/cpu/cpu.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include - -namespace NeoGeoPocket { - -CPU cpu; -#include "memory.cpp" -#include "serialization.cpp" - -auto CPU::Enter() -> void { - while(true) scheduler.synchronize(), cpu.main(); -} - -auto CPU::main() -> void { -static uint ctr=0; -if(++ctr<200) print(disassemble(), "\n"); - instruction(); - step(1); -} - -auto CPU::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(vpu); - synchronize(apu); - synchronize(psg); -} - -auto CPU::power() -> void { - TLCS900H::power(); - create(CPU::Enter, system.frequency()); - ram.allocate(0x3000); - r.pc.l.l0 = 0xff1800; - io = {}; -} - -auto CPU::setInterruptHblank(boolean line) -> void { - io.irq.hblank = line; -//if(line) interrupt(0xffff0c); -} - -auto CPU::setInterruptVblank(boolean line) -> void { - io.irq.vblank = line; - if(line) interrupt(0xffff10); -} - -} diff --git a/higan/ngp/cpu/cpu.hpp b/higan/ngp/cpu/cpu.hpp deleted file mode 100644 index 7f2ae3fe..00000000 --- a/higan/ngp/cpu/cpu.hpp +++ /dev/null @@ -1,29 +0,0 @@ -struct CPU : Processor::TLCS900H, Thread { - Emulator::Memory::Writable ram; - - //cpu.cpp - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void override; - auto power() -> void; - - auto setInterruptHblank(boolean line) -> void; - auto setInterruptVblank(boolean line) -> void; - - //memory.cpp - auto read(uint24 address) -> uint8 override; - auto write(uint24 address, uint8 data) -> void override; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - struct IO { - struct IRQ { - boolean hblank; - boolean vblank; - } irq; - } io; -}; - -extern CPU cpu; diff --git a/higan/ngp/cpu/memory.cpp b/higan/ngp/cpu/memory.cpp deleted file mode 100644 index 969f507e..00000000 --- a/higan/ngp/cpu/memory.cpp +++ /dev/null @@ -1,27 +0,0 @@ -auto CPU::read(uint24 address) -> uint8 { - if(address < 0x000100) return 0xff; - if(address < 0x004000) return 0xff; - if(address < 0x007000) return cpu.ram.read((uint14)address); - if(address < 0x008000) return apu.ram.read((uint12)address); - if(address < 0x00c000) return vpu.ram.read((uint14)address); - if(address < 0x200000) return 0xff; - if(address < 0x400000) return cartridge.read(0, (uint21)address); - if(address < 0x800000) return 0xff; - if(address < 0xa00000) return cartridge.read(1, (uint21)address); - if(address < 0xff0000) return 0xff; - return system.bios.read((uint16)address); -} - -auto CPU::write(uint24 address, uint8 data) -> void { - if(address < 0x000100) return; - if(address < 0x004000) return; - if(address < 0x007000) return cpu.ram.write((uint14)address, data); - if(address < 0x008000) return apu.ram.write((uint12)address, data); - if(address < 0x00c000) return vpu.ram.write((uint14)address, data); - if(address < 0x200000) return; - if(address < 0x400000) return cartridge.write(0, (uint21)address, data); - if(address < 0x800000) return; - if(address < 0xa00000) return cartridge.write(1, (uint21)address, data); - if(address < 0xff0000) return; - return system.bios.write((uint16)address, data); -} diff --git a/higan/ngp/cpu/serialization.cpp b/higan/ngp/cpu/serialization.cpp deleted file mode 100644 index a46fa754..00000000 --- a/higan/ngp/cpu/serialization.cpp +++ /dev/null @@ -1,4 +0,0 @@ -auto CPU::serialize(serializer& s) -> void { - TLCS900H::serialize(s); - Thread::serialize(s); -} diff --git a/higan/ngp/interface/interface.cpp b/higan/ngp/interface/interface.cpp deleted file mode 100644 index ed4ba344..00000000 --- a/higan/ngp/interface/interface.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include - -namespace NeoGeoPocket { - -#include "neo-geo-pocket.cpp" -#include "neo-geo-pocket-color.cpp" - -//todo: add correct values -auto Interface::display() -> Display { - Display display; - display.type = Display::Type::LCD; - display.colors = 1 << 12; - display.width = 160; - display.height = 152; - display.internalWidth = 160; - display.internalHeight = 152; - display.aspectCorrection = 1.0; - return display; -} - -auto Interface::color(uint32 color) -> uint64 { - uint b = color.bits(0, 3); - uint g = color.bits(4, 7); - uint r = color.bits(8,11); - - natural R = image::normalize(r, 4, 16); - natural G = image::normalize(g, 4, 16); - natural B = image::normalize(b, 4, 16); - - return R << 32 | G << 16 | B << 0; -} - -auto Interface::loaded() -> bool { - return system.loaded(); -} - -auto Interface::hashes() -> vector { - return {cartridge.hash()}; -} - -auto Interface::manifests() -> vector { - return {cartridge.manifest()}; -} - -auto Interface::titles() -> vector { - return {cartridge.title()}; -} - -auto Interface::save() -> void { -} - -auto Interface::unload() -> void { - save(); -} - -auto Interface::ports() -> vector { return { - {ID::Port::Hardware, "Hardware"}}; -} - -auto Interface::devices(uint port) -> vector { - if(port == ID::Port::Hardware) return { - {ID::Device::Controls, "Controls"} - }; - - return {}; -} - -auto Interface::inputs(uint device) -> vector { - using Type = Input::Type; - - if(device == ID::Device::Controls) return { - {Type::Hat, "Up" }, - {Type::Hat, "Down" }, - {Type::Hat, "Left" }, - {Type::Hat, "Right" }, - {Type::Button, "A" }, - {Type::Button, "B" }, - {Type::Control, "Option"} - }; - - return {}; -} - -auto Interface::power() -> void { - system.power(); -} - -auto Interface::run() -> void { - system.run(); -} - -auto Interface::serialize() -> serializer { - system.runToSave(); - return system.serialize(); -} - -auto Interface::unserialize(serializer& s) -> bool { - return system.unserialize(s); -} - -} diff --git a/higan/ngp/interface/interface.hpp b/higan/ngp/interface/interface.hpp deleted file mode 100644 index 0db16a28..00000000 --- a/higan/ngp/interface/interface.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#if defined(CORE_NGP) - -namespace NeoGeoPocket { - -struct ID { - enum : uint { - System, - NeoGeoPocket, - NeoGeoPocketColor, - }; - - struct Port { enum : uint { - Hardware, - };}; - - struct Device { enum : uint { - Controls, - };}; -}; - -struct Interface : Emulator::Interface { - auto display() -> Display override; - auto color(uint32 color) -> uint64 override; - - auto loaded() -> bool override; - auto hashes() -> vector override; - auto manifests() -> vector override; - auto titles() -> vector override; - auto save() -> void override; - auto unload() -> void override; - - auto ports() -> vector override; - auto devices(uint port) -> vector override; - auto inputs(uint device) -> vector override; - - auto power() -> void override; - auto run() -> void override; - - auto serialize() -> serializer override; - auto unserialize(serializer&) -> bool override; -}; - -struct NeoGeoPocketInterface : Interface { - auto information() -> Information override; - - auto load() -> bool override; -}; - -struct NeoGeoPocketColorInterface : Interface { - auto information() -> Information override; - - auto load() -> bool override; -}; - -} - -#endif diff --git a/higan/ngp/interface/neo-geo-pocket-color.cpp b/higan/ngp/interface/neo-geo-pocket-color.cpp deleted file mode 100644 index 0942861e..00000000 --- a/higan/ngp/interface/neo-geo-pocket-color.cpp +++ /dev/null @@ -1,11 +0,0 @@ -auto NeoGeoPocketColorInterface::information() -> Information { - Information information; - information.manufacturer = "SNK"; - information.name = "Neo Geo Pocket Color"; - information.extension = "ngpc"; - return information; -} - -auto NeoGeoPocketColorInterface::load() -> bool { - return system.load(this, System::Model::NeoGeoPocketColor); -} diff --git a/higan/ngp/interface/neo-geo-pocket.cpp b/higan/ngp/interface/neo-geo-pocket.cpp deleted file mode 100644 index 1e8d37ec..00000000 --- a/higan/ngp/interface/neo-geo-pocket.cpp +++ /dev/null @@ -1,11 +0,0 @@ -auto NeoGeoPocketInterface::information() -> Information { - Information information; - information.manufacturer = "SNK"; - information.name = "Neo Geo Pocket"; - information.extension = "ngp"; - return information; -} - -auto NeoGeoPocketInterface::load() -> bool { - return system.load(this, System::Model::NeoGeoPocket); -} diff --git a/higan/ngp/ngp.hpp b/higan/ngp/ngp.hpp deleted file mode 100644 index eb9fcd3d..00000000 --- a/higan/ngp/ngp.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -//license: GPLv3 -//started: 2019-01-03 - -#include -#include -#include -#include - -#include -#include - -namespace NeoGeoPocket { - #define platform Emulator::platform - namespace File = Emulator::File; - using Scheduler = Emulator::Scheduler; - using Cheat = Emulator::Cheat; - extern Scheduler scheduler; - extern Cheat cheat; - - struct Thread : Emulator::Thread { - auto create(auto (*entrypoint)() -> void, double frequency) -> void { - Emulator::Thread::create(entrypoint, frequency); - scheduler.append(*this); - } - - inline auto synchronize(Thread& thread) -> void { - if(clock() >= thread.clock()) scheduler.resume(thread); - } - }; - - struct Model { - inline static auto NeoGeoPocket() -> bool; - inline static auto NeoGeoPocketColor() -> bool; - }; - - #include - #include - #include - #include - #include - #include -} - -#include diff --git a/higan/ngp/psg/psg.cpp b/higan/ngp/psg/psg.cpp deleted file mode 100644 index c43f00d8..00000000 --- a/higan/ngp/psg/psg.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include - -namespace NeoGeoPocket { - -PSG psg; -#include "serialization.cpp" - -auto PSG::Enter() -> void { - while(true) scheduler.synchronize(), psg.main(); -} - -auto PSG::main() -> void { - stream->sample(0.0); - step(1); -} - -auto PSG::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); -} - -auto PSG::power() -> void { - create(PSG::Enter, system.frequency() / 2.0); - stream = Emulator::audio.createStream(1, frequency()); - stream->addHighPassFilter(20.0, Emulator::Filter::Order::First); - stream->addDCRemovalFilter(); -} - -} diff --git a/higan/ngp/psg/psg.hpp b/higan/ngp/psg/psg.hpp deleted file mode 100644 index d30c6e37..00000000 --- a/higan/ngp/psg/psg.hpp +++ /dev/null @@ -1,16 +0,0 @@ -//Texas Instruments SN76489A - -struct PSG : Thread { - shared_pointer stream; - - //psg.cpp - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; -}; - -extern PSG psg; diff --git a/higan/ngp/psg/serialization.cpp b/higan/ngp/psg/serialization.cpp deleted file mode 100644 index 80bf3879..00000000 --- a/higan/ngp/psg/serialization.cpp +++ /dev/null @@ -1,3 +0,0 @@ -auto PSG::serialize(serializer& s) -> void { - Thread::serialize(s); -} diff --git a/higan/ngp/system/serialization.cpp b/higan/ngp/system/serialization.cpp deleted file mode 100644 index 46829eee..00000000 --- a/higan/ngp/system/serialization.cpp +++ /dev/null @@ -1,59 +0,0 @@ -auto System::serializeInit() -> void { - serializer s; - - uint signature = 0; - char version[16] = {}; - char description[512] = {}; - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - information.serializeSize = s.size(); -} - -auto System::serialize() -> serializer { - serializer s(information.serializeSize); - - uint signature = 0x31545342; - char version[16] = {}; - char description[512] = {}; - memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size()); - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - return s; -} - -auto System::unserialize(serializer& s) -> bool { - uint signature = 0; - char version[16] = {}; - char description[512] = {}; - - s.integer(signature); - s.array(version); - s.array(description); - - if(signature != 0x31545342) return false; - if(string{version} != Emulator::SerializerVersion) return false; - - power(); - serializeAll(s); - return true; -} - -auto System::serializeAll(serializer& s) -> void { - system.serialize(s); - cartridge.serialize(s); - cpu.serialize(s); - apu.serialize(s); - vpu.serialize(s); - psg.serialize(s); -} - -auto System::serialize(serializer& s) -> void { -} diff --git a/higan/ngp/system/system.cpp b/higan/ngp/system/system.cpp deleted file mode 100644 index 0a488131..00000000 --- a/higan/ngp/system/system.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include - -namespace NeoGeoPocket { - -System system; -Scheduler scheduler; -Cheat cheat; -#include "serialization.cpp" - -auto System::run() -> void { - if(scheduler.enter() == Scheduler::Event::Frame) { - vpu.refresh(); - } -} - -auto System::runToSave() -> void { - scheduler.synchronize(cpu); - scheduler.synchronize(apu); - scheduler.synchronize(vpu); - scheduler.synchronize(psg); -} - -auto System::load(Emulator::Interface* interface_, Model model_) -> bool { - information.model = model_; - - if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else return false; - - auto document = BML::unserialize(information.manifest); - if(auto memory = document["system/bios"]) { - bios.allocate(memory["size"].natural()); - if(auto fp = platform->open(ID::System, memory["name"].text(), File::Read, File::Required)) { - bios.load(fp); - } else return false; - } else return false; - - if(model() == Model::NeoGeoPocket) { - } - - if(model() == Model::NeoGeoPocketColor) { - } - - if(!cartridge.load()) return false; - serializeInit(); - interface = interface_; - return information.loaded = true; -} - -auto System::save() -> void { - if(!loaded()) return; - cartridge.save(); -} - -auto System::unload() -> void { - if(!loaded()) return; - bios.reset(); - cartridge.unload(); - information.loaded = false; -} - -auto System::power() -> void { - Emulator::video.reset(interface); - Emulator::video.setPalette(); - Emulator::audio.reset(interface); - - scheduler.reset(); - cartridge.power(); - cpu.power(); - apu.power(); - vpu.power(); - psg.power(); - scheduler.primary(cpu); -} - -} diff --git a/higan/ngp/system/system.hpp b/higan/ngp/system/system.hpp deleted file mode 100644 index ecd99a36..00000000 --- a/higan/ngp/system/system.hpp +++ /dev/null @@ -1,38 +0,0 @@ -struct System { - enum class Model : uint { NeoGeoPocket, NeoGeoPocketColor }; - Emulator::Memory::Readable bios; - - inline auto loaded() const -> bool { return information.loaded; } - inline auto model() const -> Model { return information.model; } - inline auto frequency() const -> double { return 6'144'000; } - - //system.cpp - auto run() -> void; - auto runToSave() -> void; - auto load(Emulator::Interface*, Model) -> bool; - auto save() -> void; - auto unload() -> void; - auto power() -> void; - - //serialization.cpp - auto serializeInit() -> void; - auto serialize() -> serializer; - auto unserialize(serializer&) -> bool; - auto serializeAll(serializer&) -> void; - auto serialize(serializer&) -> void; - - struct Information { - string manifest; - bool loaded = false; - Model model = Model::NeoGeoPocket; - natural serializeSize; - } information; - -private: - Emulator::Interface* interface = nullptr; -}; - -extern System system; - -auto Model::NeoGeoPocket() -> bool { return system.model() == System::Model::NeoGeoPocket; } -auto Model::NeoGeoPocketColor() -> bool { return system.model() == System::Model::NeoGeoPocketColor; } diff --git a/higan/ngp/vpu/serialization.cpp b/higan/ngp/vpu/serialization.cpp deleted file mode 100644 index ed0a7d5e..00000000 --- a/higan/ngp/vpu/serialization.cpp +++ /dev/null @@ -1,3 +0,0 @@ -auto VPU::serialize(serializer& s) -> void { - Thread::serialize(s); -} diff --git a/higan/ngp/vpu/vpu.cpp b/higan/ngp/vpu/vpu.cpp deleted file mode 100644 index 505cb2f4..00000000 --- a/higan/ngp/vpu/vpu.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include - -namespace NeoGeoPocket { - -VPU vpu; -#include "serialization.cpp" - -auto VPU::Enter() -> void { - while(true) scheduler.synchronize(), vpu.main(); -} - -auto VPU::main() -> void { - cpu.setInterruptHblank(0); - for(uint hclock : range(480)) { - io.hcounter++; - step(1); - } - if(io.vcounter <= 150) { - if(ram[0x0000].bit(6)) cpu.setInterruptHblank(1); - } - for(uint hclock : range(35)) { - io.hcounter++; - step(1); - } - cpu.setInterruptHblank(0); - io.hcounter = 0; - io.vcounter++; - if(io.vcounter == 152) { - ram[0x0010].bit(6) = 1; - if(ram[0x0000].bit(7)) cpu.setInterruptVblank(1); - scheduler.exit(Scheduler::Event::Frame); - } - if(io.vcounter == 198) { - if(ram[0x0000].bit(6)) cpu.setInterruptHblank(1); - } - if(io.vcounter == 199) { - ram[0x0010].bit(6) = 0; - cpu.setInterruptVblank(0); - io.vcounter = 0; - } -} - -auto VPU::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); -} - -auto VPU::refresh() -> void { - for(uint address : range(0x4000)) buffer[address] = ram[address]; - for(uint address : range(0x1f00)) buffer[address + 0x4000] = cpu.ram[address + 0x3000 - 0x1f00]; - Emulator::video.refresh(buffer, 160 * sizeof(uint32), 160, 152); -} - -auto VPU::power() -> void { - create(VPU::Enter, system.frequency()); - ram.allocate(0x4000); - io = {}; -} - -} diff --git a/higan/ngp/vpu/vpu.hpp b/higan/ngp/vpu/vpu.hpp deleted file mode 100644 index f9fa3de5..00000000 --- a/higan/ngp/vpu/vpu.hpp +++ /dev/null @@ -1,26 +0,0 @@ -//K1GE (Neo Geo Pocket) -//K2GE (Neo Geo Pocket Color) - -struct VPU : Thread { - Emulator::Memory::Writable ram; - - //vpu.cpp - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - auto refresh() -> void; - auto power() -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - uint32 buffer[160 * 152]; - - struct IO { - uint8 vcounter; - uint10 hcounter; - } io; -}; - -extern VPU vpu; diff --git a/higan/out/.gitignore b/higan/out/.gitignore deleted file mode 100644 index 35c3356b..00000000 --- a/higan/out/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -higan -bsnes -tomoko diff --git a/higan/pce/GNUmakefile b/higan/pce/GNUmakefile deleted file mode 100644 index d0bd0fc8..00000000 --- a/higan/pce/GNUmakefile +++ /dev/null @@ -1,16 +0,0 @@ -processors += huc6280 - -objects += pce-interface -objects += pce-cpu pce-vpc pce-vce pce-vdc pce-psg -objects += pce-system pce-cartridge -objects += pce-controller - -obj/pce-interface.o: pce/interface/interface.cpp -obj/pce-cpu.o: pce/cpu/cpu.cpp -obj/pce-vpc.o: pce/vpc/vpc.cpp -obj/pce-vce.o: pce/vce/vce.cpp -obj/pce-vdc.o: pce/vdc/vdc.cpp -obj/pce-psg.o: pce/psg/psg.cpp -obj/pce-system.o: pce/system/system.cpp -obj/pce-cartridge.o: pce/cartridge/cartridge.cpp -obj/pce-controller.o: pce/controller/controller.cpp diff --git a/higan/pce/cartridge/cartridge.cpp b/higan/pce/cartridge/cartridge.cpp deleted file mode 100644 index 38f0e991..00000000 --- a/higan/pce/cartridge/cartridge.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include - -namespace PCEngine { - -Cartridge cartridge; - -auto Cartridge::load() -> bool { - information = {}; - - if(Model::PCEngine()) { - if(auto loaded = platform->load(ID::PCEngine, "PC Engine", "pce")) { - information.pathID = loaded.pathID; - } else return false; - } - - if(Model::SuperGrafx()) { - if(auto loaded = platform->load(ID::SuperGrafx, "SuperGrafx", "sg")) { - information.pathID = loaded.pathID; - } else return false; - } - - if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else return false; - - auto document = BML::unserialize(information.manifest); - information.title = document["game/label"].text(); - - if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=ROM,content=Program)"]}) { - rom.size = memory.size; - rom.data = new uint8[rom.size](); - if(auto fp = platform->open(pathID(), memory.name(), File::Read, File::Required)) { - fp->read(rom.data, rom.size); - } - } - - information.sha256 = Hash::SHA256({rom.data, rom.size}).digest(); - return true; -} - -auto Cartridge::save() -> void { - auto document = BML::unserialize(information.manifest); -} - -auto Cartridge::unload() -> void { - delete[] rom.data; - rom = {}; -} - -auto Cartridge::power() -> void { -} - -auto Cartridge::read(uint20 addr) -> uint8 { - if(!rom.size) return 0x00; - return rom.data[mirror(addr, rom.size)]; -} - -auto Cartridge::write(uint20 addr, uint8 data) -> void { -} - -auto Cartridge::mirror(uint addr, uint size) -> uint { - //384KB games have unusual mirroring (only second ROM repeats) - if(size == 0x60000) { - if(addr <= 0x3ffff) return addr; - return 0x40000 + (addr & 0x1ffff); - } - - uint base = 0; - uint mask = 1 << 20; - while(addr >= size) { - while(!(addr & mask)) mask >>= 1; - addr -= mask; - if(size > mask) { - size -= mask; - base += mask; - } - mask >>= 1; - } - return base + addr; -} - -} diff --git a/higan/pce/cartridge/cartridge.hpp b/higan/pce/cartridge/cartridge.hpp deleted file mode 100644 index 613bb0ed..00000000 --- a/higan/pce/cartridge/cartridge.hpp +++ /dev/null @@ -1,34 +0,0 @@ -struct Cartridge { - auto pathID() const -> uint { return information.pathID; } - auto hash() const -> string { return information.sha256; } - auto manifest() const -> string { return information.manifest; } - auto title() const -> string { return information.title; } - - auto load() -> bool; - auto save() -> void; - auto unload() -> void; - - auto power() -> void; - - auto read(uint20 addr) -> uint8; - auto write(uint20 addr, uint8 data) -> void; - -private: - auto mirror(uint addr, uint size) -> uint; - - struct Information { - uint pathID = 0; - string sha256; - string manifest; - string title; - } information; - - struct Memory { - uint8* data = nullptr; - uint size = 0; - }; - - Memory rom; -}; - -extern Cartridge cartridge; diff --git a/higan/pce/controller/controller.cpp b/higan/pce/controller/controller.cpp deleted file mode 100644 index f491b095..00000000 --- a/higan/pce/controller/controller.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include - -namespace PCEngine { - -ControllerPort controllerPort; -#include "gamepad/gamepad.cpp" - -Controller::Controller() { - if(!handle()) create(Controller::Enter, 1); -} - -Controller::~Controller() { - scheduler.remove(*this); -} - -auto Controller::Enter() -> void { - while(true) { - scheduler.synchronize(); - if(controllerPort.device->active()) controllerPort.device->main(); - } -} - -auto Controller::main() -> void { - step(1); - synchronize(cpu); -} - -// - -auto ControllerPort::connect(uint deviceID) -> void { - delete device; - if(!system.loaded()) return; - - switch(deviceID) { default: - case ID::Device::None: device = new Controller; break; - case ID::Device::Gamepad: device = new Gamepad; break; - } - - cpu.peripherals.reset(); - if(auto device = controllerPort.device) cpu.peripherals.append(device); -} - -auto ControllerPort::power() -> void { -} - -auto ControllerPort::unload() -> void { - delete device; - device = nullptr; -} - -auto ControllerPort::serialize(serializer& s) -> void { -} - -} diff --git a/higan/pce/controller/controller.hpp b/higan/pce/controller/controller.hpp deleted file mode 100644 index 919bc36d..00000000 --- a/higan/pce/controller/controller.hpp +++ /dev/null @@ -1,24 +0,0 @@ -struct Controller : Thread { - Controller(); - virtual ~Controller(); - - static auto Enter() -> void; - auto main() -> void; - - virtual auto readData() -> uint4 { return 0x0f; } - virtual auto writeData(uint2) -> void {} -}; - -struct ControllerPort { - auto connect(uint deviceID) -> void; - - auto power() -> void; - auto unload() -> void; - auto serialize(serializer&) -> void; - - Controller* device = nullptr; -}; - -extern ControllerPort controllerPort; - -#include "gamepad/gamepad.hpp" diff --git a/higan/pce/controller/gamepad/gamepad.cpp b/higan/pce/controller/gamepad/gamepad.cpp deleted file mode 100644 index c2fbf782..00000000 --- a/higan/pce/controller/gamepad/gamepad.cpp +++ /dev/null @@ -1,35 +0,0 @@ -Gamepad::Gamepad() { -} - -auto Gamepad::readData() -> uint4 { - if(clr) return 0; - - uint4 data; - - if(sel) { - bool up = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Up); - bool right = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Right); - bool down = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Down); - bool left = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Left); - data.bit(0) = !(up & !down); - data.bit(1) = !(right & !left); - data.bit(2) = !(down & !up); - data.bit(3) = !(left & !right); - } else { - bool one = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, One); - bool two = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Two); - bool select = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Select); - bool run = platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Run); - data.bit(0) = !one; - data.bit(1) = !two; - data.bit(2) = !select; - data.bit(3) = !run; - } - - return data; -} - -auto Gamepad::writeData(uint2 data) -> void { - sel = data.bit(0); - clr = data.bit(1); -} diff --git a/higan/pce/controller/gamepad/gamepad.hpp b/higan/pce/controller/gamepad/gamepad.hpp deleted file mode 100644 index 3db24d20..00000000 --- a/higan/pce/controller/gamepad/gamepad.hpp +++ /dev/null @@ -1,13 +0,0 @@ -struct Gamepad : Controller { - enum : uint { - Up, Down, Left, Right, Two, One, Select, Run, - }; - - Gamepad(); - - auto readData() -> uint4 override; - auto writeData(uint2 data) -> void override; - - bool sel; - bool clr; -}; diff --git a/higan/pce/cpu/cpu.cpp b/higan/pce/cpu/cpu.cpp deleted file mode 100644 index 54ae7630..00000000 --- a/higan/pce/cpu/cpu.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include - -namespace PCEngine { - -CPU cpu; -#include "memory.cpp" -#include "io.cpp" -#include "irq.cpp" -#include "timer.cpp" -#include "serialization.cpp" - -auto CPU::Enter() -> void { - while(true) scheduler.synchronize(), cpu.main(); -} - -auto CPU::main() -> void { - if(irq.pending()) return interrupt(irq.vector()); - instruction(); -} - -auto CPU::step(uint clocks) -> void { - Thread::step(clocks); - timer.step(clocks); - synchronize(vdc0); - synchronize(vdc1); - synchronize(vce); - synchronize(psg); - for(auto peripheral : peripherals) synchronize(*peripheral); -} - -auto CPU::power() -> void { - HuC6280::power(); - create(CPU::Enter, system.colorburst() * 2.0); - - r.pc.byte(0) = read(0x00, 0x1ffe); - r.pc.byte(1) = read(0x00, 0x1fff); - - for(auto& byte : ram) byte = 0x00; - irq = {}; - timer = {}; - io = {}; -} - -auto CPU::lastCycle() -> void { - irq.poll(); -} - -} diff --git a/higan/pce/cpu/cpu.hpp b/higan/pce/cpu/cpu.hpp deleted file mode 100644 index ff676dc1..00000000 --- a/higan/pce/cpu/cpu.hpp +++ /dev/null @@ -1,72 +0,0 @@ -//Hudson Soft HuC6280 - -struct CPU : Processor::HuC6280, Thread { - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void override; - auto power() -> void; - auto lastCycle() -> void override; - - //memory.cpp - auto load() -> void; - auto save() -> void; - - //io.cpp - auto read(uint8 bank, uint13 addr) -> uint8 override; - auto read_(uint8 bank, uint13 addr) -> uint8; - auto write(uint8 bank, uint13 addr, uint8 data) -> void override; - auto store(uint2 addr, uint8 data) -> void override; - - //timer.cpp - auto timerStep(uint clocks) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - - vector peripherals; - -private: - uint8 ram[0x8000]; //PC Engine = 8KB, SuperGrafx = 32KB - uint8 bram[0x800]; //PC Engine CD-ROM Backup RAM = 2KB - - struct IRQ { - //irq.cpp - auto pending() const -> bool; - auto vector() const -> uint16; - auto poll() -> void; - - private: - bool disableExternal = 0; - bool disableVDC = 0; - bool disableTimer = 0; - - bool pendingIRQ = 0; - uint16 pendingVector; - - friend class CPU; - } irq; - - struct Timer { - inline auto irqLine() const { return line; } - - //timer.cpp - auto start() -> void; - auto step(uint clocks) -> void; - - private: - bool enable = 0; - uint7 latch; - uint7 value; - uint clock = 0; - - bool line = 0; - - friend class CPU; - } timer; - - struct IO { - uint8 mdr; - } io; -}; - -extern CPU cpu; diff --git a/higan/pce/cpu/io.cpp b/higan/pce/cpu/io.cpp deleted file mode 100644 index a4da34f2..00000000 --- a/higan/pce/cpu/io.cpp +++ /dev/null @@ -1,203 +0,0 @@ -auto CPU::read(uint8 bank, uint13 addr) -> uint8 { - auto data = read_(bank, addr); - if(auto result = cheat.find(bank << 13 | addr, data)) data = result(); - return data; -} - -auto CPU::read_(uint8 bank, uint13 addr) -> uint8 { - //$00-7f HuCard - if(!bank.bit(7)) { - return cartridge.read(bank << 13 | addr); - } - - //$f7 BRAM - if(bank == 0xf7) { - return bram[addr.bits(0,10)]; - } - - //$f8-fb RAM - if(bank >= 0xf8 && bank <= 0xfb) { - if(Model::PCEngine()) return ram[addr]; - if(Model::SuperGrafx()) return ram[bank.bits(0,1) << 13 | addr]; - } - - //$ff Hardware - if(bank == 0xff) { - //$0000-03ff VDC or VPC - if((addr & 0x1c00) == 0x0000) { - HuC6280::io(); //penalty cycle - if(Model::PCEngine()) return vdc0.read(addr); - if(Model::SuperGrafx()) return vpc.read(addr); - } - - //$0400-07ff VCE - if((addr & 0x1c00) == 0x0400) { - HuC6280::io(); //penalty cycle - return vce.read(addr); - } - - //$0800-0bff PSG - if((addr & 0x1c00) == 0x0800) { - return io.mdr; - } - - //$0c00-0fff Timer - if((addr & 0x1c00) == 0x0c00) { - return (io.mdr & 0x80) | timer.value; - } - - //$1000-13ff I/O - if((addr & 0x1c00) == 0x1000) { - //note 1: Turbografx-16 games check this bit for region protection. - //yet PC Engine games do not. since we cannot tell the games apart, - //it's more compatible to always identify as a Turbografx-16 system. - //note 2: we state that the CD-ROM drive is present. - //this is so games can use its backup RAM for save data. - return ( - controllerPort.device->readData() << 0 - | 1 << 4 - | 1 << 5 - | 0 << 6 //device (0 = Turbografx-16; 1 = PC Engine) - | 0 << 7 //add-on (0 = CD-ROM; 1 = nothing) - ); - } - - //$1400-17ff IRQ - if((addr & 0x1c00) == 0x1400) { - if(addr.bits(0,1) == 0) { - return io.mdr; - } - - if(addr.bits(0,1) == 1) { - return io.mdr; - } - - if(addr.bits(0,1) == 2) { - return ( - irq.disableExternal << 0 - | irq.disableVDC << 1 - | irq.disableTimer << 2 - | (io.mdr & 0xf8) - ); - } - - if(addr.bits(0,1) == 3) { - bool pendingExternal = 0; - bool pendingVDC = vdc0.irqLine() | vdc1.irqLine(); - bool pendingTimer = timer.irqLine(); - return ( - pendingExternal << 0 - | pendingVDC << 1 - | pendingTimer << 2 - | (io.mdr & 0xf8) - ); - } - } - - //$1800-1bff CD-ROM - if((addr & 0x1c00) == 0x1800) { - return 0xff; - } - - //$1c00-1fff unmapped - if((addr & 0x1c00) == 0x1c00) { - return 0xff; - } - } - - return 0xff; -} - -auto CPU::write(uint8 bank, uint13 addr, uint8 data) -> void { - //$00-7f HuCard - if(!bank.bit(7)) { - return cartridge.write(bank << 13 | addr, data); - } - - //$f7 BRAM - if(bank == 0xf7) { - bram[addr.bits(0,10)] = data; - return; - } - - //$f8-fb RAM - if(bank >= 0xf8 && bank <= 0xfb) { - if(Model::PCEngine()) ram[addr] = data; - if(Model::SuperGrafx()) ram[bank.bits(0,1) << 13 | addr] = data; - return; - } - - //$1fe000-1fffff Hardware - if(bank == 0xff) { - //$0000-03ff VDC or VPC - if((addr & 0x1c00) == 0x0000) { - HuC6280::io(); //penalty cycle - if(Model::PCEngine()) return vdc0.write(addr, data); - if(Model::SuperGrafx()) return vpc.write(addr, data); - } - - //$0400-07ff VCE - if((addr & 0x1c00) == 0x0400) { - HuC6280::io(); //penalty cycle - return vce.write(addr, data); - } - - //$0800-0bff PSG - if((addr & 0x1c00) == 0x0800) { - return psg.write(addr, io.mdr = data); - } - - //$0c00-0fff Timer - if((addr & 0x1c00) == 0x0c00) { - io.mdr = data; - if(!addr.bit(0)) { - timer.latch = data.bits(0,6); - } else { - timer.enable = data.bit(0); - if(timer.enable) timer.start(); - } - return; - } - - //$1000-13ff I/O - if((addr & 0x1c00) == 0x1000) { - io.mdr = data; - controllerPort.device->writeData(data.bits(0,1)); - return; - } - - //$1400-17ff IRQ - if((addr & 0x1c00) == 0x1400) { - io.mdr = data; - if(addr.bits(0,1) == 2) { - irq.disableExternal = data.bit(0); - irq.disableVDC = data.bit(1); - irq.disableTimer = data.bit(2); - return; - } - - if(addr.bits(0,1) == 3) { - timer.line = 0; - return; - } - } - - //$1800-1bff CD-ROM - if((addr & 0x1c00) == 0x1800) { - return; - } - - //$1c00-1fff unmapped - if((addr & 0x1c00) == 0x1c00) { - return; - } - } -} - -//ST0, ST1, ST2 -auto CPU::store(uint2 addr, uint8 data) -> void { - HuC6280::io(); //penalty cycle - if(addr) addr++; //0,1,2 => 0,2,3 - if(Model::PCEngine()) vdc0.write(addr, data); - if(Model::SuperGrafx()) vpc.store(addr, data); -} diff --git a/higan/pce/cpu/irq.cpp b/higan/pce/cpu/irq.cpp deleted file mode 100644 index 1f04d530..00000000 --- a/higan/pce/cpu/irq.cpp +++ /dev/null @@ -1,27 +0,0 @@ -auto CPU::IRQ::pending() const -> bool { - return pendingIRQ; -} - -auto CPU::IRQ::vector() const -> uint16 { - return pendingVector; -} - -auto CPU::IRQ::poll() -> void { - pendingIRQ = false; - if(cpu.r.p.i) return; - - if(0) { //external IRQ sources - pendingIRQ = !disableExternal; - pendingVector = 0xfff6; - } - - if(!disableVDC && (vdc0.irqLine() | vdc1.irqLine())) { - pendingIRQ = !disableVDC; - pendingVector = 0xfff8; - } - - if(cpu.timer.irqLine()) { - pendingIRQ = !disableTimer; - pendingVector = 0xfffa; - } -} diff --git a/higan/pce/cpu/memory.cpp b/higan/pce/cpu/memory.cpp deleted file mode 100644 index ced825fa..00000000 --- a/higan/pce/cpu/memory.cpp +++ /dev/null @@ -1,23 +0,0 @@ -//PC Engine HuCards lack save RAM on them due to the card size and cost savings. -//The PC Engine CD adds 2KB of backup RAM that most HuCard games can use for saves. -//However, all games must share this small amount of RAM. -//Since this is an emulator, we can make this process nicer by storing BRAM per-game. - -//This does hard-code the save.ram name, rather than using a manifest file name. -//It also creates a save.ram file no matter what, even for games that don't save data. -//Unfortunately, we can't know in advance if a game supports BRAM saves or not. -//So because of this, we have to always create it. -//Thankfully, the file is very small so it should not prove to be a burden in practice. - -auto CPU::load() -> void { - for(auto& byte : bram) byte = 0xff; - if(auto fp = platform->open(cartridge.pathID(), "save.ram", File::Read)) { - fp->read(bram, 0x800); - } -} - -auto CPU::save() -> void { - if(auto fp = platform->open(cartridge.pathID(), "save.ram", File::Write)) { - fp->write(bram, 0x800); - } -} diff --git a/higan/pce/cpu/serialization.cpp b/higan/pce/cpu/serialization.cpp deleted file mode 100644 index 5c4f2dab..00000000 --- a/higan/pce/cpu/serialization.cpp +++ /dev/null @@ -1,21 +0,0 @@ -auto CPU::serialize(serializer& s) -> void { - HuC6280::serialize(s); - Thread::serialize(s); - - s.array(ram, Model::PCEngine() ? 0x2000 : 0x8000); - s.array(bram); - - s.integer(irq.disableExternal); - s.integer(irq.disableVDC); - s.integer(irq.disableTimer); - s.integer(irq.pendingIRQ); - s.integer(irq.pendingVector); - - s.integer(timer.enable); - s.integer(timer.latch); - s.integer(timer.value); - s.integer(timer.clock); - s.integer(timer.line); - - s.integer(io.mdr); -} diff --git a/higan/pce/cpu/timer.cpp b/higan/pce/cpu/timer.cpp deleted file mode 100644 index 189d2e9a..00000000 --- a/higan/pce/cpu/timer.cpp +++ /dev/null @@ -1,16 +0,0 @@ -auto CPU::Timer::start() -> void { - value = latch; - clock = 0; -} - -auto CPU::Timer::step(uint clocks) -> void { - if(!enable) return; - clock += clocks; - while(clock >= 1024) { - clock -= 1024; - if(!value--) { - value = latch; - line = 1; - } - } -} diff --git a/higan/pce/interface/interface.cpp b/higan/pce/interface/interface.cpp deleted file mode 100644 index 9cf4f42e..00000000 --- a/higan/pce/interface/interface.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include - -namespace PCEngine { - -Model model; -Settings settings; -#include "pc-engine.cpp" -#include "supergrafx.cpp" - -auto Interface::display() -> Display { - Display display; - display.type = Display::Type::CRT; - display.colors = 1 << 9; - display.width = 280; - display.height = 240; - display.internalWidth = 1120; - display.internalHeight = 240; - display.aspectCorrection = 8.0 / 7.0; - return display; -} - -auto Interface::color(uint32 color) -> uint64 { - uint3 B = color.bits(0,2); - uint3 R = color.bits(3,5); - uint3 G = color.bits(6,8); - - uint64 r = image::normalize(R, 3, 16); - uint64 g = image::normalize(G, 3, 16); - uint64 b = image::normalize(B, 3, 16); - - return r << 32 | g << 16 | b << 0; -} - -auto Interface::loaded() -> bool { - return system.loaded(); -} - -auto Interface::hashes() -> vector { - return {cartridge.hash()}; -} - -auto Interface::manifests() -> vector { - return {cartridge.manifest()}; -} - -auto Interface::titles() -> vector { - return {cartridge.title()}; -} - -auto Interface::save() -> void { - system.save(); -} - -auto Interface::unload() -> void { - save(); - system.unload(); -} - -auto Interface::ports() -> vector { return { - {ID::Port::Controller, "Controller"}}; -} - -auto Interface::devices(uint port) -> vector { - if(port == ID::Port::Controller) return { - {ID::Device::Gamepad, "Gamepad"} - }; - - return {}; -} - -auto Interface::inputs(uint device) -> vector { - using Type = Input::Type; - - if(device == ID::Device::Gamepad) return { - {Type::Hat, "Up" }, - {Type::Hat, "Down" }, - {Type::Hat, "Left" }, - {Type::Hat, "Right" }, - {Type::Button, "II" }, - {Type::Button, "I" }, - {Type::Control, "Select"}, - {Type::Control, "Run" } - }; - - return {}; -} - -auto Interface::connected(uint port) -> uint { - if(port == ID::Port::Controller) return settings.controllerPort; - return 0; -} - -auto Interface::connect(uint port, uint device) -> void { - if(port == ID::Port::Controller) controllerPort.connect(settings.controllerPort = device); -} - -auto Interface::power() -> void { - system.power(); -} - -auto Interface::run() -> void { - system.run(); -} - -auto Interface::serialize() -> serializer { - system.runToSave(); - return system.serialize(); -} - -auto Interface::unserialize(serializer& s) -> bool { - return system.unserialize(s); -} - -auto Interface::cheats(const vector& list) -> void { - cheat.assign(list); -} - -auto Interface::cap(const string& name) -> bool { - return false; -} - -auto Interface::get(const string& name) -> any { - return {}; -} - -auto Interface::set(const string& name, const any& value) -> bool { - return false; -} - -} diff --git a/higan/pce/interface/interface.hpp b/higan/pce/interface/interface.hpp deleted file mode 100644 index 5d476c18..00000000 --- a/higan/pce/interface/interface.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#if defined(CORE_PCE) - -namespace PCEngine { - -struct ID { - enum : uint { - System, - PCEngine, - SuperGrafx, - }; - - struct Port { enum : uint { - Controller, - };}; - - struct Device { enum : uint { - None, - Gamepad, - };}; -}; - -struct Interface : Emulator::Interface { - auto display() -> Display override; - auto color(uint32 color) -> uint64 override; - - auto loaded() -> bool override; - auto hashes() -> vector override; - auto manifests() -> vector override; - auto titles() -> vector override; - auto save() -> void override; - auto unload() -> void override; - - auto ports() -> vector override; - auto devices(uint port) -> vector override; - auto inputs(uint device) -> vector override; - - auto connected(uint port) -> uint override; - auto connect(uint port, uint device) -> void override; - auto power() -> void override; - auto run() -> void override; - - auto serialize() -> serializer override; - auto unserialize(serializer&) -> bool override; - - auto cheats(const vector& list) -> void override; - - auto cap(const string& name) -> bool override; - auto get(const string& name) -> any override; - auto set(const string& name, const any& value) -> bool override; -}; - -struct PCEngineInterface : Interface { - auto information() -> Information override; - - auto load() -> bool override; -}; - -struct SuperGrafxInterface : Interface { - auto information() -> Information override; - - auto load() -> bool override; -}; - -struct Settings { - uint controllerPort = ID::Device::Gamepad; -}; - -extern Settings settings; - -} - -#endif diff --git a/higan/pce/interface/pc-engine.cpp b/higan/pce/interface/pc-engine.cpp deleted file mode 100644 index 8cad36fa..00000000 --- a/higan/pce/interface/pc-engine.cpp +++ /dev/null @@ -1,11 +0,0 @@ -auto PCEngineInterface::information() -> Information { - Information information; - information.manufacturer = "NEC"; - information.name = "PC Engine"; - information.extension = "pce"; - return information; -} - -auto PCEngineInterface::load() -> bool { - return system.load(this, System::Model::PCEngine); -} diff --git a/higan/pce/interface/supergrafx.cpp b/higan/pce/interface/supergrafx.cpp deleted file mode 100644 index 884933eb..00000000 --- a/higan/pce/interface/supergrafx.cpp +++ /dev/null @@ -1,11 +0,0 @@ -auto SuperGrafxInterface::information() -> Information { - Information information; - information.manufacturer = "NEC"; - information.name = "SuperGrafx"; - information.extension = "sg"; - return information; -} - -auto SuperGrafxInterface::load() -> bool { - return system.load(this, System::Model::SuperGrafx); -} diff --git a/higan/pce/pce.hpp b/higan/pce/pce.hpp deleted file mode 100644 index 9512e97d..00000000 --- a/higan/pce/pce.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -//license: GPLv3 -//started: 2017-01-11 - -#include -#include -#include -#include - -#include - -namespace PCEngine { - #define platform Emulator::platform - namespace File = Emulator::File; - using Scheduler = Emulator::Scheduler; - using Cheat = Emulator::Cheat; - extern Scheduler scheduler; - extern Cheat cheat; - - struct Thread : Emulator::Thread { - auto create(auto (*entrypoint)() -> void, double frequency) -> void { - Emulator::Thread::create(entrypoint, frequency); - scheduler.append(*this); - } - - inline auto synchronize(Thread& thread) -> void { - if(clock() >= thread.clock()) scheduler.resume(thread); - } - }; - - struct Model { - inline static auto PCEngine() -> bool; - inline static auto SuperGrafx() -> bool; - }; - - #include - - #include - #include - #include - #include - #include - - #include - #include -} - -#include diff --git a/higan/pce/psg/channel.cpp b/higan/pce/psg/channel.cpp deleted file mode 100644 index 3f74bb16..00000000 --- a/higan/pce/psg/channel.cpp +++ /dev/null @@ -1,29 +0,0 @@ -auto PSG::Channel::power(uint id) -> void { - this->id = id; - io = {}; -} - -auto PSG::Channel::run() -> void { - if(!io.enable) return sample(0); - - if(!io.direct && --io.wavePeriod == 0) { - io.wavePeriod = io.waveFrequency; - io.waveOffset++; - io.waveSample = io.waveBuffer[io.waveOffset]; - } - - if(!io.noiseEnable) { - return sample(io.waveSample); - } - - if(--io.noisePeriod == 0) { - io.noisePeriod = ~io.noiseFrequency << 7; - io.noiseSample = nall::random() & 1 ? ~0 : 0; - } - - return sample(io.noiseSample); -} - -auto PSG::Channel::sample(uint5 sample) -> void { - io.output = sample; -} diff --git a/higan/pce/psg/io.cpp b/higan/pce/psg/io.cpp deleted file mode 100644 index 4611a14d..00000000 --- a/higan/pce/psg/io.cpp +++ /dev/null @@ -1,81 +0,0 @@ -auto PSG::write(uint4 addr, uint8 data) -> void { - if(addr == 0x00) { - io.channel = data.bits(0,2); - } - - if(addr == 0x01) { - io.volumeRight = data.bits(0,3); - io.volumeLeft = data.bits(4,7); - } - - if(addr >= 0x02 && addr <= 0x06 && io.channel <= 5) { - channel[io.channel].write(addr, data); - } - - if(addr == 0x07 && io.channel >= 4 && io.channel <= 5) { - channel[io.channel].write(addr, data); - } - - if(addr == 0x08) { - io.lfoFrequency = data; - } - - if(addr == 0x09) { - io.lfoControl = data.bits(0,1); - io.lfoEnable = data.bit(7); - if(io.lfoEnable) { - channel[1].io.waveSample = channel[1].io.waveBuffer[channel[1].io.waveOffset = 0]; - } - } -} - -auto PSG::Channel::write(uint4 addr, uint8 data) -> void { - if(addr == 0x02) { - io.waveFrequency.bits(0,7) = data.bits(0,7); - io.wavePeriod = io.waveFrequency; - } - - if(addr == 0x03) { - io.waveFrequency.bits(8,11) = data.bits(0,3); - io.wavePeriod = io.waveFrequency; - } - - if(addr == 0x04) { - if(io.direct && !data.bit(6)) { - io.waveOffset = 0; - io.waveSample = io.waveBuffer[io.waveOffset]; - } - if(!io.enable && data.bit(7) && !data.bit(6)) { - io.waveOffset++; - io.waveSample = io.waveBuffer[io.waveOffset]; - } - io.volume = data.bits(0,4); - io.direct = data.bit(6); - io.enable = data.bit(7); - } - - if(addr == 0x05) { - io.volumeRight = data.bits(0,3); - io.volumeLeft = data.bits(4,7); - } - - if(addr == 0x06) { - if(!io.direct) { - io.waveBuffer[io.waveOffset] = data.bits(0,4); - if(!io.enable) io.waveOffset++; - } - if(io.enable) { - io.waveSample = data.bits(0,4); - } - } - - //channels 4 and 5 only - if(addr == 0x07) { - if(!io.noiseEnable && data.bit(7)) { - io.noisePeriod = ~data.bits(0,4) << 7; - io.noiseSample = 0; - } - io.noiseFrequency = data.bits(0,4); - io.noiseEnable = data.bit(7); - } -} diff --git a/higan/pce/psg/psg.cpp b/higan/pce/psg/psg.cpp deleted file mode 100644 index c0f18129..00000000 --- a/higan/pce/psg/psg.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include - -namespace PCEngine { - -PSG psg; -#include "io.cpp" -#include "channel.cpp" -#include "serialization.cpp" - -auto PSG::Enter() -> void { - while(true) scheduler.synchronize(), psg.main(); -} - -auto PSG::main() -> void { - static const uint5 volumeScale[16] = { - 0x00, 0x03, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, - 0x10, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, 0x1f, - }; - - uint5 lmal = volumeScale[io.volumeLeft]; - uint5 rmal = volumeScale[io.volumeRight]; - - double outputLeft = 0.0; - double outputRight = 0.0; - - for(auto C : range(6)) { - uint5 al = channel[C].io.volume; - uint5 lal = volumeScale[channel[C].io.volumeLeft]; - uint5 ral = volumeScale[channel[C].io.volumeRight]; - - uint5 volumeLeft = min(0x1f, (0x1f - lmal) + (0x1f - lal) + (0x1f - al)); - uint5 volumeRight = min(0x1f, (0x1f - rmal) + (0x1f - ral) + (0x1f - al)); - - channel[C].run(); - if(C == 1 && io.lfoEnable) { - //todo: frequency modulation of channel 0 using channel 1's output - } else { - outputLeft += channel[C].io.output * volumeScalar[volumeLeft]; - outputRight += channel[C].io.output * volumeScalar[volumeRight]; - } - } - - stream->sample(sclamp<16>(outputLeft) / 32768.0, sclamp<16>(outputRight) / 32768.0); - step(1); -} - -auto PSG::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); -} - -auto PSG::power() -> void { - create(PSG::Enter, system.colorburst()); - stream = Emulator::audio.createStream(2, frequency()); - stream->addHighPassFilter(20.0, Emulator::Filter::Order::First); - stream->addDCRemovalFilter(); - - io = {}; - for(auto C : range(6)) channel[C].power(C); - - double level = 32767.0 / 6.0 / 32.0; //max volume / channels / steps - double step = 48.0 / 32.0; //48dB volume range spread over 32 steps - for(uint n : range(31)) { - volumeScalar[n] = level; - level /= pow(10.0, step / 20.0); - } - volumeScalar[31] = 0.0; -} - -} diff --git a/higan/pce/psg/psg.hpp b/higan/pce/psg/psg.hpp deleted file mode 100644 index c0aa2267..00000000 --- a/higan/pce/psg/psg.hpp +++ /dev/null @@ -1,63 +0,0 @@ -//Programmable Sound Generator - -struct PSG : Thread { - shared_pointer stream; - - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - - auto power() -> void; - - //io.cpp - auto write(uint4 addr, uint8 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - struct IO { - uint3 channel; - uint4 volumeLeft; - uint4 volumeRight; - uint8 lfoFrequency; - uint2 lfoControl; - uint1 lfoEnable; - } io; - - struct Channel { - //channel.cpp - auto power(uint id) -> void; - auto run() -> void; - auto sample(uint5 sample) -> void; - - //io.cpp - auto write(uint4 addr, uint8 data) -> void; - - struct IO { - uint12 waveFrequency; - uint5 volume; - uint1 direct; - uint1 enable; - uint4 volumeLeft; - uint4 volumeRight; - uint5 waveBuffer[32]; - uint5 noiseFrequency; //channels 4 and 5 only - uint1 noiseEnable; //channels 4 and 5 only - - uint12 wavePeriod; - uint5 waveSample; - uint5 waveOffset; - uint12 noisePeriod; - uint5 noiseSample; - - uint5 output; - } io; - - uint id; - } channel[6]; - - double volumeScalar[32]; -}; - -extern PSG psg; diff --git a/higan/pce/psg/serialization.cpp b/higan/pce/psg/serialization.cpp deleted file mode 100644 index ff504cdd..00000000 --- a/higan/pce/psg/serialization.cpp +++ /dev/null @@ -1,28 +0,0 @@ -auto PSG::serialize(serializer& s) -> void { - Thread::serialize(s); - - s.integer(io.channel); - s.integer(io.volumeLeft); - s.integer(io.volumeRight); - s.integer(io.lfoFrequency); - s.integer(io.lfoControl); - s.integer(io.lfoEnable); - - for(auto C : range(6)) { - s.integer(channel[C].io.waveFrequency); - s.integer(channel[C].io.volume); - s.integer(channel[C].io.direct); - s.integer(channel[C].io.enable); - s.integer(channel[C].io.volumeLeft); - s.integer(channel[C].io.volumeRight); - s.array(channel[C].io.waveBuffer); - s.integer(channel[C].io.noiseFrequency); - s.integer(channel[C].io.noiseEnable); - s.integer(channel[C].io.wavePeriod); - s.integer(channel[C].io.waveSample); - s.integer(channel[C].io.waveOffset); - s.integer(channel[C].io.noisePeriod); - s.integer(channel[C].io.noiseSample); - s.integer(channel[C].io.output); - } -} diff --git a/higan/pce/system/serialization.cpp b/higan/pce/system/serialization.cpp deleted file mode 100644 index 3aba85f1..00000000 --- a/higan/pce/system/serialization.cpp +++ /dev/null @@ -1,61 +0,0 @@ -auto System::serializeInit() -> void { - serializer s; - - uint signature = 0; - char version[16] = {0}; - char description[512] = {0}; - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - information.serializeSize = s.size(); -} - -auto System::serialize() -> serializer { - serializer s{information.serializeSize}; - - uint signature = 0x31545342; - char version[16] = {0}; - char description[512] = {0}; - memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size()); - - s.integer(signature); - s.array(version); - s.array(description); - - serializeAll(s); - return s; -} - -auto System::unserialize(serializer& s) -> bool { - uint signature = 0; - char version[16] = {0}; - char description[512] = {0}; - - s.integer(signature); - s.array(version); - s.array(description); - - if(signature != 0x31545342) return false; - if(string{version} != Emulator::SerializerVersion) return false; - - power(); - serializeAll(s); - return true; -} - -auto System::serializeAll(serializer& s) -> void { - system.serialize(s); - cpu.serialize(s); - vce.serialize(s); - vpc.serialize(s); - vdc0.serialize(s); - vdc1.serialize(s); - psg.serialize(s); - controllerPort.serialize(s); -} - -auto System::serialize(serializer& s) -> void { -} diff --git a/higan/pce/system/system.cpp b/higan/pce/system/system.cpp deleted file mode 100644 index 8cbdd25a..00000000 --- a/higan/pce/system/system.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include - -namespace PCEngine { - -System system; -Scheduler scheduler; -Cheat cheat; -#include "serialization.cpp" - -auto System::run() -> void { - if(scheduler.enter() == Scheduler::Event::Frame) vce.refresh(); -} - -auto System::runToSave() -> void { - scheduler.synchronize(cpu); - scheduler.synchronize(vce); - scheduler.synchronize(vdc0); - scheduler.synchronize(vdc1); - scheduler.synchronize(psg); -} - -auto System::load(Emulator::Interface* interface, Model model) -> bool { - information = {}; - information.model = model; - - if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) { - information.manifest = fp->reads(); - } else return false; - - auto document = BML::unserialize(information.manifest); - if(!cartridge.load()) return false; - - cpu.load(); - serializeInit(); - this->interface = interface; - information.colorburst = Emulator::Constants::Colorburst::NTSC; - return information.loaded = true; -} - -auto System::save() -> void { - cartridge.save(); - cpu.save(); -} - -auto System::unload() -> void { - cpu.peripherals.reset(); - controllerPort.unload(); - cartridge.unload(); -} - -auto System::power() -> void { - Emulator::video.reset(interface); - Emulator::video.setPalette(); - - Emulator::audio.reset(interface); - - scheduler.reset(); - cartridge.power(); - cpu.power(); - vce.power(); - vpc.power(); - vdc0.power(); - vdc1.power(); - psg.power(); - scheduler.primary(cpu); - - controllerPort.power(); - controllerPort.connect(settings.controllerPort); -} - -} diff --git a/higan/pce/system/system.hpp b/higan/pce/system/system.hpp deleted file mode 100644 index e1e443eb..00000000 --- a/higan/pce/system/system.hpp +++ /dev/null @@ -1,39 +0,0 @@ -struct System { - enum class Model : uint { PCEngine, SuperGrafx }; - - inline auto loaded() const -> bool { return information.loaded; } - inline auto model() const -> Model { return information.model; } - inline auto colorburst() const -> double { return information.colorburst; } - - auto run() -> void; - auto runToSave() -> void; - - auto load(Emulator::Interface*, Model) -> bool; - auto save() -> void; - auto unload() -> void; - - auto power() -> void; - - //serialization.cpp - auto serializeInit() -> void; - auto serialize() -> serializer; - auto unserialize(serializer&) -> bool; - auto serializeAll(serializer&) -> void; - auto serialize(serializer&) -> void; - -private: - Emulator::Interface* interface = nullptr; - - struct Information { - bool loaded = false; - Model model = Model::PCEngine; - string manifest; - double colorburst = 0.0; - uint serializeSize = 0; - } information; -}; - -extern System system; - -auto Model::PCEngine() -> bool { return system.model() == System::Model::PCEngine; } -auto Model::SuperGrafx() -> bool { return system.model() == System::Model::SuperGrafx; } diff --git a/higan/pce/vce/io.cpp b/higan/pce/vce/io.cpp deleted file mode 100644 index 1530c6f2..00000000 --- a/higan/pce/vce/io.cpp +++ /dev/null @@ -1,54 +0,0 @@ -auto VCE::read(uint3 addr) -> uint8 { - if(addr == 0x04) { - //CTR - uint8 data = cram.read(cram.address).bits(0,7); - return data; - } - - if(addr == 0x05) { - //CTR - uint1 data = cram.read(cram.address).bit(8); - cram.address++; - return 0xfe | data; - } - - return 0xff; -} - -auto VCE::write(uint3 addr, uint8 data) -> void { - if(addr == 0x00) { - //CR - if(data.bits(0,1) == 0) io.clock = 4; - if(data.bits(0,1) == 1) io.clock = 3; - if(data.bits(0,1) == 2) io.clock = 2; - if(data.bits(0,1) == 3) io.clock = 2; - io.extraLine = data.bit(2); - io.grayscale = data.bit(7); - return; - } - - if(addr == 0x02) { - //CTA - cram.address.bits(0,7) = data.bits(0,7); - return; - } - - if(addr == 0x03) { - //CTA - cram.address.bit(8) = data.bit(0); - return; - } - - if(addr == 0x04) { - //CTW - cram.write(cram.address, 0, data.bits(0,7)); - return; - } - - if(addr == 0x05) { - //CTW - cram.write(cram.address, 1, data.bit(0)); - cram.address++; - return; - } -} diff --git a/higan/pce/vce/memory.cpp b/higan/pce/vce/memory.cpp deleted file mode 100644 index 02ef2858..00000000 --- a/higan/pce/vce/memory.cpp +++ /dev/null @@ -1,11 +0,0 @@ -auto VCE::CRAM::read(uint9 addr) -> uint9 { - return data[addr]; -} - -auto VCE::CRAM::write(uint9 addr, bool a0, uint8 value) -> void { - if(!a0) { - data[addr].bits(0,7) = value.bits(0,7); - } else { - data[addr].bit(8) = value.bit(0); - } -} diff --git a/higan/pce/vce/serialization.cpp b/higan/pce/vce/serialization.cpp deleted file mode 100644 index 17a50b85..00000000 --- a/higan/pce/vce/serialization.cpp +++ /dev/null @@ -1,13 +0,0 @@ -auto VCE::serialize(serializer& s) -> void { - Thread::serialize(s); - - s.array(cram.data); - s.integer(cram.address); - - s.integer(timing.hclock); - s.integer(timing.vclock); - - s.integer(io.clock); - s.integer(io.extraLine); - s.integer(io.grayscale); -} diff --git a/higan/pce/vce/vce.cpp b/higan/pce/vce/vce.cpp deleted file mode 100644 index ccf3c193..00000000 --- a/higan/pce/vce/vce.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include - -namespace PCEngine { - -VCE vce; -#include "memory.cpp" -#include "io.cpp" -#include "serialization.cpp" - -auto VCE::Enter() -> void { - while(true) scheduler.synchronize(), vce.main(); -} - -auto VCE::main() -> void { - if(timing.vclock == 0) { - vdc0.frame(); - vdc1.frame(); - } - - vdc0.scanline(); - vdc1.scanline(); - timing.hclock = 0; - - auto output = buffer + 1365 * timing.vclock; - - while(timing.hclock < 1360) { - uint9 color; - if(Model::PCEngine()) color = vdc0.bus(); - if(Model::SuperGrafx()) color = vpc.bus(timing.hclock); - color = cram.read(color); - - if(clock() >= 2) *output++ = color; - if(clock() >= 2) *output++ = color; - if(clock() >= 3) *output++ = color; - if(clock() >= 4) *output++ = color; - step(clock()); - } - - step(1365 - timing.hclock); - - if(++timing.vclock == 262) { - timing.vclock = 0; - scheduler.exit(Scheduler::Event::Frame); - } -} - -auto VCE::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); - synchronize(vdc0); - synchronize(vdc1); - - timing.hclock += clocks; -} - -auto VCE::refresh() -> void { - Emulator::video.refresh(buffer + 1365 * 13, 1365 * sizeof(uint32), 1120, 240); -} - -auto VCE::power() -> void { - create(VCE::Enter, system.colorburst() * 6.0); - - for(auto& pixel : buffer) pixel = 0; - cram = {}; - timing = {}; - io = {}; -} - -} diff --git a/higan/pce/vce/vce.hpp b/higan/pce/vce/vce.hpp deleted file mode 100644 index ee2e406d..00000000 --- a/higan/pce/vce/vce.hpp +++ /dev/null @@ -1,43 +0,0 @@ -//HuC6260 -- Video Color Encoder - -struct VCE : Thread { - inline auto clock() const -> uint { return io.clock; } - - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - auto refresh() -> void; - auto power() -> void; - - //io.cpp - auto read(uint3 addr) -> uint8; - auto write(uint3 addr, uint8 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - uint32 buffer[1365 * 263]; - - struct CRAM { - //memory.cpp - auto read(uint9 addr) -> uint9; - auto write(uint9 addr, bool a0, uint8 data) -> void; - - uint9 data[0x200]; - uint9 address; - } cram; - - struct Timing { - uint hclock = 0; - uint vclock = 0; - } timing; - - struct IO { - uint clock = 4; - bool extraLine = 0; - bool grayscale = 0; - } io; -}; - -extern VCE vce; diff --git a/higan/pce/vdc/background.cpp b/higan/pce/vdc/background.cpp deleted file mode 100644 index a143c416..00000000 --- a/higan/pce/vdc/background.cpp +++ /dev/null @@ -1,41 +0,0 @@ -auto VDC::Background::scanline(uint y) -> void { - if(y == 0) { - vcounter = vscroll; - } else { - vcounter++; - } - hoffset = hscroll; - voffset = vcounter; -} - -auto VDC::Background::run(uint x, uint y) -> void { - color = 0; - palette = 0; - - uint16 batAddress; - batAddress = (voffset >> 3) & (height - 1); - batAddress *= width; - batAddress += (hoffset >> 3) & (width - 1); - - uint16 tiledata = vdc->vram.read(batAddress); - uint16 patternAddress = tiledata.bits(0,11) << 4; - patternAddress += (voffset & 7); - uint4 palette = tiledata.bits(12,15); - - uint16 d0 = vdc->vram.read(patternAddress + 0); - uint16 d1 = vdc->vram.read(patternAddress + 8); - - uint3 index = 7 - (hoffset & 7); - uint4 color; - color.bit(0) = d0.bit(0 + index); - color.bit(1) = d0.bit(8 + index); - color.bit(2) = d1.bit(0 + index); - color.bit(3) = d1.bit(8 + index); - - if(enable && color) { - this->color = color; - this->palette = palette; - } - - hoffset++; -} diff --git a/higan/pce/vdc/dma.cpp b/higan/pce/vdc/dma.cpp deleted file mode 100644 index 68844eb3..00000000 --- a/higan/pce/vdc/dma.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto VDC::DMA::step(uint clocks) -> void { - while(clocks--) { - if(vramActive) { - uint16 data = vdc->vram.read(source); - vdc->vram.write(target, data); - sourceIncrementMode == 0 ? source++ : source--; - targetIncrementMode == 0 ? target++ : target--; - if(!--length) { - vramActive = false; - vdc->irq.raise(VDC::IRQ::Line::TransferVRAM); - } - } - - if(satbActive) { - uint16 data = vdc->vram.read(satbSource + satbOffset); - vdc->satb.write(satbOffset, data); - if(++satbOffset == 256) { - satbActive = false; - satbOffset = 0; - satbPending = satbRepeat; - vdc->irq.raise(VDC::IRQ::Line::TransferSATB); - } - } - } -} - -auto VDC::DMA::vramStart() -> void { - vramActive = true; -} - -auto VDC::DMA::satbStart() -> void { - if(!satbPending) return; - satbActive = true; - satbOffset = 0; -} - -auto VDC::DMA::satbQueue() -> void { - satbPending = true; -} diff --git a/higan/pce/vdc/io.cpp b/higan/pce/vdc/io.cpp deleted file mode 100644 index 3d03198f..00000000 --- a/higan/pce/vdc/io.cpp +++ /dev/null @@ -1,204 +0,0 @@ -auto VDC::read(uint2 addr) -> uint8 { - bool a0 = addr.bit(0); - bool a1 = addr.bit(1); - - if(a1 == 0) { - //SR - if(a0) return 0x00; - uint8 data; - data.bit(0) = irq.pendingCollision; - data.bit(1) = irq.pendingOverflow; - data.bit(2) = irq.pendingLineCoincidence; - data.bit(3) = irq.pendingTransferSATB; - data.bit(4) = irq.pendingTransferVRAM; - data.bit(5) = irq.pendingVblank; - irq.lower(); - return data; - } else { - if(io.address == 0x02) { - //VRR - uint8 data = vram.dataRead.byte(a0); - if(a0) { - vram.addressRead += vram.addressIncrement; - vram.dataRead = vram.read(vram.addressRead); - } - return data; - } - } - - return 0x00; -} - -auto VDC::write(uint2 addr, uint8 data) -> void { - bool a0 = addr.bit(0); - bool a1 = addr.bit(1); - - if(a1 == 0) { - //AR - if(a0) return; - io.address = data.bits(0,4); - return; - } else { - if(io.address == 0x00) { - //MAWR - vram.addressWrite.byte(a0) = data; - return; - } - - if(io.address == 0x01) { - //MARR - vram.addressRead.byte(a0) = data; - vram.dataRead = vram.read(vram.addressRead); - return; - } - - if(io.address == 0x02) { - //VWR - vram.dataWrite.byte(a0) = data; - if(a0) { - vram.write(vram.addressWrite, vram.dataWrite); - vram.addressWrite += vram.addressIncrement; - } - return; - } - - if(io.address == 0x05) { - //CR - if(!a0) { - irq.enableCollision = data.bit(0); - irq.enableOverflow = data.bit(1); - irq.enableLineCoincidence = data.bit(2); - irq.enableVblank = data.bit(3); - io.externalSync = data.bits(4,5); - sprite.enable = data.bit(6); - background.enable = data.bit(7); - } else { - io.displayOutput = data.bits(0,1); - io.dramRefresh = data.bit(2); - if(data.bits(3,4) == 0) vram.addressIncrement = 0x01; - if(data.bits(3,4) == 1) vram.addressIncrement = 0x20; - if(data.bits(3,4) == 2) vram.addressIncrement = 0x40; - if(data.bits(3,4) == 3) vram.addressIncrement = 0x80; - } - return; - } - - if(io.address == 0x06) { - //RCR - io.lineCoincidence.byte(a0) = data; - return; - } - - if(io.address == 0x07) { - //BXR - background.hscroll.byte(a0) = data; - return; - } - - if(io.address == 0x08) { - //BYR - background.vscroll.byte(a0) = data; - background.vcounter = background.vscroll; - return; - } - - if(io.address == 0x09) { - //MWR - if(a0) return; - io.vramAccess = data.bits(0,1); - io.spriteAccess = data.bits(2,3); - if(data.bits(4,5) == 0) background.width = 32; - if(data.bits(4,5) == 1) background.width = 64; - if(data.bits(4,5) == 2) background.width = 128; - if(data.bits(4,5) == 3) background.width = 128; - if(data.bit(6) == 0) background.height = 32; - if(data.bit(6) == 1) background.height = 64; - io.cgMode = data.bit(7); - return; - } - - if(io.address == 0x0a) { - //HSR - if(!a0) { - timing.horizontalSyncWidth = data.bits(0,4); - } else { - timing.horizontalDisplayStart = data.bits(0,6); - } - return; - } - - if(io.address == 0x0b) { - //HDR - if(!a0) { - timing.horizontalDisplayLength = data.bits(0,6); - } else { - timing.horizontalDisplayEnd = data.bits(0,6); - } - return; - } - - if(io.address == 0x0c) { - //VPR - if(!a0) { - timing.verticalSyncWidth = data.bits(0,4); - } else { - timing.verticalDisplayStart = data.bits(0,7); - } - return; - } - - if(io.address == 0x0d) { - //VDR - if(!a0) { - timing.verticalDisplayLength.bits(0,7) = data.bits(0,7); - } else { - timing.verticalDisplayLength.bit(8) = data.bit(0); - } - return; - } - - if(io.address == 0x0e) { - //VCR - if(a0) return; - timing.verticalDisplayEnd = data.bits(0,7); - return; - } - - if(io.address == 0x0f) { - //DCR - if(a0) return; - irq.enableTransferVRAM = data.bit(0); - irq.enableTransferSATB = data.bit(1); - dma.sourceIncrementMode = data.bit(2); - dma.targetIncrementMode = data.bit(3); - dma.satbRepeat = data.bit(4); - return; - } - - if(io.address == 0x10) { - //SOUR - dma.source.byte(a0) = data; - return; - } - - if(io.address == 0x11) { - //DESR - dma.target.byte(a0) = data; - return; - } - - if(io.address == 0x12) { - //LENR - dma.length.byte(a0) = data; - if(a0) dma.vramStart(); - return; - } - - if(io.address == 0x13) { - //DVSSR - dma.satbSource.byte(a0) = data; - if(a0) dma.satbQueue(); - return; - } - } -} diff --git a/higan/pce/vdc/irq.cpp b/higan/pce/vdc/irq.cpp deleted file mode 100644 index dea7d7ae..00000000 --- a/higan/pce/vdc/irq.cpp +++ /dev/null @@ -1,48 +0,0 @@ -auto VDC::IRQ::poll() -> void { - bool pending = false; - pending |= pendingCollision; - pending |= pendingOverflow; - pending |= pendingLineCoincidence; - pending |= pendingVblank; - pending |= pendingTransferVRAM; - pending |= pendingTransferSATB; - line = pending; -} - -auto VDC::IRQ::raise(Line line) -> void { - if(line == Line::Collision && enableCollision) { - pendingCollision = true; - } - - if(line == Line::Overflow && enableOverflow) { - pendingOverflow = true; - } - - if(line == Line::LineCoincidence && enableLineCoincidence) { - pendingLineCoincidence = true; - } - - if(line == Line::Vblank && enableVblank) { - pendingVblank = true; - } - - if(line == Line::TransferVRAM && enableTransferVRAM) { - pendingTransferVRAM = true; - } - - if(line == Line::TransferSATB && enableTransferSATB) { - pendingTransferSATB = true; - } - - poll(); -} - -auto VDC::IRQ::lower() -> void { - pendingCollision = false; - pendingOverflow = false; - pendingLineCoincidence = false; - pendingVblank = false; - pendingTransferVRAM = false; - pendingTransferSATB = false; - line = false; -} diff --git a/higan/pce/vdc/memory.cpp b/higan/pce/vdc/memory.cpp deleted file mode 100644 index 0084e771..00000000 --- a/higan/pce/vdc/memory.cpp +++ /dev/null @@ -1,17 +0,0 @@ -auto VDC::VRAM::read(uint16 addr) -> uint16 { - if(addr.bit(15)) return 0x0000; //todo: random data? - return data[addr]; -} - -auto VDC::VRAM::write(uint16 addr, uint16 value) -> void { - if(addr.bit(15)) return; - data[addr] = value; -} - -auto VDC::SATB::read(uint8 addr) -> uint16 { - return data[addr]; -} - -auto VDC::SATB::write(uint8 addr, uint16 value) -> void { - data[addr] = value; -} diff --git a/higan/pce/vdc/serialization.cpp b/higan/pce/vdc/serialization.cpp deleted file mode 100644 index e6f50367..00000000 --- a/higan/pce/vdc/serialization.cpp +++ /dev/null @@ -1,83 +0,0 @@ -auto VDC::serialize(serializer& s) -> void { - Thread::serialize(s); - - s.array(vram.data); - s.integer(vram.addressRead); - s.integer(vram.addressWrite); - s.integer(vram.addressIncrement); - s.integer(vram.dataRead); - s.integer(vram.dataWrite); - - s.array(satb.data); - - s.integer(timing.horizontalSyncWidth); - s.integer(timing.horizontalDisplayStart); - s.integer(timing.horizontalDisplayLength); - s.integer(timing.horizontalDisplayEnd); - s.integer(timing.verticalSyncWidth); - s.integer(timing.verticalDisplayStart); - s.integer(timing.verticalDisplayLength); - s.integer(timing.verticalDisplayEnd); - s.integer(timing.vpulse); - s.integer(timing.hpulse); - s.integer(timing.hclock); - s.integer(timing.vclock); - s.integer(timing.hoffset); - s.integer(timing.voffset); - s.integer(timing.hstart); - s.integer(timing.vstart); - s.integer(timing.hlength); - s.integer(timing.vlength); - - s.integer(irq.enableCollision); - s.integer(irq.enableOverflow); - s.integer(irq.enableLineCoincidence); - s.integer(irq.enableVblank); - s.integer(irq.enableTransferVRAM); - s.integer(irq.enableTransferSATB); - s.integer(irq.pendingCollision); - s.integer(irq.pendingOverflow); - s.integer(irq.pendingLineCoincidence); - s.integer(irq.pendingVblank); - s.integer(irq.pendingTransferVRAM); - s.integer(irq.pendingTransferSATB); - s.integer(irq.line); - - s.integer(dma.sourceIncrementMode); - s.integer(dma.targetIncrementMode); - s.integer(dma.satbRepeat); - s.integer(dma.source); - s.integer(dma.target); - s.integer(dma.length); - s.integer(dma.satbSource); - s.integer(dma.vramActive); - s.integer(dma.satbActive); - s.integer(dma.satbPending); - s.integer(dma.satbOffset); - - s.integer(background.enable); - s.integer(background.hscroll); - s.integer(background.vscroll); - s.integer(background.vcounter); - s.integer(background.width); - s.integer(background.height); - s.integer(background.hoffset); - s.integer(background.voffset); - s.integer(background.color); - s.integer(background.palette); - - s.integer(sprite.enable); - s.integer(sprite.color); - s.integer(sprite.palette); - s.integer(sprite.priority); - //todo: serialize array - - s.integer(io.address); - s.integer(io.externalSync); - s.integer(io.displayOutput); - s.integer(io.dramRefresh); - s.integer(io.lineCoincidence); - s.integer(io.vramAccess); - s.integer(io.spriteAccess); - s.integer(io.cgMode); -} diff --git a/higan/pce/vdc/sprite.cpp b/higan/pce/vdc/sprite.cpp deleted file mode 100644 index fa9d5240..00000000 --- a/higan/pce/vdc/sprite.cpp +++ /dev/null @@ -1,102 +0,0 @@ -auto VDC::Sprite::scanline(uint y) -> void { - y += 64; - objects.reset(); - - static const uint widths[] = {15, 31}; - static const uint heights[] = {15, 31, 63, 63}; - - uint count = 0; - for(uint index : range(64)) { - uint16 d0 = vdc->satb.read(index << 2 | 0); - uint16 d1 = vdc->satb.read(index << 2 | 1); - uint16 d2 = vdc->satb.read(index << 2 | 2); - uint16 d3 = vdc->satb.read(index << 2 | 3); - - Object object; - object.y = d0.bits(0,9); - object.height = heights[d3.bits(12,13)]; - if(y < object.y) continue; - if(y > object.y + object.height) continue; - - object.x = d1.bits(0,9); - object.mode = d2.bit(0); - object.pattern = d2.bits(1,10); - object.palette = d3.bits(0,3); - object.priority = d3.bit(7); - object.width = widths[d3.bit(8)]; - object.hflip = d3.bit(11); - object.vflip = d3.bit(15); - object.first = index == 0; - - if(object.width == 31) object.pattern.bit(0) = 0; - if(object.height == 31) object.pattern.bit(1) = 0; - if(object.height == 63) object.pattern.bits(1,2) = 0; - - if(object.width == 15) { - objects.append(object); - if(++count >= 16) return vdc->irq.raise(VDC::IRQ::Line::Overflow); - } else { - //32-width sprites count as two 16-width sprite slots - object.pattern ^= object.hflip; - object.width = 15; - objects.append(object); - if(++count >= 16) return vdc->irq.raise(VDC::IRQ::Line::Overflow); - - object.x += 16; - object.pattern ^= 1; - objects.append(object); - if(++count >= 16) return vdc->irq.raise(VDC::IRQ::Line::Overflow); - } - } -} - -auto VDC::Sprite::run(uint x, uint y) -> void { - x += 32; - y += 64; - - color = 0; - palette = 0; - priority = 0; - if(!enable) return; - - bool first = false; - for(auto& object : objects) { - if(x < object.x) continue; - if(x > object.x + object.width) continue; - - uint10 hoffset = x - object.x; - uint10 voffset = y - object.y; - if(object.hflip) hoffset ^= object.width; - if(object.vflip) voffset ^= object.height; - - uint16 patternAddress = object.pattern; - patternAddress += (voffset >> 4) << 1; - patternAddress += (hoffset >> 4); - patternAddress <<= 6; - patternAddress += (voffset & 15); - - uint16 d0 = vdc->vram.read(patternAddress + 0); - uint16 d1 = vdc->vram.read(patternAddress + 16); - uint16 d2 = vdc->vram.read(patternAddress + 32); - uint16 d3 = vdc->vram.read(patternAddress + 48); - - uint4 index = 15 - (hoffset & 15); - uint4 color; - color.bit(0) = d0.bit(index); - color.bit(1) = d1.bit(index); - color.bit(2) = d2.bit(index); - color.bit(3) = d3.bit(index); - if(color == 0) continue; - - if(this->color) { - if(first) return vdc->irq.raise(VDC::IRQ::Line::Collision); - return; - } - - this->color = color; - this->palette = object.palette; - this->priority = object.priority; - - if(object.first) first = true; - } -} diff --git a/higan/pce/vdc/vdc.cpp b/higan/pce/vdc/vdc.cpp deleted file mode 100644 index dbc8c930..00000000 --- a/higan/pce/vdc/vdc.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include - -namespace PCEngine { - -VDC vdc0; -VDC vdc1; -#include "memory.cpp" -#include "io.cpp" -#include "irq.cpp" -#include "dma.cpp" -#include "background.cpp" -#include "sprite.cpp" -#include "serialization.cpp" - -auto VDC::Enter() -> void { - while(true) { - scheduler.synchronize(); - if(vdc0.active()) vdc0.main(); - if(vdc1.active()) vdc1.main(); - } -} - -auto VDC::main() -> void { - if(Model::PCEngine() && vdc1.active()) return step(frequency()); - - if(timing.vclock == 0) { - timing.voffset = 0; - timing.vstart = max((uint8)2, timing.verticalDisplayStart) - 2; - timing.vlength = min(242, timing.verticalDisplayLength + 1); - } - - timing.hclock = 0; - timing.hoffset = 0; - timing.hstart = timing.horizontalDisplayStart; - timing.hlength = (timing.horizontalDisplayLength + 1) << 3; - - if(timing.vclock >= timing.vstart && timing.voffset < timing.vlength) { - background.scanline(timing.voffset); - sprite.scanline(timing.voffset); - - step(timing.hstart); - - while(timing.hclock < 1360 && timing.hoffset < timing.hlength) { - data = 0; - - background.run(timing.hoffset, timing.voffset); - sprite.run(timing.hoffset, timing.voffset); - - if(sprite.color && sprite.priority) { - data = 1 << 8 | sprite.palette << 4 | sprite.color << 0; - } else if(background.color) { - data = 0 << 8 | background.palette << 4 | background.color << 0; - } else if(sprite.color) { - data = 1 << 8 | sprite.palette << 4 | sprite.color << 0; - } - - step(vce.clock()); - timing.hoffset++; - } - - if(timing.voffset == io.lineCoincidence - 64) { - irq.raise(IRQ::Line::LineCoincidence); - } - - timing.voffset++; - } - - data = 0; - step(1365 - timing.hclock); - - if(timing.vclock == timing.vstart + timing.vlength) { - irq.raise(IRQ::Line::Vblank); - dma.satbStart(); - } - - if(++timing.vclock == 262) { - timing.vclock = 0; - } -} - -auto VDC::scanline() -> void { - timing.hpulse = true; -} - -auto VDC::frame() -> void { - timing.vpulse = true; -} - -auto VDC::step(uint clocks) -> void { - Thread::step(clocks); - synchronize(cpu); - synchronize(vce); - - timing.hclock += clocks; - dma.step(clocks); -} - -auto VDC::power() -> void { - create(VDC::Enter, system.colorburst() * 6.0); - - memory::fill(&vram, sizeof(VRAM)); - satb = {}; - timing = {}; - irq = {}; - dma = {}; - io = {}; - background = {}; - sprite = {}; - - dma.vdc = this; - background.vdc = this; - sprite.vdc = this; -} - -} diff --git a/higan/pce/vdc/vdc.hpp b/higan/pce/vdc/vdc.hpp deleted file mode 100644 index 27221752..00000000 --- a/higan/pce/vdc/vdc.hpp +++ /dev/null @@ -1,199 +0,0 @@ -//Hudson Soft HuC6270 -- Video Display Controller - -struct VDC : Thread { - inline auto bus() const -> uint9 { return data; } - inline auto irqLine() const -> bool { return irq.line; } - - static auto Enter() -> void; - auto main() -> void; - auto step(uint clocks) -> void; - auto scanline() -> void; - auto frame() -> void; - - auto power() -> void; - - //io.cpp - auto read(uint2 addr) -> uint8; - auto write(uint2 addr, uint8 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - uint9 data; - - struct VRAM { - //memory.cpp - auto read(uint16 addr) -> uint16; - auto write(uint16 addr, uint16 data) -> void; - - uint16 data[0x8000]; - - uint16 addressRead; - uint16 addressWrite; - uint16 addressIncrement; - - uint16 dataRead; - uint16 dataWrite; - } vram; - - struct SATB { - //memory.cpp - auto read(uint8 addr) -> uint16; - auto write(uint8 addr, uint16 data) -> void; - - uint16 data[0x100]; - } satb; - - struct Timing { - uint5 horizontalSyncWidth; - uint7 horizontalDisplayStart; - uint7 horizontalDisplayLength; - uint7 horizontalDisplayEnd; - - uint5 verticalSyncWidth; - uint8 verticalDisplayStart; - uint9 verticalDisplayLength; - uint8 verticalDisplayEnd; - - bool vpulse = 0; - bool hpulse = 0; - - uint hclock = 0; - uint vclock = 0; - - uint hoffset = 0; - uint voffset = 0; - - uint hstart = 0; - uint vstart = 0; - - uint hlength = 0; - uint vlength = 0; - } timing; - - struct IRQ { - enum class Line : uint { - Collision, - Overflow, - LineCoincidence, - Vblank, - TransferVRAM, - TransferSATB, - }; - - //irq.cpp - auto poll() -> void; - auto raise(Line) -> void; - auto lower() -> void; - - bool enableCollision = 0; - bool enableOverflow = 0; - bool enableLineCoincidence = 0; - bool enableVblank = 0; - bool enableTransferVRAM = 0; - bool enableTransferSATB = 0; - - bool pendingCollision = 0; - bool pendingOverflow = 0; - bool pendingLineCoincidence = 0; - bool pendingVblank = 0; - bool pendingTransferVRAM = 0; - bool pendingTransferSATB = 0; - - bool line = 0; - } irq; - - struct DMA { - VDC* vdc = nullptr; - - //dma.cpp - auto step(uint clocks) -> void; - auto vramStart() -> void; - auto satbStart() -> void; - auto satbQueue() -> void; - - bool sourceIncrementMode = 0; - bool targetIncrementMode = 0; - bool satbRepeat = 0; - uint16 source; - uint16 target; - uint16 length; - uint16 satbSource; - - bool vramActive = 0; - bool satbActive = 0; - bool satbPending = 0; - uint16 satbOffset; - } dma; - - struct Background { - VDC* vdc = nullptr; - - //background.cpp - auto scanline(uint y) -> void; - auto run(uint x, uint y) -> void; - - bool enable = 0; - uint10 hscroll; - uint9 vscroll; - uint9 vcounter; - uint8 width; - uint8 height; - - uint10 hoffset; - uint9 voffset; - - uint4 color; - uint4 palette; - } background; - - struct Sprite { - VDC* vdc = nullptr; - - //sprite.cpp - auto scanline(uint y) -> void; - auto run(uint x, uint y) -> void; - - bool enable = 0; - - struct Object { - uint10 y; - uint10 x; - bool mode = 0; - uint10 pattern; - uint4 palette; - bool priority = 0; - uint width = 0; - bool hflip = 0; - uint height = 0; - bool vflip = 0; - bool first = 0; - }; - adaptive_array objects; - - uint4 color; - uint4 palette; - bool priority = 0; - } sprite; - - struct IO { - uint5 address; - - //$0005 CR (W) - uint2 externalSync; - uint2 displayOutput; - bool dramRefresh = 0; - - //$0006 RCR - uint10 lineCoincidence; - - //$0009 MWR - uint2 vramAccess; - uint2 spriteAccess; - bool cgMode = 0; - } io; -}; - -extern VDC vdc0; -extern VDC vdc1; diff --git a/higan/pce/vpc/serialization.cpp b/higan/pce/vpc/serialization.cpp deleted file mode 100644 index 82d697dc..00000000 --- a/higan/pce/vpc/serialization.cpp +++ /dev/null @@ -1,9 +0,0 @@ -auto VPC::serialize(serializer& s) -> void { - for(auto n : range(4)) { - s.integer(settings[n].enableVDC0); - s.integer(settings[n].enableVDC1); - s.integer(settings[n].priority); - } - s.array(window); - s.integer(select); -} diff --git a/higan/pce/vpc/vpc.cpp b/higan/pce/vpc/vpc.cpp deleted file mode 100644 index dcb44acc..00000000 --- a/higan/pce/vpc/vpc.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include - -namespace PCEngine { - -VPC vpc; -#include "serialization.cpp" - -auto VPC::bus(uint hclock) -> uint9 { - //bus values are direct CRAM entry indexes: - //d0-d3 => color (0 = neither background nor sprite) - //d4-d7 => palette - //d8 => source (0 = background; 1 = sprite) - auto bus0 = vdc0.bus(); - auto bus1 = vdc1.bus(); - - //note: timing may not be correct here; unable to test behavior - //no official SuperGrafx games ever use partial screen-width windows - bool window0 = window[0] >= 64 && (window[0] - 64) >= hclock / 2; - bool window1 = window[1] >= 64 && (window[1] - 64) >= hclock / 2; - - uint2 mode = !window0 << 0 | !window1 << 1; - auto enableVDC0 = settings[mode].enableVDC0 && bus0.bits(0,3); - auto enableVDC1 = settings[mode].enableVDC1 && bus1.bits(0,3); - auto priority = settings[mode].priority; - - if(priority == 0 || priority == 3) { - //SP0 > BG0 > SP1 > BG1 - if(bus0.bit(8) == 1 && enableVDC0) return bus0; - if(bus0.bit(8) == 0 && enableVDC0) return bus0; - if(bus1.bit(8) == 1 && enableVDC1) return bus1; - if(bus1.bit(8) == 0 && enableVDC1) return bus1; - } - - if(priority == 1) { - //SP0 > SP1 > BG0 > BG1 - if(bus0.bit(8) == 1 && enableVDC0) return bus0; - if(bus1.bit(8) == 1 && enableVDC1) return bus1; - if(bus0.bit(8) == 0 && enableVDC0) return bus0; - if(bus1.bit(8) == 0 && enableVDC1) return bus1; - } - - if(priority == 2) { - //BG0 > SP1 > BG1 > SP0 - if(bus0.bit(8) == 0 && enableVDC0) return bus0; - if(bus1.bit(8) == 1 && enableVDC1) return bus1; - if(bus1.bit(8) == 0 && enableVDC1) return bus1; - if(bus0.bit(8) == 1 && enableVDC0) return bus0; - } - - return 0x000; -} - -auto VPC::power() -> void { - settings[0].enableVDC0 = true; - settings[0].enableVDC1 = false; - settings[0].priority = 0; - - settings[1].enableVDC0 = true; - settings[1].enableVDC1 = false; - settings[1].priority = 0; - - settings[2].enableVDC0 = true; - settings[2].enableVDC1 = false; - settings[2].priority = 0; - - settings[3].enableVDC0 = true; - settings[3].enableVDC1 = false; - settings[3].priority = 0; - - window[0] = 0; - window[1] = 0; - - select = 0; -} - -auto VPC::read(uint5 addr) -> uint8 { - if(addr >= 0x00 && addr <= 0x07) return vdc0.read(addr); - if(addr >= 0x10 && addr <= 0x17) return vdc1.read(addr); - if(addr >= 0x18 && addr <= 0x1f) return 0xff; - - if(addr == 0x08) { - return ( - settings[0].enableVDC0 << 0 - | settings[0].enableVDC1 << 1 - | settings[0].priority << 2 - | settings[1].enableVDC0 << 4 - | settings[1].enableVDC1 << 5 - | settings[1].priority << 6 - ); - } - - if(addr == 0x09) { - return ( - settings[2].enableVDC0 << 0 - | settings[2].enableVDC1 << 1 - | settings[2].priority << 2 - | settings[3].enableVDC0 << 4 - | settings[3].enableVDC1 << 5 - | settings[3].priority << 6 - ); - } - - if(addr == 0x0a) return window[0].bits(0,7); - if(addr == 0x0b) return window[0].bits(8,9); - if(addr == 0x0c) return window[1].bits(0,7); - if(addr == 0x0d) return window[1].bits(8,9); - if(addr == 0x0e) return 0x00; //select is not readable - if(addr == 0x0f) return 0x00; //unused - - unreachable; -} - -auto VPC::write(uint5 addr, uint8 data) -> void { - if(addr >= 0x00 && addr <= 0x07) return vdc0.write(addr, data); - if(addr >= 0x10 && addr <= 0x17) return vdc1.write(addr, data); - if(addr >= 0x18 && addr <= 0x1f) return; - - if(addr == 0x08) { - settings[0].enableVDC0 = data.bit(0); - settings[0].enableVDC1 = data.bit(1); - settings[0].priority = data.bits(2,3); - settings[1].enableVDC0 = data.bit(4); - settings[1].enableVDC1 = data.bit(5); - settings[1].priority = data.bits(6,7); - return; - } - - if(addr == 0x09) { - settings[2].enableVDC0 = data.bit(0); - settings[2].enableVDC1 = data.bit(1); - settings[2].priority = data.bits(2,3); - settings[3].enableVDC0 = data.bit(4); - settings[3].enableVDC1 = data.bit(5); - settings[3].priority = data.bits(6,7); - return; - } - - if(addr == 0x0a) { - window[0].bits(0,7) = data.bits(0,7); - return; - } - - if(addr == 0x0b) { - window[0].bits(8,9) = data.bits(0,1); - return; - } - - if(addr == 0x0c) { - window[1].bits(0,7) = data.bits(0,7); - return; - } - - if(addr == 0x0d) { - window[1].bits(8,9) = data.bits(0,1); - return; - } - - if(addr == 0x0e) { - select = data.bit(0); - return; - } - - if(addr == 0x0f) { - //unused - return; - } -} - -auto VPC::store(uint2 addr, uint8 data) -> void { - if(select == 0) return vdc0.write(addr, data); - if(select == 1) return vdc1.write(addr, data); -} - -} diff --git a/higan/pce/vpc/vpc.hpp b/higan/pce/vpc/vpc.hpp deleted file mode 100644 index 168f42d7..00000000 --- a/higan/pce/vpc/vpc.hpp +++ /dev/null @@ -1,25 +0,0 @@ -//Hudson Soft HuC6202 -- Video Priority Controller - -struct VPC { - auto bus(uint hclock) -> uint9; - - auto power() -> void; - auto read(uint5 addr) -> uint8; - auto write(uint5 addr, uint8 data) -> void; - auto store(uint2 addr, uint8 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - struct Settings { - bool enableVDC0; - bool enableVDC1; - uint2 priority; - } settings[4]; - - uint10 window[2]; - bool select; -}; - -extern VPC vpc; diff --git a/higan/sfc/dsp/brr.cpp b/higan/sfc/dsp/brr.cpp deleted file mode 100644 index 7fae1908..00000000 --- a/higan/sfc/dsp/brr.cpp +++ /dev/null @@ -1,61 +0,0 @@ -auto DSP::brrDecode(Voice& v) -> void { - //state.t_brr_byte = ram[v.brr_addr + v.brr_offset] cached from previous clock cycle - int nybbles = (state._brrByte << 8) + apuram[(uint16)(v.brrAddress + v.brrOffset + 1)]; - - const int filter = (state._brrHeader >> 2) & 3; - const int scale = (state._brrHeader >> 4); - - //decode four samples - for(auto n : range(4)) { - //bits 12-15 = current nybble; sign extend, then shift right to 4-bit precision - //result: s = 4-bit sign-extended sample value - int s = (int16)nybbles >> 12; - nybbles <<= 4; //slide nybble so that on next loop iteration, bits 12-15 = current nybble - - if(scale <= 12) { - s <<= scale; - s >>= 1; - } else { - s &= ~0x7ff; - } - - //apply IIR filter (2 is the most commonly used) - const int p1 = v.buffer[12 + v.bufferOffset - 1]; - const int p2 = v.buffer[12 + v.bufferOffset - 2] >> 1; - - switch(filter) { - case 0: - break; - - case 1: - //s += p1 * 0.46875 - s += p1 >> 1; - s += (-p1) >> 5; - break; - - case 2: - //s += p1 * 0.953125 - p2 * 0.46875 - s += p1; - s -= p2; - s += p2 >> 4; - s += (p1 * -3) >> 6; - break; - - case 3: - //s += p1 * 0.8984375 - p2 * 0.40625 - s += p1; - s -= p2; - s += (p1 * -13) >> 7; - s += (p2 * 3) >> 4; - break; - } - - //adjust and write sample (mirror the written sample for wrapping) - s = sclamp<16>(s); - s = (int16)(s << 1); - v.buffer[v.bufferOffset + 0] = s; - v.buffer[v.bufferOffset + 12] = s; - v.buffer[v.bufferOffset + 24] = s; - if(++v.bufferOffset >= 12) v.bufferOffset = 0; - } -} diff --git a/higan/sfc/dsp/counter.cpp b/higan/sfc/dsp/counter.cpp deleted file mode 100644 index 4a2a7537..00000000 --- a/higan/sfc/dsp/counter.cpp +++ /dev/null @@ -1,48 +0,0 @@ -//counter_rate = number of samples per counter event -//all rates are evenly divisible by counter_range (0x7800, 30720, or 2048 * 5 * 3) -//note that rate[0] is a special case, which never triggers - -const uint16 DSP::CounterRate[32] = { - 0, 2048, 1536, - 1280, 1024, 768, - 640, 512, 384, - 320, 256, 192, - 160, 128, 96, - 80, 64, 48, - 40, 32, 24, - 20, 16, 12, - 10, 8, 6, - 5, 4, 3, - 2, - 1, -}; - -//counter_offset = counter offset from zero -//counters do not appear to be aligned at zero for all rates - -const uint16 DSP::CounterOffset[32] = { - 0, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 0, - 0, -}; - -inline auto DSP::counterTick() -> void { - state.counter--; - if(state.counter < 0) state.counter = CounterRange - 1; -} - -//return true if counter event should trigger - -inline auto DSP::counterPoll(uint rate) -> bool { - if(rate == 0) return false; - return (((uint)state.counter + CounterOffset[rate]) % CounterRate[rate]) == 0; -} diff --git a/higan/sfc/dsp/dsp.cpp b/higan/sfc/dsp/dsp.cpp deleted file mode 100644 index 4cbc3b5c..00000000 --- a/higan/sfc/dsp/dsp.cpp +++ /dev/null @@ -1,263 +0,0 @@ -#include - -namespace SuperFamicom { - -DSP dsp; - -#define REG(n) state.regs[n] -#define VREG(n) state.regs[v.vidx + n] - -#include "gaussian.cpp" -#include "counter.cpp" -#include "envelope.cpp" -#include "brr.cpp" -#include "misc.cpp" -#include "voice.cpp" -#include "echo.cpp" -#include "serialization.cpp" - -DSP::DSP() { - static_assert(sizeof(int) >= 32 / 8, "int >= 32-bits"); - static_assert((int8_t)0x80 == -0x80, "8-bit sign extension"); - static_assert((int16_t)0x8000 == -0x8000, "16-bit sign extension"); - static_assert((uint16_t)0xffff0000 == 0, "16-bit unsigned clip"); - static_assert((-1 >> 1) == -1, "arithmetic shift right"); - - //-0x8000 <= n <= +0x7fff - assert(sclamp<16>(+0x8000) == +0x7fff); - assert(sclamp<16>(-0x8001) == -0x8000); -} - -/* timing */ - -auto DSP::step(uint clocks) -> void { - Thread::step(clocks); -} - -auto DSP::Enter() -> void { - while(true) scheduler.synchronize(), dsp.main(); -} - -auto DSP::main() -> void { - voice5(voice[0]); - voice2(voice[1]); - tick(); - - voice6(voice[0]); - voice3(voice[1]); - tick(); - - voice7(voice[0]); - voice4(voice[1]); - voice1(voice[3]); - tick(); - - voice8(voice[0]); - voice5(voice[1]); - voice2(voice[2]); - tick(); - - voice9(voice[0]); - voice6(voice[1]); - voice3(voice[2]); - tick(); - - voice7(voice[1]); - voice4(voice[2]); - voice1(voice[4]); - tick(); - - voice8(voice[1]); - voice5(voice[2]); - voice2(voice[3]); - tick(); - - voice9(voice[1]); - voice6(voice[2]); - voice3(voice[3]); - tick(); - - voice7(voice[2]); - voice4(voice[3]); - voice1(voice[5]); - tick(); - - voice8(voice[2]); - voice5(voice[3]); - voice2(voice[4]); - tick(); - - voice9(voice[2]); - voice6(voice[3]); - voice3(voice[4]); - tick(); - - voice7(voice[3]); - voice4(voice[4]); - voice1(voice[6]); - tick(); - - voice8(voice[3]); - voice5(voice[4]); - voice2(voice[5]); - tick(); - - voice9(voice[3]); - voice6(voice[4]); - voice3(voice[5]); - tick(); - - voice7(voice[4]); - voice4(voice[5]); - voice1(voice[7]); - tick(); - - voice8(voice[4]); - voice5(voice[5]); - voice2(voice[6]); - tick(); - - voice9(voice[4]); - voice6(voice[5]); - voice3(voice[6]); - tick(); - - voice1(voice[0]); - voice7(voice[5]); - voice4(voice[6]); - tick(); - - voice8(voice[5]); - voice5(voice[6]); - voice2(voice[7]); - tick(); - - voice9(voice[5]); - voice6(voice[6]); - voice3(voice[7]); - tick(); - - voice1(voice[1]); - voice7(voice[6]); - voice4(voice[7]); - tick(); - - voice8(voice[6]); - voice5(voice[7]); - voice2(voice[0]); - tick(); - - voice3a(voice[0]); - voice9(voice[6]); - voice6(voice[7]); - echo22(); - tick(); - - voice7(voice[7]); - echo23(); - tick(); - - voice8(voice[7]); - echo24(); - tick(); - - voice3b(voice[0]); - voice9(voice[7]); - echo25(); - tick(); - - echo26(); - tick(); - - misc27(); - echo27(); - tick(); - - misc28(); - echo28(); - tick(); - - misc29(); - echo29(); - tick(); - - misc30(); - voice3c(voice[0]); - echo30(); - tick(); - - voice4(voice[0]); - voice1(voice[2]); - tick(); -} - -auto DSP::tick() -> void { - if(!system.fastDSP()) { - step(3 * 8); - synchronize(smp); - } -} - -auto DSP::sample(int16 left, int16 right) -> void { - stream->sample(left / 32768.0, right / 32768.0); - if(system.fastDSP()) { - step(32 * 3 * 8); - synchronize(smp); - } -} - -/* register interface for S-SMP $00f2,$00f3 */ - -auto DSP::mute() const -> bool { - return REG(FLG) & 0x40; -} - -auto DSP::read(uint8 addr) -> uint8 { - return REG(addr); -} - -auto DSP::write(uint8 addr, uint8 data) -> void { - REG(addr) = data; - - if((addr & 0x0f) == ENVX) { - state.envxBuffer = data; - } else if((addr & 0x0f) == OUTX) { - state.outxBuffer = data; - } else if(addr == KON) { - state.konBuffer = data; - } else if(addr == ENDX) { - //always cleared, regardless of data written - state.endxBuffer = 0; - REG(ENDX) = 0; - } -} - -/* initialization */ - -auto DSP::load() -> bool { - return true; -} - -auto DSP::power(bool reset) -> void { - create(Enter, system.apuFrequency()); - stream = Emulator::audio.createStream(2, frequency() / 768.0); - - if(!reset) random.array(apuram, sizeof(apuram)); - - state = {}; - for(auto n : range(8)) { - voice[n] = {}; - voice[n].vbit = 1 << n; - voice[n].vidx = n * 0x10; - } - - //note: memory is pseudo-random at startup; but internal state is less so - //exact differences are unknown. need to separate memory from internal state - for(auto r : range(0x80)) REG(r) = 0x00; - REG(FLG) = 0xe0; -} - -#undef REG -#undef VREG - -} diff --git a/higan/sfc/dsp/dsp.hpp b/higan/sfc/dsp/dsp.hpp deleted file mode 100644 index 5424b9c6..00000000 --- a/higan/sfc/dsp/dsp.hpp +++ /dev/null @@ -1,177 +0,0 @@ -//Sony CXD1222Q-1 - -struct DSP : Thread { - shared_pointer stream; - uint8 apuram[64 * 1024]; - - DSP(); - - alwaysinline auto step(uint clocks) -> void; - - auto mute() const -> bool; - auto read(uint8 addr) -> uint8; - auto write(uint8 addr, uint8 data) -> void; - - auto main() -> void; - auto load() -> bool; - auto power(bool reset) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - enum GlobalRegister : uint { - MVOLL = 0x0c, MVOLR = 0x1c, - EVOLL = 0x2c, EVOLR = 0x3c, - KON = 0x4c, KOFF = 0x5c, - FLG = 0x6c, ENDX = 0x7c, - EFB = 0x0d, PMON = 0x2d, - NON = 0x3d, EON = 0x4d, - DIR = 0x5d, ESA = 0x6d, - EDL = 0x7d, FIR = 0x0f, //8 coefficients at 0x0f, 0x1f, ... 0x7f - }; - - enum VoiceRegister : uint { - VOLL = 0x00, VOLR = 0x01, - PITCHL = 0x02, PITCHH = 0x03, - SRCN = 0x04, ADSR0 = 0x05, - ADSR1 = 0x06, GAIN = 0x07, - ENVX = 0x08, OUTX = 0x09, - }; - - enum EnvelopeMode : uint { - EnvelopeRelease, - EnvelopeAttack, - EnvelopeDecay, - EnvelopeSustain, - }; - - enum : uint { - BrrBlockSize = 9, - CounterRange = 2048 * 5 * 3, //30720 (0x7800) - }; - - struct State { - uint8 regs[128]; - - int echoHistory[2][8] = {}; //echo history keeps most recent 8 stereo samples - uint3 echoHistoryOffset; - - bool everyOtherSample = 1; //toggles every sample - int kon = 0; //KON value when last checked - int noise = 0x4000; - int counter = 0; - int echoOffset = 0; //offset from ESA in echo buffer - int echoLength = 0; //number of bytes that echo_offset will stop at - - //hidden registers also written to when main register is written to - int konBuffer = 0; - int endxBuffer = 0; - int envxBuffer = 0; - int outxBuffer = 0; - - //temporary state between clocks (prefixed with _) - - //read once per sample - int _pmon = 0; - int _non = 0; - int _eon = 0; - int _dir = 0; - int _koff = 0; - - //read a few clocks ahead before used - int _brrNextAddress = 0; - int _adsr0 = 0; - int _brrHeader = 0; - int _brrByte = 0; - int _srcn = 0; - int _esa = 0; - int _echoDisabled = 0; - - //internal state that is recalculated every sample - int _dirAddress = 0; - int _pitch = 0; - int _output = 0; - int _looped = 0; - int _echoPointer = 0; - - //left/right sums - int _mainOut[2] = {}; - int _echoOut[2] = {}; - int _echoIn [2] = {}; - } state; - - struct Voice { - int buffer[12 * 3] = {}; //12 decoded samples (mirrored for wrapping) - int bufferOffset = 0; //place in buffer where next samples will be decoded - int gaussianOffset = 0; //relative fractional position in sample (0x1000 = 1.0) - int brrAddress = 0; //address of current BRR block - int brrOffset = 1; //current decoding offset in BRR block - int vbit = 0; //bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc - int vidx = 0; //voice channel register index: 0x00 for voice 0, 0x10 for voice 1, etc - int konDelay = 0; //KON delay/current setup phase - int envelopeMode = 0; - int envelope = 0; //current envelope level - int hiddenEnvelope = 0; //used by GAIN mode 7, very obscure quirk - int _envxOut = 0; - } voice[8]; - - //gaussian.cpp - static const int16 GaussianTable[512]; - auto gaussianInterpolate(const Voice& v) -> int; - - //counter.cpp - static const uint16 CounterRate[32]; - static const uint16 CounterOffset[32]; - auto counterTick() -> void; - auto counterPoll(uint rate) -> bool; - - //envelope.cpp - auto envelopeRun(Voice& v) -> void; - - //brr.cpp - auto brrDecode(Voice& v) -> void; - - //misc.cpp - auto misc27() -> void; - auto misc28() -> void; - auto misc29() -> void; - auto misc30() -> void; - - //voice.cpp - auto voiceOutput(Voice& v, bool channel) -> void; - auto voice1 (Voice& v) -> void; - auto voice2 (Voice& v) -> void; - auto voice3 (Voice& v) -> void; - auto voice3a(Voice& v) -> void; - auto voice3b(Voice& v) -> void; - auto voice3c(Voice& v) -> void; - auto voice4 (Voice& v) -> void; - auto voice5 (Voice& v) -> void; - auto voice6 (Voice& v) -> void; - auto voice7 (Voice& v) -> void; - auto voice8 (Voice& v) -> void; - auto voice9 (Voice& v) -> void; - - //echo.cpp - auto calculateFIR(bool channel, int index) -> int; - auto echoOutput(bool channel) -> int; - auto echoRead(bool channel) -> void; - auto echoWrite(bool channel) -> void; - auto echo22() -> void; - auto echo23() -> void; - auto echo24() -> void; - auto echo25() -> void; - auto echo26() -> void; - auto echo27() -> void; - auto echo28() -> void; - auto echo29() -> void; - auto echo30() -> void; - - //dsp.cpp - static auto Enter() -> void; - auto tick() -> void; - auto sample(int16 left, int16 right) -> void; -}; - -extern DSP dsp; diff --git a/higan/sfc/dsp/echo.cpp b/higan/sfc/dsp/echo.cpp deleted file mode 100644 index fb84c0dc..00000000 --- a/higan/sfc/dsp/echo.cpp +++ /dev/null @@ -1,130 +0,0 @@ -auto DSP::calculateFIR(bool channel, int index) -> int { - int sample = state.echoHistory[channel][(uint3)(state.echoHistoryOffset + index + 1)]; - return (sample * (int8)REG(FIR + index * 0x10)) >> 6; -} - -auto DSP::echoOutput(bool channel) -> int { - int output = (int16)((state._mainOut[channel] * (int8)REG(MVOLL + channel * 0x10)) >> 7) - + (int16)((state._echoIn [channel] * (int8)REG(EVOLL + channel * 0x10)) >> 7); - return sclamp<16>(output); -} - -auto DSP::echoRead(bool channel) -> void { - uint addr = state._echoPointer + channel * 2; - uint8 lo = apuram[(uint16)(addr + 0)]; - uint8 hi = apuram[(uint16)(addr + 1)]; - int s = (int16)((hi << 8) + lo); - state.echoHistory[channel][state.echoHistoryOffset] = s >> 1; -} - -auto DSP::echoWrite(bool channel) -> void { - if(!(state._echoDisabled & 0x20)) { - uint addr = state._echoPointer + channel * 2; - int s = state._echoOut[channel]; - apuram[(uint16)(addr + 0)] = s; - apuram[(uint16)(addr + 1)] = s >> 8; - } - - state._echoOut[channel] = 0; -} - -auto DSP::echo22() -> void { - //history - state.echoHistoryOffset++; - - state._echoPointer = (uint16)((state._esa << 8) + state.echoOffset); - echoRead(0); - - //FIR - int l = calculateFIR(0, 0); - int r = calculateFIR(1, 0); - - state._echoIn[0] = l; - state._echoIn[1] = r; -} - -auto DSP::echo23() -> void { - int l = calculateFIR(0, 1) + calculateFIR(0, 2); - int r = calculateFIR(1, 1) + calculateFIR(1, 2); - - state._echoIn[0] += l; - state._echoIn[1] += r; - - echoRead(1); -} - -auto DSP::echo24() -> void { - int l = calculateFIR(0, 3) + calculateFIR(0, 4) + calculateFIR(0, 5); - int r = calculateFIR(1, 3) + calculateFIR(1, 4) + calculateFIR(1, 5); - - state._echoIn[0] += l; - state._echoIn[1] += r; -} - -auto DSP::echo25() -> void { - int l = state._echoIn[0] + calculateFIR(0, 6); - int r = state._echoIn[1] + calculateFIR(1, 6); - - l = (int16)l; - r = (int16)r; - - l += (int16)calculateFIR(0, 7); - r += (int16)calculateFIR(1, 7); - - state._echoIn[0] = sclamp<16>(l) & ~1; - state._echoIn[1] = sclamp<16>(r) & ~1; -} - -auto DSP::echo26() -> void { - //left output volumes - //(save sample for next clock so we can output both together) - state._mainOut[0] = echoOutput(0); - - //echo feedback - int l = state._echoOut[0] + (int16)((state._echoIn[0] * (int8)REG(EFB)) >> 7); - int r = state._echoOut[1] + (int16)((state._echoIn[1] * (int8)REG(EFB)) >> 7); - - state._echoOut[0] = sclamp<16>(l) & ~1; - state._echoOut[1] = sclamp<16>(r) & ~1; -} - -auto DSP::echo27() -> void { - //output - int outl = state._mainOut[0]; - int outr = echoOutput(1); - state._mainOut[0] = 0; - state._mainOut[1] = 0; - - //todo: global muting isn't this simple - //(turns DAC on and off or something, causing small ~37-sample pulse when first muted) - if(REG(FLG) & 0x40) { - outl = 0; - outr = 0; - } - - //output sample to DAC - sample(outl, outr); -} - -auto DSP::echo28() -> void { - state._echoDisabled = REG(FLG); -} - -auto DSP::echo29() -> void { - state._esa = REG(ESA); - - if(!state.echoOffset) state.echoLength = (REG(EDL) & 0x0f) << 11; - - state.echoOffset += 4; - if(state.echoOffset >= state.echoLength) state.echoOffset = 0; - - //write left echo - echoWrite(0); - - state._echoDisabled = REG(FLG); -} - -auto DSP::echo30() -> void { - //write right echo - echoWrite(1); -} diff --git a/higan/sfc/dsp/envelope.cpp b/higan/sfc/dsp/envelope.cpp deleted file mode 100644 index 67f615ab..00000000 --- a/higan/sfc/dsp/envelope.cpp +++ /dev/null @@ -1,58 +0,0 @@ -auto DSP::envelopeRun(Voice& v) -> void { - int envelope = v.envelope; - - if(v.envelopeMode == EnvelopeRelease) { //60% - envelope -= 0x8; - if(envelope < 0) envelope = 0; - v.envelope = envelope; - return; - } - - int rate; - int envelopeData = VREG(ADSR1); - if(state._adsr0 & 0x80) { //99% ADSR - if(v.envelopeMode >= EnvelopeDecay) { //99% - envelope--; - envelope -= envelope >> 8; - rate = envelopeData & 0x1f; - if(v.envelopeMode == EnvelopeDecay) { //1% - rate = ((state._adsr0 >> 3) & 0x0e) + 0x10; - } - } else { //env_attack - rate = ((state._adsr0 & 0x0f) << 1) + 1; - envelope += rate < 31 ? 0x20 : 0x400; - } - } else { //GAIN - envelopeData = VREG(GAIN); - int mode = envelopeData >> 5; - if(mode < 4) { //direct - envelope = envelopeData << 4; - rate = 31; - } else { - rate = envelopeData & 0x1f; - if(mode == 4) { //4: linear decrease - envelope -= 0x20; - } else if(mode < 6) { //5: exponential decrease - envelope--; - envelope -= envelope >> 8; - } else { //6, 7: linear increase - envelope += 0x20; - if(mode > 6 && (uint)v.hiddenEnvelope >= 0x600) { - envelope += 0x8 - 0x20; //7: two-slope linear increase - } - } - } - } - - //sustain level - if((envelope >> 8) == (envelopeData >> 5) && v.envelopeMode == EnvelopeDecay) v.envelopeMode = EnvelopeSustain; - v.hiddenEnvelope = envelope; - - //uint cast because linear decrease underflowing also triggers this - if((uint)envelope > 0x7ff) { - envelope = (envelope < 0 ? 0 : 0x7ff); - if(v.envelopeMode == EnvelopeAttack) v.envelopeMode = EnvelopeDecay; - } - - if(counterPoll(rate)) v.envelope = envelope; -} diff --git a/higan/sfc/dsp/gaussian.cpp b/higan/sfc/dsp/gaussian.cpp deleted file mode 100644 index 3363473d..00000000 --- a/higan/sfc/dsp/gaussian.cpp +++ /dev/null @@ -1,50 +0,0 @@ -const int16 DSP::GaussianTable[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, - 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, - 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, - 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, - 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, - 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, - 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, - 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, - 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, - 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, - 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, - 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, - 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, - 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, - 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, - 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, - 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, - 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, - 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, - 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, - 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, - 969, 974, 978, 983, 988, 992, 997, 1001, 1005, 1010, 1014, 1019, 1023, 1027, 1032, 1036, - 1040, 1045, 1049, 1053, 1057, 1061, 1066, 1070, 1074, 1078, 1082, 1086, 1090, 1094, 1098, 1102, - 1106, 1109, 1113, 1117, 1121, 1125, 1128, 1132, 1136, 1139, 1143, 1146, 1150, 1153, 1157, 1160, - 1164, 1167, 1170, 1174, 1177, 1180, 1183, 1186, 1190, 1193, 1196, 1199, 1202, 1205, 1207, 1210, - 1213, 1216, 1219, 1221, 1224, 1227, 1229, 1232, 1234, 1237, 1239, 1241, 1244, 1246, 1248, 1251, - 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1270, 1272, 1274, 1275, 1277, 1279, 1280, - 1282, 1283, 1284, 1286, 1287, 1288, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1297, 1298, - 1299, 1300, 1300, 1301, 1302, 1302, 1303, 1303, 1303, 1304, 1304, 1304, 1304, 1304, 1305, 1305, -}; - -auto DSP::gaussianInterpolate(const Voice& v) -> int { - //make pointers into gaussian table based on fractional position between samples - uint8 offset = v.gaussianOffset >> 4; - const int16* forward = GaussianTable + 255 - offset; - const int16* reverse = GaussianTable + offset; //mirror left half of gaussian table - - offset = 12 + v.bufferOffset + (v.gaussianOffset >> 12); - int output; - output = (forward[ 0] * v.buffer[offset + 0]) >> 11; - output += (forward[256] * v.buffer[offset + 1]) >> 11; - output += (reverse[256] * v.buffer[offset + 2]) >> 11; - output = (int16)output; - output += (reverse[ 0] * v.buffer[offset + 3]) >> 11; - return sclamp<16>(output) & ~1; -} diff --git a/higan/sfc/dsp/misc.cpp b/higan/sfc/dsp/misc.cpp deleted file mode 100644 index 31434815..00000000 --- a/higan/sfc/dsp/misc.cpp +++ /dev/null @@ -1,31 +0,0 @@ -auto DSP::misc27() -> void { - state._pmon = REG(PMON) & ~1; //voice 0 doesn't support PMON -} - -auto DSP::misc28() -> void { - state._non = REG(NON); - state._eon = REG(EON); - state._dir = REG(DIR); -} - -auto DSP::misc29() -> void { - state.everyOtherSample ^= 1; - if(state.everyOtherSample) { - state.konBuffer &= ~state.kon; //clears KON 63 clocks after it was last read - } -} - -auto DSP::misc30() -> void { - if(state.everyOtherSample) { - state.kon = state.konBuffer; - state._koff = REG(KOFF); - } - - counterTick(); - - //noise - if(counterPoll(REG(FLG) & 0x1f)) { - int feedback = (state.noise << 13) ^ (state.noise << 14); - state.noise = (feedback & 0x4000) ^ (state.noise >> 1); - } -} diff --git a/higan/sfc/dsp/serialization.cpp b/higan/sfc/dsp/serialization.cpp deleted file mode 100644 index 8518b667..00000000 --- a/higan/sfc/dsp/serialization.cpp +++ /dev/null @@ -1,61 +0,0 @@ -void DSP::serialize(serializer& s) { - Thread::serialize(s); - - s.array(apuram); - - s.array(state.regs, 128); - s.array(state.echoHistory[0]); - s.array(state.echoHistory[1]); - s.integer(state.echoHistoryOffset); - - s.integer(state.everyOtherSample); - s.integer(state.kon); - s.integer(state.noise); - s.integer(state.counter); - s.integer(state.echoOffset); - s.integer(state.echoLength); - - s.integer(state.konBuffer); - s.integer(state.endxBuffer); - s.integer(state.envxBuffer); - s.integer(state.outxBuffer); - - s.integer(state._pmon); - s.integer(state._non); - s.integer(state._eon); - s.integer(state._dir); - s.integer(state._koff); - - s.integer(state._brrNextAddress); - s.integer(state._adsr0); - s.integer(state._brrHeader); - s.integer(state._brrByte); - s.integer(state._srcn); - s.integer(state._esa); - s.integer(state._echoDisabled); - - s.integer(state._dirAddress); - s.integer(state._pitch); - s.integer(state._output); - s.integer(state._looped); - s.integer(state._echoPointer); - - s.array(state._mainOut, 2); - s.array(state._echoOut, 2); - s.array(state._echoIn, 2); - - for(auto n : range(8)) { - s.array(voice[n].buffer); - s.integer(voice[n].bufferOffset); - s.integer(voice[n].gaussianOffset); - s.integer(voice[n].brrAddress); - s.integer(voice[n].brrOffset); - s.integer(voice[n].vbit); - s.integer(voice[n].vidx); - s.integer(voice[n].konDelay); - s.integer(voice[n].envelopeMode); - s.integer(voice[n].envelope); - s.integer(voice[n].hiddenEnvelope); - s.integer(voice[n]._envxOut); - } -} diff --git a/higan/sfc/dsp/voice.cpp b/higan/sfc/dsp/voice.cpp deleted file mode 100644 index 14f5dca4..00000000 --- a/higan/sfc/dsp/voice.cpp +++ /dev/null @@ -1,170 +0,0 @@ -inline auto DSP::voiceOutput(Voice& v, bool channel) -> void { - //apply left/right volume - int amp = (state._output * (int8)VREG(VOLL + channel)) >> 7; - - //add to output total - state._mainOut[channel] += amp; - state._mainOut[channel] = sclamp<16>(state._mainOut[channel]); - - //optionally add to echo total - if(state._eon & v.vbit) { - state._echoOut[channel] += amp; - state._echoOut[channel] = sclamp<16>(state._echoOut[channel]); - } -} - -auto DSP::voice1(Voice& v) -> void { - state._dirAddress = (state._dir << 8) + (state._srcn << 2); - state._srcn = VREG(SRCN); -} - -auto DSP::voice2(Voice& v) -> void { - //read sample pointer (ignored if not needed) - uint16 addr = state._dirAddress; - if(!v.konDelay) addr += 2; - uint8 lo = apuram[(uint16)(addr + 0)]; - uint8 hi = apuram[(uint16)(addr + 1)]; - state._brrNextAddress = ((hi << 8) + lo); - - state._adsr0 = VREG(ADSR0); - - //read pitch, spread over two clocks - state._pitch = VREG(PITCHL); -} - -auto DSP::voice3(Voice& v) -> void { - voice3a(v); - voice3b(v); - voice3c(v); -} - -auto DSP::voice3a(Voice& v) -> void { - state._pitch += (VREG(PITCHH) & 0x3f) << 8; -} - -auto DSP::voice3b(Voice& v) -> void { - state._brrByte = apuram[(uint16)(v.brrAddress + v.brrOffset)]; - state._brrHeader = apuram[(uint16)(v.brrAddress)]; -} - -auto DSP::voice3c(Voice& v) -> void { - //pitch modulation using previous voice's output - - if(state._pmon & v.vbit) { - state._pitch += ((state._output >> 5) * state._pitch) >> 10; - } - - if(v.konDelay) { - //get ready to start BRR decoding on next sample - if(v.konDelay == 5) { - v.brrAddress = state._brrNextAddress; - v.brrOffset = 1; - v.bufferOffset = 0; - state._brrHeader = 0; //header is ignored on this sample - } - - //envelope is never run during KON - v.envelope = 0; - v.hiddenEnvelope = 0; - - //disable BRR decoding until last three samples - v.gaussianOffset = 0; - v.konDelay--; - if(v.konDelay & 3) v.gaussianOffset = 0x4000; - - //pitch is never added during KON - state._pitch = 0; - } - - //gaussian interpolation - int output = gaussianInterpolate(v); - - //noise - if(state._non & v.vbit) { - output = (int16)(state.noise << 1); - } - - //apply envelope - state._output = ((output * v.envelope) >> 11) & ~1; - v._envxOut = v.envelope >> 4; - - //immediate silence due to end of sample or soft reset - if(REG(FLG) & 0x80 || (state._brrHeader & 3) == 1) { - v.envelopeMode = EnvelopeRelease; - v.envelope = 0; - } - - if(state.everyOtherSample) { - //KOFF - if(state._koff & v.vbit) { - v.envelopeMode = EnvelopeRelease; - } - - //KON - if(state.kon & v.vbit) { - v.konDelay = 5; - v.envelopeMode = EnvelopeAttack; - } - } - - //run envelope for next sample - if(!v.konDelay) envelopeRun(v); -} - -auto DSP::voice4(Voice& v) -> void { - //decode BRR - state._looped = 0; - if(v.gaussianOffset >= 0x4000) { - brrDecode(v); - v.brrOffset += 2; - if(v.brrOffset >= 9) { - //start decoding next BRR block - v.brrAddress = (uint16)(v.brrAddress + 9); - if(state._brrHeader & 1) { - v.brrAddress = state._brrNextAddress; - state._looped = v.vbit; - } - v.brrOffset = 1; - } - } - - //apply pitch - v.gaussianOffset = (v.gaussianOffset & 0x3fff) + state._pitch; - - //keep from getting too far ahead (when using pitch modulation) - if(v.gaussianOffset > 0x7fff) v.gaussianOffset = 0x7fff; - - //output left - voiceOutput(v, 0); -} - -auto DSP::voice5(Voice& v) -> void { - //output right - voiceOutput(v, 1); - - //ENDX, OUTX and ENVX won't update if you wrote to them 1-2 clocks earlier - state.endxBuffer = REG(ENDX) | state._looped; - - //clear bit in ENDX if KON just began - if(v.konDelay == 5) state.endxBuffer &= ~v.vbit; -} - -auto DSP::voice6(Voice& v) -> void { - state.outxBuffer = state._output >> 8; -} - -auto DSP::voice7(Voice& v) -> void { - //update ENDX - REG(ENDX) = (uint8)state.endxBuffer; - state.envxBuffer = v._envxOut; -} - -auto DSP::voice8(Voice& v) -> void { - //update OUTX - VREG(OUTX) = (uint8)state.outxBuffer; -} - -auto DSP::voice9(Voice& v) -> void { - //update ENVX - VREG(ENVX) = (uint8)state.envxBuffer; -} diff --git a/higan/sfc/ppu-fast/mode7.cpp b/higan/sfc/ppu-fast/mode7.cpp deleted file mode 100644 index 5f9668fe..00000000 --- a/higan/sfc/ppu-fast/mode7.cpp +++ /dev/null @@ -1,103 +0,0 @@ -auto PPU::Line::renderMode7(PPU::IO::Background& self, uint source) -> void { - int Y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0); - int y = !io.mode7.vflip ? Y : 255 - Y; - - int a = (int16)io.mode7.a; - int b = (int16)io.mode7.b; - int c = (int16)io.mode7.c; - int d = (int16)io.mode7.d; - int hcenter = (int13)io.mode7.x; - int vcenter = (int13)io.mode7.y; - int hoffset = (int13)io.mode7.hoffset; - int voffset = (int13)io.mode7.voffset; - - uint mosaicCounter = 1; - uint mosaicPalette = 0; - uint mosaicPriority = 0; - uint mosaicColor = 0; - - auto clip = [](int n) -> int { return n & 0x2000 ? (n | ~1023) : (n & 1023); }; - int originX = (a * clip(hoffset - hcenter) & ~63) + (b * clip(voffset - vcenter) & ~63) + (b * y & ~63) + (hcenter << 8); - int originY = (c * clip(hoffset - hcenter) & ~63) + (d * clip(voffset - vcenter) & ~63) + (d * y & ~63) + (vcenter << 8); - - array windowAbove; - array windowBelow; - renderWindow(self.window, self.window.aboveEnable, windowAbove); - renderWindow(self.window, self.window.belowEnable, windowBelow); - - if(!configuration.hacks.ppuFast.hiresMode7) { - for(int X : range(256)) { - int x = !io.mode7.hflip ? X : 255 - X; - int pixelX = originX + a * x >> 8; - int pixelY = originY + c * x >> 8; - int tileX = pixelX >> 3 & 127; - int tileY = pixelY >> 3 & 127; - bool outOfBounds = (pixelX | pixelY) & ~1023; - uint15 tileAddress = tileY * 128 + tileX; - uint15 paletteAddress = ((pixelY & 7) << 3) + (pixelX & 7); - uint8 tile = io.mode7.repeat == 3 && outOfBounds ? 0 : ppu.vram[tileAddress].byte(0); - uint8 palette = io.mode7.repeat == 2 && outOfBounds ? 0 : ppu.vram[paletteAddress + (tile << 6)].byte(1); - - uint priority; - if(source == Source::BG1) { - priority = self.priority[0]; - } else if(source == Source::BG2) { - priority = self.priority[palette >> 7]; - palette &= 0x7f; - } - - if(!self.mosaicEnable || --mosaicCounter == 0) { - mosaicCounter = 1 + io.mosaicSize; - mosaicPalette = palette; - mosaicPriority = priority; - if(io.col.directColor && source == Source::BG1) { - mosaicColor = directColor(0, palette); - } else { - mosaicColor = cgram[palette]; - } - } - if(!mosaicPalette) continue; - - if(self.aboveEnable && !windowAbove[X]) plotAbove(X, source, mosaicPriority, mosaicColor); - if(self.belowEnable && !windowBelow[X]) plotBelow(X, source, mosaicPriority, mosaicColor); - } - } else { - //emulator enhancement option: render 512 pixels instead of 256 pixels of horizontal resolution - //note: this mode is impossible on real hardware due to needing 512 above+below pixels - for(int X : range(512)) { - int x = !io.mode7.hflip ? X : 511 - X; - int pixelX = 2 * originX + a * x >> 9; - int pixelY = 2 * originY + c * x >> 9; - int tileX = pixelX >> 3 & 127; - int tileY = pixelY >> 3 & 127; - bool outOfBounds = (pixelX | pixelY) & ~1023; - uint15 tileAddress = tileY * 128 + tileX; - uint15 paletteAddress = ((pixelY & 7) << 3) + (pixelX & 7); - uint8 tile = io.mode7.repeat == 3 && outOfBounds ? 0 : ppu.vram[tileAddress].byte(0); - uint8 palette = io.mode7.repeat == 2 && outOfBounds ? 0 : ppu.vram[paletteAddress + (tile << 6)].byte(1); - - uint priority; - if(source == Source::BG1) { - priority = self.priority[0]; - } else if(source == Source::BG2) { - priority = self.priority[palette >> 7]; - palette &= 0x7f; - } - - if(!self.mosaicEnable || !io.mosaicSize || --mosaicCounter == 0) { - mosaicCounter = (1 + io.mosaicSize) << 1; - mosaicPalette = palette; - mosaicPriority = priority; - if(io.col.directColor && source == Source::BG1) { - mosaicColor = directColor(0, palette); - } else { - mosaicColor = cgram[palette]; - } - } - if(!mosaicPalette) continue; - - if(self.aboveEnable && !windowAbove[X >> 1]) plotAbove(X >> 1 | (X & 1 ? 256 : 0), source, mosaicPriority, mosaicColor); - if(self.belowEnable && !windowBelow[X >> 1]) plotBelow(X >> 1 | (X & 1 ? 256 : 0), source, mosaicPriority, mosaicColor); - } - } -} diff --git a/higan/sfc/ppu-fast/ppu.cpp b/higan/sfc/ppu-fast/ppu.cpp deleted file mode 100644 index 76a270ff..00000000 --- a/higan/sfc/ppu-fast/ppu.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include - -namespace SuperFamicom { - -PPU& ppubase = ppu; -#define PPU PPUfast -#define ppu ppufast - -PPU ppu; -#include "io.cpp" -#include "line.cpp" -#include "background.cpp" -#include "mode7.cpp" -#include "object.cpp" -#include "window.cpp" -#include "serialization.cpp" - -auto PPU::interlace() const -> bool { return ppubase.display.interlace; } -auto PPU::overscan() const -> bool { return ppubase.display.overscan; } -auto PPU::vdisp() const -> uint { return ppubase.display.vdisp; } -auto PPU::hires() const -> bool { return latch.hires; } - -PPU::PPU() { - output = new uint32[512 * 512] + 16 * 512; //overscan offset - tilecache[TileMode::BPP2] = new uint8[4096 * 8 * 8]; - tilecache[TileMode::BPP4] = new uint8[2048 * 8 * 8]; - tilecache[TileMode::BPP8] = new uint8[1024 * 8 * 8]; - - for(uint y : range(lines.size())) { - lines[y].y = y; - } -} - -PPU::~PPU() { - delete[] (output - 16 * 512); //overscan offset - delete[] tilecache[TileMode::BPP2]; - delete[] tilecache[TileMode::BPP4]; - delete[] tilecache[TileMode::BPP8]; -} - -auto PPU::Enter() -> void { - while(true) scheduler.synchronize(), ppu.main(); -} - -auto PPU::step(uint clocks) -> void { - tick(clocks); - Thread::step(clocks); - synchronize(cpu); -} - -auto PPU::main() -> void { - scanline(); - uint y = vcounter(); - step(512); - if(y >= 1 && y <= 239) { - if(io.displayDisable || y >= vdisp()) { - lines[y].io.displayDisable = true; - } else { - memcpy(&lines[y].io, &io, sizeof(io)); - memcpy(&lines[y].cgram, &cgram, sizeof(cgram)); - } - if(!Line::count) Line::start = y; - Line::count++; - } - step(lineclocks() - hcounter()); -} - -auto PPU::scanline() -> void { - if(vcounter() == 0) { - ppubase.display.interlace = io.interlace; - ppubase.display.overscan = io.overscan; - latch.hires = false; - io.obj.timeOver = false; - io.obj.rangeOver = false; - } - - if(vcounter() > 0 && vcounter() < vdisp()) { - latch.hires |= io.pseudoHires || io.bgMode == 5 || io.bgMode == 6; - latch.hires |= io.bgMode == 7 && configuration.hacks.ppuFast.hiresMode7; - } - - if(vcounter() == vdisp() && !io.displayDisable) { - oamAddressReset(); - } - - if(vcounter() == 240) { - Line::flush(); - scheduler.exit(Scheduler::Event::Frame); - } -} - -auto PPU::refresh() -> void { - auto output = this->output; - if(!overscan()) output -= 14 * 512; - auto pitch = 512 << !interlace(); - auto width = 256 << hires(); - auto height = 240 << interlace(); - Emulator::video.setEffect(Emulator::Video::Effect::ColorBleed, configuration.video.blurEmulation && hires()); - Emulator::video.refresh(output, pitch * sizeof(uint32), width, height); -} - -auto PPU::load() -> bool { - return true; -} - -auto PPU::power(bool reset) -> void { - create(Enter, system.cpuFrequency()); - PPUcounter::reset(); - memory::fill(output, 512 * 480); - - function uint8> reader{&PPU::readIO, this}; - function void> writer{&PPU::writeIO, this}; - bus.map(reader, writer, "00-3f,80-bf:2100-213f"); - - if(!reset) { - for(auto address : range(32768)) { - vram[address] = 0x0000; - updateTiledata(address); - } - for(auto& color : cgram) color = 0x0000; - for(auto& object : objects) object = {}; - } - - latch = {}; - io = {}; - updateVideoMode(); - - ItemLimit = !configuration.hacks.ppuFast.noSpriteLimit ? 32 : 128; - TileLimit = !configuration.hacks.ppuFast.noSpriteLimit ? 34 : 128; - - Line::start = 0; - Line::count = 0; -} - -} diff --git a/higan/systems/ColecoVision.sys/manifest.bml b/higan/systems/ColecoVision.sys/manifest.bml deleted file mode 100644 index ab2c76fe..00000000 --- a/higan/systems/ColecoVision.sys/manifest.bml +++ /dev/null @@ -1 +0,0 @@ -system name:ColecoVision diff --git a/higan/systems/Famicom.sys/manifest.bml b/higan/systems/Famicom.sys/manifest.bml deleted file mode 100644 index 231fa137..00000000 --- a/higan/systems/Famicom.sys/manifest.bml +++ /dev/null @@ -1 +0,0 @@ -system name:Famicom diff --git a/higan/systems/Game Boy Advance.sys/manifest.bml b/higan/systems/Game Boy Advance.sys/manifest.bml deleted file mode 100644 index c4db4051..00000000 --- a/higan/systems/Game Boy Advance.sys/manifest.bml +++ /dev/null @@ -1,3 +0,0 @@ -system name:Game Boy Advance - cpu - rom name=bios.rom size=16384 diff --git a/higan/systems/Game Gear.sys/manifest.bml b/higan/systems/Game Gear.sys/manifest.bml deleted file mode 100644 index 41f40dcb..00000000 --- a/higan/systems/Game Gear.sys/manifest.bml +++ /dev/null @@ -1 +0,0 @@ -system name:Game Gear diff --git a/higan/systems/MSX.sys/bios.rom b/higan/systems/MSX.sys/bios.rom deleted file mode 100644 index 041fcf0fe093f4f5829256e6ba778a37d2d92b3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeHQe_T`7*+04Ybz}LFfWQS?y-CnU+CiFiljX%21Po3k8DQ17UBxO@Hw#R#1b@)j zcU{>}S>JancJI5|b}Omf2F_M=tqQ%P^OoLC-V7^6R?;`k-DD_Y_ zLwUPSPauSt&*&hBGDtC1I%cDe$tD;B!4wiq1;MN%nDqoxM=%c&%t3;Al3;#JFux`c zbAK+gP|iFmXI_&tN(EDVf{9Hu&lxi5$Lf{xj* zV-D$7?0 z4)e7f<~YR+QVdHm?@&xr9>By3VEqGUP8HH<7#(rOXi^%D+6Y@^d~oOc)(Jj%){!RT z3JDhK)AnSYA3Ejs9d4WU_zuSc`geFYXt(-VZap!L#=6)rS4V_=T`YgVcX)qr1qjVm zr|p=)?YE@3OPwhorKDr2bOh@Lu3%KrcC!Qcp*5zUA`@9-baH`RIg@4(R zriSr^`fqUcAMhs%&hj!EB^?jn;yy-S3$Y*#!my^nQr|hQQjRSuinRr%=;FmPM1X~0 zI`Q9`kBlp+=mgB4oG&=e8w}BcKHiWYEjYy+Owoc@c*Bw?_iKVX zq~N@2j#D#d2&^v?_2)D}qTsZkJRm3!VzmMWn*cRy5AKEQQ*bqM?$VqI0!(1NUtm4( zUM270eO)DVOdE|A3<+j9!G~W7J_H5r$egx3sXd(3?nzVe;f0E@iUu3nSm-wTqtNSg zDt#qZFe2D`ORzO6*veI6Ptr&jjP)Hp7;>Z`m?*pkFHdV7DNxrP=hKKD?z76w%oJR( ze<~+RolZ(&k(6K!^t`L+E?0Fe!e}WW#C)hqh8S4B+IT7* zg-0x=N`@n`CPpLc^z}ZIR#1Dpj!3A1E|xtW2+GqNgPtGd3}xjU$l-m5ZQt@8_Cr8p zxqwQDaUZIL7zZtfe22#lhkL|YEX0l-mLa@!WwHsJ6GC0?!F2_Wr81I){KivyNo_-V zL_!FG2x1HC5e=aTsxoyL#Pnxj3lPzZ~ zI*qjU@(GiyUtUbgJZefVL-GPc)J9|LGW}0ut-9keSq_@)WhydyWQZ!rk2VfMeY_Q+A;*3ElJMWid7-e*|Q|qj*5IBqGI2E;}wbgh$cO^O16{Y2Z$jXmJ1iCs&SJi;s zjaX${lH;f?tq}+PaFXMys$E^R8q0LdSt%>668brO6Jss18GVJ^iy9m96|(KdzH`1J zDiTaj%rh%rH~Wg%*Ox&iJYL*!O$fg1evZ)`fbT#2!2|X}DM<+Y-4S5N{WE^N@r{x= zkFmB#eJ|QvzN0<9*%Du(#5Ysoi|c1+N5{O=Qx3P!Yn`1fnx1mDS!QSTXx5hAdWI&8 zAd@equIBIWGi8mwTC6n5N2!!Tw0+b)>KJVsb&j@O&^paS?h9In`IXTFeI}JIyqI}B z5A0z>qk63SsLSp68fSgpv~0hm3?C6YG)0-wsCtSUF}?_XXCmz;<6R!)39^s2jV?}6MAIl zcBZ}gFm_O^3_W5}y{;JAZhFseED6f#G1dV-8^dm#ZwPI6vjJ{Xn!a=;r`Ngtc*i)6 zeGP>jLHX-u?j@aj$Zblu72+D46-1sb6-e7W$U=Ujk&C36vYaF1{_u={>~P=p6KUZ9 zAi(=Wa9o5oV(5Lb2#H115lq?a#(P=Ne0=kMDCEasEcm4LB{w?=?(9A89$ldqcs&XM0mq>e$-GI9|ens&&CZc)B1l|tn=`)JS+i+xZ^w=0t|hS zQ-;%!(}uH4?oX9y%L?w4%{E&M$uqjwiyE@3^FFc-@c){6<+G?~zt-tU8>z_ zyZ>kX2VTLN7M-Z+sHolKsz&6fzukDh@gAeNA_L?oT$e07WJ~AZ`ofw63R{y3u+y)q zT7x(HJxNYYZFTLs8WanR6kO*g?~U-6ZL_qj2M*udYcn4+X+`W|>S}w~cpyR1a=e(X z^C1utPWwNY!G}P?oEZvpiusVet>bd%0|b^W)51BP(`B7EWrVHW@xIqiXN2H|q9F0e z8`GKGX^1gI!6hDm%YU_4VYtMzx?`~=D7U8-xZJJ`rZ7X5qVJf`kOUkauj;^PP@Ry` zS6QrejKA}=SrgzYGPur6|0l4zUM9l@SC|O`0k8lQpg+c+F~e~;1Gvzgq=n03U>Ox$w?VRS8nxH`x`;aW3h=SqlLVNy%|dtTd$P$VGBk@a z<`rh#Qjw8zLY=xRW5Mo>TiqGAJ(01nJ7ZCA#urYgD^94_6lQ*QZN{!UGS{xnT-TYo zDJ8SCJ7Z;UMp;&7xgoQ%BEzl7Y$G$d6SHA%adt7u$+Jw;Au0uSlj-?AmaLCL%h<5* z+i;}rEb?`Rx>@d(*|E+=i)^!ISy4BB(w~p_oN1-W5G?u3R!SF2*o!rZI z1mT%(?=xju#ddg%U!BHJ7Lz;QM#G~%{Z0r};RX_X#HmLtC`6$PS#M=g=MK^|7PDscE(E=-3NEZNEUM1cK;ahVfdPEk?%GHDy)st_K&h zz}%8#uB@nVA?zcLe@PyM!iFS=X(aO1AIruo@M)N zX(m~T??raZ%lf=d5i>$XTYI|vU=F4%3(!FMJ_!SsOs zY7RcKwEG8OZH_EN%i*8{XF8s{FDDi}dwjF7;n>my8szow=HN@7_F*hOt)T=cdss)UtF#;=xlQC?M)_LAJw>fj7~4CI#^+&=W`S%k zaTvdQ&TTXXp18I`#O`f z3{zIV)`bee4Qp|1BpZERUmD9@xVX=x$X!lFhgsNP;RGh^n4=`#H)jIl0q&_8I6zu1 z^H-~Kxu<6ez8^Olz8~+gjK-|f{Bp}QPcO5{q3GcVswgP4{Ep|g<`zU?r@qc#rWaVR zfzUOc&VYlTZ1$Ef8MSd}hd^+R|I>E~?!wGu1)glD>K1(<)`q9N)tI849tT}rAZEQ1 zOV^)SQY_d1VM*F8dE;l$&tJ+d8h;*2!RFUb$c@Q(ljhU(E+7e27T>qQfsf%Ga z^IzlP&J9>5bwXjfmC4L=C*-ukhA4f4fKo=~LiG9+>}oo9f&_+~A`@ylAGSCIH+A?_ ztbZhe7uJ=$ZWB4e(Rss})JJeJM`_x-P09c;{2}I9JnYsR=Z_Hqf#Gu)QaF>1`&n`n z-xN-62#?MLtdZ+*G$-Lq4*6*4-TU)ma77dvC0Qx~uNykU5_sW($@An13q_~KG+gGa zEUiIfhxICxDkbgkhX2qoA?M^dI8n$>oN)#^ANHR+u#QY`adkjy!LK7n&<1v z%!3kMTmJ5El7CMJN>={xhs^1fB_-`+W2c$+l3hoiC@(i@k=9iHs8ALcUr1aiM%v>2 z`*8`0q9B`{oxOY+vXYetA+0Q7PPaok&7>&ErjCv#gm6wb(X`oQq9^)MaY=sudzUDr zEiXP=Tn_fN+G6a3o2AGSmcbFg#u_hKa5N2cT@~Ae%fO86nLi z=4;Kah*k@Kz~3V>4J6`FNyobcEL|9-r*KX zmrJ0%UhhSqU9=0^1!IC-1Wz*b*M#Q<{6oTo1C8egX!{Z1-AECbw>iSy(FOf`JlF%w zb9+3{A4$4}e!)W51kmP6yL|#oLp$(cuCP4xPop|v{90tjJ=J+UT}LLm0B(>K{6JIS zFt#hogFRvV;)pQ3kJye^K*Vg1 zz`CJnI}L*aP;f$aAb^EjN3bj;+T{YVzGcIXb@Q=vV+k5hSho=~Dow66h zV_?llZ*on6L4-`_Vc|jv9%4M82k5W~mOVVVxIah}9-%-JG?eyAm$|aD z7?-AvCrMZzG$cWwva?bsJ1aZEE;x?yFeUK@TENMa#Lbi(7nZ~Qm|WlvjNgO@4rLra zpT8r`mFS{SPV6xM4)^CW34LH7#r0C@qIY-^+7GL6hsjh9&sT>SQLx=Yz?ViY1e z#Piv?=!#HDi69~J`jZLEVx4$0$&+bCGU*KE9r)W(ZqVUxVt=tV=@H&T5}y8vsfm6M zlF8NSYPk%}wwF*;N&DP9FD#(;SW4KKaQv-^5?opiKLr0dFI)kwDGW z;dTA-D6r>P2Pe@|db&6oY;i{?jyrV__c~z)BM|rS^A~YJssy@{ws%CZoV!z;=Z=nZ zy;uUm5d4F^&Fh5>&mwNe)8)Ddal&q{6rWp{7yE;>Sk4Xtu-=n$cwHeJma%}uHZJkHnM?g32hudi@94$E2($hBw`y0o+&ftodecpXRdE@>iateO-e!*_OzQ1TY zzNFmzgO|ZdW1G(lHsEdJ09ezsvU{QXegF?t!PY(yxgmiCn&EBkeoF51Hp49@)Jd+3 zCqq!OdNw?445vAMAM!NP|6mehG=JGSiJvbCjtH{D#{Vx`yDq|RI2 z0OamHO)d0;yX(KSr@mopo0a~wxpHsnyfyW04>WGsy^U^ZYpNHeQ|I9iTHUa-1z*wA zI~(ZcU5#K0m2GKgXl$YD-Su1dwA9mEXgFQ3F2h2Fpiog=?X0${ zdm6TZ>C}0(J9akH57+N*-r3kdH$F%wG1$7LA$4A3!>%^ExdpU7R&53?*RJ|4&Gq!| zda9@x6A{=w}#c7EZDyB=z2Z2Hpf=9WDVx4PT*F4fzO z`HSygQefJA$Nqf>tcLay+X_^=vaGyfm7{X?XVZ&LrA(VzFLTXWOrp_w>B zVK{dzn#v~96!L37>6u0ebba8Lzt&!O=Z)X6DL&?{p%;eH;K=#t(a4pjN6&t*Yr=o| z@jtweCg1Km75K{Y-RR3te)H?!_>Y6fp859imxDie_PKxi_pg5U(eHG8?Z{&nfBgM3 z|M_1Cz3YKs@VgIAoP6&P@}h6y$Z+_nUi8FIUqU}bzr~~&HgHW$3p9vCsdNfLw=G8MH zG=H^K_-Q^X-ZR2IUQ7K$^$jh}^p@TAG`@=5`B2j?fmOeaZmVzkTTGMGhlGHHfP{dA zfP{dAfP{dAfP{dAfP{dAfP{dAfP{dAfP{dAfP{dAfP{dAfP{dAfP{dAfP{dAfP{dA zfP{dAfP{dAfP{dAfP{dAfP{dAfP{dAz+V&r_%(@tQG1dx2>}TK2>}TK2>}TK2>}TK z2>}TK2>}TK2>}TK34wnK1f)Ou_D?a*(jX-SBn1Ad2*5A4FdPtnvBjQ-FE%u`HrSVy z-?a>V<^cRXG8z2s3wB)pn2cHR|MIU+z~C3P|HU6G3(%J^b9UF^Be8|g zBk8wdBU()Wl+Tu9;a~t*4)>M7BQ093VR?6Yj+fK##FmT+-93c6_hRdQOV@SK(;viU zCXQ5$8^T@~zzbY1>1Z7QHC)#q5C|LbwrN~ryOndmFpA#K^7GeUMRKDC!<*1Kx;p>U zh{KSvntmg;%;g$nwmBA@dIBv-T&LP$DS^64Mw(K430UwGz^i2j`N%T<=7I-ekYs^; zIQSSK)G0e}JyxaMW{G^}OFZ|7(dsA%II);s!Cd5d7OPgyWB&LA$5p`3q#Om{iT-gu zZhkxyf4YKawvBcEHcPRPC?gYVBnFzF+o zcy2Cl?ecfWiHyVHQ~kuN*G_(k`*Swb$|Q~yB>u%n0Qt?vLiqUfF*9mNqbgL+-Pua5 zksrdkaj&z6dysjlC-h-HT}NZoU%f}tulMigdi|5Gs>g{XO~-cUs~m29e!kZmY5Mt2 zE!3UN*TCQFe7)LSo;$mIcduqrmwNc8DDyYsbbeGXJ?Qu0bc*!;Dr^Ui@t(H(KA?be zj_6=cUNtGdEMdow`^FHUMIsOZjYrfPJ-F65`4uiP+C^k6&Q2^>IPM)jDoL*5OB^90 zN<&ro$el`npVxvtn=MURS$^XlpS1-q&15Z`Pftx+GewK%?AhC*XyqsRteH8>F4$8= vtH`J4vJb%M#_y;GFt{kcY^CUe4ISOLf;r7B4OTM0S{LXNGHdv6;Gc~@Fa0oj diff --git a/higan/systems/Neo Geo Pocket Color.sys/manifest.bml b/higan/systems/Neo Geo Pocket Color.sys/manifest.bml deleted file mode 100644 index ff78dcc2..00000000 --- a/higan/systems/Neo Geo Pocket Color.sys/manifest.bml +++ /dev/null @@ -1,2 +0,0 @@ -system name:Neo Geo Pocket Color - bios name=bios.rom size=0x10000 diff --git a/higan/systems/Neo Geo Pocket.sys/manifest.bml b/higan/systems/Neo Geo Pocket.sys/manifest.bml deleted file mode 100644 index f8b83e07..00000000 --- a/higan/systems/Neo Geo Pocket.sys/manifest.bml +++ /dev/null @@ -1,2 +0,0 @@ -system name:Neo Geo Pocket - bios name=bios.rom size=0x10000 diff --git a/higan/systems/PC Engine.sys/manifest.bml b/higan/systems/PC Engine.sys/manifest.bml deleted file mode 100644 index fa4735f6..00000000 --- a/higan/systems/PC Engine.sys/manifest.bml +++ /dev/null @@ -1 +0,0 @@ -system name:PC Engine diff --git a/higan/systems/Pocket Challenge V2.sys/manifest.bml b/higan/systems/Pocket Challenge V2.sys/manifest.bml deleted file mode 100644 index 5a24ecb5..00000000 --- a/higan/systems/Pocket Challenge V2.sys/manifest.bml +++ /dev/null @@ -1,2 +0,0 @@ -system name:Pocket Challenge V2 - eeprom name=internal.ram size=128 diff --git a/higan/systems/SC-3000.sys/manifest.bml b/higan/systems/SC-3000.sys/manifest.bml deleted file mode 100644 index fa6204a1..00000000 --- a/higan/systems/SC-3000.sys/manifest.bml +++ /dev/null @@ -1 +0,0 @@ -system name:SC-3000 diff --git a/higan/systems/SG-1000.sys/manifest.bml b/higan/systems/SG-1000.sys/manifest.bml deleted file mode 100644 index 4b1d86f1..00000000 --- a/higan/systems/SG-1000.sys/manifest.bml +++ /dev/null @@ -1 +0,0 @@ -system name:SG-1000 diff --git a/higan/systems/SuperGrafx.sys/manifest.bml b/higan/systems/SuperGrafx.sys/manifest.bml deleted file mode 100644 index 5bbc7066..00000000 --- a/higan/systems/SuperGrafx.sys/manifest.bml +++ /dev/null @@ -1 +0,0 @@ -system name:SuperGrafx diff --git a/higan/systems/WonderSwan Color.sys/manifest.bml b/higan/systems/WonderSwan Color.sys/manifest.bml deleted file mode 100644 index 3422d5f1..00000000 --- a/higan/systems/WonderSwan Color.sys/manifest.bml +++ /dev/null @@ -1,2 +0,0 @@ -system name:WonderSwan Color - eeprom name=internal.ram size=2048 diff --git a/higan/systems/WonderSwan.sys/manifest.bml b/higan/systems/WonderSwan.sys/manifest.bml deleted file mode 100644 index 26aa0503..00000000 --- a/higan/systems/WonderSwan.sys/manifest.bml +++ /dev/null @@ -1,2 +0,0 @@ -system name:WonderSwan - eeprom name=internal.ram size=128 diff --git a/higan/target-bsnes/settings/emulator.cpp b/higan/target-bsnes/settings/emulator.cpp deleted file mode 100644 index 52641c80..00000000 --- a/higan/target-bsnes/settings/emulator.cpp +++ /dev/null @@ -1,82 +0,0 @@ -auto EmulatorSettings::create() -> void { - setIcon(Icon::Action::Settings); - setText("Emulator"); - - layout.setPadding(5_sx); - - optionsLabel.setText("Options").setFont(Font().setBold()); - inputFocusLabel.setText("When focus is lost:"); - pauseEmulation.setText("Pause emulation").onActivate([&] { - settings.input.defocus = "Pause"; - }); - blockInput.setText("Block input").onActivate([&] { - settings.input.defocus = "Block"; - }); - allowInput.setText("Allow input").onActivate([&] { - settings.input.defocus = "Allow"; - }); - if(settings.input.defocus == "Pause") pauseEmulation.setChecked(); - if(settings.input.defocus == "Block") blockInput.setChecked(); - if(settings.input.defocus == "Allow") allowInput.setChecked(); - warnOnUnverifiedGames.setText("Warn when loading games that have not been verified").setChecked(settings.emulator.warnOnUnverifiedGames).onToggle([&] { - settings.emulator.warnOnUnverifiedGames = warnOnUnverifiedGames.checked(); - }); - autoSaveMemory.setText("Auto-save memory periodically").setChecked(settings.emulator.autoSaveMemory.enable).onToggle([&] { - settings.emulator.autoSaveMemory.enable = autoSaveMemory.checked(); - }); - autoSaveStateOnUnload.setText("Auto-save undo state when unloading games").setChecked(settings.emulator.autoSaveStateOnUnload).onToggle([&] { - settings.emulator.autoSaveStateOnUnload = autoSaveStateOnUnload.checked(); - if(!autoSaveStateOnUnload.checked()) { - autoLoadStateOnLoad.setEnabled(false).setChecked(false).doToggle(); - } else { - autoLoadStateOnLoad.setEnabled(true); - } - }).doToggle(); - autoLoadStateOnLoad.setText("Auto-resume on load").setChecked(settings.emulator.autoLoadStateOnLoad).onToggle([&] { - settings.emulator.autoLoadStateOnLoad = autoLoadStateOnLoad.checked(); - }); - optionsSpacer.setColor({192, 192, 192}); - - hacksLabel.setText("Hacks").setFont(Font().setBold()); - fastPPUOption.setText("Fast PPU").setChecked(settings.emulator.hack.fastPPU.enable).onToggle([&] { - settings.emulator.hack.fastPPU.enable = fastPPUOption.checked(); - if(!fastPPUOption.checked()) { - noSpriteLimit.setEnabled(false).setChecked(false).doToggle(); - hiresMode7.setEnabled(false).setChecked(false).doToggle(); - } else { - noSpriteLimit.setEnabled(true); - hiresMode7.setEnabled(true); - } - }).doToggle(); - noSpriteLimit.setText("No sprite limit").setChecked(settings.emulator.hack.fastPPU.noSpriteLimit).onToggle([&] { - settings.emulator.hack.fastPPU.noSpriteLimit = noSpriteLimit.checked(); - }); - hiresMode7.setText("Hires mode 7").setChecked(settings.emulator.hack.fastPPU.hiresMode7).onToggle([&] { - settings.emulator.hack.fastPPU.hiresMode7 = hiresMode7.checked(); - }); - fastDSPOption.setText("Fast DSP").setChecked(settings.emulator.hack.fastDSP.enable).onToggle([&] { - settings.emulator.hack.fastDSP.enable = fastDSPOption.checked(); - }); - coprocessorsDelayedSyncOption.setText("Fast coprocessors (delayed sync)").setChecked(settings.emulator.hack.coprocessors.delayedSync).onToggle([&] { - settings.emulator.hack.coprocessors.delayedSync = coprocessorsDelayedSyncOption.checked(); - }); - coprocessorsHLEOption.setText("Prefer HLE for coprocessors").setChecked(settings.emulator.hack.coprocessors.hle).onToggle([&] { - settings.emulator.hack.coprocessors.hle = coprocessorsHLEOption.checked(); - }); - superFXLabel.setText("SuperFX clock speed:"); - superFXValue.setAlignment(0.5); - superFXClock.setLength(71).setPosition((settings.emulator.hack.fastSuperFX - 100) / 10).onChange([&] { - settings.emulator.hack.fastSuperFX = superFXClock.position() * 10 + 100; - superFXValue.setText({settings.emulator.hack.fastSuperFX, "%"}); - }).doChange(); - hacksNote.setForegroundColor({224, 0, 0}).setText("Note: some hack setting changes do not take effect until after reloading games."); -} - -auto EmulatorSettings::updateConfiguration() -> void { - emulator->configure("Hacks/FastPPU/Enable", fastPPUOption.checked()); - emulator->configure("Hacks/FastPPU/NoSpriteLimit", noSpriteLimit.checked()); - emulator->configure("Hacks/FastPPU/HiresMode7", hiresMode7.checked()); - emulator->configure("Hacks/FastDSP/Enable", fastDSPOption.checked()); - emulator->configure("Hacks/Coprocessor/DelayedSync", coprocessorsDelayedSyncOption.checked()); - emulator->configure("Hacks/Coprocessor/HLE", coprocessorsHLEOption.checked()); -} diff --git a/higan/target-higan/GNUmakefile b/higan/target-higan/GNUmakefile deleted file mode 100644 index 71e5d9d4..00000000 --- a/higan/target-higan/GNUmakefile +++ /dev/null @@ -1,68 +0,0 @@ -name := higan - -hiro.path := ../hiro -hiro.resource := $(ui)/resource/higan.rc -include $(hiro.path)/GNUmakefile - -ruby.path := ../ruby -include $(ruby.path)/GNUmakefile - -objects += ui-higan ui-program ui-input -objects += ui-settings ui-tools ui-presentation ui-resource -objects := $(objects:%=obj/%.o) - -obj/ui-higan.o: $(ui)/higan.cpp -obj/ui-program.o: $(ui)/program/program.cpp -obj/ui-input.o: $(ui)/input/input.cpp -obj/ui-settings.o: $(ui)/settings/settings.cpp -obj/ui-tools.o: $(ui)/tools/tools.cpp -obj/ui-presentation.o: $(ui)/presentation/presentation.cpp -obj/ui-resource.o: $(ui)/resource/resource.cpp - -all: $(hiro.objects) $(ruby.objects) $(objects) - $(info Linking out/$(name) ...) - +@$(compiler) -o out/$(name) $(hiro.objects) $(ruby.objects) $(objects) $(hiro.options) $(ruby.options) $(options) -ifeq ($(platform),macos) - rm -rf out/$(name).app - mkdir -p out/$(name).app/Contents/MacOS/ - mkdir -p out/$(name).app/Contents/Resources/ - mv out/$(name) out/$(name).app/Contents/MacOS/$(name) - cp $(ui)/resource/$(name).plist out/$(name).app/Contents/Info.plist - sips -s format icns $(ui)/resource/$(name).png --out out/$(name).app/Contents/Resources/$(name).icns -endif - -verbose: hiro.verbose ruby.verbose nall.verbose all; - -install: all -ifeq ($(shell id -un),root) - $(error "make install should not be run as root") -else ifeq ($(platform),windows) -else ifeq ($(platform),macos) - mkdir -p ~/Library/Application\ Support/$(name)/ - mkdir -p ~/Library/Application\ Support/$(name)/systems/ - mkdir -p ~/Emulation/ - cp -R out/$(name).app /Applications/$(name).app - cp -R systems/* ~/Library/Application\ Support/$(name)/systems/ -else ifneq ($(filter $(platform),linux bsd),) - mkdir -p $(prefix)/bin/ - mkdir -p $(prefix)/share/applications/ - mkdir -p $(prefix)/share/icons/ - mkdir -p $(prefix)/share/$(name)/ - mkdir -p $(prefix)/share/$(name)/systems/ - cp out/$(name) $(prefix)/bin/$(name) - cp -R systems/* $(prefix)/share/$(name)/systems/ - cp $(ui)/resource/$(name).desktop $(prefix)/share/applications/$(name).desktop - cp $(ui)/resource/$(name).png $(prefix)/share/icons/$(name).png -endif - -uninstall: -ifeq ($(shell id -un),root) - $(error "make uninstall should not be run as root") -else ifeq ($(platform),windows) -else ifeq ($(platform),macos) - rm -rf /Applications/$(name).app -else ifneq ($(filter $(platform),linux bsd),) - rm -f $(prefix)/bin/$(name) - rm -f $(prefix)/share/applications/$(name).desktop - rm -f $(prefix)/share/icons/$(name).png -endif diff --git a/higan/target-higan/higan.cpp b/higan/target-higan/higan.cpp deleted file mode 100644 index eacc3d33..00000000 --- a/higan/target-higan/higan.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "higan.hpp" -unique_pointer