天天看點

自制處理器OpenMIPS移植ucos-II過程之3——DE2驗證OpenMIPS

在第二部分中,已經介紹了基于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中的存放方式如下:

自制處理器OpenMIPS移植ucos-II過程之3——DE2驗證OpenMIPS

       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評估闆

       好了,關于我們實驗的基礎知識就介紹了完了,下面開始進入正題,分以下幾步:

  1. 硬體連接配接
  2. 測試程式講解
  3. Makefile與連結檔案
  4. 測試程式編譯
  5. flash燒錄
  6. OpenMIPS工程建立
  7. 下載下傳測試

1、硬體連接配接        很簡單喽,如下,DE2與PC機的連接配接如下:

自制處理器OpenMIPS移植ucos-II過程之3——DE2驗證OpenMIPS

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實踐版的釋出中也包含了該檔案)。如下:

自制處理器OpenMIPS移植ucos-II過程之3——DE2驗證OpenMIPS

       下載下傳完成後,打開DE2附帶CD光牒的DE2_Control_Panel.exe程式(在OpenMIPS實踐版的釋出中也包含了該檔案),選擇Open菜單,點選Open USB Port,然後點選FLASH這個Tab,點選Chip Erase按鈕,将erase flash,該過程大約40秒鐘。

自制處理器OpenMIPS移植ucos-II過程之3——DE2驗證OpenMIPS

       然後選中File Length前面的複選框,點選“Write a File to FLASH”按鈕,選擇在上一步節中得到的OSImage.bin檔案,就會将該檔案寫入flash中。這樣flash就燒錄完畢了。

       注意此時需要點選Open菜單,然後點選“Close USB Port”,否則下面的步驟無法進行。

6、OpenMIPS工程建立

       打開quartusii,建立一個工程檔案,添加OpenMIPS實踐版的rtl目錄下、min_sopc目錄下的所有檔案,如下:

自制處理器OpenMIPS移植ucos-II過程之3——DE2驗證OpenMIPS

       使用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開始工作。會出現如下界面:

自制處理器OpenMIPS移植ucos-II過程之3——DE2驗證OpenMIPS

       上面是BootLoader啟動界面,下面是SimpleOS運作時的回顯界面:

自制處理器OpenMIPS移植ucos-II過程之3——DE2驗證OpenMIPS

      好了,小夥伴們,OpenMIPS實踐版驗證結束了,下一步就是移植ucos-II了,未完待續哦!