前一段时间遇到给D1下载程序触发异常的问题。研究许久无果,多日后终得解决。
问题
使用全志提供的命令下载的方式,若在第一个线程启动前不做停止操作(添加while(1),延时)等操作,使用该种方式下载会触发异常。
使用全志PhoenixSuit工具下载不会触发异常。
问题定位
最终问题出现定位在第一个线程启动前。可惜水平有限,还是没找到原因。
问题解决
经高人指点,发现mstatus中的vs位在第一个线程启动前被修改。
于是在启动第一个线程前,开始排查修改vs位的地方。
最终发现是在初始化线程的现场时被修改。
rt_uint8_t *rt_hw_stack_init(void *tentry,
void *parameter,
rt_uint8_t *stack_addr,
void *texit)
{
struct rt_hw_stack_frame *frame;
rt_uint8_t *stk;
int i;
extern int __global_pointer$;
stk = stack_addr + sizeof(rt_ubase_t);
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_ubase_t)stk, REGBYTES);
stk -= sizeof(struct rt_hw_stack_frame);
frame = (struct rt_hw_stack_frame *)stk;
for (i = 0; i < sizeof(struct rt_hw_stack_frame) / sizeof(rt_ubase_t); i++)
{
((rt_ubase_t )frame)[i] = i;
}
frame->ra = (rt_ubase_t)texit;
frame->gp = (rt_ubase_t)&__global_pointer$;
frame->a0 = (rt_ubase_t)parameter;
frame->epc = (rt_ubase_t)tentry;
frame->x2 = (rt_ubase_t)stk;
/ force to supervisor mode(SPP=1) and set SPIE and SUM to 1 /
#ifdef ENABLE_FPU
frame->mstatus = MSTATUS_VS| MSTATUS_PUM | MSTATUS_FS | MSTATUS_MPP | MSTATUS_MPIE; / enable FPU */
#else
frame->mstatus = MSTATUS_PUM | MSTATUS_MPP | MSTATUS_MPIE;
#endif
return stk;
}
上述代码修改前,下载会触发异常:
frame- >mstatus = MSTATUS_PUM | MSTATUS_FS | MSTATUS_MPP | MSTATUS_MPIE; /* enable FPU */
修改后,下载正常:
frame- >mstatus = MSTATUS_VS| MSTATUS_PUM | MSTATUS_FS | MSTATUS_MPP | MSTATUS_MPIE; /* enable FPU */
为什么这么改?请看下文:
事情到这就清晰了,是因为没有初始化向量指令控制位VS.
回到最初的问题:
下载主要的操作就是数据拷贝,使用向量指令拷贝会大大加速下载速度,所以全志的下载算法会使用向量指令去拷贝,这里没有初始化VS,当然会触发异常了。
到这还有个疑问:
mstatus的vs在用户程序中修改的,这里按道理已经在用户程序了,整么还在下载,这个问题就不得而知了,你知道吗,反正我不知道
一番操作过后,看看这个向量指令到底是个啥吧:
向量指令
向量指令:单条指令操作多个数据,并行
使用场景:数据拷贝 用并行方式代替循环的方式
向量指令使用举例:
一段上下文切换中的代码:
#ifdef __riscv_vector
addi sp, sp, -(20+20)
csrr t0, vl // 记录 矢量寄存器 能 处理的 数据 个数
sd t0, (0 +0 )(sp) // 备份
csrr t0, vtype // 描述 矢量寄存器 数据 类型
sd t0, (4 +4 )(sp) // 备份
csrr t0, vstart // 向量 起始 索引 向量指令 执行 第一个元素 的 索引
sd t0, (8 +8 )(sp) // 备份
csrr t0, vxsat // 描述 运算 结果 是否 饱和
sd t0, (12 +12 )(sp) // 备份
csrr t0, vxrm // 舍入 模式 类似四舍五入的(略) 那种
sd t0, (16 +16 )(sp) // 备份
addi sp, sp, -(256+256)
vsetvli zero, zero, e8, m8 // 设置 数据宽度8(1字节) 8个向量寄存器为一组
vsb.v v0, (sp) //存储V0 ~ V7 矢量寄存器数据至 内存 存储数量 (128:矢量寄存器宽度 / 8:数据宽度) * 8:矢量寄存器组中的矢量寄存器的个数
addi sp, sp, 128//
vsb.v v8, (sp) // 存储V8 ~ V15
addi sp, sp, 128
vsb.v v16, (sp)// 存储V16 ~ V23
addi sp, sp, 128
vsb.v v24, (sp)// 存储V24 ~ V31
addi sp, sp, -(256+256-128)
#endif
la t2, do_irq// 处理中断
jalr t2
#ifdef __riscv_vector
vsetvli zero, zero, e8, m8 // 采用与之前同样的配置方式
vlb.v v0, (sp)
addi sp, sp, 128//拷贝V0 ~ V7 内存 至矢量寄存器数 拷贝数量 (128:矢量寄存器宽度 / 8:数据宽度) * 8:矢量寄存器组中的矢量寄存器的个数
vlb.v v8, (sp)
addi sp, sp, 128//拷贝V8 ~ V15
vlb.v v16, (sp)
addi sp, sp, 128//拷贝V16 ~ V23
vlb.v v24, (sp)
addi sp, sp, 128//拷贝V24 ~ V31
lwu t0, (0 +0)(sp)// 加载 vl
lwu t1, (4 +4)(sp)// 加载 vtype
lwu t2, (8 +8)(sp)// 加载 vstart
vsetvl zero, t0, t1 // 重新设置 vl vtype
csrw vstart, t2// 加载 vstart
lwu t2, (12 +12)(sp)
csrw vxsat, t2 // 加载 vxsat
lwu t2, (16 +16)(sp)
csrw vxrm, t2 // 加载 vxrm
addi sp, sp, (20+20)
#endif
RISC-V小学生,不住之处请多多指教.
-
控制器
+关注
关注
112文章
16191浏览量
177346 -
寄存器
+关注
关注
31文章
5310浏览量
119983 -
触发器
+关注
关注
14文章
1995浏览量
61044 -
RT-Thread
+关注
关注
31文章
1272浏览量
39905
发布评论请先 登录
相关推荐
评论