Add ram test and verilator in fpga DEMO.
This commit is contained in:
parent
3c3cfccfd5
commit
18c8352c09
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"BUILD": "bazel",
|
||||||
|
"memory": "cpp"
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,27 @@
|
||||||
sudo apt-get install build-essential clang bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev build-essential libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-test-dev libboost-iostreams-dev python3.9-dev libboost-iostreams-dev libeigen3-dev libudev-dev cmake python3-pip gcc gdb autoconf automake libtool libusb-dev libusb-1.0-0-dev python2.7-dev
|
sudo apt-get install build-essential clang bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev build-essential libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-test-dev libboost-iostreams-dev python3.9-dev libboost-iostreams-dev libeigen3-dev libudev-dev cmake python3-pip gcc gdb autoconf automake libtool libusb-dev libusb-1.0-0-dev python2.7-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## install verilator form source to use new version
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/verilator/verilator # Only first time
|
||||||
|
|
||||||
|
# Every time you need to build:
|
||||||
|
unsetenv VERILATOR_ROOT # For csh; ignore error if on bash
|
||||||
|
unset VERILATOR_ROOT # For bash
|
||||||
|
cd verilator
|
||||||
|
git pull # Make sure git repository is up-to-date
|
||||||
|
git tag # See what versions exist
|
||||||
|
#git checkout master # Use development branch (e.g. recent bug fixes)
|
||||||
|
#git checkout stable # Use most recent stable release
|
||||||
|
#git checkout v{version} # Switch to specified release version
|
||||||
|
|
||||||
|
autoconf # Create ./configure script
|
||||||
|
./configure # Configure and create Makefile
|
||||||
|
make -j `nproc` # Build Verilator itself (if error, try just 'make')
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
## install yosys
|
## install yosys
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -3,3 +3,5 @@
|
||||||
*.config
|
*.config
|
||||||
*.ys
|
*.ys
|
||||||
*.json
|
*.json
|
||||||
|
obj_dir
|
||||||
|
logs
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
TARGET=ram
|
TARGET=top
|
||||||
|
|
||||||
OBJS+=ram.v
|
OBJS+=top.sv
|
||||||
|
OBJS+=bram.sv
|
||||||
|
|
||||||
all: ${TARGET}.bit
|
all: ${TARGET}.bit
|
||||||
|
|
||||||
$(TARGET).json: $(OBJS)
|
$(TARGET).json: $(OBJS)
|
||||||
yosys -p "read_verilog $(OBJS); synth_ecp5 -top ${TARGET} -json $@"
|
yosys -p "read_verilog -sv $(OBJS); synth_ecp5 -top ${TARGET} -json $@"
|
||||||
|
|
||||||
$(TARGET).config: $(TARGET).json
|
$(TARGET).config: $(TARGET).json
|
||||||
nextpnr-ecp5 --25k --package CABGA381 --speed 6 --json $< --textcfg $@ --lpf $(TARGET).lpf --freq 65
|
nextpnr-ecp5 --25k --package CABGA381 --speed 6 --json $< --textcfg $@ --lpf $(TARGET).lpf --freq 65
|
||||||
|
@ -20,6 +21,11 @@ prog: ${TARGET}.svf
|
||||||
./dapprog ${TARGET}.svf
|
./dapprog ${TARGET}.svf
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.svf *.bit *.config *.ys *.json
|
rm -rf *.svf *.bit *.config *.ys *.json obj_dir logs
|
||||||
|
|
||||||
|
verilator:
|
||||||
|
rm -rf obj_dir logs
|
||||||
|
verilator -Wall --cc --exe --build --trace sim_main.cpp $(OBJS)
|
||||||
|
obj_dir/Vtop +trace
|
||||||
|
|
||||||
.PHONY: prog clean
|
.PHONY: prog clean
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
module bram(
|
||||||
|
input clk,
|
||||||
|
input re,
|
||||||
|
input we,
|
||||||
|
input [DEPTH-1:0] addr_rd,
|
||||||
|
input [DEPTH-1:0] addr_wr,
|
||||||
|
output logic [WIDTH-1:0] data_rd,
|
||||||
|
input [WIDTH-1:0] data_wr
|
||||||
|
);
|
||||||
|
|
||||||
|
parameter WIDTH=8;
|
||||||
|
parameter DEPTH=8;
|
||||||
|
parameter SIZE=(1<<DEPTH);
|
||||||
|
|
||||||
|
logic [WIDTH-1:0] ram [0:SIZE-1];
|
||||||
|
initial begin
|
||||||
|
$readmemh("data.bin", ram);
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (we) begin
|
||||||
|
ram[addr_wr] <= data_wr;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (re) begin
|
||||||
|
data_rd <= ram[addr_rd];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +0,0 @@
|
||||||
LOCATE COMP "clk_i" SITE "P3";
|
|
||||||
IOBUF PORT "clk_i" IO_TYPE=LVCMOS33;
|
|
||||||
FREQUENCY PORT "clk_i" 25 MHZ;
|
|
||||||
|
|
||||||
LOCATE COMP "led_o" SITE "U16";
|
|
||||||
|
|
||||||
IOBUF PORT "led_o" IO_TYPE=LVCMOS33;
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
module ram_single(dataout, addr, datain, we, clk);
|
|
||||||
output[7:0] dataout;
|
|
||||||
input [7:0] datain;
|
|
||||||
input [10:0] addr;
|
|
||||||
input we, clk;
|
|
||||||
reg [7:0] mem [2048:0];
|
|
||||||
always @(posedge clk) begin
|
|
||||||
if (we)
|
|
||||||
mem[addr] <= datain;
|
|
||||||
dataout <= mem[addr];
|
|
||||||
end
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module ram (
|
|
||||||
input clk_i,
|
|
||||||
output reg led_o
|
|
||||||
);
|
|
||||||
localparam MAX = 2_500_000_0;
|
|
||||||
localparam WIDTH = $clog2(MAX);
|
|
||||||
|
|
||||||
|
|
||||||
wire[7:0] dataout;
|
|
||||||
reg[7:0] datain;
|
|
||||||
reg[10:0] addr;
|
|
||||||
reg we;
|
|
||||||
|
|
||||||
ram_single mem(.dataout(dataout), .addr(addr), .datain(datain), .we(we), .clk(clk_i));
|
|
||||||
|
|
||||||
|
|
||||||
wire clk_s;
|
|
||||||
assign clk_s = clk_i;
|
|
||||||
|
|
||||||
reg [WIDTH-1:0] cpt_s;
|
|
||||||
wire [WIDTH-1:0] cpt_next_s = cpt_s + 1'b1;
|
|
||||||
wire end_s = cpt_s == MAX-1;
|
|
||||||
|
|
||||||
wire nextAddr = addr + 1'b1;
|
|
||||||
wire dataAdd = dataout + 1'b1;
|
|
||||||
|
|
||||||
always @(posedge clk_s) begin
|
|
||||||
cpt_s <= cpt_next_s;
|
|
||||||
addr <= nextAddr;
|
|
||||||
datain <= dataAdd;
|
|
||||||
|
|
||||||
led_o <= dataout[0];
|
|
||||||
// if (end_s)
|
|
||||||
// led_o <= ~led_o;
|
|
||||||
end
|
|
||||||
endmodule
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
#include <verilated.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Vtop.h"
|
||||||
|
#include "verilated_vcd_c.h"
|
||||||
|
|
||||||
|
double sc_time_stamp() { return 0; }
|
||||||
|
|
||||||
|
int main(int argc, char** argv, char** env) {
|
||||||
|
Verilated::mkdir("logs");
|
||||||
|
|
||||||
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
|
contextp->debug(0);
|
||||||
|
contextp->randReset(2);
|
||||||
|
contextp->traceEverOn(true);
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
const std::unique_ptr<Vtop> top{new Vtop{contextp.get(), "TOP"}};
|
||||||
|
|
||||||
|
top->clk = 0;
|
||||||
|
Verilated::traceEverOn(true);
|
||||||
|
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||||
|
top->trace(tfp, 99); // Trace 99 levels of hierarchy
|
||||||
|
tfp->open("logs/vlt_dump.vcd");
|
||||||
|
|
||||||
|
uint64_t steps = 10000;
|
||||||
|
while (!contextp->gotFinish() && steps) {
|
||||||
|
contextp->timeInc(1); // 1 timeprecision period passes...
|
||||||
|
|
||||||
|
top->clk = !top->clk;
|
||||||
|
|
||||||
|
top->eval();
|
||||||
|
|
||||||
|
steps--;
|
||||||
|
|
||||||
|
tfp->dump(contextp->time());
|
||||||
|
}
|
||||||
|
|
||||||
|
tfp->close();
|
||||||
|
top->final();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
LOCATE COMP "clk" SITE "P3";
|
||||||
|
IOBUF PORT "clk" IO_TYPE=LVCMOS33;
|
||||||
|
FREQUENCY PORT "clk" 25 MHZ;
|
||||||
|
|
||||||
|
LOCATE COMP "key" SITE "P4";
|
||||||
|
IOBUF PORT "key" IO_TYPE=LVCMOS33;
|
||||||
|
|
||||||
|
|
||||||
|
LOCATE COMP "led_o" SITE "U16";
|
||||||
|
IOBUF PORT "led_o" IO_TYPE=LVCMOS33;
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
module top(
|
||||||
|
input clk,
|
||||||
|
output reg led_o
|
||||||
|
);
|
||||||
|
|
||||||
|
parameter WIDTH=8;
|
||||||
|
parameter DEPTH=16;
|
||||||
|
parameter SIZE=(1<<DEPTH);
|
||||||
|
|
||||||
|
reg [DEPTH-1:0] read_addr;
|
||||||
|
reg [DEPTH-1:0] write_addr;
|
||||||
|
|
||||||
|
wire [DEPTH-1:0] read_addr_next = read_addr + 1'b1;
|
||||||
|
wire [DEPTH-1:0] write_addr_next = write_addr + 1'b1;
|
||||||
|
wire [WIDTH-1:0] read_data;
|
||||||
|
reg [WIDTH-1:0] write_data;
|
||||||
|
|
||||||
|
bram #(
|
||||||
|
.WIDTH(WIDTH),
|
||||||
|
.DEPTH(DEPTH),
|
||||||
|
.SIZE(SIZE)
|
||||||
|
) bram_i (
|
||||||
|
.clk(clk),
|
||||||
|
.re(1'b1),
|
||||||
|
.we(1'b1),
|
||||||
|
.addr_rd(read_addr),
|
||||||
|
.addr_wr(write_addr),
|
||||||
|
.data_rd(read_data),
|
||||||
|
.data_wr(write_data)
|
||||||
|
);
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
led_o <= read_data[0];
|
||||||
|
write_data <= {read_data[6:0],read_data[7]};
|
||||||
|
read_addr <= read_addr_next;
|
||||||
|
write_addr <= write_addr_next;
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$display(" Model running...\n");
|
||||||
|
|
||||||
|
read_addr = 1;
|
||||||
|
write_addr = 0;
|
||||||
|
write_data = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
||||||
|
*.svf
|
||||||
|
*.bit
|
||||||
|
*.config
|
||||||
|
*.ys
|
||||||
|
*.json
|
||||||
|
obj_dir
|
||||||
|
logs
|
|
@ -0,0 +1,13 @@
|
||||||
|
TARGET=top
|
||||||
|
|
||||||
|
OBJS+=top.v
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf *.svf *.bit *.config *.ys *.json obj_dir logs
|
||||||
|
|
||||||
|
verilator:
|
||||||
|
rm -rf obj_dir
|
||||||
|
verilator -Wall --cc --exe --build --trace sim_main.cpp $(OBJS)
|
||||||
|
obj_dir/Vtop +trace
|
||||||
|
|
||||||
|
.PHONY: prog clean
|
|
@ -0,0 +1,113 @@
|
||||||
|
#include <verilated.h>
|
||||||
|
#include <memory>
|
||||||
|
#include "Vtop.h"
|
||||||
|
|
||||||
|
double sc_time_stamp() { return 0; }
|
||||||
|
|
||||||
|
int main(int argc, char** argv, char** env) {
|
||||||
|
// Prevent unused variable warnings
|
||||||
|
if (false && argc && argv && env) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create logs/ directory in case we have traces to put under it
|
||||||
|
Verilated::mkdir("logs");
|
||||||
|
|
||||||
|
// Construct a VerilatedContext to hold simulation time, etc.
|
||||||
|
// Multiple modules (made later below with Vtop) may share the same
|
||||||
|
// context to share time, or modules may have different contexts if
|
||||||
|
// they should be independent from each other.
|
||||||
|
|
||||||
|
// Using unique_ptr is similar to
|
||||||
|
// "VerilatedContext* contextp = new VerilatedContext" then deleting at end.
|
||||||
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
|
|
||||||
|
// Set debug level, 0 is off, 9 is highest presently used
|
||||||
|
// May be overridden by commandArgs argument parsing
|
||||||
|
contextp->debug(0);
|
||||||
|
|
||||||
|
// Randomization reset policy
|
||||||
|
// May be overridden by commandArgs argument parsing
|
||||||
|
contextp->randReset(2);
|
||||||
|
|
||||||
|
// Verilator must compute traced signals
|
||||||
|
contextp->traceEverOn(true);
|
||||||
|
|
||||||
|
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
|
||||||
|
// This needs to be called before you create any model
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
|
||||||
|
// Construct the Verilated model, from Vtop.h generated from Verilating
|
||||||
|
// "top.v". Using unique_ptr is similar to "Vtop* top = new Vtop" then
|
||||||
|
// deleting at end. "TOP" will be the hierarchical name of the module.
|
||||||
|
const std::unique_ptr<Vtop> top{new Vtop{contextp.get(), "TOP"}};
|
||||||
|
|
||||||
|
// Set Vtop's input signals
|
||||||
|
top->reset_l = !0;
|
||||||
|
top->clk = 0;
|
||||||
|
top->in_small = 1;
|
||||||
|
top->in_quad = 0x1234;
|
||||||
|
top->in_wide[0] = 0x11111111;
|
||||||
|
top->in_wide[1] = 0x22222222;
|
||||||
|
top->in_wide[2] = 0x3;
|
||||||
|
|
||||||
|
uint64_t steps = 1000;
|
||||||
|
|
||||||
|
// Simulate until $finish
|
||||||
|
while (!contextp->gotFinish() && steps) {
|
||||||
|
// Historical note, before Verilator 4.200 Verilated::gotFinish()
|
||||||
|
// was used above in place of contextp->gotFinish().
|
||||||
|
// Most of the contextp-> calls can use Verilated:: calls instead;
|
||||||
|
// the Verilated:: versions simply assume there's a single context
|
||||||
|
// being used (per thread). It's faster and clearer to use the
|
||||||
|
// newer contextp-> versions.
|
||||||
|
|
||||||
|
contextp->timeInc(1); // 1 timeprecision period passes...
|
||||||
|
// Historical note, before Verilator 4.200 a sc_time_stamp()
|
||||||
|
// function was required instead of using timeInc. Once timeInc()
|
||||||
|
// is called (with non-zero), the Verilated libraries assume the
|
||||||
|
// new API, and sc_time_stamp() will no longer work.
|
||||||
|
|
||||||
|
// Toggle a fast (time/2 period) clock
|
||||||
|
top->clk = !top->clk;
|
||||||
|
|
||||||
|
// Toggle control signals on an edge that doesn't correspond
|
||||||
|
// to where the controls are sampled; in this example we do
|
||||||
|
// this only on a negedge of clk, because we know
|
||||||
|
// reset is not sampled there.
|
||||||
|
if (!top->clk) {
|
||||||
|
if (contextp->time() > 1 && contextp->time() < 10) {
|
||||||
|
top->reset_l = !1; // Assert reset
|
||||||
|
} else {
|
||||||
|
top->reset_l = !0; // Deassert reset
|
||||||
|
}
|
||||||
|
// Assign some other inputs
|
||||||
|
top->in_quad += 0x12;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate model
|
||||||
|
// (If you have multiple models being simulated in the same
|
||||||
|
// timestep then instead of eval(), call eval_step() on each, then
|
||||||
|
// eval_end_step() on each. See the manual.)
|
||||||
|
top->eval();
|
||||||
|
|
||||||
|
// Read outputs
|
||||||
|
// VL_PRINTF("[%" PRId64 "] clk=%x rstl=%x iquad=%" PRIx64 " -> oquad=%" PRIx64
|
||||||
|
// " owide=%x_%08x_%08x\n",
|
||||||
|
// contextp->time(), top->clk, top->reset_l, top->in_quad,
|
||||||
|
// top->out_quad, top->out_wide[2], top->out_wide[1],
|
||||||
|
// top->out_wide[0]);
|
||||||
|
|
||||||
|
steps--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final model cleanup
|
||||||
|
top->final();
|
||||||
|
|
||||||
|
// Coverage analysis (calling write only after the test is known to pass)
|
||||||
|
#if VM_COVERAGE
|
||||||
|
Verilated::mkdir("logs");
|
||||||
|
contextp->coveragep()->write("logs/coverage.dat");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
module top
|
||||||
|
(
|
||||||
|
input clk,
|
||||||
|
input reset_l,
|
||||||
|
|
||||||
|
output wire [1:0] out_small,
|
||||||
|
output wire [39:0] out_quad,
|
||||||
|
output wire [69:0] out_wide,
|
||||||
|
input [1:0] in_small,
|
||||||
|
input [39:0] in_quad,
|
||||||
|
input [69:0] in_wide
|
||||||
|
);
|
||||||
|
|
||||||
|
assign out_small = ~reset_l ? '0 : (in_small + 2'b1);
|
||||||
|
assign out_quad = ~reset_l ? '0 : (in_quad + 40'b1);
|
||||||
|
assign out_wide = ~reset_l ? '0 : (in_wide + 70'b1);
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
if ($test$plusargs("trace") != 0) begin
|
||||||
|
$display("[%0t] Tracing to logs/vlt_dump.vcd...\n", $time);
|
||||||
|
$dumpfile("logs/vlt_dump.vcd");
|
||||||
|
$dumpvars();
|
||||||
|
end
|
||||||
|
$display("[%0t] Model running...\n", $time);
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
Loading…
Reference in New Issue