前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >​数据存储和传输的大小端问题

​数据存储和传输的大小端问题

作者头像
IC验证
发布2021-04-28 14:25:09
1.2K0
发布2021-04-28 14:25:09
举报
文章被收录于专栏:杰瑞IC验证杰瑞IC验证

|原创作者| Q哥

先问大家一个隐私习惯,吃茶叶蛋的时候,你会先磕破鸡蛋比较小的那一端,还是比较大的那一端?

这个看似无厘头的问题,曾经引发了两个小国家持续不断的战争,好奇的读者可以自行查阅《格列佛游记》。这部小说也是big endian(大端)和little endian(小端)两个词汇的来源。

数据在memory中存储,以及在总线传输的时候,同样也会面临大小端问题。这个蛋疼的问题之所以存在,就好比各个国家的插座不兼容一样,都是历史遗留问题。

对于验证人员来说,要实现memory的后门读写,编写RAL寄存器模型的adapter,调试串口,这些都需要对大小端有所了解。

1 数据存储

数据在memory中存储的时候,低地址存放低Byte,高地址存放高byte, 称为Little Endian存储。反之,低地址存放高Byte,高地址存放低Byte,称为Big Endian存储

1.1 大端存储

例如,对于”learn verification with jerry_ic”这个字符串,对于64位大端存储,byte的排布如下:

地址

7

6

5

4

3

2

1

0

数据

6c

65

61

72

6e

20

76

65

字符

l

e

a

r

n

空格

v

e

地址

F

E

D

C

B

A

9

8

数据

72

69

66

69

63

61

74

69

字符

r

i

f

i

c

a

t

i

地址

17

16

15

14

13

12

11

10

数据

6c

65

61

72

6e

20

76

65

字符

o

n

空格

w

i

t

h

空格

地址

1F

1E

1D

1C

1B

1A

19

18

数据

72

69

66

69

63

61

74

69

字符

j

e

r

r

i

_

i

c

因为64位相当于8个字符,所以memory第一行就可以存储”learn空格ve”这8个字符。

按照高地址先存低byte,低地址存高byte这个大端规则:第一个byte,专业术语叫LSB(least significant byte),也就是字符l(字母L小写)的ASCII码值6c,存入地址7;而这8个字符里最后一个byte,专业术语叫MSB(most significant byte),即字符e的ASCII码值65,存入地址0。

从memory中读出第一行数据到logic[63:0] BigEndianData64这个变量,则BigEndianData64 == 64'h6c_65_61_72_6e_20_76_65。

这一行的8个byte,每个byte所在位置称为一个byte lane。有些memory,可以按照各个byte lane 是否enable决定只写某几个byte。这时候也要根据大端原则来给对应的byte lane enable信号。

紧接着,memory的第二行可以存储rificati这8个字符。

以此类推......

这里之所以强调行号,因为在验证环境里面,对memory进行后门读写的时候,通常需要直接用行号进行索引。

好奇的读者可能要问了,如果最后一行凑不够8个byte怎么办?

好问题!依然是先写高地址,再写低地址。所以如果只有一个byte ’hff, 会存入高地址,那么这一行的数据就是64'hff_xx_xx _xx _xx _xx _xx _xx。

1.2 小端存储

对于“learn verification with jerry_ic”这个字符串,在64位小端存储的内存里是这样的:

地址

7

6

5

4

3

2

1

0

数据

65

76

20

6e

72

61

65

6c

字符

e

v

空格

n

r

a

e

l

地址

F

E

D

C

B

A

9

8

数据

69

74

61

63

69

66

69

72

字符

i

t

a

c

i

f

i

r

地址

17

16

15

14

13

12

11

10

数据

65

76

20

6e

72

61

65

6c

字符

空格

h

t

i

w

空格

n

o

地址

1F

1E

1D

1C

1B

1A

19

18

数据

69

74

61

63

69

66

69

72

字符

c

i

_

i

r

r

e

j

跟64位大端存储对比,每一行的存储数据是一样的,只不过这一行里每个byte的排布是完全反的。

代码片段1

按照低地址先存低byte,高地址存高byte这个小端规则:第一个byte,专业术语叫LSB,也就是字符l(字母L小写)的ASCII码值6c,存入地址0;而这8个字符里最后一个byte,专业术语叫MSB,即字符e的ASCII码值65,存入地址7. 从memory中读出第一行数据到logic[63:0] LittleEndianData64这个变量,则LittleEndianData64时,LittleEndianData64 == 64'h65_76_20_6e_72_61_65_6c。

紧接着,memory的第二行可以存储rificati这8个字符。

以此类推......

最后一行如果只有一个byte ’hff, 会存入低地址,这一行的数据是64'hxx_xx_xx _xx _xx _xx _xx _ff。

对于32位大端存储,byte的排布如下:

地址

3

2

1

0

数据

6c

65

61

72

字符

l

e

a

r

地址

7

6

5

4

数据

6e

20

76

65

字符

n

空格

v

e

地址

B

A

9

8

数据

72

69

66

69

字符

r

i

f

i

地址

F

E

D

C

数据

63

61

74

69

字符

c

a

t

i

地址

13

12

11

10

数据

6c

65

61

72

字符

o

n

空格

w

地址

17

16

15

14

数据

6e

20

76

65

字符

i

t

h

空格

地址

1B

1A

19

18

数据

72

69

66

69

字符

j

e

r

r

地址

1F

1E

1D

1C

数据

63

61

74

69

字符

i

_

i

c

这里需要注意下,对于数据位宽是32位的大端存储,相当于把上面64位大端memory的一行,拆成了两行进行存储。只不过这两行存储的时候,即先存储地址范围高的那4个byte,再存储地址范围低的那4个byte 。

代码片段2

在32位小端存储的内存里是这样的:

地址

3

2

1

0

数据

72

61

65

6c

字符

r

a

e

l

地址

7

6

5

4

数据

65

76

20

6e

字符

e

v

空格

n

地址

B

A

9

8

数据

69

66

69

72

字符

i

f

i

r

地址

F

E

D

C

数据

69

74

61

63

字符

i

t

a

c

地址

13

12

11

10

数据

72

61

65

6c

字符

w

空格

n

o

地址

17

16

15

14

数据

65

76

20

6e

字符

空格

h

t

i

地址

1B

1A

19

18

数据

69

66

69

72

字符

r

r

e

j

地址

1F

1E

1D

1C

数据

69

74

61

63

字符

c

i

_

i

对于数据位宽是32位的小端存储,相当于把上图64位小端memory的一行,拆成了两行进行存储;先存低byte,再存高byte。

代码片段3

32位小端相比于32位大端就比较清晰简单了,只是把byte的顺序颠倒了一下。

代码片段4

2 总线传输

总线传输的时候,同样有大小端问题。这里按照总线是并口还是串口,分别说明。

2.1 并口总线

对于并口总线,MSB传输低地址数据,LSB传输高地址数据,即为大端传输。反之, LSB传输低地址数据,MSB传输高地址数据,即为小端传输。

这里抛开具体协议,举个例子:对于数据位宽是32位的总线,即xfer_data[31:0],有4个byte lane,其中xfer_data[7:0]称为LSB,xfer_data[31:24]称为MSB。这时候要传输地址0到3存储的4个byte。

如果xfer_data[7:0]对应地址0,xfer_data[15:8]对应地址1,xfer_data[23:16]对应地址2,xfer_data[31:24]对应地址3,这样的总线就是小端传输。常见的有AHB/AXI等。

反之,如果xfer_data[7:0]对应地址3,xfer_data[15:8]对应地址2,xfer_data[23:16]对应地址1,xfer_data[31:24]对应地址0,这样的总线就是大端传输。

这里同样存在凑不够32bit的问题。但是因为每一byte数据都有对应的地址,只使用该地址对应的byte lane就好了。

那么问题来了?同样使用小端总线,传输的时候不用考虑memory是大端还是小端吗?

总线协议千差万别,Q哥没法给大家肯定的答复。只能说,常见的总线都是byte-invariant的,也就是说,不用管它是大端memory还是小端memory,地址0对应的byte一定是放到小端总线的xfer_data[7:0] 进行传输的,以此类推。

对于总线传输数据位宽与memory存储数据位宽相等的系统,直接整行进行读写以及整行传输就好了。

对于总线位宽与memory存储位宽不匹配的系统,就需要考虑转接适配了。通常系统里面总线位宽和存储位宽是整数倍关系,只需要计算好每次传输和memory读写的地址关系就可以了。

总线位宽大于存储位宽,相当于总线上一拍数据传输,需要读写N次memory。总线位宽小于存储位宽, 相当于读写一次memory,需要总线上N拍数据传输才能完成。按照上面64位转32位的对应关系就可以了。

总线协议虽然千差万别,但是大家只要弄清楚每一拍数据对应的地址是怎么变化的,就可以游刃有余,以不变应万变。请持续关注【杰瑞IC验证】,后面会为大家带来AXI等常见总线的协议讲解,敬请期待!

2.2 串口总线

对于串口总线,就比较复杂了。不单单要考虑byte的大小端,甚至要考虑bit的大小端了。也就是说,对于一拍传输一个bit的串口总线,传输16’h1234有4种组合:

先发MS Byte,再发LS Byte(ByteBigEndian);并且,每个byte先发MS bit, 再发LS bit(Bit BigEndian)

先发MS Byte,再发LS Byte(ByteBigEndian);并且,每个byte先发LS bit, 再发MS bit(Bit LittleEndian)

先发LS Byte,再发MS Byte(Byte LittleEndian);并且,每个byte先发MS bit, 再发LS bit(Bit BigEndian)

先发LS Byte,再发MS Byte(Byte LittleEndian);并且,每个byte先发LS bit, 再发MS bit (Bit LittleEndian)

这里看似复杂,但实际上对照波形仔细检查,很容易核对。

3 如何调试大小端问题

当你搭好验证环境,开始调试的时候,发现灌到RTL上的激励或者抓到的输出结果完全对不上的时候,不要慌,有可能只是大小端搞错了。

某些项目可能因为传承原因,参考模型所提供的参考数据跟实际需要的大小端不一致。这时候只需要按照上面代码片段修改一下数据的大小端排布就好了。

另外,为了快速调试大小端问题,可以把数据设置为’h12345678这样子递增的模式。这样查看仿真log 或者波形,都是一目了然的。

VIM或者UltraEdit等文本编辑工具,都可以查看二进制文件的byte内容,如下图所示:

这里简单解释下:第1列是每行数据的起始地址,第2到第9列是每个地址存储的byte内容(地址从低到高增加),最右边是第2到第9列对应的字符。这个图相当于是一个128位(每行16byte)的小端存储器显示。

结语

Q哥今天给大家讲述了数据存储和总线传输的大小端问题。大家在集成RAL模型的时候,需要注意RAL adapter是否需要修改地址和数据匹配的代码。后门读写memory、解析仿真模型提供的参考数据时,都要注意大小端。具体的案例,先卖个关子,且听Q哥下回分解。

——The End——

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-04-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 杰瑞IC验证 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 数据存储
  • 2 总线传输
  • 3 如何调试大小端问题
  • 结语
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档