Compare commits

..

2 Commits

Author SHA1 Message Date
Nikolay Puzanov
058191de55 Add Verilator support 2022-12-03 18:36:50 +03:00
Nikolay Puzanov
f61bb7b980 Prepare to add Verilator 2022-12-03 13:52:43 +03:00
7 changed files with 299 additions and 134 deletions

View File

@ -98,7 +98,8 @@
<button onclick="save_code('%SAVECODEURI%')"><span class="text">Save (ctrl-s)</span></button> <button onclick="save_code('%SAVECODEURI%')"><span class="text">Save (ctrl-s)</span></button>
<button onclick="save_code('%SAVEASURI%')"><span class="text">Save as new</span></button> <button onclick="save_code('%SAVEASURI%')"><span class="text">Save as new</span></button>
Sim: Sim:
<button onclick="send_to_icarus()"><span class="text">Icarus</span></button> <button onclick="send_to_sim('%IVERILOGPOSTURI%')"><span class="text">Icarus</span></button>
<button onclick="send_to_sim('%VERILATORPOSTURI%')"><span class="text">Verilator</span></button>
<!-- button><span class="text">Verilator</span></button --> <!-- button><span class="text">Verilator</span></button -->
</div> </div>
@ -123,9 +124,9 @@
enableLiveAutocompletion : true enableLiveAutocompletion : true
}); });
const log_area = document.getElementById('log'); const log_area = document.getElementById('log');
function send_to_icarus() { function send_to_sim(uri) {
log_area.innerHTML = "Please wait..."; log_area.innerHTML = "Please wait...";
fetch('%IVERILOGPOSTURI%', fetch(uri,
{ {
method: 'POST', method: 'POST',
headers: { headers: {

View File

@ -1 +0,0 @@
run-restricted

View File

@ -24,22 +24,17 @@
(define INDEX-FILE "index.html") (define INDEX-FILE "index.html")
(define DELETE-WORK-DIR #t) (define DELETE-WORK-DIR #t)
(define DEFAULT-CODE (define TOP-MODULE "testbench")
(string-append
"`timescale 10ps/10ps\n\n"
"module test;\n"
" initial begin\n"
" $display(\"Hello world!\");\n"
" $finish();\n"
" end\n"
"endmodule\n"))
(define SIM-SV-FILE "testbench.sv")
(define SIM-VC-FILE "testbench.vc")
(define SIM-EXE-FILE "testbench.out")
(define SNIPPET-FILE "code.sv") (define SNIPPET-FILE "code.sv")
(define IVERILOG-METATOP-FILE "top_iverilog.sv")
(define VERILATOR-CPP-FILE "top_verilator.cpp")
(define IVERILOG-EXE "iverilog")
(define VVP-EXE "vvp")
(define VERILATR-EXE "verilator")
(define URI-IVERILOG "iverilog") (define URI-IVERILOG "iverilog")
(define URI-VERILATOR "verilator")
(define URI-SAVE-CODE "save") (define URI-SAVE-CODE "save")
(define URI-SAVEAS-CODE "saveas") (define URI-SAVEAS-CODE "saveas")
@ -50,6 +45,16 @@
(define LOG-LEVEL LOG-VERBOSE) (define LOG-LEVEL LOG-VERBOSE)
(define DEFAULT-CODE
(string-append
"`timescale 1ps/1ps\n\n"
(format "module ~a (input clock);\n" TOP-MODULE)
" initial begin\n"
" $display(\"Hello world!\");\n"
" $finish();\n"
" end\n"
"endmodule\n"))
(define (multistring . strings) (define (multistring . strings)
(apply string-append (apply string-append
(insert-between strings "\n"))) (insert-between strings "\n")))
@ -235,21 +240,6 @@
(code (regexp-substitute/global #f "\\$dump[a-z]*" code 'pre "$error" 'post))) (code (regexp-substitute/global #f "\\$dump[a-z]*" code 'pre "$error" 'post)))
code)) code))
;;;
;;; Get module name
;;;
(define (module-name code)
(let ((rx (make-regexp
"(^|\\s)module\\s*(\\s|(#\\(.*\\)\\s*))[a-zA-Z0-9_]+")))
(let loop ((pos 0)
(modname #f))
(let ((m (regexp-exec rx code pos)))
(if m
(loop (match:end m) (match:substring m))
(if modname
(match:substring (string-match "[a-zA-Z0-9_]+$" modname))
#f))))))
;;; ;;;
;;; Concatenate path elements and remove duplicate slashes ;;; Concatenate path elements and remove duplicate slashes
;;; ;;;
@ -267,52 +257,86 @@
(map string-trim-both paths)) (map string-trim-both paths))
"/"))))) "/")))))
;;; (define (wrap-exe exe wrapper)
;;; Create dump module (format "~a~a" (if wrapper (format "~a " wrapper) "") exe))
;;;
(define (create-dump-module path modname top)
(define (-> . fmt) (display (apply format fmt)) (newline))
(let ((filename (path+ path (format "~a.v" modname))))
(with-output-to-file filename
(lambda ()
(-> "`timescale 1ps/1ps")
(-> "module ~a();" modname)
(-> " initial begin")
(-> " $dumpfile(\"~a/~a.vcd\");" path modname)
(-> " $dumpvars(0, ~a);" top)
(-> " end")
(-> "endmodule")))
filename))
;;; ;;;
;;; Make workdir with sources and command file ;;; Make workdir with sources and command file. Common part
;;; Returns work directory path string ;;; Returns work directory path string, verilog file name
;;; and command file name.
;;; ;;;
(define (make-sim-workdir simulator code top base) (define* (make-sim-workdir code base top)
(let* ((work-dir (mkdtemp (path+ base (format "work-~a-XXXXXX" (current-time))))) (let* ((work-dir (mkdtemp (path+ base (format "work-~a-XXXXXX" (current-time)))))
(verilog-file (path+ work-dir SIM-SV-FILE)) (verilog-file (path+ work-dir (format "~a.sv" top)))
(command-file (path+ work-dir SIM-VC-FILE)) (command-file (path+ work-dir (format "~a.vc" top))))
(dump-file (create-dump-module work-dir "dump" top)))
(with-output-to-file verilog-file (cut display code)) (with-output-to-file verilog-file (cut display code))
(values work-dir verilog-file command-file)))
;;;
;;; Create workdir for Icarus Verilog
;;; Returns directory path
;;;
(define* (make-iverilog-workdir code metatop base top)
(let-values (((work-dir verilog-file command-file)
(make-sim-workdir code base top)))
(let ((metatop-file (path+ work-dir (format "__~a__.sv" top))))
(with-output-to-file metatop-file
(cut display (substitute metatop "@~a@"
`((WORKDIR ,work-dir)
(TOPMODULE ,top)))))
(with-output-to-file command-file (with-output-to-file command-file
(lambda () (lambda ()
(cond
((eq? simulator 'iverilog)
(println "~a" verilog-file) (println "~a" verilog-file)
(println "~a" dump-file) (println "~a" metatop-file)
(println "+define+TESTBENCH") (println "+define+TESTBENCH")
(println "+timescale+1ps/1ps"))))) (println "+timescale+1ps/1ps"))))
work-dir))
;;;
;;; Create workdir for Verilator
;;; Returns directory path
;;;
(define* (make-verilator-workdir code cpp base top)
(let-values (((work-dir verilog-file command-file)
(make-sim-workdir code base top)))
(let ((cpp-file (path+ work-dir (format "~a.cpp" top))))
(with-output-to-file cpp-file
(cut display (substitute cpp "@~a@" `((WORKDIR ,work-dir)
(TOPMODULE ,top)))))
(with-output-to-file command-file
(lambda ()
(println "+define+TESTBENCH")
(println "--timescale 1ps/1ps")
(println "--top-module ~a" top)
(println "--Mdir ~a" (path+ work-dir top))
(println "-cc")
(println "-O2")
(println "-o ~a" top)
(println "--exe")
(println "--build")
(println "-sv")
(println "-Wno-WIDTH")
(println "+1800-2017ext+sv")
(println "--timing")
(println "--trace")
(println "--quiet-exit")
(println "~a" verilog-file)
(println "~a.cpp" top))))
work-dir)) work-dir))
;;; ;;;
;;; Compile sources and execute simulation with Icarus Verilog ;;; Compile sources and execute simulation with Icarus Verilog
;;; Returns (values status log) ;;; Returns (values status log)
;;; ;;;
(define (exec-sim-iverilog work-dir vvp-exe iverilog-exe) (define (exec-sim-iverilog top work-dir iverilog-wrap vvp-wrap)
(let ((exe-file (path+ work-dir SIM-EXE-FILE)) (let ((command-file (path+ work-dir (format "~a.vc" top)))
(command-file (path+ work-dir SIM-VC-FILE))) (exe-file (path+ work-dir (format "~a.out" top))))
;; Compile ;; Compile
(let ((cmdline (format "~a -g2012 -o ~a -c~a" iverilog-exe exe-file command-file))) (let ((cmdline (format "~a -g2012 -s __~a__ -o ~a -c~a"
(wrap-exe IVERILOG-EXE iverilog-wrap)
top exe-file command-file)))
(let-values (((status out) (let-values (((status out)
(system-to-string cmdline))) (system-to-string cmdline)))
(let ((compile-log (let ((compile-log
@ -321,7 +345,7 @@
(values status compile-log) (values status compile-log)
;; Execute ;; Execute
(let ((cmdline (format "~a -N ~a" vvp-exe exe-file))) (let ((cmdline (format "~a -N ~a" (wrap-exe VVP-EXE vvp-wrap) exe-file)))
(let-values (((status out) (let-values (((status out)
(system-to-string cmdline))) (system-to-string cmdline)))
(let ((execution-log (let ((execution-log
@ -329,37 +353,61 @@
(values status (string-append compile-log execution-log))))))))))) (values status (string-append compile-log execution-log)))))))))))
;;; ;;;
;;; Get iverilog version ;;; Compile sources and execute simulation with Verilator
;;; Returns (values status log)
;;; ;;;
(define (iverilog-version iverilog-exe) (define (exec-sim-verilator top work-dir verilator-wrap verilator-sim-wrap)
;; Compile
(let* ((command-file (path+ work-dir (format "~a.vc" top)))
(cmdline (format "~a -f ~a"
(wrap-exe VERILATR-EXE verilator-wrap)
command-file)))
(let-values (((status out) (let-values (((status out)
(system-to-string-list (system-to-string cmdline)))
(format "~a -V" iverilog-exe)))) (let ((compile-log
(if (and (zero? status) (exe-log-pretty cmdline status out)))
(not (null? out))) (if (not (zero? status))
(car out) (values status compile-log)
"Unknown")))
;; Execute
(let ((cmdline (wrap-exe (path+ work-dir (format "~a/~a" top top))
verilator-sim-wrap)))
(let-values (((status out)
(system-to-string cmdline)))
(let ((execution-log
(exe-log-pretty cmdline status out)))
(values status (string-append compile-log execution-log))))))))))
;;; ;;;
;;; Execute simulation ;;; Execute simulation
;;; ;;;
(define* (exec-sim simulator code base (define* (exec-sim simulator code base top #:key
#:key (vvp-wrap "") (iverilog-wrap "") (metatop "")
(vvp-exe "vvp") (verilator-wrap "") (verilator-sim-wrap "") (verilator-cpp ""))
(iverilog-exe "iverilog"))
(let ((top (module-name code)))
(if (not top)
"Error: No module declaration\n"
(let ((work-dir (make-sim-workdir simulator code top base)))
(let-values (let-values
(((status log) (((work-dir status log)
(cond (cond
;; Run Icarus Verilog
((eq? simulator 'iverilog) ((eq? simulator 'iverilog)
(exec-sim-iverilog work-dir vvp-exe iverilog-exe)) (let ((work-dir (make-iverilog-workdir code metatop base top)))
(let-values (((status log)
(exec-sim-iverilog top work-dir iverilog-wrap vvp-wrap)))
(values work-dir status log))))
;; Run Verilator
((eq? simulator 'verilator)
(let ((work-dir (make-verilator-workdir code verilator-cpp base top)))
(let-values (((status log)
(exec-sim-verilator top work-dir verilator-wrap verilator-sim-wrap)))
(values work-dir status log))))
;; Inknown simulator
(else (else
(values -1 "No simulator found!\n"))))) (values #f #f #f)))))
(if (not work-dir)
("ERROR: Unknown simulator")
(begin
;; Delete work dir ;; Delete work dir
(when DELETE-WORK-DIR (when DELETE-WORK-DIR
(delete-recursive work-dir)) (delete-recursive work-dir))
@ -368,9 +416,19 @@
(string-append (string-append
log log
(format "-----------------\nSimulation complete~a\n" (format "-----------------\nSimulation complete~a\n"
(if (zero? status) (if (zero? status) " succesfully"" with errors")))))))
" succesfully"
" with errors")))))))) ;;;
;;; Get app version
;;;
(define* (app-version exe #:optional (option "--version"))
(let-values (((status out)
(system-to-string-list
(format "~a ~a" exe option))))
(if (and (zero? status)
(not (null? out)))
(car out)
"Unknown")))
;;; ;;;
;;; Get storage dir from URI ;;; Get storage dir from URI
@ -428,38 +486,43 @@
(define (make-page-handler host root index-file (define (make-page-handler host root index-file
work-base stor-base work-base stor-base
max-code-size max-code-size
vvp-exe iverilog-exe) iverilog-wrap vvp-wrap
verilator-wrap verilator-sim-wrap)
(let* ((root-path (split-and-decode-uri-path root)) (let* ((root-path (split-and-decode-uri-path root))
(root (encode-and-join-uri-path root-path)) (root (encode-and-join-uri-path root-path))
(iverilog-path (append root-path `(,URI-IVERILOG))) (iverilog-path (append root-path `(,URI-IVERILOG)))
(verilator-path (append root-path `(,URI-VERILATOR)))
(savecode-path (append root-path `(,URI-SAVE-CODE))) (savecode-path (append root-path `(,URI-SAVE-CODE)))
(saveas-path (append root-path `(,URI-SAVEAS-CODE))) (saveas-path (append root-path `(,URI-SAVEAS-CODE)))
(iverilog-post-uri (encode-and-join-uri-path iverilog-path))
(savecode-post-uri (encode-and-join-uri-path savecode-path))
(saveas-post-uri (encode-and-join-uri-path saveas-path))
(index-html (index-html
(read-template-text (read-template-text
index-file index-file
`(("IVERILOGPOSTURI" ,iverilog-post-uri) `(("IVERILOGPOSTURI" ,(encode-and-join-uri-path iverilog-path))
("SAVECODEURI" ,savecode-post-uri) ("VERILATORPOSTURI" ,(encode-and-join-uri-path verilator-path))
("SAVEASURI" ,saveas-post-uri) ("SAVECODEURI" ,(encode-and-join-uri-path savecode-path))
("SAVEASURI" ,(encode-and-join-uri-path saveas-path))
("HELPSTRING", ("HELPSTRING",
(string-concatenate (string-concatenate
(insert-between (insert-between
`("Verilog Playground by Punzik (c) 2022" `("Verilog Playground by Punzik (c) 2022"
"" ""
,(format "Icarus: ~a" ,(format "Icarus: ~a"
(iverilog-version iverilog-exe)) (app-version (wrap-exe IVERILOG-EXE iverilog-wrap) "-V"))
,(format "Verilator: ~a" "TODO") ,(format "Verilator: ~a"
(app-version (wrap-exe VERILATR-EXE verilator-wrap)))
"" ""
"Rules:" "Rules:"
"0. Don't fool around ;)" "0. Don't fool around ;)"
"1. (TODO) The top module must be named 'testbench'." "1. The top module must be named 'testbench'."
"2. (TODO) The top module for the Verilator must have an input clock signal." "2. The top module for the Verilator must have an input clock signal."
"3. Code size should not exceed 10000 characters." "3. Code size should not exceed 10000 characters."
"4. Code execution time no longer than 5 seconds.") "4. Code execution time no longer than 5 seconds.")
"\\n"))))))) "\\n"))))))
(iverilog-metatop
(call-with-input-file IVERILOG-METATOP-FILE get-string-all))
(verilator-cpp
(call-with-input-file VERILATOR-CPP-FILE get-string-all)))
(lambda (request request-body) (lambda (request request-body)
(let (;; Requested resource path (let (;; Requested resource path
@ -549,8 +612,27 @@
(exec-sim 'iverilog (exec-sim 'iverilog
(sanitize-verilog code) (sanitize-verilog code)
work-base work-base
#:vvp-exe vvp-exe TOP-MODULE
#:iverilog-exe iverilog-exe) #:metatop iverilog-metatop
#:vvp-wrap vvp-wrap
#:iverilog-wrap iverilog-wrap)
#:content-type 'text/plain))
;; Run verilator simulation
((equal? path verilator-path)
(logger LOG-DBG "Request verilator simulation")
(when ref-stor-dir
(save-to-storage (path+ stor-base ref-stor-dir) code))
(make-response
(exec-sim 'verilator
(sanitize-verilog code)
work-base
TOP-MODULE
#:verilator-wrap verilator-wrap
#:verilator-sim-wrap verilator-sim-wrap
#:verilator-cpp verilator-cpp)
#:content-type 'text/plain)) #:content-type 'text/plain))
;; Save snippet ;; Save snippet
@ -608,8 +690,10 @@
(-> " -p, --port PORT Listen on PORT port. Default: 8080") (-> " -p, --port PORT Listen on PORT port. Default: 8080")
(-> " -s, --host URL Run on URL hostname. Default: http://127.0.0.1:8080") (-> " -s, --host URL Run on URL hostname. Default: http://127.0.0.1:8080")
(-> " -r, --root URN Service location root. Default: ''") (-> " -r, --root URN Service location root. Default: ''")
(-> " --ivverilog-exe PATH Set Icarus Verilog compiler executable. Default: iverilog") (-> " --iverilog-wrap PATH Icarus compiler wrapper.")
(-> " --vvp-exe PATH Set Icarus Verilog interpreter executable. Default: vvp") (-> " --vvp-wrap PATH Icarus Verilog interpreter wrapper.")
(-> " --verilator-wrap PATH Verilator compiler wrapper.")
(-> " --verilator-sim-wrap PATH Verilator simulation executable wrapper.")
(-> " --max-len LEN Set maximum code size in symbols. Default: 0 (infinite)") (-> " --max-len LEN Set maximum code size in symbols. Default: 0 (infinite)")
(-> " --work-base PATH Set work base path. Default: ./") (-> " --work-base PATH Set work base path. Default: ./")
(-> " --stor-base PATH Set snippets storage path. Default: ./") (-> " --stor-base PATH Set snippets storage path. Default: ./")
@ -618,6 +702,11 @@
(-> "") (-> "")
(-> "Source code and issue tracker: <https://github.com/punzik/>"))))) (-> "Source code and issue tracker: <https://github.com/punzik/>")))))
(define (string-trim-if-string str)
(if (string? str)
(string-trim str)
str))
(define (main args) (define (main args)
(debug-disable 'backtrace) (debug-disable 'backtrace)
(let-values (let-values
@ -627,8 +716,10 @@
'(("port" #\p) required) '(("port" #\p) required)
'(("host" #\s) required) '(("host" #\s) required)
'(("root" #\r) required) '(("root" #\r) required)
'(("vvp-exe") required) '(("vvp-wrap") required)
'(("iverilog-exe") required) '(("iverilog-wrap") required)
'(("verilator-wrap") required)
'(("verilator-sim-wrap") required)
'(("max-len") required) '(("max-len") required)
'(("work-base") required) '(("work-base") required)
'(("stor-base") required) '(("stor-base") required)
@ -639,8 +730,10 @@
(port (string->number (string-trim (or (option-get opts "port") "8080")))) (port (string->number (string-trim (or (option-get opts "port") "8080"))))
(host (string-trim (or (option-get opts "host") "http://127.0.0.1:8080"))) (host (string-trim (or (option-get opts "host") "http://127.0.0.1:8080")))
(root (string-trim (or (option-get opts "root") ""))) (root (string-trim (or (option-get opts "root") "")))
(vvp (string-trim (or (option-get opts "vvp-exe") "vvp"))) (vvp-wrap (string-trim-if-string (option-get opts "vvp-wrap")))
(iverilog (string-trim (or (option-get opts "iverilog-exe") "iverilog"))) (iverilog-wrap (string-trim-if-string (option-get opts "iverilog-wrap")))
(verilator-wrap (string-trim-if-string (option-get opts "verilator-wrap")))
(verilator-sim-wrap (string-trim-if-string (option-get opts "verilator-sim-wrap")))
(max-code-size (string->number (string-trim (or (option-get opts "max-len") "0")))) (max-code-size (string->number (string-trim (or (option-get opts "max-len") "0"))))
(work-base (string-trim (or (option-get opts "work-base") "./"))) (work-base (string-trim (or (option-get opts "work-base") "./")))
(stor-base (string-trim (or (option-get opts "stor-base") "./"))) (stor-base (string-trim (or (option-get opts "stor-base") "./")))
@ -660,6 +753,10 @@
(set! LOG-LEVEL log-level) (set! LOG-LEVEL log-level)
(logger LOG-INFO "Listen on '~a' port '~a'" addr port) (logger LOG-INFO "Listen on '~a' port '~a'" addr port)
(logger LOG-INFO "Server URL: '~a/~a'" host root) (logger LOG-INFO "Server URL: '~a/~a'" host root)
(logger LOG-INFO "iverilog wrapper: '~a'" iverilog-wrap)
(logger LOG-INFO "vvp wrapper: '~a'" vvp-wrap)
(logger LOG-INFO "verilator compiler wrapper: '~a'" verilator-wrap)
(logger LOG-INFO "verilator simulator wrapper: '~a'" verilator-sim-wrap)
(logger LOG-INFO "Max code size: ~a" max-code-size) (logger LOG-INFO "Max code size: ~a" max-code-size)
(logger LOG-INFO "Work base path: '~a'" work-base) (logger LOG-INFO "Work base path: '~a'" work-base)
(logger LOG-INFO "Storage base path: '~a'" stor-base) (logger LOG-INFO "Storage base path: '~a'" stor-base)
@ -668,5 +765,7 @@
(run-server (run-server
(make-page-handler host root INDEX-FILE (make-page-handler host root INDEX-FILE
work-base stor-base work-base stor-base
max-code-size vvp iverilog) max-code-size
iverilog-wrap vvp-wrap
verilator-wrap verilator-sim-wrap)
'http `(#:host ,addr #:port ,port))))))) 'http `(#:host ,addr #:port ,port)))))))

View File

@ -1,14 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
exe=$(basename $0)
if [ -z "$DONOTUSEFIREJAIL" ]; then if [ -z "$DONOTUSEFIREJAIL" ]; then
exec firejail \ exec firejail \
--quiet --noprofile \ --quiet --noprofile \
--rlimit-cpu=5 \ --rlimit-cpu=5 \
--rlimit-as=250m \ --rlimit-as=250m \
--rlimit-fsize=250k \ --rlimit-fsize=250k \
"$exe" "$@" "$@"
else else
exec timeout -v -s INT 5 "$exe" "$@" exec timeout -v -s KILL 5 "$@"
fi fi

View File

@ -0,0 +1,11 @@
`timescale 1ps/1ps
module __@TOPMODULE@__;
logic clock = 1'b0;
initial forever #(5ns) clock = ~clock;
@TOPMODULE@ @TOPMODULE@ (clock);
initial begin
$dumpfile("@WORKDIR@/@TOPMODULE@.vcd");
$dumpvars(0, @TOPMODULE@);
end
endmodule

View File

@ -0,0 +1,58 @@
#include "V@TOPMODULE@.h"
#include <cstdint>
#include <verilated.h>
#include <verilated_vcd_c.h>
#define DUMPFILE "@WORKDIR@/@TOPMODULE@.vcd"
#define CLOCK_HALF_PERIOD 5000
int main(int argc, char **argv)
{
VerilatedContext *ctx = new VerilatedContext;
ctx->commandArgs(argc, argv);
/* Create model instance */
V@TOPMODULE@ *top = new V@TOPMODULE@(ctx);
#if (VM_TRACE == 1)
VerilatedVcdC *vcd = new VerilatedVcdC;
ctx->traceEverOn(true);
top->trace(vcd, 99);
vcd->open(DUMPFILE);
#endif
top->clock = 0;
/* ---- Evaluation loop ---- */
for (;;) {
/* Eval */
top->eval();
/* Trace steady-state values */
#if (VM_TRACE == 1)
if (vcd) vcd->dump(ctx->time());
#endif
/* Break exactly after calling $finish */
if (ctx->gotFinish()) break;
/* Clock event */
ctx->timeInc(CLOCK_HALF_PERIOD);
top->clock = top->clock ? 0 : 1;
}
top->final();
printf("[%lu] Stop simulation\n", ctx->time());
#if (VM_TRACE == 1)
if (vcd) {
vcd->close();
delete vcd;
}
#endif
delete top;
delete ctx;
return 0;
}

View File

@ -1 +0,0 @@
run-restricted