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

下載本文檔

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

文檔簡介

第十四章PicoBlaze匯編語言開發(fā)14.1PicoBlaze匯編基礎14.2子程序開發(fā)14.3PicoBlaze匯編程序開發(fā)14.4PicoBlaze軟件開發(fā)流程本章小結14.1PicoBlaze匯編基礎14.1.1KCPSM3語法規(guī)定

KCPSM3匯編語言在程序中有如下的語法規(guī)定:

(1)每個代碼段地址的開始以“代碼段名稱:”表示,也就是代碼段名稱加冒號意味著新的代碼段開始。

(2)采用“;”對單行程序進行注釋。

(3)“HH”表示常數(shù),這里H表示十六進制數(shù)值。下面是一個程序:tests0,82;比較寄存器s0與1000_0010jumpz,clr-sl;如果s0的最高位為0,則跳轉到clr_s1程序段loadsl,FF;如果不是,則置數(shù)1111_1111到s1clr-sl: ;代碼段開始loadsl,01;置數(shù)0000-0001給sl寄存器14.1.2位操作實際工程應用中,經(jīng)常會使用位操作。它用于控制I/O口活動,比如測試、置位和清零信號等。然而,PicoBlaze指令只能按字節(jié)操作。如果要實現(xiàn)按位控制操作,則通常采用的方案是首先隔離和保護無關位,然后針對目標位進行置位、清零和取反操作,對應的指令包括or、and、xor等。下面的代碼舉例說明如何進行置位、清零和取反s0寄存器的倒數(shù)第二位:

constantSET-MASK,02 ;預設“置位”屏蔽值0000_0010

constantCLR-MASK,FD ;預設“清零”屏蔽值1111_1101

constantTOG-MASK,02 ;預設“取反”屏蔽值0000_0010

ors0,SET-MASK ;設置s0倒數(shù)第二位為1

ands0,CLR-MASK ;?s0倒數(shù)第二位清零

xors0,TOG-MASK ;?s0倒數(shù)第二位異或操作同樣可以采用邏輯與的概念代替測試指令來檢查單個數(shù)據(jù)位。比如說,下面的代碼用來測試s0寄存器的最高位的值;如果為1,則代碼跳轉到適合的分支:

tests0,80 ;預設屏蔽值1000_0000

jump

nz,msb-set ;如果最高位為1,則跳轉到msb-set分支

;如果最高位不為1,則執(zhí)行下面的代碼

jumpdone

msb-set

;最高位為1時執(zhí)行的代碼

done:單獨1位信號監(jiān)測都可以采用上面的方式進行操作。比如,下例用來檢查s0寄存器的最高位是否為1;如果正確,將s0的值存儲到寄存器s1當中:

loadsl,00

tests0,80 ;預設屏蔽值1000_0000

jumpz,done ;如果是,則最高位置0

loadsl,01 ;否則,s1寄存器置01

done:

…14.1.3多字節(jié)操作工程應用中,經(jīng)常要求微處理器進行多個字節(jié)的操作。比如,要實現(xiàn)一個很大的計數(shù)器,很有可能超過微處理器的處理位寬,如PicoBlaze的處理器為8位,那么如何處理多個字節(jié)操作呢?通常的方法就是兩條指令之間設置信息傳輸機制。實際上處理器中都有進位標志位完全可以實現(xiàn)這個目的。對于加法和減法運算指令來說有兩種類型的操作指令,一種是帶進位的,另外一種是不帶進位的,比如add指令和addcy指令,而對于移位和循環(huán)指令來說,進位可以被移位到最高位、最低位或者中間某一位。這樣一來,多字節(jié)的數(shù)據(jù)信息傳輸就容易多了。假設x和y都是24位的數(shù)據(jù),那么它們各占三個寄存器。下面代碼舉例說明如何對多個字節(jié)進行數(shù)據(jù)處理:

nameregs0,x0 ;x的低字節(jié)存儲到寄存器s0中

nameregsl,xl ;x的中字節(jié)存儲到寄存器s1中

nameregs2,x2 ;x的高字節(jié)存儲到寄存器s2中

nameregs3,y0 ;y的低字節(jié)存儲到寄存器s3中

nameregs4,yl ;y的中字節(jié)存儲到寄存器s4中

nameregs5,y2 ;y的高字節(jié)存儲到寄存器s5中

;進行加法運算(x2,xl,x0)+(y2,yl,y0)

addx0,y0 ;對x和y的低字節(jié)進行加法運算

addcyxl,yl ;對x和y的中字節(jié)進行帶進位加法運算

addcyx2,y2 ;對x和y的高字節(jié)進行帶進位加法運算第一條指令執(zhí)行普通的低字節(jié)加法操作,將進位存儲到進位標志位;第二條指令針對中字節(jié)進行加法操作,同時由于低字節(jié)加法結果有進位,中字節(jié)加法操作需要帶進位加法;同樣地,第三條指令在前面加法的基礎上對高八位進行帶進位加法操作。多字節(jié)的加法和減法操作都可以用同樣的方式進行:

;加1運算:(x2,xl,x0)+1

addx0,01 ;低字節(jié)加1

addcyxl,00 ;中字節(jié)帶進位加法

addcyx2,00 ;高字節(jié)帶進位加法

;減法運算(x2,xl,x0)-(y2,yl,y0)

subx0,y0 ;低字節(jié)相減

subcyxl,yl ;中字節(jié)帶借位相減

subcyx2,y2 ;高字節(jié)帶借位相減多字節(jié)數(shù)據(jù)可以通過移位指令包含進位標志進行移位。比如說,sla指令可以向左移位數(shù)據(jù)1位,然后將進位標志位移到最低位。下面代碼反映了左移3字節(jié)的數(shù)據(jù)的例子:

;通過進位移位(x2,xl,x0)

sl0 x0;?x0最高位移處到進位標志,低位移入0

sla xl;當前進位標志移入到x1低位,而x1高位移出到進位標志

sla x2;當前進位標志移入到x2低位,而x2高位移出到進位標志14.1.4常用控制語句結構的匯編語言描述高級語言通常有各種各樣的控制結構語句來改變程序執(zhí)行的順序。比如,常用的

if-then-else,case,for-loop等。然而對于PicoBlaze來說,僅僅提供了簡單的條件控制語句和無條件跳轉語句,相對比較簡單。但是可以通過配合test和compare指令來完成高級語言能夠?qū)崿F(xiàn)的各種結構控制語句。下面通過實例介紹如何實現(xiàn)if-then-else、case和for-loop語句的操作。

1.使用匯編語言實現(xiàn)if-then-else語句

if-then-else實現(xiàn)如下控制功能:

if(s0==sl){/*滿足條件情況下的程序分支*/

}

else{

/*不滿足條件情況下的程序分支*/

}對應的匯編程序如下:

compares0,sl

jump

nz,else_branch滿足條件情況下的程序分支

jumpif_done

else_branch:不滿足條件情況下的程序分支

if_done:

if語句執(zhí)行完之后的代碼

…這段代碼使用了compare指令檢測條件(s0==s1)是否相等,并設置清零標志位。使用jump指令檢測這個標志位。如果標志位沒有被置位,則跳轉到elsebranch(不滿足條件情況下的程序分支);否則,執(zhí)行滿足條件情況下的程序分支。

2.使用匯編語言實現(xiàn)case語句在高級語言中,case語句可以理解為多重跳轉,具體哪個分支執(zhí)行要參考條件表達式。下面的語句使用s0變量作為條件來進行跳轉:switch(s0){

case第一種情況:

/*第一種情況下執(zhí)行的語句*/

break;

case第二種情況:

/*第二種情況下執(zhí)行的語句*/

break;

case第三種情況:

/*第三種情況下執(zhí)行的語句*/

break;

default:

/*默認情況下執(zhí)行的語句*/}多路跳轉在處理器中若要實現(xiàn),則可以按照硬件描述語言中常用的“地址索引”的方式執(zhí)行。然而,PicoBlaze處理器是不可以直接執(zhí)行該功能的,case語句需要與if-then-else語句一樣的方式進行處理。將上述case語句轉化成if-then-else的格式:

if(s0==valuel){

/*第一種情況下執(zhí)行的語句*/

}

elseif(s0==value2){

/*第二種情況下執(zhí)行的語句*/

}

elseif(s0==value3){

/*第三種情況下執(zhí)行的語句*/

}

else{

/*默認情況下執(zhí)行的語句*/

}如此一來,對應的匯編程序如下:

constantvalue1,...

constantvalue2,...

constantvalue3,...

compares0,value1 ;測試value1

jumpnz,case-2;?s0值與value1不同則跳轉,否則順序執(zhí)行

;codeforcase1

jumpcase-done

case-2:

compares0,value2

;測試value2

jump

nz,case-3

;s0值與value2不同則跳轉,否則順序執(zhí)行

;codeforcase2

jumpcase-done

case-3:

compares0,value3 ;測試value3

jumpdefault ;s0值與value3不同則跳轉,否則順序執(zhí)行

;codeforcase3

...

jumpcase-done

default:默認情況下執(zhí)行的語句

case-done:

;case語句完成之后接下來執(zhí)行的代碼

3.使用匯編語言實現(xiàn)for-loop語句

for-loop語句用來重復執(zhí)行代碼段。loop指令可以用計數(shù)器來追蹤計數(shù)數(shù)目,比如,下面的例子:

for(i=MAX,i=0,.i-1){

/*重復執(zhí)行語句段*/

}對應的匯編代碼如下:

nameregso,i ;loop索引值

constantMAX,... ;loop邊界值

loadi,MAX ;置數(shù)loop索引值

loop-body:

;loop語句主體

...

subi,01 ;對變量i和索引值做減法運算

jump

nz,loop-body ;變量i還沒有為0則繼續(xù)執(zhí)行l(wèi)oop主體,否則執(zhí)行l(wèi)oop語句后面的語句 14.2子?程?序?開?發(fā)匯編程序中的子程序類似于C語言中的函數(shù),通??梢酝瓿梢粋€特殊的功能,并且作為主程序中的一部分可以被重復調(diào)用。采用子程序設計的方法,方便程序員把一個復雜龐大的程序簡化成若干簡單的小程序,這樣有利于管理程序的各個模塊,提高了程序的可靠性和可讀性。在高級語言設計中都支持這種編程思想。

PicoBlaze采用call和return指令實現(xiàn)子程序調(diào)用。call指令保存當前程序計數(shù)器和程序執(zhí)行過程中產(chǎn)生的臨時值,同時讓程序指針跳轉到子程序開始執(zhí)行的地址。子程序以return指令結束時,它重新保存程序計數(shù)器值并且返回到原來跳轉的地址。要注意的是,PicoBlaze僅僅保存和重新裝載程序計數(shù)器的內(nèi)容,在子程序執(zhí)行過程中產(chǎn)生的寄存器和RAM數(shù)據(jù)值都需要編程人員手工保存,確保子程序調(diào)用結束后,原來的系統(tǒng)能夠正常工作。下面舉一個綜合應用的例程來描述子程序的開發(fā)。假設輸入為兩個8位的無符號整數(shù),輸出是16位乘積,算法包括一個簡單的“移位”和“加法”運算。由于乘數(shù)和被乘數(shù)都是8位,所以重復執(zhí)行“移位”和“加法”8次。每次執(zhí)行時被乘數(shù)左移一位。如果遇到乘數(shù)為1,則將左移的被乘數(shù)和當前乘積值相加。其匯編代碼如程序14-1所示。被乘數(shù)和乘數(shù)分別存儲在s3和s4寄存器中,判斷乘數(shù)獨立每一位是0還是1,都是由s4的重復右移之后,將最低位移至進位標志之后才判斷的。需要注意的是,不是將被乘數(shù)左移,而是移位乘積項,它包含兩個字節(jié),分別存儲到s5和s6中。在匯編語言設計過程中,由于其本身可閱讀性并不好,所以要做好程序的注釋,否則過段時間自己也看不懂。以程序14-1為例,它包含了簡單的功能描述注釋,另外還將寄存器如何分配也描述出來,這樣以防與整個大程序混淆。

【程序14-1】8位無符號整數(shù)乘法。

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

;程序名稱:mult_soft

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

;輸入寄存器,s3:被乘數(shù),s4:乘數(shù)

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

;臨時寄存器:i

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

mult_soft:

loads5,00 ;清零s5

loadi,08 ;初始化循環(huán)次數(shù)

mult_loop:

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

jump

nc,shift_prod;最低位是0

adds5,s3 ;最低位是1

shift_prod:

sras5 ;右移高字節(jié)

sras6 ;右移低字節(jié)

subi,01 ;循環(huán)減1

jump

nz,mult_loop

return

14.3PicoBlaze匯編程序開發(fā)

14.3.1開發(fā)流程開發(fā)一個完整的匯編程序包含如下4個步驟:

(1)設計主程序功能描述偽代碼;

(2)將主程序任務劃分成若干子程序任務,如果子程序比較復雜,則應該將其細分成更小的子程序;

(3)定義寄存器和數(shù)據(jù)RAM的使用;

(4)編寫子程序代碼。第(1)、(2)和(4)步驟按照逐個實現(xiàn)的方法來實現(xiàn)。任何軟件開發(fā)流程大致都如此?;谖⑻幚砥鞯膽猛ǔa槍η度胧较到y(tǒng),處理器需要不斷監(jiān)視I/O口的狀態(tài)并同時做出反應。主程序一般按照下面的結構來編寫:

call

初始化子程序

forever:

call

子程序1

call

子程序2

call

子程序n

jumpforever第(3)步僅僅用在匯編語言開發(fā)中。因為高級語言開發(fā)過程中,編譯器會自動分配變量。而匯編代碼中編譯器沒有此功能,必須人工管理數(shù)據(jù)存儲。PicoBlaze有16個寄存器和64位數(shù)據(jù)存儲器。寄存器可以被認為是快速存儲器,因為可以直接存儲數(shù)據(jù)。數(shù)據(jù)存儲器是“輔助存儲器”,它的數(shù)據(jù)需要傳輸?shù)郊拇嫫髟僮魈幚?。如果想存儲一個數(shù)據(jù)到RAM中,則必須首先將其裝到寄存器中,然后再存儲到RAM中。由于存儲數(shù)據(jù)的空間非常有限,所以其使用就應計劃著用,尤其是代碼比較復雜而且包含有程序嵌套的情況下,我們更得計劃好存儲空間的分配。應首先定義需要的全局存儲器和局部存儲器,使前者保存整個程序都需要的變量,后者保存臨時存儲的變量,在部分功能結束時其空間就可以釋放掉。14.3.2程序舉例舉例是理解開發(fā)過程的最有效方式??紤]采用前面的乘法子程序,首先從撥碼開關輸入a和b,計算a2和b2,然后將結果顯示到七段數(shù)碼管上。關于I/O接口部分,14.3.3節(jié)將詳細講解,本章內(nèi)容僅限于簡單的輸入輸出端口的介紹。本例中,只有一個8位的撥碼開關和一個8位的LED輸出端口。假設撥碼開關高4位提供給a端口輸入,低4位提供給b端口輸入。主程序如下:

callclear-data-ram

forever:

callread-switch

callsquare

callwrite-led

jumpforever操作過程如下:

(1)定義子程序。子程序定義如下:

clr_data_mem:系統(tǒng)初始化時所有數(shù)據(jù)存儲器清零。

read_switch:獲取撥碼開關提供的數(shù)據(jù)輸入端口數(shù)據(jù)并保存到數(shù)據(jù)RAM中。

square:采用乘法器子程序計算a2+b2。

write_led:將計算結果顯示到LED端口上。為了方便,還需要創(chuàng)建兩個小的子程序:get_upper_nibble和get_lower_nibble,用來在read_switch子程序中調(diào)用,從而獲取寄存器高位和低位的數(shù)值。

(2)規(guī)劃寄存器和數(shù)據(jù)RAM的使用。定義全局存儲器sw_in,用來存儲撥碼開關輸入值,開辟11?B的數(shù)據(jù)RAM空間以存儲輸入數(shù)據(jù)以及運算結果值。數(shù)據(jù)RAM的具體分配如表14-1所示。注意地址01和03不用,其余的寄存器都作為局部存儲器使用。為了程序更加清晰,定義三個符號data,addr,i,分別作為數(shù)據(jù),端口和存儲器地址,循環(huán)索引值的臨時寄存器。

(3)劃分子程序。完整的程序如程序14-2所示。

clr_data_mem用來循環(huán)清零數(shù)據(jù)寄存器,寄存器i為循環(huán)索引值并初始化為64。每次循環(huán),該索引值最后對應的寄存器置0,write_led子程序從數(shù)據(jù)RAM中取回計算結果的低位,輸出到LED端口。

read_switch子程序包括兩個小的子程序。get_upper_nibble小子程序右移數(shù)據(jù)寄存器4次,將高4位數(shù)據(jù)移位到寄存器低4位;get_lower_nibble小子程序清零數(shù)據(jù)寄存器的高4位,移除高字節(jié)。read_switch子程序獲取撥碼開關的輸入值,調(diào)用get_upper_nibble和get_lower_nibble子程序并將結果存儲到數(shù)據(jù)RAM中。

square子程序從數(shù)據(jù)RAM中取回數(shù)據(jù),并采用mult_soft子程序計算a2和b2,執(zhí)行加法并存儲結果到數(shù)據(jù)RAM中。

【程序14-2】計算a2+b2。

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

;帶簡單I/O接口的求平方和電路

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

;程序操作:

;讀取撥碼開關的高4位a和低4位b

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

;在8個led上顯示結果值

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

;數(shù)據(jù)常數(shù)

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

constantUP_NIBBLE_MASK,0F;00001111

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

;數(shù)據(jù)ram地址接口定義

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

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

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

;寄存器定義

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

;通用局部變量寄存器

nameregs0,data ;臨時數(shù)據(jù)存儲

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

nameregs2,i ;循環(huán)索引值

;全局變量

nameregsf,sw_in

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

;端口定義

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

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

constantsw_port,01 ;8-bitswitches

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

constantled_port,05

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

;主程序

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

;程序調(diào)用層次;

;main

;-clr_data_mem

;-read_switch

;-get_upper_nibble

;-get_lower_nibble

;-square

;-mult_soft

;-write_led

;

callclr_data_mem

forever:

callread_switch

callsquare

callwrite_led

jumpforever

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

;子程序:clr_data_mem

;程序功能:cleardataram

;臨時寄存器:data,i

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

clr_data_mem:

loadi,40 ;循環(huán)索引值為64

loaddata,00

clr_mem_loop:

storedata,(i)

subi,01 ;循環(huán)減1

jump

nz,clr_mem_loop ;重復直到i=0

return

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

;子程序:readswitch

;程序功能:從輸入端口獲取兩個乘數(shù)

;輸入寄存器:sw_in

;臨時寄存器:data

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

read_switch:

inputsw_in,sw_port ;讀取撥碼開關輸入

loaddata,sw_in

callget_lower_nibble

storedata,a_lsb ;存儲a到數(shù)據(jù)RAM

loaddata,sw_in

callget_upper_nibble

storedata,b_lsb ;存儲b到數(shù)據(jù)RAM

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

;子程序名:get_lower_nibble

;程序功能:獲得data低4位

;輸入寄存器:data

;輸出寄存器:data

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

get_lower_nibble:

anddata,UP_NIBBLE_MASK ;清除高4位數(shù)據(jù)

return

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

;子程序名:get_upper_nible

;程序功能:獲得data高4位

;輸入寄存器:data

;輸出寄存器:data

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

get_upper_nibble:

sr0data ;右移4次

sr0data

sr0data

sr0data

return

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

;子程序:write_led

;程序功能:輸出結果低8位到8位LED

;臨時寄存器:data

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

write_led:

fetchdata,aabb_lsb

outputdata,led_port

return

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

;子程序名:square

;程序功能:計算a×a?+?b×b,數(shù)據(jù)和計算結果存儲到以SQ_BASE_ADDR為起始地址的RAM中

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

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

square:

;計算a?×?a

fetchs3,a_lsb ;裝載a值

fetchs4,a_lsb ;裝載a值

callmult_soft ;計算a?×?a

stores6,aa_lsb ;存儲a?×?a的低字節(jié)

stores5,aa_msb ;存儲a?×?a高字節(jié)

;計算b?×?b

fetchs3,b_lsb ;裝載b值

fetchs4,b_lsb ;裝載b值

callmult_soft ;計算b?×?b

stores6,bb_lsb ;存儲b?×?b的低字節(jié)

stores5,07 ;存儲b?×?b的高字節(jié)

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

fetchdata,aa_lsb ;獲取a?×?a的低字節(jié)

adddata,s6 ;求和a?×?a?+?b?×?b的低字節(jié)

storedata,aabb_lsb ;存儲a?×?a?+?b?×?b的低字節(jié)

fetchdata,aa_msb ;獲取a?×?a的高字節(jié)

addcydata,s5 ;求和a?×?a?+?b?×?b的高字節(jié)

storedata,aabb_msb ;存儲a?×?a?+?b?×?b的高字節(jié)

loaddata,00 ;清除數(shù)據(jù),保持進位寄存器值不變

addcydata,00 ;獲取從前一次加法運算得到的進位寄存器值

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

return

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

;子程序名:mult_soft

;程序功能:利用移位和加法操作的8位無符號乘法器

;輸入寄存器:s3:被乘數(shù);s4:乘數(shù)

;輸出寄存器:s5:乘積高字節(jié);s6:乘積低字節(jié)

;臨時寄存器:i

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

mult_soft:

loads5,00 ;清零s5

loadi,08 ;初始化循環(huán)索引值

mult_loop:

sr0s4 ;右移s4最低位到進位寄存器

jump

nc,shift_prod ;s4最低位是0

adds5,s3 ;s4最低位是1

shift_prod:

sras5 ;右移寄存器s5,最高位補c,最低位移位到c寄存器

sras6 ;右移寄存器,s5的最低位移位到s6最高位

subi,01 ;循環(huán)減1

jump

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

return14.3.3說明文檔與注釋匯編程序的開發(fā)非常繁瑣,如果沒有好的文檔和符號說明,程序會非常難懂且容易發(fā)生不必要的錯誤。另外,完整的文檔也有助于代碼版本管理。對于KCPSM3編譯器,使用關鍵字constant直接用符號代表數(shù)據(jù)常數(shù)、存儲器地址或者端口的id號等,使用關鍵字namereg直接用符號代表寄存器。在程序的文件頭包含如下幾部分內(nèi)容:

(1)程序描述:描述程序的用途、操作以及I/O等。

(2)數(shù)據(jù)常數(shù):常數(shù)的符號聲明。

(3)數(shù)據(jù)RAM地址偽代碼:聲明數(shù)據(jù)RAM地址符號偽代碼。

(4)寄存器偽代碼:聲明寄存器偽代碼。

(5)端口偽代碼:聲明端口偽代碼。

(6)程序調(diào)用層次:描述程序調(diào)用結構。符號不會影響最終的機器碼編譯。當匯編程序執(zhí)行時,都會替換成實際的常數(shù)值。使用偽代碼可大大增強程序的可讀性且能降低不必要的錯誤。下面的程序代碼顯示偽代碼和文檔對程序的影響。程序的功能是獲取變量a、b和c的值,然后存儲到合適的數(shù)據(jù)存儲器中。程序輸入由UART輸入,也就是a、b、c的ASCII碼。具體代碼如下:;常數(shù)偽代碼

constantASCII_a,61 ;a的ASCII碼

constantASCII_b,62 ;b的ASCII碼

constantASCII_c,63;c的ASCII碼;數(shù)據(jù)RAM地址偽代碼

constanta_addr,02

constantb_addr,04

constantc_addr,06;地址偽代碼

nameregs0,data ;當前數(shù)據(jù)暫存寄存器

nameregs1,addr ;當前地址暫存寄存器

nameregsf,sw_in ;撥碼開關值;端口偽代碼

constantsw_port,01 ;端口撥碼開關值

constantuart_rx_port,02 ;UART輸入;使用偽代碼的匯編程序;獲取輸入

inputsw_in,sw_port ;獲取撥碼開關值

inputdata,uart_rx_port ;獲取UART字符;檢查接收字符

comparedata,ASCII_a ;檢查ASCII_a

jump

nz,chk_ascii_b ;如果不是,則檢查下一個

storesw_in,a_addr ;如果是,則存儲a到數(shù)據(jù)寄存器當中

jumpdonechk_ascii_b:

comparedata,ASCII_b ;檢查ASCII_b

jump

nz,chk_ascii_c ;如果不是,則檢查下一個

storesw_in,b_addr ;如果是,則存儲b到數(shù)據(jù)寄存器當中

jumpdonechk_ascii_c:

comparedata,ASCII_c ;檢查ASCII_c

jump

nz,ascii_err ;如果不是,則檢查下一個

storesw_in,c_addr ;如果是,則存儲b到數(shù)據(jù)寄存器當中

jumpdoneascii_err:

…done:

…如果不使用偽代碼和注釋的方式寫此程序,代碼就會變成:

inputsf,01

inputs0,02

compares0,61

jump

nz,addr1

storesf,02

jumpaddr4

addr1:

compares0,62

jump

nz,addr2

storesf,04

jumpaddr4

addr2:

compares0,63

jump

nz,addr3

storesf,06

jumpaddr4

addr3:

addr4:

… 14.4PicoBlaze軟件開發(fā)流程14.4.1使用KCPSM3編譯編譯是將指令碼翻譯成機器碼的過程。所謂機器碼,就是最終機器能夠認識的“0”和“1”碼。編譯結束后,所有的偽代碼和符號都用實際值替代,將機器指令下載到微控制器的指令存儲器中。由于PicoBlaze嵌入到FPGA內(nèi)部,因而指令ROM為一個用HDL語言例化的ROM模型,在程序頂層會例化這個ROM,然后與PicoBlaze微處理器以及I/O接口電路一起綜合。

Xilinx提供的KCPSM3編譯器是一種使用命令字操作且基于DOS操作的小程序。KCPSM3基本上是編譯器所附帶的一些模板文件,為指令ROM產(chǎn)生HDL程序。其編譯的步驟如下:

(1)新建文件夾,將kcpsm3.exe、ROM_form.vhd、ROM_form.v以及ROM_form.coe拷貝到該路徑下,后面三個文件為代碼模版。

(2)創(chuàng)建匯編程序以.psm為后綴名的二進制文本文件保存,任何基于PC的編輯器都可以,如記事本。

(3)選擇開始→程序→附件→命令提示符,打開DOS窗口并跳轉到當前目錄。

(4)敲入命令kcpsm3myfile.psm,運行該程序。

(5)檢查有無錯誤。如果有錯誤,則修改并重新編譯。

(6)編譯成功后,保存指令ROM的myfile.v文件生成。除了HDL文件,KCPSM3同時產(chǎn)生適合塊ROM的初始化文件以及其它有用文件。后綴為?.hex的文件可以用JTAG下載(后面會專門講述);后綴名為?.fmt的文件可將?.psm文件格式重新修改以適合打印。下面以程序14-2為例詳細介紹使用KCPSM3編譯器編譯的方法。

(1)新建文件夾Square_Pico,將下載下來的KCPSM3.exe、ROM_form.vhd、ROM_form.v以及ROM_form.coe拷貝到該文件夾下面。

(2)使用記事本新建文件,復制程序14-2到新建文件,并以Square.psm名稱保存在Square_Pico文件夾下。

(3)選擇開始→程序→附件→命令提示符,打開DOS窗口并使用cd命令符跳轉到當前目錄下,如F:\Square_Pico\。

(4)鍵入命令KCPSM3Square.psm,按回車,顯示如圖14-1所示,表示編譯通過。

(5)編譯成功后,在當前文件夾下面產(chǎn)生SAUARE.V的指令保存文件。圖14-1KCPSM3編譯成功界面圖14.4.2使用PBlazeIDE仿真

PBlazeIDE工具相對KCPSM3具有良好的基于Windows的IDE集成開發(fā)環(huán)境,包括文本編譯、編譯器以及指令級的仿真功能。

PBlazeIDE的指令集和KCPSM3有一些區(qū)別,其所有不一樣的指令如表14-2所示。需要注意的是,PBlazeIDE對于常數(shù)可以使用十六進制和十進制兩種表示方法,十六進制以$開頭。兩種指令集的常數(shù)表示的區(qū)別如表14-3所示。

使用PBlazeIDE編譯KCPSM3代碼的步驟如下:

(1)啟動PBlazeIDE。

(2)選擇設置→PicoBlaze3。對于Spartan-3系列,F(xiàn)PGA對應的PicoBlaze版本為PicoBlaze3。

(3)選擇文件→導入,出現(xiàn)一個對話框;選擇對應的?.fmt或者?.psm文件,導入功能將KCPSM3代碼轉換成PBlazeIDE代碼。程序的格式轉換非常簡單,有時需要人工做微小修改。

(4)針對I/O端口手工定義dsin、dsout、dsio。當有一個方向使用時,端口顯示其將會添加到仿真界面中顯示端口的活動情況。

(5)通過選擇Simulate→Simulate,執(zhí)行仿真。

(6)如果匯編代碼需要修改,則退出仿真模式,進行編輯,或者使用外部編輯器編輯?.psm文件。不過又要從第(1)步再開始執(zhí)行。需要注意的是,文件一旦被PBlazeIDE導入,將不能再返回成KCPSM3格式的代碼。依然以程序14-2為例。導入Square.psm之后,PBlazeIDE仿真編譯成功,添加輸入輸出仿真端口,在原來的程序中,增加如下兩條語句:

sw_portDSIN$01

led_portDSOUT$50同時注釋掉原來對sw_port和led_port的定義:

;------------inputportdefinitions---------------------

;sw_portEQU1;8bitswitches

;------------outputportdefinitions---------------------

;led_portEQU5圖14-2PBlazeIDE界面介紹由dsin、dsout以及dsio創(chuàng)建的仿真I/O端口顯示在右側,包括一個輸入端口sw_port,一個輸出端口led_port。仿真過程中,程序可以持續(xù)執(zhí)行、單步執(zhí)行或者根據(jù)指令執(zhí)行,同時支持斷點仿真。仿真行為可以通過仿真菜單命令或者界面控制,各指令及其功能如下:

(1)?reset:程序計數(shù)器和堆棧指針清零。

(2)?Run:執(zhí)行程序直到遇到斷點。

(3)?SigleStep:執(zhí)行一條指令。

(4)?StepOver:對于call指令為執(zhí)行整個子程序,其他情況執(zhí)行一條指令。

(5)?Runtocursor:執(zhí)行當前程序到當前光標位置。

(6)?Pause:暫停仿真。

(7)?Togglebreakpoint:在當前光標位置設置或者清除斷點。

(8)?RemoveallBreakpoints:清除所有斷點。14.4.3使用JTAG接口下載代碼使用KCPSM3編譯后,指令ROM的HDL代碼產(chǎn)生。可以繼續(xù)如圖13-4的步驟⑥和⑧,綜合整個代碼并配置到FPGA中去。需要注意的是,每次軟件代碼修改都需要重新進行綜合。由于綜合是一個復雜的過程,所以在綜合過程當中需要花費很多的運算時間。當I/O口配置固定后,每次修改完匯編代碼,不需要重新完全綜合整個電路,而是可以通過FPGA的JTAG接口重新裝載軟件編譯之后的機器碼到ROM中。這個過程對應于圖13-4中的步驟⑨,具體過程如下:

(1)以包含有JTAG接口電路的ROM模板電路替換原始的ROM模板。

(2)使用KCPSM3編譯匯編代碼。

(3)綜合頂層HDL代碼,然后編程到FPGA中。

(4)在修改了匯編代碼后,按照正常流程編譯匯編代碼,產(chǎn)生以?.hex為后綴的十六進制文件。

(5)使用Xilinx工具嵌入?.hex文件到JTAG編程文件中,通過JTAG接口下載到FPGA的塊RAM當中。14.4.4代碼綜合當產(chǎn)生指令ROM的HDL文件后,可以將其與PicoBlaze一起綜合在FPGA芯片中。與其他微控制器不同的是,PicoBlaze沒有建立I/O外設,I/O接口和外設需要根

溫馨提示

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

評論

0/150

提交評論