diff --git a/OpenKh.Command.Bdxio/Antlr4/BdxScript.g4 b/OpenKh.Command.Bdxio/Antlr4/BdxScript.g4 index 035a63d13..de02fc9d4 100644 --- a/OpenKh.Command.Bdxio/Antlr4/BdxScript.g4 +++ b/OpenKh.Command.Bdxio/Antlr4/BdxScript.g4 @@ -30,7 +30,7 @@ numberdata: | '0x' hexnumber = (DEC | HEX) | floatnumber = FLOATNUM; hexbody: DEC | HEX; -id: ID | DEC | HEX; +id: DEC | HEX | ID; include: '%include' FileName NL; section: 'section' section_id NL; section_id: '.text' | '.bss'; @@ -41,7 +41,7 @@ HEX: [0-9a-fA-F]+; FLOATNUM: [-+]? ([0-9]* '.' [0-9]+) | ([0-9]+ [eE] [-+]? [0-9]+); -ID: [a-zA-Z_][a-zA-Z0-9_]*; +ID: [a-zA-Z_][a-zA-Z0-9_]* ('.' [a-zA-Z0-9_]+)*; WS: [ \t] -> skip; NL: '\r'? '\n' | '\r'; FileName: '"' ~["]* '"'; diff --git a/OpenKh.Command.Bdxio/Antlr4/BdxScriptLexer.cs b/OpenKh.Command.Bdxio/Antlr4/BdxScriptLexer.cs index e0de6e66d..aebe4593b 100644 --- a/OpenKh.Command.Bdxio/Antlr4/BdxScriptLexer.cs +++ b/OpenKh.Command.Bdxio/Antlr4/BdxScriptLexer.cs @@ -97,7 +97,7 @@ static BdxScriptLexer() { } } private static int[] _serializedATN = { - 4,0,22,196,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7, + 4,0,22,207,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7, 6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,13,7,13,2,14, 7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,19,2,20,7,20,2,21, 7,21,1,0,1,0,1,1,1,1,1,1,1,1,1,2,1,2,1,2,1,3,1,3,1,4,1,4,1,4,1,5,1,5,1, @@ -109,22 +109,23 @@ static BdxScriptLexer() { 16,131,8,16,1,16,5,16,134,8,16,10,16,12,16,137,9,16,1,16,1,16,4,16,141, 8,16,11,16,12,16,142,1,16,4,16,146,8,16,11,16,12,16,147,1,16,1,16,3,16, 152,8,16,1,16,4,16,155,8,16,11,16,12,16,156,3,16,159,8,16,1,17,1,17,5, - 17,163,8,17,10,17,12,17,166,9,17,1,18,1,18,1,18,1,18,1,19,3,19,173,8,19, - 1,19,1,19,3,19,177,8,19,1,20,1,20,5,20,181,8,20,10,20,12,20,184,9,20,1, - 20,1,20,1,21,1,21,5,21,190,8,21,10,21,12,21,193,9,21,1,21,1,21,0,0,22, + 17,163,8,17,10,17,12,17,166,9,17,1,17,1,17,4,17,170,8,17,11,17,12,17,171, + 5,17,174,8,17,10,17,12,17,177,9,17,1,18,1,18,1,18,1,18,1,19,3,19,184,8, + 19,1,19,1,19,3,19,188,8,19,1,20,1,20,5,20,192,8,20,10,20,12,20,195,9,20, + 1,20,1,20,1,21,1,21,5,21,201,8,21,10,21,12,21,204,9,21,1,21,1,21,0,0,22, 1,1,3,2,5,3,7,4,9,5,11,6,13,7,15,8,17,9,19,10,21,11,23,12,25,13,27,14, 29,15,31,16,33,17,35,18,37,19,39,20,41,21,43,22,1,0,10,1,0,39,39,2,0,43, 43,45,45,1,0,48,57,3,0,48,57,65,70,97,102,2,0,69,69,101,101,3,0,65,90, 95,95,97,122,4,0,48,57,65,90,95,95,97,122,2,0,9,9,32,32,1,0,34,34,2,0, - 10,10,13,13,211,0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1, + 10,10,13,13,224,0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1, 0,0,0,0,11,1,0,0,0,0,13,1,0,0,0,0,15,1,0,0,0,0,17,1,0,0,0,0,19,1,0,0,0, 0,21,1,0,0,0,0,23,1,0,0,0,0,25,1,0,0,0,0,27,1,0,0,0,0,29,1,0,0,0,0,31, 1,0,0,0,0,33,1,0,0,0,0,35,1,0,0,0,0,37,1,0,0,0,0,39,1,0,0,0,0,41,1,0,0, 0,0,43,1,0,0,0,1,45,1,0,0,0,3,47,1,0,0,0,5,51,1,0,0,0,7,54,1,0,0,0,9,56, 1,0,0,0,11,59,1,0,0,0,13,64,1,0,0,0,15,69,1,0,0,0,17,76,1,0,0,0,19,79, 1,0,0,0,21,88,1,0,0,0,23,96,1,0,0,0,25,102,1,0,0,0,27,107,1,0,0,0,29,117, - 1,0,0,0,31,125,1,0,0,0,33,158,1,0,0,0,35,160,1,0,0,0,37,167,1,0,0,0,39, - 176,1,0,0,0,41,178,1,0,0,0,43,187,1,0,0,0,45,46,5,58,0,0,46,2,1,0,0,0, + 1,0,0,0,31,125,1,0,0,0,33,158,1,0,0,0,35,160,1,0,0,0,37,178,1,0,0,0,39, + 187,1,0,0,0,41,189,1,0,0,0,43,198,1,0,0,0,45,46,5,58,0,0,46,2,1,0,0,0, 47,48,5,101,0,0,48,49,5,113,0,0,49,50,5,117,0,0,50,4,1,0,0,0,51,52,5,100, 0,0,52,53,5,119,0,0,53,6,1,0,0,0,54,55,5,44,0,0,55,8,1,0,0,0,56,57,5,100, 0,0,57,58,5,98,0,0,58,10,1,0,0,0,59,60,5,114,0,0,60,61,5,101,0,0,61,62, @@ -154,16 +155,19 @@ static BdxScriptLexer() { 0,0,0,155,156,1,0,0,0,156,154,1,0,0,0,156,157,1,0,0,0,157,159,1,0,0,0, 158,130,1,0,0,0,158,145,1,0,0,0,159,34,1,0,0,0,160,164,7,5,0,0,161,163, 7,6,0,0,162,161,1,0,0,0,163,166,1,0,0,0,164,162,1,0,0,0,164,165,1,0,0, - 0,165,36,1,0,0,0,166,164,1,0,0,0,167,168,7,7,0,0,168,169,1,0,0,0,169,170, - 6,18,0,0,170,38,1,0,0,0,171,173,5,13,0,0,172,171,1,0,0,0,172,173,1,0,0, - 0,173,174,1,0,0,0,174,177,5,10,0,0,175,177,5,13,0,0,176,172,1,0,0,0,176, - 175,1,0,0,0,177,40,1,0,0,0,178,182,5,34,0,0,179,181,8,8,0,0,180,179,1, - 0,0,0,181,184,1,0,0,0,182,180,1,0,0,0,182,183,1,0,0,0,183,185,1,0,0,0, - 184,182,1,0,0,0,185,186,5,34,0,0,186,42,1,0,0,0,187,191,5,59,0,0,188,190, - 8,9,0,0,189,188,1,0,0,0,190,193,1,0,0,0,191,189,1,0,0,0,191,192,1,0,0, - 0,192,194,1,0,0,0,193,191,1,0,0,0,194,195,6,21,0,0,195,44,1,0,0,0,17,0, - 111,117,122,127,130,135,142,147,151,156,158,164,172,176,182,191,1,6,0, - 0 + 0,165,175,1,0,0,0,166,164,1,0,0,0,167,169,5,46,0,0,168,170,7,6,0,0,169, + 168,1,0,0,0,170,171,1,0,0,0,171,169,1,0,0,0,171,172,1,0,0,0,172,174,1, + 0,0,0,173,167,1,0,0,0,174,177,1,0,0,0,175,173,1,0,0,0,175,176,1,0,0,0, + 176,36,1,0,0,0,177,175,1,0,0,0,178,179,7,7,0,0,179,180,1,0,0,0,180,181, + 6,18,0,0,181,38,1,0,0,0,182,184,5,13,0,0,183,182,1,0,0,0,183,184,1,0,0, + 0,184,185,1,0,0,0,185,188,5,10,0,0,186,188,5,13,0,0,187,183,1,0,0,0,187, + 186,1,0,0,0,188,40,1,0,0,0,189,193,5,34,0,0,190,192,8,8,0,0,191,190,1, + 0,0,0,192,195,1,0,0,0,193,191,1,0,0,0,193,194,1,0,0,0,194,196,1,0,0,0, + 195,193,1,0,0,0,196,197,5,34,0,0,197,42,1,0,0,0,198,202,5,59,0,0,199,201, + 8,9,0,0,200,199,1,0,0,0,201,204,1,0,0,0,202,200,1,0,0,0,202,203,1,0,0, + 0,203,205,1,0,0,0,204,202,1,0,0,0,205,206,6,21,0,0,206,44,1,0,0,0,19,0, + 111,117,122,127,130,135,142,147,151,156,158,164,171,175,183,187,193,202, + 1,6,0,0 }; public static readonly ATN _ATN = diff --git a/OpenKh.Command.Bdxio/Antlr4/BdxScriptParser.cs b/OpenKh.Command.Bdxio/Antlr4/BdxScriptParser.cs index d93978642..5ec6fad21 100644 --- a/OpenKh.Command.Bdxio/Antlr4/BdxScriptParser.cs +++ b/OpenKh.Command.Bdxio/Antlr4/BdxScriptParser.cs @@ -1025,9 +1025,9 @@ public HexbodyContext hexbody() { } public partial class IdContext : ParserRuleContext { - [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode ID() { return GetToken(BdxScriptParser.ID, 0); } [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode DEC() { return GetToken(BdxScriptParser.DEC, 0); } [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode HEX() { return GetToken(BdxScriptParser.HEX, 0); } + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode ID() { return GetToken(BdxScriptParser.ID, 0); } public IdContext(ParserRuleContext parent, int invokingState) : base(parent, invokingState) { diff --git a/OpenKh.Command.Bdxio/Antlr4/README.md b/OpenKh.Command.Bdxio/Antlr4/README.md index b7d62b5fa..2c1c429ce 100644 --- a/OpenKh.Command.Bdxio/Antlr4/README.md +++ b/OpenKh.Command.Bdxio/Antlr4/README.md @@ -13,3 +13,28 @@ java.exe -jar antlr-4.11.1-complete.jar BdxScript.g4 -Dlanguage=CSharp -no-liste ``` Only `BdxScriptLexer.cs` and `BdxScriptParser.cs` are needed. Others are not needed. + +## How bdx text is parsed to tree + +Use Visual Studio Code `mike-lischke.vscode-antlr4` plugin. + +And write this at `OpenKh/OpenKh.Command.Bdxio/Antlr4/.vscode/launch.json` + +``` +{ + "version": "1.0.0", + "configurations": [ + { + "name": "Debug ANTLR4 grammar", + "type": "antlr-debug", + "request": "launch", + "input": "test.bdx", + "grammar": "BdxScript.g4", + "printParseTree": true, + "visualParseTree": true + }, + ] +} +``` + +Write something to `test.bdx` and press `F5` key. diff --git a/OpenKh.Command.Bdxio/Models/BdxInstructionDesc.cs b/OpenKh.Command.Bdxio/Models/BdxInstructionDesc.cs index 05e67752f..8c8969c43 100644 --- a/OpenKh.Command.Bdxio/Models/BdxInstructionDesc.cs +++ b/OpenKh.Command.Bdxio/Models/BdxInstructionDesc.cs @@ -11,21 +11,23 @@ public record BdxInstructionDesc public ushort Code { get; set; } public ushort CodeMask { get; set; } - public string Name { get; set; } + public string Name { get; set; } = ""; public bool IsSyscall { get; set; } public bool IsGosub { get; set; } public bool IsJump { get; set; } public bool IsJumpConditional { get; set; } public bool NeverReturn { get; set; } public bool IsGosubRet { get; set; } + public bool CodeRevealerLabeling { get; set; } public int CodeSize { get; set; } - public Arg[] Args { get; set; } + public Arg[] Args { get; set; } = new Arg[0]; + public string[] OldNames { get; set; } = new string[0]; public override string ToString() => Name; public record Arg { - public string Name { get; set; } + public string Name { get; set; } = ""; public ArgType Type { get; set; } /// diff --git a/OpenKh.Command.Bdxio/Models/BdxInstructionDescs.cs b/OpenKh.Command.Bdxio/Models/BdxInstructionDescs.cs index d0cf74f81..1ab92ed38 100644 --- a/OpenKh.Command.Bdxio/Models/BdxInstructionDescs.cs +++ b/OpenKh.Command.Bdxio/Models/BdxInstructionDescs.cs @@ -21,46 +21,46 @@ public class BdxInstructionDescs { #region Generated - new BdxInstructionDesc { Code = 0x0000, CodeMask = 0x003F, Name = "pushImm", CodeSize = 3, Args = new[] { new Arg { Name = "imm32", Type = ArgType.Imm32 } } }, - new BdxInstructionDesc { Code = 0x0010, CodeMask = 0x003F, Name = "pushImmf", CodeSize = 3, Args = new[] { new Arg { Name = "float32", Type = ArgType.Float32 } } }, - new BdxInstructionDesc { Code = 0x0020, CodeMask = 0xFFFF, Name = "pushFromPSp", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } } }, - new BdxInstructionDesc { Code = 0x0060, CodeMask = 0xFFFF, Name = "pushFromPWp", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, WorkPos = true } } }, - new BdxInstructionDesc { Code = 0x00A0, CodeMask = 0xFFFF, Name = "pushFromPSpVal", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } } }, - new BdxInstructionDesc { Code = 0x00E0, CodeMask = 0xFFFF, Name = "pushFromPAi", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, AiPos = true } } }, - new BdxInstructionDesc { Code = 0x0030, CodeMask = 0xFFFF, Name = "pushFromFSp", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } } }, - new BdxInstructionDesc { Code = 0x0070, CodeMask = 0xFFFF, Name = "pushFromFWp", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, WorkPos = true } } }, - new BdxInstructionDesc { Code = 0x00B0, CodeMask = 0xFFFF, Name = "pushFromFSpVal", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } } }, - new BdxInstructionDesc { Code = 0x00F0, CodeMask = 0xFFFF, Name = "pushFromFAi", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, AiPos = true } } }, - new BdxInstructionDesc { Code = 0x0001, CodeMask = 0xFFCF, Name = "popToSp", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } } }, - new BdxInstructionDesc { Code = 0x0041, CodeMask = 0xFFCF, Name = "popToWp", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, WorkPos = true } } }, - new BdxInstructionDesc { Code = 0x0081, CodeMask = 0xFFCF, Name = "popToSpVal", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } } }, - new BdxInstructionDesc { Code = 0x00C1, CodeMask = 0xFFCF, Name = "popToAi", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, AiPos = true } } }, - new BdxInstructionDesc { Code = 0x0002, CodeMask = 0xFFCF, Name = "memcpyToSp", CodeSize = 3, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 }, new Arg { Name = "imm16_2", Type = ArgType.Imm16 } } }, - new BdxInstructionDesc { Code = 0x0042, CodeMask = 0xFFCF, Name = "memcpyToWp", CodeSize = 3, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 }, new Arg { Name = "imm16_2", Type = ArgType.Imm16, WorkPos = true } } }, - new BdxInstructionDesc { Code = 0x0082, CodeMask = 0xFFCF, Name = "memcpyToSpVal", CodeSize = 3, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 }, new Arg { Name = "imm16_2", Type = ArgType.Imm16 } } }, - new BdxInstructionDesc { Code = 0x00C2, CodeMask = 0xFFCF, Name = "memcpyToSpAi", CodeSize = 3, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 }, new Arg { Name = "imm16_2", Type = ArgType.Imm16, AiPos = true } } }, - new BdxInstructionDesc { Code = 0x0003, CodeMask = 0x000F, Name = "fetchValue", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } } }, + new BdxInstructionDesc { Code = 0x0000, CodeMask = 0x003F, Name = "push", CodeRevealerLabeling = true, CodeSize = 3, Args = new[] { new Arg { Name = "imm32", Type = ArgType.Imm32 } }, OldNames = new[] { "pushImm" } }, + new BdxInstructionDesc { Code = 0x0010, CodeMask = 0x003F, Name = "push.s", CodeSize = 3, Args = new[] { new Arg { Name = "float32", Type = ArgType.Float32 } }, OldNames = new[] { "pushImmf" } }, + new BdxInstructionDesc { Code = 0x0020, CodeMask = 0xFFFF, Name = "push.sp", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } }, OldNames = new[] { "pushFromPSp" } }, + new BdxInstructionDesc { Code = 0x0060, CodeMask = 0xFFFF, Name = "push.wp", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, WorkPos = true } }, OldNames = new[] { "pushFromPWp" } }, + new BdxInstructionDesc { Code = 0x00A0, CodeMask = 0xFFFF, Name = "push.sp.d", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } }, OldNames = new[] { "pushFromPSpVal" } }, + new BdxInstructionDesc { Code = 0x00E0, CodeMask = 0xFFFF, Name = "push.bd", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, AiPos = true } }, OldNames = new[] { "pushFromPAi" } }, + new BdxInstructionDesc { Code = 0x0030, CodeMask = 0xFFFF, Name = "push.d.sp", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } }, OldNames = new[] { "pushFromFSp" } }, + new BdxInstructionDesc { Code = 0x0070, CodeMask = 0xFFFF, Name = "push.d.wp", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, WorkPos = true } }, OldNames = new[] { "pushFromFWp" } }, + new BdxInstructionDesc { Code = 0x00B0, CodeMask = 0xFFFF, Name = "push.d.sp.d", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } }, OldNames = new[] { "pushFromFSpVal" } }, + new BdxInstructionDesc { Code = 0x00F0, CodeMask = 0xFFFF, Name = "push.d.bd", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, AiPos = true } }, OldNames = new[] { "pushFromFAi" } }, + new BdxInstructionDesc { Code = 0x0001, CodeMask = 0xFFCF, Name = "pop.sp", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } }, OldNames = new[] { "popToSp" } }, + new BdxInstructionDesc { Code = 0x0041, CodeMask = 0xFFCF, Name = "pop.wp", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, WorkPos = true } }, OldNames = new[] { "popToWp" } }, + new BdxInstructionDesc { Code = 0x0081, CodeMask = 0xFFCF, Name = "pop.sp.d", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } }, OldNames = new[] { "popToSpVal" } }, + new BdxInstructionDesc { Code = 0x00C1, CodeMask = 0xFFCF, Name = "pop.bd", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, AiPos = true } }, OldNames = new[] { "popToAi" } }, + new BdxInstructionDesc { Code = 0x0002, CodeMask = 0xFFCF, Name = "memcpy.sp", CodeSize = 3, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 }, new Arg { Name = "imm16_2", Type = ArgType.Imm16 } }, OldNames = new[] { "memcpyToSp" } }, + new BdxInstructionDesc { Code = 0x0042, CodeMask = 0xFFCF, Name = "memcpy.wp", CodeSize = 3, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 }, new Arg { Name = "imm16_2", Type = ArgType.Imm16, WorkPos = true } }, OldNames = new[] { "memcpyToWp" } }, + new BdxInstructionDesc { Code = 0x0082, CodeMask = 0xFFCF, Name = "memcpy.sp.d", CodeSize = 3, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 }, new Arg { Name = "imm16_2", Type = ArgType.Imm16 } }, OldNames = new[] { "memcpyToSpVal" } }, + new BdxInstructionDesc { Code = 0x00C2, CodeMask = 0xFFCF, Name = "memcpy.bd", CodeSize = 3, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 }, new Arg { Name = "imm16_2", Type = ArgType.Imm16, AiPos = true } }, OldNames = new[] { "memcpyToSpAi" } }, + new BdxInstructionDesc { Code = 0x0003, CodeMask = 0x000F, Name = "push.d.pop", CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16 } }, OldNames = new[] { "fetchValue" } }, new BdxInstructionDesc { Code = 0x0004, CodeMask = 0x000F, Name = "memcpy", CodeSize = 1, Args = new[] { new Arg { Name = "ssub", Type = ArgType.Ssub } } }, - new BdxInstructionDesc { Code = 0x0005, CodeMask = 0xFFFF, Name = "citf", CodeSize = 1 }, + new BdxInstructionDesc { Code = 0x0005, CodeMask = 0xFFFF, Name = "cvt.w.s", CodeSize = 1, OldNames = new[] { "citf" } }, new BdxInstructionDesc { Code = 0x0085, CodeMask = 0xFFFF, Name = "neg", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x00C5, CodeMask = 0xFFFF, Name = "inv", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0105, CodeMask = 0xFFFF, Name = "eqz", CodeSize = 1 }, + new BdxInstructionDesc { Code = 0x00C5, CodeMask = 0xFFFF, Name = "not", CodeSize = 1, OldNames = new[] { "inv" } }, + new BdxInstructionDesc { Code = 0x0105, CodeMask = 0xFFFF, Name = "seqz", CodeSize = 1, OldNames = new[] { "eqz" } }, new BdxInstructionDesc { Code = 0x0145, CodeMask = 0xFFFF, Name = "abs", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0185, CodeMask = 0xFFFF, Name = "msb", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x01C5, CodeMask = 0xFFFF, Name = "info", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0205, CodeMask = 0xFFFF, Name = "eqz", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0245, CodeMask = 0xFFFF, Name = "neqz", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0285, CodeMask = 0xFFFF, Name = "msbi", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x02C5, CodeMask = 0xFFFF, Name = "ipos", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0055, CodeMask = 0xFFFF, Name = "cfti", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0095, CodeMask = 0xFFFF, Name = "negf", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0155, CodeMask = 0xFFFF, Name = "absf", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0195, CodeMask = 0xFFFF, Name = "infzf", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x01D5, CodeMask = 0xFFFF, Name = "infoezf", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0215, CodeMask = 0xFFFF, Name = "eqzf", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0255, CodeMask = 0xFFFF, Name = "neqzf", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0295, CodeMask = 0xFFFF, Name = "supoezf", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x02D5, CodeMask = 0xFFFF, Name = "supzf", CodeSize = 1 }, + new BdxInstructionDesc { Code = 0x0185, CodeMask = 0xFFFF, Name = "sltz", CodeSize = 1, OldNames = new[] { "msb" } }, + new BdxInstructionDesc { Code = 0x01C5, CodeMask = 0xFFFF, Name = "slez", CodeSize = 1, OldNames = new[] { "info" } }, + new BdxInstructionDesc { Code = 0x0205, CodeMask = 0xFFFF, Name = "seqz", CodeSize = 1, OldNames = new[] { "eqz" } }, + new BdxInstructionDesc { Code = 0x0245, CodeMask = 0xFFFF, Name = "snez", CodeSize = 1, OldNames = new[] { "neqz" } }, + new BdxInstructionDesc { Code = 0x0285, CodeMask = 0xFFFF, Name = "sgez", CodeSize = 1, OldNames = new[] { "msbi" } }, + new BdxInstructionDesc { Code = 0x02C5, CodeMask = 0xFFFF, Name = "sgtz", CodeSize = 1, OldNames = new[] { "ipos" } }, + new BdxInstructionDesc { Code = 0x0055, CodeMask = 0xFFFF, Name = "cvt.s.w", CodeSize = 1, OldNames = new[] { "cfti" } }, + new BdxInstructionDesc { Code = 0x0095, CodeMask = 0xFFFF, Name = "neg.s", CodeSize = 1, OldNames = new[] { "negf" } }, + new BdxInstructionDesc { Code = 0x0155, CodeMask = 0xFFFF, Name = "abs.s", CodeSize = 1, OldNames = new[] { "absf" } }, + new BdxInstructionDesc { Code = 0x0195, CodeMask = 0xFFFF, Name = "sltz.s", CodeSize = 1, OldNames = new[] { "infzf" } }, + new BdxInstructionDesc { Code = 0x01D5, CodeMask = 0xFFFF, Name = "slez.s", CodeSize = 1, OldNames = new[] { "infoezf" } }, + new BdxInstructionDesc { Code = 0x0215, CodeMask = 0xFFFF, Name = "seqz.s", CodeSize = 1, OldNames = new[] { "eqzf" } }, + new BdxInstructionDesc { Code = 0x0255, CodeMask = 0xFFFF, Name = "snez.s", CodeSize = 1, OldNames = new[] { "neqzf" } }, + new BdxInstructionDesc { Code = 0x0295, CodeMask = 0xFFFF, Name = "sgez.s", CodeSize = 1, OldNames = new[] { "supoezf" } }, + new BdxInstructionDesc { Code = 0x02D5, CodeMask = 0xFFFF, Name = "sgtz.s", CodeSize = 1, OldNames = new[] { "supzf" } }, new BdxInstructionDesc { Code = 0x0006, CodeMask = 0xFFFF, Name = "add", CodeSize = 1 }, new BdxInstructionDesc { Code = 0x0046, CodeMask = 0xFFFF, Name = "sub", CodeSize = 1 }, new BdxInstructionDesc { Code = 0x0086, CodeMask = 0xFFFF, Name = "mul", CodeSize = 1 }, @@ -71,17 +71,17 @@ public class BdxInstructionDescs new BdxInstructionDesc { Code = 0x01C6, CodeMask = 0xFFFF, Name = "xor", CodeSize = 1 }, new BdxInstructionDesc { Code = 0x0206, CodeMask = 0xFFFF, Name = "sll", CodeSize = 1 }, new BdxInstructionDesc { Code = 0x0246, CodeMask = 0xFFFF, Name = "sra", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0286, CodeMask = 0xFFFF, Name = "eqzv", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x02C6, CodeMask = 0xFFFF, Name = "neqzv", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0016, CodeMask = 0xFFFF, Name = "addf", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0056, CodeMask = 0xFFFF, Name = "subf", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0096, CodeMask = 0xFFFF, Name = "mulf", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x00D6, CodeMask = 0xFFFF, Name = "divf", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0116, CodeMask = 0xFFFF, Name = "modf", CodeSize = 1 }, - new BdxInstructionDesc { Code = 0x0007, CodeMask = 0xFFCF, Name = "jmp", IsJump = true, CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, IsRelative = true } } }, - new BdxInstructionDesc { Code = 0x0047, CodeMask = 0xFFCF, Name = "jz", IsJump = true, IsJumpConditional = true, CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, IsRelative = true } } }, - new BdxInstructionDesc { Code = 0x0087, CodeMask = 0xFFCF, Name = "jnz", IsJump = true, IsJumpConditional = true, CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, IsRelative = true } } }, - new BdxInstructionDesc { Code = 0x0008, CodeMask = 0x000F, Name = "gosub", IsGosub = true, CodeSize = 2, Args = new[] { new Arg { Name = "ssub", Type = ArgType.Ssub }, new Arg { Name = "imm16", Type = ArgType.Imm16, IsRelative = true } } }, + new BdxInstructionDesc { Code = 0x0286, CodeMask = 0xFFFF, Name = "land", CodeSize = 1, OldNames = new[] { "eqzv" } }, + new BdxInstructionDesc { Code = 0x02C6, CodeMask = 0xFFFF, Name = "lor", CodeSize = 1, OldNames = new[] { "neqzv" } }, + new BdxInstructionDesc { Code = 0x0016, CodeMask = 0xFFFF, Name = "add.s", CodeSize = 1, OldNames = new[] { "addf" } }, + new BdxInstructionDesc { Code = 0x0056, CodeMask = 0xFFFF, Name = "sub.s", CodeSize = 1, OldNames = new[] { "subf" } }, + new BdxInstructionDesc { Code = 0x0096, CodeMask = 0xFFFF, Name = "mul.s", CodeSize = 1, OldNames = new[] { "mulf" } }, + new BdxInstructionDesc { Code = 0x00D6, CodeMask = 0xFFFF, Name = "div.s", CodeSize = 1, OldNames = new[] { "divf" } }, + new BdxInstructionDesc { Code = 0x0116, CodeMask = 0xFFFF, Name = "mod.s", CodeSize = 1, OldNames = new[] { "modf" } }, + new BdxInstructionDesc { Code = 0x0007, CodeMask = 0xFFCF, Name = "b", IsJump = true, CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, IsRelative = true } }, OldNames = new[] { "jmp" } }, + new BdxInstructionDesc { Code = 0x0047, CodeMask = 0xFFCF, Name = "beqz", IsJump = true, IsJumpConditional = true, CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, IsRelative = true } }, OldNames = new[] { "jz" } }, + new BdxInstructionDesc { Code = 0x0087, CodeMask = 0xFFCF, Name = "bnez", IsJump = true, IsJumpConditional = true, CodeSize = 2, Args = new[] { new Arg { Name = "imm16", Type = ArgType.Imm16, IsRelative = true } }, OldNames = new[] { "jnz" } }, + new BdxInstructionDesc { Code = 0x0008, CodeMask = 0x000F, Name = "jal", IsGosub = true, CodeSize = 2, Args = new[] { new Arg { Name = "ssub", Type = ArgType.Ssub }, new Arg { Name = "imm16", Type = ArgType.Imm16, IsRelative = true } }, OldNames = new[] { "gosub" } }, new BdxInstructionDesc { Code = 0x0009, CodeMask = 0xFFCF, Name = "halt", CodeSize = 1 }, new BdxInstructionDesc { Code = 0x0049, CodeMask = 0xFFCF, Name = "exit", NeverReturn = true, CodeSize = 1 }, new BdxInstructionDesc { Code = 0x0089, CodeMask = 0xFFCF, Name = "ret", IsGosubRet = true, CodeSize = 1 }, @@ -92,7 +92,7 @@ public class BdxInstructionDescs new BdxInstructionDesc { Code = 0x0209, CodeMask = 0xFFCF, Name = "degr", CodeSize = 1 }, new BdxInstructionDesc { Code = 0x0249, CodeMask = 0xFFCF, Name = "radd", CodeSize = 1 }, new BdxInstructionDesc { Code = 0x000A, CodeMask = 0x000F, Name = "syscall", IsSyscall = true, CodeSize = 2, Args = new[] { new Arg { Name = "ssub", Type = ArgType.Ssub }, new Arg { Name = "imm16", Type = ArgType.Imm16 } } }, - new BdxInstructionDesc { Code = 0x000B, CodeMask = 0x000F, Name = "gosub32", IsGosub = true, CodeSize = 3, Args = new[] { new Arg { Name = "ssub", Type = ArgType.Ssub }, new Arg { Name = "imm32", Type = ArgType.Imm32, IsRelative = true } } }, + new BdxInstructionDesc { Code = 0x000B, CodeMask = 0x000F, Name = "jal32", IsGosub = true, CodeSize = 3, Args = new[] { new Arg { Name = "ssub", Type = ArgType.Ssub }, new Arg { Name = "imm32", Type = ArgType.Imm32, IsRelative = true } }, OldNames = new[] { "gosub32" } }, #endregion }; diff --git a/OpenKh.Command.Bdxio/Utils/BdxDecoder.cs b/OpenKh.Command.Bdxio/Utils/BdxDecoder.cs index ce010cd84..4ef18ada2 100644 --- a/OpenKh.Command.Bdxio/Utils/BdxDecoder.cs +++ b/OpenKh.Command.Bdxio/Utils/BdxDecoder.cs @@ -443,7 +443,7 @@ string GetTriggerLabelFor(int key) { if (pair.Value is CodeContent content) { - if (content.Desc.Name == "pushImm" + if (content.Desc.CodeRevealerLabeling && content.Args.Length == 1 && content.Args[0] is ParsedArg arg && arg.Label == null diff --git a/OpenKh.Command.Bdxio/Utils/BdxEncoder.cs b/OpenKh.Command.Bdxio/Utils/BdxEncoder.cs index 50e66b0fb..3fe1c1445 100644 --- a/OpenKh.Command.Bdxio/Utils/BdxEncoder.cs +++ b/OpenKh.Command.Bdxio/Utils/BdxEncoder.cs @@ -2,16 +2,9 @@ using Antlr4.Runtime.Tree; using NLog; using OpenKh.Command.Bdxio.Models; -using System; -using System.Collections.Generic; -using System.Diagnostics; using System.Globalization; -using System.Linq; -using System.Runtime.InteropServices; using System.Text; -using System.Threading.Tasks; using Xe.BinaryMapper; -using YamlDotNet.Core.Tokens; using static BdxScriptParser; using static OpenKh.Command.Bdxio.Models.BdxHeader; using static OpenKh.Command.Bdxio.Models.BdxInstructionDesc; @@ -20,7 +13,7 @@ namespace OpenKh.Command.Bdxio.Utils { public class BdxEncoder { - public byte[] Content { get; } + public byte[] Content { get; } = new byte[0]; public BdxEncoder( BdxHeader header, @@ -33,16 +26,28 @@ Func loadScript if (string.IsNullOrWhiteSpace(script) && header.IsEmpty) { - Content = new byte[0]; return; } var labels = new SortedDictionary(); - var instructionDict = BdxInstructionDescs.GetDescs() - .GroupBy(it => it.Name) + var instructionDict = new (string, BdxInstructionDesc)[0] + .Concat( + BdxInstructionDescs.GetDescs() + .Select(desc => (desc.Name, desc)) + ) + .Concat( + BdxInstructionDescs.GetDescs() + .SelectMany( + desc => desc.OldNames + .Select( + oldName => (oldName, desc) + ) + ) + ) + .GroupBy(pair => pair.Item1) .Select(it => it.First()) - .ToDictionary(it => it.Name, it => it); + .ToDictionary(it => it.Item1, it => it.Item2); Func ResolveInt32Factory( Func stringToInt32, diff --git a/OpenKh.Tests.Commands/BdxAntlrGrammarTests.cs b/OpenKh.Tests.Commands/BdxAntlrGrammarTests.cs new file mode 100644 index 000000000..dcbb4675a --- /dev/null +++ b/OpenKh.Tests.Commands/BdxAntlrGrammarTests.cs @@ -0,0 +1,63 @@ +using Antlr4.Runtime; +using OpenKh.Command.Bdxio.Models; +using OpenKh.Command.Bdxio.Utils; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Reflection.Emit; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace OpenKh.Tests.Commands +{ + public class BdxAntlrGrammarTests + { + [Theory] + [MemberData(nameof(GetOpcodes))] + public void TestOpcodeNamesCanBeParsedCorrectly(string opcode) + { + var stream = FromString(opcode); + var lexer = new BdxScriptLexer(stream); + var tokens = new CommonTokenStream(lexer); + var parser = new BdxScriptParser(tokens); + var id = parser.id(); + Assert.Equal(expected: opcode, actual: id.GetText()); + } + + [Theory] + [InlineData("cvt.s.w")] + [InlineData("keyword.12345")] + public void TestTokenCanBeParsedAsIdCorrectly(string token) + { + var stream = FromString(token); + var lexer = new BdxScriptLexer(stream); + var tokens = new CommonTokenStream(lexer); + var parser = new BdxScriptParser(tokens); + var id = parser.id(); + Assert.Equal(expected: token, actual: id.GetText()); + } + + public static IEnumerable GetOpcodes() + { + return new string[0] + .Concat( + BdxInstructionDescs.GetDescs() + .Select(desc => desc.Name) + ) + .Concat( + BdxInstructionDescs.GetDescs() + .SelectMany(desc => desc.OldNames) + ) + .Distinct() + .Select(name => new object[] { name }); + } + + private static ICharStream FromString(string script) + { + var stream = CharStreams.fromString(script); + return stream; + } + } +} diff --git a/OpenKh.Tests.Commands/BdxRegressionTests.cs b/OpenKh.Tests.Commands/BdxRegressionTests.cs index 37308c0a6..bd268138f 100644 --- a/OpenKh.Tests.Commands/BdxRegressionTests.cs +++ b/OpenKh.Tests.Commands/BdxRegressionTests.cs @@ -15,9 +15,9 @@ namespace OpenKh.Tests.Commands { public class BdxRegressionTests { - private static string SourceRootDir => Path.Combine(Environment.CurrentDirectory, "res", "bdx"); + private static string SourceRootDir => Path.Combine(Environment.CurrentDirectory, "..", "..", "..", "res", "bdx"); - private const bool RegenerateTestResults = false; + private const bool RegenerateTestResults = true; [Theory] [MemberData(nameof(GetSource))] diff --git a/OpenKh.Tests.Commands/res/bdx/t01/b.bdscript b/OpenKh.Tests.Commands/res/bdx/t01/b.bdscript index 0f88dab87..1fe0fb0fe 100644 --- a/OpenKh.Tests.Commands/res/bdx/t01/b.bdscript +++ b/OpenKh.Tests.Commands/res/bdx/t01/b.bdscript @@ -12,17 +12,17 @@ Name: aaa ; codeRevealer: section .text OBJ_INIT: - pushImm 123456789 + push 123456789 drop - pushImmf 123.45 + push.s 123.45 drop - pushFromPWp W0 + push.wp W0 drop - pushFromPWp W12 + push.wp W12 drop - pushFromPWp W24 + push.wp W24 drop - gosub 2, L34 + jal 2, L34 ret L34: ret diff --git a/OpenKh.Tests.Commands/res/bdx/t02/a.bdscript b/OpenKh.Tests.Commands/res/bdx/t02/a.bdscript new file mode 100644 index 000000000..acfb254af --- /dev/null +++ b/OpenKh.Tests.Commands/res/bdx/t02/a.bdscript @@ -0,0 +1,19 @@ +--- +WorkSize: 64 +StackSize: 64 +TempSize: 64 +Triggers: +- Key: 0 + Addr: TR0 +Name: aaa + +--- + section .text +TR0: + pushImm 123456789 + drop + push 123456789 + drop + ret +DUMMY: + ret diff --git a/OpenKh.Tests.Commands/res/bdx/t02/a.bdx b/OpenKh.Tests.Commands/res/bdx/t02/a.bdx new file mode 100644 index 000000000..6ec5dcb9a Binary files /dev/null and b/OpenKh.Tests.Commands/res/bdx/t02/a.bdx differ diff --git a/OpenKh.Tests.Commands/res/bdx/t02/b.bdscript b/OpenKh.Tests.Commands/res/bdx/t02/b.bdscript new file mode 100644 index 000000000..b7ade456e --- /dev/null +++ b/OpenKh.Tests.Commands/res/bdx/t02/b.bdscript @@ -0,0 +1,24 @@ +--- +WorkSize: 64 +StackSize: 64 +TempSize: 64 +Triggers: +- Key: 0 + Addr: OBJ_INIT +Name: aaa + +--- +; codeLabels: +; codeRevealer: + section .text +OBJ_INIT: + push 123456789 + drop + push 123456789 + drop + ret +D23: + dw 0x0089 + + section .bss + resb 64 diff --git a/OpenKh.Tests/Patcher/PatcherTests.cs b/OpenKh.Tests/Patcher/PatcherTests.cs index 3b38e3baf..1cd014fae 100644 --- a/OpenKh.Tests/Patcher/PatcherTests.cs +++ b/OpenKh.Tests/Patcher/PatcherTests.cs @@ -549,7 +549,7 @@ public void PatchKh2BdscriptTest() writer.WriteLine(" Addr: TR0"); writer.WriteLine("Name: aaa"); writer.WriteLine("---"); - writer.WriteLine(" section.text"); + writer.WriteLine(" section .text"); writer.WriteLine("TR0:"); writer.WriteLine(" ret"); writer.WriteLine("DUMMY:"); diff --git a/docs/kh2/file/ai/index.md b/docs/kh2/file/ai/index.md index 670d79dbc..f167e1b6f 100644 --- a/docs/kh2/file/ai/index.md +++ b/docs/kh2/file/ai/index.md @@ -3,3 +3,221 @@ The AI is always located into BAR archives (under the extension of MDLX, MAG, etc.). They are used as a scripting language, compiled into bytecode to comunicate with the game engine. By courtesy of [GovanifY](https://code.govanify.com/govanify/ghidra-kh2ai), there is a fairly complete documentation of [KH2 AI ISA](kh2ai.md) available. This entire documentation is generated from his repository and it is considered the most up-to-date version. + +## File format + +```c +struct header { + char name[16]; + s32 workSize; + s32 stackSize; + s32 termSize; + struct { + s32 trigger; // key + s32 entry; // pointer to code + } triggers[n]; + s32 endTrigger; // 0 + s32 endEntry; // 0 +}; +``` + +## Memory spaces + +### wp (work memory pointer) + +Single uninitialized memory space. + +It is like `.bss` [.bss - Wikipedia](https://en.wikipedia.org/wiki/.bss) + +```c +char table1[128]; +char table2[128]; +char table3[128]; + +void main() { + +} +``` + +### sp (stack memory pointer) + +Single stack memory space. + +Main usage: local variable storage of local function. + +The allocation unit is always 4 bytes: DWORD (double word). + +The fixed count of DWORD is allocated by caller, whenever the local function call is occurred. + +- `jal` or `jal32` will allocate DWORDs. Also 2 mandatory DWORDs (DWORD count, and ret addr) must be added. +- `ret` will clean it up. + +```c +void func() { + int var1; +} +``` + +### tp (temp memory pointer) + +Single temporary memory space. + +Main usage: function arguments, function return value, input/output storage, etc. + +The allocation unit is always 4 bytes: DWORD (double word). + +Many opcodes (like *push*, *pop*, *unary and binary operators*, *conditional branch operators*, *arithmetic operators*, and so on) use this memory space for input/output purpose. + +As representative things, `push*` and `pop*` use this space. + +`push*` will write a DWORD to `tp`, and then `tp` is increased by `4`. + +`pop*` will read a DWORD from `tp`, and then `tp` is decreased by `4`. + +This is used to resolve input/output of function calls of both 2 patterns: + +- `syscall` for external function call +- `jal` and `jal32` for local function call + +```c +// 2 stack in +// 1 stack out +int func(int a, int b) { + return a + b; +} + +void main() { + int res = func(123, 456); +} +``` + +Another usage is arithmetic operation. + +``` +test10036: + pushImm 12 + pushImm 3 + div ; 12 ÷ 3 → 4 + pushImm 4 + sub ; 4 - 4 → 0 + jnz fail + jmp pass +``` + +- `div` and `sub` will consume 2 DWORDs, and produce 1 DWORD. +- `jnz` will consume 1 DWORD, and produce no DWORD. + +### bd + +Single `bdx` data memory space starting at 16th byte. + +`bd` pointer is always doubled by 2 when it is accessed. So referenced data must be aligned on 2 byte alignment. + +`bd` pointer and `pc` (program counter) share same format. + +This is used to resolve: + +- Having C style string like `char text[] = "hello";` +- Having pre initialized table like `struct { ... };` +- Having some kind of integer array like `int jumpTable[] = {0, ...};` + +```c +static char text[] = "hello"; + +void main() { + puts(text); +} +``` + +## Opcode cheat sheet + +| code | old | new name | description | +|---|---|---|---| +| 0,0,x | _pushImm_ | push | `push int32` | +| 0,1,x | _pushImmf_ | push.s | `push single` | +| 0,2,0 | _pushFromPSp_ | push.sp | `push sp + int16` | +| 0,2,1 | _pushFromPWp_ | push.wp | `push wp + int16` | +| 0,2,2 | _pushFromPSpVal_ | push.sp.d | `push *sp + int16` | +| 0,2,3 | _pushFromPAi_ | push.bd | `push bd + int16` | +| 0,3,0 | _pushFromFSp_ | push.d.sp | `push *( sp + int16)` | +| 0,3,1 | _pushFromFWp_ | push.d.wp | `push *( wp + int16)` | +| 0,3,2 | _pushFromFSpVal_ | push.d.sp.d | `push *(*sp + int16)` | +| 0,3,3 | _pushFromFAi_ | push.d.bd | `push *( bd + int16)` | +| 1,x,0 | _popToSp_ | pop.sp | `pop *( sp + int16)` | +| 1,x,1 | _popToWp_ | pop.wp | `pop *( wp + int16)` | +| 1,x,2 | _popToSpVal_ | pop.sp.d | `pop *(*sp + int16)` | +| 1,x,3 | _popToAi_ | pop.bd | `pop *( bd + int16)` | +| 2,x,0 | _memcpyToSp_ | memcpy.sp | `memcpy to ( sp + int16)` | +| 2,x,1 | _memcpyToWp_ | memcpy.wp | `memcpy to ( wp + int16)` | +| 2,x,2 | _memcpyToSpVal_ | memcpy.sp.d | `memcpy to (*sp + int16)` | +| 2,x,3 | _memcpyToSpAi_ | memcpy.bd | `memcpy to ( bd + int16)` | +| 3,x,x | _fetchValue_ | push.d.pop | `push *( pop() + int16)` | +| 4,x,x | | memcpy | generic memcpy | +| 5,0,0 | _citf_ | cvt.w.s | int to float (convert word to single) | +| 5,0,2 | | neg | 1 to -1, -1 to 1 | +| 5,0,3 | _inv_ | not | bitwise not | +| 5,0,4 | _eqz_ | seqz | set 1 if: equal to 0 | +| 5,0,5 | | abs | get absolute integer (negative to positive) | +| 5,0,6 | _msb_ | sltz | set 1 if: less than 0 (negative) | +| 5,0,7 | _info_ | slez | set 1 if: less than or equal to 0 (negative and zero) | +| 5,0,8 | _eqz_ | seqz | set 1 if: equal to 0 | +| 5,0,9 | _neqz_ | snez | set 1 if: not equal to 0 | +| 5,0,10 | _msbi_ | sgez | set 1 if: greater than or equal to 0 (zero and positive) | +| 5,0,11 | _ipos_ | sgtz | set 1 if: greater than 0 (positive) | +| 5,1,1 | _cfti_ | cvt.s.w | float to int (convert single to word) | +| 5,1,2 | _negf_ | neg.s | 1.0 to -1.0, -1.0 to 1.0 | +| 5,1,5 | _absf_ | abs.s | get absolute float (negative to positive) | +| 5,1,6 | _infzf_ | sltz.s | set 1 if: less than 0 (negative) | +| 5,1,7 | _infoezf_ | slez.s | set 1 if: less than or equal to 0 (negative and zero) | +| 5,1,8 | _eqzf_ | seqz.s | set 1 if: equal to 0 | +| 5,1,9 | _neqzf_ | snez.s | set 1 if: not equal to 0 | +| 5,1,10 | _supoezf_ | sgez.s | set 1 if: greater than or equal to 0 (zero and positive) | +| 5,1,11 | _supzf_ | sgtz.s | set 1 if: greater than 0 (positive) | +| 6,0,0 | | add | `push a; push b; (a + b)` | +| 6,0,1 | | sub | `push a; push b; (a - b)` | +| 6,0,2 | | mul | `push a; push b; (a * b)` | +| 6,0,3 | | div | `push a; push b; (a / b)` | +| 6,0,4 | | mod | `push a; push b; (a % b)` | +| 6,0,5 | | and | Bitwise and | +| 6,0,6 | | or | Bitwise or | +| 6,0,7 | | xor | Bitwise xor | +| 6,0,8 | | sll | Shift left logical (unsigned) | +| 6,0,9 | | sra | Shift right arithmetic (signed) | +| 6,0,10 | _eqzv_ | land | `push a; push b; (a && b)` | +| 6,0,11 | _neqzv_ | lor | `push a; push b; (a \|\| b)` | +| 6,1,0 | _addf_ | add.s | `push a; push b; (a + b)` float | +| 6,1,1 | _subf_ | sub.s | `push a; push b; (a - b)` float | +| 6,1,2 | _mulf_ | mul.s | `push a; push b; (a * b)` float | +| 6,1,3 | _divf_ | div.s | `push a; push b; (a + b)` float | +| 6,1,4 | _modf_ | mod.s | `push a; push b; (a % b)` float | +| 7,x,0 | _jmp_ | b | branch unconditionally | +| 7,x,1 | _jz_ | beqz | branch if zero | +| 7,x,2 | _jnz_ | bnez | branch if non-zero | +| 8,x,x | _gosub_ | jal | local function call (16-bit address) | +| 9,x,0 | | halt | halt | +| 9,x,1 | | exit | exit | +| 9,x,2 | | ret | ret | +| 9,x,3 | | drop | drop one value from `tp` | +| 9,x,5 | | dup | duplicate one value at `tp` | +| 9,x,6 | | sin | sin | +| 9,x,7 | | cos | cos | +| 9,x,8 | | degr | radian to degree: `value / PI * 180.0` | +| 9,x,9 | | radd | degree to radian: `value / 180.0 * PI` | +| 10,x,x | | syscall | syscall | +| 11,x,x | _gosub32_ | jal32 | local function call (32-bit address) | + +*Notes*: + +- `.d.` is short of `.dereference.`. It is shorten for optimization in case of keyboard typing. +- For example `push.d.sp`, it reads from left to right as English grammar does. A reading example is: *push dereferenced value of (sp + imm16)* + +### Reading of comparators + +| Comparator | Reading | +|:-:|---| +| EQZ | `x == 0` | +| GEZ | `x >= 0` | +| GTZ | `x > 0` | +| LEZ | `x <= 0` | +| LTZ | `x < 0` | +| NEZ | `x != 0` | diff --git a/docs/kh2/file/type/ai.md b/docs/kh2/file/type/ai.md index f63e77b65..c5f1a7a17 100644 --- a/docs/kh2/file/type/ai.md +++ b/docs/kh2/file/type/ai.md @@ -5,23 +5,3 @@ Process the artifical intelligence of the game. The engine parse this kind of fi See also: - [AI](../ai/index.md) -- [KH2 ai | monitor-kh2fm](https://kenjiuno.github.io/monitor-kh2fm/kh2ai.html) - -# Format - -Header - -| Offset | Type | Description -|--------|-------|------------ -| 00 | char[16] | Name of the script -| 04 | | -| 08 | | -| 0c | | -| 10 | | -| 14 | | -| 18 | | -| 1c | | -| 20 | | -| 24 | | -| 28 | int | Program counter entry point -| 2c | | \ No newline at end of file