3 minute read

Signed Arithmetic

Overview

Casting in SystemVerilog is a powerful mechanism for explicitly converting data between different types, sizes, and sign interpretations. This guide covers the three main types of casting available in synthesizable SystemVerilog and their practical applications.

Video Tutorial

Watch this comprehensive video explanation of Casting:

SystemVerilog Casting Guide

Table of Contents

Cast Operator Syntax

SystemVerilog provides three primary casting syntaxes:

Syntax Purpose Example
<type>'(expression) Convert to user-defined data type packet_t'(9'b100010111)
<size>'(expression) Convert to specific bit width 8'(4'b1001)
<sign>'(expression) Convert sign interpretation signed'(8'hFF)

Type Casting

Type casting converts raw bit patterns into user-defined data types such as enums, structs, or unions.

Enum Type Casting

typedef enum logic [1:0] {
    RED   = 2'b00,
    GREEN = 2'b01,
    BLUE  = 2'b10
} colors_t;

logic [1:0] raw_color = 2'b10;
colors_t color;

// Explicit type casting
assign color = colors_t'(raw_color);    // Converts 2'b10 to BLUE

Struct Type Casting

typedef struct packed {
    logic [7:0] data;
    logic       valid;
} packet_t;

logic [8:0] raw_data = 9'b100010111;
packet_t packet;

// Convert 9-bit raw data to struct
assign packet = packet_t'(raw_data);
// Result: packet.data = 8'b00010111, packet.valid = 1'b1

When to Use Type Casting

  • Converting between packed arrays and user-defined types
  • Interfacing with external modules that use raw bit vectors
  • Deserializing data from communication protocols
  • Working with configuration registers

Size Casting

Size casting explicitly controls the bit width of signals, preventing synthesis warnings and making code intentions clear.

Basic Size Casting

logic [3:0] data4 = 4'b1101;   // 4-bit value: 13
logic [7:0] data8;
logic [1:0] data2;

// Zero extension (adding leading zeros)
assign data8 = 8'(data4);      // Result: 8'b0000_1101

// Truncation (removing MSBs)
assign data2 = 2'(data4);      // Result: 2'b01 (LSBs only)

Implicit vs Explicit Size Casting

logic [3:0] narrow;
logic [7:0] wide;

// Implicit casting (may generate warnings)
assign wide = narrow;          // Compiler warning possible

// Explicit casting (clean, warning-free)
assign wide = 8'(narrow);      // Clear intention, no warnings

Size Casting with Literals

logic [3:0] data4;

// Without explicit casting
assign data4 = 4;              // 32-bit literal truncated to 4 bits

// With explicit casting  
assign data4 = 4'(4);          // Clear 4-bit assignment

Sign Casting

Sign casting controls how bit patterns are interpreted as signed or unsigned values.

Basic Sign Conversion

logic signed   [7:0] s1 = 8'sb1111_1011;  // -5 in two's complement
logic unsigned [7:0] u1 = 8'd5;           //  5 as unsigned

// Converting signed to unsigned
assign u1 = unsigned'(s1);     // -5 becomes 251 (0xFB)

// Converting unsigned to signed
assign s1 = signed'(8'hFF);    // 255 becomes -1

Mixed Sign Operations

Critical Concept: When mixing signed and unsigned operands, SystemVerilog defaults to unsigned arithmetic.

logic signed   [7:0] s_val = -1;    // 8'b1111_1111
logic unsigned [7:0] u_val = 5;     // 8'b0000_0101
logic result;

// Dangerous: Mixed sign comparison
assign result = (u_val > s_val);           // Result: 0 (5 > 255 is false)

// Safe: Explicit sign casting
assign result = (signed'(u_val) > s_val);  // Result: 1 (5 > -1 is true)

Sign Casting in Arithmetic

logic signed   [7:0] a = -10;
logic unsigned [7:0] b = 20;
logic signed   [8:0] sum;

// Incorrect: Mixed signs lead to unexpected results
assign sum = a + b;                    // Unsigned arithmetic

// Correct: Explicit sign casting
assign sum = signed'(a) + signed'(b);  // Signed arithmetic

Best Practices

  1. Always use explicit casting when converting between different types or sizes
  2. Cast before comparisons when mixing signed and unsigned values
  3. Document casting intentions with comments explaining the conversion
  4. Use meaningful type names for custom data types
  5. Validate cast results in testbenches to ensure correct behavior

Practices to Avoid

  1. Don’t rely on implicit conversions - they can mask bugs
  2. Don’t ignore synthesis warnings about size mismatches
  3. Don’t mix signed and unsigned without explicit casting
  4. Don’t cast unnecessarily - only cast when needed for clarity or correctness

Examples

Example 1: Protocol Decoder

typedef struct packed {
    logic [3:0] opcode;
    logic [3:0] address;
    logic [7:0] data;
} instruction_t;

// Decode 16-bit instruction word
logic [15:0] raw_instruction;
instruction_t decoded;

assign decoded = instruction_t'(raw_instruction);

Example 2: Arithmetic Unit

module arithmetic_unit (
    input  logic signed   [7:0] a,
    input  logic unsigned [7:0] b,
    output logic signed   [8:0] result
);

// Safe mixed-sign arithmetic
assign result = signed'({1'b0, a}) + signed'({1'b0, b});

endmodule

Conclusion

Proper use of casting in SystemVerilog leads to:

  • Cleaner synthesis with fewer warnings
  • More predictable behavior in simulation and hardware
  • Better code documentation through explicit type conversions
  • Reduced debugging time by preventing type-related bugs

Remember: When in doubt, be explicit with your casting. The extra characters in your code will save hours of debugging later.