网站正在建设中色无夜,新公司起名大全集,法学网站阵地建设,桂林做RISCV学习#xff08;5#xff09;GD32VF103 MCU架构了解 1、芯片内核功能简介
GD32VF103 MCU架构#xff0c;采用Bumblebee内核#xff0c;芯来科技#xff08;Nuclei System Technology#xff09;与台湾晶心科技#xff08;Andes Technology#xff09;联合开发5GD32VF103 MCU架构了解 1、芯片内核功能简介
GD32VF103 MCU架构采用Bumblebee内核芯来科技Nuclei System Technology与台湾晶心科技Andes Technology联合开发由芯来科技Nuclei System Technology提供授权以及技术支持等服务。
架构特点
CPU 内核CPU Core 2 级变长流水线架构采用一流的处理器架构设计实现业界最高的能效比与最低的成本。简单的动态分支预测器。指令预取单元能够按顺序预取两条指令 从而隐藏指令的访存延迟。支持机器模式Machine Mode和用户模式User Mode。 支持指令集架构ISA Instruction Set Architecture Bumblebee内核支持32位的RISC-V指令集架构支持RV32IMAC指令子集的组合。硬件支持非对齐Misalign的存储器访问操作Load/Store 指令 总线接口 支持 32 比特宽的标准 AHB-Lite 系统总线接口用于访问外部指令和数据。支持 32 比特宽的指令局部存储器Instruction Local Memory ILM总线接口支持标准的 AHB-Lite 或 SRAM 接口协议用于连接私有的指令局部存储器支持 32 比特宽的数据局部存储器Data Local Memory DLM总线接口支持标准的 AHB-Lite 或 SRAM 接口协议用于连接私有的数据局部存储器。支持 32 比特宽的私有设备总线Private Peripheral Interface PPI支持标准的 APB接口协议用于连接私有的外设 调试功能 支持标准 JTAG 接口。支持 RISC-V 调试标准。支持 4 个硬件断点Hardware Breakpoints。支持成熟的交互式调试工具 低功耗管理 支持 WFIWait For Interrupt与 WFEWait For Event进入休眠模式。支持两级休眠模式浅度休眠与深度休眠 内核私有的计时器单元Machine Timer简称 TIMER 64 比特宽的实时计时器支持产生 RISC-V 标准定义的计时器中断。 增强的内核中断控制器Enhanced Core Level Interrupt Controller ECLIC 支持 RISC-V 标准定义的的软件中断、计时器中断和外部中断。支持数十个外部中断源中断源的数目和分配请参见具体 MCU 芯片的数据手册。支持 16 个中断级别和优先级支持软件动态可编程修改中断级别和中断优先级的数值。支持基于中断级别的中断嵌套。支持快速向量中断处理机制。支持快速中断咬尾机制。
支持NMI不可屏蔽中断 架构图如下图所示 ILM 和DLM指令/数据 局部memoryAHB LiteAHB的简单版本高性能/低功耗的嵌入式版本接口访问周期基本可达到1 Cycle相当于ARM 的TCM。访问SRAM或者外部memory则需要经过system bus总线总线周期会高一些RISCV的版本为 1.1版本更高级的版本模式等有变化比如有4个模式等等。
2、芯片指令集
RV32 架构 32 位地址空间通用寄存器宽度 32 位。I支持 32 个通用整数寄存器。M: 支持整数乘法与除法指令C支持编码长度为 16 位的压缩指令提高代码密度。A支持原子操作指令。 按照 RISC-V 架构命名规则以上指令子集的组合可表示为 RV32IMAC
2.1 指令集举例说明
寻址 mv传送寄存器到寄存器 mv rdrsrs源寄存器送到目标寄存器rd lw内存访问load word将32位寄存器加载到目标寄存器4字节读出 lwx15,0x0x23 -- x15 [x230]x15和x23是寄存器 lwsp出栈指令 lwsp x10x8(x2)x1 [x20x8]x2是sp指针sp8的值 赋值给x1 sw内存访问store word将将32位寄存器写到目标寄存器地址,4字节写入 swx27,0x0(x23) -- [x230] x27 swsp压栈指令 swsp x10x8(x2)[x20x8]x1x2是sp指针将x1压栈到sp8的地址 lui直接传输 将立即数左移12位到目标寄存器 lui x270x20000 — x27 0x2000012; lbuload byte unsigned加载一个无符号数据到目标地址lb是加载有符号数会进行扩展 lbu x270x0x25 — x27 [x25 0] sbstore byte存储一个byte字节。 sb x27, 0x0x25 sd store dword存储8字节 ld双字加载
加减乘除法左移 右移指令 slli左移指令 srli右移指令 or或指令 addi加法指令 i代表immediate 立即数 addix8x80xC9
跳转指令 j直接跳转指令后面直接跟地址 j 0x080005ZF6 jalr带连接的跳转指令一般和auipc一起用 auipc x1,0x1 将x1x1 1 12即加上0x1000,4k地址 jalr x1,-0x5CAx1先计算跳转地址pc x1- 0x5CA然后将返回地址保存到x1x1 当前pc4
其他指令 ret 指令 mret异常返回指令 ebreak ecall 来看一段汇编理解一些基础指令 函数调用传参数使用 x10 -x17总共8个参数。 左边第250行代码函数led_blink函数参数是test_counter_g。 mv x10x27将27的数据给了x10说明x27就是test_counter_g的值那就看x27的值 lw x27,0x0x22说明x27的值是通过x22地址读出来的那就看x22的地址 lui x22,0x20000addi x22,x22,0x70, x22 0x200000x70 0x20000070 地址符合地址要求 接下来auipc x1, 0x1 那么 x1 080015FC jalr x1-0x3DA那么x1 0x080045FC - 0x3DA 0x08001222就是led_blink 函数的地址 接着再看上面的代码 lw x15,0x0(x23) lw x27,0x0(x22) 加载了x22和x23地址的数据到x15和x27x22是test_counter_g的地址 x23 的地址是什么呢 通过上面可以计算其地址lui x23,0x20000addi x23,x24,0x6C, x23 0x200000x6c 0x2000006C 地址是 current_test_count_g的地址 这样就比较好理解加载了这两个变量的值就是用来判断是否相等的。beq x15,x27,0x8000632 如果不相等直接跳走否则 c.mv x10,x24 把x24的值给了x10说明又有函数调用lui x24,0x40001 addi x24,x24,-0x800 x24的地址为x24 0x40001000 - 0x800 0x40000800其是一个外设地址是TIMER3的base地址。 auipc x1,0x0 jalr x1,0x4F6(x1) x1 0x080006120x4F6 0x08000B08是timer_counter_read函数的地址 接着是一个打印刚刚x10 作为函数的返回值这次作为打印的第三个参数所以就是x12 寄存器的值mv x12x10mv x11,x27 x27是 test_counter_g的值是第二个参数addi x10,x26,0x350 x10 x26x350x26 08000000所以x10 08000350字符串的地址 最后是一个跳转函数auipc x1,0x1 jalr x1,-0x580(x1) 跳转地址 08001622 - 0x580 0x080010A2则是test_printf的函数。
3、芯片特权架构
Bumblebee 内核支持两个特权模式Privilege Modes
机器模式Machine Mode是必须的模式该 Privilege Mode 的编码是 0x3。用户模式User Mode是可配置的模式该 Privilege Mode 的编码是 0x0。
RISCV的CSR 寄存器可以反应内核的状态不是单个寄存器是一系列寄存器。
3.1 机器模式Machine Mode
Bumblebee 内核有关 Machine Mode 的关键要点如下
处理器内核被复位后默认处于 Machine Mode。在 Machine Mode 下程序能够访问所有的 CSR 寄存器。跳转到用户模式。执行mret指令
3.2 用户模式User Mode
Bumblebee 内核有关 User Mode 的关键要点如下
在 User Mode 下只能够访问 User Mode 限定的 CSR 寄存器从用户模式到机器模式通过异常中断
3.3 机器子模式Machine Sub-Mode
Bumblebee 内核的 Machine Mode 可能处于四种不同的状态下将之称之为机器子模式 Machine Sub-Mode
正常机器模式该 Machine Sub-Mode 的编码是 0x0处理器内核被复位之后处于此子模式之下。处理器复位后如果不产生异常、 NMI、中断则一直正常运行于此模式之下。异常处理模式该 Machine Sub-Mode 的编码是 0x2响应异常后处理器内核处于此状态。NMI 处理模式该 Machine Sub-Mode 的编码是 0x3响应 NMI 后处理器内核处于此状态。中断处理模式该 Machine Sub-Mode 的编码是 0x1响应中断后处理器内核处于此状态。
处理器内核当前处于的 Machine Sub-Mode 反映在 CSR 寄存器 msubm 的 TYP 域中因此软件可以通过读取此 CSR 寄存器查看当前处于的 Machine Sub-Mode。 注意 在 RISC-V 架构中进入异常、 NMI 或者中断也被统称为 Trap。
3.4 不支持PMP
PMP physical Memory Protection物理内存保护即ARM 芯片里面的MPU
4、芯片中断机制
芯片中断主要有外部中断和内部中断中断跳转模式主要有向量模式与非向量模式。 具体详情可以参考笔者这篇文章RISCV学习4GD32VF103 MCU芯片学习。
5、芯片异常机制
RISCV的芯片异常机制没有自动保存寄存器需要用户自身保存。
异常处理的流程如下均是硬件行为一个时钟周期内完成。
停止执行当前程序流转而从 CSR 寄存器 mtvec 定义的 PC 地址开始执行。更新相关 CSR 寄存器分别是以下几个寄存器 mcauseMachine Cause RegistermepcMachine Exception Program CountermtvalMachine Trap Value Register mstatusMachine Status Register 更新处理器内核的 Privilege Mode 以及 Machine Sub-Mode。 mtvec 硬件异常处理函数的统一入口最低64位对齐。 如下图所示mtvec 为 x080013C3mtvec ADDR0异常地址0x080013C0而该地址则为trap_entry的地址。mtvec MODE0x11则为ECLIC 中断模式 笔者测试的异常代码如下
if(test_counter_g 3){current_test_count_g 0;test_printf(%d\r\n,(test_counter_g/current_test_count_g));}mepc保存进入异常之前的PC值作为异常返回的地址当然也可以作为分析出错的地址2字节对齐。 如下图所述mepc值为0x080005fa指令为ebreak确实会产生异常可能编译器认为笔者是想进入异常则编译成了该指令。 mcause异常原因寄存器其值为0x38000003
INTERRUPT其值为0表示异常。MPP其值为3表示特权模式0为用户模式MPIE其值为1表示允许中断EXCCODE0x3表示断点指令可以进入异常。 mtval表示异常的访问地址或者指令编码笔者这里为0表示该数据没有意义。
再比如一个例子机器模式下面直接调用ecall会触发进入异常。
test_entry:ecallret笔者测试即使非对齐访问和写入不会触发异常依然程序正常进行待后续研究。
再来一个例子非法指令
led_blink(test_counter_g);if(current_test_count_g ! test_counter_g){test_printf(test_counter_g%d timer_counter%d\r\n,test_counter_g,timer_counter_read(TIMER3));test_printf(mcause0x%x, int num%d, time%d\r\n, int_num_g, (int_num_g0x3FF), rdtime());current_test_count_g test_counter_g;}异常编码为2代表非法指令pc指针为0800061e然后mtval记录的指令地址为0xC01026F2就是这个非法指令的值。
6、芯片timer
6.1 系统TIMER
系统timer属于外设外设的地址由厂商自己定义没有定义成CSR寄存器。64位的寄存器。
#define TIMER_MSIP 0xFFC
#define TIMER_MSIP_size 0x4
#define TIMER_MTIMECMP 0x8
#define TIMER_MTIMECMP_size 0x8
#define TIMER_MTIME 0x0
#define TIMER_MTIME_size 0x8#define TIMER_CTRL_ADDR 0xd1000000
unsigned int mtime_lo(void)
{return *(volatile unsigned int *)(TIMER_CTRL_ADDR TIMER_MTIME);
}unsigned int mtime_hi(void)
{return *(volatile unsigned int *)(TIMER_CTRL_ADDR TIMER_MTIME 4);
}寄存器地址如下 测试效果如下主循环打印
test_printf(mtime low%d, diff%d\r\n,mtime_lo(), (mtime_lo()-mtime_low_g));
mtime_low_g mtime_lo();timer里面可以软件中断msip软件中断 msip软件中断 中断号为3仍然需要设置中断模式以及向量等方式。
#if (INTERRUPT_MODEINTERRUPT_VECTOR_MODE)__attribute__((interrupt)) void eclic_msip_handler()
#else
void eclic_msip_handler()
#endif
{msip_int_num_g read_csr(mcause);msip_int_clear();
}void set_software_int()
{#if (INTERRUPT_MODE INTERRUPT_VECTOR_MODE) eclic_set_vmode(CLIC_INT_SFT);
#elseeclic_set_nonvmode(CLIC_INT_SFT);
#endifeclic_set_posedge_trig(CLIC_INT_SFT);eclic_irq_enable(CLIC_INT_SFT, 1, 0);
}void msip_int_set()
{*(volatile unsigned int *)(TIMER_CTRL_ADDR TIMER_MSIP) 1;
}int msip_int_get()
{return *(volatile unsigned int *)(TIMER_CTRL_ADDR TIMER_MSIP) ;
}void msip_int_clear()
{*(volatile unsigned int *)(TIMER_CTRL_ADDR TIMER_MSIP) 0;
}msip_int_set();
test_printf(set msip int,reg%d, int num%d\r\n,msip_int_get(), (msip_int_num_g0x3FF));6.2 指令周期计数器和指令计数器
mcycle 为指令周期计数器 instret指令计数器
这两者均是CSR寄存器。
cycle_start_g read_csr(mcycle) ;
current_test_count_g test_counter_g;
test_printf(start%d end%d, cycle%d\r\n, cycle_start_g, read_csr(mcycle), (read_csr(mcycle))-cycle_start_g);cycle_start_g read_csr(instret) ;
current_test_count_g test_counter_g;
test_printf(start%d end%d, cycle%d\r\n, cycle_start_g, read_csr(instret), (read_csr(instret))-cycle_start_g);指令完成计数器总共完成了5条指令 时钟周期总共花费5个时钟周期 7 附录参考
中断向量号
/* define interrupt number */
typedef enum IRQn
{CLIC_INT_RESERVED 0, /*! RISC-V reserved */CLIC_INT_SFT 3, /*! Software interrupt */CLIC_INT_TMR 7, /*! CPU Timer interrupt */CLIC_INT_BWEI 17, /*! Bus Error interrupt */CLIC_INT_PMOVI 18, /*! Performance Monitor *//* interruput numbers */WWDGT_IRQn 19, /*! window watchDog timer interrupt */LVD_IRQn 20, /*! LVD through EXTI line detect interrupt */TAMPER_IRQn 21, /*! tamper through EXTI line detect */RTC_IRQn 22, /*! RTC alarm interrupt */FMC_IRQn 23, /*! FMC interrupt */RCU_CTC_IRQn 24, /*! RCU and CTC interrupt */EXTI0_IRQn 25, /*! EXTI line 0 interrupts */EXTI1_IRQn 26, /*! EXTI line 1 interrupts */EXTI2_IRQn 27, /*! EXTI line 2 interrupts */EXTI3_IRQn 28, /*! EXTI line 3 interrupts */EXTI4_IRQn 29, /*! EXTI line 4 interrupts */DMA0_Channel0_IRQn 30, /*! DMA0 channel0 interrupt */DMA0_Channel1_IRQn 31, /*! DMA0 channel1 interrupt */DMA0_Channel2_IRQn 32, /*! DMA0 channel2 interrupt */DMA0_Channel3_IRQn 33, /*! DMA0 channel3 interrupt */DMA0_Channel4_IRQn 34, /*! DMA0 channel4 interrupt */DMA0_Channel5_IRQn 35, /*! DMA0 channel5 interrupt */DMA0_Channel6_IRQn 36, /*! DMA0 channel6 interrupt */ADC0_1_IRQn 37, /*! ADC0 and ADC1 interrupt */CAN0_TX_IRQn 38, /*! CAN0 TX interrupts */CAN0_RX0_IRQn 39, /*! CAN0 RX0 interrupts */CAN0_RX1_IRQn 40, /*! CAN0 RX1 interrupts */CAN0_EWMC_IRQn 41, /*! CAN0 EWMC interrupts */EXTI5_9_IRQn 42, /*! EXTI[9:5] interrupts */TIMER0_BRK_IRQn 43, /*! TIMER0 break interrupts */TIMER0_UP_IRQn 44, /*! TIMER0 update interrupts */TIMER0_TRG_CMT_IRQn 45, /*! TIMER0 trigger and commutation interrupts */TIMER0_Channel_IRQn 46, /*! TIMER0 channel capture compare interrupts */TIMER1_IRQn 47, /*! TIMER1 interrupt */TIMER2_IRQn 48, /*! TIMER2 interrupt */TIMER3_IRQn 49, /*! TIMER3 interrupts */I2C0_EV_IRQn 50, /*! I2C0 event interrupt */I2C0_ER_IRQn 51, /*! I2C0 error interrupt */I2C1_EV_IRQn 52, /*! I2C1 event interrupt */I2C1_ER_IRQn 53, /*! I2C1 error interrupt */SPI0_IRQn 54, /*! SPI0 interrupt */SPI1_IRQn 55, /*! SPI1 interrupt */USART0_IRQn 56, /*! USART0 interrupt */USART1_IRQn 57, /*! USART1 interrupt */USART2_IRQn 58, /*! USART2 interrupt */EXTI10_15_IRQn 59, /*! EXTI[15:10] interrupts */RTC_ALARM_IRQn 60, /*! RTC alarm interrupt EXTI */USBFS_WKUP_IRQn 61, /*! USBFS wakeup interrupt */EXMC_IRQn 67, /*! EXMC global interrupt */TIMER4_IRQn 69, /*! TIMER4 global interrupt */SPI2_IRQn 70, /*! SPI2 global interrupt */UART3_IRQn 71, /*! UART3 global interrupt */UART4_IRQn 72, /*! UART4 global interrupt */TIMER5_IRQn 73, /*! TIMER5 global interrupt */TIMER6_IRQn 74, /*! TIMER6 global interrupt */DMA1_Channel0_IRQn 75, /*! DMA1 channel0 global interrupt */DMA1_Channel1_IRQn 76, /*! DMA1 channel1 global interrupt */DMA1_Channel2_IRQn 77, /*! DMA1 channel2 global interrupt */DMA1_Channel3_IRQn 78, /*! DMA1 channel3 global interrupt */DMA1_Channel4_IRQn 79, /*! DMA1 channel3 global interrupt */CAN1_TX_IRQn 82, /*! CAN1 TX interrupt */CAN1_RX0_IRQn 83, /*! CAN1 RX0 interrupt */CAN1_RX1_IRQn 84, /*! CAN1 RX1 interrupt */CAN1_EWMC_IRQn 85, /*! CAN1 EWMC interrupt */USBFS_IRQn 86, /*! USBFS global interrupt */ECLIC_NUM_INTERRUPTS
} IRQn_Type;