-
Notifications
You must be signed in to change notification settings - Fork 0
/
breath.asm
494 lines (474 loc) · 15 KB
/
breath.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
#################################################################################
# Minisys_BIOS v0.1 #
# #
#################################################################################
.data 0x0000 # 数据定义的首地址
INT_TABLE .word 0x000000D4 # 外部中断0 中断处理入口
INT1 .word 0x000000DC # 外部中断1 中断处理入口
INT2 .word 0x000000E4 # 外部中断2 中断处理入口
INT3 .word 0x000000EC # 外部中断3 中断处理入口
INT4 .word 0x000000F4 # 外部中断4 中断处理入口
INT5 .word 0x0000012C # 外部中断5 中断处理入口
SYSC .word 0x00000134 # syscall 异常处理入口
BREK .word 0x000001C8 # break 异常处理入口
UIMP .word 0x000001DC # 保留指令 异常处理入口
PRIR .word 0x000001E4 # 特权级访问 异常处理入口
OVFL .word 0x000001EC # 加减溢出 异常处理入口
DVZE .word 0x000001F4 # 除零 异常处理入口
STAT .word 0x00000000 # 用于定时器1调整PWM
.space 0x0000000C
#.data 0x0040 # 堆栈区
STACK_BUFF .word 0x00000000
.space 0x0000007C
#.data 0x00C0 # 键盘输入缓冲区
KEY_BUFF .word 0x00000000 # 键盘输入缓冲区指针
.space 0x0000007C
#.data 0x0140
.space 0xf6c0
#.data 0xf800
USER_DATA .word 0x0
.text 0x0000
@start: j @initial # 跳转到初始化程序
#################################################################################
# 以下为异常中断处理程序
# 用户自定义中断处理时 根据需要 将中断处理程序地址存入 RAM 相应位置
# RAM 前六个地址对应六个中断处理程序地址 随后紧跟六个异常处理程序地址
#################################################################################
# 中断异常处理基地址
mfc0 $k0, $13 # 读cp0原因寄存器 $13:CAUSE寄存器地址
andi $k1, $k0, 0x007C # exc_code CAUSE[6:2]
beq $k1, $zero, @out_int # 外部中断
addi $t0, $zero, 0x60 # 异常
sw $k1, 0xfc00($t0) # 点亮led 显示异常代码
addi $k1, $k1, 0xFFE8 # exc_code - 8
@chk_table: lw $k1, INT_TABLE($k1) # 查中断向量表
jr $k1 # 跳转到相应中断处理程序
@out_int: andi $k1, $k0, 0xFC00 # ip[7:2] CAUSE[15:10]
mfc0 $k0, $12 # 读cp0状态寄存器 $12:STATUS寄存器
andi $k0, $k0, 0xFC00 # im[7:2] STATUS[15:10]
and $k0, $k0, $k1 # im & ip
srl $k0, $k0, 10 # 对齐到地址低位
andi $k1, $k0, 0x0001 # IP[0]
bgtz $k1, @EInt0
andi $k1, $k0, 0x0002 # IP[1]
bgtz $k1, @EInt1
andi $k1, $k0, 0x0004 # IP[2]
bgtz $k1, @EInt2
andi $k1, $k0, 0x0008 # IP[3]
bgtz $k1, @EInt3
andi $k1, $k0, 0x0010 # IP[4]
bgtz $k1, @EInt4
andi $k1, $k0, 0x0020 # IP[5]
bgtz $k1, @EInt5
@EInt0: addi $k1, $zero, 0x00 # +0x0:External Int 0
j @chk_table
@EInt1: addi $k1, $zero, 0x04 # +0x4:External Int 1
j @chk_table
@EInt2: addi $k1, $zero, 0x08 # +0x8:External Int 2
j @chk_table
@EInt3: addi $k1, $zero, 0x0c # +0xc:External Int 3
j @chk_table
@EInt4: addi $k1, $zero, 0x10 # +0x10:External Int 4
j @chk_table
@EInt5: addi $k1, $zero, 0x14 # +0x14:External Int 5
j @chk_table
# 未定义外部中断
@INT0: eret
@INT1: eret
@INT2: eret
@INT3: eret
@INT4: eret
@INT5: eret
# 4x4键盘中断处理程序
# @INT3: lw $k1, 0xFC02($zero) # 获取数码管高四位数据
# lw $k0, 0xFC00($zero) # 获取数码管低四位数据
# sll $k1, $k1, 16 # 左移16位
# add $k0, $k0, $k1 # 高低位相加
# sll $k0, $k0, 4
# lw $k1, 0xFC10($zero) # 读取键盘键值
# add $k0, $k0, $k1
# sw $k0, 0xFC00($k0) # 显示数码管低四位数据
# srl $k0, $k0, 16
# sw $k0, 0xFC02($k0) # 显示数码管高四位数据
# eret
# lui $k0, 0xFFFF
# ori $k0, $k0, 0xF000 # k0 接口地址高20位
# lw $k1, 0x0C12($k0) # 读取键盘状态
# andi $k1, $k1, 0x0001
# bgtz $k1, @load3 # 如果有按键按下
# @end3: eret
# @load3: lw $k1, 0x0C10($k0) # 读取键盘键值
# lw $k0, KEY_BUFF($zero) # 键盘输入缓冲区指针
# addi $k0, $k0, 0x0004 # +4
# andi $k0, $k0, 0x007F # 如果缓冲区满 [KEY_BUFF] = 0x0080
# bgtz $k0, @full3 # 则从缓冲区首地址重新开始
# @store3:sw $k1, KEY_BUFF($k0) # 存入键盘键值
# sw $k1, 0x0C60($k0) # 点亮led (测试)
# sw $k0, KEY_BUFF($zero) # 存入键盘输入缓冲区指针
# j @end3 # 中断处理结束
# @full3: addi $k0, $zero, 0x0004 # [KEY_BUFF] = 0x0004
# j @store3
# 定时器0
# @INT4: lui $k0, 0xFFFF
# ori $k0, $k0, 0xF000 # k0 接口地址高20位
# lw $k1, 0x0C70($k0) # 读取拨码开关状态
# sw $k1, 0x0C60($k0) # 点亮led
# eret
# 定时器1
# @INT5: lw $k0, STAT($zero) # 获取当前状态
# beq $k0, $zero, @pwmadd
# @pwm_: lw $k0, 0xFC32($zero) # 读取PWM中间值
# beq $k0, $zero, @toadd
# addi $k0, $k0, -1
# j @end5
# @toadd: sw $zero, STAT($zero) # 变状态
# addi $k0, $zero, 1
# j @end5
# @pwmadd:lw $k0, 0xFC32($zero) # 读取PWM中间值
# lw $k1, 0xFC30($zero) # 读取PWM最大值
# beq $k0, $k1, @to_
# addi $k0, $k0, 1 # 中间值+1
# j @end5
# @to_: addi $k1, $zero, 1
# sw $k1, STAT($zero) # 变状态
# addi $k0, $k0, -1
# @end5: sw $k0, 0xFC32($zero) # 存中间值
# eret
# lui $k0, 0xFFFF
# ori $k0, $k0, 0xF000 # k0 接口地址高20位
# lw $k1, 0x0C70($k0) # 读取拨码开关状态
# sw $k1, 0x0C00($k0) # 显示数码管
# srl $k1, $k1, 16
# sw $k1, 0x0C02($k0) # 显示数码管
# eret
# syscall
@sysc: addi $k0, $zero, 0x0001 #
beq $k0, $v0, @Esys1 # 系统调用1
addi $k0, $zero, 0x0002 #
beq $k0, $v0, @Esys2 # 系统调用2
addi $k0, $zero, 0x0003 #
beq $k0, $v0, @Esys3 # 系统调用3
addi $k0, $zero, 0x0004 #
beq $k0, $v0, @Esys4 # 系统调用4
addi $k0, $zero, 0x0005 #
beq $k0, $v0, @Esys5 # 系统调用5
eret
@Esys1: jal @DigiDisp
eret
@Esys2: jal @KeyDisp
eret
@Esys3: jal @BuffDisp
eret
@Esys4: jal @chk_switch
eret
@Esys5: jal @light_led
eret
# break
@brek: mfc0 $k0, $14 # 获取EPC
andi $k0, $k0, 0x0004 # EPC加4
mtc0 $k0, $14
eret
# 保留指令
@uimp: j @BREK # 同BREK
# 特权级访问
@prir: j @BREK # 同BREK
# 加减溢出
@ofvl: j @BREK # 同BREK
# 除零
@dvze: j @BREK # 同BREK
#############################################################################
# 以下为BIOS系统调用
# 使用系统调用时 将系统调用号存入$v0寄存器
# 相应系统调用所需参数存入$a0 $a1 $a2 $a3寄存器
#############################################################################
# syscall 1
# 数码管显示数字
# 传入参数:$a0 - 待显示的32位数值数据
# $a1 - 显示控制字([15:8]位选,[7:0]小数点控制)
# 临时变量:$t7
@DigiDisp: addi $t7, $zero, 0x0
sw $a0, 0xfc00($t7) # 低16位写入0xfffffc00
addi $t7, $zero ,0x2
srl $a0, $a0, 8 # 右移16位
sw $a0, 0xfc00($t7) # 高16位写入0xfffffc02
addi $t7, $zero, 0x4
sw $a1, 0xfc00($t7) # 控制字写入0xfffffc04
jr $31 # 返回主调过程
# syscall2 显示缓冲区最新数据到数码管最低位
# 数码管其它位数据左移
# 无调用参数 使用临时变量$t7 $t6 $t5
@KeyDisp: lw $t7, 0xFC02($zero) # 获取数码管高四位数据
lw $t6, 0xFC00($zero) # 获取数码管低四位数据
sll $t7, $t7, 16 # 左移16位
add $t7, $t7, $t6 # 高低位相加
lw $t6, KEY_BUFF($zero) # 获取缓冲区指针
lw $t5, KEY_BUFF($t6) # 获取最新数据
sll $t7, $t7, 4 # 左移四位
add $t7, $t5, $t7 # 相加
sw $t7, 0xFC00($zero) # 存数码管低四位
srl $t7, $t7, 16 # 右移16位
sw $t7, 0xFC02($zero) # 存数码管高四位
jr $31 # 返回
# syscall 3
# 数码管显示输入缓冲区内最新的8个字(符)
# 若缓冲区指针小于8,则只显示0xc1-bp的字符。
# 缓冲区高地址字符(新字符)在数码管右侧(低位)
# 说明:输入缓冲区从0xc1到0x13c,0xc0为缓冲区指针bp,指针向高地址移动
# 传入参数:无
# 需要调用:上面的@DigiDisp:,使用参数a0、a1。
# 临时变量:$t7 $t6 $t5 $t4
@BuffDisp: lw $t7, 0xc0($zero) # 读取缓冲区指针bp到$t7(bp>=4)
addi $t6, $t7,-32 # t6 = bp - 32
bltz $t6, @LessThan8 # if bp >= 32 then goto @LessThan8
# 若bp>=32,即缓冲区内字符不少于8个
@MoreThan8: addi $t6, $t7, -4 # t6 = t7 - 4 移位位数
lw $t5, 0xc0($t7) # t5 = buff[bp]
sllv $t5, $t5, $t6 # t5 = t5 << t6
or $a0, $a0, $t5 # a0 = a0 | t5
addi $t7, $t7, -4 # t7 -= 4
addi $t6, $t7, -4
bgez $t6, @MoreThan8 # t7>=4 then goto @MoreThan8
addi $a1, $zero, 0xff00 # 数码管八位全开,小数点不显示
j @DigiDisp # 进入显示子程序
@LessThan8: addi $t4, $zero, 0x0 # t4(count) = 0
addi $t5, $zero, 28 # t5(const) = 28
sub $t6, $t5, $t4 # t6 = 28 - count
lw $t5, 0xc0($t7) # t5 = buff[bp]
sllv $t5, $t5, $t6 # t5 = t5 << (28-count)
or $a0, $a0, $t5 # a0 = a0 | t5
addi $t4, $t4, +4 # count += 4
addi $t7, $t7, -4 # bp -= 4
addi $t6, $t7, -4
bgez $t6, @LessThan8 # t7>=4 then goto @LessThan8
sll $t4, $t4, 2 # count = count / 4
addiu $a1, $zero, 0xffff
addi $t6, $zero, 24
sub $t6, $t6, $t4 # t6 = 32 - count
srlv $a1, $a1, $t4
sllv $a1, $a1, $t4 # 取高count位,控制数码管高count位点亮
j @DigiDisp # 进入显示子程序
# syscall4
# 检查拨码开关状态 使用 $t7
# 使用 $v1 作为返回值 返回当前拨码开关状态
@chk_switch:addi $t7, $zero, 0x70
lw $v1, 0xfc00($t7) # 读取拨码开关状态
jr $31
# syscall5
# 点亮led
# 使用 $a0 作为参数 使用 $t7
@light_led: addi $t7, $zero, 0x60
sw $a0, 0xfc00($t7) # 点亮led
jr $31
################################################################################
# 以下为BIOS初始化 开启中断 从内核态转到用户态 并调到用户程序地址
################################################################################
# BIOS初始化程序
@initial: addiu $t0, $zero, 0xFC11 # im:status[15:8] = 8'b11111100
# ksu:status[4:3] = 2'b10 ie:status[0] = 1'b1
mtc0 $t0, $12 # 开中断并且切换到用户态
addi $sp, $zero, 0x0 #
# j @user_code # 跳转到用户程序
jal @main
@__loop__: j @__loop__
################################################################################
# 以下为用户程序
################################################################################
@main:addi $sp, $sp, -4
sw $ra, USER_DATA($sp)
addi $sp, $sp, -4
sw $fp, USER_DATA($sp)
addi $fp, $sp, 8
addi $sp,$sp,-552
addi $t0 ,$zero ,0x0001
addi $t1 ,$zero ,60000
addi $t2 ,$zero ,0
addi $t3 ,$zero ,0
addi $t4 ,$zero ,1
addi $t5 ,$zero ,0
addi $t6 ,$zero ,0
sw $t4 , 0x0FFFFFC34($zero)
sw $t1 , 0x0FFFFFC30($zero)
addi $v1 ,$fp , -12
sw $t0, USER_DATA($v1)
addi $v1 ,$fp , -16
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -20
sw $t2, USER_DATA($v1)
addi $v1 ,$fp , -24
sw $t3, USER_DATA($v1)
addi $v1 ,$fp , -28
sw $t4, USER_DATA($v1)
addi $v1 ,$fp , -32
sw $t5, USER_DATA($v1)
addi $v1 ,$fp , -36
sw $t6, USER_DATA($v1)
@label1:addi $t0 ,$zero ,1
addi $t1 ,$zero ,0
addi $v1 ,$fp , -40
sw $t0, USER_DATA($v1)
addi $v1 ,$fp , -44
sw $t1, USER_DATA($v1)
sub $t2, $t0, $t1
blez $t2, @label3
addi $t3 ,$zero ,0
addi $v1 ,$fp , -24
lw $t4, USER_DATA($v1)
addi $v1 ,$fp , -24
sw $t4, USER_DATA($v1)
addi $v1 ,$fp , -40
sw $t0, USER_DATA($v1)
addi $v1 ,$fp , -44
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -48
sw $t2, USER_DATA($v1)
addi $v1 ,$fp , -52
sw $t3, USER_DATA($v1)
bne $t4, $t3, @label5
addi $v1 ,$fp , -20
lw $t5, USER_DATA($v1)
addi $t5, $t5, 500
addi $v1 ,$fp , -20
sw $t5, USER_DATA($v1)
addi $v1 ,$fp , -24
sw $t4, USER_DATA($v1)
addi $v1 ,$fp , -40
sw $t0, USER_DATA($v1)
addi $v1 ,$fp , -44
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -48
sw $t2, USER_DATA($v1)
addi $v1 ,$fp , -52
sw $t3, USER_DATA($v1)
@label5:addi $t0 ,$zero ,1
addi $v1 ,$fp , -24
lw $t1, USER_DATA($v1)
addi $v1 ,$fp , -24
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -56
sw $t0, USER_DATA($v1)
bne $t1, $t0, @label7
addi $v1 ,$fp , -20
lw $t2, USER_DATA($v1)
addi $t2, $t2, -500
addi $v1 ,$fp , -20
sw $t2, USER_DATA($v1)
addi $v1 ,$fp , -24
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -56
sw $t0, USER_DATA($v1)
@label7:addi $t0 ,$zero ,60000
addi $v1 ,$fp , -20
lw $t1, USER_DATA($v1)
addi $v1 ,$fp , -20
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -60
sw $t0, USER_DATA($v1)
bne $t1, $t0, @label9
addi $v1 ,$fp , -24
lw $t2, USER_DATA($v1)
addi $t2 ,$zero ,1
addi $v1 ,$fp , -20
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -24
sw $t2, USER_DATA($v1)
addi $v1 ,$fp , -60
sw $t0, USER_DATA($v1)
@label9:addi $t0 ,$zero ,0
addi $v1 ,$fp , -20
lw $t1, USER_DATA($v1)
addi $v1 ,$fp , -20
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -64
sw $t0, USER_DATA($v1)
bne $t1, $t0, @label11
addi $v1 ,$fp , -24
lw $t2, USER_DATA($v1)
addi $t2 ,$zero ,0
addi $v1 ,$fp , -20
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -24
sw $t2, USER_DATA($v1)
addi $v1 ,$fp , -64
sw $t0, USER_DATA($v1)
@label11:addi $t0 ,$zero ,0x4000
addi $v1 ,$fp , -12
lw $t1, USER_DATA($v1)
addi $v1 ,$fp , -12
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -68
sw $t0, USER_DATA($v1)
bne $t1, $t0, @label13
addi $t1 ,$zero ,0x01
addi $v1 ,$fp , -12
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -68
sw $t0, USER_DATA($v1)
j @label14
@label13:addi $v1 ,$fp , -12
lw $t0, USER_DATA($v1)
sll $t0 ,$t0 ,1
addi $v1 ,$fp , -12
sw $t0, USER_DATA($v1)
@label14:addi $v1 ,$fp , -20
lw $t0, USER_DATA($v1)
sw $t0 , 0xFFFFFC32($zero)
addi $v1 ,$fp , -12
lw $t1, USER_DATA($v1)
sw $t1 , 0xFFFFFC60($zero)
addi $v1 ,$fp , -12
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -20
sw $t0, USER_DATA($v1)
@label15:addi $t0 ,$zero ,1000
addi $v1 ,$fp , -32
lw $t1, USER_DATA($v1)
addi $v1 ,$fp , -32
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -72
sw $t0, USER_DATA($v1)
sub $t2, $t1, $t0
bgtz $t2, @label17
addi $t1, $t1, 1
addi $v1 ,$fp , -32
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -72
sw $t0, USER_DATA($v1)
addi $v1 ,$fp , -76
sw $t2, USER_DATA($v1)
@label18:addi $t0 ,$zero ,1000
addi $v1 ,$fp , -36
lw $t1, USER_DATA($v1)
addi $v1 ,$fp , -36
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -80
sw $t0, USER_DATA($v1)
sub $t2, $t1, $t0
bgtz $t2, @label20
addi $t1, $t1, 1
addi $v1 ,$fp , -36
sw $t1, USER_DATA($v1)
addi $v1 ,$fp , -80
sw $t0, USER_DATA($v1)
addi $v1 ,$fp , -84
sw $t2, USER_DATA($v1)
j @label18
@label20:addi $v1 ,$fp , -36
lw $t0, USER_DATA($v1)
addi $t0 ,$zero ,0
addi $v1 ,$fp , -36
sw $t0, USER_DATA($v1)
j @label15
@label17:addi $v1 ,$fp , -32
lw $t0, USER_DATA($v1)
addi $t0 ,$zero ,0
addi $v1 ,$fp , -32
sw $t0, USER_DATA($v1)
j @label1
@label3:addi $t0 ,$zero ,0
addi $sp, $fp, -8
lw $fp, USER_DATA($sp)
addi $sp, $sp, 4
lw $ra, USER_DATA($sp)
addi $sp, $sp, 4
addi $v0,$t0, 0
jr $ra