• entries
222
606
• views
592238

# SaveStates and Key Names

1406 views

It's a good feeling when issue 1 is finally marked as Fixed - in this case it was another interrupt-related bug. The IFF1 flag was being used to mask non-maskable interrupts; I don't think it should and it hasn't seem to have broken anything just yet by making non-maskable interrupts truly non-maskable.

Go! Dizzy Go!

I have also changed the savestate format to something that will be a little more backwards compatible rather than a plain BinaryFormatter dump of the entire emulator state. The data is now saved in what is basically an INI file with C#-style attributes and CSS-style url() syntax for binary data.

[Type(BeeDevelopment.Sega8Bit.Hardware.VideoDisplayProcessor)]VideoRam=Dump(Video\VideoRam.bin)Address=49165WaitingForSecond=FalseAccessMode=ColourRamWriteReadBuffer=32Registers=Dump(Video\Registers.bin)System=NtscSupportsMode4=True; ... snip ...

Other changes include a faked fullscreen mode (ie, a maximised borderless window) and an option to retain the aspect ratio of the game, so games no longer appear stretched on widescreen monitors. The sound emulation is a bit better, but still a little noisy in certain games with spurious beeps or buzzes.

One minor problem was on the key configuration control panel. Converting members of the Keys enumeration into displayable strings can be done via .ToString(), but this results in names that do not match the user's keyboard layout (such as OemQuestion for /, OemTilde for # and even Oemcomma for , - note the lowercase c, all on a UK keyboard).

With a prod in the right direction from jpetrie, here's a snippet that can be used to convert Keys into friendly key name strings:
#region Converting Keys into human-readable strings./// /// Converts a  value into a human-readable string describing the key./// /// The  to convert./// A human-readable string describing the key.public static string GetKeyName(Keys key) {	// Convert the virtual key code into a scancode (as required by GetKeyNameText).	int Scancode = MapVirtualKey((int)key, MapVirtualKeyMode.MAPVK_VK_TO_VSC);	// If that returned 0 (failure) just use the value returned by Keys.ToString().	if (Scancode == 0) return key.ToString();	// Certain keys end up being mapped to the number pad by the above function,	// as their virtual key can be generated by the number pad too.	// If it's one of the known number-pad duplicates, set the extended bit:	switch (key) {		case Keys.Insert:		case Keys.Delete:		case Keys.Home:		case Keys.End:		case Keys.PageUp:		case Keys.PageDown:		case Keys.Left:		case Keys.Right:		case Keys.Up:		case Keys.Down:		case Keys.NumLock:			Scancode |= 0x100;			break;	}	// Perform the conversion:	StringBuilder KeyName = new StringBuilder("".PadRight(32));	if (GetKeyNameText((Scancode << 16), KeyName, KeyName.Length) != 0) {		return KeyName.ToString();	} else {		return key.ToString();	}}/// /// Retrieves a string that represents the name of a key./// /// Specifies the second parameter of the keyboard message (such as WM_KEYDOWN) to be processed./// Pointer to a buffer that will receive the key name./// Specifies the maximum length, in TCHAR, of the key name, including the terminating null character. (This parameter should be equal to the size of the buffer pointed to by the lpString parameter)./// The length of the returned string.[DllImport("user32.dll")]static extern int GetKeyNameText(int lParam, StringBuilder lpString, int size);/// /// Translates (maps) a virtual-key code into a scan code or character value, or translates a scan code into a virtual-key code./// /// Specifies the virtual-key code or scan code for a key. How this value is interpreted depends on the value of the  parameter./// Specifies the translation to perform. The value of this parameter depends on the value of the  parameter./// Either a scan code, a virtual-key code, or a character value, depending on the value of  and . If there is no translation, the return value is zero.[DllImport("user32.dll")]static extern int MapVirtualKey(int uCode, MapVirtualKeyMode uMapType);enum MapVirtualKeyMode {	/// uCode is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0.	MAPVK_VK_TO_VSC = 0,	/// uCode is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0.	MAPVK_VSC_TO_VK = 1,	/// uCode is a virtual-key code and is translated into an unshifted character value in the low-order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0.	MAPVK_VK_TO_CHAR = 2,	/// uCode is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0.	MAPVK_VSC_TO_VK_EX = 3,	MAPVK_VK_TO_VSC_EX = 4,}#endregion

It uses P/Invoke and the Win32 API so is only suitable for use on Windows.

Out Run

I like the work you're doing. very interesting. How complete is the emu so far? and I'm not sure where to dig this info up, did you write the emulator core?

Quote:
 Original post by deathtrap I like the work you're doing. very interesting. How complete is the emu so far? and I'm not sure where to dig this info up, did you write the emulator core?

Attaching a value to how complete the emulator is isn't very easy. As far as emulating a US Sega Master System or Game Gear, it's pretty complete (minus the few remaining bugs) and compatibility is decent.

There are, however, numerous gaps (missing SC-3000 keyboard emulation, missing TMS9918 multicolor mode, missing FM sound for Japanese hardware, front-end fixed at 60Hz). However, this leads to feature creep; if I emulate the SC-3000 better, I might as well start looking into the SF-7000 add-on; if I emulate the TMS9918 multicolor mode I'd really need to emulate the ColecoVision for testing purposes!

In other words, bits will still be added as I go along but if you just want something you can quickly load a game into and play, it should do that as long as it doesn't rely on exotic peripherals or hardware features.

(For the sake of examples, there are some free homebrew ROMs available here, here and here).

The Z80 core is mostly my own work, though I had help from Patai Gergely's code (namely his tables for setting flags after some instructions that were giving me trouble).

I meant to post this a couple entries ago, but I've been looking through the Cogwheel source code. While I can't really comment on anything specific, it did look a lot neater and more organized than your Doom code.

I'll try out the binaries tomorrow.

Quote:
 Original post by Scet While I can't really comment on anything specific, it did look a lot neater and more organized than your Doom code.
I'm not sure if that's much of a compliment or not. [wink] Both projects suffered the same problem - no real idea where I was going, just bolting on bits and pieces to the ramshackle edifice as I went. This codebase has at least the benefit of at least two major rewrites to try and get it back into shape!

## Create an account

Register a new account