Systemverilog Streaming Operator Example

A rarely used operator but very useful in many situations.


What is bit-stream type

From IEEE SV 2017:

Types that can be packed into a stream of bits are called bit-stream types. A bit-stream type is a type consisting of the following:

  • Any integral, packed, or string type
  • Unpacked arrays, structures, or classes of the preceding types
  • Dynamically sized arrays (dynamic, associative, or queues) of any of the preceding types This definition is recursive so that, for example, a structure containing a queue of int is a bit-stream type

Streaming operator

From IEEE SV 2017:

The streaming operators perform packing of bit-stream types into a sequence of bits in a user-specified order.

The slice_size determines the size of each block, measured in bits. If a slice_size is not specified, the default is 1.

The stream_operator << or >> determines the order in which blocks of data are streamed:

  • >> causes blocks of data to be streamed in left-to-right order, while << causes blocks of data to be streamed in right-to-left order.
  • Left-to-right streaming using >> shall cause the slice_size to be ignored and no re-ordering performed.
  • Right-to-left streaming using << shall reverse the order of blocks in the stream, preserving the order of bits within each block.
  • For right-to-left streaming using <<, the stream is sliced into blocks with the specified number of bits, starting with the right-most bit. If as a result of slicing the last (left-most) block has fewer bits than the block size, the last block has the size of the remaining bits; there is no padding or truncation.

Example

Full code can be find in this gist: Systemverilog stream operator example

Description Code Link
Streaming Operator: pack an array to an integral
    int            m_pack_var;

    m_pack_var = {>>byte{8'h06, 8'h07, 8'h08}};
    $display ("array to var %h\n",  m_pack_var );
    // output:
    // array to var 06070800
    
    m_pack_var = {<<byte{8'h06, 8'h07, 8'h08}};
    $display ("array to var %h\n",  m_pack_var );
    // output:
    // array to var 08070600

      
Streaming Operator: pack a queue to an integral
    automatic byte q[$] = {8'h01, 8'h02, 8'h03};
    int            m_pack_var;

    m_pack_var = {>>byte{q}};
    $display ("queue to var %h\n",  m_pack_var );
    // output
    // queue to var 01020300

      
Streaming Operator: turn an integral to a queue, 8bit slice
    byte q[$];

    q =  {>>byte{24'h060708}};
    foreach (q[i]) begin
      $display("byte queue, byte-slice 0x%0x", q[i]);
    end
    // output:
    // byte queue, byte-slice 0x6
    // byte queue, byte-slice 0x7
    // byte queue, byte-slice 0x8

      
Streaming Operator: turn an integral to a queue, 4bit slice
    bit[3:0] p[$];

    p =  {>>4{24'h060708}};
    foreach (p[i]) begin
      $display("4bit queue, 4bit-slice 0x%0x", p[i]);
    end
    // output:
    // 4bit queue, 4bit-slice 0x0
    // 4bit queue, 4bit-slice 0x6
    // 4bit queue, 4bit-slice 0x0
    // 4bit queue, 4bit-slice 0x7
    // 4bit queue, 4bit-slice 0x0
    // 4bit queue, 4bit-slice 0x8

      
Streaming Operator: re-order, 8bit slice
    $display ("byte-slice  %h",  {>>byte{24'h060708}} );
    $display ("byte-slice  %h",  {<<byte{24'h060708}} );
    // output:
    // byte-slice 060708
    // byte-slice 080706

      
Streaming Operator: reverse bit, 1bit slice
    $display ("1bit-slice %h",  {>>bit{24'h0a0a0a}} );
    $display ("1bit-slice %h",  {<<bit{24'h050505}} );
    // output:
    // 1bit-slice 0a0a0a
    // 1bit-slice 505050

      
Streaming Operator: re-order, 4bit slice
    $display ("4bit-slice %h",  {>>4{24'h0a0a0a}} );
    $display ("4bit-slice %h",  {<<4{24'h050505}} );
    // output:
    // 4bit-slice 0a0a0a
    // 4bit-slice 505050

      
Streaming operator at lhs, turn an integral to 3 different vars
    byte a, b, c;

    {<<byte{a,b,c}} = 24'h060708;
    $display("unpack a 0x%0x", a);
    $display("unpack b 0x%0x", b);
    $display("unpack c 0x%0x\n", c);

    {>>byte{a,b,c}} = 24'h060708;
    $display("unpack a 0x%0x", a);
    $display("unpack b 0x%0x", b);
    $display("unpack c 0x%0x", c);

      
Streaming Operator: use 2 Streaming Operator to turn a 32bit queue to a 8bit queue and vice versa
    automatic byte      q8[$]  = {8'h01, 8'h02, 8'h03, 8'h04, 8'h05, 8'h06, 8'h07};
    automatic bit[31:0] q32[$];

    q32 = {>>32{q8}}    ;
    foreach (q32[i]) begin
      $display ("q8 to q32  0x%0x",  q32[i] );
    end
    //
    // output:
    // 0x1020304
    // 0x5060700

    q8.delete();
    q8 = {>>8{q32}} ;
    $display ("q32 to q8  %p",  q8 );
    // output
    // '{1, 2, 3, 4, 5, 6, 7, 0}


      
Streaming Operator: use 2 Streaming Operator to turn a 8bit queue to a 32bit queue with reverse order
    // input:
    // dd 19 df f2 83 e2 5c 4b-f3 a6 cd e0 99 7f 59 33

    // expected output
    // 0xf2df19dd -  0x4b5ce283 -  0xe0cda6f3 - 0x33597f99
    automatic byte      q8[$]  = {  'hdd , 'h19 , 'hdf , 'hf2 ,
                                    'h83 , 'he2 , 'h5c , 'h4b ,
                                    'hf3 , 'ha6 , 'hcd , 'he0 ,
                                    'h99 , 'h7f , 'h59 , 'h33};
    automatic bit[31:0] q32[$];

    q32 = {<<32{{<<8{q8}}}};
    foreach (q32[i]) begin
      $display ("q8 to q32 reverse order  0x%0x",  q32[i] );
    end
    // q8 to q32 reverse order  0xf2df19dd
    // q8 to q32 reverse order  0x4b5ce283
    // q8 to q32 reverse order  0xe0cda6f3
    // q8 to q32 reverse order  0x33597f99

    q8.delete();
    q8 = {<<8{{<<32{q32}}}};
    $displayh ("q32 to q8  %p",  q8 );
    // q32 to q8  '{dd, 19, df, f2, 
    //              83, e2, 5c, 4b, 
    //              f3, a6, cd, e0, 
    //              99, 7f, 59, 33}



      
Streaming Operator: Remove offset and pack to different size
    // 32bit data queue, offset 16 bit, need to pack to 28bit data queue
    // input:           --> expected data:
    // [ 0] 0xa5dc_751c      [ 0] 0x135_a5dc
    // [ 1] 0x23ff_4135      [ 1] 0xc12_3ff4
    // [ 2] 0x56c8_29c1      [ 2] 0x056_c829

    automatic bit[31:0]   q32[$]  = {32'ha5dc_751c, 32'h23ff_4135, 32'h56c8_29c1};
    automatic bit         q1[$];
    automatic bit[27:0]   q28[$];

    int offset = 16

    // pack to 1 bit queue
    q1 = {<<1{ {<<32{q32}}  }};

    // remove unnecessary bit in the offset
    for(int i =0; i<offset;i++) q1.pop_front();
    for(int i =0; i<offset;i++) q1.push_back(0);


    // pack to 28bit queue
    q28 = {<<28{ {<<1{q1}} }};
    
    $displayh ("q28  %p",  q28 );
    // q28  '{135a5dc, c123ff4, 056c829, 0000000}


      

Finding more information

To have more understanding as well as more examples, check below references:

  1. IEEE SV 2017: 11.4.14 Streaming operators (pack/unpack)
  2. AMIQ: How to pack data using systemverilog streaming operators


[Tags systemverilog  ]