Menu Close

RISC-V 汇编语言程序设计(2)汇编程序asm_run_led

使用RISC-V 汇编语言,编写一个led 跑马灯的实验

相关参考文章:

RISC-V教学教案

程序分析:

LI x8, 0xf0000000;                               # 设置gpio address;

LI是伪指令,可被编译器翻译成LUI指令,该指令把值0xf000_0000存放到寄存器x8里,目的是把gpio的地址存储到x8寄存器中以便之后使用。

ADDI x6,x0,0 ;                                         # 初始化 变量x6 =0;

x0的值和0相加后将和存储到x6寄存器中。意为将x6寄存器清零。risc-v汇编指令集内无专门用来清零的指令。

LI x7, 0x00400000;                              # x7 设置delay counter

将值0x0040_0000存储到x7寄存器中。x7寄存器作为delay counter计时器使用。利用程序自身循环产生的延时使LED延时1s。大概跑40_0000次循环需要1s。

START:      ADDI x10, x0, 0x80;       # x10 = 0x80, set gpio bit 7

START是地址标号,后面要跟“:”,ADDI是指令码,寄存器和寄存器或立即数之间要用“,”隔开。指令结束要用“;”。如果想加注释要用“#”。编译器不会编译“#”后的语句。

该指令把x0的值和0x80相加,将和存到x10里。因为x0的值为0,实际上效果使把值0x80存到x10寄存器里。X10寄存器被用来点亮和熄灭LED。0x80对应的2进制数是1000_0000。但是目前不能把x10内的值直接输出到gpio的地址上。因为led是共阳设计,一端已经是3.3V高电平,led7对应的GPIO接口如果是1,led7不会被点亮。反而其他led灯会被点亮,因为led6-0此时为低电平。所以需要把x10的值整体取反。

NOT x18, x10;                                           # x18 = ~x10 取反输出

NOT指令是伪指令,该指令把x10内存储的值取反后存到x18里。意为最后输出的值存在x18寄存器内。

SH x18, 0(x8);                                          # addr[0xf000_0000] = val[0x18]

把x18的值存到一个地址上,地址由x8的值和立即数0相加得到。因为X8内之前保存的值是gpio的地址,所以此处是把x18的值输出到gpio上。

SH x0, 4(x8);                                            # addr[0xf000_0004] = 0 as output

用gpio的地址加4,生成方向控制寄存器地址f000_0004。使用store指令把x0的值存到地址f000_0004上去。这样方向控制寄存器的值就被设置为0,点亮led7。

灯点亮后需要让它保持1s,进行一个延时的操作。程序里通过loop循环来实现。

ADDI x6, x6, 1;                                         # x6 = x6 + 1

x6作为累加器,每循环一次加1

BNE x6, x7, LOOP;                                 # if(x6 != x7) goto loop

判断 当x6不等于x7时,程序跳转到loop。也就是x6继续累加,直到x6等于x7,loop循环完毕。进行下一条指令。

ADDI x6, x0, 0;                                        # x6 = 0

清零x6,因为x6这个累加器之后在点亮其他灯并延时1s还要被用到。

SRLI x10, x10,1;                                       # x10 >> 1 , 右移 1 bit

用srli指令,该指令把x10里的值右移1位,点亮下一个灯。

BEQ x10, x0, START;                            # if(x10 == 0x0) goto start

移动后x10的值由0x80   (1000_0000)变成0x40 (0100_0000),再右移变成0x20,最后变成0。此时取反后所有LED都被熄灭了。为了应对全是0的情况就需要BEQ语句。当x10全是0时跳转到start也就是程序一开始的位置。X10的值被赋值为0x80。

NOT x18, x10;                                           # x18 = ~x10

SH x18, 0(x8);                                          # addr[0xf000_0000] = x18

JAL LOOP;                                                 # pc = loop

如果x10不等于0,证明x10以二进制表示含有1。还不等于0,此时x10被取反再输出,等于点亮了下一个灯。随后jal跳转到loop里来延时1s。

Posted in RISC-V 教材教案

发表评论

您的电子邮箱地址不会被公开。

Leave the field below empty!

相关链接