1. 程式人生 > 實用技巧 >echarts玩轉圖表之矩形樹圖

echarts玩轉圖表之矩形樹圖

一、實驗目的

1.理解和掌握將資料、程式碼、棧放入不同邏輯段的程式的編寫和除錯2.理解具有多個段的彙編源程式對應的目標程式執行時,記憶體分配方式3.掌握大小寫字元的轉換方法、數字字元和數值之間的轉換方法
4.理解並掌握各種定址方式的靈活應用
5.掌握彙編指令loop, and, or,div, mul的用法

二、實驗準備

複習教材chapter 6-8章。

chapter 6包含多個段的程式

chapter 7更靈活的定位記憶體地址的方法

chapter 8資料處理的兩個基本問題

三、實驗內容與結論

1.實驗任務1

使用任意文字編輯器,錄入彙編源程式task1.asm。

assume cs:code, ds:data
data segment
db 'Nuist'
        db 5 dup(2)
data ends
code segment
start:
mov ax, data
mov ds, ax
mov ax, 0b800H
mov es, ax
mov cx, 5
mov si, 0
mov di, 0f00h
s:      mov al, [si]
        and al, 0dfh
        mov es:[di], al
        mov al, [5+si]
        mov es:[di+1], al
        
inc si add di, 2 loop s mov ah, 4ch int 21h code ends end start

使用masm、link對task1.asm進行彙編、連結,得到可執行檔案task1.exe,執行並觀察結果。

使用debug工具對程式進行除錯,執行到程式返回前,即line27之前,觀察結果。 修改line4裡5個位元組單元的值,重新彙編、連結、執行,觀察結果。

輸出結果:

通過閱讀程式原始碼以及逐步除錯可以看出,15-25行的loop從資料段中讀出字資料(字元的ascii碼值),向視訊記憶體指定位置輸出。

資料段中db 5 dup(2)表示定義5個重複位元組,資料值都為十進位制2,在loop中使用mov al, [5+si]讀出並且輸出,用於設定顯示顏色。

2.實驗任務2

已知資料段data中定義位元組資料如下:

data segments
    db 23, 50, 66, 71, 35
data ends

注意這裡位元組資料為十進位制,在d命令檢視記憶體時顯示十六進位制的資料

task2程式碼

assume cs:code, ds:data
data segment
        db 23,50,66,71,35
data ends

code segment
start:
        mov ax, data
        mov ds, ax

        mov ax, 0b800H
        mov es, ax

        mov cx, 5
        mov si, 0
        mov di, 0f00h
s:      mov al, [si]
        mov dx,0
        mov ah,0
        mov bx,10
        div bx
        add al,48
        add dl,48
        mov es:[di], al
        mov al,dl
        mov es:[di+2], al
        inc si
        add di, 6
        loop s

        mov ah, 4ch
        int 21h
code ends
end start

task2程式碼基於task1程式碼進行理解修改得出

思路:

迴圈之前先把資料段地址存放到ds,輸出的視訊記憶體地址存放到

迴圈時先讀出資料,資料在資料段中db存放,是單位元組資料,所以將存放資料的暫存器高位設定為0。

被除數存放在ax,除數存放在bx,利用除法指令div,商存放在ax中,餘數存放在dx中,計算出十位和個位上的數值。

利用數值和數字字元之間ascII碼的關係,把各位上的數值加上48,十六進位制0030h,得出相應字元

利用系統功能呼叫int 21h中的2號子功能,輸出單個字元,視訊記憶體位置自增6位元組(兩個資料,一個空格),資料段迴圈偏移量自增1個位元組。

輸出效果:

需要注意的是,dx初始為0,第一次運算後有垃圾資料殘餘,為了防止程式出錯每次迴圈後dx需要賦值為0。

參考:https://stackoverflow.com/questions/13028561/assembly-division

3.實驗任務3

程式原始碼task3.asm

assume cs:code, ds:data, ss:stack
data segment
  dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h
data ends

stack segment
  dw 0, 0, 0, 0, 0, 0, 0, 0
stack ends

code segment
start:  mov ax,stack
        mov ss, ax
        mov sp,16
        
        mov ax, data
        mov ds, ax
        
        push ds:[0]
        push ds:[2]
        pop ds:[2]
        pop ds:[0]
        
        mov ax,4c00h
        int 21h

code ends
end start

課本填空:

程式返回前,data段中的資料:

程式返回前,cs、ss和ds的值:

程式載入後,code段地址為X,data段地址為X-32,stack段地址為X-16。

4.實驗任務4

程式原始碼task4.asm:

assume cs:code, ds:data, ss:stack
data segment
  dw 0123h, 0456h
data ends

stack segment
  dw 0, 0
stack ends

code segment
start:  mov ax,stack
        mov ss, ax
        mov sp,16
        
        mov ax, data
        mov ds, ax
        
        push ds:[0]
        push ds:[2]
        pop ds:[2]
        pop ds:[0]
        
        mov ax,4c00h
        int 21h

code ends
end start

程式返回前,data段中資料:

程式返回前,cs、ss和ds的值:

程式載入後,code段地址為X,data段地址為X-32,stack段地址為X-16。

對於如下定義的段

name segment
...
name ends

如果段中資料佔N個位元組,程式載入後,該段實際佔有的空間為N/16+16位元組,即能容納資料的最小16位元組的整數倍。

5.實驗任務5教材

程式原始碼task5.asm:

assume cs:code, ds:data, ss:stack

code segment
start:  mov ax,stack
        mov ss, ax
        mov sp,16
        
        mov ax, data
        mov ds, ax
        
        push ds:[0]
        push ds:[2]
        pop ds:[2]
        pop ds:[0]
        
        mov ax,4c00h
        int 21h

code ends
data segment
  dw 0123h, 0456h
data ends

stack segment
  dw 0,0
stack ends
end start

程式返回前,data段中資料:

程式返回前,cs、ss和ds的值:

程式載入後,code段地址為X,data段地址為X+48,stack段地址為X+64。

6.實驗任務6

(1)(2)均無法正常執行

(3)不受影響

說明原因:

如果程式末尾為end start,CPU知道程式從start:處開始執行;如果程式末尾end,將從頭執行。

參考:王爽教材P126

由於實驗(1)task3和實驗(2)task4的資料段在code segment之前,將資料段中的資料作為指令讀出執行肯定是不正確的。實驗(3)task5中從code segment正確執行退出,從而不會進入到code segment一下的資料段中。

7.實驗任務7

教材「實驗5編寫、除錯具有多個段的程式」(5)程式原始碼見task7.asm。

注*:如果在整合軟體環境下編寫、彙編這個實驗任務,請將段名為c的邏輯段,名稱改為c1或別的標識 符。由於早期一些指令集中使用c指代暫存器,如不更正,有些彙編器在彙編時會報錯。

assume cs:code
a segment
  db 1,2,3,4,5,6,7,8
a ends

b segment
  db 1,2,3,4,5,6,7,8
b ends

c segment
  db 8 dup(0)
c ends

code segment
start:
  mov si,0
  mov cx,8
  s: mov ax,a
  mov ds,ax
  mov dl,[si]
  mov ax,b
  mov ds,ax
  add dl,[si]
  mov ax,c
  mov ds,ax
  mov [si],dl
  mov dx,0
  add si,1
  loop s

  mov ah, 4ch
  int 21h
code ends
end start

由於知道的暫存器太少,這裡實現使用了笨辦法,每次從一個數據段中讀出資料後,將ds賦值為另一個數據段的其實地址。

這裡使用了dl儲存資料進行計算,是因為資料段中定義的資料是db單位元組資料。然而這裡使用dx作為儲存資料,一次寫入兩個byte資料,由於這裡資料不存在加法溢位的顧慮,也能達到同樣的效果。

執行task7後資料段c中的資料:

8.實驗任務8教材

「實驗5編寫、除錯具有多個段的程式」(6)

程式原始碼:task8.asm

assume cs:code
a segment
  dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh
a ends

b segment
  dw 8 dup(0)
b ends

code segment
start:
  mov ax,a
  mov ds,ax
  mov ax,b
  mov ss,ax
  mov sp,16
  mov cx,8
  mov si,0
  s:
  push ds:[si]
  add si,2
  loop s

  mov ah, 4ch
  int 21h
code ends
end start

資料段a有16個雙位元組字資料,佔了32byte,該程式題沒有設定棧段,所以顯然不是用棧段作為中間容器實現逆序。經過思考,棧低為高址,每次push棧頂向低址移動,也可以實現逆序存放,所以將資料段b的末尾設定為棧低ss:sp。用loop重複讀取資料壓棧操作。

執行結果:

資料段a:076A:0000 ~ 076A:001f

資料段b:076A:0020 ~ 076A:002f

可以看出實現了逆序儲存

四、實驗總結

1、看清資料段是dw資料還是db資料,以及題目要求是什麼大小的資料。

2、實驗2困惑了很久,起初頭腦不清醒,找不到資料段中的資料。後來發現.asm原始碼中資料段是十進位制資料,在debug中-d命令時顯示十六進位制。

3、dx初始為0,第一次運算後有垃圾資料殘餘。除法運算為了防止程式出錯,每次迴圈後dx需要重新賦值為0。

4、關於彩色文字模式一般在B800h段,單色文字在B000h段;圖形模式在A000h段。task1設定es為0b800h。在文字16色模式下,字元的屬性儲存在bl中,bl為一個位元組大小,共八位。b7控制字元是否閃爍,b6-b4為背景色,b3-b0為前景色。

參考:https://blog.csdn.net/cgzldfend/article/details/80325125