Initial commit

This commit is contained in:
Nikolay Puzanov 2022-11-17 13:02:15 +03:00
commit a67cca5aa8
13 changed files with 361 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/*
!.gitignore
!_template_iverilog
!_template_verilator

View File

@ -0,0 +1,28 @@
TESTBENCH ?= testbench
SOURCES ?= testbench.sv
INCLUDE ?=
COMPILE_FLAGS += -DTESTBENCH -g2012
PLUSARGS = -fst
.SILENT:
all: clean run
dump: COMPILE_FLAGS += -DDUMP
dump: all
$(TESTBENCH).vvp: $(SOURCES)
iverilog $(COMPILE_FLAGS) $(INCLUDE) -s $(TESTBENCH) -o $(TESTBENCH).vvp $(SOURCES)
run: $(TESTBENCH).vvp
vvp $(TESTBENCH).vvp $(PLUSARGS)
preprocess: $(SORCES)
iverilog -E $(COMPILE_FLAGS) $(INCLUDE) -s $(TESTBENCH) -o $(TESTBENCH)_preprocessed.sv $(SOURCES)
clean:
rm -rf *.vvp
rm -rf *.fst
rm -rf *.vcd
rm -rf *.csv

View File

@ -0,0 +1,9 @@
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
let
iverilog-latest = callPackage /etc/nixos/programs/iverilog-latest.nix {};
in
mkShell {
packages = [ iverilog-latest gnumake ];
}

View File

@ -0,0 +1,5 @@
{ pkgs ? import <nixpkgs> {} }:
with pkgs; mkShell {
packages = [ verilog gnumake ];
}

View File

@ -0,0 +1,13 @@
`timescale 1ps/1ps
/* verilator lint_off DECLFILENAME */
/* verilator lint_off MULTITOP */
/* verilator lint_off STMTDLY */
/* verilator lint_off INFINITELOOP */
/* verilator lint_off INITIALDLY */
module testbench;
initial begin
$finish;
end
endmodule

View File

@ -0,0 +1,38 @@
BasedOnStyle: LLVM
IndentWidth: 4
UseTab: false
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveMacros: true
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments: true
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: WithoutElse
BinPackArguments: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterControlStatement: MultiLine
AfterFunction: true
AfterStruct: true
BeforeElse: true
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
IncludeBlocks: Regroup
SpaceBeforeParens: ControlStatements
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 4
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false

1
_template_verilator/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
compile_flags.txt

View File

@ -0,0 +1,23 @@
TOP_MODULE = top
SOURCES = top.sv top.cpp clock_generator.cpp
INCLUDES =
## Parameters example:
# PARAM_INPUT_WIDTH ?= 15
# PARAM_FFT_LENGTH ?= 256
# PARAM_REJECTOR_K_WIDTH ?= 8
FLAGS = -Wno-WIDTH -cc --top-module $(TOP_MODULE) +1800-2017ext+sv --timing --trace --Mdir $(TOP_MODULE)
FLAGS += $(foreach V,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(V))=$($(V)))
all: $(SOURCES)
verilator $(FLAGS) --exe --build $(INCLUDES) $(SOURCES)
pre:
verilator $(FLAGS) $(INCLUDES) $(SOURCES)
clean:
rm -rf obj_dir
rm -rf datapath
rm -rf *.vcd

View File

@ -0,0 +1,95 @@
#include "clock_generator.hpp"
ClockGenerator::~ClockGenerator()
{
while (clocks) {
clock *next = clocks->next;
delete clocks;
clocks = next;
}
};
void ClockGenerator::add_clock(uint8_t &net, uint64_t period, uint64_t skew)
{
if (skew >= period) throw "The skew value cannot exceed the period";
clock *clk = new clock(net, period, skew);
net = (clk->position < clk->period / 2) ? 0 : 1;
if (clocks == NULL)
clocks = clk;
else {
clock *last = clocks;
while (last->next)
last = last->next;
last->next = clk;
}
};
uint64_t ClockGenerator::next_event(void)
{
uint64_t time_to_next = UINT64_MAX;
clock *clk = clocks;
while (clk) {
uint64_t ttn;
if (clk->position < clk->period / 2)
ttn = clk->period / 2 - clk->position;
else
ttn = clk->period - clk->position;
if (time_to_next > ttn) time_to_next = ttn;
clk = clk->next;
}
clk = clocks;
while (clk) {
uint8_t next_val;
clk->position += time_to_next;
if (clk->position >= clk->period) clk->position -= clk->period;
next_val = (clk->position < clk->period / 2) ? 0 : 1;
clk->posedge = (next_val == 1 && clk->net == 0) ? true : false;
clk->negedge = (next_val == 0 && clk->net == 1) ? true : false;
clk->net = next_val;
clk = clk->next;
}
return time_to_next;
};
bool ClockGenerator::is_posegde(uint8_t &net)
{
clock *clk = clocks;
bool posedge = false;
while (clk) {
if (std::addressof(net) == std::addressof(clk->net)) {
posedge = clk->posedge;
break;
}
clk = clk->next;
}
return posedge;
};
bool ClockGenerator::is_negedge(uint8_t &net)
{
clock *clk = clocks;
bool negedge = false;
while (clk) {
if (std::addressof(net) == std::addressof(clk->net)) {
negedge = clk->negedge;
break;
}
clk = clk->next;
}
return negedge;
};

View File

@ -0,0 +1,31 @@
#ifndef _CLOCK_GENERATOR_HPP
#define _CLOCK_GENERATOR_HPP
#include <cstdint>
#include <memory>
class ClockGenerator
{
protected:
struct clock {
clock(uint8_t &net, uint64_t period, uint64_t position) :
net(net), period(period), position(position), next(NULL),
posedge(false), negedge(false) {};
uint8_t &net;
uint64_t period;
uint64_t position;
bool posedge;
bool negedge;
clock *next;
} *clocks = NULL;
public:
~ClockGenerator();
void add_clock(uint8_t &net, uint64_t period, uint64_t skew);
uint64_t next_event(void);
bool is_posegde(uint8_t &net);
bool is_negedge(uint8_t &net);
};
#endif // _CLOCK_GENERATOR_HPP

View File

@ -0,0 +1,20 @@
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
let
unstable = import <unstable> {};
flags-file = "compile_flags.txt";
in
mkShell {
packages = [ gnumake unstable.verilator ];
shellHook = ''
echo -n > ${flags-file}
echo -DVM_TRACE=1 >> ${flags-file}
echo -xc++ >> ${flags-file}
echo -I./obj_dir >> ${flags-file}
echo -I${unstable.verilator}/share/verilator/include >> ${flags-file}
echo -I${clang}/resource-root/include >> ${flags-file}
echo -I${glibc.dev}/include >> ${flags-file}
'';
}

View File

@ -0,0 +1,72 @@
#include "Vtop.h"
#include "clock_generator.hpp"
#include <cstdint>
#include <verilated.h>
#include <verilated_vcd_c.h>
#define DUMPFILE "test.vcd"
int main(int argc, char **argv)
{
VerilatedContext *ctx = new VerilatedContext;
ctx->commandArgs(argc, argv);
/* Create model instance */
Vtop *top = new Vtop(ctx);
#if (VM_TRACE == 1)
VerilatedVcdC *vcd = new VerilatedVcdC;
ctx->traceEverOn(true);
top->trace(vcd, 99);
vcd->open(DUMPFILE);
#endif
/* Create clock source */
ClockGenerator *clk = new ClockGenerator;
/* Add clocks and go to first event */
clk->add_clock(top->clock, 10000, 0);
clk->next_event();
/* Initial */
top->reset = 0;
/* ---- Evaluation loop ---- */
while (!ctx->gotFinish()) {
/* Clock event */
ctx->timeInc(clk->next_event());
/* Get output values (before clock edge) */
if (clk->is_posegde(top->clock)) {
printf("-- posedge clock @ %lu\n", ctx->time());
}
/* Eval */
top->eval();
/* Put input values (after clock edge)*/
if (clk->is_posegde(top->clock)) {
top->reset = !top->reset;
}
/* Trace steady-state values */
#if (VM_TRACE == 1)
if (vcd) vcd->dump(ctx->time());
#endif
}
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

@ -0,0 +1,22 @@
`timescale 1ps/1ps
/* -verilator lint_off DECLFILENAME */
/* -verilator lint_off MULTITOP */
/* -verilator lint_off STMTDLY */
/* -verilator lint_off INFINITELOOP */
/* -verilator lint_off INITIALDLY */
module top
(input wire clock,
input wire reset);
initial begin
for (int n = 0; n < 10; n += 1) begin
$display("R@%0t: %0b\n", $time, reset);
@(posedge clock);
end
$finish;
end
endmodule // top