From 1c0739db10cd5aa02dd495aca1f592269b76481a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Risto=20Peja=C5=A1inovi=C4=87?= Date: Mon, 29 May 2023 18:08:39 +0200 Subject: [PATCH] Fix unpacked struct == and != operators (#4234) (#4240) --- src/V3EmitCHeaders.cpp | 23 ++++++++++++ test_regress/t/t_unpacked_struct_eq.pl | 21 +++++++++++ test_regress/t/t_unpacked_struct_eq.v | 51 ++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100755 test_regress/t/t_unpacked_struct_eq.pl create mode 100644 test_regress/t/t_unpacked_struct_eq.v diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 4d2a77d60..abda6f4f1 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -22,7 +22,9 @@ #include "V3Global.h" #include +#include #include +#include #include VL_DEFINE_DEBUG_FUNCTIONS; @@ -236,6 +238,27 @@ class EmitCHeader final : public EmitCConstInit { puts(itemp->dtypep()->cType(itemp->nameProtect(), false, false)); puts(";\n"); } + + puts("\nbool operator==(const " + EmitCBase::prefixNameProtect(sdtypep) + "& rhs){\n"); + puts("return "); + for (const AstMemberDType* itemp = sdtypep->membersp(); itemp; + itemp = VN_AS(itemp->nextp(), MemberDType)) { + if (itemp != sdtypep->membersp()) puts("\n && "); + if (AstUnpackArrayDType* const adtypep + = VN_CAST(itemp->subDTypep(), UnpackArrayDType)) { + for (uint32_t i = 0; i < adtypep->arrayUnpackedElements(); i++) { + if (i != 0) puts("\n && "); + puts(itemp->nameProtect() + "[" + std::to_string(i) + "U] == " + "rhs." + + itemp->nameProtect() + "[" + std::to_string(i) + "U]"); + } + } else { + puts(itemp->nameProtect() + " == " + "rhs." + itemp->nameProtect()); + } + } + puts(";\n"); + puts("}\n"); + puts("bool operator!=(const " + EmitCBase::prefixNameProtect(sdtypep) + "& rhs){\n"); + puts("return !(*this == rhs);\n}\n"); puts("};\n"); } void emitStructs(const AstNodeModule* modp) { diff --git a/test_regress/t/t_unpacked_struct_eq.pl b/test_regress/t/t_unpacked_struct_eq.pl new file mode 100755 index 000000000..a17622844 --- /dev/null +++ b/test_regress/t/t_unpacked_struct_eq.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2004 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_unpacked_struct_eq.v b/test_regress/t/t_unpacked_struct_eq.v new file mode 100644 index 000000000..726922e24 --- /dev/null +++ b/test_regress/t/t_unpacked_struct_eq.v @@ -0,0 +1,51 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Use this file as a template for submitting bugs, etc. +// This module takes a single clock input, and should either +// $write("*-* All Finished *-*\n"); +// $finish; +// on success, or $stop. +// +// The code as shown applies a random vector to the Test +// module, then calculates a CRC on the Test module's outputs. +// +// **If you do not wish for your code to be released to the public +// please note it here, otherwise:** +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + typedef struct { + string txt; + struct { + logic m0; + logic [3:0] m1; + } sub; + logic [7:0] arr[2]; + } struct_t; + struct_t s1; + struct_t s2; + + assign {s1.sub.m0, s1.sub.m1} = {1'b0, 4'h5}; + assign {s2.sub.m0, s2.sub.m1} = {1'b0, 4'h5}; + assign s1.txt = "text"; + assign s2.txt = "text"; + assign s1.arr[0] = 8'h77; + assign s2.arr[0] = 8'h77; + assign s1.arr[1] = 8'h33; + assign s2.arr[1] = 8'h33; + + initial begin + if(s1 != s2) begin + $fatal; + end + if(s1 == s2) begin + $write("*-* All Finished *-*\n"); + $finish; + end else begin + $fatal; + end + end +endmodule