diff --git a/README.md b/README.md index 5720b2f..046e573 100644 --- a/README.md +++ b/README.md @@ -45,17 +45,27 @@ $ ./build/darwin-amd64/mettaur XXXX.gba ## ToDo -- [ ] Sound DMA -- [ ] Clear sound - [ ] Window - [ ] Mosaic - [ ] Blend - [ ] GUI - [ ] Serial communication - [ ] BG mode5 +- [ ] GameBoy Compatibility - [ ] Debug feature - [ ] Fix some bugs +## Game Compatibility List + +| Game Title | Compatibility | +| -------------------- | ------------- | +| バトルネットワーク ロックマンエグゼ3 BLACK | ✅ | +| ロックマンエグゼ4 トーナメント ブルームーン | ✅ | +| ロックマンエグゼ6 電脳獣グレイガ・電脳獣ファルザー | ✅ | +| ポケットモンスター ファイアレッド | ✅ | +| ドラゴンクエストモンスターズ キャラバンハート | 🔺 | + + ## References - [GBATEK](https://problemkaputt.de/gbatek.htm) diff --git a/pkg/gba/apu.go b/pkg/gba/apu.go index 8865657..ae37272 100644 --- a/pkg/gba/apu.go +++ b/pkg/gba/apu.go @@ -18,7 +18,7 @@ const ( BUFF_SAMPLES_MSK = ((BUFF_SAMPLES) - 1) SAMPLE_TIME float64 = 1.0 / SND_FREQUENCY SAMPLE_RATE = SND_FREQUENCY - STREAM_LEN = 2940 // 2 * 2 * sampleRate * (1/60) + STREAM_LEN = 2184 // 2 * 2 * sampleRate * (1/60) ) const ( @@ -498,7 +498,7 @@ func (g *GBA) soundClock(cycles uint32) { cnth := uint16(g._getRAM(ram.SOUNDCNT_H)) // snd_pcm_vol volADiv, volBDiv := int16((cnth>>2)&0b1), int16((cnth>>3)&0b1) - sampCh4, sampCh5 := fifoASamp>>volADiv, fifoBSamp>>volBDiv + sampCh4, sampCh5 := (int16(fifoASamp)<<1)>>volADiv, (int16(fifoBSamp)<<1)>>volBDiv // sampCh4, sampCh5 = 0, 0 // Left diff --git a/pkg/gba/dma.go b/pkg/gba/dma.go index 58392b3..462dcd5 100644 --- a/pkg/gba/dma.go +++ b/pkg/gba/dma.go @@ -14,11 +14,14 @@ const ( ) type DMA struct { - io [12]byte - src, dst uint32 + io [12]byte + src, dst uint32 + count, defaultCount int } -func NewDMA() [4]*DMA { return [4]*DMA{&DMA{}, &DMA{}, &DMA{}, &DMA{}} } +func NewDMA() [4]*DMA { + return [4]*DMA{&DMA{defaultCount: 0x4000}, &DMA{defaultCount: 0x4000}, &DMA{defaultCount: 0x4000}, &DMA{defaultCount: 0x10000}} +} func (ch *DMA) cnt() uint32 { return util.LE32(ch.io[8:]) } func (ch *DMA) setCnt(v uint32) { ch.io[8], ch.io[9], ch.io[10], ch.io[11] = byte(v), byte(v>>8), byte(v>>16), byte(v>>24) @@ -33,16 +36,21 @@ func (ch *DMA) set(ofs uint32, b byte) bool { old := byte(ch.cnt() >> 24) ch.io[ofs] = b if ofs == 11 { - ch.src, ch.dst = util.LE32(ch.io[0:]), util.LE32(ch.io[4:]) - switch ch.size() { - case 32: - ch.src &= ^uint32(3) - ch.dst &= ^uint32(3) - case 16: - ch.src &= ^uint32(1) - ch.dst &= ^uint32(1) + turnon := !util.Bit(old, 7) && util.Bit(b, 7) + if turnon { + ch.src, ch.dst = util.LE32(ch.io[0:]), util.LE32(ch.io[4:]) + ch.count = ch.wordCount() + switch ch.size() { + case 32: + ch.src &= ^uint32(3) + ch.dst &= ^uint32(3) + case 16: + ch.src &= ^uint32(1) + ch.dst &= ^uint32(1) + } } - return !util.Bit(old, 7) && util.Bit(b, 7) && (ch.timing() == 0) + + return turnon && ch.timing() == 0 } return false } @@ -81,13 +89,10 @@ func (ch *DMA) timing() dmaTiming { return dmaTiming((ch.cnt() >> (16 + 12)) & 0 func (ch *DMA) irq() bool { return util.Bit(ch.cnt(), 16+14) } func (ch *DMA) enabled() bool { return util.Bit(ch.cnt(), 16+15) } func (ch *DMA) disable() { ch.setCnt(ch.cnt() & 0x7fff_ffff) } -func (ch *DMA) wordCount(i int) int { +func (ch *DMA) wordCount() int { wordCount := ch.cnt() & 0xffff if wordCount == 0 { - wordCount = 0x4000 - if i == 3 { - wordCount = 0x10000 - } + return ch.defaultCount } return int(wordCount) } @@ -98,11 +103,9 @@ func (g *GBA) dmaTransfer(t dmaTiming) { continue } - g.timer(2) - - wc, size := ch.wordCount(i), ch.size() + size := ch.size() srcInc, dstInc := ch.srcCnt(), ch.dstCnt() - for wc > 0 { + for ch.count > 0 { switch size { case 16: g.setRAM16(ch.dst, g.getRAM16(ch.src, true), true) @@ -111,20 +114,21 @@ func (g *GBA) dmaTransfer(t dmaTiming) { } ch.dst, ch.src = uint32(int64(ch.dst)+dstInc), uint32(int64(ch.src)+srcInc) - wc-- + ch.count-- } if ch.irq() { g.triggerIRQ(IRQID(irqDMA0 + i)) } - if !ch.repeat() { + if ch.repeat() { + ch.count = ch.wordCount() + if ch.dstReload() { + ch.dst = util.LE32(ch.io[4:]) + } + } else { ch.disable() } - - if ch.dstReload() { - ch.dst = util.LE32(ch.io[4:]) - } } } diff --git a/pkg/gba/gba.go b/pkg/gba/gba.go index 435a438..8a340ff 100644 --- a/pkg/gba/gba.go +++ b/pkg/gba/gba.go @@ -103,7 +103,7 @@ func (g *GBA) exec(cycles int) { for g.cycle < cycles { g.step() if g.halt { - g.cycle = cycles + g.timer(cycles - g.cycle) } } g.cycle -= cycles diff --git a/pkg/gba/io.go b/pkg/gba/io.go index 39b5648..d073f8e 100644 --- a/pkg/gba/io.go +++ b/pkg/gba/io.go @@ -17,13 +17,13 @@ func (g *GBA) _getRAM(addr uint32) uint32 { idx := (bank ^ 0x10) | (addr & 0xf) return util.LE32(waveRAM[idx:]) case isDMA0IO(addr): - return g.dma[0].get(addr - 0x0400_00b0) + return g.dma[0].get(addr - ram.DMA0SAD) case isDMA1IO(addr): - return g.dma[1].get(addr - 0x0400_00bc) + return g.dma[1].get(addr - ram.DMA1SAD) case isDMA2IO(addr): - return g.dma[2].get(addr - 0x0400_00c8) + return g.dma[2].get(addr - ram.DMA2SAD) case isDMA3IO(addr): - return g.dma[3].get(addr - 0x0400_00d4) + return g.dma[3].get(addr - ram.DMA3SAD) case IsTimerIO(addr): return g.timers.GetIO(addr - 0x0400_0100) case addr == ram.KEYINPUT || addr == ram.KEYINPUT+1: