diff --git a/src/V3EmitCConstInit.h b/src/V3EmitCConstInit.h new file mode 100644 index 000000000..1cabd9f03 --- /dev/null +++ b/src/V3EmitCConstInit.h @@ -0,0 +1,122 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Emit C++ for tree +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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 +// +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Ast.h" +#include "V3EmitCBase.h" +#include "V3Error.h" + +#include + +//###################################################################### +// Emitter that can emit constant initializer expressions + +class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitor { + // MEMBERS + bool m_inUnpacked = false; + uint32_t m_unpackedWord = 0; + + // METHODS + VL_DEBUG_FUNC; // Declare debug() + +protected: + // VISITORS + virtual void visit(AstInitArray* nodep) override { + const AstUnpackArrayDType* const dtypep + = VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType); + UASSERT_OBJ(dtypep, nodep, "Array initializer has non-array dtype"); + const uint32_t size = dtypep->elementsConst(); + const uint32_t elemBytes = dtypep->subDTypep()->widthTotalBytes(); + const uint32_t tabMod = dtypep->subDTypep()->isString() ? 1 // String + : elemBytes <= 2 ? 8 // CData, SData + : elemBytes <= 4 ? 4 // IData + : elemBytes <= 8 ? 2 // QData + : 1; + VL_RESTORER(m_inUnpacked); + VL_RESTORER(m_unpackedWord); + m_inUnpacked = true; + // Note the double {{ initializer. The first { starts the initializer of the VlUnpacked, + // and the second starts the initializer of m_storage within the VlUnpacked. + puts("{"); + ofp()->putsNoTracking("{"); + puts("\n"); + for (uint32_t n = 0; n < size; ++n) { + m_unpackedWord = n; + if (n) puts(n % tabMod ? ", " : ",\n"); + iterate(nodep->getIndexDefaultedValuep(n)); + } + puts("\n"); + puts("}"); + ofp()->putsNoTracking("}"); + } + + virtual void visit(AstInitItem* nodep) override { // LCOV_EXCL_START + nodep->v3fatal("Handled by AstInitArray"); + } // LCOV_EXCL_STOP + + virtual void visit(AstConst* nodep) override { + const V3Number& num = nodep->num(); + UASSERT_OBJ(!num.isFourState(), nodep, "4-state value in constant pool"); + AstNodeDType* const dtypep = nodep->dtypep(); + if (num.isString()) { + // Note: putsQuoted does not track indentation, so we use this instead + puts("\""); + puts(num.toString()); + puts("\""); + } else if (dtypep->isWide()) { + const uint32_t size = dtypep->widthWords(); + // Note the double {{ initializer. The first { starts the initializer of the VlWide, + // and the second starts the initializer of m_storage within the VlWide. + puts("{"); + ofp()->putsNoTracking("{"); + if (m_inUnpacked) puts(" // VlWide " + cvtToStr(m_unpackedWord)); + puts("\n"); + for (uint32_t n = 0; n < size; ++n) { + if (n) puts(n % 4 ? ", " : ",\n"); + ofp()->printf("0x%08" PRIx32, num.edataWord(n)); + } + puts("\n"); + puts("}"); + ofp()->putsNoTracking("}"); + } else if (dtypep->isDouble()) { + const double dnum = num.toDouble(); + const char* const fmt + = !m_inUnpacked && (static_cast(dnum) == dnum && -1000 < dnum && dnum < 1000) + ? "%3.1f" // Force decimal point + : "%.17e"; // %e always yields a float literal + ofp()->printf(fmt, dnum); + } else if (dtypep->isQuad()) { + const uint64_t qnum = static_cast(num.toUQuad()); + const char* const fmt + = !m_inUnpacked && (qnum < 10) ? ("%" PRIx64 "ULL") : ("0x%016" PRIx64 "ULL"); + ofp()->printf(fmt, qnum); + } else { + const uint32_t unum = num.toUInt(); + const char* const fmt = !m_inUnpacked && (unum < 10) ? ("%" PRIu32 "U") + : (dtypep->widthMin() > 16) ? ("0x%08" PRIx32 "U") + : (dtypep->widthMin() > 8) ? ("0x%04" PRIx32 "U") + : ("0x%02" PRIx32 "U"); + ofp()->printf(fmt, unum); + } + } + + // Default + virtual void visit(AstNode* nodep) override { // LCOV_EXCL_START + nodep->v3fatalSrc("Unknown node type reached EmitCConstInit: " << nodep->prettyTypeName()); + } // LCOV_EXCL_STOP +}; diff --git a/src/V3EmitCConstPool.cpp b/src/V3EmitCConstPool.cpp index 589914a6e..4fa3b813c 100644 --- a/src/V3EmitCConstPool.cpp +++ b/src/V3EmitCConstPool.cpp @@ -18,7 +18,7 @@ #include "verilatedos.h" #include "V3EmitC.h" -#include "V3EmitCBase.h" +#include "V3EmitCConstInit.h" #include "V3File.h" #include "V3Global.h" #include "V3String.h" @@ -30,10 +30,8 @@ //###################################################################### // Const pool emitter -class EmitCConstPool final : EmitCBaseVisitor { +class EmitCConstPool final : public EmitCConstInit { // MEMBERS - bool m_inUnpacked = false; - uint32_t m_unpackedWord = 0; uint32_t m_outFileCount = 0; int m_outFileSize = 0; VDouble0 m_tablesEmitted; @@ -102,77 +100,9 @@ class EmitCConstPool final : EmitCBaseVisitor { } // VISITORS - virtual void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } - - virtual void visit(AstInitArray* nodep) override { - const AstUnpackArrayDType* const dtypep - = VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType); - UASSERT_OBJ(dtypep, nodep, "Array initializer has non-array dtype"); - const uint32_t size = dtypep->elementsConst(); - const uint32_t elemBytes = dtypep->subDTypep()->widthTotalBytes(); - const uint32_t tabMod = dtypep->subDTypep()->isString() ? 1 // String - : elemBytes <= 2 ? 8 // CData, SData - : elemBytes <= 4 ? 4 // IData - : elemBytes <= 8 ? 2 // QData - : 1; - VL_RESTORER(m_inUnpacked); - VL_RESTORER(m_unpackedWord); - m_inUnpacked = true; - // Note the double {{ initializer. The first { starts the initializer of the VlUnpacked, - // and the second starts the initializer of m_storage within the VlUnpacked. - puts("{"); - ofp()->putsNoTracking("{"); - puts("\n"); - for (uint32_t n = 0; n < size; ++n) { - m_unpackedWord = n; - if (n) puts(n % tabMod ? ", " : ",\n"); - iterate(nodep->getIndexDefaultedValuep(n)); - } - puts("\n"); - puts("}"); - ofp()->putsNoTracking("}"); - } - - virtual void visit(AstInitItem* nodep) override { // LCOV_EXCL_START - nodep->v3fatal("Handled by AstInitArray"); - } // LCOV_EXCL_END - virtual void visit(AstConst* nodep) override { - const V3Number& num = nodep->num(); - UASSERT_OBJ(!num.isFourState(), nodep, "4-state value in constant pool"); - AstNodeDType* const dtypep = nodep->dtypep(); - m_outFileSize += 1; - if (num.isString()) { - // Note: putsQuoted does not track indentation, so we use this instead - puts("\""); - puts(num.toString()); - puts("\""); - m_outFileSize += 9; - } else if (dtypep->isWide()) { - const uint32_t size = dtypep->widthWords(); - m_outFileSize += size - 1; - // Note the double {{ initializer. The first { starts the initializer of the VlWide, - // and the second starts the initializer of m_storage within the VlWide. - puts("{"); - ofp()->putsNoTracking("{"); - if (m_inUnpacked) puts(" // VlWide " + cvtToStr(m_unpackedWord)); - puts("\n"); - for (uint32_t n = 0; n < size; ++n) { - if (n) puts(n % 4 ? ", " : ",\n"); - ofp()->printf("0x%08" PRIx32, num.edataWord(n)); - } - puts("\n"); - puts("}"); - ofp()->putsNoTracking("}"); - } else if (dtypep->isQuad()) { - ofp()->printf("0x%016" PRIx64, static_cast(num.toUQuad())); - } else if (dtypep->widthMin() > 16) { - ofp()->printf("0x%08" PRIx32, num.toUInt()); - } else if (dtypep->widthMin() > 8) { - ofp()->printf("0x%04" PRIx32, num.toUInt()); - } else { - ofp()->printf("0x%02" PRIx32, num.toUInt()); - } + m_outFileSize += nodep->num().isString() ? 10 : nodep->isWide() ? nodep->widthWords() : 1; + EmitCConstInit::visit(nodep); } public: diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 7e63d8dc5..6f230ac57 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -19,7 +19,7 @@ #include "V3Global.h" #include "V3EmitC.h" -#include "V3EmitCFunc.h" +#include "V3EmitCConstInit.h" #include #include @@ -27,8 +27,10 @@ //###################################################################### // Internal EmitC implementation -class EmitCHeader final : public EmitCFunc { +class EmitCHeader final : public EmitCConstInit { // METHODS + VL_DEBUG_FUNC; // Declare debug() + void decorateFirst(bool& first, const string& str) { if (first) { putsDecoration(str);