Gaviar (小志掌機) >> Assembly
LED
參考資訊:
1. ws2812c
2. Delay_slot
3. FlatHeadBro
PE5用來控制LED,不過這顆LED是WS2812C,它需要透過串列訊號控制

WS2812C裡面有R、G、B三顆LED,每顆LED用一個Byte來代表亮度,傳送的串列訊號如下:

因為只有一隻DI腳位,因此,對於時序有一些要求,如果要傳送0,需要的時序是T0H(300ns)+T0L(850ns),而傳送1則是T1H(800ns)+T1L(400ns),結尾需要傳送RET(>280us)

GPIO位址

PE_CFG0

PE_DAT

main.s
.global _start
.equ GPIO_BASE, 0x02000000
.equ PE_CFG0, 0x00c0
.equ PE_DAT, 0x00d0
.equ _50NS, 10
.equ _100NS, 20
.equ _200NS, 40
.equ _300NS, 60
.equ _400NS, 80
.equ _450NS, 90
.equ _800NS, 160
.equ _850NS, 170
.equ _1US, 200
.equ _1S, 200000000
.text
.long 0x4000006f
.byte 'e','G','O','N','.','B','T','0'
.long 0x5F0A6C39
.long 0x8000
.long 0, 0
.long 0, 0, 0, 0, 0, 0, 0, 0
.long 0, 0, 0, 0, 0, 0, 0, 0
.org 0x0400
_start:
li t0, 0x100000
li a0, GPIO_BASE + PE_CFG0
sw t0, 0(a0)
li a0, GPIO_BASE + PE_DAT
0:
li t0, (1 << 12)
jal b24
li t0, _1S
jal delay
li t0, (0 << 0)
jal b24
li t0, _1S
jal delay
j 0b
b24:
move t2, ra
move t3, t0
li t4, 24
0:
and t0, t3, 1
srl t3, t3, 1
beqz t0, 1f
jal b1
j 2f
1:
jal b0
2:
addi t4, t4, -1
bgtz t4, 0b
jr t2
b0:
move t1, ra
li t0, (1 << 5)
sw t0, 0(a0)
li t0, _300NS
jal delay
li t0, (0 << 5)
sw t0, 0(a0)
li t0, _850NS
jal delay
jr t1
b1:
move t1, ra
li t0, (1 << 5)
sw t0, 0(a0)
li t0, _800NS
jal delay
li t0, (0 << 5)
sw t0, 0(a0)
li t0, _400NS
jal delay
jr t1
delay:
addi t0, t0, -1
bgtz t0, delay
jr ra
.end
main.ld
MEMORY {
FLASH : ORIGIN = 0, LENGTH = 32M
}
SECTIONS {
.text : { *(.text*) } > FLASH
.rodata : { *(.rodata*) } > FLASH
.bss : { *(.bss*) } > FLASH
}
Makefile
all: riscv64-unknown-linux-gnu-as -o main.o main.s riscv64-unknown-linux-gnu-ld -T main.ld -o main.elf main.o riscv64-unknown-linux-gnu-objcopy -O binary main.elf tmp.bin python3 gen_checksum.py tmp.bin main.bin run: xfel ddr f133 && xfel write 0x40000000 main.bin && xfel exec 0x40000000 clean: rm -rf main.bin main.o main.elf tmp.bin
連接USB到PC
$ lsusb
Bus 002 Device 064: ID 1f3a:efe8 Onda (unverified) V972 tablet in flashing mode
編譯
$ make
riscv64-unknown-linux-gnu-as -o main.o main.s
riscv64-unknown-linux-gnu-ld -T main.ld -o main.elf main.o
riscv64-unknown-linux-gnu-objcopy -O binary main.elf tmp.bin
python3 gen_checksum.py tmp.bin main.bin
下載
$ make run
xfel ddr f133 && xfel write 0x40000000 main.bin && xfel exec 0x40000000
100% [================================================] 16.000 KB, 383.004 KB/s
完成


開頭使用0x4000006f,它是一個跳躍指令,因為第4個Byte後的資料會由BROM使用,至於司徒為何要保留長度1024(0x400)?因為F133的中斷向量總共有223個,中斷向量位址達到0x380,因此,司徒就從0x400開始執行,至於BROM使用的資料格式,可以參考https://github.com/Ouyancheng/FlatHeadBro/blob/master/boot0/boot0-header.c
$ /opt/f133/bin/riscv64-unknown-linux-gnu-objdump -bbinary -mriscv:rv64 -D main.bin | head -n20
main.bin: file format binary
Disassembly of section .data:
0000000000000000 <.data>:
0: 4000006f j 0x400
4: 4765 li a4,25
6: 422e4e4f fnmadd.d ft8,ft8,ft2,fs0,rmm
a: 3054 fld fa3,160(s0)
c: 8c78 0x8c78
e: 9a24 0x9a24
10: 4000 lw s0,0(s0)
...
3fe: 0000 unimp
400: 001002b7 lui t0,0x100
404: 02000537 lui a0,0x2000
408: 0c05051b addiw a0,a0,192
40c: 00552023 sw t0,0(a0) # 0x2000000
仔細的玩家應該可以發現,RISC-V沒有MIPS的Delay Slot,不需要在跳躍指令後面塞一個nop或者做指令排序,在開發PSP模擬器踩到的坑洞,看來RISC-V應該解決了,而所謂的Delay Slot指的就是如下狀況:
lw v0,4(v1) # load word from address v1+4 into v0 nop # wasted load delay slot jr v0 # jump to the address specified by v0 nop # wasted branch delay slot
如果jr後面沒有插入nop,則會跑飛,因為jr慢了一步執行(提取、解碼、執行),這種Delay Slot狀況是跟架構設計有關係,不過,司徒可以看到RISC-V的進步,真是感動流淚~