返回介绍

3.16 位流强制类型转换

发布于 2020-09-09 22:55:44 字数 2891 浏览 1006 评论 0 收藏 0

强制类型转换还可以应用于非压缩数组以及非压缩结构体。这样就使得通过显式强制类型转换在位流类型之间自由地转换成为可能。可以压缩成一个位流的类型称为位流类型。位流类型包含下列的类型:

  • 任何integral、压缩、或字符串类型
  • 非压缩数组、结构体、或上述类型的类
  • 任何上述类型的动态尺寸数组(动态的、联合的、或队列)

这个定义是递归的,例如,一个包含int队列的结构体是一个位流类型。

假定A具有source_t的位流类型,B具有dest_t的位流类型,那么我们可以使用显式强制类型转换将A转换到B

B = dest_t'(A);

source_t类型的A转换到dest_t类型的B以下面两个步骤执行:

  1. source_t转换到一个通用的压缩值,这个压缩值与source_t具有相同的位数目。如果source_t包含任何四态数据,那么整个压缩值是四态的,否则它就是两态的。
  2. 从通用的压缩值转换到dest_t。如果通用的压缩值是四态类型并且dest_t的部分值是两态的,那么对这些两态类型的赋值被强制转换成两态的。

当一个动态数组、队列、或字符串被转换成压缩表示方式的时候,在索引0处的元素占据最高有效位。当一个联合数组被转换成压缩表示方式的时候,那么按索引顺序排列的第一个索引元素占据最高有效位。

无论是source_t还是dest_t都可以在任何位置包含一个或多个动态尺寸的数据(例如,一个包含紧跟着一个字节对列的动态数组的结构体)。如果源类型source_t包含了动态尺寸的变量,那么它们全部包含在位流当中。如果目的类型dest_t包含了许多动态尺寸类型,那么整个转换过程是很庞大的:计算source_t的尺寸,减去目的类型中具有固定尺寸的数据的尺寸,接着将目的类型中第一个动态尺寸元素的尺寸调整到剩余的尺寸;任何剩余的动态尺寸元素均被留空。

为了实现位流强制类型转换,一个字符串被认为是动态的字节数组。

无论目的类型是否只包含固定尺寸的元素还是包含了动态尺寸的元素,数据都会以从左到右的顺序提取到目的类型。因此,从一个压缩表示方式的中间部分提取数据来填充一个动态尺寸的元素是合法的。

如果source_tdest_t都是固定尺寸的非压缩类型,但它们具有不同的尺寸,那么强制类型转换会产生一个编译时错误。如果source_tdest_t包含了动态尺寸类型,那么只要能够确定它们在尺寸上的不匹配,它们在尺寸上的不一致就会产生一个编译时错误或运行时错误。例如:

// 从24位结构体转换成int(32位)是不合法的,- 编译时错误
struct {
    bit[7:0] a;
    shortint b;
} a;
int b = int'(a);

// 从20位结构体转换到int(32位)是不合法的 - 运行时错误
struct {
    bit a[$];
    shortint b;
} a = {{1,2,3,4}, 67};
int b = int'(a);

// 从int(32位)转换到dest_t结构体(25位或33位)是不合法的
// 编译时错误
typedef struct {
    byte a[$];
    bit b;
} dest_t;

int a;
dest_t b = dest_t'(a);

位流强制类型转换可以用来在不同的集合类型间转换,例如两个结构体类型,或者一个结构体与一个数组或队列类型之间。对于在串行通信流上传输包数据的建模,这种转换非常有用:

typedef struct {
    shortint address;
    reg [3:0] code;
    byte command [2];
} Control;

typedef bit Bits [36:1];

Control p;

Bits stream[$];

p = ... // 初始化Control包

stream = {stream, Bits'(p)} // 将包附加到非压缩位队列

Control q;

q = Control'(stream[0]);   // 将位流转换回一个Contorl包

stream = stream[1:$];      // 从流中删除包

下面的例子使用位流强制类型转换来建模在字节流上传输数据包:

typedef struct {
    byte length;
    shortint address;
    byte payload[];
    byte chksum;
} Packet;

上面的类型定义了一个普通的数据包,它的净荷的尺寸存储在length域。下面的函数随机地初始化包并产生校验和。

function Packet genPkt();
    Packet p;
    void'(randomize(p.address, p.length, p.payload)
    with {p.length>1 && p.payload.size == p.length});
        p.chksum = p.payload.xor();
    return p;
endfunction

字节流使用一个队列建模,一个位流强制类型转换被用来在流上发送包。

typedef byte channel_type[$];
channel_type channel;
channel = {channel, channel_type'(genPkt())};

下面的代码用来接收包。

Packet p;
int size;
size = channel[0] + 4;
p = Packet'(channel[0:size-1]); // 将流转换成包
channel = channel[size, $];     // 从流中删除包

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文