软硬件协同设计的大小端问题
缘起
最近需要在soc系统内做协处理器,加速AES加密运算,寄存器一次读取32bit,AES一次处理128bit,因此在数据拼接的时候,需要考虑大小端的问题,特来记录一番。
一、什么是大小端
大小端的问题发生在寄存器和内存间传递数据,这点非常重要,很多地方简单地说是数据存储方式,其实不准确。追根溯源,大小端问题是在设计load
,store
指令的时候考虑的,因此本质是寄存器和内存交互的问题,其他地方不会发生。
比如c语言里定义一个变量int a=ox1234
,那么查看在线汇编平台的对应汇编代码:
# 给2号寄存器赋值0x1234
li $2,4660 # 0x1234
# 保存到fp寄存器数值+8的地址,假设为0x1000
sw $2,8($fp)
假设起始地址是0x1000,那么对小端硬件,高位保存高地址,低位保存低地址:
地址 | 0x1000 | 0x1001 | 0x1002 | 0x1003 |
---|---|---|---|---|
数据 | 0x34 | 0x12 | 00 | 00 |
对大端硬件,低位保存高地址,高位保存低地址:
地址 | 0x1000 | 0x1001 | 0x1002 | 0x1003 |
---|---|---|---|---|
数据 | 00 | 00 | 0x12 | 0x34 |
我们用的x86cpu是小端,还有riscv也是。PowerPC、MIPS是大端。ARM可以切换。
二、大小端各有什么优势呢?
1.小端优势
做强制类型转换时,不需要调整字节内容。c在线工具
#include
int main()
{
int a=0x35;
char c = (char)a;
printf("%c",c);
return 0;
}
考虑上面的代码,强制转换int类型为char,如果是小端
地址 | 0x1000 | 0x1001 | 0x1002 | 0x1003 |
---|---|---|---|---|
数据 | 0x35 | 00 | 00 | 00 |
a的指针指向低地址,对应0x35,只需要直接截取给c。
如果是大端:
地址 | 0x1000 | 0x1001 | 0x1002 | 0x1003 |
---|---|---|---|---|
数据 | 00 | 00 | 00 | 0x35 |
还要考虑类型int的长度4,才能找到对应的数据。
2. 大端优势
大端高位在低地址,因此指针的位置就在高位,能够直接判断正负号。
也正是这个优势,大端被用于网络协议传输:
发送端的顺序是低地址到高地址,接收端希望先到达的是高位还是低位数据?网络传输中不可避免有数据比较,因此先接收高位数据能够边接收边比较,效率更高。因此高位数据先来,保存在低地址。这就是大端的优势。
三、如何测试是否问大小端?
下面提供了两种方法:
#include
#include
union node
{
unsigned int m;
char c;
};
int main()
{
//1.联合法
union node data;
data.m = 0x12345678;
printf("%x\n",data.c);//78为小端,12为大端
//2.指针法
short a = 0x1234;
char b = *(char*)&a;
if(0x12 == b){
printf("big\n");
}
else{
printf("little\n");
}
return 0;
}
四、AES项目中的问题
项目中定义的密钥字符串:
key="9876543210123456"
希望上进入AES的128位为:
aes_key[127:0]=0x39 0x38 0x37 0x36...0x35 0x36
1. 小端设备:
内存中key的9保存在最低位,寄存器r1第一次加载的数据为:
r1[31:0]=0x36 0x37 0x38 0x39
(低地址在低位)
第二次加载的数据为:
r2[31:0]=0x32 0x33 0x34 0x35
(低地址在低位)
如果直接拼接的话,必然达不到aes_key的输入要求,需要再做交叉分线处理。
2.大端设备
内存中key的9也保存在最低位,寄存器r1第一次加载的数据为:
r1[31:0]=0x39 0x38 0x37 0x36
(低地址在高位)
第二次加载的数据为:
r2[31:0]=0x35 0x34 0x33 0x32
(低地址在高位)
因此先加载的地址放到aes_key的高位,可以满足所需要的排序。
这样硬件加速器对平台的大小端,还需要有一个判断操作。
但为什么纯c代码在两个平台都能跑,软件上却没有大小端的判断呢? 因为c代码里都是单字节操作,没有内存和寄存器间大于1byte的加载并计算再存储的问题。
总结这一篇需要多久时间
写的过程不久,debug和找资料的过程得看运气。这种bug一般两三天吧