在第二部分中,已經介紹了基于OpenMIPS的SOPC的結構,本文介紹如何将該SOPC下載下傳到Altera的DE2上進行驗證,我們的驗證程式是模拟一個作業系統的啟動過程,包括兩個部分:BootLoader、SimpleOS,大家一看名字就了解了,前者是用來加載作業系統的,後者當然就是一個簡單的作業系統了,這個作業系統有多簡單呢?答:非常簡單,隻是讀取序列槽收到的資料,然後把資料再發送回去。 BootLoader與SimpleOS都存儲在DE2上的flash中,DE2具有4MB的nor flash,可以用來作啟動盤,通過SOPC的結構可以知道,flash控制器連接配接到Wishbone互聯矩陣的s3,是以flash的尋址空間是從0x30000000開始的,這也就要求我們的OpenMIPS啟動後,要從0x30000000位址處取指,也就是從flash的偏移位址0處開始取指執行。 BootLoader與SimpleOS的代碼在flash中的存放方式如下:
BootLoader放在flash從0x0開始的位置,在flash的0x300處存放的是SimpleOS的長度資訊,然後從0x304處開始存放SimpleOS。
OpenMIPS啟動後,BootLoader首先讀取0x300處的長度資訊length,然後根據該資訊,将從0x304處開始length個字,複制到SDRAM從0x0開始的地方,複制結束後,跳轉到0x0位址,将控制權交給SimpleOS,這個過程模拟了目前作業系統的啟動過程。
SimpleOS實作了UART的回顯,當PC通過UART給OpenMIPS輸入資料時,會引發OpenMIPS的中斷,OpenMIPS中斷處理程式将該資料回送回來。是以該程式還驗證了OpenMIPS中斷功能的實作與否。
本次試驗使用的軟硬體工具如下:
- 軟體:quartusii 10.1 sp1、DE2的附帶CD光牒、序列槽調試助手、Ubuntu虛拟機、GCC
- 硬體:Altera的DE2評估闆
好了,關于我們實驗的基礎知識就介紹了完了,下面開始進入正題,分以下幾步:
- 硬體連接配接
- 測試程式講解
- Makefile與連結檔案
- 測試程式編譯
- flash燒錄
- OpenMIPS工程建立
- 下載下傳測試
1、硬體連接配接 很簡單喽,如下,DE2與PC機的連接配接如下:
2、測試程式講解
就兩個程式BootLoader.asm、SimpleOS.asm,分别介紹,首先是BootLoader.asm,它的作用的就是讀取flash的0x304位址處的一個字,其中是SimpleOS的長度資訊length,然後從flash的0x304位址開始的length個字複制到SDRAM中,在我們的SOPC中,SDRAM是挂接在Wishbone互聯矩陣的s0接口,是以SDRAM的位址是從0x00000000開始的,BootLoader在複制完畢後,會讓處理器跳轉到0x0處開始執行,這樣就将控制器交給了剛剛複制到SDRAM的SimpleOS。代碼如下: .set noat .set noreorder .set nomacro .org 0x0 .text .align 4 .global _start _start: ###################### 設定UART控制器 ##################### lui $1,0x1000 ori $1,$1,0x0003 ori $2,$0,0x80 sb $2,0x0($1) # 向0x10000003位址寫入0x80,UART控制器連接配接到 # Wishbone總線互聯矩陣的s1,是以其位址是從0x10000000開始, # 通過查詢UART的手冊可知,偏移為3的位址對應的是line control寄存器 # 向該寄存器寫入0x80,表示下面可以設定分頻值(divisor latch) # 通過UART的手冊可知,分頻值等于系統時鐘/(16*波特率),此處設定波特率 # 為9600,DE2上的時鐘是27MHz,是以分頻值為0xB0
lui $1,0x1000 ori $1,$1,0x0001 ori $2,$0,0x00 sb $2,0x0($1) # 向0x10000001位址寫入0x00,此時的line control寄存器是0x80 # 通過查詢UART的手冊可知,此時向0x1寫入0x00,就是設定分頻值的MSB # 為0x00
lui $1,0x1000 ori $1,$1,0x0000 ori $2,$0,0xB0 sb $2,0x0($1) # 向0x10000000位址寫入0xB0,此時的line control寄存器是0x80 # 通過查詢UART的手冊可知,此時向0x0寫入0xB0,就是設定分頻值的LSB # 為0xB0
lui $1,0x1000 ori $1,$1,0x0003 ori $2,$0,0x03 sb $2,0x0($1) # 向0x10000003位址寫入0x03,對應的是line control寄存器, # 就是設定序列槽通信參數,8bit,沒有奇偶校驗位,1bit停止位
###################### 設定GPIO控制器 ##################### lui $1,0x2000 ori $1,$1,0x0008 lui $2,0xffff ori $2,$2,0xffff sw $2,0x0($1) # 向0x20000008位址寫入0xffffffff,GPIO控制器連接配接到 # Wishbone總線互聯矩陣的s2,是以其位址是從0x20000000開始, # 通過查詢GPIO的手冊可知,偏移為8的位址對應的是RGPIO_OE寄存器 # 向該寄存器寫入0xffffffff,表示GPIO的32個輸出都使能
lui $1,0x2000 ori $1,$1,0x000c lui $2,0x0000 ori $2,$2,0x0000 sw $2,0x0($1) # 向0x2000000c位址寫入0x00000000, # 通過查詢GPIO的手冊可知,偏移為c的位址對應的是RGPIO_INTE寄存器 # 向該寄存器寫入0x00000000,表示中斷禁止
###################### 等待SDRAM初始化完畢 ##################### ###在前面介紹過,SDRAM的sdram_init_done輸出連接配接到GPIO,是以可以通過GPIO的輸入判斷 ###SDRAM是否初始化完畢 _waiting_sdram_init_done: lui $1,0x2000 ori $1,$1,0x0000 lw $4,0x0($1) srl $4,$4,0x10 andi $4,$4,0x0001 beq $4,$0,_waiting_sdram_init_done nop
###################### 列印啟動開始資訊 ##################### li $1,0x1 la $2,_BootBeginInfoStr la $3,_BootBeginInfoStrLen lb $5,0x0($3) 1: lb $4,0x0($2) jal _print # 通過序列槽列印寄存器r4的值 addi $2,$2,0x1 bne $5,$0,1b subu $5,$5,$1
###################### 擷取SimpleOS的長度 ##################### li $5,0x4 lui $1,0x3000 ori $1,$1,0x0300 # SimpleOS的長度資訊存儲在flash的0x300處 lw $1,0x0($1) # r1: rom length nop
###################### 從flash向SDRAM複制SimpleOS ################### lui $2,0x0000 # r2: destination address lui $3,0x3000 ori $3,$3,0x0304 # r3: source address 1: lw $4,0x0($3) nop sw $4,0x0($2) addi $2,$2,0x4 addi $3,$3,0x4 nop bgez $1,1b subu $1,$1,$5
###################### 列印啟動結束資訊 ################### li $1,0x1 la $2,_BootEndInfoStr la $3,_BootEndInfoStrLen lb $5,0x0($3) 1: lb $4,0x0($2) jal _print addi $2,$2,0x1 bne $5,$0,1b sub $5,$5,$1
###################### 跳轉到SDRAM ################### jr $0 nop
###################### 序列槽輸出函數 ################### _print: lui $6,0x1000 ori $6,$6,0x0 sb $4,0x0($6) # 向位址0x10000000寫入r8的值,0x10000000對應的就是 # 發送緩沖位址 _waiting_transmit_done: lui $6,0x1000 ori $6,$6,0x0005 lb $7,0x0($6) # 讀取位址0x10000005的值,對應的是line state寄存器的值
andi $7,$7,0x20 beq $7,$0,_waiting_transmit_done # 如果line state寄存器的第5bit為1,表示發送完畢 nop jr $31 nop
###################### 一些預定義常量 ################### .data _BootBeginInfoStr: .ascii "Loading OS into SDRAM...\n" _BootBeginInfoStrLen: .byte 26 _BootEndInfoStr: .ascii "Load OS into SDRAM DONE!!!\n" _BootEndInfoStrLen: .byte 28
SimpleOS.asm的主要作用是當序列槽收中斷時,在中斷處理例程中将序列槽收的資料再通過序列槽發送出去,實作回顯功能,其代碼如下:
.org 0x0 .set noat .set noreorder .set nomacro .global _start _start: ######################## SimpleOS的啟動代碼 ############################ ori $1,$0,0x100 jr $1 # 跳轉到0x100處,因為0x100位址以下是一些中斷處理的入口
######################## 外部中斷處理例程 ############################ .org 0x20 # 0x20是外部中斷的處理例程入口位址 mfc0 $1,$12,0x0 andi $4,$1,0x0100 bne $4,$0,_int2 # 判斷是否是UART輸入中斷,如果是,則跳轉到_int2 nop eret
######################## UART控制器初始化 ############################ .org 0x100 lui $1,0x1000 ori $1,$1,0x0003 ori $2,$0,0x80 sb $2,0x0($1)
lui $1,0x1000 ori $1,$1,0x0001 ori $2,$0,0x00 sb $2,0x0($1) # MSB of divisor latch
lui $1,0x1000 ori $1,$1,0x0000 ori $2,$0,0xB0 sb $2,0x0($1) # LSB of divisor latch
lui $1,0x1000 ori $1,$1,0x0003 ori $2,$0,0x03 sb $2,0x0($1) # 8bit, no parity, 1 stop bit
lui $1,0x1000 ori $1,$1,0x0001 ori $2,$0,0x01 sb $2,0x0($1) # 設定UART控制器在收到資料時送出中斷信号
###################### 設定OpenMIPS的status寄存器 ##################### lui $1,0x1000 ori $1,$1,0x0101 # 使能序列槽中斷,在OpenMIPS_min_sopc中序列槽中斷對應的是 # 中斷輸入的第1bit mtc0 $1,$12,0x0
###################### 循環等待 ##################### _loop: j _loop nop
###################### 處理序列槽中斷的函數 ################# _int2: lui $1,0x1000 ori $1,$1,0x0005 lb $3,0x0($1) # get line status register andi $3,$3,0x01 # 通過line status寄存器是否有資料輸入 beq $3,$0,_end # 如果沒有則跳轉到_end,結束中斷處理 nop
_sendback: # 有輸入資料,将輸入資料再通過序列槽輸出 lui $1,0x1000 ori $1,$1,0x0000 lb $2,0x0($1) sb $2,0x0($1)
_loop2: lui $1,0x1000 ori $1,$1,0x0005 lb $2,0x0($1) # get line status register
andi $2,$2,0x20 beq $2,$0,_loop2 nop
lui $1,0x1000 ori $1,$1,0x0005 lb $3,0x0($1) andi $3,$3,0x01 bne $3,$0,_sendback nop
_end: eret nop
3、Makefile與連結檔案
好了,在上一節介紹了測試程式,本節給出編譯上面的測試程式需要的Makefile與連結檔案,注意的是:編譯BootLoader與SimpleOS需要不同的Makefile與連結檔案,下面主要給出編譯BootLoader時要用的Makefile與連結腳本,對編譯SimpleOS的不同之處,會給出說明。 首先是連結檔案,命名為ram.ld,内容如下:
MEMORY { ram : ORIGIN = 0x30000000 , LENGTH = 0x00000300 }
SECTIONS { .text : { *(.text) } > ram
.data : { *(.data) } > ram
.bss : { *(.bss) } > ram
.stack ALIGN(0x10) (NOLOAD): { *(.stack) _ram_end = .; } > ram }
ENTRY (_start)
這個連結檔案是編譯BootLoader時需要的,因為BootLoader在flash中執行,而flash的起始位址是0x30000000,是以在上面的連結檔案中ram的ORIGIN是0x30000000。相應的,編譯SimpleOS時的連結檔案就要改變,因為SimpleOS是在SDRAM中運作,SDRAM的起始位址是0x00000000,是以編譯SimpleOS的連結檔案中的ram的ORIGIN是0x00000000,這一點要注意區分。 編譯BootLoader時的Makefile檔案如下:
ifndef CROSS_COMPILE CROSS_COMPILE = mips-sde-elf- endif CC = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump
OBJECTS = BootLoader.o
exportCROSS_COMPILE
# ******************** # Rules of Compilation # ********************
all: BootLoader.om BootLoader.bin BootLoader.asm
%.o: %.S $(CC) -mips32 $< -o [email protected] BootLoader.om: ram.ld $(OBJECTS) $(LD) -T ram.ld $(OBJECTS) -o [email protected] BootLoader.bin: BootLoader.om $(OBJCOPY) -O binary $< [email protected] BootLoader.asm: BootLoader.om $(OBJDUMP) -D $< > [email protected] clean: rm -f *.o *.om *.bin *.data *.mif *.asm
注意上面在編譯的時候加上-mips32選項。最後得到的二進制檔案BootLoader.bin。編譯SimpleOS對應的Makefile與上面類似,隻需要将BootLoader都改為SimpleOS即可。
4、測試程式編譯
好了,有了源程式、Makefile、連結檔案,我們可以編譯測試程式了。要在Ubuntu虛拟機中編譯,虛拟機中要已經安裝好了增對MIPS架構的GCC編譯器,具體安裝方法我就不再詳述了,這篇博文已經很長了,可以參考http://bbs.eetop.cn/thread-429161-1-1.html,在OpenMIPS教學版的文檔中也就介紹http://bbs.elecfans.com/jishu_411089_1_1.html。 在Ubuntu中,将Makefile、連結檔案、源程式放在一個檔案夾下(當然BootLoader與SimpleOS要分别編譯,是以需要兩個檔案夾),打開終端,使用cd指令進入BootLoader所在目錄,輸入make all,然後再進入SimpleOS所在目錄,輸入make all,這樣我們就編譯結束了。 編譯結束後,得到兩個檔案:BootLoader.bin、SimpleOS.bin。在本文最開始的時候介紹過,flash中存放是有規範的,是以此時需要利用我們提供的一個小工具BinMerge.exe,将編譯得到兩個檔案合并起來,并且符合規範。步驟如下:将編譯得到的兩個bin檔案與BinMerge.exe複制到同一個目錄下,然後打開終端,進入這個目錄,輸入如下指令:
./BinMerge.exe –f SimpleOS.bin –o OSImage.bin
如此,就得到最終的二進制檔案OSImage.bin。
5、flash燒錄
在之前的介紹中可以知道,OpenMIPS從flash啟動,是以需要将測試程式燒錄到flash中。DE2評估闆上提供了一個4MB的flash,且是nor flash,可以作為啟動盤使用。在燒錄程式到flash之前,需要先erase flash,這是flash的特性決定的。 首先打開quartusii的programmer工具,選擇DE2_USB_API.sof,作為要下載下傳目标闆上的檔案(注意不要在路徑中有中文),該檔案是DE2附帶CD光牒提供的(在OpenMIPS實踐版的釋出中也包含了該檔案)。如下:
下載下傳完成後,打開DE2附帶CD光牒的DE2_Control_Panel.exe程式(在OpenMIPS實踐版的釋出中也包含了該檔案),選擇Open菜單,點選Open USB Port,然後點選FLASH這個Tab,點選Chip Erase按鈕,将erase flash,該過程大約40秒鐘。
然後選中File Length前面的複選框,點選“Write a File to FLASH”按鈕,選擇在上一步節中得到的OSImage.bin檔案,就會将該檔案寫入flash中。這樣flash就燒錄完畢了。
注意此時需要點選Open菜單,然後點選“Close USB Port”,否則下面的步驟無法進行。
6、OpenMIPS工程建立
打開quartusii,建立一個工程檔案,添加OpenMIPS實踐版的rtl目錄下、min_sopc目錄下的所有檔案,如下:
使用cycloneii的EP2C35F672C6作為目标器件,這是DE2上的FPGA型号,這樣就完成了quartusii工程建立,然後可以編譯工程,編譯完成後設定引腳資訊,其中使用DE2上的27MHz時鐘作為輸入時鐘,GPIO口連接配接到4個7段數位管,OpenMIPS的reset輸入連接配接到撥碼開關sw17,同時還還設定flash、SDRAM的連接配接。
在OpenMISP實踐版的tools/Altera/DE2目錄下提供了一個檔案“引腳配置.txt”,其中有DE2上的引腳配置檔案,可以直接将該檔案複制到OpenMIPS_min_sopc.qsf中,即可完成引腳配置。配置完引腳後,需要再次編譯工程。得到OpenMIPS_min_sopc.sof檔案。
7、下載下傳測試
打開quartueii的programmer工具,選擇在10.2節得到的OpenMIPS_min_sopc.sof,将其下載下傳到DE2上,下載下傳完成後,撥動SW17開關,先向上撥一下,對應reset為高電平,OpenMIPS在複位,打開序列槽調試程式,然後再将sw17撥到下面,對應reset無效,此時OpenMIPS開始工作。會出現如下界面:
上面是BootLoader啟動界面,下面是SimpleOS運作時的回顯界面:
好了,小夥伴們,OpenMIPS實踐版驗證結束了,下一步就是移植ucos-II了,未完待續哦!