《Xilinx FPGA設計與實踐教程》課件-第16章_第1頁
《Xilinx FPGA設計與實踐教程》課件-第16章_第2頁
《Xilinx FPGA設計與實踐教程》課件-第16章_第3頁
《Xilinx FPGA設計與實踐教程》課件-第16章_第4頁
《Xilinx FPGA設計與實踐教程》課件-第16章_第5頁
已閱讀5頁,還剩48頁未讀, 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第十六章PicoBlaze中斷16.1PicoBlaze中斷處理機制16.2外部中斷接口16.3軟件開發16.4設計舉例本章小結

16.1PicoBlaze中斷處理機制

16.1.1軟件中斷處理過程

與中斷相關的指令在13.2.9節中討論過。enableinterrupt和disableinterrupt指令使能和禁止中斷請求,對應地,還有兩個返回中斷指令:returnienable和returnidisable指令,用來返回到原來的中斷點。

典型的帶有中斷服務程序流程的軟件執行過程如圖16-1所示。它主要包括如下幾個部分:

(1)初始化enableinterrupt指令:用來允許中斷服務請求。由于中斷請求默認是禁止的,所以在初始化時需要打開。

(2)跳轉(jump)到指令存儲器最后一條指令(如3FF):跳轉到中斷服務子程序。

(3)中斷服務子程序:執行中斷請求服務,中斷服務程序必須以returni指令結束。假設正在執行adds0,s3指令時,有外部I/O有效中斷發生,則PicoBlaze執行中斷的步驟如下:

(1)完成當前執行指令;

(2)保存程序計數器內容,清除中斷標志i(置為0),保存零標志和進位標志,程序計數器置為3FF;

(3)在3FF地址執行jumpisr指令;

(4)執行中斷服務子程序;

(5)執行returni指令,恢復程序計數器和標志位;

(6)重新開始執行subs5,01指令。圖16-1中斷流程圖16.1.2中斷時序描述

中斷程序執行詳細的時序參數的描述如圖16-2所示。按照如圖16-2所示時序標注時間點描述基本時序如下:

(1)在t1時刻,外部中斷接口置位中斷信號,PicoBlaze此時繼續正常操作,執行完當前adds0,s3指令。

(2)在t2時刻,PicoBlaze發現有中斷信號來了,所以放棄執行下一條指令(subs5,01),而去執行call3FF指令。

(3)在t3時刻,PicoBlaze置位中斷響應信號,表示要對中斷請求進行處理,同時保存subs5,01指令的地址以及清零標志和進位標志,清除中斷。

(4)在t4時刻,PicoBlaze裝載并執行地址3FF的跳轉指令jumpisr,外部中斷接口電路響應中斷響應信號并撤銷中斷信號。

(5)在t5時刻,PicoBlaze開始執行中斷服務程序。圖16-2PicoBlaze中斷時序描述圖 16.2外部中斷接口

16.2.1單個中斷請求

如果在PicoBlaze系統外設中僅有一個I/O接口能夠產生中斷請求,中斷接口電路僅需要一個標志寄存器,如圖16-3所示。當中斷請求后,外部I/O接口電路置位中斷請求信號一個時鐘周期,置位中斷標志寄存器激活PicoBlaze的中斷輸入。如果PicoBlaze中斷允許,則它便通過置位中斷響應信號一個時鐘周期來響應中斷并清零中斷標志位。圖16-3單個請求中斷接口圖16.2.2多個中斷請求

在PicoBlaze系統中處理兩個或者多個中斷請求比較復雜。PicoBlaze必須決定處理哪個中斷請求,然后在接收中斷請求后清零對應的中斷標志寄存器,這就需要協調硬件接口和中斷服務子程序。

帶有兩個中斷請求的中斷接口如圖16-4所示。兩個獨立的中斷請求intrequest0和intrequest1連接兩個中斷標志觸發器。中斷標志觸發器的輸出通過一個或門產生最終的中斷請求信號。除此之外,這兩個信號同時連接到一個2選1選擇器的輸入端。當PicoBlaze發現中斷請求時,它不知道是哪個外設發出請求或者是否是兩個外設同時發出請求,中斷服務子程序必須首先輸入兩個請求信號,檢查其中斷優先級值,然后執行對應的服務程序。圖16-4多個中斷請求接口圖除此之外,PicoBlaze還需要清零對應的中斷標志觸發器。interrupt_ack信號不能直接用來清零中斷標志觸發器,因為它不知道哪一個外設請求剛才被PicoBlaze接受了。需要采用特殊的輸出邏輯譯碼電路產生一個清零脈沖信號clr。每個中斷標志觸發器的清零信號對應唯一的端口id號。在中斷服務子程序中,在決定接受哪一個中斷請求后,增加一條output指令。該指令實際上并不輸出任何數據,而是產生一個周期的脈沖信號,用來清零對應的中斷標志觸發器。 16.3軟件開發

16.3.1中斷處理主程序

基于微處理器的應用通常都采用下面軟件結構:

call

初始化程序

forever:

call

子程序任務1;

call

子程序任務2;

...

call

子程序任務n;

jumpforever;一些任務有可能包括I/O操作。在執行過程中,微處理器輪流檢查I/O狀態并對應進行處理。程序結構執行按照輪流循環處理的方式來操作,每個任務都在等待輪流到自己才能被執行。如果微處理器循環周期足夠短,以至于每個I/O請求都可以被檢查并及時執行,則這種輪換處理的方案可以正常運行。在有些應用中,存在一到兩個需要立即執行的請求,需要中斷機制來保證該請求得到及時處理。

由于中斷任何時候都可能發生,因而原始的輪流機制需要考慮中斷頻率并且每次中斷請求需要一定的執行時間。如果有多個中斷請求,則服務子程序就比較復雜。16.3.2中斷服務程序

中斷服務程序和子程序相類似,它掛起正常程序執行,先執行一個獨立的任務,然后再重新返回到原來的操作。然而,與子程序調用不同點在于中斷可以在任何時間發生,為了后來能夠返回到原來程序執行的地方,中斷服務程序必須保存PicoBlaze處理器的當前狀態。也就是說,中斷服務程序必須在返回正常程序流程之前保存在中斷服務子程序中所用到的臨時計算值或寄存器值。這個過程就稱為內容交換。由于PicoBlaze是一個8位微處理器,硬件支持的前后交換和時間片輪轉功能非常有限,所以通常需要在程序中完成這些功能并且保證中斷結構比較簡單。為了防止前后交換,可以將一些特定的寄存器在中斷程序中作為專用寄存器。 16.4設計舉例

16.4.1中斷接口

如圖16-5所示,框圖包括了硬件計數器和中斷接口以及新添加的輸出緩沖器。計數器為模500計數器,每500個時鐘周期產生一個單時鐘脈沖。由于計數器時鐘為50MHz,所以該時鐘脈沖的周期為0.1ms。由于僅有一個中斷請求,因而在中斷接口應設計標志觸發器。計數器產生的時鐘脈沖觸發標志寄存器,從而激活中斷信號。16.4.2中斷服務子程序開發

在中斷服務子程序中,使用兩個寄存器count_msb和count_lsb合并成一個16位的寄存器,來追蹤PicoBlaze產生的脈沖信號,當每次計數器中斷信號到來時,該寄存器加1,總共可以計數的最大時間為0.6s(216?×?1.01ms)。中斷相關代碼如下:

nameregse,count_msb;

nameregsf,count_lsb;

int_service_routine:

addcount_lsb,01;

addcycount_msb,00

returni

enable

;======================================

;interruptvector

;======================================

address3FF

jumpint_service_routine16.4.3匯編程序開發

根據設計目的,熟悉時序信息之后,可以針對LED顯示設計一個新的子程序display_mux_out來替換在第十五章中用到的disp_led子程序。如圖16-5所示,兩個輸出緩沖器用來存儲an和sseg信號,子程序的主要任務是存儲an模式,包括“1110”、“1101”、“1011”和“0111”,對應的七段數碼管模式周期性地輸出到相應寄存器,刷新率在幾百赫茲到1000Hz,每210個時鐘脈沖更新一次寄存器值,大約10ms。我們同樣使用led_pos寄存器來跟蹤顯示位置。使用中斷實現程序15-3,代碼需要做如下修改:

(1)增加定義新的端口和寄存器;

(2)用display_mux_out子程序替換原來的disp_led子程序;

(3)增加enableinterrupt指令在init子程序中使能中斷處理;

(4)在初始化程序中初始化led_pos、count_msb和count_lsb寄存器;

(5)增加中斷服務子程序。

修改之后的匯編代碼如程序16-1所示。圖16-5帶計數器的中斷接口圖

【程序16-1】帶硬件乘法器和UART接口的求平方電路。

;程序操作:

;從撥碼開關讀取a和b,計算a?×?a+b?×?b并在超級終端顯示結果和七段數碼管值

;=============================================

;數據常數

;=============================================

constanta_lsb,00

constantb_lsb,02

constantaa_lsb,04

constantaa_msb,05

constantbb_lsb,06

constantbb_msb,07

constantaabb_lsb,08

constantaabb_msb,09

constantaabb_cout,0A

constantled0,10

constantled1,11

constantled2,12

constantled3,13

;=============================================

;寄存器定義

;=============================================

;局部寄存器

nameregs0,data ;臨時數據寄存器

nameregs1,addr ;臨時存儲器和I/O端口地址

nameregs2,i ;通用循環計數器變量

;全局變量定義

nameregsc,switch_a_b ;當前撥碼開關輸入作為RAM存儲偏移地址

nameregsb,led_pos ;?LED顯示位置(0,1,2或3)

nameregse,count_msb ;計數脈沖計數器高8位

nameregsf,count_lsb ;計數脈沖計數器低8位

;===============================================

;端口定義

;===============================================

;------------輸入端口定義---------------------

constantrd_flag_port,00

;2位flag標志

(xxxxxxsc):

constantsw_port,01 ;?8位撥碼開關

;------------輸出端口定義---------------------

constantan_port,00

constantsseg_port,01

;==============================================

;主程序

callinit ;初始化

forever:

;主程序循環

callproc_btn ;檢查和處理按鈕

callsquare ;計算求平方

callload_led_pttn ;存儲LED顯示模式值到RAM中

calldisplay_mux_out ;動態掃描顯示LED

jumpforever

;================================================

;子程序:?init

;功能:執行初始化并清零寄存器和RAM值

;輸出寄存器:

;?switch_a_b:清零clearedto0

;臨時寄存器:data,i

;===============================================

init:

enableinterrupt

;清零寄存器

loadi,40 ;循環索引值初始化為64

loaddata,00

clr_mem_loop:

storedata,(i)

subi,01 ;循環減1

jump

nz,clr_mem_loop ;重復,直到i=0

;清零寄存器

loadswitch_a_b,00

loadled_pos,00

loadcount_msb,00

loadcount_lsb,00

return

;================================================

;子程序:proc_btn

;功能:檢查兩個按鍵并處理顯示

;輸入寄存器:

;switch_a_b:ramoffset(0為a,2為b)

;輸出寄存器:

;s3:存儲輸入端口標志

;switch_a_b:可交替鎖存0和2

;臨時寄存器:data,addr

;================================================

proc_btn:

inputs3,rd_flag_port ;獲取標志

;checkandprocesscbutton

tests3,01 ;檢查按鍵c標志

jumpz,chk_btns ;若未設置,則跳轉到chk_btns

callinit ;若設置,則執行初始化程序int

jumpproc_btn_done

chk_btns:

;檢查和處理按鍵s

tests3,02 ;檢查按鈕s標志位

jumpz,proc_btn_done ;標志未設置

inputdata,sw_port ;獲取撥碼開關值

loadaddr,a_lsb ;獲取數據a地址

addaddr,switch_a_b ;獲取地址偏移

storedata,(addr) ;寫數據到RAM中

;更新當前顯示位置

xorswitch_a_b,02 ;?switch_a_b在00和02之間鎖存

proc_btn_done:

return

;===============================================

;子程序名:load_led_pttn

;程序功能:讀取撥碼開關低三位輸入并將對應顯示值轉換成數碼管顯示形式,裝載到RAM中

;撥碼開關輸入譯碼值:000:a;001:b;010:a2;011:b2;其他a2+b2

;臨時寄存器:data,addr

;s6:從sw輸入數據

;其中所調用的hex_to_led、get_lower_nibble、get_lupper_nible可參考求平方和子程序

;=================================================

load_led_pttn:

inputs6,sw_port ;獲取撥碼開關輸入

sl0s6 ;?s6內容右移一位,獲取地址偏移值

compares6,08 ;判斷sw是否大于100

jumpc,sw_ok ;否

loads6,08 ;是,sw出錯,按默認執行

sw_ok:

;處理0字節低4位

loadaddr,a_lsb

addaddr,s6 ;獲取低地址

fetchdata,(s6) ;獲取低字節

callget_lower_nibble ;獲取低4位

callhex_to_led ;轉換成led顯示模式

storedata,led0

;處理0字節高4位

fetchdata,(addr)

callget_upper_nibble

callhex_to_led

storedata,led1

;處理1字節低4位

addaddr,01 ;獲取高地址

fetchdata,(addr)

callget_lower_nibble

callhex_to_led

storedata,led2

;處理1字節高4位

fetchdata,(addr)

callget_upper_nibble

callhex_to_led

;檢查sw是否等于100來處理led小數點的進位

compares6,08 ;是否顯示最終結果

jump

nz,led_done ;否

addaddr,01 ;獲取進位地址

fetchs6,(addr) ;寄存器存儲進位

tests6,01 ;測試進位寄存器是否為1

jump

z,led_done ;否

anddata,7F ;是,賦值最高位(dp)為0

led_done:

storedata,led3

return

;=====================================

;子程序:square

;功能:計算a?×?a+b?×?b

;數據/結果存儲RAM起始地址為SQ_BASE_ADDR

;臨時寄存器:s3,s4,s5,s6,data

;=======================================

square:

;計算a?×?a

fetchs3,a_lsb ;取a值

fetchs4,a_lsb ;取b值

callmult_hard ;計算a?×?a值

stores6,aa_lsb ;存儲a?×?a的低字節

stores5,aa_msb ;存儲a?×?a的高字節

;計算b?×?b

fetchs3,b_lsb ;取b值

fetchs4,b_lsb ;取b值

callmult_hard ;計算b?×?b值

stores6,bb_lsb ;存儲b?×?b的低字節

stores5,bb_msb ;存儲b?×?b的高字節

;計算a?×?a+b?×?b

fetchdata,aa_lsb ;獲取a?×?a的低字節

adddata,s6 ;求和a?×?a?+?b?×?b的低字節

storedata,aabb_lsb ;存儲a?×?a?+?b?×?b的高字節

fetchdata,aa_msb ;獲取a?×?a的高字節

addcydata,s5 ;求和a?×?a?+?b?×?b的高字節

storedata,aabb_msb ;存儲a?×?a?+?b?×?b的高字節

loaddata,00 ;清零data,但是保持進位寄存器值

addcydata,00 ;從前一次加法運算獲取進位值

storedata,aabb_cout ;存儲a?×?a?+?b?×?b的進位值

return

;==============================================

;程序名稱:mult_soft

;功能:利用移位和加法運算完成8位的無符號整數乘法

;輸入寄存器:s3:被乘數,s4:乘數

;輸出寄存器:s5:乘積高字節,s6:乘積低字節

;臨時寄存器:i

;=============================================

mult_soft:

loads5,00 ;清零s5

loadi,08 ;初始化循環次數

mult_loop:

sr0,s4 ;?s4最低位移位至進位寄存器

jump

nc,shift_prod ;最低位是0

adds5,s3 ;最低位是1

shift_prod:

sras5 ;右移高字節

sras6 ;右移低字節

subi,01 ;循環減1

jump

nz,mult_loop

return

;=============================================

;子程序名:display_mux_out

;程序功能:產生4位七段數碼管的使能和顯示模式信號

;輸入寄存器:

;count_msb,count_lsb:16位計數器

;led_pos:當前LED位置

;輸出寄存器:

;led_pos:更新LED位置

;臨時寄存器:data,addr

;================================================

display_mux_out:

comparecount_msb,02 ;計數器賦值為00000100_00000000

jumpc,mux_out_done

;如果count大于20,則清零計數器

loadcount_lsb,00

loadcount_msb,00

;更新七段數碼管顯示位置

addled_pos,01

compareled_pos,04

jumpnz,gen_an_signal

loadled_pos,00 ;?led位置循環顯示

gen_an_signal:

;產生4位使能信號

loaddata,0E ;?xxxx_1110

compareled_pos,00

jumpz,shift_an_0

compareled_pos,01

jumpz,shift_an_1

compareled_pos,02

jumpz,shift_an_2

sl1data ;移位1110三次

shift_an_2:

sl1data ;移位1110兩次

shift_an_1:

sl1data ;移位1110一次

shift_an_0:

outputdata,an_port

;輸出七段數碼管顯示模式

loadaddr,led0

addaddr,led_pos

fetchdata,(addr)

outputdata,sseg_port

mux_out_done:

return

;===============================================

;子程序名:interruptserviceroutine

;功能:16位加法器

;輸入寄存器:

;count_msb,count_lsb:timercount

;輸出寄存器:

;count_msb,count_lsb:incremented

;===========================================

int_service_routine:

addcount_lsb,01;16位加法器

addcycount_msb,00

returnienable

;===========================================

;中斷向量

;===========================================

address3FF

jumpint_service_routine16.4.4HDL代碼開發

基于中斷的求平方電路I/O接口包括三個部分,輸入接口與圖15-4相似,輸出接口包括一個譯碼電路和兩個針對an和sseg信號的輸出寄存器,中斷接口包括一個計數器和標志寄存器,如圖16-5所示。HDL描述如程序16-2所示。

【程序16-2】基于中斷的求平方電路HDL描述。

modulepico_int

(

input

wireclk,reset,

input

wire[7:0]sw,

input

wire[1:0]btn,

output

wire[3:0]an,

output

wire[7:0]sseg

);

//信號聲明

//KCPSM3/ROM信號

wire[9:0]address;

wire[17:0]instruction;

wire[7:0]port_id,out_port;

reg[7:0]in_port;

wirewrite_strobe,read_strobe;

wireinterrupt,interrupt_ack;

//I/O端口信號

//輸出使能

reg[1:0]en_d;

//?4位七段數碼管顯示

reg[7:0]sseg_reg;

reg[3:0]an_reg;

//兩個按鍵

regbtnc_flag_reg,btns_flag_reg;

wirebtnc_flag_next,btns_flag_next;

wireset_btnc_flag,set_btns_flag,clr_btn_flag;

//中斷相關信號

reg[8:0]timer_reg;

wire[8:0]timer_next;

wireten_us_tick;

regtimer_flag_reg;

wiretimer_flag_next;

//程序主體

//==========================================

//I/O模塊

//==========================================

debouncebtnc_unit

(.clk(clk),.reset(reset),.sw(btn[0]),

.db_level(),.db_tick(set_btnc_flag));

debouncebtns_unit

(.clk(clk),.reset(reset),.sw(btn[1]),

.db_level(),.db_tick(set_btns_flag));

//===========================================

//KCPSM3和ROM例化

//===========================================

kcpsm3proc_unit

(.clk(clk),.reset(1'b0),.address(address),

.instruction(instruction),.port_id(port_id),

.write_strobe(write_strobe),.out_port(out_port),

.read_strobe(read_strobe),.in_port(in_port),

.interrupt(interrupt),.interrupt_ack(interrupt_ack));

int_romrom_unit

(.clk(clk),.address(address),

.instruction(instruction));

//=========================================

//輸出接口

//=========================================

//輸出端口id:

//0x00:an

//0x01:ssg

//=========================================

//寄存器

always@(posedgeclk)

begin

if(en_d[0])

an_reg<=out_port[3:0];

if(en_d[1])

sseg_reg<=out_port;

end

assignan=an_reg;

assignsseg=sseg_reg;

//使能信號譯碼電路

always

@*

if(write_strobe)

case(port_id[0])

1'b0:en_d=2'b01;

1'b1:en_d=2'b10;

endcas

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論