本帖最后由 qwgaojiazhi22 于 2023-12-28 16:47 编辑
MDU运算加速模块
功能概述
支持有符号数/无符号数的算术计算功能
支持 32 位/16 位除法,16 位/16 位除法
支持 16 位x16 位乘法
支持 16 位+16 位加法
支持 16 位-16 位减法
支持 32 位硬件快速开平方
运算性能
假设系统时钟为 48M,每一个时钟周期为 1/48M,即 20.8333ns, 以下表格给出的运
算时间则以系统时钟设置 48M为例:
运类型算 | 32/32 | 开方 | 16-16 | 32-32 | 16+16 | 16x16 | 16/16 | 移位 | 所需时钟数 | 32 | 43 | 10 | 14 | 10 | 21 | 21 | 10 | 运算时间(us) | 0.67 | 0.90 | 0.21 | 0.29 | 0.21 | 0.44 | 0.44 | 0.21 | 注意:以上数据仅为估算时间,代表的是从使能运算开始到运算结束所需时间,可能存
在误差。操作数地址和结果地址为 2 byte对齐时可节省模块内部DMA的时间,从而获得最
大性能。
模块框图
软件测试
/* Private define ------------------------------------------------------------*/
#define UN_DIV_16_16 (MDU_SIGN_SEL(0x0) | MDU_OPERATION_SEL(0x0) | MDU_EN(0x1))
#define DIV_16_16 (MDU_SIGN_SEL(0x1) | MDU_OPERATION_SEL(0x0) | MDU_EN(0x1))
#define UN_DIV_32_16 (MDU_SIGN_SEL(0x0) | MDU_OPERATION_SEL(0x1) | MDU_EN(0x1))
#define DIV_32_16 (MDU_SIGN_SEL(0x1) | MDU_OPERATION_SEL(0x1) | MDU_EN(0x1))
#define UN_MUL_16_16 (MDU_SIGN_SEL(0x0) | MDU_OPERATION_SEL(0x2) | MDU_EN(0x1))
#define MUL_16_16 (MDU_SIGN_SEL(0x1) | MDU_OPERATION_SEL(0x2) | MDU_EN(0x1))
#define UN_SQRT (MDU_SIGN_SEL(0x0) | MDU_OPERATION_SEL(0x3) | MDU_EN(0x1))
#define UN_SUB_16_16 (MDU_SIGN_SEL(0x0) | MDU_OPERATION_SEL(0x4) | MDU_EN(0x1))
#define SUB_16_16 (MDU_SIGN_SEL(0x1) | MDU_OPERATION_SEL(0x4) | MDU_EN(0x1))
#define UN_ADD_16_16 (MDU_SIGN_SEL(0x0) | MDU_OPERATION_SEL(0x5) | MDU_EN(0x1))
#define ADD_16_16 (MDU_SIGN_SEL(0x1) | MDU_OPERATION_SEL(0x5) | MDU_EN(0x1))
#define UN_SUB_32_32 (MDU_SIGN_SEL(0x0) | MDU_OPERATION_SEL(0x6) | MDU_EN(0x1))
#define SUB_32_32 (MDU_SIGN_SEL(0x1) | MDU_OPERATION_SEL(0x6) | MDU_EN(0x1))
#define UN_SHIFT (MDU_SIGN_SEL(0x0) | MDU_OPERATION_SEL(0x7) | MDU_EN(0x1))
#define SHIFT (MDU_SIGN_SEL(0x1) | MDU_OPERATION_SEL(0x7) | MDU_EN(0x1))
u8 mdu_register(u8 ctl0, u8 ctl1, u16 adr0, u16 adr1, u16 adr2)
{
#define ADR_H(ADR) ((((u16)ADR)&0xFF00) > 0 ? 0x1 : 0x0)
u8 ret = 0;
MDU_ADR0 = MDU_OPERAND0_ADR((u8)adr0);
MDU_ADR1 = MDU_OPERAND1_ADR((u8)adr1);
MDU_ADR2 = MDU_RESULT_ADR((u8)adr2);
MDU_CTL1 = ctl1;
MDU_CTL0 = ctl0 |
MDU_OPERAND0_ADR_H(ADR_H(adr0)) | // 地址高位有值则是xdata变量
MDU_OPERAND1_ADR_H(ADR_H(adr1)) | // 地址高位有值则是xdata变量
MDU_RESULT_ADR_H(ADR_H(adr2)); // 地址高位有值则是xdata变量
while(MDU_EN); // 等完成标志
if(MDU_STA & (MDU_DIV_ERR_FLAG(0x1) | MDU_SHIFT_ERR_FLAG(0x1) | MDU_ADDSUB_ERR_FLAG(0x1))) {
ret = MDU_STA;
MDU_STA |= MDU_DIV_ERR_FLAG(0x1) | MDU_SHIFT_ERR_FLAG(0x1) | MDU_ADDSUB_ERR_FLAG(0x1);
}
return ret;
}
s16 s16_data1;
s16 s16_data2;
s16 s16_data3;
s32 s32_data1;
s32 s32_data2;
s32 s32_data3;
u16 u16_data1;
u16 u16_data2;
u16 u16_data3;
u32 u32_data1;
u32 u32_data2;
u32 u32_data3;
u16 u48_data3[3];
u8 shift_val;
void main(void)
{
// 看门狗默认打开, 复位时间2s
// WDT_KEY = WDT_KEY_VAL(0xDD); // 关闭看门狗 (如需配置看门狗请查看“WDT\WDT_Reset”示例)
system_init();
// 初始化打印
debug_init();
user_printf("APM8S007_SDK main start\n");
CLK_CON2 |= CLK_MDU_EN(0x1); // 打开MDU模块时钟
// 无符号32bit/16bit 结果为48位: 0~31位为整数部分,32~47位为余数
u32_data1 = 8712; // 被除数
u16_data2 = 99; // 除数
u32_data3 = 0; // 结果 (8712/99 = 88)
mdu_register(UN_DIV_32_16, 0, (u16)&u32_data1, (u16)&u16_data2, (u16)&u48_data3);
printf("UN_DIV_32_16: %ld/%d = %ld\r\n", u32_data1, u16_data2, *((u32 *)&u48_data3));
// 有符号32bit/16bit 结果为48位: 0~31位为整数部分,32~47位为余数
s32_data1 = -8712; // 被除数
s16_data2 = 99; // 除数
u48_data3[0] = 0; // 结果 (-8712/99 = -88)
u48_data3[1] = 0;
u48_data3[2] = 0;
mdu_register(DIV_32_16, 0, (u16)&s32_data1, (u16)&s16_data2, (u16)&u48_data3);
printf(" DIV_32_16: %ld/%d = %ld\r\n", s32_data1, s16_data2, *((s32 *)&u48_data3));
// 无符号16bit/16bit 结果为32位: 0~15位为整数部分,16~31位为余数
u16_data1 = 8712; // 被除数
u16_data2 = 99; // 除数
u32_data3 = 0; // 结果 (8712/99 = 88)
mdu_register(UN_DIV_16_16, 0, (u16)&u16_data1, (u16)&u16_data2, (u16)&u32_data3);
printf("UN_DIV_16_16: %d/%d = %d\r\n", u16_data1, u16_data2, *((u16 *)&u32_data3));
// 有符号16bit/16bit 结果为32位: 0~15位为整数部分,16~31位为余数
s16_data1 = -8712; // 被除数
s16_data2 = 99; // 除数
u32_data3 = 0; // 结果 (8712/99 = -88)
mdu_register(DIV_16_16, 0, (u16)&s16_data1, (u16)&s16_data2, (u16)&u32_data3);
printf(" DIV_16_16: %d/%d = %d\r\n", s16_data1, s16_data2, *((s16 *)&u32_data3));
// 无符号16bit*16bit
u16_data1 = 88; // 被乘数
u16_data2 = 99; // 乘数
u32_data3 = 0; // 结果 (88*99 = 8712)
mdu_register(UN_MUL_16_16, 0, (u16)&u16_data1, (u16)&u16_data2, (u16)&u32_data3);
printf("UN_MUL_16_16: %d*%d = %ld\r\n", u16_data1, u16_data2, u32_data3);
// 有符号16bit*16bit
u16_data1 = -88; // 被乘数
u16_data2 = 99; // 乘数
s32_data3 = 0; // 结果 (-88*99 = -8712)
mdu_register(MUL_16_16, 0, (u16)&u16_data1, (u16)&u16_data2, (u16)&s32_data3);
printf(" MUL_16_16: %d*%d = %ld\r\n", u16_data1, u16_data2, s32_data3);
// 无符号16bit-16bit
u16_data1 = 8712; // 被减数
u16_data2 = 99; // 减数
u16_data3 = 0; // 结果 (8712-99 = 8613)
mdu_register(UN_SUB_16_16, 0, (u16)&u16_data1, (u16)&u16_data2, (u16)&u16_data3);
printf("UN_SUB_16_16: %d-%d = %d\r\n", u16_data1, u16_data2, u16_data3);
// 有符号16bit-16bit
s16_data1 = -8712; // 被减数
s16_data2 = 99; // 减数
s16_data3 = 0; // 结果 (-8712-99 = -8811)
mdu_register(SUB_16_16, 0, (u16)&s16_data1, (u16)&s16_data2, (u16)&s16_data3);
printf(" SUB_16_16: %d-%d = %d\r\n", s16_data1, s16_data2, s16_data3);
// 无符号32bit-32bit
u32_data1 = 8712; // 被减数
u32_data2 = 99; // 减数
u32_data3 = 0; // 结果 (8712-99 = 8613)
mdu_register(UN_SUB_32_32, 0, (u16)&u32_data1, (u16)&u32_data2, (u16)&u32_data3);
printf("UN_SUB_32_32: %ld-%ld = %ld\r\n", u32_data1, u32_data2, u32_data3);
// 有符号32bit-32bit
s32_data1 = -8712; // 被减数
s32_data2 = 99; // 减数
s32_data3 = 0; // 结果 (-8712-99 = 8811)
mdu_register(SUB_32_32, 0, (u16)&s32_data1, (u16)&s32_data2, (u16)&s32_data3);
printf(" SUB_32_32: %ld-%ld = %ld\r\n", s32_data1, s32_data2, s32_data3);
// 无符号16bit+16bit
u16_data1 = 8712; // 被加数
u16_data2 = 99; // 加数
u16_data3 = 0; // 结果 (8712-99 = 8613)
mdu_register(UN_ADD_16_16, 0, (u16)&u16_data1, (u16)&u16_data2, (u16)&u16_data3);
printf("UN_ADD_16_16: %d+%d = %d\r\n", u16_data1, u16_data2, u16_data3);
// 有符号16bit+16bit
s16_data1 = -8712; // 被加数
s16_data2 = 99; // 加数
s16_data3 = 0; // 结果 (-8712+99 = -8613)
mdu_register(ADD_16_16, 0, (u16)&s16_data1, (u16)&s16_data2, (u16)&s16_data3);
printf(" ADD_16_16: %d+%d = %d\r\n", s16_data1, s16_data2, s16_data3);
// 无符号 左移位<<
u32_data1 = 10000; // 被移位数
shift_val = 3; // 移位值
u32_data3 = 0; // 结果 (10000<<3 = 80000)
mdu_register(UN_SHIFT, MDU_SIFT_SEL(0x0) | MDU_SIFT_NUM(shift_val), (u16)&u32_data1, 0, (u16)&u32_data3);
printf(" UN_SHIFT: %ld<<%bd = %ld\r\n", u32_data1, shift_val, u32_data3);
// 有符号 左移位<<
s32_data1 = -10000; // 被移位数
shift_val = 3; // 移位值
s32_data3 = 0; // 结果 (-10000<<3 = -80000)
mdu_register(SHIFT, MDU_SIFT_SEL(0x0) | MDU_SIFT_NUM(shift_val), (u16)&s32_data1, 0, (u16)&s32_data3);
printf(" SHIFT: %ld<<%bd = %ld\r\n", s32_data1, shift_val, s32_data3);
// 无符号 右移位>>
u32_data1 = 10000; // 被移位数
shift_val = 3; // 移位值
u32_data3 = 0; // 结果 (10000>>3 = 1250)
mdu_register(UN_SHIFT, MDU_SIFT_SEL(0x1) | MDU_SIFT_NUM(shift_val), (u16)&u32_data1, 0, (u16)&u32_data3);
printf(" UN_SHIFT: %ld>>%bd = %ld\r\n", u32_data1, shift_val, u32_data3);
// 有符号 右移位>>
s32_data1 = -10000; // 被移位数
shift_val = 3; // 移位值
s32_data3 = 0; // 结果 (-10000>>3 = -1250)
mdu_register(SHIFT, MDU_SIFT_SEL(0x1) | MDU_SIFT_NUM(shift_val), (u16)&s32_data1, 0, (u16)&s32_data3);
printf(" SHIFT: %ld>>%bd = %ld\r\n", s32_data1, shift_val, s32_data3);
// 无符号16bit*16bit<<
u16_data1 = 88; // 被乘数
u16_data2 = 99; // 乘数
shift_val = 3; // 移位值
u32_data3 = 0; // 结果 (88*99<<3 = 69696)
mdu_register(UN_MUL_16_16, MDU_SIFT_SEL(0x0) | MDU_SIFT_NUM(shift_val), (u16)&u16_data1, (u16)&u16_data2, (u16)&u32_data3);
printf("UN_MUL_16_16_SHIFT: %d*%d<<%bd = %ld\r\n", u16_data1, u16_data2, shift_val, u32_data3);
// 无符号16bit*16bit>>
u16_data1 = 88; // 被乘数
u16_data2 = 99; // 乘数
shift_val = 3; // 移位值
u32_data3 = 0; // 结果 (88*99>>3 = 1089)
mdu_register(UN_MUL_16_16, MDU_SIFT_SEL(0x1) | MDU_SIFT_NUM(shift_val), (u16)&u16_data1, (u16)&u16_data2, (u16)&u32_data3);
printf(" MUL_16_16_SHIFT: %d*%d>>%bd = %ld\r\n", u16_data1, u16_data2, shift_val, u32_data3);
// 开方
u32_data1 = 9801; // 被减数
u16_data3 = 0; // 结果 (SQRT(8712)= 99)
mdu_register(UN_SQRT, 0, (u16)&u32_data1, 0, (u16)&u16_data3);
printf(" UN_SQRT: SQRT(%ld) = %d\r\n", u32_data1, u16_data3);
while(1) {
WDT_KEY = WDT_KEY_VAL(0xAA); // 喂狗并清除 wdt_pending
}
}
串口打印结果
APM8S007_MDU.zip
(289.15 KB)
|
|