This commit is contained in:
kudzu_cp 2012-07-09 02:51:58 +00:00
parent 3f8e4f22be
commit 5a2f9cdff0
12 changed files with 473 additions and 32 deletions

View file

@ -74,7 +74,7 @@ namespace Cosmos.Build.Builder {
// VS doesnt exit right away and user can try devkit again after VS window has closed but is still running.
// So we wait a few seconds first.
if (WaitForExit("devenv", 3000)) {
if (WaitForExit("devenv", 5000)) {
throw new Exception("Visual Studio is running. Please close it or kill it in task manager.");
}
}

View file

@ -0,0 +1,88 @@
using System;
using System.Linq;
using Cosmos.Assembler;
using Cosmos.Assembler.x86;
namespace Cosmos.Debug.DebugStub {
public class CmdAsmBreak : Cosmos.Assembler.Code {
public CmdAsmBreak(Assembler.Assembler aAssembler) : base(aAssembler) {}
public override void Assemble() {
new Comment("X#: Group DebugStub");
new Comment("Location where INT3 has been injected.");
new Comment("0 if no INT3 is active.");
new Comment("X#: var AsmBreakEIP");
mAssembler.DataMembers.Add(new DataMember("DebugStub_AsmBreakEIP", 0));
new Comment("Old byte before INT3 was injected.");
new Comment("Only 1 byte is used.");
new Comment("X#: var AsmOrigByte");
mAssembler.DataMembers.Add(new DataMember("DebugStub_AsmOrigByte", 0));
new Comment("X#: procedure SetAsmBreak {");
new Label("DebugStub_SetAsmBreak");
new Comment("X#: ComReadEAX()");
new Call { DestinationLabel = "DebugStub_ComReadEAX" };
new Comment("X#: EDI = EAX");
new Mov{ DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.EAX };
new Comment("Save the old byte");
new Comment("X#: EAX = EDI[0]");
new Mov{ DestinationReg = RegistersEnum.EAX, SourceReg = RegistersEnum.EDI, SourceIsIndirect = true, SourceDisplacement = 0 };
new Comment("X#: .AsmOrigByte = EAX");
new Mov { DestinationRef = Cosmos.Assembler.ElementReference.New("DebugStub_AsmOrigByte"), DestinationIsIndirect = true , SourceReg = RegistersEnum.EAX };
new Comment("Inject INT3");
new Comment("X#: EDI[0] = $CC");
new Mov{ DestinationReg = RegistersEnum.EDI, DestinationIsIndirect = true, DestinationDisplacement = 0, SourceValue = 0xCC };
new Comment("Save EIP of the break");
new Comment("X#: .AsmBreakEIP = EDI");
new Mov { DestinationRef = Cosmos.Assembler.ElementReference.New("DebugStub_AsmBreakEIP"), DestinationIsIndirect = true , SourceReg = RegistersEnum.EDI };
new Comment("X#: }");
new Label("DebugStub_SetAsmBreak_Exit");
new Return();
new Comment("X#: procedure ClearAsmBreak {");
new Label("DebugStub_ClearAsmBreak");
new Comment("X#: EDI = .AsmBreakEIP");
new Mov { DestinationReg = RegistersEnum.EDI , SourceRef = Cosmos.Assembler.ElementReference.New("DebugStub_AsmBreakEIP"), SourceIsIndirect = true };
new Comment("If 0, we don't need to clear an older one.");
new Comment("X#: if EDI = 0 exit");
new Compare { DestinationReg = RegistersEnum.EDI, SourceValue = 0 };
new ConditionalJump { Condition = ConditionalTestEnum.Zero, DestinationLabel = "DebugStub_ClearAsmBreak_Exit" };
new Comment("Clear old break point and set back to original opcode / partial opcode");
new Comment("X#: EAX = .AsmOrigByte");
new Mov { DestinationReg = RegistersEnum.EAX , SourceRef = Cosmos.Assembler.ElementReference.New("DebugStub_AsmOrigByte"), SourceIsIndirect = true };
new Comment("X#: EDI[0] = EAX");
new Mov{ DestinationReg = RegistersEnum.EDI, DestinationIsIndirect = true, DestinationDisplacement = 0, SourceReg = RegistersEnum.EAX };
new Comment("X#: .AsmOrigByte = 0");
new Mov { DestinationRef = Cosmos.Assembler.ElementReference.New("DebugStub_AsmOrigByte"), DestinationIsIndirect = true , SourceValue = 0 };
new Comment("X#: }");
new Label("DebugStub_ClearAsmBreak_Exit");
new Return();
}
}
}

View file

@ -23,7 +23,7 @@ procedure SetAsmBreak {
procedure ClearAsmBreak {
EDI = .AsmBreakEIP
# If 0, we don't need to clear an older one.
If (EDI = 0) exit
if EDI = 0 exit
# Clear old break point and set back to original opcode / partial opcode
EAX = .AsmOrigByte

View file

@ -0,0 +1,92 @@
using System;
using System.Linq;
using Cosmos.Assembler;
using Cosmos.Assembler.x86;
namespace Cosmos.Debug.DebugStub {
public class CmdProcess : Cosmos.Assembler.Code {
public CmdProcess(Assembler.Assembler aAssembler) : base(aAssembler) {}
public override void Assemble() {
new Comment("X#: Group DebugStub");
new Comment("test when emitted after usage too");
new Comment("X#: ! DebugStub_DsVsip_CmdCompleted equ 9");
new LiteralAssemblerCode("DebugStub_DsVsip_CmdCompleted equ 9");
new Comment("X#: procedure AckCommand {");
new Label("DebugStub_AckCommand");
new Comment("We acknowledge receipt of the command AND the processing of it.");
new Comment("-In the past the ACK only acknowledged receipt.");
new Comment("We have to do this because sometimes callers do more processing.");
new Comment("We ACK even ones we dont process here, but do not ACK Noop.");
new Comment("The buffers should be ok because more wont be sent till after our NACK");
new Comment("is received.");
new Comment("Right now our max cmd size is 2 (Cmd + Cmd ID) + 5 (Data) = 7.");
new Comment("UART buffer is 16.");
new Comment("We may need to revisit this in the future to ack not commands, but data chunks");
new Comment("and move them to a buffer.");
new Comment("The buffer problem exists only to inbound data, not outbound data (relative to DebugStub).");
new Comment("DsVsip.CmdCompleted");
new Comment("X#: AL = @.DsVsip_CmdCompleted");
new Mov { DestinationReg = RegistersEnum.AL , SourceRef = Cosmos.Assembler.ElementReference.New("DebugStub_DsVsip_CmdCompleted") };
new Comment("AL = 9");
new Comment("X#: ComWriteAL()");
new Call { DestinationLabel = "DebugStub_ComWriteAL" };
new Comment("X#: EAX = .CommandID");
new Mov { DestinationReg = RegistersEnum.EAX , SourceRef = Cosmos.Assembler.ElementReference.New("DebugStub_CommandID"), SourceIsIndirect = true };
new Comment("X#: ComWriteAL()");
new Call { DestinationLabel = "DebugStub_ComWriteAL" };
new Comment("X#: }");
new Label("DebugStub_AckCommand_Exit");
new Return();
new Comment("X#: procedure ProcessCommandBatch {");
new Label("DebugStub_ProcessCommandBatch");
new Comment("X#: Begin:");
new Label("DebugStub_ProcessCommandBatch_Begin");
new Comment("X#: ProcessCommand()");
new Call { DestinationLabel = "DebugStub_ProcessCommand" };
new Comment("See if batch is complete");
new Comment("Loop and wait");
new Comment("VsipDs.BatchEnd");
new Comment("X#: if AL != 8 goto Begin");
new Compare { DestinationReg = RegistersEnum.AL, SourceValue = 8 };
new ConditionalJump { Condition = ConditionalTestEnum.NotZero, DestinationLabel = "DebugStub_ProcessCommandBatch_Begin" };
new Comment("X#: AckCommand()");
new Call { DestinationLabel = "DebugStub_AckCommand" };
new Comment("X#: }");
new Label("DebugStub_ProcessCommandBatch_Exit");
new Return();
}
}
}

View file

@ -17,8 +17,7 @@ procedure AckCommand {
# The buffer problem exists only to inbound data, not outbound data (relative to DebugStub).
# DsVsip.CmdCompleted
# ! mov AL, DebugStub_DsVsip_CmdCompleted
#AL = .DsVsip_CmdCompleted
AL = @.DsVsip_CmdCompleted
#AL = 9
ComWriteAL()
@ -33,7 +32,7 @@ Begin:
# See if batch is complete
# Loop and wait
# VsipDs.BatchEnd
if (AL != 8) goto Begin
if AL != 8 goto Begin
AckCommand()
}

View file

@ -84,16 +84,16 @@
<DesignTime>True</DesignTime>
<DependentUpon>CmdSend.xs</DependentUpon>
</Compile>
<Compile Include="Main.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Main.xs</DependentUpon>
</Compile>
<Compile Include="Init.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Init.xs</DependentUpon>
</Compile>
<Compile Include="Main.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Main.xs</DependentUpon>
</Compile>
<Compile Include="Old\Consts.cs" />
<Compile Include="Old\DebugStub.cs" />
<Compile Include="Old\ProcessCmds.cs" />

View file

@ -0,0 +1,150 @@
using System;
using System.Linq;
using Cosmos.Assembler;
using Cosmos.Assembler.x86;
namespace Cosmos.Debug.DebugStub {
public class Init : Cosmos.Assembler.Code {
public Init(Assembler.Assembler aAssembler) : base(aAssembler) {}
public override void Assemble() {
new Comment("X#: Group DebugStub");
new Comment("Todo: Change these to a group level var");
new Comment("X#: var .DebugBPs int[256]");
mAssembler.DataMembers.Add(new DataMember("DebugBPs", new int[256]));
new Comment("X#: var .DebugWaitMsg = 'Waiting for debugger connection...'");
mAssembler.DataMembers.Add(new DataMember("DebugWaitMsg", "Waiting for debugger connection..."));
new Comment("Called before Kernel runs. Inits debug stub, etc");
new Comment("X#: procedure Init {");
new Label("DebugStub_Init");
new Comment("X#: Cls()");
new Call { DestinationLabel = "DebugStub_Cls" };
new Comment("Display message before even trying to init serial");
new Comment("X#: DisplayWaitMsg()");
new Call { DestinationLabel = "DebugStub_DisplayWaitMsg" };
new Comment("X#: InitSerial()");
new Call { DestinationLabel = "DebugStub_InitSerial" };
new Comment("X#: WaitForDbgHandshake()");
new Call { DestinationLabel = "DebugStub_WaitForDbgHandshake" };
new Comment("X#: Cls()");
new Call { DestinationLabel = "DebugStub_Cls" };
new Comment("X#: }");
new Label("DebugStub_Init_Exit");
new Return();
new Comment("X#: procedure WaitForSignature {");
new Label("DebugStub_WaitForSignature");
new Comment("X#: EBX = 0");
new Mov{ DestinationReg = RegistersEnum.EBX, SourceValue = 0 };
new Comment("X#: Read:");
new Label("DebugStub_WaitForSignature_Read");
new Comment("X#: ComReadAL()");
new Call { DestinationLabel = "DebugStub_ComReadAL" };
new Comment("X#: BL = AL");
new Mov{ DestinationReg = RegistersEnum.BL, SourceReg = RegistersEnum.AL };
new Comment("X#: EBX ~> 8");
new LiteralAssemblerCode("ROR EBX, 8");
new Comment("X#: if EBX != $19740807 goto Read");
new Compare { DestinationReg = RegistersEnum.EBX, SourceValue = 0x19740807 };
new ConditionalJump { Condition = ConditionalTestEnum.NotZero, DestinationLabel = "DebugStub_WaitForSignature_Read" };
new Comment("X#: }");
new Label("DebugStub_WaitForSignature_Exit");
new Return();
new Comment("QEMU (and possibly others) send some garbage across the serial line first.");
new Comment("Actually they send the garbage inbound, but garbage could be inbound as well so we");
new Comment("keep this.");
new Comment("To work around this we send a signature. DC then discards everything before the signature.");
new Comment("QEMU has other serial issues too, and we dont support it anymore, but this signature is a good");
new Comment("feature so we kept it.");
new Comment("X#: procedure WaitForDbgHandshake {");
new Label("DebugStub_WaitForDbgHandshake");
new Comment("\"Clear\" the UART out");
new Comment("X#: AL = 0");
new Mov{ DestinationReg = RegistersEnum.AL, SourceValue = 0 };
new Comment("X#: ComWriteAL()");
new Call { DestinationLabel = "DebugStub_ComWriteAL" };
new Comment("Cosmos.Debug.Consts.Consts.SerialSignature");
new Comment("X#: +$19740807");
new Push { DestinationValue = 0x19740807, Size = 32 };
new Comment("X#: ESI = ESP");
new Mov{ DestinationReg = RegistersEnum.ESI, SourceReg = RegistersEnum.ESP };
new Comment("TODO pass a count register");
new Comment("X#: ComWrite8()");
new Call { DestinationLabel = "DebugStub_ComWrite8" };
new Comment("X#: ComWrite8()");
new Call { DestinationLabel = "DebugStub_ComWrite8" };
new Comment("X#: ComWrite8()");
new Call { DestinationLabel = "DebugStub_ComWrite8" };
new Comment("X#: ComWrite8()");
new Call { DestinationLabel = "DebugStub_ComWrite8" };
new Comment("Restore ESP, we actually dont care about EAX or the value on the stack anymore.");
new Comment("X#: -EAX");
new Pop { DestinationReg = RegistersEnum.EAX};
new Comment("We could use the signature as the start signal, but I prefer");
new Comment("to keep the logic separate, especially in DC.");
new Comment("Send the actual started signal");
new Comment("DsVsip.Started = 6");
new Comment("X#: AL = 6");
new Mov{ DestinationReg = RegistersEnum.AL, SourceValue = 6 };
new Comment("X#: ComWriteAL()");
new Call { DestinationLabel = "DebugStub_ComWriteAL" };
new Comment("X#: WaitForSignature()");
new Call { DestinationLabel = "DebugStub_WaitForSignature" };
new Comment("X#: ProcessCommandBatch()");
new Call { DestinationLabel = "DebugStub_ProcessCommandBatch" };
new Comment("X#: }");
new Label("DebugStub_WaitForDbgHandshake_Exit");
new Return();
}
}
}

View file

@ -20,7 +20,7 @@ Read:
ComReadAL()
BL = AL
EBX ~> 8
if (EBX != $19740807) goto Read
if EBX != $19740807 goto Read
}
# QEMU (and possibly others) send some garbage across the serial line first.

View file

@ -0,0 +1,111 @@
using System;
using System.Linq;
using Cosmos.Assembler;
using Cosmos.Assembler.x86;
namespace Cosmos.Debug.DebugStub {
public class Screen : Cosmos.Assembler.Code {
public Screen(Assembler.Assembler aAssembler) : base(aAssembler) {}
public override void Assemble() {
new Comment("X#: Group DebugStub");
new Comment("X#: procedure Cls {");
new Label("DebugStub_Cls");
new Comment("VidBase");
new Comment("X#: ESI = $B8000");
new Mov{ DestinationReg = RegistersEnum.ESI, SourceValue = 0xB8000 };
new Comment("X#: BeginLoop:");
new Label("DebugStub_Cls_BeginLoop");
new Comment("Text");
new Comment("X#: AL = $00");
new Mov{ DestinationReg = RegistersEnum.AL, SourceValue = 0x00 };
new Comment("X#: ESI[0] = AL");
new Mov{ DestinationReg = RegistersEnum.ESI, DestinationIsIndirect = true, DestinationDisplacement = 0, SourceReg = RegistersEnum.AL };
new Comment("X#: ESI++");
new INC { DestinationReg = RegistersEnum.ESI };
new Comment("Colour");
new Comment("X#: AL = $0A");
new Mov{ DestinationReg = RegistersEnum.AL, SourceValue = 0x0A };
new Comment("X#: ESI[0] = AL");
new Mov{ DestinationReg = RegistersEnum.ESI, DestinationIsIndirect = true, DestinationDisplacement = 0, SourceReg = RegistersEnum.AL };
new Comment("X#: ESI++");
new INC { DestinationReg = RegistersEnum.ESI };
new Comment("End of Video Area");
new Comment("VidBase + 25 * 80 * 2 = B8FA0");
new Comment("X#: If ESI < $B8FA0 goto BeginLoop");
new Compare { DestinationReg = RegistersEnum.ESI, SourceValue = 0xB8FA0 };
new ConditionalJump { Condition = ConditionalTestEnum.LessThan, DestinationLabel = "DebugStub_Cls_BeginLoop" };
new Comment("X#: }");
new Label("DebugStub_Cls_Exit");
new Return();
new Comment("X#: procedure DisplayWaitMsg {");
new Label("DebugStub_DisplayWaitMsg");
new Comment("http://wiki.osdev.org/Text_UI");
new Comment("Later can cycle for x changes of second register:");
new Comment("http://wiki.osdev.org/Time_And_Date");
new Comment("X#: ESI = @..DebugWaitMsg");
new Mov { DestinationReg = RegistersEnum.ESI , SourceRef = Cosmos.Assembler.ElementReference.New("DebugWaitMsg") };
new Comment("VidBase");
new Comment("X#: EDI = $B8000");
new Mov{ DestinationReg = RegistersEnum.EDI, SourceValue = 0xB8000 };
new Comment("10 lines down, 20 cols in (10 * 80 + 20) * 2)");
new Comment("X#: EDI + 1640");
new Add { DestinationReg = RegistersEnum.EDI, SourceValue = 1640 };
new Comment("Read and copy string till 0 terminator");
new Comment("X#: ReadChar:");
new Label("DebugStub_DisplayWaitMsg_ReadChar");
new Comment("X#: AL = ESI[0]");
new Mov{ DestinationReg = RegistersEnum.AL, SourceReg = RegistersEnum.ESI, SourceIsIndirect = true, SourceDisplacement = 0 };
new Comment("X#: if AL = 0 exit");
new Compare { DestinationReg = RegistersEnum.AL, SourceValue = 0 };
new ConditionalJump { Condition = ConditionalTestEnum.Zero, DestinationLabel = "DebugStub_DisplayWaitMsg_Exit" };
new Comment("X#: ESI++");
new INC { DestinationReg = RegistersEnum.ESI };
new Comment("X#: EDI[0] = AL");
new Mov{ DestinationReg = RegistersEnum.EDI, DestinationIsIndirect = true, DestinationDisplacement = 0, SourceReg = RegistersEnum.AL };
new Comment("X#: EDI + 2");
new Add { DestinationReg = RegistersEnum.EDI, SourceValue = 2 };
new Comment("X#: Goto ReadChar");
new Jump { DestinationLabel = "DebugStub_DisplayWaitMsg_ReadChar" };
new Comment("X#: }");
new Label("DebugStub_DisplayWaitMsg_Exit");
new Return();
}
}
}

View file

@ -17,7 +17,7 @@ BeginLoop:
# End of Video Area
# VidBase + 25 * 80 * 2 = B8FA0
If (ESI < $B8FA0) goto BeginLoop
If ESI < $B8FA0 goto BeginLoop
}
procedure DisplayWaitMsg {
@ -35,7 +35,7 @@ procedure DisplayWaitMsg {
# Read and copy string till 0 terminator
ReadChar:
AL = ESI[0]
if (AL = 0) exit
if AL = 0 exit
ESI++
EDI[0] = AL
EDI + 2

View file

@ -219,35 +219,35 @@ namespace Cosmos.Compiler.XSharp {
});
AddPattern(new string[] {
//0 1 2 3 4 5 6 7
"if (_REG < 123) goto _ABC",
"if (_REG > 123) goto _ABC",
"if (_REG = 123) goto _ABC",
"if (_REG != 123) goto _ABC",
"if (_REG <= 123) goto _ABC",
"if (_REG >= 123) goto _ABC"
//0 1 2 3 4 5
"if _REG < 123 goto _ABC",
"if _REG > 123 goto _ABC",
"if _REG = 123 goto _ABC",
"if _REG != 123 goto _ABC",
"if _REG <= 123 goto _ABC",
"if _REG >= 123 goto _ABC"
},
delegate(TokenList aTokens, ref List<string> rCode) {
rCode.Add("new Compare {{ DestinationReg = RegistersEnum.{2}, SourceValue = {4} }};");
rCode.Add("new Compare {{ DestinationReg = RegistersEnum.{1}, SourceValue = {3} }};");
var xCondition = GetCondition(aTokens[3]);
string xLabel = GetLabel(aTokens[7]);
var xCondition = GetCondition(aTokens[2]);
string xLabel = GetLabel(aTokens[5]);
rCode.Add("new ConditionalJump {{ Condition = " + xCondition + ", DestinationLabel = " + Quoted(xLabel) + " }};");
}
);
AddPattern(new string[] {
//0 1 2 3 4 5 6
"if (_REG < 123) Exit",
"if (_REG > 123) Exit",
"if (_REG = 123) Exit",
"if (_REG != 123) Exit",
"if (_REG <= 123) Exit",
"if (_REG >= 123) Exit"
//0 1 2 3 4
"if _REG < 123 Exit",
"if _REG > 123 Exit",
"if _REG = 123 Exit",
"if _REG != 123 Exit",
"if _REG <= 123 Exit",
"if _REG >= 123 Exit"
},
delegate(TokenList aTokens, ref List<string> rCode) {
rCode.Add("new Compare {{ DestinationReg = RegistersEnum.{2}, SourceValue = {4} }};");
rCode.Add("new Compare {{ DestinationReg = RegistersEnum.{1}, SourceValue = {3} }};");
var xCondition = GetCondition(aTokens[3]);
var xCondition = GetCondition(aTokens[2]);
rCode.Add("new ConditionalJump {{ Condition = " + xCondition + ", DestinationLabel = " + Quoted(ProcLabel("Exit")) + " }};");
}
);

View file

@ -49,6 +49,7 @@
<li>msglen equ $-message</li>
</ul>
</li>
<li>Errors - show filename and line no</li>
<li>Repeat 4 times { } - for comports, etc</li>
<li>X# ProcessCmds.CS, ProcessCmdBatch - #TODO Make this a do while loop. Test
elsewhere though, this method is not used currently.</li>