Compare commits
16 Commits
ab5db7f6e8
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3aee2d2f38 | ||
|
|
b84ec9a1c5 | ||
|
|
1e0bfb58cf | ||
|
|
e67558de14 | ||
|
|
54f7e2be54 | ||
|
|
cc605cce85 | ||
|
|
2f9f5b6dd1 | ||
|
|
cb8bc37dfe | ||
|
|
1e12d5d3e2 | ||
|
|
1bc6ec544d | ||
|
|
d04282e1c7 | ||
|
|
664b7b1f5c | ||
|
|
37b7a54d3b | ||
|
|
01c982fada | ||
|
|
931f4d8aa4 | ||
|
|
90905544d4 |
@@ -10,4 +10,11 @@ module testbench;
|
||||
initial begin
|
||||
$finish;
|
||||
end
|
||||
|
||||
`ifdef DUMP
|
||||
initial begin
|
||||
$dumpfile("testbench.fst");
|
||||
$dumpvars(0, testbench);
|
||||
end
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
@@ -11,19 +11,25 @@
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-variant-ligatures: none;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 3px;
|
||||
font-size: 14px;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
#buttons {
|
||||
color: white;
|
||||
background-color: #2d3d40;
|
||||
width: 100%;
|
||||
height: 38px;
|
||||
padding: 4px;
|
||||
padding: 3px;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
@@ -38,16 +44,13 @@
|
||||
background-color: #dbdbdb;
|
||||
margin-left: 1px;
|
||||
margin-right: 1px;
|
||||
height: 100%;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
button span.text { padding: 4px; }
|
||||
|
||||
#text {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
#editor {
|
||||
height: 75vh;
|
||||
width: 100%;
|
||||
@@ -70,6 +73,12 @@
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
|
||||
svg text {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 10pt;
|
||||
fill: white;
|
||||
}
|
||||
|
||||
svg #wave-signals {
|
||||
stroke: #00fcff;
|
||||
stroke-width: 1;
|
||||
@@ -77,20 +86,18 @@
|
||||
|
||||
svg #wave-clock {
|
||||
stroke: #fffe9a;
|
||||
font-size: 8pt;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
svg #wave-signals text { font-size: 8pt; }
|
||||
svg #wave-clock text { font-size: 8pt; }
|
||||
|
||||
svg #wave-delim {
|
||||
stroke: #d0d0d0;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
svg text {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 14px;
|
||||
fill: white;
|
||||
}
|
||||
|
||||
svg #wave-background { fill: #1e2426; }
|
||||
|
||||
@media (orientation: landscape) and (not (pointer: coarse)) {
|
||||
@@ -113,6 +120,11 @@
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#logdiv pre {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -120,8 +132,7 @@
|
||||
<body>
|
||||
<div id="buttons">
|
||||
<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('%SAVEASURI%')"><span class="text">Save as new</span></button>
|
||||
<button onclick="save_code('%SAVECODEURI%')"><span class="text">Save</span></button>
|
||||
Sim:
|
||||
<button onclick="send_to_sim('%IVERILOGPOSTURI%')"><span class="text">Icarus</span></button>
|
||||
<button onclick="send_to_sim('%VERILATORPOSTURI%')"><span class="text">Verilator</span></button>
|
||||
@@ -181,13 +192,6 @@
|
||||
alert("%HELPSTRING%");
|
||||
};
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key.toLowerCase() === 's' && e.ctrlKey) {
|
||||
e.preventDefault();
|
||||
save_code('%SAVECODEURI%');
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -33,12 +33,11 @@
|
||||
|
||||
(define IVERILOG-EXE "iverilog")
|
||||
(define VVP-EXE "vvp")
|
||||
(define VERILATR-EXE "verilator")
|
||||
(define VERILATOR-EXE "verilator")
|
||||
|
||||
(define URI-IVERILOG "iverilog")
|
||||
(define URI-VERILATOR "verilator")
|
||||
(define URI-SAVE-CODE "save")
|
||||
(define URI-SAVEAS-CODE "saveas")
|
||||
|
||||
(define LOG-DBG 3)
|
||||
(define LOG-VERBOSE 2)
|
||||
@@ -50,9 +49,14 @@
|
||||
(define DEFAULT-CODE
|
||||
(string-append
|
||||
"`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"
|
||||
" $display(\"Hello world!\");\n"
|
||||
" repeat(10) @(posedge clock);\n"
|
||||
" $finish();\n"
|
||||
" end\n"
|
||||
"endmodule\n"))
|
||||
@@ -304,10 +308,10 @@
|
||||
(- x1 x0 (* data-hw 2))
|
||||
(- y1 y0))
|
||||
(format-inex "<text x=\"~a\" y=\"~a\">" 0 text-position)
|
||||
(if (or (eq? sig-type 'real)
|
||||
(< sig-width 4))
|
||||
value
|
||||
(string-upcase
|
||||
(if (or (eq? sig-type 'real)
|
||||
(<= sig-width 4))
|
||||
value
|
||||
(vcd-binary->hex value #t)))
|
||||
"</text></svg>"))))
|
||||
|
||||
@@ -320,33 +324,58 @@
|
||||
;;; Make legend SVG text for VCD
|
||||
;;;
|
||||
(define* (vcd-signals->legend signals text-spacing text-position)
|
||||
(if (null? signals)
|
||||
""
|
||||
(let ((common-scope-len
|
||||
(length
|
||||
(fold
|
||||
(lambda (scope common)
|
||||
(let loop ((scope scope)
|
||||
(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)
|
||||
(vcd-signal-name sig))))
|
||||
(string-concatenate
|
||||
(insert-between
|
||||
(append
|
||||
(drop (vcd-signal-scope sig)
|
||||
common-scope-len)
|
||||
`(,(vcd-signal-name sig)))
|
||||
".")))))
|
||||
signals
|
||||
(iota (length signals))))
|
||||
(iota (length signals))))))
|
||||
|
||||
;;;
|
||||
;;; Create SVG from VCD
|
||||
;;;
|
||||
(define* (vcd->svg vcd width #:key
|
||||
(signal-height 15)
|
||||
(signal-text-position 13)
|
||||
(signal-text-position 12)
|
||||
(margin 5)
|
||||
(signal-spacing 5)
|
||||
(legend-width 100)
|
||||
(legend-width 150)
|
||||
(extra-delim-y 3))
|
||||
|
||||
(let ((tstart (apply min (vcd-timestamps vcd)))
|
||||
(tend (apply max (vcd-timestamps vcd)))
|
||||
(signals (sort
|
||||
(remove
|
||||
(lambda (sig) (< (length (vcd-signal-scope sig)) 2))
|
||||
(vcd-signals vcd))
|
||||
(vcd-signals vcd)
|
||||
(lambda (a b)
|
||||
(and (not (equal? (vcd-signal-name b) "clock"))
|
||||
(or
|
||||
(and (equal? (vcd-signal-name a) "clock")
|
||||
(not (equal? (vcd-signal-name b) "clock")))
|
||||
@@ -355,7 +384,7 @@
|
||||
(length (vcd-signal-scope b)))
|
||||
|
||||
(string-ci<? (vcd-signal-name a)
|
||||
(vcd-signal-name b)))))))
|
||||
(vcd-signal-name b))))))))
|
||||
|
||||
(if (<= tend tstart)
|
||||
'()
|
||||
@@ -542,7 +571,7 @@
|
||||
|
||||
(with-output-to-file command-file
|
||||
(lambda ()
|
||||
(println "+define+TESTBENCH")
|
||||
(println "-DTESTBENCH")
|
||||
(println "--timescale 1ps/1ps")
|
||||
(println "--top-module ~a" top)
|
||||
(println "--Mdir ~a" (path+ work-dir top))
|
||||
@@ -555,9 +584,11 @@
|
||||
(println "--build")
|
||||
(println "-sv")
|
||||
(println "-Wno-WIDTH")
|
||||
(println "+1800-2017ext+sv")
|
||||
(println "+1800-2023ext+sv")
|
||||
(println "--timing")
|
||||
(println "--trace")
|
||||
(println "--trace-structs")
|
||||
(println "--trace-depth 1")
|
||||
(println "--quiet-exit")
|
||||
(println "~a" verilog-file)
|
||||
(println "~a.cpp" top))))
|
||||
@@ -612,7 +643,7 @@
|
||||
(values status log (vcd-file-read
|
||||
vcd-file
|
||||
(lambda (sig)
|
||||
(= 2 (length (vcd-signal-scope sig))))))
|
||||
(>= (length (vcd-signal-scope sig)) 2))))
|
||||
(values status log #f)))))
|
||||
|
||||
;;;
|
||||
@@ -623,7 +654,7 @@
|
||||
(let* ((command-file (path+ work-dir (format "~a.vc" top)))
|
||||
(vcd-file (path+ work-dir (format "~a.vcd" top)))
|
||||
(cmds `(,(format "~a -f ~a"
|
||||
(wrap-exe VERILATR-EXE verilator-wrap)
|
||||
(wrap-exe VERILATOR-EXE verilator-wrap)
|
||||
command-file)
|
||||
,(wrap-exe (path+ work-dir (format "~a/~a" top top))
|
||||
verilator-sim-wrap))))
|
||||
@@ -634,7 +665,7 @@
|
||||
(values status log (vcd-file-read
|
||||
vcd-file
|
||||
(lambda (sig)
|
||||
(= 2 (length (vcd-signal-scope sig))))))
|
||||
(>= (length (vcd-signal-scope sig)) 2))))
|
||||
(values status log #f)))))
|
||||
|
||||
;;;
|
||||
@@ -745,12 +776,22 @@
|
||||
;;;
|
||||
;;; 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
|
||||
(let ((need-width
|
||||
(* minimum-sample-width
|
||||
(length (vcd-timestamps vcd)))))
|
||||
(format "~a<br/>\n<pre id=\"log\">~a</pre>\n"
|
||||
(string-concatenate
|
||||
(vcd->svg vcd canvas-width))
|
||||
log)
|
||||
(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)))
|
||||
|
||||
;;;
|
||||
@@ -767,14 +808,12 @@
|
||||
(iverilog-path (append root-path `(,URI-IVERILOG)))
|
||||
(verilator-path (append root-path `(,URI-VERILATOR)))
|
||||
(savecode-path (append root-path `(,URI-SAVE-CODE)))
|
||||
(saveas-path (append root-path `(,URI-SAVEAS-CODE)))
|
||||
(index-html
|
||||
(read-template-text
|
||||
index-file
|
||||
`(("IVERILOGPOSTURI" ,(encode-and-join-uri-path iverilog-path))
|
||||
("VERILATORPOSTURI" ,(encode-and-join-uri-path verilator-path))
|
||||
("SAVECODEURI" ,(encode-and-join-uri-path savecode-path))
|
||||
("SAVEASURI" ,(encode-and-join-uri-path saveas-path))
|
||||
("HELPSTRING",
|
||||
(string-concatenate
|
||||
(insert-between
|
||||
@@ -783,14 +822,13 @@
|
||||
,(format "Icarus: ~a"
|
||||
(app-version (wrap-exe IVERILOG-EXE iverilog-wrap) "-V"))
|
||||
,(format "Verilator: ~a"
|
||||
(app-version (wrap-exe VERILATR-EXE verilator-wrap)))
|
||||
(app-version (wrap-exe VERILATOR-EXE verilator-wrap)))
|
||||
""
|
||||
"Rules:"
|
||||
"0. Don't fool around ;)"
|
||||
"1. The top module must be named 'testbench'."
|
||||
"2. The top module for the Verilator must have an input clock signal."
|
||||
"3. Code size should not exceed 10000 characters."
|
||||
"4. Code execution time no longer than 5 seconds.")
|
||||
"2. Code size should not exceed 10000 characters."
|
||||
"3. Code execution time no longer than 5 seconds.")
|
||||
"\\n"))))))
|
||||
(iverilog-metatop
|
||||
(call-with-input-file IVERILOG-METATOP-FILE get-string-all))
|
||||
@@ -891,10 +929,6 @@
|
||||
'verilator)))
|
||||
|
||||
(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
|
||||
(((log vcd)
|
||||
(exec-sim simulator
|
||||
@@ -911,33 +945,39 @@
|
||||
|
||||
(let ((canvas-width
|
||||
(let ((v (assoc "width" query)))
|
||||
(and v (string->number (cadr v)) DEFAULT-CANVAS-WIDTH))))
|
||||
(or (and v (string->number (cadr v)))
|
||||
DEFAULT-CANVAS-WIDTH))))
|
||||
(make-response
|
||||
(make-log-html log vcd canvas-width)
|
||||
#:content-type 'text/plain)))))
|
||||
|
||||
;; Save snippet
|
||||
((or (equal? path savecode-path)
|
||||
(equal? path saveas-path))
|
||||
(let ((saveas (equal? path saveas-path)))
|
||||
(logger LOG-DBG "Request code saving~a"
|
||||
(if saveas " as new snippet" ""))
|
||||
((or (equal? path savecode-path))
|
||||
(logger LOG-DBG "Request code saving")
|
||||
(let ((old-code
|
||||
(if ref-stor-dir
|
||||
(read-from-storage (path+ stor-base ref-stor-dir))
|
||||
DEFAULT-CODE)))
|
||||
(if (equal? code old-code)
|
||||
;; 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
|
||||
(if (or saveas
|
||||
(not ref-stor-dir))
|
||||
(basename
|
||||
(mkdtemp
|
||||
(path+
|
||||
stor-base
|
||||
(if USE-TIME-IN-SAVE-URL
|
||||
(format "~a-XXXXXX" (current-time))
|
||||
"XXXXXX"))))
|
||||
ref-stor-dir)))
|
||||
"XXXXXX"))))))
|
||||
(save-to-storage (path+ stor-base stor-dir) code)
|
||||
(make-response
|
||||
(encode-and-join-uri-path
|
||||
(append root-path `(,stor-dir)))
|
||||
#:content-type 'text/plain))))
|
||||
#:content-type 'text/plain)))))
|
||||
|
||||
;; Wrong POST request
|
||||
(else
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
`timescale 1ps/1ps
|
||||
|
||||
module __@TOPMODULE@__;
|
||||
logic clock = 1'b0;
|
||||
initial forever #(5ns) clock = ~clock;
|
||||
@TOPMODULE@ @TOPMODULE@ (clock);
|
||||
@TOPMODULE@ @TOPMODULE@ ();
|
||||
|
||||
initial begin
|
||||
$dumpfile("@WORKDIR@/@TOPMODULE@.vcd");
|
||||
$dumpvars(0, @TOPMODULE@);
|
||||
$dumpvars(1, @TOPMODULE@);
|
||||
$dumplimit(100000);
|
||||
end
|
||||
endmodule
|
||||
|
||||
@@ -1,58 +1,43 @@
|
||||
#include "verilated.h"
|
||||
#include "verilated_vcd_c.h"
|
||||
#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);
|
||||
int main(int argc, char** argv, char**) {
|
||||
// Setup context, defaults, and parse command line
|
||||
Verilated::debug(0);
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
contextp->traceEverOn(true);
|
||||
contextp->commandArgs(argc, argv);
|
||||
|
||||
/* Create model instance */
|
||||
V@TOPMODULE@ *top = new V@TOPMODULE@(ctx);
|
||||
// Construct the Verilated model, from Vtop.h generated from Verilating
|
||||
const std::unique_ptr<V@TOPMODULE@> topp{new V@TOPMODULE@{contextp.get()}};
|
||||
|
||||
#if (VM_TRACE == 1)
|
||||
VerilatedVcdC *vcd = new VerilatedVcdC;
|
||||
ctx->traceEverOn(true);
|
||||
top->trace(vcd, 99);
|
||||
topp->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;
|
||||
// Simulate until $finish
|
||||
while (!contextp->gotFinish()) {
|
||||
// Evaluate model
|
||||
topp->eval();
|
||||
vcd->dump(contextp->time());
|
||||
// Advance time
|
||||
if (!topp->eventsPending()) break;
|
||||
contextp->time(topp->nextTimeSlot());
|
||||
}
|
||||
|
||||
top->final();
|
||||
printf("[%lu] Stop simulation\n", ctx->time());
|
||||
if (!contextp->gotFinish()) {
|
||||
VL_DEBUG_IF(VL_PRINTF("+ Exiting without $finish; no events left\n"););
|
||||
}
|
||||
|
||||
#if (VM_TRACE == 1)
|
||||
if (vcd) {
|
||||
// Execute 'final' processes
|
||||
topp->final();
|
||||
|
||||
// Print statistical summary report
|
||||
contextp->statsPrintSummary();
|
||||
vcd->close();
|
||||
delete vcd;
|
||||
}
|
||||
#endif
|
||||
|
||||
delete top;
|
||||
delete ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user