Use RISC-V assembly language to write a led marquee experiment
Related reference articles:
RISC-V teaching plan
# ASSEMBLY PROGRAM DESIGN li x8, 0xf0000000; # set gpio address addi x6, x0, 0; # initial x6 = 0 li x7, 0x00400000; # set x7 as delay counter START: addi x10, x0, 0x80; # x10 = 0x80, set gpio bit 7 not x18, x10; # x18 = ~x10 sh x18, 0(x8); # addr[0xf000_0000] = val[0x18] sh x0, 4(x8); # addr[0xf000_0004] = 0 as output LOOP: addi x6, x6 ,1; # x6 = x6 + 1 bne x6, x7,LOOP; # if(x6 != x7) goto LOOP addi x6, x0,0; # x6 = 0; srli x10, x10,1; # x10 >> 1 logic right shift 1 bit beq x10, x0,START; # if(x10 == 0x00) goto START not x18, x10; # x18 = ~x10 sh x18, 0(x8); # addr[0xf000_0000] = x18 jal LOOP; # pc = LOOP
LI x8, 0xf0000000; # set gpio address;
LI is a pseudo-instruction that can be translated into a LUI instruction by the compiler. This instruction stores the value 0xf000_0000 in the register x8, and the purpose is to store the address of the gpio in the x8 register for later use.
ADDI x6,x0,0 ; # Initialize variable x6 = 0;
The value of x0 is added to 0 and the sum is stored in the x6 register. Means to clear the x6 register. There is no special instruction for clearing in the risc-v assembly instruction set.
LI x7, 0x00400000; # x7 set delay counter
Store the value 0x0040_0000 into the x7 register. The x7 register is used as a delay counter timer. Use the delay generated by the program’s own loop to delay the LED for 1s. It takes about 1s to run 40_0000 loops.
START: ADDI x10, x0, 0x80; # x10 = 0x80, set gpio bit 7
START is the address label, followed by “:”, ADDI is the instruction code, and the register and the register or immediate data should be separated by “,”. Use “;” at the end of the command. Use “#” if you want to add a comment. The compiler will not compile the statement after “#”.
This instruction adds the value of x0 to 0x80 and stores the sum in x10. Since the value of x0 is 0, the actual effect is to store the value 0x80 in the x10 register. The X10 register is used to turn the LED on and off. The binary number corresponding to 0x80 is 1000_0000. But at present, the value in x10 cannot be directly output to the address of gpio. Because the led is a common anode design, one end is already 3.3V high level, if the GPIO interface corresponding to led7 is 1, led7 will not be lit. Instead, other LEDs will be lit, because LED6-0 is low at this time. So you need to invert the value of x10 as a whole.
NOT x18, x10; # x18 = ~x10 negated output
The NOT instruction is a pseudo-instruction, which inverts the value stored in x10 and stores it in x18. It means that the last output value is stored in the x18 register.
SH x18, 0(x8); # addr[0xf000_0000] = val[0x18]
Store the value of x18 at an address, which is obtained by adding the value of x8 and the immediate value 0. Because the value previously stored in X8 is the address of gpio, the value of x18 is output to gpio here.
SH x0, 4(x8); # addr[0xf000_0004] = 0 as output
Add 4 to the gpio address to generate the direction control register address f000_0004. Use the store instruction to store the value of x0 at address f000_0004. In this way, the value of the direction control register is set to 0, and LED7 is lit.
After the light is lit, it needs to be kept for 1s to perform a delayed operation. The program is implemented by loop loop.
ADDI x6, x6, 1; # x6 = x6 + 1
x6 acts as an accumulator, adding 1 once per loop
BNE x6, x7, LOOP; # if(x6 != x7) goto loop
It is judged that when x6 is not equal to x7, the program jumps to loop. That is, x6 continues to accumulate until x6 is equal to x7, and the loop is completed. Proceed to the next instruction.
ADDI x6, x0, 0; # x6 = 0
Clear x6, because the x6 accumulator will be used after lighting other lights and delaying 1s.
SRLI x10, x10,1; # x10 >> 1 , right shift 1 bit
Use the srli command, which shifts the value in x10 to the right by 1 bit to turn on the next light.
BEQ x10, x0, START; # if(x10 == 0x0) goto start
After moving, the value of x10 changes from 0x80 (1000_0000) to 0x40 (0100_0000), then moves right to 0x20, and finally becomes 0. At this point, all LEDs are turned off after inversion. The BEQ statement is needed to deal with all zeros. When x10 is all 0, jump to start, which is the position at the beginning of the program. The value of X10 is assigned the value 0x80.
NOT x18, x10; # x18 = ~x10
SH x18, 0(x8); # addr[0xf000_0000] = x18
JAL LOOP; # pc = loop
If x10 is not equal to 0, prove that x10 contains 1 in binary representation. It is not equal to 0. At this time, x10 is inverted and then output, which is equivalent to lighting the next lamp. Then jal jumps to the loop to delay 1s.