前一段時(shí)間遇到給D1下載程序觸發(fā)異常的問(wèn)題。研究許久無(wú)果,多日后終得解決。
問(wèn)題
使用全志提供的命令下載的方式,若在第一個(gè)線程啟動(dòng)前不做停止操作(添加while(1),延時(shí))等操作,使用該種方式下載會(huì)觸發(fā)異常。
使用全志PhoenixSuit工具下載不會(huì)觸發(fā)異常。
問(wèn)題定位
最終問(wèn)題出現(xiàn)定位在第一個(gè)線程啟動(dòng)前。可惜水平有限,還是沒(méi)找到原因。
問(wèn)題解決
經(jīng)高人指點(diǎn),發(fā)現(xiàn)mstatus中的vs位在第一個(gè)線程啟動(dòng)前被修改。
于是在啟動(dòng)第一個(gè)線程前,開(kāi)始排查修改vs位的地方。
最終發(fā)現(xiàn)是在初始化線程的現(xiàn)場(chǎng)時(shí)被修改。
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;
}
上述代碼修改前,下載會(huì)觸發(fā)異常:
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 */
為什么這么改?請(qǐng)看下文:
事情到這就清晰了,是因?yàn)闆](méi)有初始化向量指令控制位VS.
回到最初的問(wèn)題:
下載主要的操作就是數(shù)據(jù)拷貝,使用向量指令拷貝會(huì)大大加速下載速度,所以全志的下載算法會(huì)使用向量指令去拷貝,這里沒(méi)有初始化VS,當(dāng)然會(huì)觸發(fā)異常了。
到這還有個(gè)疑問(wèn):
mstatus的vs在用戶程序中修改的,這里按道理已經(jīng)在用戶程序了,整么還在下載,這個(gè)問(wèn)題就不得而知了,你知道嗎,反正我不知道
一番操作過(guò)后,看看這個(gè)向量指令到底是個(gè)啥吧:
向量指令
向量指令:?jiǎn)螚l指令操作多個(gè)數(shù)據(jù),并行
使用場(chǎng)景:數(shù)據(jù)拷貝 用并行方式代替循環(huán)的方式
向量指令使用舉例:
一段上下文切換中的代碼:
#ifdef __riscv_vector
addi sp, sp, -(20+20)
csrr t0, vl // 記錄 矢量寄存器 能 處理的 數(shù)據(jù) 個(gè)數(shù)
sd t0, (0 +0 )(sp) // 備份
csrr t0, vtype // 描述 矢量寄存器 數(shù)據(jù) 類(lèi)型
sd t0, (4 +4 )(sp) // 備份
csrr t0, vstart // 向量 起始 索引 向量指令 執(zhí)行 第一個(gè)元素 的 索引
sd t0, (8 +8 )(sp) // 備份
csrr t0, vxsat // 描述 運(yùn)算 結(jié)果 是否 飽和
sd t0, (12 +12 )(sp) // 備份
csrr t0, vxrm // 舍入 模式 類(lèi)似四舍五入的(略) 那種
sd t0, (16 +16 )(sp) // 備份
addi sp, sp, -(256+256)
vsetvli zero, zero, e8, m8 // 設(shè)置 數(shù)據(jù)寬度8(1字節(jié)) 8個(gè)向量寄存器為一組
vsb.v v0, (sp) //存儲(chǔ)V0 ~ V7 矢量寄存器數(shù)據(jù)至 內(nèi)存 存儲(chǔ)數(shù)量 (128:矢量寄存器寬度 / 8:數(shù)據(jù)寬度) * 8:矢量寄存器組中的矢量寄存器的個(gè)數(shù)
addi sp, sp, 128//
vsb.v v8, (sp) // 存儲(chǔ)V8 ~ V15
addi sp, sp, 128
vsb.v v16, (sp)// 存儲(chǔ)V16 ~ V23
addi sp, sp, 128
vsb.v v24, (sp)// 存儲(chǔ)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 內(nèi)存 至矢量寄存器數(shù) 拷貝數(shù)量 (128:矢量寄存器寬度 / 8:數(shù)據(jù)寬度) * 8:矢量寄存器組中的矢量寄存器的個(gè)數(shù)
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 // 重新設(shè)置 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小學(xué)生,不住之處請(qǐng)多多指教.
-
控制器
+關(guān)注
關(guān)注
112文章
16395瀏覽量
178482 -
寄存器
+關(guān)注
關(guān)注
31文章
5357瀏覽量
120622 -
觸發(fā)器
+關(guān)注
關(guān)注
14文章
2000瀏覽量
61212 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1293瀏覽量
40228
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論