# 大二下 - System Software - Note ###### tags: `大二下` `系統程式` --- ***系統程式*** CH1 Background === :bulb:skip不考的部分 >1-3 >>SIC Programming Examples (Bulk are Skipped!) 利用loader或linker將轉換的機器語言程式載入到記憶體中執行 ``` SIC這個電腦的架構可以代表->大多數硬體所具備的特性和概念且避免真實機器上大部分的特殊性質 在標準SIC機器上可以執行的程式都可以在XE系統上執行 向上相容之特性與真實機器一樣 ``` * SIC(Simple Instruction Computer) * 記憶體 >由bytes(8-bit)組成 >3個連續bytes => word(24-bits) >電腦的記憶體共 = 32768(2^15)個bytes * 暫存器 >5個 都有特定用途 >LENGTH = 24-bits = 3 bytes >![](https://hackmd.io/_uploads/H1SmAmCLn.png) >A = 累加暫存器 - 算術運算 >X = 索引暫存器 - 定址 >L = 連結暫存器 - JSUB跳到副程式 - 將return位址放這 >PC = 程式計數器 - 存下一個要取出的command位址 >SW = 狀態字組 - 存條件碼(CC) * 資料格式 >Int = 24位元二進制 負數用2's >char = ASCII (附錄B) >沒有硬體float運算器 * 指令格式 >24-bits >x = flag bit x => indexed-addressing mode >![](https://hackmd.io/_uploads/HyO6JNA8n.png) * 定址模式 >看x位元 >2種 >TA = target address >![](https://hackmd.io/_uploads/ByDNx4CLh.png) >(X) = (register or 記憶體位址) * 指令集 >(附錄A) >這邊列幾個 >``` >1.載入: LDA LDX >2.儲存: STA STX >3.COMP: 比較 reg A & 記憶體中數值 >4.JSUB: 跳到副程式 將return位址放 reg L >5.RSUB: 跳到reg L儲存的位址 >``` * I/O >reg 右邊 8個bit開始 >一次執行一個byte >每個device都有一組8-bit的device code :::info :wave: 插播一則快訊: TD(test device)指令 測試指定位址的device是否已就緒 -> 傳送or接收一個byte 測試的結果塞在CC < : ready = : not ready ::: * SIC/XE * 記憶體 >1M bytes(2^20) >導致指令&定址模式改變 * 暫存器 >![](https://hackmd.io/_uploads/BJepmV0Lh.png) >B = 定址用 >S & T = 一般 >F = float累加器(48-bits) * 資料格式 >**跟SIC一樣** >下面是SIC/XE多的一個floating data格式(SIC沒有float) > >48-bits >s = 0正1負 >exponent = 指數 >fraction = 0~1 最高位元必須=1 >![](https://hackmd.io/_uploads/rytXVVCI2.png) >![](https://hackmd.io/_uploads/SyiLHVRI3.png) * 指令格式 >用相對位址(Format 3) >or >把位址延伸成20-bits(Format 4) > >Format 1 & 2 不用參考記憶體的指令 >![](https://hackmd.io/_uploads/Hki58B0Lh.png) >![](https://hackmd.io/_uploads/Hk8o8B0U2.png) >![](https://hackmd.io/_uploads/HJXn8HRUh.png) >B mode: 12-bit = unsigned >PC mode: 12-bit = signed >![](https://hackmd.io/_uploads/SyzTLHR83.png) >e 可以分出3&4: >e = 0 -> 3 >e = 1 -> 4 >dsip = 位移量 * 定址模式 >![](https://hackmd.io/_uploads/HJDfuH0U3.png) >``` >討論 3 & 4 如何使用目的位址(TA): >n=0, i=1:目的位址=運算元的值,不用參考記憶體的值=>立即定址(immediate) >n=1, i=0:取出目的位址裡的byte值=運算元的位址=>間接定址(indirect) >n=i:目的位址=運算元的位址=>簡單定址(simple) >``` >if x bit = 1: 把index暫存器內容也一起加入 :star: SIC只能用**直接模式** 不用看index :warning: index mode不能跟immediate或indirect一起用 * 指令集 >可支援標準版中所有command >針對新register存取data **LDB STB** >浮點運算 **ADDF AUBF MULF DIVF** >暫存器運算 **ADDR SUBR MULR DIVR** >產生中斷 SVC (supervisor call) >RMO(暫存器移動) * I/O * CPU在跑時 還可以通過I/O channel 繼續輸入輸出 * 同時計算 + I/O :100: 補充:The current x86-64 design “contains 981 unique mnemonics and a total of 3,684 instruction variants”. CH2 Assemblers === :bulb:skip不考的部分 >2-3 >>Literals (Skip) >>Symbol-Defining Statements (Skip ORG) >>Forward Reference (Skip!) >>Expressions (skip!) >>Program Blocks (Skip!) >> >2-4 >>External References in Expression (Skip!) >>Forward Reference Handling in One-pass Assembler (Skip!) >> >2.5 Implementation Examples (Skip!) :::danger 這章節很重要 但我想睡覺了... :sleepy: :sleepy: :sleepy: 寫完SIC作業就會這章了~吧 :+1: :+1: :+1: ::: 參照[[SIC-README](https://hackmd.io/@simoneYC/HJmzQpeDn)] CH3 Loaders and Linkers === >only 3-1 & 3-2 * 絕對loader * 一個階段(single pass)即可完成 * 讀取到End record時 -> loader跳到標示的位址 -> 執行 * 每個字元代表object program中的一個**BYTE** * ![](https://hackmd.io/_uploads/HJhZSjEv2.png) * **xxxx表示不是來自文字Text record(內容未改變)** * 每個字元代表memory中一個Hex的**數值** * ![](https://hackmd.io/_uploads/S1DzSjNPh.png) * 缺點: * 載入程式到memory時 必須指出實際位址 * SIC/XE這種大型先進的機器會很困難 -> 可能同時執行多個程式 * 解決: * 重新寫一個<可重定址程式(relocatable programs)> * 事先給定絕對位置對使用效率很差 * 可重定址relocating loader (or 相對relative loader) * 2種方法: 1. 用修正紀錄(Modification record)找到object code需要修改的part * only前方有 + 的line會被重定址影響(延伸格式指令包含實際位址) * ![](https://hackmd.io/_uploads/rJ8sKsNDh.png) * 修正紀錄要包含 1. 修改那個值的起始位址 2. 欄位長度 * ![](https://hackmd.io/_uploads/SkoEso4vh.png) 2. 用位元遮罩(bit mask) (skip!) * 因為標準版SIC不能用相對位址 * 外部引用(external reference) * **PROGA** * REF1-REF3 = 指令運算元 / REF4-REF8 資料的值 * REF1引用程式中的label -> 用\'PC相對指令\'組譯 * 不用重定址 * ![](https://hackmd.io/_uploads/rk-7hoVvn.png) * **PROGB** * LISTA是外部引用 * 需要延伸格式的指令 +LDA * 並在object program包含一個修正紀錄 * ![](https://hackmd.io/_uploads/SyR22oVw3.png) * **PROGC** * REF4結合了重定址&外部引用 * ![](https://hackmd.io/_uploads/SJuahoVDn.png) * link loader * 也用**修正紀錄**處理重定址 * two-pass * 1.指派位址給所有外部符號 * 2.完成實際載入,重定址,連結 * **ESTAB** (~SYMTAB) * 儲存控制段以外的的外部符號(名稱+地址) * 也要指出定義在哪一個控制段 * hash * **PROGADDR**(程式載入位址) * OS提供 * **CSADDR**(控制段位址) * 包含載入器正在處理控制段的起始位址 * 加上控制段相對位址 -> 實際位址 * **pass1 ** * loader只看Header record & Define record * PROGADDR的位址 = 第一個控制段起始位址(CSADDR) * 來自Header紀錄的控制段 -> ESTAB 值=CSADDR * 出現在Define紀錄的 -> ESTAB 值=Define裡的+CSADDR * CSLTH + CSADDR = 下一個控制段起始位址 * 0063 + 4000 = 4063 下一個 * ![](https://hackmd.io/_uploads/ByHqU3Nv3.png) * pass2 * 遇到修正紀錄時 去ESTAB查符號 加加減減 * 在控制段END record上可指定第一個可執行指令位址(transfer point) CH4 Macro Processors === >only 4-1 **巨集** * MACRO * 指出巨集定義的開始 line 10 * ![](https://hackmd.io/_uploads/B12PQaEPh.png) * 參數以&開始 * ![](https://hackmd.io/_uploads/ryjjXp4Pn.png) * MEND * 標示巨集的結尾 line 95 >巨集主體內的註解會被刪除 >個別敘述的註解會保留 >主體內**沒label** >**巨集呼叫那行會被塞進程式中成為註解** * 副程式 V.S 巨集 * **副程式** : 不管呼叫幾次 敘述都只顯示一次 * **巨集** : 每次呼叫都產生+組譯巨集展開的敘述 * >差別是**顯示次數** * two pass * pass1 * 處理巨集定義 * pass2 * 處理所有巨集呼叫敘述的展開 > 不允許巨集指令主體中含有其他巨集的定義 * one pass * 在 定義 & 展開 間切換 * Data struct 1. DEFTAB定義資料表 - 儲存定義 >macro prototype >構成巨集主體的敘述(含有修正data) >comment line 不會進入DEFTAB 2. NAMTAB名稱資料表 - 巨集名字 >作為DEFTAB的index >有pointer指向DEFTAB開始&結束處 3. ARGTAB引數資料表 - 巨集呼叫的展開時間 >呼叫macro -> 根據引數清單中位置 -> 把引數存到ARGTAB >ARGTAB的引數會取代巨集主體的參數 ![](https://hackmd.io/_uploads/BkeY9pVv2.png) :::info :bulb: 1. call RDBUFF 2. NAMTAB找index 3. 讀DEFTAB(RDBUFF的) 4. 遇到第一行參數(&)改 ?n 5. 去ARGTAB找n 轉換引數成功~ ::: * Algorithm - 單階段 * ![](https://hackmd.io/_uploads/SJaLipEP3.png) * DIFINE * 讀取到定義起始點時呼叫 * 把東西存進DEFTAB & NAMTAB * ![](https://hackmd.io/_uploads/BJnwsaNPn.png) * EXPAND * 用來在ARGTAB中設定引數值 * 展開巨集呼叫敘述 * ![](https://hackmd.io/_uploads/rJSdjpEPn.png) * GETLINE * 多個位置上呼叫 * 讀取下一行敘述 * ![](https://hackmd.io/_uploads/Bkpds64Pn.png) :bulb: 這裡有個問題 ![](https://hackmd.io/_uploads/rkDKh6Ew2.png) :::warning line 3 的MEND會被誤認是MACROS的結束 DEFINE維護一個計數器 - LEVEL 每次讀到MACRO指引時 LEVEL + 1 每次讀到MEND LEVEL - 1 when LEVEL == 0 才是真的END :::