Compare commits

..

12 Commits

Author SHA1 Message Date
Nikolay Puzanov
3aee2d2f38 Fix help message 2024-04-14 16:16:45 +03:00
Nikolay Puzanov
b84ec9a1c5 Remove clock from testbench input 2024-04-14 16:08:20 +03:00
Nikolay Puzanov
1e0bfb58cf Add support for verilator 5.018+ 2023-11-07 14:27:08 +03:00
Nikolay Puzanov
e67558de14 Enable dump in iverilog testbench template 2023-06-02 11:08:51 +03:00
Nikolay Puzanov
54f7e2be54 Enable trace of structs 2022-12-13 11:49:15 +03:00
Nikolay Puzanov
cc605cce85 Top module for all simulators must have an input clock signal 2022-12-09 10:21:40 +03:00
Nikolay Puzanov
2f9f5b6dd1 Disable Save hotkey (to prevent thoughtless use) 2022-12-09 10:13:03 +03:00
Nikolay Puzanov
cb8bc37dfe Disable ligatures 2022-12-09 09:23:07 +03:00
Nikolay Puzanov
1e12d5d3e2 Don't save unmodified code 2022-12-09 09:20:53 +03:00
Nikolay Puzanov
1bc6ec544d Save code only by Save button. Save always to new location 2022-12-09 09:07:13 +03:00
Nikolay Puzanov
d04282e1c7 Add simple scroll of long waveform 2022-12-08 19:06:08 +03:00
Nikolay Puzanov
664b7b1f5c Buttons can move to new line 2022-12-07 18:07:00 +03:00
5 changed files with 136 additions and 106 deletions

View File

@@ -10,4 +10,11 @@ module testbench;
initial begin initial begin
$finish; $finish;
end end
`ifdef DUMP
initial begin
$dumpfile("testbench.fst");
$dumpvars(0, testbench);
end
`endif
endmodule endmodule

View File

@@ -11,6 +11,7 @@
box-sizing: border-box; box-sizing: border-box;
margin: 0; margin: 0;
padding: 0; padding: 0;
font-variant-ligatures: none;
} }
body { body {
@@ -28,8 +29,7 @@
color: white; color: white;
background-color: #2d3d40; background-color: #2d3d40;
width: 100%; width: 100%;
height: 38px; padding: 3px;
padding: 4px;
font-size: inherit; font-size: inherit;
} }
@@ -44,7 +44,9 @@
background-color: #dbdbdb; background-color: #dbdbdb;
margin-left: 1px; margin-left: 1px;
margin-right: 1px; margin-right: 1px;
height: 100%; margin-top: 2px;
margin-bottom: 2px;
height: 25px;
} }
button span.text { padding: 4px; } button span.text { padding: 4px; }
@@ -118,6 +120,11 @@
width: 50%; width: 50%;
height: 100%; height: 100%;
} }
#logdiv pre {
position: absolute;
height: 100%;
}
} }
</style> </style>
</head> </head>
@@ -125,8 +132,7 @@
<body> <body>
<div id="buttons"> <div id="buttons">
<button onclick="show_help()"><span class="text">?</span></button> <button onclick="show_help()"><span class="text">?</span></button>
<button onclick="save_code('%SAVECODEURI%')"><span class="text">Save (ctrl-s)</span></button> <button onclick="save_code('%SAVECODEURI%')"><span class="text">Save</span></button>
<button onclick="save_code('%SAVEASURI%')"><span class="text">Save as new</span></button>
Sim: Sim:
<button onclick="send_to_sim('%IVERILOGPOSTURI%')"><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 onclick="send_to_sim('%VERILATORPOSTURI%')"><span class="text">Verilator</span></button>
@@ -186,13 +192,6 @@
alert("%HELPSTRING%"); alert("%HELPSTRING%");
}; };
document.addEventListener('keydown', (e) => {
if (e.key.toLowerCase() === 's' && e.ctrlKey) {
e.preventDefault();
save_code('%SAVECODEURI%');
}
});
</script> </script>
</body> </body>
</html> </html>

View File

@@ -33,12 +33,11 @@
(define IVERILOG-EXE "iverilog") (define IVERILOG-EXE "iverilog")
(define VVP-EXE "vvp") (define VVP-EXE "vvp")
(define VERILATR-EXE "verilator") (define VERILATOR-EXE "verilator")
(define URI-IVERILOG "iverilog") (define URI-IVERILOG "iverilog")
(define URI-VERILATOR "verilator") (define URI-VERILATOR "verilator")
(define URI-SAVE-CODE "save") (define URI-SAVE-CODE "save")
(define URI-SAVEAS-CODE "saveas")
(define LOG-DBG 3) (define LOG-DBG 3)
(define LOG-VERBOSE 2) (define LOG-VERBOSE 2)
@@ -50,9 +49,14 @@
(define DEFAULT-CODE (define DEFAULT-CODE
(string-append (string-append
"`timescale 1ps/1ps\n\n" "`timescale 1ps/1ps\n\n"
(format "module ~a (input clock);\n" TOP-MODULE) ;; (format "module ~a (input clock);\n" TOP-MODULE)
(format "module ~a;\n" TOP-MODULE)
" logic clock = 1'b0;\n"
" initial forever #(5ns) clock = ~clock;\n"
"\n"
" initial begin\n" " initial begin\n"
" $display(\"Hello world!\");\n" " $display(\"Hello world!\");\n"
" repeat(10) @(posedge clock);\n"
" $finish();\n" " $finish();\n"
" end\n" " end\n"
"endmodule\n")) "endmodule\n"))
@@ -320,14 +324,40 @@
;;; Make legend SVG text for VCD ;;; Make legend SVG text for VCD
;;; ;;;
(define* (vcd-signals->legend signals text-spacing text-position) (define* (vcd-signals->legend signals text-spacing text-position)
(map (if (null? signals)
(lambda (sig n) ""
(string-append (let ((common-scope-len
(format-inex "<text x=\"0\" y=\"~a\">~a</text>" (length
(+ (* n text-spacing) text-position) (fold
(vcd-signal-name sig)))) (lambda (scope common)
signals (let loop ((scope scope)
(iota (length signals)))) (common common)
(out '()))
(if (or (null? scope)
(null? common))
(reverse out)
(if (string-ci= (car scope)
(car common))
(loop (cdr scope)
(cdr common)
(cons (car scope) out))
(reverse out)))))
(vcd-signal-scope (car signals))
(map vcd-signal-scope (cdr signals))))))
(map
(lambda (sig n)
(string-append
(format-inex "<text x=\"0\" y=\"~a\">~a</text>"
(+ (* n text-spacing) text-position)
(string-concatenate
(insert-between
(append
(drop (vcd-signal-scope sig)
common-scope-len)
`(,(vcd-signal-name sig)))
".")))))
signals
(iota (length signals))))))
;;; ;;;
;;; Create SVG from VCD ;;; Create SVG from VCD
@@ -337,7 +367,7 @@
(signal-text-position 12) (signal-text-position 12)
(margin 5) (margin 5)
(signal-spacing 5) (signal-spacing 5)
(legend-width 100) (legend-width 150)
(extra-delim-y 3)) (extra-delim-y 3))
(let ((tstart (apply min (vcd-timestamps vcd))) (let ((tstart (apply min (vcd-timestamps vcd)))
@@ -541,7 +571,7 @@
(with-output-to-file command-file (with-output-to-file command-file
(lambda () (lambda ()
(println "+define+TESTBENCH") (println "-DTESTBENCH")
(println "--timescale 1ps/1ps") (println "--timescale 1ps/1ps")
(println "--top-module ~a" top) (println "--top-module ~a" top)
(println "--Mdir ~a" (path+ work-dir top)) (println "--Mdir ~a" (path+ work-dir top))
@@ -554,9 +584,11 @@
(println "--build") (println "--build")
(println "-sv") (println "-sv")
(println "-Wno-WIDTH") (println "-Wno-WIDTH")
(println "+1800-2017ext+sv") (println "+1800-2023ext+sv")
(println "--timing") (println "--timing")
(println "--trace") (println "--trace")
(println "--trace-structs")
(println "--trace-depth 1")
(println "--quiet-exit") (println "--quiet-exit")
(println "~a" verilog-file) (println "~a" verilog-file)
(println "~a.cpp" top)))) (println "~a.cpp" top))))
@@ -611,7 +643,7 @@
(values status log (vcd-file-read (values status log (vcd-file-read
vcd-file vcd-file
(lambda (sig) (lambda (sig)
(= 2 (length (vcd-signal-scope sig)))))) (>= (length (vcd-signal-scope sig)) 2))))
(values status log #f))))) (values status log #f)))))
;;; ;;;
@@ -622,7 +654,7 @@
(let* ((command-file (path+ work-dir (format "~a.vc" top))) (let* ((command-file (path+ work-dir (format "~a.vc" top)))
(vcd-file (path+ work-dir (format "~a.vcd" top))) (vcd-file (path+ work-dir (format "~a.vcd" top)))
(cmds `(,(format "~a -f ~a" (cmds `(,(format "~a -f ~a"
(wrap-exe VERILATR-EXE verilator-wrap) (wrap-exe VERILATOR-EXE verilator-wrap)
command-file) command-file)
,(wrap-exe (path+ work-dir (format "~a/~a" top top)) ,(wrap-exe (path+ work-dir (format "~a/~a" top top))
verilator-sim-wrap)))) verilator-sim-wrap))))
@@ -633,7 +665,7 @@
(values status log (vcd-file-read (values status log (vcd-file-read
vcd-file vcd-file
(lambda (sig) (lambda (sig)
(= 2 (length (vcd-signal-scope sig)))))) (>= (length (vcd-signal-scope sig)) 2))))
(values status log #f))))) (values status log #f)))))
;;; ;;;
@@ -744,12 +776,22 @@
;;; ;;;
;;; Make log HTML ;;; Make log HTML
;;; ;;;
(define (make-log-html log vcd canvas-width) (define* (make-log-html log vcd canvas-width #:key
(minimum-sample-width 10)
(maximum-canvas-width 20000))
(if vcd (if vcd
(format "~a<br/>\n<pre id=\"log\">~a</pre>\n" (let ((need-width
(string-concatenate (* minimum-sample-width
(vcd->svg vcd canvas-width)) (length (vcd-timestamps vcd)))))
log) (format "~a<br/>\n<pre id=\"log\">~a</pre>\n"
(string-concatenate
(vcd->svg vcd
(if (< need-width canvas-width)
canvas-width
(if (> need-width maximum-canvas-width)
maximum-canvas-width
need-width))))
log))
(format "<pre>~a</pre>\n" log))) (format "<pre>~a</pre>\n" log)))
;;; ;;;
@@ -766,14 +808,12 @@
(iverilog-path (append root-path `(,URI-IVERILOG))) (iverilog-path (append root-path `(,URI-IVERILOG)))
(verilator-path (append root-path `(,URI-VERILATOR))) (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)))
(index-html (index-html
(read-template-text (read-template-text
index-file index-file
`(("IVERILOGPOSTURI" ,(encode-and-join-uri-path iverilog-path)) `(("IVERILOGPOSTURI" ,(encode-and-join-uri-path iverilog-path))
("VERILATORPOSTURI" ,(encode-and-join-uri-path verilator-path)) ("VERILATORPOSTURI" ,(encode-and-join-uri-path verilator-path))
("SAVECODEURI" ,(encode-and-join-uri-path savecode-path)) ("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
@@ -782,14 +822,13 @@
,(format "Icarus: ~a" ,(format "Icarus: ~a"
(app-version (wrap-exe IVERILOG-EXE iverilog-wrap) "-V")) (app-version (wrap-exe IVERILOG-EXE iverilog-wrap) "-V"))
,(format "Verilator: ~a" ,(format "Verilator: ~a"
(app-version (wrap-exe VERILATR-EXE verilator-wrap))) (app-version (wrap-exe VERILATOR-EXE verilator-wrap)))
"" ""
"Rules:" "Rules:"
"0. Don't fool around ;)" "0. Don't fool around ;)"
"1. The top module must be named 'testbench'." "1. The top module must be named 'testbench'."
"2. The top module for the Verilator must have an input clock signal." "2. Code size should not exceed 10000 characters."
"3. Code size should not exceed 10000 characters." "3. Code execution time no longer than 5 seconds.")
"4. Code execution time no longer than 5 seconds.")
"\\n")))))) "\\n"))))))
(iverilog-metatop (iverilog-metatop
(call-with-input-file IVERILOG-METATOP-FILE get-string-all)) (call-with-input-file IVERILOG-METATOP-FILE get-string-all))
@@ -890,10 +929,6 @@
'verilator))) 'verilator)))
(logger LOG-DBG "Request ~a simulation" (symbol->string simulator)) (logger LOG-DBG "Request ~a simulation" (symbol->string simulator))
(when ref-stor-dir
(save-to-storage (path+ stor-base ref-stor-dir) code))
(let-values (let-values
(((log vcd) (((log vcd)
(exec-sim simulator (exec-sim simulator
@@ -917,27 +952,32 @@
#:content-type 'text/plain))))) #:content-type 'text/plain)))))
;; Save snippet ;; Save snippet
((or (equal? path savecode-path) ((or (equal? path savecode-path))
(equal? path saveas-path)) (logger LOG-DBG "Request code saving")
(let ((saveas (equal? path saveas-path))) (let ((old-code
(logger LOG-DBG "Request code saving~a" (if ref-stor-dir
(if saveas " as new snippet" "")) (read-from-storage (path+ stor-base ref-stor-dir))
(let ((stor-dir DEFAULT-CODE)))
(if (or saveas (if (equal? code old-code)
(not ref-stor-dir)) ;; If code is not changed do nothing
(make-response
(encode-and-join-uri-path
(append root-path `(,ref-stor-dir)))
#:content-type 'text/plain)
;; New code save to new location
(let ((stor-dir
(basename (basename
(mkdtemp (mkdtemp
(path+ (path+
stor-base stor-base
(if USE-TIME-IN-SAVE-URL (if USE-TIME-IN-SAVE-URL
(format "~a-XXXXXX" (current-time)) (format "~a-XXXXXX" (current-time))
"XXXXXX")))) "XXXXXX"))))))
ref-stor-dir))) (save-to-storage (path+ stor-base stor-dir) code)
(save-to-storage (path+ stor-base stor-dir) code) (make-response
(make-response (encode-and-join-uri-path
(encode-and-join-uri-path (append root-path `(,stor-dir)))
(append root-path `(,stor-dir))) #:content-type 'text/plain)))))
#:content-type 'text/plain))))
;; Wrong POST request ;; Wrong POST request
(else (else

View File

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

View File

@@ -1,58 +1,43 @@
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "V@TOPMODULE@.h" #include "V@TOPMODULE@.h"
#include <cstdint>
#include <verilated.h>
#include <verilated_vcd_c.h>
#define DUMPFILE "@WORKDIR@/@TOPMODULE@.vcd" #define DUMPFILE "@WORKDIR@/@TOPMODULE@.vcd"
#define CLOCK_HALF_PERIOD 5000
int main(int argc, char **argv) int main(int argc, char** argv, char**) {
{ // Setup context, defaults, and parse command line
VerilatedContext *ctx = new VerilatedContext; Verilated::debug(0);
ctx->commandArgs(argc, argv); const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
contextp->traceEverOn(true);
contextp->commandArgs(argc, argv);
/* Create model instance */ // Construct the Verilated model, from Vtop.h generated from Verilating
V@TOPMODULE@ *top = new V@TOPMODULE@(ctx); const std::unique_ptr<V@TOPMODULE@> topp{new V@TOPMODULE@{contextp.get()}};
#if (VM_TRACE == 1)
VerilatedVcdC *vcd = new VerilatedVcdC; VerilatedVcdC *vcd = new VerilatedVcdC;
ctx->traceEverOn(true); topp->trace(vcd, 99);
top->trace(vcd, 99);
vcd->open(DUMPFILE); vcd->open(DUMPFILE);
#endif
top->clock = 0; // Simulate until $finish
while (!contextp->gotFinish()) {
/* ---- Evaluation loop ---- */ // Evaluate model
for (;;) { topp->eval();
/* Eval */ vcd->dump(contextp->time());
top->eval(); // Advance time
if (!topp->eventsPending()) break;
/* Trace steady-state values */ contextp->time(topp->nextTimeSlot());
#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(); if (!contextp->gotFinish()) {
printf("[%lu] Stop simulation\n", ctx->time()); VL_DEBUG_IF(VL_PRINTF("+ Exiting without $finish; no events left\n"););
#if (VM_TRACE == 1)
if (vcd) {
vcd->close();
delete vcd;
} }
#endif
delete top; // Execute 'final' processes
delete ctx; topp->final();
// Print statistical summary report
contextp->statsPrintSummary();
vcd->close();
return 0; return 0;
} }