Pdawg
Pdawg
CC#
Created by Pdawg on 11/17/2024 in #help
Micro-optimizing a Z80 emulators' pipeline. **Unsafe code**
so, i'm writing an emulator, and i'm trying to squeeze as much perf as i can out of hot paths. this seemingly simple fetch operation consumes about a third of the CPU time:
private byte Fetch()
{
return _memory.Read(Registers.PC++);
}
private byte Fetch()
{
return _memory.Read(Registers.PC++);
}
my memory class looks like this:
private GCHandle _memHandle;
private byte* pMem;
private byte[] _memory;

public MainMemory(int size)
{
// pin array and get GC ptr. omitted for brevity.
pMem = (byte*)_memHandle.AddrOfPinnedObject();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte Read(ushort address) => pMem[address];
private GCHandle _memHandle;
private byte* pMem;
private byte[] _memory;

public MainMemory(int size)
{
// pin array and get GC ptr. omitted for brevity.
pMem = (byte*)_memHandle.AddrOfPinnedObject();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte Read(ushort address) => pMem[address];
i know, it's a bit messy, and it's not really safe either, but boy does it give some perf gains. it's worth it. also, the array wont change size so it should be alright. my registers are in a similar situation. the register set is actually an array of bytes that are accessed using constant indexers into said array, like this:
private GCHandle _regSetHandle;
private byte* pRegSet;
public byte[] RegisterSet;
public ProcessorRegisters()
{
RegisterSet = new byte[26];
_regSetHandle = GCHandle.Alloc(RegisterSet, GCHandleType.Pinned);
pRegSet = (byte*)_regSetHandle.AddrOfPinnedObject();
}
// example
byte regA = pRegSet[Registers.A]; // A is an indexer into the array; i tried to follow the Z80's convention, so A = 7
private GCHandle _regSetHandle;
private byte* pRegSet;
public byte[] RegisterSet;
public ProcessorRegisters()
{
RegisterSet = new byte[26];
_regSetHandle = GCHandle.Alloc(RegisterSet, GCHandleType.Pinned);
pRegSet = (byte*)_regSetHandle.AddrOfPinnedObject();
}
// example
byte regA = pRegSet[Registers.A]; // A is an indexer into the array; i tried to follow the Z80's convention, so A = 7
but, this is a Z80, meaning it also has 16-bit register pairs. this is important, because you can either access it as its high and low parts, or its entire pair, meaning that the exposed pairs depend on this same array, so i implemented them using properties
public ushort PC
{
get => (ushort)((pRegSet[PCi] << 8) | pRegSet[PCiL]);
set
{
pRegSet[PCi] = (byte)(value >> 8);
pRegSet[PCiL] = (byte)value;
}
}
public ushort PC
{
get => (ushort)((pRegSet[PCi] << 8) | pRegSet[PCiL]);
set
{
pRegSet[PCi] = (byte)(value >> 8);
pRegSet[PCiL] = (byte)value;
}
}
with all of this in mind, how can i make that fetch instruction faster and use less CPU time?
215 replies
CC#
Created by Pdawg on 9/8/2024 in #help
Optimizing the pipeline on my Z80 emulator
Hello! I've come to ask you all a question about optimization of lambda expressions. Currently, my pipeline looks like this:
private readonly Action[] instructionTable = new Action[256];

// in ctor, for example:
instructionTable[0x48] = () => LD_R_R(C, B); // LD C, B
instructionTable[0x49] = () => LD_R_R(C, C); // LD C, C
instructionTable[0x4A] = () => LD_R_R(C, D); // LD C, D

private void LD_R_R(byte dest, byte source)
{
Registers.RegisterSet[dest] = Registers.RegisterSet[source];
LogInstructionExec($"0x{_currentInstruction:X2}: LD {Registers.RegisterName(dest)}, {Registers.RegisterName(source)}:0x{Registers.RegisterSet[source]:X2}");
}

// calling:
_currentInstruction = Fetch();
switch (_currentInstruction)
{
case 0xDD:
DDInstructionTable[_currentInstruction](); break;
case 0xFD:
FDInstructionTable[_currentInstruction](); break;
case 0xED:
EDInstructionTable[_currentInstruction](); break;
case 0xCB:
CBInstructionTable[_currentInstruction](); break;

default:
instructionTable[_currentInstruction](); break;
}
private readonly Action[] instructionTable = new Action[256];

// in ctor, for example:
instructionTable[0x48] = () => LD_R_R(C, B); // LD C, B
instructionTable[0x49] = () => LD_R_R(C, C); // LD C, C
instructionTable[0x4A] = () => LD_R_R(C, D); // LD C, D

private void LD_R_R(byte dest, byte source)
{
Registers.RegisterSet[dest] = Registers.RegisterSet[source];
LogInstructionExec($"0x{_currentInstruction:X2}: LD {Registers.RegisterName(dest)}, {Registers.RegisterName(source)}:0x{Registers.RegisterSet[source]:X2}");
}

// calling:
_currentInstruction = Fetch();
switch (_currentInstruction)
{
case 0xDD:
DDInstructionTable[_currentInstruction](); break;
case 0xFD:
FDInstructionTable[_currentInstruction](); break;
case 0xED:
EDInstructionTable[_currentInstruction](); break;
case 0xCB:
CBInstructionTable[_currentInstruction](); break;

default:
instructionTable[_currentInstruction](); break;
}
This is nice because it's very reusable, but, lambda indirection to convert the LD_R_R(C, B) into an anonymous call takes time. In this case, it seems like lambdas are pretty slow. How should I go about optimizing this while still keeping it reusable?
17 replies
CC#
Created by Pdawg on 6/22/2024 in #help
Which is faster - a type LUT or a switch?
No description
75 replies
CC#
Created by Pdawg on 3/31/2024 in #help
✅ Consuming external .winmd file in Cs/WinRT
Hello! I have a winmd file from a GitHub repo that contains some extra metadata in Windows.UI.Xaml.Hosting. How can I make Cs/WinRT consume it for use in my program? I got C++/WinRT to do it, but I'm not sure how to do it in Cs/WinRT.
2 replies
CC#
Created by Pdawg on 3/28/2024 in #help
Forcefully unloading AssemblyLoadContext
No description
22 replies
CC#
Created by Pdawg on 2/13/2024 in #help
Plugin system not casting properly
I'm trying to make a plugin system for my app, which does this:
public void LoadAndRunPlugins()
{
foreach (string dllFile in Directory.GetFiles(pluginDirectory, "*.dll"))
{
try
{
Assembly assembly = pluginLoadContext.LoadFromAssemblyPath(Path.GetFullPath(dllFile));

foreach (Type type in assembly.GetTypes().Where(asm => !asm.FullName.Contains("GyroShell.Library")))
{
if (type.GetInterface("IPlugin") != null)
{
IPlugin plugin = Activator.CreateInstance(type) as IPlugin;
plugin.Initialize();
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"[-] PluginManager: Error loading and running plugin from {dllFile}: {ex.Message}");
}
}
}
public void LoadAndRunPlugins()
{
foreach (string dllFile in Directory.GetFiles(pluginDirectory, "*.dll"))
{
try
{
Assembly assembly = pluginLoadContext.LoadFromAssemblyPath(Path.GetFullPath(dllFile));

foreach (Type type in assembly.GetTypes().Where(asm => !asm.FullName.Contains("GyroShell.Library")))
{
if (type.GetInterface("IPlugin") != null)
{
IPlugin plugin = Activator.CreateInstance(type) as IPlugin;
plugin.Initialize();
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"[-] PluginManager: Error loading and running plugin from {dllFile}: {ex.Message}");
}
}
}
The IPlugin instance is null, so calling plugin.Initialize() throws an NRE. The thing is, it should work just fine, given my plugin code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GyroShell.Library.Interfaces;

namespace TestGyroShellModule
{
public class PluginRoot : IPlugin
{
//public IPluginInfo PluginInformation => new PluginInfo();

public void Initialize()
{
Debug.WriteLine("We're alive from test plugin!");
}

public void Shutdown()
{
// Shutdown logic
}

/*private class PluginInfo : IPluginInfo
{
public string Name => "Test GyroShell Plugin";
}*/
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GyroShell.Library.Interfaces;

namespace TestGyroShellModule
{
public class PluginRoot : IPlugin
{
//public IPluginInfo PluginInformation => new PluginInfo();

public void Initialize()
{
Debug.WriteLine("We're alive from test plugin!");
}

public void Shutdown()
{
// Shutdown logic
}

/*private class PluginInfo : IPluginInfo
{
public string Name => "Test GyroShell Plugin";
}*/
}
}
And yes, they both reference the same exact interface, defined in GyroShell.Library.Interfaces. Lastly, I've tried debugging this and nothing should go wrong. It tries to cast the PluginRoot class to an IPlugin, which should work since it properly implements the interface, but it just fails. No exceptions are thrown.
58 replies
CC#
Created by Pdawg on 1/18/2023 in #help
✅ How do I move a Window in WinUI 3 C#?
5 replies
CC#
Created by Pdawg on 12/9/2022 in #help
❔ Set item to null inside a list
Hey! I am trying to remove some items from a JSON object (created like var model = new ObjectModel{}). Inside of the object model is a Pages<PagesResource> list, and inside of that is the IconBindings object. I need to be able to set it to null. It’s hard to explain, so here’s the source code (and there is a comment on what I need to do): https://github.com/Pdawg-bytes/webtile-json-serializer
3 replies
CC#
Created by Pdawg on 11/28/2022 in #help
❔ Adding logic into a JSON serializer
Hey everyone! I need to add logic into a json object, but I can't add any code in there or else it'll break. Here is what I mean: If I have a Dictionary named Icons, I need to say foreach item selected from the filepicker, create a new keypair in the Dictionary. Basically, the user selects a few .png files, the code needs to copy them to a folder and add those names to the dictionary. Here is my current code that is a static dictionary:
private async void SerializeJSON()
{
var model = new ObjectModel
{
ManifestVersion = 1,
Name = TileTitle,
Description = DescriptionTile,
Version = 1,
VersionString = "1",
Author = AuthorTile,
Organization = OrgTile,
ContactEmail = TileEmail,
TileIcon = new Dictionary<int, string>
{
[46] = "icons/tileIcon.png"
},
BadgeIcon = new Dictionary<int, string>
{
[24] = "icons/badgeIcon.png"
},
Icons = new Dictionary<string, string>
{
["iconTest"] = "newIcon1.png" // I need to add more items here when needed, based on what is pulled from the filepicker
},
};
}
private async void SerializeJSON()
{
var model = new ObjectModel
{
ManifestVersion = 1,
Name = TileTitle,
Description = DescriptionTile,
Version = 1,
VersionString = "1",
Author = AuthorTile,
Organization = OrgTile,
ContactEmail = TileEmail,
TileIcon = new Dictionary<int, string>
{
[46] = "icons/tileIcon.png"
},
BadgeIcon = new Dictionary<int, string>
{
[24] = "icons/badgeIcon.png"
},
Icons = new Dictionary<string, string>
{
["iconTest"] = "newIcon1.png" // I need to add more items here when needed, based on what is pulled from the filepicker
},
};
}
11 replies
CC#
Created by Pdawg on 11/21/2022 in #help
❔ How can I access a member of a different class in a dictionary
Hey! I'm trying to refactor my old JSON serializer code, but I ran into an issue. I can't access a string in another class named RssTitle. In this Content property, there are 3 different strings that I need to access, RssTitle, RssDesc, and RssPubDate. When I use a dictionary like this:
Resources = new List<WebTileResource>
{
new WebTileResource
{
Url = ResourceURL,
Style = ResourceType,
Content = new Dictionary<ContentList, string>
{

}
}
}
Resources = new List<WebTileResource>
{
new WebTileResource
{
Url = ResourceURL,
Style = ResourceType,
Content = new Dictionary<ContentList, string>
{

}
}
}
It can't access those 3 strings, and just says that RssTitle does not exist in the current context. Here is the data model behind this code
public class WebTileResource
{
public string Url { get; set; }
public string Style { get; set; }
public Dictionary<ContentList, string> Content { get; set; }
}

public class ContentList
{
public string RssTitle { get; set; }
public string RssDesc { get; set; }
public string RssPubDate { get; set; }
}
public class WebTileResource
{
public string Url { get; set; }
public string Style { get; set; }
public Dictionary<ContentList, string> Content { get; set; }
}

public class ContentList
{
public string RssTitle { get; set; }
public string RssDesc { get; set; }
public string RssPubDate { get; set; }
}
If I use a List, like this: public List<ContentList> Content { get; set; }, it creates an array in the serialized JSON. I need it to not be an array. Here's what the final JSON looks like:
"resources": [
{
"url": "some_rss_feed",
"style": "Simple",
"content": [{
"rssTitle": "Add any variables that you need here",
"rssDesc": "Add any variables that you need here",
"rssPubDate": "You can pull any of the data attributes from a selected data source!"
}]
}
],
"resources": [
{
"url": "some_rss_feed",
"style": "Simple",
"content": [{
"rssTitle": "Add any variables that you need here",
"rssDesc": "Add any variables that you need here",
"rssPubDate": "You can pull any of the data attributes from a selected data source!"
}]
}
],
I need it to look like this:
"resources": [
{
"url": "some_rss_feed",
"style": "Simple",
"content": {
"rssTitle": "Add any variables that you need here",
"rssDesc": "Add any variables that you need here",
"rssPubDate": "You can pull any of the data attributes from a selected data source!"
}
}
],
"resources": [
{
"url": "some_rss_feed",
"style": "Simple",
"content": {
"rssTitle": "Add any variables that you need here",
"rssDesc": "Add any variables that you need here",
"rssPubDate": "You can pull any of the data attributes from a selected data source!"
}
}
],
6 replies
CC#
Created by Pdawg on 11/17/2022 in #help
❔ Delete lines from a text file in UWP
2 replies
CC#
Created by Pdawg on 11/12/2022 in #help
Create JSON object with numbers as names
3 replies
CC#
Created by Pdawg on 11/10/2022 in #help
JSON Array to build a complex object isn't letting me create multiple different properties inside it
Hi! I'm having an issue serializing a JSON object to create a Microsoft Band WebTile. Here is my code, and then the issue I'm having
11 replies
CC#
Created by Pdawg on 10/24/2022 in #help
Calling a function from a string.
166 replies