Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
312 changes: 312 additions & 0 deletions .github/prompts/plan-protectedMode.prompt.md

Large diffs are not rendered by default.

246 changes: 246 additions & 0 deletions .github/prompts/plan-xmsEmsUnification.prompt.md

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions src/Spice86.Core/CLI/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@ public sealed class Configuration : CommandSettings {
[CommandOption("--A20Gate")]
public bool A20Gate { get; init; }

/// <summary>
/// Total RAM size, in KB, from physical address 0. Backs conventional memory, the HMA, and the
/// unified extended-memory pool shared by XMS and EMS. Default is 16MB (16384), can be raised up
/// to 64MB (65536) for demanding DOS extenders.
/// </summary>
[CommandOption("--RamSizeKb <RAMSIZEKB>")]
[DefaultValue(RamSizeDefaultKb)]
public int RamSizeKb { get; init; } = RamSizeDefaultKb;

/// <summary>Default value for <see cref="RamSizeKb"/>: 16MB.</summary>
public const int RamSizeDefaultKb = 16 * 1024;

/// <summary>Maximum allowed value for <see cref="RamSizeKb"/>: 64MB.</summary>
public const int RamSizeMaxKb = 64 * 1024;

/// <summary>
/// Gets if the program will be paused on start and stop. If <see cref="GdbPort"/> is set, the program will be paused anyway.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public DataType UType(BitWidth bitWidth) {
return DataType.UnsignedFromBitWidth(bitWidth);
}

public DataType AddressType(CfgInstruction instruction) {
return instruction.AddressSize32Prefix == null ? DataType.UINT16 : DataType.UINT32;
public DataType AddressType(BitWidth addressWidthFromPrefixes) {
return UType(addressWidthFromPrefixes);
}

/// <summary>
Expand Down
28 changes: 11 additions & 17 deletions src/Spice86.Core/Emulator/CPU/CfgCpu/Ast/Builder/StackAstBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace Spice86.Core.Emulator.CPU.CfgCpu.Ast.Builder;

using System.Collections.Generic;

using Spice86.Core.Emulator.CPU;
using Spice86.Core.Emulator.CPU.CfgCpu.Ast.Instruction;
using Spice86.Core.Emulator.CPU.CfgCpu.Ast.Operations;
Expand Down Expand Up @@ -43,19 +44,12 @@ public MethodCallValueNode Peek(BitWidth bitWidth) {
}

/// <summary>
/// Creates an AST node for 32-bit LEAVE stack semantics.
/// </summary>
/// <returns>MethodCallNode representing 32-bit LEAVE.</returns>
public MethodCallNode Leave32() {
return new MethodCallNode("Stack", nameof(Stack.Leave32));
}

/// <summary>
/// Creates an AST node for 16-bit LEAVE stack semantics.
/// Creates an AST node for LEAVE stack semantics.
/// </summary>
/// <returns>MethodCallNode representing 16-bit LEAVE.</returns>
public MethodCallNode Leave16() {
return new MethodCallNode("Stack", nameof(Stack.Leave16));
/// <param name="operandSize32Node">Constant node for whether the operand size is 32-bit.</param>
/// <returns>MethodCallNode representing Stack.Leave(operandSize32).</returns>
public MethodCallNode Leave(ValueNode operandSize32Node) {
return new MethodCallNode("Stack", nameof(Stack.Leave), operandSize32Node);
}

/// <summary>
Expand Down Expand Up @@ -103,12 +97,12 @@ public void PopValues(List<IVisitableAstNode> statements, DataType dataType, par

/// <summary>
/// Dispatcher method for LEAVE stack semantics based on bit width.
/// For 16-bit, calls Leave16.
/// For 32-bit, calls Leave32.
/// Builds a call to <see cref="Stack.Leave"/>, passing the operand size as a constant.
/// </summary>
/// <param name="bitWidth">The bit width determining which LEAVE to use</param>
/// <returns>MethodCallNode representing the appropriate Stack.LeaveN method</returns>
/// <param name="bitWidth">The bit width determining the LEAVE operand size.</param>
/// <returns>MethodCallNode representing Stack.Leave(operandSize32).</returns>
public MethodCallNode Leave(BitWidth bitWidth) {
return bitWidth == BitWidth.DWORD_32 ? Leave32() : Leave16();
return Leave(new ConstantNode(DataType.BOOL, bitWidth == BitWidth.DWORD_32 ? 1UL : 0UL));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public enum InstructionOperation {
ADC,
ADD,
AND,
ARPL,
BOUND,
BSF,
BSR,
Expand Down Expand Up @@ -91,18 +92,25 @@ public enum InstructionOperation {
JMP_NEAR,
JMP_SHORT,
LAHF,
LAR,
LDS,
LEA,
LEAVE,
LEAVEW,
LES,
LFS,
LGDT,
LGS,
LIDT,
LLDT,
LMSW,
LODS,
LOOP,
LOOPE,
LOOPNE,
LSL,
LSS,
LTR,
MOV,
MOVS,
MOVSX,
Expand Down Expand Up @@ -152,16 +160,23 @@ public enum InstructionOperation {
SETO,
SETP,
SETS,
SGDT,
SHL,
SHLD,
SHRD,
SHR,
SIDT,
SLDT,
SMSW,
STC,
STD,
STI,
STOS,
STR,
SUB,
TEST,
VERR,
VERW,
XADD,
XCHG,
XLAT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ private UnaryExpression ToExpression(UnaryOperation unaryOperation, Expression v
_ => throw new InvalidOperationException($"Unhandled Operation: {unaryOperation}")
};
}

private T EnsureNonNull<T>(T? argument) {
ArgumentNullException.ThrowIfNull(argument);
return argument;
Expand Down Expand Up @@ -193,7 +193,7 @@ private Type ToMemoryIndexerType(DataType dataType) {
private PropertyInfo FindSingleParameterIndexer(Type type) {
return EnsureNonNull(type.GetProperty("Item", [typeof(uint)]));
}

private PropertyInfo FindSegmentedIndexer(Type type) {
return EnsureNonNull(type.GetProperty("Item", [typeof(ushort), typeof(uint), typeof(SegmentAccessKind)]));
}
Expand All @@ -209,7 +209,7 @@ private IndexExpression ToMemoryIndexer(DataType dataType, Expression indexExpre
PropertyInfo indexer = FindSingleParameterIndexer(ToMemoryIndexerType(dataType));
return Expression.Property(indexerProperty, indexer, indexExpression);
}

private IndexExpression ToMemoryIndexer(DataType dataType, Expression segmentExpression, Expression offsetExpression, bool isStackSegment) {
if (segmentExpression.Type != typeof(ushort)) {
segmentExpression = Expression.Convert(segmentExpression, typeof(ushort));
Expand All @@ -222,15 +222,15 @@ private IndexExpression ToMemoryIndexer(DataType dataType, Expression segmentExp
SegmentAccessKind accessKind = isStackSegment ? SegmentAccessKind.Stack : SegmentAccessKind.Data;
return Expression.Property(indexerProperty, indexer, segmentExpression, offsetExpression, Expression.Constant(accessKind));
}

private MemberExpression ToRegisterProperty(int registerIndex, DataType dataType, bool isSegmentRegister) {
string name = isSegmentRegister ? _registerRenderer.ToStringSegmentRegister(registerIndex) : _registerRenderer.ToStringRegister(dataType.BitWidth, registerIndex);
PropertyInfo stateRegisterProperty = EnsureNonNull(typeof(State).GetProperty(name));
return Expression.Property(_stateParameter, stateRegisterProperty);
}

public Expression VisitSegmentRegisterNode(SegmentRegisterNode node) {
return ToRegisterProperty(node.RegisterIndex, node.DataType, true);
return ToRegisterProperty(node.RegisterIndex, node.DataType, true);
}

public Expression VisitSegmentedPointer(SegmentedPointerNode node) {
Expand Down Expand Up @@ -279,10 +279,10 @@ public Expression VisitFlagRegisterNode(FlagRegisterNode node) {
Expression flagsObject = Expression.Property(_stateParameter, flagsProperty);

// Select the appropriate property based on the DataType
string propertyName = node.DataType.BitWidth == BitWidth.WORD_16
? nameof(Flags.FlagRegister16)
string propertyName = node.DataType.BitWidth == BitWidth.WORD_16
? nameof(Flags.FlagRegister16)
: nameof(Flags.FlagRegister);

PropertyInfo flagRegisterProperty = EnsureNonNull(typeof(Flags).GetProperty(propertyName));
return Expression.Property(flagsObject, flagRegisterProperty);
}
Expand All @@ -299,24 +299,24 @@ public Expression VisitSegmentedAddressNode(SegmentedAddressNode node) {
ConstructorInfo constructorInfo = EnsureNonNull(typeof(SegmentedAddress).GetConstructor([typeof(ushort), typeof(ushort)]));
return Expression.New(constructorInfo, segment, offset);
}

public Expression VisitBinaryOperationNode(BinaryOperationNode node) {
Expression left = node.Left.Accept(this);
Expression right = node.Right.Accept(this);
return ToExpression(node.BinaryOperation, left, right, node.DataType);
}

public Expression VisitUnaryOperationNode(UnaryOperationNode node) {
Expression value = node.Value.Accept(this);
return ToExpression(node.UnaryOperation, value);
}

public Expression VisitTypeConversionNode(TypeConversionNode node) {
Expression value = node.Value.Accept(this);
Type targetType = FromDataType(node.DataType);
return Expression.Convert(value, targetType);
}

public Expression VisitInstructionNode(InstructionNode node) {
throw new InvalidOperationException(
$"InstructionNode is for assembly parsing and rendering, not execution. " +
Expand All @@ -343,7 +343,7 @@ private static object ToConstantValue(ConstantNode node) {
_ => throw new UnsupportedBitWidthException(node.DataType.BitWidth)
};
}

public Expression VisitNearAddressNode(NearAddressNode node) {
return VisitConstantNode(node);
}
Expand All @@ -356,19 +356,19 @@ public Expression VisitMethodCallValueNode(MethodCallValueNode node) {
public Expression<Action<State, Memory>> ToAction(Expression expression) {
return Expression.Lambda<Action<State, Memory>>(expression, _allParameters);
}

public Expression<Func<State, Memory, byte>> ToFuncUInt8(Expression expression) {
return Expression.Lambda<Func<State, Memory, byte>>(expression, _allParameters);
}

public Expression<Func<State, Memory, sbyte>> ToFuncInt8(Expression expression) {
return Expression.Lambda<Func<State, Memory, sbyte>>(expression, _allParameters);
}

public Expression<Func<State, Memory, ushort>> ToFuncUInt16(Expression expression) {
return Expression.Lambda<Func<State, Memory, ushort>>(expression, _allParameters);
}

public Expression<Func<State, Memory, short>> ToFuncInt16(Expression expression) {
return Expression.Lambda<Func<State, Memory, short>>(expression, _allParameters);
}
Expand All @@ -377,11 +377,11 @@ public Expression<Func<State, Memory, uint>> ToFuncUInt32(Expression expression)
Expression converted = Expression.Convert(expression, typeof(uint));
return Expression.Lambda<Func<State, Memory, uint>>(converted, _allParameters);
}

public Expression<Func<State, Memory, int>> ToFuncInt32(Expression expression) {
return Expression.Lambda<Func<State, Memory, int>>(expression, _allParameters);
}

public Expression<Func<State, Memory, bool>> ToFuncBool(Expression expression) {
return Expression.Lambda<Func<State, Memory, bool>>(expression, _allParameters);
}
Expand Down Expand Up @@ -553,15 +553,16 @@ public Expression VisitMoveIpNextNode(MoveIpNextNode node) {
csExpression,
nextIpAsUint,
Expression.Constant(1u),
Expression.Constant(SegmentAccessKind.Data));
Expression.Constant(SegmentAccessKind.Data),
Expression.Constant(false));

return Expression.Block(assignIp, checkAccess);
}

public Expression VisitCallNearNode(CallNearNode node) {
// helper.NearCallWithReturnIpNextInstructionXX(instruction, targetIp)
string methodName = node.CallBitWidth == BitWidth.WORD_16
? nameof(InstructionExecutionHelper.NearCallWithReturnIpNextInstruction16)
string methodName = node.CallBitWidth == BitWidth.WORD_16
? nameof(InstructionExecutionHelper.NearCallWithReturnIpNextInstruction16)
: nameof(InstructionExecutionHelper.NearCallWithReturnIpNextInstruction32);

return CallHelperMethodWithInstruction(methodName, node,
Expand All @@ -571,8 +572,8 @@ public Expression VisitCallNearNode(CallNearNode node) {
public Expression VisitCallFarNode(CallFarNode node) {
Expression targetAddress = node.TargetAddress.Accept(this);

string methodName = node.CallBitWidth == BitWidth.WORD_16
? nameof(InstructionExecutionHelper.FarCallWithReturnIpNextInstruction16)
string methodName = node.CallBitWidth == BitWidth.WORD_16
? nameof(InstructionExecutionHelper.FarCallWithReturnIpNextInstruction16)
: nameof(InstructionExecutionHelper.FarCallWithReturnIpNextInstruction32);

return CallHelperMethodWithInstruction(methodName, node,
Expand All @@ -583,7 +584,7 @@ public Expression VisitReturnNearNode(ReturnNearNode node) {
string methodName = node.RetBitWidth == BitWidth.WORD_16
? nameof(InstructionExecutionHelper.HandleNearRet16)
: nameof(InstructionExecutionHelper.HandleNearRet32);

return CallHelperMethodWithInstruction(methodName, node,
node.BytesToPop.Accept(this));
}
Expand All @@ -592,7 +593,7 @@ public Expression VisitReturnFarNode(ReturnFarNode node) {
string methodName = node.RetBitWidth == BitWidth.WORD_16
? nameof(InstructionExecutionHelper.HandleFarRet16)
: nameof(InstructionExecutionHelper.HandleFarRet32);

return CallHelperMethodWithInstruction(methodName, node,
node.BytesToPop.Accept(this));
}
Expand All @@ -601,7 +602,7 @@ public Expression VisitJumpNearNode(JumpNearNode node) {
return CallHelperMethodWithInstruction(nameof(InstructionExecutionHelper.JumpNear), node,
node.Ip.Accept(this));
}

public Expression VisitJumpFarNode(JumpFarNode node) {
return CallHelperMethodWithInstruction(nameof(InstructionExecutionHelper.JumpFar), node,
node.TargetAddress.Segment.Accept(this),
Expand Down Expand Up @@ -647,7 +648,7 @@ private Expression CallHelperMethodWithInstruction(string methodName, CfgInstruc
Expression[] allArgs = new Expression[args.Length + 1];
allArgs[0] = Expression.Constant(node.Instruction, node.Instruction.GetType());
Array.Copy(args, 0, allArgs, 1, args.Length);

return CallHelperMethod(methodName, allArgs);
}

Expand All @@ -659,16 +660,16 @@ private Expression CallHelperMethod(string methodName, params Expression[] argum
if (method == null) {
method = typeof(InstructionExecutionHelper).GetMethods()
.FirstOrDefault(m => m.Name == methodName && m.GetParameters().Length == arguments.Length);

if (method != null && method.IsGenericMethodDefinition) {
method = method.MakeGenericMethod(arguments[0].Type);
method = method.MakeGenericMethod(arguments[0].Type);
}
}

if (method == null) {
throw new InvalidOperationException($"Method {methodName} not found on InstructionExecutionHelper with {arguments.Length} arguments");
throw new InvalidOperationException($"Method {methodName} not found on InstructionExecutionHelper with {arguments.Length} arguments");
}

return Expression.Call(_helperParameter, method, arguments);
}

Expand Down
Loading
Loading