HDLBits – Vector1

Build a combinational circuit that splits an input half-word (16 bits, [15:0] ) into lower [7:0] and upper [15:8] bytes.

https://hdlbits.01xz.net/wiki/Vector1

There is a lot of great information on the HDLBits page for this exercise, so make sure that you understand everything there. Note that we will only be using the logic datatype in these exercises, unless otherwise noted. Although the rules on the HDLBits page certainly apply to the wire and reg datatypes, our focus here is on learning modern SystemVerilog. In line with this goal, the following rules apply:

  • The reg datatype should never be used when writing modern SystemVerilog (use logic instead)
    • You will still need to understand it to modify legacy code and generated Verilog IP (like code automatically generated by Vivado)
  • The wire/tri datatypes should only be used in cases where there can be multiple drivers to the same net
    • As these applications aren’t covered in the HDLBits exercises, you should never use them here
    • The wire and tri resolution tables are the same, making these datatypes functionally synonymous
    • The logic datatype will throw an error if it has multiple drivers, which will tell you that you need a wire/tri instead (if that’s your design intent)

In short, you should only be using the logic datatype in these exercises. There will be some exceptions for things like integers and enumerated types, but we’ll get there eventually.

Also, as was stated on the HDLBits page, it is very important to avoid implicit nets. These show up sometimes in code to save time, but that time is usually lost when someone else inherits the module and is forced to sift through the pot of spaghetti. The `default_nettype none compiler directive should always be used in order to prevent these issues. I’ve omitted it in these exercises in order to prevent confusion for beginners.

In terms of arrays, remember that a vector can use negative indices. In addition, when referencing a vector or grabbing a subset of it, the range of indices must match the endianness that was chosen when originally creating the vector. Here are some examples:

logic [3:-3] vec,      // Declare a 7-bit little-endian logic vector
logic [0: 4] vec_out   // Declare a 5-bit big-endian logic vector
// Valid part select statements to grab a subset of vec
vec[-1:-3]
vec[ 3:0 ]
vec[ 0:0 ]
// Invalid part select statements to grab a subset of vec
vec[-3:-1]  // Index range does not match the endianness of vec (vec has descending indices)
vec[ 0:3 ]  // Index range does not match the endianness of vec (vec has descending indices)
// Vectors of different endianness can be assigned to each other if the indices are correct
assign vec_out[0:3] = vec[0:-3];

With that, we’ll use the same approach as the last problem in order to solve this one. First, we’ll use part select:

module top_module ( 
  input  logic [15:0] in,
  output logic  [7:0] out_hi,
  output logic  [7:0] out_lo );
  assign out_hi = in[15:8];
  assign out_lo = in[ 7:0];
    
endmodule : top_module

We can also solve this one using concatenation:

module top_module ( 
  input  logic [15:0] in,
  output logic  [7:0] out_hi,
  output logic  [7:0] out_lo );
  assign {out_hi, out_lo} = in;
    
endmodule : top_module

Leave a Reply

Your email address will not be published. Required fields are marked *