Skip to content

Commit

Permalink
Create protocol for Cpu Ppu Apu.
Browse files Browse the repository at this point in the history
  • Loading branch information
miochen1226 committed Oct 13, 2023
1 parent 37819a9 commit a8e3b9e
Show file tree
Hide file tree
Showing 17 changed files with 339 additions and 337 deletions.
6 changes: 6 additions & 0 deletions NES_EMU.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@
35714DD32AD3E5FB004A7A3F /* DmcChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35714DD12AD3E5FB004A7A3F /* DmcChannel.swift */; };
358D403526C66CEB005AAAD8 /* SpriteFetchData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 358D403426C66CEB005AAAD8 /* SpriteFetchData.swift */; };
358D403626C66CEB005AAAD8 /* SpriteFetchData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 358D403426C66CEB005AAAD8 /* SpriteFetchData.swift */; };
3592DB1D2AD96E51003D52AD /* IApu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3592DB1C2AD96E51003D52AD /* IApu.swift */; };
3592DB1E2AD96E51003D52AD /* IApu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3592DB1C2AD96E51003D52AD /* IApu.swift */; };
35B78E2E2A86091100B1E42F /* Mapper4.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35B78E2D2A86091100B1E42F /* Mapper4.swift */; };
35B78E2F2A86091100B1E42F /* Mapper4.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35B78E2D2A86091100B1E42F /* Mapper4.swift */; };
35B9C57926C28F9A00E13D57 /* PpuControl1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35B9C57826C28F9A00E13D57 /* PpuControl1.swift */; };
Expand Down Expand Up @@ -187,6 +189,7 @@
356CF0942A87FF780093A24F /* PpuControl2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PpuControl2.swift; sourceTree = "<group>"; };
35714DD12AD3E5FB004A7A3F /* DmcChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DmcChannel.swift; sourceTree = "<group>"; };
358D403426C66CEB005AAAD8 /* SpriteFetchData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpriteFetchData.swift; sourceTree = "<group>"; };
3592DB1C2AD96E51003D52AD /* IApu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IApu.swift; sourceTree = "<group>"; };
35B78E2D2A86091100B1E42F /* Mapper4.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mapper4.swift; sourceTree = "<group>"; };
35B9C57826C28F9A00E13D57 /* PpuControl1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PpuControl1.swift; sourceTree = "<group>"; };
35B9C57D26C291C700E13D57 /* PpuMemory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PpuMemory.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -316,6 +319,7 @@
3505EAB32A6F835E00B14943 /* Channel */,
352AFFE32A6E6DD100F811F8 /* Apu.swift */,
352AFFE62A6E6EA800F811F8 /* AudioDriver.swift */,
3592DB1C2AD96E51003D52AD /* IApu.swift */,
);
path = Apu;
sourceTree = "<group>";
Expand Down Expand Up @@ -569,6 +573,7 @@
3557FBB32A7C12E90059AA50 /* AudioDriveImp.swift in Sources */,
3530FA3826BF6DCF00CF18DD /* Cpu.swift in Sources */,
3539627E2A83623800CF1E97 /* GameViewController.swift in Sources */,
3592DB1D2AD96E51003D52AD /* IApu.swift in Sources */,
3530B88E26C7FC4200A2858C /* ICartridge.swift in Sources */,
3530B88726C7FBE600A2858C /* ICpu.swift in Sources */,
356CF08C2A87935C0093A24F /* AudioController.swift in Sources */,
Expand Down Expand Up @@ -653,6 +658,7 @@
35265B3C26C5548F0031E1A6 /* Renderer.swift in Sources */,
352BF7612A7295D70093CB65 /* ControllerPorts.swift in Sources */,
352F931426C18E0A00323AC1 /* Bitfield8.swift in Sources */,
3592DB1E2AD96E51003D52AD /* IApu.swift in Sources */,
3525761126BD5D5B005AB816 /* RomHeader.swift in Sources */,
352575F626BD4829005AB816 /* NES_EMUApp.swift in Sources */,
352AFFE82A6E6EA800F811F8 /* AudioDriver.swift in Sources */,
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -174,21 +174,5 @@
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "D7A4FCDE-B786-49ED-A5A6-880850FC8AAF"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Shared/NES/Nes+SaveState.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "71"
endingLineNumber = "71"
landmarkName = "getSavedURL()"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>
246 changes: 119 additions & 127 deletions Shared/NES/Apu/Apu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,123 @@

import Foundation

extension Apu: IApu {
func execute(_ cpuCycles: UInt32) {
for _ in 0 ..< cpuCycles {
frameCounter?.Clock()

evenFrame = !evenFrame

triangleChannel?.clockTimer()
if evenFrame {
pulseChannel0?.clockTimer()
pulseChannel1?.clockTimer()
noiseChannel?.clockTimer()
dmcChannel?.clockTimer()
}

elapsedCpuCycles += 1

if elapsedCpuCycles >= Apu.kCpuCyclesPerSample {
elapsedCpuCycles = elapsedCpuCycles - Apu.kCpuCyclesPerSample
let inputFrame: Float32 = SampleChannelsAndMix()
audioDriver?.enqueue(inputFrame: inputFrame)
}
}
}

func handleCpuRead(_ cpuAddress: UInt16) -> UInt8 {
let bitField = Bitfield8()
switch cpuAddress {
case 0x4015:
//IF-D NT21
//@TODO: set bits 7,6,4: DMC interrupt (I), frame interrupt (F), DMC active (D)
//@TODO: Reading this register clears the frame interrupt flag (but not the DMC interrupt flag).
frameCounter?.InhibitInterrupt()

if(pulseChannel0?.getLengthCounter().getValue() ?? 0 > 0)
{
bitField.setPos(bitPos: 0, enabled: 1)
}
if(pulseChannel1?.getLengthCounter().getValue() ?? 0 > 0)
{
bitField.setPos(bitPos: 1, enabled: 1)
}
if(triangleChannel?.getLengthCounter().getValue() ?? 0 > 0)
{
bitField.setPos(bitPos: 2, enabled: 1)
}
if(noiseChannel?.getLengthCounter().getValue() ?? 0 > 0)
{
bitField.setPos(bitPos: 3, enabled: 1)
}

let D:UInt8 = dmcChannel?.interrupt ?? 0
bitField.setPos(bitPos: 4, enabled: D)

let F:UInt8 = getFrameInterrupt()
bitField.setPos(bitPos: 6, enabled: F)
break
default:
break
}

return bitField.value()
}

func handleCpuWrite(_ cpuAddress: UInt16, value: UInt8) {
switch cpuAddress {
case 0x4000,0x4001,0x4002,0x4003:
pulseChannel0?.handleCpuWrite(cpuAddress:cpuAddress,value:value)
break;
case 0x4004,0x4005,0x4006,0x4007:
pulseChannel1?.handleCpuWrite(cpuAddress:cpuAddress,value:value)
break;
case 0x4008,0x400A,0x400B:
triangleChannel?.handleCpuWrite(cpuAddress:cpuAddress,value:value)
break
case 0x400C,0x400E,0x400F:
noiseChannel?.handleCpuWrite(cpuAddress:cpuAddress,value:value)
break
case 0x4010,0x4011,0x4012,0x4013:
dmcChannel?.handleCpuWrite(cpuAddress:cpuAddress,value:value)
break
case 0x4015:
//---D NT21
let enableP1 = testBits(target: BIT(0), value: value)
pulseChannel0?.getLengthCounter().setEnabled(enableP1)

let enableP2 = testBits(target: BIT(1), value: value)
pulseChannel1?.getLengthCounter().setEnabled(enableP2)

let enableTriangle = testBits(target: BIT(2), value: value)
triangleChannel?.getLengthCounter().setEnabled(enableTriangle)

let enableNoise = testBits(target: BIT(3), value: value)
noiseChannel?.getLengthCounter().setEnabled(enableNoise)

let enableDMC = testBits(target: BIT(4), value: value)
dmcChannel?.getLengthCounter().setEnabled(enableDMC)
break
case 0x4017:
frameCounter?.handleCpuWrite(cpuAddress:cpuAddress,value:value)
break
default:
break
}
}
}

class Apu: NSObject {
func stopPlayer() {
audioDriver?.audioUnitPlayer.stop()
}

func setNes(nes:Nes) {
self.nes = nes
func startPlayer() {
audioDriver?.audioUnitPlayer.start()
}

func initialize(nes:Nes) {
self.nes = nes
func initialize() {
initCompoment()
setChannelVolume(type: .PulseChannel1, volume: 1.0)
setChannelVolume(type: .PulseChannel2, volume: 1.0)
Expand All @@ -26,6 +135,7 @@ class Apu: NSObject {

override init() {
super.init()
initialize()
}

func initCompoment() {
Expand All @@ -36,6 +146,7 @@ class Apu: NSObject {
pulseChannel1 = PulseChannel.init(pulseChannelNumber: 1)
triangleChannel = TriangleChannel()
noiseChannel = NoiseChannel()
//@TODO dmcChannel not implement now
//dmcChannel = DmcChannel()
}

Expand All @@ -60,10 +171,10 @@ class Apu: NSObject {
sampleSum = 0
numSamples = 0

HandleCpuWrite(cpuAddress: 0x4017, value: 0)
HandleCpuWrite(cpuAddress: 0x4015, value: 0)
handleCpuWrite(0x4017, value: 0)
handleCpuWrite(0x4015, value: 0)
for address in 0x4000...0x400F {
HandleCpuWrite(cpuAddress:UInt16(address), value:0);
handleCpuWrite(UInt16(address), value:0);
}
}

Expand Down Expand Up @@ -114,130 +225,11 @@ class Apu: NSObject {
return sample
}

func HandleCpuRead( cpuAddress:UInt16) -> UInt8 {
let bitField = Bitfield8()
print("APU HandleCpuRead")
switch cpuAddress {
case 0x4015:
//IF-D NT21
//@TODO: set bits 7,6,4: DMC interrupt (I), frame interrupt (F), DMC active (D)
//@TODO: Reading this register clears the frame interrupt flag (but not the DMC interrupt flag).
frameCounter?.InhibitInterrupt()

if(pulseChannel0?.getLengthCounter().getValue() ?? 0 > 0)
{
bitField.setPos(bitPos: 0, enabled: 1)
}
if(pulseChannel1?.getLengthCounter().getValue() ?? 0 > 0)
{
bitField.setPos(bitPos: 1, enabled: 1)
}
if(triangleChannel?.getLengthCounter().getValue() ?? 0 > 0)
{
bitField.setPos(bitPos: 2, enabled: 1)
}
if(noiseChannel?.getLengthCounter().getValue() ?? 0 > 0)
{
bitField.setPos(bitPos: 3, enabled: 1)
}

let D:UInt8 = dmcChannel?.interrupt ?? 0
bitField.setPos(bitPos: 4, enabled: D)

let F:UInt8 = getFrameInterrupt()
bitField.setPos(bitPos: 6, enabled: F)

//let I:UInt8 = dmcChannel?.getI() ?? 0
//bitField.setPos(bitPos: 7, enabled: I)

break
default:
break
}

return bitField.value()
}

func getFrameInterrupt() -> UInt8 {
let interrupt = frameCounter?.enableIRQ ?? 0
return interrupt
}

func HandleCpuWrite(cpuAddress: UInt16, value: UInt8) {
switch cpuAddress {
case 0x4000,0x4001,0x4002,0x4003:
pulseChannel0?.handleCpuWrite(cpuAddress:cpuAddress,value:value)
break;
case 0x4004,0x4005,0x4006,0x4007:
pulseChannel1?.handleCpuWrite(cpuAddress:cpuAddress,value:value)
break;
case 0x4008,0x400A,0x400B:
triangleChannel?.handleCpuWrite(cpuAddress:cpuAddress,value:value)
break
case 0x400C,0x400E,0x400F:
noiseChannel?.handleCpuWrite(cpuAddress:cpuAddress,value:value)
break
case 0x4010,0x4011,0x4012,0x4013:

//print("$4010–$4013")
dmcChannel?.handleCpuWrite(cpuAddress:cpuAddress,value:value)
break
case 0x4015:
//---D NT21
let enableP1 = testBits(target: BIT(0), value: value)
pulseChannel0?.getLengthCounter().setEnabled(enableP1)

let enableP2 = testBits(target: BIT(1), value: value)
pulseChannel1?.getLengthCounter().setEnabled(enableP2)


let enableTriangle = testBits(target: BIT(2), value: value)
triangleChannel?.getLengthCounter().setEnabled(enableTriangle)

let enableNoise = testBits(target: BIT(3), value: value)
noiseChannel?.getLengthCounter().setEnabled(enableNoise)

//@TODO: DMC Enable bit 4
let enableDMC = testBits(target: BIT(4), value: value)
dmcChannel?.getLengthCounter().setEnabled(enableDMC)
break
case 0x4017:
frameCounter?.handleCpuWrite(cpuAddress:cpuAddress,value:value)
break
default:
break
}
}

var evenFrame = false
func execute(_ cpuCycles: UInt32) {
for _ in 0 ..< cpuCycles {
frameCounter?.Clock()

evenFrame = !evenFrame

triangleChannel?.clockTimer()
if evenFrame {
pulseChannel0?.clockTimer()
pulseChannel1?.clockTimer()
noiseChannel?.clockTimer()
dmcChannel?.clockTimer()
}

elapsedCpuCycles += 1

//All output
//let inputFrame: Float32 = SampleChannelsAndMix()
//audioDriver?.enqueue(inputFrame: inputFrame)

if elapsedCpuCycles >= Apu.kCpuCyclesPerSample {
elapsedCpuCycles = elapsedCpuCycles - Apu.kCpuCyclesPerSample
let inputFrame: Float32 = SampleChannelsAndMix()
audioDriver?.enqueue(inputFrame: inputFrame)
}
}
}

enum ApuChannel {
case PulseChannel1
case PulseChannel2
Expand All @@ -264,5 +256,5 @@ class Apu: NSObject {
var sampleSum = 0
var numSamples = 0
var channelVolumes:[ApuChannel:Float32] = [:]
var nes:Nes? = nil
var evenFrame = false
}
3 changes: 1 addition & 2 deletions Shared/NES/Apu/AudioDriver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ class NesFrameProvider : FrameProvider{
var frames:[Float32] = []
let lockInput = NSLock()

func enqueue(inputFrame: Float32)
{
func enqueue(inputFrame: Float32) {
lockInput.lock()
frames.append(inputFrame)
lockInput.unlock()
Expand Down
14 changes: 14 additions & 0 deletions Shared/NES/Apu/IApu.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// IApu.swift
// NES_EMU
//
// Created by mio on 2023/10/13.
//

import Foundation

protocol IApu: HandleCpuReadWriteProtocol {
func execute(_ cpuCycles: UInt32)
func startPlayer()
func stopPlayer()
}
Loading

0 comments on commit a8e3b9e

Please sign in to comment.