學(xué)習(xí)筆記
《x86匯編語言:從實(shí)模式到保護(hù)模式》
http://www.itdecent.cn/p/d481cb547e9f
習(xí)題9-1:對(duì)8259芯片編程,屏蔽除RTC外的其他所有中斷,觀察字符“@”的變化速度
運(yùn)行結(jié)果
- 屏蔽完除了RTC以外的所有中斷后,字符@的變化速度和秒的變化同步
習(xí)題9-1:對(duì)8259芯片編程,屏蔽除RTC外的其他所有中斷,觀察字符“@”的變化速度
完整源碼(根據(jù)配書代碼 c09_1.asm 修改而來)
;======================================================================
;用戶程序開始
;======================================================================
;代碼清單9-1
;文件名:code_9-1.asm
;文件說明:用戶程序
;代碼功能:顯示動(dòng)態(tài)時(shí)鐘
;創(chuàng)建日期:7:20 2018/5/27
;======================================================================
;頭部段
;======================================================================
SECTION header vstart=0
;用戶程序長(zhǎng)度
program_length dd program_end ;[0x00]
;用戶程序入口地址
code_entry dw start ;[0x04]
dd section.code.start ;[0x06]
;段重定位表項(xiàng)長(zhǎng)度
realloc_tbl_len dw (header_end - realloc_begin)/4 ;[0x0a]
;段重定位表項(xiàng)
realloc_begin:
code_segment dd section.code.start ;[0x0c]
data_segment dd section.data.start ;[0x14]
stack_segment dd section.stack.start ;[0x1c]
header_end:
;======================================================================
;代碼段
;======================================================================
SECTION code align=16 vstart=0
;-------------------------------------------------------------------------------
;0x70號(hào)中斷程序
;-------------------------------------------------------------------------------
new_int_0x70: ;新的0x70中斷
;在屏幕上顯示 時(shí)分秒
push ax
push bx
push cx
push dx
push es
;讀RTC寄存器A,根據(jù)UIP位的狀態(tài)來決定是等待更新周期結(jié)束還是繼續(xù)往下執(zhí)行
.w0:
mov al,0x0a ;阻斷NMI RTC寄存器A 第7位UIP位
or al,0x80
out 0x70,al
in al,0x71
test al,0x80
jnz .w0
;更新周期結(jié)束中斷
xor al,al ;al = 0
or al,0x80
out 0x70,al
in al,0x71 ;讀RTC當(dāng)前時(shí)間(秒)
push ax
mov al,2
or al,0x80
out 0x70,al
in al,0x71 ;讀RTC當(dāng)前時(shí)間(分)
push ax
mov al,4
or al,0x80
out 0x70,al
in al,0x71 ;讀RTC當(dāng)前時(shí)間(時(shí))
push ax
mov al,0x0c ;RTC寄存器C 開發(fā)NMI
out 0x70,al
in al,0x71 ;讀一下RTC的寄存器C,否則只發(fā)生一次中斷
mov ax,0xb800
mov es,ax
pop ax
call bcd_to_ascii
mov bx,12*160+36*2 ;從屏幕上的12行36列開始顯示
mov [es:bx],ah
mov [es:bx+2],al ;顯示兩位小時(shí)數(shù)字
mov byte [es:bx+4],':'
not byte [es:bx+5]
pop ax
call bcd_to_ascii
mov [es:bx+6],ah
mov [es:bx+8],al ;顯示兩位分鐘數(shù)字
mov byte [es:bx+10],':'
not byte [es:bx+11]
pop ax
call bcd_to_ascii
mov [es:bx+12],ah
mov [es:bx+14],al ;顯示兩位秒鐘數(shù)字
mov al,0x20 ;中斷結(jié)束命令EOI(End Of Interrupt)
out 0xa0,al ;向8259芯片從片(Slave)發(fā)送EOI
out 0x20,al ;向8259芯片主片(Master)發(fā)送EOI
pop es
pop dx
pop cx
pop bx
pop ax
iret
;-------------------------------------------------------------------------------
;子程序: bcd_to_ascii
;參數(shù): AL = BCD碼
;返回: AH 十位數(shù)的ASCII碼
; AL 個(gè)位數(shù)的ASCII碼
;-------------------------------------------------------------------------------
bcd_to_ascii: ;新0x70中斷中調(diào)用的子程序
;將BCD碼轉(zhuǎn)換成ASCII
mov ah,al
and al,0x0f
add al,0x30 ;個(gè)位數(shù)的ASCII碼
shr ah,4
and ah,0x0f
add ah,0x30 ;十位數(shù)的ASCII碼
ret
;-------------------------------------------------------------------------------
;用戶程序入口
;-------------------------------------------------------------------------------
start: ;用戶程序入口
;設(shè)置寄存器
mov ax,[stack_segment]
mov ss,ax
mov sp,ss_pointer
mov ax,[data_segment]
mov ds,ax
;顯示信息,調(diào)用子程序 put_string
mov bx,init_msg ;顯示初始信息
call put_string
mov bx,inst_msg ;顯示安裝信息
call put_string
;計(jì)算0x70號(hào)中斷在中斷向量表(IVT)中的入口地址
mov al,0x70
mov bl,4
mul bl
mov bx,ax
;將0x70號(hào)中斷的入口地址改寫為 cs:new_int_0x70
cli
push es
mov ax,0x0000
mov es,ax
mov word [es:bx],new_int_0x70 ;偏移地址
mov word [es:bx+2],cs ;段地址
pop es
;0x70 [索引端口],用來指定CMOS RAM內(nèi)的單元
;0x71 [數(shù)據(jù)端口],用來讀寫CMOS RAM相應(yīng)單元里的內(nèi)容
;現(xiàn)在要訪問的就是位于CMOS RAM中的RTC(REAL TIME CLOCK)
mov al,0x0b ;RTC寄存器B
or al,0x80 ;端口0x70的最高位(bit 7)是控制NMI的開關(guān),
out 0x70,al ; 0表示允許NMI中斷到達(dá)處理器、1表示阻斷所有NMI信號(hào)
mov al,0x12 ;設(shè)置“更新周期結(jié)束中斷”
out 0x71,al
mov al,0x0c ;RTC寄存器C
out 0x70,al
in al,0x71 ;讀一下RTC寄存器C,使之可以產(chǎn)生新的中斷信號(hào)
;處理 從片slave
mov al,0xfe ;0xfe = 1111 1110B 清除第0位(此位通過從片引腳IRO連接著RTC)
out 0xa1,al ;回寫寄存器
;處理 主片master
mov al,0xfb ;只打開引腳IR2 使從片連接上主片
out 0x21,al ;回寫
sti
;顯示信息,調(diào)用子程序 put_string
mov bx,done_msg
call put_string
mov bx,tips_msg
call put_string
;顯示標(biāo)志 @ 符號(hào)
mov cx,0xb800
mov ds,cx
mov byte [12*160+32*2],'@'
;創(chuàng)建循環(huán) 停機(jī)狀態(tài)響應(yīng)外部中斷恢復(fù)執(zhí)行
.idle:
hlt ;使CPU進(jìn)入低功耗狀態(tài),直到用外部中斷喚醒
not byte [12*160+32*2+1] ;反轉(zhuǎn)顯示屬性
jmp .idle
;-------------------------------------------------------------------------------
;子程序: put_string
;功能: 顯示字符串,字符串以0結(jié)尾
;-------------------------------------------------------------------------------
put_string: ;顯示串(0結(jié)尾)。
;輸入:DS:BX=串地址
mov cl,[bx]
or cl,cl ;cl=0 ?
jz .exit ;是的,返回主程序
call put_char
inc bx ;下一個(gè)字符
jmp put_string
.exit:
ret
;-------------------------------------------------------------------------------
put_char: ;顯示一個(gè)字符
;輸入:cl=字符ascii
push ax
push bx
push cx
push dx
push ds
push es
;以下取當(dāng)前光標(biāo)位置
mov dx,0x3d4
mov al,0x0e
out dx,al
mov dx,0x3d5
in al,dx ;高8位
mov ah,al
mov dx,0x3d4
mov al,0x0f
out dx,al
mov dx,0x3d5
in al,dx ;低8位
mov bx,ax ;BX=代表光標(biāo)位置的16位數(shù)
cmp cl,0x0d ;回車符?
jnz .put_0a ;不是。看看是不是換行等字符
mov ax,bx ;此句略顯多余,但去掉后還得改書,麻煩
mov bl,80
div bl
mul bl
mov bx,ax
jmp .set_cursor
.put_0a:
cmp cl,0x0a ;換行符?
jnz .put_other ;不是,那就正常顯示字符
add bx,80
jmp .roll_screen
.put_other: ;正常顯示字符
mov ax,0xb800
mov es,ax
shl bx,1
mov [es:bx],cl
;以下將光標(biāo)位置推進(jìn)一個(gè)字符
shr bx,1
add bx,1
.roll_screen:
cmp bx,2000 ;光標(biāo)超出屏幕?滾屏
jl .set_cursor
mov ax,0xb800
mov ds,ax
mov es,ax
cld
mov si,0xa0
mov di,0x00
mov cx,1920
rep movsw
mov bx,3840 ;清除屏幕最底一行
mov cx,80
.cls:
mov word[es:bx],0x0720
add bx,2
loop .cls
mov bx,1920
.set_cursor:
mov dx,0x3d4
mov al,0x0e
out dx,al
mov dx,0x3d5
mov al,bh
out dx,al
mov dx,0x3d4
mov al,0x0f
out dx,al
mov dx,0x3d5
mov al,bl
out dx,al
pop es
pop ds
pop dx
pop cx
pop bx
pop ax
ret
;======================================================================
;數(shù)據(jù)段
;======================================================================
SECTION data align=16 vstart=0
init_msg db 'Starting...',0x0d,0x0a,0
inst_msg db 'Installing a new interrupt 70H...',0
done_msg db 'Done.',0x0d,0x0a,0
tips_msg db 'Clock is now working.',0
;======================================================================
;棧段
;======================================================================
SECTION stack align=16 vstart=0
resb 256
ss_pointer:
;======================================================================
;尾部段
;======================================================================
SECTION program_trail
program_end:
;======================================================================
;用戶程序結(jié)束
;======================================================================
代碼說明
- 屏蔽完除了RTC中斷外的全部中斷
;處理 從片slave
mov al,0xfe ;0xfe = 1111 1110B 清除第0位(此位通過從片引腳IRO連接著RTC)
out 0xa1,al ;回寫寄存器
;處理 主片master
mov al,0xfb ;只打開引腳IR2 使從片連接上主片
out 0x21,al ;回寫
-
0xfe和0xfb是什么意思?
8259芯片主片以及從片各有一個(gè)IMR(中斷屏蔽寄存器),
該寄存器是8位寄存器,寄存器的值與8個(gè)引腳一一對(duì)應(yīng)(IR0~IR7),
從引腳而來的中斷信號(hào),0表示允許中斷,1表示阻斷中斷;
0xfe = 1111 1110B ,就是打開從片上的引腳IR0
使得 RTC 與從片相連,這樣RTC的中斷就可以傳到從片,并且從片上其余引腳全部阻斷;
0xfb = 1111 1011B,就是打開主片上的引腳IR2
使得 從片與主片相連,并且主片上其余引腳全部阻斷;
RTC-從片-主片-處理器
就連好了,并且除了RTC以外的中斷全部被屏蔽。

RTC-IR0-8259從片-IR2-8259主片.png
