Skip to content

Commit

Permalink
fix timer bug
Browse files Browse the repository at this point in the history
  • Loading branch information
akatsuki105 committed Apr 13, 2021
1 parent 1931e69 commit f32b540
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 55 deletions.
87 changes: 59 additions & 28 deletions pkg/gba/apu.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"math"
"mettaur/pkg/ram"
"mettaur/pkg/util"
"time"

"github.com/hajimehoshi/oto"
)
Expand All @@ -13,6 +14,27 @@ var wavePosition byte

var waveRAM [0x20]byte

func isSoundIO(addr uint32) bool {
return addr >= 0x04000060 && addr <= 0x04000081
}
func maskSoundIO(addr uint32, b byte) byte {
switch addr {
case 0x04000060:
return b & 0x7f
case 0x04000061, 0x04000064, 0x04000066, 0x04000067, 0x0400006c, 0x0400006e, 0x0400006f, 0x04000071, 0x04000072, 0x04000074, 0x04000076, 0x04000077, 0x04000078, 0x0400007a, 0x0400007b, 0x0400007e, 0x0400007f:
return 0
case 0x04000062, 0x04000068:
return b & 0xc0
case 0x04000065, 0x0400006d, 0x04000075, 0x0400007d:
return b & 0x40
case 0x04000070, 0x04000073:
return b & 0xe0
case 0x04000080:
return b & 0x77
}
return b
}

func isWaveRAM(addr uint32) bool {
return addr >= 0x04000090 && addr <= 0x0400009f
}
Expand Down Expand Up @@ -85,20 +107,19 @@ func (g *GBA) exitAPU() {

func (g *GBA) playSound() {
go func() {
for {
for range time.Tick(time.Second / 60) {
g.soundMix()
}
}()
go func() {
for {
for range time.Tick(time.Second / 60) {
g.apu.player.Write(stream)
}
}()
}

func (g *GBA) squareSample(ch int) int8 {
cntx := g._getRAM(ram.SOUNDCNT_X)
if !util.Bit(cntx, ch) {
if !g.isSoundChanEnable(ch) {
return 0
}

Expand Down Expand Up @@ -127,25 +148,30 @@ func (g *GBA) squareSample(ch int) int8 {
if (ch == 0 && util.Bit(g._getRAM(ram.SOUND1CNT_X), 14)) || (ch == 1 && util.Bit(g._getRAM(ram.SOUND2CNT_H), 14)) {
g.apu.chans[ch].lengthTime += SAMPLE_TIME
if g.apu.chans[ch].lengthTime >= length {
g.disableSoundChan(ch)
g.enableSoundChan(ch, false)
return 0
}
}

// Frequency sweep (Square 1 channel only)
sweepTime := (g._getRAM(ram.SOUND1CNT_L) >> 4) & 0b111
sweepInterval := 0.0078 * float64(sweepTime+1) // Frquency sweep change interval in seconds
if ch == 0 {
sweepTime := (g._getRAM(ram.SOUND1CNT_L) >> 4) & 0b111
sweepInterval := 0.0078 * float64(sweepTime+1) // Frquency sweep change interval in seconds

g.apu.chans[0].sweepTime += SAMPLE_TIME
if g.apu.chans[0].sweepTime >= sweepInterval {
g.apu.chans[0].sweepTime -= sweepInterval
sweepShift := byte(g._getRAM(ram.SOUND1CNT_L) & 0b111)

// A Sweep Shift of 0 means that Sweep is disabled
sweepShift := byte(g._getRAM(ram.SOUND1CNT_L) & 7)

if sweepShift != 0 {
disp := freqHz >> sweepShift
if !util.Bit(g._getRAM(ram.SOUND1CNT_L), 3) {
freqHz += disp
} else {

if util.Bit(g._getRAM(ram.SOUND1CNT_L), 3) {
freqHz -= disp
} else {
freqHz += disp
}

if freqHz < 0x7ff {
Expand All @@ -154,15 +180,17 @@ func (g *GBA) squareSample(ch int) int8 {
ctrl = (ctrl & ^uint16(0x7ff)) | uint16(freqHz)
g._setRAM16(ram.SOUND1CNT_X, ctrl)
} else {
g.disableSoundChan(0)
g.enableSoundChan(0, false)
}
}
}
}

// Envelope volume
envelope := uint16((g._getRAM(toneAddr) >> 12) & 0xf)
if envStep > 0 {
g.apu.chans[ch].envTime += SAMPLE_TIME

if g.apu.chans[ch].envTime >= envelopeInterval {
g.apu.chans[ch].envTime -= envelopeInterval

Expand Down Expand Up @@ -207,29 +235,32 @@ func (g *GBA) squareSample(ch int) int8 {
return int8(float64(envelope) * PSG_MIN / 15)
}

func (g *GBA) enableSoundChan(ch int) {
func (g *GBA) enableSoundChan(ch int, enable bool) {
cntx := byte(g._getRAM(ram.SOUNDCNT_X))
cntx = cntx | (1 << ch)
g._setRAM8(ram.SOUNDCNT_X, cntx)
if enable {
cntx = cntx | (1 << ch)
} else {
cntx = cntx & ^(1 << ch)
}
g.RAM.IO[ram.IOOffset(ram.SOUNDCNT_X)] = cntx
}

func (g *GBA) disableSoundChan(ch int) {
func (g *GBA) isSoundChanEnable(ch int) bool {
cntx := byte(g._getRAM(ram.SOUNDCNT_X))
cntx = cntx & ^(1 << ch)
g._setRAM8(ram.SOUNDCNT_X, cntx)
return util.Bit(cntx, ch)
}

func (g *GBA) waveSample() int8 {
cntx, wave := g._getRAM(ram.SOUNDCNT_X), uint16(g._getRAM(ram.SOUND3CNT_L))
if !(util.Bit(cntx, 2) && util.Bit(wave, 7)) {
wave := uint16(g._getRAM(ram.SOUND3CNT_L))
if !(g.isSoundChanEnable(2) && util.Bit(wave, 7)) {
return 0
}

// Actual frequency in Hertz
freqHz := g._getRAM(ram.SOUND3CNT_X) & 2047
frequency := 2097152 / (2048 - float64(freqHz))

cnth := uint16(g._getRAM(ram.SOUND3CNT_H))
cnth := uint16(g._getRAM(ram.SOUND3CNT_H)) // volume

// Full length of the generated wave (if enabled) in seconds
soundLen := cnth & 0xff
Expand All @@ -242,7 +273,7 @@ func (g *GBA) waveSample() int8 {
if util.Bit(uint16(g._getRAM(ram.SOUND3CNT_X)), 14) {
g.apu.chans[2].lengthTime += SAMPLE_TIME
if g.apu.chans[2].lengthTime >= length {
g.disableSoundChan(2)
g.enableSoundChan(2, false)
return 0
}
}
Expand All @@ -259,10 +290,10 @@ func (g *GBA) waveSample() int8 {
}
}

waveAddr := (uint32(wavePosition)>>1)&0x1f + ram.WAVE_RAM
samp := int8(byte(g._getRAM(waveAddr))&0xf) - 8
waveIdx := (uint32(wavePosition) >> 1) & 0x1f
samp := int8(waveRAM[waveIdx]&0xf) - 8
if wavePosition&1 == 0 {
samp = int8((byte(g._getRAM(waveAddr))>>4)&0xf) - 8
samp = int8((waveRAM[waveIdx]>>4)&0xf) - 8
}

volume := (cnth >> 13) & 0x7
Expand All @@ -286,7 +317,7 @@ func (g *GBA) waveSample() int8 {
}

func (g *GBA) noiseSample() int8 {
if !util.Bit(g._getRAM(ram.SOUNDCNT_X), 3) {
if !g.isSoundChanEnable(3) {
return 0
}

Expand All @@ -308,7 +339,7 @@ func (g *GBA) noiseSample() int8 {
if util.Bit(cnth, 14) {
g.apu.chans[3].lengthTime += SAMPLE_TIME
if g.apu.chans[3].lengthTime >= length {
g.disableSoundChan(3)
g.enableSoundChan(3, false)
return 0
}
}
Expand Down Expand Up @@ -557,6 +588,6 @@ func (g *GBA) _resetSoundChan(ch int, enable bool) {
}
}

g.enableSoundChan(ch)
g.enableSoundChan(ch, true)
}
}
19 changes: 9 additions & 10 deletions pkg/gba/dma.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,32 +138,31 @@ func (g *GBA) dmaTransfer(t dmaTiming) {
}
}

func (g *GBA) dmaTransferFifo(dma int) {
ch := g.dma[dma] // DMA1 or DMA2
if !ch.enabled() || ch.timing() != dmaSpecial {
func (g *GBA) dmaTransferFifo(ch int) {
if !g.dma[ch].enabled() || g.dma[ch].timing() != dmaSpecial {
return
}

// 32bit × 4 = 4 words
for i := 0; i < 4; i++ {
src, dst := ch.src(), ch.dst()
src, dst := g.dma[ch].src(), g.dma[ch].dst()
g.setRAM32(dst, g.getRAM32(src, true), true)

if dma == 1 {
if ch == 1 {
g.fifoACopy()
} else {
g.fifoBCopy()
}

switch (ch.cnt() >> 7) & 0b11 {
switch (g.dma[ch].cnt() >> 7) & 0b11 {
case 0:
ch.setSrc(src + 4)
g.dma[ch].setSrc(src + 4)
case 1:
ch.setSrc(src - 4)
g.dma[ch].setSrc(src - 4)
}
}

if ch.irq() {
g.triggerIRQ(IRQID(irqDMA0 + dma))
if g.dma[ch].irq() {
g.triggerIRQ(IRQID(irqDMA0 + ch))
}
}
1 change: 1 addition & 0 deletions pkg/gba/gba.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ func New(src []byte) *GBA {
RAM: *ram.New(src),
dma: NewDMA(),
apu: newAPU(),
timers: newTimers(),
}
g._setRAM16(ram.KEYINPUT, 0x3ff)
g.playSound()
Expand Down
19 changes: 16 additions & 3 deletions pkg/gba/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,22 @@ func (g *GBA) _setRAM8(addr uint32, b byte) {
switch {
case gpu.IsIO(addr):
g.GPU.IO[addr-0x0400_0000] = b
case isResetSoundChan(addr):
g.RAM.Set8(addr, b)
g.resetSoundChan(addr, b)
case isSoundIO(addr):
if util.Bit(byte(g._getRAM(ram.SOUNDCNT_X)), 7) {
g.RAM.Set8(addr, b)
if isResetSoundChan(addr) {
g.resetSoundChan(addr, b)
}
}
case addr == ram.SOUNDCNT_X:
old := byte(g._getRAM(addr))
old = (old & 0xf) | (b & 0xf0)
g.RAM.Set8(addr, old)
if !util.Bit(b, 7) {
for i := uint32(0x4000060); i <= 0x4000081; i++ {
g.RAM.IO[ram.IOOffset(i)] = 0
}
}
case isWaveRAM(addr):
bank := (g._getRAM(ram.SOUND3CNT_L) >> 2) & 0x10
idx := (bank ^ 0x10) | (addr & 0xf)
Expand Down
37 changes: 23 additions & 14 deletions pkg/gba/timer.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ func (g *GBA) timer(cycle int) {
}
}

type Timers [4]Timer
type Timers [4]*Timer

func newTimers() Timers {
return Timers{&Timer{}, &Timer{}, &Timer{}, &Timer{}}
}

type Timer struct {
Count uint16
Expand Down Expand Up @@ -165,20 +169,22 @@ func (g *GBA) Tick() [4]bool {
overflow, irq := false, [4]bool{}
ts := &g.timers
if ts[0].enable() {
ts[0].Next--
if ts[0].Next > 0 {
ts[0].Next--
}
if ts[0].Next == 0 {
overflow = ts[0].increment()
if overflow {
cnth := uint16(g._getRAM(ram.SOUNDCNT_H))
switch {
case (cnth>>10)&1 == 0:
if (cnth>>10)&1 == 0 {
g.fifoALoad()
if fifoALen < 0x10 {
if fifoALen <= 0x10 {
g.dmaTransferFifo(1)
}
case (cnth>>14)&1 == 0:
}
if (cnth>>14)&1 == 0 {
g.fifoBLoad()
if fifoBLen < 0x10 {
if fifoBLen <= 0x10 {
g.dmaTransferFifo(2)
}
}
Expand All @@ -199,26 +205,29 @@ func (g *GBA) Tick() [4]bool {
countUp = overflow
overflow = false
} else {
ts[i].Next--
countUp = ts[1].Next == 0
if ts[i].Next > 0 {
ts[i].Next--
}
countUp = ts[i].Next == 0
}

if countUp {
overflow = ts[i].increment()
if overflow {
cnth := uint16(g._getRAM(ram.SOUNDCNT_H))
switch {
case (cnth>>10)&1 == uint16(i):
if (cnth>>10)&1 == uint16(i) {
g.fifoALoad()
if fifoALen < 0x10 {
if fifoALen <= 0x10 {
g.dmaTransferFifo(1)
}
case (cnth>>14)&1 == uint16(i):
}
if (cnth>>14)&1 == uint16(i) {
g.fifoBLoad()
if fifoBLen < 0x10 {
if fifoBLen <= 0x10 {
g.dmaTransferFifo(2)
}
}

if ts[i].overflow() {
irq[i] = true
}
Expand Down

0 comments on commit f32b540

Please sign in to comment.