拿到打樣後的 PCB, 緊接著就需要進行驗證的動作, 一般在這個環節會有簡單的量產測試工具, 用來快速驗證某些模塊的功能是否正常, 這就是司徒接下來要介紹的東西, 如何寫出簡單的測試程序並下載到小志掌機做測試~
由於需要用到平頭哥的編譯器 (司徒一開始以為平頭哥是一個人...), 因此, 需要手動下載安裝
$ cd
$ wget https://github.com/steward-fu/archives/releases/download/f133/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.1-20220906.tar.gz
$ tar xvf Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.1-20220906.tar.gz
$ sudo mv Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.1 /opt/f133
$ export PATH=/opt/f133/bin:$PATH
$ riscv64-unknown-linux-gnu-gcc --version
riscv64-unknown-linux-gnu-gcc (Xuantie-900 linux-5.10.4 glibc gcc Toolchain V2.6.1 B-20220906) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
這階段的測試驗證將會使用 xfel 工具, 安裝方式如下
$ cd
$ git clone https://github.com/xboot/xfel
$ cd xfel
$ make
$ sudo make install
$ xfel --help
xfel(v1.3.1) - https://github.com/xboot/xfel
接下來, 司徒將會說明如何驗證 LED 部份, 確定你拿到的 PCB 是可以正常工作的, PE5 用來控制 LED,不過這顆 LED 是 WS2812C,它需要透過串列訊號控制, F133 本身就支援 LEDC 控制, 因此, 司徒將介紹如何透過 LEDC 點亮 LED
1.jpg
WS2812C 裡面有 R、G、B 三顆 LED,每顆 LED 用一個 Byte 來代表亮度,傳送的串列訊號如下:
2.jpg
因為只有一隻 DI 腳位,因此,對於時序有一些要求,如果要傳送 0,需要的時序是 T0H(300ns)+T0L(850ns),而傳送 1 則是 T1H(800ns)+T1L(400ns),結尾需要傳送 RET(>280us)
3.jpg
GPIO 位址
4.jpg
PE_CFG0 (0x0101 = LEDC-DO)
5.jpg
LEDC Clock 可以使用 HOSC、PeriPLL1x
6.jpg
CCU 位址
7.jpg
LEDC Clock
8.jpg
目前使用 HOSC
9.jpg
Clock Reset、Gating
10.jpg
目前關閉 DMA
10.jpg
main.s
.global _start
.equ CCU_BASE, 0x02001000
.equ GPIO_BASE, 0x02000000
.equ LEDC_BASE, 0x02008000
.equ PE_CFG0, 0x00c0
.equ _1S, 200000000
.equ LEDC_CLK_REG, 0x0bf0
.equ LEDC_BGR_REG, 0x0bfc
.equ LEDC_CTRL_REG, 0x0000
.equ LED_T01_TIMING_CTRL_REG, 0x0004
.equ LEDC_DATA_FINISH_CNT_REG, 0x0008
.equ LED_RESET_TIMING_CTRL_REG, 0x000c
.equ LEDC_WAIT_TIME0_CTRL_REG, 0x0010
.equ LEDC_DATA_REG, 0x0014
.equ LEDC_DMA_CTRL_REG, 0x0018
.equ LEDC_INT_CTRL_REG, 0x001c
.equ LEDC_INT_STS_REG, 0x0020
.equ LEDC_WAIT_TIME1_CTRL_REG, 0x0028
.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, (1 << 16) | (1 << 0)
li a0, CCU_BASE + LEDC_BGR_REG
sw t0, 0(a0)
li t0, (1 << 31)
li a0, CCU_BASE + LEDC_CLK_REG
sw t0, 0(a0)
li t0, 0x500000
li a0, GPIO_BASE + PE_CFG0
sw t0, 0(a0)
li t0, (0x14 << 21) | (0x06 << 16) | (0x07 << 6) | (0x13 << 0)
li a0, LEDC_BASE + LED_T01_TIMING_CTRL_REG
sw t0, 0(a0)
li t0, (0x1d4c << 16)
li a0, LEDC_BASE + LEDC_DATA_FINISH_CNT_REG
sw t0, 0(a0)
li t0, (0x1d4c << 16)
li a0, LEDC_BASE + LED_RESET_TIMING_CTRL_REG
sw t0, 0(a0)
li t0, (0xff << 0)
li a0, LEDC_BASE + LEDC_WAIT_TIME0_CTRL_REG
sw t0, 0(a0)
li t0, 0
li a0, LEDC_BASE + LEDC_DMA_CTRL_REG
sw t0, 0(a0)
li t0, 0
li a0, LEDC_BASE + LEDC_INT_CTRL_REG
sw t0, 0(a0)
li t1, 0
li t2, (1 << 12)
0:
li t0, (1 << 16) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 0)
li a0, LEDC_BASE + LEDC_CTRL_REG
sw t0, 0(a0)
xor t1, t1, t2
li a0, LEDC_BASE + LEDC_DATA_REG
sw t1, 0(a0)
1:
li a0, LEDC_BASE + LEDC_INT_STS_REG
lw t0, 0(a0)
and t0, t0, 1
beqz t0, 1b
sw t0, 0(a0)
li t0, _1S
jal delay
j 0b
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
}
gen_checksum.py
import struct
import os
blocksize = 0x4000
stamp = 0x5f0a6C39
checksum_offset = 0x0c
length_offset = 0x10
def pad_to_roundup(data: bytearray, boundary):
excess = len(data) % boundary
if excess:
data += b'\0' * (boundary - excess)
def main():
# little endian + unsigned int
uint32iter = struct.Struct('<I')
input_img = open(os.sys.argv[1], 'rb')
rawbytes = bytearray(input_img.read())
pad_to_roundup(rawbytes, blocksize)
uint32iter.pack_into(rawbytes, checksum_offset, stamp)
uint32iter.pack_into(rawbytes, length_offset, len(rawbytes))
checksum = 0
for uint32 in uint32iter.iter_unpack(rawbytes):
checksum += uint32[0]
uint32iter.pack_into(rawbytes, checksum_offset, checksum % (2**32))
output_img = open(os.sys.argv[2], 'wb')
output_img.write(rawbytes)
output_img.close()
input_img.close()
if __name__ == '__main__':
main()
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
下載
$ sudo make run
xfel ddr f133 && xfel write 0x40000000 main.bin && xfel exec 0x40000000
100% [================================================] 16.000 KB, 383.004 KB/s
完成
12.jpg
13.jpg
開頭使用 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 的進步,真是感動流淚~