FPGA 调试指引

很多客户拿到我们的 CPU 会第一时间做 FPGA 集成测试,根据本指引客户无需编译软件,即可直接用 run.sh 启动 Linux。而对硬件要求仅仅是 CPU + DDR 内存即可,run.sh 运行 Linux 包含以下内容:

  • run.sh 介绍
  • ddrinit.fpga.txt
  • gdbinit.fpga.txt
  • fpga.dts.txt

fpga 就是客户自定义的最小 soc 系统,需要客户自己建立 ddrinit.fpga.txt gdbinit.fpga.txt fpga.dts.txt 文件

run.sh 介绍

run.sh <ip地址:端口> <硬件板类型> <cpu数量>

举例: 
run.sh 127.0.0.1:1025 fpga 1

run.sh 脚本做以下事情:

  • 获取 rootfs.cpio.gz 的大小,并以此设置设备树文件的 initrd-start, initrd-end 字段
  • 按需要运行 ddrinit.[board].txt 初始化程序,配置时钟,DDR
  • 运行 gdbinit.[board].txt 下载 rootfs.cpio.gz, hw.dtb, Image 到内存
  • 设置 pc 到指定内存执行

ddrinit.fpga.txt 介绍

cat ddrinit.ice_fpga.txt
# Set gdb environment
set height 0

# Don't confirm when quit
set confirm off

set *0x3fff78040 = 0xffff # xillinx FPGA 初始化 DDR PPL
shell $(sleep 3)

ddrinit 负责初始化 DDR 内存,PPL 等 soc 基础设置,请客户根据自己的情况自行调整

gdbinit.fpga.txt 介绍

➜  hw cat gdbinit.ice_fpga.txt
set confirm off
set height 0

# Invalidate & Clear IBP BTB BHT ICache & DCache
set $mcor = 0x70013

# Enable L2 Cache
set $mccr2 = 0xe0010009

# Enable L1 Cache
set $mhcr = 0x11ff

# Enable CPU Features
set $mxstatus = 0x638000
set $mhint = 0x16e30c

# 0x00000000 ~ 0x2 00000000 DDR, NAPOT rwx
set $pmpaddr0 = 0x0 >> 2 | ((0x200000000 - 1) >> 3)

# 0x3 f0000000 ~ 0x3 f8000000 plic, NAPOT rw
set $pmpaddr1 = 0x3f0000000 >> 2 | ((0x8000000 - 1) >> 3)

# 0x3 f8000000 ~ 0x4 00000000 peripherals, NAPOT rw
set $pmpaddr2 = 0x3f8000000 >> 2 | ((0x8000000 - 1) >> 3)

# 0x00000000 ~ 0x10000000 NAPOT no access
set $pmpaddr6 = 0x00000000 >> 2 | ((0x10000000 - 1) >> 3)

# 0x10000000 ~ 0x10000000000 TOR no access
set $pmpaddr7 = 0xffffffffff >> 2

# Be care! we must put background deny entries in the end of
# pmpaddrx with lowest priority and set lock bit for m state deny.
# Access needn't lock bit for the m state.
set $pmpcfg0 = 0x88980000001b1b1f

set $opensbi_addr = 0x00000000
set $vmlinux_addr = $opensbi_addr + 0x00200000
set $rootfs_addr  = $opensbi_addr + 0x02000000
set $dtb_addr  = $rootfs_addr - 0x00100000

# Load rootfs
restore ../rootfs.cpio.gz binary $rootfs_addr

# Load dtb
restore hw.dtb binary $dtb_addr
set $a1 = $dtb_addr

# Load kernel
restore ../Image binary $vmlinux_addr

# Load opensbi
restore fw_jump_0G.bin binary $opensbi_addr
set $pc = $opensbi_addr

gdbinit 是 CPU 通用设置,一般不需要客户修改,对于 910 客户依然需要正确设置 PMP,PMP 是对物理内存的权限管理寄存器,根据自身 IP 地址分布进行设置,一般需要设置 DDR 区域,PLIC 区域,外设 IO 区域,根据 riscv 规范可以用 NAPOT 和 TOR 两种方式。

fpga.dts.txt

/dts-v1/;
/ {
        model = "T-HEAD c910 fpga";
        compatible = "thead,c910_fpga";
        #address-cells = <2>;
        #size-cells = <2>;

        memory@0 {
                device_type = "memory";
                reg = <0x0 0x200000 0x0 0xffe00000>;
        };

        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
                timebase-frequency = <6250000>;
                cpu@0 {
                        device_type = "cpu";
                        reg = <0>;
                        status = "okay";
                        compatible = "riscv";
                        riscv,isa = "rv64imafdcvsu";
                        mmu-type = "riscv,sv39";
                        cpu0_intc: interrupt-controller {
                                #interrupt-cells = <1>;
                                compatible = "riscv,cpu-intc";
                                interrupt-controller;
                        };
                };
                cpu@1 {
                        device_type = "cpu";
                        reg = <1>;
                        status = "fail";
                        compatible = "riscv";
                        riscv,isa = "rv64imafdcvsu";
                        mmu-type = "riscv,sv39";
                        cpu1_intc: interrupt-controller {
                                #interrupt-cells = <1>;
                                compatible = "riscv,cpu-intc";
                                interrupt-controller;
                        };
                };
        };
        soc {
                #address-cells = <2>;
                #size-cells = <2>;
                compatible = "simple-bus";
                ranges;

                intc: interrupt-controller@3f0000000 {
                        #interrupt-cells = <1>;
                        compatible = "riscv,plic0";
                        interrupt-controller;
                        interrupts-extended = <
                                &cpu0_intc  0xffffffff &cpu0_intc  9
                                &cpu1_intc  0xffffffff &cpu1_intc  9
                                >;
                        reg = <0x3 0xf0000000 0x0 0x04000000>;
                        reg-names = "control";
                        riscv,max-priority = <7>;
                        riscv,ndev = <80>;
                };

                dummy_apb: apb-clock {
                        compatible = "fixed-clock";
                        clock-frequency = <50000000>;
                        clock-output-names = "dummy_apb";
                        #clock-cells = <0>;
                };

                serial@3fff73000 {
                        compatible = "snps,dw-apb-uart";
                        reg = <0x3 0xfff73000 0x0 0x400>;
                        interrupt-parent = <&intc>;
                        interrupts = <23>;
                        clocks = <&dummy_apb>;
                        clock-names = "baudclk";
                        reg-shift = <2>;
                        reg-io-width = <4>;
                };
        };

        chosen {
                bootargs = "console=ttyS0,115200 crashkernel=256M-:128M";
                linux,initrd-start = <0x0 0x2000000>;
                linux,initrd-end = <0x0 0x0>;
                stdout-path = "/soc/serial@3fff73000:115200";
        };
};

以上就是最小系统 dts 配置,(最多双核),几点注意:

  • cpus -> timebase-frequency 用于设置 cpu 紧耦合 timer 定时器的频率
  • riscv,isa = "rv64imafdcvsu" 用于设置 cpu ISA 类型,如果 c910 不配置 vector 模块,请把 v 字母去掉
  • intc: interrupt-controller -> compatible = "riscv,plic0"; 需要根据 soc 地址分布正确设置它的 IO 地址空间
  • dummy_apb: apb-clock 是设置提供串口 IP 的频率,这里取 apb 总线频率,串口驱动根据该设置,换算出正确的波特率

设置好以上三个文件,就可以尝试 bash run.sh 127.0.0.1:1025 fpga 1 了,如果串口没打印,参考上一章节 利用 Jtag 获取 dmesg,祝你调试愉快

results matching ""

    No results matching ""