[問題] 需要高手挑戰的詭異問題

作者: erspicu (.)   2016-09-07 10:58:24
https://www.dropbox.com/s/cit9jl96hzg4lui/Apr8086-needcheck0907.zip?dl=0
這是老電腦 8086的模擬器初步實作
目前只能算是完成CPU的部分(極少數指令尚未完成)
要問的是一個跟模擬器實作層面無關的問題
應該確認是編譯器或是 .net framework潛在的bug
只要在專案 x86\CPU.cs 裡頭的 cpu_exec() 內加入
debug_inf = Reg_B.X.ToString() + Reg_C.X.ToString(); 這樣一行 ln 266
(目前觀察到只要對register物件內容有ToString()的動作或是相關字串操作
就很容易有問題)
x86\CPU.cs cpu_exec() switch case 0x83: 內的 MessageBox.show 內容
ln 2418開始下面幾行
就會從
a:0 4
b:4
c:4
d:04
e:00
f: 0400
變成
a:0 4
b:4
c:4
d:00
e:00
f: 0000
(測試方式可以啟動程式UI後,點擊 DEBUG 的 button 就會測試運作 ,
MessageBox到 f: 後就可以把程式關閉掉)
實際上目前是簡化問題 , 有時候a b c裡頭的value 會隨著開啟程式時間不同,
跳亂數......
(前面幾次開關城市 測試 a: b: c: 內容都正常,有可能哪次突然跳亂數)
由於開發需要檢測每次執行指令各register狀態,甚至輸出log,之前撰寫GameBoy
也是用一樣的方式輸出各register內容,
沒任何問題,但這次有使用到指標與比較進階的struct
[StructLayout(LayoutKind.Explicit, Size = 2)]
struct RegWord
{
[FieldOffset(1)]
public byte H; //heigh byte
[FieldOffset(0)]
public byte L; //low byte
[FieldOffset(0)]
public ushort X; //word
}
除了編譯器或是 .net framework本身bug外,想不出別的理由....
資訊更新一:應該跟指標的使用問題有關係 但應該不是我的問題
後來把 Main.cs 中
fixed (ushort* p = &Reg_ES) { Table_SegRegs[0] = p; }
fixed (ushort* p = &Reg_CS) { Table_SegRegs[1] = p; }
fixed (ushort* p = &Reg_SS) { Table_SegRegs[2] = p; }
fixed (ushort* p = &Reg_DS) { Table_SegRegs[3] = p; }
fixed (ushort* p = &Reg_A.X) { Table_WordRegs[0] = p; }
fixed (ushort* p = &Reg_C.X) { Table_WordRegs[1] = p; }
fixed (ushort* p = &Reg_D.X) { Table_WordRegs[2] = p; }
fixed (ushort* p = &Reg_B.X) { Table_WordRegs[3] = p; }
fixed (ushort* p = &Reg_SP) { Table_WordRegs[4] = p; }
fixed (ushort* p = &Reg_BP) { Table_WordRegs[5] = p; }
fixed (ushort* p = &Reg_SI) { Table_WordRegs[6] = p; }
fixed (ushort* p = &Reg_DI) { Table_WordRegs[7] = p; }
fixed (byte* P = &Reg_A.L) { Table_ByteRegs[0] = P; }
fixed (byte* P = &Reg_C.L) { Table_ByteRegs[1] = P; }
fixed (byte* P = &Reg_D.L) { Table_ByteRegs[2] = P; }
fixed (byte* P = &Reg_B.L) { Table_ByteRegs[3] = P; }
fixed (byte* P = &Reg_A.H) { Table_ByteRegs[4] = P; }
fixed (byte* P = &Reg_C.H) { Table_ByteRegs[5] = P; }
fixed (byte* P = &Reg_D.H) { Table_ByteRegs[6] = P; }
fixed (byte* P = &Reg_B.H) { Table_ByteRegs[7] = P; }
這種寫法除掉改用別方式來處理register解碼與對應 就ok了
改用下面這種方式 但直接靠array來mapping指標操作解碼對應
不知到快了 switch有多少倍去....
byte Table_ByteRegsGet(int reg)
{
switch (reg)
{
case 0:
return Reg_A.L;
case 1:
return Reg_C.L;
case 2:
return Reg_D.L;
case 3:
return Reg_B.L;
case 4:
return Reg_A.H;
case 5:
return Reg_C.H;
case 6:
return Reg_D.H;
case 7:
return Reg_B.H;
}
return 0;
}
void Table_ByteRegsSet(int reg, byte val)
{
switch (reg)
{
case 0:
Reg_A.L = val;
break;
case 1:
Reg_C.L = val;
break;
case 2:
Reg_D.L = val;
break;
case 3:
Reg_B.L = val;
break;
case 4:
Reg_A.H = val;
break;
case 5:
Reg_C.H = val;
break;
case 6:
Reg_D.H = val;
break;
case 7:
Reg_B.H = val;
break;
}
}
作者: fo40225   2016-09-08 00:49:00
你在fixed區塊內把指標的值保留在陣列裡 出了fixed那個位址值就不保證了 只要GC一動作 你的指標就廢了ToString() 會配置物件 很容易觸發0代GC使用vs 偵錯 視窗 記憶體 把位址打上去 在init後下斷點init最後面寫個迴圈 new object() 然後觀察迴圈前後陣列裡所記錄的位址 記憶體會被改變的
作者: Litfal (Litfal)   2016-09-09 15:55:00
C#不太適合處理這種實值指標、或是需要很精確控制記憶體的狀況

Links booklink

Contact Us: admin [ a t ] ucptt.com