SystemVerilog OOP Mastery · All levels

Missing Features vs C++/Java and Reliable Workarounds: Code Examples

Code Examples for Missing Features vs C++/Java and Reliable Workarounds.

Code examples

Generic algorithms and overloaded APIs

systemverilog
// C++: template function + overloads
template <typename T>
T clamp(T v, T lo, T hi) {
  return (v < lo) ? lo : ((v > hi) ? hi : v);
}

class Writer {
public:
  void write(int v);
  void write(const std::string& s);
};

// Java: generics + overloads
class WriterJ {
  void write(int v) {}
  void write(String s) {}
}

// SystemVerilog: parameterized classes + explicit method names
class fifo #(type T = int);
  T q[$];
  function void push(T item); q.push_back(item); endfunction
  function T pop(); return q.pop_front(); endfunction
endclass

function int clamp_int(int v, int lo, int hi);
  return (v < lo) ? lo : ((v > hi) ? hi : v);
endfunction

class writer_sv;
  function void write_int(int v); $display("int=%0d", v); endfunction
  function void write_str(string s); $display("str=%0s", s); endfunction
endclass

SV supports type-parameterized classes but not full template-function ecosystems or signature-based overloads in classes, so APIs become explicitly named and type-specific.

Friend access and const-correctness

systemverilog
// C++: friend + const methods
class Token {
  int secret;
  friend class TokenInspector;
public:
  int size() const { return 1; }
};

class TokenInspector {
public:
  int read(const Token& t) { return t.secret; }
};

// SystemVerilog: explicit debug/export API + read-only conventions
class token;
  local int secret;

  function int debug_secret(bit allow);
    if (allow) return secret;
    return '0;
  endfunction

  function int size();
    return 1; // convention: query method does not mutate state
  endfunction
endclass

Without friend or const qualifiers on methods, SV teams encode privileged access and immutability through naming conventions, local/protected fields, and explicit accessor policies.

Namespaces and exceptions

systemverilog
// C++ namespace + exceptions
namespace proto {
class Crc {
public:
  static uint32_t next(uint32_t d) { return d ^ 0x04C11DB7u; }
};
}

int parse_cfg(const std::string& p) {
  if (p.empty()) throw std::runtime_error("missing path");
  return 0;
}

// Java package + try/catch
package proto;
class CrcJ {
  static int next(int d) { return d ^ 0x04C11DB7; }
}

// SystemVerilog package + status return
package proto_pkg;
  class crc;
    static function bit [31:0] next(bit [31:0] d);
      return d ^ 32'h04C11DB7;
    endfunction
  endclass

  typedef enum int {CFG_OK=0, CFG_ERR_PATH=1} cfg_status_e;

  function cfg_status_e parse_cfg(string p);
    if (p == "") return CFG_ERR_PATH;
    return CFG_OK;
  endfunction
endpackage

import proto_pkg::*;
cfg_status_e st = parse_cfg(cfg_path);
if (st != CFG_OK) begin
  $error("parse_cfg failed status=%0d", st);
end

SV uses packages for logical grouping and explicit status/error channels instead of exception propagation and catch blocks.

Related topics