.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
.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