mirror of
https://github.com/verilator/verilator.git
synced 2024-12-29 10:47:34 +00:00
Add --protect-lib to create protected libraries, bug1490.
This commit is contained in:
parent
58a42834a6
commit
da0da9e258
2
Changes
2
Changes
@ -17,6 +17,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
* Verilator 4.020 2019-10-06
|
||||
|
||||
** Add --protect-lib, bug1490. [Todd Strader]
|
||||
|
||||
*** Support $fseek, $ftell, $frewind, bug1496. [Howard Su]
|
||||
|
||||
*** Add --public-flat-rw, bug1511. [Stefan Wallentowitz]
|
||||
|
@ -108,6 +108,7 @@ SUBDIRS = src test_regress \
|
||||
examples/make_hello_sc \
|
||||
examples/make_tracing_c \
|
||||
examples/make_tracing_sc \
|
||||
examples/make_protect_lib \
|
||||
|
||||
INFOS = README README.html README.pdf \
|
||||
verilator.txt verilator.html verilator.pdf
|
||||
@ -336,6 +337,7 @@ installdata:
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/make_hello_sc
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/make_tracing_c
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/make_tracing_sc
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/make_protect_lib
|
||||
cd $(srcdir) \
|
||||
; for p in $(VL_INST_DATA_SRCDIR_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||
@ -360,6 +362,7 @@ uninstall:
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/make_hello_sc
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/make_tracing_c
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/make_tracing_sc
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/make_protect_lib
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)
|
||||
-rmdir $(DESTDIR)$(pkgconfigdir)
|
||||
@ -492,7 +495,7 @@ clean mostlyclean distclean maintainer-clean::
|
||||
rm -f *.pg *.pgs *.toc *.tp *.tps *.vr *.vrs *.idx
|
||||
rm -f *.ev *.evs *.ov *.ovs *.cv *.cvs *.ma *.mas
|
||||
rm -f *.tex
|
||||
rm -rf examples/*/obj_dir examples/*/logs
|
||||
rm -rf examples/*/obj_dir* examples/*/logs
|
||||
rm -rf test_*/obj_dir
|
||||
rm -rf nodist/obj_dir
|
||||
|
||||
|
@ -256,6 +256,7 @@ The directories in the package directory are as follows:
|
||||
examples/make_hello_sc => Example GNU-make simple Verilog->SystemC conversion
|
||||
examples/make_tracing_c => Example GNU-make Verilog->C++ with tracing
|
||||
examples/make_tracing_sc => Example GNU-make Verilog->SystemC with tracing
|
||||
examples/make_protect_lib => Example using --protect-lib
|
||||
include/ => Files that should be in your -I compiler path
|
||||
include/verilated*.cpp => Global routines to link into your simulator
|
||||
include/verilated*.h => Global headers
|
||||
|
@ -354,6 +354,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
|
||||
--prof-threads Enable generating gantt chart data for threads
|
||||
--protect-key <key> Key for symbol protection
|
||||
--protect-ids Hash identifier names for obscurity
|
||||
--protect-lib <name> Create a DPI protected library
|
||||
--private Debugging; see docs
|
||||
--public Debugging; see docs
|
||||
--public-flat-rw Mark all variables, etc as public_flat_rw
|
||||
@ -1191,6 +1192,20 @@ of information disclosed, which is limited to the DPI function prototyptes.
|
||||
Use of the VPI is not recommended as many design details may be exposed,
|
||||
and an INSECURE warning will be issued.
|
||||
|
||||
=item --protect-lib I<name>
|
||||
|
||||
Produces C++, Verilog wrappers and a Makefile which can in turn produce a
|
||||
DPI library which can be used by Verilator or other simulators along with
|
||||
the corresponding Verilog wrapper. The Makefile will build both a static
|
||||
and dynamic version of the library named libI<name>.a and libI<name>.so
|
||||
respectively. This is done because some simulators require a dynamic
|
||||
library, but the static library is arguably easier to use if possible.
|
||||
--protect-lib implies --protect-ids.
|
||||
|
||||
This allows for the secure delivery of sensitive IP without the need for
|
||||
encrypted RTL (i.e. IEEE P1735). See examples/make_protect_lib in the
|
||||
distribution for a demonstration of how to build and use the DPI library.
|
||||
|
||||
=item --private
|
||||
|
||||
Opposite of --public. Is the default; this option exists for backwards
|
||||
@ -3230,6 +3245,12 @@ Verilator does not support SEREs yet. All assertion and coverage
|
||||
statements must be simple expressions that complete in one cycle.
|
||||
(Arguably SEREs are much of the point, but one must start somewhere.)
|
||||
|
||||
=head2 Encrypted Verilog
|
||||
|
||||
Open source simulators like Verilator are unable to use encrypted RTL
|
||||
(i.e. IEEE P1735). Talk to your IP vendor about delivering IP blocks
|
||||
via Verilator's --protect-lib feature.
|
||||
|
||||
=head2 Language Keyword Limitations
|
||||
|
||||
This section describes specific limitations for each language keyword.
|
||||
|
2
examples/make_protect_lib/.gitignore
vendored
Normal file
2
examples/make_protect_lib/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
obj_*
|
||||
logs
|
97
examples/make_protect_lib/Makefile
Normal file
97
examples/make_protect_lib/Makefile
Normal file
@ -0,0 +1,97 @@
|
||||
######################################################################
|
||||
#
|
||||
# DESCRIPTION: Verilator Example: --protect-lib Makefile
|
||||
#
|
||||
# This calls the object directory makefiles. That allows the objects to
|
||||
# be placed in the "current directory" which simplifies the Makefile.
|
||||
#
|
||||
# Copyright 2019 by Todd Strader. 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.
|
||||
#
|
||||
######################################################################
|
||||
# Check for sanity to avoid later confusion
|
||||
|
||||
ifneq ($(words $(CURDIR)),1)
|
||||
$(error Unsupported: GNU Make cannot build in directories containing spaces, build elsewhere: '$(CURDIR)')
|
||||
endif
|
||||
|
||||
######################################################################
|
||||
# Set up variables
|
||||
|
||||
# If $VERILATOR_ROOT isn't in the environment, we assume it is part of a
|
||||
# package install, and verilator is in your path. Otherwise find the
|
||||
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
|
||||
ifeq ($(VERILATOR_ROOT),)
|
||||
VERILATOR = verilator
|
||||
else
|
||||
export VERILATOR_ROOT
|
||||
VERILATOR = $(VERILATOR_ROOT)/bin/verilator
|
||||
endif
|
||||
|
||||
VERILATOR_FLAGS =
|
||||
# Generate C++
|
||||
VERILATOR_FLAGS += -cc
|
||||
# Optimize
|
||||
VERILATOR_FLAGS += -O2 -x-assign 0
|
||||
# Warn abount lint issues; may not want this on less solid designs
|
||||
VERILATOR_FLAGS += -Wall
|
||||
# Make waveforms
|
||||
TOP_VERILATOR_FLAGS = $(VERILATOR_FLAGS) --trace
|
||||
|
||||
######################################################################
|
||||
default: run
|
||||
|
||||
run:
|
||||
@echo
|
||||
@echo "-- Verilator --protect-lib example -_--------------------------"
|
||||
|
||||
@echo
|
||||
@echo "-- VERILATE secret module -------------------------------------"
|
||||
@echo " --protect-lib will produce both a static and shared library"
|
||||
@echo " In this example the static library is used, but some"
|
||||
@echo " simulators may require the shared library."
|
||||
@echo "---------------------------------------------------------------"
|
||||
$(VERILATOR) $(VERILATOR_FLAGS) --protect-lib verilated_secret -Mdir obj_dir_secret/ secret_impl.v
|
||||
|
||||
@echo
|
||||
@echo "-- COMPILE protected library ----------------------------------"
|
||||
@echo " This builds verilated_secret.sv, libverilated_secret.a and"
|
||||
@echo " libverilated_secret.so which can be distributed apart from"
|
||||
@echo " the source"
|
||||
@echo "---------------------------------------------------------------"
|
||||
$(MAKE) -j 4 -C obj_dir_secret -f Vsecret_impl.mk
|
||||
|
||||
@echo
|
||||
@echo "-- VERILATE top module ----------------------------------------"
|
||||
@echo " Use the SystemVerilog wrapper (verilated_secret.sv) and the"
|
||||
@echo " library (libverilated_secret.a) generated from the previous"
|
||||
@echo " step"
|
||||
@echo "---------------------------------------------------------------"
|
||||
$(VERILATOR) $(TOP_VERILATOR_FLAGS) --exe -LDFLAGS '-L../obj_dir_secret -lverilated_secret -static' top.v obj_dir_secret/verilated_secret.sv sim_main.cpp
|
||||
|
||||
@echo
|
||||
@echo "-- COMPILE entire design --------------------------------------"
|
||||
$(MAKE) -j 4 -C obj_dir -f Vtop.mk
|
||||
|
||||
@echo
|
||||
@echo "-- RUN --------------------------------------------------------"
|
||||
@mkdir -p logs
|
||||
obj_dir/Vtop +trace
|
||||
|
||||
@echo
|
||||
@echo "-- DONE -------------------------------------------------------"
|
||||
@echo "To see waveforms, open logs/vlt_dump.vcd in a waveform viewer"
|
||||
@echo
|
||||
|
||||
|
||||
######################################################################
|
||||
# Other targets
|
||||
|
||||
show-config:
|
||||
$(VERILATOR) -V
|
||||
|
||||
maintainer-copy::
|
||||
clean mostlyclean distclean maintainer-clean::
|
||||
-rm -rf obj_dir* logs *.log core
|
27
examples/make_protect_lib/secret_impl.v
Normal file
27
examples/make_protect_lib/secret_impl.v
Normal file
@ -0,0 +1,27 @@
|
||||
// DESCRIPTION: Verilator: --protect-lib example secret module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2019 by Todd Strader.
|
||||
|
||||
// This module will be used as libsecret.a or libsecret.so without
|
||||
// exposing the source.
|
||||
module secret_impl(
|
||||
input [31:0] a,
|
||||
input [31:0] b,
|
||||
output logic [31:0] x,
|
||||
input clk);
|
||||
|
||||
logic [31:0] accum_q = 0;
|
||||
logic [31:0] secret_value = 9;
|
||||
|
||||
initial $display("%m: initialized");
|
||||
|
||||
always @(posedge clk) begin
|
||||
accum_q <= accum_q + a;
|
||||
if (accum_q > 10)
|
||||
x <= b;
|
||||
else
|
||||
x <= a + b + secret_value;
|
||||
end
|
||||
|
||||
endmodule
|
72
examples/make_protect_lib/sim_main.cpp
Normal file
72
examples/make_protect_lib/sim_main.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
// DESCRIPTION: Verilator: --protect-lib example module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2019 by Todd Strader.
|
||||
//======================================================================
|
||||
|
||||
// See examples/tracing_c for notes on tracing
|
||||
|
||||
// Include common routines
|
||||
#include <verilated.h>
|
||||
|
||||
#include "Vtop.h"
|
||||
|
||||
#if VM_TRACE
|
||||
# include <verilated_vcd_c.h>
|
||||
#endif
|
||||
|
||||
vluint64_t main_time = 0;
|
||||
double sc_time_stamp() {
|
||||
return main_time;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv, char** env) {
|
||||
if (0 && argc && argv && env) {}
|
||||
|
||||
Verilated::debug(0);
|
||||
Verilated::randReset(2);
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Construct the Verilated model, including the secret module
|
||||
Vtop* top = new Vtop;
|
||||
|
||||
#if VM_TRACE
|
||||
// When tracing, the contents of the secret module will not be seen
|
||||
VerilatedVcdC* tfp = NULL;
|
||||
const char* flag = Verilated::commandArgsPlusMatch("trace");
|
||||
if (flag && 0==strcmp(flag, "+trace")) {
|
||||
Verilated::traceEverOn(true);
|
||||
VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n");
|
||||
tfp = new VerilatedVcdC;
|
||||
top->trace(tfp, 99);
|
||||
Verilated::mkdir("logs");
|
||||
tfp->open("logs/vlt_dump.vcd");
|
||||
}
|
||||
#endif
|
||||
|
||||
top->clk = 0;
|
||||
|
||||
// Simulate until $finish
|
||||
while (!Verilated::gotFinish()) {
|
||||
main_time++;
|
||||
top->clk = ~top->clk & 0x1;
|
||||
top->eval();
|
||||
#if VM_TRACE
|
||||
if (tfp) tfp->dump(main_time);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Final model cleanup
|
||||
top->final();
|
||||
|
||||
// Close trace if opened
|
||||
#if VM_TRACE
|
||||
if (tfp) { tfp->close(); tfp = NULL; }
|
||||
#endif
|
||||
|
||||
// Destroy model
|
||||
delete top; top = NULL;
|
||||
|
||||
// Fin
|
||||
exit(0);
|
||||
}
|
34
examples/make_protect_lib/top.v
Normal file
34
examples/make_protect_lib/top.v
Normal file
@ -0,0 +1,34 @@
|
||||
// DESCRIPTION: Verilator: --protect-lib example module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2019 by Todd Strader.
|
||||
|
||||
// See also the EXAMPLE section in the verilator manpage/document.
|
||||
module top (input clk);
|
||||
|
||||
integer cyc = 0;
|
||||
logic [31:0] a = 0;
|
||||
logic [31:0] b = 0;
|
||||
logic [31:0] x;
|
||||
|
||||
verilated_secret secret (.a, .b, .x, .clk);
|
||||
|
||||
always @(posedge clk) begin
|
||||
$display("[%0t] cyc=%0d a=%0d b=%0d x=%0d", $time, cyc, a, b, x);
|
||||
cyc <= cyc + 1;
|
||||
if (cyc == 0) begin
|
||||
a <= 5;
|
||||
b <= 7;
|
||||
end else if (cyc == 1) begin
|
||||
a <= 6;
|
||||
b <= 2;
|
||||
end else if (cyc == 2) begin
|
||||
a <= 1;
|
||||
b <= 9;
|
||||
end else if (cyc > 3) begin
|
||||
$display("Done");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
@ -221,6 +221,7 @@ RAW_OBJS = \
|
||||
V3Partition.o \
|
||||
V3PreShell.o \
|
||||
V3Premit.o \
|
||||
V3ProtectLib.o \
|
||||
V3Reloop.o \
|
||||
V3Scope.o \
|
||||
V3Scoreboard.o \
|
||||
|
@ -137,6 +137,8 @@ public:
|
||||
|
||||
if (v3Global.opt.exe()) {
|
||||
of.puts("default: "+v3Global.opt.exeName()+"\n");
|
||||
} else if (!v3Global.opt.protectLib().empty()) {
|
||||
of.puts("default: lib"+v3Global.opt.protectLib()+"\n");
|
||||
} else {
|
||||
of.puts("default: "+v3Global.opt.prefix()+"__ALL.a\n");
|
||||
}
|
||||
@ -168,6 +170,9 @@ public:
|
||||
|
||||
of.puts("# User CFLAGS (from -CFLAGS on Verilator command line)\n");
|
||||
of.puts("VM_USER_CFLAGS = \\\n");
|
||||
if (!v3Global.opt.protectLib().empty()) {
|
||||
of.puts("\t-fPIC \\\n");
|
||||
}
|
||||
const V3StringList& cFlags = v3Global.opt.cFlags();
|
||||
for (V3StringList::const_iterator it = cFlags.begin(); it != cFlags.end(); ++it) {
|
||||
of.puts("\t"+*it+" \\\n");
|
||||
@ -225,6 +230,24 @@ public:
|
||||
of.puts("\n");
|
||||
}
|
||||
|
||||
if (!v3Global.opt.protectLib().empty()) {
|
||||
of.puts("\n### Library rules... (from --protect-lib)\n");
|
||||
of.puts("# Using -fPIC objects for both static and dynamic libraries "
|
||||
"(which appears to work)\n");
|
||||
of.puts(v3Global.opt.protectLibName(false)+": $(VK_OBJS) $(VK_GLOBAL_OBJS)\n");
|
||||
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o "+
|
||||
v3Global.opt.protectLib()+".o "+v3Global.opt.protectLib()+".cpp\n");
|
||||
of.puts("\tar rc $@ $^ "+v3Global.opt.protectLib()+".o\n");
|
||||
of.puts("\n");
|
||||
|
||||
of.puts(v3Global.opt.protectLibName(true)+": $(VM_PREFIX)__ALL.a $(VK_GLOBAL_OBJS)\n");
|
||||
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ "+v3Global.opt.protectLib()+".cpp $^\n");
|
||||
of.puts("\n");
|
||||
|
||||
of.puts("lib"+v3Global.opt.protectLib()+": "+v3Global.opt.protectLibName(false)+
|
||||
" "+v3Global.opt.protectLibName(true)+"\n");
|
||||
}
|
||||
|
||||
of.puts("\n");
|
||||
of.putsHeader();
|
||||
}
|
||||
|
@ -594,7 +594,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
puts(" ");
|
||||
iterate(nodep->dtypep()); puts(" ");
|
||||
puts(nodep->prettyName());
|
||||
puts(";\n");
|
||||
if (!m_suppressVarSemi) puts(";\n"); else puts("\n");
|
||||
}
|
||||
virtual void visit(AstActive* nodep) {
|
||||
m_sensesp = nodep->sensesp();
|
||||
@ -617,9 +617,11 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
|
||||
public:
|
||||
bool m_suppressVarSemi; // Suppress emitting semicolon for AstVars
|
||||
explicit EmitVBaseVisitor(AstSenTree* domainp=NULL) {
|
||||
// Domain for printing one a ALWAYS under a ACTIVE
|
||||
m_suppressSemi = false;
|
||||
m_suppressVarSemi = false;
|
||||
m_sensesp = domainp;
|
||||
}
|
||||
virtual ~EmitVBaseVisitor() {}
|
||||
@ -639,9 +641,11 @@ class EmitVFileVisitor : public EmitVBaseVisitor {
|
||||
virtual void putqs(AstNode*, const string& str) { putbs(str); }
|
||||
virtual void putsNoTracking(const string& str) { ofp()->putsNoTracking(str); }
|
||||
public:
|
||||
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText=false) {
|
||||
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText=false,
|
||||
bool suppressVarSemi=false) {
|
||||
m_ofp = ofp;
|
||||
m_trackText = trackText;
|
||||
m_suppressVarSemi = suppressVarSemi;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~EmitVFileVisitor() {}
|
||||
@ -779,7 +783,7 @@ void V3EmitV::emitvFiles() {
|
||||
if (vfilep && vfilep->tblockp()) {
|
||||
V3OutVFile of(vfilep->name());
|
||||
of.puts("// DESCR" "IPTION: Verilator generated Verilog\n");
|
||||
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true);
|
||||
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -921,6 +921,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
shift;
|
||||
m_outputSplitCTrace = atoi(argv[i]);
|
||||
}
|
||||
else if (!strcmp(sw, "-protect-lib") && (i+1)<argc) {
|
||||
shift; m_protectLib = argv[i];
|
||||
m_protectIds = true;
|
||||
}
|
||||
else if (!strcmp(sw, "-trace-fst")) {
|
||||
m_trace = true;
|
||||
m_traceFormat = TraceFormat::FST;
|
||||
|
@ -191,6 +191,7 @@ class V3Options {
|
||||
string m_pipeFilter; // main switch: --pipe-filter
|
||||
string m_prefix; // main switch: --prefix
|
||||
string m_protectKey; // main switch: --protect-key
|
||||
string m_protectLib; // main switch: --protect-lib {lib_name}
|
||||
string m_topModule; // main switch: --top-module
|
||||
string m_unusedRegexp; // main switch: --unused-regexp
|
||||
string m_xAssign; // main switch: --x-assign
|
||||
@ -358,6 +359,16 @@ class V3Options {
|
||||
string prefix() const { return m_prefix; }
|
||||
string protectKey() const { return m_protectKey; }
|
||||
string protectKeyDefaulted(); // Set default key if not set by user
|
||||
string protectLib() const { return m_protectLib; }
|
||||
string protectLibName(bool shared) {
|
||||
string libName = "lib"+protectLib();
|
||||
if (shared) {
|
||||
libName += ".so";
|
||||
} else {
|
||||
libName += ".a";
|
||||
}
|
||||
return libName;
|
||||
}
|
||||
string topModule() const { return m_topModule; }
|
||||
string unusedRegexp() const { return m_unusedRegexp; }
|
||||
string xAssign() const { return m_xAssign; }
|
||||
|
453
src/V3ProtectLib.cpp
Normal file
453
src/V3ProtectLib.cpp
Normal file
@ -0,0 +1,453 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Build DPI protected C++ and SV
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2019 by Todd Strader. 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3String.h"
|
||||
#include "V3ProtectLib.h"
|
||||
#include "V3File.h"
|
||||
#include "V3Hashed.h"
|
||||
#include "V3Task.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
|
||||
//######################################################################
|
||||
// ProtectLib top-level visitor
|
||||
|
||||
class ProtectVisitor : public AstNVisitor {
|
||||
private:
|
||||
AstVFile* m_vfilep; // DPI-enabled Verilog wrapper
|
||||
AstCFile* m_cfilep; // C implementation of DPI functions
|
||||
// Verilog text blocks
|
||||
AstTextBlock* m_modPortsp; // Module port list
|
||||
AstTextBlock* m_comboPortsp; // Combo function port list
|
||||
AstTextBlock* m_seqPortsp; // Sequential function port list
|
||||
AstTextBlock* m_comboIgnorePortsp; // Combo ignore function port list
|
||||
AstTextBlock* m_comboDeclsp; // Combo signal declaration list
|
||||
AstTextBlock* m_seqDeclsp; // Sequential signal declaration list
|
||||
AstTextBlock* m_tmpDeclsp; // Temporary signal declaration list
|
||||
AstTextBlock* m_hashValuep; // CPP hash value
|
||||
AstTextBlock* m_comboParamsp; // Combo function parameter list
|
||||
AstTextBlock* m_clkSensp; // Clock sensitivity list
|
||||
AstTextBlock* m_comboIgnoreParamsp; // Combo ignore parameter list
|
||||
AstTextBlock* m_seqParamsp; // Sequential parameter list
|
||||
AstTextBlock* m_nbAssignsp; // Non-blocking assignment list
|
||||
AstTextBlock* m_seqAssignsp; // Sequential assignment list
|
||||
AstTextBlock* m_comboAssignsp; // Combo assignment list
|
||||
// C text blocks
|
||||
AstTextBlock* m_cHashValuep; // CPP hash value
|
||||
AstTextBlock* m_cComboParamsp; // Combo function parameter list
|
||||
AstTextBlock* m_cComboInsp; // Combo input copy list
|
||||
AstTextBlock* m_cComboOutsp; // Combo output copy list
|
||||
AstTextBlock* m_cSeqParamsp; // Sequential parameter list
|
||||
AstTextBlock* m_cSeqClksp; // Sequential clock copy list
|
||||
AstTextBlock* m_cSeqOutsp; // Sequential output copy list
|
||||
AstTextBlock* m_cIgnoreParamsp; // Combo ignore parameter list
|
||||
string m_libName;
|
||||
string m_topName;
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
m_vfilep = new AstVFile(nodep->fileline(),
|
||||
v3Global.opt.makeDir()+"/"+m_libName+".sv");
|
||||
nodep->addFilesp(m_vfilep);
|
||||
m_cfilep = new AstCFile(nodep->fileline(),
|
||||
v3Global.opt.makeDir()+"/"+m_libName+".cpp");
|
||||
nodep->addFilesp(m_cfilep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
UASSERT_OBJ(!nodep->nextp(), nodep, "Multiple root modules");
|
||||
FileLine* fl = nodep->fileline();
|
||||
createSvFile(fl);
|
||||
createCppFile(fl);
|
||||
|
||||
iterateChildren(nodep);
|
||||
|
||||
V3Hash hash = V3Hashed::uncachedHash(m_cfilep);
|
||||
m_hashValuep->addText(fl, cvtToStr(hash.fullValue())+";\n");
|
||||
m_cHashValuep->addText(fl, cvtToStr(hash.fullValue())+";\n");
|
||||
}
|
||||
|
||||
void addComment(AstTextBlock* txtp, FileLine* fl, const string& comment) {
|
||||
txtp->addNodep(new AstComment(fl, comment));
|
||||
}
|
||||
|
||||
void hashComment(AstTextBlock* txtp, FileLine* fl) {
|
||||
addComment(txtp, fl, "Checks to make sure the .sv wrapper and library agree");
|
||||
}
|
||||
|
||||
void initialComment(AstTextBlock* txtp, FileLine* fl) {
|
||||
addComment(txtp, fl, "Creates an instance of the secret module at initial-time");
|
||||
addComment(txtp, fl, "(one for each instance in the user's design) also evaluates");
|
||||
addComment(txtp, fl, "the secret module's initial process");
|
||||
}
|
||||
|
||||
void comboComment(AstTextBlock* txtp, FileLine* fl) {
|
||||
addComment(txtp, fl, "Updates all non-clock inputs and retrieves the results");
|
||||
}
|
||||
|
||||
void seqComment(AstTextBlock* txtp, FileLine* fl) {
|
||||
addComment(txtp, fl, "Updates all clocks and retrieves the results");
|
||||
}
|
||||
|
||||
void comboIgnoreComment(AstTextBlock* txtp, FileLine* fl) {
|
||||
addComment(txtp, fl, "Need to convince some simulators that the input to the module");
|
||||
addComment(txtp, fl, "must be evaluated before evaluating the clock edge");
|
||||
}
|
||||
|
||||
void finalComment(AstTextBlock* txtp, FileLine* fl) {
|
||||
addComment(txtp, fl, "Evaluates the secret module's final process");
|
||||
}
|
||||
|
||||
void createSvFile(FileLine* fl) {
|
||||
// Comments
|
||||
AstTextBlock* txtp = new AstTextBlock(fl);
|
||||
addComment(txtp, fl, "Wrapper module for DPI protected library");
|
||||
addComment(txtp, fl, "This module requires lib"+m_libName+
|
||||
".a or lib"+m_libName+".so to work");
|
||||
addComment(txtp, fl, "See instructions in your simulator for how"
|
||||
" to use DPI libraries\n");
|
||||
|
||||
// Module declaration
|
||||
m_modPortsp = new AstTextBlock(fl, "module "+m_libName+" (\n", false, true);
|
||||
txtp->addNodep(m_modPortsp);
|
||||
txtp->addText(fl, ");\n\n");
|
||||
|
||||
// DPI declarations
|
||||
hashComment(txtp, fl);
|
||||
txtp->addText(fl, "import \"DPI-C\" function void "+
|
||||
m_libName+"_protectlib_check_hash (int protectlib_hash__V);\n\n");
|
||||
initialComment(txtp, fl);
|
||||
txtp->addText(fl, "import \"DPI-C\" function chandle "+
|
||||
m_libName+"_protectlib_create (string scope__V);\n\n");
|
||||
comboComment(txtp, fl);
|
||||
m_comboPortsp = new AstTextBlock(fl, "import \"DPI-C\" function longint "+
|
||||
m_libName+"_protectlib_combo_update "
|
||||
"(\n", false, true);
|
||||
m_comboPortsp->addText(fl, "chandle handle__V\n");
|
||||
txtp->addNodep(m_comboPortsp);
|
||||
txtp->addText(fl, ");\n\n");
|
||||
seqComment(txtp, fl);
|
||||
m_seqPortsp = new AstTextBlock(fl, "import \"DPI-C\" function longint "+
|
||||
m_libName+"_protectlib_seq_update "
|
||||
"(\n", false, true);
|
||||
m_seqPortsp->addText(fl, "chandle handle__V\n");
|
||||
txtp->addNodep(m_seqPortsp);
|
||||
txtp->addText(fl, ");\n\n");
|
||||
comboIgnoreComment(txtp, fl);
|
||||
m_comboIgnorePortsp = new AstTextBlock(fl, "import \"DPI-C\" function void "+
|
||||
m_libName+"_protectlib_combo_ignore "
|
||||
"(\n", false, true);
|
||||
m_comboIgnorePortsp->addText(fl, "chandle handle__V\n");
|
||||
txtp->addNodep(m_comboIgnorePortsp);
|
||||
txtp->addText(fl, ");\n\n");
|
||||
finalComment(txtp, fl);
|
||||
txtp->addText(fl, "import \"DPI-C\" function void "+
|
||||
m_libName+"_protectlib_final (chandle handle__V);\n\n");
|
||||
|
||||
// Local variables
|
||||
txtp->addText(fl, "chandle handle__V;\n\n");
|
||||
m_comboDeclsp = new AstTextBlock(fl);
|
||||
txtp->addNodep(m_comboDeclsp);
|
||||
m_seqDeclsp = new AstTextBlock(fl);
|
||||
txtp->addNodep(m_seqDeclsp);
|
||||
m_tmpDeclsp = new AstTextBlock(fl);
|
||||
txtp->addNodep(m_tmpDeclsp);
|
||||
txtp->addText(fl, "\ntime last_combo_seqnum__V;\n");
|
||||
txtp->addText(fl, "time last_seq_seqnum__V;\n\n");
|
||||
|
||||
// CPP hash value
|
||||
addComment(txtp, fl, "Hash value to make sure this file and the corresponding");
|
||||
addComment(txtp, fl, "library agree");
|
||||
m_hashValuep = new AstTextBlock(fl, "localparam int protectlib_hash__V =\n");
|
||||
txtp->addNodep(m_hashValuep);
|
||||
txtp->addText(fl, "\n");
|
||||
|
||||
// Initial
|
||||
txtp->addText(fl, "initial begin\n");
|
||||
txtp->addText(fl, m_libName+"_protectlib_check_hash(protectlib_hash__V);\n");
|
||||
txtp->addText(fl, "handle__V = "+m_libName+"_protectlib_create"
|
||||
"($sformatf(\"%m\"));\n");
|
||||
txtp->addText(fl, "end\n\n");
|
||||
|
||||
// Combinatorial process
|
||||
addComment(txtp, fl, "Combinatorialy evaluate changes to inputs");
|
||||
m_comboParamsp = new AstTextBlock(fl, "always @(*) begin\n"
|
||||
"last_combo_seqnum__V = "+
|
||||
m_libName+"_protectlib_combo_update(\n",
|
||||
false, true);
|
||||
m_comboParamsp->addText(fl, "handle__V\n");
|
||||
txtp->addNodep(m_comboParamsp);
|
||||
txtp->addText(fl, ");\n");
|
||||
txtp->addText(fl, "end\n\n");
|
||||
|
||||
// Sequential process
|
||||
addComment(txtp, fl, "Evaluate clock edges");
|
||||
m_clkSensp = new AstTextBlock(fl, "always @(", false, true);
|
||||
txtp->addNodep(m_clkSensp);
|
||||
txtp->addText(fl, ") begin\n");
|
||||
m_comboIgnoreParamsp = new AstTextBlock(fl, m_libName+"_protectlib_combo_ignore(\n",
|
||||
false, true);
|
||||
m_comboIgnoreParamsp->addText(fl, "handle__V\n");
|
||||
txtp->addNodep(m_comboIgnoreParamsp);
|
||||
txtp->addText(fl, ");\n");
|
||||
m_seqParamsp = new AstTextBlock(fl, "last_seq_seqnum__V <= "+m_libName+
|
||||
"_protectlib_seq_update(\n",
|
||||
false, true);
|
||||
m_seqParamsp->addText(fl, "handle__V\n");
|
||||
txtp->addNodep(m_seqParamsp);
|
||||
txtp->addText(fl, ");\n");
|
||||
m_nbAssignsp = new AstTextBlock(fl);
|
||||
txtp->addNodep(m_nbAssignsp);
|
||||
txtp->addText(fl, "end\n\n");
|
||||
|
||||
// Select between combinatorial and sequential results
|
||||
addComment(txtp, fl, "Select between combinatorial and sequential results");
|
||||
txtp->addText(fl, "always @(*) begin\n");
|
||||
m_seqAssignsp = new AstTextBlock(fl, "if (last_seq_seqnum__V > "
|
||||
"last_combo_seqnum__V) begin\n");
|
||||
txtp->addNodep(m_seqAssignsp);
|
||||
m_comboAssignsp = new AstTextBlock(fl, "end else begin\n");
|
||||
txtp->addNodep(m_comboAssignsp);
|
||||
txtp->addText(fl, "end\n");
|
||||
txtp->addText(fl, "end\n\n");
|
||||
|
||||
// Final
|
||||
txtp->addText(fl, "final "+m_libName+"_protectlib_final(handle__V);\n\n");
|
||||
|
||||
txtp->addText(fl, "endmodule\n");
|
||||
m_vfilep->tblockp(txtp);
|
||||
}
|
||||
|
||||
void castPtr(FileLine* fl, AstTextBlock* txtp) {
|
||||
txtp->addText(fl, m_topName+"_container* handlep__V = "
|
||||
"static_cast<"+m_topName+"_container*>(vhandlep__V);\n");
|
||||
}
|
||||
|
||||
void createCppFile(FileLine* fl) {
|
||||
// Comments
|
||||
AstTextBlock* txtp = new AstTextBlock(fl);
|
||||
addComment(txtp, fl, "Wrapper functions for DPI protected library\n");
|
||||
|
||||
// Includes
|
||||
txtp->addText(fl, "#include \""+m_topName+".h\"\n");
|
||||
txtp->addText(fl, "#include \"verilated_dpi.h\"\n\n");
|
||||
txtp->addText(fl, "#include <cstdio>\n");
|
||||
txtp->addText(fl, "#include <cstdlib>\n\n");
|
||||
|
||||
// Verilated module plus sequence number
|
||||
addComment(txtp, fl, "Container class to house verilated object and sequence number");
|
||||
txtp->addText(fl, "class "+m_topName+"_container: public "+m_topName+" {\n");
|
||||
txtp->addText(fl, "public:\n");
|
||||
txtp->addText(fl, "long long m_seqnum;\n");
|
||||
txtp->addText(fl, m_topName+"_container(const char* scopep__V):\n");
|
||||
txtp->addText(fl, m_topName+"(scopep__V) {}\n");
|
||||
txtp->addText(fl, "};\n\n");
|
||||
|
||||
// Extern C
|
||||
txtp->addText(fl, "extern \"C\" {\n\n");
|
||||
|
||||
// Hash check
|
||||
hashComment(txtp, fl);
|
||||
txtp->addText(fl, "void "+m_libName+"_protectlib_check_hash"
|
||||
" (int protectlib_hash__V) {\n");
|
||||
m_cHashValuep = new AstTextBlock(fl, "int expected_hash__V =\n");
|
||||
txtp->addNodep(m_cHashValuep);
|
||||
txtp->addText(fl, "if (protectlib_hash__V != expected_hash__V) {\n");
|
||||
txtp->addText(fl, "fprintf(stderr, \"%%Error: cannot use "+m_libName+" library, "
|
||||
"Verliog (%u) and library (%u) hash values do not "
|
||||
"agree\\n\", protectlib_hash__V, expected_hash__V);\n");
|
||||
txtp->addText(fl, "exit(EXIT_FAILURE);\n");
|
||||
txtp->addText(fl, "}\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
|
||||
// Initial
|
||||
initialComment(txtp, fl);
|
||||
txtp->addText(fl, "void* "+m_libName+"_protectlib_create"
|
||||
" (const char* scopep__V) {\n");
|
||||
txtp->addText(fl, m_topName+"_container* handlep__V = "
|
||||
"new "+m_topName+"_container(scopep__V);\n");
|
||||
txtp->addText(fl, "return handlep__V;\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
|
||||
// Updates
|
||||
comboComment(txtp, fl);
|
||||
m_cComboParamsp = new AstTextBlock(fl, "long long "+m_libName+"_protectlib_combo_update (\n",
|
||||
false, true);
|
||||
m_cComboParamsp->addText(fl, "void* vhandlep__V\n");
|
||||
txtp->addNodep(m_cComboParamsp);
|
||||
txtp->addText(fl, ")\n");
|
||||
m_cComboInsp = new AstTextBlock(fl, "{\n");
|
||||
castPtr(fl, m_cComboInsp);
|
||||
txtp->addNodep(m_cComboInsp);
|
||||
m_cComboOutsp = new AstTextBlock(fl, "handlep__V->eval();\n");
|
||||
txtp->addNodep(m_cComboOutsp);
|
||||
txtp->addText(fl, "return handlep__V->m_seqnum++;\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
|
||||
seqComment(txtp, fl);
|
||||
m_cSeqParamsp = new AstTextBlock(fl, "long long "+m_libName+"_protectlib_seq_update (\n",
|
||||
false, true);
|
||||
m_cSeqParamsp->addText(fl, "void* vhandlep__V\n");
|
||||
txtp->addNodep(m_cSeqParamsp);
|
||||
txtp->addText(fl, ")\n");
|
||||
m_cSeqClksp = new AstTextBlock(fl, "{\n");
|
||||
castPtr(fl, m_cSeqClksp);
|
||||
txtp->addNodep(m_cSeqClksp);
|
||||
m_cSeqOutsp = new AstTextBlock(fl, "handlep__V->eval();\n");
|
||||
txtp->addNodep(m_cSeqOutsp);
|
||||
txtp->addText(fl, "return handlep__V->m_seqnum++;\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
|
||||
comboIgnoreComment(txtp, fl);
|
||||
m_cIgnoreParamsp = new AstTextBlock(fl, "void "+m_libName+"_protectlib_combo_ignore (\n",
|
||||
false, true);
|
||||
m_cIgnoreParamsp->addText(fl, "void* vhandlep__V\n");
|
||||
txtp->addNodep(m_cIgnoreParamsp);
|
||||
txtp->addText(fl, ")\n");
|
||||
txtp->addText(fl, "{ }\n\n");
|
||||
|
||||
// Final
|
||||
finalComment(txtp, fl);
|
||||
txtp->addText(fl, "void "+m_libName+"_protectlib_final (void* vhandlep__V) {\n");
|
||||
castPtr(fl, txtp);
|
||||
txtp->addText(fl, "handlep__V->final();\n");
|
||||
txtp->addText(fl, "delete handlep__V;\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
|
||||
txtp->addText(fl, "}\n");
|
||||
m_cfilep->tblockp(txtp);
|
||||
}
|
||||
|
||||
virtual void visit(AstVar* nodep) {
|
||||
if (!nodep->isIO()) return;
|
||||
if (VN_IS(nodep->dtypep(), UnpackArrayDType)) {
|
||||
nodep->v3fatalSrc("Unsupported: unpacked arrays with protect-lib");
|
||||
}
|
||||
if (nodep->direction() == VDirection::INPUT) {
|
||||
if (nodep->isUsedClock()) {
|
||||
handleClock(nodep);
|
||||
} else {
|
||||
handleDataInput(nodep);
|
||||
}
|
||||
} else if (nodep->direction() == VDirection::OUTPUT) {
|
||||
handleOutput(nodep);
|
||||
} else {
|
||||
nodep->v3fatalSrc("Unsupported port direction for protect-lib: "<<
|
||||
nodep->direction().ascii());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep) { }
|
||||
|
||||
string cInputConnection(AstVar* varp) {
|
||||
string frstmt;
|
||||
bool useSetWSvlv = V3Task::dpiToInternalFrStmt(varp, varp->name(), true, frstmt);
|
||||
if (useSetWSvlv) {
|
||||
return frstmt+" handlep__V->"+varp->name()+", "+varp->name()+");\n";
|
||||
}
|
||||
return "handlep__V->"+varp->name()+" = "+frstmt+";\n";
|
||||
}
|
||||
|
||||
void handleClock(AstVar* varp) {
|
||||
FileLine* fl = varp->fileline();
|
||||
handleInput(varp);
|
||||
m_seqPortsp->addNodep(varp->cloneTree(false));
|
||||
m_seqParamsp->addText(fl, varp->name()+"\n");
|
||||
m_clkSensp->addText(fl, "edge("+varp->name()+")");
|
||||
m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
|
||||
m_cSeqClksp->addText(fl, cInputConnection(varp));
|
||||
}
|
||||
|
||||
void handleDataInput(AstVar* varp) {
|
||||
FileLine* fl = varp->fileline();
|
||||
handleInput(varp);
|
||||
m_comboPortsp->addNodep(varp->cloneTree(false));
|
||||
m_comboParamsp->addText(fl, varp->name()+"\n");
|
||||
m_comboIgnorePortsp->addNodep(varp->cloneTree(false));
|
||||
m_comboIgnoreParamsp->addText(fl, varp->name()+"\n");
|
||||
m_cComboParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
|
||||
m_cComboInsp->addText(fl, cInputConnection(varp));
|
||||
m_cIgnoreParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
|
||||
}
|
||||
|
||||
void handleInput(AstVar* varp) {
|
||||
FileLine* fl = varp->fileline();
|
||||
m_modPortsp->addNodep(varp->cloneTree(false));
|
||||
}
|
||||
|
||||
void handleOutput(AstVar* varp) {
|
||||
FileLine* fl = varp->fileline();
|
||||
m_modPortsp->addNodep(varp->cloneTree(false));
|
||||
m_comboPortsp->addNodep(varp->cloneTree(false));
|
||||
m_comboParamsp->addText(fl, varp->name()+"_combo__V\n");
|
||||
m_seqPortsp->addNodep(varp->cloneTree(false));
|
||||
m_seqParamsp->addText(fl, varp->name()+"_tmp__V\n");
|
||||
|
||||
AstNodeDType* comboDtypep = varp->dtypep()->cloneTree(false);
|
||||
m_comboDeclsp->addNodep(comboDtypep);
|
||||
m_comboDeclsp->addText(fl, " "+varp->name()+"_combo__V;\n");
|
||||
|
||||
AstNodeDType* seqDtypep = varp->dtypep()->cloneTree(false);
|
||||
m_seqDeclsp->addNodep(seqDtypep);
|
||||
m_seqDeclsp->addText(fl, " "+varp->name()+"_seq__V;\n");
|
||||
|
||||
AstNodeDType* tmpDtypep = varp->dtypep()->cloneTree(false);
|
||||
m_tmpDeclsp->addNodep(tmpDtypep);
|
||||
m_tmpDeclsp->addText(fl, " "+varp->name()+"_tmp__V;\n");
|
||||
|
||||
m_nbAssignsp->addText(fl, varp->name()+"_seq__V <= "+varp->name()+"_tmp__V;\n");
|
||||
m_seqAssignsp->addText(fl, varp->name()+" = "+varp->name()+"_seq__V;\n");
|
||||
m_comboAssignsp->addText(fl, varp->name()+" = "+varp->name()+"_combo__V;\n");
|
||||
m_cComboParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
|
||||
m_cComboOutsp->addText(fl, V3Task::assignInternalToDpi(varp, false, true, "", "",
|
||||
"handlep__V->"));
|
||||
m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
|
||||
m_cSeqOutsp->addText(fl, V3Task::assignInternalToDpi(varp, false, true, "", "",
|
||||
"handlep__V->"));
|
||||
}
|
||||
|
||||
public:
|
||||
explicit ProtectVisitor(AstNode* nodep):
|
||||
m_vfilep(NULL), m_cfilep(NULL), m_modPortsp(NULL),
|
||||
m_comboPortsp(NULL), m_seqPortsp(NULL), m_comboIgnorePortsp(NULL), m_comboDeclsp(NULL),
|
||||
m_seqDeclsp(NULL), m_tmpDeclsp(NULL), m_hashValuep(NULL), m_clkSensp(NULL),
|
||||
m_comboIgnoreParamsp(NULL), m_seqParamsp(NULL), m_nbAssignsp(NULL), m_seqAssignsp(NULL),
|
||||
m_comboAssignsp(NULL), m_cHashValuep(NULL), m_cComboParamsp(NULL), m_cComboInsp(NULL),
|
||||
m_cComboOutsp(NULL), m_cSeqParamsp(NULL), m_cSeqClksp(NULL), m_cSeqOutsp(NULL),
|
||||
m_cIgnoreParamsp(NULL), m_libName(v3Global.opt.protectLib()),
|
||||
m_topName(v3Global.opt.prefix())
|
||||
{
|
||||
iterate(nodep);
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// ProtectLib class functions
|
||||
|
||||
void V3ProtectLib::protect() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ProtectVisitor visitor(v3Global.rootp());
|
||||
}
|
37
src/V3ProtectLib.h
Normal file
37
src/V3ProtectLib.h
Normal file
@ -0,0 +1,37 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Buitd DPI protected C++ and SV
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2019 by Todd Strader. 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3PROTECTLIB_H_
|
||||
#define _V3PROTECTLIB_H_ 1
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3ProtectLib {
|
||||
public:
|
||||
static void protect();
|
||||
};
|
||||
|
||||
#endif // Guard
|
146
src/V3Task.cpp
146
src/V3Task.cpp
@ -614,42 +614,7 @@ private:
|
||||
|
||||
AstNode* createAssignInternalToDpi(AstVar* portp, bool isRtn, bool isPtr,
|
||||
const string& frSuffix, const string& toSuffix) {
|
||||
// Create assignment from internal format into DPI temporary
|
||||
bool bitvec = (portp->basicp()->keyword().isDpiBitVal() && portp->width() > 32);
|
||||
bool logicvec = (portp->basicp()->keyword().isDpiLogicVal() && portp->width() > 1);
|
||||
if (isRtn && (bitvec || logicvec)) {
|
||||
portp->v3error("DPI functions cannot return > 32 bits or four-state;"
|
||||
" use a two-state type or task instead: "<<portp->prettyNameQ());
|
||||
// Code below works, but won't compile right, and IEEE illegal
|
||||
}
|
||||
string stmt;
|
||||
string ket;
|
||||
// Someday we'll have better type support, and this can make variables and casts.
|
||||
// But for now, we'll just text-bash it.
|
||||
if (bitvec) {
|
||||
if (portp->isWide()) {
|
||||
stmt += ("VL_SET_SVBV_W("+cvtToStr(portp->width())
|
||||
+", "+portp->name()+toSuffix+", "+portp->name()+frSuffix+")");
|
||||
} else {
|
||||
stmt += "VL_SET_WQ("+portp->name()+toSuffix+", "+portp->name()+frSuffix+")";
|
||||
}
|
||||
} else if (logicvec) {
|
||||
stmt += ("VL_SET_SVLV_" + string(portp->dtypep()->charIQWN()) + "("
|
||||
+ cvtToStr(portp->width())
|
||||
+ ", "+portp->name()+toSuffix+", "+portp->name()+frSuffix+")");
|
||||
} else {
|
||||
if (isPtr) stmt += "*"; // DPI outputs are pointers
|
||||
stmt += portp->name()+toSuffix+" = ";
|
||||
if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::CHANDLE) {
|
||||
stmt += "VL_CVT_Q_VP(";
|
||||
ket += ")";
|
||||
}
|
||||
stmt += portp->name()+frSuffix;
|
||||
if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::STRING) {
|
||||
stmt += ".c_str()";
|
||||
}
|
||||
}
|
||||
stmt += ket + ";\n";
|
||||
string stmt = V3Task::assignInternalToDpi(portp, isRtn, isPtr, frSuffix, toSuffix);
|
||||
return new AstCStmt(portp->fileline(), stmt);
|
||||
}
|
||||
|
||||
@ -657,38 +622,13 @@ private:
|
||||
// Create assignment from DPI temporary into internal format
|
||||
AstVar* portp = portvscp->varp();
|
||||
string frstmt;
|
||||
if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::CHANDLE) {
|
||||
frstmt = "VL_CVT_VP_Q("+frName+")";
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiBitVal()
|
||||
&& portp->width() != 1 && portp->isQuad()) {
|
||||
// SV is vector, Verilator isn't
|
||||
frstmt = "VL_SET_QW("+frName+")";
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiLogicVal()
|
||||
&& portp->width() != 1 && portp->isQuad()) {
|
||||
frstmt = "VL_SET_Q_SVLV("+frName+")";
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiLogicVal()
|
||||
&& portp->width() != 1 && !portp->isWide()) {
|
||||
frstmt = "VL_SET_I_SVLV("+frName+")";
|
||||
}
|
||||
else if (!cvt
|
||||
&& portp->basicp() && portp->basicp()->keyword().isDpiBitVal()
|
||||
&& portp->width() != 1 && !portp->isWide()) {
|
||||
frstmt = "*"+frName; // it's a svBitVecVal, which other code won't think is arrayed (as WData aren't), but really is
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiLogicVal()
|
||||
&& portp->width() != 1 && portp->isWide()) {
|
||||
// Need to convert to wide, using special function
|
||||
AstNode* linesp = new AstText(portp->fileline(), "VL_SET_W_SVLV("+cvtToStr(portp->width()) + ",");
|
||||
bool useSetWSvlv = V3Task::dpiToInternalFrStmt(portp, frName, cvt, frstmt);
|
||||
if (useSetWSvlv) {
|
||||
AstNode* linesp = new AstText(portp->fileline(), frstmt);
|
||||
linesp->addNext(new AstVarRef(portp->fileline(), portvscp, true));
|
||||
linesp->addNext(new AstText(portp->fileline(), ","+frName+");"));
|
||||
return new AstCStmt(portp->fileline(), linesp);
|
||||
}
|
||||
else {
|
||||
frstmt = frName;
|
||||
}
|
||||
// Use a AstCMath, as we want V3Clean to mask off bits that don't make sense.
|
||||
int cwidth = VL_WORDSIZE;
|
||||
if (portp->basicp()) cwidth = portp->basicp()->keyword().width();
|
||||
@ -1495,6 +1435,84 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
|
||||
return tconnects;
|
||||
}
|
||||
|
||||
string V3Task::assignInternalToDpi(AstVar* portp, bool isRtn, bool isPtr,
|
||||
const string& frSuffix, const string& toSuffix,
|
||||
const string& frPrefix) {
|
||||
// Create assignment from internal format into DPI temporary
|
||||
bool bitvec = (portp->basicp()->keyword().isDpiBitVal() && portp->width() > 32);
|
||||
bool logicvec = (portp->basicp()->keyword().isDpiLogicVal() && portp->width() > 1);
|
||||
if (isRtn && (bitvec || logicvec)) {
|
||||
portp->v3error("DPI functions cannot return > 32 bits or four-state;"
|
||||
" use a two-state type or task instead: "<<portp->prettyNameQ());
|
||||
// Code below works, but won't compile right, and IEEE illegal
|
||||
}
|
||||
string stmt;
|
||||
string ket;
|
||||
// Someday we'll have better type support, and this can make variables and casts.
|
||||
// But for now, we'll just text-bash it.
|
||||
string frName = frPrefix+portp->name()+frSuffix;
|
||||
string toName = portp->name()+toSuffix;
|
||||
if (bitvec) {
|
||||
if (portp->isWide()) {
|
||||
stmt += ("VL_SET_SVBV_W("+cvtToStr(portp->width())
|
||||
+", "+toName+", "+frName+")");
|
||||
} else {
|
||||
stmt += "VL_SET_WQ("+toName+", "+frName+")";
|
||||
}
|
||||
} else if (logicvec) {
|
||||
stmt += ("VL_SET_SVLV_" + string(portp->dtypep()->charIQWN()) + "("
|
||||
+ cvtToStr(portp->width())
|
||||
+ ", "+toName+", "+frName+")");
|
||||
} else {
|
||||
if (isPtr) stmt += "*"; // DPI outputs are pointers
|
||||
stmt += toName+" = ";
|
||||
if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::CHANDLE) {
|
||||
stmt += "VL_CVT_Q_VP(";
|
||||
ket += ")";
|
||||
}
|
||||
stmt += frName;
|
||||
if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::STRING) {
|
||||
stmt += ".c_str()";
|
||||
}
|
||||
}
|
||||
stmt += ket + ";\n";
|
||||
return stmt;
|
||||
}
|
||||
|
||||
bool V3Task::dpiToInternalFrStmt(AstVar* portp, const string& frName, bool cvt, string& frstmt) {
|
||||
if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::CHANDLE) {
|
||||
frstmt = "VL_CVT_VP_Q("+frName+")";
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiBitVal()
|
||||
&& portp->width() != 1 && portp->isQuad()) {
|
||||
// SV is vector, Verilator isn't
|
||||
frstmt = "VL_SET_QW("+frName+")";
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiLogicVal()
|
||||
&& portp->width() != 1 && portp->isQuad()) {
|
||||
frstmt = "VL_SET_Q_SVLV("+frName+")";
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiLogicVal()
|
||||
&& portp->width() != 1 && !portp->isWide()) {
|
||||
frstmt = "VL_SET_I_SVLV("+frName+")";
|
||||
}
|
||||
else if (!cvt
|
||||
&& portp->basicp() && portp->basicp()->keyword().isDpiBitVal()
|
||||
&& portp->width() != 1 && !portp->isWide()) {
|
||||
frstmt = "*"+frName; // it's a svBitVecVal, which other code won't think is arrayed (as WData aren't), but really is
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiLogicVal()
|
||||
&& portp->width() != 1 && portp->isWide()) {
|
||||
// Need to convert to wide, using special function
|
||||
frstmt = "VL_SET_W_SVLV("+cvtToStr(portp->width()) + ",";
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
frstmt = frName;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void V3Task::taskAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
|
@ -41,6 +41,11 @@ public:
|
||||
static void taskAll(AstNetlist* nodep);
|
||||
/// Return vector of [port, pin-connects-to] (SLOW)
|
||||
static V3TaskConnects taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp);
|
||||
static string assignInternalToDpi(AstVar* portp, bool isRtn, bool isPtr,
|
||||
const string& frSuffix, const string& toSuffix,
|
||||
const string& frPrefix="");
|
||||
static bool dpiToInternalFrStmt(AstVar* portp, const string& frName, bool cvt,
|
||||
string& frstmt);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
@ -73,6 +73,7 @@
|
||||
#include "V3Partition.h"
|
||||
#include "V3PreShell.h"
|
||||
#include "V3Premit.h"
|
||||
#include "V3ProtectLib.h"
|
||||
#include "V3Reloop.h"
|
||||
#include "V3Scope.h"
|
||||
#include "V3Scoreboard.h"
|
||||
@ -547,6 +548,13 @@ void process() {
|
||||
V3EmitXml::emitxml();
|
||||
}
|
||||
|
||||
// Output DPI protected library files
|
||||
if (!v3Global.opt.protectLib().empty()) {
|
||||
V3ProtectLib::protect();
|
||||
V3EmitV::emitvFiles();
|
||||
V3EmitC::emitcFiles();
|
||||
}
|
||||
|
||||
// Statistics
|
||||
if (v3Global.opt.stats()) {
|
||||
V3Stats::statsFinalAll(v3Global.rootp());
|
||||
|
53
test_regress/t/t_prot_lib.pl
Executable file
53
test_regress/t/t_prot_lib.pl
Executable file
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2019 by Todd Strader. 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.
|
||||
|
||||
scenarios(
|
||||
vlt => 1,
|
||||
xsim => 1,
|
||||
);
|
||||
|
||||
# Always compile the secret file with Verilator no matter what simulator
|
||||
# we are testing with
|
||||
my $cmd = ["t/t_prot_lib_secret.pl", "--vlt"];
|
||||
my $secret_prefix = "t_prot_lib_secret";
|
||||
|
||||
my $secret_dir = "$Self->{obj_dir}/../../obj_vlt/$secret_prefix";
|
||||
|
||||
while (1) {
|
||||
run(logfile => "$Self->{obj_dir}/secret_compile.log",
|
||||
cmd => $cmd);
|
||||
last if $Self->{errors};
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ["$secret_dir/secret.sv",
|
||||
"--trace", "-LDFLAGS",
|
||||
"'-L../$secret_prefix -lsecret -static'"],
|
||||
xsim_flags2 => ["$secret_dir/secret.sv"],
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
xsim_run_flags2 => ["--debug",
|
||||
"all",
|
||||
"--sv_lib",
|
||||
"$secret_dir/libsecret",
|
||||
"--dpi_absolute"],
|
||||
);
|
||||
|
||||
if ($Self->{vlt}) {
|
||||
# We can see the ports of the secret module
|
||||
file_grep("$Self->{obj_dir}/simx.vcd", qr/accum_in/);
|
||||
# but we can't see what's inside
|
||||
file_grep_not("$Self->{obj_dir}/simx.vcd", qr/secret_/);
|
||||
}
|
||||
|
||||
ok(1);
|
||||
last;
|
||||
}
|
||||
1;
|
139
test_regress/t/t_prot_lib.v
Normal file
139
test_regress/t/t_prot_lib.v
Normal file
@ -0,0 +1,139 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2019 by Todd Strader.
|
||||
|
||||
`define DRIVE(sig) \
|
||||
/* Just throw a bunch of bits at the input */ \
|
||||
/* verilator lint_off WIDTH */ \
|
||||
sig``_in <= {8{crc}}; \
|
||||
/* verilator lint_on WIDTH */
|
||||
`define CHECK(sig) \
|
||||
if (cyc > 0 && sig``_in != sig``_out) begin \
|
||||
$display(`"%%Error (%m) sig``_in (0x%0x) != sig``_out (0x%0x)`", \
|
||||
sig``_in, sig``_out); \
|
||||
$stop; \
|
||||
end
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
genvar x;
|
||||
generate
|
||||
for (x = 0; x < 2; x = x + 1) begin: gen_loop
|
||||
integer cyc = 0;
|
||||
reg [63:0] crc = 64'h5aef0c8d_d70a4497;
|
||||
logic [31:0] accum_in;
|
||||
logic [31:0] accum_out;
|
||||
logic accum_bypass;
|
||||
logic [31:0] accum_bypass_out;
|
||||
logic [31:0] accum_out_expect;
|
||||
logic [31:0] accum_bypass_out_expect;
|
||||
logic s1_in;
|
||||
logic s1_out;
|
||||
logic [1:0] s2_in;
|
||||
logic [1:0] s2_out;
|
||||
logic [7:0] s8_in;
|
||||
logic [7:0] s8_out;
|
||||
logic [32:0] s33_in;
|
||||
logic [32:0] s33_out;
|
||||
logic [63:0] s64_in;
|
||||
logic [63:0] s64_out;
|
||||
logic [64:0] s65_in;
|
||||
logic [64:0] s65_out;
|
||||
logic [128:0] s129_in;
|
||||
logic [128:0] s129_out;
|
||||
logic [3:0] [31:0] s4x32_in;
|
||||
logic [3:0] [31:0] s4x32_out;
|
||||
|
||||
secret
|
||||
secret (
|
||||
.accum_in,
|
||||
.accum_out,
|
||||
.accum_bypass,
|
||||
.accum_bypass_out,
|
||||
.s1_in,
|
||||
.s1_out,
|
||||
.s2_in,
|
||||
.s2_out,
|
||||
.s8_in,
|
||||
.s8_out,
|
||||
.s33_in,
|
||||
.s33_out,
|
||||
.s64_in,
|
||||
.s64_out,
|
||||
.s65_in,
|
||||
.s65_out,
|
||||
.s129_in,
|
||||
.s129_out,
|
||||
.s4x32_in,
|
||||
.s4x32_out,
|
||||
.clk);
|
||||
|
||||
always @(posedge clk) begin
|
||||
`ifdef TEST_VERBOSE
|
||||
$display("[%0t] x=%0d, cyc=%0d accum_in=%0d accum_out=%0d accum_bypass_out=%0d",
|
||||
$time, x, cyc, accum_in, accum_out, accum_bypass_out);
|
||||
`endif
|
||||
cyc <= cyc + 1;
|
||||
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||
accum_in <= accum_in + 5;
|
||||
// 7 is the secret_value inside the secret module
|
||||
accum_out_expect <= accum_in + accum_out_expect + 7;
|
||||
`DRIVE(s1)
|
||||
`DRIVE(s2)
|
||||
`DRIVE(s8)
|
||||
`DRIVE(s33)
|
||||
`DRIVE(s64)
|
||||
`DRIVE(s65)
|
||||
`DRIVE(s129)
|
||||
`DRIVE(s4x32)
|
||||
if (cyc == 0) begin
|
||||
accum_in <= x*100;
|
||||
accum_bypass <= '0;
|
||||
end else if (cyc > 0) begin
|
||||
if (accum_out_expect != accum_out) begin
|
||||
$display("%%Error: (%m) accum_out expected %0d got %0d",
|
||||
accum_out_expect, accum_out);
|
||||
$stop;
|
||||
end
|
||||
if (accum_bypass_out_expect != accum_bypass_out) begin
|
||||
$display("%%Error: (%m) accum_bypass_out expected %0d got %0d",
|
||||
accum_bypass_out_expect, accum_bypass_out);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
if (cyc == 5) accum_bypass <= '1;
|
||||
|
||||
if (x == 0 && cyc == 10) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
always @(*) begin
|
||||
// XSim (and maybe all event simulators?) sees the moment where
|
||||
// s1_in has not yet propagated to s1_out, however, they do always
|
||||
// both change at the same time
|
||||
/* verilator lint_off STMTDLY */
|
||||
#1;
|
||||
/* verilator lint_on STMTDLY */
|
||||
`CHECK(s1)
|
||||
`CHECK(s2)
|
||||
`CHECK(s8)
|
||||
`CHECK(s33)
|
||||
`CHECK(s64)
|
||||
`CHECK(s65)
|
||||
`CHECK(s129)
|
||||
`CHECK(s4x32)
|
||||
end
|
||||
|
||||
assign accum_bypass_out_expect = accum_bypass ? accum_in :
|
||||
accum_out_expect;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule
|
5
test_regress/t/t_prot_lib_inout_bad.out
Normal file
5
test_regress/t/t_prot_lib_inout_bad.out
Normal file
@ -0,0 +1,5 @@
|
||||
%Error: Internal Error: t/t_prot_lib_inout_bad.v:8: ../V3ProtectLib.cpp:359: Unsupported port direction for protect-lib: INOUT
|
||||
inout z,
|
||||
^
|
||||
... See the manual and http://www.veripool.org/verilator for more assistance.
|
||||
%Error: Command Failed
|
27
test_regress/t/t_prot_lib_inout_bad.pl
Executable file
27
test_regress/t/t_prot_lib_inout_bad.pl
Executable file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2019 by Todd Strader. 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.
|
||||
|
||||
scenarios(vlt => 1);
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ["--protect-lib",
|
||||
"secret"],
|
||||
verilator_make_gcc => 0,
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
#run(cmd=>["make",
|
||||
# "-C",
|
||||
# "$Self->{obj_dir}",
|
||||
# "-f",
|
||||
# "V$Self->{name}.mk"]);
|
||||
|
||||
ok(1);
|
||||
1;
|
14
test_regress/t/t_prot_lib_inout_bad.v
Normal file
14
test_regress/t/t_prot_lib_inout_bad.v
Normal file
@ -0,0 +1,14 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2019 by Todd Strader.
|
||||
|
||||
module secret_impl (
|
||||
input a,
|
||||
input oe,
|
||||
inout z,
|
||||
output y);
|
||||
|
||||
assign z = oe ? a : 1'bz;
|
||||
assign y = z;
|
||||
|
||||
endmodule
|
27
test_regress/t/t_prot_lib_secret.pl
Executable file
27
test_regress/t/t_prot_lib_secret.pl
Executable file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2019 by Todd Strader. 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.
|
||||
|
||||
scenarios(vlt => 1);
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ["--protect-lib",
|
||||
"secret",
|
||||
"--protect-key",
|
||||
"SECRET_FAKE_KEY"],
|
||||
verilator_make_gcc => 0,
|
||||
);
|
||||
|
||||
run(cmd=>["make",
|
||||
"-C",
|
||||
"$Self->{obj_dir}",
|
||||
"-f",
|
||||
"V$Self->{name}.mk"]);
|
||||
|
||||
ok(1);
|
||||
1;
|
57
test_regress/t/t_prot_lib_secret.v
Normal file
57
test_regress/t/t_prot_lib_secret.v
Normal file
@ -0,0 +1,57 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2019 by Todd Strader.
|
||||
|
||||
module secret_impl (
|
||||
input [31:0] accum_in,
|
||||
output wire [31:0] accum_out,
|
||||
input accum_bypass,
|
||||
output [31:0] accum_bypass_out,
|
||||
input s1_in,
|
||||
output logic s1_out,
|
||||
input [1:0] s2_in,
|
||||
output logic [1:0] s2_out,
|
||||
input [7:0] s8_in,
|
||||
output logic [7:0] s8_out,
|
||||
input [32:0] s33_in,
|
||||
output logic [32:0] s33_out,
|
||||
input [63:0] s64_in,
|
||||
output logic [63:0] s64_out,
|
||||
input [64:0] s65_in,
|
||||
output logic [64:0] s65_out,
|
||||
input [128:0] s129_in,
|
||||
output logic [128:0] s129_out,
|
||||
input [3:0] [31:0] s4x32_in,
|
||||
output logic [3:0] [31:0] s4x32_out,
|
||||
input clk);
|
||||
|
||||
logic [31:0] secret_accum_q = 0;
|
||||
logic [31:0] secret_value = 7;
|
||||
|
||||
initial $display("created %m");
|
||||
|
||||
always @(posedge clk) begin
|
||||
secret_accum_q <= secret_accum_q + accum_in + secret_value;
|
||||
end
|
||||
|
||||
// Test combinatorial paths of different sizes
|
||||
always @(*) begin
|
||||
s1_out = s1_in;
|
||||
s2_out = s2_in;
|
||||
s8_out = s8_in;
|
||||
s33_out = s33_in;
|
||||
s64_out = s64_in;
|
||||
s65_out = s65_in;
|
||||
s129_out = s129_in;
|
||||
s4x32_out = s4x32_in;
|
||||
end
|
||||
|
||||
// Test sequential path
|
||||
assign accum_out = secret_accum_q;
|
||||
|
||||
// Test mixed combinatorial/sequential path
|
||||
assign accum_bypass_out = accum_bypass ? accum_in : secret_accum_q;
|
||||
|
||||
final $display("destroying %m");
|
||||
|
||||
endmodule
|
5
test_regress/t/t_prot_lib_unpacked_bad.out
Normal file
5
test_regress/t/t_prot_lib_unpacked_bad.out
Normal file
@ -0,0 +1,5 @@
|
||||
%Error: Internal Error: t/t_prot_lib_unpacked_bad.v:6: ../V3ProtectLib.cpp:347: Unsupported: unpacked arrays with protect-lib
|
||||
input unpacked_in [7:0],
|
||||
^~~~~~~~~~~
|
||||
... See the manual and http://www.veripool.org/verilator for more assistance.
|
||||
%Error: Command Failed
|
27
test_regress/t/t_prot_lib_unpacked_bad.pl
Executable file
27
test_regress/t/t_prot_lib_unpacked_bad.pl
Executable file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2019 by Todd Strader. 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.
|
||||
|
||||
scenarios(vlt => 1);
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ["--protect-lib",
|
||||
"secret"],
|
||||
verilator_make_gcc => 0,
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
#run(cmd=>["make",
|
||||
# "-C",
|
||||
# "$Self->{obj_dir}",
|
||||
# "-f",
|
||||
# "V$Self->{name}.mk"]);
|
||||
|
||||
ok(1);
|
||||
1;
|
16
test_regress/t/t_prot_lib_unpacked_bad.v
Normal file
16
test_regress/t/t_prot_lib_unpacked_bad.v
Normal file
@ -0,0 +1,16 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2019 by Todd Strader.
|
||||
|
||||
module secret_impl (
|
||||
input unpacked_in [7:0],
|
||||
output unpacked_out [7:0]);
|
||||
|
||||
genvar i;
|
||||
generate
|
||||
for (i = 0; i < 8; i = i + 1) begin
|
||||
assign unpacked_out[i] = unpacked_in[i];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user