0
\$\begingroup\$

What is the best practice for creating a bus, which is just extraction of certain bits of a larger bus. I do not want to store the index numbers to make the lookup in the generate-for if it could be avoided....I was hoping for something like following code which is of course not valid. Can we take advantage of the fact somehow that the extracted shorter bus is always consecutive bits from the larger bus?

localparam logic [7:0] VALID = {1'b0, 1'b1, 1'b1, 1'b1, 1'b1, 1'b0, 1'b0, 1'b0}; 


 genvar m, j;
  generate
    for (m=0; m<8; m++) begin
      if (VALID[m]) begin
        assign short_bus[j] = large_bus[m];
        j++;
      end
  endgenerate
\$\endgroup\$
  • \$\begingroup\$ Do you know in advance which bits are going to be valid? If so, you could just use assign short_bus = VALID[6:3]; - although I don't think that's what you're asking... \$\endgroup\$ – awjlogan Nov 29 '18 at 15:31
  • \$\begingroup\$ VALID only tells which bits of the large_bus go onto the short_bus \$\endgroup\$ – frank_010 Nov 29 '18 at 15:37
  • \$\begingroup\$ Think hardware instead of Verilog. The dumbest way is a set of multiplexers. The smartest way is shift register (but will require a number of cycles). \$\endgroup\$ – Anonymous Nov 29 '18 at 16:15
  • \$\begingroup\$ @Anonymous, the smartest way is just connect to the wires you want to connect to and not the other wires. No register involved (and OP doesn't seem to want the signals syncronized to a clock the way a register-based solution would require) \$\endgroup\$ – The Photon Nov 29 '18 at 16:52
  • \$\begingroup\$ @frank_010, if the wanted bits are always consecutive why not just use assign short_bus[4:0] = large_bus[first_index+4:first_index]; ? Sorry I don't know enough SystemVerilog to make this a full answer. \$\endgroup\$ – The Photon Nov 29 '18 at 16:54
0
\$\begingroup\$

I would use an array with the length of the short bus that maps short bus indices to large bus ones:

// Large Bus Width
localparam int LBW = 8;
localparam logic [LBW-1:0] VALID = {1'b0, 1'b1, 1'b1, 1'b1, 1'b1, 1'b0, 1'b0, 1'b0};

// 1. Function returning the width of the short bus
function automatic int get_short_width();
    automatic int si = 0;
    for (int li=0; li<LBW; li++)
        if (VALID[li])
            si++;
    return si;
endfunction

// Short Bus Width
localparam int SBW = get_short_width();

typedef int t_idx_arr[SBW];
// 2. Function returing the large-to-short array index mapping
function automatic t_idx_arr get_short_indices();
    t_idx_arr idx_ret;
    automatic int si = 0;

    for (int li=0; li<LBW; li++) begin
        if (VALID[li]) begin
            idx_ret[si] = li;
            si++;
        end
    end
    return idx_ret;
endfunction

// Large 2 Short Index Array
localparam t_idx_arr L2S_IDX = get_short_indices();

// 3. Assign
logic[LBW-1:0] large_bus;
logic[SBW-1:0] short_bus;

// note: loop on the SHORT bus width!
for (genvar si=0; si<SBW; si++) begin
    assign short_bus[si] = large_bus[L2S_IDX[si]];
end

assign large_bus = 8'b1101_1011;
// short_bus = 4'b1011

This works for non-consecutive valid bit positions on the large bus as well.

\$\endgroup\$
0
\$\begingroup\$

You have several options in SystemVerilog.

If your busses are nets, you can use an alias construct (See section 10.11 of the 1800-2017 LRM)

alias long_bus[M:N] = short_bus;
alias long_bus[O:+W] = short_bus;

M,N,O, and W must all be constant expressions of literals or parameters. For variables or nets, you can use the let construct (See section 11.12)

let short_bus = long_bus[M:N];
let short_bus = long_bus[O+:W]; // O does not need to be a constant

The benefits of these constructs over the assign construct is that its possible to use short_bus on both the LHS and RHS of an assignment.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.