Tuesday, March 17, 2020

針對虛擬機一次的分析


可能是我的問題,或者是編譯器的問題 , 或者組譯器問題 或者 虛擬機問題
在目前來說我發現在 cpu0 這個程式,我的input 是
sum = 0;

for (i=0; i<=10; i++)
{
  sum = sum + i;
}
return sum;
我拿去run 裡面的虛擬機 cpu.h? 好像會無窮迴圈我把暫存器印出來 發現裡面呼叫 define 裡面的值並沒有完成設值

也就是根本沒有 對暫存器做存入的動作
我嘗試修改了這個方法,可能是編譯的環境不一樣?

LoadInt32 test


void LoadInt32void(int *p , BYTE  *m)
{
   BYTE tmp[10];
   strcpy(tmp,m);
   *p= (INT32) (tmp[0]<<24|tmp[1]<<16|tmp[2]<<8|tmp[3]); 
   printf("ldi ra ex2:%d\n", (INT32) (tmp[0]<<24|tmp[1]<<16|tmp[2]<<8|tmp[3])); 
};


      case OP_LD : { //This is an empty staxxtement.
     // LoadInt32(i, m, addr) 
    BYTE *tmp=&m[caddr];
 //  R[ra]=(INT32)(m[0]<<24|m[1]<<16|m[2]<<8|m[3]); 
    printf("ld ra ex:%p\n",&R[ra])  ;
    printf("ld ra ex:%p\n", m[caddr])  ;
    printf("ld ra ex:%x\n", (m[0]<<24|m[1]<<16|m[2]<<8|m[3]))  ;
    printf("ld ra ex:%d\n", (INT32) (m[0]<<24|m[1]<<16|m[2]<<8|m[3]))  ;
    LoadInt32void(&R[ra],&m[caddr]);

經過了一段時間


這邊可以看到我們的暫存器,都一直處於空的狀態
我從指令及的asm 了解到 在 LD 和 LDI 在 LD 和 LDI 這邊怎麼吃不到 變數的值呢
首先我懷疑了 LoadInt32 和 StoreInt32 這兩個函數 是在 解析 從 變數中加載 數值
另一個 我以為 Define 出錯 ,最後一路追回我們的 Assembler
#include "Cpu0.h"

void runObjFile(char *objFile) {                 // 虛擬機器主函數
  printf("===VM0:run %s on CPU0===\n", objFile);               
  Cpu0 *cpu0 = Cpu0New(objFile);                 // 建立CPU0物件
  Cpu0Run(cpu0, 0);                              // 開始執行
  Cpu0Dump(cpu0);                                // 傾印暫存器
  Cpu0Free(cpu0);                                // 釋放記憶體 
}

Cpu0* Cpu0New(char *objFile) {                   // 建立 CPU0 物件                 
  Cpu0 *cpu0=ObjNew(Cpu0, 1);                    //  分配 CPU0 物件空間 
  cpu0->m = newFileBytes(objFile, &cpu0->mSize); //  載入映像檔 objFile 到記憶體 m 中
  return cpu0;                                                                
}                                                                             
                                                                              
void Cpu0Free(Cpu0 *cpu0) {                      // 刪除 CPU0 物件                 
  freeMemory(cpu0->m);                           //  釋放 CPU0 的 memory 
  ObjFree(cpu0);                                 //  釋放 CPU0 物件                                         
}                                                                                         
                                                                                                                                                            
#define bits(i, from, to) ((UINT32) i << (31-to) >> (31-to+from)) // 取得 from 到 to 之間的位元                   
#define ROR(i, k) (((UINT32)i>>k)|(bits(i,32-k, 31)<<(32-k)))// 向右旋轉k位元                                           
#define ROL(i, k) (((UINT32)i<<k)|(bits(i,0,k-1)<<(32-k)))   // 向左旋轉k位元                                             
#define SHR(i, k) ((UINT32)i>>k)                             // 向右移位k位元                
#define SHL(i, k) ((UINT32)i<<k)                             // 向左移位k位元                
#define bytesToInt32(p) (INT32)(p[0]<<24|p[1]<<16|p[2]<<8|p[3])// 4 byte轉 int
#define bytesToInt16(p) (INT16)(p[0]<<8|p[1])                // 2 byte轉 INT16               
#define int32ToBytes(i, bp) { bp[0]=i>>24; bp[1]=i>>16; bp[2]=i>>8; bp[3]=i;} // int轉為4 byte                                             
#define StoreInt32(i, m, addr) { BYTE *p=&m[addr]; int32ToBytes(i, p); } // i=m[addr…addr+3]                                         
#define LoadInt32(i, m, addr) { BYTE *p=&m[addr]; i=bytesToInt32(p) ; printf("dld ra ex:%x\n",&i)  ;  } // m[addr..addr+3]=i                                         
#define StoreByte(b, m, addr) { m[addr] = (BYTE) b; }        // m[addr]=b                                                 
#define LoadByte(b, m, addr) { b = m[addr]; }                // b=m[addr]                    
                                                                                          
#define PC R[15]                                             // PC is R[15]                  
#define LR R[14]                                             // LR is R[14]                  
#define SP R[13]                                             // SP is R[13]                  
#define SW R[12]                                             // SW is R[12]                  
void LoadInt32void(int *p , BYTE  *m)
{
   BYTE tmp[3];
   strcpy(tmp,m);
   *p= bytesToInt32(tmp); 
   printf("ldi ra ex2:%d\n",bytesToInt32(tmp)); 
  //   *p= (INT32) (tmp[0]<<24|tmp[1]<<16|tmp[2]<<8|tmp[3]); 
  //  printf("ldi ra ex2:%d\n", (INT32) (tmp[0]<<24|tmp[1]<<16|tmp[2]<<8|tmp[3])); 
};
void StoreInt32void(int *p , BYTE  *m)
{
   BYTE tmp[3];
   strcpy(tmp,m);
   int32ToBytes( *p,tmp); 
};


void Cpu0Run(Cpu0 *cpu0, int start) {                        // 虛擬機器的主要執行函數                   
  char buffer[200];
  unsigned int IR, op, ra, rb, rc, cc;                                                                         
  int c5, c12, c16, c24, caddr, raddr;                                                                
  unsigned int N, Z;
  BYTE *m=cpu0->m;                                                                                    
  int  *R=cpu0->R;                                           
  PC = start;                                                // 設定起始位址,準備開始執行                             
  LR = -1;                                                                                
  BOOL stop = FALSE;                                                                                  
  int testi=0;
  while (!stop) {                                            // 如果尚未結束    
    printf("time: %d\n",testi)  ;
    testi+=1;
    R[0] = 0;                                                // R[0] 永遠為 0                            
   // LoadInt32(IR, m, PC);                                    // 指令擷取,IR=[PC..PC+3]  
    LoadInt32void(&IR ,&m[PC]) ;                              
    cpu0->IR = IR;                                           // 取得指令暫存器                           
    PC += 4;                                                 // 擷取完將 PC 加 4,指向下一個指令
    op = bits(IR, 24, 31);                                   // 取得 op 欄位,IR[24..31]
    printf("op:%d\n",op)  ;
    ra = bits(IR, 20, 23);                                   // 取得 ra 欄位,IR[20..23]    
    rb = bits(IR, 16, 19);                                   // 取得 rb 欄位,IR[16..19]
    rc = bits(IR, 12, 15);                                   // 取得 rc 欄位,IR[12..15]
    c5 = bits(IR,  0, 4);                                    // 取得 5  位元的 cx 
    c12= bits(IR, 0, 11);                                    // 取得 12 位元的 cx 
    c16= bits(IR, 0, 15);                                    // 取得 16 位元的 cx                         
    c24= bits(IR, 0, 23);                                    // 取得 24 位元的 cx                                         
    N  = bits(SW, 31, 31);
    Z  = bits(SW, 30, 30);
    if (bits(IR, 11, 11)!=0) c12 |= 0xFFFFF000;              // 若 cx 為負數,則調整為2補數格式                                         
    if (bits(IR, 15, 15)!=0) c16 |= 0xFFFF0000;              // 若 cx 為負數,則調整為2補數格式                                        
    if (bits(IR, 23, 23)!=0) c24 |= 0xFF000000;              // 若 cx 為負數,則調整為2補數格式                                                                                 
    caddr = R[rb]+c16;                                       // 取得位址[Rb+cx]                          
    raddr = R[rb]+R[rc];                                     // 取得位址[Rb+Rc]                          
    switch (op) {                                            // 根據op執行動作                           
      case OP_LD : { //This is an empty staxxtement.
     // LoadInt32(i, m, addr) 
    //BYTE *tmp=&m[caddr];
 //  R[ra]=(INT32)(m[0]<<24|m[1]<<16|m[2]<<8|m[3]); 
    // printf("ld ra ex:%p\n",&R[ra])  ;
    // printf("ld ra ex:%p\n", m[caddr])  ;
    // printf("ld ra ex:%x\n", (m[0]<<24|m[1]<<16|m[2]<<8|m[3]))  ;
    // printf("ld ra ex:%d\n", (INT32) (m[0]<<24|m[1]<<16|m[2]<<8|m[3]))  ;
    LoadInt32void(&R[ra],&m[caddr]);
    //    LoadInt32(R[ra], m, caddr); 
  //  printf("ld ra ex:%x\n", R[ra])  ;
      // BYTE *p=&m[caddr];
      // BYTE *x=&m[caddr];
      // printf("轉換後address%s\n",x[0]);
      // R[ra]=(INT32)(p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3]);
      // printf("轉換後%x\n",(INT32)(p[0]<<24|p[1]<<16|p[2]<<8|p[3]));
      // printf("\nld ra tmp id:%d\n",ra)  ;
      // printf("ld ra :%x\n",(INT32)(x[0]<<24|x[1]<<16|x[2]<<8|x[3]))  ;
      // printf("ld ra :%x\n",caddr)  ;
      //  printf("ld ra ex:%x\n",R[ra])  ;

    }
      break;        // 處理 LD 指令    

      case OP_ST :// StoreInt32(R[ra], m, caddr); 
      {
         StoreInt32void(&R[ra],&m[caddr]);
      }break;       // 處理 ST 指令                            
      case OP_LDB: LoadByte(R[ra], m, caddr); break;         // 處理 LDB 指令                            
      case OP_STB: StoreByte(R[ra], m, caddr); break;        // 處理 STB 指令                            
      case OP_LDR:{ 
        //LoadInt32(R[ra], m, raddr); 
          LoadInt32void(&R[ra],&m[raddr]);
      }
      break;        // 處理 LDR 指令                           
      case OP_STR:{
         //StoreInt32(R[ra], m, raddr);
          StoreInt32void(&R[ra],&m[raddr]);
        
      } break;       // 處理 STR 指令                           
      case OP_LBR: LoadByte(R[ra], m, raddr); break;         // 處理 LBR 指令                           
      case OP_SBR: StoreByte(R[ra], m, raddr); break;        // 處理 SBR 指令                           
      case OP_LDI: R[ra] = c16;
          // byte b = c16;
           printf("c :%x\n",c16)  ;
          //           printf("ra id:%x\n",ra)  ;
          //           R[ra] = c16;
                     printf("ra ex:%x\n",R[ra])  ;
  
       break;                       // 處理 LDI 指令                           
      case OP_CMP: {                                         // 處理CMP指令,根據比較結果,設定 N,Z 旗標 
        if (R[ra] > R[rb]) {                                 // > : SW(N=0, Z=0)
          SW &= 0x3FFFFFFF;                                  // N=0, Z=0
        } else if (R[ra] < R[rb]) {                          // < : SW(N=1, Z=0, ....)                                                
          SW |= 0x80000000;                                  // N=1;
          SW &= 0xBFFFFFFF;                                  // Z=0;
        } else {                                             // = : SW(N=0, Z=1)                      
          SW &= 0x7FFFFFFF;                                  // N=0;
          SW |= 0x40000000;                                  // Z=1;
        }
        ra = 12;
        break;                                                                                        
      } case OP_MOV: R[ra] = R[rb]; break;                   // 處理MOV指令                             
      case OP_ADD: R[ra] = R[rb] + R[rc]; break;             // 處理ADD指令                             
      case OP_SUB: R[ra] = R[rb] - R[rc]; break;             // 處理SUB指令                             
      case OP_MUL: R[ra] = R[rb] * R[rc]; break;             // 處理MUL指令                             
      case OP_DIV: R[ra] = R[rb] / R[rc]; break;             // 處理DIV指令                             
      case OP_AND: R[ra] = R[rb] & R[rc]; break;             // 處理AND指令                             
      case OP_OR:  R[ra] = R[rb] | R[rc]; break;             // 處理OR指令                              
      case OP_XOR: R[ra] = R[rb] ^ R[rc]; break;             // 處理XOR指令                             
      case OP_ROL: R[ra] = ROL(R[rb],c5); break;             // 處理ROL指令                             
      case OP_ROR: R[ra] = ROR(R[rb],c5); break;             // 處理ROR指令                             
      case OP_SHL: R[ra] = SHL(R[rb],c5); break;             // 處理SHL指令                             
      case OP_SHR: R[ra] = SHR(R[rb],c5); break;             // 處理SHR指令                             
      case OP_JEQ: if (Z==1) PC += c24; break;               // 處理JEQ指令 Z=1
      case OP_JNE: if (Z==0) PC += c24; break;               // 處理JNE指令 Z=0 
      case OP_JLT: if (N==1&&Z==0) PC += c24; break;         // 處理JLT指令 NZ=10 
      case OP_JGT: if (N==0&&Z==0) PC += c24; break;         // 處理JGT指令 NZ=00
      case OP_JLE:                                           // 處理JLE指令 NZ=10 or 01
           if ((N==1&&Z==0)||(N==0&&Z==1)) PC+=c24; break;
      case OP_JGE:                                           // 處理JGE指令 NZ=00 or 01
           if ((N==0&&Z==0)||(N==0&&Z==1)) PC+=c24; break;
      case OP_JMP: PC+=c24; break;                           // 處理JMP指令                             
      case OP_SWI: LR = PC; PC=c24; break;                   // 處理SWI指令                             
      case OP_JSUB:LR = PC; PC+=c24; break;                  // 處理JSUB指令                            
      case OP_RET: if (LR<0) stop=TRUE; else PC=LR; break;   // 處理RET指令                             
      case OP_PUSH:SP-=4; StoreInt32(R[ra], m, SP); break;   // 處理PUSH指令                            
      case OP_POP:{//LoadInt32(R[ra], m, SP); 
         LoadInt32void(&R[ra],&m[SP]);
         SP+=4;
      } break;    // 處理POP指令                             
      case OP_PUSHB:SP--; StoreByte(R[ra], m, SP); break;    // 處理PUSH指令                            
      case OP_POPB:LoadByte(R[ra], m, SP); SP++; break;      // 處理POPB指令                            
      default: printf("Error:invalid op (%02x) ", op);              
      
                        // Cpu0Dump(cpu0);                                    
    }                                                                                                 
    sprintf(buffer, "PC=%08x IR=%08x SW=%08x R[%02d]=0x%08x=%d\n", // 印出 PC, IR, R[ra]暫存器的值,以利觀察
                         PC,      IR,     SW,  ra,    R[ra],R[ra]);

   // Cpu0Dump(cpu0);                                // 傾印暫存器
    strToUpper(buffer);
    printf(buffer);
  }                                                                                                   
}                                                                                       
                                                                                        
void Cpu0Dump(Cpu0 *cpu0) {                                  // 印出所有暫存器                           
  printf("\n===CPU0 dump registers===\n");                                                            
  printf("IR =0x%08x=%d\n", cpu0->IR, cpu0->IR);             // 印出 IR                                                                           
  int i;                                                                   
  for (i=0; i<16; i++)                                       // 印出 R0..R15  
    printf("R[%02d]=0x%08x=%d\n",i,cpu0->R[i],cpu0->R[i]);
}

Assembler

追到這邊還不能確定我們的 cpu 有沒有錯
簡化分析
sum = 10;

return sum;

我們做最簡化的帶入數值給 sum
原本程式碼
    case 'L' :                                                                                      
      sscanf(args, "R%d %s", &ra, p2);                                        
      if (strHead(p2, "[")) {                                                  
        sscanf(p2, "[R%d+%s]", &rb, pt);                                       
        if (sscanf(pt, "R%d", &rc)<=0)                                         
          sscanf(pt, "%d", &cx);                                               
      } else if (sscanf(p2, "%d", &cx)>0) {                                    
      } else {                                                             
        AsmCode *labelCode = HashTableGet(a->symTable, p2);                    
        cx = labelCode->address - pc;                                      
        rb = 15; // R[15] is PC                                            
      }                                                                         
      sprintf(cxCode, "%8x", cx);                                              
      sprintf(objCode, "%2x%x%x%s", code->opCode, ra, rb, &cxCode[4]);         
      break;     
修改後,應該只是應急的方式不過我們的 ASM 確實可以讀的到值,
    case 'L' :                                                                                      
      sscanf(args, "R%d %s", &ra, p2);          
      int p23= atoi(p2);       
              // printf("%d\n",p23)      ;                             
      if (strHead(p2, "[")) {                                                  
        sscanf(p2, "[R%d+%s]", &rb, pt);                                       
        if (sscanf(pt, "R%d", &rc)<=0)                                         
          sscanf(pt, "%d", &cx);              
                                   
      }  else {                                                             
        AsmCode *labelCode = HashTableGet(a->symTable, p2);                    
        cx = labelCode->address - pc;                                      
        rb = 15; // R[15] is PC                                            
      }      
      if (p23 >=0 && cx == 0){
       sscanf(p2, "%d", &cx);   
           printf("%d\n",p23)      ;   
      }                   
                                               
      sprintf(cxCode, "%8x", cx);                                              
      sprintf(objCode, "%2x%x%x%s", code->opCode, ra, rb, &cxCode[4]);         
      break;                                                               
    case 'A' :    

可以發現我們的這邊 間接定址已經出來了。
那麼開始排除 CPU ,使用我們寫好的 CPU 去 RUN 我們的 OBJ 檔

可以發現 確實不是我們的 CPU 問題,那麼問題就是 在 ASM 產生 OBJ檔 無法 間接定址的問題。
我們用複雜一點的
sum = 0;
for (i=0; i<10; i++)
{
  sum = sum  +2;
}
return sum;

BASH ROOT@ /c0c test.c0 test.asm
=AsmFile:test.asm==
LDI R1 0
ST R1 sum
LDI R1 0
ST R1 i
FOR0:
LD R1 i
LDI R2 10
CMP R1 R2
JGE _FOR0
LD R1 sum
LDI R2 2
ADD R3 R1 R2
ST R3 T0
LD R1 T0
ST R1 sum
LD R1 i
LDI R2 1
ADD R3 R1 R2
ST R3 i
JMP FOR0
_FOR0:
LD R1 sum
RET
sum: RESW 1
i: RESW 1
T0: RESW 1
BASH ROOT@ /as0 test.asm test.obj
=PASS2==
0
0000 LDI R1 0 L 8 08100000
0004 ST R1 SUM L 1 011F004C
0
0008 LDI R1 0 L 8 08100000
000C ST R1 I L 1 011F0048
0010 FOR0: FF
0010 LD R1 I L 0 001F0044
10
0014 LDI R2 10 L 8 0820000A
0018 CMP R1 R2 A 10 10120000
001C JGE _FOR0 J 25 2500002C
0020 LD R1 SUM L 0 001F0030
2
0024 LDI R2 2 L 8 08200002
0028 ADD R3 R1 R2 A 13 13312000
0
002C ST R3 T0 L 1 01300000
0
0030 LD R1 T0 L 0 00100000
0034 ST R1 SUM L 1 011F001C
0038 LD R1 I L 0 001F001C
1
003C LDI R2 1 L 8 08200001
0040 ADD R3 R1 R2 A 13 13312000
0044 ST R3 I L 1 013F0010
0048 JMP FOR0 J 26 26FFFFC4
004C _FOR0: FF
004C LD R1 SUM L 0 001F0004
0050 RET J 2C 2C000000
0054 SUM: RESW 1 D F0 00000000
0058 I: RESW 1 D F0 00000000
005C T0: RESW 1 D F0 00000000
BASH ROOT@ /vm0 test.obj
=CPU0 dump registers=
IR =0x2c000000=738197504
R[00]=0x00000000=0
R[01]=0x00000014=20
R[02]=0x0000000a=10
R[03]=0x0000000a=10
R[04]=0x00000000=0
R[05]=0x00000000=0
R[06]=0x00000000=0
R[07]=0x00000000=0
R[08]=0x00000000=0
R[09]=0x00000000=0
R[10]=0x00000000=0
R[11]=0x00000000=0
R[12]=0x40000000=1073741824
R[13]=0x00000000=0
R[14]=0xffffffff=-1

可以看到我們的 CPU 正常 WORK ,看來解決了書中 10 年前的 BUG ?XD 還是那時候編譯環境還可以正確運行也說不定。