Initial commit

This commit is contained in:
Nikolay Puzanov
2021-02-28 18:59:56 +03:00
parent ff795d2b6e
commit 2fbacc0544
61 changed files with 6063 additions and 0 deletions

5
testbench/.dir-locals.el Normal file
View File

@@ -0,0 +1,5 @@
;;; Directory Local Variables
;;; For more information see (info "(emacs) Directory Variables")
((verilog-mode . ((flycheck-verilator-include-path . ("." "../source"))
(verilog-library-directories . ("." "../source")))))

5
testbench/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
*.out
*.bin
*.vcd
*.gtkw
filtered.txt

31
testbench/Makefile Normal file
View File

@@ -0,0 +1,31 @@
VC = iverilog
VI = vvp
#SOURCES = ../source/lcd_320x240_spi.sv
SOURCES = $(wildcard ../source/*.sv)
SOURCES += ../../local/share/yosys/ice40/cells_sim.v
VFLAGS = -g2012 -I../source
TBS = $(wildcard tb_*.sv)
DEFINES = -D TESTBENCH
VCDDEPS = $(TBS:.sv=.vcd)
BINDEPS = $(TBS:.sv=.bin)
all: $(VCDDEPS)
.SECONDARY:
#.SILENT: $(VCDDEPS) $(BINDEPS) clean
%.vcd: %.bin
@echo "Simulate :" $(<:.bin=.sv)
$(VI) $< #> $(<:.bin=.out)
%.bin: %.sv $(SOURCES)
@echo "Compile :" $(@:.bin=.sv)
$(VC) $(VFLAGS) $(DEFINES) -D DUMPFILE=\"$(@:.bin=.vcd)\" -o $@ $< $(SOURCES)
clean:
@echo "Remove *.bin, *.vcd, *.out"
rm -rf *.bin
rm -rf *.out
rm -rf *.vcd

View File

@@ -0,0 +1 @@
../source/fig_circle_8x8.rom

9
testbench/fir-magn.m Normal file
View File

@@ -0,0 +1,9 @@
pkg load signal
data = csvread("filtered.txt");
data = data(8:length(data));
spec = abs(fft(data ./ 32768));
len = length(data);
x = 1:len/2;
plot(x ./ len, mag2db(spec(1:len/2)));

View File

@@ -0,0 +1 @@
../source/fir_425_50hz_100hz_0db_40db.rom

View File

@@ -0,0 +1,2 @@
-I./obj_dir
-I/usr/share/verilator/include

View File

@@ -0,0 +1,5 @@
;;; Directory Local Variables
;;; For more information see (info "(emacs) Directory Variables")
((verilog-mode . ((flycheck-verilator-include-path . ("." "../../source"))
(verilog-library-directories . ("." "../../source")))))

2
testbench/lcd-model/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
obj_dir
*.vcd

View File

@@ -0,0 +1,31 @@
SOURCE_DIR = ../../source
SOURCES = testbench_top.cpp \
testbench_top.sv \
lcd_ili9341_4spi.sv \
$(SOURCE_DIR)/sugar_lissajous.sv \
$(SOURCE_DIR)/pll_lock_reset.sv \
$(SOURCE_DIR)/pll.sv \
$(SOURCE_DIR)/mcp3201_ma.sv \
$(SOURCE_DIR)/lfsr.sv \
$(SOURCE_DIR)/lcd_top.sv \
$(SOURCE_DIR)/lcd_spi.sv \
$(SOURCE_DIR)/ice40_spram.sv \
$(SOURCE_DIR)/ice40_mac16x16.sv
SOURCES += ../../../local/share/yosys/ice40/cells_sim.v
TOP_MODULE = testbench_top
FLAGS = -DTESTBENCH -Wno-WIDTH -cc -I$(SOURCE_DIR) --top-module $(TOP_MODULE) +1800-2017ext+sv -I$(SOURCE_DIR)
#FLAGS += --threads 8
FLAGS += --trace
all: $(SOURCES)
verilator $(FLAGS) --exe --build -o $(TOP_MODULE) $(SOURCES)
pre:
verilator $(FLAGS) -o $(TOP_MODULE) $(SOURCES)
clean:
rm -rf obj_dir

View File

@@ -0,0 +1 @@
../../source/fig_circle_8x8.rom

View File

@@ -0,0 +1,80 @@
#! /usr/bin/env racket
#lang racket/gui
(require racket/gui/base)
(define display-width 240)
(define display-height 320)
(define fb-size (* display-width display-height))
(define (set-pixel! fb x y r g b)
(let ((i (* 4 (+ x (* y display-width)))))
(bytes-set! fb (+ i 0) 255)
(bytes-set! fb (+ i 1) r)
(bytes-set! fb (+ i 2) g)
(bytes-set! fb (+ i 3) b)))
(define (clear-screen fb r g b)
(for-each
(lambda (n)
(let ((n (* n 4)))
(bytes-set! fb (+ n 0) 255)
(bytes-set! fb (+ n 1) r)
(bytes-set! fb (+ n 2) g)
(bytes-set! fb (+ n 3) b)))
(range fb-size)))
;;; MAIN
(let* ((frame-buffer (make-bytes (* fb-size 4)))
(frame-bitmap (make-bitmap display-width display-height))
(frame (new frame%
(label "LCD")
(min-width display-width)
(min-height display-height)
(stretchable-width #f)
(stretchable-height #f)))
(canvas (new canvas% (parent frame)
(paint-callback
(lambda (canvas dc)
(send frame-bitmap
set-argb-pixels 0 0
display-width display-height
frame-buffer)
(send dc draw-bitmap frame-bitmap 0 0)))))
(cmdl (current-command-line-arguments))
(pipe (if (zero? (vector-length cmdl)) #f (vector-ref cmdl 0))))
(clear-screen frame-buffer 50 100 150)
(send frame show #t)
;; Read pixels data
(thread (λ ()
(let ((thunk
(lambda ()
(let loop ()
(let ((s (read-line)))
(if (eof-object? s)
(loop) ;; (send frame show #f)
(let ((l (string-split s)))
(when (= 5 (length l))
(let* ((x (string->number (list-ref l 0)))
(y (string->number (list-ref l 1)))
(r (string->number (list-ref l 2)))
(g (string->number (list-ref l 3)))
(b (string->number (list-ref l 4))))
(set-pixel! frame-buffer x y r g b)))
(loop))))))))
(if pipe
(with-input-from-file "lcd_pipe" thunk)
(thunk)))))
;; Refresh screen
(thread (lambda ()
(let loop ()
(send canvas refresh)
(sleep 0.02)
(loop)))))

View File

@@ -0,0 +1,156 @@
`timescale 1ns/100ps
`default_nettype none
module lcd_ili9341_4spi
(input wire clock,
input wire reset,
input wire csn_i,
input wire clk_i,
input wire sdi_i,
input wire dcn_i,
output int x_o,
output int y_o,
output logic [7:0] r_o,
output logic [7:0] g_o,
output logic [7:0] b_o,
output logic strobe_o);
logic [7:0] readed;
logic [7:0] spi_sr;
int bit_cntr;
logic clk_prev;
logic rstrobe;
always_ff @ (posedge clock) clk_prev <= clk_i;
always_ff @(posedge clock, posedge csn_i)
if (csn_i || reset) begin
bit_cntr <= 0;
end
else begin
if (clk_prev == 1'b0 &&
clk_i == 1'b1)
begin
spi_sr <= { spi_sr[6:0], sdi_i };
bit_cntr <= bit_cntr + 1;
end
if (bit_cntr == 8) begin
readed <= spi_sr;
rstrobe <= 1'b1;
bit_cntr <= 0;
end
else
rstrobe <= 1'b0;
end
enum int unsigned {
ST_IDLE = 0,
ST_CADDR,
ST_PADDR,
ST_MEM_WRITE
} state;
logic [15:0] x_beg;
logic [15:0] x_end;
logic [15:0] y_beg;
logic [15:0] y_end;
initial begin
x_beg = 0;
x_end = 239;
y_beg = 0;
y_end = 319;
end
int n;
int x, y;
logic [7:0] tmp;
always_ff @ (posedge clock, posedge csn_i)
if (csn_i || reset) begin
state <= ST_IDLE;
n <= 0;
strobe_o <= 1'b0;
end
else begin
strobe_o <= 1'b0;
if (rstrobe) begin
if (~dcn_i) begin
case (readed)
8'h2a: state <= ST_CADDR;
8'h2b: state <= ST_PADDR;
8'h2c: begin
x <= int'(x_beg);
y <= int'(y_beg);
state <= ST_MEM_WRITE;
end
default: begin end
endcase
n <= 0;
end
else
case (state)
ST_CADDR: begin
n <= n + 1;
case (n)
0: x_beg[15:8] <= readed;
1: x_beg[7:0] <= readed;
2: x_end[15:8] <= readed;
3: x_end[7:0] <= readed;
endcase
end
ST_PADDR: begin
n <= n + 1;
case (n)
0: y_beg[15:8] <= readed;
1: y_beg[7:0] <= readed;
2: y_end[15:8] <= readed;
3: y_end[7:0] <= readed;
endcase
end
ST_MEM_WRITE: begin
if (n == 0) begin
n <= 1;
tmp <= readed;
end
else begin
n <= 0;
// $display("%d %d %d %d %d", x, y,
// { tmp[7:3], 1'b0 },
// { tmp[2:0], readed[7:5] },
// { readed[4:0], 1'b0 });
x_o <= x;
y_o <= y;
r_o <= { 2'b00, tmp[7:3], 1'b0 };
g_o <= { 2'b00, tmp[2:0], readed[7:5] };
b_o <= { 2'b00, readed[4:0], 1'b0 };
strobe_o <= 1'b1;
x <= x + 1;
if (x == int'(x_end)) begin
x <= int'(x_beg);
y <= y + 1;
if (y == int'(y_end))
y <= int'(y_beg);
end
end
end
endcase
end
end
endmodule // lcd_ili9341_4spi

View File

@@ -0,0 +1,61 @@
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000
000

View File

@@ -0,0 +1 @@
../../source/quadrant_256.rom

View File

@@ -0,0 +1,107 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <libgen.h>
#include <verilated_vcd_c.h>
#include "Vtestbench_top.h"
#define DUMPFILE "testbench_top.vcd"
#define PIPE_FILE "lcd_pipe"
/* Clock period in timescale units
* In datapath.sv uses 100ps time unit */
#define CLOCK_PERIOD 2
#define TIMESCALE 20000
/* Simulation time */
uint64_t simtime = 0;
/* Clock cycle counter */
uint64_t cycle = 0;
/* Called by $time in Verilog */
double sc_time_stamp() {
return simtime;
}
int main(int argc, char **argv)
{
Verilated::commandArgs(argc, argv);
/* Create model instance */
Vtestbench_top *dp = new Vtestbench_top;
/* Enable trace if compiled with --trace flag */
#if (VM_TRACE == 1)
VerilatedVcdC *vcd = NULL;
const char* trace_flag = Verilated::commandArgsPlusMatch("trace");
if (trace_flag && (strcmp(trace_flag, "+trace") == 0))
{
Verilated::traceEverOn(true);
vcd = new VerilatedVcdC;
dp->trace(vcd, 99);
vcd->open(DUMPFILE);
}
#endif
/* Open pipe */
FILE *o_file = fopen(PIPE_FILE, "w");
if (!o_file) {
printf("ERROR: Can't open file/pipe '%s'\n", PIPE_FILE);
delete dp;
return -1;
}
int posedge_clock = 0;
int data_loops = 6;
uint64_t check_cycle;
/* Initial */
dp->reset = 1;
dp->clock = 0;
while (!Verilated::gotFinish())
{
posedge_clock = 0;
if ((simtime % (CLOCK_PERIOD/2)) == 0) {
dp->clock = !dp->clock;
if (dp->clock) {
posedge_clock = 1;
cycle ++;
}
}
/* release reset at 200 simulation cycle */
if (simtime == 200) dp->reset = 0;
dp->eval();
/* ouput data */
if (posedge_clock && !dp->reset && dp->strobe)
fprintf(o_file, "%i %i %i %i %i\n",
dp->x, dp->y, dp->r << 2, dp->g << 2, dp->b << 2);
#if (VM_TRACE == 1)
if (vcd)
vcd->dump(simtime * TIMESCALE);
#endif
simtime ++;
}
dp->final();
printf("[%lu] Stop simulation\n", simtime);
#if (VM_TRACE == 1)
if (vcd) vcd->close();
#endif
fclose(o_file);
delete dp;
return 0;
}

View File

@@ -0,0 +1,41 @@
`timescale 1ns/100ps
`default_nettype none
/* verilator lint_off PINMISSING */
module testbench_top
(input wire clock,
input wire reset,
output int x,
output int y,
output [7:0] r,
output [7:0] g,
output [7:0] b,
output strobe);
logic csn, mosi, clk, dcn;
sugar_lissajous DUT
(.CLK12(clock),
.P1_3(1'b0),
.P1_10(1'b1),
.P2_3(dcn),
.P2_9(clk),
.P2_11(mosi),
.P2_12(csn));
lcd_ili9341_4spi LCD
(.clock, .reset,
.csn_i(csn),
.clk_i(clk),
.sdi_i(mosi),
.dcn_i(dcn),
.x_o(x),
.y_o(y),
.r_o(r),
.g_o(g),
.b_o(b),
.strobe_o(strobe));
endmodule // testbench_top

1
testbench/lcd_init.rom Symbolic link
View File

@@ -0,0 +1 @@
../source/lcd_init.rom

1
testbench/quadrant_256.rom Symbolic link
View File

@@ -0,0 +1 @@
../source/quadrant_256.rom

60
testbench/tb_circle.sv Normal file
View File

@@ -0,0 +1,60 @@
`timescale 1ns/100ps
module tb_circle;
logic clock = 1'b0;
logic reset = 1'b1;
/* Master clock 100MHz (10ns period) */
always #(10ns/2) clock <= ~clock;
logic [9:0] angle;
logic [7:0] r;
logic [7:0] x0;
logic [7:0] y0;
logic [7:0] x;
logic [7:0] y;
logic req, ack;
circle_1024 DUT
(.clock, .reset,
.angle,
.r,
.x0,
.y0,
.x,
.y,
.req_i(req),
.ack_o(ack));
initial begin
reset = 1'b1;
req = 1'b0;
repeat(10) @(posedge clock) #1;
reset = 1'b0;
@(posedge clock) #1;
angle = '0;
r = 120;
x0 = 120;
y0 = 128;
for (int i = 0; i < 1024; i ++) begin
@(posedge clock) #1;
req = 1'b1;
wait (ack);
angle = angle + 1'b1;
end
req = 1'b0;
repeat(10) @(posedge clock) #1;
$finish;
end
initial begin
$dumpfile("tb_circle.vcd");
$dumpvars;
end
endmodule // tb_circle

View File

@@ -0,0 +1,70 @@
`timescale 1ns/100ps
module tb_fig_drawer;
logic clock = 1'b0;
logic reset = 1'b1;
/* Master clock 100MHz (10ns period) */
always #(10ns/2) clock <= ~clock;
logic [7:0] x;
logic [8:0] y;
logic [7:0] h, s, v;
logic req, ack;
logic [7:0] fb_x;
logic [8:0] fb_y;
logic [15:0] fb_color;
logic fb_req, fb_ack;
fig_drawer DUT
(.clock, .reset,
.x_i(x), .y_i(y),
.h_i(h), .s_i(s), .v_i(v),
.req_i(req), .ack_o(ack),
.fb_x_o(fb_x),
.fb_y_o(fb_y),
.fb_color_o(fb_color),
.fb_req_o(fb_req),
.fb_ack_i(fb_ack));
int fb_lat_n;
always_ff @ (posedge clock) begin
fb_ack <= 1'b0;
if (fb_req)
if (fb_lat_n == 2) begin
fb_ack <= 1'b1;
fb_lat_n <= 0;
end
else fb_lat_n <= fb_lat_n + 1;
end
always_ff @ (posedge clock)
if (ack)
req <= 1'b0;
initial begin
reset <= 1'b1;
repeat(10) @(posedge clock);
reset <= 1'b0;
@(posedge clock);
x <= 'd20;
y <= 'd50;
h <= 50;
s <= 100;
v <= 150;
req <= 1'b1;
repeat(1000) @(posedge clock);
$finish;
end
initial begin
$dumpfile("tb_fig_drawer.vcd");
$dumpvars;
end
endmodule // tb_fig_drawer

69
testbench/tb_fig_ring.sv Normal file
View File

@@ -0,0 +1,69 @@
`timescale 1ns/100ps
module tb_fig_ring;
logic clock = 1'b0;
logic reset = 1'b1;
/* Master clock 100MHz (10ns period) */
always #(10ns/2) clock <= ~clock;
logic pt_ack_o;
logic [7:0] fig_x_o;
logic [8:0] fig_y_o;
logic [7:0] fig_h_o;
logic [7:0] fig_s_o;
logic [7:0] fig_v_o;
logic fig_req_o;
logic [7:0] pt_x;
logic [7:0] pt_y;
logic [7:0] pt_h;
logic pt_req_i;
logic fig_ack_i;
fig_ring DUT (/*AUTOINST*/
// Outputs
.pt_ack_o (pt_ack_o),
.fig_x_o (fig_x_o[7:0]),
.fig_y_o (fig_y_o[8:0]),
.fig_h_o (fig_h_o[7:0]),
.fig_s_o (fig_s_o[7:0]),
.fig_v_o (fig_v_o[7:0]),
.fig_req_o (fig_req_o),
// Inputs
.clock (clock),
.reset (reset),
.pt_x (pt_x[7:0]),
.pt_y (pt_y[7:0]),
.pt_h (pt_h[7:0]),
.pt_req_i (pt_req_i),
.fig_ack_i (fig_ack_i));
assign fig_ack_i = 1'b1;
always_ff @ (posedge clock)
if (pt_ack_o)
pt_req_i <= 1'b0;
initial begin
reset = 1'b1;
pt_req_i = 1'b0;
repeat(10) @(posedge clock) #1;
reset = 1'b0;
@(posedge clock) #1;
pt_x = 0;
pt_y = 0;
pt_h = 100;
pt_req_i = 1'b1;
repeat(1000) @(posedge clock) #1;
$finish;
end
initial begin
$dumpfile("tb_fig_ring.vcd");
$dumpvars;
end
endmodule // tb_fig_ring

View File

@@ -0,0 +1,66 @@
`timescale 1ns/100ps
module tb_fir_filter;
logic clock = 1'b0;
logic reset = 1'b1;
/* Master clock 100MHz (10ns period) */
always #(10ns/2) clock <= ~clock;
logic signed [15:0] data_i;
logic signed [15:0] data_o;
logic input_ready, output_valid;
localparam FILTER_LEN = 425;
fir_filter #(.LEN(FILTER_LEN),
.COEFFS_ROM_FILE("fir_425_50hz_100hz_0db_40db.rom")) DUT
(.clock, .reset,
.data_i, .data_o,
.ready_i(input_ready),
.valid_o(output_valid));
event done;
integer file_o;
initial begin
file_o = $fopen("filtered.txt", "w");
@(done);
$fclose(file_o);
$finish;
end
initial begin
reset = 1'b1;
input_ready = 1'b0;
repeat(10) @(posedge clock) #1;
reset = 1'b0;
@(posedge clock) #1;
data_i = 16'd32767;
input_ready = 1'b1;
@(posedge clock) #1;
wait (output_valid)
$fdisplay(file_o, "%d", data_o);
data_i = '0;
for (int i = 1; i < FILTER_LEN; i ++) begin
@(posedge clock) #1;
wait (output_valid)
$fdisplay(file_o, "%d", data_o);
end
->done;
repeat(10) @(posedge clock) #1;
$finish;
end
initial begin
$dumpfile("tb_fir_filter.vcd");
$dumpvars;
end
endmodule // tb_fir_filter

49
testbench/tb_hsl2rgb.sv Normal file
View File

@@ -0,0 +1,49 @@
`timescale 1ns/100ps
module tb_hsl2rgb;
logic clock = 1'b0;
logic reset = 1'b1;
/* Master clock 100MHz (10ns period) */
always #(10ns/2) clock <= ~clock;
logic [7:0] h, s, l;
logic [7:0] r, g, b;
logic valid, ready;
hsl2rgb DUT
(.clock, .reset,
.h, .s, .l,
.ready_i(ready),
.r, .g, .b,
.valid_o(valid));
always_ff @ (posedge clock)
if (valid)
$display("%d %d %d", r, g, b);
initial begin
reset = 1'b1;
ready = 1'b0;
repeat(10) @(posedge clock) #1;
reset = 1'b0;
@(posedge clock) #1;
h = 8'd128;
s = 8'd255;
l = 8'd130;
ready = 1'b1;
@(posedge clock) #1;
ready = 1'b0;
repeat(20) @(posedge clock);
$finish;
end
initial begin
$dumpfile("tb_hsl2rgb.vcd");
$dumpvars;
end
endmodule // tb_hsl2rgb

78
testbench/tb_hsv2rgb.sv Normal file
View File

@@ -0,0 +1,78 @@
`timescale 1ns/100ps
module tb_hsv2rgb;
logic clock = 1'b0;
logic reset = 1'b1;
/* Master clock 100MHz (10ns period) */
always #(10ns/2) clock <= ~clock;
logic [7:0] h, s, v;
logic [7:0] r, g, b;
logic valid, ready;
hsv2rgb DUT
(.clock, .reset,
.h, .s, .v,
.ready_i(ready),
.r, .g, .b,
.valid_o(valid));
always_ff @ (posedge clock)
if (valid)
$display("%d %d %d", r, g, b);
initial begin
reset = 1'b1;
ready = 1'b0;
repeat(10) @(posedge clock) #1;
reset = 1'b0;
@(posedge clock) #1;
h = 8'd50;
s = 8'd100;
v = 8'd150;
ready = 1'b1;
@(posedge clock) #1;
h = 8'dx;
s = 8'dx;
v = 8'dx;
ready = 1'b0;
@(posedge clock) #1;
@(posedge clock) #1;
@(posedge clock) #1;
@(posedge clock) #1;
h = 8'd50;
s = 8'd100;
v = 8'd150;
ready = 1'b1;
@(posedge clock) #1;
h = 8'd111;
s = 8'd222;
v = 8'd33;
ready = 1'b1;
@(posedge clock) #1;
h = 8'd200;
s = 8'd150;
v = 8'd50;
ready = 1'b1;
@(posedge clock) #1;
ready = 1'b0;
repeat(10) @(posedge clock);
$finish;
end
initial begin
$dumpfile("tb_hsv2rgb.vcd");
$dumpvars;
end
endmodule // tb_hsv2rgb

63
testbench/tb_lcd_spi.sv Normal file
View File

@@ -0,0 +1,63 @@
`timescale 1ns/100ps
module tb_lcd_spi;
logic clock = 1'b0;
logic reset = 1'b1;
/* Master clock 50MHz (20ns period) */
always #(20ns/2) clock <= ~clock;
logic [7:0] data;
logic push, done;
logic sclk, sdo;
lcd_spi #(.DATA_WIDTH(8),
.SPI_CLK_PERIOD(16)) DUT
(.clock, .reset,
.data_i(data),
.push_i(push),
.done_o(done),
.spi_clk_o(sclk),
.spi_dat_o(sdo));
int state;
always_ff @(posedge clock)
if (reset) begin
push <= 1'b0;
state <= 0;
end
else begin
case (state)
0: begin
data <= $random;
push <= 1'b1;
state <= 1;
end
1: begin
if (done) begin
//data <= $random;
push <= 1'b0;
state <= 0;
end
end
endcase
end
initial begin
reset = 1'b1;
repeat(10) @(posedge clock) #1;
reset = 1'b0;
repeat(1000) @(posedge clock);
$finish;
end
initial begin
$dumpfile("tb_lcd_spi.vcd");
$dumpvars;
end
endmodule // tb_lcd_spi