はじめに
前回の記事にて、Mind開発者@killyさんより情報共有いただいた検証用Consoleをベースにした中間コードのCディスパッチャの処理結果のリターンスタック値をC#代替実装版の互換値に変換することに成功しました。本来の目的はC#版の処理結果がずれはじめた起点を特定することにありましたが、両者の結果を精査した結果C#側の処理結果の出力にも誤りがあることを検出しました。本記事はその点を是正した結果の比較と見えてきた結果のご報告です。
前提条件
Windows11 Pro 22H2
VSCode(Visual Studo Code) 1.86.1
Microsoft Visual C++ 2008 Express Edition
Mind Version 8.0.08 for Windows
C# 12
dotnet-sdk-8.0.204-win-x64
VSCodeの拡張機能
C/C++ for Visual Studio Code 1.18.5 Microsoft
C/C++ Extension Pack 1.3.0 Microsoft
.NET Install Tool 2.0.2 Microsoft
Base language support for C# 2.18.16 Microsoft
C/C++のデバッガはCで実装されているMind8kernelの動作をデバッグ実行で探るために使用します。こちらの記事の環境となります。
お題のMind8の中間コード実行リスト(C#代替版のモニタコード改修版)
下記はC#代替版でお題のステップ数60のhellolevel1.mco中間コードファイルを処理させた結果です。
前回記事でC側のリターンスタック値のアドレス値をC#版のByte配列インデックス値の変換に成功したため、両者を比較することが可能となりました。結果を比較しましたところ、処理単語がC単語(C#版ではC#単語)のステップではなくMind単語のステップ直後のリターンスタック値が異なっており、あたかもスタック動作していないような状態となっていました。(手前のスタック値が消失しているかのように見える。)
そこで、C#側のMind処理単語のリターンスタックへのPUSH操作処理を精査してみましたが、そこには問題なく、結果のモニタ処理でも使用していたスタック値の相対オフセット指定で値をとりだす処理に誤りがありました。下記はその点を修正した結果です。
SqNo mcode mc(dec) mpoint dtp.point dtp+0 dtp+1 rtp.point rtp+0 rtp+1
1 8019 32793 114 1024 0 0 1024 0 0
2 002F 47 102 1024 0 0 1023 114 0
3 0012 18 5862 1024 0 0 1023 114 0
4 0036 54 5864 1024 0 0 1023 114 0
5 0080 128 5870 1024 0 0 1023 114 0
6 0036 54 5872 1024 0 0 1023 114 0
7 0070 112 5878 1024 0 0 1023 114 0
8 803A 32826 5880 1024 0 0 1023 114 0
9 002F 47 238 1024 0 0 1022 5880 114
10 80B8 32952 5858 1024 0 0 1022 5880 114
11 0012 18 5842 1024 0 0 1021 5858 5880
12 0036 54 5844 1024 0 0 1021 5858 5880
13 0071 113 5850 1024 0 0 1021 5858 5880
14 8046 32838 5852 1024 0 0 1021 5858 5880
15 8045 32837 326 1024 0 0 1020 5852 5858
16 0012 18 314 1024 0 0 1019 326 5852
17 0036 54 316 1024 0 0 1019 326 5852
18 0074 116 322 1024 0 0 1019 326 5852
19 0020 32 324 1024 0 0 1019 326 5852
20 0020 32 328 1024 0 0 1020 5852 5858
21 80A3 32931 5854 1024 0 0 1021 5858 5880
22 0036 54 3884 1024 0 0 1020 5854 5858
23 0012 18 3890 1024 0 0 1020 5854 5858
24 016E 366 3892 1024 0 0 1020 5854 5858
25 0020 32 3898 1024 0 0 1020 5854 5858
26 0020 32 5856 1024 0 0 1021 5858 5880
27 0020 32 5860 1024 0 0 1022 5880 114
28 00A5 165 5882 1024 0 0 1023 114 0
29 803C 32828 5906 1022 20 5884 1023 114 0
30 002F 47 246 1022 20 5884 1022 5906 114
31 001A 26 5802 1022 20 5884 1022 5906 114
32 006E 110 5804 1022 20 5884 1020 0 0
33 0015 21 5808 1024 0 0 1020 20 20
34 00ED 237 5810 1022 0 1 1020 20 20
35 0022 34 5830 1024 0 0 1020 20 20
36 0020 32 5856 1024 0 0 1023 5858 5906
37 0020 32 5860 1024 0 0 1024 5906 5884
38 00A5 165 5908 1024 0 0 1025 5884 20
39 00C1 193 5926 1022 14 5910 1025 5884 20
$$COLD_FORTH
40 0020 32 5928 1024 0 0 1025 5884 20
41 658A 25994 5886 1024 0 0 1026 20 20
例外がスローされました: 'System.IndexOutOfRangeException' (mind8dispatch.dll の中)
プログラム '[11784] mind8dispatch.dll' がコード -1 (0xffffffff) で終了しました。
39ステップ目のmcodeの値が、Cオリジナルでは80C3のところ、C#代替版では従来002Aとなっていたヶ所が今回は658Aとなりました。修正した箇所は下記に説明するオフセット取得関数だけですが、それもC#単語処理中に使われていたかもしれません。
お題のC#ソースコード
namespace Mind8Kernel
{
/// <summary>スタックポインタ</summary>
public class StackPointer{
//~略~
public uint GetUlOffset(int offset){/* for unsigned long access */
//アドレス指定で直接セットしている元コードのためポインタインデックスの自動増加はなし
byte[] int32Byte = new byte[stackSize];
- uint index=(uint)(stackIndex + offset*stackSize);
+ uint index=0;
+ if((stackIndex - offset*stackSize)>=0){
+ index=(uint)(stackIndex - offset*stackSize);
+ }
for (ulong i = 0; i < stackSize; i++) int32Byte[i] = dataArray[index + i];
return BitConverter.ToUInt32(int32Byte, 0);
}
//~略~
下記のC#側モニタ出力のdtp.GetUlOffset(1)がおかしかったわけです。
namespace Mind8Kernel
{
/// <summary>Mind8ディスパッチャ</summary>
public partial class Dispatcher
{
//~略~
/// <summary>ディスパッチャ</summary>
/// <param name="McodeInfo">MCode情報構造体の参照</param>
/// <param name="csFunc">C#関数配列の参照</param>
private int Dispatch(McodeInfoStruct McodeInfo, Action[] csFuncs){
ushort mcode;
int retcode=0;//setjmp( RESTARTENV ); /* ←ディスパッチャ再 */
if ( retcode != 2 ) /* 強制脱出の検査 */
{
try{
int i=0;
for(;;)
{
mcode = mp.FetchMcode();
Console.Write("{0,4:d} {1,4:X4} {2,6:d} {3,6:d}",++i,mcode,mcode,mp.GetMcodeIndex());
Console.WriteLine(" {0,6:d} {1,8:d} {2,8:d} {3,6:d} {4,8:d} {5,8:d}",dtp.GetCurrentStackPointer(),dtp.GetUl(),
dtp.GetUlOffset(1),
rtp.GetCurrentStackPointer(),rtp.GetUl(),rtp.GetUlOffset(1));
if ( (mcode & 0x8000)==0 )
{
/* C#関数 */
csFuncs[mcode]();
}
else
{
/* Mind単語 */
//PUSH_R( McodePointer.l );
//#define PUSH_R(addr) *(--RstackPointer)=(ULONG)(addr)
rtp.PushUl(mp.GetMcodeIndex());//現在のMCodeポインタの値をリターンスタックにプッシュする
//SET_MCODE_POINTER_BY_WORDNO( mcode & 0x7fff );
//McodePointer.b = (UCHAR *)(WordOffsetTable[wordNo])
mp.ResetMcodeIndex((uint)lp.GetSl((uint)(mcode & 0x7fff)));
}
}
//~略~
お題のMind8の中間コード実行リストのリターンスタック値をC#代替互換にEXCELで加工して比較
コンバート結果を今回訂正したC#代替のリターンスタック値(インデックス値)と並べた結果が下記です。rtp+0(C#)とrtp+1(C#)の値が訂正されています。
SqNo mcode rtp.point rtp+0 rtp+0(補正) rtp+0(C#) rtp+1 rtp+1(補正) rtp+1(C#)
1 8019 1024 0 0 0 0 0 0
2 002F 1023 12533850 114 114 0 0 0
3 0012 1023 12533850 114 114 0 0 0
4 0036 1023 12533850 114 114 0 0 0
5 0080 1023 12533850 114 114 0 0 0
6 0036 1023 12533850 114 114 0 0 0
7 0070 1023 12533850 114 114 0 0 0
8 803A 1023 12533850 114 114 0 0 0
9 002F 1022 12539616 5880 5880 12533850 114 114
10 80B8 1022 12539616 5880 5880 12533850 114 114
11 0012 1021 12539594 5858 5858 12539616 5880 5880
12 0036 1021 12539594 5858 5858 12539616 5880 5880
13 0071 1021 12539594 5858 5858 12539616 5880 5880
14 8046 1021 12539594 5858 5858 12539616 5880 5880
15 8045 1020 12539588 5852 5852 12539594 5858 5858
16 0012 1019 12534062 326 326 12539588 5852 5852
17 0036 1019 12534062 326 326 12539588 5852 5852
18 0074 1019 12534062 326 326 12539588 5852 5852
19 0020 1019 12534062 326 326 12539588 5852 5852
20 0020 1020 12539588 5852 5852 12539594 5858 5858
21 80A3 1021 12539594 5858 5858 12539616 5880 5880
22 0036 1020 12539590 5854 5854 12539594 5858 5858
23 0012 1020 12539590 5854 5854 12539594 5858 5858
24 016E 1020 12539590 5854 5854 12539594 5858 5858
25 0020 1020 12539590 5854 5854 12539594 5858 5858
26 0020 1021 12539594 5858 5858 12539616 5880 5880
27 0020 1022 12539616 5880 5880 12533850 114 114
28 00A5 1023 12533850 114 114 0 0
29 803C 1023 12533850 114 114 0 0
30 002F 1022 12539642 5906 5906 12533850 114 114
31 001A 1022 12539642 5906 5906 12533850 114 114
32 006E 1020 12539590 5854 0 12539594 5858 0
33 0015 1020 20 20 12539620 5884 20
34 00ED 1020 20 20 12539620 5884 20
35 0022 1020 20 20 12539620 5884 20
36 00A5 1023 12533850 114 5858 0 5906
37 00C1 1023 12533850 114 5906 0 5884
$$COLD_FORTH 5884 20
38 0020 1023 12533850 114 5884 0 20
39 80C3 1024 0 0
40 00A5 1023 12533852 116 5884 0 20
41 8083 1023 12533852 116 20 0 20
42 0012 1022 12540140 6404 12533852 116
43 004E 1022 12540140 6404 12533852 116
44 00EC 1022 12540140 6404 12533852 116
45 0096 1022 12540140 6404 12533852 116
46 026D 1022 12540140 6404 12533852 116
Hello by mind8
47 0020 1022 12540140 6404 12533852 116
48 0020 1023 12533852 116 0 0
49 801A 1024 0 0 0
50 002F 1023 12533854 118 0 0
51 00A5 1023 12533854 118 0 0
52 00C1 1023 12533854 118 0 0
実行終り
53 801B 1023 12533854 118 0 0
54 002F 1022 12539708 5972 12533854 118
55 00A5 1022 12539708 5972 12533854 118
56 00C1 1022 12539708 5972 12533854 118
実行終り時の処理
57 0020 1022 12539708 5972 12533854 118
58 0012 1023 12533854 118 0 0
59 004E 1023 12533854 118 0 0
60 0014 1023 12533854 118 0 0
訂正された結果同士で比較しますと、ステップ31の001Aが処理された後のスタック値が一致しなくなっているようです。ステップ36以降も訂正されたC#版実行結果ではC版と異なっていますが、上記表では無視しています。
つづく
生成されたhello.mcoを解釈して、C#側で「Hello by mind8」が出力されるようにするまでの長い道のりですが(初期処理をショートカットすればこの処理自体は処理できていますが、初期処理をどの程度対応するかで道のりの長さは大きく変動しまして、カメの動きとなっております。)、問題個所の特定を引き続き行ってまいります。