自制处理器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中的存放方式如下:

       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的附带光盘、串口调试助手、Ubuntu虚拟机、GCC
  • 硬件:Altera的DE2评估板

       好了,关于我们实验的基础知识就介绍了完了,下面开始进入正题,分以下几步:

  1. 硬件连接
  2. 测试程序讲解
  3. Makefile与链接文件
  4. 测试程序编译
  5. flash烧录
  6. OpenMIPS工程建立
  7. 下载测试
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 $@
BootLoader.om: ram.ld $(OBJECTS)
$(LD) -T ram.ld $(OBJECTS) -o $@
BootLoader.bin: BootLoader.om
$(OBJCOPY) -O binary $<  $@
BootLoader.asm: BootLoader.om
$(OBJDUMP) -D $< > $@
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附带光盘提供的(在OpenMIPS实践版的发布中也包含了该文件)。如下:

       下载完成后,打开DE2附带光盘的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了,未完待续哦!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值