diff --git a/Assets/Game.unity b/Assets/Game.unity new file mode 100644 index 0000000..98b5053 --- /dev/null +++ b/Assets/Game.unity @@ -0,0 +1,994 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &54588347 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 54588348} + - component: {fileID: 54588350} + - component: {fileID: 54588349} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &54588348 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 54588347} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1712987038} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &54588349 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 54588347} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'START + +' +--- !u!222 &54588350 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 54588347} + m_CullTransparentMesh: 1 +--- !u!1 &77869763 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 77869764} + - component: {fileID: 77869766} + - component: {fileID: 77869765} + m_Layer: 0 + m_Name: AudioProvider + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &77869764 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 77869763} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 706021509} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!82 &77869765 +AudioSource: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 77869763} + m_Enabled: 1 + serializedVersion: 4 + OutputAudioMixerGroup: {fileID: 0} + m_audioClip: {fileID: 0} + m_PlayOnAwake: 1 + m_Volume: 1 + m_Pitch: 1 + Loop: 0 + Mute: 0 + Spatialize: 0 + SpatializePostEffects: 0 + Priority: 128 + DopplerLevel: 1 + MinDistance: 1 + MaxDistance: 500 + Pan2D: 0 + rolloffMode: 0 + BypassEffects: 0 + BypassListenerEffects: 0 + BypassReverbZones: 0 + rolloffCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + panLevelCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + spreadCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + reverbZoneMixCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!114 &77869766 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 77869763} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: af17dd239b0eea44592e0cd125b2e3b9, type: 3} + m_Name: + m_EditorClassIdentifier: + m_as: {fileID: 77869765} +--- !u!1 &109485475 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 109485478} + - component: {fileID: 109485477} + - component: {fileID: 109485476} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &109485476 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 109485475} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &109485477 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 109485475} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &109485478 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 109485475} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &706021508 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 706021509} + - component: {fileID: 706021510} + m_Layer: 0 + m_Name: Emulator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &706021509 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 706021508} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1348932687} + - {fileID: 77869764} + - {fileID: 884831573} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &706021510 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 706021508} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 515e71167c74b044984b170a2a141f10, type: 3} + m_Name: + m_EditorClassIdentifier: + videoProvider: {fileID: 1348932686} + audioProvider: {fileID: 77869766} + ShowBackBuf: 0 + RunEmulator: 0 + EnableAudio: 1 + BootBIOS: 0 + audioGain: 1 + btnStart: {fileID: 1712987039} +--- !u!1 &763702298 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 763702300} + - component: {fileID: 763702299} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!108 &763702299 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 763702298} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &763702300 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 763702298} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &884831572 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 884831573} + - component: {fileID: 884831576} + - component: {fileID: 884831575} + - component: {fileID: 884831574} + - component: {fileID: 884831577} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &884831573 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 884831572} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 1537688724} + - {fileID: 1712987038} + m_Father: {fileID: 706021509} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!114 &884831574 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 884831572} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &884831575 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 884831572} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &884831576 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 884831572} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &884831577 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 884831572} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a6d4732564041e4d85a5fbef37546d6, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1348932685 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1348932687} + - component: {fileID: 1348932686} + m_Layer: 0 + m_Name: VideoProvider + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1348932686 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1348932685} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 331cd2e4e0a49874cab11aa18b69e827, type: 3} + m_Name: + m_EditorClassIdentifier: + m_drawCanvas: {fileID: 1537688722} +--- !u!4 &1348932687 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1348932685} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 706021509} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1421561889 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1421561892} + - component: {fileID: 1421561891} + - component: {fileID: 1421561890} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1421561890 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1421561889} + m_Enabled: 1 +--- !u!20 &1421561891 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1421561889} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1421561892 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1421561889} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1537688721 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1537688724} + - component: {fileID: 1537688723} + - component: {fileID: 1537688722} + m_Layer: 5 + m_Name: RawImage + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1537688722 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1537688721} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 0} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!222 &1537688723 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1537688721} + m_CullTransparentMesh: 1 +--- !u!224 &1537688724 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1537688721} + m_LocalRotation: {x: 1, y: 0, z: 0, w: 0} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 884831573} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 180, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1280, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1712987037 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1712987038} + - component: {fileID: 1712987041} + - component: {fileID: 1712987040} + - component: {fileID: 1712987039} + m_Layer: 5 + m_Name: btnStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1712987038 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1712987037} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 54588348} + m_Father: {fileID: 884831573} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -471, y: -281} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1712987039 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1712987037} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1712987040} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1712987040 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1712987037} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1712987041 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1712987037} + m_CullTransparentMesh: 1 diff --git a/Assets/Game.unity.meta b/Assets/Game.unity.meta new file mode 100644 index 0000000..ffe3369 --- /dev/null +++ b/Assets/Game.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 88a72b3d9c54eff4e991fdae233d3452 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MyUnSafeCommon.cs b/Assets/MyUnSafeCommon.cs deleted file mode 100644 index 0aede9e..0000000 --- a/Assets/MyUnSafeCommon.cs +++ /dev/null @@ -1,344 +0,0 @@ -using System; -using System.Linq; -using System.Runtime.ConstrainedExecution; -using System.Runtime.InteropServices; - -public static class MyUnSafeCommon -{ - public static ref T GetArrayDataReference(T[] array) - { - if (array == null) throw new ArgumentNullException(nameof(array)); - if (array.Length == 0) throw new ArgumentException("Array cannot be empty", nameof(array)); - return ref array[0]; - } - - //public unsafe static ref T GetArrayDataReference(T[] array) where T : struct - //{ - // fixed (T* ptr = array) - // { - // return ref ArrayElementAsRef(ptr, 0); - // } - //} - - //public unsafe static ref T ArrayElementAsRef(void* ptr, int index) where T : struct - //{ - // return ref Unity.Collections.LowLevel.Unsafe.UnsafeUtility.ArrayElementAsRef(ptr, index); - //} - -} - - -public static class MyBitOperations -{ - // 计算一个整数的位计数(也称为汉明重量) - public static int PopCount(uint value) - { - int count = 0; - while (value != 0) - { - value &= value - 1; // 清除最低位的1 - count++; - } - return count; - } - - // 如果需要处理long或int等其他类型,可以添加重载 - public static int PopCount(int value) - { - return PopCount((uint)value); // 对于int,简单地将其视为无符号的uint来处理 - } - - // 对于long,你可能需要更复杂的处理或额外的迭代,但基本思想相同 - public static int PopCount(long value) - { - int count = 0; - value = value - ((value >> 1) & 0x5555555555555555L); // 每两位一组求和 - value = (value & 0x3333333333333333L) + ((value >> 2) & 0x3333333333333333L); // 每四位一组求和 - value = (value + (value >> 4)) & 0x0f0f0f0f0f0f0f0fL; // 每八位一组求和 - count = (int)((value * 0x0101010101010101L) >> 56); // 计算总和 - return count; - } - - // 向右旋转指定数量的位(等效于BitOperations.RotateRight) - public static uint RotateRight(uint value, int count) - { - // 确保旋转位数在有效范围内(对于uint,0到31) - count &= 31; - - // 使用位移和位或操作来实现旋转 - // 先右移count位 - uint rightShifted = value >> count; - - // 然后左移(32 - count)位,并将结果与右移的结果进行位或操作 - // 注意:由于uint是无符号的,所以左移不会导致符号扩展 - uint leftShifted = (value << (32 - count)) & 0xFFFFFFFF; // 实际上,对于uint,& 0xFFFFFFFF是多余的,但在这里为了清晰性而保留 - - // 组合结果 - return rightShifted | leftShifted; - } - - // 如果需要处理ulong,可以添加类似的重载 - public static ulong RotateRight(ulong value, int count) - { - // 确保旋转位数在有效范围内(对于ulong,0到63) - count &= 63; - - // 使用位移和位或操作来实现旋转 - // 注意:ulong需要64位操作 - ulong rightShifted = value >> count; - ulong leftShifted = (value << (64 - count)) & 0xFFFFFFFFFFFFFFFF; // 同样,对于ulong,& 0xFFFFFFFFFFFFFFFF是多余的,但保留以增加清晰性 - - // 组合结果 - return rightShifted | leftShifted; - } -} - - - - -public static class MyStruct -{ - [StructLayout(LayoutKind.Sequential)] - public struct Vector256 where T : struct, IComparable, IComparable, IEquatable, IFormattable - { - public T[] data; - - // 假设Vector256总是包含8个元素(对于uint来说,总共32字节) - public const int ElementCount = 8; - - // 私有构造函数,用于内部创建实例 - public Vector256(T[] data) - { - if (data == null || data.Length != ElementCount) - throw new ArgumentException("Data array must contain exactly 8 elements."); - - this.data = data; - } - - // 静态Create方法,用于从T类型的数组创建Vector256实例 - public static Vector256 Create(params T[] values) - { - if (values.Length > ElementCount) - throw new ArgumentException("Too many values provided."); - - T[] fullData = new T[ElementCount]; - Array.Copy(values, 0, fullData, 0, values.Length); - - // 对于uint,默认值是0 - if (typeof(T) == typeof(uint)) - { - for (int i = values.Length; i < ElementCount; i++) - { - fullData[i] = (T)(object)0u; // 使用显式类型转换来避免编译时错误 - } - } - - return new Vector256(fullData); - } - - // 静态Zero属性,返回一个所有元素都为0的Vector256实例 - public static Vector256 Zero - { - get - { - if (typeof(T) == typeof(uint)) - { - uint[] zeroData = new uint[ElementCount]; - //Array.Fill(zeroData, 0u); // 使用Array.Fill来填充所有元素为0 - return new Vector256((T[])(object)zeroData); // 显式类型转换以绕过泛型约束 - } - - // 如果T不是uint,这里可能需要抛出一个异常或者返回一个默认构造的Vector256 - // 但由于泛型约束,实际上T必须是uint(或者同时满足其他接口的类型,但在这个上下文中我们只关心uint) - // 因此,这里实际上不会执行到 - throw new InvalidOperationException("Zero property is only valid for Vector256."); - } - } - - // ... 可以根据需要添加更多重载 - - // 为了方便调试,可以重写ToString方法 - public override string ToString() - { - return string.Join(", ", Array.ConvertAll(data, x => x.ToString())); - } - } - - - // 模拟 Avx2.ConvertToVector256Int32 - public static Vector256 ConvertToVector256Int32(byte[] source) - { - if (source.Length < 32) // 32 bytes for 8 uints - throw new ArgumentException("Source array must be at least 32 bytes long."); - - uint[] uints = new uint[8]; - for (int i = 0; i < 8; i++) - { - uints[i] = BitConverter.ToUInt32(source, i * 4); - } - - return new Vector256(uints); - } - - // 模拟 Avx2.ShiftLeftLogical - public static Vector256 ShiftLeftLogical(Vector256 metaVec, int shift) - { - int[] shifted = new int[8]; - for (int i = 0; i < 8; i++) - { - shifted[i] = (int)(metaVec.data[i] << shift); - } - return new Vector256(shifted); - } - // 模拟 Avx2.And - public static Vector256 And(Vector256 data1, Vector256 data2) - { - int[] result = new int[8]; - for (int i = 0; i < 8; i++) - { - result[i] = data1.data[i] & data2.data[i]; - } - return new Vector256(result); - } - // 模拟 Avx2.And - public static Vector256 And(Vector256 data1, Vector256 data2) - { - uint[] result = new uint[8]; - for (int i = 0; i < 8; i++) - { - result[i] = data1.data[i] & data2.data[i]; - } - - return new Vector256(result); - } - - // 模拟 Avx2.Or - public static Vector256 Or(Vector256 data1, Vector256 data2) - { - int[] result = new int[8]; - for (int i = 0; i < 8; i++) - { - result[i] = data1.data[i] | data2.data[i]; - } - - return new Vector256(result); - } - // 模拟 Avx2.Or - public static Vector256 Or(Vector256 data1, Vector256 data2) - { - uint[] result = new uint[8]; - for (int i = 0; i < 8; i++) - { - result[i] = data1.data[i] | data2.data[i]; - } - - return new Vector256(result); - } - - // 模拟 Avx2.Xor - - public static Vector256 Xor(Vector256 data1, Vector256 data2) - { - int[] result = new int[8]; - for (int i = 0; i < 8; i++) - { - result[i] = data1.data[i] ^ data2.data[i]; - } - return new Vector256(result); - } - - public static Vector256 Xor(Vector256 data1, Vector256 data2) - { - uint[] result = new uint[8]; - for (int i = 0; i < 8; i++) - { - result[i] = data1.data[i] ^ data2.data[i]; - } - - return new Vector256(result); - } - - // 模拟 Avx2.Permute2x128 (只模拟上下两半交换) - public static Vector256 Permute2x128(Vector256 data) - { - uint[] swapped = new uint[8]; - Array.Copy(data.data, 4, swapped, 0, 4); - Array.Copy(data.data, 0, swapped, 4, 4); - return new Vector256(swapped); - } - // 模拟 Avx2.Permute2x128 (只模拟上下两半交换) - public static Vector256 Permute2x128(Vector256 data) - { - int[] swapped = new int[8]; - Array.Copy(data.data, 4, swapped, 0, 4); - Array.Copy(data.data, 0, swapped, 4, 4); - return new Vector256(swapped); - } - - // 模拟 Avx2.CompareEqual - public static Vector256 CompareEqual(Vector256 left, Vector256 right) - { - int[] result = new int[8]; - for (int i = 0; i < 8; i++) - { - result[i] = (left.data[i] == right.data[i]) ? -1 : 0; // 通常使用-1或全1表示真,0表示假 - } - return new Vector256(result); - } - // 模拟 MaskedStore 操作 - public static void MaskedStore(Vector256 destination, Vector256 mask, Vector256 source) - { - //if (destination.Length < 8 || mask.Length != 8 || source.data.Length != 8) - // throw new ArgumentException("Arrays must be of length 8 and match in size."); - - for (int i = 0; i < 8; i++) - { - // 如果掩码中的值为非零(表示真),则写入源向量的值 - if (mask.data[i] != 0) - { - destination.data[i] = source.data[i]; - } - // 如果掩码中的值为零(表示假),则不修改destination[i] - } - } - - // 注意:这不是AVX2的gather指令的直接模拟,而是一个简化的示例 - public static Vector256 GatherVector256(T[] source, int[] indices) - { - if (source.Length < 8 || indices.Length < 8) - throw new ArgumentException("Source array and indices array must be large enough."); - - int[] gatheredData = new int[8]; - for (int i = 0; i < 8; i++) - { - int index = indices[i]; - if (index < 0 || index >= source.Length) - gatheredData[i] = source[index]; - } - - return new Vector256(gatheredData); - } - - - // 模拟 ShiftRightLogicalVariable,接受两个 Vector256 参数 - // 第一个参数是要右移的向量,第二个参数是每个元素要右移的位数 - public static Vector256 ShiftRightLogicalVariable(this Vector256 vector, Vector256 shiftCounts) - { - if (vector.data.Length != shiftCounts.data.Length) - { - throw new ArgumentException("Both vectors must have the same number of elements."); - } - - uint[] shiftedData = new uint[Vector256.ElementCount]; - for (int i = 0; i < vector.data.Length; i++) - { - // 注意:这里假设 shiftCounts.data[i] 中的值是有效的右移位数(非负且小于 32) - // 如果需要,可以添加额外的检查来处理无效值 - int shiftCount = (int)shiftCounts.data[i] & 0x1F; // 限制右移位数在 0 到 31 之间 - shiftedData[i] = vector.data[i] >> shiftCount; - } - - return new Vector256(shiftedData); - } - -} \ No newline at end of file diff --git a/Assets/Resources.meta b/Assets/Resources.meta new file mode 100644 index 0000000..7af9654 --- /dev/null +++ b/Assets/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f82937a8bdf895f4788174f079d4941d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/MarioAdvance(J).gba.bytes b/Assets/Resources/MarioAdvance(J).gba.bytes new file mode 100644 index 0000000..3b44b78 Binary files /dev/null and b/Assets/Resources/MarioAdvance(J).gba.bytes differ diff --git a/Assets/Resources/MarioAdvance(J).gba.bytes.meta b/Assets/Resources/MarioAdvance(J).gba.bytes.meta new file mode 100644 index 0000000..fbd9364 --- /dev/null +++ b/Assets/Resources/MarioAdvance(J).gba.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d2ea7bc8e7d2a9d4383c5e586779c6ad +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/gba_bios.bin.bytes b/Assets/Resources/gba_bios.bin.bytes new file mode 100644 index 0000000..2a78f2c Binary files /dev/null and b/Assets/Resources/gba_bios.bin.bytes differ diff --git a/Assets/Resources/gba_bios.bin.bytes.meta b/Assets/Resources/gba_bios.bin.bytes.meta new file mode 100644 index 0000000..f18eadd --- /dev/null +++ b/Assets/Resources/gba_bios.bin.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 99103839218b11c42820fbe24d848833 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/mario2.gba.bytes b/Assets/Resources/mario2.gba.bytes new file mode 100644 index 0000000..f26541d Binary files /dev/null and b/Assets/Resources/mario2.gba.bytes differ diff --git a/Assets/Resources/mario2.gba.bytes.meta b/Assets/Resources/mario2.gba.bytes.meta new file mode 100644 index 0000000..ec8e686 --- /dev/null +++ b/Assets/Resources/mario2.gba.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9de3173972725794ab0d4d305c3f88b0 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/mario_world.gba.bytes b/Assets/Resources/mario_world.gba.bytes new file mode 100644 index 0000000..e3dcf06 Binary files /dev/null and b/Assets/Resources/mario_world.gba.bytes differ diff --git a/Assets/Resources/mario_world.gba.bytes.meta b/Assets/Resources/mario_world.gba.bytes.meta new file mode 100644 index 0000000..7957d2f --- /dev/null +++ b/Assets/Resources/mario_world.gba.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 152604cac101e294ab24dbfab7954669 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/emulator/ApplySkipLocalsInit.cs b/Assets/emulator/ApplySkipLocalsInit.cs deleted file mode 100644 index 99aa6de..0000000 --- a/Assets/emulator/ApplySkipLocalsInit.cs +++ /dev/null @@ -1 +0,0 @@ -//[module: System.Runtime.CompilerServices.SkipLocalsInit] \ No newline at end of file diff --git a/Assets/emulator/AudioProvider.cs b/Assets/emulator/AudioProvider.cs new file mode 100644 index 0000000..5dbbfd8 --- /dev/null +++ b/Assets/emulator/AudioProvider.cs @@ -0,0 +1,80 @@ +using OptimeGBA; +using System; +using UnityEngine; + + +public class AudioProvider : MonoBehaviour +{ + [SerializeField] + private AudioSource m_as; + private RingBuffer _buffer; + private TimeSpan lastElapsed; + public double audioFPS { get; private set; } + float lastData = 0; + + public void Awake() + { + //var dummy = AudioClip.Create("dummy", 1,2, AudioSettings.outputSampleRate, false); + AudioClip clip = AudioClip.Create("blank", GbaAudio.SampleRate * 2, 2, GbaAudio.SampleRate, true); + _buffer = new RingBuffer(GbaAudio.SampleRate * 2); + m_as.clip = clip; + m_as.playOnAwake = true; + //m_as.loop = true; + m_as.spatialBlend = 1; + } + public void Initialize() + { + if (!m_as.isPlaying) + { + m_as.Play(); + } + } + private void OnAudioFilterRead(float[] data, int channels) + { + int step = channels; + step = 1; + for (int i = 0; i < data.Length; i += step) + { + if (_buffer.TryRead(out float rawData)) + { + data[i] = rawData; + } + else + { + break; + } + } + + //int step = channels; + //step = 1; + //for (int i = 0; i < data.Length; i += step) + //{ + // float rawFloat = lastData; + // if (_buffer.TryRead(out float rawData)) + // { + // rawFloat = rawData; + // } + + // data[i] = rawFloat; + // for (int fill = 1; fill < step; fill++) + // data[i + fill] = rawFloat; + // lastData = rawFloat; + //} + } + + + public void AudioReady(float[] data) + { + if (!Emulator.instance.EnableAudio) return; + + var current = Emulator.sw.Elapsed; + var delta = current - lastElapsed; + lastElapsed = current; + audioFPS = 1d / delta.TotalSeconds; + + for (int i = 0; i < data.Length; i++) + { + _buffer.Write(data[i]); + } + } +} \ No newline at end of file diff --git a/Assets/emulator/ApplySkipLocalsInit.cs.meta b/Assets/emulator/AudioProvider.cs.meta similarity index 83% rename from Assets/emulator/ApplySkipLocalsInit.cs.meta rename to Assets/emulator/AudioProvider.cs.meta index 81cabb9..4103750 100644 --- a/Assets/emulator/ApplySkipLocalsInit.cs.meta +++ b/Assets/emulator/AudioProvider.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 758bfc6cd0551814abf32fc61d504c02 +guid: af17dd239b0eea44592e0cd125b2e3b9 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/BlipBuf.cs b/Assets/emulator/BlipBuf.cs index 37828cd..34ae3b5 100644 --- a/Assets/emulator/BlipBuf.cs +++ b/Assets/emulator/BlipBuf.cs @@ -126,8 +126,7 @@ namespace OptimeGBA if (sample < CurrentSampleOutPos) { - Console.Error.WriteLine("Tried to set amplitude backward in time!"); - Console.WriteLine(System.Environment.StackTrace); + //Console.WriteLine("Tried to set amplitude backward in time!"); } ChannelSample[channel] = sample; diff --git a/Assets/emulator/BlipBuf.cs.meta b/Assets/emulator/BlipBuf.cs.meta index 5bd5397..2abbfd7 100644 --- a/Assets/emulator/BlipBuf.cs.meta +++ b/Assets/emulator/BlipBuf.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d2f0e6f7505a3d04bb84e704d1ed8d33 +guid: 89bf553b1fa17dd4fa93a74803b75d0a MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/CartridgeNds.cs b/Assets/emulator/CartridgeNds.cs deleted file mode 100644 index 6e1e35f..0000000 --- a/Assets/emulator/CartridgeNds.cs +++ /dev/null @@ -1,770 +0,0 @@ -using static Util; -using static OptimeGBA.Bits; -using static OptimeGBA.MemoryUtil; -using System; -using System.Text; -namespace OptimeGBA -{ - public enum SpiEepromState - { - Ready, - ReadStatus, - WriteStatus, - SetReadAddress, - SetWriteAddress, - ReadData, - WriteData, - Done, - } - - public enum ExternalMemoryType - { - None, - Eeprom, - Flash, - FlashWithInfrared - } - - public enum CartridgeState - { - Dummy, - ReadCartridgeHeader, - ReadRomChipId1, - Dummy2, - ReadRomChipId2, - Key2DataRead, - SecureAreaRead, - ReadRomChipId3, - } - - public class CartridgeNds - { - Nds Nds; - byte[] Rom; - byte[] SecureArea = new byte[0x4000]; - - public uint[] EncLutKeycodeLevel1 = new uint[0x412]; - public uint[] EncLutKeycodeLevel2 = new uint[0x412]; - public uint[] EncLutKeycodeLevel3 = new uint[0x412]; - - public uint IdCode; - public string IdString; - - public CartridgeNds(Nds nds) - { - Nds = nds; - Rom = Nds.Provider.Rom; - - for (uint i = 0; i < 0x412; i++) - { - uint val = GetUint(Nds.Provider.Bios7, 0x30 + i * 4); - EncLutKeycodeLevel1[i] = val; - EncLutKeycodeLevel2[i] = val; - EncLutKeycodeLevel3[i] = val; - } - - if (Rom.Length >= 0x10) - { - IdCode = GetUint(Rom, 0x0C); - - Span gameIdSpan = stackalloc byte[4]; - for (int i = 0; i < 4; i++) - { - gameIdSpan[i] = GetByte(Rom, 0x0C + (uint)i); - } - - IdString = Encoding.ASCII.GetString(gameIdSpan); - Console.WriteLine("Game ID: " + IdString); - } - - InitKeycode(EncLutKeycodeLevel1, 1); - InitKeycode(EncLutKeycodeLevel2, 2); - InitKeycode(EncLutKeycodeLevel3, 3); - - if (!Nds.Provider.DirectBoot && Rom.Length >= 0x8000 && GetUint(Rom, 0x4000) == 0xE7FFDEFF) - { - for (uint i = 0; i < 0x4000; i++) - { - SecureArea[i] = Rom[0x4000 + i]; - } - Console.WriteLine("Encrypting first 2KB of secure area"); - SetUlong(SecureArea, 0x0000, 0x6A624F7972636E65); // Write in "encryObj" - - // Encrypt first 2K of the secure area with KEY1 - for (uint i = 0x0000; i < 0x0800; i += 8) - { - // Console.WriteLine("Encrypted ulong at " + Hex(i, 16)); - ulong raw = GetUlong(SecureArea, i); - ulong encrypted = Encrypt64(EncLutKeycodeLevel3, raw); - SetUlong(SecureArea, i, encrypted); - // Console.WriteLine("Before:" + Hex(raw, 16)); - // Console.WriteLine("After :" + Hex(encrypted, 16)); - } - - Console.WriteLine(Hex(GetUint(SecureArea, 0x0010), 8)); - - // Double-encrypt KEY1 - SetUlong(SecureArea, 0x0000, Encrypt64(EncLutKeycodeLevel2, GetUlong(SecureArea, 0x0000))); - } - - for (uint i = 0; i < ExternalMemory.Length; i++) - { - ExternalMemory[i] = 0xFF; - } - } - - ulong PendingCommand; - - // some GBATek example - // TODO: Replace this with something more realistic, maybe from a game DB - public uint RomChipId = 0x00001FC2; - - // State - public CartridgeState State; - public uint DataPos; - public uint BytesTransferred; - public bool Key1Encryption; - public bool Key2Encryption; - - public uint TransferLength; - public uint PendingDummyWrites; - - public bool ReadyBit23; - public byte BlockSize; - public bool SlowTransferClock; - public bool BusyBit31; - - // AUXSPICNT - public byte SpiBaudRate; - public bool SpiChipSelHold = false; - public bool SpiBusy = false; - public bool Slot1SpiMode = false; - public bool TransferReadyIrq = false; - public bool Slot1Enable = false; - - // Shared External Memory State - public SpiEepromState SpiEepromState; - public byte SpiOutData; - public uint SpiAddress; - public uint SpiBytesWritten; - public bool ExternalMemoryWriteEnable; - // only one game called art academy uses more than 1MB - public byte[] ExternalMemory = new byte[1048576]; - - // EEPROM state - public byte EepromWriteProtect; - - // Flash state - // From Nocash's original DS - // TODO: use more realistic flash ID - byte[] FlashId = new byte[] { 0x20, 0x40, 0x12 }; - public SpiFlashState SpiFlashState; - public byte FlashIdIndex; - - // ROMCTRL - byte ROMCTRLB0; - byte ROMCTRLB1; - bool ReleaseReset; - - // cart input - uint InData; - - public byte ReadHwio8(bool fromArm7, uint addr) - { - byte val = 0; - if (fromArm7 == Nds.MemoryControl.Nds7Slot1AccessRights) - { - switch (addr) - { - case 0x40001A0: // AUXSPICNT B0 - val |= SpiBaudRate; - if (SpiChipSelHold) val = BitSet(val, 6); - if (SpiBusy) val = BitSet(val, 7); - // Console.WriteLine("AUXSPICNT B0 read"); - break; - case 0x40001A1: // AUXSPICNT B1 - if (Slot1SpiMode) val = BitSet(val, 5); - if (TransferReadyIrq) val = BitSet(val, 6); - if (Slot1Enable) val = BitSet(val, 7); - break; - - case 0x40001A2: // AUXSPIDATA - return SpiOutData; - - case 0x40001A4: // ROMCTRL B0 - return ROMCTRLB0; - case 0x40001A5: // ROMCTRL B1 - return ROMCTRLB1; - case 0x40001A6: // ROMCTRL B2 - if (ReleaseReset) val = BitSet(val, 5); - if (ReadyBit23) val = BitSet(val, 7); - break; - case 0x40001A7: // ROMCTRL B3 - val |= BlockSize; - if (SlowTransferClock) val = BitSet(val, 3); - if (BusyBit31) val = BitSet(val, 7); - break; - - case 0x4100010: // From cartridge - if (Slot1Enable) - { - ReadData(fromArm7); - } - return (byte)(InData >> 0); - case 0x4100011: - return (byte)(InData >> 8); - case 0x4100012: - return (byte)(InData >> 16); - case 0x4100013: - return (byte)(InData >> 24); - } - } - else - { - Console.WriteLine((fromArm7 ? "ARM7" : "ARM9") + " tried to read from Slot 1 @ " + Hex(addr, 8)); - } - - return val; - } - - public void WriteHwio8(bool fromArm7, uint addr, byte val) - { - if (fromArm7 == Nds.MemoryControl.Nds7Slot1AccessRights) - { - switch (addr) - { - case 0x40001A0: // AUXSPICNT B0 - SpiBaudRate = (byte)(val & 0b11); - SpiChipSelHold = BitTest(val, 6); - SpiBusy = BitTest(val, 7); - return; - case 0x40001A1: // AUXSPICNT B1 - Slot1SpiMode = BitTest(val, 5); - TransferReadyIrq = BitTest(val, 6); - Slot1Enable = BitTest(val, 7); - return; - - case 0x40001A2: // AUXSPIDATA - SpiTransferTo(val); - break; - - case 0x40001A4: // ROMCTRL B0 - ROMCTRLB0 = val; - break; - case 0x40001A5: // ROMCTRL B1 - ROMCTRLB1 = val; - break; - case 0x40001A6: // ROMCTRL B2 - if (BitTest(val, 5)) ReleaseReset = true; - break; - case 0x40001A7: // ROMCTRL B3 - BlockSize = (byte)(val & 0b111); - SlowTransferClock = BitTest(val, 3); - - if (BitTest(val, 7) && !BusyBit31 && Slot1Enable) - { - ProcessCommand(fromArm7); - } - break; - } - - if (Slot1Enable) - { - switch (addr) - { - case 0x40001A8: // Slot 1 Command out - case 0x40001A9: - case 0x40001AA: - case 0x40001AB: - case 0x40001AC: - case 0x40001AD: - case 0x40001AE: - case 0x40001AF: - if (Slot1Enable) - { - int shiftBy = (int)((7 - (addr & 7)) * 8); - PendingCommand &= (ulong)(~(0xFFUL << shiftBy)); - PendingCommand |= (ulong)val << shiftBy; - } - return; - } - } - } - else - { - Console.WriteLine((fromArm7 ? "ARM7" : "ARM9") + " tried to read from Slot 1 @ " + Hex(addr, 8)); - } - } - - public void ProcessCommand(bool fromArm7) - { - ulong cmd = PendingCommand; - if (Key1Encryption) - { - cmd = Decrypt64(EncLutKeycodeLevel2, cmd); - } - - // Console.WriteLine("Slot 1 CMD: " + Hex(cmd, 16)); - - if (BlockSize == 0) - { - TransferLength = 0; - } - else if (BlockSize == 7) - { - TransferLength = 4; - } - else - { - TransferLength = 0x100U << BlockSize; - } - - if (TransferLength != 0) - { - DataPos = 0; - BytesTransferred = 0; - } - - BusyBit31 = true; - - if (cmd == 0x9F00000000000000) - { - State = CartridgeState.Dummy; - } - else if (cmd == 0x0000000000000000) - { - // Console.WriteLine("Slot 1: Putting up cartridge header"); - State = CartridgeState.ReadCartridgeHeader; - } - else if (cmd == 0x9000000000000000) - { - // Console.WriteLine("Slot 1: Putting up ROM chip ID 1"); - State = CartridgeState.ReadRomChipId1; - } - else if ((cmd & 0xFF00000000000000) == 0x3C00000000000000) - { - // Console.WriteLine("Slot 1: Enabled KEY1 encryption"); - State = CartridgeState.Dummy2; - Key1Encryption = true; - } - else if ((cmd & 0xF000000000000000) == 0x2000000000000000) - { - // Console.WriteLine("Slot 1: Get Secure Area Block"); - State = CartridgeState.SecureAreaRead; - DataPos = (uint)(((cmd >> 44) & 0xFFFF) * 0x1000); - // Console.WriteLine("Secure area read pos: " + Hex(DataPos, 8)); - } - else if ((cmd & 0xF000000000000000) == 0x4000000000000000) - { - // Console.WriteLine("Slot 1: Enable KEY2"); - State = CartridgeState.Dummy2; - } - else if ((cmd & 0xF000000000000000) == 0x1000000000000000) - { - // Console.WriteLine("Slot 1: Putting up ROM chip ID 2"); - State = CartridgeState.ReadRomChipId2; - } - else if ((cmd & 0xF000000000000000) == 0xA000000000000000) - { - // Console.WriteLine("Slot 1: Enter main data mode"); - State = CartridgeState.Dummy2; - Key1Encryption = false; - } - else if ((cmd & 0xFF00000000FFFFFF) == 0xB700000000000000) - { - // On a real DS, KEY2 encryption is transparent to software, - // as it is all handled in the hardware cartridge interface. - // Plus, DS ROM dumps are usually KEY2 decrypted, so in most cases - // there's actually no need to actually handle KEY2 encryption in - // an emulator. - // Console.WriteLine("KEY2 data read"); - State = CartridgeState.Key2DataRead; - - DataPos = (uint)((cmd >> 24) & 0xFFFFFFFF); - // Console.WriteLine("Addr: " + Hex(DataPos, 8)); - } - else if (cmd == 0xB800000000000000) - { - // Console.WriteLine("Slot 1: Putting up ROM chip ID 3"); - State = CartridgeState.ReadRomChipId3; - } - else - { - // throw new NotImplementedException("Slot 1: unimplemented command " + Hex(cmd, 16)); - } - // If block size is zero, no transfer will take place, signal end. - if (TransferLength == 0) - { - FinishTransfer(); - } - else - { - ReadyBit23 = true; - - // Trigger Slot 1 DMA - Nds.Scheduler.AddEventRelative(SchedulerId.None, 0, RepeatCartridgeTransfer); - // Console.WriteLine("Trigger slot 1 DMA, Dest: " + Hex(Nds.Dma7.Ch[3].DmaDest, 8)); - } - } - - public void ReadData(bool fromArm7) - { - if (!ReadyBit23) - { - InData = 0; - return; - } - - uint val = 0xFFFFFFFF; - - switch (State) - { - case CartridgeState.Dummy: // returns all 1s - break; - case CartridgeState.ReadCartridgeHeader: - val = GetUint(Rom, DataPos & 0xFFF); - break; - case CartridgeState.ReadRomChipId1: - case CartridgeState.ReadRomChipId2: - case CartridgeState.ReadRomChipId3: - val = RomChipId; - break; - case CartridgeState.Key2DataRead: - // Console.WriteLine("Key2 data read"); - if (DataPos < Rom.Length) - { - if (DataPos < 0x8000) - { - DataPos = 0x8000 + (DataPos & 0x1FF); - } - val = GetUint(Rom, DataPos); - } - break; - case CartridgeState.SecureAreaRead: - val = GetUint(SecureArea, DataPos - 0x4000); - // Console.WriteLine("Secure area read: Pos: " + Hex(DataPos, 8) + " Val: " + Hex(val, 4)); - break; - - default: - throw new NotImplementedException("Slot 1: bad state"); - } - - - DataPos += 4; - BytesTransferred += 4; - if (BytesTransferred >= TransferLength) - { - FinishTransfer(); - } - else - { - // TODO: Slot 1 DMA transfers - Nds.Scheduler.AddEventRelative(SchedulerId.None, 0, RepeatCartridgeTransfer); - } - - InData = val; - } - - public void RepeatCartridgeTransfer(long cyclesLate) - { - // Console.WriteLine(Hex(Nds.Dma7.Ch[3].DmaDest, 8)); - if (Nds.MemoryControl.Nds7Slot1AccessRights) - { - Nds.Dma7.Repeat((byte)DmaStartTimingNds7.Slot1); - } - else - { - Nds.Dma9.Repeat((byte)DmaStartTimingNds9.Slot1); - } - } - - public void FinishTransfer() - { - ReadyBit23 = false; - BusyBit31 = false; - - if (TransferReadyIrq) - { - if (Nds.MemoryControl.Nds7Slot1AccessRights) - { - Nds.HwControl7.FlagInterrupt((uint)InterruptNds.Slot1DataTransferComplete); - } - else - { - Nds.HwControl9.FlagInterrupt((uint)InterruptNds.Slot1DataTransferComplete); - - } - } - } - - // From the Key1 Encryption section of GBATek. - // Thanks Martin Korth. - public static ulong Encrypt64(uint[] encLut, ulong val) - { - uint y = (uint)val; - uint x = (uint)(val >> 32); - for (uint i = 0; i < 0x10; i++) - { - uint z = encLut[i] ^ x; - x = encLut[0x012 + (byte)(z >> 24)]; - x = encLut[0x112 + (byte)(z >> 16)] + x; - x = encLut[0x212 + (byte)(z >> 8)] ^ x; - x = encLut[0x312 + (byte)(z >> 0)] + x; - x ^= y; - y = z; - } - uint outLower = x ^ encLut[0x10]; - uint outUpper = y ^ encLut[0x11]; - - return ((ulong)outUpper << 32) | outLower; - } - - public static ulong Decrypt64(uint[] encLut, ulong val) - { - uint y = (uint)val; - uint x = (uint)(val >> 32); - for (uint i = 0x11; i >= 0x02; i--) - { - uint z = encLut[i] ^ x; - x = encLut[0x012 + (byte)(z >> 24)]; - x = encLut[0x112 + (byte)(z >> 16)] + x; - x = encLut[0x212 + (byte)(z >> 8)] ^ x; - x = encLut[0x312 + (byte)(z >> 0)] + x; - x ^= y; - y = z; - } - uint outLower = x ^ encLut[0x1]; - uint outUpper = y ^ encLut[0x0]; - - return ((ulong)outUpper << 32) | outLower; - } - - // modulo is always 0x08 - public void ApplyKeycode(uint[] encLut, Span keyCode, uint modulo) - { - ulong encrypted1 = Encrypt64(encLut, ((ulong)keyCode[2] << 32) | keyCode[1]); - keyCode[1] = (uint)encrypted1; - keyCode[2] = (uint)(encrypted1 >> 32); - ulong encrypted0 = Encrypt64(encLut, ((ulong)keyCode[1] << 32) | keyCode[0]); - keyCode[0] = (uint)encrypted0; - keyCode[1] = (uint)(encrypted0 >> 32); - - ulong scratch = 0; - - for (uint i = 0; i < 0x12; i++) - { - encLut[i] ^= BSwap32(keyCode[(int)(i % modulo)]); - } - - // EncLut is stored in uint for convenience so iterate in uints as well - for (uint i = 0; i < 0x412; i += 2) - { - scratch = Encrypt64(encLut, scratch); - encLut[i + 0] = (uint)(scratch >> 32); - encLut[i + 1] = (uint)scratch; - } - } - - public void InitKeycode(uint[] encLut, uint level) - { - Span keyCode = stackalloc uint[3]; - keyCode[0] = IdCode; - keyCode[1] = IdCode / 2; - keyCode[2] = IdCode * 2; - - // For game cartridge KEY1 decryption, modulo is always 2 (says 8 in GBATek) - // but is 2 when divided by four to convert from byte to uint - if (level >= 1) ApplyKeycode(encLut, keyCode, 2); - if (level >= 2) ApplyKeycode(encLut, keyCode, 2); - - keyCode[1] *= 2; - keyCode[2] /= 2; - - if (level >= 3) ApplyKeycode(encLut, keyCode, 2); // - } - - public static uint BSwap32(uint val) - { - return - ((val >> 24) & 0x000000FF) | - ((val >> 8) & 0x0000FF00) | - ((val << 8) & 0x00FF0000) | - ((val << 24) & 0xFF000000); - } - - public void SpiTransferTo(byte val) - { - // currently only EEPROM support - if (Slot1Enable) - { - var saveType = ExternalMemoryType.Eeprom; - // TODO: use a game DB to get memory type - switch (saveType) - { - case ExternalMemoryType.None: - break; - case ExternalMemoryType.Eeprom: - switch (SpiEepromState) - { - case SpiEepromState.Ready: - switch (val) - { - case 0x06: // Write Enable - ExternalMemoryWriteEnable = true; - SpiEepromState = SpiEepromState.Ready; - break; - case 0x04: // Write Disable - ExternalMemoryWriteEnable = false; - SpiEepromState = SpiEepromState.Ready; - break; - case 0x5: // Read Status Register - SpiEepromState = SpiEepromState.ReadStatus; - break; - case 0x1: // Write Status Register - SpiEepromState = SpiEepromState.WriteStatus; - break; - case 0x9F: // Read JEDEC ID (returns 0xFF on EEPROM/FLASH) - SpiOutData = 0xFF; - break; - case 0x3: // Read - SpiEepromState = SpiEepromState.SetReadAddress; - SpiAddress = 0; - SpiBytesWritten = 0; - break; - case 0x2: // Write - SpiEepromState = SpiEepromState.SetWriteAddress; - SpiAddress = 0; - SpiBytesWritten = 0; - break; - } - break; - case SpiEepromState.ReadStatus: - byte status = 0; - if (ExternalMemoryWriteEnable) status = BitSet(status, 1); - status |= (byte)(EepromWriteProtect << 2); - SpiOutData = status; - break; - case SpiEepromState.WriteStatus: - ExternalMemoryWriteEnable = BitTest(val, 1); - EepromWriteProtect = (byte)((val >> 2) & 0b11); - break; - case SpiEepromState.SetReadAddress: - SpiAddress <<= 8; - SpiAddress |= val; - if (++SpiBytesWritten == 2) - { - SpiEepromState = SpiEepromState.ReadData; - } - break; - case SpiEepromState.ReadData: - SpiOutData = ExternalMemory[SpiAddress]; - SpiAddress++; - break; - case SpiEepromState.SetWriteAddress: - SpiAddress <<= 8; - SpiAddress |= val; - if (++SpiBytesWritten == 2) - { - SpiEepromState = SpiEepromState.WriteData; - } - break; - case SpiEepromState.WriteData: - ExternalMemory[SpiAddress] = val; - SpiOutData = 0; - SpiAddress++; - break; - } - break; - case ExternalMemoryType.FlashWithInfrared: - switch (SpiFlashState) - { - case SpiFlashState.TakePrefix: - if (val == 0) - { - SpiFlashState = SpiFlashState.Ready; - Console.WriteLine("Flash with IR command"); - } - break; - case SpiFlashState.Ready: - // Console.WriteLine("SPI: Receive command! " + Hex(val, 2)); - SpiOutData = 0x00; - switch (val) - { - case 0x06: - ExternalMemoryWriteEnable = true; - break; - case 0x04: - ExternalMemoryWriteEnable = false; - break; - case 0x9F: - SpiFlashState = SpiFlashState.Identification; - SpiAddress = 0; - break; - case 0x03: - SpiFlashState = SpiFlashState.ReceiveAddress; - SpiAddress = 0; - SpiBytesWritten = 0; - break; - case 0x0B: - throw new NotImplementedException("slot1 flash fast read"); - case 0x0A: - throw new NotImplementedException("slot1 flash write"); - case 0x02: - throw new NotImplementedException("slot1 flash program"); - case 0x05: // Identification - // Console.WriteLine("SPI ID"); - SpiAddress = 0; - SpiOutData = 0x00; - break; - case 0x00: - break; - // default: - // throw new NotImplementedException("SPI: Unimplemented command: " + Hex(val, 2)); - } - break; - case SpiFlashState.ReceiveAddress: - // Console.WriteLine("SPI: Address byte write: " + Hex(val, 2)); - SpiAddress <<= 8; - SpiAddress |= val; - if (++SpiBytesWritten == 3) - { - SpiBytesWritten = 0; - SpiFlashState = SpiFlashState.Reading; - // Console.WriteLine("SPI: Address written: " + Hex(Address, 6)); - } - break; - case SpiFlashState.Reading: - // Console.WriteLine("SPI: Read from address: " + Hex(Address, 6)); - // Nds7.Cpu.Error("SPI"); - SpiOutData = ExternalMemory[SpiAddress]; - SpiAddress++; - SpiAddress &= 0xFFFFFF; - break; - case SpiFlashState.Identification: - SpiOutData = FlashId[SpiAddress]; - SpiAddress++; - SpiAddress %= 3; - break; - } - break; - } - - if (!SpiChipSelHold) - { - SpiEepromState = SpiEepromState.Ready; - SpiFlashState = SpiFlashState.TakePrefix; - } - } - } - - public byte[] GetSave() - { - return ExternalMemory; - } - - public void LoadSave(byte[] sav) - { - sav.CopyTo(ExternalMemory, 0); - } - } -} \ No newline at end of file diff --git a/Assets/emulator/CoreUtil.cs b/Assets/emulator/CoreUtil.cs index 1418727..1eb5c4c 100644 --- a/Assets/emulator/CoreUtil.cs +++ b/Assets/emulator/CoreUtil.cs @@ -1,8 +1,9 @@ +using System; using System.Runtime.CompilerServices; namespace OptimeGBA { - sealed class Bits + public sealed class Bits { public const uint BIT_0 = (1 << 0); public const uint BIT_1 = (1 << 1); @@ -121,6 +122,11 @@ namespace OptimeGBA { return (byte)(n >> (pos * 8)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte GetByteIn(uint n, int pos) + { + return (byte)(n >> (pos * 8)); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte GetByteIn(ulong n, int pos) @@ -203,5 +209,46 @@ namespace OptimeGBA { return (short)(((short)val << (15 - pos)) >> (15 - pos)); } + public static byte[] FloatArrayToByteBuffer(float[] datas) + { + byte[] result = new byte[datas.Length * 4]; + for (int i = 0; i < datas.Length; i++) + { + byte[] signalBytes = BitConverter.GetBytes(datas[i]); + result[4 * i] = signalBytes[0]; + result[4 * i + 1] = signalBytes[1]; + result[4 * i + 2] = signalBytes[2]; + result[4 * i + 3] = signalBytes[3]; + } + + return result; + } + public static float[] ByteToFloatArray(byte[] srcByte) + { + unsafe + { + int FLOATLEN = sizeof(float); + int srcLen = srcByte.Length; + int dstLen = srcLen / FLOATLEN; + float[] dstFloat = new float[dstLen]; + for (int i = 0; i < dstLen; i++) + { + float temp = 0.0F; + void* pf = &temp; + fixed (byte* pxb = srcByte) + { + byte* px = pxb; + px += i * FLOATLEN; + + for (int j = 0; j < FLOATLEN; j++) + { + *((byte*)pf + j) = *(px + j); + } + dstFloat[i] = temp; + } + } + return dstFloat; + } + } } } \ No newline at end of file diff --git a/Assets/emulator/CoreUtil.cs.meta b/Assets/emulator/CoreUtil.cs.meta index 5a11454..a3e29d2 100644 --- a/Assets/emulator/CoreUtil.cs.meta +++ b/Assets/emulator/CoreUtil.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: bc5bdea9f2094294da4dcefeebda8f63 +guid: c452c8124018a2748ba32716b989a1ea MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/Cp15.cs b/Assets/emulator/Cp15.cs index bdef11b..8ad2acc 100644 --- a/Assets/emulator/Cp15.cs +++ b/Assets/emulator/Cp15.cs @@ -5,12 +5,12 @@ namespace OptimeGBA { public class Cp15 { - Nds Nds; + /*Nds Nds; public Cp15(Nds nds) { Nds = nds; - } + }*/ public uint ControlRegister; @@ -27,25 +27,25 @@ namespace OptimeGBA ControlRegister = rdVal; ControlRegister |= 0b00000000000000000000000001111000; ControlRegister &= 0b00000000000011111111000010000101; - Nds.Mem9.UpdateTcmSettings(); + //Nds.Mem9.UpdateTcmSettings(); break; case 0x704: case 0x782: - Nds.Cpu9.Halted = true; + //Nds.Cpu9.Halted = true; break; case 0x910: DataTcmSettings = rdVal; - Nds.Mem9.UpdateTcmSettings(); + //Nds.Mem9.UpdateTcmSettings(); break; case 0x911: InstTcmSettings = rdVal; - Nds.Mem9.UpdateTcmSettings(); + //Nds.Mem9.UpdateTcmSettings(); break; default: - // Console.WriteLine($"UNIMPLEMENTED TO CP15 {opcode1},C{cRn},C{cRm},{opcode2}: {HexN(rdVal, 8)}"); + // Debug.Log($"UNIMPLEMENTED TO CP15 {opcode1},C{cRn},C{cRm},{opcode2}: {HexN(rdVal, 8)}"); break; } @@ -75,7 +75,7 @@ namespace OptimeGBA break; default: - Console.WriteLine($"UNIMPLEMENTED FROM CP15 {opcode1},C{cRn},C{cRm},{opcode2}"); + //Debug.Log($"UNIMPLEMENTED FROM CP15 {opcode1},C{cRn},C{cRm},{opcode2}"); break; } diff --git a/Assets/emulator/Cp15.cs.meta b/Assets/emulator/Cp15.cs.meta index db2ad36..e258e1c 100644 --- a/Assets/emulator/Cp15.cs.meta +++ b/Assets/emulator/Cp15.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 930c82bbb70e8d54d8bed296233fb78a +guid: 082cf1137d5d5114c8755e473d5857b5 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/Dma.cs.meta b/Assets/emulator/Dma.cs.meta index 1c6420d..2f2cbe3 100644 --- a/Assets/emulator/Dma.cs.meta +++ b/Assets/emulator/Dma.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9d57248ed47e4cf4a922bbb7f923b6e9 +guid: d1b25dbe9e7a7eb4a8af44963c72a602 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/DmaGba.cs b/Assets/emulator/DmaGba.cs index 04f8b94..f775293 100644 --- a/Assets/emulator/DmaGba.cs +++ b/Assets/emulator/DmaGba.cs @@ -231,10 +231,10 @@ namespace OptimeGBA if (c.DmaLength == 0) c.DmaLength = 0x4000; } - // Console.WriteLine($"Starting DMA {ci}"); - // Console.WriteLine($"SRC: {Util.HexN(srcAddr, 7)}"); - // Console.WriteLine($"DEST: {Util.HexN(destAddr, 7)}"); - // Console.WriteLine($"LENGTH: {Util.HexN(c.DmaLength, 4)}"); + // Debug.Log($"Starting DMA {ci}"); + // Debug.Log($"SRC: {Util.HexN(srcAddr, 7)}"); + // Debug.Log($"DEST: {Util.HexN(destAddr, 7)}"); + // Debug.Log($"LENGTH: {Util.HexN(c.DmaLength, 4)}"); int destOffsPerUnit; int sourceOffsPerUnit; diff --git a/Assets/emulator/DmaGba.cs.meta b/Assets/emulator/DmaGba.cs.meta index d9b22c4..51f0589 100644 --- a/Assets/emulator/DmaGba.cs.meta +++ b/Assets/emulator/DmaGba.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5c4ffd474f58e654b873b37f5ca89d16 +guid: 36717f7dc90280e41826611c592f97a3 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/DmaNds.cs b/Assets/emulator/DmaNds.cs deleted file mode 100644 index 6b784c4..0000000 --- a/Assets/emulator/DmaNds.cs +++ /dev/null @@ -1,417 +0,0 @@ -using static OptimeGBA.Bits; -using static Util; -using System; - - -namespace OptimeGBA -{ - public enum DmaStartTimingNds9 : byte - { - Immediately = 0, - VBlank = 1, - HBlank = 2, - UponRenderBegin = 3, - MainMemoryDisplay = 4, - Slot1 = 5, - Slot2 = 6, - GeometryCommandFifo = 7, - } - - public enum DmaStartTimingNds7 : byte - { - Immediately = 0, - VBlank = 1, - Slot1 = 2, - Misc = 3, - } - - public sealed class DmaChannelNds - { - public bool Nds7; - - public DmaChannelNds(bool nds7) - { - Nds7 = nds7; - } - - public uint DMASAD; - public uint DMADAD; - public uint DMACNT_L; - - public uint DmaSource; - public uint DmaDest; - public uint DmaLength; - - // DMACNT_H - public DmaDestAddrCtrl DestAddrCtrl; - public DmaSrcAddrCtrl SrcAddrCtrl; - public bool Repeat; - public bool TransferType; - public byte StartTiming; - public bool FinishedIRQ; - public bool Enabled; // Don't directly set to false, use Disable() - - public uint DMACNT_H; - - public byte ReadHwio8(uint addr) - { - // DMASAD, DMADAD, and DMACNT_L are write-only - byte val = 0; - switch (addr) - { - case 0x0A: // DMACNT_H B0 - case 0x0B: // DMACNT_H B1 - val = GetByteIn(GetControl(), addr & 1); - break; - } - return val; - } - - public void WriteHwio8(uint addr, byte val) - { - switch (addr) - { - case 0x00: // DMASAD B0 - case 0x01: // DMASAD B1 - case 0x02: // DMASAD B2 - case 0x03: // DMASAD B3 - DMASAD = SetByteIn(DMASAD, val, addr & 3); - break; - - case 0x04: // DMADAD B0 - case 0x05: // DMADAD B1 - case 0x06: // DMADAD B2 - case 0x07: // DMADAD B3 - DMADAD = SetByteIn(DMADAD, val, addr & 3); - break; - - case 0x08: // DMACNT_L B0 - case 0x09: // DMACNT_L B1 - DMACNT_L = SetByteIn(DMACNT_L, val, addr & 1); - break; - case 0x0A: // DMACNT_H B0 - case 0x0B: // DMACNT_H B1 - DMACNT_H = SetByteIn(DMACNT_H, val, addr & 1); - UpdateControl(); - break; - } - } - - public void UpdateControl() - { - DestAddrCtrl = (DmaDestAddrCtrl)BitRange(DMACNT_H, 5, 6); - SrcAddrCtrl = (DmaSrcAddrCtrl)BitRange(DMACNT_H, 7, 8); - Repeat = BitTest(DMACNT_H, 9); - TransferType = BitTest(DMACNT_H, 10); - if (!Nds7) - { - StartTiming = (byte)BitRange(DMACNT_H, 11, 13); - } - else - { - StartTiming = (byte)BitRange(DMACNT_H, 12, 13); - } - FinishedIRQ = BitTest(DMACNT_H, 14); - if (BitTest(DMACNT_H, 15)) - { - Enable(); - } - else - { - Disable(); - } - } - - public uint GetControl() - { - uint val = 0; - val |= ((uint)DestAddrCtrl & 0b11) << 5; - val |= ((uint)SrcAddrCtrl & 0b11) << 7; - if (Repeat) val = BitSet(val, 9); - if (TransferType) val = BitSet(val, 10); - val |= ((uint)StartTiming & 0b111) << 11; - if (FinishedIRQ) val = BitSet(val, 14); - if (Enabled) val = BitSet(val, 15); - - DMACNT_H = val; - - return val; - } - - public void Enable() - { - if (!Enabled) - { - DmaSource = DMASAD; - DmaDest = DMADAD; - DmaLength = DMACNT_L; - } - - Enabled = true; - GetControl(); - } - - public void Disable() - { - Enabled = false; - GetControl(); - } - } - - public unsafe sealed class DmaNds - { - bool Nds7; - Memory Mem; - HwControl HwControl; - - public DmaChannelNds[] Ch; - static readonly uint[] DmaSourceMask = { 0x07FFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF }; - static readonly uint[] DmaDestMask = { 0x07FFFFFF, 0x07FFFFFF, 0x07FFFFFF, 0x0FFFFFFFF }; - - public byte[] DmaFill = new byte[16]; - - public bool DmaLock; - - public DmaNds(bool nds7, Memory mem, HwControlNds hwControl) - { - Nds7 = nds7; - Mem = mem; - HwControl = hwControl; - - Ch = new DmaChannelNds[4] { - new DmaChannelNds(Nds7), - new DmaChannelNds(Nds7), - new DmaChannelNds(Nds7), - new DmaChannelNds(Nds7), - }; - } - - public byte ReadHwio8(uint addr) - { - if (addr >= 0x40000B0 && addr <= 0x40000BB) - { - return Ch[0].ReadHwio8(addr - 0x40000B0); - } - else if (addr >= 0x40000BC && addr <= 0x40000C7) - { - return Ch[1].ReadHwio8(addr - 0x40000BC); - } - else if (addr >= 0x40000C8 && addr <= 0x40000D3) - { - return Ch[2].ReadHwio8(addr - 0x40000C8); - } - else if (addr >= 0x40000D4 && addr <= 0x40000DF) - { - return Ch[3].ReadHwio8(addr - 0x40000D4); - } - else if (addr >= 0x40000E0 && addr <= 0x40000EF) - { - return DmaFill[addr & 0xF]; - } - throw new Exception("This shouldn't happen."); - } - - public void WriteHwio8(uint addr, byte val) - { - if (addr >= 0x40000B0 && addr <= 0x40000BB) - { - bool oldEnabled = Ch[0].Enabled; - Ch[0].WriteHwio8(addr - 0x40000B0, val); - if (!oldEnabled && Ch[0].Enabled) ExecuteImmediate(0); - return; - } - else if (addr >= 0x40000BC && addr <= 0x40000C7) - { - bool oldEnabled = Ch[1].Enabled; - Ch[1].WriteHwio8(addr - 0x40000BC, val); - if (!oldEnabled && Ch[1].Enabled) ExecuteImmediate(1); - return; - } - else if (addr >= 0x40000C8 && addr <= 0x40000D3) - { - bool oldEnabled = Ch[2].Enabled; - Ch[2].WriteHwio8(addr - 0x40000C8, val); - if (!oldEnabled && Ch[2].Enabled) ExecuteImmediate(2); - return; - } - else if (addr >= 0x40000D4 && addr <= 0x40000DF) - { - bool oldEnabled = Ch[3].Enabled; - Ch[3].WriteHwio8(addr - 0x40000D4, val); - if (!oldEnabled && Ch[3].Enabled) ExecuteImmediate(3); - return; - } - else if (addr >= 0x40000E0 && addr <= 0x40000EF) - { - DmaFill[addr & 0xF] = val; - return; - } - throw new Exception("This shouldn't happen."); - } - - public void ExecuteDma(DmaChannelNds c, uint ci) - { - - DmaLock = true; - - // Console.WriteLine("NDS: Executing DMA"); - // Console.WriteLine("Source: " + Util.Hex(c.DmaSource, 8)); - // Console.WriteLine("Dest: " + Util.Hex(c.DmaDest, 8)); - // Console.WriteLine("Length: " + c.DmaLength); - - if (!Nds7) - { - c.DmaSource &= 0x0FFFFFFF; - c.DmaDest &= 0x0FFFFFFF; - - // All NDS9 DMAs use 21-bit length - c.DmaLength &= 0x1FFFFF; - // Value of zero is treated as maximum length - if (c.DmaLength == 0) c.DmaLength = 0x200000; - } - else - { - // Least significant 28 (or 27????) bits - c.DmaSource &= DmaSourceMask[ci]; - c.DmaDest &= DmaDestMask[ci]; - - if (ci == 3) - { - // DMA 3 is 16-bit length - c.DmaLength &= 0xFFFF; - // Value of zero is treated as maximum length - if (c.DmaLength == 0) c.DmaLength = 0x10000; - } - else - { - // DMA 0-2 are 14-bit length - c.DmaLength &= 0x3FFF; - // Value of zero is treated as maximum length - if (c.DmaLength == 0) c.DmaLength = 0x4000; - } - } - - // if (c.DmaLength != 1 && ci == 3) - // { - // Console.WriteLine(((DmaStartTimingNds7)c.StartTiming).ToString()); - // Console.WriteLine("DMA length " + c.DmaLength); - // } - - // Console.WriteLine($"Starting DMA {ci}"); - // Console.WriteLine($"SRC: {Util.HexN(srcAddr, 7)}"); - // Console.WriteLine($"DEST: {Util.HexN(destAddr, 7)}"); - // Console.WriteLine($"LENGTH: {Util.HexN(c.DmaLength, 4)}"); - - int destOffsPerUnit; - int sourceOffsPerUnit; - if (c.TransferType) - { - switch (c.DestAddrCtrl) - { - case DmaDestAddrCtrl.Increment: destOffsPerUnit = +4; break; - case DmaDestAddrCtrl.Decrement: destOffsPerUnit = -4; break; - case DmaDestAddrCtrl.IncrementReload: destOffsPerUnit = +4; break; - default: destOffsPerUnit = 0; break; - } - switch (c.SrcAddrCtrl) - { - case DmaSrcAddrCtrl.Increment: sourceOffsPerUnit = +4; break; - case DmaSrcAddrCtrl.Decrement: sourceOffsPerUnit = -4; break; - default: sourceOffsPerUnit = 0; break; - } - } - else - { - switch (c.DestAddrCtrl) - { - case DmaDestAddrCtrl.Increment: destOffsPerUnit = +2; break; - case DmaDestAddrCtrl.Decrement: destOffsPerUnit = -2; break; - case DmaDestAddrCtrl.IncrementReload: destOffsPerUnit = +2; break; - default: destOffsPerUnit = 0; break; - } - switch (c.SrcAddrCtrl) - { - case DmaSrcAddrCtrl.Increment: sourceOffsPerUnit = +2; break; - case DmaSrcAddrCtrl.Decrement: sourceOffsPerUnit = -2; break; - default: sourceOffsPerUnit = 0; break; - } - } - - uint origLength = c.DmaLength; - - // TODO: NDS DMA timings - if (c.TransferType) - { - for (; c.DmaLength > 0; c.DmaLength--) - { - Mem.Write32(c.DmaDest & ~3u, Mem.Read32(c.DmaSource & ~3u)); - // Gba.Tick(Gba.Cpu.Timing32[(c.DmaSource >> 24) & 0xF]); - // Gba.Tick(Gba.Cpu.Timing32[(c.DmaDest >> 24) & 0xF]); - - c.DmaDest = (uint)(long)(destOffsPerUnit + c.DmaDest); - c.DmaSource = (uint)(long)(sourceOffsPerUnit + c.DmaSource); - } - } - else - { - for (; c.DmaLength > 0; c.DmaLength--) - { - Mem.Write16(c.DmaDest & ~1u, Mem.Read16(c.DmaSource & ~1u)); - // Gba.Tick(Nds.Timing8And16[(c.DmaSource >> 24) & 0xF]); - // Gba.Tick(Nds.Timing8And16[(c.DmaDest >> 24) & 0xF]); - - c.DmaDest = (uint)(long)(destOffsPerUnit + c.DmaDest); - c.DmaSource = (uint)(long)(sourceOffsPerUnit + c.DmaSource); - } - } - - if (c.DestAddrCtrl == DmaDestAddrCtrl.IncrementReload) - { - if (c.Repeat) - { - c.DmaDest = c.DMADAD; - } - } - - - if (c.FinishedIRQ) - { - HwControl.FlagInterrupt((uint)InterruptNds.Dma0 + ci); - } - - DmaLock = false; - } - - public void ExecuteImmediate(uint ci) - { - DmaChannelNds c = Ch[ci]; - // Console.WriteLine($"NDS{(Nds9 ? "9" : "7")}: Ch{ci} immediate DMA from:{Hex(c.DMASAD, 8)} to:{Hex(c.DMADAD, 8)}"); - - if (c.Enabled && c.StartTiming == (byte)DmaStartTimingNds9.Immediately) - { - c.Disable(); - - ExecuteDma(c, ci); - } - } - - public bool Repeat(byte val) - { - bool executed = false; - if (!DmaLock) - { - for (uint ci = 0; ci < 4; ci++) - { - DmaChannelNds c = Ch[ci]; - if (c.StartTiming == val) - { - executed = true; - c.DmaLength = c.DMACNT_L; - ExecuteDma(c, ci); - } - } - } - return executed; - } - } -} \ No newline at end of file diff --git a/Assets/emulator/Emulator.cs b/Assets/emulator/Emulator.cs new file mode 100644 index 0000000..7944e01 --- /dev/null +++ b/Assets/emulator/Emulator.cs @@ -0,0 +1,246 @@ +using OptimeGBA; +using System; +using System.IO; +using System.Threading; +using UnityEngine; +using UnityEngine.UI; + +public class Emulator : MonoBehaviour +{ + public static Emulator instance; + const int FrameCycles = 70224 * 4; + const int ScanlineCycles = 1232; + const float FrameRate = 59.7275f; + static bool SyncToAudio = true; + + //public Renderer screenRenderer; + public VideoProvider videoProvider; + public AudioProvider audioProvider; + public static System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); + + public bool ShowBackBuf = false; + public bool RunEmulator; + public bool EnableAudio; + public bool BootBIOS = false; + public bool RomLoaded { get; private set; } = false; + + public Gba gba; + Thread EmulationThread; + AutoResetEvent ThreadSync = new AutoResetEvent(false); + + private int _samplesAvailable; + //private PipeStream _pipeStream; + private byte[] _buffer; + public float audioGain = 1.0f; + + // key delegate + public delegate bool IsKeyPressed(GBAKeyCode keyCode); + public IsKeyPressed KeyPressed; + + + public Button btnStart; + private void Awake() + { + instance = this; + //BetterStreamingAssets.Initialize(); + // must set it to 60 or it won't sync with audio or run too fast. + Application.targetFrameRate = (int)FrameRate; + //audioSource = GetComponent(); + //AudioClip clip = AudioClip.Create("blank", GbaAudio.SampleRate * 2, 2, GbaAudio.SampleRate, true); + //audioSource.clip = clip; + //audioSource.playOnAwake = true; + //audioSource.enabled = false; + //screenRenderer.material.mainTexture = new Texture2D(240, 160, TextureFormat.RGBA32, false, false); + + // Get Unity Buffer size + AudioSettings.GetDSPBufferSize(out int bufferLength, out _); + _samplesAvailable = bufferLength; + // Must be set to 32768 + var audioConfig = AudioSettings.GetConfiguration(); + audioConfig.sampleRate = GbaAudio.SampleRate; + AudioSettings.Reset(audioConfig); + // Prepare our buffer + //_pipeStream = new PipeStream(); + //_pipeStream.MaxBufferLength = _samplesAvailable * 2 * sizeof(float); + _buffer = new byte[_samplesAvailable * 2 * sizeof(float)]; + } + void Start() + { + byte[] bios = Resources.Load("gba_bios.bin").bytes; + //byte[] bios = BetterStreamingAssets.ReadAllBytes("gba_bios.bin"); + Debug.Log(bios.Length); + gba = new Gba(new ProviderGba(bios, new byte[0], "", audioProvider.AudioReady) { BootBios = BootBIOS }); + EmulationThread = new Thread(EmulationThreadHandler); + EmulationThread.Name = "Emulation Core"; + EmulationThread.Start(); + + btnStart.onClick.AddListener( + () => + { + byte[] romdata = Resources.Load("mario_world.gba").bytes; + LoadRom(romdata, "mario_world.gba"); + } + ); + } + + // Update is called once per frame + void Update() + { + if (RomLoaded) + { + videoProvider.OnRenderFrame(); + } + OnUpdateFrame(); + } + + public void LoadRom(byte[] rom, string name) + { + string savPath = Application.persistentDataPath + "/" + name.Substring(0, name.Length - 3) + "sav"; + byte[] sav = new byte[0]; + if (File.Exists(savPath)) + { + Debug.Log($"{savPath} exists, loading"); + try + { + sav = File.ReadAllBytes(savPath); + } + catch + { + Debug.Log("Failed to load .sav file!"); + } + } + else + { + Debug.Log(".sav not available"); + } + + LoadRomAndSave(rom, sav, savPath); + Debug.Log("Load Rom Success"); + audioProvider.Initialize(); + RomLoaded = true; + RunEmulator = true; + } + + public void LoadRomAndSave(byte[] rom, byte[] sav, string savPath) + { + var bios = gba.Provider.Bios; + gba = new Gba(new ProviderGba(bios, rom, savPath, audioProvider.AudioReady) { BootBios = BootBIOS }); + gba.Mem.SaveProvider.LoadSave(sav); + } + + public void ResetGba() + { + byte[] save = gba.Mem.SaveProvider.GetSave(); + ProviderGba p = gba.Provider; + gba = new Gba(p); + gba.Mem.SaveProvider.LoadSave(save); + } + + public void EmulationThreadHandler() + { + while (true) + { + ThreadSync.WaitOne(); + + int cyclesLeft = 70224 * 4; + while (cyclesLeft > 0 && !gba.Cpu.Errored) + { + cyclesLeft -= (int)gba.Step(); + } + + while (!SyncToAudio && !gba.Cpu.Errored && RunEmulator) + { + gba.Step(); + } + } + } + + public int GetOutputSampleRate() + { + return AudioSettings.outputSampleRate; + } + + public int GetSamplesAvailable() + { + return _samplesAvailable; + } + + //private void OnAudioFilterRead(float[] data, int channels) + //{ + // if (!EnableAudio) return; + + // int r = _pipeStream.Read(_buffer, 0, data.Length * sizeof(float)); + // float[] pcm = CoreUtil.ByteToFloatArray(_buffer); + // Array.Copy(pcm, data, data.Length); + //} + + + + public void RunCycles(int cycles) + { + while (cycles > 0 && !gba.Cpu.Errored && RunEmulator) + { + cycles -= (int)gba.Step(); + } + } + + int CyclesLeft; + public void RunFrame() + { + CyclesLeft += FrameCycles; + while (CyclesLeft > 0 && !gba.Cpu.Errored) + { + CyclesLeft -= (int)gba.Step(); + } + } + + public void RunScanline() + { + CyclesLeft += ScanlineCycles; + while (CyclesLeft > 0 && !gba.Cpu.Errored) + { + CyclesLeft -= (int)gba.Step(); + } + } + + + public void OnUpdateFrame() + { + gba.Keypad.B = KeyPressed(GBAKeyCode.B); + gba.Keypad.A = KeyPressed(GBAKeyCode.A); + gba.Keypad.Left = KeyPressed(GBAKeyCode.Left); + gba.Keypad.Up = KeyPressed(GBAKeyCode.Up); + gba.Keypad.Right = KeyPressed(GBAKeyCode.Right); + gba.Keypad.Down = KeyPressed(GBAKeyCode.Down); + gba.Keypad.Start = KeyPressed(GBAKeyCode.Start); + gba.Keypad.Select = KeyPressed(GBAKeyCode.Select); + gba.Keypad.L = KeyPressed(GBAKeyCode.L); + gba.Keypad.R = KeyPressed(GBAKeyCode.R); + + SyncToAudio = !(Input.GetKey(KeyCode.Tab) || Input.GetKey(KeyCode.Space)); + + if (RunEmulator) + { + ThreadSync.Set(); + } + + if (gba.Mem.SaveProvider.Dirty) + { + DumpSav(); + } + } + + public void DumpSav() + { + try + { + //File.WriteAllBytesAsync(gba.Provider.SavPath, gba.Mem.SaveProvider.GetSave()); + File.WriteAllBytes(gba.Provider.SavPath, gba.Mem.SaveProvider.GetSave()); + } + catch + { + Debug.Log("Failed to write .sav file!"); + } + } + +} diff --git a/Assets/MyUnSafeCommon.cs.meta b/Assets/emulator/Emulator.cs.meta similarity index 83% rename from Assets/MyUnSafeCommon.cs.meta rename to Assets/emulator/Emulator.cs.meta index 22caad4..b8dd7f1 100644 --- a/Assets/MyUnSafeCommon.cs.meta +++ b/Assets/emulator/Emulator.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d82a940594010314bbfb9de2d3865d64 +guid: 515e71167c74b044984b170a2a141f10 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/EmulatorGUI.cs b/Assets/emulator/EmulatorGUI.cs new file mode 100644 index 0000000..ecd2e5f --- /dev/null +++ b/Assets/emulator/EmulatorGUI.cs @@ -0,0 +1,38 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +public class EmulatorGUI : MonoBehaviour +{ + private Dictionary keyboardKeyCodeMap; + private Emulator emulator; + + void Start() + { + keyboardKeyCodeMap = new Dictionary() + { + { GBAKeyCode.Start,KeyCode.Return}, + { GBAKeyCode.Select,KeyCode.Backspace}, + { GBAKeyCode.Left,KeyCode.A}, + { GBAKeyCode.Right,KeyCode.D}, + { GBAKeyCode.Up,KeyCode.W}, + { GBAKeyCode.Down,KeyCode.S}, + { GBAKeyCode.A,KeyCode.J}, + { GBAKeyCode.B,KeyCode.K}, + { GBAKeyCode.L,KeyCode.U}, + { GBAKeyCode.R,KeyCode.I}, + }; + emulator = GameObject.FindObjectOfType(); + emulator.KeyPressed += GetKey; + + + } + public bool GetKey(GBAKeyCode keyCode) + { +#if UNITY_EDITOR || UNITY_STANDALONE + bool input = Input.GetKey( keyboardKeyCodeMap[keyCode]); + if(input) return true;else return false; +#endif + } +} diff --git a/Assets/emulator/CartridgeNds.cs.meta b/Assets/emulator/EmulatorGUI.cs.meta similarity index 83% rename from Assets/emulator/CartridgeNds.cs.meta rename to Assets/emulator/EmulatorGUI.cs.meta index 05c40aa..f98bcc7 100644 --- a/Assets/emulator/CartridgeNds.cs.meta +++ b/Assets/emulator/EmulatorGUI.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0aa73f4dabd6dcd44b7d5eaa5cbf4c68 +guid: 2a6d4732564041e4d85a5fbef37546d6 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/GBA.asmdef b/Assets/emulator/GBA.asmdef new file mode 100644 index 0000000..ce5a7c3 --- /dev/null +++ b/Assets/emulator/GBA.asmdef @@ -0,0 +1,20 @@ +{ + "name": "GBA", + "rootNamespace": "", + "references": [ + "GUID:d3a8dd703fcbca94f97e175973c255f5", + "GUID:43b6de571eb529e4b8cd209457a5f570", + "GUID:d8b63aba1907145bea998dd612889d6b", + "GUID:2665a8d13d1b3f18800f46e256720795", + "GUID:5e90fee04fdf7164fa71eeef34c6a431" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/emulator/GBA.asmdef.meta b/Assets/emulator/GBA.asmdef.meta new file mode 100644 index 0000000..f5ca3f7 --- /dev/null +++ b/Assets/emulator/GBA.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 54cc43fb16a4d83469407e3e8e248065 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/emulator/GbAudio.cs b/Assets/emulator/GbAudio.cs index 3d9d705..2bf6c87 100644 --- a/Assets/emulator/GbAudio.cs +++ b/Assets/emulator/GbAudio.cs @@ -940,11 +940,11 @@ namespace OptimeGBA this.enabled = true; this.frameSequencerStep = 0; - // Console.WriteLine("Enabled PSGs!"); + // Debug.Log("Enabled PSGs!"); } else { - // Console.WriteLine("Disabled PSGs..."); + // Debug.Log("Disabled PSGs..."); // Disable and write zeros on everything upon main disabling this.noise_enabled = false; diff --git a/Assets/emulator/GbAudio.cs.meta b/Assets/emulator/GbAudio.cs.meta index ea2e5cc..d837e23 100644 --- a/Assets/emulator/GbAudio.cs.meta +++ b/Assets/emulator/GbAudio.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 05f5a54c4470e584daa86a0c04ddd943 +guid: ab02a6abe06f10f468911df855dd7604 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/Gba.cs b/Assets/emulator/Gba.cs index 8cfb84c..bc471cf 100644 --- a/Assets/emulator/Gba.cs +++ b/Assets/emulator/Gba.cs @@ -31,8 +31,8 @@ namespace OptimeGBA Ppu = new PpuGba(this, Scheduler); Keypad = new Keypad(); Dma = new DmaGba(this); - Timers = new Timers(GbaAudio, HwControl, Scheduler, false, true); HwControl = new HwControlGba(this); + Timers = new Timers(GbaAudio, HwControl, Scheduler, false, true); Cpu = new Arm7(StateChange, Mem, false, false, null); Cpu.SetTimingsTable( @@ -132,11 +132,6 @@ namespace OptimeGBA Mem.InitPageTables(); Cpu.InitFlushPipeline(); -#if UNSAFE - Console.WriteLine("Starting in memory UNSAFE mode"); -#else - Console.WriteLine("Starting in memory SAFE mode"); -#endif } public uint Step() diff --git a/Assets/emulator/Gba.cs.meta b/Assets/emulator/Gba.cs.meta index 9031974..20b6661 100644 --- a/Assets/emulator/Gba.cs.meta +++ b/Assets/emulator/Gba.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0c7b25fc293f60540a475ccb2f6357b6 +guid: 90fdc7ebe54f77c4da8c510515da9f9d MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/GbaAudio.cs b/Assets/emulator/GbaAudio.cs index 4c6fe21..f82e848 100644 --- a/Assets/emulator/GbaAudio.cs +++ b/Assets/emulator/GbaAudio.cs @@ -319,7 +319,7 @@ namespace OptimeGBA const int CyclesPerSample = 16777216 / SampleRate; // public CircularBuffer SampleBuffer = new CircularBuffer(32768, 0); public const uint SampleBufferMax = 256; - public short[] SampleBuffer = new short[SampleBufferMax]; + public float[] SampleBuffer = new float[SampleBufferMax]; public uint SampleBufferPos = 0; public bool AudioReady; @@ -409,8 +409,8 @@ namespace OptimeGBA VisBufB.Insert(CurrentValueB); } - SampleBuffer[SampleBufferPos++] = (short)((fifoA + psgA) * 64); - SampleBuffer[SampleBufferPos++] = (short)((fifoB + psgB) * 64); + SampleBuffer[SampleBufferPos++] = ((fifoA + psgA) * 64f)/ SampleRate; + SampleBuffer[SampleBufferPos++] = ((fifoB + psgB) * 64f)/ SampleRate; if (SampleBufferPos >= SampleBufferMax) { diff --git a/Assets/emulator/GbaAudio.cs.meta b/Assets/emulator/GbaAudio.cs.meta index 4787cf1..473494b 100644 --- a/Assets/emulator/GbaAudio.cs.meta +++ b/Assets/emulator/GbaAudio.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: eda7cec1bdd2dee48802bc4b1456d549 +guid: 8c5e3b65effa8d24da17efc42e12eb20 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/HwControl.cs.meta b/Assets/emulator/HwControl.cs.meta index d36d45d..1b5c686 100644 --- a/Assets/emulator/HwControl.cs.meta +++ b/Assets/emulator/HwControl.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c64a99535514fa649aa2a79581ea1781 +guid: 816d784dc01e7804ea2368ee2d1f800f MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/HwControlGba.cs.meta b/Assets/emulator/HwControlGba.cs.meta index bca7150..48ec66a 100644 --- a/Assets/emulator/HwControlGba.cs.meta +++ b/Assets/emulator/HwControlGba.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 654dd2b57b6345649802e6a16a013537 +guid: 8a26fb3a3a7a8044086fc98259d6b58d MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/HwControlNds.cs b/Assets/emulator/HwControlNds.cs deleted file mode 100644 index 0cb50a5..0000000 --- a/Assets/emulator/HwControlNds.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System; -using static OptimeGBA.Bits; - -namespace OptimeGBA -{ - public enum InterruptNds - { - VBlank = 0, - HBlank = 1, - VCounterMatch = 2, - Timer0Overflow = 3, - Timer1Overflow = 4, - Timer2Overflow = 5, - Timer3Overflow = 6, - Rtc = 7, - Dma0 = 8, - Dma1 = 9, - Dma2 = 10, - Dma3 = 11, - Keypad = 12, - GamePak = 13, - // 14, 15, unused - IpcSync = 16, - IpcSendFifoEmpty = 17, - IpcRecvFifoPending = 18, - Slot1DataTransferComplete = 19, - Slot1rq = 20, - GeometryFifo = 21, // ARM9 only - ScreenUnfold = 22, // ARM7 only - SpiBus = 23, // ARM7 only - Wifi = 24, // ARM7 only - } - - public sealed class HwControlNds : HwControl - { - Arm7 Cpu; - - public HwControlNds(Arm7 cpu) - { - Cpu = cpu; - } - - public byte Postflg; // POSTFLG - - public byte ReadHwio8(uint addr) - { - byte val = 0; - switch (addr) - { - case 0x4000208: // IME - if (IME) val = BitSet(val, 0); - break; - - case 0x4000210: // IE B0 - return (byte)(IE >> 0); - case 0x4000211: // IE B1 - return (byte)(IE >> 8); - case 0x4000212: // IE B2 - return (byte)(IE >> 16); - case 0x4000213: // IE B3 - return (byte)(IE >> 24); - - case 0x4000214: // IF B0 - return (byte)(IF >> 0); - case 0x4000215: // IF B1 - return (byte)(IF >> 8); - case 0x4000216: // IF B2 - return (byte)(IF >> 16); - case 0x4000217: // IF B3 - return (byte)(IF >> 24); - } - return val; - } - - public void WriteHwio8(uint addr, byte val) - { - switch (addr) - { - case 0x4000208: // IME - IME = BitTest(val, 0); - CheckAndFireInterrupts(); - break; - - case 0x4000210: // IE B0 - IE &= 0xFFFFFF00; - IE |= (uint)((uint)val << 0); - CheckAndFireInterrupts(); - break; - case 0x4000211: // IE B1 - IE &= 0xFFFF00FF; - IE |= (uint)((uint)val << 8); - CheckAndFireInterrupts(); - break; - case 0x4000212: // IE B2 - IE &= 0xFF00FFFF; - IE |= (uint)((uint)val << 16); - CheckAndFireInterrupts(); - break; - case 0x4000213: // IE B3 - IE &= 0x00FFFFFF; - IE |= (uint)((uint)val << 24); - CheckAndFireInterrupts(); - break; - - case 0x4000214: // IF B0 - IF &= ~(uint)((uint)val << 0); - CheckAndFireInterrupts(); - break; - case 0x4000215: // IF B1 - IF &= ~(uint)((uint)val << 8); - CheckAndFireInterrupts(); - break; - case 0x4000216: // IF B2 - IF &= ~(uint)((uint)val << 16); - CheckAndFireInterrupts(); - break; - case 0x4000217: // IF B3 - IF &= ~(uint)((uint)val << 24); - CheckAndFireInterrupts(); - break; - } - } - - public override void FlagInterrupt(uint i) - { - IF |= (uint)(1 << (int)i); - CheckAndFireInterrupts(); - } - - public void CheckAndFireInterrupts() - { - Available = (IE & IF & 0xFFFFFFFF) != 0; - Cpu.FlagInterrupt = Available && IME; - if (Cpu.Armv5) - { - if (Available && IME) - { - Cpu.Halted = false; - } - } - else - { - if (Available) - { - Cpu.Halted = false; - } - } - } - } -} \ No newline at end of file diff --git a/Assets/emulator/HwControlNds.cs.meta b/Assets/emulator/HwControlNds.cs.meta deleted file mode 100644 index 0cb0e5f..0000000 --- a/Assets/emulator/HwControlNds.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 423f62bf81dca7648b5974281bffb372 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/Ipc.cs b/Assets/emulator/Ipc.cs deleted file mode 100644 index b882e98..0000000 --- a/Assets/emulator/Ipc.cs +++ /dev/null @@ -1,207 +0,0 @@ -using System; -using static OptimeGBA.Bits; - -namespace OptimeGBA -{ - public sealed class Ipc - { - Nds Nds; - byte Id; - - public Ipc(Nds nds, byte id) - { - Nds = nds; - Id = id; - } - - public CircularBuffer RecvFifo = new CircularBuffer(16, 0); - public uint LastSendValue; - public uint LastRecvValue; - - public bool SendFifoEmptyIrqLevel; - public bool RecvFifoPendingIrqLevel; - - public byte IpcSyncDataOut; - - // IPCSYNC - public bool EnableRemoteIrq; - - // IPCFIFOCNT - public bool EnableSendFifoEmptyIrq; - public bool EnableRecvFifoPendingIrq; - - public bool FifoError; - public bool EnableFifos; - - public byte ReadHwio8(uint addr) - { - byte val = 0; - switch (addr) - { - case 0x4000180: // IPCSYNC B0 - val |= GetRemote().IpcSyncDataOut; - break; - case 0x4000181: // IPCSYNC B1 - val |= IpcSyncDataOut; - - if (EnableRemoteIrq) val = BitSet(val, 14 - 8); - break; - - case 0x4000184: // IPCFIFOCNT B0 - if (GetRemote().RecvFifo.Entries == 0) val = BitSet(val, 0); // Send FIFO empty - if (GetRemote().RecvFifo.Entries == 16) val = BitSet(val, 1); // Send FIFO full - if (EnableSendFifoEmptyIrq) val = BitSet(val, 2); - CheckSendFifoEmptyIrq("IPCFIFOCNT bit enable"); - break; - case 0x4000185: // IPCFIFOCNT B1 - if (RecvFifo.Entries == 0) val = BitSet(val, 0); // Receive FIFO empty - if (RecvFifo.Entries == 16) val = BitSet(val, 1); // Receive FIFO full - if (EnableRecvFifoPendingIrq) val = BitSet(val, 2); - CheckRecvFifoPendingIrq("IPCFIFOCNT bit enable"); - - if (FifoError) val = BitSet(val, 6); - if (EnableFifos) val = BitSet(val, 7); - break; - - case 0x4100000: // IPCFIFORECV B0 - if (RecvFifo.Entries > 0) - { - if (EnableFifos) - { - LastRecvValue = RecvFifo.Pop(); - GetRemote().CheckSendFifoEmptyIrq("remote pop"); - } - } - else - { - FifoError = true; - } - val = GetByteIn(LastRecvValue, addr & 3); - break; - case 0x4100001: // IPCFIFORECV B1 - case 0x4100002: // IPCFIFORECV B2 - case 0x4100003: // IPCFIFORECV B3 - val = GetByteIn(LastRecvValue, addr & 3); - break; - } - - return val; - } - - public void WriteHwio8(uint addr, byte val) - { - switch (addr) - { - case 0x4000180: // IPCSYNC B0 - break; - case 0x4000181: // IPCSYNC B1 - IpcSyncDataOut = (byte)(val & 0xF); - - // send IRQ to remote - if (BitTest(val, 13 - 8) && GetRemote().EnableRemoteIrq) - { - // Console.WriteLine($"[{Id}] Sending IRQ"); - switch (Id) - { - case 0: - Nds.HwControl7.FlagInterrupt((uint)InterruptNds.IpcSync); - break; - case 1: - Nds.HwControl9.FlagInterrupt((uint)InterruptNds.IpcSync); - break; - } - } - EnableRemoteIrq = BitTest(val, 14 - 8); - break; - - case 0x4000184: // IPCFIFOCNT B0 - EnableSendFifoEmptyIrq = BitTest(val, 2); - if (BitTest(val, 3)) - { - GetRemote().RecvFifo.Reset(); - } - break; - case 0x4000185: // IPCFIFOCNT B1 - EnableRecvFifoPendingIrq = BitTest(val, 2); - - if (BitTest(val, 6)) - { - FifoError = false; - } - EnableFifos = BitTest(val, 7); - break; - - case 0x4000188: // IPCFIFOSEND B0 - case 0x4000189: // IPCFIFOSEND B1 - case 0x400018A: // IPCFIFOSEND B2 - LastSendValue = SetByteIn(LastSendValue, val, addr & 3); - break; - case 0x400018B: // IPCFIFOSEND B3 - LastSendValue = SetByteIn(LastSendValue, val, addr & 3); - if (EnableFifos) - { - GetRemote().RecvFifo.Insert(LastSendValue); - - bool eligible = true; - - // if ((LastSendValue >> 28) == 0x8) eligible = false; - // if ((LastSendValue >> 28) == 0x4) eligible = false; - // if ((LastSendValue >> 28) == 0xC) eligible = false; - // // if ((LastSendValue >> 28) == 0x0) eligible = false; - - // if (eligible) - // { - // if (Id == 0) Console.WriteLine("ARM9 to ARM7 " + Util.Hex(LastSendValue, 8)); - // // else Console.WriteLine("ARM7 to ARM9 " + Util.Hex(LastSendValue, 8)); - // } - - unsafe - { - GetRemote().CheckRecvFifoPendingIrq("remote insert R15: " + Util.Hex(Nds.Cpu7.R[15], 8)); - } - } - break; - } - } - - public Ipc GetRemote() - { - return Nds.Ipcs[Id ^ 1]; - } - - public void CheckSendFifoEmptyIrq(string from) - { - var prev = SendFifoEmptyIrqLevel; - SendFifoEmptyIrqLevel = GetRemote().RecvFifo.Entries == 0 && EnableSendFifoEmptyIrq; - if (!prev && SendFifoEmptyIrqLevel) - { - // Console.WriteLine($"Flagging ARM{(Id == 0 ? 7 : 9)} IPC Send FIFO Empty IRQ from " + from); - FlagSourceInterrupt(InterruptNds.IpcSendFifoEmpty); - } - } - - public void CheckRecvFifoPendingIrq(string from) - { - var prev = RecvFifoPendingIrqLevel; - RecvFifoPendingIrqLevel = RecvFifo.Entries > 0 && EnableRecvFifoPendingIrq; - if (!prev && RecvFifoPendingIrqLevel) - { - // Console.WriteLine($"Flagging ARM{(Id == 0 ? 7 : 9)} IPC Recv FIFO Pending Irq from " + from); - FlagSourceInterrupt(InterruptNds.IpcRecvFifoPending); - } - } - - public void FlagSourceInterrupt(InterruptNds interrupt) - { - switch (Id) - { - case 0: - Nds.HwControl9.FlagInterrupt((uint)interrupt); - break; - case 1: - Nds.HwControl7.FlagInterrupt((uint)interrupt); - break; - } - } - } -} \ No newline at end of file diff --git a/Assets/emulator/Ipc.cs.meta b/Assets/emulator/Ipc.cs.meta deleted file mode 100644 index 2b9ce0d..0000000 --- a/Assets/emulator/Ipc.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 84b3353082f9bee4f829c5b77d38c1fd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/KeyMappingButton.cs b/Assets/emulator/KeyMappingButton.cs new file mode 100644 index 0000000..c88f4bf --- /dev/null +++ b/Assets/emulator/KeyMappingButton.cs @@ -0,0 +1,39 @@ +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; +public enum GBAKeyCode +{ + Start, + Select, + Left, + Right, + Up, + Down, + A, + B, + L, + R, +} + +public class KeyMappingButton : Button, IPointerDownHandler, IPointerUpHandler +{ + public bool pressed { private set; get; } + public GBAKeyCode keyCode { private set; get; } + protected override void Awake() + { + pressed = false; + //keyCode = System.Enum.Parse(gameObject.name); + keyCode = (GBAKeyCode)System.Enum.Parse(keyCode.GetType(),gameObject.name); + } + + public override void OnPointerDown(PointerEventData eventData) + { + base.OnPointerDown(eventData); + pressed = true; + } + public override void OnPointerUp(PointerEventData eventData) + { + base.OnPointerUp(eventData); + pressed = false; + } +} diff --git a/Assets/emulator/DmaNds.cs.meta b/Assets/emulator/KeyMappingButton.cs.meta similarity index 83% rename from Assets/emulator/DmaNds.cs.meta rename to Assets/emulator/KeyMappingButton.cs.meta index 513c504..c362ca8 100644 --- a/Assets/emulator/DmaNds.cs.meta +++ b/Assets/emulator/KeyMappingButton.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: de4ad34ffe4c2a5458453cc7c40a4065 +guid: 3d8b0ab892d8e9640a62fe93c96abfb1 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/Keypad.cs b/Assets/emulator/Keypad.cs index 7d6c086..0a6b388 100644 --- a/Assets/emulator/Keypad.cs +++ b/Assets/emulator/Keypad.cs @@ -14,14 +14,6 @@ namespace OptimeGBA public bool Down; public bool R; public bool L; - - // DS Exclusive - public bool X; - public bool Y; - public bool DebugButton; - public bool Touch; - public bool ScreensOpen = true; // DS folded - public byte ReadHwio8(uint addr) { byte val = 0; @@ -42,14 +34,6 @@ namespace OptimeGBA if (!L) val = BitSet(val, 9 - 8); break; - case 0x4000136: // EXTKEYIN - ARM7 only - if (!X) val = BitSet(val, 0); - if (!Y) val = BitSet(val, 1); - if (!DebugButton) val = BitSet(val, 3); - if (!Touch) val = BitSet(val, 6); - if (!ScreensOpen) val = BitSet(val, 7); - // System.Console.WriteLine(Util.Hex(val, 2)); - break; case 0x4000137: // EXTKEYIN B1 val = 0; break; diff --git a/Assets/emulator/Keypad.cs.meta b/Assets/emulator/Keypad.cs.meta index 35668e0..aef692a 100644 --- a/Assets/emulator/Keypad.cs.meta +++ b/Assets/emulator/Keypad.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 46a2eabfa7974ee478fa25cfdc9fa1f1 +guid: 444bf15c0d0cab040b1b4967a2c3f94c MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/Memory.cs b/Assets/emulator/Memory.cs index b3b4347..dd35ae5 100644 --- a/Assets/emulator/Memory.cs +++ b/Assets/emulator/Memory.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; -using System.Collections.Concurrent; -using static OptimeGBA.Bits; using System.Runtime.InteropServices; using static OptimeGBA.MemoryUtil; diff --git a/Assets/emulator/Memory.cs.meta b/Assets/emulator/Memory.cs.meta index 9361909..b938a3b 100644 --- a/Assets/emulator/Memory.cs.meta +++ b/Assets/emulator/Memory.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d3f8f528aeb42c246bc8da7f5e034c36 +guid: a210b172849cb384e8d6c0a0d4956259 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/MemoryControlNds.cs b/Assets/emulator/MemoryControlNds.cs deleted file mode 100644 index d5586ae..0000000 --- a/Assets/emulator/MemoryControlNds.cs +++ /dev/null @@ -1,157 +0,0 @@ -using System; -using static OptimeGBA.Bits; -using System.Runtime.CompilerServices; - -namespace OptimeGBA -{ - public class MemoryControlNds - { - public byte SharedRamControl; - - public byte[] VRAMCNT = new byte[9]; - public bool VramConfigDirty; - - // EXMEMCNT - public byte Slot2SramWaitArm9; - public byte Slot2Rom0WaitArm9; - public byte Slot2Rom1WaitArm9; - public byte Slot2RomPhiPinOutArm9; - public byte Slot2SramWaitArm7; - public byte Slot2Rom0WaitArm7; - public byte Slot2Rom1WaitArm7; - public byte Slot2RomPhiPinOutArm7; - - // Shared between 7/9 EXMEMCNT/EXMEMSTAT - // true = ARM7 - public bool Nds7Slot2AccessRights; - public bool Nds7Slot1AccessRights; - public bool MainMemoryAccessPriority; - - public byte ReadHwio8Nds9(uint addr) - { - byte val = 0; - - switch (addr) - { - case 0x4000204: - // Console.WriteLine("read from exmemcnt b0"); - val |= (byte)((Slot2SramWaitArm9 & 0b11) << 0); - val |= (byte)((Slot2Rom0WaitArm9 & 0b11) << 2); - val |= (byte)((Slot2Rom1WaitArm9 & 0b1) << 4); - val |= (byte)((Slot2RomPhiPinOutArm9 & 0b11) << 5); - if (Nds7Slot2AccessRights) val = BitSet(val, 7); - break; - case 0x4000205: - // Console.WriteLine("read from exmemcnt b1"); - if (Nds7Slot1AccessRights) val = BitSet(val, 3); - if (MainMemoryAccessPriority) val = BitSet(val, 7); - val = BitSet(val, 6); - break; - } - - return val; - } - - public void WriteHwio8Nds9(uint addr, byte val) - { - switch (addr) - { - case 0x4000204: - // Console.WriteLine("write to exmemcnt b0"); - Slot2SramWaitArm9 = (byte)BitRange(val, 0, 1); - Slot2Rom0WaitArm9 = (byte)BitRange(val, 2, 3); - Slot2Rom1WaitArm9 = (byte)BitRange(val, 4, 4); - Slot2RomPhiPinOutArm9 = (byte)BitRange(val, 5, 6); - Nds7Slot2AccessRights = BitTest(val, 7); - break; - case 0x4000205: - // Console.WriteLine("write to exmemcnt b1"); - Nds7Slot1AccessRights = BitTest(val, 3); - MainMemoryAccessPriority = BitTest(val, 7); - break; - - case 0x4000240: if (VRAMCNT[0] != val) VramConfigDirty = true; VRAMCNT[0] = val; break; - case 0x4000241: if (VRAMCNT[1] != val) VramConfigDirty = true; VRAMCNT[1] = val; break; - case 0x4000242: if (VRAMCNT[2] != val) VramConfigDirty = true; VRAMCNT[2] = val; break; - case 0x4000243: if (VRAMCNT[3] != val) VramConfigDirty = true; VRAMCNT[3] = val; break; - case 0x4000244: if (VRAMCNT[4] != val) VramConfigDirty = true; VRAMCNT[4] = val; break; - case 0x4000245: if (VRAMCNT[5] != val) VramConfigDirty = true; VRAMCNT[5] = val; break; - case 0x4000246: if (VRAMCNT[6] != val) VramConfigDirty = true; VRAMCNT[6] = val; break; - case 0x4000248: if (VRAMCNT[7] != val) VramConfigDirty = true; VRAMCNT[7] = val; break; - case 0x4000249: if (VRAMCNT[8] != val) VramConfigDirty = true; VRAMCNT[8] = val; break; - - case 0x4000247: - SharedRamControl = (byte)(val & 0b11); - break; - } - - // if (VramEnabledAndSet(2, 2) || VramEnabledAndSet(3, 2)) - // { - // throw new NotImplementedException("Implement mapping VRAM banks C and D to ARM7"); - // } - } - - public byte ReadHwio8Nds7(uint addr) - { - byte val = 0; - - switch (addr) - { - case 0x4000204: - // Console.WriteLine("read from exmemstat b0"); - val |= (byte)((Slot2SramWaitArm7 & 0b11) << 0); - val |= (byte)((Slot2Rom0WaitArm7 & 0b11) << 2); - val |= (byte)((Slot2Rom1WaitArm7 & 0b1) << 4); - val |= (byte)((Slot2RomPhiPinOutArm7 & 0b11) << 5); - if (Nds7Slot2AccessRights) val = BitSet(val, 7); - break; - case 0x4000205: - // Console.WriteLine("read from exmemstat b1"); - if (Nds7Slot1AccessRights) val = BitSet(val, 3); - if (MainMemoryAccessPriority) val = BitSet(val, 7); - val = BitSet(val, 6); - break; - - case 0x4000240: - if (VramEnabledAndSet(2, 2)) val = BitSet(val, 0); - if (VramEnabledAndSet(3, 2)) val = BitSet(val, 1); - break; - case 0x4000241: - return SharedRamControl; - } - - return val; - } - - public void WriteHwio8Nds7(uint addr, byte val) - { - switch (addr) - { - case 0x4000204: - // Console.WriteLine("write to exmemstat b0"); - Slot2SramWaitArm7 = (byte)BitRange(val, 0, 1); - Slot2Rom0WaitArm7 = (byte)BitRange(val, 2, 3); - Slot2Rom1WaitArm7 = (byte)BitRange(val, 4, 4); - Slot2RomPhiPinOutArm7 = (byte)BitRange(val, 5, 6); - break; - } - - return; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool VramEnabledAndSet(uint bank, uint mst) - { - uint vramcntMst = VRAMCNT[bank] & 0b111U; - bool vramcntEnable = BitTest(VRAMCNT[bank], 7); - - return vramcntEnable && vramcntMst == mst; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint GetOffset(uint bank) - { - return (uint)(VRAMCNT[bank] >> 3) & 0b11U; - } - } -} \ No newline at end of file diff --git a/Assets/emulator/MemoryControlNds.cs.meta b/Assets/emulator/MemoryControlNds.cs.meta deleted file mode 100644 index 1810999..0000000 --- a/Assets/emulator/MemoryControlNds.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5cce821ff321fe34ea2e0c5cbabdd74e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/MemoryGba.cs b/Assets/emulator/MemoryGba.cs index 9368bc6..ba3ad1e 100644 --- a/Assets/emulator/MemoryGba.cs +++ b/Assets/emulator/MemoryGba.cs @@ -65,7 +65,7 @@ namespace OptimeGBA } breakOuterLoop: - Console.WriteLine($"Save Type: {strings[matchedIndex]}"); + //Debug.Log($"Save Type: {strings[matchedIndex]}"); switch (matchedIndex) { @@ -80,7 +80,7 @@ namespace OptimeGBA { EepromThreshold = 0x1FFFF00; } - Console.WriteLine("EEPROM Threshold: " + Util.Hex(EepromThreshold, 8)); + //Debug.Log("EEPROM Threshold: " + Util.Hex(EepromThreshold, 8)); break; case 2: SaveProvider = new Sram(); break; case 3: SaveProvider = new Flash(Gba, FlashSize.Flash512k); break; @@ -177,7 +177,7 @@ namespace OptimeGBA ~MemoryGba() { - Console.WriteLine("Cleaning up GBA memory..."); + //Debug.Log("Cleaning up GBA memory..."); UnpinByteArray(Bios); UnpinByteArray(Ewram); UnpinByteArray(Iwram); diff --git a/Assets/emulator/MemoryGba.cs.meta b/Assets/emulator/MemoryGba.cs.meta index 0a1f5b5..a2fdf8f 100644 --- a/Assets/emulator/MemoryGba.cs.meta +++ b/Assets/emulator/MemoryGba.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c3ab94683bca44e4db631e74b158b993 +guid: 4a6b84548f6fe89488daa4de20cb9164 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/MemoryNds7.cs b/Assets/emulator/MemoryNds7.cs deleted file mode 100644 index 7c267ff..0000000 --- a/Assets/emulator/MemoryNds7.cs +++ /dev/null @@ -1,449 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Collections.Concurrent; -using static OptimeGBA.Bits; -using System.Runtime.InteropServices; -using static OptimeGBA.MemoryUtil; -using static Util; - -namespace OptimeGBA -{ - public sealed unsafe class MemoryNds7 : Memory - { - Nds Nds; - - public MemoryNds7(Nds nds, ProviderNds provider) - { - Nds = nds; - - SaveProvider = new NullSaveProvider(); - - for (uint i = 0; i < Arm7BiosSize && i < provider.Bios7.Length; i++) - { - Arm7Bios[i] = provider.Bios7[i]; - } - } - - public const int Arm7BiosSize = 16384; - public const int Arm7WramSize = 65536; - - public byte[] Arm7Bios = new byte[Arm7BiosSize]; - public byte[] Arm7Wram = new byte[Arm7WramSize]; - - public byte RCNT; - - public override void InitPageTable(byte*[] table, uint[] maskTable, bool write) - { - byte* arm7Bios = TryPinByteArray(Arm7Bios); - byte* mainRam = TryPinByteArray(Nds.MainRam); - byte* arm7Wram = TryPinByteArray(Arm7Wram); - - // 12 bits shaved off already, shave off another 12 to get 24 - for (uint i = 0; i < 1048576; i++) - { - uint addr = (uint)(i << 12); - switch (i >> 12) - { - case 0x0: // BIOS - if (!write) - { - table[i] = arm7Bios; - } - maskTable[i] = 0x00003FFF; - break; - case 0x2: // Main Memory - table[i] = mainRam; - maskTable[i] = 0x003FFFFF; - break; - case 0x3: // Shared RAM / ARM7 WRAM - if (addr >= 0x03800000) - { - table[i] = arm7Wram; - maskTable[i] = 0x0000FFFF; - } - break; - } - } - } - - ~MemoryNds7() - { - Console.WriteLine("Cleaning up NDS7 memory..."); - UnpinByteArray(Arm7Bios); - UnpinByteArray(Nds.MainRam); - UnpinByteArray(Arm7Wram); - } - - public (byte[] array, uint offset) GetSharedRamParams(uint addr) - { - switch (Nds.MemoryControl.SharedRamControl) - { - case 0: - default: - addr &= 0xFFFF; // ARM7 WRAM - return (Arm7Wram, addr); - case 1: - addr &= 0x3FFF; // 1st half of Shared RAM - return (Nds.SharedRam, addr); - case 2: - addr &= 0x3FFF; // 2st half of Shared RAM - addr += 0x4000; - return (Nds.SharedRam, addr); - case 3: - addr &= 0x7FFF; // All 32k of Shared RAM - return (Nds.SharedRam, addr); - } - } - - public override byte Read8Unregistered(bool debug, uint addr) - { - switch (addr >> 24) - { - case 0x3: // Shared RAM - (byte[] array, uint offset) = GetSharedRamParams(addr); - return GetByte(array, offset); - case 0x4: // I/O Registers - return ReadHwio8(debug, addr); - case 0x6: // ARM7 VRAM - return Nds.Ppu.ReadVram8Arm7(addr); - } - - return 0; - } - - public override ushort Read16Unregistered(bool debug, uint addr) - { - switch (addr >> 24) - { - case 0x3: // Shared RAM - (byte[] array, uint offset) = GetSharedRamParams(addr); - return GetUshort(array, offset); - case 0x4: // I/O Registers - byte f0 = ReadHwio8(debug, addr++); - byte f1 = ReadHwio8(debug, addr++); - - ushort u16 = (ushort)((f1 << 8) | (f0 << 0)); - - return u16; - case 0x6: // VRAM - return (ushort)( - (Nds.Ppu.ReadVram8Arm7(addr + 0) << 0) | - (Nds.Ppu.ReadVram8Arm7(addr + 1) << 8) - ); - } - - return 0; - } - - public override uint Read32Unregistered(bool debug, uint addr) - { - switch (addr >> 24) - { - case 0x3: // Shared RAM - (byte[] array, uint offset) = GetSharedRamParams(addr); - return GetUint(array, offset); - case 0x4: // I/O Registers - byte f0 = ReadHwio8(debug, addr++); - byte f1 = ReadHwio8(debug, addr++); - byte f2 = ReadHwio8(debug, addr++); - byte f3 = ReadHwio8(debug, addr++); - - uint u32 = (uint)((f3 << 24) | (f2 << 16) | (f1 << 8) | (f0 << 0)); - - return u32; - case 0x6: // VRAM - return (uint)( - (Nds.Ppu.ReadVram8Arm7(addr + 0) << 0) | - (Nds.Ppu.ReadVram8Arm7(addr + 1) << 8) | - (Nds.Ppu.ReadVram8Arm7(addr + 2) << 16) | - (Nds.Ppu.ReadVram8Arm7(addr + 3) << 24) - ); - } - - return 0; - } - - public override void Write8Unregistered(bool debug, uint addr, byte val) - { - switch (addr >> 24) - { - case 0x3: // Shared RAM - (byte[] array, uint offset) = GetSharedRamParams(addr); - SetByte(array, offset, val); - break; - case 0x4: // I/O Registers - WriteHwio8(debug, addr, val); - break; - case 0x6: // ARM7 VRAM - Nds.Ppu.WriteVram8Arm7(addr, val); - break; - } - } - - public override void Write16Unregistered(bool debug, uint addr, ushort val) - { - switch (addr >> 24) - { - case 0x3: // Shared RAM - (byte[] array, uint offset) = GetSharedRamParams(addr); - SetUshort(array, offset, val); - break; - case 0x4: // I/O Registers - WriteHwio8(debug, addr++, (byte)(val >> 0)); - WriteHwio8(debug, addr++, (byte)(val >> 8)); - break; - case 0x6: // ARM7 VRAM - Nds.Ppu.WriteVram8Arm7(addr + 0, (byte)(val >> 0)); - Nds.Ppu.WriteVram8Arm7(addr + 1, (byte)(val >> 8)); - break; - } - } - - public override void Write32Unregistered(bool debug, uint addr, uint val) - { - switch (addr >> 24) - { - case 0x3: // Shared RAM - (byte[] array, uint offset) = GetSharedRamParams(addr); - SetUint(array, offset, val); - break; - case 0x4: // I/O Registers - WriteHwio8(debug, addr++, (byte)(val >> 0)); - WriteHwio8(debug, addr++, (byte)(val >> 8)); - WriteHwio8(debug, addr++, (byte)(val >> 16)); - WriteHwio8(debug, addr++, (byte)(val >> 24)); - break; - case 0x6: // ARM7 VRAM - Nds.Ppu.WriteVram8Arm7(addr + 0, (byte)(val >> 0)); - Nds.Ppu.WriteVram8Arm7(addr + 1, (byte)(val >> 8)); - Nds.Ppu.WriteVram8Arm7(addr + 2, (byte)(val >> 16)); - Nds.Ppu.WriteVram8Arm7(addr + 3, (byte)(val >> 24)); - break; - } - } - - - public byte ReadHwio8(bool debug, uint addr) - { - if (LogHwioAccesses) - { - lock (HwioReadLog) - { - if ((addr & ~1) != 0 && !debug) - { - uint count; - HwioReadLog.TryGetValue(addr, out count); - HwioReadLog[addr] = count + 1; - } - } - } - - // Special exceptions for cleanly defined blocks of MMIO - if (addr >= 0x4000400 && addr < 0x4000500) // Audio channels - { - return Nds.Audio.ReadHwio8Channels(addr); - } - - switch (addr) - { - case 0x4000004: case 0x4000005: // DISPSTAT - case 0x4000006: case 0x4000007: // VCOUNT - return Nds.Ppu.ReadHwio8Arm7(addr); - - case 0x40000B0: case 0x40000B1: case 0x40000B2: case 0x40000B3: // DMA0SAD - case 0x40000B4: case 0x40000B5: case 0x40000B6: case 0x40000B7: // DMA0DAD - case 0x40000B8: case 0x40000B9: case 0x40000BA: case 0x40000BB: // DMA0CNT - case 0x40000BC: case 0x40000BD: case 0x40000BE: case 0x40000BF: // DMA1SAD - case 0x40000C0: case 0x40000C1: case 0x40000C2: case 0x40000C3: // DMA1DAD - case 0x40000C4: case 0x40000C5: case 0x40000C6: case 0x40000C7: // DMA1CNT - case 0x40000C8: case 0x40000C9: case 0x40000CA: case 0x40000CB: // DMA2SAD - case 0x40000CC: case 0x40000CD: case 0x40000CE: case 0x40000CF: // DMA2DAD - case 0x40000D0: case 0x40000D1: case 0x40000D2: case 0x40000D3: // DMA2CNT - case 0x40000D4: case 0x40000D5: case 0x40000D6: case 0x40000D7: // DMA3SAD - case 0x40000D8: case 0x40000D9: case 0x40000DA: case 0x40000DB: // DMA3DAD - case 0x40000DC: case 0x40000DD: case 0x40000DE: case 0x40000DF: // DMA3CNT - case 0x40000E0: case 0x40000E1: case 0x40000E2: case 0x40000E3: // DMA0 Fill Data - case 0x40000E4: case 0x40000E5: case 0x40000E6: case 0x40000E7: // DMA1 Fill Data - case 0x40000E8: case 0x40000E9: case 0x40000EA: case 0x40000EB: // DMA2 Fill Data - case 0x40000EC: case 0x40000ED: case 0x40000EE: case 0x40000EF: // DMA3 Fill Data - return Nds.Dma7.ReadHwio8(addr); - - case 0x4000100: case 0x4000101: case 0x4000102: case 0x4000103: // Timer 0 - case 0x4000104: case 0x4000105: case 0x4000106: case 0x4000107: // Timer 1 - case 0x4000108: case 0x4000109: case 0x400010A: case 0x400010B: // Timer 2 - case 0x400010C: case 0x400010D: case 0x400010E: case 0x400010F: // Timer 3 - return Nds.Timers7.ReadHwio8(addr); - - case 0x4000180: case 0x4000181: case 0x4000182: case 0x4000183: // IPCSYNC - case 0x4000184: case 0x4000185: case 0x4000186: case 0x4000187: // IPCFIFOCNT - case 0x4000188: case 0x4000189: case 0x400018A: case 0x400018B: // IPCFIFOSEND - case 0x4100000: case 0x4100001: case 0x4100002: case 0x4100003: // IPCFIFORECV - return Nds.Ipcs[1].ReadHwio8(addr); - - case 0x40001A0: case 0x40001A1: // AUXSPICNT - case 0x40001A2: case 0x40001A3: // AUXSPIDATA - case 0x40001A4: case 0x40001A5: case 0x40001A6: case 0x40001A7: // ROMCTRL - case 0x4100010: case 0x4100011: case 0x4100012: case 0x4100013: // Slot 1 Data In - return Nds.Cartridge.ReadHwio8(true, addr); - - case 0x40001C0: case 0x40001C1: // SPICNT - case 0x40001C2: case 0x40001C3: // SPIDATA - return Nds.Spi.ReadHwio8(addr); - - case 0x4000136: case 0x4000137: // EXTKEYIN - // Console.WriteLine(Hex(Nds7.Cpu.R[15], 8)); - goto case 0x4000130; - case 0x4000130: case 0x4000131: // KEYINPUT - return Nds.Keypad.ReadHwio8(addr); - - case 0x4000204: case 0x4000205: // EXMEMSTAT - return Nds.MemoryControl.ReadHwio8Nds7(addr); - - case 0x4000208: case 0x4000209: case 0x400020A: case 0x400020B: // IME - case 0x4000210: case 0x4000211: case 0x4000212: case 0x4000213: // IE - case 0x4000214: case 0x4000215: case 0x4000216: case 0x4000217: // IF - return Nds.HwControl7.ReadHwio8(addr); - - case 0x4000134: - return 0x80; - case 0x4000135: // Stubbed RCNT - return 0; - - case 0x4000138: case 0x4000139: // RTC - return Nds.Rtc.ReadHwio8(addr); - - case 0x4000240: case 0x4000241: // Memory Control Status - return Nds.MemoryControl.ReadHwio8Nds7(addr); - - case 0x4000500: case 0x4000501: // SOUNDCNT - case 0x4000504: case 0x4000505: // SOUNDBIAS - case 0x4000508: case 0x4000509: // SNDCAPCNT - return Nds.Audio.ReadHwio8(addr); - - case 0x4000300: - // Console.WriteLine("NDS7 POSTFLG read"); - return Nds.HwControl7.Postflg; - - case 0x4000304: case 0x4000305: case 0x4000306: case 0x4000307: // POWCNT1 - return Nds.ReadHwio8Arm7(addr); - } - - // Console.WriteLine($"NDS7: Unmapped MMIO read addr:{Hex(addr, 8)}"); - - return 0; - } - - public void WriteHwio8(bool debug, uint addr, byte val) - { - if (LogHwioAccesses) - { - lock (HwioWriteLog) - { - if ((addr & ~1) != 0 && !debug) - { - uint count; - HwioWriteLog.TryGetValue(addr, out count); - HwioWriteLog[addr] = count + 1; - } - } - } - - // Special exceptions for cleanly defined blocks of MMIO - if (addr >= 0x4000400 && addr < 0x4000500) // Audio channels - { - Nds.Audio.WriteHwio8Channels(addr, val); - return; - } - - switch (addr) - { - case 0x4000004: case 0x4000005: // DISPSTAT - case 0x4000006: case 0x4000007: // VCOUNT - Nds.Ppu.WriteHwio8Arm7(addr, val); return; - - case 0x40000B0: case 0x40000B1: case 0x40000B2: case 0x40000B3: // DMA0SAD - case 0x40000B4: case 0x40000B5: case 0x40000B6: case 0x40000B7: // DMA0DAD - case 0x40000B8: case 0x40000B9: case 0x40000BA: case 0x40000BB: // DMA0CNT - case 0x40000BC: case 0x40000BD: case 0x40000BE: case 0x40000BF: // DMA1SAD - case 0x40000C0: case 0x40000C1: case 0x40000C2: case 0x40000C3: // DMA1DAD - case 0x40000C4: case 0x40000C5: case 0x40000C6: case 0x40000C7: // DMA1CNT - case 0x40000C8: case 0x40000C9: case 0x40000CA: case 0x40000CB: // DMA2SAD - case 0x40000CC: case 0x40000CD: case 0x40000CE: case 0x40000CF: // DMA2DAD - case 0x40000D0: case 0x40000D1: case 0x40000D2: case 0x40000D3: // DMA2CNT - case 0x40000D4: case 0x40000D5: case 0x40000D6: case 0x40000D7: // DMA3SAD - case 0x40000D8: case 0x40000D9: case 0x40000DA: case 0x40000DB: // DMA3DAD - case 0x40000DC: case 0x40000DD: case 0x40000DE: case 0x40000DF: // DMA3CNT - case 0x40000E0: case 0x40000E1: case 0x40000E2: case 0x40000E3: // DMA0 Fill Data - case 0x40000E4: case 0x40000E5: case 0x40000E6: case 0x40000E7: // DMA1 Fill Data - case 0x40000E8: case 0x40000E9: case 0x40000EA: case 0x40000EB: // DMA2 Fill Data - case 0x40000EC: case 0x40000ED: case 0x40000EE: case 0x40000EF: // DMA3 Fill Data - Nds.Dma7.WriteHwio8(addr, val); return; - - case 0x4000100: case 0x4000101: case 0x4000102: case 0x4000103: // Timer 0 - case 0x4000104: case 0x4000105: case 0x4000106: case 0x4000107: // Timer 1 - case 0x4000108: case 0x4000109: case 0x400010A: case 0x400010B: // Timer 2 - case 0x400010C: case 0x400010D: case 0x400010E: case 0x400010F: // Timer 3 - Nds.Timers7.WriteHwio8(addr, val); return; - - case 0x4000180: case 0x4000181: case 0x4000182: case 0x4000183: // IPCSYNC - case 0x4000184: case 0x4000185: case 0x4000186: case 0x4000187: // IPCFIFOCNT - case 0x4000188: case 0x4000189: case 0x400018A: case 0x400018B: // IPCFIFOSEND - Nds.Ipcs[1].WriteHwio8(addr, val); return; - - case 0x40001A0: case 0x40001A1: // AUXSPICNT - case 0x40001A2: case 0x40001A3: // AUXSPIDATA - case 0x40001A4: case 0x40001A5: case 0x40001A6: case 0x40001A7: // ROMCTRL - case 0x40001A8: case 0x40001A9: case 0x40001AA: case 0x40001AB: // Slot 1 Command 0-3 - case 0x40001AC: case 0x40001AD: case 0x40001AE: case 0x40001AF: // Slot 1 Command 4-7 - Nds.Cartridge.WriteHwio8(true, addr, val); return; - - case 0x40001B0: case 0x40001B1: case 0x40001B2: case 0x40001B3: // Slot 1 KEY2 encryption seed - case 0x40001B4: case 0x40001B5: case 0x40001B6: case 0x40001B7: - case 0x40001B8: case 0x40001B9: case 0x40001BA: case 0x40001BB: - return; - - case 0x40001C0: case 0x40001C1: // SPICNT - case 0x40001C2: case 0x40001C3: // SPIDATA - Nds.Spi.WriteHwio8(addr, val); return; - - case 0x4000204: case 0x4000205: // EXMEMSTAT - Nds.MemoryControl.WriteHwio8Nds7(addr, val); return; - - case 0x4000208: case 0x4000209: case 0x400020A: case 0x400020B: // IME - case 0x4000210: case 0x4000211: case 0x4000212: case 0x4000213: // IE - case 0x4000214: case 0x4000215: case 0x4000216: case 0x4000217: // IF - Nds.HwControl7.WriteHwio8(addr, val); return; - - case 0x4000134: case 0x4000135: // Stubbed RCNT - return; - - case 0x4000138: case 0x4000139: // RTC - Nds.Rtc.WriteHwio8(addr, val); return; - - case 0x4000500: case 0x4000501: // SOUNDCNT - case 0x4000504: case 0x4000505: // SOUNDBIAS - case 0x4000508: case 0x4000509: // SNDCAPCNT - Nds.Audio.WriteHwio8(addr, val); return; - - case 0x4000300: - Console.WriteLine("NDS7 POSTFLG write"); - Nds.HwControl7.Postflg = (byte)(val & 1); - return; - - case 0x4000301: - if ((val & 0b11000000) == 0b10000000) - { - Nds.Cpu7.Halted = true; - } - return; - - case 0x4000304: case 0x4000305: case 0x4000306: case 0x4000307: // POWCNT1 - Nds.WriteHwio8Arm7(addr, val); - return; - } - - // Console.WriteLine($"NDS7: Unmapped MMIO write addr:{Hex(addr, 8)} val:{Hex(val, 2)}"); - } - } -} diff --git a/Assets/emulator/MemoryNds7.cs.meta b/Assets/emulator/MemoryNds7.cs.meta deleted file mode 100644 index 7858fbb..0000000 --- a/Assets/emulator/MemoryNds7.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f3898147a3efcd8499a8a51b3f945ff3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/MemoryNds9.cs b/Assets/emulator/MemoryNds9.cs deleted file mode 100644 index 4a505fd..0000000 --- a/Assets/emulator/MemoryNds9.cs +++ /dev/null @@ -1,622 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Collections.Concurrent; -using static OptimeGBA.Bits; -using System.Runtime.InteropServices; -using static OptimeGBA.MemoryUtil; -using static Util; - -namespace OptimeGBA -{ - public sealed unsafe class MemoryNds9 : Memory - { - Nds Nds; - - public MemoryNds9(Nds nds, ProviderNds provider) - { - Nds = nds; - - SaveProvider = new NullSaveProvider(); - - for (uint i = 0; i < Arm9BiosSize && i < provider.Bios9.Length; i++) - { - Arm9Bios[i] = provider.Bios9[i]; - } - } - - public const int Arm9BiosSize = 4096; - public byte[] Arm9Bios = new byte[Arm9BiosSize]; - public const int ItcmSize = 32768; - public byte[] Itcm = new byte[ItcmSize]; - public const int DtcmSize = 16384; - public byte[] Dtcm = new byte[DtcmSize]; - - public uint DtcmBase = 0; - public uint ItcmVirtualSize = 0; - public uint DtcmVirtualSize = 0; - public bool ItcmLoadMode = false; - public bool DtcmLoadMode = false; - - public override void InitPageTable(byte*[] table, uint[] maskTable, bool write) - { - byte* mainRam = TryPinByteArray(Nds.MainRam); - byte* arm9Bios = TryPinByteArray(Arm9Bios); - byte* dtcm = TryPinByteArray(Dtcm); - byte* itcm = TryPinByteArray(Itcm); - - // 12 bits shaved off already, shave off another 12 to get 24 - for (uint i = 0; i < 1048576; i++) - { - table[i] = null; // Clear everything out first, since on ARM9 things can move around - - uint addr = (uint)(i << 12); - switch (i >> 12) - { - case 0x2: // Main Memory - table[i] = mainRam; - maskTable[i] = 0x003FFFFF; - break; - case 0xFF: // BIOS - if (!write) - { - table[i] = arm9Bios; - } - maskTable[i] = 0x00000FFF; - break; - } - - if (addr >= DtcmBase && addr < DtcmBase + DtcmVirtualSize) - { - - if (write || !DtcmLoadMode) - { - // Console.WriteLine("DTCM page set at " + Util.Hex(addr, 8)); - table[i] = dtcm; - } - maskTable[i] = 0x00003FFF; - } - - // ITCM is immovable - // ITCM has higher priority so write pages in after DTCM - if (addr < ItcmVirtualSize) - { - if (write || !ItcmLoadMode) - { - table[i] = itcm; - } - maskTable[i] = 0x00007FFF; - } - } - } - - ~MemoryNds9() - { - Console.WriteLine("Cleaning up NDS9 memory..."); - UnpinByteArray(Nds.MainRam); - UnpinByteArray(Arm9Bios); - UnpinByteArray(Dtcm); - UnpinByteArray(Itcm); - } - - public void UpdateTcmSettings() - { - // Console.WriteLine("Data TCM Settings: " + Util.Hex(Nds.Cp15.DataTcmSettings, 8)); - ItcmVirtualSize = 512U << (int)((Nds.Cp15.InstTcmSettings >> 1) & 0x1F); - DtcmVirtualSize = 512U << (int)((Nds.Cp15.DataTcmSettings >> 1) & 0x1F); - - DtcmBase = (uint)(Nds.Cp15.DataTcmSettings & 0xFFFFF000); - - ItcmLoadMode = BitTest(Nds.Cp15.ControlRegister, 19); - DtcmLoadMode = BitTest(Nds.Cp15.ControlRegister, 17); - - Console.WriteLine("ITCM set to: " + Util.Hex(0, 8) + " - " + Util.Hex(ItcmVirtualSize - 1, 8)); - Console.WriteLine("DTCM set to: " + Util.Hex(DtcmBase, 8) + " - " + Util.Hex(DtcmBase + DtcmVirtualSize - 1, 8)); - - InitPageTables(); - } - - public (byte[] array, uint offset) GetSharedRamParams(uint addr) - { - switch (Nds.MemoryControl.SharedRamControl) - { - case 0: - default: - addr &= 0x7FFF; // All 32k of Shared RAM - return (Nds.SharedRam, addr); - case 1: - addr &= 0x3FFF; // 2nd half of Shared RAM - addr += 0x4000; - return (Nds.SharedRam, addr); - case 2: - addr &= 0x3FFF; // 1st half of Shared RAM - return (Nds.SharedRam, addr); - case 3: - // throw new NotImplementedException("Implement unmapping Shared RAM from ARM9 without EmptyPage, since some game can possibly try to write to the EmptyPage"); - EmptyPage[0] = 0; - return (EmptyPage, 0); // Unmapped - } - } - - public override byte Read8Unregistered(bool debug, uint addr) - { - switch (addr >> 24) - { - case 0x3: // Shared RAM - (byte[] array, uint offset) = GetSharedRamParams(addr); - return GetByte(array, offset); - case 0x4: // I/O Registers - return ReadHwio8(debug, addr); - case 0x5: // PPU Palettes - return Nds.Ppu.ReadPalettes8(addr); - case 0x6: // VRAM - return Nds.Ppu.ReadVram8Arm9(addr); - case 0x7: // PPU OAM - return Nds.Ppu.ReadOam8(addr); - } - - return 0; - } - - public override ushort Read16Unregistered(bool debug, uint addr) - { - switch (addr >> 24) - { - case 0x3: // Shared RAM - (byte[] array, uint offset) = GetSharedRamParams(addr); - return GetUshort(array, offset); - case 0x4: // I/O Registers - byte f0 = ReadHwio8(debug, addr++); - byte f1 = ReadHwio8(debug, addr++); - - ushort u16 = (ushort)((f1 << 8) | (f0 << 0)); - - return u16; - case 0x5: // PPU Palettes - return Nds.Ppu.ReadPalettes16(addr); - case 0x6: // VRAM - return (ushort)( - (Nds.Ppu.ReadVram8Arm9(addr + 0) << 0) | - (Nds.Ppu.ReadVram8Arm9(addr + 1) << 8) - ); - case 0x7: // PPU OAM - return Nds.Ppu.ReadOam16(addr); - } - - return 0; - } - - public override uint Read32Unregistered(bool debug, uint addr) - { - switch (addr >> 24) - { - case 0x3: // Shared RAM - (byte[] array, uint offset) = GetSharedRamParams(addr); - return GetUint(array, offset); - case 0x4: // I/O Registers - if (addr >= 0x4000320 && addr < 0x40006A4) // 3D - { - return Nds.Ppu3D.ReadHwio32(addr); - } - - byte f0 = ReadHwio8(debug, addr + 0); - byte f1 = ReadHwio8(debug, addr + 1); - byte f2 = ReadHwio8(debug, addr + 2); - byte f3 = ReadHwio8(debug, addr + 3); - - uint u32 = (uint)((f3 << 24) | (f2 << 16) | (f1 << 8) | (f0 << 0)); - - return u32; - case 0x5: // PPU Palettes - return Nds.Ppu.ReadPalettes32(addr); - case 0x6: // VRAM - return (uint)( - (Nds.Ppu.ReadVram8Arm9(addr + 0) << 0) | - (Nds.Ppu.ReadVram8Arm9(addr + 1) << 8) | - (Nds.Ppu.ReadVram8Arm9(addr + 2) << 16) | - (Nds.Ppu.ReadVram8Arm9(addr + 3) << 24) - ); - case 0x7: // PPU OAM - return Nds.Ppu.ReadOam32(addr); - } - - return 0; - } - - public override void Write8Unregistered(bool debug, uint addr, byte val) - { - switch (addr >> 24) - { - case 0x3: // Shared RAM - (byte[] array, uint offset) = GetSharedRamParams(addr); - SetByte(array, offset, val); - break; - case 0x4: // I/O Registers - WriteHwio8(debug, addr, val); - break; - case 0x5: // PPU Palettes - duplicated across upper-lower in 8-bit?? - Console.WriteLine("NDS: 8-bit write to palettes"); - // Nds.Ppu.WritePalettes8(addr + 0, val); - // Nds.Ppu.WritePalettes8(addr + 1, val); - break; - } - } - - public override void Write16Unregistered(bool debug, uint addr, ushort val) - { - switch (addr >> 24) - { - case 0x3: // Shared RAM - (byte[] array, uint offset) = GetSharedRamParams(addr); - SetUshort(array, offset, val); - break; - case 0x4: // I/O Registers - WriteHwio8(debug, addr++, (byte)(val >> 0)); - WriteHwio8(debug, addr++, (byte)(val >> 8)); - break; - case 0x5: // PPU Palettes - Nds.Ppu.WritePalettes16(addr, val); - break; - case 0x6: // VRAM - Nds.Ppu.WriteVram8Arm9(addr + 0, (byte)(val >> 0)); - Nds.Ppu.WriteVram8Arm9(addr + 1, (byte)(val >> 8)); - break; - case 0x7: // PPU OAM - Nds.Ppu.WriteOam16(addr, val); - break; - } - } - - public override void Write32Unregistered(bool debug, uint addr, uint val) - { - switch (addr >> 24) - { - case 0x3: // Shared RAM - (byte[] array, uint offset) = GetSharedRamParams(addr); - SetUint(array, offset, val); - break; - case 0x4: // I/O Registers - if (addr >= 0x4000320 && addr < 0x40006A4) // 3D - { - Nds.Ppu3D.WriteHwio32(addr, val); - return; - } - WriteHwio8(debug, addr++, (byte)(val >> 0)); - WriteHwio8(debug, addr++, (byte)(val >> 8)); - WriteHwio8(debug, addr++, (byte)(val >> 16)); - WriteHwio8(debug, addr++, (byte)(val >> 24)); - break; - case 0x5: // PPU Palettes - Nds.Ppu.WritePalettes32(addr, val); - break; - case 0x6: // VRAM - Nds.Ppu.WriteVram8Arm9(addr + 0, (byte)(val >> 0)); - Nds.Ppu.WriteVram8Arm9(addr + 1, (byte)(val >> 8)); - Nds.Ppu.WriteVram8Arm9(addr + 2, (byte)(val >> 16)); - Nds.Ppu.WriteVram8Arm9(addr + 3, (byte)(val >> 24)); - break; - case 0x7: // PPU OAM - Nds.Ppu.WriteOam32(addr, val); - break; - } - } - - public byte ReadHwio8(bool debug, uint addr) - { - if (LogHwioAccesses) - { - lock (HwioReadLog) { - if ((addr & ~1) != 0 && !debug) - { - uint count; - HwioReadLog.TryGetValue(addr, out count); - HwioReadLog[addr] = count + 1; - } - } - } - - if (addr >= 0x4000320 && addr < 0x40006A4) // 3D - { - Console.Error.WriteLine("8-bit or 16-bit read to 3D"); - return 0; - } - - switch (addr) - { - // Engine A - case 0x4000000: case 0x4000001: case 0x4000002: case 0x4000003: // DISPCNT A - case 0x4000004: case 0x4000005: // DISPSTAT - case 0x4000006: case 0x4000007: // VCOUNT - case 0x4000008: case 0x4000009: // BG0CNT - case 0x400000A: case 0x400000B: // BG1CNT - case 0x400000C: case 0x400000D: // BG2CNT - case 0x400000E: case 0x400000F: // BG3CNT - case 0x4000010: case 0x4000011: case 0x4000012: case 0x4000013: // BG0OFS - case 0x4000014: case 0x4000015: case 0x4000016: case 0x4000017: // BG1OFS - case 0x4000018: case 0x4000019: case 0x400001A: case 0x400001B: // BG2OFS - case 0x400001C: case 0x400001D: case 0x400001E: case 0x400001F: // BG3OFS - case 0x4000020: case 0x4000021: case 0x4000022: case 0x4000023: // BG2PA/PB - case 0x4000024: case 0x4000025: case 0x4000026: case 0x4000027: // BG2PC/PD - case 0x4000028: case 0x4000029: case 0x400002A: case 0x400002B: // BG2X - case 0x400002C: case 0x400002D: case 0x400002E: case 0x400002F: // BG2Y - case 0x4000030: case 0x4000031: case 0x4000032: case 0x4000033: // BG3PA/PB - case 0x4000034: case 0x4000035: case 0x4000036: case 0x4000037: // BG3PC/PD - case 0x4000038: case 0x4000039: case 0x400003A: case 0x400003B: // BG3X - case 0x400003C: case 0x400003D: case 0x400003E: case 0x400003F: // BG3Y - case 0x4000040: case 0x4000041: case 0x4000042: case 0x4000043: // WINH - case 0x4000044: case 0x4000045: case 0x4000046: case 0x4000047: // WINV - case 0x4000048: case 0x4000049: case 0x400004A: case 0x400004B: // WININ/OUT - case 0x400004C: case 0x400004D: // MOSAIC - case 0x4000050: case 0x4000051: // BLDCNT - case 0x4000052: case 0x4000053: // BLDALPHA - case 0x4000054: case 0x4000055: // BLDY - case 0x4000060: case 0x4000061: // DISP3DCNT - case 0x4000064: case 0x4000065: case 0x4000066: case 0x4000067: // DISPCAPCNT - case 0x400006C: case 0x400006D: // MASTER_BRIGHT - - // Engine B - case 0x4001000: case 0x4001001: case 0x4001002: case 0x4001003: // DISPCNT A - case 0x4001008: case 0x4001009: // BG0CNT - case 0x400100A: case 0x400100B: // BG1CNT - case 0x400100C: case 0x400100D: // BG2CNT - case 0x400100E: case 0x400100F: // BG3CNT - case 0x4001010: case 0x4001011: case 0x4001012: case 0x4001013: // BG0OFS - case 0x4001014: case 0x4001015: case 0x4001016: case 0x4001017: // BG1OFS - case 0x4001018: case 0x4001019: case 0x400101A: case 0x400101B: // BG2OFS - case 0x400101C: case 0x400101D: case 0x400101E: case 0x400101F: // BG3OFS - case 0x4001020: case 0x4001021: case 0x4001022: case 0x4001023: // BG2PA/PB - case 0x4001024: case 0x4001025: case 0x4001026: case 0x4001027: // BG2PC/PD - case 0x4001028: case 0x4001029: case 0x400102A: case 0x400102B: // BG2X - case 0x400102C: case 0x400102D: case 0x400102E: case 0x400102F: // BG2Y - case 0x4001030: case 0x4001031: case 0x4001032: case 0x4001033: // BG3PA/PB - case 0x4001034: case 0x4001035: case 0x4001036: case 0x4001037: // BG3PC/PD - case 0x4001038: case 0x4001039: case 0x400103A: case 0x400103B: // BG3X - case 0x400103C: case 0x400103D: case 0x400103E: case 0x400103F: // BG3Y - case 0x4001040: case 0x4001041: case 0x4001042: case 0x4001043: // WINH - case 0x4001044: case 0x4001045: case 0x4001046: case 0x4001047: // WINV - case 0x4001048: case 0x4001049: case 0x400104A: case 0x400104B: // WININ/OUT - case 0x400104C: case 0x400104D: // MOSAIC - case 0x4001050: case 0x4001051: // BLDCNT - case 0x4001052: case 0x4001053: // BLDALPHA - case 0x4001054: case 0x4001055: // BLDY - case 0x400106C: case 0x400106D: // MASTER_BRIGHT - return Nds.Ppu.ReadHwio8Arm9(addr); - - case 0x40000B0: case 0x40000B1: case 0x40000B2: case 0x40000B3: // DMA0SAD - case 0x40000B4: case 0x40000B5: case 0x40000B6: case 0x40000B7: // DMA0DAD - case 0x40000B8: case 0x40000B9: case 0x40000BA: case 0x40000BB: // DMA0CNT - case 0x40000BC: case 0x40000BD: case 0x40000BE: case 0x40000BF: // DMA1SAD - case 0x40000C0: case 0x40000C1: case 0x40000C2: case 0x40000C3: // DMA1DAD - case 0x40000C4: case 0x40000C5: case 0x40000C6: case 0x40000C7: // DMA1CNT - case 0x40000C8: case 0x40000C9: case 0x40000CA: case 0x40000CB: // DMA2SAD - case 0x40000CC: case 0x40000CD: case 0x40000CE: case 0x40000CF: // DMA2DAD - case 0x40000D0: case 0x40000D1: case 0x40000D2: case 0x40000D3: // DMA2CNT - case 0x40000D4: case 0x40000D5: case 0x40000D6: case 0x40000D7: // DMA3SAD - case 0x40000D8: case 0x40000D9: case 0x40000DA: case 0x40000DB: // DMA3DAD - case 0x40000DC: case 0x40000DD: case 0x40000DE: case 0x40000DF: // DMA3CNT - case 0x40000E0: case 0x40000E1: case 0x40000E2: case 0x40000E3: // DMA0 Fill Data - case 0x40000E4: case 0x40000E5: case 0x40000E6: case 0x40000E7: // DMA1 Fill Data - case 0x40000E8: case 0x40000E9: case 0x40000EA: case 0x40000EB: // DMA2 Fill Data - case 0x40000EC: case 0x40000ED: case 0x40000EE: case 0x40000EF: // DMA3 Fill Data - return Nds.Dma9.ReadHwio8(addr); - - case 0x4000100: case 0x4000101: case 0x4000102: case 0x4000103: // Timer 0 - case 0x4000104: case 0x4000105: case 0x4000106: case 0x4000107: // Timer 1 - case 0x4000108: case 0x4000109: case 0x400010A: case 0x400010B: // Timer 2 - case 0x400010C: case 0x400010D: case 0x400010E: case 0x400010F: // Timer 3 - return Nds.Timers9.ReadHwio8(addr); - - case 0x4000180: case 0x4000181: case 0x4000182: case 0x4000183: // IPCSYNC - case 0x4000184: case 0x4000185: case 0x4000186: case 0x4000187: // IPCFIFOCNT - case 0x4000188: case 0x4000189: case 0x400018A: case 0x400018B: // IPCFIFOSEND - case 0x4100000: case 0x4100001: case 0x4100002: case 0x4100003: // IPCFIFORECV - return Nds.Ipcs[0].ReadHwio8(addr); - - case 0x40001A0: case 0x40001A1: // AUXSPICNT - case 0x40001A2: case 0x40001A3: // AUXSPIDATA - case 0x40001A4: case 0x40001A5: case 0x40001A6: case 0x40001A7: // ROMCTRL - case 0x4100010: case 0x4100011: case 0x4100012: case 0x4100013: // Slot 1 Data In - return Nds.Cartridge.ReadHwio8(false, addr); - - case 0x4000208: case 0x4000209: case 0x400020A: case 0x400020B: // IME - case 0x4000210: case 0x4000211: case 0x4000212: case 0x4000213: // IE - case 0x4000214: case 0x4000215: case 0x4000216: case 0x4000217: // IF - return Nds.HwControl9.ReadHwio8(addr); - - case 0x4000130: case 0x4000131: // KEYINPUT - return Nds.Keypad.ReadHwio8(addr); - - case 0x4000204: case 0x4000205: // EXMEMCNT - case 0x4000240: case 0x4000241: case 0x4000242: case 0x4000243: // VRAMCNT - case 0x4000244: case 0x4000245: case 0x4000246: case 0x4000247: // VRAMCNT, WRAMCNT - case 0x4000248: case 0x4000249: // VRAMCNT - return Nds.MemoryControl.ReadHwio8Nds9(addr); - - case 0x4000280: case 0x4000281: case 0x4000282: case 0x4000283: // DIVCNT B3 - case 0x4000290: case 0x4000291: case 0x4000292: case 0x4000293: // DIV_NUMER - case 0x4000294: case 0x4000295: case 0x4000296: case 0x4000297: // DIV_NUMER - case 0x4000298: case 0x4000299: case 0x400029A: case 0x400029B: // DIV_DENOM - case 0x400029C: case 0x400029D: case 0x400029E: case 0x400029F: // DIV_DENOM - case 0x40002A0: case 0x40002A1: case 0x40002A2: case 0x40002A3: // DIV_RESULT - case 0x40002A4: case 0x40002A5: case 0x40002A6: case 0x40002A7: // DIV_RESULT - case 0x40002A8: case 0x40002A9: case 0x40002AA: case 0x40002AB: // DIVREM_RESULT - case 0x40002AC: case 0x40002AD: case 0x40002AE: case 0x40002AF: // DIVREM_RESULT - case 0x40002B0: case 0x40002B1: // SQRTCNT - case 0x40002B4: case 0x40002B5: case 0x40002B6: case 0x40002B7: // SQRT_RESULT - case 0x40002B8: case 0x40002B9: case 0x40002BA: case 0x40002BB: // SQRT_PARAM - case 0x40002BC: case 0x40002BD: case 0x40002BE: case 0x40002BF: // SQRT_PARAM - return Nds.Math.ReadHwio8(addr); - - case 0x4000300: - // Console.WriteLine("NDS9 POSTFLG read"); - return Nds.HwControl9.Postflg; - case 0x4000304: case 0x4000305: case 0x4000306: case 0x4000307: // POWCNT1 - return Nds.ReadHwio8Arm9(addr); - } - - // Console.WriteLine($"NDS9: Unmapped MMIO read addr:{Hex(addr, 8)}"); - - return 0; - } - - public void WriteHwio8(bool debug, uint addr, byte val) - { - if (LogHwioAccesses) - { - lock (HwioWriteLog) { - if ((addr & ~1) != 0 && !debug) - { - uint count; - HwioWriteLog.TryGetValue(addr, out count); - HwioWriteLog[addr] = count + 1; - } - } - } - - if (addr >= 0x4000320 && addr < 0x40006A4) // 3D - { - // Console.Error.WriteLine($"8-bit or 16-bit write to 3D addr:{Hex(addr, 8)} val:{Hex(val, 2)}"); - return; - } - - switch (addr) - { - // Engine A - case 0x4000000: case 0x4000001: case 0x4000002: case 0x4000003: // DISPCNT A - case 0x4000004: case 0x4000005: // DISPSTAT - case 0x4000006: case 0x4000007: // VCOUNT - case 0x4000008: case 0x4000009: // BG0CNT - case 0x400000A: case 0x400000B: // BG1CNT - case 0x400000C: case 0x400000D: // BG2CNT - case 0x400000E: case 0x400000F: // BG3CNT - case 0x4000010: case 0x4000011: case 0x4000012: case 0x4000013: // BG0OFS - case 0x4000014: case 0x4000015: case 0x4000016: case 0x4000017: // BG1OFS - case 0x4000018: case 0x4000019: case 0x400001A: case 0x400001B: // BG2OFS - case 0x400001C: case 0x400001D: case 0x400001E: case 0x400001F: // BG3OFS - case 0x4000020: case 0x4000021: case 0x4000022: case 0x4000023: // BG2PA/PB - case 0x4000024: case 0x4000025: case 0x4000026: case 0x4000027: // BG2PC/PD - case 0x4000028: case 0x4000029: case 0x400002A: case 0x400002B: // BG2X - case 0x400002C: case 0x400002D: case 0x400002E: case 0x400002F: // BG2Y - case 0x4000030: case 0x4000031: case 0x4000032: case 0x4000033: // BG3PA/PB - case 0x4000034: case 0x4000035: case 0x4000036: case 0x4000037: // BG3PC/PD - case 0x4000038: case 0x4000039: case 0x400003A: case 0x400003B: // BG3X - case 0x400003C: case 0x400003D: case 0x400003E: case 0x400003F: // BG3Y - case 0x4000040: case 0x4000041: case 0x4000042: case 0x4000043: // WINH - case 0x4000044: case 0x4000045: case 0x4000046: case 0x4000047: // WINV - case 0x4000048: case 0x4000049: case 0x400004A: case 0x400004B: // WININ/OUT - case 0x400004C: case 0x400004D: // MOSAIC - case 0x4000050: case 0x4000051: // BLDCNT - case 0x4000052: case 0x4000053: // BLDALPHA - case 0x4000054: case 0x4000055: // BLDY - case 0x4000060: case 0x4000061: // DISP3DCNT - case 0x4000064: case 0x4000065: case 0x4000066: case 0x4000067: // DISPCAPCNT - case 0x400006C: case 0x400006D: // MASTER_BRIGHT - - // Engine B - case 0x4001000: case 0x4001001: case 0x4001002: case 0x4001003: // DISPCNT A - case 0x4001008: case 0x4001009: // BG0CNT - case 0x400100A: case 0x400100B: // BG1CNT - case 0x400100C: case 0x400100D: // BG2CNT - case 0x400100E: case 0x400100F: // BG3CNT - case 0x4001010: case 0x4001011: case 0x4001012: case 0x4001013: // BG0OFS - case 0x4001014: case 0x4001015: case 0x4001016: case 0x4001017: // BG1OFS - case 0x4001018: case 0x4001019: case 0x400101A: case 0x400101B: // BG2OFS - case 0x400101C: case 0x400101D: case 0x400101E: case 0x400101F: // BG3OFS - case 0x4001020: case 0x4001021: case 0x4001022: case 0x4001023: // BG2PA/PB - case 0x4001024: case 0x4001025: case 0x4001026: case 0x4001027: // BG2PC/PD - case 0x4001028: case 0x4001029: case 0x400102A: case 0x400102B: // BG2X - case 0x400102C: case 0x400102D: case 0x400102E: case 0x400102F: // BG2Y - case 0x4001030: case 0x4001031: case 0x4001032: case 0x4001033: // BG3PA/PB - case 0x4001034: case 0x4001035: case 0x4001036: case 0x4001037: // BG3PC/PD - case 0x4001038: case 0x4001039: case 0x400103A: case 0x400103B: // BG3X - case 0x400103C: case 0x400103D: case 0x400103E: case 0x400103F: // BG3Y - case 0x4001040: case 0x4001041: case 0x4001042: case 0x4001043: // WINH - case 0x4001044: case 0x4001045: case 0x4001046: case 0x4001047: // WINV - case 0x4001048: case 0x4001049: case 0x400104A: case 0x400104B: // WININ/OUT - case 0x400104C: case 0x400104D: // MOSAIC - case 0x4001050: case 0x4001051: // BLDCNT - case 0x4001052: case 0x4001053: // BLDALPHA - case 0x4001054: case 0x4001055: // BLDY - case 0x400106C: case 0x400106D: // MASTER_BRIGHT - Nds.Ppu.WriteHwio8Arm9(addr, val); return; - - case 0x40000B0: case 0x40000B1: case 0x40000B2: case 0x40000B3: // DMA0SAD - case 0x40000B4: case 0x40000B5: case 0x40000B6: case 0x40000B7: // DMA0DAD - case 0x40000B8: case 0x40000B9: case 0x40000BA: case 0x40000BB: // DMA0CNT - case 0x40000BC: case 0x40000BD: case 0x40000BE: case 0x40000BF: // DMA1SAD - case 0x40000C0: case 0x40000C1: case 0x40000C2: case 0x40000C3: // DMA1DAD - case 0x40000C4: case 0x40000C5: case 0x40000C6: case 0x40000C7: // DMA1CNT - case 0x40000C8: case 0x40000C9: case 0x40000CA: case 0x40000CB: // DMA2SAD - case 0x40000CC: case 0x40000CD: case 0x40000CE: case 0x40000CF: // DMA2DAD - case 0x40000D0: case 0x40000D1: case 0x40000D2: case 0x40000D3: // DMA2CNT - case 0x40000D4: case 0x40000D5: case 0x40000D6: case 0x40000D7: // DMA3SAD - case 0x40000D8: case 0x40000D9: case 0x40000DA: case 0x40000DB: // DMA3DAD - case 0x40000DC: case 0x40000DD: case 0x40000DE: case 0x40000DF: // DMA3CNT - case 0x40000E0: case 0x40000E1: case 0x40000E2: case 0x40000E3: // DMA0 Fill Data - case 0x40000E4: case 0x40000E5: case 0x40000E6: case 0x40000E7: // DMA1 Fill Data - case 0x40000E8: case 0x40000E9: case 0x40000EA: case 0x40000EB: // DMA2 Fill Data - case 0x40000EC: case 0x40000ED: case 0x40000EE: case 0x40000EF: // DMA3 Fill Data - Nds.Dma9.WriteHwio8(addr, val); return; - - case 0x4000100: case 0x4000101: case 0x4000102: case 0x4000103: // Timer 0 - case 0x4000104: case 0x4000105: case 0x4000106: case 0x4000107: // Timer 1 - case 0x4000108: case 0x4000109: case 0x400010A: case 0x400010B: // Timer 2 - case 0x400010C: case 0x400010D: case 0x400010E: case 0x400010F: // Timer 3 - Nds.Timers9.WriteHwio8(addr, val); return; - - case 0x4000180: case 0x4000181: case 0x4000182: case 0x4000183: // IPCSYNC - case 0x4000184: case 0x4000185: case 0x4000186: case 0x4000187: // IPCFIFOCNT - case 0x4000188: case 0x4000189: case 0x400018A: case 0x400018B: // IPCFIFOSEND - Nds.Ipcs[0].WriteHwio8(addr, val); return; - - case 0x40001A0: case 0x40001A1: // AUXSPICNT - case 0x40001A2: case 0x40001A3: // AUXSPIDATA - case 0x40001A4: case 0x40001A5: case 0x40001A6: case 0x40001A7: // ROMCTRL - case 0x40001A8: case 0x40001A9: case 0x40001AA: case 0x40001AB: // Slot 1 Command 0-3 - case 0x40001AC: case 0x40001AD: case 0x40001AE: case 0x40001AF: // Slot 1 Command 4-7 - Nds.Cartridge.WriteHwio8(false, addr, val); return; - - case 0x40001B0: case 0x40001B1: case 0x40001B2: case 0x40001B3: // Slot 1 KEY2 encryption seed - case 0x40001B4: case 0x40001B5: case 0x40001B6: case 0x40001B7: - case 0x40001B8: case 0x40001B9: case 0x40001BA: case 0x40001BB: - return; - - case 0x4000208: case 0x4000209: case 0x400020A: case 0x400020B: // IME - case 0x4000210: case 0x4000211: case 0x4000212: case 0x4000213: // IE - case 0x4000214: case 0x4000215: case 0x4000216: case 0x4000217: // IF - Nds.HwControl9.WriteHwio8(addr, val); return; - - case 0x4000204: case 0x4000205: // EXMEMCNT - case 0x4000240: case 0x4000241: case 0x4000242: case 0x4000243: // VRAMCNT - case 0x4000244: case 0x4000245: case 0x4000246: case 0x4000247: // VRAMCNT, WRAMCNT - case 0x4000248: case 0x4000249: // VRAMCNT - Nds.MemoryControl.WriteHwio8Nds9(addr, val); return; - - case 0x4000280: case 0x4000281: case 0x4000282: case 0x4000283: // DIVCNT B3 - case 0x4000290: case 0x4000291: case 0x4000292: case 0x4000293: // DIV_NUMER - case 0x4000294: case 0x4000295: case 0x4000296: case 0x4000297: // DIV_NUMER - case 0x4000298: case 0x4000299: case 0x400029A: case 0x400029B: // DIV_DENOM - case 0x400029C: case 0x400029D: case 0x400029E: case 0x400029F: // DIV_DENOM - case 0x40002A0: case 0x40002A1: case 0x40002A2: case 0x40002A3: // DIV_RESULT - case 0x40002A4: case 0x40002A5: case 0x40002A6: case 0x40002A7: // DIV_RESULT - case 0x40002A8: case 0x40002A9: case 0x40002AA: case 0x40002AB: // DIVREM_RESULT - case 0x40002AC: case 0x40002AD: case 0x40002AE: case 0x40002AF: // DIVREM_RESULT - case 0x40002B0: case 0x40002B1: // SQRTCNT - case 0x40002B4: case 0x40002B5: case 0x40002B6: case 0x40002B7: // SQRT_RESULT - case 0x40002B8: case 0x40002B9: case 0x40002BA: case 0x40002BB: // SQRT_PARAM - case 0x40002BC: case 0x40002BD: case 0x40002BE: case 0x40002BF: // SQRT_PARAM - Nds.Math.WriteHwio8(addr, val); return; - - case 0x4000300: - Console.WriteLine("NDS9 POSTFLG write"); - Nds.HwControl9.Postflg = (byte)(val & 0b11); - return; - case 0x4000304: case 0x4000305: case 0x4000306: case 0x4000307:// POWCNT1 - Nds.WriteHwio8Arm9(addr, val); - return; - } - - // Console.WriteLine($"NDS9: Unmapped MMIO write addr:{Hex(addr, 8)} val:{Hex(val, 2)}"); - } - } -} diff --git a/Assets/emulator/MemoryNds9.cs.meta b/Assets/emulator/MemoryNds9.cs.meta deleted file mode 100644 index 78db1fa..0000000 --- a/Assets/emulator/MemoryNds9.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c562e007e77a5c448b8dfa6621f2efb8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/MemoryUtil.cs.meta b/Assets/emulator/MemoryUtil.cs.meta index 69d21ff..4984429 100644 --- a/Assets/emulator/MemoryUtil.cs.meta +++ b/Assets/emulator/MemoryUtil.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0d5d8289e96e59342bab0324b6d66a91 +guid: 13e3364ce9f87224fa1b1bfac909d236 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/Nds.cs b/Assets/emulator/Nds.cs deleted file mode 100644 index 4ecdc83..0000000 --- a/Assets/emulator/Nds.cs +++ /dev/null @@ -1,396 +0,0 @@ -using System; -using static OptimeGBA.MemoryUtil; -using static OptimeGBA.Bits; -using static Util; - -namespace OptimeGBA -{ - public unsafe sealed class Nds - { - public ProviderNds Provider; - - // ARM9 side - public MemoryNds9 Mem9; - public Arm7 Cpu9; - public HwControlNds HwControl9; - public DmaNds Dma9; - public Timers Timers9; - public Nds9Math Math; - - // ARM7 side - public MemoryNds7 Mem7; - public Arm7 Cpu7; - public HwControlNds HwControl7; - public Spi Spi; - public NdsAudio Audio; - public DmaNds Dma7; - public Timers Timers7; - - public Scheduler Scheduler; - - public Cp15 Cp15; - - public CartridgeNds Cartridge; - - // Based off of EXMEMCNT ownership rules, there 1 is ARM7 - public Ipc[] Ipcs; // 0: ARM9 to ARM7, 1: ARM7 to ARM9 - - public PpuNds Ppu; - public PpuNds3D Ppu3D; - - public MemoryControlNds MemoryControl; - - public Keypad Keypad = new Keypad(); - - public RtcNds Rtc; - - public byte[] MainRam = new byte[4194304]; - public byte[] SharedRam = new byte[32768]; - - public int Arm9PendingTicks; - - public ulong Steps; - - public Nds(ProviderNds provider) - { - Provider = provider; - Scheduler = new Scheduler(); - - Ipcs = new Ipc[] { - new Ipc(this, 0), - new Ipc(this, 1), - }; - - Cp15 = new Cp15(this); - - Cartridge = new CartridgeNds(this); - - Ppu = new PpuNds(this, Scheduler); - Ppu3D = new PpuNds3D(this, Scheduler); - - MemoryControl = new MemoryControlNds(); - - Rtc = new RtcNds(); - - // ARM9 Init - Mem9 = new MemoryNds9(this, Provider); - Cpu9 = new Arm7(StateChangeArm9, Mem9, true, true, Cp15); - HwControl9 = new HwControlNds(Cpu9); - Dma9 = new DmaNds(false, Mem9, HwControl9); - Timers9 = new Timers(null, HwControl9, Scheduler, true, false); - Math = new Nds9Math(this); - Mem9.InitPageTables(); - Cpu9.InitFlushPipeline(); - Cpu9.SetVectorMode(true); - // screw it - Cpu9.SetTimingsTable( - Cpu9.Timing8And16, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - ); - Cpu9.SetTimingsTable( - Cpu9.Timing32, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - ); - Cpu9.SetTimingsTable( - Cpu9.Timing8And16InstrFetch, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - ); - Cpu9.SetTimingsTable( - Cpu9.Timing32InstrFetch, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - ); - - // ARM7 init - Mem7 = new MemoryNds7(this, Provider); - Spi = new Spi(this); - Audio = new NdsAudio(this); - Cpu7 = new Arm7(StateChangeArm7, Mem7, false, false, null); - HwControl7 = new HwControlNds(Cpu7); - Dma7 = new DmaNds(true, Mem7, HwControl7); - Timers7 = new Timers(null, HwControl7, Scheduler, true, true); - Mem7.InitPageTables(); - Cpu7.InitFlushPipeline(); - // screw it - Cpu7.SetTimingsTable( - Cpu7.Timing8And16, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - ); - Cpu7.SetTimingsTable( - Cpu7.Timing32, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - ); - Cpu7.SetTimingsTable( - Cpu7.Timing8And16InstrFetch, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - ); - Cpu7.SetTimingsTable( - Cpu7.Timing32InstrFetch, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - ); - -#if UNSAFE - Console.WriteLine("Starting in memory UNSAFE mode"); -#else - Console.WriteLine("Starting in memory SAFE mode"); -#endif - - if (provider.DirectBoot) - { - var rom = provider.Rom; - - // Firmware init - MemoryControl.SharedRamControl = 3; - HwControl7.Postflg = 1; - HwControl9.Postflg = 1; - - Cartridge.Slot1Enable = true; - - Cpu9.IRQDisable = true; - Cpu9.FIQDisable = true; - - // Thanks Hydr8gon / fleroviux lol - Mem7.Write16(0x4000184, 0x8501); // IPCFIFOCNT7 - Mem9.Write16(0x4000184, 0x8501); // IPCFIFOCNT9 - - Cp15.TransferTo(0, 0x0005707D, 1, 0, 0); // CP15 Control - Cp15.TransferTo(0, 0x0300000A, 9, 1, 0); // Data TCM base/size - Cp15.TransferTo(0, 0x00000020, 9, 1, 1); // Instruction TCM size - Mem9.Write8(0x4000247, 0x03); // WRAMCNT - Mem9.Write16(0x4000304, 0x0001); // POWCNT1 - Mem7.Write16(0x4000504, 0x0200); // SOUNDBIAS - - Mem9.Write32(0x027FF800, 0x1FC2); // Chip ID 1 - Mem9.Write32(0x027FF804, 0x1FC2); // Chip ID 2 - Mem9.Write16(0x027FF850, 0x5835); // ARM7 BIOS CRC - Mem9.Write16(0x027FF880, 0x0007); // Message from ARM9 to ARM7 - Mem9.Write16(0x027FF884, 0x0006); // ARM7 boot task - Mem9.Write32(0x027FFC00, 0x1FC2); // Copy of chip ID 1 - Mem9.Write32(0x027FFC04, 0x1FC2); // Copy of chip ID 2 - Mem9.Write16(0x027FFC10, 0x5835); // Copy of ARM7 BIOS CRC - Mem9.Write16(0x027FFC40, 0x0001); // Boot indicator - - Mem9.Write32(0x027FF864, 0); - Mem9.Write32(0x027FF868, (uint)(GetUshort(Provider.Firmware, 0x20) << 3)); - - Mem9.Write16(0x027FF874, GetUshort(Provider.Firmware, 0x26)); - Mem9.Write16(0x027FF876, GetUshort(Provider.Firmware, 0x04)); - - // Copy in header - if (rom.Length >= 0x170) - { - for (uint i = 0; i < 0x170; i++) - { - Mem9.Write8(0x027FFE00 + i, rom[i]); - } - } - - for (uint i = 0; i < 0x70; i++) - { - Mem9.Write8(0x27FFC80 + i, Provider.Firmware[0x3FF00 + i]); - } - - Mem9.Write32(0x027FF864, 0); - Mem9.Write32(0x027FF868, (uint)(GetUshort(Provider.Firmware, 0x20) << 3)); - - Mem9.Write16(0x027FF874, GetUshort(Provider.Firmware, 0x26)); - Mem9.Write16(0x027FF876, GetUshort(Provider.Firmware, 0x04)); - - if (rom.Length >= 0x20) - { - uint arm7RomOffset = GetUint(rom, 0x30); - uint arm7EntryAddr = GetUint(rom, 0x34); - uint arm7RamAddr = GetUint(rom, 0x38); - uint arm7Size = GetUint(rom, 0x3C); - - // ROM offset is aligned by 0x1000 - Console.WriteLine("ARM7 ROM Offset: " + Hex(arm7RomOffset, 8)); - Console.WriteLine("ARM7 RAM Address: " + Hex(arm7RamAddr, 8)); - Console.WriteLine("ARM7 Entry: " + Hex(arm7EntryAddr, 8)); - Console.WriteLine("ARM7 Size: " + arm7Size); - for (uint i = 0; i < arm7Size; i++) - { - Mem7.Write8(arm7RamAddr + i, rom[arm7RomOffset + i]); - } - Cpu7.R[13] = 0x3002F7C; - Cpu7.SetModeReg(13, Arm7Mode.IRQ, 0x3003F80); - Cpu7.SetModeReg(13, Arm7Mode.SVC, 0x3003FC0); - Cpu7.R[12] = arm7EntryAddr; - Cpu7.R[14] = arm7EntryAddr; - Cpu7.R[15] = arm7EntryAddr; - Cpu7.InitFlushPipeline(); - - uint arm9RomOffset = GetUint(rom, 0x20); - uint arm9EntryAddr = GetUint(rom, 0x24); - uint arm9RamAddr = GetUint(rom, 0x28); - uint arm9Size = GetUint(rom, 0x2C); - - Console.WriteLine("ARM9 ROM Offset: " + Hex(arm9RomOffset, 8)); - Console.WriteLine("ARM9 RAM Address: " + Hex(arm9RamAddr, 8)); - Console.WriteLine("ARM9 Entry: " + Hex(arm9EntryAddr, 8)); - Console.WriteLine("ARM9 Size: " + arm9Size); - for (uint i = 0; i < arm9Size; i++) - { - Mem9.Write8(arm9RamAddr + i, rom[arm9RomOffset + i]); - } - Cpu9.R[13] = 0x380FD80; - Cpu9.SetModeReg(13, Arm7Mode.IRQ, 0x380FF80); - Cpu9.SetModeReg(13, Arm7Mode.SVC, 0x380FFC0); - Cpu9.R[12] = arm9EntryAddr; - Cpu9.R[14] = arm9EntryAddr; - Cpu9.R[15] = arm9EntryAddr; - Cpu9.InitFlushPipeline(); - } - } - } - - public uint Step() - { - Steps++; - - long beforeTicks = Scheduler.CurrentTicks; - - while (Scheduler.CurrentTicks < Scheduler.NextEventTicks) - { - // Running both CPUs at 1CPI at 32 MHz causes the firmware to loop the setup screen, - // so don't do that when not debugging simple test ROMs - // Cpu7.Execute(); - // Cpu9.Execute(); - // Scheduler.CurrentTicks += 1; - - // TODO: Proper NDS timings - // TODO: Figure out a better way to implement halting - uint ticks7 = 0; - // Run 32 ARM7 instructions at a time, who needs tight synchronization - const uint instrsAtATime = 32; - if (!Cpu7.Halted) - { - for (uint i = 0; i < instrsAtATime; i++) - { - if (!Cpu7.Halted) - { - ticks7 += Cpu7.Execute(); - } - else - { - ticks7 += instrsAtATime; - break; - } - } - } - else - { - ticks7 += instrsAtATime; - } - - Arm9PendingTicks += (int)ticks7 * 2; // ARM9 runs at twice the speed of ARM7 - while (Arm9PendingTicks > 0) - { - if (!Cpu9.Halted) - { - Arm9PendingTicks -= (int)Cpu9.Execute(); - } - else - { - Arm9PendingTicks -= (int)(Scheduler.NextEventTicks - Scheduler.CurrentTicks) * 2; - break; - } - } - - Ppu3D.Run(); - - Scheduler.CurrentTicks += ticks7; - } - - long current = Scheduler.CurrentTicks; - long next = Scheduler.NextEventTicks; - Scheduler.PopFirstEvent().Callback(current - next); - - return (uint)(Scheduler.CurrentTicks - beforeTicks); - } - - public void DoNothing(long cyclesLate) { } - - public void Tick(uint cycles) - { - Scheduler.CurrentTicks += cycles; - } - - public void HaltSkip(long cyclesOffset) { } - - // POWCNT1 - public bool EnableDisplay; - public bool Enable2DEngineA; - public bool Enable3DRenderingEngine; - public bool Enable3DGeometryEngine; - public bool Enable2DEngineB; - public bool DisplaySwap; - - public byte ReadHwio8Arm9(uint addr) - { - byte val = 0; - switch (addr) - { - case 0x4000304: - if (EnableDisplay) val = BitSet(val, 0); - if (Enable2DEngineA) val = BitSet(val, 1); - if (Enable3DRenderingEngine) val = BitSet(val, 2); - if (Enable3DGeometryEngine) val = BitSet(val, 3); - break; - case 0x4000305: - if (Enable2DEngineB) val = BitSet(val, 1); - if (DisplaySwap) val = BitSet(val, 7); - break; - } - return val; - } - - public void WriteHwio8Arm9(uint addr, byte val) - { - switch (addr) - { - case 0x4000304: - EnableDisplay = BitTest(val, 0); - Enable2DEngineA = BitTest(val, 1); - Enable3DRenderingEngine = BitTest(val, 2); - Enable3DGeometryEngine = BitTest(val, 3); - break; - case 0x4000305: - Enable2DEngineB = BitTest(val, 1); - DisplaySwap = BitTest(val, 7); - break; - } - } - - public void StateChangeArm9() { } - - // POWCNT2 - public bool EnableSpeakers; - public bool EnableWifi; - - public byte ReadHwio8Arm7(uint addr) - { - byte val = 0; - switch (addr) - { - case 0x4000304: - if (EnableSpeakers) val = BitSet(val, 0); - if (EnableWifi) val = BitSet(val, 1); - break; - } - return val; - } - - public void WriteHwio8Arm7(uint addr, byte val) - { - switch (addr) - { - case 0x4000304: - EnableSpeakers = BitTest(val, 0); - EnableWifi = BitTest(val, 1); - break; - } - } - - public void StateChangeArm7() { } - } -} \ No newline at end of file diff --git a/Assets/emulator/Nds.cs.meta b/Assets/emulator/Nds.cs.meta deleted file mode 100644 index ed372df..0000000 --- a/Assets/emulator/Nds.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f4cdddf1f287aa24d91a6aa89a4bae70 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/Nds9Math.cs b/Assets/emulator/Nds9Math.cs deleted file mode 100644 index a1cca53..0000000 --- a/Assets/emulator/Nds9Math.cs +++ /dev/null @@ -1,276 +0,0 @@ -using System; -using static OptimeGBA.Bits; -namespace OptimeGBA -{ - public unsafe sealed class Nds9Math - { - public Nds Nds; - - public Nds9Math(Nds nds) - { - Nds = nds; - } - - public long DIV_NUMER; - public long DIV_DENOM; - - public long DIV_RESULT; - public long DIVREM_RESULT; - - public uint SQRT_RESULT; - public ulong SQRT_PARAM; - - // DIVCNT - public uint DivisionMode; - public bool DividedByZero; - public bool DivideBusy; - - // SQRTCNT - public bool SqrtUse64BitInput; - public bool SqrtBusy; - - public byte ReadHwio8(uint addr) - { - byte val = 0; - switch (addr) - { - case 0x4000280: // DIVCNT B0 - val |= (byte)(DivisionMode & 0b11); - break; - case 0x4000281: // DIVCNT B1 - if (DividedByZero) val = BitSet(val, 6); - if (DivideBusy) val = BitSet(val, 7); - break; - case 0x4000282: // DIVCNT B2 - case 0x4000283: // DIVCNT B3 - break; - - case 0x4000290: // DIV_NUMER B0 - case 0x4000291: // DIV_NUMER B1 - case 0x4000292: // DIV_NUMER B2 - case 0x4000293: // DIV_NUMER B3 - case 0x4000294: // DIV_NUMER B4 - case 0x4000295: // DIV_NUMER B5 - case 0x4000296: // DIV_NUMER B6 - case 0x4000297: // DIV_NUMER B7 - return GetByteIn(DIV_NUMER, addr & 7); - case 0x4000298: // DIV_DENOM B0 - case 0x4000299: // DIV_DENOM B1 - case 0x400029A: // DIV_DENOM B2 - case 0x400029B: // DIV_DENOM B3 - case 0x400029C: // DIV_DENOM B4 - case 0x400029D: // DIV_DENOM B5 - case 0x400029E: // DIV_DENOM B6 - case 0x400029F: // DIV_DENOM B7 - return GetByteIn(DIV_DENOM, addr & 7); - case 0x40002A0: // DIV_RESULT B0 - case 0x40002A1: // DIV_RESULT B1 - case 0x40002A2: // DIV_RESULT B2 - case 0x40002A3: // DIV_RESULT B3 - case 0x40002A4: // DIV_RESULT B4 - case 0x40002A5: // DIV_RESULT B5 - case 0x40002A6: // DIV_RESULT B6 - case 0x40002A7: // DIV_RESULT B7 - return GetByteIn(DIV_RESULT, addr & 7); - case 0x40002A8: // DIVREM_RESULT B0 - case 0x40002A9: // DIVREM_RESULT B1 - case 0x40002AA: // DIVREM_RESULT B2 - case 0x40002AB: // DIVREM_RESULT B3 - case 0x40002AC: // DIVREM_RESULT B4 - case 0x40002AD: // DIVREM_RESULT B5 - case 0x40002AE: // DIVREM_RESULT B6 - case 0x40002AF: // DIVREM_RESULT B7 - return GetByteIn(DIVREM_RESULT, addr & 7); - - case 0x40002B0: // SQRTCNT B0 - if (SqrtUse64BitInput) val = BitSet(val, 0); - break; - case 0x40002B1: // SQRTCNT B0 - break; - - case 0x40002B4: // SQRT_RESULT B0 - case 0x40002B5: // SQRT_RESULT B1 - case 0x40002B6: // SQRT_RESULT B2 - case 0x40002B7: // SQRT_RESULT B3 - return GetByteIn(SQRT_RESULT, addr & 3); - case 0x40002B8: // SQRT_PARAM B0 - case 0x40002B9: // SQRT_PARAM B1 - case 0x40002BA: // SQRT_PARAM B2 - case 0x40002BB: // SQRT_PARAM B3 - case 0x40002BC: // SQRT_PARAM B4 - case 0x40002BD: // SQRT_PARAM B5 - case 0x40002BE: // SQRT_PARAM B6 - case 0x40002BF: // SQRT_PARAM B7 - return GetByteIn(SQRT_PARAM, addr & 7); - - default: - throw new NotImplementedException("Read from DS math @ " + Util.Hex(addr, 8)); - } - - return val; - } - - public void WriteHwio8(uint addr, byte val) - { - switch (addr) - { - case 0x4000280: // DIVCNT B0 - DivisionMode = (byte)(val & 0b11); - Divide(); - break; - case 0x4000281: // DIVCNT B1 - case 0x4000282: // DIVCNT B2 - case 0x4000283: // DIVCNT B3 - break; - - case 0x4000290: // DIV_NUMER B0 - case 0x4000291: // DIV_NUMER B1 - case 0x4000292: // DIV_NUMER B2 - case 0x4000293: // DIV_NUMER B3 - case 0x4000294: // DIV_NUMER B4 - case 0x4000295: // DIV_NUMER B5 - case 0x4000296: // DIV_NUMER B6 - case 0x4000297: // DIV_NUMER B7 - DIV_NUMER = SetByteIn(DIV_NUMER, val, addr & 7); - Divide(); - break; - case 0x4000298: // DIV_DENOM B0 - case 0x4000299: // DIV_DENOM B1 - case 0x400029A: // DIV_DENOM B2 - case 0x400029B: // DIV_DENOM B3 - case 0x400029C: // DIV_DENOM B4 - case 0x400029D: // DIV_DENOM B5 - case 0x400029E: // DIV_DENOM B6 - case 0x400029F: // DIV_DENOM B7 - DIV_DENOM = SetByteIn(DIV_DENOM, val, addr & 7); - Divide(); - break; - - case 0x40002B0: // SQRTCNT B0 - SqrtUse64BitInput = BitTest(val, 0); - TakeSquareRoot(); - break; - case 0x40002B1: // SQRTCNT B0 - break; - - case 0x40002B8: // SQRT_PARAM B0 - case 0x40002B9: // SQRT_PARAM B1 - case 0x40002BA: // SQRT_PARAM B2 - case 0x40002BB: // SQRT_PARAM B3 - case 0x40002BC: // SQRT_PARAM B4 - case 0x40002BD: // SQRT_PARAM B5 - case 0x40002BE: // SQRT_PARAM B6 - case 0x40002BF: // SQRT_PARAM B7 - SQRT_PARAM = SetByteIn(SQRT_PARAM, val, addr & 7); - TakeSquareRoot(); - return; - - // default: - // throw new NotImplementedException("Write to DS math @ " + Util.Hex(addr, 8)); - } - } - - public void Divide() - { - DividedByZero = DIV_DENOM == 0; - - switch (DivisionMode) - { - case 0: // 32bit / 32bit - if ((int)DIV_NUMER == int.MinValue && (int)DIV_DENOM == -1) // Overflow - { - DIV_RESULT = (long)(int)DIV_NUMER ^ (0xFFFFFFFFL << 32); - DIVREM_RESULT = 0; - } - else if ((int)DIV_DENOM != 0) - { - DIV_RESULT = (int)DIV_NUMER / (int)DIV_DENOM; - DIVREM_RESULT = (int)DIV_NUMER % (int)DIV_DENOM; - } - else // Division by 0 - { - DIV_RESULT = (((int)DIV_NUMER < 0) ? 1 : -1) ^ (0xFFFFFFFFL << 32); - DIVREM_RESULT = (int)DIV_NUMER; - } - break; - case 3: - case 1: // 64bit / 32bit - if (DIV_NUMER == long.MinValue && (int)DIV_DENOM == -1) // Overflow - { - DIV_RESULT = DIV_NUMER; - DIVREM_RESULT = 0; - } - else if ((int)DIV_DENOM != 0) - { - DIV_RESULT = DIV_NUMER / (int)DIV_DENOM; - DIVREM_RESULT = DIV_NUMER % (int)DIV_DENOM; - } - else // Division by 0 - { - DIV_RESULT = (DIV_NUMER < 0) ? 1 : -1; - DIVREM_RESULT = DIV_NUMER; - } - break; - case 2: // 64bit / 64bit - if (DIV_NUMER == long.MinValue && DIV_DENOM == -1) // Overflow - { - DIV_RESULT = DIV_NUMER; - DIVREM_RESULT = 0; - } - else if (DIV_DENOM != 0) - { - DIV_RESULT = DIV_NUMER / DIV_DENOM; - DIVREM_RESULT = DIV_NUMER % DIV_DENOM; - } - else // Division by 0 - { - DIV_RESULT = (DIV_NUMER < 0) ? 1 : -1; - DIVREM_RESULT = DIV_NUMER; - } - break; - } - - - // Console.WriteLine("Divison Mode: " + DivisionMode); - // Console.WriteLine("Numerator : " + DIV_NUMER); - // Console.WriteLine("Demoninator: " + DIV_DENOM); - // Console.WriteLine("Result : " + DIV_RESULT); - // Console.WriteLine("Remainder : " + DIVREM_RESULT); - } - - public void TakeSquareRoot() - { - if (SqrtUse64BitInput) - { - ulong val = SQRT_PARAM; - - uint final = 0; - ulong rem = 0; - uint prod = 0; - - const uint nbits = 32; - const int topShift = 62; - - for (int i = 0; i < nbits; i++) - { - rem = (rem << 2) + ((val >> topShift) & 0x3); - val <<= 2; - final <<= 1; - - prod = (final << 1) + 1; - if (rem >= prod) - { - rem -= prod; - final++; - } - } - - SQRT_RESULT = final; - } - else - { - SQRT_RESULT = (uint)Math.Sqrt((uint)SQRT_PARAM); - } - } - } -} \ No newline at end of file diff --git a/Assets/emulator/Nds9Math.cs.meta b/Assets/emulator/Nds9Math.cs.meta deleted file mode 100644 index d93fc39..0000000 --- a/Assets/emulator/Nds9Math.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 969688026ca7e194dbc2b0acc79a84d9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/NdsAudio.cs b/Assets/emulator/NdsAudio.cs deleted file mode 100644 index 29ba13c..0000000 --- a/Assets/emulator/NdsAudio.cs +++ /dev/null @@ -1,525 +0,0 @@ -using static OptimeGBA.Bits; -using static OptimeGBA.MemoryUtil; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Numerics; -namespace OptimeGBA -{ - public class CustomSample - { - public short[] Data; // In PCM16 - public uint LoopPoint; // In samples - public uint RepeatMode; - - public CustomSample(short[] data, uint loopPoint, uint repeatMode) - { - Data = data; - LoopPoint = loopPoint; - RepeatMode = repeatMode; - } - } - - public class AudioChannelNds - { - // SOUNDxCNT - public uint Volume; - public byte VolumeDiv; - public bool Hold; - public byte Pan; - public byte PulseDuty; - public byte RepeatMode; - public byte Format; - public bool Playing; - - public uint SOUNDSAD; - public uint SOUNDTMR; - public uint SOUNDPNT; - public uint SOUNDLEN; - - public uint SamplePos; - public uint Timer; - - public uint Interval; - public int CurrentValue; - public int AdpcmIndex; - public int AdpcmLoopValue; - public int AdpcmLoopIndex; - public uint AdpcmLoopCurrentData; - public uint CurrentData; - - public bool DebugEnable = true; - public uint DebugAdpcmSaved; - public uint DebugAdpcmRestored; - - public long DebugStartTicks; - } - - public class NdsAudio - { - Nds Nds; - - public NdsAudio(Nds nds) - { - Nds = nds; - - for (uint i = 0; i < 16; i++) - { - Channels[i] = new AudioChannelNds(); - } - - Sample(0); - } - - public AudioChannelNds[] Channels = new AudioChannelNds[16]; - - public const int SampleRate = 32768; - - public bool EnableBlipBufResampling = true; - public BlipBuf BlipBuf = new BlipBuf(32, true, 16); - - public bool Record = false; - public WavWriter WavWriter = new WavWriter(SampleRate); - public WavWriter WavWriterSinc = new WavWriter(SampleRate); - - public int SampleTimer = 0; - - public const uint SampleBufferMax = 256; - public short[] SampleBuffer = new short[SampleBufferMax]; - public uint SampleBufferPos = 0; - - public static sbyte[] IndexTable = { -1, -1, -1, -1, 2, 4, 6, 8 }; - public static short[] AdpcmTable = { - 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x0010, 0x0011, 0x0013, 0x0015, - 0x0017, 0x0019, 0x001C, 0x001F, 0x0022, 0x0025, 0x0029, 0x002D, 0x0032, 0x0037, 0x003C, 0x0042, - 0x0049, 0x0050, 0x0058, 0x0061, 0x006B, 0x0076, 0x0082, 0x008F, 0x009D, 0x00AD, 0x00BE, 0x00D1, - 0x00E6, 0x00FD, 0x0117, 0x0133, 0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE, 0x0220, 0x0256, 0x0292, - 0x02D4, 0x031C, 0x036C, 0x03C3, 0x0424, 0x048E, 0x0502, 0x0583, 0x0610, 0x06AB, 0x0756, 0x0812, - 0x08E0, 0x09C3, 0x0ABD, 0x0BD0, 0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307, 0x14EE, 0x1706, 0x1954, - 0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B, 0x3BB9, 0x41B2, 0x4844, 0x4F7E, - 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF - }; - - // SOUNDCNT - public byte MasterVolume; - public uint LeftOutputFrom; - public uint RightOutputFrom; - public bool Ch1ToMixer; - public bool Ch3ToMixer; - public bool MasterEnable; - - // SOUNDBIAS - public ushort SOUNDBIAS; - - // SNDCAPCNT - byte SNDCAP0CNT; - byte SNDCAP1CNT; - - public byte ReadHwio8(uint addr) - { - byte val = 0; - - switch (addr) - { - case 0x4000500: // SOUNDCNT B0 - val |= (byte)(MasterVolume & 0x7FU); - break; - case 0x4000501: // SOUNDCNT B1 - val |= (byte)((LeftOutputFrom & 0b11) << 0); - val |= (byte)((RightOutputFrom & 0b11) << 2); - if (Ch1ToMixer) val = BitSet(val, 4); - if (Ch3ToMixer) val = BitSet(val, 5); - if (MasterEnable) val = BitSet(val, 7); - break; - - case 0x4000504: - return (byte)(SOUNDBIAS >> 0); - case 0x4000505: - return (byte)(SOUNDBIAS >> 8); - - case 0x4000508: - return SNDCAP0CNT; - case 0x4000509: - return SNDCAP1CNT; - } - - return val; - } - - public void WriteHwio8(uint addr, byte val) - { - switch (addr) - { - case 0x4000500: // SOUNDCNT B0 - MasterVolume = (byte)(val & 0x7FU); - break; - case 0x4000501: // SOUNDCNT B1 - LeftOutputFrom = (byte)((val >> 0) & 0b11); - RightOutputFrom = (byte)((val >> 2) & 0b11); - Ch1ToMixer = BitTest(val, 4); - Ch3ToMixer = BitTest(val, 5); - MasterEnable = BitTest(val, 7); - break; - - case 0x4000504: - SOUNDBIAS &= 0xFF00; - SOUNDBIAS |= (ushort)(val << 0); - break; - case 0x4000505: - SOUNDBIAS &= 0x00FF; - SOUNDBIAS |= (ushort)(val << 8); - break; - - case 0x4000508: - SNDCAP0CNT = val; - break; - case 0x4000509: - SNDCAP1CNT = val; - break; - } - } - - public byte ReadHwio8Channels(uint addr) - { - var c = Channels[(addr >> 4) & 0xF]; - - byte val = 0; - - switch (addr & 0xF) - { - case 0x0: - val |= (byte)(c.Volume & 0x7F); - break; - case 0x1: - val |= c.VolumeDiv; - if (c.Hold) val = BitSet(val, 7); - break; - case 0x2: - val |= c.Pan; - break; - case 0x3: - val |= c.PulseDuty; - val |= (byte)(c.RepeatMode << 3); - val |= (byte)(c.Format << 5); - if (c.Playing) val = BitSet(val, 7); - break; - } - - return val; - } - - public void WriteHwio8Channels(uint addr, byte val) - { - var c = Channels[(addr >> 4) & 0xF]; - - switch (addr & 0xF) - { - case 0x0: - c.Volume = (byte)(val & 0x7F); - break; - case 0x1: - c.VolumeDiv = (byte)(val & 3); - c.Hold = BitTest(val, 7); - break; - case 0x2: - c.Pan = (byte)(val & 0x7F); - break; - case 0x3: - c.PulseDuty = (byte)(val & 7); - c.RepeatMode = (byte)((val >> 3) & 3); - c.Format = (byte)((val >> 5) & 3); - if (!c.Playing && BitTest(val, 7)) - { - StartChannel(c); - } - c.Playing = BitTest(val, 7); - break; - - case 0x4: - case 0x5: - case 0x6: - case 0x7: - Console.WriteLine(Util.Hex(Nds.Cpu7.GetCurrentInstrAddr(), 8)); - // Console.WriteLine(Nds.MemoryControl.SharedRamControl); - - c.SOUNDSAD = SetByteIn(c.SOUNDSAD, val, addr & 3) & 0x7FFFFFC; - - if (c.Playing) - { - StartChannel(c); - } - break; - case 0x8: - case 0x9: - c.SOUNDTMR = SetByteIn(c.SOUNDTMR, val, addr & 1); - c.Interval = 2 * (0x10000 - c.SOUNDTMR); - break; - case 0xA: - case 0xB: - c.SOUNDPNT = SetByteIn(c.SOUNDPNT, val, addr & 1); - break; - case 0xC: - case 0xD: - case 0xE: - case 0xF: - c.SOUNDLEN = SetByteIn(c.SOUNDLEN, val, addr & 3) & 0x3FFFFF; - break; - } - } - - public void StartChannel(AudioChannelNds c) - { - c.SamplePos = 0; - c.Timer = 0; - c.CurrentValue = 0; - - c.DebugStartTicks = Nds.Scheduler.CurrentTicks; - } - - public void Sample(long cyclesLate) - { - long left = 0; - long right = 0; - - for (int i = 0; i < 16; i++) - { - var c = Channels[i]; - - if (c.Playing) - { - c.Timer += 1024; - while (c.Timer >= c.Interval && c.Interval != 0) - { - c.Timer -= c.Interval; - - // Advance sample - switch (c.Format) - { - case 0: // PCM8 - if (c.SamplePos >= (c.SOUNDPNT + c.SOUNDLEN) * 4) - { - switch (c.RepeatMode) - { - case 1: // Infinite - c.SamplePos = c.SOUNDPNT * 4; - break; - case 2: // One-shot - c.Playing = false; - if (!c.Hold) - { - c.CurrentValue = 0; - } - break; - } - } - - if ((c.SamplePos & 3) == 0) - { - c.CurrentData = Nds.Mem7.Read32(c.SOUNDSAD + c.SamplePos); - } - - c.CurrentValue = (short)((byte)c.CurrentData << 8); - c.CurrentData >>= 8; - - c.SamplePos++; - break; - case 1: // PCM16 - if (c.SamplePos >= (c.SOUNDPNT + c.SOUNDLEN) * 2) - { - switch (c.RepeatMode) - { - case 1: // Infinite - c.SamplePos = c.SOUNDPNT * 2; - break; - case 2: // One-shot - c.Playing = false; - if (!c.Hold) - { - c.CurrentValue = 0; - } - break; - } - } - - if ((c.SamplePos & 1) == 0) - { - c.CurrentData = Nds.Mem7.Read32(c.SOUNDSAD + c.SamplePos * 2); - } - - c.CurrentValue = (short)c.CurrentData; - c.CurrentData >>= 16; - - c.SamplePos++; - break; - case 2: // IMA-ADPCM - if ((c.SamplePos & 7) == 0) - { - c.CurrentData = Nds.Mem7.Read32(c.SOUNDSAD + c.SamplePos / 2); - // ADPCM header - if (c.SamplePos == 0) - { - c.CurrentValue = (short)c.CurrentData; - // Console.WriteLine("header set " + x++); - // Console.WriteLine("interval: " + Util.Hex(c.Interval, 8)); - c.AdpcmIndex = Math.Clamp((int)(c.CurrentData >> 16), 0, 88); - } - // Console.WriteLine("addr: " + Util.Hex(c.Source, 8)); - } - if (c.SamplePos > 7) - { - // End of sound, loop or stop - if (c.SamplePos >= (c.SOUNDPNT + c.SOUNDLEN) * 8) - { - switch (c.RepeatMode) - { - case 1: // Infinite - c.SamplePos = c.SOUNDPNT * 8; - c.CurrentValue = c.AdpcmLoopValue; - c.AdpcmIndex = c.AdpcmLoopIndex; - c.CurrentData = c.AdpcmLoopCurrentData; - // Console.WriteLine($"Ch{i}: Loaded at " + c.SampleNum); - - c.DebugAdpcmRestored = c.SamplePos; - break; - case 2: // One-shot - c.Playing = false; - if (!c.Hold) - { - c.CurrentValue = 0; - } - break; - } - } - else - { - byte data = (byte)(c.CurrentData & 0xF); - - short tableVal = AdpcmTable[c.AdpcmIndex]; - int diff = tableVal / 8; - if ((data & 1) != 0) diff += tableVal / 4; - if ((data & 2) != 0) diff += tableVal / 2; - if ((data & 4) != 0) diff += tableVal / 1; - - if ((data & 8) == 8) - { - c.CurrentValue = Math.Max((int)c.CurrentValue - diff, -0x7FFF); - } - else - { - c.CurrentValue = Math.Min((int)c.CurrentValue + diff, 0x7FFF); - } - c.AdpcmIndex = Math.Clamp(c.AdpcmIndex + IndexTable[data & 7], 0, 88); - - c.CurrentData >>= 4; - - // Save value and ADPCM table index for loop - if (c.SamplePos == c.SOUNDPNT * 8) - { - c.AdpcmLoopValue = c.CurrentValue; - c.AdpcmLoopIndex = c.AdpcmIndex; - c.AdpcmLoopCurrentData = c.CurrentData; - - c.DebugAdpcmSaved = c.SamplePos; - // Console.WriteLine($"Ch{i}: Saved at " + c.SampleNum); - } - } - } - c.SamplePos++; - break; - case 3: // Pulse / Noise - if (((c.SamplePos ^ 7) & 7) <= c.PulseDuty) - { - c.CurrentValue = -0x7FFF; - } - else - { - c.CurrentValue = 0x7FFF; - } - c.SamplePos++; - break; - } - - if (EnableBlipBufResampling) - { - long timeTicks = Nds.Scheduler.CurrentTicks - cyclesLate + 1024 - (c.Timer % 1024); - double timeSec = (double)timeTicks / 33513982D; - double timeSample = (double)timeTicks / (33513982D / (double)SampleRate); - - if (c.DebugEnable) - { - uint effectiveVol = c.Volume; - if (effectiveVol == 127) effectiveVol++; - long leftCh = ((((long)c.CurrentValue * (16 >> c.VolumeDiv)) * effectiveVol) * (127 - c.Pan)) >> 10; - long rightCh = ((((long)c.CurrentValue * (16 >> c.VolumeDiv)) * effectiveVol) * c.Pan) >> 10; - - BlipBuf.SetValue(i, timeSample, leftCh, rightCh); - } - else - { - BlipBuf.SetValue(i, timeSample, 0, 0); - } - } - } - - if (c.DebugEnable) - { - uint effectiveVol = c.Volume; - if (effectiveVol == 127) effectiveVol++; - left += ((((long)c.CurrentValue * (16 >> c.VolumeDiv)) * effectiveVol) * (127 - c.Pan)) >> 10; - right += ((((long)c.CurrentValue * (16 >> c.VolumeDiv)) * effectiveVol) * c.Pan) >> 10; - } - } - } - - // Decimate samples to 32768 hz - // Since 33513982 hz / 1024 ≅ 32728.498 hz - SampleTimer += SampleRate * 1024; - while (SampleTimer >= 33513982) - { - SampleTimer -= 33513982; - - BlipBuf.ReadOutSample(); - - // 28 bits now, after mixing all channels - // add master volume to get 35 bits - // add - // strip 19 to get 16 bits for our short output - uint effectiveMasterVol = MasterVolume; - if (effectiveMasterVol == 127) effectiveMasterVol++; - - short leftFinalSinc = (short)(((long)BlipBuf.CurrentValL * effectiveMasterVol) >> 16); - short rightFinalSinc = (short)(((long)BlipBuf.CurrentValR * effectiveMasterVol) >> 16); - - short leftFinal = (short)((left * effectiveMasterVol) >> 16); - short rightFinal = (short)((right * effectiveMasterVol) >> 16); - - if (EnableBlipBufResampling) - { - SampleBuffer[SampleBufferPos++] = leftFinalSinc; - SampleBuffer[SampleBufferPos++] = rightFinalSinc; - } - else - { - SampleBuffer[SampleBufferPos++] = leftFinal; - SampleBuffer[SampleBufferPos++] = rightFinal; - } - - if (Record) - { - WavWriterSinc.AddSample(leftFinalSinc, rightFinalSinc); - WavWriter.AddSample(leftFinal, rightFinal); - } - - if (SampleBufferPos >= SampleBufferMax) - { - SampleBufferPos = 0; - - Nds.Provider.AudioCallback(SampleBuffer); - } - } - - Nds.Scheduler.AddEventRelative(SchedulerId.ApuSample, 1024 - cyclesLate, Sample); - } - } -} \ No newline at end of file diff --git a/Assets/emulator/NdsAudio.cs.meta b/Assets/emulator/NdsAudio.cs.meta deleted file mode 100644 index 78799d2..0000000 --- a/Assets/emulator/NdsAudio.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: aac09fde41176a14b888ed3e2d5d4676 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/PipeStream.cs b/Assets/emulator/PipeStream.cs new file mode 100644 index 0000000..1ff120d --- /dev/null +++ b/Assets/emulator/PipeStream.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.IO; + +public class PipeStream : Stream +{ + private readonly Queue _buffer = new Queue(); + private long _maxBufferLength = 8192*4; + + public long MaxBufferLength + { + get { return _maxBufferLength; } + set { _maxBufferLength = value; } + } + + public new void Dispose() + { + _buffer.Clear(); + } + + public override void Flush() + { + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (offset != 0) + throw new NotImplementedException("Offsets with value of non-zero are not supported"); + if (buffer == null) + throw new ArgumentException("Buffer is null"); + if (offset + count > buffer.Length) + throw new ArgumentException("The sum of offset and count is greater than the buffer length. "); + if (offset < 0 || count < 0) + throw new ArgumentOutOfRangeException("offset", "offset or count is negative."); + + if (count == 0) + return 0; + + int readLength = 0; + + lock (_buffer) + { + // fill the read buffer + for (; readLength < count && Length > 0; readLength++) + { + buffer[readLength] = _buffer.Dequeue(); + } + } + + return readLength; + } + + private bool ReadAvailable(int count) + { + return (Length >= count); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (buffer == null) + throw new ArgumentException("Buffer is null"); + if (offset + count > buffer.Length) + throw new ArgumentException("The sum of offset and count is greater than the buffer length. "); + if (offset < 0 || count < 0) + throw new ArgumentOutOfRangeException("offset", "offset or count is negative."); + if (count == 0) + return; + + lock (_buffer) + { + while (Length >= _maxBufferLength) + return; + + // queue up the buffer data + foreach (byte b in buffer) + { + _buffer.Enqueue(b); + } + } + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override long Length + { + get { return _buffer.Count; } + } + + public override long Position + { + get { return 0; } + set { throw new NotImplementedException(); } + } +} diff --git a/Assets/emulator/PipeStream.cs.meta b/Assets/emulator/PipeStream.cs.meta new file mode 100644 index 0000000..69784cd --- /dev/null +++ b/Assets/emulator/PipeStream.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 177ba151dcfeb3046a3b7a0db12fec0b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/emulator/Ppu.cs.meta b/Assets/emulator/Ppu.cs.meta index 625f686..acfc878 100644 --- a/Assets/emulator/Ppu.cs.meta +++ b/Assets/emulator/Ppu.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 01c48e13c41f22a45ab867df39d272b6 +guid: 11d62ad7b3245cc4bbce8635df978afc MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/PpuGba.cs b/Assets/emulator/PpuGba.cs index 19b732c..655531e 100644 --- a/Assets/emulator/PpuGba.cs +++ b/Assets/emulator/PpuGba.cs @@ -16,7 +16,7 @@ namespace OptimeGBA { Gba = gba; Scheduler = scheduler; - Renderer = new PpuRenderer(null, 240, 160); + Renderer = new PpuRenderer(240, 160); Scheduler.AddEventRelative(SchedulerId.Ppu, 960, EndDrawingToHblank); diff --git a/Assets/emulator/PpuGba.cs.meta b/Assets/emulator/PpuGba.cs.meta index 7a8e375..dab984f 100644 --- a/Assets/emulator/PpuGba.cs.meta +++ b/Assets/emulator/PpuGba.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 03dc9232a0ce9c44ea7bda048c1ff906 +guid: ebff50650dda02d42a9df8547d689656 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/PpuNds.cs b/Assets/emulator/PpuNds.cs deleted file mode 100644 index 8254dfd..0000000 --- a/Assets/emulator/PpuNds.cs +++ /dev/null @@ -1,925 +0,0 @@ -using static OptimeGBA.Bits; -using static OptimeGBA.MemoryUtil; -using System.Runtime.CompilerServices; -using System; - -namespace OptimeGBA -{ - public sealed unsafe class PpuNds - { - Nds Nds; - Scheduler Scheduler; - - public PpuRenderer[] Renderers; - - public PpuNds(Nds nds, Scheduler scheduler) - { - Nds = nds; - Scheduler = scheduler; - Renderers = new PpuRenderer[] { - new PpuRenderer(nds, 256, 192), - new PpuRenderer(nds, 256, 192) - }; - - Scheduler.AddEventRelative(SchedulerId.Ppu, 1536, EndDrawingToHblank); - } - - // Raw VRAM Blocks - public byte[] VramA = new byte[131072]; - public byte[] VramB = new byte[131072]; - public byte[] VramC = new byte[131072]; - public byte[] VramD = new byte[131072]; - public byte[] VramE = new byte[65536]; - public byte[] VramF = new byte[16384]; - public byte[] VramG = new byte[16384]; - public byte[] VramH = new byte[32768]; - public byte[] VramI = new byte[16384]; - - // Built arrays (Passed to PpuRenderer for rendering) - public byte[] VramLcdc = new byte[671744]; - public byte[] VramBgA = new byte[524288]; - public byte[] VramObjA = new byte[262144]; - public byte[] VramBgB = new byte[131072]; - public byte[] VramObjB = new byte[131072]; - - public bool DebugDisableVramUpdates; - - public byte ReadVram8Arm9(uint addr) - { - switch (addr & 0xFFE00000) - { - case 0x06000000: // Engine A BG VRAM - return ReadVram8Arm9BgA(addr); - case 0x06200000: // Engine B BG VRAM - return ReadVram8Arm9BgB(addr); - case 0x06400000: // Engine A OBJ VRAM - return ReadVram8Arm9ObjA(addr); - case 0x06600000: // Engine B OBJ VRAM - return ReadVram8Arm9ObjB(addr); - case 0x06800000: // LCDC VRAM - return ReadVram8Arm9Lcdc(addr); - } - - return 0; - } - - public byte ReadVram8Arm9BgA(uint addr) - { - addr &= 0x1FFFFF; - byte val = 0; - uint offs = Nds.MemoryControl.GetOffset(0) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(0, 1)) - { - val |= VramA[addr & 0x1FFFF]; - } - offs = Nds.MemoryControl.GetOffset(1) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(1, 1)) - { - val |= VramB[addr & 0x1FFFF]; - } - offs = Nds.MemoryControl.GetOffset(2) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(2, 1)) - { - val |= VramC[addr & 0x1FFFF]; - } - offs = Nds.MemoryControl.GetOffset(3) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(3, 1)) - { - val |= VramD[addr & 0x1FFFF]; - } - if (addr >= 0 && addr < 0x10000 && Nds.MemoryControl.VramEnabledAndSet(4, 1)) - { - val |= VramE[addr & 0xFFFF]; - } - offs = (Nds.MemoryControl.GetOffset(5) & 1) * 0x4000 + ((Nds.MemoryControl.GetOffset(5) >> 1) & 1) * 0x10000; - if (addr >= offs && addr < 0x4000 + offs && Nds.MemoryControl.VramEnabledAndSet(5, 1)) - { - val |= VramF[addr & 0x3FFF]; - } - offs = (Nds.MemoryControl.GetOffset(6) & 1) * 0x4000 + ((Nds.MemoryControl.GetOffset(6) >> 1) & 1) * 0x10000; - if (addr >= offs && addr < 0x4000 + offs && Nds.MemoryControl.VramEnabledAndSet(6, 1)) - { - val |= VramG[addr & 0x3FFF]; - } - return val; - } - - public byte ReadVram8Arm9BgB(uint addr) - { - byte val = 0; - addr &= 0x1FFFFF; - if (addr < 0x20000 && Nds.MemoryControl.VramEnabledAndSet(2, 4)) - { - val |= VramC[addr & 0x1FFFF]; - } - if (addr < 0x8000 && Nds.MemoryControl.VramEnabledAndSet(7, 1)) - { - val |= VramH[addr & 0x7FFF]; - } - if (addr >= 0x8000 && addr < 0xC000 && Nds.MemoryControl.VramEnabledAndSet(8, 1)) - { - val |= VramI[addr & 0x3FFF]; - } - return val; - } - - public byte ReadVram8Arm9ObjA(uint addr) - { - byte val = 0; - addr &= 0x1FFFFF; - uint offs = (Nds.MemoryControl.GetOffset(0) & 1) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(0, 2)) - { - val |= VramA[addr & 0x1FFFF]; - } - offs = (Nds.MemoryControl.GetOffset(1) & 1) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(1, 2)) - { - val |= VramB[addr & 0x1FFFF]; - } - if (addr >= 0 && addr < 0x10000 && Nds.MemoryControl.VramEnabledAndSet(4, 2)) - { - val |= VramE[addr & 0xFFFF]; - } - offs = (Nds.MemoryControl.GetOffset(5) & 1) * 0x4000 + ((Nds.MemoryControl.GetOffset(5) >> 1) & 1) * 0x10000; - if (addr >= offs && addr < 0x4000 + offs && Nds.MemoryControl.VramEnabledAndSet(5, 2)) - { - val |= VramF[addr & 0x3FFF]; - } - offs = (Nds.MemoryControl.GetOffset(6) & 1) * 0x4000 + ((Nds.MemoryControl.GetOffset(6) >> 1) & 1) * 0x10000; - if (addr >= offs && addr < 0x4000 + offs && Nds.MemoryControl.VramEnabledAndSet(6, 2)) - { - val |= VramG[addr & 0x3FFF]; - } - return val; - } - - public byte ReadVram8Arm9ObjB(uint addr) - { - byte val = 0; - addr &= 0x1FFFFF; - if (addr < 0x20000 && Nds.MemoryControl.VramEnabledAndSet(3, 4)) - { - val |= VramD[addr & 0x1FFFF]; - } - if (addr < 0x4000 && Nds.MemoryControl.VramEnabledAndSet(8, 2)) - { - val |= VramI[addr & 0x3FFF]; - } - return val; - } - - public byte ReadVram8Arm9Lcdc(uint addr) - { - switch (addr & 0xE0000) - { - case 0x00000: // A - if (Nds.MemoryControl.VramEnabledAndSet(0, 0)) - return VramA[addr & 0x1FFFF]; - return 0; - case 0x20000: // B - if (Nds.MemoryControl.VramEnabledAndSet(1, 0)) - return VramB[addr & 0x1FFFF]; - return 0; - case 0x40000: // C - if (Nds.MemoryControl.VramEnabledAndSet(2, 0)) - return VramC[addr & 0x1FFFF]; - return 0; - case 0x60000: // D - if (Nds.MemoryControl.VramEnabledAndSet(3, 0)) - return VramD[addr & 0x1FFFF]; - return 0; - case 0x80000: // E, F, G, H - switch (addr & 0xFF000) - { - case 0x00000: - if (Nds.MemoryControl.VramEnabledAndSet(4, 0)) - return VramE[addr & 0xFFFF]; - return 0; - case 0x90000: // F - if (Nds.MemoryControl.VramEnabledAndSet(5, 0)) - return VramF[addr & 0x3FFF]; - return 0; - case 0x94000: // G - if (Nds.MemoryControl.VramEnabledAndSet(6, 0)) - return VramG[addr & 0x3FFF]; - return 0; - case 0x98000: // H - if (Nds.MemoryControl.VramEnabledAndSet(7, 0)) - return VramH[addr & 0x7FFF]; - return 0; - } - break; - case 0x8A000: // I - if (Nds.MemoryControl.VramEnabledAndSet(8, 0)) - return VramI[addr & 0x3FFF]; - return 0; - } - - return 0; - } - - public void WriteVram8Arm9(uint addr, byte val) - { - uint offs; - byte readVal = 0; - switch (addr & 0xFFE00000) - { - case 0x06000000: // Engine A BG VRAM - addr &= 0x1FFFFF; - offs = Nds.MemoryControl.GetOffset(0) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(0, 1)) - { - readVal |= val; VramA[addr & 0x1FFFF] = val; - } - offs = Nds.MemoryControl.GetOffset(1) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(1, 1)) - { - readVal |= val; VramB[addr & 0x1FFFF] = val; - } - offs = Nds.MemoryControl.GetOffset(2) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(2, 1)) - { - readVal |= val; VramC[addr & 0x1FFFF] = val; - } - offs = Nds.MemoryControl.GetOffset(3) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(3, 1)) - { - readVal |= val; VramD[addr & 0x1FFFF] = val; - } - if (addr >= 0 && addr < 0x10000 && Nds.MemoryControl.VramEnabledAndSet(4, 1)) - { - readVal |= val; VramE[addr & 0xFFFF] = val; - } - offs = (Nds.MemoryControl.GetOffset(5) & 1) * 0x4000 + ((Nds.MemoryControl.GetOffset(5) >> 1) & 1) * 0x10000; - if (addr >= offs && addr < 0x4000 + offs && Nds.MemoryControl.VramEnabledAndSet(5, 1)) - { - readVal |= val; VramF[addr & 0x3FFF] = val; - } - offs = (Nds.MemoryControl.GetOffset(6) & 1) * 0x4000 + ((Nds.MemoryControl.GetOffset(6) >> 1) & 1) * 0x10000; - if (addr >= offs && addr < 0x4000 + offs && Nds.MemoryControl.VramEnabledAndSet(6, 1)) - { - readVal |= val; VramG[addr & 0x3FFF] = val; - } - VramBgA[addr & 0x1FFFFF] = readVal; - break; - case 0x06200000: // Engine B BG VRAM - addr &= 0x1FFFFF; - if (addr < 0x20000 && Nds.MemoryControl.VramEnabledAndSet(2, 4)) - { - readVal |= val; VramC[addr & 0x1FFFF] = val; - } - if (addr < 0x8000 && Nds.MemoryControl.VramEnabledAndSet(7, 1)) - { - readVal |= val; VramH[addr & 0x7FFF] = val; - } - if (addr >= 0x8000 && addr < 0xC000 && Nds.MemoryControl.VramEnabledAndSet(8, 1)) - { - readVal |= val; VramI[addr & 0x3FFF] = val; - } - VramBgB[addr & 0x1FFFF] = readVal; - break; - case 0x06400000: // Engine A OBJ VRAM - addr &= 0x1FFFFF; - offs = (Nds.MemoryControl.GetOffset(0) & 1) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(0, 2)) - { - readVal |= val; VramA[addr & 0x1FFFF] = val; - } - offs = (Nds.MemoryControl.GetOffset(1) & 1) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(1, 2)) - { - readVal |= val; VramB[addr & 0x1FFFF] = val; - } - if (addr >= 0 && addr < 0x10000 && Nds.MemoryControl.VramEnabledAndSet(4, 2)) - { - readVal |= val; VramE[addr & 0xFFFF] = val; - } - offs = (Nds.MemoryControl.GetOffset(5) & 1) * 0x4000 + ((Nds.MemoryControl.GetOffset(5) >> 1) & 1) * 0x10000; - if (addr >= offs && addr < 0x4000 + offs && Nds.MemoryControl.VramEnabledAndSet(5, 2)) - { - readVal |= val; VramF[addr & 0x3FFF] = val; - } - offs = (Nds.MemoryControl.GetOffset(6) & 1) * 0x4000 + ((Nds.MemoryControl.GetOffset(6) >> 1) & 1) * 0x10000; - if (addr >= offs && addr < 0x4000 + offs && Nds.MemoryControl.VramEnabledAndSet(6, 2)) - { - readVal |= val; VramG[addr & 0x3FFF] = val; - } - VramObjA[addr & 0xFFFFF] = readVal; - break; - case 0x06600000: // Engine B OBJ VRAM - addr &= 0x1FFFFF; - if (addr < 0x20000 && Nds.MemoryControl.VramEnabledAndSet(3, 4)) - { - readVal |= val; VramD[addr & 0x1FFFF] = val; - } - if (addr < 0x4000 && Nds.MemoryControl.VramEnabledAndSet(8, 2)) - { - readVal |= val; VramI[addr & 0x3FFF] = val; - } - VramObjB[addr & 0x1FFFF] = readVal; - break; - case 0x06800000: // LCDC VRAM - switch (addr & 0xFFFE0000) - { - case 0x06800000: // A - if (Nds.MemoryControl.VramEnabledAndSet(0, 0)) - readVal |= val; VramA[addr & 0x1FFFF] = val; - break; - case 0x06820000: // B - if (Nds.MemoryControl.VramEnabledAndSet(1, 0)) - readVal |= val; VramB[addr & 0x1FFFF] = val; - break; - case 0x06840000: // C - if (Nds.MemoryControl.VramEnabledAndSet(2, 0)) - readVal |= val; VramC[addr & 0x1FFFF] = val; - break; - case 0x06860000: // D - if (Nds.MemoryControl.VramEnabledAndSet(3, 0)) - readVal |= val; VramD[addr & 0x1FFFF] = val; - break; - case 0x06880000: // E, F, G, H - switch (addr & 0xFFFFF000) - { - case 0x68800000: - if (Nds.MemoryControl.VramEnabledAndSet(4, 0)) - readVal |= val; VramE[addr & 0xFFFF] = val; - break; - case 0x06890000: // F - if (Nds.MemoryControl.VramEnabledAndSet(5, 0)) - readVal |= val; VramF[addr & 0x3FFF] = val; - break; - case 0x06894000: // G - if (Nds.MemoryControl.VramEnabledAndSet(6, 0)) - readVal |= val; VramG[addr & 0x3FFF] = val; - break; - case 0x06898000: // H - if (Nds.MemoryControl.VramEnabledAndSet(7, 0)) - readVal |= val; VramH[addr & 0x7FFF] = val; - break; - } - break; - case 0x068A0000: // I - if (Nds.MemoryControl.VramEnabledAndSet(8, 0)) - readVal |= val; VramI[addr & 0x3FFF] = val; - break; - } - addr &= 0xFFFFF; - if (addr < 671744) - { - VramLcdc[addr] = readVal; - } - break; - } - } - - public byte ReadVram8Arm7(uint addr) - { - uint offs; - byte val = 0; - addr &= 0x1FFFFF; - offs = (Nds.MemoryControl.GetOffset(2) & 1) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(2, 2)) - { - val |= VramC[addr & 0x1FFFF]; - } - offs = (Nds.MemoryControl.GetOffset(3) & 1) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(3, 2)) - { - val |= VramD[addr & 0x1FFFF]; - } - - return val; - } - - public void WriteVram8Arm7(uint addr, byte val) - { - uint offs; - addr &= 0x1FFFFF; - offs = (Nds.MemoryControl.GetOffset(2) & 1) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(2, 2)) - { - VramC[addr & 0x1FFFF] = val; - } - offs = (Nds.MemoryControl.GetOffset(3) & 1) * 0x20000; - if (addr >= offs && addr < 0x20000 + offs && Nds.MemoryControl.VramEnabledAndSet(3, 2)) - { - VramD[addr & 0x1FFFF] = val; - } - } - - public void CompileVram() - { - if (Nds.MemoryControl.VramConfigDirty && !DebugDisableVramUpdates) - { - Nds.MemoryControl.VramConfigDirty = false; - if (Renderers[0].DisplayMode == 2) // LCDC MODE - { - uint index = 0; - VramA.CopyTo(VramLcdc, index); index += 131072; - VramB.CopyTo(VramLcdc, index); index += 131072; - VramC.CopyTo(VramLcdc, index); index += 131072; - VramD.CopyTo(VramLcdc, index); index += 131072; - VramE.CopyTo(VramLcdc, index); index += 65536; - VramF.CopyTo(VramLcdc, index); index += 16384; - VramG.CopyTo(VramLcdc, index); index += 16384; - VramH.CopyTo(VramLcdc, index); index += 32768; - VramI.CopyTo(VramLcdc, index); index += 16384; - } - else - { - Console.WriteLine("VRAM reconfigured, recompiling from scratch"); - for (uint i = 0; i < 524288; i++) - { - VramBgA[i] = ReadVram8Arm9(0x06000000 + i); - } - for (uint i = 0; i < 262144; i++) - { - VramObjA[i] = ReadVram8Arm9(0x06400000 + i); - } - for (uint i = 0; i < 131072; i++) - { - VramBgB[i] = ReadVram8Arm9(0x06200000 + i); - } - for (uint i = 0; i < 131072; i++) - { - VramObjB[i] = ReadVram8Arm9(0x06600000 + i); - } - } - } - } - - public long ScanlineStartCycles; - - public uint DISPCNTAValue; - public uint DISPCNTBValue; - - // DISPSTAT - public bool VCounterMatch7; - public bool VBlankIrqEnable7; - public bool HBlankIrqEnable7; - public bool VCounterIrqEnable7; - public uint VCountSetting7; - public bool VCounterMatch9; - public bool VBlankIrqEnable9; - public bool HBlankIrqEnable9; - public bool VCounterIrqEnable9; - public uint VCountSetting9; - - // State - public uint VCount; - - public long GetScanlineCycles() - { - return Scheduler.CurrentTicks - ScanlineStartCycles; - } - - public byte ReadHwio8Arm9(uint addr) - { - byte val = 0; - switch (addr) - { - case 0x4000000: // DISPCNTA B0 - return (byte)(DISPCNTAValue >> 0); - case 0x4000001: // DISPCNTA B1 - return (byte)(DISPCNTAValue >> 8); - case 0x4000002: // DISPCNTA B2 - return (byte)(DISPCNTAValue >> 16); - case 0x4000003: // DISPCNTA B3 - return (byte)(DISPCNTAValue >> 24); - - case 0x4000004: // DISPSTAT B0 - // Vblank flag is set in scanlines 192-261, not including 262 for some reason - if (VCount >= 192 && VCount <= 261) val = BitSet(val, 0); - // Hblank flag is set at cycle 1606, not cycle 1536 - if (GetScanlineCycles() >= 1606) val = BitSet(val, 1); - if (VCounterMatch9) val = BitSet(val, 2); - if (VBlankIrqEnable9) val = BitSet(val, 3); - if (HBlankIrqEnable9) val = BitSet(val, 4); - if (VCounterIrqEnable9) val = BitSet(val, 5); - val |= (byte)((VCountSetting9 >> 1) & 0x80); - return val; - case 0x4000005: // DISPSTAT B1 - val |= (byte)VCountSetting9; - return val; - - case 0x4000006: // VCOUNT B0 - B1 only exists for Nintendo DS - val |= (byte)VCount; - return val; - case 0x4000007: - val |= (byte)((VCount >> 8) & 1); - return val; - - case 0x4001000: // DISPCNTB B0 - return (byte)(DISPCNTBValue >> 0); - case 0x4001001: // DISPCNTB B1 - return (byte)(DISPCNTBValue >> 8); - case 0x4001002: // DISPCNTB B2 - return (byte)(DISPCNTBValue >> 16); - case 0x4001003: // DISPCNTB B3 - return (byte)(DISPCNTBValue >> 24); - } - - if (addr >= 0x4000000 && addr < 0x4000058) - { - return Renderers[0].ReadHwio8(addr & 0xFF); - } - if (addr >= 0x4001000 && addr < 0x4001058) - { - return Renderers[1].ReadHwio8(addr & 0xFF); - } - - return val; - } - - public void WriteHwio8Arm9(uint addr, byte val) - { - switch (addr) - { - // A lot of these DISPCNT values are shared between A/B. - case 0x4000000: // DISPCNT B0 - // A - Renderers[0].Bg0Is3D = BitTest(val, 3); - - // A+B - Renderers[0].BgMode = BitRange(val, 0, 2); - Renderers[0].ObjCharOneDimensional = BitTest(val, 4); - Renderers[0].BitmapObjShape = BitTest(val, 5); - Renderers[0].BitmapObjMapping = BitTest(val, 6); - Renderers[0].ForcedBlank = BitTest(val, 7); - - Renderers[0].BackgroundSettingsDirty = true; - - DISPCNTAValue &= 0xFFFFFF00; - DISPCNTAValue |= (uint)(val << 0); - - break; - case 0x4000001: // DISPCNT B1 - // A+B - Renderers[0].ScreenDisplayBg[0] = BitTest(val, 8 - 8); - Renderers[0].ScreenDisplayBg[1] = BitTest(val, 9 - 8); - Renderers[0].ScreenDisplayBg[2] = BitTest(val, 10 - 8); - Renderers[0].ScreenDisplayBg[3] = BitTest(val, 11 - 8); - Renderers[0].ScreenDisplayObj = BitTest(val, 12 - 8); - Renderers[0].Window0DisplayFlag = BitTest(val, 13 - 8); - Renderers[0].Window1DisplayFlag = BitTest(val, 14 - 8); - Renderers[0].ObjWindowDisplayFlag = BitTest(val, 15 - 8); - Renderers[0].AnyWindowEnabled = (val & 0b11100000) != 0; - - Renderers[0].BackgroundSettingsDirty = true; - - DISPCNTAValue &= 0xFFFF00FF; - DISPCNTAValue |= (uint)(val << 8); - break; - case 0x4000002: // DISPCNT B2 - // A - Renderers[0].LcdcVramBlock = BitRange(val, 2, 3); - Renderers[0].BitmapObj1DBoundary = BitTest(val, 6); - - // A+B - // var oldDisplayMode = Renderers[0].DisplayMode; - // if (Renderers[0].DisplayMode != oldDisplayMode) VramDirty = true; - Renderers[0].DisplayMode = BitRange(val, 0, 1); - Renderers[0].TileObj1DBoundary = BitRange(val, 4, 5); - Renderers[0].HBlankIntervalFree = BitTest(val, 7); - - Renderers[0].BackgroundSettingsDirty = true; - - DISPCNTAValue &= 0xFF00FFFF; - DISPCNTAValue |= (uint)(val << 16); - break; - case 0x4000003: // DISPCNT B3 - // A - Renderers[0].CharBaseBlockCoarse = BitRange(val, 0, 2); - Renderers[0].MapBaseBlockCoarse = BitRange(val, 3, 5); - - // A+B - Renderers[0].BgExtendedPalettes = BitTest(val, 6); - Renderers[0].ObjExtendedPalettes = BitTest(val, 7); - - DISPCNTAValue &= 0x00FFFFFF; - DISPCNTAValue |= (uint)(val << 24); - break; - - case 0x4000004: // DISPSTAT B0 - VBlankIrqEnable9 = BitTest(val, 3); - HBlankIrqEnable9 = BitTest(val, 4); - VCounterIrqEnable9 = BitTest(val, 5); - - VCountSetting9 &= 0x0FFU; - VCountSetting9 |= (uint)((val & 0x80) << 1); - break; - case 0x4000005: // DISPSTAT B1 - VCountSetting9 &= 0x100U; - VCountSetting9 |= val; - break; - - case 0x4000006: // Vcount - case 0x4000007: - // throw new NotImplementedException("NDS: write to vcount"); - break; - - case 0x4001000: // DISPCNTB B0 - // A+B - Renderers[1].BgMode = BitRange(val, 0, 2); - Renderers[1].ObjCharOneDimensional = BitTest(val, 4); - Renderers[1].BitmapObjShape = BitTest(val, 5); - Renderers[1].BitmapObjMapping = BitTest(val, 6); - Renderers[1].ForcedBlank = BitTest(val, 7); - - Renderers[1].BackgroundSettingsDirty = true; - - DISPCNTBValue &= 0xFFFFFF00; - DISPCNTBValue |= (uint)(val << 0); - - break; - case 0x4001001: // DISPCNTB B1 - // A+B - Renderers[1].ScreenDisplayBg[0] = BitTest(val, 8 - 8); - Renderers[1].ScreenDisplayBg[1] = BitTest(val, 9 - 8); - Renderers[1].ScreenDisplayBg[2] = BitTest(val, 10 - 8); - Renderers[1].ScreenDisplayBg[3] = BitTest(val, 11 - 8); - Renderers[1].ScreenDisplayObj = BitTest(val, 12 - 8); - Renderers[1].Window0DisplayFlag = BitTest(val, 13 - 8); - Renderers[1].Window1DisplayFlag = BitTest(val, 14 - 8); - Renderers[1].ObjWindowDisplayFlag = BitTest(val, 15 - 8); - Renderers[1].AnyWindowEnabled = (val & 0b11100000) != 0; - - Renderers[1].BackgroundSettingsDirty = true; - - DISPCNTBValue &= 0xFFFF00FF; - DISPCNTBValue |= (uint)(val << 8); - break; - case 0x4001002: // DISPCNTB B2 - // A+B - // var oldDisplayModeB = Renderers[1].DisplayMode; - // if (Renderers[1].DisplayMode != oldDisplayModeB) VramDirty = true; - Renderers[1].DisplayMode = BitRange(val, 0, 1); - Renderers[1].TileObj1DBoundary = BitRange(val, 4, 5); - Renderers[1].HBlankIntervalFree = BitTest(val, 7); - - Renderers[1].BackgroundSettingsDirty = true; - - DISPCNTBValue &= 0xFF00FFFF; - DISPCNTBValue |= (uint)(val << 16); - break; - case 0x4001003: // DISPCNTB B3 - // A+B - Renderers[1].BgExtendedPalettes = BitTest(val, 6); - Renderers[1].ObjExtendedPalettes = BitTest(val, 7); - - DISPCNTBValue &= 0x00FFFFFF; - DISPCNTBValue |= (uint)(val << 24); - break; - } - - if (addr >= 0x4000000 && addr < 0x4000058) - { - Renderers[0].WriteHwio8(addr & 0xFF, val); - } - if (addr >= 0x4001000 && addr < 0x4001058) - { - Renderers[1].WriteHwio8(addr & 0xFF, val); - } - } - - public byte ReadHwio8Arm7(uint addr) - { - byte val = 0; - - switch (addr) - { - case 0x4000004: // DISPSTAT B0 - // Vblank flag is set in scanlines 192-261, not including 262 for some reason - if (VCount >= 192 && VCount <= 261) val = BitSet(val, 0); - // Hblank flag is set at cycle 1606, not cycle 1536 - if (GetScanlineCycles() >= 1606) val = BitSet(val, 1); - if (VCounterMatch7) val = BitSet(val, 2); - if (VBlankIrqEnable7) val = BitSet(val, 3); - if (HBlankIrqEnable7) val = BitSet(val, 4); - if (VCounterIrqEnable7) val = BitSet(val, 5); - val |= (byte)((VCountSetting7 >> 1) & 0x80); - return val; - case 0x4000005: // DISPSTAT B1 - val |= (byte)VCountSetting7; - return val; - } - - return 0; - } - - public void WriteHwio8Arm7(uint addr, byte val) - { - switch (addr) - { - case 0x4000004: // DISPSTAT B0 - VBlankIrqEnable7 = BitTest(val, 3); - HBlankIrqEnable7 = BitTest(val, 4); - VCounterIrqEnable7 = BitTest(val, 5); - - VCountSetting7 &= 0x0FFU; - VCountSetting7 |= (uint)((val & 0x80) << 1); - break; - case 0x4000005: // DISPSTAT B1 - VCountSetting7 &= 0x100U; - VCountSetting7 |= val; - break; - } - } - - public byte ReadOam8(uint addr) - { - addr &= 0x7FF; - var id = addr >= 0x400 ? 1 : 0; - addr &= 0x3FF; - return GetByte(Renderers[id].Oam, addr); - } - - public ushort ReadOam16(uint addr) - { - addr &= 0x7FF; - var id = addr >= 0x400 ? 1 : 0; - addr &= 0x3FF; - return GetUshort(Renderers[id].Oam, addr); - } - - public uint ReadOam32(uint addr) - { - addr &= 0x7FF; - var id = addr >= 0x400 ? 1 : 0; - addr &= 0x3FF; - return GetUint(Renderers[id].Oam, addr); - } - - public void WriteOam16(uint addr, ushort val) - { - addr &= 0x7FF; - var id = addr >= 0x400 ? 1 : 0; - addr &= 0x3FF; - SetUshort(Renderers[id].Oam, addr, val); - } - - public void WriteOam32(uint addr, uint val) - { - addr &= 0x7FF; - var id = addr >= 0x400 ? 1 : 0; - addr &= 0x3FF; - SetUint(Renderers[id].Oam, addr, val); - } - - public byte ReadPalettes8(uint addr) - { - addr &= 0x7FF; - var id = addr >= 0x400 ? 1 : 0; - addr &= 0x3FF; - return GetByte(Renderers[id].Palettes, addr); - } - - public ushort ReadPalettes16(uint addr) - { - addr &= 0x7FF; - var id = addr >= 0x400 ? 1 : 0; - addr &= 0x3FF; - return GetUshort(Renderers[id].Palettes, addr); - } - - public uint ReadPalettes32(uint addr) - { - addr &= 0x7FF; - var id = addr >= 0x400 ? 1 : 0; - addr &= 0x3FF; - return GetUint(Renderers[id].Palettes, addr); - } - - public void WritePalettes16(uint addr, ushort val) - { - addr &= 0x7FF; - var id = addr >= 0x400 ? 1 : 0; - addr &= 0x3FF; - if (GetUshort(Renderers[id].Palettes, addr) != val) - { - SetUshort(Renderers[id].Palettes, addr, val); - } - } - - public void WritePalettes32(uint addr, uint val) - { - addr &= 0x7FF; - var id = addr >= 0x400 ? 1 : 0; - addr &= 0x3FF; - if (GetUint(Renderers[id].Palettes, addr) != val) - { - SetUint(Renderers[id].Palettes, addr, val); - } - } - - public void EndDrawingToHblank(long cyclesLate) - { - Scheduler.AddEventRelative(SchedulerId.Ppu, 594 - cyclesLate, EndHblank); - - // if (HBlankIrqEnable) - // { - // Gba.HwControl.FlagInterrupt(InterruptGba.HBlank); - // } - - if (Renderers[0].DisplayMode == 2) // LCDC MODE - { - Renderers[0].RenderScanlineNds(VCount, VramLcdc, VramLcdc); - } - else - { - if (Renderers[0].DebugEnableRendering) Renderers[0].RenderScanlineNds(VCount, VramBgA, VramObjA); - } - if (Renderers[1].DisplayMode == 2) - { - Renderers[1].RenderScanlineNds(VCount, VramLcdc, VramLcdc); - } - else - { - if (Renderers[1].DebugEnableRendering) Renderers[1].RenderScanlineNds(VCount, VramBgB, VramObjB); - } - Renderers[0].IncrementMosaicCounters(); - Renderers[1].IncrementMosaicCounters(); - - Nds.Dma9.Repeat((byte)DmaStartTimingNds9.HBlank); - } - - public void EndVblankToHblank(long cyclesLate) - { - Scheduler.AddEventRelative(SchedulerId.Ppu, 594 - cyclesLate, EndHblank); - - // if (HBlankIrqEnable) - // { - // Nds.HwControl.FlagInterrupt(InterruptGba.HBlank); - // } - } - - public void EndHblank(long cyclesLate) - { - ScanlineStartCycles = Scheduler.CurrentTicks; - - if (VCount != 262) - { - VCount++; - - if (VCount > 191) - { - Scheduler.AddEventRelative(SchedulerId.Ppu, 1536 - cyclesLate, EndVblankToHblank); - - if (VCount == 192) - { - // Nds.Dma.RepeatVblank(); - - if (VBlankIrqEnable7) - { - Nds.HwControl7.FlagInterrupt((uint)InterruptNds.VBlank); - } - if (VBlankIrqEnable9) - { - Nds.HwControl9.FlagInterrupt((uint)InterruptNds.VBlank); - } - - Renderers[0].RunVblankOperations(); - Renderers[1].RunVblankOperations(); - - Renderers[0].TotalFrames++; - if (Renderers[0].DebugEnableRendering) Renderers[0].SwapBuffers(); - if (Renderers[1].DebugEnableRendering) Renderers[1].SwapBuffers(); - - Renderers[0].RenderingDone = true; - } - } - else - { - Scheduler.AddEventRelative(SchedulerId.Ppu, 1536 - cyclesLate, EndDrawingToHblank); - } - } - else - { - VCount = 0; - Scheduler.AddEventRelative(SchedulerId.Ppu, 1536 - cyclesLate, EndDrawingToHblank); - - // CompileVram(); - - // Pre-render sprites for line zero - fixed (byte* vramObjA = VramObjA, vramObjB = VramObjB) - { - if (Renderers[0].DebugEnableObj && Renderers[0].ScreenDisplayObj) Renderers[0].RenderObjs(0, vramObjA); - if (Renderers[1].DebugEnableObj && Renderers[1].ScreenDisplayObj) Renderers[1].RenderObjs(0, vramObjB); - } - } - - VCounterMatch7 = VCount == VCountSetting7; - VCounterMatch9 = VCount == VCountSetting9; - - if (VCounterMatch7 && VCounterIrqEnable7) - { - Nds.HwControl7.FlagInterrupt((uint)InterruptNds.VCounterMatch); - } - if (VCounterMatch9 && VCounterIrqEnable9) - { - Nds.HwControl9.FlagInterrupt((uint)InterruptNds.VCounterMatch); - } - } - } -} diff --git a/Assets/emulator/PpuNds.cs.meta b/Assets/emulator/PpuNds.cs.meta deleted file mode 100644 index 65452d8..0000000 --- a/Assets/emulator/PpuNds.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 94cef7d2d800ba548a03c0fb676340ec -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/PpuNds3D.cs b/Assets/emulator/PpuNds3D.cs deleted file mode 100644 index 00189a7..0000000 --- a/Assets/emulator/PpuNds3D.cs +++ /dev/null @@ -1,1016 +0,0 @@ -using System; -using static OptimeGBA.Bits; -using static OptimeGBA.CoreUtil; -using static Util; -using System.Runtime.CompilerServices; -using System.Diagnostics; - -namespace OptimeGBA -{ - public struct Command - { - public byte Cmd; - public uint Param; - - public Command(byte cmd, uint param) - { - Cmd = cmd; - Param = param; - } - } - - public enum PrimitiveType - { - Tris, - Quads, - TriStrips, - QuadStrips - } - - public unsafe struct Matrix - { - public fixed int Data[16]; - - public static Matrix GetIdentity() - { - var m = new Matrix(); - - m.Data[0] = 0x00001000; - m.Data[5] = 0x00001000; - m.Data[10] = 0x00001000; - m.Data[15] = 0x00001000; - - return m; - } - - public Matrix Multiply(Matrix a) - { - var m = new Matrix(); - - for (int i = 0; i < 16; i++) - { - long sum = 0; - - int ai = i & ~3; // Matrix A row - int bi = i & 3; // Matrix B column - - for (int j = 0; j < 4; j++) - { - sum += (long)a.Data[ai] * Data[bi]; - ai++; - bi += 4; - } - - // Trim multiplied fixed point digits off - m.Data[i] = (int)(sum >> 12); - } - - return m; - } - - public Vector Multiply(Vector a) - { - var v = new Vector(); - - for (int i = 0; i < 4; i++) - { - long sum = 0; - - for (int j = 0; j < 4; j++) - { - sum += (long)Data[j * 4 + i] * a.Data[j]; - } - - // Trim multiplied fixed point digits off - v.Data[i] = (int)(sum >> 12); - } - - return v; - } - - public void Print(string s) - { - PpuNds3D.Debug(s); - PpuNds3D.Debug($"{HexN((uint)Data[0x0], 8)} {HexN((uint)Data[0x1], 8)} {HexN((uint)Data[0x2], 8)} {HexN((uint)Data[0x3], 8)}"); - PpuNds3D.Debug($"{HexN((uint)Data[0x4], 8)} {HexN((uint)Data[0x5], 8)} {HexN((uint)Data[0x6], 8)} {HexN((uint)Data[0x7], 8)}"); - PpuNds3D.Debug($"{HexN((uint)Data[0x8], 8)} {HexN((uint)Data[0x9], 8)} {HexN((uint)Data[0xA], 8)} {HexN((uint)Data[0xB], 8)}"); - PpuNds3D.Debug($"{HexN((uint)Data[0xC], 8)} {HexN((uint)Data[0xD], 8)} {HexN((uint)Data[0xE], 8)} {HexN((uint)Data[0xF], 8)}"); - } - } - - public unsafe struct Vector - { - public fixed int Data[4]; - - public void Print(string s) - { - PpuNds3D.Debug(s); - PpuNds3D.Debug($"{HexN((uint)Data[0x0], 8)} {HexN((uint)Data[0x1], 8)} {HexN((uint)Data[0x2], 8)} {HexN((uint)Data[0x3], 8)}"); - } - } - - public unsafe struct Vertex - { - public Vector Pos; - public fixed byte Color[3]; - } - - public class MatrixStack - { - public Matrix[] Stack; - public Matrix Current; - - public sbyte Sp; - public sbyte SpMask; - - public MatrixStack(uint size, sbyte spMask) - { - Stack = new Matrix[size]; - SpMask = spMask; - } - - public void Push() - { - // Debug("Matrix push"); - if ((Sp & 31) != 31) - { - Stack[Sp & 31] = Current; - } - Sp++; - Sp &= SpMask; - } - - public void Pop(sbyte offset) - { - // Debug("Matrix pop"); - Sp -= offset; - Sp &= SpMask; - if ((Sp & 31) != 31) - { - Current = Stack[Sp & 31]; - } - } - - public void Store(byte addr) - { - Stack[addr] = Current; - } - - public void Restore(byte addr) - { - Current = Stack[addr]; - } - } - - public enum MatrixMode - { - Projection, - Position, - PositionDirection, - Texture - } - - public sealed unsafe class PpuNds3D - { - Nds Nds; - Scheduler Scheduler; - - public PpuNds3D(Nds nds, Scheduler scheduler) - { - Nds = nds; - Scheduler = scheduler; - } - - public static readonly byte[] CommandParamLengths = new byte[256] { - /* 0x00 No operation */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x10 Matrix ops */ 1, 0, 1, 1, 1, 0, 16, 12, 16, 12, 9, 3, 3, 0, 0, 0, - /* 0x20 Vertex data */ 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, - /* 0x30 Lighting */ 1, 1, 1, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x40 Begin/end vertex list */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x50 Swap buffers */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x60 Set viewport */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x70 Tests */ 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - - - // Screen - public ushort[] Screen = new ushort[256 * 192]; - - // GXSTAT - public byte CommandFifoIrqMode; - - // GXFIFO - public CircularBuffer PackedCommandQueue = new CircularBuffer(4, 0); - public int PackedParamsQueued = 0; - public CircularBuffer CommandFifo = new CircularBuffer(256, new Command()); - - // GPU State - public MatrixMode MatrixMode; - public MatrixStack ProjectionStack = new MatrixStack(1, 0); - public MatrixStack PositionStack = new MatrixStack(31, 63); - public MatrixStack DirectionStack = new MatrixStack(31, 63); - public MatrixStack TextureStack = new MatrixStack(1, 0); - public Matrix ClipMatrix; - // public bool ClipMatrixDirty; // TODO - reimplement this when I need more speed - - public byte[] Viewport1 = new byte[2]; - public byte[] Viewport2 = new byte[2]; - - // Debug State - public Matrix DebugProjectionMatrix; - public Matrix DebugPositionMatrix; - public Matrix DebugDirectionMatrix; - - - - - public Matrix DebugTextureMatrix; - - public PrimitiveType PrimitiveType; - public short[] VertexCoords = new short[3]; - public byte[] VertexColor = new byte[3]; - public CircularBuffer VertexQueueFront = new CircularBuffer(6144, new Vertex()); - public CircularBuffer VertexQueueBack = new CircularBuffer(6144, new Vertex()); - - public uint ReadHwio32(uint addr) - { - uint val = 0; - - switch (addr) - { - case 0x4000600: // GXSTAT - val |= 0b10; // always true boxtest - - val |= (uint)(PositionStack.Sp & 0b11111) << 8; - val |= (uint)(ProjectionStack.Sp & 0b1) << 13; - - val |= CommandFifo.Entries << 16; - if (CommandFifo.Entries == 256) val = BitSet(val, 24); - if (CommandFifo.Entries < 128) val = BitSet(val, 25); - if (CommandFifo.Entries == 0) val = BitSet(val, 26); - if (CommandFifo.Entries > 0) val = BitSet(val, 27); - val |= (uint)CommandFifoIrqMode << 30; - break; - } - - return val; - } - - public void WriteHwio32(uint addr, uint val) - { - if (addr >= 0x4000440 && addr < 0x4000600) - { - Debug2("3D: MMIO insert cmd " + Hex((byte)(addr >> 2), 2) + " param " + Hex(val, 8)); - - QueueCommand((byte)(addr >> 2), val); - // Debug("3D: Port command send"); - } - - // GXFIFO - if (addr >= 0x4000400 && addr < 0x4000440) - { - // QueueCommand(0); - // TODO: GXFIFO commands - // Console.WriteLine("GXFIFO command send"); - if (PackedCommandQueue.Entries == 0) - { - // Console.WriteLine(CommandFifo.Entries); - for (int i = 0; i < 4; i++) - { - byte cmd = (byte)val; - - if (cmd != 0) - { - if (cmd > 0x72) - { - throw new Exception("3D: GXFIFO insert invalid cmd " + Hex(cmd, 2) + " from addr " + Hex(addr, 8)); - } - - Debug2("3D: GXFIFO insert " + Hex(cmd, 2) + " from addr " + Hex(addr, 8)); - if (CommandParamLengths[cmd] != 0) - { - PackedCommandQueue.Insert(cmd); - } - else - { - // if no params just queue it up - QueueCommand(cmd, 0); - } - } - - val >>= 8; - } - } - else - { - // Console.WriteLine("quued"); - byte cmd = PackedCommandQueue.Peek(0); - QueueCommand(cmd, val); - - PackedParamsQueued++; - - Debug2("3D: GXFIFO take param cmd " + Hex(cmd, 2) + " param " + Hex(val, 8) + " remaining " + (CommandParamLengths[cmd] - PackedParamsQueued) + " from addr " + Hex(addr, 8)); - - if (PackedParamsQueued >= CommandParamLengths[cmd]) - { - PackedParamsQueued = 0; - - PackedCommandQueue.Pop(); - - Debug("execu"); - } - } - return; - } - - switch (addr) - { - case 0x4000600: - CommandFifoIrqMode = (byte)((val >> 30) & 0b11); - return; - } - } - - public void QueueCommand(byte cmd, uint val) - { - if (!CommandFifo.Insert(new Command(cmd, val))) - { - Console.Error.WriteLine("3D: GXFIFO overflow"); - } - - CheckCommands(); - } - - public void RunCommand(Command cmd) - { - Debug2("3D CMD: " + Hex(cmd.Cmd, 2) + " take " + CommandParamLengths[cmd.Cmd] + " params " + "queue " + CommandFifo.Entries); - - switch (cmd.Cmd) - { - case 0x10: // Set Matrix Mode - PopCommand(); - MatrixMode = (MatrixMode)(cmd.Param & 0b11); - Debug("Set Matrix Mode: " + MatrixMode); - break; - case 0x11: // Push Current Matrix - Debug("Push Current Matrix"); - PopCommand(); - switch (MatrixMode) - { - case MatrixMode.Projection: - // ProjectionStack.Current.Print("Push Projection"); - ProjectionStack.Push(); - break; - case MatrixMode.Position: - case MatrixMode.PositionDirection: - // PositionStack.Current.Print("Push PositionDirection"); - PositionStack.Push(); - DirectionStack.Push(); - break; - case MatrixMode.Texture: - TextureStack.Push(); - break; - } - break; - case 0x12: // Pop Current Matrix - Debug("Pop Current Matrix"); - PopCommand(); - switch (MatrixMode) - { - case MatrixMode.Projection: - ProjectionStack.Pop(SignExtend8((byte)cmd.Param, 5)); - break; - case MatrixMode.Position: - case MatrixMode.PositionDirection: - // PositionStack.Current.Print("Pre-pop position matrix"); - PositionStack.Pop(SignExtend8((byte)cmd.Param, 5)); - DirectionStack.Pop(SignExtend8((byte)cmd.Param, 5)); - break; - case MatrixMode.Texture: - TextureStack.Pop(SignExtend8((byte)cmd.Param, 5)); - break; - } - break; - case 0x13: // Store Current Matrix - PopCommand(); - switch (MatrixMode) - { - case MatrixMode.Projection: - ProjectionStack.Store((byte)(cmd.Param & 0b11111)); - break; - case MatrixMode.Position: - case MatrixMode.PositionDirection: - PositionStack.Store((byte)(cmd.Param & 0b11111)); - DirectionStack.Store((byte)(cmd.Param & 0b11111)); - break; - case MatrixMode.Texture: - TextureStack.Store((byte)(cmd.Param & 0b11111)); - break; - } - break; - case 0x14: // Restore Current Matrix - PopCommand(); - switch (MatrixMode) - { - case MatrixMode.Projection: - ProjectionStack.Restore((byte)(cmd.Param & 0b11111)); - break; - case MatrixMode.Position: - case MatrixMode.PositionDirection: - PositionStack.Restore((byte)(cmd.Param & 0b11111)); - DirectionStack.Restore((byte)(cmd.Param & 0b11111)); - break; - case MatrixMode.Texture: - TextureStack.Restore((byte)(cmd.Param & 0b11111)); - break; - } - break; - case 0x15: // Load Identity Matrix - Debug("Load Identity Matrix"); - PopCommand(); - switch (MatrixMode) - { - case MatrixMode.Projection: - ProjectionStack.Current = Matrix.GetIdentity(); - break; - case MatrixMode.Position: - PositionStack.Current = Matrix.GetIdentity(); - break; - case MatrixMode.PositionDirection: - PositionStack.Current = Matrix.GetIdentity(); - DirectionStack.Current = Matrix.GetIdentity(); - break; - case MatrixMode.Texture: - TextureStack.Current = Matrix.GetIdentity(); - break; - } - break; - case 0x16: // Load 4x4 Matrix to Current Matrix - { - Matrix m = new Matrix(); - - for (int i = 0; i < 16; i++) - { - m.Data[i] = (int)PopCommand().Param; - } - - LoadCurrentMatrix(ref m); - } - break; - case 0x17: // Load 4x3 Matrix to Current Matrix - { - Matrix m = Matrix.GetIdentity(); - - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 3; j++) - { - m.Data[i * 4 + j] = (int)PopCommand().Param; - } - } - - LoadCurrentMatrix(ref m); - } - break; - case 0x18: // Multiply Current Matrix by 4x4 Matrix - Debug("Multiply Current Matrix by 4x4 Matrix"); - { - Matrix m = new Matrix(); - - for (int i = 0; i < 16; i++) - { - m.Data[i] = (int)PopCommand().Param; - } - - MultiplyCurrentMatrixBy(ref m); - } - break; - case 0x19: // Multiply Current Matrix by 4x3 Matrix - Debug("Multiply Current Matrix by 4x3 Matrix"); - { - Matrix m = Matrix.GetIdentity(); - - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 3; j++) - { - m.Data[i * 4 + j] = (int)PopCommand().Param; - } - } - - MultiplyCurrentMatrixBy(ref m); - } - break; - case 0x1A: // Multiply Current Matrix by 3x3 Matrix - Debug("Multiply Current Matrix by 3x3 Matrix"); - { - Matrix m = Matrix.GetIdentity(); - - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - { - m.Data[i * 4 + j] = (int)PopCommand().Param; - } - } - - MultiplyCurrentMatrixBy(ref m); - } - break; - case 0x1B: // Multiply Current Matrix by Scale Matrix - Debug("Multiply Current Matrix by Scale Matrix"); - { - Matrix m = Matrix.GetIdentity(); - - m.Data[0] = (int)PopCommand().Param; - m.Data[5] = (int)PopCommand().Param; - m.Data[10] = (int)PopCommand().Param; - - switch (MatrixMode) - { - case MatrixMode.Projection: - ProjectionStack.Current = ProjectionStack.Current.Multiply(m); - break; - case MatrixMode.Position: - case MatrixMode.PositionDirection: - PositionStack.Current = PositionStack.Current.Multiply(m); - break; - case MatrixMode.Texture: - TextureStack.Current = TextureStack.Current.Multiply(m); - break; - } - } - break; - case 0x1C: // Multiply Current Matrix by Translation Matrix - Debug("Multiply Current Matrix by Translation Matrix"); - { - Matrix m = Matrix.GetIdentity(); - - m.Data[12] = (int)PopCommand().Param; - m.Data[13] = (int)PopCommand().Param; - m.Data[14] = (int)PopCommand().Param; - - MultiplyCurrentMatrixBy(ref m); - } - break; - case 0x20: // Directly Set Vertex Color - Debug("Directly Set Vertex Color"); - PopCommand(); - for (int i = 0; i < 3; i++) - { - uint color = cmd.Param & 0b11111; - - VertexColor[i] = (byte)(color * 2 + (color + 31) / 32); - cmd.Param >>= 5; - } - break; - case 0x21: // TODO: Set Normal Vector - PopCommand(); - break; - case 0x22: // TODO: Set Texture Coordinates - PopCommand(); - break; - case 0x23: // Set Vertex XYZ 12-bit fraction - Debug("Set Vertex XYZ 12-bit fraction"); - PopCommand(); - VertexCoords[0] = (short)cmd.Param; - VertexCoords[1] = (short)(cmd.Param >> 16); - cmd = PopCommand(); - VertexCoords[2] = (short)cmd.Param; - - TransformAndAddVertex(); - break; - case 0x24: // Set Vertex XYZ 6-bit fraction - PopCommand(); - VertexCoords[0] = (short)(((cmd.Param >> 0) & 1023) << 6); - VertexCoords[1] = (short)(((cmd.Param >> 10) & 1023) << 6); - VertexCoords[2] = (short)(((cmd.Param >> 20) & 1023) << 6); - - TransformAndAddVertex(); - break; - case 0x25: // Set Vertex XY 12-bit fraction - PopCommand(); - VertexCoords[0] = (short)cmd.Param; - VertexCoords[1] = (short)(cmd.Param >> 16); - - TransformAndAddVertex(); - break; - case 0x26: // Set Vertex XZ 12-bit fraction - PopCommand(); - VertexCoords[0] = (short)cmd.Param; - VertexCoords[2] = (short)(cmd.Param >> 16); - - TransformAndAddVertex(); - break; - case 0x27: // Set Vertex YZ 12-bit fraction - PopCommand(); - VertexCoords[1] = (short)cmd.Param; - VertexCoords[2] = (short)(cmd.Param >> 16); - - TransformAndAddVertex(); - break; - case 0x28: // Relative add vertex coordinates - PopCommand(); - VertexCoords[0] += (short)((((cmd.Param >> 0) & 1023) << 6) >> 6); - VertexCoords[1] += (short)((((cmd.Param >> 10) & 1023) << 6) >> 6); - VertexCoords[2] += (short)((((cmd.Param >> 20) & 1023) << 6) >> 6); - - TransformAndAddVertex(); - break; - case 0x29: // TODO: Polygon Attributes - Debug("Polygon Attributes"); - PopCommand(); - break; - case 0x2A: // TODO: Texture Parameters - Debug("Texture Parameters"); - PopCommand(); - break; - case 0x2B: // TODO: Set Texture Palette Base Address - PopCommand(); - break; - case 0x30: // TODO: Diffise/Ambient Reflections - PopCommand(); - break; - case 0x31: // TODO: Specular Reflections & Emission - PopCommand(); - break; - case 0x32: // TODO: Light Vector - PopCommand(); - break; - case 0x33: // TODO: Set Light Color - PopCommand(); - break; - case 0x34: // TODO: Shininess - for (uint i = 0; i < 32; i++) - { - PopCommand(); - } - break; - case 0x40: // Begin Vertex List - PopCommand(); - PrimitiveType = (PrimitiveType)(cmd.Param & 0b11); - // Console.WriteLine("Begin Vertex List: " + PrimitiveType); - break; - case 0x41: // End Vertex List - essentially a NOP - Debug("End Vertex List"); - PopCommand(); - break; - case 0x50: // Swap Buffers - Debug("Swap Buffers"); - PopCommand(); - // TODO: swap buffers parameters - Render(); - Swap(ref VertexQueueFront, ref VertexQueueBack); - break; - case 0x60: // Set Viewport - Debug("Set Viewport"); - PopCommand(); - Viewport1[0] = (byte)cmd.Param; - Viewport1[1] = (byte)(cmd.Param >> 8); - Viewport2[0] = (byte)(cmd.Param >> 16); - Viewport2[1] = (byte)(cmd.Param >> 24); - break; - case 0x70: // TODO: Box Test - PopCommand(); - PopCommand(); - PopCommand(); - break; - case 0x71: // TODO: Position Test - PopCommand(); - PopCommand(); - break; - default: - throw new Exception(Hex(cmd.Cmd, 2)); - - if (CommandParamLengths[cmd.Cmd] == 0) - { - PopCommand(); - } - else - { - for (uint i = 0; i < CommandParamLengths[cmd.Cmd]; i++) - { - PopCommand(); - } - } - break; - } - } - - public void CheckCommands() - { - while (CommandFifo.Entries > 0) - { - Command cmd = PeekCommand(); - - if (CommandFifo.Entries >= CommandParamLengths[cmd.Cmd]) - { - RunCommand(cmd); - } - else - { - break; - } - } - } - - public void Run() - { - if ( - (CommandFifo.Entries == 0 && CommandFifoIrqMode == 2) || - (CommandFifo.Entries < 128 && CommandFifoIrqMode == 1) - ) - { - Nds.HwControl9.FlagInterrupt((uint)InterruptNds.GeometryFifo); - } - } - - public Command PopCommand() - { - if (CommandFifo.Entries == 0) Console.Error.WriteLine("3D: Tried popping with no more commands left!"); - - return CommandFifo.Pop(); - } - - public Command PeekCommand() - { - return CommandFifo.Peek(0); - } - - public void LoadCurrentMatrix(ref Matrix m) - { - switch (MatrixMode) - { - case MatrixMode.Projection: - ProjectionStack.Current = m; - break; - case MatrixMode.Position: - PositionStack.Current = m; - break; - case MatrixMode.PositionDirection: - PositionStack.Current = m; - DirectionStack.Current = m; - break; - case MatrixMode.Texture: - TextureStack.Current = m; - break; - } - } - - public void MultiplyCurrentMatrixBy(ref Matrix m) - { - switch (MatrixMode) - { - case MatrixMode.Projection: - ProjectionStack.Current = ProjectionStack.Current.Multiply(m); - // ProjectionStack.Current.Print("Projection after multiply"); - break; - case MatrixMode.Position: - PositionStack.Current = PositionStack.Current.Multiply(m); - break; - case MatrixMode.PositionDirection: - PositionStack.Current.Print("Before translation mul"); - PositionStack.Current = PositionStack.Current.Multiply(m); - DirectionStack.Current = DirectionStack.Current.Multiply(m); - PositionStack.Current.Print("After translation mul"); - break; - case MatrixMode.Texture: - TextureStack.Current = TextureStack.Current.Multiply(m); - break; - } - } - - public void TransformAndAddVertex() - { - var v = new Vertex(); - - for (int i = 0; i < 3; i++) - { - v.Color[i] = VertexColor[i]; - v.Pos.Data[i] = VertexCoords[i]; - } - - v.Pos.Data[3] = 0x1000; // Set W coordinate to 1 - v.Pos = PositionStack.Current.Multiply(v.Pos); - v.Pos = ProjectionStack.Current.Multiply(v.Pos); - // PositionStack.Current.Print("Position Matrix"); - VertexQueueBack.Insert(v); - - } - - public void Render() - { - // Fill screen with black for now - for (uint i = 0; i < Screen.Length; i++) - { - Screen[i] = 0; - } - - Span vertices = stackalloc Vertex[3]; - while (VertexQueueFront.Entries >= 1) - { - var v = VertexQueueFront.Pop(); - - int x = v.Pos.Data[0]; - int y = v.Pos.Data[1]; - int z = v.Pos.Data[2]; - int w = v.Pos.Data[3]; - - if (w == 0) - { - continue; - } - - // int screenX = (((x * (Viewport2[0] - Viewport1[0] + 1)) >> 12) / 8) + Viewport2[0] / 2; - // int screenY = (((y * (Viewport2[1] - Viewport1[1] + 1)) >> 12) / 8) + Viewport2[1] / 2; - // int screenX = (x * (Viewport2[0] - Viewport1[0] + 1)) / (2 * w) + Viewport2[0] / 2; - // int screenY = (y * (Viewport2[1] - Viewport1[1] + 1)) / (2 * w) + Viewport2[1] / 2; - - // int screenX = (x * 256) / (2 * w) + 128; - // int screenY = (y * 192) / (2 * w) + 96; - - int screenX = x * 128 / w + 128; - int screenY = -y * 96 / w + 96; - - // Console.WriteLine($"{screenX} {screenY}"); - - // 0,0 is bottom left on NDS - // screenY = 191 - screenY; - - SetPixel(screenX, screenY); - } - - // Console.WriteLine(VertexQueueFront.Entries); - - // while (VertexQueue.Entries >= 3) - // { - // for (int i = 0; i < 3; i++) - // { - // vertices[i] = VertexQueue.Pop(); - - // int x = vertices[i].Pos.Data[0]; - // int y = vertices[i].Pos.Data[1]; - // int z = vertices[i].Pos.Data[2]; - // int w = vertices[i].Pos.Data[3]; - - // if (w == 0) - // { - // w = 0x1000; - // } - - // // int screenX = (((x * (Viewport2[0] - Viewport1[0] + 1)) >> 12) / 8) + Viewport2[0] / 2; - // // int screenY = (((y * (Viewport2[1] - Viewport1[1] + 1)) >> 12) / 8) + Viewport2[1] / 2; - // int screenX = (x * (Viewport2[0] - Viewport1[0] + 1)) / (2 * w) + Viewport2[0] / 2; - // int screenY = (y * (Viewport2[1] - Viewport1[1] + 1)) / (2 * w) + Viewport2[1] / 2; - - // // 0,0 is bottom left on NDS - // screenY = 191 - screenY; - - // // Console.WriteLine($"{screenX}, {screenY}, {z}, {w}"); - - // vertices[i].Pos.Data[0] = screenX; - // vertices[i].Pos.Data[1] = screenY; - - // SetPixel(screenX, screenY); - // } - - // DrawLine(vertices[0].Pos.Data[0], vertices[0].Pos.Data[1], vertices[1].Pos.Data[0], vertices[1].Pos.Data[1]); - // DrawLine(vertices[1].Pos.Data[0], vertices[1].Pos.Data[1], vertices[2].Pos.Data[0], vertices[2].Pos.Data[1]); - // DrawLine(vertices[2].Pos.Data[0], vertices[2].Pos.Data[1], vertices[0].Pos.Data[0], vertices[0].Pos.Data[1]); - // } - - // var m = PositionStack.Current; - var m = ProjectionStack.Current; - - } - - void DrawLine(int x0, int y0, int x1, int y1) - { - bool low; - bool swap; - int dx0; - int dy0; - int dx1; - int dy1; - - if (Math.Abs(y1 - y0) < Math.Abs(x1 - x0)) - { - low = true; - swap = x0 > x1; - } - else - { - low = false; - swap = y0 > y1; - } - - if (swap) - { - dx0 = x1; - dy0 = y1; - dx1 = x0; - dy1 = y0; - } - else - { - dx0 = x0; - dy0 = y0; - dx1 = x1; - dy1 = y1; - } - - if (low) - { - int dx = dx1 - dx0; - int dy = dy1 - dy0; - - int yi = 1; - - if (dy < 0) - { - yi = -1; - dy = -dy; - } - - int d = (2 * dy) - dx; - int y = dy0; - - for (int x = dx0; x <= dx1; x++) - { - SetPixel(x, y); - if (d > 0) - { - y = y + yi; - d = d + (2 * (dy - dx)); - } - else - { - d = d + 2 * dy; - } - } - } - else - { - int dx = dx1 - dx0; - int dy = dy1 - dy0; - - int xi = 1; - - if (dx < 0) - { - xi = -1; - dx = -dx; - } - - int d = (2 * dx) - dy; - int x = dx0; - - for (int y = dy0; y <= dy1; y++) - { - SetPixel(x, y); - if (d > 0) - { - x = x + xi; - d = d + (2 * (dx - dy)); - } - else - { - d = d + 2 * dx; - } - } - } - } - - void SetPixel(int x, int y) - { - if ((uint)x >= 256 || (uint)y >= 192) - { - return; - } - - var screenIndex = y * 256 + x; - - Screen[screenIndex] = 0x7FFF; - } - - [Conditional("NEVER")] - public static void Debug(string s) - { - Console.WriteLine("3D: " + s); - } - - [Conditional("NEVER")] - public void Debug2(string s) - { - Console.WriteLine("[" + Hex(Nds.Cpu9.GetCurrentInstrAddr(), 8) + "] " + s); - } - } -} diff --git a/Assets/emulator/PpuNds3D.cs.meta b/Assets/emulator/PpuNds3D.cs.meta deleted file mode 100644 index f8cfdf0..0000000 --- a/Assets/emulator/PpuNds3D.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5c1d666a4057424428483e53a56bdc1c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/PpuRenderer.cs b/Assets/emulator/PpuRenderer.cs index aee9b29..cbe6de8 100644 --- a/Assets/emulator/PpuRenderer.cs +++ b/Assets/emulator/PpuRenderer.cs @@ -1,32 +1,34 @@ -using System; -using System.IO; -using System.Runtime.CompilerServices; -using static MyStruct; -using Avx2 = MyStruct; -using static OptimeGBA.Bits; using static OptimeGBA.CoreUtil; +using static OptimeGBA.Bits; +using System.Runtime.CompilerServices; +using System; using static OptimeGBA.MemoryUtil; +using Unity.Burst.Intrinsics; +using static Unity.Burst.Intrinsics.X86; + namespace OptimeGBA { public sealed unsafe class PpuRenderer { public int Width; public int Height; - public Nds Nds; - public PpuRenderer(Nds nds, int width, int height) + public PpuRenderer(int width, int height) { Width = width; Height = height; - Nds = nds; Backgrounds = new Background[4] { - new Background(Nds != null, 0), - new Background(Nds != null, 1), - new Background(Nds != null, 2), - new Background(Nds != null, 3), + new Background(false, 0), + new Background(false, 1), + new Background(false, 2), + new Background(false, 3), }; - Array.Fill(DebugEnableBg, true); + //Array.Fill(DebugEnableBg, true); + for (int i = 0; i < DebugEnableBg.Length; i++) + { + DebugEnableBg[i] = true; + } int ScreenBufferSize = Width * Height; #if UNSAFE @@ -54,14 +56,14 @@ namespace OptimeGBA ScreenBack[i] = 0x7FFF; } - if (nds == null) + //if (nds == null) { DisplayMode = 1; } // Load 3D placeholder // Why do I waste time on useless crap like this - Stream img = typeof(PpuRenderer).Assembly.GetManifestResourceStream("OptimeGBA-OpenTK.resources.3d-placeholder.raw"); + /*Stream img = typeof(PpuRenderer).Assembly.GetManifestResourceStream("OptimeGBA-OpenTK.resources.3d-placeholder.raw"); if (img == null) { img = typeof(PpuRenderer).Assembly.GetManifestResourceStream("OptimeGBA-SDL.resources.3d-placeholder.raw"); @@ -86,7 +88,7 @@ namespace OptimeGBA b >>= 3; PlaceholderFor3D[index++] = (ushort)((b << 10) | (g << 5) | r); - } + }*/ for (uint i = 0; i < Width; i++) WinMasks[i + 8] = 0b111111; @@ -316,43 +318,6 @@ namespace OptimeGBA } } - public void RenderScanlineNds(uint vcount, byte[] bgVramArr, byte[] objVramArr) - { - if (!ForcedBlank) - { - fixed (byte* bgVram = bgVramArr, objVram = objVramArr) - { - switch (DisplayMode) - { - case 1: // Regular rendering - PrepareBackgroundAndWindow(vcount); - RenderBgModes(vcount, bgVram); - - if (DebugForce3DLayer) { - uint srcBase = (uint)(vcount * Width); - - for (uint i = 0; i < Width; i++) - { - BgLo[i + 8] = BgHi[i + 8]; - BgHi[i + 8] = (uint)(Nds.Ppu3D.Screen[srcBase + i]); - } - } - - Composite(vcount); - if (DebugEnableObj && ScreenDisplayObj && vcount != 191) RenderObjs(vcount + 1, objVram); - break; - case 2: // LCDC Mode - RenderMode3(vcount, bgVram); - break; - } - } - } - else - { - RenderWhiteScanline(vcount); - } - } - public void RunVblankOperations() { Backgrounds[2].CopyAffineParams(); @@ -493,51 +458,16 @@ namespace OptimeGBA Backgrounds[1].Mode = BackgroundMode.Char; Backgrounds[2].Mode = BackgroundMode.Char; Backgrounds[3].Mode = BackgroundMode.Char; - if (Nds == null) - { - switch (BgMode) - { - case 1: - Backgrounds[2].Mode = BackgroundMode.Affine; - break; - case 2: - Backgrounds[2].Mode = BackgroundMode.Affine; - Backgrounds[3].Mode = BackgroundMode.Affine; - break; - } - } - else - { - if (Bg0Is3D) - { - Backgrounds[0].Mode = BackgroundMode.Display3D; - } - switch (BgMode) - { - case 1: - Backgrounds[3].Mode = BackgroundMode.Affine; - break; - case 2: - Backgrounds[2].Mode = BackgroundMode.Affine; - Backgrounds[3].Mode = BackgroundMode.Affine; - break; - case 3: - Backgrounds[3].Mode = BackgroundMode.Extended; - break; - case 4: - Backgrounds[2].Mode = BackgroundMode.Affine; - Backgrounds[3].Mode = BackgroundMode.Extended; - break; - case 5: - Backgrounds[2].Mode = BackgroundMode.Extended; - Backgrounds[3].Mode = BackgroundMode.Extended; - break; - case 6: - Backgrounds[0].Mode = BackgroundMode.Display3D; - Backgrounds[2].Mode = BackgroundMode.Large; - break; - } + switch (BgMode) + { + case 1: + Backgrounds[2].Mode = BackgroundMode.Affine; + break; + case 2: + Backgrounds[2].Mode = BackgroundMode.Affine; + Backgrounds[3].Mode = BackgroundMode.Affine; + break; } // Extended mode backgrounds have extra options @@ -620,154 +550,8 @@ namespace OptimeGBA } } - //[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)] - //private void _RenderCharBackground( - // uint vcount, byte* vram, - // byte* palettes, - // byte* winMasks, - // uint* hi, uint* lo, - // Background bg, bool mosaicX - // ) - //{ - // uint charBase = bg.CharBaseBlock * CharBlockSize + CharBaseBlockCoarse * CoarseBlockSize; - // uint mapBase = bg.MapBaseBlock * MapBlockSize + MapBaseBlockCoarse * CoarseBlockSize; - - // uint pixelY = bg.VerticalOffset + vcount; - // if (bg.EnableMosaic) - // { - // pixelY -= BgMosaicYCounter; - // } - // uint pixelYWrapped = pixelY & 255; - - // uint screenSizeBase = bg.ScreenSize * 2; - // uint verticalOffsetBlocks = CharBlockHeightTable[screenSizeBase + ((pixelY & 511) >> 8)]; - // uint mapVertOffset = MapBlockSize * verticalOffsetBlocks; - - // uint tileY = pixelYWrapped >> 3; - // uint intraTileY = pixelYWrapped & 7; - - // uint pixelX = bg.HorizontalOffset; - // uint intraTileX = bg.HorizontalOffset & 7; - // uint lineIndex = 8 - intraTileX; - - // uint tilesToRender = (uint)(Width / 8); - // if (lineIndex < 8) tilesToRender++; - - // uint mosaicXCounter = BgMosaicX; - - // // Every byte of these vectors are filled - // Vector256 metaVec = Vector256.Create((bg.Priority << 8) | (1 << bg.Id)); - - // for (uint tile = 0; tile < tilesToRender; tile++) - // { - // uint pixelXWrapped = pixelX & 255; - - // // 2 bytes per tile - // uint tileX = pixelXWrapped >> 3; - // uint horizontalOffsetBlocks = CharBlockWidthTable[screenSizeBase + ((pixelX & 511) >> 8)]; - // uint mapHoriOffset = MapBlockSize * horizontalOffsetBlocks; - // uint mapEntryIndex = mapBase + mapVertOffset + mapHoriOffset + tileY * 64 + tileX * 2; - // uint mapEntry = GetUshort(vram, mapEntryIndex); - - // uint tileNumber = mapEntry & 1023; // 10 bits - // bool xFlip = BitTest(mapEntry, 10); - // bool yFlip = BitTest(mapEntry, 11); - - // uint effectiveIntraTileY = intraTileY; - // if (yFlip) - // { - // effectiveIntraTileY ^= 7; - // } - - // Vector256 clearMaskVec; - // Vector256 indicesVec = Vector256.Zero; - // uint paletteRow = 0; - - // if (bg.Use8BitColor) - // { - // clearMaskVec = Vector256.Create(0xFFU); - - // uint vramTileAddr = charBase + tileNumber * 64 + effectiveIntraTileY * 8; - // ulong data = GetUlong(vram, vramTileAddr); - - // if (data != 0) - // { - // indicesVec = Avx2.ConvertToVector256Int32((byte*)&data).AsUInt32(); - // if (xFlip) - // { - // // First, reverse within 128-bit lanes - // indicesVec = Avx2.Shuffle(indicesVec, 0b00_01_10_11); - // // Then, swap upper and lower halves - // indicesVec = Avx2.Permute2x128(indicesVec, indicesVec, 1); - // } - // indicesVec = Avx2.And(indicesVec, clearMaskVec); - // } - // else - // { - // pixelX += 8; - // lineIndex += 8; - // continue; - // } - // } - // else - // { - // clearMaskVec = Vector256.Create(0xFU); - - // paletteRow = (mapEntry >> 12) & 0xF; - // uint vramTileAddr = charBase + tileNumber * 32 + effectiveIntraTileY * 4; - - // uint data = GetUint(vram, vramTileAddr); - - // if (data != 0) - // { - // Vector256 shifts; - // if (xFlip) - // { - // shifts = Vector256.Create(28U, 24U, 20U, 16U, 12U, 8U, 4U, 0U); - // } - // else - // { - // shifts = Vector256.Create(0U, 4U, 8U, 12U, 16U, 20U, 24U, 28U); - // } - // indicesVec = Vector256.Create(data); - // indicesVec = Avx2.ShiftRightLogicalVariable(indicesVec, shifts); - // indicesVec = Avx2.And(indicesVec, clearMaskVec); - // } - // else - // { - // pixelX += 8; - // lineIndex += 8; - // continue; - // } - // } - - // Vector256 color = Avx2.GatherVector256((int*)((ushort*)palettes + paletteRow * 16), indicesVec.AsInt32(), sizeof(ushort)); - // color = Avx2.And(color, Vector256.Create(0xFFFF)); - // // Weave metadata (priority, ID) into color data - // color = Avx2.Or(color, Avx2.ShiftLeftLogical(metaVec, 16)); - - // Vector256 winMask = Avx2.ConvertToVector256Int32((byte*)(winMasks + lineIndex)); - // winMask = Avx2.And(winMask, metaVec); - // winMask = Avx2.CompareEqual(winMask, Vector256.Zero); - // // Get important color bits - // Vector256 clear = Avx2.And(indicesVec, clearMaskVec).AsInt32(); - // // Are those bits clear? - // clear = Avx2.CompareEqual(clear, Vector256.Zero); - // // Merge with window mask - // winMask = Avx2.Or(winMask, clear); - // winMask = Avx2.Xor(winMask, Vector256.Create(0xFFFFFFFF).AsInt32()); - - // // Push back covered pixels from hi to lo - // Avx2.MaskStore((int*)(lo + lineIndex), winMask, Avx2.LoadVector256((int*)(hi + lineIndex))); - // Avx2.MaskStore((int*)(hi + lineIndex), winMask, color); - - // pixelX += 8; - // lineIndex += 8; - // } - //} - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void _RenderCharBackground( + unsafe private void _RenderCharBackground( uint vcount, byte* vram, byte* palettes, byte* winMasks, @@ -802,7 +586,7 @@ namespace OptimeGBA uint mosaicXCounter = BgMosaicX; // Every byte of these vectors are filled - Vector256 metaVec = Vector256.Create((bg.Priority << 8) | (1 << bg.Id)); + v256 metaVec = new v256((int)((bg.Priority << 8) | (1 << bg.Id))); for (uint tile = 0; tile < tilesToRender; tile++) { @@ -825,29 +609,28 @@ namespace OptimeGBA effectiveIntraTileY ^= 7; } - Vector256 clearMaskVec; - Vector256 indicesVec = Vector256.Zero; + v256 clearMaskVec; + v256 indicesVec; uint paletteRow = 0; if (bg.Use8BitColor) { - clearMaskVec = Vector256.Create(0xFFU); + clearMaskVec = new v256(0xFFU); uint vramTileAddr = charBase + tileNumber * 64 + effectiveIntraTileY * 8; ulong data = GetUlong(vram, vramTileAddr); if (data != 0) { - //indicesVec = Avx2.ConvertToVector256Int32((byte*)&data).AsUInt32(); - indicesVec = Avx2.ConvertToVector256Int32(data).AsUInt32(); + indicesVec = Avx2.mm256_cvtepu8_epi32(new v128(data)); if (xFlip) { // First, reverse within 128-bit lanes - indicesVec = Avx2.Shuffle(indicesVec, 0b00_01_10_11); + indicesVec = Avx2.mm256_shuffle_epi32(indicesVec, 0b00_01_10_11); // Then, swap upper and lower halves - indicesVec = Avx2.Permute2x128(indicesVec, indicesVec, 1); + indicesVec = Avx2.mm256_permute2x128_si256(indicesVec, indicesVec, 1); } - indicesVec = Avx2.And(indicesVec, clearMaskVec); + indicesVec = Avx2.mm256_and_si256(indicesVec, clearMaskVec); } else { @@ -858,7 +641,7 @@ namespace OptimeGBA } else { - clearMaskVec = Vector256.Create(0xFU); + clearMaskVec = new v256(0xFU); paletteRow = (mapEntry >> 12) & 0xF; uint vramTileAddr = charBase + tileNumber * 32 + effectiveIntraTileY * 4; @@ -867,18 +650,18 @@ namespace OptimeGBA if (data != 0) { - Vector256 shifts; + v256 shifts; if (xFlip) { - shifts = Vector256.Create(28U, 24U, 20U, 16U, 12U, 8U, 4U, 0U); + shifts = new v256(28U, 24U, 20U, 16U, 12U, 8U, 4U, 0U); } else { - shifts = Vector256.Create(0U, 4U, 8U, 12U, 16U, 20U, 24U, 28U); + shifts = new v256(0U, 4U, 8U, 12U, 16U, 20U, 24U, 28U); } - indicesVec = Vector256.Create(data); - indicesVec = Avx2.ShiftRightLogicalVariable(indicesVec, shifts); - indicesVec = Avx2.And(indicesVec, clearMaskVec); + indicesVec = new v256(data); + indicesVec = Avx2.mm256_srlv_epi32(indicesVec, shifts); + indicesVec = Avx2.mm256_and_si256(indicesVec, clearMaskVec); } else { @@ -888,25 +671,28 @@ namespace OptimeGBA } } - Vector256 color = Avx2.GatherVector256((int*)((ushort*)palettes + paletteRow * 16), indicesVec.AsInt32(), sizeof(ushort)); - color = Avx2.And(color, Vector256.Create(0xFFFF)); + v256 color = Avx2.mm256_i32gather_epi32((int*)((ushort*)palettes + paletteRow * 16), indicesVec, sizeof(ushort)); + color = Avx2.mm256_and_si256(color, new v256(0xFFFF)); // Weave metadata (priority, ID) into color data - color = Avx2.Or(color, Avx2.ShiftLeftLogical(metaVec, 16)); + color = Avx2.mm256_or_si256(color, Avx2.mm256_slli_epi32(metaVec, 16)); - Vector256 winMask = Avx2.ConvertToVector256Int32((byte*)(winMasks + lineIndex)); - winMask = Avx2.And(winMask, metaVec); - winMask = Avx2.CompareEqual(winMask, Vector256.Zero); + ulong addr = GetUlong(winMasks, lineIndex); + v256 winMask = Avx2.mm256_cvtepi8_epi32(new v128(addr)); + winMask = Avx2.mm256_and_si256(winMask, metaVec); + winMask = Avx2.mm256_cmpeq_epi32(winMask, new v256((byte)0)); // Get important color bits - Vector256 clear = Avx2.And(indicesVec, clearMaskVec).AsInt32(); + v256 clear = Avx2.mm256_and_si256(indicesVec, clearMaskVec); // Are those bits clear? - clear = Avx2.CompareEqual(clear, Vector256.Zero); + clear = Avx2.mm256_cmpeq_epi32(clear, new v256(0)); // Merge with window mask - winMask = Avx2.Or(winMask, clear); - winMask = Avx2.Xor(winMask, Vector256.Create(0xFFFFFFFF).AsInt32()); + winMask = Avx2.mm256_or_si256(winMask, clear); + winMask = Avx2.mm256_xor_si256(winMask, new v256(int.MinValue)); // Push back covered pixels from hi to lo - Avx2.MaskStore((int*)(lo + lineIndex), winMask, Avx2.LoadVector256((int*)(hi + lineIndex))); - Avx2.MaskStore((int*)(hi + lineIndex), winMask, color); + // This render the front image + Avx2.mm256_maskstore_epi32((void*)(lo + lineIndex), winMask, Avx2.mm256_stream_load_si256((void*)(hi + lineIndex))); + // This render the background, has some bugs + Avx2.mm256_maskstore_epi32((void*)(hi + lineIndex), winMask, color); pixelX += 8; lineIndex += 8; @@ -1178,7 +964,7 @@ namespace OptimeGBA uint tileX = (uint)(objX / 8); uint tileY = (uint)(objY / 8); - uint charBase = Nds != null ? 0U : 0x10000U; + uint charBase = false ? 0U : 0x10000U; tile <<= (int)TileObj1DBoundary; uint effectiveTileNumber = (uint)(tile + tileX); @@ -1362,22 +1148,16 @@ namespace OptimeGBA public bool BgIsEnabled(int id) { - if (Nds == null) + + switch (BgMode) { - switch (BgMode) - { - case 1: - if (id == 3) return false; - break; - case 2: - if (id == 0) return false; - if (id == 1) return false; - break; - } - } - else - { - if (BgMode == 6 && (id == 0 || id == 2)) return false; + case 1: + if (id == 3) return false; + break; + case 2: + if (id == 0) return false; + if (id == 1) return false; + break; } return ScreenDisplayBg[id] && DebugEnableBg[id]; @@ -1403,25 +1183,12 @@ namespace OptimeGBA RenderAffineBitmapBackground(vcount, vram, bg, false); break; case BackgroundMode.Display3D: - Render3DBackground(vcount, vram, bg); + //Render3DBackground(vcount, vram, bg); break; } } } - public void Render3DBackground(uint vcount, byte* vram, Background bg) - { - uint srcBase = (uint)(vcount * Width); - - ushort meta = bg.GetMeta(); - - for (uint i = 0; i < Width; i++) - { - if (Nds.Ppu3D.Screen[srcBase + i] != 0) - PlaceBgPixel(i + 8, Nds.Ppu3D.Screen[srcBase + i], meta); - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RenderAffineBitmapBackground(uint vcount, byte* vram, Background bg, bool fullColor) { diff --git a/Assets/emulator/PpuRenderer.cs.meta b/Assets/emulator/PpuRenderer.cs.meta index af7427c..49f3396 100644 --- a/Assets/emulator/PpuRenderer.cs.meta +++ b/Assets/emulator/PpuRenderer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d6510d22717f6584b81af5ea97b0569a +guid: 53de3b275b2214443a61d7a3d8c35e3d MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/Provider.cs b/Assets/emulator/Provider.cs index 8fb5b1a..2f107df 100644 --- a/Assets/emulator/Provider.cs +++ b/Assets/emulator/Provider.cs @@ -1,6 +1,6 @@ namespace OptimeGBA { - public delegate void AudioCallback(short[] stereo16BitInterleavedData); + public delegate void AudioCallback(float[] stereo16BitInterleavedData); public abstract class Provider { public bool OutputAudio = true; diff --git a/Assets/emulator/Provider.cs.meta b/Assets/emulator/Provider.cs.meta index fbac89c..807280d 100644 --- a/Assets/emulator/Provider.cs.meta +++ b/Assets/emulator/Provider.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 73818cdc5ac0e0647a35b1b78a717b70 +guid: 3c36d17ca19732446911ae6dc3eee94e MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/ProviderGba.cs b/Assets/emulator/ProviderGba.cs index c1dcd63..8d6d9c6 100644 --- a/Assets/emulator/ProviderGba.cs +++ b/Assets/emulator/ProviderGba.cs @@ -9,7 +9,7 @@ namespace OptimeGBA public byte[] Bios; public byte[] Rom; - + public string RomName; public string RomId; public ProviderGba(byte[] bios, byte[] rom, string savPath, AudioCallback audioCallback) @@ -18,6 +18,10 @@ namespace OptimeGBA Rom = rom; AudioCallback = audioCallback; SavPath = savPath; + if (rom.Length > 0xA0 + 12) + { + RomName = Encoding.ASCII.GetString(Rom, 0xA0, 12); + } if (rom.Length >= 0xAC + 4) { diff --git a/Assets/emulator/ProviderGba.cs.meta b/Assets/emulator/ProviderGba.cs.meta index 277f577..84a3421 100644 --- a/Assets/emulator/ProviderGba.cs.meta +++ b/Assets/emulator/ProviderGba.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 2b60a85ffb5daaa4aa83e8999b108e9d +guid: 05e3df20197e4ba46a0d39f32107f0a5 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/ProviderNds.cs b/Assets/emulator/ProviderNds.cs deleted file mode 100644 index 0fac2e4..0000000 --- a/Assets/emulator/ProviderNds.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Text; - -namespace OptimeGBA -{ - public sealed class ProviderNds : Provider - { - public bool DirectBoot = true; - - public byte[] Bios7; - public byte[] Bios9; - public byte[] Firmware; - public byte[] Rom; - - public string RomId; - - public ProviderNds(byte[] bios7, byte[] bios9, byte[] firmware, byte[] rom, string savPath, AudioCallback audioCallback) - { - Bios7 = bios7; - Bios9 = bios9; - Firmware = firmware; - Rom = rom; - AudioCallback = audioCallback; - SavPath = savPath; - } - } -} \ No newline at end of file diff --git a/Assets/emulator/ProviderNds.cs.meta b/Assets/emulator/ProviderNds.cs.meta deleted file mode 100644 index 4fac925..0000000 --- a/Assets/emulator/ProviderNds.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f149b75fc4a1c4b4881e9d79fc7a1edc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/RingBuffer.cs b/Assets/emulator/RingBuffer.cs new file mode 100644 index 0000000..ff3727c --- /dev/null +++ b/Assets/emulator/RingBuffer.cs @@ -0,0 +1,72 @@ +using System.Threading; + +public class RingBuffer +{ + private readonly T[] buffer; + private readonly int capacity; + private int writePos; + private int readPos; + private int count; + + public RingBuffer(int capacity) + { + this.capacity = capacity; + this.buffer = new T[capacity]; + this.writePos = 0; + this.readPos = 0; + this.count = 0; + } + + public void Write(T item) + { + int localWritePos; + int localReadPos; + + do + { + localWritePos = Volatile.Read(ref writePos); + localReadPos = Volatile.Read(ref readPos); + + int nextWritePos = (localWritePos + 1) % capacity; + + if (nextWritePos == localReadPos) + { + // ɵδ + Interlocked.CompareExchange(ref readPos, (localReadPos + 1) % capacity, localReadPos); + } + } + while (Interlocked.CompareExchange(ref writePos, (localWritePos + 1) % capacity, localWritePos) != localWritePos); + + buffer[localWritePos] = item; + Interlocked.Increment(ref count); + } + + public bool TryRead(out T item) + { + item = default(T); + + int localReadPos; + int localWritePos; + + do + { + localReadPos = Volatile.Read(ref readPos); + localWritePos = Volatile.Read(ref writePos); + + if (localReadPos == localWritePos) + { + return false; // Ϊ + } + } + while (Interlocked.CompareExchange(ref readPos, (localReadPos + 1) % capacity, localReadPos) != localReadPos); + + item = buffer[localReadPos]; + Interlocked.Decrement(ref count); + return true; + } + + public int Available() + { + return Volatile.Read(ref count); + } +} diff --git a/Assets/emulator/RingBuffer.cs.meta b/Assets/emulator/RingBuffer.cs.meta new file mode 100644 index 0000000..f3b92d4 --- /dev/null +++ b/Assets/emulator/RingBuffer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4889053f721ce7f4283fae5176d60772 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/emulator/RtcNds.cs b/Assets/emulator/RtcNds.cs deleted file mode 100644 index 870acf5..0000000 --- a/Assets/emulator/RtcNds.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using static OptimeGBA.Bits; - -namespace OptimeGBA -{ - - public enum RtcNdsState - { - ReceivingCommand, - CommandEntered - } - - public class RtcNds - { - public void UpdateTime() - { - var now = DateTime.Now; - - DateAndTime[0] = ConvertToBcd((byte)(now.Year % 100)); - DateAndTime[1] = ConvertToBcd((byte)now.Month); - DateAndTime[2] = ConvertToBcd((byte)now.Day); - DateAndTime[3] = ConvertToBcd((byte)now.DayOfWeek); - DateAndTime[4] = ConvertToBcd((byte)now.Hour); - DateAndTime[5] = ConvertToBcd((byte)now.Minute); - DateAndTime[6] = ConvertToBcd((byte)now.Second); - } - - public static byte ConvertToBcd(byte val) - { - uint upper = val / 10U; - uint lower = val % 10U; - - return (byte)((upper << 4) | lower); - } - - public byte ReadHwio8(uint addr) - { - switch (addr) - { - case 0x4000138: - return Rtc; - } - - return 0; - } - - byte Rtc; - byte Command; - int BitsWritten; - byte Status1; - - byte[] DateAndTime = new byte[7]; - - RtcNdsState State; - - public void WriteHwio8(uint addr, byte val) - { - switch (addr) - { - case 0x4000138: - if (BitTest(val, 2)) // CS - { - if (BitTest(Rtc, 1) && !BitTest(val, 1)) // /SC to low - { - switch (State) - { - case RtcNdsState.ReceivingCommand: - Command |= (byte)((val & 1) << (7 - BitsWritten)); - if (++BitsWritten == 8) - { - State = RtcNdsState.CommandEntered; - // Console.WriteLine("RTC: command set " + Util.Hex(Command, 2)); - BitsWritten = 0; - - switch ((Command >> 1) & 0b111) - { - case 0: - // Console.WriteLine("RTC status 1"); - break; - - case 1: - // Console.WriteLine("RTC status 2"); - break; - - case 2: - // Console.WriteLine("RTC date and time"); - UpdateTime(); - break; - - case 3: - // Console.WriteLine("RTC time"); - UpdateTime(); - break; - } - } - break; - case RtcNdsState.CommandEntered: - if (!BitTest(val, 4)) // Read - { - val &= 0xFE; // Erase bit 0 - int commandBits = (Command >> 1) & 0b111; - - int byteNum = BitsWritten / 8; - int bitNum = (BitsWritten % 8); - switch (commandBits) - { - case 0: // Status 1 - // Console.WriteLine("status 1 read"); - val |= (byte)((Status1 >> BitsWritten) & 1); - break; - - case 2: // Date & Time (7 bytes) - val |= (byte)((DateAndTime[byteNum] >> bitNum) & 1); - break; - - case 3: // Time (3 bytes); - val |= (byte)((DateAndTime[byteNum + 4] >> bitNum) & 1); - break; - - default: - // Console.WriteLine("RTC: unknown command read " + commandBits); - break; - } - } - else - { - byte bit = (byte)(val & 1U); - switch ((Command >> 1) & 0b111) - { - case 0: // Status 1 - if (BitsWritten >= 1 && BitsWritten <= 3) - { - // Console.WriteLine("status 1 write "); - Status1 &= (byte)(~(1 << BitsWritten)); - Status1 |= (byte)(bit << BitsWritten); - } - break; - } - } - BitsWritten++; - break; - } - } - else if (!BitTest(Rtc, 1) && BitTest(val, 1) && !BitTest(val, 4)) - { - val &= 0xFE; - val |= (byte)(Rtc & 1); - } - } - else - { - Command = 0; - BitsWritten = 0; - State = RtcNdsState.ReceivingCommand; - } - - Rtc = val; - break; - } - } - } -} \ No newline at end of file diff --git a/Assets/emulator/RtcNds.cs.meta b/Assets/emulator/RtcNds.cs.meta deleted file mode 100644 index 7310f7c..0000000 --- a/Assets/emulator/RtcNds.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f19637330f5677d4fa311abfed7f81f5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/Scheduler.cs.meta b/Assets/emulator/Scheduler.cs.meta index 6982443..ebce652 100644 --- a/Assets/emulator/Scheduler.cs.meta +++ b/Assets/emulator/Scheduler.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 7a3ce826f3cf2804588653e63ff30378 +guid: 56299f29f00a78c4e84616fb9fc75b69 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/Soundgoodizer.cs b/Assets/emulator/Soundgoodizer.cs deleted file mode 100644 index 3f04364..0000000 --- a/Assets/emulator/Soundgoodizer.cs +++ /dev/null @@ -1,176 +0,0 @@ -using System; -//using NAudio.Dsp; -using static OptimeGBA.CoreUtil; - -namespace OptimeGBA -{ - - public class SoundgoodizerFilterChannel - { - // Each biquad filter has a slope of 12db/oct so 2 biquads chained gets us 24db/oct - //BiQuadFilter[] LowFilters = new BiQuadFilter[2]; - //BiQuadFilter[] MidFilters = new BiQuadFilter[4]; - //BiQuadFilter[] HighFilters = new BiQuadFilter[2]; - - public float OutLow = 0; - public float OutMid = 0; - public float OutHigh = 0; - - public bool DbPerOct24; - - public SoundgoodizerFilterChannel(bool dbPerOct24, float sampleRate, float lowHz, float highHz) - { - DbPerOct24 = dbPerOct24; - - // q = 1/sqrt(2) maximally flat "butterworth" filter - float q = 1F/(float)Math.Sqrt(2); - //LowFilters[0] = BiQuadFilter.LowPassFilter(sampleRate, lowHz, q); - //LowFilters[1] = BiQuadFilter.LowPassFilter(sampleRate, lowHz, q); - - //MidFilters[0] = BiQuadFilter.HighPassFilter(sampleRate, lowHz, q); - //MidFilters[1] = BiQuadFilter.LowPassFilter(sampleRate, highHz, q); - //MidFilters[2] = BiQuadFilter.HighPassFilter(sampleRate, lowHz, q); - //MidFilters[3] = BiQuadFilter.LowPassFilter(sampleRate, highHz, q); - - //HighFilters[0] = BiQuadFilter.HighPassFilter(sampleRate, highHz, q); - //HighFilters[1] = BiQuadFilter.HighPassFilter(sampleRate, highHz, q); - } - - public void ChangeFilterParams(bool dbPerOct24, float sampleRate, float lowHz, float highHz) - { - DbPerOct24 = dbPerOct24; - - float q = 1F/(float)Math.Sqrt(2); - //LowFilters[0].SetLowPassFilter(sampleRate, lowHz, q); - //LowFilters[1].SetLowPassFilter(sampleRate, lowHz, q); - - //MidFilters[0].SetHighPassFilter(sampleRate, lowHz, q); - //MidFilters[1].SetLowPassFilter(sampleRate, highHz, q); - //MidFilters[2].SetHighPassFilter(sampleRate, lowHz, q); - //MidFilters[3].SetLowPassFilter(sampleRate, highHz, q); - - //HighFilters[0].SetHighPassFilter(sampleRate, highHz, q); - //HighFilters[1].SetHighPassFilter(sampleRate, highHz, q); - } - - public void Process(float inVal) - { - OutLow = inVal; - OutMid = inVal; - OutHigh = inVal; - - //for (int i = 0; i < (DbPerOct24 ? 2 : 1); i++) - //{ - // OutLow = LowFilters[i].Transform(OutLow); - //} - - //for (int i = 0; i < (DbPerOct24 ? 4 : 2); i++) - //{ - // OutMid = MidFilters[i].Transform(OutMid); - //} - - //for (int i = 0; i < (DbPerOct24 ? 2 : 1); i++) - //{ - // OutHigh = HighFilters[i].Transform(OutHigh); - //} - } - } - public class Soundgoodizer - { - public float MixLevel = 0.6F; - - public SoundgoodizerFilterChannel L; - public SoundgoodizerFilterChannel R; - - public float OutL = 0; - public float OutR = 0; - - //SimpleCompressor CompressorLow; - //SimpleCompressor CompressorMid; - //SimpleCompressor CompressorHigh; - //SimpleCompressor CompressorMaster; - - public float PreGainLow = 1.78F; - public float PreGainMid = 2.09F; - public float PreGainHigh = 2.20F; - public float PreGainMaster = 1; - - public float PostGainLow = 1.91F; - public float PostGainMid = 1.00F; - public float PostGainHigh = 1.40F; - - public bool DbPerOct24; - public float SampleRate; - public float LowHz; - public float HighHz; - - // Default filter cutoffs based on Soundgoodizer Preset A from FL Studio - public Soundgoodizer(float sampleRate) : this(true, sampleRate, 200, 3000) { } - - public Soundgoodizer(bool dbPerOct24, float sampleRate, float lowHz, float highHz) - { - DbPerOct24 = dbPerOct24; - SampleRate = sampleRate; - LowHz = lowHz; - HighHz = highHz; - - L = new SoundgoodizerFilterChannel(dbPerOct24, sampleRate, lowHz, highHz); - R = new SoundgoodizerFilterChannel(dbPerOct24, sampleRate, lowHz, highHz); - - // Compressor parameters also taken from Soundgoodizer Preset A - //CompressorLow = new SimpleCompressor(2.0, 137.48, sampleRate); - //CompressorMid = new SimpleCompressor(2.0, 85.53, sampleRate); - //CompressorHigh = new SimpleCompressor(2.0, 85.53, sampleRate); - //CompressorMaster = new SimpleCompressor(2.0, 85.53, sampleRate); - } - - public void ChangeFilterParams(bool dbPerOct24, float sampleRate, float lowHz, float highHz) - { - DbPerOct24 = dbPerOct24; - SampleRate = sampleRate; - LowHz = lowHz; - HighHz = highHz; - - if (lowHz > highHz) Swap(ref highHz, ref lowHz); - L.ChangeFilterParams(dbPerOct24, sampleRate, lowHz, highHz); - R.ChangeFilterParams(dbPerOct24, sampleRate, lowHz, highHz); - } - - public void Process(float inL, float inR) - { - L.Process(inL); - R.Process(inR); - - // Apply pre-gain (Soundgoodizer Preset A) - double outLowL = L.OutLow * PreGainLow; - double outLowR = R.OutLow * PreGainLow; - double outMidL = L.OutMid * PreGainMid; - double outMidR = R.OutMid * PreGainMid; - double outHighL = L.OutHigh * PreGainHigh; - double outHighR = R.OutHigh * PreGainHigh; - - //CompressorLow.Process(ref outLowL, ref outLowR); - //CompressorMid.Process(ref outMidL, ref outMidR); - //CompressorHigh.Process(ref outHighL, ref outHighR); - - // Apply post-gain (Soundgoodizer Preset A) - outLowL *= PostGainLow; - outLowR *= PostGainLow; - outMidL *= PostGainMid; - outMidR *= PostGainMid; - outHighL *= PostGainHigh; - outHighR *= PostGainHigh; - - double outL = outLowL + outMidL + outHighL; - double outR = outLowR + outMidR + outHighR; - - outL *= PreGainMaster; - outR *= PreGainMaster; - - //CompressorMaster.Process(ref outL, ref outR); - - OutL = (float)(MixLevel * outL + (1 - MixLevel) * inL); - OutR = (float)(MixLevel * outR + (1 - MixLevel) * inR); - } - } -} \ No newline at end of file diff --git a/Assets/emulator/Soundgoodizer.cs.meta b/Assets/emulator/Soundgoodizer.cs.meta deleted file mode 100644 index 6fbe438..0000000 --- a/Assets/emulator/Soundgoodizer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4244c1f833ecf894b8ad5d41c8277cda -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/Spi.cs b/Assets/emulator/Spi.cs deleted file mode 100644 index 2cd1ec6..0000000 --- a/Assets/emulator/Spi.cs +++ /dev/null @@ -1,183 +0,0 @@ -using static OptimeGBA.Bits; -using static OptimeGBA.MemoryUtil; - -namespace OptimeGBA -{ - public enum SpiDevice : byte - { - PowerManager = 0, - Firmware = 1, - Touchscreen = 2 - } - - public enum SpiTouchscreenState - { - Ready, - Command, - } - - public unsafe sealed class Spi - { - public Nds Nds; - - public Spi(Nds nds) - { - Nds = nds; - - Flash = new SpiFlash(Nds.Provider.Firmware); - } - - // From Nocash's original DS - byte[] Id = new byte[] { 0x20, 0x40, 0x12 }; - - // SPICNT - byte BaudRate; - SpiDevice DeviceSelect; - bool TransferSize; - bool ChipSelHold; - bool EnableIrq; - bool EnableSpi; - bool Busy; - - // Flash - public SpiFlash Flash; - - // Touchscreen state - public SpiTouchscreenState TouchscreenState; - public byte TouchscreenCommand; - public byte TouchscreenDataByte; - - public ushort TouchAdcX; - public ushort TouchAdcY; - - public void SetTouchPos(uint x, uint y) - { - ushort adcX1 = GetUshort(Flash.Data, 0x3FF58); - ushort adcY1 = GetUshort(Flash.Data, 0x3FF5A); - byte scrX1 = Flash.Data[0x3FF5C]; - byte scrY1 = Flash.Data[0x3FF5D]; - ushort adcX2 = GetUshort(Flash.Data, 0x3FF5E); - ushort adcY2 = GetUshort(Flash.Data, 0x3FF60); - byte scrX2 = Flash.Data[0x3FF62]; - byte scrY2 = Flash.Data[0x3FF63]; - - // Convert screen coords to calibrated ADC touchscreen coords - TouchAdcX = (ushort)((x - (scrX1 - 1)) * (adcX2 - adcX1) / (scrX2 - scrX1) + adcX1); - TouchAdcY = (ushort)((y - (scrY1 - 1)) * (adcY2 - adcY1) / (scrY2 - scrY1) + adcY1); - } - - public void ClearTouchPos() - { - TouchAdcX = 0; - TouchAdcY = 0xFFF; - } - - public byte OutData; - - public byte ReadHwio8(uint addr) - { - byte val = 0; - switch (addr) - { - case 0x40001C0: // SPICNT B0 - val |= BaudRate; - if (Busy) val = BitSet(val, 7); - break; - case 0x40001C1: // SPICNT B1 - val |= (byte)DeviceSelect; - if (TransferSize) val = BitSet(val, 2); - if (ChipSelHold) val = BitSet(val, 3); - if (EnableIrq) val = BitSet(val, 6); - if (EnableSpi) val = BitSet(val, 7); - break; - - case 0x40001C2: // SPIDATA - // Console.WriteLine("SPI: Read! " + Hex(InData, 2)); - if (!EnableSpi) return 0; - return OutData; - } - - return val; - } - - public void WriteHwio8(uint addr, byte val) - { - switch (addr) - { - case 0x40001C0: // SPICNT B0 - BaudRate = (byte)(val & 0b11); - break; - case 0x40001C1: // SPICNT B1 - DeviceSelect = (SpiDevice)(val & 0b11); - TransferSize = BitTest(val, 2); - bool oldChipSelHold = ChipSelHold; - ChipSelHold = BitTest(val, 3); - EnableIrq = BitTest(val, 6); - EnableSpi = BitTest(val, 7); - - if (!EnableSpi) - { - ChipSelHold = false; - } - break; - - case 0x40001C2: // SPIDATA - TransferTo(val); - break; - } - } - - public void TransferTo(byte val) - { - if (EnableSpi) - { - switch (DeviceSelect) - { - case SpiDevice.Firmware: - OutData = Flash.TransferTo(val, TransferSize); - break; - case SpiDevice.Touchscreen: - TransferToTouchscreen(val); - break; - case SpiDevice.PowerManager: - // Console.WriteLine("Power manager access"); - break; - - } - } - - if (!ChipSelHold) - { - Flash.Deselect(); - TouchscreenState = SpiTouchscreenState.Ready; - } - } - - public void TransferToTouchscreen(byte val) - { - switch (TouchscreenState) - { - case SpiTouchscreenState.Ready: - TouchscreenState = SpiTouchscreenState.Command; - OutData = 0; - TouchscreenCommand = val; - TouchscreenDataByte = 0; - break; - case SpiTouchscreenState.Command: - switch ((TouchscreenCommand >> 4) & 0b111) - { - case 1: // Y position - // Shift 12-byte up left three to get start with 1-bit dummy - OutData = (byte)((TouchAdcY << 3) >> (8 * (1 - (TouchscreenDataByte & 1)))); - break; - case 5: // X position - OutData = (byte)((TouchAdcX << 3) >> (8 * (1 - (TouchscreenDataByte & 1)))); - // Console.WriteLine("Y"); - break; - } - TouchscreenDataByte++; - break; - } - } - } -} \ No newline at end of file diff --git a/Assets/emulator/Spi.cs.meta b/Assets/emulator/Spi.cs.meta deleted file mode 100644 index f0b8d9d..0000000 --- a/Assets/emulator/Spi.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: dc3ada11b34fabd45b3e4e141afd9b7b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/SpiFlash.cs b/Assets/emulator/SpiFlash.cs deleted file mode 100644 index c04c9dd..0000000 --- a/Assets/emulator/SpiFlash.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using static Util; - -namespace OptimeGBA -{ - public enum SpiFlashState - { - Ready, - Identification, - ReceiveAddress, - Reading, - Status, - TakePrefix, // For cartridges with IR and Flash - } - - public unsafe sealed class SpiFlash - { - public byte[] Data; - - public SpiFlash(byte[] data) { - Data = data; - } - - // Firmware flash state - public SpiFlashState FlashState; - public bool EnableWrite; - public byte IdIndex; - public uint Address; - public byte AddressByteNum = 0; - - // From Nocash's original DS - byte[] Id = new byte[] { 0x20, 0x40, 0x12 }; - - public byte OutData; - - public byte TransferTo(byte val, bool transferSize) - { - switch (FlashState) - { - case SpiFlashState.Ready: - // Console.WriteLine("SPI: Receive command! " + Hex(val, 2)); - OutData = 0x00; - switch (val) - { - case 0x06: - EnableWrite = true; - break; - case 0x04: - EnableWrite = false; - break; - case 0x9F: - FlashState = SpiFlashState.Identification; - IdIndex = 0; - break; - case 0x03: - FlashState = SpiFlashState.ReceiveAddress; - Address = 0; - AddressByteNum = 0; - break; - case 0x05: // Identification - // Console.WriteLine("SPI ID"); - OutData = 0x00; - break; - case 0x00: - break; - default: - throw new NotImplementedException("SPI: Unimplemented command: " + Hex(val, 2)); - } - break; - case SpiFlashState.ReceiveAddress: - // Console.WriteLine("SPI: Address byte write: " + Hex(val, 2)); - Address |= (uint)(val << ((2 - AddressByteNum) * 8)); - AddressByteNum++; - if (AddressByteNum > 2) - { - AddressByteNum = 0; - FlashState = SpiFlashState.Reading; - // Console.WriteLine("SPI: Address written: " + Hex(Address, 6)); - } - break; - case SpiFlashState.Reading: - // Console.WriteLine("SPI: Read from address: " + Hex(Address, 6)); - // Nds7.Cpu.Error("SPI"); - if (Address < 0x40000) - { - OutData = Data[Address]; - } - else - { - OutData = 0; - } - Address += transferSize ? 2U : 1U; - Address &= 0xFFFFFF; - break; - case SpiFlashState.Identification: - OutData = Id[IdIndex]; - IdIndex++; - IdIndex %= 3; - break; - } - - return OutData; - } - - public void Deselect() - { - FlashState = SpiFlashState.Ready; - } - } -} \ No newline at end of file diff --git a/Assets/emulator/SpiFlash.cs.meta b/Assets/emulator/SpiFlash.cs.meta deleted file mode 100644 index e562332..0000000 --- a/Assets/emulator/SpiFlash.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5f7e39ea1a758aa4890a88f1d00e7703 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/Timers.cs b/Assets/emulator/Timers.cs index 0edbd68..04e75bc 100644 --- a/Assets/emulator/Timers.cs +++ b/Assets/emulator/Timers.cs @@ -68,6 +68,7 @@ namespace OptimeGBA ReloadVal &= 0x00FF; ReloadVal |= ((uint)val << 8); RecalculateInterval(); + break; case 0x02: // TMCNT_H B0 PrescalerSel = (uint)(val & 0b11); @@ -103,7 +104,7 @@ namespace OptimeGBA Reload(); Timers.Scheduler.AddEventRelative(GetSchedulerId(), CalculateOverflowCycles(), TimerOverflow); EnableCycles = CalculateAlignedCurrentTicks(); - // Console.WriteLine($"[Timer] {Id} Enable"); + // Debug.Log($"[Timer] {Id} Enable"); } Enabled = true; @@ -212,7 +213,7 @@ namespace OptimeGBA } EnableCycles = CalculateAlignedCurrentTicks() - cyclesLate; - // Console.WriteLine($"[Timer] {Id} Overflow"); + // Debug.Log($"[Timer] {Id} Overflow"); } public void UnscheduledTimerIncrement() diff --git a/Assets/emulator/Timers.cs.meta b/Assets/emulator/Timers.cs.meta index ca3103c..4df9d81 100644 --- a/Assets/emulator/Timers.cs.meta +++ b/Assets/emulator/Timers.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 298e97a62e33e8c428f0dd465f1382f9 +guid: 78841f13936f80a44b825d87e775adea MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Util.cs b/Assets/emulator/Util.cs similarity index 71% rename from Assets/Util.cs rename to Assets/emulator/Util.cs index 2b22830..68a68bf 100644 --- a/Assets/Util.cs +++ b/Assets/emulator/Util.cs @@ -11,18 +11,18 @@ static class Util public static void WriteDebug(string text) { - // Console.WriteLine(text); + // Debug.Log(text); } - public static string Pad(string n, int width, char padChar) - { - return n.Length >= width ? n : string.Join(padChar, new int[width - (n.Length + 1)]) + n; - } + //public static string Pad(string n, int width, char padChar) + //{ + // return n.Length >= width ? n : string.Join(padChar, new int[width - (n.Length + 1)]) + n; + //} - public static string RightPad(string n, int width, char z) - { - return n.Length >= width ? n : n + string.Join(z, new int[width - (n.Length + 1)]); - } + //public static string RightPad(string n, int width, char z) + //{ + // return n.Length >= width ? n : n + string.Join(z, new int[width - (n.Length + 1)]); + //} public static string Hex(long i, int digits) { diff --git a/Assets/Util.cs.meta b/Assets/emulator/Util.cs.meta similarity index 83% rename from Assets/Util.cs.meta rename to Assets/emulator/Util.cs.meta index d7fd294..b3e0983 100644 --- a/Assets/Util.cs.meta +++ b/Assets/emulator/Util.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1a5554b2d514cfb40a6352bbea330fe6 +guid: 98d3717b73bea1b4b9b81c2493c8c47f MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/VideoProvider.cs b/Assets/emulator/VideoProvider.cs new file mode 100644 index 0000000..68f1a70 --- /dev/null +++ b/Assets/emulator/VideoProvider.cs @@ -0,0 +1,90 @@ +using OptimeGBA; +using System; +using System.Runtime.InteropServices; +using UnityEngine; +using UnityEngine.UI; + + +public class VideoProvider : MonoBehaviour +{ + public RawImage m_drawCanvas; + private RectTransform m_drawCanvasrect; + private IntPtr wrapTexBufferPointer; + private Texture2D wrapTex; + private int TexBufferSize; + + + uint[] wrapTexBuffer = new uint[240 * 160]; + Color32[] DisplayColorBuffer = new Color32[240 * 160]; + + + public void OnRenderFrame() + { + if (wrapTex == null) + { + wrapTex = new Texture2D(240, 160, TextureFormat.RGBA32, false); + wrapTex.filterMode = FilterMode.Point; + //wrapTexBuffer = screenData; + + // ̶飬ֹƶ + GCHandle handle = GCHandle.Alloc(wrapTexBuffer, GCHandleType.Pinned); + // ȡָ + wrapTexBufferPointer = handle.AddrOfPinnedObject(); + m_drawCanvas.texture = wrapTex; + TexBufferSize = wrapTexBuffer.Length * 4; + + + m_drawCanvasrect = m_drawCanvas.GetComponent(); + float targetWidth = ((float)240 / 160) * m_drawCanvasrect.rect.height; + m_drawCanvasrect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, targetWidth); + + } + + DrawDisplay(); + } + public void DrawDisplay() + { + var buf = Emulator.instance.ShowBackBuf ? Emulator.instance.gba.Ppu.Renderer.ScreenBack : Emulator.instance.gba.Ppu.Renderer.ScreenFront; + unsafe + { + for (uint i = 0; i < 240 * 160; i++) + { + wrapTexBuffer[i] = PpuRenderer.ColorLutCorrected[buf[i] & 0x7FFF]; + fixed (uint* p = &wrapTexBuffer[i]) + { + byte* bp = (byte*)p; + DisplayColorBuffer[i] = new Color32(*(bp++), *(bp++), *(bp++), *(bp++)); + } + } + } + + //wrapTex.LoadRawTextureData(wrapTexBufferPointer, TexBufferSize); + wrapTex.SetPixels32(DisplayColorBuffer, 0); + wrapTex.Apply(); + + } + + //public void SetDrawData(uint[] screenData, byte[] lineColorMode, int screenWidth, int screenHeight) + //{ + // if (wrapTex == null) + // { + // //wrapTex = new Texture2D(272, 240, TextureFormat.BGRA32, false); + // wrapTex = new Texture2D(272, 240, TextureFormat.RGBA32, false); + // wrapTex.filterMode = FilterMode.Point; + // wrapTexBuffer = screenData; + + // // ̶飬ֹƶ + // GCHandle handle = GCHandle.Alloc(wrapTexBuffer, GCHandleType.Pinned); + // // ȡָ + // wrapTexBufferPointer = handle.AddrOfPinnedObject(); + + // Image.texture = wrapTex; + // Image.material.SetTexture("_MainTex", wrapTex); + + // TexBufferSize = wrapTexBuffer.Length * 4; + // } + + // wrapTex.LoadRawTextureData(wrapTexBufferPointer, TexBufferSize); + // wrapTex.Apply(); + //} +} \ No newline at end of file diff --git a/Assets/emulator/VideoProvider.cs.meta b/Assets/emulator/VideoProvider.cs.meta new file mode 100644 index 0000000..260e9ac --- /dev/null +++ b/Assets/emulator/VideoProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 331cd2e4e0a49874cab11aa18b69e827 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/emulator/WavWriter.cs b/Assets/emulator/WavWriter.cs deleted file mode 100644 index 13c98b1..0000000 --- a/Assets/emulator/WavWriter.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System.IO; -using System.Collections.Generic; - -public class WavWriter { - public const int BitsPerSample = 16; - public const int Channels = 2; - public int SampleRate; - - public int RecordBufferAt; - - public List RecordBuffer = new List(); - - public WavWriter(int sampleRate) { - SampleRate = sampleRate; - } - - public void AddSample(short valL, short valR) { - RecordBuffer.Add(valL); - RecordBuffer.Add(valR); - RecordBufferAt += 2; - } - - public void Save(string path) { - var file = File.OpenWrite(path); - - // RIFF header - file.WriteByte(0x52); - file.WriteByte(0x49); - file.WriteByte(0x46); - file.WriteByte(0x46); - - int size = RecordBuffer.Count * Channels * (BitsPerSample / 2) - 8 + 44; - file.WriteByte((byte)(size >> 0)); - file.WriteByte((byte)(size >> 8)); - file.WriteByte((byte)(size >> 16)); - file.WriteByte((byte)(size >> 24)); - - // WAVE - file.WriteByte(0x57); - file.WriteByte(0x41); - file.WriteByte(0x56); - file.WriteByte(0x45); - - // Subchunk1ID "fmt " - file.WriteByte(0x66); - file.WriteByte(0x6d); - file.WriteByte(0x74); - file.WriteByte(0x20); - - // Subchunk1Size - file.WriteByte(16); - file.WriteByte(0); - file.WriteByte(0); - file.WriteByte(0); - - // AudioFormat - file.WriteByte(1); - file.WriteByte(0); - - // 2 channels - file.WriteByte(Channels); - file.WriteByte(0); - - // Sample rate - file.WriteByte((byte)(SampleRate >> 0)); - file.WriteByte((byte)(SampleRate >> 8)); - file.WriteByte((byte)(SampleRate >> 16)); - file.WriteByte((byte)(SampleRate >> 24)); - - // ByteRate - // SampleRate * NumChannels * BitsPerSample/8 - int byteRate = SampleRate * Channels * (BitsPerSample / 8); - file.WriteByte((byte)(byteRate >> 0)); - file.WriteByte((byte)(byteRate >> 8)); - file.WriteByte((byte)(byteRate >> 16)); - file.WriteByte((byte)(byteRate >> 24)); - - // BlockAlign - // NumChannels * BitsPerSample / 8 - int blockAlign = Channels * (BitsPerSample / 8); - file.WriteByte((byte)(blockAlign >> 0)); - file.WriteByte((byte)(blockAlign >> 8)); - - // BitsPerSample - file.WriteByte(16); - file.WriteByte(0); - - // Subchunk2ID "data" - file.WriteByte(0x64); - file.WriteByte(0x61); - file.WriteByte(0x74); - file.WriteByte(0x61); - - // NumSamples * NumChannels * BitsPerSample/8 - int subchunk2Size = RecordBufferAt * 2 * (BitsPerSample / 8); - file.WriteByte((byte)(subchunk2Size >> 0)); - file.WriteByte((byte)(subchunk2Size >> 8)); - file.WriteByte((byte)(subchunk2Size >> 16)); - file.WriteByte((byte)(subchunk2Size >> 24)); - - for (int i = 0; i < RecordBufferAt; i++) { - file.WriteByte((byte)(RecordBuffer[i] >> 0)); - file.WriteByte((byte)(RecordBuffer[i] >> 8)); - } - } -} \ No newline at end of file diff --git a/Assets/emulator/WavWriter.cs.meta b/Assets/emulator/WavWriter.cs.meta deleted file mode 100644 index 16e4a8e..0000000 --- a/Assets/emulator/WavWriter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3268f3abb89a2bb448bf321f561a1c51 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/emulator/cpu.meta b/Assets/emulator/cpu.meta index 2425e9e..7e4537f 100644 --- a/Assets/emulator/cpu.meta +++ b/Assets/emulator/cpu.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a84b3ac2aebc05e42b619bc3aa18d958 +guid: 2c6387663f6d88942855a2078226b79d folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/emulator/cpu/Arm.cs b/Assets/emulator/cpu/Arm.cs index 94b940e..a91b831 100644 --- a/Assets/emulator/cpu/Arm.cs +++ b/Assets/emulator/cpu/Arm.cs @@ -1,7 +1,6 @@ +using System.Runtime.CompilerServices; using static OptimeGBA.Bits; using static Util; -using System.Numerics; -using System.Runtime.CompilerServices; namespace OptimeGBA { @@ -9,6 +8,20 @@ namespace OptimeGBA public unsafe static class Arm { + public static uint popcount_8(uint n) + { + uint m = 0x01010101; + uint c = n & m; + int i; + for (i = 0; i < 7; i++) + { + n >>= 1; + c += n & m; + } + c += c >> 8; + c += c >> 16; + return c & 0x3f; + } public static void SWI(Arm7 arm7, uint ins) { arm7.SPSR_svc = arm7.GetCPSR(); @@ -52,7 +65,7 @@ namespace OptimeGBA // String regs = ""; - uint bitsSet = (uint)BitOperations.PopCount(ins & 0xFFFF); + uint bitsSet = popcount_8(ins & 0xFFFF); uint writebackValue; if (U) { @@ -232,7 +245,7 @@ namespace OptimeGBA // String regs = ""; - uint bitsSet = (uint)BitOperations.PopCount(ins & 0xFFFF); + uint bitsSet = popcount_8(ins & 0xFFFF); uint writebackValue; if (U) { @@ -1733,7 +1746,7 @@ namespace OptimeGBA } else { - arm7.R[rd] = (uint)BitOperations.LeadingZeroCount(rmVal); + arm7.R[rd] = 32 - popcount_8(rmVal);//zero_count } } diff --git a/Assets/emulator/cpu/Arm.cs.meta b/Assets/emulator/cpu/Arm.cs.meta index 05ba135..f25e5fd 100644 --- a/Assets/emulator/cpu/Arm.cs.meta +++ b/Assets/emulator/cpu/Arm.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 4fd0e52258ac1ba48ba82b603fbc5462 +guid: fd32d89589f585b4bbd5b339286502ee MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/cpu/Arm7.cs b/Assets/emulator/cpu/Arm7.cs index 452e8a2..e4b5988 100644 --- a/Assets/emulator/cpu/Arm7.cs +++ b/Assets/emulator/cpu/Arm7.cs @@ -76,7 +76,7 @@ namespace OptimeGBA ~Arm7() { - MemoryUtil.FreeUnmanagedArray(R); + FreeUnmanagedArray(R); MemoryUtil.FreeUnmanagedArray(Timing8And16); MemoryUtil.FreeUnmanagedArray(Timing32); @@ -1219,8 +1219,8 @@ namespace OptimeGBA [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write8(uint addr, byte val) { - // if (addr == 0x300402C) Console.WriteLine("DMA1 Write8: " + Util.HexN(GetCurrentInstrAddr(), 8)); - // if (addr == 0x300465C) Console.WriteLine("DMA2 Write8: " + Util.HexN(GetCurrentInstrAddr(), 8)); + // if (addr == 0x300402C) Debug.Log("DMA1 Write8: " + Util.HexN(GetCurrentInstrAddr(), 8)); + // if (addr == 0x300465C) Debug.Log("DMA2 Write8: " + Util.HexN(GetCurrentInstrAddr(), 8)); InstructionCycles += Timing8And16[(addr >> 24) & 0xF]; Mem.Write8(addr, val); @@ -1229,8 +1229,8 @@ namespace OptimeGBA [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write16(uint addr, ushort val) { - // if (addr == 0x300402C) Console.WriteLine("DMA1 Write16: " + Util.HexN(GetCurrentInstrAddr(), 8)); - // if (addr == 0x300465C) Console.WriteLine("DMA2 Write16: " + Util.HexN(GetCurrentInstrAddr(), 8)); + // if (addr == 0x300402C) Debug.Log("DMA1 Write16: " + Util.HexN(GetCurrentInstrAddr(), 8)); + // if (addr == 0x300465C) Debug.Log("DMA2 Write16: " + Util.HexN(GetCurrentInstrAddr(), 8)); InstructionCycles += Timing8And16[(addr >> 24) & 0xF]; Mem.Write16(addr, val); @@ -1239,8 +1239,8 @@ namespace OptimeGBA [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write32(uint addr, uint val) { - // if (addr == 0x300402C) Console.WriteLine("DMA1 Write32: " + Util.HexN(GetCurrentInstrAddr(), 8)); - // if (addr == 0x300465C) Console.WriteLine("DMA2 Write32: " + Util.HexN(GetCurrentInstrAddr(), 8)); + // if (addr == 0x300402C) Debug.Log("DMA1 Write32: " + Util.HexN(GetCurrentInstrAddr(), 8)); + // if (addr == 0x300465C) Debug.Log("DMA2 Write32: " + Util.HexN(GetCurrentInstrAddr(), 8)); InstructionCycles += Timing32[(addr >> 24) & 0xF]; Mem.Write32(addr, val); diff --git a/Assets/emulator/cpu/Arm7.cs.meta b/Assets/emulator/cpu/Arm7.cs.meta index d9c2bed..c41b8fe 100644 --- a/Assets/emulator/cpu/Arm7.cs.meta +++ b/Assets/emulator/cpu/Arm7.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: bdbb33da106a94d408b21f7b02ea9466 +guid: 4d301843e4c74ee4385e087f8972482f MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/cpu/Thumb.cs b/Assets/emulator/cpu/Thumb.cs index ea48967..8d87154 100644 --- a/Assets/emulator/cpu/Thumb.cs +++ b/Assets/emulator/cpu/Thumb.cs @@ -998,7 +998,7 @@ namespace OptimeGBA // String regs = ""; uint addr = arm7.R[13]; - uint registerCount = (uint)BitOperations.PopCount(ins & 0x1FFU); + uint registerCount = Arm.popcount_8(ins & 0x1FFU); arm7.R[13] = addr + registerCount * 4; if (BitTest(ins, 0)) { /* regs += "R0 "; */ arm7.R[0] = arm7.Read32(addr & ~3u); addr += 4; } @@ -1032,7 +1032,7 @@ namespace OptimeGBA arm7.R[15] = arm7.Read32(addr & ~3u); arm7.FlushPipeline(); } - System.Console.WriteLine("POP empty Rlist"); + //Debug.Log("POP empty Rlist"); arm7.R[13] += 0x40; } @@ -1047,7 +1047,7 @@ namespace OptimeGBA uint addr = arm7.R[13]; - addr -= 4 * (uint)BitOperations.PopCount((uint)ins & 0x1FF); + addr -= 4 * Arm.popcount_8((uint)ins & 0x1FF); if (BitTest(ins, 0)) { /* regs += "R0 "; */ arm7.Write32(addr & ~3u, arm7.R[0]); addr += 4; arm7.R[13] -= 4; } if (BitTest(ins, 1)) { /* regs += "R1 "; */ arm7.Write32(addr & ~3u, arm7.R[1]); addr += 4; arm7.R[13] -= 4; } @@ -1153,7 +1153,7 @@ namespace OptimeGBA // String regs = ""; uint registerList = ins & 0xFFU; - uint registerCount = (uint)BitOperations.PopCount(registerList); + uint registerCount = Arm.popcount_8(registerList); uint writebackVal = arm7.R[rn] + registerCount * 4; arm7.R[rn] = writebackVal; @@ -1197,7 +1197,7 @@ namespace OptimeGBA arm7.R[15] += 2; uint registerList = ins & 0xFFU; - uint registerCount = (uint)BitOperations.PopCount(registerList); + uint registerCount = Arm.popcount_8(registerList); uint writebackVal = arm7.R[rn] + registerCount * 4; uint register = 0; diff --git a/Assets/emulator/cpu/Thumb.cs.meta b/Assets/emulator/cpu/Thumb.cs.meta index 932bbbd..0d13027 100644 --- a/Assets/emulator/cpu/Thumb.cs.meta +++ b/Assets/emulator/cpu/Thumb.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f4c625315174d2b449589c3b015a86c4 +guid: 7b72164ac8d76e54b9bf01f1fa4db6a1 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/saving.meta b/Assets/emulator/saving.meta index f40f3b1..3b00d0a 100644 --- a/Assets/emulator/saving.meta +++ b/Assets/emulator/saving.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 30b648fdc4aff1d43b6fe55d747a6dc2 +guid: bd6b71625a1769b4098d821997132026 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/emulator/saving/Eeprom.cs b/Assets/emulator/saving/Eeprom.cs index 8b5e153..c4fb111 100644 --- a/Assets/emulator/saving/Eeprom.cs +++ b/Assets/emulator/saving/Eeprom.cs @@ -63,7 +63,7 @@ namespace OptimeGBA { if (Gba.Dma.DmaLock) { - // Console.WriteLine("[EEPROM] Read from DMA"); + // Debug.Log("[EEPROM] Read from DMA"); } byte val = 0; @@ -72,7 +72,7 @@ namespace OptimeGBA if (ReadBitsRemaining <= 64) { val = ReadBitEEPROM(); - // Console.WriteLine($"[EEPROM] Read (addr: {Util.Hex(ReadAddr, 4)}) {val}, bits remaining: " + ReadBitsRemaining); + // Debug.Log($"[EEPROM] Read (addr: {Util.Hex(ReadAddr, 4)}) {val}, bits remaining: " + ReadBitsRemaining); ReadAddr++; } else @@ -94,7 +94,7 @@ namespace OptimeGBA { if (Gba.Dma.DmaLock) { - // Console.WriteLine("[EEPROM] Write from DMA"); + // Debug.Log("[EEPROM] Write from DMA"); } bool bit = BitTest(val, 0); @@ -103,7 +103,7 @@ namespace OptimeGBA case EepromState.Ready: if (bit) { - // Console.WriteLine("[EEPROM] Request started"); + // Debug.Log("[EEPROM] Request started"); State = EepromState.StartRequest; } break; @@ -111,13 +111,13 @@ namespace OptimeGBA BitsRemaining = Size == EepromSize.Eeprom64k ? 14U : 6U; if (bit) { - // Console.WriteLine("[EEPROM] Receiving read address"); + // Debug.Log("[EEPROM] Receiving read address"); State = EepromState.ReceiveAddrForRead; ReadAddr = 0; } else { - // Console.WriteLine("[EEPROM] Receiving write address"); + // Debug.Log("[EEPROM] Receiving write address"); State = EepromState.ReceiveAddrForWrite; Addr = 0; } @@ -130,11 +130,11 @@ namespace OptimeGBA ReadAddr &= 0x3FF; BitsRemaining--; - // Console.WriteLine($"[EEPROM] Setting read address ({bit}), bits remaining: {BitsRemaining}"); + // Debug.Log($"[EEPROM] Setting read address ({bit}), bits remaining: {BitsRemaining}"); if (BitsRemaining == 0) { - // Console.WriteLine("[EEPROM] Read address written: " + Util.Hex(ReadAddr, 4)); + // Debug.Log("[EEPROM] Read address written: " + Util.Hex(ReadAddr, 4)); State = EepromState.ReceiveTerminatingZero; BitsRemaining = 68; ReadBitsRemaining = 68; @@ -149,13 +149,13 @@ namespace OptimeGBA Addr &= 0x3FF; BitsRemaining--; - // Console.WriteLine($"[EEPROM] Setting write address ({bit}), bits remaining: {BitsRemaining}"); + // Debug.Log($"[EEPROM] Setting write address ({bit}), bits remaining: {BitsRemaining}"); if (BitsRemaining == 0) { BitsRemaining = 64; State = EepromState.ReceiveDataForWrite; - // Console.WriteLine("[EEPROM] Write address set: " + Util.Hex(Addr, 4)); + // Debug.Log("[EEPROM] Write address set: " + Util.Hex(Addr, 4)); } } break; @@ -163,20 +163,20 @@ namespace OptimeGBA if (BitsRemaining > 0) { WriteBitEEPROM(bit); - // Console.WriteLine($"[EEPROM] Write (addr: {Util.Hex(Addr, 4)}) {Convert.ToByte(bit)}, bits remaining: " + BitsRemaining); + // Debug.Log($"[EEPROM] Write (addr: {Util.Hex(Addr, 4)}) {Convert.ToByte(bit)}, bits remaining: " + BitsRemaining); Addr++; BitsRemaining--; if (BitsRemaining == 0) { - // Console.WriteLine($"[EEPROM] Write finished"); + // Debug.Log($"[EEPROM] Write finished"); State = EepromState.Ready; } } break; case EepromState.ReceiveTerminatingZero: State = EepromState.Ready; - // Console.WriteLine($"[EEPROM] Received terminating zero"); + // Debug.Log($"[EEPROM] Received terminating zero"); break; } } diff --git a/Assets/emulator/saving/Eeprom.cs.meta b/Assets/emulator/saving/Eeprom.cs.meta index af7c651..4a3c720 100644 --- a/Assets/emulator/saving/Eeprom.cs.meta +++ b/Assets/emulator/saving/Eeprom.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 02514cda0b41acb43b39679713973344 +guid: fa9a22a851fb8794785263965dc0ba95 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/saving/Flash.cs b/Assets/emulator/saving/Flash.cs index dbcd0cb..a06f644 100644 --- a/Assets/emulator/saving/Flash.cs +++ b/Assets/emulator/saving/Flash.cs @@ -90,7 +90,7 @@ namespace OptimeGBA } } - // Console.WriteLine("Flash.Read8 addr:" + HexN(addr, 8) + " val:" + HexN(val, 2)); + // Debug.Log("Flash.Read8 addr:" + HexN(addr, 8) + " val:" + HexN(val, 2)); // Gba.Arm7.Error("read"); return val; @@ -127,14 +127,14 @@ namespace OptimeGBA case FlashState.InitialState: if (addr == 0xE005555 && val == 0xAA) { - // Console.WriteLine("pre-command 0 sent"); + // Debug.Log("pre-command 0 sent"); State = FlashState.PreCommand0; } break; case FlashState.PreCommand0: if (addr == 0xE002AAA && val == 0x55) { - // Console.WriteLine("pre-command 1 sent, ready to receive commands"); + // Debug.Log("pre-command 1 sent, ready to receive commands"); State = FlashState.PreCommand1; } break; @@ -147,24 +147,24 @@ namespace OptimeGBA switch (val) { case 0x90: - // Console.WriteLine("enter identification mode"); + // Debug.Log("enter identification mode"); IdentificationMode = true; break; case 0xF0: - // Console.WriteLine("exit identification mode"); + // Debug.Log("exit identification mode"); // Gba.Arm7.Error("here"); IdentificationMode = false; break; case 0x80: - // Console.WriteLine("preparing to erase"); + // Debug.Log("preparing to erase"); StateSecondary = FlashStateSecondary.PrepareEraseCommand; break; case 0xB0: - // Console.WriteLine("preparing to set bank"); + // Debug.Log("preparing to set bank"); PrepareSetBank = true; break; case 0xA0: - // Console.WriteLine("preparing to write"); + // Debug.Log("preparing to write"); PrepareWrite = true; break; } diff --git a/Assets/emulator/saving/Flash.cs.meta b/Assets/emulator/saving/Flash.cs.meta index cd21824..73804c8 100644 --- a/Assets/emulator/saving/Flash.cs.meta +++ b/Assets/emulator/saving/Flash.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1c16b6ed7731d8241808dee15c595b1a +guid: 15f55003531599d49a19bd9d3f1fa02b MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/saving/NullSaveProvider.cs.meta b/Assets/emulator/saving/NullSaveProvider.cs.meta index 98ef998..b5564d8 100644 --- a/Assets/emulator/saving/NullSaveProvider.cs.meta +++ b/Assets/emulator/saving/NullSaveProvider.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: cdf64d6c1dcbdd04086faacf9d434ae4 +guid: b27e23c59e24720458146eac1ee96ed4 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/saving/SaveProvider.cs.meta b/Assets/emulator/saving/SaveProvider.cs.meta index 4bc13ac..c0fbaa8 100644 --- a/Assets/emulator/saving/SaveProvider.cs.meta +++ b/Assets/emulator/saving/SaveProvider.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 330b8a9bc8cbda54888256ca7fdf4532 +guid: 683894b29367b7043910cbca0ff21762 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/emulator/saving/Sram.cs.meta b/Assets/emulator/saving/Sram.cs.meta index 373d4fc..65db06c 100644 --- a/Assets/emulator/saving/Sram.cs.meta +++ b/Assets/emulator/saving/Sram.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9eaade4d84ac1dc40a7f22e635f80b39 +guid: 95ddaaafdb3cbe24eb7921237c5862c4 MonoImporter: externalObjects: {} serializedVersion: 2