打印
[新品上市]

APM8S007-MDU运算加速模块

[复制链接]
233|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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)





使用特权

评论回复
沙发
elephant00| | 2024-1-3 14:24 | 只看该作者
价格怎么样?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

18

主题

19

帖子

0

粉丝