mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 12:30:32 +00:00
161 lines
4.7 KiB
C#
161 lines
4.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
|
|
namespace Cosmos.Assembler {
|
|
public class ElementReference {
|
|
public static ElementReference New(string aName, int aOffset)
|
|
{
|
|
ElementReference xResult;
|
|
if (aName.StartsWith("."))
|
|
{
|
|
aName = Label.LastFullLabel + aName;
|
|
}
|
|
|
|
if (aOffset == 0)
|
|
{
|
|
xResult = new ElementReference(aName);
|
|
}
|
|
else
|
|
{
|
|
xResult = new ElementReference(aName, aOffset);
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
|
|
public static ElementReference New(string aName) {
|
|
return New(aName, 0);
|
|
}
|
|
|
|
private ElementReference(string aName, int aOffset)
|
|
: this(aName) {
|
|
Offset = aOffset;
|
|
}
|
|
|
|
private ElementReference(string aName) {
|
|
if (String.IsNullOrEmpty(aName)) {
|
|
throw new ArgumentNullException("aName");
|
|
}
|
|
if (aName == "00h") {
|
|
Console.Write("");
|
|
}
|
|
if (aName.StartsWith(".")) {
|
|
Name = Label.LastFullLabel + aName;
|
|
} else {
|
|
Name = aName;
|
|
}
|
|
}
|
|
|
|
private ulong? mActualAddress;
|
|
|
|
private static ReaderWriterLockSlim mCacheLocker = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
|
|
private static Dictionary<string, BaseAssemblerElement> mCache;// = new SortedList<string, BaseAssemblerElement>(StringComparer.InvariantCultureIgnoreCase);
|
|
private static int? mThreadId = null;
|
|
|
|
private static BaseAssemblerElement DoResolve(Cosmos.Assembler.Assembler aAssembler, string aName) {
|
|
if (!mThreadId.HasValue) {
|
|
mThreadId = Thread.CurrentThread.ManagedThreadId;
|
|
} else {
|
|
if (mThreadId.Value != Thread.CurrentThread.ManagedThreadId) {
|
|
throw new Exception("Called from multiple threads");
|
|
}
|
|
}
|
|
mCacheLocker.EnterReadLock();
|
|
try {
|
|
if (mCache != null) {
|
|
BaseAssemblerElement xTempResult;
|
|
if (mCache.TryGetValue(aName, out xTempResult)) {
|
|
return xTempResult;
|
|
}
|
|
}
|
|
} finally {
|
|
mCacheLocker.ExitReadLock();
|
|
}
|
|
mCacheLocker.EnterWriteLock();
|
|
try {
|
|
if (mCache == null) {
|
|
mCache = new Dictionary<string, BaseAssemblerElement>(StringComparer.InvariantCultureIgnoreCase);
|
|
int xMax = aAssembler.AllAssemblerElementCount;
|
|
for (int i = 0; i < xMax; i++) {
|
|
var xInstruction = aAssembler.GetAssemblerElement(i);
|
|
var xLabel = xInstruction as Label;
|
|
if (xLabel != null) {
|
|
mCache.Add(xLabel.QualifiedName, xLabel);
|
|
}
|
|
var xDataMember = xInstruction as DataMember;
|
|
if (xDataMember != null) {
|
|
if (mCache.ContainsKey(xDataMember.Name)) {
|
|
Console.Write("");
|
|
}
|
|
mCache.Add(xDataMember.Name, xDataMember);
|
|
}
|
|
}
|
|
}
|
|
BaseAssemblerElement xTempResult;
|
|
if (mCache.TryGetValue(aName, out xTempResult)) {
|
|
return xTempResult;
|
|
}
|
|
throw new Exception("Cannot resolve ElementReference to '" + aName + "'!");
|
|
//foreach(var xInstruction in aAssembler.Instructions ) {
|
|
// var xLabel = xInstruction as Label;
|
|
// if(xLabel!=null) {
|
|
// if(aName.Equals(xLabel.Name, StringComparison.InvariantCultureIgnoreCase)) {
|
|
// xTempResult = xLabel;
|
|
// break;
|
|
// }
|
|
// }
|
|
//}
|
|
//if (xTempResult == null) {
|
|
// foreach (var xDataMember in aAssembler.DataMembers) {
|
|
// if (aName.Equals(xDataMember.Name, StringComparison.InvariantCultureIgnoreCase)) {
|
|
// xTempResult = xDataMember;
|
|
// break;
|
|
// }
|
|
// }
|
|
//}
|
|
} finally {
|
|
mCacheLocker.ExitWriteLock();
|
|
}
|
|
}
|
|
|
|
public bool Resolve(Cosmos.Assembler.Assembler aAssembler, out ulong aAddress) {
|
|
//
|
|
if (mActualAddress != null) {
|
|
aAddress = mActualAddress.Value;
|
|
return true;
|
|
}
|
|
var xElement = DoResolve(aAssembler, Name);
|
|
if (xElement != null) {
|
|
if (xElement.ActualAddress.HasValue) {
|
|
mActualAddress = (ulong)((long)xElement.ActualAddress.Value + Offset);
|
|
aAddress = mActualAddress.Value;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
aAddress = 0;
|
|
return false;
|
|
}
|
|
|
|
public int Offset {
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public string Name {
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public override string ToString() {
|
|
if (Offset != 0) {
|
|
return Name + " + " + Offset;
|
|
} else {
|
|
return Name;
|
|
}
|
|
}
|
|
}
|
|
}
|