package nes import "encoding/gob" const frameCounterRate = CPUFrequency / 240.0 var lengthTable = []byte{ 10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30, } var dutyTable = [][]byte{ {0, 1, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 0, 0, 0}, {1, 0, 0, 1, 1, 1, 1, 1}, } var triangleTable = []byte{ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, } var noiseTable = []uint16{ 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068, } var dmcTable = []byte{ 214, 190, 170, 160, 143, 127, 113, 107, 95, 80, 71, 64, 53, 42, 36, 27, } var pulseTable [31]float32 var tndTable [203]float32 func init() { for i := 0; i < 31; i++ { pulseTable[i] = 95.52 / (8128.0/float32(i) + 100) } for i := 0; i < 203; i++ { tndTable[i] = 163.67 / (24329.0/float32(i) + 100) } } // APU type APU struct { console *Console channel chan float32 sampleRate float64 pulse1 Pulse pulse2 Pulse triangle Triangle noise Noise dmc DMC cycle uint64 framePeriod byte frameValue byte frameIRQ bool filterChain FilterChain } func NewAPU(console *Console) *APU { apu := APU{} apu.console = console apu.noise.shiftRegister = 1 apu.pulse1.channel = 1 apu.pulse2.channel = 2 apu.dmc.cpu = console.CPU return &apu } func (apu *APU) Save(encoder *gob.Encoder) error { encoder.Encode(apu.cycle) encoder.Encode(apu.framePeriod) encoder.Encode(apu.frameValue) encoder.Encode(apu.frameIRQ) apu.pulse1.Save(encoder) apu.pulse2.Save(encoder) apu.triangle.Save(encoder) apu.noise.Save(encoder) apu.dmc.Save(encoder) return nil } func (apu *APU) Load(decoder *gob.Decoder) error { decoder.Decode(&apu.cycle) decoder.Decode(&apu.framePeriod) decoder.Decode(&apu.frameValue) decoder.Decode(&apu.frameIRQ) apu.pulse1.Load(decoder) apu.pulse2.Load(decoder) apu.triangle.Load(decoder) apu.noise.Load(decoder) apu.dmc.Load(decoder) return nil } func (apu *APU) Step() { cycle1 := apu.cycle apu.cycle++ cycle2 := apu.cycle apu.stepTimer() f1 := int(float64(cycle1) / frameCounterRate) f2 := int(float64(cycle2) / frameCounterRate) if f1 != f2 { apu.stepFrameCounter() } s1 := int(float64(cycle1) / apu.sampleRate) s2 := int(float64(cycle2) / apu.sampleRate) if s1 != s2 { apu.sendSample() } } func (apu *APU) sendSample() { output := apu.filterChain.Step(apu.output()) select { case apu.channel <- output: default: } } func (apu *APU) output() float32 { p1 := apu.pulse1.output() p2 := apu.pulse2.output() t := apu.triangle.output() n := apu.noise.output() d := apu.dmc.output() pulseOut := pulseTable[p1+p2] tndOut := tndTable[3*t+2*n+d] return pulseOut + tndOut } // mode 0: mode 1: function // --------- ----------- ----------------------------- // - - - f - - - - - IRQ (if bit 6 is clear) // - l - l l - l - - Length counter and sweep // e e e e e e e e - Envelope and linear counter func (apu *APU) stepFrameCounter() { switch apu.framePeriod { case 4: apu.frameValue = (apu.frameValue + 1) % 4 switch apu.frameValue { case 0, 2: apu.stepEnvelope() case 1: apu.stepEnvelope() apu.stepSweep() apu.stepLength() case 3: apu.stepEnvelope() apu.stepSweep() apu.stepLength() apu.fireIRQ() } case 5: apu.frameValue = (apu.frameValue + 1) % 5 switch apu.frameValue { case 0, 2: apu.stepEnvelope() case 1, 3: apu.stepEnvelope() apu.stepSweep() apu.stepLength() } } } func (apu *APU) stepTimer() { if apu.cycle%2 == 0 { apu.pulse1.stepTimer() apu.pulse2.stepTimer() apu.noise.stepTimer() apu.dmc.stepTimer() } apu.triangle.stepTimer() } func (apu *APU) stepEnvelope() { apu.pulse1.stepEnvelope() apu.pulse2.stepEnvelope() apu.triangle.stepCounter() apu.noise.stepEnvelope() } func (apu *APU) stepSweep() { apu.pulse1.stepSweep() apu.pulse2.stepSweep() } func (apu *APU) stepLength() { apu.pulse1.stepLength() apu.pulse2.stepLength() apu.triangle.stepLength() apu.noise.stepLength() } func (apu *APU) fireIRQ() { if apu.frameIRQ { apu.console.CPU.triggerIRQ() } } func (apu *APU) readRegister(address uint16) byte { switch address { case 0x4015: return apu.readStatus() // default: // log.Fatalf("unhandled apu register read at address: 0x%04X", address) } return 0 } func (apu *APU) writeRegister(address uint16, value byte) { switch address { case 0x4000: apu.pulse1.writeControl(value) case 0x4001: apu.pulse1.writeSweep(value) case 0x4002: apu.pulse1.writeTimerLow(value) case 0x4003: apu.pulse1.writeTimerHigh(value) case 0x4004: apu.pulse2.writeControl(value) case 0x4005: apu.pulse2.writeSweep(value) case 0x4006: apu.pulse2.writeTimerLow(value) case 0x4007: apu.pulse2.writeTimerHigh(value) case 0x4008: apu.triangle.writeControl(value) case 0x4009: case 0x4010: apu.dmc.writeControl(value) case 0x4011: apu.dmc.writeValue(value) case 0x4012: apu.dmc.writeAddress(value) case 0x4013: apu.dmc.writeLength(value) case 0x400A: apu.triangle.writeTimerLow(value) case 0x400B: apu.triangle.writeTimerHigh(value) case 0x400C: apu.noise.writeControl(value) case 0x400D: case 0x400E: apu.noise.writePeriod(value) case 0x400F: apu.noise.writeLength(value) case 0x4015: apu.writeControl(value) case 0x4017: apu.writeFrameCounter(value) // default: // log.Fatalf("unhandled apu register write at address: 0x%04X", address) } } func (apu *APU) readStatus() byte { var result byte if apu.pulse1.lengthValue > 0 { result |= 1 } if apu.pulse2.lengthValue > 0 { result |= 2 } if apu.triangle.lengthValue > 0 { result |= 4 } if apu.noise.lengthValue > 0 { result |= 8 } if apu.dmc.currentLength > 0 { result |= 16 } return result } func (apu *APU) writeControl(value byte) { apu.pulse1.enabled = value&1 == 1 apu.pulse2.enabled = value&2 == 2 apu.triangle.enabled = value&4 == 4 apu.noise.enabled = value&8 == 8 apu.dmc.enabled = value&16 == 16 if !apu.pulse1.enabled { apu.pulse1.lengthValue = 0 } if !apu.pulse2.enabled { apu.pulse2.lengthValue = 0 } if !apu.triangle.enabled { apu.triangle.lengthValue = 0 } if !apu.noise.enabled { apu.noise.lengthValue = 0 } if !apu.dmc.enabled { apu.dmc.currentLength = 0 } else { if apu.dmc.currentLength == 0 { apu.dmc.restart() } } } func (apu *APU) writeFrameCounter(value byte) { apu.framePeriod = 4 + (value>>7)&1 apu.frameIRQ = (value>>6)&1 == 0 // apu.frameValue = 0 if apu.framePeriod == 5 { apu.stepEnvelope() apu.stepSweep() apu.stepLength() } } // Pulse type Pulse struct { enabled bool channel byte lengthEnabled bool lengthValue byte timerPeriod uint16 timerValue uint16 dutyMode byte dutyValue byte sweepReload bool sweepEnabled bool sweepNegate bool sweepShift byte sweepPeriod byte sweepValue byte envelopeEnabled bool envelopeLoop bool envelopeStart bool envelopePeriod byte envelopeValue byte envelopeVolume byte constantVolume byte } func (p *Pulse) Save(encoder *gob.Encoder) error { encoder.Encode(p.enabled) encoder.Encode(p.channel) encoder.Encode(p.lengthEnabled) encoder.Encode(p.lengthValue) encoder.Encode(p.timerPeriod) encoder.Encode(p.timerValue) encoder.Encode(p.dutyMode) encoder.Encode(p.dutyValue) encoder.Encode(p.sweepReload) encoder.Encode(p.sweepEnabled) encoder.Encode(p.sweepNegate) encoder.Encode(p.sweepShift) encoder.Encode(p.sweepPeriod) encoder.Encode(p.sweepValue) encoder.Encode(p.envelopeEnabled) encoder.Encode(p.envelopeLoop) encoder.Encode(p.envelopeStart) encoder.Encode(p.envelopePeriod) encoder.Encode(p.envelopeValue) encoder.Encode(p.envelopeVolume) encoder.Encode(p.constantVolume) return nil } func (p *Pulse) Load(decoder *gob.Decoder) error { decoder.Decode(&p.enabled) decoder.Decode(&p.channel) decoder.Decode(&p.lengthEnabled) decoder.Decode(&p.lengthValue) decoder.Decode(&p.timerPeriod) decoder.Decode(&p.timerValue) decoder.Decode(&p.dutyMode) decoder.Decode(&p.dutyValue) decoder.Decode(&p.sweepReload) decoder.Decode(&p.sweepEnabled) decoder.Decode(&p.sweepNegate) decoder.Decode(&p.sweepShift) decoder.Decode(&p.sweepPeriod) decoder.Decode(&p.sweepValue) decoder.Decode(&p.envelopeEnabled) decoder.Decode(&p.envelopeLoop) decoder.Decode(&p.envelopeStart) decoder.Decode(&p.envelopePeriod) decoder.Decode(&p.envelopeValue) decoder.Decode(&p.envelopeVolume) decoder.Decode(&p.constantVolume) return nil } func (p *Pulse) writeControl(value byte) { p.dutyMode = (value >> 6) & 3 p.lengthEnabled = (value>>5)&1 == 0 p.envelopeLoop = (value>>5)&1 == 1 p.envelopeEnabled = (value>>4)&1 == 0 p.envelopePeriod = value & 15 p.constantVolume = value & 15 p.envelopeStart = true } func (p *Pulse) writeSweep(value byte) { p.sweepEnabled = (value>>7)&1 == 1 p.sweepPeriod = (value>>4)&7 + 1 p.sweepNegate = (value>>3)&1 == 1 p.sweepShift = value & 7 p.sweepReload = true } func (p *Pulse) writeTimerLow(value byte) { p.timerPeriod = (p.timerPeriod & 0xFF00) | uint16(value) } func (p *Pulse) writeTimerHigh(value byte) { p.lengthValue = lengthTable[value>>3] p.timerPeriod = (p.timerPeriod & 0x00FF) | (uint16(value&7) << 8) p.envelopeStart = true p.dutyValue = 0 } func (p *Pulse) stepTimer() { if p.timerValue == 0 { p.timerValue = p.timerPeriod p.dutyValue = (p.dutyValue + 1) % 8 } else { p.timerValue-- } } func (p *Pulse) stepEnvelope() { if p.envelopeStart { p.envelopeVolume = 15 p.envelopeValue = p.envelopePeriod p.envelopeStart = false } else if p.envelopeValue > 0 { p.envelopeValue-- } else { if p.envelopeVolume > 0 { p.envelopeVolume-- } else if p.envelopeLoop { p.envelopeVolume = 15 } p.envelopeValue = p.envelopePeriod } } func (p *Pulse) stepSweep() { if p.sweepReload { if p.sweepEnabled && p.sweepValue == 0 { p.sweep() } p.sweepValue = p.sweepPeriod p.sweepReload = false } else if p.sweepValue > 0 { p.sweepValue-- } else { if p.sweepEnabled { p.sweep() } p.sweepValue = p.sweepPeriod } } func (p *Pulse) stepLength() { if p.lengthEnabled && p.lengthValue > 0 { p.lengthValue-- } } func (p *Pulse) sweep() { delta := p.timerPeriod >> p.sweepShift if p.sweepNegate { p.timerPeriod -= delta if p.channel == 1 { p.timerPeriod-- } } else { p.timerPeriod += delta } } func (p *Pulse) output() byte { if !p.enabled { return 0 } if p.lengthValue == 0 { return 0 } if dutyTable[p.dutyMode][p.dutyValue] == 0 { return 0 } if p.timerPeriod < 8 || p.timerPeriod > 0x7FF { return 0 } // if !p.sweepNegate && p.timerPeriod+(p.timerPeriod>>p.sweepShift) > 0x7FF { // return 0 // } if p.envelopeEnabled { return p.envelopeVolume } else { return p.constantVolume } } // Triangle type Triangle struct { enabled bool lengthEnabled bool lengthValue byte timerPeriod uint16 timerValue uint16 dutyValue byte counterPeriod byte counterValue byte counterReload bool } func (t *Triangle) Save(encoder *gob.Encoder) error { encoder.Encode(t.enabled) encoder.Encode(t.lengthEnabled) encoder.Encode(t.lengthValue) encoder.Encode(t.timerPeriod) encoder.Encode(t.timerValue) encoder.Encode(t.dutyValue) encoder.Encode(t.counterPeriod) encoder.Encode(t.counterValue) encoder.Encode(t.counterReload) return nil } func (t *Triangle) Load(decoder *gob.Decoder) error { decoder.Decode(&t.enabled) decoder.Decode(&t.lengthEnabled) decoder.Decode(&t.lengthValue) decoder.Decode(&t.timerPeriod) decoder.Decode(&t.timerValue) decoder.Decode(&t.dutyValue) decoder.Decode(&t.counterPeriod) decoder.Decode(&t.counterValue) decoder.Decode(&t.counterReload) return nil } func (t *Triangle) writeControl(value byte) { t.lengthEnabled = (value>>7)&1 == 0 t.counterPeriod = value & 0x7F } func (t *Triangle) writeTimerLow(value byte) { t.timerPeriod = (t.timerPeriod & 0xFF00) | uint16(value) } func (t *Triangle) writeTimerHigh(value byte) { t.lengthValue = lengthTable[value>>3] t.timerPeriod = (t.timerPeriod & 0x00FF) | (uint16(value&7) << 8) t.timerValue = t.timerPeriod t.counterReload = true } func (t *Triangle) stepTimer() { if t.timerValue == 0 { t.timerValue = t.timerPeriod if t.lengthValue > 0 && t.counterValue > 0 { t.dutyValue = (t.dutyValue + 1) % 32 } } else { t.timerValue-- } } func (t *Triangle) stepLength() { if t.lengthEnabled && t.lengthValue > 0 { t.lengthValue-- } } func (t *Triangle) stepCounter() { if t.counterReload { t.counterValue = t.counterPeriod } else if t.counterValue > 0 { t.counterValue-- } if t.lengthEnabled { t.counterReload = false } } func (t *Triangle) output() byte { if !t.enabled { return 0 } if t.lengthValue == 0 { return 0 } if t.counterValue == 0 { return 0 } return triangleTable[t.dutyValue] } // Noise type Noise struct { enabled bool mode bool shiftRegister uint16 lengthEnabled bool lengthValue byte timerPeriod uint16 timerValue uint16 envelopeEnabled bool envelopeLoop bool envelopeStart bool envelopePeriod byte envelopeValue byte envelopeVolume byte constantVolume byte } func (n *Noise) Save(encoder *gob.Encoder) error { encoder.Encode(n.enabled) encoder.Encode(n.mode) encoder.Encode(n.shiftRegister) encoder.Encode(n.lengthEnabled) encoder.Encode(n.lengthValue) encoder.Encode(n.timerPeriod) encoder.Encode(n.timerValue) encoder.Encode(n.envelopeEnabled) encoder.Encode(n.envelopeLoop) encoder.Encode(n.envelopeStart) encoder.Encode(n.envelopePeriod) encoder.Encode(n.envelopeValue) encoder.Encode(n.envelopeVolume) encoder.Encode(n.constantVolume) return nil } func (n *Noise) Load(decoder *gob.Decoder) error { decoder.Decode(&n.enabled) decoder.Decode(&n.mode) decoder.Decode(&n.shiftRegister) decoder.Decode(&n.lengthEnabled) decoder.Decode(&n.lengthValue) decoder.Decode(&n.timerPeriod) decoder.Decode(&n.timerValue) decoder.Decode(&n.envelopeEnabled) decoder.Decode(&n.envelopeLoop) decoder.Decode(&n.envelopeStart) decoder.Decode(&n.envelopePeriod) decoder.Decode(&n.envelopeValue) decoder.Decode(&n.envelopeVolume) decoder.Decode(&n.constantVolume) return nil } func (n *Noise) writeControl(value byte) { n.lengthEnabled = (value>>5)&1 == 0 n.envelopeLoop = (value>>5)&1 == 1 n.envelopeEnabled = (value>>4)&1 == 0 n.envelopePeriod = value & 15 n.constantVolume = value & 15 n.envelopeStart = true } func (n *Noise) writePeriod(value byte) { n.mode = value&0x80 == 0x80 n.timerPeriod = noiseTable[value&0x0F] } func (n *Noise) writeLength(value byte) { n.lengthValue = lengthTable[value>>3] n.envelopeStart = true } func (n *Noise) stepTimer() { if n.timerValue == 0 { n.timerValue = n.timerPeriod var shift byte if n.mode { shift = 6 } else { shift = 1 } b1 := n.shiftRegister & 1 b2 := (n.shiftRegister >> shift) & 1 n.shiftRegister >>= 1 n.shiftRegister |= (b1 ^ b2) << 14 } else { n.timerValue-- } } func (n *Noise) stepEnvelope() { if n.envelopeStart { n.envelopeVolume = 15 n.envelopeValue = n.envelopePeriod n.envelopeStart = false } else if n.envelopeValue > 0 { n.envelopeValue-- } else { if n.envelopeVolume > 0 { n.envelopeVolume-- } else if n.envelopeLoop { n.envelopeVolume = 15 } n.envelopeValue = n.envelopePeriod } } func (n *Noise) stepLength() { if n.lengthEnabled && n.lengthValue > 0 { n.lengthValue-- } } func (n *Noise) output() byte { if !n.enabled { return 0 } if n.lengthValue == 0 { return 0 } if n.shiftRegister&1 == 1 { return 0 } if n.envelopeEnabled { return n.envelopeVolume } else { return n.constantVolume } } // DMC type DMC struct { cpu *CPU enabled bool value byte sampleAddress uint16 sampleLength uint16 currentAddress uint16 currentLength uint16 shiftRegister byte bitCount byte tickPeriod byte tickValue byte loop bool irq bool } func (d *DMC) Save(encoder *gob.Encoder) error { encoder.Encode(d.enabled) encoder.Encode(d.value) encoder.Encode(d.sampleAddress) encoder.Encode(d.sampleLength) encoder.Encode(d.currentAddress) encoder.Encode(d.currentLength) encoder.Encode(d.shiftRegister) encoder.Encode(d.bitCount) encoder.Encode(d.tickPeriod) encoder.Encode(d.tickValue) encoder.Encode(d.loop) encoder.Encode(d.irq) return nil } func (d *DMC) Load(decoder *gob.Decoder) error { decoder.Decode(&d.enabled) decoder.Decode(&d.value) decoder.Decode(&d.sampleAddress) decoder.Decode(&d.sampleLength) decoder.Decode(&d.currentAddress) decoder.Decode(&d.currentLength) decoder.Decode(&d.shiftRegister) decoder.Decode(&d.bitCount) decoder.Decode(&d.tickPeriod) decoder.Decode(&d.tickValue) decoder.Decode(&d.loop) decoder.Decode(&d.irq) return nil } func (d *DMC) writeControl(value byte) { d.irq = value&0x80 == 0x80 d.loop = value&0x40 == 0x40 d.tickPeriod = dmcTable[value&0x0F] } func (d *DMC) writeValue(value byte) { d.value = value & 0x7F } func (d *DMC) writeAddress(value byte) { // Sample address = %11AAAAAA.AA000000 d.sampleAddress = 0xC000 | (uint16(value) << 6) } func (d *DMC) writeLength(value byte) { // Sample length = %0000LLLL.LLLL0001 d.sampleLength = (uint16(value) << 4) | 1 } func (d *DMC) restart() { d.currentAddress = d.sampleAddress d.currentLength = d.sampleLength } func (d *DMC) stepTimer() { if !d.enabled { return } d.stepReader() if d.tickValue == 0 { d.tickValue = d.tickPeriod d.stepShifter() } else { d.tickValue-- } } func (d *DMC) stepReader() { if d.currentLength > 0 && d.bitCount == 0 { d.cpu.stall += 4 d.shiftRegister = d.cpu.Read(d.currentAddress) d.bitCount = 8 d.currentAddress++ if d.currentAddress == 0 { d.currentAddress = 0x8000 } d.currentLength-- if d.currentLength == 0 && d.loop { d.restart() } } } func (d *DMC) stepShifter() { if d.bitCount == 0 { return } if d.shiftRegister&1 == 1 { if d.value <= 125 { d.value += 2 } } else { if d.value >= 2 { d.value -= 2 } } d.shiftRegister >>= 1 d.bitCount-- } func (d *DMC) output() byte { return d.value }