Emit: Factor out visitor that can emit constant initializers
This is needed both by the V3EmitCConstPool emitter and the V3EmitCHeaders emitter.
This commit is contained in:
parent
bac84726e1
commit
cf39331d1f
|
|
@ -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 <cinttypes>
|
||||||
|
|
||||||
|
//######################################################################
|
||||||
|
// 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<int>(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<uint64_t>(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
|
||||||
|
};
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
#include "verilatedos.h"
|
#include "verilatedos.h"
|
||||||
|
|
||||||
#include "V3EmitC.h"
|
#include "V3EmitC.h"
|
||||||
#include "V3EmitCBase.h"
|
#include "V3EmitCConstInit.h"
|
||||||
#include "V3File.h"
|
#include "V3File.h"
|
||||||
#include "V3Global.h"
|
#include "V3Global.h"
|
||||||
#include "V3String.h"
|
#include "V3String.h"
|
||||||
|
|
@ -30,10 +30,8 @@
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Const pool emitter
|
// Const pool emitter
|
||||||
|
|
||||||
class EmitCConstPool final : EmitCBaseVisitor {
|
class EmitCConstPool final : public EmitCConstInit {
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
bool m_inUnpacked = false;
|
|
||||||
uint32_t m_unpackedWord = 0;
|
|
||||||
uint32_t m_outFileCount = 0;
|
uint32_t m_outFileCount = 0;
|
||||||
int m_outFileSize = 0;
|
int m_outFileSize = 0;
|
||||||
VDouble0 m_tablesEmitted;
|
VDouble0 m_tablesEmitted;
|
||||||
|
|
@ -102,77 +100,9 @@ class EmitCConstPool final : EmitCBaseVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// VISITORS
|
// 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 {
|
virtual void visit(AstConst* nodep) override {
|
||||||
const V3Number& num = nodep->num();
|
m_outFileSize += nodep->num().isString() ? 10 : nodep->isWide() ? nodep->widthWords() : 1;
|
||||||
UASSERT_OBJ(!num.isFourState(), nodep, "4-state value in constant pool");
|
EmitCConstInit::visit(nodep);
|
||||||
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<uint64_t>(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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#include "V3Global.h"
|
#include "V3Global.h"
|
||||||
#include "V3EmitC.h"
|
#include "V3EmitC.h"
|
||||||
#include "V3EmitCFunc.h"
|
#include "V3EmitCConstInit.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -27,8 +27,10 @@
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Internal EmitC implementation
|
// Internal EmitC implementation
|
||||||
|
|
||||||
class EmitCHeader final : public EmitCFunc {
|
class EmitCHeader final : public EmitCConstInit {
|
||||||
// METHODS
|
// METHODS
|
||||||
|
VL_DEBUG_FUNC; // Declare debug()
|
||||||
|
|
||||||
void decorateFirst(bool& first, const string& str) {
|
void decorateFirst(bool& first, const string& str) {
|
||||||
if (first) {
|
if (first) {
|
||||||
putsDecoration(str);
|
putsDecoration(str);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue