From 2121107d1a43e86f5154c855c02c738f624af6de Mon Sep 17 00:00:00 2001 From: feos Date: Mon, 24 Dec 2018 01:59:15 +0300 Subject: [PATCH 01/15] gpgx tracer: pc & 0xFFFFFF --- BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs index 8fca3a8e16..377a6ab7be 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs @@ -23,7 +23,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx { var regs = DebuggableCore.GetCpuFlagsAndRegisters(); uint pc = (uint)regs["M68K PC"].Value; - var disasm = Disassembler.Disassemble(MemoryDomains.SystemBus, pc, out int length); + var disasm = Disassembler.Disassemble(MemoryDomains.SystemBus, pc & 0xFFFFFF, out int length); var traceInfo = new TraceInfo { From 62c178ff2e7a969e3d95af12fb7708cc9ca1c788 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 24 Dec 2018 12:33:09 -0600 Subject: [PATCH 02/15] GBHawk: add default bindings --- Assets/defctrl.json | 3020 +++++++++-------- .../config/ControllerConfig.cs | 2 + 2 files changed, 1527 insertions(+), 1495 deletions(-) diff --git a/Assets/defctrl.json b/Assets/defctrl.json index 64ab6bdc4a..dabbc31374 100644 --- a/Assets/defctrl.json +++ b/Assets/defctrl.json @@ -1,1499 +1,1529 @@ { - "AllTrollers": { - "LibRetro Controls": { - "P1 RetroPad Up": "UpArrow,J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 RetroPad Down": "DownArrow,J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 RetroPad Left": "LeftArrow,J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 RetroPad Right": "RightArrow,J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 RetroPad Select": "Space, J1 B9, X1 Back", - "P1 RetroPad Start": "Return, J1 B10, X1 Start", - "P1 RetroPad Y": "A, J1 B1, X1 X", - "P1 RetroPad B": "Z, J1 B2, X1 A", - "P1 RetroPad X": "S, J1 B4, X1 Y", - "P1 RetroPad A": "X, J1 B3, X1 B", - "P1 RetroPad L": "W, J1 B5, X1 LeftShoulder", - "P1 RetroPad R": "E, J1 B6, X1 RightShoulder", - "P2 RetroPad Up": "", - "P2 RetroPad Down": "", - "P2 RetroPad Left": "", - "P2 RetroPad Right": "", - "P2 RetroPad Select": "", - "P2 RetroPad Start": "", - "P2 RetroPad Y": "", - "P2 RetroPad B": "", - "P2 RetroPad X": "", - "P2 RetroPad A": "", - "P2 RetroPad L": "", - "P2 RetroPad R": "", - "Pointer Pressed": "WMouse L", - "Key Backspace": "Backspace", - "Key Tab": "Tab", - "Key Clear": "", - "Key Return": "Return", - "Key Pause": "", - "Key Escape": "Escape", - "Key Space": "Space", - "Key Exclaim": "", - "Key QuoteDbl": "", - "Key Hash": "", - "Key Dollar": "", - "Key Ampersand": "", - "Key Quote": "", - "Key LeftParen": "", - "Key RightParen": "", - "Key Asterisk": "", - "Key Plus": "", - "Key Comma": "Comma", - "Key Minus": "Minus", - "Key Period": "Period", - "Key Slash": "Slash", - "Key 0": "D0", - "Key 1": "D1", - "Key 2": "D2", - "Key 3": "D3", - "Key 4": "D4", - "Key 5": "D5", - "Key 6": "D6", - "Key 7": "D7", - "Key 8": "D8", - "Key 9": "D9", - "Key Colon": "", - "Key Semicolon": "Semicolon", - "Key Less": "", - "Key Equals": "Equals", - "Key Greater": "", - "Key Question": "", - "Key At": "", - "Key LeftBracket": "LeftBracket", - "Key Backslash": "Backslash", - "Key RightBracket": "RightBracket", - "Key Caret": "", - "Key Underscore": "", - "Key Backquote": "Grave", - "Key A": "A", - "Key B": "B", - "Key C": "C", - "Key D": "D", - "Key E": "E", - "Key F": "F", - "Key G": "G", - "Key H": "H", - "Key I": "I", - "Key J": "J", - "Key K": "K", - "Key L": "L", - "Key M": "M", - "Key N": "N", - "Key O": "O", - "Key P": "P", - "Key Q": "Q", - "Key R": "R", - "Key S": "S", - "Key T": "T", - "Key U": "U", - "Key V": "V", - "Key W": "W", - "Key X": "X", - "Key Y": "Y", - "Key Z": "Z", - "Key Delete": "Delete", - "Key KP0": "NumberPad0", - "Key KP1": "NumberPad1", - "Key KP2": "NumberPad2", - "Key KP3": "NumberPad3", - "Key KP4": "NumberPad4", - "Key KP5": "NumberPad5", - "Key KP6": "NumberPad6", - "Key KP7": "NumberPad7", - "Key KP8": "NumberPad8", - "Key KP9": "NumberPad9", - "Key KP_Period": "NumberPadPeriod", - "Key KP_Divide": "NumberPadSlash", - "Key KP_Multiply": "NumberPadStar", - "Key KP_Minus": "NumberPadMinus", - "Key KP_Plus": "NumberPadPlus", - "Key KP_Enter": "NumberPadEnter", - "Key KP_Equals": "", - "Key Up": "UpArrow", - "Key Down": "DownArrow", - "Key Left": "LeftArrow", - "Key Insert": "LeftControl", - "Key Home": "Home", - "Key End": "End", - "Key PageUp": "PageUp", - "Key PageDown": "PageDown", - "Key F1": "F1", - "Key F2": "F2", - "Key F3": "F3", - "Key F4": "F4", - "Key F5": "F5", - "Key F6": "F6", - "Key F7": "F7", - "Key F8": "F8", - "Key F9": "F9", - "Key F10": "F10", - "Key F11": "F11", - "Key F12": "F12", - "Key F13": "", - "Key F14": "", - "Key F15": "", - "Key NumLock": "NumberLock", - "Key CapsLock": "CapsLock", - "Key ScrollLock": "ScrollLock", - "Key RShift": "RightShift", - "Key LShift": "LeftShift", - "Key RCtrl": "RightControl", - "Key LCtrl": "LeftControl", - "Key RAlt": "RightAlt", - "Key LAlt": "LeftAlt", - "Key RMeta": "", - "Key LMeta": "", - "Key LSuper": "", - "Key RSuper": "", - "Key Mode": "", - "Key Compose": "", - "Key Help": "", - "Key Print": "", - "Key SysReq": "", - "Key Break": "", - "Key Menu": "Applications", - "Key Power": "", - "Key Euro": "", - "Key Undo": "", - "Key Right": "RightArrow" - }, - "NES Controller": { - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 Start": "Return, J1 B10, X1 Start", - "P1 Select": "Space, J1 B9, X1 Back", - "P1 B": "Z, J1 B1, X1 X", - "P1 A": "X, J1 B2, X1 A", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 Start": "", - "P2 Select": "", - "P2 B": "", - "P2 A": "", - "P2 Fire": "WMouse L", - "P2 Microphone": "", - "P3 Fire": "WMouse L", - "Reset": "", - "Power": "" - }, - "SNES Controller": { - "Reset": "", - "Power": "", - "P1 Up": "UpArrow,J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow,J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow,J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow,J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 Select": "Space, J1 B9, X1 Back", - "P1 Start": "Return, J1 B10, X1 Start", - "P1 Y": "A, J1 B1, X1 X", - "P1 X": "S, J1 B4, X1 Y", - "P1 B": "Z, J1 B2, X1 A", - "P1 A": "X, J1 B3, X1 B", - "P1 L": "W, J1 B5, X1 LeftShoulder", - "P1 R": "E, J1 B6, X1 RightShoulder", - "P1 Mouse Left": "Z, J1 B1, X1 X", - "P1 Mouse Right": "X, J1 B2, X1 A", - "P2 Trigger": "Z, J1 B1, X1 X", - "P2 Cursor": "X, J1 B2, X1 A", - "P2 Turbo": "A, J1 B3 X1 Y", - "P2 Pause": "S, J1 B4 X1 B" - }, - "Nintento 64 Controller": { - "P1 A Up": "UpArrow, J1 POV1U", - "P1 A Down": "DownArrow, J1 POV1D", - "P1 A Left": "LeftArrow, J1 POV1L", - "P1 A Right": "RightArrow, J1 POV1R", - "P1 DPad U": "X1 DpadUp", - "P1 DPad D": "X1 DpadDown", - "P1 DPad L": "X1 DpadLeft", - "P1 DPad R": "X1 DpadRight", - "P1 Start": "Return, J1 B10, X1 Start", - "P1 Z": "D, J1 B3, X1 B", - "P1 B": "S, J1 B1, X1 X", - "P1 A": "A, J1 B2, X1 A", - "P1 C Up": "NumberPad8, J1 RotationZ-, X1 RStickUp", - "P1 C Down": "NumberPad2, J1 RotationZ+, X1 RStickDown", - "P1 C Left": "NumberPad4, J1 Z-, X1 RStickLeft", - "P1 C Right": "NumberPad6, J1 Z+, X1 RStickRight", - "P1 L": "Q, J1 B5, X1 LeftShoulder", - "P1 R": "W, J1 B6, X1 RightShoulder", - "P2 X Axis": "", - "P2 Y Axis": "", - "P2 A Up": "", - "P2 A Down": "", - "P2 A Left": "", - "P2 A Right": "", - "P2 DPad U": "", - "P2 DPad D": "", - "P2 DPad L": "", - "P2 DPad R": "", - "P2 Start": "", - "P2 Z": "", - "P2 B": "", - "P2 A": "", - "P2 C Up": "", - "P2 C Down": "", - "P2 C Left": "", - "P2 C Right": "", - "P2 L": "", - "P2 R": "", - "P3 X Axis": "", - "P3 Y Axis": "", - "P3 A Up": "", - "P3 A Down": "", - "P3 A Left": "", - "P3 A Right": "", - "P3 DPad U": "", - "P3 DPad D": "", - "P3 DPad L": "", - "P3 DPad R": "", - "P3 Start": "", - "P3 Z": "", - "P3 B": "", - "P3 A": "", - "P3 C Up": "", - "P3 C Down": "", - "P3 C Left": "", - "P3 C Right": "", - "P3 L": "", - "P3 R": "", - "P4 X Axis": "", - "P4 Y Axis": "", - "P4 A Up": "", - "P4 A Down": "", - "P4 A Left": "", - "P4 A Right": "", - "P4 DPad U": "", - "P4 DPad D": "", - "P4 DPad L": "", - "P4 DPad R": "", - "P4 Start": "", - "P4 Z": "", - "P4 B": "", - "P4 A": "", - "P4 C Up": "", - "P4 C Down": "", - "P4 C Left": "", - "P4 C Right": "", - "P4 L": "", - "P4 R": "", - "Reset": "", - "Power": "" - }, - "Gameboy Controller": { - "Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "Start": "Return, J1 B10, X1 Start", - "Select": "Space, J1 B9, X1 Back", - "B": "Z, J1 B1, X1 X", - "A": "X, J1 B2, X1 A", - "Power": "", - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 Start": "Return, J1 B10, X1 Start", - "P1 Select": "Space, J1 B9, X1 Back", - "P1 B": "Z, J1 B1, X1 X", - "P1 A": "X, J1 B2, X1 A" - }, - "GBA Controller": { - "Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "Start": "Return, J1 B10, X1 Start", - "Select": "Space, J1 B9, X1 Back", - "B": "Z, J1 B1, X1 X", - "A": "X, J1 B2, X1 A", - "L": "W, J1 B5, X1 LeftShoulder", - "R": "E, J1 B6, X1 RightShoulder", - "Power": "" - }, - "Atari 2600 Basic Controller": { - "Reset": "D, J1 B9, X1 Back", - "Select": "S, J1 B10, X1 Start", - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow,J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow,J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 Button": "Z, J1 B1, X1 X", - "P2 Up": "NumberPad8, J1 RotationZ-, X1 RStickUp", - "P2 Down": "NumberPad2, J1 RotationZ+, X1 RStickDown", - "P2 Left": "NumberPad4, J1 Z-, X1 RStickLeft", - "P2 Right": "NumberPad6, J1 Z+, X1 RStickRight", - "P2 Button": "NumberPad1, J1 B2, X1 A" - }, - "Atari 7800 ProLine Joystick Controller": { - "Power": "", - "Reset": "D, J1 B9, X1 Back", - "Select": "S, J1 B10, X1 Start", - "Pause": "", - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 Trigger": "Z, J1 B1, X1 X", - "P1 Trigger 2": "X, J1 B2, X1 A", - "P2 Up": "NumberPad8, J1 RotationZ-, X1 RStickUp", - "P2 Down": "NumberPad2, J1 RotationZ+, X1 RStickDown", - "P2 Left": "NumberPad4, J1 Z-, X1 RStickLeft", - "P2 Right": "NumberPad6, J1 Z+, X1 RStickRight", - "P2 Trigger": "NumberPad1, J1 B4, X1 Y", - "P2 Trigger 2": "NumberPad3, J1 B3, X1 B" - }, - "Atari 7800 Joystick Controller": { - "Power": "", - "Reset": "D, J1 B9, X1 Back", - "Select": "S, J1 B10, X1 Start", - "Pause": "", - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 Trigger": "Z, J1 B1, X1 X", - "P1 Trigger 2": "X, J1 B2, X1 A", - "P2 Up": "NumberPad8, J1 RotationZ-, X1 RStickUp", - "P2 Down": "NumberPad2, J1 RotationZ+, X1 RStickDown", - "P2 Left": "NumberPad4, J1 Z-, X1 RStickLeft", - "P2 Right": "NumberPad6, J1 Z+, X1 RStickRight", - "P2 Trigger": "NumberPad1, J1 B4, X1 Y" - }, - "Atari 7800 Light Gun Controller": { - "Power": "", - "Reset": "D, J1 B9, X1 Back", - "Select": "S, J1 B10, X1 Start", - "Pause": "", - "P1 Trigger": "WMouse L" - }, - "Atari 7800 Paddle Controller": { - "Power": "", - "Reset": "D, J1 B9, X1 Back", - "Select": "S, J1 B10, X1 Start", - "Pause": "", - "P2 Trigger": "NumberPad1, J1 B4, X1 Y" - }, - "Commodore 64 Controller": { - "P1 Up": "NumberPad8, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "NumberPad2, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "NumberPad4, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "NumberPad6, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 Button": "NumberPad1, J1 B1, X1 X", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 Button": "", - "Key F1": "F1", - "Key F3": "F3", - "Key F5": "F5", - "Key F7": "F7", - "Key Left Arrow": "Grave", - "Key 1": "D1", - "Key 2": "D2", - "Key 3": "D3", - "Key 4": "D4", - "Key 5": "D5", - "Key 6": "D6", - "Key 7": "D7", - "Key 8": "D8", - "Key 9": "D9", - "Key 0": "D0", - "Key Plus": "Equals", - "Key Minus": "Minus", - "Key Pound": "Insert", - "Key Clear/Home": "Delete", - "Key Insert/Delete": "Backspace", - "Key Control": "Tab", - "Key Q": "Q", - "Key W": "W", - "Key E": "E", - "Key R": "R", - "Key T": "T", - "Key Y": "Y", - "Key U": "U", - "Key I": "I", - "Key O": "O", - "Key P": "P", - "Key At": "LeftBracket", - "Key Asterisk": "RightBracket", - "Key Up Arrow": "Backslash", - "Key Restore": "", - "Key Run/Stop": "CapsLock", - "Key Lck": "", - "Key A": "A", - "Key S": "S", - "Key D": "D", - "Key F": "F", - "Key G": "G", - "Key H": "H", - "Key J": "J", - "Key K": "K", - "Key L": "L", - "Key Colon": "Semicolon", - "Key Semicolon": "Apostrophe", - "Key Equal": "RightControl", - "Key Return": "Return", - "Key Commodore": "LeftControl", - "Key Left Shift": "LeftShift", - "Key Z": "Z", - "Key X": "X", - "Key C": "C", - "Key V": "V", - "Key B": "B", - "Key N": "N", - "Key M": "M", - "Key Comma": "Comma", - "Key Period": "Period", - "Key Slash": "Slash", - "Key Right Shift": "RightShift", - "Key Cursor Up/Down": "DownArrow", - "Key Cursor Left/Right": "RightArrow", - "Key Space": "Space" - }, - "ZXSpectrum Controller": { - "P1 Up": "NumberPad8, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "NumberPad2, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "NumberPad4, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "NumberPad6, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 Button": "NumberPad1, J1 B1, X1 X", - "Key True Video": "", - "Key Inv Video": "", - "Key 1": "D1", - "Key 2": "D2", - "Key 3": "D3", - "Key 4": "D4", - "Key 5": "D5", - "Key 6": "D6", - "Key 7": "D7", - "Key 8": "D8", - "Key 9": "D9", - "Key 0": "D0", - "Key Break": "Delete", - "Key Delete": "Backspace", - "Key Graph": "", - "Key Q": "Q", - "Key W": "W", - "Key E": "E", - "Key R": "R", - "Key T": "T", - "Key Y": "Y", - "Key U": "U", - "Key I": "I", - "Key O": "O", - "Key P": "P", - "Key Extend Mode": "", - "Key Edit": "", - "Key A": "A", - "Key S": "S", - "Key D": "D", - "Key F": "F", - "Key G": "G", - "Key H": "H", - "Key J": "J", - "Key K": "K", - "Key L": "L", - "Key Return": "Return", - "Key Caps Shift": "LeftShift, RightShift", - "Key Caps Lock": "", - "Key Z": "Z", - "Key X": "X", - "Key C": "C", - "Key V": "V", - "Key B": "B", - "Key N": "N", - "Key M": "M", - "Key Period": "Period", - "Key Symbol Shift": "LeftControl, RightControl", - "Key Semi-Colon": "Semicolon", - "Key Inverted-Comma": "", - "Key Left Cursor": "LeftArrow", - "Key Right Cursor": "RightArrow", - "Key Space": "Space", - "Key Up Cursor": "UpArrow", - "Key Down Cursor": "DownArrow", - "Key Comma": "Comma", - "Play Tape": "F1", - "Stop Tape": "F2", - "RTZ Tape": "F3", - "Record Tape": "", - "Key Quote": "Shift+D2", - "Insert Next Tape": "F6", - "Insert Previous Tape": "F5", - "Next Tape Block": "F8", - "Prev Tape Block": "F7", - "Get Tape Status": "F9", - "Insert Next Disk": "F11", - "Insert Previous Disk": "F10", - "Get Disk Status": "F12" - }, - "Intellivision Controller": { - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 L": "Z, J1 B1, X1 X", - "P1 R": "X, J1 B2, X1 A", - "P1 Key0": "NumberPad0", - "P1 Key1": "NumberPad1", - "P1 Key2": "NumberPad2", - "P1 Key3": "NumberPad3", - "P1 Key4": "NumberPad4", - "P1 Key5": "NumberPad5", - "P1 Key6": "NumberPad6", - "P1 Key7": "NumberPad7", - "P1 Key8": "NumberPad9", - "P1 Key9": "NumberPad9", - "P1 Enter": "NumberPadEnter", - "P1 Clear": "NumberPadPeriod", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 L": "", - "P2 R": "", - "P2 Key0": "", - "P2 Key1": "", - "P2 Key2": "", - "P2 Key3": "", - "P2 Key4": "", - "P2 Key5": "", - "P2 Key6": "", - "P2 Key7": "", - "P2 Key8": "", - "P2 Key9": "", - "P2 Enter": "", - "P2 Clear": "" - }, - "PC-FX Controller": { - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 I": "C, J1 B1, X1 X", - "P1 II": "X, J1 B2, X1 A", - "P1 III": "Z, J1 B4, X1 Y", - "P1 IV": "D, J1 B3, X1 B", - "P1 V": "S, J1 B11, X1 X", - "P1 VI": "A, J1 B12, X1 X", - "P1 Select": "Space, J1 B9, X1 Back", - "P1 Run": "Return, J1 B10, X1 Start", - "P1 Mode 1": "", - "P1 Mode 2": "", - "P2 Mouse Left": "NumberPad1", - "P2 Mouse Right": "NumberPad2", - "Power": "", - "Reset": "", - "Previous Disk": "", - "Next Disk": "", - "P2 Mouse Left": "WMouse L", - "P2 Mouse Right": "WMouse R", - }, - "Saturn Controller": { - "Power": "", - "Reset": "", - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 Start": "Return, J1 B10, X1 Start", - "P1 X": "D, J1 B3, X1 B", - "P1 Y": "S, J1 B11, X1 X", - "P1 Z": "A, J1 B12, X1 X", - "P1 A": "C, J1 B1, X1 X", - "P1 B": "X, J1 B2, X1 A", - "P1 C": "Z, J1 B4, X1 Y", - "P1 L": "Q, J1 B5, X1 LeftShoulder", - "P1 R": "W, J1 B6, X1 RightShoulder", - "P1 Mouse Left": "WMouse L", - "P1 Mouse Center": "WMouse M", - "P1 Mouse Right": "WMouse R", - "P1 Escape": "Escape", - "P1 F1": "F1", - "P1 F2": "F2", - "P1 F3": "F3", - "P1 F4": "F4", - "P1 F5": "F5", - "P1 F6": "F6", - "P1 F7": "F7", - "P1 F8": "F8", - "P1 F9": "F9", - "P1 F10": "F10", - "P1 F11": "F11", - "P1 F12": "F12", - "P1 Grave`": "Grave", - "P1 1(One)": "D1", - "P1 2": "D2", - "P1 3": "D3", - "P1 4": "D4", - "P1 5": "D5", - "P1 6": "D6", - "P1 7": "D7", - "P1 8": "D8", - "P1 9": "D9", - "P1 0(Zero)": "D0", - "P1 Minus-": "Minus", - "P1 Equals=": "Equals", - "P1 Backslash\\": "Backslash", - "P1 Backspace": "Backspace", - "P1 Tab": "Tab", - "P1 Q": "Q", - "P1 W": "W", - "P1 E": "E", - "P1 R(Key)": "R", - "P1 T": "T", - "P1 Y(Key)": "Y", - "P1 U": "U", - "P1 I": "I", - "P1 O": "O", - "P1 P": "P", - "P1 LeftBracket[": "LeftBracket", - "P1 RightBracket]": "RightBracket", - "P1 Enter": "Return", - "P1 CapsLock": "CapsLock", - "P1 A(Key)": "A", - "P1 S": "S", - "P1 D": "D", - "P1 F": "F", - "P1 G": "G", - "P1 H": "H", - "P1 J": "J", - "P1 K": "K", - "P1 L(Key)": "L", - "P1 Semicolon;": "Semicolon", - "P1 Quote'": "Apostrophe", - "P1 LeftShift": "LeftShift", - "P1 Z(Key)": "Z", - "P1 X(Key)": "X", - "P1 C(Key)": "C", - "P1 V": "V", - "P1 B(Key)": "B", - "P1 N": "N", - "P1 M": "M", - "P1 Comma,": "Comma", - "P1 Period.": "Period", - "P1 Slash/": "Slash", - "P1 RightShift": "RightShift", - "P1 LeftCtrl": "LeftControl", - "P1 LeftAlt": "LeftAlt", - "P1 Space": "Space", - "P1 RightAlt": "RightAlt", - "P1 RightCtrl": "RightControl", - "P1 PrintScreen": "", - "P1 ScrollLock": "ScrollLock", - "P1 Pause": "Pause", - "P1 Insert": "Insert", - "P1 Delete": "Delete", - "P1 Home": "Home", - "P1 End": "End", - "P1 PageUp": "PageUp", - "P1 PageDown": "PageDown", - "P1 Up": "UpArrow", - "P1 Down": "DownArrow", - "P1 CursorLeft": "LeftArrow", - "P1 Right": "RightArrow", - "P1 NumLock": "NumberLock", - "P1 KeypadSlash(Divide)": "NumberPadSlash", - "P1 KeypadAsterisk(Multiply)": "NumberPadStar", - "P1 KeypadMinus": "NumberPadMinus", - "P1 KeypadHome/7": "NumberPad7", - "P1 KeypadUp/8": "NumberPad8", - "P1 KeypadPageup/9": "NumberPad9", - "P1 KeypadPlus": "NumberPadPlus", - "P1 KeypadLeft/4": "NumberPad4", - "P1 KeypadCenter/5": "NumberPad5", - "P1 KeypadRight/6": "NumberPad6", - "P1 KeypadEnd/1": "NumberPad1", - "P1 KeypadDown/2": "NumberPad2", - "P1 KeypadPagedown/3": "NumberPad3", - "P1 KeypadEnter": "NumberPadEnter", - "P1 KeypadInsert/0": "NumberPad0", - "P1 KeypadDelete": "NumberPadPeriod" - }, - "PC Engine Controller": { - "Reset": "", - "Power": "", - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 B2": "Z, J1 B1, X1 X", - "P1 B1": "X, J1 B2, X1 A", - "P1 Select": "V, J1 B9, X1 Back", - "P1 Run": "Return, J1 B10, X1 Start", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 B1": "", - "P2 B2": "", - "P2 Select": "", - "P2 Run": "", - "P3 Up": "", - "P3 Down": "", - "P3 Left": "", - "P3 Right": "", - "P3 B1": "", - "P3 B2": "", - "P3 Select": "", - "P3 Run": "", - "P4 Up": "", - "P4 Down": "", - "P4 Left": "", - "P4 Right": "", - "P4 B1": "", - "P4 B2": "", - "P4 Select": "", - "P4 Run": "", - "P5 Up": "", - "P5 Down": "", - "P5 Left": "", - "P5 Right": "", - "P5 B1": "", - "P5 B2": "", - "P5 Select": "", - "P5 Run": "" - }, - "ColecoVision Basic Controller": { - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 L": "Z, J1 B5, X1 LeftShoulder", - "P1 R": "X, J1 B6, X1 RightShoulder", - "P1 Key 1": "NumberPad1, J1 B1, X1 X", - "P1 Key 2": "NumberPad2, J1 B2, X1 A", - "P1 Key 3": "NumberPad3, J1 B3, X1 B", - "P1 Key 4": "NumberPad4, J1 B4, X1 Y", - "P1 Key 5": "NumberPad5, J1 RotationZ-, X1 RStickUp", - "P1 Key 6": "NumberPad6, J1 RotationZ+, X1 RStickDown", - "P1 Key 7": "NumberPad7, J1 Z-, X1 RStickLeft", - "P1 Key 8": "NumberPad8, J1 Z+, X1 RStickRight", - "P1 Key 9": "NumberPad9, J1 B11, X1 LeftThumb", - "P1 Star": "NumberPadEnter, J1 B9, X1 Back", - "P1 Key 0": "NumberPad0, J1 B12, X1 RightThumb", - "P1 Pound": "NumberPadPeriod, J1 B10, X1 Start", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 L": "", - "P2 R": "", - "P2 Key1": "", - "P2 Key2": "", - "P2 Key3": "", - "P2 Key4": "", - "P2 Key5": "", - "P2 Key6": "", - "P2 Key7": "", - "P2 Key8": "", - "P2 Key9": "", - "P2 Star": "", - "P2 Key0": "", - "P2 Pound": "" - }, - "SMS Controller": { - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 B1": "Z, J1 B1, X1 X", - "P1 B2": "X, J1 B2, X1 A", - "Reset": "J1 B9, X1 Back", - "Pause": "J1 B10, X1 Start", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 B1": "", - "P2 B2": "" - }, - "SMS Paddle Controller": { - "P1 Left": "LeftArrow, J1 POV1L", - "P1 Right": "RightArrow, J1 POV1R", - "P1 B1": "Z, J1 B1, X1 X", - "Reset": "J1 B9, X1 Back", - "Pause": "J1 B10, X1 Start" - }, - "SMS Light Phaser Controller": { - "P1 Trigger": "Z, J1 B1, X1 X, WMouse L", - "Reset": "J1 B9, X1 Back", - "Pause": "J1 B10, X1 Start" - }, - "SMS Sports Pad Controller": { - "P1 Up": "UpArrow, J1 POV1U", - "P1 Down": "DownArrow, J1 POV1D", - "P1 Left": "LeftArrow, J1 POV1L", - "P1 Right": "RightArrow, J1 POV1R", - "P1 B1": "Z, J1 B1, X1 X", - "P1 B2": "X, J1 B2, X1 A", - "Reset": "J1 B9, X1 Back", - "Pause": "J1 B10, X1 Start", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 B1": "", - "P2 B2": "" - }, - "SMS Keyboard Controller": { - "Key 1": "D1", - "Key 2": "D2", - "Key 3": "D3", - "Key 4": "D4", - "Key 5": "D5", - "Key 6": "D6", - "Key 7": "D7", - "Key 8": "D8", - "Key 9": "D9", - "Key 0": "D0", - "Key Minus": "Minus", - "Key Caret": "Equals", - "Key Yen": "Backspace", - "Key Break": "Delete", - - "Key Function": "Tab", - "Key Q": "Q", - "Key W": "W", - "Key E": "E", - "Key R": "R", - "Key T": "T", - "Key Y": "Y", - "Key U": "U", - "Key I": "I", - "Key O": "O", - "Key P": "P", - "Key At": "LeftBracket", - "Key Left Bracket": "RightBracket", - "Key Return": "Return", - "Key Up Arrow": "UpArrow", - - "Key Control": "CapsLock", - "Key A": "A", - "Key S": "S", - "Key D": "D", - "Key F": "F", - "Key G": "G", - "Key H": "H", - "Key J": "J", - "Key K": "K", - "Key L": "L", - "Key Semicolon": "Semicolon", - "Key Colon": "Apostrophe", - "Key Right Bracket": "Backslash", - "Key Left Arrow": "LeftArrow", - "Key Right Arrow": "RightArrow", - - "Key Shift": "LeftShift", - "Key Z": "Z", - "Key X": "X", - "Key C": "C", - "Key V": "V", - "Key B": "B", - "Key N": "N", - "Key M": "M", - "Key Comma": "Comma", - "Key Period": "Period", - "Key Slash": "Slash", - "Key PI": "RightShift", - "Key Down Arrow": "DownArrow", - - "Key Graph": "PageUp", - "Key Kana": "PageDown", - "Key Space": "Space", - "Key Home/Clear": "Home", - "Key Insert/Delete": "Insert", - - "P1 Up": "J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 B1": "J1 B1, X1 X", - "P1 B2": "J1 B2, X1 A", - "Reset": "J1 B9, X1 Back", - "Pause": "J1 B10, X1 Start", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 B1": "", - "P2 B2": "" - }, - "GG Controller": { - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 B1": "Z, J1 B1, X1 X", - "P1 B2": "X, J1 B2, X1 A", - "Reset": "J1 B9, X1 Back", - "P1 Start": "Return, J1 B10, X1 Start" - }, - "Dual Gameboy Controller": { - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 Start": "Return, J1 B10, X1 Start", - "P1 Select": "Space, J1 B9, X1 Space", - "P1 B": "Z, J1 B1, X1 X", - "P1 A": "X, J1 B2, X1 A", - "P1 Power": "", - "P2 Up": "NumberPad8, J1 RotationZ-, X1 RStickUp", - "P2 Down": "NumberPad2, J1 RotationZ+, X1 RStickDown", - "P2 Left": "NumberPad4, J1 Z-, X1 RStickLeft", - "P2 Right": "NumberPad6, J1 Z+, X1 RStickRight", - "P2 Start": "RightBracket, J1 B5, X1 LeftShoulder", - "P2 Select": "LeftBracket, J1 B6, X1 RightShoulder", - "P2 B": "C, J1 B4, X1 Y", - "P2 A": "V, J1 B3, X1 B", - "P2 Power": "" - }, - "TI83 Controller": { - "0": "NumberPad0", - "1": "NumberPad1", - "2": "NumberPad2", - "3": "NumberPad3", - "4": "NumberPad4", - "5": "NumberPad5", - "6": "NumberPad6", - "7": "NumberPad7", - "8": "NumberPad8", - "9": "NumberPad9", - "DOT": "NumberPadPeriod", - "ON": "Space", - "ENTER": "Return, NumberPadEnter", - "DOWN": "DownArrow", - "UP": "UpArrow", - "LEFT": "LeftArrow", - "RIGHT": "RightArrow", - "PLUS": "NumberPadPlus", - "MINUS": "NumberPadMinus", - "MULTIPLY": "NumberPadStar", - "DIVIDE": "NumberPadSlash", - "CLEAR": "Escape", - "EXP": "6", - "DASH": "Minus", - "PARACLOSE": "0", - "TAN": "T", - "VARS": "V", - "PARAOPEN": "9", - "COS": "C", - "PRGM": "R", - "STAT": "S", - "SIN": "Period", - "MATRIX": "LeftBracket", - "X": "X", - "STO": "Insert", - "LN": "L", - "LOG": "O", - "SQUARED": "2", - "NEG1": "1", - "MATH": "M", - "ALPHA": "A", - "GRAPH": "G", - "TRACE": "Home", - "ZOOM": "Z", - "WINDOW": "W", - "Y": "Y", - "SECOND": "Slash", - "MODE": "BackSlash", - "DEL": "Delete", - "COMMA": "Comma" - }, - "GPGX Genesis Controller": { - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 A": "Z, J1 B1, X1 X", - "P1 B": "X, J1 B2, X1 A", - "P1 C": "C, J1 B4, X1 Y", - "P1 Start": "Return, J1 B10, X1 Start", - "P1 X": "A, J1 B3, X1 B", - "P1 Y": "S, J1 B5, X1 LeftShoulder", - "P1 Z": "D, J1 B6, X1 RightShoulder", - "P1 Mode": "E, J1 B9, X1 Back", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 A": "", - "P2 B": "", - "P2 C": "", - "P2 Start": "", - "P2 X": "", - "P2 Y": "", - "P2 Z": "", - "P2 Mode": "", - "P2 Lightgun Trigger": "WMouse L", - "P2 Lightgun Start": "NumberPad5", - "P2 Mouse Left": "WMouse L", - "P2 Mouse Center": "WMouse M", - "P2 Mouse Right": "WMouse R", - "P2 Mouse Start": "NumberPad5", - "Power": "", - "Reset": "" - }, - "PicoDrive Genesis Controller": { - "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 A": "Z, J1 B1, X1 X", - "P1 B": "X, J1 B2, X1 A", - "P1 C": "C, J1 B4, X1 Y", - "P1 Start": "Return, J1 B10, X1 Start", - "P1 X": "A, J1 B3, X1 B", - "P1 Y": "S, J1 B5, X1 LeftShoulder", - "P1 Z": "D, J1 B6, X1 RightShoulder", - "P1 Mode": "E, J1 B9, X1 Back", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 A": "", - "P2 B": "", - "P2 C": "", - "P2 Start": "", - "P2 X": "", - "P2 Y": "", - "P2 Z": "", - "P2 Mode": "", - "Power": "", - "Reset": "" - }, - "WonderSwan Controller": { - "P1 X1": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P1 X3": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P1 X4": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P1 X2": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P1 Y1": "NumberPad8, J1 RotationZ-, X1 RStickUp", - "P1 Y3": "NumberPad2, J1 RotationZ+, X1 RStickDown", - "P1 Y4": "NumberPad4, J1 Z-, X1 RStickLeft", - "P1 Y2": "NumberPad6, J1 Z+, X1 RStickRight", - "P1 Start": "Return, J1 B10, X1 Start", - "P1 B": "Z, J1 B1, X1 X", - "P1 A": "X, J1 B2, X1 A", - "P2 X1": "", - "P2 X3": "X, J1 B2, X1 A", - "P2 X4": "Z, J1 B1, X1 X", - "P2 X2": "", - "P2 Y1": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", - "P2 Y3": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", - "P2 Y4": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", - "P2 Y2": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", - "P2 Start": "Return, J1 B10, X1 Start", - "P2 B": "", - "P2 A": "", - "Power": "" - }, - "PSX DualShock Controller": { - "P1 Up": "X1 DpadUp,UpArrow", - "P1 Down": "X1 DpadDown,DownArrow", - "P1 Left": "X1 DpadLeft,LeftArrow", - "P1 Right": "X1 DpadRight,RightArrow", - "P1 Select": "X1 Back,Space", - "P1 Start": "X1 Start,Return", - "P1 Square": "X1 X,A", - "P1 Triangle": "X1 Y,S", - "P1 Circle": "X1 B,X", - "P1 Cross": "X1 A,Z", - "P1 L1": "X1 LeftShoulder,Q", - "P1 R1": "X1 RightShoulder,W", - "P1 L2": "X1 LeftTrigger,E", - "P1 R2": "X1 RightTrigger,R", - "P1 L3": "X1 LeftThumb,T", - "P1 R3": "X1 RightThumb,Y", - "P1 MODE": "D" - }, - "Lynx Controller": { - "Up": "UpArrow", - "Down": "DownArrow", - "Left": "LeftArrow", - "Right": "RightArrow", - "A": "X", - "B": "Z", - "Option 1": "A", - "Option 2": "S", - "Pause": "Return", - "Power": "" - }, - "Apple IIe Keyboard": { - "Delete": "Delete", - "Left": "LeftArrow", - "Tab": "Tab", - "Down": "DownArrow", - "Up": "UpArrow", - "Return": "Return", - "Right": "RightArrow", - "Escape": "", - "Space": "Space", - "'": "Apostrophe", - ",": "Comma", - "-": "Minus", - ".": "Period", - "/": "Slash", - "0": "NumberPad0", - "1": "NumberPad1", - "2": "NumberPad2", - "3": "NumberPad3", - "4": "NumberPad4", - "5": "NumberPad5", - "6": "NumberPad6", - "7": "NumberPad7", - "8": "NumberPad8", - "9": "NumberPad9", - ";": "Semicolon", - "=": "Equals", - "[": "LeftBracket", - "\\": "Backslash", - "]": "RightBracket", - "`": "Grave", - "A": "A", - "B": "B", - "C": "C", - "D": "D", - "E": "E", - "F": "F", - "G": "G", - "H": "H", - "I": "I", - "J": "J", - "K": "K", - "L": "L", - "M": "M", - "N": "N", - "O": "O", - "P": "P", - "Q": "Q", - "R": "R", - "S": "S", - "T": "T", - "U": "U", - "V": "V", - "W": "W", - "X": "X", - "Y": "Y", - "Z": "Z", - "Control": "RightControl", - "Shift": "RightShift", - "Caps Lock": "CapsLock", - "Previous Disk": "", - "Next Disk": "" - }, - "VirtualBoy Controller": { - "L_Up": "UpArrow, X1 DpadUp, X1 LStickUp", - "L_Down": "DownArrow, X1 DpadDown, X1 LStickDown", - "L_Left": "LeftArrow, X1 DpadLeft, X1 LStickLeft", - "L_Right": "RightArrow, X1 DpadRight, X1 LStickRight", - "R_Up": "NumberPad8, X1 RStickUp", - "R_Down": "NumberPad2, X1 RStickDown", - "R_Left": "NumberPad4, X1 RStickLeft", - "R_Right": "NumberPad6, X1 RStickRight", - "B": "Z, X1 X", - "A": "X, X1 A", - "R": "W, X1 LeftShoulder", - "L": "E, X1 RightShoulder", - "Select": "Space, X1 Back", - "Start": "Return, X1 Start", - "Power": "" - }, - "NeoGeo Portable Controller": { - "Up": "UpArrow, X1 DpadUp, X1 LStickUp", - "Down": "DownArrow, X1 DpadDown, X1 LStickDown", - "Left": "LeftArrow, X1 DpadLeft, X1 LStickLeft", - "Right": "RightArrow, X1 DpadRight, X1 LStickRight", - "B": "Z, J1 B1, X1 X", - "A": "X, J1 B2, X1 A", - "Option": "Return, J1 B10, X1 Start", - "Power": "" - } - }, - "AllTrollersAutoFire": { - "NES Controller": { - "P1 Up": "", - "P1 Down": "", - "P1 Left": "", - "P1 Right": "", - "P1 Start": "", - "P1 Select": "", - "P1 B": "A", - "P1 A": "S", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 Start": "", - "P2 Select": "", - "P2 B": "", - "P2 A": "", - "P2 Fire": "", - "P2 Microphone": "", - "P3 Fire": "", - "Reset": "", - "Power": "" - }, - "Gameboy Controller": { - "Up": "", - "Down": "", - "Left": "", - "Right": "", - "Start": "", - "Select": "", - "B": "A", - "A": "S", - "Power": "" - }, - "GBAController": { - "Up": "", - "Down": "", - "Left": "", - "Right": "", - "Start": "", - "Select": "", - "B": "A", - "A": "S", - "L": "", - "R": "", - "Power": "" - }, - "Atari 2600 Basic Controller": { - "Reset": "", - "Select": "", - "P1 Up": "", - "P1 Down": "", - "P1 Left": "", - "P1 Right": "", - "P1 Button": "A", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 Button": "S" - }, - "PC Engine Controller": { - "Reset": "", - "Power": "", - "P1 Up": "", - "P1 Down": "", - "P1 Left": "", - "P1 Right": "", - "P1 B2": "A", - "P1 B1": "S", - "P1 Select": "", - "P1 Run": "", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 B2": "", - "P2 B1": "", - "P2 Select": "", - "P2 Run": "", - "P3 Up": "", - "P3 Down": "", - "P3 Left": "", - "P3 Right": "", - "P3 B2": "", - "P3 B1": "", - "P3 Select": "", - "P3 Run": "", - "P4 Up": "", - "P4 Down": "", - "P4 Left": "", - "P4 Right": "", - "P4 B2": "", - "P4 B1": "", - "P4 Select": "", - "P4 Run": "", - "P5 Up": "", - "P5 Down": "", - "P5 Left": "", - "P5 Right": "", - "P5 B2": "", - "P5 B1": "", - "P5 Select": "", - "P5 Run": "" - }, - "SMS Controller": { - "P1 Up": "", - "P1 Down": "", - "P1 Left": "", - "P1 Right": "", - "P1 B1": "A", - "P1 B2": "S", - "Reset": "", - "Pause": "", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 B1": "", - "P2 B2": "" - }, - "GPGX Genesis Controller": { - "P1 Up": "", - "P1 Down": "", - "P1 Left": "", - "P1 Right": "", - "P1 A": "", - "P1 B": "", - "P1 C": "", - "P1 Start": "", - "P1 X": "", - "P1 Y": "", - "P1 Z": "", - "P1 Mode": "", - "P2 Up": "", - "P2 Down": "", - "P2 Left": "", - "P2 Right": "", - "P2 A": "", - "P2 B": "", - "P2 C": "", - "P2 Start": "", - "P2 X": "", - "P2 Y": "", - "P2 Z": "", - "P2 Mode": "", - "Power": "", - "Reset": "" - }, - "GBA Controller": { - "Up": "", - "Down": "", - "Left": "", - "Right": "", - "Start": "", - "Select": "", - "B": "A", - "A": "S", - "L": "", - "R": "", - "Power": "" - }, - "WonderSwan Controller": { - "P1 B": "A", - "P1 A": "S", - "P2 X4": "A", - "P2 X3": "S", - "Power": "" - }, - "Lynx Controller": { - "Up": "", - "Down": "", - "Left": "", - "Right": "", - "A": "", - "B": "", - "Option 1": "", - "Option 2": "", - "Pause": "", - "Power": "" - }, - "Apple IIe Keyboard": { - "Delete": "", - "Left": "", - "Tab": "", - "Down": "", - "Up": "", - "Return": "Return", - "Right": "", - "Escape": "", - "Space": "", - "'": "", - ",": "", - "-": "", - ".": "", - "/": "", - "0": "", - "1": "", - "2": "", - "3": "", - "4": "", - "5": "", - "6": "", - "7": "", - "8": "", - "9": "", - ";": "", - "=": "", - "[": "", - "\\": "", - "]": "", - "`": "", - "A": "", - "B": "", - "C": "", - "D": "", - "E": "", - "F": "", - "G": "", - "H": "", - "I": "", - "J": "", - "K": "", - "L": "", - "M": "", - "N": "", - "O": "", - "P": "", - "Q": "", - "R": "", - "S": "", - "T": "", - "U": "", - "V": "", - "W": "", - "X": "", - "Y": "", - "Z": "", - "Control": "", - "Shift": "", - "Caps Lock": "", - "Previous Disk": "", - "Next Disk": "" - }, - "VirtualBoy Controller": { - "L_Up": "", - "L_Down": "", - "L_Left": "", - "L_Right": "", - "R_Up": "", - "R_Down": "", - "R_Left": "", - "R_Right": "", - "B": "", - "A": "", - "R": "", - "L": "", - "Select": "", - "Start": "", - "Power": "" - }, - "NeoGeo Portable Controller": { - "Up": "", - "Down": "", - "Left": "", - "Right": "", - "B": "", - "A": "", - "Option": "", - "Power": "" - } - }, + "AllTrollers": { + "LibRetro Controls": { + "P1 RetroPad Up": "UpArrow,J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 RetroPad Down": "DownArrow,J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 RetroPad Left": "LeftArrow,J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 RetroPad Right": "RightArrow,J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 RetroPad Select": "Space, J1 B9, X1 Back", + "P1 RetroPad Start": "Return, J1 B10, X1 Start", + "P1 RetroPad Y": "A, J1 B1, X1 X", + "P1 RetroPad B": "Z, J1 B2, X1 A", + "P1 RetroPad X": "S, J1 B4, X1 Y", + "P1 RetroPad A": "X, J1 B3, X1 B", + "P1 RetroPad L": "W, J1 B5, X1 LeftShoulder", + "P1 RetroPad R": "E, J1 B6, X1 RightShoulder", + "P2 RetroPad Up": "", + "P2 RetroPad Down": "", + "P2 RetroPad Left": "", + "P2 RetroPad Right": "", + "P2 RetroPad Select": "", + "P2 RetroPad Start": "", + "P2 RetroPad Y": "", + "P2 RetroPad B": "", + "P2 RetroPad X": "", + "P2 RetroPad A": "", + "P2 RetroPad L": "", + "P2 RetroPad R": "", + "Pointer Pressed": "WMouse L", + "Key Backspace": "Backspace", + "Key Tab": "Tab", + "Key Clear": "", + "Key Return": "Return", + "Key Pause": "", + "Key Escape": "Escape", + "Key Space": "Space", + "Key Exclaim": "", + "Key QuoteDbl": "", + "Key Hash": "", + "Key Dollar": "", + "Key Ampersand": "", + "Key Quote": "", + "Key LeftParen": "", + "Key RightParen": "", + "Key Asterisk": "", + "Key Plus": "", + "Key Comma": "Comma", + "Key Minus": "Minus", + "Key Period": "Period", + "Key Slash": "Slash", + "Key 0": "D0", + "Key 1": "D1", + "Key 2": "D2", + "Key 3": "D3", + "Key 4": "D4", + "Key 5": "D5", + "Key 6": "D6", + "Key 7": "D7", + "Key 8": "D8", + "Key 9": "D9", + "Key Colon": "", + "Key Semicolon": "Semicolon", + "Key Less": "", + "Key Equals": "Equals", + "Key Greater": "", + "Key Question": "", + "Key At": "", + "Key LeftBracket": "LeftBracket", + "Key Backslash": "Backslash", + "Key RightBracket": "RightBracket", + "Key Caret": "", + "Key Underscore": "", + "Key Backquote": "Grave", + "Key A": "A", + "Key B": "B", + "Key C": "C", + "Key D": "D", + "Key E": "E", + "Key F": "F", + "Key G": "G", + "Key H": "H", + "Key I": "I", + "Key J": "J", + "Key K": "K", + "Key L": "L", + "Key M": "M", + "Key N": "N", + "Key O": "O", + "Key P": "P", + "Key Q": "Q", + "Key R": "R", + "Key S": "S", + "Key T": "T", + "Key U": "U", + "Key V": "V", + "Key W": "W", + "Key X": "X", + "Key Y": "Y", + "Key Z": "Z", + "Key Delete": "Delete", + "Key KP0": "NumberPad0", + "Key KP1": "NumberPad1", + "Key KP2": "NumberPad2", + "Key KP3": "NumberPad3", + "Key KP4": "NumberPad4", + "Key KP5": "NumberPad5", + "Key KP6": "NumberPad6", + "Key KP7": "NumberPad7", + "Key KP8": "NumberPad8", + "Key KP9": "NumberPad9", + "Key KP_Period": "NumberPadPeriod", + "Key KP_Divide": "NumberPadSlash", + "Key KP_Multiply": "NumberPadStar", + "Key KP_Minus": "NumberPadMinus", + "Key KP_Plus": "NumberPadPlus", + "Key KP_Enter": "NumberPadEnter", + "Key KP_Equals": "", + "Key Up": "UpArrow", + "Key Down": "DownArrow", + "Key Left": "LeftArrow", + "Key Insert": "LeftControl", + "Key Home": "Home", + "Key End": "End", + "Key PageUp": "PageUp", + "Key PageDown": "PageDown", + "Key F1": "F1", + "Key F2": "F2", + "Key F3": "F3", + "Key F4": "F4", + "Key F5": "F5", + "Key F6": "F6", + "Key F7": "F7", + "Key F8": "F8", + "Key F9": "F9", + "Key F10": "F10", + "Key F11": "F11", + "Key F12": "F12", + "Key F13": "", + "Key F14": "", + "Key F15": "", + "Key NumLock": "NumberLock", + "Key CapsLock": "CapsLock", + "Key ScrollLock": "ScrollLock", + "Key RShift": "RightShift", + "Key LShift": "LeftShift", + "Key RCtrl": "RightControl", + "Key LCtrl": "LeftControl", + "Key RAlt": "RightAlt", + "Key LAlt": "LeftAlt", + "Key RMeta": "", + "Key LMeta": "", + "Key LSuper": "", + "Key RSuper": "", + "Key Mode": "", + "Key Compose": "", + "Key Help": "", + "Key Print": "", + "Key SysReq": "", + "Key Break": "", + "Key Menu": "Applications", + "Key Power": "", + "Key Euro": "", + "Key Undo": "", + "Key Right": "RightArrow" + }, + "NES Controller": { + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 Start": "Return, J1 B10, X1 Start", + "P1 Select": "Space, J1 B9, X1 Back", + "P1 B": "Z, J1 B1, X1 X", + "P1 A": "X, J1 B2, X1 A", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 Start": "", + "P2 Select": "", + "P2 B": "", + "P2 A": "", + "P2 Fire": "WMouse L", + "P2 Microphone": "", + "P3 Fire": "WMouse L", + "Reset": "", + "Power": "" + }, + "SNES Controller": { + "Reset": "", + "Power": "", + "P1 Up": "UpArrow,J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow,J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow,J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow,J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 Select": "Space, J1 B9, X1 Back", + "P1 Start": "Return, J1 B10, X1 Start", + "P1 Y": "A, J1 B1, X1 X", + "P1 X": "S, J1 B4, X1 Y", + "P1 B": "Z, J1 B2, X1 A", + "P1 A": "X, J1 B3, X1 B", + "P1 L": "W, J1 B5, X1 LeftShoulder", + "P1 R": "E, J1 B6, X1 RightShoulder", + "P1 Mouse Left": "Z, J1 B1, X1 X", + "P1 Mouse Right": "X, J1 B2, X1 A", + "P2 Trigger": "Z, J1 B1, X1 X", + "P2 Cursor": "X, J1 B2, X1 A", + "P2 Turbo": "A, J1 B3 X1 Y", + "P2 Pause": "S, J1 B4 X1 B" + }, + "Nintento 64 Controller": { + "P1 A Up": "UpArrow, J1 POV1U", + "P1 A Down": "DownArrow, J1 POV1D", + "P1 A Left": "LeftArrow, J1 POV1L", + "P1 A Right": "RightArrow, J1 POV1R", + "P1 DPad U": "X1 DpadUp", + "P1 DPad D": "X1 DpadDown", + "P1 DPad L": "X1 DpadLeft", + "P1 DPad R": "X1 DpadRight", + "P1 Start": "Return, J1 B10, X1 Start", + "P1 Z": "D, J1 B3, X1 B", + "P1 B": "S, J1 B1, X1 X", + "P1 A": "A, J1 B2, X1 A", + "P1 C Up": "NumberPad8, J1 RotationZ-, X1 RStickUp", + "P1 C Down": "NumberPad2, J1 RotationZ+, X1 RStickDown", + "P1 C Left": "NumberPad4, J1 Z-, X1 RStickLeft", + "P1 C Right": "NumberPad6, J1 Z+, X1 RStickRight", + "P1 L": "Q, J1 B5, X1 LeftShoulder", + "P1 R": "W, J1 B6, X1 RightShoulder", + "P2 X Axis": "", + "P2 Y Axis": "", + "P2 A Up": "", + "P2 A Down": "", + "P2 A Left": "", + "P2 A Right": "", + "P2 DPad U": "", + "P2 DPad D": "", + "P2 DPad L": "", + "P2 DPad R": "", + "P2 Start": "", + "P2 Z": "", + "P2 B": "", + "P2 A": "", + "P2 C Up": "", + "P2 C Down": "", + "P2 C Left": "", + "P2 C Right": "", + "P2 L": "", + "P2 R": "", + "P3 X Axis": "", + "P3 Y Axis": "", + "P3 A Up": "", + "P3 A Down": "", + "P3 A Left": "", + "P3 A Right": "", + "P3 DPad U": "", + "P3 DPad D": "", + "P3 DPad L": "", + "P3 DPad R": "", + "P3 Start": "", + "P3 Z": "", + "P3 B": "", + "P3 A": "", + "P3 C Up": "", + "P3 C Down": "", + "P3 C Left": "", + "P3 C Right": "", + "P3 L": "", + "P3 R": "", + "P4 X Axis": "", + "P4 Y Axis": "", + "P4 A Up": "", + "P4 A Down": "", + "P4 A Left": "", + "P4 A Right": "", + "P4 DPad U": "", + "P4 DPad D": "", + "P4 DPad L": "", + "P4 DPad R": "", + "P4 Start": "", + "P4 Z": "", + "P4 B": "", + "P4 A": "", + "P4 C Up": "", + "P4 C Down": "", + "P4 C Left": "", + "P4 C Right": "", + "P4 L": "", + "P4 R": "", + "Reset": "", + "Power": "" + }, + "Gameboy Controller": { + "Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "Start": "Return, J1 B10, X1 Start", + "Select": "Space, J1 B9, X1 Back", + "B": "Z, J1 B1, X1 X", + "A": "X, J1 B2, X1 A", + "Power": "", + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 Start": "Return, J1 B10, X1 Start", + "P1 Select": "Space, J1 B9, X1 Back", + "P1 B": "Z, J1 B1, X1 X", + "P1 A": "X, J1 B2, X1 A" + }, + "Gameboy Controller H": { + "Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "Start": "Return, J1 B10, X1 Start", + "Select": "Space, J1 B9, X1 Back", + "B": "Z, J1 B1, X1 X", + "A": "X, J1 B2, X1 A", + "Power": "", + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 Start": "Return, J1 B10, X1 Start", + "P1 Select": "Space, J1 B9, X1 Back", + "P1 B": "Z, J1 B1, X1 X", + "P1 A": "X, J1 B2, X1 A" + }, + "GBA Controller": { + "Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "Start": "Return, J1 B10, X1 Start", + "Select": "Space, J1 B9, X1 Back", + "B": "Z, J1 B1, X1 X", + "A": "X, J1 B2, X1 A", + "L": "W, J1 B5, X1 LeftShoulder", + "R": "E, J1 B6, X1 RightShoulder", + "Power": "" + }, + "Atari 2600 Basic Controller": { + "Reset": "D, J1 B9, X1 Back", + "Select": "S, J1 B10, X1 Start", + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow,J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow,J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 Button": "Z, J1 B1, X1 X", + "P2 Up": "NumberPad8, J1 RotationZ-, X1 RStickUp", + "P2 Down": "NumberPad2, J1 RotationZ+, X1 RStickDown", + "P2 Left": "NumberPad4, J1 Z-, X1 RStickLeft", + "P2 Right": "NumberPad6, J1 Z+, X1 RStickRight", + "P2 Button": "NumberPad1, J1 B2, X1 A" + }, + "Atari 7800 ProLine Joystick Controller": { + "Power": "", + "Reset": "D, J1 B9, X1 Back", + "Select": "S, J1 B10, X1 Start", + "Pause": "", + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 Trigger": "Z, J1 B1, X1 X", + "P1 Trigger 2": "X, J1 B2, X1 A", + "P2 Up": "NumberPad8, J1 RotationZ-, X1 RStickUp", + "P2 Down": "NumberPad2, J1 RotationZ+, X1 RStickDown", + "P2 Left": "NumberPad4, J1 Z-, X1 RStickLeft", + "P2 Right": "NumberPad6, J1 Z+, X1 RStickRight", + "P2 Trigger": "NumberPad1, J1 B4, X1 Y", + "P2 Trigger 2": "NumberPad3, J1 B3, X1 B" + }, + "Atari 7800 Joystick Controller": { + "Power": "", + "Reset": "D, J1 B9, X1 Back", + "Select": "S, J1 B10, X1 Start", + "Pause": "", + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 Trigger": "Z, J1 B1, X1 X", + "P1 Trigger 2": "X, J1 B2, X1 A", + "P2 Up": "NumberPad8, J1 RotationZ-, X1 RStickUp", + "P2 Down": "NumberPad2, J1 RotationZ+, X1 RStickDown", + "P2 Left": "NumberPad4, J1 Z-, X1 RStickLeft", + "P2 Right": "NumberPad6, J1 Z+, X1 RStickRight", + "P2 Trigger": "NumberPad1, J1 B4, X1 Y" + }, + "Atari 7800 Light Gun Controller": { + "Power": "", + "Reset": "D, J1 B9, X1 Back", + "Select": "S, J1 B10, X1 Start", + "Pause": "", + "P1 Trigger": "WMouse L" + }, + "Atari 7800 Paddle Controller": { + "Power": "", + "Reset": "D, J1 B9, X1 Back", + "Select": "S, J1 B10, X1 Start", + "Pause": "", + "P2 Trigger": "NumberPad1, J1 B4, X1 Y" + }, + "Commodore 64 Controller": { + "P1 Up": "NumberPad8, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "NumberPad2, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "NumberPad4, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "NumberPad6, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 Button": "NumberPad1, J1 B1, X1 X", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 Button": "", + "Key F1": "F1", + "Key F3": "F3", + "Key F5": "F5", + "Key F7": "F7", + "Key Left Arrow": "Grave", + "Key 1": "D1", + "Key 2": "D2", + "Key 3": "D3", + "Key 4": "D4", + "Key 5": "D5", + "Key 6": "D6", + "Key 7": "D7", + "Key 8": "D8", + "Key 9": "D9", + "Key 0": "D0", + "Key Plus": "Equals", + "Key Minus": "Minus", + "Key Pound": "Insert", + "Key Clear/Home": "Delete", + "Key Insert/Delete": "Backspace", + "Key Control": "Tab", + "Key Q": "Q", + "Key W": "W", + "Key E": "E", + "Key R": "R", + "Key T": "T", + "Key Y": "Y", + "Key U": "U", + "Key I": "I", + "Key O": "O", + "Key P": "P", + "Key At": "LeftBracket", + "Key Asterisk": "RightBracket", + "Key Up Arrow": "Backslash", + "Key Restore": "", + "Key Run/Stop": "CapsLock", + "Key Lck": "", + "Key A": "A", + "Key S": "S", + "Key D": "D", + "Key F": "F", + "Key G": "G", + "Key H": "H", + "Key J": "J", + "Key K": "K", + "Key L": "L", + "Key Colon": "Semicolon", + "Key Semicolon": "Apostrophe", + "Key Equal": "RightControl", + "Key Return": "Return", + "Key Commodore": "LeftControl", + "Key Left Shift": "LeftShift", + "Key Z": "Z", + "Key X": "X", + "Key C": "C", + "Key V": "V", + "Key B": "B", + "Key N": "N", + "Key M": "M", + "Key Comma": "Comma", + "Key Period": "Period", + "Key Slash": "Slash", + "Key Right Shift": "RightShift", + "Key Cursor Up/Down": "DownArrow", + "Key Cursor Left/Right": "RightArrow", + "Key Space": "Space" + }, + "ZXSpectrum Controller": { + "P1 Up": "NumberPad8, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "NumberPad2, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "NumberPad4, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "NumberPad6, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 Button": "NumberPad1, J1 B1, X1 X", + "Key True Video": "", + "Key Inv Video": "", + "Key 1": "D1", + "Key 2": "D2", + "Key 3": "D3", + "Key 4": "D4", + "Key 5": "D5", + "Key 6": "D6", + "Key 7": "D7", + "Key 8": "D8", + "Key 9": "D9", + "Key 0": "D0", + "Key Break": "Delete", + "Key Delete": "Backspace", + "Key Graph": "", + "Key Q": "Q", + "Key W": "W", + "Key E": "E", + "Key R": "R", + "Key T": "T", + "Key Y": "Y", + "Key U": "U", + "Key I": "I", + "Key O": "O", + "Key P": "P", + "Key Extend Mode": "", + "Key Edit": "", + "Key A": "A", + "Key S": "S", + "Key D": "D", + "Key F": "F", + "Key G": "G", + "Key H": "H", + "Key J": "J", + "Key K": "K", + "Key L": "L", + "Key Return": "Return", + "Key Caps Shift": "LeftShift, RightShift", + "Key Caps Lock": "", + "Key Z": "Z", + "Key X": "X", + "Key C": "C", + "Key V": "V", + "Key B": "B", + "Key N": "N", + "Key M": "M", + "Key Period": "Period", + "Key Symbol Shift": "LeftControl, RightControl", + "Key Semi-Colon": "Semicolon", + "Key Inverted-Comma": "", + "Key Left Cursor": "LeftArrow", + "Key Right Cursor": "RightArrow", + "Key Space": "Space", + "Key Up Cursor": "UpArrow", + "Key Down Cursor": "DownArrow", + "Key Comma": "Comma", + "Play Tape": "F1", + "Stop Tape": "F2", + "RTZ Tape": "F3", + "Record Tape": "", + "Key Quote": "Shift+D2", + "Insert Next Tape": "F6", + "Insert Previous Tape": "F5", + "Next Tape Block": "F8", + "Prev Tape Block": "F7", + "Get Tape Status": "F9", + "Insert Next Disk": "F11", + "Insert Previous Disk": "F10", + "Get Disk Status": "F12" + }, + "Intellivision Controller": { + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 L": "Z, J1 B1, X1 X", + "P1 R": "X, J1 B2, X1 A", + "P1 Key0": "NumberPad0", + "P1 Key1": "NumberPad1", + "P1 Key2": "NumberPad2", + "P1 Key3": "NumberPad3", + "P1 Key4": "NumberPad4", + "P1 Key5": "NumberPad5", + "P1 Key6": "NumberPad6", + "P1 Key7": "NumberPad7", + "P1 Key8": "NumberPad9", + "P1 Key9": "NumberPad9", + "P1 Enter": "NumberPadEnter", + "P1 Clear": "NumberPadPeriod", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 L": "", + "P2 R": "", + "P2 Key0": "", + "P2 Key1": "", + "P2 Key2": "", + "P2 Key3": "", + "P2 Key4": "", + "P2 Key5": "", + "P2 Key6": "", + "P2 Key7": "", + "P2 Key8": "", + "P2 Key9": "", + "P2 Enter": "", + "P2 Clear": "" + }, + "PC-FX Controller": { + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 I": "C, J1 B1, X1 X", + "P1 II": "X, J1 B2, X1 A", + "P1 III": "Z, J1 B4, X1 Y", + "P1 IV": "D, J1 B3, X1 B", + "P1 V": "S, J1 B11, X1 X", + "P1 VI": "A, J1 B12, X1 X", + "P1 Select": "Space, J1 B9, X1 Back", + "P1 Run": "Return, J1 B10, X1 Start", + "P1 Mode 1": "", + "P1 Mode 2": "", + "P2 Mouse Left": "NumberPad1", + "P2 Mouse Right": "NumberPad2", + "Power": "", + "Reset": "", + "Previous Disk": "", + "Next Disk": "", + "P2 Mouse Left": "WMouse L", + "P2 Mouse Right": "WMouse R" + }, + "Saturn Controller": { + "Power": "", + "Reset": "", + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 Start": "Return, J1 B10, X1 Start", + "P1 X": "D, J1 B3, X1 B", + "P1 Y": "S, J1 B11, X1 X", + "P1 Z": "A, J1 B12, X1 X", + "P1 A": "C, J1 B1, X1 X", + "P1 B": "X, J1 B2, X1 A", + "P1 C": "Z, J1 B4, X1 Y", + "P1 L": "Q, J1 B5, X1 LeftShoulder", + "P1 R": "W, J1 B6, X1 RightShoulder", + "P1 Mouse Left": "WMouse L", + "P1 Mouse Center": "WMouse M", + "P1 Mouse Right": "WMouse R", + "P1 Escape": "Escape", + "P1 F1": "F1", + "P1 F2": "F2", + "P1 F3": "F3", + "P1 F4": "F4", + "P1 F5": "F5", + "P1 F6": "F6", + "P1 F7": "F7", + "P1 F8": "F8", + "P1 F9": "F9", + "P1 F10": "F10", + "P1 F11": "F11", + "P1 F12": "F12", + "P1 Grave`": "Grave", + "P1 1(One)": "D1", + "P1 2": "D2", + "P1 3": "D3", + "P1 4": "D4", + "P1 5": "D5", + "P1 6": "D6", + "P1 7": "D7", + "P1 8": "D8", + "P1 9": "D9", + "P1 0(Zero)": "D0", + "P1 Minus-": "Minus", + "P1 Equals=": "Equals", + "P1 Backslash\\": "Backslash", + "P1 Backspace": "Backspace", + "P1 Tab": "Tab", + "P1 Q": "Q", + "P1 W": "W", + "P1 E": "E", + "P1 R(Key)": "R", + "P1 T": "T", + "P1 Y(Key)": "Y", + "P1 U": "U", + "P1 I": "I", + "P1 O": "O", + "P1 P": "P", + "P1 LeftBracket[": "LeftBracket", + "P1 RightBracket]": "RightBracket", + "P1 Enter": "Return", + "P1 CapsLock": "CapsLock", + "P1 A(Key)": "A", + "P1 S": "S", + "P1 D": "D", + "P1 F": "F", + "P1 G": "G", + "P1 H": "H", + "P1 J": "J", + "P1 K": "K", + "P1 L(Key)": "L", + "P1 Semicolon;": "Semicolon", + "P1 Quote'": "Apostrophe", + "P1 LeftShift": "LeftShift", + "P1 Z(Key)": "Z", + "P1 X(Key)": "X", + "P1 C(Key)": "C", + "P1 V": "V", + "P1 B(Key)": "B", + "P1 N": "N", + "P1 M": "M", + "P1 Comma,": "Comma", + "P1 Period.": "Period", + "P1 Slash/": "Slash", + "P1 RightShift": "RightShift", + "P1 LeftCtrl": "LeftControl", + "P1 LeftAlt": "LeftAlt", + "P1 Space": "Space", + "P1 RightAlt": "RightAlt", + "P1 RightCtrl": "RightControl", + "P1 PrintScreen": "", + "P1 ScrollLock": "ScrollLock", + "P1 Pause": "Pause", + "P1 Insert": "Insert", + "P1 Delete": "Delete", + "P1 Home": "Home", + "P1 End": "End", + "P1 PageUp": "PageUp", + "P1 PageDown": "PageDown", + "P1 Up": "UpArrow", + "P1 Down": "DownArrow", + "P1 CursorLeft": "LeftArrow", + "P1 Right": "RightArrow", + "P1 NumLock": "NumberLock", + "P1 KeypadSlash(Divide)": "NumberPadSlash", + "P1 KeypadAsterisk(Multiply)": "NumberPadStar", + "P1 KeypadMinus": "NumberPadMinus", + "P1 KeypadHome/7": "NumberPad7", + "P1 KeypadUp/8": "NumberPad8", + "P1 KeypadPageup/9": "NumberPad9", + "P1 KeypadPlus": "NumberPadPlus", + "P1 KeypadLeft/4": "NumberPad4", + "P1 KeypadCenter/5": "NumberPad5", + "P1 KeypadRight/6": "NumberPad6", + "P1 KeypadEnd/1": "NumberPad1", + "P1 KeypadDown/2": "NumberPad2", + "P1 KeypadPagedown/3": "NumberPad3", + "P1 KeypadEnter": "NumberPadEnter", + "P1 KeypadInsert/0": "NumberPad0", + "P1 KeypadDelete": "NumberPadPeriod" + }, + "PC Engine Controller": { + "Reset": "", + "Power": "", + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 B2": "Z, J1 B1, X1 X", + "P1 B1": "X, J1 B2, X1 A", + "P1 Select": "V, J1 B9, X1 Back", + "P1 Run": "Return, J1 B10, X1 Start", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 B1": "", + "P2 B2": "", + "P2 Select": "", + "P2 Run": "", + "P3 Up": "", + "P3 Down": "", + "P3 Left": "", + "P3 Right": "", + "P3 B1": "", + "P3 B2": "", + "P3 Select": "", + "P3 Run": "", + "P4 Up": "", + "P4 Down": "", + "P4 Left": "", + "P4 Right": "", + "P4 B1": "", + "P4 B2": "", + "P4 Select": "", + "P4 Run": "", + "P5 Up": "", + "P5 Down": "", + "P5 Left": "", + "P5 Right": "", + "P5 B1": "", + "P5 B2": "", + "P5 Select": "", + "P5 Run": "" + }, + "ColecoVision Basic Controller": { + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 L": "Z, J1 B5, X1 LeftShoulder", + "P1 R": "X, J1 B6, X1 RightShoulder", + "P1 Key 1": "NumberPad1, J1 B1, X1 X", + "P1 Key 2": "NumberPad2, J1 B2, X1 A", + "P1 Key 3": "NumberPad3, J1 B3, X1 B", + "P1 Key 4": "NumberPad4, J1 B4, X1 Y", + "P1 Key 5": "NumberPad5, J1 RotationZ-, X1 RStickUp", + "P1 Key 6": "NumberPad6, J1 RotationZ+, X1 RStickDown", + "P1 Key 7": "NumberPad7, J1 Z-, X1 RStickLeft", + "P1 Key 8": "NumberPad8, J1 Z+, X1 RStickRight", + "P1 Key 9": "NumberPad9, J1 B11, X1 LeftThumb", + "P1 Star": "NumberPadEnter, J1 B9, X1 Back", + "P1 Key 0": "NumberPad0, J1 B12, X1 RightThumb", + "P1 Pound": "NumberPadPeriod, J1 B10, X1 Start", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 L": "", + "P2 R": "", + "P2 Key1": "", + "P2 Key2": "", + "P2 Key3": "", + "P2 Key4": "", + "P2 Key5": "", + "P2 Key6": "", + "P2 Key7": "", + "P2 Key8": "", + "P2 Key9": "", + "P2 Star": "", + "P2 Key0": "", + "P2 Pound": "" + }, + "SMS Controller": { + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 B1": "Z, J1 B1, X1 X", + "P1 B2": "X, J1 B2, X1 A", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 B1": "", + "P2 B2": "" + }, + "SMS Paddle Controller": { + "P1 Left": "LeftArrow, J1 POV1L", + "P1 Right": "RightArrow, J1 POV1R", + "P1 B1": "Z, J1 B1, X1 X", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start" + }, + "SMS Light Phaser Controller": { + "P1 Trigger": "Z, J1 B1, X1 X, WMouse L", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start" + }, + "SMS Sports Pad Controller": { + "P1 Up": "UpArrow, J1 POV1U", + "P1 Down": "DownArrow, J1 POV1D", + "P1 Left": "LeftArrow, J1 POV1L", + "P1 Right": "RightArrow, J1 POV1R", + "P1 B1": "Z, J1 B1, X1 X", + "P1 B2": "X, J1 B2, X1 A", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 B1": "", + "P2 B2": "" + }, + "SMS Keyboard Controller": { + "Key 1": "D1", + "Key 2": "D2", + "Key 3": "D3", + "Key 4": "D4", + "Key 5": "D5", + "Key 6": "D6", + "Key 7": "D7", + "Key 8": "D8", + "Key 9": "D9", + "Key 0": "D0", + "Key Minus": "Minus", + "Key Caret": "Equals", + "Key Yen": "Backspace", + "Key Break": "Delete", + + "Key Function": "Tab", + "Key Q": "Q", + "Key W": "W", + "Key E": "E", + "Key R": "R", + "Key T": "T", + "Key Y": "Y", + "Key U": "U", + "Key I": "I", + "Key O": "O", + "Key P": "P", + "Key At": "LeftBracket", + "Key Left Bracket": "RightBracket", + "Key Return": "Return", + "Key Up Arrow": "UpArrow", + + "Key Control": "CapsLock", + "Key A": "A", + "Key S": "S", + "Key D": "D", + "Key F": "F", + "Key G": "G", + "Key H": "H", + "Key J": "J", + "Key K": "K", + "Key L": "L", + "Key Semicolon": "Semicolon", + "Key Colon": "Apostrophe", + "Key Right Bracket": "Backslash", + "Key Left Arrow": "LeftArrow", + "Key Right Arrow": "RightArrow", + + "Key Shift": "LeftShift", + "Key Z": "Z", + "Key X": "X", + "Key C": "C", + "Key V": "V", + "Key B": "B", + "Key N": "N", + "Key M": "M", + "Key Comma": "Comma", + "Key Period": "Period", + "Key Slash": "Slash", + "Key PI": "RightShift", + "Key Down Arrow": "DownArrow", + + "Key Graph": "PageUp", + "Key Kana": "PageDown", + "Key Space": "Space", + "Key Home/Clear": "Home", + "Key Insert/Delete": "Insert", + + "P1 Up": "J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 B1": "J1 B1, X1 X", + "P1 B2": "J1 B2, X1 A", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 B1": "", + "P2 B2": "" + }, + "GG Controller": { + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 B1": "Z, J1 B1, X1 X", + "P1 B2": "X, J1 B2, X1 A", + "Reset": "J1 B9, X1 Back", + "P1 Start": "Return, J1 B10, X1 Start" + }, + "Dual Gameboy Controller": { + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 Start": "Return, J1 B10, X1 Start", + "P1 Select": "Space, J1 B9, X1 Space", + "P1 B": "Z, J1 B1, X1 X", + "P1 A": "X, J1 B2, X1 A", + "P1 Power": "", + "P2 Up": "NumberPad8, J1 RotationZ-, X1 RStickUp", + "P2 Down": "NumberPad2, J1 RotationZ+, X1 RStickDown", + "P2 Left": "NumberPad4, J1 Z-, X1 RStickLeft", + "P2 Right": "NumberPad6, J1 Z+, X1 RStickRight", + "P2 Start": "RightBracket, J1 B5, X1 LeftShoulder", + "P2 Select": "LeftBracket, J1 B6, X1 RightShoulder", + "P2 B": "C, J1 B4, X1 Y", + "P2 A": "V, J1 B3, X1 B", + "P2 Power": "" + }, + "TI83 Controller": { + "0": "NumberPad0", + "1": "NumberPad1", + "2": "NumberPad2", + "3": "NumberPad3", + "4": "NumberPad4", + "5": "NumberPad5", + "6": "NumberPad6", + "7": "NumberPad7", + "8": "NumberPad8", + "9": "NumberPad9", + "DOT": "NumberPadPeriod", + "ON": "Space", + "ENTER": "Return, NumberPadEnter", + "DOWN": "DownArrow", + "UP": "UpArrow", + "LEFT": "LeftArrow", + "RIGHT": "RightArrow", + "PLUS": "NumberPadPlus", + "MINUS": "NumberPadMinus", + "MULTIPLY": "NumberPadStar", + "DIVIDE": "NumberPadSlash", + "CLEAR": "Escape", + "EXP": "6", + "DASH": "Minus", + "PARACLOSE": "0", + "TAN": "T", + "VARS": "V", + "PARAOPEN": "9", + "COS": "C", + "PRGM": "R", + "STAT": "S", + "SIN": "Period", + "MATRIX": "LeftBracket", + "X": "X", + "STO": "Insert", + "LN": "L", + "LOG": "O", + "SQUARED": "2", + "NEG1": "1", + "MATH": "M", + "ALPHA": "A", + "GRAPH": "G", + "TRACE": "Home", + "ZOOM": "Z", + "WINDOW": "W", + "Y": "Y", + "SECOND": "Slash", + "MODE": "BackSlash", + "DEL": "Delete", + "COMMA": "Comma" + }, + "GPGX Genesis Controller": { + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 A": "Z, J1 B1, X1 X", + "P1 B": "X, J1 B2, X1 A", + "P1 C": "C, J1 B4, X1 Y", + "P1 Start": "Return, J1 B10, X1 Start", + "P1 X": "A, J1 B3, X1 B", + "P1 Y": "S, J1 B5, X1 LeftShoulder", + "P1 Z": "D, J1 B6, X1 RightShoulder", + "P1 Mode": "E, J1 B9, X1 Back", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 A": "", + "P2 B": "", + "P2 C": "", + "P2 Start": "", + "P2 X": "", + "P2 Y": "", + "P2 Z": "", + "P2 Mode": "", + "P2 Lightgun Trigger": "WMouse L", + "P2 Lightgun Start": "NumberPad5", + "P2 Mouse Left": "WMouse L", + "P2 Mouse Center": "WMouse M", + "P2 Mouse Right": "WMouse R", + "P2 Mouse Start": "NumberPad5", + "Power": "", + "Reset": "" + }, + "PicoDrive Genesis Controller": { + "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 A": "Z, J1 B1, X1 X", + "P1 B": "X, J1 B2, X1 A", + "P1 C": "C, J1 B4, X1 Y", + "P1 Start": "Return, J1 B10, X1 Start", + "P1 X": "A, J1 B3, X1 B", + "P1 Y": "S, J1 B5, X1 LeftShoulder", + "P1 Z": "D, J1 B6, X1 RightShoulder", + "P1 Mode": "E, J1 B9, X1 Back", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 A": "", + "P2 B": "", + "P2 C": "", + "P2 Start": "", + "P2 X": "", + "P2 Y": "", + "P2 Z": "", + "P2 Mode": "", + "Power": "", + "Reset": "" + }, + "WonderSwan Controller": { + "P1 X1": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P1 X3": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P1 X4": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P1 X2": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P1 Y1": "NumberPad8, J1 RotationZ-, X1 RStickUp", + "P1 Y3": "NumberPad2, J1 RotationZ+, X1 RStickDown", + "P1 Y4": "NumberPad4, J1 Z-, X1 RStickLeft", + "P1 Y2": "NumberPad6, J1 Z+, X1 RStickRight", + "P1 Start": "Return, J1 B10, X1 Start", + "P1 B": "Z, J1 B1, X1 X", + "P1 A": "X, J1 B2, X1 A", + "P2 X1": "", + "P2 X3": "X, J1 B2, X1 A", + "P2 X4": "Z, J1 B1, X1 X", + "P2 X2": "", + "P2 Y1": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft", + "P2 Y3": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight", + "P2 Y4": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", + "P2 Y2": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", + "P2 Start": "Return, J1 B10, X1 Start", + "P2 B": "", + "P2 A": "", + "Power": "" + }, + "PSX DualShock Controller": { + "P1 Up": "X1 DpadUp,UpArrow", + "P1 Down": "X1 DpadDown,DownArrow", + "P1 Left": "X1 DpadLeft,LeftArrow", + "P1 Right": "X1 DpadRight,RightArrow", + "P1 Select": "X1 Back,Space", + "P1 Start": "X1 Start,Return", + "P1 Square": "X1 X,A", + "P1 Triangle": "X1 Y,S", + "P1 Circle": "X1 B,X", + "P1 Cross": "X1 A,Z", + "P1 L1": "X1 LeftShoulder,Q", + "P1 R1": "X1 RightShoulder,W", + "P1 L2": "X1 LeftTrigger,E", + "P1 R2": "X1 RightTrigger,R", + "P1 L3": "X1 LeftThumb,T", + "P1 R3": "X1 RightThumb,Y", + "P1 MODE": "D" + }, + "Lynx Controller": { + "Up": "UpArrow", + "Down": "DownArrow", + "Left": "LeftArrow", + "Right": "RightArrow", + "A": "X", + "B": "Z", + "Option 1": "A", + "Option 2": "S", + "Pause": "Return", + "Power": "" + }, + "Apple IIe Keyboard": { + "Delete": "Delete", + "Left": "LeftArrow", + "Tab": "Tab", + "Down": "DownArrow", + "Up": "UpArrow", + "Return": "Return", + "Right": "RightArrow", + "Escape": "", + "Space": "Space", + "'": "Apostrophe", + ",": "Comma", + "-": "Minus", + ".": "Period", + "/": "Slash", + "0": "NumberPad0", + "1": "NumberPad1", + "2": "NumberPad2", + "3": "NumberPad3", + "4": "NumberPad4", + "5": "NumberPad5", + "6": "NumberPad6", + "7": "NumberPad7", + "8": "NumberPad8", + "9": "NumberPad9", + ";": "Semicolon", + "=": "Equals", + "[": "LeftBracket", + "\\": "Backslash", + "]": "RightBracket", + "`": "Grave", + "A": "A", + "B": "B", + "C": "C", + "D": "D", + "E": "E", + "F": "F", + "G": "G", + "H": "H", + "I": "I", + "J": "J", + "K": "K", + "L": "L", + "M": "M", + "N": "N", + "O": "O", + "P": "P", + "Q": "Q", + "R": "R", + "S": "S", + "T": "T", + "U": "U", + "V": "V", + "W": "W", + "X": "X", + "Y": "Y", + "Z": "Z", + "Control": "RightControl", + "Shift": "RightShift", + "Caps Lock": "CapsLock", + "Previous Disk": "", + "Next Disk": "" + }, + "VirtualBoy Controller": { + "L_Up": "UpArrow, X1 DpadUp, X1 LStickUp", + "L_Down": "DownArrow, X1 DpadDown, X1 LStickDown", + "L_Left": "LeftArrow, X1 DpadLeft, X1 LStickLeft", + "L_Right": "RightArrow, X1 DpadRight, X1 LStickRight", + "R_Up": "NumberPad8, X1 RStickUp", + "R_Down": "NumberPad2, X1 RStickDown", + "R_Left": "NumberPad4, X1 RStickLeft", + "R_Right": "NumberPad6, X1 RStickRight", + "B": "Z, X1 X", + "A": "X, X1 A", + "R": "W, X1 LeftShoulder", + "L": "E, X1 RightShoulder", + "Select": "Space, X1 Back", + "Start": "Return, X1 Start", + "Power": "" + }, + "NeoGeo Portable Controller": { + "Up": "UpArrow, X1 DpadUp, X1 LStickUp", + "Down": "DownArrow, X1 DpadDown, X1 LStickDown", + "Left": "LeftArrow, X1 DpadLeft, X1 LStickLeft", + "Right": "RightArrow, X1 DpadRight, X1 LStickRight", + "B": "Z, J1 B1, X1 X", + "A": "X, J1 B2, X1 A", + "Option": "Return, J1 B10, X1 Start", + "Power": "" + } + }, + "AllTrollersAutoFire": { + "NES Controller": { + "P1 Up": "", + "P1 Down": "", + "P1 Left": "", + "P1 Right": "", + "P1 Start": "", + "P1 Select": "", + "P1 B": "A", + "P1 A": "S", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 Start": "", + "P2 Select": "", + "P2 B": "", + "P2 A": "", + "P2 Fire": "", + "P2 Microphone": "", + "P3 Fire": "", + "Reset": "", + "Power": "" + }, + "Gameboy Controller": { + "Up": "", + "Down": "", + "Left": "", + "Right": "", + "Start": "", + "Select": "", + "B": "A", + "A": "S", + "Power": "" + }, + "Gameboy Controller H": { + "Up": "", + "Down": "", + "Left": "", + "Right": "", + "Start": "", + "Select": "", + "B": "A", + "A": "S", + "Power": "" + }, + "GBAController": { + "Up": "", + "Down": "", + "Left": "", + "Right": "", + "Start": "", + "Select": "", + "B": "A", + "A": "S", + "L": "", + "R": "", + "Power": "" + }, + "Atari 2600 Basic Controller": { + "Reset": "", + "Select": "", + "P1 Up": "", + "P1 Down": "", + "P1 Left": "", + "P1 Right": "", + "P1 Button": "A", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 Button": "S" + }, + "PC Engine Controller": { + "Reset": "", + "Power": "", + "P1 Up": "", + "P1 Down": "", + "P1 Left": "", + "P1 Right": "", + "P1 B2": "A", + "P1 B1": "S", + "P1 Select": "", + "P1 Run": "", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 B2": "", + "P2 B1": "", + "P2 Select": "", + "P2 Run": "", + "P3 Up": "", + "P3 Down": "", + "P3 Left": "", + "P3 Right": "", + "P3 B2": "", + "P3 B1": "", + "P3 Select": "", + "P3 Run": "", + "P4 Up": "", + "P4 Down": "", + "P4 Left": "", + "P4 Right": "", + "P4 B2": "", + "P4 B1": "", + "P4 Select": "", + "P4 Run": "", + "P5 Up": "", + "P5 Down": "", + "P5 Left": "", + "P5 Right": "", + "P5 B2": "", + "P5 B1": "", + "P5 Select": "", + "P5 Run": "" + }, + "SMS Controller": { + "P1 Up": "", + "P1 Down": "", + "P1 Left": "", + "P1 Right": "", + "P1 B1": "A", + "P1 B2": "S", + "Reset": "", + "Pause": "", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 B1": "", + "P2 B2": "" + }, + "GPGX Genesis Controller": { + "P1 Up": "", + "P1 Down": "", + "P1 Left": "", + "P1 Right": "", + "P1 A": "", + "P1 B": "", + "P1 C": "", + "P1 Start": "", + "P1 X": "", + "P1 Y": "", + "P1 Z": "", + "P1 Mode": "", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 A": "", + "P2 B": "", + "P2 C": "", + "P2 Start": "", + "P2 X": "", + "P2 Y": "", + "P2 Z": "", + "P2 Mode": "", + "Power": "", + "Reset": "" + }, + "GBA Controller": { + "Up": "", + "Down": "", + "Left": "", + "Right": "", + "Start": "", + "Select": "", + "B": "A", + "A": "S", + "L": "", + "R": "", + "Power": "" + }, + "WonderSwan Controller": { + "P1 B": "A", + "P1 A": "S", + "P2 X4": "A", + "P2 X3": "S", + "Power": "" + }, + "Lynx Controller": { + "Up": "", + "Down": "", + "Left": "", + "Right": "", + "A": "", + "B": "", + "Option 1": "", + "Option 2": "", + "Pause": "", + "Power": "" + }, + "Apple IIe Keyboard": { + "Delete": "", + "Left": "", + "Tab": "", + "Down": "", + "Up": "", + "Return": "Return", + "Right": "", + "Escape": "", + "Space": "", + "'": "", + ",": "", + "-": "", + ".": "", + "/": "", + "0": "", + "1": "", + "2": "", + "3": "", + "4": "", + "5": "", + "6": "", + "7": "", + "8": "", + "9": "", + ";": "", + "=": "", + "[": "", + "\\": "", + "]": "", + "`": "", + "A": "", + "B": "", + "C": "", + "D": "", + "E": "", + "F": "", + "G": "", + "H": "", + "I": "", + "J": "", + "K": "", + "L": "", + "M": "", + "N": "", + "O": "", + "P": "", + "Q": "", + "R": "", + "S": "", + "T": "", + "U": "", + "V": "", + "W": "", + "X": "", + "Y": "", + "Z": "", + "Control": "", + "Shift": "", + "Caps Lock": "", + "Previous Disk": "", + "Next Disk": "" + }, + "VirtualBoy Controller": { + "L_Up": "", + "L_Down": "", + "L_Left": "", + "L_Right": "", + "R_Up": "", + "R_Down": "", + "R_Left": "", + "R_Right": "", + "B": "", + "A": "", + "R": "", + "L": "", + "Select": "", + "Start": "", + "Power": "" + }, + "NeoGeo Portable Controller": { + "Up": "", + "Down": "", + "Left": "", + "Right": "", + "B": "", + "A": "", + "Option": "", + "Power": "" + } + }, "AllTrollersAnalog": { "NES Controller": { "P2 Paddle": { diff --git a/BizHawk.Client.EmuHawk/config/ControllerConfig.cs b/BizHawk.Client.EmuHawk/config/ControllerConfig.cs index 4b54d570be..303f054169 100644 --- a/BizHawk.Client.EmuHawk/config/ControllerConfig.cs +++ b/BizHawk.Client.EmuHawk/config/ControllerConfig.cs @@ -24,6 +24,8 @@ namespace BizHawk.Client.EmuHawk ControllerImages.Add("SNES Controller", Properties.Resources.SNES_Controller); ControllerImages.Add("Nintento 64 Controller", Properties.Resources.N64); ControllerImages.Add("Gameboy Controller", Properties.Resources.GBController); + ControllerImages.Add("Gameboy Controller H", Properties.Resources.GBController); + ControllerImages.Add("Gameboy Controller + Tilt", Properties.Resources.GBController); ControllerImages.Add("GBA Controller", Properties.Resources.GBA_Controller); ControllerImages.Add("Dual Gameboy Controller", Properties.Resources.GBController); From 642bc13e842e490d80431837c7f82b7e59313877 Mon Sep 17 00:00:00 2001 From: zeromus Date: Mon, 24 Dec 2018 20:33:09 -0500 Subject: [PATCH 03/15] fix build error (maybe some new c# thing) --- .../Consoles/Sega/gpgx64/GPGX.ITraceable.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs index 377a6ab7be..c8d8dab662 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ITraceable.cs @@ -23,7 +23,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx { var regs = DebuggableCore.GetCpuFlagsAndRegisters(); uint pc = (uint)regs["M68K PC"].Value; - var disasm = Disassembler.Disassemble(MemoryDomains.SystemBus, pc & 0xFFFFFF, out int length); + int length; + var disasm = Disassembler.Disassemble(MemoryDomains.SystemBus, pc & 0xFFFFFF, out length); var traceInfo = new TraceInfo { From 45de86de8d06a8fef7d1b0e4ac398b9ef0aeafd6 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Fri, 28 Dec 2018 06:51:22 -0600 Subject: [PATCH 04/15] GBHawk: LY = LYC Fix: Fixes Slugfest --- .../Consoles/Nintendo/GBHawk/GBC_PPU.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs index 7c679ab952..18574b8a3e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs @@ -112,11 +112,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk case 0xFF41: // STAT // note that their is no stat interrupt bug in GBC // writing to STAT during mode 0 or 1 causes a STAT IRQ - if (LCDC.Bit(7) && !Core.GBC_compat) + if (LCDC.Bit(7)) { - if (((STAT & 3) == 0) || ((STAT & 3) == 1)) + if (!Core.GBC_compat) { - LYC_INT = true; + if (((STAT & 3) == 0) || ((STAT & 3) == 1)) + { + LYC_INT = true; + } + } + + if (value.Bit(6)) + { + if (LY == LYC) { LYC_INT = true; } + else { LYC_INT = false; } } } STAT = (byte)((value & 0xF8) | (STAT & 7) | 0x80); From 36e159da7273cc8ce2de5cd786fa47c6c3fd781c Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Fri, 28 Dec 2018 09:15:16 -0600 Subject: [PATCH 05/15] GBHawk: GBC pass remaining Wilbert Pol tests --- .../Consoles/Nintendo/GBHawk/GBC_PPU.cs | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs index 18574b8a3e..6c137ea199 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs @@ -53,6 +53,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public int last_HBL; public bool HBL_HDMA_go; public bool HBL_test; + public byte LYC_t; + public int LYC_cd; public override byte ReadReg(int addr) { @@ -143,20 +145,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk LY = 0; /*reset*/ break; case 0xFF45: // LYC - LYC = value; - if (LCDC.Bit(7)) - { - if (LY != LYC) { STAT &= 0xFB; LYC_INT = false; } - else { STAT |= 0x4; LYC_INT = true; } - // special case: at cycle 454, some strange things are happening, and it appears as though LY becomes LY + 1 - // two cycles ahead of where it's supposed to. this is probably related to strange behaviour around cycle 452 - if ((LY_inc == 0) && cycle == 6) - { - //if (0 == LYC) { STAT |= 0x4; LYC_INT = true; } - //else { STAT &= 0xFB; LYC_INT = false; } - } - } + // tests indicate that latching writes to LYC should take place 4 cycles after the write + // otherwise tests around LY boundaries will fail + LYC_t = value; + LYC_cd = 4; break; case 0xFF46: // DMA DMA_addr = value; @@ -578,12 +571,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (LY_inc == 0) { - if (cycle == 10) + if (cycle == 12) { LYC_INT = false; STAT &= 0xFB; } - else if (cycle == 12) + else if (cycle == 14) { // Special case of LY = LYC if ((LY == LYC) && !STAT.Bit(2)) @@ -596,7 +589,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } // here LY=LYC will be asserted or cleared (but only if LY isnt 0 as that's a special case) - if ((cycle == 2) && (LY != 0)) + if ((cycle == 4) && (LY != 0)) { if (LY_inc == 1) { @@ -604,7 +597,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk STAT &= 0xFB; } } - else if ((cycle == 4) && (LY != 0)) + else if ((cycle == 6) && (LY != 0)) { if ((LY == LYC) && !STAT.Bit(2)) { @@ -645,6 +638,21 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // process latch delays //latch_delay(); + + if (LYC_cd > 0) + { + LYC_cd--; + if (LYC_cd == 0) + { + LYC = LYC_t; + + if (LCDC.Bit(7)) + { + if (LY != LYC) { STAT &= 0xFB; LYC_INT = false; } + else { STAT |= 0x4; LYC_INT = true; } + } + } + } } // might be needed, not sure yet @@ -1535,6 +1543,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync("BG_bytes_index", ref BG_bytes_index); ser.Sync("OBJ_bytes_index", ref OBJ_bytes_index); + ser.Sync("LYC_t", ref LYC_t); + ser.Sync("LYC_cd", ref LYC_cd); + base.SyncState(ser); } From 19f3aeec3acf8c063d853ad079a79f05869b1bd2 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Fri, 28 Dec 2018 10:11:37 -0600 Subject: [PATCH 06/15] GBHawk: GBC HW IO --- .../Nintendo/GBHawk/GBHawk.IStatable.cs | 8 ++ .../Consoles/Nintendo/GBHawk/GBHawk.cs | 3 + .../Consoles/Nintendo/GBHawk/HW_Registers.cs | 80 ++++++++++++++++++- 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs index 104274715c..161f06c92d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs @@ -90,6 +90,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync("speed_switch", ref speed_switch); ser.Sync("HDMA_transfer", ref HDMA_transfer); + ser.Sync("undoc_6C", ref undoc_6C); + ser.Sync("undoc_72", ref undoc_72); + ser.Sync("undoc_73", ref undoc_73); + ser.Sync("undoc_74", ref undoc_74); + ser.Sync("undoc_75", ref undoc_75); + ser.Sync("undoc_76", ref undoc_76); + ser.Sync("undoc_77", ref undoc_77); + ser.Sync("Use_MT", ref Use_MT); ser.Sync("addr_access", ref addr_access); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs index a809042862..d14cc55f50 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs @@ -56,6 +56,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public bool speed_switch; public bool HDMA_transfer; // stalls CPU when in progress + // several undocumented GBC Registers + public byte undoc_6C, undoc_72, undoc_73, undoc_74, undoc_75, undoc_76, undoc_77; + public byte[] _bios; public readonly byte[] _rom; public readonly byte[] header = new byte[0x50]; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs index 249c8e3ddf..5124e4371f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs @@ -101,7 +101,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // Speed Control for GBC case 0xFF4D: - if (is_GBC) + if (GBC_compat) { ret = (byte)(((double_speed ? 1 : 0) << 7) + ((speed_switch ? 1 : 0))); } @@ -149,7 +149,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // Speed Control for GBC case 0xFF70: - if (is_GBC) + if (GBC_compat) { ret = (byte)RAM_Bank; } @@ -159,6 +159,41 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } break; + case 0xFF6C: + if (GBC_compat) { ret = undoc_6C; } + else { ret = 0xFF; } + break; + + case 0xFF72: + if (is_GBC) { ret = undoc_72; } + else { ret = 0xFF; } + break; + + case 0xFF73: + if (is_GBC) { ret = undoc_73; } + else { ret = 0xFF; } + break; + + case 0xFF74: + if (GBC_compat) { ret = undoc_74; } + else { ret = 0xFF; } + break; + + case 0xFF75: + if (is_GBC) { ret = undoc_75; } + else { ret = 0xFF; } + break; + + case 0xFF76: + if (is_GBC) { ret = undoc_76; } + else { ret = 0xFF; } + break; + + case 0xFF77: + if (is_GBC) { ret = undoc_77; } + else { ret = 0xFF; } + break; + // interrupt control register case 0xFFFF: ret = REG_FFFF; @@ -323,7 +358,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // Speed Control for GBC case 0xFF4D: - if (is_GBC) + if (GBC_compat) { speed_switch = (value & 1) > 0; } @@ -365,13 +400,41 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // RAM Bank in GBC mode case 0xFF70: //Console.WriteLine(value); - if (is_GBC) + if (GBC_compat) { RAM_Bank = value & 7; if (RAM_Bank == 0) { RAM_Bank = 1; } } break; + case 0xFF6C: + if (GBC_compat) { undoc_6C |= (byte)(value & 1); } + break; + + case 0xFF72: + if (is_GBC) { undoc_72 = value; } + break; + + case 0xFF73: + if (is_GBC) { undoc_73 = value; } + break; + + case 0xFF74: + if (GBC_compat) { undoc_74 = value; } + break; + + case 0xFF75: + if (is_GBC) { undoc_75 |= (byte)(value & 0x70); } + break; + + case 0xFF76: + // read only + break; + + case 0xFF77: + // read only + break; + // interrupt control register case 0xFFFF: REG_FFFF = value; @@ -401,6 +464,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public void Register_Reset() { input_register = 0xCF; // not reading any input + + //undocumented registers + undoc_6C = 0xFE; + undoc_72 = 0; + undoc_73 = 0; + undoc_74 = 0; + undoc_75 = 0x8F; + undoc_76 = 0; + undoc_77 = 0; } } } From cf806baff7aaca3246d62623e7ba91f30894743e Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Fri, 28 Dec 2018 19:49:20 -0600 Subject: [PATCH 07/15] GBHawk: Fix very stupid bug: Fixes Lego Racers --- BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs index 6c137ea199..b02084f64b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs @@ -37,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public byte HDMA_ctrl { - get { return (byte)(((HDMA_active ? 0 : 1) << 7) | ((HDMA_length >> 16) - 1)); } + get { return (byte)(((HDMA_active ? 0 : 1) << 7) | ((HDMA_length >> 4) - 1)); } } From 9d14c1f214eac85012e527a80bd88625e8fda5d8 Mon Sep 17 00:00:00 2001 From: zeromus Date: Sun, 30 Dec 2018 02:32:38 -0500 Subject: [PATCH 08/15] fix ugly cleartype mangling on lua canvas drawtext, unintended goof-up in code. fixes #1411 --- BizHawk.Client.EmuHawk/tools/Lua/LuaPictureBox.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaPictureBox.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaPictureBox.cs index 301cfa90f9..6c8bf524d5 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaPictureBox.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaPictureBox.cs @@ -373,7 +373,6 @@ namespace BizHawk.Client.EmuHawk boxBackground.FillRectangle(GetBrush(backcolor ?? _defaultTextBackground.Value), rect); boxBackground = Graphics.FromImage(Image); boxBackground.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit; - boxBackground = Graphics.FromImage(Image); boxBackground.DrawString(message, font, new SolidBrush(forecolor ?? Color.Black), x, y); } From 0621db45853ab2bf707783a752935bc2922bc3dd Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 31 Dec 2018 19:14:53 -0600 Subject: [PATCH 09/15] GBHawk: inital register state --- BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs index d14cc55f50..d7c8edcf4f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs @@ -278,7 +278,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk private void HardReset() { GB_bios_register = 0; // bios enable - GBC_compat = true; + GBC_compat = is_GBC; in_vblank = true; // we start off in vblank since the LCD is off in_vblank_old = true; From 3766e2380cf02074a923e9164aa5fa6389e3191b Mon Sep 17 00:00:00 2001 From: Asnivor Date: Wed, 2 Jan 2019 12:38:32 +0000 Subject: [PATCH 10/15] ZXHawk: Fix exception thrown randomly by tape player subsystem --- .../SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs index 55e4a1d14c..c47af9c1b0 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs @@ -624,9 +624,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } } - // update waitEdge with current position within the current block - _waitEdge = _dataBlocks[_currentDataBlockIndex].DataPeriods[_position]; - + // update waitEdge with current position within the current block + _waitEdge = _dataBlocks[_currentDataBlockIndex].DataPeriods.Count() > 0 ? _dataBlocks[_currentDataBlockIndex].DataPeriods[_position] : 0; // flip the current state FlipTapeState(); From 2b7014f8b8b4ea16fb6386c02eab7a47c0062326 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Wed, 2 Jan 2019 14:02:09 +0000 Subject: [PATCH 11/15] ZXHawk: Some comment and group structure cleanup --- .../BizHawk.Emulation.Cores.csproj | 154 ++++++++++++------ .../Hardware/Datacorder/DatacorderDevice.cs | 68 ++------ .../Hardware/Input/StandardKeyboard.cs | 1 - .../Hardware/SoundOuput/Beeper.cs | 2 - .../Machine/SpectrumBase.Input.cs | 2 - .../Machine/SpectrumBase.Media.cs | 5 +- .../Machine/SpectrumBase.Memory.cs | 1 + .../Machine/SpectrumBase.Port.cs | 17 -- .../SinclairSpectrum/Machine/SpectrumBase.cs | 9 +- .../Computers/SinclairSpectrum/Machine/ULA.cs | 2 - .../Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs | 3 +- .../Machine/ZXSpectrum48K/ZX48.cs | 2 - .../ZXSpectrum.IMemoryDomains.cs | 20 +-- .../SinclairSpectrum/ZXSpectrum.ISettable.cs | 12 +- .../SinclairSpectrum/ZXSpectrum.Util.cs | 21 ++- 15 files changed, 153 insertions(+), 166 deletions(-) diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index c4d8705210..f57d61d6eb 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -317,27 +317,33 @@ + - - - - - - - - + - - - - - - + + NECUPD765.cs + + + NECUPD765.cs + + + NECUPD765.cs + + + NECUPD765.cs + + + NECUPD765.cs + + + NECUPD765.cs + @@ -346,10 +352,6 @@ - - - - @@ -372,30 +374,94 @@ - - - - - - - - - - - - - - + + SpectrumBase.cs + + + SpectrumBase.cs + + + SpectrumBase.cs + + + SpectrumBase.cs + + + + + + ZX48.cs + + + ZX48.cs + + + + + + ZX128.cs + + + ZX128.cs + + + + + + ZX128Plus2a.cs + + + ZX128Plus2a.cs + + + + + ZX128Plus3.cs + + + ZX128Plus3.cs + + + + Pentagon128.cs + + + Pentagon128.cs + + + + - - - - - - - - - + + ZXSpectrum.cs + + + ZXSpectrum.cs + + + ZXSpectrum.cs + + + ZXSpectrum.cs + + + ZXSpectrum.cs + + + ZXSpectrum.cs + + + ZXSpectrum.cs + + + ZXSpectrum.cs + + + ZXSpectrum.cs + + + ZXSpectrum.cs + Atari2600.cs @@ -1500,13 +1566,7 @@ - - - - - - diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs index c47af9c1b0..3ae4eafd72 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs @@ -131,13 +131,16 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// /// Should be fired at the end of every frame - /// Primary purpose is to detect tape traps and manage auto play (if/when this is ever implemented) + /// Primary purpose is to detect tape traps and manage auto play /// public void EndFrame() { MonitorFrame(); } + /// + /// No longer in use + /// public void StartFrame() { //_buzzer.ProcessPulseValue(currentState); @@ -296,14 +299,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum sbd.Append("("); sbd.Append((targetBlockId + 1) + " of " + _dataBlocks.Count()); sbd.Append(") : "); - //sbd.Append("ID" + bl.BlockID.ToString("X2") + " - "); sbd.Append(bl.BlockDescription); if (bl.MetaData.Count > 0) { sbd.Append(" - "); sbd.Append(bl.MetaData.First().Key + ": " + bl.MetaData.First().Value); - //sbd.Append("\n"); - //sbd.Append(bl.MetaData.Skip(1).First().Key + ": " + bl.MetaData.Skip(1).First().Value); } if (skipForward) @@ -522,7 +522,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum sbd.Append("("); sbd.Append((_currentDataBlockIndex + 1) + " of " + _dataBlocks.Count()); sbd.Append(") : "); - //sbd.Append("ID" + bl.BlockID.ToString("X2") + " - "); sbd.Append(bl.BlockDescription); if (bl.MetaData.Count > 0) { @@ -532,14 +531,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum _machine.Spectrum.OSD_TapePlayingBlockInfo(sbd.ToString()); } - // increment the current period position _position++; if (_position >= _dataBlocks[_currentDataBlockIndex].DataPeriods.Count()) { // we have reached the end of the current block - if (_dataBlocks[_currentDataBlockIndex].DataPeriods.Count() == 0) { // notify about the current block (we are skipping it because its empty) @@ -548,13 +545,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum sbd.Append("("); sbd.Append((_currentDataBlockIndex + 1) + " of " + _dataBlocks.Count()); sbd.Append(") : "); - //sbd.Append("ID" + bl.BlockID.ToString("X2") + " - "); sbd.Append(bl.BlockDescription); if (bl.MetaData.Count > 0) - { - sbd.Append(" - "); - sbd.Append(bl.MetaData.First().Key + ": " + bl.MetaData.First().Value); - } + { + sbd.Append(" - "); + sbd.Append(bl.MetaData.First().Key + ": " + bl.MetaData.First().Value); + } _machine.Spectrum.OSD_TapePlayingSkipBlockInfo(sbd.ToString()); } @@ -583,7 +579,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } _monitorTimeOut = 2000; - break; case TapeCommand.STOP_THE_TAPE_48K: if (is48k) @@ -626,17 +621,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // update waitEdge with current position within the current block _waitEdge = _dataBlocks[_currentDataBlockIndex].DataPeriods.Count() > 0 ? _dataBlocks[_currentDataBlockIndex].DataPeriods[_position] : 0; + // flip the current state FlipTapeState(); - } // update lastCycle and return currentstate _lastCycle = cpuCycle - (long)cycles; - // play the buzzer - //_buzzer.ProcessPulseValue(false, currentState); - return currentState; } @@ -648,6 +640,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// /// Flash loading implementation /// (Deterministic Emulation must be FALSE) + /// CURRENTLY NOT ENABLED/WORKING /// private bool FlashLoad() { @@ -961,47 +954,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum if (_machine.UPDDiskDevice == null || !_machine.UPDDiskDevice.FDD_IsDiskLoaded) MonitorRead(); - /* - - if (TapeIsPlaying) - { - if (GetEarBit(_cpu.TotalExecutedCycles)) - { - result &= ~(TAPE_BIT); // reset is EAR ON - } - else - { - result |= (TAPE_BIT); // set is EAR Off - } - } - else - { - if (_machine.KeyboardDevice.IsIssue2Keyboard) - { - if ((_machine.LASTULAOutByte & (EAR_BIT + MIC_BIT)) == 0) - { - result &= ~(TAPE_BIT); - } - else - { - result |= (TAPE_BIT); - } - } - else - { - if ((_machine.LASTULAOutByte & EAR_BIT) == 0) - { - result &= ~(TAPE_BIT); - } - else - { - result |= TAPE_BIT; - } - } - } - - */ - return true; } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/StandardKeyboard.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/StandardKeyboard.cs index 7e23f843a7..77cb18d38c 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/StandardKeyboard.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Input/StandardKeyboard.cs @@ -183,7 +183,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return (byte)index; } - #region IPortIODevice /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/Beeper.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/Beeper.cs index 5b518b031c..a3f5dec9c4 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/Beeper.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/Beeper.cs @@ -8,9 +8,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// Logical Beeper class /// Represents the piezoelectric buzzer used in the Spectrum to produce sound /// The beeper is controlled by rapidly toggling bit 4 of port &FE - /// /// It is instantiated twice, once for speccy beeper output, and once tape buzzer emulation - /// /// This implementation uses BlipBuffer and should *always* output at 44100 with 882 samples per frame /// (so that it can be mixed easily further down the line) /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Input.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Input.cs index b64fa125eb..18345b0077 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Input.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Input.cs @@ -198,7 +198,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { if (!pressed_TapeStatus) { - //Spectrum.OSD_FireInputMessage(TapeStatus); Spectrum.OSD_ShowTapeStatus(); pressed_TapeStatus = true; } @@ -269,7 +268,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { if (!pressed_DiskStatus) { - //Spectrum.OSD_FireInputMessage(TapeStatus); Spectrum.OSD_ShowDiskStatus(); pressed_DiskStatus = true; } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Media.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Media.cs index 57525f6028..46d6a62de2 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Media.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Media.cs @@ -63,6 +63,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // load the media into the tape device tapeMediaIndex = result; + // fire osd message if (!IsLoadState) Spectrum.OSD_TapeInserted(); @@ -232,10 +233,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum Spectrum.CoreComm.ShowMessage("You are trying to load one of more disk images.\n\n Please select ZX Spectrum +3 emulation immediately and reboot the core"); return; } - else - { - //Spectrum.CoreComm.ShowMessage("You are attempting to load a disk into the +3 disk drive.\n\nThis DOES NOT currently work properly but IS under active development."); - } UPDDiskDevice.FDD_LoadDisk(diskImages[diskMediaIndex]); } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs index 7c39525cdf..475c0cd6bd 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs @@ -199,6 +199,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// /// Monitors ROM access /// Used to auto start/stop the tape device when appropriate + /// * This isnt really used anymore for tape trap detection * /// /// public virtual void TestForTapeTraps(int addr) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs index d1c0f29271..3f5cb5a477 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs @@ -34,22 +34,5 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// /// public abstract void WritePort(ushort port, byte value); - - /// - /// Increments the CPU totalCycles counter by the tStates value specified - /// - /// - //public virtual void PortContention(int tStates) - //{ - // CPU.TotalExecutedCycles += tStates; - //} - - /// - /// Simulates IO port contention based on the supplied address - /// This method is for 48k and 128k/+2 machines only and should be overridden for other models - /// - /// - //public abstract void ContendPort(ushort addr); - } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs index eca5cf0c54..a03e22ed25 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs @@ -72,11 +72,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public virtual IJoystick[] JoystickCollection { get; set; } - /// - /// Signs whether the disk motor is on or off - /// - //protected bool DiskMotorState; - /// /// +3/2a printer port strobe /// @@ -153,8 +148,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum FrameCompleted = false; - if (UPDDiskDevice == null || !UPDDiskDevice.FDD_IsDiskLoaded) - TapeDevice.StartFrame(); + //if (UPDDiskDevice == null || !UPDDiskDevice.FDD_IsDiskLoaded) + //TapeDevice.StartFrame(); if (_renderSound) { diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs index 00a3be3bef..5951326a93 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs @@ -785,7 +785,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public int GetContentionValue(int tstate) { - //tstate += MemoryContentionOffset; if (tstate >= FrameCycleLength) tstate -= FrameCycleLength; @@ -801,7 +800,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public int GetPortContentionValue(int tstate) { - //tstate += PortContentionOffset; if (tstate >= FrameCycleLength) tstate -= FrameCycleLength; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs index c27f74a265..f681ec3bd0 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs @@ -18,8 +18,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public ZX128Plus3(ZXSpectrum spectrum, Z80A cpu, ZXSpectrum.BorderType borderType, List files, List joysticks) { Spectrum = spectrum; - CPU = cpu; - + CPU = cpu; CPUMon = new CPUMonitor(this); CPUMon.machineType = MachineType.ZXSpectrum128Plus3; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.cs index 1f2508dd63..3291f5c20a 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.cs @@ -22,8 +22,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum CPU = cpu; CPUMon = new CPUMonitor(this); - - //ULADevice = new ULA48(this); ULADevice = new Screen48(this); BuzzerDevice = new Beeper(this); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IMemoryDomains.cs index 16b439ed71..5a645c8d71 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IMemoryDomains.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.IMemoryDomains.cs @@ -92,25 +92,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum SyncByteArrayDomain("RAM - BANK 7 (Shadow Screen)", _machine.RAM7); break; } - /* - SyncByteArrayDomain("ROM0", _machine.ROM0); - SyncByteArrayDomain("ROM1", _machine.ROM1); - SyncByteArrayDomain("ROM2", _machine.ROM2); - SyncByteArrayDomain("ROM3", _machine.ROM3); - SyncByteArrayDomain("RAM0", _machine.RAM0); - SyncByteArrayDomain("RAM1", _machine.RAM1); - SyncByteArrayDomain("RAM2", _machine.RAM2); - SyncByteArrayDomain("RAM3", _machine.RAM3); - SyncByteArrayDomain("RAM4", _machine.RAM4); - SyncByteArrayDomain("RAM5", _machine.RAM5); - SyncByteArrayDomain("RAM6", _machine.RAM6); - SyncByteArrayDomain("RAM7", _machine.RAM7); - */ } private void SyncByteArrayDomain(string name, byte[] data) - { - + { if (_memoryDomainsInit || _byteArrayDomains.ContainsKey(name)) { var m = _byteArrayDomains[name]; @@ -120,8 +105,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { var m = new MemoryDomainByteArray(name, MemoryDomain.Endian.Little, data, true, 1); _byteArrayDomains.Add(name, m); - } - + } } } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.ISettable.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.ISettable.cs index 5d07d4fc07..1e8e491ca6 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.ISettable.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.ISettable.cs @@ -242,6 +242,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum Dictionary Data = new Dictionary(); + /// + /// Detailed info to be displayed within the settings UIs + /// + /// + /// public static ZXMachineMetaData GetMetaObject(MachineType type) { ZXMachineMetaData m = new ZXMachineMetaData(); @@ -345,6 +350,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return m; } + /// + /// Returns machine metadata as a formatted string (to be displayed in a textbox) + /// + /// + /// public static string GetMetaString(MachineType type) { var m = GetMetaObject(type); @@ -410,8 +420,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum sb.Append(builder[i]); sb.Append("\r\n"); } - - //sb.Append("\r\n"); } return sb.ToString(); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs index d5a46ca3b3..21fd979f96 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs @@ -35,7 +35,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum _machine.WriteBus(addr, value); } - + /// + /// Called by MainForm so that the core label can display a more detailed tooltip about the emulated spectrum model + /// + /// public string GetMachineType() { string m = ""; @@ -59,17 +62,31 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum case MachineType.ZXSpectrum128Plus3: m = "(Amstrad) ZX Spectrum 128K +3"; break; + case MachineType.Pentagon128: + m = "(Clone) Pentagon 128K"; + break; } return m; } + /// + /// Called by MainForm - dumps a close approximation of the Spectaculator SZX snapshot format + /// DEV use only - this is nowhere near accurate + /// + /// public byte[] GetSZXSnapshot() { return SZX.ExportSZX(_machine); - //return System.Text.Encoding.Default.GetString(data); } + /// + /// Utility method to get MemberName from an object + /// + /// + /// + /// + /// public static string GetMemberName(Expression> memberAccess) { return ((MemberExpression)memberAccess.Body).Member.Name; From f47c2d15588be661fde2a2b66dd0edbd47027364 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 3 Jan 2019 12:10:53 -0600 Subject: [PATCH 12/15] GBHawk: Start link support --- BizHawk.Client.Common/RomLoader.cs | 19 +- .../BizHawk.Emulation.Cores.csproj | 25 +++ .../Nintendo/GBHawk/GBHawk.IEmulator.cs | 2 +- .../Nintendo/GBHawk/GBHawk.IStatable.cs | 4 +- .../Consoles/Nintendo/GBHawk/GBHawk.cs | 3 +- .../GBHawkLink/GBHawkLink.ICodeDataLog.cs | 186 ++++++++++++++++++ .../GBHawkLink/GBHawkLink.IDebuggable.cs | 77 ++++++++ .../GBHawkLink/GBHawkLink.IEmulator.cs | 128 ++++++++++++ .../GBHawkLink/GBHawkLink.IInputPollable.cs | 24 +++ .../GBHawkLink/GBHawkLink.IMemoryDomains.cs | 129 ++++++++++++ .../GBHawkLink/GBHawkLink.ISaveRam.cs | 34 ++++ .../GBHawkLink/GBHawkLink.ISettable.cs | 91 +++++++++ .../GBHawkLink/GBHawkLink.IStatable.cs | 63 ++++++ .../Nintendo/GBHawkLink/GBHawkLink.cs | 88 +++++++++ .../GBHawkLink/GBHawkLinkControllerDeck.cs | 84 ++++++++ .../GBHawkLink/GBHawkLinkControllers.cs | 94 +++++++++ .../Consoles/Nintendo/GBHawkLink/ReadMe.txt | 1 + 17 files changed, 1044 insertions(+), 8 deletions(-) create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ICodeDataLog.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IDebuggable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IInputPollable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IMemoryDomains.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllers.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/ReadMe.txt diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs index ef007eeac6..3a4b1d69a6 100644 --- a/BizHawk.Client.Common/RomLoader.cs +++ b/BizHawk.Client.Common/RomLoader.cs @@ -14,6 +14,7 @@ using BizHawk.Emulation.Cores.Computers.Commodore64; using BizHawk.Emulation.Cores.Consoles.Sega.gpgx; using BizHawk.Emulation.Cores.Nintendo.Gameboy; using BizHawk.Emulation.Cores.Nintendo.GBHawk; +using BizHawk.Emulation.Cores.Nintendo.GBHawkLink; using BizHawk.Emulation.Cores.Nintendo.SNES; using BizHawk.Emulation.Cores.PCEngine; using BizHawk.Emulation.Cores.Sega.Saturn; @@ -630,7 +631,20 @@ namespace BizHawk.Client.Common var left = Database.GetGameInfo(leftBytes, "left.gb"); var right = Database.GetGameInfo(rightBytes, "right.gb"); - nextEmulator = new GambatteLink( + if (Global.Config.GB_UseGBHawk) + { + nextEmulator = new GBHawkLink( + nextComm, + left, + leftBytes, + right, + rightBytes, + GetCoreSettings(), + GetCoreSyncSettings()); + } + else + { + nextEmulator = new GambatteLink( nextComm, left, leftBytes, @@ -639,7 +653,8 @@ namespace BizHawk.Client.Common GetCoreSettings(), GetCoreSyncSettings(), Deterministic); - + } + // other stuff todo break; case "AppleII": diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index f57d61d6eb..744a7d8c27 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -789,6 +789,31 @@ VBANext.cs + + + + GBHawkLink.cs + + + GBHawkLink.cs + + + GBHawkLink.cs + + + GBHawkLink.cs + + + GBHawkLink.cs + + + GBHawkLink.cs + + + GBHawkLink.cs + + + diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs index be2812ef86..01f04f8338 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs @@ -159,7 +159,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } ticker++; - //if (ticker > 10000000) { vblank_rise = true; }//throw new Exception("ERROR: Unable to Resolve Frame"); } + // if (ticker > 10000000) { vblank_rise = true; }//throw new Exception("ERROR: Unable to Resolve Frame"); } in_vblank_old = in_vblank; REG_FF0F_OLD = REG_FF0F; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs index 161f06c92d..5091c6ceb8 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs @@ -107,9 +107,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync("cart_RAM", ref cart_RAM, false); } - - - ser.EndSection(); + ser.EndSection(); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs index d7c8edcf4f..00e89a039e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs @@ -3,7 +3,6 @@ using BizHawk.Common.BufferExtensions; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.Components.LR35902; -using BizHawk.Common.NumberExtensions; using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy; using System.Runtime.InteropServices; @@ -275,7 +274,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk private readonly GBHawkControllerDeck _controllerDeck; - private void HardReset() + public void HardReset() { GB_bios_register = 0; // bios enable GBC_compat = is_GBC; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ICodeDataLog.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ICodeDataLog.cs new file mode 100644 index 0000000000..cfc841d321 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ICodeDataLog.cs @@ -0,0 +1,186 @@ +using System; +using System.IO; +using System.Collections.Generic; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.Components.LR35902; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : ICodeDataLogger + { + private ICodeDataLog _cdl; + + public void SetCDL(ICodeDataLog cdl) + { + _cdl = cdl; + if (cdl == null) + this.L.cpu.CDLCallback = null; + else this.L.cpu.CDLCallback = CDLCpuCallback; + } + + public void NewCDL(ICodeDataLog cdl) + { + cdl["ROM"] = new byte[MemoryDomains["ROM L"].Size]; + cdl["HRAM"] = new byte[MemoryDomains["Zero Page RAM L"].Size]; + + cdl["WRAM"] = new byte[MemoryDomains["Main RAM L"].Size]; + + if (MemoryDomains.Has("Cart RAM L")) + { + cdl["CartRAM"] = new byte[MemoryDomains["Cart RAM L"].Size]; + } + + cdl.SubType = "GB"; + cdl.SubVer = 0; + } + + [FeatureNotImplemented] + void ICodeDataLogger.DisassembleCDL(Stream s, ICodeDataLog cdl) + { + } + + public void SetCDL(LR35902.eCDLogMemFlags flags, string type, int cdladdr) + { + if (type == null) return; + byte val = (byte)flags; + _cdl[type][cdladdr] |= (byte)flags; + } + + void CDLCpuCallback(ushort addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x8000) + { + //don't record writes to the ROM, it's just noisy + //NOTE: in principle a mapper could mount a useful resource here, but I doubt it) + if ((flags & LR35902.eCDLogMemFlags.Write) != 0) return; + } + + if (L.ppu.DMA_start) + { + // some of gekkio's tests require these to be accessible during DMA + if (addr < 0x8000) + { + if (L.ppu.DMA_addr < 0x80) + { + return; + } + else + { + L.mapper.MapCDL(addr, flags); + return; + } + } + else if ((addr >= 0xE000) && (addr < 0xF000)) + { + SetCDL(flags, "WRAM", addr - 0xE000); + } + else if ((addr >= 0xF000) && (addr < 0xFE00)) + { + SetCDL(flags, "WRAM", (L.RAM_Bank * 0x1000) + (addr - 0xF000)); + } + else if ((addr >= 0xFE00) && (addr < 0xFEA0) && L.ppu.DMA_OAM_access) + { + return; + } + else if ((addr >= 0xFF00) && (addr < 0xFF80)) // The game GOAL! Requires Hardware Regs to be accessible + { + return; + } + else if ((addr >= 0xFF80)) + { + SetCDL(flags, "HRAM", addr - 0xFF80); + } + + } + + if (addr < 0x900) + { + if (addr < 0x100) + { + // return Either BIOS ROM or Game ROM + if ((L.GB_bios_register & 0x1) == 0) + { + return; + } + else + { + L.mapper.MapCDL(addr, flags); + return; + } + } + else if (addr >= 0x200) + { + // return Either BIOS ROM or Game ROM + if (((L.GB_bios_register & 0x1) == 0) && L.is_GBC) + { + return; + } + else + { + L.mapper.MapCDL(addr, flags); + return; + } + } + else + { + L.mapper.MapCDL(addr, flags); + return; + } + } + else if (addr < 0x8000) + { + L.mapper.MapCDL(addr, flags); + return; + } + else if (addr < 0xA000) + { + return; + } + else if (addr < 0xC000) + { + L.mapper.MapCDL(addr, flags); + return; + } + else if (addr < 0xD000) + { + return; + } + else if (addr < 0xE000) + { + SetCDL(flags, "WRAM", (L.RAM_Bank * 0x1000) + (addr - 0xD000)); + } + else if (addr < 0xF000) + { + SetCDL(flags, "WRAM", addr - 0xE000); + } + else if (addr < 0xFE00) + { + SetCDL(flags, "WRAM", (L.RAM_Bank * 0x1000) + (addr - 0xF000)); + } + else if (addr < 0xFEA0) + { + return; + } + else if (addr < 0xFF00) + { + return; + } + else if (addr < 0xFF80) + { + return; + } + else if (addr < 0xFFFF) + { + SetCDL(flags, "HRAM", addr - 0xFF80); + } + else + { + return; + } + + } + + + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IDebuggable.cs new file mode 100644 index 0000000000..e9b191d02a --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IDebuggable.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : IDebuggable + { + public IDictionary GetCpuFlagsAndRegisters() + { + return new Dictionary + { + /* + ["A"] = cpu.A, + ["X"] = cpu.X, + ["Y"] = cpu.Y, + ["S"] = cpu.S, + ["PC"] = cpu.PC, + ["Flag C"] = cpu.FlagC, + ["Flag Z"] = cpu.FlagZ, + ["Flag I"] = cpu.FlagI, + ["Flag D"] = cpu.FlagD, + ["Flag B"] = cpu.FlagB, + ["Flag V"] = cpu.FlagV, + ["Flag N"] = cpu.FlagN, + ["Flag T"] = cpu.FlagT + */ + }; + } + + public void SetCpuRegister(string register, int value) + { + switch (register) + { + default: + throw new InvalidOperationException(); + case "A": + //cpu.A = (byte)value; + break; + case "X": + //cpu.X = (byte)value; + break; + case "Y": + //cpu.Y = (byte)value; + break; + case "S": + //cpu.S = (byte)value; + break; + case "PC": + //cpu.PC = (ushort)value; + break; + case "Flag I": + //cpu.FlagI = value > 0; + break; + } + } + + public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" }); + + public bool CanStep(StepType type) + { + return false; + } + + [FeatureNotImplemented] + public void Step(StepType type) + { + throw new NotImplementedException(); + } + + public long TotalExecutedCycles + { + get { return (long)L.cpu.TotalExecutedCycles; } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs new file mode 100644 index 0000000000..790ab1fa06 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs @@ -0,0 +1,128 @@ +using BizHawk.Common.NumberExtensions; +using BizHawk.Emulation.Common; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : IEmulator, IVideoProvider + { + public IEmulatorServiceProvider ServiceProvider { get; } + + public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; + + public byte controller_state; + public bool in_vblank_old; + public bool in_vblank; + public bool vblank_rise; + + public void FrameAdvance(IController controller, bool render, bool rendersound) + { + //Console.WriteLine("-----------------------FRAME-----------------------"); + if (_tracer.Enabled) + { + L.cpu.TraceCallback = s => _tracer.Put(s); + } + else + { + L.cpu.TraceCallback = null; + } + + _frame++; + + if (controller.IsPressed("Power")) + { + HardReset(); + } + + _islag = true; + + GetControllerState(controller); + + do_frame(); + + _islag = L._islag; + + if (_islag) + { + _lagcount++; + } + } + + public void do_frame() + { + L.do_frame(); + R.do_frame(); + } + + public void GetControllerState(IController controller) + { + InputCallbacks.Call(); + L.controller_state = _controllerDeck.ReadPort1(controller); + R.controller_state = _controllerDeck.ReadPort2(controller); + } + + public int Frame => _frame; + + public string SystemId => "GB"; + + public bool DeterministicEmulation { get; set; } + + public void ResetCounters() + { + _frame = 0; + _lagcount = 0; + _islag = false; + } + + public CoreComm CoreComm { get; } + + public void Dispose() + { + L.Dispose(); + R.Dispose(); + } + + #region Video provider + + public int _frameHz = 60; + + public int[] _vidbuffer = new int[160 * 2 * 144]; + public int[] buff_L; + public int[] buff_R; + + public int[] GetVideoBuffer() + { + // combine the 2 video buffers from the instances + buff_L = L.GetVideoBuffer(); + buff_R = R.GetVideoBuffer(); + + for (int i = 0; i < 144; i++) + { + for (int j = 0; j < 160; j++) + { + _vidbuffer[i * 320 + j] = buff_L[i * 160 + j]; + _vidbuffer[i * 320 + j + 160] = buff_R[i * 160 + j]; + } + } + + return _vidbuffer; + } + + public int VirtualWidth => 160 * 2; + public int VirtualHeight => 144; + public int BufferWidth => 160 * 2; + public int BufferHeight => 144; + public int BackgroundColor => unchecked((int)0xFF000000); + public int VsyncNumerator => _frameHz; + public int VsyncDenominator => 1; + + public static readonly uint[] color_palette_BW = { 0xFFFFFFFF , 0xFFAAAAAA, 0xFF555555, 0xFF000000 }; + public static readonly uint[] color_palette_Gr = { 0xFFA4C505, 0xFF88A905, 0xFF1D551D, 0xFF052505 }; + + public uint[] color_palette = new uint[4]; + + #endregion + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IInputPollable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IInputPollable.cs new file mode 100644 index 0000000000..021a1ac3a0 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IInputPollable.cs @@ -0,0 +1,24 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : IInputPollable + { + public int LagCount + { + get { return _lagcount; } + set { _lagcount = value; } + } + + public bool IsLagFrame + { + get { return _islag; } + set { _islag = value; } + } + + public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem(); + + public bool _islag = true; + private int _lagcount; + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IMemoryDomains.cs new file mode 100644 index 0000000000..d28fdaba55 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IMemoryDomains.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink + { + private IMemoryDomains MemoryDomains; + + public void SetupMemoryDomains() + { + var domains = new List + { + new MemoryDomainDelegate( + "Main RAM L", + L.RAM.Length, + MemoryDomain.Endian.Little, + addr => L.RAM[addr], + (addr, value) => L.RAM[addr] = value, + 1), + new MemoryDomainDelegate( + "Main RAM R", + R.RAM.Length, + MemoryDomain.Endian.Little, + addr => R.RAM[addr], + (addr, value) => R.RAM[addr] = value, + 1), + new MemoryDomainDelegate( + "Zero Page RAM L", + L.ZP_RAM.Length, + MemoryDomain.Endian.Little, + addr => L.ZP_RAM[addr], + (addr, value) => L.ZP_RAM[addr] = value, + 1), + new MemoryDomainDelegate( + "Zero Page RAM R", + R.ZP_RAM.Length, + MemoryDomain.Endian.Little, + addr => R.ZP_RAM[addr], + (addr, value) => R.ZP_RAM[addr] = value, + 1), + new MemoryDomainDelegate( + "System Bus L", + 0X10000, + MemoryDomain.Endian.Little, + addr => PeekSystemBusL(addr), + (addr, value) => PokeSystemBusL(addr, value), + 1), + new MemoryDomainDelegate( + "System Bus R", + 0X10000, + MemoryDomain.Endian.Little, + addr => PeekSystemBusR(addr), + (addr, value) => PokeSystemBusR(addr, value), + 1), + new MemoryDomainDelegate( + "ROM L", + L._rom.Length, + MemoryDomain.Endian.Little, + addr => L._rom[addr], + (addr, value) => L._rom[addr] = value, + 1), + new MemoryDomainDelegate( + "ROM R", + R._rom.Length, + MemoryDomain.Endian.Little, + addr => R._rom[addr], + (addr, value) => R._rom[addr] = value, + 1), + new MemoryDomainDelegate( + "VRAM L", + L.VRAM.Length, + MemoryDomain.Endian.Little, + addr => L.VRAM[addr], + (addr, value) => L.VRAM[addr] = value, + 1), + new MemoryDomainDelegate( + "VRAM R", + R.VRAM.Length, + MemoryDomain.Endian.Little, + addr => R.VRAM[addr], + (addr, value) => R.VRAM[addr] = value, + 1) + }; + + if (L.cart_RAM != null) + { + var CartRamL = new MemoryDomainByteArray("Cart RAM L", MemoryDomain.Endian.Little, L.cart_RAM, true, 1); + domains.Add(CartRamL); + } + + if (R.cart_RAM != null) + { + var CartRamR = new MemoryDomainByteArray("Cart RAM R", MemoryDomain.Endian.Little, R.cart_RAM, true, 1); + domains.Add(CartRamR); + } + + MemoryDomains = new MemoryDomainList(domains); + (ServiceProvider as BasicServiceProvider).Register(MemoryDomains); + } + + private byte PeekSystemBusL(long addr) + { + ushort addr2 = (ushort)(addr & 0xFFFF); + return L.PeekMemory(addr2); + } + + private byte PeekSystemBusR(long addr) + { + ushort addr2 = (ushort)(addr & 0xFFFF); + return R.PeekMemory(addr2); + } + + private void PokeSystemBusL(long addr, byte value) + { + ushort addr2 = (ushort)(addr & 0xFFFF); + L.WriteMemory(addr2, value); + } + + private void PokeSystemBusR(long addr, byte value) + { + ushort addr2 = (ushort)(addr & 0xFFFF); + R.WriteMemory(addr2, value); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs new file mode 100644 index 0000000000..e8a6a9d0b5 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs @@ -0,0 +1,34 @@ +using System; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : ISaveRam + { + public byte[] CloneSaveRam() + { + if (L.cart_RAM != null) + { + return (byte[])L.cart_RAM.Clone(); + } + else + { + return null; + } + } + + public void StoreSaveRam(byte[] data) + { + Buffer.BlockCopy(data, 0, L.cart_RAM, 0, data.Length); + Console.WriteLine("loading SRAM here"); + } + + public bool SaveRamModified + { + get + { + return L.has_bat & _syncSettings.L.Use_SRAM; + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs new file mode 100644 index 0000000000..dd2711ded1 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs @@ -0,0 +1,91 @@ +using System; +using System.ComponentModel; + +using Newtonsoft.Json; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Nintendo.GBHawk; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : IEmulator, IStatable, ISettable + { + public GBLinkSettings GetSettings() + { + return new GBLinkSettings + ( + L.GetSettings(), + R.GetSettings() + ); + } + + public GBLinkSyncSettings GetSyncSettings() + { + return new GBLinkSyncSettings + ( + L.GetSyncSettings(), + R.GetSyncSettings() + ); + } + + public bool PutSettings(GBLinkSettings o) + { + return L.PutSettings(o.L) || R.PutSettings(o.R); + } + + public bool PutSyncSettings(GBLinkSyncSettings o) + { + return L.PutSyncSettings(o.L) || R.PutSyncSettings(o.R); + } + + private GBLinkSettings _settings = new GBLinkSettings(); + public GBLinkSyncSettings _syncSettings = new GBLinkSyncSettings(); + + public class GBLinkSettings + { + public GBHawk.GBHawk.GBSettings L; + public GBHawk.GBHawk.GBSettings R; + + public GBLinkSettings() + { + L = new GBHawk.GBHawk.GBSettings(); + R = new GBHawk.GBHawk.GBSettings(); + } + + public GBLinkSettings(GBHawk.GBHawk.GBSettings L, GBHawk.GBHawk.GBSettings R) + { + this.L = L; + this.R = R; + } + + public GBLinkSettings Clone() + { + return new GBLinkSettings(L.Clone(), R.Clone()); + } + } + + public class GBLinkSyncSettings + { + public GBHawk.GBHawk.GBSyncSettings L; + public GBHawk.GBHawk.GBSyncSettings R; + + public GBLinkSyncSettings() + { + L = new GBHawk.GBHawk.GBSyncSettings(); + R = new GBHawk.GBHawk.GBSyncSettings(); + } + + public GBLinkSyncSettings(GBHawk.GBHawk.GBSyncSettings L, GBHawk.GBHawk.GBSyncSettings R) + { + this.L = L; + this.R = R; + } + + public GBLinkSyncSettings Clone() + { + return new GBLinkSyncSettings(L.Clone(), R.Clone()); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs new file mode 100644 index 0000000000..e078e962a9 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs @@ -0,0 +1,63 @@ +using System.IO; +using Newtonsoft.Json; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Nintendo.GBHawk; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public partial class GBHawkLink : IStatable + { + public bool BinarySaveStatesPreferred => true; + + public void SaveStateText(TextWriter writer) + { + L.SaveStateText(writer); + R.SaveStateText(writer); + SyncState(new Serializer(writer)); + } + + public void LoadStateText(TextReader reader) + { + L.LoadStateText(reader); + R.LoadStateText(reader); + SyncState(new Serializer(reader)); + } + + public void SaveStateBinary(BinaryWriter bw) + { + L.SaveStateBinary(bw); + R.SaveStateBinary(bw); + // other variables + SyncState(new Serializer(bw)); + } + + public void LoadStateBinary(BinaryReader br) + { + L.LoadStateBinary(br); + R.LoadStateBinary(br); + // other variables + SyncState(new Serializer(br)); + } + + public byte[] SaveStateBinary() + { + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + return ms.ToArray(); + } + + //private JsonSerializer ser = new JsonSerializer { Formatting = Formatting.Indented }; + + private void SyncState(Serializer ser) + { + ser.Sync("Lag", ref _lagcount); + ser.Sync("Frame", ref _frame); + ser.Sync("IsLag", ref _islag); + _controllerDeck.SyncState(ser); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs new file mode 100644 index 0000000000..c4f2ffacda --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs @@ -0,0 +1,88 @@ +using System; + +using BizHawk.Common.BufferExtensions; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.Components.LR35902; + +using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy; +using BizHawk.Emulation.Cores.Nintendo.GBHawk; +using System.Runtime.InteropServices; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + [Core( + "GBHawkLink", + "", + isPorted: false, + isReleased: true)] + [ServiceNotApplicable(typeof(IDriveLight))] + public partial class GBHawkLink : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, ILinkable, + ISettable + { + // we want to create two GBHawk instances that we will run concurrently + // maybe up to 4 eventually? + public GBHawk.GBHawk L; + public GBHawk.GBHawk R; + + //[CoreConstructor("GB", "GBC")] + public GBHawkLink(CoreComm comm, GameInfo game_L, byte[] rom_L, GameInfo game_R, byte[] rom_R, /*string gameDbFn,*/ object settings, object syncSettings) + { + var ser = new BasicServiceProvider(this); + + GBLinkSettings linkSettings = (GBLinkSettings)settings ?? new GBLinkSettings(); + GBLinkSyncSettings linkSyncSettings = (GBLinkSyncSettings)syncSettings ?? new GBLinkSyncSettings(); + _controllerDeck = new GBHawkLinkControllerDeck(GBHawkControllerDeck.DefaultControllerName, GBHawkControllerDeck.DefaultControllerName); + + CoreComm = comm; + + L = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, + game_L, rom_L, linkSettings.L, linkSyncSettings.L); + + R = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, + game_R, rom_R, linkSettings.R, linkSyncSettings.R); + + ser.Register(this); + ser.Register(L.audio); + + _tracer = new TraceBuffer { Header = L.cpu.TraceHeader }; + ser.Register(_tracer); + + ServiceProvider = ser; + + SetupMemoryDomains(); + + HardReset(); + + L.color_palette[0] = color_palette_BW[0]; + L.color_palette[1] = color_palette_BW[1]; + L.color_palette[2] = color_palette_BW[2]; + L.color_palette[3] = color_palette_BW[3]; + + R.color_palette[0] = color_palette_BW[0]; + R.color_palette[1] = color_palette_BW[1]; + R.color_palette[2] = color_palette_BW[2]; + R.color_palette[3] = color_palette_BW[3]; + } + + public void HardReset() + { + L.HardReset(); + R.HardReset(); + } + + public DisplayType Region => DisplayType.NTSC; + + public int _frame = 0; + + private readonly GBHawkLinkControllerDeck _controllerDeck; + + private readonly ITraceable _tracer; + + bool ILinkable.LinkConnected { get; } + + private void ExecFetch(ushort addr) + { + MemoryCallbacks.CallExecutes(addr, "System Bus"); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs new file mode 100644 index 0000000000..fd2e5c7ae8 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Common; +using BizHawk.Common.ReflectionExtensions; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + public class GBHawkLinkControllerDeck + { + public GBHawkLinkControllerDeck(string controller1Name, string controller2Name) + { + if (!ValidControllerTypes.ContainsKey(controller1Name)) + { + throw new InvalidOperationException("Invalid controller type: " + controller1Name); + } + + if (!ValidControllerTypes.ContainsKey(controller2Name)) + { + throw new InvalidOperationException("Invalid controller type: " + controller2Name); + } + + Port1 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller1Name], 1); + Port2 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller2Name], 2); + + Definition = new ControllerDefinition + { + Name = Port1.Definition.Name, + BoolButtons = Port1.Definition.BoolButtons + .Concat(Port2.Definition.BoolButtons) + .ToList() + }; + } + + public byte ReadPort1(IController c) + { + return Port1.Read(c); + } + + public byte ReadPort2(IController c) + { + return Port2.Read(c); + } + + public ControllerDefinition Definition { get; } + + public void SyncState(Serializer ser) + { + ser.BeginSection("Port1"); + Port1.SyncState(ser); + ser.EndSection(); + + ser.BeginSection("Port2"); + Port2.SyncState(ser); + ser.EndSection(); + } + + private readonly IPort Port1; + private readonly IPort Port2; + + private static Dictionary _controllerTypes; + + public static Dictionary ValidControllerTypes + { + get + { + if (_controllerTypes == null) + { + _controllerTypes = typeof(GBHawkLinkControllerDeck).Assembly + .GetTypes() + .Where(t => typeof(IPort).IsAssignableFrom(t)) + .Where(t => !t.IsAbstract && !t.IsInterface) + .ToDictionary(tkey => tkey.DisplayName()); + } + + return _controllerTypes; + } + } + + public static string DefaultControllerName => typeof(StandardControls).DisplayName(); + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllers.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllers.cs new file mode 100644 index 0000000000..b1617ce740 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllers.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +using BizHawk.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink +{ + /// + /// Represents a GB add on + /// + public interface IPort + { + byte Read(IController c); + + ControllerDefinition Definition { get; } + + void SyncState(Serializer ser); + + int PortNum { get; } + } + + [DisplayName("Gameboy Controller")] + public class StandardControls : IPort + { + public StandardControls(int portNum) + { + PortNum = portNum; + Definition = new ControllerDefinition + { + Name = "Gameboy Controller H", + BoolButtons = BaseDefinition + .Select(b => "P" + PortNum + " " + b) + .ToList() + }; + } + + public int PortNum { get; } + + public ControllerDefinition Definition { get; } + + public byte Read(IController c) + { + byte result = 0xFF; + + if (c.IsPressed(Definition.BoolButtons[0])) + { + result -= 4; + } + if (c.IsPressed(Definition.BoolButtons[1])) + { + result -= 8; + } + if (c.IsPressed(Definition.BoolButtons[2])) + { + result -= 2; + } + if (c.IsPressed(Definition.BoolButtons[3])) + { + result -= 1; + } + if (c.IsPressed(Definition.BoolButtons[4])) + { + result -= 128; + } + if (c.IsPressed(Definition.BoolButtons[5])) + { + result -= 64; + } + if (c.IsPressed(Definition.BoolButtons[6])) + { + result -= 32; + } + if (c.IsPressed(Definition.BoolButtons[7])) + { + result -= 16; + } + + return result; + } + + private static readonly string[] BaseDefinition = + { + "Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power" + }; + + public void SyncState(Serializer ser) + { + //nothing + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/ReadMe.txt b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/ReadMe.txt new file mode 100644 index 0000000000..bc60bf4b01 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/ReadMe.txt @@ -0,0 +1 @@ +TODO: From 42764f0019990c93d3eb61719c97f03ecfb68a71 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 4 Jan 2019 08:50:55 +1000 Subject: [PATCH 13/15] Add preliminary Unix compatibility (using Mono; resolves #1384) (#1380) * Move PlatformSpecificLinkedLibs and implementations to common and rename * Specify file ext. at LoadPlatformSpecific call site * Move Client.Common.Global.RunningOnUnix to PlatformLinkedLibSingleton * Inline var Resolver * Use PlatformLinkedLibManager internally * Move plugin load check to LinkedLibManager, use LinkedLibManager * Interpolate * Return exit code from dlclose/FreeLibrary * Skip all calls to externs in BlipBufDll when using mono * Use PlatformLinkedLibManager in SevenZipLibraryManager * Add expected return value to workaround (from testing on Win32) * Remove ".dll" from DllImport attr, remove temporary workaround, see desc. The library can be built by changing the output file name in `.../blip_buf/Makefile` to `libblip_buf.so`, and running `make`. It will be loaded if placed in the `.../output` folder. * Remove unused code, add TODO (this class is req. for Waterbox.PeWrapper) The TODO is to [rewrite with C#](https://docs.microsoft.com/en-us/dotnet/standard/io/memory-mapped-files) instead of importing from `kernel32.dll`. * Update OpenTK again but better (for #1384) * Add Mono run script * Add libblip_buf.so (temporary) Temporary because it should be a separate package which BizHawk depends on. * Add distro detection, add "already running" and "unknown distro" messages * Gray-out Lua Console on Unix * Extract superclass from EmuLuaLibrary, add shell implementation for Unix * Specify libdl version, Fedora doesn't have the versionless symlink * Remove empty `ToolStripMenuItem`, null `Text` caused crash on Unix * Transform OpenTK keyboard input into a `List` and read that Also fixes crash on rebind * Remove debug `using ...;` --- Assets/EmuHawkMono.sh | 18 ++++ Assets/libblip_buf.so | Bin 0 -> 16840 bytes BizHawk.Client.Common/7z/LibraryManager.cs | 18 ++-- BizHawk.Client.Common/7z/NativeMethods.cs | 12 +-- BizHawk.Client.Common/Global.cs | 2 - .../BizHawk.Client.EmuHawk.csproj | 2 + BizHawk.Client.EmuHawk/Input/Input.cs | 37 +++---- BizHawk.Client.EmuHawk/Input/OTK_Keyboard.cs | 38 +++++++- BizHawk.Client.EmuHawk/MainForm.Events.cs | 1 + BizHawk.Client.EmuHawk/MainForm.cs | 4 - BizHawk.Client.EmuHawk/Program.cs | 80 +++------------ BizHawk.Client.EmuHawk/ScreenSaver.cs | 3 +- BizHawk.Client.EmuHawk/Sound/Sound.cs | 3 +- BizHawk.Client.EmuHawk/Throttle.cs | 3 +- BizHawk.Client.EmuHawk/config/InputWidget.cs | 6 +- .../tools/Lua/Libraries/EmuLuaLibrary.cs | 56 ++++++----- .../Lua/Libraries/NotReallyLuaLibrary.cs | 60 ++++++++++++ .../Lua/Libraries/PlatformEmuLuaLibrary.cs | 45 +++++++++ .../tools/Lua/LuaConsole.cs | 47 ++++----- .../tools/Lua/LuaRegisteredFunctionsList.cs | 14 +-- BizHawk.Client.EmuHawk/tools/ToolManager.cs | 8 +- .../tools/TraceLogger.Designer.cs | 8 -- BizHawk.Common/BizHawk.Common.csproj | 1 + .../BizInvoke/DynamicLibraryImportResolver.cs | 56 ++--------- BizHawk.Common/BizInvoke/MemoryBlock.cs | 29 +----- BizHawk.Common/PlatformLinkedLibSingleton.cs | 86 +++++++++++++++++ .../Sound/Utilities/BlipBuffer.cs | 24 ++--- .../N64/NativeApi/mupen64plusCoreApi.cs | 91 ++++++++---------- .../Consoles/Nintendo/QuickNES/QuickNES.cs | 4 +- References/OpenTK.GLControl.dll | Bin 28672 -> 45056 bytes References/OpenTK.dll | Bin 5525504 -> 5525504 bytes References/OpenTK.dll.config | 41 +++++--- 32 files changed, 455 insertions(+), 342 deletions(-) create mode 100755 Assets/EmuHawkMono.sh create mode 100755 Assets/libblip_buf.so create mode 100644 BizHawk.Client.EmuHawk/tools/Lua/Libraries/NotReallyLuaLibrary.cs create mode 100644 BizHawk.Client.EmuHawk/tools/Lua/Libraries/PlatformEmuLuaLibrary.cs create mode 100644 BizHawk.Common/PlatformLinkedLibSingleton.cs diff --git a/Assets/EmuHawkMono.sh b/Assets/EmuHawkMono.sh new file mode 100755 index 0000000000..45298de879 --- /dev/null +++ b/Assets/EmuHawkMono.sh @@ -0,0 +1,18 @@ +#!/bin/sh +cd "$(dirname "$0")" +if [ "$(ps -C "mono" -o "cmd" --no-headers | grep "EmuHawk.exe")" ]; then + echo "EmuHawk is already running, exiting..." + exit 0 +fi +libpath="" +if [ "$(command -v lsb_release)" ]; then + case "$(lsb_release -i | cut -c17- | tr -d "\n")" in + "Arch"|"ManjaroLinux") libpath="/usr/lib/wine";; + "Ubuntu"|"LinuxMint") libpath="/usr/lib/x86_64-linux-gnu/wine";; + esac +fi +if [ -z "$libpath" ]; then + printf "%s\n" "Unknown distro, assuming WINE library location is /usr/lib/wine..." + libpath="/usr/lib/wine" +fi +LD_LIBRARY_PATH="$libpath" mono ./EmuHawk.exe diff --git a/Assets/libblip_buf.so b/Assets/libblip_buf.so new file mode 100755 index 0000000000000000000000000000000000000000..9c060d4189a81d6404d0cfaa8cddccffd5375194 GIT binary patch literal 16840 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 y?D@g(Thrm. */ +using BizHawk.Common; + using System; using System.Collections.Generic; #if !WINCE && !MONO @@ -87,6 +89,8 @@ namespace SevenZip // private static string _LibraryVersion; private static bool? _modifyCapabale; + private static readonly PlatformLinkedLibSingleton.PlatformLinkedLibManager libLoader = PlatformLinkedLibSingleton.LinkedLibManager; + private static void InitUserInFormat(object user, InArchiveFormat format) { if (!_inArchives.ContainsKey(user)) @@ -148,16 +152,16 @@ namespace SevenZip //{ // throw new SevenZipLibraryException("DLL file does not exist."); //} - if ((_modulePtr = NativeMethods.LoadLibrary(_libraryFileName)) == IntPtr.Zero) + if ((_modulePtr = libLoader.LoadPlatformSpecific(_libraryFileName)) == IntPtr.Zero) { //try a different directory string alternateFilename = Path.Combine(Path.Combine(Path.GetDirectoryName(_libraryFileName),"dll"),"7z.dll"); - if ((_modulePtr = NativeMethods.LoadLibrary(alternateFilename)) == IntPtr.Zero) + if ((_modulePtr = libLoader.LoadPlatformSpecific(alternateFilename)) == IntPtr.Zero) throw new SevenZipLibraryException("failed to load library."); } - if (NativeMethods.GetProcAddress(_modulePtr, "GetHandlerProperty") == IntPtr.Zero) + if (libLoader.GetProcAddr(_modulePtr, "GetHandlerProperty") == IntPtr.Zero) { - NativeMethods.FreeLibrary(_modulePtr); + libLoader.FreePlatformSpecific(_modulePtr); throw new SevenZipLibraryException("library is invalid."); } } @@ -431,7 +435,7 @@ namespace SevenZip if (_totalUsers == 0) { #if !WINCE && !MONO - NativeMethods.FreeLibrary(_modulePtr); + libLoader.FreePlatformSpecific(_modulePtr); #endif _modulePtr = IntPtr.Zero; @@ -466,7 +470,7 @@ namespace SevenZip } var createObject = (NativeMethods.CreateObjectDelegate) Marshal.GetDelegateForFunctionPointer( - NativeMethods.GetProcAddress(_modulePtr, "CreateObject"), + libLoader.GetProcAddr(_modulePtr, "CreateObject"), typeof(NativeMethods.CreateObjectDelegate)); if (createObject == null) { @@ -525,7 +529,7 @@ namespace SevenZip } var createObject = (NativeMethods.CreateObjectDelegate) Marshal.GetDelegateForFunctionPointer( - NativeMethods.GetProcAddress(_modulePtr, "CreateObject"), + libLoader.GetProcAddr(_modulePtr, "CreateObject"), typeof(NativeMethods.CreateObjectDelegate)); if (createObject == null) { diff --git a/BizHawk.Client.Common/7z/NativeMethods.cs b/BizHawk.Client.Common/7z/NativeMethods.cs index 02ef5e7eb4..33fbcd9998 100644 --- a/BizHawk.Client.Common/7z/NativeMethods.cs +++ b/BizHawk.Client.Common/7z/NativeMethods.cs @@ -35,18 +35,8 @@ namespace SevenZip [MarshalAs(UnmanagedType.Interface)] out object outObject); #endregion - - [DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)] - public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string fileName); - - [DllImport("kernel32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool FreeLibrary(IntPtr hModule); - - [DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)] - public static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName); #endif - + #if WINCE [DllImport("7z.dll", EntryPoint="CreateObject")] public static extern int CreateCOMObject( diff --git a/BizHawk.Client.Common/Global.cs b/BizHawk.Client.Common/Global.cs index 3631df9a7b..c233e7a7ec 100644 --- a/BizHawk.Client.Common/Global.cs +++ b/BizHawk.Client.Common/Global.cs @@ -159,7 +159,5 @@ namespace BizHawk.Client.Common } public static Dictionary UserBag = new Dictionary(); - - public static bool RunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX; } } diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 646beb4e11..2587f62945 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -943,6 +943,8 @@ + + Form diff --git a/BizHawk.Client.EmuHawk/Input/Input.cs b/BizHawk.Client.EmuHawk/Input/Input.cs index a812d55017..0727baeffe 100644 --- a/BizHawk.Client.EmuHawk/Input/Input.cs +++ b/BizHawk.Client.EmuHawk/Input/Input.cs @@ -2,11 +2,8 @@ using System.Linq; using System.Collections.Generic; using System.Threading; -#if WINDOWS + using SlimDX.DirectInput; -#else -using OpenTK.Input; -#endif using BizHawk.Common; using BizHawk.Client.Common; @@ -116,19 +113,17 @@ namespace BizHawk.Client.EmuHawk private Input() { -#if WINDOWS UpdateThread = new Thread(UpdateThreadProc) { IsBackground = true, Priority = ThreadPriority.AboveNormal //why not? this thread shouldn't be very heavy duty, and we want it to be responsive }; UpdateThread.Start(); -#endif } public static void Initialize() { - if (Global.RunningOnUnix) + if (PlatformLinkedLibSingleton.RunningOnUnix) { OTK_Keyboard.Initialize(); // OTK_Gamepad.Initialize(); @@ -145,10 +140,11 @@ namespace BizHawk.Client.EmuHawk public static void Cleanup() { -#if WINDOWS - KeyInput.Cleanup(); - GamePad.Cleanup(); -#endif + if (!PlatformLinkedLibSingleton.RunningOnUnix) + { + KeyInput.Cleanup(); + GamePad.Cleanup(); + } } public enum InputEventType @@ -331,14 +327,22 @@ namespace BizHawk.Client.EmuHawk return FloatValuesCopy; } -#if WINDOWS void UpdateThreadProc() { - for (; ; ) + while (true) { - var keyEvents = KeyInput.Update().Concat(IPCKeyInput.Update()); - GamePad.UpdateAll(); - GamePad360.UpdateAll(); + var keyEvents = PlatformLinkedLibSingleton.RunningOnUnix + ? OTK_Keyboard.Update() + : KeyInput.Update().Concat(IPCKeyInput.Update()); + if (PlatformLinkedLibSingleton.RunningOnUnix) + { + //TODO + } + else + { + GamePad.UpdateAll(); + GamePad360.UpdateAll(); + } //this block is going to massively modify data structures that the binding method uses, so we have to lock it all lock (this) @@ -441,7 +445,6 @@ namespace BizHawk.Client.EmuHawk Thread.Sleep(10); } } -#endif public void StartListeningForFloatEvents() { diff --git a/BizHawk.Client.EmuHawk/Input/OTK_Keyboard.cs b/BizHawk.Client.EmuHawk/Input/OTK_Keyboard.cs index 2c8faa7cbb..200c970e6b 100644 --- a/BizHawk.Client.EmuHawk/Input/OTK_Keyboard.cs +++ b/BizHawk.Client.EmuHawk/Input/OTK_Keyboard.cs @@ -6,18 +6,47 @@ namespace BizHawk.Client.EmuHawk { public static class OTK_Keyboard { - private static OpenTK.Input.KeyboardState _kbState; + private static readonly Dictionary KeyEnumMap = new Dictionary + { + // A-Z + {Key.A, SlimDX.DirectInput.Key.A}, {Key.B, SlimDX.DirectInput.Key.B}, {Key.C, SlimDX.DirectInput.Key.C}, {Key.D, SlimDX.DirectInput.Key.D}, {Key.E, SlimDX.DirectInput.Key.E}, {Key.F, SlimDX.DirectInput.Key.F}, {Key.G, SlimDX.DirectInput.Key.G}, {Key.H, SlimDX.DirectInput.Key.H}, {Key.I, SlimDX.DirectInput.Key.I}, {Key.J, SlimDX.DirectInput.Key.J}, {Key.K, SlimDX.DirectInput.Key.K}, {Key.L, SlimDX.DirectInput.Key.L}, {Key.M, SlimDX.DirectInput.Key.M}, {Key.N, SlimDX.DirectInput.Key.N}, {Key.O, SlimDX.DirectInput.Key.O}, {Key.P, SlimDX.DirectInput.Key.P}, {Key.Q, SlimDX.DirectInput.Key.Q}, {Key.R, SlimDX.DirectInput.Key.R}, {Key.S, SlimDX.DirectInput.Key.S}, {Key.T, SlimDX.DirectInput.Key.T}, {Key.U, SlimDX.DirectInput.Key.U}, {Key.V, SlimDX.DirectInput.Key.V}, {Key.W, SlimDX.DirectInput.Key.W}, {Key.X, SlimDX.DirectInput.Key.X}, {Key.Y, SlimDX.DirectInput.Key.Y}, {Key.Z, SlimDX.DirectInput.Key.Z}, + // 0-9 + {Key.Number1, SlimDX.DirectInput.Key.D1}, {Key.Number2, SlimDX.DirectInput.Key.D2}, {Key.Number3, SlimDX.DirectInput.Key.D3}, {Key.Number4, SlimDX.DirectInput.Key.D4}, {Key.Number5, SlimDX.DirectInput.Key.D5}, {Key.Number6, SlimDX.DirectInput.Key.D6}, {Key.Number7, SlimDX.DirectInput.Key.D7}, {Key.Number8, SlimDX.DirectInput.Key.D8}, {Key.Number9, SlimDX.DirectInput.Key.D9}, {Key.Number0, SlimDX.DirectInput.Key.D0}, + // misc. printables (ASCII order) + {Key.Space, SlimDX.DirectInput.Key.Space}, {Key.Quote, SlimDX.DirectInput.Key.Apostrophe}, {Key.Comma, SlimDX.DirectInput.Key.Comma}, {Key.Minus, SlimDX.DirectInput.Key.Minus}, {Key.Period, SlimDX.DirectInput.Key.Period}, {Key.Slash, SlimDX.DirectInput.Key.Slash}, {Key.Semicolon, SlimDX.DirectInput.Key.Semicolon}, {Key.Plus, SlimDX.DirectInput.Key.Equals}, {Key.BracketLeft, SlimDX.DirectInput.Key.LeftBracket}, {Key.BackSlash, SlimDX.DirectInput.Key.Backslash}, {Key.BracketRight, SlimDX.DirectInput.Key.RightBracket}, {Key.Tilde, SlimDX.DirectInput.Key.Grave}, + // misc. (alphabetically) + {Key.BackSpace, SlimDX.DirectInput.Key.Backspace}, {Key.CapsLock, SlimDX.DirectInput.Key.CapsLock}, {Key.Delete, SlimDX.DirectInput.Key.Delete}, {Key.Down, SlimDX.DirectInput.Key.DownArrow}, {Key.End, SlimDX.DirectInput.Key.End}, {Key.Enter, SlimDX.DirectInput.Key.Return}, {Key.Escape, SlimDX.DirectInput.Key.Escape}, {Key.Home, SlimDX.DirectInput.Key.Home}, {Key.Insert, SlimDX.DirectInput.Key.Insert}, {Key.Left, SlimDX.DirectInput.Key.LeftArrow}, {Key.PageDown, SlimDX.DirectInput.Key.PageDown}, {Key.PageUp, SlimDX.DirectInput.Key.PageUp}, {Key.Pause, SlimDX.DirectInput.Key.Pause}, {Key.Right, SlimDX.DirectInput.Key.RightArrow}, {Key.ScrollLock, SlimDX.DirectInput.Key.ScrollLock}, {Key.Tab, SlimDX.DirectInput.Key.Tab}, {Key.Up, SlimDX.DirectInput.Key.UpArrow}, + // modifier + {Key.WinLeft, SlimDX.DirectInput.Key.LeftWindowsKey}, {Key.WinRight, SlimDX.DirectInput.Key.RightWindowsKey}, {Key.ControlLeft, SlimDX.DirectInput.Key.LeftControl}, {Key.ControlRight, SlimDX.DirectInput.Key.RightControl}, {Key.AltLeft, SlimDX.DirectInput.Key.LeftAlt}, {Key.AltRight, SlimDX.DirectInput.Key.RightAlt}, {Key.ShiftLeft, SlimDX.DirectInput.Key.LeftShift}, {Key.ShiftRight, SlimDX.DirectInput.Key.RightShift}, + + // function + {Key.F1, SlimDX.DirectInput.Key.F1}, {Key.F2, SlimDX.DirectInput.Key.F2}, {Key.F3, SlimDX.DirectInput.Key.F3}, {Key.F4, SlimDX.DirectInput.Key.F4}, {Key.F5, SlimDX.DirectInput.Key.F5}, {Key.F6, SlimDX.DirectInput.Key.F6}, {Key.F7, SlimDX.DirectInput.Key.F7}, {Key.F8, SlimDX.DirectInput.Key.F8}, {Key.F9, SlimDX.DirectInput.Key.F9}, {Key.F10, SlimDX.DirectInput.Key.F10}, {Key.F11, SlimDX.DirectInput.Key.F11}, {Key.F12, SlimDX.DirectInput.Key.F12}, + // keypad (alphabetically) + {Key.Keypad0, SlimDX.DirectInput.Key.NumberPad0}, {Key.Keypad1, SlimDX.DirectInput.Key.NumberPad1}, {Key.Keypad2, SlimDX.DirectInput.Key.NumberPad2}, {Key.Keypad3, SlimDX.DirectInput.Key.NumberPad3}, {Key.Keypad4, SlimDX.DirectInput.Key.NumberPad4}, {Key.Keypad5, SlimDX.DirectInput.Key.NumberPad5}, {Key.Keypad6, SlimDX.DirectInput.Key.NumberPad6}, {Key.Keypad7, SlimDX.DirectInput.Key.NumberPad7}, {Key.Keypad8, SlimDX.DirectInput.Key.NumberPad8}, {Key.Keypad9, SlimDX.DirectInput.Key.NumberPad9}, {Key.KeypadAdd, SlimDX.DirectInput.Key.NumberPadPlus}, {Key.KeypadDecimal, SlimDX.DirectInput.Key.NumberPadPeriod}, {Key.KeypadDivide, SlimDX.DirectInput.Key.NumberPadSlash}, {Key.KeypadEnter, SlimDX.DirectInput.Key.NumberPadEnter}, {Key.KeypadMultiply, SlimDX.DirectInput.Key.NumberPadStar}, {Key.KeypadSubtract, SlimDX.DirectInput.Key.NumberPadMinus} + }; + + private static readonly List _eventList = new List(); + private static KeyboardState _kbState; public static void Initialize () { - _kbState = OpenTK.Input.Keyboard.GetState(); + _kbState = Keyboard.GetState(); } - public static void Update () + public static IEnumerable Update () { + _eventList.Clear(); + var lastState = _kbState; try { - _kbState = OpenTK.Input.Keyboard.GetState(); + _kbState = Keyboard.GetState(); + foreach (KeyValuePair entry in KeyEnumMap) + { + if (lastState.IsKeyUp(entry.Key) && _kbState.IsKeyDown(entry.Key)) + _eventList.Add(new KeyInput.KeyEvent { Key = entry.Value, Pressed = true }); + else if (lastState.IsKeyDown(entry.Key) && _kbState.IsKeyUp(entry.Key)) + _eventList.Add(new KeyInput.KeyEvent { Key = entry.Value, Pressed = false }); + } } catch { @@ -30,6 +59,7 @@ namespace BizHawk.Client.EmuHawk System.Console.WriteLine("OpenTK Keyboard thread is angry."); } } + return _eventList; } public static bool IsPressed (Key key) diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index e47ce7a138..583898ae0f 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -1386,6 +1386,7 @@ namespace BizHawk.Client.EmuHawk RamSearchMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["RAM Search"].Bindings; HexEditorMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Hex Editor"].Bindings; LuaConsoleMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Lua Console"].Bindings; + LuaConsoleMenuItem.Enabled = GlobalWin.Tools.IsAvailable(); CheatsMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Cheats"].Bindings; TAStudioMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["TAStudio"].Bindings; VirtualPadMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Virtual Pad"].Bindings; diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 5eb4a1d93d..9684d7b21e 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -1118,11 +1118,7 @@ namespace BizHawk.Client.EmuHawk private void OpenLuaConsole() { -#if WINDOWS GlobalWin.Tools.Load(); -#else - MessageBox.Show("Sorry, Lua is not supported on this platform.", "Lua not supported", MessageBoxButtons.OK, MessageBoxIcon.Error); -#endif } public void NotifyLogWindowClosing() diff --git a/BizHawk.Client.EmuHawk/Program.cs b/BizHawk.Client.EmuHawk/Program.cs index 8321603006..cc970daf55 100644 --- a/BizHawk.Client.EmuHawk/Program.cs +++ b/BizHawk.Client.EmuHawk/Program.cs @@ -17,26 +17,25 @@ namespace BizHawk.Client.EmuHawk { static class Program { - static bool RunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX; - static Program() { //this needs to be done before the warnings/errors show up Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - PlatformSpecificLinkedLibs libLoader = RunningOnUnix ? (PlatformSpecificLinkedLibs) new UnixMono() : (PlatformSpecificLinkedLibs) new Win32(); + var libLoader = PlatformLinkedLibSingleton.LinkedLibManager; //http://www.codeproject.com/Articles/310675/AppDomain-AssemblyResolve-Event-Tips //try loading libraries we know we'll need //something in the winforms, etc. code below will cause .net to popup a missing msvcr100.dll in case that one's missing //but oddly it lets us proceed and we'll then catch it here - var d3dx9 = libLoader.LoadPlatformSpecific("d3dx9_43.dll"); - var vc2015 = libLoader.LoadPlatformSpecific("vcruntime140.dll"); - var vc2012 = libLoader.LoadPlatformSpecific("msvcr120.dll"); //TODO - check version? - var vc2010 = libLoader.LoadPlatformSpecific("msvcr100.dll"); //TODO - check version? - var vc2010p = libLoader.LoadPlatformSpecific("msvcp100.dll"); + var libExt = PlatformLinkedLibSingleton.RunningOnUnix ? ".dll.so" : ".dll"; + var d3dx9 = libLoader.LoadPlatformSpecific($"d3dx9_43{libExt}"); + var vc2015 = libLoader.LoadPlatformSpecific($"vcruntime140{libExt}"); + var vc2012 = libLoader.LoadPlatformSpecific($"msvcr120{libExt}"); //TODO - check version? + var vc2010 = libLoader.LoadPlatformSpecific($"msvcr100{libExt}"); //TODO - check version? + var vc2010p = libLoader.LoadPlatformSpecific($"msvcp100{libExt}"); bool fail = false, warn = false; warn |= d3dx9 == IntPtr.Zero; fail |= vc2015 == IntPtr.Zero; @@ -66,7 +65,7 @@ namespace BizHawk.Client.EmuHawk libLoader.FreePlatformSpecific(vc2010); libLoader.FreePlatformSpecific(vc2010p); - if (!RunningOnUnix) + if (!PlatformLinkedLibSingleton.RunningOnUnix) { // this will look in subdirectory "dll" to load pinvoked stuff string dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll"); @@ -90,63 +89,6 @@ namespace BizHawk.Client.EmuHawk return SubMain(args); } - private interface PlatformSpecificLinkedLibs - { - IntPtr LoadPlatformSpecific(string dllToLoad); - IntPtr GetProcAddr(IntPtr hModule, string procName); - void FreePlatformSpecific(IntPtr hModule); - } - private class Win32 : PlatformSpecificLinkedLibs - { - [DllImport("kernel32.dll")] - private static extern IntPtr LoadLibrary(string dllToLoad); - [DllImport("kernel32.dll")] - private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); - [DllImport("kernel32.dll")] - private static extern void FreeLibrary(IntPtr hModule); - public IntPtr LoadPlatformSpecific(string dllToLoad) - { - return LoadLibrary(dllToLoad); - } - public IntPtr GetProcAddr(IntPtr hModule, string procName) - { - return GetProcAddress(hModule, procName); - } - public void FreePlatformSpecific(IntPtr hModule) - { - FreeLibrary(hModule); - } - } - private class UnixMono : PlatformSpecificLinkedLibs - { - // This class is copied from a tutorial, so don't git blame and then email me expecting insight. - const int RTLD_NOW = 2; - [DllImport("libdl.so")] - private static extern IntPtr dlopen(String fileName, int flags); - [DllImport("libdl.so")] - private static extern IntPtr dlerror(); - [DllImport("libdl.so")] - private static extern IntPtr dlsym(IntPtr handle, String symbol); - [DllImport("libdl.so")] - private static extern int dlclose(IntPtr handle); - public IntPtr LoadPlatformSpecific(string dllToLoad) - { - return dlopen(dllToLoad + ".so", RTLD_NOW); - } - public IntPtr GetProcAddr(IntPtr hModule, string procName) - { - dlerror(); - var res = dlsym(hModule, procName); - var errPtr = dlerror(); - if (errPtr != IntPtr.Zero) throw new Exception("dlsym: " + Marshal.PtrToStringAnsi(errPtr)); - return res; - } - public void FreePlatformSpecific(IntPtr hModule) - { - dlclose(hModule); - } - } - private interface PlatformSpecificMainLoopCrashHandler { void TryCatchFinally(string[] args); @@ -258,7 +200,7 @@ namespace BizHawk.Client.EmuHawk } } } - private static PlatformSpecificMainLoopCrashHandler mainLoopCrashHandler = RunningOnUnix + private static PlatformSpecificMainLoopCrashHandler mainLoopCrashHandler = PlatformLinkedLibSingleton.RunningOnUnix ? (PlatformSpecificMainLoopCrashHandler) new UnixMonoMainLoopCrashHandler() : (PlatformSpecificMainLoopCrashHandler) new Win32MainLoopCrashHandler(); @@ -323,7 +265,7 @@ namespace BizHawk.Client.EmuHawk GlobalWin.GLManager = GLManager.Instance; //now create the "GL" context for the display method. we can reuse the IGL_TK context if opengl display method is chosen - if (RunningOnUnix) Global.Config.DispMethod = Config.EDispMethod.GdiPlus; + if (PlatformLinkedLibSingleton.RunningOnUnix) Global.Config.DispMethod = Config.EDispMethod.GdiPlus; REDO_DISPMETHOD: if (Global.Config.DispMethod == Config.EDispMethod.GdiPlus) GlobalWin.GL = new Bizware.BizwareGL.Drivers.GdiPlus.IGL_GdiPlus(); @@ -371,7 +313,7 @@ namespace BizHawk.Client.EmuHawk goto REDO_DISPMETHOD; } - if (!RunningOnUnix) + if (!PlatformLinkedLibSingleton.RunningOnUnix) { //WHY do we have to do this? some intel graphics drivers (ig7icd64.dll 10.18.10.3304 on an unknown chip on win8.1) are calling SetDllDirectory() for the process, which ruins stuff. //The relevant initialization happened just before in "create IGL context". diff --git a/BizHawk.Client.EmuHawk/ScreenSaver.cs b/BizHawk.Client.EmuHawk/ScreenSaver.cs index 70aedf1540..d362b4b2c2 100644 --- a/BizHawk.Client.EmuHawk/ScreenSaver.cs +++ b/BizHawk.Client.EmuHawk/ScreenSaver.cs @@ -2,6 +2,7 @@ using System.Runtime.InteropServices; using BizHawk.Client.Common; +using BizHawk.Common; namespace BizHawk.Client.EmuHawk { @@ -40,7 +41,7 @@ namespace BizHawk.Client.EmuHawk //TODO implement } } - private static PlatformSpecificScreenBlankInterface screenBlankInterface = Global.RunningOnUnix + private static PlatformSpecificScreenBlankInterface screenBlankInterface = PlatformLinkedLibSingleton.RunningOnUnix ? (PlatformSpecificScreenBlankInterface) new MiscUnixScreenBlankInterface() : (PlatformSpecificScreenBlankInterface) new WinScreenBlankInterface(); diff --git a/BizHawk.Client.EmuHawk/Sound/Sound.cs b/BizHawk.Client.EmuHawk/Sound/Sound.cs index 93abdb7f40..1edaaae699 100644 --- a/BizHawk.Client.EmuHawk/Sound/Sound.cs +++ b/BizHawk.Client.EmuHawk/Sound/Sound.cs @@ -4,6 +4,7 @@ using System.Threading; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; using BizHawk.Client.Common; +using BizHawk.Common; namespace BizHawk.Client.EmuHawk { @@ -26,7 +27,7 @@ namespace BizHawk.Client.EmuHawk { if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.OpenAL) _outputDevice = new OpenALSoundOutput(this); - if (!Global.RunningOnUnix) + if (!PlatformLinkedLibSingleton.RunningOnUnix) { if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.DirectSound) _outputDevice = new DirectSoundSoundOutput(this, mainWindowHandle); diff --git a/BizHawk.Client.EmuHawk/Throttle.cs b/BizHawk.Client.EmuHawk/Throttle.cs index 3ae65cdc70..5eb8fcba22 100644 --- a/BizHawk.Client.EmuHawk/Throttle.cs +++ b/BizHawk.Client.EmuHawk/Throttle.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using System.Threading; using BizHawk.Client.Common; +using BizHawk.Common; //this throttle is nitsuja's fine-tuned techniques from desmume @@ -159,7 +160,7 @@ namespace BizHawk.Client.EmuHawk return timeBeginPeriod(ms); } } - static PlatformSpecificSysTimer sysTimer = Global.RunningOnUnix ? (PlatformSpecificSysTimer) new UnixMonoSysTimer() : (PlatformSpecificSysTimer) new WinSysTimer(); + static PlatformSpecificSysTimer sysTimer = PlatformLinkedLibSingleton.RunningOnUnix ? (PlatformSpecificSysTimer) new UnixMonoSysTimer() : (PlatformSpecificSysTimer) new WinSysTimer(); static uint TimeBeginPeriod(uint ms) { return sysTimer.TimeBeginPeriod(ms); diff --git a/BizHawk.Client.EmuHawk/config/InputWidget.cs b/BizHawk.Client.EmuHawk/config/InputWidget.cs index f02130560c..79167ea11f 100644 --- a/BizHawk.Client.EmuHawk/config/InputWidget.cs +++ b/BizHawk.Client.EmuHawk/config/InputWidget.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Runtime.InteropServices; using System.Windows.Forms; +using BizHawk.Common; + namespace BizHawk.Client.EmuHawk { public sealed class InputWidget : TextBox @@ -69,7 +71,7 @@ namespace BizHawk.Client.EmuHawk protected override void OnMouseClick(MouseEventArgs e) { - HideCaret(Handle); + if (!PlatformLinkedLibSingleton.RunningOnUnix) HideCaret(Handle); base.OnMouseClick(e); } @@ -262,7 +264,7 @@ namespace BizHawk.Client.EmuHawk protected override void OnGotFocus(EventArgs e) { - HideCaret(Handle); + if (!PlatformLinkedLibSingleton.RunningOnUnix) HideCaret(Handle); } protected override bool ProcessCmdKey(ref Message msg, Keys keyData) diff --git a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.cs b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.cs index 30b1c40f7c..08efa298d3 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.cs @@ -13,7 +13,7 @@ using BizHawk.Client.Common; namespace BizHawk.Client.EmuHawk { - public class EmuLuaLibrary + public class EmuLuaLibrary : PlatformEmuLuaLibrary { public EmuLuaLibrary() { @@ -82,16 +82,6 @@ namespace BizHawk.Client.EmuHawk } } - public bool IsRebootingCore { get; set; } // pretty hacky.. we dont want a lua script to be able to restart itself by rebooting the core - - private readonly Dictionary Libraries = new Dictionary(); - public LuaFileList ScriptList { get; } = new LuaFileList(); - - public IEnumerable RunningScripts - { - get { return ScriptList.Where(lf => lf.Enabled); } - } - private Lua _lua = new Lua(); private Lua _currThread; @@ -101,9 +91,7 @@ namespace BizHawk.Client.EmuHawk private EmulatorLuaLibrary EmulatorLuaLibrary => (EmulatorLuaLibrary)Libraries[typeof(EmulatorLuaLibrary)]; - public GuiLuaLibrary GuiLibrary => (GuiLuaLibrary)Libraries[typeof(GuiLuaLibrary)]; - - public void Restart(IEmulatorServiceProvider newServiceProvider) + public override void Restart(IEmulatorServiceProvider newServiceProvider) { foreach (var lib in Libraries) { @@ -111,7 +99,7 @@ namespace BizHawk.Client.EmuHawk } } - public void StartLuaDrawing() + public override void StartLuaDrawing() { if (ScriptList.Any() && GuiLibrary.SurfaceIsNull) { @@ -119,7 +107,7 @@ namespace BizHawk.Client.EmuHawk } } - public void EndLuaDrawing() + public override void EndLuaDrawing() { if (ScriptList.Any()) { @@ -127,34 +115,35 @@ namespace BizHawk.Client.EmuHawk } } - public LuaDocumentation Docs { get; } public bool IsRunning { get; set; } - public EventWaitHandle LuaWait { get; private set; } public bool FrameAdvanceRequested { get; private set; } - public LuaFunctionList RegisteredFunctions => EventsLibrary.RegisteredFunctions; + public override LuaFunctionList GetRegisteredFunctions() + { + return EventsLibrary.RegisteredFunctions; + } - public void WindowClosed(IntPtr handle) + public override void WindowClosed(IntPtr handle) { FormsLibrary.WindowClosed(handle); } - public void CallSaveStateEvent(string name) + public override void CallSaveStateEvent(string name) { EventsLibrary.CallSaveStateEvent(name); } - public void CallLoadStateEvent(string name) + public override void CallLoadStateEvent(string name) { EventsLibrary.CallLoadStateEvent(name); } - public void CallFrameBeforeEvent() + public override void CallFrameBeforeEvent() { EventsLibrary.CallFrameBeforeEvent(); } - public void CallFrameAfterEvent() + public override void CallFrameAfterEvent() { EventsLibrary.CallFrameAfterEvent(); } @@ -164,7 +153,12 @@ namespace BizHawk.Client.EmuHawk EventsLibrary.CallExitEvent(thread); } - public void Close() + public override void CallExitEvent(LuaFile lf) + { + CallExitEvent(lf.Thread); + } + + public override void Close() { FormsLibrary.DestroyAll(); _lua.Close(); @@ -187,7 +181,12 @@ namespace BizHawk.Client.EmuHawk return lua; } - public void ExecuteString(string command) + public override void SpawnAndSetFileThread(string pathToLoad, LuaFile lf) + { + lf.Thread = SpawnCoroutine(pathToLoad); + } + + public override void ExecuteString(string command) { _currThread = _lua.NewThread(); _currThread.DoString(command); @@ -232,6 +231,11 @@ namespace BizHawk.Client.EmuHawk } } + public override ResumeResult ResumeScriptFromThreadOf(LuaFile lf) + { + return ResumeScript(lf.Thread); + } + public static void Print(params object[] outputs) { ConsoleLuaLibrary.Log(outputs); diff --git a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/NotReallyLuaLibrary.cs b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/NotReallyLuaLibrary.cs new file mode 100644 index 0000000000..e47b7e750b --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/NotReallyLuaLibrary.cs @@ -0,0 +1,60 @@ +using System; + +using BizHawk.Client.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.EmuHawk +{ + /// + /// Methods intentionally blank. + /// + public sealed class NotReallyLuaLibrary : PlatformEmuLuaLibrary + { + public override void CallExitEvent(LuaFile lf) + { + } + public override void CallFrameAfterEvent() + { + } + public override void CallFrameBeforeEvent() + { + } + public override void CallLoadStateEvent(string name) + { + } + public override void CallSaveStateEvent(string name) + { + } + public override void Close() + { + } + public override void EndLuaDrawing() + { + } + public override void ExecuteString(string command) + { + } + private static readonly LuaFunctionList EmptyLuaFunList = new LuaFunctionList(); + public override LuaFunctionList GetRegisteredFunctions() + { + return EmptyLuaFunList; + } + public override void Restart(IEmulatorServiceProvider newServiceProvider) + { + } + private static readonly EmuLuaLibrary.ResumeResult EmptyResumeResult = new EmuLuaLibrary.ResumeResult(); + public override EmuLuaLibrary.ResumeResult ResumeScriptFromThreadOf(LuaFile lf) + { + return EmptyResumeResult; + } + public override void SpawnAndSetFileThread(string pathToLoad, LuaFile lf) + { + } + public override void StartLuaDrawing() + { + } + public override void WindowClosed(IntPtr handle) + { + } + } +} \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/PlatformEmuLuaLibrary.cs b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/PlatformEmuLuaLibrary.cs new file mode 100644 index 0000000000..93c99a0427 --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/PlatformEmuLuaLibrary.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +using BizHawk.Client.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.EmuHawk +{ + public abstract class PlatformEmuLuaLibrary + { + public LuaDocumentation Docs { get; protected set; } + + public GuiLuaLibrary GuiLibrary => (GuiLuaLibrary) Libraries[typeof(GuiLuaLibrary)]; + + public bool IsRebootingCore { get; set; } // pretty hacky.. we dont want a lua script to be able to restart itself by rebooting the core + + protected readonly Dictionary Libraries = new Dictionary(); + + public EventWaitHandle LuaWait { get; protected set; } + + public IEnumerable RunningScripts + { + get { return ScriptList.Where(lf => lf.Enabled); } + } + + public readonly LuaFileList ScriptList = new LuaFileList(); + + public abstract void CallExitEvent(LuaFile lf); + public abstract void CallFrameAfterEvent(); + public abstract void CallFrameBeforeEvent(); + public abstract void CallLoadStateEvent(string name); + public abstract void CallSaveStateEvent(string name); + public abstract void Close(); + public abstract void EndLuaDrawing(); + public abstract void ExecuteString(string command); + public abstract LuaFunctionList GetRegisteredFunctions(); + public abstract void Restart(IEmulatorServiceProvider newServiceProvider); + public abstract EmuLuaLibrary.ResumeResult ResumeScriptFromThreadOf(LuaFile lf); + public abstract void SpawnAndSetFileThread(string pathToLoad, LuaFile lf); + public abstract void StartLuaDrawing(); + public abstract void WindowClosed(IntPtr handle); + } +} \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs index 881e32d219..c84ad96923 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs @@ -7,10 +7,11 @@ using System.Linq; using System.Text.RegularExpressions; using System.Windows.Forms; -using BizHawk.Emulation.Common; using BizHawk.Client.Common; -using BizHawk.Client.EmuHawk.WinFormExtensions; using BizHawk.Client.EmuHawk.ToolExtensions; +using BizHawk.Client.EmuHawk.WinFormExtensions; +using BizHawk.Common; +using BizHawk.Emulation.Common; namespace BizHawk.Client.EmuHawk { @@ -78,7 +79,7 @@ namespace BizHawk.Client.EmuHawk LuaSandbox.DefaultLogger = ConsoleLog; } - public EmuLuaLibrary LuaImp { get; private set; } + public PlatformEmuLuaLibrary LuaImp { get; private set; } public bool UpdateBefore => true; @@ -154,15 +155,15 @@ namespace BizHawk.Client.EmuHawk foreach (var file in runningScripts) { - LuaImp.CallExitEvent(file.Thread); + LuaImp.CallExitEvent(file); - var functions = LuaImp.RegisteredFunctions + var functions = LuaImp.GetRegisteredFunctions() .Where(lf => lf.Lua == file.Thread) .ToList(); foreach (var function in functions) { - LuaImp.RegisteredFunctions.Remove(function); + LuaImp.GetRegisteredFunctions().Remove(function); } UpdateRegisteredFunctionsDialog(); @@ -172,7 +173,9 @@ namespace BizHawk.Client.EmuHawk } var currentScripts = LuaImp?.ScriptList; // Temp fix for now - LuaImp = new EmuLuaLibrary(Emulator.ServiceProvider); + LuaImp = PlatformLinkedLibSingleton.RunningOnUnix + ? (PlatformEmuLuaLibrary) new NotReallyLuaLibrary() + : (PlatformEmuLuaLibrary) new EmuLuaLibrary(Emulator.ServiceProvider); if (currentScripts != null) { LuaImp.ScriptList.AddRange(currentScripts); @@ -188,7 +191,7 @@ namespace BizHawk.Client.EmuHawk { LuaSandbox.Sandbox(file.Thread, () => { - file.Thread = LuaImp.SpawnCoroutine(pathToLoad); + LuaImp.SpawnAndSetFileThread(pathToLoad, file); LuaSandbox.CreateSandbox(file.Thread, Path.GetDirectoryName(pathToLoad)); file.State = LuaFile.RunState.Running; }, () => @@ -306,7 +309,7 @@ namespace BizHawk.Client.EmuHawk LuaSandbox.Sandbox(null, () => { string pathToLoad = ProcessPath(file.Path); - file.Thread = LuaImp.SpawnCoroutine(file.Path); + LuaImp.SpawnAndSetFileThread(file.Path, file); LuaSandbox.CreateSandbox(file.Thread, Path.GetDirectoryName(pathToLoad)); }, () => { @@ -552,10 +555,10 @@ namespace BizHawk.Client.EmuHawk var prohibit = lf.FrameWaiting && !includeFrameWaiters; if (!prohibit) { - var result = LuaImp.ResumeScript(lf.Thread); + var result = LuaImp.ResumeScriptFromThreadOf(lf); if (result.Terminated) { - LuaImp.CallExitEvent(lf.Thread); + LuaImp.CallExitEvent(lf); lf.Stop(); UpdateDialog(); } @@ -786,7 +789,7 @@ namespace BizHawk.Client.EmuHawk SelectAllMenuItem.Enabled = LuaImp.ScriptList.Any(); StopAllScriptsMenuItem.Enabled = LuaImp.ScriptList.Any(script => script.Enabled); - RegisteredFunctionsMenuItem.Enabled = LuaImp.RegisteredFunctions.Any(); + RegisteredFunctionsMenuItem.Enabled = LuaImp.GetRegisteredFunctions().Any(); } private void NewScriptMenuItem_Click(object sender, EventArgs e) @@ -840,26 +843,26 @@ namespace BizHawk.Client.EmuHawk else if (!file.Enabled && file.Thread != null) { - LuaImp.CallExitEvent(file.Thread); + LuaImp.CallExitEvent(file); var items = SelectedItems.ToList(); foreach (var sitem in items) { var temp = sitem; - var functions = LuaImp.RegisteredFunctions.Where(lf => lf.Lua == temp.Thread).ToList(); + var functions = LuaImp.GetRegisteredFunctions().Where(lf => lf.Lua == temp.Thread).ToList(); foreach (var function in functions) { - LuaImp.RegisteredFunctions.Remove(function); + LuaImp.GetRegisteredFunctions().Remove(function); } UpdateRegisteredFunctionsDialog(); } - LuaImp.CallExitEvent(file.Thread); + LuaImp.CallExitEvent(file); file.Stop(); if (Global.Config.RemoveRegisteredFunctionsOnToggle) { - LuaImp.RegisteredFunctions.ClearAll(); + LuaImp.GetRegisteredFunctions().ClearAll(); } } } @@ -879,7 +882,7 @@ namespace BizHawk.Client.EmuHawk ? item.Path : PathManager.MakeProgramRelativePath(item.Path); - item.Thread = LuaImp.SpawnCoroutine(pathToLoad); + LuaImp.SpawnAndSetFileThread(pathToLoad, item); LuaSandbox.CreateSandbox(item.Thread, Path.GetDirectoryName(pathToLoad)); }, () => { @@ -933,10 +936,10 @@ namespace BizHawk.Client.EmuHawk foreach (var item in items) { var temp = item; - var functions = LuaImp.RegisteredFunctions.Where(x => x.Lua == temp.Thread).ToList(); + var functions = LuaImp.GetRegisteredFunctions().Where(x => x.Lua == temp.Thread).ToList(); foreach (var function in functions) { - LuaImp.RegisteredFunctions.Remove(function); + LuaImp.GetRegisteredFunctions().Remove(function); } LuaImp.ScriptList.Remove(item); @@ -1052,7 +1055,7 @@ namespace BizHawk.Client.EmuHawk private void RegisteredFunctionsMenuItem_Click(object sender, EventArgs e) { - if (LuaImp.RegisteredFunctions.Any()) + if (LuaImp.GetRegisteredFunctions().Any()) { var alreadyOpen = false; foreach (Form form in Application.OpenForms) @@ -1209,7 +1212,7 @@ namespace BizHawk.Client.EmuHawk private void ConsoleContextMenu_Opening(object sender, CancelEventArgs e) { - RegisteredFunctionsContextItem.Enabled = LuaImp.RegisteredFunctions.Any(); + RegisteredFunctionsContextItem.Enabled = LuaImp.GetRegisteredFunctions().Any(); CopyContextItem.Enabled = OutputBox.SelectedText.Any(); ClearConsoleContextItem.Enabled = SelectAllContextItem.Enabled = diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaRegisteredFunctionsList.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaRegisteredFunctionsList.cs index 2a53a725e9..194c940646 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaRegisteredFunctionsList.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaRegisteredFunctionsList.cs @@ -17,7 +17,7 @@ namespace BizHawk.Client.EmuHawk public void UpdateValues() { - if (GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions.Any()) + if (GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions().Any()) { PopulateListView(); } @@ -46,7 +46,7 @@ namespace BizHawk.Client.EmuHawk { FunctionView.Items.Clear(); - var nlfs = GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions.OrderBy(x => x.Event).ThenBy(x => x.Name).ToList(); + var nlfs = GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions().OrderBy(x => x.Event).ThenBy(x => x.Name).ToList(); foreach (var nlf in nlfs) { var item = new ListViewItem { Text = nlf.Event }; @@ -76,7 +76,7 @@ namespace BizHawk.Client.EmuHawk foreach (int index in indices) { var guid = FunctionView.Items[index].SubItems[2].Text; - GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions[guid].Call(); + GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions()[guid].Call(); } } } @@ -89,8 +89,8 @@ namespace BizHawk.Client.EmuHawk foreach (int index in indices) { var guid = FunctionView.Items[index].SubItems[2].Text; - var nlf = GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions[guid]; - GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions.Remove(nlf); + var nlf = GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions()[guid]; + GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions().Remove(nlf); } PopulateListView(); @@ -109,7 +109,7 @@ namespace BizHawk.Client.EmuHawk private void RemoveAllBtn_Click(object sender, EventArgs e) { - GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions.ClearAll(); + GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions().ClearAll(); PopulateListView(); } @@ -118,7 +118,7 @@ namespace BizHawk.Client.EmuHawk var indexes = FunctionView.SelectedIndices; CallButton.Enabled = indexes.Count > 0; RemoveButton.Enabled = indexes.Count > 0; - RemoveAllBtn.Enabled = GlobalWin.Tools.LuaConsole.LuaImp.RegisteredFunctions.Any(); + RemoveAllBtn.Enabled = GlobalWin.Tools.LuaConsole.LuaImp.GetRegisteredFunctions().Any(); } private void FunctionView_KeyDown(object sender, KeyEventArgs e) diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index 05d530176d..e26c0930ef 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -8,9 +8,11 @@ using System.ComponentModel; using System.Windows.Forms; using BizHawk.Client.Common; -using BizHawk.Emulation.Common; -using BizHawk.Common.ReflectionExtensions; +using BizHawk.Client.EmuHawk; using BizHawk.Client.EmuHawk.CoreExtensions; +using BizHawk.Common; +using BizHawk.Common.ReflectionExtensions; +using BizHawk.Emulation.Common; namespace BizHawk.Client.EmuHawk { @@ -730,6 +732,8 @@ namespace BizHawk.Client.EmuHawk return false; } + if (t == typeof(LuaConsole) && PlatformLinkedLibSingleton.RunningOnUnix) return false; + var tool = Assembly .GetExecutingAssembly() .GetTypes() diff --git a/BizHawk.Client.EmuHawk/tools/TraceLogger.Designer.cs b/BizHawk.Client.EmuHawk/tools/TraceLogger.Designer.cs index c129113c37..b9afaa15a2 100644 --- a/BizHawk.Client.EmuHawk/tools/TraceLogger.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TraceLogger.Designer.cs @@ -39,7 +39,6 @@ this.SelectAllContextMenu = new System.Windows.Forms.ToolStripMenuItem(); this.ClearContextMenu = new System.Windows.Forms.ToolStripMenuItem(); this.menuStrip1 = new MenuStripEx(); - this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.FileSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.SaveLogMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); @@ -149,7 +148,6 @@ // this.menuStrip1.ClickThrough = true; this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripMenuItem1, this.FileSubMenu, this.EditSubMenu, this.OptionsSubMenu}); @@ -159,11 +157,6 @@ this.menuStrip1.TabIndex = 2; this.menuStrip1.Text = "menuStrip1"; // - // toolStripMenuItem1 - // - this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - this.toolStripMenuItem1.Size = new System.Drawing.Size(12, 20); - // // FileSubMenu // this.FileSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -371,7 +364,6 @@ private System.Windows.Forms.GroupBox TracerBox; private MenuStripEx menuStrip1; - private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1; private System.Windows.Forms.ToolStripMenuItem FileSubMenu; private System.Windows.Forms.ToolStripMenuItem SaveLogMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; diff --git a/BizHawk.Common/BizHawk.Common.csproj b/BizHawk.Common/BizHawk.Common.csproj index 8b9b8cac99..bc85c00225 100644 --- a/BizHawk.Common/BizHawk.Common.csproj +++ b/BizHawk.Common/BizHawk.Common.csproj @@ -84,6 +84,7 @@ + diff --git a/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs b/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs index 5749b6b362..842eedb9b5 100644 --- a/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs +++ b/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs @@ -8,41 +8,24 @@ namespace BizHawk.Common.BizInvoke public class DynamicLibraryImportResolver : IImportResolver, IDisposable { private IntPtr _p; + private readonly PlatformLinkedLibSingleton.PlatformLinkedLibManager libLoader = PlatformLinkedLibSingleton.LinkedLibManager; public DynamicLibraryImportResolver(string dllName) { -#if !MONO - _p = Win32.LoadLibrary(dllName); -#else - // TODO: how can we read name remaps out of app.confg ? - _p = Libdl.dlopen(dllName, Libdl.RTLD_NOW); -#endif - if (_p == IntPtr.Zero) - { - throw new InvalidOperationException("LoadLibrary returned NULL"); - } + _p = libLoader.LoadPlatformSpecific(dllName); + if (_p == IntPtr.Zero) throw new InvalidOperationException("null pointer returned by LoadPlatformSpecific"); } public IntPtr Resolve(string entryPoint) { -#if !MONO - return Win32.GetProcAddress(_p, entryPoint); -#else - return Libdl.dlsym(_p, entryPoint); -#endif + return libLoader.GetProcAddr(_p, entryPoint); } private void Free() { - if (_p != IntPtr.Zero) - { -#if !MONO - Win32.FreeLibrary(_p); -#else - Libdl.dlclose(_p); -#endif - _p = IntPtr.Zero; - } + if (_p == IntPtr.Zero) return; + libLoader.FreePlatformSpecific(_p); + _p = IntPtr.Zero; } public void Dispose() @@ -55,30 +38,5 @@ namespace BizHawk.Common.BizInvoke { Free(); } - -#if !MONO - private static class Win32 - { - [DllImport("kernel32.dll")] - public static extern IntPtr LoadLibrary(string dllToLoad); - - [DllImport("kernel32.dll")] - public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); - - [DllImport("kernel32.dll")] - public static extern bool FreeLibrary(IntPtr hModule); - } -#else - private static class Libdl - { - [DllImport("libdl.so")] - public static extern IntPtr dlopen(string filename, int flags); - [DllImport("libdl.so")] - public static extern IntPtr dlsym(IntPtr handle, string symbol); - [DllImport("libdl.so")] - public static extern int dlclose(IntPtr handle); - public const int RTLD_NOW = 2; - } -#endif } } diff --git a/BizHawk.Common/BizInvoke/MemoryBlock.cs b/BizHawk.Common/BizInvoke/MemoryBlock.cs index 6f353cbc70..fd8e57181b 100644 --- a/BizHawk.Common/BizInvoke/MemoryBlock.cs +++ b/BizHawk.Common/BizInvoke/MemoryBlock.cs @@ -9,6 +9,8 @@ namespace BizHawk.Common.BizInvoke { public sealed class MemoryBlock : IDisposable { + //TODO rewrite this class without using the external functions in Kernel32 - this may help: https://docs.microsoft.com/en-us/dotnet/standard/io/memory-mapped-files + /// /// starting address of the memory block /// @@ -442,37 +444,10 @@ namespace BizHawk.Common.BizInvoke private static class Kernel32 { - [DllImport("kernel32.dll", SetLastError = true)] - public static extern UIntPtr VirtualAlloc(UIntPtr lpAddress, UIntPtr dwSize, - AllocationType flAllocationType, MemoryProtection flProtect); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool VirtualFree(UIntPtr lpAddress, UIntPtr dwSize, - FreeType dwFreeType); - [DllImport("kernel32.dll", SetLastError = true)] public static extern bool VirtualProtect(UIntPtr lpAddress, UIntPtr dwSize, MemoryProtection flNewProtect, out MemoryProtection lpflOldProtect); - public enum FreeType : uint - { - DECOMMIT = 0x4000, - RELEASE = 0x8000 - } - - [Flags] - public enum AllocationType : uint - { - COMMIT = 0x1000, - RESERVE = 0x2000, - RESET = 0x80000, - RESET_UNDO = 0x1000000, - LARGE_PAGES = 0x20000000, - PHYSICAL = 0x400000, - TOP_DOWN = 0x100000, - WRITE_WATCH = 0x200000 - } - [Flags] public enum MemoryProtection : uint { diff --git a/BizHawk.Common/PlatformLinkedLibSingleton.cs b/BizHawk.Common/PlatformLinkedLibSingleton.cs new file mode 100644 index 0000000000..9a9ed2baab --- /dev/null +++ b/BizHawk.Common/PlatformLinkedLibSingleton.cs @@ -0,0 +1,86 @@ +using System; +using System.Runtime.InteropServices; + +namespace BizHawk.Common +{ + public sealed class PlatformLinkedLibSingleton + { + public static readonly bool RunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX; + + private static readonly Lazy lazy = new Lazy(() => RunningOnUnix + ? (PlatformLinkedLibManager) new UnixMonoLinkedLibManager() + : (PlatformLinkedLibManager) new Win32LinkedLibManager()); + + public static PlatformLinkedLibManager LinkedLibManager { get { return lazy.Value; } } + + private PlatformLinkedLibSingleton() {} + + public interface PlatformLinkedLibManager + { + IntPtr LoadPlatformSpecific(string dllToLoad); + IntPtr GetProcAddr(IntPtr hModule, string procName); + int FreePlatformSpecific(IntPtr hModule); + } + + public class UnixMonoLinkedLibManager : PlatformLinkedLibManager + { + // This class is copied from a tutorial, so don't git blame and then email me expecting insight. + const int RTLD_NOW = 2; + [DllImport("libdl.so.2")] + private static extern IntPtr dlopen(String fileName, int flags); + [DllImport("libdl.so.2")] + private static extern IntPtr dlerror(); + [DllImport("libdl.so.2")] + private static extern IntPtr dlsym(IntPtr handle, String symbol); + [DllImport("libdl.so.2")] + private static extern int dlclose(IntPtr handle); + public IntPtr LoadPlatformSpecific(string dllToLoad) + { + return dlopen(dllToLoad, RTLD_NOW); + } + public IntPtr GetProcAddr(IntPtr hModule, string procName) + { + dlerror(); + var res = dlsym(hModule, procName); + var errPtr = dlerror(); + if (errPtr != IntPtr.Zero) throw new InvalidOperationException($"error in dlsym: {Marshal.PtrToStringAnsi(errPtr)}"); + return res; + } + public int FreePlatformSpecific(IntPtr hModule) + { + return dlclose(hModule); + } + } + + public class Win32LinkedLibManager : PlatformLinkedLibManager + { + [DllImport("kernel32.dll")] + private static extern UInt32 GetLastError(); + // was annotated `[DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)]` in SevenZip.NativeMethods + // param dllToLoad was annotated `[MarshalAs(UnmanagedType.LPStr)]` in SevenZip.NativeMethods + [DllImport("kernel32.dll")] + private static extern IntPtr LoadLibrary(string dllToLoad); + // was annotated `[DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)]` in SevenZip.NativeMethods + // param procName was annotated `[MarshalAs(UnmanagedType.LPStr)]` in SevenZip.NativeMethods + [DllImport("kernel32.dll")] + private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); + // was annotated `[return: MarshalAs(UnmanagedType.Bool)]` in SevenZip.NativeMethods + [DllImport("kernel32.dll")] + private static extern bool FreeLibrary(IntPtr hModule); + public IntPtr LoadPlatformSpecific(string dllToLoad) + { + var p = LoadLibrary(dllToLoad); + if (p == IntPtr.Zero) throw new InvalidOperationException($"got null pointer, error code {GetLastError()}"); + return p; + } + public IntPtr GetProcAddr(IntPtr hModule, string procName) + { + return GetProcAddress(hModule, procName); + } + public int FreePlatformSpecific(IntPtr hModule) + { + return FreeLibrary(hModule) ? 1 : 0; + } + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Common/Sound/Utilities/BlipBuffer.cs b/BizHawk.Emulation.Common/Sound/Utilities/BlipBuffer.cs index 5454adf67c..42d57dbef6 100644 --- a/BizHawk.Emulation.Common/Sound/Utilities/BlipBuffer.cs +++ b/BizHawk.Emulation.Common/Sound/Utilities/BlipBuffer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.InteropServices; // ReSharper disable StyleCop.SA1300 @@ -17,12 +17,12 @@ namespace BizHawk.Emulation.Common /** Creates new buffer that can hold at most sample_count samples. Sets rates so that there are blip_max_ratio clocks per sample. Returns pointer to new buffer, or NULL if insufficient memory. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr blip_new(int sample_count); /** Sets approximate input clock rate and output sample rate. For every clock_rate input clocks, approximately sample_rate samples are generated. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern void blip_set_rates(IntPtr context, double clock_rate, double sample_rate); /** Maximum clock_rate/sample_rate ratio. For a given sample_rate, @@ -30,20 +30,20 @@ namespace BizHawk.Emulation.Common public const int BlipMaxRatio = 1 << 20; /** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern void blip_clear(IntPtr context); /** Adds positive/negative delta into buffer at specified clock time. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern void blip_add_delta(IntPtr context, uint clock_time, int delta); /** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern void blip_add_delta_fast(IntPtr context, uint clock_time, int delta); /** Length of time frame, in clocks, needed to make sample_count additional samples available. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern int blip_clocks_needed(IntPtr context, int sample_count); /** Maximum number of samples that can be generated from one time frame. */ @@ -54,24 +54,24 @@ namespace BizHawk.Emulation.Common the new time frame specifies the same clock as clock_duration in the old time frame specified. Deltas can have been added slightly past clock_duration (up to however many clocks there are in two output samples). */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern void blip_end_frame(IntPtr context, uint clock_duration); /** Number of buffered samples available for reading. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern int blip_samples_avail(IntPtr context); /** Reads and removes at most 'count' samples and writes them to 'out'. If 'stereo' is true, writes output to every other element of 'out', allowing easy interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed samples. Returns number of samples actually read. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern int blip_read_samples(IntPtr context, short[] @out, int count, int stereo); - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern int blip_read_samples(IntPtr context, IntPtr @out, int count, int stereo); /** Frees buffer. No effect if NULL is passed. */ - [DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("blip_buf", CallingConvention = CallingConvention.Cdecl)] public static extern void blip_delete(IntPtr context); } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs index c1fdd04a45..c499855ae5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; +using BizHawk.Common; using BizHawk.Emulation.Common; using System.Text; @@ -26,17 +27,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi bool event_frameend = false; bool event_breakpoint = false; - [DllImport("kernel32.dll")] - public static extern UInt32 GetLastError(); - - [DllImport("kernel32.dll")] - public static extern IntPtr LoadLibrary(string dllToLoad); - - [DllImport("kernel32.dll")] - public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); - - [DllImport("kernel32.dll")] - public static extern bool FreeLibrary(IntPtr hModule); + private static readonly PlatformLinkedLibSingleton.PlatformLinkedLibManager libLoader = PlatformLinkedLibSingleton.LinkedLibManager; public enum m64p_error { @@ -506,7 +497,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi } this.bizhawkCore = bizhawkCore; - CoreDll = LoadLibrary("mupen64plus.dll"); + CoreDll = libLoader.LoadPlatformSpecific("mupen64plus"); if (CoreDll == IntPtr.Zero) throw new InvalidOperationException(string.Format("Failed to load mupen64plus.dll")); @@ -605,41 +596,41 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi /// void connectFunctionPointers() { - m64pCoreStartup = (CoreStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreStartup"), typeof(CoreStartup)); - m64pCoreShutdown = (CoreShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreShutdown"), typeof(CoreShutdown)); - m64pCoreDoCommandByteArray = (CoreDoCommandByteArray)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandByteArray)); - m64pCoreDoCommandPtr = (CoreDoCommandPtr)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandPtr)); - m64pCoreDoCommandRefInt = (CoreDoCommandRefInt)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRefInt)); - m64pCoreDoCommandFrameCallback = (CoreDoCommandFrameCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandFrameCallback)); - m64pCoreDoCommandVICallback = (CoreDoCommandVICallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandVICallback)); - m64pCoreDoCommandRenderCallback = (CoreDoCommandRenderCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRenderCallback)); - m64pCoreAttachPlugin = (CoreAttachPlugin)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreAttachPlugin"), typeof(CoreAttachPlugin)); - m64pCoreDetachPlugin = (CoreDetachPlugin)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDetachPlugin"), typeof(CoreDetachPlugin)); - m64pConfigOpenSection = (ConfigOpenSection)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "ConfigOpenSection"), typeof(ConfigOpenSection)); - m64pConfigSetParameter = (ConfigSetParameter)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameter)); - m64pConfigSetParameterStr = (ConfigSetParameterStr)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameterStr)); - m64pCoreSaveState = (savestates_save_bkm)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "savestates_save_bkm"), typeof(savestates_save_bkm)); - m64pCoreLoadState = (savestates_load_bkm)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "savestates_load_bkm"), typeof(savestates_load_bkm)); - m64pDebugMemGetPointer = (DebugMemGetPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugMemGetPointer"), typeof(DebugMemGetPointer)); - m64pDebugSetCallbacks = (DebugSetCallbacks)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugSetCallbacks"), typeof(DebugSetCallbacks)); - m64pDebugBreakpointLookup = (DebugBreakpointLookup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugBreakpointLookup"), typeof(DebugBreakpointLookup)); - m64pDebugBreakpointCommand = ( DebugBreakpointCommand )Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugBreakpointCommand"), typeof(DebugBreakpointCommand)); - m64pDebugGetState = (DebugGetState)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugGetState"), typeof(DebugGetState)); - m64pDebugSetRunState = (DebugSetRunState)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugSetRunState"), typeof(DebugSetRunState)); - m64pDebugStep = (DebugStep)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "DebugStep"), typeof(DebugStep)); - m64pMemGetSize = (MemGetSize)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "MemGetSize"), typeof(MemGetSize)); - m64pinit_saveram = (init_saveram)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "init_saveram"), typeof(init_saveram)); - m64psave_saveram = (save_saveram)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "save_saveram"), typeof(save_saveram)); - m64pload_saveram = (load_saveram)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "load_saveram"), typeof(load_saveram)); + m64pCoreStartup = (CoreStartup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreStartup"), typeof(CoreStartup)); + m64pCoreShutdown = (CoreShutdown)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreShutdown"), typeof(CoreShutdown)); + m64pCoreDoCommandByteArray = (CoreDoCommandByteArray)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandByteArray)); + m64pCoreDoCommandPtr = (CoreDoCommandPtr)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandPtr)); + m64pCoreDoCommandRefInt = (CoreDoCommandRefInt)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRefInt)); + m64pCoreDoCommandFrameCallback = (CoreDoCommandFrameCallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandFrameCallback)); + m64pCoreDoCommandVICallback = (CoreDoCommandVICallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandVICallback)); + m64pCoreDoCommandRenderCallback = (CoreDoCommandRenderCallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRenderCallback)); + m64pCoreAttachPlugin = (CoreAttachPlugin)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreAttachPlugin"), typeof(CoreAttachPlugin)); + m64pCoreDetachPlugin = (CoreDetachPlugin)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDetachPlugin"), typeof(CoreDetachPlugin)); + m64pConfigOpenSection = (ConfigOpenSection)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "ConfigOpenSection"), typeof(ConfigOpenSection)); + m64pConfigSetParameter = (ConfigSetParameter)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameter)); + m64pConfigSetParameterStr = (ConfigSetParameterStr)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameterStr)); + m64pCoreSaveState = (savestates_save_bkm)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "savestates_save_bkm"), typeof(savestates_save_bkm)); + m64pCoreLoadState = (savestates_load_bkm)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "savestates_load_bkm"), typeof(savestates_load_bkm)); + m64pDebugMemGetPointer = (DebugMemGetPointer)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugMemGetPointer"), typeof(DebugMemGetPointer)); + m64pDebugSetCallbacks = (DebugSetCallbacks)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugSetCallbacks"), typeof(DebugSetCallbacks)); + m64pDebugBreakpointLookup = (DebugBreakpointLookup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugBreakpointLookup"), typeof(DebugBreakpointLookup)); + m64pDebugBreakpointCommand = ( DebugBreakpointCommand )Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugBreakpointCommand"), typeof(DebugBreakpointCommand)); + m64pDebugGetState = (DebugGetState)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugGetState"), typeof(DebugGetState)); + m64pDebugSetRunState = (DebugSetRunState)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugSetRunState"), typeof(DebugSetRunState)); + m64pDebugStep = (DebugStep)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugStep"), typeof(DebugStep)); + m64pMemGetSize = (MemGetSize)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "MemGetSize"), typeof(MemGetSize)); + m64pinit_saveram = (init_saveram)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "init_saveram"), typeof(init_saveram)); + m64psave_saveram = (save_saveram)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "save_saveram"), typeof(save_saveram)); + m64pload_saveram = (load_saveram)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "load_saveram"), typeof(load_saveram)); - m64pSetTraceCallback = (SetTraceCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "SetTraceCallback"), typeof(SetTraceCallback)); + m64pSetTraceCallback = (SetTraceCallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "SetTraceCallback"), typeof(SetTraceCallback)); - m64pGetRegisters = (GetRegisters)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "GetRegisters"), typeof(GetRegisters)); + m64pGetRegisters = (GetRegisters)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "GetRegisters"), typeof(GetRegisters)); - m64p_read_memory_8 = (biz_read_memory)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "biz_read_memory"), typeof(biz_read_memory)); - m64p_write_memory_8 = (biz_write_memory)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "biz_write_memory"), typeof(biz_write_memory)); + m64p_read_memory_8 = (biz_read_memory)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "biz_read_memory"), typeof(biz_read_memory)); + m64p_write_memory_8 = (biz_write_memory)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "biz_write_memory"), typeof(biz_write_memory)); - m64p_decode_op = (biz_r4300_decode_op)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "biz_r4300_decode_op"), typeof(biz_r4300_decode_op)); + m64p_decode_op = (biz_r4300_decode_op)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "biz_r4300_decode_op"), typeof(biz_r4300_decode_op)); } /// @@ -933,7 +924,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi m64pCoreDoCommandPtr(m64p_command.M64CMD_ROM_CLOSE, 0, IntPtr.Zero); m64pCoreShutdown(); - FreeLibrary(CoreDll); + libLoader.FreePlatformSpecific(CoreDll); disposed = true; } @@ -953,18 +944,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi DetachPlugin(type); AttachedPlugin plugin; - plugin.dllHandle = LoadLibrary(PluginName); - if (plugin.dllHandle == IntPtr.Zero) - throw new InvalidOperationException(string.Format("Failed to load plugin {0}, error code: 0x{1:X}", PluginName, GetLastError())); + plugin.dllHandle = libLoader.LoadPlatformSpecific(PluginName); - plugin.dllStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(plugin.dllHandle, "PluginStartup"), typeof(PluginStartup)); - plugin.dllShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(plugin.dllHandle, "PluginShutdown"), typeof(PluginShutdown)); + plugin.dllStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(plugin.dllHandle, "PluginStartup"), typeof(PluginStartup)); + plugin.dllShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(plugin.dllHandle, "PluginShutdown"), typeof(PluginShutdown)); plugin.dllStartup(CoreDll, null, null); m64p_error result = m64pCoreAttachPlugin(type, plugin.dllHandle); if (result != m64p_error.M64ERR_SUCCESS) { - FreeLibrary(plugin.dllHandle); + libLoader.FreePlatformSpecific(plugin.dllHandle); throw new InvalidOperationException(string.Format("Error during attaching plugin {0}", PluginName)); } @@ -980,7 +969,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi plugins.Remove(type); m64pCoreDetachPlugin(type); plugin.dllShutdown(); - FreeLibrary(plugin.dllHandle); + libLoader.FreePlatformSpecific(plugin.dllHandle); } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs index 899ae0254f..fc632d8fa9 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs @@ -21,8 +21,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES { static QuickNES() { - Resolver = new DynamicLibraryImportResolver(LibQuickNES.dllname); - QN = BizInvoker.GetInvoker(Resolver, CallingConventionAdapters.Native); + QN = BizInvoker.GetInvoker(new DynamicLibraryImportResolver(LibQuickNES.dllname), CallingConventionAdapters.Native); QN.qn_setup_mappers(); } @@ -74,7 +73,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES } static readonly LibQuickNES QN; - static readonly DynamicLibraryImportResolver Resolver; public IEmulatorServiceProvider ServiceProvider { get; private set; } diff --git a/References/OpenTK.GLControl.dll b/References/OpenTK.GLControl.dll index 9cfe53e67ff8ca4ca26568fb59c9b8294527ca40..9d928cfb69790fe36c46f809547c1d0fe1af30f5 100644 GIT binary patch literal 45056 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 - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + From 12ad2d5b369354ea4dbf75e5103659faadb8245b Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 3 Jan 2019 17:31:35 -0600 Subject: [PATCH 14/15] GBHawk: Link Cable work --- BizHawk.Client.EmuHawk/MainForm.Designer.cs | 32 +++- BizHawk.Client.EmuHawk/MainForm.Events.cs | 5 + BizHawk.Client.EmuHawk/MainForm.cs | 11 +- .../Nintendo/GBHawk/GBHawk.IEmulator.cs | 83 ++++++++++ .../GBHawkLink/GBHawkLink.IEmulator.cs | 143 ++++++++++++++++-- .../GBHawkLink/GBHawkLink.ISaveRam.cs | 55 ++++++- .../GBHawkLink/GBHawkLink.ISettable.cs | 123 ++++++++++----- .../Nintendo/GBHawkLink/GBHawkLink.cs | 44 +++--- .../GBHawkLink/GBHawkLinkControllerDeck.cs | 1 + 9 files changed, 426 insertions(+), 71 deletions(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index 746d1ebd37..092908ba95 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -351,7 +351,9 @@ this.SaturnPreferencesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.DGBSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.DGBsettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.GenesisSubMenu = new System.Windows.Forms.ToolStripMenuItem(); + this.DGBHawkSubMenu = new System.Windows.Forms.ToolStripMenuItem(); + this.DGBHawksettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.GenesisSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.vDPViewerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.GenesisGameGenieECDC = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator26 = new System.Windows.Forms.ToolStripSeparator(); @@ -503,7 +505,8 @@ this.N64SubMenu, this.SaturnSubMenu, this.DGBSubMenu, - this.GenesisSubMenu, + this.DGBHawkSubMenu, + this.GenesisSubMenu, this.wonderSwanToolStripMenuItem, this.AppleSubMenu, this.C64SubMenu, @@ -3177,10 +3180,25 @@ this.DGBsettingsToolStripMenuItem.Size = new System.Drawing.Size(152, 22); this.DGBsettingsToolStripMenuItem.Text = "Settings..."; this.DGBsettingsToolStripMenuItem.Click += new System.EventHandler(this.DgbSettingsMenuItem_Click); - // - // GenesisSubMenu - // - this.GenesisSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + // + // DGBHawkSubMenu + // + this.DGBHawkSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.DGBHawksettingsToolStripMenuItem}); + this.DGBHawkSubMenu.Name = "DGBHawkSubMenu"; + this.DGBHawkSubMenu.Size = new System.Drawing.Size(59, 19); + this.DGBHawkSubMenu.Text = "&GB Link"; + // + // DGBHawksettingsToolStripMenuItem + // + this.DGBHawksettingsToolStripMenuItem.Name = "DGBHawksettingsToolStripMenuItem"; + this.DGBHawksettingsToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.DGBHawksettingsToolStripMenuItem.Text = "Settings..."; + this.DGBHawksettingsToolStripMenuItem.Click += new System.EventHandler(this.DgbHawkSettingsMenuItem_Click); + // + // GenesisSubMenu + // + this.GenesisSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.vDPViewerToolStripMenuItem, this.GenesisGameGenieECDC, this.toolStripSeparator26, @@ -4504,6 +4522,8 @@ private System.Windows.Forms.ToolStripMenuItem FdsEjectDiskMenuItem; private System.Windows.Forms.ToolStripMenuItem DGBSubMenu; private System.Windows.Forms.ToolStripMenuItem DGBsettingsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem DGBHawkSubMenu; + private System.Windows.Forms.ToolStripMenuItem DGBHawksettingsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem GenesisSubMenu; private System.Windows.Forms.ToolStripMenuItem GenesisSettingsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem AtariSettingsToolStripMenuItem; diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index 583898ae0f..e9bce5e5aa 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -2350,6 +2350,11 @@ namespace BizHawk.Client.EmuHawk DGBPrefs.DoDGBPrefsDialog(this); } + private void DgbHawkSettingsMenuItem_Click(object sender, EventArgs e) + { + GenericCoreConfig.DoDialog(this, "Gameboy Settings"); + } + #endregion #region GEN diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 9684d7b21e..4c02e8bf16 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -24,6 +24,7 @@ using BizHawk.Emulation.Cores.Nintendo.GBA; using BizHawk.Emulation.Cores.Nintendo.NES; using BizHawk.Emulation.Cores.Nintendo.SNES; using BizHawk.Emulation.Cores.Nintendo.N64; +using BizHawk.Emulation.Cores.Nintendo.GBHawkLink; using BizHawk.Client.EmuHawk.WinFormExtensions; using BizHawk.Client.EmuHawk.ToolExtensions; @@ -1720,6 +1721,7 @@ namespace BizHawk.Client.EmuHawk N64SubMenu.Visible = false; SaturnSubMenu.Visible = false; DGBSubMenu.Visible = false; + DGBHawkSubMenu.Visible = false; GenesisSubMenu.Visible = false; wonderSwanToolStripMenuItem.Visible = false; AppleSubMenu.Visible = false; @@ -1802,7 +1804,14 @@ namespace BizHawk.Client.EmuHawk SaturnSubMenu.Visible = true; break; case "DGB": - DGBSubMenu.Visible = true; + if (Emulator is GBHawkLink) + { + DGBHawkSubMenu.Visible = true; + } + else + { + DGBSubMenu.Visible = true; + } break; case "WSWAN": wonderSwanToolStripMenuItem.Visible = true; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs index 01f04f8338..e0aa0baeef 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs @@ -168,6 +168,89 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk vblank_rise = false; } + public void do_single_step() + { + // These things do not change speed in GBC double spped mode + audio.tick(); + ppu.tick(); + if (Use_MT) { mapper.Mapper_Tick(); } + + if (!HDMA_transfer) + { + // These things all tick twice as fast in GBC double speed mode + ppu.DMA_tick(); + timer.tick_1(); + serialport.serial_transfer_tick(); + cpu.ExecuteOne(ref REG_FF0F, REG_FFFF); + timer.tick_2(); + + if (double_speed) + { + ppu.DMA_tick(); + timer.tick_1(); + serialport.serial_transfer_tick(); + cpu.ExecuteOne(ref REG_FF0F, REG_FFFF); + timer.tick_2(); + } + } + else + { + timer.tick_1(); + timer.tick_2(); + cpu.TotalExecutedCycles++; + if (double_speed) + { + timer.tick_1(); + timer.tick_2(); + cpu.TotalExecutedCycles++; + } + } + + if (in_vblank && !in_vblank_old) + { + vblank_rise = true; + } + + in_vblank_old = in_vblank; + REG_FF0F_OLD = REG_FF0F; + } + + public void do_controller_check() + { + // check if new input changed the input register and triggered IRQ + byte contr_prev = input_register; + + input_register &= 0xF0; + if ((input_register & 0x30) == 0x20) + { + input_register |= (byte)(controller_state & 0xF); + } + else if ((input_register & 0x30) == 0x10) + { + input_register |= (byte)((controller_state & 0xF0) >> 4); + } + else if ((input_register & 0x30) == 0x00) + { + // if both polls are set, then a bit is zero if either or both pins are zero + byte temp = (byte)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4)); + input_register |= temp; + } + else + { + input_register |= 0xF; + } + + // check for interrupts + if (((contr_prev & 8) > 0) && ((input_register & 8) == 0) || + ((contr_prev & 4) > 0) && ((input_register & 4) == 0) || + ((contr_prev & 2) > 0) && ((input_register & 2) == 0) || + ((contr_prev & 1) > 0) && ((input_register & 1) == 0)) + { + if (REG_FFFF.Bit(4)) { cpu.FlagI = true; } + REG_FF0F |= 0x10; + } + } + // Switch Speed (GBC only) public int SpeedFunc(int temp) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs index 790ab1fa06..3d0fa172cf 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs @@ -4,9 +4,11 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; +using BizHawk.Emulation.Cores.Nintendo.GBHawk; + namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink { - public partial class GBHawkLink : IEmulator, IVideoProvider + public partial class GBHawkLink : IEmulator, IVideoProvider, ISoundProvider { public IEmulatorServiceProvider ServiceProvider { get; } @@ -20,6 +22,37 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public void FrameAdvance(IController controller, bool render, bool rendersound) { //Console.WriteLine("-----------------------FRAME-----------------------"); + //Update the color palette if a setting changed + if (linkSettings.Palette_L == GBHawk.GBHawk.GBSettings.PaletteType.BW) + { + L.color_palette[0] = color_palette_BW[0]; + L.color_palette[1] = color_palette_BW[1]; + L.color_palette[2] = color_palette_BW[2]; + L.color_palette[3] = color_palette_BW[3]; + } + else + { + L.color_palette[0] = color_palette_Gr[0]; + L.color_palette[1] = color_palette_Gr[1]; + L.color_palette[2] = color_palette_Gr[2]; + L.color_palette[3] = color_palette_Gr[3]; + } + + if (linkSettings.Palette_R == GBHawk.GBHawk.GBSettings.PaletteType.BW) + { + R.color_palette[0] = color_palette_BW[0]; + R.color_palette[1] = color_palette_BW[1]; + R.color_palette[2] = color_palette_BW[2]; + R.color_palette[3] = color_palette_BW[3]; + } + else + { + R.color_palette[0] = color_palette_Gr[0]; + R.color_palette[1] = color_palette_Gr[1]; + R.color_palette[2] = color_palette_Gr[2]; + R.color_palette[3] = color_palette_Gr[3]; + } + if (_tracer.Enabled) { L.cpu.TraceCallback = s => _tracer.Put(s); @@ -36,6 +69,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink HardReset(); } + bool cablediscosignalNew = controller.IsPressed("Toggle Cable"); + if (cablediscosignalNew && !_cablediscosignal) + { + _cableconnected ^= true; + Console.WriteLine("Cable connect status to {0}", _cableconnected); + LinkConnected = _cableconnected; + } + + _cablediscosignal = cablediscosignalNew; + _islag = true; GetControllerState(controller); @@ -52,8 +95,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public void do_frame() { - L.do_frame(); - R.do_frame(); + L.do_controller_check(); + R.do_controller_check(); + + // advance one full frame + for (int i = 0; i < 70224; i++) + { + L.do_single_step(); + R.do_single_step(); + + // if we hit a frame boundary, update video + if (L.vblank_rise) + { + buff_L = L.GetVideoBuffer(); + L.vblank_rise = false; + } + if (R.vblank_rise) + { + buff_R = R.GetVideoBuffer(); + R.vblank_rise = false; + } + } } public void GetControllerState(IController controller) @@ -65,7 +127,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public int Frame => _frame; - public string SystemId => "GB"; + public string SystemId => "DGB"; public bool DeterministicEmulation { get; set; } @@ -89,15 +151,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public int _frameHz = 60; public int[] _vidbuffer = new int[160 * 2 * 144]; - public int[] buff_L; - public int[] buff_R; + public int[] buff_L = new int[160 * 144]; + public int[] buff_R = new int[160 * 144]; public int[] GetVideoBuffer() { // combine the 2 video buffers from the instances - buff_L = L.GetVideoBuffer(); - buff_R = R.GetVideoBuffer(); - for (int i = 0; i < 144; i++) { for (int j = 0; j < 160; j++) @@ -124,5 +183,71 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public uint[] color_palette = new uint[4]; #endregion + + #region audio + + public bool CanProvideAsync => false; + + public void SetSyncMode(SyncSoundMode mode) + { + if (mode != SyncSoundMode.Sync) + { + throw new InvalidOperationException("Only Sync mode is supported_"); + } + } + + public SyncSoundMode SyncMode => SyncSoundMode.Sync; + + public void GetSamplesSync(out short[] samples, out int nsamp) + { + short[] temp_samp_L; + short[] temp_samp_R; + + int nsamp_L; + int nsamp_R; + + L.audio.GetSamplesSync(out temp_samp_L, out nsamp_L); + R.audio.GetSamplesSync(out temp_samp_R, out nsamp_R); + + if (linkSettings.AudioSet == GBLinkSettings.AudioSrc.Left) + { + samples = temp_samp_L; + nsamp = nsamp_L; + } + else if (linkSettings.AudioSet == GBLinkSettings.AudioSrc.Right) + { + samples = temp_samp_R; + nsamp = nsamp_R; + } + else + { + samples = new short[0]; + nsamp = 0; + } + } + + public void GetSamplesAsync(short[] samples) + { + throw new NotSupportedException("Async is not available"); + } + + public void DiscardSamples() + { + L.audio.DiscardSamples(); + R.audio.DiscardSamples(); + } + + private void GetSamples(short[] samples) + { + + } + + public void DisposeSound() + { + L.audio.DisposeSound(); + R.audio.DisposeSound(); + } + + #endregion } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs index e8a6a9d0b5..1a92caf11b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs @@ -7,9 +7,43 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink { public byte[] CloneSaveRam() { - if (L.cart_RAM != null) + if ((L.cart_RAM != null) || (R.cart_RAM != null)) { - return (byte[])L.cart_RAM.Clone(); + int Len1 = 0; + int Len2 = 0; + int index = 0; + + if (L.cart_RAM != null) + { + Len1 = L.cart_RAM.Length; + } + + if (R.cart_RAM != null) + { + Len2 = R.cart_RAM.Length; + } + + byte[] temp = new byte[Len1 + Len2]; + + if (L.cart_RAM != null) + { + for (int i = 0; i < L.cart_RAM.Length; i++) + { + temp[index] = L.cart_RAM[i]; + index++; + } + } + + if (R.cart_RAM != null) + { + for (int i = 0; i < L.cart_RAM.Length; i++) + { + temp[index] = R.cart_RAM[i]; + index++; + } + } + + return temp; } else { @@ -19,7 +53,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public void StoreSaveRam(byte[] data) { - Buffer.BlockCopy(data, 0, L.cart_RAM, 0, data.Length); + if ((L.cart_RAM != null) && (R.cart_RAM == null)) + { + Buffer.BlockCopy(data, 0, L.cart_RAM, 0, L.cart_RAM.Length); + } + else if ((R.cart_RAM != null) && (L.cart_RAM == null)) + { + Buffer.BlockCopy(data, 0, R.cart_RAM, 0, R.cart_RAM.Length); + } + else if ((R.cart_RAM != null) && (L.cart_RAM != null)) + { + Buffer.BlockCopy(data, 0, L.cart_RAM, 0, L.cart_RAM.Length); + Buffer.BlockCopy(data, L.cart_RAM.Length, R.cart_RAM, 0, R.cart_RAM.Length); + } + Console.WriteLine("loading SRAM here"); } @@ -27,7 +74,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink { get { - return L.has_bat & _syncSettings.L.Use_SRAM; + return (L.has_bat || R.has_bat) & linkSyncSettings.Use_SRAM; } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs index dd2711ded1..75cea814bc 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs @@ -13,78 +13,133 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink { public GBLinkSettings GetSettings() { - return new GBLinkSettings - ( - L.GetSettings(), - R.GetSettings() - ); + return linkSettings.Clone(); } public GBLinkSyncSettings GetSyncSettings() { - return new GBLinkSyncSettings - ( - L.GetSyncSettings(), - R.GetSyncSettings() - ); + return linkSyncSettings.Clone(); } public bool PutSettings(GBLinkSettings o) { - return L.PutSettings(o.L) || R.PutSettings(o.R); + linkSettings = o; + return false; } public bool PutSyncSettings(GBLinkSyncSettings o) { - return L.PutSyncSettings(o.L) || R.PutSyncSettings(o.R); + bool ret = GBLinkSyncSettings.NeedsReboot(linkSyncSettings, o); + linkSyncSettings = o; + return ret; } - private GBLinkSettings _settings = new GBLinkSettings(); - public GBLinkSyncSettings _syncSettings = new GBLinkSyncSettings(); + private GBLinkSettings linkSettings = new GBLinkSettings(); + public GBLinkSyncSettings linkSyncSettings = new GBLinkSyncSettings(); public class GBLinkSettings { - public GBHawk.GBHawk.GBSettings L; - public GBHawk.GBHawk.GBSettings R; + [DisplayName("Color Mode")] + [Description("Pick Between Green scale and Grey scale colors")] + [DefaultValue(GBHawk.GBHawk.GBSettings.PaletteType.BW)] + public GBHawk.GBHawk.GBSettings.PaletteType Palette_L { get; set; } - public GBLinkSettings() + [DisplayName("Color Mode")] + [Description("Pick Between Green scale and Grey scale colors")] + [DefaultValue(GBHawk.GBHawk.GBSettings.PaletteType.BW)] + public GBHawk.GBHawk.GBSettings.PaletteType Palette_R { get; set; } + + public enum AudioSrc { - L = new GBHawk.GBHawk.GBSettings(); - R = new GBHawk.GBHawk.GBSettings(); + Left, + Right, + Both } - public GBLinkSettings(GBHawk.GBHawk.GBSettings L, GBHawk.GBHawk.GBSettings R) - { - this.L = L; - this.R = R; - } + [DisplayName("Audio Selection")] + [Description("Choose Audio Source. Both will produce Stereo sound.")] + [DefaultValue(AudioSrc.Left)] + public AudioSrc AudioSet { get; set; } public GBLinkSettings Clone() { - return new GBLinkSettings(L.Clone(), R.Clone()); + return (GBLinkSettings)MemberwiseClone(); } } public class GBLinkSyncSettings { - public GBHawk.GBHawk.GBSyncSettings L; - public GBHawk.GBHawk.GBSyncSettings R; + [DisplayName("Console Mode L")] + [Description("Pick which console to run, 'Auto' chooses from ROM extension, 'GB' and 'GBC' chooses the respective system")] + [DefaultValue(GBHawk.GBHawk.GBSyncSettings.ConsoleModeType.Auto)] + public GBHawk.GBHawk.GBSyncSettings.ConsoleModeType ConsoleMode_L { get; set; } - public GBLinkSyncSettings() + [DisplayName("Console Mode R")] + [Description("Pick which console to run, 'Auto' chooses from ROM extension, 'GB' and 'GBC' chooses the respective system")] + [DefaultValue(GBHawk.GBHawk.GBSyncSettings.ConsoleModeType.Auto)] + public GBHawk.GBHawk.GBSyncSettings.ConsoleModeType ConsoleMode_R { get; set; } + + [DisplayName("CGB in GBA")] + [Description("Emulate GBA hardware running a CGB game, instead of CGB hardware. Relevant only for titles that detect the presense of a GBA, such as Shantae.")] + [DefaultValue(false)] + public bool GBACGB { get; set; } + + [DisplayName("RTC Initial Time L")] + [Description("Set the initial RTC time in terms of elapsed seconds.")] + [DefaultValue(0)] + public int RTCInitialTime_L { - L = new GBHawk.GBHawk.GBSyncSettings(); - R = new GBHawk.GBHawk.GBSyncSettings(); + get { return _RTCInitialTime_L; } + set { _RTCInitialTime_L = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); } } - public GBLinkSyncSettings(GBHawk.GBHawk.GBSyncSettings L, GBHawk.GBHawk.GBSyncSettings R) + [DisplayName("RTC Initial Time R")] + [Description("Set the initial RTC time in terms of elapsed seconds.")] + [DefaultValue(0)] + public int RTCInitialTime_R { - this.L = L; - this.R = R; + get { return _RTCInitialTime_R; } + set { _RTCInitialTime_R = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); } } + [DisplayName("Timer Div Initial Time L")] + [Description("Don't change from 0 unless it's hardware accurate. GBA GBC mode is known to be 8.")] + [DefaultValue(8)] + public int DivInitialTime_L + { + get { return _DivInitialTime_L; } + set { _DivInitialTime_L = Math.Min((ushort)65535, (ushort)value); } + } + + [DisplayName("Timer Div Initial Time R")] + [Description("Don't change from 0 unless it's hardware accurate. GBA GBC mode is known to be 8.")] + [DefaultValue(8)] + public int DivInitialTime_R + { + get { return _DivInitialTime_R; } + set { _DivInitialTime_R = Math.Min((ushort)65535, (ushort)value); } + } + + [DisplayName("Use Existing SaveRAM")] + [Description("When true, existing SaveRAM will be loaded at boot up")] + [DefaultValue(false)] + public bool Use_SRAM { get; set; } + + [JsonIgnore] + private int _RTCInitialTime_L; + private int _RTCInitialTime_R; + [JsonIgnore] + public ushort _DivInitialTime_L; + public ushort _DivInitialTime_R; + public GBLinkSyncSettings Clone() { - return new GBLinkSyncSettings(L.Clone(), R.Clone()); + return (GBLinkSyncSettings)MemberwiseClone(); + } + + public static bool NeedsReboot(GBLinkSyncSettings x, GBLinkSyncSettings y) + { + return !DeepEquality.DeepEquals(x, y); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs index c4f2ffacda..3cd8412bc7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs @@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink "GBHawkLink", "", isPorted: false, - isReleased: true)] + isReleased: false)] [ServiceNotApplicable(typeof(IDriveLight))] public partial class GBHawkLink : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, ILinkable, ISettable @@ -24,25 +24,45 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink public GBHawk.GBHawk L; public GBHawk.GBHawk R; + // if true, the link cable is currently connected + private bool _cableconnected = true; + + // if true, the link cable toggle signal is currently asserted + private bool _cablediscosignal = false; + //[CoreConstructor("GB", "GBC")] public GBHawkLink(CoreComm comm, GameInfo game_L, byte[] rom_L, GameInfo game_R, byte[] rom_R, /*string gameDbFn,*/ object settings, object syncSettings) { var ser = new BasicServiceProvider(this); - GBLinkSettings linkSettings = (GBLinkSettings)settings ?? new GBLinkSettings(); - GBLinkSyncSettings linkSyncSettings = (GBLinkSyncSettings)syncSettings ?? new GBLinkSyncSettings(); + linkSettings = (GBLinkSettings)settings ?? new GBLinkSettings(); + linkSyncSettings = (GBLinkSyncSettings)syncSettings ?? new GBLinkSyncSettings(); _controllerDeck = new GBHawkLinkControllerDeck(GBHawkControllerDeck.DefaultControllerName, GBHawkControllerDeck.DefaultControllerName); CoreComm = comm; + var temp_set_L = new GBHawk.GBHawk.GBSettings(); + var temp_set_R = new GBHawk.GBHawk.GBSettings(); + + var temp_sync_L = new GBHawk.GBHawk.GBSyncSettings(); + var temp_sync_R = new GBHawk.GBHawk.GBSyncSettings(); + + temp_sync_L.ConsoleMode = linkSyncSettings.ConsoleMode_L; + temp_sync_R.ConsoleMode = linkSyncSettings.ConsoleMode_R; + + temp_sync_L.DivInitialTime = linkSyncSettings.DivInitialTime_L; + temp_sync_R.DivInitialTime = linkSyncSettings.DivInitialTime_R; + temp_sync_L.RTCInitialTime = linkSyncSettings.RTCInitialTime_L; + temp_sync_R.RTCInitialTime = linkSyncSettings.RTCInitialTime_R; + L = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, - game_L, rom_L, linkSettings.L, linkSyncSettings.L); + game_L, rom_L, temp_set_L, temp_sync_L); R = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, - game_R, rom_R, linkSettings.R, linkSyncSettings.R); + game_R, rom_R, temp_set_R, temp_sync_R); ser.Register(this); - ser.Register(L.audio); + ser.Register(this); _tracer = new TraceBuffer { Header = L.cpu.TraceHeader }; ser.Register(_tracer); @@ -52,16 +72,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink SetupMemoryDomains(); HardReset(); - - L.color_palette[0] = color_palette_BW[0]; - L.color_palette[1] = color_palette_BW[1]; - L.color_palette[2] = color_palette_BW[2]; - L.color_palette[3] = color_palette_BW[3]; - - R.color_palette[0] = color_palette_BW[0]; - R.color_palette[1] = color_palette_BW[1]; - R.color_palette[2] = color_palette_BW[2]; - R.color_palette[3] = color_palette_BW[3]; } public void HardReset() @@ -78,7 +88,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink private readonly ITraceable _tracer; - bool ILinkable.LinkConnected { get; } + public bool LinkConnected { get; private set; } private void ExecFetch(ushort addr) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs index fd2e5c7ae8..9bc1143bb4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLinkControllerDeck.cs @@ -30,6 +30,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink Name = Port1.Definition.Name, BoolButtons = Port1.Definition.BoolButtons .Concat(Port2.Definition.BoolButtons) + .Concat(new[] { "Toggle Cable" } ) .ToList() }; } From 32e4a2d9a4762d2ac643d9fa5396b588f8c9e16b Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 3 Jan 2019 19:24:18 -0600 Subject: [PATCH 15/15] GBHAwk: Linked play initial capability --- .../Consoles/Nintendo/GBHawk/SerialPort.cs | 15 +++++--- .../GBHawkLink/GBHawkLink.IEmulator.cs | 34 +++++++++++++++++++ .../GBHawkLink/GBHawkLink.IStatable.cs | 2 ++ .../Nintendo/GBHawkLink/GBHawkLink.cs | 2 ++ 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/SerialPort.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/SerialPort.cs index 64de7f5457..4aa700268c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/SerialPort.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/SerialPort.cs @@ -16,6 +16,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public int serial_bits; public bool clk_internal; public int clk_rate; + public byte going_out; + public byte coming_in; public byte ReadReg(int addr) { @@ -84,16 +86,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (serial_start) { if (serial_clock > 0) { serial_clock--; } + if (serial_clock == 0) { if (serial_bits > 0) { - send_external_bit((byte)(serial_data & 0x80)); - byte temp = get_external_bit(); serial_data = (byte)((serial_data << 1) | temp); serial_bits--; + if (serial_bits == 0) { serial_control &= 0x7F; @@ -122,12 +124,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // no device connected returns 0xFF public byte get_external_bit() { - return 1; + return coming_in; } + // calling this function buts an external bit on the cable line public void send_external_bit(byte bit_send) { - + going_out = (byte)(bit_send >> 7); } public void Reset() @@ -135,6 +138,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk serial_control = 0x7E; serial_start = false; serial_data = 0x00; + going_out = 0; + coming_in = 1; } public void SyncState(Serializer ser) @@ -146,6 +151,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync("serial_bits", ref serial_bits); ser.Sync("clk_internal", ref clk_internal); ser.Sync("clk_rate", ref clk_rate); + ser.Sync("going_out", ref going_out); + ser.Sync("coming_in", ref coming_in); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs index 3d0fa172cf..0a95188026 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs @@ -104,6 +104,40 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink L.do_single_step(); R.do_single_step(); + // the signal to shift out a bit is when serial_clock = 1 + if (L.serialport.serial_clock == 1) + { + if (LinkConnected) + { + L.serialport.send_external_bit((byte)(L.serialport.serial_data & 0x80)); + + if ((R.serialport.clk_rate == -1) && R.serialport.serial_start) + { + R.serialport.serial_clock = 1; + R.serialport.send_external_bit((byte)(R.serialport.serial_data & 0x80)); + R.serialport.coming_in = L.serialport.going_out; + } + + L.serialport.coming_in = R.serialport.going_out; + } + } + else if (R.serialport.serial_clock == 1) + { + if (LinkConnected) + { + R.serialport.send_external_bit((byte)(R.serialport.serial_data & 0x80)); + + if ((L.serialport.clk_rate == -1) && L.serialport.serial_start) + { + L.serialport.serial_clock = 1; + L.serialport.send_external_bit((byte)(L.serialport.serial_data & 0x80)); + L.serialport.coming_in = R.serialport.going_out; + } + + R.serialport.coming_in = L.serialport.going_out; + } + } + // if we hit a frame boundary, update video if (L.vblank_rise) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs index e078e962a9..ffd05ea99f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IStatable.cs @@ -57,6 +57,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink ser.Sync("Lag", ref _lagcount); ser.Sync("Frame", ref _frame); ser.Sync("IsLag", ref _islag); + ser.Sync("_cableconnected", ref _cableconnected); + ser.Sync("_cablediscosignal", ref _cablediscosignal); _controllerDeck.SyncState(ser); } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs index 3cd8412bc7..d007d533fb 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs @@ -72,6 +72,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink SetupMemoryDomains(); HardReset(); + + LinkConnected = _cableconnected; } public void HardReset()