CPU0 的組譯器 (程式範例)

作品

書籍

課程

程式集

小說集

論文集

散文集

影片集

編輯雜誌

程式人

電子書

JavaScript

計算語言學

微積分

Blender 動畫

C# 語言

系統程式

高等 C 語言

Java

Android

Verilog

Wikidot

R 統計軟體

機率統計

計算機數學

組合語言

人工智慧

開放原始碼

網路資源運用

計算機結構

相關訊息

常用工具

友站連結

在家教育

RSS

最新修改

網頁列表

簡體版

English

簡單的組譯範例

                 EX1  START   0x0100
00000100              LD      R1, B             T(0010010C)          T(001F0008)
00000104              ST      R1, A             T(01100108)          T(011F0000)
00000108         A    RESW    1                 T(00000000)          T(00000000)
0000010C         B    WORD    29                T(0000001D)          T(0000001D)
                      END     EX1

組譯器的第一階段演算法 (指定記憶體位址)

Algorithm AssemblerPass1                                        // 組譯器的第一階段演算法
input AssmeblyFile                                              // 輸入:組合語言檔
ouptut SymbolTable                                              // 輸出:符號表
begin
  SymbolTable = new Table;                                      // 建立空的符號表
  file = open(AssemblyFile)                                     // 開啟組合語言檔作為輸入
  while not file.end                                            // 當檔案還沒結束前,繼續讀檔
    line = readLine(file)                                       // 讀下一行
        if line is comment                                      // 如果該行為註解
          continue                                              //   則忽略此行,繼續下一輪迴圈
        label= label(line)                                      // 取得該行中的標記
        if label is not null                                    // 如果該行有標記
          symbolRecord = symbolTable.search(label)              //   於符號表中尋找該標記
          if symbolRecord is not null                           //     如果找到該標記
            report error                                        //   則報告錯誤 - 標記重複定義
        end if                                                  //
        op   = operator(line)                                   // 取得該行中的指令部分 (助憶符號)
        opRecord = opTable.search(op);                          // 於指令表中尋找該指令
        if opRecord is not null                                 // 如果找到該指令
          address += 4;                                         //   則將位址加4
                                                                //   (因為CPU0的每個指令都是 4 byte)
        else if op is 'START'                                   // 如果指令是 START
          address = (parameter 1 as integer)                    //   則將位址設定為參數 1 所代表的位址
        else if op is 'BYTE'                                    // 如果指令是 BYTE
          address += 1*length(parameters)                       //   則將位址加1
        else if op is 'WORD'                                    // 如果指令是 WORD
          address += 4 * length(parameters)                     //   則將位址加4 (CPU0的word是4 byte)
        else if op is 'RESB'                                    // 如果指令是 RESB
          address += length(parameter 1)                        //   則將位址加上參數所占的 byte 數目
        else if op is 'RESW'                                    // 如果指令是 RESW
          address += 4 * length(parameter 1)                    //   則將位址加上4*參數所占的Word數
        else                                                    // 如果不屬於上述情形之一,則代表該指令
          report error                                          //   可能拼寫有誤,於是顯示錯誤訊息
        end if 
  end while 
end

組譯器的第二階段演算法 (進行指令與資料編碼)

Algorithm AssemblerPass2                                        // 組譯器的第二階段演算法
input AssmeblyFile, SymbolTable                                 // 輸入:組合語言檔,符號表
ouptut ObjFile                                                  // 輸出:目的檔
begin
  file = open(AssemblyFile)                                     // 開啟組合語言檔作為輸入
  while not file.end                                            // 當檔案還沒結束前,繼續讀檔
    line = readLine(file)                                       // 讀下一行
    (op, params) = parse(line)                                  // 取得指令碼與參數
        opRecord = opTable.search(op)                           // 於指令表中尋找該指令
        if opRecord is not null                                 // 如果找到該指令
           objCode = translate(line, address, opRecord)         // 將指令轉換為目的碼
           address += length(objCode)                           // 計算下一個指令位址
        else if op is 'WORD' or 'BYTE'                          // 如果指令是 WORD 或 BYTE
           objCode = translateData(line)                        //   將資料轉換為目的碼
           address += length(objCode)                           // 計算下一個指令位址
        else if op is 'START'                                   // 如果指令是 START
          address = (parameter 1 as integer)                    //   則將記憶體位址設定為參數 1 所代表的位址
        else if op is 'RESB'                                    // 如果指令是 RESB
          address += length(parameter 1)                        //   則將記憶體位址加上參數所占的 byte 數
        else if op is 'RESW'                                    // 如果指令是 RESW
          address += 4 * length(parameter 1)                    //   則將記憶體位址加上4 *參數所占的Word數
        end if
        output ObjCode to ObjFile                               // 將目的碼寫入目的檔當中。
  end while
end

Algorithm translate                                             //轉換指令為目的碼。
Input line, pc, opRecord                                        // 輸入:指令、程式計數器
Output objCode                                                  // 輸出:目的碼
  if (opRecord.type is L)                                       // 如果是L型指令
    Ra = parameters[1]                                          // 設定 Ra 參數
    if (parameters[3] is Constant)                              // 如果是常數
      Cx = toInteger(parameter[2]);                             //  設定 Cx為該常數。
    if (parameters[3] is Variable)                              // 如果是變數
      Cx = address(Variable) - pc                               //  設定 Cx為位移 (標記-PC)。
      Rb = parameters[2]                                        //  設定 Rb 參數。
    end if 
    objCode = opRecord.opCode+id(Ra)+hex(Cx);                   // 設定目的碼。
  else if (op.type is A)                                        // 如果是A型指令
    Ra = parameter[1]                                           // 取得 Ra
    Rb = parameter[2]                                           // 取得 Rb
    Rc = parameter[3]                                           // 取得 Rc
    objCode = opRecord.opCode+id(Ra)+id(Rb)+id(Rc)              // 將目的碼寫入目的檔當中。
    …                                                          // … 處理 A型與資料宣告…
End

完整的組譯範例 (相對於PC定址)

記憶體位址  程式碼                                  目的碼
            MAIN    START
00000000            LD     R1, x                    T(001F000C)
00000004            LDI    R2, 4                    T(08200004)
00000008            JSUB   sum                      T(2B000018)
0000000C            ST     R3, y                    T(013F0010)
00000010    x       WORD   1, 7, 3, 6               T(00000001) T(00000007)
                                                    T(00000003) T(00000006)
00000020    y       RESW   1                        T(00000000)

            sum:
00000024            MOV     R4, R0                  T(12400000)
00000028            MOV     R5, R0                  T(12500000)
0000002C            LDI     R6, 1                   T(08600001)
            FOR:
00000030            CMP     R5, R2                  T(10520000)
00000034            JGE     EXIT                    T(2500000C)
00000038            ADD     R4, R4, R5              T(13445000)
0000003C            ADD     R5, R5, R6              T(13556000)
00000040            JMP     FOR                     T(26FFFFEC)
            EXIT:
00000044            RET                             T(2C000000)
00000048    i       RESW    1                       T(00000000)
0000004C    s       WORD    0                       T(00000000)
            END     MAIN

完整的輸出目的碼

T {
  001F000C 08200004 2B000018 013F0010
  00000001 00000007 00000003 00000006
  00000000 12400000 12500000 08600001
  10520000 2500000C 13445000 13556000
  26FFFFFEC 2C000000 00000001 00000000
}

存取超過定址範圍的資料

EX1   START   0x0100                        EX1     START   0x0100
      LD      R1, B                                 LD      R9, Base
      ST      R1, A                                 LD      R1, R9+B-A
X     RESW    100000                                ST      R1, R9+A-A
A     RESW    1                             X       RESW    100000
B     WORD    29                            A       RESW    1
      END     EX1                           B       WORD    29
                                            Base    WORD    &A
                                                    END     EX1

常數值的寫法

…
        LD R1, EOF
WLOOP:  ST R1, oDev
…
EOF     BYTE =C'EOF'
oDev    WORD =X'FFFFFF00'

實字 (Literal) 的組合語言程式範例

…                                           …
        LD R1, =C'EOF'                               LD R1, $L1
WLOOP:  ST R1, =X'FFFFFF00'                  WLOOP:  ST R1, $L2
…                                           …
                                             $L1     BYTE =C'EOF'
                                             $L2     WORD =X'FFFFFF00'

以 LTORG 提早展開實字的範例

…                                           …
        LD     R1, =C'EOF'                           LD     R1, $L1
WLOOP:  ST     R1, =X'FFFFFF00'              WLOOP:  ST     R1, $L2
        LTORG                                        LTORG
BUFFER  RESW   65536                         $L1     BYTE   =C'EOF'
…                                           $L2     WORD   =X'FFFFFF00'
                                             BUFFER  RESW   65536
                                             …

使用EQU假指令的組合語言程式片段

MAXLEN  EQU 4096
PC      EQU R15
LR      EQU R14
SP      EQU R13
…
LD      R1, #MAXLEN
MOV     LR, PC
MOV     SP, R1
…

使用EQU進行相對位址模擬 C語言的 struct 結構

person  RESB 24                           struct person {
name    EQU  person                         char name[20];
age     EQU  person + 20                    int age;
…                                        }

使用EQU與星號 * 模擬 C語言的 struct 結構

person  EQU *                             struct person {
name    RESB 20                             char name[20];
age     RESW 1                              int age;
…                                        }

使用ORG假指令的組合語言程式片段

person  RESB 240                          struct {
        ORG person
name    RESB 20                             char name[10];
age     RESW 1                              int age;
size    EQU *-person
        ORG                               } person[10];
sum     WORD 0                            int sum = 0;
…

使用運算式計算陣列大小的組合語言程式片段

BUFFER RESB 4096
BUFEND EQU *
BUFLEN EQU BUFEND-BUFFER

以USE區塊解決巨大陣列所造成的定址問題

        LD R1, EOF                                LD R1, EOF
WLOOP:  ST R1, oDev                       WLOOP:  ST R1, oDev
        RET                                       RET
BUFFER  RESB 65536                                USE CBLKS
EOF     RESW =C'EOF'                      BUFFER  RESB 65536
oDev    WORD =X'FFFFFF00'                         USE
                                          EOF     RESW =C'EOF'
                                          oDev    WORD =X'FFFFFF00'

Facebook

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License